/*
 * The match card, shared by the player profile and /biewbad/matches.
 *
 * Self-contained: the colour tokens are declared on the card itself rather
 * than inherited from a page wrapper, so it renders the same wherever it is
 * dropped. The profile declares the same names on .pf for the rest of its
 * layout in its own light values; because the card redeclares every token it
 * uses, nesting one inside the other is still harmless.
 */

/*
 * Dark, following the board at /biewbad/main rather than inventing a second
 * dark palette — same canvas, same hues, same red. The board is the newest
 * design in the project, so the card moving to it closes a little of the gap
 * flagged in CLAUDE.md rather than widening it.
 *
 * The panel and border are lighter than the board's own #14181f/#222833
 * though: those are mixed to sit quietly *within* a dark page, and a card that
 * has to read as a raised object on that page needs more separation than a
 * stat tile does. See the notes on --surface and --line below.
 *
 * Every root this file styles has to declare the tokens itself. The score
 * dialog in particular is appended to <body>, so it sits outside .pf-match and
 * .pf entirely — leaving it off this list made its var() references resolve to
 * nothing, which turned the save button into white-on-white.
 */
.pf-match,
.pf-matches,
.pf-loading,
.pf-none,
.pf-score {
    /*
     * --band stays the site red for anything it *fills*, where white type sits
     * on top of it and the contrast is the other way round. As type on the
     * panel it only reaches 3.77:1, so --accent is the lifted version used
     * wherever the red is the text or the mark rather than the background.
     */
    --band: #e02424;
    --accent: #ff5c5c;
    /*
     * Lifted well clear of the #0b0d10 canvas. The board's own #14181f panel
     * sits at 1.06:1 against it — near enough to read as one flat surface with
     * a seam, which is exactly what a card should not do. This is 1.28:1, and
     * the border below carries the rest of the separation.
     */
    --surface: #1e2632;
    /* One step up again, for anything inset on the card. */
    --raised: #283143;
    --ink: #e8edf5;
    /* Both grey tiers were mixed for the darker #14181f surface; lifting the
     * panel cost them contrast, and --faint fell under AA at 4.36. Raised
     * together so they stay visibly two tiers: 6.1:1 and 5.0:1. */
    --muted: #9aa4b5;
    --faint: #8894a6;
    /*
     * The edge is what actually separates a card from the canvas, so it is a
     * visible line rather than the barely-there #222833 the board uses on its
     * darker panels — that was 1.05:1 against the surface it bounded.
     */
    --line: #38445a;
    /* Interior rules (the meta underline, the results divider) sit back from
     * the card's own edge, or every card looks like a table. */
    --rule: #2a3446;
    --wash: #283143;

    /*
     * The status colours are lifted from the board's light-card values, which
     * are mixed for white behind them and go muddy on #14181f. Same hues,
     * enough lightness to clear the surface.
     */
    --win: #35c97e;
    --loss: #f5827b;
    --gold: #f5c542;
    --info: #5aa9e6;
}

/*
 * The canvas behind the cards, so dark panels do not sit on a white sheet.
 *
 * Same colour and the same :has() approach board.css uses for /biewbad/main —
 * and the colour is repeated literally for the same reason it is there: custom
 * properties inherit downwards only, so an ancestor selector cannot read a
 * --token declared on the card.
 */
html:has(.pf-matches),
body:has(.pf-matches) {
    background: #0b0d10;
}

/*
 * Two cards abreast. Each card is a self-contained block, so the pair reads as
 * a board rather than a list — and the row layout inside means a half-width
 * card still has room for everything.
 *
 * align-items: start keeps a short card short instead of stretching it to its
 * neighbour's height, which left the tinted side floating in dead space.
 */
.pf-matches {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    align-items: start;
    gap: 10px;
    margin-top: 4px;
}

/* States are messages about the whole list, not one column of it. */
.pf-matches > .pf-loading,
.pf-matches > .pf-none {
    grid-column: 1 / -1;
}

/*
 * Kept tight on purpose: players screenshot a single match to share it, so the
 * card should crop cleanly without a screen's worth of padding around it.
 */
