/* ==========================================================================
   Focus Ritual — focusritual.app landing page
   Design tokens mirror the app: bg-void #05050A, neutral white interactive,
   Spectrum triad (cyan / magenta / blue) reserved for meaning, never chrome.
   ========================================================================== */

:root {
  --void: #05050A;
  --panel: #0C0C14;
  --panel-2: #12121C;
  --line: #23232F;
  --text: #F2F2F6;
  --muted: #8A8A94;
  --cyan: #00E5FF;
  --magenta: #FF00E5;
  --blue: #0057D9;
  --triad: linear-gradient(135deg, var(--cyan), var(--magenta), var(--blue));
  --nav-h: 72px;

  --font-display: "Anton", "Arial Narrow", sans-serif;
  --font-body: "Inter", system-ui, sans-serif;
  --font-mono: "JetBrains Mono", Consolas, monospace;
}

* { margin: 0; padding: 0; box-sizing: border-box; }

/* Account for the fixed nav so #how / #tester anchor jumps don't land a
   section heading directly underneath it. */
html { scroll-behavior: smooth; scroll-padding-top: var(--nav-h); }

html, body {
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;
}

body {
  background: var(--void);
  color: var(--text);
  font-family: var(--font-body);
  font-size: 17px;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  -webkit-touch-callout: none;
}

.container { max-width: 1080px; margin: 0 auto; padding: 0 24px; }
.container.narrow { max-width: 780px; }

h1, h2, h3 { font-family: var(--font-display); font-weight: 400; letter-spacing: 0.01em; text-wrap: balance; }

h2 { font-size: clamp(34px, 5vw, 56px); line-height: 1.06; text-transform: uppercase; margin-bottom: 22px; }

.eyebrow {
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 16px;
}

.section-lede { color: var(--muted); max-width: 60ch; margin-bottom: 40px; }
.section-lede b { color: var(--text); }

section { padding: 110px 0; }

