/* ==========================================================================
   BeCozU — Design System (core.css)
   Tokens, typography, nav/footer chrome, and the shared component vocabulary
   (.card/.card-feature/.card-media/.tile/.chip, card grids, icons, the Neuro
   Flow diagram) loaded by every page: index.html, about/, technology/, app/.
   Page-specific sections (hero, the Cinema, product-360, bento, research,
   specs, final CTA) live in home.css and load only on the root page.
   ========================================================================== */

:root {
  /* Plus Jakarta Sans leads. It used to sit fifth, behind SF Pro, which meant
     Macs and iPhones downloaded it and then never rendered a glyph of it —
     the page wore one face on Apple hardware and another on everything else.
     Apple can ship the OS font because it is their OS; a cinematic product
     page has to look the same wherever it is opened, and we were already
     paying the download. ("Inter" was in the old stack but never loaded.) */
  --font-sans: "Plus Jakarta Sans", system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
  /* One decorative glyph — the research card's opening quote mark. Body text
     is never serif. */
  --font-quote: Georgia, serif;

  --bg-primary: #000000;
  --bg-secondary: #07080c;
  --bg-surface: #0f1118;
  --bg-surface-elevated: #161924;
  --bg-glass: rgba(15, 17, 24, 0.75);
  --bg-nav: rgba(0, 0, 0, 0.82);

  --text-primary: #f5f5f7;
  --text-secondary: #a1a1a6;
  --text-tertiary: #6e6e73;
  --text-highlight: #ffffff;

  --accent-cyan: #00d2ff;
  --accent-cyan-glow: rgba(0, 210, 255, 0.35);
  /* Two lighter cyans the page already used as raw hex. Named, not invented —
     the values are unchanged. Anything cyan must come from these three. */
  --accent-cyan-hi: #5ec8ff;
  --accent-cyan-pale: #7fe3ff;
  /* The wash behind a cyan icon tile. Already in the file twice as raw rgba
     (.neuro-card-icon, and its reduced-motion/no-JS lit state at 0.22).
     Named, not invented — the value is unchanged. */
  --accent-cyan-dim: rgba(0, 210, 255, 0.1);
  /* Cyan's quiet sibling. Sensing and measuring only — the right ear watches
     while the left ear acts. Never a general-purpose second accent. */
  --accent-blue: #2997ff;
  --accent-blue-soft: rgba(41, 151, 255, 0.15);
  --accent-gradient: linear-gradient(135deg, #00d2ff 0%, #3a7bd5 100%);
  --text-gradient: linear-gradient(180deg, #ffffff 40%, #c7c7cc 100%);
  --hero-gradient: linear-gradient(180deg, #ffffff 45%, #d1d1d6 100%);
  --cyan-text-gradient: linear-gradient(135deg, #ffffff 0%, #00d2ff 100%);

  /* Dawn palette — the destination.
     Semantic rule: cyan is the light that guides you THROUGH the dark;
     amber is the dawn you ARRIVE at. Amber never appears before the final third. */
  --accent-dawn: #ffb26b;
  --accent-dawn-soft: rgba(255, 178, 107, 0.28);
  --dawn-gradient: linear-gradient(135deg, #ffd9a0 0%, #ff9d5c 100%);
  --dawn-text-gradient: linear-gradient(135deg, #ffffff 0%, #ffb26b 100%);
  /* Text sitting on dawn amber. Dark enough to read, warm enough to belong. */
  --on-dawn: #2a1405;

  /* Journey progress, 0 -> 1, written by initJourney() in main.js */
  --journey: 0;
  --journey-dawn: 0;
  /* journey^2.2 — when the sky starts to lift */
  --journey-horizon: 0;
  /* journey^4   — when the sun breaks the horizon */

  /* The white veil ladder — four steps, and only four.
     On a black page every "faint white film" is the same idea at a different
     strength, so it gets one ladder instead of ten one-off alphas. */
  --veil-1: rgba(255, 255, 255, 0.04);
  --veil-2: rgba(255, 255, 255, 0.08);
  --veil-3: rgba(255, 255, 255, 0.12);
  --veil-4: rgba(255, 255, 255, 0.32);

  --border-subtle: rgba(255, 255, 255, 0.08);
  --border-active: rgba(0, 210, 255, 0.4);
  --border-glass: rgba(255, 255, 255, 0.12);

  --radius-xs: 4px;
  --radius-md: 16px;
  --radius-lg: 24px;
  --radius-xl: 32px;
  --radius-pill: 9999px;

  /* Structural spacing snaps to this ladder. Values under 12px (2/4/6/8/10)
     are optical nudges inside chips and glyphs, not layout — they sit outside
     the scale on purpose rather than in violation of it. */
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 20px;
  --space-6: 24px;
  --space-7: 32px;
  --space-8: 40px;
  --space-9: 48px;
  --space-10: 64px;
  --space-11: 80px;
  --space-12: 120px;

  /* Depth on black cannot come from a black shadow, so shadow is reserved for
     things that must read as physical: media cards and device mockups.
     Everything else rises by getting lighter (see --bg-surface-elevated). */
  --shadow-lift: 0 10px 30px rgba(0, 0, 0, 0.6);
  --shadow-float: 0 20px 60px rgba(0, 0, 0, 0.8);
  --shadow-cinema: 0 30px 80px rgba(0, 0, 0, 0.9);

  /* Glows are light sources, not shadows — no vertical offset to speak of.
     Never put a glow and a shadow on the same element. */
  --glow-cyan: 0 0 22px rgba(0, 210, 255, 0.35);
  --glow-dawn: 0 8px 38px rgba(255, 178, 107, 0.55);
  --glow-soft: 0 4px 20px rgba(255, 255, 255, 0.15);

  --ease-apple: cubic-bezier(0.16, 1, 0.3, 1);
  --duration-fast: 0.2s;
  --duration-base: 0.4s;
  --duration-slow: 0.8s;
  --transition-default: all var(--duration-base) var(--ease-apple);

  /* Fixed header (52px) + sticky local ribbon (48px). This was referenced by
     .hero-sector-open but never declared anywhere, so its calc() was invalid
     and the whole padding-top declaration was being thrown away. */
  --nav-height: 100px;

  /* Caution yellow. This is signage, not sunrise: --accent-dawn (#ffb26b) is
     the arrival colour the journey clause reserves for the end of the root
     page and forbids outright on sub-pages, so a caution mark cannot borrow
     it. A separate, yellower value keeps the two unmistakably apart — a
     warning triangle reads as a warning at a glance, which a cyan one does
     not, and the narrative amber stays spent only on the dawn.
     Status marks only. Never a surface, never a headline, never decoration. */
  --status-caution: #ffc94d;

  --container-max: 1200px;
  --container-wide: 1400px;
  --container-narrow: 880px;


  /* Reading measure for documentation prose (manual/). Marketing sections scale
     their type with clamp() because they are scanned; a manual is read line by
     line, so its body column is pinned to a measure instead: 640px lands at
     ~34 Korean / ~67 Latin characters per line, inside the comfortable band for
     both. See design.md 매뉴얼 컴포넌트. */
  --measure-read: 640px;
}

/* --------------------------------------------------------------------------
   The Journey — Night to Dawn
   The page itself is the passage out of the dark. Three fixed sky layers
   cross-fade against scroll progress; sections sit on top of them, transparent.
   Cross-fading opacity is cheaper on the GPU (and far better supported) than
   interpolating gradient colour stops from a custom property.
   -------------------------------------------------------------------------- */
.journey-sky {
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  overflow: hidden;
}

.journey-sky>div {
  position: absolute;
  inset: 0;
  will-change: opacity;
}

/* Layer 1 — the night. Always present beneath everything. */
.sky-night {
  background:
    radial-gradient(ellipse 120% 80% at 50% 0%, #05070e 0%, var(--bg-primary) 60%),
    var(--bg-primary);
}

/* Layer 2 — the sky lifting. Deep navy replaces pure black. */
.sky-dawn {
  background:
    radial-gradient(ellipse 140% 100% at 50% 110%, #16233f 0%, #0a0f1e 45%, #04060d 100%);
  opacity: var(--journey-dawn);
}

/* Layer 3 — the sun breaking the horizon. The arrival. */
.sky-horizon {
  background:
    radial-gradient(ellipse 90% 46% at 50% 104%, rgba(255, 217, 160, 0.42) 0%, rgba(255, 157, 92, 0.24) 32%, rgba(255, 120, 80, 0.08) 55%, transparent 76%);
  opacity: var(--journey-horizon);
}

/* The light rail — one continuous thread of light travelling with the reader.
   Cyan at the start, dawn amber by the end. */
.light-rail {
  position: fixed;
  top: 0;
  left: 0;
  width: 2px;
  height: 100vh;
  z-index: 95;
  pointer-events: none;
  background: rgba(255, 255, 255, 0.06);
}

/* Clipped, not scaled. Scaling squeezes the whole cyan-to-amber gradient into
   the filled portion, which showed amber at the top of the page from the very
   first scroll. Clipping keeps the gradient fixed and reveals it in place, so
   the colour you see genuinely reports how far into the night you are. */
.light-rail-fill {
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, var(--accent-cyan) 0%, var(--accent-cyan-hi) 45%, var(--accent-dawn) 100%);
  box-shadow: 0 0 12px rgba(0, 210, 255, 0.5);
  clip-path: inset(0 0 calc((1 - var(--journey)) * 100%) 0);
  will-change: clip-path;
}

@media (max-width: 768px) {
  .light-rail {
    top: auto;
    bottom: 0;
    width: 100%;
    height: 2px;
  }

  .light-rail-fill {
    background: linear-gradient(90deg, var(--accent-cyan) 0%, var(--accent-cyan-hi) 45%, var(--accent-dawn) 100%);
    clip-path: inset(0 calc((1 - var(--journey)) * 100%) 0 0);
  }
}

/* --------------------------------------------------------------------------
   Scroll Reveal
   -------------------------------------------------------------------------- */
/* :where() keeps the JS gate at zero specificity, so the reduced-motion
   override further down still wins on plain `.reveal`. */
:where(.has-js) .reveal {
  opacity: 0;
  transform: translateY(24px);
  transition:
    opacity 0.8s var(--ease-apple),
    transform 0.8s var(--ease-apple);
  transition-delay: calc(var(--i, 0) * 80ms);
  will-change: opacity, transform;
}

.reveal.is-visible {
  opacity: 1;
  transform: none;
}

/* --------------------------------------------------------------------------
   Global Layout & Typography
   -------------------------------------------------------------------------- */
.container {
  width: 100%;
  max-width: var(--container-max);
  margin-left: auto;
  margin-right: auto;
  padding-left: var(--space-6);
  padding-right: var(--space-6);
}

.container-narrow {
  width: 100%;
  max-width: var(--container-narrow);
  margin-left: auto;
  margin-right: auto;
  padding-left: var(--space-6);
  padding-right: var(--space-6);
}

.section {
  position: relative;
  padding: var(--space-12) 0;
  /* clip, not hidden: `overflow: hidden` makes a scroll container, which
     silently kills `position: sticky` on any descendant. */
  overflow-x: clip;
}

/* The block every section opens with: eyebrow, headline, lead paragraph.
   This was pasted inline into six sections with three different max-widths
   and two different bottom margins, which is why no two sections quite
   agreed on where their body copy started. */
.section-intro {
  max-width: 800px;
  margin: 0 auto var(--space-9) auto;
  text-align: center;
}

/* The eyebrow is a label and belongs close to its headline; the lede is a
   separate paragraph and needs the extra step. Both gaps were 16px, which
   read as one undifferentiated block. */
.section-intro .body-large {
  margin-top: var(--space-6);
}

/* Apple Pro Eyebrow Tag */
.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 0.875rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--accent-cyan);
  margin-bottom: var(--space-4);
  line-height: 1.3;
}

.eyebrow-dot {
  width: 6px;
  height: 6px;
  background-color: var(--accent-cyan);
  border-radius: 50%;
  box-shadow: 0 0 10px var(--accent-cyan);
}

/* Headings with Anti-Clipping & Balanced Line Wrapping */
.headline-huge {
  font-size: clamp(2.5rem, 5.5vw, 4.5rem);
  font-weight: 700;
  line-height: 1.15;
  letter-spacing: -0.03em;
  background: var(--hero-gradient);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
  padding-bottom: 0.08em;
  margin-bottom: var(--space-5);
  word-break: keep-all;
  overflow-wrap: break-word;
  text-wrap: balance;
}

.headline-large {
  font-size: clamp(2rem, 4vw, 3.25rem);
  font-weight: 700;
  line-height: 1.2;
  letter-spacing: -0.025em;
  background: var(--text-gradient);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
  padding-bottom: 0.08em;
  margin-bottom: var(--space-4);
  word-break: keep-all;
  overflow-wrap: break-word;
  text-wrap: balance;
}

.headline-medium {
  font-size: clamp(1.6rem, 3vw, 2.25rem);
  font-weight: 700;
  line-height: 1.3;
  letter-spacing: -0.02em;
  color: var(--text-primary);
  margin-bottom: var(--space-3);
  word-break: keep-all;
  overflow-wrap: break-word;
  text-wrap: balance;
}

.headline-small {
  font-size: clamp(1.2rem, 2vw, 1.5rem);
  font-weight: 600;
  line-height: 1.38;
  color: var(--text-primary);
  margin-bottom: var(--space-2);
  word-break: keep-all;
  overflow-wrap: break-word;
  text-wrap: balance;
}

.body-large {
  font-size: clamp(1.125rem, 1.5vw, 1.25rem);
  line-height: 1.75;
  color: #f5f5f7;
  font-weight: 400;
  letter-spacing: -0.01em;
  word-break: keep-all;
  overflow-wrap: break-word;
  text-wrap: balance;
}

.body-medium {
  font-size: 1.0625rem;
  line-height: 1.75;
  color: #d1d1d6;
  font-weight: 400;
  letter-spacing: -0.005em;
  word-break: keep-all;
  overflow-wrap: break-word;
  text-wrap: balance;
}

/* Universal paragraph rhythm — stacked paragraphs never cram together */
.body-large + .body-medium,
.body-large + .body-large,
.body-medium + .body-medium,
.body-medium + .body-large,
.body-large + .feature-list,
.body-medium + .feature-list,
.body-large + .btn-row,
.body-medium + .btn-row {
  margin-top: var(--space-5);
}

.body-small {
  font-size: 0.9375rem;
  line-height: 1.65;
  color: var(--text-secondary);
  word-break: keep-all;
  overflow-wrap: break-word;
  text-wrap: balance;
}

/* Text Gradients (Anti-Clipping for 'g', 'y', 'p', 'q', 'j') */
.text-cyan-gradient {
  background: var(--cyan-text-gradient);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
  display: inline;
  padding-bottom: 0.08em;
}

/* --------------------------------------------------------------------------
   Hard line breaks
   Every intentional break in a headline is a literal <br>, placed by eye at
   desktop width. Left standing on a phone they work against text-wrap:
   balance: the balancer runs per segment, so a break splits one headline into
   two independently balanced halves and the block can never even itself out.
   Below 640px the copy needs every line it can get, so the hand-placed breaks
   step aside and the balancer takes the decision.
   Deliberately not listed: .specs-value and the footer address, where the
   breaks separate real items rather than shape a sentence; the closing CTA
   headline, whose two lines carry two different gradients; and the closing
   CTA lede (.cta-lead), a three-beat line the dash used to carry ("It walks
   through them — so you reach the morning") until the beat was put in the
   break instead and the connective word dropped, matching the asyndetic
   line above it.
   -------------------------------------------------------------------------- */
@media (max-width: 640px) {

  .br-wide,
  .headline-large br {
    display: none;
  }
}

/* --------------------------------------------------------------------------
   Scroll Anchor Clearance for Sticky Navigation
   -------------------------------------------------------------------------- */
section[id],
.section[id],
.story-scroll-track[id] {
  scroll-margin-top: 96px;
}

#hero {
  scroll-margin-top: 0;
}

/* --------------------------------------------------------------------------
   Layout utilities
   -------------------------------------------------------------------------- */
.text-center {
  text-align: center;
}

.font-weight-bold {
  font-weight: 700;
}

/* Matches the 24px rhythm the rest of the page already spaces on. */
.space-y-6>*+* {
  margin-top: 24px;
}

/* Buttons & CTA */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 14px 28px;
  font-size: 0.95rem;
  font-weight: 600;
  border-radius: var(--radius-pill);
  transition: var(--transition-default);
  text-decoration: none;
  white-space: nowrap;
}

.btn-primary {
  background: var(--text-primary);
  color: var(--bg-primary);
  box-shadow: var(--glow-soft);
}

.btn-primary:hover {
  background: var(--text-highlight);
  transform: translateY(-2px);
  box-shadow: 0 6px 28px rgba(0, 210, 255, 0.4);
}

.btn-secondary {
  background: var(--veil-2);
  color: var(--text-primary);
  backdrop-filter: blur(12px);
  border: 1px solid var(--border-subtle);
}

.btn-secondary:hover {
  background: var(--veil-3);
  border-color: var(--border-glass);
  transform: translateY(-2px);
}

/* The closing CTA's pair. Both buttons carried their own inline padding and
   disagreed with each other by 4px; this is the one size they share. */
.btn-lg {
  padding: var(--space-4) var(--space-7);
  font-size: 1rem;
}

.btn-icon {
  width: 18px;
  height: 18px;
  stroke-width: 2.2;
}

/* The only amber button in the system. Base look only — the closing CTA's
   3.5s arrival rise lives in home.css, scoped to .final-cta-section, not
   folded into this rule. A bare .btn-dawn (app/'s store-download exception,
   the sole sub-page use per design.md's journey clause) just looks like a
   button: no lingering low-opacity entrance state waiting for a
   .dawn-active ancestor that only the root's #cta ever supplies. */
.btn-dawn {
  background: var(--dawn-gradient);
  color: var(--on-dawn);
  font-weight: 700;
  box-shadow: 0 4px 28px var(--accent-dawn-soft);
}

.btn-dawn:hover {
  transform: translateY(-2px) scale(1.02);
  box-shadow: var(--glow-dawn);
}

/* --------------------------------------------------------------------------
   Header & Local Nav (Apple Glassmorphism)
   -------------------------------------------------------------------------- */
.global-header {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  z-index: 100;
  background: var(--bg-nav);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
  border-bottom: 1px solid var(--border-subtle);
  transition: transform 0.3s ease, background 0.3s ease;
}

.nav-container {
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 52px;
  max-width: var(--container-wide);
  margin: 0 auto;
  padding: 0 24px;
}

.nav-brand {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 1.25rem;
  font-weight: 700;
  letter-spacing: -0.03em;
  color: var(--text-highlight);
}

.nav-brand-logo {
  height: 24px;
  width: auto;
  filter: brightness(0) invert(1);
  display: block;
}

.nav-links {
  display: flex;
  align-items: center;
  gap: var(--space-7);
}

.nav-link {
  font-size: 0.8125rem;
  font-weight: 400;
  color: var(--text-secondary);
  transition: color 0.2s ease;
  letter-spacing: -0.01em;
}

.nav-link:hover {
  color: var(--text-highlight);
}

.nav-link.active {
  color: var(--text-highlight);
  font-weight: 600;
}

.nav-actions {
  display: flex;
  align-items: center;
  gap: var(--space-4);
}

.menu-toggle {
  display: none;
  flex-direction: column;
  gap: 5px;
  padding: 8px;
  z-index: 101;
}

.menu-toggle span {
  display: block;
  width: 20px;
  height: 2px;
  background-color: var(--text-highlight);
  transition: var(--transition-default);
}

/* --------------------------------------------------------------------------
   Language switcher (header-mounted)
   Lives in .nav-actions, left of the hamburger. Only manual/ ships the markup
   today, but this is chrome, not a manual component, so it belongs here rather
   than in manual.css — and the slot is ready if another page family ever needs
   translating.

   The visible widget is built at runtime by /js/manual.js, which hides
   the native <select id="lang-selector"> and appends .custom-select-container
   as its sibling. The select must survive: every option click routes back
   through langSelector.dispatchEvent(new Event('change')), which is what
   persists the choice to localStorage.
   -------------------------------------------------------------------------- */
.lang-wrapper {
  display: flex;
  align-items: center;
}

.custom-select-container {
  position: relative;
  user-select: none;
}

.custom-select-trigger {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: 6px 12px;
  font-size: 0.8125rem;
  font-weight: 600;
  font-family: inherit;
  color: var(--text-primary);
  background: var(--veil-2);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-pill);
  cursor: pointer;
  transition: var(--transition-default);
}

.custom-select-trigger:hover {
  color: var(--text-highlight);
  border-color: var(--border-glass);
}

.custom-select-flag {
  width: 20px;
  height: 14px;
  object-fit: cover;
  border-radius: 2px;
  border: 1px solid var(--border-subtle);
  flex-shrink: 0;
}

.custom-select-arrow {
  font-size: 0.625rem;
  color: var(--text-secondary);
  transition: transform var(--duration-fast) ease;
}

.custom-select-container.open .custom-select-arrow {
  transform: rotate(180deg);
}

/* Right-anchored, not stretched to the trigger: the trigger is now content-sized
   (it was a fixed 140px box in the old in-page toolbar) and it sits at the right
   edge of the viewport, so a left-anchored panel would overflow. */
.custom-select-options {
  position: absolute;
  top: calc(100% + var(--space-2));
  right: 0;
  left: auto;
  min-width: 168px;
  background: var(--bg-surface-elevated);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-lift);
  overflow: hidden;
  display: none;
}

.custom-select-container.open .custom-select-options {
  display: block;
}

.custom-select-option {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  padding: 10px 14px;
  cursor: pointer;
  font-size: 0.875rem;
  color: var(--text-secondary);
  transition: background-color 0.15s ease, color 0.15s ease;
}

.custom-select-option:hover,
.custom-select-option.selected {
  background: var(--accent-cyan-dim);
  color: var(--accent-cyan);
}

.custom-select-option.selected {
  font-weight: 700;
}

/* Local Subnav Ribbon */
.local-nav {
  position: sticky;
  top: 52px;
  left: 0;
  width: 100%;
  z-index: 90;
  background: rgba(0, 0, 0, 0.75);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  border-bottom: 1px solid var(--border-subtle);
  transition: all 0.3s ease;
}

/* Header retracts on scroll-down, returns on scroll-up (Apple behaviour).
   The local ribbon rides up with it so no gap opens. */
.global-header.is-hidden {
  transform: translateY(-100%);
}

.nav-retracted .local-nav {
  top: 0;
}

.local-nav-container {
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 48px;
  max-width: var(--container-wide);
  margin: 0 auto;
  padding: 0 24px;
}

.local-nav-title {
  font-size: 1.125rem;
  font-weight: 700;
  color: var(--text-highlight);
  letter-spacing: -0.02em;
}

/* Breadcrumb variant of the ribbon title, for a sub-site that has real
   hierarchy to say out loud (manual/ = index → topic). The plain
   .local-nav-title is a page name standing alone and can afford 1.125rem/700;
   a two-part crumb sitting directly above the article's own h1 has to be
   quieter than it, or the two headings compete. */
.local-nav-crumb {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-width: 0;
  font-size: 0.875rem;
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--text-secondary);
}

