:root {
    /* The wheel answers to the room's height as well as its width: on a 720px
       projector or laptop it shrinks instead of pushing SPIN! out of reach. */
    --pie-size: clamp(240px, min(40vw, calc(100vh - 320px)), 420px);

    /* Type — one family, so the hierarchy is carried by size, weight and tone. The
       tokens are named for the job, never the value: --t-display means "the verdict"
       whatever it happens to measure. A role the sheet does not use is not defined. */
    --t-display: 2.5rem;    /* the winner's name — the loudest type in the product */
    --t-lead: 1.75rem;      /* the ceremonial line above it, always smaller than it */
    --t-headline: 1.5rem;   /* the product name in the chrome */
    --t-title: 1.2rem;      /* section headings, the SPIN! control, a lone empty state */
    --t-body: 1rem;         /* the base: chips, fields, buttons, record cells, notice copy */
    --t-small: 0.9rem;      /* table head bands, tabs, the odds list, quiet utility */
    /* Marks are the emoji glyphs that ride alongside text. They are sized, not set:
       nobody is asked to read a sentence at them, so they sit outside the ramp. */
    --t-mark-lg: 4rem;      /* the winner's celebration glyph */
    --t-mark-md: 1.5rem;    /* the wheel's hub glyph */
    --t-mark-sm: 1.1rem;    /* the record's per-row delete glyph */
    /* Leading is set per job. UI lines hold the rhythm of the row they live in;
       prose gets more air because it is read as sentences at the far end of a
       table. 1.4 is what this face already produced at `normal` — now it is a
       choice a role can be tuned against instead of a metric inherited by accident. */
    --lh-ui: 1.4;
    --lh-prose: 1.55;
    --lh-tight: 1.1;
    --lh-fitted: 1.15;
    /* Only two kinds of text are tracked: uppercase labels, which lose legibility
       without it, and the display name, which sprawls at 800 weight with it. */
    --track-caps: 0.06em;
    --track-display: -0.015em;
    /* Paragraph-length copy shares one measure, so a new section inherits it instead
       of inventing a line length. 60ch is measured, not traditional: the widest
       notice this tool writes was setting 78 characters on a line, and this pulls it
       back inside the 45–75 the page is read at. Utility labels (the hint under the
       add field) are single lines by nature and take the leading, not the cap. */
    --measure-prose: 60ch;

    /* Surfaces — paperwork first: white cards on a faintly green page. */
    --paper: #ffffff;
    --bg: #f4f7f0;
    --surface-config: #f9fbf8;
    --sage-mist: #e0f0e8;
    --linen: #fff8f0;
    --wash-mint: #f0f7f0;
    --wash-config-row: #f9fdfb;
    /* The ceremony opens on the page's own colour, so the wheel looks like it grew
       out of the paperwork rather than being pasted over it. */
    --scrim: rgba(244, 247, 240, 0.97);

    /* Structure — Chalkline Forest is the institution; it is not the action colour. */
    --forest: #2d7050;
    --meadow: #3a9a6a;
    --ink: #222222;
    /* The whole neutral ramp carries the page's own hue (about 120°) at the same
       lightness it always had. Nothing here is a new colour: a green-tinted world
       with achromatic borders, dividers and greys made every control look like it
       was borrowed from another tool. Lightness is untouched, so nothing got
       darker, heavier, or lost contrast — the ramp just stopped being colourless. */
    --graphite: #2d392d;
    --detail: #4d5c4d;
    /* The one quiet text tone, tinted from the page ground rather than a flat gray,
       and dark enough to read at room distance (4.5:1 on every surface it ships on). */
    --ash: #5f6b62;
    --fog: #c4cfc4;
    --mist: #ebefeb;
    --putty: #dde3dd;

    /* The verb. Green fills only a control you can act on right now, or one already
       in the chosen state. Deepened from #00ad00 so white label text clears AA. */
    --green: #0a7f30;
    --green-deep: #086b28;
    --green-focus: #065c22;
    --green-glow: rgba(10, 127, 48, 0.32);
    --green-tint: rgba(10, 127, 48, 0.16);
    /* A disabled control is a designed pair, never 50% opacity: this tool is read
       across a table, and washed-out text is the one thing a room cannot decipher. */
    --off-action: #d7e6dc;
    --off-action-ink: #3f4a44;
    --off-neutral: #e6e8e4;
    --off-neutral-ink: #4f5754;

    /* The record. Orange is where a verdict is written down, never where it is
       reached — and it is never a button. Deepened for AA under white table text. */
    --record: #b34a00;
    --banner-gold: #ffe082;
    --banner-plate: rgba(12, 33, 24, 0.62);
    --header-from: #2d7050;
    --header-to: #3a9a6a;

    /* Status */
    --alert: #d32f2f;
    --alert-ink: #991b1b;
    --alert-detail: #7f1d1d;
    --alert-wash: #fee2e2;
    --alert-bed: #fbe9e7;
    --alert-bed-deep: #fecaca;
    --alert-quiet: #b3261e;
    --confirm: #166534;
    --confirm-wash: #dcfce7;
    --confirm-bed: #bbf0d2;
    /* Neutral is the state a teammate sits in, not an error and not a win: the same
       sage as every other neutral here, no longer the blue-grey the pair used to
       carry — the only blue in the product, on the one badge that must not shout.
       Darkened in step: the old ink measured 4.39:1 on its own wash. */
    --neutral-wash: #f4f5f4;
    --neutral-ink: #5d655d;

    /* The Wait Ladder: the longer since your last turn, the warmer the record's
       date. It reads as lightness as well as hue, so it survives a colour-blind
       colleague and a washed-out projector, and the words sit beside it anyway. */
    --wait-now: var(--ash);
    --wait-days: #8b6737;
    --wait-week: #8f521b;
    --wait-overdue: #863806;

    --scroll-thumb: #a9c6b5;
    color-scheme: light;
    --t-interact: background-color 0.2s ease, border-color 0.2s ease, color 0.2s ease, transform 0.2s ease, box-shadow 0.2s ease;
}

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

