/* ============================================================
   Lunamux landing page — "Lunamux Dark" terminal aesthetic:
   deep navy with a cyan glow and a mint-white lift.
   Pure CSS, no external fonts or assets.

   NOTE: the --green* custom-property names are historical — they
   now hold the Lunamux Dark navy/cyan palette, not green. Names
   kept so every existing usage picks up the new colours untouched.
   ============================================================ */

:root {
  --bg:        #04090f;   /* near-black navy ground (from Lunamux Dark theme) */
  --panel:     #070f1a;   /* surface (from Lunamux Dark theme) */
  --panel-2:   #0b1626;   /* raised surface (from Lunamux Dark theme) */
  --green:     #4dc8f5;   /* primary text — cyan glow */
  --green-hi:  #66d9ff;   /* bright accent — vivid cyan (clearly blue vs. the white headings) */
  --green-dim: #5f7590;   /* secondary / comments */
  --green-dimmer: #24384f;
  --border:    rgba(77, 200, 245, .20);
  --border-hi: rgba(77, 200, 245, .45);
  --glow:      rgba(77, 200, 245, .35);
  --red:       #ff5f57;
  --yellow:    #febc2e;
  --traffic-g: #28c840;
  --blue:      #5fa8ff;
  --mono: ui-monospace, "SF Mono", "JetBrains Mono", "Fira Code", Menlo, Consolas, monospace;

  --maxw: 1120px;
}

* { box-sizing: border-box; }

html { scroll-behavior: smooth; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--green);
  font-family: var(--mono);
  font-size: 15px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

/* faint radial vignette in the page background */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  background:
    radial-gradient(120% 80% at 70% -10%, rgba(77,200,245,.06), transparent 60%),
    radial-gradient(90% 60% at 0% 110%, rgba(77,200,245,.05), transparent 55%);
  pointer-events: none;
  z-index: -1;            /* behind all page content, incl. screenshots */
}

a { color: inherit; text-decoration: none; }
code, em { font-style: normal; color: var(--green-hi); }

/* ---------- decorative CRT scanline overlay ---------- */
/* The standalone .overlay div is no longer painted — see the note below.
   We keep the rule as a no-op so the leftover markup stays harmless. */
.overlay { display: none; }

/* The scanlines are rendered as a pseudo-element of the ACTIVE page rather
   than a viewport-fixed div. Each page forms its own stacking context (via
   its fade-in animation), so painting the scanlines here lets them sit
   ABOVE the page text for the CRT look but BELOW the framed screenshots
   (z-index 3) — otherwise multiply blending bands ugly horizontal lines
   across them, most visible on light-themed shots. The nav (1000),
   progress bar (10000) and lightbox (10001) all stay above this. */
.page.is-active::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  background: repeating-linear-gradient(
    to bottom,
    rgba(0,0,0,0) 0px,
    rgba(0,0,0,0) 2px,
    rgba(0,0,0,.18) 3px,
    rgba(0,0,0,0) 4px
  );
  mix-blend-mode: multiply;
  opacity: .35;
}
/* Over the embedded live demo the scanlines read as a rendering artifact,
   so drop them while the demo page is active (script.js toggles the class). */
body.demo-active .page.is-active::after { content: none; }

/* ---------- scroll progress bar ---------- */
.progress {
  position: fixed;
  top: 0; left: 0;
  height: 2px;
  width: 0%;
  background: linear-gradient(90deg, var(--green-dim), var(--green-hi));
  box-shadow: 0 0 8px var(--glow);
  z-index: 10000;
  transition: width .08s linear;
}

/* ---------- NAV ---------- */
.nav {
  position: sticky;
  top: 0;
  z-index: 1000;
  background: rgba(4, 9, 15, .82);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--border);
}
.nav-inner {
  max-width: var(--maxw);
  margin: 0 auto;
  padding: 10px 20px;
  display: flex;
  align-items: center;
  gap: 18px;
}
.brand {
  display: flex;
  align-items: center;
  gap: 8px;
  font-weight: 600;
  color: var(--green-hi);
  letter-spacing: .5px;
  white-space: nowrap;
}
.brand .dot {
  width: 9px; height: 9px;
  border-radius: 50%;
  background: var(--green-hi);
  box-shadow: 0 0 10px var(--green-hi);
  animation: dotGlow 2.2s ease-in-out infinite;
}
@keyframes dotGlow {
  0%, 100% {
    background: var(--green-dim);
    box-shadow: 0 0 2px rgba(102,217,255,.25);
    opacity: .35;
  }
  50% {
    background: var(--green-hi);
    box-shadow: 0 0 14px var(--green-hi), 0 0 28px rgba(102,217,255,1),
                0 0 46px rgba(102,217,255,.6);
    opacity: 1;
  }
}
.tabs {
  display: flex;
  gap: 4px;
  margin-left: auto;
  flex-wrap: wrap;
}
.tabs a {
  padding: 5px 12px;
  border: 1px solid transparent;
  border-radius: 7px;
  color: var(--green-dim);
  font-size: 13px;
  transition: color .2s, border-color .2s, background .2s;
}
.tabs a:hover { color: var(--green); border-color: var(--border); }
.tabs a.active {
  color: var(--green-hi);
  border-color: var(--border-hi);
  background: rgba(77,200,245,.06);
}
/* ---------- buttons ---------- */
.btn {
  display: inline-block;
  padding: 11px 20px;
  border-radius: 9px;
  font-size: 14px;
  font-weight: 600;
  letter-spacing: .3px;
  border: 1px solid var(--border-hi);
  transition: transform .15s, box-shadow .2s, background .2s, color .2s;
  white-space: nowrap;
}
.btn:hover { transform: translateY(-1px); }
.btn-primary {
  background: var(--green-hi);
  color: #062033;
  box-shadow: 0 0 0 rgba(77,200,245,0);
}
.btn-primary:hover { box-shadow: 0 6px 26px var(--glow); }
.btn-ghost { color: var(--green); background: transparent; }
.btn-ghost:hover { background: rgba(77,200,245,.08); box-shadow: 0 0 18px rgba(77,200,245,.12); }