.local-nav-crumb a {
  color: var(--text-secondary);
  transition: color var(--duration-fast) ease;
}

.local-nav-crumb a:hover {
  color: var(--text-highlight);
}

.local-nav-crumb-sep {
  color: var(--text-tertiary);
}

/* The trailing crumb is where you actually are — the one part that gets full
   brightness. It also truncates, because a translated topic name plus the
   TOC button has to survive a 390px ribbon. */
.local-nav-crumb-current {
  color: var(--text-highlight);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Opens the manual TOC as a drawer. Hidden on desktop, where the TOC is a
   permanent column and a button to reveal it would be a lie. */
.toc-toggle {
  display: none;
  align-items: center;
  gap: var(--space-2);
  flex-shrink: 0;
  padding: 6px 14px;
  border-radius: var(--radius-pill);
  background: var(--veil-2);
  border: 1px solid var(--border-subtle);
  color: var(--text-primary);
  font-size: 0.8125rem;
  font-weight: 600;
  white-space: nowrap;
  transition: var(--transition-default);
}

.toc-toggle:hover {
  background: var(--veil-3);
  border-color: var(--border-glass);
}

.toc-toggle .icon {
  width: 16px;
  height: 16px;
}

.local-nav-items {
  display: flex;
  align-items: center;
  gap: 22px;
}

.local-nav-item {
  font-size: 0.75rem;
  color: var(--text-secondary);
  transition: color 0.2s ease;
}

.local-nav-item:hover,
.local-nav-item.active {
  color: var(--accent-cyan);
}

/* Mobile Nav Drawer */
.mobile-nav-overlay {
  display: none;
  position: fixed;
  top: 52px;
  left: 0;
  width: 100%;
  height: calc(100vh - 52px);
  background: rgba(0, 0, 0, 0.95);
  backdrop-filter: blur(24px);
  z-index: 99;
  padding: 40px 24px;
  flex-direction: column;
  gap: var(--space-6);
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  transform: translateY(-100%);
  opacity: 0;
  transition: all 0.4s var(--ease-apple);
}

.mobile-nav-overlay.open {
  transform: translateY(0);
  opacity: 1;
}

.mobile-nav-link {
  font-size: 1.5rem;
  font-weight: 600;
  color: var(--text-secondary);
  transition: color 0.2s ease;
}

.mobile-nav-link.active,
.mobile-nav-link:hover {
  color: var(--text-highlight);
}

/* The drawer holds four links now, but it is a fixed-height container with
   no scroll of its own: when it also carried the page's section anchors the
   overflow was simply unreachable. Short viewports (landscape phones) can
   still run out of room, so it scrolls rather than clips. */

/* --------------------------------------------------------------------------
   Cards
   design.md's card table, finally implemented. Four shapes, one idea: the
   surface lifts and the edge brightens (제2원칙). Nothing here gains a
   shadow on hover — a shadow on black is invisible anyway, and the depth
   ladder is surface + border, not blur. .card-feature and .card-media are
   modifiers, used as class="card card-feature".

   The root page's seven bespoke cards (.neuro-card, .dual-ear-card,
   .bento-card, .research-card, .product-video-card, .box-item-card,
   .box-flatlay-card) are deliberately NOT refactored onto this family —
   they are genuinely different objects (gradients, --bg-glass blur,
   asymmetric padding) and some already drift from 제2·3원칙 (-4px hover,
   added shadows). This family sits before them in file order on purpose:
   class="neuro-card card" would work later with .neuro-card's own
   declarations winning by source order, should that migration ever happen.
   -------------------------------------------------------------------------- */
.card {
  background: var(--bg-surface);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  padding: var(--space-7);
  transition:
    background var(--duration-base) var(--ease-apple),
    border-color var(--duration-base) var(--ease-apple),
    transform var(--duration-base) var(--ease-apple);
}

.card:hover {
  background: var(--bg-surface-elevated);
  border-color: var(--border-glass);
  transform: translateY(-2px);
}

/* .reveal also declares the `transition` shorthand, and a shorthand replaces
   the whole property list — so whichever wins source order silently takes
   the other's properties with it. At (0,1,0) each that's decided by nothing
   but file position. This rule at (0,2,0) settles it: opacity/transform get
   the 0.8s entrance and --i stagger, background/border-color/transform get
   the 0.4s hover treatment. (The root page has this exact bug today on its
   bespoke cards via --transition-default — not fixed here, out of scope.) */
:where(.has-js) .card.reveal,
:where(.has-js) .tile.reveal {
  transition:
    opacity var(--duration-slow) var(--ease-apple) calc(var(--i, 0) * 80ms),
    transform var(--duration-slow) var(--ease-apple) calc(var(--i, 0) * 80ms),
    background var(--duration-base) var(--ease-apple),
    border-color var(--duration-base) var(--ease-apple);
}

.card-feature {
  display: flex;
  flex-direction: column;
  border-radius: var(--radius-xl);
  padding: var(--space-8);
  height: 100%;
}

/* Media: the one card allowed a shadow, because it has to read as a
   physical object rather than a panel. The border comes off; the image
   is the edge. The vignette + dimming keeps bright photography from
   reading as a glowing rectangle floating on #000. */
.card-media {
  position: relative;
  isolation: isolate;
  border: 0;
  border-radius: var(--radius-xl);
  padding: 0;
  overflow: hidden;
  background: var(--bg-surface);
  box-shadow: var(--shadow-float);
}

.card-media > img,
.card-media > video {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: brightness(0.88) contrast(1.04);
}

.card-media::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: radial-gradient(circle at 50% 50%, transparent 48%, rgba(0, 0, 0, 0.42) 82%, rgba(0, 0, 0, 0.72) 100%);
}

