/* ─────────────────────────────────────────────────────────────────────────
   HYPER — site design system v2 (the immersive pass).
   The page is a DESCENT: stars sink past you as you scroll, glass surfaces
   float in real 3D and answer the pointer, features are shown as living
   objects instead of paragraphs. Tokens mirror the app's own design tokens.
   Motion is layered but always optional — reduced-motion gets calm stills.
   ───────────────────────────────────────────────────────────────────────── */

:root {
  --void: #050506;
  --abyss: #0a0a0d;
  --surface: #101014;
  --line: rgba(255, 255, 255, 0.07);
  --line-active: rgba(255, 255, 255, 0.13);
  --ink: #ededea;
  --dim: #8b8b92;
  --ghost: #55555c;
  --glow: #c7d9d1;
  --teal-deep: #0e7d74;
  --teal: #1db5a5;
  --teal-bright: #5fe0cf;
  --magenta: #b75ce8;
  --presence: #4ade80;

  --disp: -apple-system, "Helvetica Neue", "Segoe UI", Roboto, sans-serif;
  --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
  --breath: 4s;
  --gutter: clamp(20px, 5vw, 48px);
  --sect: clamp(64px, 10vh, 120px);
}
/* Mobile breathes tighter — the maker's note: too much dead space between
   sections on a phone. The rhythm stays, the gaps shrink. */
@media (max-width: 640px) {
  :root { --sect: clamp(40px, 6.5vh, 64px); }
}

/* tap-highlight: Android paints its own translucent flash over anything
   tappable — FAQ summaries included (maker: "that horrible blue highlight",
   2026-08-31). The site's own hover/focus-visible states do that job. */
* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }
html { scroll-behavior: smooth; color-scheme: dark; background: var(--void); }
html, body { margin: 0; }

