/* BCC2 base styles. Mobile-first. */

:root {
    --fg: #faf6db;         /* cream body text */
    --muted: #b0aa95;      /* dimmed cream — secondary text, borders, alias/inactive bg */
    --accent-dark: #881f05;/* burnt red — buttons, hot accents, dark fills */
    --panel: #55595c;      /* main charcoal — primary panel bg */
    --panel-2: #45484b;    /* darker charcoal — body bg, zebra rows, nested panels, inputs */
    --green:        #8fd17a;  /* fresh green — In RSVP, positive % / cash deltas */
    --green-dark:   #4a7c3a;  /* darker green — status-complete bg, most-improved bg, tri "yes" */
    --badge-bubble: #7a4a0f;  /* muted amber — bubble-boy badge bg */
    --badge-consolation: #6a6f73; /* neutral gray — consolation badge bg */
    --col-shadow: 0 0 6px rgba(0, 0, 0, 0.4);  /* drop shadow for matrix sticky cols */
}

* { box-sizing: border-box; }

html, body {
    margin: 0;
    padding: 0;
    background: var(--panel-2);
    color: var(--fg);
    font: 16px/1.45 'Roboto Condensed', 'Arial Narrow', 'Helvetica Neue', sans-serif;
    /* Disable browser scroll anchoring — mobile Chrome's anchor
       hunting reacts to sub-pixel reflows from the per-tick font
       refit and yanks the scroll position back, even when the page
       height hasn't actually changed. */
    overflow-anchor: none;
    /* Clip any horizontal overflow from full-bleed bands (.embedded-game
       uses 100vw, which on most browsers includes the vertical scrollbar
       and would otherwise spawn a phantom horizontal scrollbar). `clip`
       beats `hidden` because it doesn't create a scroll container, so
       sticky positioning inside the page still works. */
    overflow-x: clip;
}

a { color: var(--fg); text-decoration: none; }
a:hover { text-decoration: underline; }

/* All buttons read uppercase for consistency. Single-glyph buttons
   (× rm, etc.) are unaffected; this applies via text-transform so
   the source case stays normal-cased and readable. */
button { text-transform: uppercase; }
button.rm { text-transform: none; }

header.site, footer.site {
    padding: 8px 20px;
    border-bottom: 1px solid var(--muted);
    display: flex;
    align-items: center;
    gap: 18px;
    flex-wrap: wrap;
}
header.site {
    position: sticky;
    top: 0;
    z-index: 50;
    background: var(--panel-2);
}
footer.site {
    border-bottom: 0;
    border-top: 1px solid var(--muted);
    color: var(--muted);
    justify-content: center;
}

.brand {
    display: inline-flex;
    align-items: center;
    background: var(--fg);            /* cream — pops the dark logo on charcoal */
    padding: 6px 12px;
    border-radius: 8px;
}
.brand img {
    height: 36px;
    width: auto;
}

.crumbs {
    color: var(--muted);
    font-size: 18px;
    font-weight: 500;
    line-height: 1.2;
}
.crumbs .sep { margin: 0 8px; opacity: 0.5; }

.crumbs a { color: var(--muted); }
.crumbs a:hover { color: var(--fg); }
.crumbs .current { color: var(--fg); font-weight: 600; }
.crumbs .current.champ { color: var(--fg); font-style: italic; font-weight: 700; }

/* Group of right-side header actions (search + profile/sign-in). Wrapped
   together so they always wrap as a unit when the header runs out of
   horizontal room — the search button never ends up stranded on its
   own line away from the profile icon. margin-left: auto pushes the
   whole group to the right end of the header row. */
.header-actions {
    margin-left: auto;
    display: flex;
    align-items: center;
    gap: 18px;
}

/* When search expands, take over the whole header row and hide the
   other items — both the siblings outside the group (brand, crumbs)
   and the profile icon inside the group. */
.header-actions:has(.search.open) {
    flex: 1 1 100%;
    margin-left: 0;
}
.header-actions:has(.search.open) > :not(.search) { display: none; }

/* Header search — sits inside .header-actions; expands to fill the row
   when opened. Always shows as a magnifying-glass icon by default;
   tapping expands the input (which takes over the header row by
   hiding brand/crumbs/profile). */
.search {
    position: relative;
    display: flex;
    align-items: center;
}
.search input[type=search] {
    display: none;        /* shown only when .search.open */
    width: 260px;
    padding: 8px 12px;
    background: var(--panel-2);
    color: var(--fg);
    border: 1px solid var(--muted);
    border-radius: 8px;
    font: inherit;
    outline: none;
}
.search input[type=search]:focus { border-color: var(--accent-dark); }
.search-toggle {
    display: inline-flex;
    align-items: center;
    background: var(--panel-2);
    color: var(--fg);
    border: 1px solid var(--muted);
    border-radius: 8px;
    padding: 6px 8px;
    cursor: pointer;
    line-height: 0;
}
.search-toggle:hover { border-color: var(--accent-dark); }
.search.open { flex: 1 1 100%; }
.search.open .search-toggle { display: none; }
.search.open input[type=search] { display: block; width: 100%; }
.search.open .results { left: 0; right: 0; width: auto; }
.site:has(.search.open) > :not(.header-actions) { display: none; }
.search .results {
    position: absolute;
    top: calc(100% + 4px);
    right: 0;
    width: 260px;
    max-height: 60vh;
    overflow-y: auto;
    background: var(--panel);
    border: 1px solid var(--muted);
    border-radius: 8px;
    box-shadow: 0 8px 24px rgba(0,0,0,0.35);
    z-index: 60;
}
.search .results.hidden { display: none; }
.search .hit {
    display: flex;
    align-items: baseline;
    gap: 10px;
    padding: 8px 12px;
    color: var(--fg);
    border-bottom: 1px solid var(--muted);
}
.search .hit:last-child { border-bottom: 0; }
.search .hit:hover { background: var(--panel-2); text-decoration: none; }
.search .hit .kind {
    font-size: 10px;
    text-transform: uppercase;
    color: var(--muted);
    min-width: 50px;
}
.search .hit .name { color: var(--fg); }

/* No card chrome on .account-link — the inner .player-link calling
   card already provides its own pill styling. */
.account-link:hover { text-decoration: none; }
.account-signin {
    display: inline-flex;
    align-items: center;
    color: var(--fg);
    background: var(--panel-2);
    border: 1px solid var(--muted);
    border-radius: 6px;
    padding: 5px 8px;
    line-height: 0;
}
.account-signin:hover { border-color: var(--accent-dark); text-decoration: none; }

@media (max-width: 700px) {
    /* Tighter header: smaller gaps + padding so brand, search, and
       account fit together on one row without awkward wrapping. */
    .site {
        gap: 10px;
        padding: 6px 14px;
    }
    .header-actions { gap: 10px; }
    .brand { padding: 4px 10px; }
    .brand img { height: 28px; }

    .crumbs { font-size: 16px; }
    .crumbs .sep { margin: 0 5px; }
}