.card-media-4x3 { aspect-ratio: 4 / 3; }
.card-media-16x9 { aspect-ratio: 16 / 9; }
.card-media-auto { aspect-ratio: auto; }

/* A media card sits still: shadow is not a hover affordance here, and a
   card that already floats has nowhere to rise to. */
.card-media:hover {
  background: var(--bg-surface);
  transform: none;
}

/* Interactive video media card */
.card-media-video {
  display: block;
  cursor: pointer;
  text-decoration: none;
  transition: transform var(--transition-base), box-shadow var(--transition-base);
}

.card-media-video:hover {
  transform: translateY(-2px);
  box-shadow: var(--shadow-float), 0 0 30px rgba(0, 210, 255, 0.2);
}

.card-media-video > img {
  transition: transform var(--transition-base), filter var(--transition-base);
}

.card-media-video:hover > img {
  transform: scale(1.03);
  filter: brightness(0.98) contrast(1.04);
}

.video-play-btn {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 54px;
  height: 54px;
  border-radius: 50%;
  background: rgba(0, 0, 0, 0.65);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  border: 1px solid rgba(255, 255, 255, 0.28);
  display: flex;
  align-items: center;
  justify-content: center;
  color: #ffffff;
  z-index: 2;
  transition: transform var(--transition-base), background var(--transition-base), border-color var(--transition-base), color var(--transition-base), box-shadow var(--transition-base);
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.6);
}

