/* ============================================================================
   Vala — Train with vision.
   ----------------------------------------------------------------------------
   The design idea, so nobody has to guess later:

   The palette is SEMANTIC, not decorative. Cold is the plan; warm is the work.

     --seer   (cold cyan)   the prescription — what was foreseen, not yet done
     --ember  (warm amber)  what you actually logged — your work, your progress
     --rune   (violet)      phase 2 / intensification techniques

   In the day view a card starts cold and turns warm as sets are entered. That
   is the one memorable thing in this interface, and it is also the fastest
   possible read at arm's length with sweaty hands: cold = to do, warm = done.
   Everything else stays quiet so that signal keeps working.

   Numbers are set in a monospace face at a large size. In a training log the
   numbers *are* the content; they get the characterful face, not the chrome.

   No webfonts. This app has to render instantly in a gym basement with no
   signal, and it has no build step. System stacks, used deliberately.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. The [hidden] guard. Keep this FIRST.
   The browser's `[hidden] { display: none }` lives in the user-agent
   stylesheet, so any author `display` rule outranks it. This has cost real
   debugging time on other projects. Never think about it again.
   -------------------------------------------------------------------------- */
[hidden] { display: none !important; }

/* --------------------------------------------------------------------------
   2. Tokens
   Nothing colour-related is hardcoded outside this layer. A whole new visual
   identity later is then a contained change.
   -------------------------------------------------------------------------- */
:root {
  --font-ui: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --font-data: ui-monospace, SFMono-Regular, "SF Mono", "Cascadia Mono", "Roboto Mono", Menlo, monospace;

  --fs-micro: 0.6875rem;  /* 11px — eyebrows, units */
  --fs-small: 0.8125rem;  /* 13px */
  --fs-body:  0.9375rem;  /* 15px */
  --fs-lead:  1.0625rem;  /* 17px */
  --fs-h2:    1.25rem;    /* 20px */
  --fs-h1:    1.625rem;   /* 26px */
  --fs-data:  1.375rem;   /* 22px — logged numbers */

  --sp-1: 0.25rem;  --sp-2: 0.5rem;  --sp-3: 0.75rem;
  --sp-4: 1rem;     --sp-5: 1.5rem;  --sp-6: 2rem;   --sp-7: 3rem;

  --r-sm: 3px;
  --r:    5px;
  --r-lg: 8px;

  --shell: 430px;        /* single column cap — mobile first, centred beyond */
  --tap: 44px;           /* minimum touch target */

  /* Z-index scale with real headroom, defined once. */
  --z-base: 1;
  --z-sticky: 100;
  --z-header: 200;
  --z-drawer: 300;
  --z-modal: 400;
  --z-toast: 500;

  --dur: 160ms;
  --ease: cubic-bezier(0.2, 0, 0.2, 1);
}

/* Dark is the primary identity: a cold night ground with genuine blue chroma,
   not a neutral near-black. */
:root,
[data-theme="dark"] {
  --ink-0: #0C1118;
  --ink-1: #121A24;
  --ink-2: #1A2431;
  --line:  #24313F;
  --line-soft: #1B2530;

  --text:     #E4EAF1;
  --text-dim: #8494A6;
  --text-mute:#5C6C7E;

  --seer:      #7FD1E8;
  --seer-soft: #24414E;
  --seer-ink:  #0C1118;

  --ember:      #F0A94C;
  --ember-soft: #40301A;
  --ember-ink:  #1A1204;

  --rune:      #A78BFA;
  --rune-soft: #2B2544;

  --ok:     #6FCF97;
  --warn:   #E8C15C;
  --danger: #EF6B6B;
  --danger-soft: #3A1F22;

  --field: #0A0F15;
  --shadow: 0 1px 2px rgb(0 0 0 / 0.5), 0 8px 24px -12px rgb(0 0 0 / 0.7);

  color-scheme: dark;
}

[data-theme="light"] {
  --ink-0: #EDF1F6;
  --ink-1: #FFFFFF;
  --ink-2: #F5F8FB;
  --line:  #D3DCE6;
  --line-soft: #E4EAF1;

  --text:     #0E1620;
  --text-dim: #56657A;
  --text-mute:#7C8A9C;

  --seer:      #15697F;
  --seer-soft: #D6EDF4;
  --seer-ink:  #FFFFFF;

  --ember:      #A85F10;
  --ember-soft: #FAECD8;
  --ember-ink:  #FFFFFF;

  --rune:      #5B3FCB;
  --rune-soft: #E7E1FB;

  --ok:     #1B7F4D;
  --warn:   #926A0B;
  --danger: #B4262C;
  --danger-soft: #FBE3E4;

  --field: #FFFFFF;
  --shadow: 0 1px 2px rgb(16 24 36 / 0.06), 0 8px 24px -14px rgb(16 24 36 / 0.24);

  color-scheme: light;
}