/* scrollbar-color inherits, so one declaration themes every scroll host on the
   page — the wheel's odds list, the sideways-scrolling records, all of them. */
html { scrollbar-color: var(--scroll-thumb) var(--bg); }

body {
    font-family: 'Segoe UI', system-ui, -apple-system, sans-serif;
    background: var(--bg);
    color: var(--ink);
    font-size: var(--t-body);
    line-height: var(--lh-ui);
    min-height: 100vh;
}

body.locked { overflow: hidden; }

/* Form controls inherit neither the font nor the leading of the page, which is why
   every control here already repeats `font-family: inherit`. The base leading is
   handed over the same way, so a label that has to wrap inside a chip, a tab or a
   button leads the way the same words lead everywhere else on the page. */
.btn, .tab, .spin-btn, .close-btn, .more-btn, .btn-toggle-status,
.btn-delete-participant, .btn-delete-row, .name-chip,
.add-participant-form input[type="text"] {
    line-height: var(--lh-ui);
}

::selection { background: var(--green-tint); }

/* One focus treatment for everything you can act on — the 3px green ring the
   system already uses on the text field, widened so it survives room distance. */
:focus { outline: none; }
:focus-visible {
    outline: 3px solid var(--green-focus);
    outline-offset: 2px;
}

.sr-only {
    position: absolute;
    width: 1px; height: 1px;
    padding: 0; margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
}

header {
    background: linear-gradient(135deg, var(--header-from), var(--header-to));
    color: var(--paper);
    padding: 20px 30px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    flex-wrap: wrap;
    box-shadow: 0 2px 8px rgba(0,0,0,0.15);
}

header h1 {
    font-size: var(--t-headline);
    font-weight: 600;
    /* The header is a nameplate: two words on one line and one on the next would
       be the same words read twice. */
    text-wrap: balance;
}

/* The header's one job is the last verdict, so it gets a plate of its own: the
   gradient shows through, but white and gold land on deep forest, which is the
   only way either of them clears 4.5:1 over a mid-green gradient. */
.latest-banner {
    background: var(--banner-plate);
    border-radius: 10px;
    padding: 8px 16px;
    font-size: var(--t-body);
    text-align: right;
    text-wrap: pretty;
    min-width: 0;
    overflow-wrap: anywhere;
}

.latest-banner strong { color: var(--banner-gold); }
.latest-banner .banner-error { color: var(--paper); font-weight: 600; }
/* A verdict the record never took is an admission, not a celebration: it takes the
   plate's own white at a heavier weight, so the gold stays the winner's alone. */
.latest-banner .banner-pending { color: var(--paper); font-weight: 700; }

.container {
    max-width: 1100px;
    margin: 0 auto;
    padding: 30px 20px;
}

h2 {
    font-size: var(--t-title);
    /* 700 was coming from the user-agent's `bold`; a role this load-bearing is
       written down, because the ceremonial heading overrides it and must win on
       weight as well as size. */
    font-weight: 700;
    margin-bottom: 16px;
    color: var(--forest);
    text-wrap: balance;
}

/* --- Name Selection --- */
.section { margin-bottom: 30px; }

.name-grid {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    justify-content: center;
}