/* ---------- layout sections ---------- */
section { position: relative; }

/* ---------- page views (single-file router) ---------- */
.page { display: none; }
.page.is-active {
  display: block;
  animation: pageFade .4s cubic-bezier(.2,.7,.2,1) both;
}
@keyframes pageFade {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: none; }
}

/* ---------- HERO ---------- */
.hero {
  max-width: var(--maxw);
  margin: 0 auto;
  padding: 80px 20px 60px;
}
.hero-grid {
  display: grid;
  grid-template-columns: 1fr 1.25fr;
  gap: 48px;
  align-items: center;
}
.kicker {
  color: var(--green-dim);
  font-size: 13px;
  letter-spacing: 1px;
  margin-bottom: 16px;
}
h1 {
  font-size: clamp(34px, 5vw, 56px);
  line-height: 1.08;
  margin: 0 0 20px;
  font-weight: 700;
  letter-spacing: -.5px;
  color: #eaf3fb;
}
.glow {
  color: var(--green-hi);
  text-shadow: 0 0 24px var(--glow), 0 0 4px var(--glow);
}
.lede {
  color: var(--green);
  font-size: 16px;
  max-width: 46ch;
  margin: 0 0 28px;
}
.hero-cta { display: flex; gap: 12px; flex-wrap: wrap; }
.hero-meta {
  margin-top: 22px;
  color: var(--green-dim);
  font-size: 13px;
}

/* ---------- terminal window component ---------- */
.term {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 12px;
  overflow: hidden;
  box-shadow: 0 24px 60px rgba(0,0,0,.55);
}
.term-focused {
  border-color: var(--border-hi);
  box-shadow: 0 0 0 1px var(--border-hi), 0 24px 70px rgba(0,0,0,.6),
              0 0 50px rgba(77,200,245,.12);
}
.term-bar {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 14px;
  background: var(--panel-2);
  border-bottom: 1px solid var(--border);
}
.lights { display: flex; gap: 7px; }
.lights i { width: 11px; height: 11px; border-radius: 50%; display: inline-block; }
.lights .r { background: var(--red); }
.lights .y { background: var(--yellow); }
.lights .g { background: var(--traffic-g); }
.term-title {
  color: var(--green-dim);
  font-size: 12px;
  letter-spacing: 1px;
}
@keyframes blink { 50% { opacity: 0; } }

/* ---------- FEATURES ---------- */
.features {
  max-width: var(--maxw);
  margin: 0 auto;
  padding: 40px 20px 30px;
  display: flex;
  flex-direction: column;
  gap: 96px;
}
.feature {
  display: grid;
  /* shot lives in the wider column so it matches the hero screenshot's size */
  grid-template-columns: 1fr 1.25fr;
  gap: 48px;
  align-items: center;
}
.feature[data-side="right"] { grid-template-columns: 1.25fr 1fr; }
.feature[data-side="right"] .feature-copy { order: 2; }
.feature[data-side="right"] .shot { order: 1; }

/* Labeled divider between feature groups — marks where the experimental
   sections begin. Fading rules on either side of a centered pill. */
.feature-sep {
  display: flex;
  align-items: center;
  gap: 18px;
  /* pull in against the 96px .features gap so the rule reads as a divider
     that belongs with the section below it, not a free-floating row */
  margin: -24px 0;
}
.feature-sep::before,
.feature-sep::after {
  content: "";
  flex: 1;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--border-hi), transparent);
}
.feature-sep-label {
  flex: none;
  font-family: var(--mono, monospace);
  font-size: 12px;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--green-dim);
  white-space: nowrap;
}

/* A screenshot-free feature: one centered column instead of the two-up grid. */
.feature.feature-noshot {
  grid-template-columns: 1fr;
  justify-items: center;
  text-align: center;
  padding: 8px 0;
}
.feature-noshot .feature-copy {
  display: flex;
  flex-direction: column;
  align-items: center;
  /* fixed width so typing never reflows / re-centers the block */
  width: min(640px, 100%);
}
.feature-noshot .feature-index { margin-bottom: 10px; }
.feature-noshot h3 { font-size: clamp(26px, 3.6vw, 38px); }
/* The index and heading stay centered (they're static). The typed text is
   left-aligned inside the fixed-width block so its left edge stays put as
   characters appear — centering each line would make it jitter sideways. */
.feature.feature-noshot p { width: 100%; max-width: none; text-align: left; }
.feature-noshot .kv { width: 100%; text-align: left; margin-top: 6px; }

.feature-index {
  color: var(--green-dimmer);
  font-size: 56px;
  font-weight: 700;
  line-height: 1;
  margin-bottom: 4px;
}
.feature h3 {
  font-size: clamp(24px, 3vw, 32px);
  margin: 0 0 14px;
  color: #eaf3fb;
  letter-spacing: -.3px;
}

