/*
 * Traman.
 *
 * Palette is lifted from the DrillScript prototype so diagrams sit natively in the app
 * rather than looking embedded from elsewhere: the court green and its line colour, the
 * prototype's blue as the interactive accent, ball yellow reserved for favourites and
 * draft state, team red/blue used only inside diagrams.
 *
 * Neutrals are biased slightly green rather than pure grey, so they read as chosen. The
 * typeface is the system UI stack on purpose — this is an app, and it should look like it
 * belongs on the device rendering it.
 *
 * One file. Propshaft does not bundle, so splitting means a link tag per file, which is
 * not worth it at this size.
 */

:root {
  color-scheme: light dark;

  --bg: #f6f7f4;
  --surface: #ffffff;
  --surface-2: #eef0ec;
  --line: #d7dcd4;
  --line-strong: #bcc4b9;
  --text: #14181a;
  --muted: #5f6b66;
  --accent: #1f6fd0;
  --accent-soft: #e4eefb;
  --accent-ink: #ffffff;
  --court: #2f6b45;
  --court-line: #8fbfa2;
  --danger: #b3392f;
  --danger-soft: #fae8e7;
  --ok: #2f7d4f;
  --ok-soft: #e3f2e8;
  --ball: #a8760d;
  --ball-soft: #fdf3dd;

  /* Diagram palette. Named separately from the UI tokens because these belong to the
     court, not the chrome — the renderer reads them straight out of CSS so a diagram
     follows the theme without being told which one is active. */
  --ds-court: #2f6b45;
  --ds-court-line: #8fbfa2;
  --ds-team-a: #b93b34;
  --ds-team-b: #2f6fc0;
  --ds-ball: #a8760d;
  --ds-attack: #c2453f;
  --ds-block: #6b7770;
  --ds-move: #5f6b66;
  --ds-equipment: #7a6a2e;

  --radius: 8px;
  --radius-sm: 6px;
  --shadow: 0 1px 2px rgb(20 24 26 / 6%), 0 8px 24px -14px rgb(20 24 26 / 20%);

  --step: 0.5rem;
  --measure: 68ch;
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #0d1117;
    --surface: #151a21;
    --surface-2: #1c222b;
    --line: #29313c;
    --line-strong: #3a4450;
    --text: #e6eae8;
    --muted: #8a958f;
    --accent: #4a9eff;
    --accent-soft: #16283d;
    --accent-ink: #08121f;
    --court: #1f4a30;
    --court-line: #4f7f63;
    --danger: #ff6b6b;
    --danger-soft: #331a1a;
    --ok: #4fbf7f;
    --ok-soft: #16291d;
    --ball: #ffd166;
    --ball-soft: #33290f;
    --shadow: 0 1px 2px rgb(0 0 0 / 40%), 0 12px 32px -16px rgb(0 0 0 / 70%);

    --ds-court: #1a3a26;
    --ds-court-line: #5a8a6e;
    --ds-team-a: #ff6b6b;
    --ds-team-b: #6ba8ff;
    --ds-ball: #ffd166;
    --ds-attack: #ff5252;
    --ds-block: #cfd8dc;
    --ds-move: #8a93a3;
    --ds-equipment: #d8c47a;
  }
}

*,
*::before,
*::after { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  font-size: 16px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

/* ---------- typography ---------- */

h1, h2, h3 {
  margin: 0 0 calc(var(--step) * 1.5);
  line-height: 1.15;
  letter-spacing: -0.02em;
  text-wrap: balance;
}

h1 { font-size: clamp(1.5rem, 4vw, 2rem); font-weight: 660; }
h2 { font-size: 1.2rem; font-weight: 640; margin-top: calc(var(--step) * 5); }
h3 { font-size: 1rem; font-weight: 620; }

p { margin: 0 0 var(--step); max-width: var(--measure); }

a { color: var(--accent); text-decoration-thickness: 1px; text-underline-offset: 2px; }
a:hover { text-decoration-thickness: 2px; }

small {
  display: inline-block;
  font-size: 0.8125rem;
  color: var(--muted);
  max-width: var(--measure);
  line-height: 1.5;
}

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 3px;
}

/* ---------- app bar ---------- */

.appbar {
  background: var(--surface);
  border-bottom: 1px solid var(--line);
  position: sticky;
  top: 0;
  z-index: 10;
}

.appbar-inner {
  max-width: 1080px;
  margin: 0 auto;
  padding: calc(var(--step) * 1.5) calc(var(--step) * 3);
  display: flex;
  align-items: center;
  gap: calc(var(--step) * 2);
  flex-wrap: wrap;
}

.appbar-identity {
  display: flex;
  align-items: center;
  gap: calc(var(--step) * 2);
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: var(--step);
  font-weight: 660;
  font-size: 0.95rem;
  letter-spacing: -0.015em;
  color: var(--text);
  text-decoration: none;
}

/* A miniature court: green, with a net line down the middle. */
.brand-mark {
  width: 20px;
  height: 20px;
  border-radius: 5px;
  background: var(--court);
  border: 1px solid var(--court-line);
  position: relative;
  flex: none;
}

.brand-mark::after {
  content: "";
  position: absolute;
  inset: 2px auto 2px 50%;
  width: 1px;
  background: var(--court-line);
}

/* A label, never a switcher — the session was bound to this club at sign-in. */
.club-chip {
  font-size: 0.8125rem;
  color: var(--muted);
  padding: 2px calc(var(--step) * 1.25);
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--surface-2);
  white-space: nowrap;
}

.nav {
  display: flex;
  gap: calc(var(--step) * 0.5);
  flex-wrap: wrap;
}

.nav a {
  font-size: 0.875rem;
  padding: calc(var(--step) * 0.75) calc(var(--step) * 1.5);
  border-radius: var(--radius-sm);
  color: var(--muted);
  text-decoration: none;
}

.nav a:hover { background: var(--surface-2); color: var(--text); }

.nav a[aria-current="page"] {
  background: var(--accent-soft);
  color: var(--accent);
  font-weight: 560;
}

.appbar-end {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: var(--step);
}

.who {
  font-size: 0.8125rem;
  color: var(--muted);
  white-space: nowrap;
}

/* ---------- page ---------- */

.page {
  max-width: 1080px;
  margin: 0 auto;
  padding: calc(var(--step) * 4) calc(var(--step) * 3) calc(var(--step) * 10);
}


/* The diagram editor. Two panes side by side need more than the reading width a page of
   prose is capped at — and unlike prose, code does not get harder to read as it gets wider.
   Still centred: it inherits margin: 0 auto from .page, so wide screens keep real gutters
   rather than going full-bleed. */
.page-wide { max-width: 1440px; }

/* ---------- flash and errors ---------- */

.flash {
  padding: calc(var(--step) * 1.5) calc(var(--step) * 2);
  border-radius: var(--radius);
  margin-bottom: calc(var(--step) * 3);
  border: 1px solid;
  font-size: 0.9375rem;
}

.flash-notice { background: var(--ok-soft); border-color: var(--ok); color: var(--ok); }
.flash-alert { background: var(--danger-soft); border-color: var(--danger); color: var(--danger); }

