/* TennisHub — light theme only. Clay dominates; a shiny blue seconds it.

   The file reads in the order of docs/system/ui.md:

     TOKENS       our colours, and the kit's semantic tokens pointed at them
     FOUNDATIONS  the reset and the page shell
     PRIMITIVES   everything a view composes from, under the chapter's
                  areas and in its order; inside a family the base comes
                  first and each variant after it
     PAGES        each page's own classes, in the menu's order; the UI
                  gallery's last

   A pattern a second page needs moves up into PRIMITIVES, and into the chapter, before that page uses it (tests/test_ui_lint.py). */

/* ======================================================================
   TOKENS
   ====================================================================== */

/* Ours. Nothing is painted with a literal colour outside this block (docs/system/ui.md#colors-and-tokens). */
:root {
  --clay: #b3541e;
  --clay-deep: #8f3f12;
  --clay-dark: #6f300c;
  --blue: #1f6fd6;
  --blue-bright: #3b8bff;
  --ink: #26221e;
  --muted: #7a726a;
  --paper: #faf6f1;
  --card: #ffffff;
  --line: #e8ddd2;
  /* Success and danger sit in the clay's own key (2026-09-05): a sunny leaf green and a crimson, each at the clay's saturation and depth. */
  --ok: #568a1f;
  --warn: #b02a37;
  --amber: #c9911a;

  /* The blue family's own shades, which the kit's tokens take under `.blue` and a few pieces paint with directly. */
  --blue-deep: #1657b0;
  --blue-fill: #dbe8fb;
  --blue-line: #a9c6ef;
  --blue-glow: rgba(31, 111, 214, 0.12);
  /* White as paint: what is written and drawn on a loud fill. A surface is `--card`. */
  --white: #fff;
  /* On the clay — the menu, the phone's header: its words, its links, its quiet foot, its faintest line. */
  --on-clay: #f7ece3;
  --on-clay-link: #f3ddcd;
  --on-clay-quiet: #e9c6ae;
  --on-clay-faint: #dcb08d;
  /* White laid thin over a loud ground: a hover, a pressed control, a ring. */
  --veil: rgba(255, 255, 255, 0.16);
  --veil-strong: rgba(255, 255, 255, 0.24);
  --veil-line: rgba(255, 255, 255, 0.5);
  /* Somebody worn (docs/system/accounts-and-roles.md): amber on the clay. */
  --worn: #ffd9a8;
  --worn-fill: rgba(255, 170, 60, 0.22);
  --worn-line: rgba(255, 190, 90, 0.65);
  /* Shadows, three depths. */
  --shade-soft: rgba(0, 0, 0, 0.1);
  --shade: rgba(0, 0, 0, 0.18);
  --shade-deep: rgba(0, 0, 0, 0.3);
  /* A rule that has to show on the paper. */
  --line-deep: #cdc3b4;
  /* The dashboard's tile themes (docs/system/dashboard.md): a fill a theme. */
  --tile-blue: #eaf2fc;
  --tile-clay: #f7ede1;
  --tile-green: #ebf3e6;
  /* The weather's statuses (docs/system/dashboard.md), a fill and its ink: drizzle wears the blue family's, heavy rain the blue itself. */
  --wx-perfect: #d9eccd;
  --wx-perfect-ink: #2e5d1f;
  --wx-rain: #c4ddf7;
  --wx-wind: #e4e0da;
  --wx-wind-ink: #4d463e;
  --wx-gusts: #9c948a;
  --wx-chilly: #e2ecf2;
  --wx-chilly-ink: #38607a;
  --wx-cold: #b7d3e4;
  --wx-cold-ink: #1f4a66;
  --wx-hot: #f8ddc0;
  --wx-xhot: #d9531e;

  /* Type (docs/system/ui.md#type). The kit's scale at our 0.9375 is 11, 12, 13, 15, 19, 24, 30, 38 and 48 px. Above the body size it steps by 1.125 twice; these are the steps between, by 1.125 once as the kit's own small ones are: 17, 21, 27, 34 and 43 px. Two more stand under its smallest, 10 and 9 px, for a figure in a ring. */
  --font-size-3xs: round(calc(var(--wa-font-size-2xs) / 1.125), 1px);
  --font-size-4xs: round(calc(var(--wa-font-size-2xs) / 1.125 / 1.125), 1px);
  --font-size-m-plus: round(calc(var(--wa-font-size-m) * 1.125), 1px);
  --font-size-l-plus: round(calc(var(--wa-font-size-l) * 1.125), 1px);
  --font-size-xl-plus: round(calc(var(--wa-font-size-xl) * 1.125), 1px);
  --font-size-2xl-plus: round(calc(var(--wa-font-size-2xl) * 1.125), 1px);
  --font-size-3xl-plus: round(calc(var(--wa-font-size-3xl) * 1.125), 1px);
  /* The duel card's percent, and nothing else. */
  --font-size-display: 4.6rem;
  /* The smallest a field's words may be on a phone before its browser zooms into the field. */
  --font-size-touch: 16px;
  /* Beside words of any size, as the kit's `--wa-font-size-smaller` is: two steps down and three. */
  --font-size-smaller-2: round(calc(1em / 1.125 / 1.125), 1px);
  --font-size-smaller-3: round(calc(1em / 1.125 / 1.125 / 1.125), 1px);
}

/* The kit wears our colours (docs/system/ui.md#theme): its semantic tokens point at the clay and the blue above; success, warning, danger and neutral carry the full set each, so a pill, a callout and a button in any of them draw only from ours. */
:root {
  --wa-font-family-body: system-ui, -apple-system, "Segoe UI", sans-serif;
  --wa-font-size-scale: 0.9375;          /* the kit's medium is our 15px */
  --wa-font-family-code: ui-monospace, SFMono-Regular, Menlo, monospace;
  --wa-color-text-link: var(--blue);
  --wa-color-text-normal: var(--ink);
  --wa-color-text-quiet: var(--muted);
  --wa-border-radius-m: 0.5rem;
  --wa-form-control-padding-block: 0.45rem;
  --wa-form-control-padding-inline: 0.6rem;
  --wa-color-focus: var(--blue);
  --wa-focus-ring-width: 2px;
  --blue-quiet: #eef4fd;                 /* the blue family's quiet fill */
  --wa-color-brand-fill-loud: var(--clay);
  --wa-color-brand-fill-normal: #f3e3d6;
  --wa-color-brand-fill-quiet: #fbf1ea;
  --wa-color-brand-border-loud: var(--clay);
  --wa-color-brand-border-normal: #dcb397;
  --wa-color-brand-border-quiet: #eed6c3;
  --wa-color-brand-on-loud: #fff;
  --wa-color-brand-on-normal: var(--clay-deep);
  --wa-color-brand-on-quiet: var(--clay);
  /* Success, warning, danger and neutral: the full set each, so a pill, a callout and a button in any of them draw only from ours (2026-09-05). */
  --wa-color-success-fill-loud: var(--ok);
  --wa-color-success-fill-normal: #e9f2df;
  --wa-color-success-fill-quiet: #f3f8ec;
  --wa-color-success-border-loud: var(--ok);
  --wa-color-success-border-normal: #b9d69a;
  --wa-color-success-border-quiet: #d9e8c7;
  --wa-color-success-on-loud: #fff;
  --wa-color-success-on-normal: #3f6a15;
  --wa-color-success-on-quiet: var(--ok);
  --wa-color-warning-fill-loud: var(--amber);
  --wa-color-warning-fill-normal: #f7ecd5;
  --wa-color-warning-fill-quiet: #fbf5e8;
  --wa-color-warning-border-loud: var(--amber);
  --wa-color-warning-border-normal: #e4c98a;
  --wa-color-warning-border-quiet: #efdfb9;
  --wa-color-warning-on-loud: #fff;
  --wa-color-warning-on-normal: #8a6210;
  --wa-color-warning-on-quiet: var(--amber);
  --wa-color-danger-fill-loud: var(--warn);
  --wa-color-danger-fill-normal: #f8e4e6;
  --wa-color-danger-fill-quiet: #fcf0f1;
  --wa-color-danger-border-loud: var(--warn);
  --wa-color-danger-border-normal: #e3a3aa;
  --wa-color-danger-border-quiet: #f0cbd0;
  --wa-color-danger-on-loud: #fff;
  --wa-color-danger-on-normal: #8c1f2a;
  --wa-color-danger-on-quiet: var(--warn);
  --wa-color-neutral-fill-loud: var(--muted);
  --wa-color-neutral-fill-normal: #efeae3;
  --wa-color-neutral-fill-quiet: #f5f1ec;
  --wa-color-neutral-border-loud: var(--muted);
  --wa-color-neutral-border-normal: var(--line);
  --wa-color-neutral-border-quiet: #f0e8df;
  --wa-color-neutral-on-loud: #fff;
  --wa-color-neutral-on-normal: var(--muted);
  --wa-color-neutral-on-quiet: var(--ink);
  --wa-color-surface-border: var(--line);
  --wa-color-surface-lowered: var(--paper);
  --wa-form-control-border-color: var(--line);
}
/* `.blue` on a kit component re-themes its brand family to the blue. */
.blue {
  --wa-color-brand-fill-loud: var(--blue);
  --wa-color-brand-fill-normal: var(--blue-fill);
  --wa-color-brand-fill-quiet: var(--blue-quiet);
  --wa-color-brand-border-loud: var(--blue);
  --wa-color-brand-border-normal: var(--blue-line);
  --wa-color-brand-border-quiet: #d5e3f8;
  --wa-color-brand-on-loud: #fff;
  --wa-color-brand-on-normal: var(--blue-deep);
  --wa-color-brand-on-quiet: var(--blue);
}

/* ======================================================================
   FOUNDATIONS
   ====================================================================== */

* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; min-height: 100%; }
body {
  font-family: var(--wa-font-family-body);
  background: var(--paper);
  color: var(--wa-color-text-normal);
  font-size: var(--wa-font-size-m);
}

/* Type (docs/system/ui.md#type). Three heading sizes a reader tells apart at a glance — 21, 18 and 15 px; the link and inline code on the kit's own tokens; and the quiet line every hint and description is built on. */
h1 { font-size: var(--font-size-l-plus); margin: 0 0 1rem; }
h2 { font-size: var(--wa-font-size-l); margin: 1.4rem 0 0.5rem; }
h3 { font-size: var(--wa-font-size-m); }
a { color: var(--wa-color-text-link); text-underline-offset: 0.125em; }
a:hover { color: color-mix(in oklab, var(--wa-color-text-link), var(--wa-color-mix-hover)); }
code { padding: 0.125em 0.25em; font-family: var(--wa-font-family-code);
  font-size: var(--wa-font-size-smaller); background: var(--wa-color-overlay-inline);
  border-radius: var(--wa-border-radius-s); }
/* Hint and description (docs/system/ui.md#hint-and-description): a quiet line. */
.meta { color: var(--wa-color-text-quiet); font-size: var(--wa-font-size-s); margin: 0.2rem 0 0.8rem; }

/* Utilities (docs/system/ui.md#utilities). The hidden attribute always hides: a class that sets display must not undo el.hidden. A cell or span that may wrap; a quiet line with no margin. */
[hidden] { display: none !important; }
.wrap { white-space: normal; }
.meta.tight { margin: 0; }

/* Page shell and menu (docs/system/ui.md#page-shell-and-menu): the kit's page. The sidebar is its navigation — the menu column, sticky and viewport-tall by the kit, on a desktop; the kit's drawer on a phone — and the header shows on a phone only, the brand beside the kit's toggle. The clay gradient sits on the menu part and on the nav itself, so the column and the drawer wear it alike. */
wa-page { --menu-width: 220px; }
wa-page[view="mobile"] { --menu-width: 0; }
wa-page::part(menu) { background: linear-gradient(175deg, var(--clay-deep), var(--clay-dark)); }
/* The drawer on a phone: no padding around the menu, the clay's dark behind it and the kit's close in white. */
wa-page::part(drawer) { --spacing: 0; --size: 260px;
  --wa-color-surface-default: var(--clay-dark); color: var(--white); }
.side {
  color: var(--on-clay); min-height: 100%; box-sizing: border-box;
  background: linear-gradient(175deg, var(--clay-deep), var(--clay-dark));
  padding: 1.2rem 0.9rem; display: flex; flex-direction: column; gap: 0.3rem;
}
wa-page::part(header) { background: var(--clay-deep); color: var(--white);
  padding: 0.35rem 0.8rem 0.35rem 0.4rem; }
wa-page[view="desktop"]::part(header) { display: none; }
/* The phone header's controls in white on the clay: the kit's toggle and its icon, and the drawer's close, reached through the exported parts — the button bases take the kit's ink otherwise (2026-09-09). */
wa-page::part(navigation-toggle) { color: var(--white); --wa-color-neutral-on-quiet: var(--white);
  --wa-color-neutral-on-normal: var(--white); --wa-color-neutral-fill-quiet: var(--veil);
  --wa-color-neutral-fill-normal: var(--veil-strong); --wa-focus-ring-color: var(--white); }
wa-page::part(navigation-toggle-icon) { color: var(--white); }
wa-page::part(drawer__close-button) { --wa-color-neutral-on-quiet: var(--white); --wa-color-neutral-on-normal: var(--white);
  --wa-color-neutral-fill-quiet: var(--veil); --wa-color-neutral-fill-normal: var(--veil-strong);
  --wa-focus-ring-color: var(--white); }
wa-page::part(drawer__close-button__base) { color: var(--white); }
/* The kit paints every slotted region on its surface colour; the header shows the part's clay through and the main column the paper. */
/* The page's ground is the paper everywhere; cards and folds are white on it (docs/system/ui.md#theme's page painted itself
   white before, and only the body behind it was paper). */
wa-page { background: var(--paper); }
.topbar, .main { background: transparent; }
.topbar { flex: 1; display: flex; align-items: center; min-width: 0; }
.topbar .brand { margin: 0; font-size: var(--wa-font-size-m); flex: 1; }
.brand { font-weight: 800; font-size: var(--wa-font-size-l); letter-spacing: 0.2px;
         margin-bottom: 1.1rem; color: var(--white); }
.brand .hub {
  background: var(--white); color: var(--clay-deep); border-radius: var(--wa-border-radius-m);
  padding: 0.05rem 0.35rem; margin-left: 1px;
}
.side a {
  color: var(--on-clay-link); text-decoration: none; padding: 0.5rem 0.7rem;
  border-radius: var(--wa-border-radius-m); display: block; font-weight: 500;
}
.side a.active, .side a:hover { background: var(--veil); color: var(--white); }
.side a.sub { margin-left: 0.9rem; font-size: var(--wa-font-size-s); padding: 0.38rem 0.7rem; }
.side a.sub2 { margin-left: 1.8rem; font-size: var(--wa-font-size-s); padding: 0.32rem 0.7rem; }
.side a.sub3 { margin-left: 2.7rem; font-size: var(--wa-font-size-s); padding: 0.3rem 0.7rem; }
/* What the account pinned, under its parent: one line each, the name cut where it runs long. */
.side a.pinned { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.side a.pinned wa-icon { font-size: var(--font-size-smaller-2); margin-right: 0.4rem; opacity: 0.7; }
.side .foot { margin-top: auto; font-size: var(--wa-font-size-s); color: var(--on-clay-quiet); }
.side .foot a { display: inline; padding: 0; color: var(--white); text-decoration: underline; }
/* The profile card: a small hero-like plate — the person on the left, the way out on the right. */
.side .foot .me-card { display: flex; align-items: center; gap: 0.35rem;
  background: var(--card); border-radius: var(--wa-border-radius-l); padding: 0.5rem 0.55rem;
  box-shadow: 0 2px 6px var(--shade-deep); }
.side .foot .me-card:hover { box-shadow: 0 3px 9px var(--shade-deep); }
/* A worn face is never quiet: the sidebar says whose, and the card wears a warning edge so it cannot be mistaken for one's own. */
.side .foot .worn { display: flex; align-items: center; gap: 0.4rem;
  font-size: var(--wa-font-size-xs); font-weight: 700; letter-spacing: 0.02em;
  text-transform: uppercase; color: var(--worn); margin: 0 0 0.35rem;
  padding: 0.25rem 0.4rem 0.25rem 0.5rem; border-radius: var(--wa-border-radius-m);
  background: var(--worn-fill);
  border: 1px solid var(--worn-line); }
.side .foot .worn span { overflow-wrap: anywhere; flex: 1; }
.side .foot .worn a { color: var(--worn); display: flex; cursor: pointer; }
.side .foot .worn a:hover { color: var(--white); }
.side .foot .me-card.me-worn { outline: 2px solid var(--worn-line);
  outline-offset: 1px; }
.side .foot .me-link { display: flex; align-items: center; gap: 0.4rem;
  flex: 1; min-width: 0; color: var(--ink); font-weight: 600;
  font-size: var(--wa-font-size-xs); text-decoration: none; }
.side .foot .me-link wa-icon { font-size: var(--font-size-m-plus); color: var(--clay);
  flex: none; }
/* Two lines before the ellipsis: one line fits 91% of names, two cover 99.99% (measured store-wide, 2026-08-27). */
.side .foot .me-link span { overflow: hidden; display: -webkit-box;
  -webkit-box-orient: vertical; -webkit-line-clamp: 2;
  line-height: 1.25; }
.side .foot #signout { color: var(--muted); opacity: 0.7;
  display: inline-flex; }