/* "experimental" badge */
.badge-exp {
  display: inline-block;
  vertical-align: middle;
  margin-left: 10px;
  padding: 3px 9px;
  border: 1px solid var(--yellow);
  border-radius: 999px;
  color: var(--yellow);
  background: rgba(254, 188, 46, .08);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .8px;
  text-transform: uppercase;
  white-space: nowrap;
  box-shadow: 0 0 12px rgba(254, 188, 46, .12);
}
/* inline variant used inside list items */
.badge-exp.sm { margin-left: 6px; padding: 1px 7px; font-size: 10px; }
/* version badge next to a download card's platform name */
.badge-ver {
  display: inline-block;
  vertical-align: middle;
  margin-left: 10px;
  padding: 2px 8px;
  border: 1px solid var(--green-dim);
  border-radius: 999px;
  color: var(--green);
  background: rgba(77, 200, 245, .08);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: .5px;
  white-space: nowrap;
}
.feature p {
  color: var(--green);
  max-width: 48ch;
  margin: 0 0 22px;
  min-height: 4.8em;   /* reserve space so typing doesn't reflow the layout */
}
/* blinking caret shown to the right of text while it types in */
.type-caret {
  display: inline-block;
  color: var(--green-hi);
  margin-left: 2px;
  text-shadow: 0 0 8px var(--glow);
  transform: scaleX(1.5);          /* 50% wider block cursor */
  transform-origin: left center;
  animation: blink 1.05s steps(1) infinite;
}
.kv { list-style: none; margin: 0; padding: 0; display: grid; gap: 9px; }
.kv li {
  display: flex;
  align-items: baseline;
  gap: 10px;
  color: var(--green);
  font-size: 14px;
}
.kv li span:first-child:not(.led):not(.tt-ind) {
  flex: none;
  min-width: 64px;
  color: var(--green-hi);
  font-weight: 600;
}
.kv em { color: var(--green-dim); }

/* status LEDs used in feature lists */
.led {
  width: 9px; height: 9px; border-radius: 50%;
  display: inline-block; flex: none;
  transform: translateY(1px);
}
.led-r { background: var(--red);    box-shadow: 0 0 8px var(--red); }
.led-b { background: var(--blue);   box-shadow: 0 0 8px var(--blue); }
.led-g { background: var(--traffic-g); box-shadow: 0 0 8px var(--traffic-g); }
.led-y { background: var(--yellow); box-shadow: 0 0 8px var(--yellow); }

/* agent-state indicators — mirror the real Lunamux app: a rotating
   spinner while an agent is working, a pulsating warning triangle while
   it waits for input (fades opacity 1 → 0.3 → 1 over 2.5s, like the app's
   `fade-warning` keyframes). */
/* reserve the same 64px label column as the key rows so the text after
   the icon aligns with the other feature lists; the icon sits left. */
.tt-ind {
  min-width: 64px; height: 13px; flex: none;
  display: inline-flex; align-items: center; justify-content: flex-start;
  transform: translateY(2px);
}
.tt-working::before {
  content: ""; width: 13px; height: 13px; box-sizing: border-box;
  border-radius: 50%;
  border: 1.5px solid var(--green-dimmer);
  border-top-color: var(--green);
  box-shadow: 0 0 6px rgba(77, 200, 245, .5);
  animation: tt-spin .7s linear infinite;
}
@keyframes tt-spin { to { transform: rotate(360deg); } }
.tt-waiting {
  color: var(--yellow);
  filter: drop-shadow(0 0 4px rgba(254, 188, 46, .6));
  animation: tt-fade-warning 2.5s ease-in-out infinite;
}
.tt-waiting svg { display: block; }
@keyframes tt-fade-warning { 0%, 100% { opacity: 1; } 50% { opacity: .3; } }
@media (prefers-reduced-motion: reduce) {
  .tt-working { animation: none; }
  .tt-waiting { animation: none; opacity: 1; }
}

/* ---------- screenshot placeholder ---------- */
.shot { margin: 0; }
.shot-canvas {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  aspect-ratio: 16 / 10;          /* same box as a real screenshot slot */
  margin: 0;
  border: 1px dashed var(--border-hi);
  border-radius: 14px;
  color: var(--green-dim);
  font-size: 13px;
  letter-spacing: .5px;
  background:
    repeating-linear-gradient(45deg,
      rgba(77,200,245,.03) 0, rgba(77,200,245,.03) 10px,
      transparent 10px, transparent 20px);
}
.shot-glyph { font-size: 22px; color: var(--green-dim); }
/* Real screenshots render frameless (no fake window chrome) and are
   clickable to open full size in the lightbox modal. */
.shot-zoom {
  display: block;
  position: relative;
  z-index: 3;                     /* above the scanline overlay (2) so it doesn't band the shot */
  width: 100%;
  aspect-ratio: 16 / 10;          /* same proportions as the hero screenshot */
  padding: 14px;
  border: 1px solid var(--green-dim);
  border-radius: 14px;
  overflow: hidden;
  background: var(--panel);
  cursor: zoom-in;
  box-shadow: 0 24px 60px rgba(0,0,0,.45), 0 0 24px rgba(77,200,245,.10);
  transition: border-color .18s ease, box-shadow .18s ease;
}
.shot-zoom:hover,
.shot-zoom:focus-visible {
  border-color: var(--green);
  box-shadow: 0 24px 60px rgba(0,0,0,.5), 0 0 30px rgba(77,200,245,.14);
  outline: none;
}
.shot-zoom img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
  border-radius: 6px;
}

/* A thin, wide screenshot (e.g. a status-bar strip) shouldn't float in a
   tall 16/10 box. The short variant drops the fixed ratio so the slot hugs
   the image's natural height, and centers it vertically in the feature row. */
.shot--short { align-self: center; }
.shot-zoom--short {
  aspect-ratio: auto;
  padding: 10px 14px;
}
.shot-zoom--short img {
  height: auto;
  object-fit: fill;
}

/* A candid photo paired with a single bezeled phone beside it. The photo is
   portrait (≈7:8), not 16/10, so it gets its own portrait box instead of the
   default landscape one — otherwise it floats letterboxed with dead side
   margins. Width is vw-driven so its height tracks the phone bezel beside it,
   making the two read as a balanced pair; it may shrink on narrow screens. */
