/* ==========================================================================
   Kalvien — landing page stylesheet.

   Split out of the page rather than inlined: this is the project's existing
   convention (index.html + styles.css + app.js), it keeps the stylesheet
   cacheable across visits, and a 2,300-line style block is not something
   anyone should have to scroll past to reach the markup.

   The design is version C — near-black, iridescent, glassy and grained.
   Techniques in use, and why each is here rather than a simpler thing:
     · @property-registered custom props  → animatable conic-gradient borders
     · animation-timeline: view()/scroll() → compositor-threaded, JS-free
                                            scroll linkage
     · 3D perspective + preserve-3d       → the feature deck has real depth
     · SVG feTurbulence/feDisplacementMap → organic dissolve CSS cannot do
     · backdrop-filter glass + grain      → surface material, not flat fills
   Every one is @supports- or JS-gated so nothing is load-bearing.
   ========================================================================== */

/* ==========================================================================
   Kalvien — landing page, version C

   Deliberately not version A (product-dark Aurora) or B (bright Gen-Z blocks).
   This is near-black, iridescent, glassy and grained — cinematic rather than
   playful.

   Techniques in use, and why each one is here rather than a simpler thing:
     · @property-registered custom props  → animatable conic-gradient borders
                                            and typed scroll progress
     · animation-timeline: view()/scroll() → compositor-threaded, JS-free
                                            continuous scroll linkage
     · 3D perspective + preserve-3d       → the feature deck has real depth
     · SVG feTurbulence/feDisplacementMap → organic dissolve CSS cannot do
     · backdrop-filter glass + grain      → surface material, not flat fills
   Every one is @supports- or JS-gated so nothing is load-bearing.
   ========================================================================== */

/* ---------- registered custom properties (Houdini) ---------- */

@property --angle {
  syntax: '<angle>';
  inherits: false;
  initial-value: 0deg;
}
@property --glow {
  syntax: '<percentage>';
  inherits: false;
  initial-value: 0%;
}
@property --p {
  syntax: '<number>';
  inherits: true;
  initial-value: 0;
}

/* ---------- tokens ---------- */

:root {
  /* Near-black with a blue cast, so the accents read as emitted light. */
  --bg:#05070C;
  --bg-2:#080B12;
  --surface:rgba(255,255,255,.038);
  --surface-2:rgba(255,255,255,.06);
  --line:rgba(255,255,255,.10);
  --line-2:rgba(255,255,255,.16);

  --text:#EAF0F7;
  --dim:#8793A6;
  --dim-2:#5C6779;

  /* Iridescent accent. #6FB5FF is the product's own accent, kept as the
     middle stop so the site and the app share an identity. */
  --i1:#22D3EE;
  --i2:#6FB5FF;
  --i3:#A78BFA;
  --i4:#F472B6;
  --iris:linear-gradient(100deg,var(--i1),var(--i2) 38%,var(--i3) 70%,var(--i4));
  --iris-soft:linear-gradient(100deg,rgba(34,211,238,.16),rgba(111,181,255,.16) 38%,rgba(167,139,250,.16) 70%,rgba(244,114,182,.16));

  /* Acid: reserved strictly for "encryption is happening" states. */
  --acid:#D4FF3F;
  --warn:#FF8A6B;

  --r-lg:28px;
  --r-md:18px;
  --r-sm:12px;

  --ease:cubic-bezier(.22,.86,.24,1);
}

*, *::before, *::after { box-sizing:border-box; }
* { margin:0; }

html {
  -webkit-text-size-adjust:100%;
  scroll-behavior:smooth;
  scroll-padding-top:5.5rem;
  background:var(--bg);
}
@media (prefers-reduced-motion:reduce) { html { scroll-behavior:auto; } }

body {
  background:var(--bg);
  color:var(--text);
  font:400 16.5px/1.55 system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;
  -webkit-font-smoothing:antialiased;
  -moz-osx-font-smoothing:grayscale;
  overflow-x:clip;
}

/* Film grain. A tiled SVG turbulence at very low opacity stops large flat
   dark areas from banding on cheap panels, and gives surfaces material. */
body::after {
  content:"";
  position:fixed; inset:0; z-index:200; pointer-events:none;
  opacity:.032; mix-blend-mode:overlay;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='1' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
}

svg { display:block; }
a { color:inherit; }
.svg-defs { position:absolute; width:0; height:0; overflow:hidden; }

.wrap { width:min(1180px, 100% - 2.75rem); margin-inline:auto; }

.sr {
  position:absolute; width:1px; height:1px; padding:0; overflow:hidden;
  clip-path:inset(50%); white-space:nowrap; border:0;
}
.hp { position:absolute; left:-9999px; width:1px; height:1px; overflow:hidden; }

.skip {
  position:absolute; left:-999px; top:0; z-index:300;
  background:var(--text); color:var(--bg);
  padding:.8rem 1.3rem; border-radius:0 0 var(--r-sm) 0; font-weight:600;
  text-decoration:none;
}
.skip:focus { left:0; }

:focus-visible { outline:2px solid var(--i2); outline-offset:3px; border-radius:8px; }

/* ---------- type ---------- */

h1, h2, h3 { font-weight:600; letter-spacing:-.035em; text-wrap:balance; }

h1 {
  font-size:clamp(2.9rem, 7.4vw, 6rem);
  line-height:.98;
  margin-top:1.5rem;
}
h1 .line { display:block; }

h2 {
  font-size:clamp(2.1rem, 5vw, 3.7rem);
  line-height:1.02;
}
h3 { font-size:1.15rem; letter-spacing:-.02em; line-height:1.25; }

.grad {
  background:var(--iris);
  -webkit-background-clip:text; background-clip:text; color:transparent;
}
.grad-warn { color:var(--warn); }

.eyebrow {
  display:inline-flex; align-items:center; gap:.55rem;
  font-size:.75rem; font-weight:600; letter-spacing:.11em;
  text-transform:uppercase; color:var(--dim);
}
.eyebrow .dot {
  width:6px; height:6px; border-radius:50%; background:var(--acid);
  box-shadow:0 0 0 0 rgba(212,255,63,.6);
  animation:pulse 2.6s var(--ease) infinite;
}
@keyframes pulse {
  0%   { box-shadow:0 0 0 0 rgba(212,255,63,.55); }
  70%  { box-shadow:0 0 0 9px rgba(212,255,63,0); }
  100% { box-shadow:0 0 0 0 rgba(212,255,63,0); }
}

.lede {
  font-size:clamp(1.05rem, 1.6vw, 1.22rem);
  line-height:1.6; color:var(--dim); max-width:46ch; margin-top:1.7rem;
  text-wrap:pretty;
}
.section-lede {
  font-size:1.05rem; line-height:1.65; color:var(--dim);
  max-width:56ch; margin-top:1.2rem; text-wrap:pretty;
}
.section-lede em { font-style:normal; color:var(--text); font-weight:600; }
code {
  font:500 .88em/1 ui-monospace,"SF Mono",Menlo,Consolas,monospace;
  color:var(--i2);
}

/* ---------- brand + nav ---------- */

.nav {
  position:fixed; inset:0 0 auto 0; z-index:120;
  display:flex; align-items:center; justify-content:space-between; gap:1rem;
  padding:.85rem clamp(1rem, 3vw, 2rem);
  background:rgba(5,7,12,.62);
  backdrop-filter:blur(18px) saturate(140%);
  -webkit-backdrop-filter:blur(18px) saturate(140%);
  border-bottom:1px solid transparent;
  transition:border-color .3s ease, background .3s ease;
}
.nav.stuck { border-bottom-color:var(--line); background:rgba(5,7,12,.82); }

/* ---------- section nav ---------- */
/* 17 sections is too many to list, so this is the spine of the argument:
   product → proof → trade-offs. The full map stays in the footer. */

