/* ============================================================
   0FFDAYS — Mobile App Stylesheet v3
   Dark, premium, app-like. Phone-first, one-handed use.
   ============================================================ */

@import url("fonts/fonts.css");

/* Force dark mode — the app is dark by design. */
:root {
  color-scheme: dark;
  forced-color-adjust: none;
}

:root {
  /* The brand values, from the kit -- not Tailwind's defaults. #008BFD is
     the blue in the 0FFDAYS lockup itself, so an accent of #3b82f6 put the
     wordmark and the buttons beside it in two different blues. Every one of
     these is asserted by tests/test_branding.py. */
  --bg: #0A0A0B;
  --surface: #0B1B2B;
  --surface-2: #0D1E30;
  --surface-3: #16293C;
  --accent: #008BFD;
  --accent-bright: #47AEFF;
  --accent-dim: #0063C4;
  --go: #12A150;
  --warn: #C77700;
  --gold: #C77700;
  --border: #2a3a52;
  --border-light: #374a66;
  --text: #E8EFF6;
  --text-muted: #8FA3B8;
  --text-dim: #6E8399;
  /* The name the rest of the stylesheet has always used. Renaming it to
     --text-muted left every existing rule resolving to nothing. */
  --muted: #8FA3B8;
  --danger: #DD5A50;
  --danger-dim: #C4453C;

  --left: #008BFD;
  --right: #F0A64A;

  --radius: 14px;
  --radius-sm: 10px;
  --radius-lg: 20px;
  --radius-xl: 28px;
  --font: "Inter", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --font-condensed: "Barlow Condensed", var(--font);
  --font-mono: "JetBrains Mono", ui-monospace, Menlo, monospace;

  --shadow-sm: 0 1px 3px rgba(0,0,0,0.4);
  --shadow-md: 0 4px 12px rgba(0,0,0,0.5);
  --shadow-lg: 0 8px 30px rgba(0,0,0,0.6);
  --glow-accent: 0 0 20px rgba(59,130,246,0.3);
}

@supports not (font-family: "Inter") {
  :root {
    --font: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
    --font-condensed: "Barlow Condensed", var(--font);
  }
}

/* ============================================================
   RESET & BASE
   ============================================================ */
*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  -webkit-tap-highlight-color: transparent;
}

body {
  margin: 0;
  font-family: var(--font);
  font-size: 16px;
  line-height: 1.5;
  background: var(--bg);
  color: var(--text);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overscroll-behavior: none;
  min-height: 100vh;
  min-height: 100dvh;
}

/* Scrollbar styling for webkit */
::-webkit-scrollbar { width: 6px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: var(--border); border-radius: 3px; }
::-webkit-scrollbar-thumb:hover { background: var(--border-light); }

/* ============================================================
   TYPOGRAPHY
   ============================================================ */
h1, h2, h3, h4 {
  margin: 0;
  font-family: var(--font-condensed);
  font-weight: 700;
  letter-spacing: -0.01em;
  line-height: 1.1;
  color: var(--text);
}

h1 { font-size: 2.2rem; }
h2 { font-size: 1.5rem; }
h3 { font-size: 1.15rem; }

p { margin: 0 0 0.75rem; color: var(--text-muted); line-height: 1.6; }
p:last-child { margin-bottom: 0; }

small, .small { font-size: 0.8rem; }
.muted { color: var(--text-muted); }

/* A control that belongs beside text rather than in a column of its own. */
.linkish {
  background: none;
  border: 0;
  padding: 0;
  margin: 2px 0 0;
  min-height: 0;
  font: inherit;
  font-size: 0.78rem;
  color: var(--accent);
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 2px;
}
.linkish:hover { text-decoration: none; }
.linkish:disabled { color: var(--text-muted); cursor: default; }
.dim { color: var(--text-dim); }

a { color: var(--accent-bright); text-decoration: none; }
a:hover { text-decoration: underline; }

code, .code, .claim-code {
  font-family: var(--font-mono);
  font-size: 0.9em;
  background: var(--surface-2);
  padding: 0.1em 0.4em;
  border-radius: 4px;
  color: var(--accent-bright);
}

/* ============================================================
   LAYOUT
   ============================================================ */
/* Phone-first pages (capture, parent, leaderboard, sign-in) are one narrow
   column. The coach dashboard is read on a laptop or a tablet and gets the
   width it had before the re-skin: a 480px column on a 1280px screen is a
   phone app in a desktop window. Cards on it flow into two columns. */
.wrap {
  max-width: 1100px;
  margin: 0 auto;
  padding: 0 16px 80px;
}
.wrap--narrow { max-width: 480px; }
@media (min-width: 900px) {
  .wrap.wrap--grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0 16px;
    align-items: start;
  }
  .wrap.wrap--grid > .card,
  .wrap.wrap--grid > .sponsor-slot,
  .wrap.wrap--grid > details { min-width: 0; }
  .wrap.wrap--grid > .card.card--wide { grid-column: 1 / -1; }
}

.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 1.25rem;
  margin-bottom: 1rem;
  box-shadow: var(--shadow-sm);
}

.card-sm {
  padding: 0.875rem;
  margin-bottom: 0.75rem;
}

/* ============================================================
   TOPBAR — App-like header
   ============================================================ */
.topbar {
  position: sticky;
  top: 0;
  z-index: 100;
  /* Three columns so the club's crest is centred on the bar itself rather
     than on the branding block. The outer two are minmax(0, 1fr) and not
     1fr: with plain 1fr the sign-out block's min-content width sets both
     sides, which pushes the centre off-centre and overflows on a phone. */
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  align-items: center;
  gap: 12px;
  /* Inside the phone app the page runs under the status bar (viewport-fit=
     cover), so the clock and battery sat on top of the logo. The inset is 0
     in an ordinary browser tab, so nothing changes there. */
  padding: calc(0.75rem + env(safe-area-inset-top, 0px)) calc(16px + env(safe-area-inset-right, 0px)) 0.75rem calc(16px + env(safe-area-inset-left, 0px));
  background: var(--surface);
  border-bottom: 1px solid var(--border);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
}

.topbar-brand {
  display: flex;
  align-items: center;
  gap: 10px;
  text-decoration: none;
}

.topbar-logo {
  width: 40px;
  height: 40px;
  border-radius: 10px;
  object-fit: contain;
  flex-shrink: 0;
  background: #0B1B2B;
  background: linear-gradient(135deg, #0B1B2B 0%, #0A0A0B 100%);
  display: block;
  /* Visible even if the PNG fails to load — electric blue ring fills in */
  background-size: contain;
  background-repeat: no-repeat;
  background-position: center;
}

.topbar-title {
  font-family: var(--font-condensed);
  font-weight: 700;
  font-size: 1.25rem;
  color: var(--text);
  letter-spacing: -0.02em;
}

.topbar-title .highlight {
  color: var(--accent-bright);
}

.topbar-right {
  display: flex;
  align-items: center;
  gap: 8px;
  justify-self: end;
}

/* ---- The club's header ----------------------------------------------
   An athlete opens this app to train for their club, not for us. Their
   crest leads at a size you would call a logo and sits in the middle of
   the bar; ours sits at the far left at a size you would call a credit. */

/* The slot lays out nothing itself: its two children become bar columns,
   which is what allows the crest to centre on the whole header. */
#masthead { display: contents; }
.mast-left { display: flex; align-items: center; gap: 12px; min-width: 0; }
.masthead { display: flex; align-items: center; gap: 12px; min-width: 0; }
.mast-left .stack, .masthead .stack {
  display: flex; flex-direction: column; gap: 1px; min-width: 0;
}

.club-badge {
  /* Sized from the crest's real aspect (2.80:1) so it still leads our
     120px lockup -- tests/test_branding_club.py measures it. */
  height: 72px; width: auto; max-width: 240px; display: block; flex: 0 0 auto;
}
.club-name {
  font-family: var(--font-condensed); font-weight: 600; font-size: 1.18rem;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* The full lockup at its documented 120px minimum, at every width. The
   guidelines allow swapping to the bare glyph where it will not fit; a
   half-logo reads as a broken one, so the bar wraps instead. */
.offdays-lockup { width: 120px; height: auto; display: block; }
.offdays-mark { display: none; height: 22px; width: auto; }
.role {
  font-size: .68rem; letter-spacing: .12em; text-transform: uppercase;
  color: var(--muted); white-space: nowrap; margin-top: 2px;
}

/* ============================================================
   BUTTONS — Solid, tappable, premium
   ============================================================ */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  width: 100%;
  padding: 0.8rem 1.25rem;
  min-height: 52px;
  font-family: var(--font);
  font-size: 1rem;
  font-weight: 600;
  line-height: 1.2;
  color: #fff;
  background: var(--accent);
  border: none;
  border-radius: var(--radius-xl);
  cursor: pointer;
  transition: all 0.15s ease;
  box-shadow: 0 2px 8px rgba(59,130,246,0.3);
  -webkit-tap-highlight-color: transparent;
  user-select: none;
  position: relative;
  overflow: hidden;
}

.btn::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(255,255,255,0.15) 0%, transparent 100%);
  opacity: 0;
  transition: opacity 0.15s;
}

.btn:hover::after { opacity: 1; }
.btn:active { transform: scale(0.97); box-shadow: 0 1px 4px rgba(59,130,246,0.2); }
.btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
  transform: none;
  box-shadow: none;
}
.btn:disabled::after { opacity: 0; }

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

.btn-secondary {
  background: var(--surface-2);
  color: var(--text);
  border: 1px solid var(--border-light);
  box-shadow: none;
}

.btn-secondary::after { display: none; }
.btn-secondary:hover { background: var(--surface-3); border-color: var(--accent-dim); }

.btn-ghost {
  background: transparent;
  color: var(--text-muted);
  border: 1px solid var(--border);
  box-shadow: none;
}
.btn-ghost::after { display: none; }
.btn-ghost:hover { color: var(--text); border-color: var(--border-light); background: var(--surface-2); }

.btn-sm {
  padding: 0.6rem 1rem;
  min-height: 40px;
  font-size: 0.875rem;
  border-radius: var(--radius-sm);
}

