:root {
  /* ---- brand palette (2026 brand deck — do not deviate from these hex values) ---- */
  --magenta: #E8255A;
  --violet: #5533FF;
  --plum: #542C7B;
  --hotpink: #FF3399;
  --sky: #7BC4E8;
  --teal: #00A8A8;
  --cream: #F2F0EB;
  --black: #131018;

  /* ---- working alias (kept: "paper" reads as a true synonym for cream, unlike
     the old coral/orange/shadow-rose aliases which pointed at unrelated hues and
     have been replaced everywhere with their real token names) ---- */
  --paper: var(--cream);
  --line: rgba(19, 16, 24, 0.12);
  --line-dark: rgba(19, 16, 24, 0.14);
  --line-on-dark: rgba(242, 240, 235, 0.16);
  --max: 1180px;

  /* ---- jewel-tone dark surface gradients (restored "previous design" language) ---- */
  --jewel-1: linear-gradient(160deg, var(--black) 0%, var(--plum) 100%);
  --jewel-2: linear-gradient(150deg, var(--black) 0%, var(--plum) 78%);
  --jewel-3: linear-gradient(165deg, var(--plum) 0%, var(--black) 70%);
  --jewel-quote: linear-gradient(170deg, var(--black) 0%, var(--plum) 60%, var(--black) 100%);

  /* ---- type scale — the definitive set; every heading/label in the file should
     reference one of these rather than hand-rolling a new clamp(). Two contexts
     get an intentional second variant (Display, H2, Eyebrow) because the homepage
     hero/section carries denser supporting copy than inner pages and the closing
     CTA is a deliberate emphasis moment — both are documented, not drift. ---- */
  --text-display-hero: clamp(2.2rem, 5vw, 4.3rem);      /* homepage hero H1 */
  --text-display-page: clamp(2.8rem, 8vw, 5.6rem);      /* inner-page hero H1 */
  --text-h2: clamp(2rem, 5vw, 3.2rem);                  /* standard section heading */
  --text-h2-lg: clamp(2.1rem, 5.8vw, 3.6rem);           /* closing-CTA emphasis heading */
  --text-h3-card: 1.5rem;                               /* heading inside a boxed card (offer/service card) */
  --text-h3-grid-item: 1.1rem;                          /* heading inside a values/props grid item */
  --text-h3-quote: clamp(1.4rem, 3.5vw, 2.2rem);        /* standalone pull-quote statement */
  --text-h3-testimonial: clamp(1.3rem, 3vw, 1.9rem);    /* social-proof quote-card headline */
  --text-h3-step: 1.2rem;                               /* "how it works" step heading */
  --text-h3-faq: 1.05em;                                /* FAQ question (relative — tracks host font-size) */
  --text-kicker: 0.78rem;                                /* unified eyebrow/kicker label, used above every hero and section heading */
}

* { margin: 0; padding: 0; box-sizing: border-box; }

html { scroll-behavior: auto; }

body {
  font-family: 'Montserrat', sans-serif;
  background: var(--cream);
  color: var(--black);
  font-size: clamp(0.95rem, 1.5vw, 1.1rem);
  font-weight: 300;
  line-height: 1.65;
  overflow-x: hidden;
}

h1, h2, h3 {
  font-family: 'League Spartan', sans-serif;
  font-weight: 700;
  letter-spacing: 0.01em;
  text-transform: uppercase;
  line-height: 1.02;
  color: var(--black);
}
/* real default so a bare <h2> always gets the standard section-heading size,
   even without a wrapping .section-head — fixes a handful of headings that
   were silently falling back to the browser's ~24px default */
h2 { font-size: var(--text-h2); }

/* reserved for rare, single-moment emphasis — not a running script */
.script,
.script-accent {
  font-family: 'Permanent Marker', cursive;
  font-weight: 400;
  text-transform: none;
  letter-spacing: 0.01em;
}

/* handwritten quote treatment — every quote/script/brush accent site-wide sits
   on the same slight diagonal, like it was scrawled on top of the page rather
   than typeset. inline-block is what makes the rotation behave on inline
   spans; the one place this class lands on a full-width <p> (the Buckminster
   Fuller pull-quote) gets its own gentler override below so a wide block of
   text doesn't swing too far out of its normal reading line. */
.script,
.script-accent,
.accent,
.brush {
  display: inline-block;
  transform: rotate(-2.5deg);
}
p.script {
  display: block;
  transform: rotate(-1deg);
}

/* signature highlighter-marker stroke behind a key word — a solid flat
   colour fill (like a real highlighter swipe), shaped as a slightly crooked
   quadrilateral rather than a true rectangle: no two corners line up, so it
   reads as hand-drawn without any wave, fray, or texture that could
   interfere with reading the text. Corner offsets are kept small on purpose
   — enough tilt to read as "not machine-perfect", never enough to eat into
   the padding margin around the text (a bigger tilt looked hand-drawn but
   left too little colour behind ascenders/quote-marks near the shallow
   corners, making the text hard to read against a sudden background change). */
