/* RosterChief member app -- the installed PWA (see design_handoff_rosterchief_platform/ * README.md, "Member mode (mobile, 402x874 reference)"). Its own stylesheet, not shared * with management.css/controlpanel.css/app.css: the component vocabulary (app header, * role switcher, bottom tab bar, hero card) has nothing in common with the desktop * surfaces' daisyUI-shaped one. * * Design tokens copied from management.css's own @theme (built against the same design * doc) rather than re-derived -- same colours, same self-hosted fonts (shared * static/fonts/ directory, one download for every stylesheet). Two differences: * - --radius-box is 14px here (mobile cards), not management's 0.75rem/12px (desktop * "rounded-xl" cards) -- see the design doc's own radius table. * - --color-ice/--color-ice-ink get their own names (management just calls the same * #14B8E8 hex "info", since it has no coach-mode concept) -- the design doc is * explicit that Coach mode uses ice "regardless of club", so it needs a name that * survives club theming rather than colliding with a generic status colour. * * Club theming (design doc, "Club theming"): mobile/templates/mobile/base.html sets * --tenant-club/--tenant-club-content from Club.secondary_color (app header active tab, * primary buttons, hero eyebrow) and --tenant-navy from Club.primary_color where the * club overrides the platform navy header -- same --tenant-* custom-property pattern * management/templates/management/base.html already uses, so both surfaces stay * consistent with each other and with the identity page's own live preview. */ @import "tailwindcss"; @source "../mobile"; @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; --color-navy: var(--tenant-navy, #101e36); --color-steel: #1b2b47; --color-hairline: #1e2b42; --color-paper: #f4f5f7; --color-line: #e3e6eb; --color-rule: #eef0f3; --color-edge: #d6dae1; --color-stroke: #c9cfd8; --color-muted: #6c7787; --color-dim: #8b95a4; --color-slate: #3a4658; --color-on-dark: #93a0b4; --color-on-dark-dim: #7c8aa0; --color-on-dark-faint: #5c6b85; --color-club: var(--tenant-club, #e4002b); --color-club-dark: var(--tenant-club-dark, #b00021); --color-club-content: var(--tenant-club-content, #ffffff); --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: #14b8e8; --color-info-bg: #eaf7fc; --color-info-border: #c3e7f4; --color-info-text: #0a6f91; /* Coach-mode accent -- never club-themed, see the file banner. */ --color-ice: #14b8e8; --color-ice-ink: #04212c; /* Referee sign-up accent -- deliberately distinct from game/training/other's club-red/info-blue/warn-amber (mobile/_calendar_row.html) so a "needs a referee" row stands out from the member's own RSVP rows at a glance. */ --color-referee: #7c4dff; --color-referee-bg: #f1ecff; --color-referee-border: #d9caff; --color-referee-text: #5b2fd6; --color-row-sel: #fff7f8; --color-row-focus: #f4f9ff; --color-row-warn: #fffdf6; --color-subhead: #f8f9fa; --radius-box: 0.875rem; /* 14px -- mobile card radius, see the file banner */ } /* --- fonts: identical set to management.css/controlpanel.css, same self-hosted files. --- */ @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: 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: 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: 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 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: 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: 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: "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: 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; } @layer base { body { background: var(--color-paper); color: var(--color-slate); font-family: var(--font-sans); /* env(safe-area-inset-*) support -- design doc: "The app content starts below a 54px status-bar inset and ends above a 26-30px home-indicator inset -- preserve those safe areas via env(safe-area-inset-*), not fixed padding." */ padding-top: env(safe-area-inset-top); padding-bottom: env(safe-area-inset-bottom); } /* Standard Alpine convention -- hides an x-cloak'd element until Alpine has initialized, so an x-show/x-if starting state never flashes unstyled. */ [x-cloak] { display: none !important; } } @layer components { /* --- App shell -------------------------------------------------------------- */ .app-header { padding: max(env(safe-area-inset-top), 14px) 16px 14px; background: var(--color-navy); color: #fff; flex-shrink: 0; } /* Club logo (img) or initials (span) in the app header -- always a plain circle, unlike management.css's own hexagon crest mark. */ .app-crest { width: 32px; height: 32px; border-radius: 999px; flex-shrink: 0; object-fit: cover; } .app-crest-fallback { background: var(--color-club); color: var(--color-club-content); display: flex; align-items: center; justify-content: center; font-family: var(--font-display); font-weight: 800; font-size: 0.75rem; } /* Scrolls normally, just without the visible scrollbar chrome -- for the person-switcher's horizontally-scrolling chip row. */ .scrollbar-hide { scrollbar-width: none; /* Firefox */ -ms-overflow-style: none; /* old Edge */ } .scrollbar-hide::-webkit-scrollbar { display: none; /* Chrome/Safari/WebKit */ } /* Role switcher -- design doc "Component" table: full-width segmented pill, bg-steel track, active segment bg-white text-ink (member mode). Only rendered when the account holds >=1 staff role -- see mobile/templates/mobile/base.html. */ .role-switcher { display: flex; background: var(--color-steel); border-radius: 999px; padding: 4px; gap: 4px; margin-top: 10px; } .role-switcher-item { flex: 1; height: 36px; border-radius: 999px; display: flex; align-items: center; justify-content: center; font-family: var(--font-display); font-weight: 800; font-size: 0.875rem; letter-spacing: 0.1em; text-transform: uppercase; color: var(--color-on-dark); } .role-switcher-item-active { background: #fff; color: var(--color-ink); } /* Coach mode's own active segment -- design doc: "the role switcher with Coach active (bg-ice)", distinct from member mode's white/ink one above. */ .role-switcher-item-active-ice { background: var(--color-ice); color: var(--color-ice-ink); } /* Bottom tab bar -- design doc: "bg-white border-t border-line pt-2 pb-[26px] (member)... four equal items, 48px tall". pb uses the safe-area inset instead of the doc's fixed 26px, which was standing in for it. */ .tab-bar { flex-shrink: 0; background: #fff; border-top: 1px solid var(--color-line); padding: 8px 8px max(env(safe-area-inset-bottom), 26px); display: flex; } .tab-bar-item { flex: 1; height: 48px; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px; color: var(--color-dim); } .tab-bar-item-active { color: var(--color-club); } .tab-bar-label { font-family: var(--font-display); font-weight: 700; font-size: 0.75rem; letter-spacing: 0.08em; text-transform: uppercase; } /* --- Buttons ------------------------------------------------------------------ */ .btn { display: inline-flex; align-items: center; justify-content: center; gap: 0.5rem; height: 46px; /* design doc: "height 46px mobile" */ padding-inline: 1.25rem; border-radius: 0.5rem; font-family: var(--font-display); font-weight: 800; font-size: 1rem; letter-spacing: 0.1em; text-transform: uppercase; border: none; cursor: pointer; white-space: nowrap; } .btn:disabled { opacity: 0.45; cursor: not-allowed; } .btn-primary { background: var(--color-club); color: #fff; } .btn-dark { background: var(--color-ink); color: #fff; } .btn-positive { background: var(--color-ok); color: #fff; } .btn-secondary { background: #fff; border: 1.5px solid var(--color-stroke); color: var(--color-ink); } .btn-ghost-on-dark { background: rgba(255, 255, 255, 0.15); color: #fff; } /* --- Status pills --------------------------------------------------------------- */ .pill { border-radius: 999px; padding: 5px 10px; font-family: var(--font-display); font-weight: 700; font-size: 0.75rem; letter-spacing: 0.1em; text-transform: uppercase; display: inline-flex; align-items: center; } .pill-ok { background: var(--color-ok-bg); color: var(--color-ok-text); border: 1px solid var(--color-ok-border); } .pill-danger { background: var(--color-danger-bg); color: var(--color-club-dark); border: 1px solid var(--color-danger-border); } .pill-warn { background: var(--color-warn-bg); color: var(--color-warn-text); border: 1px solid var(--color-warn-border); } .pill-info { background: var(--color-info-bg); color: var(--color-info-text); border: 1px solid var(--color-info-border); } .pill-neutral { background: var(--color-rule); color: #4a5566; border: 1px solid #dde1e7; } .pill-referee { background: var(--color-referee-bg); color: var(--color-referee-text); border: 1px solid var(--color-referee-border); } /* --- Person switcher chips (Home's own -- see mobile/templates/mobile/home.html) --- */ .person-chip { display: flex; align-items: center; gap: 6px; background: #fff; border: 1.5px solid var(--color-line); border-radius: 999px; padding: 4px 10px 4px 4px; color: var(--color-muted); flex-shrink: 0; } .person-chip-active { border-color: var(--color-ink); color: var(--color-ink); } .person-chip-avatar { width: 22px; height: 22px; border-radius: 999px; background: var(--color-stroke); color: #fff; display: flex; align-items: center; justify-content: center; font-family: var(--font-display); font-weight: 800; font-size: 0.6875rem; flex-shrink: 0; } .person-chip-active .person-chip-avatar { background: var(--color-club); } .person-chip-label { font-family: var(--font-display); font-weight: 700; font-size: 0.8125rem; letter-spacing: 0.06em; text-transform: uppercase; } /* --- Cards ---------------------------------------------------------------------- */ .m-card { background: #fff; border: 1px solid var(--color-line); border-radius: var(--radius-box); } .m-card-dark { background: var(--color-ink); color: #fff; border-radius: var(--radius-box); } /* --- File input ------------------------------------------------------------------ The bare native control (a browser-chrome "Choose Files" button + status text) clashes with every other input on the page, which are all styled boxes -- same fix as management's own .file-input (assets/management.css), recolored for the mobile palette. ::file-selector-button needs `appearance: none` first or Safari keeps drawing its own bezeled button regardless of the rest of this. Height comes from padding-block, not an explicit height -- the button is shadow content Safari won't vertically center via align-items no matter what, so it floats at the top of any extra box height instead of the middle. Sizing the box around the button's own height (padding-block split evenly: 2.75rem target box - 2 * 1px border - 1.75rem button, halved) keeps the button flush with no leftover space for Safari to mis-center it into (same fix, same reasoning, as management's own .file-input's own comment). */ .m-file-input { display: flex; align-items: center; padding-block: 0.4375rem; width: 100%; border: 1px solid var(--color-stroke); border-radius: 0.5rem; background: var(--color-paper); padding-inline: 0.75rem; color: var(--color-dim); font-size: 0.9375rem; } .m-file-input::file-selector-button, .m-file-input::-webkit-file-upload-button { appearance: none; -webkit-appearance: none; height: 1.75rem; padding-inline: 0.75rem; margin-right: 0.75rem; border: none; border-radius: 0.375rem; background: var(--color-ink); color: #fff; font-family: var(--font-display); font-weight: 800; font-size: 0.6875rem; letter-spacing: 0.08em; text-transform: uppercase; cursor: pointer; transition: opacity 0.15s ease; } .m-file-input:hover::file-selector-button, .m-file-input:hover::-webkit-file-upload-button { opacity: 0.85; } .m-file-input:focus-within { outline: 2px solid var(--color-club); outline-offset: -1px; border-color: var(--color-club); } /* --- Coach mode shell (C1-C6) --------------------------------------------------- Dark ink header (never club-themed) with the role switcher's own active segment in ice-blue (see .role-switcher-item-active-ice above) -- that's the mode's signature accent, not the header background itself. .coach-sheet sits flush below it, edge to edge like the member shell's own header/body join -- no rounded overlap. */ .coach-header { padding: max(env(safe-area-inset-top), 14px) 16px 22px; background: var(--color-ink); color: #fff; flex-shrink: 0; } .coach-sheet { background: var(--color-paper); flex: 1; overflow-y: auto; } .coach-tab-bar { flex-shrink: 0; position: relative; /* anchors the "+" action's popup menu */ background: var(--color-ink); border-top: 1px solid var(--color-hairline); padding: 8px 8px max(env(safe-area-inset-bottom), 26px); display: flex; } .coach-tab-bar-item { flex: 1; height: 48px; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px; color: var(--color-on-dark); } .coach-tab-bar-item-active { color: var(--color-ice); } /* The tab bar's own "+" action -- raised above the bar line in a solid ice circle so it reads as the one prominent action among otherwise-equal nav items, same idea as a FAB parked inside a bottom bar. */ .coach-tab-bar-add { flex: 1; display: flex; align-items: flex-start; justify-content: center; } .coach-tab-bar-add-button { width: 48px; height: 48px; margin-top: -20px; border-radius: 999px; background: var(--color-ice); color: var(--color-ice-ink); display: flex; align-items: center; justify-content: center; border: 4px solid var(--color-ink); box-shadow: 0 2px 10px rgba(0, 0, 0, 0.35); } }