/* Tunafly's type (static/brand/BRAND.md, NEXT_FIXES_PLAN wave 41): Source Sans 3
   for text, Fraunces 600 for headings and the wordmark -- free (SIL OFL), served
   from our own site (the CSP allows fonts from 'self' only; it works offline). */
@font-face {
    font-family: "Source Sans 3"; font-style: normal; font-weight: 400 700; font-display: swap;
    src: url("../fonts/source-sans-3-latin.woff2") format("woff2");
}
@font-face {
    font-family: "Fraunces"; font-style: normal; font-weight: 600; font-display: swap;
    src: url("../fonts/fraunces-600-latin.woff2") format("woff2");
}
@font-face {
    font-family: "Fraunces"; font-style: italic; font-weight: 600; font-display: swap;
    src: url("../fonts/fraunces-600-italic-latin.woff2") format("woff2");
}

/* The brand's palette (static/brand/BRAND.md): ivory paper, slate ink, a clay
   accent. Clay itself is 2.96:1 on ivory, too light for text, so links and
   buttons take a deeper clay (--primary, 4.5:1 either way); clay stays the
   icon's and the accents' (wave 41, decision a). */
:root {
    --ivory: #FAF9F5;
    --slate: #141413;
    --clay: #D97757;
    --muted: #5E5D59;
    --line: #DDD9CE;
    --bar-lift: max(0.4rem, env(safe-area-inset-bottom));
    --font-body: "Source Sans 3", "Segoe UI", system-ui, -apple-system, BlinkMacSystemFont, Roboto, sans-serif,
                 "Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji";
    --font-heading: "Fraunces", Georgia, "Times New Roman", serif,
                    "Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji";
    --primary: #C0502B;
    --primary-dark: #A3431F;
    --on-primary: #ffffff;           /* text on --primary: 4.6:1 */
    --success: #3f7d4e;
    --on-success: #ffffff;           /* text on --success: 4.9:1 (the match card's winner's box) */
    --warning: #c27a1a;
    --danger: #b9382f;
    --on-danger: #ffffff;            /* text on --danger: 5.7:1 (wave 43) */
    --info: #3a7891;
    --bg: var(--ivory);
    --bg-card: #ffffff;
    --text: var(--slate);
    --text-muted: var(--muted);
    --border: var(--line);
    --surface-muted: #f0eee6;
    --tint: #f7ede6;
    --sidebar-bg: #efede4;
    --sidebar-text: #57554f;
    --sidebar-strong: var(--slate);
    --sidebar-hover: rgba(31, 30, 29, 0.06);
    --sidebar-line: rgba(31, 30, 29, 0.08);
    --sidebar-section: #8f8b81;
    --sidebar-active: var(--primary);
    /* Role accent (role-colours feature): signals which role you're acting as,
       on top of whatever personal theme is chosen. Visitors fall back to the
       theme's primary. One owner: role sets --role-accent, the theme keeps the
       rest of the palette. */
    --role-accent: var(--primary);
    --role-accent-contrast: #ffffff;
    /* State colours (NEXT_FIXES_PLAN R-7): used only to say a match's or a
       to-do's state, never as decoration. */
    --state-your-turn: #d97706;
    --state-waiting: #b45309;
    --state-disputed: #dc2626;
    --state-final: #16a34a;
}

