/*
 * Team Angus Hockey. The palette is the football site's (team-angus-fantasy), so the two pools
 * read as one family; the layout is simpler because the pages are.
 */
:root {
    --bg: #0f1420;
    --card: #182031;
    --raised: #1f2940;
    --border: #27314a;
    --text: #e8ecf5;
    --muted: #94a0bb;
    --accent: #4f8cff;
    --pos: #5fd39a;
    --neg: #ef7b77;
    --danger: #d9534f;
    --warn: #e0a84a;
    --silver: #b9c3d6;
    --bronze: #c98a5a;
}

* {
    box-sizing: border-box;
}

body {
    margin: 0;
    min-height: 100vh;
    display: flex;
    flex-direction: column;
    align-items: center;
    padding: 2rem 1rem;
    background: var(--bg);
    color: var(--text);
    font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
    line-height: 1.5;
}

a {
    color: var(--accent);
}

.card {
    width: 100%;
    max-width: 64rem;
    background: var(--card);
    border: 1px solid var(--border);
    border-radius: 14px;
    padding: 1.5rem 2rem 2rem;
    box-shadow: 0 12px 40px rgba(0, 0, 0, 0.35);
}

/* The slate grid has a column per manager, so its page takes the whole window. */
/* Wide enough for a full season's slates grid (17 managers, every stat) on a 1920 screen. */
.wide-card {
    max-width: 100rem;
}

h1 {
    margin: 0;
    font-size: 1.5rem;
}

h2, h3 {
    margin: 1.5rem 0 0.75rem;
}

h3 {
    font-size: 1.05rem;
}

.subtitle,
.muted {
    color: var(--muted);
}

.page-head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem 1.5rem;
    padding-bottom: 1rem;
    border-bottom: 1px solid var(--border);
}

.page-head .subtitle {
    margin: 0;
}

.view-switch {
    display: flex;
    flex-wrap: wrap;
    gap: 0.25rem;
}

.view-tab {
    padding: 0.35rem 0.8rem;
    border-radius: 999px;
    color: var(--muted);
    text-decoration: none;
    font-size: 0.92rem;
}

.view-tab:hover {
    color: var(--text);
    background: var(--raised);
}

.view-tab-on,
.view-tab-on:hover {
    color: var(--text);
    background: var(--accent);
}

.picker {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-top: 1.25rem;
    color: var(--muted);
}

.picker select,
.picker button,
.card input,
.card select,
.card textarea,
.btn {
    font: inherit;
    color: var(--text);
    background: var(--raised);
    border: 1px solid var(--border);
    border-radius: 8px;
    padding: 0.35rem 0.6rem;
}

.btn,
.picker button {
    cursor: pointer;
}

.btn:hover,
.picker button:hover {
    border-color: var(--accent);
}

.btn-primary {
    background: var(--accent);
    border-color: var(--accent);
}

.btn-small {
    padding: 0.1rem 0.5rem;
    font-size: 0.8rem;
}

.season-title {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 0.75rem;
    margin-top: 1.25rem;
}

.season-status {
    font-size: 0.9rem;
    font-weight: normal;
    color: var(--muted);
}

.notice {
    padding: 0.75rem 1rem;
    background: var(--raised);
    border-radius: 8px;
}

.crumb {
    margin: 1rem 0 0;
}

/* The payout strip: pot, per-slate prize, most-points prize. */
.payout {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
    gap: 0.75rem;
    margin: 1rem 0 1.25rem;
}

.payout > div {
    padding: 0.75rem 1rem;
    background: var(--raised);
    border: 1px solid var(--border);
    border-radius: 10px;
}

.payout dt {
    font-size: 0.8rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--muted);
}

.payout dd {
    margin: 0.1rem 0 0;
    font-size: 1.5rem;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}

.payout-note {
    font-size: 0.8rem;
    color: var(--muted);
}

/* Tables. A wrapper scrolls sideways on a phone rather than the page. */
.table-wrap {
    overflow-x: auto;
}

.grid {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.92rem;
}

.grid th,
.grid td {
    padding: 0.4rem 0.6rem;
    border-bottom: 1px solid var(--border);
    text-align: left;
}

.grid thead th,
.grid tfoot th {
    font-size: 0.78rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: var(--muted);
    white-space: nowrap;
}

.grid tfoot th {
    border-bottom: none;
    border-top: 1px solid var(--border);
}

.grid tbody tr:hover {
    background: rgba(255, 255, 255, 0.03);
}

.grid .num {
    text-align: right;
    font-variant-numeric: tabular-nums;
}

.grid tr.leader td {
    background: rgba(79, 140, 255, 0.08);
}

.strong {
    font-weight: 600;
}

.nowrap {
    white-space: nowrap;
}

.mono {
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 0.85rem;
}

.pos {
    color: var(--pos);
}

.neg {
    color: var(--neg);
}

.warn {
    color: var(--warn);
}

.row-link {
    color: inherit;
    text-decoration: none;
}

.row-link:hover {
    color: var(--accent);
    text-decoration: underline;
}

.footnote {
    margin: 0.75rem 0 0;
    font-size: 0.82rem;
    color: var(--muted);
}

/* A ROUNDS season's round leaders, above its standings. */
.grid.rounds {
    margin-bottom: 1.5rem;
}