.nav-sections {
  display:flex; align-items:center; gap:.15rem;
  min-width:0; overflow-x:auto; overscroll-behavior-x:contain;
  scrollbar-width:none; -ms-overflow-style:none;
  mask-image:linear-gradient(90deg,transparent,#000 14px,#000 calc(100% - 14px),transparent);
}
.nav-sections::-webkit-scrollbar { width:0; height:0; }
.nav-sections a {
  position:relative; flex:none;
  padding:.42rem .68rem; border-radius:999px;
  font-size:.8125rem; font-weight:500; letter-spacing:-.005em;
  color:var(--dim); text-decoration:none; white-space:nowrap;
  transition:color .22s var(--ease), background .22s var(--ease);
}
@media (hover:hover) {
  .nav-sections a:hover { color:var(--text); background:var(--surface-2); }
}
.nav-sections a[aria-current="true"] { color:var(--text); }
.nav-sections a[aria-current="true"]::after {
  content:""; position:absolute; left:.68rem; right:.68rem; bottom:.1rem;
  height:1.5px; border-radius:2px; background:var(--iris);
}
@media (prefers-reduced-motion:no-preference) {
  .nav-sections a::after { animation:navUnderline .3s var(--ease) both; }
}
@keyframes navUnderline { from { transform:scaleX(0); } to { transform:scaleX(1); } }
/* Below this the bar can't hold links and the brand at once. */
@media (max-width:1000px) { .nav-sections { display:none; } }

/* Reading-progress hairline, driven by a scroll timeline where supported. */
.nav::after {
  content:""; position:absolute; left:0; bottom:-1px; height:2px; width:100%;
  background:var(--iris); transform-origin:0 50%; transform:scaleX(0);
}
@supports (animation-timeline: scroll()) {
  @media (prefers-reduced-motion: no-preference) {
    .nav::after {
      animation:progress linear both;
      animation-timeline:scroll(root block);
    }
    @keyframes progress { to { transform:scaleX(1); } }
  }
}

.brand {
  display:flex; align-items:center; gap:.6rem;
  font-weight:600; font-size:1.05rem; letter-spacing:-.025em; text-decoration:none;
}
.brand-mark {
  position:relative; display:grid; place-items:center;
  width:34px; height:34px; border-radius:11px; flex:none;
  background:var(--bg-2); color:var(--bg);
  isolation:isolate;
}
.brand-mark::before {
  content:""; position:absolute; inset:0; border-radius:inherit;
  background:var(--iris); z-index:-1;
}
.brand-mark svg { width:18px; height:18px; }
.brand-mark.sm { width:26px; height:26px; border-radius:9px; }
.brand-mark.sm svg { width:14px; height:14px; }

/* ---------- buttons ---------- */

.btn {
  position:relative; isolation:isolate;
  display:inline-flex; align-items:center; justify-content:center;
  padding:.95rem 1.5rem; border:0; border-radius:999px;
  background:var(--text); color:var(--bg);
  font:600 .97rem/1 system-ui,-apple-system,"Segoe UI",sans-serif;
  letter-spacing:-.01em; white-space:nowrap; cursor:pointer; text-decoration:none;
  transition:transform .18s var(--ease), box-shadow .25s ease, color .2s ease;
}
.btn::before {
  content:""; position:absolute; inset:0; border-radius:inherit; z-index:-1;
  background:var(--iris); opacity:0; transition:opacity .25s ease;
}
.btn[disabled] { opacity:.55; cursor:progress; }
.btn-sm { padding:.62rem 1.05rem; font-size:.875rem; }
@media (hover:hover) {
  .btn:hover {
    transform:translateY(-2px);
    box-shadow:0 14px 34px -14px rgba(111,181,255,.55);
  }
  .btn:hover::before { opacity:1; }
}
.btn:active { transform:translateY(0); }

.btn-ghost {
  background:transparent; color:var(--text);
  box-shadow:inset 0 0 0 1px var(--line-2);
  margin-top:1.9rem;
}
.btn-ghost::before { display:none; }
@media (hover:hover) {
  .btn-ghost:hover { box-shadow:inset 0 0 0 1px var(--i2); color:var(--i2); transform:none; }
}

/* ---------- reveal system (one-shot, JS-driven for universal support) ---------- */

.js .anim { opacity:0; transform:translateY(22px); }
.js .anim.in {
  opacity:1; transform:none;
  transition:opacity .7s var(--ease), transform .85s var(--ease);
}
.js .a1.in { transition-delay:.08s; }
.js .a2.in { transition-delay:.16s; }
.js .a3.in { transition-delay:.24s; }

/* ---------- section headings: per-line rise ----------
   Every h2 on the page is written as two lines with an explicit <br>, so the
   line break is authored, not measured — which makes a masked per-line reveal
   safe to build from the markup. The heading's own fade is switched off so the
   lines carry the motion instead of both firing at once. */

.js .anim.h-split { opacity:1; transform:none; }
.hl {
  display:block;
  /* Clip the rising line without cropping descenders off the resting one. */
  overflow:hidden; padding-bottom:.12em; margin-bottom:-.12em;
}
.hl-i { display:block; transform:translateY(112%); }
.h-split.in .hl-i {
  transform:none;
  transition:transform .95s var(--ease);
}
.h-split.in .hl:nth-child(2) .hl-i { transition-delay:.1s; }
.h-split.in .hl:nth-child(3) .hl-i { transition-delay:.2s; }

@media (prefers-reduced-motion:reduce) {
  .hl { overflow:visible; padding-bottom:0; margin-bottom:0; }
  .hl-i { transform:none !important; }
}
html[data-motion="off"] .hl-i { transform:none !important; }

/* ---------- hero ---------- */

.hero {
  position:relative; isolation:isolate; overflow:clip;
  min-height:100vh; min-height:100svh;
  display:flex; align-items:center;
  padding:7.5rem 0 4rem;
}
.hero-gl, .hero-field {
  position:absolute; inset:0; width:100%; height:100%;
  z-index:-2; display:block;
}
.hero-field { z-index:-1; }
.hero-vignette {
  position:absolute; inset:0; z-index:-1; pointer-events:none;
  background:
    radial-gradient(120% 80% at 50% 42%, transparent 30%, rgba(5,7,12,.72) 72%, var(--bg) 100%),
    linear-gradient(180deg, rgba(5,7,12,.7) 0%, transparent 22%, transparent 68%, var(--bg) 100%);
}
.hero-inner { position:relative; z-index:1; }
/* Guaranteed dark base under the copy column. The shader and the character
   field both animate, so text contrast would otherwise vary frame to frame —
   WCAG 1.4.3 has to hold at the WORST frame of the range, not the best one.
   Extends past the viewport edge so there is no visible seam. */
.hero-inner::before {
  content:""; position:absolute; z-index:-1; pointer-events:none;
  inset:-14% -10% -14% -50vw;
  /* Tuned down from .94/.88: the heavier scrim guaranteed contrast but wiped
     out the plaintext half of the character field, which is the whole point of
     the effect. The headline is large white type and the lede is #B3BECC, both
     still well past 4.5:1 against this base. */
  background:linear-gradient(90deg,
    rgba(5,7,12,.86) 0%, rgba(5,7,12,.76) 46%,
    rgba(5,7,12,.42) 74%, rgba(5,7,12,0) 100%);
}
.hero .lede { color:#B3BECC; }

.motion-toggle {
  position:absolute; right:clamp(1rem,3vw,2rem); bottom:1.5rem; z-index:2;
  display:inline-flex; align-items:center; gap:.5rem;
  padding:.5rem .85rem; border:0; border-radius:999px; cursor:pointer;
  background:rgba(255,255,255,.06); color:var(--dim);
  box-shadow:inset 0 0 0 1px var(--line);
  backdrop-filter:blur(10px); -webkit-backdrop-filter:blur(10px);
  font:600 .75rem/1 system-ui,-apple-system,sans-serif; letter-spacing:.04em;
}
.mt-dot { width:6px; height:6px; border-radius:50%; background:var(--acid); }
.motion-toggle[aria-pressed="true"] .mt-dot { background:var(--dim-2); }
@media (hover:hover) { .motion-toggle:hover { color:var(--text); } }

/* ---------- signup ---------- */

.signup { margin-top:2.5rem; width:min(520px,100%); }
.signup-row {
  display:flex; gap:.5rem; padding:.4rem;
  background:rgba(255,255,255,.05); border-radius:999px;
  box-shadow:inset 0 0 0 1px var(--line);
  backdrop-filter:blur(14px); -webkit-backdrop-filter:blur(14px);
  transition:box-shadow .25s ease;
}
.signup-row:focus-within { box-shadow:inset 0 0 0 1px var(--i2), 0 0 0 4px rgba(111,181,255,.14); }
.signup input[type="email"] {
  flex:1; min-width:0; border:0; background:transparent; color:var(--text);
  font:400 1rem/1 system-ui,-apple-system,sans-serif;
  padding:.9rem .5rem .9rem 1.05rem;
}
.signup input::placeholder { color:var(--dim-2); }
.signup input:focus { outline:none; }
.signup-note {
  margin-top:.95rem; font-size:.8125rem; line-height:1.5; color:var(--dim);
  min-height:2.5em;
}
.signup-note.is-err { color:var(--warn); }
.signup-note.is-ok  { color:var(--acid); }
.count-line { display:block; font-weight:600; color:var(--text); }
.signup-lg { margin-inline:auto; }

/* ==========================================================================
   LIVE PRODUCT · self-playing thread

   Inside the device the tokens switch to the shipped Android app's own dark
   theme rather than this page's palette — the point of the section is that you
   are looking at the real product, so it should not be restyled to match the
   marketing site.
   ========================================================================== */

.live { padding:clamp(5.5rem,12vh,9rem) 0 clamp(4rem,9vh,6rem); }
.live-grid {
  margin-top:3rem;
  display:grid; grid-template-columns:minmax(0,.85fr) minmax(0,1.15fr);
  gap:clamp(2rem,5vw,4.5rem); align-items:start;
}
.live-phone { display:flex; flex-direction:column; align-items:center; gap:1.1rem; }

.dev, .screens, .flow {
  /* Secure Chat's own dark theme, verbatim — the same tokens as .theme-dark in
     the app source, so a screen here and a screen in the build are the same
     pixels. The marketing palette stops at the bezel. */
  --a-bg:#0f0f14; --a-surface:#1b1b22; --a-thread:#131318; --a-raised:#242431;
  --a-line:rgba(255,255,255,.075);
  --a-text:#f4f4f5; --a-dim:#8e8e97;
  /* #6d5ef6 is the brand accent and stays the fill. Small text and icons use
     #8f7dff — #6d5ef6 only reaches 3.9:1 on #0f0f14, which fails 1.4.3. */
  --a-accent:#8f7dff;
  --a-grad:linear-gradient(135deg,#6d5ef6,#9b6dff);
  --a-mine:linear-gradient(135deg,#6d5ef6,#9b6dff);
  --a-mine-line:rgba(155,109,255,.4);
  --a-chip:#2a2740; --a-danger:#fb7185;
  /* Self-host Geist and put it at the front of this stack to match the app
     exactly. Until then the platform font stands in — see the head comment. */
  --a-font:system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;
}
.dev { position:relative; }
.dev-glow {
  position:absolute; inset:6% -22% -4%;
  background:radial-gradient(52% 42% at 50% 55%, rgba(123,102,246,.45) 0%, transparent 72%);
  filter:blur(34px); opacity:.55; z-index:-1;
}
.dev-body {
  width:clamp(260px,25vw,306px);
  aspect-ratio:390 / 844;
  background:#0a0a0c; border-radius:clamp(36px,3.6vw,46px);
  padding:clamp(8px,.8vw,11px);
  box-shadow:0 44px 90px -34px rgba(0,0,0,.9), 0 0 0 1.5px rgba(255,255,255,.09);
  position:relative;
}
.dev-island {
  position:absolute; top:clamp(8px,.8vw,11px); left:50%; transform:translateX(-50%);
  width:27%; height:3.1%; background:#0a0a0c; border-radius:20px; z-index:6;
}
.dev-screen {
  height:100%; background:var(--a-bg); color:var(--a-text);
  border-radius:clamp(29px,2.9vw,36px);
  overflow:hidden; display:flex; flex-direction:column;
  font-family:var(--a-font);
}

.dev-status {
  display:flex; align-items:center; justify-content:space-between;
  padding:clamp(11px,1.1vw,15px) 1.1rem .1rem;
  font-size:.6875rem; font-weight:600; letter-spacing:.01em;
}
.dev-status-r { display:flex; align-items:center; gap:4px; }
.dev-status-r .sig { width:14px; height:9px; border-radius:2px; background:var(--a-text); opacity:.85; }
.dev-status-r .bat { width:20px; height:9px; border-radius:3px; box-shadow:inset 0 0 0 1.2px var(--a-text); opacity:.6; }

.dev-head {
  display:flex; align-items:center; gap:.5rem;
  padding:.55rem .7rem .6rem; border-bottom:1px solid var(--a-line);
}
.dev-back { color:var(--a-dim); }
.dev-back svg { width:15px; height:15px; }
.dev-av {
  width:28px; height:28px; border-radius:10px; flex:none;
  background:var(--a-grad);
  color:#fff; display:grid; place-items:center;
  font-size:.72rem; font-weight:700;
}
.dev-who { display:flex; flex-direction:column; line-height:1.2; min-width:0; }
.dev-who b { font-size:.78rem; font-weight:600; }
.dev-who i {
  font-style:normal; font-size:.5625rem; color:var(--a-accent);
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
}
.dev-verified {
  margin-left:auto; color:var(--a-dim); opacity:.45;
  transition:color .4s ease, opacity .4s ease, transform .4s var(--ease);
}
.dev-verified svg { width:16px; height:16px; }
.dev-verified.on { color:var(--a-accent); opacity:1; transform:scale(1.1); }

/* The scrolling thread. overflow-y is what makes the auto-scroll real. */
.dev-thread {
  flex:1; min-height:0; overflow-y:auto; overscroll-behavior:contain;
  padding:.7rem .6rem 1rem;
  background:var(--a-thread);
  display:flex; flex-direction:column; gap:.4rem;
  scrollbar-width:none;
}
.dev-thread::-webkit-scrollbar { width:0; height:0; }

.m {
  max-width:82%; padding:.45rem .62rem; font-size:.6875rem; line-height:1.42;
  border-radius:20px; position:relative;
  animation:mIn .34s var(--ease) both;
}
@keyframes mIn { from { opacity:0; transform:translateY(9px) scale(.975); } to { opacity:1; transform:none; } }
.m.them {
  align-self:flex-start; background:var(--a-surface); border-bottom-left-radius:7px;
}
.m.mine {
  align-self:flex-end; background:var(--a-mine); color:#fff;
  border-bottom-right-radius:7px;
  box-shadow:0 6px 18px -10px rgba(109,94,246,.9);
}
.m-time {
  display:block; margin-top:.2rem; font-size:.5rem; color:var(--a-dim); opacity:.75;
}
.m.mine .m-time, .m.mine .m-stat, .m.mine .m-edited { color:rgba(255,255,255,.72); }
.m.mine .m-quote { color:rgba(255,255,255,.8); border-left-color:rgba(255,255,255,.7); }
.m-edited { font-size:.5rem; color:var(--a-dim); opacity:.8; margin-left:.25rem; }

/* reply quote */
.m-quote {
  display:block; margin-bottom:.28rem; padding:.24rem .4rem;
  border-left:2px solid var(--a-accent); border-radius:4px;
  background:rgba(255,255,255,.05);
  font-size:.5625rem; color:var(--a-dim);
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
}

/* reaction chip. Class is .rx (never .anim/.pop) so page-wide reveal rules
   can never zero its opacity. */
.rx {
  position:absolute; right:-.25rem; bottom:-.55rem;
  background:var(--a-raised); box-shadow:inset 0 0 0 1px var(--a-line);
  border-radius:999px; padding:.06rem .28rem; font-size:.5625rem; line-height:1.3;
  animation:rxPop .38s cubic-bezier(.34,1.7,.64,1) both;
}
@keyframes rxPop { from { transform:scale(0); } to { transform:scale(1) rotate(-8deg); } }

/* typing indicator */
.m.typing { padding:.5rem .65rem; }
.m.typing span {
  display:inline-block; width:5px; height:5px; margin-right:3px;
  border-radius:50%; background:var(--a-dim);
  animation:dot 1.25s ease-in-out infinite;
}
.m.typing span:nth-child(2) { animation-delay:.16s; }
.m.typing span:nth-child(3) { animation-delay:.32s; margin-right:0; }
@keyframes dot { 0%,60%,100% { opacity:.3; transform:translateY(0); } 30% { opacity:1; transform:translateY(-3px); } }

/* encrypted media */
.m-media {
  width:132px; height:90px; border-radius:16px; overflow:hidden; position:relative;
  background:
    linear-gradient(135deg, rgba(109,94,246,.55), rgba(155,109,255,.45) 55%, rgba(197,107,255,.5)),
    var(--a-raised);
  display:grid; place-items:center;
}
.m-media::after {
  content:""; position:absolute; inset:0;
  background-image:radial-gradient(rgba(255,255,255,.16) 1px, transparent 1px);
  background-size:7px 7px; opacity:.5;
}
.m-media span {
  position:relative; z-index:1; font-size:.5rem; font-weight:600;
  color:#06110E; background:rgba(255,255,255,.82);
  padding:.14rem .38rem; border-radius:999px;
}

/* burn */
.m.burning { animation:mBurn 1.1s ease forwards; }
@keyframes mBurn {
  0%   { opacity:1; }
  60%  { opacity:.6; filter:sepia(.7) saturate(3) hue-rotate(-18deg); }
  100% { opacity:0; transform:translateY(-8px) scale(.95); filter:blur(3px); }
}

/* system notes inside the thread */
.m-sys {
  align-self:center; font-size:.5625rem; font-weight:600; letter-spacing:.03em;
  color:var(--a-dim); background:rgba(255,255,255,.05);
  padding:.24rem .6rem; border-radius:999px;
  animation:mIn .34s var(--ease) both;
}
.m-sys.acid { color:var(--a-accent); background:rgba(143,125,255,.12); }

.dev-composer {
  display:flex; align-items:center; gap:.4rem;
  margin:0 .55rem .8rem; padding:.32rem .32rem .32rem .6rem;
  background:var(--a-surface); border-radius:16px;
  box-shadow:inset 0 0 0 1px var(--a-line);
}
.dev-clip { color:var(--a-dim); }
.dev-clip svg { width:14px; height:14px; }
.dev-input { flex:1; font-size:.625rem; color:var(--a-dim); }
.dev-send {
  width:22px; height:22px; border-radius:50%; flex:none;
  background:var(--a-grad);
  color:#fff; display:grid; place-items:center;
}
.dev-send svg { width:11px; height:11px; }

/* controls */
.live-controls { display:flex; align-items:center; gap:.8rem; }
.live-btn {
  border:0; border-radius:999px; cursor:pointer;
  padding:.5rem 1rem; background:rgba(255,255,255,.06); color:var(--text);
  box-shadow:inset 0 0 0 1px var(--line);
  font:600 .8125rem/1 system-ui,-apple-system,sans-serif;
}
@media (hover:hover) { .live-btn:hover { box-shadow:inset 0 0 0 1px var(--i2); color:var(--i2); } }
.live-hint { font-size:.75rem; color:var(--dim-2); }

/* feature checklist */
.live-list-title {
  font-size:.6875rem; font-weight:700; letter-spacing:.12em;
  text-transform:uppercase; color:var(--dim-2); margin-bottom:1.1rem;
}
.live-list ul { list-style:none; padding:0; margin:0; display:grid; gap:.15rem; }
.live-list li {
  display:grid; grid-template-columns:auto 1fr; gap:.2rem .75rem;
  padding:.7rem .8rem; border-radius:var(--r-sm);
  transition:background .45s ease, box-shadow .45s ease;
}
.live-list li i {
  grid-row:span 2; align-self:start; margin-top:.28rem;
  width:15px; height:15px; border-radius:50%; flex:none;
  box-shadow:inset 0 0 0 1.5px var(--line-2);
  position:relative; transition:box-shadow .4s ease, background .4s ease;
}
.live-list li i::after {
  content:""; position:absolute; inset:3.5px; border-radius:50%;
  background:var(--acid); transform:scale(0);
  transition:transform .4s cubic-bezier(.34,1.7,.64,1);
}
.live-list li b { font-size:.94rem; font-weight:600; }
.live-list li span { font-size:.82rem; color:var(--dim); line-height:1.5; }
.live-list li.done i { box-shadow:inset 0 0 0 1.5px rgba(212,255,63,.55); }
.live-list li.done i::after { transform:scale(1); }
.live-list li.now {
  background:rgba(212,255,63,.055);
  box-shadow:inset 0 0 0 1px rgba(212,255,63,.22);
}
.live-more {
  margin-top:1.2rem; padding-top:1.1rem; border-top:1px solid var(--line);
  font-size:.85rem; line-height:1.6; color:var(--dim-2);
}
.live-list li code { font-size:.86em; }

/* The not-yet list. Deliberately quieter and dot-less: an unfinished thing
   should not be able to pass for a shipped one at a glance. */
.next-title { margin-top:2.25rem; padding-top:1.6rem; border-top:1px solid var(--line); }
.live-next { list-style:none; padding:0; margin:0; display:grid; gap:.15rem; }
.live-next li {
  display:grid; grid-template-columns:auto 1fr; gap:.2rem .75rem;
  padding:.7rem .8rem; border-radius:var(--r-sm);
}
.live-next li i {
  grid-row:span 2; align-self:start; margin-top:.34rem;
  width:15px; height:15px; border-radius:50%; flex:none;
  box-shadow:inset 0 0 0 1.5px rgba(167,139,250,.4);
  background:repeating-linear-gradient(45deg,transparent,transparent 2px,rgba(167,139,250,.22) 2px,rgba(167,139,250,.22) 4px);
}
.live-next li b { font-size:.94rem; font-weight:600; color:var(--dim); }
.live-next li span { font-size:.82rem; color:var(--dim-2); line-height:1.5; }

/* ==========================================================================
   THE INTERCEPTOR
   `--p` (0→1) is driven from JS rather than a scroll timeline: the packet
   position, the wire fill and the readout all need the same progress value in
   sync, and JS gives that on every engine including Firefox.
   ========================================================================== */

.intercept { position:relative; }
.intercept-track { height:260vh; }
.intercept-pin {
  position:sticky; top:0;
  height:100vh; height:100svh;
  display:flex; align-items:center;
}
.intercept-head { text-align:center; margin-bottom:clamp(2rem,5vh,3.5rem); }
.intercept-head h2 { margin-top:1rem; }

.lane {
  display:grid; grid-template-columns:auto 1fr auto;
  align-items:center; gap:clamp(.75rem,2vw,1.75rem);
}

.node { flex:none; }
.node-label {
  margin-top:.7rem; text-align:center;
  font-size:.6875rem; font-weight:600; letter-spacing:.12em;
  text-transform:uppercase; color:var(--dim-2);
}
.mini {
  width:clamp(120px,15vw,176px);
  background:var(--surface); border-radius:var(--r-md);
  box-shadow:inset 0 0 0 1px var(--line);
  backdrop-filter:blur(12px); -webkit-backdrop-filter:blur(12px);
  overflow:hidden;
}
.mini-top {
  display:flex; align-items:center; gap:.45rem;
  padding:.6rem .7rem; border-bottom:1px solid var(--line);
  font-size:.75rem; font-weight:600;
}
.mini-top i {
  width:18px; height:18px; border-radius:50%; flex:none;
  background:var(--iris);
}
.mini-body { padding:.7rem; min-height:74px; display:flex; align-items:flex-start; }
.mini-bub {
  font-size:.6875rem; line-height:1.4; padding:.4rem .55rem;
  border-radius:11px 11px 11px 4px;
  background:rgba(255,255,255,.07); color:var(--text);
}
.mini-bub.in {
  border-radius:11px 11px 4px 11px;
  background:linear-gradient(135deg,rgba(34,211,238,.18),rgba(167,139,250,.18));
  box-shadow:inset 0 0 0 1px rgba(111,181,255,.28);
  opacity:calc((var(--p) - .82) * 6);
}

/* wire.
   container-type here, NOT on .packet: container query units inside .packet
   resolve against its nearest ANCESTOR container. With the container on the
   packet itself, 100cqw fell back to the viewport and threw the packet past
   the right edge (+156px of document overflow at 768px). */
.wire { position:relative; height:120px; container-type:inline-size; }
.wire-svg { position:absolute; inset:0; width:100%; height:100%; overflow:visible; }
.wire-path { fill:none; stroke:var(--line-2); stroke-width:1.5; stroke-dasharray:5 7; }
.wire-live {
  fill:none; stroke:var(--i2); stroke-width:2; stroke-linecap:round;
  filter:drop-shadow(0 0 6px rgba(111,181,255,.7));
  /* pathLength-independent fill driven by the same --p as everything else. */
  stroke-dasharray:1; stroke-dashoffset:1;
  /* vector-effect keeps the dash math stable under non-uniform scaling. */
  vector-effect:non-scaling-stroke;
  transform:scaleX(var(--p)); transform-origin:0 50%;
}

.packet {
  position:absolute; top:50%; left:0;
  /* Travels the wire's width, not the viewport's. */
  transform:translate(calc(var(--p) * (100cqw - 100%)), -50%);
  padding:.45rem .7rem; border-radius:10px;
  background:rgba(5,7,12,.9);
  box-shadow:inset 0 0 0 1px var(--line-2), 0 8px 26px -12px rgba(0,0,0,.9);
  font:600 .6875rem/1 ui-monospace,"SF Mono",Menlo,Consolas,monospace;
  white-space:nowrap;
}
.packet-plain { display:none; color:var(--warn); }
.packet-cipher { color:var(--acid); }
.lane[data-mode="others"] .packet-plain { display:inline; }
.lane[data-mode="others"] .packet-cipher { display:none; }

/* The interceptor sits at the midpoint of the wire. */
.tap {
  position:absolute; left:50%; top:50%;
  transform:translate(-50%,-50%);
  display:grid; place-items:center;
}
.tap-box {
  width:clamp(150px,19vw,220px);
  padding:.7rem .8rem; border-radius:var(--r-sm);
  background:rgba(8,11,18,.92);
  box-shadow:inset 0 0 0 1px var(--line-2);
  text-align:center;
  transition:box-shadow .35s ease, transform .35s var(--ease);
}
.lane[data-mode="others"] .tap-box {
  box-shadow:inset 0 0 0 1px rgba(255,138,107,.5), 0 0 32px -8px rgba(255,138,107,.35);
}
.tap-title {
  display:flex; align-items:center; justify-content:center; gap:.35rem;
  font-size:.625rem; font-weight:700; letter-spacing:.14em;
  text-transform:uppercase; color:var(--dim-2); margin-bottom:.45rem;
}
.tap-title svg { width:13px; height:13px; }
.lane[data-mode="others"] .tap-title { color:var(--warn); }
.tap-read {
  font:600 .8125rem/1.35 ui-monospace,"SF Mono",Menlo,Consolas,monospace;
  color:var(--acid); word-break:break-all; min-height:2.7em;
}
.lane[data-mode="others"] .tap-read { color:var(--warn); }

.mode {
  display:flex; justify-content:center; gap:.4rem;
  margin-top:clamp(1.75rem,4vh,2.75rem);
  padding:.3rem; width:fit-content; margin-inline:auto;
  background:rgba(255,255,255,.05); border-radius:999px;
  box-shadow:inset 0 0 0 1px var(--line);
}
.mode-btn {
  border:0; border-radius:999px; cursor:pointer;
  padding:.55rem 1.1rem; background:transparent; color:var(--dim);
  font:600 .8125rem/1 system-ui,-apple-system,sans-serif;
  transition:background .25s ease, color .25s ease;
}
.mode-btn.is-on { background:var(--text); color:var(--bg); }
@media (hover:hover) { .mode-btn:not(.is-on):hover { color:var(--text); } }

.intercept-verdict {
  margin:1.5rem auto 0; max-width:52ch; text-align:center;
  font-size:.95rem; line-height:1.6; color:var(--dim);
}
.intercept-verdict.bad { color:var(--warn); }

/* ==========================================================================
   LIVE CIPHER · byte grid
   ========================================================================== */

.cipher { padding:clamp(6rem,13vh,9rem) 0; }
.cipher-shell {
  margin-top:2.75rem;
  display:grid; grid-template-columns:minmax(0,.9fr) minmax(0,1.1fr);
  gap:clamp(1.25rem,3vw,2.25rem);
  padding:clamp(1.25rem,3vw,2rem);
  background:var(--surface); border-radius:var(--r-lg);
  box-shadow:inset 0 0 0 1px var(--line);
  backdrop-filter:blur(16px); -webkit-backdrop-filter:blur(16px);
}
.cipher-input, .cipher-output { display:flex; flex-direction:column; min-width:0; }
.cipher-label {
  font-size:.6875rem; font-weight:700; letter-spacing:.12em;
  text-transform:uppercase; color:var(--dim-2);
}
.cipher-label-row {
  display:flex; align-items:center; justify-content:space-between;
  gap:.75rem; margin-bottom:.75rem;
}
.cipher-badge {
  font:600 .625rem/1 ui-monospace,"SF Mono",Menlo,Consolas,monospace;
  letter-spacing:.06em; color:var(--acid);
  padding:.28rem .55rem; border-radius:999px;
  background:rgba(212,255,63,.1); box-shadow:inset 0 0 0 1px rgba(212,255,63,.28);
}
.cipher-input textarea {
  margin-top:.75rem; flex:1; resize:none; width:100%;
  background:rgba(0,0,0,.4); color:var(--text);
  border:0; border-radius:var(--r-md); padding:.9rem;
  box-shadow:inset 0 0 0 1px var(--line);
  font:400 1rem/1.55 system-ui,-apple-system,sans-serif;
}
.cipher-input textarea:focus { outline:none; box-shadow:inset 0 0 0 1px var(--i2); }
.cipher-note { margin-top:.7rem; font-size:.78rem; color:var(--dim-2); line-height:1.55; }
#flip-count { color:var(--acid); font-weight:600; }

/* Byte tiles. Each is one real ciphertext byte; changed tiles flip. */
.bytes {
  display:grid; grid-template-columns:repeat(auto-fill, minmax(30px, 1fr));
  gap:4px; align-content:start;
}
.byte {
  aspect-ratio:1; display:grid; place-items:center; border-radius:6px;
  background:rgba(255,255,255,.045);
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.06);
  font:600 .625rem/1 ui-monospace,"SF Mono",Menlo,Consolas,monospace;
  color:var(--dim);
  transform-style:preserve-3d;
}
.byte.flip {
  animation:byteflip .5s var(--ease);
  color:var(--acid);
  background:rgba(212,255,63,.1);
  box-shadow:inset 0 0 0 1px rgba(212,255,63,.34);
}
@keyframes byteflip {
  0%   { transform:rotateX(0deg)   scale(1); }
  45%  { transform:rotateX(-84deg) scale(1.12); }
  100% { transform:rotateX(0deg)   scale(1); }
}

/* ==========================================================================
   VERIFY IT YOURSELF
   The page's weakest point is that the source isn't published, so this section
   hands over the only thing that beats a promise: the actual request body, the
   actual stored row, and a real decrypt attempt that really fails. All three
   are generated live from the textarea above by the same Web Crypto calls.
   ========================================================================== */

.proof { padding:clamp(5rem,11vh,8rem) 0; }
.proof-grid {
  margin-top:2.75rem;
  display:grid; grid-template-columns:minmax(0,.82fr) minmax(0,1.18fr);
  gap:clamp(1.75rem,4vw,3.25rem); align-items:start;
}
.proof-steps {
  list-style:none; padding:0; margin:0; display:grid; gap:1.35rem;
  counter-reset:step;
}
.proof-steps li {
  display:grid; grid-template-columns:auto 1fr; gap:.25rem 1rem;
}
.proof-steps li::before {
  counter-increment:step; content:counter(step,decimal-leading-zero);
  grid-row:span 2;
  font:600 .6875rem/1.7 ui-monospace,"SF Mono",Menlo,Consolas,monospace;
  letter-spacing:.14em; color:var(--i2);
}
.proof-steps b { font-size:1rem; font-weight:600; letter-spacing:-.02em; }
.proof-steps span { font-size:.9rem; line-height:1.6; color:var(--dim); text-wrap:pretty; }
.proof-steps kbd {
  font:500 .82em/1 ui-monospace,"SF Mono",Menlo,Consolas,monospace;
  padding:.12rem .35rem; border-radius:5px;
  background:rgba(255,255,255,.07); box-shadow:inset 0 0 0 1px var(--line);
  color:var(--text);
}

.term {
  border-radius:var(--r-lg); overflow:hidden;
  background:rgba(0,0,0,.42);
  box-shadow:inset 0 0 0 1px var(--line);
  backdrop-filter:blur(14px); -webkit-backdrop-filter:blur(14px);
}
.term-bar {
  display:flex; align-items:center; gap:.3rem;
  padding:.55rem .6rem; border-bottom:1px solid var(--line);
}
.term-tab {
  border:0; cursor:pointer; padding:.45rem .85rem; border-radius:999px;
  background:transparent; color:var(--dim);
  font:600 .8125rem/1 system-ui,-apple-system,sans-serif; white-space:nowrap;
  transition:color .2s ease, background .2s ease, box-shadow .2s ease;
}
.term-tab.on {
  color:var(--text); background:rgba(255,255,255,.08);
  box-shadow:inset 0 0 0 1px var(--line-2);
}
@media (hover:hover) { .term-tab:not(.on):hover { color:var(--text); } }
.term-live {
  margin-left:auto; padding-right:.5rem; flex:none;
  display:inline-flex; align-items:center; gap:.4rem;
  font:700 .625rem/1 ui-monospace,"SF Mono",Menlo,Consolas,monospace;
  letter-spacing:.12em; text-transform:uppercase; color:var(--acid);
}
.term-live i {
  width:6px; height:6px; border-radius:50%; background:var(--acid);
  animation:pulse 2.6s var(--ease) infinite;
}
.term-body {
  margin:0; padding:1.15rem 1.2rem; min-height:16.5rem;
  font:500 .8125rem/1.75 ui-monospace,"SF Mono",Menlo,Consolas,monospace;
  color:var(--dim); white-space:pre-wrap; word-break:break-word;
}
.term-body b { color:var(--i2); font-weight:600; }
.term-body i { color:var(--acid); font-style:normal; }
.term-body u { color:var(--warn); text-decoration:none; }
.term-body em { color:var(--dim-2); font-style:normal; }
.proof-note {
  margin-top:1.35rem; font-size:.85rem; line-height:1.6; color:var(--dim-2);
  text-wrap:pretty;
}

@media (max-width:1000px) {
  .proof-grid { grid-template-columns:1fr; }
}
@media (max-width:600px) {
  .term-bar { flex-wrap:wrap; }
  .term-live { margin-left:0; }
  .term-body { font-size:.75rem; padding:.9rem; }
}

/* ==========================================================================
   3D FEATURE DECK
   Real perspective. Cards rotate toward the viewer as they cross the
   viewport, using a per-element view() timeline where supported.
   ========================================================================== */

.deck { padding:clamp(5rem,11vh,8rem) 0 clamp(6rem,13vh,9rem); }
.deck-rail {
  margin-top:3rem;
  display:grid; grid-template-columns:repeat(auto-fit,minmax(min(300px,100%),1fr));
  gap:1.1rem;
  width:min(1180px,100% - 2.75rem); margin-inline:auto;
  perspective:1400px;
}
.card {
  position:relative; isolation:isolate;
  padding:1.75rem 1.6rem 1.6rem;
  border-radius:var(--r-lg);
  background:linear-gradient(180deg,rgba(255,255,255,.055),rgba(255,255,255,.025));
  backdrop-filter:blur(14px); -webkit-backdrop-filter:blur(14px);
  transform-style:preserve-3d;
  overflow:hidden;
}
/* Animated conic border — this is what @property --angle exists for. A conic
   gradient cannot be transitioned without a registered custom property. */
.card::before {
  content:""; position:absolute; inset:0; border-radius:inherit; padding:1px;
  background:conic-gradient(from var(--angle),
    transparent 0deg, rgba(34,211,238,.55) 40deg, rgba(167,139,250,.55) 80deg, transparent 130deg);
  -webkit-mask:linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite:xor; mask-composite:exclude;
  z-index:-1;
}
@media (prefers-reduced-motion: no-preference) {
  .card::before { animation:spin 7s linear infinite; }
  .card:nth-child(2)::before { animation-delay:-1.75s; }
  .card:nth-child(3)::before { animation-delay:-3.5s; }
  .card:nth-child(4)::before { animation-delay:-5.25s; }
}
@keyframes spin { to { --angle:360deg; } }
/* Fallback ring for engines without @property support. */
@supports not (background: conic-gradient(from var(--angle), red, blue)) {
  .card { box-shadow:inset 0 0 0 1px var(--line); }
  .card::before { display:none; }
}

@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .card {
      animation:cardIn linear both;
      animation-timeline:view();
      animation-range:entry 5% entry 92%;
    }
    @keyframes cardIn {
      from { opacity:0; transform:translateY(46px) rotateX(11deg) scale(.955); }
      to   { opacity:1; transform:none; }
    }
    /* JS reveal would double up on the same elements. */
    .js .deck-rail .anim { opacity:1; transform:none; }
  }
}

.card-n {
  font:600 .6875rem/1 ui-monospace,"SF Mono",Menlo,Consolas,monospace;
  letter-spacing:.14em; color:var(--i2); margin-bottom:.95rem;
}
.card h3 { margin-bottom:.7rem; }
.card p { font-size:.95rem; line-height:1.62; color:var(--dim); text-wrap:pretty; }
.card p em { font-style:normal; color:var(--text); }

.card-art {
  margin-top:1.4rem; min-height:78px;
  display:flex; align-items:center; gap:.45rem; flex-wrap:wrap;
  padding:.85rem; border-radius:var(--r-md);
  background:rgba(0,0,0,.32);
  box-shadow:inset 0 0 0 1px var(--line);
  font:500 .78rem/1.4 ui-monospace,"SF Mono",Menlo,Consolas,monospace;
  color:var(--dim);
}
.art-react .chip {
  padding:.25rem .45rem; border-radius:999px;
  background:rgba(255,255,255,.06); font-size:.85rem;
}
.art-react .blob { margin-left:auto; color:var(--acid); }
.art-id { flex-direction:column; align-items:flex-start; gap:.4rem; }
.art-id .field {
  padding:.3rem .55rem; border-radius:7px; background:rgba(255,255,255,.06);
}
.art-id .struck { text-decoration:line-through; color:var(--dim-2); opacity:.6; }

/* State tag: which side of the shipped line a card sits on. The deck used to
   be all-built, so the tag is what keeps "designed" from reading as "done". */
.card-tag {
  position:absolute; top:1.5rem; right:1.5rem; z-index:1;
  padding:.26rem .6rem; border-radius:999px;
  font:700 .625rem/1 ui-monospace,"SF Mono",Menlo,Consolas,monospace;
  letter-spacing:.1em; text-transform:uppercase;
}
.card-tag.now {
  color:var(--acid); background:rgba(212,255,63,.1);
  box-shadow:inset 0 0 0 1px rgba(212,255,63,.28);
}
.card-tag.soon {
  color:var(--i3); background:rgba(167,139,250,.1);
  box-shadow:inset 0 0 0 1px rgba(167,139,250,.3);
}
/* "Exploring" is a weaker commitment than "next" or "later", so it gets a
   neutral chip rather than the accent one. */
.card-tag.maybe {
  color:var(--dim); background:rgba(255,255,255,.05);
  box-shadow:inset 0 0 0 1px var(--line-2);
}
.card h3 { padding-right:5.5rem; }

/* Planned cards are deliberately quieter and ringed in dashes rather than the
   animated conic border — unfinished things should look unfinished. */
.card.soon {
  background:linear-gradient(180deg,rgba(255,255,255,.03),rgba(255,255,255,.012));
  box-shadow:inset 0 0 0 1px rgba(167,139,250,.16);
}
.card.soon::before { display:none; }
.card.soon .card-n { color:var(--i3); opacity:.75; }
.card.soon .card-art { opacity:.75; border-radius:var(--r-md); }
.card.soon .card-art::after {
  content:""; position:absolute; inset:0; border-radius:inherit;
  box-shadow:inset 0 0 0 1px rgba(167,139,250,.18);
}
.card.soon .card-art { position:relative; }
.field.acid { color:var(--acid); }

/* ==========================================================================
   DISAPPEARING · SVG dissolve
   ========================================================================== */

.vanish { padding:clamp(5rem,11vh,8rem) 0; }
.vanish-grid {
  display:grid; grid-template-columns:1fr 1fr;
  gap:clamp(2rem,5vw,4rem); align-items:center;
}
.vanish-stage { position:relative; min-height:230px; }
.vanish-thread { display:flex; flex-direction:column; gap:.6rem; align-items:flex-start; }
.vb {
  padding:.65rem .95rem; border-radius:14px 14px 14px 5px;
  background:var(--surface-2); box-shadow:inset 0 0 0 1px var(--line);
  font-size:.95rem; color:var(--text);
  backdrop-filter:blur(10px); -webkit-backdrop-filter:blur(10px);
}
.vanish-thread.dissolving { filter:url(#dissolve); }
.vanish-after {
  position:absolute; left:0; top:.4rem; opacity:0;
  display:inline-flex; align-items:center; gap:.5rem;
  padding:.6rem 1rem; border-radius:999px;
  background:rgba(212,255,63,.1); color:var(--acid);
  box-shadow:inset 0 0 0 1px rgba(212,255,63,.3);
  font-size:.9rem; font-weight:600;
  transition:opacity .5s ease;
}
.vanish-after.show { opacity:1; }

/* ==========================================================================
   WHO IT'S FOR  +  THREAT MODEL
   Two halves of the same argument: naming the people who should use something
   else is what makes the first list credible, and a threat model that lists
   only wins isn't a threat model.
   ========================================================================== */

.who { padding:clamp(5rem,11vh,8rem) 0; }
.who-grid {
  margin-top:3rem;
  display:grid; grid-template-columns:repeat(auto-fit,minmax(min(380px,100%),1fr));
  gap:1.1rem;
}
.who-card {
  padding:1.7rem; border-radius:var(--r-lg);
  background:var(--surface); box-shadow:inset 0 0 0 1px var(--line);
}
.who-card h3 { margin-bottom:.4rem; }
.who-card > p {
  font-size:.875rem; line-height:1.6; color:var(--dim-2);
  margin-bottom:1.3rem; text-wrap:pretty;
}
.who-card ul { list-style:none; padding:0; margin:0; display:grid; gap:1rem; }
.who-card li {
  /* Explicit marker track: an `auto` column here would size to the longest
     description's max-content and squeeze the text into a sliver. */
  display:grid; grid-template-columns:1.15rem 1fr; gap:0 .7rem;
}
.who-card li b,
.who-card li span {
  grid-column:2;
  font-size:.95rem; line-height:1.6; text-wrap:pretty;
}
.who-card li b { color:var(--text); font-weight:600; margin-bottom:.15rem; }
.who-card li span { color:var(--dim); }
.who-card li span em { font-style:normal; color:var(--text); font-weight:600; }
.who-card li::before {
  grid-column:1; grid-row:1; align-self:start; margin-top:.1rem;
  font:700 .8125rem/1.55 ui-monospace,"SF Mono",Menlo,Consolas,monospace;
}
.who-yes li::before { content:"✓"; color:var(--acid); }
.who-no  li::before { content:"→"; color:var(--warn); }
.who-no { background:rgba(255,138,107,.035); box-shadow:inset 0 0 0 1px rgba(255,138,107,.14); }

.threat {
  padding:clamp(5.5rem,12vh,9rem) 0;
  background:
    radial-gradient(70% 45% at 50% 0%, rgba(111,181,255,.06) 0%, transparent 62%),
    var(--bg-2);
  border-block:1px solid var(--line);
}
.threat-list {
  list-style:none; padding:0; margin:3rem 0 0;
  display:grid; grid-template-columns:repeat(auto-fit,minmax(min(330px,100%),1fr));
  gap:1rem;
}
.threat-list li {
  display:flex; flex-direction:column; gap:.55rem;
  padding:1.45rem 1.5rem; border-radius:var(--r-md);
  background:var(--surface); box-shadow:inset 0 0 0 1px var(--line);
}
.t-chip {
  align-self:flex-start;
  padding:.28rem .6rem; border-radius:999px;
  font:700 .625rem/1 ui-monospace,"SF Mono",Menlo,Consolas,monospace;
  letter-spacing:.1em; text-transform:uppercase;
}
.t-chip.ok   { color:var(--acid); background:rgba(212,255,63,.1);  box-shadow:inset 0 0 0 1px rgba(212,255,63,.26); }
.t-chip.part { color:var(--i2);   background:rgba(111,181,255,.1); box-shadow:inset 0 0 0 1px rgba(111,181,255,.26); }
.t-chip.no   { color:var(--warn); background:rgba(255,138,107,.1); box-shadow:inset 0 0 0 1px rgba(255,138,107,.3); }
.threat-list h3 { font-size:1.05rem; }
.threat-list p {
  font-size:.92rem; line-height:1.6; color:var(--dim); text-wrap:pretty;
}
.threat-list p em { font-style:normal; color:var(--text); font-weight:600; }
.threat-foot {
  margin-top:2.25rem; font-size:.9rem; line-height:1.7; color:var(--dim-2);
  max-width:66ch; text-wrap:pretty;
}
.threat-foot a { color:var(--i2); }

/* ==========================================================================
   HONESTY
   ========================================================================== */

.honest {
  padding:clamp(5.5rem,12vh,9rem) 0;
  background:
    radial-gradient(75% 45% at 50% 0%, rgba(111,181,255,.07) 0%, transparent 62%),
    var(--bg-2);
  border-block:1px solid var(--line);
}
.honest-grid {
  margin-top:3rem;
  display:grid; grid-template-columns:repeat(auto-fit,minmax(min(400px,100%),1fr));
  gap:1.1rem;
}
.hcard {
  padding:1.7rem; border-radius:var(--r-lg);
  background:var(--surface);
  box-shadow:inset 0 0 0 1px var(--line);
}
.hcard h3 { margin-bottom:.8rem; }
.hcard p { font-size:.95rem; line-height:1.62; color:var(--dim); text-wrap:pretty; }

/* ==========================================================================
   COMPARISON
   Three of these rows are losses. That is the point — a table that only
   flatters us would undo the section above it.
   ========================================================================== */

.cmp {
  padding:clamp(5.5rem,12vh,9rem) 0;
  background:
    radial-gradient(70% 50% at 50% 100%, rgba(167,139,250,.07) 0%, transparent 62%),
    var(--bg-2);
  border-block:1px solid var(--line);
}
.cmp-scroll {
  margin-top:3rem; overflow-x:auto; overscroll-behavior-x:contain;
  scrollbar-width:thin;
}
.cmp table {
  width:100%; min-width:720px; border-collapse:collapse; text-align:left;
}
.cmp caption { text-align:left; }
.cmp th, .cmp td {
  padding:1.05rem 1rem; vertical-align:top;
  border-top:1px solid var(--line);
  font-size:.92rem; line-height:1.5;
}
.cmp thead th {
  border-top:0; padding-top:0;
  font-size:.75rem; font-weight:600; letter-spacing:.11em;
  text-transform:uppercase; color:var(--dim-2); white-space:nowrap;
}
.cmp thead th.own { color:var(--text); }
.cmp tbody th {
  font-weight:600; color:var(--text); letter-spacing:-.015em;
  width:26%; min-width:190px;
}
.cmp tbody th span {
  display:block; margin-top:.3rem;
  font-size:.8125rem; font-weight:400; color:var(--dim-2); text-wrap:pretty;
}
.cmp td { color:var(--dim); }

/* The Kalvien column is tinted end to end rather than per-cell, so the eye
   reads one panel instead of six highlights. */
.cmp .own {
  background:linear-gradient(180deg, rgba(111,181,255,.09), rgba(167,139,250,.045));
  color:var(--text);
}
.cmp tbody tr:first-child .own { box-shadow:inset 0 1px 0 rgba(111,181,255,.3); }
.cmp tbody tr:last-child .own { box-shadow:inset 0 -1px 0 rgba(111,181,255,.3); }

.cmp b.y, .cmp b.n, .cmp b.p {
  display:inline-flex; align-items:center; gap:.4rem;
  font-size:.92rem; font-weight:600;
}
.cmp b.y { color:var(--acid); }
.cmp b.n { color:var(--warn); }
.cmp b.p { color:var(--dim); }
.cmp b::before {
  font:700 .78rem/1 ui-monospace,"SF Mono",Menlo,Consolas,monospace;
  width:1.15rem; height:1.15rem; border-radius:50%;
  display:grid; place-items:center; flex:none;
}
.cmp b.y::before { content:"✓"; background:rgba(212,255,63,.14); }
.cmp b.n::before { content:"✕"; background:rgba(255,138,107,.14); }
.cmp b.p::before { content:"~"; background:rgba(255,255,255,.07); }
.cmp-note {
  margin-top:1.75rem; font-size:.85rem; line-height:1.6; color:var(--dim-2);
  max-width:62ch; text-wrap:pretty;
}
.cmp-note a { color:var(--i2); }

/* ---- motion ----
   The table's job is cross-column comparison, so the motion is sequential by
   ROW: each row switches on in turn, its label draws an accent, its verdict
   glyph pops, and the Kalvien column flashes brighter before settling to its
   resting tint — which makes the tinted panel look like it fills in top-down.
   Rows animate opacity only (transform on a table-row is historically
   unreliable); the movement comes from the label accent and the glyphs. */

.js .cmp tbody tr { opacity:0; }
.js .cmp-scroll.in tbody tr {
  animation:cmpRow .5s var(--ease) both;
  animation-delay:calc(var(--i, 0) * 90ms);
}
@keyframes cmpRow { from { opacity:0; } to { opacity:1; } }

.cmp tbody th { position:relative; }
.cmp tbody th::before {
  content:""; position:absolute; left:0; top:.9rem; bottom:.9rem; width:2px;
  background:var(--iris); border-radius:2px;
  transform:scaleY(0); transform-origin:50% 0;
}
.js .cmp-scroll.in tbody th::before {
  animation:cmpRule .5s var(--ease) both;
  animation-delay:calc(var(--i, 0) * 90ms + 90ms);
}
@keyframes cmpRule { from { transform:scaleY(0); } to { transform:scaleY(1); } }

.js .cmp-scroll.in tbody b {
  animation:cmpPop .42s cubic-bezier(.34,1.56,.64,1) both;
  animation-delay:calc(var(--i, 0) * 90ms + 150ms);
}
@keyframes cmpPop {
  from { opacity:0; transform:translateY(4px) scale(.9); }
  to   { opacity:1; transform:none; }
}

.js .cmp-scroll.in tbody .own {
  animation:cmpOwn 1.1s var(--ease) both;
  animation-delay:calc(var(--i, 0) * 90ms);
}
@keyframes cmpOwn {
  0%   { background:linear-gradient(180deg, rgba(111,181,255,.3), rgba(167,139,250,.18)); }
  100% { background:linear-gradient(180deg, rgba(111,181,255,.09), rgba(167,139,250,.045)); }
}

.cmp tbody tr:nth-child(1) { --i:0; }
.cmp tbody tr:nth-child(2) { --i:1; }
.cmp tbody tr:nth-child(3) { --i:2; }
.cmp tbody tr:nth-child(4) { --i:3; }
.cmp tbody tr:nth-child(5) { --i:4; }
.cmp tbody tr:nth-child(6) { --i:5; }
.cmp tbody tr:nth-child(7) { --i:6; }
.cmp tbody tr:nth-child(8) { --i:7; }

/* Row highlight — a 5-column table is hard to read across, so this is
   legibility as much as polish. */
.cmp tbody tr { transition:background .25s ease; }
@media (hover:hover) {
  .cmp tbody tr:hover { background:rgba(255,255,255,.03); }
  .cmp tbody tr:hover th { color:#fff; }
  .cmp tbody tr:hover td { color:var(--text); }
}

@media (prefers-reduced-motion:reduce) {
  .js .cmp tbody tr { opacity:1; }
  .js .cmp-scroll.in tbody tr,
  .js .cmp-scroll.in tbody b,
  .js .cmp-scroll.in tbody .own,
  .js .cmp-scroll.in tbody th::before { animation:none !important; }
  .cmp tbody th::before { transform:scaleY(1); }
}
html[data-motion="off"] .cmp tbody tr { opacity:1; }

@media (max-width:700px) {
  .cmp th, .cmp td { padding:.85rem .75rem; font-size:.875rem; }
  .cmp tbody th { min-width:160px; }
}

/* ==========================================================================
   ROADMAP · drawn connector
   ========================================================================== */

.road { padding:clamp(5.5rem,12vh,9rem) 0; }
.road-list {
  list-style:none; padding:0; margin:3rem 0 0;
  position:relative;
  display:grid; gap:1rem;
}
/* Vertical rail, drawn as scroll advances where scroll timelines exist. */
.road-list::before {
  content:""; position:absolute; left:0; top:0; bottom:0; width:2px;
  background:var(--iris); transform-origin:50% 0; transform:scaleY(1);
  opacity:.55;
}
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .road-list::before {
      animation:draw linear both;
      animation-timeline:view();
      animation-range:entry 10% cover 60%;
    }
    @keyframes draw { from { transform:scaleY(0); } to { transform:scaleY(1); } }
  }
}
.road-list li {
  position:relative; padding:1.4rem 1.5rem 1.4rem 2rem;
  border-radius:var(--r-md);
  background:var(--surface);
  box-shadow:inset 0 0 0 1px var(--line);
}
.rtag {
  display:inline-block; font-size:.625rem; font-weight:700;
  letter-spacing:.12em; text-transform:uppercase;
  padding:.26rem .6rem; border-radius:999px; margin-bottom:.75rem;
}
.rtag.next    { color:var(--acid); background:rgba(212,255,63,.1);  box-shadow:inset 0 0 0 1px rgba(212,255,63,.28); }
.rtag.later   { color:var(--i2);   background:rgba(111,181,255,.1); box-shadow:inset 0 0 0 1px rgba(111,181,255,.28); }
.rtag.explore { color:var(--i3);   background:rgba(167,139,250,.1); box-shadow:inset 0 0 0 1px rgba(167,139,250,.28); }
.road-list h3 { font-size:1.05rem; }
.road-list p { margin-top:.5rem; font-size:.92rem; line-height:1.6; color:var(--dim); text-wrap:pretty; }

/* ==========================================================================
   ONBOARDING
   Four frames, not devices — the rail above already spends six bezels, so
   these are plain screen cards to keep the two sections from reading as the
   same thing twice. Two of the four steps exist only because we ask for a
   number, which is why the section says so out loud.
   ========================================================================== */

.flow { padding:clamp(5rem,11vh,8rem) 0; }
.flow-list {
  list-style:none; padding:0; margin:3rem 0 0; position:relative;
  display:grid; grid-template-columns:repeat(4,minmax(0,1fr));
  gap:clamp(1rem,2.2vw,1.6rem);
}

.step { position:relative; z-index:1; }
/* Same device shell as the screens rail — these are phone screens, so they get
   the phone. Capped at the rail's width so a single-column layout doesn't blow
   one frame up to 400px wide. */
.step .scr { width:100%; max-width:252px; margin-inline:auto; }
.step-n {
  position:relative;
  margin:1.15rem 0 .45rem;
  font:600 .6875rem/1 ui-monospace,"SF Mono",Menlo,Consolas,monospace;
  letter-spacing:.14em; color:var(--i2);
}
/* Connector, drawn on the step-number row rather than across the frames: the
   frames are aspect-ratio sized, so any single absolute offset over them
   breaks at the next breakpoint. Per-step lines can't drift. */
.step-n::after {
  content:""; position:absolute; top:50%; left:2.3rem; height:2px;
  right:calc(-1 * clamp(1rem,2.2vw,1.6rem) - .2rem);
  background:var(--iris); opacity:.4;
  transform:scaleX(0); transform-origin:0 50%;
}
.step:last-child .step-n::after { display:none; }
.js .step.in .step-n::after { animation:drawX .55s var(--ease) both; }
.js .step.a1.in .step-n::after { animation-delay:.16s; }
.js .step.a2.in .step-n::after { animation-delay:.24s; }
.js .step.a3.in .step-n::after { animation-delay:.32s; }
@keyframes drawX { from { transform:scaleX(0); } to { transform:scaleX(1); } }
@media (prefers-reduced-motion:reduce) {
  .step-n::after { transform:scaleX(1); }
}
html[data-motion="off"] .step-n::after { transform:scaleX(1); }
/* Direct children only — an unscoped `.step b` / `.step span` also matched
   every span inside the phone screens and forced them to 14px blocks. */
.step > b { display:block; font-size:1.02rem; font-weight:600; letter-spacing:-.02em; }
.step > span {
  display:block; margin-top:.35rem;
  font-size:.875rem; line-height:1.6; color:var(--dim); text-wrap:pretty;
}

/* ---- screen internals, on top of the rail's .s-* primitives ---- */

.step .s-cta { margin:8px 12px 0; padding:9px; }
.step .s-cta.ghost { padding:7px; }
.s-lede { margin:0 14px 10px; font-size:9px; line-height:1.5; color:var(--a-dim); }
.s-lede b { color:var(--a-text); font-weight:600; }
/* Pushes the primary action to the bottom of the screen, where it lives in the
   real app, instead of leaving a void under short content. */
.s-bottom { margin-top:auto; }
.fs-row { display:flex; gap:6px; margin:0 12px 8px; }
/* Inside the row the fields lose their own margins, never wrap, and the number
   takes the remaining width — a phone number field is one line or it's wrong. */
.fs-row .s-search {
  margin:0; padding:8px 10px; min-width:0;
  white-space:nowrap; overflow:hidden;
}
.fs-row .s-search:last-child { flex:1; }
.s-search.pill { flex:none; font-weight:600; gap:4px; }

.fs-crumb {
  align-self:flex-start; margin:0 12px 10px;
  display:inline-flex; align-items:center; gap:5px;
  padding:4px 8px; border-radius:9px;
  font-size:8px; font-weight:700; letter-spacing:.02em;
  color:#6ee7a8; background:rgba(110,231,168,.12);
}
.fs-otp { display:flex; gap:4px; margin:0 12px 9px; }
.fs-otp i {
  flex:1; height:26px; border-radius:8px; background:var(--a-surface);
  display:grid; place-items:center;
  font:600 12px/1 var(--a-font); font-style:normal; color:var(--a-text);
}
.fs-otp i.on { box-shadow:inset 0 0 0 1.5px var(--a-accent); }
.fs-otp i.next { box-shadow:inset 0 0 0 1.5px var(--a-line); color:var(--a-accent); }
.fs-link { display:block; margin:0 12px 10px; font-size:8.5px; font-weight:600; color:var(--a-accent); }
.fs-emoji { display:flex; gap:5px; margin:0 12px 8px; }
.fs-emoji span {
  width:26px; height:26px; border-radius:9px; display:grid; place-items:center;
  background:var(--a-surface); font-size:12px;
}
.fs-emoji span.on { box-shadow:inset 0 0 0 1.5px var(--a-accent); }
.fs-keys { display:grid; gap:5px; margin:0 14px 8px; }
.fs-key {
  display:flex; align-items:center; gap:6px;
  font:500 8.5px/1.4 ui-monospace,Menlo,monospace;
  color:var(--a-dim);
}
.fs-key b { color:var(--a-accent); font-weight:600; }
.fs-key .tick { color:#6ee7a8; font-size:9px; }

.flow-foot {
  margin-top:2.5rem; padding-top:1.5rem; border-top:1px solid var(--line);
  display:flex; flex-wrap:wrap; gap:.6rem 2rem; align-items:baseline;
}
.flow-foot p { font-size:.875rem; line-height:1.6; color:var(--dim); max-width:52ch; text-wrap:pretty; }
.flow-foot p a { color:var(--i2); }
.flow-time {
  font:600 .75rem/1 ui-monospace,"SF Mono",Menlo,Consolas,monospace;
  letter-spacing:.1em; text-transform:uppercase; color:var(--acid); flex:none;
}

@media (max-width:880px) {
  .flow-list { grid-template-columns:repeat(2,minmax(0,1fr)); gap:1.75rem 1.25rem; }
  .step-n::after { display:none; }
}
@media (max-width:520px) {
  .flow-list { grid-template-columns:1fr; }
}

/* ==========================================================================
   JOIN
   ========================================================================== */

.join {
  position:relative; isolation:isolate; overflow:clip; text-align:center;
  padding:clamp(6rem,14vh,10rem) 0;
}
.join-gl { position:absolute; inset:0; width:100%; height:100%; z-index:-2; }
.join::after {
  content:""; position:absolute; inset:0; z-index:-1; pointer-events:none;
  background:radial-gradient(100% 70% at 50% 100%, transparent 20%, var(--bg) 78%);
}
.join-inner { position:relative; }
.join h2 { margin-top:1.6rem; }
.join .section-lede { margin-inline:auto; }
.join-mark {
  display:grid; place-items:center; width:70px; height:70px;
  margin:0 auto; border-radius:22px; position:relative; isolation:isolate;
  color:var(--bg);
}
.join-mark::before {
  content:""; position:absolute; inset:0; border-radius:inherit; z-index:-1;
  background:var(--iris);
  box-shadow:0 20px 50px -18px rgba(111,181,255,.55);
}
.join-mark svg { width:35px; height:35px; }

/* ---------- sticky CTA ---------- */

.sticky-cta {
  position:fixed; z-index:110;
  left:50%; transform:translateX(-50%);
  bottom:max(1rem, env(safe-area-inset-bottom));
  animation:ctaUp .32s var(--ease) both;
}
.sticky-cta[hidden] { display:none; }
@keyframes ctaUp {
  from { opacity:0; transform:translateX(-50%) translateY(14px); }
  to   { opacity:1; transform:translateX(-50%) translateY(0); }
}
@keyframes ctaFade { from { opacity:0; } to { opacity:1; } }

/* ==========================================================================
   FAQ
   Native <details name="faq"> gives exclusive-accordion behaviour with no JS
   at all, and stays fully usable in engines that ignore the name attribute —
   they just allow more than one panel open at a time.
   ========================================================================== */

.faq { padding:clamp(5.5rem,12vh,9rem) 0; }
.faq-list { margin-top:2.75rem; display:grid; gap:.6rem; }
.faq details {
  border-radius:var(--r-md);
  background:var(--surface);
  box-shadow:inset 0 0 0 1px var(--line);
  overflow:hidden;
}
.faq summary {
  cursor:pointer; list-style:none;
  padding:1.15rem 3rem 1.15rem 1.35rem; position:relative;
  font-size:1.05rem; font-weight:600; letter-spacing:-.015em;
}
.faq summary::-webkit-details-marker { display:none; }
.faq summary::after {
  content:""; position:absolute; right:1.35rem; top:50%;
  width:11px; height:11px; margin-top:-6px;
  border-right:2px solid var(--dim); border-bottom:2px solid var(--dim);
  transform:rotate(45deg); transform-origin:60% 60%;
  transition:transform .25s var(--ease), border-color .25s ease;
}
.faq details[open] summary::after { transform:rotate(225deg); border-color:var(--i2); }
@media (hover:hover) { .faq summary:hover { color:var(--i2); } }
.faq details p {
  padding:0 1.35rem 1.3rem; margin:0;
  font-size:.98rem; line-height:1.66; color:var(--dim); max-width:70ch;
  text-wrap:pretty;
}
.faq details p em { font-style:normal; color:var(--text); font-weight:600; }
.faq details p a { color:var(--i2); }

/* ---------- footer ----------
   Split into a product column and the two groups a Google Play listing
   requires: the policy links (privacy, terms, data safety, account deletion)
   and a real support/report route for a messaging app carrying user content.
   The section links only point at sections that exist on this page. */

.foot { border-top:1px solid var(--line); padding:3rem 0 3.25rem; }
.foot-inner {
  display:grid; gap:2.5rem clamp(1.5rem,4vw,3.5rem);
  grid-template-columns:minmax(220px,1.3fr) repeat(3,minmax(140px,1fr));
}
.foot-brand { display:flex; align-items:center; gap:.55rem; font-weight:600; letter-spacing:-.025em; }
.foot-blurb {
  margin-top:.9rem; font-size:.8125rem; line-height:1.7; color:var(--dim-2);
  max-width:34ch; text-wrap:pretty;
}
.foot-col h4 {
  font-size:.6875rem; font-weight:600; letter-spacing:.12em;
  text-transform:uppercase; color:var(--dim-2); margin-bottom:1rem;
}
.foot-links {
  display:flex; flex-direction:column; gap:.65rem;
  font-size:.8125rem; font-weight:500;
}
.foot-links a { color:var(--dim); text-decoration:none; }
.foot-links a:hover { color:var(--text); text-decoration:underline; }

.foot-legal {
  margin-top:2.75rem; padding-top:1.5rem; border-top:1px solid var(--line);
  display:flex; flex-wrap:wrap; justify-content:space-between; gap:.75rem 2rem;
  font-size:.8125rem; line-height:1.7; color:var(--dim-2);
}
.foot-legal p { max-width:62ch; text-wrap:pretty; }
.foot-legal a { color:var(--i2); text-decoration:none; }
.foot-legal a:hover { text-decoration:underline; }

@media (max-width:820px) {
  .foot-inner { grid-template-columns:repeat(2,minmax(0,1fr)); }
}
@media (max-width:560px) {
  .foot-inner { grid-template-columns:1fr; gap:2rem; }
  .foot-legal { flex-direction:column; }
}

/* ==========================================================================
   INTERACTIVE DEMO · composer, reaction bar, burn timer, try-chips
   The phone stopped being a video: everything below exists because the user
   can now drive the thread themselves.
   ========================================================================== */

/* Every bubble is a target now — reactions and reply live behind a tap. */
.dev-thread .m { cursor:pointer; }
.dev-thread .m.typing { cursor:default; }
.dev-thread .m:focus-visible { outline:2px solid var(--a-accent); outline-offset:2px; }

/* Per-message crypto receipt. Real byte count, real leading ciphertext bytes. */
.m-stat {
  display:block; margin-top:.2rem;
  font:600 .5rem/1.3 ui-monospace,"SF Mono",Menlo,Consolas,monospace;
  letter-spacing:.02em; color:var(--a-dim);
}
.m-stat.enc { color:var(--a-accent); }
/* A reaction chip overlaps the bubble's bottom-right corner, which is exactly
   where the receipt ends. Reserve room for it. */
.m:has(.rx) .m-stat { padding-right:2.4rem; }

/* Reaction + reply bar. Sits above the tapped bubble; the thread scrolls to
   the newest message, so there is always room. */
.rx-bar {
  position:absolute; z-index:8; bottom:calc(100% + 3px); left:0;
  display:flex; align-items:center; gap:.05rem; padding:.16rem .2rem;
  border-radius:999px; background:var(--a-raised); white-space:nowrap;
  box-shadow:inset 0 0 0 1px var(--a-line), 0 10px 22px -12px rgba(0,0,0,.95);
  animation:rxBar .18s var(--ease) both;
}
.m.mine .rx-bar { left:auto; right:0; }
@keyframes rxBar {
  from { opacity:0; transform:translateY(5px) scale(.9); }
  to   { opacity:1; transform:none; }
}
.rx-bar button {
  border:0; background:none; cursor:pointer; padding:.18rem .24rem;
  border-radius:999px; font-size:.75rem; line-height:1; color:var(--a-text);
  transition:background .15s ease, transform .15s var(--ease);
}
.rx-bar button:hover { background:rgba(255,255,255,.12); transform:scale(1.15); }
.rx-bar .rx-reply {
  font-size:.625rem; font-weight:700; color:var(--a-accent);
  margin-left:.1rem; padding-left:.3rem;
  box-shadow:inset 1px 0 0 var(--a-line);
  border-radius:0 999px 999px 0;
}

/* Disappearing-message countdown, ticking on the bubble it will destroy. */
.m-burn-t {
  position:absolute; top:-.42rem; left:-.3rem;
  font:700 .5rem/1 ui-monospace,Menlo,Consolas,monospace;
  color:#FFC46B; background:var(--a-surface);
  box-shadow:inset 0 0 0 1px rgba(255,196,107,.35);
  padding:.1rem .3rem; border-radius:999px;
}
.m.mine .m-burn-t { left:auto; right:-.3rem; }

/* Composer. A real form inside the device. */
.dev-composer { position:relative; }
.dev-composer .dev-clip,
.dev-composer .dev-send {
  border:0; padding:0; font:inherit; cursor:pointer;
  transition:transform .18s var(--ease), opacity .2s ease, color .2s ease;
}
.dev-composer .dev-clip { background:none; }
.dev-composer .dev-clip:hover { color:var(--a-accent); }
.dev-inputbox {
  flex:1; min-width:0; border:0; background:transparent; color:var(--a-text);
  font:400 .6875rem/1.35 system-ui,-apple-system,"Segoe UI",sans-serif;
  padding:.3rem 0;
}
.dev-inputbox::placeholder { color:var(--a-dim); }
.dev-inputbox:focus { outline:none; }
.dev-send[disabled] { opacity:.4; cursor:default; }
.dev-send:not([disabled]):hover { transform:scale(1.1); }

/* Reply-to strip above the composer. */
.dev-reply {
  position:absolute; left:0; right:0; bottom:calc(100% + .32rem);
  display:flex; align-items:center; gap:.35rem;
  padding:.28rem .45rem; border-radius:9px;
  background:var(--a-surface); box-shadow:inset 0 0 0 1px var(--a-line);
  border-left:2px solid var(--a-accent);
  font:500 .5625rem/1.3 system-ui,-apple-system,sans-serif; color:var(--a-dim);
}
.dev-reply[hidden] { display:none; }
.dev-reply q { min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; quotes:none; }
.dev-reply button {
  margin-left:auto; flex:none; border:0; background:none; cursor:pointer;
  color:var(--a-dim); font-size:.75rem; line-height:1; padding:0 .1rem;
}
.dev-reply button:hover { color:var(--a-text); }

/* Feature chips under the phone: the things a composer can't teach. */
.try {
  display:flex; flex-wrap:wrap; gap:.4rem; justify-content:center;
  width:min(330px,100%);
}
.try-btn {
  border:0; cursor:pointer; border-radius:999px;
  padding:.44rem .8rem; background:rgba(255,255,255,.055); color:var(--dim);
  box-shadow:inset 0 0 0 1px var(--line);
  font:600 .75rem/1 system-ui,-apple-system,sans-serif; letter-spacing:-.01em;
  transition:color .2s ease, box-shadow .2s ease, background .2s ease;
}
@media (hover:hover) { .try-btn:hover { color:var(--text); box-shadow:inset 0 0 0 1px var(--line-2); } }
.try-btn.used {
  color:var(--acid); background:rgba(212,255,63,.07);
  box-shadow:inset 0 0 0 1px rgba(212,255,63,.3);
}

.live-progress { font-size:.75rem; color:var(--dim-2); }
.live-progress b { color:var(--acid); font-weight:700; }

@media (prefers-reduced-motion:reduce) {
  .rx-bar { animation:none !important; }
}

/* ==========================================================================
   SCREENS RAIL
   The demo phone only ever shows one thread, but the copy claims folders,
   vibes, verification, hashed discovery, themes and privacy defaults. This is
   where those get shown instead of asserted. Native scroll-snap does the
   carousel; the buttons are a discoverability affordance on top of it, not the
   mechanism.
   ========================================================================== */

.screens { padding:clamp(4rem,9vh,6.5rem) 0 clamp(5rem,11vh,8rem); }
.rail-wrap { margin-top:2.75rem; }
.rail {
  display:flex; align-items:flex-start;
  gap:clamp(1rem,2.4vw,1.75rem);
  overflow-x:auto; overscroll-behavior-x:contain;
  scroll-snap-type:x mandatory; scroll-behavior:smooth;
  /* Aligns the first screen with .wrap's left edge without a wrapper. */
  padding:.5rem max(1.375rem, (100vw - 1180px) / 2) 1rem;
  scrollbar-width:none;
}
.rail::-webkit-scrollbar { width:0; height:0; }
@media (prefers-reduced-motion:reduce) { .rail { scroll-behavior:auto; } }
.rail:focus-visible { outline:2px solid var(--i2); outline-offset:6px; }

.rail-item {
  flex:none; width:252px; scroll-snap-align:center;
  display:flex; flex-direction:column; gap:1.1rem; margin:0;
}
.rail-item figcaption { font-size:.85rem; line-height:1.55; color:var(--dim); text-wrap:pretty; }
.rail-item figcaption b {
  display:block; margin-bottom:.25rem;
  font-size:.95rem; font-weight:600; letter-spacing:-.02em; color:var(--text);
}

@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .rail-item {
      animation:railIn linear both;
      animation-timeline:view(inline);
      animation-range:entry 0% entry 88%;
    }
    @keyframes railIn {
      from { opacity:.18; transform:translateY(16px) scale(.93); }
      to   { opacity:1; transform:none; }
    }
  }
}

/* ---- the device ---- */

.scr {
  position:relative; width:252px; aspect-ratio:390 / 844; flex:none;
  background:#0a0a0c; border-radius:32px; padding:7px;
  box-shadow:0 30px 62px -28px rgba(0,0,0,.9), 0 0 0 1.2px rgba(255,255,255,.09);
}
.scr::before {
  content:""; position:absolute; top:7px; left:50%; transform:translateX(-50%);
  width:26%; height:2.9%; background:#0a0a0c; border-radius:20px; z-index:4;
}
.scr-in {
  height:100%; border-radius:26px; overflow:hidden;
  background:var(--a-bg); color:var(--a-text);
  display:flex; flex-direction:column;
  font:400 10px/1.45 var(--a-font);
  letter-spacing:-.1px;
}

.s-top {
  display:flex; align-items:center; justify-content:space-between;
  padding:11px 12px 2px; font-size:8.5px; font-weight:700; flex:none;
}
.s-top i { display:block; width:15px; height:7px; border-radius:2px; box-shadow:inset 0 0 0 1px var(--a-text); opacity:.55; }

.s-head {
  display:flex; align-items:center; gap:7px; flex:none;
  padding:9px 14px 8px;
}
.s-head h4 { font-size:17px; font-weight:600; letter-spacing:-.7px; margin:0; }
.s-head .s-ic { color:var(--a-dim); margin-left:auto; display:flex; gap:7px; }
.s-head .s-ic svg { width:13px; height:13px; }
/* The app's back affordance is a rounded card square, not a bare chevron. */
.s-back {
  width:24px; height:24px; border-radius:8px; flex:none;
  display:grid; place-items:center; color:var(--a-text);
  background:var(--a-surface);
}
.s-back svg { width:12px; height:12px; }

.s-body { flex:1; min-height:0; overflow:hidden; display:flex; flex-direction:column; }
.s-scroll { flex:1; min-height:0; overflow:hidden; }

/* Search pill — the app's chat list opens with one. */
.s-find {
  display:flex; align-items:center; gap:7px; margin:2px 12px 8px;
  padding:8px 11px; border-radius:11px;
  background:var(--a-surface); color:var(--a-dim); font-size:9.5px;
}
.s-find svg { width:11px; height:11px; flex:none; }

/* Notes row (the app calls a vibe a note: 60 characters, gone in 24h). */
.s-notes { display:flex; gap:9px; padding:2px 12px 10px; }
.s-not { width:44px; flex:none; text-align:center; }
.s-not .ring {
  width:38px; height:38px; margin:0 auto 4px; border-radius:13px;
  position:relative; display:grid; place-items:center;
  font-size:13px; font-weight:700; color:#fff;
}
.s-not .ring.on { box-shadow:0 0 0 1.5px var(--a-bg), 0 0 0 3px var(--a-accent); }
.s-not span { font-size:8.5px; color:var(--a-dim); }

.s-tabs {
  display:flex; gap:5px; padding:0 12px 9px; flex:none;
}
.s-tab {
  padding:4px 9px; border-radius:10px; font-size:9px; font-weight:600;
  color:var(--a-dim); background:var(--a-surface); white-space:nowrap;
}
.s-tab.on { color:#fff; background:var(--a-grad); }
.s-tab .n { opacity:.7; margin-left:3px; }

.s-sec {
  padding:8px 14px 5px; font-size:8px; font-weight:600;
  letter-spacing:.08em; text-transform:uppercase; color:var(--a-dim);
}

/* Chat rows are cards with their own radius in this app, not a flat list. */
.s-row {
  display:flex; align-items:center; gap:9px;
  margin:0 10px 5px; padding:8px 10px;
  background:var(--a-surface); border-radius:14px;
}
.s-av {
  width:32px; height:32px; border-radius:11px; flex:none;
  display:grid; place-items:center; font-size:11px; font-weight:700; color:#fff;
  background:var(--a-grad);
}
.s-av.b { background:linear-gradient(135deg,#9b6dff,#c56bff); }
.s-av.c { background:linear-gradient(135deg,#f97362,#ec4899); }
.s-av.d { background:linear-gradient(135deg,#3fb6c9,#6d5ef6); }
.s-av.g { background:var(--a-chip); color:var(--a-accent); }
.s-txt { flex:1; min-width:0; }
.s-nm { display:flex; align-items:center; gap:4px; font-size:10.5px; font-weight:600; letter-spacing:-.2px; }
.s-nm svg { width:9px; height:9px; color:var(--a-accent); flex:none; }
.s-pv {
  display:flex; align-items:center; gap:3px; margin-top:1px;
  font-size:9px; color:var(--a-dim);
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
}
.s-pv.acid { color:var(--a-accent); }
.s-side { display:flex; flex-direction:column; align-items:flex-end; gap:3px; flex:none; }
.s-time { font-size:8px; color:var(--a-dim); }
.s-badge {
  min-width:15px; padding:1px 4px; border-radius:999px; text-align:center;
  font-size:8px; font-weight:700; color:#fff; background:var(--a-grad);
}
.s-flame { font-size:8px; font-weight:700; color:#FFC46B; }

/* safety number */
.s-center { text-align:center; padding:10px 14px 0; }
.s-center .s-av { width:48px; height:48px; border-radius:16px; margin:0 auto 8px; font-size:17px; }
.s-center h5 { font-size:12.5px; font-weight:600; letter-spacing:-.3px; margin:0 0 3px; }
.s-center p { font-size:9px; color:var(--a-dim); line-height:1.5; margin:0; }
.s-digits {
  display:grid; grid-template-columns:repeat(3,1fr); gap:5px 8px;
  margin:11px 16px;
  font:500 11px/1.3 ui-monospace,"SF Mono",Menlo,monospace;
  letter-spacing:.04em; text-align:center; color:var(--a-text);
}
.s-qr {
  position:relative; width:72px; height:72px; margin:0 auto; border-radius:10px;
  padding:5px; background:#fff;
}
.s-qr i {
  display:grid; width:100%; height:100%; gap:1px;
  grid-template-columns:repeat(11,1fr); grid-template-rows:repeat(11,1fr);
}
.s-qr i span { border-radius:1px; }
.s-qr i span.on { background:#0e0e12; }
.s-qr b {
  position:absolute; inset:50% auto auto 50%; transform:translate(-50%,-50%);
  width:20px; height:20px; border-radius:7px; background:#fff;
  display:grid; place-items:center;
}
.s-qr b span { width:12px; height:12px; border-radius:4px; background:var(--a-grad); }
.s-cta {
  margin:12px 14px 0; padding:11px; border-radius:13px; text-align:center;
  font-size:11px; font-weight:600; color:#fff;
  background:var(--a-grad);
  box-shadow:0 10px 22px -12px rgba(109,94,246,.9);
}
.s-cta.ghost {
  color:var(--a-accent); background:none; box-shadow:none;
  font-weight:600;
}
.s-foot {
  margin-top:auto; padding:10px 14px 12px; font-size:8.5px; line-height:1.5;
  color:var(--a-dim);
}
.s-foot code { font-size:8.5px; color:var(--a-accent); }

/* search / discovery */
.s-search {
  display:flex; align-items:center; gap:6px; margin:2px 12px 8px;
  padding:9px 11px; border-radius:11px;
  background:var(--a-surface);
  font-size:10px; color:var(--a-text);
}
.s-search svg { width:11px; height:11px; color:var(--a-dim); flex:none; }
.s-search .caret { width:1px; height:11px; background:var(--a-accent); }
.s-hash {
  margin:3px 12px 0; padding:7px 9px; border-radius:10px;
  background:rgba(143,125,255,.1);
  font:500 8px/1.5 ui-monospace,"SF Mono",Menlo,monospace;
  color:var(--a-accent); word-break:break-all;
}
.s-add {
  padding:4px 9px; border-radius:9px; flex:none;
  font-size:9px; font-weight:600; color:#fff; background:var(--a-grad);
}

/* themes */
.s-themes { display:grid; gap:7px; padding:4px 12px 10px; }
.s-theme {
  display:flex; align-items:center; gap:9px; padding:8px;
  border-radius:14px; background:var(--a-surface);
}
.s-theme.on { box-shadow:inset 0 0 0 1.5px var(--a-accent); }
.s-swatch {
  width:34px; height:44px; border-radius:9px; flex:none; padding:4px;
  display:flex; flex-direction:column; justify-content:flex-end; gap:3px;
}
.s-swatch i { display:block; height:5px; border-radius:2px; }
.s-swatch i:first-child { width:70%; }
.s-swatch i:last-child { width:50%; align-self:flex-end; }
.s-theme .lbl { flex:1; }
.s-theme .lbl b { display:block; font-size:10.5px; font-weight:600; letter-spacing:-.2px; }
.s-theme .lbl span { font-size:8.5px; color:var(--a-dim); }
.s-check { color:var(--a-accent); font-size:11px; font-weight:700; }

/* toggle groups sit inside one card, the way the app groups settings */
.s-card {
  margin:2px 12px 0; border-radius:14px; overflow:hidden;
  background:var(--a-surface);
}
.s-tog { display:flex; align-items:center; gap:9px; padding:9px 11px; }
.s-tog + .s-tog { box-shadow:inset 0 1px 0 var(--a-line); }
.s-tog .lbl { flex:1; min-width:0; }
.s-tog .lbl b { display:block; font-size:10.5px; font-weight:600; letter-spacing:-.2px; }
.s-tog .lbl span { font-size:8.5px; line-height:1.45; color:var(--a-dim); }
.s-sw {
  width:26px; height:15px; border-radius:999px; flex:none; padding:2px;
  background:var(--a-raised); display:flex;
}
.s-sw i { width:11px; height:11px; border-radius:50%; background:var(--a-dim); }
.s-sw.on { background:var(--a-grad); justify-content:flex-end; }
.s-sw.on i { background:#fff; }
.s-pill {
  padding:3px 8px; border-radius:9px; flex:none;
  font-size:8.5px; font-weight:600; color:var(--a-accent);
  background:var(--a-chip);
}
.s-pill.none { color:var(--a-dim); background:var(--a-raised); text-decoration:line-through; }
.s-danger { color:var(--a-danger); }

/* Floating tab bar, as in the app. */
.s-bar {
  display:flex; flex:none; margin:auto 12px 12px; padding:6px;
  border-radius:16px; background:var(--a-surface);
  box-shadow:0 -8px 24px -14px rgba(0,0,0,.8);
}
.s-bar span {
  flex:1; text-align:center; font-size:7.5px; font-weight:600; color:var(--a-dim);
  display:flex; flex-direction:column; align-items:center; gap:3px;
  padding:4px 0; border-radius:11px;
}
.s-bar span.on { color:#fff; background:var(--a-grad); }
.s-bar svg { width:14px; height:14px; }

/* ---- rail controls ---- */

.rail-nav {
  display:flex; align-items:center; justify-content:center; gap:.85rem;
  margin-top:2.25rem;
}
.rail-btn {
  width:40px; height:40px; border-radius:999px; display:grid; place-items:center;
  border:0; cursor:pointer; color:var(--text);
  background:rgba(255,255,255,.06); box-shadow:inset 0 0 0 1px var(--line);
  transition:color .2s ease, box-shadow .2s ease, opacity .2s ease;
}
.rail-btn svg { width:16px; height:16px; }
@media (hover:hover) { .rail-btn:not([disabled]):hover { color:var(--i2); box-shadow:inset 0 0 0 1px var(--i2); } }
.rail-btn[disabled] { opacity:.3; cursor:default; }
.rail-count {
  font:600 .8125rem/1 ui-monospace,"SF Mono",Menlo,Consolas,monospace;
  color:var(--dim-2); min-width:5ch; text-align:center;
}

/* ==========================================================================
   Responsive
   ========================================================================== */

@media (max-width:1000px) {
  .cipher-shell { grid-template-columns:1fr; }
  .vanish-grid  { grid-template-columns:1fr; }
  .live-grid    { grid-template-columns:1fr; justify-items:center; }
  .live-list    { width:100%; max-width:560px; }
}

@media (max-width:820px) {
  /* The lane cannot survive one column: stack sender/wire/recipient and turn
     the wire vertical so the packet still travels a real distance. */
  .intercept-track { height:180vh; }
  .lane { grid-template-columns:1fr; justify-items:center; gap:.5rem; }
  .wire { width:100%; max-width:340px; height:150px; }
  .mini { width:min(280px,86vw); }
  .intercept-pin { height:auto; min-height:100svh; padding:6rem 0 3rem; }
}

@media (max-width:600px) {
  .rail { padding-inline:1rem; }
  .rail-item, .scr { width:232px; }
  .brand-word { display:none; }
  .signup-row { flex-direction:column; padding:.55rem; border-radius:24px; }
  .signup input[type="email"] { padding:.85rem 1rem; }
  .btn { width:100%; }
  .sticky-cta { left:1rem; right:1rem; transform:none; animation-name:ctaFade; }
  .sticky-cta .btn { width:100%; }
  .bytes { grid-template-columns:repeat(auto-fill,minmax(26px,1fr)); }
  .motion-toggle { left:1rem; right:auto; }
}

/* ==========================================================================
   Reduced motion.
   Reduced ≠ removed: content stays, the pinned section collapses so it no
   longer eats 260vh of scroll with the payoff stripped out, and continuous
   ambient motion stops. Functional state changes are preserved.
   ========================================================================== */

@media (prefers-reduced-motion:reduce) {
  *, *::before, *::after {
    animation-duration:.001ms !important;
    animation-iteration-count:1 !important;
    transition-duration:.001ms !important;
  }
  .js .anim { opacity:1 !important; transform:none !important; }
  .nav::after { display:none; }
  .eyebrow .dot { animation:none !important; }

  /* Collapse the pin: show the end state, reclaim the scroll distance. */
  .intercept-track { height:0; }
  .intercept-pin { position:static; height:auto; padding:5rem 0; }
  .mini-bub.in { opacity:1 !important; }
  .wire-live { transform:scaleX(1) !important; }
  .packet { position:static; transform:none !important; margin:.75rem auto 0; width:fit-content; }

  .card { opacity:1 !important; transform:none !important; }
  .road-list::before { transform:scaleY(1) !important; }

  /* The live thread still populates — it is product information, not
     decoration — but it lands instantly, all features are marked done, and
     nothing loops. app.js reads the same preference and skips the timeline. */
  .m, .m-sys { animation:none !important; }
  .rx { animation:none !important; transform:scale(1) !important; }
  .m.typing { display:none !important; }
  .m.burning { animation:none !important; opacity:0 !important; }
  .live-list li.done i::after { transform:scale(1) !important; }
  /* Keep the outcome — messages gone — without the dissolve. */
  .vanish-thread.dissolving { filter:none !important; opacity:0 !important; }
}

/* Users who never opt out still get a manual escape hatch (WCAG 2.2.2). */
html[data-motion="off"] .eyebrow .dot,
html[data-motion="off"] .card::before,
html[data-motion="off"] .nav::after { animation:none !important; }
html[data-motion="off"] .byte.flip { animation:none !important; }