@media (prefers-color-scheme: light) {
  [data-theme="auto"] {
    --ink-0: #EDF1F6; --ink-1: #FFFFFF; --ink-2: #F5F8FB;
    --line: #D3DCE6; --line-soft: #E4EAF1;
    --text: #0E1620; --text-dim: #56657A; --text-mute: #7C8A9C;
    --seer: #15697F; --seer-soft: #D6EDF4; --seer-ink: #FFFFFF;
    --ember: #A85F10; --ember-soft: #FAECD8; --ember-ink: #FFFFFF;
    --rune: #5B3FCB; --rune-soft: #E7E1FB;
    --ok: #1B7F4D; --warn: #926A0B; --danger: #B4262C; --danger-soft: #FBE3E4;
    --field: #FFFFFF;
    --shadow: 0 1px 2px rgb(16 24 36 / 0.06), 0 8px 24px -14px rgb(16 24 36 / 0.24);
    color-scheme: light;
  }
}

/* --------------------------------------------------------------------------
   3. Base
   -------------------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  min-height: 100dvh;
  background: var(--ink-0);
  color: var(--text);
  font: var(--fs-body)/1.55 var(--font-ui);
  font-synthesis-weight: none;
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3 { margin: 0; font-weight: 650; line-height: 1.2; letter-spacing: -0.015em; }
h1 { font-size: var(--fs-h1); }
h2 { font-size: var(--fs-h2); }
h3 { font-size: var(--fs-lead); }
p  { margin: 0 0 var(--sp-3); }
p:last-child { margin-bottom: 0; }

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

:focus-visible {
  outline: 2px solid var(--seer);
  outline-offset: 2px;
  border-radius: var(--r-sm);
}

/* An eyebrow labels a region. It encodes hierarchy, so it earns the tracking. */
.eyebrow {
  font-size: var(--fs-micro);
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-mute);
}

/* Numbers are the content. */
.num, output, td.num {
  font-family: var(--font-data);
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.01em;
}

.dim { color: var(--text-dim); }
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap;
}

/* --------------------------------------------------------------------------
   4. Shell
   -------------------------------------------------------------------------- */
.shell {
  width: 100%;
  max-width: var(--shell);
  margin-inline: auto;
  padding: 0 var(--sp-4) var(--sp-7);
}

.site-header {
  position: sticky;
  top: 0;
  z-index: var(--z-header);
  background: color-mix(in srgb, var(--ink-0) 88%, transparent);
  backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--line-soft);
  /* viewport-fit=cover (needed for an edge-to-edge installed app) lets content
     draw under the status bar / notch. In a normal browser tab the browser's
     own chrome already sits above the page, so this resolves to 0 there and
     changes nothing — it only does anything once the app is installed and
     running with no browser chrome above it at all. */
  padding-top: env(safe-area-inset-top, 0px);
}

.site-header__inner {
  max-width: var(--shell);
  margin-inline: auto;
  padding: var(--sp-3) var(--sp-4);
  /* The toggle button is position:fixed and no longer a DOM child here (see
     the nav-drawer section below), so this padding is the only thing stopping
     the wordmark from running underneath it. */
  padding-right: calc(var(--sp-4) + var(--tap) + var(--sp-2));
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
}

/* The wordmark: wide tracking, small caps energy, with the seer's mark as a
   luminous dot on the descender-free A. Restraint — it appears once. */
.wordmark {
  display: inline-flex;
  align-items: baseline;
  gap: 0.4em;
  min-width: 0;
  overflow: hidden;
  flex: 1 1 auto;
  font-size: var(--fs-lead);
  font-weight: 680;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--text);
  text-decoration: none;
}
.wordmark__mark { flex: none; color: var(--seer); }
.wordmark__tag {
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  font-size: var(--fs-micro);
  font-weight: 500;
  letter-spacing: 0.04em;
  text-transform: none;
  color: var(--text-mute);
}