.side .foot #signout:hover { opacity: 1; color: var(--clay); }
.metafoot { font-size: var(--wa-font-size-2xs); line-height: 1.55; color: var(--on-clay-faint);
            margin-top: 0.55rem; border-top: 1px solid var(--veil);
            padding-top: 0.55rem; }
.main { flex: 1; padding: 1.4rem 1.8rem; min-width: 0; }
/* On a phone (the kit's mobile view, under 760px) the menu is the drawer's: the brand is the header's, the meta block stays away. */
wa-page[view="mobile"] .side .brand, wa-page[view="mobile"] .metafoot { display: none; }
wa-page[view="mobile"] .main { padding: 0.9rem; }

/* ======================================================================
   PRIMITIVES (docs/system/ui.md). Everything a view composes from, under the chapter's areas and in its order. A page's own classes live under PAGES.
   ====================================================================== */

/* ---------- Layout and Navigation ---------- */

/* Card (docs/system/ui.md#card): the kit's, our surface, border and radius on its tokens, our padding on its body, a breath beneath. */
wa-card { --spacing: 1rem; --wa-panel-border-radius: var(--wa-border-radius-l); margin-bottom: 1rem; }
wa-card::part(body) { padding: 1rem 1.1rem; }

/* Key-value list (docs/system/ui.md#key-value-list): the facts a detail card opens with. */
.kv { display: grid; grid-template-columns: max-content 1fr; gap: 0.25rem 1rem; }
.kv dt { color: var(--muted); }
.kv dd { margin: 0; overflow-wrap: anywhere; }
/* A phone's width: the label above its value, one column (2026-09-21). */
@media (max-width: 700px) {
  .kv { grid-template-columns: 1fr; gap: 0; }
  .kv dt { margin-top: 0.55rem; font-size: var(--wa-font-size-s); }
  .kv dt:first-child { margin-top: 0; }
}
/* A facts list with more beneath it. */
.facts { margin: 0 0 0.9rem; }
/* The tournament's card (docs/system/ui.md#key-value-list): the facts, the logo at their right, the organizer's words beneath a rule. */
.t-card-top { display: flex; gap: 1rem; align-items: flex-start; justify-content: space-between; }
.t-card-top .kv { flex: 1 1 auto; min-width: 0; }
.t-card-logo { flex: none; width: 6rem; height: 6rem; object-fit: contain; }
.t-card-about { margin-top: 0.9rem; padding-top: 0.9rem; border-top: 1px solid var(--line); }
@media (max-width: 640px) {
  .t-card-top { flex-direction: column-reverse; }
  .t-card-logo { width: 4.5rem; height: 4.5rem; }
}

/* Field rows (docs/system/ui.md#field-rows): a page's facts and settings, the label in the muted ink at the left, the words or the control that changes them at the right. */
table.fields td { vertical-align: middle; }
table.fields td.field-label { color: var(--muted); width: 22rem; max-width: 40%; }
table.fields wa-select, table.fields wa-input, table.fields .picker { display: inline-block; width: 18rem; max-width: 100%; vertical-align: middle; }
table.fields .hint { display: block; }
table.fields .err:not(:empty) { margin-bottom: 0.3rem; max-width: 30rem; }
.field-said .saved-mark { margin-left: 0.6rem; }

/* Page head (docs/system/ui.md#page-head): the way back and the title on one line, the back button plain; at the far end the one thing to do from here, or the clock to it. */
.page-head { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap;
  margin: 0 0 0.9rem; }
.page-head h1 { margin: 0; }
.page-head wa-button.back { flex: none; }
/* The head's far end: the one thing to do from here, or the clock to it. */
.head-acts { margin-left: auto; display: flex; align-items: center; gap: 0.6rem; }

/* Tabs (docs/system/ui.md#tabs): the kit's strip in our inks, its panels on the page's ground with a breath above — never a card around a whole panel; a card inside one is the content's own. */
wa-tab-group { --indicator-color: var(--clay-deep); --track-color: var(--line);
  --track-width: 1px; margin: 0.9rem 0 0; }
wa-tab-panel { --padding: 0.9rem 0 0; }
wa-tab::part(base) { font-weight: 600; color: var(--muted); padding: 0.5rem 1rem; }
wa-tab[active]::part(base) { color: var(--clay-deep); }
wa-tab:hover:not([active])::part(base) { color: var(--ink); }
/* A pane holding several sections (the simulation's gender tabs): the sections' own cards dissolve into the shared surface. */
wa-tab-panel.pane-group wa-card { border: none; border-radius: 0; margin-bottom: 0.4rem; }
wa-tab-panel.pane-group wa-card::part(body) { padding: 0.2rem 0 0; }
wa-tab-panel.pane-group h2 { margin-top: 0.7rem; }

/* Accordion (docs/system/ui.md#accordion): the kit's details, plain, the icon first — a plus that becomes a minus and never turns. */
wa-details.acc { margin-top: 0.6rem; }
wa-details.acc::part(header) { padding: 0.4rem 0; font-weight: 600; }
wa-details.acc::part(icon) { rotate: none; color: var(--muted); }
wa-details.acc::part(content) { padding: 0.2rem 0 0.6rem 1.7rem; }

/* Folded card (docs/system/ui.md#folded-card): the kit's details in its outlined form — the card's radius and border, the head a section's title, the plus at the left that never turns, the step number in its clay circle. */
wa-details.fold { --wa-panel-border-radius: var(--wa-border-radius-l); margin-bottom: 1rem; }
wa-details.fold::part(header) { font-weight: 600;
  font-size: var(--wa-font-size-l); }
wa-details.fold > [slot="summary"] { display: inline-flex; align-items: center; gap: 0.6rem; }
wa-details.fold::part(icon) { rotate: none; color: var(--muted); }
/* A step's number in its clay circle: a folded card's, a step strip's. */
.stepno { display: inline-flex; width: 1.5rem; height: 1.5rem;
  border-radius: var(--wa-border-radius-circle); align-items: center; justify-content: center;
  background: var(--clay); color: var(--white); font-size: var(--wa-font-size-s); font-weight: 700; }

/* Pager (docs/system/ui.md#pager): the kit's, compact, a size down. */
wa-pagination { margin-top: 0.8rem; font-size: var(--wa-font-size-s); }

/* Document (docs/system/ui.md#document): the documentation as the Help section shows it — the words in a column made for reading, the contents beside them where the screen is wide and folded above them where it is not. What it holds is what app/docs.py renders: headings, paragraphs, lists, tables, code, callouts, links. */
.doc-layout { display: grid; grid-template-columns: minmax(0, 46rem) minmax(12rem, 16rem);
  gap: 2.4rem; align-items: start; }
.doc-fold { display: none; grid-column: 1 / -1; }
.doc { min-width: 0; line-height: 1.6; }
.doc > :first-child { margin-top: 0; }
.doc h2 { font-size: var(--wa-font-size-l); margin: 2rem 0 0.6rem; padding-top: 1rem;
  border-top: 1px solid var(--line); }
.doc h3 { font-size: var(--font-size-m-plus); margin: 1.5rem 0 0.4rem; }
.doc h4 { font-size: var(--wa-font-size-m); margin: 1.2rem 0 0.3rem; color: var(--muted); }
.doc p { margin: 0 0 0.8rem; }
.doc ul, .doc ol { margin: 0 0 0.9rem; padding-left: 1.4rem; }
.doc li { margin: 0.2rem 0; }
.doc li > ul { margin: 0.2rem 0 0.3rem; }
.doc-lead { margin: 0; padding: 0.7rem 0.9rem; background: var(--wa-color-overlay-inline);
  border-left: 3px solid var(--clay); }
.doc-lead + .doc-lead { border-top: 1px solid var(--line); margin-bottom: 1.2rem; }
.doc-lead:first-child { border-radius: var(--wa-border-radius-m) var(--wa-border-radius-m) 0 0; }
.doc-code { background: var(--wa-color-overlay-inline); font-family: var(--wa-font-family-code);
  font-size: var(--wa-font-size-smaller); line-height: 1.5; padding: 0.8rem 1rem; border-radius: var(--wa-border-radius-m);
  overflow-x: auto; margin: 0 0 1rem; }
.doc-code code { padding: 0; background: none; font-size: inherit; }
.doc-callout { margin: 0 0 1rem; }
.doc .tablewrap { margin: 0 0 1rem; }
table.doc-table th, table.doc-table td { white-space: normal; vertical-align: top; }
table.doc-table td:first-child { font-weight: 600; }
.doc-crumb { margin: -0.6rem 0 1.2rem; }
/* The contents: a column that stays in view while the words scroll. */
.doc-nav { position: sticky; top: 1rem; max-height: calc(100vh - 2rem); overflow-y: auto;
  font-size: var(--wa-font-size-s); padding-left: 1rem; border-left: 1px solid var(--line); }
.doc-nav .cardtitle, .doc-fold .cardtitle { margin: 0 0 0.4rem; }
.doc-nav .doc-list + .cardtitle, .doc-fold .doc-list + .cardtitle { margin-top: 1.2rem; }
.doc-list { list-style: none; margin: 0; padding: 0; }
.doc-list li { margin: 0; }
.doc-list li.l3 { padding-left: 0.9rem; }
.doc-list a { display: block; padding: 0.18rem 0; color: var(--muted); text-decoration: none; }
.doc-list a:hover { color: var(--blue); }
.doc-list li.on a { color: var(--clay-deep); font-weight: 600; }
/* The chapter before and the one after, at a chapter's foot. */
.doc-steps { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; margin-top: 2.4rem; }
.doc-step { display: block; padding: 0.8rem 1rem; border: 1px solid var(--line);
  border-radius: var(--wa-border-radius-m); text-decoration: none; color: var(--ink); background: var(--card); }
.doc-step:hover { border-color: var(--blue); }
.doc-step.next { text-align: right; }
.doc-step strong { display: block; color: var(--blue); }
/* The Help landing: a book a tile, the kind above its title. */
.doc-tile { flex: 1 1 260px; }
.doc-tile .meta { display: block; margin-bottom: 0.3rem; text-transform: uppercase; letter-spacing: 0.04em;
  font-size: var(--wa-font-size-2xs); }
.doc-search { min-width: min(28rem, 80vw); }
#help-hits { margin: 0 0 1.4rem; }
table.doc-hits td { white-space: normal; vertical-align: top; }
@media (max-width: 980px) {
  .doc-layout { grid-template-columns: minmax(0, 1fr); gap: 1rem; }
  .doc-nav { display: none; }
  .doc-fold { display: block; }
}
@media (max-width: 700px) {
  .doc h2 { margin-top: 1.6rem; }
  .doc-steps { grid-template-columns: 1fr; }
  .doc-step.next { text-align: left; }
}
/* A specification rendered small and readable: the import spec, the score guide. */
.spec { font-size: var(--wa-font-size-m); line-height: 1.5; }
.spec pre { background: var(--wa-color-overlay-inline); font-family: var(--wa-font-family-code);
  border-radius: var(--wa-panel-border-radius); padding: var(--wa-space-m); overflow-x: auto;
  font-size: var(--wa-font-size-smaller); }
.spec pre code { padding: 0; background: none; font-size: inherit; }
.spec h2, .spec h3 { margin: 0.9rem 0 0.3rem; }
.spec li { margin-left: 1.2rem; }
.spec table td, .spec table th { white-space: normal; }
wa-details.acc .spec li { margin-left: 1.2rem; }

/* Read more (docs/system/ui.md#read-more): words to their fifth line (a document's lines are 1.6 high), the rest behind the button. */
.more.shut .more-body { max-height: 8em; overflow: hidden;
  -webkit-mask-image: linear-gradient(to bottom, black 60%, transparent); mask-image: linear-gradient(to bottom, black 60%, transparent); }
.more-turn { margin: 0.2rem 0 0 -0.6rem; }

/* Landing tiles (docs/system/ui.md#landing-tiles): a page that only sends the reader on — Ratings, Admin Tools, Data browser, Help. */
.tiles { display: flex; gap: 1rem; flex-wrap: wrap; }
.tile {
  flex: 1; min-width: 220px; background: var(--card);
  border: 1px solid var(--line); border-radius: var(--wa-border-radius-l); padding: 1.3rem;
  text-decoration: none; color: var(--ink);
}
.tile:hover { border-color: var(--blue); box-shadow: 0 4px 14px var(--blue-glow); }
.tile h3 { margin: 0 0 0.3rem; color: var(--blue); }
.tile p { margin: 0; color: var(--muted); font-size: var(--wa-font-size-m); }

/* ---------- Text and Status ---------- */

/* Headings and text (docs/system/ui.md#headings-and-text): a line of arithmetic in the code face, and a card's title. */
.formula { font-family: var(--wa-font-family-code); font-size: var(--wa-font-size-smaller);
  background: var(--wa-color-overlay-inline); border-radius: var(--wa-panel-border-radius);
  padding: var(--wa-space-m); overflow-x: auto; white-space: nowrap; margin: 0.5rem 0; }
/* A card's title (docs/system/ui.md#headings-and-text). */
.cardtitle { margin: 0 0 0.5rem; font-size: var(--wa-font-size-m); }
/* A card's title that follows other content in the card. */
.cardtitle.spaced { margin-top: 1rem; }

/* Rich text (docs/system/ui.md#rich-text): somebody's own words inside a card, drawn as a document is. */
.doc.rich { max-width: 46rem; }
.doc.rich h2 { margin-top: 1.2rem; padding-top: 0; border-top: 0; }
.doc.rich > :first-child { margin-top: 0; }
.doc.rich > :last-child { margin-bottom: 0; }

/* Pill (docs/system/ui.md#pill): the kit's badge at our size. */
wa-badge { font-size: var(--wa-font-size-2xs); font-weight: 600; letter-spacing: 0.01em; vertical-align: middle; }

/* Tag (docs/system/ui.md#tag): a short list of the kit's tags that can be taken off. */
.disc-players { display: flex; flex-wrap: wrap; gap: 0.35rem; margin-bottom: 0.45rem; }

/* Count (docs/system/ui.md#count): a small pill beside a label — a tab's, a menu item's. The premium mark sits as a count does. */
wa-badge.count { margin-left: 0.35rem; vertical-align: middle; position: relative; top: -0.1em; }
/* The kit paints the badge on its host, so the host is what turns. */
.side wa-badge.count, .navdemo wa-badge.count {
  background-color: var(--white); color: var(--clay-deep); }

/* Marks (docs/system/ui.md#marks): an asterisk a little smaller than the words it follows, in its tone — red after a member priced on assumptions alone or a rating that is approximate, yellow after a doubles Elo worked out from the singles Elo, blue after a doubles team the simulation paired itself. */
.mark { margin-left: 0.25em; font-size: var(--wa-font-size-smaller); }
.mark.fresh { color: var(--warn); }
.mark.derived { color: var(--amber); }
.mark.assigned { color: var(--blue); }
/* The seed before a name. */
.seedno { display: inline-block; min-width: 1.4em; text-align: center;
  background: var(--wa-color-brand-fill-normal); color: var(--clay-deep); border-radius: var(--wa-border-radius-s);
  font-size: var(--font-size-smaller-2); font-weight: 700; padding: 0 0.28em;
  margin-right: 0.4em; }
/* Movement (docs/system/ui.md#marks): the places or points gained or lost since last week. Up is blue and down is clay — the pair the inline H2H uses, so the reader learns one convention and not two. */
.move { font-size: var(--wa-font-size-s); font-weight: 600; margin-left: 0.3rem;
  white-space: nowrap; cursor: default; }
.move .arr { letter-spacing: -0.08em; margin-right: 0.05em; }
.move.up { color: var(--blue); }
.move.down { color: var(--clay); }

/* Tooltip (docs/system/ui.md#tooltip): a light card in our ink, not the kit's dark. */
wa-tooltip { --max-width: 22rem; font-size: var(--wa-font-size-s);
  font-weight: var(--wa-font-weight-normal, 400); font-style: normal; color: var(--ink);
  --wa-tooltip-background-color: var(--wa-color-surface-default);
  --wa-tooltip-content-color: var(--wa-color-text-normal);
  --wa-tooltip-border-color: var(--line);
  --wa-tooltip-border-radius: var(--wa-border-radius-m); }
wa-tooltip::part(body) { box-shadow: 0 4px 14px var(--shade-soft); }
/* A rich tooltip's rule (the simulation's stories). */
wa-tooltip hr { border: 0; border-top: 1px solid var(--line); margin: 0.35rem 0; }

