/*
 * Application styles for korfcoach. Plain CSS served by Propshaft.
 */

:root {
  --bg: #0f1c2e;
  --panel: #16273f;
  --panel-2: #1e3350;
  --ink: #e8eef6;
  --muted: #9fb3c8;
  --line: #2b4565;
  --accent: #ff9f1c;
  --accent-ink: #1a1205;
  --ok: #3ddc97;
  --bad: #ff6b6b;
  /* Report shading (PlayerTable tiers): a diverging blue/red pair either side of a plain middle.
     Validated on --panel for colour-blind separation, each visible against the panel (2:1+) and
     the ink text readable on it (6:1+). */
  --shade-hi: #2c578f;
  --shade-lo: #874049;
  /* Player report profile radar (ReportsHelper#radar_chart): the player amber, who they're
     compared with blue (and dashed). Validated as a pair on --panel and on the radar's washes of
     the two shades: colour-blind separation, chroma and 3:1 contrast. */
  --radar-player: #c98500;
  --radar-compare: #3987e5;
  /* The average the player is drawn against: ink, softened, a reference rather than a series. */
  --radar-average: color-mix(in srgb, var(--ink) 75%, transparent);
  /* Match report (reports/_match_report): home amber, away blue, the radar's validated pair, so
     the sides stay apart for colour-blind readers. Literals, re-declared for print like the radar's. */
  --match-home: #c98500;
  --match-away: #3987e5;
  /* Awards' badges (AwardsHelper#award_badge): the ring of an earned one, bright enough on --panel
     and --panel-2 to read as gold, and its count's tab. */
  --award: #f2c94c;
  --radius: 10px;
  --radius-sm: 6px;
  --radius-lg: 14px;
  --radius-pill: 999px;

  --font-xs: 0.75rem;
  --font-sm: 0.875rem;
  --font-base: 1rem;
  --font-md: 1.125rem;
  --font-lg: 1.375rem;
  --font-xl: 1.75rem;
  --font-2xl: 2.25rem;
  --line-tight: 1.2;
  --line-normal: 1.5;

  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-5: 1.5rem;
  --space-6: 2rem;
  --space-8: 3rem;

  --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.35);
  --shadow-md: 0 4px 12px rgba(0, 0, 0, 0.40);
  --shadow-lg: 0 12px 32px rgba(0, 0, 0, 0.45);
  --shadow-focus: 0 0 0 3px rgba(255, 159, 28, 0.35);

  --transition-fast: 120ms ease;
  --transition-base: 180ms ease;
  --transition-slow: 280ms ease;

  /* Gender colors: deliberately distinct from --accent (orange) and from each other. The
     Unknown Player catch-all is not a 4th color — see .avatar--unknown below. */
  --gender-male: #2dd4bf;
  --gender-male-ink: #062623;
  --gender-female: #f4548c;
  --gender-female-ink: #2b0714;
  --gender-neutral: #a78bfa;
  --gender-neutral-ink: #1e1333;
  /* Tinted/translucent versions of the gender colors, for chip/button backgrounds where the
     full-saturation fill would be too heavy across a whole list. */
  --gender-male-bg: rgba(45, 212, 191, 0.14);
  --gender-female-bg: rgba(244, 84, 140, 0.14);
  --gender-neutral-bg: rgba(167, 139, 250, 0.14);

  /* Shot-type colours for the court-entry "Shot details" control. Kept distinct from the gender
     trio and from --ok/--bad so the shot dimension reads as its own signal: Open Play (the
     default) a calm blue, running-in a movement green, penalty an alert amber, free pass a
     referee's-flag yellow. Only the chosen segment is filled, so they never sit side by side. */
  --shot-open: #4c9ef0;      --shot-open-ink: #04121f;
  --shot-running: #3ddc97;   --shot-running-ink: #05240f;
  --shot-penalty: #ff9f1c;   --shot-penalty-ink: #1a1205;
  --shot-free-pass: #f5d547; --shot-free-pass-ink: #1f1a03;

  /* What only the site admins see (RoleOnlyHelper): admin sky blue, outlined; super admin violet,
     filled. Neither is --accent, so a mark still shows on an orange primary button. */
  --role-admin: #7cc4fa;
  --role-super: #c4a5ff;
  --role-super-ink: #1c1033;

  /* Mark then enrich's marks, by kind (the Mark screen's keys and the timeline): a goal the green of
     --ok, a missed shot Open Play's blue, a feed violet, a turnover the red of --bad, anything else
     yellow. A kick-off is a divider in --ink, not a colour. The kind is also in every mark's label. */
  --mark-goal: #3ddc97;
  --mark-shot: #4c9ef0;
  --mark-feed: #a78bfa;
  --mark-turnover: #ff6b6b;
  --mark-other: #f5d547;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  background: var(--bg);
  color: var(--ink);
  line-height: 1.5;
}

a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }
/* A record's name linked to its page (ApplicationHelper#record_link; ticket #20, James's call: quiet).
   It keeps the colour of the text it sits in, a heading's ink or a muted line's grey, with a faint
   underline to say it goes somewhere, and takes the accent on hover. */
a.record-link {
  color: inherit;
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-decoration-color: color-mix(in srgb, currentColor 45%, transparent);
  text-underline-offset: 0.2em;
}
a.record-link:hover { color: var(--accent); text-decoration-color: currentColor; }

.topnav {
  position: sticky;
  top: 0;
  z-index: 10;
  display: flex;
  align-items: center;
  gap: var(--space-4);
  padding: var(--space-3) var(--space-5);
  background: rgba(22, 39, 63, 0.92);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  border-bottom: 1px solid var(--line);
  box-shadow: var(--shadow-sm);
}
.topnav .brand { font-weight: 700; font-size: var(--font-md); }
.topnav .brand a { color: var(--ink); }
.topnav nav { display: flex; gap: var(--space-4); flex-wrap: wrap; }
.topnav nav a {
  color: var(--muted);
  padding-bottom: 2px;
  border-bottom: 2px solid transparent;
  transition: color var(--transition-fast), border-color var(--transition-fast);
}
.topnav nav a:hover { color: var(--ink); text-decoration: none; }
.topnav nav a.active { color: var(--ink); font-weight: 600; border-bottom-color: var(--accent); }
.topnav .spacer { flex: 1; }
.topnav .who { color: var(--muted); font-size: var(--font-sm); }
.topnav .topnav__request { display: inline-flex; align-items: center; gap: var(--space-1); }
/* Signed out, the header is just Features and Sign in, one row at any width: it has no Menu, and
   the phone's Menu rules below are scoped to .topnav__menu so they leave it alone. */
.topnav--guest .btn { white-space: nowrap; }
/* Wider than a phone, the links wrap onto a second row when the header runs out of room; the name
   and buttons don't. */
@media (min-width: 801px) {
  .topnav .who, .topnav .btn { white-space: nowrap; }
  /* A link's admin pill (RoleOnlyHelper) shrinks to a ring of its colour, keeping a super admin's
     header on one row down to 1280px; the phone Menu has room for the pill. Its words stay for
     screen readers, and in the tooltip. */
  .topnav .role-badge { width: .6rem; height: .6rem; padding: 0; border-width: 2px; }
  .topnav .role-badge__label { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
}
/* Between the phone Menu and a wide screen, a little more room for the links: closer together, and
   the name without the role (which its tooltip still gives). */
@media (min-width: 801px) and (max-width: 1439px) {
  .topnav, .topnav nav { gap: var(--space-3); }
  .topnav .who__role { display: none; }
}
/* A dropdown of related links (layouts/_nav_group): a toggle that reads like the links beside it,
   and a panel under it that shows while the toggle is aria-expanded (menu_controller.js). Scoped
   under .topnav to beat the button rules, which come later. */
.topnav__group { position: relative; }
.topnav .topnav__group-toggle {
  display: inline-flex; align-items: center; gap: 0.2rem;
  padding: 0 0 2px; border: 0; border-bottom: 2px solid transparent; border-radius: 0;
  background: none; box-shadow: none; transform: none;
  color: var(--muted); font: inherit; line-height: inherit;
}
.topnav .topnav__group-toggle:hover, .topnav .topnav__group-toggle[aria-expanded="true"] { color: var(--ink); transform: none; box-shadow: none; }
.topnav .topnav__group-toggle.active { color: var(--ink); font-weight: 600; border-bottom-color: var(--accent); }
.topnav .topnav__group-toggle:focus-visible { box-shadow: var(--shadow-focus); border-radius: var(--radius-sm); }
.topnav__caret { transition: transform var(--transition-fast); }
.topnav__group-toggle[aria-expanded="true"] .topnav__caret { transform: rotate(180deg); }
/* Lined up so the links' text starts under the toggle's. */
.topnav__group-panel {
  position: absolute; top: calc(100% + var(--space-2)); left: calc(-1 * (var(--space-1) + var(--space-3) + 1px)); z-index: 20;
  display: flex; flex-direction: column; gap: 2px; min-width: 10rem;
  padding: var(--space-1);
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius);
  box-shadow: var(--shadow-lg);
}
.topnav__group-toggle[aria-expanded="false"] + .topnav__group-panel { display: none; }
.topnav nav .topnav__group-panel a { padding: var(--space-2) var(--space-3); border-bottom: 0; border-radius: var(--radius-sm); color: var(--ink); }
.topnav nav .topnav__group-panel a:hover { background: var(--panel-2); }
.topnav nav .topnav__group-panel a.active { background: var(--panel-2); box-shadow: inset 3px 0 0 var(--accent); border-radius: 0 var(--radius-sm) var(--radius-sm) 0; }
@media (prefers-reduced-motion: reduce) { .topnav__caret { transition: none; } }
/* The signed-in user's name (layouts/_account_menu): a dropdown like those above, as small as the
   name always was, whose panel hangs from the header's right edge. It's outside the Main nav, so
   its link and Sign out button have rules of their own, the button's scoped to beat the button
   rules, which come later. */
.topnav .topnav__account .topnav__group-toggle { font-size: var(--font-sm); }
.topnav__account .topnav__account-panel { left: auto; right: 0; width: max-content; min-width: 12rem; max-width: 22rem; }
.topnav__account-who {
  display: flex; flex-direction: column; margin: 0 0 var(--space-1); padding: var(--space-2) var(--space-3);
  border-bottom: 1px solid var(--line); font-size: var(--font-sm); overflow-wrap: anywhere;
}
.topnav__account-panel .button_to { margin: 0; }
.topnav__account-panel a, .topnav .topnav__account-signout {
  display: block; width: 100%; padding: var(--space-2) var(--space-3);
  border: 0; border-radius: var(--radius-sm); background: none; box-shadow: none; transform: none;
  color: var(--ink); font: inherit; line-height: inherit; text-align: left;
}
.topnav__account-panel a:hover, .topnav .topnav__account-signout:hover { background: var(--panel-2); text-decoration: none; transform: none; box-shadow: none; }
.topnav .topnav__account-signout:focus-visible { box-shadow: var(--shadow-focus); }
.topnav__account-panel a.active { background: var(--panel-2); box-shadow: inset 3px 0 0 var(--accent); border-radius: 0 var(--radius-sm) var(--radius-sm) 0; }
/* Switch to the account linked to this one (AccountSwitch): a link, or a button when it asks nothing. */
.topnav__account-panel .topnav__account-switch { display: flex; align-items: center; gap: var(--space-2); }

/* Who's really signed in (layouts/application; James's call). A super admin's header is washed in the
   super admin's violet (--role-super) with a stripe along its top, and the Super admin mark by the
   site's name. Viewing KorfCoach as someone (ViewingAs), it's striped instead, and says whose view it
   is, with Stop. Inset shadows rather than borders, so the header keeps its height: court entry v2
   is sized to fit under it (--v2-screen). */
.topnav--super-admin {
  background: color-mix(in srgb, var(--role-super) 14%, rgba(22, 39, 63, 0.94));
  border-bottom-color: color-mix(in srgb, var(--role-super) 55%, var(--line));
  box-shadow: inset 0 3px 0 var(--role-super), var(--shadow-sm);
}
.topnav__mode {
  display: inline-flex; align-items: center; gap: var(--space-1); flex: none;
  padding: 1px var(--space-2); border-radius: var(--radius-pill);
  background: var(--role-super); color: var(--role-super-ink);
  font-size: var(--font-xs); font-weight: 700; line-height: 1.6; white-space: nowrap;
}
.topnav--viewing {
  background:
    repeating-linear-gradient(-45deg, color-mix(in srgb, var(--role-super) 18%, transparent) 0 10px, transparent 10px 20px),
    rgba(22, 39, 63, 0.94);
  border-bottom-color: var(--role-super);
  box-shadow: inset 0 3px 0 var(--role-super), var(--shadow-sm);
}
.topnav__viewing {
  display: inline-flex; align-items: center; gap: var(--space-2); min-width: 0; flex: 0 1 auto;
  padding: 2px 2px 2px var(--space-3);
  border: 1px dashed var(--role-super); border-radius: var(--radius-pill);
  background: color-mix(in srgb, var(--role-super) 20%, var(--panel));
  font-size: var(--font-sm); white-space: nowrap;
}
.topnav__viewing .icon { flex: none; color: var(--role-super); }
.topnav__viewing-who { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.topnav__viewing-note { color: var(--muted); }
.topnav__viewing .inline-form { flex: none; }
.topnav .topnav__viewing-stop { border-radius: var(--radius-pill); }
/* Between the phone Menu and a wide screen, the marks take less room: the super admin's its shield
   alone (its words stay for screen readers, and in the tooltip), and the view drops its end time. */
@media (min-width: 801px) and (max-width: 1439px) {
  .topnav__mode { padding: 3px; }
  .topnav__mode-label { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
  .topnav__viewing-note { display: none; }
}
/* On a phone the brand and Menu fill the row, so the view takes a row of its own under them, whose
   name it is and Stop. */
@media (max-width: 800px) {
  .topnav--viewing { flex-wrap: wrap; row-gap: var(--space-2); }
  .topnav__viewing { order: 1; flex: 1 1 100%; }
  .topnav__viewing .inline-form { margin-left: auto; }
  .topnav__viewing-note { display: none; }
}

/* The Menu toggle and its panel only come into play on narrow screens (below). Wider, the panel
   has no box of its own, so the links, name and Sign out are laid out in the header's row. The
   toggle's rules are scoped under .topnav to beat .btn's display, which comes later. */
.topnav .topnav__toggle { display: none; }
.topnav__menu { display: contents; }

/* Narrow screens: the brand and a Menu toggle, which drops the rest down over the page as a
   panel. menu_controller.js flips the toggle's aria-expanded and the panel follows it, so the two
   can't disagree; the panel scrolls itself if it's taller than the screen (a phone on its side). */
@media (max-width: 800px) {
  .topnav { padding: var(--space-2) var(--space-4); }
  .topnav .topnav__toggle { display: inline-flex; align-items: center; gap: var(--space-2); margin-left: auto; }
  .topnav__toggle-icon, .topnav__toggle-icon::before, .topnav__toggle-icon::after {
    width: 1rem; height: 2px; border-radius: 1px; background: currentColor;
  }
  .topnav__toggle-icon { position: relative; transition: background var(--transition-fast); }
  .topnav__toggle-icon::before, .topnav__toggle-icon::after {
    content: ""; position: absolute; left: 0; transition: transform var(--transition-base);
  }
  .topnav__toggle-icon::before { transform: translateY(-5px); }
  .topnav__toggle-icon::after { transform: translateY(5px); }
  .topnav__toggle[aria-expanded="true"] .topnav__toggle-icon { background: transparent; }
  .topnav__toggle[aria-expanded="true"] .topnav__toggle-icon::before { transform: rotate(45deg); }
  .topnav__toggle[aria-expanded="true"] .topnav__toggle-icon::after { transform: rotate(-45deg); }

  .topnav__menu {
    position: absolute; top: 100%; left: 0; right: 0;
    display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center;
    gap: var(--space-3) var(--space-4);
    max-height: calc(100dvh - 100%); overflow-y: auto; overscroll-behavior: contain;
    padding: var(--space-3) var(--space-4) var(--space-4);
    background: var(--panel); border-top: 1px solid var(--line); border-bottom: 1px solid var(--line);
    box-shadow: var(--shadow-lg);
  }
  .topnav__toggle[aria-expanded="false"] + .topnav__menu { display: none; }
  .topnav__menu nav {
    grid-column: 1 / -1; display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-1);
    padding-bottom: var(--space-3); border-bottom: 1px solid var(--line);
  }
  .topnav__menu nav a { padding: 0.625rem var(--space-3); border-bottom: 0; border-radius: var(--radius-sm); }
  .topnav__menu nav a:hover { background: var(--panel-2); }
  .topnav__menu nav a.active { background: var(--panel-2); box-shadow: inset 3px 0 0 var(--accent); border-radius: 0 var(--radius-sm) var(--radius-sm) 0; }
  /* The Menu already holds every link, so a dropdown's toggle goes and its links join the grid. */
  .topnav .topnav__group-toggle { display: none; }
  .topnav__group, .topnav .topnav__group-toggle + .topnav__group-panel { display: contents; }
  .topnav nav .topnav__group-panel a { padding: 0.625rem var(--space-3); color: var(--muted); }
  .topnav nav .topnav__group-panel a.active { color: var(--ink); }
  .topnav__menu .spacer { display: none; }
  .topnav .topnav__request { grid-column: 1 / -1; justify-self: start; }
  /* The account menu's toggle goes too, and its panel sits flat across the foot of the Menu: the
     name and email, then Your profile and Sign out side by side, like the links above. */
  .topnav .topnav__account { display: block; grid-column: 1 / -1; padding-top: var(--space-3); border-top: 1px solid var(--line); }
  .topnav .topnav__account .topnav__account-panel {
    position: static; display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-1);
    min-width: 0; padding: 0; background: none; border: 0; box-shadow: none;
  }
  .topnav__account-who { grid-column: 1 / -1; padding-top: 0; border-bottom: 0; }
  .topnav__account-panel a, .topnav .topnav__account-signout { padding: 0.625rem var(--space-3); color: var(--muted); }
  .topnav__account-panel a.active { color: var(--ink); }
}
@media (max-width: 800px) and (prefers-reduced-motion: reduce) {
  .topnav__toggle-icon::before, .topnav__toggle-icon::after { transition: none; }
}

main { max-width: 1100px; margin: 0 auto; padding: var(--space-5) var(--space-4); }
/* Every page's foot (layouts/_footer): the privacy links, then the deploy stamp. */
.site-footer { display: flex; flex-direction: column; align-items: center; gap: var(--space-2); padding: var(--space-5) var(--space-4) var(--space-4); font-size: var(--font-sm); }
.site-footer nav { display: flex; flex-wrap: wrap; justify-content: center; gap: var(--space-2) var(--space-5); }
.site-footer nav a { color: var(--muted); }
.site-footer nav a:hover { color: var(--ink); }
.site-footer .release-stamp { margin: 0; padding: 0; }
@media print { .site-footer { display: none; } }
.release-stamp { text-align: center; color: var(--muted); font-size: var(--font-sm); padding: var(--space-4); }

h1, h2, h3 { line-height: var(--line-tight); }
h1 { font-size: var(--font-xl); margin: 0 0 var(--space-4); }
h2 { font-size: var(--font-lg); margin: 0 0 var(--space-3); }
h3 { font-size: var(--font-md); margin: 0 0 var(--space-2); }

@keyframes flash-in { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: none; } }
.flash {
  max-width: 1100px; margin: var(--space-3) auto 0; padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-lg); box-shadow: var(--shadow-sm);
  animation: flash-in var(--transition-base);
}
.flash--notice { background: rgba(61, 220, 151, 0.15); color: var(--ok); border: 1px solid rgba(61, 220, 151, 0.4); }
.flash--alert { background: rgba(255, 107, 107, 0.15); color: var(--bad); border: 1px solid rgba(255, 107, 107, 0.4); }

table { width: 100%; border-collapse: collapse; background: var(--panel); border-radius: var(--radius); overflow: hidden; }
th, td { text-align: left; padding: var(--space-3) var(--space-4); border-bottom: 1px solid var(--line); }
th { color: var(--muted); font-size: var(--font-xs); text-transform: uppercase; letter-spacing: 0.03em; }
tr:last-child td { border-bottom: none; }
tbody tr { transition: background var(--transition-fast); }
tbody tr:hover { background: var(--panel-2); }
/* A closing total row (match stats' "Team"), set apart from the rows it adds up. */
tfoot th, tfoot td { border-top: 1px solid var(--line); border-bottom: none; font-weight: 600; }
tfoot th { color: var(--ink); }

.table-scroll { max-height: 70vh; overflow-y: auto; border-radius: var(--radius); }
.table-scroll table { border-radius: 0; }
.table-scroll thead th { position: sticky; top: 0; background: var(--panel); z-index: 1; }
/* Scrolls sideways on a narrow screen instead of widening the page; the page still scrolls down. */
.table-wrap { overflow-x: auto; border-radius: var(--radius); }

/* Sortable column headers (see DirectoryHelper#sort_header): the link keeps the header's look,
   and the sorted column reads in full ink. */
th.sortable a { color: inherit; text-decoration: none; white-space: nowrap; }
th.sortable a:hover { color: var(--accent); }
th.sortable[aria-sort] a { color: var(--ink); }
.sort-arrow { font-size: 0.8em; }
/* The same headers sorting a table in place (ReportsHelper#table_sort_header): a bare button that
   reads like the header text, not a .btn. */
th.sortable button {
  padding: 0; border: 0; border-radius: var(--radius-sm); background: none; box-shadow: none;
  color: inherit; font: inherit; letter-spacing: inherit; text-transform: inherit; line-height: inherit;
  white-space: nowrap; transform: none;
}
th.sortable button:hover { color: var(--accent); transform: none; box-shadow: none; }
th.sortable[aria-sort] button { color: var(--ink); }
th.sortable button .sort-arrow:not(:empty) { margin-left: 0.3em; }
/* Numbers in a table column (shirt numbers, counts) line up digit for digit. */
td.num { font-variant-numeric: tabular-nums; }