body {
  background: var(--void);
  color: var(--ink);
  font-family: var(--disp);
  font-weight: 300;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

::selection { background: rgba(29, 181, 165, 0.35); color: var(--ink); }

#sky { position: fixed; inset: 0; width: 100%; height: 100%; z-index: 0; pointer-events: none; }
main, .top, .foot { position: relative; z-index: 1; }

/* ── GLASS — the one surface recipe, worn by everything that floats ─────── */
.glass {
  position: relative;
  border-radius: 22px;
  background:
    linear-gradient(160deg, rgba(255, 255, 255, 0.055), rgba(255, 255, 255, 0.012) 38%, rgba(255, 255, 255, 0) 60%),
    linear-gradient(rgba(12, 14, 16, 0.62), rgba(8, 9, 11, 0.66));
  -webkit-backdrop-filter: blur(18px) saturate(1.25);
  backdrop-filter: blur(18px) saturate(1.25);
  border: 1px solid rgba(199, 217, 209, 0.14);
  box-shadow:
    0 24px 60px rgba(0, 0, 0, 0.55),
    0 2px 8px rgba(0, 0, 0, 0.4),
    inset 0 1px 0 rgba(255, 255, 255, 0.09);
  transition: box-shadow 0.9s var(--ease-out), border-color 0.9s var(--ease-out);
}
.glass:hover {
  border-color: rgba(95, 224, 207, 0.32);
  box-shadow:
    0 36px 90px rgba(0, 0, 0, 0.62),
    0 0 44px rgba(29, 181, 165, 0.13),
    inset 0 1px 0 rgba(255, 255, 255, 0.12);
}

/* 3D tilt (engine.js drives --rx/--ry/--px/--py per pointer; touch = off).
   The transform and its layer promotion are scoped to the SAME query the
   listeners are (2026-08-31). A touch device never sets --rx/--ry, so all these
   two lines ever gave it was `will-change: transform` — which promotes every
   glass card to its own composited layer and hands the text back rasterised at
   that layer's resolution instead of the screen's. That is the maker's
   "low-res text on mobile", and it was on every glass surface on the page.
   No pointer, no transform, no layer, no soft type. The sheen below is
   untouched: --sheen only ever leaves 0 on a pointer move, and .glass already
   supplies the position:relative the ::after needs, so nothing here is holding
   up a stacking or containing-block assumption. */
@media (hover: hover) and (pointer: fine) {
  .tilt {
    transform:
      perspective(900px)
      rotateX(calc(var(--rx, 0) * 1deg))
      rotateY(calc(var(--ry, 0) * 1deg))
      translateZ(0);
    will-change: transform;
  }
}
.tilt::after {
  /* The sheen — the moonlit-teal glow catching the glass where the pointer
     is, breathing on the app's 4s clock (never a plain white light). */
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: radial-gradient(
    380px circle at calc(var(--px, 50) * 1%) calc(var(--py, 40) * 1%),
    rgba(95, 224, 207, 0.16),
    rgba(29, 181, 165, 0.07) 38%,
    rgba(29, 181, 165, 0) 64%
  );
  opacity: var(--sheen, 0);
  transition: opacity 0.7s var(--ease-out);
  pointer-events: none;
}
@media (prefers-reduced-motion: no-preference) {
  .tilt::after { animation: sheenBreath var(--breath) ease-in-out infinite; }
  @keyframes sheenBreath { 50% { filter: brightness(1.45) saturate(1.15); } }
}

/* ── Top chrome ─────────────────────────────────────────────────────────── */
/* Persistent floating header (maker order): the wordmark + a DOWNLOAD pill ride
   every scroll position, on a glass bed so the void reads through. `main` gains
   matching top padding below; anchored sections gain scroll-margin so a jump
   never hides its target under this bar. --bar-pad drives the bar's vertical
   rhythm per breakpoint; env(safe-area-inset-top) keeps notched phones clear
   (both pages carry viewport-fit=cover so the env() is live). */
.top {
  --bar-pad: 14px;
  position: fixed; top: 0; left: 0; right: 0; z-index: 5;
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  /* The bar can never be wider than the screen it is pinned to, whatever it
     is asked to hold — without this a nowrap child sets the flex line's
     min-content and pushes the pill past the right edge. */
  max-width: 100%;
  padding: calc(var(--bar-pad) + env(safe-area-inset-top, 0px)) var(--gutter) var(--bar-pad);
  background: rgba(5, 5, 6, 0.78);
  -webkit-backdrop-filter: blur(14px) saturate(1.15);
  backdrop-filter: blur(14px) saturate(1.15);
  border-bottom: 1px solid rgba(255, 255, 255, 0.06);
  transition: background 0.7s var(--ease-out), border-color 0.7s var(--ease-out);
}
/* At the very top the bar has nothing to separate from, so it wears no bed at
   all — the wordmark and the pill float over the hero and the bar stops being
   a toolbar. site.js adds `.at-top` only while scrollY is ~0; with no JS the
   opaque state above stands, which is the legible one. The blur stays on in
   both states so the bar never appears or disappears, it only fills. */
.top.at-top { background: rgba(5, 5, 6, 0); border-bottom-color: transparent; }
/* The one bright thing in the chrome — the persistent way in. It never shrinks
   and never wraps; everything else in the bar yields to it. */
.dl-pill {
  flex: 0 0 auto;
  display: inline-flex; align-items: center; justify-content: center;
  padding: 9px 18px;
  border-radius: 999px;
  background: var(--teal);
  color: var(--void);
  text-decoration: none;
  white-space: nowrap;
  /* text-indent cancels the trailing letter-space so the word sits optically
     centred in the pill (the same trick .orb-button uses). */
  font-size: 11px; font-weight: 600; letter-spacing: 0.22em; text-indent: 0.22em;
  transition: box-shadow 0.4s var(--ease-out), transform 0.4s var(--ease-out);
}
.dl-pill:hover, .dl-pill:focus-visible {
  box-shadow: 0 0 22px rgba(29, 181, 165, 0.55);
  transform: translateY(-1px);
}
/* Desktop bar's REAL height is ~65px (14px pads + the pill's 36px flex box);
   the offsets clear it with a hair to spare. */
main { padding-top: calc(72px + env(safe-area-inset-top, 0px)); }
#storeRow, section[id] { scroll-margin-top: calc(84px + env(safe-area-inset-top, 0px)); }
/* The wordmark is the flexible half of the bar: it may shrink, the pill may
   not. min-width:0 is what lets it, since a flex item's automatic minimum is
   its min-content width and this one is a single unbreakable word. */
.wordmark { flex: 0 1 auto; min-width: 0; font-size: 15px; font-weight: 500; letter-spacing: 0.5em; color: var(--ink); }
.wordmark.small { font-size: 12px; color: var(--dim); }
.topnav { display: flex; gap: 26px; }
.topnav a {
  color: var(--ghost); text-decoration: none;
  /* A label is one line or it is not a label: the bar had been letting them
     WRAP as the window narrowed (three lines on "MAKE IT REAL" at ~700px),
     which read as debris rather than an index. They hold their line now, and
     the two rules below give the bar room for them or take it away. */
  white-space: nowrap;
  font-size: 11.5px; letter-spacing: 0.22em; text-transform: uppercase;
  transition: color 0.5s var(--ease-out), text-shadow 0.5s var(--ease-out);
}
.topnav a:hover, .topnav a:focus-visible { color: var(--glow); text-shadow: 0 0 18px rgba(199, 217, 209, 0.6); }
a:focus-visible, button:focus-visible { outline: 1px solid var(--glow); outline-offset: 4px; border-radius: 4px; }
/* One tighter rhythm before the index gives up — the labels keep their line
   on a laptop that isn't full-screen. */
@media (max-width: 980px) {
  .topnav { gap: 18px; }
  .topnav a { font-size: 11px; letter-spacing: 0.15em; }
}
/* Below this the whole index steps aside and the DOWNLOAD pill is the header,
   exactly as it always has been on a phone. Measured, not guessed: six labels
   at the tightened rhythm stop clearing the wordmark and the pill here. */
@media (max-width: 820px) { .topnav { display: none; } }
/* Phones: the nav is gone — wordmark left, DOWNLOAD right. The pill becomes a
   true ≥44px touch target, the bar's own padding tightens so the bed stays
   ~57px tall, and the main / scroll-margin offsets ride the same numbers. */
@media (max-width: 640px) {
  .top { --bar-pad: 6px; }
  .dl-pill { min-height: 44px; padding: 0 18px; }
  main { padding-top: calc(60px + env(safe-area-inset-top, 0px)); }
  #storeRow, section[id] { scroll-margin-top: calc(72px + env(safe-area-inset-top, 0px)); }
}
/* The narrowest phones: the wordmark's wide tracking gives up a step so it can
   never crowd the pill, and the pill tightens to match. Measured at 320px:
   gutter 20 + wordmark 53 + gap 12 + pill 110 + gutter 20 = 215 of 320 — the
   bar keeps ~105px of slack, so nothing in it can be clipped. */
@media (max-width: 400px) {
  .top .wordmark { font-size: 13px; letter-spacing: 0.34em; }
  .dl-pill { padding: 0 15px; letter-spacing: 0.16em; text-indent: 0.16em; }
}

/* ── Hero ───────────────────────────────────────────────────────────────── */
.hero {
  min-height: calc(100svh - 70px);
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  text-align: center;
  padding: 8px var(--gutter) 20px;
  /* THE page's one real horizontal overflow lived here. #halo is deliberately
     210% of .orb-stage (the aura has to bleed past the mark), and #heroLogo's
     bounding box swells to √2 of its width as the spiral turns — together they
     put the document 82px past the viewport at 320, 96px at 375, 110px at 430.
     `body { overflow-x: hidden }` hid the scrollbar but the overflow was still
     real, and iOS Safari does not reliably honour that propagation: the page
     pans right, and because .top is fixed to the layout viewport the DOWNLOAD
     pill slides out of the visible frame — the maker's clipped-pill screenshot.
     Clipping it HERE renders identically (the bleed was already invisible past
     the viewport edge) and makes documentElement.scrollWidth honest.
     `clip` on one axis leaves the other visible — the aura still spills up and
     down as designed — which `hidden` could not do without becoming a scroller. */
  overflow-x: clip;
}
/* The hero's opening line. It used to be a flex row: a live green ember + a
   ticking population count. Both are gone (the app shows no count — presence
   existence gate), so this is one centred sentence and nothing else. The
   `.presence-dot` rule went with it; `--presence` stays because .truth-chip
   still uses it. */
.presence {
  color: var(--dim); font-size: 13.5px; line-height: 1.5;
  margin: 0 0 4px;
  text-align: center; text-wrap: balance;
}

.orb-stage { position: relative; width: min(72vw, 330px); aspect-ratio: 1; margin: 10px 0 26px; }
#halo { position: absolute; inset: -55%; width: 210%; height: 210%; pointer-events: none; }
#heroLogo {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  -webkit-user-select: none; user-select: none;
  filter: drop-shadow(0 0 46px rgba(29, 181, 165, 0.45));
}
.orb-button {
  position: absolute; inset: 0;
  border-radius: 50%;
  border: none; background: transparent;
  color: var(--ink);
  font-family: var(--disp);
  font-size: clamp(23px, 5.6vw, 32px);
  font-weight: 200;
  letter-spacing: 0.42em; text-indent: 0.42em;
  line-height: 1.5;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  cursor: pointer;
  text-shadow: 0 1px 22px rgba(5, 5, 6, 0.95), 0 0 2px rgba(5, 5, 6, 0.9);
  transition: transform 1.2s var(--ease-out), letter-spacing 1.2s var(--ease-out);
}
.orb-button:hover { transform: scale(1.03); letter-spacing: 0.5em; }
.orb-button:active { transform: scale(0.99); }