.name-chip {
    padding: 12px 20px;
    border: 2px solid var(--fog);
    border-radius: 12px;
    cursor: pointer;
    user-select: none;
    font-family: inherit;
    font-size: var(--t-body);
    font-weight: 600;
    line-height: var(--lh-ui);
    text-wrap: balance;
    transition: var(--t-interact);
    background: var(--paper);
    min-width: 160px;
    max-width: min(100%, 320px);
    min-height: 46px;
    text-align: center;
    overflow-wrap: anywhere;
}

.name-chip:hover { border-color: var(--meadow); transform: translateY(-2px); box-shadow: 0 3px 8px rgba(0,0,0,0.1); }
.name-chip.selected { background: var(--green); color: var(--paper); border-color: var(--green); }
.name-chip.selected:hover { background: var(--green-deep); }

.grid-empty {
    width: 100%;
    text-align: center;
    padding: 40px;
    color: var(--ash);
    /* Size says "this is the whole of it", ash says "nothing here yet" — the two
       together are the statement, so it does not need a third size of its own. */
    font-size: var(--t-title);
    text-wrap: balance;
}

.notice-host:not(:empty) { margin-top: 16px; }

/* --- Notices: the shared way this tool says "something went wrong" --- */
.notice {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 12px 20px;
    padding: 12px 16px;
    border: 2px solid var(--fog);
    border-radius: 12px;
    background: var(--paper);
    max-width: 760px;
    margin: 0 auto;
}

.notice-copy { min-width: 0; flex: 1 1 260px; }
/* Stacked admissions (an unwritten verdict above a spent wheel) keep the working
   step rather than touching, in either host that can carry two of them. */
.notice + .notice { margin-top: 10px; }
.notice-title { font-size: var(--t-body); font-weight: 700; color: var(--graphite); text-wrap: balance; }
.notice-detail { margin-top: 4px; font-size: var(--t-body); line-height: var(--lh-prose); color: var(--detail); overflow-wrap: anywhere; max-width: var(--measure-prose); text-wrap: pretty; }
.notice-actions { display: flex; gap: 8px; flex-wrap: wrap; }

.notice-error { background: var(--alert-wash); border-color: var(--alert); }
.notice-error .notice-title { color: var(--alert-ink); }
.notice-error .notice-detail { color: var(--alert-detail); }

.notice-confirm { background: var(--confirm-wash); border-color: var(--confirm); }
.notice-confirm .notice-title { color: var(--confirm); }

/* A busy notice is the machinery working, not an admission of failure: it keeps
   the paper surface and takes the softer face of the forest as its edge, with the
   spinner doing the part colour cannot — the busy wash and the confirm wash are
   indistinguishable without hue perception, a spinner is not. */
.notice-neutral .notice-title { color: var(--graphite); }
.notice-neutral .notice-detail { color: var(--detail); }
.notice-neutral.is-busy { border-color: var(--meadow); }

.notice.is-busy .spinner {
    width: 14px; height: 14px;
    border: 2px solid var(--fog);
    border-top-color: var(--forest);
    border-radius: 50%;
    animation: spin-around 0.9s linear infinite;
}

@keyframes spin-around { to { transform: rotate(360deg); } }

/* Utilities hug the grid they act on; the wheel button is separated from both,
   so the one button that starts the ritual is never just the third in a row. */
.actions {
    display: flex;
    gap: 24px;
    justify-content: center;
    margin-top: 20px;
    flex-wrap: wrap;
}

.actions-group {
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
    justify-content: center;
}

.btn {
    padding: 12px 28px;
    border: none;
    border-radius: 12px;
    font-family: inherit;
    font-size: var(--t-body);
    cursor: pointer;
    transition: var(--t-interact);
    font-weight: 600;
}

.btn:hover { transform: translateY(-2px); box-shadow: 0 4px 12px rgba(0,0,0,0.15); }
.btn-primary { background: var(--green); color: var(--paper); }
.btn-secondary { background: var(--putty); color: var(--graphite); }
/* A control that cannot be used says so in its own fill and words, not by fading:
   half-opacity text is unreadable at the far end of the table. */
.btn:disabled { cursor: not-allowed; transform: none; box-shadow: none; background: var(--off-neutral); color: var(--off-neutral-ink); }
.btn-primary:disabled { background: var(--off-action); color: var(--off-action-ink); }
.btn-danger { background: var(--alert); color: var(--paper); font-size: var(--t-small); padding: 8px 18px; }
.btn-sm { padding: 8px 16px; font-size: var(--t-small); }