.video-play-btn svg {
  width: 22px;
  height: 22px;
  margin-left: 3px;
  fill: currentColor;
}

.card-media-video:hover .video-play-btn {
  transform: translate(-50%, -50%) scale(1.12);
  background: rgba(0, 210, 255, 0.25);
  border-color: var(--accent-cyan);
  color: var(--accent-cyan-pale);
  box-shadow: 0 0 25px rgba(0, 210, 255, 0.5);
}

.video-badge-pill {
  position: absolute;
  bottom: var(--space-4);
  left: var(--space-4);
  z-index: 2;
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: 6px 14px;
  background: rgba(0, 0, 0, 0.72);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  border: 1px solid rgba(255, 255, 255, 0.18);
  border-radius: var(--radius-full);
  font-size: var(--text-xs);
  font-weight: 600;
  color: var(--text-primary);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  transition: border-color var(--transition-fast), background var(--transition-fast);
}

.video-badge-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--accent-cyan);
  box-shadow: 0 0 8px var(--accent-cyan);
}

.card-media-video:hover .video-badge-pill {
  border-color: var(--accent-cyan);
  background: rgba(0, 0, 0, 0.88);
}

/* Video Lightbox Modal */
.video-modal-backdrop {
  position: fixed;
  inset: 0;
  z-index: 9999;
  background: rgba(0, 0, 0, 0.88);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-4);
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.28s ease, visibility 0.28s ease;
}