.shot-companion {
  display: flex;
  align-items: flex-end;
  justify-content: center;
  gap: clamp(14px, 2vw, 32px);
}
.shot-companion .shot-zoom {
  flex: 0 1 auto;
  width: clamp(240px, 34vw, 390px);
  height: auto;
  aspect-ratio: 1274 / 1466;   /* match the photo's real proportions */
  min-width: 0;
}
.shot-companion .phone { flex: 0 0 auto; }

/* ---------- phone device frames (devices section) ----------
   Two phone screenshots in CSS-drawn bezels instead of one 16/10 shot.
   Each .phone is a click-to-zoom trigger (data-full) like .shot-zoom. */
.shot-phones { align-self: center; }
.phones {
  display: flex;
  justify-content: center;
  align-items: flex-end;
  gap: clamp(18px, 3vw, 44px);
}
.phone {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  margin: 0;
  padding: 0;
  border: none;
  background: none;
  cursor: zoom-in;
}
.phone-bezel {
  position: relative;
  z-index: 3;                       /* above the scanline overlay (2) */
  display: block;
  width: clamp(142px, 19vw, 210px);
  padding: 9px;
  border-radius: 34px;
  background: linear-gradient(155deg, #1e273300, #161d27) , #0c141d;
  border: 1px solid var(--border-hi);
  box-shadow:
    0 26px 60px rgba(0,0,0,.55),
    0 0 26px rgba(77,200,245,.08),
    inset 0 0 0 2px rgba(0,0,0,.6);
  transition: border-color .18s ease, box-shadow .18s ease, transform .18s ease;
}
.phone-bezel img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 26px;
  background: #000;
}
/* iOS dynamic island — sits in the empty gap at the top of the shot */
.phone--ios .phone-bezel::after {
  content: "";
  position: absolute;
  top: 20px;
  left: 50%;
  transform: translateX(-50%);
  width: 30%;
  height: 19px;
  border-radius: 12px;
  background: #000;
  z-index: 2;
}
/* Android punch-hole camera */
.phone--android .phone-bezel::after {
  content: "";
  position: absolute;
  top: 18px;
  left: 50%;
  transform: translateX(-50%);
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: #000;
  box-shadow: inset 0 0 0 1px rgba(77,200,245,.18);
  z-index: 2;
}
.phone-label {
  font-size: 12px;
  letter-spacing: 1.5px;
  text-transform: uppercase;
  color: var(--green-dim);
  transition: color .18s ease;
}
.phone:hover .phone-bezel,
.phone:focus-visible .phone-bezel {
  border-color: var(--green);
  box-shadow:
    0 30px 70px rgba(0,0,0,.6),
    0 0 34px rgba(77,200,245,.16),
    inset 0 0 0 2px rgba(0,0,0,.6);
  transform: translateY(-4px);
}
.phone:hover .phone-label,
.phone:focus-visible .phone-label { color: var(--green); }
.phone:focus-visible { outline: none; }

/* ---------- lightbox (full-size screenshot modal) ---------- */
.lightbox {
  position: fixed;
  inset: 0;
  z-index: 10001;            /* above the nav (9000) and progress bar (10000) */
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  background: rgba(4, 9, 16, .82);
  backdrop-filter: blur(4px);
  opacity: 0;
  transition: opacity .2s ease;
}
.lightbox[hidden] { display: none; }
.lightbox.open { opacity: 1; }
.lightbox-img {
  /* size to the viewport so the whole screenshot always fits */
  max-width: calc(100vw - 48px);
  max-height: calc(100vh - 48px);
  width: auto;
  height: auto;
  object-fit: contain;
  border: 1px solid var(--border-hi);
  border-radius: 10px;
  box-shadow: 0 30px 90px rgba(0,0,0,.7);
}
.lightbox-close {
  position: fixed;
  top: max(14px, env(safe-area-inset-top));
  right: max(14px, env(safe-area-inset-right));
  z-index: 1;
  width: 44px;
  height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 26px;
  line-height: 1;
  color: var(--green-hi);
  background: var(--panel-2);
  border: 1px solid var(--border-hi);
  border-radius: 50%;
  cursor: pointer;
  transition: background .15s ease, color .15s ease;
}
.lightbox-close:hover,
.lightbox-close:focus-visible {
  background: var(--border-hi);
  color: #062033;
  outline: none;
}

/* ---------- form thank-you modal ---------- */
.modal {
  position: fixed;
  inset: 0;
  z-index: 10001;            /* same layer as the lightbox */
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  background: rgba(4, 9, 16, .82);
  backdrop-filter: blur(4px);
  opacity: 0;
  transition: opacity .2s ease;
}
.modal[hidden] { display: none; }
.modal.open { opacity: 1; }
.modal-card {
  width: min(440px, 100%);
  box-shadow: 0 30px 90px rgba(0,0,0,.7);
  transform: translateY(8px) scale(.98);
  transition: transform .2s ease;
}
.modal.open .modal-card { transform: none; }
.modal-body { position: relative; padding: 30px 28px 28px; text-align: center; }
.modal-title {
  margin: 6px 0 10px;
  color: #eaf3fb;
  font-size: 22px;
  letter-spacing: -.2px;
}
.modal-text {
  margin: 0 auto 22px;
  max-width: 42ch;
  color: var(--green);
  font-size: 14.5px;
  line-height: 1.65;
}
.modal-ok { align-self: center; }
.modal-close {
  position: absolute;
  top: 10px;
  right: 12px;
  width: 30px;
  height: 30px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 20px;
  line-height: 1;
  color: var(--green-dim);
  background: transparent;
  border: none;
  border-radius: 8px;
  cursor: pointer;
  transition: color .15s ease, background .15s ease;
}
.modal-close:hover,
.modal-close:focus-visible {
  color: var(--green-hi);
  background: rgba(77,200,245,.1);
  outline: none;
}