/* --- Wheel Overlay --- */
.wheel-overlay {
    position: fixed;
    inset: 0;
    /* The page's own colour at 97% — the ceremony happens in the same room. */
    background: var(--scrim);
    z-index: 100;
    display: none;
    place-items: center;
    /* Centred when it fits, scrollable from the top when it does not — a plain
       centred stack would bury whatever overflowed past the top edge. */
    align-content: safe center;
    gap: 30px;
    /* A rotated square's bounding box grows past the circle that is painted,
       so the overlay scrolls lengthwise only. */
    overflow: hidden auto;
    padding: 70px 20px 30px;
}

.wheel-overlay.active { display: grid; }

/* Wheel, status and button travel as one group; the odds list sits beside that
   group while there is room for it and falls below it when there is not. */
.wheel-stage {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    align-items: center;
    gap: 30px 40px;
    width: 100%;
}

.wheel-primary {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 20px;
    flex: 0 0 auto;
}

/* The wheel's own admissions line up with the wheel, not with the widest thing the
   stage could hold. */
.wheel-primary > .notice-host { width: 100%; max-width: 560px; }

.wheel-container {
    position: relative;
    width: var(--pie-size);
    height: var(--pie-size);
    display: grid;
    place-items: center;
}

.wheel {
    width: 100%;
    height: 100%;
    border-radius: 50%;
    position: relative;
    transition: transform 4s cubic-bezier(0.17, 0.67, 0.12, 0.99);
    overflow: hidden;
}

.wheel-slice {
    position: absolute;
    width: 100%;
    height: 100%;
    border-radius: 50%;
    display: grid;
    place-items: center;
}

.wheel-label {
    position: absolute;
    text-align: center;
    color: var(--paper);
    font-weight: 600;
    line-height: var(--lh-fitted);
    /* The label lies along the spoke, so its width is radial room: from outside the
       hub to inside the rim. Everything the slice has to spare is the arc its height
       sits on, which is why fitSliceLabels() decides name by name. */
    width: 34%;
    user-select: none;
    overflow-wrap: anywhere;
    /* The slice ramp is kept dark enough (see buildWheel) that white labels clear
       4.5:1 on every hue; this halo only tidies the edge of a long name. */
    text-shadow: 0 1px 2px rgba(0,0,0,0.55);
}

.wheel-label[hidden] { display: none; }

.wheel-pointer {
    position: absolute;
    top: 50%;
    right: -18px;
    width: 0;
    height: 0;
    border-top: 18px solid transparent;
    border-bottom: 18px solid transparent;
    border-right: 30px solid var(--forest);
    transform: translateY(-50%);
    z-index: 10;
    filter: drop-shadow(-2px 0 3px rgba(0,0,0,0.3));
}

.wheel-center {
    position: absolute;
    width: 50px;
    height: 50px;
    background: var(--paper);
    border-radius: 50%;
    box-shadow: 0 0 10px rgba(0,0,0,0.2);
    z-index: 5;
    display: grid;
    place-items: center;
    font-size: var(--t-mark-md);
}

/* The odds, as words and numbers — the wheel's colour-and-area claim, audible. */
.wheel-legend {
    list-style: none;
    flex: 1 1 320px;
    max-width: min(100%, 560px);
    /* Beside the wheel the list gets the wheel's own height to work with, so a
       normal roster is read whole instead of scrolling inside the overlay. */
    max-height: min(48vh, 440px);
    overflow: auto;
    background: var(--paper);
    border: 2px solid var(--fog);
    border-radius: 12px;
    padding: 12px 14px;
    font-size: var(--t-small);
}

.legend-head { display: grid; gap: 2px; padding-bottom: 8px; border-bottom: 1px solid var(--mist); }
.legend-title { font-weight: 700; color: var(--forest); text-wrap: balance; }
/* The sentence that explains the drawing is the most-read prose in the ceremony, so
   it takes the shared measure: at the wheel's full 560px column it was setting
   77-character lines. */
.legend-note { color: var(--detail); line-height: var(--lh-prose); max-width: var(--measure-prose); text-wrap: pretty; }

.legend-item {
    display: grid;
    grid-template-columns: 14px minmax(0, 1fr) auto;
    gap: 4px 10px;
    align-items: center;
    padding: 6px 0;
    border-bottom: 1px solid var(--mist);
}
.legend-item:last-child { border-bottom: none; }
/* The swatch is the wheel's slice, so it is the one place the wheel's hues appear
   as a key rather than as the thing itself. */
.legend-swatch { width: 14px; height: 14px; border-radius: 4px; box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.12); }
.legend-name { font-weight: 600; color: var(--graphite); min-width: 0; overflow-wrap: anywhere; }
.legend-wait { grid-column: 2; color: var(--wait-now); font-size: var(--t-small); font-variant-numeric: tabular-nums; }
.legend-odds { font-weight: 700; color: var(--forest); font-variant-numeric: tabular-nums; text-align: right; }