.mark {
  position: relative;
  display: inline;
  box-decoration-break: clone;
  -webkit-box-decoration-break: clone;
  margin: 0 0.07em;
  padding: 0.28em 0.55em;
  background-repeat: no-repeat;
  background-position: center;
  background-size: 100% 100%;
  /* the colour shape is a background-image (an SVG quadrilateral), never a
     clip-path/mask: clip-path combined with box-decoration-break:clone made
     Chromium drop entire wrapped-line fragments (confirmed on multiple pages
     at mobile widths — a plain rectangle was the fix at the time). A
     background-image doesn't share that failure mode: the text itself is a
     normal sibling layer that's never clipped. No default background/colour
     here: every usage must carry one of the three variants below. */
}
.mark.is-coral   { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 300 64' preserveAspectRatio='none'%3E%3Cpath d='M4,11 L296,2 L291,57 L9,63 Z' fill='%235533FF'/%3E%3C/svg%3E"); color: var(--cream); }
.mark.is-pink    { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 300 64' preserveAspectRatio='none'%3E%3Cpath d='M4,11 L296,2 L291,57 L9,63 Z' fill='%23FF3399'/%3E%3C/svg%3E"); color: var(--black); }
.mark.is-magenta { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 300 64' preserveAspectRatio='none'%3E%3Cpath d='M4,11 L296,2 L291,57 L9,63 Z' fill='%23E8255A'/%3E%3C/svg%3E"); color: var(--cream); }
.mark.is-sky     { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 300 64' preserveAspectRatio='none'%3E%3Cpath d='M4,11 L296,2 L291,57 L9,63 Z' fill='%237BC4E8'/%3E%3C/svg%3E"); color: var(--black); }
/* .mark's own display:inline (below) otherwise wins the cascade over
   .brush's display:inline-block and silently drops the rotate — transform
   has no effect on plain inline boxes per spec, so a "wonky" mark needs
   this to actually tilt. */
.mark.brush { display: inline-block; }

/* thicker version for marks that wrap across multiple lines (e.g. the
   homepage hero quote) — taller viewBox, notably more padding since this
   variant pairs with the .script (Permanent Marker) font, whose glyphs
   (especially the opening quotation mark) sit tighter to the cap-height
   than League Spartan and need more clearance from the shape's edge */
.mark.thick { padding: 0.55em 0.75em; }
.mark.thick.is-coral   { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 300 100' preserveAspectRatio='none'%3E%3Cpath d='M4,17 L296,3 L291,89 L9,98 Z' fill='%235533FF'/%3E%3C/svg%3E"); color: var(--cream); }
.mark.thick.is-pink    { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 300 100' preserveAspectRatio='none'%3E%3Cpath d='M4,17 L296,3 L291,89 L9,98 Z' fill='%23FF3399'/%3E%3C/svg%3E"); color: var(--black); }
.mark.thick.is-magenta { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 300 100' preserveAspectRatio='none'%3E%3Cpath d='M4,17 L296,3 L291,89 L9,98 Z' fill='%23E8255A'/%3E%3C/svg%3E"); color: var(--cream); }

/* secondary emphasis — a plain colour underline instead of a filled block, for
   texture variety alongside .mark; used sparingly on a phrase here or there */
.underline-accent {
  text-decoration: none;
  border-bottom: 0.14em solid var(--violet);
  padding-bottom: 0.03em;
}
.tone-deep .underline-accent,
.tone-black .underline-accent { border-bottom-color: var(--magenta); }

/* scroll-drawn underline — a ::after line under a run of inline text that
   grows in via the --draw custom property (see initUnderlineAccent), rather
   than a static border. GSAP tweens --draw directly. */
.draw-underline {
  --draw: 0;
  position: relative;
  display: inline-block;
}
.draw-underline::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: -0.15em;
  height: 2px;
  background: currentColor;
  transform: scaleX(var(--draw));
  transform-origin: left center;
}

/* ---------- glitch / chromatic-aberration accent — reserved for moments that
   describe the "broken" old way of doing marketing (problem copy, the 'ick'),
   never on persistent brand elements (logo, nav) or solution/CTA copy.
   Built with text-shadow + transform only, deliberately avoiding clip-path:
   combined with .mark's box-decoration-break:clone, clip-path silently drops
   whichever line-fragment it's applied to when text wraps (see the .mark fix
   above) — text-shadow has no such failure mode.
   Entirely gated behind prefers-reduced-motion: no-preference, so it's purely
   additive for users who haven't asked their OS for less motion. ---------- */
@media (prefers-reduced-motion: no-preference) {
  .glitch-hover { cursor: default; }
  .glitch-hover:hover,
  .glitch-hover:focus-visible,
  .glitch-hover.is-glitching {
    animation: glitch-jitter 0.3s steps(2, end) infinite;
  }
  @keyframes glitch-jitter {
    0%   { text-shadow: 2px 0 var(--sky), -2px 0 var(--magenta); transform: translate(0, 0); }
    25%  { text-shadow: -2px 1px var(--sky), 2px -1px var(--magenta); transform: translate(-1px, 1px); }
    50%  { text-shadow: 2px -1px var(--sky), -2px 1px var(--magenta); transform: translate(1px, -1px); }
    75%  { text-shadow: -1px 0 var(--sky), 1px 0 var(--magenta); transform: translate(0, 1px); }
    100% { text-shadow: 2px 0 var(--sky), -2px 0 var(--magenta); transform: translate(0, 0); }
  }
  /* .brush marks already carry a rotate(); the keyframes above set transform
     outright, so a wonky mark would snap straight the moment it glitched.
     Same jitter, with the tilt baked back into every keyframe. */
  .mark.brush.glitch-hover:hover,
  .mark.brush.glitch-hover:focus-visible,
  .mark.brush.glitch-hover.is-glitching {
    animation-name: glitch-jitter-brush;
  }
  @keyframes glitch-jitter-brush {
    0%   { text-shadow: 2px 0 var(--sky), -2px 0 var(--magenta); transform: rotate(-2.5deg) translate(0, 0); }
    25%  { text-shadow: -2px 1px var(--sky), 2px -1px var(--magenta); transform: rotate(-2.5deg) translate(-1px, 1px); }
    50%  { text-shadow: 2px -1px var(--sky), -2px 1px var(--magenta); transform: rotate(-2.5deg) translate(1px, -1px); }
    75%  { text-shadow: -1px 0 var(--sky), 1px 0 var(--magenta); transform: rotate(-2.5deg) translate(0, 1px); }
    100% { text-shadow: 2px 0 var(--sky), -2px 0 var(--magenta); transform: rotate(-2.5deg) translate(0, 0); }
  }
}

/* ---------- Problem → Shift scroll transition — a brief signal-glitch as the
   page moves from naming the broken way into the shift toward the other way.
   Opacity is scrubbed to scroll position by GSAP (index.html inline script);
   the scanline/jitter animation runs continuously underneath but is invisible
   at opacity 0, so it's already mid-motion the instant it becomes visible.
   Skipped entirely under reduced-motion — see JS gating alongside it. ---------- */
.glitch-transition {
  position: absolute;
  inset: 0;
  z-index: 5;
  pointer-events: none;
  opacity: 0;
  background:
    repeating-linear-gradient(0deg, rgba(242, 240, 235, 0.07) 0px, rgba(242, 240, 235, 0.07) 1px, transparent 1px, transparent 3px),
    linear-gradient(90deg, rgba(123, 196, 232, 0.18), rgba(232, 37, 90, 0.18));
  mix-blend-mode: screen;
}
@media (prefers-reduced-motion: no-preference) {
  .glitch-transition { animation: glitch-scan-drift 0.5s steps(4, end) infinite; }
  .glitch-transition-bar {
    position: absolute;
    left: 0;
    right: 0;
    height: 5%;
    background: rgba(242, 240, 235, 0.55);
    mix-blend-mode: overlay;
    animation: glitch-bar-jitter 0.4s steps(3, end) infinite;
  }
  .glitch-transition-bar:nth-child(1) { top: 14%; animation-delay: 0s; }
  .glitch-transition-bar:nth-child(2) { top: 48%; animation-delay: 0.12s; }
  .glitch-transition-bar:nth-child(3) { top: 76%; animation-delay: 0.06s; }
  @keyframes glitch-scan-drift {
    0%   { background-position: 0 0, 0 0; }
    100% { background-position: 0 6px, 4px 0; }
  }
  @keyframes glitch-bar-jitter {
    0%   { transform: translateX(0); }
    33%  { transform: translateX(-2.5%); }
    66%  { transform: translateX(3%); }
    100% { transform: translateX(0); }
  }
}

a { color: inherit; text-decoration: none; }

.wrap {
  max-width: var(--max);
  margin: 0 auto;
  padding: 0 6vw;
}

.wrap-narrow {
  max-width: 760px;
  margin: 0 auto;
  padding: 0 6vw;
}

/* ---------- background texture ---------- */
.grain {
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 1;
  opacity: 0.10;
  mix-blend-mode: multiply;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160' viewBox='0 0 160 160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

.scratches {
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 1;
  opacity: 0.065;
  mix-blend-mode: multiply;
  background-image:
    repeating-linear-gradient(115deg, rgba(19,16,24,0.7) 0px, transparent 1.5px, transparent 140px, rgba(19,16,24,0.4) 142px),
    repeating-linear-gradient(35deg, rgba(19,16,24,0.5) 0px, transparent 1px, transparent 220px, rgba(19,16,24,0.3) 222px);
}

/* let the texture breathe instead of sitting perfectly static — grain jitters
   in discrete steps like real film flicker, scratches drift slowly like dust
   on an old reel. Purely decorative motion, so fully gated. */
@media (prefers-reduced-motion: no-preference) {
  .grain { animation: grain-jitter 1.2s steps(4) infinite, grain-breathe 6s ease-in-out infinite; }
  .scratches { animation: scratches-drift 24s linear infinite; }
  @keyframes grain-jitter {
    0%   { background-position: 0 0; }
    25%  { background-position: -17px 8px; }
    50%  { background-position: 11px -13px; }
    75%  { background-position: -8px -6px; }
    100% { background-position: 0 0; }
  }
  @keyframes grain-breathe {
    0%, 100% { opacity: 0.10; }
    50%      { opacity: 0.14; }
  }
  @keyframes scratches-drift {
    0%   { background-position: 0 0, 0 0; }
    100% { background-position: 420px 240px, -320px 280px; }
  }
}

/* ---------- decorative blocks ---------- */
.block {
  position: absolute;
  z-index: 0;
}
.block-pink   { background: var(--magenta); }
.block-coral  { background: var(--violet); }
.block-paper  { background: var(--paper); }
.block-line   { border: 1px solid currentColor; background: transparent; }

/* ---------- nav ---------- */
body > nav {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 50;
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 1.2rem 6vw;
  background: rgba(19, 16, 24, 0.45);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  color: var(--cream);
  transition: background 0.4s ease, border-color 0.4s ease;
}
body > nav.is-scrolled {
  background: rgba(19, 16, 24, 0.82);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
}

/* ---------- scroll progress bar — a thin brand-gradient hairline that fills
   as you move through the page, sitting above nav so it's always visible ---------- */
.scroll-progress {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  height: 3px;
  z-index: 60;
  background: rgba(19, 16, 24, 0.1);
  pointer-events: none;
}
.scroll-progress-fill {
  height: 100%;
  width: 100%;
  background: linear-gradient(90deg, var(--violet), var(--magenta), var(--teal), var(--sky));
  transform: scaleX(0);
  transform-origin: left center;
  will-change: transform;
}

.nav-mark {
  font-family: 'League Spartan', sans-serif;
  font-size: 1.25rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--cream);
}
.nav-links { display: flex; gap: 2rem; font-size: 0.82rem; letter-spacing: 0.08em; text-transform: uppercase; }
.nav-links a { opacity: 0.65; transition: opacity 0.3s ease, color 0.3s ease; }
.nav-links a:hover, .nav-links a.is-active { opacity: 1; color: var(--violet); }

/* hamburger toggle — hidden above the mobile breakpoint */
.nav-toggle {
  display: none;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  gap: 5px;
  width: 2.4rem;
  height: 2.4rem;
  background: none;
  border: none;
  cursor: pointer;
  z-index: 51;
}
.nav-toggle span {
  display: block;
  width: 22px;
  height: 2px;
  background: var(--cream);
  border-radius: 2px;
  transition: transform 0.3s ease, opacity 0.3s ease;
}
nav.is-open .nav-toggle span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
nav.is-open .nav-toggle span:nth-child(2) { opacity: 0; }
nav.is-open .nav-toggle span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }

@media (max-width: 640px) {
  .nav-toggle { display: flex; }
  .nav-links {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    height: 100vh;
    z-index: 49;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    gap: 2.2rem;
    font-size: 1.15rem;
    background: rgba(19, 16, 24, 0.97);
    backdrop-filter: blur(14px);
    -webkit-backdrop-filter: blur(14px);
    opacity: 0;
    visibility: hidden;
    transform: translateY(-8px);
    transition: opacity 0.35s ease, transform 0.35s ease, visibility 0s linear 0.35s;
  }
  nav.is-open .nav-links {
    opacity: 1;
    visibility: visible;
    transform: translateY(0);
    transition: opacity 0.35s ease, transform 0.35s ease, visibility 0s linear 0s;
  }
  .nav-links .btn-header { margin-top: 0.6rem; }
}

/* ---------- page hero (shorter, for inner pages) — deep jewel-tone gradient ---------- */
.page-hero {
  position: relative;
  min-height: 56vh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  overflow: hidden;
  background: var(--jewel-2);
  color: var(--paper);
  padding: 9rem 0 5rem;
  border-bottom: 1px solid var(--line-on-dark);
}
.page-hero .hero-inner { position: relative; z-index: 2; }
.page-hero h1 { font-size: var(--text-display-page); color: var(--paper); }
.page-hero .tagline {
  margin-top: 1.8rem;
  max-width: 56ch;
  font-size: inherit;
  font-weight: 300;
  color: rgba(242, 240, 235, 0.78);
}
/* handwritten variant of the inner-page hero tagline — same role the
   homepage .hero .tagline-handwritten plays under its h1, sized down a step
   because the page-hero display type above it is already smaller. overflow
   stays visible so a .brush tilt/.mark shape can't be clipped. */
.page-hero .tagline-handwritten {
  margin-top: 1.4rem;
  max-width: 40ch;
  font-size: clamp(1.05rem, 2.4vw, 1.7rem);
  line-height: 1.35;
  font-weight: 400;
  color: var(--paper);
  overflow: visible;
}

/* full-bleed image + scrim variant of the inner-page hero — same family as
   the homepage .hero's ::before (image) / ::after (legibility gradient)
   pattern, ported here as real elements (not pseudo-elements) so each page
   can carry its own [data-photo-wipe] image or image-placeholder-bleed
   stand-in. Left-strong horizontal fade mirrors .hero::after since page-hero
   copy is left-aligned, not centered. */
.page-hero-fullbleed { position: relative; overflow: hidden; }
.page-hero-fullbleed .page-hero-photo-bleed {
  position: absolute;
  inset: 0;
  z-index: 0;
}
.page-hero-fullbleed .page-hero-photo-bleed img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 30%;
}
.page-hero-fullbleed .mesh { z-index: 1; }
.page-hero-scrim {
  position: absolute;
  inset: 0;
  z-index: 2;
  background: linear-gradient(90deg,
    rgba(19,16,24,0.84) 0%,
    rgba(19,16,24,0.62) 32%,
    rgba(19,16,24,0.3) 55%,
    rgba(19,16,24,0.1) 74%);
}
.page-hero-fullbleed .hero-inner { z-index: 3; }
/* placeholder tag reads top-left copy zone on desktop, so park it bottom-right
   instead of whyyou-fullbleed's default centered-top position */
.page-hero-fullbleed .image-placeholder-tag {
  top: auto;
  left: auto;
  bottom: 2rem;
  right: 6vw;
  transform: none;
}
@media (max-width: 880px) {
  .page-hero-scrim {
    background: linear-gradient(180deg, rgba(19,16,24,0.82) 0%, rgba(19,16,24,0.58) 45%, rgba(19,16,24,0.8) 100%);
  }
}

/* ---------- hero (homepage, full height) — jewel gradient + image, no flattening overlay ---------- */
.hero {
  position: relative;
  min-height: 92vh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  overflow: hidden;
  background: var(--black);
  color: var(--paper);
  border-bottom: 1px solid var(--line-on-dark);
  padding-top: 7rem;
  padding-bottom: 4rem;
}
/* the lollipop image on its own layer so it can be colour-boosted (bold, not dull)
   without touching the text on top */
.hero::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 0;
  background: url('images/hero-lollipop.jpg') center / cover no-repeat;
  filter: saturate(1.16) contrast(1.05) brightness(1.02);
}
/* legibility scrim — only on the left where the copy sits; fully clear by ~52%
   so the lips + Earth lollipop on the right stay crisp and vivid */
.hero::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 2;
  background: linear-gradient(90deg,
    rgba(19,16,24,0.74) 0%,
    rgba(19,16,24,0.5) 20%,
    rgba(19,16,24,0.16) 40%,
    rgba(19,16,24,0) 52%);
}
@media (max-width: 880px) {
  /* On narrow screens 'cover' crops this 16:9 shot down to a ~24%-wide slice, so
     the focal point has to do real work. 72% landed that slice half on the flat
     purple backdrop; 86% puts the lips, tongue and Earth lollipop in frame and
     drops most of the empty wall. */
  .hero::before { background-position: 86% center; }
  .hero::after {
    background: linear-gradient(180deg,
      rgba(19,16,24,0.82) 0%,
      rgba(19,16,24,0.6) 45%,
      rgba(19,16,24,0.72) 100%);
  }
}

.mesh {
  position: absolute;
  inset: -10%;
  z-index: 0;
  overflow: hidden;
  will-change: background-position;
  /* Multi-tone gradient mesh — Sky, Violet, Magenta, Teal drifting slowly and
     independently of scroll. initMeshScrub() layers a separate scale/opacity
     scrub on top via transform/opacity, so the two animations don't collide. */
  background:
    radial-gradient(45% 40% at 20% 20%, rgba(123, 196, 232, 0.32), transparent 70%),
    radial-gradient(40% 45% at 80% 30%, rgba(85, 51, 255, 0.26), transparent 70%),
    radial-gradient(50% 45% at 50% 80%, rgba(232, 37, 90, 0.16), transparent 70%),
    radial-gradient(35% 35% at 85% 85%, rgba(0, 168, 168, 0.2), transparent 70%);
  background-size: 200% 200%;
  animation: meshDrift 26s ease-in-out infinite alternate;
}
@keyframes meshDrift {
  0%   { background-position: 0% 0%, 100% 0%, 50% 100%, 100% 100%; }
  50%  { background-position: 22% 32%, 78% 18%, 42% 82%, 88% 68%; }
  100% { background-position: 10% 16%, 90% 8%, 56% 92%, 94% 84%; }
}

.hero-inner {
  position: relative;
  z-index: 3;
  padding: 0 6vw;
}
/* ambient glow — the same drifting mesh extended to other dark sections so
   the page keeps breathing beyond just the hero. Sits behind the content
   wrap, which is why every dark section's inner wrap needs z-index above 0. */
.mesh-ambient {
  opacity: 0.32;
  mix-blend-mode: screen;
}
.tone-deep > .wrap,
.tone-black > .wrap,
.tone-quote > .wrap { position: relative; z-index: 1; }
/* keep the drifting mesh over the left copy zone only, so the image reads true */
.hero .mesh {
  z-index: 1;
  opacity: 0.6;
  -webkit-mask: linear-gradient(90deg, #000 0%, #000 28%, transparent 52%);
  mask: linear-gradient(90deg, #000 0%, #000 28%, transparent 52%);
}
@media (max-width: 880px) {
  .hero .mesh { -webkit-mask: none; mask: none; opacity: 0.45; }
}

/* ---------- hero — single column, all copy on the left over the image's negative space ---------- */
.hero-copy {
  max-width: 720px;
}
.hero-lead {
  font-size: clamp(1.25rem, 2.4vw, 1.8rem);
  font-weight: 500;
  color: rgba(250, 247, 241, 0.92);
  white-space: nowrap;
  margin-bottom: 0.7rem;
}
@media (max-width: 560px) {
  .hero-lead { white-space: normal; }
}
.hero-copy h1 {
  font-size: var(--text-display-hero);
  line-height: 1;
  color: var(--paper);
  margin: 0;
  white-space: nowrap;
}
@media (max-width: 700px) {
  /* The <br> in the markup already sets the intended two lines. Below ~460px
     the clamp's 2rem floor made each of those two halves wrap again, so the
     statement broke over four lines. The measure is fixed by construction:
     .hero-inner pads 6vw a side, so the line box is always 0.88 x viewport,
     and the longest half ("giving you the 'ick'") plus .mark.thick's 0.75em
     side padding is always 10.997 x the font-size. 0.88 / 10.997 = 8vw is the
     exact fit, so 7.7vw is that same relationship with a ~4% safety margin
     rather than a number tuned to one phone. min() means it only ever caps the
     size, never raises it: from ~457px up the 2rem floor is still what wins. */
  .hero-copy h1 {
    white-space: normal;
    font-size: min(var(--text-display-hero), 7.7vw);
  }
}
/* the whole "giving you the ick" line glitches continuously, like the 404
   numeral — a persistent signal that something's broken, not just a hover
   surprise (previously scoped to just the 'ick' word's .mark) */

.hero-prompt {
  margin-top: 3.6rem;
  font-family: 'Montserrat', sans-serif;
  font-weight: 300;
  text-transform: none;
  letter-spacing: normal;
  font-size: clamp(0.95rem, 1.5vw, 1.1rem);
  color: rgba(250, 247, 241, 0.82);
}

.hero .tagline {
  margin-top: 1.1rem;
  max-width: 46ch;
  font-size: clamp(1.05rem, 2.4vw, 1.85rem);
  line-height: 1.3;
  color: var(--paper);
  overflow: visible;
}
.hero .tagline em { font-style: italic; }
.tagline .word { display: inline-block; will-change: transform, opacity; }

.hero .btn { margin-top: 3.2rem; }


.scroll-cue {
  position: absolute;
  bottom: 2.6rem;
  right: 6vw;
  font-size: 0.76rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: rgba(250, 247, 241, 0.45);
  display: flex;
  align-items: center;
  gap: 0.7rem;
  z-index: 3;
}
.scroll-cue .stem {
  width: 1px;
  height: 38px;
  background: rgba(250, 247, 241, 0.3);
  position: relative;
  overflow: hidden;
}
.scroll-cue .stem::after {
  content: '';
  position: absolute;
  inset: 0;
  background: var(--violet);
  transform: translateY(-100%);
  animation: cue 2.4s ease-in-out infinite;
}
@keyframes cue {
  0% { transform: translateY(-100%); }
  50% { transform: translateY(0); }
  100% { transform: translateY(100%); }
}

/* ---------- headline statement — standalone pull-quote break between problem beats ---------- */
.headline-statement {
  font-family: 'League Spartan', sans-serif;
  font-weight: 700;
  text-transform: uppercase;
  font-size: clamp(1.6rem, 3.8vw, 2.8rem);
  line-height: 1.2;
  max-width: 26ch;
  margin: 0 auto;
  text-align: center;
  color: var(--cream);
}
.headline-statement strong { color: var(--magenta); }
/* full-bleed variant — the "second 404-echo moment": no competing image,
   drama through scale alone. Wider column, much bigger type than the
   original image-split treatment could afford. */
.headline-statement-big {
  font-size: clamp(1.8rem, 4.4vw, 3.4rem);
  max-width: 22ch;
  line-height: 1.1;
}
.headline-fullbleed { display: flex; align-items: center; justify-content: center; min-height: 70vh; text-align: center; }
/* handwritten lead-in line sitting directly above a .headline-statement —
   sets up the statement as something that was actually said out loud */
.headline-lead-in {
  text-align: center;
  margin: 0 auto 1.6rem;
  font-size: clamp(1rem, 2.2vw, 1.45rem);
  color: var(--sky);
  max-width: 30ch;
}

/* ---------- section shell ---------- */
section { position: relative; z-index: 2; }
.overflow-hidden { overflow: hidden; }

/* soft blended transitions — a section boundary is a hard flat-colour cut by
   default; these fade the PREVIOUS section's tone in across the first ~90px
   of THIS section instead, so the page reads as one continuous flow rather
   than stacked blocks. Deliberately not used on the full-bleed photo
   sections (Problem, The Shift, the Final CTA) — those already carry their
   own carefully-tuned scrim/contrast and a second overlay would wash them
   out the same way the CTA's old grey scrim did. */
.blend-top-dark::before,
.blend-top-light::before,
.blend-top-pink::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 90px;
  z-index: 0;
  pointer-events: none;
}
.blend-top-dark::before { background: linear-gradient(180deg, rgba(19, 16, 24, 0.55) 0%, rgba(19, 16, 24, 0) 100%); }
.blend-top-light::before { background: linear-gradient(180deg, rgba(242, 240, 235, 0.7) 0%, rgba(242, 240, 235, 0) 100%); }
.blend-top-pink::before { background: linear-gradient(180deg, rgba(232, 37, 90, 0.4) 0%, rgba(232, 37, 90, 0) 100%); }

.section-pad { padding: clamp(5rem, 12vh, 9rem) 0; }
.section-pad-sm { padding: clamp(3.5rem, 9vh, 6rem) 0; }
/* chapter-break spacing — reserved for genuine narrative pivots and the
   full-bleed statement moments echoing the 404 page's generosity, not a
   general "bigger is better" replacement for .section-pad */
.section-pad-lg { padding: clamp(7rem, 18vh, 13rem) 0; }

/* single, unified label style used above every hero and section heading;
   colour varies by section via the tone/section overrides below */
.kicker {
  display: block;
  overflow: hidden;
  font-family: 'Montserrat', sans-serif;
  font-size: var(--text-kicker);
  letter-spacing: 0.26em;
  text-transform: uppercase;
  font-weight: 700;
  color: var(--violet);
  margin-bottom: 1.2rem;
}
.hero .kicker,
.page-hero .kicker { color: var(--sky); }
.hero .kicker {
  overflow: visible;
  white-space: nowrap;
  font-size: clamp(0.4rem, 1.7vw, 0.85rem);
  letter-spacing: clamp(0.05em, 0.28vw, 0.18em);
}
/* The nowrap + vw clamp above bottomed out at 0.4rem (6.4px) on a phone, which
   is unreadable. On mobile the hero kicker drops back to the site-wide kicker
   token so it matches every other section, and is allowed to wrap: two legible
   lines beat one 6px line. */
@media (max-width: 700px) {
  .hero .kicker {
    white-space: normal;
    font-size: var(--text-kicker);
    letter-spacing: 0.2em;
    line-height: 1.5;
  }
}

.section-head h2 {
  max-width: 18ch;
}

.lede {
  margin-top: 1.6rem;
  font-size: inherit;
  font-weight: 300;
  max-width: 68ch;
  color: rgba(19, 16, 24, 0.72);
}

.prose p {
  font-size: inherit;
  font-weight: 300;
  color: rgba(19, 16, 24, 0.72);
  max-width: 72ch;
}
.prose p + p { margin-top: 1.2rem; }
/* scoped paragraph rhythm for sections that want copy to arrive as
   individually scroll-triggered "beats" (each <p> carries its own
   [data-reveal-up]) rather than one flat paragraph block — documented in
   style-guide.html's Layout & Spacing section, used on About's long-form
   story section to give 18 unbroken paragraphs real breathing room. */
.problem-beats p + p { margin-top: 7rem; }
.prose .accent {
  font-family: 'Permanent Marker', cursive;
  font-weight: 600;
  font-size: 1.3em;
  color: var(--violet);
}
.prose strong { color: var(--black); font-weight: 600; }

/* =====================================================================
   SECTION TONES
   .tone-deep / .tone-black  → dark jewel-tone gradient sections (restored)
   .tone-light                → cream/white sections (new — the "lighten it up" pass)
   .tone-quote                → mid-tone vivid gradient for testimonials
   ===================================================================== */

/* dark jewel-tone block — deep gradient, not flat */
.tone-deep {
  background: var(--jewel-1);
  color: var(--cream);
}
.tone-deep .kicker { color: var(--sky); }
.tone-deep .lede,
.tone-deep .prose p,
.tone-deep p { color: rgba(242, 240, 235, 0.78); }
.tone-deep h2,
.tone-deep h3 { color: var(--cream); }
.tone-deep .prose strong { color: var(--cream); }
.tone-deep .btn { background: var(--cream); color: var(--black); box-shadow: 6px 6px 0 0 var(--violet); }
.tone-deep .btn::before { background: var(--black); }
.tone-deep .btn:hover {
  background: var(--violet);
  box-shadow: 3px 3px 0 0 var(--cream);
  color: var(--cream);
}

/* explicit light/cream section — the alternation introduced in this pass */
.tone-light {
  background: var(--cream);
  color: var(--black);
}
.tone-light .lede,
.tone-light .prose p,
.tone-light h2 { color: inherit; }
.tone-light .prose p,
.tone-light .lede { color: rgba(19, 16, 24, 0.72); }
/* style-guide rule: every kicker on a white/cream section background stays
   the brand violet rather than inheriting the section's body-text colour —
   .kicker's own base color is already violet, so this just stops
   .tone-light from overriding it back to black/inherit */
.tone-light .kicker { color: var(--violet); }

.tone-base { background: var(--hotpink); color: var(--black); }

/* mid-tone vivid gradient block for quotes/testimonials */
.tone-quote {
  background: var(--jewel-quote);
  color: var(--cream);
}

/* the reserved high-contrast black moment on the site — used sparingly, e.g. a single CTA band */
.tone-black {
  background: var(--black);
  color: var(--cream);
}
.tone-black .kicker { color: var(--sky); }
.tone-black .lede,
.tone-black .prose p,
.tone-black p { color: rgba(242, 240, 235, 0.78); }
.tone-black h2 { color: var(--cream); }
.tone-black .btn { background: var(--cream); color: var(--black); box-shadow: 6px 6px 0 0 var(--violet); }
.tone-black .btn::before { background: var(--black); }
.tone-black .btn:hover {
  background: var(--violet);
  box-shadow: 3px 3px 0 0 var(--cream);
  color: var(--cream);
}

/* ---------- accent overrides — each card/section gets a deliberate colour from the hierarchy ---------- */
/* --accent-ink pairs each accent with a readable ink colour for when it's used as a
   solid chip background (light accents get black ink, dark accents get cream ink) —
   this is what lets pastel/mid-tone colours like Hot Pink or Teal read as vivid chips on
   a light host section instead of washing out as plain coloured text. */
.accent-pink    { --accent: var(--hotpink); --accent-ink: var(--black); }  /* Hot Pink — energy accent */
.accent-coral   { --accent: var(--violet);       --accent-ink: var(--cream); }  /* Violet — signature anchor */
.accent-magenta { --accent: var(--magenta);     --accent-ink: var(--cream); }  /* Magenta — secondary heat */
.accent-teal    { --accent: var(--teal);        --accent-ink: var(--black); }  /* Teal — fresh / growth */
.accent-plum    { --accent: var(--plum);        --accent-ink: var(--cream); }  /* Plum — depth */
.accent-sky     { --accent: var(--sky);         --accent-ink: var(--black); }  /* Sky — air */
/* the middle/featured card in a 3-card row gets a cream button + coral shadow instead of a solid accent fill */
.card.accent-coral .btn {
  background: var(--cream);
  color: var(--black);
  box-shadow: 6px 6px 0 0 var(--violet);
}
.card.accent-coral .btn::before { background: var(--violet); }
.card.accent-coral .btn:hover {
  background: var(--violet);
  color: var(--cream);
  box-shadow: 3px 3px 0 0 var(--cream);
}

/* ---------- grids ---------- */
.grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 2.6rem; }
.grid-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1.6rem; }
@media (max-width: 880px) {
  .grid-2, .grid-3 { grid-template-columns: 1fr; }
}

/* ---------- cards — gradient top-border accent + faded number watermark bleeding off bottom-right ---------- */
.cards {
  position: relative;
  z-index: 1;
  margin-top: 3.5rem;
}

.card {
  position: relative;
  overflow: hidden;
  background: rgba(242, 240, 235, 0.04);
  border: 1px solid var(--line-on-dark);
  border-top: 3px solid transparent;
  border-image: linear-gradient(90deg, var(--violet), var(--accent, var(--magenta))) 1;
  border-radius: 2px;
  padding: 2.4rem 2rem;
  transition: transform 0.4s cubic-bezier(.2,.8,.2,1), box-shadow 0.4s ease, border-color 0.4s ease;
}
.card:hover {
  transform: translateY(-6px);
  box-shadow: 10px 14px 0 0 var(--accent, var(--violet));
}
.card .num {
  font-family: 'League Spartan', sans-serif;
  font-size: 1.05rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--accent, var(--violet));
}
.card h3 {
  margin-top: 0.9rem;
  font-size: var(--text-h3-card);
  color: var(--cream);
}
.card p {
  position: relative;
  z-index: 1;
  margin-top: 0.9rem;
  font-size: inherit;
  font-weight: 300;
  color: rgba(242, 240, 235, 0.74);
}
.card .underline {
  margin-top: 1.6rem;
  height: 2px;
  width: 100%;
  background: var(--line-on-dark);
  position: relative;
  overflow: hidden;
}
.card .underline::after {
  content: '';
  position: absolute;
  inset: 0;
  background: var(--accent, var(--violet));
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.5s cubic-bezier(.2,.8,.2,1);
}
.card:hover .underline::after { transform: scaleX(1); }
.card .btn {
  margin-top: 1.6rem;
  background: var(--accent, var(--violet));
  color: var(--accent-ink, var(--cream));
  box-shadow: none;
}
.card .btn:hover { color: var(--cream); }
.card .btn::before { background: var(--black); }