/* The slate grid. */
/* Tight, so a season's grid fits a desktop screen without scrolling sideways. */
.slate-grid {
    font-size: 0.84rem;
}

.slate-grid td,
.slate-grid th {
    padding: 0.3rem 0.25rem;
}

/* A wrapped header ("Yahoo best") is two lines; the rest sit on its bottom line, over the numbers. */
.slate-grid thead th {
    vertical-align: bottom;
}

.slate-grid .manager-col {
    text-transform: none;
    letter-spacing: 0;
    font-size: 0.8rem;
}

/* A slate's top score and its lowest; every other score is left plain. */
.cell-win {
    background: #2f9e6b;
    color: #fff;
    font-weight: 700;
}

.cell-low {
    background: #b8413d;
    color: #fff;
}

.cell-absent {
    background: repeating-linear-gradient(135deg, transparent 0 4px, rgba(255, 255, 255, 0.04) 4px 8px);
}

/* One of the three lowest scores a manager's points drop: struck out, and faded back. */
.cell-dropped {
    text-decoration: line-through;
    text-decoration-thickness: 2px;
    opacity: 0.6;
}

.legend-dropped {
    margin-right: 0.35rem;
    text-decoration: line-through;
    text-decoration-thickness: 2px;
    opacity: 0.75;
}

/* The slate statistics down the right, set off from the managers' columns. */
.slate-grid .stat-col {
    border-left: 1px solid var(--muted);
}

/* The manager statistics along the bottom: a label per block, then a label per row. */
.slate-grid tfoot td {
    font-size: 0.82rem;
    border-bottom: 1px solid var(--border);
}

.slate-grid tfoot .foot-first th,
.slate-grid tfoot .foot-first td {
    border-top: 1px solid var(--muted);
}

.slate-grid .foot-group {
    vertical-align: top;
    white-space: normal;
    min-width: 0;
    max-width: 4.5rem;
    font-size: 0.72rem;
    color: var(--text);
}

.slate-grid .foot-stat {
    text-align: left;
}

.legend {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.4rem 0.9rem;
    font-size: 0.82rem;
    color: var(--muted);
}

.swatch {
    display: inline-block;
    width: 0.9rem;
    height: 0.9rem;
    margin-right: -0.5rem;
    border-radius: 3px;
    border: 1px solid var(--border);
    vertical-align: middle;
}

/* One slate's lineups as cards, best first; the winner's edged green, the lowest red. */
.slate-nav {
    display: flex;
    justify-content: space-between;
    margin: 0 0 1rem;
}

.lineups {
    display: grid;
    /* A card is at least 25rem, or the whole width on a phone narrower than that. */
    grid-template-columns: repeat(auto-fill, minmax(min(25rem, 100%), 1fr));
    gap: 1rem;
}

.lineup {
    padding: 0.5rem 0.75rem 0.25rem;
    background: var(--raised);
    border: 1px solid var(--border);
    border-radius: 10px;
}

.lineup-win {
    border-color: #2f9e6b;
    box-shadow: inset 0 3px 0 #2f9e6b;
}

.lineup-low {
    border-color: #b8413d;
    box-shadow: inset 0 3px 0 #b8413d;
}

.lineup header {
    display: flex;
    align-items: baseline;
    gap: 0.5rem;
    margin-bottom: 0.25rem;
}