/* --------------------------------------------------------------------------
   5. Cards — the spine carries state
   -------------------------------------------------------------------------- */
.card {
  position: relative;
  background: var(--ink-1);
  border: 1px solid var(--line);
  border-left: 3px solid var(--seer-soft);
  border-radius: var(--r);
  padding: var(--sp-4);
  margin-bottom: var(--sp-3);
  box-shadow: var(--shadow);
  transition: border-color var(--dur) var(--ease), background var(--dur) var(--ease);
}
/* The signature: work turns the plan warm. */
.card.is-logged { border-left-color: var(--ember); }
.card.is-done   { border-left-color: var(--ember); background: color-mix(in srgb, var(--ember-soft) 30%, var(--ink-1)); }
.card.is-phase2 { border-left-color: var(--rune); }

.card__head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-3); margin-bottom: var(--sp-2); }

.stack > * + * { margin-top: var(--sp-3); }
.row { display: flex; align-items: center; gap: var(--sp-3); }
.row--between { justify-content: space-between; }
.grow { flex: 1 1 auto; min-width: 0; }

/* --------------------------------------------------------------------------
   6. Controls
   -------------------------------------------------------------------------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  min-height: var(--tap);
  padding: 0 var(--sp-4);
  border: 1px solid var(--line);
  border-radius: var(--r);
  background: var(--ink-2);
  color: var(--text);
  font: 550 var(--fs-body)/1 var(--font-ui);
  cursor: pointer;
  transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.btn:hover { border-color: var(--text-mute); }
.btn:active { transform: translateY(1px); }
.btn[disabled] { opacity: 0.5; cursor: not-allowed; }

/* Primary is warm: the primary action in this app is always "record what you did". */
.btn--primary { background: var(--ember); border-color: var(--ember); color: var(--ember-ink); font-weight: 650; }
.btn--primary:hover { border-color: var(--ember); filter: brightness(1.06); }
.btn--ghost { background: transparent; }
.btn--danger { background: var(--danger-soft); border-color: var(--danger); color: var(--danger); }
.btn--block { width: 100%; }
.btn--small { min-height: 34px; padding: 0 var(--sp-3); font-size: var(--fs-small); }

label { display: block; font-size: var(--fs-small); font-weight: 550; color: var(--text-dim); margin-bottom: var(--sp-1); }

input, select, textarea {
  width: 100%;
  min-height: var(--tap);
  padding: var(--sp-2) var(--sp-3);
  background: var(--field);
  color: var(--text);
  border: 1px solid var(--line);
  border-radius: var(--r);
  font: var(--fs-body)/1.4 var(--font-ui);
}
textarea { min-height: 7rem; resize: vertical; }
input::placeholder, textarea::placeholder { color: var(--text-mute); }

/* Set entry: thumb-sized, monospaced, the biggest type on the screen. */
.entry {
  font: 600 var(--fs-data)/1 var(--font-data);
  font-variant-numeric: tabular-nums;
  text-align: center;
  min-height: 52px;
  padding: var(--sp-2);
}
.entry:not(:placeholder-shown) { border-color: var(--ember); color: var(--ember); }

.badge {
  display: inline-flex;
  align-items: center;
  gap: 0.35em;
  padding: 2px var(--sp-2);
  border-radius: 999px;
  font-size: var(--fs-micro);
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  background: var(--seer-soft);
  color: var(--seer);
}
.badge--phase2 { background: var(--rune-soft); color: var(--rune); }
.badge--done   { background: var(--ember-soft); color: var(--ember); }
.badge--ok     { background: color-mix(in srgb, var(--ok) 18%, transparent); color: var(--ok); }

/* Disclosure: summaries display, bodies act. Never put a control in a summary —
   it fights the toggle for the click. */
details { border: 1px solid var(--line); border-radius: var(--r); background: var(--ink-1); }
summary {
  min-height: var(--tap);
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-3);
  cursor: pointer;
  font-weight: 550;
  list-style: none;
}
summary::-webkit-details-marker { display: none; }
summary::after { content: "＋"; margin-left: auto; color: var(--text-mute); }
details[open] > summary::after { content: "－"; }
details > .details__body { padding: 0 var(--sp-3) var(--sp-3); }

/* --------------------------------------------------------------------------
   7. Definition rows (status lists, prescriptions)
   -------------------------------------------------------------------------- */