/* Names (docs/system/ui.md#names): a player's name, linked for those who may open the player page. */
a.pname { font-weight: 600; color: inherit; text-decoration: none; }
a.pname:hover { text-decoration: underline; }
/* The TennisHub id beside a name. */
.thid { margin-left: 0.4rem; }

/* Logo (docs/system/ui.md#logo): a competition's square mark beside its name, the whole image inside. */
.logo-mark { width: 1.6em; height: 1.6em; object-fit: contain; vertical-align: middle; margin-right: 0.45em; flex: none; }
.logo-mark.big { width: 4.5rem; height: 4.5rem; margin-right: 0.3rem; border: 1px solid var(--line);
  border-radius: var(--wa-border-radius-m); padding: 0.25rem; }

/* Pin (docs/system/ui.md#pin): faint until pinned, the brand's blue while it is. */
.pin { cursor: pointer; opacity: 0.35; margin-left: 0.35rem; font-size: var(--font-size-smaller-2); vertical-align: middle; color: inherit; }
.pin:hover { opacity: 1; }
.pin.on { opacity: 1; color: var(--blue); }
.pin:focus-visible { outline: 2px solid var(--blue); outline-offset: 2px; border-radius: var(--wa-border-radius-s); }

/* Follow bell (docs/system/ui.md#follow-bell): icon only, faint until followed, the blue while it is. */
.fbell { cursor: pointer; opacity: 0.35; margin-left: 0.25rem;
  color: inherit; }
.fbell:hover { opacity: 1; }
.fbell.on { opacity: 1; color: var(--blue); }
.fbell wa-icon { font-size: var(--wa-font-size-smaller); }
/* Under a finger the bell is as large as a finger: its mark stays the size it is, what takes the touch reaches beyond it. */
@media (pointer: coarse) {
  .fbell { position: relative; opacity: 0.55; }
  .fbell::after { content: ""; position: absolute; inset: -0.85rem -0.7rem; }
}
/* A row crossing between two follow lists: the leaving one slides out, the arriving one slides in. */
tr.row-out { opacity: 0; transform: translateX(16px);
  transition: opacity 0.25s ease, transform 0.25s ease; }
tr.row-in { animation: rowin 0.45s ease; }
@keyframes rowin {
  from { opacity: 0; transform: translateX(-16px); }
}

/* Money (docs/system/ui.md#money): what there is to pay, a line a fee, its price at the right. */
.fee-list { list-style: none; margin: 0 0 0.8rem; padding: 0; max-width: 30rem; }
.fee-list li { display: flex; justify-content: space-between; gap: 1rem; padding: 0.3rem 0; border-top: 1px solid var(--line); }
.fee-list li:first-child { border-top: 0; }
/* The price a discount replaces, struck through. */
.fee-was { color: var(--wa-color-text-quiet); font-weight: 400; }
/* An entry's payment, as a pill. */
.entry-status { vertical-align: middle; }

/* ---------- States and Feedback ---------- */

/* Callouts (docs/system/ui.md#callouts). A flash slot holds the answer to an act, above what it answers for, with a breath beneath it when it holds something. */
.flash:not(:empty) { margin: 0 0 0.9rem; }
/* A page's status slot: the callout stands clear of what follows. */
#status wa-callout { margin: 0 0 0.9rem; }
/* Reserved room beside the refresh button: the outcome lands here without shifting the table. */
.refresh-note { display: inline-block; min-width: 7.5rem; margin-left: 0.6rem; }

/* Loaders (docs/system/ui.md#loaders). The ball is for content that is not there yet; it is the loading state's indicator and never stands alone. */
.loading { display: flex; flex-direction: column; align-items: center;
  padding: 2.6rem 0 2.2rem; }
.ball { width: 22px; height: 22px; border-radius: var(--wa-border-radius-circle);
  background: radial-gradient(circle at 35% 30%, var(--blue-bright),
    var(--blue));
  animation: ball-bounce 0.55s cubic-bezier(0.35, 0, 0.7, 1)
    infinite alternate; }
.ball-shadow { width: 26px; height: 5px; border-radius: var(--wa-border-radius-circle);
  margin-top: 6px; background: var(--shade);
  animation: ball-squash 0.55s cubic-bezier(0.35, 0, 0.7, 1)
    infinite alternate; }
@keyframes ball-bounce {
  from { transform: translateY(-17px); }
  to { transform: translateY(4px) scale(1.06, 0.9); }
}
@keyframes ball-squash {
  from { transform: scale(0.55); opacity: 0.35; }
  to { transform: scale(1); opacity: 0.75; }
}
/* The circle (docs/system/ui.md#loaders): the kit's spinner, for a refresh that keeps the content on screen; big in the simulation's overlay. */
wa-spinner.big { font-size: var(--font-size-3xl-plus); margin: 0 auto 1rem; display: block; }

/* Loading and empty states (docs/system/ui.md#loading-and-empty-states): centred, quiet, on the page's ground. */
.state { display: flex; flex-direction: column; align-items: center;
  text-align: center; padding: 2.2rem 1rem 2.4rem; color: var(--muted); }
.state .loading { padding: 0 0 1.2rem; }
.state > wa-icon { font-size: var(--font-size-2xl-plus); margin-bottom: 0.8rem; opacity: 0.6; }
.state-title { color: var(--ink); font-weight: 600; }
.state-hint { font-size: var(--wa-font-size-s); margin-top: 0.3rem; }
.state-act { margin-top: 1.1rem; }

/* ---------- Actions ---------- */

/* Buttons (docs/system/ui.md#buttons): the kit's. Our button was 36px tall; the kit's control padding brings its medium size to that. */
wa-button { font-weight: 600; font-size: inherit; --wa-form-control-height: 2.3rem;
  --wa-form-control-padding-inline: 1em; }
/* The small button, and a row's own acts smaller still. */
wa-button[size="s"] { font-size: var(--wa-font-size-s); --wa-form-control-height: 1.9rem; }

/* Row actions (docs/system/ui.md#row-actions): at the left of their cell, text buttons or icons that name themselves on hover, and smaller than any other button. */
.acts wa-button { font-size: var(--wa-font-size-s); --wa-form-control-height: 1.5rem;
  --wa-form-control-padding-inline: 0.6em; }
/* Row actions, at the left of their cell: text buttons, or icons that name themselves on hover. */
td.acts { white-space: nowrap; text-align: left; }
/* In a row that opens something the acts' cell is the acts' alone (docs/system/ui.md#table): no hand over it, since a click there does not open the row — the row's tint under the pointer it keeps. */
tr.click td.acts { cursor: default; }
/* Every act after the first stands the same step from the one before, whether or not a tooltip was hung between them (`~`, not `+`). */
.acts wa-button ~ wa-button { margin-left: 0.3rem; }
/* An action a row does not offer keeps its place (docs/system/ui.md#row-actions): the same icon, unseen, so the acts line up down the list. */
.acts wa-button.act-gap { visibility: hidden; pointer-events: none; }
/* A row's acts beside words rather than in a cell. */
.acts.inline { display: inline-block; margin-left: 0.6rem; }

/* Order arrows (docs/system/ui.md#order-arrows): the pair of quiet chevrons that move a row a place — the standings' ruling, the social courts' order. */
td.ord-acts { white-space: nowrap; padding-top: 0; padding-bottom: 0; }
td.ord-acts wa-button::part(base) { padding: 0 0.2rem; min-height: 1.4rem; }

/* Share link (docs/system/ui.md#share-link): the kit's plain button, small, beside a title. */
wa-button.share { margin-left: 0.4rem; vertical-align: middle; }
h1 wa-button.share, h2 wa-button.share { font-weight: 500; }

/* Problem report (docs/system/ui.md#problem-report): a quiet bug at the end of the brand row, plain until hovered. */
.brand { display: flex; align-items: center; gap: 0.4rem; }
.brand .bugbtn { margin-left: auto; opacity: 0.45; --wa-color-brand-on-quiet: var(--white); color: var(--white); }
.brand .bugbtn::part(base) { color: var(--white); }
.brand .bugbtn:hover { opacity: 1; }
/* The problem report's dialog: the form block, a row for the screenshot. */
wa-dialog.bug { --width: 34rem; }
wa-dialog.bug .form .row { margin-bottom: 0.7rem; }
.bug-shotrow { display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap; }
.bug-thumb { height: 2.2rem; border-radius: var(--wa-border-radius-s); vertical-align: middle; margin-right: 0.3rem;
  border: 1px solid var(--line); }
wa-dialog.bug .flash:empty { display: none; }

/* ---------- Forms and Pickers ---------- */

/* Form field (docs/system/ui.md#form-field). The kit's inputs and selects at our height and type size; a control fills its field. */
wa-input, wa-select, wa-time-input { font-size: inherit; --wa-form-control-height: 2.3rem; width: 100%; }

/* A native control, wherever it stands — a filter row, the form block, the picker — reads the kit's form-control tokens, so it matches the kit's own inputs. */
.filters input, .filters select, .form .f input, .form .f select, .picker input {
  border: var(--wa-form-control-border-width) var(--wa-form-control-border-style)
    var(--wa-form-control-border-color);
  border-radius: var(--wa-form-control-border-radius);
  padding: var(--wa-form-control-padding-block) var(--wa-form-control-padding-inline);
  font: inherit; color: var(--wa-form-control-value-color);
  background: var(--wa-form-control-background-color);
}
.filters input:focus, .filters select:focus, .picker input:focus,
.form .f input:focus, .form .f select:focus {
  outline: var(--wa-focus-ring); outline-offset: 0; border-color: var(--wa-color-focus);
}
.filters label, .form .f label { font-size: var(--wa-font-size-xs);
  color: var(--wa-form-control-label-color); font-weight: var(--wa-form-control-label-font-weight); }

/* Every form is `.form`; a `.row` is a grid of equal fields; a `.f` is label, error slot, control, description. `.extra` holds the small choices beneath a control (a month-only box, the approximate mark). */
.form .row { display: grid; grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
  gap: 0.6rem 1rem; align-items: start; margin-bottom: 0.9rem; }
/* A lone field: half the row, in line with a row of two — never under 34rem while the place has it, so the whole row in a dialog. */
.form .row.one { grid-template-columns: min(100%, max(calc(50% - 0.5rem), 34rem)); }
/* A field that takes the whole row: the rich text field. */
.form .row.wide { grid-template-columns: minmax(0, 1fr); }
.form .row.five { grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr)); }
.form .f { display: flex; flex-direction: column; gap: 0.2rem; min-width: 0; }
.form .f input, .form .f select { width: 100%; box-sizing: border-box; }
.form .f input:disabled, .form .f select:disabled {
  color: var(--wa-color-text-quiet); background: var(--wa-color-surface-lowered); cursor: not-allowed; }
.form .f .extra { display: flex; flex-wrap: wrap; gap: 0.6rem; align-items: center;
  margin-top: 0.15rem; }
.form .err { margin: 0 0 0.3rem; }
/* A field that follows other fields: its computed value beside the box that hands it over. */
.form .tf-name { display: flex; gap: 0.8rem; align-items: center; }
/* The description under a control, the error slot above it, the foot with the form's button. */
.hint { font-size: var(--wa-font-size-xs); color: var(--wa-form-control-hint-color);
  display: block; margin-top: 0.15rem; }
.err:empty { display: none; }
.err { margin: 0.4rem 0 0.6rem; }
.form-foot { margin-top: 1rem; }
.form-foot.end { display: flex; justify-content: flex-end; gap: 0.6rem; }
/* Saved, said in the head of the card a setting was changed in (docs/system/ui.md#form-field). */
.saved-mark { margin-left: 0.5rem; font-size: var(--wa-font-size-s); font-weight: 400; color: var(--ok); }
.saved-mark.busy { color: var(--muted); }
/* A note at the head of a form's card stands clear of the first field. */
wa-card.form > wa-callout { margin-bottom: 0.9rem; }

/* A mark — the kit's checkbox — never breaks its words; beside a control it keeps its width, and the hint beneath it is prose. A radio group's label is the kit's own, dressed as the block's. */
.filters wa-checkbox, .form .f wa-checkbox { white-space: nowrap; flex: none; }
/* The words beside the box never break; the hint beneath it is prose, and does. */
wa-checkbox::part(hint) { white-space: normal; }
/* A radio group's label is the kit's own (docs/system/ui.md, 2026-09-07), dressed as the form block's: the small size, the label's ink and weight. */
wa-radio-group::part(form-control-label) { font-size: var(--wa-font-size-xs);
  color: var(--wa-form-control-label-color); font-weight: var(--wa-form-control-label-font-weight); }

/* Date and time (docs/system/ui.md#date-and-time): the browser's own control inside a date or time field — its segments in our ink, its calendar's highlight in our clay. The icon and the unset segments are past the part's reach: app.js adopts DATE_SHEET into each field's shadow root. */
wa-input[type="date"]::part(input), wa-input[type="time"]::part(input) {
  accent-color: var(--clay); color-scheme: light; color: var(--wa-form-control-value-color); }
/* The approximate mark beneath a control. */
.approx { min-height: 0; display: inline-flex; gap: 0.3rem; align-items: center;
  color: var(--muted); }

/* The two sides of a match (docs/system/ui.md#form-field): a column a side, "vs" between them in a column of its own that mirrors a field — a label's height, then the word level with the first control. */
.sides { display: grid; grid-template-columns: 1fr auto 1fr; gap: 1rem;
  align-items: start; margin-bottom: 0.8rem; }
.sides-col { display: flex; flex-direction: column; gap: 0.4rem; min-width: 0; }
.sides-vs { display: flex; flex-direction: column; gap: 0.2rem; color: var(--muted);
  font-weight: 700; }
.sides-vs label { min-height: 1em; font-size: var(--wa-font-size-xs); }
.sides-vs span { height: var(--wa-form-control-height, 2.3rem); display: flex;
  align-items: center; }
@media (max-width: 720px) {
  .sides { grid-template-columns: 1fr; }
  .sides-vs { display: none; }
}

/* Picker (docs/system/ui.md#picker): our combobox. The input shows the choice and the list suggests. */
.picker { position: relative; }
.picker input { width: 100%; padding-right: 2rem; }
.picker .clear {
  position: absolute; right: 0.55rem; top: 50%; transform: translateY(-50%);
  cursor: pointer; color: var(--muted); font-size: var(--font-size-m-plus); line-height: 1;
  user-select: none;
}
.picker .clear:hover { color: var(--warn); }
.picker input.chosen { border-color: var(--blue); color: var(--blue); font-weight: 600; }
/* The picker is our combobox (docs/system/ui.md): its field is a kit-styled input, its list a card in the kit's surface and border, its rows the blue family's quiet fill on hover — the look of the kit's own lists. */
.picker .drop {
  position: absolute; z-index: 30; left: 0; right: 0; top: 100%; margin-top: 0.25rem;
  background: var(--wa-color-surface-default);
  border: var(--wa-border-width-s) solid var(--wa-color-surface-border);
  border-radius: var(--wa-border-radius-m);
  max-height: 260px; overflow-y: auto; box-shadow: 0 8px 22px var(--shade-soft);
  font-size: var(--wa-font-size-s);
}
.picker .drop div { padding: 0.45rem 0.7rem; cursor: pointer; }
.picker .drop div:hover { background: var(--blue-quiet); }
.picker .drop small { color: var(--wa-color-text-quiet); margin-left: 0.4rem; }
.picker .drop .hd { color: var(--wa-color-text-quiet); font-size: var(--wa-font-size-xs);
                    cursor: default; padding-bottom: 0.1rem; }
.picker .drop .hd:hover { background: none; }
/* In a filter row the picker's field is a size down, as the row's other controls are. */
.filters .picker input { min-width: 0; height: 2rem; padding-block: 0;
  font-size: var(--wa-font-size-s); }
/* Under a finger (2026-09-29): the field at 16px — a phone's browser zooms into a field whose letters are smaller — and tall enough to touch, its choices the same. */
@media (max-width: 700px) {
  .picker input, .form .f .picker input, .filters .picker input { font-size: var(--font-size-touch); min-height: 2.75rem; }
  .picker .drop { font-size: var(--wa-font-size-m); max-height: 50vh; }
  .picker .drop div { padding: 0.7rem 0.8rem; }
  .picker .drop small { display: block; margin: 0.1rem 0 0; }
}
.picker[hidden] { display: none; }

/* Slot picker (docs/system/ui.md#slot-picker): the default duration above — a form field, with a rule beneath — then the month's calendar beside the days picked, each day its time options. */
.slots-len { padding-bottom: 0.1rem; margin-bottom: 1rem; border-bottom: 1px solid var(--line); }
.slots-len wa-button-group { align-self: flex-start; }
.slots-body { display: grid; grid-template-columns: minmax(16rem, 22rem) 1fr; gap: 1.2rem 2rem;
  align-items: start; }
.slots-nav { display: flex; align-items: center; justify-content: space-between; margin-bottom: 0.4rem; }
.slots-month { font-weight: 600; color: var(--ink); text-transform: capitalize; }
.slots-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 0.2rem; margin-bottom: 0.7rem; }
.slots-wd { text-align: center; font-size: var(--wa-font-size-xs); color: var(--muted);
  padding: 0.2rem 0; text-transform: capitalize; }