.pf-match {
    padding: 8px 12px 10px;
    border: 1px solid var(--line);
    border-radius: 10px;
    background: var(--surface);
    color: var(--ink);
    /* A real lift, so a single match crops as a discrete object when shared and
     * sits above the canvas rather than in it. Cast darker than the surface
     * rather than the near-white it was: a pale shadow on a dark panel reads
     * as a glow. */
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.55);
}

/* Cards are spaced by the grid gap now; a margin here would double it. */

/* ---------- Meta strip: position, id, when, status ---------- */

.pf-match__meta {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 4px 10px;
    padding-bottom: 6px;
    border-bottom: 1px solid var(--rule);
    font-size: 11.5px;
    color: var(--muted);
}

.pf-match__no {
    font-size: 14px;
    font-weight: 800;
    color: var(--ink);
}

.pf-match__id { color: var(--faint); }

.pf-match__status { margin-left: auto; font-weight: 700; }

.pf-match__status.is-done    { color: var(--win); }
.pf-match__status.is-live    { color: var(--info); }
.pf-match__status.is-waiting { color: var(--accent); }

.pf-fact { display: inline-flex; align-items: center; gap: 5px; }
.pf-fact b { font-weight: 800; color: var(--ink); }

.pf-shuttles { display: inline-flex; gap: 2px; color: var(--gold); font-size: 7px; }

/* ---------- Strength comparisons ---------- */

/*
 * The three comparisons always share one row — three equal columns rather than
 * a wrapping flex line, so they stay side by side down to the narrowest phone.
 */
.pf-match__facts {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 8px;
    padding: 6px 0 5px;
    line-height: 1.35;
    font-size: 12px;
    color: var(--muted);
}

/* Label over its values, which is what lets three fit across. */
.pf-vs {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 1px;
    min-width: 0;
    text-align: center;
}

.pf-vs__values {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    min-width: 0;
}

.pf-vs__label {
    font-size: 10.5px;
    color: var(--muted);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 100%;
}

.pf-vs__side {
    font-weight: 700;
    color: var(--ink);
    font-variant-numeric: tabular-nums;
}

/* The stronger of the two, so the eye lands on it before counting arrows. */
.pf-vs__side.is-lead { font-weight: 800; }

.pf-vs--level .pf-vs__side.is-lead { color: var(--info); }
.pf-vs--score .pf-vs__side.is-lead { color: var(--accent); }

/*
 * One caret per 1000 points of difference, pointing at the stronger side so
 * the row reads like a "<" or ">" comparison.
 */
.pf-vs__arrows {
    display: inline-flex;
    gap: 1px;
    font-size: 9px;
    line-height: 1;
}

.pf-vs--level .pf-vs__arrows { color: var(--info); }
.pf-vs--score .pf-vs__arrows { color: var(--accent); }

/* Evenly matched: no direction to point in. */
.pf-vs__even { font-size: 11px; color: var(--muted); }

.pf-vs__sep { font-size: 11px; color: var(--muted); }

/* ---------- Gained performance ---------- */

.pf-gain { font-weight: 800; font-variant-numeric: tabular-nums; }

.pf-gain.is-up   { color: var(--win); }
.pf-gain.is-down { color: var(--loss); }
.pf-gain.is-flat { color: var(--muted); }

.pf-vs__side.is-pending { font-weight: 600; color: var(--faint); }

/* ---------- Teams ---------- */

/*
 * One team left, the other right — at every width. The sides never stack: a
 * team that drops below its opponent stops reading as "against" and you lose
 * track of which pair is which.
 *
 * minmax(0, 1fr) rather than 1fr, or a long name would set the column's
 * min-content width and push the card wider than its container.
 *
 * The results row below uses this same template, which is what keeps each
 * outcome under the team it belongs to.
 */
/*
 * Top-aligned so all four portraits sit on one line. Centring instead would
 * offset a side whose name wrapped, leaving the teams' portraits at different
 * heights.
 *
 * The gap is wide enough to be a channel rather than a seam: the VS mark sits
 * in it, out of flow, so the two sides stay equal columns.
 */
.pf-match__teams {
    position: relative;
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: 30px;
    align-items: start;
    padding-top: 2px;
}

/*
 * The mark between opponents, on the portraits' centre line rather than the
 * row's — the portraits are the anchor, and a row centre would drift downward
 * whenever one side's names wrapped to a second line.
 *
 * The offset is the side's own padding plus half a portrait.
 */
