/* ===================================================================
   AdsNine — stylesheet (warm light edition)

   Sections, in order:
     1. Font
     2. Design tokens
     3. Reset + base
     4. Type scale
     5. Layout helpers
     6. Buttons
     7. Motion
     8. Mascots
     9. Header
    10. Hero — the canvas
    11. Marquee
    12. Problem
    13. The nine
    14. Support assets
    15. Setup proof
    16. Bonuses
    17. Price
    18. Guarantee
    19. FAQ
    20. Final CTA + footer
    21. Sticky mobile CTA
   =================================================================== */


/* 1. FONT ---------------------------------------------------------- */

@font-face {
  font-family: 'General Sans';
  src: url('assets/fonts/GeneralSans-Variable.woff2') format('woff2-variations');
  font-weight: 300 700;
  font-style: normal;
  font-display: swap;
}



/* 2. DESIGN TOKENS -------------------------------------------------
   Every colour comes from here. Change once, changes everywhere. */

:root {
  --canvas:    #FBF8F3;              /* warm off-white page */
  --canvas-2:  #F4EEE4;              /* alternating band */
  --surface:   #FFFFFF;              /* cards */
  --hairline:  rgba(26,23,20,.13);

  --ink:       #1A1714;              /* near-black, warm */
  --ink-dim:   rgba(26,23,20,.68);   /* body copy — 5.4:1 on canvas */
  --ink-faint: rgba(26,23,20,.44);   /* decorative only */

  --violet:    #A855F7;
  --magenta:   #FF3D9A;
  --orange:    #FF6B35;
  --brand-grad: linear-gradient(100deg, #A855F7 0%, #FF3D9A 52%, #FF6B35 100%);
  /* Same gradient at low alpha, for the headline highlight. */
  --brand-grad-soft: linear-gradient(100deg, rgba(168,85,247,.30) 0%, rgba(255,61,154,.30) 52%, rgba(255,107,53,.30) 100%);

  /* Canvas hero: the grid and the paper objects. --sel, the Figma blue,
     went with the cursor on 2026-08-05 — it was the last thing using
     it, as the selection frame it originally drew had gone before. */
  --grid-line:  rgba(26,23,20,.06);
  /* --pill-a, the yellow of the "9 platforms, not 1" tag, went with the
     canvas objects on 2026-08-05. --note-a and --note-b, two sticky-note
     colours, were already unused before that and are left alone here
     rather than swept up in an unrelated change. */
  --note-a:     #C8F0DC;             /* mint sticky note — unused */
  --note-b:     #FFE7B0;             /* cream sticky note — unused */

  --s1: 8px;   --s2: 12px;  --s3: 16px;  --s4: 24px;  --s5: 32px;
  --s6: 48px;  --s7: 64px;  --s8: 96px;  --s9: 128px;

  --section-pad: clamp(72px, 12vw, 160px);
  --content:     1120px;
  --prose:       640px;
  --radius:      24px;
  --ease:        cubic-bezier(.16, 1, .3, 1);
  --spring:      cubic-bezier(.34, 1.56, .64, 1);
}


/* 3. RESET + BASE -------------------------------------------------- */

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

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }

body {
  margin: 0;
  background: var(--canvas);
  color: var(--ink);
  font-family: 'General Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  font-size: 1rem;
  font-weight: 400;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
  position: relative;      /* the page wash below is absolute to this */
}

/* The page wash -----------------------------------------------------
   Brand colour used to stop dead after the second section: the hero had
   its mesh, the problem section had one too, and the remaining 4,650px
   — about 70% of the page — were flat cream with one beige band at the
   price. That was not a decision. The mesh had a third instance in the
   final CTA at the foot, and when that section was cut the page lost
   its closing bookend and nobody noticed.

   This is one continuous field rather than a fourth copy of the mesh.
   Three blobs repeated per section would tile: same colours, same
   corners, five times down the page. Six ellipses placed by percentage
   of the document instead, alternating side to side and cycling violet
   → magenta → orange, so the colour keeps moving and never repeats a
   position.

   It starts at 30%, which is where the problem section ends. Above that
   the hero and the problem run their own mesh at their own strength,
   and a second field underneath would just double them.

   Positioned, and first in the body, so every later positioned element
   — the sections all carry position:relative — paints over it without
   needing a z-index. It sits above the body's own cream background for
   the same reason: that is painted first, in the bottom layer. */
.page-wash {
  position: absolute;
  inset: 0;
  pointer-events: none;
  overflow: hidden;
  background:
    radial-gradient(46vw 480px at  8% 30%, rgba(168,85,247,.24), transparent 70%),
    radial-gradient(44vw 460px at 94% 43%, rgba(255, 61,154,.20), transparent 70%),
    radial-gradient(48vw 500px at  4% 56%, rgba(255,107, 53,.22), transparent 70%),
    radial-gradient(42vw 440px at 96% 68%, rgba(168, 85,247,.22), transparent 70%),
    radial-gradient(46vw 480px at  6% 80%, rgba(255, 61,154,.19), transparent 70%),
    radial-gradient(44vw 460px at 92% 92%, rgba(255,107, 53,.20), transparent 70%);
}

img, svg { max-width: 100%; height: auto; display: block; }
a { color: inherit; }

a:focus-visible, button:focus-visible, summary:focus-visible {
  outline: 2.5px solid var(--ink);
  outline-offset: 3px;
  border-radius: 6px;
}


/* 4. TYPE SCALE ---------------------------------------------------- */

h1, h2, h3 { margin: 0; font-weight: 500; }

.display {
  /* 64px desktop cap matches the reference calibration, and buys back
     the vertical room the hero demo needs. */
  font-size: clamp(2.125rem, 6.4vw, 4rem);
  line-height: 1.05;
  letter-spacing: -0.03em;
  text-wrap: balance;   /* evens the line lengths, avoids orphan words */
}

h2, .h2 { font-size: clamp(2rem, 5vw, 3.25rem); line-height: 1.10; letter-spacing: -0.02em; }
h3, .h3 { font-size: clamp(1.25rem, 3vw, 1.5rem); line-height: 1.25; letter-spacing: -0.01em; }

.body-lg { font-size: clamp(1.05rem, 2.2vw, 1.25rem); line-height: 1.55; color: var(--ink-dim); }

.eyebrow {
  color: var(--ink-dim);
  text-transform: uppercase;
  letter-spacing: 0.12em;
  font-size: 0.75rem;
  font-weight: 500;
}


p { margin: 0 0 var(--s4); }
p:last-child { margin-bottom: 0; }


/* 5. LAYOUT HELPERS ------------------------------------------------ */

.section { padding-block: var(--section-pad); padding-inline: var(--s4); position: relative; }
.wrap  { max-width: var(--content); margin-inline: auto; }
.prose { max-width: var(--prose);   margin-inline: auto; }

.section-head { margin-bottom: var(--s8); text-align: center; }
.section-head h2 { margin-bottom: var(--s4); }
.section-head .body-lg { max-width: 34ch; margin-inline: auto; }

.card {
  background: var(--surface);
  border: 1.5px solid var(--hairline);
  border-radius: var(--radius);
  padding: var(--s5);
  position: relative;
}


/* 6. BUTTONS -------------------------------------------------------
   Primary is a white card carrying the brand gradient as a ring, not as
   a fill. It was solid ink until 2026-08-05 — a black block on a warm
   cream page, the one element that did not belong to the same design
   system as everything around it.

   The old note here said gradient buttons were the cliché being avoided
   and that white on the brand gradient only reaches 3.1:1. Both still
   hold, which is why the gradient is on the border and not behind the
   text: the label stays ink on white at about 15:1, better than the ink
   button it replaces, and the brand colour reads at full strength
   because nothing has to stay legible on top of it.

   Prominence comes from the ring, a brand-tinted lift, and the logo
   mark, rather than from mass. That is a deliberate trade — see the
   note on .btn-ghost about keeping the two apart. */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 58px;
  padding: 0 var(--s6);
  border-radius: 999px;
  font-size: 1.0625rem;
  font-weight: 500;
  letter-spacing: -0.01em;
  text-decoration: none;
  cursor: pointer;
  position: relative;
  transition: transform .25s var(--spring), box-shadow .25s var(--ease);
}

/* Three background layers, outermost first: the brand gradient at low
   alpha, a flat white base, and the brand gradient at full strength —
   the first two clipped to the padding box, the last to the border box.
   The border is transparent, so the full-strength gradient shows through
   it and nowhere else: a 1.5px brand ring around a softly washed white
   card, matching the 1.5px hairline every other card here carries.

   The wash is what makes it work on the pricing card. Pure white was
   the first try and it vanished there — a white button on a white card
   with only a hairline of colour reads as an outline, not a purchase.
   At 12% the fill is barely a tint on the cream page and clearly a
   surface on white, and ink on it still measures about 13:1. */