.deflist { display: grid; grid-template-columns: auto 1fr; gap: var(--sp-2) var(--sp-4); margin: 0; }
.deflist dt { font-size: var(--fs-small); color: var(--text-dim); }
.deflist dd { margin: 0; font-family: var(--font-data); font-size: var(--fs-small); text-align: right; }

/* --------------------------------------------------------------------------
   8. Toast / sync chip
   -------------------------------------------------------------------------- */
.toast {
  position: fixed;
  left: 50%;
  bottom: calc(env(safe-area-inset-bottom, 0px) + var(--sp-4));
  transform: translateX(-50%);
  z-index: var(--z-toast);
  max-width: calc(var(--shell) - var(--sp-6));
  padding: var(--sp-3) var(--sp-4);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background: var(--ink-2);
  box-shadow: var(--shadow);
  font-size: var(--fs-small);
}
.toast--warn { border-color: var(--warn); color: var(--warn); }

.notice {
  padding: var(--sp-3) var(--sp-4);
  border: 1px solid var(--line);
  border-left: 3px solid var(--seer);
  border-radius: var(--r);
  background: var(--ink-1);
  font-size: var(--fs-small);
}
.notice--error { border-left-color: var(--danger); background: var(--danger-soft); }

/* --------------------------------------------------------------------------
   8b. Nav drawer
   A <details> element doing the whole job: open/close is native browser
   behaviour, not hand-rolled JS state. The one thing a <details> does not do —
   close itself when a link inside it is tapped — is the only enhancement
   app.js adds. Everything else here works with JavaScript off.

   The whole element is a SIBLING of <header> in the markup, not nested inside
   it — see the comment in head.ejs. Consequence: the toggle button is visually
   part of the header bar but not structurally inside it, so it is pinned with
   its own position:fixed rather than relying on the header's flex row, and the
   header reserves space on its right so the wordmark never runs under it.
   -------------------------------------------------------------------------- */
.navdrawer__toggle {
  position: fixed;
  /* env(), not the header's own padding: a position:fixed element sits outside
     normal flow entirely, so it does not inherit any ancestor's padding —
     including the safe-area padding just added to .site-header above. Without
     this, the toggle stayed at a plain 12px from the true top of the screen,
     which in an installed standalone app (no browser chrome) can be UNDER the
     status bar or camera cutout: present in the DOM, correctly styled, and
     genuinely invisible because the OS is drawing over it. This is almost
     certainly why it disappeared specifically after installing as an app. */
  top: calc(env(safe-area-inset-top, 0px) + var(--sp-3));
  right: calc(env(safe-area-inset-right, 0px) + var(--sp-4));
  z-index: var(--z-drawer);
  min-height: var(--tap);
  min-width: var(--tap);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border-radius: var(--r);
  cursor: pointer;
  color: var(--text);
  background: transparent;
  list-style: none;
}
/* This toggle is not a normal disclosure row, so the generic summary styling
   (full-width, +/− marker, left-aligned text) is reset here rather than reused. */
.navdrawer__toggle::-webkit-details-marker { display: none; }
.navdrawer__toggle::after { content: none; }
.navdrawer__toggle:hover { background: var(--ink-2); }

.navdrawer__iconClose { display: none; }
.navdrawer[open] .navdrawer__iconOpen { display: none; }
.navdrawer[open] .navdrawer__iconClose { display: block; }

.navdrawer__panel {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  z-index: var(--z-drawer);
  width: min(84vw, 340px);
  display: flex;
  flex-direction: column;
  gap: var(--sp-1);
  padding: calc(env(safe-area-inset-top, 0px) + var(--sp-5)) var(--sp-4)
           calc(env(safe-area-inset-bottom, 0px) + var(--sp-5));
  background: var(--ink-1);
  border-left: 1px solid var(--line);
  box-shadow: var(--shadow);
  overflow-y: auto;
  transform: translateX(100%);
  transition: transform var(--dur) var(--ease);
}
.navdrawer[open] .navdrawer__panel { transform: translateX(0); }

/* Dims the page behind the open drawer and gives a tap-outside-to-close target.
   :has() is the only thing doing that — no listener, no state, and if a browser
   somehow lacks it the drawer still opens and closes correctly, it just isn't
   dimmed. A pure enhancement, never a dependency. */
body:has(.navdrawer[open]) {
  overflow: hidden;
}
body:has(.navdrawer[open])::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: calc(var(--z-drawer) - 1);
  background: rgb(0 0 0 / 0.5);
  animation: fade-in var(--dur) var(--ease);
}
@keyframes fade-in { from { opacity: 0; } }