.lineup-points {
    margin-left: auto;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

/*
 * Every pick row the same height, so cards side by side line up row for row: room for the name,
 * how rostered he was, the game, and a box score of up to two lines. Fixed layout, and each of
 * those capped at its lines (cut with an ellipsis, whole on hover), so nothing can push one row
 * taller than its neighbours.
 */
.lineup-table {
    font-size: 0.85rem;
    table-layout: fixed;
}

.lineup-table .col-slot {
    width: 2.6rem;
}

.lineup-table .col-cost {
    width: 3rem;
}

.lineup-table .col-pts {
    width: 3.8rem;
}

.lineup-table tbody tr {
    height: 6.1rem;
}

.lineup-table .pick,
.pick-detail {
    min-width: 0;
}

/* Flex inside the cell, not on it: a cell that is itself flex stops being a table cell, and its
   row's border stops short. */
.lineup-table td {
    vertical-align: middle;
}

.pick-detail > * {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.pick-detail > :last-child {
    white-space: normal;
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    line-clamp: 2;
}

/*
 * The best and worst lineups as one mirrored table: the best reads out from the middle to the
 * left, the worst to the right, the position shared between them. Green edge on the best side,
 * red on the worst, as their cards have. Scrolls sideways on a phone rather than squeezing.
 */
.compare {
    overflow-x: auto;
    background: var(--raised);
    border: 1px solid var(--border);
    border-radius: 10px;
    border-left: 3px solid #2f9e6b;
    border-right: 3px solid #b8413d;
    padding: 0.25rem 0.75rem;
}

.compare-table {
    min-width: 46rem;
}

/* The slate's player pool: its own scrolling box, header pinned. */
/* The list runs the page's length, no scroll box. Its headers pin to the window, which needs no
   scrolling ancestor, so it gives up .table-wrap's sideways scroll where it fits; narrower, it
   keeps the scroll and the headers don't pin. */
@media (min-width: 1200px) {
    .table-wrap.player-pool {
        overflow-x: visible;
    }
}

/* Both header rows - names and filters - stay pinned as the list scrolls. */
.pool-table thead {
    position: sticky;
    top: 0;
    z-index: 1;
    background: var(--card);
}

/* The cells too: a row group's background leaves the gaps between cells see-through. And borders
   kept separate: Chrome paints collapsed borders apart from a pinned header, letting the rows
   scrolling under it show through. */
.pool-table {
    border-collapse: separate;
    border-spacing: 0;
}

.pool-table thead th {
    background: var(--card);
}

.pool-table .pool-filters th {
    padding: 0.2rem 0.3rem 0.4rem;
}

/* Qualified to outrank `.card input`, and appearance off so a search box takes the dark theme. */
.pool-table .pool-filters input[type="search"],
.pool-table .pool-filters select {
    width: 100%;
    min-width: 2.6rem;
    padding: 0.2rem 0.3rem;
    font-size: 0.8rem;
    background: var(--raised);
    color: var(--text);
    color-scheme: dark;
}

/* The inputs only: a select keeps its arrow so it reads as a dropdown. */
.pool-table .pool-filters input[type="search"] {
    appearance: none;
    -webkit-appearance: none;
}

/* Owned by: a dropdown of checkboxes. The menu is placed by pool-table.js with position: fixed,
   so the list's scroll box doesn't clip it. */
.owner-filter summary {
    list-style: none;
    cursor: pointer;
    padding: 0.2rem 1.4rem 0.2rem 0.4rem;
    font-size: 0.8rem;
    font-weight: 400;
    text-transform: none;
    letter-spacing: 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 9rem;
    border: 1px solid var(--border);
    border-radius: 6px;
    background: var(--raised);
    color: var(--text);
    position: relative;
}

.owner-filter summary::-webkit-details-marker {
    display: none;
}

.owner-filter summary::after {
    content: "▾";
    position: absolute;
    right: 0.4rem;
}

.owner-filter[data-active] summary {
    border-color: var(--accent);
}

.owner-menu {
    position: fixed;
    z-index: 10;
    max-height: 18rem;
    overflow-y: auto;
    min-width: 10rem;
    padding: 0.3rem 0;
    border: 1px solid var(--border);
    border-radius: 8px;
    background: var(--raised);
    box-shadow: 0 6px 20px rgba(0, 0, 0, 0.45);
}

.owner-menu label {
    display: flex;
    gap: 0.5rem;
    align-items: center;
    padding: 0.25rem 0.8rem;
    font-size: 0.85rem;
    font-weight: 400;
    text-transform: none;
    letter-spacing: 0;
    white-space: nowrap;
    cursor: pointer;
}

.owner-menu input {
    margin: 0;
    accent-color: var(--accent);
}

.owner-menu label:hover {
    background: var(--card);
}

.pool-table .pool-filters input.filter-bad {
    border-color: var(--danger);
}

.pool-hint {
    font-size: 0.8rem;
}

.pool-table .owners {
    font-size: 0.8rem;
}

.pool-controls {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem 0.75rem;
    margin-bottom: 0.75rem;
}

.pool-table th[data-sort] {
    cursor: pointer;
    user-select: none;
}

.pool-table th[aria-sort="descending"]::after {
    content: " ▼";
}

.pool-table th[aria-sort="ascending"]::after {
    content: " ▲";
}

/* Nobody in the pool had him: the rows worth scanning for what everyone missed. */
.pool-table tr.unowned .strong {
    font-weight: 400;
}

.compares {
    display: flex;
    flex-direction: column;
    gap: 1rem;
}

/* Qualified by the table: the plain .grid header style (left-aligned, small caps) would win. */
.compare-table thead th.compare-head {
    font-size: 0.95rem;
    font-weight: 400;
    text-transform: none;
    letter-spacing: 0;
    color: var(--text);
}

.compare-table thead th.compare-best {
    text-align: left;
}

.compare-best .lineup-points {
    float: right;
}

.compare-table thead th.compare-worst {
    text-align: right;
}

.compare-worst .lineup-points {
    float: left;
}

.compare-head .muted,
.compare-head .strong {
    margin: 0 0.3rem;
}

.compare-table .compare-slot,
.compare-table thead th.compare-slot {
    text-align: center;
    border-left: 1px solid var(--border);
    border-right: 1px solid var(--border);
}

/* The worst side's pick, mirrored: portrait on the outer edge, text reading in to the middle. */
.pick-mirror {
    flex-direction: row-reverse;
    text-align: right;
}

.lineup-table td,
.lineup-table th {
    padding: 0.25rem 0.35rem;
}

/* A player's headshot beside his name: round, on the card's own ground. */
.pick {
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

/* Lineup portraits at Yahoo's size: 60px (its lineups show 120px images at 60). The stored ones
   are 128px, so they stay sharp on high-density screens. */
.headshot {
    flex: none;
    width: 40px;
    height: 40px;
    border-radius: 50%;
    background: var(--border);
    object-fit: cover;
}

.headshot-small {
    width: 32px;
    height: 32px;
}

.headshot-lineup {
    width: 60px;
    height: 60px;
}

.headshot-medium {
    width: 72px;
    height: 72px;
}

/* A player's seasons and teams, each in that jersey. */
.jerseys {
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem;
    margin: 0.5rem 0 1rem;
}

.jerseys figure {
    margin: 0;
    text-align: center;
    font-size: 0.78rem;
}

.headshot-large {
    width: 112px;
    height: 112px;
}

.player-title {
    align-items: center;
}

/* A pick's name, then how rostered he was, the game, and his box score - a line each. */
.pick-detail {
    display: flex;
    flex-direction: column;
    font-size: 0.75rem;
    line-height: 1.35;
}

.pick-detail .pick-name {
    font-size: 0.85rem;
    font-weight: 600;
}

.lineup-game {
    display: block;
    font-size: 0.75rem;
}

.lineup-none {
    margin: 0.5rem 0;
}

.kind-switch {
    margin-top: 1.25rem;
}

/* A long list kept to a sensible height beside its neighbour. */
.scroll-list {
    max-height: 32rem;
    overflow-y: auto;
}

/* Two tables side by side, stacked on a narrow screen. */
.two-up {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(22rem, 100%), 1fr));
    gap: 0 2rem;
}

/* A grid column otherwise grows to its widest table; this lets the table scroll in it instead. */
.two-up > *,
.boards > * {
    min-width: 0;
}

/* Two boards a row on a desktop - each record's regular-season board beside its playoffs twin,
   the order RecordBookResolver gives them in - and one a row below tablet width. */
.boards {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0 2rem;
}

@media (max-width: 52rem) {
    .boards {
        grid-template-columns: 1fr;
    }
}

/* Admin. */
.admin-section {
    margin-top: 1.5rem;
    padding-top: 0.5rem;
    border-top: 1px solid var(--border);
}

.admin-row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.6rem;
    margin-top: 1rem;
}