/* The Wait Ladder, applied to the odds list and to the record's dates. */
.wait-now { color: var(--wait-now); }
.wait-days { color: var(--wait-days); }
.wait-week { color: var(--wait-week); }
.wait-overdue { color: var(--wait-overdue); font-weight: 600; }

.spin-status { min-height: 1.4em; font-size: var(--t-body); font-weight: 600; color: var(--forest); }

.spin-btn {
    padding: 16px 40px;
    background: var(--green);
    color: var(--paper);
    border: none;
    border-radius: 16px;
    font-family: inherit;
    font-size: var(--t-title);
    font-weight: 700;
    cursor: pointer;
    transition: var(--t-interact);
    z-index: 10;
}

.spin-btn:hover { transform: scale(1.05); box-shadow: 0 4px 16px var(--green-glow); }
.spin-btn:disabled { cursor: not-allowed; transform: none; background: var(--off-action); color: var(--off-action-ink); }

.close-btn {
    position: absolute;
    top: 20px;
    right: 20px;
    padding: 10px 20px;
    background: var(--paper);
    border: 2px solid var(--fog);
    border-radius: 10px;
    font-family: inherit;
    cursor: pointer;
    font-size: var(--t-body);
    z-index: 10;
}

/* --- Winner Announcement --- */
.winner-announce {
    display: none;
    position: fixed;
    inset: 0;
    background: rgba(0,0,0,0.6);
    z-index: 200;
    place-items: center;
    padding: 20px;
    overflow: auto;
}

.winner-announce.active {
    display: grid;
    /* `safe center` keeps the card centred while it fits and scrollable from its top
       when it does not — the same grant the wheel overlay already holds. A long name
       plus the day's quote on a short laptop must not push the celebration out of reach. */
    align-content: safe center;
}

.winner-card {
    background: var(--paper);
    border-radius: 24px;
    padding: 40px 50px;
    text-align: center;
    max-width: min(92vw, 620px);
    box-shadow: 0 20px 60px rgba(0,0,0,0.3);
    animation: pop-in 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
}

/* The ceremony speaks in two lines and the name still outshines both. The spoken
   line takes the ceremonial step the heading used to hold (the heading itself is now
   screen-reader only, so the dialog is named "Today's sharer" rather than a heart), and
   the day's quote sits under the name in the quiet tier. Both ends of the clamp land on
   documented steps, and the name's floor is still the spoken line's ceiling, so the
   pairing rule holds at 320px exactly as it does at 1440px. */
.winner-card .winner-line {
    font-size: clamp(var(--t-title), 5.5vw, var(--t-lead));
    font-weight: 700;
    line-height: var(--lh-ui);
    color: var(--forest);
    text-wrap: balance;
    margin: 10px 0 0;
}
.winner-card .winner-quote {
    font-size: var(--t-small);
    line-height: var(--lh-prose);
    color: var(--detail);
    max-width: var(--measure-prose);
    margin: 0 auto;
    text-wrap: balance;
}
.winner-card .winner-name {
    font-size: clamp(var(--t-lead), 8vw, var(--t-display));
    font-weight: 800;
    line-height: var(--lh-tight);
    letter-spacing: var(--track-display);
    text-wrap: balance;
    color: var(--record);
    margin: 16px 0;
    overflow-wrap: anywhere;
}
.winner-card .winner-emoji { font-size: var(--t-mark-lg); line-height: var(--lh-tight); }
.winner-card .notice { margin: 16px 0 0; text-align: left; }
.winner-actions { margin-top: 24px; display: flex; flex-direction: column; gap: 8px; align-items: center; }
.winner-hint { font-size: var(--t-small); color: var(--ash); }

@keyframes pop-in {
    from { transform: scale(0.5); opacity: 0; }
    to { transform: scale(1); opacity: 1; }
}

/* --- Toasts --- */
.toast-region {
    position: fixed;
    left: 50%;
    bottom: 24px;
    transform: translateX(-50%);
    z-index: 300;
    display: flex;
    flex-direction: column;
    gap: 10px;
    width: min(92vw, 560px);
    pointer-events: none;
}

.toast-region .notice {
    box-shadow: 0 4px 12px rgba(0,0,0,0.15);
    pointer-events: auto;
    animation: toast-in 0.22s ease-out;
}

.toast-region .notice.is-leaving { opacity: 0; transform: translateY(6px); transition: var(--t-interact); }

@keyframes toast-in {
    from { opacity: 0; transform: translateY(8px); }
    to { opacity: 1; transform: translateY(0); }
}