main {
    /* Full viewport width, vertical padding only. Each top-level child
       (panel, details, embedded-game) handles its own horizontal
       padding so its background can run viewport edge-to-edge while
       its content stays in a centered ~1000px column. */
    padding: 20px 0 40px;
}
/* Column-centering padding applied to direct children of main:
   enough horizontal padding to push content into a centered ~1000px
   column, with a 12px gutter on narrow screens. */
main > * {
    padding-left:  max(12px, calc((100% - 1000px) / 2));
    padding-right: max(12px, calc((100% - 1000px) / 2));
}

h1 { margin: 0 0 16px; font-size: 28px; color: var(--fg); }

/* Championship games get the red + italic treatment wherever a game
   name appears (h1, list links, table links). */
.champ, .champ .game-name {
    color: var(--fg);
    font-style: italic;
    font-weight: 700;
}
.champ:hover, .champ:hover .game-name { color: var(--fg); }
h2 { margin: 0 0 12px; font-size: 18px; color: var(--muted); text-transform: uppercase; }

.panel {
    background: var(--panel);
    padding-top: 14px;
    padding-bottom: 14px;
    /* Horizontal padding inherited from the column-centering rule on
       :where(main, .embedded-game) > * — bg runs full width, content
       sits in the centered ~1000px column. No margin-bottom — adjacent
       panels are distinguished by alternating bg colors instead of
       body-color gaps (rule below). */
}
/* Alternate .panel + .admin-edit bg colors as a single
   sequence so adjacent stacked elements always read distinct without
   needing vertical gap. Counted among main's children matching
   either selector. */
main > :nth-child(odd of .panel, .admin-edit) {
    background: var(--panel);
}
main > :nth-child(even of .panel, .admin-edit) {
    background: var(--panel-2);
}

/* Per-game leaderboard panels on the season page — collapsed by default,
   the summary row styled to match the .panel h2 look. */
.game-collapse > summary {
    cursor: pointer;
    font-size: 18px;
    color: var(--muted);
    text-transform: uppercase;
    list-style: none;
}
.game-collapse > summary::-webkit-details-marker { display: none; }
.game-collapse > summary::before {
    content: '▸';
    display: inline-block;
    width: 1em;
    color: var(--muted);
    transition: transform 0.15s;
}
.game-collapse[open] > summary::before { transform: rotate(90deg); }
.game-collapse[open] > summary { margin-bottom: 12px; }

.meta {
    display: flex;
    gap: 18px;
    flex-wrap: wrap;
    color: var(--muted);
    font-size: 14px;
}
/* Spacing below .meta only matters when something follows it (e.g. on
   the game page). Inside a .panel where it's the only child, the panel's
   own padding handles spacing — adding margin-bottom here would make the
   bottom gap larger than the top. */
/* Only when .meta is rendered standalone (e.g., inside .player-header)
   does it need its own margin-bottom — when it IS a top-level panel
   (.panel.meta on the game page), the alternating-stack rhythm
   handles spacing and an extra margin would break the flush layout. */
.meta:not(.panel):not(:last-child) { margin-bottom: 14px; }
.meta strong { color: var(--fg); font-weight: 600; }

.empty {
    color: var(--muted);
    padding: 12px 0;
}

code {
    background: var(--panel-2);
    padding: 2px 5px;
    border-radius: 3px;
    font-size: 14px;
    color: var(--fg);
}

.badge {
    display: inline-block;
    background: var(--accent-dark);
    color: white;
    font-size: 11px;
    font-weight: 700;
    padding: 3px 7px;
    border-radius: 4px;
    text-transform: uppercase;
    vertical-align: middle;
    margin-left: 6px;
}
.badge.small { font-size: 10px; padding: 2px 5px; }
.badge.alias { background: var(--muted); }

.status {
    display: inline-block;
    padding: 2px 8px;
    border-radius: 4px;
    font-size: 13px;
    font-weight: 600;
    text-transform: uppercase;
}
.status-scheduled { background: var(--panel-2); color: var(--muted); }
.status-live      { background: var(--fg); color: var(--accent-dark); }
.status-complete  { background: var(--green-dark); color: white; }

.pc.up { color: var(--green); font-weight: 600; margin-left: 4px; }
.pc.dn { color: var(--accent-dark); font-weight: 600; margin-left: 4px; }

/* Season pot summary panel — sits above the championship/leaderboard. */
.pot-summary .pot-headline {
    font-size: 22px;
    font-weight: 600;
    color: var(--fg);
    margin: 4px 0 10px;
}
.pot-summary .pot-tiles {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
    gap: 10px;
}
.pot-summary .pot-tile {
    background: var(--panel-2);
    border: 1px solid var(--muted);
    border-radius: 6px;
    padding: 8px 12px;
}
.pot-summary .pot-tile .asset {
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
    color: var(--muted);
}
.pot-summary .pot-tile .qty   { font-size: 15px; }
.pot-summary .pot-tile .value { font-size: 15px; font-weight: 600; margin-top: 2px; }

.pot-adjustments { margin-top: 14px; }
.pot-adjustments h3 {
    font-size: 12px;
    font-weight: 600;
    text-transform: uppercase;
    color: var(--muted);
    margin: 0 0 6px;
}
.pot-adjustments .mini-table { width: auto; font-size: 14px; }
.pot-adjustments .mini-table td { padding: 3px 10px 3px 0; }
.pot-adjustments .mini-table td.num { font-weight: 600; }
.pot-adjustments .mini-table td.num.up { color: var(--green); }
.pot-adjustments .mini-table td.num.dn { color: var(--accent-dark); }
.pot-adjustments .mini-table td.rm-cell form { display: inline; }
.pot-adjustments .add-adjustment {
    display: flex;
    gap: 8px;
    align-items: center;
    margin-top: 8px;
}
.pot-adjustments .add-adjustment input[type=text]   { flex: 1 1 220px; }
.pot-adjustments .add-adjustment input[type=number] { width: 120px; }
.pot-adjustments .add-adjustment input {
    font: inherit;
    padding: 6px 8px;
    border: 1px solid var(--muted);
    border-radius: 5px;
    background: var(--panel-2);
    color: var(--fg);
}
.pot-adjustments .add-adjustment button {
    font: inherit;
    padding: 7px 14px;
    background: var(--accent-dark);
    color: white;
    border: 0;
    border-radius: 5px;
    cursor: pointer;
}

/* Game-attached pot adjustment: tucked under the "Invested:" line. */
.invest-adj {
    font-size: 13px;
    color: var(--muted);
    margin-left: 14px;
}
.invest-adj .amt         { font-weight: 600; margin-left: 4px; }
.invest-adj .amt.up      { color: var(--green); }
.invest-adj .amt.dn      { color: var(--accent-dark); }