/* ---------- Buttons: neutral white/black only, per the app's rule ---------- */
.btn {
  display: inline-block;
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 16px;
  padding: 14px 28px;
  border-radius: 999px;
  border: 1px solid transparent;
  cursor: pointer;
  text-decoration: none;
  text-align: center;
  transition: transform 0.15s ease, background 0.15s ease;
}
.btn:active { transform: scale(0.97); }
.btn-primary { background: #FFFFFF; color: #000000; }
.btn-primary:hover { background: #E4E4EC; }
.btn-ghost { background: transparent; color: var(--text); border-color: var(--line); }
.btn-ghost:hover { border-color: var(--muted); }
.btn-lg { font-size: 18px; padding: 17px 36px; }

/* ==========================================================================
   HERO
   ========================================================================== */
.hero {
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  position: relative;
  overflow: hidden;
  /* Nav is now fixed (out of flow) — reserve the same space at the top so
     .hero-grid still lands exactly where it did when nav was in-flow. */
  padding-top: var(--nav-h);
}
/* Faint triad glow rising from the bottom edge — the wipe, at rest. */
.hero::after {
  content: "";
  position: absolute;
  inset: auto 0 0 0;
  height: 30vh;
  background: var(--triad);
  opacity: 0.07;
  filter: blur(60px);
  pointer-events: none;
}

.nav {
  /* Pinned to the viewport through the whole page (--nav-h 72px). The
     background/blur live on this full-width bar; .nav-inner below
     constrains just the content, so the tint reaches both edges instead
     of stopping at 1080px. */
  position: fixed;
  top: 0; left: 0; right: 0;
  height: var(--nav-h);
  z-index: 100;
  background: rgba(5, 5, 10, 0.72);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
}
.nav-inner {
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  max-width: 1080px;
  margin: 0 auto;
  padding: 0 20px;
}
.brand { display: flex; align-items: center; gap: 10px; text-decoration: none; color: var(--text); }
.brand-mark { width: 28px; height: 28px; }
.brand-name { font-family: var(--font-display); font-size: 17px; letter-spacing: 0.14em; }
/* Solid white pill (the app's primary-action treatment) rather than a ghost
   outline — this is the page's one persistent conversion point, visible at
   every scroll depth, so it should read as THE action, not an option. */
.nav-cta {
  font-family: var(--font-body); font-weight: 600; font-size: 14px;
  color: #000; background: #FFF; text-decoration: none;
  border: 1px solid #FFF; border-radius: 999px; padding: 9px 20px;
  transition: background 0.15s ease;
}
.nav-cta:hover { background: #E4E4EC; }

.hero-grid {
  flex: 1;
  display: grid;
  grid-template-columns: 1.15fr 1fr;
  gap: 48px;
  align-items: center;
  max-width: 1080px;
  width: 100%;
  margin: 0 auto;
  padding: 40px 24px 80px;
}

.hero-eyebrow {
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 18px;
}
.hero-copy h1 {
  font-size: clamp(72px, 12vw, 148px);
  line-height: 0.94;
  text-transform: uppercase;
  margin-bottom: 26px;
}
/* "on" pulses like a power indicator — the literal switch the headline
   promises. Text glow only; the fill stays plain white per the neutral
   interactive rule (color is reserved for ritual surfaces). */
.on-word { animation: onGlow 4s ease-in-out infinite; }
@keyframes onGlow {
  0%, 100% { text-shadow: 0 0 18px rgba(0, 229, 255, 0.25); }
  50% { text-shadow: 0 0 42px rgba(0, 229, 255, 0.65), 0 0 90px rgba(255, 0, 229, 0.25); }
}
.lede { color: var(--muted); font-size: 19px; max-width: 46ch; margin-bottom: 34px; }
.hero-actions { display: flex; gap: 14px; flex-wrap: wrap; }
.hero-note { font-family: var(--font-mono); font-size: 12.5px; color: var(--muted); margin-top: 22px; letter-spacing: 0.04em; }

/* ---------- The demo phone ---------- */
.phone-wrap { display: flex; flex-direction: column; align-items: center; gap: 16px; }

.phone {
  /* Third clamp term keys the width off viewport HEIGHT (width ≈ height ÷
     1.78), so the whole phone stays visible without scrolling on short
     viewports — small phones and shallow desktop windows alike. */
  width: min(290px, 74vw, 42svh);
  aspect-ratio: 9 / 16;
  border-radius: 32px;
  border: 1px solid var(--line);
  background: var(--void);
  overflow: hidden;
  position: relative;
  box-shadow: 0 30px 80px rgba(0, 0, 0, 0.6);
}

.screen { position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; }
.screen[hidden] { display: none; }

/* Screen: set target */
.scr-target { gap: 0; padding: 22px; }
.scr-label { font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.18em; color: var(--muted); margin-bottom: 6px; }
.scr-task { font-size: 18px; font-weight: 600; margin-bottom: 18px; }

.scr-duration { display: flex; align-items: baseline; gap: 20px; font-family: var(--font-mono); }
.dur-side { color: #3A3A46; font-size: 20px; }
.dur-main { color: #FFFFFF; font-size: 40px; font-weight: 500; }
.scr-unit { font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.18em; color: var(--muted); margin-bottom: 20px; }

/* Category picker now lives on the target screen (used to be a row below
   the phone) — an even 3x2 grid instead of ragged wrapped pills, so all 6
   sit flush and aligned instead of looking scattered. */
.scr-mode-label {
  font-family: var(--font-mono); font-size: 9px; letter-spacing: 0.18em; color: var(--muted); margin-bottom: 8px;
  transition: color 0.4s ease;
}
/* "PICK A MODE" pulses brighter than the surrounding gray labels — the hint
   lives on the label the picker already has, in the phone itself, instead
   of a separate floating element pointing at it. Stops the instant the
   visitor taps any mode (see .picked below / script.js), so it never nags
   once the point has landed. */
.scr-mode-label:not(.picked) { animation: modeLabelPulse 2.4s ease-in-out infinite; }
@keyframes modeLabelPulse {
  0%, 100% { color: var(--muted); }
  50% { color: #FFFFFF; }
}
.scr-categories {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px; width: 100%; margin-bottom: 22px;
  border-radius: 10px;
  transition: box-shadow 0.4s ease;
}
/* Same soft glow language as .scr-begin's ctaPulse below, run on the mode
   grid first — a two-step spotlight (pick a mode, then Begin) instead of a
   bubble bolted on beside the phone. */
.scr-categories:not(.picked) { animation: ctaPulse 2.4s ease-in-out infinite; }
.scr-categories .dcat { font-size: 10.5px; padding: 7px 4px; }
.scr-begin { font-size: 15px; padding: 12px 24px; transition: opacity 0.3s ease; }
/* Disabled (no mode picked yet, see HTML/script.js): flat and inert, no
   pulse — the grid's own pulse is the active hint at this stage. Soft
   attract pulse only kicks in once Begin is actually the next real step. */
.scr-begin:not(:disabled) { animation: ctaPulse 3s ease-in-out infinite; }
.scr-begin:disabled { opacity: 0.35; pointer-events: none; }
@keyframes ctaPulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(255, 255, 255, 0); }
  50% { box-shadow: 0 0 26px 2px rgba(255, 255, 255, 0.28); }
}

/* ---------- Demo category picker ----------
   Text pills, not color swatches (categories aren't colors) — same visual
   language as the app's own Category chips (Input screen / .chip below).
   Base sizing here; .scr-categories .dcat above shrinks them to fit inside
   the phone's target screen alongside the duration picker. */
.dcat {
  font-size: 12px; font-weight: 600;
  border: 1px solid var(--line); color: var(--muted);
  background: transparent;
  border-radius: 999px; padding: 6px 14px;
  cursor: pointer;
  transition: color 0.15s ease, border-color 0.15s ease;
}
.dcat:hover { border-color: rgba(255, 255, 255, 0.4); color: #FFF; }
.dcat.on { 
  background: #FFF !important; 
  color: #000 !important; 
  border-color: #FFF !important; 
  transition: none !important; 
}

/* Screen: countdown — colors set per-card via inline custom properties
   (script.js paints --card-dark/--card-accent/--card-contrast for each of
   the 3 ritual cards); values below are the Card 1 / Spectrum fallback. */
.scr-count { background: var(--card-dark, #001014); }
.wipe {
  position: absolute; inset: 0;
  background: var(--card-accent, #00E5FF);
  transform: scaleY(0);
  transform-origin: bottom;
}
.scr-count.running .wipe { transform: scaleY(1); transition: transform var(--wipe-duration, 3s) linear; }
.numeral {
  position: absolute; inset: 0;
  display: grid; place-items: center;
  font-family: var(--font-display);
  font-size: 148px;
  line-height: 1;
}
.numeral-accent { color: var(--card-accent, #00E5FF); }
.numeral-contrast {
  color: var(--card-contrast, #000000);
  clip-path: inset(100% 0 0 0);
}
.scr-count.running .numeral-contrast { clip-path: inset(0 0 0 0); transition: clip-path var(--wipe-duration, 3s) linear; }

/* Screen: ritual card — hard cut, accent bg, contrast text (same custom
   properties as the countdown, so card and its wipe always match). */
.scr-card { background: var(--card-accent, #00E5FF); }
.card-line { font-family: var(--font-display); font-size: var(--card-line-size, 56px); line-height: 1.04; color: var(--card-contrast, #000000); }

/* Screen: timer. No extra `position` here: .screen already sets
   position:absolute (needed for inset:0 to stretch+center this screen in
   the phone) -- adding position:relative on top of that used to override
   it (later same-specificity rule), collapsing the screen to its own
   content size stuck at the top instead of filling+centering the phone.
   absolute is already a valid positioning context for .burst::after below,
   so relative was never actually needed. */
.scr-timer { gap: 18px; }
/* Ring and digits share one relative box so the digits can be centered
   directly on the ring's own center via absolute inset:0 + grid — the
   previous negative-margin approach approximated this and drifted off
   true-center depending on font metrics. */
.ring-wrap { position: relative; width: 72%; aspect-ratio: 1; display: grid; place-items: center; }
/* overflow:visible overrides the UA default (SVGs clip at their own
   viewBox by default) — without it, the shockwave circles growing past
   the small 200x200 viewBox got clipped square, leaving 4 stray corner
   arcs visible mid-burst. Now they grow freely and are clipped only by
   .phone's own rounded-rect edge, matching the real app's burst. */
.ring { width: 100%; height: 100%; overflow: visible; }
.ring-progress { stroke-dasharray: 553; stroke-dashoffset: 0; animation: ringBreathe 4s ease-in-out infinite; }
.ring-breathe { animation: ringBreathe 4s ease-in-out infinite; }
@keyframes ringBreathe { 0%, 100% { opacity: 1; } 50% { opacity: 0.55; } }
/* The moment the session ends, the ring stops depleting and snaps back to a
   solid closed circle (script.js adds .closing + sets dashoffset to 0),
   using the same custom ease TimerScreen.tsx uses for its close transition —
   this transition is what makes that snap read as a deliberate "closing"
   beat instead of the ring just continuing to drain to empty. */
.ring-progress.closing { transition: stroke-dashoffset var(--close-duration, 400ms) cubic-bezier(0.55, 0, 0.2, 1); animation: none; opacity: 1; }

/* Hero ring (track + progress) and the digits/task all fade out together,
   fast (120ms), the instant the burst fires — same beat as
   TimerScreen.tsx's `motion.g`/digits/task opacity:burst?0:1. */
.ring-hero, .timer-digits, .timer-task { transition: opacity 120ms; }
.scr-timer.burst .ring-hero,
.scr-timer.burst .timer-digits,
.scr-timer.burst .timer-task { opacity: 0; }

.timer-digits {
  position: absolute; inset: 0;
  display: grid; place-items: center;
  font-family: var(--font-mono); font-size: 40px; font-weight: 500;
  font-variant-numeric: tabular-nums;
  color: #FFFFFF;
}
.timer-task { font-size: 13px; color: #FFFFFF; }

/* Shockwave: two concentric rings expanding from the ring's own radius past
   the screen edges, thinning and fading as they grow — same SVG, same
   gradient, mirrors the two motion.circle shockwaves in TimerScreen.tsx. */
.shock { opacity: 0; }
@keyframes shock1 {
  from { r: 88; stroke-width: 7; opacity: 0.95; }
  to { r: 340; stroke-width: 2.5; opacity: 0; }
}
@keyframes shock2 {
  from { r: 88; stroke-width: 5; opacity: 0.6; }
  to { r: 260; stroke-width: 2; opacity: 0; }
}
.scr-timer.burst .shock-1 { animation: shock1 650ms cubic-bezier(0.16, 1, 0.3, 1) forwards; }
.scr-timer.burst .shock-2 { animation: shock2 550ms cubic-bezier(0.16, 1, 0.3, 1) 90ms forwards; }

/* Camera-flash: one full-screen gradient pop in screen-blend mode, fired
   with the shockwave — mirrors TimerScreen.tsx's flash div exactly
   (opacity 0.75 -> 0 over 400ms, mix-blend-mode: screen). */
.scr-timer.burst::after {
  content: "";
  position: absolute; inset: 0;
  z-index: 1;
  background: var(--triad);
  mix-blend-mode: screen;
  opacity: 0.75;
  animation: burstFlash 400ms ease-out forwards;
  pointer-events: none;
}
@keyframes burstFlash {
  from { opacity: 0.75; }
  to { opacity: 0; }
}

/* Statement: "Session Delivered" springs in with overshoot as the burst
   fades — a fixed statement, not an Export Card quote (that bank is
   reserved for the Focus Card only; see TimerScreen.tsx). */
.end-statement {
  position: absolute; inset: 0;
  z-index: 2;
  display: grid; place-items: center;
  padding: 0 24px;
  font-family: var(--font-display);
  font-size: clamp(24px, 9vw, 36px);
  line-height: 1;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  text-align: center;
  color: #FFFFFF;
  opacity: 0;
  transform: scale(0.3);
  pointer-events: none;
}
.scr-timer.statement .end-statement {
  opacity: 1;
  transform: scale(1);
  transition: transform 480ms cubic-bezier(0.34, 1.56, 0.64, 1), opacity 200ms ease;
}

/* Screen: result — the Focus Card payoff */
.scr-result { gap: 18px; padding: 26px; }
/* Compound selector beats the later, single-class .mini-focus-card rule
   (both are one-class specificity, so source order would otherwise win).
   94%, not a smaller fraction: this is the demo's payoff moment, so the
   card should read as the dominant element on screen, not a small preview.
   Square corners (not the real card's rounded ones) is a deliberate
   distinction — this mockup is a stand-in, not a pixel copy. */
.mini-focus-card.result-card { width: 94%; border-radius: 0; }
.result-label {
  font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.2em;
  color: var(--muted);
}
.btn-replay { font-size: 13px; padding: 9px 18px; }

/* ==========================================================================
   QUOTE MARQUEE — the sentence banks, scrolling
   ========================================================================== */
.quotes {
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  padding: 20px 0;
  overflow: hidden;
  /* Fade both edges so lines enter/exit softly instead of clipping hard. */
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
}
.quotes-track {
  display: flex;
  align-items: center;
  gap: 34px;
  width: max-content;
  animation: quotesScroll 42s linear infinite;
}
.quotes:hover .quotes-track { animation-play-state: paused; }
.q {
  font-family: var(--font-display);
  font-size: 21px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: rgba(242, 242, 246, 0.82);
  white-space: nowrap;
}
/* Separator dots carry the active triad — --tri-1/2/3 are set by the demo's
   theme picker (script.js applyTheme), falling back to Spectrum. */
.qdot { font-size: 8px; line-height: 1; }
.qd1 { color: var(--tri-1, var(--cyan)); }
.qd2 { color: var(--tri-2, var(--magenta)); }
.qd3 { color: var(--tri-3, var(--blue)); }
/* Content is duplicated once in the HTML, so -50% lands exactly on the
   seam and the loop is invisible. */
@keyframes quotesScroll {
  from { transform: translateX(0); }
  to { transform: translateX(-50%); }
}

/* ==========================================================================
   PROBLEM
   ========================================================================== */
.problem { border-top: 1px solid var(--line); }
.problem h2 { margin-bottom: 26px; }
.problem p { color: var(--muted); font-size: 18px; }

/* ==========================================================================
   HOW IT WORKS
   ========================================================================== */
.how { border-top: 1px solid var(--line); }
.steps {
  list-style: none;
  display: grid;
  /* minmax(0, 1fr), not bare 1fr: a bare 1fr track's minimum is "auto" (its
     content's min-content size), so a column with wider nowrap content
     (the Focus Card footer) grows independently of its siblings instead of
     matching them -- exactly what made step 4's box balloon to ~2x the
     others'. minmax(0, ...) removes that auto-minimum, letting all 4
     columns share the row equally regardless of content. */
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 22px;
  margin-top: 56px;
}
.step h3 { font-size: 20px; text-transform: uppercase; margin: 20px 0 10px; display: flex; align-items: center; gap: 10px; }
.step-num {
  font-family: var(--font-mono); font-size: 12px; color: #000;
  background: #FFF; border-radius: 50%;
  width: 24px; height: 24px;
  display: inline-grid; place-items: center;
  flex: none;
}
/* Direct child, not a descendant selector: a plain ".step p" would also
   match every <p> nested inside the mockup cards (mfc-tag, mfc-hero,
   sv-task, ...), and at (0,1,1) it out-specifies their own single-class
   rules like .mfc-hero (0,1,0) -- silently overriding intended colors and
   sizes to this muted grey. This is what made the Focus Card text (and
   step 1's task text) render grey instead of white. */
.step > p { color: var(--muted); font-size: 15px; }

.step-visual {
  /* Capped + centered, same scale rule as the hero's phone mockup
     (`min(300px, 78vw)`) — without this, once .steps drops to 1-2 columns
     on mobile each box stretches to the full column width and, combined
     with the 4:5 aspect-ratio, balloons into a near-full-screen block
     instead of staying a compact card mockup like on desktop. */
  width: 100%;
  max-width: 300px;
  margin: 0 auto;
  aspect-ratio: 4 / 5;
  border-radius: 22px;
  /* No border — depth comes from a soft diagonal panel gradient plus a
     floating drop shadow and a hairline top highlight instead, so the box
     reads as a lifted card rather than an outlined UI frame. */
  border: none;
  background: linear-gradient(165deg, var(--panel-2), var(--panel));
  box-shadow: 0 28px 60px -24px rgba(0, 0, 0, 0.65), inset 0 1px 0 rgba(255, 255, 255, 0.06);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 18px;
  text-align: center;
  transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.step-visual:hover { transform: translateY(-4px); }
/* Each mockup gets a faint glow tinted to what it depicts — the target
   picker's cyan, the ritual cards' magenta, the timer ring's blue, and a
   neutral white lift for the finished card — so the row reads as four
   connected beats of the same triad rather than four identical grey boxes. */
.sv-target { box-shadow: 0 28px 60px -24px rgba(0, 0, 0, 0.65), 0 0 46px -14px rgba(0, 229, 255, 0.35), inset 0 1px 0 rgba(255, 255, 255, 0.06); }
.sv-ritual { box-shadow: 0 28px 60px -24px rgba(0, 0, 0, 0.65), 0 0 46px -14px rgba(255, 0, 229, 0.28), inset 0 1px 0 rgba(255, 255, 255, 0.06); }
.sv-session { box-shadow: 0 28px 60px -24px rgba(0, 0, 0, 0.65), 0 0 46px -14px rgba(0, 87, 217, 0.4), inset 0 1px 0 rgba(255, 255, 255, 0.06); }
.sv-export { box-shadow: 0 28px 60px -24px rgba(0, 0, 0, 0.65), 0 0 46px -14px rgba(255, 255, 255, 0.2), inset 0 1px 0 rgba(255, 255, 255, 0.06); }
.sv-target:hover { box-shadow: 0 32px 70px -24px rgba(0, 0, 0, 0.7), 0 0 60px -12px rgba(0, 229, 255, 0.45), inset 0 1px 0 rgba(255, 255, 255, 0.06); }
.sv-ritual:hover { box-shadow: 0 32px 70px -24px rgba(0, 0, 0, 0.7), 0 0 60px -12px rgba(255, 0, 229, 0.38), inset 0 1px 0 rgba(255, 255, 255, 0.06); }
.sv-session:hover { box-shadow: 0 32px 70px -24px rgba(0, 0, 0, 0.7), 0 0 60px -12px rgba(0, 87, 217, 0.5), inset 0 1px 0 rgba(255, 255, 255, 0.06); }
.sv-export:hover { box-shadow: 0 32px 70px -24px rgba(0, 0, 0, 0.7), 0 0 60px -12px rgba(255, 255, 255, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.06); }
/* Step 4 keeps the same bordered-panel footprint as steps 1-3 — only the
   card inside it changed (structural overlap fix + watermark). Width is
   96%, not a smaller fraction: at this box's ~240px size the footer
   (timestamp + watermark) needs nearly the full available inner width to
   avoid clipping. */
.sv-export .mini-focus-card {
  width: 96%;
}
.sv-small { font-family: var(--font-mono); font-size: 9px; letter-spacing: 0.16em; color: var(--muted); }
.sv-task { font-weight: 600; font-size: 16px; }
.sv-duration { display: flex; align-items: baseline; gap: 6px; font-family: var(--font-mono); margin-top: 6px; }
.sv-dur-num { color: #FFFFFF; font-size: 40px; font-weight: 500; }
.sv-dur-unit { color: var(--muted); font-size: 11px; letter-spacing: 0.14em; }
.sv-chips { display: flex; gap: 6px; flex-wrap: wrap; justify-content: center; margin-top: 14px; }
.chip {
  font-size: 11px; font-weight: 600;
  border: 1px solid var(--line); color: var(--muted);
  border-radius: 999px; padding: 4px 12px;
}
.chip-on { background: #FFF; color: #000; border-color: #FFF; }

.sv-cards { position: relative; width: 100%; height: 100%; }
.sv-card {
  position: absolute;
  inset: 12% 10%;
  border-radius: 12px;
  display: grid; place-items: center;
  font-family: var(--font-display);
  font-size: 17px;
  line-height: 1.15;
}
.sv-card.c1 { background: var(--cyan); color: #000; transform: rotate(-7deg) translate(-6%, -4%); }
.sv-card.c2 { background: var(--magenta); color: #000; transform: rotate(3deg) translate(4%, 2%); }
.sv-card.c3 { background: var(--blue); color: #FFF; transform: rotate(-2deg) translate(-1%, 8%); font-size: 26px; }

.sv-session { position: relative; }
.ring-sm { width: 78%; }
.sv-digits {
  position: absolute;
  font-family: var(--font-mono); font-size: 26px; font-weight: 500;
  font-variant-numeric: tabular-nums;
}

/* ---------- Mini focus cards (pure CSS reproductions) ----------
   Body (tag/hero/task) and footer (meta/watermark) are two stacked flex
   children, not a centered block plus corner-pinned absolute text — the
   footer always gets its own reserved row this way, so it can never
   collide with the body regardless of how small the card renders (the
   previous absolute-positioned footer only "worked" at showcase size and
   overlapped the centered body at step 4's smaller size). */
.mini-focus-card {
  width: 100%;
  aspect-ratio: 1;
  border-radius: 14px;
  display: flex;
  flex-direction: column;
  padding: 16px;
  text-align: center;
  overflow: hidden; /* keep long text from ever bleeding past the rounded corner */
  box-shadow: inset 0 0 60px rgba(5, 5, 10, 0.35);
}
/* Scoped to .mini-focus-card on purpose: bare .theme-* classes once leaked
   onto the theme roster's Founders <li>, painting the whole row gold. */
.mini-focus-card.theme-spectrum { background: linear-gradient(135deg, #00E5FF, #FF00E5, #0057D9); }
.mini-focus-card.theme-inferno { background: linear-gradient(135deg, #7F1D1D, #C2410C, #EAB308); }
.mini-focus-card.theme-terminal { background: linear-gradient(135deg, #059669, #14532D, #6EE7B7); }
.mini-focus-card.theme-obsidian { background: linear-gradient(135deg, #475569, #52525B, #1A1A1A); }
.mini-focus-card.theme-midnight { background: linear-gradient(135deg, #8B5CF6, #3B82F6, #1E1B4B); }
.mini-focus-card.theme-crimson { background: linear-gradient(135deg, #6B0F1A, #DC2626, #FB7185); }
.mini-focus-card.theme-founders { background: linear-gradient(135deg, #E8C468, #C89B3C, #8A6410); }

.mfc-body {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 6px;
}
/* Shadows are tight (small blur) on purpose: a wide soft blur behind bold
   white letters on a vivid gradient smears into the letterforms' own
   anti-aliased edges, reading as dull grey instead of crisp white. A short,
   fairly opaque shadow gives lift/legibility without muddying the fill. */
.mfc-tag { font-family: var(--font-display); font-size: 11px; letter-spacing: 0.14em; color: #FFF; text-shadow: 0 1px 3px rgba(0,0,0,0.6); }
.mfc-hero { font-family: var(--font-display); font-size: 42px; line-height: 1; color: #FFF; text-shadow: 0 1px 4px rgba(0,0,0,0.6); }
.mfc-task { font-size: 12px; font-weight: 500; color: #FFF; }

.mfc-footer {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 6px;
  width: 100%;
  min-width: 0; /* let its nowrap children shrink-negotiate instead of forcing the row wider */
}
.mfc-meta {
  font-family: var(--font-mono); font-size: 7.5px; letter-spacing: 0.02em;
  white-space: nowrap;
  color: rgba(255,255,255,0.88);
}
/* Watermark: same ring glyph + wordmark focusCard.ts draws on every real
   exported card (see src/lib/focusCard.ts's drawRingMark) — reused here so
   these mockups read as the same artifact, not a stand-in. */
.mfc-watermark {
  display: flex; align-items: center; gap: 3px;
  font-family: var(--font-display); font-size: 7px; letter-spacing: 0.08em;
  color: rgba(255,255,255,0.78);
  white-space: nowrap;
  flex: none;
}
.mfc-mark { width: 9px; height: 9px; color: rgba(255,255,255,0.78); flex: none; }

/* ==========================================================================
   SHOWCASE
   ========================================================================== */
.showcase { border-top: 1px solid var(--line); }
.card-fan {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 26px;
  align-items: center;
}
.mfc-lg { border-radius: 20px; padding: 22px; }
.mfc-lg .mfc-tag { font-size: 14px; }
.mfc-lg .mfc-hero { font-size: 62px; }
.mfc-lg .mfc-task { font-size: 15px; }
.mfc-lg .mfc-meta { font-size: 10.5px; }
.mfc-lg .mfc-watermark { font-size: 10px; }
.mfc-lg .mfc-mark { width: 13px; height: 13px; }
.card-fan .mfc-lg:nth-child(1) { transform: rotate(-3deg); }
.card-fan .mfc-lg:nth-child(2) { transform: translateY(-14px); z-index: 1; box-shadow: inset 0 0 60px rgba(5,5,10,0.35), 0 24px 60px rgba(0,0,0,0.5); }
.card-fan .mfc-lg:nth-child(3) { transform: rotate(3deg); }

/* Theme roster lives inside the showcase section, bridged by its own lede
   (the fan's middle card sits 14px high, so the lede carries generous top
   margin to clear it and read as a new beat, not a caption). */
/* Second conversion point — catches interest right after the card fan,
   before the reader either scrolls on or drifts off; deliberately a plain
   link (not a pill button) so it doesn't compete with the tester section's
   real CTA below. */
.showcase-cta { text-align: center; margin: 44px 0 8px; }
.showcase-cta a {
  font-family: var(--font-body); font-weight: 600; font-size: 15px;
  color: var(--text); text-decoration: none;
  border-bottom: 1px solid var(--line);
  padding-bottom: 2px;
  transition: border-color 0.15s ease;
}
.showcase-cta a:hover { border-color: var(--muted); }
.themes-lede { color: var(--muted); max-width: 60ch; margin: 40px 0 36px; }
.theme-list { list-style: none; display: grid; gap: 0; }
.theme-list li {
  display: flex; align-items: center; gap: 20px;
  padding: 18px 4px;
  border-bottom: 1px solid var(--line);
}
.theme-list li:first-child { border-top: 1px solid var(--line); }
/* Theme name (bold, uppercase, same as before) stacked over the category
   that carries it by default — one column instead of two separate lists
   that'd otherwise repeat the same pairing. */
.pair { display: flex; flex-direction: column; gap: 2px; min-width: 130px; }
.theme-list b { font-family: var(--font-display); font-weight: 400; font-size: 19px; letter-spacing: 0.06em; text-transform: uppercase; }
.pair-cat { font-size: 12px; color: var(--muted); letter-spacing: 0.04em; }
.theme-note { color: var(--muted); font-size: 14px; }
.themes-stat { color: var(--muted); font-size: 13px; max-width: 60ch; margin-top: 22px; }
/* Same single gradient circle as the app's swatch row (and the demo picker
   above) — one circle per theme, not a trio of chips. */
.tri { display: flex; }
.tri i {
  width: 28px; height: 28px; border-radius: 50%; display: block;
  box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.12);
  /* Subtle breathing glow, tinted per-theme via each swatch's own --glow
     custom property (set inline next to its background gradient) — a quiet
     "this is alive" touch for an otherwise static reference list, without
     building a second interactive demo (the hero phone already owns that). */
  animation: swatchGlow 3.6s ease-in-out infinite;
}
@keyframes swatchGlow {
  0%, 100% { box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.12), 0 0 0 0 var(--glow, transparent); }
  50% { box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.12), 0 0 14px 2px var(--glow, transparent); }
}
/* Staggered delays so the row of circles breathes as a wave, not a single
   synchronized blink. */
.theme-list li:nth-child(1) .tri i { animation-delay: 0s; }
.theme-list li:nth-child(2) .tri i { animation-delay: 0.5s; }
.theme-list li:nth-child(3) .tri i { animation-delay: 1s; }
.theme-list li:nth-child(4) .tri i { animation-delay: 1.5s; }
.theme-list li:nth-child(5) .tri i { animation-delay: 2s; }
.theme-list li:nth-child(6) .tri i { animation-delay: 2.5s; }
.theme-list li:nth-child(7) .tri i { animation-delay: 3s; }
.row-founders .tri i {
  box-shadow: 0 0 0 1px rgba(200, 155, 60, 0.6), 0 0 12px rgba(200, 155, 60, 0.45);
  animation-name: swatchGlowGold;
}
@keyframes swatchGlowGold {
  0%, 100% { box-shadow: 0 0 0 1px rgba(200, 155, 60, 0.6), 0 0 12px rgba(200, 155, 60, 0.45); }
  50% { box-shadow: 0 0 0 1px rgba(200, 155, 60, 0.6), 0 0 20px 3px rgba(200, 155, 60, 0.75); }
}
/* The Founders row is the one earned theme, so it breaks out of the plain
   roster: detached, gold-edged, softly gold-washed — clearly special, but a
   tint and a hairline, not the solid gold slab an unscoped gradient once
   painted across it. */
.theme-list .row-founders {
  margin-top: 12px;
  border: 1px solid rgba(200, 155, 60, 0.4);
  border-radius: 14px;
  /* Left padding matches the plain rows above (4px) so this row's circle
     lands in the same column as theirs — only the right side gets extra
     breathing room from the card's border. */
  padding: 18px 16px 18px 4px;
  background: linear-gradient(90deg, rgba(200, 155, 60, 0.13), rgba(200, 155, 60, 0.03) 55%, transparent);
  box-shadow: 0 0 34px -12px rgba(200, 155, 60, 0.4);
}
.row-founders .theme-note { color: rgba(232, 196, 104, 0.8); }

/* ==========================================================================
   TESTER OFFER
   ========================================================================== */
.tester {
  border-top: 1px solid var(--line);
  position: relative;
  overflow: hidden;
}
.tester::before {
  content: "";
  position: absolute; inset: 0 0 auto 0; height: 1px;
  background: var(--triad);
}
/* Deal list + the gold Founders card side by side: the reward should be
   something you can SEE while reading the terms, not a sentence to trust. */
.tester-grid {
  display: grid;
  grid-template-columns: 1fr 236px;
  gap: 36px;
  align-items: center;
  margin: 44px 0;
}
.tester-grid .deal { margin: 0; }
.founders-showcase { display: flex; flex-direction: column; gap: 12px; align-items: center; }
.founders-showcase .mini-focus-card {
  box-shadow: inset 0 0 60px rgba(5, 5, 10, 0.35), 0 18px 50px rgba(0, 0, 0, 0.5), 0 0 56px -8px rgba(200, 155, 60, 0.45);
  transform: rotate(2deg);
}
.founders-caption { font-size: 12.5px; color: var(--muted); text-align: center; max-width: 210px; }
/* This card renders smaller than the showcase fan's cards — scale the
   .mfc-lg type down a notch so nothing crowds the 236px column. */
.founders-showcase .mfc-hero { font-size: 46px; }
.founders-showcase .mfc-tag { font-size: 11.5px; }
.founders-showcase .mfc-task { font-size: 12.5px; }
.founders-showcase .mfc-meta { font-size: 8.5px; }
.founders-showcase .mfc-watermark { font-size: 8px; }

.deal { list-style: none; counter-reset: deal; display: grid; gap: 22px; margin: 44px 0; }
.deal li {
  counter-increment: deal;
  position: relative;
  padding: 22px 24px 22px 74px;
  border: 1px solid var(--line);
  border-radius: 16px;
  background: var(--panel);
  color: var(--muted);
}
.deal li b { color: var(--text); }
.deal li::before {
  content: counter(deal);
  position: absolute; left: 24px; top: 50%;
  transform: translateY(-50%);
  font-family: var(--font-display);
  font-size: 26px;
  color: #000;
  background: #FFF;
  width: 36px; height: 36px; border-radius: 50%;
  display: grid; place-items: center;
}
.tester-cta { text-align: center; margin-top: 40px; }
.tester-note { font-size: 13.5px; color: var(--muted); margin-top: 14px; }
/* Explicit platform callout right at the CTA — the hero/nav already say
   "Android" in passing, but an iOS visitor who scrolls straight to this
   button and clicks should never get as far as "Open Gmail" before
   learning this doesn't apply to them yet. */
.tester-platform {
  display: inline-block;
  font-size: 12px; font-weight: 600; letter-spacing: 0.04em;
  color: var(--muted);
  border: 1px solid var(--line); border-radius: 999px;
  padding: 5px 14px;
  margin-top: 10px;
}

/* ---------- "How to join" popup ----------
   Native <dialog>: centered on screen, with a blurred backdrop dimming
   everything behind it. Browser-native focus trapping and Esc-to-close,
   no custom JS positioning needed. */
.tester-dialog {
  /* The site's own reset (`* { margin: 0 }`) is author-origin CSS, which
     always wins over the browser's default dialog:modal { margin: auto }
     centering rule regardless of selector specificity — so centering has
     to be set explicitly here rather than relying on the UA default. */
  position: fixed;
  top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  margin: 0;
  border: none;
  border-radius: 20px;
  padding: 34px 32px 30px;
  /* One step shows at a time (wizard), so a narrow single-card width
     works everywhere — phones included. */
  max-width: 460px;
  width: calc(100% - 48px);
  max-height: calc(100vh - 48px);
  overflow-y: auto;
  background: linear-gradient(165deg, var(--panel-2), var(--panel));
  color: var(--text);
  box-shadow: 0 40px 80px -30px rgba(0, 0, 0, 0.7);
}
.tester-dialog::backdrop {
  background: rgba(5, 5, 10, 0.6);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}
.tester-dialog[open] { animation: testerDialogIn 0.2s ease; }
/* Both keyframes must keep the -50%/-50% centering transform from the
   base rule above — an end-state of "transform: none" would cancel it
   out and snap the dialog to the top-left corner once the animation ends. */
@keyframes testerDialogIn {
  from { opacity: 0; transform: translate(-50%, -50%) translateY(8px) scale(0.98); }
  to { opacity: 1; transform: translate(-50%, -50%); }
}
.tp-title {
  font-family: var(--font-mono); font-size: 12px; letter-spacing: 0.06em;
  text-transform: uppercase; color: var(--muted);
  text-align: center;
  /* Side margins keep the centered label clear of the absolutely
     positioned × close button. */
  margin: 0 36px;
}
.tester-dialog-close {
  position: absolute; top: 14px; right: 14px;
  width: 32px; height: 32px; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--void); border: 1px solid var(--line); color: var(--muted);
  font-size: 20px; line-height: 1;
  cursor: pointer;
}
.tester-dialog-close:hover { color: var(--text); border-color: var(--muted); }

/* One step at a time (wizard), one clear action per screen. Layout:
   eyebrow ("STEP 1 OF 3") → segmented progress bar → the step itself
   rendered directly on the dialog (no card-inside-card nesting) with
   its title in the same big display type as the rest of the site →
   Back/Next nav. Copyable strings are inline "fields" with a small
   Copy chip, so the big white Next button is always the one primary
   action on screen. */
.tester-progress { display: flex; gap: 6px; width: 148px; margin: 10px auto 0; }
.tester-dialog-platform {
  text-align: center;
  font-size: 12.5px; color: var(--muted);
  margin: 14px auto 0; max-width: 32ch;
}
.tseg {
  height: 4px; flex: 1; border-radius: 999px;
  background: var(--line);
  transition: background 0.25s ease;
}
.tseg.on { background: #FFF; }

.tester-panes { margin: 0 0 20px; }
/* .tpane's own `display: flex` outranks the browser's `[hidden]
   { display: none }` UA rule, so without this the "hidden" panes all
   stay visible, stacked under the current one. */
.tpane[hidden] { display: none; }
.tpane {
  /* min-height keeps the dialog from jumping in height between steps
     with different amounts of content; justify-content centers the
     shorter ones inside that fixed frame. */
  min-height: 264px;
  padding: 18px 0 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
  text-align: center;
}
.tpane-icon {
  width: 64px; height: 64px;
  display: grid; place-items: center;
  border-radius: 18px;
  background: var(--panel);
  border: 1px solid var(--line);
  color: var(--text);
  margin-bottom: 6px;
}
.tpane-icon svg { width: 30px; height: 30px; }
.tpane-icon .gmail-logo { width: 34px; height: 26px; }
.tpane-title { font-size: 27px; text-transform: uppercase; margin: 0; }
.tpane-text { color: var(--muted); font-size: 14.5px; line-height: 1.55; max-width: 32ch; }
.tpane-text b { color: var(--text); }

.copy-field {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  margin-top: 10px;
  padding: 9px 9px 9px 16px;
  background: var(--void);
  border: 1px solid var(--line);
  /* Soft rectangle, not a 999px pill: the message string wraps to two
     lines on phones, and a full pill looks broken around wrapped text. */
  border-radius: 16px;
  text-align: left;
}
.copy-field-text {
  flex: 1;
  font-family: var(--font-mono);
  font-size: 12.5px;
  color: var(--text);
  overflow-wrap: anywhere;
}
.copy-chip {
  flex: none;
  font-family: var(--font-body);
  font-size: 12.5px;
  font-weight: 600;
  color: #000;
  background: #FFF;
  border: none;
  border-radius: 999px;
  padding: 9px 18px;
  cursor: pointer;
  transition: background 0.15s ease, transform 0.15s ease;
}
.copy-chip:hover { background: #E4E4EC; }
.copy-chip:active { transform: scale(0.96); }

.tpane-icon-done { border-color: var(--muted); }

.tester-nav { display: flex; gap: 10px; }
#testerBackBtn { flex: 0 0 auto; }
#testerNextBtn { flex: 1; }

@media (max-width: 560px) {
  .tester-dialog { padding: 30px 22px 26px; }
}

/* ==========================================================================
   FAQ
   ========================================================================== */
.faq { border-top: 1px solid var(--line); }
.faq details { border-bottom: 1px solid var(--line); }
.faq details:first-of-type { border-top: 1px solid var(--line); margin-top: 30px; }
.faq summary {
  cursor: pointer;
  font-weight: 600;
  font-size: 17px;
  padding: 20px 4px;
  list-style: none;
  display: flex;
  justify-content: space-between;
  align-items: center;
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after { content: "+"; font-family: var(--font-mono); color: var(--muted); font-size: 20px; }
.faq details[open] summary::after { content: "–"; }
.faq details p { color: var(--muted); padding: 0 4px 22px; max-width: 64ch; }

/* ==========================================================================
   FOOTER
   ========================================================================== */
.footer { border-top: 1px solid var(--line); padding: 60px 0; }
.footer-grid { display: flex; flex-direction: column; gap: 24px; align-items: flex-start; }
.footer-brand { display: flex; align-items: center; gap: 14px; color: var(--muted); font-size: 15px; }
.footer-brand .brand-mark { width: 28px; height: 28px; }
.footer-links { display: flex; gap: 24px; }
.footer-links a { color: var(--text); font-size: 14px; font-weight: 500; text-decoration: none; }
.footer-links a:hover { text-decoration: underline; }
.footer-fine { font-family: var(--font-mono); font-size: 12px; color: var(--muted); }

/* ==========================================================================
   SCROLL REVEAL
   Elements only hide when JS has confirmed it's running (body.anim) — with
   scripts blocked or reduced motion requested, everything renders visible.
   ========================================================================== */
body.anim .reveal {
  opacity: 0;
  transform: translateY(24px);
  transition: opacity 0.7s ease, transform 0.7s ease;
}
body.anim .reveal.in { opacity: 1; transform: none; }
/* Steps cascade left-to-right instead of popping in as one block. */
body.anim .steps .reveal:nth-child(2) { transition-delay: 0.1s; }
body.anim .steps .reveal:nth-child(3) { transition-delay: 0.2s; }
body.anim .steps .reveal:nth-child(4) { transition-delay: 0.3s; }

/* ==========================================================================
   RESPONSIVE
   ========================================================================== */
@media (max-width: 900px) {
  .hero-grid { grid-template-columns: 1fr; text-align: center; padding-bottom: 60px; gap: 32px; }
  /* The stacked layout's first screen is the pitch alone — min-height still
     pins .hero-copy to the full viewport (so the interactive phone demo
     stays off-screen until the visitor scrolls or taps "Try the ritual"),
     but the content itself is vertically centered as one block via
     justify-content + gap rather than split top/bottom with an auto margin
     — that split left a dead gap in the middle on short copy. */
  .hero-copy { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 28px; min-height: calc(100svh - var(--nav-h) - 40px); padding: 44px 0 36px; }
  .hero-eyebrow { margin-bottom: 0; }
  .hero-copy h1 { margin-bottom: 0; }
  .lede { margin-bottom: 0; }
  .hero-actions { justify-content: center; }
  .hero-note { margin-top: 0; }
  .steps { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .card-fan { grid-template-columns: 1fr; max-width: 380px; margin: 0 auto; }
  .card-fan .mfc-lg { transform: none !important; }
  .tester-grid { grid-template-columns: 1fr; gap: 30px; }
  .founders-showcase .mini-focus-card { max-width: 250px; transform: rotate(2deg); }
  section { padding: 80px 0; }
}
@media (max-width: 520px) {
  /* Hero on small phones: .hero-copy now owns a full viewport on its own
     (see the 900px block above), so these are sizing choices for that
     single screen — not space-saving to squeeze in the phone demo, which
     is deliberately off-screen until the visitor scrolls or taps "Try the
     ritual". Type is sized up from the 900px pass so the centered block
     reads as a confident, near-full screen rather than a small cluster
     floating in empty space. */
  /* hero-grid's own top padding shrinks from 40px to 8px at this width, so
     .hero-copy's min-height needs the matching narrower offset to keep its
     bottom edge lined up with the viewport's (see the 900px block). */
  .hero-grid { padding: 8px 20px 40px; gap: 20px; }
  .hero-copy { min-height: calc(100svh - var(--nav-h) - 8px); gap: 32px; }
  .hero-eyebrow { font-size: 11px; letter-spacing: 0.15em; }
  .hero-copy h1 { font-size: clamp(70px, 23vw, 120px); }
  .lede { font-size: 19px; }
  .hero-actions .btn { padding: 15px 26px; font-size: 16px; }
  .phone-wrap { gap: 10px; }

  .steps { grid-template-columns: minmax(0, 1fr); }
  .pair { min-width: 100px; }
  .theme-list b { font-size: 16px; }
  .pair-cat { font-size: 11px; }
  .theme-note { font-size: 12.5px; }
  .deal li { padding: 18px 18px 18px 64px; }

  /* How-it-works mockups: at the phone widths this app actually ships to
     (see Native/Android Considerations), the 300px desktop cap still eats
     ~80% of the viewport once container padding is subtracted, making each
     step feel like a full-screen slide instead of a compact illustration
     next to its heading/copy. Shrink the box and scale its inner text down
     with it so nothing looks stretched or clipped. */
  .step-visual { max-width: 190px; padding: 14px; gap: 6px; }
  .sv-small { font-size: 8px; }
  .sv-task { font-size: 13px; }
  .sv-dur-num { font-size: 28px; }
  .sv-dur-unit { font-size: 9px; }
  .sv-chips { gap: 4px; margin-top: 10px; }
  .chip { font-size: 9px; padding: 3px 9px; }
  .sv-card { font-size: 13px; }
  .sv-card.c3 { font-size: 19px; }
  .ring-sm { width: 68%; }
  .sv-digits { font-size: 19px; }
  .step-visual .mfc-tag { font-size: 8px; }
  .step-visual .mfc-hero { font-size: 26px; }
  .step-visual .mfc-task { font-size: 9px; }
  .step-visual .mfc-meta { font-size: 6px; }
  .step-visual .mfc-watermark { font-size: 5.5px; }
  .step-visual .mfc-mark { width: 7px; height: 7px; }

  /* Focus Card showcase: same over-sized problem on the fanned example
     cards — cap them well below the 380px container so each square card
     reads as a poster-sized example, not a near-full-screen block.
     (Sized at +40% over the initial mobile pass per feedback — that first
     pass read as too small/cramped on an actual phone.) */
  .card-fan { max-width: 308px; gap: 25px; }
  .mfc-lg { padding: 22px; border-radius: 22px; }
  .mfc-lg .mfc-tag { font-size: 13px; }
  .mfc-lg .mfc-hero { font-size: 45px; }
  .mfc-lg .mfc-task { font-size: 14px; }
  .mfc-lg .mfc-meta { font-size: 10px; }
  .mfc-lg .mfc-watermark { font-size: 9px; }
  .mfc-lg .mfc-mark { width: 11px; height: 11px; }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .scr-count.running .wipe,
  .scr-count.running .numeral-contrast { transition: none; }
  .ring-progress, .ring-breathe { animation: none; }
  .ring-progress.closing,
  .ring-hero, .timer-digits, .timer-task,
  .scr-timer.statement .end-statement { transition: none; }
  .scr-timer.burst .shock-1, .scr-timer.burst .shock-2, .scr-timer.burst::after { animation: none; }
  .quotes-track { animation: none; }
  .on-word, .scr-begin { animation: none; }
  .tri i { animation: none; }
  body.anim .reveal { opacity: 1; transform: none; transition: none; }
}