/* --- Leaderboard --- */
.leaderboard-table,
.history-table {
    width: 100%;
    border-collapse: collapse;
    background: var(--paper);
    border-radius: 12px;
    box-shadow: 0 2px 8px rgba(0,0,0,0.08);
    font-variant-numeric: tabular-nums;
}

/* A fifty-row record needs its header band to stay while the rows scroll, so the
   rounded band is clipped by its own corners instead of by overflow: hidden. */
.leaderboard-table thead th,
.history-table thead th {
    position: sticky;
    top: 0;
    z-index: 2;
}

.leaderboard-table thead th:first-child,
.history-table thead th:first-child { border-radius: 12px 0 0 0; }
.leaderboard-table thead th:last-child,
.history-table thead th:last-child { border-radius: 0 12px 0 0; }
.leaderboard-table tbody tr:last-child td:first-child,
.history-table tbody tr:last-child td:first-child { border-radius: 0 0 0 12px; }
.leaderboard-table tbody tr:last-child td:last-child,
.history-table tbody tr:last-child td:last-child { border-radius: 0 0 12px 0; }

/* Numbers and dates hold still so the names get the room they need. A count is
   scanned from its right edge, so the wins column and its header share one; the
   history's stamp now carries a full year like every other date in the record, so
   its column is measured on the real string rather than the truncated one. */
.leaderboard-table th:first-child { width: 72px; }
.leaderboard-table th:nth-child(3) { width: 110px; text-align: right; }
.leaderboard-table td:nth-child(3) { text-align: right; }
.leaderboard-table th:nth-child(4) { width: 150px; }
.history-table th:first-child { width: 175px; }
.history-table th:nth-child(2) { width: 220px; }
.history-table th:last-child { width: 64px; }

.leaderboard-table th {
    background: var(--forest);
    color: var(--paper);
    padding: 12px 16px;
    text-align: left;
    font-size: var(--t-small);
}

.leaderboard-table td {
    padding: 10px 16px;
    border-bottom: 1px solid var(--mist);
    font-size: var(--t-body);
    overflow-wrap: anywhere;
}

.leaderboard-table tr:hover td { background: var(--wash-mint); }
.leaderboard-table .rank { font-weight: 700; color: var(--forest); }

/* --- History --- */
.history-table th {
    background: var(--record);
    color: var(--paper);
    padding: 12px 16px;
    text-align: left;
    font-size: var(--t-small);
}

.history-table td {
    padding: 10px 16px;
    border-bottom: 1px solid var(--mist);
    font-size: var(--t-body);
    min-width: 0;
    overflow-wrap: anywhere;
    vertical-align: top;
}

.history-table tr:hover td { background: var(--linen); }
/* A name in the record is the verdict already written down, so it carries the
   record's colour — never the action's. */
.history-table td strong { color: var(--record); }

.participants-cell { display: table-cell; }

.more-btn {
    display: block;
    margin-top: 4px;
    padding: 2px 8px;
    border: 2px solid var(--fog);
    border-radius: 8px;
    background: var(--paper);
    color: var(--graphite);
    font-family: inherit;
    font-size: var(--t-small);
    font-weight: 600;
    cursor: pointer;
    transition: var(--t-interact);
}

.more-btn:hover { border-color: var(--meadow); transform: translateY(-2px); }

.record-foot { margin-top: 12px; display: flex; justify-content: flex-end; }
.record-note { font-size: var(--t-small); color: var(--ash); }

/* The key for the Wait Ladder, set in the four colours it explains. */
.record-key {
    margin-top: 12px;
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 4px 10px;
    font-size: var(--t-small);
    color: var(--ash);
}
.record-key-label { font-weight: 700; color: var(--graphite); }
.record-key-sep { color: var(--ash); }

.btn-delete-row {
    background: none;
    border: none;
    color: var(--alert-quiet);
    cursor: pointer;
    /* Without `inherit` this button was the one control on the page drawing the
       user-agent's own font — and it is a glyph, so it took the size of a mark. */
    font-family: inherit;
    font-size: var(--t-mark-sm);
    display: inline-grid;
    place-items: center;
    /* A glyph-only control still has to be aimed at, on whatever screen is on the
       table; the mark stays small, the bed it sits on does not. */
    min-width: 36px;
    min-height: 36px;
    padding: 4px 8px;
    border-radius: 6px;
    transition: var(--t-interact);
}
.btn-delete-row:hover { color: var(--alert-ink); background: var(--alert-bed); }

.tabs {
    display: flex;
    gap: 8px;
    margin-bottom: 16px;
    flex-wrap: wrap;
}

.tab {
    padding: 10px 18px;
    border: 2px solid var(--fog);
    border-radius: 8px;
    cursor: pointer;
    background: var(--paper);
    color: var(--ink);
    font-family: inherit;
    font-size: var(--t-small);
    transition: var(--t-interact);
}