/* Admin knockouts panel: mini-table + add form inline like pot adjustments. */
.ko-list tr.self-keep td em { font-style: italic; color: var(--muted); }
.add-knockout {
    display: flex;
    gap: 8px;
    align-items: center;
    margin-top: 8px;
    flex-wrap: wrap;
}
.add-knockout select,
.add-knockout input {
    font: inherit;
    padding: 6px 8px;
    border: 1px solid var(--muted);
    border-radius: 5px;
    background: var(--panel-2);
    color: var(--fg);
}
.add-knockout input[type=number] { width: 160px; }
.add-knockout button {
    font: inherit;
    padding: 7px 14px;
    background: var(--accent-dark);
    color: white;
    border: 0;
    border-radius: 5px;
    cursor: pointer;
}

/* Free entries — asterisk + footnote on the results table, admin-only
   checkbox column for toggling. */
.free-mark       { color: var(--accent-dark); margin-left: 1px; }
.improvement-badge {
    margin-left: 8px;
    padding: 1px 6px;
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
    color: white;
    border-radius: 4px;
    white-space: nowrap;
}
.improvement-badge.most-improved  { background: var(--green-dark); }   /* green */
.improvement-badge.least-improved { background: var(--accent-dark); }
.improvement-badge.bubble-boy     { background: var(--badge-bubble); }
.improvement-badge.consolation    { background: var(--badge-consolation); }
.free-footnote   { color: var(--muted); font-size: 12px; margin: 6px 0 0; }
.free-col        { text-align: center; }
.free-col input  { margin: 0; cursor: pointer; }
.free-save       { margin-top: 8px; }

/* A pot-split row set to "remainder" — the value box is unused so grey it out. */
.pot-split-row.remainder input[type=number] { opacity: 0.45; }

/* Admin inline edit panels */
.admin-edit {
    /* Bg comes from the alternating-stack rule on :where(main,
       .embedded-game) > :nth-child(... of .panel, .admin-edit).
       Horizontal padding from the column-centering rule. */
    padding-top: 8px;
    padding-bottom: 8px;
}
.admin-edit > summary {
    cursor: pointer;
    font-size: 13px;
    font-weight: 600;
    text-transform: uppercase;
    color: var(--muted);
    padding: 4px 0;
}
.admin-edit[open] > summary { margin-bottom: 10px; }
.admin-edit form {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: 10px 14px;
    padding-bottom: 10px;
}
.admin-edit label {
    display: flex;
    flex-direction: column;
    gap: 3px;
    font-size: 12px;
    text-transform: uppercase;
    color: var(--muted);
}
/* Checkbox labels read "[ ] Text", not stacked. */
.admin-edit label:has(> input[type=checkbox]) {
    flex-direction: row;
    align-items: center;
    gap: 6px;
}
.admin-edit label.wide { grid-column: 1 / -1; }
/* Any direct child of an admin-edit form marked .wide spans every column.
   Without this, fieldsets / nested details that live next to single-column
   inputs end up overlapping awkwardly inside auto-fit grid cells. */
.admin-edit > form > .wide { grid-column: 1 / -1; }
.admin-edit input, .admin-edit textarea, .admin-edit select {
    font: inherit;
    padding: 6px 8px;
    border: 1px solid var(--muted);
    border-radius: 5px;
    background: var(--panel-2);
    color: var(--fg);
    text-transform: none;
}
.admin-edit .actions {
    grid-column: 1 / -1;
    display: flex;
    gap: 10px;
    justify-content: flex-end;
    padding-top: 4px;
}
.admin-edit button {
    font: inherit;
    padding: 7px 16px;
    background: var(--accent-dark);
    color: white;
    border: 0;
    border-radius: 5px;
    cursor: pointer;
}
.admin-edit button:hover { filter: brightness(1.1); }

.admin-edit .hint {
    font-size: 11px;
    font-weight: 400;
    text-transform: none;
    color: var(--muted);
    margin-top: 2px;
}
.admin-edit .hint code {
    font-size: 11px;
    padding: 1px 4px;
}
.admin-edit .hint.wide { grid-column: 1 / -1; padding-top: 2px; }

/* Season-level "Default game settings" block — mirrors the structure of the
   game-level override, but nested under the season form. */
.admin-edit fieldset.defaults-block {
    grid-column: 1 / -1;
    border: 1px solid var(--muted);
    border-radius: 6px;
    padding: 6px 12px 10px;
    margin: 4px 0 0;
    background: var(--panel-2);
}
.admin-edit fieldset.defaults-block legend {
    padding: 0 6px;
    font-size: 12px;
    font-weight: 600;
    text-transform: uppercase;
    color: var(--muted);
}
.admin-edit fieldset.defaults-block .defaults-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: 8px 14px;
}
/* An inherited value (null on the game, falling back to season) reads
   dimmer than an explicit override — so the admin can see at a glance
   which fields this game has chosen to override. */
.admin-edit fieldset.defaults-block label.field.inherited {
    opacity: 0.55;
}
.admin-edit fieldset.defaults-block label.field.inherited select,
.admin-edit fieldset.defaults-block label.field.inherited input {
    font-style: italic;
}

.admin-edit fieldset.payout-schedule {
    grid-column: 1 / -1;
    border: 1px solid var(--muted);
    border-radius: 6px;
    padding: 8px 12px 10px;
    margin: 4px 0 0;
    background: var(--panel-2);
}
.admin-edit fieldset.payout-schedule legend {
    padding: 0 6px;
    font-size: 12px;
    font-weight: 600;
    text-transform: uppercase;
    color: var(--muted);
}
.admin-edit fieldset.payout-schedule label.inline {
    flex-direction: row;
    align-items: center;
    gap: 6px;
    font-size: 12px;
    margin: 4px 0 6px;
}
.admin-edit fieldset.payout-schedule label.inline input { width: 80px; }
.admin-edit table.mini-table {
    width: 100%;
    border-collapse: collapse;
    margin: 4px 0;
}
.admin-edit table.mini-table th,
.admin-edit table.mini-table td {
    padding: 3px 4px;
    text-align: left;
    border: 0;
}
.admin-edit table.mini-table th {
    font-size: 11px;
    text-transform: uppercase;
    color: var(--muted);
}
.admin-edit table.mini-table input,
.admin-edit table.mini-table select {
    width: 100%;
}
.admin-edit table.mini-table td:last-child  { width: 28px; text-align: center; }
.admin-edit table.mini-table th.auto,
.admin-edit table.mini-table td.auto { background: var(--panel-2); text-align: center; }
.admin-edit table.mini-table td.first-cell { font-weight: 600; color: var(--accent-dark); }
.admin-edit table.mini-table th.auto small { font-weight: 400; color: var(--muted); font-size: 10px; }

/* Payout grid: let each % input breathe, and scroll the table when the
   fieldset's own width is too narrow to fit every column. */