.errors {
  margin: 0 0 calc(var(--step) * 3);
  padding: calc(var(--step) * 1.5) calc(var(--step) * 2) calc(var(--step) * 1.5) calc(var(--step) * 4);
  background: var(--danger-soft);
  border: 1px solid var(--danger);
  border-radius: var(--radius);
  color: var(--danger);
  font-size: 0.9375rem;
}

/* ---------- forms ---------- */

form { max-width: var(--measure); }

label {
  display: block;
  font-size: 0.8125rem;
  font-weight: 560;
  color: var(--muted);
  margin-bottom: calc(var(--step) * 0.5);
}

input[type="text"],
input[type="email"],
input[type="password"],
input[type="number"],
input[type="date"],
input[type="search"],
input[type="datetime-local"],
input[type="url"],
select,
textarea {
  display: block;
  width: 100%;
  max-width: 420px;
  padding: calc(var(--step) * 1.25) calc(var(--step) * 1.5);
  margin-bottom: calc(var(--step) * 2);
  font: inherit;
  font-size: 0.9375rem;
  color: var(--text);
  background: var(--surface);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
}

input:focus, select:focus, textarea:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}

input::placeholder { color: var(--muted); opacity: 0.75; }

/* Explanatory text sits tight under the control it explains. */
input + small, select + small { margin: calc(var(--step) * -1.5) 0 calc(var(--step) * 2); }

.field { margin-bottom: calc(var(--step) * 2); }

/* ---------- buttons ---------- */

input[type="submit"],
button,
.btn {
  display: inline-flex;
  align-items: center;
  gap: calc(var(--step) * 0.75);
  padding: calc(var(--step) * 1.25) calc(var(--step) * 2);
  font: inherit;
  font-size: 0.875rem;
  font-weight: 560;
  color: var(--accent-ink);
  background: var(--accent);
  border: 1px solid var(--accent);
  border-radius: var(--radius-sm);
  cursor: pointer;
  text-decoration: none;
  white-space: nowrap;
}

input[type="submit"]:hover,
button:hover,
.btn:hover { filter: brightness(1.08); }

.btn-secondary {
  background: var(--surface);
  border-color: var(--line-strong);
  color: var(--text);
}

.btn-ghost {
  background: transparent;
  border-color: transparent;
  color: var(--muted);
  padding-inline: calc(var(--step) * 1.25);
}

.btn-ghost:hover { background: var(--surface-2); color: var(--text); filter: none; }

.btn-danger {
  background: transparent;
  border-color: var(--line-strong);
  color: var(--danger);
}

/* button_to renders a form; keep it inline with neighbouring controls. */
form.button_to { display: inline-block; margin: 0; max-width: none; }

.actions {
  display: flex;
  align-items: center;
  gap: var(--step);
  flex-wrap: wrap;
  margin-top: calc(var(--step) * 2);
}

/* ---------- tables ---------- */

.table-wrap {
  overflow-x: auto;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  margin-bottom: calc(var(--step) * 3);
}

table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.9375rem;
}

th {
  text-align: left;
  padding: calc(var(--step) * 1.5) calc(var(--step) * 2);
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 0.625rem;
  font-weight: 500;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: var(--muted);
  border-bottom: 1px solid var(--line);
  white-space: nowrap;
}

td {
  padding: calc(var(--step) * 1.5) calc(var(--step) * 2);
  border-bottom: 1px solid var(--line);
  color: var(--muted);
  vertical-align: middle;
}

tbody tr:last-child td { border-bottom: none; }
td:first-child { color: var(--text); font-weight: 560; }
td:empty::after { content: "—"; color: var(--line-strong); }

/* ---------- pills and empty states ---------- */

.pill {
  display: inline-block;
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  padding: 2px calc(var(--step) * 1.25);
  border-radius: 999px;
  background: var(--surface-2);
  border: 1px solid var(--line);
  color: var(--muted);
}

.pill-owner { background: var(--accent-soft); border-color: transparent; color: var(--accent); }
.pill-you { background: transparent; border-style: dashed; }

.empty {
  padding: calc(var(--step) * 5);
  text-align: center;
  color: var(--muted);
  border: 1px dashed var(--line-strong);
  border-radius: var(--radius);
  margin-bottom: calc(var(--step) * 3);
}

/* An aside inside a form — not an empty state. .empty was being borrowed for this and then
   corrected with inline styles at every call site. */
.note {
  padding: calc(var(--step) * 2);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface-2);
  color: var(--muted);
  font-size: 0.8125rem;
  margin-bottom: calc(var(--step) * 2);
}

/* Rows and lines that sit directly under something and need no margin of their own. */
.tight { margin: 0; }

/* A plan's notes, on its own screen. pre-line so the line breaks a coach typed survive. */
.notes {
  margin: 0 0 calc(var(--step) * 3);
  color: var(--muted);
  font-size: 0.875rem;
  line-height: 1.55;
  white-space: pre-line;
}

/* ---------- signed-out screens ---------- */

.centered {
  min-height: 100dvh;
  display: grid;
  place-items: center;
  padding: calc(var(--step) * 3);
}

.centered .content { width: 100%; max-width: 460px; }

.card {
  width: 100%;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 11px;
  padding: calc(var(--step) * 4);
  box-shadow: var(--shadow);
}

.card form { max-width: none; }
.card input, .card select { max-width: none; }

.auth-links {
  margin-top: calc(var(--step) * 3);
  font-size: 0.875rem;
  color: var(--muted);
}

/* ---------- drill library ---------- */

.page-head {
  display: flex;
  align-items: center;
  gap: calc(var(--step) * 2);
  flex-wrap: wrap;
  margin-bottom: calc(var(--step) * 3);
}

.page-head h1 { margin: 0; }
.page-head .btn { margin-left: auto; }

.lede { color: var(--muted); font-size: 1rem; margin-bottom: calc(var(--step) * 2); }

.library {
  display: grid;
  grid-template-columns: 210px minmax(0, 1fr);
  gap: calc(var(--step) * 4);
  align-items: start;
  max-width: none;
}

.facets {
  display: flex;
  flex-direction: column;
  gap: calc(var(--step) * 3);
  position: sticky;
  top: calc(var(--step) * 10);
}

/* The disclosure's summary is shown only where collapsing is worth offering. On a laptop the
   column has room and the control would be noise. */
.facets > summary {
  display: none;
  font-weight: 600;
  font-size: 0.875rem;
  cursor: pointer;
  padding: calc(var(--step) * 1.5) 0;
  min-height: 44px;
  align-items: center;
}

@media (max-width: 900px) {
  .facets > summary { display: flex; }
}

.facet { display: flex; flex-direction: column; gap: calc(var(--step) * 0.75); }
.facet input, .facet select { margin-bottom: 0; max-width: none; }

.facet-label {
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 0.625rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted);
}

.check {
  display: flex;
  align-items: center;
  gap: calc(var(--step) * 1.25);
  font-size: 0.875rem;
  font-weight: 400;
  color: var(--muted);
  margin: 0;
  cursor: pointer;
}

.check input { width: auto; margin: 0; }

.check-row {
  display: flex;
  flex-wrap: wrap;
  gap: calc(var(--step) * 1.25) calc(var(--step) * 3);
}

.library-main { min-width: 0; display: flex; flex-direction: column; gap: calc(var(--step) * 2); }
.result-count { font-size: 0.8125rem; color: var(--muted); margin: 0; }

.drill-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: calc(var(--step) * 2);
}