/* Role accents: amber admin, clay organizer, blue official, teal player (role-colours feature). */
[data-role="admin"]     { --role-accent: #946117; --role-accent-contrast: #ffffff; }
[data-role="organizer"] { --role-accent: var(--primary); --role-accent-contrast: var(--on-primary); }
[data-role="player"]    { --role-accent: #3d7a6e; --role-accent-contrast: #ffffff; }
[data-role="official"]  { --role-accent: #4a5fa8; --role-accent-contrast: #ffffff; }
/* On the dark theme the role colours are text on dark (the bottom bar's current page) as well as a chip's fill: lighter,
   with slate on the chip (wave 43; they were 2.2:1 to 3.6:1 as text). The organizer's is the theme's primary. */
html[data-theme="dark"][data-role="admin"]    { --role-accent: #d18a23; --role-accent-contrast: var(--slate); }
html[data-theme="dark"][data-role="player"]   { --role-accent: #53a796; --role-accent-contrast: var(--slate); }
html[data-theme="dark"][data-role="official"] { --role-accent: #8a99cc; --role-accent-contrast: var(--slate); }

/* ── Dark theme ───────────────────────────────────── */
html[data-theme="dark"] {
    --state-your-turn: #fbbf24;
    --state-waiting: #fcd34d;
    --state-disputed: #f87171;
    --state-final: #4ade80;
    /* A hair lighter than clay, for links on the dark cards (4.5:1; clay is 4.24:1 there); slate text on it. */
    --primary: #DB7E5F;
    --primary-dark: #E58D70;
    --on-primary: var(--slate);
    --success: #6fb07f;
    --on-success: var(--slate);      /* 7.2:1; white was 2.6:1 */
    --warning: #e0a44a;
    --danger: #e5786d;
    --on-danger: var(--slate);       /* 6.4:1; white was 2.9:1 */
    --info: #7fb3c8;
    --bg: #262624;
    --bg-card: #30302e;
    --text: var(--ivory);
    --text-muted: #a6a39a;
    --border: #45433f;
    --surface-muted: #2b2b29;
    --tint: #3d322c;
    --sidebar-bg: #1f1e1d;
    --sidebar-text: #b7b4ab;
    --sidebar-strong: #faf9f5;
    --sidebar-hover: rgba(255, 255, 255, 0.06);
    --sidebar-line: rgba(255, 255, 255, 0.08);
    --sidebar-section: #85827a;
    --sidebar-active: var(--clay);
}
/* The messages as dark tints with light words, not bright boxes (the walkthrough, 2026-10-18). */
html[data-theme="dark"] .alert-success { background: color-mix(in srgb, var(--success) 18%, var(--bg-card)); color: var(--text); border-color: color-mix(in srgb, var(--success) 45%, var(--bg-card)); }
html[data-theme="dark"] .alert-error { background: color-mix(in srgb, var(--danger) 18%, var(--bg-card)); color: var(--text); border-color: color-mix(in srgb, var(--danger) 45%, var(--bg-card)); }
html[data-theme="dark"] .alert-warning { background: color-mix(in srgb, var(--warning) 18%, var(--bg-card)); color: var(--text); border-color: color-mix(in srgb, var(--warning) 45%, var(--bg-card)); }
html[data-theme="dark"] .alert-info { background: color-mix(in srgb, var(--info) 18%, var(--bg-card)); color: var(--text); border-color: color-mix(in srgb, var(--info) 45%, var(--bg-card)); }
html[data-theme="dark"] th { background: #30302e; color: #a6a39a; }
html[data-theme="dark"] tr:hover { background: #3d322c; }
html[data-theme="dark"] .btn-outline { background: #30302e; border-color: #45433f; color: #f5f4ee; }
html[data-theme="dark"] .btn-outline:hover { background: #45433f; }
html[data-theme="dark"] .form-control,
html[data-theme="dark"] .form-select { background: #30302e; color: #f5f4ee; border-color: #45433f; }
html[data-theme="dark"] .filters { background: #30302e; }
html[data-theme="dark"] .filters select,
html[data-theme="dark"] .filters input { background: #262624; color: #f5f4ee; border-color: #45433f; }
html[data-theme="dark"] .slot-option { background: #30302e; }
html[data-theme="dark"] .slot-team-schedule { background: #262624; }
html[data-theme="dark"] .empty-state { background: #30302e; }

/* Semantic highlight classes (theme-aware) */
.row-selected { background: var(--tint); }
.row-me       { background: var(--tint); font-weight: 600; }
.row-advance  { background: #d1fae5; }
.info-panel   { background: var(--surface-muted); border: 1px solid var(--border); border-radius: 6px; padding: 0.6rem 0.75rem; }
.info-success { background: #f0fdf4; border: 1px solid #bbf7d0; border-radius: 6px; }
.info-warning { background: #fff7ed; border: 1px solid #fed7aa; border-radius: 6px; }

html[data-theme="dark"] .row-selected { background: #3d322c; color: #f5f4ee; }
html[data-theme="dark"] .row-me       { background: #3d322c; color: #f5f4ee; }
html[data-theme="dark"] .row-advance  { background: #14532d; color: #bbf7d0; }
.row-advance a  { color: inherit; }
html[data-theme="dark"] .row-advance a { color: #bbf7d0; }
html[data-theme="dark"] .info-panel   { background: #30302e; }
html[data-theme="dark"] .info-success { background: #052e16; border-color: #166534; color: #bbf7d0; }
html[data-theme="dark"] .info-warning { background: #1c1407; border-color: #92400e; color: #fcd34d; }

/* Analytics bars and win/loss/draw form pills (theme-aware) */
.bar-track { background: var(--border); border-radius: 4px; }
.form-pill { width: 28px; height: 28px; border-radius: 50%; display: inline-flex;
             align-items: center; justify-content: center; font-size: 0.75rem; font-weight: 700; }
.form-pill.is-win  { background: #d1fae5; color: #065f46; }
.form-pill.is-loss { background: #fecaca; color: #991b1b; }
.form-pill.is-draw { background: var(--border); color: var(--text-muted); }
html[data-theme="dark"] .form-pill.is-win  { background: #064e3b; color: #a7f3d0; }
html[data-theme="dark"] .form-pill.is-loss { background: #7f1d1d; color: #fecaca; }
/* A walkover's "W/O" (batch 4, 2026-10-24): a pill, not a circle, so the three characters fit. */
.wo-mark { margin-left: 0.2em; font-size: 0.75rem; font-weight: 600; color: var(--text-muted); white-space: nowrap; }
.form-pill.is-walkover { width: auto; min-width: 28px; padding: 0 0.4rem; border-radius: 999px; }

/* ── Emerald theme ────────────────────────────────── */
html[data-theme="emerald"] {
    --primary: #047857;              /* wave 43: #059669 was 3.6:1 as a link, 3.8:1 under white */
    --primary-dark: #065f46;
    --success: #16a34a;
    --on-success: #141413;           /* 5.6:1; white was 3.3:1 */
    --warning: #d97706;
    --danger: #dc2626;
    --info: #0891b2;
    --bg: #f0fdf4;
    --bg-card: #ffffff;
    --text: #14532d;
    --text-muted: #6b7280;
    --border: #bbf7d0;
    --sidebar-bg: #14532d;
    --sidebar-text: #bbf7d0;
    --sidebar-active: #059669;
    --surface-muted: #f1f5f9;
    --tint: #eff6ff;
    --sidebar-strong: #ffffff;
    --sidebar-hover: rgba(255, 255, 255, 0.08);
    --sidebar-line: rgba(255, 255, 255, 0.1);
    --sidebar-section: rgba(255, 255, 255, 0.4);
}

/* ── Purple theme ─────────────────────────────────── */
html[data-theme="purple"] {
    --primary: #7c3aed;
    --primary-dark: #6d28d9;
    --success: #16a34a;
    --on-success: #141413;           /* 5.6:1; white was 3.3:1 */
    --warning: #d97706;
    --danger: #dc2626;
    --info: #0891b2;
    --bg: #faf5ff;
    --bg-card: #ffffff;
    --text: #3b0764;
    --text-muted: #7c3aed;
    --border: #e9d5ff;
    --sidebar-bg: #3b0764;
    --sidebar-text: #e9d5ff;
    --sidebar-active: #7c3aed;
    --surface-muted: #f1f5f9;
    --tint: #eff6ff;
    --sidebar-strong: #ffffff;
    --sidebar-hover: rgba(255, 255, 255, 0.08);
    --sidebar-line: rgba(255, 255, 255, 0.1);
    --sidebar-section: rgba(255, 255, 255, 0.4);
}

/* ── Theme picker widget ──────────────────────────── */
.theme-picker {
    display: flex;
    align-items: center;
    gap: 0.4rem;
}

* { box-sizing: border-box; margin: 0; padding: 0; }

/* Links in the theme's accent, not the browser's blue. */
a { color: var(--primary); text-underline-offset: 2px; }
/* Buttons, fields and pickers in the page's type too (BRAND.md: Source Sans 3 for body and UI). */
button, input, select, textarea { font-family: inherit; }
/* Help under a field and other small print, at 14 px rather than the browser's 13.3 (wave 43). Printed sheets keep
   the browser's own, a step below the text around it. */
small { font-size: 0.875rem; }
/* Sign-up's first and last name side by side, one above the other on a narrow phone. */
.signup-names { display: grid; grid-template-columns: 1fr 1fr; gap: 0 0.75rem; }
@media (max-width: 360px) { .signup-names { grid-template-columns: 1fr; } }
.signup-names-note { margin: -0.4rem 0 0.9rem; }
/* Every fold's heading opens it: a hand, not the text cursor (the owner, 2026-10-14: "Type both scores" on the desk
   showed the text cursor; eight folds each set it for itself, the others didn't). */
summary { cursor: pointer; }
/* A button that opens its second step (the live board's first Share): no fold marker beside it. */
.board-share-step > summary { list-style: none; }
.board-share-step > summary::-webkit-details-marker { display: none; }
.print-page small { font-size: smaller; }

body {
    font-family: var(--font-body);
    background: var(--bg);
    color: var(--text);
    line-height: 1.5;
}

/* Layout */
.app-layout {
    display: flex;
    min-height: 100vh;
}

.sidebar {
    width: 240px;
    background: var(--sidebar-bg);
    color: var(--sidebar-text);
    position: fixed;
    top: 0;
    left: 0;
    bottom: 0;
    overflow-y: auto;
    z-index: 100;
    transition: transform 0.3s;
}

/* The brand (wave 13, D-99): the mark, the wordmark and, where there is
   room, the tagline. One partial draws it: core/partials/brand.html. */
.brand { display: inline-flex; align-items: center; gap: 0.6rem; color: inherit; line-height: 1.15; }
/* The app icon at 32px, the smallest the full icon is drawn (BRAND.md); the gap keeps a quarter of it clear. */
.brand-mark { width: 32px; height: 32px; flex: none; }
/* The icons on their clay tile, on slate on the dark theme (static/brand/BRAND.md, "On the site"). */
.brand-mark--dark, .takes-icon--dark { display: none; }
html[data-theme="dark"] .brand-mark--light, html[data-theme="dark"] .takes-icon--light { display: none; }
html[data-theme="dark"] .brand-mark--dark { display: block; }
html[data-theme="dark"] .takes-icon--dark { display: inline; }
/* The "Takes" icon, beside Tournament News only (BRAND.md). */
.takes-icon { width: 1.25em; height: 1.25em; vertical-align: -0.28em; margin-right: 0.3em; }
.brand-text { display: flex; flex-direction: column; min-width: 0; }
.brand-name { font-family: var(--font-heading); font-size: 1.3rem; font-weight: 600; letter-spacing: -0.01em;
              color: var(--text); }
.brand-tagline { font-size: 0.75rem; font-weight: 500; color: var(--text-muted); letter-spacing: 0.01em;
                 margin-top: 0.1rem; white-space: nowrap; }
.brand--large { flex-direction: column; gap: 1rem; text-align: center; }    /* a quarter of the tile clear (BRAND.md) */
.brand--large .brand-mark { width: 64px; height: 64px; }
.brand--large .brand-name { font-size: 2rem; }
.brand--large .brand-tagline { font-size: 0.95rem; margin-top: 0.25rem; }

.sidebar { border-right: 1px solid var(--border); }
.sidebar-brand {
    padding: 1.1rem 1.25rem;
    border-bottom: 1px solid var(--sidebar-line);
    display: flex;
    align-items: center;
    text-decoration: none;
}
.sidebar-brand .brand-name { color: var(--sidebar-strong); }
.sidebar-brand .brand-tagline { color: var(--sidebar-section); }
/* On a phone the sidebar is hidden; the mark alone starts the top bar. */
.topbar-brand { display: none; }
.login-brand { display: flex; justify-content: center; margin: 0.5rem 0 1.5rem; text-decoration: none; }

.sidebar-nav { padding: 0.5rem 0; }

.sidebar-nav a, .sidebar-nav .nav-item {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0.6rem 1.25rem;
    color: var(--sidebar-text);
    text-decoration: none;
    font-size: 0.9rem;
    transition: all 0.15s;
}

.sidebar-nav a:hover {
    background: var(--sidebar-hover);
    color: var(--sidebar-strong);
}

.sidebar-nav a.active {
    background: rgba(37,99,235,0.18);
    background: color-mix(in srgb, var(--role-accent) 16%, transparent);
    color: var(--sidebar-strong);
    border-left: 3px solid var(--role-accent);
    padding-left: calc(1.25rem - 3px);
}

/* Who is signed in and Log out, at the foot of the sidebar (wave 53): pinned to its bottom, always on screen. A phone
   has Log out at the end of More; Me keeps its own. */
.sidebar { display: flex; flex-direction: column; }
.sidebar-account { margin-top: auto; padding: 0.75rem 0 0.5rem; border-top: 1px solid var(--sidebar-line); }
.sidebar-account-who { margin: 0; padding: 0 1.25rem 0.25rem; font-size: 0.875rem; color: var(--sidebar-text); }
.sidebar-account-name { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
                        color: var(--sidebar-strong); font-weight: 600; font-size: 0.9rem; }
.logout-form { margin: 0; }
.logout-button { display: flex; align-items: center; gap: 0.75rem; width: 100%; margin: 0; border: 0; background: none;
                 font: inherit; text-align: left; cursor: pointer; }
.sidebar .logout-button { padding: 0.6rem 1.25rem; color: var(--sidebar-text); font-size: 0.9rem; transition: all 0.15s; }
.sidebar .logout-button:hover { background: var(--sidebar-hover); color: var(--sidebar-strong); }

.icon { width: 20px; height: 20px; flex: none; }
.nav-badge {
    margin-left: auto; min-width: 1.25rem; padding: 0 0.4rem; border-radius: 999px;
    background: var(--danger, #dc2626); color: var(--on-danger, #fff); font-size: 0.75rem; font-weight: 700;
    line-height: 1.25rem; text-align: center;
}
.topbar-tournament-name { font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.topbar-bell { display: inline-flex; align-items: center; }
.bell-count { position: absolute; top: -5px; right: -5px; min-width: 1.15rem; height: 1.15rem; padding: 0 0.25rem;
    border-radius: 999px; background: var(--danger); color: var(--on-danger); font-size: 0.75rem; font-weight: 700;
    display: flex; align-items: center; justify-content: center; line-height: 1; box-sizing: border-box; }
.btn-link { background: none; border: 0; padding: 0; color: var(--primary); cursor: pointer; font: inherit; text-decoration: underline; }

/* The phone menu (NEXT_FIXES_PLAN D-54): the same items as the sidebar, as a bottom bar. */
.bottom-bar { display: none; }
.me-list { display: flex; flex-direction: column; gap: 0.6rem; max-width: 640px; }
.me-list .card { margin-bottom: 0; }
/* A row wraps rather than run off the side when text is enlarged (wave 43: Theme's Save at 200%). */
.me-row { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center; gap: 0.75rem; padding: 0.85rem 1rem;
          color: inherit; text-decoration: none; }
.me-block .me-row { padding-bottom: 0.4rem; }
/* Hide names is on (wave 42): a strip at the top of every page, so nobody forgets it. */
.names-hidden-strip { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 0.5rem;
    margin: 0 0 1rem; padding: 0.6rem 0.9rem; border-radius: 8px; background: var(--tint); color: var(--text);
    border: 1px solid var(--border); }
.me-sub { display: block; padding: 0.35rem 1rem; }
.me-block .me-sub:last-child { padding-bottom: 0.85rem; }
.welcome-steps { margin: 0 0 1.25rem 1.25rem; display: grid; gap: 0.5rem; }

.sidebar-section {
    padding: 0.75rem 1.25rem 0.25rem;
    font-size: 0.75rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--sidebar-section);
}

.main-content {
    margin-left: 240px;
    flex: 1;
    min-width: 0;
}

.topbar {
    background: var(--bg-card);
    border-bottom: 1px solid var(--border);
    border-top: 3px solid transparent;
    padding: 0.75rem 1.5rem;
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 1rem;
    position: sticky;
    top: 0;
    z-index: 50;
}

.setup-note { margin: 0 0 0.6rem; font-weight: 600; }
.setup-advanced { margin: 0.25rem 0 0.75rem; }
.setup-advanced > summary { font-weight: 600; }
.setup-summary ul { margin: 0 0 0.5rem 1.1rem; }
.setup-summary li { margin: 0.2rem 0; }
.setup-section { font-size: 1rem; margin: 1.25rem 0 0.6rem; padding-bottom: 0.3rem; border-bottom: 1px solid var(--border); }
[data-role] .topbar { border-top-color: var(--role-accent); }
.topbar-left { display: flex; align-items: center; gap: 1rem; }
/* The role chip: which role you are acting as, in the role accent colour. */
.role-chip { display: inline-block; background: var(--role-accent); color: var(--role-accent-contrast, #fff);
    font-size: 0.75rem; font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase;
    padding: 0.12rem 0.55rem; border-radius: 999px; white-space: nowrap; }
.topbar-right { display: flex; align-items: center; gap: 1rem; }

.content { padding: 1.5rem; max-width: 1400px; }

.page-title {
    font-size: 1.6rem;
    font-weight: 600;
    margin-bottom: 1.5rem;
}

/* Headings in the serif, text in the sans (D-100). */
h1, h2, .page-title { font-family: var(--font-heading); font-weight: 600; letter-spacing: -0.01em; }
table, .stat-value { font-variant-numeric: tabular-nums; }

/* Cards */
.card {
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: 12px;
    margin-bottom: 1rem;
}

.card-header {
    padding: 0.75rem 1rem;
    border-bottom: 1px solid var(--border);
    font-weight: 600;
    display: flex;
    justify-content: space-between;
    align-items: center;
}

.card-body { padding: 1rem; }

/* Grid */
.grid { display: grid; gap: 1rem; }
/* A grid column may shrink below its widest table (the table scrolls
   inside its .table-container instead of widening the page). */
.grid > * { min-width: 0; }
.grid-2 { grid-template-columns: repeat(2, 1fr); }
.grid-3 { grid-template-columns: repeat(3, 1fr); }
.grid-4 { grid-template-columns: repeat(4, 1fr); }

/* Stats */
.stat-card {
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: 8px;
    padding: 1rem;
    text-align: center;
}

.stat-value { font-size: 2rem; font-weight: 700; color: var(--primary); }
.stat-label { font-size: 0.8rem; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.05em; }

/* Tables */
.table-container { overflow-x: auto; }

table {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.9rem;
}

th {
    background: var(--surface-muted);
    padding: 0.6rem 0.75rem;
    text-align: left;
    font-weight: 600;
    font-size: 0.8rem;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: var(--text-muted);
    border-bottom: 2px solid var(--border);
    white-space: nowrap;
}

td {
    padding: 0.6rem 0.75rem;
    border-bottom: 1px solid var(--border);
    vertical-align: middle;
}

tr:hover { background: var(--tint); }

table a {
    color: var(--primary);
    text-decoration: none;
    font-weight: 500;
}
table a:hover { text-decoration: underline; }

/* Badges */
.badge {
    display: inline-block;
    padding: 0.15rem 0.5rem;
    border-radius: 9999px;
    font-size: 0.75rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.03em;
}

.badge-upcoming { background: #dbeafe; color: #1d4ed8; }
.badge-in_progress { background: #fef3c7; color: #92400e; }
.badge-pending_confirmation { background: #fed7aa; color: #9a3412; }
.badge-confirmed { background: #d1fae5; color: #065f46; }
.badge-disputed { background: #fecaca; color: #991b1b; }
.badge-cancelled { background: #e2e8f0; color: #475569; }
.badge-replaced { background: #e2e8f0; color: #475569; }    /* a move replaced by a newer time (part B) */
.badge-forfeited { background: #fce7f3; color: #9d174d; }
.badge-bye { background: #e2e8f0; color: #475569; }
.badge-active { background: #d1fae5; color: #065f46; }
.badge-setup { background: #fef3c7; color: #92400e; }
.badge-registration_open { background: #dbeafe; color: #1d4ed8; }
.badge-ready { background: #ede9fe; color: #6d28d9; }
.badge-scheduled { background: #dcfce7; color: #166534; }
.badge-completed { background: #e2e8f0; color: #334155; }
.badge-withdrawn { background: #fecaca; color: #991b1b; }
.badge-pending { background: #fed7aa; color: #9a3412; }
.badge-waitlisted { background: #ede9fe; color: #6d28d9; }
.badge-approved { background: #d1fae5; color: #065f46; }
.badge-rejected { background: #fecaca; color: #991b1b; }

/* Buttons */
.btn {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.45rem 0.9rem;
    border-radius: 6px;
    font-size: 0.85rem;
    font-weight: 500;
    border: 1px solid transparent;
    cursor: pointer;
    text-decoration: none;
    transition: all 0.15s;
    white-space: nowrap;
}

.btn-primary { background: var(--primary); color: var(--on-primary); }
.btn-primary:hover { background: var(--primary-dark); }
.btn-success { background: var(--success); color: white; }
.btn-success:hover { background: #15803d; }
.btn-warning { background: var(--warning); color: white; }
.btn-warning:hover { background: #b45309; }
.btn-danger { background: var(--danger); color: white; }
.btn-danger:hover { background: #b91c1c; }
.btn-outline { background: var(--bg-card); border-color: var(--border); color: var(--text); }
.btn-outline:hover { background: var(--surface-muted); }
.btn-sm { padding: 0.25rem 0.6rem; font-size: 0.8rem; }
.btn-lg { padding: 0.6rem 1.25rem; font-size: 1rem; }

/* Forms */
.form-group { margin-bottom: 1rem; }
.form-group label { display: block; margin-bottom: 0.3rem; font-weight: 500; font-size: 0.85rem; }
.form-control {
    width: 100%;
    padding: 0.45rem 0.75rem;
    border: 1px solid var(--border);
    border-radius: 6px;
    font-size: 0.9rem;
    transition: border-color 0.15s;
}
/* Date and time boxes: Safari (iPhone, iPad) gives them its own look and a built-in minimum width, so with width 100%
   they still stuck out of a narrow card (the owner, 2026-10-25: "Ask to move match card: day and time forms out of
   card area"). Reset once for every such box on the site, never per form. */
input[type="date"], input[type="time"], input[type="datetime-local"] {
    -webkit-appearance: none; appearance: none; display: block; min-width: 0; max-width: 100%; min-height: 2.35rem; }
input[type="date"]::-webkit-date-and-time-value, input[type="time"]::-webkit-date-and-time-value,
input[type="datetime-local"]::-webkit-date-and-time-value { text-align: left; margin: 0; }
/* A grid's columns may shrink below their content (a box's built-in width must not widen the column). */
.grid > * { min-width: 0; }
.form-control:focus { outline: none; border-color: var(--primary); box-shadow: 0 0 0 3px color-mix(in srgb, var(--primary) 18%, transparent); }
.form-select {
    width: 100%;
    padding: 0.45rem 0.75rem;
    border: 1px solid var(--border);
    border-radius: 6px;
    font-size: 0.9rem;
    background: var(--bg-card);
}
/* iPhone Safari zooms in on a field under 16px when it's tapped and stays
   zoomed, so the page then slides left and right: on a touch screen every
   field is 16px (no field here is larger). Important, to win over the smaller
   sizes above, the filters' and the few set on the field itself. */
@media (pointer: coarse) {
    input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="hidden"]),
    select, textarea { font-size: 16px !important; }
}

.slot-picker {
    display: grid;
    gap: 0.6rem;
    margin-bottom: 0.4rem;
}

.slot-option {
    display: flex !important;
    align-items: flex-start;
    gap: 0.75rem;
    padding: 0.75rem 0.9rem;
    border: 1px solid var(--border);
    border-radius: 8px;
    background: var(--surface-muted);
    cursor: pointer;
    transition: all 0.15s ease;
}

.slot-option:hover {
    border-color: var(--primary);
    background: var(--tint);
}

.slot-option-input {
    padding-top: 0.1rem;
}

.slot-option-radio {
    margin-top: 0.2rem;
}

.slot-option-body {
    display: grid;
    gap: 0.35rem;
    flex: 1;
}

.slot-option-content {
    font-size: 0.9rem;
    color: var(--text);
}

.slot-option-hint {
    font-size: 0.8rem;
    color: var(--text-muted);
}

.slot-team-context {
    display: none;
    gap: 0.5rem;
    margin-top: 0.25rem;
    padding-top: 0.6rem;
    border-top: 1px solid var(--border);
}

.slot-option-radio:checked + .slot-option-body {
    color: var(--primary-dark);
}

.slot-option-radio:checked + .slot-option-body .slot-option-content {
    font-weight: 600;
    color: var(--primary-dark);
}

.slot-option-radio:checked + .slot-option-body .slot-team-context {
    display: grid;
}

.slot-submit-inline {
    display: none;
    margin-top: 0.6rem;
}

.slot-option-radio:checked + .slot-option-body .slot-submit-inline {
    display: inline-flex;
}

.slot-context-title {
    font-size: 0.75rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--text-muted);
}

.slot-team-schedule {
    display: block;
    padding: 0.55rem 0.65rem;
    border: 1px solid var(--border);
    border-radius: 6px;
    background: var(--bg-card);
}

.slot-match-list {
    margin: 0.35rem 0 0 1rem;
    font-size: 0.85rem;
    color: var(--text-muted);
}

.slot-context-empty {
    display: block;
    margin-top: 0.25rem;
    font-size: 0.85rem;
    color: var(--text-muted);
}

.empty-state {
    padding: 0.75rem 0.9rem;
    border: 1px dashed var(--border);
    border-radius: 8px;
    background: var(--surface-muted);
    color: var(--text-muted);
    font-size: 0.9rem;
}

.form-check-input { margin-right: 0.5rem; }
.form-inline { display: flex; gap: 0.75rem; align-items: flex-end; flex-wrap: wrap; }
.form-inline .form-group { margin-bottom: 0; }

/* Auto-refresh live regions: prevent flash/flicker on content swap */
[data-auto-refresh="true"] {
    /* Minimum height avoids collapsing to 0 between old and new content */
    min-height: 1px;
}

/* Alerts */
.alert {
    padding: 0.75rem 1rem;
    border-radius: 6px;
    margin-bottom: 1rem;
    font-size: 0.9rem;
}

.alert-success { background: #d1fae5; color: #065f46; border: 1px solid #a7f3d0; }
.alert-error { background: #fecaca; color: #991b1b; border: 1px solid #fca5a5; }
.alert-warning { background: #fef3c7; color: #92400e; border: 1px solid #fcd34d; }
.alert-info { background: #dbeafe; color: #1d4ed8; border: 1px solid #93c5fd; }
/* The page's notices stay in sight under the top bar: a form that comes back to
   its place on a long page (Run's closed days) still shows what it did. Passing
   ones fade; the rest have a close button. */
#main-content-region > #flash-messages { position: sticky; top: calc(var(--topbar-h, 60px) + 0.5rem); z-index: 50; }
#main-content-region > #flash-messages .alert { box-shadow: 0 4px 14px rgba(20, 20, 19, 0.12); }

/* Bracket */
.bracket-container {
    /* Its own box for what's absolutely placed inside (hidden labels): they once sat outside it and the page
       scrolled sideways at 390px (the Winter Open walkthrough, 2026-10-23). */
    position: relative;
    overflow-x: auto;
    padding: 1rem;
    background: linear-gradient(180deg, rgba(193, 95, 60, 0.05), rgba(193, 95, 60, 0.015));
    border-radius: 12px;
}

/* More to the right: the right edge fades while the bracket can still scroll that way (app.js sets is-more; walkthrough
   11, U5: at 390 px nothing said it scrolls). A mask, so it reads the same in light and dark. */
.bracket-container.is-more {
    -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 2.5rem), transparent);
    mask-image: linear-gradient(to right, #000 calc(100% - 2.5rem), transparent);
}

.bracket-round {
    display: inline-flex;
    flex-direction: column;
    justify-content: flex-start;
    gap: 0.6rem;
    min-width: 240px;
    margin-right: 2rem;
}

/* On a computer the rounds share the card's width, so every round, the Final too, shows without a drag: a 16-player
   bracket with a 3rd-place match had its Final cut off inside the card at 1647 px (batch 4, 2026-10-24,
   walkthrough 5). A bracket with too many rounds for that still scrolls inside its card. Phones keep their fixed
   columns and scroll in the card (the rule under 760px). */
@media (min-width: 761px) {
    .bracket-round { flex: 1 1 0; min-width: 150px; margin-right: 1rem; }
    .bracket-round:last-child { margin-right: 0; }
    .bracket-team { padding: 0.5rem 0.65rem; }
}

.bracket-round-title {
    font-family: "Trebuchet MS", "Segoe UI", sans-serif;
    font-weight: 700;
    text-align: center;
    margin-bottom: 0.35rem;
    font-size: 0.8rem;
    color: var(--primary);   /* the brand's accent, not a blue of its own (the walkthrough, 2026-10-23) */
    text-transform: uppercase;
    letter-spacing: 0.08em;
}

.bracket-match-wrap {
    margin-bottom: 0.8rem;
}

.bracket-match {
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: 10px;
    overflow: hidden;
    box-shadow: 0 3px 10px rgba(20, 20, 19, 0.08);
}

.bracket-team {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 0.55rem 0.8rem;
    font-size: 0.88rem;
    font-weight: 600;
    color: #1f2937;
}

.bracket-team + .bracket-team { border-top: 1px solid var(--border); }

.bracket-team.winner {
    background: linear-gradient(90deg, #dcfce7, #ecfeff);
    color: #065f46;
}

.bracket-score {
    min-width: 1.75rem;
    text-align: right;
    font-family: "Segoe UI", "Trebuchet MS", sans-serif;
    font-size: 0.92rem;
    font-weight: 800;
    color: var(--text);
}

.bracket-match-info {
    margin-top: 0.45rem;
    display: flex;
    flex-wrap: wrap;
    gap: 0.35rem;
}

.bracket-info-chip {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    padding: 0.22rem 0.55rem;
    border-radius: 999px;
    border: 1px solid var(--border);
    background: var(--surface-muted);
    color: var(--text);
    font-size: 0.75rem;
    font-weight: 600;
}

.bracket-info-chip-place {
    border-color: #fcd34d;
    background: #fffbeb;
    color: #854d0e;
}

.bracket-info-label {
    font-size: 0.75rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    font-weight: 800;
    color: rgba(15, 23, 42, 0.65);
}

html[data-theme="dark"] .bracket-container {
    background: linear-gradient(180deg, rgba(217, 119, 87, 0.10), rgba(217, 119, 87, 0.03));
}

html[data-theme="dark"] .bracket-round-title { color: #e8b9a5; }

html[data-theme="dark"] .bracket-match {
    background: linear-gradient(180deg, #30302e, #262624);
    border-color: #45433f;
    box-shadow: 0 6px 14px rgba(0, 0, 0, 0.3);
}

html[data-theme="dark"] .bracket-team {
    color: #ece9e0;
}

html[data-theme="dark"] .bracket-team + .bracket-team {
    border-top-color: #45433f;
}

html[data-theme="dark"] .bracket-team.winner {
    background: linear-gradient(90deg, rgba(22, 101, 52, 0.5), rgba(6, 78, 59, 0.45));
    color: #bbf7d0;
}



html[data-theme="dark"] .bracket-info-chip-place {
    border-color: #a16207;
    background: rgba(69, 26, 3, 0.45);
    color: #fde68a;
}

html[data-theme="dark"] .bracket-info-label {
    color: #c9c6bc;
}

/* Filters */
.filters {
    display: flex;
    gap: 0.75rem;
    flex-wrap: wrap;
    margin-bottom: 1rem;
    padding: 0.75rem;
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: 8px;
}

.filters select, .filters input {
    padding: 0.35rem 0.6rem;
    border: 1px solid var(--border);
    border-radius: 6px;
    font-size: 0.85rem;
}

/* Pagination */
.pagination {
    display: flex;
    flex-wrap: wrap;           /* the pages wrap on a phone, never the page sideways at 320 px (batch 4, 2026-10-24) */
    gap: 0.25rem;
    justify-content: center;
    margin-top: 1rem;
}

.pagination a, .pagination span {
    padding: 0.35rem 0.65rem;
    border: 1px solid var(--border);
    border-radius: 4px;
    font-size: 0.85rem;
    text-decoration: none;
    color: var(--text);
}

.pagination .pagination-gap { border-color: transparent; color: var(--text-muted); }
.pagination .active { background: var(--primary); color: var(--on-primary); border-color: var(--primary); }
.pagination a:hover { background: var(--surface-muted); }

/* Chart placeholder */
.chart-container { position: relative; height: 300px; }

/* Utility */
.text-muted { color: var(--text-muted); }
.text-success { color: var(--success); }
.text-danger { color: var(--danger); }
.text-warning { color: var(--warning); }
.text-center { text-align: center; }
.mb-1 { margin-bottom: 0.5rem; }
.mb-2 { margin-bottom: 1rem; }
.mt-1 { margin-top: 0.5rem; }
.mt-2 { margin-top: 1rem; }
.d-flex { display: flex; }
.gap-1 { gap: 0.5rem; }
.gap-2 { gap: 1rem; }
.flex-wrap { flex-wrap: wrap; }
.align-center { align-items: center; }
.justify-between { justify-content: space-between; }

/* Responsive */
@media (max-width: 760px) {
    .sidebar { display: none; }
    .topbar-brand { display: inline-flex; flex: none; }
    /* The bar sits above the phone's home or gesture bar: env() reports that
       strip only with viewport-fit=cover (base.html); without it it was 0 and
       the bar sat on the iPhone's home indicator. A phone with no strip
       still gets a little room. Sideways, it clears the notch. */
    .main-content { margin-left: 0; padding-bottom: calc(4.5rem + var(--bar-lift));
                    padding-left: env(safe-area-inset-left); padding-right: env(safe-area-inset-right); }
    .bottom-bar {
        display: flex; position: fixed; left: 0; right: 0; bottom: 0; z-index: 120;
        background: var(--bg-card); border-top: 1px solid var(--border);
        padding: 0 env(safe-area-inset-right) var(--bar-lift) env(safe-area-inset-left);
    }
    .bottom-bar > .nav-item, .bottom-bar > .nav-more { flex: 1 1 0; min-width: 0; }
    .bottom-bar .nav-item {
        position: relative; display: flex; flex-direction: column; align-items: center; gap: 2px;
        padding: 0.45rem 0.05rem 0.4rem; color: var(--text-muted, #64748b); text-decoration: none;
        font-size: 0.75rem; letter-spacing: -0.01em; cursor: pointer; list-style: none;
    }
    .bottom-bar .nav-item::-webkit-details-marker { display: none; }
    .bottom-bar .nav-item.active { color: var(--role-accent); font-weight: 600; }
    /* A label may reach 4px into the slots beside it, so in a bar of five, enlarged text still shows "Matches"
       whole (wave 43). */
    .bottom-bar .nav-label { max-width: calc(100% + 8px); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
    .bottom-bar .nav-badge { position: absolute; top: 2px; left: calc(50% + 4px); margin: 0; font-size: 0.75rem;
                             min-width: 1rem; line-height: 1rem; padding: 0 0.3rem; }
    .nav-more { position: relative; }
    .nav-more-sheet {
        position: absolute; right: 0.25rem; bottom: calc(100% + 0.25rem); min-width: 12rem;
        background: var(--bg-card); border: 1px solid var(--border); border-radius: 12px;
        box-shadow: 0 8px 24px rgba(0,0,0,0.18); padding: 0.35rem;
    }
    .nav-more-sheet .nav-item { flex-direction: row; gap: 0.6rem; font-size: 0.9rem; padding: 0.6rem 0.75rem;
                                color: var(--text); }
    .nav-more-sheet .nav-badge { position: static; margin-left: auto; }
    .nav-more-line { margin: 0.35rem 0.5rem; border: 0; border-top: 1px solid var(--border); }
    .nav-more-sheet .logout-button { gap: 0.6rem; padding: 0.6rem 0.75rem; font-size: 0.9rem; color: var(--text);
                                     border-radius: 8px; }
    .grid-2, .grid-3, .grid-4 { grid-template-columns: 1fr; }
    /* Three small numbers stay side by side (the entry page's Played · Wins · Losses filled the screen stacked). */
    .grid-3.stat-row { grid-template-columns: repeat(auto-fit, minmax(5.5rem, 1fr)); gap: 0.5rem; }   /* wraps when the text is large */
    .stat-row .stat-card { padding: 0.75rem 0.4rem; }
    .content { padding: 1rem; }
    .filters { flex-direction: column; }
    .bracket-container { padding: 0.7rem; }
    .bracket-round { min-width: 205px; margin-right: 1.1rem; }
    .bracket-team { font-size: 0.82rem; padding: 0.48rem 0.62rem; }
    .bracket-match-info { gap: 0.28rem; }
    .bracket-info-chip { font-size: 0.75rem; padding: 0.2rem 0.45rem; }
    .form-inline { flex-direction: column; align-items: stretch; }
    .perf-bar-outer, .perf-stats { flex-direction: column !important; }
    .perf-bar-outer > div,
    .perf-stats > div {
        border-right: none !important;
        border-bottom: 1px solid var(--border) !important;
        padding: 0.6rem 0.5rem !important;
        margin-right: 0 !important;
    }
    .perf-bar-outer > div:last-child,
    .perf-stats > div:last-child { border-bottom: none !important; }
}

@media (max-width: 1200px) {
    /* The top bar on a phone or tablet: the page title and notifications in
       one row, the tournament switcher below it, full width. */
    .topbar { flex-wrap: wrap; padding: 0.5rem 0.75rem; gap: 0.5rem; }
    .topbar-left { flex: 1; min-width: 0; gap: 0.25rem 0.5rem; flex-wrap: wrap; }
    .topbar-left > span { font-weight: 600; overflow-wrap: anywhere; }
    .topbar-left > .role-chip { flex: none; font-weight: 700; }
    .topbar-right { display: contents; }
    .topbar-bell { order: 1; }
    .topbar-tournament, .topbar-tournament-name { order: 3; width: 100%; }
    .topbar-tournament label { display: none; }
    .topbar-tournament select { min-width: 0 !important; width: 100%; flex: 1; }
}

@media (max-width: 1024px) {
    .grid-4 { grid-template-columns: repeat(2, 1fr); }
}

/* Tournament Completion Celebration Styles */
@keyframes bounce {
    0%, 100% { transform: translateY(0); }
    50% { transform: translateY(-12px); }
}

.winner-podium-section {
    padding: 1rem;
    background: linear-gradient(135deg, rgba(255, 215, 0, 0.1), rgba(255, 165, 0, 0.1));
    border-radius: 12px;
    margin-bottom: 1rem;
}

.runner-up-podium {
    padding: 0.75rem;
    background: rgba(200, 200, 200, 0.08);
    border-radius: 8px;
    border: 2px solid rgba(200, 200, 200, 0.2);
    transition: transform 0.3s ease, box-shadow 0.3s ease;
}

.runner-up-podium:hover {
    transform: translateY(-4px);
    box-shadow: 0 8px 16px rgba(0, 0, 0, 0.1);
}

/* Fireworks styles */
#fireworks-canvas {
    position: absolute;
    top: 0;
    left: 0;
}

/* Tournament news board (templates/core/partials/news_board_body.html) */
.news-story { margin: 0 0 1rem; padding: 0.2rem 0 0.2rem 0.9rem; border-left: 3px solid var(--primary); }
.news-story p { margin: 0 0 0.55rem; line-height: 1.5; }
.news-title { font-size: 1.2rem; font-weight: 800; margin: 0 0 0.35rem; line-height: 1.25; }
.news-intro { font-weight: 600; }
.news-story-heading { font-size: 0.95rem; margin: 0.7rem 0 0.25rem; }
.news-sign-off { font-style: italic; color: var(--text-muted); margin-bottom: 0 !important; }
.news-section { margin-bottom: 0.9rem; }
.news-day { font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.06em; margin: 0 0 0.35rem; color: var(--primary); }
.news-day .text-muted { text-transform: none; letter-spacing: 0; }
.news-item { display: block; padding: 0.45rem 0.6rem; margin-bottom: 0.3rem; border-radius: 6px; border: 1px solid var(--border); color: var(--text); text-decoration: none; }
.news-item:hover { border-color: var(--primary); }
.news-item strong { display: block; line-height: 1.3; }
.news-score { display: block; font-size: 0.8rem; color: var(--text-muted); margin-top: 0.15rem; }
.news-score-only { font-size: 0.9rem; color: var(--text); margin-top: 0; }
.news-empty { font-size: 0.85rem; margin: 0; }
.news-footnote { font-size: 0.75rem; }
.news-header { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; flex-wrap: wrap; }
.news-flip { font-size: 0.78rem; padding: 0.2rem 0.6rem; }
.news-team-banner { display: inline-block; font-size: 0.75rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em; color: var(--primary); margin-bottom: 0.5rem; }

/* Visible to screen readers only (labels for the per-game score boxes). */
/* Hidden labels sit at their box's corner, so none can poke out of a scroller and widen the page. */
.sr-only {
    position: absolute; top: 0; left: 0; width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}

/* Lists of things to open (NEXT_FIXES_PLAN R-3): whole rows and tiles tap through. */
.section-title { font-size: 1.05rem; margin: 1.25rem 0 0.6rem; }
.tile-grid { display: grid; gap: 0.75rem; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); }
.tile-grid .card { margin-bottom: 0; }
.tile-title { font-size: 1rem; margin: 0 0 0.25rem; }
.tile-title a, .tile-link { color: inherit; text-decoration: none; }
.tile-meta { font-size: 0.85rem; margin: 0 0 0.5rem; }
.list-card { padding: 0; overflow: hidden; }
.list-row { display: flex; justify-content: space-between; align-items: center; gap: 0.75rem; padding: 0.7rem 1rem;
            color: inherit; text-decoration: none; border-top: 1px solid var(--border); }
.list-row:first-child { border-top: 0; }
.list-row:hover { background: var(--bg); }
.filters-fold { margin-bottom: 0.75rem; }
.filters-fold > summary { color: var(--primary); margin-bottom: 0.5rem; }
.filters-form { display: flex; flex-wrap: wrap; gap: 0.75rem; align-items: flex-end; }
.filters-form .form-group { margin: 0; min-width: 140px; flex: 1; }

/* Home (NEXT_FIXES_PLAN R-2, R-7): one primary card; the rest plain. */
.card--primary { border-left: 4px solid var(--primary); box-shadow: 0 4px 16px rgba(15,23,42,0.08); }
.card-title-sm { font-size: 1rem; margin: 0 0 0.5rem; }
.eyebrow { font-size: 0.8rem; color: var(--text-muted, #64748b); margin: 0 0 0.25rem; text-transform: none; }
.next-opponent { font-size: 1.5rem; margin: 0 0 0.25rem; }
.next-when { margin: 0 0 0.9rem; font-size: 1.05rem; }
/* What's at stake (wave 19): one quiet line under the time. */
.next-stake { margin: -0.6rem 0 0.9rem; color: var(--text-muted, #64748b); }
/* Two of your matches booked at once (wave 27, F11). */
.next-clash, .m-clash { color: var(--danger, #b42318); font-weight: 600; }
.next-clash { margin: -0.4rem 0 0.9rem; }
.standing-line { margin: 0.25rem 0 1rem; }
.standing-line a { text-decoration: none; }
.todo-list { list-style: none; margin: 0; padding: 0; }
.todo-row { display: flex; justify-content: space-between; gap: 0.75rem; padding: 0.55rem 0; color: inherit;
            text-decoration: none; border-top: 1px solid var(--border); }
.todo-list li:first-child .todo-row { border-top: 0; }
.todo-u0 { font-weight: 600; }
.todo-card { border-left: 4px solid var(--state-your-turn); }
.stage-chip { font-size: 0.75rem; padding: 0.1rem 0.5rem; border-radius: 999px; background: var(--bg); white-space: nowrap; }
.stage-live { background: #dcfce7; color: #166534; }
html[data-theme="dark"] .stage-live { background: #14532d; color: #bbf7d0; }

/* Matches (NEXT_FIXES_PLAN R-3, UX-6): whole rows tap through; cards on a phone. */
/* Never wider than the screen: with three choices and large text on a small phone they wrap (Today, 61202ec). */
.seg { display: inline-flex; flex-wrap: wrap; max-width: 100%; border: 1px solid var(--border); border-radius: 1.25rem;
       padding: 2px; margin-bottom: 0.75rem; background: var(--bg-card); }
.seg-item { padding: 0.35rem 0.9rem; border-radius: 999px; text-decoration: none; color: inherit; font-size: 0.9rem;
            white-space: nowrap; }
.seg-item.active { background: var(--primary); color: var(--on-primary); }
.match-row { display: grid; grid-template-columns: 4rem 7rem minmax(0, 1fr) minmax(0, 13rem); gap: 0.75rem; align-items: center;
             padding: 0.7rem 1rem; color: inherit; text-decoration: none; border-top: 1px solid var(--border); }
.match-list .match-row:first-child { border-top: 0; }
.match-row:hover { background: var(--bg); }
.no-time .match-row { grid-template-columns: 7rem minmax(0, 1fr) minmax(0, 13rem); }
.no-court .match-row { grid-template-columns: 4rem minmax(0, 1fr) minmax(0, 13rem); }
.no-time.no-court .match-row { grid-template-columns: minmax(0, 1fr) minmax(0, 13rem); }
.m-time { font-variant-numeric: tabular-nums; font-weight: 600; }
.m-won { font-weight: 700; }
.m-lost { color: var(--text-muted); }
/* The score as a badge, its games small under it (the owner's review, 2026-10-20). */
.m-score { display: inline-block; font-weight: 700; font-size: 1.05rem; font-variant-numeric: tabular-nums;
           padding: 0.05rem 0.6rem; border-radius: 999px; background: var(--surface-muted, var(--bg)); }
.m-games { color: var(--text-muted); font-variant-numeric: tabular-nums; line-height: 1.3; }
.m-note, .m-outcome { color: var(--text-muted); }
.m-result { text-align: right; display: flex; flex-direction: column; align-items: flex-end; }
.m-state { color: var(--text-muted, #64748b); }
.m-stake { margin: 0 0 0.25rem; color: var(--text-muted, #64748b); }
.m-credit { margin: 0 0 0.25rem; color: var(--success, #15803d); }
.closing-card .eyebrow { margin-bottom: 0.35rem; }
.state-pending_confirmation { color: var(--state-waiting); }
.state-disputed { color: var(--state-disputed); }
.state-confirmed, .state-forfeited { color: var(--state-final); }
/* A finished match as a card (MATCH_CARDS_PLAN_2026-10-21): one row per side, each game's points, a box with its games
   won; green for the winner, grey for the other, never red. */
.match-row.mc-row-link { display: block; }
.match-row.mc-mine { box-shadow: inset 3px 0 0 var(--primary); }
.mc-tr > td { padding-block: 0.55rem; }
a.mc-row-link { display: block; color: inherit; text-decoration: none; }
.mc { display: block; min-width: 0; }
.mc-meta { display: block; font-size: 0.8125rem; color: var(--text-muted); margin-bottom: 0.15rem; }
.mc-rows { display: grid; gap: 0.2rem; }
/* The name keeps a few words' room; past that (large text on a phone) the games wrap under each other, never off the
   card. */
.mc-row { display: grid; grid-template-columns: minmax(min(6em, 40%), 1fr) auto 2rem; align-items: center; gap: 0.5rem; }
.mc-name { min-width: 0; overflow-wrap: anywhere; color: var(--text-muted); }
.mc-won .mc-name { color: var(--text); font-weight: 700; }
.mc-note { font-size: 0.8125rem; color: var(--text-muted); font-weight: 400; }
.mc-pts { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 0.15rem; font-variant-numeric: tabular-nums; }
.mc-pts span { min-width: 1.45rem; text-align: center; color: var(--text-muted); }
.mc-pts span.mc-w { color: var(--text); font-weight: 700; }
.mc-box { height: 1.75rem; border-radius: 6px; display: grid; place-items: center; font-weight: 700;
          font-variant-numeric: tabular-nums; background: var(--surface-muted); color: var(--text);
          border: 1px solid var(--border); }
.mc-won .mc-box { background: var(--success); color: var(--on-success); border-color: var(--success); }
/* On a phone every game still shows, a best of 7 too (the owner, 2026-10-25: "Why scores only for few matches not
   all?"): narrower columns, the numbers a little smaller (13px), and a long name wraps rather than the games going. */
@media (max-width: 480px) {
    .mc-row { grid-template-columns: minmax(min(6em, 40%), 1fr) auto 1.75rem; gap: 0.375rem; }
    .mc-name { font-size: 0.9375rem; }
    .mc-pts { gap: 0.125rem; font-size: 0.8125rem; }
    .mc-pts span { min-width: 0.9375rem; }
}

@media (max-width: 760px) {
    .match-row, .no-time .match-row, .no-court .match-row, .no-time.no-court .match-row {
        grid-template-columns: auto 1fr; grid-template-areas: "time court" "sides sides" "result result";
        gap: 0.15rem 0.6rem; }
    .m-time { grid-area: time; }
    .m-court { grid-area: court; }
    .m-sides { grid-area: sides; }
    .m-result { grid-area: result; align-items: baseline; text-align: left; flex-direction: row; flex-wrap: wrap;
                gap: 0.15rem 0.5rem; }
}

/* Table (NEXT_FIXES_PLAN R-3, UX-7): on a phone the essentials, the rest under the row. */
.standings-table .row-extra { display: none; }
.table-legend { font-size: 0.82rem; margin: 0.25rem 0 0.75rem; }
.table-legend abbr { text-decoration: none; font-weight: 600; }
@media (max-width: 760px) {
    .standings-table .col-extra { display: none; }
    .standings-table .row-extra { display: block; font-size: 0.8rem; color: var(--text-muted, #64748b); }
    .standings-table .row-extra summary { color: var(--primary); }
    .standings-table table { min-width: 0; }
}

/* Match (NEXT_FIXES_PLAN R-3, UX-8): one state leads; the rest folds away. */
.match-result { font-size: 1.6rem; font-weight: 700; margin: 0 0 0.25rem; }
.match-when { font-size: 1.05rem; margin: 0 0 0.25rem; }
.match-when .badge { margin-left: 0.35rem; }          /* "played early" a space apart from the time (the walkthrough) */
.fold { margin: 0 0 1rem; }
.fold > summary { color: var(--primary); }
.fold[open] > summary { margin-bottom: 0.5rem; }
/* Add to calendar (wave 44): a choice's words stay together ("Google Calendar" broke over two lines). */
.add-calendar a { white-space: nowrap; }
/* All my matches (wave 44, step 2): the two ways, one under the other; on Me, in a card of its own. */
.my-calendar.card { padding: 0 1rem; }
.my-calendar.card > summary { padding: 0.85rem 0; }
.my-calendar-way { padding: 0 0 0.75rem; }
.my-calendar-way + .my-calendar-way { border-top: 1px solid var(--border); padding-top: 0.75rem; }
.my-calendar-new { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.25rem 0.5rem; margin: 0 0 0.25rem; }
.my-calendar-last { margin: 0; }
.move-request { padding: 0.4rem 0; border-top: 1px solid var(--border); }
.move-request:first-child { border-top: 0; }
.details-list { display: grid; grid-template-columns: max-content 1fr; gap: 0.25rem 1rem; margin: 0 0 0.75rem; }
.details-list dt { color: var(--text-muted, #64748b); }
.details-list dd { margin: 0; }
.form-pill { display: inline-flex; width: 1.6rem; height: 1.6rem; border-radius: 50%; align-items: center;
             justify-content: center; font-size: 0.75rem; font-weight: 700; background: #e2e8f0; margin-right: 2px; }

/* The team's season (UX-9). */
.season-figures { display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: 0.5rem 1rem; margin: 0.5rem 0; }
.season-figures dt { font-size: 0.78rem; color: var(--text-muted, #64748b); }
.season-figures dd { margin: 0; font-size: 1.15rem; font-weight: 700; }

/* Run (NEXT_FIXES_PLAN R-4, UX-10). */
.checklist { list-style: none; margin: 0 0 1rem; padding: 0; display: grid; gap: 0.5rem; }
.check-step { background: var(--bg-card); border: 1px solid var(--border); border-radius: 12px; }
.check-step.card { margin-bottom: 0; }
.check-row { display: grid; grid-template-columns: 2rem 1fr auto; gap: 0.75rem; align-items: center; padding: 0.8rem 1rem;
             color: inherit; text-decoration: none; }
.check-mark { width: 1.8rem; height: 1.8rem; border-radius: 50%; display: inline-flex; align-items: center;
              justify-content: center; background: var(--bg); font-weight: 700; }
.is-done .check-mark { background: #dcfce7; color: #166534; }
.is-current .check-mark { background: var(--primary); color: var(--on-primary); }
.run-actions { display: flex; flex-wrap: wrap; gap: 0.5rem; margin: 0 0 1rem; align-items: center; }
.run-actions form { margin: 0; }
/* Run's other pages (the owner, 2026-10-11: dotted links too small to tap on a phone). A line on a wide screen;
   on a phone a list of full-width rows, 48px each, the danger one last and red. */
.run-links { display: flex; flex-wrap: wrap; align-items: center; font-size: 0.9rem; color: var(--text-muted, #64748b); margin: 0 0 1rem; }
.run-links a { padding: 0.35rem 0; }
.run-links a + a::before { content: "·"; display: inline-block; margin: 0 0.55rem; color: var(--text-muted, #64748b); text-decoration: none; }
@media (max-width: 640px) {
    .run-links { flex-direction: column; align-items: stretch; border: 1px solid var(--border); border-radius: 12px;
        background: var(--bg-card); overflow: hidden; font-size: 1rem; }
    .run-links a { display: flex; align-items: center; justify-content: space-between; min-height: 48px; padding: 0 1rem;
        color: var(--text); text-decoration: none; border-top: 1px solid var(--border); }
    .run-links a:first-child { border-top: 0; }
    .run-links a + a::before { content: none; }
    .run-links a::after { content: "›"; color: var(--text-muted, #64748b); font-size: 1.2rem; }
    .run-links a.run-link-danger { color: var(--danger, #b42318); }
}
.plain-list { list-style: none; margin: 0 0 0.75rem; padding: 0; }
.plain-list li { padding: 0.2rem 0; }
.visually-hidden { position: absolute; top: 0; left: 0; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
.run-grid { align-items: start; }
.danger-card { border: 1px solid var(--danger, #dc2626); border-top-width: 1px; max-width: 700px; }
.run-grid small, .run-grid .text-muted, .card small { overflow-wrap: anywhere; }
.basic-badge { background: var(--bg); color: var(--text-muted, #64748b); border: 1px solid var(--border); font-weight: 500; }

/* The invite link on Run (wave 9). */
.invite-link-row { display: flex; gap: 0.5rem; margin-bottom: 0.5rem; }
.invite-link-row input { flex: 1; min-width: 0; font-size: 0.85rem; }
.invite-link-row input[readonly] { font-family: ui-monospace, monospace; }
.invite-form { display: grid; gap: 0.35rem; margin-top: 0.5rem; }
.checkbox-label { display: flex; gap: 0.5rem; align-items: center; }
.public-brand { text-decoration: none; min-width: 0; }
@media (max-width: 520px) { .public-brand .brand-tagline { display: none; } }

/* Table hours (NEXT_FIXES_PLAN wave 10): errors at their field, the one estimate line. */
.errorlist { list-style: none; margin: 0.25rem 0 0; padding: 0; color: var(--danger); font-size: 0.85rem; font-weight: 600; }
/* A game that can't be, flagged as it's typed (score_entry_sets.html). */
.score-games input[aria-invalid="true"] { border-color: var(--danger); box-shadow: 0 0 0 1px var(--danger); }
.score-games-problem { margin: 0.35rem 0; color: var(--danger); font-size: 0.85rem; font-weight: 600; }
.estimate-line { display: block; font-size: 0.9rem; font-weight: normal; color: var(--text-muted); margin-top: 0.25rem; }
.estimate-line--short { color: var(--danger); font-weight: 600; }
.hours-estimate { margin: 0.75rem 0; padding: 0.6rem 0.75rem; border: 1px solid var(--border); border-radius: 6px; font-size: 0.9rem; }
.hours-estimate.is-short { border-color: var(--danger); }
/* Tables and hours (NEXT_FIXES_PLAN wave 46d): one column; the fit said once at the top; a card a table with its
   hours and buttons; the add forms folded; tables and days as a row of buttons (44px for a finger). */
.run-tables { display: grid; gap: 1rem; max-width: 52rem; }
.run-tables .card { margin-bottom: 0; }
.tables-summary .estimate-line { margin: 0 0 0.35rem; font-size: 1rem; }
.tables-summary .span-line { color: var(--text); }
.table-card { display: grid; gap: 0.35rem; padding: 0.65rem 0.8rem; background: var(--surface-muted); border-radius: 8px; margin-bottom: 0.6rem; }
.table-card-head { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; }
.table-hours-line { display: flex; justify-content: space-between; align-items: baseline; gap: 0.25rem 0.75rem; flex-wrap: wrap; margin: 0; font-size: 0.9rem; }
.table-hours-line form, .table-card-actions form { margin: 0; }
.table-card-actions { display: flex; align-items: flex-start; gap: 0.5rem 0.75rem; flex-wrap: wrap; }
.table-rename { margin: 0; }
.table-rename[open] { flex-basis: 100%; }
.inline-form { display: flex; gap: 0.5rem; align-items: center; flex-wrap: wrap; }
.inline-form .form-control { flex: 1 1 10rem; min-width: 0; width: auto; }
.add-fold { margin: 0.6rem 0 0; padding-top: 0.5rem; border-top: 1px solid var(--border); }
.add-fold > summary { font-weight: 600; }
.pill-field { border: 0; padding: 0; margin: 0 0 0.75rem; min-width: 0; }
.pill-field legend { font-weight: 600; padding: 0; margin-bottom: 0.35rem; }
.pills { display: flex; flex-wrap: wrap; gap: 0.4rem; }
.pills .pill { position: relative; display: inline-flex; align-items: center; min-height: 44px; margin: 0; padding: 0 0.9rem; border: 1px solid var(--border); border-radius: 999px; background: var(--bg-card); font-size: 0.95rem; font-weight: 500; cursor: pointer; }
.pills .pill input { position: absolute; opacity: 0; width: 1px; height: 1px; margin: 0; }
.pills .pill:has(input:checked) { background: var(--primary); border-color: var(--primary); color: var(--on-primary); }
.pills .pill:has(input:focus-visible) { outline: 2px solid var(--primary); outline-offset: 2px; }
.pill-shortcuts { display: flex; flex-wrap: wrap; gap: 0.35rem 1rem; margin-top: 0.4rem; font-size: 0.875rem; }
.card-fold { margin: 0; }
.card-fold > summary.card-header { color: inherit; padding: 0.75rem 1rem; }
/* The folded card's own marker: a card header is a flex row, which hides the browser's. */
.card-fold > summary.card-header::after { content: "▸"; color: var(--primary); }
.card-fold[open] > summary.card-header::after { content: "▾"; }
.card-fold[open] > summary.card-header { margin-bottom: 0; }
.closed-list li { margin: 0.25rem 0; }
.seed-prompt .seed-list { font-size: 0.95rem; }
/* What the draft needs first, in place of a button that would be refused (the owner's screenshot, 2026-10-14). */
.draft-blockers { margin-top: 0.75rem; padding: 0.75rem 1rem; background: var(--surface-muted); border-left: 3px solid var(--state-your-turn, #d97706); border-radius: 0 6px 6px 0; }
.draft-blockers .plain-list { margin: 0; }
.hours-list { list-style: none; margin: 0 0 0.75rem; padding: 0; }
.hours-list li { display: flex; justify-content: space-between; align-items: center; gap: 0.5rem; padding: 0.3rem 0; font-size: 0.9rem; border-bottom: 1px solid var(--border); }
.hours-dates { margin: 0.5rem 0; }
.hours-dates summary { color: var(--primary); font-size: 0.9rem; }

/* Tournament News in brief on Home (NEXT_FIXES_PLAN wave 12). */
.news-card .news-new { display: inline-block; margin-left: 0.4rem; padding: 0.05rem 0.5rem; border-radius: 999px;
    background: var(--primary); color: var(--on-primary); font-size: 0.75rem; font-weight: 700; letter-spacing: 0.03em;
    text-transform: uppercase; vertical-align: middle; }
.news-card .news-headline { font-size: 1.02rem; }
.news-card .news-read { margin: 0; }
.news-strip { margin: 0 0 0.75rem; padding: 0.5rem 0.75rem; border: 1px solid var(--border); border-radius: 6px;
    background: var(--bg-card); font-size: 0.92rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.news-strip a { color: inherit; text-decoration: none; }
.news-strip a:hover strong { text-decoration: underline; }

/* ── Login playfield (wave 14) ───────────────────────────────────────
   Stick figures playing behind the login card, drawn and directed by
   static/js/playfield.js. Ink is the theme's muted text, accents its clay;
   everything sits behind the page (z-index -1 inside the public shell) and
   ignores the pointer. */
.public-shell { position: relative; z-index: 1; }
.playfield { position: fixed; inset: 0; z-index: -1; overflow: hidden; pointer-events: none;
             color: var(--text-muted); opacity: 0.85; }
.pf-svg { position: absolute; inset: 0; overflow: visible; fill: none; stroke: currentColor; stroke-width: 2.3;
          stroke-linecap: round; stroke-linejoin: round; }
.pf-head { fill: var(--bg); }
.pf-eye { stroke-width: 1.3; fill: none; }
.pf-eye-dot, .pf-eye-sad { fill: currentColor; }
.pf-mouth { stroke-width: 1.4; fill: none; }
.pf-mouth-grin, .pf-mouth-shock { fill: currentColor; }
.pf-svg .pf-accent { fill: var(--primary); stroke: var(--primary); }
.pf-svg .pf-accent-line { stroke: var(--primary); }
.pf-svg .pf-fill { fill: currentColor; }
.pf-svg .pf-ball { fill: var(--bg-card); stroke: var(--primary); }
.pf-svg .pf-thick { stroke-width: 4; }
.pf-svg .pf-bat { stroke-width: 4.5; }
.pf-svg .pf-club { stroke-width: 2; }
.pf-svg .pf-rope { stroke: var(--primary); stroke-width: 2; }
.pf-svg .pf-net { stroke-width: 1; opacity: 0.55; }
.pf-svg .pf-cloud { fill: currentColor; stroke: none; opacity: 0.35; }
.pf-svg .pf-rain { stroke: var(--info); stroke-width: 1.5; }
.pf-svg .pf-tear { fill: var(--info); stroke: none; }
.pf-svg .pf-blush { fill: var(--primary); stroke: none; opacity: 0.45; }
.pf-svg .pf-dust { fill: currentColor; stroke: none; opacity: 0.18; }
.pf-svg .pf-speed { stroke-width: 1.6; opacity: 0.55; }
.pf-svg .pf-word { fill: var(--primary); stroke: none; font: italic 600 11px var(--font-heading); }
.pf-svg .pf-big { font-size: 15px; font-style: normal; font-weight: 700; }
@media (max-width: 760px) { .playfield { opacity: 0.7; } }
/* The front page's strip (2026-10-16): the same figures in a box of their own between the lead and the features,
   one story at a time on its floor; what leaves the box (a smash into the sky) is cut off at its edge. */
.playfield.playfield-strip { position: relative; inset: auto; z-index: auto; height: 150px; margin: 0 auto 1.5rem;
                             opacity: 0.85; }
@media (max-width: 760px) { .playfield.playfield-strip { height: 120px; opacity: 0.85; } }

/* ── About, Privacy, Terms and the footer (owner, 2026-10-06) ───────── */
.site-footer { margin: 2.5rem 0 1rem; padding-top: 1rem; border-top: 1px solid var(--border); text-align: center;
               font-size: 0.8rem; color: var(--text-muted); }
.site-footer a { color: var(--text-muted); text-decoration: none; }
.site-footer a:hover { color: var(--primary); text-decoration: underline; }
.legal-page { max-width: 720px; line-height: 1.65; }
.legal-page h1 { margin-bottom: 0.25rem; }
.legal-page h2 { font-size: 1.15rem; margin: 1.75rem 0 0.5rem; }
.legal-page p, .legal-page ul { margin: 0 0 0.75rem; }
.legal-page ul { padding-left: 1.25rem; }
.legal-page li { margin: 0.2rem 0; }
.legal-updated { color: var(--text-muted); font-size: 0.85rem; margin-bottom: 1.25rem; }
.testing-note { background: var(--tint); border: 1px solid var(--border); border-left: 4px solid var(--primary);
                border-radius: 8px; padding: 0.75rem 1rem; margin: 0 0 1.5rem; }
.danger-zone { border-color: var(--danger); }
.signup-terms { font-size: 0.8rem; color: var(--text-muted); text-align: center; margin-top: 0.5rem; }

/* Touching the playfield (owner, 2026-10-07): only the invisible zones over
   figures and objects take the pointer; nothing hints at them but the hand. */
.pf-svg .pf-hit { fill: transparent; stroke: none; pointer-events: all; cursor: pointer;
                  -webkit-tap-highlight-color: transparent; }
.pf-svg .pf-sun { stroke-width: 1.8; }
.pf-reward { position: fixed; right: 16px; bottom: 16px; z-index: 5; pointer-events: none;
             background: var(--bg-card); color: var(--text); border: 1px solid var(--border);
             border-left: 4px solid var(--primary); border-radius: 10px; padding: 0.5rem 0.9rem;
             font: 600 0.9rem var(--font-body); box-shadow: 0 6px 18px rgba(0, 0, 0, 0.12);
             animation: pf-reward-in 0.35s ease-out; transition: opacity 0.8s, transform 0.8s; }
.pf-reward.pf-reward-out { opacity: 0; transform: translateY(8px); }
@keyframes pf-reward-in { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) { .pf-svg .pf-hit { pointer-events: none; cursor: auto; } }

/* Chances on the table (wave 17, WI-6) */
.col-chance { white-space: nowrap; text-align: right; font-variant-numeric: tabular-nums; padding-left: 0.25rem !important; padding-right: 0.5rem !important; }
.chance-sure { color: var(--success); font-weight: 600; }
.chance-out { color: var(--text-muted); }
.chance-link { color: inherit; text-decoration: underline dotted; text-underline-offset: 2px; }

/* What if? (WHAT_IF_CARD_PLAN_2026-10-31): the card on the real table, then what to try, folded */
.wi-card .card-body { padding: 1rem 1rem 0.85rem; overflow-wrap: anywhere; }
.wi-where { font-size: 0.9rem; color: var(--text-muted); margin: 0 0 0.35rem; }
.wi-note { font-size: 0.9rem; margin: 0 0 0.35rem; }
.wi-say { font-size: 1.15rem; font-weight: 600; line-height: 1.35; margin: 0 0 0.6rem; }
/* The ✓ is a mark, not text (3:1 is asked of a graphic; --success is 3.3:1 in one theme): its words are sr-only. */
.wi-ok { color: var(--success); }
.wi-more { margin: 0 0 0.6rem; }
.wi-next { border-top: 1px solid var(--border); padding-top: 0.6rem; margin: 0 0 0.6rem; }
.wi-next p { margin: 0; }
.wi-next .wi-what { margin-top: 0.15rem; }
.wi-link { margin: 0; }
.wi-link a { color: var(--primary); text-decoration: none; font-weight: 600; }
.card-fold.wi-try { margin-bottom: 1rem; }             /* a card's own space below, which .card-fold takes off */
.whatif-who { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; margin-bottom: 0.5rem; }
.whatif-who label { font-weight: 600; margin: 0; }
.whatif-who select { max-width: 18rem; flex: 1 1 12rem; }
.whatif-after p { margin: 0; }
.whatif-after p:last-child { margin-bottom: 0.75rem; }
.whatif-actions { font-size: 0.85rem; color: var(--text-muted); margin-top: 0.15rem !important; }
.whatif-shortcuts { display: flex; flex-wrap: wrap; gap: 0.4rem; margin: 0 0 0.75rem; }
/* A button's words wrap on a narrow screen with large text ("Fill the rest at random" was 342 px wide at 320 px
   with text at 200%: a button keeps its words on one line, .btn). */
.whatif-shortcuts .btn { white-space: normal; max-width: 100%; }
.whatif-sub { font-size: 1rem; margin: 1rem 0 0.5rem; }
.whatif-how { font-size: 0.85rem; margin: 0 0 0.25rem; }
.whatif-caveat { font-size: 0.875rem; margin: 0.5rem 0 0; }
.whatif-note { margin: 0.5rem 0 0; }
.whatif-pick { border: 0; margin: 0 0 0.7rem; padding: 0; min-width: 0; }
.whatif-pick legend { font-size: 0.85rem; padding: 0; margin-bottom: 0.25rem; }
.whatif-helps { display: inline-block; color: var(--success); font-weight: 600; }
.whatif-seg { display: flex; flex-wrap: wrap; gap: 0.35rem; }
.whatif-seg input { position: absolute; opacity: 0; width: 1px; height: 1px; pointer-events: none; }
.whatif-seg label { border: 1px solid var(--border); border-radius: 999px; padding: 0.35rem 0.8rem; font-size: 0.85rem; cursor: pointer; background: var(--bg-card); max-width: 100%; overflow-wrap: anywhere; min-height: 2.25rem; display: inline-flex; align-items: center; }
.whatif-seg input:checked + label { background: var(--primary); border-color: var(--primary); color: var(--on-primary); }
.whatif-seg input:checked + label::before { content: "✓ "; white-space: pre; }
.whatif-seg input:focus-visible + label { outline: 2px solid var(--primary); outline-offset: 2px; }
.whatif-others { margin: 0.75rem 0; }
.whatif-others > summary, .whatif-full > summary { font-weight: 600; padding: 0.4rem 0; }
.whatif-filter { display: flex; gap: 0.5rem; align-items: center; flex-wrap: wrap; margin: 0.25rem 0 0.5rem; font-size: 0.85rem; }
.whatif-filter select { max-width: 16rem; }
.whatif-round-title { font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.04em; color: var(--text-muted); margin: 0.75rem 0 0.35rem; }
.whatif-table td, .whatif-table th { white-space: nowrap; }
.whatif-table td:nth-child(2) { white-space: normal; }
.whatif-mark { text-align: center; color: var(--success); font-weight: 700; }
.whatif-mark--out { color: var(--danger); opacity: 0.75; }
.whatif-gap td { text-align: center; color: var(--text-muted); padding: 0.1rem !important; }
.whatif-cut td { font-size: 0.75rem; color: var(--primary); border-top: 2px dashed var(--primary); padding: 0.2rem 0.5rem !important; }
.whatif-up { color: var(--success); font-size: 0.8rem; }
.whatif-down { color: var(--danger); font-size: 0.8rem; }
.whatif-full { margin: 0.5rem 0; }

/* Email settings (wave 20). */
.email-form { display: flex; gap: 0.5rem; flex-wrap: wrap; align-items: center; }
.email-form .form-control { flex: 1 1 14rem; min-width: 0; }
.email-kind { display: flex; gap: 0.6rem; align-items: flex-start; padding: 0.45rem 0; }
.email-kind input { margin-top: 0.3rem; }
.email-nudge { display: flex; gap: 0.75rem; align-items: center; justify-content: space-between; flex-wrap: wrap; }
.email-nudge form { margin: 0; }

/* Names an organizer entered, to claim (wave 23) */
.claim-list { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.claim-form { margin: 0; }
/* "That's me" is the one tap on the card: a finger's height (WORDING_AND_UI §8; it was .btn-sm's 28 px). */
.claim-form .btn { min-height: 44px; }
.claim-name { padding: 0.25rem 0.6rem; border: 1px solid var(--border); border-radius: 999px; }
.named-list { list-style: none; padding: 0; margin: 0.25rem 0 0; font-size: 0.85rem; }
.named-list li { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; }
.named-list form { margin: 0; }
.club-night-when { display: grid; grid-template-columns: repeat(auto-fit, minmax(130px, 1fr)); gap: 0 0.75rem; }
.club-night-form fieldset { border: 0; padding: 0; }
/* Admin → AI (wave 32): one choice a line, the model under DeepInfra's. */
.ai-choice { border: 0; padding: 0; margin: 0 0 0.5rem; }
.ai-choice label { display: flex; align-items: center; margin: 0.25rem 0; }
.ai-choice select { max-width: 22rem; margin-left: 1.6rem; width: calc(100% - 1.6rem); }
.club-night-form ul { list-style: none; padding: 0; margin: 0.25rem 0 0; }
.quick-card:hover { border-color: var(--primary); }
.share-row { display: flex; gap: 1rem; flex-wrap: wrap; align-items: flex-start; }
.share-qr { width: 132px; height: 132px; flex: none; background: #fff; border-radius: 8px; padding: 4px; }
.share-qr svg { width: 100%; height: 100%; display: block; }
.share-text { flex: 1; min-width: 200px; }
/* An invite link's QR code, folded until wanted (core/partials/qr_link.html) */
.qr-fold { flex-basis: 100%; margin: 0.25rem 0 0.5rem; }
.qr-fold > summary { color: var(--primary); font-size: 0.9rem; min-height: 32px; display: inline-flex; align-items: center; }
.qr-fold-body { display: flex; flex-wrap: wrap; gap: 0.75rem; align-items: center; margin-top: 0.5rem; }
.qr-fold-body p { flex: 1; min-width: 160px; }
.share-qr--big { width: 220px; height: 220px; }

/* The tournament's public page, phone first */
.pub-hero { margin-bottom: 1rem; }
.pub-grid { display: grid; grid-template-columns: 1fr; gap: 1rem; align-items: start; }
.pub-side { display: grid; gap: 1rem; }
@media (min-width: 900px) { .pub-grid { grid-template-columns: minmax(240px, 1fr) 2fr; } }
.facts { display: grid; grid-template-columns: auto 1fr; gap: 0.35rem 1rem; margin: 0; }
.facts dt { color: var(--text-muted); font-weight: normal; }
.facts dd { margin: 0; }
.pub-round { margin-bottom: 0.5rem; }
.pub-round summary { padding: 0.4rem 0; font-weight: 600; }
.pub-result { white-space: nowrap; text-align: right; }

/* The installable app card on Me (wave 24) */
.app-steps { margin: 0.25rem 0 0; padding-left: 1.25rem; line-height: 1.6; }
.app-share { width: 1.1em; height: 1.1em; vertical-align: -0.2em; }
.app-card[hidden], .app-card [hidden] { display: none !important; }
.app-card [data-do] { margin: 0.25rem 0; }
.app-card div[data-part] { display: inline-block; margin-right: 0.5rem; }
.app-card-later { margin: 0.25rem 0 0; }

/* The results desk during play (wave 25) */
.desk-chips { display: flex; gap: 0.4rem; flex-wrap: wrap; margin: 0.5rem 0 1rem; }
.desk-chips .chip { padding: 0.35rem 0.8rem; border: 1px solid var(--border); border-radius: 999px; text-decoration: none; color: inherit; }
.desk-chips .chip.is-on { background: var(--primary); border-color: var(--primary); color: var(--on-primary); }
.desk-table { margin-bottom: 0.9rem; }
.desk-table.is-busy { border-left: 4px solid var(--primary); }
.desk-table-name { font-size: 1.05rem; margin: 0 0 0.35rem; }
.desk-when { margin: 0; font-size: 0.9rem; color: var(--text-muted); }
.desk-late { color: var(--danger, #b42318); font-weight: 600; }
.desk-sides { font-size: 1.15rem; margin: 0.15rem 0 0.6rem; line-height: 1.3; }
.desk-next { margin-top: 0.75rem; padding-top: 0.6rem; border-top: 1px solid var(--border); }
/* The tables at a glance (wave 60e): one tile a table, its state as a coloured edge and in words. */
.desk-tiles { display: grid; grid-template-columns: repeat(auto-fill, minmax(9.5rem, 1fr)); gap: 0.5rem; margin: 0 0 1rem; }
.desk-tile { display: flex; flex-direction: column; gap: 0.15rem; min-height: 44px; padding: 0.55rem 0.7rem;
    border-radius: 10px; border: 1px solid var(--border); border-left: 6px solid var(--border); background: var(--bg-card);
    color: var(--text); text-decoration: none; overflow-wrap: anywhere; }
.desk-tile:hover, .desk-tile:focus-visible { border-color: var(--primary); }
.desk-tile.is-on { box-shadow: 0 0 0 2px var(--primary); }
.desk-tile-name { font-weight: 700; }
.desk-tile-state { font-size: 0.875rem; font-weight: 600; }
.desk-tile-sides, .desk-tile-live { font-size: 0.875rem; color: var(--text-muted); }
.desk-tile-live { font-variant-numeric: tabular-nums; color: var(--text); }
.desk-tile.is-playing { border-left-color: var(--primary); }
.desk-tile.is-playing .desk-tile-state { color: var(--primary); }
.desk-tile.is-due { border-left-color: var(--warning); }
.desk-tile.is-late, .desk-tile.is-disputed { border-left-color: var(--danger); }
.desk-tile.is-late .desk-tile-state, .desk-tile.is-disputed .desk-tile-state { color: var(--danger); }
.desk-tile.is-free { border-left-color: var(--success); }
.desk-tile.is-out, .desk-tile.is-closed { border-left-style: dashed; color: var(--text-muted); }
.desk-tile.is-all { justify-content: center; font-weight: 600; color: var(--primary); }
.desk-shorter { margin: 0 0 1rem; }
/* Everyone's here all day (wave 60g): the check-in QR, who isn't in yet, the matches waiting. */
.desk-queue { margin: 0 0 1rem; }
.desk-queue-qr { width: 9rem; max-width: 100%; margin: 0.25rem 0 0.5rem; }
.desk-checkin { display: flex; flex-wrap: wrap; gap: 0.4rem; margin-top: 0.4rem; }
.desk-checkin form { margin: 0; }
.desk-queue-title { font-size: 0.95rem; margin: 0.75rem 0 0.35rem; }
.desk-queue-list { margin: 0; padding-left: 1.5rem; }
.desk-queue-list li { padding: 0.15rem 0; overflow-wrap: anywhere; }
.check-in-card { max-width: 32rem; }
.desk-shorter-form { display: flex; flex-direction: column; gap: 0.35rem; max-width: 28rem; margin-top: 0.5rem; }
/* The days an entry can't play, on Run → Players (core/cant_play.py). */
.cant-play-note { font-size: 0.875rem; margin-top: 0.25rem; }
/* The waiting list on Run → Players (core/waitlist.py, wave 60a). */
.waitlist-card { margin-top: 1rem; padding: 0.75rem; border-radius: 6px; background: var(--surface-muted); }
.waitlist-title { font-size: 0.95rem; margin: 0 0 0.35rem; }
.waitlist { margin: 0; padding-left: 1.5rem; }
.waitlist li { padding: 0.25rem 0; overflow-wrap: anywhere; }
.waitlist-remove { display: inline; margin: 0 0 0 0.5rem; }
.waitlist-remove .btn-link { min-height: 44px; }
.waitlist-held { font-size: 0.875rem; margin-top: 0.25rem; }
.cant-play { margin-top: 0.35rem; }
.cant-play > summary { font-size: 0.875rem; }
.cant-play form { margin-top: 0.4rem; }
.cant-play-days { display: flex; flex-wrap: wrap; gap: 0.25rem 1rem; margin-bottom: 0.4rem; }
.cant-play-date { max-width: 14rem; }
/* The live board (core/board.py): no menus, for a group chat or a screen at the venue. Two columns on a wide screen;
   across a room, everything a quarter bigger (the root's size, so every rem follows and the reader's own still counts). */
.board-head { display: flex; align-items: center; gap: 0.5rem 1rem; flex-wrap: wrap; max-width: 90rem; margin: 0 auto;
    padding: 1rem 16px 0.25rem; }
.board-brand { display: flex; align-items: center; gap: 0.5rem; margin: 0; flex: none; color: var(--text-muted); font-size: 0.875rem; }
.board-title { font-family: var(--font-heading); font-size: 1.6rem; line-height: 1.2; margin: 0; flex: 1 1 14rem; min-width: 0;
    overflow-wrap: anywhere; }
.board-qr { display: none; margin: 0; flex: none; text-align: center; color: var(--text-muted); font-size: 0.875rem; }
.board-qr [data-qr] { width: 112px; height: 112px; margin: 0 auto 0.25rem; background: #fff; border-radius: 8px; padding: 4px; }
.board-qr svg { width: 100%; height: 100%; display: block; }
.board-main { max-width: 90rem; margin: 0 auto; padding: 0.25rem 16px 2rem; }
.board-status { color: var(--text-muted); margin: 0 0 0.5rem; }
.board-live-dot { display: inline-block; width: 0.6rem; height: 0.6rem; margin-right: 0.4rem; border-radius: 50%;
    background: var(--success); }
.board-grid { display: grid; gap: 0.75rem; grid-template-columns: repeat(auto-fill, minmax(min(100%, 15rem), 1fr)); }
.board-grid .card { margin-bottom: 0; }
.board-table.is-busy { border-left: 4px solid var(--primary); }
.board-table-name { font-size: 1.05rem; margin: 0 0 0.35rem; }
.board-label { margin: 0; font-size: 0.875rem; color: var(--text-muted); }
.board-sides { margin: 0.1rem 0 0; line-height: 1.3; overflow-wrap: anywhere; }
/* A match's count as it's scored live (core/live_count.py, wave 60d), on the board and the desk. */
.live-count { margin: 0.3rem 0 0; font-size: 1rem; overflow-wrap: anywhere; }
.live-count-mark { color: var(--primary); font-weight: 700; font-size: 0.875rem; }
.live-count-score { font-size: 1.25rem; font-variant-numeric: tabular-nums; }
.live-count-serve { color: var(--text-muted); font-size: 0.875rem; }
.live-count.is-stale .live-count-mark { color: var(--text-muted); }
.board-next { margin-top: 0.6rem; padding-top: 0.5rem; border-top: 1px solid var(--border); }
.board-sub { font-size: 1rem; margin: 1rem 0 0.4rem; }
.board-list li { padding: 0.45rem 0; border-bottom: 1px solid var(--border); overflow-wrap: anywhere; }
.board-champion-line { font-size: 1.15rem; margin: 0 0 0.35rem; }
.board-starts { font-size: 1.35rem; font-weight: 600; margin: 0.1rem 0 0.5rem; }
.board-soon .card-body { display: flex; flex-wrap: wrap; gap: 0 3rem; }
.board-soon-note { flex-basis: 100%; margin: 0; }
.board-layout { display: grid; gap: 0 1.5rem; }
.board-col { min-width: 0; }
@media (min-width: 1100px) {
    .board-layout:not(.board-layout--one) { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
    .board-qr { display: block; }
}
@media (min-width: 1600px) { html.board-root { font-size: 125%; } }
/* Who is at the table (core/presence.py). */
.presence-actions { display: flex; flex-wrap: wrap; gap: 0.5rem; align-items: center; margin: 0.25rem 0 0.4rem; }
.presence-actions form { margin: 0; }
.presence-late { display: flex; flex-wrap: wrap; gap: 0.4rem; align-items: center; }
.presence-late select { width: auto; }
.presence-note { font-size: 0.85rem; }
.desk-word { margin: 0 0 0.35rem; font-size: 0.9rem; }
.desk-here { display: flex; flex-wrap: wrap; gap: 0.4rem; margin: 0 0 0.5rem; }
.desk-here form { margin: 0; }
.desk-boxes { margin-bottom: 0.6rem; }
.desk-save { width: 100%; min-height: 48px; font-size: 1.05rem; }
.desk-done-link { flex: 1; color: inherit; text-decoration: none; }
.desk-pending { position: fixed; left: 1rem; right: 1rem; bottom: calc(4.5rem + var(--bar-lift)); z-index: 50;
                background: #1f1e1d; color: #fff; padding: 0.7rem 0.9rem; border-radius: 10px; font-size: 0.9rem; }
.desk-pending[hidden] { display: none; }

/* Results nobody can misread (2026-10-10) */
.you-mark { font-size: 0.75em; font-weight: 500; color: var(--text-muted); white-space: nowrap; }
.match-head .scoreboard { width: 100%; max-width: 100%; border-collapse: collapse; margin: 0.25rem 0 0.6rem; font-variant-numeric: tabular-nums;
                          table-layout: auto; background: none; }
.match-head .scoreboard th, .match-head .scoreboard td { background: none; border: 0; text-transform: none; letter-spacing: normal;
                          font-size: 1rem; padding: 0.3rem 0.2rem; }
.match-head .scoreboard th { text-align: left; font-weight: 500; color: inherit; white-space: normal; overflow-wrap: anywhere;
                             line-height: 1.25; padding-right: 0.4rem; }
.match-head .scoreboard td { text-align: center; color: var(--text-muted); white-space: nowrap; width: 1.75rem;
                             min-width: 1.75rem; padding-left: 0; padding-right: 0; }
.match-head .scoreboard td.took { color: inherit; font-weight: 600; }
.match-head .scoreboard .scoreboard-total { font-weight: 700; color: inherit; width: 2rem; text-align: right; font-size: 1.15rem; }
.match-head .scoreboard tr + tr th, .match-head .scoreboard tr + tr td { border-top: 1px solid var(--border); }
.match-head .scoreboard tr.is-winner th { font-weight: 700; }
.match-head .scoreboard tr.is-winner th::after { content: " ✓"; color: var(--success, #2e7d32); }
/* A best-of-7 with long names cut off at 320 px (walkthrough 5, 2026-10-24): `anywhere` lets a long name break so the
   name column can shrink below its longest word, and under 360 px the game cells and the type narrow a little; 360 px
   and wider unchanged. */
@media (max-width: 359.98px) {
    .match-head .scoreboard th, .match-head .scoreboard td { font-size: 0.92rem; }
    .match-head .scoreboard td { width: 1.4rem; min-width: 1.4rem; }
    .match-head .scoreboard .scoreboard-total { width: 1.6rem; font-size: 1.05rem; }
}
.score-whole { white-space: nowrap; }
/* A result not final yet: what happens next, in the same card, under the score (2026-10-12). */
.match-head .match-next { border-top: 1px solid var(--border); margin-top: 0.6rem; padding-top: 0.6rem; }
.match-head .match-next .dispute-fold[open] { flex-basis: 100%; }
.dispute-fold { display: inline-block; vertical-align: top; }
.dispute-fold[open] { display: block; width: 100%; margin-top: 0.5rem; }
.dispute-fold > summary { list-style: none; display: inline-block; }
.dispute-fold > summary::-webkit-details-marker { display: none; }
.desk-link { display: block; text-decoration: none; color: inherit; margin-bottom: 1rem; }
.desk-link .card-body { display: block; }      /* a span inside the link: its padding as a block's (the walkthrough, 2026-10-18) */
.desk-link:hover { border-color: var(--primary); }

/* An official's Home card: their hat named, one block per tournament. */
/* Which hat a card or line is for (wave 31), shown to someone who wears more than one: the role
   colours, darkened so white small text keeps 4.5:1. */
.hat-tag { display: inline-block; color: #fff; border-radius: 999px; font-family: var(--font-body); font-size: 0.75rem;
           font-weight: 600; letter-spacing: 0; padding: 0.05rem 0.5rem; margin-right: 0.35rem; vertical-align: middle;
           line-height: 1.5; white-space: nowrap; }
.hat-organizer { background: #a84f30; }
.hat-official { background: #4a5fa8; }
.hat-admin { background: #8a5a12; }
.duty-row + .duty-row { border-top: 1px solid var(--border, #e5e5e5); margin-top: 0.75rem; padding-top: 0.75rem; }
.duty-row .todo-list { margin-bottom: 0.5rem; }

/* A password box with its Show button (sign-in). */
.password-row { display: flex; gap: 0.5rem; align-items: stretch; }
.password-row .form-control { flex: 1; min-width: 0; }
.password-row .btn { flex: none; min-width: 4.25rem; }

/* The × on a notice that stays until read. */
.alert-close { float: right; margin: -0.15rem -0.25rem 0 0.5rem; background: none; border: 0; font-size: 1.25rem;
               line-height: 1; cursor: pointer; color: inherit; opacity: 0.7; }
.alert-close:hover { opacity: 1; }
.temp-password { font-size: 1.5rem; letter-spacing: 0.03em; font-family: ui-monospace, monospace; margin: 0.5rem 0 1rem; }

/* The live scorer (core/views/scorer.py): a page of its own, two big sides to tap. */
/* The page holds still (the owner, 2026-10-11: dragging slid it up and down on an iPhone): it is exactly the
   screen, nothing scrolls or bounces, and the two sides take whatever height is left. */
html:has(.scorer-body), .scorer-body { height: 100%; overflow: hidden; overscroll-behavior: none; }
.scorer-body { margin: 0; background: var(--bg); touch-action: manipulation; }
.scorer { position: fixed; inset: 0; display: flex; flex-direction: column; padding: 0.6rem;
    padding: max(0.6rem, env(safe-area-inset-top)) max(0.6rem, env(safe-area-inset-right))
             max(0.6rem, env(safe-area-inset-bottom)) max(0.6rem, env(safe-area-inset-left));
    gap: 0.5rem; box-sizing: border-box; overflow: hidden; }
.scorer-bar { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem; justify-content: space-between; }
.scorer-title { display: flex; flex-direction: column; align-items: center; text-align: center; flex: 1; min-width: 10rem; }
.scorer-status { font-size: 1.05rem; }
.scorer-so-far, .scorer-where { font-size: 0.85rem; color: var(--text-muted); }
.scorer-tools { display: flex; gap: 0.4rem; flex-wrap: wrap; align-items: center; }
/* A thumb's size, and Undo a gap away from the rest (the walkthrough, 2026-10-18). */
.scorer-bar .btn { min-height: 44px; min-width: 44px; }
.scorer-undo { margin-left: 0.75rem; }
/* The bar on one line on a small phone, so the sides keep their room: Back and Full screen as icons. */
.scorer-bar .btn { padding-left: 0.6rem; padding-right: 0.6rem; }
.scorer-icon { display: inline-flex; align-items: center; justify-content: center; }
/* One Swap at a time: while the banner offers its own, the bar's steps aside. */
.scorer:has(.scorer-banner:not([hidden]) [data-do="swap"]) .scorer-tools [data-do="swap"] { display: none; }
.scorer-banner { display: flex; flex-wrap: wrap; gap: 0.6rem; align-items: center; justify-content: center; padding: 0.6rem;
    border-radius: 12px; background: var(--bg-card); border: 2px solid var(--primary); font-weight: 600; }
.scorer-banner[hidden], .scorer-serve[hidden], .scorer-done[hidden] { display: none; }
.scorer-serve { text-align: center; padding: 0.75rem; border-radius: 12px; background: var(--bg-card); }
.scorer-serve p { margin: 0 0 0.5rem; font-weight: 600; }
.scorer-serve-choices { display: flex; flex-wrap: wrap; gap: 0.5rem; justify-content: center; align-items: center; }
.scorer-sides { display: flex; gap: 0.6rem; flex: 1 1 auto; min-height: 0; }
/* The scorer shows once scorer.js has drawn it (its title, the serve question): the first paint was a half-drawn page.
   If the script never runs, it shows anyway after 2.5 s; without script (no .js) it shows at once. */
.js .scorer:not(.is-ready) { visibility: hidden; animation: tm-scorer-show 0s linear 2.5s forwards; }
@keyframes tm-scorer-show { to { visibility: visible; } }
.scorer.is-swapped .scorer-sides { flex-direction: row-reverse; }
/* Each side keeps its own colour wherever it stands, so the eye follows the colour across a swap: clay and slate
   (ivory in the dark theme), the text on each its colour's own. */
.scorer-side[data-point="1"] { --side: var(--primary); --on-side: var(--on-primary); }
.scorer-side[data-point="2"] { --side: var(--text); --on-side: var(--bg); }
.scorer-side { flex: 1 1 0; min-width: 0; display: flex; flex-direction: column; align-items: center; justify-content: center;
    gap: 0.4rem; border: 3px solid var(--side, var(--primary)); border-radius: 18px; background: var(--bg-card); color: var(--text);
    padding: 0.75rem 0.5rem; cursor: pointer; touch-action: manipulation; -webkit-tap-highlight-color: transparent;
    overflow: hidden; min-height: 0; container-type: size; }
.scorer-side:active { background: var(--side, var(--primary)); color: var(--on-side, var(--on-primary)); }
.scorer-side:disabled { opacity: 0.55; cursor: default; }
.scorer-name { font-size: clamp(1rem, 3.5vw, 1.6rem); font-weight: 700; text-align: center; overflow-wrap: break-word; }
/* The points take the room the side has, not the screen's (the owner, 2026-10-17: with the banner and the minute up,
   a number sized to the screen pushed the name and the games out of a short side). The name and the games keep
   their line; the screen's size stays for a browser without container units. */
.scorer-name, .scorer-meta { flex: none; }
.scorer-points { font-size: clamp(3rem, min(20vw, 22vh), 12rem);
    font-size: clamp(1.5rem, min(44cqw, 100cqh - 5rem), 12rem); font-weight: 700; line-height: 1; font-variant-numeric: tabular-nums; }
.scorer-meta { font-size: 0.95rem; color: var(--text-muted); }
.scorer-side:active .scorer-meta { color: var(--on-side, #fff); }
.scorer-serving-mark { visibility: hidden; color: var(--side, var(--primary)); font-weight: 700; }
.scorer-side.is-serving { box-shadow: 0 0 0 4px color-mix(in srgb, var(--side, var(--primary)) 30%, transparent); }
/* After a swap made by itself the sides wait for "OK, ends changed": a tap scores nothing and says so. */
.scorer.is-held .scorer-side { opacity: 0.55; }
.scorer.is-held .scorer-side:active { background: var(--bg-card); color: var(--text); }
.scorer-swapped-chip { align-self: center; font-size: 0.8rem; font-weight: 700; padding: 0.15rem 0.5rem; border-radius: 999px;
    border: 1px solid var(--primary); color: var(--primary); white-space: nowrap; }
.scorer-swapped-chip[hidden], .scorer-banner [hidden] { display: none; }
.scorer-banner.is-nudged { border-color: var(--danger, #dc2626); }
/* While a banner or the minute between games shows, the help steps aside: the sides keep their room. */
.scorer:has(.scorer-banner:not([hidden])) .scorer-help,
.scorer:has(.scorer-timer:not([hidden])) .scorer-help { display: none; }
.scorer-banner.is-pulsing { animation: scorer-pulse 0.35s ease-in-out 3; }
@keyframes scorer-pulse { 50% { transform: scale(1.04); } }
@media (prefers-reduced-motion: reduce) { .scorer-banner.is-pulsing { animation: none; } }
.scorer-auto { display: flex; gap: 0.4rem; align-items: center; justify-content: center; font-size: 0.85rem; margin: 0; }
.scorer-side.is-serving .scorer-serving-mark { visibility: visible; }
.scorer-help { text-align: center; font-size: 0.85rem; margin: 0; }
/* Time-outs and breaks (wave 47): a time-out for each side under its name, the minute counting down, and a flash at
   its end with the beep and the buzz. */
.scorer-timeouts { display: flex; gap: 0.6rem; }
.scorer.is-swapped .scorer-timeouts { flex-direction: row-reverse; }
.scorer-timeout { flex: 1 1 0; justify-content: center; text-align: center; }
/* Thumb-sized where the room allows: the time-outs and the banner's buttons (the walkthrough, 2026-10-18: 27px). */
/* Not on a short screen, where the sides need the room (the swap walk's 320x568 phone and a phone on its side). */
@media (min-height: 700px) { .scorer-timeout, .scorer-banner .btn { min-height: 40px; } }
.scorer-timer { display: flex; flex-wrap: wrap; gap: 0.4rem 0.8rem; align-items: center; justify-content: center;
    padding: 0.6rem; border-radius: 12px; background: var(--bg-card); border: 2px solid var(--primary); text-align: center; }
.scorer-timer[hidden], .scorer-towel[hidden] { display: none; }
/* The count on the server (wave 60d): held by another phone, asked for, and doubles' serving order. */
.scorer-held, .scorer-asked, .scorer-start { display: flex; flex-wrap: wrap; gap: 0.5rem; align-items: center;
    justify-content: center; padding: 0.6rem; border-radius: 12px; background: var(--bg-card); text-align: center; }
.scorer-held { border: 2px dashed var(--border); }
.scorer-asked { border: 2px solid var(--primary); }
.scorer-start { flex-direction: column; }
.scorer-held p, .scorer-asked p, .scorer-start p { margin: 0; font-weight: 600; flex-basis: 100%; }
.scorer-held[hidden], .scorer-asked[hidden], .scorer-start[hidden], .scorer-order[hidden] { display: none; }
.scorer-order { margin: 0; text-align: center; font-weight: 600; font-size: 1.05rem; }
.scorer.is-readonly .scorer-side { cursor: default; }
.scorer-timer p { margin: 0; }
.scorer-timer-what { font-weight: 700; }
.scorer-timer-left { font-size: 2rem; font-weight: 700; font-variant-numeric: tabular-nums; line-height: 1; }
.scorer-towel { text-align: center; margin: 0; font-size: 0.9rem; }
.scorer.is-flashing { animation: scorer-flash 0.5s ease-in-out 6; }
@keyframes scorer-flash { 50% { background: var(--primary); } }
@media (prefers-reduced-motion: reduce) { .scorer.is-flashing { animation: none; outline: 6px solid var(--primary); } }
.scorer-done { position: fixed; inset: 0; z-index: 20; display: flex; align-items: center; justify-content: center; padding: 1rem;
    background: color-mix(in srgb, var(--bg) 88%, transparent); }
.scorer-done .card { max-width: 34rem; width: 100%; margin: 0 auto; }
.scorer-summary { font-size: 1.15rem; font-weight: 700; }
.scorer-save { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-bottom: 0.6rem; }
.scorer-closed { max-width: 34rem; margin: 2rem auto; }

/* What placed rows level on the table's first count (core/standings.tie_notes). */
.tie-note { font-size: 0.9rem; margin: 0.5rem 1rem 0.75rem; }

/* What a menu badge counts, marked on its page (the owner, 2026-10-11): a red edge on the card, a red dot on
   each row, and on the card a few words saying what it needs. The badge's link opens at #needs-you. */
.needs-you { border-left: 4px solid var(--danger, #dc2626) !important; }
.needs-you-inline { border-left: 3px solid var(--danger, #dc2626); padding-left: 0.6rem; }
.needs-dot { display: inline-block; width: 0.55rem; height: 0.55rem; border-radius: 50%; margin-right: 0.45rem;
    background: var(--danger, #dc2626); vertical-align: middle; }
.needs-tag { display: inline-flex; align-items: center; gap: 0.4rem; margin: 0 0 0.35rem; font-size: 0.85rem;
    font-weight: 700; color: var(--danger, #dc2626); }
.needs-tag::before { content: ""; width: 0.55rem; height: 0.55rem; border-radius: 50%; background: var(--danger, #dc2626); }
.needs-elsewhere { font-size: 0.85rem; margin-top: 0.5rem; }
/* A place a page or a form comes back to clears the sticky top bar. */
#needs-you, .card[id] { scroll-margin-top: calc(var(--topbar-h, 60px) + 0.75rem); }
.match-next[id] { scroll-margin-top: calc(var(--topbar-h, 60px) + 0.75rem); }
/* A move waiting on the viewer, first on the match page (wave 59k): both sides' other matches that day. */
.move-day { margin: 0 0 0.6rem; }
.move-day li { margin-bottom: 0.15rem; }
.move-answer-buttons { margin-bottom: 0.5rem; }
.move-answer .fold { margin-top: 0.5rem; }
/* "Suggest another time": the third answer, a button like the other two (PLAYER_TIMES_PLAN, part B). */
.move-answer .fold > summary.btn { display: inline-flex; list-style: none; padding: 0.45rem 0.9rem; color: var(--text); }
.move-answer .fold > summary.btn::-webkit-details-marker { display: none; }
html[data-theme="dark"] .move-answer .fold > summary.btn { color: #f5f4ee; }
/* A time the players agreed outside the table hours (part A): said plainly, never alarming. */
.move-outside { color: var(--text-muted); font-size: 0.9rem; }


/* An open knockout place: who will fill it, or a reported side still to be confirmed (core/knockout.side_words). */
.open-side { color: var(--text-muted); font-style: italic; }

/* A bracket box's words the score can't say (core/bracket_view): "Bye", "ret.", "To confirm". */
.bracket-bye { color: var(--text-muted); font-style: italic; font-weight: 500; }
.bracket-mark { font-size: 0.75rem; font-weight: 600; color: var(--text-muted); }
.bracket-match-note { font-size: 0.75rem; margin-top: 0.3rem; }
/* What the table says since the news story it sits under (wave 59i): plain, from the table, never the AI. */
.news-since { font-size: 0.9rem; padding: 0.35rem 0.6rem; border-left: 3px solid var(--primary, #C0502B); background: var(--surface-muted, rgba(0, 0, 0, 0.03)); }
/* A knockout match's name above its box, "QF 1" (wave 59l), which open places refer to ("Winner of QF 1"). */
.bracket-match-name { font-size: 0.75rem; font-weight: 600; color: var(--text-muted); margin-bottom: 0.2rem; }

/* Paused (core/pause.py): said where the next match is shown. */
.next-paused { font-weight: 600; color: var(--warning-text, #92400e); }

/* Words a person wrote (templates/core/partials/person_words.html; walkthrough 9, the owner): a request's reason, a
   dispute's, the "Neither side played" reason. On its own line, labelled, in a soft box with a bar at its left: set
   apart from the site's sentences, and never red (it isn't the site warning anyone). */
.person-words { display: block; margin: 0.3rem 0 0.6rem; padding: 0.4rem 0.7rem; border-left: 3px solid var(--text-muted); border-radius: 0 6px 6px 0; background: var(--surface-muted); color: var(--text); font-weight: 400; text-align: left; }
.person-words-who { display: block; font-size: 0.875rem; color: var(--text-muted); }
.person-words-text { display: block; white-space: pre-line; overflow-wrap: anywhere; }

/* My sign-ups: one entry a row, its way out under it (2026-10-12) */
.signup-row { padding: 0.65rem 0; border-top: 1px solid var(--border); }
.signup-row:first-child { border-top: 0; padding-top: 0; }

.d-block { display: block; }

/* Me → Email: the link sent, where it may have landed, and another after a minute. */
.link-sent { border-left: 3px solid var(--role-accent, var(--primary)); padding: 0.5rem 0 0.25rem 0.75rem; margin: 0.5rem 0 0.75rem; }

/* Paper (wave 36): the printed sheets (core/print/, core/views/printing.py) on screen and on
   paper, and any other page printed from the browser without its menus and buttons. */
.print-page { background: #fff; color: #1f1e1d; }
.print-toolbar { position: sticky; top: 0; z-index: 2; display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem;
                 padding: 0.6rem 16px; background: var(--bg); border-bottom: 1px solid var(--border); }
.print-toolbar > .btn-primary { margin-left: auto; }
/* Each sheet's PDF, made on the server (core/pdf.py), beside Print. */
.print-pdf { display: inline-flex; align-items: center; gap: 0.35rem; margin-left: auto; font-size: 0.9rem; }
.print-pdf + .btn-primary { margin-left: 0; }
.print-days { display: flex; flex-wrap: wrap; gap: 0.35rem; }
.print-days .chip { padding: 0.25rem 0.7rem; border: 1px solid var(--border); border-radius: 999px; text-decoration: none;
                    color: inherit; font-size: 0.85rem; }
.print-days .chip.is-on { background: var(--primary); border-color: var(--primary); color: var(--on-primary); }
.print-sheet { max-width: 60rem; margin: 0 auto; padding: 1.25rem 16px 2rem; }
.print-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 1rem;
              border-bottom: 2px solid #1f1e1d; padding-bottom: 0.6rem; margin-bottom: 1rem; }
.print-head h1 { font-family: var(--font-heading); font-size: 1.6rem; line-height: 1.2; margin: 0.15rem 0; }
.print-brand { display: flex; align-items: center; gap: 0.5rem; margin: 0; font-size: 0.85rem; color: var(--text-muted); }
.print-what { margin: 0; }
.print-qr { margin: 0; flex: none; text-align: center; font-size: 0.7rem; color: var(--text-muted); }
/* Each QR code is a link too, so a sheet's PDF opens it when tapped (the owner, 2026-10-15). */
.print-qr [data-qr] { display: block; width: 84px; height: 84px; margin-bottom: 0.2rem; }
.print-qr svg, .score-sheet-qr svg { display: block; width: 100%; height: 100%; }
.print-champion { font-size: 1.1rem; }
/* The sign-up flyer (core/print/flyer.html): one page for a notice board, the QR code its centre. The clay
   rule and tile print in colour (or grey); the QR code stays black on white so every phone reads it. */
.flyer { max-width: 186mm; margin: 0 auto; padding: 8mm 10mm 6mm; border-top: 8px solid var(--clay);
         -webkit-print-color-adjust: exact; print-color-adjust: exact; }
.flyer-brand { display: flex; align-items: center; gap: 0.5rem; margin: 0 0 1.25rem; font-family: var(--font-heading);
               font-weight: 600; font-size: 1.1rem; }
.flyer-sport { margin: 0; text-transform: uppercase; letter-spacing: 0.08em; font-weight: 700; font-size: 0.95rem;
               color: var(--primary); }
.flyer-name { font-family: var(--font-heading); font-size: 2.6rem; line-height: 1.1; margin: 0.2rem 0 0.8rem;
              overflow-wrap: anywhere; }
.flyer-facts { list-style: none; padding: 0; margin: 0 0 1.25rem; font-size: 1.15rem; line-height: 1.5; }
.flyer-join { display: flex; align-items: center; gap: 1.5rem; padding: 1.25rem; margin: 0 0 1.25rem;
              border: 2px solid var(--line); border-radius: 12px; }
.flyer-qr { display: block; width: 62mm; max-width: 45vw; aspect-ratio: 1; flex: none; background: #fff; padding: 2.5mm;
            box-sizing: border-box; }
.flyer-qr svg { display: block; width: 100%; height: 100%; }
.flyer-scan { font-family: var(--font-heading); font-weight: 600; font-size: 1.5rem; line-height: 1.2; margin: 0 0 0.4rem; }
.flyer-ask { font-size: 1.1rem; margin: 0 0 0.75rem; }
.flyer-link { font-family: ui-monospace, monospace; font-size: 0.8rem; color: var(--text-muted); margin: 0;
              overflow-wrap: anywhere; }
.flyer-link a { color: inherit; text-underline-offset: 2px; }
.flyer-how h2 { font-family: var(--font-heading); font-size: 1.15rem; margin: 0 0 0.4rem; }
.flyer-how ul { margin: 0; padding-left: 1.2rem; line-height: 1.45; }
.flyer-how li + li { margin-top: 0.3rem; }
.flyer-foot { margin: 1.25rem 0 0; padding-top: 0.6rem; border-top: 1px solid var(--line); color: var(--text-muted); }
@media (max-width: 520px) {
    .flyer { padding: 6mm 4mm; }
    .flyer-name { font-size: 2rem; }
    .flyer-join { flex-direction: column; text-align: center; }
    .flyer-qr { max-width: 70vw; width: 60vw; }
}
.print-group h2, .print-day h2 { font-size: 1.1rem; margin: 1.1rem 0 0.4rem; }
.print-group { break-inside: avoid; }
.print-note, .print-sheet .tie-note, .print-sheet .table-legend { color: var(--text-muted); font-size: 0.85rem; }
.print-order { width: 100%; border-collapse: collapse; }
.print-order th, .print-order td { border: 1px solid #b9b5aa; padding: 0.3rem 0.5rem; text-align: left; vertical-align: top; }
.print-order tr { break-inside: avoid; }
.print-order .print-score, .print-order .print-score-h { width: 11rem; }
.print-order .print-score { font-size: 0.85rem; }
/* The table on paper: tighter rows, names in ink, and the going-through shading printed (browsers leave
   backgrounds out, and the legend says "shaded"). */
.print-sheet a { color: inherit; text-decoration: none; }
.print-sheet .standings-table th, .print-sheet .standings-table td { padding: 0.3rem 0.5rem; }
.print-sheet .row-advance td { -webkit-print-color-adjust: exact; print-color-adjust: exact; }
.score-sheets { display: grid; grid-template-columns: repeat(2, 1fr); gap: 0.75rem; }
.score-sheet { display: flex; flex-direction: column; gap: 0.45rem; border: 1.5px solid #1f1e1d; border-radius: 6px;
               padding: 0.6rem 0.7rem; break-inside: avoid; }
.score-sheet p { margin: 0; }
.score-sheet header { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 0 0.75rem; font-size: 0.85rem; }
.score-sheet-when { white-space: nowrap; }
.score-sheet-what { font-weight: 600; }
.score-sheet-boxes { width: 100%; border-collapse: collapse; table-layout: fixed; }
.score-sheet-boxes th, .score-sheet-boxes td { border: 1px solid #1f1e1d; padding: 0.3rem; font-size: 0.8rem; background: none;
                                               color: inherit; text-transform: none; letter-spacing: normal; }
.score-sheet-boxes thead th { font-weight: 500; text-align: center; }
.score-sheet-boxes thead th:first-child { text-align: left; color: var(--text-muted); }
.score-sheet-boxes thead th:first-child { width: 38%; }
.score-sheet-boxes tbody th { text-align: left; font-weight: 600; overflow-wrap: anywhere; }
.score-sheet-boxes td { height: 2.2rem; }
.score-sheet footer { display: grid; grid-template-columns: 1fr auto; align-items: end; gap: 0.35rem 0.6rem; font-size: 0.85rem; }
.score-sheet-qr { grid-row: 1 / span 2; grid-column: 2; margin: 0; text-align: center; font-size: 0.65rem; color: var(--text-muted); }
.score-sheet-qr [data-qr] { display: block; width: 64px; height: 64px; margin-bottom: 0.15rem; }
.score-sheet-line { display: inline-block; width: 9rem; height: 1rem; border-bottom: 1px solid #1f1e1d; vertical-align: bottom; }
.score-sheet-line.short { width: 3.5rem; }
@media (max-width: 640px) { .score-sheets { grid-template-columns: 1fr; } }
@page { margin: 12mm; }
@media print {
    .print-toolbar, .sidebar, .topbar, .bottom-bar, .site-footer, .btn, button, form, .no-print { display: none !important; }
    .print-sheet { max-width: none; padding: 0; }
    .main-content { margin: 0 !important; }
    body, .print-page { background: #fff !important; color: #000; }
    .card { box-shadow: none !important; break-inside: avoid; }
    a { color: inherit !important; text-decoration: none; }
    .standings-table .col-extra { display: table-cell !important; }
    .standings-table .row-extra { display: none !important; }
    .score-sheets { grid-template-columns: repeat(2, 1fr); }
    /* A bracket wider than the page scrolls on screen; on paper its rounds wrap instead of being cut off. */
    .print-brackets .bracket-container { overflow: visible; flex-wrap: wrap; row-gap: 1rem; }
    .print-brackets .card { break-inside: auto; }
}

/* The rules card (wave 36, core/rules_card.py). */
.rules-list { margin: 0; padding-left: 1.1rem; }
.rules-list li { margin: 0.3rem 0; line-height: 1.45; }

/* Closed days on Run's Tables step (wave 38, core/closures.py). */
.holiday-ask { border-left: 3px solid var(--state-your-turn, #d97706); padding: 0.25rem 0 0.4rem 0.75rem; margin-bottom: 0.75rem; }
.inline-actions { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.closed-list li { margin: 0.3rem 0; }
.no-play { margin: 0.5rem 0; padding: 0.5rem 0.75rem; border-radius: 8px; background: var(--tint); font-size: 0.95rem; }

/* Score live where the match is about to be played (wave 47g): its buttons side by side, the hint small. */
.next-actions, .live-offer { display: flex; flex-wrap: wrap; gap: 0.5rem; align-items: center; margin: 0.5rem 0; }
.live-offer p { flex-basis: 100%; }
.next-live-hint { font-size: 0.875rem; }
/* Home's two ways to record a match (the owner, 2026-10-27, A1): each button with its one line beside it, under it on a
   narrow phone. */
.record-ways { margin: 0.5rem 0; }
.record-way { display: flex; flex-wrap: wrap; gap: 0.25rem 0.75rem; align-items: center; margin: 0 0 0.5rem; }
.record-way .btn { flex: 0 0 auto; min-width: 9.5rem; justify-content: center; text-align: center; }
.record-way > span { flex: 1 1 12rem; font-size: 0.875rem; }

/* The front page (views/site_pages.front_page): what Tunafly is, for a first visit and search engines. */
.front-hero { text-align: center; margin: 0.5rem 0 2rem; }
.front-lead { font-size: 1.15rem; max-width: 36rem; margin: 0 auto 1rem; }
.front-actions { margin: 1rem 0 0.5rem; }
.front-features { display: grid; grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr)); gap: 1rem; }
.front-features .card { margin: 0; }
.front-features p { margin: 0; }
.front-organize { text-align: center; margin: 2rem 0 1rem; }

/* Seeding (wave 49b): the seed beside a name on Players. */
/* The seed places (wave 54): each band its places, a list of the players in each. */
.seed-band { border: 0; padding: 0; margin: 0 0 1.1rem; min-width: 0; }
.seed-band legend { padding: 0; margin-bottom: 0.4rem; font-size: 1rem; }
.seed-slots { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 13rem), 1fr)); gap: 0.5rem; }
.seed-slot-wrong { border-color: var(--danger); box-shadow: 0 0 0 1px var(--danger); }
/* Save stays in reach while the places are on screen, and says when there's something to save. */
.seed-save { position: sticky; bottom: 0; z-index: 5; display: flex; flex-wrap: wrap; align-items: center; gap: 0.75rem;
             padding: 0.75rem 0; background: var(--bg-card); border-top: 1px solid var(--border); }
.seed-unsaved { font-weight: 600; color: var(--text); }
.seed-unsaved[hidden] { display: none; }
@media (max-width: 760px) { .seed-save { bottom: calc(4.5rem + var(--bar-lift)); } }     /* above the phone's bar */
.seed-tag { display: inline-block; margin-left: 0.35rem; padding: 0 0.45rem; border-radius: 999px; font-size: 0.875rem;
    font-weight: 600; border: 1px solid var(--primary); color: var(--primary); text-decoration: none; vertical-align: 0.05em; }

/* The end of a done step: "✓ This step is done." and Next (wave 51a). */
.step-next { margin-top: 1.5rem; padding-top: 1rem; border-top: 1px solid var(--border); scroll-margin-top: 6rem; }
.step-next-done { display: flex; align-items: center; gap: 0.6rem; margin: 0 0 0.75rem; font-weight: 600; }
.step-next .btn { min-height: 44px; }
.draft-note { display: flex; flex-wrap: wrap; gap: 0.5rem 1rem; align-items: center; justify-content: space-between; }
.draft-note form { margin: 0; }
.topbar-tournament-slot { display: contents; }

/* The draft check (wave 52b): what passed, the problems that stop Publish, what's worth knowing. */
.draft-check-list li { display: grid; grid-template-columns: 1.4rem 1fr; gap: 0.4rem; padding: 0.3rem 0; }
.draft-check-mark { font-weight: 700; text-align: center; }
.draft-check-ok .draft-check-mark { color: var(--success); }
.draft-check-problem .draft-check-mark, .draft-check-problem { color: var(--danger); }
.draft-check-note .draft-check-mark { color: var(--text-muted); }
.draft-check-sub { font-size: 0.9rem; font-weight: 700; color: var(--text-muted); margin: 0.6rem 0 0.2rem; }

/* A player's own matches on paper (Print my matches, 2026-10-17): one page an entry when the organizer prints them all. */
.my-sheet-people { margin: 0 0 0.2rem; }
/* The same columns every day, so the days line up down the page. */
.my-sheet-matches { table-layout: fixed; }
.my-sheet-matches .my-sheet-time, .my-sheet-matches .my-sheet-n { width: 4.5rem; }
.my-sheet-matches .my-sheet-table { width: 6rem; }
.my-sheet-matches .my-sheet-result { width: 11rem; }
.my-sheet > .print-note { margin-top: 0.9rem; }
@media (max-width: 640px) {
    .my-sheet-matches .my-sheet-time, .my-sheet-matches .my-sheet-n { width: 3.6rem; }
    .my-sheet-matches .my-sheet-table { width: 4.2rem; }
    .my-sheet-matches .my-sheet-result { width: 6.5rem; }
}
.my-sheet + .my-sheet { margin-top: 2.5rem; }
@media print { .my-sheet + .my-sheet { margin-top: 0; break-before: page; } }
.print-mine-link { margin: 0.25rem 0 0.75rem; }
.fixtures-whose { font-size: 1.15rem; margin: 0.5rem 0; }
/* A long name in a title breaks rather than widen the page (a player's page with text at 200%, 2026-11-04). */
.page-title { overflow-wrap: anywhere; min-width: 0; }
/* Notifications: the actions beside the title wrap under it on a phone; the cleared link under the list. */
.notif-head { display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 0.5rem; }
.notif-actions { display: flex; gap: 0.5rem; flex-wrap: wrap; }
.notif-cleared { margin: 0.75rem 1rem; }
/* "‹ Today's matches" over a match opened from Matches: a phone app has no browser back (the owner, 2026-11-04). */
.back-link { margin: 0 0 0.25rem; }
.back-link a { display: inline-block; padding: 0.5rem 0; min-height: 44px; text-decoration: none; font-weight: 600; }
/* A player's page: the card beside their tournaments and matches; one column on a phone (their matches are why
   players open it: the owner, 2026-11-02). */
.profile-grid { grid-template-columns: 1fr 2fr; gap: 1.5rem; align-items: start; }
@media (max-width: 700px) { .profile-grid { grid-template-columns: 1fr; gap: 1rem; } }   /* "Kim Lee's matches": a name tapped on the Table */

/* Told about your matches (core/reach.py): one card, two rows. */
.reach-card[hidden], .reach-card [hidden] { display: none !important; }
.reach-row { border-top: 1px solid var(--border); padding-top: 0.6rem; margin-top: 0.6rem; }
.reach-row-h { font-size: 0.95rem; font-weight: 700; margin: 0 0 0.35rem; }
.reach-email { display: flex; flex-wrap: wrap; gap: 0.5rem; align-items: center; margin-bottom: 0.35rem; }
.reach-email .form-control { flex: 1 1 12rem; min-width: 0; }
.reach-later { margin-top: 0.5rem; }
.reach-count summary { font-weight: 600; }
/* The iPhone's steps, each with its picture: drawn in the theme's own colours, the place to tap in clay. */
.app-steps-pictured { list-style: none; padding-left: 0; counter-reset: app-step; }
.app-steps-pictured li { display: flex; gap: 0.75rem; align-items: center; margin-bottom: 0.5rem; counter-increment: app-step; }
.app-steps-pictured li > span::before { content: counter(app-step) ". "; font-weight: 700; }
.app-step-pic { flex: none; width: 96px; height: auto; }
.app-step-pic[hidden], .app-steps-pictured [data-browser][hidden] { display: none; }
.app-step-pic .pic-screen { fill: var(--bg); stroke: var(--text-muted); stroke-width: 1.5; }
.app-step-pic .pic-page { fill: var(--surface-muted, var(--border)); }
.app-step-pic .pic-bar { fill: var(--bg-card); stroke: var(--border); }
.app-step-pic .pic-line { fill: none; stroke: var(--text-muted); stroke-width: 1.6; stroke-linecap: round; }
.app-step-pic .pic-ink { fill: var(--text); }
.app-step-pic .pic-tap { fill: none; stroke: var(--primary); stroke-width: 2.5; }
.app-step-pic .pic-tap-row { fill: color-mix(in srgb, var(--primary) 14%, transparent); stroke: var(--primary); stroke-width: 2; }
.app-step-pic .pic-share { fill: none; stroke: var(--primary); stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }

/* Send feedback (core/feedback.py): the form, the inbox and My feedback. */
.feedback-kinds, .feedback-to { border: 0; padding: 0; margin: 0 0 0.9rem; }
.feedback-kinds { display: flex; flex-wrap: wrap; gap: 0.4rem; }
.feedback-kinds legend { width: 100%; }
.feedback-to .radio-label { display: block; margin-bottom: 0.35rem; }
.feedback-attached { border-top: 1px solid var(--border); padding-top: 0.6rem; margin: 0.6rem 0; }
.feedback-send { display: flex; flex-wrap: wrap; gap: 0.75rem; align-items: center; }
.feedback-meta { font-size: 0.9rem; margin-bottom: 0.35rem; }
.feedback-text { white-space: normal; overflow-wrap: anywhere; }
.feedback-reply { border-left: 3px solid var(--primary); padding: 0.25rem 0 0.25rem 0.6rem; margin: 0.5rem 0; }
.feedback-picture { max-width: min(100%, 22rem); max-height: 16rem; border: 1px solid var(--border); border-radius: 8px; }
.feedback-answer { margin-top: 0.6rem; }
.feedback-actions { display: flex; flex-wrap: wrap; gap: 0.4rem; margin-top: 0.4rem; }
.feedback-state-new { background: var(--primary); color: var(--on-primary); }
.feedback-state-seen { background: var(--surface-muted, var(--border)); color: var(--text); }
.feedback-state-done { background: transparent; border: 1.5px solid var(--success); color: var(--success); }

/* The questions at a tournament's end (core/feedback_form.py): the form, Home's card and the summary. */
.survey-question { border: 0; padding: 0; margin: 0 0 1.1rem; min-width: 0; }
.survey-question legend { font-weight: 600; margin-bottom: 0.4rem; }
.survey-question .radio-label { display: flex; gap: 0.5rem; align-items: center; min-height: 44px; }
/* How the day runs: each choice its own line, Save under them (walkthrough 11, U6: on a phone the two ran together
   with Save in the middle). */
.run-mode-choice { display: block; margin-bottom: 0.5rem; }
.survey-question textarea { width: 100%; }
.survey-error { color: var(--danger); font-weight: 600; margin: 0 0 0.3rem; }
.survey-card-actions { display: flex; flex-wrap: wrap; gap: 0.75rem; align-items: center; }
.survey-counts { list-style: none; margin: 0 0 0.6rem; padding: 0; }
.survey-counts li { display: flex; justify-content: space-between; gap: 1rem; padding: 0.3rem 0; border-bottom: 1px solid var(--border); }
.survey-counts li:last-child { border-bottom: 0; }
.survey-said { list-style: none; margin: 0 0 0.6rem; padding: 0; }
.survey-said li { padding: 0.4rem 0; border-bottom: 1px solid var(--border); overflow-wrap: anywhere; }
.survey-said li:last-child { border-bottom: 0; }
.board-questions .board-qr { display: flex; gap: 0.75rem; align-items: center; text-align: left; font-size: 1rem; color: var(--text); }
.board-questions .board-qr [data-qr] { margin: 0; }
.feedback-item.is-done { opacity: 0.8; }
.feedback-item.is-done .feedback-text { color: var(--text-muted); }

/* The live board's screen mode (core/board.screen, static/js/board_screen.js; 2026-10-17): a TV across the hall.
   The page is the window and never scrolls; text is sized by the window and never under 18px; the tables stay put
   on top and the panels rotate below. Dark whatever the viewer's theme (the template sets it). */
html.screen-root { font-size: clamp(18px, 0.85vw + 0.55vh, 34px); height: 100%; overflow: hidden; }
.screen-page { height: 100%; margin: 0; overflow: hidden; display: flex; flex-direction: column; background: var(--bg);
               color: var(--text); }
.screen-head { display: flex; align-items: center; gap: 0.75rem; padding: 0.5rem 1rem 0.25rem; flex: none; }
.screen-title { font-family: var(--font-heading); font-size: 1.5rem; line-height: 1.15; margin: 0; flex: 1; min-width: 0;
                overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.screen-tools { display: flex; gap: 0.4rem; flex: none; }
.screen-icon { display: inline-flex; align-items: center; justify-content: center; width: 2rem; height: 2rem; padding: 0;
               border: 1px solid var(--border); border-radius: 8px; background: transparent; color: var(--text-muted);
               cursor: pointer; }
.screen-icon[hidden] { display: none; }
.screen-icon svg { width: 1.1rem; height: 1.1rem; }
.screen-icon:hover, .screen-icon:focus-visible { color: var(--text); border-color: var(--text-muted); }
.screen-banner { flex: none; margin: 0 1rem 0.4rem; padding: 0.5rem 0.9rem; border-radius: 10px; background: var(--primary);
                 color: var(--on-primary); font-weight: 700; font-size: 1.15rem; }
.screen-banner[hidden] { display: none; }
.screen-banner.is-sliding { animation: screen-in 0.45s ease-out; }
@keyframes screen-in { from { transform: translateY(-0.6rem); opacity: 0; } to { transform: none; opacity: 1; } }
.screen-main { flex: 1; min-height: 0; display: flex; flex-direction: column; gap: 0.6rem; padding: 0 1rem 0.6rem; overflow: hidden; }
.screen-status { margin: 0; color: var(--text-muted); font-size: 0.85rem; flex: none; }
.screen-label { margin: 0; color: var(--text-muted); }
.screen-big { font-size: 2.2rem; font-weight: 700; margin: 0 0 0.6rem; }
.screen-soon { display: flex; flex-wrap: wrap; gap: 1rem 3rem; align-items: center; }
.screen-champion { flex: none; padding: 0.6rem 1rem; border-radius: 12px; background: var(--bg-card); border: 2px solid var(--primary); }
.screen-champion-line { font-size: 1.6rem; margin: 0; }
.screen-podium { margin: 0.25rem 0 0; font-size: 1.1rem; }
/* The tables: their room by how many there are; the tiles in number order, never shuffled. */
.screen-tables { flex: none; display: flex; flex-direction: column; gap: 0.3rem; }
.screen-tiles { display: grid; gap: 0.6rem; overflow: hidden; align-content: start;
                grid-template-columns: repeat(auto-fit, minmax(min(100%, 13rem), 1fr)); max-height: 38vh; }
.screen-tables[data-band="1-2"] .screen-tiles { grid-template-columns: repeat(auto-fit, minmax(min(100%, 20rem), 1fr)); max-height: 50vh; }
.screen-tables[data-band="7-12"] .screen-tiles { grid-template-columns: repeat(auto-fit, minmax(min(100%, 10rem), 1fr)); max-height: 44vh; }
.screen-tables[data-band="13-24"] .screen-tiles,
.screen-tables[data-band="many"] .screen-tiles { grid-template-columns: repeat(auto-fit, minmax(min(100%, 8rem), 1fr)); max-height: 48vh; }
.screen-tile { background: var(--bg-card); border: 2px solid var(--border); border-radius: 12px; padding: 0.45rem 0.65rem;
               min-width: 0; overflow: hidden; }
.screen-tile[hidden] { display: none; }
.screen-tile.is-busy { border-color: color-mix(in srgb, var(--primary) 55%, var(--border)); }
.screen-tile.is-point { border-color: var(--primary); box-shadow: 0 0 0 3px color-mix(in srgb, var(--primary) 35%, transparent); }
.screen-tile.is-free { border-color: color-mix(in srgb, var(--success) 60%, var(--border)); }
.screen-tile.is-closed { opacity: 0.6; }
.screen-tile-name { font-size: 1rem; margin: 0 0 0.15rem; color: var(--text-muted); }
.screen-tile-state { font-size: 1.2rem; font-weight: 700; margin: 0; }
.screen-free-word { color: var(--success); }
.screen-sides { margin: 0; line-height: 1.25; overflow-wrap: anywhere; }
.screen-short { display: none; }
.screen-tables.is-compact .screen-full { display: none; }
.screen-tables.is-compact .screen-short { display: inline; }
.screen-tables.is-compact .screen-tile.is-full .screen-full { display: inline; }
.screen-tables.is-compact .screen-tile.is-full .screen-short { display: none; }
.screen-tables.is-bare .screen-detail { display: none; }
.screen-score { font-size: 1.6rem; font-weight: 700; margin: 0.1rem 0 0; font-variant-numeric: tabular-nums; }
.screen-tables[data-band="1-2"] .screen-score { font-size: 3.2rem; }
.screen-tables[data-band="7-12"] .screen-score, .screen-tables[data-band="13-24"] .screen-score,
.screen-tables[data-band="many"] .screen-score { font-size: 1.2rem; }
.screen-point { margin: 0.1rem 0 0; font-weight: 700; color: var(--primary); }
.screen-detail { margin: 0.15rem 0 0; color: var(--text-muted); font-size: 0.85rem; }
.screen-called { margin: 0 0 0.2rem; font-weight: 700; color: var(--on-primary); background: var(--primary); border-radius: 6px;
                 padding: 0.1rem 0.4rem; }
.screen-tile.is-called { animation: screen-flash 0.6s ease-in-out 4; }
@keyframes screen-flash { 50% { background: color-mix(in srgb, var(--primary) 30%, var(--bg-card)); } }
.screen-folded, .screen-tile-pages { margin: 0; color: var(--text-muted); font-size: 0.9rem; }
.screen-folded[hidden], .screen-tile-pages[hidden] { display: none; }
/* The panels: one at a time, filling what's left; a long one pages through itself. */
.screen-panels { flex: 1; min-height: 0; position: relative; }
.screen-panel { display: none; height: 100%; overflow: hidden; }
.screen-panel.is-shown { display: block; }
.screen-panel-title { font-size: 1.15rem; margin: 0 0 0.4rem; color: var(--text-muted); }
.screen-list li { padding: 0.35rem 0; border-bottom: 1px solid var(--border); overflow-wrap: anywhere; }
.screen-list li[hidden], .screen-unit[hidden] { display: none; }
.screen-muted { color: var(--text-muted); }
/* What matters, readable across a hall (the owner, 2026-10-18): the winner bright, a live score in the accent, the
   table's names and points stronger than its counts. */
.screen-winner { color: var(--text); }
.screen-loser { color: color-mix(in srgb, var(--text) 78%, var(--bg)); }
.screen-scoreline { color: var(--text); font-weight: 600; font-variant-numeric: tabular-nums; }
.screen-score { color: var(--primary); }
.screen-panel .standings-table td { color: color-mix(in srgb, var(--text) 72%, var(--bg)); font-variant-numeric: tabular-nums; }
.screen-panel .standings-table td:first-child { color: var(--text); font-weight: 700; }
.screen-panel .standings-table td.col-name { color: var(--text); font-weight: 600; }
/* The points in the text's colour, bold, on every row: clay read as red across a room, on the rows below the cut
   (the owner, 2026-10-23); the results' scores too (.screen-scoreline). */
.screen-panel .standings-table td:not(:first-child) strong { color: var(--text); font-weight: 700; }
.screen-sub { font-size: 1rem; margin: 0.4rem 0 0.25rem; }
.screen-unit { margin-bottom: 0.5rem; }
.screen-bracket--one .card-header { display: none; }   /* the panel's title names the one bracket */
.screen-panel .standings-table { font-size: 0.95rem; }
.screen-news-title { font-family: var(--font-heading); font-size: 1.5rem; margin: 0 0 0.4rem; }
.screen-news-intro { font-size: 1.1rem; margin: 0 0 0.5rem; }
.screen-news-line { margin: 0 0 0.5rem; }
.screen-qr { margin: 0; text-align: center; }
.screen-panel[data-panel="follow"] { container-type: size; }
.screen-qr [data-qr] { width: min(40vh, 18rem); height: min(40vh, 18rem); margin: 0 auto 0.4rem; background: #fff; padding: 8px;
                       border-radius: 10px; box-sizing: border-box; }
/* In its panel, the code takes the room the panel has under its title and words. */
.screen-panel .screen-qr [data-qr] { width: min(100cqh - 6rem, 18rem); height: min(100cqh - 6rem, 18rem); }
.screen-qr svg { width: 100%; height: 100%; display: block; }
tr.moved-up td:first-child::after { content: " ▲"; color: var(--success); }
tr.moved-down td:first-child::after { content: " ▼"; color: var(--primary); }
.screen-dots { flex: none; display: flex; gap: 0.5rem; justify-content: center; align-items: center; }
/* A small dot, a finger's room around it to tap (the walkthrough, 2026-10-18: 13px to hit). */
.screen-dot { width: 2.25rem; height: 2.25rem; border-radius: 50%; border: 0; padding: 0.78rem; background: var(--border);
    background-clip: content-box; cursor: pointer; }
.screen-dot.is-on { background: var(--primary); background-clip: content-box; }
.screen-dots { gap: 0; }
.screen-held { font-size: 0.8rem; margin-left: 0.5rem; padding: 0.15rem 0.6rem; border-radius: 999px; cursor: pointer;
               border: 1px solid var(--border); background: transparent; color: var(--text); }
/* A wide screen shows two panels side by side, and reads larger: the room a TV has (the owner: "lot of empty space"). */
@media (min-width: 1100px) and (min-aspect-ratio: 4/3) {
    .screen-panels.is-two { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 0 2rem; }
    .screen-panels.is-two .screen-panel.is-shown { height: 100%; }
    .screen-panel { font-size: 1.12rem; }
    .screen-panel-title { font-size: 1.3rem; }
}
/* A phone in screen mode: one panel at a time, the tables first, as a list. */
@media (max-width: 699px) {
    .screen-tables.screen-panel:not(.is-shown) { display: none; }
    .screen-tables.screen-panel.is-shown { flex: 1; min-height: 0; overflow: hidden; }
    .screen-main:has(.screen-tables.is-shown) .screen-panels { display: none; }
    .screen-tables.screen-panel .screen-tiles { grid-template-columns: 1fr; max-height: none; overflow: visible; }
}
@media (prefers-reduced-motion: reduce) {
    .screen-banner.is-sliding, .screen-tile.is-called { animation: none; }
}
/* Run → Players: the list as asked (core/views/run._players_shown). */
.players-view .desk-chips { margin: 0.5rem 0; }
.players-view .chip { display: inline-flex; align-items: center; min-height: 40px; }
.players-sort { align-items: center; }
.still-to-claim { margin: 0.5rem 0 1rem; }
/* What the draft will make (core/draft_summary.py). */
.draft-summary-list li { padding: 0.15rem 0; }
.draft-summary-warnings { margin-top: 0.5rem; }
.draft-summary-warnings li { padding: 0.2rem 0; color: var(--warning-text, var(--text)); }

/* "My take" while it's written: the box holds its height, the story dimmed under the status line, a faint wave in
   the theme's colour across it (static/js/app.js; the owner, 2026-10-21). */
#news-body { transition: height 0.3s ease; }
#news-body.is-writing { position: relative; overflow: hidden; }
#news-body.is-writing .news-under { opacity: 0.35; pointer-events: none; margin-top: 0.5rem; }
#news-body.is-writing::after { content: ""; position: absolute; inset: 0; pointer-events: none;
    background: linear-gradient(100deg, transparent 20%, color-mix(in srgb, var(--primary) 11%, transparent) 40%,
                color-mix(in srgb, var(--primary) 11%, transparent) 50%, transparent 70%);
    background-size: 250% 100%; animation: tm-news-wave 2.2s ease-in-out infinite; }
@keyframes tm-news-wave { from { background-position: 120% 0; } to { background-position: -120% 0; } }
@media (prefers-reduced-motion: reduce) {
    #news-body { transition: none; }
    #news-body.is-writing::after { animation: none; background: color-mix(in srgb, var(--primary) 6%, transparent); }
}

/* See the site as them, look only (core/look_only.py): the bar at the top, in the theme's warning colour. */
.look-only-bar { position: sticky; top: 0; z-index: 9999; padding: 0.5rem 1rem; text-align: center; font-weight: 600;
    background: color-mix(in srgb, var(--warning) 22%, var(--bg-card)); color: var(--text);
    border-bottom: 1px solid color-mix(in srgb, var(--warning) 55%, var(--bg-card)); overflow-wrap: anywhere; }
.look-only-stop { display: inline; margin: 0; }
.look-only-stop button { background: none; border: none; padding: 0; font: inherit; color: inherit; text-decoration: underline;
    cursor: pointer; min-height: 44px; }

/* Taps a finger can hit (WORDING_AND_UI §8): every button, text button and fold heading in the site's pages is at least
   44 px tall, by one rule. Batch 4 (2026-10-24) listed the buttons one class at a time, and walkthrough 6 found the
   ones it missed: Home's "Not now", "Add your email" and "Score live", and Players' folds at 0.85rem (P8). The
   scorer and the TV view are pages of their own, sized for their screens. */
:is(.app-layout, .public-shell) :is(.btn, button.btn-link) { min-height: 44px; }
:is(.app-layout, .public-shell) button.btn-link { display: inline-flex; align-items: center; }
:is(.app-layout, .public-shell) details > summary { min-height: 44px; }
/* A plain fold's heading, its words in the middle of the 44 px: a heading stays a list item, to keep its marker. */
.fold > summary:not(.btn) { padding: max(0px, calc((44px - 1.5em) / 2)) 0; }

/* A list of names in a box that scrolls sideways on a phone keeps each row's name in view (walkthrough 6, 2026-10-24,
   P9: at 390 px Players' five columns scrolled the name away, and opening a row's fold scrolled the box to it). The
   cell is opaque, the card's colour or the row's hover tint, so the cells passing under it don't show through; a
   fold opened in a row wraps its words within a phone's width rather than widening the table. */
.names-first th:first-child, .names-first td:first-child { position: sticky; left: 0; z-index: 1; }
.names-first td:first-child { background: var(--bg-card); box-shadow: inset -1px 0 0 var(--border); }
.names-first tr:hover td:first-child { background: var(--tint); }
.names-first th:first-child { box-shadow: inset -1px 0 0 var(--border); }
.names-first td .fold > :not(summary) { width: min(20rem, 70vw); white-space: normal; }
/* Players (the entries to review) on a phone: each row a card, its name and status, then the username (or its
   players) and the day it entered, then what can be done, the full width (walkthrough 11, U4: at 390 px the actions
   were off the screen and a row stood 230 px tall). The headings stay for screen readers. */
@media (max-width: 600px) {
    .entry-rows thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
    .entry-rows, .entry-rows tbody { display: block; }
    .entry-rows tr { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 0.25rem 0.75rem; align-items: center;
                     padding: 0.65rem 0.75rem; border-bottom: 1px solid var(--border); }
    .entry-rows td { display: block; min-width: 0; padding: 0; border: 0; }
    .entry-rows.names-first td:first-child { position: static; background: none; box-shadow: none; font-weight: 600; }
    .entry-rows.names-first tr:hover td:first-child { background: none; }
    .entry-rows td:nth-child(2) { grid-column: 1; grid-row: 2; }
    .entry-rows td:nth-child(3) { grid-column: 2; grid-row: 1; }
    .entry-rows td:nth-child(4) { grid-column: 2; grid-row: 2; text-align: right; }
    .entry-rows td:nth-child(5) { grid-column: 1 / -1; }
    .entry-rows td:nth-child(5):empty { display: none; }
    .entry-rows td .fold > :not(summary) { width: auto; }
}