.admin-grid {
    display: grid;
    grid-template-columns: max-content minmax(0, 20rem);
    align-items: center;
    gap: 0.5rem 0.75rem;
    margin: 0.75rem 0;
}

.paste {
    width: 100%;
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 0.85rem;
}

.admin-actions {
    display: flex;
    gap: 0.5rem;
    margin: 0.75rem 0;
}

.preview {
    margin-top: 1rem;
    padding: 0 1rem 0.5rem;
    background: var(--raised);
    border-radius: 10px;
}

.podcast-upload {
    flex-wrap: wrap;
    align-items: center;
}

/* The admin page's uploaded episodes: each with its size and a Take down button. */
.podcast-episodes {
    display: grid;
    gap: 0.4rem;
    margin: 0.75rem 0;
    padding: 0;
    list-style: none;
}

.podcast-episodes li {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem 0.75rem;
}

.podcast-episodes form {
    margin: 0;
}

.logout-form {
    margin-top: 2rem;
}

.site-footer {
    margin-top: 1.25rem;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.25rem;
    font-size: 0.8rem;
    color: var(--muted);
}

@media (max-width: 40rem) {
    body {
        padding: 1rem 0.5rem;
    }

    .card {
        padding: 1rem;
        border-radius: 10px;
    }

    .boards,
    .two-up {
        grid-template-columns: 1fr;
    }
}

/* A player's season-by-season table: its total set off from the seasons above. */
.grid tfoot.totals td {
    border-top: 2px solid var(--border);
    border-bottom: none;
    font-weight: 600;
}

/* The players list's two switches - seasons, and skaters or goalies - side by side. */
.list-switches {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    gap: 0.75rem;
    margin-top: 1.25rem;
}

/* The best-and-worst comparison: the mirrored table, or on a phone - too narrow for it - the two
   lineups as stacked cards. */
.compare-cards {
    display: none;
}

@media (max-width: 40rem) {
    .compare {
        display: none;
    }

    .compare-cards {
        display: grid;
        gap: 1rem;
        margin-bottom: 1rem;
    }
}

/* A lineup card on a phone: cards stack one per row there, so rows need not match a neighbour's
   height. Everything wraps instead of being cut short, around a smaller portrait. */
@media (max-width: 40rem) {
    .lineup-table tbody tr {
        height: auto;
    }

    .lineup-table .col-slot {
        width: 1.9rem;
    }

    .lineup-table .col-cost {
        width: 2.7rem;
    }

    .lineup-table .col-pts {
        width: 3.3rem;
    }

    .pick-detail > *,
    .pick-detail > :last-child {
        white-space: normal;
        overflow: visible;
        display: block;
        -webkit-line-clamp: unset;
    }

    .headshot-lineup {
        width: 44px;
        height: 44px;
    }
}

/* The perfect lineup: gold, the one colour nothing else on the site uses. */
.lineup-perfect {
    border-color: #c9a13b;
    box-shadow: inset 0 3px 0 #c9a13b;
}

.perfect-title {
    color: #e3b94f;
    font-weight: 700;
}

.perfect-star {
    color: #e3b94f;
    font-weight: 800;
    margin-left: 0.25rem;
}

/* League: head to head, all at once. Row's win % against column, coloured by cellStyle. */
.h2h {
    border-collapse: separate;
    border-spacing: 2px;
    font-size: 0.8rem;
    font-variant-numeric: tabular-nums;
}

.h2h th,
.h2h td {
    padding: 0;
}

.h2h .rowhead {
    text-align: right;
    padding-right: 0.5rem;
    white-space: nowrap;
    font-weight: 700;
    line-height: 1.9rem;
    position: sticky;
    left: 0;
    background: var(--card);
    z-index: 1;
}

