/* ==========================================================================
   SSF Crew — design system
   One stylesheet for the whole volunteer portal.
   Sections: 1 tokens · 2 reset · 3 layout · 4 navigation · 5 typography
             6 cards · 7 buttons · 8 forms · 9 tables · 10 dialogs
             11 toasts · 12 states · 13 misc · 14 print
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Tokens
   -------------------------------------------------------------------------- */

:root {
    color-scheme: light;

    /* Brand — deep forest green, flat, no gradient. */
    --brand: #145013;
    --brand-strong: #0d380c;
    --brand-fill: #145013;
    --on-brand: #ffffff;
    --brand-soft: rgba(20, 80, 19, .09);
    --brand-soft-strong: rgba(20, 80, 19, .15);
    --brand-ring: rgba(20, 80, 19, .25);

    /* Neutrals — warm paper. The green stays on accents only, never on surfaces. */
    --bg: #f4f3ef;
    --bg-accent: none;
    --surface: #ffffff;
    --surface-2: #faf9f5;
    --surface-3: #f0efe9;
    --surface-inset: #f6f5f1;
    --overlay: rgba(20, 22, 25, .42);

    --border: #e3e1d9;
    --border-strong: #cdcabf;

    --text: #1b1d1c;
    --text-muted: #5c615e;
    --text-subtle: #878b88;

    /* Semantic — muted, never neon. */
    --ok: #2d7a2b;
    --ok-soft: rgba(45, 122, 43, .11);
    --warn: #9a6f24;
    --warn-soft: rgba(154, 111, 36, .13);
    --danger: #a8433a;
    --danger-soft: rgba(168, 67, 58, .10);
    --info: #3d6a8a;
    --info-soft: rgba(61, 106, 138, .11);

    /* Role accents (also used by shift/timeline colours) */
    --role-bartending: #9a6f24;
    --role-ticketScanning: #2d7a2b;
    --role-security: #a8433a;
    --role-soundLightSetup: #3d6a8a;
    --role-venueSetup: #6b5f8a;
    --role-ansvarlig: #8a5a6e;
    --role-admin: #2b312d;
    --role-ekstern: #7d857f;
    --role-user: #9aa19c;

    /* Shape — restrained corners; softer than square, well short of pill-like. */
    --r-xs: 5px;
    --r-sm: 7px;
    --r-md: 9px;
    --r-lg: 12px;
    --r-xl: 14px;
    --r-pill: 999px;

    /* Elevation — light touch; borders do most of the separating. */
    --shadow-sm: 0 1px 2px rgba(20, 22, 25, .05);
    --shadow-md: 0 4px 12px rgba(20, 22, 25, .06), 0 1px 3px rgba(20, 22, 25, .04);
    --shadow-lg: 0 16px 40px rgba(20, 22, 25, .12), 0 4px 12px rgba(20, 22, 25, .06);

    /* Stacking.
       Leaflet places its panes at 200–700 and its controls at 1000, so every
       piece of app chrome has to clear 1000. Modal <dialog> renders in the
       browser's top layer and needs no z-index at all. */
    --z-subnav: 1100;
    --z-appbar: 1200;
    --z-tabbar: 1250;
    --z-drawer: 1300;
    --z-toast: 1400;

    /* Metrics */
    --appbar-h: 60px;
    --tabbar-h: 62px;
    --container: 1200px;
    --container-narrow: 760px;

    --ease: cubic-bezier(.2, .7, .3, 1);
}

/* Dark palette — applied for explicit choice and for system-dark default. */
@media (prefers-color-scheme: dark) {
    :root:not([data-theme=light]) {
        color-scheme: dark;

        /* #145013 is too dark to read on a dark surface, so the accent moves to
           lighter tints of the same hue. Surfaces stay strictly neutral grey. */
        --brand: #63b45f;
        --brand-strong: #7cc878;
        --brand-fill: #256e23;
        --on-brand: #ffffff;
        --brand-soft: rgba(99, 180, 95, .13);
        --brand-soft-strong: rgba(99, 180, 95, .21);
        --brand-ring: rgba(99, 180, 95, .32);

        --bg: #101112;
        --bg-accent: none;
        --surface: #191b1d;
        --surface-2: #1f2224;
        --surface-3: #26292c;
        --surface-inset: #141618;
        --overlay: rgba(0, 0, 0, .66);

        --border: #303336;
        --border-strong: #43474b;

        --text: #e8eaec;
        --text-muted: #a5abb0;
        --text-subtle: #80868b;

        --ok: #63b45f;
        --ok-soft: rgba(99, 180, 95, .13);
        --warn: #d0a052;
        --warn-soft: rgba(208, 160, 82, .14);
        --danger: #dd8a80;
        --danger-soft: rgba(221, 138, 128, .14);
        --info: #82aecd;
        --info-soft: rgba(130, 174, 205, .13);

        --role-bartending: #d0a052;
        --role-ticketScanning: #63b45f;
        --role-security: #dd8a80;
        --role-soundLightSetup: #82aecd;
        --role-venueSetup: #a99cc4;
        --role-ansvarlig: #c396a8;
        --role-admin: #e8eaec;
        --role-ekstern: #a5abb0;
        --role-user: #80868b;

        --shadow-sm: 0 1px 2px rgba(0, 0, 0, .40);
        --shadow-md: 0 8px 20px rgba(0, 0, 0, .45);
        --shadow-lg: 0 28px 70px rgba(0, 0, 0, .60);
    }
}

[data-theme=dark] {
    color-scheme: dark;

    /* Keep in step with the prefers-color-scheme block above. */
    --brand: #63b45f;
    --brand-strong: #7cc878;
    --brand-fill: #256e23;
    --on-brand: #ffffff;
    --brand-soft: rgba(99, 180, 95, .13);
    --brand-soft-strong: rgba(99, 180, 95, .21);
    --brand-ring: rgba(99, 180, 95, .32);

    --bg: #101112;
    --bg-accent: none;
    --surface: #191b1d;
    --surface-2: #1f2224;
    --surface-3: #26292c;
    --surface-inset: #141618;
    --overlay: rgba(0, 0, 0, .66);

    --border: #303336;
    --border-strong: #43474b;

    --text: #e8eaec;
    --text-muted: #a5abb0;
    --text-subtle: #80868b;

    --ok: #63b45f;
    --ok-soft: rgba(99, 180, 95, .13);
    --warn: #d0a052;
    --warn-soft: rgba(208, 160, 82, .14);
    --danger: #dd8a80;
    --danger-soft: rgba(221, 138, 128, .14);
    --info: #82aecd;
    --info-soft: rgba(130, 174, 205, .13);

    --role-bartending: #d0a052;
    --role-ticketScanning: #63b45f;
    --role-security: #dd8a80;
    --role-soundLightSetup: #82aecd;
    --role-venueSetup: #a99cc4;
    --role-ansvarlig: #c396a8;
    --role-admin: #e8eaec;
    --role-ekstern: #a5abb0;
    --role-user: #80868b;

    --shadow-sm: 0 1px 2px rgba(0, 0, 0, .40);
    --shadow-md: 0 8px 20px rgba(0, 0, 0, .45);
    --shadow-lg: 0 28px 70px rgba(0, 0, 0, .60);
}