.video-modal-backdrop.is-open {
  opacity: 1;
  visibility: visible;
}

.video-modal-container {
  position: relative;
  width: 100%;
  max-width: 920px;
  background: #000000;
  border-radius: var(--radius-lg);
  overflow: hidden;
  border: 1px solid var(--border-subtle);
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.85), 0 0 40px rgba(0, 210, 255, 0.12);
  transform: scale(0.95);
  transition: transform 0.28s cubic-bezier(0.16, 1, 0.3, 1);
}

.video-modal-backdrop.is-open .video-modal-container {
  transform: scale(1);
}

.video-modal-wrapper {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9;
  background: #000000;
}

.video-modal-wrapper iframe {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  border: 0;
}

.video-modal-close {
  position: absolute;
  top: var(--space-3);
  right: var(--space-3);
  z-index: 10;
  background: rgba(0, 0, 0, 0.7);
  border: 1px solid rgba(255, 255, 255, 0.2);
  color: #ffffff;
  width: 38px;
  height: 38px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  transition: background var(--transition-fast), transform var(--transition-fast), border-color var(--transition-fast);
}

.video-modal-close:hover {
  background: rgba(255, 255, 255, 0.25);
  border-color: rgba(255, 255, 255, 0.4);
  transform: scale(1.08);
}

.video-modal-close svg {
  width: 18px;
  height: 18px;
}