.h2h .corner {
    color: var(--muted);
    font-size: 0.7rem;
    text-align: right;
    padding-right: 0.5rem;
    vertical-align: bottom;
    position: sticky;
    left: 0;
    background: var(--card);
}

/* A column name, rotated, taken out of the width calculation so every column is the same width
   however long the name. */
.h2h th.rot {
    height: 5.5rem;
    width: 2.7rem;
    position: relative;
}

.h2h th.rot span {
    position: absolute;
    left: 1.35rem;
    bottom: 0.3rem;
    transform: rotate(-55deg);
    transform-origin: left bottom;
    white-space: nowrap;
    font-size: 0.75rem;
    color: var(--muted);
}

.h2h td.cell,
.h2h td.self,
.h2h td.none {
    width: 2.7rem;
    min-width: 2.7rem;
    height: 1.9rem;
    text-align: center;
    border-radius: 4px;
}

.h2h td.cell a {
    display: block;
    color: var(--text);
    text-decoration: none;
    line-height: 1.9rem;
}

.h2h td.cell a:hover,
.h2h td.cell a:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: -2px;
    border-radius: 4px;
}

.h2h td.self {
    color: var(--muted);
    background: var(--raised);
}

/* A pair that met in fewer than two seasons: a small sample, shown faintly. */
.h2h td.thin {
    opacity: 0.45;
}

.h2h-controls {
    font-size: 0.9rem;
}

.legend {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem 1rem;
    font-size: 0.82rem;
    color: var(--muted);
}

.swatch {
    display: inline-block;
    width: 1.4rem;
    height: 0.9rem;
    border-radius: 3px;
    vertical-align: middle;
    margin-right: 0.3rem;
}

.swatch-lose { background: rgba(239, 123, 119, 0.58); }
.swatch-even { background: rgba(95, 211, 154, 0.08); }
.swatch-win { background: rgba(95, 211, 154, 0.58); }

/* A manager's Rivals: three highlight chips, each opening its rivalry. */
.rival-chips {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(14rem, 100%), 1fr));
    gap: 0.75rem;
    margin-bottom: 1rem;
}

.rival-chip {
    display: grid;
    gap: 0.15rem;
    padding: 0.75rem 0.9rem;
    background: var(--raised);
    border: 1px solid var(--border);
    border-radius: 10px;
    color: var(--text);
    text-decoration: none;
    font-variant-numeric: tabular-nums;
}

.rival-chip:hover,
.rival-chip:focus-visible {
    border-color: var(--accent);
}

.rival-kind {
    font-size: 0.72rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--muted);
    font-weight: 700;
}

.rival-name {
    font-size: 1.15rem;
    font-weight: 800;
}

.versus-record {
    color: var(--muted);
    font-variant-numeric: tabular-nums;
}

/* A row's name is a whole row tall, so it's easy to tap. */
.h2h .rowhead a {
    display: block;
}

/* The best lineup submitted on all of Yahoo: teal, beside the perfect lineup's gold. */
.lineup-best {
    border-color: #3aa3b3;
    box-shadow: inset 0 3px 0 #3aa3b3;
}

.best-title {
    color: #5ec8d8;
    font-weight: 700;
}

/* A manager's night to remember, beside their name. */
.badge {
    display: inline-block;
    font-size: 0.66rem;
    font-weight: 800;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    padding: 0.05rem 0.4rem;
    border-radius: 4px;
    margin-left: 0.4rem;
    white-space: nowrap;
    vertical-align: 0.12em;
}

.badge-best {
    background: rgba(94, 200, 216, 0.13);
    color: #5ec8d8;
    border: 1px solid rgba(94, 200, 216, 0.45);
}

.badge-perfect {
    background: rgba(227, 185, 79, 0.12);
    color: #e3b94f;
    border: 1px solid rgba(227, 185, 79, 0.5);
}

.best-count {
    color: #5ec8d8;
}

.gold-count {
    color: #e3b94f;
}

/* The night in four numbers, above best and worst. */
.score-strip {
    display: flex;
    flex-wrap: wrap;
    gap: 0.35rem 1.5rem;
    padding: 0.55rem 0.8rem;
    background: var(--raised);
    border: 1px solid var(--border);
    border-radius: 8px;
    color: var(--muted);
    font-size: 0.9rem;
    font-variant-numeric: tabular-nums;
}

.score-strip b {
    color: var(--text);
}

/* The slates grid: a ring on a score that was the best on Yahoo (teal) or perfect (gold). */
.slate-grid td.cell-best {
    box-shadow: inset 0 0 0 2px #5ec8d8;
}

.slate-grid td.cell-perfect {
    box-shadow: inset 0 0 0 2px #e3b94f;
}

.swatch.ring-best {
    box-shadow: inset 0 0 0 2px #5ec8d8;
}

.swatch.ring-perfect {
    box-shadow: inset 0 0 0 2px #e3b94f;
}

/* A pick's name and its ★ on one line: together they're one line of the pick's details. */
.pick-name-line .pick-name {
    display: inline;
}

/* A slate's recap, at the top of slate.xhtml. */
.recap {
    display: grid;
    gap: 0.9rem;
}

.recap h3 {
    margin-bottom: 0;
}

.recap-eyebrow {
    font-size: 0.75rem;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--muted);
    font-weight: 700;
}