/* --------------------------------------------------------------------------
   2. Reset
   -------------------------------------------------------------------------- */

*, *::before, *::after { box-sizing: border-box; }

html {
    -webkit-text-size-adjust: 100%;
    scroll-behavior: smooth;
}

@media (prefers-reduced-motion: reduce) {
    html { scroll-behavior: auto; }
    *, *::before, *::after {
        animation-duration: .001ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: .001ms !important;
    }
}

body {
    margin: 0;
    /* svh, not vh or dvh. With vh a short page is still taller than the
       visible area on a phone and scrolls by exactly the height of the
       address bar, for no reason. dvh would fix that but its value changes
       as the address bar slides, relaying the page on every frame of the
       scroll. svh is the small viewport: always fits, never changes. */
    min-height: 100vh;
    min-height: 100svh;
    font-family: "Manrope", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
    font-size: 16px;
    line-height: 1.55;
    color: var(--text);
    background-color: var(--bg);
    background-image: var(--bg-accent);
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

img, svg, video, canvas { max-width: 100%; height: auto; display: block; }

h1, h2, h3, h4, h5, h6, p, figure, dl, dd { margin: 0; }
ul, ol { margin: 0; padding: 0; }

a {
    color: var(--brand);
    text-decoration: none;
    text-underline-offset: 3px;
}
a:hover { text-decoration: underline; }

button, input, select, textarea { font: inherit; color: inherit; }

hr {
    border: 0;
    height: 1px;
    background: var(--border);
    margin: 24px 0;
}

:focus-visible {
    outline: 2px solid var(--brand);
    outline-offset: 2px;
    border-radius: 4px;
}

::selection { background: var(--brand-soft-strong); }

/* --------------------------------------------------------------------------
   3. Layout
   -------------------------------------------------------------------------- */

.page {
    width: min(100%, var(--container));
    margin-inline: auto;
    padding: 24px 16px calc(32px + env(safe-area-inset-bottom));
}
.page--narrow { width: min(100%, var(--container-narrow)); }

body.has-tabbar .page { padding-bottom: calc(var(--tabbar-h) + 32px + env(safe-area-inset-bottom)); }

.stack     { display: grid; gap: 16px; }
.stack--sm { gap: 10px; }
.stack--lg { gap: 24px; }

.row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px;
}
.row--between { justify-content: space-between; }
.row--end { justify-content: flex-end; }
.row--top { align-items: flex-start; }
.spacer { flex: 1 1 auto; }

.grid { display: grid; gap: 16px; }
.grid--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.grid--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.grid--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.grid--auto { grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); }
.grid--sidebar { grid-template-columns: minmax(0, 1fr) minmax(0, 1.4fr); }

@media (max-width: 900px) {
    .grid--3, .grid--4, .grid--sidebar { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 640px) {
    .grid--2, .grid--3, .grid--4, .grid--sidebar { grid-template-columns: 1fr; }
    .page { padding: 16px 12px calc(24px + env(safe-area-inset-bottom)); }
}

/* Centred single-panel screens (login, reset, error…) */
.shell-centered {
    min-height: 100vh;
    min-height: 100dvh;
    display: grid;
    place-items: center;
    padding: 24px 16px;
    position: relative;
}

.backdrop-media {
    position: fixed;
    inset: 0;
    z-index: -2;
    overflow: hidden;
    background: #070b16;
}
.backdrop-media video,
.backdrop-media img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    filter: saturate(.95) brightness(.62);
}
.backdrop-media::after {
    content: "";
    position: absolute;
    inset: 0;
    background:
        linear-gradient(135deg, rgba(10, 12, 13, .84), rgba(14, 17, 18, .58) 45%, rgba(10, 12, 13, .86)),
        radial-gradient(circle at 15% 10%, rgba(20, 80, 19, .30), transparent 42%);
}

/* --------------------------------------------------------------------------
   4. Navigation
   -------------------------------------------------------------------------- */

.appbar {
    position: sticky;
    top: 0;
    z-index: var(--z-appbar);
    background: color-mix(in srgb, var(--surface) 88%, transparent);
    backdrop-filter: saturate(1.4) blur(14px);
    border-bottom: 1px solid var(--border);
}

.appbar__inner {
    width: min(100%, var(--container));
    margin-inline: auto;
    min-height: var(--appbar-h);
    padding: 8px 16px;
    display: flex;
    align-items: center;
    gap: 12px;
}

.brand {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    font-weight: 800;
    letter-spacing: -.02em;
    color: var(--text);
    white-space: nowrap;
}
.brand:hover { text-decoration: none; }
.brand__mark {
    width: 34px;
    height: 34px;
    flex: none;
    display: grid;
    place-items: center;
    border-radius: 11px;
    background: var(--brand-fill);
    color: #fff;
    font-size: .82rem;
    font-weight: 800;
    letter-spacing: .02em;
    box-shadow: var(--shadow-sm);
}
.brand__text { display: grid; line-height: 1.15; }
.brand__text small {
    font-size: .68rem;
    font-weight: 700;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--text-subtle);
}

.nav {
    display: flex;
    align-items: center;
    gap: 2px;
    margin-left: auto;
}
.nav__link {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding: 9px 12px;
    border-radius: var(--r-sm);
    color: var(--text-muted);
    font-size: .93rem;
    font-weight: 700;
    white-space: nowrap;
    transition: background-color .16s var(--ease), color .16s var(--ease);
}
.nav__link:hover {
    background: var(--surface-3);
    color: var(--text);
    text-decoration: none;
}
.nav__link.is-active {
    background: var(--brand-soft);
    color: var(--brand);
}
.nav__link .i { font-size: 1.15em; }

.icon-btn {
    display: inline-grid;
    place-items: center;
    width: 40px;
    height: 40px;
    flex: none;
    border: 1px solid var(--border);
    border-radius: var(--r-sm);
    background: var(--surface);
    color: var(--text-muted);
    cursor: pointer;
    transition: background-color .16s var(--ease), color .16s var(--ease), border-color .16s var(--ease);
}
.icon-btn:hover { background: var(--surface-3); color: var(--text); border-color: var(--border-strong); }
.icon-btn .i { font-size: 1.3rem; line-height: 1; }

.nav-toggle { display: none; }