/* Plain <button>s (capture.html, coach.html, parent.html still use them)
   get the same treatment as .btn, with the three modifiers those pages
   rely on. Without this a bare <button> is the browser default -- a
   44x21 grey chip, which is how Start/Finish shipped on 2026-11-02. */
button:not([class*="btn"]):not(.bell):not(.feel):not(.cue-btn) {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  width: 100%;
  padding: 0.8rem 1.25rem;
  min-height: 52px;
  font-family: var(--font);
  font-size: 1rem;
  font-weight: 600;
  line-height: 1.2;
  color: #fff;
  background: var(--accent);
  border: none;
  border-radius: var(--radius-xl);
  cursor: pointer;
  box-shadow: 0 2px 8px rgba(59,130,246,0.3);
  -webkit-tap-highlight-color: transparent;
  user-select: none;
}
button:not([class*="btn"]):active { transform: scale(0.97); }
button:not([class*="btn"]):disabled { opacity: 0.5; cursor: not-allowed; transform: none; box-shadow: none; }
button.secondary, button.secondary:not([class*="btn"]):not(.bell):not(.feel):not(.cue-btn) { background: var(--surface-2); color: var(--text); border: 1px solid var(--border-light); box-shadow: none; }
#ball-calibrate { background: var(--surface-2); color: var(--text); border: 1px solid var(--border-light); box-shadow: none; min-height: 44px; font-size: 0.9rem; }
button.danger, button.danger:not([class*="btn"]):not(.bell):not(.feel):not(.cue-btn) { background: var(--danger); color: #fff; box-shadow: 0 2px 8px rgba(239,68,68,0.35); }
button.inline, button.inline:not([class*="btn"]):not(.bell):not(.feel):not(.cue-btn) { width: auto; padding: 0.5rem 0.9rem; min-height: 38px; font-size: 0.875rem; border-radius: var(--radius-sm); }

/* A small button for a row of a table: about half the height of .inline, and
   only as wide as its words. The roster's "Email parent" sat in the athlete
   cell as a full-width 52px blue slab, bigger than the name above it. */
button.tiny, button.tiny:not([class*="btn"]):not(.bell):not(.feel):not(.cue-btn),
a.tiny {
  display: inline-flex; align-items: center; justify-content: center;
  width: auto; min-height: 26px; padding: 0.2rem 0.65rem; margin: 4px 6px 0 0;
  font-size: 0.75rem; font-weight: 600; line-height: 1.2; white-space: nowrap;
  border-radius: var(--radius-sm); box-shadow: none;
  background: var(--surface-2); color: var(--text); border: 1px solid var(--border-light);
}
button.tiny:hover, a.tiny:hover { border-color: var(--accent); text-decoration: none; }

/* Status pills (coach roster, families). Lost in the v3 re-skin. */
.pill {
  display: inline-block; padding: 3px 9px; border-radius: 99px;
  font-size: .7rem; font-weight: 700; letter-spacing: .03em; white-space: nowrap;
  background: var(--surface-3); color: var(--text-muted);
}
.pill.ok { background: color-mix(in srgb, var(--go) 18%, transparent); color: var(--go); }
.pill.warn { background: color-mix(in srgb, var(--warn) 18%, transparent); color: var(--warn); }
.pill.bad { background: color-mix(in srgb, var(--danger) 18%, transparent); color: var(--danger); }

/* Families card: one stacked row per family, never a four-column table --
   at tablet width the table folded every cell into a column of words. */
.family-row {
  display: grid; grid-template-columns: 1fr auto; gap: 4px 12px; align-items: center;
  padding: 10px 0; border-bottom: 1px solid var(--border);
}
.family-row:last-child { border-bottom: none; }
.family-row .family-main { min-width: 0; }
.family-row .family-stage { margin-top: 3px; }
.family-row .family-parent { font-size: .85rem; color: var(--text-muted); margin-top: 2px; overflow-wrap: anywhere; }
.family-row button { width: auto; }

/* Teams table on a phone: six columns ran 500px wide in a 300px box, so the
   join code and Remove sat off to the right. Each team stacks into a block. */
@media (max-width: 559px) {
  .teams-table thead { display: none; }
  .teams-table tr {
    display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 6px 12px;
    padding: 12px 0; border-bottom: 1px solid var(--border);
  }
  .teams-table tr:last-child { border-bottom: none; }
  .teams-table td, .teams-table td.num { border: none; padding: 0; text-align: left; }
  .teams-table td:nth-child(1), .teams-table td:nth-child(2), .teams-table td:nth-child(6),
  .teams-table td[colspan] { grid-column: 1 / -1; }
  .teams-table td[data-label]:not(:first-child)::before {
    content: attr(data-label); display: block; font-size: .68rem; font-weight: 700;
    letter-spacing: .05em; text-transform: uppercase; color: var(--text-muted); margin-bottom: 2px;
  }
}

/* Roster table on a phone: five columns ran 435px wide in a 300px box, so
   Last active and Status sat off to the right. Each player stacks into a block. */
@media (max-width: 559px) {
  .roster-table thead { display: none; }
  .roster-table tr {
    display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 6px 12px;
    padding: 12px 0; border-bottom: 1px solid var(--border);
  }
  .roster-table tr:last-child { border-bottom: none; }
  .roster-table td, .roster-table td.num { border: none; padding: 0; text-align: left; }
  .roster-table td:nth-child(1), .roster-table td:nth-child(5),
  .roster-table td[colspan] { grid-column: 1 / -1; }
  .roster-table td[data-label]::before {
    content: attr(data-label); display: block; font-size: .68rem; font-weight: 700;
    letter-spacing: .05em; text-transform: uppercase; color: var(--text-muted); margin-bottom: 2px;
  }
}

/* Roster import preview on a phone: seven columns ran 434px wide in a 302px
   box, so each row's new / update / skip sat off to the right. Name and
   action on the first line, the file's values labelled underneath. */
@media (max-width: 559px) {
  .preview-table thead { display: none; }
  .preview-table tr {
    display: grid; grid-template-columns: 2.2em 2.2em minmax(0, 1.7fr) minmax(0, 1fr) minmax(0, 1fr); gap: 6px 10px;
    padding: 10px 0; border-bottom: 1px solid var(--border);
  }
  .preview-table tr:last-child { border-bottom: none; }
  .preview-table td, .preview-table td.num { border: none; padding: 0; text-align: left; overflow-wrap: break-word; }
  .preview-table td:nth-child(2) { grid-column: 1 / 5; grid-row: 1; }
  .preview-table td:nth-child(7) { grid-column: 5; grid-row: 1; justify-self: end; }
  .preview-table td[data-label]::before {
    content: attr(data-label); display: block; font-size: .68rem; font-weight: 700;
    letter-spacing: .05em; text-transform: uppercase; color: var(--text-muted); margin-bottom: 2px;
  }
}

/* Before-practice card on a phone: three columns squeezed "what to do" into
   a third of the card, a few words a line, and ran past the edge at 360px.
   Name and Not training / Modified / Keep an eye on one line, what to do
   across the full width under them. */
@media (max-width: 559px) {
  .practice-table tr {
    display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 4px 10px;
    align-items: center; padding: 12px 0; border-bottom: 1px solid var(--border);
  }
  .practice-table tr:last-child { border-bottom: none; }
  .practice-table td { border: none; padding: 0; }
  .practice-table td:nth-child(3) { grid-column: 1 / -1; }
}

/* Assignment compliance on a phone: five columns ran 357px wide in a 302px
   box, so Targets met sat off to the right. Name on its own line, sessions,
   reps and off-hand three across under it, targets met full width, each
   with its label. */
@media (max-width: 559px) {
  .compliance thead { display: none; }
  .compliance tr {
    display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 6px 10px;
    padding: 12px 0; border-bottom: 1px solid var(--border);
  }
  .compliance tr:last-child { border-bottom: none; }
  .compliance td, .compliance td.num { border: none; padding: 0; text-align: left; }
  .compliance td:first-child { grid-column: 1 / -1; font-weight: 600; }
  .compliance td:nth-child(5) { grid-column: 1 / -1; }
  .compliance td[data-label]::before {
    content: attr(data-label); display: block; font-size: .68rem; font-weight: 700;
    letter-spacing: .05em; text-transform: uppercase; color: var(--text-muted); margin-bottom: 2px;
  }
}

/* Skill work (ball drills) on a phone: five columns ran 382px wide in a
   302px box, so Drills sat off to the right. Name on its own line, touches,
   sessions and sees-the-ball three across under it, drills full width, each
   with its label. */
@media (max-width: 559px) {
  .ball-table thead { display: none; }
  .ball-table tr {
    display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 6px 10px;
    padding: 12px 0; border-bottom: 1px solid var(--border);
  }
  .ball-table tr:last-child { border-bottom: none; }
  .ball-table td, .ball-table td.num { border: none; padding: 0; text-align: left; }
  .ball-table td:first-child { grid-column: 1 / -1; }
  .ball-table td:nth-child(5) { grid-column: 1 / -1; }
  .ball-table td[data-label]::before {
    content: attr(data-label); display: block; font-size: .68rem; font-weight: 700;
    letter-spacing: .05em; text-transform: uppercase; color: var(--text-muted); margin-bottom: 2px;
  }
}

/* Evaluation export on a phone: five columns ran 410px wide in a 302px box,
   so Form and Trend sat off to the right. Name on its own line, the four
   values two by two under it, each with its label. */
@media (max-width: 559px) {
  .ev-table thead { display: none; }
  .ev-table tr {
    display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 6px 10px;
    padding: 12px 0; border-bottom: 1px solid var(--border);
  }
  .ev-table tr:last-child { border-bottom: none; }
  .ev-table td, .ev-table td.num { border: none; padding: 0; text-align: left; }
  .ev-table td:first-child { grid-column: 1 / -1; font-weight: 600; }
  .ev-table td[data-label]::before {
    content: attr(data-label); display: block; font-size: .68rem; font-weight: 700;
    letter-spacing: .05em; text-transform: uppercase; color: var(--text-muted); margin-bottom: 2px;
  }
}

/* Team standings on a phone: five columns ran 346px wide in a 302px box, so
   Total XP sat off to the right. Rank and team on one line, the three
   numbers under the team name, each with its label. */
@media (max-width: 559px) {
  .standings-table thead { display: none; }
  .standings-table tr {
    display: grid; grid-template-columns: 2.2em minmax(0, 1fr) minmax(0, 1.4fr) minmax(0, 1fr); gap: 6px 10px;
    padding: 12px 0; border-bottom: 1px solid var(--border);
  }
  .standings-table tr:last-child { border-bottom: none; }
  .standings-table td, .standings-table td.num { border: none; padding: 0; text-align: left; }
  .standings-table td:nth-child(2) { grid-column: 2 / -1; }
  .standings-table td.num[data-label] { white-space: nowrap; }
  .standings-table td[colspan] { grid-column: 1 / -1; }
  .standings-table td:nth-child(3) { grid-column-start: 2; }
  .standings-table td[data-label]::before {
    content: attr(data-label); display: block; font-size: .68rem; font-weight: 700;
    letter-spacing: .05em; text-transform: uppercase; color: var(--text-muted); margin-bottom: 2px;
  }
}

/* Coaches card rows and team chips (lost in the v3 re-skin). */
.staff-row {
  display: flex; justify-content: space-between; gap: 10px; align-items: center;
  padding: 10px 0; border-bottom: 1px solid var(--border); flex-wrap: wrap;
}
.staff-row:last-child { border-bottom: none; }
.team-chips { display: flex; gap: 6px; flex-wrap: wrap; align-items: center; }
.team-chip {
  font-size: .72rem; background: var(--surface-2); border: 1px solid var(--border);
  border-radius: 99px; padding: 3px 9px; display: inline-flex; gap: 5px; align-items: center;
}
.team-chip button, .team-chip button:not([class*="btn"]):not(.bell):not(.feel):not(.cue-btn) {
  width: auto; min-height: auto; padding: 0 2px; background: none; border: none;
  box-shadow: none; color: var(--text-muted); font-size: .85rem; line-height: 1;
}
.team-chip button:hover { color: var(--danger); }

/* Small inline forms on the dashboard: label above its field. */
.inline-form { display: flex; gap: 10px; flex-wrap: wrap; align-items: flex-end; }
.inline-form > div { display: flex; flex-direction: column; }
.inline-form label { margin-bottom: 4px; }
.inline-form select[multiple] { min-height: 72px; padding: 4px; }

/* A link styled as a small secondary button (mailto: and the like). */
.btn-link {
  display: inline-flex; align-items: center; justify-content: center;
  padding: 0.5rem 0.9rem; min-height: 38px; font-size: 0.875rem; font-weight: 600;
  background: var(--surface-2); color: var(--text); border: 1px solid var(--border-light);
  border-radius: var(--radius-sm); text-decoration: none; white-space: nowrap;
}
.btn-link:hover { background: var(--surface-3); border-color: var(--accent-dim); }

/* The one button that matters on the capture screen. Pinned to the bottom
   of the phone so it is on screen the moment the camera opens and still
   under the thumb when the kid comes back to end the session -- never
   below a demo figure or a paragraph of hints. */
#view-capture .startstop-dock {
  position: sticky;
  bottom: 0;
  z-index: 5;
  margin: 12px -12px -12px;
  padding: 10px 12px calc(10px + env(safe-area-inset-bottom));
  background: linear-gradient(180deg, transparent 0%, var(--surface) 28%);
}
#startstop {
  min-height: 64px;
  font-size: 1.25rem;
  letter-spacing: 0.02em;
}
#startstop:not(:disabled):not(.danger) { box-shadow: 0 4px 18px rgba(59,130,246,0.45); }
#startstop.danger { background: var(--danger); box-shadow: 0 4px 18px rgba(239,68,68,0.45); }
/* Once recording, the demo figure has done its job; the camera and the
   count are what the kid needs to see, with Finish right under them. */