.slots-day { font: inherit; font-weight: 600; color: var(--ink); background: none; cursor: pointer;
  border: 1px solid transparent; border-radius: var(--wa-border-radius-m); aspect-ratio: 1;
  min-height: 2.2rem; padding: 0; }
.slots-day:hover:not(:disabled) { background: var(--wa-color-brand-fill-quiet); }
.slots-day:focus-visible { outline: 2px solid var(--clay); outline-offset: 1px; }
.slots-day.today { border-color: var(--line); }
.slots-day.on, .slots-day.on:hover { background: var(--clay); border-color: var(--clay); color: var(--white); }
.slots-day:disabled { color: var(--muted); opacity: 0.45; cursor: default; font-weight: 400; }
.slots-one { display: flex; gap: 0.9rem; align-items: flex-start; padding: 0 0 0.9rem; margin-bottom: 0.9rem;
  border-bottom: 1px solid var(--line); }
.slots-one:last-child { border-bottom: 0; margin-bottom: 0; padding-bottom: 0; }
.slots-stamp { display: flex; flex-direction: column; align-items: center; flex: 0 0 3.2rem;
  border: 1px solid var(--line); border-radius: var(--wa-border-radius-m); padding: 0.25rem 0;
  font-size: var(--wa-font-size-xs); color: var(--muted); text-transform: capitalize; line-height: 1.25; }
.slots-stamp b { font-size: var(--wa-font-size-l); color: var(--ink); }
.slots-opts { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 0.45rem; }
.slots-opt { display: flex; align-items: center; gap: 0.5rem; min-height: 2.3rem; }
.slots-opt wa-time-input { width: 7.5rem; flex: 0 1 7.5rem; }
.slots-to, .slots-dur { color: var(--muted); }
.slots-dur { font-size: var(--wa-font-size-s); min-width: 5.2rem; white-space: nowrap; }
.slots-opt.bad .slots-dur { color: var(--warn); white-space: normal; }
.slots-acts { display: flex; align-items: center; gap: 0.3rem; }
.slots-body.with-side { grid-template-columns: minmax(16rem, 22rem) 1fr minmax(15rem, 20rem); }
.slots-side { display: flex; flex-direction: column; gap: 0.6rem; }
.slots-side wa-button { width: 100%; }
.slots-side[hidden] { display: none; }
@media (max-width: 1150px) {
  .slots-body.with-side { grid-template-columns: minmax(16rem, 22rem) 1fr; }
  .slots-side { grid-column: 1 / -1; }
}
@media (max-width: 760px) {
  .slots-body, .slots-body.with-side { grid-template-columns: 1fr; }
  .slots-opt { flex-wrap: wrap; }
  .slots-dur { min-width: 0; }
}

/* File field (docs/system/ui.md#file-field): the file kept on one line, the chooser beneath it — and the logo's square, previewed on a chequered ground so what is transparent shows, with the slider that moves it along the longer side. */
.file-kept { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; margin: 0 0 0.5rem; overflow-wrap: anywhere; }
input[type=file] { display: block; max-width: 100%; font: inherit; color: var(--muted); }
input[type=file]::file-selector-button { font: inherit; margin-right: 0.7rem; padding: 0.45rem 0.9rem;
  border: 1px solid var(--line); border-radius: var(--wa-border-radius-m); background: transparent;
  color: var(--blue); cursor: pointer; }
input[type=file]::file-selector-button:hover { border-color: var(--blue); }
/* The logo's square (docs/system/ui.md#file-field): the preview on a chequered ground, so what is transparent shows, and the slider that moves the square along the longer side. */
.sq-preview { display: block; width: 15rem; height: 15rem; margin: 0.6rem auto 0.9rem; border: 1px solid var(--line); border-radius: var(--wa-border-radius-l);
  background: repeating-conic-gradient(var(--wa-color-neutral-fill-normal) 0% 25%, var(--white) 0% 50%) 50% / 1.2rem 1.2rem; }
.sq-pos { width: 100%; accent-color: var(--clay); }

/* Rich text field (docs/system/ui.md#rich-text-field): a bar of marks over the words, in the frame of a kit control. */
.rich-editor { border: 1px solid var(--line); border-radius: var(--wa-border-radius-m); background: var(--wa-color-surface-default, var(--card)); }
.rich-editor:focus-within { border-color: var(--blue); outline: 2px solid color-mix(in srgb, var(--blue) 25%, transparent); }
.rich-bar { display: flex; flex-wrap: wrap; gap: 0.15rem; padding: 0.25rem; border-bottom: 1px solid var(--line); }
.rich-btn { all: unset; display: inline-flex; align-items: center; justify-content: center; width: 2rem; height: 2rem;
  border-radius: var(--wa-border-radius-s); color: var(--muted); cursor: pointer; }
.rich-btn:hover { background: var(--wa-color-overlay-inline); color: var(--ink); }
.rich-btn.on { background: var(--wa-color-overlay-inline); color: var(--blue); }
.rich-btn:focus-visible { outline: 2px solid var(--blue); outline-offset: 1px; }
.rich-content { min-height: 8rem; max-height: 24rem; overflow-y: auto; padding: 0.6rem 0.8rem; outline: none; max-width: none; }
.rich-content.doc.rich { max-width: none; }

/* Filters (docs/system/ui.md#filters): each field as short as its content needs, and only a line that has to be filled — because the row wraps — stretches its fields. layoutFilters (app.js) measures, packs the lines so none holds a single field, and writes each field's width. */
.filters { display: flex; flex-wrap: wrap; gap: 0.5rem; align-items: flex-end;
  margin-bottom: 0.9rem; }
.filters > * { flex: 0 0 auto; }
.filters .f { display: flex; flex-direction: column; gap: 0.2rem; }
/* A field's width is the layout's, never its content's intrinsic one: an input's twenty characters would push it wide. */
.filters > * { min-width: 0; }
/* `display: flex` above beats the browser's own rule for [hidden], so a filter switched off with el.hidden stays on screen without this. */
.filters .f[hidden] { display: none; }
.filters label { min-height: 1em; }
.filters input, .filters select { width: 100%; min-width: 0; }
/* A filter row's controls are a size down from a form's and fill their column. */
.filters wa-input, .filters wa-select { --wa-form-control-height: 2rem;
  --wa-form-control-value-font-size: var(--wa-font-size-s); font-size: var(--wa-font-size-s); }
.filters wa-select, .filters wa-input, .filters .picker { width: 100%; min-width: 0; }
.filters .f > wa-button { align-self: flex-start; }
/* A mark in a filter row stands a control's height, its box centred on the controls beside it; a mark never breaks its words — beside a control in a form's row it keeps its width (2026-09-07). */
.filters wa-checkbox { font-size: var(--wa-font-size-s); min-height: 2rem; }
.filters wa-checkbox::part(base) { margin-block: auto; }

/* ---------- Tables and Lists ---------- */

/* Table (docs/system/ui.md#table): it stands on the page or in a card alike — its own rules draw the head and the rows, the surface behind it is the parent's. */
.tablewrap { overflow-x: auto; }
table { border-collapse: collapse; width: 100%; font-size: var(--wa-font-size-s); }
th, td { text-align: left; padding: 0.45rem 0.6rem; white-space: nowrap; }
/* Every body row stands the same height, whatever it holds. */
tbody td { height: 2.4rem; box-sizing: border-box; }
th { color: var(--wa-color-text-quiet); font-weight: 600; font-size: var(--wa-font-size-xs);
     border-bottom: var(--wa-border-width-m) solid var(--wa-color-surface-border);
     position: sticky; top: 0; background: inherit; }
td { border-bottom: var(--wa-border-width-s) solid var(--wa-color-surface-border); }
tr.click { cursor: pointer; }
@media (hover: hover) { tr.click:hover td { background: var(--blue-quiet); } }
tr.me td { background: var(--wa-color-brand-fill-quiet); font-weight: 600; }
/* A cell that keeps to its content; and the race table's arrow column, which hugs the value it explains. */
td.tight, th.tight { width: 1%; white-space: nowrap; }
td.delta.hug, th.delta.hug { width: 1%; padding-left: 0; }
/* The race's qualifiers: a division's top eight, when one is chosen. */
/* The row highlight (docs/system/ui.md): the kit's quiet brand tint. */
tr.hi td { background: color-mix(in srgb, var(--blue) 16%, var(--card)); }
tr.hi td:first-child { box-shadow: inset 3px 0 0 var(--blue); }
/* The row asked for (docs/system/ui.md#table): the player a ranking is read around — the clay's tint and its rule, so it tells itself from a highlighted row where a list has both. */
tr.picked td, tr.picked.hi td { background: color-mix(in srgb, var(--clay) 15%, var(--card)); }
tr.picked td:first-child, tr.picked.hi td:first-child { box-shadow: inset 3px 0 0 var(--clay); }
tr.picked td { font-weight: 600; }
td.num, th.num { text-align: right; font-variant-numeric: tabular-nums; }
/* A row's detail (docs/system/ui.md#table): a second row under one that has more to show, its one cell holding a small line and a table of its own. */
tr.sub > td { padding-top: 0.25rem; padding-bottom: 0.5rem; padding-left: 1.5rem; }
tr.sub .tablewrap { margin: 0.25rem 0 0.5rem; }
/* Movement sits in its own column so the numbers beside it line up: the figure right-aligned as always, the arrow left-aligned against it. */
td.delta, th.delta { text-align: left; white-space: nowrap;
  width: 1%; padding-left: 0.35rem; }
/* Five columns do not need the whole card. Left to fill it, the name and the rating end up at opposite edges of a wide screen and the eye has to travel the gap for every row. */
table.narrow { max-width: 44rem; }
/* A cell of several lines, one a thing: a player's events, and beside each its seed and its bin. */
.lines > div { min-height: 2.1rem; display: flex; align-items: center; gap: 0.3rem; }
td.num .lines > div { justify-content: flex-end; }
td.seed .lines wa-input { width: 4.2rem; }
/* "vs" between the two sides of a match's row. */
.meta.vs { margin: 0 0.3rem; }

/* Stacked table (docs/system/ui.md#stacked-table): on a phone's width a `table.stack` drops its head and lays every row as a block — the cells flow as words on wrapped lines, each naming itself (`data-label`) where the head did, an empty one gone. The row's first line is its title (`td.lead`), the row's number before it and the row's acts after; `td.line` takes a line of its own where it stands. A table inside a cell is its own table: stacked only if it says so. */
@media (max-width: 700px) {
  table.stack, table.stack > tbody { display: block; }
  table.stack > thead { display: none; }
  table.stack > tbody > tr { display: flex; flex-wrap: wrap; align-items: center;
    gap: 0.15rem 0.9rem; padding: 0.55rem 0.2rem;
    border-bottom: var(--wa-border-width-s) solid var(--wa-color-surface-border); }
  table.stack > tbody > tr > td { display: block; height: auto; min-width: 0; padding: 0;
    border: 0; white-space: normal; text-align: left; }
  table.stack > tbody > tr > td:empty { display: none; }
  table.stack > tbody > tr > td[data-label]::before { content: attr(data-label) " ";
    color: var(--wa-color-text-quiet); font-size: var(--wa-font-size-xs); font-weight: 600; }
  table.stack > tbody > tr > td.lead { order: -1; flex: 1 1 6rem; font-size: var(--wa-font-size-m); }
  table.stack > tbody > tr > td.num:first-child { order: -1; color: var(--wa-color-text-quiet); }
  table.stack > tbody > tr > td.acts:not(.line) { order: -1; }
  /* The title line ends where its cells do. */
  table.stack > tbody > tr:has(> td.lead)::after { content: ""; order: -1; flex: 0 0 100%;
    margin-top: -0.15rem; }
  table.stack > tbody > tr > td.line, table.stack > tbody > tr > td[colspan] { flex: 1 0 100%; }
  table.stack > tbody > tr > td.acts.line:not(:empty) { margin-top: 0.35rem; }
  table.stack > tbody > tr.add { border-bottom-style: dashed; }
  /* A row and its detail read as one block, the rule under the pair; the detail's own table a size down, its acts a line of their own. */
  table.stack > tbody > tr:has(+ tr.sub:not([hidden])) { border-bottom: 0; padding-bottom: 0.2rem; }
  table.stack > tbody > tr.sub { padding-top: 0;
    border-bottom-width: var(--wa-border-width-m); }
  table.stack > tbody > tr.sub > td { padding-left: 0.6rem; }
  tr.sub table.stack > tbody > tr > td.lead, wa-dialog table.stack > tbody > tr > td.lead { font-size: inherit; }
  tr.sub .acts.inline { display: flex; flex-wrap: wrap; gap: 0.3rem; margin: 0.3rem 0 0; }
  tr.sub .acts.inline wa-button + wa-button { margin-left: 0; }
}

/* Folding row (docs/system/ui.md#folding-row): a row that opens the detail under it. A chevron at its start, turned while the detail shows; a blank of its width where a row has nothing to open, so the rows' words line up. A row called off reads quieter. */
tr[data-fold] { cursor: pointer; }
.fold-mark { all: unset; display: inline-flex; align-items: center; justify-content: center; width: 1.1rem; height: 1.1rem;
  margin-right: 0.35rem; vertical-align: -0.15em; color: var(--wa-color-text-quiet); cursor: pointer; border-radius: var(--wa-border-radius-s); }
.fold-mark.none { cursor: default; }
.fold-mark wa-icon { font-size: var(--wa-font-size-2xs); transition: transform 0.15s ease; }
.fold-mark[aria-expanded="true"] wa-icon { transform: rotate(90deg); }
.fold-mark:focus-visible { outline: 2px solid var(--blue); outline-offset: 1px; }
tr[data-fold]:hover .fold-mark { color: var(--ink); }
tr.fold-head.off > td:not(.acts) { color: var(--wa-color-text-quiet); }
@media (prefers-reduced-motion: reduce) { .fold-mark wa-icon { transition: none; } }

/* Add row (docs/system/ui.md#add-row): a list that takes new things opens with one, above its rows — quiet, dashed, blue on hover, never a button above the table. */
tr.add td { color: var(--blue); font-weight: 600; cursor: pointer;
  border-bottom: 1px dashed var(--line); line-height: 1.4; }
tr.add:hover td { background: var(--blue-quiet); }
tr.add wa-icon { margin-right: 0.45rem; vertical-align: -0.1em; font-size: var(--wa-font-size-smaller); line-height: 1; }

/* Tick grid (docs/system/ui.md#tick-grid): a table whose cells hold a box that saves the moment it is ticked — a row a player, a column a thing they did or did not do. The box sits in the middle of its cell, under a heading that may wrap. */
table.ticks th.tick, table.ticks td.tick { text-align: center; }
table.ticks th.tick { white-space: normal; width: 9rem; min-width: 6rem; vertical-align: bottom; }
.tick-box { width: 1.15rem; height: 1.15rem; margin: 0; cursor: pointer; accent-color: var(--blue);
  vertical-align: middle; }
.tick-box:disabled { cursor: progress; opacity: 0.5; }
.tick-none { all: unset; display: inline-block; min-width: 1.15rem; line-height: 1.15rem; text-align: center;
  color: var(--muted); cursor: pointer; border-radius: var(--wa-border-radius-s); }
.tick-none:hover { color: var(--ink); background: var(--wa-color-overlay-inline); }
.tick-none:focus-visible { outline: 2px solid var(--blue); outline-offset: 2px; }
.tick-none:disabled { cursor: progress; opacity: 0.5; }

/* Sortable column (docs/system/ui.md#sortable-column): the arrow shows the direction, faint until chosen. */
th.sort { cursor: pointer; user-select: none; white-space: nowrap; }
th.sort:hover { color: var(--clay-deep); }
th.sort .arrow { opacity: 0.3; margin-left: 0.25rem; font-size: var(--font-size-smaller-2); }
th.sort.on .arrow { opacity: 1; }

/* Progress bar (docs/system/ui.md#progress-bar): the kit's, small and blue, in a cell of a fixed band by default. */
td.winbar { width: 180px; min-width: 140px; }
wa-progress-bar.bar { --track-height: 0.6rem; --indicator-color: var(--blue);
  --track-color: color-mix(in srgb, var(--blue) 12%, var(--card)); }

/* Sparkline (docs/system/ui.md#sparkline): a blue line, blue points that take the kit's hover mix. svg-scoped: the cell that holds one shares the class name, and a table cell displayed as block falls out of its row. */
svg.spark { display: block; margin: 0.25rem 0; }
.spark polyline { fill: none; stroke: var(--blue); stroke-width: 1.6; }
.spark circle { fill: var(--blue); }
.spark circle:hover { fill: color-mix(in oklab, var(--blue), var(--wa-color-mix-hover)); }
/* The cell that holds a sparkline. */
td.spark { width: 120px; }
td.spark svg { display: block; }
td.spark svg polyline { fill: none; stroke: var(--blue); stroke-width: 1.6; }
td.spark svg circle { fill: var(--blue); }
td.spark svg circle:hover { fill: color-mix(in oklab, var(--blue), var(--wa-color-mix-hover)); }