/* Drawer (mobile / admin) */
.drawer {
    position: fixed;
    inset: 0;
    z-index: var(--z-drawer);
    display: none;
}
.drawer[open] { display: block; }
.drawer__scrim {
    position: absolute;
    inset: 0;
    background: var(--overlay);
    animation: fade-in .18s var(--ease);
}
.drawer__panel {
    position: absolute;
    inset: 0 0 0 auto;
    width: min(340px, 86vw);
    padding: 16px 16px calc(24px + env(safe-area-inset-bottom));
    background: var(--surface);
    border-left: 1px solid var(--border);
    box-shadow: var(--shadow-lg);
    overflow-y: auto;
    display: grid;
    align-content: start;
    gap: 6px;
    animation: slide-in .22s var(--ease);
}
.drawer__head {
    display: flex;
    align-items: center;
    gap: 12px;
    padding-bottom: 12px;
    margin-bottom: 6px;
    border-bottom: 1px solid var(--border);
}
.drawer .nav__link {
    padding: 12px 14px;
    font-size: 1rem;
    border-radius: var(--r-md);
}

@keyframes fade-in { from { opacity: 0 } to { opacity: 1 } }
@keyframes slide-in { from { transform: translateX(14px); opacity: 0 } to { transform: none; opacity: 1 } }

/* Secondary tab strip (admin sections) */
.subnav {
    position: sticky;
    top: var(--appbar-h);
    z-index: var(--z-subnav);
    background: color-mix(in srgb, var(--bg) 90%, transparent);
    backdrop-filter: blur(10px);
    border-bottom: 1px solid var(--border);
}
.subnav__inner {
    width: min(100%, var(--container));
    margin-inline: auto;
    padding: 10px 16px;
    display: flex;
    gap: 6px;
    overflow-x: auto;
    scrollbar-width: none;
}
.subnav__inner::-webkit-scrollbar { display: none; }
.subnav__link {
    padding: 8px 14px;
    border-radius: var(--r-pill);
    border: 1px solid transparent;
    color: var(--text-muted);
    font-size: .9rem;
    font-weight: 700;
    white-space: nowrap;
}
.subnav__link:hover { background: var(--surface); color: var(--text); text-decoration: none; }
.subnav__link.is-active {
    background: var(--surface);
    border-color: var(--border);
    color: var(--text);
    box-shadow: var(--shadow-sm);
}

/* Bottom tab bar (mobile, volunteers) */
.tabbar {
    display: none;
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: var(--z-tabbar);
    padding-bottom: env(safe-area-inset-bottom);
    /* Opaque and unblurred on purpose. A translucent bar has to resample
       whatever is behind it on every scroll frame, and on phones that repaint
       lags the scroll — the bar visibly comes unstuck from the bottom edge. */
    background: var(--surface);
    border-top: 1px solid var(--border);
    /* Its own compositing layer, so scrolling the page never repaints it. */
    transform: translateZ(0);
}
.tabbar__inner {
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: 1fr;
    min-height: var(--tabbar-h);
}
.tabbar__link {
    display: grid;
    place-items: center;
    gap: 2px;
    padding: 8px 4px;
    color: var(--text-subtle);
    font-size: .68rem;
    font-weight: 700;
}
.tabbar__link:hover { text-decoration: none; }
.tabbar__link .i { font-size: 1.45rem; line-height: 1; }
.tabbar__link.is-active { color: var(--brand); }

@media (max-width: 860px) {
    .nav--primary { display: none; }
    .nav-toggle { display: inline-grid; margin-left: auto; }
    .appbar__inner { padding-inline: 12px; }
}
@media (max-width: 640px) {
    body.has-tabbar .tabbar { display: block; }
    .brand__text small { display: none; }
}

/* --------------------------------------------------------------------------
   5. Typography
   -------------------------------------------------------------------------- */

.h1, h1 { font-size: clamp(1.6rem, 3.4vw, 2.3rem); font-weight: 800; letter-spacing: -.03em; line-height: 1.12; }
.h2, h2 { font-size: clamp(1.25rem, 2.4vw, 1.6rem); font-weight: 800; letter-spacing: -.02em; line-height: 1.2; }
.h3, h3 { font-size: 1.12rem; font-weight: 800; letter-spacing: -.01em; }
.h4, h4 { font-size: 1rem; font-weight: 800; }

.lead { font-size: 1.05rem; color: var(--text-muted); max-width: 68ch; }
.muted { color: var(--text-muted); }
.subtle { color: var(--text-subtle); }
.small { font-size: .88rem; }
.tiny { font-size: .78rem; }
.strong { font-weight: 700; color: var(--text); }
.mono { font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace; }
.nowrap { white-space: nowrap; }
.center { text-align: center; }
.truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.eyebrow {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding: 5px 11px;
    border-radius: var(--r-pill);
    background: var(--brand-soft);
    color: var(--brand);
    font-size: .74rem;
    font-weight: 800;
    letter-spacing: .09em;
    text-transform: uppercase;
}

.page-head {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    justify-content: space-between;
    gap: 14px;
    margin-bottom: 20px;
}
.page-head__text { display: grid; gap: 6px; }

.prose { max-width: 72ch; display: grid; gap: 14px; color: var(--text-muted); }
.prose h2 { color: var(--text); margin-top: 12px; }
.prose h3 { color: var(--text); }
.prose ul, .prose ol { padding-left: 20px; display: grid; gap: 6px; }
.prose strong { color: var(--text); }

/* --------------------------------------------------------------------------
   6. Cards & surfaces
   -------------------------------------------------------------------------- */

.card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--r-xl);
    box-shadow: var(--shadow-sm);
    overflow: hidden;
}
.card--flat { box-shadow: none; }
.card--pad { padding: 20px; }
.card--glass {
    background: color-mix(in srgb, var(--surface) 92%, transparent);
    backdrop-filter: blur(18px);
    box-shadow: var(--shadow-lg);
}
.card--accent { position: relative; }

.card__head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 18px 20px;
    border-bottom: 1px solid var(--border);
}
.card__title { display: grid; gap: 3px; }
.card__body { padding: 20px; }
.card__body--tight { padding: 12px; }
.card__foot {
    padding: 14px 20px;
    border-top: 1px solid var(--border);
    background: var(--surface-2);
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    justify-content: flex-end;
}

.panel {
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--r-lg);
    padding: 16px;
}

.note {
    display: flex;
    gap: 12px;
    padding: 14px 16px;
    border-radius: var(--r-lg);
    border: 1px solid var(--border);
    background: var(--surface-2);
    color: var(--text-muted);
}
.note .i { font-size: 1.3rem; line-height: 1.2; flex: none; }
.note--info { border-color: color-mix(in srgb, var(--info) 35%, var(--border)); background: var(--info-soft); }
.note--info .i { color: var(--info); }
.note--ok { border-color: color-mix(in srgb, var(--ok) 35%, var(--border)); background: var(--ok-soft); }
.note--ok .i { color: var(--ok); }
.note--warn { border-color: color-mix(in srgb, var(--warn) 40%, var(--border)); background: var(--warn-soft); }
.note--warn .i { color: var(--warn); }
.note--danger { border-color: color-mix(in srgb, var(--danger) 38%, var(--border)); background: var(--danger-soft); }
.note--danger .i { color: var(--danger); }