.recap-headline {
    font-size: 1.7rem;
    line-height: 1.15;
    margin: 0;
    text-wrap: balance;
}

.recap-flags {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin: 0;
}

.record-flag {
    display: inline-flex;
    background: rgba(227, 185, 79, 0.12);
    color: #e3b94f;
    border: 1px solid rgba(227, 185, 79, 0.5);
    border-radius: 999px;
    padding: 0.15rem 0.7rem;
    font-size: 0.8rem;
    font-weight: 700;
}

/* A milestone (a first win, a drought over): gold like a record, but not bold - a record is bigger news. */
.milestone-flag {
    font-weight: 500;
}

.recap-intro {
    display: grid;
    gap: 0.35rem;
    max-width: 62ch;
    font-size: 1.05rem;
    line-height: 1.6;
}

.recap-intro p {
    margin: 0;
}

.recap-awards {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(15rem, 100%), 1fr));
    gap: 0.75rem;
}

.recap-award {
    display: grid;
    grid-template-columns: 44px 1fr;
    gap: 0.15rem 0.75rem;
    align-items: start;
    padding: 0.8rem 0.9rem;
    background: var(--raised);
    border: 1px solid var(--border);
    border-radius: 10px;
}

.recap-award > .headshot,
.recap-award-blank {
    width: 44px;
    height: 44px;
    grid-row: span 3;
    border-radius: 50%;
    background: var(--card);
}

.recap-award-title {
    font-size: 0.7rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--muted);
    font-weight: 700;
}

.recap-award-name {
    font-weight: 800;
}

.recap-award-note {
    color: var(--muted);
    font-size: 0.85rem;
    font-variant-numeric: tabular-nums;
}

.recap-award-note b {
    color: var(--text);
}

.recap-race-note {
    margin: 0.2rem 0 0.5rem;
    font-size: 0.85rem;
}

.recap-more {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem 1.5rem;
}

/* The bar chart race (race.js): bars placed by transform, re-sorted as the values move. */
.race-controls {
    display: flex;
    align-items: center;
    gap: 0.8rem;
    margin-bottom: 0.6rem;
    color: var(--muted);
    font-size: 0.85rem;
}

.race-controls input[type="range"] {
    flex: 1;
    min-width: 0;
    accent-color: var(--accent);
}

.race-play {
    flex: none;
    width: 2.2rem;
    height: 2.2rem;
    border: none;
    border-radius: 50%;
    background: var(--accent);
    color: #fff;
    font-size: 0.8rem;
    cursor: pointer;
}

.race-play:focus-visible {
    outline: 2px solid var(--text);
    outline-offset: 2px;
}

.race-track {
    position: relative;
}

.race-item {
    position: absolute;
    left: 0;
    right: 0;
    height: 1.5rem;
    display: grid;
    grid-template-columns: 5.5rem 1fr 4.8rem;
    gap: 0.6rem;
    align-items: center;
    font-size: 0.85rem;
    font-variant-numeric: tabular-nums;
    transition: transform 0.35s ease;
}