.navdrawer__who {
  margin: 0 0 var(--sp-2);
  font-weight: 650;
  line-height: 1.3;
}
.navdrawer__who .card__meta { display: block; font-weight: 500; }

.navdrawer__panel a,
.navdrawer__logout {
  display: block;
  width: 100%;
  min-height: var(--tap);
  padding: var(--sp-2) var(--sp-2);
  border: none;
  border-radius: var(--r);
  background: none;
  color: var(--text);
  font: 550 var(--fs-lead)/var(--tap) var(--font-ui);
  text-align: left;
  text-decoration: none;
  cursor: pointer;
}
.navdrawer__panel a[aria-current="page"] { color: var(--seer); background: var(--seer-soft); }
.navdrawer__panel a:hover,
.navdrawer__logout:hover { background: var(--ink-2); }
.navdrawer__logout { color: var(--danger); }

.navdrawer__rule { border: none; border-top: 1px solid var(--line-soft); margin: var(--sp-2) 0; }

.navdrawer__label {
  margin: 0 0 var(--sp-2);
  font-size: var(--fs-micro);
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-mute);
}
.navdrawer__theme { display: flex; gap: var(--sp-2); }
.navdrawer__theme button {
  flex: 1 1 0;
  min-height: var(--tap);
  padding: 0 var(--sp-2);
  border: 1px solid var(--line);
  border-radius: var(--r);
  background: var(--ink-2);
  color: var(--text-dim);
  font: 550 var(--fs-small)/1 var(--font-ui);
  cursor: pointer;
}
.navdrawer__theme button[aria-pressed="true"] {
  border-color: var(--seer);
  background: var(--seer-soft);
  color: var(--seer);
}

/* --------------------------------------------------------------------------
   9. Forms and auth pages
   -------------------------------------------------------------------------- */
.auth { padding: var(--sp-6) 0 var(--sp-7); }

.form > * + * { margin-top: var(--sp-3); }
.field { margin: 0; }
.hint { margin: var(--sp-1) 0 0; font-size: var(--fs-micro); color: var(--text-mute); }

.flash { display: flex; align-items: flex-start; gap: var(--sp-3); }
.flash__text { flex: 1 1 auto; min-width: 0; overflow-wrap: anywhere; }
.notice--warn { border-left-color: var(--warn); }

/* One-time links and 2FA keys: long, unbroken, and meant to be copied. */
.copyable {
  margin: var(--sp-2) 0 0;
  padding: var(--sp-2) var(--sp-3);
  background: var(--field);
  border: 1px solid var(--line);
  border-radius: var(--r);
  font-size: var(--fs-small);
  overflow-wrap: anywhere;
  cursor: copy;
}


/* --------------------------------------------------------------------------
   10. Library, prose and select-mode reordering
   -------------------------------------------------------------------------- */

/* Tracking type is a real distinction, so it gets colour: weight is the plain
   case, assisted is the inverted one (less is better), time is its own thing. */
.badge--weight   { background: var(--seer-soft);  color: var(--seer); }
.badge--assisted { background: var(--rune-soft);  color: var(--rune); }
.badge--time     { background: var(--ember-soft); color: var(--ember); }

a.card--link { display: block; color: inherit; text-decoration: none; }
a.card--link:hover { border-color: var(--text-mute); }
.card.is-archived { opacity: 0.6; border-left-color: var(--line); }

.card--row { display: flex; align-items: center; gap: var(--sp-3); }
.card--row a { color: inherit; }

.checkline { display: flex; align-items: center; gap: var(--sp-2); font-weight: 500; }
.checkline input { width: auto; min-height: 0; }

/* Rendered Markdown. The allowlist is short, so this is short too. */
.prose > :first-child { margin-top: 0; }
.prose > :last-child { margin-bottom: 0; }
.prose ul, .prose ol { padding-left: 1.2em; margin: 0 0 var(--sp-3); }
.prose li + li { margin-top: var(--sp-1); }
.prose code {
  font-family: var(--font-data);
  font-size: 0.9em;
  padding: 0.1em 0.35em;
  background: var(--ink-2);
  border-radius: var(--r-sm);
}

.mdbar { display: flex; gap: var(--sp-1); margin-bottom: var(--sp-1); }
.mdbar .btn { min-width: 2.5rem; padding: 0 var(--sp-2); }