.hero-line {
  font-size: clamp(30px, 5.6vw, 54px);
  font-weight: 200; line-height: 1.2; letter-spacing: 0.01em;
  margin: 0 0 16px; text-wrap: balance;
}
/* SUPERPOWER wears the site's teal-accent emphasis idiom — luminous, but the
   light-weight type is preserved (never bold). */
.hero-line em {
  font-style: normal;
  color: var(--teal-bright);
  font-weight: 300;
  letter-spacing: 0.03em;
  text-shadow: 0 0 30px rgba(95, 224, 207, 0.42);
}
.hero-sub { max-width: 52ch; color: var(--dim); font-size: clamp(15px, 2.4vw, 18px); margin: 0 0 20px; }
.hero-sub b { color: var(--teal-bright); font-weight: 400; }
.hero-whisper {
  color: var(--glow); font-size: 15px; margin: 0 0 38px;
  text-shadow: 0 0 24px rgba(199, 217, 209, 0.45);
}

.store-row { display: flex; gap: 14px; flex-wrap: wrap; justify-content: center; }
.store-badge {
  display: flex; align-items: center; gap: 12px;
  padding: 12px 22px;
  border-radius: 16px;
  color: var(--ink); text-decoration: none;
}
.store-badge svg { width: 22px; height: 26px; }
.store-badge span { display: flex; flex-direction: column; text-align: left; line-height: 1.25; }
.store-badge small { font-size: 10.5px; color: var(--dim); letter-spacing: 0.07em; }
.store-badge b { font-size: 16px; font-weight: 500; letter-spacing: 0.02em; }

/* ── Statement strips ───────────────────────────────────────────────────── */
.strip { padding: var(--sect) var(--gutter); text-align: center; }
.strip-line { max-width: 60ch; margin: 0 auto 14px; color: var(--dim); font-size: clamp(16px, 2.6vw, 20px); }
.strip-line.strong { color: var(--ink); font-size: clamp(22px, 3.8vw, 32px); font-weight: 200; text-wrap: balance; }
.strip-line em { font-style: normal; color: var(--glow); }

/* The turn: the old world's guilt-chips burn away on a loop, then HYPER's
   line lands. Mocking the enemy is allowed to be fun. */
.guilt-row { display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; margin: 22px 0 30px; }
.guilt-chip {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 9px 18px;
  border-radius: 999px;
  border: 1px solid rgba(176, 122, 122, 0.4);
  background: rgba(176, 122, 122, 0.08);
  color: #b07a7a;
  font-size: 13px;
}
.guilt-chip .flame { font-style: normal; filter: saturate(0.7); }
.guilt-chip .badge-dot {
  width: 9px; height: 9px; border-radius: 50%;
  background: #d9534f;
  box-shadow: 0 0 10px rgba(217, 83, 79, 0.8);
}
@media (prefers-reduced-motion: no-preference) {
  .guilt-chip { animation: guiltBurn 7s var(--ease-out) infinite; }
  .guilt-chip:nth-child(2) { animation-delay: 0.35s; }
  .guilt-chip:nth-child(3) { animation-delay: 0.7s; }
  @keyframes guiltBurn {
    0%   { opacity: 0; transform: translateY(10px); filter: blur(0); }
    6%   { opacity: 1; transform: none; }
    74%  { opacity: 1; transform: none; filter: blur(0); }
    77%  { transform: translateX(-2px) rotate(-0.6deg); }
    80%  { transform: translateX(2px) rotate(0.6deg); }
    92%  { opacity: 0; transform: translateY(-26px) scale(0.92); filter: blur(6px); }
    100% { opacity: 0; transform: translateY(-26px); filter: blur(6px); }
  }
}

/* What HYPER pushes instead — steady green truths beneath the answer. The red
   chips churn and burn; these stand still and breathe. That IS the contrast. */
.truth-row { display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; margin-top: 26px; }
.truth-chip {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 9px 18px;
  border-radius: 999px;
  border: 1px solid rgba(74, 222, 128, 0.45);
  background: rgba(74, 222, 128, 0.07);
  color: #7de8a5;
  font-size: 13px;
  box-shadow: 0 0 18px rgba(74, 222, 128, 0.12);
}
.truth-chip::before {
  content: "";
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--presence);
  box-shadow: 0 0 10px rgba(74, 222, 128, 0.9);
}
@media (prefers-reduced-motion: no-preference) {
  .truth-chip { animation: truthBreath var(--breath) ease-in-out infinite; }
  .truth-chip:nth-child(2) { animation-delay: 1.3s; }
  .truth-chip:nth-child(3) { animation-delay: 2.6s; }
  @keyframes truthBreath { 50% { box-shadow: 0 0 26px rgba(74, 222, 128, 0.28); border-color: rgba(74, 222, 128, 0.7); } }
}

/* ── Shared bits ────────────────────────────────────────────────────────── */
.eyebrow {
  font-size: 12px; font-weight: 500; letter-spacing: 0.34em; text-transform: uppercase;
  color: var(--glow); text-align: center; margin: 0 0 20px;
}
.big-line {
  font-size: clamp(26px, 4.6vw, 42px);
  font-weight: 200; line-height: 1.25; text-align: center;
  margin: 0 auto 16px; max-width: 24ch; text-wrap: balance;
}
.big-line em { font-style: normal; color: var(--teal-bright); text-shadow: 0 0 30px rgba(95, 224, 207, 0.4); }

/* ── The ritual ─────────────────────────────────────────────────────────── */
.ritual { padding: var(--sect) var(--gutter); }
.ritual-steps {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 22px;
  max-width: 1080px; margin: 40px auto 0;
  perspective: 1200px;
}
@media (max-width: 860px) { .ritual-steps { grid-template-columns: 1fr; max-width: 520px; } }
.step { padding: 34px 30px; text-align: center; }
.step h3 { font-size: 20px; font-weight: 300; letter-spacing: 0.04em; margin: 22px 0 10px; }
.step p { color: var(--dim); font-size: 15px; margin: 0; text-align: left; }
.step p em { font-style: normal; color: var(--glow); }