/* Stat tiles */
.stat {
    display: grid;
    gap: 4px;
    padding: 18px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--r-lg);
    box-shadow: var(--shadow-sm);
}
.stat__label {
    font-size: .76rem;
    font-weight: 800;
    letter-spacing: .07em;
    text-transform: uppercase;
    color: var(--text-subtle);
}
.stat__value {
    font-size: clamp(1.6rem, 4vw, 2.1rem);
    font-weight: 800;
    letter-spacing: -.03em;
    line-height: 1.1;
    font-variant-numeric: tabular-nums;
}
.stat__hint { font-size: .84rem; color: var(--text-muted); }
.stat--ok .stat__value { color: var(--ok); }
.stat--warn .stat__value { color: var(--warn); }
.stat--danger .stat__value { color: var(--danger); }

/* Definition list used across detail views */
.dl {
    display: grid;
    gap: 10px;
}
.dl__row {
    display: grid;
    grid-template-columns: minmax(110px, auto) minmax(0, 1fr);
    gap: 6px 16px;
    align-items: baseline;
}
.dl__key { font-size: .84rem; font-weight: 700; color: var(--text-subtle); }
.dl__val { min-width: 0; word-break: break-word; }
@media (max-width: 480px) {
    .dl__row { grid-template-columns: 1fr; gap: 2px; }
}

/* --------------------------------------------------------------------------
   7. Buttons
   -------------------------------------------------------------------------- */

.btn {
    --btn-bg: var(--surface);
    --btn-fg: var(--text);
    --btn-bd: var(--border-strong);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    padding: 11px 17px;
    min-height: 44px;
    border: 1px solid var(--btn-bd);
    border-radius: var(--r-md);
    background: var(--btn-bg);
    color: var(--btn-fg);
    font-size: .95rem;
    font-weight: 700;
    line-height: 1.2;
    text-align: center;
    cursor: pointer;
    user-select: none;
    transition: background-color .16s var(--ease), border-color .16s var(--ease), color .16s var(--ease), opacity .16s var(--ease);
}
/* Each variant supplies its own hover fill, so a danger button never greys out. */
.btn:hover { text-decoration: none; background: var(--btn-bg-hover, var(--surface-3)); }
.btn[disabled], .btn.is-disabled, .btn[aria-disabled=true] {
    opacity: .5;
    pointer-events: none;
}
.btn .i { font-size: 1.2em; line-height: 1; }

.btn--primary {
    --btn-bg: var(--brand-fill);
    --btn-bg-hover: var(--brand-strong);
    --btn-fg: var(--on-brand);
    --btn-bd: transparent;
}

.btn--soft {
    --btn-bg: var(--brand-soft);
    --btn-bg-hover: var(--brand-soft-strong);
    --btn-fg: var(--brand);
    --btn-bd: transparent;
}
.btn--ghost {
    --btn-bg: transparent;
    --btn-bg-hover: var(--surface-3);
    --btn-fg: var(--text-muted);
    --btn-bd: transparent;
}
.btn--ghost:hover { --btn-fg: var(--text); }