/* number watermark — large faded numeral bleeding off the bottom-right corner of a card */
.card .watermark,
.step .watermark,
.value-prop .watermark {
  position: absolute;
  bottom: -0.22em;
  right: 0.1em;
  font-family: 'League Spartan', sans-serif;
  font-weight: 800;
  font-size: 8.5rem;
  line-height: 1;
  color: var(--accent, var(--magenta));
  opacity: 0.14;
  pointer-events: none;
  z-index: 0;
  user-select: none;
}

/* true frosted glassmorphism on the service cards specifically — sits on the
   .tone-deep gradient behind #services, so the blur has something to frost */
#services .card {
  background: rgba(242, 240, 235, 0.08);
  backdrop-filter: blur(18px) saturate(150%);
  -webkit-backdrop-filter: blur(18px) saturate(150%);
}

/* on light/cream hosts, cards invert to dark text + lighter glass so they still read as "clean plastic" cards */
.tone-light .card,
.tone-base .card {
  background: rgba(19, 16, 24, 0.03);
  border-color: var(--line);
}
.tone-light .card h3,
.tone-base .card h3 { color: var(--black); }
.tone-light .card p,
.tone-base .card p { color: rgba(19, 16, 24, 0.68); }
.tone-light .card .underline,
.tone-base .card .underline { background: var(--line); }