.drill-card {
  display: flex;
  flex-direction: column;
  gap: var(--step);
  padding: calc(var(--step) * 2.5);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}

.drill-card-head { display: flex; align-items: flex-start; gap: var(--step); }
.drill-card h3 { margin: 0; font-size: 0.9375rem; line-height: 1.3; }
.drill-card h3 a { color: var(--text); text-decoration: none; }
.drill-card h3 a:hover { color: var(--accent); }
.star { margin-left: auto; color: var(--ball); font-size: 0.875rem; }

.drill-objective {
  margin: 0;
  font-size: 0.8125rem;
  color: var(--muted);
  line-height: 1.45;
}

.drill-meta {
  display: flex;
  flex-wrap: wrap;
  gap: calc(var(--step) * 1.5);
  font-size: 0.75rem;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

.tags { display: flex; flex-wrap: wrap; gap: calc(var(--step) * 0.75); align-items: center; }

/* Three tagging layers, three visual weights: shared, private, state. */
.pill-skill { background: var(--accent-soft); border-color: transparent; color: var(--accent); }
.pill-mine { background: transparent; border-style: dashed; }
.pill-draft { background: var(--ball-soft); border-color: transparent; color: var(--ball); }
.pill-published { background: transparent; border-color: currentColor; color: var(--ok); }

/* ---------- drill detail ---------- */

/* One card, main content and a sidebar sharing an edge — the sidebar is attached rather
   than floating, which is what makes it read as part of the drill instead of beside it. */
.detail {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 250px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
}

.detail-main {
  min-width: 0;
  padding: calc(var(--step) * 3) calc(var(--step) * 3.5);
  display: flex;
  flex-direction: column;
  gap: calc(var(--step) * 3);
}

.detail-side {
  border-left: 1px solid var(--line);
  background: var(--surface-2);
  padding: calc(var(--step) * 3);
  display: flex;
  flex-direction: column;
  gap: calc(var(--step) * 3);
}

/* Title and actions on one line: what the drill is, and what you can do with it, without
   scrolling between them. */
.detail-head {
  display: flex;
  align-items: flex-start;
  gap: calc(var(--step) * 2);
  flex-wrap: wrap;
}

.detail-title {
  flex: 1 1 240px;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: var(--step);
}

.detail-actions { display: flex; gap: var(--step); flex-wrap: wrap; }

.detail h1 { margin: 0; font-size: 1.35rem; font-weight: 650; letter-spacing: -0.02em; }
.detail .objective { margin: 0; font-size: 0.875rem; color: var(--muted); }

/* Sections are labelled, not headed. A drill is a set of short fields to scan, and headings
   at heading size would shout over the content they name. */
.detail .field { display: flex; flex-direction: column; gap: calc(var(--step) * 0.6); margin: 0; }
.detail .field p { margin: 0; font-size: 0.875rem; color: var(--muted); line-height: 1.55; }
.detail .field ul { margin: 0; padding-left: calc(var(--step) * 2.25); font-size: 0.875rem; color: var(--muted); }
.detail .field li { margin-bottom: 3px; }

.label {
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 0.625rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted);
}

.sidefield { display: flex; flex-direction: column; gap: calc(var(--step) * 0.75); }
.sidefield-link { font-size: 0.8125rem; }

.kv { display: flex; justify-content: space-between; gap: var(--step); font-size: 0.8125rem; }
.kv span:first-child { color: var(--muted); }
.kv span:last-child { font-weight: 560; font-variant-numeric: tabular-nums; text-align: right; }

.drill-images { display: flex; flex-wrap: wrap; gap: var(--step); }
.drill-images img { max-width: 100%; border-radius: var(--radius-sm); border: 1px solid var(--line); }

.field-row { display: flex; gap: calc(var(--step) * 2); flex-wrap: wrap; }
.field-row .field { flex: 1 1 140px; }
.field-row input, .field-row select { max-width: none; }

.tag-form { display: flex; gap: var(--step); align-items: center; max-width: none; }
.tag-form input { margin: 0; max-width: none; }

/* An inline remove control inside a pill. */
.tag-remove {
  padding: 0 0 0 calc(var(--step) * 0.5);
  font-size: 0.6875rem;
  min-height: 0;
  color: inherit;
  opacity: 0.65;
}

.tag-remove:hover { background: transparent; opacity: 1; }

/* ---------- diagrams ---------- */

/* The court is portrait and to scale — 9m across, 18m long, each half square — so it is
   taller than any pane is wide. Sized by height, therefore, and centred by the SVG's own
   aspect handling.

   No background colour here on purpose: the green belongs to the court rectangle the
   renderer draws. Painting the whole canvas green would make the empty space either side
   look like part of the court, which is the very thing the wrong ratio was doing before. */
/* The court is landscape and framed per beat, so width fills the pane and the height
   follows from the viewBox — no fixed height, which would only letterbox it. */
.court-canvas {
  display: block;
  width: 100%;
  height: auto;
  border-radius: var(--radius-sm);
}

.viewer {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
  margin-bottom: calc(var(--step) * 3);
  background: var(--surface);
}

.viewer-bar, .editor-bar {
  display: flex;
  align-items: center;
  gap: var(--step);
  padding: calc(var(--step) * 1.25) calc(var(--step) * 1.5);
  background: var(--surface-2);
  border-bottom: 1px solid var(--line);
}

/* The controls keep their size; the caption gives way. Otherwise a long beat title
   squeezes the 2D/3D control until it is clipped. */
.viewer-bar > *, .editor-bar > * { flex: none; }
.editor-bar .label { white-space: nowrap; }

.spacer { flex: 1; }

/* Segmented 2D/3D control. Both options stay visible with the active one filled, so it
   reads as a state rather than as a button that does something unknown. */
.seg {
  display: inline-flex;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  overflow: hidden;
}

.seg button {
  padding: calc(var(--step) * 0.5) calc(var(--step) * 1.5);
  font-size: 0.75rem;
  font-weight: 560;
  border: none;
  border-radius: 0;
  background: var(--surface);
  color: var(--muted);
}

.seg button.on { background: var(--accent); color: var(--accent-ink); }
.seg button:hover:not(.on) { background: var(--surface-2); color: var(--text); filter: none; }

/* The beat caption sits at the far end of the bar, away from the controls — and it is the
   one thing allowed to shrink, so a long beat title never clips the 2D/3D control. */
.beatbar {
  flex: 1 1 auto;
  min-width: 0;
  margin-left: auto;
  font-size: 0.75rem;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
  text-align: right;
}

.viewer .court-canvas { border-radius: 0; }


/* Works on SVG as well as HTML, unlike the [hidden] attribute. */
.is-hidden { display: none !important; }

/* The 3D canvas needs a real height — WebGL cannot infer one the way an SVG viewBox can. */
.court-stage {
  height: min(60vh, 480px);
  background: #0a1419;
}

.court-stage canvas { display: block; width: 100%; height: 100%; }

/* Authoring is a desktop activity — nobody writes a DSL on a phone — so the split pane
   collapses rather than trying to be usable at 380px. */
/* One card split by a single border, not two cards with a gap — source and preview are two
   views of the same thing, and a gutter between them makes them read as separate tools. */
/* Forms cap at reading width, which is right for a column of fields and wrong for this: the
   editor *is* a form, so 68ch was squeezing the whole split pane into a third of the page. */