/* Select mode: the controls and the hint only exist while reordering, and the
   destructive per-row controls step out of the way so a mis-tap can't delete. */
.reorder-only, .reorder-hint { display: none; }
[data-reorder-scope].is-reordering .reorder-only,
[data-reorder-scope].is-reordering .reorder-hint { display: flex; }
[data-reorder-scope].is-reordering .reorder-hint { display: block; }
[data-reorder-scope].is-reordering .reorder-hidden { display: none; }

[data-reorder-list].is-reordering [data-reorder-id] {
  cursor: pointer;
  user-select: none;
  border-left-color: var(--line);
}
[data-reorder-list].is-reordering [data-reorder-id].is-picked {
  border-left-color: var(--ember);
  background: color-mix(in srgb, var(--ember-soft) 30%, var(--ink-1));
}

.pick {
  display: none;
  flex: none;
  width: 1.75rem;
  height: 1.75rem;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--line);
  border-radius: 999px;
  font: 600 var(--fs-small)/1 var(--font-data);
  color: var(--ember);
}
[data-reorder-list].is-reordering .pick { display: inline-flex; }


/* --------------------------------------------------------------------------
   11. Program authoring
   -------------------------------------------------------------------------- */

/* The day key (A / B / C) is how the athlete refers to a session out loud, so
   it gets to look like a stamped letter rather than body text. */
.daykey {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: 1.6rem;
  height: 1.6rem;
  margin-right: var(--sp-2);
  border: 1px solid var(--seer-soft);
  border-radius: var(--r-sm);
  background: var(--seer-soft);
  color: var(--seer);
  font: 650 var(--fs-small)/1 var(--font-data);
}

.itemlist { list-style: none; margin: 0; padding: 0; }
.itemlist__row { padding: var(--sp-3) 0; border-top: 1px solid var(--line-soft); }
.itemlist__row:first-child { border-top: 0; }
.phase2-line { color: var(--rune); }

.daytable { width: 100%; border-collapse: collapse; font-size: var(--fs-small); }
.daytable td { padding: var(--sp-2) var(--sp-1); border-top: 1px solid var(--line-soft); vertical-align: middle; }
.daytable__week th {
  padding: var(--sp-3) var(--sp-1) var(--sp-1);
  text-align: left;
  font-size: var(--fs-micro);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-mute);
}
.badge--pending { background: var(--ink-2); color: var(--text-dim); }
.badge--open    { background: var(--seer-soft); color: var(--seer); }
.badge--done    { background: var(--ember-soft); color: var(--ember); }
.badge--skipped { background: var(--ink-2); color: var(--text-mute); }

/* An item in the editor. Four numeric cells side by side is the densest layout
   that still leaves each field a thumb wide at 430px. */
.item {
  padding: var(--sp-3);
  margin-bottom: var(--sp-3);
  border: 1px solid var(--line);
  border-left: 3px solid var(--seer-soft);
  border-radius: var(--r);
  background: var(--ink-1);
}

.itemgrid { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--sp-2); margin-top: var(--sp-3); }
.itemgrid__cell { display: flex; flex-direction: column; gap: var(--sp-1); margin: 0; }
.itemgrid__cell > span { font-size: var(--fs-micro); color: var(--text-mute); text-transform: uppercase; letter-spacing: 0.08em; }
.itemgrid__cell input { min-height: 40px; padding: var(--sp-1) var(--sp-2); text-align: center; }

/* A field restored from the draft mirror is marked until it is saved, so the
   coach can see which values the server has not yet acknowledged. */
input.is-draft, textarea.is-draft { border-color: var(--warn); }

.savechip {
  flex: none;
  min-width: 1.25rem;
  font: 600 var(--fs-small)/1 var(--font-data);
  text-align: center;
  color: var(--text-mute);
}
.savechip[data-state="saved"] { color: var(--ok); }
.savechip[data-state="error"] { color: var(--danger); }

details.tpl { margin-bottom: var(--sp-3); }
details.tpl > summary .grow { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }


/* --------------------------------------------------------------------------
   12. The day view
   The one screen used one-handed, mid-set, with sweaty hands. Everything here
   is sized for a thumb and readable at arm's length.
   -------------------------------------------------------------------------- */
.dayhead { padding: var(--sp-5) 0 var(--sp-4); }