/* ---------- Dialogs and Wizards ---------- */

/* A dialog that is a form: the roster's member, a fee, a discount, a new entry — 30 rem, its rows a little closer than a page's. */
wa-dialog.member { --width: 30rem; }
wa-dialog.member .form .row { margin-bottom: 0.7rem; }

/* Confirm box (docs/system/ui.md#confirm-box): the kit's, a little narrower. */
wa-dialog.confirm { --width: 30rem; }
wa-dialog.confirm p { margin: 0; }
/* The running job's dialog (docs/system/ui.md#confirm-box): narrow, its Cancel centred under the loading state. */
wa-dialog.job { --width: 22rem; }
wa-dialog.job::part(footer) { justify-content: center; }

/* Choice box (docs/system/ui.md#choice-box): the words, then a button a choice, stacked; the place a click gave a choice, a small ring before its name. */
wa-dialog.choose { --width: 26rem; }
wa-dialog.choose p { margin: 0 0 0.75rem; }
wa-dialog.choose .choices { display: flex; flex-direction: column; gap: 0.5rem; }
wa-dialog.choose .choices wa-button::part(base) { justify-content: flex-start; }
/* The place a click gave a choice, a small ring before its name. */
wa-dialog.choose .ord:not(:empty) { display: inline-flex; align-items: center; justify-content: center;
  width: 1.2rem; height: 1.2rem; margin-right: 0.5rem; border-radius: var(--wa-border-radius-circle); font-size: var(--wa-font-size-2xs);
  font-weight: 700; background: var(--white); color: var(--clay-deep); }

/* Copy box (docs/system/ui.md#copy-box). */
wa-dialog.copybox { --width: 38rem; }

/* Wizard (docs/system/ui.md#wizard): a dialog of several steps — what it has to say under its header, the steps strip, the step's own content, the step's buttons in the footer. */
wa-dialog.wizard { --width: 42rem; }
.wiz-says wa-callout { margin-bottom: 0.9rem; }
.wiz-says .flash { margin: 0; }
/* The closing screen: what was done, a callout a fact. */
.wiz-done { display: grid; gap: 0.7rem; }
ol.steps { list-style: none; display: flex; flex-wrap: wrap; gap: 0.4rem 1.2rem; margin: 0 0 1rem;
  padding: 0 0 0.8rem; border-bottom: 1px solid var(--line); color: var(--muted);
  font-size: var(--wa-font-size-s); font-weight: 600; }
ol.steps li { display: flex; align-items: center; gap: 0.4rem; }
ol.steps li .stepno { background: var(--line); color: var(--muted); margin: 0; }
ol.steps li.on { color: var(--clay-deep); }
ol.steps li.on .stepno { background: var(--clay-deep); color: var(--white); }
ol.steps li.done .stepno { background: var(--ok); color: var(--white); }
/* A step's opening words. */
.wiz-lead { margin: 0 0 0.8rem; }
/* The way back: a plain button at the footer's lower left. */
wa-dialog.wizard > .wiz-back { margin-inline-end: auto; }
wa-dialog.wizard .flash:empty { display: none; }
/* On a phone the wizard is a sheet the size of the screen: a dialog afloat in it left a fifth of the height unused and the question beneath the fold. One line of steps, the step in hand alone named; the footer's accent first and the width of the sheet, the way back and the quiet act beneath it. */
@media (max-width: 700px) {
  wa-dialog.wizard::part(dialog) { width: 100vw; max-width: 100vw; height: 100dvh; max-height: 100dvh;
    margin: 0; border-radius: 0; }
  ol.steps { flex-wrap: nowrap; gap: 0.7rem; }
  ol.steps li:not(.on) .step-name { display: none; }
  wa-dialog.wizard::part(footer) { flex-wrap: wrap; gap: 0.5rem; }
  wa-dialog.wizard > .wiz-go { order: -1; flex: 1 0 100%; }
}

/* ---------- Charts and Tournament Views ---------- */

/* Duel card (docs/system/ui.md#duel-card): the card IS the proportion — a clay-to-blue gradient split at side one's chance (the stops come from the view), everything on it white. */
.h2h-stage.duel { color: var(--white); border: none;
  background: linear-gradient(105deg, var(--clay-deep) 0%, var(--clay) var(--split-lo, 45%),
                              var(--blue) var(--split-hi, 55%), var(--blue-deep) 100%); }
.h2h-row { display: flex; align-items: stretch; gap: 1rem;
  justify-content: space-between; padding: 0.8rem 0 1.1rem; }
.h2h-face { flex: 1; text-align: center; padding: 0.8rem 0.4rem; }
.h2h-pct { font-size: var(--font-size-display); font-weight: 800; line-height: 1;
  letter-spacing: -0.02em; color: var(--white); font-variant-numeric: tabular-nums;
  text-shadow: 0 1px 2px var(--shade); }
.h2h-pct span { font-size: var(--wa-font-size-2xl); font-weight: 600; margin-left: 0.15rem;
  opacity: 0.75; }
.h2h-who { display: block; margin-top: 0.6rem; font-weight: 700;
  font-size: var(--font-size-l-plus); color: var(--white); }
.h2h-sub { margin-top: 0.2rem; font-size: var(--wa-font-size-m); opacity: 0.8; }
.h2h-vs { align-self: center; flex: 0 0 auto; width: 3.3rem; height: 3.3rem;
  border-radius: var(--wa-border-radius-circle); border: 1px solid var(--veil-line);
  background: var(--veil);
  display: flex; align-items: center; justify-content: center;
  font-weight: 700; font-size: var(--font-size-m-plus); color: var(--white);
  text-transform: uppercase; }
.h2h-note { font-size: var(--wa-font-size-m); opacity: 0.92; text-align: center;
  padding-bottom: 0.2rem; }
.h2h-stage.duel { position: relative; display: flex;
  flex-direction: column; justify-content: center; }
wa-button.h2h-share { position: absolute; top: 0.5rem; right: 0.6rem; margin: 0;
  --wa-color-brand-on-quiet: var(--white); opacity: 0.85; }
wa-button.h2h-share:hover { opacity: 1; }
.h2h-follow { display: inline-flex; align-items: center; gap: 0.3rem;
  margin-top: 0.4rem; color: var(--white); opacity: 0.75; font-size: var(--wa-font-size-m);
  text-decoration: underline; text-underline-offset: 2px; }
.h2h-follow:hover { opacity: 1; }

/* Rivalry chart (docs/system/ui.md#rivalry-chart): drawn at the card's own width, one unit one pixel. */
wa-card.h2h-chartcard::part(body) { padding-bottom: 0.6rem; }
.h2h-chartwrap { overflow-x: auto; }
.h2h-charthead { display: flex; align-items: baseline; gap: 0.8rem;
  margin-bottom: 0.5rem; }
.h2h-charthead .meta { margin: 0; }
.h2h-chart { max-width: 100%; height: auto; display: block; }
.h2h-line { fill: none; stroke: var(--clay-deep); stroke-width: 2.4;
  stroke-linejoin: round; stroke-linecap: round; }
.h2h-midline { stroke: var(--muted); stroke-width: 1;
  stroke-dasharray: 4 5; opacity: 0.5; }
.h2h-dot { fill: var(--white); stroke: var(--clay-deep); stroke-width: 2;
  cursor: pointer; }
.h2h-dot:hover { fill: var(--clay); }
.h2h-dot-now { fill: var(--clay); stroke: var(--white); stroke-width: 2;
  cursor: pointer; }
.h2h-halo { fill: none; stroke: var(--clay); stroke-width: 2;
  transform-box: fill-box; transform-origin: center;
  animation: h2h-halo 2s ease-out infinite; }
@keyframes h2h-halo {
  0% { transform: scale(0.6); opacity: 0.9; }
  70% { transform: scale(1.8); opacity: 0; }
  100% { transform: scale(1.8); opacity: 0; }
}
/* The chart's words are the page's: the body face at the kit's sizes, the quiet ink for the axis, each side's name in its own colour. */
.h2h-xlabel { font-family: var(--wa-font-family-body); font-size: var(--wa-font-size-xs);
  fill: var(--wa-color-text-quiet); }
.h2h-xlabel.h2h-blue { fill: var(--blue); font-weight: 600; }
.h2h-xlabel.h2h-clay { fill: var(--clay-deep); font-weight: 600; }
.h2h-pctlabel { font-family: var(--wa-font-family-body); font-size: var(--wa-font-size-s);
  font-weight: 700; fill: var(--clay-deep); }
.h2h-pctlabel.now { font-size: var(--wa-font-size-m); }
/* The hover targets a weekly chart lays over every point: they paint nothing while still taking the pointer. */
.elochart circle.chart-grab, .h2h-chart circle.chart-grab {
  fill: none; stroke: none; pointer-events: all; cursor: pointer; }
/* The chart cursor: a filled dot in the series' colour and a hairline guide, on the week under the pointer. */
.chart-cursor { fill: var(--clay-deep); stroke: var(--white); stroke-width: 2;
  pointer-events: none; }
.chart-cursor.el-s { fill: var(--blue); }
.chart-cursor.el-d { fill: var(--clay); }
.chart-guide { stroke: var(--muted); stroke-width: 1;
  stroke-dasharray: 3 4; opacity: 0.7; pointer-events: none; }
/* On a phone the duel stays side by side but shrinks to fit; the chart keeps its labels readable by scrolling in its own wrap. */
@media (max-width: 760px) {
  .h2h-pct { font-size: var(--font-size-3xl-plus); }
  .h2h-pct span { font-size: var(--wa-font-size-l); }
  .h2h-who { font-size: var(--wa-font-size-m); }
  .h2h-sub { font-size: var(--wa-font-size-xs); }
  .h2h-vs { width: 2.3rem; height: 2.3rem; font-size: var(--wa-font-size-xs); }
  .h2h-row { gap: 0.4rem; padding: 0.4rem 0 0.7rem; }
  .h2h-face { padding: 0.5rem 0.2rem; }
  .h2h-note { font-size: var(--wa-font-size-s); }
  .h2h-chart { min-width: 560px; }
  .h2h-charthead { flex-direction: column; gap: 0.15rem; }
}

/* Inline H2H (docs/system/ui.md#inline-h2h): it always sits at the right of its cell. */
td.h2hcol, td:has(> .h2hcell), th:has(> .h2hcell) { text-align: right; }
.h2hcell { font-size: var(--wa-font-size-s); color: var(--muted);
  white-space: nowrap; cursor: default; }
a.h2hcell { cursor: pointer; text-decoration: none; }
a.h2hcell:hover { text-decoration: underline; }
.h2hcell .arr { font-weight: 700; letter-spacing: -0.08em; }
.h2hcell.up .arr { color: var(--blue); }
.h2hcell.down .arr { color: var(--clay); }
.h2hcell .yy { width: 0.9em; height: 0.9em; vertical-align: -0.1em; }
.h2hcell.h2h-arrows { color: inherit; }

/* Knock-out draw (docs/system/ui.md#knock-out-draw): a round strip on top, then a window of flex columns, one per visible round; equal flex cells centre every match exactly between its two feeders, so the elbow connectors — a stub out of each feeder, a vertical join spanning the parent cell's middle half, a stub into the parent — line up by construction. The match boxes are raised kit surfaces with the kit's border and radius, the connectors in the kit's quiet border ink. */
/* The knock-out draw (docs/system/ui.md): the round strip on the kit's small pill buttons, the match boxes as raised kit surfaces with the kit's border and radius, the connectors in the kit's quiet border ink. */
wa-button-group.bk-navs { margin: 0.2rem 0 0.6rem; }
.bk-host { position: relative; }
.bk-wrap { overflow-x: auto; overflow-y: hidden; margin: 0 0 0.9rem;
  touch-action: pan-y; user-select: none; scrollbar-width: thin; }
.bk-wrap.can-drag { cursor: grab; }
.bk-wrap.can-drag.dragging { cursor: grabbing; }
.bk { display: flex; width: max-content; }
/* The arrows: over the sheet's edges, shown while the pointer is on the draw, one round back or on. */
.bk-arrow { position: absolute; top: 50%; transform: translateY(-50%);
  opacity: 0; transition: opacity 0.15s ease; z-index: 2; }
.bk-host:hover .bk-arrow, .bk-arrow:focus-within { opacity: 0.92; }
.bk-prev { left: 0.2rem; }
.bk-next { right: 0.2rem; }
.bk-round { width: 250px; flex: none; }
.bk-links { flex: none; }
.bk-links svg { display: block; }
.bk-links path { stroke: var(--wa-color-neutral-border-normal); stroke-width: 1.5; fill: none; }
.bk-round-name { font-size: var(--wa-font-size-xs); color: var(--wa-color-text-quiet);
  font-weight: 600; text-align: center; margin-bottom: 0.25rem; min-height: 1rem; }
.bk-col { display: flex; flex-direction: column; height: var(--col-h); }
.bk-cell { flex: 1; display: flex; flex-direction: column;
  justify-content: center; position: relative; }
.bk-match { border: 1px solid var(--wa-color-surface-border);
  border-radius: var(--wa-border-radius-m); background: var(--wa-color-surface-raised);
  box-shadow: var(--wa-shadow-s); overflow: hidden; position: relative; }
.bk-slot { padding: 0.3rem 0.6rem; font-size: var(--wa-font-size-s);
  display: flex; align-items: center; gap: 0.3rem; white-space: nowrap; }
.bk-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
/* A decided match's games, one column a set beside the names, each side's on its own row; a tie-break's points as a superscript on the games that lost it (2026-09-08). */
.bk-sets { display: inline-flex; flex: none; font-variant-numeric: tabular-nums; }
.bk-set { display: inline-flex; align-items: baseline; }
.bk-g { display: inline-block; min-width: 1.3em; text-align: right; }
.bk-tb { display: inline-block; width: 0.8em; font-size: var(--font-size-smaller-3); line-height: 1; }
.bk-slot .h2hcell { flex: none; font-size: var(--wa-font-size-xs); margin-left: auto; }
.bk-slot .mark { flex: none; margin-left: 0; }
.bk-slot + .bk-slot { border-top: 1px solid var(--wa-color-surface-border); }
.bk-empty { color: var(--wa-color-text-quiet); font-style: italic; }
.bk-line { display: inline-block; min-width: 1.6em; color: var(--wa-color-text-quiet);
  font-size: var(--wa-font-size-xs); font-style: normal; }
/* A winner on the success tint's normal shade — brighter than the quiet one the standings use, so a decided match reads at a glance (2026-09-08). */
.bk-win { font-weight: 700; background: var(--wa-color-success-fill-normal); }
.bk-you { color: var(--blue); font-weight: 650; }
.bk-champ { border-color: var(--wa-color-brand-border-loud); }
/* Pick mode (docs/system/predictions.md): an open slot a button, the reader's pick on the brand rule and tint with a check — green when right, the danger rule and a cross when wrong — TennisHub's a TH chip, a slot the reader's own pick filled in italics, a closed match under a lock. */
button.bk-slot { display: flex; width: 100%; text-align: left; font: inherit;
  font-size: var(--wa-font-size-s);  /* the reset's inherit took the box's size, not the slot's */
  color: inherit; background: none; border: 0; cursor: pointer; }
button.bk-slot:hover { background: var(--wa-color-neutral-fill-quiet); }
/* The reader's side while the match is open: the blue fill; once decided, a wrong pick's row on the darker red, a pick whose side never got there tinting the whole box on the lighter red (2026-09-08). */
.bk-slot.bk-picked { background: var(--blue-quiet); box-shadow: inset 3px 0 0 var(--blue); }
.bk-wrong { background: var(--wa-color-danger-fill-normal);
  box-shadow: inset 3px 0 0 var(--wa-color-danger-border-loud); }
.bk-match.bk-stale .bk-slot:not(.bk-win) { background: var(--wa-color-danger-fill-quiet); }
/* The fate badge (docs/system/predictions.md): a small ring outside the box, on the line leading out of the match — empty blue while open, blue with a check once picked, green when right, red when wrong or when the picked side never got there, quiet with a dash where nothing was picked. */
.bk-fate { position: absolute; top: 50%; right: 0; z-index: 1;
  transform: translate(calc(100% + 4px), -50%);
  width: 1.05rem; height: 1.05rem; border-radius: var(--wa-border-radius-circle); box-sizing: border-box;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--wa-color-surface-raised); border: 2px solid var(--wa-color-neutral-border-normal);
  color: var(--wa-color-text-quiet); font-size: var(--font-size-4xs); }