.diagram-editor { max-width: none; }
.diagram-editor .actions { justify-content: center; }

/* Bounded by the viewport so the Save button below stays on screen. Both panes scroll
   inside it rather than the page growing under them. */
.editor {
  display: grid;
  grid-template-columns: minmax(0, 46fr) minmax(0, 54fr);
  height: clamp(380px, calc(100vh - 290px), 780px);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
  margin-bottom: calc(var(--step) * 3);
}

/* min-height: 0 on both. A grid item defaults to min-height: auto, which refuses to shrink
   below its content — so without this the panes grow to fit the code, the editor overflows
   its own height, and the scrolling escapes to the page instead of staying in the pane. */
.editor-src {
  display: flex;
  flex-direction: column;
  border-right: 1px solid var(--line);
  min-width: 0;
  min-height: 0;
  overflow: hidden;
}

.editor-prev {
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
  overflow: hidden;
  background: var(--surface-2);
}

/* The bars and the error strip keep their size; only the code and the preview scroll. */
.editor-src > .editor-bar,
.editor-prev > .editor-bar,
.editor-src > [data-drillscript-editor-target="errors"] { flex: none; }

.prev-body {
  flex: 1;
  min-height: 0;
  overflow: auto;
  padding: calc(var(--step) * 2);
  display: flex;
  flex-direction: column;
  gap: calc(var(--step) * 1.5);
}

.prev-body p { margin: 0; }

/* An amber strip under the source, not a red box: a diagram with a bad line still saves and
   still draws, so this is a warning about one line rather than a failure of the whole. */
.errline {
  padding: calc(var(--step) * 1.25) calc(var(--step) * 2);
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 0.75rem;
  background: var(--ball-soft);
  color: var(--ball);
  border-top: 1px solid var(--line);
}

/* The preview summary reads as a sentence fragment — "red · 6 players" — so it keeps its
   case, unlike the pills that label a thing. */
.prev-body .pill { text-transform: none; font-size: 0.75rem; letter-spacing: 0; }

.pill-warn { background: transparent; border-color: var(--danger); color: var(--danger); }
.pill-team-red { background: transparent; border-color: var(--ds-team-a); color: var(--ds-team-a); }
.pill-team-blue { background: transparent; border-color: var(--ds-team-b); color: var(--ds-team-b); }

/* ---------- the code editor ---------- */

/* A highlighted <pre> under a transparent <textarea>. The two only stay aligned if they
   render identically, so every metric that affects layout is declared once, here, and
   inherited by both. Changing any of it in one place only is how these drift apart. */
.code-layer {
  margin: 0;
  border: 0;
  padding: calc(var(--step) * 1.75) calc(var(--step) * 2);
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 0.9375rem;
  line-height: 1.7;
  letter-spacing: 0;
  tab-size: 2;

  /* Code does not wrap. A soft-wrapped line looks like two lines of DrillScript, and the
     line numbers in error messages refer to the real ones. */
  white-space: pre;
  overflow-wrap: normal;
  word-break: normal;
}

.code-surface {
  flex: 1;
  min-height: 0;
  display: flex;
  overflow: auto;
  background: var(--surface);
}

.code-area { position: relative; flex: 1; min-width: 0; }

.code-layer:first-child {
  /* The painted layer. It sets the size of the box; the textarea is laid over it. */
  color: var(--text);
  min-width: 100%;
  width: max-content;
}

.code-input {
  position: absolute;
  inset: 0;
  width: 100%;
  max-width: none;
  height: 100%;
  resize: none;
  overflow: hidden;
  background: transparent;
  color: transparent;
  caret-color: var(--accent);
  border-radius: 0;
}

.code-input:focus { outline: none; box-shadow: none; }
.code-input::selection { background: var(--accent-soft); color: transparent; }

/* Line numbers. Sticky so they stay put when a long line scrolls the pane sideways. */
.code-gutter {
  position: sticky;
  left: 0;
  z-index: 1;
  flex: none;
  padding: calc(var(--step) * 1.75) calc(var(--step) * 1.25);
  background: var(--surface-2);
  border-right: 1px solid var(--line);
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 0.9375rem;
  line-height: 1.7;
  text-align: right;
  color: var(--line-strong);
  user-select: none;
}

.code-gutter .ln { font-variant-numeric: tabular-nums; }

/* The line an error is on, marked in the same amber as the message below. */
.code-gutter .ln.has-error {
  color: var(--ball);
  font-weight: 700;
}

/* ---------- autocomplete ---------- */

/* Positioned inside .code-area, which scrolls with the code — so the popup follows the
   caret without any scroll arithmetic. */
.completions {
  position: absolute;
  z-index: 5;
  margin: 0;
  padding: calc(var(--step) * 0.5);
  list-style: none;
  min-width: 200px;
  max-height: 260px;
  overflow-y: auto;
  background: var(--surface);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow);
}

.completion {
  display: flex;
  align-items: baseline;
  gap: calc(var(--step) * 1.5);
  padding: calc(var(--step) * 0.75) calc(var(--step) * 1.25);
  border-radius: 4px;
  cursor: pointer;
  white-space: nowrap;
}

.completion-value {
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 0.8125rem;
  color: var(--text);
}

.completion-detail { margin-left: auto; font-size: 0.6875rem; color: var(--muted); }

.completion.is-selected { background: var(--accent); }
.completion.is-selected .completion-value,
.completion.is-selected .completion-detail { color: var(--accent-ink); }

/* ---------- syntax colours ---------- */

.tok-key { color: var(--accent); font-weight: 600; }
.tok-str { color: var(--ok); }
.tok-comment { color: var(--muted); font-style: italic; opacity: 0.8; }
.tok-red { color: var(--ds-team-a); }
.tok-blue { color: var(--ds-team-b); }
.tok-verb { color: var(--text); }
.tok-pos { color: var(--ball); }

.template-picker { margin: 0; max-width: 210px; font-size: 0.8125rem; padding: calc(var(--step) * 0.75) var(--step); }

.diagram-errors { margin: 0; border: none; border-top: 1px solid var(--line); border-radius: 0; }

/* ---------- the tutorial ---------- */

.guide-toc {
  display: flex;
  flex-wrap: wrap;
  gap: calc(var(--step) * 0.5);
  padding: calc(var(--step) * 2) 0;
  border-bottom: 1px solid var(--line);
  margin-bottom: calc(var(--step) * 2);
}

.guide-toc a {
  font-size: 0.8125rem;
  padding: calc(var(--step) * 0.75) calc(var(--step) * 1.5);
  border-radius: var(--radius-sm);
  color: var(--muted);
  text-decoration: none;
  background: var(--surface-2);
}

.guide-toc a:hover { color: var(--accent); }

/* Prose stays at a readable width even though the page is wide for the examples. */
.page-wide section > p,
.page-wide section > h2,
.page-wide section > h3 { max-width: var(--measure); }

.page-wide section { scroll-margin-top: calc(var(--step) * 2); }

.guide-example {
  display: grid;
  grid-template-columns: minmax(0, 1fr) clamp(260px, 28vw, 400px);
  gap: calc(var(--step) * 3);
  align-items: start;
  margin: calc(var(--step) * 2) 0 calc(var(--step) * 5);
}