.race-name {
    font-weight: 700;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.race-bar {
    height: 1.15rem;
    border-radius: 3px;
    background: var(--accent);
    opacity: 0.85;
}

.race-lead .race-bar {
    background: var(--pos);
}

.race-value {
    text-align: right;
}

@media (prefers-reduced-motion: reduce) {
    .race-item {
        transition: none;
    }
}

.recap-link {
    margin: 0.2rem 0 0.8rem;
}

.recap-copy {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.4rem 0.9rem;
    margin: 0;
}

/* A two-word header that may take two lines, so its column is only as wide as its numbers. */
.slate-grid th.head-wrap {
    white-space: normal;
    width: 3.2rem;
}

/* A manager's Yahoo handle beside their name: how to find them in Yahoo's app. */
.yahoo-handle {
    margin-left: 0.45rem;
    color: var(--muted);
    font-size: 0.8em;
    font-weight: 400;
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
}

.yahoo-handles {
    margin: -0.3rem 0 0.9rem;
    color: var(--muted);
}

.yahoo-handles .strong {
    color: var(--text);
}

/* A recap's written commentary: set apart from the derived intro above it. */
.recap-commentary {
    display: grid;
    gap: 0.6rem;
    max-width: 68ch;
    padding: 0.2rem 0 0.2rem 1rem;
    border-left: 3px solid var(--accent);
    font-size: 1.02rem;
    line-height: 1.6;
}

.recap-commentary p {
    margin: 0;
}

/* The slate's podcast episode: the show's name, then a player as wide as the commentary. */
.recap-podcast {
    display: grid;
    gap: 0.5rem;
    max-width: 68ch;
    padding: 0.7rem 0.9rem;
    background: var(--card);
    border: 1px solid var(--border);
    border-radius: 8px;
}

.recap-podcast-title {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 0.2rem 0.6rem;
    margin: 0;
}

.recap-podcast-show {
    font-weight: 700;
    letter-spacing: 0.02em;
}

.recap-podcast audio {
    width: 100%;
    color-scheme: dark;
}

/* The Records page's headings between groups of boards. */
.records-group {
    margin: 2rem 0 0.2rem;
    padding-top: 1rem;
    border-top: 1px solid var(--border);
}

.board-detail {
    display: block;
    color: var(--text);
    font-size: 0.85rem;
}

/* On a phone a record's detail (who owned him, the season and dates) goes under its name and
   figure, full width, instead of a column squeezed to a few words a line. */
@media (max-width: 640px) {
    .board .grid tr {
        display: grid;
        grid-template-columns: 1.6rem 1fr auto;
        column-gap: 0.5rem;
        border-bottom: 1px solid var(--border);
    }

    .board .grid td {
        border-bottom: none;
    }

    .board .grid td:nth-child(4) {
        grid-column: 2 / -1;
        padding-top: 0;
    }
}

/* A manager's Pick style: a label, then each measure on a track from the pool's lowest to its
   highest, the pool's average a tick and the manager a dot. */
.style-block {
    min-width: 0;
    margin-bottom: 1.5rem;
}

.style-block h4 {
    margin: 1.1rem 0 0.5rem;
    font-size: 0.95rem;
}

.style-kind {
    margin: 0 0 0.4rem;
    font-weight: 600;
}

.style-label {
    display: inline-block;
    margin: 0 0 0.9rem;
    padding: 0.45rem 0.8rem;
    border: 1px solid var(--border);
    border-radius: 8px;
    background: var(--raised);
    font-weight: 700;
    letter-spacing: 0.03em;
    text-transform: uppercase;
}

.style-row {
    margin-bottom: 0.9rem;
}

.style-name {
    display: flex;
    justify-content: space-between;
    font-size: 0.9rem;
}

.style-track {
    position: relative;
    height: 6px;
    margin: 0.45rem 0.4rem 0.35rem;
    border-radius: 3px;
    background: var(--border);
}

.style-dot,
.style-pool {
    position: absolute;
    top: 50%;
    transform: translate(-50%, -50%);
}

.style-dot {
    width: 14px;
    height: 14px;
    border-radius: 50%;
    background: var(--accent);
    box-shadow: 0 0 0 3px var(--card);
}

.style-pool {
    width: 2px;
    height: 16px;
    background: var(--muted);
}

.style-ends {
    display: flex;
    justify-content: space-between;
    gap: 0.5rem;
    font-size: 0.75rem;
    color: var(--muted);
}

.style-ends > :last-child {
    text-align: right;
}

.style-note {
    font-size: 0.82rem;
}

.style-loyalties {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: 0.3rem 1rem;
    margin: 0;
    font-size: 0.9rem;
}

.style-loyalties dt {
    color: var(--muted);
}

.style-loyalties dd {
    margin: 0;
}

/* The League page's pick-styles chart. */
.styles-title {
    margin-top: 2.5rem;
}

/* Never shrunk past legible on a phone: it scrolls in its box instead. */
.style-chart {
    overflow-x: auto;
}

.style-chart svg {
    display: block;
    width: 100%;
    min-width: 560px;
    max-width: 760px;
    height: auto;
}

.style-chart .axis {
    stroke: var(--border);
    stroke-width: 1.5;
}

.style-chart .pool-line {
    stroke: var(--muted);
    stroke-width: 1;
    stroke-dasharray: 4 4;
    opacity: 0.6;
}

.style-chart .pool-text,
.style-chart .axis-text {
    fill: var(--muted);
    font-size: 12px;
}

.style-chart .dot {
    fill: var(--accent);
    stroke: var(--card);
    stroke-width: 2;
}

.style-chart .dot-stacker {
    stroke: var(--warn);
    stroke-width: 2.5;
}

.style-chart .dot-name {
    fill: var(--text);
    font-size: 12px;
}

.style-chart a:hover .dot {
    fill: var(--pos);
}

.style-chart a:hover .dot-name {
    text-decoration: underline;
}

.swatch-dot {
    display: inline-block;
    width: 11px;
    height: 11px;
    border-radius: 50%;
    background: var(--accent);
    vertical-align: middle;
    margin-right: 0.3rem;
}

.swatch-dot-stacker {
    box-shadow: 0 0 0 2px var(--warn);
}

/* A season's last recap: the champion first, with every title of its kind. */
.recap-finale {
    margin: 0 0 1.25rem;
    padding: 1rem 1.1rem;
    border: 1px solid var(--border);
    border-left: 3px solid var(--warn);
    border-radius: 10px;
    background: var(--raised);
}

.recap-finale h3 {
    margin-top: 0;
}

.recap-titles {
    width: auto;
}

.recap-prize {
    margin: 0 0 0.6rem;
}

/* ---- Drawn charts (Charts.java): the standings over time, a manager's finishes, a player's
   nights. SVG in its own units, scaled to the column; a wide one scrolls in its box on a phone. */
.chart {
    display: block;
    width: 100%;
    height: auto;
}

.chart-scroll {
    overflow-x: auto;
}

.chart-scroll .chart {
    min-width: 640px;
}

.chart text {
    fill: var(--muted);
    font-size: 11px;
}

.chart-note {
    margin: -0.3rem 0 0.6rem;
    font-size: 0.85rem;
}

.chart-sub {
    margin: 0 0 0.4rem;
    font-size: 0.75rem;
    color: var(--muted);
    text-transform: uppercase;
    letter-spacing: 0.05em;
}

.chart .grid-line {
    stroke: var(--border);
}

.chart .zero-line {
    stroke: var(--muted);
    stroke-opacity: 0.5;
}

/* Standings over time: grey lines, the top three in colour, any line picked out on hover. */
.bump-line path {
    fill: none;
    stroke: var(--muted);
    stroke-opacity: 0.3;
    stroke-width: 1.5;
}

.bump-line circle {
    fill: var(--muted);
    fill-opacity: 0.6;
}

.bump-line.tone-gold path { stroke: var(--warn); }
.bump-line.tone-accent path { stroke: var(--accent); }
.bump-line.tone-pos path { stroke: var(--pos); }
.bump-line.tone-gold circle { fill: var(--warn); }
.bump-line.tone-accent circle { fill: var(--accent); }
.bump-line.tone-pos circle { fill: var(--pos); }

.bump-line.tone-gold path,
.bump-line.tone-accent path,
.bump-line.tone-pos path {
    stroke-opacity: 1;
    stroke-width: 2.5;
}

.chart .bump-line.tone-gold text,
.chart .bump-line.tone-accent text,
.chart .bump-line.tone-pos text {
    fill: var(--text);
}

.bump-line:hover path {
    stroke: var(--text);
    stroke-opacity: 1;
    stroke-width: 3;
}

.chart .bump-line:hover text {
    fill: var(--text);
}

/* A manager's finishes and scores. */
.chart .bar.tone-gold { fill: var(--warn); }
.chart .bar.tone-pos { fill: var(--pos); }
.chart .bar.tone-accent { fill: var(--accent); }

.spark-gap {
    fill: var(--neg);
    fill-opacity: 0.14;
}

.spark-top {
    fill: none;
    stroke: var(--muted);
    stroke-width: 1.5;
    stroke-dasharray: 4 3;
}

.spark-mine {
    fill: none;
    stroke: var(--accent);
    stroke-width: 2;
}

.spark-dot { fill: var(--accent); }
.spark-win { fill: var(--warn); }

.chart-key {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.3rem 0.5rem;
    margin: 0.3rem 0 0;
    font-size: 0.78rem;
    color: var(--muted);
}

.chart-key span {
    display: inline-block;
    width: 14px;
    height: 0;
    margin-left: 0.4rem;
    border-top: 2px solid var(--accent);
}

.chart-key .key-top { border-top: 2px dashed var(--muted); }

.chart-key .key-win {
    width: 9px;
    height: 9px;
    border: none;
    border-radius: 50%;
    background: var(--warn);
}

/* A player's nights. */
.chart .night-bar { fill: var(--accent); }
.chart .po-ground { fill: var(--warn); fill-opacity: 0.07; }

.chart .season-line {
    stroke: var(--muted);
    stroke-opacity: 0.4;
    stroke-dasharray: 2 4;
}

.chart text.po-label { fill: var(--warn); }

/* Every manager, every season: medals for the podium, a shaded place below it. */
.franchise td.fcell,
.franchise th.head-wrap {
    text-align: center;
}

.medal {
    display: inline-grid;
    place-items: center;
    width: 24px;
    height: 24px;
    border-radius: 50%;
    font-size: 0.75rem;
    font-weight: 700;
    color: #10151f;
}

.medal-1 { background: var(--warn); }
.medal-2 { background: var(--silver); }
.medal-3 { background: var(--bronze); }

.fplace {
    display: inline-block;
    min-width: 26px;
    padding: 1px 0;
    border-radius: 5px;
    font-size: 0.82rem;
    text-align: center;
}

.franchise .live {
    outline: 1px dashed var(--muted);
    outline-offset: 2px;
}

.franchise .absent {
    color: var(--muted);
    opacity: 0.5;
}

/* The score chart's seasons: a chip each, the one shown filled. */
.season-chips {
    display: flex;
    flex-wrap: wrap;
    gap: 0.35rem;
    margin: 0 0 0.5rem;
}

.season-chip {
    padding: 0.15rem 0.6rem;
    border: 1px solid var(--border);
    border-radius: 999px;
    color: var(--muted);
    font-size: 0.78rem;
    text-decoration: none;
}

.season-chip:hover {
    color: var(--text);
    border-color: var(--muted);
}

.season-chip-on,
.season-chip-on:hover {
    background: var(--accent);
    border-color: var(--accent);
    color: #fff;
}

/* The 404 page (public/error/404.html). */
.not-found {
    max-width: 36rem;
}

.not-found-links {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem 1.2rem;
}

/* A manager's award on the awards page: the recap's award card, without a headshot column. */
.recap-award.award-plain {
    grid-template-columns: 1fr;
}

/* The player page's two tabs, pool nights and game log. */
.page-tabs {
    margin: 0.5rem 0 1rem;
}

/* A player's game log: a pool night's row stands out a little. */
.game-log tr.pool-night td {
    background: color-mix(in srgb, var(--warn) 7%, transparent);
}

/* The admin page's returning-managers checklist: two columns, a line each. */
.entrant-picks {
    list-style: none;
    padding: 0;
    margin: 0.6rem 0;
    columns: 2 16rem;
    column-gap: 1.5rem;
}

.entrant-picks li {
    break-inside: avoid;
    padding: 0.15rem 0;
}

.entrant-picks label {
    margin-left: 0.35rem;
}

.entrant-pick-actions {
    display: flex;
    gap: 0.5rem;
    align-items: center;
}