.bk-fate-open { border-color: var(--blue); }
.bk-fate-picked { border-color: var(--blue); background: var(--blue); color: var(--white); }
.bk-fate-right { border-color: var(--ok); background: var(--ok); color: var(--white); }
.bk-fate-wrong, .bk-fate-stale { border-color: var(--warn); background: var(--warn); color: var(--white); }
.bk-guess .bk-name { font-style: italic; }
.bk-fate-locked { font-size: var(--font-size-4xs); }
/* A fed final's line waiting on the reader's word (docs/system/predictions.md#ties-on-a-table): the empty slot a quiet blue "Choose…"; where a word broke a tie, the scales at the box's top right corner reopen the choice. */
button.bk-choose .bk-name { color: var(--blue); font-style: italic; }
.bk-tie { position: absolute; top: 0; right: 0; z-index: 1;
  transform: translate(calc(100% + 4px), -50%);
  width: 1.05rem; height: 1.05rem; border-radius: var(--wa-border-radius-circle); box-sizing: border-box; padding: 0;
  display: inline-flex; align-items: center; justify-content: center; cursor: pointer;
  background: var(--wa-color-surface-raised); border: 2px solid var(--blue);
  color: var(--blue); font-size: var(--font-size-4xs); }
.bk-tie:hover { background: var(--blue-quiet); }

/* Round-robin draw (docs/system/ui.md#round-robin-draw): sides down and across, a win on the success tint, a loss plain, a meeting to come a quiet dot, the diagonal lowered. */
table.rr th.rr-head { text-align: center; font-weight: 600; white-space: nowrap; }
table.rr th.rr-side { text-align: left; font-weight: 500; color: var(--ink);
  font-size: var(--wa-font-size-s); }
table.rr td { text-align: center; white-space: nowrap; font-variant-numeric: tabular-nums; }
table.rr td.rr-self { background: var(--wa-color-surface-lowered); }
table.rr td.rr-win { background: var(--wa-color-success-fill-normal); font-weight: 700; }
table.rr td.rr-open { color: var(--wa-color-text-quiet); }

/* Standings table (docs/system/ui.md#standings-table): promoted rows on the success tint with its rule, demoted on the danger tint with its rule, each in a lighter shade where the feed only says "may". */
table.standings tr.up td { background: var(--wa-color-success-fill-quiet); }
table.standings tr.up td:first-child { box-shadow: inset 3px 0 0 var(--ok); }
table.standings tr.up2 td { background: color-mix(in srgb, var(--wa-color-success-fill-quiet) 45%, var(--card)); }
table.standings tr.up2 td:first-child { box-shadow: inset 3px 0 0 color-mix(in srgb, var(--ok) 45%, var(--card)); }
table.standings tr.down td { background: var(--wa-color-danger-fill-quiet); }
table.standings tr.down td:first-child { box-shadow: inset 3px 0 0 var(--warn); }
table.standings tr.down2 td { background: color-mix(in srgb, var(--wa-color-danger-fill-quiet) 45%, var(--card)); }
table.standings tr.down2 td:first-child { box-shadow: inset 3px 0 0 color-mix(in srgb, var(--warn) 45%, var(--card)); }

/* Meetings grid (docs/system/ui.md#meetings-grid): the same table, ticked rather than read. Only the lower triangle carries a box — a meeting is one cell, not two — the halves of the table are shaded apart (the pots a league draws from), and a row whose count is not what it owes says so on the danger tint. */
table.rr.mt td.mt-mirror { background: var(--wa-color-surface-lowered); }
table.rr.mt td.mt-cell { padding: 0.15rem; }
table.rr.mt td.mt-other { background: var(--wa-color-neutral-fill-quiet); }
table.rr.mt tr.mt-split > * { border-top: 2px solid var(--wa-color-neutral-border-loud); }
table.rr.mt .mt-box { width: 1.05rem; height: 1.05rem; margin: 0; cursor: pointer;
  accent-color: var(--blue); }
table.rr.mt td.mt-count, table.rr.mt th.mt-count { font-weight: 700;
  border-right: 2px solid var(--wa-color-neutral-border-loud); padding: 0 0.5rem; }
table.rr.mt td.mt-count.mt-short { background: var(--wa-color-danger-fill-quiet);
  color: var(--wa-color-danger-on-quiet); }

/* Podium (docs/system/ui.md#podium): a card per event in a grid that wraps, a quiet line naming the draw where the event has several, and the places in the facts list — the winner's row on the success tint so the eye lands there first. */
.podiums { display: grid; grid-template-columns: repeat(auto-fill, minmax(17rem, 1fr));
  gap: var(--wa-space-m); align-items: start; }
.podium .podium-draw { margin: var(--wa-space-s) 0 var(--wa-space-2xs); font-weight: 600;
  color: var(--muted); font-size: var(--wa-font-size-s); }
.podium .podium-draw:first-of-type { margin-top: 0; }
.podium .podium-list { margin: 0 0 var(--wa-space-2xs); align-items: center; }
.podium .podium-list dd.podium-1 { background: var(--wa-color-success-fill-quiet);
  border-radius: var(--wa-border-radius-s); padding: 0 var(--wa-space-2xs); }

/* Countdown (docs/system/ui.md#countdown): four ticking numerals, pulsing colons, the words beneath saying what the moment is. */
.countdown { display: block; margin: 0.4rem 0 0.5rem; animation: cd-in 0.6s ease-out;
  font-weight: 400; line-height: 1.2; }
.cd-row { display: flex; align-items: flex-start; gap: 0.3rem; }
/* The small one: a line beside a heading, the caption at its side. */
.countdown.cd-s { display: inline-flex; align-items: center; gap: 0.5rem;
  margin: 0; vertical-align: middle; }
.cd-s .cd-row { gap: 0.15rem; align-items: baseline; }
.cd-s .cd-cell { min-width: 1.3rem; }
.cd-s .cd-num { font-size: var(--wa-font-size-m); font-weight: 700; }
.cd-s .cd-unit { font-size: var(--font-size-4xs); }
.cd-s .cd-sep { font-size: var(--wa-font-size-s); line-height: 1.1; }
.cd-s .cd-to { font-size: var(--wa-font-size-xs); margin: 0; }
.cd-cell { display: inline-flex; flex-direction: column;
  align-items: center; min-width: 2.1rem; }
.cd-num { font-size: var(--font-size-xl-plus); font-weight: 800; line-height: 1;
  color: var(--clay-deep); font-variant-numeric: tabular-nums; }
.cd-num.cd-tick { animation: cd-tick 0.5s ease-out; }
.cd-unit { font-size: var(--font-size-3xs); color: var(--muted);
  text-transform: uppercase; letter-spacing: 0.06em; }
.cd-sep { font-size: var(--font-size-l-plus); font-weight: 800; color: var(--clay);
  line-height: 1.25; animation: cd-blink 1s ease-in-out infinite; }
.cd-to { display: block; font-size: var(--wa-font-size-s); color: var(--muted); margin-top: 0.15rem; }
@keyframes cd-in { from { opacity: 0; transform: translateY(6px); }
  to { opacity: 1; transform: none; } }
@keyframes cd-tick { from { transform: translateY(-0.35em);
  opacity: 0.2; } to { transform: none; opacity: 1; } }
@keyframes cd-blink { 0%, 100% { opacity: 1; } 50% { opacity: 0.25; } }
@media (prefers-reduced-motion: reduce) {
  .countdown, .cd-num.cd-tick, .cd-sep { animation: none; } }

/* ---------- Mail ---------- */

/* The frame a mail is shown in (docs/system/ui.md#mail-template): the width of the page, on the page's own ground. */
.mail-frame { display: block; width: 100%; height: 34rem; border: 0; border-radius: var(--wa-border-radius-m); background: var(--paper); }

/* ======================================================================
   PAGES. Each page's own classes, in the menu's order.
   ====================================================================== */

/* ---------- Login ---------- */
.loginerror { text-align: left; margin: 0.9rem 0; }
.loginwrap {
  min-height: 100vh; display: flex; align-items: center; justify-content: center;
  background: linear-gradient(160deg, var(--clay-deep) 0%, var(--clay-dark) 100%);
}
.logincard {
  background: var(--card); border-radius: var(--wa-border-radius-l); padding: 2.2rem 2.4rem;
  width: min(92vw, 380px); text-align: center;
  box-shadow: 0 18px 50px var(--shade-deep);
}
.logincard .brand { color: var(--ink); font-size: var(--wa-font-size-xl); }
.logincard .loginart { width: 100%; margin-top: 0.6rem; }
.logincard .brand .hub { background: var(--clay); color: var(--white); }
.logincard p { color: var(--muted); margin: 0.4rem 0 1.4rem; }
.logincard .gsi { display: flex; justify-content: center; }
/* The login page's request-access link and form. */
.reqlink { margin: 0.8rem 0 0; }
#req-form { text-align: left; margin-top: 0.6rem; }
/* The login card's forms are the form block (docs/system/ui.md), left-aligned on the centred card; beneath the Google button. */
.logincard .login-form { text-align: left; margin: 0.6rem 0 0.8rem; }
.logincard .login-form .row { margin-bottom: 0.55rem; }
.logincard .login-form .row.one { grid-template-columns: minmax(0, 1fr); }
.req-head { display: flex; justify-content: space-between;
  align-items: baseline; margin-bottom: 0.5rem; }
.req-head a { color: var(--muted); font-size: var(--wa-font-size-l);
  text-decoration: none; line-height: 1; }
#req-form .f, .req-row .f { display: flex; flex-direction: column;
  gap: 0.2rem; }
#req-form label, .req-row .f label { font-size: var(--wa-font-size-xs);
  color: var(--muted); min-height: 1em; }
#req-form input, .req-row .f input {
  border: 1px solid var(--line); border-radius: var(--wa-border-radius-m);
  padding: 0.45rem 0.6rem; font: inherit; background: var(--card); }
#req-form input:focus, .req-row .f input:focus {
  outline: 2px solid var(--blue-bright); outline-offset: 0;
  border-color: var(--blue); }
#req-form .f { margin-bottom: 0.5rem; }
#req-form input { width: 100%; }
#req-form wa-button { margin-top: 0.2rem; }
#req-form wa-callout, #req-note wa-callout { margin-top: 0.5rem; }