/* A textarea, not a <pre>: the examples are meant to be edited. Styled to still read as a
   code block so the page doesn't look like a form. */
.code-sample {
  display: block;
  width: 100%;
  max-width: none;
  margin: 0;
  padding: calc(var(--step) * 2);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 0.875rem;
  line-height: 1.7;
  color: var(--text);
  tab-size: 2;
  resize: vertical;
  white-space: pre;
  overflow-wrap: normal;
  overflow-x: auto;
}

.code-sample:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}

.guide-source { display: flex; flex-direction: column; gap: var(--step); min-width: 0; }
.guide-hint { margin: 0; display: flex; align-items: center; gap: var(--step); }
.guide-hint .btn-ghost { font-size: 0.75rem; padding: 2px calc(var(--step) * 1.25); }
.guide-source .diagram-errors { margin: 0; border-radius: var(--radius); border: 1px solid var(--danger); }

.guide-diagram {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--surface);
}

.guide-diagram .court-canvas { border-radius: 0; }

/* Two examples side by side, for comparing one word against another. */
.guide-pair {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
  gap: calc(var(--step) * 3);
}

.guide-pair .guide-example { grid-template-columns: minmax(0, 1fr); margin-bottom: calc(var(--step) * 2); }
.guide-pair h3 { margin-bottom: 0; }

.detail code {
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 0.85em;
  background: var(--surface-2);
  padding: 1px 4px;
  border-radius: 3px;
}

.card-diagram {
  margin: calc(var(--step) * -1) calc(var(--step) * -1) 0;
  line-height: 0;
  background: var(--surface-2);
  border-radius: var(--radius-sm) var(--radius-sm) 0 0;
}

.card-diagram .court-canvas { border-radius: var(--radius-sm) var(--radius-sm) 0 0; }

@media (max-width: 900px) {
  .editor, .guide-example { grid-template-columns: minmax(0, 1fr); }

  /* Stacked, the fixed viewport height and overflow: hidden clipped the preview pane out of
     existence — the source pane sized to its code and pushed it past the edge, with no way
     to scroll to it. 768px tablet portrait hits this, and clipped is broken rather than
     merely cramped. Height goes back to the content; each pane keeps its own scroll. */
  .editor { height: auto; overflow: visible; }
  .editor-src, .editor-prev { max-height: 70vh; overflow: auto; }

  .library, .detail { grid-template-columns: minmax(0, 1fr); }
  .facets { position: static; }

  /* On a phone the sidebar becomes a strip under the content rather than a column. */
  .detail-side { border-left: none; border-top: 1px solid var(--line); }
}

@media (max-width: 640px) {
  /* Only the identity row stays stuck to the top. At 375px the whole bar is four rows —
     brand and club, account, then six nav links wrapping — and pinning all of it spends a
     fifth of the viewport on chrome that never changes. */
  .appbar { position: static; }
  .appbar-identity {
    position: sticky;
    top: 0;
    z-index: 10;
    background: var(--surface);
  }

  .appbar-inner { padding-inline: calc(var(--step) * 2); gap: var(--step); }
  .page { padding-inline: calc(var(--step) * 2); }
  .appbar-end { margin-left: 0; width: 100%; justify-content: flex-end; }
  .nav { order: 3; width: 100%; }
  .nav a {
    padding-inline: var(--step);
    min-height: 44px;
    display: inline-flex;
    align-items: center;
  }

  /* The signed-in name does not change and does not earn a line on every screen. */
  .who { display: none; }

  /* Thumb-sized. These are all controls the product expects to be used one-handed in a
     hall: the picker's filter chips, the add-drill link, the template form's remove button,
     and the 2D/3D switch. */
  .filter-chip,
  .clear-all,
  .add-drill,
  .block-remove,
  .seg button,
  .tag-remove {
    min-height: 44px;
    display: inline-flex;
    align-items: center;
  }

  .filter-chip { padding: 0 calc(var(--step) * 1.5); }
  .seg button { padding-inline: calc(var(--step) * 2); }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation: none !important; transition: none !important; }
}

/* --- training composer -------------------------------------------------------
   One column at every width. A two-pane plan-beside-library is faster on a
   laptop and impossible on a phone, and one composer to build, style and test
   is worth more than a faster one maintained twice. */

.composer {
  max-width: none;
  display: flex;
  flex-direction: column;
  gap: calc(var(--step) * 3);
}

.composer-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--step);
  flex-wrap: wrap;
}

.composer-head h1 { margin: 0; }
.composer-meta { margin: calc(var(--step) * 0.5) 0 0; color: var(--muted); }

.composer-total {
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  text-align: right;
  color: var(--muted);
  font-size: 0.85rem;
}
.composer-total .big {
  display: block;
  font-size: 1.75rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--text);
}
.composer-total.is-over .big { color: var(--danger); }

.blocks { display: flex; flex-direction: column; gap: calc(var(--step) * 1.5); }

.block {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--surface);
}

.block-head {
  display: flex;
  align-items: baseline;
  gap: var(--step);
  padding: calc(var(--step) * 1.5);
  background: var(--surface-2);
  cursor: pointer;
}

.block-name { font-weight: 650; }
.block-count { color: var(--muted); font-size: 0.85rem; }

.block-budget {
  margin-left: auto;
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-variant-numeric: tabular-nums;
  color: var(--ok);
  font-weight: 600;
  flex: none;
}
.block-budget.is-over { color: var(--danger); }

.block-body {
  padding: calc(var(--step) * 1.5);
  display: flex;
  flex-direction: column;
  gap: var(--step);
  border-top: 1px solid var(--line);
}
.block.is-collapsed .block-body { display: none; }

.block-empty { margin: 0; color: var(--muted); font-size: 0.9rem; }

.meter { height: 3px; border-radius: 999px; background: var(--line); overflow: hidden; }
.meter i { display: block; height: 100%; background: var(--accent); }
.meter i.is-over { background: var(--danger); }

.items { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 2px; }

.item {
  display: flex;
  align-items: center;
  gap: var(--step);
  padding: calc(var(--step) * 0.75) var(--step);
  border-radius: var(--radius-sm);
}
.item:nth-child(odd) { background: var(--surface-2); }
/* Two buttons rather than a drag handle. 44px so they work with a thumb, and they are the
   only reordering affordance — nothing here promises a gesture it does not implement. */
.move { display: flex; flex: none; gap: 2px; }
button.move-up,
button.move-down {
  background: none;
  border: 1px solid var(--line);
  color: var(--muted);
  border-radius: var(--radius-sm);
  min-width: 44px;
  min-height: 44px;
  padding: 0;
  font-size: 0.9rem;
}
button.move-up:hover,
button.move-down:hover { border-color: var(--accent); color: var(--accent); filter: none; }
.item-name { flex: 1; min-width: 0; }
.item-name small { color: var(--muted); }

.item-dur { flex: none; }
.item-dur input[type="number"] {
  width: 4.5rem;
  min-height: 44px;
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-variant-numeric: tabular-nums;
  font-size: 0.85rem;
  text-align: right;
}

/* button_to puts the class on the <button>, not on the <form> it wraps it in — so these are
   element-qualified, never descendant selectors. Written the other way they match nothing
   and every one of these falls through to the primary button style. */
button.item-remove {
  background: none;
  border: none;
  color: var(--muted);
  font-size: 0.8rem;
  cursor: pointer;
  padding: 2px 6px;
}
button.item-remove:hover { color: var(--danger); }