/* ---------- panels — flat, bordered glass treatment; works on light or dark host sections ---------- */
.glass {
  background: rgba(19, 16, 24, 0.035);
  border: 1px solid var(--line);
  border-radius: 2px;
  padding: 2.4rem 2.2rem;
}
.tone-quote .glass,
.tone-black .glass,
.tone-deep .glass {
  background: rgba(242, 240, 235, 0.06);
  border: 1px solid var(--line-on-dark);
}

/* ---------- testimonial / social proof — vertical accent bar, display headline, script attribution ---------- */
.quote {
  position: relative;
  z-index: 1;
  padding-left: 2.4rem;
  border-left: 3px solid var(--violet);
}
.quote .quote-mark {
  position: absolute;
  top: -0.18em;
  left: -0.1em;
  font-family: 'League Spartan', sans-serif;
  font-size: clamp(10rem, 20vw, 18rem);
  line-height: 1;
  color: var(--violet);
  opacity: 0.12;
  display: block;
  pointer-events: none;
  user-select: none;
  z-index: 0;
}
.quote h3 {
  position: relative;
  z-index: 1;
  font-size: var(--text-h3-quote);
  max-width: 32ch;
  color: var(--cream);
}
.quote p {
  position: relative;
  z-index: 1;
  margin-top: 1rem;
  font-weight: 300;
  color: rgba(242, 240, 235, 0.82);
  font-size: inherit;
  max-width: 72ch;
}
.quote cite {
  position: relative;
  z-index: 1;
  display: block;
  margin-top: 1.3rem;
  font-family: 'Permanent Marker', cursive;
  font-weight: 600;
  font-size: 1.3rem;
  color: var(--violet);
}

/* ---------- quote v2 — tilted "sticky note" card floating on the dark gradient ---------- */
.quote-card {
  position: relative;
  z-index: 1;
  max-width: 46rem;
  margin: 0 auto;
  background: var(--cream);
  color: var(--black);
  padding: 3rem 3.2rem 2.6rem;
  border-radius: 3px;
  border-left: none;
  box-shadow: 14px 14px 0 0 var(--violet);
  transform: rotate(-1.1deg);
}
.quote-card.alt {
  transform: rotate(1deg);
  box-shadow: 14px 14px 0 0 var(--hotpink);
}
.quote-card .quote-doodle {
  position: absolute;
  top: -3.6rem;
  left: -1.2rem;
  color: var(--violet);
  transform: rotate(-6deg);
  z-index: 2;
  pointer-events: none;
}
@media (max-width: 640px) { .quote-card .quote-doodle { display: none; } }
.quote-card .quote-tag {
  display: inline-block;
  background: var(--black);
  color: var(--cream);
  font-family: 'League Spartan', sans-serif;
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  padding: 0.4rem 0.95rem;
  border-radius: 2px;
  margin-bottom: 1.5rem;
}
.quote-card .quote-mark {
  position: absolute;
  top: -1.4rem;
  right: 1.8rem;
  font-family: 'League Spartan', sans-serif;
  font-size: 5.5rem;
  line-height: 1;
  color: var(--violet);
  opacity: 1;
  z-index: 2;
  pointer-events: none;
  display: block;
}
.quote-card h3 {
  position: relative;
  z-index: 1;
  max-width: 28ch;
  color: var(--black);
  font-size: var(--text-h3-testimonial);
}
.quote-card p {
  position: relative;
  z-index: 1;
  margin-top: 1rem;
  font-weight: 300;
  color: rgba(19, 16, 24, 0.74);
  font-size: inherit;
  max-width: 60ch;
}
.quote-card cite {
  position: relative;
  z-index: 1;
  display: block;
  margin-top: 1.3rem;
  font-family: 'Permanent Marker', cursive;
  font-weight: 600;
  font-size: 1.4rem;
  color: var(--violet);
}
@media (max-width: 640px) {
  .quote-card { padding: 2.4rem 1.8rem; transform: rotate(0); }
}

/* ---------- testimonial slider (initQuoteSlider) — default state is a
   plain stacked list of quote-cards, fully readable with no JS at all.
   Only once JS confirms GSAP/ScrollTrigger loaded and motion is allowed
   does it add .is-active and switch to the crossfade slider mechanic,
   same proven pattern as services.html's steps-slider. ---------- */
.quote-slide { margin-bottom: 2.6rem; }
.quote-slide:last-child { margin-bottom: 0; }
.quote-ui { display: none; }

/* Grid stacking (all slides share grid-area 1/1) instead of a JS-measured
   fixed pixel height on the track: the row auto-sizes to the tallest slide
   on every layout pass — window resize, zoom, external-monitor moves,
   late-loading webfonts — so a stale height can never clip a card's text
   at any viewport width. See initQuoteSlider in animations.js for the full
   reasoning; this replaces what used to be `track.style.height` + slides
   at `position: absolute; inset: 0`. */
.quote-slider.is-active .quote-track {
  display: grid;
  overflow: visible;
}
.quote-slider.is-active .quote-slide {
  grid-area: 1 / 1;
  margin-bottom: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  /* without min-width:0 the flex item refuses to shrink below the card's
     min-content, so on a 375px screen the card measured wider than the track and
     hung over both edges — straight into the slide's own clip-path */
  min-width: 0;
  will-change: clip-path;
}
.quote-slider.is-active .quote-slide > .quote-card {
  width: 100%;
  min-width: 0;
}
.quote-slider.is-active .quote-ui {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 1.5rem;
  margin-top: 2.2rem;
}
.quote-progress { display: flex; flex-direction: column; align-items: center; gap: 0.6rem; }
.quote-count {
  font-family: 'League Spartan', sans-serif;
  font-weight: 700;
  font-size: 0.95rem;
  letter-spacing: 0.06em;
}
.quote-of { opacity: 0.4; }
.quote-bar-wrap {
  width: 160px;
  height: 3px;
  background: rgba(242, 240, 235, 0.2);
  overflow: hidden;
}
.quote-bar-fill {
  height: 100%;
  width: 25%;
  background: currentColor;
  transform-origin: left center;
}
.quote-nav {
  background: none;
  border: 1.5px solid currentColor;
  width: 2.4rem;
  height: 2.4rem;
  border-radius: 50%;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background 0.2s, color 0.2s, transform 0.2s;
  flex-shrink: 0;
}
.quote-nav:hover { background: var(--cream); color: var(--black); transform: scale(1.08); }

/* ---------- numbered process steps ---------- */
.steps {
  margin-top: 3rem;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 1.6rem;
}
@media (max-width: 980px) { .steps { grid-template-columns: 1fr 1fr; } }
@media (max-width: 600px) { .steps { grid-template-columns: 1fr; } }
.step {
  position: relative;
  overflow: hidden;
  background: rgba(242, 240, 235, 0.04);
  border: 1px solid var(--line-on-dark);
  border-top: 3px solid transparent;
  border-image: linear-gradient(90deg, var(--violet), var(--accent, var(--magenta))) 1;
  padding: 2.2rem 2rem;
}
.step::after {
  content: attr(data-step);
  position: absolute;
  bottom: -0.18em;
  right: 0.15em;
  font-family: 'League Spartan', sans-serif;
  font-weight: 800;
  font-size: 8.5rem;
  line-height: 1;
  color: var(--accent, var(--magenta));
  opacity: 0.14;
  pointer-events: none;
  z-index: 0;
  user-select: none;
}
.step > * { position: relative; z-index: 1; }
.step .num {
  font-family: 'League Spartan', sans-serif;
  font-weight: 700;
  font-size: 2.2rem;
  letter-spacing: 0.04em;
  line-height: 1;
  color: var(--accent, var(--magenta));
  margin-bottom: 0.4rem;
}
.step h3 { margin-top: 0.7rem; font-size: var(--text-h3-step); color: var(--cream); }
.step p { margin-top: 0.6rem; font-size: inherit; font-weight: 300; color: rgba(242, 240, 235, 0.74); }

/* steps on a light host invert back to dark text */
.tone-light .step,
.tone-base .step {
  background: rgba(19, 16, 24, 0.03);
  border-color: var(--line);
}
.tone-light .step h3,
.tone-base .step h3 { color: var(--black); }
.tone-light .step p,
.tone-base .step p { color: rgba(19, 16, 24, 0.68); }

/* ---------- how-it-works — connected step path (replaces the one-at-a-time
   slider on the homepage: all 4 steps sit side by side so the sequence reads
   at a glance instead of needing clicks to discover there even are 4 steps).
   Still uses the shared .step/.glass/.accent-* card look for consistency with
   the slider version still used on services.html. ---------- */
.steps-path {
  position: relative;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 1.8rem;
  margin-top: 3.5rem;
}
@media (max-width: 980px) {
  .steps-path { grid-template-columns: 1fr 1fr; gap: 2.4rem 1.8rem; }
}
@media (max-width: 640px) {
  .steps-path { grid-template-columns: 1fr; gap: 2.6rem; }
}
/* dotted path threading through the row of markers — lives on the parent
   (not the cards) so it isn't clipped by each card's own overflow:hidden;
   sits behind the cards (z-index 0) so it only shows through the gaps,
   reading as one connected line linking marker 01 → 02 → 03 → 04. Only
   makes sense as a straight line across the full 4-up desktop row. */
@media (min-width: 981px) {
  .steps-path::before {
    content: '';
    position: absolute;
    top: 2.9rem;
    left: 0;
    right: 0;
    height: 2px;
    background: repeating-linear-gradient(90deg, var(--line-dark) 0 10px, transparent 10px 18px);
    z-index: 0;
  }
  .tone-deep .steps-path::before,
  .tone-black .steps-path::before {
    background: repeating-linear-gradient(90deg, var(--line-on-dark) 0 10px, transparent 10px 18px);
  }
}
/* padding-top has to clear the absolutely-positioned marker completely:
   marker top (1.6rem) + marker height (2.6rem) = 4.2rem, plus breathing room.
   At 3.3rem the marker's lower third sat on top of the step's <h3>. */
.step-node {
  position: relative;
  z-index: 1;
  padding-top: 5.2rem;
  transition: transform 0.35s cubic-bezier(.2,.8,.2,1), box-shadow 0.35s ease;
}
.step-node:hover {
  transform: translateY(-5px);
  box-shadow: 8px 10px 0 0 var(--accent, var(--violet));
}
.step-node-marker {
  position: absolute;
  top: 1.6rem;
  left: 2rem;
  z-index: 2;
  width: 2.6rem;
  height: 2.6rem;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: 'League Spartan', sans-serif;
  font-weight: 800;
  font-size: 0.95rem;
  letter-spacing: 0.02em;
  background: var(--accent, var(--magenta));
  /* the accent's own paired ink, not a flat black — violet and magenta
     markers were failing contrast with black numerals */
  color: var(--accent-ink, var(--black));
  box-shadow: 0 3px 10px rgba(19, 16, 24, 0.28);
}

/* ---------- stats — count-up numbers on scroll (initCounters) ---------- */
/* flex, not grid: justify-content:center means an incomplete last row (e.g.
   5 items at 3-per-row leaves 2 on their own) centers itself automatically,
   instead of sitting left-aligned with dead space to the right like grid's
   default item placement would. */
.stats-grid {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 2.4rem 1.6rem;
}
.stat {
  flex: 0 1 calc(33.333% - 1.0667rem);
  min-width: 0;
  text-align: center;
  padding: 2.2rem 1.2rem;
  border-top: 3px solid var(--accent, var(--violet));
}
@media (max-width: 720px) { .stat { flex-basis: calc(50% - 0.8rem); } }
@media (max-width: 420px) { .stat { flex-basis: 100%; } }
.capitals-footnote {
  margin: 2.6rem auto 0;
  max-width: 46ch;
  text-align: center;
  font-size: 0.85rem;
  font-style: italic;
  color: rgba(19, 16, 24, 0.55);
}