.pf-match__vs {
    position: absolute;
    left: 50%;
    top: calc(2px + 5px + clamp(48px, 6.5vw, 68px) / 2);
    transform: translate(-50%, -50%);
    display: flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 26px;
    border-radius: 50%;
    background: var(--raised);
    border: 1px solid var(--line);
    font-size: 9.5px;
    font-weight: 800;
    letter-spacing: 0.04em;
    color: var(--muted);
}

/* A side is its two players abreast, each a portrait above their own name. */
.pf-match__side {
    min-width: 0;
    padding: 5px 7px;
}

.pf-match__pair {
    display: flex;
    flex-direction: row;
    justify-content: center;
    gap: 8px;
    min-width: 0;
}

/* ---------- The result row ---------- */

/*
 * Its own band beneath the teams rather than sitting inside them, so the
 * portraits and names have the full column width to themselves.
 *
 * Each outcome sits over the team it describes, with the games centred between
 * them: the two outer columns take the slack so the score line stays on the
 * card's centre line whatever the words either side of it are.
 */
/*
 * The same two columns and the same channel as the teams above, so each
 * outcome lands directly under the team it describes — within a pixel or two,
 * rather than the 20-odd it drifted when the score line held a column of its
 * own and pushed the words outward.
 */
.pf-match__results {
    position: relative;
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    align-items: center;
    gap: 30px;
    margin-top: 6px;
    padding-top: 6px;
    border-top: 1px solid var(--rule);
}

/*
 * The word, in place of the trophy and cross icons that were here before.
 * Sized off the longest of the three (เสมอ) so both halves stay symmetrical
 * whatever the outcome.
 */
.pf-match__outcome {
    flex: 0 0 auto;
    min-width: 34px;
    font-size: 13px;
    font-weight: 800;
    line-height: 1;
    text-align: center;
    white-space: nowrap;
}

/* Sits directly under the winning team, so the tick marks that side without
 * needing any chrome drawn around it. */
.pf-match__outcome.is-won  { color: var(--win); }
.pf-match__outcome.is-draw { color: var(--gold); }

/* Small on purpose: a mark beside the word, not a badge of its own. */
.pf-match__tick {
    margin-right: 3px;
    font-size: 14px;
    line-height: 1;
    vertical-align: -2px;
}

/* The loser is stated plainly rather than in red: the winner should be what
 * the eye lands on, and both halves shouting cancels out. */
.pf-match__outcome.is-lost { color: var(--muted); font-weight: 600; }

/* No recorded result — holds the space so the two halves stay symmetrical. */
.pf-match__outcome.is-empty { visibility: hidden; }

/* ---------- Game scores ---------- */

/*
 * The games as one line — "21-10, 10-21" — left team's number first in each,
 * matching the team on the left of the card above.
 */
/*
 * Centred in the card, out of the grid flow — which is what lets the two
 * outcome words keep the teams' own column centres. It sits directly below the
 * VS mark, on the card's centre line.
 */
.pf-match__scoreline {
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    font-size: 14px;
    font-weight: 600;
    line-height: 1.3;
    color: var(--muted);
    font-variant-numeric: tabular-nums;
    text-align: center;
    white-space: nowrap;
}

/* The winner of an individual game, which is not always the winner of the
 * match — a side can take a game and still lose. */
.pf-match__scoreline b { color: var(--ink); font-weight: 800; }

/*
 * Who won is carried by the tick, the bolder name and the word below — not by
 * a tinted, bordered panel around the side. Three filled boxes per card, in
 * green or yellow or grey, drowned out the portraits they were meant to frame.
 *
 * The losing side just sits back a shade so the winner still carries the
 * weight; its portraits are left at full strength, since dimming a photograph
 * reads as a loading state rather than a result.
 */
.pf-match__side.is-lost .pf-match__player { color: var(--muted); }

.pf-match__player {
    flex: 1 1 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 5px;
    min-width: 0;
    font-size: 13px;
    line-height: 1.25;
    color: var(--ink);
    text-decoration: none;
    text-align: center;
}

.pf-match__player:hover { color: var(--accent); }

/*
 * Larger than before. Moving the outcome and the scores out to their own row
 * freed the height, so the portraits can grow without pushing the card taller.
 */