/* ---------- CTA ---------- */
.cta {
  max-width: 760px;
  margin: 60px auto;
  padding: 56px 28px;
  text-align: center;
  border: 1px solid var(--border);
  border-radius: 16px;
  background:
    radial-gradient(120% 120% at 50% 0%, rgba(77,200,245,.07), transparent 60%),
    var(--panel);
}
.cta h2 {
  font-size: clamp(26px, 4vw, 38px);
  margin: 0 0 10px;
  color: #eaf3fb;
}
.cta p { color: var(--green-dim); margin: 0 0 26px; }
.cta .hero-cta { justify-content: center; }

/* ---------- LIVE DEMO PAGE ---------- */
/* The demo page is chromeless: while it's active (script.js toggles
   body.demo-active) the page stops scrolling and the embedded client
   fills everything below the sticky nav. */
body.demo-active {
  display: flex;
  flex-direction: column;
  height: 100vh;
  height: 100dvh;
  overflow: hidden;
}
body.demo-active main { flex: 1; min-height: 0; }
#page-demo.is-active { height: 100%; }
.demo { height: 100%; }
.demo iframe {
  display: block;
  width: 100%;
  height: 100%;
  border: 0;
  background: #fff; /* the client paints its own theme over this */
}

/* ---------- DOWNLOAD PAGE ---------- */
.dl {
  max-width: var(--maxw);
  margin: 0 auto;
  padding: 72px 20px 40px;
}
.dl-head { text-align: center; margin-bottom: 44px; }
.dl-head h1 { color: #eaf3fb; }
.dl-head .lede { margin-left: auto; margin-right: auto; }
.dl-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 24px;
}
.dl-card { display: flex; flex-direction: column; }
/* The mobile cards (iOS, Android) stack in the right column, leaving macOS a
   single-row-height card in the left column (same height as the iOS box). */
.dl-grid .dl-card:not(.term-focused) { grid-column: 2; }
/* The star card fills the empty cell under macOS (left column, second row),
   overriding the rule above that pushes non-focused cards to column 2. */
.dl-grid .dl-card.dl-star { grid-column: 1; grid-row: 2; }
/* The star card holds two CTAs on one row at the card base: Star on GitHub on
   the left, Get in touch pushed to the lower-right via space-between. */
.dl-star-actions {
  margin-top: auto;
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: center;
  gap: 10px;
}
.dl-star .dl-star-actions .btn { margin-top: 0; align-self: center; }
.dl-card .term-bar { flex: none; }
.dl-body {
  padding: 24px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  flex: 1;
}
/* Platform name + version badge on the left, the small "Changelog" text link
   pushed to the far right of the same row. */
.dl-plat-row {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 10px;
}
.dl-plat {
  font-size: 22px;
  color: #eaf3fb;
  font-weight: 700;
  letter-spacing: -.2px;
}
.dl-ver { color: var(--green-dim); font-size: 13px; }
.dl-body p { color: var(--green); margin: 4px 0 0; font-size: 14px; }
/* Card base row: the download/CTA button on the left, the "Version log" link
   pushed to the lower-right corner via space-between. Pinned to the card base
   with margin-top:auto so cards of differing copy length stay aligned. */
.dl-foot {
  margin-top: auto;
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: center;
  gap: 10px;
}
.dl-foot .btn { align-self: center; margin-top: 0; }
/* High-contrast "source" pill beside the download button; space-between in
   .dl-foot pushes it to the far right of the row. Bordered + tinted so it
   reads as meaningful info, not skippable metadata. */
.dl-src {
  color: var(--green);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: .2px;
  white-space: nowrap;
  padding: 5px 11px;
  border: 1px solid var(--border-hi);
  border-radius: 7px;
  background: rgba(77, 200, 245, .06);
}
.dl-src-note { color: var(--green-dim); font-weight: 500; }
.dl-src-arrow { opacity: .7; }
/* Small, borderless "Changelog" text link, pushed to the far right of the
   platform row. */
.dl-vlog {
  margin-left: auto;
  color: var(--green-dim);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: .2px;
  white-space: nowrap;
  padding: 4px 10px;
  border: 1px solid var(--border-hi);
  border-radius: 7px;
  transition: color .2s, border-color .2s, background .2s;
}
.dl-vlog:hover {
  color: var(--green);
  border-color: var(--green-dim);
  background: rgba(77,200,245,.06);
}
.dl-note {
  margin: 36px auto 0;
  max-width: 60ch;
  text-align: center;
  color: var(--green-dim);
  font-size: 13px;
}
.dl-note code { color: var(--green); }
.dl-note a {
  color: var(--green);
  text-decoration: underline;
  text-underline-offset: 2px;
  transition: color .15s;
}
.dl-note a:hover { color: var(--green-hi); }
/* Q&A footer note: the "Reach out!" link should read as part of the sentence,
   not brighter than the surrounding text. */
.dl-note.reveal a { color: inherit; }
.dl-note.reveal a:hover { color: var(--green); }

/* ---------- pages: per-platform version logs ---------- */
/* A single centered terminal card listing releases newest-first. */
.vlog-card { max-width: 640px; margin: 0 auto; }
.vlog-body { gap: 28px; }
.vlog-release { display: flex; flex-direction: column; gap: 10px; }
/* A subtle divider between releases (skipped above the first one). */
.vlog-release + .vlog-release {
  padding-top: 26px;
  border-top: 1px solid rgba(77,200,245,.14);
}
.vlog-rel-head {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 10px;
}
.vlog-ver {
  margin: 0;
  font-size: 18px;
  color: #eaf3fb;
  font-weight: 700;
  letter-spacing: -.2px;
}
.vlog-date {
  color: var(--green-dim);
  font-size: 12px;
  letter-spacing: .04em;
  text-transform: uppercase;
}
.vlog-list {
  margin: 0;
  padding-left: 20px;
  display: flex;
  flex-direction: column;
  gap: 7px;
}
.vlog-list li {
  color: var(--green);
  font-size: 14px;
  line-height: 1.5;
}
.vlog-list li::marker { color: var(--green-dim); }