/* 2x2 Square Media Grid */
.media-grid-2x2 {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--space-3);
  width: 100%;
  aspect-ratio: 1 / 1;
}

.media-grid-cell {
  position: relative;
  overflow: hidden;
  border-radius: var(--radius-lg);
  background: var(--bg-surface);
  border: 1px solid var(--border-subtle);
  aspect-ratio: 1 / 1;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: var(--shadow-float);
  transition: transform var(--transition-base), border-color var(--transition-base), box-shadow var(--transition-base);
}

.media-grid-cell:hover {
  transform: translateY(-2px) scale(1.02);
  border-color: var(--border-active);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.6), 0 0 20px rgba(0, 210, 255, 0.18);
  z-index: 2;
}

.media-grid-cell > img,
.media-grid-cell > video {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Wraps a .card-media plus ambient glow circles that bleed past its edge.
   .card-media itself clips (overflow: hidden, so the image corners stay
   sharp) — the glow needs a visible outer box to bleed into, hence a
   separate positioning context around both. Promoted from the root page's
   #design section, which was the only user until app/'s hero needed the
   same glow-behind-media shape. */
.card-media-frame {
  position: relative;
  isolation: isolate;
}

.ambient-glow-circle {
  position: absolute;
  width: 380px;
  height: 380px;
  border-radius: 50%;
  background: radial-gradient(circle, var(--accent-cyan-glow) 0%, transparent 70%);
  filter: blur(60px);
  z-index: 0;
  pointer-events: none;
}

.glow-top-right {
  top: -60px;
  right: -60px;
}

.glow-bottom-left {
  bottom: -60px;
  left: -60px;
}

/* Tile: a labelled cell inside a card. The faintest rung on the veil
   ladder, so it reads as a subdivision of its parent surface rather than
   a second card on top of one. Not interactive, so no hover. */
.tile {
  background: var(--veil-1);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
  padding: var(--space-4);
}

/* Chip: a word with a border around it. Inline, so it sits in text flow. */
.chip {
  display: inline-flex;
  align-items: center;
  gap: 6px; /* optical, inside a chip: outside the 12-step scale */
  padding: var(--space-2) var(--space-4);
  background: var(--veil-1);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-pill);
  font-size: 0.8125rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--text-secondary);
  white-space: nowrap;
}

/* The one sanctioned emphasis tint: cyan, lit rather than filled. Same
   values the ear tags already use. No amber variant exists on purpose —
   see the journey clause under 제1원칙. */
.chip-active {
  background: rgba(0, 210, 255, 0.15);
  border-color: var(--border-active);
  color: var(--accent-cyan);
}

/* --------------------------------------------------------------------------
   Card grids
   design.md's own gap rhythm (space-6, space-9 above, one column at 1024),
   named for what they hold rather than assembled per-section like the root
   page's seven bespoke grids (.neuro-flow-grid, .dual-ear-container,
   .research-quote-grid, .box-items-grid, .bento-grid, .product-showcase-grid,
   .app-showcase-wrap). New sections use these instead of growing an eighth.
   -------------------------------------------------------------------------- */
.card-grid {
  display: grid;
  gap: var(--space-6);
  margin-top: var(--space-9);
}

.card-grid-2 { grid-template-columns: repeat(2, 1fr); }
.card-grid-3 { grid-template-columns: repeat(3, 1fr); }
.card-grid-4 { grid-template-columns: repeat(4, 1fr); }

@media (max-width: 1024px) {
  .card-grid { gap: 40px; }
  .card-grid-2,
  .card-grid-3 { grid-template-columns: 1fr; }
  .card-grid-4 { grid-template-columns: repeat(2, 1fr); }
}

@media (max-width: 768px) {
  .card-grid-4 { grid-template-columns: 1fr; }
}

/* --------------------------------------------------------------------------
   Research quote cards
   Promoted to core: the root's #research section and technology/'s "Backed
   by Research" section quote the same four papers verbatim (content.md §6),
   so this is now a 2-page shared component rather than a root-only one.
   Two across, not three: there are four citations, and technology/ — the
   page these quotes are taken from — lays them out two across as well.
   -------------------------------------------------------------------------- */
.research-quote-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--space-6);
  margin-top: var(--space-9);
}

@media (max-width: 1024px) {
  .research-quote-grid {
    grid-template-columns: 1fr;
  }
}

.research-card {
  background: var(--bg-glass);
  backdrop-filter: blur(12px);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  padding: var(--space-7);
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: var(--space-6);
  transition: var(--transition-default);
}

/* Quotes from papers read as primary text, not as supporting copy. */
.research-card .body-medium {
  color: var(--text-primary);
}

.research-disclaimer {
  margin-top: var(--space-8);
  color: var(--text-tertiary);
}

.research-card:hover {
  border-color: var(--border-active);
  transform: translateY(-4px);
}

.research-quote-mark {
  font-size: 2.5rem;
  color: var(--accent-cyan);
  line-height: 1;
  font-family: var(--font-quote);
}

.research-journal-tag {
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--accent-cyan);
}

/* --------------------------------------------------------------------------
   Specs table & box contents
   Promoted to core: about/'s "Product Details" and "What's in the Box"
   sections are this same shape as the root's #specs, not new components.
   -------------------------------------------------------------------------- */
.specs-table {
  width: 100%;
  border-collapse: collapse;
  margin-top: var(--space-9);
}

.specs-row {
  border-bottom: 1px solid var(--border-subtle);
  display: grid;
  grid-template-columns: 280px 1fr;
  padding: var(--space-6) 0;
  transition: background 0.2s ease;
}

@media (max-width: 1024px) {
  .specs-row {
    grid-template-columns: 1fr;
    gap: 8px;
  }
}

.specs-label {
  font-size: 1rem;
  font-weight: 600;
  color: var(--text-highlight);
}

.specs-value {
  font-size: 1rem;
  color: var(--text-secondary);
  line-height: 1.6;
}

.box-items-grid {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: var(--space-5);
  margin-top: var(--space-9);
  text-align: center;
}

@media (max-width: 1024px) {
  .box-items-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

.box-item-card {
  background: var(--bg-surface);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  padding: var(--space-7) var(--space-4);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-4);
}

.box-item-card .body-small {
  font-weight: 600;
  color: var(--text-highlight);
}

.box-flatlay-card {
  max-width: 880px;
  margin: 36px auto 32px auto;
  border-radius: var(--radius-xl);
  overflow: hidden;
  border: 1px solid var(--border-subtle);
  box-shadow: var(--shadow-float);
  background: var(--bg-surface);
}

.box-flatlay-card {
  margin-top: var(--space-8);
  margin-bottom: var(--space-7);
}

.specs-box-title {
  margin-top: var(--space-11);
}

.box-flatlay-img {
  width: 100%;
  height: auto;
  display: block;
}