.btn--ok {
    --btn-bg: var(--ok);
    --btn-bg-hover: color-mix(in srgb, var(--ok) 86%, #000);
    --btn-fg: #fff;
    --btn-bd: transparent;
}
.btn--danger {
    --btn-bg: var(--danger);
    --btn-bg-hover: color-mix(in srgb, var(--danger) 86%, #000);
    --btn-fg: #fff;
    --btn-bd: transparent;
}
.btn--danger-soft {
    --btn-bg: var(--danger-soft);
    --btn-bg-hover: color-mix(in srgb, var(--danger) 18%, transparent);
    --btn-fg: var(--danger);
    --btn-bd: color-mix(in srgb, var(--danger) 30%, transparent);
}
.btn--warn {
    --btn-bg: var(--warn-soft);
    --btn-bg-hover: color-mix(in srgb, var(--warn) 22%, transparent);
    --btn-fg: var(--warn);
    --btn-bd: color-mix(in srgb, var(--warn) 35%, transparent);
}

.btn--sm { padding: 7px 12px; min-height: 36px; font-size: .86rem; border-radius: var(--r-sm); }
.btn--lg { padding: 14px 24px; min-height: 52px; font-size: 1.02rem; }
.btn--block { width: 100%; }
.btn--icon { padding: 0; width: 44px; min-height: 44px; }
.btn--sm.btn--icon { width: 36px; }

.btn-group { display: inline-flex; flex-wrap: wrap; gap: 8px; }

.segmented {
    display: inline-flex;
    padding: 4px;
    gap: 2px;
    border: 1px solid var(--border);
    border-radius: var(--r-pill);
    background: var(--surface-2);
}
.segmented button,
.segmented a {
    display: inline-flex;
    align-items: center;
    padding: 8px 15px;
    border: 0;
    border-radius: var(--r-pill);
    background: transparent;
    color: var(--text-muted);
    font-size: .88rem;
    font-weight: 700;
    cursor: pointer;
    white-space: nowrap;
}
.segmented a:hover { text-decoration: none; color: var(--text); }
.segmented button.is-active,
.segmented a.is-active { background: var(--surface); color: var(--text); box-shadow: var(--shadow-sm); }

/* --------------------------------------------------------------------------
   8. Forms
   -------------------------------------------------------------------------- */

.field { display: grid; gap: 7px; min-width: 0; }
.field__label { font-size: .89rem; font-weight: 700; }
.field__label .req { color: var(--danger); }
.field__hint { font-size: .84rem; color: var(--text-muted); }
.field__error { font-size: .84rem; color: var(--danger); font-weight: 600; }

.input, .select, .textarea {
    width: 100%;
    min-height: 46px;
    padding: 11px 14px;
    border: 1px solid var(--border-strong);
    border-radius: var(--r-md);
    background: var(--surface);
    color: var(--text);
    transition: border-color .16s var(--ease), box-shadow .16s var(--ease);
}
.input::placeholder, .textarea::placeholder { color: var(--text-subtle); }
.input:focus, .select:focus, .textarea:focus {
    outline: none;
    border-color: var(--brand);
    box-shadow: 0 0 0 4px var(--brand-ring);
}
.input:disabled, .select:disabled, .textarea:disabled {
    background: var(--surface-inset);
    color: var(--text-subtle);
    cursor: not-allowed;
}
.textarea { min-height: 110px; resize: vertical; line-height: 1.55; }

.select {
    appearance: none;
    padding-right: 40px;
    background-image: linear-gradient(45deg, transparent 50%, currentColor 50%),
                      linear-gradient(135deg, currentColor 50%, transparent 50%);
    background-position: calc(100% - 20px) calc(50% + 2px), calc(100% - 15px) calc(50% + 2px);
    background-size: 5px 5px, 5px 5px;
    background-repeat: no-repeat;
}

.input-group { display: flex; gap: 8px; align-items: stretch; flex-wrap: wrap; }
.input-group > .input, .input-group > .select { flex: 1 1 200px; }

.input-icon { position: relative; display: block; }
.input-icon .i {
    position: absolute;
    left: 13px;
    top: 50%;
    translate: 0 -50%;
    color: var(--text-subtle);
    font-size: 1.25rem;
    pointer-events: none;
}
.input-icon .input { padding-left: 42px; }
.input-icon__action {
    position: absolute;
    right: 6px;
    top: 50%;
    translate: 0 -50%;
    width: 34px;
    height: 34px;
    display: grid;
    place-items: center;
    border: 0;
    border-radius: var(--r-sm);
    background: transparent;
    color: var(--text-subtle);
    cursor: pointer;
}
.input-icon__action:hover { background: var(--surface-3); color: var(--text); }

/* Choice cards (radio / checkbox) */
.choices { display: grid; gap: 10px; }
.choices--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.choices--auto { grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); }
@media (max-width: 520px) { .choices--2, .choices--auto { grid-template-columns: 1fr; } }

.choice {
    display: grid;
    grid-template-columns: 20px minmax(0, 1fr);
    align-items: start;
    gap: 12px;
    padding: 14px 15px;
    border: 1px solid var(--border);
    border-radius: var(--r-md);
    background: var(--surface);
    cursor: pointer;
    transition: border-color .16s var(--ease), background-color .16s var(--ease), box-shadow .16s var(--ease);
}
.choice:hover { border-color: var(--brand); background: var(--brand-soft); }
.choice input { margin: 2px 0 0; width: 18px; height: 18px; accent-color: var(--brand); cursor: pointer; }
.choice__text { display: grid; gap: 2px; min-width: 0; }
.choice__text b { font-weight: 700; }
.choice__text span { font-size: .86rem; color: var(--text-muted); }
.choice:has(input:checked) {
    border-color: var(--brand);
    background: var(--brand-soft);
    box-shadow: 0 0 0 1px var(--brand);
}
.choice:has(input:focus-visible) { outline: 2px solid var(--brand); outline-offset: 2px; }

/* Inline check */
.check {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    cursor: pointer;
    font-weight: 600;
}
.check input { width: 18px; height: 18px; accent-color: var(--brand); cursor: pointer; }

/* Switch */
.switch { display: inline-flex; align-items: center; gap: 10px; cursor: pointer; font-weight: 600; }
.switch input { position: absolute; opacity: 0; pointer-events: none; }
.switch__track {
    width: 46px;
    height: 27px;
    flex: none;
    border-radius: var(--r-pill);
    background: var(--border-strong);
    position: relative;
    transition: background-color .18s var(--ease);
}
.switch__track::after {
    content: "";
    position: absolute;
    top: 3px;
    left: 3px;
    width: 21px;
    height: 21px;
    border-radius: 50%;
    background: #fff;
    box-shadow: var(--shadow-sm);
    transition: translate .18s var(--ease);
}
.switch input:checked + .switch__track { background: var(--brand); }
.switch input:checked + .switch__track::after { translate: 19px 0; }
.switch input:focus-visible + .switch__track { outline: 2px solid var(--brand); outline-offset: 2px; }

/* Multi-select chips */
.chips {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}
.chip {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding: 8px 13px;
    border: 1px solid var(--border);
    border-radius: var(--r-pill);
    background: var(--surface);
    font-size: .88rem;
    font-weight: 700;
    color: var(--text-muted);
    cursor: pointer;
    transition: all .16s var(--ease);
}
.chip:hover { border-color: var(--brand); color: var(--brand); }
.chip input { position: absolute; opacity: 0; width: 0; height: 0; }
.chip:has(input:checked) {
    background: var(--brand-fill);
    border-color: transparent;
    color: var(--on-brand);
}
.chip:has(input:focus-visible) { outline: 2px solid var(--brand); outline-offset: 2px; }

/* Editor toolbar for rich-text areas */
.editor { border: 1px solid var(--border-strong); border-radius: var(--r-md); overflow: hidden; background: var(--surface); }
.editor__bar {
    display: flex;
    flex-wrap: wrap;
    gap: 2px;
    padding: 6px;
    border-bottom: 1px solid var(--border);
    background: var(--surface-2);
}
.editor__bar button {
    width: 34px;
    height: 34px;
    display: grid;
    place-items: center;
    border: 0;
    border-radius: var(--r-xs);
    background: transparent;
    color: var(--text-muted);
    cursor: pointer;
}
.editor__bar button:hover { background: var(--surface-3); color: var(--text); }
.editor__area {
    min-height: 180px;
    max-height: 45vh;
    overflow-y: auto;
    padding: 14px;
    outline: none;
    line-height: 1.6;
}
.editor__area:empty::before { content: attr(data-placeholder); color: var(--text-subtle); }
.editor__area ul, .editor__area ol { padding-left: 22px; }

/* --------------------------------------------------------------------------
   9. Tables (desktop grid → mobile cards)
   -------------------------------------------------------------------------- */

.table-tools {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px;
    padding: 14px 16px;
    border-bottom: 1px solid var(--border);
}
.table-tools .input-icon { flex: 1 1 220px; max-width: 380px; }

.table-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }

.table {
    width: 100%;
    border-collapse: collapse;
    font-size: .92rem;
}
.table th, .table td {
    padding: 12px 16px;
    text-align: left;
    vertical-align: middle;
}
.table thead th {
    position: sticky;
    top: 0;
    z-index: 1;
    background: var(--surface-2);
    border-bottom: 1px solid var(--border);
    font-size: .76rem;
    font-weight: 800;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--text-subtle);
    white-space: nowrap;
}
.table thead th.is-sortable { cursor: pointer; user-select: none; }
.table thead th.is-sortable:hover { color: var(--text); }
.table thead th .sort-ind { opacity: .35; margin-left: 5px; }
.table thead th[aria-sort] .sort-ind { opacity: 1; color: var(--brand); }
.table tbody tr { border-bottom: 1px solid var(--border); }
.table tbody tr:last-child { border-bottom: 0; }
.table tbody tr.is-clickable { cursor: pointer; }
.table tbody tr.is-clickable:hover { background: var(--surface-2); }
.table td.num { font-variant-numeric: tabular-nums; }
.table .cell-actions { display: flex; flex-wrap: wrap; gap: 6px; justify-content: flex-end; }

/* Free-text remarks shown inline in a row. Clamped by default so one long
   note cannot push every other row off the screen. */