/* ---------- page: news ---------- */
/* Reuses the version-log terminal card; each item is a .vlog-release with a
   body paragraph and an optional "Learn more" button. */
.news-card { max-width: 640px; }
.news-text {
  margin: 0;
  color: var(--green);
  font-size: 14px;
  line-height: 1.6;
}
.news-actions { margin-top: 2px; }
/* Keep the button hugging its text rather than stretching the card width. */
.news-more { align-self: flex-start; }
.news-status {
  margin: 0;
  color: var(--green-dim);
  font-size: 14px;
}

/* ---------- page: android access form ---------- */
/* A single centered card rather than the download grid. */
.form-card { max-width: 520px; margin: 0 auto; }
.form-body { gap: 18px; }
.form-field { display: flex; flex-direction: column; gap: 7px; }
.form-label {
  color: var(--green-dim);
  font-size: 12px;
  letter-spacing: .04em;
  text-transform: uppercase;
}
.form-body input,
.form-body textarea {
  width: 100%;
  box-sizing: border-box;
  padding: 11px 13px;
  font: inherit;
  font-size: 14px;
  color: #eaf3fb;
  background: rgba(77,200,245,.04);
  border: 1px solid rgba(77,200,245,.22);
  border-radius: 8px;
  transition: border-color .2s, box-shadow .2s, background .2s;
}
.form-body textarea { resize: vertical; min-height: 110px; }
.form-body input:focus,
.form-body textarea:focus {
  outline: none;
  border-color: var(--green);
  background: rgba(77,200,245,.07);
  box-shadow: 0 0 0 3px rgba(77,200,245,.12);
}
.form-body .btn { align-self: flex-start; margin-top: 4px; }
/* Inline submission error, shown above the fields on a failed POST. Stays
   collapsed until script.js fills it with a message. */
.form-error-summary { font-size: 14px; line-height: 1.5; }
.form-error-summary:not(:empty) {
  padding: 11px 13px;
  border-radius: 8px;
  color: #ffb4b4;
  background: rgba(255,120,120,.07);
  border: 1px solid rgba(255,120,120,.28);
}
.form-back { margin-top: 22px; }
.form-back a { color: var(--green); text-decoration: none; }
.form-back a:hover { text-decoration: underline; }

@media (max-width: 820px) {
  .dl { padding: 44px 18px 28px; }
  .dl-grid { grid-template-columns: 1fr; }
  .dl-grid .dl-card:not(.term-focused) { grid-column: auto; }
}

/* ---------- credits: Framna studio block ---------- */
/* Logo + blurb that closes the credits page. */
.framna-block {
  text-align: center;
  margin: 28px auto 0;
}
.framna-logo {
  display: flex;
  justify-content: center;
  margin: 4px auto 14px;
  color: var(--green-hi);
  transition: opacity .2s;
}
.framna-logo:hover { opacity: .82; }
.framna-wordmark {
  width: min(340px, 72%);
  height: auto;
  color: inherit;
  filter: drop-shadow(0 0 22px rgba(77,200,245,.18));
}
/* The Framna mark on its own, used as the Framna nav item. The link is sized
   to the icon, which matches the height of the neighbouring tab labels. */
.nav-link--icon {
  display: inline-flex;
  align-items: center;
}
.nav-link--icon .framna-symbol {
  display: block;
  height: 15px;
  width: auto;
  color: inherit;
}
.framna-body {
  max-width: 60ch;
  margin: 0 auto;
  color: var(--green-dim);
  font-size: 15px;
  line-height: 1.7;
}
/* Links in the blurb (e.g. Framna cases) keep the surrounding text color so
   they don't stand out — only the underline signals they're links. */
.framna-body a {
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 2px;
  transition: color .15s;
}
.framna-body a:hover { color: var(--green-hi); }
/* The three call-to-action points beneath the blurb, as a card grid that
   borrows the bordered-panel look used by the screenshot frames elsewhere. */
.framna-points {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 16px;
  max-width: 760px;
  margin: 26px auto 0;
}
.framna-card {
  display: flex;
  flex-direction: column;
  padding: 18px 20px 20px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 12px;
  text-align: left;
  color: var(--green-dim);
  text-decoration: none;
  transition: border-color .2s, box-shadow .2s, transform .2s;
}
.framna-card:hover {
  border-color: var(--border-hi);
  box-shadow: 0 0 0 1px var(--border-hi), 0 18px 50px rgba(0,0,0,.5);
  transform: translateY(-2px);
}
.framna-card-label {
  font-size: 11px;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--green-hi);
  opacity: .85;
}
.framna-card-body {
  margin-top: 12px;
  font-size: 14px;
  line-height: 1.6;
  color: var(--green-dim);
}
/* Pin the link/CTA to the bottom so cards of uneven copy stay aligned. */
.framna-card-link {
  margin-top: auto;
  padding-top: 16px;
  font-size: 14px;
  color: var(--green);
}
.framna-card:hover .framna-card-link { color: var(--green-hi); }
.framna-card-arrow {
  display: inline-block;
  transition: transform .2s;
}
.framna-card:hover .framna-card-arrow { transform: translateX(3px); }

@media (max-width: 680px) {
  .framna-points {
    grid-template-columns: 1fr;
    max-width: 60ch;
    gap: 12px;
  }
}
.framna-disclaimer {
  max-width: 60ch;
  margin: 18px auto 0;
  padding-top: 18px;
  color: var(--green);
  opacity: .85;
  font-size: 11px;
  line-height: 1.6;
}