.exercise { padding-bottom: var(--sp-4); }
.exercise[data-save="saving"] { border-left-color: var(--seer); }
.exercise[data-save="error"]  { border-left-color: var(--danger); }

.prescription { margin: 0 0 var(--sp-2); font-size: var(--fs-small); color: var(--text-dim); }
.cue { margin-bottom: var(--sp-3); color: var(--text-dim); }

/* Two kinds of note, and they are different things: the plan note is what the
   coach wants from this athlete on this exercise, and it is always visible. The
   library cue is how the movement is performed in general — useful the first few
   times, noise after that, so it folds away. */
.cuedetails { border: 0; background: none; margin-bottom: var(--sp-3); }
.cuedetails > summary { min-height: 0; padding: 0; font-size: var(--fs-micro); color: var(--text-mute); text-transform: uppercase; letter-spacing: 0.1em; }
.cuedetails > .details__body { padding: var(--sp-2) 0 0; }

/* Done is a big, unambiguous target. It toggles in any order — there is no
   forced sequence through a session. */
.donetoggle {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--tap);
  height: var(--tap);
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--ink-2);
  color: var(--text-mute);
  cursor: pointer;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}
.donetoggle[aria-pressed="true"] { background: var(--ember); border-color: var(--ember); color: var(--ember-ink); }
.donetoggle[disabled] { opacity: 0.4; cursor: not-allowed; }

/* Two columns of numbers, one index. The grid stays fixed so the inputs sit in
   the same place on every card and the thumb learns one position. */
.sets { display: grid; gap: var(--sp-2); }
.sets__head,
.setrow { display: grid; grid-template-columns: 1.75rem 1fr 1fr; gap: var(--sp-2); align-items: center; }
.sets__head span {
  font-size: var(--fs-micro);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-mute);
  text-align: center;
}
.setrow__index { color: var(--text-mute); text-align: center; font-size: var(--fs-small); }
.setrow__top { color: var(--ember); font-size: 0.7em; vertical-align: super; }
.setrow.is-extra .setrow__index { color: var(--seer); }

.resttimer {
  position: fixed;
  left: 50%;
  bottom: calc(env(safe-area-inset-bottom, 0px) + var(--sp-4));
  transform: translateX(-50%);
  z-index: var(--z-toast);
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-4);
  border: 1px solid var(--seer);
  border-radius: var(--r-lg);
  background: var(--ink-2);
  box-shadow: var(--shadow);
}
.resttimer__clock { font-size: var(--fs-h2); font-weight: 650; color: var(--seer); min-width: 3.5rem; }
.resttimer[data-state="done"] { border-color: var(--ember); }
.resttimer[data-state="done"] .resttimer__clock { color: var(--ember); }

/* A superset is one unit of work, so it gets one bracket around it. */
.superset {
  position: relative;
  padding-left: var(--sp-3);
  margin-bottom: var(--sp-3);
  border-left: 2px dashed var(--rune);
  border-radius: var(--r-sm);
}
.superset__label {
  margin: 0 0 var(--sp-2);
  font-size: var(--fs-micro);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--rune);
}

/* RPE is ten taps, not a dropdown: one gesture, and the whole scale is visible. */
.rpescale { display: grid; grid-template-columns: repeat(10, 1fr); gap: 2px; }
.rpescale__step { margin: 0; }
.rpescale__step input { position: absolute; opacity: 0; pointer-events: none; }
.rpescale__step span {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 40px;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  font-size: var(--fs-small);
  color: var(--text-dim);
  cursor: pointer;
}
.rpescale__step input:checked + span { background: var(--ember); border-color: var(--ember); color: var(--ember-ink); }
.rpescale__step input:focus-visible + span { outline: 2px solid var(--seer); outline-offset: 2px; }

.card.is-next { border-left-color: var(--ember); }


/* --------------------------------------------------------------------------
   13. Charts
   Hand-rolled SVG, so the colours come from the same tokens as everything else
   and dark mode needs no chart-specific code.
   -------------------------------------------------------------------------- */
.chart { display: block; width: 100%; height: auto; overflow: visible; }
.chart__line { stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; }
.chart__grid { stroke: var(--line-soft); stroke-width: 1; }
.chart__axis { fill: var(--text-mute); font: 500 10px var(--font-data); }
.chart__empty { fill: var(--text-mute); font: 500 12px var(--font-ui); }
.chart__dot { transition: r var(--dur) var(--ease); }
.chart__dot:hover, .chart__dot:focus-visible { r: 5.5; outline: none; }
.chartcard { padding: var(--sp-3) var(--sp-2); }