.btn, button, input[type="submit"] {
  display: inline-block;
  padding: 0.5rem 0.9rem;
  border-radius: var(--radius);
  border: 1px solid var(--line);
  background: var(--panel-2);
  color: var(--ink);
  cursor: pointer;
  font-size: 0.95rem;
  /* Explicit so <button>s match <a class="btn"> links: a button's UA line-height is `normal`
     (~1.2) and doesn't inherit, which otherwise renders it a few px shorter than a sibling link. */
  line-height: 1.5;
  transition: background var(--transition-fast), border-color var(--transition-fast),
    transform var(--transition-fast), box-shadow var(--transition-fast);
}
.btn:hover, button:hover { text-decoration: none; border-color: var(--accent); transform: translateY(-1px); box-shadow: var(--shadow-sm); }
.btn:active, button:active { transform: none; box-shadow: none; }
.btn:focus-visible, button:focus-visible, input:focus-visible, select:focus-visible, textarea:focus-visible {
  outline: none; box-shadow: var(--shadow-focus);
}
.btn--primary, input[type="submit"] { background: var(--accent); color: var(--accent-ink); border-color: var(--accent); font-weight: 600; }
.btn--danger { color: var(--bad); }
.actions { display: flex; gap: var(--space-2); flex-wrap: wrap; align-items: center; margin: var(--space-4) 0; }

form .field { margin-bottom: var(--space-4); }
/* .field__label heads a field that isn't a single input (e.g. the court form's preview). */
form label, form .field__label { display: block; margin-bottom: var(--space-1); color: var(--muted); font-size: var(--font-sm); }
form input[type="text"], form input[type="email"], form input[type="password"],
form input[type="number"], form input[type="date"], form input[type="url"],
form input[type="datetime-local"], form select, form textarea {
  width: 100%;
  max-width: 28rem;
  padding: var(--space-2) var(--space-3);
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  color: var(--ink);
  transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
}
form .checkbox { display: flex; align-items: center; gap: var(--space-2); }
form .checkbox[hidden] { display: none; }
form .checkbox input { width: auto; }

.card { background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius); padding: var(--space-4) var(--space-5); margin-bottom: var(--space-4); box-shadow: var(--shadow-sm); transition: box-shadow var(--transition-base), transform var(--transition-base); }
.card--clickable:hover { box-shadow: var(--shadow-md); transform: translateY(-2px); cursor: pointer; }
.errors { background: rgba(255, 107, 107, 0.12); border: 1px solid rgba(255, 107, 107, 0.4); color: var(--bad); padding: var(--space-3) var(--space-4); border-radius: var(--radius); margin-bottom: var(--space-4); }

.badge { display: inline-block; padding: var(--space-1) var(--space-2); border-radius: var(--radius-pill); font-size: var(--font-xs); font-weight: 600; border: 1px solid var(--line); color: var(--muted); }
.badge--active { color: var(--ok); border-color: rgba(61, 220, 151, 0.5); }
.badge--square { border-radius: var(--radius-sm); }
/* A fixture's tag: tells apart copies of one match (Fixture#duplicate). */
.badge--tag { color: var(--ink); background: var(--panel-2); vertical-align: middle; }
/* Another club's fixture (Fixture#recording_club): "Entered by X" / "Shared by X". */
.badge--recording { vertical-align: middle; font-weight: 500; }
/* A copy kept for one team (Fixture#counts_for_team): "Counts for X". Dashed, as it counts for half
   the match, and told from the tag beside it without colour. */
.badge--counts-for { color: var(--ink); border-style: dashed; border-color: var(--muted); vertical-align: middle; white-space: nowrap; }
.muted { color: var(--muted); }

.btn--small { padding: 0.3rem 0.6rem; font-size: 0.85rem; }
/* Icon-only square button (the ⋯ overflow toggle). Narrower than a text button; height still
   comes from the shared line-height so it matches its sibling buttons. */
.btn--icon { padding: 0.5rem 0.65rem; }
label.radio { margin-right: 1rem; color: var(--ink); }

/* --- Breadcrumb --- */
.breadcrumb { color: var(--muted); font-size: var(--font-sm); margin: 0 0 var(--space-2); }
.breadcrumb__sep { margin: 0 var(--space-2); color: var(--line); }

/* --- Generic dropdown menu (menu_controller.js) ---
   A toggle plus an absolutely-positioned panel. The trigger's wrapper owns the positioning
   context, so .menu opens off the toggle's right edge by default; add .menu__panel--up where a
   downward menu would be clipped. */
.menu { position: relative; }
.menu__panel {
  position: absolute; top: 100%; right: 0; z-index: 20; margin-top: var(--space-1);
  display: flex; flex-direction: column; gap: 2px; min-width: 12rem;
  padding: var(--space-1);
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius);
  box-shadow: var(--shadow-lg);
}
.menu__panel[hidden] { display: none; } /* flex would otherwise beat [hidden] */
.menu__panel--up { top: auto; bottom: 100%; margin: 0 0 var(--space-1); }
.menu__panel form { margin: 0; } /* button_to wraps each button in a form */
.menu__item {
  display: block; width: 100%; text-align: left;
  background: transparent; border: none; border-radius: var(--radius-sm);
  padding: var(--space-2) var(--space-3); font-weight: 600; color: var(--ink);
}
.menu__item:hover { background: var(--panel-2); border-color: transparent; transform: none; box-shadow: none; text-decoration: none; }
.menu__item--danger { color: var(--bad); }
.menu__sep { height: 1px; margin: var(--space-1) 0; background: var(--line); }
/* An entry screen's Match finished (entry/_finish_match), beside Switch entry: its button, or the
   Finished badge once it's pressed. */
.finish-match { display: flex; align-items: center; }
.finish-match .button_to { margin: 0; }
/* Every entry screen's Switch entry (entry/_entry_switcher): the screens under their group's name,
   the current one marked, Mark then enrich's greyed without a video. */
.entry-switcher .menu__panel { min-width: 14rem; }
.entry-switcher__group {
  margin: var(--space-2) var(--space-3) 0; font-size: var(--font-xs); font-weight: 600;
  letter-spacing: 0.05em; text-transform: uppercase; color: var(--muted);
}
.entry-switcher__group:first-child { margin-top: var(--space-1); }
.entry-switcher__screen { white-space: nowrap; }
span.entry-switcher__screen { cursor: default; }
span.entry-switcher__screen:hover { background: none; }
.entry-switcher__screen--current { color: var(--accent); }
.entry-switcher__screen--current::after { content: " ✓"; }
.entry-switcher__screen--unavailable { color: var(--muted); font-weight: 500; }

/* --- Fixture header (fixtures#show) ---
   One card carrying the whole match identity: score, meta, the primary Enter events action (which
   opens the entry chooser), and the recording link. Actions dock right of the score and drop below
   it on narrow viewports. */
.fixture-head__bar { display: flex; align-items: flex-start; justify-content: space-between; flex-wrap: wrap; gap: var(--space-4); }
.fixture-head__score { margin: 0; font-size: var(--font-xl); }
.fixture-head__goals { color: var(--accent); white-space: nowrap; }
.fixture-head__meta { margin: var(--space-2) 0 0; color: var(--muted); font-size: var(--font-sm); }
.fixture-head__actions { display: flex; align-items: center; gap: var(--space-2); flex: none; }
.fixture-head__foot { margin-top: var(--space-3); padding-top: var(--space-3); border-top: 1px solid var(--line); }
/* Enter events (fixtures/_entry_chooser, entry_chooser_controller.js): the entry-flow dialog, a
   little wider, with the three ways in as whole-card links. The wrapper keeps the button in the
   actions row. Mark then enrich without a video is dimmed and not a link. */
.entry-chooser { display: contents; }
.entry-flow.entry-chooser__dialog { max-width: min(94vw, 34rem); }
.entry-chooser__title { margin: 0; font-size: var(--font-md); }
.entry-chooser .entry-flow__prompt { margin-bottom: var(--space-3); }
.entry-chooser__note { margin: calc(-1 * var(--space-1)) 0 var(--space-3); color: var(--muted); font-size: var(--font-sm); }
.entry-chooser__note strong { color: var(--ink); }
.entry-chooser__list { display: grid; gap: var(--space-2); margin: 0; padding: 0; list-style: none; }
.entry-choice {
  display: block; padding: var(--space-3); color: var(--ink); text-decoration: none;
  background: var(--bg); border: 1px solid var(--line); border-radius: var(--radius);
  transition: border-color var(--transition-fast), background var(--transition-fast);
}
a.entry-choice:hover { color: var(--ink); text-decoration: none; border-color: var(--accent); background: var(--panel-2); }
a.entry-choice:focus-visible { outline: none; border-color: var(--accent); box-shadow: var(--shadow-focus); }
.entry-choice__name { display: block; font-weight: 600; }
.entry-choice__blurb { display: block; margin-top: 2px; color: var(--muted); font-size: var(--font-sm); }
.entry-choice--unavailable .entry-choice__name,
.entry-choice--unavailable .entry-choice__blurb { opacity: 0.55; }
.entry-choice__note { display: block; margin-top: var(--space-2); font-size: var(--font-sm); }
.entry-choice__more { display: inline-block; margin: var(--space-1) 0 0 var(--space-3); font-size: var(--font-sm); }
/* Match stats: one player table per side, in the one card. */
.match-stats__team + .match-stats__team { margin-top: var(--space-5); }
.match-stats__uncounted { font-size: var(--font-sm); font-weight: 400; }
/* Duplicate (fixture_duplicates/new): on a match between two of the club's teams, what the copy is
   for, as cards with a visually hidden radio each (like the ticket templates). A team's copy stays in
   the original's season, so the season is hidden, and its tag may be left blank. */
.copy-choices { border: 0; margin: 0 0 var(--space-4); padding: 0; min-width: 0; display: grid; gap: var(--space-2); max-width: 40rem; }
.copy-choices legend { padding: 0; margin-bottom: var(--space-2); color: var(--ink); font-weight: 600; }
form .copy-choice { position: relative; display: block; margin: 0; color: var(--ink); font-size: var(--font-base); font-weight: 400; cursor: pointer; }
.copy-choice__input { position: absolute; opacity: 0; width: 1px; height: 1px; margin: 0; }
.copy-choice__card {
  display: block; padding: var(--space-3); background: var(--bg); border: 1px solid var(--line); border-radius: var(--radius);
  transition: border-color var(--transition-fast), background var(--transition-fast);
}
.copy-choice__name { display: block; font-weight: 600; }
.copy-choice__blurb { display: block; margin-top: 2px; color: var(--muted); font-size: var(--font-sm); }
.copy-choice__blurb strong { color: var(--ink); }
.copy-choice:hover .copy-choice__card { border-color: var(--accent); }
.copy-choice__input:checked + .copy-choice__card { border-color: var(--accent); background: var(--panel-2); box-shadow: inset 0 0 0 1px var(--accent); }
.copy-choice__input:focus-visible + .copy-choice__card { box-shadow: var(--shadow-focus); }
.copy-form__tag-hint--team { display: none; }
.copy-form:has(.copy-choice--team .copy-choice__input:checked) .copy-form__tag-hint { display: none; }
.copy-form:has(.copy-choice--team .copy-choice__input:checked) .copy-form__tag-hint--team { display: block; }
.copy-form:has(.copy-choice--team .copy-choice__input:checked) .copy-form__season { display: none; }

/* --- Event entry --- */
.entry__header { display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 0.5rem; }
.entry__grid { display: grid; grid-template-columns: 2fr 1fr; gap: 1rem; align-items: start; }
@media (max-width: 900px) { .entry__grid { grid-template-columns: 1fr; } }
/* On wide screens the page's 1100px cap leaves empty margins either side. Let the
   entry page spill into that space and funnel the extra width to the sidebar, so the
   video can grow while the court column stays pinned at its current ~700px — nothing
   in the main column shrinks and the video keeps its spot at the top of the sidebar. */
@media (min-width: 1200px) {
  main:has(.entry) { max-width: 1440px; }
  .entry__grid { grid-template-columns: minmax(0, 700px) 1fr; }
}
.entry__teams { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; }
@media (max-width: 700px) { .entry__teams { grid-template-columns: 1fr; } }

.scoreboard { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: var(--space-4); padding: var(--space-3) var(--space-5); margin-bottom: var(--space-3); }
.scoreboard p { margin: 0; }
.scoreboard__score { display: flex; gap: 1rem; align-items: baseline; font-size: 1.1rem; }
/* nowrap: where the scoreboard is narrow the team names wrap, but the score stays whole. */
.scoreboard__score strong { font-size: 1.6rem; color: var(--accent); white-space: nowrap; }
.scoreboard__attack { color: var(--accent); font-weight: 600; white-space: nowrap; }

.match-clock { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: var(--space-2); padding: var(--space-2) var(--space-4); margin-bottom: var(--space-2); }
.match-clock__readout { display: flex; align-items: baseline; gap: var(--space-3); }
.match-clock__label { color: var(--muted); font-size: 0.8rem; }
.match-clock__time { font-size: 1.1rem; font-weight: 700; font-variant-numeric: tabular-nums; color: var(--accent); }
/* Clock actions + the help icon, docked right of the readout. */
.match-clock__side { display: flex; align-items: center; gap: var(--space-2); }
.match-clock__actions { position: relative; }
.match-clock__toggle::after { content: "▾"; margin-left: 0.4rem; }
/* Opens downward off the card's right edge; the match-clock card isn't overflow-clipped. */
.match-clock__menu {
  position: absolute; top: 100%; right: 0; z-index: 20; margin-top: var(--space-1);
  display: flex; flex-direction: column; gap: 2px; min-width: 12rem;
  padding: var(--space-1);
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius);
  box-shadow: var(--shadow-lg);
}
.match-clock__menu[hidden] { display: none; } /* flex would otherwise beat [hidden] */
.match-clock__menu form { margin: 0; } /* button_to wraps each button in a form */
.match-clock__item {
  display: block; width: 100%; text-align: left;
  background: transparent; border: none; border-radius: var(--radius-sm);
  padding: var(--space-2) var(--space-3); font-weight: 600;
}
.match-clock__item:hover { background: var(--panel-2); border-color: transparent; transform: none; box-shadow: none; }