.cell-note {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    overflow: hidden;
    max-width: 40ch;
    white-space: pre-line;
    overflow-wrap: anywhere;
}
/* Hovering the note lifts the clamp so the whole remark can be read without
   opening the profile. The row simply grows — nothing is overlaid, so the
   horizontally scrolling wrapper around the table cannot clip it. */
.cell-note:hover,
.table tbody tr:focus .cell-note {
    -webkit-line-clamp: none;
    line-clamp: none;
}
.cell-tags { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 5px; }

/* Identity columns, kept narrow so the remarks column gets the room. A grid
   item needs min-width:0 before an ellipsis can kick in. */
.cell-name { max-width: 190px; }
.cell-contact { max-width: 210px; }
.cell-name > *,
.cell-contact > * { min-width: 0; }
/* Names wrap rather than truncate: "anywhere" also caps the column's
   min-content width, so one long surname cannot widen the whole column. */
.cell-name > * { overflow-wrap: anywhere; }

.table-foot {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    padding: 12px 16px;
    border-top: 1px solid var(--border);
    font-size: .88rem;
    color: var(--text-muted);
}
.pager { display: flex; gap: 6px; align-items: center; }

@media (max-width: 760px) {
    .table thead { display: none; }
    .table, .table tbody, .table tr, .table td { display: block; width: 100%; }
    .table tbody tr {
        border: 1px solid var(--border);
        border-radius: var(--r-lg);
        margin-bottom: 10px;
        padding: 6px 4px;
        background: var(--surface);
    }
    .table td {
        display: grid;
        grid-template-columns: minmax(88px, 38%) minmax(0, 1fr);
        gap: 6px 12px;
        align-items: baseline;
        padding: 8px 12px;
    }
    .table td::before {
        content: attr(data-label);
        font-size: .74rem;
        font-weight: 800;
        letter-spacing: .05em;
        text-transform: uppercase;
        color: var(--text-subtle);
    }
    .table td:not([data-label]) { grid-template-columns: 1fr; }
    .table .cell-actions { justify-content: flex-start; }

    /* Cards have the width, and a phone has no hover: show everything. */
    .cell-name, .cell-contact { max-width: none; }
    .cell-contact .truncate { white-space: normal; overflow-wrap: anywhere; }
    .cell-note { -webkit-line-clamp: none; line-clamp: none; max-width: none; }
}

/* --------------------------------------------------------------------------
   10. Dialogs
   -------------------------------------------------------------------------- */

dialog.modal {
    width: min(560px, calc(100vw - 24px));
    max-height: min(86vh, 900px);
    padding: 0;
    border: 1px solid var(--border);
    border-radius: var(--r-xl);
    background: var(--surface);
    color: var(--text);
    box-shadow: var(--shadow-lg);
    overflow: hidden;
}
dialog.modal--lg { width: min(900px, calc(100vw - 24px)); }
dialog.modal--sm { width: min(430px, calc(100vw - 24px)); }
dialog.modal::backdrop {
    background: var(--overlay);
    backdrop-filter: blur(3px);
}
dialog.modal[open] { animation: modal-in .18s var(--ease); }
@keyframes modal-in {
    from { opacity: 0; transform: translateY(10px) scale(.985); }
    to { opacity: 1; transform: none; }
}

.modal__inner { display: grid; grid-template-rows: auto minmax(0, 1fr) auto; max-height: inherit; }
.modal__head {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 18px 20px;
    border-bottom: 1px solid var(--border);
}
.modal__head h2 { flex: 1; min-width: 0; }
.modal__body { padding: 20px; overflow-y: auto; }
.modal__foot {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    justify-content: flex-end;
    padding: 14px 20px;
    border-top: 1px solid var(--border);
    background: var(--surface-2);
}
.modal--danger .modal__head { background: var(--danger-soft); border-bottom-color: color-mix(in srgb, var(--danger) 30%, var(--border)); }
.modal--danger .modal__head h2 { color: var(--danger); }

@media (max-width: 560px) {
    dialog.modal {
        width: 100vw;
        max-width: 100vw;
        max-height: 92dvh;
        margin: auto auto 0;
        border-radius: var(--r-xl) var(--r-xl) 0 0;
        border-bottom: 0;
    }
    dialog.modal[open] { animation: sheet-in .22s var(--ease); }
    @keyframes sheet-in { from { transform: translateY(24px); opacity: 0 } to { transform: none; opacity: 1 } }
    .modal__foot { padding-bottom: calc(14px + env(safe-area-inset-bottom)); }
    .modal__foot .btn { flex: 1 1 140px; }
}

/* --------------------------------------------------------------------------
   11. Toasts
   -------------------------------------------------------------------------- */

.toasts {
    position: fixed;
    z-index: var(--z-toast);
    right: 16px;
    bottom: calc(16px + env(safe-area-inset-bottom));
    display: grid;
    /* Rows keep their own height and stack upward from the bottom. Without
       these a grid's default `align-content: normal` stretches its rows to fill
       the container, which makes every toast as tall as the stack. */
    align-content: end;
    grid-auto-rows: max-content;
    height: auto;
    gap: 10px;
    width: min(380px, calc(100vw - 32px));
    pointer-events: none;
}
body.has-tabbar .toasts { bottom: calc(var(--tabbar-h) + 16px + env(safe-area-inset-bottom)); }

.toast {
    pointer-events: auto;
    display: flex;
    align-items: flex-start;
    gap: 12px;
    padding: 14px 16px;
    border: 1px solid var(--border);
    border-left: 4px solid var(--brand);
    border-radius: var(--r-md);
    background: var(--surface);
    box-shadow: var(--shadow-lg);
    animation: toast-in .2s var(--ease);
}
.toast.is-leaving { animation: toast-out .18s var(--ease) forwards; }
@keyframes toast-in { from { opacity: 0; transform: translateY(10px) } to { opacity: 1; transform: none } }
@keyframes toast-out { to { opacity: 0; transform: translateY(6px) } }
.toast .i { font-size: 1.35rem; line-height: 1.1; flex: none; color: var(--brand); }
.toast__text { flex: 1; min-width: 0; display: grid; gap: 2px; }
.toast__title { font-weight: 700; }
.toast__msg { font-size: .88rem; color: var(--text-muted); }
.toast__close {
    border: 0;
    background: transparent;
    color: var(--text-subtle);
    cursor: pointer;
    padding: 0;
    font-size: 1.2rem;
    line-height: 1;
}
.toast--ok { border-left-color: var(--ok); }
.toast--ok .i { color: var(--ok); }
.toast--warn { border-left-color: var(--warn); }
.toast--warn .i { color: var(--warn); }
.toast--danger { border-left-color: var(--danger); }
.toast--danger .i { color: var(--danger); }

@media (max-width: 560px) {
    .toasts { left: 12px; right: 12px; width: auto; }
}