.admin-edit fieldset.payout-schedule { overflow-x: auto; }
.admin-edit table.payout-grid input[type=number] {
    text-align: right;
    min-width: 58px;
}
/* Hide the number-input spinners inside the payout schedule — admin always
   types the numbers in, so the up/down arrows just waste horizontal space.
   The `appearance: textfield` covers Firefox; the WebKit-specific spin-
   button pseudo-elements need their own `appearance: none` to vanish. */
.admin-edit fieldset.payout-schedule input[type=number] {
    appearance: textfield;
}
.admin-edit fieldset.payout-schedule input[type=number]::-webkit-inner-spin-button,
.admin-edit fieldset.payout-schedule input[type=number]::-webkit-outer-spin-button {
    appearance: none;
    margin: 0;
}
.admin-edit button.rm, .admin-edit button.add-row {
    font: inherit;
    padding: 3px 8px;
    background: transparent;
    color: var(--muted);
    border: 1px solid var(--muted);
    border-radius: 4px;
    cursor: pointer;
}
.admin-edit button.rm { padding: 1px 7px; font-size: 14px; line-height: 1; }
.admin-edit button.add-row:hover { color: var(--accent-dark); border-color: var(--accent-dark); }

.admin-edit .attend-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
    gap: 4px 14px;
    padding: 6px 0;
}
.admin-edit label.attend {
    flex-direction: row;
    align-items: center;
    gap: 6px;
    font-size: 13px;
    text-transform: none;
    color: var(--fg);
}
.admin-edit label.attend small { color: var(--muted); margin-left: auto; font-size: 11px; }

.hidden { display: none !important; }

/* CSS-driven reveals — replaces JS class toggles. The container shows
   only when its sibling control is in the relevant state. */