.pf-match__avatar {
    flex: 0 0 auto;
    width: clamp(48px, 6.5vw, 68px);
    height: clamp(48px, 6.5vw, 68px);
    border-radius: 50%;
    object-fit: cover;
    object-position: top center;
    background: var(--raised);
    /* The ring separates a portrait from the panel behind it, so it follows
     * the surface rather than staying white — a white ring on a dark card
     * outlined every face like a sticker. */
    border: 2px solid var(--surface);
    box-shadow: 0 0 0 1px var(--rule);
}

/*
 * Two names per column and four across the card: an ellipsis on one line hides
 * more than it saves here, so they wrap to two and are capped there, which
 * stops a long name stretching the row.
 */
.pf-match__label {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    width: 100%;
    min-width: 0;
    overflow: hidden;
    overflow-wrap: anywhere;
}

.pf-match__level {
    font-size: 11px;
    font-weight: 700;
    color: var(--muted);
}

/* The winning side carries the weight — the plainest way to say who won, and
 * what replaces the badge icons. */
.pf-match__side.is-won .pf-match__player { font-weight: 800; }
.pf-match__side.is-draw .pf-match__player { font-weight: 700; }

/* The subject's own name, so their side is findable at a glance. Underlined
 * rather than bolded now that weight means "won". */
.pf-match__player--self {
    text-decoration: underline;
    text-underline-offset: 3px;
    text-decoration-thickness: 2px;
    text-decoration-color: var(--accent);
}

.pf-match__avatar.is-self { box-shadow: 0 0 0 2px var(--accent); }

/* ---------- Foot: shuttles and game scores ---------- */

.pf-match__foot {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 4px 14px;
    margin-top: 6px;
    padding-top: 5px;
    border-top: 1px dashed var(--rule);
    font-size: 11.5px;
    color: var(--muted);
}

.pf-match__scores {
    font-size: 13px;
    letter-spacing: 0.02em;
}

.pf-match__scores-label { margin-right: 6px; color: var(--muted); }
.pf-match__scores b { font-weight: 800; color: var(--ink); }
.pf-match__scores-none { color: var(--faint); font-size: 12px; }

/* ---------- Recording scores ---------- */

.pf-match__record {
    margin-left: 8px;
    padding: 2px 9px;
    border: 1px solid var(--line);
    border-radius: 999px;
    background: var(--raised);
    font-size: 11.5px;
    font-weight: 700;
    color: var(--ink);
    cursor: pointer;
}

.pf-match__record:hover {
    border-color: var(--band);
    background: var(--band);
    color: #fff;
}

/*
 * The dialog is Bootstrap's, so its own light .modal-content has to be
 * overridden rather than merely left alone — otherwise the dark tokens below
 * paint pale text onto a white sheet.
 */
.pf-score .modal-content {
    border: 1px solid var(--line);
    border-radius: 12px;
    background: var(--surface);
    color: var(--ink);
}

.pf-score .modal-header,
.pf-score .modal-footer { border-color: var(--line); }

.pf-score .modal-title { font-weight: 800; color: var(--ink); }

/* Bootstrap's close button is a dark SVG; invert it to show on the panel. */
.pf-score .btn-close { filter: invert(1) grayscale(1) brightness(1.8); }

.pf-score__teams {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
    align-items: center;
    gap: 10px;
    padding-bottom: 12px;
    border-bottom: 1px solid var(--rule);
    text-align: center;
}

.pf-score__team { font-size: 13.5px; font-weight: 700; color: var(--ink); }

.pf-score__vs {
    padding: 3px 10px;
    border-radius: 999px;
    background: var(--wash);
    font-size: 12px;
    font-weight: 800;
    color: var(--muted);
}

/* Says plainly what this can and cannot change. */
.pf-score__note {
    margin: 12px 0 14px;
    padding: 9px 11px;
    border-radius: 8px;
    background: rgba(90, 169, 230, 0.10);
    border: 1px solid rgba(90, 169, 230, 0.22);
    font-size: 12.5px;
    line-height: 1.55;
    color: #bcd8ef;
}

.pf-score__row {
    display: grid;
    grid-template-columns: 1fr auto auto auto;
    align-items: center;
    gap: 10px;
}