/* Top-layer variant.
   A modal <dialog> renders in the browser's top layer, which no z-index can
   reach — so where the Popover API exists, app.js promotes the stack there too
   and toasts stay visible above an open dialog. The UA stylesheet forces
   inset/margin/border/padding/background on [popover], so the placement has to
   be restated rather than inherited. */
.toasts[popover] {
    position: fixed;
    top: auto;
    left: auto;
    right: 16px;
    bottom: calc(16px + env(safe-area-inset-bottom));
    width: min(380px, calc(100vw - 32px));
    /* The UA sheet sets height: fit-content on [popover]; left alone it lets the
       grid rows stretch and every toast becomes the height of the stack. */
    height: auto;
    max-height: none;
    display: grid;
    align-content: end;
    grid-auto-rows: max-content;
    gap: 10px;
    margin: 0;
    padding: 0;
    border: 0;
    background: transparent;
    color: inherit;
    overflow: visible;
}
body.has-tabbar .toasts[popover] {
    bottom: calc(var(--tabbar-h) + 16px + env(safe-area-inset-bottom));
}
@media (max-width: 560px) {
    .toasts[popover] { left: 12px; right: 12px; width: auto; }
}

/* --------------------------------------------------------------------------
   12. Badges & states
   -------------------------------------------------------------------------- */

.badge {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 4px 10px;
    border-radius: var(--r-pill);
    background: var(--surface-3);
    color: var(--text-muted);
    font-size: .78rem;
    font-weight: 800;
    letter-spacing: .01em;
    white-space: nowrap;
}
.badge--ok { background: var(--ok-soft); color: var(--ok); }
.badge--warn { background: var(--warn-soft); color: var(--warn); }
.badge--danger { background: var(--danger-soft); color: var(--danger); }
.badge--info { background: var(--info-soft); color: var(--info); }
.badge--brand { background: var(--brand-soft); color: var(--brand); }
.badge--solid { background: var(--brand-fill); color: var(--on-brand); }

.dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: currentColor;
    flex: none;
}
.dot--pulse { animation: dot-pulse 1.6s ease-in-out infinite; }
@keyframes dot-pulse {
    0%, 100% { opacity: 1; transform: scale(1); }
    50% { opacity: .45; transform: scale(1.35); }
}

.role-tag {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    font-weight: 700;
    font-size: .86rem;
}
.role-tag::before {
    content: "";
    width: 9px;
    height: 9px;
    border-radius: 3px;
    background: var(--role-color, var(--text-subtle));
    flex: none;
}

.empty {
    display: grid;
    justify-items: center;
    gap: 10px;
    padding: 46px 20px;
    text-align: center;
    color: var(--text-muted);
}
.empty .i {
    font-size: 2.6rem;
    color: var(--text-subtle);
    opacity: .7;
}
.empty h3 { color: var(--text); }
.empty p { max-width: 44ch; }

.skeleton {
    border-radius: var(--r-sm);
    background: linear-gradient(90deg, var(--surface-3) 25%, var(--surface-2) 37%, var(--surface-3) 63%);
    background-size: 400% 100%;
    animation: shimmer 1.4s ease infinite;
    min-height: 14px;
}
@keyframes shimmer { from { background-position: 100% 0 } to { background-position: 0 0 } }

.spinner {
    width: 20px;
    height: 20px;
    border: 2px solid var(--brand-soft-strong);
    border-top-color: var(--brand);
    border-radius: 50%;
    animation: spin .8s linear infinite;
    flex: none;
}
.spinner--lg { width: 40px; height: 40px; border-width: 3px; }
@keyframes spin { to { transform: rotate(360deg) } }

.loading-row {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 28px 20px;
    justify-content: center;
    color: var(--text-muted);
}

.progress {
    height: 8px;
    border-radius: var(--r-pill);
    background: var(--surface-3);
    overflow: hidden;
}
.progress__bar {
    height: 100%;
    width: 0;
    border-radius: inherit;
    background: var(--brand-fill);
    transition: width .3s var(--ease);
}

/* --------------------------------------------------------------------------
   13. Feature blocks
   -------------------------------------------------------------------------- */

/* Shift / event cards used on the volunteer dashboard */
.item-card {
    display: grid;
    gap: 12px;
    padding: 18px;
    border: 1px solid var(--border);
    border-left: 4px solid var(--item-color, var(--brand));
    border-radius: var(--r-lg);
    background: var(--surface);
    box-shadow: var(--shadow-sm);
}
.item-card__head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; }
.item-card__title { font-size: 1.05rem; font-weight: 800; letter-spacing: -.01em; }
.item-card__meta { display: grid; gap: 8px; font-size: .9rem; }
.item-card__meta div { display: flex; gap: 9px; align-items: flex-start; color: var(--text-muted); }
.item-card__meta .i { color: var(--text-subtle); font-size: 1.15rem; line-height: 1.25; flex: none; }
.item-card__actions { display: flex; flex-wrap: wrap; gap: 8px; }

.timerange {
    display: inline-flex;
    align-items: baseline;
    gap: 8px;
    font-weight: 700;
    color: var(--text);
}
.timerange small { font-weight: 600; color: var(--text-muted); }

/* Map */
.map {
    height: 100%;
    min-height: 320px;
    border-radius: var(--r-lg);
    overflow: hidden;
    border: 1px solid var(--border);
    background: var(--surface-2);
}
.leaflet-container { font: inherit; background: var(--surface-2); }
.leaflet-popup-content-wrapper, .leaflet-popup-tip {
    background: var(--surface);
    color: var(--text);
    box-shadow: var(--shadow-md);
}
.leaflet-popup-content { font-weight: 600; }
[data-theme=dark] .leaflet-tile { filter: brightness(.72) contrast(1.05) hue-rotate(180deg) invert(1); }
@media (prefers-color-scheme: dark) {
    :root:not([data-theme=light]) .leaflet-tile { filter: brightness(.72) contrast(1.05) hue-rotate(180deg) invert(1); }
}

/* QR display */
.qr-panel {
    display: grid;
    justify-items: center;
    gap: 18px;
    padding: 26px;
    text-align: center;
}
/* The code plate stays black-on-white in every theme.
   A QR needs a light "quiet zone" of at least four modules around it; on a dark
   surface without one, readers fail to find the finder patterns. This is the
   gate at the venue, so the ring is deliberately generous and the plate opts out
   of any theme, forced-colour or auto-dark treatment. */
