Files
RosterChief/assets/mobile.css
Bernard Siebens 240b6bd345 Fix vertical centering of the coach news form's photo picker button
Same Safari quirk as management's own .file-input (assets/management.css):
the file input's Choose Files button is shadow content that ignores
align-items/flex centering, so an explicit box height left it floating at
the top with dead space below. Fixed the same way -- size the box from
padding-block around the button's own height instead of an explicit height.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-23 17:52:42 +02:00

596 lines
19 KiB
CSS

/* 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);
}
}