.btn-primary {
  background:
    linear-gradient(100deg, rgba(168,85,247,.12) 0%, rgba(255,61,154,.12) 52%, rgba(255,107,53,.12) 100%) padding-box,
    linear-gradient(var(--surface), var(--surface)) padding-box,
    var(--brand-grad) border-box;
  border: 1.5px solid transparent;
  color: var(--ink);
  /* Two shadows: a tight neutral one to seat the card, and a wider
     magenta-tinted one so the lift reads as brand light rather than as
     grey drop shadow. */
  box-shadow: 0 1px 2px rgba(26,23,20,.05), 0 8px 24px rgba(255,61,154,.13);
}
/* The gradient again, blurred, as a glow behind the whole button on
   hover. .btn is position:relative with z-index auto, so it opens no
   stacking context and a negative-z-index child really does go behind
   the element's own background — unlike .tb-cmo, which had z-index:1
   and washed its own card for months. */
.btn-primary::before {
  content: '';
  position: absolute;
  inset: -3px;
  border-radius: inherit;
  background: var(--brand-grad);
  filter: blur(16px);
  opacity: 0;
  z-index: -1;
  transition: opacity .3s var(--ease);
}
.btn-primary:hover {
  transform: translateY(-3px);
  box-shadow: 0 2px 4px rgba(26,23,20,.06), 0 16px 36px rgba(255,61,154,.22);
}
.btn-primary:hover::before { opacity: .5; }

/* Ghost has to stay clearly the lesser of the two now that primary is
   also light: no fill at all against primary's white, and a neutral
   hairline against primary's gradient ring. */
.btn-ghost { background: transparent; color: var(--ink); border: 1.5px solid var(--hairline); }
.btn-ghost:hover { background: var(--canvas-2); transform: translateY(-2px); }

.btn-block { display: flex; width: 100%; }


/* 7. MOTION --------------------------------------------------------
   .js is set by an inline script in <head>. Without JS nothing is
   hidden, so the page degrades to fully readable. */

.js [data-reveal] {
  opacity: 0;
  transform: translateY(20px);
  transition: opacity .7s var(--ease), transform .7s var(--ease);
  transition-delay: calc(var(--i, 0) * 60ms);
}
.js [data-reveal].is-visible { opacity: 1; transform: none; }

.js .hero-rise { animation: rise .9s var(--ease) both; }
.js .hero-rise-1 { animation-delay: .08s; }
.js .hero-rise-2 { animation-delay: .16s; }
.js .hero-rise-3 { animation-delay: .24s; }
@keyframes rise { from { opacity: 0; transform: translateY(24px); } to { opacity: 1; transform: none; } }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
}


/* 8. MASCOTS -------------------------------------------------------
   Nine characters, one per platform. Flat accent fill with a dark
   keyline so each reads clearly whatever its platform colour. */

.mascot-stage { margin-bottom: var(--s4); }

.mascot { width: 108px; height: auto; overflow: visible; }