/* ---------- Dashboard ---------- */
/* The tile grid. Columns 2/3/4/5 by viewport, rows a fixed 150px unit, dense flow so small tiles backfill the holes wide ones leave. Importance bands style the tiles: accent / card / border / naked. */
.dash-tabs { margin: 0 0 1rem; }
.dash-grid { display: grid; gap: 16px;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  grid-auto-rows: 150px; grid-auto-flow: dense; max-width: 1600px; }
@media (min-width: 640px) {
  .dash-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (min-width: 1024px) {
  .dash-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
@media (min-width: 1440px) {
  .dash-grid { grid-template-columns: repeat(5, minmax(0, 1fr)); } }
/* overflow stays visible so the border chips can sit astride the edge; the body is the scroll container that actually clips. */
.gtile { border-radius: var(--wa-border-radius-l); padding: 0.8rem 1rem; display: flex;
  flex-direction: column; min-width: 0; position: relative; }
.gtile-img { overflow: hidden; }
.t-w1 { grid-column: span 1; }
.t-w2 { grid-column: span 2; }
.t-w3 { grid-column: span 3; }
.t-h1 { grid-row: span 1; }
.t-h2 { grid-row: span 2; }
.t-h3 { grid-row: span 3; }
.t-h4 { grid-row: span 4; }
@media (max-width: 639px) { .t-w3 { grid-column: span 2; } }
/* The five visual themes, painted by dashLayout so touching tiles — corners included — never share one. General tiles wear them as filled backgrounds; linked tiles (gtile-linked) wear them as coloured borders on the page ground, so the border chips straddle cleanly. All five keep the ink dark. */
.th-0 { background: var(--card); box-shadow: 0 1px 5px var(--shade-soft); }
.th-1 { border: 1px solid var(--line); }
.th-2 { background: var(--tile-blue); }
.th-3 { background: var(--tile-clay); }
.th-4 { background: var(--tile-green); }
.gtile-linked.th-0 { background: none; box-shadow: none;
  border: 2px solid var(--blue-line); }
.gtile-linked.th-1 { border: 2px solid var(--wa-color-brand-border-normal); }
.gtile-linked.th-2 { background: none; border: 2px solid var(--wa-color-success-border-normal); }
.gtile-linked.th-3 { background: none; border: 2px solid var(--line-deep); }
.gtile-linked.th-4 { background: none; border: 2px solid var(--wa-color-warning-border-normal); }
.gtile-img { padding: 0; }
/* Breadcrumb and border title share one chip on the tile's top border, legend-style — "SeRCE › C Singles › Path to trophy 🏆" — with the page-paper background covering the border line beneath. */
.crumb { position: absolute; top: -0.68em; z-index: 1; left: 10px;
  max-width: calc(100% - 32px); padding: 0 6px;
  background: var(--paper); font-size: var(--wa-font-size-xs); color: var(--muted);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* Tiles never grow a scrollbar of their own; only the folding surfaces — tables, the draw sheet, the day plan's match list — may scroll inside their tile. */
.gtile-body { flex: 1 1 auto; min-height: 0; overflow: hidden; }
.gtile:is(:has(.tablewrap), :has(.bk-host), :has(.m-line)) .gtile-body {
  overflow: auto; }
.gtile h3 { margin: 0 0 0.35rem; font-size: var(--wa-font-size-m); }
.gtile .meta { margin: 0 0 0.15rem; }
.gtile td.h2hcol { text-align: right; }
/* Names wrap inside a tile: a doubles pair's two names pushed the table past the tile and the verdict column off its edge (2026-09-02). The verdict keeps to one line. */
.gtile table td:first-child { white-space: normal; }
.gtile img.fill { width: 100%; height: 100%; object-fit: cover;
  border-radius: var(--wa-border-radius-l); display: block; }
.gtile-hero .gtile-body { display: flex; flex-direction: column;
  justify-content: center; overflow: hidden; }
/* One sentence, one size, black and blue only. */
.gtile-hero .dash-hello { font-size: var(--font-size-2xl-plus); font-weight: 800; }
.dash-name { color: var(--blue); }
/* The You tile: question rows, muted question left, bold answer right, hairlines between — the status pill closes the square. */
.gtile-you .gtile-body { display: flex; flex-direction: column;
  justify-content: space-evenly; }
.gtile-you .gtile-body h3 { margin: 0; font-size: var(--font-size-m-plus);
  color: var(--clay-deep); }
.you-row { display: flex; justify-content: space-between;
  align-items: baseline; gap: 0.5rem; padding: 0.3rem 0;
  border-bottom: 1px solid var(--line); font-size: var(--wa-font-size-s);
  color: var(--muted); }
.you-row:last-of-type { border-bottom: none; }
.you-row strong { color: var(--ink); font-size: var(--font-size-m-plus);
  white-space: nowrap; }
.you-status { margin: 0; text-align: center; }
/* A tile's proper title: the You tiles' look, shared by name. */
.gtile h3.gtile-title { font-size: var(--font-size-m-plus); color: var(--clay-deep); }
/* The Win tile fills its square: title up, territory chart centred (the H2H rivalry chart's look), link down. */
.gtile-win .gtile-body { display: flex; flex-direction: column;
  justify-content: space-between; }
.gtile-win .win-pct { float: right; color: var(--blue); }
.win-chart { width: 100%; flex: 1 1 auto; min-height: 0;
  margin: 0.3rem 0; }
/* The shape tile: four question rows must fit the square. */
.gtile-shape .you-row { padding: 0.14rem 0; }
/* The tournament tile's face and links. */
/* The tournament tile: name and image up top, the clock as the centrepiece, the facts and links along the floor. */
.t-tile { display: flex; flex-direction: column;
  justify-content: space-between; height: 100%; }
.t-head { display: flex; justify-content: space-between;
  align-items: flex-start; gap: 0.7rem; }
.t-logo { flex: 0 1 26%; max-width: 26%; max-height: 4.6rem;
  object-fit: contain; object-position: top right; border-radius: var(--wa-border-radius-m); }
.t-tile .countdown { align-self: center; text-align: center;
  margin: 0.2rem 0; }
.t-tile .cd-row { justify-content: center; }
.t-tile .cd-num { font-size: var(--font-size-2xl-plus); }
.t-foot .meta { margin: 0 0 0.1rem; }
/* A bare anchor (no href) skips the UA's link look — restore it. */
.t-refresh a[data-trefresh] { text-decoration: underline; cursor: pointer; }
/* The tightening steps (fitTournamentTiles): the clock first, with status and dates sharing a line; then the "to the first serve" line goes and the floor's type follows the tile. */
.t-tile.t-tight .cd-num { font-size: var(--wa-font-size-xl); }
.t-tile.t-tight .cd-sep { font-size: var(--font-size-m-plus); line-height: 1.15; }
.t-tile.t-tight .countdown { margin: 0; }
.t-tile.t-tight .t-head .meta { display: inline-block; margin: 0 0.5rem 0 0; }
.t-tile.t-tight .gtile-title { margin-bottom: 0.15rem; }
.t-tile.t-tighter .cd-to { display: none; }
.t-tile.t-tighter .t-foot .meta { font-size: var(--wa-font-size-xs); line-height: 1.25; }
/* The followed-players tile refreshes from its own title. */
.folnews-refresh { font-size: var(--wa-font-size-xs); font-weight: 400;
  text-decoration: underline; cursor: pointer; margin-left: 0.5rem; }
/* The Matchup tile: the share card in miniature — clay against blue, white type, the vs badge riding the frontier. */
.gtile-mday { padding: 0; border: none; }
.gtile-mday .gtile-body { overflow: hidden; border-radius: var(--wa-border-radius-l); }
.mday { display: flex; flex-direction: column; height: 100%;
  color: var(--white); padding: 0.7rem 0.8rem;
  background: linear-gradient(105deg, var(--clay-deep) 0%, var(--clay) var(--split-lo, 45%),
                              var(--blue) var(--split-hi, 55%), var(--blue-deep) 100%); }
.mday-links { display: flex; justify-content: space-between;
  font-size: var(--wa-font-size-xs); }
.mday-links a { color: var(--white); opacity: 0.92;
  display: inline-flex; align-items: center; gap: 0.25rem; }
.mday-links wa-icon { font-size: var(--wa-font-size-smaller); }
.mday-title { text-align: center; font-weight: 700;
  font-size: var(--wa-font-size-s); opacity: 0.95; }
.mday-row { flex: 1 1 auto; display: flex; align-items: center;
  justify-content: space-between; gap: 0.4rem; }
.mday-half { flex: 1 1 0; text-align: center; min-width: 0; }
.mday-pct { font-size: var(--wa-font-size-xl); font-weight: 800; line-height: 1.1; }
.mday-name { font-size: var(--wa-font-size-xs); font-weight: 650; overflow-wrap:
  break-word; }
.mday-vs { flex: 0 0 auto; width: 1.9rem; height: 1.9rem;
  border: 1px solid var(--veil-line); border-radius: var(--wa-border-radius-circle);
  display: inline-flex; align-items: center; justify-content: center;
  font-size: var(--wa-font-size-s); }
/* The venue's own picture fills the tile's second row. */
.v-img { display: block; width: 100%; aspect-ratio: 1;
  object-fit: contain; margin-bottom: 0.5rem; }
.m-pot { font-weight: 650; color: var(--clay-deep);
  font-size: var(--wa-font-size-s); white-space: nowrap; }
/* Path to trophy: one card per match ahead — round name and its candidates bound inside the same card. */
.road { display: flex; flex-direction: column; gap: 0.5rem; }
.road-step { background: var(--card); border: 1px solid var(--line);
  border-radius: var(--wa-border-radius-l); padding: 0.35rem 0.7rem; }
.road-round { font-weight: 650; color: var(--clay-deep);
  font-size: var(--wa-font-size-s); padding: 0.15rem 0; }
.road-opp { display: flex; justify-content: space-between;
  align-items: baseline; gap: 0.6rem; padding: 0.3rem 0;
  border-top: 1px solid var(--line); min-width: 0; }
/* The Elo tile: the legend rides the title row, so the chart takes the whole body and nothing below it can be cut. */
.gtile-elo .gtile-body { display: flex; flex-direction: column; }
.gtile-elo .gtile-title { display: flex; justify-content: space-between;
  align-items: baseline; gap: 0.6rem; }
.gtile-elo .gtile-title > span:first-child { min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.el-legend { font-size: var(--wa-font-size-xs); font-weight: 400; color: var(--muted);
  white-space: nowrap; }
.elochart { width: 100%; height: auto; flex: 1 1 auto; min-height: 0;
  display: block; }
.elochart path { fill: none; stroke-width: 2; stroke-linejoin: round;
  stroke-linecap: round; }
.elochart circle.el-now.el-s { fill: var(--blue); stroke: var(--white);
  stroke-width: 1.8; }
.elochart circle.el-now.el-d { fill: var(--clay); stroke: var(--white);
  stroke-width: 1.8; }
/* The Elo tile always reads on white, whatever the themes deal. */
.gtile-elo { background: var(--card); }
/* Filler art floats free: its torn edge is the frame. */
.gtile-img { background: none; border: none; box-shadow: none; }
.gtile-img img.fill { object-fit: contain; border-radius: 0; }
.elochart path.el-s { stroke: var(--blue); }
.elochart path.el-d { stroke: var(--clay); }
.elochart text { font-size: var(--wa-font-size-2xs); font-weight: 700; stroke: none; }
.elochart text.el-s { fill: var(--blue); }
.elochart text.el-d { fill: var(--clay); }
.el-key.el-s { color: var(--blue); }
.el-key.el-d { color: var(--clay); }
.m-line { display: flex; flex-wrap: wrap; align-items: baseline;
  gap: 0.45rem; padding: 0.3rem 0;
  border-bottom: 1px solid var(--line); font-size: var(--wa-font-size-m); }
.m-time { font-weight: 700; min-width: 2.9em; }
.m-who .m-win { font-weight: 700; }
.m-score { font-variant-numeric: tabular-nums; }
.m-wx { color: var(--muted); font-size: var(--wa-font-size-s); white-space: nowrap; }
.m-day { margin: 0.6rem 0 0.2rem; font-size: var(--wa-font-size-xs);
  text-transform: uppercase; letter-spacing: 0.04em;
  color: var(--muted); }
.news-item { padding: 0.35rem 0; border-bottom: 1px solid var(--line);
  font-size: var(--wa-font-size-s); }
.news-at { color: var(--muted); font-size: var(--wa-font-size-xs);
  margin-right: 0.4rem; }
.news-ev { color: var(--clay-deep); font-size: var(--wa-font-size-xs); }
.news-nav { display: flex; align-items: center; gap: 0.6rem;
  justify-content: center; padding-top: 0.4rem; flex: none; }
/* The pager is pinned: only the items area may clip. */
.gtile:has(.news-body) .gtile-body { display: flex;
  flex-direction: column; }
.news-body { flex: 1 1 auto; min-height: 0; display: flex;
  flex-direction: column; }
.news-items { flex: 1 1 auto; min-height: 0; overflow: hidden; }
/* The Weather tile is 1×2: one white card per day, the stack stretched to fill the tile. */
.dash-weather { display: flex; flex-direction: column; gap: 0.5rem;
  height: 100%; }
.dash-day { border: 1px solid var(--line); border-radius: var(--wa-border-radius-l);
  padding: 0.4rem 0.7rem; text-align: center;
  background: var(--card); flex: 1 1 0; display: flex;
  flex-direction: column; justify-content: center; }
.dash-day-st { display: flex; flex-wrap: wrap; gap: 0.25rem;
  justify-content: center; margin-top: 0.25rem; }
.wx-st { font-size: var(--wa-font-size-2xs); padding: 0.1rem 0.5rem;
  border-radius: var(--wa-border-radius-pill); background: var(--line); color: var(--ink); }
.wx-st.wx-perfect { background: var(--wx-perfect); color: var(--wx-perfect-ink); }
.wx-st.wx-drizzle { background: var(--blue-fill); color: var(--blue-deep); }
.wx-st.wx-rain { background: var(--wx-rain); color: var(--blue-deep); }
.wx-st.wx-heavy { background: var(--blue); color: var(--white); }
.wx-st.wx-wind { background: var(--wx-wind); color: var(--wx-wind-ink); }
.wx-st.wx-gusts { background: var(--wx-gusts); color: var(--white); }
.wx-st.wx-chilly { background: var(--wx-chilly); color: var(--wx-chilly-ink); }
.wx-st.wx-cold { background: var(--wx-cold); color: var(--wx-cold-ink); }
.wx-st.wx-hot { background: var(--wx-hot); color: var(--clay-deep); }
.wx-st.wx-xhot { background: var(--wx-xhot); color: var(--white); }
.dash-day-name { font-size: var(--wa-font-size-xs); color: var(--muted); }
.dash-day-icon { font-size: var(--font-size-l-plus); line-height: 1.5; }
.dash-day-temp { font-size: var(--wa-font-size-s); font-weight: 600; }
.dash-day-rain { font-size: var(--wa-font-size-xs); color: var(--muted); }
.dash-details { margin-left: 0.35rem; }
.dash-sep .why { color: var(--muted); font-size: var(--wa-font-size-s);
  text-align: right; }
.dash-you td { color: var(--blue); font-weight: 650; }
@media (max-width: 700px) {
  .gtile-hero .dash-hello { font-size: var(--wa-font-size-xl); }
}
/* The suggestions tile's wave-away cross. */
.sug-x a { cursor: pointer; color: var(--muted); font-size: var(--wa-font-size-m);
  padding: 0 0.3rem; text-decoration: none; }
.sug-x a:hover { color: var(--clay); }
/* On the matchup tile's gradient the blue would vanish — the bell stays white. */
.mday .fbell { opacity: 0.65; }
.mday .fbell.on { color: var(--white); }
/* The Report match result tile (2026-09-03): the title, the blurb, the call to action, spread evenly down a 1×1 square (2026-09-04) — the Your matches link went; the profile tab is a click away. A border on the page ground, no fill, outside the theme rotation. */
.gtile-report { background: none; border: 2px solid var(--wa-color-brand-border-normal); }
.gtile-report .gtile-body, .gtile-call .gtile-body { display: flex; flex-direction: column;
  justify-content: space-evenly; }
.gtile-report .gtile-title, .gtile-call .gtile-title { margin: 0; }
/* A tile's blurb and act — the Report, Entries-open and Open-predictions tiles (2026-09-14). */
.gtile-blurb { margin: 0; color: var(--muted); font-size: var(--wa-font-size-s); }
.gtile-call .gtile-blurb { color: inherit; opacity: 0.85; }
.gtile-acts { display: flex; align-items: flex-start; }
/* The Create player profile tile (docs/system/dashboard.md, 2026-09-29): the one thing an account with no player has to do — the brand's own fill, outside the theme rotation, its button the light one. */
.gtile.gtile-profile { background: linear-gradient(160deg, var(--clay-deep) 0%, var(--clay-dark) 100%);
  color: var(--white); border: 0; box-shadow: 0 10px 26px var(--shade); }
.gtile-profile .gtile-body { padding: 0.4rem 0.6rem; }
.gtile-profile h3.gtile-title { color: var(--white); font-size: var(--font-size-xl-plus); line-height: 1.15; }
.gtile-profile .gtile-blurb { font-size: var(--wa-font-size-m); opacity: 0.92; }
.gtile-profile-icon { font-size: var(--wa-font-size-3xl); opacity: 0.9; }
.gtile-profile a.gtile-go { background: var(--white); color: var(--clay-deep); font-size: var(--font-size-m-plus);
  padding: 0.7rem 1.3rem; }
.gtile-profile a.gtile-go:hover { background: var(--paper); }
/* The calibration tile wears the same fill at half the height. */
.gtile-calibrate h3.gtile-title { font-size: var(--font-size-l-plus); }
.gtile-calibrate .gtile-blurb { font-size: var(--wa-font-size-m); }
.gtile-calibrate a.gtile-go { font-size: var(--wa-font-size-m); padding: 0.55rem 1.1rem; }
a.gtile-go { display: inline-block; background: var(--clay); color: var(--white);
  border-radius: var(--wa-border-radius-m); padding: 0.5rem 1rem; font-weight: 600;
  text-decoration: none; }
a.gtile-go:hover { background: var(--clay-deep); }

/* ---------- The profile wizard, the Join dialog and the calibration wizard ---------- */
/* The player under "Is this you?": the kit's card with its slots — the name and where they play in its header, their matches in its body, the question in its footer and its answers the footer's actions. */
.wiz-card { margin-top: 0.4rem; }
.wiz-who { display: flex; flex-wrap: wrap; align-items: center; gap: 0.4rem 0.8rem; }
.wiz-who .cardtitle { margin: 0; }
.wiz-pills { display: inline-flex; flex-wrap: wrap; gap: 0.3rem; }
.wiz-card th:first-child, .wiz-card td:first-child { padding-left: 0; }
.wiz-card th:last-child, .wiz-card td:last-child { padding-right: 0; }
.wiz-card tbody tr:last-child td { border-bottom: 0; }
.wiz-card::part(footer) { flex-wrap: wrap; gap: 0.6rem 1rem; }
/* A competition and, beside its name, the matches played in it: on one line, centred on each other — `.meta` brings a paragraph's margins, which set the count beneath the name's line. */
.wiz-list { display: grid; gap: 0.55rem; margin-bottom: 0.4rem; }
.wiz-row { display: flex; flex-wrap: wrap; align-items: center; gap: 0.2rem 0.8rem; }
.wiz-row .meta { margin: 0; line-height: 1; }
/* Beneath a ticked competition that asks for an id: the field on a line of its own under the name — the row's whole width, so it never sits beside the checkbox — the form's own lone-field row inside. */
.wiz-field { flex: 0 0 100%; grid-column: 1 / -1; padding: 0.3rem 0 0.5rem 1.9rem; }
/* Beside a competition's name: how it is joined, and what was played. */
.wiz-note { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 0.3rem 0.6rem; }
/* The name leads and the reason follows it, a size down. */
table.wiz-follow .why { font-size: var(--wa-font-size-s); }
.wiz-followed { margin: 0.8rem 0 0; line-height: 1.9; }
.wiz-chip { display: inline-block; margin-left: 0.6rem; white-space: nowrap; }
@media (max-width: 700px) {
  /* A match in three lines: where, then the day and the result, then against whom. */
  .wiz-card table.stack > tbody > tr { padding: 0.5rem 0; }
  .wiz-card table.stack > tbody > tr > td.line { flex: 0 1 auto; }
  .wiz-card table.stack > tbody > tr > td.wiz-against { order: 1; flex: 1 0 100%; }
  .wiz-card::part(footer) { flex-direction: column; align-items: stretch; }
  .wiz-card wa-button[slot="footer-actions"] { width: 100%; }
  /* The question, then its accent, then the quiet answer: the footer's two slots are one column here, and the accent alone moved up would stand above what it answers. */
  .wiz-card [slot="footer"] { order: -2; }
  .wiz-card wa-button[slot="footer-actions"][variant="brand"] { order: -1; }
  /* A competition a row the finger finds, its count at the row's end. */
  .wiz-list { gap: 0; }
  .wiz-row { display: grid; grid-template-columns: 1fr auto; min-height: 2.75rem;
    border-bottom: 1px solid var(--line); }
  .wiz-row wa-checkbox { white-space: normal; }
  table.wiz-follow.stack > tbody > tr { padding: 0.45rem 0; min-height: 2.75rem; }
  table.wiz-follow.stack > tbody > tr > td.lead { font-size: var(--wa-font-size-m); }
  .wiz-chip { margin: 0 0.6rem 0 0; }
}
/* The calibration wizard's rows of a match: a thin rule between them. */
.wiz-match { padding-top: 0.6rem; border-top: 1px solid var(--line); }
.wiz-match:first-child { border-top: 0; padding-top: 0; }
.wiz-match.kept .row { opacity: 0.6; }
.wiz-sub { margin: 0 0 1.2rem; }
.wiz-more { margin: 0.9rem 0 0; }
.wm-said { display: inline-flex; white-space: nowrap; }
/* The calibration wizard's question (docs/system/ratings.md#the-calibration-wizard): one player, the seven answers as the H2H arrows over their words, and the way past a player not known. */
.rate-card { border: 1px solid var(--line); border-radius: var(--wa-border-radius-l); background: var(--surface, var(--card)); padding: 1rem 1.1rem; }
.rate-who { font-size: var(--wa-font-size-l); display: flex; align-items: center; gap: 0.4rem; }
.rate-ask { margin: 0.9rem 0 0.5rem; font-weight: 600; }
.rate-scale { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 0.4rem; }
.rate-pick { display: flex; flex-direction: column; align-items: center; justify-content: flex-start; gap: 0.3rem;
  min-height: 4.2rem; padding: 0.55rem 0.2rem; border: 1px solid var(--line); border-radius: var(--wa-border-radius-m);
  background: var(--paper); color: inherit; font: inherit; font-size: var(--wa-font-size-xs); line-height: 1.2;
  text-align: center; cursor: pointer; }
.rate-pick:hover:not(:disabled) { border-color: var(--clay); background: color-mix(in srgb, var(--clay) 8%, var(--card)); }
.rate-pick:disabled { opacity: 0.5; cursor: default; }
.rate-pick .h2hcell { font-size: var(--wa-font-size-l); }
.rate-skip { margin: 0.8rem 0 0; }
.rate-own { margin-top: 1.1rem; }
.rate-level { display: flex; flex-direction: column; gap: 0.1rem; }
.rate-level strong { font-size: var(--wa-font-size-2xl); line-height: 1.1; }
.rate-level strong .meta { font-size: var(--wa-font-size-m); font-weight: 400; }
.rate-level strong .mark { font-size: var(--wa-font-size-m); vertical-align: super; margin-left: 0.1em; }
@media (max-width: 700px) {
  .rate-scale { grid-template-columns: 1fr; }
  .rate-pick { flex-direction: row; justify-content: flex-start; min-height: 2.75rem; padding: 0.4rem 0.8rem; gap: 0.7rem;
    font-size: var(--wa-font-size-s); }
  .rate-pick .h2hcell { min-width: 2.6rem; text-align: center; }
}

/* ---------- Social sessions ---------- */
/* The social courts' dialog (docs/system/social-tennis.md#the-order-by-level). */
wa-dialog.courts { --width: 38rem; }
/* The social courts' order: a narrow place field a row. */
wa-dialog.courts td.seed wa-input { width: 3.6rem; }
wa-dialog.courts .tablewrap { margin-bottom: 1rem; }

/* ---------- Matches ---------- */
/* Where to play and who books, above the slot picker (docs/system/matches.md#lets-play). */
.play-where .disc-players:empty { display: none; }
/* The invitation's dialog (docs/system/matches.md#inviting-to-play): the proposals as a list that scrolls inside it. */
wa-dialog.invite { --width: 40rem; }
wa-dialog.invite .tablewrap { max-height: 55vh; overflow-y: auto; }
wa-dialog.invite .invite-count { margin-right: auto; }
wa-dialog.invite td.swords { font-size: var(--wa-font-size-l); line-height: 1; width: 2rem; text-align: center; color: var(--clay-deep); }
wa-dialog.invite tr.off td { opacity: 0.45; }
wa-dialog.invite tr[data-pick]:focus-visible { outline: 2px solid var(--clay); outline-offset: -2px; }
wa-dialog.invite .form { margin-bottom: 0.8rem; }
/* The invitations' lists: an invitation's time options, one under the other; one no longer on offer is struck through. */
.slot-list { display: flex; flex-direction: column; align-items: flex-start; gap: 0.3rem; }
.slot-off { color: var(--muted); text-decoration: line-through; }

/* ---------- Reporting a result and the match view ---------- */
/* The report page: three stacked steps, revealed in turn. */
.rs-head { display: flex; align-items: baseline; gap: 0.6rem;
  margin-bottom: 0.6rem; }
.rs-head h2 { margin: 0; }
/* The pending matches (docs/system/ui.md#form-field): a radio group, each match a row of its own — the kit's radio with the row's pieces inside. */
.rs-rows { margin: 0.4rem 0; }
/* A pick folds the list to the picked row (docs/system/matches.md, 2026-09-20): the other rows go, and the outlined Unselect stands level with the one left, at the line's end. */
.rs-pick-line { display: flex; align-items: flex-end; gap: 0.6rem; }
.rs-pick-line wa-radio-group { flex: 1; min-width: 0; }
.rs-rows.picked wa-radio.rs-row:not(.on) { display: none; }
/* The kit leaves 6px under its last radio: the button's margin adds it, so its centre meets the row's. */
.rs-unpick { margin-bottom: calc(0.4rem + 6px); white-space: nowrap; }
wa-radio.rs-row { display: flex; padding: 0.45rem 0.3rem;
  border-bottom: 1px solid var(--line); }
wa-radio.rs-row.on { background: var(--blue-quiet); }
.rs-row-body { display: inline-flex; flex-wrap: wrap; gap: 0.6rem; align-items: center; }
.rs-when { font-weight: 700; font-variant-numeric: tabular-nums; }
.rs-crumb { color: var(--muted); font-size: var(--wa-font-size-s); }
/* The match view: its series, its pills, its trace. */
.rs-series { margin: 0.9rem 0 0.7rem; }
.rs-pill-row { margin: 0 0 0.5rem; }
.rs-trace { margin: 0 0 0.6rem 1.2rem; }
.wrap-any { word-break: break-all; }
#rs-head .meta { margin: 0.2rem 0 0.8rem; }

/* ---------- Tournaments ---------- */
/* A fee a withdrawn player had paid: read, not ticked (docs/system/tournaments.md#withdrawn-players). */
.tick-paid { color: var(--blue); }
/* The plan page (docs/system/tournaments.md#running-a-tournament): the acts under a phase's draws, the pairing row inside its callout. */
.plan-acts { display: flex; gap: 0.5rem; flex-wrap: wrap; margin-top: 0.8rem; }
.plan-pair { margin-top: 0.6rem; }
.plan-dates { margin-top: 0.8rem; }
.plan-dates .row { margin-bottom: 0.3rem; max-width: 30rem; }

/* The entry page: the organisers' contacts, a short list under the closed-entry callout. */
.en-org { margin: 0.8rem 0 1rem; }
.en-org ul { margin: 0.2rem 0 0.4rem 1.2rem; }
/* The entry page: what the player accepts, what there is to pay, what was paid. */
.en-accept { margin: 0.9rem 0 0; }
.en-accept + .en-accept { margin-top: 0.35rem; }
.en-fees { margin-top: 0.4rem; }
wa-callout.pay-done p { margin: 0.5rem 0; }
wa-callout.pay-done .fee-list { margin-bottom: 0.5rem; }

/* The tournament form: an event's card and its head. */
.form .tf-event { margin: 0.6rem 0; }
.form .tf-head { display: flex; justify-content: space-between; align-items: center;
  margin-bottom: 0.5rem; }

/* ---------- Competitions ---------- */
/* A competition's list of things: directors, competitions directed. */
.comp-list { list-style: none; padding: 0; margin: 0; }
.comp-list > li { padding: 0.5rem 0; border-top: 1px solid var(--line); }
.comp-list > li > ul { list-style: none; padding: 0.15rem 0 0 1rem; margin: 0;
  display: grid; grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr));
  gap: 0.1rem 1rem; font-size: var(--wa-font-size-m); }
.comp-list .meta { margin: 0; }
/* A competition's custom rules: a pill for what each speaks to, then the rule in a sentence that wraps beside it. */
.comp-list.rules li { display: flex; gap: 0.6rem; align-items: flex-start; padding: 0.35rem 0; }
.comp-list.rules li:first-child { border-top: 0; }
.comp-list.rules wa-badge { flex: none; }
/* The sentence's first line stands level with the pill: a line as tall as the pill. */
.comp-list.rules li > span { line-height: 1.5; }
/* Who may be moved to a lower division: an arrow down beside the division. */
.relegable { color: var(--clay-deep); margin-left: 0.25rem; vertical-align: -0.1em; }
/* A discount (docs/system/competitions.md#discounts): what it takes off, under a fee's mark, and the form's list of ticks. */
.disc-off { font-size: var(--wa-font-size-2xs); color: var(--wa-color-text-quiet); line-height: 1.2; margin-top: 0.15rem; white-space: nowrap; }
.disc-ticks { display: flex; flex-direction: column; gap: 0.35rem; }

/* ---------- Predictions ---------- */
/* A predictor's board, read-only, in the ranking's dialog. */
wa-dialog.predview { --width: min(96vw, 1100px); }
wa-dialog.predview .pred-tourn h2 { font-size: var(--font-size-m-plus); margin: 0.2rem 0 0.6rem; }
.pred-side { display: inline-flex; align-items: center; gap: 0.25rem; }
.pred-side.picked { color: var(--blue); font-weight: 600; }
/* The inline H2H and the red mark inside a pick's button. */
.pred-lines wa-button .h2hcell, .pred-lines wa-button .mark { margin-left: 0.3rem; }
.pred-tourn { margin: 0 0 1.6rem; }
.pred-tourn h2 { display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap; }
.pred-tourn h2 .pred-share { margin-left: auto; font-weight: 400; }
.pred-draw { margin: 0 0 1.1rem; }
.pred-draw:last-child { margin-bottom: 0; }
.pred-draw .flash:empty { display: none; }
/* The two sides of a line: a block inside the cell, never the cell itself — a flex table cell stops being one, and on a phone the wrapped buttons overlapped the next row (2026-09-08). */
.pred-sides { display: flex; align-items: center; gap: 0.4rem; flex-wrap: wrap; }
table.pred-lines td { vertical-align: middle; }
.pred-examples { margin: 0.2rem 0 0.8rem 1.2rem; }
.pred-examples li { margin: 0.15rem 0; }

/* ---------- Tournament simulation ---------- */
/* The simulation's headings, with their share links. */
.simhead { display: flex; gap: 0.9rem;
  align-items: baseline; margin-top: 1.2rem; }
.simhead h1 { margin: 0 0 0.6rem; }
/* The simulation's own table spreads its four columns proportionally instead. */
table.sim th:first-child { width: 40%; }
table.sim td.winbar { width: 28%; }
table.sim td.spark { width: 20%; }
/* The simulation's long lists: rows behind Show more. */
tr.hiddenrow { display: none; }
button.morebtn { margin: 0.5rem 0 0.1rem; color: var(--blue); }
/* Record-only journal rows: kept for the story, no simulation effect. */
.news-item.inert { opacity: 0.62; }
.inert-tag { color: var(--muted); font-size: var(--font-size-smaller-2); }
/* The scraping line under the simulation title. */
.sim-fresh { margin: -0.4rem 0 1rem; }
.sim-fresh a[data-simrefresh] { text-decoration: underline;
  cursor: pointer; margin-left: 0.2rem; }

/* ---------- H2H matchup ---------- */
/* Side one, said for an account with no player of its own. */
.h2h-nolink { margin: 0.4rem 0 0; }
/* The H2H suggestion line: one row of links under the form. */
.h2h-sugg { margin: 0.5rem 0 0; }
/* The H2H explainer: how the card above got its numbers. */
.h2h-explain h3.cardtitle { margin-top: 1.2rem; }
.h2h-explain p { margin: 0.5rem 0; }

/* ---------- Data freshness ---------- */
/* The freshness page: the refresh buttons on one line. */
.fresh-runs { display: flex; gap: 0.5rem; align-items: center;
  margin-bottom: 0.8rem; }
/* What a refresh did, in the log: quiet words that wrap. */
.fresh-detail { color: var(--muted); font-size: var(--wa-font-size-smaller); }

/* ---------- Profile ---------- */
/* The profile's lists sit under the details. */
.profile-sub { margin: 1.4rem 0 0.5rem; }
/* An act under one of the profile's lists: Join a competition. */
.profile-act { margin: 0.7rem 0 0; }
.profile-act.head { margin: 0 0 0.9rem; }
/* A competition on the profile: its name, then its facts as field rows. */
.comp-block { margin: 0 0 1.2rem; }
.comp-name { margin: 0.9rem 0 0.5rem; }
/* A country the player does not choose: read, at a control's height. */
.own-country { min-height: 2.3rem; display: flex; align-items: center; margin: 0; }

/* ---------- Data browser ---------- */
/* The lists' two multi-selects keep room for their chips. */
.filters wa-select.fl-status { min-width: 240px; }
.filters wa-select.fl-source { min-width: 210px; }

/* ---------- Users ---------- */
/* A worn face is put on from the list of accounts. */
a.impersonate { text-decoration: underline; cursor: pointer;
  white-space: nowrap; }

/* The review desk: a request a row — the facts, the player, the competitions, the acts. */
.req-row { display: grid;
  grid-template-columns: minmax(200px, 1fr) minmax(230px, 320px) minmax(180px, 260px) auto;   /* facts, player, competitions (2026-09-22), acts */
  gap: 1rem; align-items: end; padding: 0.7rem 0;
  border-bottom: 1px solid var(--line); }
.req-row:last-child { border-bottom: none; }
@media (max-width: 720px) { .req-row { grid-template-columns: 1fr; } }
.req-facts { display: flex; flex-direction: column;
  gap: 0.15rem; }
/* A steady width keeps the picker column aligned when a row has no Grant button; the lone Delete then sits under its neighbours'. */
.req-acts { display: flex; gap: 0.5rem; min-width: 16.5rem;
  justify-content: flex-end; }
.req-note { grid-column: 1 / -1; }
.req-note wa-callout { margin: 0.15rem 0 0.2rem; }

/* ---------- Email templates ---------- */
/* The Email templates page: the mail as it goes out beside its words. */
.mt-cols { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 1rem; align-items: start; }
@media (max-width: 900px) { .mt-cols { grid-template-columns: minmax(0, 1fr); } }

/* ---------- UI gallery ---------- */
/* The palette: a chip of each colour, its name, its value, its role. */
.swatches { display: grid; grid-template-columns: repeat(auto-fill, minmax(12rem, 1fr));
  gap: 0.7rem; }
.swatch .chip { height: 3rem; border-radius: var(--wa-border-radius-m);
  border: 1px solid var(--line); margin-bottom: 0.3rem; background: var(--chip); }
.swatch .nm { font-weight: 600; font-size: var(--wa-font-size-s); }
.swatch .val { font-family: ui-monospace, monospace; font-size: var(--wa-font-size-xs);
  color: var(--muted); }
.swatch .role { font-size: var(--wa-font-size-xs); color: var(--muted); }
/* What is painted on the clay is shown on it. */
.swatches.clay .ground { padding: 0.5rem; margin-bottom: 0.3rem; border-radius: var(--wa-border-radius-m);
  background: linear-gradient(175deg, var(--clay-deep), var(--clay-dark)); }
.swatches.clay .chip { height: 2rem; margin: 0; border-color: var(--veil); }
/* The type scale: a step a line — its name, its size, and words set in it. */
.typescale { display: grid; grid-template-columns: max-content max-content minmax(0, 1fr); gap: 0.35rem 1rem; align-items: baseline; }
.typescale .nm { font-family: var(--wa-font-family-code); font-size: var(--wa-font-size-xs); }
.typescale .val { font-size: var(--wa-font-size-xs); color: var(--muted); font-variant-numeric: tabular-nums; }
.typescale .say { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; line-height: 1.15; }
.ty-font-size-4xs { font-size: var(--font-size-4xs); }
.ty-font-size-3xs { font-size: var(--font-size-3xs); }
.ty-wa-font-size-2xs { font-size: var(--wa-font-size-2xs); }
.ty-wa-font-size-xs { font-size: var(--wa-font-size-xs); }
.ty-wa-font-size-s { font-size: var(--wa-font-size-s); }
.ty-wa-font-size-m { font-size: var(--wa-font-size-m); }
.ty-font-size-touch { font-size: var(--font-size-touch); }
.ty-font-size-m-plus { font-size: var(--font-size-m-plus); }
.ty-wa-font-size-l { font-size: var(--wa-font-size-l); }
.ty-font-size-l-plus { font-size: var(--font-size-l-plus); }
.ty-wa-font-size-xl { font-size: var(--wa-font-size-xl); }
.ty-font-size-xl-plus { font-size: var(--font-size-xl-plus); }
.ty-wa-font-size-2xl { font-size: var(--wa-font-size-2xl); }
.ty-font-size-2xl-plus { font-size: var(--font-size-2xl-plus); }
.ty-wa-font-size-3xl { font-size: var(--wa-font-size-3xl); }
.ty-font-size-3xl-plus { font-size: var(--font-size-3xl-plus); }
.ty-wa-font-size-4xl { font-size: var(--wa-font-size-4xl); }
.ty-font-size-display { font-size: var(--font-size-display); }
.ty-wa-font-size-smaller { font-size: var(--wa-font-size-smaller); }
.ty-font-size-smaller-2 { font-size: var(--font-size-smaller-2); }
.ty-font-size-smaller-3 { font-size: var(--font-size-smaller-3); }
/* The radii: a box a step. */
.radii { display: flex; flex-wrap: wrap; gap: 1rem; }
.rad { width: 6rem; height: 3.4rem; display: grid; place-items: center; border: 1px solid var(--wa-color-brand-border-normal);
  background: var(--wa-color-brand-fill-quiet); font-family: var(--wa-font-family-code); font-size: var(--wa-font-size-xs); }
.rad-circle { width: 3.4rem; }
.rad-s { border-radius: var(--wa-border-radius-s); }
.rad-m { border-radius: var(--wa-border-radius-m); }
.rad-l { border-radius: var(--wa-border-radius-l); }
.rad-pill { border-radius: var(--wa-border-radius-pill); }
.rad-circle { border-radius: var(--wa-border-radius-circle); }
/* A menu item out of the menu, for the count and the premium mark. */
.navdemo { display: inline-block; background: var(--clay-deep); color: var(--white);
  padding: 0.45rem 0.8rem; border-radius: var(--wa-border-radius-m); font-weight: 600; }
/* The menu's brand row out of the menu, for the problem report's bug. */
.navdemo.brand { display: inline-flex; gap: 0.8rem; margin: 0; }
/* A line of pills, a line of buttons, a sample title in a card. */
.pillrow { margin: 0; }
.pillrow + .pillrow { margin-top: 0.6rem; }
.btnrow { margin: 0.4rem 0 1rem; }
.btnrow.last { margin-bottom: 0; }
wa-card h1.ui-sample, wa-card h2.ui-sample { margin-top: 0; }
/* The loaders on one line. */
.loaders { display: flex; align-items: center; gap: 1rem; margin: 0.4rem 0 0; }
/* A heading with a small countdown at its side. */
.ui-cd-line { display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap; margin: 0.8rem 0 0; }