/* The Plans library. Structurally the drills index — a list of reusable things — so it
   borrows .drill-card's shape rather than inventing a third card. */
.training-summary {
  padding: calc(var(--step) * 2.5);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  margin-bottom: calc(var(--step) * 1.5);
}

.training-summary h2 { margin: 0 0 var(--step); font-size: 0.9375rem; line-height: 1.3; }
.training-summary h2 a { color: var(--text); text-decoration: none; }
.training-summary h2 a:hover { color: var(--accent); }
.training-summary p { margin: 0; font-size: 0.8125rem; color: var(--muted); }

.minutes {
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-variant-numeric: tabular-nums;
  font-size: 0.78rem;
}
.minutes.is-over { color: var(--danger); font-weight: 600; }

/* Training templates. Same card as a plan — a template is the shape a plan is stamped
   from, so they should not look like different kinds of object. */
.template {
  padding: calc(var(--step) * 2.5);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  margin-bottom: calc(var(--step) * 1.5);
}

.template h2 { margin: 0 0 var(--step); font-size: 0.9375rem; }
.template h2 small { color: var(--muted); font-weight: 400; font-size: 0.78rem; }
.template > p { margin: 0 0 var(--step); font-size: 0.8125rem; color: var(--muted); }

/* Archived, not deleted: still readable, visibly out of rotation. */
.template.archived { opacity: 0.62; }

.block-list { margin: 0 0 var(--step); padding-left: calc(var(--step) * 3); }
.block-list li { font-size: 0.8125rem; line-height: 1.9; }
.block-list small { color: var(--muted); margin-left: 4px; }
.block-list .minutes { float: right; color: var(--muted); }

/* The club's templates, summarised on the settings screen. A run-on list of names, not a
   bulleted column — settings is a page of answers, not an outline. */
.inline-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: calc(var(--step) * 0.75) calc(var(--step) * 2);
}
.inline-list li { font-size: 0.8125rem; }
.inline-list small { color: var(--muted); }

/* Block controls sit in the body, under the drills. Both rows wrap on a phone rather than
   scrolling, and every control clears 44px so it can be used with a thumb in a hall. */
/* The header is a button so it can be reached by keyboard and report its state — but it
   should still look like a header. `all: unset` drops the global button styling, which would
   otherwise render every block header as a full-width solid accent bar. */
button.block-toggle {
  all: unset;
  display: flex;
  align-items: center;
  gap: var(--step);
  width: 100%;
  min-height: 44px;
  cursor: pointer;
  box-sizing: border-box;
}
button.block-toggle:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.block-controls,
.add-block {
  display: flex;
  flex-wrap: wrap;
  gap: var(--step);
  align-items: center;
  margin-top: calc(var(--step) * 1.5);
}

.block-controls { border-top: 1px solid var(--line); padding-top: calc(var(--step) * 1.5); }

.block-retime { display: flex; flex-wrap: wrap; gap: var(--step); align-items: center; }
.block-retime input[type="text"] { flex: 1 1 8rem; min-width: 0; }
.block-retime input[type="number"] { flex: 0 0 5rem; }

.add-block {
  padding: calc(var(--step) * 2);
  border: 1px dashed var(--line-strong);
  border-radius: var(--radius);
}
.add-block input[type="text"] { flex: 1 1 10rem; min-width: 0; }
.add-block select { flex: 0 0 9rem; }
.add-block input[type="number"] { flex: 0 0 5rem; }

.block-controls input,
.block-controls select,
.block-controls button,
.add-block input,
.add-block select,
.add-block button { min-height: 44px; }

@media (max-width: 560px) {
  .block-retime,
  .add-block { width: 100%; }
  .block-retime input[type="text"],
  .add-block input[type="text"] { flex-basis: 100%; }
}

/* --- agenda -------------------------------------------------------------------
   A list, not a calendar. Two or three sessions a week is a lot of empty grid,
   and a month view needs a different phone screen — which would break the
   one-screen-both-widths rule the composer already follows. */

.agenda-group { margin-bottom: calc(var(--step) * 4); }

.agenda-group h2 {
  font-size: 0.8rem;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--muted);
  margin-bottom: var(--step);
}

.session-row {
  display: flex;
  align-items: center;
  gap: var(--step);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: var(--step);
  margin-bottom: 4px;
  background: var(--surface);
}
.session-row.is-next { border-color: var(--accent); background: var(--accent-soft); }

/* The textual half of the "next" signal. The border says it to people who can see it; this
   says it to everyone else. */
.next-flag {
  display: inline-block;
  margin-left: var(--step);
  padding: 1px calc(var(--step) * 0.75);
  border-radius: 999px;
  background: var(--accent);
  color: var(--accent-ink);
  font-size: 0.7rem;
  font-weight: 660;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  vertical-align: 1px;
}

/* The row's primary fact, on the screen most often read walking into a hall. The mockups'
   run-mode revision records that small grey text is the first thing to fail at arm's length,
   and this was 0.78rem muted. The muting stays where it belongs — on the secondary line. */
.session-when {
  flex: 0 0 5.5rem;
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 0.875rem;
  color: var(--text);
  line-height: 1.35;
}
.session-when b { display: block; font-weight: 660; }

.session-what { flex: 1; min-width: 0; }
.session-meta { font-size: 0.8rem; color: var(--muted); }

.session-marks { display: flex; gap: var(--step); align-items: center; flex: none; }
.session-marks .score { color: var(--ball); font-variant-numeric: tabular-nums; font-size: 0.85rem; }
.session-marks .ran {
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 0.78rem;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

/* The phone drops the durations rather than shrinking them — the cut the mockup
   makes, not a smaller copy of the same row. */
@media (max-width: 560px) {
  .session-row { flex-wrap: wrap; }
  .session-when { flex: 0 0 auto; }
  .session-marks { margin-left: auto; }
  .session-marks .ran { display: none; }
}

/* --- session screen ----------------------------------------------------------
   The handover from desk to hall: the plan in full, the total against the
   template, and one button that starts it. */

.session-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--step);
  flex-wrap: wrap;
}
.session-head h1 { margin: 0; }
.session-head .session-meta { margin: calc(var(--step) * 0.5) 0 0; }

.status {
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  border-radius: 999px;
  padding: 2px 9px;
  border: 1px solid var(--line-strong);
  color: var(--muted);
  flex: none;
}
.status-running { border-color: var(--accent); color: var(--accent); }
.status-completed { border-color: var(--ok); color: var(--ok); }

.plan-phase { margin-bottom: calc(var(--step) * 3); }
.plan-phase h2 {
  font-size: 0.8rem;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--muted);
}
.plan-target { float: right; font-variant-numeric: tabular-nums; }

.plan-items { list-style: none; margin: 0; padding: 0; }

.plan-item {
  display: flex;
  align-items: baseline;
  gap: var(--step);
  padding: calc(var(--step) * 0.6) var(--step);
  border-radius: var(--radius-sm);
}
.plan-item:nth-child(odd) { background: var(--surface-2); }

.plan-number {
  flex: 0 0 1.4rem;
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-variant-numeric: tabular-nums;
  color: var(--muted);
  font-size: 0.85rem;
}
.plan-name { flex: 1; min-width: 0; }
.plan-dur {
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-variant-numeric: tabular-nums;
  color: var(--muted);
  flex: none;
}