.pf-score__row + .pf-score__row { margin-top: 8px; }

.pf-score__game { font-size: 13px; font-weight: 700; color: var(--ink); margin: 0; }
.pf-score__optional { font-weight: 400; color: var(--muted); }

.pf-score__input {
    width: 68px;
    padding: 7px 9px;
    border: 1px solid var(--line);
    border-radius: 8px;
    background: var(--raised);
    font-size: 15px;
    font-weight: 700;
    text-align: center;
    color: var(--ink);
}

.pf-score__input:focus-visible { outline: 2px solid var(--band); outline-offset: 1px; }

.pf-score__dash { color: var(--muted); font-weight: 700; }

.pf-score__error {
    margin-top: 12px;
    font-size: 13px;
    line-height: 1.5;
    color: var(--loss);
}

.pf-score__error:empty { margin-top: 0; }

.pf-score__cancel,
.pf-score__save {
    padding: 8px 18px;
    border-radius: 8px;
    font-size: 13.5px;
    font-weight: 700;
    cursor: pointer;
}

.pf-score__cancel { border: 1px solid var(--line); background: var(--raised); color: var(--ink); }
.pf-score__save   { border: 1px solid var(--band); background: var(--band); color: #fff; }
.pf-score__save[disabled] { opacity: 0.6; cursor: default; }

/* ---------- Empty and loading states ---------- */

.pf-loading, .pf-none {
    padding: 22px;
    border: 1px dashed var(--line);
    border-radius: 10px;
    background: var(--surface);
    color: var(--muted);
    text-align: center;
    font-size: 14px;
}

/* ---------- Narrow ---------- */

/*
 * Below this the grid drops to one column and each card gets the full width.
 *
 * The limit is the player column, not the card: a card splits into two teams
 * and each team into two players, so one card carries four name columns.
 *
 * 768px is where Bootstrap's .container stops being fluid and fixes at 720px,
 * which makes this breakpoint free: a card is 343px wide anywhere from 768px
 * up to 991px, so two-abreast at 768 is geometrically identical to two-abreast
 * at the 900 this used to sit at — 65px per player, and the same two names out
 * of 96 hitting the two-line cap either way.
 *
 * Going lower is not free. The container is fluid below 768, so at 600px the
 * card is 253px and the player column 51px against a 48px portrait — three
 * pixels of slack, and five names clipped. Two-abreast on a phone would leave
 * 31px per player, narrower than the portrait itself, which is why phones keep
 * one card per row and the teams stay left and right.
 *
 * .98 rather than a whole 767, following Bootstrap's own breakpoints: on a
 * fractional device pixel ratio the viewport lands on 767.x, where
 * `max-width: 767px` does not match but `max-width: 768px` does. Written as
 * 767 this rule left that sliver two-abreast at 43px per player, with 25 of
 * the 96 names on the page clipped.
 */
@media (max-width: 767.98px) {
    .pf-matches { grid-template-columns: minmax(0, 1fr); }
}

@media (max-width: 620px) {
    /* The row layout holds at every width — the space comes out of the gaps
     * and the type rather than out of the arrangement. */
    .pf-match { padding: 8px 8px 10px; }

    /* Still a channel, just a narrower one — the VS mark has to fit in it. */
    .pf-match__teams,
    .pf-match__results { gap: 24px; }

    .pf-match__vs { width: 22px; height: 22px; font-size: 8.5px; }

    .pf-match__side { padding: 5px 4px; }
    .pf-match__pair { gap: 5px; }

    .pf-match__player { font-size: 11.5px; }
    .pf-match__level { font-size: 10px; }

    .pf-match__outcome { min-width: 28px; font-size: 11.5px; }
    .pf-match__scoreline { font-size: 12.5px; }

    /* The status keeps its own line rather than being pushed off the end. */
    .pf-match__status { margin-left: 0; }

    /* The three stay abreast; only the type shrinks to make room. */
    .pf-match__facts { gap: 4px; padding: 6px 0 5px; }
    .pf-vs__label { font-size: 9.5px; }
    .pf-vs__values { gap: 3px; font-size: 11px; }
    .pf-vs__arrows { font-size: 8px; }

    .pf-match__foot { justify-content: flex-start; }
}