#override-payout-grid                                         { display: none; }
form:has(#override-payout:checked)        #override-payout-grid { display: block; }
#new-location-fields                                          { display: none; }
form:has(#location-choice option[value="new"]:checked) #new-location-fields { display: block; }

/* Lists */
ul.seasons, ul.games {
    list-style: none;
    padding: 0;
    margin: 0;
    display: grid;
    gap: 8px;
}
ul.seasons li a, ul.games li a {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 14px;
    padding: 12px 16px;
    background: var(--panel-2);
    border: 1px solid var(--muted);
    border-radius: 8px;
    color: var(--fg);
}
ul.seasons li a:hover, ul.games li a:hover {
    border-color: var(--accent-dark);
    text-decoration: none;
}
.season-name, .game-name { font-weight: 600; }
.season-range, .game-when { color: var(--muted); font-size: 13px; font-variant-numeric: tabular-nums; }

/* Tables */
.leaderboard, .results {
    width: 100%;
    border-collapse: collapse;
    font-variant-numeric: tabular-nums;
}
.leaderboard th, .results th,
.leaderboard td, .results td {
    padding: 4px 10px;
    text-align: left;
}
.leaderboard th, .results th {
    font-size: 12px;
    text-transform: uppercase;
    color: var(--muted);
    font-weight: 600;
}
table .num { text-align: right; }
/* Alternate row backgrounds give visual separation without per-row
   borders or extra vertical padding. The lighten-by-alpha works on
   any panel bg, so the same rule applies regardless of which shade
   the surrounding panel happens to have. */
.leaderboard tbody tr:nth-child(even),
.results     tbody tr:nth-child(even) { background: rgba(255, 255, 255, 0.05); }
.leaderboard tbody tr:hover,
.results     tbody tr:hover           { background: rgba(255, 255, 255, 0.10); }
table tr.alias td { color: var(--muted); font-style: italic; }

/* All-time leaderboard: cut at top 10 publicly; admins see the long tail
   below a heavier divider, dimmed so it reads as secondary. */
tr.leaderboard-divider td {
    padding: 0;
    border-bottom: 3px double var(--accent-dark);
}
tr.below-cut td { color: var(--muted); }

/* Payouts preview block — label on top, pair row below. The pair row
   never wraps; instead, the rank/cash text and inter-pair gap scale
   with viewport width via clamp() so a long row of payouts squishes
   to fit instead of breaking onto a second line. */
.payouts-preview .head {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 12px;
    margin-bottom: 6px;
}
.payouts-preview .head h2 { margin: 0; }
.payouts-preview .label {
    font-size: 12px;
    font-weight: 700;
    text-transform: uppercase;
    color: var(--muted);
}
.payouts-preview .pairs {
    display: flex;
    flex-wrap: nowrap;
    align-items: baseline;
    gap: clamp(6px, 2.5vw, 18px);
    min-width: 0;
}
.payouts-preview .pair {
    display: inline-flex;
    align-items: baseline;
    gap: clamp(3px, 1vw, 6px);
    flex: 0 0 auto;
    white-space: nowrap;
}
.payouts-preview .rank {
    font-size: clamp(9px, 2.2vw, 11px);
    text-transform: uppercase;
    color: var(--muted);
}
.payouts-preview .cash {
    font-size: clamp(14px, 4.5vw, 20px);
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    color: var(--fg);
}

/* RSVP status icons in the season-leaderboard cells of upcoming games.
   The clock is an inline SVG (using currentColor) instead of an emoji
   so the color rule actually takes effect; the rest are plain text
   glyphs that respect color out of the box. */
.rsvp-icon         { font-weight: 700; line-height: 1; }
.rsvp-icon svg     { vertical-align: -2px; }
.rsvp-icon-in      { color: var(--green-dark); }
.rsvp-icon-late    { color: var(--green); }
.rsvp-icon-out     { color: var(--accent-dark); }
.rsvp-icon-unknown { color: var(--muted); }

/* Player avatars — circular images with a textured grey placeholder
   when the player hasn't uploaded one yet. `display: block` avoids the
   <img>-on-baseline phantom gap below image avatars; the placeholder
   uses inline-flex (further down) for centered initial rendering and
   doesn't suffer from this. */
.avatar {
    display: block;
    border-radius: 50%;
    overflow: hidden;
    flex: 0 0 auto;
    object-fit: cover;
    background: var(--panel-2);
}
.avatar-sm { width: 22px; height: 22px; }
.avatar-md { width: 36px; height: 36px; }
.avatar-lg { width: 80px; height: 80px; }
.avatar-placeholder {
    /* Per-player hue is set inline via PHP. Layout here just centers
       the initial inside the circle for whichever size class wins.
       Explicit border-radius so a placeholder is always a circle, even
       if some other selector tries to override the .avatar default.
       container-type: inline-size lets the inner .avatar-init scale
       its font-size off the placeholder's own width via cqi units. */
    color: var(--accent-dark);
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-weight: 700;
    text-transform: uppercase;
    line-height: 1;
    container-type: inline-size;
}
.avatar-init {
    font-size: 38cqi;
    line-height: 1;
    /* The em-box is taller than the cap-height (it reserves space for
       ascenders + descenders we never render), so flex-centered uppercase
       reads visually high. Nudge down a hair so the cap optically centers. */
    transform: translateY(0.06em);
}

/* Inline player rows: avatar + name on a baseline. Used everywhere
   players are listed (RSVP buckets, leaderboards, etc.). The name is
   rendered as a "calling card" — cream pill with burnt-red text — so
   it reads as a tap target without the coral accent. */
.player-link {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    text-decoration: none;
    /* Center the inline-flex in its line instead of sitting on the
       baseline — otherwise an img-only first child puts the baseline
       at the bottom of the box and the surrounding line reserves
       descender space below it (taller table rows for img-avatar
       players vs placeholder-avatar players). */
    vertical-align: middle;
}
/* Avatar + name pill inside .player-link share the same em-based
   formula for their height, so they always match regardless of the
   surrounding font-size. Pill height = line-height * 1em + 2 * pad-y;
   avatar = same. Width on the avatar mirrors the height to keep it
   round. Everything scales with the inherited font-size. */
.player-link > span:not(.avatar) {
    background: var(--fg);
    color: var(--accent-dark);
    padding: 0.25em 0.75em;          /* pad-y=0.25em → contributes 0.5em to total height */
    line-height: 1.45;
    border-radius: 6px;
    font-weight: 600;
    white-space: nowrap;
}
.player-link .avatar {
    vertical-align: middle;
    width:  calc(1.45em + 0.5em);    /* line-height(1.45em) + pad-y*2 */
    height: calc(1.45em + 0.5em);
}
.player-link:hover { text-decoration: none; }
.player-link:hover > span:not(.avatar) { background: #fff; }

/* Player edit form: avatar preview alongside the file input. Spans
   the full form width because the file input chrome doesn't fit
   neatly inside a half-width grid cell. */
.avatar-field {
    display: flex;
    align-items: center;
    gap: 14px;
    flex-wrap: wrap;
    grid-column: 1 / -1;
    max-width: 100%;
    min-width: 0;
}
.avatar-field-input {
    display: flex;
    flex-direction: column;
    gap: 4px;
    flex: 1 1 0;
    min-width: 0;
}
.avatar-field input[type=file] {
    font-size: 13px;
    max-width: 100%;
}

.player-header { display: flex; align-items: center; gap: 18px; }
.player-header h2 { margin: 0 0 4px; font-size: 22px; color: var(--fg); text-transform: none; }
.player-header-meta { flex: 1; }

/* Inline avatar prompt shown right after a player RSVPs, when they
   haven't uploaded one yet. */
.rsvp-avatar-prompt {
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
    padding: 10px 12px;
    background: var(--panel-2);
    border: 1px solid var(--muted);
    border-radius: 8px;
    margin: 14px 0;
}
.rsvp-avatar-prompt-text { display: flex; flex-direction: column; min-width: 0; }
.rsvp-avatar-prompt input[type=file] { font-size: 13px; max-width: 100%; min-width: 0; flex: 1 1 0; }

/* Divider between the embedded game body and the season's own panels
   on the season page. Sits at the column max-width so it visually
   matches the rest of the page's content rhythm. */
.section-divider {
    height: 0;
    border: 0;
    border-top: 5px solid var(--muted);
    margin: 24px 0;
    width: 100%;
}

/* RSVP panel — the player's own action row + an admin manage section.
   The in/late/out lists are folded into the leaderboard itself: late
   RSVPers get a clock icon next to their name; out RSVPers are listed
   below the leaderboard as a comma-separated line. */
.rsvp-late-mark {
    display: inline-flex;
    align-items: center;
    margin-left: 4px;
    color: var(--muted);
    vertical-align: middle;
}
.rsvp-out-list {
    margin: 8px 12px 0;
    color: var(--muted);
}
.rsvp-out-list strong { color: var(--fg); }
.rsvp-out-list a { color: inherit; }

.rsvp-mine {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
    padding: 10px 12px;
    background: var(--panel-2);
    border: 1px solid var(--muted);
    border-radius: 8px;
    /* Single source of truth for the vertical gap between buckets,
       the player's own action row, and the admin manage panel. */
    margin: 14px 0;
}

/* Attention-grabbing pulse when the logged-in user hasn't RSVPed yet
   for the game they're looking at. The keyframe spends most of its
   cycle dim, then briefly flares a soft accent ring so it nudges the
   eye without strobing. */
@keyframes rsvp-attention {
    0%, 70%, 100% {
        box-shadow: 0 0 0 0 rgba(229, 133, 114, 0);
        border-color: var(--muted);
    }
    35% {
        box-shadow: 0 0 0 5px rgba(229, 133, 114, 0.35);
        border-color: var(--accent-dark);
    }
}
.rsvp-mine--needs-rsvp {
    animation: rsvp-attention 3.5s ease-in-out infinite;
}
@media (prefers-reduced-motion: reduce) {
    .rsvp-mine--needs-rsvp { animation: none; border-color: var(--accent-dark); }
}
.rsvp-btn {
    background: var(--panel);
    color: var(--fg);
    border: 1px solid var(--muted);
    border-radius: 6px;
    padding: 6px 12px;
    font: inherit;
    cursor: pointer;
}
.rsvp-btn:hover { border-color: var(--accent-dark); }
.rsvp-btn.current {
    background: var(--accent-dark);
    border-color: var(--accent-dark);
    color: white;
}
.rsvp-btn.rm:hover { border-color: var(--accent-dark); color: var(--accent-dark); }

.rsvp-list td { padding: 4px 10px 4px 0; }
.rsvp-list .rm-cell { width: 1%; }
.rsvp-add { display: flex; gap: 8px; margin-top: 10px; flex-wrap: wrap; }
.invite-toggle-all-label {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    cursor: pointer;
    user-select: none;
}


/* Location block in the game edit form. The "+ Add a new location"
   inputs stay hidden until the dropdown switches to "new". */
.location-block #new-location-fields { display: flex; gap: 12px; flex-wrap: wrap; margin-top: 8px; }
.location-block #new-location-fields.hidden { display: none; }
.meta .addr { color: var(--muted); }

/* Outbound messaging — flash banner after a redirect, plus the inline
   send-invite form on the player edit panel. */
.flash {
    background: var(--panel);
    border: 1px solid var(--accent-dark);
    color: var(--fg);
    padding: 8px 14px;
    border-radius: 8px;
    margin-bottom: 14px;
}
.send-invite,
.link-telegram { display: flex; gap: 8px; align-items: center; margin-top: 10px; flex-wrap: wrap; }
.send-invite input[type=text] { flex: 1 1 240px; }

/* Game-page mass-invite button: lives between the player's RSVP row and
   the admin manage panel. */
.mass-invite {
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
    /* Same vertical rhythm as .rsvp-mine — 14px above and below. */
    margin: 14px 0;
}
.mass-invite button {
    background: var(--accent-dark);
    color: white;
    border: 0;
    border-radius: 6px;
    padding: 8px 14px;
    font: inherit;
    cursor: pointer;
}
.mass-invite button:hover { filter: brightness(1.1); }

/* Login page — SMS form + Telegram bot link. Phone input mirrors the
   header search input so the page reads consistently. */
.login-sms { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }
.login-sms input[type=tel] {
    padding: 8px 12px;
    background: var(--panel-2);
    color: var(--fg);
    border: 1px solid var(--muted);
    border-radius: 8px;
    font: inherit;
    outline: none;
}
.login-sms input[type=tel]:focus { border-color: var(--accent-dark); }
.btn-link {
    display: inline-block;
    background: var(--accent-dark);
    color: white;
    padding: 8px 14px;
    border: 0;
    border-radius: 6px;
    font: inherit;
    font-weight: 600;
    text-transform: uppercase;
    cursor: pointer;
}
.btn-link:hover { filter: brightness(1.1); text-decoration: none; }

/* Tables — horizontal scroll on narrow screens */
.panel:has(table) { overflow-x: auto; }

/* Matrix leaderboard: wide tables with a narrow per-game column.
   The matrix panel respects the same column max-width as every other
   panel; the .scroller inside provides horizontal scrolling when the
   table is wider than the column. */
.panel:has(.matrix) > .scroller { overflow-x: auto; }

.matrix th, .matrix td { padding: 3px 5px; vertical-align: middle; font-size: 13px; }
/* Calling cards in the season leaderboard get a slight font-size bump
   so they (and their avatars, which scale off the same em) read taller
   than the surrounding 13px cells. */
.matrix .col-player .player-link { font-size: 15px; }
.matrix thead tr:first-child th { font-size: 11px; }
.matrix th a { color: var(--fg); }
.matrix th a:hover { color: var(--accent-dark); }
/* Dropped-score cells: grayed out so the "best N of M" rule is visible. */
.matrix td.dropped { color: var(--muted); }
/* Zebra shading on every other game column to aid scanning up/down. */
.matrix th.alt, .matrix td.alt { background: rgba(255,255,255,0.05); }

/* Admin-only champ-player override column. Tri-state segmented control. */
.matrix .col-override { text-align: center; min-width: 96px; }
.tri {
    display: inline-flex;
    border: 1px solid var(--muted);
    border-radius: 999px;
    overflow: hidden;
    background: var(--panel-2);
}
.tri input { position: absolute; opacity: 0; pointer-events: none; }
.tri label {
    cursor: pointer;
    padding: 2px 8px;
    font-size: 11px;
    font-weight: 600;
    color: var(--muted);
    user-select: none;
}
.tri label:has(input:checked) { color: white; }
.tri label:nth-child(1):has(input:checked) { background: var(--accent-dark); }
.tri label:nth-child(2):has(input:checked) { background: var(--muted); }
.tri label:nth-child(3):has(input:checked) { background: var(--green-dark); }
.override-actions {
    padding: 10px 12px;
    display: flex;
    justify-content: flex-end;
}
.override-actions button {
    font: inherit;
    padding: 7px 16px;
    background: var(--accent-dark);
    color: white;
    border: 0;
    border-radius: 5px;
    cursor: pointer;
}

/* Edge columns are sticky-pinned on each side; the middle game-score
   columns scroll horizontally underneath them. None of these have
   min-widths — the JS at the bottom of the season view measures their
   actual content widths on load and writes them into the CSS vars
   below, so the sticky offsets always track the real layout. */
.matrix .col-rank,
.matrix .col-player,
.matrix .col-points,
.matrix .col-stack,
.matrix .col-override {
    position: sticky;
    z-index: 2;
    background: var(--panel-2);
}
.matrix .col-rank   { left: 0; }
.matrix .col-player { left: var(--col-rank-w, 0); box-shadow: var(--col-shadow); }
.matrix .col-points { right: 0; box-shadow: var(--col-shadow); }
.matrix .col-stack    { right: 0; }
.matrix .col-override { right: 0; box-shadow: var(--col-shadow); }
/* When optional right-edge columns are present, scoot the inner ones
   leftward by the dynamic width of the columns to their right. The
   rightmost keeps the box-shadow; inner ones drop it. */
.matrix.has-stack    .col-points    { right: var(--col-stack-w, 0); box-shadow: none; }
.matrix.has-stack    .col-stack     { box-shadow: var(--col-shadow); }
.matrix.has-override .col-points    { right: var(--col-stack-plus-override-w, 0); box-shadow: none; }
.matrix.has-override .col-stack     { right: var(--col-override-w, 0); box-shadow: none; }
/* Hover background carries to sticky cells too. */
.matrix tbody tr:hover .col-rank,
.matrix tbody tr:hover .col-player,
.matrix tbody tr:hover .col-points,
.matrix tbody tr:hover .col-stack,
.matrix tbody tr:hover .col-override {
    background: var(--panel-2);
}
/* Prize stacks under the rank number so the column can stay narrow. */
.col-rank .rank-prize {
    display: block;
    font-size: 11px;
    font-weight: 600;
    color: var(--fg);
    line-height: 1.1;
}

/* Live-game elimination control in the rank cell — a small × button
   that opens the shared .elim-modal <dialog>. The form fields used to
   live in this cell, but it's far too narrow to host a select and a
   bust-kind picker without crowding; the modal gives them a real
   surface to render on. */
.col-rank .elim-trigger {
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 22px; height: 22px;
    padding: 0;
    background: transparent;
    border: 1px solid var(--muted);
    border-radius: 4px;
    color: var(--muted);
    font-size: 14px;
    line-height: 1;
    text-transform: none;
}
.col-rank .elim-trigger:hover {
    color: var(--fg);
    border-color: var(--accent-dark);
}

/* Shared elimination dialog. The native <dialog> + ::backdrop handles
   modality and click-outside-to-dismiss when paired with the JS in
   admin.js. Two stacked forms inside: the main "Bust" form (KO-by +
   bust-kind selectors) and the secondary "Delete entry" form for
   when an entry was recorded against the wrong player and just needs
   to go. */
.elim-modal {
    background: var(--panel);
    color: var(--fg);
    border: 1px solid var(--muted);
    border-radius: 8px;
    padding: 0;
    width: min(420px, 92vw);
    max-height: 90vh;
    box-shadow: 0 12px 32px rgba(0, 0, 0, 0.5);
}
.elim-modal::backdrop {
    background: rgba(0, 0, 0, 0.6);
    backdrop-filter: blur(2px);
}
.elim-modal-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 12px 16px;
    border-bottom: 1px solid var(--muted);
}
.elim-modal-header h3 {
    margin: 0;
    font-size: 16px;
    text-transform: uppercase;
    color: var(--muted);
}
.elim-modal-header h3 .elim-modal-name {
    color: var(--fg);
    text-transform: none;
}
.elim-modal-close {
    background: transparent;
    border: 0;
    color: var(--muted);
    cursor: pointer;
    font-size: 20px;
    line-height: 1;
    padding: 4px 8px;
}
.elim-modal-close:hover { color: var(--fg); }

.elim-modal .elim-form {
    display: flex;
    flex-direction: column;
    gap: 12px;
    align-items: stretch;
    padding: 16px;
}
.elim-modal .elim-form label {
    display: flex;
    flex-direction: column;
    gap: 4px;
    color: var(--muted);
    font-size: 11px;
    text-transform: uppercase;
}
.elim-modal .elim-form select {
    font: inherit;
    padding: 8px 10px;
    background: var(--panel-2);
    color: var(--fg);
    border: 1px solid var(--muted);
    border-radius: 4px;
}
.elim-modal .elim-form button {
    align-self: stretch;
    padding: 10px 16px;
}
.elim-modal .elim-delete-form {
    padding: 0 16px 16px;
}
.elim-modal .elim-delete-btn {
    width: 100%;
    padding: 8px 16px;
    font-size: 12px;
    background: transparent;
    color: var(--muted);
    border: 1px solid var(--muted);
}
.elim-modal .elim-delete-btn:hover {
    color: var(--fg);
    border-color: var(--accent-dark);
}

.col-rank .uneliminate { display: inline; }
.col-rank .uneliminate button {
    background: transparent;
    border: 0;
    color: var(--muted);
    cursor: pointer;
    padding: 0 0 0 4px;
    font-size: 14px;
    line-height: 1;
}
.col-rank .uneliminate button:hover { color: var(--fg); }
/* Sub-header row: month labels beneath each game column. */
.matrix thead tr.sub th {
    font-size: 11px;
    font-weight: 400;
    padding: 4px 8px;
    border-bottom: 1px solid var(--muted);
    color: var(--muted);
    text-transform: none;
}

/* Tournament clock — big-and-loud panel above the game body. State line
   ("CARDS UP IN" / "LEVEL N" / "PAUSED") on top, fat time digits in the
   middle, blinds + level notes underneath, and a thin progress bar
   showing how far into the current level we are. */
/* Top row of the game body — clock on the left fills remaining space,
   leaderboard panel on the right takes its natural content width.
   Flex's default align-items: stretch makes both boxes share the
   row's height (= max of the two), so they always match. Wraps to
   a single column when the clock would have to drop below ~320px. */
/* Layout direction is decided by clock.js's layout() — it adds .is-row
   when innerWidth >= innerHeight (landscape), .is-col otherwise. The
   class swap drives all the sizing here; JS only handles font fitting. */
.game-top {
    gap: 16px;
    /* Breathing room above the clock/leaderboard so they aren't flush
       against whatever panel sits directly above (was implicit when
       .game-top was main's first child; now the RSVP panel is). */
    padding-top: 14px;
    margin-bottom: 18px;
}

/* Landscape: side-by-side. .game-top is content-sized but capped at
   one viewport minus the sticky header. align-items: stretch makes the
   clock match the panel height, so the red box only grows as tall as
   the leaderboard (or its own content, whichever is larger), capped at
   the viewport. */
.game-top.is-row {
    display: grid;
    grid-template-columns: auto auto;
    /* Two rows: title (auto) and the leaderboard scroll-area (1fr).
       The clock spans both. Headers and rows share the same table now,
       so a single .results-scroll cell with a sticky thead handles the
       "headers visible while rows scroll" behavior naturally — no
       split tables, no manual column-width sync. */
    grid-template-rows: auto minmax(0, 1fr);
    max-height: calc(100vh - var(--header-h, 64px));
}

.game-top > .game-clock {
    /* Override the base .game-clock { margin: 0 0 18px } — inside
       .game-top, gap handles spacing, and the leftover 18px would
       leave the clock visibly taller than the panel in side-by-side. */
    margin: 0;
}

.game-top.is-row > .game-clock {
    grid-row: 1 / span 2;
}

/* Shared panel setup — both modes treat .panel as a flex column with
   .results-scroll as the only shrinkable child. The list's
   min-height: 120px contributes to the panel's automatic content-min
   (min-height: auto on flex items), so flex-shrink in either mode
   stops at chrome + 120 — no JS budgeting needed. */
.game-top > .panel {
    margin: 0;
    padding: 0;
    background: transparent;
    border-radius: 0;
    /* Block the implicit overflow-y: auto promotion from
       .panel:has(table) { overflow-x: auto } — vertical scrolling
       belongs to .results-scroll, not the whole panel. */
    overflow: visible;
    display: flex;
    flex-direction: column;
}

/* When admin can edit Paid/AO, game_results.php wraps .results-scroll
   in a <form>. Without this, the form would be the panel's direct flex
   item — flex on .results-scroll wouldn't apply where it matters, and
   the panel's natural-height squeeze would shrink h2/payouts instead
   of the list. display: contents pulls .results-scroll up to be a
   direct flex item of the panel (the form's submit semantics stay
   intact). */
.game-top > .panel > form {
    display: contents;
}

/* Everything in the panel except .results-scroll holds its natural
   size — only the list gives way when there's not enough room. */
.game-top > .panel > *:not(.results-scroll):not(form) {
    flex-shrink: 0;
}

/* Scope to descendants of .game-top — that's the only place the
   leaderboard wrapper needs a height floor + scroll behavior. The
   previous :last-child variant broke as soon as a sibling element
   landed after it (the elim-modal <dialog>, etc.), and didn't
   meaningfully apply on the season page either, where .results-scroll
   sits inside its own .panel without a height-bound parent. */
.game-top .results-scroll {
    min-height: 50px;
    overflow-y: auto;
    overflow-x: auto;
}

/* Side-by-side specifics. */
.game-top.is-row > .panel {
    flex: 0 0 auto;
    min-width: 0;
    /* Cap panel main-axis (height) at viewport. align-items: stretch
       on the row syncs both items' heights, but a tall leaderboard
       would still push the row past the viewport without this cap. */
    max-height: calc(100vh - var(--header-h, 64px));
}

/* Stacked: definite height (= viewport - header) so flex-shrink
   actually fires when content exceeds it. max-height alone leaves the
   container indefinite for flex purposes — items wouldn't shrink, and
   the panel + list would just overflow into the layout below. With
   height: cap, the panel can shrink toward its content min and
   .results-scroll inside it absorbs the squeeze and scrolls. */
.game-top.is-col {
    display: flex;
    flex-direction: column;
    max-height: calc(100vh - var(--header-h, 64px));
}

/* Sticky thead — the .results-scroll wrapper is the scroll container;
   pinning thead to its top keeps column headers visible as the rows
   scroll underneath, in both row mode (results-scroll fills the 1fr
   grid cell) and col mode (it shrinks via max-height). Solid bg so
   the alternating row stripes don't bleed through. */
.game-top .results-scroll table.results thead th {
    position: sticky;
    top: 0;
    background: var(--panel-2);
    z-index: 1;
}

.game-clock {
    background: var(--accent-dark);
    border-radius: 12px;
    margin: 0 0 18px;
    text-align: center;
    color: var(--fg);
    position: relative;
    /* Stack the clock contents (state / time / blinds / notes /
       progress / pause) and center them vertically. When the clock
       sits next to a taller leaderboard panel and stretches to match,
       the contents float in the middle of the panel rather than
       hugging the top. */
    display: flex;
    flex-direction: column;
    justify-content: center;
    color: var(--fg);
}
.game-clock-state {
    font-size: clamp(20px, 3.5vw, 36px);
    border-top-left-radius: 12px;
    border-top-right-radius: 12px;
    text-transform: uppercase;
    color: var(--panel-2);
    background: var(--fg);
    font-weight: 700;
    line-height: 1.1;
}
.game-clock-max-text {
    font-size: 14px;
    flex-grow: 1;
    line-height: 1;
    font-weight: 700;
    white-space: nowrap;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
}

.game-clock-blinds .sep {
    color: var(--muted);
}
/* Level/break notes — a small subordinate line under the headline. */
.game-clock-notes {
    margin-top: 6px;
    font-size: 12px;
    color: var(--muted);
    text-transform: uppercase;
    min-height: 1em;
}
.game-clock-notes:empty { display: none; }
.game-clock-progress {
    margin: 18px auto 6px;
    height: 8px;
    width: 100%;
    max-width: 480px;
    background: rgba(255, 255, 255, 0.08);
    border-radius: 4px;
    position: relative;
    /* No overflow:hidden — the playhead marker on the bar deliberately
       extends taller than the track. */
}
.game-clock-progress-bar {
    display: block;
    height: 100%;
    width: 0;
    background: var(--fg);
    border-radius: 4px 0 0 4px;
    position: relative;
    transition: width 0.5s linear;
}
/* Vertical playhead at the boundary between completed and remaining
   time. Sticks above and below the track for emphasis. */
.game-clock-progress-bar::after {
    content: '';
    position: absolute;
    right: -2px;
    top: -7px;
    bottom: -7px;
    width: 4px;
    background: var(--fg);
    border-radius: 2px;
}
/* Small "Next: X / Y" or "Next: 20m Break" line under the progress bar. */
.game-clock-next {
    font-size: clamp(22px, 3.5vw, 36px);
    color: var(--muted);
}
.game-clock-next:empty { display: none; }
/* Pre-game state: nothing to track yet, so suppress the progress bar
   and the "Next:" tease until cards are up. */
.game-clock--pre-game .game-clock-progress,
.game-clock--pre-game .game-clock-next { display: none; }
.game-clock-pause {
    margin-top: 14px;
}
.game-clock-pause button {
    font-size: 12px;
    padding: 6px 16px;
}
.game-clock--final .game-clock-time { color: var(--muted); }

/* Page-wide mute toggle pinned to bottom-left. Starts in the muted state
   (X icon, dimmed). One click anywhere on the site swaps to the speaker
   icon and unmutes; thereafter clicking the button toggles. */
.bcc-mute {
    position: fixed;
    left: 12px;
    bottom: 12px;
    width: 38px;
    height: 38px;
    border-radius: 50%;
    border: 1px solid var(--muted);
    background: rgba(20, 24, 30, 0.85);
    color: var(--fg);
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    z-index: 50;
    padding: 0;
    backdrop-filter: blur(4px);
    -webkit-backdrop-filter: blur(4px);
}
.bcc-mute:hover { color: var(--accent-dark); }
.bcc-mute .bcc-mute-on,
.bcc-mute .bcc-mute-off { display: none; }
.bcc-mute[data-muted="0"] .bcc-mute-on  { display: block; }
.bcc-mute[data-muted="1"] .bcc-mute-off { display: block; color: var(--muted); }

/* Blind structure editor inside Edit Game. Nested <details> so it
   stays collapsed by default; the preset bar / grid / save-as-preset
   block only render when the admin opens it. */
details.blind-editor { margin-top: 4px; }
details.blind-editor > summary {
    cursor: pointer;
    font-weight: 600;
    font-size: 12px;
    text-transform: uppercase;
    color: var(--muted);
    padding: 6px 0;
    user-select: none;
}
details.blind-editor[open] > summary { color: var(--fg); margin-bottom: 8px; }
.blind-preset-bar {
    display: flex;
    gap: 10px;
    align-items: end;
    flex-wrap: wrap;
    margin-bottom: 10px;
}
.blind-preset-bar label { display: flex; flex-direction: column; gap: 4px; }
.blind-preset-bar select { min-width: 180px; }
.blind-preset-delete:disabled { opacity: 0.4; cursor: not-allowed; }
.blind-grid { width: 100%; }
.blind-grid th { text-align: left; font-size: 11px; color: var(--muted); }
.blind-grid td.lv { width: 32px; color: var(--muted); font-variant-numeric: tabular-nums; }
.blind-grid td input[type="number"][name$="[mins]"] { min-width: 5ch;  padding-left: 4px; padding-right: 2px; }
.blind-grid td input[type="number"][name$="[big]"]  { min-width: 10ch; padding-left: 4px; padding-right: 2px; }
.blind-grid tr.is-break td input[type="number"][name$="[big]"] { display: none; }
.blind-grid td input[type="text"]   { width: 100%; min-width: 140px; }
.blind-grid td.rm-cell { width: 24px; }
/* Beats the generic last-child width on admin-edit mini-tables. The
   column shrinks to fit the buttons; the inner flex div holds spacing
   constant regardless of whitespace between the button tags. */
.admin-edit table.mini-table td.row-controls {
    width: 1%;
    white-space: nowrap;
    padding-left: 6px;
}
.blind-grid .row-ctrl {
    display: flex;
    justify-content: flex-end;
    gap: 2px;
}
.blind-grid .row-ctrl .row-mv,
.blind-grid .row-ctrl .rm {
    flex: 0 0 auto;
    background: transparent;
    border: 1px solid var(--muted);
    color: var(--muted);
    width: 24px;
    height: 24px;
    padding: 0;
    border-radius: 4px;
    cursor: pointer;
    line-height: 1;
    font-size: 14px;
}
.blind-grid .row-ctrl .row-mv:hover,
.blind-grid .row-ctrl .rm:hover { color: var(--fg); border-color: var(--accent-dark); }
.blind-grid-actions { margin: 8px 0 14px; }
.blind-preset-save {
    display: flex;
    gap: 8px;
    align-items: center;
    flex-wrap: wrap;
    border-top: 1px dashed var(--muted);
    padding-top: 10px;
}
.blind-preset-save .blind-preset-name { flex: 0 1 220px; }
.blind-preset-save .hint { flex-basis: 100%; }