/* ---------- capital icons (initCapitalIcons) — each grows/fills on scroll,
   default CSS state below is the *finished* look so reduced-motion users
   just see the completed icon with no animation. ---------- */
.capital-icon {
  width: 4.2rem;
  height: 4.2rem;
  margin: 0 auto 1.1rem;
  color: var(--accent, var(--violet));
}
.capital-icon svg { width: 100%; height: 100%; overflow: visible; }

.icon-dollar-main, .icon-dollar-echo {
  font-family: 'League Spartan', sans-serif;
  font-weight: 800;
  fill: currentColor;
}
.icon-dollar-main { font-size: 30px; }
.icon-dollar-echo { font-size: 16px; opacity: 0.55; }

.icon-heart-outline {
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  opacity: 0.35;
}
.icon-heart-fill { fill: currentColor; }

.icon-pot-rim, .icon-pot-body {
  fill: none;
  stroke: currentColor;
  stroke-width: 2.5;
  stroke-linejoin: round;
}
.icon-paint-fill { fill: currentColor; }

.icon-book-spine {
  stroke: currentColor;
  stroke-width: 2.5;
}
.icon-page-left, .icon-page-right {
  fill: currentColor;
  fill-opacity: 0.8;
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linejoin: round;
}

.icon-stem {
  stroke: currentColor;
  stroke-width: 3;
  stroke-linecap: round;
}
.icon-petal, .icon-flower-center { fill: currentColor; }
.icon-flower-center { opacity: 0.85; }
.stat-num {
  font-family: 'League Spartan', sans-serif;
  font-weight: 800;
  font-size: clamp(2.6rem, 5vw, 3.6rem);
  line-height: 1;
  color: var(--black);
}
.stat-suffix {
  font-size: 0.5em;
  margin-left: 0.15em;
  text-transform: uppercase;
  color: var(--accent, var(--violet));
}
.stat-label {
  margin-top: 0.9rem;
  font-size: 0.78rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  font-weight: 600;
  color: rgba(19, 16, 24, 0.6);
}

/* ---------- value statements grid ---------- */
.values-grid {
  margin-top: 3rem;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1.4rem;
}
/* 4-item variant (e.g. a named, sequential 4-part series) — same responsive
   collapse as the 3-up base (2-up at 980px, 1-up at 640px), just a wider
   base row. Reuses the .values-grid/.value/.accent-* card system as-is. */
.values-grid.cols-4 { grid-template-columns: repeat(4, 1fr); }
/* .cols-4 repeated in each query below to match its higher (two-class)
   specificity above — otherwise the narrower breakpoints below would lose
   to the more specific .cols-4 rule and never collapse it. */
@media (max-width: 980px) {
  .values-grid, .values-grid.cols-4 { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 640px) {
  .values-grid, .values-grid.cols-4 { grid-template-columns: 1fr; }
}
.value,
.value-prop,
.offer-card {
  border-top: 3px solid var(--accent, var(--violet));
}
.value h3 {
  display: inline-block;
  font-size: var(--text-h3-grid-item);
  letter-spacing: 0.04em;
  padding: 0.22em 0.5em;
  margin-bottom: 0.3rem;
  background: var(--accent, var(--violet));
  color: var(--accent-ink, var(--cream));
  clip-path: polygon(0% 4%, 100% 14%, 99% 96%, 1% 88%);
}
.value p { margin-top: 0.6rem; font-size: inherit; font-weight: 300; color: rgba(19, 16, 24, 0.68); }

/* ---------- checklists (step-in invitation) ---------- */
.checklist { margin-top: 1.6rem; list-style: none; }
.checklist li {
  position: relative;
  padding-left: 2rem;
  font-size: inherit;
  font-weight: 300;
  color: rgba(19, 16, 24, 0.78);
}
.checklist li + li { margin-top: 0.85rem; }
.checklist li::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0.5em;
  width: 0.85rem;
  height: 0.85rem;
  background: var(--violet);
}

/* pull-quote variant — every item carries the Permanent Marker script
   treatment, including the closing line. Two deliberate departures from
   the shared .script rule: the -2.5deg tilt is neutralised (charming on a
   single scrawled line, but five stacked lines all leaning the same way read
   as a broken layout, not a handwritten aside), and the leading is opened up
   because Permanent Marker's tall ascenders collide at the default 1.4. */
.checklist-script li { color: var(--black); }
.checklist-script li + li { margin-top: 1.25rem; }
.checklist-script li .script {
  display: block;
  transform: none;
  color: var(--violet);
  font-size: 1.08rem;
  line-height: 1.6;
}
@media (max-width: 640px) {
  .checklist-script li .script { font-size: 1rem; }
}

/* ---------- offer breakdown — solid pink/magenta button variant lives here ---------- */
.offer-card {
  position: relative;
  display: flex;
  flex-direction: column;
  height: 100%;
  overflow: hidden;
  background: rgba(242, 240, 235, 0.04);
  border: 1px solid var(--line-on-dark);
  border-top: 3px solid transparent;
  border-image: linear-gradient(90deg, var(--violet), var(--accent, var(--magenta))) 1;
  padding: 2.4rem 2rem;
}
.offer-card .offer-name {
  font-family: 'League Spartan', sans-serif;
  font-weight: 700;
  font-size: 1.05rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--accent, var(--violet));
}
.offer-card h3 { margin-top: 0.5rem; font-size: var(--text-h3-card); color: var(--cream); }
.offer-card p { position: relative; z-index: 1; margin-top: 0.9rem; font-size: inherit; font-weight: 300; color: rgba(242, 240, 235, 0.74); }
.offer-card .deliverables { margin-top: 1.2rem; list-style: none; }
.offer-card .deliverables li {
  position: relative;
  padding-left: 1.4rem;
  font-size: 0.92rem;
  font-weight: 300;
  color: rgba(242, 240, 235, 0.66);
}
.offer-card .deliverables li + li { margin-top: 0.5rem; }
.offer-card .deliverables li::before {
  content: '—';
  position: absolute;
  left: 0;
  color: var(--accent, var(--violet));
}
.offer-card .price {
  position: relative;
  z-index: 1;
  margin-top: 1.4rem;
  font-family: 'Permanent Marker', cursive;
  font-weight: 600;
  font-size: 1.3rem;
  color: var(--cream);
}
.offer-card .btn {
  position: relative;
  z-index: 1;
  margin-top: 1.4rem;
  align-self: flex-start;
  background: var(--accent, var(--magenta));
  color: var(--black);
  box-shadow: 6px 6px 0 0 rgba(19, 16, 24, 0.25);
}
.offer-card .btn::before { background: var(--black); }
.offer-card .btn:hover { color: var(--cream); }

/* offer-card divider — same drawn-in underline .card already has, added here
   so initDrawIn('.offer-card .underline') can reuse the identical mechanic;
   sits between price and button, doesn't compete with the deliverables list */
.offer-card .underline {
  margin-top: 1.2rem;
  height: 2px;
  width: 100%;
  background: var(--line-on-dark);
  position: relative;
  overflow: hidden;
}
.offer-card .underline::after {
  content: '';
  position: absolute;
  inset: 0;
  background: var(--accent, var(--violet));
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.5s cubic-bezier(.2,.8,.2,1);
}
.offer-card:hover .underline::after { transform: scaleX(1); }

/* ---------- value props ---------- */
.value-prop {
  position: relative;
  overflow: hidden;
}
.value-prop h3 { font-size: var(--text-h3-grid-item); color: var(--black); }
.value-prop p { position: relative; z-index: 1; margin-top: 0.6rem; font-size: inherit; font-weight: 300; color: rgba(19, 16, 24, 0.68); }
.value-prop h3 { position: relative; z-index: 1; }
.value-prop .num,
.value .num {
  display: inline-block;
  font-family: 'League Spartan', sans-serif;
  font-weight: 700;
  font-size: 1rem;
  letter-spacing: 0.04em;
  padding: 0.18em 0.5em;
  background: var(--accent, var(--violet));
  color: var(--accent-ink, var(--cream));
}
/* labelled part number sits above the .value h3, so give it its own
   bottom margin (the h3 already carries margin-bottom via .value p's
   margin-top spacing) — reused badge look, new-to-.value spacing only */
.value .num { margin-bottom: 0.5rem; }

/* ---------- about ---------- */
.about {
  background: var(--cream);
  color: var(--black);
}
.about-grid {
  margin-top: 3rem;
  display: grid;
  grid-template-columns: 1fr 1.15fr;
  gap: 4rem;
  align-items: start;
}
@media (max-width: 880px) {
  .about-grid { grid-template-columns: 1fr; gap: 2rem; }
}
.about .kicker { color: var(--violet); }
.about h2 { color: var(--black); }

/* image placeholder — obviously a stand-in, not a broken image, for spots
   the redesign spec calls for a real commissioned photo that doesn't exist
   yet. Swap the whole element for a real <img> once the photo is shot. */
.image-placeholder {
  margin-top: 2.2rem;
  border: 1.5px dashed var(--line);
  border-radius: 2px;
  background: rgba(19, 16, 24, 0.025);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  gap: 0.9rem;
  padding: 2rem;
  color: rgba(19, 16, 24, 0.4);
}
.image-placeholder-portrait { aspect-ratio: 4 / 5; max-width: 320px; }
.image-placeholder-icon { width: 2.2rem; height: 2.2rem; opacity: 0.6; }
.image-placeholder-label {
  font-family: 'Montserrat', sans-serif;
  font-size: 0.78rem;
  font-weight: 500;
  line-height: 1.5;
  letter-spacing: 0.01em;
  max-width: 24ch;
}

/* full-bleed placeholder variant — previews the eventual real-photo
   composition (dark scrim, centered light text) rather than a boxed
   stand-in, for sections the redesign spec wants full-bleed from day one */
.whyyou-fullbleed {
  position: relative;
  min-height: 85vh;
  display: flex;
  align-items: center;
}
.image-placeholder-bleed {
  position: absolute;
  inset: 0;
  z-index: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: linear-gradient(160deg, rgba(85, 51, 255, 0.1) 0%, rgba(19, 16, 24, 0.05) 60%);
}
.image-placeholder-bleed .image-placeholder-icon {
  width: 3.5rem;
  height: 3.5rem;
  opacity: 0.18;
  color: var(--black);
}
.whyyou-scrim {
  position: absolute;
  inset: 0;
  z-index: 1;
  background: rgba(19, 16, 24, 0.6);
}
.image-placeholder-tag {
  position: absolute;
  top: 6.5rem;
  left: 50%;
  transform: translateX(-50%);
  z-index: 2;
  font-family: 'Montserrat', sans-serif;
  font-size: 0.68rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  background: rgba(19, 16, 24, 0.7);
  color: var(--cream);
  padding: 0.4em 0.9em;
  border: 1px dashed rgba(242, 240, 235, 0.4);
  border-radius: 2px;
  white-space: nowrap;
}
.whyyou-fullbleed .wrap { position: relative; z-index: 3; }
.whyyou-text-centered {
  max-width: 640px;
  margin: 0 auto;
  text-align: center;
}
.whyyou-text-centered .kicker { text-align: center; color: var(--sky); }
.whyyou-text-centered h2 { color: var(--cream); }
.whyyou-text-centered .about-bio p { color: rgba(242, 240, 235, 0.85); }
.whyyou-text-centered .about-bio .btn { margin-left: auto; margin-right: auto; }
@media (max-width: 640px) {
  .image-placeholder-tag { font-size: 0.6rem; padding: 0.35em 0.7em; }
}

/* WHY YOU — real photo split layout (replaces the placeholder full-bleed
   above now that a real team photo exists); text and portrait side by side,
   collage tag/shadow mirrored from the problem/weapon photo treatment so it
   reads as part of the same family rather than a one-off component */
.whyyou-grid {
  display: grid;
  grid-template-columns: 1.05fr 0.95fr;
  gap: clamp(2.5rem, 5vw, 5rem);
  align-items: center;
}
/* mirrored variant — photo first / text second, so alternating two-up bios
   (e.g. About's team section) read as deliberately alternating rather than
   the same layout twice in a row */
.whyyou-grid.is-reverse { grid-template-columns: 0.95fr 1.05fr; }
@media (max-width: 880px) {
  .whyyou-grid { grid-template-columns: 1fr; gap: 2.5rem; }
  .whyyou-grid.is-reverse { grid-template-columns: 1fr; }
  .whyyou-photo { width: 100%; max-width: 420px; margin: 0 auto; }
}
.whyyou-photo { position: relative; }
.whyyou-photo img {
  width: 100%;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  object-position: center 25%;
  display: block;
  border-radius: 2px;
  filter: contrast(1.05) saturate(1.04);
  box-shadow: calc(-1 * var(--collage-offset)) var(--collage-offset) 0 0 var(--violet);
  transform: rotate(calc(-1 * var(--collage-tilt)));
}
.whyyou-photo .photo-tag {
  position: absolute;
  bottom: 1.3rem;
  right: -0.7rem;
  z-index: 2;
  font-family: 'League Spartan', sans-serif;
  font-weight: 800;
  text-transform: uppercase;
  font-size: 1.05rem;
  letter-spacing: 0.04em;
  color: var(--cream);
  background: var(--violet);
  padding: 0.3em 0.75em;
  clip-path: polygon(0% 6%, 100% 0%, 98% 94%, 2% 100%);
  transform: rotate(var(--collage-tilt));
}
.about-bio p {
  font-size: inherit;
  font-weight: 300;
  color: rgba(19, 16, 24, 0.78);
}
.about-bio p + p { margin-top: 1.3rem; }
.about-bio strong { color: var(--black); font-weight: 600; }
.about-bio .accent {
  font-family: 'Permanent Marker', cursive;
  font-weight: 600;
  font-size: 1.08em;
  color: var(--magenta);
}
.about .btn { background: var(--black); color: var(--cream); box-shadow: 6px 6px 0 0 var(--violet); }
.about .btn::before { background: var(--violet); }
.about .btn:hover {
  background: var(--violet);
  box-shadow: 3px 3px 0 0 var(--black);
  color: var(--cream);
}