.card--court { padding: 0; overflow: hidden; }
.card--court .court { border-radius: 0; }
.court-card__body { padding: var(--space-4) var(--space-5); }
.court {
  position: relative;
  width: 100%;
  aspect-ratio: 2 / 1;
  /* Floor colour and marking dimensions come from the court's geometry (CourtGeometry#css_vars,
     set inline on this element). The fallbacks reproduce the standard 40x20 court. */
  background: var(--court-floor, #1b5e20);
  background-image: linear-gradient(rgba(255,255,255,0.08), rgba(255,255,255,0.08));
  /* Line markings take the court's line colour (CourtGeometry sets --court-line; fallback white).
     color-mix keeps each marking's original opacity so the visual hierarchy survives a recolour. */
  border: 2px solid color-mix(in srgb, var(--court-line, #fff) 50%, transparent);
  border-radius: 6px;
  cursor: crosshair;
  overflow: hidden;
  /* A Shift-click (the feed) would otherwise extend a text selection across the page. */
  -webkit-user-select: none;
  user-select: none;
}
/* Non-attacking half — dimmed so the active attacking end stands out. Positioned via inline
   `left` (0 or 50%) from _court_shade; pointer-events:none keeps click-to-place working. */
.court__shade { position: absolute; top: 0; bottom: 0; width: 50%; background: rgba(0,0,0,0.32); pointer-events: none; z-index: 1; transition: left .15s ease; }
.court__centerline { position: absolute; left: 50%; top: 0; bottom: 0; width: 2px; background: color-mix(in srgb, var(--court-line, #fff) 40%, transparent); z-index: 2; }
/* Penalty area — stadium 2.5 m around the post, the spot, and the line between them.
   Dimensions scale with the court (var fallbacks = standard 40x20); `left` is set inline. */
.court__penalty-area {
  position: absolute;
  width: var(--penalty-area-w, 18.75%); height: var(--penalty-area-h, 25%); top: var(--penalty-area-top, 37.5%);
  box-sizing: border-box;
  border: 2px solid color-mix(in srgb, var(--court-line, #fff) 30%, transparent); border-radius: 999px;
  background: color-mix(in srgb, var(--court-line, #fff) 4%, transparent); pointer-events: none;
}
/* Free-pass circle — radius 2.5 m centred on the penalty spot */
.court__freepass {
  position: absolute;
  width: var(--freepass-w, 12.5%); height: var(--freepass-h, 25%); top: 50%;
  transform: translate(-50%, -50%); box-sizing: border-box;
  border: 2px solid color-mix(in srgb, var(--court-line, #fff) 40%, transparent); border-radius: 50%; pointer-events: none;
}
/* Penalty mark/spot — 2.5 m in front of the post */
.court__penalty-spot {
  position: absolute; width: 6px; height: 6px; margin: -3px 0 0 -3px; top: 50%;
  background: color-mix(in srgb, var(--court-line, #fff) 70%, transparent); border-radius: 50%; pointer-events: none;
}
.court__korf {
  position: absolute; width: 16px; height: 16px; margin: -8px 0 0 -8px; z-index: 2;
  border: 3px solid #ffd54f; border-radius: 50%; background: rgba(0,0,0,0.2);
}
.court__marker {
  position: absolute; width: 14px; height: 14px; margin: -7px 0 0 -7px; z-index: 3;
  background: var(--accent); border: 2px solid #fff; border-radius: 50%; pointer-events: none;
}
/* Hover readout — distance from the nearest korf, shown beside the pointer */
.court__hover {
  position: absolute; z-index: 4; padding: 1px 6px;
  font-size: 0.72rem; line-height: 1.5; font-variant-numeric: tabular-nums;
  color: #fff; background: rgba(0,0,0,0.6); border-radius: 4px;
  white-space: nowrap; pointer-events: none;
}

/* --- SVG court (courts/_diagram) ---
   The court page's, a fixture's shot map's and the New drill chooser's court. Its viewBox is in metres, so every stroke width and radius below is
   a real distance (0.1 = 10 cm lines). Floor/line colours use the same custom properties as the
   CSS-span entry court so a court's colours apply to both diagrams. */
.court-svg { display: block; width: 100%; height: auto; border-radius: 6px; touch-action: none; user-select: none; }
/* A half-court view is square, so at full width it would stand twice as tall as the 2:1 full
   court. Half the width keeps it the same height, centred. */
.court-svg[data-court-view="left_half"], .court-svg[data-court-view="right_half"] { width: 50%; margin: 0 auto; }
.court-svg__floor { fill: var(--court-floor, #1b5e20); }
.court-svg__boundary { fill: rgba(255,255,255,0.08); stroke: color-mix(in srgb, var(--court-line, #fff) 50%, transparent); stroke-width: 0.1; }
.court-svg__centreline { stroke: color-mix(in srgb, var(--court-line, #fff) 40%, transparent); stroke-width: 0.1; }
.court-svg__penalty-area { fill: color-mix(in srgb, var(--court-line, #fff) 4%, transparent); stroke: color-mix(in srgb, var(--court-line, #fff) 30%, transparent); stroke-width: 0.1; }
.court-svg__freepass { fill: none; stroke: color-mix(in srgb, var(--court-line, #fff) 40%, transparent); stroke-width: 0.1; }
.court-svg__penalty-spot { fill: color-mix(in srgb, var(--court-line, #fff) 70%, transparent); }
.court-svg__korf { fill: rgba(0,0,0,0.2); stroke: #ffd54f; stroke-width: 0.15; }
/* A hall's other markings (HallMarkings, hall_markings_svg): each sport's lines in its own colour (the
   group's `color`), under korfball's. On the court page and form the hall round the court is the floor
   darkened; on the entry court they're faint, with lines a pixel and a half wide however the court is
   stretched, and the Hall markings tick (hall_markings_toggle_controller.js) hides them. */
.court-svg__hall { fill: color-mix(in srgb, var(--court-floor, #1b5e20) 65%, #000); }
.hall-marking { fill: none; stroke: currentColor; stroke-width: 0.08; }
.hall-marking .hall-marking__spot { fill: currentColor; stroke: none; }
.court__hall { position: absolute; inset: 0; width: 100%; height: 100%; opacity: 0.5; pointer-events: none; }
.court__hall .hall-marking > * { stroke-width: 1.5px; vector-effect: non-scaling-stroke; }
html[data-hall-markings="hidden"] .court__hall { display: none; }
.hall-toggle { display: inline-flex; align-items: center; gap: var(--space-1); font-size: 0.85rem; color: var(--muted); white-space: nowrap; cursor: pointer; }
.hall-toggle input { margin: 0; }

/* --- Court page and form (courts/show, courts/_form) --- */
/* Tables drop the line under their last row, but here it runs full width as the divider above
   the court preview (only the td loses it by default, so a row-header th kept a stub of it).
   Square corners, or the table's rounded clip trims the ends of that line. */
.court-details table { border-radius: 0; }
.court-details tr:last-child td { border-bottom: 1px solid var(--line); }
.court-details .court-preview { margin-top: var(--space-4); }
/* Just a picture: let a touch on it scroll the page (.court-svg blocks that, for pages that drag on it). */
.court-preview .court-svg { touch-action: auto; }
.court-preview--form { max-width: 28rem; } /* the form inputs' width */
/* The court form's hall markings (courts/_hall_markings_fields): a row of small fields per marking. */
.hall-markings { border: 1px solid var(--line); border-radius: var(--radius); padding: var(--space-3) var(--space-4); margin: 0 0 var(--space-4); max-width: 44rem; }
.hall-markings legend { padding: 0 var(--space-1); color: var(--ink); font-weight: 600; }
.hall-markings__list { list-style: none; margin: var(--space-3) 0 0; padding: 0; display: grid; gap: var(--space-3); }
.hall-markings__list:empty { display: none; }
.hall-marking-row { padding-top: var(--space-3); border-top: 1px solid var(--line); }
.hall-marking-row__head { display: flex; align-items: center; gap: var(--space-2); margin-bottom: var(--space-2); }
.hall-marking-row__head strong { margin-right: auto; }
.hall-marking-row__fields { display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-3); }
.hall-marking-row__fields label { margin: 0; }
.hall-marking-row__fields input { display: block; margin-top: var(--space-1); }
form .hall-marking-row__fields input[type="number"] { width: 6.5rem; }
form .hall-marking-row__fields input[type="text"] { width: 12rem; }
.hall-markings__add { display: flex; flex-wrap: wrap; align-items: end; gap: var(--space-2); margin-top: var(--space-3); }
.hall-markings__add label { margin: 0; }
form .hall-markings__add select { width: auto; display: block; margin-top: var(--space-1); }
/* The court page's list of them. */
.hall-markings-list { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-2); }
.hall-markings-list__swatch { display: inline-block; width: 0.9rem; height: 0.9rem; margin-right: var(--space-1); border-radius: 3px; vertical-align: middle; }

/* The search row every directory list shares (shared/_directory_filter), and the drills library's tags. */
.drill-filter { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; margin: var(--space-3) 0; }
.drill-filter input[type="search"] { max-width: 20rem; padding: var(--space-2) var(--space-3); background: var(--bg); border: 1px solid var(--line); border-radius: var(--radius); color: var(--ink); }
.drill-tags { display: flex; flex-wrap: wrap; gap: var(--space-1); margin: 0 0 var(--space-3); }
.drill-tag { text-decoration: none; }
.drill-tag:hover { border-color: var(--accent); color: var(--ink); }
.drill-tags-cell .badge { margin-right: var(--space-1); }
/* The drills library's filter (v2/drills/index), and the search row every directory list shares. */
.drill-share__row { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; }
.drill-share__row form { margin: 0; }
.drill-share__link { flex: 1 1 20rem; min-width: 0; padding: var(--space-2) var(--space-3); background: var(--bg); color: var(--ink); border: 1px solid var(--line); border-radius: var(--radius); font-size: var(--font-sm); }
.drill-share p { margin: var(--space-2) 0 0; font-size: var(--font-sm); }
.drill-share form.drill-share__row { margin: 0; }
.drill-share .drill-share__period { margin-top: var(--space-2); }
.drill-share__row label { margin: 0; display: inline; color: var(--muted); font-size: var(--font-sm); }
.drill-share__row select { width: auto; }
/* A team report's Share card (reports/_team_report_share): its other links, one to a line. */
.team-report-share__others { margin-top: var(--space-3); }
.team-report-share__others h3 { margin: 0 0 var(--space-2); font-size: var(--font-sm); color: var(--muted); }
.team-report-share__others ul { margin: 0; padding: 0; list-style: none; display: grid; gap: var(--space-2); }
.team-report-share__others li { justify-content: space-between; font-size: var(--font-sm); }

/* A drill's Videos and pictures card (drill_media/_card): links to videos, YouTube and Vimeo playing
   in a 16:9 frame, then uploaded pictures and videos, each in the same frame (letterboxed, as they
   aren't resized), and the forms to add more. */
.drill-media { margin-top: var(--space-4); }
.drill-media h2 { margin-top: 0; }
.drill-media h3 { font-size: var(--font-md); margin: 0 0 var(--space-2); }
.drill-media__grid { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 20rem), 1fr)); gap: var(--space-4); }
.drill-media__item { display: flex; flex-direction: column; gap: var(--space-2); min-width: 0; }
.drill-media .video-embed { margin-top: 0; }
.drill-media .video-embed iframe { border: 0; background: #000; }
.drill-media__picture { display: block; }
.drill-media__video, .drill-media__picture img { display: block; width: 100%; aspect-ratio: 16 / 9; object-fit: contain; background: #000; border-radius: var(--radius-sm); }
.drill-media__site { display: flex; flex-direction: column; justify-content: center; align-items: center; gap: var(--space-1); aspect-ratio: 16 / 9; padding: var(--space-3); border: 1px dashed var(--line); border-radius: var(--radius-sm); background: var(--bg); color: var(--ink); text-align: center; text-decoration: none; }
.drill-media__site:hover { border-color: var(--accent); }
.drill-media__site-name { font-size: var(--font-lg); font-weight: 600; overflow-wrap: anywhere; }
.drill-media__caption { display: flex; flex-direction: column; gap: var(--space-1); font-size: var(--font-sm); }
.drill-media__title { font-weight: 600; overflow-wrap: anywhere; }
.drill-media__meta { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); min-height: 2rem; }
.drill-media__meta form { margin: 0 0 0 auto; }
.drill-media__add { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 20rem), 1fr)); gap: var(--space-5); margin-top: var(--space-4); padding-top: var(--space-4); border-top: 1px solid var(--line); }
.drill-media__form { margin: 0; min-width: 0; }
.drill-media__form .field { margin-bottom: var(--space-2); }
.drill-media__form input[type="file"] { max-width: 100%; color: var(--muted); font-size: var(--font-sm); }
.drill-media__form input[type="file"]::file-selector-button { margin-right: var(--space-2); padding: 0.3rem 0.6rem; border: 1px solid var(--line); border-radius: var(--radius); background: var(--panel-2); color: var(--ink); font: inherit; cursor: pointer; }
.drill-media__form input[type="file"]:hover::file-selector-button { border-color: var(--accent); }
.drill-media__hint { margin: var(--space-2) 0 0; font-size: var(--font-sm); }
.drill-media__error { margin: var(--space-2) 0; color: var(--bad); font-size: var(--font-sm); }
.drill-media__progress { list-style: none; margin: var(--space-2) 0 0; padding: 0; font-size: var(--font-sm); }
.drill-media__progress:empty { display: none; }
.drill-media__progress li { display: flex; align-items: center; gap: var(--space-2); }
.drill-media__progress-name { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.drill-media__progress progress { flex: 0 0 8rem; accent-color: var(--accent); }

/* The fixture page's Sharing card: the clubs a fixture is shared with, and sharing with another. */
.fixture-share__list { list-style: none; margin: 0; padding: 0; }
.fixture-share__row { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; padding: var(--space-2) 0; border-bottom: 1px solid var(--line); }
.fixture-share__row form { margin: 0 0 0 auto; }
.fixture-share__form { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; margin-top: var(--space-3); }
.fixture-share__form label { margin: 0; }
.fixture-share__form select { width: auto; flex: 0 1 18rem; min-width: 0; }
.fixture-share p { margin: var(--space-2) 0 0; font-size: var(--font-sm); }

/* Notes (notes/_card, _note, show) on a player, team, fixture or drill, and their replies. */
.notes h2, .note-replies h2 { margin-top: 0; }
.note-list { list-style: none; margin: var(--space-3) 0 0; padding: 0; }
.note-list > li + li { border-top: 1px solid var(--line); }
.note { padding: var(--space-3) 0; }
.card > .note { padding: 0; }
.note__meta { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1) var(--space-3); margin: 0 0 var(--space-2); color: var(--muted); font-size: var(--font-sm); }
.note__body { overflow-wrap: anywhere; }
.note__actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); margin-top: var(--space-2); }
.note__actions form { margin: 0; }
.note__kind { vertical-align: middle; }
.notes-table__about { display: flex; flex-direction: column; align-items: flex-start; gap: var(--space-1); min-width: 10rem; }
.note-form { margin: 0 0 var(--space-3); }
.note-form .field { margin-bottom: var(--space-2); }
.note-form__actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); }
.note-form__actions label { margin: 0; }
.note-form__actions select { width: auto; flex: 0 1 18rem; min-width: 0; }
.note-form__hint { margin: var(--space-2) 0 0; font-size: var(--font-sm); }
.note-form__privacy { margin: var(--space-2) 0 0; font-size: var(--font-sm); }
.rich-text__error { margin: var(--space-1) 0 0; color: var(--bad); font-size: var(--font-sm); }
/* A team's coaches for a season (teams/_coaches). */
.team-coaches__head { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3); }
.team-coaches__head h2 { margin: 0; }
.team-coaches__season { display: flex; align-items: center; gap: var(--space-2); margin: 0; }
.team-coaches__season select { width: auto; }
.team-coaches__list { list-style: none; margin: var(--space-3) 0 0; padding: 0; }
.team-coaches__form { display: flex; flex-wrap: wrap; align-items: flex-end; gap: var(--space-3); margin-top: var(--space-3); }
.team-coaches__form .field { flex: 1 1 13rem; margin: 0; }
.team-coaches p { margin: var(--space-2) 0 0; font-size: var(--font-sm); }
/* Text for screen readers only (a field's label where the card heading already says it). */
.visually-hidden { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
/* Locked drills and deletion requests (drills/_lock, the drills index, the dashboard). */
.badge--warn { color: var(--accent); border-color: rgba(255, 159, 28, 0.5); }
.badge--bad { color: var(--bad); border-color: rgba(255, 107, 107, 0.5); }
.drill-lock__row { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; }
.drill-lock__row form, form.drill-lock__row { margin: 0; }
.drill-lock__row + .drill-lock__row, .drill-lock__reason + .drill-lock__row { margin-top: var(--space-3); }
.drill-lock__reason { margin: var(--space-3) 0 0; padding-left: var(--space-3); border-left: 3px solid var(--line); white-space: pre-wrap; }
form input.drill-lock__reason-field { flex: 1 1 20rem; min-width: 0; max-width: none; width: auto; }
.drill-lock p { margin: var(--space-2) 0 0; font-size: var(--font-sm); }
.drill-lock__note { margin-top: calc(-1 * var(--space-2)); font-size: var(--font-sm); }
.shared-drill__brand { align-self: flex-start; }
/* What only the site admins see (RoleOnlyHelper), shown to them alone. A pill labels a title, field,
   card, tab or link; a rule down the left edge marks a block, or a control repeated down a table.
   Admin: outlined, a single rule. Super admin: filled, a double rule, so the two differ without
   colour. */
.role-badge { display: inline-block; padding: 0 var(--space-2); border: 1px solid var(--role-admin); border-radius: var(--radius-pill); color: var(--role-admin); font-size: var(--font-xs); font-weight: 700; line-height: 1.6; letter-spacing: .02em; vertical-align: middle; white-space: nowrap; }
.role-badge--super-admin { background: var(--role-super); border-color: var(--role-super); color: var(--role-super-ink); }
/* `form select` beats the filter bars' own select borders (.audit-filter select). */
.role-only, form select.role-only { border-left: 3px solid var(--role-admin); }
.role-only--super-admin, form select.role-only--super-admin { border-left: 5px double var(--role-super); }
:is(div, section, article, td, p).role-only:not(.card) { padding-left: var(--space-3); }
a.role-only:not(.btn) { padding-left: var(--space-2); }
/* --- Guides (guides/*): a reading column with screenshots breaking out wider than the text. --- */
.guide-list { display: grid; grid-template-columns: repeat(auto-fill, minmax(18rem, 1fr)); gap: var(--space-4); }
.guide-card { display: block; text-decoration: none; color: inherit; }
.guide-card h2 { margin: 0 0 var(--space-2); font-size: var(--font-md); }
.guide-card p { margin: 0; }
.guide { max-width: 58rem; margin: 0 auto; }
.guide__head { padding-bottom: var(--space-4); margin-bottom: var(--space-6); border-bottom: 2px solid var(--court-floor, #1b5e20); }
.guide__eyebrow { margin: 0 0 var(--space-2); font-size: var(--font-xs); font-weight: 600; text-transform: uppercase; letter-spacing: .12em; color: var(--muted); }
.guide__eyebrow a { color: inherit; }
.guide__head h1 { margin: 0 0 var(--space-2); text-wrap: balance; }
.guide__lede { margin: 0; max-width: 60ch; font-size: var(--font-md); color: var(--muted); }
.guide__toc { display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-4); margin-top: var(--space-3); font-weight: 600; }
.guide__toc a { color: var(--ink); text-decoration: none; border-bottom: 2px solid var(--line); }
.guide__toc a:hover, .guide__toc a:focus-visible { border-color: var(--accent); outline: none; }
.guide__section { display: grid; gap: var(--space-3); margin-bottom: var(--space-6); }
.guide__section-head { display: grid; grid-template-columns: auto 1fr; gap: var(--space-3); align-items: baseline; }
.guide__step-no { font-size: 2.4rem; line-height: 1; font-weight: 700; color: var(--ok); font-variant-numeric: tabular-nums; }
.guide__section h2 { margin: 0; text-wrap: balance; }
.guide__section h3 { margin: var(--space-2) 0 0; font-size: var(--font-md); }
.guide__section p, .guide__section li { max-width: 66ch; margin: 0; line-height: var(--line-normal); }
.guide__section ul, .guide__section ol { margin: 0; padding-left: 1.3rem; display: grid; gap: var(--space-2); }
.guide__section li::marker { color: var(--ok); font-weight: 600; }
.guide__figure { margin: var(--space-2) 0 0; display: grid; gap: var(--space-2); }
.guide__figure img { display: block; width: 100%; height: auto; border: 1px solid var(--line); border-top: 4px solid var(--ok); border-radius: var(--radius-sm); }
.guide__figure figcaption { font-size: var(--font-sm); color: var(--muted); }
.guide__callout { display: grid; gap: var(--space-1); padding: var(--space-3) var(--space-4); background: var(--panel); border-left: 4px solid var(--ok); border-radius: 0 var(--radius) var(--radius) 0; }
.guide__callout-label { font-size: var(--font-xs); font-weight: 700; text-transform: uppercase; letter-spacing: .1em; color: var(--ok); }
.guide__section--tips { border-top: 2px solid var(--court-floor, #1b5e20); padding-top: var(--space-4); }
.guide kbd { font-family: inherit; font-size: .85em; padding: 0 .35em; border: 1px solid var(--line); border-bottom-width: 2px; border-radius: 3px; background: var(--bg); }
.guide__foot { display: flex; gap: var(--space-2); margin: 0; }
/* The Draw with AI guide's copyable instructions for AIs without the korfcoach skill. */
.guide__instructions { display: grid; gap: var(--space-2); justify-items: start; }
.guide__instructions textarea {
  width: 100%; padding: var(--space-2) var(--space-3); background: var(--bg); color: var(--ink);
  border: 1px solid var(--line); border-radius: var(--radius); font-size: var(--font-xs);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
}
.guide code { font-size: .9em; padding: 0 .3em; border-radius: 3px; background: var(--bg); }
.guide sub { line-height: 0; } /* B₂, a drill label: keeps its line from opening up */
/* The Draw with AI guide's example requests: what a coach types into the chat, wrapped as typed. */
.guide__example {
  max-width: 66ch; margin: var(--space-2) 0 0; padding: var(--space-3); background: var(--bg); color: var(--ink);
  border: 1px solid var(--line); border-left: 4px solid var(--ok); border-radius: 0 var(--radius) var(--radius) 0;
  font-family: inherit; font-size: var(--font-sm); line-height: var(--line-normal); white-space: pre-wrap;
}

/* The Features page (features/index, feature_tour_controller.js): a carousel with a slide per
   feature, its picture beside what it does (above it, on a phone). The track is a row that scrolls
   sideways and snaps, one slide at a time, so it swipes and works without the controller; its
   scrollbar is hidden, as Previous/Next, the arrow keys and the sections move it. */
.tour { scroll-margin-top: 5rem; }
.tour__sections { display: flex; flex-wrap: wrap; gap: var(--space-2); margin-bottom: var(--space-4); }
.tour__section {
  display: inline-flex; align-items: center; gap: var(--space-2); padding: var(--space-1) var(--space-3);
  border: 1px solid var(--line); border-radius: var(--radius-pill); color: var(--muted);
  font-size: var(--font-sm); font-weight: 600;
}
.tour__section:hover { color: var(--ink); border-color: var(--muted); text-decoration: none; }
.tour__section:focus-visible { outline: none; box-shadow: var(--shadow-focus); }
.tour__section[aria-current="true"] { color: var(--ink); border-color: var(--accent); }
.tour__count { color: var(--muted); font-weight: 500; font-variant-numeric: tabular-nums; }
.tour__track {
  position: relative; display: grid; grid-auto-flow: column; grid-auto-columns: 100%; gap: var(--space-4);
  overflow-x: auto; overscroll-behavior-x: contain; scroll-snap-type: x mandatory; scrollbar-width: none;
  border-radius: var(--radius-lg);
}
.tour__track::-webkit-scrollbar { display: none; }
.tour__track:focus-visible { outline: none; box-shadow: var(--shadow-focus); }
/* A slide linked to (/features#notes) lands clear of the sticky site header. */
.tour__slide {
  scroll-snap-align: start; scroll-snap-stop: always; scroll-margin-top: 5rem;
  display: grid; grid-template-columns: minmax(0, 3fr) minmax(0, 2fr); gap: var(--space-5); align-items: center;
  padding: var(--space-5); background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius-lg);
}
.tour__figure { margin: 0; }
.tour__figure img {
  display: block; width: 100%; height: auto; aspect-ratio: 16 / 10; object-fit: cover; object-position: top;
  background: var(--bg); border: 1px solid var(--line); border-top: 4px solid var(--ok); border-radius: var(--radius-sm);
}
.tour__body { display: grid; gap: var(--space-3); align-content: center; }
.tour__eyebrow {
  display: flex; align-items: center; gap: var(--space-2); margin: 0;
  font-size: var(--font-xs); font-weight: 600; text-transform: uppercase; letter-spacing: .12em; color: var(--muted);
}
.tour__title { margin: 0; font-size: var(--font-lg); text-wrap: balance; }
.tour__summary { margin: 0; line-height: var(--line-normal); }
.tour__points { display: grid; gap: var(--space-1); margin: 0; padding-left: 1.2rem; color: var(--muted); font-size: var(--font-sm); line-height: var(--line-normal); }
.tour__points li::marker { color: var(--ok); }
.tour__actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); margin-top: var(--space-1); }
.tour__actions .btn { display: inline-flex; align-items: center; gap: var(--space-2); }
.tour__audience { margin: 0; padding: var(--space-2) var(--space-3); color: var(--muted); font-size: var(--font-sm); border: 1px dashed var(--line); border-radius: var(--radius); }
.tour__controls { display: flex; align-items: center; justify-content: center; gap: var(--space-4); margin: var(--space-4) 0 var(--space-6); }
.tour__position { min-width: 6rem; margin: 0; text-align: center; color: var(--muted); font-variant-numeric: tabular-nums; }
.tour__step:disabled { opacity: .45; cursor: default; border-color: var(--line); transform: none; box-shadow: none; }
.features__all h2 { margin: 0 0 var(--space-3); }
.features__index { display: grid; grid-template-columns: repeat(auto-fill, minmax(13rem, 1fr)); gap: var(--space-4) var(--space-5); }
.features__index h3 { margin: 0 0 var(--space-2); font-size: var(--font-xs); text-transform: uppercase; letter-spacing: .12em; color: var(--muted); }
.features__index ul { display: grid; gap: var(--space-1); margin: 0; padding: 0; list-style: none; }
@media (prefers-reduced-motion: no-preference) { .tour__track { scroll-behavior: smooth; } }
@media (max-width: 800px) {
  .tour__slide { grid-template-columns: minmax(0, 1fr); gap: var(--space-4); padding: var(--space-3); align-items: start; }
  .tour__controls { justify-content: space-between; gap: var(--space-2); }
}

/* Training-session plan: an ordered list of drills/items with minutes and per-item actions. */
.session-plan { list-style: none; margin: 0 0 var(--space-4); padding: 0; }
.session-plan__item { display: flex; justify-content: space-between; align-items: flex-start; gap: var(--space-3); padding: var(--space-3) 0; border-top: 1px solid var(--line); }
.session-plan__item:first-child { border-top: none; }
.session-plan__main { display: flex; gap: var(--space-3); align-items: flex-start; min-width: 0; }
.session-plan__number { flex: 0 0 auto; width: 1.8rem; height: 1.8rem; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center; background: var(--panel-2); color: var(--muted); font-size: var(--font-sm); font-weight: 600; }
.session-plan__name { font-size: var(--font-base); }
.session-plan__meta { display: block; font-size: var(--font-sm); margin-top: var(--space-1); }
.session-plan__meta .badge { margin-left: var(--space-1); }
.session-plan__notes { margin: var(--space-2) 0 0; color: var(--muted); font-size: var(--font-sm); }
.session-plan__notes p { margin: 0; }
.session-plan__side { display: flex; align-items: center; gap: var(--space-3); flex: 0 0 auto; }
.session-plan__minutes { min-width: 4rem; text-align: right; font-variant-numeric: tabular-nums; }
.session-plan__actions { display: inline-flex; gap: var(--space-1); }
.session-plan__actions form { margin: 0; }
.session-plan__actions .btn[disabled] { opacity: 0.4; cursor: default; }
.session-item-form { border-top: 1px solid var(--line); padding-top: var(--space-4); }
.session-item-form h3 { margin: 0 0 var(--space-3); font-size: var(--font-base); }
.session-item-form__row { display: grid; grid-template-columns: minmax(0, 2fr) minmax(0, 2fr) minmax(0, 1fr); gap: var(--space-3); }
.session-item-form__row .field { margin-bottom: var(--space-3); }
@media (max-width: 700px) { .session-item-form__row { grid-template-columns: 1fr; } }
/* Feedback (tickets/_dialog, ticket_request_controller.js): the entry-flow dialog look, wide enough
   for its three templates side by side, scrolling inside on a short window. The form hides while
   the thanks is showing. */
.entry-flow.ticket-dialog { max-width: min(94vw, 44rem); } /* .entry-flow's own width comes later */
.ticket-dialog .entry-flow__panel { max-height: min(90vh, 52rem); overflow-y: auto; }
.ticket-dialog__title { margin: 0; font-size: var(--font-md); }
.ticket-dialog:has(.ticket-sent) .ticket-form { display: none; }
.ticket-form { margin-top: var(--space-3); }
.ticket-form fieldset { border: 0; margin: 0; padding: 0; min-width: 0; }
.ticket-form fieldset[hidden] { display: none; }
.ticket-form .field { margin-bottom: var(--space-3); }
.ticket-form .field label { color: var(--ink); font-weight: 600; }
.ticket-form input[type="text"], .ticket-form textarea { max-width: none; }
.ticket-form textarea { resize: vertical; font: inherit; }
.ticket-form .errors:focus { outline: none; }
.ticket-form .errors ul { margin: 0; padding-left: 1.2rem; }
.ticket-form__legend {
  padding: 0; margin: 0 0 var(--space-2); font-size: var(--font-xs); font-weight: 600;
  text-transform: uppercase; letter-spacing: 0.06em; color: var(--muted);
}
.ticket-form__hint { margin: 0 0 var(--space-1); color: var(--muted); font-size: var(--font-xs); }
.ticket-form__optional { color: var(--muted); font-weight: 400; }
/* The templates as cards, three across or one above another: a visually hidden radio each, the card
   showing its state. */
.ticket-form .ticket-form__templates { display: grid; grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr)); gap: var(--space-2); margin-bottom: var(--space-4); }
form .ticket-template { position: relative; margin: 0; color: var(--ink); font-size: var(--font-base); cursor: pointer; }
.ticket-template__input { position: absolute; opacity: 0; width: 1px; height: 1px; margin: 0; }
.ticket-template__card {
  display: grid; grid-template-columns: auto minmax(0, 1fr); align-items: start; gap: 2px var(--space-2); height: 100%;
  padding: var(--space-3); background: var(--bg); border: 1px solid var(--line); border-radius: var(--radius);
  transition: border-color var(--transition-fast), background var(--transition-fast);
}
.ticket-template__icon { margin-top: 0.15rem; color: var(--accent); }
.ticket-template__name { font-weight: 600; }
.ticket-template__blurb { grid-column: 2; color: var(--muted); font-size: var(--font-sm); }
.ticket-template:hover .ticket-template__card { border-color: var(--accent); }
.ticket-template__input:checked + .ticket-template__card { border-color: var(--accent); background: var(--panel-2); box-shadow: inset 0 0 0 1px var(--accent); }
.ticket-template__input:focus-visible + .ticket-template__card { box-shadow: var(--shadow-focus); }
/* A question answered by picking one of its choices (how often, how much it gets in the way): its
   legend reads like the other questions' labels, the choices a wrapping row of pills, each a
   visually hidden radio. */
.ticket-form .ticket-form__question { display: block; padding: 0; margin-bottom: var(--space-1); color: var(--ink); font-size: var(--font-sm); font-weight: 600; }
.ticket-choices { display: flex; flex-wrap: wrap; gap: var(--space-2); }
.ticket-form .field .ticket-choice { position: relative; display: inline-flex; margin: 0; color: var(--ink); font-weight: 400; cursor: pointer; }
.ticket-choice__input { position: absolute; opacity: 0; width: 1px; height: 1px; margin: 0; }
.ticket-choice__label {
  padding: 0.35rem 0.85rem; background: var(--bg); border: 1px solid var(--line); border-radius: var(--radius-pill);
  transition: border-color var(--transition-fast), background var(--transition-fast);
}
.ticket-choice:hover .ticket-choice__label { border-color: var(--accent); }
.ticket-choice__input:checked + .ticket-choice__label { border-color: var(--accent); background: var(--panel-2); box-shadow: inset 0 0 0 1px var(--accent); font-weight: 600; }
.ticket-choice__input:focus-visible + .ticket-choice__label { box-shadow: var(--shadow-focus); }
/* What goes with the request: who from, and the page. */
.ticket-form__context { padding: var(--space-3); border: 1px dashed var(--line); border-radius: var(--radius); }
.ticket-form__facts { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: var(--space-1) var(--space-3); margin: 0 0 var(--space-2); font-size: var(--font-sm); }
.ticket-form__facts dt { color: var(--muted); }
.ticket-form__facts dd { margin: 0; overflow-wrap: anywhere; }
.ticket-form__foot { display: flex; justify-content: flex-end; flex-wrap: wrap; gap: var(--space-2); }
.ticket-sent { margin-top: var(--space-3); }
.ticket-sent__title { margin: 0 0 var(--space-2); font-size: var(--font-md); font-weight: 600; color: var(--ok); }

/* The tickets list and a ticket's page. The list reloads in its frame once a ticket's sent
   (ticket_list_controller.js); a custom element is inline unless told otherwise. */
#tickets-list { display: block; }
.ticket-answers { margin: 0; }
.ticket-answers dt { font-weight: 600; margin-top: var(--space-4); }
.ticket-answers dt:first-child { margin-top: 0; }
.ticket-answers dd { margin: var(--space-1) 0 0; white-space: pre-wrap; overflow-wrap: anywhere; }
.ticket-facts, .profile-facts { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: var(--space-2) var(--space-4); margin: 0; font-size: var(--font-sm); }
.ticket-facts dt, .profile-facts dt { color: var(--muted); }
.ticket-facts dd, .profile-facts dd { margin: 0; overflow-wrap: anywhere; }
/* A drill's print sheet (v2/drills/print) and its share page's head (v2/shared_drills/show). */
.drill-print__head { display: flex; justify-content: space-between; gap: var(--space-4); align-items: flex-start; flex-wrap: wrap; }
.drill-print__head h1 { margin-bottom: var(--space-1); }
.drill-print__description { max-width: 60ch; }
.drill-print__media { margin-top: var(--space-5); break-inside: avoid; }
.drill-print__media h2 { font-size: var(--font-md); margin: 0 0 var(--space-2); }
.drill-print__media-list { margin: 0 0 var(--space-3); padding-left: var(--space-5); overflow-wrap: anywhere; }
.drill-print__pictures { display: flex; flex-wrap: wrap; gap: var(--space-3); }
.drill-print__pictures img { max-width: calc(50% - var(--space-3)); max-height: 16rem; object-fit: contain; break-inside: avoid; }
@media print {
  .drill-print__actions { display: none !important; }
  .print-layout { background: #fff; color: #000; }
  .print-layout .card { box-shadow: none; border: 1px solid #999; background: #fff; }
  .print-layout .muted { color: #333; }
}

.event-feed { list-style: none; margin: 0; padding: 0; max-height: 60vh; overflow-y: auto; }
/* Each event is tight, wrapping inline text — it fills the sidebar width and wraps within it
   (like the original) but with smaller type, tight leading, and a corner delete to cut height. */
.event-row {
  position: relative;
  padding: 0.2rem 2.4rem 0.2rem 0.55rem; /* right pad clears the corner edit + delete */
  border-bottom: 1px solid var(--line);
  border-left: 3px solid transparent;
  font-size: 0.8rem; line-height: 1.4;
}
.event-row--home { border-left-color: var(--accent); }
.event-row--away { border-left-color: #58a6ff; }
.event-row__period {
  color: var(--muted); font-size: 0.68rem; text-transform: uppercase;
  font-variant-numeric: tabular-nums; margin-right: 0.15rem;
}
.event-row__clock {
  color: var(--muted); font-size: 0.68rem; font-variant-numeric: tabular-nums; margin-right: 0.3rem;
}
.event-row__desc { font-weight: 600; }
.event-row__desc--goal { color: var(--ok); }
.event-row__player { color: var(--muted); }
.event-row__player::before,
.event-row__detail::before { content: "· "; color: var(--line); }
.event-row__detail { color: var(--muted); }
/* Edit (✎) + delete (✕) tucked into the top-right corner, over the wrapping event text. */
.event-row__actions { position: absolute; top: 0.1rem; right: 0.15rem; display: inline-flex; align-items: center; gap: 0.05rem; line-height: 1; }
.event-row__delete-form { line-height: 1; } /* positioning now lives on .event-row__actions */
.event-row__edit, .event-row__delete {
  padding: 0 0.3rem; border: none; background: transparent; text-decoration: none;
  color: var(--muted); font-size: 0.78rem; line-height: 1.3; cursor: pointer;
  opacity: 0.35; transition: color var(--transition-fast), opacity var(--transition-fast);
}
.event-row:hover .event-row__edit, .event-row:hover .event-row__delete { opacity: 1; }
.event-row__edit:hover { color: var(--accent); border-color: transparent; transform: none; box-shadow: none; }
.event-row__delete:hover { color: var(--bad); border-color: transparent; transform: none; box-shadow: none; }

/* Collapsed, this card holds only the two buttons; drop the extra .actions margin
   so they aren't stranded in whitespace (the card's own padding is enough). */
.card--video .actions { margin: 0; }
.video-embed { position: relative; padding-bottom: 56.25%; height: 0; margin-top: 0.5rem; }
.video-embed iframe { position: absolute; top: 0; left: 0; width: 100%; height: 100%; border-radius: 6px; }

.team-actions h4 { margin: 0 0 0.5rem; }
/* The one-team screens' per-team Substitute buttons sit in the page's own row of controls: the
   #substitutions wrapper steps aside so each team's button lays out with the buttons beside it. */
.substitutions { display: contents; }
.substitution form { margin: 0; } /* holds the picker's hidden fields and dialog, nothing visible */

/* Single Substitute control at the bottom of the court card: a button that drops down a list of
   teams, each opening the substitution popover scoped to that team. */
.court-controls { position: relative; margin-top: var(--space-3); }
/* Court entry's "Home shoots ← Left / Right →", until the first event (entry/_starting_end): at the
   right-hand end of the court controls' row, its wrapper making it part of that row. */
.starting-end-slot { display: contents; }
/* Two classes, to beat .view-toggle's margin further down, which would make the row taller. */
.view-toggle.starting-end { align-items: center; margin: 0 0 0 auto; }
.court-controls__actions { display: flex; align-items: center; flex-wrap: wrap; gap: var(--space-2); }
.court-controls__actions form { margin: 0; } /* button_to wraps each button in a form */
.court-controls__toggle::after { content: "▾"; margin-left: 0.4rem; }
/* Opens upward: the trigger sits at the bottom of the court card, whose overflow is clipped, so a
   downward menu would be cut off. */
.court-controls__menu {
  position: absolute; bottom: 100%; left: 0; z-index: 20; margin-bottom: var(--space-1);
  display: flex; flex-direction: column; gap: 2px; min-width: 12rem;
  padding: var(--space-1);
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius);
  box-shadow: var(--shadow-lg);
}
.court-controls__menu[hidden] { display: none; } /* flex would otherwise beat [hidden] */
.court-controls__team {
  display: block; width: 100%; text-align: left;
  background: transparent; border: none; border-radius: var(--radius-sm);
  padding: var(--space-2) var(--space-3); font-weight: 600;
}
.court-controls__team:hover:not([disabled]) { background: var(--panel-2); border-color: transparent; transform: none; box-shadow: none; }
.court-controls__team[disabled] { opacity: 0.4; cursor: default; }
/* Team label above the group in the substitution popover's "who comes off" step. */
.entry-flow__team { font-size: var(--font-xs); text-transform: uppercase; letter-spacing: 0.03em; margin: var(--space-1) 0 var(--space-2); }

.key-hint { display: inline-block; margin-left: 0.25rem; padding: 0 0.3rem; border: 1px solid var(--line); border-radius: 4px; font-size: 0.7rem; color: var(--muted); }

/* --- Mark then enrich (entry/mark, entry/enrich; see EventMark) ---
   One column: the video across the page, then the keys (Mark) or the current mark (Enrich), then the
   timeline of marks; Enrich then has court entry's grid under it. */
.entry--marks:focus { outline: none; } /* it takes focus back from the video, to keep the keys */
/* Widescreen, but short enough on a laptop for the keys (or the current mark) under it to stay in
   view: the window's height less the header and those, never under 18rem. */
.card--video-wide .video-embed {
  padding-bottom: 0; height: auto; aspect-ratio: 16 / 9;
  width: min(100%, calc(max(18rem, 100vh - 22rem) * 16 / 9)); margin-inline: auto;
}

/* The kind buttons as one row of chips, the play controls beside them, wrapping on a narrow screen. */
.mark-controls {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: var(--space-2) var(--space-4); padding: var(--space-3) var(--space-4);
}
.mark-keys { display: flex; flex-wrap: wrap; gap: var(--space-2); }
.mark-key {
  display: inline-flex; align-items: center; gap: var(--space-2);
  padding: 0.3rem 0.7rem; font-size: var(--font-sm); font-weight: 600;
  border-left: 4px solid var(--mark-color, var(--line));
}
.mark-key:hover { border-left-color: var(--mark-color, var(--accent)); }
.mark-key--goal, .mark-row--goal, .mark-timeline__mark--goal, .mark-timeline__lane-name--goal,
.marks-panel__kind--goal { --mark-color: var(--mark-goal); }
.mark-key--shot, .mark-row--shot, .mark-timeline__mark--shot, .mark-timeline__lane-name--shot,
.marks-panel__kind--shot { --mark-color: var(--mark-shot); }
.mark-key--feed, .mark-row--feed, .mark-timeline__mark--feed, .mark-timeline__lane-name--feed,
.marks-panel__kind--feed { --mark-color: var(--mark-feed); }
.mark-key--turnover, .mark-row--turnover, .mark-timeline__mark--turnover, .mark-timeline__lane-name--turnover,
.marks-panel__kind--turnover { --mark-color: var(--mark-turnover); }
.mark-key--other, .mark-row--other, .mark-timeline__mark--other, .mark-timeline__lane-name--other,
.marks-panel__kind--other { --mark-color: var(--mark-other); }
.mark-key--kickoff, .mark-row--kickoff { --mark-color: var(--ink); }
.mark-key[disabled] { opacity: 0.45; cursor: default; }
.mark-key[disabled]:hover { transform: none; box-shadow: none; }
.mark-key__key, .mark-transport kbd {
  font-family: inherit; font-size: var(--font-xs); padding: 0 0.4em; color: var(--ink);
  border: 1px solid var(--line); border-bottom-width: 2px; border-radius: 3px; background: var(--bg);
}
.mark-key__count { color: var(--muted); font-size: var(--font-xs); font-weight: 400; font-variant-numeric: tabular-nums; }
.mark-transport { display: flex; flex-wrap: wrap; gap: var(--space-2); }
.mark-focus-banner { flex-basis: 100%; margin: 0; max-width: none; }
.mark-focus-banner[hidden] { display: none; }

/* The Mark screen's two layouts (mark_layout_controller.js, its Keys switch on the lede row): the keys
   and play controls in a column on the video's left (the default) or below it. Beside needs the width
   for a column and a video, so a narrower screen keeps them below and hides the switch. */
.entry__lede-row {
  display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: var(--space-2) var(--space-4);
  margin: calc(-1 * var(--space-3)) 0 var(--space-3);
}
.entry__lede-row > * { margin: 0; }
.mark-stage { display: grid; grid-template-areas: "video" "keys"; grid-template-columns: minmax(0, 1fr); }
.mark-stage > .card--video { grid-area: video; }
.mark-stage > .mark-controls { grid-area: keys; }
@media (max-width: 899px) { .view-toggle.mark-layout-toggle { display: none; } } /* over .view-toggle's flex, below */
@media (min-width: 900px) {
  [data-mark-layout="beside"] .mark-stage {
    grid-template-areas: "keys video"; grid-template-columns: minmax(12rem, 15rem) minmax(0, 1fr);
    column-gap: var(--space-4); align-items: start;
  }
  [data-mark-layout="beside"] .mark-controls { flex-direction: column; align-items: stretch; }
  [data-mark-layout="beside"] .mark-keys { flex-direction: column; }
  [data-mark-layout="beside"] .mark-key { padding: var(--space-2) var(--space-3); font-size: var(--font-base); }
  [data-mark-layout="beside"] .mark-key__count { margin-left: auto; }
  [data-mark-layout="beside"] .mark-transport { display: grid; grid-template-columns: 1fr 1fr; }
  [data-mark-layout="beside"] .mark-transport__play { grid-column: 1 / -1; grid-row: 1; }
  /* Taller, as nothing sits under it now but the timeline. */
  [data-mark-layout="beside"] .card--video-wide .video-embed { width: min(100%, calc(max(18rem, 100vh - 18rem) * 16 / 9)); }
}
/* A view-toggle of buttons (a switch on the page itself, not a link): the pressed one current. */
.view-toggle button {
  padding: var(--space-1) var(--space-3); border: 1px solid var(--line); border-radius: var(--radius-pill);
  background: transparent; color: var(--muted); font-size: var(--font-sm); line-height: var(--line-normal);
}
.view-toggle button[aria-pressed="true"] { color: var(--ink); border-color: var(--accent); }
.view-toggle button:hover { transform: none; box-shadow: none; }

/* Every mark, under the Mark screen's timeline, scrolling within the card. */
.mark-list { list-style: none; margin: 0; padding: 0; max-height: 22rem; overflow-y: auto; }
.mark-row {
  display: flex; align-items: center; gap: var(--space-2);
  border-bottom: 1px solid var(--line); border-left: 3px solid var(--mark-color, var(--line));
}
.mark-row__jump {
  flex: 1; display: flex; align-items: baseline; gap: var(--space-3); min-width: 0; text-align: left;
  padding: var(--space-1) var(--space-2); border: none; border-radius: 0; background: transparent;
}
.mark-row__jump:hover { background: var(--panel-2); transform: none; box-shadow: none; }
.mark-row__time { font-variant-numeric: tabular-nums; font-weight: 600; min-width: 4.5ch; }
.mark-row__state { font-size: var(--font-sm); padding-right: var(--space-2); }
.mark-row__delete { padding: 0 var(--space-2); border: none; background: transparent; color: var(--muted); }
.mark-row__delete:hover { color: var(--bad); transform: none; box-shadow: none; }

/* The timeline: a lane per kind of mark (EventMark::LANES, named on the left), the kick-offs as
   dividers across them with the period's name above, and the times under. The bar is the whole video,
   sized by mark_timeline_controller.js to show about 30 minutes across and scrolling sideways within
   the card; marks, dividers and times sit at their second as a share of it. */
.mark-timeline-card {
  --lane-h: 18px; --lanes: 5; --lane-top: 20px; --times-h: 20px;
  display: grid; grid-template-columns: auto minmax(0, 1fr); gap: var(--space-2);
  padding: var(--space-3) var(--space-4);
}
.mark-timeline__lane-names { list-style: none; margin: 0; padding: var(--lane-top) 0 0; }
.mark-timeline__lane-name {
  height: var(--lane-h); line-height: var(--lane-h); text-align: right;
  font-size: var(--font-xs); font-weight: 600; color: var(--mark-color);
}
/* Room under the times for a scrollbar drawn over the content (a phone's, a Mac's). */
.mark-timeline-scroller { overflow-x: auto; overflow-y: hidden; padding-bottom: var(--space-2); }
.mark-timeline {
  position: relative; min-width: 100%; cursor: pointer;
  height: calc(var(--lane-top) + var(--lanes) * var(--lane-h) + var(--times-h));
}
.mark-timeline__lanes {
  position: absolute; left: 0; right: 0; top: var(--lane-top); height: calc(var(--lanes) * var(--lane-h));
  border-radius: var(--radius-sm);
  background: repeating-linear-gradient(to bottom, var(--panel-2) 0 var(--lane-h),
    color-mix(in srgb, var(--panel-2) 50%, var(--panel)) var(--lane-h) calc(2 * var(--lane-h)));
}
.mark-timeline__marks { position: absolute; inset: 0; }
.mark-timeline__mark {
  position: absolute; width: 5px; margin-left: -2.5px; padding: 0;
  top: calc(var(--lane-top) + var(--lane) * var(--lane-h) + 2px); height: calc(var(--lane-h) - 4px);
  border: none; border-radius: 2px; background: var(--mark-color);
}
.mark-timeline__mark--goal { --lane: 0; }
.mark-timeline__mark--shot { --lane: 1; }
.mark-timeline__mark--feed { --lane: 2; }
.mark-timeline__mark--turnover { --lane: 3; }
.mark-timeline__mark--other { --lane: 4; }
.mark-timeline__mark::before { content: ""; position: absolute; inset: -3px -5px; } /* a bigger target */
.mark-timeline__mark:hover { transform: scaleY(1.3); box-shadow: none; }
/* The enrich screen's states: done marks fade, a mark with nothing in it is hollow, the current one
   fills its lane, ringed. */
.entry--enrich .mark-timeline__mark[data-state="done"] { opacity: 0.35; }
.entry--enrich .mark-timeline__mark[data-state="nothing"] { background: transparent; box-shadow: inset 0 0 0 1px var(--mark-color); opacity: 0.6; }
.entry--enrich .mark-timeline__mark[data-state="current"] {
  top: calc(var(--lane-top) + var(--lane) * var(--lane-h)); height: var(--lane-h);
  width: 6px; margin-left: -3px; box-shadow: 0 0 0 2px var(--accent);
}
.mark-timeline__period {
  position: absolute; width: 2px; margin-left: -1px; padding: 0;
  top: calc(var(--lane-top) - 4px); height: calc(var(--lanes) * var(--lane-h) + 8px);
  border: none; border-radius: 0; background: var(--ink);
}
.mark-timeline__period:hover { transform: none; box-shadow: none; }
.entry--enrich .mark-timeline__period[data-state="current"] { background: var(--accent); }
.mark-timeline__period-name { position: absolute; bottom: 100%; left: 4px; font-size: var(--font-xs); color: var(--muted); white-space: nowrap; }
.mark-timeline__playhead {
  position: absolute; width: 2px; margin-left: -1px; background: var(--accent); pointer-events: none;
  top: calc(var(--lane-top) - 6px); height: calc(var(--lanes) * var(--lane-h) + 12px);
}
.mark-timeline__playhead[hidden] { display: none; }
.mark-timeline__times { position: absolute; left: 0; right: 0; bottom: 0; height: var(--times-h); pointer-events: none; }
.mark-timeline__time {
  position: absolute; bottom: 0; transform: translateX(-50%); white-space: nowrap;
  font-size: var(--font-xs); color: var(--muted); font-variant-numeric: tabular-nums;
}
.mark-timeline__time:first-child { transform: none; }

/* The enrich screen's panel under the video. */
.marks-panel__head { display: flex; justify-content: space-between; align-items: center; gap: var(--space-2); }
.marks-panel__progress { font-size: var(--font-md); margin: 0; }
.marks-panel__current { margin-top: var(--space-3); padding: var(--space-3) var(--space-4); border-left: 4px solid var(--accent); background: var(--panel-2); border-radius: var(--radius-sm); }
.marks-panel__current .actions { margin: var(--space-2) 0 0; }
.marks-panel__current .actions form, .marks-panel__last form { margin: 0; }
.marks-panel__label { margin: 0; font-size: var(--font-md); }
/* The kind of mark being entered, in its colour from the Mark screen's keys and the timeline. */
.marks-panel__kind { color: var(--mark-color, var(--ink)); }
.marks-panel__hint { margin: var(--space-1) 0 0; }
.marks-panel__attackers { border: none; margin: var(--space-2) 0; padding: 0; display: flex; flex-wrap: wrap; gap: var(--space-4); }
.marks-panel__attackers legend { padding: 0; margin-bottom: var(--space-1); color: var(--muted); font-size: var(--font-sm); }
form label.marks-panel__choice { display: inline-flex; align-items: center; gap: var(--space-2); color: var(--ink); font-size: var(--font-base); margin: 0; }
.marks-panel__kickoff + form { margin-top: var(--space-2); } /* a kick-off's Delete, under its form */
.marks-panel__last { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: var(--space-2); margin-top: var(--space-3); }
.marks-panel__last p { margin: 0; }
.marks-panel__last .actions { margin: 0; }
.marks-panel__adding { margin: var(--space-2) 0 0; color: var(--accent); }
.marks-panel__adding[hidden] { display: none; }
.marks-panel__add { margin-top: var(--space-3); }
.marks-panel__add summary { cursor: pointer; color: var(--muted); }
.marks-panel__add .actions { margin: var(--space-2) 0 0; }
.marks-panel__note { margin: var(--space-3) 0 0; font-size: var(--font-sm); }
/* No mark to enter against (none left, or a kick-off to start first): the court is held. */
[data-enrich-state="none"] .card--court .court,
[data-enrich-state="kickoff"] .card--court .court { pointer-events: none; opacity: 0.45; }

/* --- Entry flow popup, court and quick entry (centered popover state machine) --- */
.entry-flow {
  border: none;
  padding: 0;
  background: transparent;
  color: var(--ink);
  width: 100%;
  max-width: min(92vw, 30rem);
}
.entry-flow::backdrop { background: rgba(8, 15, 26, 0.66); }
.entry-flow__panel {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  padding: var(--space-4) var(--space-5) var(--space-5);
}
.entry-flow__head { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); min-height: 1.25rem; }
.entry-flow__crumbs { font-size: var(--font-xs); min-height: 1em; }
.entry-flow__close {
  padding: 0.1rem 0.5rem; line-height: 1;
  background: transparent; border-color: transparent; color: var(--muted);
}
.entry-flow__close:hover { color: var(--ink); border-color: var(--line); transform: none; }
.entry-flow__prompt { font-size: var(--font-md); font-weight: 600; margin: var(--space-2) 0 var(--space-4); }
.entry-flow__options { display: flex; flex-wrap: wrap; gap: var(--space-2); }
/* Player grid: boys column on the left, girls column on the right. */
.entry-flow__players { flex-basis: 100%; display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-2); align-items: start; }
.entry-flow__col { display: flex; flex-direction: column; gap: var(--space-2); min-width: 0; }
/* Narrower chips than the flat list — two columns halve the width, so trim the gap/padding
   to keep "#12 Ian Jones" on one line. */
.entry-flow__player { cursor: pointer; font-size: var(--font-sm); gap: var(--space-1); padding-right: var(--space-2); }
/* Fine line splitting a player step's primary roster from a secondary one (assist: attack division
   above, the scorer's own defence division below). Spans the full flex row. */
.entry-flow__divider { flex-basis: 100%; height: 0; border-top: 1px solid var(--line); margin: var(--space-1) 0; }
/* Heading above the first choice in a group (the turnover causes' Forced / Unforced split). Spans
   the full flex row so the buttons below it wrap underneath as their own band. */
.entry-flow__group {
  flex-basis: 100%; margin-top: var(--space-2); font-size: var(--font-xs); font-weight: 600;
  text-transform: uppercase; letter-spacing: 0.06em; color: var(--muted);
}
.entry-flow__group:first-child { margin-top: 0; }
.entry-flow__action { flex: 1 1 8rem; padding: var(--space-3) var(--space-4); font-weight: 600; }
.entry-flow__outcome { font-size: var(--font-base); }
.entry-flow__mods {
  display: flex; align-items: center; flex-wrap: wrap; gap: var(--space-3);
  margin-top: var(--space-4); padding-top: var(--space-3); border-top: 1px solid var(--line);
}
/* `display: flex` would otherwise beat the [hidden] UA rule; keep it hidden for transitions. */
.entry-flow__mods[hidden] { display: none; }
.entry-flow__mods-label { font-size: var(--font-xs); color: var(--muted); text-transform: uppercase; letter-spacing: 0.03em; }
/* Shot type: an icon sits left of the label inside each segment. The four segments span the popup,
   each as wide as its label, which stays on one line where there's room; a phone wraps them. */
.entry-flow__mods .segmented { display: flex; width: 100%; }
.entry-flow__mods .segmented__option { display: flex; flex: 1 1 auto; }
/* A defended shot's step leaves Penalty out (entry_flow.js showPenaltyType). */
.entry-flow__mods .segmented__option[hidden] { display: none; }
.entry-flow__mods .segmented__option label {
  display: inline-flex; flex: 1; align-items: center; justify-content: center; gap: 0.3rem;
  padding-inline: 0.6rem; white-space: nowrap;
}
@media (max-width: 480px) { .entry-flow__mods .segmented__option label { white-space: normal; } }
.entry-flow__mods .segmented__option .icon { flex-shrink: 0; }
/* Selected shot-type: each option fills with its own colour, so the active choice is obvious AND
   the four types stay distinguishable at a glance (see the :root --shot-* colours). */
.entry-flow__mods .segmented__option--shot-open input:checked + label      { background: var(--shot-open);      color: var(--shot-open-ink); }
.entry-flow__mods .segmented__option--shot-running input:checked + label   { background: var(--shot-running);   color: var(--shot-running-ink); }
.entry-flow__mods .segmented__option--shot-penalty input:checked + label   { background: var(--shot-penalty);   color: var(--shot-penalty-ink); }
.entry-flow__mods .segmented__option--shot-free-pass input:checked + label { background: var(--shot-free-pass); color: var(--shot-free-pass-ink); }
/* A tick on its own line, in ink once ticked: No collect/rebound under the shot type, and Defended
   under a shot step's buttons. */
.entry-flow__flag {
  flex-basis: 100%; display: flex; align-items: center; gap: var(--space-2);
  margin: 0; font-size: var(--font-sm); color: var(--muted); cursor: pointer;
}
/* `display: flex` would otherwise beat the [hidden] UA rule; a penalty hides it. */
.entry-flow__flag[hidden] { display: none; }
.entry-flow__flag input { width: 1rem; height: 1rem; margin: 0; accent-color: var(--accent); cursor: pointer; }
.entry-flow__flag:has(input:checked) { color: var(--ink); font-weight: 600; }
.entry-flow__foot { margin-top: var(--space-4); }
.entry-flow__foot .btn[disabled] { opacity: 0.4; cursor: default; }
/* Clear of the video (entry_flow.js fitWhilePlayingOn): once the popup has handed the video back, it
   sits on the court (left, top and width inline), rather than across the video, with no shade over
   the page, so it's outlined in the accent as quick entry's is. Absolute, not fixed, so it scrolls
   with the page. */
.entry-flow[data-playing-on] { position: absolute; inset: auto; margin: 0; }
.entry-flow[data-playing-on]::backdrop { background: transparent; }
.entry-flow[data-playing-on] .entry-flow__panel { border-color: var(--accent); }

/* Quick-edit dialog: reuses the .entry-flow modal chrome with a compact stacked form. */
.entry-flow--edit { max-width: min(92vw, 24rem); }

/* Court entry guide (entry/_court_guide, court_guide_controller.js): a carousel of how-tos in the
   entry-flow modal chrome. Its court pictures are small courts built from the real markings. */
.court-guide__title { margin: var(--space-2) 0 var(--space-3); font-size: var(--font-md); }
/* Every slide sits in the same cell, so the carousel is as tall as its tallest slide and the popup
   doesn't jump as you step through. An inactive slide keeps its space but can't be seen or read. */
.court-guide__slides { display: grid; }
.court-guide__slide { grid-area: 1 / 1; }
.court-guide__slide[hidden] { display: block; visibility: hidden; }
.court-guide__slide p { margin: 0 0 var(--space-3); font-size: var(--font-sm); line-height: var(--line-normal); }
.court-guide__slide:not([hidden]) { animation: court-guide-in 0.18s ease; }
@keyframes court-guide-in { from { opacity: 0; transform: translateX(0.5rem); } }
@media (prefers-reduced-motion: reduce) { .court-guide__slide:not([hidden]) { animation: none; } }
.court-guide__art { margin-bottom: var(--space-3); }
.court-guide__court { max-width: 22rem; margin: 0 auto; cursor: default; border-radius: var(--radius); }
/* The line under a court picture: "⇧ Shift + click", "Click the dimmed half". */
.court-guide__caption { margin: var(--space-2) 0 0; text-align: center; color: var(--muted); font-size: var(--font-sm); }
.court-guide__caption strong { color: var(--ink); }
.court-guide__caption kbd {
  font-family: inherit; font-size: var(--font-sm); font-weight: 600; color: var(--ink);
  padding: 0.1rem 0.5rem; background: var(--bg); border: 1px solid var(--line); border-bottom-width: 3px; border-radius: var(--radius-sm);
}
/* Slide 3: a few of the causes the dimmed-half popup offers, as small chips. */
.court-guide__choices { display: flex; flex-wrap: wrap; justify-content: center; gap: var(--space-1); margin-top: var(--space-2); }
.court-guide__choice {
  padding: 0.1rem 0.55rem; border: 1px solid var(--line); border-radius: var(--radius-pill);
  background: var(--panel-2); color: var(--ink); font-size: var(--font-xs); font-weight: 600;
}
.court-guide__note { font-size: var(--font-xs); }
/* Slide 2: what to log now and what to leave until the play is over, as three steps in order. */
.court-guide__steps {
  list-style: none; margin: 0 0 var(--space-3); padding: 0;
  display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--space-2);
}
.court-guide__step {
  position: relative; display: flex; flex-direction: column; gap: 0.15rem;
  padding: var(--space-2) var(--space-3); border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--panel-2); font-size: var(--font-xs); color: var(--muted);
}
.court-guide__step strong { color: var(--ink); font-size: var(--font-sm); }
.court-guide__step--now { border-color: var(--accent); }
.court-guide__step--now strong { color: var(--accent); }
.court-guide__step + .court-guide__step::before {
  content: "→"; position: absolute; left: calc(-1 * var(--space-2)); top: 50%;
  transform: translate(-50%, -50%) scale(0.85); color: var(--muted);
}
.court-guide__dots { display: flex; justify-content: center; gap: var(--space-2); margin-top: var(--space-2); }
.court-guide__dot {
  width: 0.55rem; height: 0.55rem; padding: 0; border: none; border-radius: 50%; background: var(--line);
}
.court-guide__dot:hover { background: var(--muted); transform: none; box-shadow: none; }
.court-guide__dot[aria-current="true"] { background: var(--accent); }
.court-guide__foot { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: var(--space-3); }
.court-guide__dismiss { display: flex; align-items: center; gap: var(--space-2); color: var(--muted); font-size: var(--font-sm); cursor: pointer; }
.court-guide__nav { display: flex; gap: var(--space-2); }
/* The fixture page's "Is someone entering each team?" popup (fixtures/_copy_per_team_hint): the two ways
   to enter a match between two of the club's teams, side by side (stacked on a phone), the one that
   needs setting up edged in the accent. */
.entry-flow.copy-hint__dialog { max-width: min(94vw, 44rem); }
.copy-hint__dialog .entry-flow__panel { max-height: min(90vh, 46rem); overflow-y: auto; }
.copy-hint__title { margin: var(--space-2) 0 var(--space-2); font-size: var(--font-md); }
.copy-hint__lede { margin: 0 0 var(--space-3); font-size: var(--font-sm); line-height: var(--line-normal); }
.copy-hint__ways { display: grid; grid-template-columns: minmax(0, 2fr) minmax(0, 3fr); align-items: start; gap: var(--space-3); }
.copy-hint__way {
  padding: var(--space-3); border: 1px solid var(--line); border-radius: var(--radius); background: var(--panel-2);
  font-size: var(--font-sm); line-height: var(--line-normal);
}
.copy-hint__way--split { border-color: var(--accent); }
.copy-hint__way h3 { margin: 0 0 var(--space-2); font-size: var(--font-sm); }
.copy-hint__way p { margin: 0; color: var(--muted); }
.copy-hint__way ol { margin: 0; padding-left: 1.2rem; display: grid; gap: var(--space-2); color: var(--muted); }
.copy-hint__way strong { color: var(--ink); }
.copy-hint__foot { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: var(--space-3); }
.copy-hint__actions { display: flex; flex-wrap: wrap; gap: var(--space-2); }
@media (max-width: 640px) { .copy-hint__ways { grid-template-columns: 1fr; } }
/* Mark then enrich's guides (entry/_mark_guide, entry/_enrich_guide) in the same frame: the kind keys
   as on the Mark screen, a small timeline, and what to do with each kind of mark. */
.court-guide__keys { display: flex; flex-wrap: wrap; justify-content: center; gap: var(--space-2); }
.court-guide__keys .mark-key {
  background: var(--panel-2); border: 1px solid var(--line); border-left: 4px solid var(--mark-color);
  border-radius: var(--radius); cursor: default;
}
.court-guide__timeline { --lane-h: 15px; padding: 0; }
.court-guide__timeline .mark-timeline { cursor: default; }
.court-guide__timeline .mark-timeline__mark:hover { transform: none; }
.court-guide__kinds {
  list-style: none; margin: 0 0 var(--space-3); padding: 0; display: grid; gap: var(--space-2);
  font-size: var(--font-sm);
}
.court-guide__kinds kbd {
  font-family: inherit; font-size: var(--font-xs); font-weight: 600; color: var(--ink);
  padding: 0 0.4rem; background: var(--bg); border: 1px solid var(--line); border-bottom-width: 2px; border-radius: var(--radius-sm);
}
/* "Court entry guide" in the court hint: a text link that opens the guide. */
.court-guide__reopen {
  padding: 0; line-height: inherit; background: transparent; border: none;
  color: var(--accent); font-size: inherit; font-weight: 600; cursor: pointer;
}
.court-guide__reopen:hover { text-decoration: underline; border-color: transparent; transform: none; box-shadow: none; }
.event-edit-form { margin-top: var(--space-3); }
.event-edit-form .field { margin-bottom: var(--space-3); }
.event-edit-form select { max-width: none; }
.event-edit-form__flags { border: none; padding: 0; margin-bottom: var(--space-3); }
.event-edit-form__flags legend { padding: 0; color: var(--muted); font-size: var(--font-sm); margin-bottom: var(--space-1); }
.event-edit-form__flags .checkbox { margin-bottom: var(--space-1); }
/* A defended shot's flag, which the edit doesn't change, said in the checkboxes' place. */
.event-edit-form__defended { margin: var(--space-1) 0 0; font-size: var(--font-sm); }
.event-edit-form__foot { display: flex; gap: var(--space-2); align-items: center; }
/* A shot-clock turnover names nobody (Event.division_turnover?): the Player field gives way to a line
   saying so while Shot clock is the reason picked. */
.event-edit-form__division { display: none; }
.event-edit-form:has(#event_turnover_reason option[value="shot_clock"]:checked) .event-edit-form__player { display: none; }
.event-edit-form:has(#event_turnover_reason option[value="shot_clock"]:checked) .event-edit-form__division { display: block; }

/* --- Reports --- */
.bar-row { display: flex; align-items: center; gap: 0.75rem; margin: 0.4rem 0; }
.bar-rows__caption { margin: var(--space-3) 0 0; font-size: var(--font-sm); }
.bar-row__label { width: 5.75rem; flex-shrink: 0; color: var(--muted); white-space: nowrap; }
.bar-row__value { width: 9rem; color: var(--muted); font-size: 0.9rem; }
.bar { flex: 1; height: 14px; background: var(--bg); border: 1px solid var(--line); border-radius: 999px; overflow: hidden; }
.bar__fill { height: 100%; background: var(--accent); }
/* A report card's heading with its controls (the Totals | Per game toggle) beside it. */
.report-card__head { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: var(--space-3); margin-bottom: var(--space-3); }
.report-card__head h2 { margin: 0; }
.report-card__head .view-toggle { margin: 0; }
.table-note { font-size: var(--font-sm); margin: var(--space-3) 0 0; }

/* Players table: a cell's shade against the squad, and a percentage on too few attempts to rank. */
td.shade, .shade-key .shade { color: var(--ink); }
.shade--hi { background: var(--shade-hi); }
.shade--lo { background: var(--shade-lo); }
td.unqualified { color: var(--muted); }
.shade-key { display: inline-flex; flex-wrap: wrap; gap: var(--space-1); vertical-align: middle; }
.shade-key .shade { padding: 0 var(--space-2); border-radius: var(--radius-sm); font-size: var(--font-xs); }

/* Stat tiles (the Attack card) and the season leaders: a label, a figure, what it's made of. */
.stat-tiles, .leaders { display: grid; grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr)); gap: var(--space-3); }
.leaders { margin-bottom: var(--space-4); }
/* Six tiles read as two rows of three rather than five and a straggler. */
@media (min-width: 40rem) { .stat-tiles--three { grid-template-columns: repeat(3, 1fr); } }
.stat-tile, .leader-tile { display: flex; flex-direction: column; gap: 2px; padding: var(--space-3); background: var(--panel-2); border: 1px solid var(--line); border-radius: var(--radius); }
.stat-tile__label, .leader-tile__label { margin: 0; font-size: var(--font-sm); font-weight: 400; color: var(--muted); }
.stat-tile__value, .leader-tile__value { margin: 0; font-size: var(--font-xl); font-weight: 600; line-height: var(--line-tight); }
.stat-tile--hero .stat-tile__value { font-size: var(--font-2xl); }
.stat-tile__note { font-size: var(--font-xs); color: var(--muted); }
.leader-tile__detail { font-size: var(--font-sm); font-weight: 400; color: var(--muted); }
.leader-tile__who { margin: 0; font-weight: 600; }
.leader-tile__rest { margin: var(--space-2) 0 0; padding-left: 1.2em; font-size: var(--font-sm); }

/* Game log: the season's form as sparklines (ReportsHelper#sparkline) and each match's result. */
.form-lines { display: flex; flex-wrap: wrap; gap: var(--space-5); margin: 0 0 var(--space-4); }
.form-line { margin: 0; }
.form-line figcaption { font-size: var(--font-sm); color: var(--muted); margin-bottom: var(--space-1); }
.sparkline { display: block; overflow: visible; max-width: 100%; height: auto; }
.sparkline__line { fill: none; stroke: var(--muted); stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; }
.sparkline__avg { stroke: var(--muted); stroke-opacity: 0.45; stroke-width: 1; stroke-dasharray: 3 3; }
.sparkline__dot { fill: var(--muted); stroke: var(--panel); stroke-width: 2; }
.sparkline__dot--last { fill: var(--accent); }
.sparkline__dot:hover { fill: var(--ink); }

/* Player report profile: a radar of ranks in the squad (ReportsHelper#radar_chart) beside its key. */
.profile { display: grid; grid-template-columns: minmax(0, 28rem) minmax(0, 1fr); gap: var(--space-5); align-items: start; }
@media (max-width: 800px) { .profile { grid-template-columns: minmax(0, 1fr); } }
.profile__chart { margin: 0; }
.radar { display: block; width: 100%; max-width: 440px; height: auto; overflow: visible; }
.radar__band--hi { fill: color-mix(in srgb, var(--shade-hi) 35%, transparent); fill-rule: evenodd; }
.radar__band--lo { fill: color-mix(in srgb, var(--shade-lo) 35%, transparent); }
.radar__ring, .radar__spoke { fill: none; stroke: var(--line); stroke-width: 1; }
.radar__ring--median { stroke: var(--muted); stroke-opacity: 0.45; stroke-dasharray: 3 3; }
.radar__label { fill: var(--muted); font-size: 13px; }
.radar__label--unranked { opacity: 0.5; }
.radar__shape { stroke-width: 2; stroke-linejoin: round; }
.radar__shape--player { fill: var(--radar-player); fill-opacity: 0.18; stroke: var(--radar-player); }
.radar__shape--compare { fill: var(--radar-compare); fill-opacity: 0.12; stroke: var(--radar-compare); stroke-dasharray: 6 4; }
/* The player's gender average: a reference, so a light outline in ink rather than a series colour. */
.radar__shape--average { fill: none; stroke: var(--radar-average); stroke-width: 1.5; }
.radar__hit { fill: transparent; }
.radar__dot { stroke: var(--panel); stroke-width: 2; }
.radar__vertex--player .radar__dot { fill: var(--radar-player); }
.radar__vertex--compare .radar__dot { fill: var(--radar-compare); }
.radar__vertex--average .radar__dot { fill: var(--radar-average); }
.radar__vertex:hover .radar__dot { fill: var(--ink); }
.radar-legend { display: flex; flex-wrap: wrap; gap: var(--space-4); list-style: none; margin: var(--space-2) 0 0; padding: 0; font-size: var(--font-sm); color: var(--muted); }
.radar-legend__key { display: inline-block; width: 1.5rem; border-top: 2px solid; vertical-align: middle; margin-right: var(--space-2); }
.radar-legend__key--player { border-top-color: var(--radar-player); }
.radar-legend__key--compare { border-top: 2px dashed var(--radar-compare); }
.radar-legend__key--average { border-top-color: var(--radar-average); }
.profile-key th, .profile-key td { padding: var(--space-2) var(--space-3); font-size: var(--font-sm); }
.profile-key td { white-space: nowrap; }
.profile-key tr:last-child th { border-bottom: none; }
.profile-key tbody th { color: var(--ink); font-weight: 400; text-transform: none; letter-spacing: normal; }
.profile-compare { display: flex; align-items: center; flex-wrap: wrap; gap: var(--space-2); }
.profile-compare label { display: inline; margin: 0; }
.profile-compare select { width: auto; max-width: 16rem; }

/* Strengths and focus areas (reports/_strengths): the stats the player stands out on, each with a
   level pill. Two intensities per side out of one token: the fifth outlined, the end of it filled.
   Fill against outline reads without colour, and a border survives a print that drops backgrounds. */
.traits { display: grid; grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr)); gap: var(--space-5); }
.traits__head { display: flex; align-items: center; gap: var(--space-2); margin: 0 0 var(--space-2); padding-bottom: var(--space-2); border-bottom: 1px solid var(--line); }
.traits__mark { padding: 0 var(--space-2); border-radius: var(--radius-sm); font-size: var(--font-sm); color: var(--ink); }
.traits__mark--hi { background: var(--shade-hi); }
.traits__mark--lo { background: var(--shade-lo); }
.traits__list { list-style: none; margin: 0; padding: 0; }
.trait { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); padding: var(--space-2) 0; border-bottom: 1px solid var(--panel-2); }
.trait:last-child { border-bottom: none; }
.trait__body { display: flex; flex-direction: column; min-width: 0; }
.trait__detail { font-size: var(--font-xs); color: var(--muted); }
.trait__level { flex: none; padding: var(--space-1) var(--space-2); border: 1px solid transparent; border-radius: var(--radius-sm); font-size: var(--font-xs); font-weight: 600; color: var(--ink); white-space: nowrap; }
.trait__level--hi { border-color: var(--shade-hi); }
.trait__level--hi-very { background: var(--shade-hi); border-color: var(--shade-hi); }
.trait__level--lo { border-color: var(--shade-lo); }
.trait__level--lo-very { background: var(--shade-lo); border-color: var(--shade-lo); }
.result { display: inline-block; min-width: 1.6em; text-align: center; padding: 0 var(--space-1); border-radius: var(--radius-sm); font-weight: 600; background: var(--panel-2); }
.result--w { background: rgba(61, 220, 151, 0.2); }
.result--l { background: rgba(255, 107, 107, 0.2); }
/* Season picker on the team/player reports (and the fixtures Day | Weekend toggle): pill links,
   the one shown marked aria-current. */
.season-picker, .view-toggle { display: flex; flex-wrap: wrap; gap: var(--space-2); margin: var(--space-3) 0; }
.season-picker a, .view-toggle a { padding: var(--space-1) var(--space-3); border: 1px solid var(--line); border-radius: var(--radius-pill); color: var(--muted); text-decoration: none; font-size: var(--font-sm); }
.season-picker a[aria-current], .view-toggle a[aria-current] { color: var(--ink); border-color: var(--accent); }
/* A toggle that needs saying what it switches ("Ranked against"): the nav's own name, in the
   muted voice of a field label rather than another pill. */
.view-toggle__label { align-self: center; color: var(--muted); font-size: var(--font-sm); }

/* --- Match report (reports/_match_report, MatchReportsHelper) ---
   Home v away throughout: two columns (.match-sides), each headed by its team in its colour. */
.match-head__kicker { margin: 0 0 var(--space-1); font-size: var(--font-xs); letter-spacing: 0.06em; text-transform: uppercase; color: var(--muted); }
.match-head__periods { margin: var(--space-2) 0 0; font-size: var(--font-sm); color: var(--muted); }
.match-head__periods strong { color: var(--ink); }
/* A copy per team's match report: the way to both copies together, and the combined report's
   warning when the copies' scores differ (MatchReport::Combined). */
.combined-report__link { margin: var(--space-2) 0 0; font-size: var(--font-sm); }
.combined-report__differ { margin: var(--space-2) 0 0; font-size: var(--font-sm); }
.combined-report__differ .badge { margin-right: var(--space-1); }
.team-swatch { display: inline-block; width: 0.7em; height: 0.7em; margin: 0 0.4em; border-radius: 2px; }
.team-swatch--home { background: var(--match-home); }
.team-swatch--away { background: var(--match-away); }
.match-sides { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-5); }
@media (max-width: 800px) { .match-sides { grid-template-columns: minmax(0, 1fr); } }
.match-side__head { margin: 0 0 var(--space-3); font-size: var(--font-md); }
:is(.match-side__head, .score-flow__key, .moments__table, .duel__title > span, .period-table__team) .team-swatch:first-child { margin-left: 0; }
.match-side__subhead { margin: var(--space-3) 0 var(--space-1); font-size: var(--font-sm); font-weight: 600; color: var(--muted); }
/* Six tiles in half a card: three rows of two rather than two squeezed rows of three. */
.match-side .stat-tiles--three { grid-template-columns: repeat(2, minmax(0, 1fr)); }
/* The Turnovers card's causes run longer than a Shooting card's types ("Defended shot"). */
.match-turnovers .bar-row__label { width: 7rem; }

/* How the score went: the chart (MatchReportsHelper#score_flow_chart) beside its key. */
.score-flow__body { display: grid; grid-template-columns: minmax(0, 1fr) minmax(12rem, 16rem); gap: var(--space-5); align-items: start; }
@media (max-width: 800px) { .score-flow__body { grid-template-columns: minmax(0, 1fr); } }
.score-flow__chart { display: block; width: 100%; height: auto; overflow: visible; }
.score-flow__lead--home { fill: color-mix(in srgb, var(--match-home) 35%, transparent); }
.score-flow__lead--away { fill: color-mix(in srgb, var(--match-away) 35%, transparent); }
.score-flow__zero { stroke: var(--muted); stroke-opacity: 0.6; stroke-width: 1; }
.score-flow__divider { stroke: var(--muted); stroke-opacity: 0.5; stroke-dasharray: 3 3; }
.score-flow__line { fill: none; stroke: var(--ink); stroke-width: 2; stroke-linejoin: round; }
.score-flow__goal { stroke: var(--panel); stroke-width: 1.5; }
.score-flow__goal--home { fill: var(--match-home); }
.score-flow__goal--away { fill: var(--match-away); }
.score-flow__goal:hover { fill: var(--ink); }
.score-flow__period, .score-flow__side, .score-flow__tick { fill: var(--muted); font-size: 11px; }
/* The chart scales down to a phone's width, so its labels grow in its own units to stay legible. */
@media (max-width: 600px) { .score-flow__period, .score-flow__side, .score-flow__tick { font-size: 20px; } }
.score-flow__key { list-style: none; margin: 0; padding: 0; font-size: var(--font-sm); }
.score-flow__key li { padding: var(--space-2) 0; border-bottom: 1px solid var(--line); }
.score-flow__key li:last-child { border-bottom: none; }
.period-table { margin-top: var(--space-4); }
.period-table :is(th, td) { text-align: center; }
.period-table tbody th { text-align: left; }

/* Shot map: the court's left half on the report's own surface rather than the court's floor, so
   the team colours read on any court (and in print), and a touch on it scrolls the page. */
.shot-map .court-svg, .shot-map .court-svg[data-court-view="left_half"] { width: 100%; max-width: 22rem; margin: 0; touch-action: auto; }
.shot-map .court-svg__floor { fill: var(--panel-2); }
.shot-map :is(.court-svg__boundary, .court-svg__penalty-area) { fill: none; stroke: var(--line); }
.shot-map :is(.court-svg__centreline, .court-svg__freepass) { stroke: var(--line); }
.shot-map .court-svg__penalty-spot { fill: var(--muted); }
.shot-map .court-svg__korf { fill: none; stroke: var(--muted); }
/* A goal and a miss differ in shape and weight, not only fill: a solid dot ringed in ink, and a
   light cross (MatchReportsHelper#shot_marks), so they read apart in print and without colour. */
.shot-mark--home { --mark: var(--match-home); }
.shot-mark--away { --mark: var(--match-away); }
.shot-mark--goal { fill: var(--mark); stroke: var(--ink); stroke-width: 0.07; }
.shot-mark--miss { fill: none; stroke: var(--mark); stroke-width: 0.13; stroke-linecap: round; opacity: 0.8; pointer-events: bounding-box; }
.shot-mark--defended { fill: none; stroke: var(--mark); stroke-width: 0.11; opacity: 0.9; pointer-events: bounding-box; }
.shot-map__legend { display: flex; flex-wrap: wrap; gap: var(--space-3); margin: var(--space-2) 0 0; font-size: var(--font-sm); }
.shot-map__legend-item { display: inline-flex; align-items: center; gap: var(--space-1); }
.shot-map__key { width: 1em; height: 1em; overflow: visible; }
.shot-map__note { margin: var(--space-2) 0 0; font-size: var(--font-sm); }

/* Division duels: each a score and a small table, with who played in the fours. */
/* The two fours wrap as wholes, never mid-name. */
.duel__title { display: flex; flex-wrap: wrap; align-items: baseline; column-gap: 0.4em; margin: 0; font-size: var(--font-md); font-weight: 600; }
.duel__score { margin: var(--space-2) 0; font-size: var(--font-2xl); font-weight: 600; line-height: var(--line-tight); }
.duel__table { font-size: var(--font-sm); }
.duel__players { margin: var(--space-2) 0 0; font-size: var(--font-sm); color: var(--muted); }
.duel__players strong { color: var(--ink); }

/* Key moments: two rows of pill radios filter the table in CSS alone (reports/_match_moments). */
.moments__filters { display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-5); margin-bottom: var(--space-3); }
.moments__filter { display: flex; flex-wrap: wrap; gap: var(--space-2); min-width: 0; margin: 0; padding: 0; border: 0; }
.moments__choice { position: relative; display: inline-flex; margin: 0; color: var(--ink); font-weight: 400; cursor: pointer; }
.moments__input { position: absolute; opacity: 0; width: 1px; height: 1px; margin: 0; }
.moments__pill { padding: var(--space-1) var(--space-3); border: 1px solid var(--line); border-radius: var(--radius-pill); font-size: var(--font-sm); }
.moments__choice:hover .moments__pill { border-color: var(--accent); }
.moments__input:checked + .moments__pill { border-color: var(--accent); background: var(--panel-2); box-shadow: inset 0 0 0 1px var(--accent); font-weight: 600; }
.moments__input:focus-visible + .moments__pill { box-shadow: var(--shadow-focus); }
.moments:has(#moments-show-scoring:checked) .moment--turnovers,
.moments:has(#moments-show-turnovers:checked) .moment:not(.moment--turnovers),
.moments:has(#moments-team-home:checked) .moment--away,
.moments:has(#moments-team-away:checked) .moment--home { display: none; }
.moment__label { font-weight: 600; white-space: nowrap; }

/* --- Fixtures index: weekend/day calendar and team season list --- */
.fixture-nav { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3); margin: var(--space-4) 0; }
.fixture-nav .view-toggle { margin: 0; }
.fixture-nav__jump { display: flex; align-items: center; gap: var(--space-2); }
.fixture-nav__jump input[type="date"] { width: auto; }
/* Prev arrow · title · next arrow; empty spans hold the grid slot at either end of the data. */
.fixture-nav__steps { display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: var(--space-3); margin: var(--space-5) 0 var(--space-4); }
.fixture-nav__steps h2 { margin: 0; text-align: center; }
.fixture-nav__steps > :last-child { justify-self: end; }
.fixture-nav__steps > :first-child { justify-self: start; }
.fixture-day { margin-bottom: var(--space-5); }
/* One table per day (or month), so fixed column widths keep the days' columns lined up; the
   fixture column takes the rest. Scrolls sideways on a narrow screen rather than squashing. The
   result column is as wide as its longest status badge ("In progress", "Abandoned") with room to
   spare for other fonts, and a badge after a score wraps under it rather than running into Open.
   The minimum width leaves the fixture column no narrower than it was with a 6rem result. */
.fixture-table-wrap { overflow-x: auto; border-radius: var(--radius); }
.fixture-table { table-layout: fixed; min-width: 48rem; }
.fixture-table th:nth-child(1) { width: 5rem; }
.fixture-table--dated th:nth-child(1) { width: 10rem; }
.fixture-table th:nth-child(3) { width: 22%; }
.fixture-table th:nth-child(4) { width: 18%; }
.fixture-table th:nth-child(5) { width: 8rem; }
.fixture-table th:nth-child(6) { width: 4.5rem; }
.fixture-table__result .badge { white-space: nowrap; }
.fixture-day h3 { margin: 0 0 var(--space-2); color: var(--muted); font-size: var(--font-sm); text-transform: uppercase; letter-spacing: 0.03em; }
@media (max-width: 600px) {
  .fixture-nav__steps { grid-template-columns: 1fr 1fr; }
  .fixture-nav__steps h2 { grid-column: 1 / -1; grid-row: 1; }
}

/* --- Player identity avatar ---
   Encodes gender by color (fill + inset ring) AND a redundant corner glyph + accessible
   title/aria-label, so the signal never relies on color alone. The Unknown Player catch-all
   gets a dashed ring + forced "?" instead of the solid gender ring, so it stays visually
   distinct from a real named player who merely has gender=neutral. */
.avatar {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  vertical-align: middle;
  border-radius: 50%;
  font-weight: 700;
  line-height: 1;
  background: var(--panel-2);
}
.avatar__inner { display: flex; align-items: center; justify-content: center; width: 100%; height: 100%; border-radius: 50%; }

.avatar--sm { width: 1.75rem; height: 1.75rem; font-size: var(--font-xs); }
.avatar--md { width: 2.5rem; height: 2.5rem; font-size: var(--font-sm); }
.avatar--lg { width: 4rem; height: 4rem; font-size: var(--font-md); }

.avatar--male .avatar__inner    { background: var(--gender-male);    color: var(--gender-male-ink); }
.avatar--female .avatar__inner  { background: var(--gender-female);  color: var(--gender-female-ink); }
.avatar--neutral .avatar__inner { background: var(--gender-neutral); color: var(--gender-neutral-ink); }
.avatar--male    { box-shadow: 0 0 0 2px var(--gender-male) inset; }
.avatar--female  { box-shadow: 0 0 0 2px var(--gender-female) inset; }
.avatar--neutral { box-shadow: 0 0 0 2px var(--gender-neutral) inset; }

.avatar__sex {
  position: absolute;
  bottom: -2px; right: -2px;
  width: 1.1em; height: 1.1em;
  min-width: 14px; min-height: 14px;
  display: flex; align-items: center; justify-content: center;
  font-size: 0.55em;
  font-weight: 800;
  border-radius: 50%;
  background: var(--bg);
  border: 1.5px solid var(--panel);
  color: var(--ink);
}
.avatar--sm .avatar__sex { font-size: 0.5em; }

.avatar--unknown { box-shadow: none; border: 2px dashed var(--muted); }
.avatar--unknown .avatar__inner { background: var(--panel-2); color: var(--muted); }
.avatar--unknown .avatar__glyph { font-size: 1.1em; }

/* --- Segmented control (CSS-only radio group, used for the gender field) --- */
.segmented { display: inline-flex; border-radius: var(--radius-pill); overflow: hidden; border: 1px solid var(--line); }
.segmented__option { position: relative; }
.segmented__option input { position: absolute; opacity: 0; width: 0; height: 0; }
.segmented__option label {
  display: inline-block; margin: 0; padding: 0.45rem 1rem;
  font-size: var(--font-sm); color: var(--muted); cursor: pointer;
  background: var(--panel); border-right: 1px solid var(--line);
  transition: background var(--transition-fast), color var(--transition-fast);
}
.segmented__option:last-child label { border-right: none; }
.segmented__option input:checked + label { color: var(--ink); font-weight: 600; }
.segmented__option--male input:checked + label    { background: var(--gender-male);    color: var(--gender-male-ink); }
.segmented__option--female input:checked + label  { background: var(--gender-female);  color: var(--gender-female-ink); }
.segmented__option--neutral input:checked + label { background: var(--gender-neutral); color: var(--gender-neutral-ink); }
.segmented__option input:focus-visible + label { box-shadow: var(--shadow-focus); position: relative; z-index: 1; }

/* --- Pagination (Kaminari default markup: nav.pagination > span.first/.prev/.page/.next/.last) --- */
.pagination {
  display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap;
  margin: var(--space-4) 0;
}
.pagination span { display: inline-flex; }
.pagination a, .pagination span.current, .pagination span.gap {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 2rem; height: 2rem; padding: 0 var(--space-2);
  border-radius: var(--radius-pill); border: 1px solid var(--line);
  background: var(--panel-2); color: var(--ink); font-size: var(--font-sm);
  transition: background var(--transition-fast), border-color var(--transition-fast), transform var(--transition-fast);
}
.pagination a:hover { text-decoration: none; border-color: var(--accent); transform: translateY(-1px); }
.pagination span.current { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); font-weight: 600; }
.pagination span.gap { border-style: dashed; color: var(--muted); background: transparent; }

/* --- Player roster (club/team show pages) ---
   Gender groups lay out as side-by-side columns when there's room, collapsing to a single
   stacked column on narrow viewports — auto-fit/minmax handles this without breakpoints,
   which matters here since the number of groups varies (2 or 3, depending on whether any
   neutral-gender players are present). */
.roster { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: var(--space-5); align-items: start; }
.roster__group h3 { margin: 0 0 var(--space-2); color: var(--muted); font-size: var(--font-sm); text-transform: uppercase; letter-spacing: 0.03em; }
.roster__list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-2); }

/* Player chip: a stylised button-like link, colored by gender so it's recognisable even before
   reading the name. Tinted (not full-saturation) background keeps a list of many chips legible;
   the avatar inside still carries the full-strength gender color. */
.player-chip {
  display: flex; align-items: center; gap: var(--space-2);
  padding: var(--space-1) var(--space-3) var(--space-1) var(--space-1);
  border-radius: var(--radius-pill);
  border: 1.5px solid var(--line);
  background: var(--panel-2);
  color: var(--ink);
  font-weight: 600;
  transition: transform var(--transition-fast), box-shadow var(--transition-fast), border-color var(--transition-fast);
}
.player-chip:hover { text-decoration: none; transform: translateY(-1px); box-shadow: var(--shadow-sm); }
.player-chip__name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.player-chip--male    { border-color: var(--gender-male);    background: var(--gender-male-bg); }
.player-chip--female  { border-color: var(--gender-female);  background: var(--gender-female-bg); }
.player-chip--neutral { border-color: var(--gender-neutral); background: var(--gender-neutral-bg); }
.player-chip--unknown { border-style: dashed; }

/* --- Court entry v2 (entry/court_v2): our team's events only, on the half the ball is in beside a
   bigger video, all on one screen, edge to edge. The bar runs across the top; the stage (court and
   video) and our buttons under it fill the width left of the side column (our team on court, then
   the recent events). The stage's columns (--v2-columns, set inline) are the court window's and the
   video's aspect ratios, so court and video come out the same height. On a screen too short for its
   width the stage is capped at the height the screen leaves it, and centred. The match controls
   sit under our buttons, keeping the side column narrow. The court is court
   entry's whole court, cropped by .court-v2__window. data-ball-end and data-possession follow
   possession (court_focus_controller.js). The rules on .one-team (the bar's score, clock, keys and
   flash; our Substitute only) hold for both one-team pages, court entry v2 and quick entry, and
   those on .court-focus (the cropped court) for court entry v2. Placed after .card,
   .scoreboard, .match-clock, .court, .video-embed and .player-chip, which it adjusts. --- */
main:has(.entry--v2) { max-width: none; padding: var(--space-3) var(--space-5) var(--space-4); }
.court-v2 {
  --v2-gap: var(--space-3);
  --v2-bar: 3.25rem;
  --v2-side: 18rem;
  --v2-ours: 9rem; /* the least our buttons need under the stage */
  /* The screen below the site header (3.5625rem, sticky) and main's padding. */
  --v2-screen: calc(100dvh - 3.5625rem - var(--space-3) - var(--space-4));
  display: grid; gap: var(--v2-gap);
  grid-template-columns: minmax(0, 1fr) var(--v2-side);
  grid-template-rows: auto auto minmax(var(--v2-ours), 1fr);
  grid-template-areas: "bar bar" "stage side" "ours side";
  min-height: var(--v2-screen);
}
.court-v2 > form { display: contents; } /* the popup's form holds nothing that takes space */
.one-team #entry-flash { flex-basis: 100%; }
.one-team #entry-flash:empty { display: none; }
.one-team #entry-flash .flash { margin: 0; }
.one-team kbd {
  margin-left: 0.3rem; padding: 0 0.3rem; border: 1px solid var(--line); border-radius: 4px;
  font: 600 0.7rem/1.4 ui-monospace, SFMono-Regular, Menlo, monospace; color: var(--muted);
}

.court-v2__bar {
  grid-area: bar; display: flex; align-items: center; flex-wrap: wrap; gap: var(--space-2) var(--space-4);
  min-height: var(--v2-bar); padding: var(--space-1) var(--space-4);
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius); box-shadow: var(--shadow-sm);
}
.court-v2__title { margin: 0; font-size: var(--font-base); white-space: nowrap; }
.one-team .scoreboard { margin: 0; padding: 0; gap: var(--space-3); flex-wrap: nowrap; background: none; border: 0; box-shadow: none; }
.one-team .scoreboard__score { font-size: var(--font-base); gap: var(--space-2); white-space: nowrap; }
.one-team .scoreboard__score strong { font-size: 1.4rem; }
.one-team .scoreboard p { display: none; }
.court-v2__their-goal { white-space: nowrap; border-color: rgba(88, 166, 255, 0.55); background: rgba(88, 166, 255, 0.1); }
.one-team .match-clock { margin: 0; padding: 0; background: none; border: 0; box-shadow: none; flex-wrap: nowrap; }
.court-v2__links { display: flex; gap: var(--space-2); margin-left: auto; }

.court-v2__stage {
  grid-area: stage; display: grid; grid-template-columns: var(--v2-columns); gap: var(--v2-gap); align-items: start;
  width: 100%; justify-self: center;
  max-width: calc((var(--v2-screen) - var(--v2-bar) - var(--v2-ours) - 2 * var(--v2-gap)) * var(--stage-ratio) + var(--v2-gap));
}
.court-v2__window {
  position: relative; aspect-ratio: var(--court-aspect); overflow: hidden;
  border: 1px solid var(--line); border-radius: var(--radius); box-shadow: var(--shadow-sm);
}
/* The whole court, as wide as the window's share of it says, pinned to the ball's end. */
.court-v2__window .court {
  position: absolute; top: 0; left: 0; width: calc(100% / var(--court-window)); height: 100%;
  aspect-ratio: auto; border-radius: 0;
}
.court-focus[data-ball-end="right"] .court-v2__window .court { left: auto; right: 0; }
.court-focus .court__shade { background: rgba(0, 0, 0, 0.42); }
.court-v2__strip {
  position: absolute; z-index: 3; top: 0; bottom: 0; right: 0; width: var(--court-strip);
  display: flex; align-items: center; justify-content: center; pointer-events: none;
}
.court-focus[data-ball-end="right"] .court-v2__strip { right: auto; left: 0; }
.court-v2__strip span {
  writing-mode: vertical-rl; transform: rotate(180deg); white-space: nowrap;
  font-size: var(--font-xs); font-weight: 600; letter-spacing: 0.1em; text-transform: uppercase; color: rgba(255, 255, 255, 0.8);
}
.court-v2__label, .court-v2__hint {
  position: absolute; z-index: 4; left: var(--space-3); pointer-events: none; white-space: nowrap;
  padding: 0.15rem 0.6rem; background: rgba(10, 20, 34, 0.72); font-size: var(--font-xs);
}
.court-focus[data-ball-end="right"] :is(.court-v2__label, .court-v2__hint) { left: calc(var(--court-strip) + var(--space-3)); }
.court-v2__label { top: var(--space-3); border-radius: var(--radius-pill); color: var(--accent); font-weight: 600; }
.court-v2__hint { bottom: var(--space-3); border-radius: var(--radius-sm); color: var(--ink); }
.court-v2__map {
  position: absolute; z-index: 4; right: var(--space-3); top: var(--space-3); width: 64px; height: 32px;
  border: 1px solid rgba(255, 255, 255, 0.55); border-radius: 3px; background: rgba(0, 0, 0, 0.35); pointer-events: none;
}
.court-focus[data-ball-end="left"] .court-v2__map { right: calc(var(--court-strip) + var(--space-3)); }
.court-v2__map::before { content: ""; position: absolute; top: 0; bottom: 0; left: 50%; width: 1px; background: rgba(255, 255, 255, 0.5); }
.court-v2__map-window {
  position: absolute; top: 0; bottom: 0; left: 0; width: calc(var(--court-window) * 100%);
  border: 1px solid var(--accent); background: rgba(255, 159, 28, 0.28);
}
.court-focus[data-ball-end="right"] .court-v2__map-window { left: auto; right: 0; }
.court-v2__video .card--video { margin: 0; padding: 0; overflow: hidden; }
.court-v2__video .video-embed { margin-top: 0; }
.court-v2__video .video-embed iframe { border-radius: 0; }

.court-v2__ours { grid-area: ours; }
/* contain: size keeps a long list of recent events from stretching the page: the column takes the
   rows the stage and our buttons set, and the list scrolls in it. */
.court-v2__side { grid-area: side; display: flex; flex-direction: column; gap: var(--v2-gap); min-height: 0; contain: size; }
.court-v2__ours, .court-v2__side .card { margin: 0; min-height: 0; overflow: auto; padding: var(--space-3) var(--space-4); }
.court-v2__court-side { flex: none; }
.court-v2__recent { flex: 1 1 0; }
.court-v2__heading { display: flex; align-items: center; gap: var(--space-2); margin: 0 0 var(--space-2); font-size: var(--font-sm); font-weight: 600; }
.one-team .substitution__team { display: none; }
/* Attack, Defence and Discipline side by side, Defence (the most buttons) taking what's left. */
.court-v2__groups { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; gap: var(--space-2) var(--space-5); align-items: start; }
.court-v2__group { display: flex; flex-direction: column; gap: var(--space-1); min-width: 0; }
.court-v2__group-name {
  margin: 0; white-space: nowrap;
  font-size: var(--font-xs); font-weight: 600; letter-spacing: 0.05em; text-transform: uppercase; color: var(--muted);
}
.court-v2__now { display: inline-block; width: 1.1em; font-size: 0.8em; visibility: hidden; }
.court-v2[data-possession="ours"] .court-v2__group--attack .court-v2__group-name,
.court-v2[data-possession="theirs"] .court-v2__group--defence .court-v2__group-name { color: var(--accent); }
.court-v2[data-possession="ours"] .court-v2__group--attack .court-v2__now,
.court-v2[data-possession="theirs"] .court-v2__group--defence .court-v2__now { visibility: visible; }
.court-v2__buttons { display: flex; flex-wrap: wrap; gap: var(--space-1) var(--space-2); }
.court-v2__button, .court-v2__match .btn, .court-v2__match .view-toggle button { padding: 0.15rem 0.5rem; font-size: 0.8rem; white-space: nowrap; }
.court-v2__fours { display: grid; gap: var(--space-2); }
.court-v2__four { padding: var(--space-1) var(--space-2) var(--space-2); border: 1px solid var(--line); border-radius: var(--radius-sm); }
.court-v2__four > .muted { font-size: var(--font-xs); }
.court-v2__four--on-ball { border-color: var(--accent); }
.court-v2__four-head {
  display: flex; justify-content: space-between; margin: 0 0 var(--space-1);
  font-size: 0.7rem; font-weight: 600; letter-spacing: 0.05em; text-transform: uppercase; color: var(--muted);
}
.court-v2__four-tag { color: var(--accent); }
.court-v2__four-players { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-1); }
.court-v2__four-players .player-chip { padding: 0 var(--space-2); font-size: var(--font-xs); }
.court-v2__four-players .player-chip:hover { transform: none; box-shadow: none; }
.court-v2__match {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2);
  margin-top: var(--space-3); padding-top: var(--space-3); border-top: 1px solid var(--line);
}
.court-v2__match .court-v2__group-name { margin-right: var(--space-2); }
.court-v2__match form { margin: 0; }
/* The #substitutions stream renders both teams; the one-team pages substitute only their own. */
.one-team[data-our-side="home"] .substitution[data-side="away"],
.one-team[data-our-side="away"] .substitution[data-side="home"] { display: none; }
@media (max-width: 1000px) {
  .court-v2 {
    min-height: 0; grid-template-columns: minmax(0, 1fr); grid-template-rows: none;
    grid-template-areas: "bar" "stage" "ours" "side";
  }
  .court-v2__stage { grid-template-columns: minmax(0, 1fr); max-width: none; }
  .court-v2__groups { grid-template-columns: minmax(0, 1fr); }
  .court-v2__side { contain: none; }
  .court-v2__links { margin-left: 0; }
}

/* --- Quick entry's newest events (entry/_latest_events), three under the video. --- */
.latest-events { min-width: 0; }
.latest-events__list { margin: 0; padding: 0; list-style: none; }
.latest-events__row { display: flex; align-items: center; gap: var(--space-3); min-height: 2rem; font-size: var(--font-base); }
.latest-events__clock { min-width: 3rem; color: var(--muted); font-size: var(--font-sm); font-variant-numeric: tabular-nums; }
.latest-events__what { white-space: nowrap; }
.latest-events__what--goal { color: var(--ok); }
.latest-events__detail { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--muted); }
.latest-events__actions { display: flex; gap: var(--space-2); margin-left: auto; flex-shrink: 0; }
.latest-events__actions form { margin: 0; }
.latest-events__none { margin: 0; font-size: var(--font-sm); }

/* --- The entry popup anchored in a page (entry/_flow_fields placement: :anchored): no backdrop, no
   centring. Quick entry's, placed over a player card by quick_controller.js (left, top and width
   inline). --- */
.entry-flow--anchored { margin: 0; max-width: none; }
.entry-flow--anchored { position: fixed; inset: auto; z-index: 30; overflow: auto; }
.entry-flow--anchored .entry-flow__panel { padding: var(--space-3) var(--space-4) var(--space-4); border-color: var(--accent); }
.entry-flow--anchored .entry-flow__prompt { margin: var(--space-1) 0 var(--space-3); }
.entry-flow--anchored .entry-flow__mods { margin-top: var(--space-3); padding-top: var(--space-2); }
.entry-flow--anchored .entry-flow__foot { margin-top: var(--space-3); }

/* --- Quick entry (entry/quick): a card for each of our four in the ball's half, drawn by
   quick_controller.js, beside a big video with the newest events under it, all on one screen.
   The video is capped at the height the screen leaves it. data-possession picks the team buttons. --- */
.quick {
  --v2-gap: var(--space-3);
  --v2-bar: 3.25rem;
  --v2-screen: calc(100dvh - 3.5625rem - var(--space-3) - var(--space-4));
  --quick-side: 30rem;
  --quick-recent: 8rem;
  display: flex; flex-direction: column; gap: var(--v2-gap);
  min-height: var(--v2-screen);
}
.quick > form { display: contents; } /* the popup's form holds nothing that takes space */
.quick__main { flex: 1; min-height: 0; display: grid; grid-template-columns: minmax(0, 1fr) var(--quick-side); gap: var(--v2-gap); }
.quick__left { display: flex; flex-direction: column; gap: var(--v2-gap); min-height: 0; }
.quick__video {
  width: 100%; margin-inline: auto;
  max-width: calc((var(--v2-screen) - var(--v2-bar) - var(--quick-recent) - 2 * var(--v2-gap)) * 16 / 9);
}
.quick__video .card--video { margin: 0; padding: 0; overflow: hidden; }
.quick__video .video-embed { margin-top: 0; }
.quick__video .video-embed iframe { border-radius: 0; }
.quick__recent { flex: 1 1 var(--quick-recent); min-height: var(--quick-recent); margin: 0; padding: var(--space-2) var(--space-4); overflow: auto; }
.quick__recent-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: var(--space-1); font-size: var(--font-sm); }
.quick__recent-head h2 { margin: 0; font-size: var(--font-sm); font-weight: 600; color: var(--muted); }
.quick__recent-head a { color: var(--muted); }
.quick__right { display: flex; flex-direction: column; gap: var(--space-2); min-height: 0; }
.quick__mode { display: flex; align-items: baseline; gap: var(--space-3); min-height: 2rem; }
.quick__mode-title { font-size: var(--font-lg); font-weight: 700; color: var(--accent); }
.quick__mode-sub { color: var(--muted); }
.quick__mode form { margin: 0 0 0 auto; }
.quick__switch { padding: 0; border: 0; background: none; color: var(--muted); font-size: var(--font-sm); text-decoration: underline; }
.quick__switch:hover { color: var(--ink); transform: none; box-shadow: none; }
.quick__cards { display: flex; flex-direction: column; gap: var(--space-2); }
.quick-card {
  display: flex; flex-direction: column; gap: var(--space-1); padding: var(--space-1) var(--space-3) var(--space-2);
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius);
}
.quick-card__head { display: flex; align-items: center; gap: var(--space-2); margin: 0; font-size: 1.15rem; font-weight: 600; }
.quick-card__dot { width: 0.65rem; height: 0.65rem; border-radius: 50%; flex-shrink: 0; background: var(--gender-neutral); }
.quick-card__dot--male { background: var(--gender-male); }
.quick-card__dot--female { background: var(--gender-female); }
.quick-card__dot--unknown { background: none; border: 1px dashed var(--muted); }
.quick-card__actions { display: grid; grid-template-columns: repeat(var(--actions, 4), minmax(0, 1fr)); gap: var(--space-2); }
.quick-card__action { min-height: 2.75rem; padding: 0 var(--space-2); font-size: var(--font-base); white-space: nowrap; }
.quick-card__action--goal { border-color: color-mix(in srgb, var(--ok) 60%, transparent); background: color-mix(in srgb, var(--ok) 14%, var(--panel-2)); }
/* "Not sure who": one line, its name beside smaller buttons. */
.quick-card--unknown { flex-direction: row; align-items: center; gap: var(--space-3); padding-block: var(--space-1); background: transparent; border-style: dashed; }
.quick-card--unknown .quick-card__head { flex-shrink: 0; font-size: var(--font-sm); font-weight: 500; color: var(--muted); }
.quick-card--unknown .quick-card__actions { flex: 1; }
/* Five small buttons beside the name in attack, so they keep their padding tight. */
.quick-card--unknown .quick-card__action { min-height: 2.25rem; padding-inline: var(--space-1); font-size: var(--font-sm); }
.quick__team { margin: 0; padding: var(--space-2) var(--space-3); display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--space-2); }
.quick__team-row { display: contents; }
.quick[data-possession="ours"] .quick__team-row--defence,
.quick[data-possession="theirs"] .quick__team-row--attack { display: none; }
.quick__team form { margin: 0; }
.quick__team .btn { width: 100%; min-height: 2.5rem; display: inline-flex; align-items: center; justify-content: center; gap: var(--space-2); font-size: var(--font-sm); white-space: nowrap; }
.quick__team-row--attack > :last-child { grid-column: span 2; }
.quick__their-goal { border-color: rgba(88, 166, 255, 0.55); background: rgba(88, 166, 255, 0.12); }
/* A short screen: each card on one line, its name beside its buttons. */
@media (max-height: 720px) {
  .quick-card { flex-direction: row; align-items: center; gap: var(--space-3); padding-block: var(--space-1); }
  .quick-card__head { flex: 0 0 9rem; min-width: 0; font-size: var(--font-base); }
  .quick-card__name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .quick-card__actions { flex: 1; }
}
@media (max-width: 1000px) {
  .quick__main { grid-template-columns: minmax(0, 1fr); }
  .quick__video { max-width: none; }
}

/* --- Teams table (clubs show page) — per-team roster breakdown by gender. --- */
.teams-table td { vertical-align: middle; }
.teams-table__squad { white-space: nowrap; }
.teams-table__num { text-align: right; font-variant-numeric: tabular-nums; }
.teams-table__actions { white-space: nowrap; text-align: right; }
.teams-table__actions a + a { margin-left: var(--space-2); }

/* --- Jerseys (club page card, club_jerseys/_card): each drawn as a shirt, halved when two colours.
   The colours are custom properties on the swatch (ClubJerseysHelper#jersey_swatch); the outline
   keeps a navy or black shirt visible on the dark panels. --- */
.jersey-swatch { flex: none; vertical-align: middle; }
.jersey-swatch__body { fill: var(--jersey-primary, var(--panel-2)); }
.jersey-swatch__half { fill: var(--jersey-secondary, var(--jersey-primary, var(--panel-2))); }
.jersey-swatch__outline {
  fill: none;
  stroke: color-mix(in srgb, var(--ink) 60%, transparent);
  stroke-width: 1.25;
  stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
}
.jersey-list { list-style: none; margin: 0; padding: 0; }
.jersey-list__item { display: flex; align-items: center; gap: var(--space-3); padding: var(--space-2) 0; border-bottom: 1px solid var(--line); }
.jersey-list__text { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.jersey-list__text strong { overflow-wrap: anywhere; }
.jersey-list__colours { color: var(--muted); font-size: var(--font-sm); font-variant-numeric: tabular-nums; }
.jersey-list__actions { display: flex; align-items: center; gap: var(--space-1); flex: none; }
.jersey-list__actions .button_to { margin: 0; }
/* The second colour only while Two colours is ticked (ClubJersey#two_colours= drops it unticked). */
.jersey-form:has(#club_jersey_two_colours:not(:checked)) .jersey-form__second { display: none; }
.jersey-form .field small { display: block; margin-top: var(--space-1); color: var(--muted); font-size: var(--font-sm); }
/* A fixture's jerseys (fixtures/_jersey): beside each team's name in the head once picked, and the
   picker under each squad card's name. */
.fixture-jersey-mark:not(:empty) { display: inline-flex; margin-right: var(--space-2); vertical-align: -0.15em; }
.fixture-jersey { display: flex; align-items: center; flex-wrap: wrap; gap: var(--space-2) var(--space-3); margin: 0 0 var(--space-4); }
.fixture-jersey__swatch { display: inline-flex; }
.fixture-jersey__form { display: flex; align-items: center; gap: var(--space-2); }
.fixture-jersey__form label { margin: 0; }
.fixture-jersey__form select { width: auto; }
.fixture-jersey__status { color: var(--muted); font-size: var(--font-sm); }
.fixture-jersey__none { margin: 0; }
/* A team's jersey before its name on the entry screens (ClubJerseysHelper#team_jersey), if picked. */
.team-jersey { display: inline-flex; margin-right: 0.35em; vertical-align: -0.2em; }

/* Inline SVG icon (see IconHelper). Sizes with the surrounding text by default. */
.icon { vertical-align: -0.125em; }

/* Small icon + label button used for row actions (Fixtures / Edit). */
.action-link {
  display: inline-flex; align-items: center; gap: var(--space-1);
  padding: var(--space-1) var(--space-2);
  border-radius: var(--radius-sm);
  border: 1px solid transparent;
  color: var(--muted); font-size: var(--font-sm); font-weight: 600;
  transition: color var(--transition-fast), background var(--transition-fast), border-color var(--transition-fast);
}
.action-link:hover { text-decoration: none; color: var(--accent); background: var(--panel-2); border-color: var(--line); }
.action-link .icon { width: 1rem; height: 1rem; flex: none; }
/* As a button_to's button (a row's Remove): no button chrome, so it matches the links beside it. */
button.action-link { background: none; font: inherit; font-size: var(--font-sm); font-weight: 600; line-height: inherit; }
button.action-link:hover { transform: none; box-shadow: none; }
.action-link--danger:hover { color: var(--bad); }

/* Small gender-tinted count pill (number only), reusing the shared gender palette. */
.gender-count {
  display: inline-flex; align-items: center; gap: var(--space-1);
  padding: var(--space-1) var(--space-2);
  border-radius: var(--radius-pill);
  border: 1px solid var(--line);
  font-size: var(--font-xs); font-weight: 600;
}
.gender-count + .gender-count { margin-left: var(--space-1); }
.gender-count--male    { border-color: var(--gender-male);    background: var(--gender-male-bg); }
.gender-count--female  { border-color: var(--gender-female);  background: var(--gender-female-bg); }
.gender-count--neutral { border-color: var(--gender-neutral); background: var(--gender-neutral-bg); }

/* --- Roster manager (drag-and-drop team assignment + team reorder) --- */
.roster-manager__columns {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: var(--space-5);
  align-items: start;
}
.roster-manager__column {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: var(--space-3);
  transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
}
.roster-manager__column-header {
  display: flex; align-items: center; gap: var(--space-2);
  margin-bottom: var(--space-3);
}
.roster-manager__handle {
  cursor: grab;
  color: var(--muted);
  font-size: var(--font-md);
  line-height: 1;
  padding: var(--space-1);
  border-radius: var(--radius-sm);
  user-select: none;
}
.roster-manager__handle:hover { color: var(--ink); background: var(--panel-2); }
.roster-manager__handle:active { cursor: grabbing; }
.roster-manager__player-list {
  list-style: none; margin: 0; padding: 0;
  display: flex; flex-direction: column; gap: var(--space-2);
  min-height: 2.5rem; /* keeps empty columns droppable */
}

/* Drag states — subtle: dashed outline + slight scale/opacity on the dragged element,
   accent-colored highlight on a valid drop target. Matches the restrained visual language
   already used for focus/hover states elsewhere (.btn:hover, .card--clickable:hover). */
.is-dragging {
  opacity: 0.5;
  transform: scale(0.97);
}
.player-chip.is-dragging {
  border-style: dashed;
}
.roster-manager__column.is-dragging {
  border-style: dashed;
}
.roster-manager__column.is-drag-over,
.roster-manager__column--unassigned.is-drag-over {
  border-color: var(--accent);
  box-shadow: var(--shadow-focus);
}
.player-chip[draggable="true"] { cursor: grab; }
.player-chip[draggable="true"]:active { cursor: grabbing; }

/* --- Team roster editor (team show page) — name/remove players for one team via search +
   click, or by dragging chips between the roster and the available-players pool. Two bordered
   zones side by side, collapsing to a stacked column on narrow viewports. --- */
.team-roster {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: var(--space-5);
  align-items: start;
}
.team-roster__zone {
  background: var(--panel-2);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: var(--space-3) var(--space-4);
  transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
}
.team-roster__zone.is-drag-over {
  border-color: var(--accent);
  box-shadow: var(--shadow-focus);
}
.team-roster__zone h2 { margin-top: 0; }
.team-roster__search {
  width: 100%;
  padding: var(--space-2) var(--space-3);
  margin-bottom: var(--space-3);
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  color: var(--ink);
  transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
}
.team-roster__list {
  list-style: none; margin: 0; padding: 0;
  display: flex; flex-direction: column; gap: var(--space-2);
  min-height: 2.5rem; /* keeps an empty zone droppable */
}
.team-roster__empty { color: var(--muted); font-size: var(--font-sm); padding: var(--space-2); }
.team-roster__list:has(.player-chip:not(.hidden)) .team-roster__empty { display: none; }

/* The ＋/✕ affordance on each chip, and the "currently 2s" note on a player named elsewhere. */
.player-chip__action {
  margin-left: auto;
  display: inline-flex; align-items: center; justify-content: center;
  width: 1.5rem; height: 1.5rem; padding: 0; flex: none;
  border-radius: var(--radius-pill);
  border: 1px solid var(--line);
  background: var(--bg); color: var(--muted);
  font-size: var(--font-sm); line-height: 1; cursor: pointer;
}
.player-chip__action:hover { color: var(--ink); border-color: var(--accent); }
.player-chip__badge {
  margin-left: var(--space-1);
  color: var(--muted); font-size: var(--font-xs); font-weight: 500; white-space: nowrap;
}

.player-chip.hidden { display: none; }

/* --- Fixture squad picker (fixtures show page) — drag players from a searchable, grouped pool
   (this team's roster, then rest of the club) into Attack / Defence / Bench lanes. Two columns
   (pool | squad) collapsing to a stack on narrow viewports; reuses the shared .player-chip and the
   .is-dragging / .is-drag-over drag states. --- */
.fixture-squad {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: var(--space-5);
  align-items: start;
}
.fixture-squad__zone,
.fixture-squad__lane {
  background: var(--panel-2);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: var(--space-3) var(--space-4);
  transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
}
.fixture-squad__zone.is-drag-over,
.fixture-squad__lane.is-drag-over {
  border-color: var(--accent);
  box-shadow: var(--shadow-focus);
}
.fixture-squad__zone h4,
.fixture-squad__lane h4 { margin: 0 0 var(--space-2); }
.fixture-squad__search {
  width: 100%;
  padding: var(--space-2) var(--space-3);
  margin-bottom: var(--space-3);
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  color: var(--ink);
  transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
}
.fixture-squad__group {
  margin: var(--space-3) 0 var(--space-2);
  color: var(--muted); font-size: var(--font-sm);
  text-transform: uppercase; letter-spacing: 0.03em;
}
.fixture-squad__squad { display: flex; flex-direction: column; gap: var(--space-3); }
/* Where ＋ put a player, or why a division refused one. Takes no room until it says something. */
.fixture-squad__status { margin: 0; color: var(--muted); font-size: var(--font-sm); }
.fixture-squad__status:empty { display: none; }
.fixture-squad__list {
  list-style: none; margin: 0; padding: 0;
  display: flex; gap: var(--space-2);
  min-height: 2.5rem; /* keeps an empty list droppable */
}
.fixture-squad__zone .fixture-squad__list { flex-direction: column; }
.fixture-squad__lane .fixture-squad__list { flex-direction: row; flex-wrap: wrap; align-content: flex-start; }
.fixture-squad__empty { color: var(--muted); font-size: var(--font-sm); padding: var(--space-2); }
.fixture-squad__list:has(.player-chip:not(.hidden)) .fixture-squad__empty { display: none; }
/* The pinned Unknown Player: shown in the squad but not draggable/removable. */
.fixture-squad__pinned { margin-top: var(--space-3); cursor: default; }

/* --- Help icons & popovers (help_popover_controller.js, HelpHelper#help_icon) ---
   A quiet inline "?" disclosing a short explanation. Same anchoring trick as .menu; sits above
   the z-index:20 dropdowns so an open popover isn't cut by a neighbouring menu. */
.help { position: relative; display: inline-flex; vertical-align: middle; }
.help__toggle {
  display: inline-flex; align-items: center; justify-content: center;
  padding: 2px; line-height: 1;
  background: transparent; border: none; border-radius: 50%;
  color: var(--muted); cursor: help;
}
.help__toggle:hover, .help__toggle[aria-expanded="true"] {
  color: var(--accent); background: transparent; border-color: transparent;
  transform: none; box-shadow: none;
}
.help__toggle:focus-visible { box-shadow: var(--shadow-focus); }
/* The panel and its title/body are <span>s styled as blocks — phrasing content, so a help icon
   can legally sit inside a <p> or heading (see HelpHelper#help_icon). */
.help__panel {
  display: block;
  position: absolute; top: 100%; left: 0; z-index: 30; margin-top: var(--space-1);
  width: max-content; max-width: min(18rem, calc(100vw - 2rem));
  padding: var(--space-3);
  background: var(--panel-2); border: 1px solid var(--line); border-radius: var(--radius);
  box-shadow: var(--shadow-lg);
  font-size: var(--font-sm); font-weight: 400; line-height: var(--line-normal); text-align: left;
  white-space: normal;
}
.help__panel[hidden] { display: none; }
/* Right-anchored, for icons near the viewport's right edge (the sidebar cards). */
.help__panel--left { left: auto; right: 0; }
/* Opens upward, for icons at the bottom of the overflow-clipped court card. */
.help__panel--up { top: auto; bottom: 100%; margin: 0 0 var(--space-1); }
.help__title { display: block; margin: 0 0 var(--space-1); font-weight: 600; color: var(--ink); }
.help__body { display: block; margin: 0; color: var(--muted); }
.help__more {
  margin-top: var(--space-2); padding: 0; line-height: inherit;
  background: transparent; border: none;
  color: var(--accent); font-size: var(--font-xs); font-weight: 600; cursor: pointer;
}
.help__more:hover { text-decoration: underline; border-color: transparent; transform: none; box-shadow: none; }
/* "Learn more" opens the page's help drawer, so only show it where one exists — shared partials
   (scoreboard, video, match clock) also render on screens with no drawer. */
.help__more { display: none; }
[data-controller~="help-drawer"] .help__more { display: inline-block; }
/* Narrow screens: the single-column layout puts icons hard against both edges, so anchored
   panels overflow whichever way they open. A fixed bottom sheet always fits (position:fixed
   also escapes the court card's overflow clipping — no ancestor creates a containing block). */
@media (max-width: 700px) {
  .help__panel, .help__panel--left, .help__panel--up {
    position: fixed; top: auto; bottom: var(--space-3); left: var(--space-3); right: var(--space-3);
    width: auto; max-width: none; margin: 0;
  }
}

/* Always-visible nudge above the court controls pointing new users at the click-to-log flow. */
.court-hint { margin: 0 0 var(--space-3); font-size: var(--font-sm); }

/* --- Help drawer (help_drawer_controller.js, entry/_help_drawer) ---
   A fixed right-side panel of long-form help. Non-modal by design — no backdrop, so the court
   stays clickable while reading. Above the popovers/menus; the native <dialog> entry flows
   render in the browser's top layer and so always win, which is correct. */
.help-drawer {
  position: fixed; inset: 0 0 0 auto; z-index: 40;
  width: min(26rem, 100%);
  background: var(--panel); border-left: 1px solid var(--line);
  box-shadow: var(--shadow-lg);
  overflow-y: auto; overscroll-behavior: contain;
}
.help-drawer[hidden] { display: none; }
.help-drawer__head {
  position: sticky; top: 0; z-index: 1;
  display: flex; align-items: center; justify-content: space-between; gap: var(--space-3);
  padding: var(--space-4) var(--space-5);
  background: var(--panel); border-bottom: 1px solid var(--line);
}
.help-drawer__title { margin: 0; font-size: var(--font-md); }
.help-drawer__title:focus-visible { outline: none; box-shadow: var(--shadow-focus); border-radius: var(--radius-sm); }
.help-drawer__close {
  padding: 0.1rem 0.5rem; line-height: 1;
  background: transparent; border-color: transparent; color: var(--muted);
}
.help-drawer__close:hover { color: var(--ink); border-color: var(--line); transform: none; }
.help-drawer__body { padding: var(--space-4) var(--space-5) var(--space-6); }
.help-drawer__intro { margin: 0 0 var(--space-4); color: var(--muted); font-size: var(--font-sm); }
.help-drawer__section {
  padding: var(--space-4) 0; border-top: 1px solid var(--line);
  scroll-margin-top: var(--space-8); /* clears the sticky head when scrolled to */
  font-size: var(--font-sm);
}
.help-drawer__section h3 { font-size: var(--font-base); margin: 0 0 var(--space-2); }
.help-drawer__section p { margin: 0 0 var(--space-2); color: var(--muted); }
.help-drawer__section p:last-child { margin-bottom: 0; }
.help-drawer__section ul { margin: 0 0 var(--space-2); padding-left: 1.2rem; color: var(--muted); }
.help-drawer__section li { margin-bottom: var(--space-1); }
.help-drawer__section strong, .help-drawer__section em { color: var(--ink); }
/* Brief highlight when "Learn more" jumps to a section. */
@keyframes help-flash {
  from { background: rgba(255, 159, 28, 0.16); }
  to { background: transparent; }
}
.help-drawer__section.is-flash { animation: help-flash 1.2s ease-out; }
.help-drawer__guide-link { display: block; margin-top: var(--space-2); font-weight: 600; }
.help-drawer kbd { font-family: inherit; font-size: 0.85em; padding: 0 0.35em; border: 1px solid var(--line); border-radius: 3px; color: var(--ink); background: var(--bg); }
.help-drawer__keys { width: 100%; border-collapse: collapse; font-size: var(--font-sm); color: var(--muted); }
.help-drawer__keys td { padding: var(--space-1) var(--space-2) var(--space-1) 0; vertical-align: top; border: none; }
.help-drawer__keys td:first-child { white-space: nowrap; }

/* --- Audit trail (/activity, /versions) and the users page presence columns --- */
.audit-subnav { display: flex; gap: var(--space-2); margin: var(--space-3) 0; }
.audit-subnav a { padding: var(--space-1) var(--space-3); border: 1px solid var(--line); border-radius: var(--radius-pill); color: var(--muted); text-decoration: none; }
.audit-subnav a.active { color: var(--ink); border-color: var(--accent); }
.audit-filter input, .audit-filter select { width: auto; max-width: 16rem; padding: var(--space-2) var(--space-3); background: var(--bg); border: 1px solid var(--line); border-radius: var(--radius); color: var(--ink); }
.audit-filter .audit-filter__short { max-width: 7rem; }
.table-scroll { overflow-x: auto; }
.audit-table td { vertical-align: top; font-size: var(--font-sm); }
.audit-table code { font-size: var(--font-xs); }
.audit-path { word-break: break-all; max-width: 18rem; }
.audit-changes ul { margin: 0; padding-left: 1rem; }
.audit-changes li { word-break: break-word; }
.audit-params-row td { padding-top: 0; border-bottom: 1px solid var(--line); }
.audit-params summary { cursor: pointer; font-size: var(--font-xs); }
.audit-params pre { margin: var(--space-2) 0 0; padding: var(--space-2) var(--space-3); background: var(--bg); border-radius: var(--radius); font-size: var(--font-xs); max-height: 20rem; overflow: auto; }
.nowrap { white-space: nowrap; }
td .inline-form { display: inline; }
/* The event log's Edit and Delete, side by side on the row's right. */
.event-log__actions { white-space: nowrap; text-align: right; }
.event-log__actions .button_to { display: inline; margin-left: var(--space-2); }

/* --- Two-step sign-in (profile_two_factors/new, users/sessions/two_factor) --- */
/* White, with a quiet zone, whatever the theme: a QR code needs dark on light to scan. */
.two-factor__qr { display: inline-block; padding: var(--space-3); background: #fff; border-radius: var(--radius); line-height: 0; }
.two-factor__qr svg { width: 12rem; height: 12rem; }
.two-factor__secret { font-size: var(--font-md); letter-spacing: 0.05em; overflow-wrap: anywhere; }
form input.two-factor__code { max-width: 10rem; font-size: 1.25rem; letter-spacing: 0.15em; font-variant-numeric: tabular-nums; }

/* --- Privacy requests (privacy_requests/*): the public form and the super admin's pages --- */
/* A player's personal data export (player_personal_data/show, print layout). */
.personal-data { max-width: 60rem; margin: 0 auto; }
.personal-data__warning { flex-basis: 100%; margin: var(--space-2) 0 0; color: var(--muted); }
.personal-data__note + .personal-data__note { border-top: 1px solid var(--line); margin-top: var(--space-3); padding-top: var(--space-3); }
.personal-data__events { font-size: var(--font-sm); margin-bottom: var(--space-3); }
.privacy-request__form { max-width: 40rem; }
.privacy-request__choices { border: 0; margin: 0 0 var(--space-4); padding: 0; min-width: 0; }
.privacy-request__choices legend { font-weight: 600; margin-bottom: var(--space-2); padding: 0; }
.privacy-request__choices .radio { display: block; margin: 0 0 var(--space-2); }
.privacy-request__form .field small { display: block; margin-top: var(--space-1); color: var(--muted); font-size: var(--font-sm); }
/* The bots' trap field (PrivacyRequestsController::HONEYPOT): off-screen, never display:none,
   which some bots skip. aria-hidden and tabindex=-1 keep it from people. */
.privacy-request__trap { position: absolute; left: -10000px; width: 1px; height: 1px; overflow: hidden; }
.privacy-request__facts { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: var(--space-2) var(--space-4); margin: 0 0 var(--space-4); font-size: var(--font-sm); }
.privacy-request__facts dt { color: var(--muted); }
.privacy-request__facts dd { margin: 0; overflow-wrap: anywhere; }
.privacy-request__details { white-space: pre-wrap; overflow-wrap: anywhere; }

/* --- Awards (Award): the badges, Your awards and an account's (awards/_board), the profile card's
   chips and the toast announcing new ones (awards/_toast, award_toast_controller.js), fixed in the
   bottom corner above everything but a modal dialog. --- */
.award-badge {
  position: relative; display: inline-grid; place-items: center; flex-shrink: 0;
  width: 2.5rem; height: 2.5rem; border-radius: 50%;
  border: 3px solid var(--award); color: var(--award);
  background: radial-gradient(circle at 50% 30%, color-mix(in srgb, var(--award) 24%, var(--panel-2)), var(--panel-2) 72%);
  box-shadow: inset 0 0 0 2px var(--panel), 0 0 0 1px color-mix(in srgb, var(--award) 35%, transparent);
}
/* A ladder's milestone: its count on a tab over the foot of the ring. */
.award-badge__count {
  position: absolute; bottom: -0.55rem; left: 50%; transform: translateX(-50%);
  min-width: 1.25rem; padding: 0 0.3rem; border: 2px solid var(--panel); border-radius: var(--radius-pill);
  background: var(--award); color: #1d1a10;
  font-size: 0.6875rem; font-weight: 700; line-height: 1.2; text-align: center; white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.award-badge--unearned { border-color: var(--line); color: var(--muted); background: var(--panel-2); box-shadow: none; opacity: 0.7; }
.award-badge--unearned .award-badge__count { background: var(--line); color: var(--ink); }
.award-badge--small { width: 1.6rem; height: 1.6rem; border-width: 2px; box-shadow: none; }

.award-groups {
  display: grid; gap: var(--space-4); align-items: start;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 26rem), 1fr));
}
.award-group h2 { margin-top: 0; }
.award-list { display: grid; gap: var(--space-3); margin: 0 0 var(--space-3); padding: 0; list-style: none; }
.award { display: flex; align-items: center; gap: var(--space-3); }
.award__body { flex: 1; min-width: 0; }
.award__title { margin: 0; font-weight: 600; }
.award:not(.award--earned) .award__title { color: var(--muted); }
.award__text { margin: 0; color: var(--muted); font-size: var(--font-sm); }
.award__status {
  flex-shrink: 0; min-width: 6.5rem; margin: 0; text-align: right;
  color: var(--muted); font-size: var(--font-sm); font-variant-numeric: tabular-nums;
}
.award--earned .award__status { color: var(--ink); }
.award__bar {
  display: block; height: 4px; margin-bottom: 4px; border-radius: var(--radius-pill);
  background: linear-gradient(to right, var(--accent) calc(var(--award-share) * 100%), var(--line) 0);
}
@media (max-width: 480px) {
  .award { flex-wrap: wrap; }
  .award__status { flex-basis: 100%; padding-left: calc(2.5rem + var(--space-3)); text-align: left; }
}

.award-chips { display: flex; flex-wrap: wrap; gap: var(--space-2); margin: 0 0 var(--space-3); padding: 0; list-style: none; }
.award-chip {
  display: inline-flex; align-items: center; gap: var(--space-2);
  padding: 0.2rem 0.75rem 0.2rem 0.2rem; border: 1px solid var(--line); border-radius: var(--radius-pill);
  background: var(--panel-2); font-size: var(--font-sm);
}

.award-toasts {
  position: fixed; right: var(--space-4); bottom: var(--space-4); z-index: 40;
  display: grid; gap: var(--space-2); width: min(22rem, calc(100vw - 2 * var(--space-4)));
  pointer-events: none;
}
.award-toast {
  position: relative; display: flex; align-items: flex-start; gap: var(--space-3);
  padding: var(--space-3) var(--space-6) var(--space-3) var(--space-3);
  border: 1px solid var(--line); border-left: 4px solid var(--accent); border-radius: var(--radius-lg);
  background: var(--panel); box-shadow: var(--shadow-lg); pointer-events: auto;
  transition: opacity var(--transition-slow), transform var(--transition-slow);
  animation: award-toast-in var(--transition-slow);
}
.award-toast--leaving { opacity: 0; transform: translateY(0.5rem); }
@keyframes award-toast-in { from { opacity: 0; transform: translateY(0.5rem); } }
@media (prefers-reduced-motion: reduce) { .award-toast { animation: none; transition: none; } }
.award-toast__body { min-width: 0; }
.award-toast__kicker {
  margin: 0; color: var(--accent);
  font-size: var(--font-xs); font-weight: 600; letter-spacing: 0.05em; text-transform: uppercase;
}
.award-toast__title { margin: 0; font-weight: 700; }
.award-toast__text { margin: 0 0 var(--space-1); color: var(--muted); font-size: var(--font-sm); }
.award-toast__link { font-size: var(--font-sm); }
.award-toast__close {
  position: absolute; top: var(--space-1); right: var(--space-1); padding: var(--space-1) var(--space-2);
  border: 0; border-radius: var(--radius-sm); background: none; color: var(--muted);
  font-size: 1.25rem; line-height: 1; cursor: pointer;
}
.award-toast__close:hover, .award-toast__close:focus-visible { color: var(--ink); }
@media print { .award-toasts { display: none; } }

/* --- Season pack print sheet (reports/team_pack, reports/season_pack) ---
   A paged sheet the browser saves as one PDF: the report, then a page per player. The dark theme's
   tokens are redefined light on .report-pack inside @media print, so every card, table, shade and
   SVG paint follows from one place instead of dozens of overrides. Scoped to .report-pack, never
   .print-layout, which the drill print sheet also uses.
   These rules sit at the end of the file on purpose: .print-layout .card / .muted above have the
   same specificity, so the pack's equivalents have to come later to win. */
.report-pack__player { break-before: page; page-break-before: always; }
@media print {
  .report-pack {
    --bg: #fff;  --panel: #fff;  --panel-2: #f4f6f9;
    --ink: #111; --muted: #555;  --line: #b9c2cc;
    --accent: #a85f00;                           /* reads as ink on white, still the brand amber */
    --shade-hi: #cadff6; --shade-lo: #f7d2d6;    /* pale: td.shade paints var(--ink) on them */
    --radar-player: #a85f00; --radar-compare: #1f5fae;
    /* Re-declared, not inherited: a custom property whose value uses var() is substituted where it
       is DECLARED (:root), so --ink above can never reach the original. It's the only such token. */
    --radar-average: #6b7280;
    --match-home: #a85f00; --match-away: #1f5fae;
    /* Browsers drop background colours when printing unless asked. The shading, the shooting bars,
       the stat tiles and the radar's washes are all backgrounds, and all load-bearing. Inherited. */
    print-color-adjust: exact; -webkit-print-color-adjust: exact;
    color: var(--ink);
    font-size: 9.5pt;
  }
  .report-pack .muted { color: var(--muted); }
  .report-pack .card {
    background: var(--panel); border: 1px solid var(--line); box-shadow: none;
    padding: var(--space-3) var(--space-4); margin-bottom: var(--space-3);
  }
  .report-pack a { color: var(--ink); text-decoration: none; }

  /* Chrome that never belongs on paper (.actions is already hidden globally). */
  .report-pack .sort-arrow, .report-pack .season-picker,
  .report-pack .view-toggle, .report-pack .profile-compare { display: none; }

  /* Paper doesn't scroll: .table-wrap's overflow-x would clip the players table. */
  .report-pack .table-wrap { overflow: visible; }
  .report-pack table { border-radius: 0; }
  .report-pack .player-table, .report-pack .game-log { font-size: 8pt; }
  .report-pack .player-table :is(th, td), .report-pack .game-log :is(th, td) { padding: 2px 4px; }
  /* The players table runs to 27 columns in a season, so on paper it takes smaller type, headers
     that wrap ("FP con" over two lines), and each name without its avatar and chip, to fit the
     page's width rather than run off it. */
  .report-pack .player-table { font-size: 7pt; }
  .report-pack .player-table :is(th, td) { padding: 2px 2px; }
  .report-pack .player-table th { font-size: 6.5pt; letter-spacing: 0; vertical-align: bottom; }
  .report-pack .player-table th.sortable button { white-space: normal; text-align: left; }
  .report-pack .player-table .avatar { display: none; }
  .report-pack .player-table .player-chip { padding: 0; border: 0; background: none; font-weight: 600; }
  .report-pack .player-table .player-chip__name { white-space: normal; }

  /* The radar keeps its key beside it: the max-width:800px collapse fires at paper width and
     would push every player onto a second page. */
  .report-pack .profile { grid-template-columns: minmax(0, 19rem) minmax(0, 1fr); gap: var(--space-4); }
  .report-pack .radar { max-width: 19rem; }
  /* 35% of a pale tint is invisible on white, so the bands take a heavier mix of the same tokens. */
  .report-pack .radar__band--hi { fill: color-mix(in srgb, var(--shade-hi) 75%, transparent); }
  .report-pack .radar__band--lo { fill: color-mix(in srgb, var(--shade-lo) 75%, transparent); }

  /* The print shades are pale tints chosen to sit UNDER ink text, so as a hairline on white they'd
     be invisible: the outlined levels borrow the sheet's own line instead. The filled ones keep the
     tint, which the inherited print-color-adjust above carries onto paper. */
  .report-pack :is(.trait__level--hi, .trait__level--lo) { border-color: var(--line); }

  /* A match report keeps its two sides, and the score chart its key, side by side: the 800px
     collapse fires at paper width too. Its small tables print as small as the players table. */
  .report-pack .match-sides { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-4); }
  .report-pack .score-flow__body { grid-template-columns: minmax(0, 1fr) 13rem; gap: var(--space-4); }
  .report-pack :is(.moments__table, .period-table, .duel__table) { font-size: 8pt; }
  .report-pack :is(.moments__table, .period-table, .duel__table) :is(th, td) { padding: 2px 4px; }
  .report-pack .duel__score { font-size: var(--font-xl); }

  /* Keep small things whole. A card holding a table must still be allowed to split: an
     unbreakable oversized box gets clipped rather than paginated. */
  .report-pack :is(.stat-tile, .leader-tile, .bar-row, .form-line, .profile__chart, .trait, tr,
                   .duel, .shot-map__side, .score-flow__body) { break-inside: avoid; }
  .report-pack .card:not(:has(table)) { break-inside: avoid; }
  .report-pack thead { display: table-header-group; }
  .report-pack :is(h1, h2, h3) { break-after: avoid; }
}

/* Add missed events (entry/insert): court entry at a place in the log. The place card heads the main
   column, saying where an event entered now goes and how the match stood there; Around here lists the
   batches either side, the place between them. */
.insert-entry__lede { margin: 0 0 var(--space-3); max-width: 70ch; font-size: var(--font-sm); }
.insert-place { margin-bottom: 1rem; border-left: 3px solid var(--accent); }
.insert-place__where { margin: 0 0 var(--space-2); font-size: 1rem; line-height: 1.4; }
.insert-place__state { margin: 0 0 var(--space-3); font-size: var(--font-sm); color: var(--muted); }
.insert-place__score { color: var(--ink); font-variant-numeric: tabular-nums; font-weight: 600; }
.insert-place__actions { flex-wrap: wrap; }
.insert-place__actions [aria-disabled="true"] { opacity: 0.45; cursor: default; }
.insert-place__note { margin: var(--space-2) 0 0; font-size: var(--font-sm); }
.insert-around__list { list-style: none; margin: 0; padding: 0; }
.insert-around__row { border-bottom: 1px solid var(--line); border-left: 3px solid transparent; }
.insert-around__row--home { border-left-color: var(--accent); }
.insert-around__row--away { border-left-color: #58a6ff; }
.insert-around__link {
  display: flex; gap: 0.4rem; align-items: baseline; flex-wrap: wrap;
  padding: 0.25rem 0.55rem; color: inherit; text-decoration: none; font-size: 0.8rem; line-height: 1.4;
}
.insert-around__link:hover, .insert-around__link:focus-visible { background: var(--panel-2); }
.insert-around__when { color: var(--muted); font-size: 0.68rem; font-variant-numeric: tabular-nums; min-width: 4.5em; }
.insert-around__place {
  margin: 0.3rem 0; padding: 0.3rem 0.55rem; border: 1px dashed var(--accent); border-radius: var(--radius-sm);
  color: var(--accent); font-size: 0.8rem; font-weight: 600;
}
.insert-around__foot { margin: var(--space-2) 0 0; font-size: var(--font-sm); }

/* Import from spreadsheet (team_stats_sheets): a tab's fixture and score, a name's member. */
.stats-import__table td, .stats-import__table th { vertical-align: middle; }
.stats-import__table tbody th { color: var(--ink); font-size: var(--font-sm); text-transform: none; letter-spacing: 0; white-space: nowrap; }
.stats-import__pick { display: flex; align-items: center; gap: var(--space-2); }
.stats-import__pick select { min-width: 16rem; }
.stats-import input.stats-import__score { width: 5rem; }
.stats-import__bad { color: var(--bad); }
.stats-sheet-last__matches { margin: var(--space-2) 0; }
.stats-sheet-link__form .field small { display: block; margin-top: var(--space-1); color: var(--muted); font-size: var(--font-sm); }
