/* ═══════════════════════════════════════════════════════════════════════════
   THE GRAND SLAM PAGE — shared by the US Open and Wimbledon.

   Billy, 2026-09-12: "update the wimbledon page to match us open choices."
   The two were separate pages that had drifted a long way apart: Wimbledon
   still had segmented button groups (the house rule in styles.css says never),
   a full-width bracket with no lines in it, an archetype column, and none of
   the switch, the final four or the scorecard.

   They are the same object — a 128 draw, two tours, a projected bracket and a
   live one — so they are one page now. What stays per-event is the HEAD of each
   shell: title, description, canonical and og: tags are the one thing that
   genuinely differs, and serving one file at both URLs would have handed
   Wimbledon the US Open's canonical link.
   ═══════════════════════════════════════════════════════════════════════════ */
  /* ── 2026-08-29 · the broadsheet head ─────────────────────────────────
     The page used to open on a bracket frame 2,288px wide whether or not a
     draw existed, with a status line that said "loading projection…" forever
     because the thing it waited on could not arrive until the draw was made.
     It now opens on words, and the draw section is created only when there is
     a draw to put in it. */
  /* head, section heads, tabs and empty states now live in styles.css as
     .page-* so this page and tennis-live cannot drift apart. */

  /* tabs, in the sub-nav manner the rest of the site uses. Replaces a pair of
     segmented button groups that read as a control panel. */
  /* Before the draw both fields are on screen at once, so on a wide screen the
     men/women switch would only pick which of two visible things is "current".
     The phone stacks to one field at a time and genuinely needs it. */
  @media (min-width: 780px) { .page-tabs.fields-mode { display: none; } }
  .uo-tab-sep { color: var(--text-faint); font-size: 13px; }

  /* ── the field / the draw, as one heading ─────────────────────────────
     Built from .page-sec-head so the row it replaces is the row it sits in:
     same baseline, same rule, same quiet note on the right. The active view
     takes the heading color and the gold underline; the other waits beside it
     at the same size, which is what makes it read as the alternative rather
     than as a button. `.one` is the case where only one half exists — the
     unbuilt half is hidden and what is left is simply a title. */
  .uo-panehead {
    display: flex; align-items: baseline; justify-content: space-between; gap: 12px;
    border-bottom: 1px solid var(--border); padding: 0 3px 9px; margin: 30px 0 14px;
  }
  .uo-panehead > span { font-size: 12.5px; font-weight: 600; color: var(--text-tertiary); }
  .uo-panes { display: flex; align-items: baseline; gap: 22px; flex-wrap: wrap; min-width: 0; }
  .uo-pane {
    font-family: var(--font-display); font-weight: 400; font-size: 26px; letter-spacing: -.01em;
    color: var(--text-faint); background: none; border: 0; cursor: pointer;
    padding: 0 0 9px; margin-bottom: -9px; border-bottom: 2px solid transparent;
    transition: color .12s, border-color .12s;
  }
  .uo-pane:hover { color: var(--text-secondary); }
  .uo-pane.on { color: var(--text-primary); border-bottom-color: var(--gold); }
  .uo-panehead.one .uo-pane { cursor: default; border-bottom-color: transparent; }
  /* The switch is the section head, so the section beneath it must not add a
     second gap of its own. */
  .uo-pane-sec { margin-top: 0; }
  .uo-pane-sec + .uo-pane-sec { margin-top: 30px; }
  @media (max-width: 780px) {
    .uo-pane { font-size: 22px; }
    .uo-panes { gap: 16px; }
  }

  /* ── the field, both tours facing ─────────────────────────────────── */
  .uo-facing { display: grid; grid-template-columns: 1fr 1fr; gap: 34px; }
  .uo-facing > * { min-width: 0; }
  .uo-facing-lab { font-size: 12.5px; font-weight: 600; letter-spacing: .07em; text-transform: uppercase;
                   color: var(--gold); margin: 0 0 10px; }
  .uo-fieldrow { display: grid; grid-template-columns: 24px 1fr auto; gap: 10px; align-items: baseline;
                 padding: 7px 0; border-bottom: 1px solid var(--border-dashed); }
  .uo-fieldrow:last-child { border-bottom: 0; }
  .uo-fieldrow .r { font-size: 12px; color: var(--text-faint); font-variant-numeric: tabular-nums; }
  .uo-fieldrow .n { font-family: var(--font-display); font-weight: 400; font-size: 16px; color: var(--text-primary);
                    overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .uo-fieldrow .v { font-size: 13px; font-weight: 600; color: var(--text-secondary); font-variant-numeric: tabular-nums; }
  .uo-fieldrow .d { font-size: 11.5px; color: var(--text-faint); font-variant-numeric: tabular-nums; margin-left: 6px; }

  /* ── D2 · title odds ──────────────────────────────────────────────── */
  .tw { overflow-x: auto; }
  #odds-table th.rankcol, #odds-table td.rankcol { width: 34px; color: var(--text-faint); }
  #odds-table td.shot { font-variant-numeric: tabular-nums; }
  #odds-table caption { caption-side: bottom; text-align: left; font-size: 12.5px;
                        color: var(--text-faint); padding-top: 10px; }
  /* a player's name goes to their card, on every tennis page */
  .plink { color: inherit; text-decoration: none; border-bottom: 1px solid transparent; }
  .plink:hover, .plink:focus { color: var(--gold); border-bottom-color: var(--gold); }
  .uo-odds { margin-top: 2px; }
  .uo-oddsrow { display: grid; grid-template-columns: 30px 1fr 110px 62px; gap: 12px; align-items: baseline;
                padding: 9px 0; border-bottom: 1px solid var(--border-dashed); }
  .uo-oddsrow:last-child { border-bottom: 0; }
  .uo-oddsrow .sd { font-size: 12px; color: var(--text-faint); font-variant-numeric: tabular-nums; }
  .uo-oddsrow .nm { font-family: var(--font-display); font-weight: 400; font-size: 17px; color: var(--text-primary);
                    overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .uo-oddsbar { height: 5px; background: var(--bg-inset); border-radius: 3px; overflow: hidden; align-self: center; }
  .uo-oddsbar i { display: block; height: 100%; background: var(--gold); }
  .uo-oddsrow .pc { text-align: right; font-size: 14px; font-weight: 600; color: var(--text-primary);
                    font-variant-numeric: tabular-nums; }

  /* ── D3 · the sheet, one quarter at a time ────────────────────────── */
  /* The note used to sit in this section's own heading, which the switch now
     carries. It explains the quarter tabs, so it sits with them. */
  .uo-qrow { display: flex; align-items: baseline; justify-content: space-between;
             gap: 14px; flex-wrap: wrap; margin: 0 0 16px; }
  .uo-qnote { font-size: 12.5px; font-weight: 600; color: var(--text-tertiary); }
  .uo-sheetnote { font-size: 12.5px; color: var(--text-tertiary); margin: 14px 0 0; max-width: 76ch; line-height: 1.7; }
  .uo-sheetnote s { text-decoration-color: var(--danger-text); opacity: .7; }
  .uo-sheetnote i { font-style: normal; font-weight: 700; }
  .uo-sheetnote i:first-of-type { color: var(--success-text); }
  .uo-sheetnote i:last-of-type { color: var(--danger-text); }
  .uo-qtabs { display: flex; gap: 18px; align-items: baseline; flex-wrap: wrap; }
  .uo-qtab { font-size: 13px; font-weight: 600; color: var(--text-tertiary); cursor: pointer;
             background: none; border: 0; padding: 3px 0; border-bottom: 2px solid transparent;
             font-family: var(--font-sans); }
  .uo-qtab:hover { color: var(--gold); }
  .uo-qtab.on { color: var(--gold); border-bottom-color: var(--gold); }
  /* the sheet is genuinely wide; it scrolls inside its own box so the page never does */
  .uo-sheetwrap { overflow-x: auto; padding-bottom: 6px; }

  /* ── the sheet reads as a bracket ───────────────────────────────────────
     The alignment was already right and had been all along: equal-height ties
     spread with `space-around` over counts that halve land each one exactly on
     the midpoint of the two it comes from. Measured before touching it — round
     two sat 0px off its feeders on all eight ties. What was missing was any
     LINE saying so, and a reader cannot see an alignment they have to measure.

     The rows are pinned rather than left to flexbox now, because the elbows are
     drawn in CSS from the row pitch and that pitch has to be a number the
     stylesheet knows. A tie is a fixed box of two equal halves, so its height
     no longer depends on the font loading, and the pitch is height + gap. */
  /* Both brackets on this page — the quarter sheet and the final-four capstone
     — are the same object at two scales and share these. */
  .uo-sheet, .uo-ff {
    --tie-h: 70px; --tie-gap: 7px; --colgap: 22px;
    --pitch: calc(var(--tie-h) + var(--tie-gap));
    display: grid; column-gap: var(--colgap);
  }
  .uo-sheet { grid-template-columns: repeat(5, minmax(178px, 1fr)); min-width: 980px; }
  .uo-sheet > div, .uo-ff > div { display: flex; flex-direction: column; min-width: 0; }
  .uo-sheet-lab { font-size: 11px; font-weight: 600; letter-spacing: .07em; text-transform: uppercase;
                  color: var(--text-faint); margin: 0 0 9px; flex: 0 0 auto; }
  .uo-sheet-body {
    flex: 1; display: grid; align-content: start;
    grid-template-rows: repeat(var(--n1, 1), var(--tie-h)); row-gap: var(--tie-gap);
  }
  .uo-tie { position: relative; align-self: center; height: var(--tie-h); box-sizing: border-box;
            display: grid; grid-template-rows: 1fr 1fr;
            border: 1px solid var(--border-dashed); border-radius: 5px; cursor: pointer; }
  .uo-tie:hover { border-color: var(--gold); }
  .uo-tie > div { display: grid; grid-template-columns: 22px 1fr 42px; gap: 6px; padding: 0 9px;
                  font-size: 12.6px; align-items: center; min-width: 0; }
  .uo-tie > div:first-child { border-radius: 4px 4px 0 0; }
  .uo-tie > div:last-child { border-radius: 0 0 4px 4px; }
  .uo-tie > div + div { border-top: 1px solid var(--border-dashed); }

  /* The fork: two arms back to the ties this one comes from, and the bar that
     joins them. `--elbow` is the gap between those two feeders' centers, which
     is the row pitch of the column they sit in — handed to each tie by the
     renderer, which is the only place that knows how many rows a tie spans. */
  [data-elbow], [data-line] { position: relative; }
  [data-elbow]::before {
    content: ''; position: absolute; pointer-events: none;
    right: calc(100% + var(--colgap) / 2); width: calc(var(--colgap) / 2);
    top: 50%; height: var(--elbow); transform: translateY(-50%);
    border: 1px solid var(--border-dashed); border-left: 0;
    border-radius: 0 4px 4px 0;
  }
  [data-elbow]::after {
    content: ''; position: absolute; pointer-events: none;
    right: 100%; width: calc(var(--colgap) / 2); top: 50%;
    border-top: 1px solid var(--border-dashed);
  }
  /* The champion comes from ONE match, so it is joined by a line rather than a
     fork. A fork of zero height would have drawn a 2px smudge in the gap. */
  [data-line]::after {
    content: ''; position: absolute; pointer-events: none;
    right: 100%; width: var(--colgap); top: 50%;
    border-top: 1px solid var(--border-dashed);
  }
  .uo-tie .sd { font-size: 10.5px; color: var(--text-faint); font-variant-numeric: tabular-nums; }
  .uo-tie .nm { font-family: var(--font-display); font-weight: 400; font-size: 14px; color: var(--text-tertiary);
                overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .uo-tie .pr { text-align: right; font-size: 11.5px; color: var(--text-faint); font-variant-numeric: tabular-nums; }
  /* Already out of the tournament, and the chalk has not caught up. Struck
     rather than removed: the point of the projection view is what we said, so
     the wrong name has to stay legible beside the line through it. */
  .uo-tie .gone .nm, .uo-tie .gone .sd,
  .uo-ff-champ.gone .nm, .uo-ff-champ.gone .sd { text-decoration: line-through;
    text-decoration-color: var(--danger-text); text-decoration-thickness: 1px; opacity: .62; }
  .uo-tie .gone .pr, .uo-ff-champ.gone .pr { opacity: .45; }
  /* A champion who is out does not get the gold. The card still says what we
     projected — that is the point of this view — but it stops celebrating it. */
  .uo-ff-champ.gone { border-color: var(--border-dashed); background: none; }
  .uo-tie .won { background: var(--gold-tint); }
  .uo-tie .won .nm { color: var(--text-primary); }
  .uo-tie .won .pr { color: var(--gold); font-weight: 600; }
  .uo-tie .hit .pr::after { content: " \2713"; color: var(--success-text); }
  .uo-tie .miss .pr::after { content: " \2717"; color: var(--danger-text); }
  /* the Final Four capstone — the semis + final the quarter sheet cannot show */
  .uo-ffwrap { overflow-x: auto; padding-bottom: 6px; }
  .uo-ff { grid-template-columns: repeat(4, minmax(150px, 1fr)); min-width: 700px; }
  .uo-ff-champ { border: 1px solid var(--gold); border-radius: 5px; background: var(--gold-tint);
    display: grid; grid-template-columns: 22px 1fr auto; gap: 6px; align-items: center; padding: 8px 10px;
    align-self: center; }
  .uo-ff-champ .sd { font-size: 10.5px; color: var(--text-faint); font-variant-numeric: tabular-nums; }
  .uo-ff-champ .nm { font-family: var(--font-display); font-weight: 400; font-size: 15px; color: var(--text-primary); }
  .uo-ff-champ .pr small { display: block; font-size: 9.5px; font-weight: 600; letter-spacing: .06em;
    text-transform: uppercase; color: var(--text-faint); margin-top: 2px; }
  .uo-ff-champ .pr { text-align: right; font-size: 12px; font-weight: 600; color: var(--gold); font-variant-numeric: tabular-nums; }

  /* ── the scorecard ────────────────────────────────────────────────── */
  .uo-score { display: grid; grid-template-columns: repeat(3, 1fr);
              border-top: 1px solid var(--border); border-bottom: 1px solid var(--border); }
  .uo-score > div { padding: 14px 16px; border-right: 1px solid var(--border-dashed); }
  .uo-score > div:last-child { border-right: 0; }
  .uo-score .k { font-size: 11.5px; font-weight: 600; letter-spacing: .07em; text-transform: uppercase;
                 color: var(--text-tertiary); margin: 0; }
  .uo-score .v { font-family: var(--font-display); font-weight: 400; font-size: 30px; color: var(--gold);
                 line-height: 1.15; margin: 4px 0 0; }
  .uo-score .w { font-size: 13px; color: var(--text-tertiary); margin: 2px 0 0; }
  /* .state-msg is right-aligned mono, which read as a stray note pinned to the
     far edge of an empty table. An empty state is a sentence, set like one. */

  /* phone: one field at a time, chosen by the switch above */
  @media (max-width: 779.98px) {
    .uo-facing > [data-tour] { display: none; }
    .uo-facing[data-show="m"] > [data-tour="m"],
    .uo-facing[data-show="w"] > [data-tour="w"] { display: block; }
  }
  @media (max-width: 780px) {
    .uo-facing { grid-template-columns: 1fr; gap: 26px; }
    .uo-score { grid-template-columns: 1fr; }
    .uo-score > div { border-right: 0; border-bottom: 1px solid var(--border-dashed); }
  }

  .state-msg { color: var(--text-tertiary); font-family: var(--font-mono); font-size: 12px; padding: 24px; text-align: center; }

  /* matchup popout */
  .ko-modal-bg { position: fixed; inset: 0; background: rgba(0,0,0,.55); z-index: 200; display: none; align-items: center; justify-content: center; padding: 20px; }
  .ko-modal-bg.show { display: flex; }
  .ko-modal { background: var(--bg-card); border: 1px solid var(--border); border-radius: var(--radius-card); max-width: 520px; width: 100%; padding: 22px 24px; position: relative; }
  .ko-modal .close { position: absolute; top: 12px; right: 14px; background: none; border: none; color: var(--text-tertiary); font-size: 20px; cursor: pointer; }
  .ko-modal h3 { font-family: var(--font-display); font-size: 17px; margin: 0 0 2px; color: var(--text-primary); }
  .ko-modal .sub { font-family: var(--font-mono); font-size: 10.5px; color: var(--text-tertiary); margin-bottom: 12px; }
  .ko-mr-bar { display: flex; height: 30px; border-radius: 7px; overflow: hidden; border: 1px solid var(--border); margin: 4px 0 12px; }
  .ko-mr-a { background: var(--gold); color: var(--on-gold); display: flex; align-items: center; padding: 0 10px; font-weight: 600; white-space: nowrap; font-family: var(--font-mono); font-size: 12px; }
  .ko-mr-b { background: var(--bg-raised); color: var(--text-secondary); display: flex; align-items: center; justify-content: flex-end; padding: 0 10px; font-weight: 600; white-space: nowrap; flex: 1; font-family: var(--font-mono); font-size: 12px; }
  .ko-md { display: flex; gap: 26px; flex-wrap: wrap; }
  .ko-md-col { min-width: 180px; flex: 1; }
  .ko-md-h { font-family: var(--font-button); font-size: 9.5px; letter-spacing: .5px; text-transform: uppercase; color: var(--text-tertiary); margin-bottom: 6px; }
  .ko-md-row { display: flex; justify-content: space-between; gap: 14px; font-family: var(--font-mono); font-size: 12px; padding: 3px 0; border-bottom: 1px dashed var(--border-dashed); }
  .ko-md-row:last-child { border-bottom: none; }
  .ko-md-k { color: var(--text-secondary); }
  .ko-md-v { color: var(--gold); font-weight: 600; }
  .ko-modal .foot { font-size: 12px; color: var(--text-tertiary); margin-top: 12px; }

  /* prose, so the body face — a typewriter face is for keys and numbers */
  /* Pre-draw favorites panel (shown until the main draw is released). Reuses the
     page tokens; a functional first pass — Billy owns the tennis look. */