/* Glyphs sit centred on their card — small altars, not bullet icons. */
.step-glyph { width: 54px; height: 54px; position: relative; margin: 0 auto; }
.step-glyph::before, .step-glyph::after { content: ""; position: absolute; border-radius: 50%; }
.glyph-threshold::before { inset: 6px; border: 1px solid rgba(199, 217, 209, 0.55); }
.glyph-threshold::after { inset: 18px; background: radial-gradient(circle, rgba(199, 217, 209, 0.9), rgba(199, 217, 209, 0) 70%); }
.glyph-hyper::before {
  inset: 12px;
  background: radial-gradient(circle at 42% 38%, #5fe0cf, #0e7d74 72%);
  box-shadow: 0 0 34px rgba(29, 181, 165, 0.55);
}
.glyph-echo::before { inset: 6px 26px 26px 6px; background: radial-gradient(circle, rgba(199, 217, 209, 0.85), rgba(199, 217, 209, 0) 70%); }
.glyph-echo::after { inset: 24px 8px 8px 24px; background: radial-gradient(circle, rgba(95, 224, 207, 0.5), rgba(95, 224, 207, 0) 70%); }
@media (prefers-reduced-motion: no-preference) {
  .glyph-threshold::before { animation: ringBreath var(--breath) ease-in-out infinite; }
  .glyph-hyper::before { animation: orbBreath var(--breath) ease-in-out infinite; }
  /* The Echo: a word spoken, and its softer answer — they trade places. */
  .glyph-echo::before { animation: echoCall 5.2s var(--ease-out) infinite; }
  .glyph-echo::after { animation: echoAnswer 5.2s var(--ease-out) infinite; }
  @keyframes ringBreath { 50% { transform: scale(1.14); opacity: 0.7; } }
  @keyframes orbBreath { 50% { transform: scale(1.09); box-shadow: 0 0 48px rgba(29, 181, 165, 0.8); } }
  @keyframes echoCall {
    0%, 100% { transform: none; opacity: 1; }
    50% { transform: translate(7px, 7px) scale(0.72); opacity: 0.3; }
  }
  @keyframes echoAnswer {
    0%, 100% { transform: none; opacity: 0.4; }
    50% { transform: translate(-6px, -6px) scale(1.3); opacity: 1; }
  }
}

/* ── Hyper Mode showcase (the live phone) ───────────────────────────────── */
.showcase {
  display: grid; grid-template-columns: 1.05fr 0.95fr;
  gap: clamp(28px, 6vw, 80px);
  align-items: center;
  max-width: 1080px;
  margin: 0 auto;
  padding: var(--sect) var(--gutter);
}
@media (max-width: 860px) { .showcase { grid-template-columns: 1fr; text-align: center; } }
.showcase .eyebrow { text-align: left; }
.showcase-sub { color: var(--dim); font-size: 16px; max-width: 46ch; }
.ticks { list-style: none; margin: 22px 0 0; padding: 0; }
.ticks li {
  color: var(--dim); font-size: 15px; margin-bottom: 12px; padding-left: 26px; position: relative;
}
.ticks li::before {
  content: ""; position: absolute; left: 0; top: 7px;
  width: 9px; height: 9px; border-radius: 50%;
  background: radial-gradient(circle at 40% 35%, var(--teal-bright), var(--teal-deep));
  box-shadow: 0 0 12px rgba(29, 181, 165, 0.7);
}
.ticks li b { color: var(--ink); font-weight: 400; }
@media (max-width: 860px) {
  .showcase .eyebrow, .showcase .big-line { text-align: center !important; }
  .ticks { display: inline-block; text-align: left; }
}

.phone {
  width: min(78vw, 300px);
  /* The frame's aspect IS the recording's (1080×2132) — matching them means
     object-fit can never crop the app's edge-riding dock out of the shot.
     (The mock UI era used 9/19; the real screen is a touch shorter.) */
  aspect-ratio: 1080 / 2132;
  border-radius: 42px;
  margin: 0 auto;
  overflow: hidden;
  border-color: rgba(255, 255, 255, 0.16);
}
/* The real session recording — the mock canvas + fake UI it replaced came out
   on the maker's word (2026-08-31): the app's own pixels or nothing. */
#phoneDemo { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: block; }

/* ── The Brain ────────────────────────────────────────────────────────────
   The card is READ first, the galaxy plays under it (maker's order,
   2026-08-31) — one order, both breakpoints. The canvas used to be an absolute
   backdrop for the whole section with the glass floating on top of it, which is
   why the phone rule had to shove the card to the section's foot to stop it
   smothering the nodes; neither is needed now that the galaxy owns a box. */
.brain {
  padding: var(--sect) var(--gutter);
  display: flex; flex-direction: column; align-items: center;
}
.brain-copy { text-align: center; max-width: 500px; padding: 44px 38px; }
.brain-copy p:not(.big-line) { color: var(--dim); font-size: 15.5px; margin: 0; }
.brain-copy p em { font-style: normal; color: var(--teal-bright); }

/* The galaxy's own box. Square-or-wider is not a taste call: the constellation
   seeds a CENTRED ring only while its canvas is not portrait — give it a tall
   box and the ring rides high to clear a card that is no longer there, and the
   core stops sitting at the middle of it. */
.brain-galaxy {
  position: relative;
  width: min(100%, 1000px);
  aspect-ratio: 16 / 10;
  margin: clamp(26px, 5vh, 54px) auto 0;
}
#brainCanvas { position: absolute; inset: 0; width: 100%; height: 100%; }
/* The core: the mark itself at the centre of the web, breathing on a slow
   multiple of the app's 4s clock. inset:0 + margin:auto centres it without
   touching `transform`, which the pulse needs for itself. */
.brain-core {
  position: absolute; inset: 0; margin: auto;
  width: 84px; height: 84px;
  z-index: 1;
  pointer-events: none;
  -webkit-user-select: none; user-select: none;
  /* Three glow layers (maker: the pulse must be SEEN): two drop-shadows trace
     the mark's silhouette, and the box-shadow — on the rounded, transparent
     box — paints the soft radial aura behind it that a silhouette shadow
     alone could never give against the constellation's own blooms. */
  border-radius: 50%;
  filter: drop-shadow(0 0 14px rgba(95, 224, 207, 0.9)) drop-shadow(0 0 34px rgba(29, 181, 165, 0.7));
  box-shadow: 0 0 34px 8px rgba(29, 181, 165, 0.4);
}
@media (max-width: 640px) {
  .brain-copy { padding: 30px 24px; }
  .brain-galaxy { aspect-ratio: 1 / 1; }
  .brain-core { width: 62px; height: 62px; }
}
@media (prefers-reduced-motion: no-preference) {
  .brain-core { animation: coreBreath calc(var(--breath) * 1.2) ease-in-out infinite; }
  @keyframes coreBreath {
    50% {
      transform: scale(1.09);
      filter: drop-shadow(0 0 22px rgba(95, 224, 207, 1)) drop-shadow(0 0 64px rgba(29, 181, 165, 0.95));
      box-shadow: 0 0 78px 20px rgba(29, 181, 165, 0.65);
    }
  }
}

/* ── The Vault ──────────────────────────────────────────────────────────── */
.vault { padding: var(--sect) var(--gutter); text-align: center; }
.monument { max-width: 640px; margin: 36px auto 26px; padding: 30px 34px; }
.rule {
  height: 2px; border-radius: 2px;
  background: linear-gradient(90deg, rgba(29,181,165,0), rgba(29,181,165,0.8), rgba(29,181,165,0));
  box-shadow: 0 0 12px rgba(29, 181, 165, 0.45);
}
.monument-row { display: flex; align-items: center; justify-content: space-between; padding: 26px 0; gap: 12px; }
/* min-width:0 lets the three stats shrink past their labels' min-content —
   without it "HOURS IN HYPERFOCUS" sets a floor for the whole row and the
   monument pushes off the screen (it did, by 3px, at 300px wide, and would do
   it again on any phone running enlarged system text). */
.m-side, .m-hero { display: flex; flex-direction: column; align-items: center; gap: 6px; flex: 1; min-width: 0; }
.m-hero { flex: 1.5; }
.m-side b { font-size: clamp(22px, 4vw, 30px); font-weight: 300; color: var(--dim); font-variant-numeric: tabular-nums; }
.m-hero b { font-size: clamp(44px, 8vw, 64px); font-weight: 200; color: var(--ink); line-height: 1; font-variant-numeric: tabular-nums; }
.m-side small, .m-hero small { color: var(--ghost); font-size: 10.5px; letter-spacing: 0.18em; text-transform: uppercase; }
.m-col { width: 1px; align-self: stretch; margin: 8px 0; background: var(--line); }
.vault-sub { max-width: 54ch; margin: 0 auto; color: var(--dim); font-size: 15.5px; }
.vault-sub em { font-style: normal; color: var(--glow); }
/* Narrow phones: the monument gives back side padding and column gap so the
   three stats keep their own line rather than crushing into each other. */
@media (max-width: 380px) {
  .monument { padding: 26px 18px; }
  .monument-row { gap: 6px; padding: 22px 0; }
}

/* ── Fidgets (playable) ─────────────────────────────────────────────────── */
.toys { padding: var(--sect) var(--gutter); text-align: center; }
.toys-sub { color: var(--dim); max-width: 52ch; margin: 0 auto 36px; }
.toys-sub em { font-style: normal; color: var(--glow); }
.toy-grid {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px;
  max-width: 1080px; margin: 0 auto;
}
@media (max-width: 860px) { .toy-grid { grid-template-columns: 1fr; max-width: 460px; } }
.toy { margin: 0; padding: 10px 10px 0; overflow: hidden; }
.toy canvas {
  width: 100%; aspect-ratio: 1 / 0.92;
  display: block;
  border-radius: 14px;
  background: #030304;
  cursor: grab;
  touch-action: none;
}
.toy canvas:active { cursor: grabbing; }
.toy figcaption { color: var(--ghost); font-size: 12.5px; padding: 12px 6px 14px; letter-spacing: 0.04em; }
.toy figcaption b { color: var(--dim); font-weight: 500; letter-spacing: 0.14em; text-transform: uppercase; margin-right: 6px; }
.toys-more { color: var(--ghost); font-size: 14px; max-width: 56ch; margin: 30px auto 0; }
.toys-more b { color: var(--dim); font-weight: 500; }

/* ── The card rails (Fidgets + Dopamine) — snap-carousels on mobile ──────── */
.demo-rail .toy canvas { touch-action: pan-x pan-y; }   /* let a swipe scroll a rail */
@media (max-width: 860px) {
  /* A rail becomes a horizontal, edge-to-edge scroll-snap carousel — one card
     centred at a time, the next peeking, a flick moves between them. The games
     wore this first; the fidgets rail mirrors it exactly (maker's ask). */
  .demo-rail {
    display: flex;
    grid-template-columns: none;
    max-width: none;
    gap: 16px;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch;
    scroll-padding-inline: var(--gutter);
    padding: 4px var(--gutter) 16px;
    margin-inline: calc(var(--gutter) * -1);   /* bleed to the screen edges */
    scrollbar-width: none;
  }
  .demo-rail::-webkit-scrollbar { display: none; }
  .demo-rail .toy {
    flex: 0 0 82%;
    max-width: 380px;
    scroll-snap-align: center;
  }
}

/* ── Make it real ───────────────────────────────────────────────────────── */
.real { padding: var(--sect) var(--gutter); }
.real-sub { text-align: center; color: var(--dim); max-width: 52ch; margin: 0 auto 44px; }
.real-grid {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 22px;
  max-width: 1080px; margin: 0 auto;
  perspective: 1200px;
}
@media (max-width: 860px) { .real-grid { grid-template-columns: 1fr; max-width: 520px; } }
.card { padding: 26px 26px 28px; }
.card h3 {
  font-size: 13px; font-weight: 500; letter-spacing: 0.3em; text-transform: uppercase;
  color: var(--teal-bright); margin: 18px 0 10px;
}
.card p { color: var(--dim); font-size: 15px; margin: 0; }
.card p em { font-style: normal; color: var(--ink); }

.card-visual {
  height: 92px; border-radius: 14px;
  background: linear-gradient(rgba(5,5,6,0.5), rgba(5,5,6,0.72));
  border: 1px solid var(--line);
  position: relative; overflow: hidden;
}
/* The Slip: a written thought drifts to the edge and DOCKS on the glowing
   tick — parked, not lost. (The old lone line read as nothing.) */
.v-slip .slip-tick {
  position: absolute; right: 0; top: 50%;
  width: 4px; height: 34px; transform: translateY(-50%);
  border-radius: 4px 0 0 4px;
  background: var(--glow);
  box-shadow: 0 0 14px rgba(199, 217, 209, 0.8);
}
/* The note holds a real sentence now, not two skeleton bars, so the geometry
   was re-cut around it (2026-08-31). The dock still lands on the tick: left +
   width + travel = 8 + 58 + 0.54×58 = 97.3% of the visual, and the tick's 4px
   sits at the far edge. The narrowest this visual ever gets is ~192px (three
   `.real-grid` columns at an 861px window), which leaves the sentence 91px of
   content box — it needs ~84px at 10.5px, and the line is left free to wrap
   rather than nowrap, so if a system font runs wider than that it breaks to a
   second line inside the note instead of being clipped by it. */
.v-slip .slip-note {
  position: absolute; left: 8%; top: 50%;
  transform: translateY(-50%);
  width: 58%; height: 34px;
  border-radius: 9px;
  background: linear-gradient(165deg, rgba(255,255,255,0.07), rgba(255,255,255,0.02)), rgba(10, 10, 13, 0.9);
  border: 1px solid rgba(199, 217, 209, 0.28);
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.5);
  display: flex; flex-direction: column; justify-content: center;
  padding: 0 10px;
  overflow: hidden;
}
.v-slip .slip-type {
  display: block;
  color: rgba(199, 217, 209, 0.72);
  font-size: 10.5px; font-weight: 300; line-height: 1.3;
  letter-spacing: 0.01em;
  text-align: left;
}
/* The caret rides inline after the last typed character — including onto a
   second line, if the sentence took one — because it is part of the same box. */