#view-capture.running .demo { display: none; }

.btn-lg {
  padding: 1rem 1.5rem;
  min-height: 58px;
  font-size: 1.1rem;
}

/* ============================================================
   FORM ELEMENTS — Polished, tappable
   ============================================================ */
.form-group {
  margin-bottom: 1rem;
}

.form-label {
  display: block;
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  margin-bottom: 0.4rem;
}

/* Bare inputs, selects, labels and tables on the dashboard pages. The v3
   re-skin styled only .form-input / .form-label and left every plain
   <input> on coach.html at the browser default. These are the same rules
   the dashboard had before the re-skin, in the new tokens. */
input:not([class]):not([type="checkbox"]):not([type="radio"]):not([type="file"]):not([type="range"]),
select:not([class]) {
  font: inherit; font-size: 1rem; width: 100%; padding: 0.7rem 0.9rem; min-height: 44px;
  background: var(--surface-2); color: var(--text);
  border: 1.5px solid var(--border); border-radius: var(--radius-sm); margin-bottom: 10px;
  -webkit-appearance: none; appearance: none;
}
input:not([class]):focus, select:not([class]):focus { outline: none; border-color: var(--accent); }
label:not([class]) {
  display: block; font-size: 0.8rem; font-weight: 600; color: var(--text-muted);
  text-transform: uppercase; letter-spacing: 0.05em; margin-bottom: 6px;
}
table { width: 100%; border-collapse: collapse; font-size: 0.9rem; }
th, td { text-align: left; padding: 10px 8px; border-bottom: 1px solid var(--border); vertical-align: middle; }
th { color: var(--text-muted); font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.05em; font-weight: 700; }
td.num, th.num { text-align: right; font-variant-numeric: tabular-nums; }
tbody tr:hover { background: var(--surface-2); }

.form-input, .form-select, .form-textarea {
  width: 100%;
  padding: 0.8rem 1rem;
  font-family: var(--font);
  font-size: 1rem;
  color: var(--text);
  background: var(--surface-2);
  border: 1.5px solid var(--border);
  border-radius: var(--radius-sm);
  transition: all 0.15s ease;
  -webkit-appearance: none;
  appearance: none;
}

.form-input:focus, .form-select:focus, .form-textarea:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(59,130,246,0.15);
  background: var(--surface);
}

.form-input::placeholder { color: var(--text-dim); }
.form-input:-webkit-autofill {
  -webkit-box-shadow: 0 0 0 1000px var(--surface-2) inset;
  -webkit-text-fill-color: var(--text);
}

.form-select {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%2394a3b8' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 1rem center;
  padding-right: 2.5rem;
}

.form-textarea {
  resize: vertical;
  min-height: 80px;
}

/* Feeling buttons (capture.html wellness "how do you feel") */
.feel-row {
  display: flex;
  gap: 0.5rem;
  flex-wrap: wrap;
  margin: 0.75rem 0;
}
.feel-btn, .feel {
  display: flex; flex-direction: column; align-items: center; gap: 4px;
  flex: 1;
  min-width: 70px;
  padding: 0.65rem 0.5rem;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--text-muted);
  font-family: var(--font);
  font-size: 0.8rem;
  font-weight: 500;
  cursor: pointer;
  text-align: center;
  transition: all 0.15s ease;
  -webkit-tap-highlight-color: transparent;
}
.feel-btn:hover, .feel:hover { border-color: var(--accent-dim); color: var(--text); }
.feel-btn.selected, .feel.selected {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
  box-shadow: 0 0 12px rgba(59,130,246,0.3);
}
.feel-btn:active, .feel:active { transform: scale(0.96); }

.form-error {
  font-size: 0.8rem;
  color: var(--danger);
  margin-top: 0.4rem;
  display: flex;
  align-items: center;
  gap: 4px;
}

.form-hint {
  font-size: 0.78rem;
  color: var(--text-dim);
  margin-top: 0.3rem;
}

/* ============================================================
   INPUT ROW — Label + input side by side (for compact forms)
   ============================================================ */
.input-row {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 0.75rem;
}

.input-row-label {
  font-size: 0.8rem;
  color: var(--text-muted);
  min-width: 70px;
  flex-shrink: 0;
  font-weight: 500;
}

.input-row input, .input-row select {
  flex: 1;
  padding: 0.7rem 0.9rem;
  font-size: 0.95rem;
  background: var(--surface-2);
  border: 1.5px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--text);
  transition: border-color 0.15s;
}

.input-row input:focus, .input-row select:focus {
  outline: none;
  border-color: var(--accent);
}

/* ============================================================
   DIVIDERS & SECTION HEADERS
   ============================================================ */
.section-divider {
  height: 1px;
  background: var(--border);
  margin: 1.25rem 0;
}

.section-header {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 1rem;
}

.section-header::after {
  content: '';
  flex: 1;
  height: 1px;
  background: var(--border);
}

.section-title {
  font-family: var(--font-condensed);
  font-weight: 700;
  font-size: 1.1rem;
  color: var(--text);
  letter-spacing: -0.01em;
  white-space: nowrap;
}

/* ============================================================
   CARDS — Elevated, with subtle depth
   ============================================================ */
.card-elevated {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 1.25rem;
  margin-bottom: 1rem;
  box-shadow: var(--shadow-md);
}

.card-accent {
  border-left: 3px solid var(--accent);
}

.card-success {
  border-left: 3px solid var(--go);
}

.card-warning {
  border-left: 3px solid var(--warn);
}

.card-danger {
  border-left: 3px solid var(--danger);
}

.card-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 0.75rem;
}

.card-head h3 {
  font-size: 1rem;
  font-weight: 700;
}

.card-head .card-subtitle {
  font-size: 0.78rem;
  color: var(--text-muted);
}

/* ============================================================
   STATS / KPI TILES
   ============================================================ */
.stat-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
  gap: 0.75rem;
}

.stat-tile {
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 1rem;
  text-align: center;
}

.stat-tile .stat-value {
  display: block;
  font-size: 1.8rem;
  font-weight: 800;
  color: var(--text);
  letter-spacing: -0.03em;
  line-height: 1;
  margin-bottom: 0.25rem;
  font-variant-numeric: tabular-nums;
}