.box-item-icon {
  width: 44px;
  height: 44px;
  color: var(--accent-cyan);
}

/* --------------------------------------------------------------------------
   Icons
   The page draws its icons; it does not typeset them. Every glyph is an
   inline 24x24 stroke SVG inheriting currentColor, matching the root
   page's existing 25 SVGs (fill:none, stroke:currentColor, stroke-width:2,
   round caps/joins). No icon font: a ligature font renders its own source
   text until it loads (a flash of grey words on black), and a filled
   glyph is a different drawing language from the outlines used everywhere
   else on the page.
   -------------------------------------------------------------------------- */
.icon {
  width: 24px;
  height: 24px;
  flex-shrink: 0;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.icon-sm { width: 20px; height: 20px; }
.icon-lg { width: 32px; height: 32px; stroke-width: 1.75; }

/* The 48px cyan icon tile the neuro cards already use, generalised as a
   component. Climbs the veil ladder, not the shadow ladder — it is the
   icon's surface. */
.card-icon {
  width: 48px;
  height: 48px;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--radius-md);
  background: var(--accent-cyan-dim);
  color: var(--accent-cyan);
  margin-bottom: var(--space-5);
}

.card-icon-center { margin-left: auto; margin-right: auto; }

/* For icons that label rather than signal — no cyan, no light source. */
.card-icon-quiet {
  background: var(--veil-1);
  color: var(--text-primary);
}

/* Large cyan-gradient numeral, promoted from the root's bento grid (name
   kept as-is since root's markup already references it -- renaming here
   would silently unstyle the root's bento numerals). about/'s timeline
   needed the same "big number" treatment. */
.bento-big-stat {
  font-size: clamp(3rem, 5vw, 4.5rem);
  font-weight: 800;
  line-height: 1.25;
  letter-spacing: -0.04em;
  color: var(--text-highlight);
  margin: 8px 0 14px 0;
  background: var(--cyan-text-gradient);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
  display: inline-block;
  padding-bottom: 0.15em;
}

/* A short list of icon + sentence rows. Promoted from the root page's
   dual-hardware section, which was the only user until sub-pages needed
   the same shape for feature bullets. */
.feature-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  margin-top: 24px;
}

.feature-item {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  font-size: 0.9375rem;
  color: var(--text-secondary);
  line-height: 1.5;
}

.feature-check-icon {
  width: 20px;
  height: 20px;
  flex-shrink: 0;
  color: var(--accent-cyan);
  margin-top: 2px;
}

.feature-item strong {
  color: var(--text-highlight);
}

/* A feature list with no top margin of its own -- e.g. sitting beside a
   card rather than under a heading that already carries the gap. */
.feature-list-flush {
  margin-top: 0;
}

/* --------------------------------------------------------------------------
   Sub-page layout helpers
   Sub-pages carry no .journey-sky and no local .hero-section, so they need
   a few small generic pieces the root page never needed on its own.
   -------------------------------------------------------------------------- */

/* Fixed-chrome offset for sub-pages: absorbs the 52px header, not a
   section-padding exception. .section keeps 120px 0 everywhere, including
   a sub-page's first section — see design.md 고정 크롬. */
.page-main {
  padding-top: 52px;
}

/* Night variant of the light rail for pages that never reach dawn: same
   three-stop shape, same brightening curve, but the last stop is the
   lightest cyan instead of amber, so progress reads as brightness and the
   rail never promises a sunrise the page cannot deliver. .light-rail-fill's
   own values are untouched (준보호) — this is an added sibling modifier. */
.light-rail-fill-cool {
  background: linear-gradient(180deg, var(--accent-cyan) 0%, var(--accent-cyan-hi) 45%, var(--accent-cyan-pale) 100%);
}

@media (max-width: 768px) {
  .light-rail-fill-cool {
    background: linear-gradient(90deg, var(--accent-cyan) 0%, var(--accent-cyan-hi) 45%, var(--accent-cyan-pale) 100%);
  }
}

/* Two-column split, the honest generic name for the shape
   .product-showcase-grid already is. Joined via a comma selector so the
   root page's rule is unchanged. */
.split-grid,
.product-showcase-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--space-8);
  align-items: center;
}

/* Media on the left at desktop, text first in DOM order (correct reading
   order and correct mobile stacking without a second markup order). */
.split-grid-alt > *:first-child {
  order: 2;
}

@media (max-width: 1024px) {
  .split-grid,
  .product-showcase-grid {
    grid-template-columns: 1fr;
  }

  .split-grid-alt > *:first-child {
    order: 0;
  }
}

/* Two split-grid pairs stacked in one section (about/'s overview and
   comfort sections each cover two sub-topics) need the same breathing
   room a fresh .section would give them, without opening a new section
   and its 120px rhythm. */
.split-grid + .split-grid {
  margin-top: var(--space-11);
}

/* A card-feature that opens with a photo before its text -- the media
   needs the same gap below it that a heading would carry. */
.card-feature > .card-media {
  margin-bottom: var(--space-6);
}

/* An attribution line following body copy inside a card. */
.card-feature > .body-medium {
  flex-grow: 1;
  margin-bottom: var(--space-4);
}

.body-medium + .chip,
.card-feature > .chip {
  margin-top: auto;
  align-self: flex-start;
}

/* For a portrait subject where the top of the frame matters more than
   the centre (about/'s team section crops a tall process photo). */
.card-media-top > img {
  object-position: top;
}

/* A block of stacked sub-sections inside one split-grid column (about/'s
   "Who We Are" + "Our Journey" pair, sharing one image on the right). */
.stacked-blocks {
  display: flex;
  flex-direction: column;
  gap: var(--space-9);
}

/* Sub-page closer: a doorway, not an arrival. No .final-cta-section padding
   exception — see the unified closer in the migration plan. */
.closer-actions {
  display: flex;
  justify-content: center;
  flex-wrap: wrap;
  gap: var(--space-4);
  margin-top: var(--space-8);
}

/* Left-aligned button group, for anywhere two buttons sit beside text
   rather than centred under it (the root's .hero-cta-group is the
   centred, hero-only version of this same shape). */
.btn-row {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  flex-wrap: wrap;
  margin-top: var(--space-7);
}

/* --------------------------------------------------------------------------
   Neuro Flow Diagram
   Promoted to core: originally lived only in the root page's taVNS section,
   but technology/ now reuses this exact component (its 'How It Works'
   section) rather than reimplementing a static arrow diagram. #neuro-flow
   is the id initNeuroFlow() (js/main.js) keys on -- required on any page
   using this block, or the connector pulse never lights.
   -------------------------------------------------------------------------- */