/* ---------- FAQ ---------- */
.faq { margin-top: 2.6rem; }
.faq-item {
  position: relative;
  padding: 1.6rem 0;
}
.faq-item:last-child { border-bottom: 1px solid var(--line); }
/* dedicated draw-in bar for initDrawIn — a real, content-free element so
   GSAP's scaleX tween never compresses the question/answer text the way
   scaling .faq-item itself would */
.faq-item-line {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 1px;
  background: var(--line);
  transform-origin: left center;
}
.faq-item h3 {
  font-family: 'Montserrat', sans-serif;
  text-transform: none;
  font-size: var(--text-h3-faq);
  font-weight: 600;
  color: var(--black);
}
.faq-item p {
  margin-top: 0.7rem;
  font-size: inherit;
  font-weight: 300;
  color: rgba(19, 16, 24, 0.68);
  max-width: 70ch;
}

/* ---------- forms (contact, sign-up) ---------- */
.form { margin-top: 2.4rem; }
.form-row { margin-bottom: 1.3rem; }
.form-row label {
  display: block;
  font-size: inherit;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  font-weight: 600;
  color: var(--violet);
  margin-bottom: 0.5rem;
}
.form-row input,
.form-row textarea {
  width: 100%;
  background: rgba(19, 16, 24, 0.03);
  border: 1px solid var(--line);
  border-radius: 2px;
  padding: 0.9rem 1.1rem;
  font-family: 'Montserrat', sans-serif;
  font-size: inherit;
  font-weight: 300;
  color: var(--black);
  transition: border-color 0.3s ease, background 0.3s ease;
}
.form-row input::placeholder,
.form-row textarea::placeholder { color: rgba(19, 16, 24, 0.4); }
.form-row input:focus,
.form-row textarea:focus {
  outline: none;
  border-color: var(--teal); /* grounding — a stable, trustworthy tone for a vulnerable moment */
  background: rgba(19, 16, 24, 0.05);
}
.form-row textarea { resize: vertical; min-height: 130px; }
.form-note { margin-top: 1rem; font-size: 0.85rem; font-weight: 300; color: rgba(19, 16, 24, 0.5); }

/* forms on a dark jewel host */
.tone-deep .form-row label { color: var(--magenta); }
.tone-deep .form-row input,
.tone-deep .form-row textarea {
  background: rgba(242, 240, 235, 0.06);
  border-color: var(--line-on-dark);
  color: var(--cream);
}
.tone-deep .form-row input::placeholder,
.tone-deep .form-row textarea::placeholder { color: rgba(242, 240, 235, 0.45); }
.tone-deep .form-note { color: rgba(242, 240, 235, 0.55); }

/* ---------- the deets ---------- */
.deets-grid {
  margin-top: 2.4rem;
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 1.4rem;
}
@media (max-width: 640px) { .deets-grid { grid-template-columns: 1fr; } }
.deet .label {
  font-size: inherit;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  font-weight: 600;
  color: var(--violet);
}
.deet p { margin-top: 0.5rem; font-size: inherit; font-weight: 300; color: var(--black); }

/* ---------- CTA ---------- */
.cta {
  text-align: center;
  padding: clamp(6rem, 16vh, 11rem) 0;
}
.cta h2 {
  font-size: var(--text-h2-lg);
  max-width: 18ch;
  margin: 0 auto;
}
.cta p {
  margin-top: 1.4rem;
  font-weight: 300;
  color: rgba(19, 16, 24, 0.68);
  max-width: 52ch;
  margin-left: auto;
  margin-right: auto;
}
.tone-quote .cta p,
.tone-black .cta p,
.tone-deep .cta p { color: rgba(242, 240, 235, 0.78); }
.btn-row {
  display: flex;
  justify-content: center;
  gap: 1rem;
  flex-wrap: wrap;
}
.btn-ghost {
  background: transparent !important;
  color: var(--black) !important;
  border: 1px solid rgba(19, 16, 24, 0.3);
  box-shadow: none !important;
}
.tone-quote .btn-ghost,
.tone-black .btn-ghost,
.tone-deep .btn-ghost,
.hero .btn-ghost,
.page-hero .btn-ghost {
  color: var(--cream) !important;
  border: 1px solid rgba(242, 240, 235, 0.35);
}
.btn-ghost::before { display: none; }
.btn-ghost:hover { border-color: var(--violet); }

/* ---------- buttons — "clean plastic": solid cream, condensed bold uppercase, dark text, coral offset drop-shadow ---------- */
.btn {
  margin-top: 2.6rem;
  display: inline-flex;
  align-items: center;
  gap: 0.8rem;
  background: var(--cream);
  color: var(--black);
  padding: 1.05rem 2.3rem;
  border-radius: 3px;
  font-family: 'League Spartan', sans-serif;
  font-size: 0.92rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  position: relative;
  overflow: hidden;
  isolation: isolate;
  box-shadow: 6px 6px 0 0 var(--violet);
  transition: transform 0.3s cubic-bezier(.2,.8,.2,1), box-shadow 0.3s ease, color 0.4s ease;
}
.btn:hover {
  transform: translate(2px, -3px);
  background: var(--violet);
  box-shadow: 3px 3px 0 0 var(--cream);
  color: var(--cream);
  filter: drop-shadow(0 0 16px rgba(85, 51, 255, 0.55));
}
.btn::before {
  content: '';
  position: absolute;
  inset: 0;
  background: var(--violet);
  transform: translateX(-101%);
  transition: transform 0.5s cubic-bezier(.2,.8,.2,1);
  z-index: -1;
  opacity: 0;
}
.btn .arrow { transition: transform 0.4s cubic-bezier(.2,.8,.2,1); }
.btn:hover .arrow { transform: translateX(6px); }

/* Hero CTA — colour-picked from the actual old hero screenshot: solid coral button, cream text, soft pink drop-shadow */
.btn-primary {
  background: var(--violet);
  color: var(--cream);
  box-shadow: 6px 6px 0 0 var(--magenta);
}
.btn-primary:hover {
  background: var(--magenta);
  box-shadow: 3px 3px 0 0 var(--violet);
  color: var(--cream);
}

/* on a cream/light section host, the default button inverts to a solid dark/magenta "plastic" chip with cream text */
.tone-light .btn,
.tone-base .btn,
.about .btn {
  background: var(--black);
  color: var(--cream);
  box-shadow: 6px 6px 0 0 var(--violet);
}
.tone-light .btn:hover,
.tone-base .btn:hover {
  background: var(--violet);
  box-shadow: 3px 3px 0 0 var(--black);
  color: var(--cream);
}
.tone-light .btn-primary,
.tone-base .btn-primary {
  background: var(--violet);
  color: var(--cream);
  box-shadow: 6px 6px 0 0 var(--black);
}
.tone-light .btn-primary:hover,
.tone-base .btn-primary:hover {
  background: var(--black);
  box-shadow: 3px 3px 0 0 var(--violet);
  color: var(--cream);
}

/* ---------- email sign-up ---------- */
.signup {
  text-align: center;
}
.signup .form { max-width: 480px; margin: 2rem auto 0; text-align: left; }
.signup .form-row { display: flex; gap: 0.7rem; margin-bottom: 0; }
.signup .form-row input { flex: 1; }
.signup .btn { margin-top: 0; white-space: nowrap; }
.signup .form-note { text-align: center; }
@media (max-width: 560px) {
  .signup .form-row { flex-direction: column; }
  .signup .btn { width: 100%; justify-content: center; }
}

/* ---------- editorial photo blocks / collage imagery with colour-tint overlay ---------- */
.photo-block {
  position: relative;
  overflow: hidden;
  background: var(--plum);
}
.photo-block img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: contrast(1.08) saturate(1.05) brightness(0.96);
}
.photo-block::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(165deg, rgba(85,51,255,0.34), rgba(84,44,123,0.55));
  mix-blend-mode: multiply;
}
.photo-block .cap {
  position: absolute;
  left: 1.4rem;
  bottom: 1.3rem;
  z-index: 2;
  font-family: 'Permanent Marker', cursive;
  font-weight: 600;
  font-size: 1.15rem;
  color: var(--paper);
}

footer {
  position: relative;
  z-index: 2;
  padding: 3rem 6vw 3rem;
  font-size: inherit;
  letter-spacing: 0.04em;
  color: var(--cream);
  background: var(--black);
  display: flex;
  flex-direction: column;
  gap: 1.6rem;
  border-top: 1px solid var(--line-on-dark);
}
.footer-mark {
  font-family: 'League Spartan', sans-serif;
  font-weight: 700;
  font-size: 1.4rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--cream);
}
.footer-nav {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.6rem;
  font-size: 0.82rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
.footer-nav a { opacity: 0.7; transition: opacity 0.3s ease; }
.footer-nav a:hover { opacity: 1; color: var(--magenta); }
.footer-social {
  display: flex;
  gap: 1rem;
  font-size: 0.82rem;
  letter-spacing: 0.06em;
}
.footer-social a { opacity: 0.7; transition: opacity 0.3s ease; }
.footer-social a:hover { opacity: 1; color: var(--magenta); }
.footer-tagline {
  font-family: 'Montserrat', sans-serif;
  text-transform: none;
  font-weight: 300;
  font-size: 0.92rem;
  line-height: 1.6;
  color: rgba(242, 240, 235, 0.7);
  max-width: 62ch;
}
.footer-bottom {
  display: flex;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 0.6rem;
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: rgba(242, 240, 235, 0.45);
  padding-top: 1.6rem;
  border-top: 1px solid var(--line-on-dark);
}
@media (max-width: 640px) { .footer-bottom { flex-direction: column; gap: 0.6rem; } }

/* ---------- lead magnet placeholder (TODO — Blossom to confirm asset) ---------- */
.lead-magnet-todo {
  margin-top: 2.4rem;
  border: 1px dashed rgba(19, 16, 24, 0.3);
  background: rgba(19, 16, 24, 0.03);
  border-radius: 2px;
  padding: 2.2rem 2rem;
  text-align: center;
}
.lead-magnet-todo p {
  font-family: 'Montserrat', sans-serif;
  font-size: 0.95rem;
  font-weight: 500;
  letter-spacing: 0.02em;
  color: rgba(19, 16, 24, 0.5);
}

/* ---------- the shift — photo left / text right ---------- */
.shift-grid {
  display: grid;
  grid-template-columns: 1fr 1.2fr;
  gap: 5rem;
  align-items: center;
}
.shift-photo {
  width: 100%;
  aspect-ratio: 3 / 4;
  overflow: hidden;
  border-radius: 2px;
}
.shift-photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center top;
  display: block;
}
.shift-text {
  text-align: right;
}
.shift-text .prose p { color: rgba(242, 240, 235, 0.78); }
.shift-text .prose strong { color: var(--cream); }
@media (max-width: 880px) {
  .shift-grid { grid-template-columns: 1fr; gap: 2.5rem; }
  .shift-photo { aspect-ratio: 4 / 3; }
  .shift-text { text-align: left; }
}

/* full-bleed variant — image as backdrop, text centered on top, scoped so
   the original split layout (still used elsewhere) is untouched */
.shift-fullbleed {
  position: relative;
  min-height: 90vh;
  display: flex;
  align-items: center;
}
.shift-fullbleed .shift-photo-bleed {
  position: absolute;
  inset: 0;
  z-index: 0;
  aspect-ratio: auto;
  border-radius: 0;
  overflow: hidden;
}
.shift-fullbleed .shift-photo-bleed img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 35%;
}
.shift-scrim {
  position: absolute;
  inset: 0;
  z-index: 1;
  background: linear-gradient(180deg, rgba(19,16,24,0.72) 0%, rgba(19,16,24,0.48) 45%, rgba(19,16,24,0.78) 100%);
}
/* width:100% + min-width:0 are load-bearing, not defensive noise: .shift-fullbleed
   is a flex container, so .wrap is a flex item whose default flex-basis:auto +
   min-width:auto let it grow to its own max-content and refuse to shrink below
   its min-content. The nowrap brush statement inside made that min-content ~460px,
   which pushed the whole text block off the right edge of a 375px screen. */