.tab:hover { border-color: var(--meadow); }
.tab.active { background: var(--forest); color: var(--paper); border-color: var(--forest); }
.tab-content { display: none; }
.tab-content.active { display: block; }

.empty-state {
    text-align: center;
    padding: 40px;
    color: var(--ash);
    font-size: var(--t-title);
    text-wrap: balance;
}

/* --- Participants Configuration Tab --- */
.participants-config {
    padding: 20px;
    background: var(--surface-config);
    border-radius: 12px;
}

.participants-config h2 {
    margin-bottom: 16px;
}

.add-participant-form {
    display: flex;
    gap: 10px;
    flex-wrap: wrap;
    align-items: center;
    margin-bottom: 20px;
}

.add-participant-form input[type="text"] {
    flex: 1 1 250px;
    min-width: 200px;
    max-width: 420px;
    padding: 12px 16px;
    border: 2px solid var(--fog);
    border-radius: 8px;
    font-family: inherit;
    font-size: var(--t-body);
    background: var(--paper);
    color: var(--ink);
    caret-color: var(--green);
    outline: none;
    transition: var(--t-interact);
}

.add-participant-form input[type="text"]::placeholder { color: var(--ash); opacity: 1; }

.add-participant-form input[type="text"]:focus-visible {
    border-color: var(--green);
    box-shadow: 0 0 0 3px var(--green-tint);
}

/* Own line by design: the admission belongs to the field above it. It keeps the
   prose leading and the tidy wrap, and takes no measure cap — a max-width here is
   read before the line breaks, which would pull the hint back up beside the Add
   button it is meant to sit under. */
.form-hint {
    flex: 1 1 100%;
    font-size: var(--t-small);
    line-height: var(--lh-prose);
    text-wrap: pretty;
    color: var(--detail);
}

/* An admission about the add-field sits against the field it belongs to, then
   the table resumes on the generous step. */
.add-participant-form + .notice-host { margin-top: 8px; }
.add-participant-form + .notice-host .notice { margin-bottom: 20px; max-width: 620px; }

/* The counts are the table's footline, not a block of their own. */
.participants-table-section { margin-bottom: 12px; overflow-x: auto; }

.participants-table {
    width: 100%;
    border-collapse: collapse;
    background: var(--paper);
    border-radius: 12px;
    overflow: hidden;
    box-shadow: 0 2px 4px rgba(0,0,0,0.05);
}

/* Names get the room; the badge and the two row actions hold still. */
.participants-table th:nth-child(2) { width: 170px; }
.participants-table th:last-child { width: 210px; }

.participants-table th,
.participants-table td {
    padding: 12px 16px;
    text-align: left;
    border-bottom: 1px solid var(--mist);
    min-width: 0;
    overflow-wrap: anywhere;
}

/* The one uppercase role in the product, and the only place tracking is earned:
   capitals at 14px run together without it. It now matches the other two table head
   bands on size, so three records read as one surface. */
.participants-table th {
    background: var(--sage-mist);
    font-size: var(--t-small);
    letter-spacing: var(--track-caps);
    text-transform: uppercase;
    color: var(--detail);
    font-weight: 600;
}

.participants-table tr:hover td {
    background: var(--wash-config-row);
}

.participants-table .name-cell {
    font-weight: 600;
    color: var(--graphite);
}

.participants-table .status-icon {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 4px 12px;
    border-radius: 20px;
    font-size: var(--t-small);
    /* A badge may be two words or four, and in a bilingual team it will be both at
       once. It wraps by phrase rather than pushing its column or clipping. */
    white-space: normal;
    text-wrap: balance;
}

.participants-table .status-active {
    background: var(--confirm-wash);
    color: var(--confirm);
}

/* An inactive teammate is not an error: the badge stays grey on purpose. */
.participants-table .status-inactive {
    background: var(--neutral-wash);
    color: var(--neutral-ink);
}

.participants-table .actions-cell {
    display: flex;
    gap: 6px;
    flex-wrap: wrap;
}

/* Row buttons share one box whether they carry a border or not, so the three
   actions on a roster row stay a row and not a stagger. The 2px border is paid for
   out of the padding (4+2 where it was 6, 12+2 where it was 14), so every button's
   outer box is the one it always had and the actions column never rewraps. */
.btn-toggle-status {
    padding: 4px 12px;
    border: 2px solid transparent;
    border-radius: 6px;
    cursor: pointer;
    font-family: inherit;
    font-size: var(--t-small);
    font-weight: 600;
    transition: var(--t-interact);
}

.btn-toggle-status.activate {
    background: var(--confirm-wash);
    color: var(--confirm);
}

