/* ============================================================
   NODU — marketing landing page
   Built on the Nodu design tokens (warm ink, Coral Sunset accent).
   Mobile is treated as the primary experience; desktop scales up.
   The page ships at motion mode "max" (set on <html data-motion>).
   ============================================================ */

*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; scroll-padding-top: 84px; overflow-x: clip; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  background: var(--bg-base, #14100E);
  color: var(--text-hi, #FBF3EE);
  font-family: var(--font-body, 'Plus Jakarta Sans', system-ui, sans-serif);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: clip;
}
::selection { background: rgba(255,61,113,.30); color: #fff; }
img, svg { display: block; max-width: 100%; }
a { color: inherit; text-decoration: none; }
button { font-family: inherit; }

/* Accent feeds the gradient (kept as vars so a single edit re-themes the page) */
:root {
  --accent-1: var(--accent, #FF3D71);
  --accent-2: var(--accent-warm, #FF8A3D);
  --grad: linear-gradient(115deg, var(--accent-1), var(--accent-2));
  --reveal-ease: cubic-bezier(.16,.84,.30,1);
  --reveal-dur: 820ms;
  --glow-strength: 1;
  /* single source of truth for the vertical rhythm between sections */
  --sec-pad: clamp(62px, 8.5vh, 128px);
}

/* ---------- Ambient background layers (fixed) ---------- */
.bg-layer { position: fixed; inset: 0; pointer-events: none; z-index: 0; }
.bg-wash {
  background:
    radial-gradient(60vw 50vh at 84% -8%, rgba(255,61,113,.16), transparent 60%),
    radial-gradient(55vw 45vh at 6% 4%, rgba(255,138,61,.10), transparent 58%),
    radial-gradient(70vw 60vh at 50% 118%, rgba(255,61,113,.10), transparent 62%);
}
.bg-mesh {
  opacity: .9;
  background:
    radial-gradient(38vw 38vw at var(--m1x,20%) var(--m1y,18%), rgba(255,61,113,.20), transparent 60%),
    radial-gradient(34vw 34vw at var(--m2x,82%) var(--m2y,70%), rgba(255,138,61,.16), transparent 60%),
    radial-gradient(30vw 30vw at var(--m3x,60%) var(--m3y,40%), rgba(124,77,255,.10), transparent 60%);
  filter: blur(20px);
  transition: opacity .6s ease;
}
.bg-grain {
  opacity: .05; mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}
.bg-scan {
  opacity: 0;
  background-image: repeating-linear-gradient(to bottom, rgba(255,255,255,.025) 0 1px, transparent 1px 3px);
  transition: opacity .6s ease;
}
.cursor-glow {
  position: fixed; top: 0; left: 0; width: 520px; height: 520px; z-index: 1;
  border-radius: 50%; pointer-events: none; opacity: 0;
  transform: translate3d(-50%, -50%, 0);
  background: radial-gradient(circle, rgba(255,61,113,.16), rgba(255,138,61,.05) 42%, transparent 68%);
  transition: opacity .5s ease;
}

/* Mode gating: extra-techy layers only show in "max" */
[data-motion="bold"] .bg-mesh { opacity: .55; filter: blur(34px); }
[data-motion="bold"] .bg-grain { opacity: .025; }
[data-motion="max"] .bg-mesh { animation: meshDrift 26s ease-in-out infinite alternate; }
[data-motion="max"] .bg-scan { opacity: .5; }
[data-motion="max"].fine-pointer .cursor-glow { opacity: 1; }
@keyframes meshDrift {
  0%   { --m1x:18%; --m1y:16%; --m2x:84%; --m2y:72%; --m3x:58%; --m3y:38%; }
  100% { --m1x:30%; --m1y:30%; --m2x:70%; --m2y:58%; --m3x:46%; --m3y:54%; }
}
/* Property registration so the mesh positions can animate */
@property --m1x { syntax: '<length-percentage>'; inherits: true; initial-value: 18%; }
@property --m1y { syntax: '<length-percentage>'; inherits: true; initial-value: 16%; }
@property --m2x { syntax: '<length-percentage>'; inherits: true; initial-value: 84%; }
@property --m2y { syntax: '<length-percentage>'; inherits: true; initial-value: 72%; }
@property --m3x { syntax: '<length-percentage>'; inherits: true; initial-value: 58%; }
@property --m3y { syntax: '<length-percentage>'; inherits: true; initial-value: 38%; }

/* ---------- Layout primitives ---------- */
.wrap { width: 100%; max-width: 1320px; margin: 0 auto; padding-inline: clamp(22px, 5.4vw, 88px); position: relative; z-index: 2; }
.section { position: relative; z-index: 2; padding-block: var(--sec-pad); }
.section-head { max-width: 46rem; }

.eyebrow {
  display: inline-flex; align-items: center; gap: 10px;
  font-family: var(--font-mono, 'JetBrains Mono', monospace);
  font-size: clamp(10px, 1.4vw, 12px); font-weight: 500; letter-spacing: 1.8px;
  text-transform: uppercase; color: var(--accent-2, #FF8A3D);
  margin: 0 0 18px; white-space: nowrap;
}
.eyebrow .idx { color: var(--accent-1, #FF3D71); }
.eyebrow .tick { width: 26px; height: 1px; flex-shrink: 0; background: linear-gradient(90deg, var(--accent-2), transparent); }

h1, h2, h3 { font-family: var(--font-display, 'Fredoka', sans-serif); font-weight: 600; margin: 0; }
.display {
  font-size: clamp(40px, 8.6vw, 86px); line-height: 1.0; letter-spacing: -.025em;
  text-wrap: balance;
}
.h-section {
  font-size: clamp(34px, 5.2vw, 66px); line-height: 1.03; letter-spacing: -.02em;
  text-wrap: balance; margin: 0 0 20px;
}
.lede { font-size: clamp(17px, 1.5vw, 22px); line-height: 1.66; color: var(--text-med, #C9BBB1); max-width: 44ch; margin: 0; }
.lede.wide { max-width: 50ch; }
.text-grad {
  background: var(--grad); -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent; color: transparent;
}

/* ---------- Top nav ---------- */
.nav {
  position: fixed; top: 0; left: 0; right: 0; z-index: 60;
  display: flex; align-items: center; justify-content: space-between;
  gap: 16px; padding: 18px clamp(18px, 5vw, 44px);
  transition: background .4s ease, border-color .4s ease, box-shadow .4s ease, padding .4s ease;
  border-bottom: 1px solid transparent;
}
.nav.scrolled {
  background: rgba(20,16,14,.62);
  -webkit-backdrop-filter: blur(20px) saturate(1.4); backdrop-filter: blur(20px) saturate(1.4);
  border-bottom: 1px solid var(--glass-border, rgba(255,255,255,.10));
  box-shadow: 0 8px 30px rgba(0,0,0,.34);
}
.nav-links { display: flex; align-items: center; gap: 30px; }
.nav-links a { font-size: 14px; font-weight: 600; color: var(--text-med, #C9BBB1); transition: color .2s ease; position: relative; }
.nav-links a::after { content: ''; position: absolute; left: 0; right: 100%; bottom: -5px; height: 1.5px; background: var(--grad); transition: right .28s var(--reveal-ease); }
.nav-links a:hover { color: var(--text-hi, #FBF3EE); }
.nav-links a:hover::after { right: 0; }
.nav-cta {
  display: inline-flex; align-items: center; gap: 8px; cursor: pointer;
  font-size: 14px; font-weight: 700; color: #fff; border: 0;
  padding: 11px 18px; border-radius: var(--radius-button, 14px);
  background: var(--accent-1, #FF3D71);
  box-shadow: var(--elev-glow-soft, 0 8px 22px rgba(255,61,113,.26));
  transition: transform .14s ease, background .2s ease;
}
.nav-cta:hover { background: var(--accent-pressed, #E62E5F); }
.nav-cta:active { transform: scale(.96); }

/* ---------- Hero ---------- */
/* Clip horizontally only (contains the wide halo / prevents sideways scroll).
   overflow-y stays visible so the floating hero card is never sliced top/bottom
   by the clip edge — that slicing is what squared off the card's rounded corners. */
.hero { position: relative; min-height: 100svh; display: grid; align-items: center; padding: clamp(96px, 13vh, 134px) 0 var(--sec-pad); overflow-x: clip; }
.hero-grid { display: grid; grid-template-columns: 1fr 1.04fr; gap: clamp(28px, 4.6vw, 64px); align-items: center; width: 100%; }
.hero-copy { max-width: 37rem; }
.hero h1 { margin: 0 0 22px; }
.hero .lede { margin-bottom: 30px; }
.hero-foot { display: flex; align-items: center; gap: 14px; margin-top: 22px; flex-wrap: wrap; }
.facepile { display: flex; }
.facepile > * { margin-left: -11px; box-shadow: 0 0 0 2.5px var(--bg-base); border-radius: 999px; }
.facepile > *:first-child { margin-left: 0; }
.hero-foot .micro { font-size: 13.5px; color: var(--text-low, #8E807A); max-width: 28ch; line-height: 1.5; }
.hero-foot .micro b { color: var(--text-med, #C9BBB1); font-weight: 700; }

/* Hero stage — holds the bounded list artifact + its halo. Everything lives
   INSIDE this flex box (no negative offsets), so the hero can never be clipped. */
.hero-stage { position: relative; display: flex; justify-content: center; isolation: isolate; }
.hero-stage .halo {
  position: absolute; top: 47%; left: 50%; width: min(116%, 560px); aspect-ratio: 1;
  transform: translate(-50%, -50%); border-radius: 50%; z-index: 0; pointer-events: none;
  background: radial-gradient(closest-side, rgba(255,61,113,.26), rgba(255,138,61,.10) 48%, transparent 72%);
  filter: blur(10px); opacity: calc(.8 * var(--glow-strength));
}
@media (prefers-reduced-motion: no-preference) {
  .hero-stage .halo { animation: haloBreathe 7.5s ease-in-out infinite; }
}
@keyframes haloBreathe {
  0%, 100% { transform: translate(-50%, -50%) scale(1);    opacity: calc(.64 * var(--glow-strength)); }
  50%      { transform: translate(-50%, -50%) scale(1.06); opacity: calc(1 * var(--glow-strength)); }
}

/* ---------- Hero list (the payoff, as an editorial artifact) ---------- */
.hero-list-wrap { position: relative; z-index: 2; width: min(480px, 100%); }
.hero-list {
  position: relative; width: 100%; padding: 20px 18px 16px;
  isolation: isolate; /* contain the ::before surface layer (z-index:-1) */
}
/* THE ROUNDED-CORNER "TRIANGLE" FIX (root cause + cure)
   ----------------------------------------------------
   When a rounded card lives on its own GPU compositing layer — forced here by
   the infinite listFloat animation, and elsewhere by reveal transforms / overlap
   with the fixed background layers — Chromium & WebKit paint the element's OUTER
   box-shadow with SQUARE corners (WebKit bug 15158). The dark shadow's square
   corner then pokes diagonally past the rounded card as a triangle: "rectangular,
   not matching the curves."
   Cure: never cast the OUTER shadow with box-shadow on these cards. Use
   `filter: drop-shadow()`, which derives the shadow from the element's real
   rounded alpha shape, so it physically cannot be square. Inset highlights stay
   as box-shadow (they live inside the radius and are never the culprit). */
.hero-list::before {
  content: ''; position: absolute; inset: 0; z-index: -1; border-radius: 26px;
  background: linear-gradient(180deg, var(--surface-1, #1E1815), rgba(26,20,18,.92));
  border: 1px solid var(--border-subtle, #2E2620);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.05);
  filter:
    drop-shadow(0 30px 38px rgba(0,0,0,.55))
    drop-shadow(0 12px 20px rgba(0,0,0,.42));
}
@media (prefers-reduced-motion: no-preference) {
  .hero-list { animation: listFloat 10s ease-in-out infinite; }
}
@keyframes listFloat { 0%, 100% { transform: translateY(-6px); } 50% { transform: translateY(6px); } }

.hl-head { display: flex; align-items: flex-end; justify-content: space-between; gap: 12px; margin-bottom: 16px; padding-inline: 4px; }
.hl-eyebrow { display: flex; align-items: center; gap: 8px; margin: 0 0 7px; white-space: nowrap; font-family: var(--font-mono, 'JetBrains Mono', monospace); font-size: 10.5px; font-weight: 500; letter-spacing: 1.7px; text-transform: uppercase; color: var(--accent-2, #FF8A3D); }
.hl-eyebrow .d { width: 6px; height: 6px; border-radius: 999px; background: var(--accent-1, #FF3D71); box-shadow: 0 0 0 0 rgba(255,61,113,.5); }
@media (prefers-reduced-motion: no-preference) { .hl-eyebrow .d { animation: livePulse 2.6s ease-in-out infinite; } }
@keyframes livePulse { 0%, 100% { box-shadow: 0 0 0 0 rgba(255,61,113,.5); } 50% { box-shadow: 0 0 0 4px rgba(255,61,113,0); } }
.hl-title { font-family: var(--font-display, 'Fredoka', sans-serif); font-weight: 600; font-size: 28px; letter-spacing: -.01em; color: var(--text-hi, #FBF3EE); }
.hl-count { flex-shrink: 0; white-space: nowrap; font-family: var(--font-mono, 'JetBrains Mono', monospace); font-size: 11px; color: var(--text-low, #8E807A); }

.hl-list { position: relative; }
.hl-row {
  position: absolute; left: 0; right: 0; top: 0;
  transition: transform .52s cubic-bezier(.2,.8,.2,1), opacity .4s ease;
}
/* The rounded card surface lives on .hl-inner, NOT on .hl-row. Each .hl-row is
   permanently transformed (translateY positioning in the stack), which promotes
   it to its own GPU compositing layer — and Chromium paints that layer's
   background/shadow with SQUARE corners behind the rounded edge (the "triangles
   at the corners" bug). Keeping the radius + shadow on the untransformed
   .hl-inner lets the corners render correctly. */
/* Each .hl-row is permanently transformed (translateY stacking) + the whole list
   floats, so the rows ride on GPU layers. OUTER shadow → drop-shadow (follows the
   radius). The #1 / just-placed highlight RING → an INSET ring: inset shadows are
   clipped to the radius and so never square off at the corners the way an outer
   `0 0 0 Npx` ring does. */
.hl-inner {
  display: flex; align-items: center; gap: 12px; width: 100%; min-height: 74px;
  background: var(--surface-1, #1E1815); border: 1px solid var(--border-subtle, #2E2620);
  border-radius: 15px; padding: 8px 13px 8px 9px;
  filter: drop-shadow(0 2px 6px rgba(0,0,0,.35));
  transition: box-shadow .4s ease, border-color .4s ease, filter .4s ease;
}
.hl-row.first .hl-inner { border-color: transparent; background: linear-gradient(180deg, rgba(255,61,113,.14), var(--surface-1, #1E1815)); box-shadow: inset 0 0 0 1.5px var(--accent-1, #FF3D71); filter: drop-shadow(0 8px 16px rgba(0,0,0,.42)); }
.hl-row.just .hl-inner { border-color: transparent; box-shadow: inset 0 0 0 1.5px var(--accent-2, #FF8A3D); filter: drop-shadow(0 8px 16px rgba(0,0,0,.42)); }
@media (prefers-reduced-motion: no-preference) {
  .hl-row.just { animation: hlCardIn .5s ease both; }
  .hl-inner.in { animation: hlInnerIn .5s var(--reveal-ease) both; }
}
.hl-inner.out { opacity: 0; transition: opacity .26s ease; }
.hl-row.leaving { opacity: 0 !important; z-index: 1 !important; transition: transform .5s cubic-bezier(.2,.8,.2,1), opacity .28s ease; }
@keyframes hlCardIn { from { opacity: 0; } to { opacity: 1; } }
@keyframes hlInnerIn { from { opacity: 0; transform: translateY(7px); } to { opacity: 1; transform: none; } }
.hl-rk { font-family: var(--font-display, 'Fredoka', sans-serif); font-weight: 700; font-size: 21px; width: 23px; text-align: center; flex-shrink: 0; color: var(--text-med, #C9BBB1); }
.hl-row.first .hl-rk { background: var(--grad); -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent; }
.hl-info { flex: 1; min-width: 0; }
.hl-info b { display: block; font-size: 15px; font-weight: 700; color: var(--text-hi, #FBF3EE); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.hl-info small { font-size: 12px !important; }
.hl-info small { display: block; font-size: 11px; color: var(--text-low, #8E807A); }

.hl-foot { display: flex; align-items: center; gap: 10px; margin: 16px 0 0; padding-inline: 4px; font-size: 12.5px; line-height: 1.4; color: var(--text-med, #C9BBB1); }
.hl-foot-ic { position: relative; width: 19px; height: 17px; flex-shrink: 0; }
.hl-foot-ic i { position: absolute; top: 1px; width: 9px; height: 14px; border-radius: 2px; }
.hl-foot-ic i:nth-child(1) { left: 0; transform: rotate(-12deg); border: 1.5px solid var(--accent-2, #FF8A3D); }
.hl-foot-ic i:nth-child(2) { right: 0; transform: rotate(12deg); border: 1.5px solid var(--accent-1, #FF3D71); }

/* ---------- Feature acts ---------- */
.act { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(28px, 5vw, 80px); align-items: center; }
.act.flip .act-visual { order: -1; }
.act-copy { max-width: 30rem; }
.act-points { list-style: none; margin: 26px 0 0; padding: 0; display: grid; gap: 14px; }
.act-points li { display: flex; gap: 12px; align-items: flex-start; font-size: 15px; color: var(--text-med, #C9BBB1); line-height: 1.5; }
.act-points .dot { flex-shrink: 0; width: 20px; height: 20px; border-radius: 7px; background: var(--accent-soft-fill, #2E1A1C); border: 1px solid var(--accent-soft-border, #4A2630); display: flex; align-items: center; justify-content: center; color: var(--accent-text, #FF5C7E); margin-top: 1px; }
.act-points .dot svg { width: 12px; height: 12px; }

.act-visual { position: relative; min-height: 380px; display: flex; align-items: center; justify-content: center; }

/* ---------- Track scene ---------- */
.track-stage { position: relative; width: 100%; max-width: 540px; min-height: 480px; }
.track-card {
  position: absolute; left: 0; right: 0;
  display: flex; align-items: center; gap: 13px;
  background: var(--surface-1, #1E1815); border: 1px solid var(--border-subtle, #2E2620);
  border-radius: 16px; padding: 10px 14px;
  /* drop-shadow (not box-shadow): these reveal with a transform, which promotes
     them to a GPU layer mid-animation where a box-shadow squares off. */
  filter: drop-shadow(0 8px 16px rgba(0,0,0,.42));
  transition: opacity .55s var(--reveal-ease), transform .55s var(--reveal-ease);
}
.reveal-on .track-card { opacity: 0; transform: translateY(34px) scale(.97); }
.reveal-on .track-card:not(.shown) { will-change: opacity, transform; }
.reveal-on .track-card.shown { opacity: 1; transform: none; }
.track-card .meta { flex: 1; min-width: 0; }
.track-card .meta b { display: block; font-size: 14px; font-weight: 700; color: var(--text-hi); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.track-card .meta small { display: block; font-size: 11px; color: var(--text-low); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.track-card .add { margin-left: auto; flex-shrink: 0; white-space: nowrap; font-size: 12px; font-weight: 800; color: var(--accent-text); display: inline-flex; align-items: center; gap: 5px; }
.track-card .add svg { width: 15px; height: 15px; }

/* ---------- Compare scene (head-to-head clash) ---------- */
.clash { position: relative; width: 100%; max-width: 560px; }
.clash-q { text-align: center; font-family: var(--font-display); font-weight: 600; font-size: clamp(22px, 3.4vw, 32px); color: var(--text-hi); margin-bottom: 22px; letter-spacing: -.02em; }
.clash-row { position: relative; display: flex; gap: clamp(14px, 4vw, 30px); align-items: stretch; justify-content: center; }
.clash-side { flex: 1; max-width: 240px; }
.clash-side .clash-poster { position: relative; }
.clash-side .title { text-align: center; font-size: 16px; font-weight: 700; color: var(--text-hi); margin-top: 16px; }
.clash-or {
  position: absolute; left: 50%; top: 42%; transform: translate(-50%,-50%);
  width: 52px; height: 52px; border-radius: 999px; z-index: 3;
  background: var(--bg-base); border: 2px solid var(--border-strong, #463A31);
  display: flex; align-items: center; justify-content: center;
  font-family: var(--font-display); font-weight: 700; font-size: 15px; color: var(--accent-2);
}
.clash-meter { display: flex; align-items: center; justify-content: center; gap: 9px; margin-top: 22px; font-family: var(--font-mono); font-size: 12px; color: var(--text-low); white-space: nowrap; }
.clash-dots { display: flex; gap: 6px; }
.clash-dots i { width: 7px; height: 7px; border-radius: 999px; background: var(--surface-3, #342A23); transition: background .3s ease, transform .3s ease; }
.clash-dots i.on { background: var(--accent-1); transform: scale(1.25); }

/* ---------- Rank scene (pinned scroll) ---------- */
.rank-scene { position: relative; height: 200svh; padding-block: 0; margin-block: 0; }
.rank-sticky { position: sticky; top: 0; height: 100svh; display: grid; grid-template-columns: 1fr 1fr; gap: clamp(24px, 5vw, 72px); align-items: center; overflow: hidden; }
.rank-copy { align-self: center; }
.rank-progress { margin-top: 26px; height: 4px; border-radius: 999px; background: var(--surface-2, #29211C); overflow: hidden; max-width: 280px; }
.rank-progress > i { display: block; height: 100%; width: 0%; background: var(--grad); border-radius: 999px; }
.rank-stage { position: relative; height: 100%; display: flex; align-items: center; justify-content: center; }
.rank-list { position: relative; width: 100%; max-width: 520px; height: 560px; }
.rank-item { position: absolute; left: 0; right: 0; }
.rank-row {
  position: relative; display: flex; align-items: center; gap: 13px;
  border-radius: 15px; padding: 9px 14px 9px 10px;
}
.rank-row > *:not(.rank-rowbg) { position: relative; z-index: 1; }
.rank-rowbg {
  position: absolute; inset: 0; z-index: 0; border-radius: 15px;
  background: var(--surface-1, #1E1815); border: 1px solid var(--border-subtle, #2E2620);
  /* drop-shadow keeps the shadow on the radius (see .hero-list::before note) */
  filter: drop-shadow(0 8px 16px rgba(0,0,0,.42));
}
.reveal-on .rank-item .reveal-late { opacity: 0; }
.rank-row .num { font-family: var(--font-display); font-weight: 700; font-size: 26px; width: 30px; text-align: center; flex-shrink: 0; color: var(--text-med, #C9BBB1); }
.rank-row.first > .num { background: var(--grad); -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent; }
.rank-row .info { flex: 1; min-width: 0; }
.rank-row .info b { display: block; font-size: 16px; font-weight: 700; color: var(--text-hi); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.rank-row .info small { font-size: 11px; color: var(--text-low); }

/* ---------- Social scene ---------- */
.social-grid { display: grid; grid-template-columns: .92fr 1.08fr; gap: clamp(28px, 5vw, 72px); align-items: center; }
.feed-col { display: grid; gap: 14px; max-width: 420px; width: 100%; justify-self: center; }
/* These cards overlap the fixed background layers and get overlap-composited on
   some GPUs. The rounded surface lives on ::before; its OUTER shadow is cast with
   filter: drop-shadow() so it follows the radius instead of squaring off at the
   corners. (See the note by .hero-list::before.) */
.feed-card {
  position: relative; isolation: isolate;
  border-radius: var(--radius-card, 20px); padding: 14px;
}
.feed-card::before {
  content: ''; position: absolute; inset: 0; z-index: -1; border-radius: inherit;
  background: var(--surface-1, #1E1815); border: 1px solid var(--border-subtle, #2E2620);
  filter: drop-shadow(0 8px 16px rgba(0,0,0,.42));
}
.feed-head { display: flex; align-items: center; gap: 9px; margin-bottom: 12px; }
.feed-head .who { font-size: 13px; font-weight: 700; color: var(--text-hi); }
.feed-head .act-txt { font-size: 13px; color: var(--text-low); }
.feed-head .ago { font-size: 11px; color: var(--text-low); display: block; }
.feed-head .grow { flex: 1; line-height: 1.3; }
.feed-vs { display: flex; align-items: center; gap: 10px; }
.feed-vs .beat { font-family: var(--font-display); font-weight: 700; font-size: 13px; color: var(--accent-2); }
.feed-vs .poster { flex: 1; width: auto; }
.feed-line { font-size: 13px; color: var(--text-med); margin-top: 10px; }
.feed-line b { color: var(--text-hi); }
.feed-rating { display: flex; gap: 12px; align-items: center; }
.feed-rating .rt-title { display: block; font-family: var(--font-display); font-weight: 600; font-size: 16px; color: var(--text-hi); }
.feed-rating .rt-meta { display: block; font-size: 12px; color: var(--text-low); margin-bottom: 6px; }
.feed-react { display: flex; align-items: center; gap: 8px; margin-top: 12px; }
.react-chip {
  display: inline-flex; align-items: center; gap: 6px; font-size: 13px; font-weight: 700;
  padding: 7px 13px; border-radius: 999px; overflow: clip; /* clip bg to the pill even if composited */
  transition: transform .3s var(--reveal-ease), background .3s ease;
}
.react-chip.heart { background: var(--accent-soft-fill, #2E1A1C); color: var(--accent-text, #FF5C7E); border: 1px solid var(--accent-soft-border, #4A2630); }
.react-chip.cmt { background: var(--surface-2, #29211C); color: var(--text-med); border: 1px solid var(--border-strong, #463A31); }
.react-pop { margin-left: auto; font-size: 18px; opacity: 0; transform: scale(.4) rotate(-12deg); transition: opacity .4s ease, transform .5s var(--reveal-ease); }
.feed-card.is-in .react-pop { opacity: 1; transform: scale(1) rotate(0); }
.note { font-size: 12.5px; color: var(--text-med); font-style: italic; }

/* confetti on waitlist join (echoes the app's celebrate moment) */
.confetti { position: absolute; inset: 0; overflow: hidden; pointer-events: none; z-index: 5; border-radius: inherit; }
.confetti i { position: absolute; top: -14px; width: 9px; height: 9px; border-radius: 2px; opacity: 0; animation: confettiFall 1.9s ease-in forwards; }
@keyframes confettiFall { 0% { transform: translateY(-10px) rotate(0); opacity: 0; } 12% { opacity: 1; } 100% { transform: translateY(420px) rotate(440deg); opacity: 0; } }

.hide-sm {}

/* ---------- Waitlist CTA ---------- */
.cta { position: relative; text-align: center; overflow: hidden; }
.cta-card {
  position: relative; max-width: 720px; margin: 0 auto; text-align: center;
  background: linear-gradient(180deg, var(--surface-1, #1E1815), rgba(30,24,21,.4));
  border: 1px solid var(--border-subtle, #2E2620); border-radius: var(--radius-sheet, 28px);
  padding: clamp(36px, 6vw, 72px) clamp(24px, 5vw, 64px);
  /* drop-shadow (not box-shadow) so the shadow follows the rounded corners on the
     composited layer — see the note by .hero-list::before. */
  filter:
    drop-shadow(0 18px 26px rgba(0,0,0,.5))
    drop-shadow(0 6px 12px rgba(0,0,0,.4));
}
.cta-card .appicon { width: 64px; height: 64px; margin: 0 auto 22px; border-radius: 18px; box-shadow: var(--elev-glow-soft); }
.cta-card h2 { margin-bottom: 14px; }

/* Waitlist form */
.waitlist { display: flex; gap: 10px; max-width: 440px; margin: 28px auto 0; }
.waitlist.left { margin-inline: 0; }
.waitlist .field {
  flex: 1; min-width: 0; height: 54px; padding: 0 18px; border-radius: var(--radius-button, 14px);
  background: var(--surface-2, #29211C); border: 1px solid var(--border-strong, #463A31);
  color: var(--text-hi); font-size: 15px; font-family: inherit; outline: none;
  transition: border-color .2s ease, box-shadow .2s ease;
}
.waitlist .field::placeholder { color: var(--text-low, #8E807A); }
.waitlist .field:focus { border-color: var(--accent-1); box-shadow: 0 0 0 3px rgba(255,61,113,.18); }
.waitlist .field.err { border-color: var(--error, #FF5247); box-shadow: 0 0 0 3px rgba(255,82,71,.18); }
.waitlist .submit {
  flex-shrink: 0; height: 54px; padding: 0 24px; border: 0; cursor: pointer;
  border-radius: var(--radius-button, 14px); color: #fff; font-size: 15px; font-weight: 700;
  background: var(--grad); box-shadow: var(--elev-glow-soft, 0 8px 22px rgba(255,61,113,.26));
  transition: transform .14s ease, filter .2s ease;
  display: inline-flex; align-items: center; justify-content: center; gap: 8px; white-space: nowrap;
}
.waitlist .submit:hover { filter: brightness(1.05); }
.waitlist .submit:active { transform: scale(.96); }
.waitlist .submit[aria-busy="true"] { opacity: .7; pointer-events: none; }
.form-msg { min-height: 20px; margin: 12px 2px 0; font-size: 13px; font-weight: 600; }
.form-msg.left { text-align: left; }
.form-msg.err { color: var(--error, #FF5247); }
.form-msg.ok { color: var(--success, #2FBF87); }

.waitlist-done { max-width: 440px; margin: 26px auto 0; display: flex; align-items: center; gap: 14px; justify-content: center;
  background: var(--surface-2, #29211C); border: 1px solid var(--success, #2FBF87); border-radius: var(--radius-button, 14px); padding: 16px 20px; }
.waitlist-done.left { margin-inline: 0; justify-content: flex-start; }
.waitlist-done .tick { width: 32px; height: 32px; border-radius: 999px; background: var(--success, #2FBF87); color: #06281d; display: flex; align-items: center; justify-content: center; font-size: 16px; flex-shrink: 0; }
.waitlist-done b { display: block; font-size: 15px; color: var(--text-hi); }
.waitlist-done small { font-size: 13px; color: var(--text-med); }

/* ---------- Footer ---------- */
.footer { border-top: 1px solid var(--border-subtle, #2E2620); padding-block-start: var(--sec-pad); padding-block-end: clamp(40px, 6vh, 72px); position: relative; z-index: 2; }
.footer-grid { display: flex; align-items: flex-start; justify-content: space-between; gap: 32px; flex-wrap: wrap; }
.footer .tag { font-size: 14px; color: var(--text-low, #8E807A); margin-top: 14px; max-width: 30ch; }
.footer-base { display: flex; align-items: center; justify-content: space-between; gap: 16px; flex-wrap: wrap; margin-top: clamp(32px, 5vh, 56px); padding-top: 22px; border-top: 1px solid var(--border-subtle); font-size: 13px; color: var(--text-low); }
.tmdb-credit { font-size: 11px; line-height: 1.5; color: var(--text-low); margin: 14px 0 0; max-width: 40ch; }
.tmdb-credit a { color: var(--text-med); text-decoration: underline; }

/* ============================================================
   PORTED DESIGN-SYSTEM COMPONENTS
   (were inline-styled React components; now plain CSS classes)
   ============================================================ */

/* Tier color sets — applied to .score-chip / .sentiment-chip */
.t-loved    { --c-dot:#FF3D71; --c-text:#FF6B8A; --c-border:#FF3D71; --c-fill:rgba(255,61,113,.13); }
.t-liked    { --c-dot:#FF7A4D; --c-text:#FF8A5A; --c-border:#FF7A4D; --c-fill:rgba(255,122,77,.13); }
.t-okay     { --c-dot:#E0A06A; --c-text:#E0A06A; --c-border:#C99463; --c-fill:rgba(224,160,106,.13); }
.t-disliked { --c-dot:#9A8579; --c-text:#9A8579; --c-border:#9A8579; --c-fill:rgba(154,133,121,.13); }

/* PosterTile — real movie artwork (from TMDB) sized cover over a warm fallback.
   The striped seed classes remain as a graceful fallback if an image is missing. */
.poster {
  display: block; position: relative; aspect-ratio: 2 / 3; border-radius: var(--radius-poster, 16px);
  box-shadow: var(--elev-2, 0 8px 24px rgba(0,0,0,.45)); overflow: hidden; flex-shrink: 0;
  background-color: #2A211B; background-size: cover; background-position: center; background-repeat: no-repeat;
  transition: transform var(--dur-base, 200ms) var(--ease-standard, ease), opacity var(--dur-base, 200ms) ease, box-shadow var(--dur-base, 200ms) ease;
}
.poster.s0 { background-image: repeating-linear-gradient(135deg,#3A2E22 0 8px,#31271F 8px 16px); }
.poster.s1 { background-image: repeating-linear-gradient(135deg,#2A2433 0 8px,#231F2A 8px 16px); }
.poster.s2 { background-image: repeating-linear-gradient(135deg,#223A33 0 8px,#1F312A 8px 16px); }
.poster.s3 { background-image: repeating-linear-gradient(135deg,#322A3A 0 8px,#292233 8px 16px); }
.poster.dimmed { opacity: .45; }
.poster.won { box-shadow: 0 0 0 3px var(--accent, #FF3D71), var(--elev-glow, 0 12px 34px rgba(255,61,113,.4)); transform: scale(1.03); }
.poster .won-tick {
  position: absolute; top: 7px; right: 7px; width: 22px; height: 22px; border-radius: 999px;
  background: var(--accent-gradient, linear-gradient(135deg,#FF3D71,#FF8A3D));
  display: flex; align-items: center; justify-content: center; color: #fff; font-size: 12px;
}

/* ScoreChip — tier-tinted Nodu Score circle + label */
.score-chip { display: flex; flex-direction: column; align-items: center; gap: 3px; flex-shrink: 0; }
.score-chip .num {
  border-radius: 999px; display: flex; align-items: center; justify-content: center;
  font-family: var(--font-display, 'Fredoka', sans-serif); font-weight: 700;
  background: var(--c-fill); border: 1.5px solid var(--c-border); color: var(--c-text);
}
.score-chip .lbl {
  font-family: var(--font-body, 'Plus Jakarta Sans', sans-serif); font-size: 8.5px; font-weight: 800;
  letter-spacing: .4px; text-transform: uppercase; color: var(--c-text);
}

/* SentimentChip — small tier dot + label */
.sentiment-chip {
  display: inline-flex; align-items: center; gap: 6px; flex-shrink: 0;
  font-family: var(--font-body, 'Plus Jakarta Sans', sans-serif); font-size: 11px; font-weight: 800; color: var(--c-text);
}
.sentiment-chip .dot { width: 7px; height: 7px; border-radius: 2px; background: var(--c-dot); }

/* Avatar — circular initial tile (size + color via inline style) */
.avatar {
  border-radius: 999px; display: flex; align-items: center; justify-content: center; color: #fff;
  font-family: var(--font-body, 'Plus Jakarta Sans', sans-serif); font-weight: 800; flex-shrink: 0; overflow: hidden;
}

/* NoduWordmark — brush N + Fredoka "odu" */
.wordmark { display: inline-flex; align-items: flex-end; font-family: var(--font-display, 'Fredoka', sans-serif); font-weight: 600; line-height: 1; color: var(--text-hi, #FBF3EE); }
.wordmark svg { height: 1.16em; width: auto; display: block; margin-bottom: -.05em; }
.wordmark .odu { margin-left: -.12em; letter-spacing: -.02em; }

/* ============================================================
   REVEAL / MOTION UTILITIES
   ============================================================ */
/* Content is visible by default. The hidden start-state only engages once JS
   adds .reveal-on to <html> (inside requestAnimationFrame), so a context
   without rAF / JS keeps everything readable. */
[data-reveal] { transition: opacity var(--reveal-dur) var(--reveal-ease), transform var(--reveal-dur) var(--reveal-ease), filter var(--reveal-dur) var(--reveal-ease); transition-delay: var(--d, 0ms); }
.reveal-on [data-reveal] { opacity: 0; }
/* will-change only WHILE animating in — leaving it on permanently promotes the
   card to a compositing layer whose box-shadow paints square corners (the
   "triangle behind rounded cards" bug). Drop it once revealed. */
.reveal-on [data-reveal]:not(.is-in) { will-change: transform, opacity; }
.reveal-on [data-reveal="up"] { transform: translateY(46px); }
.reveal-on [data-reveal="down"] { transform: translateY(-40px); }
.reveal-on [data-reveal="left"] { transform: translateX(-54px); }
.reveal-on [data-reveal="right"] { transform: translateX(54px); }
.reveal-on [data-reveal="scale"] { transform: scale(.86); }
.reveal-on [data-reveal="blur"] { transform: translateY(28px); filter: blur(12px); }
.reveal-on [data-reveal="mask"] { transform: translateY(34px); clip-path: inset(0 0 100% 0); }
.reveal-on [data-reveal].is-in { opacity: 1; transform: none; filter: none; }
/* clip-path ONLY for the mask reveal. Applying it to every settled card pinned a
   RECTANGULAR clip at each card's rest box — which sliced the floating hero card's
   top/bottom as it bobbed past that rectangle ("goes under the viewport into the
   darkness") and clipped the drop-shadows. Scope it to mask, which is the only
   variant that needs it. */
.reveal-on [data-reveal="mask"].is-in { clip-path: inset(0 0 0 0); }

/* Maximal mode dials the reveal a touch springier + adds a slight overshoot */
[data-motion="max"] [data-reveal] { --reveal-ease: cubic-bezier(.18,.92,.26,1.06); }

[data-parallax] { will-change: transform; }

/* Reduced-motion + no-JS safety: everything visible, nothing pinned */
@media (prefers-reduced-motion: reduce) {
  [data-reveal] { opacity: 1 !important; transform: none !important; filter: none !important; clip-path: none !important; transition: none !important; }
  .bg-mesh { animation: none !important; }
  .rank-scene { height: auto !important; }
  .rank-sticky { position: static !important; height: auto !important; padding-block: 60px; }
}
html.no-js [data-reveal] { opacity: 1; transform: none; filter: none; clip-path: none; }

/* ============================================================
   ACCESSIBILITY
   ============================================================ */
.skip-link {
  position: absolute; left: -9999px; top: 0; z-index: 200;
  background: var(--accent, #FF3D71); color: #fff; padding: 10px 16px;
  border-radius: 0 0 12px 0; font-weight: 700; font-size: 14px;
}
.skip-link:focus { left: 0; }
:focus-visible { outline: 2px solid var(--accent-warm, #FF8A3D); outline-offset: 3px; border-radius: 4px; }
.nav-cta:focus-visible, .waitlist .submit:focus-visible { outline-offset: 4px; }
.visually-hidden { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }

/* ============================================================
   SCROLL-SNAP — desktop scrolls one full-viewport section at a time.
   Rank is a tall section: you snap in, scrub the list together, then
   snap on to Share. Mobile keeps natural flow; reduced-motion disables it.
   ============================================================ */
@media (min-width: 981px) and (prefers-reduced-motion: no-preference) {
  html { scroll-snap-type: y proximity; }
  /* Every section snaps EXCEPT Rank. Rank is a tall in-place scrub zone you
     free-scroll through (down or up); giving it its own snap point would sit a
     snap target in the middle of the scrub and disrupt the neighbouring
     sections. So it has no snap-align — you flow from Compare's snap, scrub the
     list together, and hand off to Share's snap. */
  .hero, .section:not(.rank-scene), .footer { scroll-snap-align: start; }
  .section:not(.rank-scene):not(.hero) {
    min-height: 100svh; display: flex; flex-direction: column; justify-content: center;
  }
}

/* ============================================================
   GUIDED MODE — when motion.js drives one-section-per-gesture scrolling it
   adds .guided to <html> (and turns off CSS snap inline). The window no longer
   free-scrolls, so Rank stops being a 200vh scroll-scrub and collapses into a
   single section whose stack animation plays on arrival. No-JS / reduced-motion
   viewports never get .guided, so they keep the scrub fallback above.
   ============================================================ */
html.guided .rank-scene { height: 100svh; }
html.guided .rank-sticky { position: relative; top: auto; }

/* ============================================================
   SECTION PAGER — desktop vertical dots (a port of the mobile .m-dots).
   Visual progress + quick-nav only; .nav-links and the footer carry the
   accessible navigation, so the pager is aria-hidden and not tab-focusable.
   Hidden under 981px — phones get the /m swipe experience.
   ============================================================ */
.pager { display: none; }

@media (min-width: 981px) {
  .pager {
    position: fixed; z-index: 40; top: 50%; right: clamp(16px, 2.4vw, 40px);
    transform: translateY(-50%);
    display: flex; flex-direction: column; align-items: flex-end; gap: 14px;
  }
  .pager-dot {
    position: relative; display: flex; align-items: center; justify-content: flex-end;
    width: 11px; height: 11px; padding: 0; border: 0; background: transparent;
    cursor: pointer; -webkit-appearance: none; appearance: none;
  }
  .pager-dot::after {
    content: ''; width: 9px; height: 9px; border-radius: 999px;
    background: rgba(251, 243, 238, .24);
    transition: background .3s ease, height .3s ease;
  }
  .pager-dot:hover::after { background: rgba(251, 243, 238, .55); }
  .pager-dot.is-on::after { background: var(--accent-1, #FF3D71); height: 22px; }

  /* hover tooltip — names each slide so the affordance reads at a glance */
  .pager-label {
    position: absolute; right: 22px; white-space: nowrap; pointer-events: none;
    font-family: var(--font-body, 'Plus Jakarta Sans', sans-serif);
    font-size: 12px; font-weight: 700; letter-spacing: .01em;
    color: var(--text-hi, #FBF3EE);
    padding: 5px 11px; border-radius: 9px;
    background: rgba(20, 16, 14, .9); border: 1px solid rgba(251, 243, 238, .1);
    box-shadow: 0 8px 24px rgba(0, 0, 0, .4);
    opacity: 0; transform: translateX(6px);
    transition: opacity .25s ease, transform .25s ease;
  }
  .pager-dot:hover .pager-label { opacity: 1; transform: translateX(0); }
}

@media (prefers-reduced-motion: reduce) {
  .pager-dot::after, .pager-label { transition: none; }
}

/* ============================================================
   RESPONSIVE — mobile is the priority experience
   ============================================================ */
@media (max-width: 980px) {
  .hero { min-height: auto; display: block; padding-top: clamp(96px, 14vh, 128px); padding-bottom: var(--sec-pad); }
  .hero-grid { grid-template-columns: 1fr; gap: 6px; }
  .hero-copy { max-width: 100%; }
  .hero-stage { width: 100%; max-width: 480px; margin: 28px auto 0; justify-self: center; }
  .act { grid-template-columns: 1fr; gap: 30px; }
  .act.flip .act-visual { order: 0; }
  .act-visual { min-height: 320px; order: 0; }
  .act-copy { max-width: 100%; }
  .rank-sticky { grid-template-columns: 1fr; align-content: center; gap: 18px; }
  .rank-copy { text-align: center; }
  .rank-progress { margin-inline: auto; }
  .rank-stage { order: 1; }
  .social-grid { grid-template-columns: 1fr; gap: 34px; }
  .social-grid .social-copy { order: -1; text-align: center; }
  .social-grid .lede { margin-inline: auto; }
}

@media (max-width: 640px) {
  .nav-links { display: none; }
  .nav { padding: 16px 18px; }
  .hero { padding-top: 104px; }
  .lede.wide, .lede { max-width: 100%; }
  .hero .lede { font-size: 16px; }
  .waitlist { flex-direction: column; }
  .waitlist .submit { width: 100%; }
  .waitlist .field { text-align: center; }
  .waitlist.left .field { text-align: left; }
  .facepile { justify-content: center; }
  .hero-foot { justify-content: flex-start; }
  .rank-scene { height: 178svh; }
  .rank-list { height: 500px; max-width: 400px; }
  .clash-or { width: 44px; height: 44px; font-size: 13px; }
  .footer-grid { flex-direction: column; gap: 24px; }
  .hide-sm { display: none !important; }
  .act-points li { font-size: 14px; }
}

@media (max-width: 380px) {
  .rank-list { max-width: 348px; }
}