/* ---------- page: q&a (expandable tree) ---------- */
/* The whole tree is indented so even the top-level headlines hang off one
   shared trunk (drawn per-node below) rather than being split into separate
   bordered sections. */
.qa-tree {
  max-width: 760px;
  margin: 0 auto;
  position: relative;
  padding-left: 26px;
}
/* Each node is a native <details>; nesting <details> builds the tree. */
.qa-q {
  list-style: none;
  cursor: pointer;
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 14px 4px;
  color: #eaf3fb;
  font-size: 15.5px;
  transition: color .15s;
}
.qa-q::-webkit-details-marker { display: none; }   /* hide the default triangle */
.qa-q:hover { color: var(--green-hi); }
/* The twisty is styled as a small bordered "chip" so it clearly reads as an
   expand control rather than a stray glyph. It brightens on hover and rotates
   from ▸ to ▾ when the node is open. */
.qa-tw {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  margin-top: 2px;
  border: 1px solid var(--border-hi);
  border-radius: 5px;
  color: var(--green);
  font-size: 9px;
  line-height: 1;
  transition: transform .18s ease, color .15s, background .15s, border-color .15s;
}
.qa-q:hover .qa-tw {
  color: var(--green-hi);
  border-color: var(--green);
  background: rgba(77, 200, 245, 0.10);
}
.qa-node[open] > .qa-q .qa-tw { transform: rotate(90deg); }
.qa-children .qa-q { font-size: 14.5px; }
.qa-a {
  max-width: 64ch;
  padding: 0 4px 16px 26px;
  color: var(--green-dim);
  font-size: 14.5px;
  line-height: 1.7;
}
.qa-a a { color: var(--green); border-bottom: 1px solid var(--border-hi); }
.qa-a a:hover { color: var(--green-hi); }
.qa-a code { color: var(--green); }
/* Inline toolbar-button glyph: the actual app icon rendered as a small phosphor
   chip so the prose matches what the user sees in the toolbar. */
.qa-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  vertical-align: -0.25em;
  margin: 0 0.15em;
  color: var(--green-hi);
}
.qa-icon svg { height: 16px; width: auto; display: block; }
/* Keyboard shortcut rendering: small phosphor key caps grouped with thin "+"
   separators. <kbd> is the cap; .kbd-combo wraps the whole chord. */
.kbd-combo {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  vertical-align: baseline;
}
.kbd-combo kbd {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 1.7em;
  height: 1.7em;
  padding: 0 0.5em;
  border: 1px solid var(--border-hi);
  border-bottom-width: 2px;
  border-radius: 6px;
  background: rgba(77, 200, 245, 0.07);
  box-shadow: inset 0 1px 0 rgba(102, 217, 255, 0.12);
  color: var(--green-hi);
  font: 600 13px/1 var(--mono, ui-monospace, SFMono-Regular, Menlo, monospace);
  font-style: normal;
}
.kbd-combo kbd.kbd-wide { min-width: auto; }
/* List of keyboard shortcuts: each row pairs a chord with its description. */
.kbd-list {
  list-style: none;
  margin: 10px 0 2px;
  padding: 0;
}
.kbd-list li {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin: 0 0 10px;
  line-height: 1.7;
}
/* A pull-quote rendering for first-person answers: a big phosphor opening
   quote mark, gently emphasised text, and an attribution footer. */
.qa-quote {
  position: relative;
  margin: 10px 0 2px;
  padding: 14px 18px 16px 52px;
  border: 1px solid var(--border-hi);
  border-radius: 10px;
  background: rgba(77, 200, 245, 0.045);
  color: var(--green);
  font-style: italic;
}
/* The oversized leading curly quote, tucked into the top-left padding gutter. */
.qa-quote::before {
  content: "\201C";
  position: absolute;
  top: 0.06em;
  left: 12px;
  font-style: normal;
  font-size: 56px;
  line-height: 1;
  color: var(--green-hi);
  opacity: 0.5;
}
.qa-quote p { margin: 0 0 0.9em; }
.qa-quote p:last-of-type { margin-bottom: 0; }
.qa-quote-by {
  margin-top: 1em;
  font-style: normal;
  color: var(--green-dim);
  font-size: 13.5px;
  letter-spacing: 0.02em;
}
.qa-quote-by::before { content: "— "; }
/* A nested sub-tree indents under its parent and links each child to the trunk
   with a rounded elbow connector, so the rows read as one connected tree rather
   than a stack of loose vertical lines. Each child draws its own connector:
   `::before` is the elbow (vertical down from above + a curved turn into the
   row's ▸ marker); `::after` continues the trunk down to the next sibling and is
   dropped on the last child so the line stops cleanly instead of dangling. */
.qa-children {
  position: relative;
  margin-left: 9px;
  padding-left: 26px;
}
.qa-tree > .qa-node,
.qa-children > .qa-node {
  position: relative;
}
.qa-tree > .qa-node::before,
.qa-children > .qa-node::before {
  content: "";
  position: absolute;
  left: -26px;
  top: 0;
  width: 18px;
  height: 25px;
  border-left: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
  border-bottom-left-radius: 7px;
}
.qa-tree > .qa-node::after,
.qa-children > .qa-node::after {
  content: "";
  position: absolute;
  left: -26px;
  top: 25px;
  bottom: 0;
  width: 1px;
  background: var(--border);
}
.qa-tree > .qa-node:last-child::after,
.qa-children > .qa-node:last-child::after { display: none; }
/* The first node has nothing above it to connect to, so it must not draw the
   upward trunk segment (which would dangle off the top). Instead it starts the
   trunk AT its own elbow, turning down into the siblings below with a rounded
   top-left corner (┌) rather than the from-above corner (└) used by the rest. */