.btn-toggle-status.activate:hover { background: var(--confirm-bed); }

/* Sitting someone out of today is the grey state, so it wears the grey uniform:
   a quiet paper control with the tool's other utility affordances. Red is the
   colour of a loss, and a colleague on the bench is not one — the badge this
   button produces is grey, and the button that produces it now matches it. */
.btn-toggle-status.deactivate {
    background: var(--paper);
    border-color: var(--fog);
    color: var(--graphite);
}

.btn-toggle-status.deactivate:hover {
    border-color: var(--meadow);
    transform: translateY(-2px);
    box-shadow: 0 3px 8px rgba(0, 0, 0, 0.1);
}

.btn-delete-participant {
    padding: 4px 12px;
    border: 2px solid transparent;
    border-radius: 6px;
    cursor: pointer;
    font-family: inherit;
    font-size: var(--t-small);
    background: var(--alert-wash);
    color: var(--alert-ink);
    transition: var(--t-interact);
}

.btn-delete-participant:hover {
    background: var(--alert-bed-deep);
    transform: scale(1.05);
}

.active-count-info {
    padding: 12px 16px;
    background: var(--paper);
    border-radius: 8px;
    display: flex;
    gap: 24px;
    font-size: var(--t-small);
    flex-wrap: wrap;
    font-variant-numeric: tabular-nums;
}

.active-count-info strong {
    color: var(--forest);
}

/* The warm note in the orange corner of the tool: the configuration rule, the one
   place the record's family appears as ambience rather than as a signal. */
.config-note {
    margin-top: 24px;
    padding: 12px;
    background: var(--linen);
    border-radius: 8px;
    color: #7c2d12;
    font-size: var(--t-body);
    line-height: var(--lh-prose);
    max-width: var(--measure-prose);
    text-wrap: pretty;
}

.config-note em {
    /* The note is the record's family used as ambience; the emphasised word takes the
       note's own warm ink and a heavier weight rather than a fourth colour. */
    color: inherit;
    font-weight: 700;
}

/* --- Small screens: the wheel, the pointer and the tables have to fit --- */
@media (max-width: 430px) {
    :root { --pie-size: min(78vw, 320px); }
    .container { padding: 20px 12px; }
    header { padding: 16px 18px; }
    .latest-banner { text-align: left; }
    .wheel-overlay { padding: 60px 10px 20px; }
    .wheel-stage { gap: 20px; }
    .wheel-primary { gap: 16px; }
    .wheel-pointer { right: -10px; filter: none; }
    /* On a phone the ✕ and the rim of the wheel are competing for the same corner, so
       the control takes the small type and the tight padding the rest of the phone
       block already allows. */
    .close-btn { top: 10px; right: 10px; padding: 6px 14px; font-size: var(--t-small); }
    .wheel-legend { max-height: min(60vh, 420px); }
    .winner-card { padding: 26px 20px; }
    .grid-empty { padding: 24px 12px; }
    /* A wide record reads better scrolling sideways than squeezing one letter per
       line, so the record keeps a readable measure and its panel scrolls. */
    #leaderboardContainer,
    #historyContainer { overflow-x: auto; }
    .leaderboard-table,
    .history-table { min-width: 640px; }
    .participants-table { min-width: 480px; }
    .actions { gap: 16px; }
    .btn { padding: 12px 16px; }
    .winner-actions { flex-direction: row; }
    .winner-actions .btn { flex: 1 1 140px; }
}

/* --- When the room cannot see well, or cannot wait --- */
@media (prefers-reduced-motion: reduce) {
    .name-chip:hover,
    .btn:hover,
    .spin-btn:hover,
    .more-btn:hover,
    .btn-toggle-status.deactivate:hover,
    .btn-delete-participant:hover { transform: none; }
    .spin-btn:hover { transform: none; }
    .winner-card { animation-duration: 0.01s; }
    .toast-region .notice { animation: none; }
    .notice.is-busy .spinner { animation-duration: 2.4s; }
}

@media (forced-colors: active) {
    :focus-visible { outline-color: highlight; }
    .notice { border-color: canvasText; background: canvas; }
    .notice .notice-title, .notice .notice-detail { color: canvasText; }
    .name-chip.selected { border-color: highlight; }
    .wheel-legend { border-color: canvasText; }
    /* The Wait Ladder is colour first, so in high contrast the overdue step keeps
       a weight difference and the rest returns to the system ink. */
    .wait-now, .wait-days, .wait-week { color: canvasText; }
    .wait-overdue { color: canvasText; }
    .record-key-sep { color: canvasText; }
    .latest-banner { background: canvas; color: canvasText; }
    .latest-banner strong { color: canvasText; }
}