.stat-tile .stat-value.accent { color: var(--accent-bright); }
.stat-tile .stat-value.go { color: var(--go); }
.stat-tile .stat-value.warn { color: var(--warn); }
.stat-tile .stat-value.danger { color: var(--danger); }

.stat-tile .stat-label {
  font-size: 0.7rem;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-weight: 600;
}

/* ============================================================
   PROGRESS BARS
   ============================================================ */
.progress-bar {
  height: 8px;
  background: var(--surface-3);
  border-radius: 99px;
  overflow: hidden;
  margin: 0.5rem 0;
}

.progress-bar-fill {
  height: 100%;
  background: linear-gradient(90deg, var(--accent-dim), var(--accent-bright));
  border-radius: 99px;
  transition: width 0.4s ease;
}

.progress-bar-fill.warning { background: linear-gradient(90deg, #d97706, var(--warn)); }
.progress-bar-fill.danger { background: linear-gradient(90deg, var(--danger-dim), var(--danger)); }
.progress-bar-fill.success { background: linear-gradient(90deg, #16a34a, var(--go)); }

/* ============================================================
   BUDGET / PLAN CARDS
   ============================================================ */
.budget-card {
  border-left: 3px solid var(--accent);
  padding: 1rem 1.25rem;
  background: var(--surface);
  border-radius: var(--radius-sm);
  margin-bottom: 0.75rem;
}

.budget-card.building { border-left-color: var(--left); }
.budget-card.full { border-left-color: var(--gold); }
.budget-card.over { border-left-color: var(--warn); }

.budget-header {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 0.5rem;
  flex-wrap: wrap;
}

.budget-header h4 {
  font-size: 0.95rem;
  font-weight: 700;
  margin: 0;
}

.budget-status {
  font-size: 0.72rem;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  font-weight: 600;
}

.budget-bar {
  height: 10px;
  background: var(--surface-3);
  border-radius: 99px;
  overflow: hidden;
  margin: 0.6rem 0;
  position: relative;
}

.budget-bar-fill {
  height: 100%;
  border-radius: 99px;
  transition: width 0.4s ease, background 0.3s;
}

.budget-bar-fill.building { background: linear-gradient(90deg, var(--left), var(--accent-bright)); }
.budget-bar-fill.good { background: linear-gradient(90deg, var(--accent-dim), var(--accent-bright)); }
.budget-bar-fill.full { background: linear-gradient(90deg, #d97706, var(--gold)); }
.budget-bar-fill.over { background: linear-gradient(90deg, var(--danger-dim), var(--danger)); }

.budget-detail {
  font-size: 0.85rem;
  line-height: 1.5;
  color: var(--text-muted);
  margin-top: 0.3rem;
}

/* ============================================================
   FILM / IQ CLIPS
   ============================================================ */
.iq-clip {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 1rem;
  margin-bottom: 0.75rem;
  transition: border-color 0.15s;
}

.iq-clip:hover { border-color: var(--border-light); }

.iq-clip-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 0.5rem;
}

.iq-clip-title {
  font-weight: 700;
  font-size: 0.9rem;
  color: var(--text);
  line-height: 1.3;
}

.iq-clip-status {
  font-size: 0.7rem;
  padding: 0.2rem 0.6rem;
  border-radius: 99px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  flex-shrink: 0;
}

.iq-clip-status.watched { background: rgba(34,197,94,0.15); color: var(--go); }
.iq-clip-status.partial { background: rgba(245,158,11,0.15); color: var(--warn); }
.iq-clip-status.unwatched { background: rgba(148,163,184,0.15); color: var(--text-muted); }

.iq-clip-focus {
  font-size: 0.8rem;
  color: var(--text-muted);
  margin-bottom: 0.6rem;
  line-height: 1.4;
}

.iq-clip-bar {
  height: 4px;
  background: var(--surface-3);
  border-radius: 99px;
  overflow: hidden;
  margin: 0.5rem 0;
}

.iq-clip-bar-fill {
  height: 100%;
  background: var(--accent);
  border-radius: 99px;
}

.iq-clip-question {
  font-size: 0.82rem;
  color: var(--text-muted);
  padding-top: 0.5rem;
  border-top: 1px solid var(--border);
  margin-top: 0.5rem;
}

.iq-clip-question strong {
  color: var(--text);
}

/* ============================================================
   TRAINING STAGE (camera view)
   ============================================================ */
.stage {
  position: relative;
  background: #000;
  border-radius: var(--radius);
  overflow: hidden;
  aspect-ratio: 3/4;
  box-shadow: var(--shadow-lg);
}

.stage video, .stage canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.stage video { transform: scaleX(-1); }
.stage canvas { transform: scaleX(-1); }

.stage-hud {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  padding: 1rem 1.25rem;
  background: linear-gradient(0deg, rgba(0,0,0,0.85) 0%, transparent 100%);
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 12px;
}

.rep-count {
  font-size: 3.5rem;
  font-weight: 800;
  line-height: 1;
  letter-spacing: -0.04em;
  color: #fff;
  text-shadow: 0 2px 8px rgba(0,0,0,0.5);
}

.rep-count small {
  display: block;
  font-size: 0.85rem;
  font-weight: 500;
  color: var(--text-muted);
  letter-spacing: 0;
  margin-top: 2px;
}

.hands-row {
  display: flex;
  gap: 8px;
}

.hand-chip {
  background: rgba(0,0,0,0.6);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 0.4rem 0.7rem;
  text-align: center;
  min-width: 60px;
  backdrop-filter: blur(4px);
}

.hand-chip b {
  display: block;
  font-size: 1.3rem;
  font-weight: 800;
  line-height: 1.1;
  color: #fff;
}

.hand-chip.left b { color: var(--left); }
.hand-chip.right b { color: var(--right); }

.hand-chip span {
  display: block;
  font-size: 0.6rem;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  margin-top: 1px;
}

/* Cue grid for cued drills */
.cue-overlay {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 12px;
  pointer-events: none;
}

.cue-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: repeat(3, 1fr);
  gap: 5px;
  width: 55%;
  max-width: 220px;
  aspect-ratio: 1/1.05;
}

.cue-cell {
  border: 2px solid rgba(255,255,255,0.15);
  border-radius: 10px;
  transition: all 0.08s ease;
}

.cue-cell.lit {
  background: var(--accent);
  border-color: #fff;
  box-shadow: 0 0 24px rgba(59,130,246,0.4);
}

.cue-word {
  font-size: 1.3rem;
  font-weight: 800;
  line-height: 1.15;
  text-align: center;
  text-transform: uppercase;
  letter-spacing: 0.01em;
  background: rgba(0,0,0,0.7);
  padding: 0.5rem 0.9rem;
  border-radius: var(--radius-sm);
  max-width: 80%;
  color: #fff;
}

.cue-word.waiting {
  font-size: 0.9rem;
  font-weight: 600;
  text-transform: none;
  color: var(--text-muted);
}

/* ============================================================
   ALERTS / STATUS
   ============================================================ */
.conn-status {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 0.5rem 0.75rem;
  border-radius: var(--radius-sm);
  font-size: 0.78rem;
  font-weight: 500;
  margin-bottom: 0.75rem;
  background: var(--surface-2);
  border: 1px solid var(--border);
}

.conn-status.connected { color: var(--go); border-color: rgba(34,197,94,0.3); }
.conn-status.connected .dot { background: var(--go); box-shadow: 0 0 6px rgba(34,197,94,0.4); }

.conn-status.offline { color: var(--warn); border-color: rgba(245,158,11,0.3); }
.conn-status.offline .dot { background: var(--warn); }

.conn-status.syncing { color: var(--accent-bright); border-color: rgba(59,130,246,0.3); }
.conn-status.syncing .dot {
  background: var(--accent-bright);
  animation: pulse-dot 1s ease-in-out infinite;
}

@keyframes pulse-dot {
  0%, 100% { opacity: 1; transform: scale(1); }
  50% { opacity: 0.5; transform: scale(0.8); }
}

.conn-status .dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  flex-shrink: 0;
}

/* ============================================================
   NOTIFICATIONS
   ============================================================ */
.notif-list { display: flex; flex-direction: column; }

.notif {
  display: flex;
  gap: 10px;
  align-items: flex-start;
  padding: 0.75rem 0;
  border-bottom: 1px solid var(--border);
}

.notif:last-child { border-bottom: none; }
.notif.unread { padding-left: 0.75rem; border-left: 2px solid var(--accent); margin-left: -0.75rem; }

.notif-icon {
  width: 32px;
  height: 32px;
  border-radius: 8px;
  background: var(--surface-2);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1rem;
  flex-shrink: 0;
  color: var(--accent-bright);
}

.notif-content { flex: 1; min-width: 0; }
.notif-title { font-size: 0.88rem; font-weight: 600; color: var(--text); margin-bottom: 2px; }
.notif-text { font-size: 0.8rem; color: var(--text-muted); line-height: 1.4; }
.notif-time { font-size: 0.7rem; color: var(--text-dim); margin-top: 3px; }

/* ============================================================
   DRILL LIST
   ============================================================ */
.drill-list { display: flex; flex-direction: column; gap: 0.5rem; }

.drill-item {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 0.85rem 1rem;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  cursor: pointer;
  transition: all 0.15s;
  text-align: left;
  width: 100%;
  border: none;
  font-family: var(--font);
  color: var(--text);
}

.drill-item:hover { border-color: var(--border-light); background: var(--surface-3); }
.drill-item:active { transform: scale(0.99); }

.drill-item-icon {
  width: 40px;
  height: 40px;
  border-radius: 10px;
  background: var(--surface);
  border: 1px solid var(--border);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.2rem;
  flex-shrink: 0;
}

.drill-item-info { flex: 1; min-width: 0; }
.drill-item-name { font-weight: 600; font-size: 0.92rem; }
.drill-item-desc { font-size: 0.75rem; color: var(--text-muted); margin-top: 2px; }

.drill-item-target {
  font-size: 0.72rem;
  color: var(--text-dim);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* ============================================================
   ASSIGNMENTS
   ============================================================ */
.assignment-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius-sm);
  padding: 1rem;
  margin-bottom: 0.6rem;
}

.assignment-card.done { opacity: 0.7; border-left-color: var(--go); }
.assignment-card.overdue { border-left-color: var(--danger); }

.assignment-card h4 {
  margin: 0 0 4px;
  font-size: 0.92rem;
  font-weight: 700;
}

.assignment-card .assignment-meta {
  font-size: 0.72rem;
  color: var(--text-muted);
  margin-bottom: 0.6rem;
}

.target-row {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
}

.target-pill {
  flex: 1;
  min-width: 80px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 0.5rem 0.7rem;
  text-align: center;
}

.target-pill b {
  display: block;
  font-size: 1rem;
  font-weight: 700;
  color: var(--text);
  font-variant-numeric: tabular-nums;
  line-height: 1.2;
}

.target-pill span {
  font-size: 0.62rem;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.target-pill.met b { color: var(--go); }
.target-pill.unmet b { color: var(--warn); }

/* ============================================================
   BELL / NOTIFICATION BUTTON
   ============================================================ */
.bell-btn, .bell {
  position: relative;
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 0.5rem 0.75rem;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--text);
  font-size: 0.85rem;
  font-weight: 500;
  cursor: pointer;
  transition: all 0.15s;
  min-height: auto;
}

.bell-btn:hover, .bell:hover { border-color: var(--border-light); }
.bell-btn .badge, .bell .dot {
  position: absolute;
  top: -5px;
  right: -5px;
  min-width: 18px;
  height: 18px;
  background: var(--danger);
  color: #fff;
  font-size: 0.62rem;
  font-weight: 700;
  border-radius: 99px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 4px;
  border: 2px solid var(--surface);
}

/* ============================================================
   APP SHELL — For pages with nav tabs
   ============================================================ */
.app-shell {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  min-height: 100dvh;
}

.app-nav {
  display: flex;
  background: var(--surface);
  border-top: 1px solid var(--border);
  padding: 0.5rem 0;
  justify-content: space-around;
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  z-index: 100;
}

.app-nav-btn {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
  padding: 0.4rem 0.8rem;
  background: none;
  border: none;
  color: var(--text-dim);
  font-size: 0.65rem;
  font-weight: 500;
  cursor: pointer;
  transition: color 0.15s;
  text-decoration: none;
  min-height: auto;
}

.app-nav-btn.active { color: var(--accent-bright); }
.app-nav-btn.active .nav-icon { color: var(--accent-bright); }
.app-nav-btn .nav-icon {
  font-size: 1.3rem;
  line-height: 1;
}

/* ============================================================
   MISC
   ============================================================ */
.hide-scrollbar { scrollbar-width: none; }
.hide-scrollbar::-webkit-scrollbar { display: none; }

/* Coach sub-card headers — consistent section-header pattern */
.coach-card-header {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 10px;
  padding-bottom: 0.5rem;
  border-bottom: 1px solid var(--border);
  margin-bottom: 0.75rem;
}
.coach-card-header h2 {
  margin: 0;
  font-size: 1.15rem;
  font-weight: 700;
  color: var(--text);
}

.badge-tag {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 0.2rem 0.6rem;
  border-radius: 99px;
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.02em;
}

.badge-tag.accent { background: rgba(59,130,246,0.12); color: var(--accent-bright); }
.badge-tag.go { background: rgba(34,197,94,0.12); color: var(--go); }
.badge-tag.warn { background: rgba(245,158,11,0.12); color: var(--warn); }
.badge-tag.danger { background: rgba(239,68,68,0.12); color: var(--danger); }
.badge-tag.muted { background: rgba(148,163,184,0.12); color: var(--text-muted); }

.avatar {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: var(--surface-2);
  border: 2px solid var(--border);
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 700;
  font-size: 1rem;
  color: var(--accent-bright);
  flex-shrink: 0;
}

.avatar-sm { width: 32px; height: 32px; font-size: 0.8rem; }
.avatar-lg { width: 56px; height: 56px; font-size: 1.3rem; }

.privacy-note {
  font-size: 0.78rem;
  color: var(--text-muted);
  background: var(--surface-2);
  border-left: 2px solid var(--accent);
  padding: 0.6rem 0.8rem;
  margin: 0.75rem 0;
  line-height: 1.5;
}

/* Details/collapsible panels (used in capture.html wellness) */
.details-block { margin-top: 1rem; }
.details-toggle {
  background: var(--surface-2);
  color: var(--text);
  border: 1px solid var(--border-light);
  border-radius: var(--radius-sm);
  padding: 0.65rem 1rem;
  font-family: var(--font);
  font-size: 0.875rem;
  font-weight: 500;
  cursor: pointer;
  transition: background 0.15s, border-color 0.15s;
  width: 100%;
  -webkit-tap-highlight-color: transparent;
}
.details-toggle:hover { background: var(--surface-3); border-color: var(--accent-dim); }
.details-toggle:active { transform: scale(0.98); }
.details-panel {
  padding: 0.75rem;
  background: var(--surface-2);
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  margin-top: 0.5rem;
}
/* The one every page relies on to reveal a panel only when it applies --
   coach.html alone uses it ninety times. Losing it did not break a layout,
   it showed every conditional card at once: the week plan, the team goal
   and the notifications all on screen before there was anything in them. */
.hidden { display: none !important; }

.details-panel.hidden { display: none; }

/* ============================================================
   SPONSOR SLOTS — placeholder branding areas
   data-sponsor-level: app | athlete | parent | coach
   Populate .sponsor-logo with an <img> and .sponsor-text
   with the sponsor name; hide the whole slot when empty.
   ============================================================ */
/* A small form: two columns on a desktop, one on a phone. */
.form-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px 16px; margin-top: 10px; }
.form-grid label { display: block; margin-bottom: 4px; }
@media (max-width: 640px) { .form-grid { grid-template-columns: minmax(0, 1fr); } }

/* Where does the roster live: four big buttons, one active. */
.source-pick { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 10px; margin: 12px 0 16px; }
.source-btn {
  display: flex; flex-direction: column; align-items: flex-start; gap: 4px; text-align: left;
  padding: 14px; min-height: 76px; background: var(--surface-2); color: var(--text);
  border: 2px solid var(--border); border-radius: var(--radius); cursor: pointer;
}
.source-btn b { font-size: 1rem; }
.source-btn span { font-size: .78rem; color: var(--text-muted); line-height: 1.3; }
.source-btn:hover { border-color: var(--accent); }
.source-btn.active { border-color: var(--accent); background: var(--surface); box-shadow: inset 0 0 0 1px var(--accent); }
@media (max-width: 760px) { .source-pick { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .source-pick .source-btn:last-child { grid-column: 1 / -1; } }
.src-panel { margin-top: 4px; }
/* The one we recommend: always outlined, with a flag, so a director who is
   unsure which to pick has an answer. Active still reads as selected. */
.source-btn { position: relative; }
.source-btn--easiest { border-color: var(--accent); }
.source-btn--easiest.active { box-shadow: 0 0 0 3px rgba(10, 132, 255, 0.35), inset 0 0 0 1px var(--accent); }
.source-flag {
  position: absolute; top: -10px; right: 12px; font-style: normal;
  background: var(--accent); color: #fff; font-size: .68rem; font-weight: 700;
  letter-spacing: .08em; text-transform: uppercase; padding: 2px 9px; border-radius: 999px;
}


/* The roster drop box. A real target: dashed, big, obviously a place to
   put a file, with a Browse button for anyone who would rather click. */
.dropzone {
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  border: 2px dashed var(--border-light, var(--border)); border-radius: var(--radius);
  padding: 28px 18px; text-align: center; cursor: pointer;
  background: var(--surface-2);
  transition: border-color .15s ease, background .15s ease;
}
.dropzone:hover, .dropzone:focus-visible, .dropzone.over { border-color: var(--accent); background: var(--surface); outline: none; }
.dropzone.over { box-shadow: inset 0 0 0 2px var(--accent); }
.dropzone-icon { font-size: 2rem; line-height: 1; color: var(--accent); }
.dropzone b { font-size: 1.05rem; }
.dropzone span { font-size: .8rem; color: var(--text-muted); }
.dropzone .dropzone-or { text-transform: uppercase; letter-spacing: .1em; font-size: .7rem; }
.dropzone button { margin-top: 2px; }

/* Setup walkthrough: while it is on, the rest of the dashboard waits. The
   embedded card loses its own frame so the step reads as one thing. */
/* One rule for every role's walkthrough (#wizard director, #pwizard
   parent, #awizard athlete): while it is on, every other top-level thing
   in the page waits. */
body.wizard-on .wrap > :not(#wizard):not(#pwizard):not(#awizard):not(#err) { display: none !important; }
body.wizard-on #wizard, body.wizard-on #pwizard, body.wizard-on #awizard { grid-column: 1 / -1; }
#pwizard-next:disabled { opacity: 0.45; cursor: not-allowed; }
.wizard-embedded { border: none; background: transparent; padding: 0; margin: 0; box-shadow: none; }
.wizard-embedded > h2:first-child,
.wizard-embedded > h2:first-child + p.small.muted { display: none; }
#wizard-next:disabled { opacity: 0.45; cursor: not-allowed; }

/* Landing page on a laptop: brand and the four role buttons on the left,
   the chosen role's form on the right, nothing to scroll. On a phone the
   two columns stack and it is the one-screen page. */
.landing-empty { display: none; }
@media (min-width: 900px) {
  main.landing.wrap--narrow { max-width: 1100px; }
  main.landing {
    display: grid;
    grid-template-columns: minmax(0, 5fr) minmax(0, 6fr);
    gap: 28px;
    align-items: start;
    padding-top: 28px;
  }
  .landing-hero { text-align: left !important; padding: 1.5rem 1.5rem 1.25rem !important; }
  .landing-hero h1 { font-size: 2rem !important; line-height: 1.1; }
  .landing-hero p { font-size: 0.95rem; }
  .landing .role-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .landing .role-btn { min-height: 108px; }
  .landing-right { position: sticky; top: 84px; min-height: 420px; }
  .landing-empty {
    display: flex; align-items: center; justify-content: center;
    min-height: 420px;
    border: 1px dashed var(--border);
    border-radius: var(--radius);
    color: var(--text-muted);
  }
  .landing-empty-inner { display: flex; flex-direction: column; align-items: center; gap: 6px; max-width: 320px; text-align: center; }
  .landing-empty-inner b { color: var(--text); font-family: var(--font-condensed); font-size: 1.3rem; }
  .landing .role-panel { margin-top: 0; }
}

/* Landing page: four role buttons, one panel open at a time. */
.role-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px;
  margin: 14px 0 6px;
}
.role-btn {
  display: flex; flex-direction: column; align-items: flex-start; gap: 2px;
  padding: 14px 14px 12px;
  min-height: 92px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  color: var(--text);
  text-align: left;
  cursor: pointer;
  width: 100%;
  font: inherit;
  transition: border-color 120ms, background 120ms, transform 120ms;
}
.role-btn:hover { border-color: var(--accent); }
.role-btn:active { transform: scale(0.985); }
.role-btn.active { border-color: var(--accent); background: var(--surface-2); box-shadow: inset 0 0 0 1px var(--accent); }
.role-btn .role-icon { font-size: 1.5rem; line-height: 1; margin-bottom: 4px; }
.role-btn b { font-family: var(--font-condensed); font-size: 1.15rem; letter-spacing: 0.01em; }
.role-btn > span:last-child { font-size: 0.8rem; color: var(--text-muted); }
.role-panel { margin-top: 12px; }
@media (min-width: 600px) { .role-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); } }