.qr-frame {
    padding: 24px;
    border-radius: var(--r-lg);
    box-shadow: var(--shadow-md);
    line-height: 0;

    /* `only` forbids the user agent from overriding the scheme — this is the
       opt-out from Android/Samsung system-wide forced dark mode, which would
       otherwise repaint the plate and make the code unscannable. */
    color-scheme: only light;

    /* Belt and braces: forced-dark repaints background-COLOURS but leaves
       background-IMAGES alone, so the white plate is painted as a gradient.
       The colour stays as a fallback for engines that ignore the above. */
    background-color: #ffffff;
    background-image: linear-gradient(#ffffff, #ffffff);

    forced-color-adjust: none;
    -webkit-print-color-adjust: exact;
    print-color-adjust: exact;
}
.qr-frame img,
.qr-frame svg,
.qr-frame canvas {
    width: min(288px, 68vw);
    height: auto;
    background-color: #ffffff;
    background-image: linear-gradient(#ffffff, #ffffff);
}
.qr-token {
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 1.05rem;
    letter-spacing: .18em;
    padding: 10px 16px;
    border-radius: var(--r-md);
    background: var(--surface-inset);
    border: 1px solid var(--border);
    word-break: break-all;
}

/* Scanner */
.scanner {
    display: grid;
    gap: 16px;
    justify-items: center;
}
.scanner__view {
    width: min(460px, 100%);
    border-radius: var(--r-lg);
    overflow: hidden;
    border: 1px solid var(--border);
    background: #000;
}
.scanner__view video { width: 100%; display: block; }
.scan-result {
    width: min(460px, 100%);
    display: grid;
    gap: 6px;
    padding: 18px;
    border-radius: var(--r-lg);
    text-align: center;
    border: 1px solid var(--border);
    background: var(--surface-2);
}
.scan-result--ok { background: var(--ok-soft); border-color: color-mix(in srgb, var(--ok) 40%, var(--border)); }
.scan-result--err { background: var(--danger-soft); border-color: color-mix(in srgb, var(--danger) 40%, var(--border)); }
.scan-result__title { font-size: 1.35rem; font-weight: 800; }
.scan-result--ok .scan-result__title { color: var(--ok); }
.scan-result--err .scan-result__title { color: var(--danger); }

/* Timeline (custom gantt).
   Grid children run: corner, hours, then name/lane per person. */
.tl {
    border: 1px solid var(--border);
    border-radius: var(--r-lg);
    background: var(--surface);
    overflow: hidden;
}
.tl__scroll { overflow: auto; max-height: 70vh; }
.tl__grid {
    display: grid;
    grid-template-columns: var(--tl-label, 180px) var(--tl-track, 1200px);
    min-width: max-content;
}
.tl__corner {
    position: sticky;
    top: 0;
    left: 0;
    z-index: 4;
    padding: 10px 14px;
    background: var(--surface-2);
    border-right: 1px solid var(--border);
    border-bottom: 1px solid var(--border);
    font-size: .72rem;
    font-weight: 800;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--text-subtle);
}
.tl__hours {
    position: sticky;
    top: 0;
    z-index: 3;
    display: flex;
    background: var(--surface-2);
    border-bottom: 1px solid var(--border);
}
.tl__hour {
    flex: 0 0 var(--tl-step, 80px);
    padding: 10px 0 10px 7px;
    font-size: .72rem;
    font-weight: 700;
    color: var(--text-subtle);
    border-left: 1px solid var(--border);
    white-space: nowrap;
}
.tl__name {
    position: sticky;
    left: 0;
    z-index: 2;
    padding: 8px 14px;
    background: var(--surface);
    border-right: 1px solid var(--border);
    border-bottom: 1px solid var(--border);
    font-size: .86rem;
    font-weight: 700;
    display: grid;
    align-content: center;
    gap: 1px;
    min-height: 50px;
}
.tl__name small { font-weight: 600; color: var(--text-subtle); font-size: .74rem; }
.tl__lane {
    position: relative;
    min-height: 50px;
    border-bottom: 1px solid var(--border);
    background-image: repeating-linear-gradient(to right,
        var(--border) 0 1px, transparent 1px var(--tl-step, 80px));
}
.tl__grid > :nth-child(4n+3),
.tl__grid > :nth-child(4n+4) { background-color: var(--surface-2); }
.tl__bar {
    position: absolute;
    top: 8px;
    bottom: 8px;
    min-width: 26px;
    display: flex;
    align-items: center;
    padding: 0 9px;
    border-radius: var(--r-sm);
    background: var(--bar-color, var(--brand));
    color: #fff;
    font-size: .76rem;
    font-weight: 800;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
    box-shadow: var(--shadow-sm);
    cursor: default;
}
.tl__now {
    position: absolute;
    top: 0;
    bottom: 0;
    width: 2px;
    background: var(--danger);
    z-index: 1;
    pointer-events: none;
}

/* Assignment picker list */
.picker { display: grid; gap: 6px; max-height: 46vh; overflow-y: auto; padding-right: 4px; }
.picker__item {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto auto;
    align-items: center;
    gap: 12px;
    padding: 11px 13px;
    border: 1px solid var(--border);
    border-radius: var(--r-md);
    background: var(--surface);
    text-align: left;
    cursor: pointer;
    transition: border-color .16s var(--ease), background-color .16s var(--ease);
}
.picker__item:hover { border-color: var(--brand); background: var(--brand-soft); }
.picker__item[data-status=warning] { border-color: color-mix(in srgb, var(--ok) 45%, var(--border)); background: var(--ok-soft); }
.picker__item[data-status=danger] { opacity: .78; }
.picker__name { display: grid; gap: 2px; min-width: 0; }
.picker__name b { font-weight: 700; }
.picker__name span { font-size: .8rem; color: var(--text-muted); }

/* Charts */
.chart-box { position: relative; height: 300px; }
.chart-box--tall { height: 340px; }

/* Two panels that sit side by side and stack on small screens */
.split {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
}
.split > * + * { border-left: 1px solid var(--border); }
@media (max-width: 800px) {
    .split { grid-template-columns: 1fr; }
    .split > * + * { border-left: 0; border-top: 1px solid var(--border); }
}
.pad-lg { padding: clamp(22px, 4vw, 40px); }
.surface-2 { background: var(--surface-2); }

/* Utility helpers */
.hidden { display: none !important; }
.visually-hidden {
    position: absolute !important;
    width: 1px; height: 1px;
    margin: -1px; padding: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
    border: 0;
}
.mt-0 { margin-top: 0 } .mt-1 { margin-top: 8px } .mt-2 { margin-top: 16px } .mt-3 { margin-top: 24px }
.mb-0 { margin-bottom: 0 } .mb-1 { margin-bottom: 8px } .mb-2 { margin-bottom: 16px } .mb-3 { margin-bottom: 24px }
.w-full { width: 100% }
.text-ok { color: var(--ok) } .text-warn { color: var(--warn) } .text-danger { color: var(--danger) }

/* --------------------------------------------------------------------------
   14. Print (QR pages get printed / screenshotted at the gate)
   -------------------------------------------------------------------------- */

@media print {
    .appbar, .subnav, .tabbar, .toasts, .btn, .no-print { display: none !important; }
    body { background: #fff; color: #000; }
    .card { box-shadow: none; border-color: #ccc; }
    .qr-frame { box-shadow: none; }
}