.plan-total {
  border-top: 1px solid var(--line);
  padding-top: var(--step);
  color: var(--muted);
}
.plan-total .big {
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 1.4rem;
  font-weight: 700;
  color: var(--text);
  font-variant-numeric: tabular-nums;
}
.plan-total.is-over .big { color: var(--danger); }

/* --- after-session review -----------------------------------------------------
   Every number is a pair. A skipped drill stays visible, struck through: what
   was dropped tells you as much as what was run. */

.review-total {
  color: var(--muted);
  border-bottom: 1px solid var(--line);
  padding-bottom: var(--step);
}
.review-total .big {
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 1.4rem;
  font-weight: 700;
  color: var(--text);
  font-variant-numeric: tabular-nums;
}
.review-total .big.is-over { color: var(--danger); }
.review-total .score { color: var(--ball); }

.review-phase { margin-bottom: calc(var(--step) * 3); }
.review-phase h2 {
  font-size: 0.8rem;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--muted);
}
.review-phase-total {
  float: right;
  font-variant-numeric: tabular-nums;
  color: var(--ok);
}
.review-phase-total.is-over { color: var(--danger); }

.review-items { list-style: none; margin: 0; padding: 0; }

.review-item {
  display: flex;
  align-items: baseline;
  gap: var(--step);
  padding: calc(var(--step) * 0.6) var(--step);
  border-radius: var(--radius-sm);
}
/* nth-child, not nth-of-type: the note used to be a sibling <li> and was counted, so every
   row after a note took the wrong shade. It lives inside its item now, and nth-child stays
   correct if anything else is ever added to the list. */
.review-item:nth-child(odd) { background: var(--surface-2); }
.review-item.is-skipped { opacity: 0.55; }
.review-item.is-skipped .review-name { text-decoration: line-through; }

.review-number {
  flex: 0 0 1.4rem;
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-variant-numeric: tabular-nums;
  color: var(--muted);
  font-size: 0.85rem;
}
.review-name { flex: 1; min-width: 0; }
.review-rating {
  color: var(--ball);
  font-variant-numeric: tabular-nums;
  flex: none;
  font-size: 0.85rem;
}
.review-actual, .review-planned {
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-variant-numeric: tabular-nums;
  flex: none;
}
.review-planned { color: var(--muted); }

/* Sits on its own line inside the item's flex row. */
.review-note {
  flex-basis: 100%;
  margin: 4px 0 0;
  padding-left: calc(var(--step) * 3.5);
  font-size: 0.82rem;
  color: var(--muted);
  font-style: italic;
}

/* --- drill picker ------------------------------------------------------------
   The filters are visible and removable on purpose. Four constraints applied
   silently would make a three-result list look like an empty library, and the
   coach would never learn which one to loosen. */

.add-drill {
  align-self: flex-start;
  font-size: 0.9rem;
  color: var(--accent);
  text-decoration: none;
}
.add-drill:hover { text-decoration: underline; }

.picker {
  border: 1px solid var(--accent);
  background: var(--accent-soft);
  border-radius: var(--radius-sm);
  padding: var(--step);
  display: flex;
  flex-direction: column;
  gap: calc(var(--step) * 0.75);
}

.picker-search input[type="search"] { width: 100%; }

.filters { display: flex; flex-wrap: wrap; gap: 4px; align-items: center; }

.filter-chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 0.78rem;
  border-radius: 999px;
  padding: 2px 9px;
  border: 1px solid var(--accent);
  background: var(--surface);
  color: var(--accent);
  font-weight: 600;
  text-decoration: none;
  white-space: nowrap;
}
.filter-chip .x { color: var(--muted); font-weight: 400; }
.filter-chip:hover { background: var(--accent); color: var(--accent-ink); }
.filter-chip:hover .x { color: var(--accent-ink); }

.clear-all { font-size: 0.78rem; color: var(--muted); margin-left: auto; white-space: nowrap; }

.results { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 3px; }

.result {
  display: flex;
  align-items: center;
  gap: var(--step);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: calc(var(--step) * 0.6) var(--step);
}
.result-dur {
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-variant-numeric: tabular-nums;
  color: var(--muted);
  font-size: 0.85rem;
  flex: none;
}
button.result-add {
  border: 1px solid var(--accent);
  background: var(--surface);
  color: var(--accent);
  border-radius: var(--radius-sm);
  font-weight: 700;
  cursor: pointer;
  padding: 2px 9px;
}
button.result-add:hover { background: var(--accent); color: var(--accent-ink); }

.picker-count, .picker-empty { font-size: 0.78rem; color: var(--muted); margin: 0; }

/* On a phone four chips wrap to three rows before a single result appears, so they
   scroll on one line instead. Same filters, same results, less furniture.

   The fade is the part that was missing: with the scrollbar hidden and no edge treatment, a
   filter off-screen narrowed the results with nothing on screen to say so — which also made
   the "3 of 47 drills" count unexplainable from what the coach could see. */