.qa-tree > .qa-node:first-child::before,
.qa-children > .qa-node:first-child::before {
  top: 25px;
  height: 9px;
  border-bottom: none;
  border-top: 1px solid var(--border);
  border-bottom-left-radius: 0;
  border-top-left-radius: 7px;
}
/* A lone first-and-only child needs no vertical trunk at all — just the elbow. */
.qa-tree > .qa-node:first-child:last-child::before,
.qa-children > .qa-node:first-child:last-child::before {
  height: 0;
  border-left: none;
  border-top-left-radius: 0;
}

/* ---------- page: credits ---------- */
.credits-grid {
  max-width: var(--maxw);
  margin: 0 auto;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 24px;
}
/* Credits layout: "Made by" and "Inspired by" stack in the left column;
   "Built with" fills the right column across both rows. The spanning box
   stretches the left rows so the stacked pair matches its height. */
.credits-page .credit-group:nth-child(1) { grid-column: 1; grid-row: 1; }   /* Made by */
.credits-page .credit-group:nth-child(2) { grid-column: 1; grid-row: 2; }   /* Inspired by */
.credits-page .credit-group:nth-child(3) { grid-column: 2; grid-row: 1 / span 2; } /* Built with */
/* Contributors page: a single full-width box. */
.contributors-page .credits-grid { grid-template-columns: 1fr; }
.credit-group {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 22px 24px;
  display: flex;
  flex-direction: column;
}
.credit-title {
  margin: 0 0 14px;
  color: var(--green-dim);
  font-size: 12px;
  letter-spacing: 1px;
  text-transform: uppercase;
}
.credit-blurb {
  margin: -6px 0 14px;
  color: var(--green-dim);
  font-size: 13px;
  line-height: 1.5;
}
/* Sub-heading for a section nested inside a credit box (e.g. "Feedback"). */
.credit-subtitle {
  margin: 22px 0 14px;
  color: var(--green-dim);
  font-size: 12px;
  letter-spacing: 1px;
  text-transform: uppercase;
}
.credit-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.credit-item { display: flex; flex-direction: column; gap: 2px; }
/* Name paired with a chip tagging how the person helped. */
.credit-line { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.credit-chip {
  color: var(--green-dim);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: .5px;
  text-transform: uppercase;
  padding: 2px 8px;
  border: 1px solid var(--border);
  border-radius: 999px;
}
.credit-name, .credit-link { color: #eaf3fb; font-size: 15px; font-weight: 600; }
.credit-link {
  align-self: flex-start;
  border-bottom: 1px solid var(--border-hi);
  transition: color .15s, border-color .15s;
}
.credit-link:hover { color: var(--green-hi); border-color: var(--green-hi); }
.credit-role { color: var(--green-dim); font-size: 13px; }
/* CTA button anchored to the box's lower-left; margin-top:auto pushes it to the
   bottom of the (stretched) credit-group box. */
.credit-actions {
  margin-top: auto;
  padding-top: 18px;
  /* Full width so item buttons stay on the left while a trailing group
     button (e.g. "Contributors") is pushed to the box's far right. */
  align-self: stretch;
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 12px;
}
.credit-actions .btn { margin-top: 0; }
@media (max-width: 820px) {
  .credits-grid { grid-template-columns: 1fr; }
  .credits-page .credit-group:nth-child(1),
  .credits-page .credit-group:nth-child(2),
  .credits-page .credit-group:nth-child(3) { grid-column: auto; grid-row: auto; }
}

/* ---------- FOOTER ---------- */
.footer {
  border-top: 1px solid var(--border);
  background: var(--panel-2);
  padding: 22px 20px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px;
  max-width: var(--maxw);
  margin: 0 auto;
}
.prompt { color: var(--green); font-size: 13px; }
.prompt .path { color: var(--green-dim); }
.cursor { color: var(--green-hi); animation: blink 1.05s steps(1) infinite; }
.footer-meta { color: var(--green); font-size: 12px; }

/* ---------- reveal animation ---------- */
.reveal {
  opacity: 0;
  transform: translateY(28px);
  transition: opacity .7s ease, transform .7s cubic-bezier(.2,.7,.2,1);
}
.feature[data-side="left"].reveal  { transform: translateX(-40px); }
.feature[data-side="right"].reveal { transform: translateX(40px); }
/* the centered, screenshot-free section rises straight up instead */
.feature.feature-noshot.reveal { transform: translateY(28px); }
.reveal.visible { opacity: 1; transform: none; }
/* The side selectors above are more specific (0,3,0) than `.reveal.visible`
   (0,2,0), so without this the revealed end-state never clears their transform:
   the feature stays offset AND its lingering transform forms a stacking context
   that traps the shot's z-index:3 below the scanline overlay (z-index 2), banding
   light screenshots. Match their specificity so `visible` actually wins. */
.feature[data-side="left"].reveal.visible,
.feature[data-side="right"].reveal.visible { transform: none; }

/* ---------- responsive ---------- */
@media (max-width: 820px) {
  .hero { padding: 48px 18px 36px; }
  .hero-grid { grid-template-columns: 1fr; gap: 36px; }
  .feature,
  .feature[data-side="right"] { grid-template-columns: 1fr; gap: 28px; }
  .feature[data-side="right"] .feature-copy,
  .feature[data-side="right"] .shot { order: initial; }
  .features { gap: 64px; }
  .feature-index { font-size: 44px; }
  .feature[data-side="left"].reveal,
  .feature[data-side="right"].reveal { transform: translateY(28px); }
}

/* ---------- reduced motion: show everything, kill animation ---------- */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .reveal { opacity: 1 !important; transform: none !important; transition: none; }
  .page.is-active { animation: none; }
  .progress { transition: none; }
  .cursor { animation: none; }
  .brand .dot { animation: none; }
  .btn:hover { transform: none; }
}