.shift-fullbleed .wrap { position: relative; z-index: 3; width: 100%; min-width: 0; }
.shift-fullbleed .shift-grid { grid-template-columns: 1fr; min-width: 0; }
.shift-text-centered {
  text-align: center;
  max-width: 640px;
  min-width: 0;
  margin: 0 auto;
}
.shift-text-centered .prose p { color: rgba(242, 240, 235, 0.9); }
.shift-text .accent { color: var(--sky); }

/* ---------- lead magnet — tangible "video training" mockup card (no image asset needed) ---------- */
.lead-magnet-grid {
  display: grid;
  grid-template-columns: 1fr 1.15fr;
  gap: 4.5rem;
  align-items: center;
}
@media (max-width: 880px) {
  .lead-magnet-grid { grid-template-columns: 1fr; gap: 2.5rem; }
}
.lead-magnet-mockup {
  display: block;
  position: relative;
  aspect-ratio: 4 / 3;
  border-radius: 2px;
  overflow: hidden;
  background: var(--jewel-2);
  box-shadow: 14px 14px 0 0 var(--violet);
  transition: transform 0.3s cubic-bezier(.2,.8,.2,1), box-shadow 0.3s ease;
}
.lead-magnet-mockup:hover {
  transform: translate(-4px, -4px);
  box-shadow: 18px 18px 0 0 var(--violet);
}
.video-mock {
  position: relative;
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  padding: 1.7rem 1.9rem;
}
.video-mock-tag {
  align-self: flex-start;
  font-family: 'League Spartan', sans-serif;
  font-weight: 800;
  font-size: 0.72rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--black);
  background: var(--hotpink);
  padding: 0.4em 0.85em;
  clip-path: polygon(0% 6%, 100% 0%, 98% 94%, 2% 100%);
}
.video-mock-play {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 4.2rem;
  height: 4.2rem;
  border-radius: 50%;
  background: rgba(242, 240, 235, 0.14);
  border: 1.5px solid rgba(242, 240, 235, 0.5);
  color: var(--cream);
  display: flex;
  align-items: center;
  justify-content: center;
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  transition: background 0.3s ease, transform 0.3s ease;
}
.video-mock-play svg { margin-left: 2px; }
.lead-magnet-mockup:hover .video-mock-play {
  background: var(--violet);
  transform: translate(-50%, -50%) scale(1.08);
}
.video-mock-title h3 {
  font-size: clamp(1.15rem, 2.4vw, var(--text-h3-card));
  color: var(--cream);
}
.video-mock-title h3 .script { color: var(--violet); }
.video-mock-title p {
  margin-top: 0.4rem;
  font-size: 0.85rem;
  font-weight: 300;
  color: rgba(242, 240, 235, 0.68);
}
.video-mock-scrub {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  margin-top: 1.4rem;
  font-size: 0.7rem;
  font-weight: 300;
  color: rgba(242, 240, 235, 0.55);
}
.video-mock-bar {
  flex: 1;
  height: 4px;
  background: rgba(242, 240, 235, 0.2);
  border-radius: 2px;
  position: relative;
}
.video-mock-bar span {
  position: absolute;
  top: 0; left: 0;
  height: 100%;
  width: 14%;
  background: var(--violet);
  border-radius: 2px;
}
.video-mock-bar span::after {
  content: '';
  position: absolute;
  right: -4px;
  top: 50%;
  transform: translateY(-50%);
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--violet);
}

/* ---------- steps slider ---------- */
.steps-slider { margin-top: 3rem; }
.steps-track {
  position: relative;
  overflow: hidden;
  min-height: 260px;
}
.step-slide {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  will-change: clip-path;
}
.steps-ui {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-top: 1.8rem;
  gap: 1rem;
}
.steps-progress {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.7rem;
}
.steps-count {
  font-family: 'League Spartan', sans-serif;
  font-weight: 700;
  font-size: 1rem;
  letter-spacing: 0.06em;
  color: var(--black);
}
.steps-of { opacity: 0.3; }
.steps-bar-wrap {
  width: 200px;
  height: 4px;
  background: rgba(19, 16, 24, 0.1);
  overflow: hidden;
}
.steps-bar-fill {
  height: 100%;
  width: 25%;
  background: var(--violet);
  transform-origin: left center;
}
.step-nav {
  background: none;
  border: 1.5px solid currentColor;
  width: 2.6rem; height: 2.6rem;
  border-radius: 50%;
  font-size: 1rem;
  cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  transition: background 0.2s, color 0.2s, transform 0.2s;
  color: var(--black);
  flex-shrink: 0;
}
.step-nav:hover {
  background: var(--black);
  color: var(--cream);
  transform: scale(1.08);
}

/* initial hidden state set by JS in initReveals() / initCardStagger() so content stays visible if animations fail */

/* =====================================================================
   BRAND IMAGERY PASS — collage, text-as-weapon, brush, saturated block
   Carries the hero's visual language (grunge found imagery, marker type,
   offset shadows) down through the page instead of stopping at the fold.
   ===================================================================== */

/* Collage system — one shadow throw and one tilt shared by every collaged
   element, so the grit reads as an intentional system rather than one-offs.
   Rule: shadow falls DOWN and OUTWARD (toward the nearer page edge); tags and
   brush accents rotate by a single tilt value. */
:root {
  --collage-offset: 14px;
  --collage-tilt: -4deg;
}

/* brush display — Permanent Marker as a free stand-in for a true painted
   brush face (e.g. Biro Script Plus); used for one gut-punch statement */
.brush {
  font-family: 'Permanent Marker', cursive;
  font-weight: 400;
  text-transform: none;
  letter-spacing: 0.01em;
  line-height: 1.05;
}

/* PROBLEM — the "ick" Barbie beside the copy, with a collage marker tag */
.problem-grid {
  display: grid;
  grid-template-columns: 0.85fr 1.15fr;
  gap: clamp(2rem, 5vw, 4rem);
  align-items: center;
}
@media (max-width: 880px) { .problem-grid { grid-template-columns: 1fr; gap: 2.2rem; } }
.problem-photo { position: relative; }
.problem-photo img {
  width: 100%;
  max-height: 600px;
  object-fit: cover;
  object-position: center top;
  display: block;
  border-radius: 2px;
  filter: contrast(1.06) saturate(1.05);
  box-shadow: var(--collage-offset) var(--collage-offset) 0 0 var(--magenta);
}
.problem-photo .photo-tag {
  position: absolute;
  bottom: 1.3rem;
  left: -0.7rem;
  z-index: 2;
  font-family: 'League Spartan', sans-serif;
  font-weight: 800;
  text-transform: uppercase;
  font-size: 1.15rem;
  letter-spacing: 0.04em;
  color: var(--violet);
  background: var(--magenta);
  padding: 0.3em 0.75em;
  clip-path: polygon(0% 6%, 100% 0%, 98% 94%, 2% 100%);
  transform: rotate(var(--collage-tilt));
}

/* full-bleed variant — image as backdrop, text centered on top, scoped so
   the original split layout (still used elsewhere) is untouched */
.problem-fullbleed {
  position: relative;
  min-height: 90vh;
  display: flex;
  align-items: center;
}
.problem-fullbleed .problem-photo-bleed {
  position: absolute;
  inset: 0;
  z-index: 0;
  aspect-ratio: auto;
  overflow: hidden;
}
.problem-fullbleed .problem-photo-bleed img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 30%;
  border-radius: 0;
  box-shadow: none;
  filter: contrast(1.06) saturate(1.05);
}
.problem-scrim {
  position: absolute;
  inset: 0;
  z-index: 1;
  background: linear-gradient(180deg, rgba(19,16,24,0.72) 0%, rgba(19,16,24,0.48) 45%, rgba(19,16,24,0.78) 100%);
}
/* MOBILE — burnout-barbie.jpg is 1376x768 (16:9). Used as a full-height backdrop
   behind a ~880px-tall section on a 375px phone, object-fit:cover kept only about
   a quarter of its width, so the doll, laptop and mess were unreadable. Below
   880px the photo stops being a backdrop and becomes a 4:3 band at the top of the
   section, masked so it dissolves into the section's own jewel gradient instead
   of ending on a hard edge. Same image, same tone, ~3x more of the scene visible.
   Scoped to #problem rather than .problem-fullbleed because the other pages using
   that class currently hold image placeholders, not real photography. */
@media (max-width: 880px) {
  #problem.problem-fullbleed {
    display: block;
    min-height: 0;
    padding-top: 0;
  }
  #problem.problem-fullbleed .problem-photo-bleed {
    position: relative;
    inset: auto;
    aspect-ratio: 4 / 3;
    margin-bottom: clamp(2.5rem, 9vw, 4rem);
    -webkit-mask-image: linear-gradient(180deg, #000 0%, #000 58%, transparent 99%);
    mask-image: linear-gradient(180deg, #000 0%, #000 58%, transparent 99%);
  }
  #problem.problem-fullbleed .problem-photo-bleed img {
    object-position: 50% 38%;
  }
  /* the full-section scrim would now darken the in-flow photo itself; the mask
     above already carries the blend into the section, so it's not needed here */
  #problem .problem-scrim { display: none; }
}
/* same flex-item guard as .shift-fullbleed .wrap — see the note there */
.problem-fullbleed .wrap { position: relative; z-index: 3; width: 100%; min-width: 0; }
.problem-text-centered {
  text-align: center;
  max-width: 640px;
  min-width: 0;
  margin: 0 auto;
}
.problem-text-centered .kicker { text-align: center; }
.problem-text-centered .prose p { color: rgba(242, 240, 235, 0.9); }
/* match the Shift section's "gut-punch statement" brush size for the Viral
   Hooks callout. Colour is Hot Pink instead of .mark.is-coral's default
   Cream — scoped here rather than on .mark.is-coral itself so the Shift
   section's unrelated is-coral mark keeps its Cream text. */
.problem-text-centered .brush {
  display: block;
  font-size: clamp(1.5rem, 3vw, 2rem);
  margin-bottom: 0.3rem;
  color: var(--hotpink);
}
/* below 720px the 3vw-based curve above no longer tracks the phrase's
   word-wrap points closely enough (checked against real breakpoints:
   375/390/412/428/480/550/650px) — this steeper curve keeps it wrapping
   to 3 lines through that range. Sub-375px devices (rare today) may still
   land on 4 lines; going smaller than this to force 3 there reads as too
   small to be worth it. */
@media (max-width: 720px) {
  .problem-text-centered .brush { font-size: clamp(0.95rem, 4.3vw, 1.5rem); }
}

/* HEADLINE — text as weapon beside a bleeding portrait */
.weapon-grid {
  display: grid;
  grid-template-columns: 1.25fr 0.75fr;
  gap: clamp(1.8rem, 4vw, 3.4rem);
  align-items: center;
}
@media (max-width: 880px) { .weapon-grid { grid-template-columns: 1fr; gap: 2rem; } }
.weapon-grid .headline-statement { text-align: left; max-width: none; margin: 0; }
.weapon-photo img {
  width: 100%;
  max-height: 540px;
  object-fit: cover;
  object-position: center top;
  display: block;
  border-radius: 2px;
  box-shadow: calc(-1 * var(--collage-offset)) var(--collage-offset) 0 0 var(--magenta);
}

/* STATS reframed — the four capitals we actually measure */
.stat-word {
  font-family: 'League Spartan', sans-serif;
  font-weight: 800;
  text-transform: uppercase;
  font-size: clamp(1.4rem, 2.6vw, 2rem);
  line-height: 1.05;
  color: var(--accent, var(--magenta));
  overflow-wrap: break-word;
}

/* THE SHIFT — brush statement */
.shift-text .brush {
  display: block;
  font-size: clamp(1.9rem, 4vw, 3rem);
  color: var(--hotpink);
  margin-bottom: 0.3rem;
}
/* .mark.brush inside .shift-text (the "That 'no' is not a weakness." highlight)
   needs its own override here: a plain display:block box nested inside a <p>
   is invalid HTML that Chromium resolves via its "block-in-inline" anonymous-
   box splitting, and in testing that path doesn't reliably give the box a
   width that matches its own nowrap text at every viewport — at wide widths,
   where the clamp() above is maxed out at 3rem, the text can end up very
   slightly wider than the shrink-fit box the browser computes, so the
   background-size:100% 100% highlighter shape (sized to that box, not the
   text) comes up short right at the last word. width:fit-content forces the
   box to always exactly match the nowrap text's own width, so the highlight
   can never be narrower than the sentence it's covering, at any viewport. */
.shift-text .mark.brush {
  width: fit-content;
  /* was an inline style on the span; moved here so it can be lifted on narrow
     screens, where one unbreakable 460px line is wider than the phone itself */
  white-space: nowrap;
  max-width: 100%;
}
/* Desktop: the fit-content box above was being capped by that max-width:100%.
   Its parent is .shift-text-centered, a fixed 640px measure; once the font-size
   clamp maxes out (3rem, from ~1110px viewport up) this nowrap sentence needs
   ~720px, so max-width:100% clamped the *box* to 640px while its own non-
   wrapping text stayed 720px wide. background-size:100% 100% sizes the
   highlighter shape to the box, not the text, so the swash stopped ~2 words
   short of the sentence — the wider the screen, the more of "weakness." was
   left bare. Let the box grow to its own text and centre it in the measure
   instead. Safe at every desktop width by construction rather than by tuning:
   below the clamp's cap the sentence tracks 4vw, so it stays ~0.58 x viewport
   against a wrap inner width of 0.88 x viewport; above the cap it's frozen at
   ~720px while the wrap is already 1036px or wider. It can never reach a
   viewport edge at any width in this range. */