/* Biochemical Flow Diagram — one route, not three loose boxes.
   The connector sits behind the cards at the icons' vertical centre
   (28px padding + half of the 48px icon = 52px), and since the cards are
   opaque it is only ever visible in the gaps between them. */
.neuro-flow-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-6);
  margin-top: var(--space-9);
  position: relative;
}

.neuro-flow-connector {
  position: absolute;
  top: 52px;
  left: 0;
  right: 0;
  height: 2px;
  background: var(--veil-2);
  z-index: 0;
  pointer-events: none;
}

.neuro-flow-fill {
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg, var(--accent-cyan) 0%, var(--accent-cyan-hi) 100%);
  box-shadow: 0 0 10px rgba(0, 210, 255, 0.55);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 1.6s var(--ease-apple);
}

.neuro-flow-grid.is-flowing .neuro-flow-fill {
  transform: scaleX(1);
}

/* Each icon lights as the pulse reaches it. */
.neuro-card-icon {
  transition:
    background 0.5s var(--ease-apple),
    box-shadow 0.5s var(--ease-apple),
    color 0.5s var(--ease-apple);
}

.neuro-flow-grid.is-flowing .neuro-card:nth-child(2) .neuro-card-icon {
  transition-delay: 0.25s;
}

.neuro-flow-grid.is-flowing .neuro-card:nth-child(3) .neuro-card-icon {
  transition-delay: 0.85s;
}

.neuro-flow-grid.is-flowing .neuro-card:nth-child(4) .neuro-card-icon {
  transition-delay: 1.45s;
}

/* The lit state. Three separate routes arrive here — the pulse reached this
   icon, motion is off so the pathway is shown complete, or there is no JS to
   run the pulse at all. They cannot be merged into one selector list: a media
   query can't join one, and the no-JS rule is :where()-zeroed so it has to
   stay *below* the base .neuro-card-icon rule to win. Edit all three together:
   here, the prefers-reduced-motion block, and the html:not(.has-js) block. */
.neuro-flow-grid.is-flowing .neuro-card-icon {
  background: rgba(0, 210, 255, 0.22);
  box-shadow: var(--glow-cyan);
  color: var(--accent-cyan-pale);
}

.neuro-card {
  background: var(--bg-surface);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
  padding: var(--space-7);
  position: relative;
  z-index: 1;
  /* opaque, so it masks the connector behind it */
  transition: var(--transition-default);
}

.neuro-card .headline-small {
  margin-bottom: var(--space-2);
}

.neuro-card:hover {
  border-color: var(--border-active);
  transform: translateY(-4px);
  box-shadow: 0 12px 32px rgba(0, 210, 255, 0.12);
}

.neuro-card-icon {
  width: 48px;
  height: 48px;
  border-radius: var(--radius-md);
  background: rgba(0, 210, 255, 0.1);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--accent-cyan);
  margin-bottom: 20px;
}


.footer {
  position: relative;
  background: var(--bg-secondary);
  border-top: 1px solid var(--border-subtle);
  padding: 80px 0 40px 0;
  color: var(--text-secondary);
  font-size: 0.8125rem;
}

/* The mark is the footer's route home -- the header nav deliberately has no
   Home link, so without this the footer had none either. inline-block keeps
   the click target on the mark instead of stretching it across the column. */
.footer-brand {
  display: inline-block;
}

.footer-logo {
  height: 24px;
  width: auto;
  /* The logo ships dark; this flips it to white without a second asset. */
  filter: brightness(0) invert(1);
  margin-bottom: var(--space-4);
}

.footer-blurb {
  max-width: 320px;
  line-height: 1.6;
}

.footer-grid {
  display: grid;
  grid-template-columns: 2fr 1fr 1fr 1fr;
  gap: var(--space-9);
  padding-bottom: 48px;
  border-bottom: 1px solid var(--border-subtle);
}

.footer-col-title {
  font-size: 0.75rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-highlight);
  margin-bottom: 20px;
}

.footer-links {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.footer-link {
  color: var(--text-secondary);
  transition: color 0.2s ease;
}

.footer-link:hover {
  color: var(--text-highlight);
}

.footer-bottom {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding-top: 32px;
  flex-wrap: wrap;
  gap: var(--space-4);
}


@media (max-width: 1024px) {
  .footer-grid {
    grid-template-columns: 1fr 1fr;
  }

  /* Seven nav links plus a brand and a CTA stop fitting well before 768px —
     the 769-1024px band was overflowing with no hamburger to fall back to. */
  .nav-links,
  .nav-cta {
    display: none;
  }

  .menu-toggle {
    display: flex;
  }

  .mobile-nav-overlay {
    display: flex;
  }

  /* Below this the manual's TOC column is a drawer, so the ribbon has to be
     able to open it. Same breakpoint as the hamburger by design: one width
     where every permanent navigation on the page folds into a trigger. */
  .toc-toggle {
    display: inline-flex;
  }
}

@media (max-width: 768px) {
  .section {
    padding: 80px 0;
  }

  .local-nav-items {
    display: none;
  }

  /* Neuro Flow: stacked cards, route runs down the icon column. */
  .neuro-flow-grid {
    grid-template-columns: 1fr;
  }

  /* Stacked cards: the route runs down the icon column instead of across. */
  .neuro-flow-connector {
    top: 52px;
    bottom: 52px;
    left: 52px;
    right: auto;
    width: 2px;
    height: auto;
  }

  .neuro-flow-fill {
    background: linear-gradient(180deg, var(--accent-cyan) 0%, var(--accent-cyan-hi) 100%);
    transform: scaleY(0);
    transform-origin: top center;
  }

  .neuro-flow-grid.is-flowing .neuro-flow-fill {
    transform: scaleY(1);
  }

  .footer-grid {
    grid-template-columns: 1fr;
  }

  .footer-bottom {
    flex-direction: column;
    align-items: flex-start;
  }
}

/* --------------------------------------------------------------------------
   Reduced Motion (generic)
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }

  .reveal {
    opacity: 1;
    transform: none;
  }

  .sky-dawn {
    opacity: 0.85;
  }

  .light-rail {
    display: none;
  }

  /* The neuro pathway is shown complete rather than travelled. */
  .neuro-flow-fill {
    transform: none !important;
  }

  .neuro-card-icon {
    background: rgba(0, 210, 255, 0.22);
    box-shadow: var(--glow-cyan);
    color: var(--accent-cyan-pale);
  }
}

/* Same for the no-JS case: nothing is around to add .is-flowing, so the
   connector must not be left permanently unlit. */
:where(html:not(.has-js)) .neuro-flow-fill {
  transform: none;
}

:where(html:not(.has-js)) .neuro-card-icon {
  background: rgba(0, 210, 255, 0.22);
  box-shadow: var(--glow-cyan);
  color: var(--accent-cyan-pale);
}