.m-body, .m-prop, .m-eye {
  stroke: var(--ink);
  stroke-width: 3.5;
  stroke-linejoin: round;
}
.m-body   { fill: var(--accent); }
.m-prop   { fill: #fff; }
.m-eye    { fill: #fff; }
.m-pupil  { fill: var(--ink); }
.m-dot    { fill: var(--ink); }
.m-tie    { fill: var(--ink); }
.m-spark  { fill: var(--accent); }
.m-shadow { fill: rgba(26,23,20,.10); }
.m-prop-tail { fill: #fff; stroke: var(--ink); stroke-width: 3.5; stroke-linejoin: round; }

/* Collar reads as a shirt, so it needs to sit light on a dark body. */
.m-shirt { fill: none; stroke: #fff; stroke-width: 4; stroke-linecap: round; stroke-linejoin: round; }

.m-mouth, .m-stroke {
  fill: none;
  stroke: var(--ink);
  stroke-width: 3.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* Idle float. Staggered per card so the cast never moves in lockstep. */
.m-float { animation: bob 4.2s ease-in-out infinite; }
@keyframes bob { 0%,100% { transform: translateY(0); } 50% { transform: translateY(-7px); } }

.platform:nth-child(2) .m-float { animation-delay: -.5s; animation-duration: 4.6s; }
.platform:nth-child(3) .m-float { animation-delay: -1.1s; animation-duration: 3.9s; }
.platform:nth-child(4) .m-float { animation-delay: -1.7s; animation-duration: 4.4s; }
.platform:nth-child(5) .m-float { animation-delay: -2.2s; animation-duration: 4.1s; }
.platform:nth-child(6) .m-float { animation-delay: -2.8s; animation-duration: 4.7s; }
.platform:nth-child(7) .m-float { animation-delay: -3.3s; animation-duration: 4.0s; }
.platform:nth-child(8) .m-float { animation-delay: -3.9s; animation-duration: 4.5s; }
.platform:nth-child(9) .m-float { animation-delay: -4.4s; animation-duration: 4.3s; }

/* Eyes glance around — cheap, and reads as alive. */
.m-pupil { animation: glance 7s ease-in-out infinite; }
@keyframes glance {
  0%, 38%   { transform: translateX(0); }
  46%, 66%  { transform: translateX(2.6px); }
  74%, 100% { transform: translateX(0); }
}

.m-antenna { animation: wiggle 3s ease-in-out infinite; transform-origin: 60px 40px; }
@keyframes wiggle { 0%,100% { transform: rotate(-7deg); } 50% { transform: rotate(7deg); } }

.m-spark { animation: twinkle 2.6s ease-in-out infinite; transform-origin: 60px 22px; }
@keyframes twinkle { 0%,100% { transform: scale(1) rotate(0); } 50% { transform: scale(1.14) rotate(18deg); } }


/* 9. HEADER -------------------------------------------------------- */

/* Sticky, translucent, and always readable over whatever scrolls
   under it. The hairline keeps it from dissolving into the hero. */
.site-header {
  position: sticky; top: 0; z-index: 20;
  display: flex; align-items: center; gap: var(--s4);
  padding: 10px var(--s4);
  background: rgba(251,248,243,.82);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border-bottom: 1.5px solid var(--hairline);
}

.site-nav { display: none; }
@media (min-width: 900px) {
  .site-nav {
    display: flex; align-items: center; gap: var(--s4);
    margin-inline: auto;
  }
  .site-nav a {
    font-size: .875rem; font-weight: 500;
    color: var(--ink-dim);
    text-decoration: none;
    transition: color .2s var(--ease);
  }
  .site-nav a:hover { color: var(--ink); }
}

/* The header's copy of the offer. The phone already carries it in the
   bottom bar, so this one only exists where there is room. */
.site-buy { display: none; }
@media (min-width: 900px) {
  .site-buy {
    display: inline-flex;
    min-height: 40px;
    padding: 8px 18px;
    font-size: .875rem;
    margin-left: auto;
  }
  .site-nav { margin-inline: auto; }
}

/* The phone menu: a hamburger that is really a details element. */
.site-menu { margin-left: auto; position: relative; }
@media (min-width: 900px) { .site-menu { display: none; } }
.site-menu summary {
  list-style: none;
  display: grid; place-items: center;
  width: 44px; height: 44px;
  border-radius: 12px;
  border: 1.5px solid var(--hairline);
  background: var(--surface);
  cursor: pointer;
}
.site-menu summary::-webkit-details-marker { display: none; }
.site-menu summary i,
.site-menu summary i::before,
.site-menu summary i::after {
  content: "";
  display: block;
  width: 18px; height: 2px;
  border-radius: 2px;
  background: var(--ink);
}
.site-menu summary i { position: relative; }
.site-menu summary i::before { position: absolute; top: -6px; }
.site-menu summary i::after  { position: absolute; top: 6px; }

.menu-panel {
  position: fixed;
  left: 0; right: 0; top: 65px;
  display: grid;
  padding: var(--s2) var(--s4) var(--s4);
  background: rgba(251,248,243,.97);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border-bottom: 1.5px solid var(--hairline);
}
.menu-panel a {
  padding: 14px 4px;
  font-size: 1rem; font-weight: 500;
  color: var(--ink);
  text-decoration: none;
  border-bottom: 1.5px solid var(--hairline);
}
.menu-panel a:last-of-type { border-bottom: 0; }
.menu-panel .menu-buy {
  margin-top: var(--s2);
  text-align: center;
  background: var(--ink);
  color: var(--canvas);
  border-radius: 999px;
  border-bottom: 0;
}

/* Anchored sections stop under the sticky header, not behind it. */
.section[id], #hero { scroll-margin-top: 64px; }

.wordmark {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  gap: 10px;
  font-weight: 500;
  font-size: 1.1875rem;
  letter-spacing: -0.02em;
  text-decoration: none;
}
.wordmark img { width: 30px; height: 30px; }


/* 10. HERO — THE CANVAS --------------------------------------------
   The hero is staged as a design canvas: ruler, 100px grid, objects
   pinned around the edges, and a cursor that flies in diagonally and
   selects the headline. All CSS — no library, no images.

   Reading order for anyone editing copy:
     .script-note   the handwritten line
     .canvas-word   the giant headline
     .canvas-status the availability line under it
   ------------------------------------------------------------------ */

.hero {
  /* The header sits in flow now, so a full-viewport hero has to give
     its height back or the buy button slips under the fold. The top
     padding was sized for a header that overlaid the canvas; with the
     header solid it only made the dead band above the eyebrow. */
  /* On a phone the hero is exactly as tall as its content. Forcing a
     full viewport just moved the dead band around: centred it sat above
     the eyebrow, top-aligned it pooled under the button. The full-screen
     stage only exists from 900px up, where there is content enough to
     fill it. */
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding-block: var(--s6) var(--s6);
  padding-inline: var(--s4);
  position: relative;
  overflow: hidden;
  text-align: center;
}
@media (min-width: 900px) {
  .hero {
    min-height: calc(100svh - 65px);
    align-items: center;
    padding-top: clamp(64px, 9vw, 120px);
    padding-bottom: var(--s7);
  }
}



/* Canvas background: drifting colour, then the faint grid on top ---- */

/* .mesh is the same three blobs without the grid — reused by the final
   CTA section at the foot of the page. */
.canvas-bg, .mesh { position: absolute; inset: 0; pointer-events: none; overflow: hidden; z-index: 0; }
.canvas-bg > span, .mesh > span {
  position: absolute;
  display: block;
  border-radius: 50%;
  filter: blur(70px);
  will-change: transform;
}
.mesh-a {
  width: 46vw; height: 46vw; min-width: 320px; min-height: 320px;
  top: -12%; left: -8%;
  background: var(--violet); opacity: .18;
  animation: float-a 22s ease-in-out infinite alternate;
}
.mesh-b {
  width: 42vw; height: 42vw; min-width: 300px; min-height: 300px;
  bottom: -18%; right: -6%;
  background: var(--orange); opacity: .20;
  animation: float-b 26s ease-in-out infinite alternate;
}
.mesh-c {
  width: 34vw; height: 34vw; min-width: 240px; min-height: 240px;
  top: 34%; left: 52%;
  background: var(--magenta); opacity: .12;
  animation: float-c 30s ease-in-out infinite alternate;
}
@keyframes float-a { to { transform: translate3d(70px, 50px, 0) scale(1.12); } }
@keyframes float-b { to { transform: translate3d(-60px, -45px, 0) scale(1.08); } }
@keyframes float-c { to { transform: translate3d(-80px, 40px, 0) scale(1.16); } }

/* The grid, masked so it dissolves into the canvas at the edges. */
.canvas-bg::after {
  content: '';
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(to right,  var(--grid-line) 1px, transparent 1px),
    linear-gradient(to bottom, var(--grid-line) 1px, transparent 1px);
  background-size: 100px 100px;
  -webkit-mask-image: radial-gradient(118% 88% at 50% 42%, #000 34%, transparent 100%);
          mask-image: radial-gradient(118% 88% at 50% 42%, #000 34%, transparent 100%);
}


/* Objects pinned to the canvas -------------------------------------
   All four went on 2026-08-05, with the @keyframes drift that floated
   them: .canvas-objects, the two .tagpill tags, and the two circular
   .thumb stickers. They only ever appeared from 1100px up, so the
   phone never had them and the desktop had four things competing with
   the headline for the same glance. The canvas keeps its mesh and its
   grid, which are backdrop rather than objects. */

/* The sub-line inside the front half of a tilted logo orbit. The nine
   marks are injected and driven per-frame by main.js §5; the rear arc
   fades out, so only the half in front of the text reads. Without JS
   none of the orbit exists and the block is just the sub-line. */
.hero-orbit {
  position: relative;
  height: clamp(230px, 26vw, 250px);
  /* Pulled up into the empty band the hidden rear arc leaves, so the
     sub-line sits close under the headline. */
  margin: calc(var(--s2) * -1) 0 0;
}
html:not(.js) .hero-orbit { height: auto; margin-top: var(--s4); }
/* Short phones: the orbit is the one ornament with height to spare.
   Lives after the base rule, or the base rule wins the cascade. */
@media (max-height: 700px) {
  .hero-orbit { height: 190px; }
}

/* The ellipse centre sits at 30% height: the invisible rear arc gets
   the small top share, the visible front arc the room below the text. */
.orbit-copy { margin: 0 auto; }
.js .orbit-copy {
  position: absolute;
  left: 50%; top: 30%;
  transform: translate(-50%, -50%);
  width: 100%;
  z-index: 6;
}
.orbit-ring {
  position: absolute;
  left: 50%; top: 50%;
  border: 1px solid rgba(26,23,20,.14);
  border-radius: 50%;
  /* Only the front (lower) arc of the path shows, like the logos. */
  -webkit-mask-image: linear-gradient(to bottom, transparent 30%, #000 60%);
          mask-image: linear-gradient(to bottom, transparent 30%, #000 60%);
}
.orbit-glow {
  position: absolute;
  left: 50%; top: 50%;
  width: min(150%, 560px);
  aspect-ratio: 1.6;
  transform: translate(-50%, -50%);
  opacity: 0;
}
.orbit-logo {
  position: absolute;
  left: 50%; top: 50%;
  will-change: transform, opacity, filter;
}
.orbit-logo svg {
  display: block;
  width: var(--logo, 40px);
  height: var(--logo, 40px);
  fill: var(--brand, var(--ink));
}


/* The headline, as a selected object ------------------------------- */

.hero-inner { position: relative; z-index: 2; width: 100%; min-width: 0; max-width: var(--content); margin-inline: auto; }

.canvas-h1 { margin: 0; font-weight: 500; }

.selection { position: relative; display: inline-block; }

.canvas-word {
  display: block;
  font-size: clamp(2rem, 8.5vw, 6.25rem);
  font-weight: 600;
  line-height: 1.02;
  letter-spacing: .005em;
  text-transform: uppercase;
}
/* One line per span, so the break always lands between the two phrases
   instead of wherever the viewport happens to put it. */
.canvas-word > span { display: block; white-space: nowrap; }

/* A blue Figma cursor labelled "you" used to fly in from off-canvas and
   park at the headline's lower-left. It went on 2026-08-05, with its
   .fly keyframes, its mobile and reduced-motion suppressions, and the
   --sel token that was by then feeding nothing else. The hero had
   already lost the ruler, the clock and the selection frame it belonged
   to; a lone cursor was the last piece of a design-tool costume the
   page is not selling. */

/* Availability line, styled like a status row rather than an eyebrow. */
/* Sits above the headline as the eyebrow. The dot is inline rather
   than a flex child: when the line wraps on a narrow screen a flex dot
   strands itself on its own row. */
.canvas-status {
  display: inline-block;
  margin: 0 0 var(--s4);
  font-size: .8125rem;
  font-weight: 500;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--ink-dim);
}
.canvas-status i {
  display: inline-block;
  width: 9px; height: 9px;
  margin-right: 9px;
  vertical-align: 1px;
  border-radius: 50%;
  background: var(--brand-grad);
}

.hero .body-lg { max-width: 46ch; margin: var(--s4) auto var(--s6); }


/* Hero CTA ---------------------------------------------------------- */

.hero-cta { display: flex; flex-direction: column; align-items: center; gap: var(--s3); }
.hero-note { color: var(--ink-dim); max-width: 44ch; font-size: .9375rem; }

/* Squared-off variant, so the button reads as a canvas object rather
   than a generic pill. */
.btn-canvas { border-radius: 16px; padding: 0 var(--s5) 0 12px; gap: var(--s2); }

/* The logo itself — assets/logo.svg, the same file the header loads, at
   the header's proportions. It used to be a .btn-spark: a rounded square
   filled with the linear brand gradient and an eight-pointed white star
   punched out by clip-path. Nothing about that was the logo, which is a
   circle carrying a five-stop radial mesh with a soft four-pointed
   sparkle. Drawing it in CSS would mean maintaining a second copy that
   drifts; the file is 1.2KB and the browser has it cached from the
   header two hundred pixels up the page. */
.btn-mark { width: 34px; height: 34px; flex: none; }


/* Snapchat's true yellow (#FFFC00) measures 1.05:1 on this canvas — it
   would vanish. A dark keyline keeps the real brand colour usable. */
.mark-keyline svg {
  stroke: var(--ink);
  stroke-width: 1.1;
  stroke-linejoin: round;
  paint-order: stroke fill;
}

/* The big mascot holding a finished ad — .mascot-hero and its .mh-*
   parts — went with the canvas objects on 2026-08-05. It was drawn
   inside .thumb-a and nowhere else by then; the comment here claimed it
   was also used "full size in the nine", which stopped being true when
   that section was rebuilt. @keyframes tilt went with it. glance,
   twinkle and bob stay: the .m-* mascots in §8 share them. */


/* Product demo panel ------------------------------------------------
   Lives in "How it works" — it shows step 3 actually happening. */

.hero-demo { margin-top: var(--s6); }

.demo-frame {
  max-width: 560px;
  margin-inline: auto;
  text-align: left;
  background: var(--surface);
  border: 1.5px solid var(--hairline);
  border-radius: 18px;
  box-shadow: 0 24px 60px rgba(26,23,20,.14);
  overflow: hidden;
}

.demo-bar {
  display: flex; align-items: center; gap: 6px;
  padding: 11px var(--s3);
  border-bottom: 1.5px solid var(--hairline);
  background: var(--canvas-2);
}
.demo-bar span { width: 10px; height: 10px; border-radius: 50%; background: var(--hairline); flex: none; }
/* Names the window and the skill in one line, in the chrome itself.
   --ink-dim rather than --ink-faint: this is explanatory, not decoration. */
.demo-bar-label {
  margin: 0 0 0 auto;
  font-size: .75rem; font-weight: 500; letter-spacing: .02em;
  color: var(--ink-dim);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.demo-body { padding: var(--s4); display: grid; gap: var(--s3); }

.demo-msg { margin: 0; font-size: .875rem; line-height: 1.5; }
.demo-user {
  justify-self: end;
  max-width: 84%;
  background: var(--canvas-2);
  border-radius: 14px 14px 4px 14px;
  padding: 10px 14px;
  color: var(--ink);
}
.demo-reply { color: var(--ink-dim); display: grid; gap: var(--s2); }
.demo-reply p { margin: 0; }
.demo-reply b { color: var(--ink); font-weight: 500; }

.demo-badge {
  display: inline-flex; align-items: center; gap: 7px;
  font-size: .6875rem; font-weight: 500; letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--ink-faint);
}
.demo-badge i { width: 9px; height: 9px; border-radius: 50%; background: var(--accent); border: 1.5px solid var(--ink); }

/* Typewriter caret. main.js moves this along as it types; the finished
   text is already in the HTML, so no-JS shows the completed panel. */
.demo-caret {
  display: inline-block;
  width: 2px; height: 1em;
  margin-left: 2px;
  vertical-align: -2px;
  background: var(--ink);
  animation: blink 1.1s steps(2, start) infinite;
}
@keyframes blink { 50% { opacity: 0; } }


/* Replaces band. The strip between the hero and the board slides the
   going agency rate for each platform past the reader, then the price
   of the whole set. Same form as the old platform marquee, but the
   content argues instead of repeating the orbit. Rates come from the
   product spec's market research; change them there first. */
.marquee {
  border-block: 1.5px solid var(--hairline);
  background: var(--surface);
  overflow: hidden;
  padding-block: var(--s3);
}
.marquee-track {
  display: flex;
  align-items: center;
  gap: var(--s5);
  width: max-content;
  /* Slower than the old name strip: these items are meant to be read,
     not recognised. */
  animation: slide 60s linear infinite;
}
.marquee-track span {
  font-size: .9375rem;
  font-weight: 500;
  letter-spacing: -0.01em;
  color: var(--ink-dim);
  white-space: nowrap;
}
.marquee-track span i {
  font-style: normal;
  font-weight: 400;
  color: var(--ink-faint);
  margin-left: 6px;
}
.marquee-track b { width: 6px; height: 6px; border-radius: 50%; background: var(--ink-faint); flex: none; }
/* The one item set in ink on ink's own terms: the punchline chip. */
.mq-punch {
  padding: 7px 14px;
  border-radius: 999px;
  background: var(--ink);
  color: var(--canvas) !important;
}
@keyframes slide { to { transform: translateX(-50%); } }
@media (prefers-reduced-motion: reduce) { .marquee-track { animation: none; } }

/* For content that must reach a screen reader but not the screen. */
.visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  clip-path: inset(50%);
  overflow: hidden;
  white-space: nowrap;
}

/* The hero's reduced-motion block lived here. Its one rule stopped the
   canvas objects drifting, and it went with them. */


/* 11b. HOW IT WORKS ------------------------------------------------
   Three steps, each copy + illustration, alternating sides on desktop.
   Step 3's illustration is the real product output. */

.how .section-head { margin-bottom: var(--s7); }
.how .eyebrow { margin-bottom: var(--s3); }
.how .section-head .body-lg { max-width: 40ch; }

/* What is an agent: one opened up ----------------------------------
   A specimen chip, a stem, and three columns of real file names read
   from the shipping plugin. The rows borrow the page's tile language;
   the foot line borrows the graph legend's voice. */

.anatomy .section-head { margin-bottom: var(--s6); }

.agent-anatomy {
  max-width: 940px;
  margin-inline: auto;
  display: grid;
  justify-items: center;
}

.aa-chip {
  display: flex; align-items: center; gap: 10px;
  padding: 12px 18px;
  background: var(--surface);
  border: 1.5px solid var(--hairline);
  border-radius: 14px;
  box-shadow: 0 6px 16px rgba(26,23,20,.07);
}
.aa-logo { width: 22px; height: 22px; fill: #0866FF; }
.aa-chip b { font-size: .9375rem; font-weight: 500; }
.aa-chip i {
  font-style: normal;
  font-size: .75rem;
  color: var(--ink-faint);
  padding-left: 10px;
  border-left: 1.5px solid var(--hairline);
}

.aa-stem { width: 1.5px; height: 26px; background: var(--hairline); }

.aa-grid {
  width: 100%;
  display: grid;
  gap: var(--s3);
}
@media (min-width: 720px) { .aa-grid { grid-template-columns: repeat(3, 1fr); } }

.aa-tile {
  background: var(--surface);
  border: 1.5px solid var(--hairline);
  border-radius: 16px;
  padding: var(--s4);
  text-align: left;
}
.aa-tile h3 { margin: var(--s3) 0 6px; font-size: 1rem; font-weight: 400; color: var(--ink-dim); }
.aa-tile h3 b { font-weight: 600; color: var(--ink); }
.aa-tile > p { margin: 0; font-size: .8125rem; line-height: 1.5; color: var(--ink-dim); }

/* Every tile leads with a picture of the same height, so the row scans
   as three exhibits rather than three paragraphs. */
.aa-viz { position: relative; height: 150px; }

/* Skills: a fanned stack of playbooks. */
.aa-viz-skills span {
  position: absolute;
  left: 50%; top: 50%;
  width: min(200px, 84%);
  padding: 12px 14px;
  background: var(--canvas);
  border: 1.5px solid var(--hairline);
  border-radius: 10px;
  font-size: .75rem;
  color: var(--ink-dim);
  transform: translate(-50%, -50%)
             translateY(calc(var(--n) * -12px))
             rotate(calc(var(--n) * 3deg - 3deg));
  box-shadow: 0 6px 16px rgba(26,23,20,.06);
}
.aa-viz-skills span[style*="--n:0"] { color: var(--ink); font-weight: 500; }

/* Commands: a strip of terminal, ink on ink's own terms. */
.aa-viz-cmd {
  display: grid;
  align-content: center;
  gap: 8px;
  padding: 0 var(--s4);
  background: var(--ink);
  border-radius: 12px;
  overflow: hidden;
}
.aa-viz-cmd span {
  font-size: .78125rem;
  font-weight: 500;
  letter-spacing: .01em;
  color: rgba(251,248,243,.55);
  white-space: nowrap;
}
.aa-viz-cmd span:last-child { color: var(--canvas); }
.aa-viz-cmd i {
  display: inline-block;
  width: 7px; height: 13px;
  margin-left: 5px;
  vertical-align: -2px;
  background: var(--canvas);
  animation: aa-caret 1.1s steps(1) infinite;
}
@keyframes aa-caret { 50% { opacity: 0; } }
@media (prefers-reduced-motion: reduce) { .aa-viz-cmd i { animation: none; } }

/* Memory: the four files inside one dashed ring, with the point of the
   ring written on it. */
.aa-viz-mem {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
  align-content: center;
  padding: var(--s4) var(--s3) var(--s4);
  border: 2px dashed var(--hairline);
  border-radius: 14px;
}
.aa-viz-mem span {
  padding: 8px 10px;
  background: var(--canvas);
  border: 1.5px solid var(--hairline);
  border-radius: 9px;
  font-size: .71875rem;
  color: var(--ink);
  text-align: center;
  white-space: nowrap;
}
.aa-viz-mem b {
  position: absolute;
  top: -9px; left: 50%;
  translate: -50% 0;
  padding: 2px 10px;
  background: var(--surface);
  font-size: .625rem; font-weight: 500;
  letter-spacing: .1em; text-transform: uppercase;
  color: var(--ink-faint);
}

/* The chat's closing lines: the draft gets a rule above it, the next
   step reads as an aside. */
.demo-plan { border-top: 1.5px solid var(--hairline); padding-top: 10px; }
.demo-next span { font-size: .78125rem; color: var(--ink-faint); }

.aa-foot {
  margin: var(--s5) 0 0;
  font-size: .6875rem; font-weight: 500;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--ink-faint);
  text-align: center;
}

/* How it works: one window, three acts -----------------------------
   The rail on the left is the three steps; the window on the right
   plays them. Acts stack in one grid cell, so the stage is always as
   tall as its tallest act and nothing jumps when they swap. Every
   is-staged rule below only exists once main.js has declared it will
   actually run the show; without that class (no JS, reduced motion)
   the finished chat shows and the rail is a plain list. */

.hiw2 { display: grid; gap: var(--s6); }
@media (min-width: 860px) {
  .hiw2 { grid-template-columns: .9fr 1.1fr; gap: var(--s7); align-items: center; }
}

.hiw-rail {
  list-style: none; margin: 0; padding: 0;
  display: grid; gap: var(--s5);
}
.hiw-item h3 { margin: var(--s2) 0 var(--s2); }
.hiw-item p { margin: 0; max-width: 42ch; color: var(--ink-dim); }
.hiw-n {
  display: inline-block;
  font-size: .75rem; font-weight: 500;
  letter-spacing: .12em; text-transform: uppercase;
  color: var(--ink-faint);
}
/* The lit step. Dimming the others rather than decorating the active
   one keeps the rail quiet; the window is the show. */
.is-staged .hiw-item { opacity: .38; transition: opacity .35s var(--ease); }
.is-staged .hiw-item.is-active,
.is-staged .hiw-item.is-done { opacity: 1; }
.is-staged .hiw-item.is-done { opacity: .75; }

.hiw-window { max-width: 560px; width: 100%; margin-inline: auto; }

.hiw-acts { display: grid; }
.hiw-act {
  grid-area: 1 / 1;
  min-width: 0;
}
/* Only a staged show hides acts; the default page is the finished chat. */
.is-staged .hiw-act { opacity: 0; visibility: hidden; transition: opacity .3s var(--ease); }
.is-staged .hiw-act.is-on { opacity: 1; visibility: visible; }
html:not(.js) .hiw-act-dl, html:not(.js) .hiw-act-drop { display: none; }
.hiw-window:not(.is-staged) .hiw-act-dl,
.hiw-window:not(.is-staged) .hiw-act-drop { display: none; }

/* Act 1, the download card. Same card as before, now living inside
   the window instead of floating on the canvas. */
.hiw-act-dl { display: grid; align-content: center; padding: var(--s5) var(--s4); }
.hb-card {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--s4);
  align-items: center;
  width: 100%; max-width: 380px;
  margin-inline: auto;
  padding: var(--s4);
  background: var(--canvas);
  border: 1.5px solid var(--hairline);
  border-radius: 16px;
}
.hb-folder {
  position: relative;
  display: grid; place-items: center;
  width: 56px; height: 56px;
  border-radius: 16px;
  background: var(--surface);
  border: 1.5px solid var(--hairline);
  color: var(--ink);
}
.hb-folder svg { width: 28px; height: 28px; }
.hb-folder b {
  position: absolute; right: -7px; bottom: -7px;
  min-width: 22px; height: 22px;
  display: grid; place-items: center;
  padding: 0 5px;
  border-radius: 999px;
  background: var(--ink);
  color: var(--canvas);
  font-size: .6875rem; font-weight: 600;
  font-variant-numeric: tabular-nums;
}
.hb-meta { min-width: 0; }
.hb-name { margin: 0; font-size: 1rem; font-weight: 500; }
.hb-sub  { margin: 3px 0 0; font-size: .78125rem; color: var(--ink-faint); }
.hb-bar {
  grid-column: 1 / -1;
  height: 7px;
  border-radius: 999px;
  background: rgba(26,23,20,.08);
  overflow: hidden;
}
.hb-bar i {
  display: block;
  width: 100%; height: 100%;
  border-radius: inherit;
  background: var(--brand-grad);
}
/* Fills when the show starts, not when the page loads: is-on arrives
   at staging time, is-going only once the stage has scrolled into
   view, and the bar waits for the second one. The state line waits a
   beat longer, so "Downloaded" lands after the bar arrives. */
.is-staged .hb-bar i { width: 0; }
.is-staged.is-going .hiw-act-dl.is-on .hb-bar i {
  width: 100%;
  transition: width 1.1s var(--ease) .15s;
}
.is-staged .hb-state { opacity: 0; }
.is-staged.is-going .hb-state { opacity: 1; transition: opacity .3s var(--ease) 1.3s; }
.hb-state {
  grid-column: 1 / -1;
  margin: -2px 0 0;
  font-size: .78125rem;
  color: var(--ink-faint);
}

/* Act 2, the drop. */
.hiw-act-drop { display: grid; }
.hiw-dropzone {
  position: relative;
  margin: var(--s4);
  min-height: 220px;
  display: grid; place-items: center;
  border: 2px dashed var(--hairline);
  border-radius: 14px;
  background: var(--canvas);
}
.hiw-dropzone p { margin: 0; font-size: .8125rem; color: var(--ink-faint); }
.hiw-chip {
  position: absolute;
  top: 50%; left: 50%;
  display: inline-flex; align-items: center; gap: 8px;
  padding: 9px 14px;
  background: var(--surface);
  border: 1.5px solid var(--hairline);
  border-radius: 10px;
  font-size: .8125rem; font-weight: 500;
  box-shadow: 0 10px 24px rgba(26,23,20,.14);
  transform: translate(-50%, -50%);
}
.hiw-chip svg { width: 16px; height: 16px; fill: #0866FF; }
/* Falls once when the act opens, and stays where it lands. */
.is-staged .hiw-act-drop.is-on .hiw-chip {
  animation: hiw-drop 1.5s var(--ease) both;
}
@keyframes hiw-drop {
  0%   { transform: translate(-50%, -210%) rotate(-6deg); opacity: 0; }
  55%  { transform: translate(-50%, -50%)  rotate(0deg);  opacity: 1; }
  66%  { transform: translate(-50%, -42%); }
  100% { transform: translate(-50%, -50%); opacity: 1; }
}


/* 12. PROBLEM ------------------------------------------------------
   Two parts: one frame that plays the buyer's week running out and
   then resolves into the media mix it produces, then the cost in
   numbers. The graph is drawn by main.js §6. */

.problem { position: relative; text-align: center; }
.problem .wrap { position: relative; z-index: 1; }
.problem .section-head { margin-bottom: var(--s6); }
/* Bridges the promise in the H2 to the week shown under it. */
.problem-lead { max-width: 32ch; margin: var(--s4) auto 0; color: var(--ink-dim); }
.problem .eyebrow { margin-bottom: var(--s3); }

/* The hero's mesh at the hero's own strength — same three blobs, same
   violet / orange / magenta, same per-blob opacities (.18 / .20 / .12).
   It ran at a flat .11 with a wider blur until 2026-08-05, which read as
   a washed-out copy of the hero rather than the same canvas continuing.

   Clipped to the section: at full strength the blobs are placed to hang
   off the edges (top: -12%, bottom: -18%) and, unclipped, would carry
   that colour into the sections either side. The hero does the same
   thing for the same reason.

   Clipping alone left a seam. The hero can cut its blobs off at the top
   because the page ends there; this section has the platform marquee
   directly above it, so a blob cut at the boundary put full-strength
   violet hard against a white strip — a ruled line across the page. The
   mask fades the mesh out over the first and last tenth of the section,
   so the colour arrives and leaves instead of starting. It masks the
   mesh, not the section, or it would take the cards with it. */
.problem { overflow: hidden; }
.problem > .mesh {
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 11%, #000 89%, transparent 100%);
          mask-image: linear-gradient(to bottom, transparent 0, #000 11%, #000 89%, transparent 100%);
}

/* The team. One free-standing graph — there is no window around it and
   nothing above it: an earlier version played a week filling up first,
   inside a demo-frame panel, and that whole act was cut. */
.pain-visual { margin-top: var(--s6); }
.pain-stage { display: block; }
.team-graph { max-width: 900px; }


/* The board. Laid out as a plain column; the connectors are drawn by
   main.js §6 from whatever the cards actually measure, so this stays
   correct at any width without the CSS and the geometry having to
   agree. */
.team-graph {
  --wire: rgba(26,23,20,.20);
  position: relative;
  margin-inline: auto;
  display: flex; flex-direction: column; align-items: center;
  justify-content: center;
  gap: var(--s5);
  text-align: center;
}

/* Behind the cards on purpose: a connector running down a column passes
   under the card in the row between, so nothing crosses the content. */
.tb-wires {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  overflow: visible;
  pointer-events: none;
  z-index: 0;
}
/* One weight, one colour, right angles only — the connectors are
   structure, not decoration, and nine coloured diagonals fanning out of
   one node read as noise however pretty each one is. */
.tb-wire {
  fill: none;
  stroke: var(--wire);
  stroke-width: 1.25;
  stroke-linecap: butt;
  stroke-linejoin: round;
}

.tb-node, .tb-chip {
  position: relative; z-index: 1;
  background: var(--surface);
  border: 1.5px solid var(--hairline);
  border-radius: 12px;
}
.tb-node { padding: var(--s3) var(--s4); box-shadow: 0 6px 16px rgba(26,23,20,.07); }
.tb-node b { display: block; font-size: .9375rem; font-weight: 500; }
.tb-node i {
  font-style: normal; display: block;
  margin-top: 2px;
  font-size: .75rem; line-height: 1.35; color: var(--ink-faint);
}

/* The one node the eye should find first, marked with the least that
   will do it: a pink hairline and a pink title on the same white card
   the others get.

   It used to sit in a blurred wash of the hero gradient — inset -14px,
   blurred 18px, meant as a halo outside the card. It never was one.
   .tb-node is position:relative with z-index:1, so the card is its own
   stacking context, and inside one a negative-z-index child paints after
   the element's background and before its content: behind the text, in
   front of the white fill. The halo was a full-bleed gradient across the
   card the whole time. Removed on 2026-08-05 rather than fixed — with
   the connectors down to one hairline weight it was the loudest thing
   left in the section. */
.tb-cmo { border-color: rgba(255,61,154,.38); }
.tb-cmo b { color: var(--magenta); }
.tb-cmo i { max-width: 30ch; }

/* Three columns at every width. The nine used to open out into a single
   row above 700px, but the connectors are a hierarchy now — a trunk, one
   bus, three branches, each carrying its column down — and that only
   exists if there are three columns to carry. The row gap is the space
   those column connectors live in, so it is set well clear of the column
   gap rather than matching it. */
.tb-grid {
  list-style: none; margin: 0; padding: 0;
  width: 100%; max-width: 640px;
  display: grid; grid-template-columns: repeat(3, 1fr);
  column-gap: 10px; row-gap: 30px;
  /* On top of the board's own gap: the trunk, the bus and the branch
     drops all have to fit between the CMO and the first row. */
  margin-top: 14px;
}
@media (min-width: 700px) {
  .tb-grid { max-width: 760px; column-gap: 22px; row-gap: 38px; }
}
.tb-chip {
  display: flex; flex-direction: column; align-items: center; gap: 5px;
  padding: 16px 8px 14px;
  border-radius: 14px;
}

/* Each card is themed by its own platform, exactly as the hero orbit
   marks are — the colour is the platform's, not the page's. */
.tb-head { position: relative; display: block; }
.tb-logo { width: 26px; height: 26px; fill: var(--brand, var(--ink)); }
.tb-live {
  position: absolute; top: -1px; right: -7px;
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--brand, var(--magenta));
  box-shadow: 0 0 0 2px var(--surface);
}
.tb-chip b { font-size: .8125rem; font-weight: 500; line-height: 1.25; }
/* "agent" carries the whole point, so it is on every card — but dim, so
   nine repetitions read as a label and not as shouting. */
.tb-chip b em { display: block; font-style: normal; font-weight: 400; color: var(--ink-faint); }

/* The command line. Cycling through each agent's real commands is what
   proves the card is a specialist and not a single task — a Claude Code
   buyer reads a command set faster than any adjective. */
.tb-cmd {
  font-style: normal;
  font-size: .6875rem; line-height: 1.3;
  font-weight: 500; letter-spacing: .01em;
  color: var(--ink-dim);
  transition: opacity .22s var(--ease);
}
.tb-cmd.is-swapping { opacity: 0; }

.tb-foot {
  margin: 0;
  font-size: .6875rem; font-weight: 500;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

/* A dot used to ride each wire from the CMO down to its agent, and each
   wire drew itself on. Both are gone: the connectors are static now, and
   a travelling dot on an orthogonal path either cuts the corner or needs
   its own path-following animation to avoid doing so. The order of
   operations still reads — the CMO arrives before the nine do. */

/* The arrival: one brief lands, then the nine. */
.js .team-graph .tb-node,
.js .team-graph .tb-chip,
.js .team-graph .tb-foot { opacity: 0; transform: translateY(6px); }
.js .team-graph.is-on .tb-node,
.js .team-graph.is-on .tb-chip,
.js .team-graph.is-on .tb-foot {
  opacity: 1; transform: none;
  transition: opacity .35s var(--ease), transform .35s var(--ease);
}
.js .team-graph.is-on .tb-cmo  { transition-delay: .35s; }
.js .team-graph.is-on .tb-chip { transition-delay: calc(.75s + var(--i) * 55ms); }
.js .team-graph.is-on .tb-foot { transition-delay: 1.3s; }
.js .team-graph .tb-cmd, .js .team-graph .tb-live { opacity: 0; }
.js .team-graph.is-on .tb-cmd,
.js .team-graph.is-on .tb-live {
  opacity: 1;
  transition: opacity .3s var(--ease);
  transition-delay: calc(1.15s + var(--i) * 55ms);
}
/* Once it has arrived, main.js starts cycling it — so the arrival delay
   has to go, or every swap would wait a second and a half first. */
.js .team-graph .tb-cmd.is-ready { transition: opacity .22s var(--ease); transition-delay: 0s; }

/* The graph holds until it is on screen, then arrives as one piece. */
.js .team-graph { opacity: 0; pointer-events: none; }
.js .team-graph.is-on { opacity: 1; transition: opacity .5s var(--ease); }

/* Reduced motion: nothing animates and nothing stays hidden. The wires
   and the cards are still built — only the arrival is skipped. */
@media (prefers-reduced-motion: reduce) {
  .js .team-graph,
  .js .team-graph .tb-node, .js .team-graph .tb-chip, .js .team-graph .tb-foot,
  .js .team-graph .tb-cmd, .js .team-graph .tb-live {
    opacity: 1; transform: none; transition: none;
  }
}


/* 12c. WHAT'S INCLUDED ---------------------------------------------
   Nine logo buttons in a 3x3 block and one panel of five lines. The
   block is fixed rather than a scrolling row: a platform the visitor
   never sees cannot sell anything, and this section exists to show the
   spread. With JS off every panel shows, stacked under its heading. */

.included .section-head { margin-bottom: var(--s6); }
.included .eyebrow { margin-bottom: var(--s3); }

.inc { max-width: 940px; margin-inline: auto; }
@media (min-width: 860px) {
  .inc { display: grid; grid-template-columns: 280px 1fr; gap: var(--s7); align-items: start; }
}

.inc-tabs {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--s1);
  margin-bottom: var(--s5);
}
@media (min-width: 860px) { .inc-tabs { margin-bottom: 0; } }

.inc-tab {
  display: grid;
  justify-items: center;
  gap: 5px;
  padding: 12px 4px 10px;
  min-height: 76px;
  border: 1.5px solid var(--hairline);
  border-radius: 14px;
  background: var(--surface);
  color: var(--ink-dim);
  font: inherit;
  font-size: .75rem;
  cursor: pointer;
  transition: border-color .2s var(--ease), background .2s var(--ease), color .2s var(--ease);
}
.inc-tab svg { width: 22px; height: 22px; fill: var(--brand); }
@media (hover: hover) {
  .inc-tab:hover { border-color: rgba(26,23,20,.3); color: var(--ink); }
}
.inc-tab[aria-selected="true"] {
  border-color: var(--ink);
  border-width: 2px;
  background: var(--canvas);
  color: var(--ink);
  font-weight: 500;
}

.inc-panel h3 {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--s2);
  margin-bottom: var(--s4);
  font-size: 1.25rem;
}
.inc-panel h3 i {
  font-style: normal;
  font-size: .8125rem; font-weight: 400;
  color: var(--ink-faint);
}

/* Only the chosen panel shows once JS is running. */
.js .inc-panel[hidden] { display: none; }
.js .inc-panel.is-active { animation: inc-in .4s var(--ease) both; }
@keyframes inc-in { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) {
  .js .inc-panel.is-active { animation: none; }
  .inc-tab { transition: none; }
}
/* Without JS the panels stack, each labelled by its own heading. */
html:not(.js) .inc-panel + .inc-panel { margin-top: var(--s6); }

.inc-list { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--s3); }
.inc-list li {
  position: relative;
  padding-left: 28px;
  font-size: .9375rem;
  line-height: 1.55;
  color: var(--ink-dim);
}
.inc-list li::before {
  content: "";
  position: absolute; left: 5px; top: .45em;
  width: 11px; height: 6px;
  border-left: 2px solid var(--ink);
  border-bottom: 2px solid var(--ink);
  rotate: -45deg;
}


/* 12d. PRICE -------------------------------------------------------
   One offer, one card: the number and the button on one side, what
   you actually get on the other. */

/* The alternating band, now translucent rather than solid --canvas-2:
   at full opacity it punched an 840px beige hole straight through the
   page wash, at exactly the point the visitor is deciding to buy. At
   62% it still reads as a distinct band and the colour behind it still
   comes through. */
.sec-price { background: rgba(244,238,228,.62); }
.sec-price .section-head { margin-bottom: var(--s6); }
.sec-price .eyebrow { margin-bottom: var(--s3); }

.price-card {
  max-width: 940px;
  margin-inline: auto;
  padding: var(--s5);
  display: grid;
  gap: var(--s5);
}
@media (min-width: 820px) {
  .price-card { grid-template-columns: 1fr 1.15fr; gap: var(--s7); align-items: start; padding: var(--s6); }
}

.price-tag { display: flex; align-items: baseline; gap: var(--s2); margin: 0 0 var(--s2); }
.price-was {
  font-size: 1.5rem;
  color: var(--ink-faint);
  text-decoration: line-through;
  text-decoration-thickness: 1.5px;
}
.price-now {
  font-size: clamp(3.25rem, 9vw, 4.5rem);
  font-weight: 500;
  line-height: 1;
  letter-spacing: -0.03em;
}
.price-maths {
  margin: 0 0 var(--s4);
  font-size: .875rem;
  color: var(--ink-dim);
}
.price-note {
  margin: var(--s3) 0 0;
  font-size: .8125rem;
  line-height: 1.5;
  color: var(--ink-faint);
  text-align: center;
}

/* The support line is the last thing a hesitating buyer reads, so it gets
   readable ink and real links where the note above stays decorative. */
.price-support {
  margin-top: var(--s2);
  color: var(--ink-dim);
}
.price-support a {
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 2px;
}

.price-label {
  margin: 0 0 var(--s3);
  font-size: .75rem; font-weight: 500;
  letter-spacing: .12em; text-transform: uppercase;
  color: var(--ink-faint);
}

.price-list { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--s2); }
.price-list li {
  position: relative;
  padding-left: 28px;
  font-size: .9375rem;
  line-height: 1.5;
  color: var(--ink-dim);
}
.price-list b { color: var(--ink); font-weight: 500; }
.price-list li::before {
  content: "";
  position: absolute; left: 5px; top: .4em;
  width: 11px; height: 6px;
  border-left: 2px solid var(--ink);
  border-bottom: 2px solid var(--ink);
  rotate: -45deg;
}

/* Buy switch — two ways in, one control. Sized for a thumb: the whole
   pill is 52px tall on mobile, each half well over the 44px target. */
.price-switch {
  max-width: 940px;
  margin: 0 auto var(--s4);
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 4px;
  padding: 4px;
  background: rgba(26,23,20,.06);
  border-radius: 999px;
}
.price-switch-btn {
  appearance: none;
  border: 0;
  background: none;
  border-radius: 999px;
  padding: 12px 8px;
  min-height: 48px;
  font: inherit;
  font-size: .9375rem;
  color: var(--ink-dim);
  cursor: pointer;
  /* Both halves stay one line, so the pill never goes lopsided. */
  white-space: nowrap;
  transition: background .2s var(--ease), color .2s var(--ease), box-shadow .2s var(--ease);
}
@media (max-width: 359px) { .price-switch-btn { font-size: .8125rem; } }
.price-switch-btn b { font-weight: 600; margin-left: 4px; }
.price-switch-btn[aria-selected="true"] {
  background: var(--surface);
  color: var(--ink);
  box-shadow: 0 1px 3px rgba(26,23,20,.12);
}
@media (hover: hover) {
  .price-switch-btn:hover:not([aria-selected="true"]) { color: var(--ink); }
}

/* .price-card sets display:grid, which would beat the hidden attribute. */
.price-card[hidden] { display: none; }

/* Picker panel. Same card shell as the bundle so switching does not
   shift the page around. */
@media (min-width: 820px) {
  .price-pick { grid-template-columns: 1.35fr 1fr; }
}

.pick-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--s1);
  margin-top: var(--s3);
}

.pick-tile {
  appearance: none;
  display: grid;
  justify-items: center;
  gap: 3px;
  padding: 12px 4px 10px;
  min-height: 92px;
  background: var(--surface);
  border: 1.5px solid var(--hairline);
  border-radius: 14px;
  font: inherit;
  color: var(--ink-dim);
  cursor: pointer;
  transition: border-color .18s var(--ease), background .18s var(--ease), transform .18s var(--spring);
}
.pick-tile svg {
  width: 22px; height: 22px;
  fill: var(--brand);
  transition: transform .18s var(--spring);
}
.pick-name  { font-size: .75rem; line-height: 1.2; }
.pick-price { font-size: .6875rem; color: var(--ink-faint); }

.pick-tile[aria-pressed="true"] {
  border-color: var(--ink);
  background: var(--canvas);
  color: var(--ink);
}
.pick-tile[aria-pressed="true"] svg { transform: scale(1.12); }
.pick-tile[aria-pressed="true"] .pick-price { color: var(--ink-dim); }
@media (hover: hover) {
  .pick-tile:hover { border-color: rgba(26,23,20,.3); transform: translateY(-2px); }
}
.pick-tile:active { transform: scale(.96); }

/* Running total. This is the argument: four at $29 is more than all
   nine at $97, and the visitor gets there on their own. */
.pick-side { display: flex; flex-direction: column; justify-content: center; }
.pick-total {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s2);
  padding-bottom: var(--s2);
  border-bottom: 1px solid var(--hairline);
  margin-bottom: var(--s3);
}
.pick-count { font-size: .875rem; color: var(--ink-dim); }
.pick-sum   { font-size: 2rem; font-weight: 500; letter-spacing: -.02em; line-height: 1; }

.pick-nudge {
  margin: 0 0 var(--s3);
  padding: 10px 14px;
  background: var(--canvas-2);
  border-radius: 12px;
  font-size: .8125rem;
  line-height: 1.45;
  color: var(--ink-dim);
}
.pick-nudge b { color: var(--ink); font-weight: 600; }

/* The bundle escape hatch under the primary button. .btn-block sets
   display:flex, which would beat the hidden attribute. */
.pick-alt { margin-top: var(--s1); }
.pick-alt[hidden] { display: none; }

@media (prefers-reduced-motion: reduce) {
  .pick-tile, .pick-tile svg, .price-switch-btn { transition: none; }
}


/* 13. THE NINE ----------------------------------------------------- */

.sec-cast { background: var(--canvas-2); }

.grid-nine { display: grid; grid-template-columns: 1fr; gap: var(--s4); }
@media (min-width: 768px)  { .grid-nine { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1024px) { .grid-nine { grid-template-columns: repeat(3, 1fr); } }

.platform {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  padding: var(--s5);
  overflow: hidden;
  transition: transform .3s var(--ease), box-shadow .3s var(--ease), border-color .3s var(--ease);
}
/* Accent wash behind the mascot, at rest on mobile. */
.platform::before {
  content: '';
  position: absolute;
  inset: 0 0 auto 0;
  height: 190px;
  background: radial-gradient(ellipse at 26% 0%, var(--accent) 0%, transparent 68%);
  opacity: .16;
  transition: opacity .3s var(--ease);
  pointer-events: none;
}
.platform > * { position: relative; }

.platform-who {
  font-size: .8125rem;
  font-weight: 500;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--ink-faint);
  margin: 0 0 2px;
}
.platform h3 { margin-bottom: var(--s2); display: flex; align-items: center; gap: 10px; }

/* Real platform mark beside the name, so recognition is instant. */
.plat-badge { width: 22px; height: 22px; flex: none; fill: var(--ink); opacity: .82; }
.platform-role { color: var(--ink-dim); margin: 0; font-size: .9375rem; }

.platform-buy {
  margin-top: auto;
  padding-top: var(--s4);
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  color: var(--ink-dim);
  font-size: .875rem;
  font-weight: 500;
  text-decoration: none;
  border-bottom: 1.5px solid transparent;
  transition: color .2s var(--ease), border-color .2s var(--ease);
}
.platform-buy:hover { color: var(--ink); border-bottom-color: var(--ink); }

@media (hover: hover) {
  .platform:hover {
    transform: translateY(-6px);
    border-color: rgba(26,23,20,.2);
    box-shadow: 0 18px 40px rgba(26,23,20,.10);
  }
  .platform:hover::before { opacity: .3; }
  .platform:hover .m-float { animation-play-state: paused; }
  .platform:hover .mascot { transform: scale(1.08) rotate(-3deg); }
}
.mascot { transition: transform .35s var(--spring); }


/* 14. SUPPORT ASSETS ----------------------------------------------- */

.grid-four { display: grid; grid-template-columns: 1fr; gap: var(--s4); }
@media (min-width: 768px) { .grid-four { grid-template-columns: repeat(2, 1fr); } }

.asset h3 { margin-bottom: var(--s2); }
.asset p  { color: var(--ink-dim); margin: 0; }
.asset-num {
  font-size: .8125rem; font-weight: 500; letter-spacing: .08em;
  color: var(--ink-faint); margin-bottom: var(--s3);
}


/* 15. SETUP PROOF -------------------------------------------------- */

.steps { display: grid; gap: var(--s7); }

.step-head { display: flex; align-items: baseline; gap: var(--s3); margin-bottom: var(--s4); flex-wrap: wrap; }
.step-num {
  font-size: 1.5rem; font-weight: 500; color: var(--ink-faint);
  font-variant-numeric: tabular-nums;
}
.step-head h3 { flex: 1 1 14ch; }
.step-head p  { width: 100%; color: var(--ink-dim); margin: 0; }

.tag-optional {
  display: inline-flex; align-items: center;
  padding: 4px 11px; border-radius: 999px;
  border: 1.5px solid var(--hairline);
  background: var(--canvas-2);
  color: var(--ink-dim);
  font-size: .75rem; font-weight: 500; letter-spacing: .04em; text-transform: uppercase;
}

.frame {
  border: 1.5px solid var(--hairline);
  border-radius: 16px;
  overflow: hidden;
  background: var(--surface);
  box-shadow: 0 12px 32px rgba(26,23,20,.07);
}
.frame-bar {
  display: flex; align-items: center; gap: 6px;
  padding: 11px var(--s2);
  border-bottom: 1.5px solid var(--hairline);
  background: var(--canvas-2);
}
.frame-bar span { width: 10px; height: 10px; border-radius: 50%; background: var(--hairline); }

.shot-placeholder {
  aspect-ratio: 16 / 10;
  display: grid; place-items: center;
  padding: var(--s4); margin: var(--s2);
  border: 1.5px dashed rgba(26,23,20,.28);
  border-radius: 10px;
  color: var(--ink-faint);
  text-align: center; font-size: .875rem;
}


/* 16. BONUSES ------------------------------------------------------ */

.grid-two { display: grid; grid-template-columns: 1fr; gap: var(--s4); }
@media (min-width: 768px) { .grid-two { grid-template-columns: repeat(2, 1fr); } }

.bonus { background: transparent; border-style: dashed; }
.bonus h3 { margin-bottom: var(--s2); }
.bonus p  { color: var(--ink-dim); margin: 0; }


/* 19. FAQ ---------------------------------------------------------- */

.faq { max-width: var(--prose); margin-inline: auto; }
.faq .section-head { margin-bottom: var(--s5); }
.faq .eyebrow { margin-bottom: var(--s3); }
.faq details { border-bottom: 1.5px solid var(--hairline); }
/* The first row needs a rule above it too, or the list looks unfinished. */
.faq details:first-of-type { border-top: 1.5px solid var(--hairline); }
.faq details p { max-width: 58ch; }
.faq summary {
  display: flex; justify-content: space-between; align-items: center; gap: var(--s4);
  padding: var(--s4) 0; min-height: 44px; cursor: pointer;
  font-size: 1.0625rem; font-weight: 500; list-style: none;
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after {
  content: ''; flex: none;
  width: 10px; height: 10px;
  border-right: 2px solid var(--ink-faint);
  border-bottom: 2px solid var(--ink-faint);
  transform: rotate(45deg) translateY(-2px);
  transition: transform .25s var(--ease);
}
.faq details[open] summary::after { transform: rotate(-135deg) translateY(-2px); }
.faq details p { color: var(--ink-dim); padding-bottom: var(--s4); margin: 0; }


/* 20. FINAL CTA + FOOTER ------------------------------------------- */

.final { text-align: center; overflow: hidden; }
.final-inner { position: relative; z-index: 1; }
.final h2 { margin-bottom: var(--s4); }
.final .body-lg { max-width: 46ch; margin-inline: auto; margin-bottom: var(--s6); }
.final .hero-note { margin-top: var(--s3); margin-inline: auto; }

.site-footer {
  border-top: 1.5px solid var(--hairline);
  padding: var(--s6) var(--s4);
  color: var(--ink-dim);
  font-size: .875rem;
  background: var(--surface);
}
.footer-inner {
  max-width: var(--content); margin-inline: auto;
  display: flex; flex-wrap: wrap; gap: var(--s4);
  align-items: center; justify-content: space-between;
}
.footer-links { display: flex; flex-wrap: wrap; gap: var(--s4); }
.footer-links a {
  display: inline-flex; align-items: center; min-height: 44px;
  text-decoration: none; color: var(--ink-dim);
  border-bottom: 1.5px solid transparent;
}
.footer-links a:hover { color: var(--ink); border-bottom-color: var(--ink); }

.footer-legal {
  max-width: var(--content);
  margin: var(--s4) auto 0;
  padding-top: var(--s4);
  border-top: 1.5px solid var(--hairline);
  color: var(--ink-faint);
  font-size: .8125rem;
  line-height: 1.5;
}


/* 21. STICKY MOBILE CTA -------------------------------------------- */

/* Follows the visitor on every screen size once the hero scrolls out
   of view (main.js §2 toggles .is-shown): a full-width bar on phones,
   a floating pill in the corner on anything larger. */
.sticky-cta {
  display: flex;
  align-items: center;
  gap: var(--s3);
  position: fixed;
  z-index: 20;
  background: rgba(251,248,243,.92);
  backdrop-filter: blur(12px);
  transform: translateY(140%);
  transition: transform .35s var(--ease);
}
.sticky-cta.is-shown { transform: none; }
.sticky-cta .btn { min-height: 48px; padding-inline: var(--s4); font-size: 1rem; }

.sticky-price { line-height: 1.2; white-space: nowrap; }
.sticky-price strong { display: block; font-weight: 500; font-size: 1.125rem; }
.sticky-price span   { color: var(--ink-faint); font-size: .75rem; }

@media (max-width: 767px) {
  .sticky-cta {
    left: 0; right: 0; bottom: 0;
    justify-content: space-between;
    padding: var(--s2) var(--s3);
    padding-bottom: calc(var(--s2) + env(safe-area-inset-bottom));
    border-top: 1.5px solid var(--hairline);
  }

  /* Clears the bar at the bottom of the document. */
  main { padding-bottom: var(--s5); }
  .site-footer { padding-bottom: calc(var(--s6) + 88px); }

  .mascot { width: 96px; }
}

@media (min-width: 768px) {
  .sticky-cta {
    right: var(--s4); bottom: var(--s4);
    padding: var(--s2) var(--s2) var(--s2) var(--s5);
    border: 1.5px solid var(--hairline);
    border-radius: 999px;
    box-shadow: 0 14px 34px rgba(26,23,20,.16);
  }
}