@media (min-width: 701px) {
  .shift-text .mark.brush {
    max-width: none;
    margin-inline: auto;
  }
}
@media (max-width: 700px) {
  /* let the statement take two lines rather than overflow the viewport. The
     highlighter shape is a background-image on a single block box, so it fills
     the wrapped box as one taller swipe, which still reads as a marker stroke. */
  .shift-text .mark.brush {
    white-space: normal;
    width: auto;
    font-size: clamp(1.5rem, 7.4vw, 1.9rem);
  }
}

/* SIGN-UP — the one full-saturation "colour with conviction" block */
.signup { background: var(--hotpink); color: var(--black); }
.signup .kicker { color: var(--violet); }
.signup h2 { color: var(--black); }
.signup .lede { color: rgba(0, 0, 0, 0.72); }
.signup .form-row input {
  background: rgba(0, 0, 0, 0.06);
  border-color: rgba(0, 0, 0, 0.28);
  color: var(--black);
}
.signup .form-row input::placeholder { color: rgba(0, 0, 0, 0.45); }
.signup .btn {
  background: var(--black);
  color: var(--cream);
  box-shadow: 6px 6px 0 0 var(--violet);
}
.signup .btn::before { background: var(--violet); }
.signup .btn:hover {
  background: var(--violet);
  color: var(--cream);
  box-shadow: 3px 3px 0 0 var(--black);
}
.signup .form-note { color: rgba(0, 0, 0, 0.6); }

/* respect reduced-motion for the drifting hero mesh */
@media (prefers-reduced-motion: reduce) {
  .mesh { animation: none; }
  #cta h2.is-glowing { animation: none; }
}

/* ==========================================================================
   SERVICES — give the glass cards more brand weight via the big numeral
   ========================================================================== */
#services .card .watermark {
  opacity: 0.22;
  font-size: 10rem;
  color: var(--accent, var(--magenta));
}
/* the base .underline bar is var(--line-on-dark) elsewhere — near-invisible
   cream-on-dark, which made initDrawIn's scroll-in draw imperceptible here.
   Scoped to the homepage cards only, in accent colour, so the draw actually
   reads; the hover ::after swipe (full-strength accent) still layers a
   noticeably stronger sweep on top of it. */
#services .card .underline {
  background: var(--accent, var(--violet));
  opacity: 0.5;
}

/* ==========================================================================
   FINAL CTA — subverted Old Master (sacred) answering the fire-Barbie (profane)
   ========================================================================== */
.cta-grid {
  display: grid;
  grid-template-columns: 0.85fr 1.15fr;
  gap: clamp(2rem, 5vw, 4.5rem);
  align-items: center;
  text-align: left;
}
.cta-grid h2 { margin: 0; max-width: 20ch; }
.cta-grid p { margin: 1.4rem 0 0; max-width: 52ch; }
.cta-grid .kicker { text-align: left; }

.cta-art {
  position: relative;
  align-self: stretch;
  min-height: 100%;
}
.cta-art img {
  display: block;
  width: 100%;
  height: 100%;
  max-height: 560px;
  object-fit: cover;
  object-position: center 18%;
  border-radius: 2px;
  filter: grayscale(0.12) contrast(1.05) saturate(0.92);
  box-shadow: var(--collage-offset) var(--collage-offset) 0 0 var(--violet);
}
.cta-art-brush {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  font-family: 'Permanent Marker', cursive;
  font-size: clamp(2.2rem, 6vw, 4rem);
  line-height: 0.92;
  text-transform: uppercase;
  color: var(--magenta);
  transform: rotate(var(--collage-tilt));
  text-shadow: 0 4px 22px rgba(0, 0, 0, 0.55);
  pointer-events: none;
}

/* full-bleed variant — the classical painting as a true backdrop, centered
   text on top, scoped so the original split layout is untouched. Placed
   after .cta-art/.cta-art-brush above so these overrides actually win the
   cascade (same-specificity rules resolve by source order). */
.cta-fullbleed { position: relative; min-height: 92vh; display: flex; align-items: center; }
.cta-art-bleed {
  position: absolute;
  inset: 0;
  z-index: 0;
  min-height: 0;
}
.cta-art-bleed img {
  width: 100%;
  height: 100%;
  max-height: none;
  object-fit: cover;
  object-position: center 30%;
  border-radius: 0;
  box-shadow: none;
  /* small permanent buffer so the boosted parallax drift (data-parallax-strength
     on this element) never reveals an edge */
  transform: scale(1.06);
}
/* no desktop scrim here on purpose — the photo's own blue wash is the whole
   point visually, and a dark overlay on top of it just reads as grey. Text
   contrast is instead handled by weight/size (League Spartan 700/800) plus
   the mobile-only fallback scrim below. */
.cta-scrim {
  position: absolute;
  inset: 0;
  z-index: 1;
}
@media (max-width: 880px) {
  /* on narrow screens the blue zone gets cropped away almost entirely and
     the copy sits directly over the photo, so it still needs a scrim here */
  /* The section is ~92vh tall against a 16:9 photo, so object-fit:cover crops
     purely horizontally here — only the X value does anything, Y is inert. At
     30% the window landed on roughly 21%-50% of the frame, which sliced the
     doll in half down her face and kept mostly empty desk. The subject (doll
     from ~8% to her hand at ~36%, book from ~9%) is almost exactly as wide as
     the visible window, so 12% puts the window at ~9%-37%: her whole face and
     hair, her hand on the page, and the book's left page with the tree. */
  .cta-art-bleed img { object-position: 12% center; }
  .cta-scrim {
    background: linear-gradient(180deg, rgba(19,16,24,0.6) 0%, rgba(19,16,24,0.68) 45%, rgba(19,16,24,0.88) 100%);
  }
}
.cta-fullbleed .wrap { position: relative; z-index: 3; width: 100%; }
.cta-brush-lead {
  display: block;
  font-family: 'Permanent Marker', cursive;
  font-size: clamp(1.3rem, 3vw, 1.9rem);
  color: var(--magenta);
  margin-bottom: 1.1rem;
  text-transform: none;
}
.cta-copy-centered {
  text-align: center;
  max-width: 640px;
  margin: 0 auto;
}
.cta-copy-centered h2 { max-width: none; }
.cta-copy-centered p { max-width: none; margin: 1.4rem auto 0; }
.cta-copy-centered .kicker { text-align: center; }
.cta-copy-centered .btn-row { justify-content: center; margin-top: 2rem; }

/* right-aligned variant — copy sits inside the photo's own blue negative
   space on the right rather than overlaying the subject, e.g. the Barbie
   'ah-ha' moment CTA image. Mirrors the hero's own approach (hero-inner:
   uncapped width, fluid 6vw side padding; hero-copy: a fixed max-width
   sitting tight against that padding) rather than the generic 1180px-capped
   .wrap, so it stays tight to the edge the same way at any window size
   instead of getting stranded mid-image once the viewport out-grows 1180px. */
.cta-fullbleed .wrap {
  max-width: none;
  padding: 0 6vw;
}
.cta-copy-right {
  text-align: right;
  max-width: 560px;
  margin-left: auto;
}
.cta-copy-right h2 { max-width: none; }
.cta-copy-right p { max-width: none; margin: 1.4rem 0 0; }
.cta-copy-right .kicker { text-align: right; color: var(--violet); }
.cta-copy-right .btn-row { justify-content: flex-end; margin-top: 2rem; }

/* left-aligned mirror of .cta-copy-right — same full-bleed CTA system, copy
   sits in the photo's left-hand negative space instead of the right (Contact
   page's "Haven't met us yet?" closer). Stays left on mobile too: the
   mobile scrim already guarantees contrast, and centering short body copy
   under a long headline reads weaker than a clean left edge. */
.cta-copy-left {
  text-align: left;
  max-width: 560px;
  margin-right: auto;
}
.cta-copy-left h2 { max-width: none; margin-left: 0; }
.cta-copy-left p { max-width: none; margin: 1.4rem 0 0; }
.cta-copy-left .kicker { text-align: left; color: var(--violet); }
.cta-copy-left .btn-row { justify-content: flex-start; margin-top: 2rem; }

/* ah-ha glow — a violet text-shadow breathing once the closing headline has
   scrolled in, see initCtaGlow. A white-hot inner layer plus a wide violet
   bloom, so it reads clearly against the busy photo instead of disappearing
   into it. */
#cta h2.is-glowing {
  animation: ctaTextGlow 1.6s ease-in-out infinite alternate;
}
@keyframes ctaTextGlow {
  from { text-shadow: 0 0 0 rgba(85, 51, 255, 0); }
  to   {
    text-shadow:
      0 0 12px rgba(255, 255, 255, 0.55),
      0 0 34px rgba(85, 51, 255, 0.95),
      0 0 70px rgba(85, 51, 255, 0.65);
  }
}
@media (max-width: 880px) {
  .cta-copy-right {
    text-align: center;
    max-width: 560px;
    margin: 0 auto;
  }
  /* Violet works on desktop because the copy sits in the photo's own pale-blue
     negative space. On mobile that zone is cropped away and the kicker lands on
     the darkened photo + scrim, where Violet on near-black fails contrast. Sky
     is the style guide's own kicker colour for dark tones (#cta is .tone-black),
     so this is a return to the system rather than a one-off. */
  .cta-copy-right .kicker { text-align: center; color: var(--sky); }
  .cta-copy-right .btn-row { justify-content: center; }
}

@media (max-width: 880px) {
  .cta-grid { grid-template-columns: 1fr; }
  .cta-art { order: -1; }
  /* :not(.cta-art-bleed) is the fix for the closing CTA on mobile. This rule
     used to be a bare `.cta-art img`, which has the same specificity as the
     `.cta-art-bleed img { max-height: none }` above but comes later in the
     file, so it won the cascade and capped the full-bleed backdrop at 420px.
     The photo then stopped short of the section's 92vh and the copy + button
     rendered below it on flat black instead of on top of the image. */
  .cta-art:not(.cta-art-bleed) img { max-height: 420px; }
}

/* ==========================================================================
   MOVE 5 — one persistent primary action always within reach in the nav
   ========================================================================== */
.btn-header {
  opacity: 1;
  padding: 0.5em 1.1em;
  border-radius: 2px;
  background: var(--magenta);
  color: var(--cream);
  box-shadow: 6px 6px 0 0 var(--violet);
  transition: transform 0.25s ease, box-shadow 0.25s ease, background 0.25s ease;
}
/* nav-scoped so this beats .nav-links a:hover's color:violet on specificity
   (both have 2 class/pseudo-class components, so the extra element-selector
   on ".nav-links a:hover" would otherwise win the tiebreak) */
.nav-links .btn-header:hover,
.btn-header:hover {
  color: var(--cream);
  background: var(--violet);
  transform: translate(-1px, -1px);
  box-shadow: 3px 3px 0 0 var(--magenta);
}

/* ==========================================================================
   MOVE 6 — type as architecture: tighter display tracking + one oversized
   wordmark bleeding off both edges behind the intro
   ========================================================================== */
h1, h2, .display { letter-spacing: -0.015em; }

#intro-about { position: relative; }
#intro-about .wrap-narrow { position: relative; z-index: 1; }
.giant-word {
  position: absolute;
  top: -0.12em;
  left: 50%;
  transform: translateX(-50%);
  z-index: 0;
  font-family: 'League Spartan', sans-serif;
  font-weight: 900;
  font-size: clamp(6rem, 22vw, 19rem);
  line-height: 0.8;
  letter-spacing: -0.045em;
  white-space: nowrap;
  text-transform: uppercase;
  color: transparent;
  -webkit-text-stroke: 1.5px rgba(19, 16, 24, 0.06);
  pointer-events: none;
  user-select: none;
}

/* ==========================================================================
   MOVE 2 — brand signature on the closing Why-You line
   ========================================================================== */
.about .brush.accent {
  color: var(--magenta);
  font-size: 1.08em;
}

/* ---------- five capitals — all 5 in one row once there's genuinely
   enough width; below that a 3/2/1-column stack (defined earlier) reads
   better than cramming these longer two-word labels into tiny columns.
   Placed at end of file so it reliably wins over the earlier .stat-word
   rule regardless of selector specificity. ---------- */
@media (min-width: 1100px) {
  .stats-grid { gap: 1.4rem 0.9rem; }
  .stat { flex-basis: calc(20% - 0.72rem); padding: 1.8rem 0.5rem; }
  .capital-icon { width: 3.3rem; height: 3.3rem; margin-bottom: 0.9rem; }
  .stat-word {
    font-size: clamp(1.05rem, 1.35vw, 1.32rem);
    line-height: 1.1;
  }
  .stat-label {
    font-size: 0.66rem;
    letter-spacing: 0.1em;
  }
}