.v-slip .slip-type::after {
  content: "";
  display: inline-block;
  width: 1.5px; height: 0.95em;
  margin-left: 1.5px;
  vertical-align: -0.14em;
  background: rgba(199, 217, 209, 0.85);
  box-shadow: 0 0 6px rgba(199, 217, 209, 0.5);
}
@media (prefers-reduced-motion: no-preference) {
  .v-slip .slip-note { animation: slipDock 7.2s var(--ease-out) infinite; }
  .v-slip .slip-tick { animation: tickCatch 7.2s var(--ease-out) infinite; }
  .v-slip .slip-type::after { animation: slipCaret 1.1s steps(1, end) infinite; }
  /* The cycle grew from 5.4s to 7.2s to make room for the writing. The note
     appears, is written IN PLACE (site.js types it on this animation's own
     iteration events), holds a beat with the thought finished, and only then
     carries it to the tick. The typing has to land inside the still stretch:
     0.42s in, 17 characters at 0.12s, done by 2.5s — and nothing moves until
     46% = 3.3s. Retime one and retime the other. */
  @keyframes slipDock {
    0%   { transform: translate(0, -50%); opacity: 0; }
    5%   { transform: translate(0, -50%); opacity: 1; }
    46%  { transform: translate(0, -50%); opacity: 1; } /* written, and held */
    64%  { transform: translate(54%, -50%); opacity: 1; }
    92%  { transform: translate(54%, -50%); opacity: 1; } /* rests docked */
    97%  { opacity: 0; }
    100% { transform: translate(0, -50%); opacity: 0; }
  }
  @keyframes tickCatch {
    0%, 58%, 100% { box-shadow: 0 0 14px rgba(199, 217, 209, 0.8); }
    68% { box-shadow: 0 0 32px rgba(199, 217, 209, 1); }
  }
  @keyframes slipCaret { 50% { opacity: 0; } }
}
/* Embers: three coals that refuse to go out — each its own heat. */
.v-ember { display: flex; align-items: center; justify-content: center; gap: 26%; }
.v-ember span {
  width: 16px; height: 16px; border-radius: 50%;
}
.v-ember span:nth-child(1) {
  background: radial-gradient(circle at 42% 38%, #ffd9a8, #ff8a3d 55%, rgba(255, 138, 61, 0) 78%);
  box-shadow: 0 0 30px rgba(255, 160, 80, 0.85);
}
.v-ember span:nth-child(2) {
  background: radial-gradient(circle at 42% 38%, #d8fbf4, #1db5a5 55%, rgba(29, 181, 165, 0) 78%);
  box-shadow: 0 0 30px rgba(29, 181, 165, 0.85);
}
.v-ember span:nth-child(3) {
  background: radial-gradient(circle at 42% 38%, #ecdcff, #b75ce8 55%, rgba(183, 92, 232, 0) 78%);
  box-shadow: 0 0 30px rgba(183, 92, 232, 0.85);
}
@media (prefers-reduced-motion: no-preference) {
  .v-ember span { animation: emberBreath 3.8s ease-in-out infinite; }
  .v-ember span:nth-child(2) { animation-delay: 1.25s; }
  .v-ember span:nth-child(3) { animation-delay: 2.5s; }
  @keyframes emberBreath { 50% { filter: brightness(1.4); transform: scale(1.18); } }
}
.v-summit canvas { position: absolute; inset: 0; width: 100%; height: 100%; }

/* ── HYPER Deep ─────────────────────────────────────────────────────────── */
.deep { padding: var(--sect) var(--gutter); }
.deep-cols {
  /* Two equal slabs — symmetry is the promise that free isn't second-class. */
  display: grid; grid-template-columns: 1fr 1fr; gap: 22px;
  max-width: 960px; margin: 40px auto 0; align-items: stretch;
  perspective: 1200px;
}
@media (max-width: 780px) { .deep-cols { grid-template-columns: 1fr; max-width: 480px; } }
/* min-width:0 is load-bearing, not defensive. A grid item's automatic minimum
   is its MIN-CONTENT width, so the nowrap store-badge row below was sizing the
   `1fr` track to 331px inside a 280px column at 320px wide — the card hung 26px
   off each edge of the phone. The track may now be told how narrow it really
   is; the rules further down make the contents actually fit it. */
.deep-col { padding: 32px 30px; display: flex; flex-direction: column; min-width: 0; }
.deep-col ul { flex: 1; }
.deep-col.door {
  border-color: rgba(95, 224, 207, 0.34);
  background:
    radial-gradient(130% 90% at 50% -20%, rgba(29, 181, 165, 0.16), rgba(29, 181, 165, 0) 55%),
    linear-gradient(160deg, rgba(255, 255, 255, 0.05), rgba(255, 255, 255, 0.012) 40%),
    linear-gradient(rgba(10, 12, 14, 0.72), rgba(8, 9, 11, 0.76));
}
.free-h, .deep-h {
  font-size: 12px; font-weight: 500; letter-spacing: 0.3em; text-transform: uppercase;
  margin: 0 0 18px; text-align: center;
}
.free-h { color: var(--glow); }
.deep-h { color: var(--teal-bright); }
.deep-col ul { margin: 0; padding: 0 0 0 18px; color: var(--dim); font-size: 15px; }
.deep-col li { margin-bottom: 10px; }
.deep-col li em { font-style: normal; color: var(--ink); }

/* The price pills wear the app's own Vault-pill recipe — teal wash, bright
   teal edge, soft bloom. Choosing a plan should feel like the app's doors.
   THREE DOORS, STACKED — not three columns. The 3-across row was measured and
   abandoned: "yearly · 14 days free" needs ~119px of capsule to hold one line,
   and a third of this card is only that wide in patches (it wrapped to two
   lines at 421–560px and again at 781–950px, which is where the maker caught
   it). Squeezed into a third it also drove the capsule to 99×110px — a circle
   with 17px type in it, the maker's "too big, text too small".
   Stacked, each capsule is a true lozenge: the price reads first at a size the
   shape can carry, the term sits beside it on the same baseline, and the whole
   card width is available to the label so it cannot wrap at any width.
   It is also the shape this page wants — three doors in a row is the SaaS
   pricing table the brand exists to not be.
   CENTRED, not justified (maker's ruling, 2026-08-31): space-between pinned the
   price to one wall and the term to the other with a hole between them, and on
   a phone — where the capsule is nearly the screen — the two read as unrelated
   rather than as one offer. They are one group now, centred in the pill, at
   every width. */
.prices { display: flex; flex-direction: column; gap: 9px; margin: 26px 0 16px; }
.price {
  display: flex; align-items: baseline; justify-content: center; gap: 14px;
  border-radius: 999px;
  padding: 11px 22px;
  background: rgba(29, 181, 165, 0.14);
  border: 1.5px solid rgba(95, 224, 207, 0.75);
  box-shadow: 0 0 22px rgba(29, 181, 165, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.1);
  transition: transform 0.7s var(--ease-out), box-shadow 0.7s var(--ease-out), background 0.7s var(--ease-out);
}
/* Lift only — a scale() on a capsule that now spans the whole card would push
   it wider than the card on hover, and nothing here clips. */
.price:hover {
  transform: translateY(-3px);
  background: rgba(29, 181, 165, 0.22);
  box-shadow: 0 10px 38px rgba(29, 181, 165, 0.45), inset 0 1px 0 rgba(255, 255, 255, 0.14);
}
.price b {
  flex: 0 0 auto;
  font-size: clamp(21px, 4.4vw, 26px); font-weight: 300; line-height: 1.05;
  letter-spacing: 0.005em;
  font-variant-numeric: tabular-nums;
  color: var(--teal-bright);
}
/* The term must read like part of the price, not a footnote (maker,
   2026-08-31) — full glow, medium weight, and a clamp that keeps the longest
   term ("yearly · 14 days free") on one line beside its price at 375px. */
.price small {
  flex: 0 1 auto;
  color: var(--glow);
  font-size: clamp(13px, 3vw, 15px);
  font-weight: 500;
  letter-spacing: 0.04em;
  white-space: nowrap;   /* the term is one line or the capsule is wrong */
}
.price.rec {
  border-color: var(--teal-bright);
  background: rgba(29, 181, 165, 0.24);
}
.price.rec b { color: #eafffb; }
.price.rec small { color: #eafffb; }
@media (prefers-reduced-motion: no-preference) {
  .price.rec { animation: pillBreath var(--breath) ease-in-out infinite; }
  @keyframes pillBreath { 50% { box-shadow: 0 0 40px rgba(29, 181, 165, 0.55), inset 0 1px 0 rgba(255,255,255,0.1); } }
}
/* The narrowest phones: the capsule gives back side padding rather than type
   size — the price stays the hero and the term stays on its line. */
@media (max-width: 420px) {
  .price { padding: 10px 17px; gap: 10px; }
  .price small { font-size: 12.5px; letter-spacing: 0.02em; }
}

/* The download badges live INSIDE the free card — that card IS the download
   (maker-directed). In the free card the list gives up its flex so the CTA
   takes ALL the leftover height and centres the badges within it: equal air
   above and below, never a blank gulf with badges pinned at the foot. */
.deep-col.free ul { flex: 0 0 auto; }
.deep-col.free .deep-cta { flex: 1; align-items: center; }
.deep-cta { display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; margin-top: 22px; }
.deep-cta .store-badge { padding: 14px 22px; }
.deep-cta .store-badge b { font-size: 17px; }
.deep-cta .store-badge svg { width: 24px; height: 28px; }
/* Phones: both badges share ONE line — each flexes to half the row. The
   kicker line ("download on the") wraps scrappily at half-width, so the badge
   slims to icon + store name. */
@media (max-width: 640px) {
  .deep-cta { flex-wrap: nowrap; gap: 10px; }
  .deep-cta .store-badge { flex: 1 1 0; min-width: 0; justify-content: center; padding: 13px 8px; }
  .deep-cta .store-badge b { font-size: 15px; white-space: nowrap; }
  .deep-cta .store-badge small { display: none; }
  .deep-cta .store-badge svg { width: 20px; height: 24px; }
}
/* Narrow phones: the card gives back side padding. That alone buys the badge
   pair enough room from ~340px up (measured: the two nowrap badges need 300px
   of column, and 20px gutters leave 320 at a 360px screen). */
@media (max-width: 420px) {
  .deep-col { padding: 28px 20px; }
}
/* Only the very narrowest — a 320px screen is 20px short even after that, so
   here the badges themselves tighten. Scoped this low on purpose: at 375 and
   390 the pair fits at full size and shrinking it there would be for nothing. */
@media (max-width: 360px) {
  .deep-cta { gap: 8px; }
  .deep-cta .store-badge { gap: 8px; padding: 12px 6px; }
  .deep-cta .store-badge b { font-size: 13.5px; }
  .deep-cta .store-badge svg { width: 18px; height: 22px; }
}

/* ── FAQ ────────────────────────────────────────────────────────────────────
   Native <details>/<summary>, so there is no JS to load, nothing to break with
   scripts off, and Ctrl-F finds text inside a closed answer in Chromium. The
   shared `name` makes the browser itself run the accordion (one open at a
   time); browsers without that support simply let several stand open, which is
   a fine page rather than a broken one. Answers are prose, left-aligned — this
   section is the one place on the site that is read rather than felt. */
.faq { padding: var(--sect) var(--gutter); text-align: center; }
.faq-sub { color: var(--dim); max-width: 52ch; margin: 0 auto 40px; }
.faq-list { max-width: 720px; margin: 0 auto; text-align: left; }
.faq-item { padding: 0 clamp(20px, 3.4vw, 30px); margin-bottom: 14px; }
.faq-item summary {
  /* The default marker is removed on BOTH engines — `list-style` covers modern
     Safari/Chromium, the -webkit pseudo-element covers the older ones. */
  list-style: none;
  cursor: pointer;
  display: flex; align-items: center; justify-content: space-between; gap: 18px;
  padding: 22px 0;
  color: var(--ink);
  font-size: clamp(15.5px, 2.2vw, 17px); font-weight: 300; letter-spacing: 0.01em;
  transition: color 0.5s var(--ease-out);
}
.faq-item summary::-webkit-details-marker { display: none; }
.faq-item summary:hover, .faq-item summary:focus-visible { color: var(--glow); }
/* The chevron: a drawn corner, never a glyph — it points down, then up. */
.faq-item summary::after {
  content: "";
  flex: 0 0 auto;
  width: 9px; height: 9px;
  margin-right: 3px;
  border-right: 1px solid var(--glow);
  border-bottom: 1px solid var(--glow);
  transform: translateY(-3px) rotate(45deg);
  transition: transform 0.6s var(--ease-out);
}
.faq-item[open] summary::after { transform: translateY(2px) rotate(-135deg); }
.faq-answer { padding-bottom: 26px; border-top: 1px solid var(--line); }
.faq-answer p { color: var(--dim); font-size: 15px; margin: 18px 0 0; }
.faq-answer em { font-style: normal; color: var(--glow); }
.faq-answer b { color: var(--ink); font-weight: 400; }
.faq-answer a { color: var(--glow); }
@media (prefers-reduced-motion: no-preference) {
  .faq-item[open] .faq-answer { animation: faqUnfold 0.5s var(--ease-out); }
  @keyframes faqUnfold { from { opacity: 0; transform: translateY(-6px); } }
}

/* ── Close + footer ─────────────────────────────────────────────────────── */
.close { text-align: center; padding: var(--sect) var(--gutter) clamp(90px, 13vh, 150px); }
.close-line { max-width: 34ch; margin: 0 auto 8px; font-size: clamp(20px, 3.4vw, 28px); font-weight: 200; text-wrap: balance; }
/* The planet — real continents from the same Natural Earth mask the app
   decodes, one lazy spin, and no people-lights on it (js/scenes.js explains
   why: the app's own light feed returns an empty set). */
/* Sized against its own column, not the viewport. `min(94vw, …)` was wider
   than .close's content box on a small phone (300.8px inside 280px at 320),
   and `margin: 0 auto` cannot centre an over-wide block — the auto margins
   resolve to zero, so the globe started at the left gutter and hung 0.8px off
   the right edge of the screen. `100%` is the same "as wide as the phone
   allows" intent, expressed in a value that cannot overrun. */
.close-globe { position: relative; width: min(100%, 560px); aspect-ratio: 1; margin: 0 auto; }
#globeCanvas { position: absolute; inset: 0; width: 100%; height: 100%; z-index: 0; }
/* The way in sits AT the planet's core, where the inner glow already was, and
   the globe turns BEHIND it — desktop and phone alike, since .close-globe is
   sized off its own column and the button is a fixed 172px inside it.
   inset:0 + margin:auto is the whole centring: `transform` is spoken for twice
   over on this element (.reveal animates it in, .orb-button:hover scales it),
   so a translate-centred button would be knocked off the core by either. */
.orb-button.ground {
  position: absolute;
  inset: 0;
  margin: auto;
  z-index: 1;
  width: 172px; height: 172px;
  font-size: 16px;
  border: 1px solid rgba(199, 217, 209, 0.3);
  background: radial-gradient(circle at 50% 40%, rgba(29, 181, 165, 0.18), rgba(5, 5, 6, 0) 72%);
  transition: border-color 0.8s var(--ease-out), transform 1.2s var(--ease-out);
}
.orb-button.ground:hover { border-color: rgba(95, 224, 207, 0.65); }
@media (prefers-reduced-motion: no-preference) {
  #heroLogo { animation: spiral 9s linear infinite; }
  @keyframes spiral { to { transform: rotate(360deg); } }
}

.foot { border-top: 1px solid var(--line); text-align: center; padding: 46px var(--gutter) 60px; color: var(--ghost); font-size: 13.5px; }
.foot p { margin: 14px 0 18px; }
.foot nav { display: flex; gap: 14px; justify-content: center; }
.foot a { color: var(--dim); text-decoration: none; }
.foot a:hover { color: var(--glow); }

/* ── Reveals — glass surfaces POP out of the deep ───────────────────────── */
.reveal { opacity: 0; transform: translateY(34px) scale(0.955); }
.reveal.lit {
  opacity: 1; transform: none;
  transition: opacity 1.3s var(--ease-out), transform 1.3s var(--ease-out);
}
.reveal.lit:nth-child(2) { transition-delay: 0.12s; }
.reveal.lit:nth-child(3) { transition-delay: 0.24s; }
@media (prefers-reduced-motion: reduce) {
  .reveal { opacity: 1; transform: none; }
  html { scroll-behavior: auto; }
  .tilt { transform: none !important; }
}

/* ── The Threshold overlay ──────────────────────────────────────────────── */
.threshold {
  position: fixed; inset: 0; z-index: 10;
  background: var(--void);
  display: flex; align-items: center; justify-content: center;
  opacity: 0; pointer-events: none;
  transition: opacity 1.1s var(--ease-out);
}
.threshold.on { opacity: 1; pointer-events: auto; }
.threshold-word {
  position: absolute;
  color: var(--ink);
  font-size: clamp(26px, 5.4vw, 40px);
  font-weight: 200; letter-spacing: 0.14em; text-align: center;
  padding: 0 24px;
  opacity: 0;
  transition: opacity 1.3s var(--ease-out);
  text-shadow: 0 0 30px rgba(199, 217, 209, 0.35);
}
.threshold-word.show { opacity: 1; }
.threshold-ring {
  width: 150px; height: 150px; border-radius: 50%;
  border: 1px solid rgba(199, 217, 209, 0.5);
  box-shadow: 0 0 60px rgba(29, 181, 165, 0.25), inset 0 0 40px rgba(29, 181, 165, 0.12);
}
@media (prefers-reduced-motion: no-preference) {
  .threshold.on .threshold-ring { animation: thresholdBreath var(--breath) ease-in-out infinite; }
  @keyframes thresholdBreath {
    0%, 100% { transform: scale(1); opacity: 0.75; }
    50% { transform: scale(1.22); opacity: 1; }
  }
}
.threshold-out {
  position: absolute; bottom: 8vh;
  background: none; border: none;
  color: var(--ghost);
  font-family: var(--disp); font-size: 12px; letter-spacing: 0.3em; text-transform: uppercase;
  cursor: pointer; padding: 14px 22px;
}
.threshold-out:hover { color: var(--dim); }

/* ── Consent banner — only ever rendered when a marketing pixel id is set
   (see MARKETING_PIXELS in js/site.js). Wears the site's .glass recipe. ─── */
.consent {
  position: fixed;
  left: 50%; bottom: 20px;
  transform: translateX(-50%);
  z-index: 40;
  width: min(92vw, 460px);
  padding: 16px 18px;
  display: flex; flex-direction: column; gap: 12px;
}
.consent p { margin: 0; color: var(--dim); font-size: 13px; line-height: 1.55; }
.consent-row { display: flex; gap: 10px; }
.consent-btn {
  flex: 1;
  padding: 10px 14px;
  border-radius: 12px;
  border: 1px solid rgba(95, 224, 207, 0.4);
  background: rgba(29, 181, 165, 0.12);
  color: var(--ink);
  font-family: var(--disp);
  font-size: 12px; letter-spacing: 0.12em; text-transform: uppercase;
  cursor: pointer;
  transition: border-color 0.5s var(--ease-out), background 0.5s var(--ease-out), color 0.5s var(--ease-out);
}
.consent-btn:hover { border-color: var(--teal-bright); background: rgba(29, 181, 165, 0.2); }
.consent-btn.ghost { border-color: var(--line-active); background: transparent; color: var(--dim); }
.consent-btn.ghost:hover { border-color: rgba(255, 255, 255, 0.24); color: var(--ink); }