.sponsor-slot:not(.has-sponsor) { display: none; }
.sponsor-slot {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 0.6rem 1rem;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  margin: 0.75rem 0;
}
.sponsor-slot.hidden { display: none; }

.sponsor-logo {
  width: 36px;
  height: 36px;
  border-radius: 6px;
  background: var(--surface-3);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  overflow: hidden;
}
.sponsor-logo img {
  width: 100%;
  height: 100%;
  object-fit: contain;
}

.sponsor-text {
  font-size: 0.82rem;
  color: var(--text-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* App-level slot sits just below the topbar masthead. */
.sponsor-slot[data-sponsor-level="app"] {
  margin: 0.5rem 0 0.75rem;
}

/* Athlete-level slot sits inside capture.html bottom card. */
.sponsor-slot[data-sponsor-level="athlete"] {
  margin-top: 0.75rem;
  justify-content: center;
  text-align: center;
}
.sponsor-slot[data-sponsor-level="athlete"] .sponsor-text {
  display: block;
  text-align: center;
}

/* Parent-level slot sits inside parent.html wrap. */
.sponsor-slot[data-sponsor-level="parent"] {
  margin: 0.75rem 0;
}

/* Coach-level slot sits inside coach.html staff card area. */
.sponsor-slot[data-sponsor-level="coach"] {
  margin-top: 0.75rem;
  justify-content: center;
  text-align: center;
}
.sponsor-slot[data-sponsor-level="coach"] .sponsor-text {
  display: block;
  text-align: center;
}

.details-toggle:hover { background: var(--surface-3); border-color: var(--accent-dim); }

.emoji { font-size: 1.2em; }

/* ============================================================
   RESPONSIVE — Phone-first adaptations
   ============================================================ */
@media (max-width: 420px) {
  .card { padding: 1rem; }
  .group-row { gap: 0.25rem; }
  .btn { padding: 0.7rem 1rem; }
}

@media (min-width: 600px) {
  .card { padding: 1.5rem; }
}

/* ============================================================
   MEDIA QUERIES
   ============================================================ */
@media (max-width: 480px) {
  .wrap { padding: 0 12px 70px; }
  h1 { font-size: 1.8rem; }
  h2 { font-size: 1.3rem; }
  .btn { min-height: 48px; padding: 0.7rem 1rem; }
  .stat-grid { grid-template-columns: repeat(2, 1fr); }
  .topbar-title { font-size: 1.1rem; }
}

@media (min-width: 768px) {
  .wrap { padding: 0 24px 100px; }
  .card { padding: 1.5rem; }
  h1 { font-size: 2.5rem; }
  h2 { font-size: 1.7rem; }
}


/* ---- The club header on a phone -------------------------------------- */
@media (max-width: 560px) {
  .club-badge { height: 44px; max-width: 124px; }
  .mast-left, .masthead { gap: 9px; }
  .club-name { font-size: 1rem; }
  .role { display: none; }
  /* An athlete knows their own name; the crest does not fit beside it, and
     between the two the club's mark is the one worth the room. */
  #whoami { display: none; }
}
/* Below about 430px a 120px lockup, a legible crest and a control cannot
   share one row, so the bar wraps: marks first, the crest centred across
   the second row at a size that still reads. */
@media (max-width: 430px) {
  .topbar {
    grid-template-columns: auto minmax(0, 1fr);
    grid-template-areas: "left right" "centre centre";
    row-gap: 6px;
    /* Keep the status-bar inset the base rule adds: this phone-width rule
       used to replace the whole padding and put the clock on the logo. */
    padding: calc(10px + env(safe-area-inset-top, 0px)) calc(14px + env(safe-area-inset-right, 0px)) 10px calc(14px + env(safe-area-inset-left, 0px));
  }
  .mast-left { grid-area: left; }
  .club-badge, .club-name { grid-area: centre; justify-self: center; }
  .topbar > #masthead ~ * { grid-area: right; }
  .club-badge { height: 46px; max-width: 70vw; }
}


/* ---- Assignment targets ----------------------------------------------
   This column was three unlabelled letters told apart only by colour.
   Named now, and met/unmet differ by glyph and border as well as hue so
   the state survives a printout and a coach who cannot separate the two. */
.marks { display: flex; gap: 5px; flex-wrap: wrap; }
.mark {
  font-size: .72rem; padding: 2px 8px; border-radius: 999px;
  white-space: nowrap; line-height: 1.5;
}
.mark.met { color: var(--go); border: 1px solid var(--go); }
.mark.unmet { color: var(--muted); border: 1px dashed var(--border); }

/* ---- Film IQ coverage ------------------------------------------------ */
.iq-clip {
  border: 1px solid var(--border); border-radius: 11px;
  padding: 13px 14px; margin-bottom: 11px;
}
.iq-head {
  display: flex; justify-content: space-between; align-items: baseline;
  gap: 12px; flex-wrap: wrap;
}
/* How far a clip has reached, before any names are read. */
.iq-bar {
  height: 4px; border-radius: 2px; background: var(--border);
  margin: 10px 0 12px; overflow: hidden;
}
.iq-bar span { display: block; height: 100%; background: var(--accent); }
.who-row {
  display: flex; align-items: baseline; gap: 6px; flex-wrap: wrap;
  margin-top: 7px;
}
.who-label {
  font-size: .66rem; letter-spacing: .1em; text-transform: uppercase;
  color: var(--muted); min-width: 62px;
}
/* Three states told apart by border and weight as well as colour. */
.who {
  font-size: .76rem; padding: 2px 9px; border-radius: 999px;
  white-space: nowrap; border: 1px solid transparent;
}
.who.done { color: var(--go); border-color: var(--go); }
.who.part { color: var(--warn); border-color: var(--warn); border-style: dashed; }
.who.none { color: var(--muted); border-color: var(--border); border-style: dotted; }
.who .again { margin-left: 5px; opacity: .8; font-size: .9em; }

/* Squad label on a leaderboard row. A cohort board mixes two squads from the
   same birth year, so the row has to say which one without the reader
   working it out from the names. */
.squad {
  display: inline-block;
  margin-left: 6px;
  padding: 1px 7px;
  border-radius: 999px;
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  vertical-align: 2px;
  color: var(--muted);
  border: 1px solid var(--border);
}
.squad--red   { color: #E88;     border-color: #7A3B3B; background: rgba(196,65,63,0.12); }
.squad--blue  { color: #7FBEF5; border-color: #2C5A80; background: rgba(0,139,253,0.12); }
.squad--white { color: #E4ECF4; border-color: #55657A; background: rgba(228,236,244,0.10); }
.squad--black { color: #A9B7C6; border-color: #3C4757; background: rgba(20,26,34,0.55); }
.squad--green { color: #6FD69B; border-color: #2A6B48; background: rgba(18,161,80,0.12); }
.squad--gold  { color: #E7B45A; border-color: #7A5A22; background: rgba(199,119,0,0.14); }

/* Your own child's row on the cohort board. A parent scanning two squads of
   names needs to find theirs without reading every line. */
tr.mine { background: rgba(0, 139, 253, 0.10); }
tr.mine td { border-color: var(--accent-dim); }

/* ---------------------------------------------------------------
   TRAINING LOAD GAUGE

   The markup for this shipped without any styles at all, so the
   athlete's workload gauge rendered as three words concatenated
   against the left edge ("easiersteadysharp jump") with no track,
   no steady band, and no marker. It is the one number on the home
   screen that is about not getting hurt, so it has to read.

   The track runs 0 to 2 on the acute:chronic ratio. The shaded
   band is the steady range, and the marker is where this athlete
   actually sits.
   --------------------------------------------------------------- */
.gauge {
  position: relative;
  margin: 14px 0 26px;
  padding-top: 2px;
}
.gauge-track {
  position: relative;
  height: 6px;
  border-radius: 999px;
  background: var(--border);
  overflow: hidden;
}
.gauge-safe {
  position: absolute;
  top: 0;
  height: 100%;
  background: var(--go);
  opacity: 0.55;
}
.gauge-mark {
  position: absolute;
  top: 0;
  width: 3px;
  height: 14px;
  margin-left: -1.5px;
  border-radius: 2px;
  background: var(--text);
}
.gauge-mark.elevated { background: var(--warn); }
.gauge-mark.high     { background: var(--danger); }
.gauge-scale {
  display: flex;
  justify-content: space-between;
  margin-top: 9px;
  font-size: 0.7rem;
  letter-spacing: 0.04em;
  color: var(--text-dim);
}

/* ---------------------------------------------------------------
   THE REST OF THE TRAINING-LOAD AND BUDGET CARD

   These classes were in the markup with no rules behind them, so
   the athlete's home screen rendered a scale as "075 min for a
   good week" (the zero and the target with nothing between them),
   advisories at body size with an invisible bullet, and the zone
   label as plain text. All of it is the wellbeing half of the
   screen, which is the half that has to be legible.
   --------------------------------------------------------------- */
.budget-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  flex-wrap: wrap;
}
.budget-head span {
  font-size: 0.8rem;
  color: var(--text-dim);
}
.budget-scale {
  display: flex;
  justify-content: space-between;
  font-size: 0.72rem;
  color: var(--text-dim);
  margin-top: 2px;
}
.budget-bar .ceiling {
  position: absolute;
  top: -2px;
  width: 2px;
  height: calc(100% + 4px);
  background: var(--text-dim);
  opacity: 0.7;
}

.load-zone {
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 3px 9px;
  border-radius: 999px;
  border: 1px solid var(--border);
  color: var(--text-muted);
}
.load-zone.optimal    { color: var(--go);     border-color: #1C5E3A; background: rgba(18,161,80,0.12); }
.load-zone.elevated   { color: #E39A2B;       border-color: #6B4A16; background: rgba(199,119,0,0.12); }
.load-zone.high       { color: var(--danger); border-color: #6E2C28; background: rgba(221,90,80,0.12); }
.load-zone.detraining { color: var(--text-dim); }

/* An advisory is a sentence about this athlete's body. It reads as a note,
   not as a headline, because the headline is the number above it. */
.advisory {
  display: flex;
  gap: 9px;
  align-items: flex-start;
  font-size: 0.9rem;
  line-height: 1.5;
  color: var(--text-muted);
  margin-top: 10px;
}
.advisory em {
  display: block;
  font-style: normal;
  font-size: 0.82rem;
  color: var(--text-dim);
  margin-top: 2px;
}
.advisory .dotmark {
  flex: none;
  width: 7px;
  height: 7px;
  margin-top: 7px;
  border-radius: 50%;
  background: var(--text-dim);
}
.advisory.info .dotmark    { background: var(--accent); }
.advisory.caution .dotmark { background: var(--warn); }
.advisory.warning .dotmark { background: var(--danger); }
.advisory.warning { color: var(--text); }

/* ---------------------------------------------------------------
   THE DRILL PICKER AND THE STAT ROW

   Two more blocks whose markup shipped without rules. The picker
   is the screen an athlete opens to train, and it was rendering as
   default grey browser buttons with centre-aligned paragraphs. The
   stat row ran its number straight into its label, so a streak
   read "35Day streak".
   --------------------------------------------------------------- */
.drill-btn {
  display: block;
  width: 100%;
  text-align: left;
  font: inherit;
  cursor: pointer;
  margin-top: 9px;
  padding: 13px 15px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  border-left: 3px solid var(--accent);
  background: var(--surface);
  color: var(--text);
  transition: border-color 0.15s, background 0.15s, transform 0.1s;
}
.drill-btn:hover { background: var(--surface-2, var(--surface)); border-color: var(--border-light); }
.drill-btn:active { transform: translateY(1px); }
.drill-btn b {
  display: block;
  font-family: var(--font-condensed);
  font-size: 1.15rem;
  font-weight: 600;
  line-height: 1.15;
}
.drill-btn span {
  display: block;
  margin-top: 4px;
  font-size: 0.88rem;
  line-height: 1.45;
  color: var(--text-muted);
}
.drill-btn .transfer-inline { color: var(--text-dim); font-size: 0.8rem; }
.drill-btn .held-note { color: var(--warn); font-size: 0.8rem; }
/* A drill an athlete cannot start right now still shows, with its reason. */
.drill-btn.held { border-left-color: var(--warn); opacity: 0.75; }

.stat-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(84px, 1fr));
  gap: 12px;
}
/* Four numbers do not fit across a phone; auto-fit left the fourth alone
   on its own line. Two by two reads as one block. */
@media (max-width: 559px) {
  .stat-row:has(> .stat:nth-child(4):last-child) { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
/* The dashboard strip sits between two cards; give it the cards' gap. */
#summary.stat-row { margin-bottom: 1rem; }
.stat b {
  display: block;
  font-family: var(--font-condensed);
  font-size: 1.5rem;
  font-weight: 700;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}
.stat span {
  display: block;
  margin-top: 3px;
  font-size: 0.68rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-dim);
}

/* ---------------------------------------------------------------
   DRILL LIBRARY

   A hundred rows a coach scans to decide what their athletes are
   offered, so the row has to be readable at a glance and the
   checkbox has to be the obvious thing to hit on a phone.
   --------------------------------------------------------------- */
.lib-row {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 10px;
  padding: 9px 0;
  border-bottom: 1px solid var(--border);
}
.lib-row:last-child { border-bottom: 0; }
.lib-toggle {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  cursor: pointer;
  margin: 0;
  text-transform: none;
  letter-spacing: normal;
  font-size: inherit;
  color: inherit;
}
.lib-toggle input { flex: none; width: 18px; height: 18px; margin-top: 2px; }
.lib-toggle b { font-weight: 600; }
.lib-toggle .small { display: block; margin-top: 2px; }
.lib-tag {
  display: inline-block;
  margin-left: 6px;
  padding: 1px 7px;
  border-radius: 999px;
  border: 1px solid var(--border);
  font-size: 0.68rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-dim);
  vertical-align: 1px;
}
.lib-tag.alt { color: var(--accent); border-color: var(--accent-dim); }

/* Rhythm strip on a session counted by ear: one tick per rep across the
   session in the brand's hand colours, with the stops shaded behind. */
.rh-strip {
  position: relative;
  height: 34px;
  background: var(--surface-3);
  border-radius: var(--radius-sm);
  overflow: hidden;
}
.rh-tick {
  position: absolute;
  top: 6px;
  bottom: 6px;
  width: 2px;
  margin-left: -1px;
  border-radius: 1px;
  background: var(--text-dim);
}
.rh-tick.rh-l { background: var(--left); }
.rh-tick.rh-r { background: var(--right); }
.rh-stop {
  position: absolute;
  top: 0;
  bottom: 0;
  background: rgba(199, 119, 0, 0.22);
  border-left: 1px solid var(--warn);
  border-right: 1px solid var(--warn);
}
.rh-legend { display: flex; gap: 14px; margin: 6px 0 2px; }
.rh-legend i {
  display: inline-block;
  width: 10px;
  height: 10px;
  border-radius: 2px;
  margin-right: 5px;
  vertical-align: -1px;
}
.rh-legend .rh-l { background: var(--left); }
.rh-legend .rh-r { background: var(--right); }
.rh-legend .rh-stop-key { background: rgba(199, 119, 0, 0.45); }

/* Shot speed: one bar per shot, height relative to the session's best.
   Untimed shots show as a short grey stub so the count still reads right. */
.sp-bars {
  display: flex;
  align-items: flex-end;
  gap: 3px;
  height: 64px;
  margin-top: 10px;
  padding: 6px;
  background: var(--surface-3);
  border-radius: var(--radius-sm);
}
.sp-bar {
  flex: 1;
  min-width: 3px;
  background: var(--accent);
  border-radius: 2px 2px 0 0;
}
.sp-bar.sp-none { height: 6%; background: var(--text-dim); opacity: .5; }

/* Shot-speed percentile: a single marker on a bar. No other athletes drawn. */
.pct-card { margin-top: 8px; padding: 10px 12px; border-radius: var(--radius-sm);
            background: var(--surface-3); }
.pct-row { margin-top: 8px; }
.pct-bar { position: relative; height: 8px; margin-top: 6px; border-radius: 4px;
           background: linear-gradient(90deg, var(--surface-2), var(--accent-dim)); }
.pct-bar i { position: absolute; top: -4px; width: 4px; height: 16px; margin-left: -2px;
             border-radius: 2px; background: var(--text); }

/* Small links to the policy, on the pages a stranger can reach. */
.legal-links { text-align: center; margin: 1.5rem 0 1rem; font-size: .8rem; }
.legal-links a { color: var(--text-muted); text-decoration: underline; }

/* App shell: keep content clear of the home indicator and the notch. */
body { padding-bottom: env(safe-area-inset-bottom, 0px); }

/* Folding cards: the director and coach pages are long, so every card shows only
   its heading until it is clicked. A card the walkthrough has pulled into itself
   (.wizard-embedded) is never folded: that step needs it open. */
.fold > .fold-head { cursor: pointer; user-select: none; }
/* The heading is either the h2 itself or a row that holds one. */
.fold > h2.fold-head,
.fold > .fold-head h2 { display: flex; align-items: center; gap: 8px; }
.fold > h2.fold-head::after,
.fold > .fold-head h2::after {
  content: ""; margin-left: auto; flex: 0 0 auto;
  width: 8px; height: 8px;
  border-right: 2px solid var(--text-muted); border-bottom: 2px solid var(--text-muted);
  transform: rotate(45deg); transition: transform .15s ease;
}
.fold.open > h2.fold-head::after,
.fold.open > .fold-head h2::after { transform: rotate(-135deg); }
.fold > .fold-head:focus-visible { outline: 2px solid var(--accent); outline-offset: 4px; border-radius: 6px; }
.fold:not(.open):not(.wizard-embedded) > .fold-item { display: none !important; }
.fold.wizard-embedded > h2.fold-head::after,
.fold.wizard-embedded > .fold-head h2::after { display: none; }
/* Inside the walkthrough the step title already names the card; the fold rule
   above would otherwise bring the card's own heading back. The season card's
   "set the dates on the Season card" note is said while on that card. */
.fold.wizard-embedded > h2.fold-head:first-child,
.wizard-embedded .season-bill-note { display: none; }
.fold > .fold-head:not(h2) h2 { flex: 1 1 auto; }

/* A red star on a card that still needs the director or coach to choose something. */
.todo-star {
  display: inline-flex; align-items: center; gap: 4px; flex: 0 0 auto;
  margin-left: 8px; font-size: 0.72rem; font-weight: 700; letter-spacing: .02em;
  color: var(--danger); white-space: nowrap;
}
.todo-star::before { content: "\2605"; font-size: 1rem; line-height: 1; }

/* Getting-set-up checklist (director, coach and parent pages). These rules were
   lost in an earlier restyle, which left every tick on its own line above the
   title and made finished steps look undone. */
.setup-bar { height: 5px; border-radius: 99px; background: var(--surface-2);
             overflow: hidden; margin-top: 8px; }
.setup-bar i { display: block; height: 100%; background: var(--accent);
               transition: width .4s ease; }
.setup-step { display: flex; align-items: flex-start; gap: 10px; padding: 9px 0;
              border-bottom: 1px solid var(--border); }
.setup-step:last-child { border-bottom: none; }
.setup-step > div { flex: 1; min-width: 0; }
/* One fixed slot at the left holds the tick or the Go button, so every title
   starts at the same place and the control sits right beside its words. */
.setup-lead { flex: 0 0 44px; display: flex; justify-content: center; }
.setup-lead .tiny { margin: 0; }
.setup-lead .setup-tick { margin-top: 1px; }
.setup-step.done > div { opacity: .7; }
.setup-tick { flex: none; width: 20px; height: 20px; border-radius: 99px;
              border: 1px solid var(--border-light); display: flex; align-items: center;
              justify-content: center; font-size: 12px; margin-top: 1px; }
.setup-step.done .setup-tick { background: var(--accent); border-color: var(--accent);
                               color: #fff; }

/* Director/coach dashboard tabs: Today, Families, Teams, Settings. */
.tabbar { grid-column: 1 / -1; display: flex; gap: 6px; overflow-x: auto;
          padding: 2px 0 4px; margin: 0 0 4px; -webkit-overflow-scrolling: touch; }
.tabbar button:not([class*="btn"]):not(.bell):not(.feel):not(.cue-btn) {
  flex: 1 1 0; min-width: 0; width: auto; min-height: 44px; margin: 0;
  padding: 0.5rem 0.6rem; font-size: 0.9rem; font-weight: 700; letter-spacing: 0;
  white-space: nowrap; background: var(--surface); color: var(--text-muted);
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  box-shadow: none; position: relative;
}
.tabbar button[aria-selected="true"]:not([class*="btn"]):not(.bell):not(.feel):not(.cue-btn) { background: var(--accent); border-color: var(--accent); color: #fff; }
.tabbar button .tab-dot { position: absolute; top: 5px; right: 6px; width: 9px; height: 9px;
                          border-radius: 99px; background: var(--danger); }
.tab-off:not(.wizard-embedded) { display: none !important; }

/* Needs attention: one list instead of four boxes. */
.needs-row { display: flex; align-items: center; gap: 10px; padding: 10px 0;
             border-bottom: 1px solid var(--border); }
.needs-row:last-child { border-bottom: none; }
.needs-row .needs-n { flex: 0 0 34px; height: 34px; border-radius: 99px; display: flex;
                      align-items: center; justify-content: center; font-weight: 800;
                      background: color-mix(in srgb, var(--danger) 20%, transparent);
                      color: var(--danger); }
.needs-row > span:nth-child(2) { flex: 1; min-width: 0; }
.needs-clear { color: var(--text-muted); }

/* Leaderboard pickers (scope, board, window). The .tabs rules were lost in an
   earlier restyle, so each button fell back to the general full-width blue
   button and ten of them stacked edge to edge. Small pills that wrap; only the
   selected one is blue. */
.tabs { display: flex; flex-wrap: wrap; gap: 6px; margin: 8px 0 0; }
.tabs button:not([class*="btn"]):not(.bell):not(.feel):not(.cue-btn) {
  width: auto; min-height: 34px; margin: 0; padding: 0.3rem 0.8rem;
  font-size: 0.82rem; font-weight: 600; letter-spacing: 0; white-space: nowrap;
  background: var(--surface-2); color: var(--text-muted);
  border: 1px solid var(--border); border-radius: 99px; box-shadow: none;
}
.tabs button:not([class*="btn"]):hover { border-color: var(--accent); color: var(--text); }
.tabs button[aria-selected="true"]:not([class*="btn"]):not(.bell):not(.feel):not(.cue-btn) {
  background: var(--accent); border-color: var(--accent); color: #fff;
}

/* Typing a roster in by hand: one block per player on a phone, one line per player on a laptop. */
.rt-row { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px 10px; padding: 12px; margin-bottom: 10px;
  background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--radius-sm); }
.rt-row.bad { border-color: var(--danger); }
.rt-f { display: block; margin: 0; min-width: 0; }
.rt-l { display: block; font-size: .72rem; letter-spacing: .06em; text-transform: uppercase; color: var(--text-muted); margin-bottom: 3px; }
.rt-wide { grid-column: 1 / -1; }
.rt-msg { grid-column: 1 / -1; font-size: .85rem; color: var(--danger); }
.rt-x { display: flex; justify-content: flex-end; align-items: center; }
.rt-head { display: none; }
.rt-actions { display: flex; gap: 8px; flex-wrap: wrap; margin: 10px 0; }
.rt-box { width: 100%; box-sizing: border-box; padding: 10px 12px; font: inherit; color: var(--text); background: transparent;
  border: 1px solid var(--border); border-radius: var(--radius-sm); resize: vertical; }
@media (min-width: 900px) {
  .rt-head, .rt-row { display: grid; grid-template-columns: 1.1fr 1.1fr .65fr 1.8fr 1.2fr .6fr .9fr 36px; gap: 8px; align-items: center; }
  .rt-head { padding: 0 0 6px; font-size: .72rem; letter-spacing: .06em; text-transform: uppercase; color: var(--text-muted); }
  .rt-row { padding: 6px 0; margin: 0; background: none; border: 0; border-bottom: 1px solid var(--border); border-radius: 0; }
  .rt-row.bad { border-bottom-color: var(--danger); }
  .rt-l { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
  .rt-wide { grid-column: auto; }
  .rt-msg { grid-column: 1 / -1; }
}

/* Sending or resending invites to many families at once. */
.fam-bar { display: flex; align-items: center; justify-content: space-between; gap: 10px 14px; flex-wrap: wrap;
  padding: 10px 12px; margin: 0 0 6px; background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--radius-sm); }
.fam-bar label { display: flex; align-items: center; gap: 10px; margin: 0; min-height: 44px; cursor: pointer;
  text-transform: none; letter-spacing: normal; font-size: .95rem; color: var(--text); }
.fam-bar input[type="checkbox"], .fam-pick input[type="checkbox"] { width: 22px; height: 22px; min-height: 0; margin: 0; flex: none; }
.fam-pick { display: flex; align-items: center; justify-content: center; min-width: 44px; min-height: 44px; margin: -10px 0 -10px -10px; cursor: pointer; }
.family-row.has-pick { grid-template-columns: auto 1fr auto; }
.fam-result { margin: 0 0 8px; padding: 10px 12px; border-radius: var(--radius-sm); border: 1px solid var(--border); background: var(--surface-2); font-size: .9rem; }
.fam-result .why { margin-top: 6px; color: var(--text-muted); font-size: .85rem; }
/* On a phone the action (Resend, or Send email + Copy link) goes under the family, not beside it: beside it, it took most
   of the row and squeezed the name into one word per line. */
@media (max-width: 640px) {
  .family-row { grid-template-columns: minmax(0, 1fr); }
  .family-row.has-pick { grid-template-columns: auto minmax(0, 1fr); }
  .family-row.has-pick > div:last-child { grid-column: 2; }
}

/* Badges: earned ones as tiles, the next few as rows with a progress bar. Tier colours are bronze / silver / gold. */
.badge-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(112px, 1fr)); gap: 10px; margin-top: 8px; }
.badge { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 6px; padding: 12px 8px;
  min-height: 92px; text-align: center; border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--surface-2); }
.badge .ico { font-size: 1.9rem; line-height: 1; }
.badge .nm { font-size: .82rem; font-weight: 700; line-height: 1.2; }
.badge.bronze { border-color: #8A5A2B; background: rgba(205, 127, 50, 0.13); }
.badge.silver { border-color: #9AA7B5; background: rgba(160, 175, 190, 0.13); }
.badge.gold   { border-color: #C77700; background: rgba(199, 119, 0, 0.17); }
.badge-next-title { margin: 18px 0 4px; font-size: .72rem; letter-spacing: .08em; text-transform: uppercase; color: var(--text-muted); font-weight: 700; }
.badge-next { display: grid; grid-template-columns: 44px minmax(0, 1fr); gap: 4px 12px; align-items: start; padding: 12px 0; border-bottom: 1px solid var(--border); }
.badge-next:last-child { border-bottom: 0; }
.badge-next .ico { font-size: 1.7rem; line-height: 1; text-align: center; filter: grayscale(1); opacity: .6; }
.badge-next .bn-body > div { margin-top: 2px; }
.badge-bar { height: 8px; margin: 8px 0 4px; border-radius: 4px; background: var(--surface-3); overflow: hidden; }
.badge-bar i { display: block; height: 100%; border-radius: 4px; background: var(--accent); }

/* Every player, ranked: staff only. A row per player; players who have not started are muted and share the last rank. */
.rank-row { display: grid; grid-template-columns: 40px minmax(0, 1fr) auto; gap: 4px 10px; align-items: center; padding: 9px 0; border-bottom: 1px solid var(--border); }
.rank-row:last-child { border-bottom: 0; }
.rank-n { font-family: var(--font-condensed); font-weight: 700; font-size: 1.15rem; text-align: center; }
.rank-xp { text-align: right; font-variant-numeric: tabular-nums; font-weight: 700; }
.rank-row.idle .rank-n, .rank-row.idle .rank-who b { color: var(--text-muted); font-weight: 600; }
.rank-who { min-width: 0; overflow-wrap: anywhere; }

.terms-check { display: flex; gap: 12px; align-items: flex-start; font-size: .9rem; line-height: 1.45; cursor: pointer; }
.terms-check input[type="checkbox"] { width: 22px; height: 22px; min-height: 0; margin: 2px 0 0; flex: none; }
.terms-check a { text-decoration: underline; }
.show-row { display: flex; gap: 10px; align-items: flex-start; margin-top: 10px; font-size: .9rem; }
.show-row input[type="checkbox"] { width: 22px; height: 22px; min-height: 0; margin: 2px 0 0; flex: none; }