.spark { flex: none; width: 96px; height: 28px; }
.spark polyline { stroke-width: 1.5; stroke-linejoin: round; }

/* A horizontal strip of athlete buttons, scrollable rather than wrapped. */
.scroller { overflow-x: auto; scrollbar-width: none; padding-bottom: var(--sp-1); }
.scroller::-webkit-scrollbar { display: none; }
.scroller > * { flex: none; }

.charttip {
  position: absolute;
  z-index: var(--z-toast);
  padding: var(--sp-1) var(--sp-2);
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--ink-2);
  font: 600 var(--fs-small)/1 var(--font-data);
  pointer-events: none;
  white-space: nowrap;
}


/* --------------------------------------------------------------------------
   14. Offline
   -------------------------------------------------------------------------- */

/* The sync chip sits above the header, out of the way of both thumbs. It is the
   only thing that looks different about training with no signal, which is the
   point: the athlete should not have to think about it. */
.syncchip {
  position: fixed;
  top: calc(env(safe-area-inset-top, 0px) + var(--sp-2));
  left: 50%;
  transform: translateX(-50%);
  z-index: var(--z-toast);
  padding: var(--sp-1) var(--sp-3);
  border: 1px solid var(--warn);
  border-radius: 999px;
  background: var(--ink-2);
  color: var(--warn);
  font: 600 var(--fs-micro)/1.6 var(--font-data);
  letter-spacing: 0.04em;
  box-shadow: var(--shadow);
}
.syncchip[data-state="auth"] { border-color: var(--danger); color: var(--danger); }

/* A queued write shows a different spine from a saved one, so "it went through"
   and "it will go through" are never confused. */
.exercise[data-save="queued"] { border-left-color: var(--warn); }

.toast--update {
  border-color: var(--seer);
  color: var(--seer);
  cursor: pointer;
  font: 600 var(--fs-small)/1.4 var(--font-ui);
}


/* --------------------------------------------------------------------------
   15. Feedback and review
   -------------------------------------------------------------------------- */

/* The status ladder is the whole point of the feature-request board: a
   submitter has to be able to tell "not read yet" from "read, not doing it". */
.badge--status-submitted    { background: var(--seer-soft);  color: var(--seer); }
.badge--status-pending      { background: var(--ink-2);      color: var(--text-dim); }
.badge--status-in_review    { background: var(--rune-soft);  color: var(--rune); }
.badge--status-implementing { background: var(--ember-soft); color: var(--ember); }
.badge--status-implemented  { background: color-mix(in srgb, var(--ok) 18%, transparent); color: var(--ok); }
.badge--status-declined     { background: var(--danger-soft); color: var(--danger); }

/* A reply is someone else's voice, so it is set apart rather than merged into
   the surrounding text. */
.reply {
  border-left: 3px solid var(--seer);
  padding-left: var(--sp-3);
  color: var(--text-dim);
}

/* --------------------------------------------------------------------------
   16. Utilities
   These exist because the CSP has no 'unsafe-inline' in style-src, which blocks
   inline style attributes as well as <style> blocks. Templates therefore carry
   no `style=` — every spacing decision is a class. Keep this set small.
   -------------------------------------------------------------------------- */
.hero { padding: var(--sp-6) 0 var(--sp-5); }
.section { margin-top: var(--sp-5); }
.section__label { margin-bottom: var(--sp-3); }

.u-mt-2 { margin-top: var(--sp-2); }
.u-mt-3 { margin-top: var(--sp-3); }
.u-mt-5 { margin-top: var(--sp-5); }
.u-mb-0 { margin-bottom: 0; }

.text-small { font-size: var(--fs-small); }
.row--tight { gap: var(--sp-2); }
.card__meta { margin: 0; font-size: var(--fs-small); color: var(--text-dim); }

/* --------------------------------------------------------------------------
   17. Motion
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* --------------------------------------------------------------------------
   18. Print — a coach printing a plan should get something readable.
   -------------------------------------------------------------------------- */
@media print {
  .site-header, .nav, .btn, .syncchip, .resttimer { display: none !important; }
  body { background: #fff; color: #000; }
  .card { break-inside: avoid; box-shadow: none; border-color: #ccc; }
}