@media (max-width: 560px) {
  .filters {
    flex-wrap: nowrap;
    overflow-x: auto;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
    mask-image: linear-gradient(to right, #000 calc(100% - 28px), transparent);
  }
  .filters::-webkit-scrollbar { display: none; }
  .clear-all { margin-left: 0; }
}

/* Preview expands in place rather than navigating. Judging a drill must not cost the
   training you are part-way through building. */

.result-group { display: flex; flex-direction: column; }

.result.is-open {
  border-color: var(--accent);
  border-bottom-left-radius: 0;
  border-bottom-right-radius: 0;
  font-weight: 650;
}

/* Expanding a result into its preview is the picker's headline interaction. It was styled as
   plain text whose only affordance was a hover underline, and hover does not exist on a
   touchscreen — so on a phone there was nothing to say the name did anything. */
.result-name { flex: 1; min-width: 0; text-decoration: none; color: var(--accent); }
.result-name::after { content: " ›"; color: var(--muted); }
.result.is-open .result-name::after { content: " ⌄"; }
.result-name:hover { text-decoration: underline; }

.preview {
  display: flex;
  gap: var(--step);
  border: 1px solid var(--accent);
  border-top: none;
  border-bottom-left-radius: var(--radius-sm);
  border-bottom-right-radius: var(--radius-sm);
  background: var(--surface);
  padding: var(--step);
}

.preview-diagram { flex: 0 0 140px; }
.preview-diagram .court-canvas { width: 100%; height: auto; display: block; }

.preview-detail { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 6px; }
.preview-objective { margin: 0; font-size: 0.9rem; }

.preview-facts {
  margin: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  font-size: 0.78rem;
  color: var(--muted);
}

.preview-actions { display: flex; gap: 6px; align-items: center; margin-top: 2px; }
button.preview-add {
  border: 1px solid var(--accent);
  background: var(--accent);
  color: var(--accent-ink);
  border-radius: var(--radius-sm);
  font-weight: 600;
  font-size: 0.82rem;
  cursor: pointer;
  padding: 4px 10px;
}
.preview-open { font-size: 0.82rem; color: var(--muted); }

@media (max-width: 560px) {
  .preview { flex-direction: column; }
  .preview-diagram { flex: none; }
}

/* --- nested block fields ------------------------------------------------------ */

.block-fields { display: flex; flex-direction: column; gap: var(--step); }

.block-row {
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: var(--step);
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: calc(var(--step) * 0.75);
}
.block-row[hidden] { display: none; }

.block-remove {
  align-self: flex-start;
  background: none;
  border: none;
  color: var(--muted);
  font-size: 0.8rem;
  cursor: pointer;
  padding: 2px 0;
}
.block-remove:hover { color: var(--danger); }

.block-add {
  margin-top: var(--step);
  background: none;
  border: 1px dashed var(--line-strong);
  border-radius: var(--radius-sm);
  color: var(--accent);
  font-size: 0.9rem;
  font-weight: 600;
  cursor: pointer;
  padding: calc(var(--step) * 0.75) var(--step);
}
.block-add:hover { border-color: var(--accent); background: var(--accent-soft); }

/* ---------------------------------------------------------------------------
   Run-mode — the two gym screens
   ---------------------------------------------------------------------------
   Sized for a phone held at arm's length in a lit hall, read between rallies
   with a ball in the air. Everything here is bigger than the rest of the app
   on purpose: rows are thumb-sized, the clock is glanceable, and coaching
   points are body text rather than the small grey text they would be on a
   desk screen.

   The layout opts out of dark mode (see layouts/run.html.erb), so these rules
   deliberately use fixed light values rather than the themed tokens.
--------------------------------------------------------------------------- */

.visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.run-body {
  background: var(--bg);
  margin: 0;
}

.run {
  max-width: 44rem;
  margin: 0 auto;
  padding: calc(var(--step) * 2);
  /* Notch and home-indicator safe. A footer button under the home bar is a
     button that takes two taps. */
  padding-top: max(calc(var(--step) * 2), env(safe-area-inset-top));
  padding-bottom: max(calc(var(--step) * 2), env(safe-area-inset-bottom));
}

.run-head { margin-bottom: calc(var(--step) * 2); }
.run-head h1 { margin: calc(var(--step) * 0.5) 0; font-size: 1.5rem; line-height: 1.2; }
.run-head-meta { color: var(--muted); font-size: 0.9rem; }
.run-budget { color: var(--muted); font-size: 0.95rem; }
.run-budget b { color: var(--text); }

.run-block { margin-bottom: calc(var(--step) * 2.5); }

.run-block-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  padding: 0 calc(var(--step) * 0.5) calc(var(--step) * 0.5);
  border-bottom: 1px solid var(--line);
  margin-bottom: calc(var(--step) * 0.5);
}
.run-block-target { color: var(--muted); font-size: 0.9rem; }

.run-item {
  display: flex;
  align-items: center;
  gap: var(--step);
  /* 60px, comfortably over the 44px floor. A mis-tap here opens the wrong
     drill in the middle of a session. */
  min-height: 60px;
  padding: calc(var(--step) * 0.75) var(--step);
  border-radius: var(--radius);
  background: var(--surface);
  border: 1px solid var(--line);
  margin-bottom: calc(var(--step) * 0.5);
  color: var(--text);
  text-decoration: none;
}
.run-item:hover { border-color: var(--line-strong); }

.run-item-mark { width: 1.25rem; text-align: center; color: var(--muted); font-size: 1.1rem; }
.run-item-name { flex: 1; font-size: 1.05rem; }
.run-item-time { color: var(--muted); font-variant-numeric: tabular-nums; }

.run-item.is-running {
  border-color: var(--accent);
  background: var(--accent-soft);
  /* Two signals, not one: colour alone fails for anyone who cannot separate
     these two backgrounds, and the mark carries the same fact. */
  box-shadow: inset 3px 0 0 var(--accent);
}
.run-item.is-running .run-item-mark,
.run-item.is-running .run-item-time { color: var(--accent); font-weight: 600; }

.run-item.is-done { background: var(--ok-soft); border-color: var(--ok); }
.run-item.is-done .run-item-mark { color: var(--ok); }

.run-item.is-skipped { opacity: 0.6; }
.run-item.is-skipped .run-item-name { text-decoration: line-through; }

.run-resume {
  display: block;
  text-align: center;
  position: sticky;
  bottom: calc(var(--step) + env(safe-area-inset-bottom));
  margin-top: calc(var(--step) * 2);
  box-shadow: var(--shadow);
}

.run-foot {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--step);
  margin-top: calc(var(--step) * 3);
  padding-top: calc(var(--step) * 2);
  border-top: 1px solid var(--line);
}

/* --- the drill screen ---------------------------------------------------- */

.run-drill-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: var(--step);
}

.run-clock {
  font-size: 2rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--accent);
  line-height: 1;
}

.run-drill-where { color: var(--muted); font-size: 0.9rem; }
.run-drill h1 { margin: calc(var(--step) * 0.5) 0 var(--step); font-size: 1.6rem; line-height: 1.2; }

.run-diagram {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
  margin-bottom: calc(var(--step) * 2);
}
.run-diagram .court-canvas { display: block; width: 100%; height: auto; }

.run-points {
  margin: 0 0 calc(var(--step) * 2);
  padding-left: calc(var(--step) * 2.5);
}
.run-points li {
  /* Body size. Small grey text at arm's length is the first thing to fail,
     and this is the part being read between rallies. */
  font-size: 1.05rem;
  line-height: 1.5;
  margin-bottom: calc(var(--step) * 0.75);
}

.run-gone { color: var(--muted); font-style: italic; }

.run-drill-foot {
  position: sticky;
  bottom: 0;
  background: var(--bg);
  border-top: 1px solid var(--line);
  padding: var(--step) 0 max(var(--step), env(safe-area-inset-bottom));
  margin-top: calc(var(--step) * 2);
}

.run-next {
  color: var(--muted);
  font-size: 0.9rem;
  margin-bottom: calc(var(--step) * 0.75);
}
.run-next span { font-variant-numeric: tabular-nums; }

.run-capture { margin-bottom: var(--step); }

.run-rate { display: flex; gap: calc(var(--step) * 0.25); border: 0; padding: 0; margin: 0 0 calc(var(--step) * 0.5); }
.run-rate legend { padding: 0; }

.run-star {
  /* The radio itself is hidden rather than removed: it stays focusable and
     still announces its label, so the rating is reachable by keyboard and by
     screen reader even though what is drawn is a star. */
  cursor: pointer;
  font-size: 1.75rem;
  line-height: 1;
  color: var(--line-strong);
  padding: calc(var(--step) * 0.25);
}
.run-star input { position: absolute; opacity: 0; width: 0; height: 0; }
.run-star.is-set { color: var(--ball); }
.run-star:focus-within { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: var(--radius-sm); }

.run-capture textarea {
  width: 100%;
  font: inherit;
  padding: calc(var(--step) * 0.75);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--text);
  resize: vertical;
}

.run-actions { display: flex; gap: var(--step); }
.run-actions form { flex: 1; }
.run-actions .btn, .run-actions button { width: 100%; min-height: 52px; font-size: 1.05rem; }

@media (max-width: 30rem) {
  .run { padding-left: var(--step); padding-right: var(--step); }
  .run-head h1, .run-drill h1 { font-size: 1.35rem; }
}

.session-run { display: flex; align-items: center; gap: var(--step); margin: calc(var(--step) * 2) 0; }
.session-run small { color: var(--muted); }
