:root {
  /* ============================================================
     ACTIVE THEME: "high-tech" (docs/design/tema-hightech-referens.html).
     :root IS the active theme — the failure mode of a missing theme class must be
     the correct theme, never a silent fallback. The preserved charcoal theme lives
     in .theme-charcoal below and applies ONLY when ThemeConfig.Active explicitly
     selects it (Theme/ThemeConfig.cs is THE single pointer; it also swaps the
     MudBlazor palette in RunAheadTheme.cs — keep both mirrors in sync).
     Glow discipline: glow is meaningful (state, pulse, system signature), never
     decoration. Charcoal turns every glow/gradient token off, so structural rules
     below are written once and themed by tokens only.
     ============================================================ */
  /* Brand tokens — single source; RunAheadTheme.cs HighTechPalette mirrors these. */
  --brand-bg:#050506; --brand-accent:#d8ba79; --brand-text:#f4f1ea;

  --bg:var(--brand-bg); --surface:#0d0d0f; --surface2:#131316; --border:#221f1a;
  --border-quiet:#161410;
  --text:var(--brand-text); --muted:#8f8a7e; --accent:var(--brand-accent);
  --accent-hi:#e6c983; --accent-lo:#bf9e5c; /* active-switch gradient stops */
  --red:#d64d3c;   /* CONTROL + pulse role (arrows, logout dot, system pulse) */
  --green:#5c9e6f;

  /* Neutral hierarchy: --text > --text-dim > --muted > --faint > --faintest.
     --text-dim sits between the reference's text-2 and muted so hover/dim states
     stay visibly distinct from both ends.
     LÄS/VISK role rule (spec §1.3, decision #166): text that must be READ to use the page
     (section labels, table headers, key names) takes the lifted --faint tone; text whose
     WHISPER is the point (a collapsed row's archive status, a version stamp, a timestamp)
     stays down at --faintest. Selectors elsewhere in this file that moved between the two
     roles point back to this comment instead of repeating it. */
  --text-dim:#c9c4b8;
  --faint:#8a857a; /* AA target (ContrastFloorTests): 3.2 -> 5.1:1 vs --surface2 */
  --faintest:#5a5648;

  /* Card/panel depth: vertical gradient in high-tech; charcoal flattens both stops. */
  --panel-top:#0d0d0f; --panel-bot:#0a0a0b; --panel-quiet:#08080a;

  /* Glow recipes (meaningful glow only) — copied from the reference, not reinvented.
     --glow-gold-soft is the reference's deliberately weaker sibling (alpha .4): the today-dot
     ring and the race number wear it, while --glow-gold (alpha .5) stays for active nav /
     stronger accents. */
  --glow-gold:0 0 6px rgba(216,186,121,.5);
  --glow-gold-soft:0 0 6px rgba(216,186,121,.4);
  --glow-gold-strong:0 0 12px rgba(216,186,121,.4);
  --glow-red:0 0 8px rgba(214,77,60,.7);
  --glow-swapped:0 0 10px rgba(224,138,46,.15);

  /* Ambient reactor glow (gold, viewport top) — background layer only, never on elements.
     The red counterpart is --pulse-halo below: it originates from the SystemBar's pulse dot
     (owner adjustment), so it lives on that element, not in this background stack. */
  --reactor:radial-gradient(ellipse 460px 180px at 50% -40px, rgba(216,186,121,.10), transparent 70%);
  --pulse-halo:radial-gradient(closest-side, rgba(214,77,60,.10), transparent);

  /* pass tags (identities preserved, toned into the theme; long no longer tracks
     --red, which is the control role in this theme — it gets its own warm ember) */
  --tag-long-bg:#180d08;     --tag-long-fg:#c77b52;
  --tag-thresh-bg:#0c1319;   --tag-thresh-fg:#4a90b8;
  --tag-interval-bg:#120e18; --tag-interval-fg:#8f7bc4;
  --tag-fasted-bg:#0a1410;   --tag-fasted-fg:var(--green);
  --tag-strength-bg:#17120a; --tag-strength-fg:var(--accent);
  --tag-rest-bg:#0d0d0d;     --tag-rest-fg:#5a5648;
  --tag-easy-bg:#0c120c;     --tag-easy-fg:#5c9e6f;
  --tag-race-bg:#17120a;     --tag-race-fg:var(--accent);

  /* Day-outcome status language (feature: veckovy). Function is an acceptance
     requirement: contrast vs #050506 — matched 6.4:1, swapped 7.6:1, extra 5.8:1,
     race 10.9:1 (all ≥3:1); missed deliberately muted (~2.4:1). Green/amber/blue
     also differ in LIGHTNESS, carrying separability under color-blindness. */
  --status-matched:#5c9e6f;
  --status-swapped:#e08a2e;
  --status-missed:#4d4d53;
  --status-extra:#4a90b8;
  --status-race:var(--accent); /* gold RESERVED for race, never swapped */
  --missed-line:#3a2420; --missed-text:#7a5248; /* missed goes warm dark red-brown */

  /* Day-header status bar: OWN tokens because high-tech paints the MATCHED line gold
     (state role, "statuslinje på aktiva dagar") while the card's matched text stays
     green — one token cannot serve both surfaces. */
  --daybar-matched:var(--accent);
  --daybar-swapped:var(--status-swapped);
  --daybar-extra:var(--status-extra);
  --daybar-missed:var(--missed-line);
  --daybar-neutral:#1e1c18;
  --daybar-matched-glow:var(--glow-gold);
  --daybar-swapped-glow:0 0 6px rgba(224,138,46,.5);
  --daybar-extra-glow:0 0 6px rgba(74,144,184,.5);

  /* Component role tokens (a var may carry a whole gradient; charcoal flattens). */
  /* Header vignette (reference .header): painted as a viewport-top ambient layer UNDER the
     reactor glow (owner adjustment) — an opaque background on the header element itself would
     occlude the gold radial and cut it off with a hard edge at the header's top boundary. */
  --header-grad:linear-gradient(180deg, #08080a, transparent 110px);
  --header-border:#17150f; /* hairline under the header, drawn as box-shadow (no layout impact) */
  --zoom-on-bg:linear-gradient(180deg, var(--accent-hi), var(--accent-lo));
  --zoom-on-fg:#080809;
  --nav-arrow-fg:var(--red);
  --ctrl-text:#c4877a;              /* logout text, dulled red-brown */
  --card-matched-border:#26332a;
  --card-extra-border:#223440;
  --card-swapped-top:#140f08; --card-swapped-bot:#0d0a06;
  --card-empty-text:#4a4638;

  /* Today landing page (feature: today-peprad). Highlight accent reuses the brand gold
     (--accent) as its base — a role token, not a new hue, so the daily highlight reads as the
     same "state" gold used elsewhere (never invented decoration). --race-days reuses
     --status-race directly (no separate token needed: race is already the gold role). */
  --highlight-accent:var(--accent);

  /* Today composition (K3a): WeekDots dot states + attention. Plan-free activity presence is
     its OWN role (never outcome semantics) even though it currently shares --muted's value —
     same precedent as --daybar-* being a separate family from --status-* despite overlap. */
  --neutral-activity:var(--muted);
  /* Future-day dot outline: deliberately distinct from --border (structural line) — a dot-only
     role, no existing token matches docs/design/today-referens.html's #26262a. */
  --dot-future-border:#26262a;
  /* Rest-day dot fill: distinct role from --daybar-neutral (that token means "future/no data"
     on the week-grid bar, not "rest") — no existing token matches the reference's #1c1a16. */
  --dot-rest-fill:#1c1a16;

  /* Today composition (K3b): LATEST card border. The reference's literal (#26332a) IS the app's
     existing --card-matched-border value — aliased, not duplicated, so both themes stay in sync
     through the token it already points at. */
  --border-latest:var(--card-matched-border);
}

/* ============================================================
   PRESERVED THEME: charcoal — the return point. A COMPLETE override group: every
   token :root defines is redefined here (TokenParityTests enforces it). Selected
   ONLY via ThemeConfig.Active = AppTheme.Charcoal; never a silent fallback.
   Values render pixel-identically to the pre-theme app: glows off, gradients
   flattened, theme-introduced elements not rendered (gated in components).
   RunAheadTheme.cs CharcoalPalette mirrors these values — keep in sync.
   ============================================================ */
.theme-charcoal {
  --brand-bg:#131315; --brand-accent:#d8ba79; --brand-text:#eceae6;

  --bg:var(--brand-bg); --surface:#1a1a1d; --surface2:#222226; --border:#2e2e33;
  --border-quiet:var(--border);
  --text:var(--brand-text); --accent:var(--brand-accent);
  --accent-hi:var(--accent); --accent-lo:var(--accent);
  --red:#c97060; --green:#7eb8a4;

  --text-dim:#b9b6ae;
  /* Tone lift + LÄS/VISK role rule (spec §1.2, decision #166; rule text lives once in
     :root's Neutral hierarchy comment above). --muted and --faint both move up to clear
     AA against --surface2 -- this also fixes the inverted hierarchy this group used to
     carry (--muted read DARKER than --faint). --faintest, previously an alias of --faint
     ("charcoal never had a fifth level"), gets its OWN value again: yesterday's --faint
     becomes today's whisper tone, so the fifth level returns now that --faint itself
     reads as READ text. */
  --muted:#a4a39c; /* AA target: 3.0 -> 6.3:1 vs --surface2 */
  --faint:#96958f; /* AA target: 3.1 -> 5.3:1 vs --surface2 */
  --faintest:#6f6e68;

  --panel-top:var(--surface); --panel-bot:var(--surface); --panel-quiet:var(--surface2);

  --glow-gold:none; --glow-gold-soft:none; --glow-gold-strong:none; --glow-red:none; --glow-swapped:none;
  --reactor:none; --pulse-halo:none;

  --tag-long-bg:#251a1a;     --tag-long-fg:var(--red);
  --tag-thresh-bg:#1a1f28;   --tag-thresh-fg:#7a9ec8;
  --tag-interval-bg:#221a28; --tag-interval-fg:#a07ec8;
  --tag-fasted-bg:#1a2520;   --tag-fasted-fg:var(--green);
  --tag-strength-bg:#252015; --tag-strength-fg:var(--accent);
  --tag-rest-bg:#1e1e1e;     --tag-rest-fg:var(--muted);
  --tag-easy-bg:#1c211c;     --tag-easy-fg:#9fbf8f;
  --tag-race-bg:#2a1d15;     --tag-race-fg:#d89b5a;

  --status-matched:#97C459;
  --status-swapped:#FAC775;
  --status-missed:#4d4d53;
  --status-extra:#85B7EB;
  --status-race:var(--accent);
  /* Charcoal's missed card was the dashed "empty" look (border + faint text) —
     pixel-identity beats the spec table's #4d4d53 here. */
  --missed-line:var(--border); --missed-text:var(--faint);

  --daybar-matched:var(--status-matched);
  --daybar-swapped:var(--status-swapped);
  --daybar-extra:var(--status-extra);
  --daybar-missed:var(--status-missed);
  --daybar-neutral:#33333a;
  --daybar-matched-glow:none; --daybar-swapped-glow:none; --daybar-extra-glow:none;

  --header-grad:none; --header-border:transparent; /* charcoal has no header vignette */
  --zoom-on-bg:var(--surface);
  --zoom-on-fg:var(--accent);
  --nav-arrow-fg:var(--text-dim);
  --ctrl-text:var(--text); /* matches Mud's text-primary, today's outlined-button text */
  --card-matched-border:var(--border);
  --card-extra-border:var(--border);
  --card-swapped-top:var(--surface); --card-swapped-bot:var(--surface);
  --card-empty-text:var(--faint);

  /* Charcoal flattens the highlight accent to a neutral line (the gold accent is high-tech's
     STATE treatment; charcoal's state role is not gold — cf. its green --daybar-matched).
     Reuses the border line tone, same mapping as --missed-line above. */
  --highlight-accent:var(--border);

  --neutral-activity:var(--muted);
  --dot-future-border:var(--border);
  --dot-rest-fill:var(--surface2);

  --border-latest:var(--card-matched-border);
}

/* Scale root (decision #165): the rem scale's single source of truth. Every other
   font-size in this file is a rem multiple of this value — the px pin
   (tests/RunAhead.Tests/Components/FontScaleTests.cs) enforces that this is the ONLY
   px font-size declaration left in app.css. Snap (spec §1.1, decision #166): candidate A,
   16px -> 17px, owner-judged against real pixels (paired with the tone lift below). Candidate
   B (18px) is the one-line path if the drift later calls for a second snap — BACKLOG. */
html { font-size: 17px; }

html, body {
  background: var(--bg);
  color: var(--text);
  font-family: 'DM Mono', monospace;
}

/* The theme wrapper (MainLayout's outermost element, encloses the MudBlazor providers
   so popovers/dialogs inherit the token group). Carries the ambient reactor glow as a
   background layer — never on elements. Flex column so the SystemBar signature sits at
   the bottom of short pages. */
.runahead-app {
  min-height:100dvh;
  display:flex; flex-direction:column;
  background-color:var(--bg);
  /* Layer order: reactor glow ON TOP of the header vignette, so the gold radial flows
     unbroken through the header row (owner adjustment — no hard edge, full glow size). */
  background-image:var(--reactor), var(--header-grad);
  background-attachment:fixed;
  background-repeat:no-repeat;
}
.runahead-app > .runahead-shell { flex:1; width:100%; }

/* The system signature bar: an always-visible fixed footer (owner adjustment), same width
   discipline as the shell. The gradient backdrop fades scrolling content out underneath it.
   Pulse = meaningful glow (the system is working for you). Only rendered in high-tech, so
   charcoal is untouched by the fixed positioning. */
/* THREE ZONES, GEOMETRICALLY (owner click-round fix). This was a flex row where .line's flex:1
   ate every pixel of slack, so the human zone clustered left against the version and left a hole
   before the system signature -- the zone decision said left/MIDDLE/right and the layout only
   said left. Grid with `1fr auto 1fr` centres the middle column against the BAR, not against
   whatever space the neighbours left over, and it keeps doing so when the right zone is absent
   (signed out, or the charcoal theme): the third column simply stays empty. At narrow desktop
   widths the fr columns shrink to their content and the middle stops being perfectly centred
   rather than overlapping a neighbour -- readability wins over centring, per the same fix. */
.runahead-app .sysbar { position:fixed; bottom:0; left:0; right:0; z-index:5; max-width:1440px; margin:0 auto; padding:10px 20px 14px; display:grid; grid-template-columns:1fr auto 1fr; align-items:center; column-gap:14px; background:linear-gradient(180deg, transparent, var(--bg) 55%); }
/* Both flanks stretch so their quiet rule can fill the gap between the version (or the
   signature) and the centred zone. The rules are a PAIR: before the centring fix there was one
   gap and one rule, and centring created two symmetric gaps while the rule stayed on the right
   flank only -- the left gaped empty and the bar read lopsided. Same gap value on both sides so
   the framing is symmetric around the middle. */
.runahead-app .sysbar-left { justify-self:stretch; min-width:0; display:flex; align-items:center; gap:10px; }
.runahead-app .sysbar-right { justify-self:stretch; min-width:0; display:flex; align-items:center; gap:10px; }
.runahead-app .sysbar .line { flex:1; height:1px; background:linear-gradient(90deg, transparent, var(--border), transparent); }
.runahead-app .sysbar .lbl { font-size:0.625rem; color:var(--faintest); letter-spacing:.2em; }
.runahead-app .sysbar .ver { font-size:0.625rem; color:var(--faintest); letter-spacing:.08em; }
/* Middle zone (owner click-round fix: the feedback link used to sit right after the version with
   only the row's own 10px gap, same-ish tone, reading as one metadata string). margin-left adds
   real breathing room on top of that gap -- 10px (row) + 14px (here) = 24px, the same zone-gap
   value .app-header already uses -- so the link visibly belongs to a DIFFERENT zone than the
   version, not just a different color. A flex row of link SLOTS: FEEDBACK, CONTACT, TERMS, then
   the "Created by Refi AB" signature (SEO sweep, design spec 2026-08-08-seo-svep-design.md Del 2)
   -- categorical order (action, navigation, navigation, provenance), no redesign needed. The
   house " · " idiom (used inline throughout, e.g. ActivityDetail's hero meta row) separates any
   two inhabitants via ::before on non-first children -- so the signed-out view (Feedback absent)
   loses its leading dot by itself, no hand-written separator logic. */
.runahead-app .sysbar-mid { justify-self:center; min-width:0; display:flex; align-items:center; }
/* white-space:pre is load-bearing, not decoration (owner click-round fix): the ::before content's
   LEADING space sits at the start of a flex item's line box, where normal white-space processing
   strips it -- which rendered "Contact· Terms", the dot glued to the word before it and floating
   away from the word after. `pre` preserves both spaces so the separator breathes evenly on each
   side, per the house separator form. */
.runahead-app .sysbar-mid > * + *::before { content:" · "; color:var(--faintest); white-space:pre; }
/* Feedback link (design spec 2026-08-03-epost-design.md §Task E6): the .guide idiom's PHILOSOPHY
   (quiet text link, never an icon without a label) applied to its own scoped selector -- never
   the bare .guide class itself, which belongs to onboarding/controls-row/guards/investigations
   surfaces. Renders in BOTH themes (its own AuthorizeView sits outside the IsHighTech gate in
   SystemBar.razor), unlike .lbl/.pulse/.line above which are high-tech-only. Lives in the middle
   zone (.sysbar-mid): --faint is one hierarchy step lighter than the version's --faintest
   (version = metadata, links = actions) -- the same token the link already carried, the zone
   wrapper is what actually fixes the "melts into the version" complaint. */
.runahead-app .sysbar .feedback-link { font-size:0.625rem; color:var(--faint); letter-spacing:.08em; cursor:pointer; }
.runahead-app .sysbar .feedback-link:hover { color:var(--text-dim); }
/* Contact/Terms/signature (SEO sweep, reference NOTES 7): same quiet-link tone as the feedback
   link above -- "in the same link tone as its neighbours" per spec -- so a plain <a> in this
   zone needs no class of its own. Both render in BOTH auth states (public trust signals). */
.runahead-app .sysbar-mid a { font-size:0.625rem; color:var(--faint); letter-spacing:.08em; text-decoration:none; }
.runahead-app .sysbar-mid a:hover { color:var(--text-dim); }
/* The whole-phrase signature link (reference NOTES 7). It carried a hairline border-bottom on the
   theory that an underline-free link reads as plain text at this size; the owner's click round
   rejected it, and the reason generalises: the signature rested UNDERLINED while Feedback,
   Contact and Terms rested clean, so the one link in the row that was decorated was the only one
   nobody needed a hint about -- an inconsistency that reads as a mistake rather than as an
   affordance. The zone's own rest state IS the affordance; hover carries the rest. Color stays
   explicit (not inherited) because an anchor's UA default otherwise wins in MoreSheet's version
   row, where no ".sysbar-mid a" rule applies. */
.runahead-app .sig-link { color:var(--faint); text-decoration:none; }
.runahead-app .sysbar .pulse { position:relative; width:6px; height:6px; border-radius:50%; background:var(--red); box-shadow:var(--glow-red); animation:sysbar-pulse 2.4s ease-in-out infinite; }
/* The ambient red halo radiates from the pulse dot itself (owner adjustment). The sysbar is a
   fixed stacking context, so the negative z-index puts the halo ABOVE the bar's backdrop and
   the content edge, but below the line/label/dot. */
.runahead-app .sysbar .pulse::after { content:""; position:absolute; left:50%; top:50%; width:460px; height:300px; transform:translate(-50%, -50%); background:var(--pulse-halo); pointer-events:none; z-index:-1; }
@keyframes sysbar-pulse { 0%, 100% { opacity:1; } 50% { opacity:.35; } }
/* The signature stays visible under reduced motion — only the pulsing stops. Covers both
   homes of the one signature (MG4: .m-pulse is the mobile header's copy of this same dot). */
@media (prefers-reduced-motion: reduce) {
  .runahead-app .sysbar .pulse, .runahead-app .m-sys .m-pulse { animation:none; opacity:1; }
}

h1, h2, h3, h4, h5, h6 { font-family: 'Fraunces', serif; }

/* The single app content container (arch §8): centered wide frame, LEFT-aligned content inside.
   1440px chosen within the spec's 1400-1600 band; fine-tune against real content if needed. */
.runahead-shell { max-width: 1440px; margin: 0 auto; padding: 16px 20px 48px; }

/* ---------- App shell: one-row header (wordmark home link · nav · account) ---------- */
/* Header hairline from the reference; the line is a box-shadow so charcoal (transparent)
   keeps today's exact layout — no border height added. The vignette itself lives in
   .runahead-app's background stack, under the reactor glow. */
.runahead-shell .app-header { display:flex; align-items:center; gap:24px; padding:6px 0 18px; box-shadow:0 1px 0 var(--header-border); }
/* Shared by the desktop header AND the mobile header (MG4) — one wordmark style, two homes;
   .wordmark-sm (mobile) only overrides font-size. */
/* The m-header variant is scoped to .runahead-app (not the shell): the mobile header lives
   OUTSIDE the padded shell — viewport chrome, edge to edge (owner adjustment). */
.runahead-shell .app-header .wordmark, .runahead-app .m-header .wordmark { font-family:'Fraunces',serif; font-weight:700; font-size:1.375rem; color:var(--brand-text); text-decoration:none; line-height:1; }
.runahead-shell .app-header .wordmark span, .runahead-app .m-header .wordmark span { font-weight:400; font-style:italic; color:var(--brand-accent); letter-spacing:0.02em; text-shadow:var(--glow-gold-strong); }
.runahead-shell .app-nav { display:flex; align-items:center; gap:4px; }
.runahead-shell .app-nav a { position:relative; font-size:0.8125rem; color:var(--muted); text-decoration:none; padding:6px 10px 8px; border-bottom:2px solid transparent; letter-spacing:0.02em; }
.runahead-shell .app-nav a:hover { color:var(--text-dim); }
/* Active item = the view's identity: lighter text + gold underline with meaningful glow
   (state role, never red). The line is an ::after so the glow hugs the 2px line, not the
   whole link box; charcoal's --glow-gold:none renders exactly the old flat underline.
   bottom:-2px because the ::after positions against the padding box (the 2px transparent
   border strip lies outside it), so -2px re-occupies exactly the strip the old border filled. */
.runahead-shell .app-nav a.active { color:var(--text); }
.runahead-shell .app-nav a.active::after { content:""; position:absolute; left:0; right:0; bottom:-2px; height:2px; background:var(--accent); box-shadow:var(--glow-gold); }
.runahead-shell .app-account { display:flex; align-items:center; gap:12px; margin-left:auto; white-space:nowrap; }
.runahead-shell .app-account .email { font-size:0.75rem; color:var(--muted); }
/* Control/pulse role: the logout status dot (high-tech only — the markup is gated). */
.runahead-shell .app-account .logout-dot { display:inline-block; width:5px; height:5px; border-radius:50%; background:var(--red); box-shadow:var(--glow-red); margin-right:7px; vertical-align:middle; }
.runahead-shell .app-account .mud-button-root { color:var(--ctrl-text); }

/* ---------- Landing page (/, design spec 2026-08-02-landing-login-design.md §L1) ----------
   Signed-out root content: hero (the real h1), the moved login form (.f-* field family), and the
   optional BETA status block, in that order. Unlike the rest of this file's rules these are NEVER
   gated by .authed — Landing only ever renders for a signed-out visitor (an authed one bounces to
   /today before this content paints), so no auth-state selector is needed here.
   Left-aligned, prose width per the house's document language (arch §9) — never a centered
   marketing layout, so no margin:auto centering (the reference mockup's frame was much narrower
   than this app's real 1440px shell; auto-centering there would read as a huge marketing island
   here). */
.runahead-shell .landing-hero { margin:56px 0 0; max-width:640px; }
/* .wordmark's rule is scoped to .app-header/.m-header, so the hero mark needs its own font
   declaration — same family/weight/color, hero scale (44px vs the header's 22px). */
.runahead-shell .landing-mark { font-family:'Fraunces',serif; font-weight:700; font-size:2.75rem; line-height:1.1; color:var(--brand-text); margin:0; }
.runahead-shell .landing-mark span { font-weight:400; font-style:italic; color:var(--brand-accent); letter-spacing:0.02em; text-shadow:var(--glow-gold-strong); }
.runahead-shell .landing-lead { font-family:'Fraunces',serif; font-weight:600; font-size:1.375rem; color:var(--text); margin:14px 0 0; }
/* Brödtext in text-dim prose (design spec §L1 point 1, verbatim requirement). */
.runahead-shell .landing-body { font-size:0.78125rem; color:var(--text-dim); line-height:1.7; margin:14px 0 0; max-width:58ch; }

.runahead-shell .landing-login { margin:36px 0 0; max-width:640px; }
.runahead-shell .landing-card { background:linear-gradient(180deg, var(--panel-top), var(--panel-bot)); border:1px solid var(--border); border-radius:12px; padding:20px; max-width:420px; }
/* House label-style fields (design spec §L1 point 2): faintest uppercase labels over own-styled
   inputs, replacing MudBlazor's floating labels, which don't survive this layout. Not scoped
   under .landing-card — the .f-* family is the house's general form language, reusable wherever
   a form needs it next, not a landing-only one-off. */
/* LÄS role, moved up from --faintest (:root Neutral hierarchy comment, spec §1.3): a field
   label must be read to fill in the field. */
.runahead-shell .f-lbl { display:block; font-size:0.625rem; letter-spacing:.16em; color:var(--faint); text-transform:uppercase; margin-bottom:5px; }
/* Protected min-width (the tysta-klipp-regeln, silent-clip rule): the field shrinks with its
   container but never below a readable placeholder width. */
.runahead-shell .f-input { background:var(--panel-quiet); border:1px solid var(--border); border-radius:8px; padding:10px 12px; color:var(--text-dim); font-size:0.8125rem; width:100%; min-width:16ch; box-sizing:border-box; margin-bottom:14px; font-family:inherit; }
.runahead-shell .f-input:focus { outline:none; border-color:var(--accent-lo); }
.runahead-shell .landing-btn { display:inline-block; border:1px solid var(--accent-lo); border-radius:8px; padding:9px 22px; font-size:0.6875rem; letter-spacing:.08em; text-transform:uppercase; color:#080809; cursor:pointer; background:linear-gradient(180deg, var(--accent-hi), var(--accent-lo)); font-weight:600; font-family:inherit; }
.runahead-shell .landing-btn:disabled { opacity:.6; cursor:default; }
.runahead-shell .landing-error { font-size:0.75rem; color:var(--red); margin:10px 0 0; }
.runahead-shell .landing-reg-row { font-size:0.6875rem; color:var(--faint); margin-top:14px; }
.runahead-shell .landing-reg-row a { color:var(--accent); text-decoration:none; }
/* "Forgot password? ›" quiet row (design spec Task E4, reference epost-referens.html §3):
   dampened, sits below Log in so it never competes with the primary action. */
.runahead-shell .landing-forgot-row { margin-top:10px; }

/* ---------- Email-flow mid-pages (/verify-email, /invite, /forgot-password, /reset-password) ----
   design spec Task E4, docs/design/epost-referens.html §1-3. These reuse the landing card idiom
   verbatim (.landing-card/.f-lbl/.f-input/.landing-btn/.landing-error, all above) per the
   reference's own note: "mellansidornas/formkortens gemensamma form (landningens kortidiom)".
   Only the genuinely new pieces (heading/body typography, success/error accents, quiet links) get
   their own classes here. */
.runahead-shell .mid { max-width:420px; }
.runahead-shell .mid-h3 { font-family:'Fraunces',serif; font-weight:600; font-size:1.375rem; margin:0 0 10px; color:var(--text); }
.runahead-shell .mid-body { color:var(--text-dim); font-size:0.78125rem; line-height:1.65; margin:0 0 20px; }
.runahead-shell .mid-body .addr { color:var(--text); }
.runahead-shell .ok-line { display:flex; align-items:center; gap:8px; color:var(--green); font-size:0.8125rem; margin:0 0 14px; }
.runahead-shell .sent-quiet { color:var(--muted); font-size:0.75rem; line-height:1.6; margin:14px 0 0; }
.runahead-shell .quietlink { color:var(--faint); font-size:0.75rem; border-bottom:1px dotted var(--faint); text-decoration:none; }
.runahead-shell .quietlink:hover { color:var(--text-dim); }

/* Status block (design spec §L1 point 3, NOTES 6): structurally freestanding after a quiet
   divider — BETA in gold label style + faintest separator + faint text, the same typographic
   role as the quota-line elsewhere in the app. The page renders fully without it (LandingTests'
   structural test); removing it later is a content edit, never a layout one. */
.runahead-shell .landing-status { margin:44px 0 0; max-width:640px; border-top:1px solid var(--border-quiet); padding-top:16px; }
.runahead-shell .landing-lbl-gold { font-size:0.625rem; letter-spacing:.16em; color:var(--accent); text-transform:uppercase; }
.runahead-shell .landing-sep { color:var(--faintest); margin:0 6px; }
.runahead-shell .landing-tx { font-size:0.71875rem; color:var(--faint); line-height:1.6; }

/* View head: controls only (no titles exist) — compact, left-aligned. */
.runahead-shell .controls-row { display:flex; align-items:center; gap:8px; flex-wrap:wrap; margin-bottom:16px; }
/* Prose stays readably narrow inside the wide frame; empty space falls to the RIGHT. */
.runahead-shell .prose-col { max-width:720px; }
/* Prominent instance identity for detail views (never a static view name). */
.runahead-shell .instance-label { font-family:'Fraunces',serif; font-size:1.375rem; font-weight:600; color:var(--text); }
/* The controls-row range text (between the step arrows) — a plain span so the shell's
   `p { margin-top }` rule can't push it off the row's vertical midline (reference .range). */
.runahead-shell .wk-range { font-size:0.75rem; color:var(--faint); letter-spacing:.12em; }
/* Mobile-format companion span to .wk-range (mobile 1.5 Task 3, design §4 NOTES 5-6): same visual
   styling, hidden above the breakpoint — the 768px block below swaps which of the two is shown. */
.runahead-shell .wk-range-compact { font-size:0.75rem; color:var(--faint); letter-spacing:.12em; display:none; }
/* Discrete week-step arrows (replaces the big PREVIOUS/NEXT buttons). */
.runahead-shell .wk-weeknav { background:transparent; border:1px solid var(--border); border-radius:6px; color:var(--nav-arrow-fg); font:inherit; font-size:0.875rem; line-height:1; padding:4px 10px; cursor:pointer; }
.runahead-shell .wk-weeknav:hover { color:var(--text); }
/* Pager group (mobile 1.5 Task 3, design §4 NOTES 5): wraps the ‹ range › pager unit so the
   mobile breakpoint can push it right while the zoom switch stays left (space-between on
   .controls-row below). display:contents keeps desktop pixel-identical — the wrapper never
   participates in the desktop flex row, it only exists as a CSS grouping hook. */
.runahead-shell .wk-pager { display:contents; }

/* PagerControl (plan Task P1, spec §1.1, reference NOTES 1): shared dumb pager, placed by the
   consumer directly after the .datalist frame -- own control, own CSS, same "MudBlazor is for
   behavior-heavy primitives only" reasoning as .datalist-refresh. Button form borrows the
   .wk-weeknav grammar (same border/radius/color, quiet until hovered) rather than duplicating it
   under a new name -- this IS the week-nav's prev/next language, reused for a second surface. */
.runahead-shell .pager { display:flex; align-items:center; justify-content:center; gap:14px; padding:10px 0 0; }
.runahead-shell .pager button {
  background:transparent; border:1px solid var(--border); border-radius:6px; color:var(--nav-arrow-fg);
  font:inherit; font-size:0.875rem; line-height:1; padding:4px 11px; cursor:pointer;
}
.runahead-shell .pager button:hover:not(:disabled) { color:var(--text); }
.runahead-shell .pager button:disabled { opacity:.35; cursor:default; }
/* Fixed min-width counter (same muscle-memory reasoning as .wk-range-compact): the arrows must
   not drift when the digit count changes between "1–25 of 132" and "126–132 of 132". */
.runahead-shell .pager .range { font-size:0.65625rem; letter-spacing:.1em; color:var(--faint); min-width:14ch; text-align:center; }

.runahead-shell p { color: var(--muted); margin-top: 12px; }

h1:focus {
    outline: none;
}

.runahead-shell .tag {
  display:inline-block; font-size:0.5625rem; letter-spacing:0.1em; text-transform:uppercase;
  padding:2px 7px; border-radius:2px; margin-right:6px; font-weight:500; white-space:nowrap;
}
.runahead-shell .tag-long     { background:var(--tag-long-bg);     color:var(--tag-long-fg); }
.runahead-shell .tag-thresh   { background:var(--tag-thresh-bg);   color:var(--tag-thresh-fg); }
.runahead-shell .tag-interval { background:var(--tag-interval-bg); color:var(--tag-interval-fg); }
.runahead-shell .tag-fasted   { background:var(--tag-fasted-bg);   color:var(--tag-fasted-fg); }
.runahead-shell .tag-strength { background:var(--tag-strength-bg); color:var(--tag-strength-fg); }
.runahead-shell .tag-rest     { background:var(--tag-rest-bg);     color:var(--tag-rest-fg); }
.runahead-shell .tag-easy     { background:var(--tag-easy-bg);     color:var(--tag-easy-fg); }
.runahead-shell .tag-race     { background:var(--tag-race-bg);     color:var(--tag-race-fg); }

/* ============================================================
   Merged week view (feature: veckovy). Two zoom levels share the
   status language above (Task 6). Translated from
   docs/design/veckovy-referens-v2.html; Tasks 7/9 build the day
   components that consume these classes.
   ============================================================ */

/* ---------- Vecka (single week, plan | outcome workspace) ---------- */
.runahead-shell .wk-title  { font-size:0.8125rem; margin-top:3px; color:var(--text); } /* Vecka title, 400-weight */
.runahead-shell .wk-detail { font-size:0.75rem; margin-top:2px; color:var(--muted); line-height:1.6; }
.runahead-shell .wk-delta { font-size:0.6875rem; color:var(--faint); margin-top:2px; } /* small numbers, never a flag */
.runahead-shell .wk-status-chip { font-size:0.6875rem; }

/* ---------- Zoom switcher (sits in the view header, Vecka | Block) ---------- */
.runahead-shell .zoom { display:inline-flex; border:1px solid var(--border); border-radius:8px; overflow:hidden; }
.runahead-shell .zoom button {
  background:transparent; color:var(--muted); border:0; padding:7px 16px;
  font:inherit; font-size:0.75rem; cursor:pointer;
}
.runahead-shell .zoom button.active { background:var(--zoom-on-bg); color:var(--zoom-on-fg); }

/* ---------- Block (multi-week overview, replaces Schedule) ---------- */
.runahead-shell .wk-block {
  display:grid; grid-template-columns:92px repeat(7, minmax(0,1fr)); gap:4px; margin-bottom:4px;
}
.runahead-shell .wk-block > * { align-self:start; } /* cards take natural height, no stretch (v2 correction) */
.runahead-shell .wk-dayhead { text-align:center; font-size:0.6875rem; color:var(--faint); padding:4px 0; }
.runahead-shell .wk-gutter { padding:6px 8px; }
.runahead-shell .wk-gutter .wk-wk { font-size:0.75rem; }
.runahead-shell .wk-gutter .wk-label { font-size:0.6875rem; color:var(--muted); } /* editable week title */
.runahead-shell .wk-gutter .wk-origin { font-size:0.6875rem; color:var(--faint); } /* rolling | countdown */
/* Fully paused week's gutter (design §4 / reference NOTES 5): replaces the (otherwise empty)
   label slot with a muted "paused" — a paused week is also PlanFree, so origin never renders
   here either. Partial weeks carry no gutter marking (the day cells carry it). */
.runahead-shell .wk-gutter .wk-paused { font-size:0.6875rem; color:var(--faint); letter-spacing:.06em; }
.runahead-shell .wk-gutter .wk-vol { font-size:0.6875rem; color:var(--faint); }
.runahead-shell .wk-gutter.current { border-left:2px solid var(--accent); box-shadow:var(--glow-gold); }
.runahead-shell .wk-gutter.current .wk-wk { color:var(--accent); }
.runahead-shell .wk-cell {
  background:var(--surface); border:1px solid var(--border); border-radius:6px;
  padding:5px 6px; min-height:52px;
}
.runahead-shell .wk-cell .wk-bar { height:2px; border-radius:1px; margin-bottom:4px; background:var(--border); } /* future: neutral */
.runahead-shell .wk-cell .wk-t { font-size:0.6875rem; }
.runahead-shell .wk-cell .wk-v { font-size:0.6875rem; color:var(--muted); }
.runahead-shell .wk-cell .wk-v.future { color:var(--text-dim); }
.runahead-shell .wk-cell.rest { background:var(--bg); border-color:var(--border); opacity:.55; }
.runahead-shell .wk-cell.missed { background:transparent; border-style:dashed; border-color:var(--border); }
.runahead-shell .wk-cell.missed .wk-t { opacity:.6; }
.runahead-shell .wk-cell.race { border-color:var(--status-race); }
/* A day with no row at all (planless mode §4 / reference NOTES 5): no VILA card exists to draw
   on, so the day is a quiet transparent cell — never the active-look default background. */
.runahead-shell .wk-cell.blank { background:transparent; border-color:var(--border-quiet); }

/* ---------- Vecka mode: horizontal two-zone grid (feature: veckovy-horisontell, v2 reference) ---------- */
.runahead-shell .wk-week { display:grid; grid-template-columns:32px repeat(7, minmax(0,1fr)); gap:7px; }
/* CRITICAL: align-self:start so cards take natural height (no stretch to row height). */
.runahead-shell .wk-week > * { align-self:start; }
.runahead-shell .wk-dhead { text-align:center; padding:8px 2px; }
.runahead-shell .wk-dhead b { font-size:0.875rem; font-weight:600; display:block; }
.runahead-shell .wk-dhead span { font-size:0.75rem; color:var(--muted); }
.runahead-shell .wk-daybar { height:2px; margin-top:7px; border-radius:1px; background:var(--daybar-neutral); } /* future/neutral */
.runahead-shell .wk-daybar.matched { background:var(--daybar-matched); box-shadow:var(--daybar-matched-glow); }
.runahead-shell .wk-daybar.swapped { background:var(--daybar-swapped); box-shadow:var(--daybar-swapped-glow); }
.runahead-shell .wk-daybar.extra   { background:var(--daybar-extra);   box-shadow:var(--daybar-extra-glow); }
.runahead-shell .wk-daybar.missed  { background:var(--daybar-missed); }
/* Race already owned gold; matched joins it on the LINE level in high-tech (state role) —
   the cards below disambiguate. */
.runahead-shell .wk-daybar.race    { background:var(--status-race); box-shadow:var(--daybar-matched-glow); }
/* Planless (design §4 / reference NOTES 3+6): activity PRESENCE, never an outcome — reuses
   --neutral-activity (Today's dot-activity precedent) and deliberately carries NO glow. */
.runahead-shell .wk-daybar.activity { background:var(--neutral-activity); }
.runahead-shell .wk-zonelabel { display:flex; align-items:center; justify-content:center; }
.runahead-shell .wk-zonelabel span { font-size:0.6875rem; color:var(--faint); writing-mode:vertical-rl; transform:rotate(180deg); letter-spacing:.1em; }
.runahead-shell .wk-stack { display:flex; flex-direction:column; gap:6px; }
/* Flex column so every child (status chip, figures, the relink link) stacks on its own line —
   otherwise the inline StatusChip span and the MudMenu activator sit side by side. */
.runahead-shell .wk-card { background:linear-gradient(180deg, var(--panel-top), var(--panel-bot)); border:1px solid var(--border); border-radius:8px; padding:9px; display:flex; flex-direction:column; align-items:flex-start; }
.runahead-shell .wk-card.matched { border-color:var(--card-matched-border); }
.runahead-shell .wk-card.extra   { border-color:var(--card-extra-border); }
.runahead-shell .wk-card.rest { background:var(--panel-quiet); border-color:var(--border-quiet); opacity:.5; }
.runahead-shell .wk-card.empty { border-style:dashed; border-color:var(--border); background:transparent; color:var(--card-empty-text); text-align:center; align-items:center; justify-content:center; gap:6px; min-height:44px; }
/* Missed: same quiet dashed layout as empty, but the theme's missed hue (charcoal maps
   the tokens back to border/faint = the old empty look, pixel-identical). */
.runahead-shell .wk-card.missed { border-style:dashed; border-color:var(--missed-line); background:transparent; color:var(--missed-text); text-align:center; align-items:center; justify-content:center; gap:6px; min-height:44px; }
/* Swapped: the ONE glowing card — the week's deviation signal (amber, never gold). */
.runahead-shell .wk-card.swapped { background:linear-gradient(180deg, var(--card-swapped-top), var(--card-swapped-bot)); border-color:var(--status-swapped); box-shadow:var(--glow-swapped); }
.runahead-shell .wk-card.race { border-color:var(--status-race); }       /* gold: race only */
/* Delvis pausad vecka (design §4 / reference NOTES 3/5): a TYST PAUSED cell replacing the dashed
   "—" — no ram-dramatik, faint text carries the readability. Same panel-quiet/border-quiet
   language as the fully paused field below, at card scale. */
.runahead-shell .wk-card.paused { align-items:center; justify-content:center; min-height:44px; background:var(--panel-quiet); border-color:var(--border-quiet); }
.runahead-shell .wk-card.paused span { font-size:0.625rem; color:var(--faint); letter-spacing:.08em; }
/* An ACTUAL-zone card with an activity renders as <a href> (real navigation to the detail page,
   not onclick-only) — strip the browser's link styling so it stays visually identical to the
   non-linking .wk-card divs (rest/missed/no-activity), just with a pointer cursor. */
.runahead-shell a.wk-card { text-decoration:none; color:inherit; cursor:pointer; }
.runahead-shell .wk-relink { font-size:0.6875rem; color:var(--text-dim); cursor:pointer; }

/* Planless PLAN zone (design §4 / reference NOTES 2): the week's ONE quiet field, replacing the
   seven PLAN cells. Today-quietcard form language (--panel-quiet/--border-quiet). Explicit
   placement 2 / span 7 (reference-literal): the field owns the seven day columns regardless of
   what auto-placement would do if markup were ever inserted between the zonelabel and it.
   PlanPause (design §4 / reference NOTES 1): a fully paused week reuses this EXACT shape — one
   shared selector list rather than duplicating declarations, so the two forms can never drift;
   only the text (WeekGrid.razor) carries the extra knowledge. */
.runahead-shell .wk-planfree-field, .runahead-shell .wk-paused-field { grid-column:2 / span 7; display:flex; flex-direction:column; align-items:center; justify-content:center; gap:3px; background:var(--panel-quiet); border:1px solid var(--border-quiet); border-radius:8px; padding:14px; min-height:44px; text-decoration:none; }
.runahead-shell .wk-planfree-field .pf-title, .runahead-shell .wk-paused-field .pf-title { font-size:0.75rem; color:var(--muted); }
.runahead-shell .wk-planfree-field .pf-sub, .runahead-shell .wk-paused-field .pf-sub { font-size:0.6875rem; color:var(--faint); }

.runahead-shell .wk-week-scroll { overflow-x:auto; }

/* ---------- Today landing page (route /today, feature: today-peprad + today-composition) ----------
   Full bespoke composition (K3b), translated structurally from docs/design/today-referens.html
   into the shell's existing token vocabulary rather than inventing a parallel one: reference
   --panel-hi/--panel-lo/--label/--text-faint/--text-dim map onto the app's established
   --panel-top/--panel-bot/--faintest/--faint/--muted (K3a's neutral-hierarchy note above);
   reference --matched/--amber map onto the week grid's own --status-matched/--status-swapped
   (StatusChip, reused by LatestCard's marker) rather than duplicate literals. */
.runahead-shell .today-load-error { color:var(--card-empty-text); padding:10px 0; }

.runahead-shell .page { position:relative; overflow:hidden; }
/* Ambient gold wash over the page top — reuses the same --reactor recipe as the app-wide
   background layer (never a new color), so it also goes --reactor:none in charcoal for free. */
.runahead-shell .halo { position:absolute; top:-40px; left:20%; width:380px; height:160px; background:var(--reactor); pointer-events:none; }

.runahead-shell .toprow { display:flex; justify-content:space-between; align-items:baseline; margin-bottom:14px; }
.runahead-shell .date { font-size:0.75rem; color:var(--faint); letter-spacing:.12em; text-transform:uppercase; }
.runahead-shell .race-label { font-size:0.625rem; color:var(--faint); letter-spacing:.14em; text-transform:uppercase; }
/* Race countdown: one line, gold day-count with the soft glow (state/goal role, reuses --accent
   directly — --status-race already points at it, kept separate per the day-header precedent). */
.runahead-shell .race-days { font-size:0.9375rem; color:var(--accent); margin-left:10px; text-shadow:var(--glow-gold-soft); }
.runahead-shell .race-unit { font-size:0.6875rem; color:var(--text-dim); margin-left:4px; }

.runahead-shell .maingrid { display:grid; grid-template-columns:1.7fr 1fr; gap:10px; margin-bottom:12px; }
.runahead-shell .rightcol { display:flex; flex-direction:column; gap:10px; }

/* TODAY hero / LATEST hero (plan-free): shared card shell. Rendered as either <div> (TodayHero's
   quiet branch) or <a> (LatestCard, the plan-free empty-account fallback) — display:block plus
   inherited text color/no-underline make both read identically. */
.runahead-shell .hero {
  background:linear-gradient(180deg, var(--panel-top), var(--panel-bot)); border:1px solid var(--border);
  border-radius:10px; padding:16px; position:relative; display:block; text-decoration:none; color:inherit;
}
/* Quiet state: no planned session, or (LATEST) no activity yet. Drops the gold line entirely —
   the quiet panel tone IS the state, not a dimmed-down active card. */
.runahead-shell .hero.quiet { background:var(--panel-quiet); border-color:var(--border-quiet); }
.runahead-shell .hero-line { height:2px; background:var(--accent); box-shadow:var(--glow-gold); border-radius:1px; position:absolute; top:0; left:16px; right:16px; }
.runahead-shell .chip { font-size:0.6875rem; letter-spacing:.06em; margin-top:10px; }
.runahead-shell .hero-title { font-size:1.1875rem; color:var(--text); margin-top:4px; }
.runahead-shell .hero-title.quiet { color:var(--text-dim); font-size:1rem; margin-top:10px; }
.runahead-shell .hero-sub { font-size:0.8125rem; color:var(--text-dim); margin-top:6px; }

/* TOMORROW / LATEST smallcard and the quiet TOMORROW / PLAN card. Same <div>-or-<a> shell as
   .hero above. */
.runahead-shell .smallcard { background:linear-gradient(180deg, var(--panel-top), var(--panel-bot)); border:1px solid var(--border); border-radius:10px; padding:11px 13px; display:block; text-decoration:none; color:inherit; }
.runahead-shell .quietcard { background:var(--panel-quiet); border:1px solid var(--border-quiet); border-radius:10px; padding:11px 13px; opacity:.75; display:block; text-decoration:none; color:inherit; }
.runahead-shell .cardrow { display:flex; justify-content:space-between; }
.runahead-shell .card-text { font-size:0.8125rem; color:var(--text-dim); margin-top:5px; }
/* Emphasised card body (LATEST/TOMORROW figures) — reuses the page's primary --text color rather
   than the reference's near-identical standalone literal (#e8e4da vs --text's #f4f1ea/#eceae6);
   the two read as the same "strong" tone, one fewer token to keep in parity. */
.runahead-shell .card-text-strong { font-size:0.8125rem; color:var(--text); margin-top:5px; }

.runahead-shell .bottomrow { display:flex; justify-content:space-between; align-items:center; }

/* Row-identity labels (docs/design/today-referens.html): uppercase, letter-spaced, label
   color; TODAY/HIGHLIGHT use the gold variant (active state / system voice). Generic classes
   shared by every Today row that carries a label. LÄS role, moved up from --faintest (:root
   Neutral hierarchy comment, spec §1.3): section navigation -- the testers' explicit finding. */
.runahead-shell .label { font-size:0.625rem; letter-spacing:.16em; color:var(--faint); text-transform:uppercase; }
.runahead-shell .label-gold { font-size:0.625rem; letter-spacing:.16em; color:var(--accent); text-transform:uppercase; }

/* Daily highlight ("pep"): gradient panel + gold left edge, HIGHLIGHT label. Gold as STATE
   role (never red), soft glow that charcoal turns off via --glow-gold:none — same recipe as
   the reactor/nav-underline gold. */
.runahead-shell .highlight-row {
  background:linear-gradient(180deg, var(--panel-top), var(--panel-bot));
  border:1px solid var(--border); border-left:2px solid var(--highlight-accent);
  box-shadow:var(--glow-gold); border-radius:10px;
  padding:12px 14px; margin:10px 0;
}
.runahead-shell .highlight-row .pep-text { font-size:0.8125rem; color:var(--text-dim); margin-top:5px; line-height:1.5; }

/* THIS WEEK dots — structural (always renders), the whole row links to Week. Outcome tokens
   (matched/swapped/missed/race) are shared with the week grid's --status-* family; plan-free
   mode swaps in --neutral-activity (activity presence, never outcome semantics). Today = gold
   ring with soft glow; future = outline — identical in both modes. */
.runahead-shell .dots { display:flex; align-items:center; gap:9px; text-decoration:none; color:inherit; }
.runahead-shell .day { text-align:center; }
.runahead-shell .dot { width:11px; height:11px; border-radius:3px; margin:0 auto; }
.runahead-shell .dot-matched  { background:var(--status-matched); }
.runahead-shell .dot-swapped  { background:var(--status-swapped); }
.runahead-shell .dot-missed   { background:var(--status-missed); }
.runahead-shell .dot-rest     { background:var(--dot-rest-fill); }
.runahead-shell .dot-race     { background:var(--status-race); }
.runahead-shell .dot-activity { background:var(--neutral-activity); }
.runahead-shell .dot-today    { background:transparent; border:1px solid var(--accent); box-shadow:var(--glow-gold-soft); }
.runahead-shell .dot-future   { background:transparent; border:1px solid var(--dot-future-border); }
.runahead-shell .daylabel       { font-size:0.625rem; color:var(--faintest); margin-top:3px; }
.runahead-shell .daylabel-today { font-size:0.625rem; color:var(--accent); margin-top:3px; }
.runahead-shell .weeklink { font-size:0.6875rem; color:var(--faint); margin-left:6px; }

/* Attention: 0-2 opportunistic amber items, each its OWN destination — never a combined
   number, never a placeholder when both are silent. Amber reuses --status-swapped (the
   week grid's own amber-deviation hue) rather than minting a duplicate token. */
.runahead-shell .attention-row { display:flex; align-items:center; gap:14px; padding:8px 0; }
.runahead-shell .signal { font-size:0.75rem; color:var(--status-swapped); text-decoration:none; }
.runahead-shell .signal:hover { color:var(--text-dim); }

/* ---------- Terms & Conditions document (TermsDocumentView) ----------
   Typography for the markdown-rendered T&C body. Self-contained (not scoped to
   .runahead-shell) so the gate, the registration/admin expanders and the public
   /terms page render identically wherever the component is placed. Quiet document
   look: serif headings (global h-rule), muted body text, modest sizes. */
.terms-doc h1 { font-size:1.25rem; margin:18px 0 6px; color:var(--text); }
.terms-doc h2 { font-size:1rem; margin:16px 0 4px; color:var(--text); }
.terms-doc h3 { font-size:0.875rem; margin:14px 0 2px; color:var(--text); }
.terms-doc h4, .terms-doc h5, .terms-doc h6 { font-size:0.8125rem; margin:12px 0 2px; color:var(--text); }
.terms-doc h1:first-child, .terms-doc h2:first-child, .terms-doc h3:first-child { margin-top:0; }
.terms-doc p { font-size:0.8125rem; line-height:1.7; color:var(--muted); margin:10px 0 0; }
.terms-doc ul, .terms-doc ol { font-size:0.8125rem; line-height:1.7; color:var(--muted); margin:10px 0 0; padding-left:22px; }
.terms-doc li { margin-top:2px; }
.terms-doc strong { color:var(--text-dim); font-weight:600; }
.terms-doc a { color:var(--accent); }
.terms-doc blockquote { margin:10px 0 0; padding-left:12px; border-left:2px solid var(--border); }
.terms-doc code { font-size:0.75rem; background:var(--surface2); padding:1px 4px; border-radius:3px; }

/* ---------- Contact page (SEO sweep Task S5, seo-referens.html section 5) ----------
   The house's document language under prose width (.prose-col, reused verbatim -- no new
   breakpoint): Fraunces heading (global h-rule), a lead line, then sections divided by a thin
   top rule with a faintest-uppercase .label (the existing house label idiom, line ~574) above a
   value line and an optional faint hint line. .contact-val a's gold-with-quiet-underline recipe
   mirrors GarminExportGuide's `.gguide a.ext` (line ~784) -- same tokens, own rule because that
   class is scoped to its own component, not a shared one. */
.runahead-shell .contact-doc h1 { margin:0 0 14px; }
.runahead-shell .contact-lead { font-size:0.9375rem; color:var(--text-dim); line-height:1.65; margin:0 0 28px; }
.runahead-shell .contact-sec { border-top:1px solid var(--border-quiet); padding-top:16px; margin:0 0 18px; }
.runahead-shell .contact-sec .label { display:block; margin-bottom:6px; }
.runahead-shell .contact-val { font-size:0.875rem; color:var(--text); }
.runahead-shell .contact-val a { color:var(--accent); text-decoration:none; border-bottom:1px solid rgba(216,186,121,.35); }
.runahead-shell .contact-hint { font-size:0.71875rem; color:var(--faint); line-height:1.55; margin:5px 0 0; }

/* ---------- TrendChart (docs/design/profil-referens.html NOTES 6-7, spec §3) ----------
   The app's shared trend-line SVG norm. Self-contained (not scoped to .runahead-shell) so it
   renders identically wherever it's dropped, same reasoning as .terms-doc above — the weight
   panel today, RHR/sleep panels tomorrow, and any future MAUI host. viewBox-based sizing: width
   100% + height:auto lets the box scale to its container instead of a fixed pixel size. */
.trendchart svg { display:block; width:100%; height:auto; }
.trendchart-grid { stroke:var(--border-quiet); stroke-width:1; }
.trendchart-axis { font-size:0.625rem; fill:var(--faint); font-family:inherit; }
.trendchart-line { fill:none; stroke-width:1.5; }
.trendchart-lastdot { fill:var(--text); }
.trendchart-lastval { font-size:0.6875rem; fill:var(--text); font-weight:600; }

/* ---------- Profile page: mirror zones (docs/design/profil-referens.html NOTES 1-4, spec §1) ----------
   ONE DOM, responsive grid: input zone (left, dampened .label) beside derivation zone (right,
   .label-gold — the system's voice, same semantics as TODAY/HIGHLIGHT). 2fr/3fr (40/60) —
   asymmetric content volumes, attributes-on-top-left as the height balance. align-items:stretch
   evens the card heights on desktop (the shorter column's card stretches, content stays
   top-anchored); mobile stacking is DOM order alone, handled in the 768 block below — no
   .desktop-chrome/.mobile-chrome duplication for the zones themselves. */
.runahead-shell .profile-zones { display:grid; grid-template-columns:2fr 3fr; gap:18px; align-items:stretch; }
.runahead-shell .zone {
  background:linear-gradient(180deg, var(--panel-top), var(--panel-bot));
  border:1px solid var(--border); border-radius:12px; padding:16px;
}
.runahead-shell .zone-head { margin-bottom:14px; }
.runahead-shell .zone-sub { font-size:0.6875rem; color:var(--faint); margin-top:3px; }
.runahead-shell .sect { margin-bottom:16px; }
.runahead-shell .sect .label,
.runahead-shell .sect .label-gold { display:block; margin-bottom:7px; }
.runahead-shell .readval { color:var(--muted); }

/* Background field (NOTES 1b, input surface): fixed height with internal scroll — the athlete's
   writing never pushes the zone taller. Targets both the rendered textarea and MudBlazor's own
   input-slot wrapper so the rule holds regardless of the exact DOM MudBlazor emits.
   Calibrated in CONTENT terms (owner adjustment after onboarding review, decision #92
   amendment): a typical COMPLETE background runs ~900-1000 chars (max 2000). At the zone's
   desktop line length (~60-65 chars/line at this field's font) and MudTextField's ~20px line
   height, ~15-16 visible lines show a complete background fully without scrolling — the
   2000-char ceiling is what actually scrolls. 240px = 12 lines * 20px; owner trimmed 320-260-240 in two visual rounds - zone balance won over the full-length target, a complete background scrolls slightly. */
.runahead-shell .background-textarea textarea,
.runahead-shell .background-textarea .mud-input-slot {
  height:240px; overflow-y:auto;
}

/* AI-derived profile text (reading surface, NOTES 1b/1c): capped at ~78ch regardless of zone
   width — past the readability zone, dense analysis text reads as tiring, not roomier. Long text
   is clipped with a fade + "Read more" that expands IN PAGE FLOW (the page grows), never an inner
   scroll box — nested scroll is the mobile scroll-trap, and the read-and-correct flow (the
   correction field sits right below) must stay one scroll context. Same family as the
   corrections' "Show all": long content clips with expansion, never an inner scrollbar. */
.runahead-shell .profile-cliptext { font-size:0.8125rem; color:var(--text-dim); line-height:1.6; white-space:pre-wrap; max-width:78ch; }
.runahead-shell .profile-cliptext.clipped { max-height:230px; overflow:hidden; position:relative; }
.runahead-shell .profile-cliptext.clipped::after {
  content:""; position:absolute; left:0; right:0; bottom:0; height:56px;
  background:linear-gradient(180deg, transparent, var(--panel-bot));
}
.runahead-shell .readmore,
.runahead-shell .showall { display:inline-block; margin-top:8px; font-size:0.6875rem; color:var(--faint); cursor:pointer; letter-spacing:.04em; }

/* ---------- Profile page: weight panel (docs/design/profil-referens.html NOTES 5, spec §2) ----------
   Full-width panel under the mirror zones: TrendChart is the reading surface, the entries list
   (desktop table / mobile rowcards) the editing surface behind "Show entries". Same panel-gradient
   family as .zone/.hero above. */
.runahead-shell .weight {
  background:linear-gradient(180deg, var(--panel-top), var(--panel-bot));
  border:1px solid var(--border); border-radius:12px; padding:16px; margin-top:18px;
}
.runahead-shell .weight-head { display:flex; align-items:center; justify-content:space-between; margin-bottom:12px; }

/* Segment toggle (3M/6M/ALL, NOTES 5): the theme's segment form, reusing the same active-state
   recipe as ZoomSwitcher's .zoom (--zoom-on-bg/--zoom-on-fg gradient tokens) rather than sharing
   its markup — .zoom is the Razor component scoped to the week pager's Mode contract, this is a
   second instance of the same VISUAL idiom for an unrelated control (time window, not view mode). */
.runahead-shell .seg { display:inline-flex; border:1px solid var(--border); border-radius:7px; overflow:hidden; }
.runahead-shell .seg button {
  background:transparent; color:var(--muted); border:0; padding:4px 11px;
  font:inherit; font-size:0.625rem; letter-spacing:.08em; cursor:pointer;
}
.runahead-shell .seg button.active { background:var(--zoom-on-bg); color:var(--zoom-on-fg); }

/* Input row wrapper (owner adjustment after live review, decision #93 amendment): the mobile
   form is its OWN form, never a compressed desktop row. The helper text moved OUT of `.inrow`
   to a FULL-WIDTH block below it (both forms — never a column beside Add, the mobile failure
   this replaces): a 5-line column of help text beside the button left a void above it. `.wt-date`
   /`.wt-kg` (landing on MudDatePicker's/MudNumericField's root wrapper via Class) get protected
   min-widths under the breakpoint below so their placeholders can never silently clip. */
.runahead-shell .weight-input { margin-bottom:12px; }
.runahead-shell .weight-input .inrow { display:flex; gap:8px; align-items:flex-end; flex-wrap:nowrap; }
.runahead-shell .weight-input .help { display:block; font-size:0.6875rem; color:var(--faint); margin-top:6px; line-height:1.5; }

/* Entries list, mobile form (NOTES 5, map §Mobil table-pattern norm): bespoke two-row cards, NOT
   the shared row-card component (that's built in the Activities mobile pass as the pattern's
   first real consumer — docs/BACKLOG.md "Profile-omdesign / TrendChart"). The card is deliberately
   NOT a click surface here (no detail page exists for a weight entry), so DELETE sits inside the
   card rather than an <a> wrapper — same quiet-panel tone as .quietcard, own class to keep this
   bespoke instance out of that component's naming. Visibility switch lives in the 768px block
   below; these appearance rules are unscoped to a breakpoint like the tabbar/msheet rules above
   (the element is already display:none by default via .mobile-chrome). */
.runahead-shell .weight-rowcard {
  background:var(--panel-quiet); border:1px solid var(--border-quiet); border-radius:8px;
  padding:10px 12px; margin-bottom:8px;
}
.runahead-shell .weight-rowcard .titlerow { display:flex; align-items:center; justify-content:space-between; gap:8px; }
.runahead-shell .weight-rowcard .title { font-size:0.8125rem; color:var(--text); }
.runahead-shell .weight-rowcard .meta { font-size:0.6875rem; color:var(--muted); margin-top:4px; }

/* ---------- Onboarding steps (/onboarding/import, /onboarding/profile) ----------
   docs/design/onboarding-referens.html §1-3, onboarding design spec §"/onboarding/import"/
   §"/onboarding/profile": a single narrow column shared by both steps. Step label reuses the
   house `.label` idiom (faintest uppercase); card labels reuse `.label-gold` (system's-voice
   gold, same semantics as TODAY/HIGHLIGHT); cards reuse the panel-gradient family (.zone/.weight
   precedent) rather than inventing a new panel look. `.guide` (the discreet text-link idiom) is
   reused verbatim for both steps' quiet exits ("I'll do this later ›", "Skip for now…"). */
.runahead-shell .ob { max-width:640px; }
.runahead-shell .ob-title { font-size:1.625rem; font-weight:600; margin:0 0 10px; color:var(--text); }
.runahead-shell .ob-lede { color:var(--text-dim); line-height:1.6; font-size:0.8125rem; margin:0 0 22px; max-width:560px; }
.runahead-shell .ob-card {
  background:linear-gradient(180deg, var(--panel-top), var(--panel-bot));
  border:1px solid var(--border); border-radius:10px; padding:20px; margin:0 0 18px;
}
.runahead-shell .ob-card > .label-gold { display:block; margin-bottom:12px; }
.runahead-shell .ob-formrow { margin:14px 0 0; display:flex; align-items:center; gap:14px; flex-wrap:wrap; }
.runahead-shell .ob-wait { border-top:1px dashed var(--border-quiet); margin-top:16px; padding-top:14px; }
.runahead-shell .ob-wtxt { color:var(--muted); font-size:0.75rem; line-height:1.6; margin:0; }
.runahead-shell .ob-done-line { display:flex; align-items:center; gap:8px; color:var(--green); font-size:0.8125rem; font-weight:600; margin:0 0 10px; }
.runahead-shell .ob-done-sub { color:var(--muted); font-size:0.71875rem; margin:0 0 14px; }
.runahead-shell .ob-skiprow { margin-top:14px; }
/* Gold link affordance (spec §1.3, decision #169): the ONE shared `.guide` rule for all eleven
   placements across the app -- dampened gold, never underline (referens NOTES 5). Supersedes the
   old ".guide heal" fix (design spec Task E4), which patched the missing style here by adding
   yet another scoped color/hover duplicate (.ob-formrow .guide, .controls-row .guide,
   .guards-intro/.guards-howto .guide) instead of the shared rule that should have existed from
   the start. The four scoped rules below now carry ONLY their layout divergence
   (font-size/margin); color/hover/cursor/letter-spacing live here, once. */
.runahead-shell .guide {
  color:var(--accent); opacity:.82; cursor:pointer; text-decoration:none; letter-spacing:.04em;
}
.runahead-shell .guide:hover { opacity:1; }

.runahead-shell .ob-formrow .guide { font-size:0.75rem; }

/* Verification row (design spec Task E4, drawn spot: docs/design/onboarding-referens.html §1
   .verifrow) -- opportunistic, renders only for an unverified current user. It sits in the UPLOAD
   card directly under the (disabled) Browse/Import controls it explains, not in the guide card
   (owner click-round): the reason belongs in the same field of view as the thing it gates. */
.runahead-shell .ob-verifrow { display:flex; align-items:center; gap:10px; margin-top:12px; padding:10px 12px; background:var(--panel-quiet); border:1px solid var(--border-quiet); border-radius:8px; }
.runahead-shell .ob-verifdot { width:6px; height:6px; border-radius:50%; background:var(--accent); box-shadow:0 0 8px rgba(216,186,121,.5); flex-shrink:0; }
.runahead-shell .ob-veriftxt { color:var(--faint); font-size:0.71875rem; flex:1; }
.runahead-shell .ob-verifresend { color:var(--faint); font-size:0.71875rem; border-bottom:1px dotted var(--faint); text-decoration:none; cursor:pointer; }
.runahead-shell .ob-verifresend:hover { color:var(--text-dim); }

/* GarminExportGuide (design spec §GarminExportGuide, reference NOTES 5): ONE content, TWO
   surfaces (inline on /onboarding/import, kvarstannande dialog on Activities) — shared markup,
   shared CSS, no per-surface duplication. Scoped to `.runahead-app` (not `.runahead-shell`):
   the Activities dialog surface renders via MudDialogProvider, a SIBLING of `.runahead-shell`
   (MainLayout) — same self-containment reasoning as `.import-guide-list`/.terms-doc above. */
.runahead-app .gguide ol { margin:0 0 12px; padding-left:20px; color:var(--text-dim); line-height:1.7; font-size:0.78125rem; }
.runahead-app .gguide ol li::marker { color:var(--accent-lo); }
.runahead-app .gguide a.ext { color:var(--accent); text-decoration:none; border-bottom:1px solid rgba(216,186,121,.35); }
.runahead-app .gguide .expect { color:var(--muted); font-size:0.75rem; line-height:1.6; margin:0 0 10px; }
.runahead-app .gguide .bridge {
  color:var(--text-dim); font-size:0.78125rem; line-height:1.6; border-left:2px solid var(--accent-lo); padding-left:12px; margin:12px 0 0;
}

/* Today's profile nudge (design spec §"Todays skyddsnät"): opportunistic quiet row below the
   attention block — activities exist but the profile has no content yet. Same quiet-panel tone
   as `.quietcard`/`.profilerow`'s reference precedent, own class since it sits below `.bottomrow`
   rather than inside the main grid. */
.runahead-shell .today-profilerow {
  display:flex; align-items:center; gap:8px; padding:9px 14px; margin-top:8px;
  background:var(--panel-quiet); border:1px solid var(--border-quiet); border-radius:8px;
  font-size:0.75rem; color:var(--muted); text-decoration:none;
}
.runahead-shell .today-profilerow:hover { color:var(--text-dim); }
.runahead-shell .today-profilerow .arrow { color:var(--accent-lo); }

/* ---------- DataList (design spec §1, reference NOTES 9): the shared row-list pattern's FIRST
   real consumer — the ".rowcard"/.titlerow/.title/.meta naming the weight panel's comment above
   already reserved for this pass. Frame: border-quiet + radius, mirrors the reference's inner
   table frame (a plain nested div in the static reference; DataList owns it directly since every
   future consumer gets the frame for free). Desktop table mirrors the reference's table.list
   verbatim, real tokens instead of hex. Mobile cards reuse the weight card's nested class names
   (titlerow/title/meta) but are NOT the same visual family: unlike .weight-rowcard (deliberately
   quiet/non-clickable, no detail page exists for a weight entry), DataList's cards ARE the whole-
   row click target (reference NOTES 9: mobile two-row card, hela kortet klickyta), so they get the
   .hero/.smallcard gradient-panel treatment instead of the flat quiet-panel one. */
.runahead-shell .datalist {
  border:1px solid var(--border-quiet); border-radius:10px; padding:10px 10px 2px;
}
/* Activities list (design spec §2, reference NOTES 9-11): the toolbar slot's vy-verktyg row --
   search field + (mobile-only) sort-cycle button sit side by side, wrapping under real width
   pressure rather than ever forcing horizontal scroll (375px floor, NOTES 15). */
.runahead-shell .datalist-toolbar { display:flex; align-items:center; gap:10px; flex-wrap:wrap; margin-bottom:8px; }
.runahead-shell .datalist-toolbar .search {
  flex:1; min-width:0; background:var(--panel-quiet); border:1px solid var(--border-quiet); border-radius:7px;
  padding:7px 11px; font-size:0.75rem; color:var(--text-dim); font-family:inherit;
}
.runahead-shell .datalist-toolbar .search::placeholder { color:var(--faint); }
/* Mobile-only "Sort: Date ▾" cycle button (reference NOTES 11): hidden by default via the shared
   .mobile-chrome idiom, revealed in the 768px block below. FIXED WIDTH (owner click-through fix,
   same muscle-memory-target class as the week-nav pager's .wk-range-compact): the label cycles
   through Date/Distance/Time/Pace/"Heart rate" so a content-sized button would resize itself on
   every tap, and the search field sharing this row must not reflow because of it. Sized to the
   longest rendered string, "Sort: Heart rate ▾" (18 characters) plus this button's own
   letter-spacing (.04em × 18 ≈ 0.7ch) -- the base font is monospace ('DM Mono', so ch is exact,
   same precondition the pager's comment relies on) -- rounded up to 20ch for headroom. */
.runahead-shell .datalist-toolbar .sort-cycle {
  flex:0 0 auto; width:20ch; text-align:left; background:transparent; border:0; font:inherit;
  font-size:0.6875rem; color:var(--faint); letter-spacing:.04em; cursor:pointer; padding:0; white-space:nowrap;
}
.runahead-shell .datalist-toolbar .sort-cycle .dir { color:var(--accent); }

/* Page-size selector (polish-paginering design spec §1.2, reference NOTES 2): the MudSelect form-
   input the invariant allows, dressed down to the toolbar's dampened tone rather than a full-weight
   form control -- font-size and colour match .sort-cycle above, quiet border matches the .search
   field's. margin-left:auto pushes it to the row's right edge, same idiom as .datalist-refresh,
   whether or not a refresh button is also present (Activities has none; a future ToolbarContent
   consumer that adds both keeps this ordered before the refresh button by DOM position). Always
   present -- unlike PagerControl below it, this control is never hidden by the emptiness rule. */
/* Pixel cap vs rem scale (R1 review finding after U0+U1): every OTHER width in this file that
   needs to track content is ch-based and self-scales with the root snap; this literal
   `width:100px` was the one exception, and it clipped this MudSelect's own content ("100"/"All"
   + the dense-variant dropdown chevron + the outlined "Rows" label notch) once the 17px snap
   lifted type size. Sized in rem so a future snap (candidate B, BACKLOG) grows it too; the value
   covers the widest item value plus the chevron and notch with margin to spare. */
.runahead-shell .pagesize-select { flex:0 0 auto; width:6.875rem; margin-left:auto; }
.runahead-shell .pagesize-select .mud-input-outlined-border { border-color:var(--border-quiet); }
.runahead-shell .pagesize-select .mud-input-label,
.runahead-shell .pagesize-select .mud-select-input,
.runahead-shell .pagesize-select input {
  font-size:0.6875rem; color:var(--faint); font-family:inherit;
}

/* Refresh control (DataList's ShowRefresh/OnRefresh, admin-svep design spec §"Del 3", reference
   NOTES 2): a pure trigger on the consumer's own load path, so it is an own control with own CSS
   rather than MudBlazor (invariant: MudBlazor is for behavior-heavy primitives, a refresh button
   is not one). margin-left:auto pushes it to the toolbar's right edge whether or not
   ToolbarContent is present, same idiom as .guide.desktop-chrome/.row-actions elsewhere in this
   file. The glyph spins via .spin while Loading is true (component sets the class; disabled is a
   plain HTML attribute, not a CSS concern). */
.runahead-shell .datalist-toolbar .datalist-refresh {
  margin-left:auto; flex:0 0 auto; display:inline-flex; align-items:center; gap:5px;
  background:var(--panel-quiet); border:1px solid var(--border-quiet); border-radius:7px;
  padding:5px 11px; font-size:0.625rem; letter-spacing:.08em; text-transform:uppercase;
  color:var(--muted); font-family:inherit; cursor:pointer;
}
.runahead-shell .datalist-toolbar .datalist-refresh:hover:not(:disabled) { color:var(--text-dim); border-color:var(--border); }
.runahead-shell .datalist-toolbar .datalist-refresh:disabled { color:var(--faintest); cursor:not-allowed; }
.runahead-shell .datalist-toolbar .datalist-refresh .spin { display:inline-block; animation:datalist-refresh-spin .8s linear infinite; }
@keyframes datalist-refresh-spin { to { transform:rotate(360deg); } }
/* The glyph stops spinning under reduced motion, same accommodation as the sysbar/inv-runcard
   pulses (.sysbar .pulse / .inv-runcard .pulse) -- Loading is still communicated by :disabled. */
@media (prefers-reduced-motion: reduce) {
  .runahead-shell .datalist-toolbar .datalist-refresh .spin { animation:none; }
}

/* Busy indicator (polish-paginering design spec §1.3, reference NOTES 3): DataList's
   parameter-free loading semantics. .datalist-busy is the toolbar's own spinner for the
   ShowRefresh-less path (when the refresh button exists it already spins -- this ring never
   appears alongside it, DataList's render condition enforces that). .datalist-busy-rows dims the
   STANDING rows (tbody / card-stack container) while a reload is in flight -- the same
   opacity-and-transition idiom used everywhere else in the house for "content never blinks"
   (e.g. Plans' RowClass dimming, the week views' .wk-busy). Gold ring: --accent, never a raw
   "--gold" token (house rule, cf. .mday.today's comment) -- the plan text's "--gold" shorthand
   resolves to the same token family as the reactor/nav-underline/today-header gold. */
.runahead-shell .datalist-busy {
  display:inline-block; width:11px; height:11px; margin-left:auto;
  border:1.5px solid var(--faintest); border-top-color:var(--accent); border-radius:50%;
  animation:datalist-busy-spin .8s linear infinite;
}
@keyframes datalist-busy-spin { to { transform:rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .runahead-shell .datalist-busy { animation:none; }
}
.runahead-shell .datalist-busy-rows { opacity:.45; transition:opacity .15s; }

/* Task P6 (design spec §2.1, reference NOTES 6): same principle as .datalist-busy-rows just
   above, on a second surface -- content never blanks. WeekView/BlockView's keep-until-replaced
   render branch dims a week/block already on screen (grid, mobile list, or the empty-text
   branch alike) instead of swapping it for the Loading… hint while the next one is in flight. */
.runahead-shell .wk-busy { opacity:.45; transition:opacity .15s; }

.runahead-shell .qmark {
  /* Circle box in rem (final-review finding): fixed 13px dimensions around a rem font-size is
     the same clip class .pagesize-select had — the glyph scales with a root snap, the circle
     does not. 0.8125rem preserves the original 13/16 ratio. */
  display:inline-block; width:0.8125rem; height:0.8125rem; border:1px solid var(--faint); border-radius:50%;
  /* line-height in rem (R1 review finding, cheap NOTE a): a literal px value here was decoupled
     from the rule's own rem font-size, so the two stopped scaling together across a root snap;
     0.75rem preserves the original 12/16 ratio to font-size. */
  color:var(--faint); font-size:0.5625rem; text-align:center; line-height:0.75rem; cursor:help; margin-left:4px;
}

/* Triage presence marker (reference NOTES 16): a plain monospace "!" PREFIX before the title, ONE
   nivaneutral signal-palette token -- --status-extra, the reference's watch/threshold-blue tone --
   never --red (alert is the destructive register) and never --accent (gold is reserved for state/
   race). No ring, no click affordance of its own: the row/card it sits inside already carries the
   click surface. BOLD (owner click-through fix): compared against StatusChip's "+ extra" prefix
   (the grammar this marker mirrors, character-space-text) -- that prefix carries NO explicit
   font-weight (.wk-status-chip has none, inherits the body's normal 400), so there is no existing
   bold value to match; 700 is the marker's own weight, not borrowed from "+ extra". Size unchanged. */
.runahead-shell .tri-marker { color:var(--status-extra); font-weight:700; }

/* "What gets imported ›" guide link (reference NOTES 12): a KVARSTANNANDE-dialog trigger, styled
   like the reference's quiet .guide text link, never the "?" tooltip's hover form. Two placements,
   BOTH inside the page's own .controls-row (SNITTNORM: this is a mangd/help affordance, the same
   family as Upload/Add, not a vy-verktyg -- it never moves into DataList's ToolbarContent slot).
   Desktop's .guide is pushed right via margin-left:auto (mirrors the reference's flex spacer),
   first in DOM order. Owner click-through fix: .guide-mobile used to render AFTER the whole
   DataList frame (end of document flow, below every card) -- invisible, and least useful exactly
   there since the guide matters most BEFORE the first upload. It now sits inside .controls-row
   too, LAST (mobile reading order: Upload, Add, guide -- least prominent, dampened, last), held
   together with Upload/Add above the search/sort toolbar. Same .desktop-chrome/.mobile-chrome gate
   DataList's own dual form uses. */
.runahead-shell .controls-row .guide { font-size:0.75rem; }
.runahead-shell .controls-row .guide.desktop-chrome { margin-left:auto; margin-right:4px; }

.runahead-shell .datalist-table { width:100%; border-collapse:collapse; }
/* LÄS role, moved up from --faintest (:root Neutral hierarchy comment, spec §1.3):
   OWNER-DECIDED UP -- the column header is the key to reading the column, plain read text. */
.runahead-shell .datalist-table th {
  font-size:0.625rem; letter-spacing:.14em; color:var(--faint); text-transform:uppercase;
  text-align:left; padding:6px 10px; border-bottom:1px solid var(--border);
}
.runahead-shell .datalist-table th.sortable { cursor:pointer; }
.runahead-shell .datalist-table th .dir { color:var(--accent); }
.runahead-shell .datalist-table td {
  padding:9px 10px; border-bottom:1px solid var(--border-quiet); font-size:0.75rem; color:var(--text-dim);
}
/* Activity column's primary/caption split (Activities list, reference NOTES 2/16): .t is the
   title line, .c the muted "weekday date · sport · gear" caption underneath. */
.runahead-shell .datalist-table td .t { color:var(--text); font-size:0.8125rem; }
.runahead-shell .datalist-table td .c { font-size:0.6875rem; color:var(--faint); margin-top:2px; }
.runahead-shell .datalist-table tbody tr { cursor:pointer; }
.runahead-shell .datalist-table tbody tr:hover td { background:var(--panel-quiet); }
.runahead-shell .datalist-table .datalist-hint {
  text-align:center; color:var(--faint); letter-spacing:.08em; padding:14px 0; cursor:default;
}

.runahead-shell .datalist-cards .datalist-hint {
  text-align:center; color:var(--faint); letter-spacing:.08em; padding:14px 0;
}
.runahead-shell .datalist-cards .rowcard {
  display:block; background:linear-gradient(180deg, var(--panel-top), var(--panel-bot));
  border:1px solid var(--border); border-radius:8px; padding:10px 12px; margin-bottom:8px; cursor:pointer;
}
.runahead-shell .datalist-cards .rowcard .titlerow { display:flex; align-items:center; justify-content:space-between; gap:8px; }
.runahead-shell .datalist-cards .rowcard .title { font-size:0.8125rem; color:var(--text); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.runahead-shell .datalist-cards .rowcard .meta { font-size:0.6875rem; color:var(--muted); margin-top:4px; }
/* Row actions (DataList's RowActions, admin-svep design spec §"Del 3", reference NOTES 2/5): a
   trailing slot the consumer fills with its own trigger (a kebab/menu, Task A4's job -- DataList
   only owns placement plus the stopPropagation trap in the .razor markup). Desktop: narrow
   right-aligned trailing cell so it never steals width from real columns. Mobile: pinned to the
   title row's end, same flex item family as .chip. */
.runahead-shell .datalist-table td.datalist-actions { width:1%; white-space:nowrap; text-align:right; }
.runahead-shell .datalist-cards .rowcard .titlerow .datalist-actions { flex:0 0 auto; }
/* Gear is dimmer than the rest of the caption/meta line on both surfaces (read-path rule: what's
   loaded is shown, but gear stays visually secondary to the metrics around it). */
.runahead-shell .datalist-table td .c .g,
.runahead-shell .datalist-cards .rowcard .meta .g { color:var(--faint); }

/* ---------- AdminUsersSection (Task A4, design spec 2026-08-06-admin-svep-design.md "Del 1",
   reference NOTES 3-6): the row menu's kebab trigger and popover contents, and the row's own
   chip family (role/plan/status). ---------- */

/* Kebab trigger (reference's own class name, NOTES 5): a plain glyph, not a MudIconButton --
   same "own control, own CSS" reasoning as .datalist-refresh (MudBlazor is for behaviour-heavy
   primitives, a static trigger glyph is not one). Click/toggle wiring lives in the .razor markup
   (MenuContext.ToggleAsync, same activator idiom as OutcomeCard's RelinkMenu); DataList's own
   @onclick:stopPropagation on the .datalist-actions surface already stops this click from ever
   reaching OnRowClick, so no stopPropagation is needed here too. */
.runahead-shell .kebab { display:inline-block; color:var(--faint); font-size:1rem; line-height:1; cursor:pointer; padding:2px 5px; }
.runahead-shell .kebab:hover { color:var(--accent); }

/* Row menu contents (MudMenu's popover, rendered into MudPopoverProvider -- a SEPARATE render
   tree from the row/card, which is exactly what makes the menu a true overlay: opening/closing it
   can never move a pixel of the list, unlike the reference's inline-drawn "open" mockup, a
   document artefact for showing the state on paper). .admin-menu-head labels the one group NOTES
   5 gives its own label (Add role); the other three groups are divider-separated only, matching
   the reference's own menu markup exactly (only "Add role" carries an .mhead).

   SCOPED TO .runahead-app, NOT .runahead-shell, and that is the whole point: MudPopoverProvider
   sits inside the theme wrapper but OUTSIDE the padded shell (MainLayout.razor), so a
   .runahead-shell-prefixed rule can never reach anything MudBlazor portals into a popover. That
   is what broke the reason's right-alignment in the first click round after the fix: the markup
   change landed (the parentheses appeared) while every layout declaration silently missed, so
   the reason rendered inline and ran straight up against the item text. Any future rule for
   popover or dialog content belongs at .runahead-app for the same reason. */
.runahead-app .admin-menu-head {
  font-size:0.5625rem; letter-spacing:.14em; color:var(--faintest); text-transform:uppercase; padding:6px 4px 2px;
}
.runahead-app .admin-mi { display:flex; justify-content:space-between; align-items:center; gap:10px; width:100%; }
/* margin-left:auto pins the reason right even if a future MudBlazor version wraps the item's
   content in an extra element, which would break space-between's reliance on these two spans
   being siblings. */
.runahead-app .admin-mi-reason {
  font-size:0.5625rem; color:var(--faintest); letter-spacing:.04em; white-space:nowrap; margin-left:auto;
}
.runahead-app .admin-mi-danger { color:var(--red); }

/* Row chip family (NOTES 3): role/plan are neutral informational chips; ok/warn are the status
   chip's two tones. Own bordered-mini-chip class rather than the existing unrelated `.chip` (that
   one is the hero card's unbordered badge, a different family -- same reasoning as
   `.guards-chip`/`.inv-chip` above), reusing THEIR exact shape and the already-established
   status-token palette: amber reuses --status-swapped (the house's general-purpose amber, see
   `.signal`'s own comment), never a new colour. Role chips are pure information (adversarial
   review fix on top of Task A4 -- removal moved into the row menu's own "Remove role" group, see
   RolesCell/RowActionsFragment's comments), so only `.plan` still needs the button/hover treatment
   (it stays the click-to-change-plan trigger). */
.runahead-shell .admin-chip {
  display:inline-block; font:inherit; font-size:0.5625rem; letter-spacing:.1em; text-transform:uppercase;
  border:1px solid var(--border-quiet); border-radius:4px; padding:2px 7px; margin:0 4px 4px 0;
  white-space:nowrap; color:var(--faint); background:transparent; cursor:default;
}
button.admin-chip { cursor:pointer; }
button.admin-chip:hover { border-color:var(--border); color:var(--text-dim); }
.runahead-shell .admin-chip.role { color:var(--text-dim); }
.runahead-shell .admin-chip.plan { color:var(--muted); }
.runahead-shell .admin-chip.ok { color:var(--faint); }
/* Unverified + Invite pending share this exact tone -- deliberate (NOTES 3): the tone carries the
   severity, the chip TEXT carries the kind. */
.runahead-shell .admin-chip.warn { color:var(--status-swapped); border-color:var(--status-swapped); }

/* Last-run lines (NOTES 4): outcomes live in the row, never the menu. Plain block lines under the
   chips (mobile) / in their own column (desktop) -- "ok"/"err" pick up the same colour language as
   everywhere else (gold for a good outcome, red for a blocked/failed one); the running state and
   the neutral "no new patterns"/"skipped" case both stay the faint default, no third colour. */
.runahead-shell .admin-run-line { font-size:0.6875rem; color:var(--faint); }
.runahead-shell .admin-run-line.ok { color:var(--accent); }
.runahead-shell .admin-run-line.err { color:var(--red); }
.runahead-shell .admin-run-empty { color:var(--faintest); font-size:0.6875rem; }

/* ---------- AdminOutboxSection (Task A6, design spec 2026-08-06-admin-svep-design.md "Del 3
   (forts)", reference NOTES 7-8): status chip tones + the Queued column's two-line date/time. */

/* Outbox status chip tones, added to the SAME .admin-chip family Task A4 started (NOTES 7:
   "progressionen är tonal och bara felet skriker" -- dampened except Failed). .quiet mirrors
   .ok's minimal shape one level fainter (--faintest, not --faint: Queued/Sent are non-actionable
   states, not a good outcome, so they sit at the bottom of the neutral hierarchy). .cool reuses
   the house's watch/signal tone (--status-extra, same token as .tri-marker/.inv-chip.signal).
   .gold is the ONLY warm tone and reuses the filled-gold recipe (--zoom-on-bg/--zoom-on-fg, same
   as .zoom/.seg/.guards-btn.fill) rather than plain gold text on transparent -- the house rule
   that text on a gold SURFACE is always the theme's own dark contrast token, never invented here.
   .bad reuses --red, same shape as .admin-mi-danger. */
.runahead-shell .admin-chip.quiet { color:var(--faintest); }
.runahead-shell .admin-chip.cool { color:var(--status-extra); border-color:var(--status-extra); }
.runahead-shell .admin-chip.gold { color:var(--zoom-on-fg); background:var(--zoom-on-bg); border-color:var(--accent-lo); }
.runahead-shell .admin-chip.bad { color:var(--red); border-color:var(--red); }

/* ---------- AdminCoachLinksSection mobile containment (click-round Finding 4). NOTES 6's "stays
   unchanged" exemption (docs/design/admin-referens.html, AdminMobileParityGuardTests' one named
   MudTable exception) is about FORM, not a licence to burst the 375 viewport -- see that razor
   file's own header comment for the full reasoning. Desktop-scoped rules here are byte-for-byte
   the OLD inline styles (min-width:260px on both selects, unwrapped row); the 768px override below
   is the only thing that changes behaviour. ---------- */
.runahead-shell .admin-coach-controls { display:flex; gap:12px; align-items:center; flex-wrap:wrap; }
.runahead-shell .admin-coach-select { min-width:260px; }
/* Table scrolls WITHIN its own wrapper instead of the page gaining horizontal scroll -- same
   overflow-x:auto idiom as .wk-week-scroll above, applied unconditionally (a table that already
   fits never triggers it, so no breakpoint gate is needed on the wrapper itself). */
.runahead-shell .admin-coach-table-wrap { max-width:100%; overflow-x:auto; }

/* Queued column (NOTES 7): date on line one, clock time dampened on line two underneath -- own
   class rather than the reference's generic .nowrap/.sub2 (same "own class, not a loosely-named
   generic one" reasoning as .admin-chip vs .chip above). */
.runahead-shell .outbox-queued { white-space:nowrap; }
.runahead-shell .outbox-queued .time { font-size:0.625rem; color:var(--faintest); margin-top:2px; }

/* ---------- OutboxDetailDialog (Task A6, reference NOTES 8): rendered via MudDialogProvider,
   which lives inside .runahead-app but OUTSIDE .runahead-shell (see MainLayout.razor) -- same
   scoping precedent as .import-guide-list/.terms-doc, so these are .runahead-app selectors, not
   .runahead-shell. */
.runahead-app .outbox-dialog-title { font-family:"Fraunces", Georgia, serif; font-size:1.0625rem; margin:0 0 2px; color:var(--text); }
.runahead-app .outbox-dialog-sub { font-size:0.6875rem; color:var(--faint); margin-bottom:14px; }
.runahead-app .outbox-kv { display:flex; gap:12px; padding:6px 0; border-bottom:1px solid var(--border-quiet); font-size:0.71875rem; }
/* LÄS role, moved up from --faintest (:root Neutral hierarchy comment, spec §1.3):
   OWNER-DECIDED UP -- the key to a key/value pair; the value is worthless without a readable key. */
.runahead-app .outbox-kv .k { color:var(--faint); min-width:150px; letter-spacing:.06em; text-transform:uppercase; font-size:0.59375rem; flex-shrink:0; padding-top:2px; }
.runahead-app .outbox-kv .v { color:var(--text-dim); }
.runahead-app .outbox-kv .v.empty { color:var(--faintest); }
/* Last error (block layout, not the flex k/v row): the reference's own note for this row
   ("radbrytning bevarad") is white-space:pre-wrap so LastError's embedded newlines survive. */
.runahead-app .outbox-kv-block { display:block; border-bottom:none; }
.runahead-app .outbox-kv-block .k { display:block; margin-bottom:5px; }
.runahead-app .outbox-errbox {
  background:var(--panel-quiet); border:1px solid var(--red); border-radius:7px; padding:9px 11px;
  color:var(--text-dim); font-size:0.71875rem; white-space:pre-wrap; word-break:break-word;
}
/* Footnote (A6/A7 review fix): states the webhook-sourced-timestamps fact ONCE, outside the
   per-row k/v fields, instead of baking it into Delivered/Opened's own text -- see this dialog's
   header comment for why. Same dampened tone as .outbox-dialog-sub. */
.runahead-app .outbox-dialog-footnote { font-size:0.65625rem; color:var(--faintest); margin-top:14px; padding-top:11px; border-top:1px solid var(--border-quiet); }

/* ---------- AdminSettingsSection (Task A7, design spec 2026-08-06-admin-svep-design.md "Del 4",
   reference NOTES 9): the settings card's FIXED order -- control, description, then an action
   row divided by a thin rule, ONLY when the setting has one. Generalizes the SEND TEST EMAIL fix
   (previously wedged straight after the description text) so RESUME PAUSED SENDS, and any future
   action-bearing setting, inherit the same separation for free. */
.runahead-shell .admin-settings-desc { display:block; margin-top:8px; }
.runahead-shell .admin-actionrow { margin-top:12px; padding-top:11px; border-top:1px solid var(--border-quiet); }

/* ---------- AdminFeedbackSection (Task A8, design spec 2026-08-06-admin-svep-design.md "Del 8",
   reference NOTES 11-13; converted onto DataList fixing an adversarial review BLOCKER on the first
   pass -- the hand-rolled .admin-fb-cards/.admin-fb-card family this comment used to describe is
   gone, DataList's own .datalist-table/.datalist-cards now carry both forms, same as Users/Outbox):
   source/filter chip tone, the compact nowrap date, the now-visible action button, and the
   Item-column dim hook RowClass drives. */

/* New chip tone (NOTES 11): AI FEEDBACK's "neutral base tone" is --muted specifically, one step
   brighter than the existing .quiet tone's --faintest (.quiet marks NON-ACTIONABLE states like
   Outbox's Queued/Sent; AI feedback rows are a real, if low-priority, product signal, not a
   non-state) -- the reference draws it with an explicit color:var(--muted), matching neither the
   chip's own default (--faint) nor .quiet. SYSTEM/DATA HEALTH/USER FEEDBACK reuse the existing
   .bad/.cool/.gold tones Task A4/A6 already established rather than a parallel set (checked
   before adding this one: those three fit exactly, only AI FEEDBACK's tone was missing). Carries
   a border-color like its three siblings (review finding: colour-only left it the one tone with
   nothing but a low-saturation grey to read at rest, worse still once the filter row dims its
   inactive chips to opacity .55). */
.runahead-shell .admin-chip.muted { color:var(--muted); border-color:var(--muted); }

/* Filter row (NOTES 11): same .admin-chip + tone classes as the row chips (SourceTone in the
   .razor code is the single source both call), so the chip-to-filter link is structural, not just
   visually similar. "Active" is expressed as opacity rather than a colour override, so the
   filter's own permanent source colour is never masked at the one moment (selection) it matters
   most -- unselected filters sit dimmed, the selected one is at full strength. Reusing the generic
   button.admin-chip:hover rule (border/color shift on hover) is deliberate, not an oversight: it
   is the same interactive-chip affordance AdminUsersSection's .plan chip already relies on. */
.runahead-shell .admin-fb-filters { display:flex; flex-wrap:wrap; gap:8px; margin:12px 0 14px; }
.runahead-shell .admin-chip.feedback-filter { opacity:.55; }
.runahead-shell .admin-chip.feedback-filter:hover { opacity:.85; }
.runahead-shell .admin-chip.feedback-filter.active { opacity:1; }

/* Compact date column (NOTES 12): ActivityFormatter.AdminDate has no weekday and no space to wrap
   on by itself; nowrap here additionally keeps the two-line date/origin block from wrapping onto
   a third line under column-width pressure. */
.runahead-shell .admin-fb-date { white-space:nowrap; }

/* Action button (NOTES 13): a bordered button visible at rest, replacing the former
   Variant.Text/opacity:.6 MudButton -- same small bordered-button recipe as .guards-btn/the
   reference's own .btn.sm (border + radius + gold text), given its own class rather than reusing
   .guards-btn by name across an unrelated section (same "own class, shared recipe" precedent as
   .admin-chip vs .chip). The verb text itself is unchanged (DISMISS/ACKNOWLEDGE/RESOLVE, per
   source); only its visibility changed. Now lives inside DataList's RowActions slot -- ONE
   fragment, rendered once per row, in whichever form is on screen; DataList's own
   @onclick:stopPropagation on that slot (see DataList.razor's header comment) keeps the click from
   ever reaching OnRowClick, which this section never wires up anyway. */
.runahead-shell .admin-fb-act {
  display:inline-block; border:1px solid var(--border); border-radius:7px; padding:4px 10px;
  font-size:0.59375rem; letter-spacing:.06em; color:var(--accent); cursor:pointer; background:transparent;
  font-family:inherit;
}
.runahead-shell .admin-fb-act:hover { border-color:var(--accent-lo); }

/* Actioned marker (NOTES 13): faintest tone, unchanged position (the RowActions slot) -- same
   shape as the reference's own dismissed-row marker span. */
.runahead-shell .admin-fb-marker { font-size:0.59375rem; letter-spacing:.1em; text-transform:uppercase; color:var(--faintest); }

/* Dimming an actioned row (review fix): ONE mechanism now, DataList's RowClass ("dim", the exact
   token Plans introduced -- DataList itself does not know or care what "dim" means, per its own
   header comment). The mobile card gets the dim for free from the ALREADY-GENERIC
   .datalist-cards .rowcard.dim rule Plans' pass added; desktop needs its own scoped rule because
   Plans' matching desktop rule targets ITS OWN `.t` title-cell class, not a blanket `tr.dim td`
   (a blanket rule would also silently re-style Plans' and every other DataList consumer's desktop
   rows -- exactly the cross-consumer leakage a shared primitive must not cause). Scoping to
   .admin-fb-item, a class this section's own Item-column Cell renders, keeps the effect local to
   this consumer, same precedent as Plans' `.t`. Only the Item column dims (title/body/athlete
   label), matching the pre-conversion look exactly -- date/source/marker stay at full strength. */
.runahead-shell .datalist-table tbody tr.dim .admin-fb-item { opacity:.5; }

/* ---------- AdminUsagePlansSection (Task A9, design spec 2026-08-06-admin-svep-design.md
   "Del 9b"): the plan card's own header row -- name/description left, action buttons
   (Make default/Edit/Add quota/Delete) right. Desktop keeps the inline row (wraps if it must,
   never assumed to fit); the quota list itself is a DataList instance now (see AdminUsagePlansSection
   .razor's own comment) and needs no CSS here -- it inherits every .datalist-table/.datalist-cards
   rule above for free, the whole point of the shared primitive. */
.runahead-shell .admin-plan-head { display:flex; justify-content:space-between; align-items:flex-start; gap:16px; flex-wrap:wrap; }
.runahead-shell .admin-plan-actions { display:flex; align-items:center; gap:4px; flex-wrap:wrap; }

/* ---------- Del 6 cost row (Task A10, design spec "6.2", reference NOTES 14/section 7): the
   plan card's cost estimate, between the header and the quota DataList. .big carries the range
   itself (accent tone on the two numbers, same "plain gold-toned emphasis text" family as
   .admin-run-line.ok / .race-days -- not a chip, just emphasised text); .basis carries the
   mandatory explanation + underlying-data lines one size down, faintest by default; .basis.thin
   reuses the house's general-purpose amber (--status-swapped, the SAME token AdminUsersSection's
   .admin-chip.warn uses for Unverified/Invite pending) rather than minting a new hue, coloring the
   WHOLE line (including the "Based on N calls" prefix) so the thin-data warning cannot be missed
   as just a trailing clause. */
.runahead-shell .admin-plan-cost { margin-top:10px; padding-top:10px; border-top:1px solid var(--border-quiet); }
.runahead-shell .admin-plan-cost .big { font-size:0.78125rem; color:var(--text-dim); }
.runahead-shell .admin-plan-cost .big b { color:var(--accent); font-weight:400; }
.runahead-shell .admin-plan-cost .basis { font-size:0.625rem; color:var(--faintest); margin-top:3px; letter-spacing:.03em; }
.runahead-shell .admin-plan-cost .basis.thin { color:var(--status-swapped); }

/* ---------- AdminTermsSection (Task A7, design spec "Del 7", reference NOTES 10): version
   history as a clickable row list ("v3 · published 2026-07-14 · 14:22"), replacing
   MudExpansionPanels -- the STRUCTURAL fix for the em-dash panel-header string, which no longer
   exists as a form. Same row shape family as .datalist-table tbody tr / .vrow in the reference. */
.runahead-shell .admin-vrow {
  padding:9px 2px; border-bottom:1px solid var(--border-quiet); font-size:0.75rem;
  color:var(--text-dim); cursor:pointer;
}
.runahead-shell .admin-vrow:hover { color:var(--text); }
.runahead-shell .admin-vrow.active { color:var(--accent); }

/* ---------- AdminTabs (Task A3, design spec 2026-08-06-admin-svep-design.md "Del 9a", reference
   NOTES 1): own tab row replacing MudTabs on /admin. Desktop: underlined label row, quiet border
   under the whole row, active label in gold with a gold bottom border. Mobile: a horizontally
   scrolling chip row with no arrows -- the next chip clips under a gradient mask instead, and
   scrollbar-width:none/::-webkit-scrollbar hide the native scrollbar so only that mask reads as
   the "more" affordance. */
.runahead-shell .admin-tabs-desktop {
  display:flex; gap:26px; border-bottom:1px solid var(--border); padding:0 0 0 2px; margin-bottom:16px;
}
.runahead-shell .admin-tabs-desktop button {
  background:transparent; border:0; border-bottom:2px solid transparent; margin-bottom:-1px;
  font:inherit; font-size:0.6875rem; letter-spacing:.14em; text-transform:uppercase; color:var(--faint);
  padding:0 0 9px; cursor:pointer;
}
.runahead-shell .admin-tabs-desktop button:hover { color:var(--text-dim); }
.runahead-shell .admin-tabs-desktop button.active { color:var(--accent); border-bottom-color:var(--accent); }

/* Mobile row: the gradient mask (.admin-tabs-clip) is a SIBLING of the scrolling row, not a child
   of it, so it stays pinned to the right edge of .admin-tabs-mobile regardless of scroll position
   instead of scrolling away with the chips underneath it. */
.runahead-shell .admin-tabs-mobile { position:relative; margin-bottom:16px; }
.runahead-shell .admin-tabs-scroll {
  display:flex; gap:8px; overflow-x:auto; padding:2px 0 10px; border-bottom:1px solid var(--border);
  scrollbar-width:none;
}
.runahead-shell .admin-tabs-scroll::-webkit-scrollbar { display:none; }
.runahead-shell .admin-tabs-scroll .admin-tabchip {
  flex:0 0 auto; font:inherit; font-size:0.625rem; letter-spacing:.12em; text-transform:uppercase;
  color:var(--faint); border:1px solid var(--border-quiet); border-radius:999px; padding:6px 13px;
  background:var(--panel-quiet); white-space:nowrap; cursor:pointer;
}
/* Text on gold is always dark (theme rule): the active chip reuses the seg switch's active-state
   gradient tokens (--zoom-on-bg/-fg), same recipe as .zoom/.seg/.guards-btn.fill rather than
   re-declaring a gold gradient here. */
.runahead-shell .admin-tabs-scroll .admin-tabchip.active {
  color:var(--zoom-on-fg); background:var(--zoom-on-bg); border-color:var(--accent-lo);
}
.runahead-shell .admin-tabs-clip {
  position:absolute; right:0; top:2px; bottom:10px; width:34px; pointer-events:none;
  background:linear-gradient(90deg, transparent, var(--bg));
}

/* Comprehension intro (Task U3, design spec 2026-08-10-anvandartest-polish-design.md Del 3):
   same shape as `.guards-intro` above, own selector since the two pages' rules are read
   independently, not shared -- identical `font-size`/`color`/`margin-bottom` values are the
   deliberate parity, not an accident to fold into one rule. */
.runahead-shell .plans-intro { font-size:0.75rem; color:var(--muted); margin-bottom:18px; }

/* ---------- Plans overview (Plans redesign, design spec 2026-07-29-plans-sida-design.md §2,
   reference NOTES 2-4/13-14): DataList's SECOND consumer. .st is the status-hierarchy label
   (ACTIVE gold+glow, DRAFT muted, ARCHIVED faintest -- guld ar tillstand, no green imported); .verb
   is the row-level forward-action label (ACTIVATE/RE-ACTIVATE gold, EDIT/END plain dim); .dim is
   the RowClass hook DataList now exposes additively (draft rows: dampened title on desktop,
   dampened whole card on mobile -- reference's only `tr.dim` case). .days mirrors --race-days'
   gold/glow color role for the list's per-row countdown without adopting that hero rule's own
   font-size/margin layout tokens (own scoped selector, same tokens). */
.runahead-shell .st { font-size:0.625rem; letter-spacing:.14em; text-transform:uppercase; }
.runahead-shell .st.active { color:var(--accent); text-shadow:var(--glow-gold); }
.runahead-shell .st.draft { color:var(--muted); }
.runahead-shell .st.archived { color:var(--faintest); }

.runahead-shell .verb {
  font-size:0.625rem; letter-spacing:.08em; color:var(--faint); cursor:pointer; text-transform:uppercase;
}
.runahead-shell .verb.gold { color:var(--accent); }

.runahead-shell .datalist-table tbody tr.dim td .t { color:var(--text-dim); }
.runahead-shell .datalist-cards .rowcard.dim { opacity:.75; }

.runahead-shell .datalist-table td .days,
.runahead-shell .datalist-cards .rowcard .meta .days { color:var(--accent); text-shadow:var(--glow-gold-soft); }

/* PLANS/PAUSES controls-row action groups pushed right of the .label (same margin-left:auto
   spacer idiom as .guide.desktop-chrome above, grouped in a wrapper here since each row carries
   more than one button). */
.runahead-shell .controls-row .row-actions { display:flex; align-items:center; gap:8px; margin-left:auto; }

/* ---------- Plan editor (Plans redesign, design spec 2026-07-29-plans-sida-design.md §3,
   reference NOTES 5/8-12, Task P3): identity zone reuses the existing `.zone`/`.label`/`.frow`
   panel family (Profile's spegelzoner) rather than a parallel set. `.stype` mirrors
   `.activity-form .stype` (Type select + its "?" tooltip on one row) but scoped to
   `.runahead-shell` instead: PlanEditor is a routed page inside the shell, not a MudDialogProvider
   sibling like ActivityForm's three homes, so the shell-scoped selector reaches it. */
.runahead-shell .stype { display:flex; align-items:center; gap:4px; }
.runahead-shell .stype > div:first-child { flex:1; min-width:0; }

/* Editor zone stack (owner click-round fix, decision #99 amendment): vertical rhythm between the
   identity zone and each week's `.zone` card, and the air above "+ ADD WEEK" that marks it as
   standing OUTSIDE the section stack -- both were lost because the shared `.zone` class (Profile's
   spegelzoner, decision #92) is deliberately margin-less: those zones sit SIDE BY SIDE in a CSS
   grid whose own `gap` supplies the spacing, so baking a margin into `.zone` itself would double
   up spacing there. This editor stacks zones VERTICALLY in plain flow instead and never got its
   own rhythm rule -- root cause was a missing margin, not a MudBlazor reset or a missing class.
   Scoped to `.editor-zones` (added Task P3 review round) rather than changing `.zone` globally, so
   Profile's grid-based spacing is untouched. Mirrors the reference's own `.zone{margin-bottom:14px}`
   + the ADD WEEK div's `margin:-4px 0 14px` (plans-referens.html) exactly. */
.runahead-shell .editor-zones .zone { margin-bottom: 14px; }
.runahead-shell .editor-zones .addweek { margin: -4px 0 14px; }
/* Size hierarchy (owner click-round fix): ADD SESSION (`.wkhead .verb`, unchanged -- owner
   approved its current smaller-than-reference size) and ADD WEEK share the same gold verb-style
   and weight class (viktklassregeln, both are additions, neither is a Save-button commit) but ADD
   WEEK is the PAGE-level structural action and must read ONE NOTCH LARGER so the hierarchy is
   week-over-session, not just implied by position on the page. */
.runahead-shell .editor-zones .addweek .verb { font-size:0.75rem; }

/* Override-help row (NOTES 8) and the AI-draft review row (NOTES 12) -- `.help` generalized out of
   the weight panel's own `.weight-input .help` scope into a reusable rule (same visual values). */
.runahead-shell .help { font-size:0.6875rem; color:var(--faint); margin-top:4px; line-height:1.5; }
.runahead-shell .aidraft {
  background:linear-gradient(90deg, rgba(216,186,121,.05), transparent);
  border:1px solid var(--border-quiet); border-left:2px solid var(--faint); border-radius:8px;
  padding:8px 12px; font-size:0.6875rem; color:var(--muted); margin-bottom:14px;
}

/* ---------- Guards page (Guards redesign Task G3, design spec 2026-07-30-guards-sida-design.md
   §3, reference docs/design/guards-referens.html NOTES 1-12) ----------
   Own .guards-* classes (identity-bearing UI rule); MudBlazor stays only for the retire dialog
   (PlanConflictDialog reuse) and the ACCEPT/REJECT commit-weight-class buttons. Three zones in
   falling priority: PROPOSALS (opportunistic, full-width read cards -- NOTES 5's "two forms two
   purposes"), PERSONAL/STANDARD GUARDS (instrument grids, NOTES 3-4). */
.runahead-shell .guards-intro { font-size:0.75rem; color:var(--muted); margin-bottom:18px; }
.runahead-shell .guards-intro .guide,
.runahead-shell .guards-howto .guide { font-size:0.6875rem; }

/* HOW THIS WORKS: persistent inline toggle expansion in page flow (NOTES 8) -- reversible, no
   inner scroll -- replaces the old standing scout banner + permanent "no proposals yet" text. */
.runahead-shell .guards-howto {
  background:var(--panel-quiet); border:1px solid var(--border-quiet); border-radius:10px;
  padding:12px 14px; margin-bottom:18px; font-size:0.75rem; color:var(--text-dim); line-height:1.6;
}

/* Zone headers: established heading level (--muted, distinct from the g-stat .label idiom below,
   which stays faintest) with counts; PROPOSALS carries the gold "system's voice" variant (NOTES
   2). Quiet bottom border per the reference. */
.runahead-shell .guards-zone { margin-bottom:26px; }
.runahead-shell .guards-zone-head {
  display:flex; align-items:baseline; gap:8px; margin-bottom:10px;
  border-bottom:1px solid var(--border-quiet); padding-bottom:6px;
}
.runahead-shell .guards-zone-title { font-size:0.6875rem; letter-spacing:.14em; color:var(--muted); text-transform:uppercase; }
.runahead-shell .guards-zone-title.gold { color:var(--accent); }
.runahead-shell .guards-zone-count { font-size:0.6875rem; color:var(--faint); }

/* PROPOSALS: full-width READ card (NOTES 5, zone-form distinction) -- gold left edge, description
   read in full width, provenance line, ACCEPT (filled/commit)+REJECT (dim/text) actions. flex-wrap
   on .p-top is what makes the action row wrap below the name on narrow viewports (mobile block
   below adds the explicit column layout so it wraps deliberately rather than only when it happens
   to run out of room). */
.runahead-shell .guards-proposal {
  background:linear-gradient(180deg, var(--panel-top), var(--panel-bot));
  border:1px solid var(--border); border-left:2px solid var(--accent); border-radius:10px;
  padding:14px 16px; max-width:820px; margin-bottom:12px;
}
.runahead-shell .guards-proposal .p-top { display:flex; justify-content:space-between; align-items:flex-start; gap:16px; flex-wrap:wrap; }
.runahead-shell .guards-proposal .name { font-size:0.875rem; color:var(--text); }
.runahead-shell .guards-proposal .desc { font-size:0.75rem; color:var(--text-dim); line-height:1.55; margin:7px 0 9px; max-width:64ch; }
.runahead-shell .guards-proposal .p-actions { display:flex; gap:8px; flex-shrink:0; }
.runahead-shell .guards-proposal .prov { font-size:0.625rem; color:var(--faintest); letter-spacing:.03em; }

/* Own button family (house rule: MudBlazor stays reserved for the retire dialog on this page --
   ACCEPT/REJECT/REACTIVATE are plain clickable spans, same idiom as .verb/.showall/.guide). .fill
   reuses the seg switch's active-state gradient tokens (--zoom-on-bg/-fg) rather than re-declaring
   the gold gradient a third time; .dim is the muted bordered variant (REJECT/REACTIVATE). */
.runahead-shell .guards-btn {
  display:inline-block; border:1px solid var(--border); border-radius:7px; padding:5px 12px;
  font-size:0.625rem; letter-spacing:.06em; color:var(--accent); cursor:pointer;
}
.runahead-shell .guards-btn.fill { background:var(--zoom-on-bg); color:var(--zoom-on-fg); border-color:var(--accent-lo); }
.runahead-shell .guards-btn.dim { color:var(--muted); }

/* Empty personal zone (NOTES 2): a single faint line, no permanent banner. */
.runahead-shell .guards-empty { color:var(--faint); font-size:0.75rem; }

/* INSTRUMENT GRID (NOTES 3): 3 columns wide desktop, 2 at a narrower desktop step. The 2-column
   step is a CONTAINER query scoped to the grid's own box (container-type:inline-size on the host
   wrapper) rather than a viewport media rule -- BreakpointParityTests requires every viewport
   width media query to share the single 768px mobile breakpoint; a container query answers the
   grid's OWN rendered width, not the viewport, so it never enters that scan (the test only matches
   the literal at-rule keyword the viewport form uses) while still giving a genuinely responsive 3/2
   step picked against real content width (~1100px). The forced single column below the 768px
   VIEWPORT breakpoint is the one true instance of that viewport rule, in the mobile block. Equal
   row height + top-anchored content (align-items:stretch, same rule as Profile's mirror zones) --
   .g-desc flex-grows so every card's .g-foot bottoms out level with its row neighbors regardless of
   description length. */
.runahead-shell .guards-grid-host { container-type:inline-size; container-name:guards-grid; }
.runahead-shell .guards-grid { display:grid; grid-template-columns:repeat(3, 1fr); gap:12px; align-items:stretch; }
@container guards-grid (max-width: 1100px) {
  .runahead-shell .guards-grid { grid-template-columns:repeat(2, 1fr); }
}

/* Card anatomy, INVERTED hierarchy (NOTES 4): name top-left full weight, key figure top-right in
   the LABEL idiom (reuses the house .label class for "LAST FLAGGED"/blank -- same faintest token
   as every other row-identity label in the app), description dim+small and flex-grown, footer row
   with a quiet top border (provenance + RETIRE verb, or the STANDARD GUARD chip). */
.runahead-shell .guards-card {
  background:var(--panel-quiet); border:1px solid var(--border-quiet); border-radius:10px;
  padding:12px 14px; display:flex; flex-direction:column; gap:7px;
}
.runahead-shell .guards-card .g-top { display:flex; justify-content:space-between; align-items:flex-start; gap:12px; }
.runahead-shell .guards-card .g-name { font-size:0.8125rem; color:var(--text); line-height:1.3; }
.runahead-shell .guards-card .g-stat { text-align:right; flex-shrink:0; }
.runahead-shell .guards-card .g-stat .label { display:block; line-height:1.5; margin-bottom:2px; }
.runahead-shell .guards-card .g-stat .val { display:block; line-height:1.4; font-size:0.75rem; color:var(--text); white-space:nowrap; }
.runahead-shell .guards-card .g-stat .val .times { color:var(--text-dim); }
.runahead-shell .guards-card .g-stat.never .val { color:var(--faint); font-size:0.625rem; letter-spacing:.1em; }
.runahead-shell .guards-card .g-desc { color:var(--faint); font-size:0.6875rem; line-height:1.45; flex-grow:1; }
.runahead-shell .guards-card .g-foot {
  display:flex; justify-content:space-between; align-items:baseline; gap:10px;
  border-top:1px solid var(--border-quiet); padding-top:7px;
}
.runahead-shell .guards-card .prov { font-size:0.625rem; color:var(--faintest); letter-spacing:.03em; }
/* RetirementSuggested marker (NOTES 4): a dim TEXT marker inline with the provenance, never a
   colored MudChip -- reads immediately before the RETIRE verb it explains. */
.runahead-shell .guards-card .retire-hint { color:var(--muted); }

/* STANDARD GUARD chip: bordered mini-chip, display-only (no verbs -- NOTES 9). Own class rather
   than the existing `.chip` (that one is the hero card's unbordered margin-topped badge, a
   different visual family entirely). */
.runahead-shell .guards-chip {
  font-size:0.5625rem; letter-spacing:.1em; color:var(--faint); text-transform:uppercase;
  border:1px solid var(--border-quiet); border-radius:4px; padding:1px 6px; white-space:nowrap;
}

/* Rejected & retired rows, behind the house Show-family toggle (NOTES 2 -- replaces the old
   MudExpansionPanel). */
.runahead-shell .guards-inactive-row {
  display:flex; justify-content:space-between; align-items:center; gap:8px;
  padding:8px 0; border-bottom:1px solid var(--border-quiet);
}
.runahead-shell .guards-inactive-row .title { font-size:0.8125rem; color:var(--text-dim); }
/* VISK role, moved down from --faint (:root Neutral hierarchy comment, spec §1.3):
   OWNER-DECIDED DOWN -- the scout date row's kin, archive status inside a disclosure. */
.runahead-shell .guards-inactive-row .status { font-size:0.625rem; color:var(--faintest); letter-spacing:.08em; text-transform:uppercase; }

/* Week section head (NOTES 10): editable label field ("Week N" default, PlanEditorLogic owns the
   renumbering rule), ADD SESSION + week delete. `.trash` is a new class family (this pass's first
   use) for the red delete affordance the reference draws as a plain "✕" rather than a MudIconButton
   -- same dampened-verb tone family as `.verb`/`.showall`, own class since red carries meaning
   (--red is the CONTROL role per the theme's glow discipline) that `.verb`'s faint/gold pair
   doesn't. */
.runahead-shell .wkhead { display:flex; align-items:center; gap:10px; margin-bottom:8px; flex-wrap:wrap; }
.runahead-shell .wkhead .wklabel { min-width:130px; }
.runahead-shell .wkhead .spacer { flex:1; }
.runahead-shell .trash { color:var(--red); opacity:.6; cursor:pointer; font-size:0.75rem; }
.runahead-shell .trash:hover { opacity:1; }

/* Session rows, RADFORM (NOTES 11): a div-grid "table" rather than a literal <table> -- SessionRow
   emits its mobile `.sesscard` form as a DOM sibling of the desktop `.sess-row`, and a real
   <table>/<tbody> would make that sibling an invalid tbody child even though .desktop-chrome/
   .mobile-chrome keeps only one of the two visible at a time (Blazor builds the DOM directly, so
   the browser never rejects it, but the shape is still wrong to author deliberately). Column
   widths are fixed via the grid template rather than per-field classes sized individually, so the
   Day/Type/Sport/Title/Km/Time/Pace/Actions header row (`.sess-head`) and every `SessionRow`
   share one alignment definition. */
.runahead-shell .sess-row {
  display:grid; grid-template-columns:64px 96px 96px 1fr 56px 64px 74px 52px;
  gap:6px; align-items:center; padding:3px 0;
}
.runahead-shell .sess-head span {
  font-size:0.5625rem; letter-spacing:.12em; color:var(--faintest); text-transform:uppercase;
}
.runahead-shell .sess-actions { display:flex; align-items:center; gap:6px; justify-content:flex-end; }

/* Mobile stacked session card (NOTES 5/14): row 1 day+type+trash, row 2 title, row 3 km/time/pace
   -- the row form doesn't fit at 375px, so the same bound fields render into this shape instead
   (reference panel 4). */
.runahead-shell .sesscard {
  background:var(--panel-quiet); border:1px solid var(--border-quiet); border-radius:8px;
  padding:9px 11px; margin-bottom:8px;
}
.runahead-shell .sesscard .l1 { display:flex; gap:8px; align-items:center; justify-content:space-between; }
.runahead-shell .sesscard .l1 > span:first-child { display:flex; gap:6px; flex:1; min-width:0; }
.runahead-shell .sesscard .l2 { display:flex; gap:8px; margin-top:6px; }
.runahead-shell .sesscard .l2 > * { flex:1; min-width:0; }

/* "What gets imported" guide dialog content (ActivityImportGuideDialog). MudDialogProvider is a
   SIBLING of .runahead-shell (MainLayout), not nested inside it -- scoped to .runahead-app
   instead, same as the tabbar/sysbar rules above that also render outside the shell. */
.runahead-app .import-guide-list { margin:0; padding-left:18px; color:var(--text-dim); font-size:0.8125rem; line-height:1.6; }

/* ---------- Activity detail page, four bands (design spec §3, reference NOTES 2-8, Task A4) ----------
   Replaces the old MudSimpleTable row dump. Reuses the shared `.label`/`.controls-row` tokens
   already declared above rather than inventing a parallel set -- only the band-specific layout
   rules (flex/grid/spacing) and the two new leaf value classes (`.stat .v`, `.userrow .tx`) are
   new here. */
.runahead-shell .hero-row { display:flex; align-items:flex-start; justify-content:space-between; gap:12px; margin-bottom:4px; }
.runahead-shell .d-meta { font-size:0.75rem; color:var(--muted); margin:2px 0 16px; }

/* Statband (NOTES 3): replaces five of the old table rows. flex-wrap so it wraps naturally at
   375px (house rule: never horizontal scroll) instead of clipping or squeezing the values. */
.runahead-shell .statband {
  display:flex; gap:26px; flex-wrap:wrap; border-top:1px solid var(--border-quiet);
  border-bottom:1px solid var(--border-quiet); padding:12px 2px; margin-bottom:12px;
}
.runahead-shell .statband .stat .label { display:block; margin-bottom:3px; }
.runahead-shell .statband .stat .v { font-size:1rem; color:var(--text); font-family:inherit; }

/* User-content row (NOTES 4): Notes + Gear as CONTEXT, not technical metadata -- own row before
   the graph, each block opportunistic (the page omits the whole row, and each block within it,
   when empty; no "-" placeholder for absent context). */
.runahead-shell .userrow { display:flex; gap:26px; flex-wrap:wrap; margin-bottom:16px; }
.runahead-shell .userrow .blk { min-width:180px; }
.runahead-shell .userrow .blk .label { display:block; margin-bottom:4px; }
.runahead-shell .userrow .blk .tx { font-size:0.75rem; color:var(--text-dim); line-height:1.5; }

/* Chartbox (Task U2, design spec Del 2): each of HR/Pace/Laps gets its own box; a following
   chartbox gets a quiet top divider + a little air instead of the sections flowing straight into
   each other — the house avdelaridiom, same shape as the other `border-top: 1px solid
   var(--border-quiet)` separators in this file. */
.runahead-shell .chartbox + .chartbox { border-top:1px solid var(--border-quiet); padding-top:0.9rem; margin-top:1.1rem; }

/* Laps table (NOTES 6-7): dual desktop/mobile form via the house .desktop-chrome/.mobile-chrome
   idiom (two separate <table> elements sharing this class family -- the DataList/guide-link
   precedent, chosen over CSS nth-child column hiding because a dropped COLUMN, not just a
   narrower one, is simplest and least fragile as two small static markups). Right-aligned value
   columns, label-idiom header row -- same recipe as `.datalist-table` above, own class family
   since this is a distinct visual instance (no sort arrows, no hover-row affordance). */
.runahead-shell .laps-table { width:100%; border-collapse:collapse; margin-top:8px; }
.runahead-shell .laps-table th {
  font-size:0.625rem; letter-spacing:.14em; color:var(--faintest); text-transform:uppercase;
  text-align:right; padding:5px 8px; border-bottom:1px solid var(--border);
}
.runahead-shell .laps-table th:first-child { text-align:left; }
.runahead-shell .laps-table td {
  padding:6px 8px; border-bottom:1px solid var(--border-quiet); font-size:0.75rem; color:var(--text-dim); text-align:right;
}
.runahead-shell .laps-table td:first-child { text-align:left; color:var(--muted); }

/* Faint footer (NOTES 2): SOURCE + SAMPLES metadata, LAST band on the page. */
.runahead-shell .footrow { font-size:0.625rem; color:var(--faintest); letter-spacing:.08em; margin-top:14px; }

/* ---------- ActivityForm (design spec §4, reference panel 4, NOTES 12-14, Task A5) ----------
   The shared Add/Edit form, three homes: ManualDialog (desktop MudDialog), ActivityAddSheet
   (mobile full-screen sheet), ActivityEditPage (its own /activities/{id}/edit route). UNSCOPED
   (not .runahead-shell-prefixed), same reasoning as .trendchart/.terms-doc above:
   MudDialogProvider renders as a .runahead-shell SIBLING (MainLayout comment near the mobile
   header below), so a shell-scoped .sect/.label selector would silently not apply inside
   ManualDialog -- this form must look identical in all three homes regardless of where the DOM
   happens to nest it. Group header recipe duplicates .runahead-shell .label's visual values
   rather than depending on it, for the same self-containment reason. */
.activity-form .grp { margin-bottom:18px; }
.activity-form .grp-label {
  display:block; margin-bottom:8px; font-size:0.625rem; letter-spacing:.16em; color:var(--faintest);
  text-transform:uppercase;
}
.activity-form .frow { display:flex; gap:10px; flex-wrap:wrap; }
.activity-form .frow > * { flex:1; min-width:140px; }
/* Session type + its "?" tooltip (NOTES 12) share one flex row so the qmark sits beside the
   select, never wrapping onto its own line. */
.activity-form .stype { display:flex; align-items:center; gap:4px; flex:1; min-width:140px; }
.activity-form .stype > div { flex:1; min-width:0; }
.activity-form .qmark {
  /* Circle box in rem: same fix/reason as .runahead-shell .qmark above (0.8125rem keeps the
     circle scaling with its own rem font-size across a root snap). */
  display:inline-block; width:0.8125rem; height:0.8125rem; border:1px solid var(--faint); border-radius:50%;
  /* line-height in rem: same fix/reason as .runahead-shell .qmark above (0.75rem keeps the
     original 12/16 ratio to font-size scaling together with a root snap). */
  color:var(--faint); font-size:0.5625rem; text-align:center; line-height:0.75rem; cursor:help; flex:0 0 auto;
}
.activity-form .actions { display:flex; gap:8px; margin-top:6px; }

/* ---------- ActivityAddSheet (design spec §4, Task A5): mobile full-screen Add home ----------
   MoreSheet's own pointer-drag mechanics (down/move/up/cancel/leave), but a FULL-HEIGHT sheet
   rather than MoreSheet's bottom quietcard -- Add is a real form, not a short menu. Own class
   family (.actsheet-*) instead of reusing .msheet-*: the visual form differs (full height, no
   rounded top corners), only the drag mechanics are shared. z-index above the tabbar/msheet
   family (6/7) since the full-screen form covers everything, including the tab bar, while open.
   Display-none by default via the shared .mobile-chrome idiom; the display:block switch lives in
   the 768px block below, same host-class pattern as .msheet-host/.mweight-host. */
.runahead-app .actsheet-overlay { position: fixed; inset: 0; z-index: 8; background: rgba(0, 0, 0, .55); }
.runahead-app .actsheet {
  position: fixed; inset: 0; z-index: 8; overflow-y: auto;
  background: linear-gradient(180deg, var(--panel-top), var(--panel-bot));
  padding: 10px 16px calc(16px + env(safe-area-inset-bottom));
}
.runahead-app .actsheet-grab { width: 36px; height: 4px; border-radius: 2px; background: #2a2620;
  margin: 2px auto 14px; cursor: grab; touch-action: none; }
.runahead-app .actsheet-title { display:block; margin-bottom:14px; font-size:0.625rem; letter-spacing:.16em;
  color:var(--faintest); text-transform:uppercase; }

/* ---------- Investigations page + report document (design spec 2026-08-01-investigations-sida-
   design.md §I3, reference docs/design/investigations-referens.html NOTES 1-9, BINDING) ----------
   Own .inv-* classes; reuses the house `.label`/`.guide`/`.zone-head`/`.zone-title`/`.prose-col`
   families (Guards/Today precedent) rather than duplicating them. MudBlazor stays only for the
   question textarea + RUN button (behavior-heavy form input, per the theme-tokens rule) and the
   quota hint. */
.runahead-shell .inv-intro { font-size:0.75rem; color:var(--muted); margin-bottom:10px; }
.runahead-shell .inv-intro .guide,
.runahead-shell .inv-howto .guide { margin-left:6px; }
.runahead-shell .inv-howto {
  background:var(--panel-quiet); border:1px solid var(--border-quiet); border-radius:10px;
  padding:12px 14px; margin-bottom:14px; font-size:0.75rem; color:var(--text-dim); line-height:1.6;
}

.runahead-shell .inv-field { max-width:640px; margin-bottom:6px; }
.runahead-shell .inv-run-row { display:flex; align-items:center; gap:12px; }
.runahead-shell .inv-quota { color:var(--faintest); }

/* Example questions (reference NOTES 4): dim, ›-prefixed, click fills the field -- guidefri
   onboarding of the question surface's range. Same dampened-link tone as `.guide`, own class since
   the ::before prefix and block-per-line layout are specific to this list. */
.runahead-shell .inv-examples { margin-top:10px; }
.runahead-shell .inv-examples .ex {
  display:block; font-size:0.6875rem; color:var(--faint); cursor:pointer; padding:3px 0;
}
.runahead-shell .inv-examples .ex:hover { color:var(--accent); }
.runahead-shell .inv-examples .ex::before { content:"› "; color:var(--faintest); }

/* Running card (reference NOTES 5): gold left edge + pulse dot -- the system's own voice, same
   "state role, never decoration" glow discipline as `.highlight-row`/`.hero-line` elsewhere. */
.runahead-shell .inv-runcard {
  background:linear-gradient(180deg, var(--panel-top), var(--panel-bot));
  border:1px solid var(--border); border-left:2px solid var(--accent); border-radius:10px;
  padding:12px 15px; margin:14px 0;
}
.runahead-shell .inv-runcard .pulse {
  display:inline-block; width:7px; height:7px; border-radius:50%; background:var(--accent);
  box-shadow:var(--glow-gold-soft); margin-right:8px; animation:sysbar-pulse 2.4s ease-in-out infinite;
}
.runahead-shell .inv-run-text { font-size:0.75rem; color:var(--text-dim); }
.runahead-shell .inv-run-text .q { color:var(--muted); }
.runahead-shell .inv-run-caption { font-size:0.625rem; color:var(--faintest); margin-top:4px; letter-spacing:.06em; }
.runahead-shell .inv-coalesced { font-size:0.75rem; color:var(--status-swapped); margin-top:6px; }
.runahead-shell .inv-error { font-size:0.75rem; color:var(--red); margin:14px 0; }
/* The running card's pulse stops under reduced motion, same accommodation as the sysbar/mobile
   header pulses it borrows the keyframe from. */
@media (prefers-reduced-motion: reduce) {
  .runahead-shell .inv-runcard .pulse { animation:none; opacity:1; }
}

/* Provenance chip (reference NOTES 6, .chip/.signal/.scout): bordered mini-chip, same family as
   `.guards-chip` (own class rather than the unrelated hero-card `.chip`, see that class's own
   comment above). USER QUESTION stays the neutral base; FROM SIGNAL/SCOUT get the reference's exact
   status-extra / gold-low border+text tones. */
.runahead-shell .inv-chip {
  font-size:0.5625rem; letter-spacing:.1em; color:var(--faint); text-transform:uppercase;
  border:1px solid var(--border-quiet); border-radius:4px; padding:1px 6px; white-space:nowrap;
}
.runahead-shell .inv-chip.signal { color:var(--status-extra); border-color:#1d3140; }
.runahead-shell .inv-chip.scout { color:var(--accent-lo); border-color:#2e2716; }

.runahead-shell .inv-notfound { font-size:0.8125rem; color:var(--faint); margin:14px 0; }

/* Report document (reference NOTES 7-8): sections labeled in the faintest-uppercase `.label`
   idiom, VERDICT accentuated with a gold left border (the answer's core), FINDINGS/RECOMMENDATIONS
   as dash-marker items in full text (no client-side truncation -- I1 already lifted the server-side
   250-char clip), DETAILS as plain paragraphs. `.prose-col` (existing, ~720px) bounds the width. */
.runahead-shell .inv-report .instance-label { margin-bottom:4px; }
.runahead-shell .inv-meta {
  font-size:0.65625rem; color:var(--faintest); margin-bottom:16px; display:flex; gap:10px; align-items:center;
}
.runahead-shell .inv-sec { margin:16px 0 0; }
.runahead-shell .inv-sec .label { display:block; margin-bottom:6px; }
.runahead-shell .inv-verdict {
  font-size:0.875rem; color:var(--text); line-height:1.6; border-left:2px solid var(--accent); padding-left:12px;
}
.runahead-shell .inv-fitem {
  font-size:0.78125rem; color:var(--text-dim); line-height:1.6; margin:0 0 9px; padding-left:14px; position:relative;
}
.runahead-shell .inv-fitem::before { content:"—"; position:absolute; left:0; color:var(--faintest); }
.runahead-shell .inv-para { font-size:0.75rem; color:var(--text-dim); line-height:1.65; margin:0 0 10px; }

/* Timeline (process proof, reference NOTES 9): dampened appendix AFTER the report, own toggle. */
.runahead-shell .inv-timeline { border-top:1px solid var(--border-quiet); margin-top:20px; padding-top:10px; }
.runahead-shell .inv-timeline-head { display:flex; align-items:center; gap:8px; margin-bottom:6px; }
.runahead-shell .inv-tstep { display:flex; gap:12px; font-size:0.6875rem; padding:3px 0; color:var(--faint); }
.runahead-shell .inv-tstep .tn { color:var(--muted); min-width:170px; }
.runahead-shell .inv-tstep .tm { color:var(--faintest); }
/* Expand/collapse three-state (reference NOTES 9/12, resolved WITHOUT JS interop): the body carries
   exactly one of auto/open/closed (InvestigationReport.razor's TimelineBodyClass). "closed" hides at
   EVERY width -- one rule here covers both, no media query needed since the class itself is the
   explicit override. "open" needs no rule at all: a div's default display is block, so it is already
   visible everywhere the "auto" hide-under-768 rule (below, inside the shared breakpoint block)
   doesn't reach it -- the classes are mutually exclusive, so "open" is never touched by that rule.
   "auto" (the no-explicit-choice default) is left NOT hidden here on purpose: visible above 768px is
   the plain CSS default, only the below-768px case needs an explicit override. */
.runahead-shell .inv-timeline-body.closed { display:none; }

.validation-message {
    color: var(--red);
}

#blazor-error-ui {
    color-scheme: dark;
    background: var(--surface);
    color: var(--text);
    border-top: 1px solid var(--red);
    bottom: 0;
    box-shadow: none;
    box-sizing: border-box;
    display: none;
    left: 0;
    padding: 0.6rem 1.25rem 0.7rem 1.25rem;
    position: fixed;
    width: 100%;
    z-index: 1000;
}

    #blazor-error-ui .dismiss {
        cursor: pointer;
        position: absolute;
        right: 0.75rem;
        top: 0.5rem;
    }

.blazor-error-boundary {
    background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, var(--surface);
    padding: 1rem 1rem 1rem 3.7rem;
    color: var(--text); border: 1px solid var(--red);
}

    .blazor-error-boundary::after {
        content: "An error has occurred."
    }

.loading-progress {
    position: absolute;
    display: block;
    width: 8rem;
    height: 8rem;
    inset: 20vh 0 auto 0;
    margin: 0 auto 0 auto;
}

    .loading-progress circle {
        fill: none;
        stroke: var(--border);
        stroke-width: 0.6rem;
        transform-origin: 50% 50%;
        transform: rotate(-90deg);
    }

        .loading-progress circle:last-child {
            stroke: var(--accent);
            stroke-dasharray: calc(3.141 * var(--blazor-load-percentage, 0%) * 0.8), 500%;
            transition: stroke-dasharray 0.05s ease-in-out;
        }

.loading-progress-text {
    position: absolute;
    text-align: center;
    font-weight: bold;
    inset: calc(20vh + 3.25rem) 0 auto 0.2rem;
    color: var(--muted);
}

    .loading-progress-text:after {
        content: var(--blazor-load-percentage-text, "Loading");
    }

/* ============ Mobile (breakpoint 768px = Breakpoints.MobileMaxPx; BreakpointParityTests
   is the watchdog — every width-based media query in this file MUST use exactly 768px).
   Dual-render rule (design §2): both chrome forms live in the DOM; display:none SPECIFICALLY
   (never visibility/opacity) so the hidden form leaves the accessibility tree and tab order.
   Mobile chrome is signed-in surface: signed out shows the desktop chrome at every width. */
.mobile-chrome { display: none; }

@media (max-width: 768px) {
  /* Signed in under the breakpoint: desktop chrome out, mobile chrome in. The .authed class
     is stamped on .runahead-app by MainLayout from auth state. */
  .runahead-app.authed .desktop-chrome { display: none; }
  .runahead-app.authed .sysbar { display: none; }
  .runahead-app.authed .m-header.mobile-chrome { display: flex; }
  .runahead-app.authed .tabbar.mobile-chrome { display: flex; }
  .runahead-app.authed .msheet-host.mobile-chrome { display: block; }
  .runahead-app.authed .mweek-host.mobile-chrome { display: block; }
  .runahead-app.authed .mblock-host.mobile-chrome { display: block; }
  /* Content must not hide behind the fixed tab bar (~58px measured: 9+11px padding + 22px
     icon + label/gap; 64px reserved for headroom) + iPhone home indicator. */
  .runahead-app.authed .runahead-shell { padding-bottom: calc(64px + env(safe-area-inset-bottom)); }
  /* Week-nav one-row healing (MG5, reference NOTES 12): the switch + arrows + range must never
     wrap under the breakpoint (the forward arrow wrapping onto its own line was the bug). This
     ellipsis rule is superseded below (Task 3 hides .wk-range entirely under the breakpoint in
     favor of .wk-range-compact) but is kept as a harmless guard against desktop-format leaks. */
  .runahead-app.authed .controls-row { flex-wrap: nowrap; }
  .runahead-app.authed .wk-range { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }

  /* Week-nav two-group form (mobile 1.5 Task 3, design §4 NOTES 5-6): the pager (‹ range ›) is
     pushed right, away from the zoom switch, via space-between on the row and .wk-pager becoming
     a real flex item (overriding the desktop display:contents above). The full ISO .wk-range is
     replaced by the compact mobile-formatted .wk-range-compact; arrows get a minimum hit width. */
  .runahead-app.authed .controls-row { justify-content: space-between; }
  .runahead-app.authed .wk-pager { display: flex; align-items: center; gap: 6px; }
  .runahead-app.authed .wk-weeknav { min-width: 34px; }
  .runahead-app.authed .wk-range { display: none; }
  /* Fixed-width range box (owner adjustment after live review): the arrows are a REPEATED
     tap target — muscle memory breaks if they shift with the interval text's width. Sized to
     the longest binding format, the year-boundary case "29 DEC–4 JAN" (NOTES 6): 12 chars ≈
     12ch + letter-spacing (.12em × 12 ≈ 2.4ch) → 15ch with headroom. Block's "V.27–32" is
     shorter and centers in the same box, so Week/Block switching moves nothing either. */
  .runahead-app.authed .wk-range-compact { display: inline-block; white-space: nowrap;
    width: 15ch; text-align: center; }

  /* Today stapling (mobile 1.5 Task 2, spec §1 NOTES 1): single-column full-width stack. DOM
     order already gives hero -> TOMORROW -> LATEST (.rightcol keeps its own column-flex
     direction, untouched) and state C's LATEST-hero -> PLAN collapse for free, both for free —
     no markup change, pure form. */
  .runahead-app.authed .maingrid { grid-template-columns: 1fr; }

  /* Title-ellipsis (mobile 1.5 Task 2, spec §1 NOTES 3, mweek-rule): .hero-title (TodayHero's
     three branches, LatestCard's Hero branch, and the plan-free empty-account fallback inline in
     Today.razor) and .card-text-strong (LatestCard/TomorrowCard smallcards) are the title-bearing
     lines in this composition. Unlike .wk-title's parent .wk-card (flex column with
     align-items:flex-start, which sizes children to fit-content and needs align-self:stretch to
     give the title a real box to clip against), .hero and .smallcard are display:block — a block
     child already stretches to its parent's full width by default, so no stretch fix applies here
     (verified against the .hero/.smallcard rules above before writing this; only
     nowrap/hidden/ellipsis/min-width:0 are needed). Desktop above the breakpoint keeps wrapping
     unchanged (no rule outside this media block touches these classes). */
  .runahead-app.authed .hero-title,
  .runahead-app.authed .card-text-strong {
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0;
  }

  /* Row healing (mobile 1.5 Task 2, spec §2 NOTES 2), same controls-row pattern as .wk-range
     above: .toprow/.bottomrow never wrap and their flexible tails never clip silently. Fixed
     (flex:0 0 auto): the date, the dots group, and the countdown's day-count + unit (the number
     is the information itself and must never truncate). Flexible (ellipsed): the race name label
     and the attention row. .race gets its own flex context (Today.razor) so the label alone
     shrinks while the day-count/unit stay put. */
  .runahead-app.authed .toprow,
  .runahead-app.authed .bottomrow { flex-wrap: nowrap; }
  .runahead-app.authed .toprow .date { flex: 0 0 auto; }
  .runahead-app.authed .toprow .race { display: flex; align-items: baseline; gap: 4px; min-width: 0; }
  .runahead-app.authed .race-label {
    min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  .runahead-app.authed .race-days,
  .runahead-app.authed .race-unit { flex: 0 0 auto; }
  .runahead-app.authed .dots { flex: 0 0 auto; }
  .runahead-app.authed .attention-row {
    min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }

  /* Profile mirror zones (spec §1 NOTES 8): mobile stacking is DOM order alone (input zone
     before derivation zone) — the single column is the only change, no markup duplication. */
  .runahead-app.authed .profile-zones { grid-template-columns: 1fr; }

  /* Onboarding steps (design spec §"Todays skyddsnät"/CSS + mobil, reference NOTES 11): the `.ob`
     column is already a single-card stack at every width, so mobile only trims size/padding —
     same values the reference's phone frame uses. */
  .runahead-app.authed .ob-title { font-size:1.3125rem; }
  .runahead-app.authed .ob-card { padding: 16px; }

  /* Weight entries list (spec §2 NOTES 5): switches the desktop table off (.desktop-chrome is
     already covered by the generic rule above) and the mobile rowcards on, same host-class idiom
     as .mweek-host/.mblock-host. */
  .runahead-app.authed .mweight-host.mobile-chrome { display: block; }

  /* DataList mobile cards (spec §1, reference NOTES 9): same host-class idiom as .mweek-host/
     .mblock-host/.mweight-host above, except the host class lives ON the component's own root
     (.datalist-cards) rather than a per-page wrapper — DataList is the shared primitive, so its
     dual-form switch travels with it into every future consumer instead of being re-declared per
     page. */
  .runahead-app.authed .datalist-cards.mobile-chrome { display: block; }

  /* AdminTabs mobile chip row (Task A3, design spec "Del 9a", reference NOTES 1): same host-class
     idiom as .datalist-cards above -- the host class lives on the component's own root. */
  .runahead-app.authed .admin-tabs-mobile.mobile-chrome { display: block; }

  /* AdminCoachLinksSection minimal containment (click-round Finding 4, NOTES 6's "form stays
     unchanged" exemption is not a licence to burst the viewport): the two selects drop their
     fixed 260px floor and take the wrapped row's full width instead, so the control row and the
     table wrapper above both stay inside the 375 viewport with no page-level horizontal scroll. */
  .runahead-app.authed .admin-coach-select { min-width: 0; width: 100%; }

  /* Plan card header (Task A9, design spec "Del 9b"): flex-direction switch, same idiom as
     .guards-proposal .p-top below -- title block stacks above the action-button row instead of
     both squeezing into one line with no room. */
  .runahead-app.authed .admin-plan-head { flex-direction: column; align-items: flex-start; }
  .runahead-app.authed .admin-plan-actions { margin-top: 8px; }

  /* Activity detail laps table, mobile form (design spec §3, reference NOTES 7): the desktop
     5-value-column table is already covered by the generic .desktop-chrome rule above; this
     revives the 4-column mobile table, same host-class idiom as every other .mobile-chrome
     element in this block. A <table> needs an explicit `display: table` (not `block`) to keep
     its row/cell layout. */
  .runahead-app.authed .laps-table.mobile-chrome { display: table; }

  /* Activities list's mobile-only toolbar/controls-row pieces (design spec §2/§4, reference
     NOTES 11-12): the "Sort: Date ▾" cycle button, the short-placeholder search field, and the
     .guide-mobile "What gets imported" link all follow the same reveal-under-768 idiom as every
     other .mobile-chrome element above; the desktop .guide/.search are already covered by the
     generic .desktop-chrome rule near the top of this block. */
  .runahead-app.authed .datalist-toolbar .sort-cycle.mobile-chrome { display: inline-flex; align-items: center; justify-content: space-between; gap: 4px; }
  .runahead-app.authed .datalist-toolbar .search.mobile-chrome { display: block; }
  .runahead-app.authed .controls-row .guide-mobile.mobile-chrome { display: inline-flex; }

  /* Add home trigger + sheet (design spec §4, Task A5): the mobile "Add manually" button
     (scoped to .controls-row, not a blanket .mobile-chrome reveal, so other pages' controls-row
     mobile-chrome children -- none exist today -- aren't silently affected by this rule) and the
     ActivityAddSheet host, same host-class idiom as .msheet-host/.mweight-host above. */
  .runahead-app.authed .controls-row .add-mobile.mobile-chrome { display: inline-flex; }
  .runahead-app.authed .actsheet-host.mobile-chrome { display: block; }

  /* Plans overview's two top-row buttons (design spec §2/§4, reference NOTES 14, button-label
     rule): shortened GENERATE/NEW labels replace GENERATE WITH AI/NEW PLAN under the breakpoint,
     same desktop-chrome/mobile-chrome dual-element idiom as Activities' Add trigger above. */
  .runahead-app.authed .controls-row .plans-generate-mobile.mobile-chrome,
  .runahead-app.authed .controls-row .plans-new-mobile.mobile-chrome { display: inline-flex; }

  /* Plan editor, mobile session card (design spec §3, reference NOTES 5/14, Task P3): the row
     form's desktop `.sess-row`/`.sess-head` are already covered by the generic .desktop-chrome
     rule above; this reveals the stacked `.sesscard` in its place, plus the week head's shortened
     ADD/✕ verb pair (same knappetikettregel as Activities' GENERATE/NEW, decision #95). */
  .runahead-app.authed .sesscard.mobile-chrome { display: block; }
  .runahead-app.authed .wkhead .verb.mobile-chrome,
  .runahead-app.authed .wkhead .trash.mobile-chrome { display: inline-block; }

  /* Weight input row, mobile own-form (owner adjustment after live review, decision #93
     amendment): the row wraps instead of squeezing every field to fit (the root cause of the
     observed clip — date placeholder to "7/", weight to "Weig" with overlapping spinner arrows).
     Date/weight get a protected flex-basis+min-width so they can never shrink below a readable
     placeholder; Add naturally wraps to its own line when the row has no room left for it, never
     overlapping the fields. */
  .runahead-app.authed .weight-input .inrow { flex-wrap: wrap; }
  .runahead-app.authed .weight-input .wt-date { flex: 0 0 130px; min-width: 130px; }
  .runahead-app.authed .weight-input .wt-kg { flex: 0 0 90px; min-width: 90px; }

  /* Guards page (design spec 2026-07-30-guards-sida-design.md §3, reference NOTES 3/12): the
     instrument grid collapses to a single column below the viewport breakpoint (the one true
     viewport-media step -- the 3/2 desktop steps above use a container query, see
     .guards-grid-host in the desktop rules). The proposal card's action row wraps below the name
     (NOTES 5's mobile panel) via flex-direction switching rather than a second markup form. */
  .runahead-app.authed .guards-grid { grid-template-columns: 1fr; }
  .runahead-app.authed .guards-proposal .p-top { flex-direction: column; align-items: flex-start; }
  .runahead-app.authed .guards-proposal .p-actions { margin-top: 8px; }

  /* Investigation report timeline, "auto" default (design spec §I3, reference NOTES 9/12,
     coordinator follow-up): the ONE width-based rule the three-state pattern needs -- collapsed by
     default under the breakpoint when the athlete has made no explicit open/closed choice yet (see
     .inv-timeline-body.closed's always-hidden rule outside this block, and TimelineBodyClass's own
     comment in InvestigationReport.razor). Above 768px "auto" stays visible via plain CSS default,
     no rule needed there. */
  .runahead-app.authed .inv-timeline-body.auto { display: none; }

  /* Landing page mobile stacking (design spec §L1 point 4, reference NOTES 7): hero, login card
     (full width), and status block simply stack in DOM order already -- no grid, so this is
     value overrides only, not a new layout. NOT gated by .authed, unlike every other rule in
     this block (see the desktop rule set's comment above): Landing only ever renders signed out,
     so this is the one deliberate exception. Logged-out chrome itself (desktop header + SystemBar
     at every width) is untouched -- this only restyles page content inside .runahead-shell. */
  .runahead-shell .landing-hero { margin-top:28px; }
  .runahead-shell .landing-mark { font-size:2.125rem; }
  .runahead-shell .landing-lead { font-size:1.125rem; }
  .runahead-shell .landing-login { margin-top:24px; }
  .runahead-shell .landing-card { max-width:none; }
  .runahead-shell .landing-status { margin-top:30px; }
}

/* Bottom nav look (reference: .tabbar). Outside the media block on purpose — the element is
   already display:none on desktop via .mobile-chrome, so its appearance rules can live here
   unconditionally; only the display:flex switch belongs in the 768px query above.
   Fixed; safe-area padding so iPhone's home indicator never covers the row (spec §6 —
   invisible in devtools emulation, real on every iPhone). */
.runahead-app .tabbar { position: fixed; bottom: 0; left: 0; right: 0; z-index: 6;
  border-top: 1px solid #17150f; background: linear-gradient(0deg, #08080a, #0a0a0b);
  padding-bottom: env(safe-area-inset-bottom); }
.runahead-app .tabbar .tab { flex: 1; display: flex; flex-direction: column; align-items: center;
  gap: 4px; padding: 9px 0 11px; color: var(--muted); font-size:0.5625rem; letter-spacing: .09em;
  position: relative; text-decoration: none; background: none; border: 0; font-family: inherit; cursor: pointer; }
.runahead-app .tabbar .tab svg { width: 22px; height: 22px; stroke: currentColor; fill: none;
  stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }
.runahead-app .tabbar .tab.active { color: var(--accent); }
.runahead-app .tabbar .tab.active::before { content: ""; position: absolute; top: 0; left: 22%;
  right: 22%; height: 2px; background: var(--accent); box-shadow: var(--glow-gold); }
.runahead-app .tabbar .ic { line-height: 0; }

/* More sheet (reference: .overlay/.sheet/.sheet-item/.sheet-account/.sheet-version), translated
   to .msheet-*. Outside the media block for the same reason as the tabbar above — the host is
   already display:none on desktop via .mobile-chrome; only that display:block switch lives in
   the 768px query. Overlay sits above the tabbar (z-index 6) so it dims it; the sheet shares the
   same stacking layer and wins on DOM order. Never a full-height drawer — quietcard form only. */
.runahead-app .msheet-overlay { position: fixed; inset: 0; z-index: 7; background: rgba(0, 0, 0, .55); }
.runahead-app .msheet { position: fixed; left: 0; right: 0; bottom: 0; z-index: 7;
  background: linear-gradient(180deg, var(--panel-top), var(--panel-bot));
  border: 1px solid var(--border); border-bottom: 0; border-radius: 16px 16px 0 0;
  /* Safe area (spec §6): the sheet inherits the inset so the grab handle's controls never sit
     under the iPhone home indicator. */
  padding-bottom: calc(10px + env(safe-area-inset-bottom)); }
.runahead-app .msheet-grab { width: 36px; height: 4px; border-radius: 2px; background: #2a2620;
  margin: 10px auto 6px; cursor: grab; touch-action: none; }
.runahead-app .msheet-item { display: flex; align-items: center; gap: 12px; padding: 13px 20px;
  font-size:0.8125rem; color: var(--text-dim); letter-spacing: .04em; text-decoration: none; cursor: pointer; }
.runahead-app .msheet-item svg { width: 18px; height: 18px; stroke: var(--muted); fill: none;
  stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }
.runahead-app .msheet-sep { border-top: 1px solid var(--border-quiet); margin: 6px 20px; }
.runahead-app .msheet-account { display: flex; align-items: center; justify-content: space-between; padding: 11px 20px; }
.runahead-app .msheet-account .mail { font-size:0.6875rem; color: var(--faint); }
.runahead-app .msheet-logout { display: flex; align-items: center; gap: 7px; border: 1px solid #2a201c;
  border-radius: 6px; padding: 5px 11px; background: none; cursor: pointer; font-family: inherit;
  color: var(--ctrl-text); font-size:0.6875rem; letter-spacing: .05em; }
.runahead-app .msheet-logout .logout-dot { width: 5px; height: 5px; border-radius: 50%;
  background: var(--red); box-shadow: var(--glow-red); }
/* Feedback row (design spec 2026-08-03-epost-design.md §Task E6, "ONE pulse, two homes"): mobile
   home for the entry SystemBar's .feedback-link renders on desktop -- same quiet-text-link idiom,
   placed just above the version row it is textually paired with (see MoreSheet.razor's own
   comment for why this lives here rather than in MobileHeader). */
.runahead-app .msheet-feedback { padding: 4px 20px; font-size:0.6875rem; color: var(--faint); letter-spacing: .04em; cursor: pointer; }
.runahead-app .msheet-feedback:hover { color: var(--text-dim); }
/* Version row (SEO sweep, reference NOTES 7): now carries the "Created by Refi AB" signature
   alongside the version -- provenance, not a navigation row, so it does not join the icon rows
   above. flex/space-between matches the reference mockup; .sig-link (shared with SystemBar's
   footer) supplies the underline that marks it clickable at this size. */
.runahead-app .msheet-version { padding: 8px 20px 4px; font-size:0.625rem; color: var(--faint); letter-spacing: .08em; display: flex; align-items: baseline; justify-content: space-between; }
.runahead-app .msheet-version .sig-link:hover { color: var(--text-dim); }

/* Mobile header (reference NOTES 4/7): sticky, thin, 36px total height (air trimmed to mobile
   level). Outside the media block for the same reason as the tabbar/sheet above — already
   display:none on desktop via .mobile-chrome; only the display:flex switch lives in the 768px
   query (MG1). Background: sticky header sits OVER scrolling content, so the gradient ends
   opaque (var(--bg)) rather than transparent like the desktop header's hairline shadow — if the
   reactor glow should show through a sticky header, that needs the background-stack solution
   from decision #65; keeping it simple (opaque bottom) here per the plan. */
/* Height carries the top safe-area inset (viewport-fit=cover): 0 in ordinary browsers —
   identical 36px — but keeps the signature clear of the notch in standalone/MAUI contexts,
   mirroring the bottom nav's env() discipline. */
.runahead-app .m-header { position: sticky; top: 0; z-index: 6;
  height: calc(36px + env(safe-area-inset-top));
  align-items: center; justify-content: space-between;
  padding: env(safe-area-inset-top) 12px 0; box-sizing: border-box;
  border-bottom: 1px solid #17150f; background: linear-gradient(180deg, #08080a, var(--bg)); }
.runahead-app .m-header .wordmark-sm { font-size:1rem; }
.runahead-app .m-sys { display: flex; align-items: center; gap: 6px; padding: 2px 0 2px 2px; }
.runahead-app .m-sys .lbl { font-size:0.5625rem; color: var(--faint); letter-spacing: .16em; }
/* ONE pulse, two homes (reference NOTES 4): same size/color/glow/animation as .sysbar .pulse —
   the exact declarations, including the animation name so both dots share one @keyframes rule
   (a second declaration with the same numbers would still be "two pulses" if they could ever
   drift out of sync). The sysbar's ambient halo (::after, sized for the fixed full-width
   footer) is NOT copied here — it would be visually meaningless behind a 36px opaque sticky bar. */
.runahead-app .m-sys .m-pulse { position: relative; width: 6px; height: 6px; border-radius: 50%;
  background: var(--red); box-shadow: var(--glow-red); animation: sysbar-pulse 2.4s ease-in-out infinite; }

/* Vecka mobile form (MG5, reference NOTES 9-12), root .mweek. Outside the media block for the
   same reason as the other mobile-chrome hosts above — the host is already display:none on
   desktop via .mobile-chrome; only the display:block switch for .mweek-host lives in the 768px
   query (MG1). Leaf cards (.wk-card/.wk-title/.wk-stack/.wk-daybar/...) are the SAME classes
   WeekGrid uses — reused unstyled here, only the day-major container geometry is new. */
.runahead-app .mday { margin-bottom: 12px; }
.runahead-app .mday-head { display: flex; align-items: baseline; gap: 7px; padding: 2px 0 5px; }
.runahead-app .mday-head b { font-size:0.8125rem; font-weight: 600; color: var(--text); }
.runahead-app .mday-head span { font-size:0.6875rem; color: var(--faint); }
.runahead-app .mday-head .wk-daybar { flex: 1; margin-top: 0; margin-left: 6px; }
/* Today (MG5, reference NOTES 9): gold day header, same token family as the desktop current-week
   gutter marker (.wk-gutter.current) — --accent + --glow-gold, never a new "--gold" token. */
.runahead-app .mday.today .mday-head b { color: var(--accent); text-shadow: var(--glow-gold); }
/* Grid (not flex space-between) so PLAN/ACTUAL align over their own .mcols columns below,
   sharing the same 1fr/1fr + 8px gap template (reference NOTES 9). */
.runahead-app .mzonehead { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin-bottom: 4px; }
.runahead-app .mzonehead span { font-size:0.5625rem; color: var(--faint); letter-spacing: .14em; }
.runahead-app .mcols { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; align-items: start; }
.runahead-app .mcols.single { grid-template-columns: 1fr; }
.runahead-app .mweek-field { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px;
  background: var(--panel-quiet); border: 1px solid var(--border-quiet); border-radius: 8px; padding: 14px;
  min-height: 44px; text-decoration: none; margin-bottom: 12px; }
.runahead-app .mweek-field .pf-title { font-size:0.75rem; color: var(--muted); }
.runahead-app .mweek-field .pf-sub { font-size:0.6875rem; color: var(--faint); }
/* Long titles clip to one line on mobile (reference NOTES 10); desktop keeps wrapping as today.
   .wk-card is `display:flex; flex-direction:column; align-items:flex-start` (shared desktop
   rule, untouched) — flex-start sizes each child to fit-content, and once white-space:nowrap
   makes min-content == max-content, fit-content resolves to the FULL unwrapped text width
   regardless of the card's available space, so overflow:hidden/text-overflow:ellipsis never see
   an overflow to clip. align-self:stretch opts .wk-title (only) out of that sizing, stretching
   it to the card's actual cross-axis width so the ellipsis has a real box to clip against;
   min-width:0 clears the flex item's default auto min-width so stretch can shrink below the
   text's intrinsic width. .wk-detail/.wk-sub/.wk-delta keep the untouched flex-start/wrap
   behavior on purpose (reference: only titles truncate on mobile, other lines keep wrapping). */
.runahead-app .mweek .wk-title { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; align-self: stretch; min-width: 0; }

/* Block mobile form (MG6, reference NOTES 13), root .mblock-list. Outside the media block for
   the same reason as the other mobile-chrome hosts above — the host is already display:none on
   desktop via .mobile-chrome; only the display:block switch for .mblock-host lives in the 768px
   query (MG1). .mblock-main's .wk-wk/.wk-paused/.wk-origin/.wk-label reuse the desktop gutter's
   class names (.wk-gutter's rules above) for the shared tokens; only the row geometry is new. */
.runahead-app .mblock { margin-bottom: 12px; }
.runahead-app .mblock-main { display: flex; align-items: baseline; gap: 9px; padding: 5px 8px 5px 10px;
  border-left: 2px solid transparent; cursor: pointer; }
.runahead-app .mblock-main .wk-wk { font-size:0.75rem; color: var(--text); }
.runahead-app .mblock-main .wk-paused { font-size:0.6875rem; color: var(--faint); letter-spacing: .06em; }
.runahead-app .mblock-main .wk-origin { font-size:0.6875rem; color: var(--faint); flex: 0 0 auto; }
/* Label ellipsis (matches the desktop gutter's clipping rule): min-width:0 lets a flex child
   shrink below its content size so text-overflow:ellipsis actually bites. */
.runahead-app .mblock-label { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.runahead-app .mblock-label .wk-label { font-size:0.6875rem; color: var(--muted);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.runahead-app .mblock-vol { font-size:0.625rem; color: var(--faint); margin-left: auto; flex: 0 0 auto; }
/* Current week (same token family as the desktop gutter's .wk-gutter.current): gold left edge +
   gold week number. */
.runahead-app .mblock-main.current { border-left-color: var(--accent); }
.runahead-app .mblock-main.current .wk-wk { color: var(--accent); text-shadow: var(--glow-gold); }
.runahead-app .mcells { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 3px; padding: 0 2px; }
.runahead-app .mweek .wk-card { min-width: 0; }
.runahead-app .mweek .wk-stack { min-width: 0; }

/* Swipe navigator (mobile 1.5 Task 4, design §5, reference NOTES 7), root .swipe-nav. Outside the
   media block for the same reason as the other mobile-chrome-scoped rules above — the container
   only ever wraps content inside .mweek-host/.mblock-host, which are already display:none on
   desktop via .mobile-chrome, so no breakpoint gate is needed on this rule itself.
   touch-action:pan-y is the mechanism that makes the gesture work at all: it tells the browser to
   keep handling vertical scrolling natively while releasing horizontal drags to reach Blazor's
   pointermove instead of being swallowed as a scroll gesture. */
.runahead-app .swipe-nav { touch-action: pan-y; }