/* RosterChief control panel — a deliberately separate stylesheet. * * The control panel is a distinct surface (see design_handoff_rosterchief_platform/README.md): * industrial, dark command bar over a light workspace, its own type system (Barlow / * Barlow Condensed / IBM Plex Mono) and colour tokens, and — per that handoff — "never * club-branded". It does not import assets/app.css and does not load daisyUI: sharing either * would mean the panel inherits the club-facing app's theme variables and component shapes, * which is exactly what "standalone" rules out. * * One wrinkle: a handful of templates the control panel renders — `controlpanel/_form_fields.html`, * `templatetags/field.html`, and the `daisy`/`form_field` template tags in * `controlpanel/templatetags/ui.py` — are also used by the sitewide login/MFA templates * (templates/account/, templates/allauth/), so their *markup* is off limits here (changing it * would reskin the login page too). Those templates emit daisyUI-shaped class names * (`input`, `select`, `textarea`, `checkbox`, `toggle`, `file-input`, `btn`, `badge`, `card`, * `table`, `modal`, `alert`, `avatar`, `progress`, `form-control`, `label`, `divide-y`, `link`) * without daisyUI itself supplying their CSS (it isn't loaded here). So this file hand-rolls * industrial-styled definitions for exactly that class vocabulary — same names, new look — * scoped to controlpanel templates only via @source below, so nothing here reaches the * pages built on assets/app.css. */ @import "tailwindcss"; @source "../controlpanel"; @theme { --font-display: "Barlow Condensed", ui-sans-serif, system-ui, sans-serif; --font-sans: "Barlow", ui-sans-serif, system-ui, sans-serif; --font-mono: "IBM Plex Mono", ui-monospace, SFMono-Regular, monospace; --color-ink: #0b1220; /* darkest -- command bar, sidebars, dark cards */ --color-navy: #101e36; --color-steel: #1b2b47; /* inset controls on dark */ --color-hairline: #1e2b42; /* rules on dark surfaces */ --color-paper: #f4f5f7; /* app/page background */ --color-line: #e3e6eb; /* 1px borders on light */ --color-rule: #eef0f3; /* table row dividers */ --color-edge: #d6dae1; /* stronger light border -- control panel, inputs */ --color-stroke: #c9cfd8; /* secondary-button border */ --color-muted: #6c7787; /* secondary text */ --color-dim: #8b95a4; /* tertiary text, inactive icons */ --color-slate: #3a4658; /* body copy on light */ --color-on-dark: #93a0b4; --color-on-dark-dim: #7c8aa0; --color-on-dark-faint: #5c6b85; /* Fixed platform brand red -- the control panel is never club-branded (per the design handoff), so this is NOT the club.secondary_color CSS variable used elsewhere. */ --color-club: #e4002b; --color-club-dark: #b00021; --color-ice: #14b8e8; --color-ice-ink: #04212c; --color-ok: #14a05a; --color-ok-bg: #e6f6ee; --color-ok-border: #bfe7d3; --color-ok-text: #0c7a43; --color-warn: #f0a22e; --color-warn-bg: #fff5e4; --color-warn-border: #f6e0b8; --color-warn-text: #9a6410; --color-warn-deep: #7a4e08; --color-danger-bg: #fdecec; --color-danger-border: #f5c9ce; --color-info-bg: #eaf7fc; --color-info-border: #c3e7f4; --color-info-text: #0a6f91; --color-row-sel: #fff7f8; /* selected table row */ --color-row-focus: #f4f9ff; /* focused/active row */ --color-row-warn: #fffdf6; /* row needing attention */ --color-subhead: #f8f9fa; /* table header fill */ --radius-box: 0.25rem; /* control panel is square by intent -- 4px, not the usual rounded-xl */ } /* --- fonts: self-hosted, same latin/latin-ext split as assets/app.css and the same reasoning -- no request to Google's CDN on an EU club platform's admin surface. --- */ @font-face { font-family: "Barlow"; font-style: normal; font-weight: 400; font-display: swap; src: url("../fonts/barlow-latin-400-normal.woff2") format("woff2"); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } @font-face { font-family: "Barlow"; font-style: normal; font-weight: 400; font-display: swap; src: url("../fonts/barlow-latin-ext-400-normal.woff2") format("woff2"); unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; } @font-face { font-family: "Barlow"; font-style: normal; font-weight: 500; font-display: swap; src: url("../fonts/barlow-latin-500-normal.woff2") format("woff2"); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } @font-face { font-family: "Barlow"; font-style: normal; font-weight: 500; font-display: swap; src: url("../fonts/barlow-latin-ext-500-normal.woff2") format("woff2"); unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; } @font-face { font-family: "Barlow"; font-style: normal; font-weight: 600; font-display: swap; src: url("../fonts/barlow-latin-600-normal.woff2") format("woff2"); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } @font-face { font-family: "Barlow"; font-style: normal; font-weight: 600; font-display: swap; src: url("../fonts/barlow-latin-ext-600-normal.woff2") format("woff2"); unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; } @font-face { font-family: "Barlow"; font-style: normal; font-weight: 700; font-display: swap; src: url("../fonts/barlow-latin-700-normal.woff2") format("woff2"); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } @font-face { font-family: "Barlow"; font-style: normal; font-weight: 700; font-display: swap; src: url("../fonts/barlow-latin-ext-700-normal.woff2") format("woff2"); unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; } @font-face { font-family: "Barlow Condensed"; font-style: normal; font-weight: 600; font-display: swap; src: url("../fonts/barlow-condensed-latin-600-normal.woff2") format("woff2"); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } @font-face { font-family: "Barlow Condensed"; font-style: normal; font-weight: 600; font-display: swap; src: url("../fonts/barlow-condensed-latin-ext-600-normal.woff2") format("woff2"); unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; } @font-face { font-family: "Barlow Condensed"; font-style: normal; font-weight: 700; font-display: swap; src: url("../fonts/barlow-condensed-latin-700-normal.woff2") format("woff2"); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } @font-face { font-family: "Barlow Condensed"; font-style: normal; font-weight: 700; font-display: swap; src: url("../fonts/barlow-condensed-latin-ext-700-normal.woff2") format("woff2"); unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; } @font-face { font-family: "Barlow Condensed"; font-style: normal; font-weight: 800; font-display: swap; src: url("../fonts/barlow-condensed-latin-800-normal.woff2") format("woff2"); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } @font-face { font-family: "Barlow Condensed"; font-style: normal; font-weight: 800; font-display: swap; src: url("../fonts/barlow-condensed-latin-ext-800-normal.woff2") format("woff2"); unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; } @font-face { font-family: "IBM Plex Mono"; font-style: normal; font-weight: 400; font-display: swap; src: url("../fonts/ibm-plex-mono-latin-400-normal.woff2") format("woff2"); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } @font-face { font-family: "IBM Plex Mono"; font-style: normal; font-weight: 400; font-display: swap; src: url("../fonts/ibm-plex-mono-latin-ext-400-normal.woff2") format("woff2"); unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; } @font-face { font-family: "IBM Plex Mono"; font-style: normal; font-weight: 500; font-display: swap; src: url("../fonts/ibm-plex-mono-latin-500-normal.woff2") format("woff2"); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } @font-face { font-family: "IBM Plex Mono"; font-style: normal; font-weight: 500; font-display: swap; src: url("../fonts/ibm-plex-mono-latin-ext-500-normal.woff2") format("woff2"); unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; } @font-face { font-family: "IBM Plex Mono"; font-style: normal; font-weight: 600; font-display: swap; src: url("../fonts/ibm-plex-mono-latin-600-normal.woff2") format("woff2"); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } @font-face { font-family: "IBM Plex Mono"; font-style: normal; font-weight: 600; font-display: swap; src: url("../fonts/ibm-plex-mono-latin-ext-600-normal.woff2") format("woff2"); unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; } /* @layer base, not a bare rule: a bare `body { background: ... }` is unlayered CSS, which * beats every Tailwind utility class regardless of specificity -- including a `bg-ink` on * itself (see controlpanel/templates/controlpanel/_auth_base.html), which would * silently lose to this and always render var(--color-paper) instead. Layering it puts it * where Tailwind's own base styles live, so a `bg-*`/`text-*` utility on wins as * expected; this only supplies the default for whichever page doesn't set one. */ @layer base { body { background: var(--color-paper); color: var(--color-slate); font-family: var(--font-sans); } } /* --- component layer: the daisyUI-shaped class vocabulary the shared form/message templates render (controlpanel/templates/controlpanel/_form_fields.html, controlpanel/templates/templatetags/field.html, controlpanel/templatetags/ui.py), plus the same names used directly in controlpanel's own page templates. Hand-rolled rather than @plugin "daisyui" -- see the file banner. --- */ @layer components { /* Buttons -- 34-36px desktop per the handoff; controlpanel is desktop-only. */ .btn { display: inline-flex; align-items: center; justify-content: center; gap: 0.5rem; /* Matches .input/.select's own 2.25rem -- see that rule's comment; .btn itself never had the clipping problem (flex centring), this is purely so a button sitting next to a field in the same row lines up. */ height: 2.25rem; padding-inline: 0.875rem; border-radius: var(--radius-box); font-family: var(--font-display); font-weight: 800; font-size: 0.8125rem; letter-spacing: 0.1em; text-transform: uppercase; background: var(--color-ink); color: #fff; border: 1px solid transparent; cursor: pointer; transition: opacity 0.15s ease; white-space: nowrap; } .btn:hover { opacity: 0.85; } .btn:disabled { opacity: 0.45; cursor: not-allowed; } .btn-primary { background: var(--color-club); color: #fff; } .btn-success { background: var(--color-ok); color: #fff; } .btn-warning { background: var(--color-warn); color: var(--color-ink); } .btn-error { background: var(--color-club-dark); color: #fff; } .btn-ghost { background: transparent; color: var(--color-ink); } .btn-ghost:hover { background: var(--color-rule); opacity: 1; } .btn-outline { background: #fff; color: var(--color-ink); border-color: var(--color-stroke); } .btn-outline:hover { background: var(--color-subhead); opacity: 1; } .btn-outline.btn-primary { background: #fff; color: var(--color-club-dark); border-color: var(--color-danger-border); } .btn-outline.btn-error { background: #fff; color: var(--color-club-dark); border-color: var(--color-danger-border); } .btn-outline.btn-success { background: #fff; color: var(--color-ok-text); border-color: var(--color-ok-border); } /* accent -- allauth tags the passkey/security-key buttons "accent" (see templates/allauth/elements/button.html and the manual btn-accent usages in templates/account/login.html, password_change.html, mfa/authenticate.html). Not one of the daisyUI semantic colours the rest of the app uses, so it gets its own token: the ice cyan, which otherwise only appears on focus rings. */ .btn-accent { background: var(--color-ice); color: var(--color-ice-ink); } .btn-outline.btn-accent { background: #fff; color: var(--color-ice-ink); border-color: var(--color-ice); } /* A bare text link shaped like a button-slot -- allauth's button element renders this for anything tagged "link" (a lower-emphasis alternative action). */ .btn-link { height: auto; padding-inline: 0; background: transparent; color: var(--color-club-dark); border-color: transparent; text-transform: none; letter-spacing: normal; font-family: var(--font-sans); font-weight: 600; text-decoration: underline; } .btn-link:hover { opacity: 1; text-decoration: none; } .btn-soft { background: color-mix(in oklab, currentColor 12%, transparent); } .btn-square { padding-inline: 0; width: 2.25rem; } .btn-sm { height: 1.75rem; padding-inline: 0.625rem; font-size: 0.75rem; } .btn-xs { height: 1.5rem; padding-inline: 0.5rem; font-size: 0.6875rem; gap: 0.25rem; } /* Badges / status pills -- rounded-full per the handoff's "status pills" spec. */ .badge { display: inline-flex; align-items: center; gap: 0.25rem; padding: 0.15rem 0.6rem; border-radius: 999px; font-family: var(--font-display); font-weight: 700; font-size: 0.6875rem; letter-spacing: 0.08em; text-transform: uppercase; background: var(--color-rule); color: var(--color-slate); border: 1px solid var(--color-line); white-space: nowrap; } .badge-sm { font-size: 0.625rem; padding: 0.1rem 0.45rem; } .badge-xs { font-size: 0.5625rem; padding: 0.05rem 0.35rem; } .badge-success { background: var(--color-ok-bg); color: var(--color-ok-text); border-color: var(--color-ok-border); } .badge-error { background: var(--color-danger-bg); color: var(--color-club-dark); border-color: var(--color-danger-border); } .badge-warning { background: var(--color-warn-bg); color: var(--color-warn-text); border-color: var(--color-warn-border); } .badge-info { background: var(--color-info-bg); color: var(--color-info-text); border-color: var(--color-info-border); } .badge-ghost, .badge-outline { background: #fff; color: var(--color-muted); border-color: var(--color-edge); } .badge-neutral { background: var(--color-ink); color: #fff; border-color: var(--color-ink); } /* Cards -- square by intent (4px radius), hairline border, no shadow. */ .card { background: #fff; border: 1px solid var(--color-edge); border-radius: var(--radius-box); } .card-body { padding: 1.125rem; display: flex; flex-direction: column; gap: 0.5rem; } .card-title { display: flex; align-items: center; gap: 0.5rem; font-family: var(--font-display); font-weight: 800; font-size: 0.9375rem; letter-spacing: 0.06em; text-transform: uppercase; color: var(--color-ink); } /* The action row a card/form/panel puts its buttons in -- allauth's own form and panel elements (templates/allauth/elements/form.html, panel.html) render this unconditionally, pairing it with justify-end plus a margin/padding utility that varies per call site. */ .card-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem; } /* Tables -- CSS-grid-flavoured look via plain : subhead fill, mono headings, hairline row dividers. */ .table { width: 100%; border-collapse: collapse; font-size: 0.8125rem; } .table thead tr { background: var(--color-subhead); border-bottom: 1px solid var(--color-line); } .table thead th { padding: 0.5rem 0.875rem; text-align: left; font-family: var(--font-mono); font-size: 0.6875rem; letter-spacing: 0.06em; text-transform: uppercase; color: var(--color-muted); font-weight: 500; } .table tbody tr { border-bottom: 1px solid var(--color-rule); } .table tbody tr:last-child { border-bottom: none; } .table tbody td { padding: 0.625rem 0.875rem; color: var(--color-ink); vertical-align: middle; } /* Alerts -- left-accented banner, per the handoff's severity-bar language. */ .alert { display: flex; align-items: flex-start; gap: 0.75rem; padding: 0.875rem 1rem; border-radius: var(--radius-box); border: 1px solid var(--color-line); background: #fff; font-size: 0.875rem; } .alert-soft { background: var(--color-warn-bg); } .alert-error { background: var(--color-danger-bg); border-color: var(--color-danger-border); color: var(--color-club-dark); } .alert-warning { background: var(--color-warn-bg); border-color: var(--color-warn-border); color: var(--color-warn-deep); } .alert-success { background: var(--color-ok-bg); border-color: var(--color-ok-border); color: var(--color-ok-text); } .alert-info { background: var(--color-info-bg); border-color: var(--color-info-border); color: var(--color-info-text); } /* Avatars -- fallback initials block; a real club.logo uses the branch. */ .avatar > div { border-radius: 999px; overflow: hidden; } .avatar-placeholder > div { display: flex; align-items: center; justify-content: center; background: var(--color-ink); color: #fff; font-family: var(--font-display); font-weight: 800; } /* Progress bars. */ progress.progress { appearance: none; width: 100%; height: 0.375rem; border-radius: 999px; overflow: hidden; background: var(--color-rule); border: none; } progress.progress::-webkit-progress-bar { background: var(--color-rule); } progress.progress::-webkit-progress-value { background: var(--color-ink); } progress.progress::-moz-progress-bar { background: var(--color-ink); } progress.progress-success::-webkit-progress-value { background: var(--color-ok); } progress.progress-success::-moz-progress-bar { background: var(--color-ok); } progress.progress-warning::-webkit-progress-value { background: var(--color-warn); } progress.progress-warning::-moz-progress-bar { background: var(--color-warn); } progress.progress-error::-webkit-progress-value { background: var(--color-club); } progress.progress-error::-moz-progress-bar { background: var(--color-club); } /* Form controls -- rounded-lg per the handoff's field spec (a touch softer than the square 4px chrome, matching "buttons and inputs rounded-lg"). */ .input, .select, .textarea, .file-input { width: 100%; border: 1px solid var(--color-edge); border-radius: 0.5rem; background: #fff; color: var(--color-ink); font-family: var(--font-sans); font-size: 0.875rem; padding: 0.5rem 0.75rem; } /* .input and .select get an explicit, identical height rather than relying on padding plus the browser's own line-height to land on the same box: a , so the same padding alone does not guarantee the same rendered height. appearance: none plus a hand-drawn arrow replaces the native one, since that reserved space was part of what caused the mismatch. 2.25rem, not 2.125rem: at the tighter height, a isn't a flex container) left only ~16px of content box for a 14px line -- descenders (g/y/p/q) rendered clipped at the bottom in some browsers. .btn is bumped the same amount purely for row alignment (a filter bar mixing buttons and inputs) -- flex centring itself was never the problem. */ .input, .select { height: 2.25rem; } .select { padding-right: 2rem; appearance: none; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' fill='none' stroke='%236c7787' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 7.5L10 12.5L15 7.5'/%3E%3C/svg%3E"); background-repeat: no-repeat; background-position: right 0.6rem center; background-size: 1rem; } .input:focus, .select:focus, .textarea:focus { outline: 2px solid var(--color-ice); outline-offset: -1px; border-color: var(--color-ice); } .textarea { height: auto; min-height: 6rem; } .input-error, .select-error, .textarea-error { border-color: var(--color-club); color: var(--color-club-dark); } /* Taller variant for a code-entry input that has fallen back out of the boxed .otp layout below (a recovery code is longer than the boxes fit). */ .input-lg { height: 3rem; font-family: var(--font-mono); font-size: 1.125rem; letter-spacing: 0.2em; text-align: center; } /* Boxed one-time-code input -- recreates daisyUI's `otp`/`otp-lg` layout (a row of character boxes with the real, accessible sitting on top, invisible but still focusable/typeable, so a tap or click still lands on it) without daisyUI. The boxes are drawn as plain sibling s -- see templates/allauth/elements/fields.html, which keeps the exact daisyUI-shaped markup/class names because the same template also renders on a club subdomain, where daisyUI itself (assets/app.css) still styles them. A letter-spacing/text-indent overlay (faking alignment by spacing the real input's own glyphs to match the box pitch) turned out too font-metric-fragile to land reliably -- drifted more with every character typed, in a way that resisted two rounds of tuning. Instead the real input's text is made invisible (`color: transparent`, only the caret shows) and controlpanel/templates/controlpanel/_auth_base.html's `data-otp` script writes each typed character into its own 's textContent -- exact by construction, no font metrics involved. */ .otp { position: relative; display: inline-flex; gap: 0.5rem; } .otp span { display: flex; align-items: center; justify-content: center; width: 2.75rem; height: 3rem; border: 1px solid var(--color-edge); border-radius: 0.5rem; background: #fff; font-family: var(--font-mono); font-size: 1.25rem; color: var(--color-ink); } .otp:focus-within span { border-color: var(--color-ice); } .otp input { position: absolute; inset: 0; width: 100%; height: 100%; padding: 0; border: none; outline: none; background: transparent; color: transparent; caret-color: var(--color-ink); } .otp-lg span { width: 3.25rem; height: 3.5rem; font-size: 1.375rem; } .checkbox { width: 1.125rem; height: 1.125rem; border-radius: 0.25rem; border: 1.5px solid var(--color-stroke); accent-color: var(--color-club); } .toggle { width: 2.5rem; height: 1.375rem; border-radius: 999px; accent-color: var(--color-ok); } .form-control { display: flex; flex-direction: column; } /* Wraps a .label-text (+ an optional trailing badge/alt), a row by default -- see templates/allauth/elements/field.html and fields.html, whose checkbox layout pairs it with justify-start/gap-3 utilities for the checkbox-then-text order. */ .label { display: flex; align-items: center; gap: 0.5rem; padding-bottom: 0.375rem; } .label-text { font-size: 0.8125rem; font-weight: 600; color: var(--color-slate); } .label-text-alt { font-size: 0.75rem; color: var(--color-muted); } /* Links inside table rows / prose. */ .link { color: var(--color-club-dark); text-decoration: none; } .link-hover:hover { text-decoration: underline; } /* A plain horizontal rule between sections -- allauth's `hr` element (templates/allauth/elements/hr.html) renders a bare `
`. */ .divider { margin: 1.5rem 0; border-top: 1px solid var(--color-line); } /* A native
/ disclosure -- allauth's `details` element (templates/allauth/elements/details.html), not currently exercised by any of the pages this redesign covers, restyled defensively since it is shared low-level allauth plumbing like the rest of templates/allauth/elements/. The browser's own default marker on is left alone rather than replaced. */ .collapse { border: 1px solid var(--color-line); border-radius: var(--radius-box); overflow: hidden; } .collapse-title { padding: 0.75rem 1rem; cursor: pointer; font-weight: 600; color: var(--color-ink); } .collapse-content { padding: 0 1rem 1rem; color: var(--color-slate); } .border-base-300 { border-color: var(--color-line); } /* The command bar's account menu (controlpanel/base.html) -- a native
/ disclosure, so the only CSS it actually needs is hiding the browser's own marker triangle; position/spacing are plain utilities at the call site. */ .account-menu > summary { list-style: none; } .account-menu > summary::-webkit-details-marker { display: none; } /* --- daisyUI's semantic "base"/"content" vocabulary, aliased rather than renamed. templates/allauth/elements/*.html, templates/allauth/layouts/base.html and templates/403.html/maintenance.html are shared with the club-branded skin (assets/app.css + real daisyUI, untouched, still in charge there), so they keep daisyUI's own class names rather than controlpanel-specific ones. These give those exact names an industrial-appropriate meaning for pages rendered through this stylesheet; shadow-xl/shadow and .prose are deliberately left undefined -- no shadow and no auto-prose-spacing is the point of the square, hairline-bordered look here, not a gap. --- */ .bg-base-100 { background: #fff; } .border-base-content { border-color: var(--color-line); } .border-base-content\/20 { border-color: var(--color-line); } .text-base-content { color: var(--color-slate); } .text-base-content\/70 { color: var(--color-muted); } .text-base-content\/80 { color: var(--color-slate); } .text-error, .text-error-content { color: var(--color-club-dark); } .text-warning { color: var(--color-warn-deep); } .text-neutral-content { color: #fff; } /* Divide-y utility (used by label/value stat lists). */ .divide-y > * + * { border-top: 1px solid var(--color-rule); } /* Native -based modals -- see controlpanel/templates/controlpanel/_modal_form.html and _confirm_modal.html. No JS beyond the inline .showModal()/method=dialog already in those templates; this only supplies the visual treatment daisyUI would otherwise. */ dialog.modal { margin: auto; padding: 0; border: none; border-radius: var(--radius-box); background: transparent; max-width: none; max-height: none; } dialog.modal::backdrop { background: rgba(11, 18, 32, 0.55); } dialog.modal .modal-box { background: #fff; border: 1px solid var(--color-edge); border-radius: var(--radius-box); padding: 1.5rem; width: 32rem; max-width: 91vw; max-height: 85vh; overflow-y: auto; } dialog.modal.modal-start { margin: 0 0 0 auto; height: 100vh; max-height: none; } dialog.modal.modal-start .modal-box { height: 100%; max-height: none; border-radius: 0; border-left: 1px solid var(--color-edge); } .modal-action { display: flex; justify-content: flex-end; gap: 0.5rem; margin-top: 1.5rem; } .modal-backdrop { display: none; } /* The club crest mark -- fallback for every club until a real Club.logo is uploaded. A plain circle, same convention as .avatar-placeholder elsewhere in this file. Size and colour are set per usage site (bg-* + explicit width/height utilities); this only supplies the shape. */ .crest { border-radius: 999px; } /* A club's own primary_color, applied as a ring around its uploaded logo -- scoped to a locally-set --color-primary custom property (see club_detail.html) rather than a page-wide override, because the control panel itself is never club-branded. */ .ring-primary { box-shadow: 0 0 0 2px #fff, 0 0 0 4px var(--color-primary, var(--color-edge)); } /* Sidebar menu (mobile nav drawer only -- see base.html). */ .menu li a { display: flex; align-items: center; gap: 0.625rem; padding: 0.5rem 0.75rem; border-radius: 0.375rem; font-family: var(--font-display); font-weight: 700; font-size: 0.875rem; letter-spacing: 0.04em; text-transform: uppercase; color: var(--color-slate); } .menu li a:hover { background: var(--color-rule); } .menu li a.menu-active { background: var(--color-club); color: #fff; } .menu-title { padding: 0.5rem 0.75rem 0.25rem; font-family: var(--font-mono); font-size: 0.6875rem; letter-spacing: 0.06em; text-transform: uppercase; color: var(--color-dim); } } /* SubscriptionForm.notes (Change plan / Start billing modal), PlanForm.description (New/Edit * plan modal) and FlagForm.note (Edit feature modal): templatetags/field.html's textarea * branch hard-codes an `h-72` (18rem) utility class on every textarea with no per-field way * to pass rows/height, so the only remaining hook is the rendered `name` attribute -- unique * to these fields within the control panel (no other controlpanel form uses "notes", * "description" or "note"). Kept unlayered, rather than inside `@layer components` above, so * it beats the `.h-72` utility class regardless of selector specificity: Tailwind's utilities * layer is declared after components and always wins at equal or lower specificity, and only * an unlayered rule is guaranteed to outrank it. Every other textarea in the panel * (maintenance message, etc.) is untouched, so this does not shrink anything else. */ textarea[name="notes"], textarea[name="description"], textarea[name="note"] { height: 5rem; }