/* Homepage styles — extracted from index.html's <head> so they're cached
   between visits instead of re-downloaded inside every HTML response.
   Bump ?v= on the <link> in index.html when this file changes. */
    /* ─────────────────────────────────────────────────────────────────────
       Design system

       Restraint is the goal here. The previous version of this page leaned
       on a multi-stop red→purple→cyan gradient for every accent surface,
       which made everything feel equally loud and nothing feel important.
       This rewrite reserves the gradient for one moment per screen
       (typically the title) and lets the rest of the surface be
       near-monochrome with subtle palette tints in the background.

       Color variables map 1:1 to the iOS app's AlbumArtPalette tokens so
       this page reads as the same product as the screenshots we'll add
       later.
       ───────────────────────────────────────────────────────────────────── */
    :root {
      --bg:            #0A0A0F;
      --bg-elev-1:     rgba(255, 255, 255, 0.03);
      --bg-elev-2:     rgba(255, 255, 255, 0.05);
      --bg-elev-3:     rgba(255, 255, 255, 0.08);

      --fg:            #FFFFFF;
      --fg-secondary:  rgba(255, 255, 255, 0.62);
      --fg-tertiary:   rgba(255, 255, 255, 0.38);

      --hairline:      rgba(255, 255, 255, 0.08);
      --hairline-soft: rgba(255, 255, 255, 0.05);

      /* Curated StoryPalette pairs — same set as the iOS app's
         hand-curated story palettes. Replaces the generic purple-
         pink-amber multi-stop gradient (which made everything
         feel equally loud and nothing feel important) with bold
         solid pairs. The hero owns "Neon Dusk"; sections rotate
         through the others. */
      --neon-dusk-bg:     #1A1745;
      --neon-dusk-accent: #FF3B7A;
      --acid-summer-bg:     #D8FF3B;
      --acid-summer-accent: #FF1F8B;
      --citrus-glass-bg:     #0A22FF;
      --citrus-glass-accent: #FF8C1F;
      --vapor-bg:     #3BFFD8;
      --vapor-accent: #C18BFF;
      --late-drive-bg:     #0A0A0F;
      --late-drive-accent: #FFC83B;
      --marathon-bg:     #FF1F8B;
      --marathon-accent: #1FB8FF;
      --peak-sun-bg:     #FFD93B;
      --peak-sun-accent: #1A4D6B;

      /* Compatibility shims — old code paths reference these. They
         now resolve to the Neon Dusk palette so the palette change
         is non-breaking. */
      --vibe-purple:   var(--neon-dusk-bg);
      --vibe-pink:     var(--neon-dusk-accent);
      --vibe-blue:     #5AB4FF;
      --vibe-amber:    #FFB95A;

      /* Legacy gradient — kept narrow + only used in places that
         haven't been ported yet. New surfaces use solid palette. */
      --gradient: linear-gradient(135deg, var(--neon-dusk-accent) 0%, var(--peak-sun-bg) 100%);

      --radius-card: 24px;
      --radius-pill: 999px;

      --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
    }

    * { margin: 0; padding: 0; box-sizing: border-box; }
    *::selection { background: rgba(165, 107, 255, 0.40); color: white; }

    html { scroll-behavior: smooth; }

    body {
      font-family: "Inter Tight", -apple-system, BlinkMacSystemFont, system-ui, sans-serif;
      font-feature-settings: "ss01", "cv11";
      background: var(--bg);
      color: var(--fg);
      line-height: 1.5;
      -webkit-font-smoothing: antialiased;
      -moz-osx-font-smoothing: grayscale;
      overflow-x: hidden;
      min-height: 100vh;
      min-height: 100dvh;
    }

    /* Editorial pull-quote face — used only inside the song cards
       and in one feature title to provide rhythmic contrast. */
    .editorial { font-family: "Fraunces", Georgia, serif; font-style: italic; }

    /* ─────────────────────────────────────────────────────────────────────
       Mesh backdrop

       Three layered radial gradients composited at low saturation, blurred
       hard so they read as ambient color rather than discrete shapes. The
       drift animation moves them on a 30s cycle which is slow enough to
       feel atmospheric, not fidgety. Reduced-motion users get a static
       mesh — the design still works without movement.
       ───────────────────────────────────────────────────────────────────── */
    /* Hero backdrop — saturated Neon Dusk palette field that
       owns the upper viewport, with a bold coral accent circle
       bleeding off the top-right corner. The Wrapped signature.
       Replaces the prior multi-radial mesh that read as "ambient
       gradient" rather than "designed surface." */
    /* The mesh is the hero composition — solid Neon Dusk panel + a
       coral accent circle bleeding off the top-right + a soft peak-sun
       blob bottom-left. It used to be position:fixed which meant it
       followed the viewport on scroll and bled the coral accent over
       every downstream section. Now it's position:absolute pinned to
       the top of the page and capped at one viewport height, so the
       atmospherics are confined to the hero — and the page's solid
       --bg fills everything below. */
    .mesh {
      position: absolute;
      top: 0;
      left: 0;
      right: 0;
      height: 100vh;
      height: 100dvh;
      z-index: -2;
      background: var(--neon-dusk-bg);
      pointer-events: none;
      overflow: hidden;
    }
    .mesh::before {
      /* Big accent circle — half-bleeds off the top-right corner.
         Animates on a slow 30s drift so it feels alive without
         demanding attention. */
      content: "";
      position: absolute;
      top: -32vw;
      right: -28vw;
      width: 88vw;
      height: 88vw;
      max-width: 900px;
      max-height: 900px;
      border-radius: 50%;
      background: var(--neon-dusk-accent);
      opacity: 0.92;
      animation: drift 30s ease-in-out infinite alternate;
    }
    .mesh::after {
      /* Soft secondary blob bottom-left for atmospheric depth.
         Lower opacity so it reads as weather, not a focal element. */
      content: "";
      position: absolute;
      bottom: -20vw;
      left: -20vw;
      width: 60vw;
      height: 60vw;
      max-width: 700px;
      max-height: 700px;
      border-radius: 50%;
      background: var(--peak-sun-bg);
      opacity: 0.18;
      filter: blur(40px);
    }
    @keyframes drift {
      0%   { transform: translate3d(0, 0, 0) scale(1); }
      50%  { transform: translate3d(-3%, 2%, 0) scale(1.04); }
      100% { transform: translate3d(2%, -2%, 0) scale(1.02); }
    }

    /* Subtle film grain — sits above the mesh, below content. The opacity
       is tuned low (0.025) so it reads as texture, not noise. */
    .grain {
      position: fixed;
      inset: 0;
      pointer-events: none;
      z-index: -1;
      opacity: 0.025;
      background-image: url("data:image/png,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
    }

    @media (prefers-reduced-motion: reduce) {
      .mesh { animation: none; }
    }

    /* ─────────────────────────────────────────────────────────────────────
       Navigation
       ───────────────────────────────────────────────────────────────────── */
    nav {
      position: fixed;
      top: 24px;
      left: 50%;
      transform: translateX(-50%);
      z-index: 100;
      display: flex;
      align-items: center;
      gap: 8px;
      padding: 8px 8px 8px 16px;
      background: rgba(10, 10, 15, 0.55);
      backdrop-filter: blur(28px) saturate(1.4);
      -webkit-backdrop-filter: blur(28px) saturate(1.4);
      border: 1px solid var(--hairline);
      border-radius: var(--radius-pill);
      box-shadow:
        0 1px 0 rgba(255,255,255,0.06) inset,
        0 20px 40px rgba(0, 0, 0, 0.35);
    }

    .nav-logo {
      display: flex;
      align-items: center;
      gap: 10px;
      padding: 6px 10px 6px 4px;
      font-weight: 700;
      font-size: 15px;
      letter-spacing: -0.01em;
      text-decoration: none;
      color: var(--fg);
    }

    /*
      Brand mark — uses the actual app icon (1024×1024 JPEG cropped from
      Assets.xcassets). The wordmark inside the image reads "Vibes",
      matching the brand. The mark + "Vibes" text in the nav forms a
      consistent lockup at every size.

      object-fit: cover + a forced square frame keeps the rounded
      rectangle clean even when the source image isn't perfectly
      square-cropped. The shadow uses the logo's dominant purple to
      bleed the mark into the surrounding glass nav pill.
    */
    .nav-logo-mark {
      width: 28px; height: 28px;
      border-radius: 8px;
      overflow: hidden;
      box-shadow: 0 6px 18px rgba(165, 107, 255, 0.40);
      flex-shrink: 0;
    }
    .nav-logo-mark img {
      width: 100%; height: 100%;
      object-fit: cover;
      display: block;
    }

    .nav-links {
      display: flex;
      gap: 2px;
      margin-left: 4px;
    }
    .nav-links a {
      padding: 8px 14px;
      color: var(--fg-secondary);
      text-decoration: none;
      font-size: 14px;
      font-weight: 500;
      border-radius: var(--radius-pill);
      transition: color 0.2s ease, background 0.2s ease;
    }
    .nav-links a:hover { color: var(--fg); background: var(--bg-elev-2); }

    .nav-cta {
      padding: 9px 16px;
      background: var(--fg);
      color: var(--bg);
      text-decoration: none;
      font-weight: 600;
      font-size: 14px;
      border-radius: var(--radius-pill);
      transition: transform 0.2s var(--ease-out), box-shadow 0.2s var(--ease-out);
    }
    .nav-cta:hover {
      transform: translateY(-1px);
      box-shadow: 0 10px 28px rgba(255, 255, 255, 0.20);
    }

    /* ─────────────────────────────────────────────────────────────────────
       Hero
       ───────────────────────────────────────────────────────────────────── */
    .hero {
      min-height: 100dvh;
      display: flex;
      flex-direction: column;
      justify-content: center;
      padding: 160px 32px 96px;
      /* Full-bleed — let the aurora cover the entire viewport width.
         Content children below get their own max-width so the
         headline + CTA + ticker stay readable on wide monitors. */
      width: 100%;
      position: relative;
      overflow: hidden;
      isolation: isolate; /* so blend modes scope to the hero */
    }
    /* All real hero content sits above the ambient layers AND is
       constrained to the 1280px reading column, centered. */
    .hero > .eyebrow,
    .hero > .hero-title,
    .hero > .hero-audio,
    .hero > .hero-bottom,
    .hero > .hero-ticker {
      position: relative;
      z-index: 10;
      max-width: 1280px;
      margin-left: auto;
      margin-right: auto;
      width: 100%;
    }

    .eyebrow {
      display: inline-flex;
      align-items: center;
      gap: 10px;
      padding: 6px 14px 6px 6px;
      background: var(--bg-elev-1);
      border: 1px solid var(--hairline);
      border-radius: var(--radius-pill);
      font-size: 13px;
      color: var(--fg-secondary);
      letter-spacing: 0.005em;
      margin-bottom: 32px;
      width: fit-content;
    }
    /* Solid coral pill — replaces the multi-stop gradient with
       the curated Neon Dusk accent so the badge reads as part of
       the new design system. */
    .eyebrow-badge {
      padding: 4px 10px;
      background: var(--neon-dusk-accent);
      border-radius: var(--radius-pill);
      font-size: 11px;
      font-weight: 800;
      letter-spacing: 0.12em;
      text-transform: uppercase;
      color: white;
    }

    /* Wrapped-voice hero title — Antonio Bold condensed at
       display sizes, uppercase, hard negative tracking. Each
       word stacks on its own line so even a short title reads
       as a designed poster. The second word renders in palette
       accent — same "context word, KEY WORD" rhythm the iOS
       Profile / ShareHome / Discover heroes use. */
    .hero-title {
      font-family: "Antonio", "Arial Narrow", "Roboto Condensed", "Inter Tight", -apple-system, sans-serif;
      font-weight: 700;
      /* Lowered min from 72px to 48px so a 320–375px viewport
         doesn't force "NOT FEEDS" to overflow horizontally. The
         16vw mid-range still drives proportional scaling on
         tablets and desktop. */
      font-size: clamp(48px, 16vw, 200px);
      line-height: 0.86;
      letter-spacing: -0.04em;
      text-transform: uppercase;
      margin-bottom: 32px;
      color: var(--fg);
    }
    .hero-title .line {
      display: block;
      /* The reveal mask. Tight line-height (0.86) makes the glyphs taller
         than this box, so a plain overflow:hidden shears the BOTTOM of the
         letters (the "NOT FEEDS" cutoff). Pad the clip box down to clear the
         glyph descenders, then cancel that padding with a negative margin so
         the layout/stack spacing is unchanged. Rising chars stay invisible
         (they animate opacity 0 -> 1), so the mask still reads clean. */
      overflow: hidden;
      padding-bottom: 0.2em;
      margin-bottom: -0.2em;
    }
    .hero-title .line span {
      display: inline-block;
      animation: rise 1s var(--ease-out) both;
    }
    /* Second word lands in palette accent — Wrapped signature
       two-tone moment. */
    .hero-title .line:nth-child(2) span {
      animation-delay: 0.1s;
      color: var(--neon-dusk-accent);
    }
    @keyframes rise {
      from { transform: translateY(110%); }
      to   { transform: translateY(0); }
    }

    .hero-bottom {
      display: grid;
      grid-template-columns: 1fr auto;
      gap: 48px;
      align-items: end;
      margin-top: 48px;
    }
    .hero-description {
      max-width: 44ch;
      font-size: clamp(17px, 1.4vw, 19px);
      line-height: 1.55;
      color: var(--fg-secondary);
    }
    .hero-description b {
      color: var(--fg);
      font-weight: 600;
    }

    .hero-cta { display: flex; gap: 12px; }

    /* ─────────────────────────────────────────────────────────────────────
       HERO SPICE — ambient depth layers behind the headline.
       Stacked under the content via z-index. Each layer is decorative
       (aria-hidden in markup) and respects prefers-reduced-motion.
       ───────────────────────────────────────────────────────────────────── */

    /* 1. Aurora — four FULL-BLEED layers, each painting a single
       radial-gradient color spot anchored to a different corner.
       Because each layer is a rectangle that fills the whole hero,
       the only visible thing is the gradient itself (no circular
       div edge to draw a ring). Layers blend via mix-blend-mode
       to create the multi-color wash. */
    .hero-aurora {
      position: absolute;
      inset: 0;
      z-index: 0;
      pointer-events: none;
      overflow: hidden;
    }
    .aurora-blob {
      position: absolute;
      /* Extend past the hero so transform-drift doesn't reveal an edge */
      inset: -20%;
      filter: blur(40px) saturate(1.25);
      mix-blend-mode: screen;
      will-change: transform;
    }
    /* The gradient's "at X% Y%" places the saturated spot — the rest
       of the rectangle is fully transparent, so layers stack cleanly
       without any visible circle boundary. */
    .aurora-blob--pink {
      background: radial-gradient(circle at 18% 22%, #FF3B7A 0%, rgba(255,59,122,0.55) 18%, transparent 55%);
      animation: aurora-drift-a 28s ease-in-out infinite alternate;
    }
    .aurora-blob--yellow {
      background: radial-gradient(circle at 88% 12%, #FFD93B 0%, rgba(255,217,59,0.55) 18%, transparent 55%);
      animation: aurora-drift-b 34s ease-in-out infinite alternate;
    }
    .aurora-blob--cyan {
      background: radial-gradient(circle at 22% 92%, #3BFFD8 0%, rgba(59,255,216,0.5) 18%, transparent 58%);
      animation: aurora-drift-c 40s ease-in-out infinite alternate;
    }
    .aurora-blob--purple {
      background: radial-gradient(circle at 78% 82%, #C18BFF 0%, rgba(193,139,255,0.55) 18%, transparent 58%);
      animation: aurora-drift-d 32s ease-in-out infinite alternate;
    }
    /* Drift translations are intentionally small — the gradient
       spots wander a few percent of the hero, just enough to read
       as alive without changing the overall composition. */
    @keyframes aurora-drift-a {
      0%   { transform: translate(0, 0); }
      100% { transform: translate(6%, 4%); }
    }
    @keyframes aurora-drift-b {
      0%   { transform: translate(0, 0); }
      100% { transform: translate(-5%, 7%); }
    }
    @keyframes aurora-drift-c {
      0%   { transform: translate(0, 0); }
      100% { transform: translate(7%, -5%); }
    }
    @keyframes aurora-drift-d {
      0%   { transform: translate(0, 0); }
      100% { transform: translate(-6%, -4%); }
    }

    /* 2. Cursor spotlight — soft radial glow that tracks the mouse
       via CSS variables set in JS. mix-blend-mode lifts the type. */
    .hero-spotlight {
      position: absolute;
      inset: 0;
      z-index: 2;
      pointer-events: none;
      background: radial-gradient(
        circle 380px at var(--spot-x, 50%) var(--spot-y, 50%),
        rgba(255, 217, 59, 0.18) 0%,
        rgba(255, 59, 122, 0.10) 30%,
        transparent 70%
      );
      mix-blend-mode: screen;
      opacity: 0;
      transition: opacity 0.4s ease;
    }
    .hero:hover .hero-spotlight { opacity: 1; }

    /* 4. Per-letter reveal — replaces the old .line span animation.
       JS injects .char spans with --i index; CSS staggers from that. */
    .hero-title .line .char {
      display: inline-block;
      transform: translateY(110%);
      opacity: 0;
      animation: hero-char-rise 0.85s cubic-bezier(0.22, 1, 0.36, 1) forwards;
      animation-delay: calc(var(--i, 0) * 45ms + 0.1s);
      will-change: transform, opacity;
    }
    /* Second line starts after first finishes so the rhythm reads
       "SONGS" — beat — "NOT FEEDS" */
    .hero-title .line:nth-child(2) .char {
      animation-delay: calc(var(--i, 0) * 45ms + 0.55s);
    }
    @keyframes hero-char-rise {
      0%   { transform: translateY(110%) rotate(8deg); opacity: 0; }
      55%  { opacity: 1; }
      100% { transform: translateY(0) rotate(0); opacity: 1; }
    }
    /* Preserve spaces between split chars */
    .hero-title .char.space { width: 0.3em; }

    /* 6. Audio-meter underline under "NOT FEEDS" — five thin bars
       that pulse like a real-time audio meter, anchored to the
       second hero line. */
    .hero-meter {
      display: flex;
      gap: 6px;
      align-items: flex-end;
      height: 28px;
      margin-top: 12px;
      padding-left: 2px;
    }
    .hero-meter-bar {
      width: 6px;
      background: var(--neon-dusk-accent, #FF3B7A);
      border-radius: 3px;
      animation: meter-pulse 1.1s ease-in-out infinite;
      transform-origin: bottom;
    }
    .hero-meter-bar:nth-child(1) { animation-delay: 0.00s; background: #FFD93B; }
    .hero-meter-bar:nth-child(2) { animation-delay: 0.12s; background: #FF3B7A; }
    .hero-meter-bar:nth-child(3) { animation-delay: 0.24s; background: #C18BFF; }
    .hero-meter-bar:nth-child(4) { animation-delay: 0.36s; background: #3BFFD8; }
    .hero-meter-bar:nth-child(5) { animation-delay: 0.48s; background: #FFC83B; }
    @keyframes meter-pulse {
      0%, 100% { height: 8px; opacity: 0.55; }
      50%      { height: 28px; opacity: 1; }
    }

    /* ─────────────────────────────────────────────────────────────────────
       AUDIO-REACTIVE HERO — the whole hero breathes with the music.
       preview-player.js publishes two smoothed 0..1 signals as CSS vars
       (--audio-bass, --audio-level) and toggles `.is-audio-live` on the
       hero while a preview plays. All motion is scoped under that class,
       so the resting state is completely unchanged. Vars default to 0.
       ───────────────────────────────────────────────────────────────────── */
    .hero { --audio-bass: 0; --audio-level: 0; }

    /* Aurora breathes with the bass. Scale/opacity live on the .hero-aurora
       CONTAINER (which has no transform of its own) so we never fight the
       per-blob drift animations. A tasteful swell, not a strobe. */
    .hero.is-audio-live .hero-aurora {
      transform: scale(calc(1 + var(--audio-bass) * 0.12));
      opacity: calc(0.85 + var(--audio-bass) * 0.15);
      transition: transform 0.09s ease-out, opacity 0.12s ease-out;
      will-change: transform, opacity;
    }

    /* Headline thickens a hair with bass and glows with overall level.
       Antonio isn't a variable font here, so we use micro-scale + a
       text-shadow glow. Motion is a couple percent so type stays crisp. */
    .hero.is-audio-live .hero-title {
      transform: scale(calc(1 + var(--audio-bass) * 0.02));
      transform-origin: left center;
      text-shadow: 0 0 calc(var(--audio-level) * 26px) rgba(255, 59, 122, calc(var(--audio-level) * 0.55));
      transition: transform 0.09s ease-out, text-shadow 0.12s ease-out;
      will-change: transform;
    }

    /* Optional global accent glow — the play button pulses on the beat. */
    .hero.is-audio-live .hero-play {
      box-shadow: 0 0 calc(var(--audio-level) * 34px) rgba(255, 59, 122, calc(var(--audio-level) * 0.5));
      transition: box-shadow 0.12s ease-out, transform .2s cubic-bezier(.16,1,.3,1), background .2s ease;
    }

    /* Reduced motion: the vars still update, but nothing moves or glows.
       Audio keeps playing; the page just doesn't dance. */
    @media (prefers-reduced-motion: reduce) {
      .hero.is-audio-live .hero-aurora,
      .hero.is-audio-live .hero-title,
      .hero.is-audio-live .hero-play {
        transform: none !important;
        text-shadow: none !important;
        box-shadow: none !important;
        opacity: initial;
        transition: none !important;
      }
    }

    /* ─────────────────────────────────────────────────────────────────────
       WEBGL LIVING GRADIENT — the <canvas class="hero-shader"> is created
       and appended by js/hero-shader.js ONLY when WebGL is available AND
       prefers-reduced-motion is not set. It sits above the aurora (z 0) and
       below the cursor spotlight (z 2) + hero content (z 10). Purely
       decorative and non-interactive. When the shader inits, JS adds
       `.hero--shader`; if it never inits (no WebGL / reduced motion) the
       class is never added and the CSS aurora stays as the fallback.
       ───────────────────────────────────────────────────────────────────── */
    .hero-shader {
      position: absolute;
      inset: 0;
      z-index: 1;
      width: 100%;
      height: 100%;
      display: block;
      pointer-events: none;
      opacity: 0;
      transition: opacity 1.2s ease;
    }
    .hero--shader .hero-shader { opacity: 1; }
    /* Fade the CSS aurora down while the shader is live so the two don't
       double up. Specificity (0,3,0) matches the audio-live aurora rule
       above and this comes LATER in source, so it wins in both the resting
       and the is-audio-live states. */
    .hero.hero--shader .hero-aurora {
      opacity: 0.25;
      transition: opacity 1.2s ease;
    }

    /* Audio waveform ribbon (js/hero-viz.js) — a soft glowing soundwave
       along the lower hero that undulates ambiently and swells to the real
       preview's frequencies. Sits above the shader, below the hero content,
       screen-blended so its glow melts into the dark gradient. Decorative. */
    .hero-viz {
      position: absolute;
      left: 0;
      bottom: 0;
      width: 100%;
      height: 34%;
      z-index: 2;
      pointer-events: none;
      opacity: 0.5;
      mix-blend-mode: screen;
    }
    .hero.is-audio-live .hero-viz { opacity: 0.72; } /* brighter while a song plays */
    @media (prefers-reduced-motion: reduce) { .hero-viz { opacity: 0.32; } }

    /* 7. Live "now playing" ticker — horizontal marquee at the
       bottom of the hero rotating recent send/receive events. */
    .hero-ticker {
      margin-top: 56px;
      position: relative;
      overflow: hidden;
      /* Hidden until real vibes are rendered (or a no-data fallback
         reveals the seed names) — so we never flash stock then swap. */
      opacity: 0;
      transition: opacity .45s ease;
      mask-image: linear-gradient(
        to right,
        transparent 0,
        black 8%,
        black 92%,
        transparent 100%
      );
      -webkit-mask-image: linear-gradient(
        to right,
        transparent 0,
        black 8%,
        black 92%,
        transparent 100%
      );
    }
    .hero-ticker.is-ready { opacity: 1; }
    .ticker-track {
      display: flex;
      gap: 48px;
      align-items: center;
      width: max-content;
      animation: ticker-scroll 110s linear infinite;
      will-change: transform;
    }
    .ticker-track:hover { animation-play-state: paused; }
    .ticker-item {
      display: inline-flex;
      align-items: center;
      gap: 10px;
      font-family: "Inter Tight", -apple-system, sans-serif;
      font-size: 13px;
      letter-spacing: 0.02em;
      color: rgba(255, 255, 255, 0.55);
      white-space: nowrap;
    }
    .ticker-item b {
      color: var(--fg, white);
      font-weight: 600;
    }
    .ticker-item em {
      font-family: "Fraunces", serif;
      font-style: italic;
      color: rgba(255, 255, 255, 0.85);
      font-weight: 400;
    }
    .ticker-dot {
      width: 6px;
      height: 6px;
      border-radius: 50%;
      flex-shrink: 0;
    }
    @keyframes ticker-scroll {
      from { transform: translateX(0); }
      to   { transform: translateX(-50%); }
    }

    /* Reduced motion: kill the kinetic decoration */
    @media (prefers-reduced-motion: reduce) {
      .aurora-blob,
      .hero-meter-bar,
      .ticker-track,
      .hero-title .line .char {
        animation: none !important;
        transform: translate(0) !important;
        opacity: 1 !important;
      }
      .hero-title .line .char { transform: none !important; }
      .hero-spotlight { display: none; }
    }

    /* Buttons */
    .btn {
      display: inline-flex;
      align-items: center;
      gap: 10px;
      padding: 16px 24px;
      border-radius: var(--radius-pill);
      font-weight: 600;
      font-size: 15px;
      text-decoration: none;
      letter-spacing: -0.005em;
      border: 1px solid transparent;
      transition: transform 0.2s var(--ease-out), box-shadow 0.2s var(--ease-out), background 0.2s ease;
    }
    .btn:active { transform: scale(0.98); }
    .btn-primary {
      background: var(--fg);
      color: var(--bg);
    }
    .btn-primary:hover {
      transform: translateY(-1px);
      box-shadow: 0 16px 36px rgba(255, 255, 255, 0.18);
    }
    .btn-primary svg { transition: transform 0.2s var(--ease-out); }
    .btn-primary:hover svg { transform: translateX(3px); }

    .btn-ghost {
      background: transparent;
      border-color: var(--hairline);
      color: var(--fg);
    }
    .btn-ghost:hover { background: var(--bg-elev-2); border-color: var(--bg-elev-3); }

    /* ─────────────────────────────────────────────────────────────────────
       Quiet rule between hero and bento — replaces the old marquee, which
       advertised "Beautiful UI / Dark Mode / Real-time Previews" and read
       as a checklist of table-stakes features. Three honest values feel
       more like a manifesto, less like a feature comparison sheet.
       ───────────────────────────────────────────────────────────────────── */
    /* Manifesto — Wrapped voice. Each rule is a small poster, big
       Antonio condensed numeral as the visual anchor + uppercase
       headline + editorial follow-up clause. Borderless so the rules
       feel like they sit directly on the page rather than in a
       container. */
    .manifesto {
      max-width: 1280px;
      margin: 0 auto;
      padding: 64px 32px 32px;
      display: grid;
      grid-template-columns: repeat(3, 1fr);
      gap: 48px;
    }
    .manifesto-item {
      display: flex;
      flex-direction: column;
      gap: 12px;
    }
    .manifesto-num {
      font-family: "Antonio", "Arial Narrow", "Roboto Condensed", "Inter Tight", -apple-system, sans-serif;
      font-weight: 700;
      font-size: clamp(56px, 6vw, 88px);
      line-height: 0.86;
      letter-spacing: -0.04em;
      color: var(--neon-dusk-accent);
    }
    .manifesto-line {
      font-family: "Antonio", "Arial Narrow", "Roboto Condensed", "Inter Tight", -apple-system, sans-serif;
      font-weight: 700;
      font-size: clamp(22px, 2.4vw, 30px);
      line-height: 1.05;
      letter-spacing: -0.02em;
      text-transform: uppercase;
      color: var(--fg);
    }
    .manifesto-line .editorial {
      display: block;
      margin-top: 6px;
      text-transform: none;
      letter-spacing: -0.01em;
      font-size: 0.7em;
      color: var(--fg-secondary);
    }
    /* Stagger the manifesto numerals across the curated palette so each
       rule has its own colour. Reads as a hand-set spread, not a row of
       three identical cards. */
    .manifesto-item:nth-child(1) .manifesto-num { color: var(--neon-dusk-accent); }
    .manifesto-item:nth-child(2) .manifesto-num { color: var(--peak-sun-bg); }
    .manifesto-item:nth-child(3) .manifesto-num { color: var(--vapor-bg); }

    /* ─────────────────────────────────────────────────────────────────────
       Moment picker demo — interactive vinyl on the homepage.
       Late-drive palette (dark page + amber accent) so the disc reads
       as a real turntable. Pure visual interaction: drag the disc, the
       readout updates, "Pick this moment" gives a satisfying double-
       spin confirmation. No audio (Apple owns the 30-second preview
       window for anonymous visitors and we don't want to play a
       different window than the user picked).
       ───────────────────────────────────────────────────────────────────── */
    .home-moment {
      padding: 96px 32px;
      background: var(--bg, #0A0A0F);
      position: relative;
      overflow: hidden;
    }
    .home-moment-inner {
      max-width: 1280px;
      margin: 0 auto;
      display: grid;
      grid-template-columns: 1fr 1fr;
      gap: 64px;
      align-items: center;
    }
    @media (max-width: 900px) {
      .home-moment-inner {
        grid-template-columns: 1fr;
        gap: 48px;
        text-align: center;
      }
    }

    .home-moment-kicker {
      display: inline-block;
      font-family: "Antonio", "Arial Narrow", "Roboto Condensed", "Inter Tight", -apple-system, sans-serif;
      font-weight: 700;
      font-size: 12px;
      letter-spacing: 0.18em;
      text-transform: uppercase;
      color: var(--late-drive-accent, #FFC83B);
      padding: 6px 12px;
      border: 1px solid rgba(255, 200, 59, 0.32);
      border-radius: var(--radius-pill);
      margin-bottom: 24px;
    }
    .home-moment-title {
      font-family: "Antonio", "Arial Narrow", "Roboto Condensed", "Inter Tight", -apple-system, sans-serif;
      font-weight: 700;
      font-size: clamp(40px, 5.5vw, 80px);
      line-height: 0.92;
      letter-spacing: -0.03em;
      text-transform: uppercase;
      color: var(--fg, white);
      margin: 0 0 20px;
      max-width: 14ch;
    }
    .home-moment-title .editorial {
      color: var(--late-drive-accent, #FFC83B);
      text-transform: none;
    }
    .home-moment-lede {
      font-size: clamp(16px, 1.3vw, 18px);
      line-height: 1.55;
      color: var(--fg-secondary, rgba(255,255,255,0.74));
      max-width: 48ch;
      margin: 0 0 24px;
    }
    .home-moment-track {
      display: inline-flex;
      flex-direction: column;
      gap: 4px;
      margin: 0;
    }
    .home-moment-track-eyebrow {
      font-family: "Antonio", sans-serif;
      font-weight: 700;
      font-size: 10px;
      letter-spacing: 0.20em;
      text-transform: uppercase;
      color: rgba(255, 255, 255, 0.46);
    }
    .home-moment-track-name {
      font-family: "Fraunces", Georgia, serif;
      font-style: italic;
      font-size: 16px;
      color: var(--fg, white);
    }

    /* ── Stage: vinyl + readout + button ────────────────────────── */
    .home-moment-stage {
      display: flex;
      flex-direction: column;
      align-items: center;
      gap: 28px;
    }
    .home-moment-disc-wrap {
      position: relative;
      width: min(380px, 90vw);
      aspect-ratio: 1 / 1;
      /* Tonearm needs room to bleed past the disc on the upper-right */
      padding: 28px 28px 0 0;
    }
    .home-moment-disc {
      position: relative;
      width: 100%;
      height: 100%;
      border-radius: 50%;
      background: radial-gradient(circle, #1a1a22 0%, #0A0A0F 70%);
      box-shadow:
        0 0 0 1px rgba(255, 255, 255, 0.06) inset,
        0 24px 60px rgba(0, 0, 0, 0.55),
        0 0 0 6px rgba(0, 0, 0, 0.4);
      cursor: grab;
      touch-action: none;
      /* No transform-origin shift; default center is correct */
      will-change: transform;
      user-select: none;
      -webkit-user-select: none;
    }
    .home-moment-disc:active,
    .home-moment-disc.is-dragging {
      cursor: grabbing;
    }
    .home-moment-disc:focus-visible {
      outline: 2px solid var(--late-drive-accent, #FFC83B);
      outline-offset: 8px;
    }
    /* Concentric grooves — drawn with a repeating radial gradient. */
    .home-moment-grooves {
      position: absolute;
      inset: 0;
      border-radius: 50%;
      background: repeating-radial-gradient(
        circle at center,
        rgba(255, 255, 255, 0.06) 0px,
        rgba(255, 255, 255, 0.06) 1px,
        transparent 1px,
        transparent 5px
      );
      pointer-events: none;
    }
    /* Center label — amber/gold like the iOS picker. */
    .home-moment-label {
      position: absolute;
      inset: 34%;
      border-radius: 50%;
      background:
        radial-gradient(circle at 35% 35%, #FFE07A, var(--late-drive-accent, #FFC83B) 70%);
      box-shadow:
        0 0 0 1px rgba(0, 0, 0, 0.25) inset,
        0 4px 12px rgba(0, 0, 0, 0.4);
      display: grid;
      place-items: center;
      pointer-events: none;
    }
    .home-moment-label-text {
      font-family: "Antonio", sans-serif;
      font-weight: 700;
      font-size: 14px;
      letter-spacing: 0.22em;
      color: #0A0A0F;
      opacity: 0.85;
    }
    /* Spindle hole at the very center. */
    .home-moment-spindle {
      position: absolute;
      top: 50%; left: 50%;
      width: 8px; height: 8px;
      margin: -4px 0 0 -4px;
      border-radius: 50%;
      background: #0A0A0F;
      box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.06);
      pointer-events: none;
    }
    /* Tick mark on the outer edge — makes the rotation visible
       even when the disc is moving slowly. */
    .home-moment-tick {
      position: absolute;
      top: 4%; left: 50%;
      width: 4px; height: 16px;
      margin-left: -2px;
      border-radius: 2px;
      background: var(--late-drive-accent, #FFC83B);
      opacity: 0.95;
      box-shadow: 0 0 8px rgba(255, 200, 59, 0.6);
      pointer-events: none;
    }

    /* Tonearm — pivot at top-right, needle tip extends to the disc's
       12 o'clock. Stays fixed while the disc spins underneath. */
    .home-moment-cartridge {
      position: absolute;
      top: 0;
      right: 0;
      width: 50%;
      height: 50%;
      pointer-events: none;
      transform-origin: top right;
      transform: rotate(-12deg);
    }
    .home-moment-cartridge-arm {
      position: absolute;
      top: 8px;
      right: 8px;
      width: 4px;
      height: 80%;
      background: linear-gradient(to bottom, #6E6E76, #2A2A2E);
      border-radius: 2px;
      transform-origin: top center;
      transform: rotate(28deg);
      box-shadow: 0 4px 10px rgba(0, 0, 0, 0.5);
    }
    .home-moment-cartridge-head {
      position: absolute;
      top: 0;
      right: -2px;
      width: 22px;
      height: 22px;
      border-radius: 50%;
      background: radial-gradient(circle, #A5A5AB, #4A4A50);
      box-shadow: 0 4px 10px rgba(0, 0, 0, 0.5);
    }
    .home-moment-needle-tip {
      position: absolute;
      bottom: -8px;
      left: 32%;
      width: 6px;
      height: 18px;
      border-radius: 3px;
      background: var(--late-drive-accent, #FFC83B);
      box-shadow: 0 0 10px rgba(255, 200, 59, 0.7);
      transform: rotate(28deg);
      transform-origin: top center;
    }

    /* Readout — start → end timestamp + "of {total}" */
    .home-moment-readout {
      display: inline-flex;
      align-items: baseline;
      gap: 10px;
      padding: 12px 22px;
      border-radius: var(--radius-pill);
      background: rgba(255, 200, 59, 0.06);
      border: 1px solid rgba(255, 200, 59, 0.18);
    }
    .home-moment-time {
      font-family: "Antonio", sans-serif;
      font-weight: 700;
      font-size: 22px;
      letter-spacing: 0.04em;
      color: var(--late-drive-accent, #FFC83B);
      font-variant-numeric: tabular-nums;
    }
    .home-moment-arrow {
      font-family: "Antonio", sans-serif;
      font-size: 20px;
      color: rgba(255, 200, 59, 0.55);
    }
    .home-moment-of {
      font-size: 12px;
      letter-spacing: 0.06em;
      color: rgba(255, 255, 255, 0.46);
      text-transform: uppercase;
      font-family: "Antonio", sans-serif;
    }

    .home-moment-pick {
      padding: 14px 28px;
      border-radius: var(--radius-pill);
      border: none;
      cursor: pointer;
      font-family: inherit;
      font-weight: 700;
      font-size: 13px;
      letter-spacing: 0.16em;
      text-transform: uppercase;
      background: var(--fg, white);
      color: var(--bg, #0A0A0F);
      transition: transform 0.2s var(--ease-out),
                  box-shadow 0.2s var(--ease-out),
                  background 0.2s ease;
    }
    .home-moment-pick:hover {
      transform: translateY(-1px);
      box-shadow: 0 14px 28px rgba(255, 200, 59, 0.20);
    }
    .home-moment-pick.is-confirmed {
      background: var(--late-drive-accent, #FFC83B);
      color: #0A0A0F;
    }
    .home-moment-fine {
      margin: 0;
      font-size: 13px;
      color: rgba(255, 255, 255, 0.55);
      max-width: 32ch;
      text-align: center;
    }
    .home-moment-fine .editorial { color: var(--late-drive-accent, #FFC83B); }

    /* Reduced motion — keep the disc still on confirm (no spin) */
    @media (prefers-reduced-motion: reduce) {
      .home-moment-disc { transition: none !important; }
    }

    /* ─────────────────────────────────────────────────────────────────────
       Postcard composer — full-bleed citrus-glass section between the
       moment picker and the Android band. Deep-blue ground, orange
       accent. Two columns on desktop: composer form left, live preview
       right. Stacks on mobile.
       ───────────────────────────────────────────────────────────────────── */
    .home-postcard {
      padding: 96px 32px;
      background: var(--citrus-glass-bg);
      color: white;
      position: relative;
      overflow: hidden;
    }
    /* Decorative accent disc bottom-left — Wrapped poster nod */
    .home-postcard::before {
      content: "";
      position: absolute;
      left: -160px;
      bottom: -180px;
      width: 460px;
      height: 460px;
      border-radius: 50%;
      background: var(--citrus-glass-accent);
      opacity: 0.18;
      pointer-events: none;
    }
    .home-postcard-inner {
      max-width: 1280px;
      margin: 0 auto;
      display: grid;
      grid-template-columns: 1fr 1fr;
      gap: 64px;
      align-items: start;
      position: relative;
      z-index: 2;
    }
    @media (max-width: 900px) {
      .home-postcard-inner {
        grid-template-columns: 1fr;
        gap: 48px;
      }
    }

    .home-postcard-kicker {
      display: inline-block;
      font-family: "Antonio", "Arial Narrow", "Roboto Condensed", "Inter Tight", -apple-system, sans-serif;
      font-weight: 700;
      font-size: 12px;
      letter-spacing: 0.18em;
      text-transform: uppercase;
      color: var(--citrus-glass-accent);
      padding: 6px 12px;
      border: 1px solid rgba(255, 140, 31, 0.32);
      border-radius: var(--radius-pill);
      margin-bottom: 24px;
    }
    .home-postcard-title {
      font-family: "Antonio", "Arial Narrow", "Roboto Condensed", "Inter Tight", -apple-system, sans-serif;
      font-weight: 700;
      font-size: clamp(40px, 5.5vw, 80px);
      line-height: 0.92;
      letter-spacing: -0.03em;
      text-transform: uppercase;
      color: white;
      margin: 0 0 16px;
      max-width: 14ch;
    }
    .home-postcard-title .editorial {
      color: var(--citrus-glass-accent);
      text-transform: none;
    }
    .home-postcard-lede {
      font-size: 16px;
      line-height: 1.55;
      color: rgba(255, 255, 255, 0.78);
      max-width: 44ch;
      margin: 0 0 32px;
    }

    /* ── Form fields ──────────────────────────────────────────── */
    .home-postcard-form {
      display: grid;
      gap: 18px;
    }
    .home-postcard-field {
      display: grid;
      gap: 6px;
      position: relative;
    }
    .home-postcard-fieldlabel {
      font-family: "Antonio", sans-serif;
      font-weight: 700;
      font-size: 11px;
      letter-spacing: 0.16em;
      text-transform: uppercase;
      color: rgba(255, 255, 255, 0.62);
    }
    .home-postcard-optional {
      font-family: "Fraunces", Georgia, serif;
      font-style: italic;
      letter-spacing: 0.02em;
      color: rgba(255, 255, 255, 0.42);
      text-transform: none;
    }
    .home-postcard-form input[type="text"],
    .home-postcard-form textarea {
      padding: 14px 18px;
      border: 1px solid rgba(255, 255, 255, 0.18);
      border-radius: 14px;
      background: rgba(255, 255, 255, 0.06);
      font-family: inherit;
      font-size: 15px;
      color: white;
      transition: border-color 0.2s ease, background 0.2s ease;
      width: 100%;
    }
    .home-postcard-form input[type="text"]::placeholder,
    .home-postcard-form textarea::placeholder {
      color: rgba(255, 255, 255, 0.42);
    }
    .home-postcard-form input[type="text"]:focus,
    .home-postcard-form textarea:focus {
      outline: none;
      border-color: var(--citrus-glass-accent);
      background: rgba(255, 255, 255, 0.10);
    }
    .home-postcard-form textarea {
      resize: vertical;
      font-family: "Fraunces", Georgia, serif;
      font-style: italic;
      line-height: 1.4;
    }
    .home-postcard-counter {
      position: absolute;
      right: 6px;
      bottom: -18px;
      font-family: "Antonio", sans-serif;
      font-size: 10px;
      letter-spacing: 0.10em;
      color: rgba(255, 255, 255, 0.42);
    }

    /* Song search dropdown */
    .home-postcard-results {
      position: absolute;
      top: 100%;
      left: 0; right: 0;
      margin-top: 6px;
      background: #0F0F18;
      border: 1px solid rgba(255, 255, 255, 0.10);
      border-radius: 14px;
      box-shadow: 0 24px 60px rgba(0, 0, 0, 0.55);
      max-height: 320px;
      overflow-y: auto;
      z-index: 5;
    }
    .home-postcard-results[hidden] { display: none; }
    .home-postcard-result {
      display: flex;
      align-items: center;
      gap: 12px;
      padding: 10px 12px;
      cursor: pointer;
      transition: background 0.15s ease;
    }
    .home-postcard-result:hover,
    .home-postcard-result.is-focused {
      background: rgba(255, 140, 31, 0.10);
    }
    .home-postcard-result img {
      width: 40px; height: 40px;
      border-radius: 6px;
      object-fit: cover;
      flex-shrink: 0;
    }
    .home-postcard-result-meta {
      display: flex;
      flex-direction: column;
      min-width: 0;
    }
    .home-postcard-result-title {
      font-size: 14px;
      font-weight: 600;
      color: white;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
    }
    .home-postcard-result-artist {
      font-size: 12px;
      color: rgba(255, 255, 255, 0.6);
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
    }

    /* Picked-song chip — replaces the search input when chosen */
    .home-postcard-picked {
      display: flex;
      align-items: center;
      gap: 12px;
      padding: 10px 12px;
      background: rgba(255, 140, 31, 0.10);
      border: 1px solid rgba(255, 140, 31, 0.40);
      border-radius: 14px;
      margin-top: 6px;
    }
    .home-postcard-picked[hidden] { display: none; }
    .home-postcard-picked img {
      width: 44px; height: 44px;
      border-radius: 6px;
      object-fit: cover;
      flex-shrink: 0;
    }
    .home-postcard-picked-meta {
      flex: 1;
      display: flex;
      flex-direction: column;
      min-width: 0;
    }
    .home-postcard-picked-title {
      font-size: 14px;
      font-weight: 600;
      color: white;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
    }
    .home-postcard-picked-artist {
      font-size: 12px;
      color: rgba(255, 255, 255, 0.74);
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
    }
    .home-postcard-picked-clear {
      width: 30px; height: 30px;
      border-radius: 50%;
      border: 1px solid rgba(255, 255, 255, 0.24);
      background: transparent;
      color: white;
      font-size: 18px;
      cursor: pointer;
      flex-shrink: 0;
      line-height: 1;
    }

    /* Generate button */
    #postcardGenerate {
      margin-top: 10px;
      padding: 16px 28px;
      border-radius: var(--radius-pill);
      border: none;
      cursor: pointer;
      font-family: inherit;
      font-weight: 600;
      font-size: 15px;
      letter-spacing: -0.005em;
      background: white;
      color: var(--citrus-glass-bg);
      transition: transform 0.2s var(--ease-out),
                  box-shadow 0.2s var(--ease-out),
                  background 0.2s ease, color 0.2s ease;
    }
    #postcardGenerate:hover:not(:disabled) {
      transform: translateY(-1px);
      box-shadow: 0 14px 28px rgba(255, 140, 31, 0.32);
      background: var(--citrus-glass-accent);
      color: white;
    }
    #postcardGenerate:disabled {
      opacity: 0.4;
      cursor: not-allowed;
    }
    /* Inline validation hint — shows up beside disabled button */
    .home-postcard-hint {
      margin-top: 8px;
      font-family: "Fraunces", Georgia, serif;
      font-style: italic;
      font-size: 13px;
      color: rgba(255, 255, 255, 0.46);
      min-height: 1.4em;
      transition: opacity 0.3s ease;
    }
    .home-postcard-hint.is-quiet {
      opacity: 0;
    }
    @keyframes postcard-burst-fly {
      0%   { opacity: 1; transform: translate(0, 0) scale(0.6); }
      60%  { opacity: 1; }
      100% { opacity: 0; transform: translate(var(--bx, 0), var(--by, 0)) scale(1); }
    }

    /* ── Live preview ─────────────────────────────────────────── */
    .home-postcard-stage {
      position: relative;
      min-height: 480px;
    }
    .home-postcard-preview {
      position: relative;
      width: 100%;
      aspect-ratio: 4 / 5;
      border-radius: 24px;
      overflow: hidden;
      background: rgba(255, 255, 255, 0.04);
      border: 1px solid rgba(255, 255, 255, 0.10);
      box-shadow: 0 24px 60px rgba(0, 0, 0, 0.4);
      transition: background 0.4s ease, border-color 0.4s ease;
    }
    .home-postcard-preview-empty {
      position: absolute;
      inset: 0;
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      gap: 8px;
      color: rgba(255, 255, 255, 0.55);
      text-align: center;
      padding: 24px;
    }
    .home-postcard-preview-empty-eyebrow {
      font-family: "Antonio", sans-serif;
      font-weight: 700;
      font-size: 11px;
      letter-spacing: 0.18em;
      text-transform: uppercase;
      opacity: 0.6;
    }
    .home-postcard-preview-empty-title {
      font-family: "Fraunces", Georgia, serif;
      font-style: italic;
      font-size: 22px;
    }

    /* Card composition — the actual postcard render (shared with /p/) */
    .pc {
      position: absolute;
      inset: 0;
      padding: 36px;
      display: flex;
      flex-direction: column;
      justify-content: space-between;
      color: var(--pc-fg, white);
      background: var(--pc-bg, #1A1745);
    }
    .pc::before {
      content: "";
      position: absolute;
      right: -120px;
      top: -100px;
      width: 380px; height: 380px;
      border-radius: 50%;
      background: var(--pc-accent, #FF3B7A);
      opacity: 0.22;
      pointer-events: none;
    }
    .pc-eyebrow {
      font-family: "Antonio", sans-serif;
      font-weight: 700;
      font-size: 12px;
      letter-spacing: 0.20em;
      text-transform: uppercase;
      color: var(--pc-fg-muted, rgba(255,255,255,0.74));
      position: relative;
      z-index: 1;
    }
    .pc-recipient {
      font-family: "Antonio", sans-serif;
      font-weight: 700;
      font-size: clamp(40px, 6vw, 84px);
      line-height: 0.86;
      letter-spacing: -0.04em;
      text-transform: uppercase;
      margin: 6px 0 0;
      position: relative;
      z-index: 1;
      word-break: break-word;
    }
    .pc-mid {
      display: flex;
      align-items: center;
      gap: 16px;
      position: relative;
      z-index: 1;
    }
    .pc-art {
      width: 88px; height: 88px;
      border-radius: 10px;
      object-fit: cover;
      flex-shrink: 0;
      box-shadow: 0 8px 20px rgba(0, 0, 0, 0.4);
    }
    .pc-track {
      display: flex;
      flex-direction: column;
      gap: 2px;
      min-width: 0;
    }
    .pc-track-title {
      font-family: "Fraunces", Georgia, serif;
      font-style: italic;
      font-size: clamp(18px, 2vw, 26px);
      font-weight: 500;
      line-height: 1.15;
    }
    .pc-track-artist {
      font-size: 12px;
      letter-spacing: 0.02em;
      color: var(--pc-fg-muted, rgba(255,255,255,0.74));
    }
    .pc-note {
      font-family: "Fraunces", Georgia, serif;
      font-style: italic;
      font-size: clamp(15px, 1.4vw, 18px);
      line-height: 1.4;
      color: var(--pc-fg, white);
      margin: 16px 0;
      max-width: 32ch;
      position: relative;
      z-index: 1;
    }
    .pc-foot {
      display: flex;
      align-items: center;
      justify-content: space-between;
      gap: 12px;
      font-family: "Antonio", sans-serif;
      font-size: 11px;
      letter-spacing: 0.16em;
      text-transform: uppercase;
      position: relative;
      z-index: 1;
    }
    .pc-foot-from {
      color: var(--pc-fg-muted, rgba(255,255,255,0.74));
    }
    .pc-foot-mark {
      color: var(--pc-accent, #FF3B7A);
      font-weight: 700;
    }

    /* ─────────────────────────────────────────────────────────────────────
       Today on Vibes — live grid of real Songs of the Day. Cards are
       mini Wrapped posters with per-song palette. Tap the album art
       to play 30s preview; tap the rest of the card to visit profile.
       ───────────────────────────────────────────────────────────────────── */
    .home-today[hidden] { display: none !important; }
    .home-today {
      padding: 112px 32px;
      background: var(--bg, #0A0A0F);
      position: relative;
      overflow: hidden;
    }
    .home-today-inner {
      max-width: 1280px;
      margin: 0 auto;
    }
    .home-today-head {
      max-width: 720px;
      margin: 0 0 48px;
    }
    .home-today-kicker {
      display: inline-block;
      font-family: "Antonio", "Arial Narrow", "Roboto Condensed", "Inter Tight", -apple-system, sans-serif;
      font-weight: 700;
      font-size: 12px;
      letter-spacing: 0.18em;
      text-transform: uppercase;
      color: var(--neon-dusk-accent, #FF3B7A);
      padding: 6px 12px;
      border: 1px solid rgba(255, 59, 122, 0.32);
      border-radius: var(--radius-pill);
      margin-bottom: 24px;
    }
    .home-today-title {
      font-family: "Antonio", "Arial Narrow", "Roboto Condensed", "Inter Tight", -apple-system, sans-serif;
      font-weight: 700;
      font-size: clamp(40px, 5.5vw, 80px);
      line-height: 0.92;
      letter-spacing: -0.03em;
      text-transform: uppercase;
      color: var(--fg, white);
      margin: 0 0 16px;
      max-width: 16ch;
    }
    .home-today-title .editorial {
      color: var(--neon-dusk-accent, #FF3B7A);
      text-transform: none;
    }
    .home-today-lede {
      font-size: 16px;
      line-height: 1.55;
      color: var(--fg-secondary, rgba(255, 255, 255, 0.74));
      max-width: 58ch;
      margin: 0;
    }
    .home-today-fine {
      margin: 40px 0 0;
      font-size: 13px;
      color: var(--fg-tertiary, rgba(255, 255, 255, 0.46));
    }
    .home-today-fine a {
      color: var(--fg, white);
      text-decoration: underline;
      text-underline-offset: 3px;
    }

    /* Sample-mode banner — only visible when .today-sample-mode is
       set on the section (no Cloud Function endpoint configured).
       Honest indicator so a deploy-too-early can't fake live data. */
    .home-today-sample-banner {
      display: none;
      align-items: flex-start;
      gap: 10px;
      margin-top: 20px;
      padding: 12px 16px;
      background: rgba(255, 200, 59, 0.08);
      border: 1px solid rgba(255, 200, 59, 0.30);
      border-radius: 12px;
      max-width: 600px;
      font-family: "Inter Tight", -apple-system, sans-serif;
      font-size: 13px;
      line-height: 1.5;
      color: var(--fg-secondary, rgba(255, 255, 255, 0.78));
    }
    .home-today-sample-banner strong {
      color: var(--late-drive-accent, #FFC83B);
      font-weight: 700;
    }
    .home-today-sample-dot {
      width: 8px;
      height: 8px;
      flex-shrink: 0;
      margin-top: 7px;
      border-radius: 50%;
      background: var(--late-drive-accent, #FFC83B);
      box-shadow: 0 0 8px rgba(255, 200, 59, 0.6);
    }
    .today-sample-mode .home-today-sample-banner {
      display: flex;
    }
    /* In sample mode, also tone down the lede so the banner is the
       authoritative source of truth about what's being shown. */
    .today-sample-mode .home-today-lede {
      opacity: 0.6;
    }

    /* ── Card grid ─────────────────────────────────────────────── */
    .today-grid {
      display: grid;
      grid-template-columns: repeat(4, 1fr);
      gap: 16px;
    }
    @media (max-width: 1100px) {
      .today-grid { grid-template-columns: repeat(3, 1fr); }
    }
    @media (max-width: 820px) {
      .today-grid { grid-template-columns: repeat(2, 1fr); }
    }
    @media (max-width: 500px) {
      /* Mobile: horizontal scroll instead of a tall vertical column */
      .today-grid {
        display: flex;
        gap: 12px;
        overflow-x: auto;
        scroll-snap-type: x mandatory;
        margin: 0 -32px;
        padding: 0 32px 8px;
        scrollbar-width: none;
      }
      .today-grid::-webkit-scrollbar { display: none; }
      .today-card {
        flex: 0 0 220px;
        scroll-snap-align: start;
      }
    }

    /* ── Single card ───────────────────────────────────────────── */
    .today-card {
      position: relative;
      display: flex;
      flex-direction: column;
      padding: 16px;
      border-radius: 18px;
      background: var(--c-bg, #1A1745);
      color: var(--c-fg, white);
      overflow: hidden;
      isolation: isolate;
      transition: transform 0.25s var(--ease-out), box-shadow 0.25s var(--ease-out);
    }
    .today-card:hover {
      transform: translateY(-3px);
      box-shadow: 0 24px 60px rgba(0, 0, 0, 0.4);
    }
    /* Whole card toggles the preview (profiles aren't live on web). */
    .today-card--interactive { cursor: pointer; }
    /* Accent disc bleeds off the upper-right — Wrapped vocabulary */
    .today-card-bg {
      position: absolute;
      right: -40px;
      top: -50px;
      width: 160px;
      height: 160px;
      border-radius: 50%;
      background: var(--c-accent, #FF3B7A);
      opacity: 0.22;
      pointer-events: none;
      z-index: 0;
    }
    .today-card > * { position: relative; z-index: 1; }

    /* Tappable album art — 88px square with progress arc overlay */
    .today-card-art {
      position: relative;
      width: 96px;
      height: 96px;
      padding: 0;
      border: none;
      border-radius: 10px;
      overflow: hidden;
      background: rgba(0, 0, 0, 0.18);
      cursor: pointer;
      flex-shrink: 0;
      box-shadow: 0 8px 20px rgba(0, 0, 0, 0.4);
      transition: transform 0.18s var(--ease-out);
    }
    .today-card-art:hover { transform: scale(1.04); }
    .today-card-art img {
      width: 100%; height: 100%;
      object-fit: cover;
      display: block;
    }
    .today-card-art-fallback {
      display: grid; place-items: center;
      width: 100%; height: 100%;
      font-family: "Antonio", sans-serif;
      font-size: 32px;
      color: var(--c-accent, white);
    }
    /* SVG progress arc — drawn around the art tile while previewing.
       Renders only when the art has .is-playing. */
    .today-card-arc {
      position: absolute;
      inset: 0;
      width: 100%; height: 100%;
      transform: rotate(-90deg);
      pointer-events: none;
      opacity: 0;
      transition: opacity 0.2s ease;
    }
    .today-card-arc circle {
      fill: none;
      stroke: var(--c-accent, #FF3B7A);
      stroke-width: 4;
      stroke-linecap: round;
      stroke-dasharray: 289;
      stroke-dashoffset: 289;
      transition: stroke-dashoffset 0.05s linear;
    }
    .today-card-art.is-playing .today-card-arc { opacity: 1; }
    /* Center play/pause icon is intentionally hidden — many album
       covers (Marshmello, Pinegrove, plenty of others) include
       stylized play buttons as part of the artwork itself. Any
       overlay we add reads as "two play buttons" on those cards.
       The progress arc (drawn in the per-card accent color around
       the tile) is the playback indicator, and cursor:pointer +
       the 1.04 scale on hover handle discoverability. */
    .today-card-play { display: none; }

    .today-card-text {
      display: flex;
      flex-direction: column;
      gap: 4px;
      margin-top: 14px;
      min-width: 0;
    }
    .today-card-eyebrow {
      display: inline-flex;
      align-items: center;
      gap: 8px;
      font-family: "Antonio", sans-serif;
      font-weight: 700;
      font-size: 10px;
      letter-spacing: 0.16em;
      text-transform: uppercase;
      color: var(--c-fg-muted, rgba(255, 255, 255, 0.74));
    }
    .today-card-handle {
      flex: 1;
      min-width: 0;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
    }
    /* Tiny circular avatar next to @handle. base64 data URIs from
       /publicProfiles render directly; monogram fallback when the
       user hasn't set a photo. */
    .today-card-avatar {
      width: 24px;
      height: 24px;
      border-radius: 50%;
      flex-shrink: 0;
      object-fit: cover;
      background: rgba(255, 255, 255, 0.10);
      box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.18) inset;
      display: block;
    }
    .today-card-avatar--monogram {
      display: grid;
      place-items: center;
      font-family: "Antonio", sans-serif;
      font-weight: 700;
      font-size: 11px;
      letter-spacing: 0;
      color: var(--c-fg, white);
      background: var(--c-accent, rgba(255, 255, 255, 0.12));
      text-transform: uppercase;
    }
    .today-card-title {
      font-family: "Antonio", sans-serif;
      font-weight: 700;
      font-size: 18px;
      line-height: 1.05;
      letter-spacing: -0.01em;
      color: var(--c-fg, white);
      /* Two-line clamp keeps card heights tidy */
      display: -webkit-box;
      -webkit-line-clamp: 2;
      -webkit-box-orient: vertical;
      overflow: hidden;
    }
    .today-card-artist {
      font-size: 13px;
      color: var(--c-fg-muted, rgba(255, 255, 255, 0.74));
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
    }
    .today-card-note {
      margin-top: 6px;
      font-family: "Fraunces", Georgia, serif;
      font-style: italic;
      font-size: 13px;
      line-height: 1.3;
      color: var(--c-fg, white);
      opacity: 0.86;
    }

    /* Card-wide link to /u/handle — sits BEHIND text but ABOVE bg,
       and the art button takes priority via stacking + z-index. */
    .today-card-link {
      position: absolute;
      inset: 0;
      z-index: 0;
      text-indent: -9999px;
      overflow: hidden;
    }
    .today-card-art,
    .today-card-text {
      pointer-events: auto;
    }
    .today-card-text { z-index: 2; pointer-events: none; }
    .today-card-link { z-index: 1; }
    .today-card-art { z-index: 3; }

    /* Skeleton state — shimmer placeholder while loading */
    .today-card--skeleton {
      background: rgba(255, 255, 255, 0.03);
      border: 1px solid rgba(255, 255, 255, 0.06);
    }
    .today-card--skeleton .today-card-art {
      background: rgba(255, 255, 255, 0.06);
      cursor: default;
    }
    .today-skel {
      height: 8px;
      border-radius: 4px;
      background: rgba(255, 255, 255, 0.08);
      animation: today-shimmer 1.6s ease-in-out infinite;
    }
    .today-skel--xs { width: 40%; }
    .today-skel--sm { width: 50%; }
    .today-skel--md { width: 75%; height: 12px; }
    @keyframes today-shimmer {
      0%, 100% { opacity: 0.6; }
      50%      { opacity: 1; }
    }

    /* Empty state */
    .today-empty {
      grid-column: 1 / -1;
      display: flex;
      flex-direction: column;
      align-items: center;
      gap: 8px;
      padding: 64px 24px;
      text-align: center;
      border: 1px dashed var(--hairline, rgba(255, 255, 255, 0.08));
      border-radius: 20px;
    }
    .today-empty-eyebrow {
      font-family: "Antonio", sans-serif;
      font-weight: 700;
      font-size: 11px;
      letter-spacing: 0.20em;
      text-transform: uppercase;
      color: var(--fg-tertiary, rgba(255, 255, 255, 0.46));
    }
    .today-empty-title {
      font-family: "Antonio", sans-serif;
      font-weight: 700;
      font-size: 28px;
      letter-spacing: -0.02em;
      text-transform: uppercase;
      color: var(--fg, white);
    }
    .today-empty-sub {
      font-family: "Fraunces", Georgia, serif;
      font-style: italic;
      font-size: 16px;
      color: var(--fg-secondary, rgba(255, 255, 255, 0.74));
    }

    /* Dark-mode overrides — quiet the cards a touch like the other
       homepage bands (same vocabulary as .home-android-band etc.). */
    :root:not([data-theme="light"]) .today-card {
      filter: brightness(0.88) saturate(0.9);
    }

    /* ─────────────────────────────────────────────────────────────────────
       Android band — full-bleed Wrapped section right after the hero.
       Acid-summer palette (yellow-green ground, magenta accent) so it
       interrupts the dark page with a saturated band that's impossible
       to scroll past. Inline waitlist form lives here so visitors can
       sign up without clicking through to /android/.
       ───────────────────────────────────────────────────────────────────── */
    .home-android-band {
      background: var(--acid-summer-bg);
      color: var(--peak-sun-accent);   /* same dark teal as acid-summer */
      padding: 96px 32px;
      position: relative;
      overflow: hidden;
    }
    /* Decorative accent disc bottom-right — small Wrapped poster nod
       without competing with the headline. */
    .home-android-band::before {
      content: "";
      position: absolute;
      right: -120px;
      bottom: -140px;
      width: 380px;
      height: 380px;
      border-radius: 50%;
      background: var(--acid-summer-accent);
      opacity: 0.18;
      pointer-events: none;
    }
    .home-android-band-inner {
      max-width: 1280px;
      margin: 0 auto;
      position: relative;
      z-index: 2;
    }
    .home-android-band-kicker {
      display: inline-block;
      font-family: "Antonio", "Arial Narrow", "Roboto Condensed", "Inter Tight", -apple-system, sans-serif;
      font-weight: 700;
      font-size: 12px;
      letter-spacing: 0.18em;
      text-transform: uppercase;
      color: var(--acid-summer-accent);
      padding: 6px 12px;
      border: 1px solid rgba(255, 31, 139, 0.32);
      border-radius: var(--radius-pill);
      margin-bottom: 24px;
    }
    .home-android-band-title {
      font-family: "Antonio", "Arial Narrow", "Roboto Condensed", "Inter Tight", -apple-system, sans-serif;
      font-weight: 700;
      font-size: clamp(40px, 7vw, 96px);
      line-height: 0.92;
      letter-spacing: -0.03em;
      text-transform: uppercase;
      color: #1A4D6B;
      margin: 0 0 24px;
      max-width: 22ch;
    }
    .home-android-band-title .editorial {
      color: var(--acid-summer-accent);
      text-transform: none;
    }
    .home-android-band-lede {
      font-size: clamp(17px, 1.4vw, 19px);
      line-height: 1.55;
      color: rgba(26, 77, 107, 0.86);
      max-width: 58ch;
      margin: 0 0 32px;
    }
    .home-android-band-form {
      display: grid;
      grid-template-columns: 1fr auto;
      gap: 12px;
      max-width: 560px;
    }
    .home-android-band-form input[type="email"] {
      padding: 16px 22px;
      border: 1px solid rgba(26, 77, 107, 0.32);
      border-radius: var(--radius-pill);
      background: rgba(255, 255, 255, 0.6);
      font-family: inherit;
      font-size: 16px;
      color: #1A4D6B;
      width: 100%;
      transition: border-color 0.2s ease, background 0.2s ease;
    }
    .home-android-band-form input[type="email"]::placeholder {
      color: rgba(26, 77, 107, 0.5);
    }
    .home-android-band-form input[type="email"]:focus {
      outline: none;
      border-color: var(--acid-summer-accent);
      background: white;
    }
    .home-android-band-form button {
      padding: 16px 28px;
      border-radius: var(--radius-pill);
      border: none;
      font-family: inherit;
      font-weight: 600;
      font-size: 15px;
      background: var(--acid-summer-accent);
      color: white;
      cursor: pointer;
      letter-spacing: -0.005em;
      transition: transform 0.2s var(--ease-out), box-shadow 0.2s var(--ease-out);
    }
    .home-android-band-form button:hover {
      transform: translateY(-1px);
      box-shadow: 0 14px 28px rgba(255, 31, 139, 0.30);
    }
    .home-android-band-form button:disabled {
      opacity: 0.4;
      cursor: not-allowed;
      transform: none;
      box-shadow: none;
    }
    .home-android-band-status {
      margin-top: 16px;
      font-size: 13px;
      letter-spacing: 0.01em;
      color: rgba(26, 77, 107, 0.74);
      min-height: 1.4em;
    }
    .home-android-band-status.is-success {
      color: var(--acid-summer-accent);
      font-weight: 600;
    }
    .home-android-band-status.is-error {
      color: #B81F3C;
    }
    .home-android-band-more {
      display: inline-block;
      margin-top: 24px;
      font-family: "Antonio", "Arial Narrow", "Roboto Condensed", "Inter Tight", -apple-system, sans-serif;
      font-weight: 700;
      font-size: 13px;
      letter-spacing: 0.14em;
      text-transform: uppercase;
      color: var(--acid-summer-accent);
      text-decoration: none;
      transition: transform 0.2s var(--ease-out);
    }
    .home-android-band-more:hover {
      transform: translateX(4px);
    }
    /* ── Two-column layout: copy left, Android phone right ─────────── */
    .home-android-band-inner {
      display: grid;
      grid-template-columns: minmax(0, 1fr) auto;
      align-items: center;
      gap: 48px;
    }
    .home-android-band-copy { min-width: 0; }

    /* ── The Android phone (pure CSS) ──────────────────────────────────
       Pixel-style: uniform thin bezel, centered punch-hole, gesture
       bar, flat matte back. Deliberately NOT an iPhone silhouette —
       no notch, no Dynamic Island, squarer corners. Tilted a few
       degrees and floating so it reads as an object, not a screenshot. */
    .android-phone-wrap {
      justify-self: end;
      padding: 12px 24px 12px 0;
      perspective: 1400px;
    }
    .android-phone {
      width: 272px;
      height: 580px;
      border-radius: 34px;
      background: linear-gradient(160deg, #2b2f33 0%, #16181b 60%, #0d0e10 100%);
      box-shadow:
        0 40px 80px rgba(20, 40, 20, 0.35),
        0 12px 24px rgba(0, 0, 0, 0.25),
        inset 0 0 0 2px rgba(255, 255, 255, 0.06);
      padding: 10px;
      position: relative;
      transform: rotate(-4deg) rotateY(-6deg);
      animation: androidFloat 7s ease-in-out infinite;
    }
    /* Side buttons — power + volume on the right edge (Pixel layout). */
    .android-btn {
      position: absolute; right: -4px; width: 4px; border-radius: 2px;
      background: #3a3e43; cursor: pointer;
      transition: background 0.15s ease, right 0.1s ease;
    }
    .android-btn:hover { background: #ff1f8b; }
    .android-btn:active { right: -2px; }
    .android-btn:focus-visible { outline: 2px solid #ff1f8b; outline-offset: 2px; }
    .android-btn-power { top: 118px; height: 40px; }
    .android-btn-vol   { top: 176px; height: 72px; }

    .android-phone-screen {
      width: 100%;
      height: 100%;
      border-radius: 26px;
      background: #0f1216;
      overflow: hidden;
      display: flex;
      flex-direction: column;
      font-family: "Roboto", "Inter", -apple-system, system-ui, sans-serif;
      color: #f2f4f6;
      position: relative;
    }
    /* Ambient palette wash — the received card's colors bleed up the
       screen, same "vibes wear your colors" recipe as the app. */
    .android-phone-screen::before {
      content: "";
      position: absolute;
      inset: 0;
      background:
        radial-gradient(120% 60% at 50% 38%, rgba(255, 31, 139, 0.28), transparent 70%),
        radial-gradient(80% 40% at 80% 90%, rgba(196, 226, 60, 0.18), transparent 70%);
      pointer-events: none;
    }

    .android-status {
      display: flex;
      align-items: center;
      justify-content: space-between;
      padding: 12px 18px 0;
      font-size: 12px;
      font-weight: 600;
      letter-spacing: 0.01em;
      position: relative;
      z-index: 1;
    }
    .android-punch {
      position: absolute;
      left: 50%;
      top: 10px;
      width: 12px;
      height: 12px;
      margin-left: -6px;
      border-radius: 50%;
      background: #050607;
      box-shadow: inset 0 0 0 2px #1c2024, 0 0 0 1px rgba(255,255,255,0.05);
    }
    .android-status-icons { display: inline-flex; gap: 5px; align-items: flex-end; }
    .android-status-icons i { display: inline-block; background: #f2f4f6; border-radius: 1px; }
    .android-ico-signal { width: 10px; height: 9px; clip-path: polygon(0 100%, 100% 0, 100% 100%); }
    .android-ico-wifi   { width: 11px; height: 9px; clip-path: polygon(50% 100%, 0 30%, 100% 30%); border-radius: 40% 40% 0 0 !important; }
    .android-ico-batt   { width: 18px; height: 9px; border-radius: 2px !important; }

    /* Heads-up notification — Material style, rounded 20, tonal. */
    .android-notif {
      margin: 20px 12px 0;
      padding: 12px 14px;
      border-radius: 20px;
      background: rgba(255, 255, 255, 0.10);
      backdrop-filter: blur(10px);
      display: flex;
      flex-direction: column;
      gap: 2px;
      font-size: 12px;
      position: relative;
      z-index: 1;
      animation: androidNotifIn 0.7s cubic-bezier(.2,.8,.2,1) 0.6s both;
    }
    .android-notif-app {
      display: inline-flex; align-items: center; gap: 6px;
      font-size: 10.5px; color: rgba(242,244,246,0.7);
    }
    .android-notif-dot {
      width: 12px; height: 12px; border-radius: 4px;
      background: linear-gradient(135deg, #ff1f8b, #7c5cff);
    }
    .android-notif strong { font-size: 13px; font-weight: 600; }
    .android-notif-body { color: rgba(242,244,246,0.72); }

    /* The received vibe card. */
    .android-card {
      margin: 14px 12px 0;
      border-radius: 24px;
      background: rgba(255, 255, 255, 0.06);
      border: 1px solid rgba(255,255,255,0.08);
      overflow: hidden;
      position: relative;
      z-index: 1;
    }
    .android-card-art {
      height: 124px;
      background: linear-gradient(135deg, #ff1f8b 0%, #ff8a3d 55%, #ffd23c 100%);
      position: relative;
      display: grid;
      place-items: center;
    }
    /* Real cover art (set by JS) — the gradient is the placeholder. A
       soft scrim keeps the record readable on bright covers. */
    .android-card-art.has-art::before,
    .android-reply-art.has-art::before {
      content: ""; position: absolute; inset: 0;
      background: rgba(0,0,0,0.18); pointer-events: none;
    }
    .android-reply-art { position: relative; overflow: hidden; }
    .android-avatar {
      border-radius: 50%; object-fit: cover; display: inline-block;
      box-shadow: 0 0 0 1.5px rgba(255,255,255,0.35);
    }
    .android-pop-avatar .android-avatar { width: 40px; height: 40px; }
    .android-sender .android-avatar { width: 16px; height: 16px; margin-right: 2px; }
    .android-card-art-disc { position: relative; z-index: 1; }
    .android-card-art-disc {
      width: 84px; height: 84px; border-radius: 50%;
      background: radial-gradient(circle at 50% 50%, #ffd23c 0 10px, #1a1a1a 11px 13px, #2a2a2a 14px 16px, #1a1a1a 17px 19px, #2a2a2a 20px 22px, #151515 23px);
      box-shadow: 0 10px 30px rgba(0,0,0,0.35);
      animation: androidSpin 6s linear infinite;
    }
    .android-card-meta {
      padding: 14px 16px 6px;
      display: flex; flex-direction: column; gap: 2px;
    }
    .android-card-from {
      font-family: "Antonio", "Roboto Condensed", sans-serif;
      font-size: 10.5px; letter-spacing: 0.16em; color: #ff1f8b; font-weight: 700;
      margin-bottom: 4px;
    }
    .android-card-title { font-size: 17px; font-weight: 700; letter-spacing: -0.01em; }
    .android-card-artist { font-size: 12.5px; color: rgba(242,244,246,0.7); }
    .android-card-note {
      margin-top: 8px;
      font-family: Georgia, "Times New Roman", serif;
      font-style: italic;
      font-size: 12.5px;
      color: rgba(242,244,246,0.85);
    }
    .android-card-actions {
      display: flex; gap: 8px; padding: 12px 16px 16px;
    }
    .android-pill {
      font-size: 11.5px; font-weight: 600;
      padding: 8px 12px; border-radius: 999px;
      background: rgba(255,255,255,0.10);
      color: #f2f4f6;
    }
    .android-pill-primary { background: #ff1f8b; }

    /* Gesture nav bar — the Android tell. */
    .android-navbar {
      margin-top: auto;
      padding: 10px 0 8px;
      display: grid; place-items: center;
      position: relative; z-index: 1;
    }
    .android-gesture {
      width: 92px; height: 4px; border-radius: 2px;
      background: rgba(242,244,246,0.75);
    }

    /* ── Interactive states (android-phone.js) ────────────────────── */
    /* Tilt: JS writes --tilt-x/--tilt-y; the float keyframes fold
       them in so hover-tilt and idle-float compose instead of fight. */
    .android-phone { --tilt-x: 0deg; --tilt-y: 0deg; }
    .android-phone.is-interactive {
      transition: transform 0.18s ease-out;
      cursor: default;
    }
    .android-phone.is-playing { box-shadow:
        0 40px 80px rgba(20, 40, 20, 0.35),
        0 12px 24px rgba(0, 0, 0, 0.25),
        0 0 0 2px rgba(255, 31, 139, 0.35),
        inset 0 0 0 2px rgba(255, 255, 255, 0.06); }

    .android-pill { cursor: pointer; user-select: none; transition: transform 0.15s ease, background 0.2s ease; }
    .android-pill:hover { transform: translateY(-1px); background: rgba(255,255,255,0.16); }
    .android-pill-primary:hover { background: #ff3d9c; }
    .android-pill:active { transform: scale(0.96); }
    .android-pill:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }
    .android-pill.is-loading { opacity: 0.6; }
    .android-pill.is-saved { background: rgba(196, 226, 60, 0.22); color: #d9f36a; }

    /* Record: paused by default, JS runs it while audio is audible. */
    .android-card-art-disc { animation-play-state: paused; }
    .android-card-art { position: relative; }
    .android-progress {
      position: absolute; left: 0; bottom: 0; height: 3px; width: 0%;
      background: #fff; opacity: 0.9;
      transition: width 0.25s linear;
    }

    /* Card flip → reply card (chains demo). */
    .android-card { transform-style: preserve-3d; transition: transform 0.6s cubic-bezier(.2,.8,.2,1); }
    .android-card > *:not(.android-card-back) { backface-visibility: hidden; }
    .android-card.is-flipped { transform: rotateY(180deg); }
    .android-card-back {
      position: absolute; inset: 0;
      transform: rotateY(180deg);
      backface-visibility: hidden;
      background: #12151a;
      display: flex; flex-direction: column;
    }
    .android-reply-head {
      display: flex; align-items: center; gap: 6px;
      padding: 12px 16px 0;
      font-family: Georgia, "Times New Roman", serif; font-style: italic;
      font-size: 12px; color: rgba(242,244,246,0.7);
    }
    .android-reply-arrow { font-style: normal; font-size: 13px; }
    .android-reply-art {
      height: 118px; margin: 10px 16px 0; border-radius: 16px;
      background: linear-gradient(135deg, #c4e23c 0%, #3bffd8 60%, #12b8ff 100%);
      display: grid; place-items: center;
    }
    .android-reply-art-disc {
      width: 64px; height: 64px; border-radius: 50%;
      background: radial-gradient(circle, #ff1f8b 0 8px, #1a1a1a 9px 11px, #2a2a2a 12px 14px, #151515 15px);
      box-shadow: 0 8px 22px rgba(0,0,0,0.35);
    }
    .android-card-from-you { color: #c4e23c; }
    .android-reply-sent { background: #c4e23c; color: #10251a; }

    /* Heads-up notification dismiss. */
    .android-notif { cursor: pointer; transition: transform 0.35s cubic-bezier(.2,.8,.2,1), opacity 0.3s ease, margin 0.35s ease; }
    .android-notif.is-dismissed { transform: translateY(-24px); opacity: 0; pointer-events: none; }

    /* Material snackbar — rises from just above the gesture bar. */
    .android-snackbar {
      position: absolute; left: 12px; right: 12px; bottom: 34px; z-index: 3;
      padding: 12px 16px; border-radius: 12px;
      background: #e9ebef; color: #1b1e23;
      font-size: 12.5px; font-weight: 500;
      box-shadow: 0 8px 24px rgba(0,0,0,0.35);
      transform: translateY(16px); opacity: 0; pointer-events: none;
      transition: transform 0.28s cubic-bezier(.2,.8,.2,1), opacity 0.22s ease;
    }
    .android-snackbar.is-visible { transform: translateY(0); opacity: 1; }

    /* Sender tap → popover */
    .android-sender { cursor: pointer; display: inline-flex; align-items: center; gap: 5px; }
    .android-sender-dot {
      display: inline-block; width: 12px; height: 7px; border-radius: 4px;
      background: linear-gradient(90deg, #3bffd8 50%, #ffd23c 50%);
      border: 1px solid rgba(255,255,255,0.35);
    }
    .android-pop {
      position: absolute; left: 14px; right: 14px; top: 46%;
      background: #1c2027; border-radius: 18px; padding: 14px;
      display: grid; grid-template-columns: 40px 1fr; grid-template-rows: auto auto auto;
      column-gap: 12px; row-gap: 2px; z-index: 4;
      box-shadow: 0 16px 40px rgba(0,0,0,0.5);
      transform: translateY(12px) scale(0.96); opacity: 0; pointer-events: none;
      transition: transform 0.28s cubic-bezier(.2,.8,.2,1), opacity 0.2s ease;
    }
    .android-pop.is-open { transform: none; opacity: 1; pointer-events: auto; }
    .android-pop-avatar {
      grid-row: 1 / span 3; width: 40px; height: 40px; border-radius: 50%;
      display: grid; place-items: center; font-weight: 700; color: #10251a;
      background: linear-gradient(135deg, #3bffd8, #ffd23c);
    }
    .android-pop-name { font-size: 14px; font-weight: 700; }
    .android-pop-sub { font-size: 11px; color: rgba(242,244,246,0.65); }
    .android-pop-stat { font-size: 11.5px; color: #ffd23c; margin-top: 3px; }

    /* Reactions — hidden until the note is tapped */
    .android-note-tap { cursor: pointer; }
    .android-reactions {
      display: flex; gap: 6px; margin-top: 8px;
      max-height: 0; overflow: hidden; opacity: 0;
      transition: max-height 0.3s ease, opacity 0.25s ease;
    }
    .android-reactions.is-open { max-height: 40px; opacity: 1; }
    .android-react {
      font-size: 16px; line-height: 1; padding: 6px 8px; border-radius: 999px;
      background: rgba(255,255,255,0.08); cursor: pointer;
      transition: transform 0.15s ease, background 0.2s ease;
    }
    .android-react:hover { transform: translateY(-2px) scale(1.08); }
    .android-react.is-picked { background: #ff1f8b; transform: scale(1.12); }

    /* Hit or Miss chip row */
    .android-hom {
      display: flex; align-items: center; gap: 6px; margin-top: 10px;
      font-size: 10.5px;
    }
    .android-hom-ask {
      font-family: "Antonio", "Roboto Condensed", sans-serif;
      letter-spacing: 0.14em; color: rgba(242,244,246,0.6);
    }
    .android-hom-btn {
      padding: 5px 9px; border-radius: 999px; font-weight: 600; cursor: pointer;
      border: 1px solid rgba(255,255,255,0.22); transition: background 0.2s, transform 0.15s;
    }
    .android-hom-btn:hover { transform: translateY(-1px); background: rgba(255,255,255,0.1); }
    .android-hom.is-decided .android-hom-btn { pointer-events: none; opacity: 0.35; }
    .android-hom.is-decided .android-hom-btn.is-picked { opacity: 1; background: #ff1f8b; border-color: transparent; }

    /* Home screen (gesture bar tap) */
    .android-home {
      position: absolute; inset: 0; z-index: 3;
      background:
        radial-gradient(90% 55% at 30% 20%, rgba(255,31,139,0.55), transparent 70%),
        radial-gradient(70% 50% at 85% 80%, rgba(196,226,60,0.45), transparent 70%),
        #14181f;
      padding: 44px 18px 60px; display: flex; flex-direction: column;
      opacity: 0; transform: scale(1.06); pointer-events: none;
      transition: opacity 0.3s ease, transform 0.35s cubic-bezier(.2,.8,.2,1);
    }
    .android-home.is-open { opacity: 1; transform: none; pointer-events: auto; }
    .android-home-clock { font-size: 44px; font-weight: 300; letter-spacing: -0.02em; line-height: 1; }
    .android-home-date { font-size: 12px; color: rgba(242,244,246,0.75); margin: 6px 0 26px; }
    .android-home-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; }
    .android-app { display: flex; flex-direction: column; align-items: center; gap: 5px; font-size: 10px; position: relative; }
    .android-app i { width: 44px; height: 44px; border-radius: 14px; background: #2a2f38; display: block; }
    .android-app i.a1 { background: linear-gradient(135deg, #ffd23c, #ff8a3d); }
    .android-app i.a2 { background: linear-gradient(135deg, #3bffd8, #12b8ff); }
    .android-app i.a3 { background: linear-gradient(135deg, #7c5cff, #c18bff); }
    .android-app b { font-weight: 500; color: rgba(242,244,246,0.9); }
    .android-app-vibes { cursor: pointer; }
    .android-app-vibes i { background: linear-gradient(135deg, #ff1f8b, #7c5cff); box-shadow: 0 6px 18px rgba(255,31,139,0.45); }
    .android-app-vibes:hover i { transform: scale(1.06); }
    .android-app-vibes em {
      position: absolute; top: -4px; right: 8px; font-style: normal; font-size: 9px; font-weight: 700;
      background: #ff1f8b; color: #fff; border-radius: 999px; padding: 1px 5px;
    }
    .android-home-search {
      margin-top: auto; padding: 12px 16px; border-radius: 999px;
      background: rgba(255,255,255,0.12); font-size: 12px; color: rgba(242,244,246,0.7);
    }
    .android-gesture { cursor: pointer; }
    .android-gesture:hover { background: #fff; }

    /* Volume HUD + power-off */
    .android-vol {
      position: absolute; right: 10px; top: 150px; z-index: 5;
      padding: 8px 6px; border-radius: 999px; background: #1c2027;
      opacity: 0; transform: translateX(8px); pointer-events: none;
      transition: opacity 0.2s ease, transform 0.2s ease;
    }
    .android-vol.is-visible { opacity: 1; transform: none; }
    .android-vol-bar { display: block; width: 6px; height: 110px; border-radius: 3px; background: rgba(255,255,255,0.15); position: relative; overflow: hidden; }
    .android-vol-fill { position: absolute; left: 0; right: 0; bottom: 0; height: 70%; background: #ff1f8b; transition: height 0.2s ease; }
    .android-off {
      position: absolute; inset: 0; z-index: 6; background: #000;
      opacity: 0; pointer-events: none; transition: opacity 0.25s ease;
    }
    .android-off.is-on { opacity: 1; pointer-events: auto; cursor: pointer; }

    @keyframes androidFloat {
      0%, 100% { transform: rotate(-4deg) rotateY(calc(-6deg + var(--tilt-y))) rotateX(var(--tilt-x)) translateY(0); }
      50%      { transform: rotate(-4deg) rotateY(calc(-6deg + var(--tilt-y))) rotateX(var(--tilt-x)) translateY(-10px); }
    }
    @keyframes androidNotifIn {
      from { opacity: 0; transform: translateY(-14px); }
      to   { opacity: 1; transform: translateY(0); }
    }
    @keyframes androidSpin { to { transform: rotate(360deg); } }

    @media (prefers-reduced-motion: reduce) {
      .android-phone, .android-notif, .android-card-art-disc { animation: none; }
    }
    @media (max-width: 960px) {
      .home-android-band-inner { grid-template-columns: 1fr; gap: 40px; }
      .android-phone-wrap { justify-self: center; padding: 0; }
      .android-phone { width: 240px; height: 512px; transform: rotate(-3deg); }
      @keyframes androidFloat {
        0%, 100% { transform: rotate(-3deg) translateY(0); }
        50%      { transform: rotate(-3deg) translateY(-8px); }
      }
    }
    @media (max-width: 600px) {
      .home-android-band { padding: 64px 24px; }
      .home-android-band-form { grid-template-columns: 1fr; }
    }

    /* ─────────────────────────────────────────────────────────────────────
       Bento grid — features
       ───────────────────────────────────────────────────────────────────── */
    .bento-section {
      padding: 128px 32px;
      max-width: 1280px;
      margin: 0 auto;
    }

    /* Section eyebrow — Wrapped kicker voice. Uppercase, heavy,
       3pt tracked. Palette accent dot replaces the dash so the
       eyebrow ties back to the iOS section kickers. */
    .section-eyebrow {
      display: inline-flex;
      align-items: center;
      gap: 10px;
      font-size: 12px;
      font-weight: 800;
      letter-spacing: 0.22em;
      text-transform: uppercase;
      color: var(--fg-secondary);
      margin-bottom: 16px;
    }
    .section-eyebrow::before {
      content: "";
      width: 8px; height: 8px;
      border-radius: 50%;
      background: var(--neon-dusk-accent);
    }

    /* Wrapped-voice section title — Antonio Bold condensed at
       display sizes, uppercase. The .editorial child renders the
       follow-up clause in Fraunces italic so each section title
       still has the two-tone "headline / kicker" rhythm. */
    .section-title {
      font-family: "Antonio", "Arial Narrow", "Roboto Condensed", "Inter Tight", -apple-system, sans-serif;
      font-weight: 700;
      /* Lowered min from 56px to 40px so multi-word titles like
         "Things people always ask" don't clip on 320–375px
         viewports. 8vw still drives mid-range scaling. */
      font-size: clamp(40px, 8vw, 112px);
      line-height: 0.92;
      letter-spacing: -0.035em;
      text-transform: uppercase;
      max-width: 16ch;
      margin-bottom: 64px;
    }
    .section-title .editorial {
      font-family: "Fraunces", Georgia, serif;
      font-style: italic;
      font-weight: 500;
      text-transform: none;
      letter-spacing: -0.015em;
      color: var(--fg-secondary);
      font-size: 0.65em;
    }

    .bento-grid {
      display: grid;
      grid-template-columns: repeat(6, 1fr);
      grid-auto-rows: 220px;
      gap: 16px;
    }

    /* Wrapped-voice bento card — each card owns its own curated palette
       pair via --card-bg/--card-accent CSS vars. The card body is the
       palette background (saturated, opaque) and a half-circle accent
       shape bleeds off the top-right corner the same way the hero does.
       Replaces the prior "glassy bg-elev-1 with hairline" treatment
       that made every card read identically. */
    .card {
      position: relative;
      overflow: hidden;
      padding: 32px;
      background: var(--card-bg, var(--bg-elev-1));
      color: var(--card-fg, var(--fg));
      border: 0;
      border-radius: var(--radius-card);
      display: flex;
      flex-direction: column;
      gap: 14px;
      transition: transform 0.4s var(--ease-out);
      isolation: isolate;
    }
    .card:hover {
      transform: translateY(-4px);
    }
    .card::after {
      /* Bold accent half-circle — bleeds off the top-right corner of
         each card. Sized at 60% of the card width so it owns visual
         weight without obliterating the copy. */
      content: "";
      position: absolute;
      top: -30%;
      right: -20%;
      width: 70%;
      aspect-ratio: 1;
      border-radius: 50%;
      background: var(--card-accent, var(--neon-dusk-accent));
      opacity: 0.95;
      z-index: -1;
      transition: transform 0.6s var(--ease-out);
    }
    .card:hover::after { transform: scale(1.06) translate(-2%, 2%); }

    .card .icon {
      width: 44px;
      height: 44px;
      border-radius: 12px;
      display: grid;
      place-items: center;
      background: rgba(255, 255, 255, 0.16);
      border: 1px solid rgba(255, 255, 255, 0.20);
      color: var(--card-fg, white);
      backdrop-filter: blur(10px);
      -webkit-backdrop-filter: blur(10px);
      align-self: flex-start;
    }
    .card .icon svg { display: block; }

    .card h3 {
      font-family: "Antonio", "Arial Narrow", "Roboto Condensed", "Inter Tight", -apple-system, sans-serif;
      font-weight: 700;
      font-size: clamp(28px, 3.4vw, 44px);
      line-height: 0.96;
      letter-spacing: -0.025em;
      text-transform: uppercase;
      margin-top: auto;
      max-width: 14ch;
    }
    .card p {
      font-size: 15px;
      line-height: 1.5;
      color: var(--card-fg-secondary, rgba(255, 255, 255, 0.78));
      max-width: 36ch;
    }

    /* Per-card palette assignments — rotate through the curated pairs
       so the bento reads as a hand-set magazine spread, not a Bootstrap
       grid. Order chosen so loud + quiet pairs alternate. */
    .bento-grid > .card:nth-child(1) {
      --card-bg: var(--neon-dusk-bg);
      --card-accent: var(--neon-dusk-accent);
      --card-fg: white;
      --card-fg-secondary: rgba(255, 255, 255, 0.80);
    }
    .bento-grid > .card:nth-child(2) {
      --card-bg: var(--peak-sun-bg);
      --card-accent: var(--peak-sun-accent);
      --card-fg: #1A1745;
      --card-fg-secondary: rgba(26, 23, 69, 0.78);
    }
    .bento-grid > .card:nth-child(3) {
      --card-bg: var(--late-drive-bg);
      --card-accent: var(--late-drive-accent);
      --card-fg: white;
      --card-fg-secondary: rgba(255, 255, 255, 0.78);
    }
    .bento-grid > .card:nth-child(4) {
      --card-bg: var(--vapor-bg);
      --card-accent: var(--vapor-accent);
      --card-fg: #0A1F1A;
      --card-fg-secondary: rgba(10, 31, 26, 0.74);
    }
    .bento-grid > .card:nth-child(5) {
      --card-bg: var(--marathon-bg);
      --card-accent: var(--marathon-accent);
      --card-fg: white;
      --card-fg-secondary: rgba(255, 255, 255, 0.84);
    }
    .bento-grid > .card:nth-child(6) {
      --card-bg: var(--citrus-glass-bg);
      --card-accent: var(--citrus-glass-accent);
      --card-fg: white;
      --card-fg-secondary: rgba(255, 255, 255, 0.80);
    }

    /* Card spans */
    .span-3-2 { grid-column: span 3; grid-row: span 2; }
    .span-3-1 { grid-column: span 3; }
    .span-2-1 { grid-column: span 2; }
    .span-2-2 { grid-column: span 2; grid-row: span 2; }
    .span-4-1 { grid-column: span 4; }

    /* ─────────────────────────────────────────────────────────────────────
       Card: postcard demo

       This card carries the most weight on the page — it has to make the
       core idea ("a song is a postcard") feel real. Built as a stylized
       chat bubble with album-art rectangle + caption + recipient line,
       all in the iOS palette vocabulary. No emoji.
       ───────────────────────────────────────────────────────────────────── */
    .postcard-card {
      padding: 28px;
      background:
        radial-gradient(120% 80% at 100% 0%, rgba(255, 90, 138, 0.18), transparent 50%),
        radial-gradient(120% 80% at 0% 100%, rgba(165, 107, 255, 0.18), transparent 55%),
        var(--bg-elev-1);
    }
    .postcard {
      margin-top: auto;
      padding: 16px;
      background: rgba(20, 20, 28, 0.65);
      backdrop-filter: blur(18px);
      -webkit-backdrop-filter: blur(18px);
      border: 1px solid var(--hairline);
      border-radius: 18px;
      display: grid;
      grid-template-columns: 56px 1fr auto;
      gap: 14px;
      align-items: center;
      box-shadow: 0 24px 48px rgba(0, 0, 0, 0.30);
    }
    /*
      The album-art tile is now a real <button> so it's keyboard-focusable
      and announces correctly to screen readers. The play glyph centers
      via grid; we morph between play (triangle) and pause (two bars) by
      swapping the SVG `d` path attribute from JS — so the entire tile
      stays one element, no layout shift on toggle.
    */
    .postcard-art {
      width: 56px; height: 56px;
      border-radius: 10px;
      background: linear-gradient(135deg, #FF5A8A, #A56BFF 60%, #5AB4FF);
      box-shadow: 0 8px 20px rgba(255, 90, 138, 0.45);
      position: relative;
      overflow: hidden;
      border: 0;
      cursor: pointer;
      padding: 0;
      display: grid;
      place-items: center;
      transition: transform 0.18s var(--ease-out), box-shadow 0.3s var(--ease-out);
    }
    .postcard-art::after {
      content: "";
      position: absolute;
      inset: 0;
      background: radial-gradient(circle at 30% 30%, rgba(255,255,255,0.3), transparent 50%);
      pointer-events: none;
    }
    .postcard-art:hover { transform: scale(1.04); }
    .postcard-art:focus-visible {
      outline: 2px solid var(--vibe-pink);
      outline-offset: 3px;
    }
    .postcard-art.is-playing {
      box-shadow:
        0 8px 20px rgba(255, 90, 138, 0.65),
        0 0 0 3px rgba(255, 90, 138, 0.20);
    }
    .postcard-art.is-loading {
      cursor: progress;
    }
    .postcard-play-icon {
      position: relative;
      z-index: 1;
      color: white;
      filter: drop-shadow(0 1px 2px rgba(0,0,0,0.4));
      transition: transform 0.18s var(--ease-out);
    }
    .postcard-art:hover .postcard-play-icon { transform: scale(1.08); }

    .postcard-meta {
      display: flex; flex-direction: column; gap: 4px;
      min-width: 0;
    }
    /*
      Live waveform — visible only while audio plays. The bars react via
      a CSS-only animation (no JS in the render loop) so the page stays
      cheap. Animations pause when .is-playing is removed from the
      postcard-art element via the [data-paused] selector.
    */
    .postcard-waveform {
      display: flex;
      align-items: flex-end;
      gap: 2.5px;
      height: 24px;
      width: 22px;
      opacity: 0;
      transition: opacity 0.3s var(--ease-out);
    }
    .postcard-waveform i {
      width: 3px;
      background: linear-gradient(to top, var(--vibe-pink), var(--vibe-purple));
      border-radius: 2px;
      transform-origin: bottom;
      animation: pcwave 1s ease-in-out infinite;
      animation-play-state: paused;
    }
    .postcard-waveform i:nth-child(1) { height: 60%; animation-delay: 0s; }
    .postcard-waveform i:nth-child(2) { height: 100%; animation-delay: 0.12s; }
    .postcard-waveform i:nth-child(3) { height: 45%; animation-delay: 0.24s; }
    .postcard-waveform i:nth-child(4) { height: 80%; animation-delay: 0.36s; }
    .postcard-waveform.is-active {
      opacity: 1;
    }
    .postcard-waveform.is-active i {
      animation-play-state: running;
    }
    @keyframes pcwave {
      0%, 100% { transform: scaleY(0.45); }
      50%      { transform: scaleY(1); }
    }
    @media (prefers-reduced-motion: reduce) {
      .postcard-waveform i { animation: none; transform: scaleY(0.7); }
    }

    /* The "Tap the cover to hear it" hint — only visible until the user
       has played once (or hovers the card). Disappears for good after
       first interaction so it doesn't keep nagging. */
    .postcard-hint {
      margin-top: 12px;
      font-size: 11px;
      letter-spacing: 0.04em;
      color: var(--fg-tertiary);
      transition: opacity 0.4s var(--ease-out), transform 0.4s var(--ease-out);
    }
    .postcard-hint.is-hidden {
      opacity: 0;
      transform: translateY(-2px);
      pointer-events: none;
    }

    .postcard-from {
      font-size: 11px;
      font-weight: 600;
      color: var(--fg-tertiary);
      letter-spacing: 0.10em;
      text-transform: uppercase;
    }
    .postcard-title {
      font-size: 15px;
      font-weight: 700;
      letter-spacing: -0.01em;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
    }
    .postcard-note {
      font-family: "Fraunces", Georgia, serif;
      font-style: italic;
      font-size: 13px;
      color: var(--fg-secondary);
      margin-top: 2px;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
    }

    /* ─────────────────────────────────────────────────────────────────────
       Card: friends listening — story rings

       Replaces the emoji avatars with palette-ringed circles that share
       the same "album-art-as-ring" vocabulary used in the iOS Share tab.
       Names are short, real-feeling.
       ───────────────────────────────────────────────────────────────────── */
    .friends-row {
      display: flex;
      gap: 14px;
      margin-top: auto;
    }
    .friend {
      flex: 1;
      display: flex;
      flex-direction: column;
      align-items: center;
      gap: 8px;
    }
    .ring {
      width: 56px; height: 56px;
      border-radius: 50%;
      padding: 2px;
      background: linear-gradient(135deg, var(--vibe-purple), var(--vibe-pink));
      position: relative;
    }
    .ring::after {
      content: "";
      position: absolute;
      inset: 2px;
      border-radius: 50%;
      background: var(--bg);
    }
    .ring.alt-1 { background: linear-gradient(135deg, var(--vibe-blue), var(--vibe-purple)); }
    .ring.alt-2 { background: linear-gradient(135deg, var(--vibe-amber), var(--vibe-pink)); }
    .ring.alt-3 { background: linear-gradient(135deg, var(--vibe-pink), var(--vibe-blue)); }
    .ring-letter {
      position: absolute;
      inset: 0;
      display: grid; place-items: center;
      font-weight: 700;
      font-size: 19px;
      letter-spacing: -0.01em;
      z-index: 1;
    }
    .friend-name {
      font-size: 12px;
      font-weight: 600;
      color: var(--fg);
    }
    .friend-track {
      font-size: 11px;
      color: var(--fg-tertiary);
      max-width: 9ch;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
    }

    /* ─────────────────────────────────────────────────────────────────────
       Card: weekly recap

       Uses the same eyebrow/numeral typography as the iOS WeeklyRecapView.
       The "47" / "MOST SHARED FRIEND" pattern signals we're showing real
       app surfaces, not stock content blocks.
       ───────────────────────────────────────────────────────────────────── */
    .recap-row {
      display: grid;
      grid-template-columns: 1fr 1fr;
      gap: 16px;
      margin-top: auto;
    }
    .recap-stat {
      padding: 14px 16px;
      background: var(--bg-elev-2);
      border: 1px solid var(--hairline);
      border-radius: 14px;
    }
    .recap-stat-eyebrow {
      font-size: 10px;
      font-weight: 700;
      letter-spacing: 0.14em;
      text-transform: uppercase;
      color: var(--fg-tertiary);
      margin-bottom: 4px;
    }
    .recap-stat-value {
      font-size: 28px;
      font-weight: 800;
      letter-spacing: -0.02em;
      line-height: 1.05;
    }
    .recap-stat.gradient .recap-stat-value {
      background: var(--gradient);
      -webkit-background-clip: text;
      background-clip: text;
      color: transparent;
    }

    /* ─────────────────────────────────────────────────────────────────────
       Card: phone mock

       A more honest device frame than the previous mini-phone. Inside, we
       render an actual stylized Share-tab moment with day-group eyebrow,
       three messages with palette glows, and a now-playing bar pinned to
       the bottom — visually consistent with the actual iOS surface.
       ───────────────────────────────────────────────────────────────────── */
    .device-card {
      padding: 0;
      background:
        radial-gradient(80% 80% at 50% 0%, rgba(165, 107, 255, 0.18), transparent 60%),
        var(--bg-elev-1);
      align-items: center;
      justify-content: center;
      overflow: hidden;
    }
    /*
      The device frame supports two render modes:

        1. Stylized mock (default) — what's currently rendered. Three
           message rows with palette art, an animated NowPlayingBar,
           drawn entirely from CSS. Safe pre-launch placeholder that
           visually matches the actual iOS app's vocabulary.

        2. Real screenshot — once the user has an iOS Simulator
           screenshot of the Share tab they're happy with, drop the
           image into landing-page/assets/share-tab.png and add
           data-screenshot="share-tab.png" to the .device element. The
           CSS automatically swaps the stylized children for an <img>
           overlay sized to the screen area.

      The toggle is purely CSS-driven so we can switch modes without
      touching JS, and the same .device markup serves both states. When
      data-screenshot is present, the .device-screen children are
      hidden via [data-screenshot] > .device-screen — the screenshot
      itself takes over the inside of the device frame.
    */
    .device {
      width: 248px;
      aspect-ratio: 248 / 510;
      margin: 32px auto 0;
      background: linear-gradient(160deg, #18181F, #0E0E14);
      border: 8px solid #1A1A22;
      border-radius: 40px;
      box-shadow:
        0 0 0 1px rgba(255,255,255,0.04) inset,
        0 30px 60px rgba(0, 0, 0, 0.55);
      position: relative;
      overflow: hidden;
    }
    .device-shot {
      /* Real-screenshot layer. Hidden by default; fades in when the
         .device element has a data-screenshot attribute set. */
      position: absolute;
      inset: 0;
      width: 100%;
      height: 100%;
      object-fit: cover;
      object-position: top center;
      opacity: 0;
      transition: opacity 0.4s var(--ease-out);
      pointer-events: none;
    }
    .device[data-screenshot] .device-shot { opacity: 1; }
    .device[data-screenshot] .device-screen { visibility: hidden; }
    .device-screen {
      position: absolute;
      inset: 0;
      padding: 14px 14px 0;
      display: flex;
      flex-direction: column;
      gap: 12px;
      background:
        radial-gradient(60% 40% at 50% 0%, rgba(255, 90, 138, 0.25), transparent 55%),
        linear-gradient(180deg, #0F0F18, #060609);
    }
    .device-notch {
      width: 88px; height: 24px;
      margin: 0 auto;
      background: #050508;
      border-radius: 0 0 14px 14px;
    }
    .device-eyebrow {
      font-size: 9px;
      font-weight: 700;
      letter-spacing: 0.18em;
      text-transform: uppercase;
      color: var(--fg-tertiary);
      padding: 0 4px;
    }
    .device-msg {
      display: grid;
      grid-template-columns: 32px 1fr;
      gap: 10px;
      align-items: center;
      padding: 10px;
      background: rgba(255, 255, 255, 0.04);
      border: 1px solid var(--hairline);
      border-radius: 14px;
    }
    .device-msg-art {
      width: 32px; height: 32px;
      border-radius: 8px;
    }
    .device-msg-art.a { background: linear-gradient(135deg, #A56BFF, #5AB4FF); }
    .device-msg-art.b { background: linear-gradient(135deg, #FF5A8A, #FFB95A); }
    .device-msg-art.c { background: linear-gradient(135deg, #5AB4FF, #A56BFF, #FF5A8A); }
    .device-msg-meta { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
    .device-msg-from {
      font-size: 10px;
      font-weight: 700;
      letter-spacing: -0.01em;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
    }
    .device-msg-track {
      font-size: 9px;
      color: var(--fg-tertiary);
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
    }
    .device-now-playing {
      margin-top: auto;
      margin-bottom: 14px;
      padding: 8px 10px;
      background: rgba(255, 255, 255, 0.06);
      backdrop-filter: blur(12px);
      -webkit-backdrop-filter: blur(12px);
      border: 1px solid var(--hairline);
      border-radius: 16px;
      display: grid;
      grid-template-columns: 24px 1fr 16px;
      gap: 8px;
      align-items: center;
    }
    .device-now-art {
      width: 24px; height: 24px;
      border-radius: 6px;
      background: linear-gradient(135deg, #FF5A8A, #A56BFF);
    }
    .device-now-title {
      font-size: 9px;
      font-weight: 700;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
    }
    .device-now-bars {
      display: flex; gap: 1.5px; align-items: flex-end;
      height: 12px;
    }
    .device-now-bars i {
      width: 1.5px;
      background: var(--vibe-pink);
      border-radius: 1px;
      animation: barpulse 1s ease-in-out infinite;
      transform-origin: bottom;
    }
    .device-now-bars i:nth-child(1) { height: 60%; animation-delay: 0s; }
    .device-now-bars i:nth-child(2) { height: 100%; animation-delay: 0.15s; }
    .device-now-bars i:nth-child(3) { height: 40%; animation-delay: 0.3s; }
    @keyframes barpulse {
      0%, 100% { transform: scaleY(0.45); }
      50%      { transform: scaleY(1); }
    }
    @media (prefers-reduced-motion: reduce) {
      .device-now-bars i { animation: none; }
    }

    /* ─────────────────────────────────────────────────────────────────────
       Card: privacy — diagram-as-content

       The previous version had no privacy story. This one shows the on-
       device hashing flow visually — phone number → SHA-256 → hash. Stops
       it from being just a copy paragraph.
       ───────────────────────────────────────────────────────────────────── */
    .privacy-flow {
      display: grid;
      grid-template-columns: 1fr auto 1fr auto 1fr;
      gap: 10px;
      align-items: center;
      margin-top: auto;
      padding: 14px;
      background: rgba(0, 0, 0, 0.25);
      border: 1px solid var(--hairline);
      border-radius: 14px;
      font-family: "JetBrains Mono", "Menlo", monospace;
      font-size: 11px;
      letter-spacing: -0.01em;
    }
    .privacy-pill {
      padding: 8px 10px;
      background: var(--bg-elev-2);
      border-radius: 8px;
      text-align: center;
      color: var(--fg-secondary);
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
    }
    .privacy-pill.input { color: var(--fg); }
    .privacy-pill.hash {
      background: linear-gradient(135deg, rgba(165, 107, 255, 0.20), rgba(255, 90, 138, 0.20));
      border: 1px solid rgba(165, 107, 255, 0.35);
      color: var(--vibe-purple);
      transition: transform 0.4s var(--ease-out), box-shadow 0.4s var(--ease-out);
    }
    /* While the scramble JS is cycling characters, the hash pill gets a
       subtle inner-glow so the eye can track that something is happening
       even before the final hash settles. .is-locked is added when the
       JS reaches its terminal state. */
    .privacy-pill.hash.is-scrambling {
      box-shadow:
        0 0 0 1px rgba(165, 107, 255, 0.50) inset,
        0 0 24px rgba(165, 107, 255, 0.35);
    }
    .privacy-pill.hash.is-locked {
      box-shadow: 0 0 0 1px rgba(165, 107, 255, 0.30) inset;
    }
    /* The middle SHA-256 pill — gets a centered two-line layout so the
       "on device" subtitle reads as a metadata caption rather than as
       part of the algorithm name. */
    .privacy-pill.privacy-step {
      display: flex;
      flex-direction: column;
      align-items: center;
      gap: 1px;
      transition: background 0.4s var(--ease-out);
    }
    .privacy-pill.privacy-step.is-pulsing {
      background: linear-gradient(135deg, rgba(165, 107, 255, 0.10), rgba(255, 90, 138, 0.10));
    }
    .privacy-step-label {
      font-weight: 600;
      color: var(--fg-secondary);
    }
    .privacy-step-sub {
      font-size: 9px;
      letter-spacing: 0.10em;
      text-transform: uppercase;
      color: var(--fg-tertiary);
    }
    .privacy-arrow {
      color: var(--fg-tertiary);
      font-size: 14px;
      transition: color 0.4s var(--ease-out);
    }
    .privacy-flow.is-active .privacy-arrow {
      color: var(--vibe-pink);
    }
    .privacy-note {
      grid-column: 1 / -1;
      font-family: "Inter Tight", sans-serif;
      font-size: 11px;
      color: var(--fg-tertiary);
      text-align: center;
      margin-top: 4px;
      letter-spacing: 0;
      opacity: 0;
      transform: translateY(4px);
      transition: opacity 0.5s var(--ease-out), transform 0.5s var(--ease-out);
    }
    /* Note settles in only after the hash locks — adds a beat of "and
       here's what that means" pacing instead of all firing at once. */
    .privacy-flow.is-complete .privacy-note {
      opacity: 1;
      transform: translateY(0);
    }

    /* ─────────────────────────────────────────────────────────────────────
       Interactive weekly recap

       Three vertically-stacked recap "cards" the user can flick between
       horizontally — recreates the iOS WeeklyRecapView vocabulary on
       the web. Snap-scroll on touch devices, paddles + dots on desktop.

       Each card has a distinct visual treatment matching the iOS:
         • Top Palette  — full-bleed mesh gradient
         • Most Shared  — editorial portrait + heavy 56pt numeral
         • Lyric Quote  — typography-only pull-quote
       ───────────────────────────────────────────────────────────────────── */
    .recap-section {
      padding: 96px 0 96px;
      max-width: 1280px;
      margin: 0 auto;
    }
    .recap-header {
      padding: 0 32px;
      max-width: 720px;
    }
    .recap-rail {
      margin-top: 48px;
      position: relative;
    }
    .recap-track {
      display: flex;
      gap: 20px;
      padding: 12px 32px;
      overflow-x: auto;
      scroll-snap-type: x mandatory;
      scroll-behavior: smooth;
      scrollbar-width: none;
      -webkit-overflow-scrolling: touch;
    }
    .recap-track::-webkit-scrollbar { display: none; }
    .recap-card {
      flex: 0 0 360px;
      aspect-ratio: 360 / 480;
      border-radius: 28px;
      padding: 32px;
      position: relative;
      overflow: hidden;
      scroll-snap-align: center;
      display: flex;
      flex-direction: column;
      justify-content: space-between;
      border: 1px solid var(--hairline);
      transition: transform 0.5s var(--ease-out);
    }
    .recap-card-eyebrow {
      font-size: 11px;
      font-weight: 700;
      letter-spacing: 0.16em;
      text-transform: uppercase;
      color: var(--fg-tertiary);
    }
    .recap-card-title {
      font-family: "Antonio", "Arial Narrow", "Roboto Condensed", "Inter Tight", -apple-system, sans-serif;
      font-size: clamp(28px, 3vw, 40px);
      font-weight: 700;
      letter-spacing: -0.025em;
      line-height: 0.96;
      text-transform: uppercase;
    }
    .recap-card-num {
      font-family: "Antonio", "Arial Narrow", "Roboto Condensed", "Inter Tight", -apple-system, sans-serif;
      font-size: clamp(96px, 14vw, 168px);
      font-weight: 700;
      line-height: 0.82;
      letter-spacing: -0.045em;
      background: var(--gradient);
      -webkit-background-clip: text;
      background-clip: text;
      color: transparent;
    }
    .recap-card-byline {
      font-size: 14px;
      color: var(--fg-secondary);
      letter-spacing: -0.005em;
    }
    /* Card variant: top palette — full-bleed mesh gradient */
    .recap-card.palette {
      background:
        radial-gradient(80% 90% at 30% 20%, rgba(165, 107, 255, 0.85), transparent 60%),
        radial-gradient(80% 80% at 80% 70%, rgba(255, 90, 138, 0.70), transparent 65%),
        radial-gradient(60% 80% at 50% 100%, rgba(255, 185, 90, 0.55), transparent 70%),
        #1a0f25;
      border-color: rgba(165, 107, 255, 0.30);
    }
    .recap-card.palette .recap-card-title { color: #fff; }
    .recap-card.palette .recap-palette-meta {
      display: flex;
      gap: 8px;
      flex-wrap: wrap;
    }
    .recap-card.palette .swatch {
      width: 28px; height: 28px;
      border-radius: 50%;
      box-shadow: 0 0 0 1px rgba(255,255,255,0.20) inset, 0 4px 12px rgba(0,0,0,0.4);
    }
    /* Card variant: most shared friend — editorial portrait + heavy numeral */
    .recap-card.friend {
      background:
        linear-gradient(180deg, var(--bg-elev-1) 0%, rgba(8, 8, 14, 0.98) 100%);
    }
    .recap-card.friend .friend-portrait {
      width: 96px; height: 96px;
      border-radius: 50%;
      background: linear-gradient(135deg, var(--vibe-pink), var(--vibe-purple));
      display: grid; place-items: center;
      font-size: 36px;
      font-weight: 800;
      color: white;
      letter-spacing: -0.02em;
      box-shadow: 0 12px 32px rgba(255, 90, 138, 0.40);
    }
    /* Card variant: lyric quote — typography-only */
    .recap-card.lyric {
      background:
        radial-gradient(120% 80% at 50% 0%, rgba(165, 107, 255, 0.10), transparent 70%),
        var(--bg-elev-1);
      justify-content: center;
      text-align: center;
      gap: 24px;
    }
    .recap-card.lyric .lyric-mark {
      font-family: "Fraunces", Georgia, serif;
      font-size: 96px;
      font-weight: 600;
      color: var(--vibe-pink);
      line-height: 0.6;
      opacity: 0.7;
    }
    .recap-card.lyric .lyric-text {
      font-family: "Fraunces", Georgia, serif;
      font-style: italic;
      font-size: 26px;
      line-height: 1.3;
      letter-spacing: -0.015em;
      color: var(--fg);
    }
    .recap-card.lyric .lyric-source {
      font-family: "Inter Tight", sans-serif;
      font-style: normal;
      font-size: 12px;
      font-weight: 600;
      letter-spacing: 0.1em;
      text-transform: uppercase;
      color: var(--fg-tertiary);
    }
    /* Paddle controls — desktop only. On touch, the snap-scroll
       interaction itself is the navigation. */
    .recap-paddles {
      display: flex;
      gap: 8px;
      padding: 16px 32px 0;
      align-items: center;
    }
    .recap-paddle {
      appearance: none;
      border: 1px solid var(--hairline);
      background: var(--bg-elev-1);
      color: var(--fg);
      width: 40px; height: 40px;
      border-radius: 50%;
      cursor: pointer;
      display: grid; place-items: center;
      transition: background 0.2s ease, transform 0.18s var(--ease-out);
    }
    .recap-paddle:hover { background: var(--bg-elev-3); }
    .recap-paddle:active { transform: scale(0.94); }
    .recap-paddle:disabled { opacity: 0.35; cursor: not-allowed; }
    .recap-dots {
      display: flex;
      gap: 6px;
      margin-left: 12px;
    }
    .recap-dots i {
      width: 6px; height: 6px;
      border-radius: 50%;
      background: var(--bg-elev-3);
      transition: width 0.3s var(--ease-out), background 0.3s ease;
    }
    .recap-dots i.is-active {
      width: 24px;
      border-radius: 3px;
      background: var(--gradient);
    }

    /* ─────────────────────────────────────────────────────────────────────
       Anti-features section ("What we don't do")

       Flips the manifesto from "what we believe in" → "what we refuse to
       build." Strikethrough text reinforces the negation visually so
       skim-readers get the message even if they don't parse the words.
       Two-column on desktop for density; one column on mobile.
       ───────────────────────────────────────────────────────────────────── */
    .anti-section {
      padding: 96px 32px;
      max-width: 1280px;
      margin: 0 auto;
    }
    .anti-grid {
      margin-top: 48px;
      display: grid;
      grid-template-columns: repeat(2, 1fr);
      gap: 0;
      border-top: 1px solid var(--hairline-soft);
    }
    .anti-item {
      padding: 24px 28px;
      border-bottom: 1px solid var(--hairline-soft);
      border-right: 1px solid var(--hairline-soft);
      display: flex;
      flex-direction: column;
      gap: 6px;
      transition: background 0.3s ease;
    }
    .anti-item:nth-child(2n) { border-right: 0; }
    @media (max-width: 720px) {
      .anti-section { padding: 72px 20px; }
      .anti-grid { grid-template-columns: 1fr; }
      .anti-item { border-right: 0; padding: 22px 4px; }
      .anti-item-line { overflow-wrap: anywhere; }
    }
    .anti-item:hover { background: var(--bg-elev-1); }
    .anti-item-line {
      font-family: "Antonio", "Arial Narrow", "Roboto Condensed", "Inter Tight", -apple-system, sans-serif;
      font-weight: 700;
      font-size: clamp(28px, 3vw, 40px);
      line-height: 0.96;
      letter-spacing: -0.025em;
      text-transform: uppercase;
      color: var(--fg);
      text-decoration: line-through;
      text-decoration-color: var(--neon-dusk-accent);
      text-decoration-thickness: 4px;
      text-underline-offset: -2px;
    }
    .anti-item-because {
      font-size: 14px;
      color: var(--fg-secondary);
      line-height: 1.5;
      letter-spacing: -0.005em;
    }
    /* Stagger the strike colour across the curated palette so the page
       reads as multi-coloured editorial rather than a single accent. */
    .anti-item:nth-child(1) .anti-item-line { text-decoration-color: var(--neon-dusk-accent); }
    .anti-item:nth-child(2) .anti-item-line { text-decoration-color: var(--peak-sun-bg); }
    .anti-item:nth-child(3) .anti-item-line { text-decoration-color: var(--vapor-bg); }
    .anti-item:nth-child(4) .anti-item-line { text-decoration-color: var(--late-drive-accent); }
    .anti-item:nth-child(5) .anti-item-line { text-decoration-color: var(--marathon-bg); }
    .anti-item:nth-child(6) .anti-item-line { text-decoration-color: var(--citrus-glass-accent); }

    /* ─────────────────────────────────────────────────────────────────────
       Sticky mobile CTA

       Bottom-pinned email pill that appears on mobile after the user
       scrolls past the hero. Hidden by default; JS toggles .is-visible.
       Honors safe-area-inset-bottom so it doesn't sit under the iOS
       home indicator. Tucks itself away when the user is *in* the
       closing-CTA section so it doesn't double up with the main form.
       ───────────────────────────────────────────────────────────────────── */
    .sticky-cta {
      position: fixed;
      left: 16px; right: 16px;
      bottom: calc(16px + env(safe-area-inset-bottom));
      z-index: 90;
      padding: 8px 8px 8px 16px;
      background: rgba(10, 10, 15, 0.92);
      backdrop-filter: blur(28px) saturate(1.4);
      -webkit-backdrop-filter: blur(28px) saturate(1.4);
      border: 1px solid var(--hairline);
      border-radius: var(--radius-pill);
      box-shadow: 0 16px 36px rgba(0, 0, 0, 0.45);
      display: none;
      align-items: center;
      gap: 8px;
      transform: translateY(120%);
      opacity: 0;
      transition: transform 0.4s var(--ease-out), opacity 0.4s var(--ease-out);
    }
    .sticky-cta.is-visible {
      transform: translateY(0);
      opacity: 1;
    }
    .sticky-cta.is-suppressed {
      transform: translateY(120%);
      opacity: 0;
      pointer-events: none;
    }
    .sticky-cta input {
      flex: 1; min-width: 0;
      background: transparent;
      border: 0; outline: 0;
      padding: 10px 4px;
      font-family: inherit;
      font-size: 14px;
      color: var(--fg);
    }
    .sticky-cta input::placeholder { color: var(--fg-tertiary); }
    .sticky-cta-text { flex: 1; min-width: 0; font-size: 14px; color: var(--fg-secondary); padding-left: 2px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
    .sticky-cta-text b { color: var(--fg); }
    .sticky-cta-btn {
      flex-shrink: 0; padding: 10px 16px; border-radius: var(--radius-pill);
      background: var(--gradient); color: #fff; font-weight: 700; font-size: 13px;
      text-decoration: none; white-space: nowrap;
    }
    .sticky-cta button {
      appearance: none;
      border: 0;
      cursor: pointer;
      padding: 10px 16px;
      border-radius: var(--radius-pill);
      background: var(--gradient);
      color: white;
      font-family: inherit;
      font-weight: 700;
      font-size: 13px;
      letter-spacing: -0.005em;
      flex-shrink: 0;
    }
    .sticky-cta-msg {
      position: absolute;
      bottom: calc(100% + 8px);
      left: 0; right: 0;
      text-align: center;
      font-size: 12px;
      color: var(--vibe-pink);
      opacity: 0;
      transform: translateY(4px);
      transition: opacity 0.3s ease, transform 0.3s ease;
      pointer-events: none;
    }
    .sticky-cta-msg.is-shown {
      opacity: 1;
      transform: translateY(0);
    }
    /* Only show on small screens. Below 640px the regular header CTA
       isn't visible without scrolling, which is what the sticky bar
       solves; above 640px the regular nav CTA is always there. */
    @media (max-width: 640px) {
      .sticky-cta { display: flex; }
    }

    /* ─────────────────────────────────────────────────────────────────────
       FAQ
       Anticipates the questions a skeptic asks before they decide whether
       to install. Native <details>/<summary> for a11y + free state mgmt.
       Custom-styled to match the page vocabulary instead of the browser
       default disclosure triangle.
       ───────────────────────────────────────────────────────────────────── */
    .faq-section {
      padding: 96px 32px 128px;
      max-width: 920px;
      margin: 0 auto;
    }
    .faq-list {
      margin-top: 48px;
      display: flex;
      flex-direction: column;
      gap: 4px;
    }
    .faq-item {
      border-top: 1px solid var(--hairline-soft);
      padding: 4px 0;
    }
    .faq-item:last-child {
      border-bottom: 1px solid var(--hairline-soft);
    }
    /* Hide the default disclosure marker and replace with a custom
       plus/minus that rotates on open. The rotation is hardware-
       accelerated so it stays smooth on cheaper Android browsers. */
    .faq-item summary {
      list-style: none;
      cursor: pointer;
      padding: 28px 4px;
      display: grid;
      grid-template-columns: 1fr 24px;
      align-items: center;
      gap: 16px;
      font-family: "Antonio", "Arial Narrow", "Roboto Condensed", "Inter Tight", -apple-system, sans-serif;
      font-size: clamp(20px, 2.2vw, 28px);
      font-weight: 700;
      line-height: 1.05;
      letter-spacing: -0.02em;
      text-transform: uppercase;
      color: var(--fg);
      transition: color 0.2s ease;
    }
    .faq-item summary::-webkit-details-marker { display: none; }
    .faq-item summary:hover { color: var(--vibe-pink); }
    .faq-item summary::after {
      content: "";
      width: 14px;
      height: 14px;
      background-image:
        linear-gradient(currentColor, currentColor),
        linear-gradient(currentColor, currentColor);
      background-size: 14px 1.5px, 1.5px 14px;
      background-position: center;
      background-repeat: no-repeat;
      transition: transform 0.3s var(--ease-out), background-size 0.3s var(--ease-out);
      color: var(--fg-secondary);
      justify-self: end;
    }
    .faq-item[open] summary::after {
      /* Rotate + remove the vertical bar to morph plus → minus. */
      transform: rotate(180deg);
      background-size: 14px 1.5px, 0 14px;
    }
    .faq-answer {
      padding: 0 4px 22px;
      font-size: 15px;
      line-height: 1.6;
      color: var(--fg-secondary);
      max-width: 64ch;
    }
    .faq-answer p + p { margin-top: 12px; }
    .faq-answer a {
      color: var(--vibe-pink);
      text-decoration: none;
      border-bottom: 1px solid currentColor;
    }
    .faq-answer a:hover { color: var(--vibe-purple); }

    /* ─────────────────────────────────────────────────────────────────────
       Email capture (notify-me-at-launch)
       Lives inside the closing CTA card so it doesn't fragment the page
       into another full-bleed section. Uses Formspree as the action so
       there's no backend to host. Replace the action= URL with a real
       Formspree endpoint after creating the form (free tier is fine).
       ───────────────────────────────────────────────────────────────────── */
    .email-capture {
      max-width: 480px;
      margin: 32px auto 0;
      display: flex;
      gap: 8px;
      padding: 6px;
      background: rgba(255, 255, 255, 0.05);
      border: 1px solid var(--hairline);
      border-radius: var(--radius-pill);
      backdrop-filter: blur(20px);
      -webkit-backdrop-filter: blur(20px);
      transition: border-color 0.3s ease, box-shadow 0.3s ease;
    }
    .email-capture:focus-within {
      border-color: rgba(255, 90, 138, 0.45);
      box-shadow: 0 0 0 4px rgba(255, 90, 138, 0.10);
    }
    .email-capture input {
      flex: 1;
      min-width: 0;
      background: transparent;
      border: 0;
      outline: 0;
      padding: 12px 18px;
      font-family: inherit;
      font-size: 15px;
      color: var(--fg);
      letter-spacing: -0.005em;
    }
    .email-capture input::placeholder { color: var(--fg-tertiary); }
    .email-capture button {
      appearance: none;
      border: 0;
      cursor: pointer;
      padding: 12px 22px;
      border-radius: var(--radius-pill);
      background: var(--fg);
      color: var(--bg);
      font-family: inherit;
      font-weight: 600;
      font-size: 14px;
      letter-spacing: -0.005em;
      transition: transform 0.2s var(--ease-out), background 0.2s ease;
      white-space: nowrap;
    }
    .email-capture button:hover { transform: translateY(-1px); }
    .email-capture button:disabled {
      opacity: 0.55;
      cursor: not-allowed;
      transform: none;
    }
    .email-capture-msg {
      margin-top: 14px;
      font-size: 13px;
      color: var(--fg-tertiary);
      min-height: 18px;
      transition: color 0.2s ease;
    }
    .email-capture-msg.is-success { color: var(--vibe-purple); }
    .email-capture-msg.is-error { color: #FF7A8A; }
    /* Inline form-divider — renders the "or" word between the email
       capture and the TestFlight CTA when both are present. Visually
       quieter than a horizontal rule. */
    .cta-or {
      margin: 28px auto 16px;
      display: flex;
      align-items: center;
      gap: 14px;
      max-width: 480px;
      color: var(--fg-tertiary);
      font-size: 12px;
      letter-spacing: 0.16em;
      text-transform: uppercase;
    }
    .cta-or::before, .cta-or::after {
      content: "";
      flex: 1;
      height: 1px;
      background: var(--hairline-soft);
    }

    /* ─────────────────────────────────────────────────────────────────────
       Closing CTA
       ───────────────────────────────────────────────────────────────────── */
    .cta-section {
      padding: 128px 32px;
    }
    /* Closing CTA — Wrapped poster. Solid Neon Dusk panel with the
       coral accent half-circle bleeding off the top-right, mirroring
       the hero composition so the page reads as one signature piece
       rather than a stack of unrelated sections. */
    .cta-card {
      max-width: 1080px;
      margin: 0 auto;
      padding: 96px 64px;
      background: var(--neon-dusk-bg);
      color: white;
      border: 0;
      border-radius: 36px;
      text-align: left;
      position: relative;
      overflow: hidden;
      isolation: isolate;
    }
    .cta-card::before {
      /* Bold accent half-circle bleeding off top-right. Same recipe as
         the hero + bento cards. */
      content: "";
      position: absolute;
      top: -30%;
      right: -18%;
      width: 56%;
      aspect-ratio: 1;
      border-radius: 50%;
      background: var(--neon-dusk-accent);
      z-index: -1;
    }
    .cta-card::after {
      /* Secondary peak-sun blob bottom-left for two-tone depth. */
      content: "";
      position: absolute;
      bottom: -22%;
      left: -10%;
      width: 36%;
      aspect-ratio: 1;
      border-radius: 50%;
      background: var(--peak-sun-bg);
      opacity: 0.75;
      z-index: -1;
    }
    .cta-content { position: relative; z-index: 1; }
    .cta-title {
      font-family: "Antonio", "Arial Narrow", "Roboto Condensed", "Inter Tight", -apple-system, sans-serif;
      font-weight: 700;
      /* Lowered min from 56px to 44px for narrow phones. */
      font-size: clamp(44px, 8vw, 120px);
      letter-spacing: -0.03em;
      line-height: 0.88;
      text-transform: uppercase;
      margin-bottom: 24px;
      max-width: 14ch;
    }
    .cta-sub {
      font-size: 18px;
      color: rgba(255, 255, 255, 0.84);
      max-width: 50ch;
      margin: 0 0 36px;
      line-height: 1.5;
    }
    .cta-buttons { display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; }

    /* Primary install button — solid white-on-coral pill with bold
       Antonio caps. Inside the dark CTA poster the white reads as the
       loudest possible affordance. */
    .btn-glow {
      position: relative;
      padding: 22px 36px;
      background: white;
      color: var(--neon-dusk-bg);
      text-decoration: none;
      font-family: "Antonio", "Arial Narrow", "Roboto Condensed", "Inter Tight", -apple-system, sans-serif;
      font-weight: 700;
      font-size: 18px;
      letter-spacing: 0.04em;
      text-transform: uppercase;
      border-radius: var(--radius-pill);
      transition: transform 0.2s var(--ease-out), background 0.3s ease, color 0.3s ease;
    }
    .btn-glow:hover {
      transform: translateY(-1px);
      background: var(--peak-sun-bg);
      color: var(--neon-dusk-bg);
    }

    /* ─────────────────────────────────────────────────────────────────────
       Cookie consent banner (EU only)

       Shown only to users whose timezone matches an EU/UK/EEA region.
       This is a heuristic — IP-based geo would be more accurate, but
       requires a backend or third-party API. Timezone-based detection
       gets us 95% accuracy with zero network cost and zero PII.

       Three states:
         (a) hidden — user has already chosen, or isn't in EU
         (b) visible — initial paint
         (c) dismissed — user clicked Accept or Decline

       The choice persists in localStorage. Re-prompts only happen when
       the consent version (COOKIE_CONSENT_VERSION) bumps in the JS,
       which we'd do if we materially changed what cookies we use.
       ───────────────────────────────────────────────────────────────────── */
    .cookie-banner {
      position: fixed;
      left: 16px;
      right: 16px;
      bottom: calc(16px + env(safe-area-inset-bottom));
      max-width: 640px;
      margin: 0 auto;
      padding: 18px 20px;
      background: rgba(15, 15, 21, 0.92);
      backdrop-filter: blur(28px) saturate(1.4);
      -webkit-backdrop-filter: blur(28px) saturate(1.4);
      border: 1px solid var(--hairline);
      border-radius: 18px;
      box-shadow: 0 24px 48px rgba(0, 0, 0, 0.45);
      z-index: 95;
      display: none;
      flex-wrap: wrap;
      align-items: center;
      gap: 12px;
      transform: translateY(20px);
      opacity: 0;
      transition: transform 0.4s var(--ease-out), opacity 0.4s var(--ease-out);
    }
    .cookie-banner.is-visible {
      display: flex;
      transform: translateY(0);
      opacity: 1;
    }
    .cookie-banner-text {
      flex: 1;
      min-width: 220px;
      font-size: 13px;
      line-height: 1.5;
      color: var(--fg-secondary);
    }
    .cookie-banner-text strong { color: var(--fg); }
    .cookie-banner-text a {
      color: var(--vibe-pink);
      text-decoration: none;
      border-bottom: 1px solid currentColor;
    }
    .cookie-banner-buttons {
      display: flex;
      gap: 8px;
      flex-shrink: 0;
    }
    .cookie-banner button {
      appearance: none;
      cursor: pointer;
      padding: 9px 14px;
      border-radius: var(--radius-pill);
      font-family: inherit;
      font-size: 13px;
      font-weight: 600;
      letter-spacing: -0.005em;
      border: 1px solid var(--hairline);
      background: var(--bg-elev-2);
      color: var(--fg);
      transition: background 0.2s ease, transform 0.18s var(--ease-out);
    }
    .cookie-banner button:hover { background: var(--bg-elev-3); }
    .cookie-banner button:active { transform: scale(0.96); }
    .cookie-banner button.is-primary {
      background: var(--fg);
      color: var(--bg);
      border-color: transparent;
    }
    .cookie-banner button.is-primary:hover {
      background: var(--vibe-pink);
      color: white;
    }
    @media (prefers-reduced-motion: reduce) {
      .cookie-banner { transition: none; }
    }

    /* ─────────────────────────────────────────────────────────────────────
       Footer

       Full site footer — five columns on desktop (Brand / Product /
       Resources / Connect / Legal), plus a colophon row beneath.
       Collapses gracefully: 3 cols at 1024px, 2 cols at 768px, 1 col
       at 480px. The brand column is always twice the width of the
       link columns since it carries copy weight, not just links.
       ───────────────────────────────────────────────────────────────────── */
    footer {
      padding: 96px 32px 48px;
      border-top: 1px solid var(--hairline-soft);
      background:
        radial-gradient(60% 80% at 50% 0%, rgba(165, 107, 255, 0.06), transparent 70%);
    }
    .footer-grid {
      max-width: 1280px;
      margin: 0 auto;
      display: grid;
      grid-template-columns: 2fr 1fr 1fr 1fr 1fr;
      gap: 48px 32px;
    }

    .footer-brand {
      display: flex;
      flex-direction: column;
      gap: 16px;
      max-width: 32ch;
    }
    .footer-brand-mark {
      display: flex;
      align-items: center;
      gap: 12px;
      font-weight: 700;
      font-size: 17px;
      letter-spacing: -0.01em;
    }
    .footer-brand-mark img {
      width: 32px; height: 32px;
      border-radius: 9px;
      object-fit: cover;
    }
    .footer-tagline {
      font-size: 14px;
      color: var(--fg-secondary);
      line-height: 1.55;
    }

    .footer-col {
      display: flex;
      flex-direction: column;
      gap: 14px;
    }
    .footer-col-title {
      font-size: 11px;
      font-weight: 700;
      letter-spacing: 0.16em;
      text-transform: uppercase;
      color: var(--fg-tertiary);
      margin-bottom: 4px;
    }
    .footer-col a {
      font-size: 14px;
      color: var(--fg-secondary);
      text-decoration: none;
      transition: color 0.2s ease;
      display: inline-flex;
      align-items: center;
      gap: 8px;
      width: fit-content;
    }
    .footer-col a:hover { color: var(--fg); }
    .footer-col a .external-glyph {
      width: 10px;
      height: 10px;
      opacity: 0.5;
    }
    .footer-col a:hover .external-glyph { opacity: 1; }

    /* Social row — pill-shaped chip per platform, sits underneath the
       brand column on desktop. */
    .footer-social {
      display: flex;
      gap: 8px;
      margin-top: 8px;
    }
    .footer-social a {
      width: 36px; height: 36px;
      border-radius: 50%;
      background: var(--bg-elev-1);
      border: 1px solid var(--hairline);
      display: grid;
      place-items: center;
      color: var(--fg-secondary);
      transition: background 0.2s ease, border-color 0.2s ease, color 0.2s ease;
    }
    .footer-social a:hover {
      background: var(--bg-elev-2);
      border-color: var(--bg-elev-3);
      color: var(--fg);
    }

    /* New badge for unbuilt links — visually softens the "this isn't
       up yet" while still letting users know what's coming. */
    .footer-badge {
      font-size: 9px;
      font-weight: 700;
      letter-spacing: 0.08em;
      text-transform: uppercase;
      color: var(--vibe-purple);
      padding: 2px 6px;
      border-radius: 999px;
      background: rgba(165, 107, 255, 0.12);
      border: 1px solid rgba(165, 107, 255, 0.25);
    }

    /* Colophon row beneath the columns — copyright, "made with care,"
       region/locale chip, sneaky little credit. Kept quiet. */
    .footer-base {
      max-width: 1280px;
      margin: 64px auto 0;
      padding-top: 32px;
      border-top: 1px solid var(--hairline-soft);
      display: flex;
      flex-wrap: wrap;
      gap: 24px;
      align-items: center;
      font-size: 12px;
      color: var(--fg-tertiary);
      letter-spacing: -0.005em;
    }
    .footer-base .colophon-spacer { flex: 1; }
    .footer-base .colophon-item {
      display: inline-flex;
      align-items: center;
      gap: 8px;
    }
    .footer-base .colophon-item a {
      color: var(--fg-secondary);
      text-decoration: none;
    }
    .footer-base .colophon-item a:hover { color: var(--fg); }
    .footer-base .made-glyph {
      color: var(--vibe-pink);
      animation: heartpulse 2.6s ease-in-out infinite;
    }
    @keyframes heartpulse {
      0%, 100% { transform: scale(1); }
      45%      { transform: scale(1.18); }
      55%      { transform: scale(1.10); }
    }
    @media (prefers-reduced-motion: reduce) {
      .footer-base .made-glyph { animation: none; }
    }

    /* ─────────────────────────────────────────────────────────────────────
       Responsive
       ───────────────────────────────────────────────────────────────────── */
    @media (max-width: 1024px) {
      .bento-grid { grid-template-columns: repeat(2, 1fr); grid-auto-rows: auto; }
      .span-3-2, .span-3-1, .span-2-1, .span-2-2, .span-4-1 { grid-column: span 2; grid-row: auto; }
      .hero-bottom { grid-template-columns: 1fr; gap: 32px; }
      .hero { padding: 140px 24px 80px; }
      .nav-links { display: none; }
      .manifesto { grid-template-columns: 1fr; gap: 16px; padding: 24px 24px; }
      .footer-grid { grid-template-columns: 1.5fr 1fr 1fr; gap: 40px 24px; }
      .footer-grid .footer-col:nth-child(5) { grid-column: 1 / -1; }
    }
    @media (max-width: 768px) {
      .footer-grid { grid-template-columns: 1fr 1fr; }
      .footer-brand { grid-column: 1 / -1; }
    }
    @media (max-width: 640px) {
      /*
        Mobile bento → horizontal flick-through carousel.

        Trade-off: a vertically-stacked bento on mobile turns the
        features section into a 6-card column the user has to thumb-
        scroll through. That works but reads like every other
        Bootstrap landing on the web. By switching to a horizontal
        scroll-snap carousel on mobile we get:
          • A native, App-Store-quality flick interaction
          • Each card occupies the viewport at its own moment, so
            the user sees the design at full width instead of half-width
          • A scroll-cue (peek) at the right edge tells the user
            there's more, without a desktop-style "scroll →" caption

        scroll-snap-type: x mandatory means each flick lands on a
        card, never between them. scroll-padding-left mirrors the
        section's left padding so the snapped card stays inset by
        the same amount as the section title above it.
      */
      /* (`.bento-section` padding is set in the section-padding
         block below — kept here only the inner section-eyebrow /
         section-title insets that need the bento-grid's 24px gutter.) */
      .bento-section > .section-eyebrow,
      .bento-section > .section-title {
        padding-left: 24px;
        padding-right: 24px;
      }
      .bento-grid {
        display: flex;
        grid-template-columns: none;
        grid-auto-rows: auto;
        gap: 12px;
        padding: 0 24px;
        overflow-x: auto;
        overflow-y: hidden;
        scroll-snap-type: x mandatory;
        scroll-padding-left: 24px;
        scrollbar-width: none;
        -webkit-overflow-scrolling: touch;
      }
      .bento-grid::-webkit-scrollbar { display: none; }
      .bento-grid > .card {
        flex: 0 0 86%;
        min-height: 340px;
        scroll-snap-align: start;
        scroll-snap-stop: always;
      }
      /* Spans collapse — every card is the same width on mobile. The
         postcard card is still the most important one, so we let it
         lead. */
      .span-3-2, .span-3-1, .span-2-1, .span-2-2, .span-4-1 {
        grid-column: auto;
        grid-row: auto;
      }
      /* Add a trailing spacer so the last card can snap to the left
         edge with the same inset as the first card — without it the
         last card snaps tight against the screen edge. */
      .bento-grid::after {
        content: "";
        flex: 0 0 12px;
      }

      .hero-cta { flex-direction: column; align-items: stretch; }
      .btn { justify-content: center; }
      .cta-card { padding: 56px 24px; border-radius: 24px; }
      .footer-grid { grid-template-columns: 1fr; gap: 40px; }
      .footer-base { flex-direction: column; align-items: flex-start; gap: 12px; }
      .footer-base .colophon-spacer { display: none; }
      .recap-row { grid-template-columns: 1fr; }
      .friends-row { gap: 8px; }

      /* The privacy diagram's 5-col grid is too wide for phone screens
         — fall back to a vertical stack with the arrows turned 90°. */
      .privacy-flow {
        grid-template-columns: 1fr;
        gap: 8px;
      }
      .privacy-arrow {
        transform: rotate(90deg);
        justify-self: center;
      }

      /* Email capture stack — the inline pill input + button doesn't
         have room on a 320px screen. Stack vertically so the input
         can breathe. */
      .email-capture {
        flex-direction: column;
        border-radius: 20px;
        padding: 8px;
      }
      .email-capture button { width: 100%; }

      /* ─── Section padding reductions for narrow phones ───────────
         Default desktop section padding is 96–160px vertical / 32px
         horizontal. At 320–414px viewports the 32px horizontal eats
         too much usable width and the 96–160px vertical adds dead
         space between sections. Trim both so the page reads as
         dense and continuous on mobile. */
      .hero            { padding: 100px 20px 64px; }
      .bento-section   { padding: 64px 0 80px; }
      .recap-section   { padding: 64px 0 64px; }
      .anti-section    { padding: 64px 20px; }
      .writing-section { padding: 64px 20px 24px; }
      .faq-section     { padding: 64px 20px 80px; }
      .cta-section     { padding: 64px 20px 96px; }

      /* The writing-grid was already responsive (4→2→1); this just
         ensures the cards aren't pinched at 320px. */
      .writing-card { min-height: 280px; padding: 24px 22px 22px; }
      .writing-card-title { font-size: clamp(22px, 6.5vw, 30px); }

      /* Pull in the giant nav title so logo + CTA both fit on a
         320px viewport without jamming the edges. */
      nav { padding: 6px 6px 6px 12px; gap: 6px; }
      .nav-cta { padding: 8px 14px; font-size: 13px; }
      .nav-logo { padding: 4px 6px 4px 0; font-size: 14px; }
    }

    /* ─────────────────────────────────────────────────────────────────
       Writing / blog section
       Surfaces the long-form posts that explain the why behind the
       refusals listed in the anti-section above. Each card is a
       solid-palette poster matching the iOS app's Wrapped vocabulary —
       same recipe as the recap cards and the bento heroes, just at
       reading-card scale.
       ───────────────────────────────────────────────────────────────── */
    .writing-section {
      max-width: 1200px;
      margin: 0 auto;
      padding: 96px 32px 32px;
    }
    .writing-section .writing-intro {
      color: var(--fg-secondary);
      font-size: 17px;
      max-width: 56ch;
      margin: -32px 0 56px;
    }

    .writing-grid {
      display: grid;
      grid-template-columns: repeat(4, 1fr);
      gap: 16px;
    }
    @media (max-width: 1100px) {
      .writing-grid { grid-template-columns: repeat(2, 1fr); }
    }
    @media (max-width: 600px) {
      .writing-grid { grid-template-columns: 1fr; }
    }

    .writing-card {
      position: relative;
      overflow: hidden;
      isolation: isolate;
      padding: 28px 26px 26px;
      border-radius: var(--radius-card);
      background: var(--w-card-bg, var(--neon-dusk-bg));
      color: var(--w-card-fg, white);
      text-decoration: none;
      display: flex;
      flex-direction: column;
      gap: 14px;
      min-height: 320px;
      transition: transform 0.3s var(--ease-out), box-shadow 0.3s var(--ease-out);
    }
    .writing-card:hover {
      transform: translateY(-4px);
      box-shadow: 0 24px 48px rgba(0, 0, 0, 0.4);
    }
    /* Signature accent half-circle, bleeding off top-trailing — same
       composition the iOS app's Story panels and the bento heroes use. */
    .writing-card::after {
      content: "";
      position: absolute;
      top: -32%;
      right: -22%;
      width: 70%;
      aspect-ratio: 1;
      border-radius: 50%;
      background: var(--w-card-accent, var(--neon-dusk-accent));
      opacity: 0.95;
      z-index: -1;
      transition: transform 0.5s var(--ease-out);
    }
    .writing-card:hover::after { transform: scale(1.06); }

    .writing-card-meta {
      font-size: 11px;
      font-weight: 800;
      letter-spacing: 0.18em;
      text-transform: uppercase;
      color: var(--w-card-fg-muted, rgba(255, 255, 255, 0.74));
      display: flex;
      flex-wrap: wrap;
      gap: 8px;
      align-items: center;
    }
    .writing-card-tag {
      padding: 3px 9px;
      border-radius: 999px;
      background: rgba(255, 255, 255, 0.18);
      border: 1px solid rgba(255, 255, 255, 0.30);
      letter-spacing: 0.14em;
      font-weight: 700;
    }
    /* Light-palette cards (peak-sun, vapor) — invert the chip so it
       still reads against the lighter background. */
    .writing-card.is-light .writing-card-tag {
      background: rgba(26, 23, 69, 0.14);
      border-color: rgba(26, 23, 69, 0.30);
    }

    .writing-card-title {
      font-family: "Antonio", "Arial Narrow", "Roboto Condensed", "Inter Tight", -apple-system, sans-serif;
      font-weight: 700;
      font-size: clamp(26px, 2.4vw, 34px);
      line-height: 0.96;
      letter-spacing: -0.025em;
      text-transform: uppercase;
      max-width: 14ch;
      margin-top: auto;
    }

    .writing-card-body {
      font-size: 14px;
      line-height: 1.55;
      color: var(--w-card-fg-muted, rgba(255, 255, 255, 0.82));
      max-width: 38ch;
    }

    .writing-card-cta {
      font-family: "Antonio", "Arial Narrow", "Roboto Condensed", "Inter Tight", -apple-system, sans-serif;
      font-weight: 700;
      font-size: 12px;
      letter-spacing: 0.16em;
      text-transform: uppercase;
      color: var(--w-card-fg, white);
      opacity: 0.85;
      transition: opacity 0.2s ease, transform 0.2s var(--ease-out);
      margin-top: 8px;
    }
    .writing-card:hover .writing-card-cta {
      opacity: 1;
      transform: translateX(2px);
    }

    /* Per-card palette mixins — same StoryPalette pairs as the iOS
       app's curated set + the wrapped.css cards on secondary pages. */
    .writing-card--marathon     { --w-card-bg: var(--marathon-bg);     --w-card-accent: var(--marathon-accent);     --w-card-fg: white; }
    .writing-card--neon-dusk    { --w-card-bg: var(--neon-dusk-bg);    --w-card-accent: var(--neon-dusk-accent);    --w-card-fg: white; }
    .writing-card--citrus-glass { --w-card-bg: var(--citrus-glass-bg); --w-card-accent: var(--citrus-glass-accent); --w-card-fg: white; }
    .writing-card--vapor        { --w-card-bg: var(--vapor-bg);        --w-card-accent: var(--vapor-accent);        --w-card-fg: #0A1F1A; --w-card-fg-muted: rgba(10, 31, 26, 0.74); }

    /* "View all posts" footer link — quiet, sits below the grid. */
    .writing-all {
      display: inline-flex;
      align-items: center;
      gap: 8px;
      margin-top: 32px;
      font-family: "Antonio", "Arial Narrow", "Roboto Condensed", "Inter Tight", -apple-system, sans-serif;
      font-weight: 700;
      font-size: 13px;
      letter-spacing: 0.16em;
      text-transform: uppercase;
      color: var(--fg-secondary);
      text-decoration: none;
      padding: 14px 22px;
      border-radius: 999px;
      border: 1px solid var(--hairline);
      background: var(--bg-elev-1);
      transition: color 0.2s ease, border-color 0.2s ease, background 0.2s ease, transform 0.2s var(--ease-out);
    }
    .writing-all:hover {
      color: var(--fg);
      border-color: var(--bg-elev-3);
      background: var(--bg-elev-2);
      transform: translateY(-1px);
    }

    /* ─────────────────────────────────────────────────────────────────
       Modern animations — three additions, all progressive enhancement,
       all reduce-motion respecting.

       1) Scroll-driven section reveals — sections fade in + lift 16px
          as they cross into the viewport. Uses the native CSS
          animation-timeline: view() API (Chromium full, Safari 18.2+,
          Firefox in progress). Browsers without support just see the
          static layout — same behavior as today.

       2) Hero accent palette drift — the big coral half-circle in
          the hero already drifts on a 30s position loop. Now it ALSO
          cycles through the curated StoryPalette accent colors on a
          slower 60s loop. Mirrors the iOS app's per-song palette
          extraction. Uses CSS @property to interpolate the color
          smoothly.

       3) Cross-document view transitions — clicking a writing-card
          on the homepage smoothly morphs into the corresponding
          blog post hero. Native @view-transition rule (Chromium
          126+, Safari 18.2+). Each shared title gets a matching
          view-transition-name, set inline on the writing-card-title
          + the corresponding post page <h1>.
       ───────────────────────────────────────────────────────────────── */

    /* (1) Scroll-driven section reveals */
    @keyframes section-reveal {
      from {
        opacity: 0;
        transform: translateY(16px);
      }
      to {
        opacity: 1;
        transform: translateY(0);
      }
    }

    /* Apply to every major section below the hero. The hero itself
       stays fully visible at load — first impression matters and
       we don't want the headline ghosting in. */
    .bento-section,
    .recap-section,
    .anti-section,
    .writing-section,
    .faq-section,
    .cta-section {
      animation: section-reveal linear both;
      animation-timeline: view();
      /* Animation plays from the moment a section's leading edge
         enters the viewport (entry 0%) to when it's 50% in (entry
         50%) — the section is fully revealed by the time the
         reader reaches its first content. */
      animation-range: entry 0% entry 50%;
    }

    /* (2) Hero accent palette drift — color cycles through the
       curated StoryPalette accent set on a slow 60s loop. */
    @property --hero-accent {
      syntax: "<color>";
      inherits: false;
      initial-value: #FF3B7A;
    }

    @keyframes hero-accent-cycle {
      0%   { --hero-accent: var(--neon-dusk-accent); }    /* coral */
      25%  { --hero-accent: var(--marathon-accent); }     /* electric blue */
      50%  { --hero-accent: var(--citrus-glass-accent); } /* orange */
      75%  { --hero-accent: var(--late-drive-accent); }   /* amber */
      100% { --hero-accent: var(--neon-dusk-accent); }    /* back to coral */
    }

    /* Override the static accent fill on the mesh's accent circle
       with the cycling --hero-accent custom property. The existing
       30s drift animation continues to control position; this adds
       a parallel 60s color cycle so the accent is always changing
       in two dimensions at once. */
    .mesh::before {
      background: var(--hero-accent);
      animation: drift 30s ease-in-out infinite alternate,
                 hero-accent-cycle 60s linear infinite;
    }

    @media (prefers-reduced-motion: reduce) {
      /* Reduced motion: drop the section reveals + the palette
         cycle. Sections render statically; accent stays on the
         neon-dusk coral. The position drift is already disabled
         by the existing reduce-motion guard further up. */
      .bento-section,
      .recap-section,
      .anti-section,
      .writing-section,
      .faq-section,
      .cta-section {
        animation: none;
        opacity: 1;
        transform: none;
      }
      .mesh::before {
        animation: none;
        background: var(--neon-dusk-accent);
      }
    }

    /* ─────────────────────────────────────────────────────────────────────
       SCROLLYTELLING — "One song. One friend. One note."
       A single cinematic pinned sequence. A tall track (300vh) holds a
       sticky 100vh stage; as the reader scrolls through the track, the
       stage pins and three beats scrub past: the song card appears, it
       hands off to a friend (postcard-in-flight), and a handwritten note
       writes itself in. Ends on the postcard tagline.

       Progressive enhancement, three tiers:
         • DEFAULT (no scroll-driven-animation support): the pin + scrub
           are never applied. The track is auto-height, the stage is
           static, and all three beats render stacked + fully visible —
           a clean, legible column. Zero JS required.
         • @supports (animation-timeline: view()): pin + scrub turn on.
           Beats overlay and animate on the track's own view-timeline,
           each mapped to a slice of the `contain` phase (= the pinned
           window, since the 300vh track is taller than the viewport).
         • prefers-reduced-motion (inside the @supports block): revert to
           the static stacked layout — no pin, no scrub.
       GPU-friendly: only opacity / transform / clip-path animate.
       ───────────────────────────────────────────────────────────────────── */

    .scrolly {
      position: relative;
    }
    /* Tall scroll container. Default height auto = no pin (fallback). */
    .scrolly-track {
      position: relative;
    }
    /* The stage. Default static (fallback); becomes sticky under @supports. */
    .scrolly-stage {
      position: relative;
      padding: 96px 32px;
      max-width: 1280px;
      margin: 0 auto;
      overflow: hidden;
    }
    /* Soft aurora backdrop — palette accents, blurred, consistent with
       the page's aurora blobs. Static (no motion). */
    .scrolly-aurora {
      position: absolute;
      inset: -20% -10%;
      z-index: 0;
      pointer-events: none;
      background:
        radial-gradient(38% 42% at 22% 30%, rgba(255, 59, 122, 0.28), transparent 70%),
        radial-gradient(34% 40% at 82% 26%, rgba(135, 102, 255, 0.24), transparent 72%),
        radial-gradient(46% 50% at 60% 88%, rgba(31, 184, 255, 0.18), transparent 74%);
      filter: blur(30px);
      opacity: 0.9;
    }
    .scrolly-inner {
      position: relative;
      z-index: 1;
      display: flex;
      flex-direction: column;
      align-items: center;
      text-align: center;
    }
    .scrolly-eyebrow {
      justify-content: center;
      margin-bottom: 40px;
    }
    /* Beats container. Fallback: normal flow, stacked. */
    .scrolly-beats {
      position: relative;
      width: 100%;
      display: flex;
      flex-direction: column;
      align-items: center;
      gap: 72px;
    }
    .scrolly-beat {
      display: flex;
      flex-direction: column;
      align-items: center;
      gap: 20px;
      width: 100%;
    }
    .scrolly-count {
      font-family: "Fraunces", Georgia, serif;
      font-style: italic;
      font-size: clamp(20px, 2.4vw, 30px);
      color: var(--fg-secondary);
      letter-spacing: 0.01em;
    }
    .scrolly-word {
      font-family: "Antonio", "Arial Narrow", "Roboto Condensed", "Inter Tight", -apple-system, sans-serif;
      font-weight: 700;
      font-size: clamp(56px, 13vw, 168px);
      line-height: 0.86;
      letter-spacing: -0.04em;
      text-transform: uppercase;
      color: var(--fg);
    }
    .scrolly-beat--song  .scrolly-word { color: var(--neon-dusk-accent); }
    .scrolly-beat--friend .scrolly-word { color: var(--vibe-blue, #1FB8FF); }
    .scrolly-beat--note  .scrolly-word { color: var(--peak-sun-bg, #FFD93B); }

    /* Beat 1 — the song card */
    .scrolly-card {
      display: inline-flex;
      align-items: center;
      gap: 16px;
      padding: 16px 22px 16px 16px;
      background: var(--bg-elev-2);
      border: 1px solid var(--hairline);
      border-radius: var(--radius-card);
      box-shadow: 0 20px 60px rgba(0, 0, 0, 0.4);
      max-width: 90vw;
    }
    .scrolly-card-art {
      width: 72px;
      height: 72px;
      border-radius: 14px;
      flex: 0 0 auto;
      background: linear-gradient(135deg, #8766FF, #FF3B7A);
      box-shadow: 0 10px 26px rgba(255, 59, 122, 0.36);
    }
    .scrolly-card-meta { display: flex; flex-direction: column; align-items: flex-start; gap: 4px; }
    .scrolly-card-t { font-weight: 700; font-size: 18px; color: #fff; }
    .scrolly-card-s { font-size: 14px; color: var(--fg-secondary); }

    /* Beat 2 — the handoff (postcard-in-flight) */
    .scrolly-handoff {
      position: relative;
      width: min(420px, 90vw);
      height: 120px;
      display: flex;
      align-items: center;
      justify-content: space-between;
      overflow: hidden;
    }
    .scrolly-flycard {
      position: absolute;
      left: 50%;
      top: 50%;
      width: 66px;
      height: 66px;
      margin: -33px 0 0 -33px;
      border-radius: 13px;
      background: linear-gradient(135deg, #8766FF, #FF3B7A);
      box-shadow: 0 14px 34px rgba(255, 59, 122, 0.42);
    }
    /* Sender (left) — where the song comes FROM. The flycard flies from
       here across to the friend on the right. */
    .scrolly-sender {
      position: relative;
      margin-right: auto;
      width: 64px;
      height: 64px;
      border-radius: 50%;
      background: linear-gradient(135deg, #8766FF, #FF3B7A);
      display: grid;
      place-items: center;
      box-shadow: 0 10px 26px rgba(0, 0, 0, 0.35);
      flex: 0 0 auto;
    }
    /* Friend / recipient (right) — where the song lands. */
    .scrolly-avatar {
      position: relative;
      margin-left: auto;
      width: 64px;
      height: 64px;
      border-radius: 50%;
      background: linear-gradient(135deg, #47E0D1, #FFC83B);
      display: grid;
      place-items: center;
      box-shadow: 0 10px 26px rgba(0, 0, 0, 0.35);
      flex: 0 0 auto;
    }
    .scrolly-avatar-name {
      font-family: "Antonio", sans-serif;
      font-weight: 700;
      font-size: 15px;
      letter-spacing: 0.04em;
      color: #0a0a12;
    }

    /* Beat 3 — the handwritten note */
    .scrolly-note {
      font-family: "Fraunces", Georgia, serif;
      font-style: italic;
      font-size: clamp(24px, 4.4vw, 46px);
      line-height: 1.25;
      color: #fff;
      max-width: 22ch;
    }

    .scrolly-tagline {
      margin-top: 64px;
      font-size: clamp(16px, 1.6vw, 20px);
      color: var(--fg-secondary);
      max-width: 40ch;
    }
    .scrolly-tagline .editorial { color: var(--fg); }

    @media (max-width: 720px) {
      .scrolly-stage { padding: 64px 20px; }
      .scrolly-beats { gap: 56px; }
    }

    /* ── Scroll-driven pin + scrub. Purely additive: only browsers with
       native scroll-driven animations enter this block; everyone else
       keeps the static stacked layout defined above. ── */
    @supports (animation-timeline: view()) {
      /* Pin the stage across the tall track. The 300vh track is taller
         than the viewport, so its view-timeline `contain` phase == the
         window during which the sticky stage is pinned full-viewport. */
      .scrolly-track {
        /* 220vh (was 300vh): same three beats, ~an 80vh shorter scroll. */
        min-height: 220vh;
        view-timeline-name: --scrolly;
        view-timeline-axis: block;
      }
      .scrolly-stage {
        position: sticky;
        top: 0;
        /* vh fallback first; svh so the pinned frame matches the
           toolbar-VISIBLE height on mobile and never clips a beat
           behind the browser chrome. svh is stable during the
           toolbar show/hide, so the scroll scrub stays smooth. */
        height: 100vh;
        height: 100svh;
        display: flex;
        flex-direction: column;
        justify-content: center;
      }
      /* Overlay the beats — they now cross-fade in place instead of
         stacking. Fixed height keeps the layout from jumping. */
      .scrolly-beats {
        height: clamp(320px, 46vh, 460px);
        height: clamp(300px, 46svh, 460px);
      }
      .scrolly-beat {
        position: absolute;
        inset: 0;
        justify-content: center;
        gap: 24px;
        opacity: 0;
        will-change: opacity, transform;
        animation: linear both;
        animation-timeline: --scrolly;
      }
      .scrolly-beat--song {
        animation-name: sc-beat-song;
        animation-range: contain 2% contain 40%;
      }
      .scrolly-beat--friend {
        animation-name: sc-beat-friend;
        animation-range: contain 33% contain 70%;
      }
      .scrolly-beat--note {
        animation-name: sc-beat-note;
        animation-range: contain 60% contain 100%;
      }
      /* The postcard flies left→right into the friend as beat 2 scrubs. */
      .scrolly-flycard {
        opacity: 0;
        will-change: opacity, transform;
        animation: sc-fly linear both;
        animation-timeline: --scrolly;
        animation-range: contain 34% contain 70%;
      }
      .scrolly-avatar {
        will-change: transform;
        animation: sc-avatar linear both;
        animation-timeline: --scrolly;
        animation-range: contain 42% contain 70%;
      }
      /* The note writes itself in, left→right, as beat 3 scrubs. */
      .scrolly-note {
        clip-path: inset(0 100% 0 0);
        will-change: clip-path, opacity;
        animation: sc-note-write linear both;
        animation-timeline: --scrolly;
        animation-range: contain 66% contain 90%;
      }
      /* Tagline lands last. */
      .scrolly-tagline {
        opacity: 0;
        will-change: opacity, transform;
        animation: sc-tagline linear both;
        animation-timeline: --scrolly;
        animation-range: contain 86% contain 100%;
      }
    }

    @keyframes sc-beat-song {
      0%   { opacity: 0; transform: translateY(44px) scale(0.96); }
      18%  { opacity: 1; transform: translateY(0) scale(1); }
      74%  { opacity: 1; transform: translateY(0) scale(1); }
      100% { opacity: 0; transform: translateY(-32px) scale(0.98); }
    }
    @keyframes sc-beat-friend {
      0%   { opacity: 0; transform: translateY(44px); }
      24%  { opacity: 1; transform: translateY(0); }
      78%  { opacity: 1; transform: translateY(0); }
      100% { opacity: 0; transform: translateY(-32px); }
    }
    @keyframes sc-beat-note {
      0%   { opacity: 0; transform: translateY(44px); }
      26%  { opacity: 1; transform: translateY(0); }
      100% { opacity: 1; transform: translateY(0); }
    }
    @keyframes sc-fly {
      0%   { opacity: 0; transform: translate(-150px, 12px) rotate(-9deg) scale(0.78); }
      28%  { opacity: 1; transform: translate(-70px, -6px) rotate(-3deg) scale(1); }
      70%  { opacity: 1; transform: translate(96px, -4px) rotate(5deg) scale(0.9); }
      100% { opacity: 0; transform: translate(150px, 8px) rotate(9deg) scale(0.66); }
    }
    @keyframes sc-avatar {
      0%   { transform: scale(0.7); }
      40%  { transform: scale(1.08); }
      60%  { transform: scale(1); }
      100% { transform: scale(1); }
    }
    @keyframes sc-note-write {
      0%   { clip-path: inset(0 100% 0 0); opacity: 0.25; }
      100% { clip-path: inset(0 0 0 0); opacity: 1; }
    }
    @keyframes sc-tagline {
      0%   { opacity: 0; transform: translateY(22px); }
      100% { opacity: 1; transform: translateY(0); }
    }

    /* Reduced motion: no pin, no scrub — the clean static stacked
       layout defined at the top of this block is exactly what we want,
       so we neutralise the @supports enhancements. */
    @media (prefers-reduced-motion: reduce) {
      .scrolly-track {
        min-height: 0;
        view-timeline-name: none;
      }
      .scrolly-stage {
        position: relative;
        height: auto;
      }
      .scrolly-beats {
        height: auto;
      }
      .scrolly-beat {
        position: relative;
        inset: auto;
        opacity: 1;
        animation: none;
        transform: none;
      }
      .scrolly-flycard,
      .scrolly-avatar,
      .scrolly-note,
      .scrolly-tagline {
        animation: none;
        opacity: 1;
        transform: none;
        clip-path: none;
      }
      /* In the static layout the flycard sits between card + avatar. */
      .scrolly-flycard { position: static; margin: 0; }
    }

    /* ─────────────────────────────────────────────────────────────────────
       Dark-mode overrides for homepage-specific surfaces. Global theme
       behaviors (toggle, hero aurora dim) live in motion.css; this block
       handles homepage-only elements that motion.css can't see.
       ───────────────────────────────────────────────────────────────────── */

    /* Cursor spotlight — already subtle, just hide it in dark mode
       so a bright mouse-following glow doesn't undo the dimming. */
    :root:not([data-theme="light"]) .hero-spotlight { display: none; }

    /* Mesh + grain decorative layers behind the page — heavily dim
       so the page reads as clean and dark, not chaotic. Grain's base
       opacity is 0.025 (very subtle); we drop it further. The mesh
       accent disc is at 0.92 base — fade the whole .mesh wrapper
       so it reads as a hint of atmosphere, not a focal element. */
    :root:not([data-theme="light"]) .mesh { opacity: 0.12; }
    :root:not([data-theme="light"]) .grain { opacity: 0.018; }

    /* Hero gradient text (the "Beta · Now on TestFlight" pill is fine,
       but the audio meter colors can be dimmed slightly) */
    :root:not([data-theme="light"]) .hero-meter-bar { opacity: 0.7; }

    /* Moment-picker tonearm glow + vinyl tick — they read fine in
       dark mode since they're amber on black, just dial back the
       glow halo so it doesn't punch out of the dimmed page. */
    :root:not([data-theme="light"]) .home-moment-tick {
      box-shadow: 0 0 5px rgba(255, 200, 59, 0.4);
    }
    :root:not([data-theme="light"]) .home-moment-needle-tip {
      box-shadow: 0 0 6px rgba(255, 200, 59, 0.45);
    }

    /* ─────────────────────────────────────────────────────────────────────
       LIGHT MODE — homepage specifics.

       The token flip (footer.css) turns the body + all var(--bg/--fg)
       surfaces cream/ink. These rules handle the homepage's bespoke,
       hardcoded-dark layers so the hero reads as a genuine light surface
       instead of the default indigo mesh: the mesh becomes the cream page
       ground, the bright accent disc stays (echoing the share cards), the
       dark WebGL living-gradient fades out, and the cursor spotlight +
       grain are tuned for a pale ground. Saturated palette sections
       (postcard, android band, tour stops) intentionally stay vivid.
       ───────────────────────────────────────────────────────────────────── */
    :root[data-theme="light"] .mesh { background: var(--bg); opacity: 1; }
    :root[data-theme="light"] .mesh::before { opacity: 0.85; }  /* pink accent disc pops on cream */
    :root[data-theme="light"] .mesh::after  { opacity: 0.34; }  /* warm secondary glow */
    :root[data-theme="light"] .hero-shader  { opacity: 0 !important; } /* dark gradient off in light */
    :root[data-theme="light"] .hero-aurora  { opacity: 0.9; filter: saturate(1); }
    :root[data-theme="light"] .grain        { opacity: 0.05; } /* grain reads a touch more on cream */
    :root[data-theme="light"] .hero-spotlight { display: block; } /* re-enable the warm follow-glow */
    /* Nav pill: give it a translucent cream so it doesn't float as a dark chip */
    :root[data-theme="light"] nav .nav-inner,
    :root[data-theme="light"] .w-nav {
      background: rgba(255, 247, 232, 0.72);
      border-color: rgba(26, 23, 69, 0.10);
    }

    /* ── "Sent all over" globe showpiece ────────────────────────────
       Dark backdrop, centered rhythm (eyebrow + Antonio title + lede),
       with the Canvas 2D globe as the centerpiece. Everything but the
       canvas is real HTML so the section reads with JS off / on error. */
    .globe-sec {
      padding: 96px 0 96px;
      max-width: 1280px;
      margin: 0 auto;
      text-align: center;
      position: relative;
      overflow: hidden;
    }
    .globe-inner {
      max-width: 640px;
      margin: 0 auto;
      padding: 0 32px;
    }
    .globe-sec .section-eyebrow { justify-content: center; }
    .globe-sec .section-title {
      max-width: 18ch;
      margin-left: auto;
      margin-right: auto;
      margin-bottom: 20px;
    }
    .globe-lede {
      color: var(--fg-secondary);
      font-size: 17px;
      line-height: 1.5;
      max-width: 46ch;
      margin: 0 auto;
    }
    .globe-count {
      margin: 20px auto 0;
      font-size: 15px;
      letter-spacing: 0.01em;
      color: var(--fg-secondary);
    }
    .globe-count strong {
      font-family: "Antonio", "Arial Narrow", "Roboto Condensed", -apple-system, sans-serif;
      font-weight: 700;
      font-size: 22px;
      letter-spacing: -0.01em;
      color: #fff;
      margin-right: 4px;
    }
    /* Square stage; width capped so the globe never causes horizontal
       overflow on small screens. */
    .globe-stage {
      position: relative;
      width: 100%;
      max-width: min(560px, 90vw);
      aspect-ratio: 1 / 1;
      margin: 8px auto 0;
    }
    /* CSS glow as a backstop even if the canvas is removed on error. */
    .globe-stage::before {
      content: "";
      position: absolute;
      inset: 8%;
      border-radius: 50%;
      background: radial-gradient(circle at 50% 46%,
        rgba(135, 102, 255, 0.22) 0%,
        rgba(31, 184, 255, 0.10) 42%,
        transparent 70%);
      filter: blur(6px);
      pointer-events: none;
      z-index: 0;
    }
    .globe-stage canvas {
      position: relative;
      z-index: 1;
      display: block;
      width: 100%;
      height: 100%;
    }
    @media (max-width: 600px) {
      .globe-sec { padding: 64px 0 64px; }
      .globe-inner { padding: 0 24px; }
    }
  

/* Closing CTA card + mobile beta bar are always dark surfaces, in both
   themes — pin their text colors instead of using theme tokens (which
   go dark in light mode and vanish on the navy/black surface). */
.cta-card .cta-or {
  color: rgba(255, 255, 255, 0.62);
  font-size: 14px; letter-spacing: 0; text-transform: none; text-align: center;
  max-width: 520px;
}
.cta-card .cta-or::before, .cta-card .cta-or::after { background: rgba(255, 255, 255, 0.14); min-width: 24px; }
.cta-card .email-capture input { color: #fff; }
.cta-card .email-capture input::placeholder { color: rgba(255, 255, 255, 0.45); }
.sticky-cta .sticky-cta-text { color: rgba(255, 255, 255, 0.7); }
.sticky-cta .sticky-cta-text b { color: #fff; }
@media (max-width: 640px) {
  .cta-card .cta-or::before, .cta-card .cta-or::after { display: none; }
}
.cta-card .email-capture button { background: #fff; color: #0A0A0F; }
.cta-card .pair-title { color: #fff; }
.cta-card .pair-sub { color: rgba(255, 255, 255, 0.72); }
.cta-card .pair-sub b { color: #fff; }
.cta-card .pair-preview, .cta-card .pair-msg { color: rgba(255, 255, 255, 0.6); }
