/* == /brand.css == */
/* ============================================================================
 * Good Dogz KC — Calendar PWA Brand Foundation
 * Palette + typography from ~/Projects/paper-test/gdkc-design-decisions.md
 * Wave 1-B (feat/ui-calendar) extends this file with the full calendar grid.
 * ============================================================================ */

:root {
  /* Base */
  --bg:          #0A091A;
  --bg-elev-1:  #14122A;
  --bg-elev-2:  #1E1B3C;
  --navy:       #2C2977;

  /* Accents */
  --teal:         #07EDBE;
  --pink:         #FF7EC0;
  --violet:       #9945FF;
  --mid-purple:   #C77DFF;
  --light-purple: #A08CFF;
  --blue:         #477ED6;
  --light-blue:   #A0C7FF;
  --lilac:        #F1E0FF;

  /* Text */
  --text:          #F8F8F8;
  --text-muted:    rgba(248, 248, 248, 0.55);
  --text-body:     rgba(248, 248, 248, 0.65);
  --heading-white: #F0EEFF;
  --gray-purple:   #5A5880;

  /* Surfaces */
  --surface:           var(--bg-elev-1);
  /* Haiti 900 — card fill in the newer sections. Split from --surface (#14122A)
   * is documented in docs/BRAND.md §1; collapsing to one value is Andrew's call. */
  --surface-card:      #16143A;
  --surface-border:    rgba(248, 248, 248, 0.08);
  --surface-border-strong: rgba(248, 248, 248, 0.16);

  /* Radius */
  --radius-sm: 8px;
  --radius-md: 12px;
  --radius-lg: 20px;
  --radius-pill: 500px;

  /* Mesh gradient — buttons/accents (135deg diagonal) */
  --mesh-gradient: linear-gradient(135deg, #A0C7FF 0%, #477ED6 30%, #C77DFF 65%, #9945FF 100%);
  /* Mesh text gradient — Paper Hero A2v4 canonical (90deg, teal→violet→pink→blue) */
  --mesh-text-gradient: linear-gradient(90deg, #07EDBE 0%, #9945FF 33.333%, #FF7EC0 66.667%, #477ED6 100%);
  /* Conic-gradient border for pill CTA buttons on dark surfaces */
  --mesh-conic-border: conic-gradient(from 0deg at 50% 50%, #07EDBE 0%, #9945FF 25%, #FF7EC0 50%, #477ED6 75%, #07EDBE 100%);
  --hero-gradient: linear-gradient(180deg, #9945FF 0%, #2C2977 100%);

  /* Elevation */
  --shadow-lg: 0 20px 60px rgba(0, 0, 0, 0.5);
  --shadow-glow-teal: 0 8px 32px rgba(7, 237, 190, 0.25);
  --shadow-glow-violet: 0 8px 32px rgba(153, 69, 255, 0.25);
}

/* Fonts — self-hosted Cera Round (display) + Nunito (body).
   Both have rounded end caps — that's the GDKC brand feel. No Inter. */
@font-face {
  font-family: 'CeraRound';
  src: url('/assets/fonts/Cera-Round-Black-Web.woff2') format('woff2');
  font-weight: 900;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'CeraRound';
  src: url('/assets/fonts/Cera-Round-Regular-Web.ttf') format('truetype');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Nunito';
  src: url('/assets/fonts/Nunito-Variable-Latin.woff2') format('woff2-variations'),
       url('/assets/fonts/Nunito-Variable-Latin.woff2') format('woff2');
  font-weight: 200 900;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Nunito';
  src: url('/assets/fonts/Nunito-Variable-Latin-Ext.woff2') format('woff2-variations'),
       url('/assets/fonts/Nunito-Variable-Latin-Ext.woff2') format('woff2');
  font-weight: 200 900;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

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

html, body { background: var(--bg); color: var(--text); min-height: 100vh; }
body {
  font-family: 'Nunito', -apple-system, BlinkMacSystemFont, system-ui, sans-serif;
  font-size: 15px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3 {
  font-family: 'CeraRound', 'Nunito', sans-serif;
  font-weight: 900;
  letter-spacing: -0.01em;
}

h1 { font-size: 40px; line-height: 48px; }
h2 { font-size: 28px; line-height: 36px; }
h3 { font-size: 20px; line-height: 26px; }

@media (max-width: 640px) {
  h1 { font-size: 28px; line-height: 36px; }
  h2 { font-size: 22px; line-height: 30px; }
}

.muted { color: var(--text-muted); }

/* Gradient text (used on hero) */
.gradient-text {
  background: var(--mesh-gradient);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  color: transparent;
}

/* Mesh-gradient pill button (primary CTA) */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: 'CeraRound', 'Nunito', sans-serif;
  font-weight: 900;
  font-size: 15px;
  height: 44px;
  padding: 0 24px;
  border-radius: var(--radius-pill);
  border: 4px solid var(--violet);
  background: var(--bg) padding-box,
              var(--mesh-gradient) border-box;
  color: var(--text);
  cursor: pointer;
  text-decoration: none;
  transition: transform 120ms ease, filter 120ms ease, box-shadow 120ms ease;
}
.btn:hover { filter: brightness(1.1); box-shadow: var(--shadow-glow-violet); }
.btn:active { transform: scale(0.98); }
.btn:disabled { opacity: 0.4; pointer-events: none; }

.btn-secondary {
  border-color: var(--surface-border-strong);
  background: var(--bg);
}

/* Big mesh-gradient CTA pill (full-fill interior, used on Confirm) */
.btn-mesh {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  max-width: 320px;
  height: 52px;
  border-radius: var(--radius-pill);
  border: 4px solid var(--teal);
  background: var(--bg);
  padding: 4px;
  cursor: pointer;
  overflow: hidden;
  transition: transform 160ms ease, box-shadow 160ms ease;
  font-family: 'CeraRound', 'Nunito', sans-serif;
  font-weight: 900;
  font-size: 16px;
  color: #fff;
  letter-spacing: 0.3px;
}
.btn-mesh::before {
  content: "";
  position: absolute;
  inset: 4px;
  border-radius: var(--radius-pill);
  background: var(--mesh-gradient);
  z-index: 0;
}
.btn-mesh > span { position: relative; z-index: 1; }
.btn-mesh:hover { transform: translateY(-2px); box-shadow: var(--shadow-glow-teal); }
.btn-mesh:disabled { opacity: 0.4; pointer-events: none; }

/* Card surface */
.card {
  position: relative;
  background: var(--surface);
  border: 1px solid var(--surface-border);
  border-radius: var(--radius-lg);
  padding: 24px;
  overflow: hidden;
}

/* Dot pattern utility */
.dot-pattern {
  position: absolute;
  inset: -24px;
  background-image: radial-gradient(circle, var(--navy) 8px, transparent 8px);
  background-size: 16px 16px;
  opacity: 0.88;
  pointer-events: none;
  z-index: 0;
  mask-image: linear-gradient(180deg, rgba(0,0,0,1) 0%, rgba(0,0,0,0.1) 100%);
  -webkit-mask-image: linear-gradient(180deg, rgba(0,0,0,1) 0%, rgba(0,0,0,0.1) 100%);
}

/* PWA viewport fixes */
@supports (padding: max(0px)) {
  body {
    padding-top: max(env(safe-area-inset-top), 16px);
    padding-bottom: max(env(safe-area-inset-bottom), 16px);
  }
}

/* ============================================================================
 * Page layout + hero
 * ============================================================================ */

.page {
  max-width: 960px;
  margin: 0 auto;
  padding: 48px 24px 140px;
  display: flex;
  flex-direction: column;
  gap: 32px;
}

@media (max-width: 640px) {
  .page { padding: 32px 16px 160px; gap: 24px; }
}

.hero {
  text-align: center;
  max-width: 620px;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.hero h1 { font-size: clamp(28px, 5vw, 44px); line-height: 1.1; }
.hero .hello {
  font-size: 17px;
  color: var(--text-body);
  margin-top: 4px;
}
.hero .progress {
  display: inline-flex;
  align-self: center;
  align-items: center;
  gap: 8px;
  padding: 6px 14px;
  border: 1px solid var(--surface-border-strong);
  border-radius: var(--radius-pill);
  font-size: 13px;
  font-weight: 500;
  color: var(--text-muted);
  margin-top: 4px;
}
.hero .progress::before {
  content: "";
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--teal);
  box-shadow: 0 0 8px var(--teal);
}

/* Hidden attribute helper */
[hidden] { display: none !important; }

/* == /site.css == */
/* ============================================================================
 * GDKC Landing Pages — site base
 * Layers on top of brand.css. Page-specific CSS lives in /public/<page>.css.
 * ============================================================================ */

/* Squiggle pattern lives on the body so it tiles continuously across the
   hero → pain-mirror boundary (and any other dark sections). Individual
   sections layer on top via transparent or solid backgrounds. */
body {
  background-color: var(--bg);
  background-image: url("/assets/squiggle-bg.svg");
  background-repeat: repeat;
  background-size: 480px 480px;
  background-position: 0 0;
}

/* Layout */
.container {
  width: min(100% - 40px, 1200px);
  margin: 0 auto;
}
main {
  display: block;
  padding-block: 0;
}
section {
  padding: clamp(56px, 8vw, 120px) 0;
}

/* --- Top nav --- */
.site-nav {
  position: sticky;
  top: 0;
  z-index: 50;
  background: rgba(10, 9, 26, 0.85);
  backdrop-filter: saturate(150%) blur(12px);
  border-bottom: 1px solid var(--surface-border);
}
.site-nav .container {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  padding: 14px 20px;
}
.site-nav a.brand {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  color: var(--text);
  text-decoration: none;
  font-family: 'CeraRound', 'Nunito', sans-serif;
  font-weight: 900;
  letter-spacing: -0.01em;
  font-size: 18px;
}
.site-nav a.brand img {
  height: 28px;
  width: auto;
}
.site-nav ul.nav-links {
  list-style: none;
  display: flex;
  gap: 24px;
  align-items: center;
}
.site-nav ul.nav-links a {
  color: var(--text-body);
  text-decoration: none;
  font-size: 14px;
  font-weight: 500;
  transition: color 140ms ease;
}
.site-nav ul.nav-links a:hover {
  color: var(--teal);
}
.nav-burger {
  display: none;
  background: transparent;
  border: 0;
  padding: 8px;
  cursor: pointer;
  color: var(--text);
}
.nav-burger svg { display: block; width: 24px; height: 24px; }

@media (max-width: 820px) {
  .site-nav ul.nav-links {
    position: fixed;
    inset: 56px 0 auto 0;
    flex-direction: column;
    gap: 0;
    padding: 12px 20px 20px;
    background: var(--bg-elev-1);
    border-bottom: 1px solid var(--surface-border);
    transform: translateY(-120%);
    transition: transform 220ms ease;
  }
  .site-nav ul.nav-links a {
    display: block;
    padding: 14px 0;
    border-bottom: 1px solid var(--surface-border);
    font-size: 16px;
  }
  .nav-burger { display: inline-flex; }
  body.nav-open .site-nav ul.nav-links {
    transform: translateY(0);
  }
}

/* --- Buttons --- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 14px 24px;
  border-radius: var(--radius-pill);
  font-family: 'CeraRound', 'Nunito', sans-serif;
  font-weight: 900;
  font-size: 15px;
  text-decoration: none;
  cursor: pointer;
  border: 0;
  transition: filter 140ms ease, transform 140ms ease;
  color: #FFFFFF;
}
.btn:hover { filter: brightness(1.08); }
.btn:active { transform: scale(0.98); }

.btn-primary {
  background: var(--mesh-gradient);
  box-shadow: var(--shadow-glow-violet);
}
.btn-secondary {
  background: transparent;
  color: var(--teal);
  border: 1px solid var(--teal);
}
.btn-secondary:hover { background: rgba(7, 237, 190, 0.08); }

/* --- Hero (landing-site base) --- */
.hero {
  padding: clamp(60px, 10vw, 140px) 0 clamp(48px, 8vw, 96px);
  position: relative;
  overflow: hidden;
}
.hero .container {
  display: grid;
  grid-template-columns: 1fr;
  gap: 32px;
  align-items: center;
}
@media (min-width: 920px) {
  .hero .container {
    grid-template-columns: 1.2fr 1fr;
    gap: 64px;
  }
}
.hero h1 {
  font-size: clamp(32px, 5vw, 56px);
  line-height: 1.05;
  letter-spacing: -0.02em;
  margin-bottom: 20px;
}
.hero .lede {
  color: var(--text-body);
  font-size: clamp(16px, 1.6vw, 20px);
  line-height: 1.5;
  max-width: 640px;
  margin-bottom: 28px;
}
.hero-media {
  position: relative;
  aspect-ratio: 16 / 9;
  border-radius: var(--radius-lg);
  overflow: hidden;
  background: var(--bg-elev-1);
  border: 1px solid var(--surface-border);
}
.hero-media .rive-slot,
.hero-media video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.gradient-text {
  background: var(--mesh-gradient);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

/* --- Retired banner (Board & Train redirect) --- */
.retired-banner {
  background: linear-gradient(90deg, var(--violet) 0%, var(--mid-purple) 100%);
  color: #FFFFFF;
  text-align: center;
  padding: 10px 48px 10px 16px;
  font-size: 14px;
  position: relative;
}
.retired-banner a {
  color: #FFFFFF;
  text-decoration: underline;
  font-weight: 600;
}
.retired-banner button {
  position: absolute;
  top: 50%;
  right: 12px;
  transform: translateY(-50%);
  background: transparent;
  border: 0;
  color: #FFFFFF;
  font-size: 20px;
  line-height: 1;
  cursor: pointer;
  padding: 4px 8px;
}

/* --- Contact form --- */
.contact-form {
  background: var(--bg-elev-1);
  border-top: 1px solid var(--surface-border);
  border-bottom: 1px solid var(--surface-border);
}
.contact-form .container {
  max-width: 640px;
}
.contact-form h2 {
  margin-bottom: 24px;
}
.contact-form form {
  display: grid;
  gap: 16px;
}
.contact-form label {
  display: grid;
  gap: 6px;
  color: var(--text-body);
  font-size: 14px;
}
.contact-form input[type="text"],
.contact-form input[type="email"],
.contact-form input[type="tel"],
.contact-form textarea {
  background: var(--bg);
  color: var(--text);
  border: 1px solid var(--surface-border-strong);
  border-radius: var(--radius-md);
  padding: 12px 14px;
  font-family: inherit;
  font-size: 15px;
  transition: border-color 140ms ease, background 140ms ease;
}
.contact-form input:focus,
.contact-form textarea:focus {
  outline: none;
  border-color: var(--teal);
  background: rgba(7, 237, 190, 0.04);
}
.contact-form textarea {
  resize: vertical;
  min-height: 100px;
}
.contact-form label.consent {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  font-size: 13px;
  color: var(--text-muted);
  line-height: 1.4;
}
.contact-form label.consent input {
  margin-top: 2px;
}
.contact-form .hp {
  position: absolute !important;
  left: -9999px !important;
  width: 1px;
  height: 1px;
  overflow: hidden;
  opacity: 0;
  pointer-events: none;
}
.contact-form .form-error {
  margin-top: 8px;
  padding: 10px 14px;
  background: rgba(255, 126, 192, 0.1);
  border: 1px solid var(--pink);
  border-radius: var(--radius-sm);
  color: var(--pink);
  font-size: 14px;
}
.contact-form button[type="submit"] {
  justify-self: start;
  margin-top: 8px;
}

/* --- FAQ accordion --- */
.faq h2 {
  text-align: center;
  margin-bottom: 32px;
}
.faq-list {
  max-width: 760px;
  margin: 0 auto;
  display: grid;
  gap: 12px;
}
.faq details {
  background: var(--bg-elev-1);
  border: 1px solid var(--surface-border);
  border-radius: var(--radius-md);
  padding: 0;
  overflow: hidden;
}
.faq summary {
  list-style: none;
  cursor: pointer;
  padding: 18px 20px;
  font-weight: 600;
  font-size: 16px;
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after {
  content: "";
  width: 10px;
  height: 10px;
  border-right: 2px solid var(--text-muted);
  border-bottom: 2px solid var(--text-muted);
  transform: rotate(45deg);
  transition: transform 180ms ease;
  margin-left: 16px;
  flex-shrink: 0;
}
.faq details[open] summary::after {
  transform: rotate(-135deg);
}
.faq .faq-body {
  padding: 0 20px 18px;
  color: var(--text-body);
  line-height: 1.6;
}

/* --- Service cards --- */
.service-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 20px;
}
.service-card {
  background: var(--bg-elev-1);
  border: 1px solid var(--surface-border);
  border-radius: var(--radius-lg);
  padding: 24px;
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.service-card h3 { color: var(--text); }
.service-card p {
  color: var(--text-body);
  font-size: 14px;
  line-height: 1.55;
  flex: 1;
}
.service-icon {
  width: 56px;
  height: 56px;
  border-radius: 999px;
  background: rgba(7, 237, 190, 0.12);
  display: grid;
  place-items: center;
}
.service-icon img { width: 28px; height: 28px; }
.service-card .btn {
  align-self: flex-start;
}

/* --- Testimonial --- */
.testimonial {
  background: var(--bg-elev-1);
  border: 1px solid var(--surface-border);
  border-radius: var(--radius-lg);
  padding: 28px;
  max-width: 720px;
  margin: 0 auto;
}
.testimonial .stars {
  color: var(--pink);
  font-size: 18px;
  letter-spacing: 2px;
  margin-bottom: 12px;
}
.testimonial p {
  font-size: 17px;
  line-height: 1.55;
  margin-bottom: 14px;
  color: var(--text);
}
.testimonial cite {
  font-style: normal;
  color: var(--text-muted);
  font-size: 14px;
  display: block;
}
.testimonial cite .source {
  margin-left: 8px;
  opacity: 0.7;
}

/* --- Footer --- */
.site-footer {
  background: var(--bg);
  border-top: 1px solid var(--surface-border);
  padding-block: 56px 32px;
  color: var(--text-muted);
}
.site-footer .footer-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 40px;
  margin-bottom: 40px;
}
@media (min-width: 720px) {
  .site-footer .footer-grid {
    grid-template-columns: 2fr 1fr 1fr;
  }
}
.site-footer h4 {
  color: var(--text);
  font-family: 'CeraRound', 'Nunito', sans-serif;
  font-weight: 900;
  font-size: 16px;
  margin-bottom: 14px;
}
.site-footer ul {
  list-style: none;
  display: grid;
  gap: 10px;
}
.site-footer a {
  color: var(--text-body);
  text-decoration: none;
  font-size: 14px;
}
.site-footer a:hover { color: var(--teal); }
.site-footer .socials {
  display: flex;
  gap: 14px;
  margin-top: 12px;
}
.site-footer .legal {
  padding-top: 24px;
  border-top: 1px solid var(--surface-border);
  font-size: 13px;
  color: var(--text-muted);
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  justify-content: space-between;
}

/* == /components/nav-pill/style.css == */
/* ============================================================================
 * NavPill — vanilla port of NavPill.tsx
 * Tokens come from brand.css (--light-purple #A08CFF, --teal #07EDBE, --pink #FF7EC0).
 * Keyframes (shine) live here so they're scoped to nav-pill use.
 *
 * ─────────────────────────────────────────────────────────────────────────────
 *  🔒 LOCKED LAYOUT — sign-off Andrew 2026-06-08. Do NOT change without asking.
 * ─────────────────────────────────────────────────────────────────────────────
 *  Mobile  (<640px)              Desktop (≥640px)
 *  ─────────────                 ────────────────
 *  pill height   96px           124px
 *  logo         86×86px         116×116px
 *  CTA label    "Call now"       "Book a free call"
 *  CTA href     tel:+1…          #consult-embed
 *  container gutter 20px        16px
 *  pill padding  0 18px 0 14px  0 48px 0 28px
 *  CTA inner pad 10px 16px      14px 28px
 *  CTA font/lh   13/16          16/20
 *
 *  RATIONALE: desktop visitors don't tap-to-dial — they research and book.
 *  Desktop CTA scrolls to the booking calendar. Mobile keeps tap-to-dial
 *  because phone-in-hand = call wins. Two separate <a> elements in markup
 *  (`--desktop` + `--mobile`); CSS toggles which one is visible.
 *  Curtain menu (burger-open state) is desktop+mobile shared and still
 *  surfaces the phone number, so desktop users who want it can find it.
 * ─────────────────────────────────────────────────────────────────────────────
 * ============================================================================ */

@keyframes nav-pill-shine {
  0%   { left: -100%; width: 30%; }
  50%  {              width: 30%; }
  100% { left:  100%; width: 10%; }
}

/* ---- Wrapper ---- */
.nav-pill {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 50;
  width: 100%;
  padding-top: 16px;
  pointer-events: none; /* allow click-through on the gutter; children re-enable */
  transition: transform 300ms ease;
}
.nav-pill[data-showcase="true"] {
  position: relative;
  padding-bottom: 16px;
}
.nav-pill__container {
  max-width: 800px;
  margin: 0 auto;
  position: relative;
  padding: 0 16px;
  overflow: visible;
}

/* ---- Pill ---- */
.nav-pill__nav {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: space-between;
  background: #fff;
  border-radius: 9999px;
  min-height: 104px;
  padding: 0 32px 0 20px;
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.12), 0 2px 8px rgba(0, 0, 0, 0.08);
  overflow: visible;
  pointer-events: auto;
}
@media (min-width: 640px) {
  .nav-pill__nav {
    min-height: 124px;
    padding: 0 48px 0 28px;
  }
}

/* ---- Progress ring ---- */
.nav-pill__ring {
  position: absolute;
  top: -16px;
  left: -12px;
  width: calc(100% + 24px);
  height: calc(100% + 32px);
  z-index: -1;
  pointer-events: none;
  opacity: 1;
}
.nav-pill__ring-progress {
  visibility: hidden; /* JS reveals after first measurement */
}

/* ---- Logo (Rive canvas) ---- */
.nav-pill__logo {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 96px;
  height: 96px;
  margin: 0 0 0 -4px;
  position: relative;
  cursor: pointer;
  transition: transform 300ms ease;
  text-decoration: none;
}
.nav-pill__logo:hover { transform: scale(1.05); }
@media (min-width: 640px) {
  .nav-pill__logo { width: 116px; height: 116px; }
}
.nav-pill__rive {
  width: 100%;
  height: 100%;
  transform: scale(1.3) translateX(8px);
  display: block;
}

/* ---- CTA pill button ---- */
.nav-pill__cta-wrap {
  flex: 1 1 auto;
  display: flex;
  justify-content: flex-end;
  align-items: center;
  padding: 0 24px 0 8px;
}
@media (min-width: 640px) {
  .nav-pill__cta-wrap { padding-right: 32px; }
}
/* CTA — mirrors hero CTA: solid light-purple ring | dark gap | paper-mesh fill | white label */
.nav-pill__cta {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 4px;                       /* dark gap between outer ring and mesh fill */
  border: 4px solid var(--light-purple);
  border-radius: 999px;
  background: #FFFFFF;                /* matches the white pill behind it */
  text-decoration: none;
  cursor: pointer;
  white-space: nowrap;
  transition: filter 160ms ease, transform 160ms ease;
  box-shadow: 0 8px 16px rgba(160, 140, 255, 0.35);
}
.nav-pill__cta:hover { filter: brightness(1.08); }
.nav-pill__cta:active { transform: scale(0.98); }
.nav-pill__cta-inner {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 999px;
  padding: 12px 22px;
  background: linear-gradient(135deg, #A0C7FF 0%, #477ED6 35%, #A08CFF 70%, #07EDBE 100%);
  overflow: hidden;
  isolation: isolate;
}
@media (min-width: 640px) {
  .nav-pill__cta-inner { padding: 14px 28px; }
}
.nav-pill__cta-mesh {
  position: absolute;
  inset: 0;
  z-index: 0;
  border-radius: inherit;
  pointer-events: none;
}
.nav-pill__cta-mesh canvas {
  display: block;
  width: 100% !important;
  height: 100% !important;
  border-radius: inherit;
}
.nav-pill__cta-label {
  position: relative;
  z-index: 1;
  color: #FFFFFF;
  font-family: 'CeraRound', 'Cera Round', 'Nunito', sans-serif;
  font-size: 14px;
  font-weight: 900;
  letter-spacing: 0.01em;
  line-height: 18px;
  text-shadow: 0 1px 2px rgba(10, 9, 26, 0.35);
}
@media (min-width: 640px) {
  .nav-pill__cta-label { font-size: 16px; line-height: 20px; }
}

/* Desktop = "Book a free call" (anchor to #consult-embed).
   Mobile  = "Call now" (tel: link). One visible at a time, the other display:none. */
.nav-pill__cta--mobile  { display: none; }
@media (max-width: 639px) {
  .nav-pill__cta--desktop { display: none; }
  .nav-pill__cta--mobile  { display: inline-flex; }
}

/* Mobile sizing: taller pill, bigger logo, more breathing room on both sides
   so the pill never kisses the screen edges. Phone CTA stays as "Call now". */
@media (max-width: 639px) {
  .nav-pill__container { padding: 0 20px; }
  .nav-pill__nav {
    min-height: 96px;
    padding: 0 18px 0 14px;
  }
  .nav-pill__logo { width: 86px; height: 86px; margin-left: 0; }
  .nav-pill__cta-wrap { padding: 0 10px 0 6px; }
  .nav-pill__cta-inner { padding: 10px 16px; }
  .nav-pill__cta-label { font-size: 13px; line-height: 16px; }
}

/* ---- Hamburger ---- */
.nav-pill__burger {
  flex: 0 0 auto;
  display: inline-flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  gap: 9px;
  background: none;
  border: 0;
  padding: 6px;
  cursor: pointer;
  width: auto;
  height: auto;
}
.nav-pill__burger-line {
  display: block;
  width: 36px;
  height: 5px;
  border-radius: 3px;
  background: linear-gradient(90deg, #A08CFF, #07EDBE);
  transition: transform 300ms ease, opacity 300ms ease;
}
.nav-pill__burger[aria-expanded="true"] .nav-pill__burger-line:nth-child(1) {
  transform: rotate(45deg) translate(10px, 10px);
}
.nav-pill__burger[aria-expanded="true"] .nav-pill__burger-line:nth-child(2) {
  opacity: 0;
}
.nav-pill__burger[aria-expanded="true"] .nav-pill__burger-line:nth-child(3) {
  transform: rotate(-45deg) translate(10px, -10px);
}

/* ---- Curtain menu ---- */
.nav-pill__curtain {
  position: fixed;
  inset: 0;
  z-index: 40;
  background: rgba(255, 255, 255, 0.95);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  transform: translateY(-150%);
  /* CLOSE = a rising curtain. The old close used a 400ms ease-OUT, which dumped
     ~95% of the travel in the first ~120ms — the panel snapped up and vanished
     instead of reading as a rise. This easing spreads the travel across the whole
     duration so you actually SEE the curtain lift up and reveal the page. */
  transition: transform 950ms cubic-bezier(0.45, 0, 0.55, 1);
  pointer-events: none;
}
.nav-pill__curtain[data-open="true"] {
  /* OPEN = the curtain drops DOWN from the top to cover the page (a curtain
     closing/lowering). Kept as its own slower ease-out so the two motions read
     distinctly: drop in, rise out. */
  transform: translateY(0);
  transition: transform 1100ms cubic-bezier(0.16, 1, 0.3, 1);
  pointer-events: auto;
}
.nav-pill__curtain-inner {
  /* Center within the VISIBLE viewport, not iOS Safari's taller layout
     viewport — inset:0 spans under the toolbars, which parked the whole stack
     high with dead space at the bottom (Andrew 2026-07-14). 100dvh tracks the
     visible height; top pad clears the fixed nav-pill bar. */
  height: 100vh;
  height: 100dvh;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 44px;
  padding: 92px 16px calc(32px + env(safe-area-inset-bottom));
}
.nav-pill__curtain-list {
  list-style: none;
  margin: 0; padding: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 24px;
}
@media (min-width: 640px) {
  .nav-pill__curtain-list { gap: 32px; }
}
.nav-pill__curtain-list a {
  display: inline-block;
  font-family: 'Nunito', system-ui, sans-serif;
  font-weight: 700;
  font-size: 22px;
  color: #1f2937;
  text-decoration: none;
  transition: color 300ms ease, transform 300ms ease, opacity 300ms ease;
  transform: translateY(16px);
  opacity: 0;
}
@media (min-width: 640px) {
  .nav-pill__curtain-list a { font-size: 26px; }
}
.nav-pill__curtain-list a:hover { color: #A08CFF; }
.nav-pill__curtain[data-open="true"] .nav-pill__curtain-list a {
  transform: translateY(0);
  opacity: 1;
}
/* Stagger up to 6 items (homeItems is 4, landingItems is 3) */
.nav-pill__curtain[data-open="true"] .nav-pill__curtain-list li:nth-child(1) a { transition-delay: 100ms; }
.nav-pill__curtain[data-open="true"] .nav-pill__curtain-list li:nth-child(2) a { transition-delay: 150ms; }
.nav-pill__curtain[data-open="true"] .nav-pill__curtain-list li:nth-child(3) a { transition-delay: 200ms; }
.nav-pill__curtain[data-open="true"] .nav-pill__curtain-list li:nth-child(4) a { transition-delay: 250ms; }
.nav-pill__curtain[data-open="true"] .nav-pill__curtain-list li:nth-child(5) a { transition-delay: 300ms; }
.nav-pill__curtain[data-open="true"] .nav-pill__curtain-list li:nth-child(6) a { transition-delay: 350ms; }

/* Two stacked, centered CTAs (Andrew 2026-07-14): primary "Free Phone
   Consultation" over secondary "Start Training". */
.nav-pill__curtain-cta-wrap {
  padding-top: 24px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  transform: translateY(16px);
  opacity: 0;
  transition: transform 300ms ease, opacity 300ms ease;
  transition-delay: 0ms;
}
.nav-pill__curtain[data-open="true"] .nav-pill__curtain-cta-wrap {
  transform: translateY(0);
  opacity: 1;
  transition-delay: 400ms;
}
/* Curtain CTA reuses the hero-style ring + mesh treatment, just bigger label.
   min-width matches the two stacked pills on a phone; the inner flexes to fill
   so the mesh spans the whole pill instead of floating in a white gap. */
.nav-pill__curtain-cta {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: min(280px, 76vw);
  padding: 5px;
  border: 5px solid var(--light-purple);
  border-radius: 999px;
  background: #FFFFFF;
  text-decoration: none;
  cursor: pointer;
  white-space: nowrap;
  transition: filter 160ms ease, transform 160ms ease;
  box-shadow: 0 8px 16px rgba(160, 140, 255, 0.35);
}
.nav-pill__curtain-cta:hover { filter: brightness(1.08); }
.nav-pill__curtain-cta:active { transform: scale(0.98); }
.nav-pill__curtain-cta .nav-pill__cta-inner { flex: 1; padding: 15px 30px; }
.nav-pill__curtain-cta .nav-pill__cta-label {
  font-size: clamp(15px, 4.3vw, 18px);
  line-height: 1.25;
}
/* Primary label: "Get started"-style sticker lettering — dark glyphs wrapped
   in a thick white outline (paint-order draws the stroke behind the fill),
   matching .c-pricing__card-cta-label (Andrew 2026-07-14, reference image). */
.nav-pill__curtain-cta:not(.nav-pill__curtain-cta--secondary) .nav-pill__cta-label {
  color: #0A091A;
  -webkit-text-stroke: 3px #FFFFFF;
          text-stroke: 3px #FFFFFF;
  paint-order: stroke fill;
  text-shadow: none;
}

/* Secondary (Start Training → checkout): same pill silhouette as the primary,
   but a plain white fill + dark slate label (matches the menu list items, not
   a different purple — Andrew 2026-07-14) so it reads as the lighter action. */
.nav-pill__curtain-cta--secondary {
  box-shadow: 0 6px 14px rgba(160, 140, 255, 0.22);
}
.nav-pill__curtain-cta--secondary .nav-pill__cta-inner { background: #FFFFFF; }
.nav-pill__curtain-cta--secondary .nav-pill__cta-label {
  color: #1f2937;
  text-shadow: none;
}

/* Curtain bottom gradient edge (matches old NavPill aesthetic).
   Anchored to the bottom of the curtain (= bottom edge of the screen when open)
   instead of top:100% (which pushed it just past the bottom, off-screen). */
.nav-pill__curtain-edge {
  position: absolute;
  bottom: 0;
  left: 0;
  width: 100%;
  height: 10px;
  background: linear-gradient(90deg, #A08CFF 0%, #07EDBE 50%, #FF7EC0 100%);
  pointer-events: none;
}

/* When curtain is open, lock body scroll (set by JS via class on <body>) */
body.nav-pill--menu-open { overflow: hidden; }

/* Avoid double-applying the Rive logo when JS hasn't loaded yet — fallback is invisible canvas. */
.nav-pill__rive:not(.is-mounted) {
  background: transparent;
}

/* ---- Native scrollbar hidden site-wide ----
   The nav pill's gradient progress ring IS the site's scroll indicator, so the
   browser's own scrollbar on the right edge just doubles it up. Hide it in every
   engine; scrolling itself is unchanged. Lives here because every page that
   shows the pill loads this sheet (linked from partials/head). */
html {
  scrollbar-width: none;      /* Firefox */
  -ms-overflow-style: none;   /* legacy Edge/IE */
}
html::-webkit-scrollbar,
body::-webkit-scrollbar {
  display: none;              /* Chrome / Safari / new Edge */
  width: 0;
  height: 0;
}

/* --- Client Hub login (curtain footer) — feat/training-hub ------------------
   Visible only when lib/render.ts renders data-hub-enabled="on" (flag-gated).
   Deliberately quiet: it must not compete with the two conversion CTAs. */
.nav-pill__client-login {
  display: none;
}
.nav-pill__client-login[data-hub-enabled="on"] {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  justify-content: center;
  margin: 18px auto 0;
  color: rgba(44, 41, 119, 0.72);
  font-family: 'CeraRound', 'Nunito', sans-serif;
  font-weight: 900;
  font-size: 13px;
  letter-spacing: 0.03em;
  text-decoration: none;
  padding: 8px 14px;
  border-radius: 999px;
  transition: color 0.15s ease;
}
.nav-pill__client-login[data-hub-enabled="on"]:hover {
  color: #9945FF;
}
.nav-pill__client-login img {
  opacity: 0.7;
}

/* == /components/hero/style.css?v=4 == */
/* Hero A2v4 — pixel-port of Paper artboard 35T-0 */
.c-hero {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  /* Transparent so the body's squiggle pattern tiles through. Lets the
     pattern continue uninterrupted into the next section. */
  background: transparent;
  /* Clip horizontally so icons near the L/R edge never spawn a scrollbar, but
     allow VERTICAL bleed so bottom-edge icons cross the seam into the next
     section's top "breath" instead of being sliced off. z-index:1 lifts the
     bleeding icons above the (opaque) next section so they actually show. */
  overflow-x: clip;
  overflow-y: visible;
  /* Full-viewport hero — nothing else shares the screen with it. Andrew
     wants this to own 100% of the first fold and have room for the floating
     icons around it. svh wins on modern browsers so the hero height stays FIXED
     as the mobile URL bar hides/shows on scroll (100vh flexes with it, which
     dragged the %-positioned icons around mid-scroll). vh is the old fallback. */
  min-height: 100vh;
  min-height: 100svh;
}
.c-hero__pattern {
  /* Pattern lives on body now — keep this element for layout backward
     compat but visually inert. */
  display: none;
}
.c-hero__content {
  position: relative;
  z-index: 1;
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 40px;
  /* More top space than bottom so the H1 doesn't get crammed against the
     nav pill. Bottom is trimmed since pain-mirror takes over below. */
  padding: 120px 80px 40px;
  text-align: center;
}
.c-hero__headline {
  margin: 0;
  font-family: 'CeraRound', 'Cera Round', 'Nunito', system-ui, sans-serif;
  font-weight: 900;
  /* Fluid scale — fills the full-viewport hero on big screens, still
     comfortable on phones. */
  font-size: clamp(56px, 9vw, 132px);
  line-height: 1.0;
  letter-spacing: -0.03em;
  display: flex;
  flex-direction: column;
  align-items: center;
}
.c-hero__accent {
  /* Sticker outline (Andrew 2026-07-12), two layers: this span is the WHITE
     base (thick stroke wrapped around the glyphs via paint-order), and the
     animated gradient paints on a COPY of the text stacked on top (::after,
     reads data-text). A gradient background can't sit above a stroked copy
     any other way: element backgrounds always paint below children. */
  color: #FFFFFF;
  -webkit-text-stroke: 0.17em #FFFFFF;
          text-stroke: 0.17em #FFFFFF;
  paint-order: stroke fill;
  display: inline-block;
  position: relative;
  z-index: 0;
}
.c-hero__accent::after {
  content: attr(data-text);
  position: absolute;
  inset: 0;
  /* 5-stop palindromic gradient so the ping-pong animation loops seamlessly */
  background-image: linear-gradient(90deg, #07EDBE 0%, #9945FF 25%, #FF7EC0 50%, #9945FF 75%, #07EDBE 100%);
  background-size: 200% 100%;
  background-position: 0% 50%;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  /* text-stroke inherits — zero it here or it covers the gradient */
  -webkit-text-stroke: 0;
          text-stroke: 0;
  animation: hero-accent-flow 12s cubic-bezier(0.45, 0, 0.55, 1) infinite;
}
@keyframes hero-accent-flow {
  0%, 100% { background-position:   0% 50%; }
  50%      { background-position: 100% 50%; }
}
@media (prefers-reduced-motion: reduce) {
  .c-hero__accent::after { animation: none; }
}
.c-hero__rest {
  /* Sticker lettering (Andrew 2026-07-12): dark fill + thick white border,
     same recipe as the pain-mirror Free Consultation pill. paint-order draws
     the stroke BEHIND the glyphs so it wraps around them instead of eating in;
     with line-height 1.0 neighbouring outlines run together on purpose. */
  color: #0A091A;
  -webkit-text-stroke: 0.17em #FFFFFF;
          text-stroke: 0.17em #FFFFFF;
  paint-order: stroke fill;
  display: inline-block;
  /* Balanced wrap so "Kansas City" stays together on its own line instead
     of breaking "Kansas / City" across rows. */
  text-wrap: balance;
  max-width: 14ch;
}
.c-hero__tags {
  margin: 0;
  color: rgba(255, 255, 255, 0.55);
  font-family: 'Nunito', system-ui, sans-serif;
  font-size: 22px;
  font-weight: 600;
  line-height: 28px;
  letter-spacing: 0.01em;
  /* Balance so "Anxiety" never wraps onto its own line as an orphan. */
  text-wrap: balance;
  max-width: 32ch;
}

/* ---- CTA button (matches Paper "Get Started": solid ring | dark gap | mesh fill) ---- */
.c-hero__cta {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 6px;                    /* dark gap between outer ring and mesh fill */
  border: 5px solid var(--light-purple);
  border-radius: 999px;
  background: var(--bg);           /* the dark "gap" ring */
  text-decoration: none;
  transition: filter 160ms ease, transform 160ms ease;
}
.c-hero__cta:hover { filter: brightness(1.08); }
.c-hero__cta:active { transform: scale(0.98); }
.c-hero__cta-inner {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 999px;
  padding: 22px 56px;
  /* Fallback gradient so the button looks right even if WebGL fails */
  background: linear-gradient(135deg, #07EDBE 0%, #9945FF 50%, #FF7EC0 100%);
  overflow: hidden;
  isolation: isolate;
}
.c-hero__cta-mesh {
  position: absolute;
  inset: 0;
  z-index: 0;
  border-radius: inherit;
  pointer-events: none;
}
.c-hero__cta-mesh canvas {
  display: block;
  width: 100% !important;
  height: 100% !important;
  border-radius: inherit;
}
.c-hero__cta-label {
  position: relative;
  z-index: 1;
  color: #FFFFFF;
  font-family: 'CeraRound', 'Cera Round', 'Nunito', sans-serif;
  font-size: 22px;
  font-weight: 900;
  letter-spacing: 0.01em;
  line-height: 26px;
  text-shadow: 0 1px 2px rgba(10, 9, 26, 0.35);
}
.c-hero__rive {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

/* ---------- Floating brand illustrations (issue #34) ---------- */
.c-hero__float {
  position: absolute;
  inset: 0;
  z-index: 0;            /* behind .c-hero__content (z-index: 1) */
  pointer-events: none;
  /* Clip L/R (no scrollbar from edge icons) but let the bottom row bleed down
     across the section seam. */
  overflow-x: clip;
  overflow-y: visible;
}
/* Groups: desktop vs mobile arrangements, toggled at the 820px breakpoint.
   Each group fills the hero box so its icons' % left/top map to the hero. */
.c-hero__group {
  position: absolute;
  inset: 0;
}
.c-hero__group--mobile { display: none; }
.c-hero__icon {
  position: absolute;
  /* Inline left/top/width % + --r come from the playground arrangement.
     Centering + rest tilt live HERE, in pure CSS, and GSAP never touches this
     wrapper — so the icon always sits exactly where it was placed (identical to
     the playground). The float animation runs on the inner <img> instead, so it
     can't stack a second -50% on top of this centering.
     --px/--py are the "keep-out bulb" offsets: hero-float-icons.js measures the
     real text at the current screen width and nudges any icon that lands on the
     headline / tags / CTA just clear of it. Default 0 = sits exactly as placed. */
  transform:
    translate(calc(-50% + var(--px, 0px)), calc(-50% + var(--py, 0px)))
    rotate(var(--r, 0deg));
  transition: transform 240ms ease;
}
.c-hero__icon > img {
  display: block;
  width: 100%;
  height: auto;
  user-select: none;
}
.c-hero__float.is-armed .c-hero__icon > img { opacity: 0; }
/* Reduced motion / no GSAP: icons stay visible at their inline position. */
@media (prefers-reduced-motion: reduce) {
  .c-hero__float.is-armed .c-hero__icon > img { opacity: 1; }
}

/* ---------- Mobile (Paper Hero Mobile v2) ---------- */
@media (max-width: 820px) {
  .c-hero__group--desktop { display: none; }
  .c-hero__group--mobile { display: block; }
  /* Mobile: full viewport too. */
  .c-hero__content {
    padding: 100px 24px 32px;
    gap: 28px;
  }
  .c-hero__headline {
    /* Mobile bump — clamp keeps it controlled on tiny phones. */
    font-size: clamp(48px, 13vw, 64px);
    line-height: 1.02;
  }
  .c-hero__tags { font-size: 16px; line-height: 22px; }
  .c-hero__cta { padding: 4px; border-width: 4px; }
  .c-hero__cta-inner { padding: 18px 36px; }
  .c-hero__cta-label { font-size: 17px; line-height: 22px; }
}
@media (max-width: 480px) {
  /* Phone breakpoint: 14vw rendered "Dog Training in Kansas City" at ~55px,
     which forced the heading_rest to break across 3 lines (orphaning "Dog").
     12vw / 50px cap lets the rest settle into a clean 2 lines on every phone
     width (360–430px), so the H1 reads In-Home / Dog Training / in Kansas
     City. Locked hero design (gradient, CTA, shader) is untouched. */
  .c-hero__headline { font-size: clamp(40px, 12vw, 50px); }
}

/* == /components/quiz-game/style.css?v=1 == */
/* Quiz arm "game": ARM SWITCHING and the takeover shell. Nothing else.
 *
 * ⚠️ THIS IS NOT THE DESIGN, and it must not become it by default. Andrew owns
 * the look of this arm and is building it in Rive. What lives here is the
 * minimum that makes the arm a page rather than a floating card: the switch,
 * the takeover, and a legible fallback. Every rule below the switch can be
 * deleted and the quiz still renders and still works, which is the same
 * guarantee dev-skin.css carries and the reason the seam is provably real.
 *
 * The signals the real stylesheet will target are written on the section by
 * motion.js and are listed at the top of dev-skin.css: data-state, data-phase,
 * data-type, data-lane, data-severity, data-beat, data-motion, plus the
 * --q-progress family of custom properties.
 */

/* ── The switch ────────────────────────────────────────────────────────────
 * Same shape quiz-hero/style.css uses, and for the same reason: head.html
 * stamps html[data-arm] before first paint, so the arm is chosen with zero
 * flicker on an edge-cached document that ships all three arms.
 *
 * NO data-arm (JS off, or the inline script threw) paints the FORM arm, because
 * that is the markup that works with no JavaScript at all. This arm is the one
 * that degrades worst without it: the engine paints every question, so with JS
 * off there is nothing in the card. Defaulting here would show a blank box. */
.q-game { display: none; }
html[data-arm="game"] .q-game { display: block; }
html[data-arm="game"] .c-quiz,
html[data-arm="game"] .c-hero { display: none; }

/* ── The takeover ──────────────────────────────────────────────────────────
 * Andrew's build item 3, "black takeover". The card owns the first screen
 * outright rather than sitting in a page: this arm's whole premise is that
 * question one is already live when you land, so anything else competing for
 * the fold is the Start button coming back in another form.
 *
 * svh, not vh: on iOS the URL bar makes vh taller than the visible screen, so
 * the card's bottom sits under the browser chrome and the CTA is the thing that
 * gets cut. See docs and reference on the ios vh trap. */
html[data-arm="game"] .q-game {
  background: #0A091A; /* the site's own theme-color, not a new black */
  min-height: 100vh;
  min-height: 100svh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--quiz-nav-clearance, 112px) 20px 32px;
  box-sizing: border-box;
}

.q-game .q-stage { width: 100%; max-width: 560px; }

/* ⚠️ THE COACH SLOT COLLAPSES UNTIL THERE IS A COACH, and this is a fold bug, not
 * a tidiness one. A <canvas> with no width/height attributes is 300x150 by
 * default and the skin stretches it, so an empty slot was reserving 232px above
 * the card: measured on a 390x844 phone, the card started at y=360 and question
 * one's chips fell below the fold. The whole premise of this arm is that Q1 is
 * already live when you land.
 *
 * Keyed on data-rive-src because that attribute is ALREADY the only switch that
 * turns the coach on (see the component's own comment, and motion.js: the engine
 * makes no request without it). So the slot appears the moment the .riv does,
 * with no second flag to remember and no way for the two to disagree. */
.q-game .q-coach:not([data-rive-src]) { display: none; }

/* The honeypots must EXIST and must never be seen or focused. Not display:none:
 * some autofill and some assistive tooling skip a display:none field, and the
 * whole point is that a bot fills it. lib/validate.ts rejects the post when
 * either arrives filled. */
.q-game .q-hp {
  position: absolute; width: 1px; height: 1px;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap;
}

/* Escape hatch, Andrew's call: scroll past it. Deliberately not a modal — an
 * interstitial over the fold is a Google Ads policy risk on a landing page. */
.q-game .q-escape {
  display: block; margin: 20px auto 0; text-align: center;
  color: rgba(255,255,255,.55); font-size: 14px; text-decoration: underline;
}
.q-game .q-escape:hover { color: rgba(255,255,255,.85); }
/* Gone once the call is booked. "Just looking around?" under a confirmation is
   the page still selling to somebody who already bought. Here and not in
   rive-skin.css: that file loads only when an artboard drew, and the escape
   hatch is on the screen either way. motion.js writes data-state on the section
   whether the skin armed or not, so this needs no JS. */
.q-game[data-state="done"] .q-escape { display: none; }

@media (prefers-reduced-motion: reduce) {
  .q-game * { animation: none !important; transition: none !important; }
}

/* 🔴 THE BLANK AFTER YES. Andrew, 2026-09-01: "after they say yes... just go to a
 * blank screen... take them to the homepage." The card goes; the page behind it
 * stays, which is the header and its squiggles and everything below the fold.
 * ⚠️ visibility, NOT display: the stage keeps the card's box so the page does not
 * jump under a tap, and `data-q-blank="off"` on the next render brings it back
 * (a deferred booking that fails needs the card again). */
.q-game .q-stage[data-q-blank="on"] .q-card { visibility: hidden; }

/* == /components/quiz-game/dev-skin.css?v=1 == */
/* ⚠️ PLACEHOLDER SKIN. NOT THE DESIGN.
 *
 * Andrew owns the look of this arm and is building it in Rive. This file exists
 * so the engine is legible while it is being built, and so the seam is provably
 * real: every rule here can be deleted and the quiz still renders and still
 * works. It is deliberately plain so nobody mistakes it for a design decision.
 *
 * The signals the real stylesheet will target, all written by motion.js on the
 * section element:
 *   data-state   current state id          data-phase  questions|capture|extra|done
 *   data-type    choice|reward|field|...   data-dir    forward|back
 *   data-lane    which lane matched        data-severity 0..3
 *   data-beat    last beat that fired      data-motion full|reduced
 *   --q-progress --q-phase-progress --q-step --q-total --q-phase-step --q-phase-total
 */
.q-game { padding: 24px 16px 48px; }
.q-stage { max-width: 480px; margin: 0 auto; }
.q-coach { display: block; width: 100%; max-width: 220px; margin: 0 auto 12px; aspect-ratio: 1/1; }
.q-card { border: 1px solid currentColor; border-radius: 8px; padding: 16px; }

.q-trail { display: flex; gap: 6px; margin-bottom: 14px; }
.q-node { flex: 1; height: 4px; border-radius: 2px; background: currentColor; opacity: .18; }
.q-node.is-done { opacity: .85; }
.q-node.is-now { opacity: .5; }

/* The opener is above the card, so it needs a rest state here too: dev-skin
   loads on every landing page and is what paints when the skin is off. */
.q-open { text-align: center; margin: 0 0 16px; }
.q-stage { position: relative; }
.q-open-head { font-size: 22px; font-weight: 800; margin: 0 0 4px; }
.q-open-sub { font-size: 15px; opacity: .7; margin: 0; }
.q-stage[data-q-open="off"] .q-open { display: none; }
.q-ask { font-size: 20px; margin: 0 0 4px; }
.q-hint { font-size: 13px; opacity: .7; margin: 0 0 12px; }
.q-chips { display: grid; gap: 8px; }
.q-chip, .q-consent, .q-next, .q-back, .q-skip {
  font: inherit; text-align: left; padding: 12px 14px;
  border: 1px solid currentColor; border-radius: 6px;
  background: transparent; color: inherit; cursor: pointer; width: 100%;
}
.q-chip.is-selected, .q-consent.is-selected { border-width: 3px; }
.q-chip:focus-visible, .q-consent:focus-visible, .q-next:focus-visible,
.q-back:focus-visible, .q-skip:focus-visible, .q-input:focus-visible,
.q-range:focus-visible { outline: 3px solid currentColor; outline-offset: 2px; }
.q-next[disabled] { opacity: .4; cursor: default; }
.q-foot { display: grid; gap: 8px; margin-top: 14px; }
.q-input, .q-free {
  font: inherit; width: 100%; padding: 12px 14px; box-sizing: border-box;
  border: 1px solid currentColor; border-radius: 6px; background: transparent; color: inherit;
}
.q-free { margin-top: 8px; }

/* 🔴 THE TWO-ACROSS ROW LIVES HERE TOO, and that is not duplication for its own
 * sake. Andrew, 2026-08-31: "the human name fields are stacked, but they should
 * be side by side first and last." They were side by side at every width WITH the
 * skin and stacked without it, because `index.js` ships `.q-field.is-half` on
 * every arm and only rive-skin.css honoured it.
 * A layout the MARKUP asks for cannot live only in the stylesheet that may never
 * load. This file is the placeholder look; the grid is structure, so it belongs
 * wherever the markup does. rive-skin.css restates it with its own spacing. */
.q-form { display: grid; grid-template-columns: 1fr 1fr; gap: 9px; }
.q-field { grid-column: 1 / -1; }
.q-field.is-half { grid-column: span 1; }
.q-label { display: flex; align-items: baseline; gap: 6px; font-size: 12px; margin: 0 0 4px; }
.q-opt { font-size: 10px; opacity: .7; text-transform: uppercase; }
.q-plan-head { font-size: 20px; margin: 0 0 4px; }
.q-plan { list-style: none; margin: 8px 0 0; padding: 0; display: grid; gap: 6px; }
.q-plan-item { border: 1px solid currentColor; border-radius: 6px; padding: 10px 12px; }

.q-scale { position: relative; margin: 18px 0 4px; }
.q-band { position: absolute; top: 4px; height: 14px; border: 1px dashed currentColor; border-radius: 7px; }
.q-band-tag { position: absolute; bottom: calc(100% + 4px); left: 50%; transform: translateX(-50%);
  white-space: nowrap; font-size: 10px; text-transform: uppercase; letter-spacing: .08em; }
.q-range { width: 100%; position: relative; z-index: 1; }
.q-scale-ends { display: flex; justify-content: space-between; font-size: 12px; opacity: .7; }
.q-amount { font-size: 28px; text-align: center; margin: 12px 0 0; }
.q-escape { display: block; text-align: center; margin-top: 16px; font-size: 14px; opacity: .7; }

/* ⚠️ THE BOOT FLIP IS GONE FROM HERE, and do not put it back. This file used to
 * carry an `is-rive-booting` rule that hid the controls the skin was about to
 * draw. It could not work: the class was added by rive-skin.js, which is five
 * dynamic imports deep, and the outlines Andrew was seeing had been on screen
 * since 424ms. It also hid the wrong half, naming seven classes and leaving the
 * card, the trail, the inputs and the calendar painting.
 *
 * The fix is that the design paints FIRST. rive-skin.css is a real <link> in
 * head.html, its html[data-quizskin] gate is stamped inline before first paint,
 * and each control hands over to its artboard on its own data-rive-ready. There
 * is no window left to hide. */

/* Screen 5, unskinned. Same job as everything else here: legible, obviously not
   the design. The real look lives in rive-skin.css. */
.q-sec { font-size: 11px; text-transform: uppercase; letter-spacing: .1em; opacity: .7; margin: 14px 0 6px; }
.q-days { display: grid; grid-template-columns: repeat(4, 1fr); gap: 6px; }
.q-slots { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; }
.q-day, .q-slot {
  font: inherit; padding: 10px 6px; text-align: center; cursor: pointer;
  border: 1px solid currentColor; border-radius: 6px; background: transparent; color: inherit;
}
.q-day { display: grid; gap: 2px; }
.q-day-num { font-size: 18px; }
.q-day.is-selected, .q-slot.is-selected { border-width: 3px; }
.q-more {
  font: inherit; font-size: 13px; padding: 6px; margin: 6px auto 0; display: block;
  border: 0; background: none; color: inherit; cursor: pointer; text-decoration: underline;
}
.q-day:focus-visible, .q-slot:focus-visible, .q-more:focus-visible { outline: 3px solid currentColor; outline-offset: 2px; }
.q-next.is-busy { opacity: .4; }
.q-finale { width: 100%; aspect-ratio: 1/1; display: grid; place-items: center; }
.q-finale-art { display: block; width: 100%; height: 100%; object-fit: contain; }
/* `display` beats the `hidden` attribute, so name it back. */
.q-finale-art[hidden] { display: none; }

.q-hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }
.q-error { border: 2px solid currentColor; border-radius: 6px; padding: 10px 12px; margin: 12px 0 0; font-size: 14px; }


/* The engine reports reduced motion; the placeholder honours it so the
   behaviour is testable before the real stylesheet exists. */
[data-motion="reduced"] .q-plan-item { animation: none; }

/* == /components/quiz-game/rive-skin.css?v=1 == */
/* Quiz arm "game": the layout the Rive skin sits in.
 *
 * Loaded by rive-skin.js only, and only when an artboard has actually drawn, so
 * a visitor whose .riv never arrives gets the arm's plain fallback rather than a
 * card full of invisible text. That is why every rule that HIDES something is
 * under `.is-rive`, and every rule that only positions is not.
 *
 * ⚠️ This file lays out boxes. It paints no control. Chips, the Next button and
 * the heading are drawn by artboards built in Andjroo111/rive-lab
 * (examples/gdkc-quiz-rive), against the design Andrew locked on 2026-08-29.
 * Values here are the ones measured off that design, not new decisions.
 */
/* 🔴 WIDER. Andrew, 2026-08-31: "we need the whole thing a little wider and
 * longer", after offering the width a session earlier: "we can make this whole
 * card wider if we need to, honestly. We have space."
 * He was right that the space was there and unused: at 393px the card was 344
 * with 25px of dead margin each side. 380 plus the tighter page padding below
 * puts the card at 365, so it uses the room instead of floating in it.
 * ⚠️ It is a CAP, not a width. On a wider phone the page padding still decides,
 * and the card stops growing at 380 so the two-line chip labels do not turn into
 * one long line with a hole beside them. */
.q-game .q-stage { max-width: 380px; }
/* The page's own side padding, which was doing most of the narrowing. Overridden
   here rather than in style.css because that file is the arm switch and the
   takeover shell, and this is a look decision. */
html[data-arm="game"][data-quizskin] .q-game { padding-left: 14px; padding-right: 14px; }

/* 🔴 CENTRE THE CARD, NOT THE CARD PLUS THE ESCAPE LINK. Andrew, 2026-08-31:
 * "when we go to the next page, it's not centered."
 * The maths was already right and centring the wrong thing. `.q-stage` holds the
 * card AND "Just looking around? Scroll on down", and the stage was perfectly
 * centred: 46px of clearance above it and 46px below, measured. But the escape
 * link is 43px of faint grey text that carries no visual weight, so what the eye
 * centres on is the CARD, and the card was 46px from the nav and 90px from the
 * bottom. Off by 44, and worse on the taller screens because the imbalance is
 * fixed while the card is not.
 *
 * So the link hangs out of flow, below the card, and stops voting on the centre.
 * ⚠️ padding-bottom 0 is deliberate and paired with it. Centring happens inside
 * the padding box, so any bottom padding tilts the card up by half of it against
 * a top padding that is the nav's own height and cannot shrink. Solved for equal
 * visible gaps above and below the card: padBottom has to be 0.
 * ⚠️ The link keeps its own margin, so it is not against the card, and `bottom`
 * on the game element still guards the page's end. */
html[data-quizskin] .q-game .q-stage { position: relative; }

/* ── the opener, above the card ─────────────────────────────────────────────
 * On the dark ground, not on the card, so the card's geometry never changes
 * between screens. It keeps its box on all three and only its visibility moves.
 * ⚠️ NO COLOUR IN IT. "your dog" carried the teal-to-violet run for one build and
 * Andrew cut it, 2026-09-01. Colour on this screen belongs to the Next button and
 * the trail; a third source competes with the thing the visitor has to press. */
/* 🔴 OUT OF FLOW, AND THAT IS THE WHOLE DESIGN OF IT. Two in-flow versions were
 * built and measured first, and both lost something real:
 *   visibility:hidden, box reserved  -> the BOOK screen went 13px under the fold
 *                                       at 390x750 with a 59px inset. His phone.
 *   display:none, box reclaimed      -> the card jumped 66px up on the first Next,
 *                                       drift across the three screens 40 -> 80px.
 * Absolute costs neither. `.q-stage` hugs the card, so with the opener out of flow
 * the stage box IS the card box, `bottom: 100%` lands exactly on the card's top
 * edge, and the takeover centres the card to the pixel it already used. Below-fold
 * back to 0 on all three screens, drift back to its pre-existing 40px.
 * ⚠️ The 40px was ALWAYS there: the card re-centres as it grows, 436 -> 487 ->
 * 515px. Nothing above it can hold it still, so do not add something that tries. */
html[data-quizskin] .q-game .q-open {
  position: absolute;
  top: 0; left: 0; right: 0;
  text-align: center;
}
/* 🔴 THE BAND IS PADDING ON THE STAGE, AND THAT IS THE WHOLE FIX. Andrew's phone,
 * 2026-09-01: the first line drew BEHIND the nav pill. Reproduced at 393x664 with
 * NO inset, 29px under, and it starts at 750 and worsens as the viewport shortens.
 * Cause: the opener was absolute with `bottom: 100%`, hanging off the card's top
 * edge and contributing nothing to any box, so the takeover centred the CARD and
 * the opener went wherever that left it, which on a short viewport is under the nav.
 * The stage now reserves the band, so what gets centred is the opener AND the card.
 * ⚠️ ONLY on screen 1. The band is why this was taken out of flow in the first
 * place: carried onto the BOOK screen it put the card 13px under the fold. Keyed on
 * the stage's own attribute, so screens 2 and 3 measure exactly as production. */
html[data-quizskin] .q-game .q-stage[data-q-open="on"] { padding-top: var(--q-open-band, 88px); }
html[data-quizskin] .q-game .q-stage[data-q-open="off"] .q-open { display: none; }
html[data-quizskin] .q-game .q-open-head {
  font: 900 27px/1.12 'CeraRound', 'Nunito', system-ui, sans-serif;
  color: #F8F8F8; margin: 0 0 6px; letter-spacing: -.01em;
}
html[data-quizskin] .q-game .q-open-sub {
  font: 700 15.5px/1.35 'Nunito', system-ui, sans-serif;
  color: rgba(248,248,248,.62); margin: 0;
}

/* ⚠️ A SHORT VIEWPORT RUNS THE OPENER INTO THE NAV PILL. At 390x667 with a 59px
 * inset, an iPhone SE with his real safe area, the full-size opener measured
 * clearance -1px against the nav's bottom edge: it touched. The card cannot move
 * to make room, it is centred and already the tallest thing on screen, so the
 * opener is what gives. Keyed on HEIGHT, not width: the collision is vertical and
 * a wide short window hits it too.
 * ⚠️ Measured at 59px of inset. This Mac reports 16 and shows no collision at all. */
@media (max-height: 700px) {
  html[data-quizskin] .q-game .q-stage { --q-open-band: 63px; }
  html[data-quizskin] .q-game .q-open-head { font-size: 21px; margin-bottom: 4px; }
}
@media (prefers-reduced-motion: reduce) {
  html[data-quizskin] .q-game .q-open { transition: none; }
}
html[data-quizskin] .q-game .q-escape {
  position: absolute; top: 100%; left: 0; right: 0;
  margin: 20px auto 0;
}
/* 🔴 THE TAKEOVER FILLS THE SAFE VIEWPORT, NOT THE RAW ONE. This is the other
 * half of "it's not centered", and the half that only misbehaves on a phone.
 * brand.css pads the BODY by the safe-area insets:
 *     padding-top: max(env(safe-area-inset-top), 16px)
 * so `.q-game` starts that far down, and `min-height: 100svh` then runs the same
 * distance PAST the fold. Centring inside a box whose bottom is off-screen puts
 * the card low by half the overhang, every time.
 * ⚠️ On this desktop the inset is the 16px floor and the error is 16px, which is
 * why it measured as a nudge here and reads as plainly wrong on his iPhone: the
 * real top inset there is 47 to 59px.
 * So the height loses both insets, and the nav clearance is measured from the
 * VIEWPORT rather than from the element: the pill is fixed at the top of the
 * screen and does not move down with the body's padding, so the clearance this
 * element needs is the pill's height MINUS however far down it already starts. */
html[data-arm="game"][data-quizskin] .q-game {
  --q-safe-t: max(env(safe-area-inset-top), 16px);
  --q-safe-b: max(env(safe-area-inset-bottom), 16px);
  /* Cancel the body's own safe-area padding for this section only, so the
     takeover spans the viewport exactly and `100svh` means what it says. Doing it
     by subtraction instead does NOT work: the two paddings are not symmetric
     (bottom computes to 0 on a desktop and to the home indicator on a phone), so
     any figure taken off the height is wrong on one of them. Cancelling is right
     on both because it asks for nothing. */
  margin-top: calc(-1 * var(--q-safe-t));
  margin-bottom: calc(-1 * var(--q-safe-b));
  min-height: 100svh;
  /* The pill is FIXED, so its clearance is measured from the viewport, and the
     element now starts there. The bottom keeps the card off the home indicator. */
  padding-top: var(--quiz-nav-clearance, 112px);
  padding-bottom: var(--q-safe-b);
  /* 🔴 SAFE CENTRE, OR A TALL CARD LOSES ITS TOP. Andrew, 2026-08-31, from an
   * in-app browser: "the scheduling page didn't center. The others did great."
   * The calendar is the tallest screen, and on a short viewport it is TALLER than
   * the space between the nav and the fold. Plain centring then overflows both
   * ends equally, and the end that goes is the top: the trail, the heading and the
   * whole day row disappeared behind the fixed nav pill, leaving him on "AVAILABLE
   * TIMES" with no way to know a day row existed.
   * `safe` keeps centring while it fits and falls back to start alignment the
   * moment it does not, so an oversized card begins at the top and the rest is
   * simply scrolled to. Nothing is ever hidden under the nav.
   * ⚠️ Two declarations on purpose. A browser without `safe` keeps the first and
   * behaves exactly as it did; there is no version of this that is worse than
   * what shipped. */
  align-items: center;
  align-items: safe center;
}

html[data-arm="game"][data-quizskin] .q-game {
  background-color: #0A091A;
  background-image: url('/assets/rive/squiggle.svg');
  background-repeat: repeat;
  background-size: 480px 480px;
}

html[data-quizskin] .q-game .q-card {
  position: relative;
  border-radius: 32px;
  padding: 20px 17px 18px;
  display: flex;
  flex-direction: column;
  gap: 17px;
  background: linear-gradient(180deg, #FFFFFF 0%, #FBFAFC 62%, #F2F1F5 100%);
  box-shadow: inset 0 1.5px 0 rgba(255,255,255,1),
              0 1px 2px rgba(5,4,16,.5),
              0 26px 58px rgba(5,4,16,.55);
}

/* The artboards are wider than the card so the press can overshoot. `clip`, not
   `hidden`: it makes no scroll container, so it cannot swallow the bounce. */
html[data-quizskin] .q-game, html[data-quizskin]:has(.q-game) body { overflow-x: clip; }

/* ── every control keeps its box and its tap ─────────────────────────────────
 * Geometry only. What PAINTS a control is decided further down by whether its
 * artboard has drawn yet: the browser draws the rest state until then, and
 * `[data-rive-ready]` hands the painting over. */
html[data-quizskin] .q-game .q-chip,
html[data-quizskin] .q-game .q-consent,
html[data-quizskin] .q-game .q-next {
  position: relative;
  border: 0;
  width: 100%;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}

/* 🔴 THE HANDOVER, and the reason this arm no longer flashes.
 * Andrew, 2026-08-31: "just the outlines of the boxes of where the quiz is going
 * to be", 567ms of it on his phone against 86ms on localhost. The cause was not
 * that the design was missing. It was that THIS FILE was fetched by JavaScript
 * inside createRiveSkin, so at first paint the browser held dev-skin.css, the
 * placeholder, and nothing else. head.html links it now and the gate is stamped
 * before first paint, so the design is what paints first.
 *
 * That leaves the five controls an artboard draws. They get their REST state in
 * CSS, ported from the approved mock (rive-lab examples/gdkc-quiz,
 * quiz-final.html `.g`), which is the same source build-glass.py and
 * build-next.py were compiled from, so the two agree by construction rather than
 * by eye. When a control's artboard loads, rive-skin.js stamps data-rive-ready
 * on THAT element and the rules below stop it painting, because the canvas over
 * it is now drawing the identical shape with motion on top.
 *
 * ⚠️ Per element, not global. A global flip is the flash in another form: twelve
 * chips do not finish together, and the one that finishes last would be bare.
 * ⚠️ 697 KB of gzipped rive.wasm has to land and compile before any artboard can
 * draw, measured off this server. That floor cannot be removed, only hidden
 * behind a first paint that already looks right, which is what this is.
 * ⚠️ A missing or broken .riv now degrades to THIS, the full design without the
 * press, rather than to the dev-skin placeholder. That is the better fallback
 * and it is deliberate: fail() no longer takes the design away. */
html[data-quizskin] .q-game .q-chip[data-rive-ready],
html[data-quizskin] .q-game .q-consent[data-rive-ready],
html[data-quizskin] .q-game .q-next[data-rive-ready] {
  background: none;
  box-shadow: none;
  color: transparent;
  padding: 0;
}
/* The Next button builds its rim, face and base out of two pseudo-elements. Both
   have to go when the artboard takes over or they draw a second button. */
html[data-quizskin] .q-game .q-next[data-rive-ready]::before,
html[data-quizskin] .q-game .q-next[data-rive-ready]::after { display: none; }
/* The artboard reads these four off the element (rive-skin.js `geom`), so the
   shape of a control is a stylesheet decision and no JS changes to move it. */
html[data-quizskin] .q-game .q-chip {
  height: 48px;
  --q-radius: 24; --q-text-size: 14.5; --q-pad-l: 16; --q-pad-r: 23; --q-text-r: 40;
}
/* ⚠️ --q-lines is a REAL cap: the skin shrinks the text until it fits that many
   lines. The consent card is a paragraph, so it needs its own number or it would
   be squeezed to two lines at the floor size and become unreadable. */
html[data-quizskin] .q-game .q-consent {
  min-height: 104px;
  /* --q-text-r leaves the check somewhere to sit. At 16 the last line of the
     TCPA paragraph ran under it. */
  --q-radius: 22; --q-text-size: 13; --q-pad-l: 16; --q-pad-r: 20; --q-text-r: 44;
  --q-lines: 7;
}
html[data-quizskin] .q-game .q-next { height: 74px; }

/* ── the Next button's TWO DROP SHADOWS, drawn by the browser ────────────────
 * Andrew, 2026-08-30: "multiple shadows going on". They were outer feathers on
 * the Ring artboard, and `@rive-app/canvas-advanced` has no feather: it draws
 * each one as a hard offset copy of the pill. A pixel column through the shipped
 * button found three flat slabs under the face where the design has soft shading.
 *
 * So the artboard stopped painting them (build-next.py in rive-lab) and they moved
 * here, at the mock's own values. `drop-shadow` and not `box-shadow`: it follows
 * the CANVAS ALPHA, so the shadow is the pill's silhouette plus its base, not the
 * button's rectangular box, which is wider and 6px shorter than what is drawn.
 *
 * ⚠️ On the canvas, not the button. rive-skin.js writes `canvas.style.cssText` on
 * every refit, which would blow away an inline filter but leaves a stylesheet rule
 * alone. */
html[data-quizskin] .q-game .q-next > canvas[data-rive-skin] {
  filter: drop-shadow(0 10px 24px rgba(5,4,16,.45))
          drop-shadow(0 2px 3px rgba(5,4,16,.5));
}

/* 9px between chips is the design; the button's body hangs 6px below its box,
   so the gap has to carry both or the chips touch. */
html[data-quizskin] .q-game .q-chips { display: grid; gap: 15px; }

/* ── THREE across ───────────────────────────────────────────────────────────
 * Andrew, 2026-08-31, from his phone: the card ran off the bottom. Measured on a
 * 393x684 viewport (iPhone 15 Pro under Brave's chrome) the card was 646px and
 * **90px too tall**.
 *
 * 🔴 THE HEADER IS NOT WHERE THE HEIGHT IS, and he offered to shrink it. It is
 * 21px of a 646px card, so shrinking it buys about 2px. The chips are 430px, two
 * thirds of the card, because twelve of them two-across is SIX ROWS.
 * Three-across is four rows, which is the 128px. Measured, every option, same
 * minute, against the live tunnel:
 *
 *     now                      over 90    over 114 at vh660
 *     trim spacing only        over 43    over 67
 *     chips 60 -> 52 + trim    fits +5    over 19      cramped, and still fails
 *     drop to 10 chips         fits +37   fits +13     costs him two pains
 *     THREE ACROSS             fits +62   fits +40     header untouched, 12 kept
 *
 * So nothing else here moved: the card keeps its padding, the body keeps its
 * gap, the heading keeps its size. Only the grid changed.
 *
 * 🔴 --q-pad-r AND --q-text-r MOVE TOGETHER, ALWAYS. Andrew, 2026-08-31: the
 * check "can move over and be scooted over to the left". It can, because
 * build-glass.py binds the Check's x to PadR through the `neg` converter, so it
 * sits exactly --q-pad-r in from the right edge. No artboard rebuild.
 * But the two share one 98px chip: --q-pad-r is where the CHECK sits and
 * --q-text-r is where the LABEL stops, so moving the check left without moving
 * the label's boundary with it just puts the glyph on top of the words. At
 * pad-r 30 against text-r 26 the check drew straight through "come back", which
 * is the screenshot he sent back.
 * ⚠️ And overcorrecting costs a label. pad-r 18 with text-r 32 cleared the check
 * and broke the longest one: "Scared of everything" went to three lines and split
 * `everythin/g` out of the pill. 18 and 28 is what clears the check on every
 * selected chip with no collision and no label losing a size step, verified with
 * five long labels picked at once.
 * ⚠️ Do not test this by injecting CSS into a loaded page. The skin only re-pushes
 * geometry on a ResizeObserver fire, and these two change no box, so a late
 * stylesheet never reaches the artboard and every value looks identical. It has
 * to be in before the chips mount.
 * ⚠️ Seven is still the threshold and still a COUNT, so a question that grows or
 * shrinks lays itself out. A browser without :has gets one column, the safe way
 * round. */
html[data-quizskin] .q-game .q-chips:has(> :nth-child(7)) {
  grid-template-columns: repeat(3, 1fr);
  gap: 14px 8px;
}
html[data-quizskin] .q-game .q-chips:has(> :nth-child(7)) .q-chip {
  /* 🔴 LONGER, and this is the half that COSTS something. Width was free; height
   * comes straight out of the fit margin. At 393x684 the card had 58px of
   * headroom, 34px at vh660 and it was already 6px SHORT at vh620. Four rows of
   * chips means every pixel here is four on the card, so 64 spends 16 of the 58.
   * ⚠️ Do not raise this without re-running the fit numbers at vh660 and vh620.
   * The card fitting on his phone is not the same as it fitting on a phone with
   * more browser chrome, and 620 is already the one that clips. */
  height: 64px;
  --q-radius: 18; --q-text-size: 11.5; --q-pad-l: 9; --q-pad-r: 18; --q-text-r: 28;
}
html[data-quizskin] .q-game .q-foot { display: grid; gap: 10px; margin-top: 2px; }

/* The heading block is a fixed 46px box the Head artboard draws into. Its h2 and
   p are taken OUT OF FLOW rather than merely made transparent: left in flow they
   set the block's real height, which pushed it past 46 and let the artboard's
   canvas overlap the first chip. They stay in the DOM for screen readers and for
   the case where the artboard never loads. */
/* 🔴 NO FIXED HEIGHT AT REST, and this was a 25px jump. The skin measures each
 * title and writes an inline height on this element, 21px for a one-line ask with
 * no hint. A flat 46px here meant the card laid out 46 before the artboards landed
 * and 21 after, so the heading and every chip under it stepped up on the handover.
 * At rest the h2 and p are in flow and size the box themselves, which is the same
 * number the skin arrives at. The 46 survives only as the fallback for the moment
 * the artboard has drawn but the skin has not yet written its height. */
html[data-quizskin] .q-game .q-head { position: relative; }
html[data-quizskin] .q-game .q-head[data-rive-ready] { height: 46px; }
/* ⚠️ SCOPED TO .q-head, and that is load-bearing. These two rules take text out
   of flow and paint it transparent because the Head artboard is drawing it. An
   unscoped `.q-hint` also matches the confirmation line on `done` and the
   calendar's loading line, neither of which has an artboard behind it: they
   would render as invisible text in an empty card. */
/* At REST the heading is ordinary centred text, at the mock's own values
   (quiz-final.html h1 / .hint). 46px is what those two lines measure, which is
   why the box is 46 and why the handover does not move anything. */
html[data-quizskin] .q-game .q-head { text-align: center; }
html[data-quizskin] .q-game .q-head .q-ask {
  font: 900 19px/1.1 'CeraRound', sans-serif; letter-spacing: -.012em;
  color: #12102B; margin: 0;
}
html[data-quizskin] .q-game .q-head .q-hint {
  font: 400 13px/1.4 'Nunito', system-ui, sans-serif;
  color: #6E6A93; margin: 6px 0 0; opacity: 1;
}
/* Handed over: the Head artboard is drawing these two lines, so they go out of
   flow and stop painting. Out of flow rather than merely transparent because in
   flow they set the block's real height, which pushed it past 46 and let the
   canvas overlap the first chip. They stay in the DOM for screen readers. */
html[data-quizskin] .q-game .q-head[data-rive-ready] .q-ask,
html[data-quizskin] .q-game .q-head[data-rive-ready] .q-hint {
  position: absolute; left: 0; right: 0; top: 0;
  color: transparent; margin: 0; pointer-events: none;
}
/* Prose that is NOT a drawn heading: the confirmation and the calendar's
   loading line.
   🔴 AND THE GATE'S OWN VIEWS, which sit one wrapper deeper. Andrew's phone,
   2026-09-01: "This cancels the call on" rendered nearly invisible with only the
   bold date showing. `.q-gate-fade` was added to give each view its own keyframe
   and it broke this `>` on the way past, so the line lost its colour AND its
   centring while the UNSCOPED `.q-hint strong` rule kept the date dark. That
   split is exactly what he photographed.
   ⚠️ The child combinator is deliberate and stays: an unscoped `.q-hint` also
   matches `.q-head .q-hint`, which is painted transparent because an artboard
   draws it. So each real path is named rather than the combinator loosened. */
html[data-quizskin] .q-game .q-body > .q-hint,
html[data-quizskin] .q-game .q-body > .q-gate-fade > .q-hint {
  font: 700 14px/1.4 'Nunito', system-ui, sans-serif;
  color: #6E6A93; margin: 0; text-align: center;
}

/* Focus has to survive a transparent control, or the arm is unusable by
   keyboard the moment the skin arms. */
html[data-quizskin] .q-game .q-chip:focus-visible,
html[data-quizskin] .q-game .q-consent:focus-visible,
html[data-quizskin] .q-game .q-next:focus-visible {
  outline: 3px solid #9945FF;
  outline-offset: 3px;
  border-radius: 999px;
}

/* Still HTML, on purpose: Rive has no runtime text input. */
html[data-quizskin] .q-game .q-input,
html[data-quizskin] .q-game .q-free {
  font: 700 15.5px/1 'Nunito', system-ui, sans-serif;
  width: 100%; box-sizing: border-box; color: #12102B;
  border: 0; border-radius: 999px; padding: 14px 16px;
  background: linear-gradient(180deg, #FFFFFF 0%, #F7F6FA 100%);
  box-shadow: inset 0 2px 3px rgba(90,86,110,.16),
              inset 0 0 0 1px rgba(90,86,110,.10),
              0 1px 0 rgba(255,255,255,.9);
}
html[data-quizskin] .q-game .q-input::placeholder,
html[data-quizskin] .q-game .q-free::placeholder { color: #B6B2C2; font-weight: 600; }

html[data-quizskin] .q-game .q-back,
html[data-quizskin] .q-game .q-skip {
  border: 0; background: none; cursor: pointer;
  font: 700 12.5px/1 'Nunito', system-ui, sans-serif; color: #6E6A93;
  text-decoration: underline; text-underline-offset: 3px; padding: 6px;
}
html[data-quizskin] .q-game .q-plan-head {
  font: 900 19px/1.15 'CeraRound', sans-serif; color: #12102B; margin: 0; text-align: center;
}
html[data-quizskin] .q-game .q-plan { list-style: none; margin: 8px 0 0; padding: 0; display: grid; gap: 8px; }
html[data-quizskin] .q-game .q-plan-item {
  font: 700 14px/1.35 'Nunito', system-ui, sans-serif; color: #12102B;
  background: linear-gradient(180deg, #FFFFFF 0%, #F7F6FA 100%);
  border-radius: 18px; padding: 12px 14px;
  box-shadow: inset 0 1.2px 0 #fff, 0 1px 1px rgba(20,18,40,.10), 0 4px 10px rgba(20,18,40,.08);
}
/* 🔴 ON BRAND, AND SHAPED LIKE THE REST OF THE CARD. Andrew, 2026-08-31: "the
 * color is not on brand." It was #FFF3F3, a pink wash that appears nowhere in
 * this design: the palette here is ink, the greys, and the teal-to-violet run,
 * and colour belongs to the Next button and the trail. A red-tinted panel also
 * reads as an error the visitor caused, when every one of these is just a box
 * left to fill.
 * So it takes the card's own raised-glass recipe, the one the chips and the price
 * rows use, with the violet already used for focus carrying the attention. */
html[data-quizskin] .q-game .q-error {
  font: 700 13px/1.4 'Nunito', system-ui, sans-serif; color: #12102B;
  background: linear-gradient(180deg, #FFFFFF 0%, #F7F6FA 100%);
  border-radius: 14px; padding: 11px 14px; margin: 12px 0 0;
  box-shadow: inset 0 0 0 2px #9945FF,
              inset 0 1.2px 0 rgba(255,255,255,1),
              0 3px 0 #A6A1B3;
}
/* The box the blocked tap was about. Same violet, same weight as the ring above,
   so "this one" reads without a word of copy. Paired with focus() in render(). */
html[data-quizskin] .q-game .q-free.is-wanted,
html[data-quizskin] .q-game .q-input.is-wanted {
  box-shadow: inset 0 0 0 2px #9945FF,
              inset 0 2px 3px rgba(90,86,110,.16),
              0 1px 0 rgba(255,255,255,.9);
}

/* ⚠️ ENGAGED IS THE PILL'S OWN EDGE, NOT A RING AROUND IT. Andrew, 2026-09-01:
 * "instead of doing the regular pill, and then it has a black line around it.
 * Can we just do the pill edge has a black line around it?"
 * dev-skin.css:37 puts `outline: 3px solid currentColor; outline-offset: 2px` on
 * a focused .q-input, and currentColor here is the ink, so the ring drew 2px OUTSIDE
 * the pill as a second shape and crossed into the field beside it at is-half.
 * ⚠️ The outline has to be NAMED to die. dev-skin loads on every landing page, so an
 * unset property is not an overridden one, same trap as the trail-disc opacity.
 * The ring moves inside as the same 2px ink the chips draw at rest, at the pill's
 * own 999px radius, so the edge thickens rather than a second shape appearing.
 * ⚠️ :not(.is-wanted) is load-bearing and it is NOT belt and braces. `.q-input.is-wanted`
 * and `.q-input:focus-visible` are both (0,2,0), and render() FOCUSES the wanted box, so
 * the two states are always live together and source order alone would decide the colour.
 * Violet has to win: it is the blocked-tap answer, chosen after three shapes were tried. */
/* ⚠️ TWO RULES, AND SPLITTING THEM IS THE POINT. The outer ring dies for EVERY engaged
 * box; only the colour of the edge is conditional. Folded into one :not(.is-wanted) rule
 * it came straight back on the blocked tap, because render() focuses the wanted box: the
 * violet edge won the box-shadow and dev-skin's black ring drew around it anyway, which is
 * the exact second shape this change removes, in the state he hits most. Measured. */
html[data-quizskin] .q-game .q-input:focus-visible,
html[data-quizskin] .q-game .q-free:focus-visible { outline: none; }

html[data-quizskin] .q-game .q-input:focus-visible:not(.is-wanted),
html[data-quizskin] .q-game .q-free:focus-visible:not(.is-wanted) {
  box-shadow: inset 0 0 0 2px #12102B,
              inset 0 2px 3px rgba(90,86,110,.16),
              0 1px 0 rgba(255,255,255,.9);
}
/* ⚠️ No underline, and a size up. Andrew, 2026-08-31: "we need to take the line out of that,
   and you can make that text a little bit bigger." It is the one link on a dark ground and the
   rule under it read as a divider rather than as a link. */
html[data-quizskin] .q-game .q-escape {
  color: rgba(248,248,248,.55); text-decoration: none; font-size: 15.5px;
}
html[data-quizskin] .q-game .q-nowrap { white-space: nowrap; }

/* ── the budget gate, after the finale ──────────────────────────────────────
 * The ladder is READ here, not tapped: the question is one yes or no under it,
 * so the rows lose the button's press and keep the card's raised-glass recipe.
 * ⚠️ `.is-flat` and not a state on `.q-price`: the skin mounts an artboard on
 * every `.q-price` it finds, and a row nobody can press must not get one. */
html[data-quizskin] .q-game .q-price.is-flat {
  display: flex; align-items: baseline; justify-content: space-between;
  width: 100%; text-align: left; padding: 11px 14px; border-radius: 14px;
  background: linear-gradient(180deg, #FFFFFF 0%, #F7F6FA 100%);
  box-shadow: inset 0 1.2px 0 rgba(255,255,255,1),
              inset 0 0 0 1px rgba(90,86,110,.10);
}
/* The thumbs up on the close. Sized off the plan headline beneath it so the two
 * read as one mark and a word, which is the length he asked for. */
html[data-quizskin] .q-game .q-thumb {
  margin: 6px 0 14px; text-align: center; color: #12102B; line-height: 0;
}
html[data-quizskin] .q-game .q-thumb svg { width: 54px; height: 54px; }

/* A deposit is not a fourth price, it comes out of one of the three above it.
 * The rule says "these are not the same kind of thing" before the note explains
 * which; a solid line would read as a table border, a dotted one as an aside. */
html[data-quizskin] .q-game .q-prices-flat li.has-rule {
  margin-top: 14px; padding-top: 14px;
  border-top: 2px dotted rgba(18,16,43,.22);
}
html[data-quizskin] .q-game .q-price-note {
  display: block; margin-top: 3px;
  font: 700 11.5px/1.3 'Nunito', system-ui, sans-serif; color: #8A86A0;
}

/* ⚠️ THE FADE IS ON THE CONTENT, NOT ON THE CARD. Andrew, 2026-09-01: "we could
 * fade that in just a little bit more smoothly." render() rewrites the body, so
 * a keyframe on the new markup replays on every view change with nothing to
 * clean up. Animating the card instead would fade the trail and the pills too. */
@keyframes q-gate-in { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
html[data-quizskin] .q-game .q-gate-fade { animation: q-gate-in .42s cubic-bezier(.22,.61,.36,1) both; }
@media (prefers-reduced-motion: reduce) {
  html[data-quizskin] .q-game .q-gate-fade { animation: none; }
}

/* 🔴 THE GATE USES THE NEXT BUTTON AT HALF SIZE, AND EVERYTHING ABOUT IT WAS
 * TUNED FOR FULL WIDTH. `.q-next` is 74px tall and spans the card everywhere
 * else; here it is 160x60 beside a No. Andrew, 2026-09-01: "the shadow behind
 * it looks too much. They should have the same shadow."
 * Measured: the canvas carried drop-shadow 0 10px 24px at 45% plus 0 2px 3px at
 * 50%, against the No's single 0 7px 0 at 16%. At full width that pair reads as
 * the page's one CTA lifting off the card; at half width beside a peer it reads
 * as one button shouting.
 * ⚠️ SCOPED TO THE GATE, via the attribute only these two buttons carry. The
 * unscoped values are the mock's own and a test pins them, because since the
 * feather came out of the artboard this rule is the only thing drawing them on
 * every other screen. */
html[data-quizskin] .q-game .q-next[data-q-gate] { height: 60px; }
/* 🔴 NO CSS SHADOW ON THE YES AT ALL. Andrew, 2026-09-01: "I'm just trying to
 * figure out why there is... two shadows in the yes button... the yes button
 * should only have one shadow underneath, the same one that matches the colors."
 * The artboard already draws a base, and it is the teal-to-violet run. Adding a
 * grey one under it was giving this button two, which is what he counted. The
 * grey one is the NO's base and it is over there now.
 * ⚠️ Only at the gate. Everywhere else `.q-next` is the page's single CTA at full
 * width and keeps the two drop-shadows the mock specifies, which a test pins. */
html[data-quizskin] .q-game .q-next[data-q-gate] > canvas[data-rive-skin] {
  /* ⚠️ `opacity(1)`, NOT `none`, and it is a compositing fix rather than a look.
   * Andrew's phone, 2026-09-01: a white rectangle appeared behind the pill the
   * moment this said `none`, and it does not reproduce in headless webkit here.
   * The canvas is a FIXED 420x190 centred on a 160x60 button (NEXT in
   * rive-skin.js), so most of it is empty, and it reads transparent on this box:
   * the corner pixel samples rgba(0,0,0,0) and build-next.py deletes the default
   * artboard fill, so there is no background in the file either.
   * What changed is the compositing path. Any non-`none` filter promotes the
   * canvas to its own layer; dropping to `none` let it composite inline, and iOS
   * rasterised the empty area opaque. `opacity(1)` restores the layer and draws
   * nothing, so the button still has the single coloured base he asked for.
   * ⚠️ UNVERIFIED ON HIS DEVICE. It cannot be reproduced here, so this is the
   * likely cause and not a measured one. If the rectangle survives, the next
   * suspect is the canvas size, and the fix there is a real one: clip the canvas
   * to what the artboard actually draws instead of its full 420x190. */
  filter: opacity(1);
  /* 🔴 ATTEMPT TWO ON THE WHITE RECTANGLE. `opacity(1)` alone did not close it:
   * Andrew, 2026-09-01, "still seeing that white rectangle mainly inside of this
   * chat when I pull up the link, but I did see it for a slight second" in
   * Safari. Persistent in an in-app webview, a flash in Safari, invisible in
   * headless webkit here.
   * So stop relying on the empty area compositing correctly and REMOVE it. The
   * canvas is a fixed 420x190 centred on a 160x60 button, which is 5x the area
   * the artboard ever draws into. This clips it back to a centred band that
   * still contains the whole pill and its base.
   * ⚠️ ASYMMETRIC ON PURPOSE. The artboard draws its rim +3.1 to +55.6 inside a
   * 60px box and hangs the base to +62.6, so the drawn mass sits BELOW centre. A
   * symmetric inset clips the base off; this leaves 12px more at the bottom.
   * ⚠️ Percentages, so it follows the canvas at any button width. */
  clip-path: inset(calc(50% - 40px) calc(50% - 92px) calc(50% - 52px));
}
/* Its CSS rest state is the same story: built at 74px full width, it draws a box
 * that does not match the artboard about to replace it, and the mismatch is
 * visible for the whole wasm wait. Andrew: "there's a box behind one now that is
 * visible... once it's fully loaded, it's not there." */
html[data-quizskin] .q-game .q-next[data-q-gate]:not([data-rive-ready]) {
  border-radius: 999px;
}
html[data-quizskin] .q-game .q-next[data-q-gate]:not([data-rive-ready])::before,
html[data-quizskin] .q-game .q-next[data-q-gate]:not([data-rive-ready])::after {
  border-radius: 999px;
}

/* Financing, on the ladders that have it. ONE CARD with a gradient rim, header
 * and rows in the same box. Andrew, 2026-09-01: "the financing available should
 * all be a gradient, and then the gradient should be around that... that should
 * all be one uniform card."
 * ⚠️ TWO-LAYER BACKGROUND, not a border-image: padding-box carries the card's own
 * face and border-box carries the run, so the rim is the teal-to-violet the Next
 * button draws and the inside stays the same glass as every other row here.
 * ⚠️ This is the ONE place colour appears outside the Next button and the trail,
 * and it earns it: it is the answer to the biggest number on the screen. */
html[data-quizskin] .q-game .q-fin-card {
  margin-top: 10px;
  border: 1.5px solid transparent;
  border-radius: 16px;
  background:
    linear-gradient(180deg, #FFFFFF 0%, #F7F6FA 100%) padding-box,
    linear-gradient(90deg, #9945FF 0%, #A0C7FF 100%) border-box;
  overflow: hidden;
}
html[data-quizskin] .q-game .q-fin {
  display: flex; align-items: center; justify-content: space-between;
  width: 100%; padding: 12px 14px;
  border: 0; background: none; cursor: pointer; text-align: left;
  font: 800 14px/1.2 'Nunito', system-ui, sans-serif;
}
/* Only the RIM carries the run. Andrew, 2026-09-01: the label is the regular
   text colour, and so is the chevron. */
html[data-quizskin] .q-game .q-fin-title { color: #12102B; }
html[data-quizskin] .q-game .q-fin-chev {
  flex: none; width: 9px; height: 9px;
  border-right: 2.2px solid #12102B; border-bottom: 2.2px solid #12102B;
  transform: rotate(45deg) translate(-2px, -2px); transition: transform .2s ease;
}
html[data-quizskin] .q-game .q-fin[aria-expanded="true"] .q-fin-chev {
  transform: rotate(225deg) translate(-2px, -2px);
}
html[data-quizskin] .q-game .q-fin:focus-visible {
  outline: 3px solid #9945FF; outline-offset: -3px;
}
/* The open panel stays the card's own light face. Andrew, 2026-09-01: "I don't
   want it to pop out dark, I want it to be light, just inside of that container." */
html[data-quizskin] .q-game .q-fin-rows {
  list-style: none; margin: 0; padding: 2px 14px 0; display: grid; gap: 7px;
  animation: q-gate-in .3s cubic-bezier(.22,.61,.36,1) both;
}
html[data-quizskin] .q-game .q-fin-rows li {
  display: flex; align-items: baseline; justify-content: space-between; gap: 10px;
  font: 700 13px/1.5 'Nunito', system-ui, sans-serif; color: #12102B;
}
html[data-quizskin] .q-game .q-fin-for { color: #6E6A93; }
html[data-quizskin] .q-game .q-fin-amt { font-weight: 800; white-space: nowrap; }
html[data-quizskin] .q-game .q-fin-mo { font-weight: 700; color: #6E6A93; }
html[data-quizskin] .q-game .q-fin-foot {
  font: 700 11.5px/1.35 'Nunito', system-ui, sans-serif; color: #8A86A0;
  text-align: center; margin: 0; padding: 9px 14px 12px;
}
@media (prefers-reduced-motion: reduce) {
  html[data-quizskin] .q-game .q-fin-rows { animation: none; }
  html[data-quizskin] .q-game .q-fin-chev { transition: none; }
}

html[data-quizskin] .q-game .q-gate-ask {
  font: 800 16px/1.3 'Nunito', system-ui, sans-serif;
  color: #12102B; text-align: center; margin: 14px 0 0;
}
/* ⚠️ A SENTENCE SURVIVES HERE, and the rule is not broken. Andrew, 2026-08-31:
 * ring the field, say nothing. That holds WHERE THERE IS A FIELD to point at.
 * This is a consequence of a button, and a consequence has to be written. */
html[data-quizskin] .q-game .q-gate-note {
  font: 700 12.5px/1.4 'Nunito', system-ui, sans-serif;
  color: #6E6A93; text-align: center; margin: 12px 0 0;
}

/* ── the trail ──────────────────────────────────────────────────────────────
 * CSS, not Rive, and deliberately. gdkc-trail.riv has FOUR discs because the
 * approved mock has four; the engine's trail is per PHASE and phaseTotal is 5
 * for questions, 4 for capture and 3 for extra. An artboard cannot change how
 * many nodes it has, so using it here draws the wrong count on most screens.
 * Making it N-up is the next Rive job on this arm.
 *
 * ⚠️ Nothing here may assume a count. The first attempt spaced the discs with a
 * fixed 66px margin, which is right at four and overflows the card at five: node
 * 5 was clipped by the card's edge. space-between and one full-width run are
 * count-independent by construction.
 *
 * The run is a single teal to violet gradient across the whole trail, revealed
 * up to --q-phase-progress (motion.js writes it), over a grey track. The 7px
 * clearance the design asks for is punched by a ring in the card's own colour
 * around each disc, because the bar is continuous underneath.
 */
/* ⚠️ dev-skin.css is loaded by head.html on EVERY landing page and styles
   .q-node as a 4px bar at opacity .18 / .5. Those two properties have to be
   named here or the discs render as ghosts: an unset property is not an
   overridden one, however specific the rest of the rule is. */
html[data-quizskin] .q-game .q-trail {
  position: relative; display: flex; align-items: center;
  justify-content: space-between; height: 28px; gap: 0;
  counter-reset: q-node;
}
html[data-quizskin] .q-game .q-trail::before,
html[data-quizskin] .q-game .q-trail::after {
  content: ''; position: absolute; top: 50%; transform: translateY(-50%);
  left: 0; height: 4px; border-radius: 99px;
}
html[data-quizskin] .q-game .q-trail::before { right: 0; background: #DCD9E4; }
html[data-quizskin] .q-game .q-trail::after {
  /* ⚠️ --q-trail-progress, NOT --q-phase-progress. The phase one resets on the
     screen the discs keep counting through; see trailHtml in index.js. */
  width: calc(var(--q-trail-progress, 0) * 100%);
  background: linear-gradient(90deg, #07EDBE 0%, #9945FF 100%);
  background-size: 100% 100%;
  background-attachment: local;
}
html[data-quizskin] .q-game .q-node {
  counter-increment: q-node;
  position: relative; z-index: 1; flex: none;
  width: 28px; height: 28px; border-radius: 50%;
  display: grid; place-items: center;
  font: 900 12px/1 'CeraRound', sans-serif;
  opacity: 1;
  background: #EFEDF3; color: #B6B2C2;
  box-shadow: 0 0 0 7px #FCFBFD,
              inset 0 1px 0 #fff, inset 0 -1.5px 2px rgba(90,86,110,.16),
              0 1px 2px rgba(5,4,16,.12);
}
html[data-quizskin] .q-game .q-node::before { content: counter(q-node); }
html[data-quizskin] .q-game .q-node.is-done,
html[data-quizskin] .q-game .q-node.is-now {
  opacity: 1;
  background: #12102B; color: #FFFFFF;
  box-shadow: 0 0 0 7px #FCFBFD,
              inset 0 1px 0 rgba(255,255,255,.18), 0 1px 3px rgba(5,4,16,.40);
}

/* .q-body has no gap of its own, so the heading block sits directly on the first
   chip and the Head artboard's canvas, which is taller than its box so the text
   can never clip, laps 16px into it. */
html[data-quizskin] .q-game .q-body { display: flex; flex-direction: column; gap: 17px; }

/* Disabled has to be visible on a control the browser no longer paints. It also
   must not depend on dev-skin.css, which is a placeholder and will be deleted. */
/* ⚠️ GREYED, not just dimmed. `opacity: .45` alone on a white pill on a white card does not
   read as unpressable, and Andrew hit exactly that on the calendar: "nothing's happening."
   The colour rim is what makes this button look like the action, so the colour is what has
   to go. Rare now that the first time is preselected, and still reachable on a day with no
   times at all. */
html[data-quizskin] .q-game .q-next[disabled] { opacity: .5; filter: grayscale(1); }

/* A question with no hint is half a heading block. Written by the skin, because
   only it knows whether the artboard was given a hint to draw. */


/* ── the capture form ────────────────────────────────────────────────────────
 * Every box on one screen, then the opt-in under them. Six fields since the dog
 * screen was folded in on 2026-08-31, which is why they needed labels and a
 * two-across row to stay scannable rather than reading as one tall stack.
 * Values are the approved mock's `.fields`, `.row` and `.field label`. */
html[data-quizskin] .q-game .q-form {
  display: grid; grid-template-columns: 1fr 1fr; gap: 9px;
}
/* A field spans the row unless it asked to be half of one. Expressed this way
   round so a new field is full width by default, which is the safe way to be
   wrong: a stray half-width box leaves a hole beside it. */
html[data-quizskin] .q-game .q-field { grid-column: 1 / -1; }
html[data-quizskin] .q-game .q-field.is-half { grid-column: span 1; }

html[data-quizskin] .q-game .q-label {
  /* Wraps, because his own label for the notes box is five words and the tag
     rides beside it. Without this the tag pushes past the card on a narrow
     phone instead of dropping under the words. */
  display: flex; align-items: baseline; gap: 6px; flex-wrap: wrap;
  margin: 0 0 5px 16px;
  font: 800 10.5px/1 'Nunito', system-ui, sans-serif;
  letter-spacing: .10em; text-transform: uppercase; color: #6E6A93;
}
/* 🔴 "Make optional very present." Andrew, 2026-08-31. It used to live inside the
 * placeholder ("More about the situation, optional"), which vanishes the instant
 * somebody types, so the one field they were allowed to leave alone stopped
 * saying so exactly when they were deciding. A tag on the label stays put.
 * Tonal, not chromatic: on this design colour belongs to the Next button and the
 * trail run and nothing else. */
html[data-quizskin] .q-game .q-opt {
  font-size: 9px; font-weight: 800; letter-spacing: .08em;
  color: #B6B2C2; background: #F2F1F5;
  border-radius: 999px; padding: 3px 7px;
  text-transform: uppercase;
}

/* ── the foot: a black back button beside a smaller CTA ─────────────────────
 * Andrew, 2026-08-30: "the send it button a little bit more smaller, and then a
 * back button that's solid black with a white arrow."
 * The Next artboard takes W and H now, so the CTA is sized here and the drawing
 * follows. The arrow is a stroked SVG with round caps, like everything else. */
/* Back and the CTA share a row; a skip goes on its own line under them. Three
   buttons in one row is what the first version did and they overlapped. */
html[data-quizskin] .q-game .q-foot {
  display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin-top: 2px;
}
/* 1 1 0 with min-width 0, not 1 1 auto: `auto` sizes the flex base from the
   CTA's own content, and a long label like "That's about right" then wraps the
   button onto its own line and leaves the back button sitting in a gap. */
html[data-quizskin] .q-game .q-next { height: 60px; flex: 1 1 0; min-width: 0; order: 2; }
html[data-quizskin] .q-game .q-back {
  order: 1; flex: none; width: 50px; height: 50px; padding: 0;
  border: 0; border-radius: 50%; cursor: pointer;
  font-size: 0; color: transparent;
  background: #12102B url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M19 12H6.5'/%3E%3Cpath d='M12 5.5 5.5 12 12 18.5'/%3E%3C/svg%3E") center / 22px 22px no-repeat;
  box-shadow: 0 1px 1px rgba(20,18,40,.14), 0 4px 10px rgba(20,18,40,.18);
  text-decoration: none;
  /* 🔴 NUDGED DOWN 3px, because the BOXES were already perfectly aligned and that
   * is not what the eye reads. Andrew, 2026-08-31: "it looks like the back
   * button's up a little bit."
   * Measured: both flex items centre at exactly the same y, diff 0. But the Next
   * artboard does not fill its box. It draws its rim from +3.1 to +55.6 inside a
   * 60px element and hangs its base to +62.6, so the drawn mass is centred about
   * 3px BELOW the box centre while this circle is centred ON it.
   * ⚠️ So do not "fix" this by touching align-items. The row is aligned; the
   * artboard is offset inside its own box, and 3px is that offset. */
  transform: translateY(3px);
}
/* 🔴 THE PAIR ON THE GATE. Andrew, 2026-09-01: "two buttons next to each other.
 * Yes. That has this gradient border, and then next to it... No. And the other
 * one should be black with white letters."
 * ⚠️ 52.5px AND NUDGED 3px, ALIGNED TO WHAT THE ARTBOARD DRAWS. The Next element
 * is 60px but its artboard draws the pill from +3.1 to +55.6 inside that box, so
 * a 60px black pill beside it reads as taller AND higher. Same measurement the
 * back button is nudged by, and the same rule: do not "fix" it with align-items.
 * ⚠️ order 3, so Yes stays on the left where the gradient is. */
html[data-quizskin] .q-game .q-no {
  position: relative;
  order: 1; flex: 1 1 0; min-width: 0; height: 52.5px;
  border: 0; border-radius: 999px; cursor: pointer;
  background: #FFFFFF; color: #12102B;
  font: 900 19px/1 'CeraRound', 'Nunito', system-ui, sans-serif;
  /* 🔴 AN OUTLINE, BECAUSE SOLID BLACK OUTRANKED THE YES. Andrew, 2026-09-01:
   * "now the no button looks too dominant... just do an outline for that one...
   * it just needs to dominate the space a little less."
   * ⚠️ It KEEPS the base, which is what fixed the balance an hour earlier: the
   * Yes artboard draws its rim +3.1 to +55.6 and hangs a base to +62.6, so a
   * flat pill beside it reads as the lighter of the two. Outline is about
   * WEIGHT, the base is about MASS, and dropping the base to get the weight down
   * would put the earlier bug straight back.
   * ⚠️ Same 2px #12102B ink the chips draw at rest, so the ring on this button
   * is the one ring this whole design uses. Zero blur on the base copy: a
   * blurred one is a shadow and reads as one. */
  /* 🔴 ONE FILLED BASE, AND THE FILL IS WHAT MAKES IT ONE. Andrew, 2026-09-01:
   * "there's a line clearly above the gray line above the no... because it's two
   * overlapping pills. There should be a white fill inside the no button."
   * He is describing my own fix failing. I made the base a RING to stop it
   * reading as a slab behind a transparent button, and a ring offset 7px down
   * draws its TOP arc inside the button, which is the second pill he can see.
   * Giving the button a fill solves the original problem properly: the base goes
   * back to a filled copy offset down, and the fill hides its top 7px, so what
   * shows is the 7px under the bottom edge and nothing else. That is the recipe
   * every other control here uses. Depth is a SHAPE, and a shape needs something
   * opaque in front of it. */
  box-shadow: inset 0 0 0 2px #12102B,
              0 7px 0 rgba(18,16,43,.16);
  transform: translateY(3px);
}
html[data-quizskin] .q-game .q-no:focus-visible {
  outline: 3px solid #9945FF; outline-offset: 3px;
}
html[data-quizskin] .q-game .q-skip { order: 3; flex: 1 0 100%; text-align: center; }

/* The price ladder. Rows, not prose: the label on the left, the number on the
   right, the number doing the talking. */
html[data-quizskin] .q-game .q-prices { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }
/* 🔴 A ROW IS A BUTTON NOW. Andrew, 2026-08-31: "there's nothing to really press
 * on screen. It's just that next button, and I think that's gonna trip people
 * up." So the rows take the card's own glass recipe and its ink ring, the same
 * one the chips and the day tiles use, which is what makes them read as
 * tappable rather than as a table somebody styled. */
html[data-quizskin] .q-game .q-price {
  width: 100%; border: 0; cursor: pointer; text-align: left;
  -webkit-tap-highlight-color: transparent; touch-action: manipulation;
  display: flex; align-items: baseline; justify-content: space-between;
  padding: 13px 16px; border-radius: 18px;
  color: #12102B;
  background: linear-gradient(180deg, #FFFFFF 0%, #F7F6FA 100%);
  box-shadow: inset 0 0 0 2px #12102B,
              inset 0 1.2px 0 rgba(255,255,255,1),
              inset 0 -1.5px 2px rgba(90,86,110,.10),
              0 3px 0 #A6A1B3,
              0 5.5px 0 #BFBBCD;
}
/* Chosen: the ink panel the day tiles and time slots already use, not a second
   idea. Tonal and not chromatic, because colour on this design belongs to the
   Next button and the trail run. */
html[data-quizskin] .q-game .q-price.is-selected {
  background: #12102B;
  box-shadow: inset 0 1px 0 rgba(255,255,255,.14), 0 1px 3px rgba(5,4,16,.40);
}
html[data-quizskin] .q-game .q-price.is-selected .q-price-amt { color: #FFFFFF; }
html[data-quizskin] .q-game .q-price.is-selected .q-price-for { color: rgba(255,255,255,.72); }
html[data-quizskin] .q-game .q-price.is-selected .q-price-runs { color: rgba(255,255,255,.48); }
html[data-quizskin] .q-game .q-price:focus-visible {
  outline: 3px solid #9945FF; outline-offset: 3px;
}
/* 🔴 "Make optional very present." Andrew, 2026-08-31. Above the ladder, not
 * under the button: the decision is being made while the eye is on the prices,
 * so that is where the permission to skip has to be. */
html[data-quizskin] .q-game .q-sec-opt {
  color: #6E6A93; background: #F2F1F5;
  border-radius: 999px; padding: 4px 10px;
  justify-self: start; align-self: start;
  margin: 0 0 2px 0;
}
html[data-quizskin] .q-game .q-price-for {
  font: 700 14px/1 'Nunito', system-ui, sans-serif; color: #6E6A93;
  display: grid; gap: 4px;                 /* the run sits under the count, not beside it */
}
/* How long the package actually runs. Andrew, 2026-08-31. Quieter than the count above it
   and quieter again than the price, so the row still reads count then money. */
html[data-quizskin] .q-game .q-price-runs {
  font: 700 11.5px/1 'Nunito', system-ui, sans-serif; color: #B6B2C2;
}
html[data-quizskin] .q-game .q-price-amt {
  font: 900 20px/1 'CeraRound', sans-serif; color: #12102B;
}

/* ── screen 5: the calendar ─────────────────────────────────────────────────
 * Every value below is measured off the approved mock (rive-lab
 * examples/gdkc-quiz, quiz-final.html?screen=book). Nothing here is a new
 * decision, and the day tiles and time pills reuse the card's own raised-glass
 * recipe rather than inventing a third one.
 *
 * ⚠️ CSS and not Rive, deliberately, same reason as the trail: how many days and
 * how many times exist is decided by Andrew's actual calendar at run time, and
 * an artboard cannot change how many children it has. Skinning these is a Rive
 * job once the counts stop moving.
 */
/* ⚠️ Rebalanced. Andrew, 2026-08-30: "available times is like it just needs a
 * rebalance for everything... the spacing is just kind of all over the place."
 * `q-body` puts a flat 17px between every child, which is right between a heading
 * and a grid and far too much between a LABEL and the grid it names. A label and
 * its grid are one block, so the label is pulled to 6px off its own grid and the
 * space is spent between the two blocks instead, where it does some work. */
html[data-quizskin] .q-game .q-sec {
  margin: 0 0 6px 4px;
  font: 800 9.5px/1 'Nunito', system-ui, sans-serif;
  letter-spacing: .13em; text-transform: uppercase; color: #B6B2C2;
}
html[data-quizskin] .q-game .q-sec + .q-days,
html[data-quizskin] .q-game .q-sec + .q-slots { margin-top: -11px; }
/* The second block starts a new thought, so it carries the air the label lost. */
html[data-quizskin] .q-game [data-q-times] { display: contents; }
html[data-quizskin] .q-game [data-q-times] .q-sec { margin-top: 0; }

/* ── the day row: three days between two arrows ──────────────────────────────
 * Andrew, 2026-08-31: "let's add a arrow to the left and to the right... the
 * calendar should be left and right", and on how many days, "arrows plus 2-3
 * days". Three tiles sit wider here than the four that were there, so the card
 * kept its 344px and did not need the widening he offered.
 * The row that unfolded all 26 days at once is gone with its chevron. */
html[data-quizskin] .q-game .q-daynav {
  display: grid; grid-template-columns: 34px 1fr 34px; align-items: center; gap: 4px;
}
html[data-quizskin] .q-game .q-days { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }
html[data-quizskin] .q-game .q-arrow {
  display: grid; place-items: center;
  width: 34px; height: 34px; padding: 0;
  border: 0; border-radius: 50%; background: none; cursor: pointer;
  color: #6E6A93;
  -webkit-tap-highlight-color: transparent; touch-action: manipulation;
}
html[data-quizskin] .q-game .q-arrow:active { color: #12102B; }
/* ⚠️ DIMMED AND STILL THERE, never hidden. An arrow that disappears at the ends
   moves the whole day row sideways by its own width on the first and last page,
   which is the row jumping under the thumb that is about to tap it. */
html[data-quizskin] .q-game .q-arrow[disabled] { color: #DCD9E4; cursor: default; }
html[data-quizskin] .q-game .q-arrow:focus-visible {
  outline: 3px solid #9945FF; outline-offset: 2px;
}
/* The label above the row spans the whole nav, arrows included, so it does not
   sit over the left arrow only. */
html[data-quizskin] .q-game .q-sec + .q-daynav { margin-top: -11px; }
html[data-quizskin] .q-game .q-slots { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }

/* ⚠️ THE ARTBOARD DRAWS THE BODY, this file draws the TEXT. Andrew, 2026-08-30:
 * they "have no bounce like the button we had already created". So they go
 * through the same glass path the chips take and get the press for free, and
 * what is left here is the box, the geometry the artboard reads off it, and the
 * labels. Nothing below paints a control.
 *
 * ⚠️ Neither is made transparent, unlike a chip. Both mount with an EMPTY label:
 * a day tile is three lines and Glass takes one Label string, and a time slot is
 * centred in the mock while the artboard draws its label at PadL from the left.
 * So the text stays HTML and sits over the canvas. */
html[data-quizskin] .q-game .q-day,
html[data-quizskin] .q-game .q-slot {
  position: relative;
  border: 0; padding: 0;
  -webkit-tap-highlight-color: transparent; touch-action: manipulation;
  --q-pad-l: 0; --q-pad-r: 0; --q-text-r: 0; --q-text-size: 1; --q-lines: 1;
}
html[data-quizskin] .q-game .q-day[data-rive-ready],
html[data-quizskin] .q-game .q-slot[data-rive-ready] {
  background: none; box-shadow: none;
}
/* 🔴 The canvas is position:absolute and a label is not, so without this the
   canvas paints OVER the text: a positioned element beats a static one whatever
   the source order. Both controls would render as blank pills. */
html[data-quizskin] .q-game .q-day > span,
html[data-quizskin] .q-game .q-slot > span { position: relative; z-index: 1; }

html[data-quizskin] .q-game .q-slot {
  height: 46px; --q-radius: 23;
  display: grid; place-items: center;
}
/* This one names a real family, so the shorthand is valid. Kept explicit anyway
   so the two labels on this screen read the same way in the file. */
html[data-quizskin] .q-game .q-slot > span {
  font-family: 'Nunito', system-ui, sans-serif; font-weight: 800;
  font-size: 14.5px; line-height: 1; color: #12102B;
}

/* ⚠️ Andrew, 2026-08-30: "for the next available part, Monday, August, the
 * spacing is just off." It was: a 76px box with three centred lines and a flat
 * 3px gap put the number nowhere in particular and left the two labels floating.
 * The number is the thing being read, so it gets the optical centre and the two
 * label lines sit tight against it. `gap` is gone, because equal gaps around
 * lines of 10px, 20px and 8.5px are not equal to the eye. */
html[data-quizskin] .q-game .q-day {
  height: 68px; --q-radius: 18;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  font-family: 'CeraRound', sans-serif;
}
/* 🔴 LONGHANDS, not the `font:` shorthand. `font: 900 9.5px/1 inherit` is INVALID:
 * `inherit` is not a family name, so the whole declaration is dropped, and with
 * it the line-height. Each of these three spans was a 22.5px line box holding
 * 9.5px of text, which is why the day tile's content was 40px taller than it
 * looked and spilled out of the 68px box. Measured, not guessed: 22.5 / 27 / 22.5
 * against a stated line-height of 1. */
html[data-quizskin] .q-game .q-day-dow,
html[data-quizskin] .q-game .q-day-num,
html[data-quizskin] .q-game .q-day-mon { font-family: inherit; font-weight: 900; line-height: 1; }
html[data-quizskin] .q-game .q-day-dow { font-size: 9.5px; letter-spacing: .09em; color: #B6B2C2; }
html[data-quizskin] .q-game .q-day-num { font-size: 22px; color: #12102B; margin: 5px 0 4px; }
html[data-quizskin] .q-game .q-day-mon { font-size: 8.5px; letter-spacing: .09em; color: #B6B2C2; }

/* ── the chosen one ─────────────────────────────────────────────────────────
 * Andrew, 2026-08-30: "instead of check marks in these areas, we need to have it
 * kind of highlighted or something. I don't want the check marks." The check is
 * off at the artboard (ShowCheck false), and Picked on its own is a deeper inner
 * shadow and a slightly thicker ring, which at 71px does not read as chosen.
 *
 * So the highlight is an ink panel with the label knocked out white, which is the
 * trail's own active-node treatment: dark disc, white number. Tonal and not
 * chromatic, because on this design colour belongs to the Next button and the
 * trail run and nothing else.
 *
 * ⚠️ It does NOT travel with the press. The artboard's face dips 6px and springs
 * back; this panel is on the element, so for ~100ms its edge sits still while the
 * face moves under it. Doing it properly means binding the face's own fill to a
 * new bool in build-glass.py so the chips keep their look, which is a third Glass
 * rebuild. Andrew's call whether the artifact is worth it. */
html[data-quizskin] .q-game .q-day.is-selected::after,
html[data-quizskin] .q-game .q-slot.is-selected::after {
  content: ''; position: absolute; inset: 0; z-index: 1; pointer-events: none;
  border-radius: inherit; background: #12102B;
  box-shadow: inset 0 1px 0 rgba(255,255,255,.14), 0 1px 3px rgba(5,4,16,.40);
}
html[data-quizskin] .q-game .q-day.is-selected { border-radius: 18px; }
html[data-quizskin] .q-game .q-slot.is-selected { border-radius: 999px; }
/* 🔴 OFF WHILE THE FACE IS NOT HOME. The panel is on the element and the artboard's face
 * dips 3.5px and eases back, so a static panel leaves the artboard's own light body showing
 * under its bottom edge for the whole travel: the white hairline Andrew saw coming down and
 * going back up. `is-landing` is set on pointerdown and cleared 170ms after release, in
 * rive-skin.js `press()`. The pill presses as plain glass and the ink lands with the face.
 * ⚠️ Do NOT replace this with a transform that chases the press. CSS has no elastic easing
 * and the face squashes on one, so a mirror leaves residue; measured, both directions. */
html[data-quizskin] .q-game .q-day.is-landing::after,
html[data-quizskin] .q-game .q-slot.is-landing::after { opacity: 0; }

/* 🔴 Above the panel, which is z-index 1 and paints after them in source order. */
html[data-quizskin] .q-game .q-day.is-selected > span,
html[data-quizskin] .q-game .q-slot.is-selected > span { z-index: 2; }
html[data-quizskin] .q-game .q-slot.is-selected > span { color: #FFFFFF; }
html[data-quizskin] .q-game .q-day.is-selected .q-day-num { color: #FFFFFF; }
html[data-quizskin] .q-game .q-day.is-selected .q-day-dow,
html[data-quizskin] .q-game .q-day.is-selected .q-day-mon { color: rgba(255,255,255,.62); }

/* 🔴 Nothing shows until its own artboard has drawn into it. Under `is-rive`
 * these controls have no background of their own, so between render and the
 * canvas's first frame a tile is bare text with no pill: "I see the HTML
 * version, and then it flips into the live version" (Andrew, 2026-08-30).
 * rive-skin.js stamps data-rive-ready in the artboard's own onLoad, so a control
 * appears finished or not at all.
 * ⚠️ visibility, not display: the box still takes its space, so nothing below it
 * moves when the artboard lands. */
/* Nothing is hidden any more: an unmounted tile paints its own rest state above,
   and the artboard replaces it in place. The old rule hid the tile until its
   canvas drew, which was correct when the alternative was bare text on no pill
   and is now just a slower way to show the same thing. */

/* ⚠️ A CHEVRON, not the word "More". Andrew, 2026-08-30: "the underlying More
 * are getting kind of a little bit too much... it should just be like an arrow or
 * slider or something. A little bit more visual, less words." Two underlined
 * words on a screen that already carries two section labels and ten controls were
 * reading as a third kind of thing to decide about. The word survives as the
 * button's aria-label, so it is still announced.
 * ⚠️ align-self, not justify-self: q-body is a flex COLUMN, so justify-self is
 * inert there and the control would sit full width against the left edge. */
html[data-quizskin] .q-game .q-more {
  display: grid; place-items: center; align-self: center;
  width: 30px; height: 20px; margin: -11px 0 -9px; padding: 0;
  border: 0; background: none; cursor: pointer; color: #B6B2C2;
  -webkit-tap-highlight-color: transparent;
}
html[data-quizskin] .q-game .q-more:active { color: #6E6A93; }
/* Open, the same arrow points back at the list it will close. Andrew, 2026-08-31. */
html[data-quizskin] .q-game .q-more svg { transition: transform .18s cubic-bezier(.2,.7,.3,1); }
html[data-quizskin] .q-game .q-more.is-open svg { transform: rotate(180deg); }

/* Waiting for the calendar. Roughly one row of days plus three rows of times,
   so the CTA does not jump when they arrive. */
html[data-quizskin] .q-game .q-wait { min-height: 250px; }

html[data-quizskin] .q-game .q-day:focus-visible,
html[data-quizskin] .q-game .q-slot:focus-visible,
html[data-quizskin] .q-game .q-more:focus-visible {
  outline: 3px solid #9945FF; outline-offset: 3px;
}

/* In flight. The CTA is already disabled by the time this shows, so this only
   has to say "something is happening" on a button the browser no longer
   paints. */
html[data-quizskin] .q-game .q-next.is-busy { opacity: .45; }

/* ── the finale ─────────────────────────────────────────────────────────────
 * Andrew, 2026-08-30: the booked screen "needs to mainly focus on having a big
 * white space for the Pawesome final animation." A square that keeps its size
 * whatever fills it, so swapping the sticker for an artboard moves nothing under
 * it, and so the card does not resize mid-animation.
 *
 * ⚠️ aspect-ratio and not a height: the card is 344px on a phone and wider on a
 * desktop, and a fixed height would letterbox the art on one of them. */
html[data-quizskin] .q-game .q-finale {
  width: 100%; aspect-ratio: 1 / 1;
  display: grid; place-items: center;
  margin: 4px 0 2px;
}
html[data-quizskin] .q-game .q-finale-art {
  display: block; width: 100%; height: 100%;
  object-fit: contain;
}
/* ⚠️ `display: block` above BEATS the `hidden` attribute, which is a presentation
   default and loses to any rule that names display. Without this the canvas draws
   over the sticker before the artboard has mounted. */
html[data-quizskin] .q-game .q-finale-art[hidden] { display: none; }

/* The confirmation. `q-plan-head` and `q-hint` are already styled above; the
   time is the one thing on the screen that has to be unmissable. */
html[data-quizskin] .q-game .q-hint strong { font-weight: 900; color: #12102B; }

/* The opt-in as a note under the button. Small, grey, and immediately adjacent
   to the control that records it, which is what makes consent-by-continue hold. */
html[data-quizskin] .q-game .q-consent-note {
  flex: 1 0 100%; order: 4; margin: 2px 0 0;
  font: 600 11px/1.45 'Nunito', system-ui, sans-serif;
  color: #6E6A93; text-align: center;
}


/* ══ THE REST STATE ═══════════════════════════════════════════════════════════
 * What the browser draws until each artboard has drawn, and what it keeps
 * drawing forever if one never arrives.
 *
 * ⚠️ EVERY VALUE BELOW IS A PORT, NOT A DECISION. The source is rive-lab
 * examples/gdkc-quiz/quiz-final.html, the design Andrew approved on 2026-08-29,
 * and specifically its `.g` / `.g.on` recipe, `.chip`, `.next` and `.next-face`.
 * build-glass.py and build-next.py were compiled from that same file, which is
 * the whole reason the handover is invisible: the two are not eyeballed to
 * match, they have one source. Changing a number here without changing it there
 * puts a visible step back into the flip.
 *
 * ⚠️ Geometry comes off the --q-* custom properties rather than being repeated,
 * so a chip that changes shape (one column vs two-across) changes shape in both
 * states at once. Those are the same numbers the artboard is handed by geom()
 * in rive-skin.js, which is what keeps them honest.
 */

/* ── the one glass recipe every tappable thing uses (quiz-final.html `.g`) ── */
html[data-quizskin] .q-game .q-chip,
html[data-quizskin] .q-game .q-consent,
html[data-quizskin] .q-game .q-day,
html[data-quizskin] .q-game .q-slot {
  color: #12102B;
  background: linear-gradient(180deg, #FFFFFF 0%, #F7F6FA 100%);
  /* 🔴 THE BASE IS A SHAPE, NOT A SHADOW, and reading it as one is why the first
   * attempt was 100 levels light. Below the ink ring the artboard draws 6px of
   * dark that ENDS ABRUPTLY and is inset at the corners exactly as a pill of the
   * same radius would be: it is the chip's own body, offset down and showing
   * under it, the same construction the Next button's base uses.
   * Two hard offset copies rather than a gradient because a box-shadow with zero
   * blur and zero spread IS the border-box shape redrawn lower, radius included,
   * and stacking two of them steps the colour the way the artboard ramps it.
   * Sampled down the middle of a chip on a 2x phone: #9490A2 at the ring falling
   * to #C7C3D4 at the cut, so each copy takes the mean of its own 3px band.
   * ⚠️ AND NO AMBIENT SHADOW UNDER IT. The mock's `.g` carries one and the
   * artboard draws none: two pixels past the cut the card is back to its own
   * colour, measured. Keeping the mock's `0 4px 10px` put a grey haze under all
   * twelve chips that lifted on the handover. */
  box-shadow: inset 0 0 0 2px #12102B,
              inset 0 1.2px 0 rgba(255,255,255,1),
              inset 0 -1.5px 2px rgba(90,86,110,.10),
              0 3px 0 #A6A1B3,
              0 5.5px 0 #BFBBCD;
}
/* ⚠️ THE INK RING IS NOT IN THE MOCK, AND THE SHIPPED ARTBOARD IS RIGHT.
 * quiz-final.html `.g` has no ring at rest; only `.g.on` does. The Glass artboard
 * draws one on every control, and Andrew's 2026-08-31 note says why: the white
 * Glass rim came out "on purpose so the outline is one weight all the way round".
 * The artboards moved on from the mock here and nothing wrote it down.
 * Measured off the shipped artboard rather than taken from either: 3 solid device
 * pixels plus antialiasing on both sides, on a 2x phone, sampled at the left,
 * right, top and bottom edge of a chip, and the colour is exactly #12102B
 * (18,16,43). So: 2 CSS px, inset, one weight all the way round. */
/* `.g.on`: a deeper inner shadow and a 2px ink ring. The day tiles and time
   slots do NOT take this, because their chosen state is the ink panel further
   up and taking both would draw a ring inside a filled tile. */
/* 🔴 `:not([data-rive-ready])`, AND IT IS NOT BELT AND BRACES. Without it this
 * rule TIES the handover block on specificity, and it sits later in the file, so
 * it wins: a selected chip kept painting its own ring and its own base under a
 * live artboard. press-sweep.mjs caught it as a 5px band across 260 columns from
 * down+2 to down+7, which is exactly the white-edge bug in a new place. The face
 * dips on press, the CSS ring does not move, and the artboard's light body shows
 * between them.
 * ⚠️ Any future rest-state rule that carries a class must carry this too. A plain
 * `.q-chip` rule is a specificity below the handover and safe; anything with a
 * second class is level with it and is decided by source order, which is not a
 * thing to leave to chance. */
html[data-quizskin] .q-game .q-chip.is-selected:not([data-rive-ready]),
html[data-quizskin] .q-game .q-consent.is-selected:not([data-rive-ready]) {
  background: linear-gradient(180deg, #FFFFFF 0%, #EFEDF3 100%);
  box-shadow: inset 0 1.2px 0 rgba(255,255,255,1),
              inset 0 -2px 3px rgba(90,86,110,.16),
              inset 0 0 0 2px #12102B,
              0 1px 1px rgba(20,18,40,.14),
              0 5px 14px rgba(20,18,40,.14);
}

/* ── chips and the consent card ─────────────────────────────────────────────
   padding-right is --q-text-r, not --q-pad-r: the first is where the LABEL has
   to stop so the check has somewhere to sit, which is what the mock's 40px is,
   and the second is the artboard's own inset. */
html[data-quizskin] .q-game .q-chip,
html[data-quizskin] .q-game .q-consent {
  display: flex; align-items: center; text-align: left;
  border-radius: calc(var(--q-radius, 24) * 1px);
  padding: 0 calc(var(--q-text-r, 40) * 1px) 0 calc(var(--q-pad-l, 16) * 1px);
  /* ⚠️ Every one of these four reads the same custom property geom() reads in
     rive-skin.js, so the browser lays the label out in the artboard's own box.
     --q-line and --q-text-weight default to 1.25 and 700 THERE, so they default
     to the same here; 1.2 was close enough to look right and moved every
     two-line label 3px on the handover. */
  font-family: 'Nunito', system-ui, sans-serif;
  font-weight: var(--q-text-weight, 700);
  font-size: calc(var(--q-text-size, 14.5) * 1px);
  line-height: var(--q-line, 1.25);
}
/* A paragraph, so it takes the top of its box and the line-height of prose. */
html[data-quizskin] .q-game .q-consent {
  align-items: flex-start;
  padding-top: 14px; padding-bottom: 14px;
  line-height: 1.45;
}

/* ── day tiles and time slots ───────────────────────────────────────────────
   Radius only: their layout, their fonts and their labels are already set above
   and are HTML in both states, because Glass takes one Label string and a day
   tile is three lines. */
html[data-quizskin] .q-game .q-day { border-radius: calc(var(--q-radius, 18) * 1px); }
html[data-quizskin] .q-game .q-slot { border-radius: calc(var(--q-radius, 23) * 1px); }

/* ── the Next button (quiz-final.html `.next` / `.next-face` / `.next-base`) ──
 * Three layers out of one <button>: the element is the gradient RIM, ::before is
 * the light FACE inset 3.5px, ::after is the dark BASE the face sits on and
 * which shows 7px below it.
 *
 * ⚠️ z-index -1 and -2, and the button carries `z-index: 0` to make a stacking
 * context for them. Without that context a negative pseudo paints below the
 * button's own background instead of between it and the label. With a plain
 * `z-index: 0` pseudo the face would paint OVER the label, because a positioned
 * element beats in-flow content whatever the source order.
 * ⚠️ The two drop shadows are the same pair rive-skin.css puts on the canvas
 * once the artboard takes over, so the button keeps its shadow across the flip.
 * They are box-shadow here and drop-shadow there for the reason written up
 * there: the canvas is wider than what it draws. */
/* ── the Next button (quiz-final.html `.next` / `.next-face` / `.next-base`) ──
 * Three layers out of one <button>: ::before is the RIM with the light FACE
 * inside it, ::after is the dark BASE the face sits on. The element itself paints
 * nothing; it only carries the label.
 *
 * ⚠️ THE NUMBERS ARE MEASURED OFF THE SHIPPED ARTBOARD, not off the mock, and
 * they disagree with it. The mock's `.next` fills its box and hangs its base 7px
 * below. The artboard draws a 52.5px pill inside a 60px box, starting 3.1px down,
 * with the base ending 2.6px below the box. Sampled on a 2x phone down the middle
 * of the button: rim top at +3.1, face at +6.1, rim bottom at +55.6, base from
 * +57.1 to +62.6. Building this to the mock instead put the whole button 3px high
 * and its base 4.5px too long, which is a step you can see on the handover.
 *
 * ⚠️ z-index -1 and -2, and the button carries `z-index: 0` to make a stacking
 * context. Without that context a negative pseudo paints below the button's own
 * background rather than between it and the label; with a plain `z-index: 0` it
 * paints OVER the label, because a positioned element beats in-flow content
 * whatever the source order.
 * ⚠️ The two drop shadows are the pair rive-skin.css puts on the canvas once the
 * artboard takes over, so the button keeps its shadow across the flip. box-shadow
 * here and drop-shadow there, for the reason written up there: the canvas is
 * wider than what it draws. */
html[data-quizskin] .q-game .q-next {
  z-index: 0;
  display: grid; place-items: center;
  padding: 0;
  background: none;
  font: 900 22px/1 'CeraRound', sans-serif;
  letter-spacing: .10em; text-indent: .10em;
  color: #FFFFFF;
  -webkit-text-stroke: 4.5px #12102B;
  paint-order: stroke fill;
}
/* The rim and the face in one box: two background layers, the face clipped to the
   content box and the rim to the border box, with 3.5px of padding between them.
   That is the mock's own 3.5px rim, and it beats a second pseudo-element because
   there are only two and the base needs the other one. */
html[data-quizskin] .q-game .q-next::before {
  content: ''; position: absolute; z-index: -1;
  left: 0; right: 0; top: 3.1px; bottom: 4.4px;
  border-radius: 999px;
  padding: 3.5px;
  background:
    linear-gradient(180deg, #FFFFFF 0%, #F8F7FA 46%, #E9E7EE 100%) content-box,
    linear-gradient(90deg, #07EDBE 0%, #9945FF 100%) border-box;
}
/* The base. Its top is under the rim and never seen; only the 5.5px below the
   pill is, which is what `bottom: -2.6px` against a rim bottom of +55.6 gives. */
/* 🔴 THE SHADOWS LIVE HERE, ON THE BASE, NOT ON THE RIM. Put them on the rim and
 * the rim casts them straight down onto the base, which sits 3px lower and
 * behind: the base read (12,40,49) against the artboard's (23,95,104), a base
 * darkened almost twice over. Measured down the middle of the button. On the base
 * they fall below the button, which is where the design puts them, and nothing
 * the page draws is sitting in them. */
html[data-quizskin] .q-game .q-next::after {
  content: ''; position: absolute; z-index: -2;
  left: 0; right: 0; top: 10px; bottom: -2.6px;
  border-radius: 999px;
  background: linear-gradient(90deg, #07EDBE 0%, #9945FF 100%);
  filter: brightness(.5) drop-shadow(0 10px 24px rgba(5,4,16,.45))
                         drop-shadow(0 2px 3px rgba(5,4,16,.5));
}
/* 🔴 The stroke has to go too. `color: transparent` alone leaves a 4.5px ink
   outline of the label painted over the artboard's own label. */
html[data-quizskin] .q-game .q-next[data-rive-ready] {
  -webkit-text-stroke: 0;
  text-indent: 0;
}

/* == /components/section-header/style.css?v=2 == */
.c-section-header {
  max-width: 760px;
  margin: 0 auto 48px;
}
.c-section-header--center { text-align: center; }
.c-section-header--left { text-align: left; margin-inline: 0; }
.c-section-header__title {
  margin: 0 0 16px;
  font-family: 'CeraRound', 'Cera Round', 'Nunito', sans-serif;
  font-weight: 900;
  /* Shared section-header size (matches "From First Call…" and "You're not alone"). */
  font-size: clamp(38px, 6vw, 60px);
  line-height: 1.1;
  letter-spacing: -0.02em;
  color: var(--text);
  /* Balance multi-line titles so they break evenly ("In-Home Dog Training" /
     "in Kansas City") instead of orphaning a word. */
  text-wrap: balance;
}
.c-section-header__subtitle {
  margin: 0;
  color: rgba(248, 248, 248, 0.55);
  font-family: 'Nunito', system-ui, sans-serif;
  font-weight: 400;
  font-size: 20px;
  line-height: 1.55;
}

@media (max-width: 820px) {
  .c-section-header { margin-bottom: 32px; }
  /* title size now handled by the shared clamp above */
  .c-section-header__subtitle { font-size: 16px; }
}

/* == /components/service-cards/style.css?v=15 == */
/* Service Cards — pixel-port of Paper HS9-0 (Var B: Dots) */
.c-service-cards {
  position: relative;
  background: var(--bg);
  padding: 100px 0 clamp(56px, 9vw, 96px);  /* top padding clears the seam */
  /* The card entrance (motion-core [data-animate="cards"]) nudges each card a
     few px sideways + tilts it before it settles; clip x so a full-width mobile
     card can't flash a horizontal scrollbar mid-animation. x-only keeps the
     seam + peel lift (vertical) unclipped. */
  overflow-x: clip;
}
/* Wider stage than the default 1200 container so four ~302px cards sit with clear
   space from the page edges (≥40px each side). Reset to the default inset on
   mobile so single cards stay full-width. */
/* Stage widened from 1284 to 1320 so the larger 40px inter-card gap doesn't steal
   width from the cards — four ~300px cards still fit, just with more air between. */
.c-service-cards > .container { position: relative; z-index: 1; width: min(100% - 80px, 1320px); }

.c-service-cards__seam {
  position: absolute;
  top: -50px;            /* overflows half its height up into the white above */
  left: 0;
  width: 100%;
  height: 100px;
  display: block;
  pointer-events: none;
  z-index: 2;            /* sit above the section's flat dark bg */
}
.c-service-cards__seam-white { fill: #FFFFFF; }
/* Spoke pages: nothing white sits above this section (the training-in-action
   band is home-only), so the above-the-wave region stays transparent and the
   body squiggle runs right up to the gradient line. */
.c-service-cards__seam--dark-above .c-service-cards__seam-white { fill: transparent; }
.c-service-cards__seam-dark  { fill: var(--bg); }
.c-service-cards__seam-line {
  fill: none;
  /* Use vector-effect so stroke stays a uniform pixel thickness even though
     preserveAspectRatio=none stretches the SVG horizontally to full width. */
  stroke-width: 8;
  vector-effect: non-scaling-stroke;
  stroke-linecap: round;
  stroke-linejoin: round;
  filter: drop-shadow(0 2px 8px rgba(160, 140, 255, 0.5));
}
.c-service-cards__row {
  /* Flex-wrap (was a 4-col grid): with FIVE cards, a strict grid strands the
     odd one out at the left of its row; centered wrapping keeps any short row
     (the 5th card on desktop, the odd card in 2-up) centered instead. Card
     width is pinned to the old 4-col size via flex-basis below. */
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 40px;
  margin: 0 auto;
  /* Stretch all cards in a row to the tallest one so a longer title/copy (e.g.
     Anxiety, Reactivity & Aggression wrapping to an extra line) doesn't make
     that card taller than the rest. */
  align-items: stretch;
}
/* 4-up width (container minus 3 gaps, split 4 ways) — same card size as the
   old grid. */
.c-service-cards__row > .c-service-card { flex: 0 1 calc((100% - 120px) / 4); min-width: 0; }

.c-service-card {
  position: relative;
  width: 100%;
  /* A FLOOR, not a fixed size. A fixed aspect-ratio kept the tall proportion but
     WebKit/Safari refuses to let align-items:stretch override it, so the tallest
     card's content overflowed and its button got clipped. min-height keeps the
     proportion while letting content (and the row's stretch) grow the card taller,
     so no card ever clips its button. */
  min-height: 420px;
  border-radius: 16px;
  border: 8px solid var(--card-color);
  overflow: clip;
  isolation: isolate;
  /* Card-tinted gradient: saturated top → near-black bottom (oklab-equivalent in sRGB) */
  background-image: linear-gradient(180deg, var(--card-top) 0%, var(--card-bottom, #1A1538) 100%);
  /* 3-row vertical rhythm: icon at the top, the words container fills the middle
     (1fr) and centres its copy, and the button is pinned to the bottom. Using auto
     for the icon row (not a % of card height) is what lets the card grow with its
     content instead of fixing the height. (Absolutely-positioned .c-service-card__dots
     is out of flow, so the grid rows only hold icon / body / CTA.) */
  display: grid;
  grid-template-rows: auto 1fr auto;
  justify-items: center;
  align-items: center;
  padding: 18px 16px 18px;   /* space above the icon + below the button */
  box-sizing: border-box;
}
/* Dark cards: near-black with just a hint of the card colour at the top. The
   bright --card-color stays for the border, the icon ring, and the CTA ring. */
/* Five cards sample the site's signature gradient LEFT TO RIGHT (the hero/CTA
   teal -> violet -> pink), so the whole row reads as one fluid fade:
   teal -> blue -> violet -> mid-purple -> pink. */
.c-service-card--teal         { --card-color: #07EDBE; --card-top: #0A373C; --card-bottom: #0B0A1B; }
.c-service-card--blue         { --card-color: #477ED6; --card-top: #16223C; --card-bottom: #0B0A1B; }
.c-service-card--violet       { --card-color: #9945FF; --card-top: #241641; --card-bottom: #0B0A1B; }
.c-service-card--mid-purple   { --card-color: #C77DFF; --card-top: #2C2147; --card-bottom: #0B0A1B; }
.c-service-card--pink         { --card-color: #FF7EC0; --card-top: #3C213C; --card-bottom: #0B0A1B; }

/* Dot pattern — Paper Var B: 8px-radius circles on a 16px grid so adjacent
   circles touch, leaving diamond-shaped negative space at every 4-circle
   junction. Vertical opacity fade mirrors Paper's per-row 0.88 → 0.005 ramp.
   #2C2977 = --navy. */
.c-service-card__dots {
  position: absolute;
  top: -24px; left: -24px;
  width: calc(100% + 48px);
  height: calc(100% + 48px);
  background-image: radial-gradient(circle at 8px 8px, #2C2977 8px, transparent 8.5px);
  background-size: 16px 16px;
  pointer-events: none;
  -webkit-mask-image: linear-gradient(180deg, rgba(0,0,0,0.88) 0%, rgba(0,0,0,0.5) 50%, rgba(0,0,0,0) 100%);
          mask-image: linear-gradient(180deg, rgba(0,0,0,0.88) 0%, rgba(0,0,0,0.5) 50%, rgba(0,0,0,0) 100%);
}

.c-service-card__icon {
  position: relative;
  /* Big feature circle — the icon is the hero of the card's top third. */
  width: 130px;
  height: 130px;
  border-radius: 999px;
  background: var(--bg);
  border: 5px solid var(--card-color);
  display: grid;
  place-items: center;
  z-index: 1;
  flex-shrink: 0;
}
/* White icon discs on the service pages; home (index variant, no modifier)
   keeps the dark discs. Applied via the --light-discs modifier on each service
   variant's root section (Andrew 2026-07-14). */
.c-service-cards--light-discs .c-service-card__icon { background: #fff; }
.c-service-card__icon svg {
  width: 70px;
  height: 70px;
}
/* Real brand illustration inside the circle. Bounded by BOTH a max width (%)
   and a max height (definite px — a % height doesn't resolve inside the grid
   icon), so it fits whatever the aspect is: a portrait illustration is height-
   limited, a landscape one is width-limited. Either way it stays in the circle. */
.c-service-card__icon img {
  width: auto;
  height: auto;
  max-width: 78%;
  max-height: 104px;
  object-fit: contain;
}

.c-service-card__body {
  position: relative;
  width: 100%;
  /* Fill the middle row so the copy container reaches toward the icon and button
     (its dark panel covers what used to be empty card background), but keep a
     little clear space on each side via the margin. Text centred inside. */
  align-self: stretch;
  margin: 16px 0;
  padding: 18px 20px;
  border-radius: 12px;
  border: 4px solid var(--card-color);
  background: var(--bg);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 12px;
  z-index: 1;
  box-sizing: border-box;
}
.c-service-card__title {
  margin: 0;
  font-family: 'CeraRound', 'Cera Round', 'Nunito', sans-serif;
  font-weight: 900;
  font-size: 20px;
  line-height: 24px;
  letter-spacing: -0.01em;
  color: var(--text);
  text-align: center;
}
.c-service-card__desc {
  margin: 0;
  font-family: 'Nunito', system-ui, sans-serif;
  font-size: 15px;
  font-weight: 400;
  line-height: 22px;
  color: var(--text-body);
  text-align: center;
}

/* CTA — solid colored ring, dark gap (4px), mesh-gradient fill, white CeraRound */
.c-service-card__cta {
  position: relative;
  width: 100%;             /* near full width, side to side */
  height: 52px;
  border-radius: 999px;   /* Nimiq pill */
  border: 4px solid var(--card-color);
  background: var(--bg);
  padding: 4px;
  display: flex;
  align-items: center;
  justify-content: center;
  text-decoration: none;
  overflow: clip;
  z-index: 1;
  transition: filter 160ms ease, transform 160ms ease;
  box-sizing: border-box;
}
.c-service-card__cta::before {
  content: "";
  position: absolute;
  /* TWO concentric borders: the host's colored ring on the outside, then this
     black ring, then the gradient fill. The black ring is a real 4px BORDER on
     this layer (not an inset gap) so it follows the pill at uniform width and
     can't pool unevenly at the rounded tips. background-clip: padding-box keeps
     the gradient inside the black border. */
  inset: 0;
  border-radius: 999px;
  border: 4px solid var(--bg);
  box-sizing: border-box;
  /* 5-stop palindromic palette so the pan animation loops seamlessly */
  background: linear-gradient(135deg, #A0C7FF 0%, #477ED6 25%, #C77DFF 50%, #477ED6 75%, #A0C7FF 100%);
  background-clip: padding-box;
  background-size: 300% 300%;
  background-position: 0% 50%;
  animation: service-cta-flow 8s cubic-bezier(0.45, 0, 0.55, 1) infinite;
  z-index: 0;
}
@keyframes service-cta-flow {
  0%, 100% { background-position: 0% 50%; }
  50%      { background-position: 100% 50%; }
}
/* Per-variant stagger so no two CTAs share a phase. Different durations +
   negative delays + alternate gradient angle keep each button visually unique. */
.c-service-card--violet       .c-service-card__cta::before { animation-duration: 7s;  animation-delay: -1.2s; }
.c-service-card--mid-purple   .c-service-card__cta::before { animation-duration: 9s;  animation-delay: -3.5s;
  background-image: linear-gradient(95deg,  #C77DFF 0%, #9945FF 25%, #FF7EC0 50%, #9945FF 75%, #C77DFF 100%); }
.c-service-card--blue         .c-service-card__cta::before { animation-duration: 11s; animation-delay: -5.8s;
  background-image: linear-gradient(160deg, #A0C7FF 0%, #477ED6 25%, #07EDBE 50%, #477ED6 75%, #A0C7FF 100%); }
.c-service-card--teal         .c-service-card__cta::before { animation-duration: 8s;  animation-delay: -2.8s;
  background-image: linear-gradient(70deg,  #07EDBE 0%, #477ED6 25%, #A0C7FF 50%, #477ED6 75%, #07EDBE 100%); }
.c-service-card--pink         .c-service-card__cta::before { animation-duration: 15s; animation-delay: -6.2s;
  background-image: linear-gradient(30deg,  #FF7EC0 0%, #C77DFF 25%, #9945FF 50%, #C77DFF 75%, #FF7EC0 100%); }
@media (prefers-reduced-motion: reduce) {
  .c-service-card__cta::before { animation: none; }
}
.c-service-card__cta-label {
  position: relative;
  z-index: 1;
  font-family: 'CeraRound', 'Cera Round', 'Nunito', sans-serif;
  font-weight: 900;
  font-size: 18px;
  line-height: 22px;
  color: #FFFFFF;
  text-shadow: 0 1px 2px rgba(10, 9, 26, 0.4);
}
.c-service-card__cta:hover { filter: brightness(1.1); transform: scale(1.02); }
.c-service-card__cta:active { transform: scale(0.98); }

/* ---------- Tablet (4→2 cols) ---------- */
@media (max-width: 1280px) {
  .c-service-cards__row { max-width: 640px; margin: 0 auto; }
  /* 2-up: container minus 1 gap, split 2 ways */
  .c-service-cards__row > .c-service-card { flex-basis: calc((100% - 40px) / 2); }
}

/* ---------- Mobile: single column, full container width ---------- */
@media (max-width: 640px) {
  /* Reset to the default container inset so single cards stay full-width
     (matching the Training In Action widget / quote card = 350px), not the
     narrower desktop stage. */
  .c-service-cards > .container { width: min(100% - 40px, 1200px); }
  .c-service-cards__row {
    gap: 44px;                 /* a little more space between stacked cards */
    max-width: 100%;
  }
  .c-service-cards__row > .c-service-card { flex-basis: 100%; }
  .c-service-card {
    margin: 0 auto;           /* fill the container width = the reference cards */
  }
  /* Bigger feature icon on mobile (the top third has more room here than on the
     narrower desktop cards). */
  .c-service-card__icon { width: 156px; height: 156px; }
  .c-service-card__icon svg { width: 86px; height: 86px; }
  .c-service-card__icon img { max-height: 126px; }
  /* Bigger type on the full-width mobile cards — the desktop sizes read small
     here. */
  .c-service-card__title { font-size: 27px; line-height: 32px; }
  .c-service-card__desc  { font-size: 17px; line-height: 25px; }
}

/* == /components/how-it-works-text/style.css?v=3 == */
/* How It Works — Nimiq-foundation rebuild on the dark GDKC stage.
   Radical simplicity + white-space hierarchy: no toggle, no timeline glow, no
   left-accent stripe. Color appears only as the gradient number accents and the
   single CTA "break"; everything else is structured with breathing room. */
.c-hiw {
  position: relative;
  /* The squiggle is painted by ::before (a solid var(--bg) + squiggle layer) that
     extends a little past the section, top and bottom, so the pattern CREEPS into
     the solid neighbours with an organic, non-uniform wavy edge. z-index lifts the
     section (and that creep) above the section below it. */
  background: transparent;
  z-index: 1;
  /* Clip horizontally, but let the creep overflow vertically into the neighbours. */
  overflow: clip visible;
  display: flex;
  flex-direction: column;
  /* Override the global `section { padding: clamp(56px,8vw,120px) 0 }` on the
     BOTTOM only: that ~115px was stacking on top of the inner's own bottom
     padding, leaving a big gap below "Get Started". 16px here + 24px inner +
     32px lifetime top ≈ the 72px gap above the button, so the CTA sits balanced
     between the cadence cards above and the Investment section below. */
  padding-bottom: 16px;
}
.c-hiw::before {
  content: "";
  position: absolute;
  inset: -30px 0;          /* 30px of squiggle creeps up and down into neighbours */
  z-index: 0;
  pointer-events: none;
  background-color: var(--bg);
  background-image: url("/assets/squiggle-bg.svg");
  background-size: 480px 480px;
  background-repeat: repeat;
  /* Organic wavy creep at the TOP only (blends into the solid section above).
     The BOTTOM runs the squiggle solid all the way down to the wavy seam — the
     seam below is transparent now, so a bottom fade left a squiggle-less dark
     band just above the wave. */
  -webkit-mask:
    url("/assets/hiw-creep-top.svg") 0 0 / 100% 70px no-repeat,
    linear-gradient(#000, #000) 0 70px / 100% calc(100% - 70px) no-repeat;
          mask:
    url("/assets/hiw-creep-top.svg") 0 0 / 100% 70px no-repeat,
    linear-gradient(#000, #000) 0 70px / 100% calc(100% - 70px) no-repeat;
}
.c-hiw__inner {
  position: relative;
  z-index: 1;            /* above the ::before squiggle overlay */
  /* Tighter bottom padding pulls the "Get Started" CTA closer to the
     "An Investment…" section that follows. */
  padding: 112px 80px 24px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 64px;
  flex: 1;
  width: 100%;
  max-width: 1200px;
  margin: 0 auto;
  box-sizing: border-box;
}

/* ---- Header ---- */
.c-hiw__header { display: flex; flex-direction: column; gap: 16px; align-items: center; max-width: 720px; }
.c-hiw__title {
  margin: 0;
  font-family: 'CeraRound', 'Cera Round', 'Nunito', sans-serif;
  font-weight: 900;
  /* Shared section-header size (matches "How I Can Help" and "You're not alone"). */
  font-size: clamp(38px, 6vw, 60px);
  line-height: 1.08;
  letter-spacing: -0.02em;
  text-align: center;
  color: var(--text);
  text-wrap: balance;
}
.c-hiw__accent {
  background: linear-gradient(90deg, #07EDBE 0%, #9945FF 50%, #FF7EC0 100%);
  background-size: 200% 100%;
  -webkit-background-clip: text;
          background-clip: text;
  color: transparent;
  animation: hiw-accent-flow 12s ease-in-out infinite;
}
@keyframes hiw-accent-flow {
  0%, 100% { background-position: 0% 50%; }
  50%      { background-position: 100% 50%; }
}
.c-hiw__subtitle {
  margin: 0;
  color: var(--text-muted);
  font-family: 'Nunito', system-ui, sans-serif;
  font-size: 18px;
  line-height: 28px;
  max-width: 540px;
  text-align: center;
  text-wrap: pretty;
}

/* ---- Steps: four clean cards, sequence carried by the numbers + white space ---- */
.c-hiw__steps {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  /* Match the "How I Can Help" service-card row spacing (40px) so the two
     four-up card rows read as the same rhythm down the page. */
  gap: 40px;
  list-style: none;
  margin: 0;
  padding: 0;
  width: 100%;
}
.c-hiw__step {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: 30px 26px;
  border-radius: 20px;
  /* Solid outlined card — the site's card language (matches lifetime-support
     stat tiles + service-cards): solid dark fill, solid brand-colored border. */
  border: 2px solid var(--light-purple);
  background: var(--bg);
  /* Scroll-reveal entrance — JS adds .is-in to trigger */
  opacity: 0;
  transform: translateY(20px);
  transition: opacity 600ms cubic-bezier(0.16, 1, 0.3, 1),
              transform 600ms cubic-bezier(0.16, 1, 0.3, 1),
              box-shadow 220ms ease;
  transition-delay: calc(var(--step-i) * 110ms);
}
.c-hiw__step.is-in { opacity: 1; transform: translateY(0); }
.c-hiw__step:hover { box-shadow: 0 14px 32px rgba(153, 69, 255, 0.20); }
.c-hiw__num {
  display: inline-block;
  font-family: 'CeraRound', 'Cera Round', 'Nunito', sans-serif;
  font-weight: 900;
  font-size: 54px;
  line-height: 0.9;
  letter-spacing: -0.04em;
  margin-bottom: 4px;
  background: linear-gradient(135deg, var(--light-purple) 0%, var(--mid-purple) 100%);
  -webkit-background-clip: text;
          background-clip: text;
  color: transparent;
}
/* Zigzag the even cards (01, 03): number, title and body all align to the right
   edge instead of the left. text-align on the card cascades to the full-width
   flex children. */
.c-hiw__step:nth-child(even) { text-align: right; }

.c-hiw__step-title {
  margin: 0;
  font-family: 'CeraRound', 'Cera Round', 'Nunito', sans-serif;
  font-weight: 900;
  font-size: 21px;
  line-height: 27px;
  color: var(--text);
}
.c-hiw__step-body {
  margin: 0;
  color: var(--text-body);
  font-family: 'Nunito', system-ui, sans-serif;
  font-size: 17px;
  line-height: 26px;
}

/* ---- Cadence: a section title sitting directly above the note card ---- */
.c-hiw__cadence {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 20px;
  width: 100%;
}
.c-hiw__cadence-title {
  margin: 0;
  font-family: 'CeraRound', 'Cera Round', 'Nunito', sans-serif;
  font-weight: 900;
  font-size: clamp(26px, 3.4vw, 34px);
  line-height: 1.1;
  letter-spacing: -0.02em;
  text-align: center;
  color: var(--text);
  text-wrap: balance;
}

/* Two parallel cadence cards (non-aggressive vs aggressive) */
.c-hiw__cadence-cards {
  display: grid;
  grid-template-columns: 1fr 1fr;
  /* Match the "How I Can Help" service-card gap (40px). */
  gap: 40px;
  width: 100%;
  max-width: 880px;
  margin: 0 auto;
}
.c-hiw__cadence-cards .c-hiw__callout { max-width: none; margin: 0; height: 100%; }
/* The frequency — the headline answer of each card */
.c-hiw__callout-cadence {
  margin: 0;
  font-family: 'CeraRound', 'Cera Round', 'Nunito', sans-serif;
  font-weight: 900;
  font-size: 26px;
  line-height: 30px;
  letter-spacing: -0.01em;
  background: linear-gradient(135deg, var(--light-purple) 0%, var(--mid-purple) 100%);
  -webkit-background-clip: text;
          background-clip: text;
  color: transparent;
}
/* Recommended package — a quiet footer line, set off by a hairline divider */
.c-hiw__callout-rec {
  margin: 6px 0 0;
  margin-top: auto;            /* push to the card bottom so both cards align */
  padding-top: 14px;
  width: 100%;
  border-top: 1px solid rgba(248, 248, 248, 0.12);
  font-family: 'Nunito', system-ui, sans-serif;
  font-size: 15px;
  line-height: 21px;
  color: var(--text-muted);
}
.c-hiw__callout-rec strong { color: var(--text); font-weight: 800; }

/* ---- Cadence note: uniform-bordered card (no accent stripe) ---- */
.c-hiw__callout {
  position: relative;
  width: 100%;
  max-width: 760px;
  margin: 0 auto;
  border: 2px solid var(--mid-purple);
  border-radius: 20px;
  background: var(--bg);
  padding: 28px 32px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  text-align: center;
  align-items: center;
}
.c-hiw__callout-title {
  margin: 0;
  font-family: 'CeraRound', 'Cera Round', 'Nunito', sans-serif;
  font-weight: 900;
  font-size: 19px;
  line-height: 25px;
  color: var(--text);
}
.c-hiw__callout-body {
  margin: 0;
  max-width: 600px;
  color: var(--text-body);
  font-family: 'Nunito', system-ui, sans-serif;
  font-size: 17px;
  line-height: 26px;
}

/* ---- CTA: the one calculated break — filled brand pill, bottom-right radial spin ---- */
.c-hiw__cta-wrap { padding-top: 8px; }
.c-hiw__cta {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 20px 48px;
  border-radius: var(--radius-pill);
  /* The site's signature CTA pill (matches the "Free Consultation" button):
     brand gradient fill, dark text with a thick white outline, brand shadow. */
  background: linear-gradient(135deg, #07EDBE 0%, #9945FF 50%, #FF7EC0 100%);
  color: #0A091A;
  font-family: 'CeraRound', 'Cera Round', 'Nunito', sans-serif;
  font-weight: 900;
  font-size: 24px;
  line-height: 28px;
  letter-spacing: 0.01em;
  text-decoration: none;
  box-shadow: 0 18px 40px rgba(153, 69, 255, 0.35);
  transition: filter 160ms ease, transform 160ms ease;
  /* Thick white border around the label (paint-order keeps it around the glyphs). */
  -webkit-text-stroke: 6px #FFFFFF;
          text-stroke: 6px #FFFFFF;
  paint-order: stroke fill;
}
.c-hiw__cta:hover { filter: brightness(1.07); transform: translateY(-2px); }
.c-hiw__cta:active { transform: scale(0.98); }

/* ---- Reduced motion ---- */
@media (prefers-reduced-motion: reduce) {
  .c-hiw__accent { animation: none; }
  .c-hiw__step { opacity: 1; transform: none; transition: none; }
}

/* ---- Responsive ---- */
@media (max-width: 1100px) {
  .c-hiw__inner { padding: 80px 40px 24px; gap: 48px; }
  .c-hiw__steps { grid-template-columns: repeat(2, 1fr); gap: 40px; }
  /* Cards are wider once they stack 2-up, so the title can read bigger. */
  .c-hiw__step-title { font-size: 24px; line-height: 30px; }
}
@media (max-width: 680px) {
  .c-hiw__cadence-cards { grid-template-columns: 1fr; max-width: 480px; gap: 44px; }
}
@media (max-width: 560px) {
  .c-hiw__inner { padding: 64px 20px 24px; }
  .c-hiw__steps { grid-template-columns: 1fr; gap: 44px; }
  .c-hiw__num { font-size: 50px; }
}

/* == /components/how-it-works-rail/style.css == */
/* How It Works — zigzag squiggly journey rail (desktop) / single-column
   vertical-squiggle (mobile). Visual language matches pain-mirror-v2. */

.c-hiwr {
  position: relative;
  width: 100%;
  background: transparent;
  overflow: clip;
  color: var(--text);
}
.c-hiwr__inner {
  position: relative;
  z-index: 1;
  max-width: 960px;
  margin: 0 auto;
  padding: 96px 32px 96px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 64px;
  box-sizing: border-box;
}

/* ---- Header ---------------------------------------------------------- */
.c-hiwr__header {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 18px;
  text-align: center;
}
.c-hiwr__title {
  margin: 0;
  font-family: 'CeraRound', 'Cera Round', 'Nunito', sans-serif;
  font-weight: 900;
  font-size: clamp(40px, 6vw, 72px);
  line-height: 1.04;
  letter-spacing: -0.02em;
  color: var(--text);
}
.c-hiwr__accent {
  background: linear-gradient(90deg, #07EDBE 0%, #9945FF 50%, #FF7EC0 100%);
  background-size: 200% 100%;
  -webkit-background-clip: text;
          background-clip: text;
  color: transparent;
  -webkit-text-fill-color: transparent;
  animation: hiw-accent-flow 12s cubic-bezier(0.45, 0, 0.55, 1) infinite;
}
@keyframes hiw-accent-flow {
  0%, 100% { background-position: 0% 50%; }
  50%      { background-position: 100% 50%; }
}
.c-hiwr__subtitle {
  margin: 0;
  max-width: 560px;
  color: rgba(248, 248, 248, 0.7);
  font-family: 'Nunito', system-ui, sans-serif;
  font-size: clamp(15px, 1.4vw, 17px);
  line-height: 1.5;
}

/* ---- Rail ------------------------------------------------------------ */
.c-hiwr__rail {
  position: relative;
  width: 100%;
  max-width: 760px;
  margin: 0;
}
.c-hiwr__steps {
  position: relative;
  z-index: 1;
  margin: 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 64px;
}

/* ---- Spine — vertical squiggle pinned to the left rail (marker column) */
.c-hiwr__spine {
  position: absolute;
  top: 0;
  left: 0;
  width: 120px;
  height: 100%;
  pointer-events: none;
  overflow: visible;
  z-index: 0;
}
.c-hiwr__spine-draw {
  /* JS sets stroke-dasharray to path.getTotalLength() and dashoffset to match;
     adding .is-in transitions dashoffset to 0 to "draw" the squiggle. */
  transition: stroke-dashoffset 2000ms cubic-bezier(0.45, 0, 0.55, 1);
}

/* ---- Step rows ------------------------------------------------------- */
.c-hiwr__step {
  position: relative;
  display: grid;
  grid-template-columns: 120px 1fr;
  gap: 40px;
  align-items: center;
  opacity: 0;
  transform: translateY(20px);
  transition: opacity 700ms cubic-bezier(0.16, 1, 0.3, 1),
              transform 700ms cubic-bezier(0.16, 1, 0.3, 1);
  transition-delay: calc(var(--step-i) * 140ms);
}
.c-hiwr__step.is-in {
  opacity: 1;
  transform: translateY(0);
}

/* Marker — organic blob outline + big numeral, per-step brand color. */
.c-hiwr__marker {
  position: relative;
  width: 120px;
  height: 120px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--blob-color, #A08CFF);
  filter: drop-shadow(0 8px 18px rgba(10, 9, 26, 0.5));
}
.c-hiwr__step.is-in .c-hiwr__marker {
  animation: hiw-marker-settle 1200ms cubic-bezier(0.16, 1, 0.3, 1)
             calc(var(--step-i) * 140ms + 200ms) both;
}
@keyframes hiw-marker-settle {
  0%   { transform: rotate(-6deg) scale(0.92); }
  60%  { transform: rotate(3deg)  scale(1.04); }
  100% { transform: rotate(0)     scale(1);    }
}
.c-hiwr__blob {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}
.c-hiwr__num {
  position: relative;
  z-index: 1;
  font-family: 'CeraRound', 'Cera Round', 'Nunito', sans-serif;
  font-weight: 900;
  font-size: 36px;
  line-height: 1;
  letter-spacing: -0.02em;
  color: var(--blob-color, #A08CFF);
}

/* Content column */
.c-hiwr__step-content {
  display: flex;
  flex-direction: column;
  gap: 10px;
  max-width: 560px;
}
.c-hiwr__step-title {
  margin: 0;
  font-family: 'CeraRound', 'Cera Round', 'Nunito', sans-serif;
  font-weight: 900;
  font-size: clamp(20px, 2vw, 24px);
  line-height: 1.2;
  letter-spacing: -0.01em;
  color: var(--text);
}
.c-hiwr__step-body {
  margin: 0;
  color: rgba(248, 248, 248, 0.75);
  font-family: 'Nunito', system-ui, sans-serif;
  font-size: clamp(15px, 1.3vw, 16px);
  line-height: 1.55;
}

/* ---- CTA ------------------------------------------------------------- */
.c-hiwr__cta-wrap {
  display: flex;
  justify-content: center;
}
.c-hiwr__cta {
  display: inline-flex;
  align-items: center;
  padding: 18px 36px;
  border-radius: 999px;
  background: linear-gradient(135deg, #07EDBE 0%, #9945FF 50%, #FF7EC0 100%);
  background-size: 200% 100%;
  color: #0A091A;
  font-family: 'CeraRound', 'Cera Round', 'Nunito', sans-serif;
  font-weight: 900;
  font-size: clamp(16px, 1.5vw, 20px);
  letter-spacing: 0.01em;
  text-decoration: none;
  box-shadow: 0 18px 40px rgba(153, 69, 255, 0.32);
  animation: hiw-cta-pan 10s cubic-bezier(0.45, 0, 0.55, 1) infinite;
  transition: filter 160ms ease, transform 160ms ease;
}
.c-hiwr__cta:hover  { filter: brightness(1.07); transform: translateY(-1px); }
.c-hiwr__cta:active { transform: scale(0.98); }
@keyframes hiw-cta-pan {
  0%, 100% { background-position: 0% 50%; }
  50%      { background-position: 100% 50%; }
}

@media (max-width: 720px) {
  .c-hiwr__inner {
    padding: 72px 20px 72px;
    gap: 48px;
  }
  .c-hiwr__steps { gap: 48px; }
  .c-hiwr__step  { grid-template-columns: 80px 1fr; gap: 20px; }
  .c-hiwr__spine  { width: 80px; }
  .c-hiwr__marker { width: 80px; height: 80px; }
  .c-hiwr__num    { font-size: 26px; }
}

@media (max-width: 420px) {
  .c-hiwr__inner  { padding: 56px 16px 56px; }
  .c-hiwr__step   { grid-template-columns: 68px 1fr; gap: 16px; }
  .c-hiwr__spine  { width: 68px; }
  .c-hiwr__marker { width: 68px; height: 68px; }
  .c-hiwr__num    { font-size: 22px; }
}

/* ---- GSAP scrub mode (class added by /js/how-it-works-rail.js) -------- */
/* When ScrollTrigger owns the rail (scrubbed spine draw + per-marker pops),
   the CSS IO mechanism above is neutralized so CSS and GSAP never fight over
   the same properties: steps render visible (GSAP hides/reveals the marker +
   content itself, applied same-frame — the is-armed recipe), the marker
   keyframe is dropped, and so is the 2s dashoffset transition (it would
   smear every scrubbed frame). Without JS this class never appears. */
[data-component="how-it-works-rail"].is-scrub .c-hiwr__step {
  opacity: 1;
  transform: none;
  transition: none;
}
[data-component="how-it-works-rail"].is-scrub .c-hiwr__step.is-in .c-hiwr__marker {
  animation: none;
}
[data-component="how-it-works-rail"].is-scrub .c-hiwr__spine-draw {
  transition: none;
}

/* ---- Reduced motion -------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  .c-hiwr__accent,
  .c-hiwr__cta { animation: none; }
  .c-hiwr__step {
    opacity: 1;
    transform: none;
    transition: none;
  }
  .c-hiwr__step.is-in .c-hiwr__marker { animation: none; }
  .c-hiwr__spine-draw {
    transition: none;
    stroke-dashoffset: 0;
  }
}

/* == /components/get-pricing-cta/style.css == */
/* Get Pricing — Mesh Gradient — port of Paper 2EG-0 (1440×420) + 2FM-0 mobile */
.c-get-pricing {
  position: relative;
  background: var(--bg);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 80px 24px;
  overflow: clip;
}
.c-get-pricing__overlay {
  position: absolute;
  inset: 0;
  background: rgba(160, 140, 255, 0.05);
  pointer-events: none;
}
.c-get-pricing__card {
  position: relative;
  width: 100%;
  max-width: 896px;
  min-height: 279px;
  background: #8B7FCC; /* Solid fallback if WebGL fails */
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: 24px;
  box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5);
  overflow: clip;
  display: flex;
  align-items: stretch;
}
.c-get-pricing__mesh {
  position: absolute;
  inset: 0;
  pointer-events: none;
}
.c-get-pricing__content {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  gap: 32px;
  padding: 48px;
  width: 100%;
}
.c-get-pricing__copy {
  display: flex;
  flex-direction: column;
  gap: 16px;
  flex: 1 1 0;
  min-width: 0;
}
.c-get-pricing__title {
  margin: 0;
  font-family: 'CeraRound', 'Cera Round', 'Nunito', sans-serif;
  font-weight: 900;
  font-size: clamp(26px, 3vw, 36px);
  line-height: 1.16;
  color: var(--bg-elev-1);
  letter-spacing: -0.01em;
}
.c-get-pricing__subtitle {
  margin: 0;
  font-family: 'Nunito', system-ui, sans-serif;
  font-size: 18px;
  line-height: 1.5;
  color: rgba(10, 9, 26, 0.7);
}
.c-get-pricing__form {
  display: flex;
  gap: 12px;
  min-width: 400px;
  flex-shrink: 0;
}
.c-get-pricing__input {
  flex: 1 1 0;
  min-width: 0;
  padding: 16px;
  font-family: 'Nunito', system-ui, sans-serif;
  font-size: 15px;
  line-height: 18px;
  color: var(--bg);
  background: rgba(10, 9, 26, 0.12);
  border: 1px solid rgba(10, 9, 26, 0.15);
  border-radius: 12px;
  outline: none;
  transition: border-color 200ms ease, background 200ms ease;
}
.c-get-pricing__input::placeholder { color: rgba(10, 9, 26, 0.4); }
.c-get-pricing__input:focus {
  border-color: rgba(10, 9, 26, 0.45);
  background: rgba(255, 255, 255, 0.7);
}
.c-get-pricing__submit {
  flex-shrink: 0;
  padding: 16px 32px;
  font-family: 'Nunito', system-ui, sans-serif;
  font-size: 15px;
  font-weight: 700;
  line-height: 18px;
  color: var(--text);
  background: var(--bg-elev-1);
  border: 0;
  border-radius: 12px;
  box-shadow: 0 8px 20px rgba(0, 0, 0, 0.25);
  cursor: pointer;
  transition: transform 150ms ease, background 200ms ease;
}
.c-get-pricing__submit:hover { background: var(--bg); transform: translateY(-1px); }

/* Mobile (Paper 2FM-0, 390×428) */
@media (max-width: 720px) {
  .c-get-pricing { padding: 48px 20px; }
  .c-get-pricing__content {
    flex-direction: column;
    align-items: flex-start;
    padding: 32px 24px;
    gap: 24px;
  }
  .c-get-pricing__form {
    flex-direction: column;
    min-width: 0;
    width: 100%;
    gap: 10px;
  }
  .c-get-pricing__submit { width: 100%; }
}

/* Visually-hidden helper for screen-reader-only labels */
.visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* == /components/lifetime-support/style.css == */
/* Lifetime Support — pixel-port of Paper 2UL-0. DESIGN polish: mid-purple register.
   The full-bleed grid is dialled back and radially faded toward the edges (texture, not a
   wall), and a soft mid-purple blob sits behind the copy column. Light-touch — structure,
   stat tiles and the art card are unchanged.
   ANIMATION HOOKS: [data-animate] on the copy + the art card; [data-three-blob] on the blob. */
.c-lifetime {
  position: relative;
  /* Transparent (was an opaque var(--bg)) so the continuous body squiggle carries
     through from the pricing section above — otherwise the squiggle stops dead at
     this section's top edge and the edge-masked purple grid leaves a flat dark band
     in the gutters. The purple grid (.c-lifetime__pattern) + blob still overlay on
     top as this section's mid-purple accent; stat tiles + art card keep their own bg. */
  background: transparent;
  /* Top padding sets the breathing room above the "An Investment…" title from
     the "Get Started" button above. */
  padding: 48px 100px 60px;
  overflow: clip;
}
.c-lifetime__blob {
  position: absolute;
  top: 50%; left: 18%;
  transform: translate(-50%, -50%);
  width: 560px; height: 420px;
  border-radius: 50%;
  filter: blur(90px);
  background: radial-gradient(50% 50% at 50% 50%, rgba(199, 125, 255, 0.22) 0%, transparent 75%);
  opacity: 0.7;
  pointer-events: none;
}
.c-lifetime__pattern {
  position: absolute;
  inset: 0;
  opacity: 0.12;
  background-image:
    repeating-linear-gradient(90deg, transparent 0, transparent 19px, rgba(199,125,255,0.22) 19px, rgba(199,125,255,0.22) 20px),
    repeating-linear-gradient(0deg, transparent 0, transparent 59px, rgba(199,125,255,0.18) 59px, rgba(199,125,255,0.18) 60px);
  pointer-events: none;
  -webkit-mask-image: radial-gradient(110% 100% at 50% 50%, #000 0%, rgba(0,0,0,0.4) 55%, transparent 85%);
          mask-image: radial-gradient(110% 100% at 50% 50%, #000 0%, rgba(0,0,0,0.4) 55%, transparent 85%);
}
.c-lifetime__row {
  position: relative;
  display: grid;
  grid-template-columns: 1fr 480px;
  gap: 64px;
  /* Top-align so the title sits just under the section's top padding instead of
     floating to the vertical center of the tall illustration (which left a big
     gap below the "Get Started" button above). */
  align-items: start;
  max-width: 1240px;
  margin: 0 auto;
}
.c-lifetime__copy {
  display: flex;
  flex-direction: column;
  gap: 24px;
  max-width: 640px;
  /* Center the header + copy (text and the constrained-width paragraph). */
  text-align: center;
  align-items: center;
}
.c-lifetime__eyebrow {
  margin: 0;
  font-family: 'CeraRound', 'Cera Round', 'Nunito', sans-serif;
  font-weight: 900;
  font-size: 13px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--light-purple);
}
.c-lifetime__title {
  margin: 0;
  font-family: 'CeraRound', 'Cera Round', 'Nunito', sans-serif;
  font-weight: 900;
  /* Shared section-header size (site-wide type scale). */
  font-size: clamp(38px, 6vw, 60px);
  line-height: 1.08;
  letter-spacing: -0.02em;
  color: var(--text);
  /* Balanced wraps on phones so "Dog" never orphans onto its own line. */
  text-wrap: balance;
}
.c-lifetime__title span { display: block; }
.c-lifetime__accent { color: var(--light-purple); }

.c-lifetime__desc {
  margin: 0;
  color: #BFBFBF;
  font-family: 'Nunito', system-ui, sans-serif;
  font-size: 17px;
  line-height: 1.7;
  max-width: 560px;
}
.c-lifetime__desc strong { color: var(--text); font-weight: 800; }

.c-lifetime__stats {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 20px;
  padding-top: 8px;
}
.c-lifetime__stat {
  position: relative;
  background: var(--bg);
  border: 2px solid var(--light-purple);
  border-radius: 21px;
  padding: 28px 20px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  align-items: center;
  justify-content: center;
}
.c-lifetime__stat-num {
  font-family: 'CeraRound', 'Cera Round', 'Nunito', sans-serif;
  font-weight: 900;
  font-size: 40px;
  line-height: 1.0;
}
.c-lifetime__stat-label {
  color: #BFBFBF;
  font-family: 'Nunito', system-ui, sans-serif;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  line-height: 15px;
  text-align: center;
}

.c-lifetime__art {
  position: relative;
  width: 480px;
  height: 480px;
  border-radius: 36px;
  padding: 5px;
  background: linear-gradient(135deg, #A08CFF 0%, #6B5ED9 100%);
  flex-shrink: 0;
}
.c-lifetime__art::before {
  content: "";
  position: absolute;
  inset: 5px;
  border-radius: 30px;
  background: var(--surface-card);
  padding: 16px;
}
.c-lifetime__art::after {
  content: "";
  position: absolute;
  inset: 21px;
  border-radius: 18px;
  /* Zoomed in close on the in-home scene. cover-and-beyond (170%) crops the
     outer edges of the couch/floor on purpose so the people + dog read large. */
  background: #FFFFFF url("/assets/illustrations/light/home-training-scene.png") no-repeat;
  /* Horizontal 37.5% = halfway between the original center (50%) and the
     dog-centered 25%, so the dog reads near-center without the girl getting
     pushed off the left edge. */
  background-position: 37.5% 36%;
  background-size: 170%;
}

@media (max-width: 1100px) {
  .c-lifetime { padding: 48px 40px 56px; }
  .c-lifetime__row { grid-template-columns: 1fr; }
  /* Stacked layout: the art card spans the column width instead of sitting at a
     fixed size (which read as narrower than the copy above it). Capped so it
     doesn't balloon on a wide tablet. */
  .c-lifetime__art {
    width: 100%;
    max-width: 640px;
    height: auto;
    aspect-ratio: 1 / 1;
    margin-inline: auto;
  }
}
@media (max-width: 640px) {
  .c-lifetime__stats { grid-template-columns: 1fr; gap: 12px; }
  .c-lifetime__stat { padding: 20px; }
  .c-lifetime__stat-num { font-size: 32px; }
  /* Phones: full-bleed. Break out of the section's 40px side padding so the
     purple frame's straight sides run flush to both screen edges; height
     follows the square ratio off the full width. Rounded corners kept (inside
     and out) per the brand card language. */
  .c-lifetime__art {
    width: calc(100% + 80px);
    max-width: none;
    height: auto;
    aspect-ratio: 1 / 1;
    margin-left: -40px;
    margin-right: -40px;
  }
}

/* == /components/about-andrew/style.css == */
/* About Andrew — pixel-port of Paper 2PI-0 */
.c-about {
  position: relative;
  background: var(--bg);
  overflow: clip;
  padding: 80px;
  display: flex;
  align-items: center;
  justify-content: center;
}
.c-about__pattern {
  position: absolute;
  inset: 0;
  opacity: 0.18;
  background-image:
    repeating-linear-gradient(90deg, transparent 0, transparent 19px, rgba(160,140,255,0.22) 19px, rgba(160,140,255,0.22) 20px);
  pointer-events: none;
}
.c-about__card {
  position: relative;
  width: 100%;
  max-width: 1100px;
  background: #FFFFFF;
  border-radius: 32px;
  box-shadow: 0 25px 80px rgba(0, 0, 0, 0.3);
  display: grid;
  grid-template-columns: 60% 40%;
  overflow: clip;
  min-height: 520px;
}

.c-about__copy {
  display: flex;
  flex-direction: column;
  gap: 20px;
  justify-content: center;
  padding: 56px 48px;
}
.c-about__title {
  margin: 0;
  font-family: 'CeraRound', 'Cera Round', 'Nunito', sans-serif;
  font-weight: 900;
  /* Shared section-header size (site-wide type scale). */
  font-size: clamp(38px, 6vw, 60px);
  line-height: 1.1;
  letter-spacing: -0.01em;
  color: #171717;
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  align-items: baseline;
}
.c-about__accent { color: var(--light-purple); }

.c-about__body {
  display: flex;
  flex-direction: column;
  gap: 16px;
}
.c-about__body p {
  margin: 0;
  color: #404040;
  font-family: 'Nunito', system-ui, sans-serif;
  font-size: 17px;
  line-height: 1.75;
}

.c-about__cta {
  align-self: flex-start;
  display: inline-flex;
  align-items: center;
  background: var(--light-purple);
  border-radius: 999px;
  padding: 16px 36px;
  color: var(--bg);
  font-family: 'Nunito', system-ui, sans-serif;
  font-size: 18px;
  font-weight: 700;
  line-height: 22px;
  text-decoration: none;
  margin-top: 12px;
  transition: filter 160ms ease, transform 160ms ease;
}
.c-about__cta:hover { filter: brightness(1.05); }
.c-about__cta:active { transform: scale(0.98); }

.c-about__photo {
  position: relative;
  display: flex;
}
.c-about__photo-frame {
  position: absolute;
  inset: 0;
  padding: 6px;
  background: linear-gradient(135deg, #9945FF 0%, #07EDBE 100%);
  /* Match the card's 32px outer radius on the right side so the gradient
     border follows the card's curvature instead of being cut by overflow. */
  border-radius: 0 32px 32px 0;
}
.c-about__photo-frame img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
  border-radius: 0 26px 26px 0;
}
.c-about__photo-frame--placeholder::after {
  content: "";
  position: absolute;
  inset: 6px;
  background: #E5E5E5;
  /* Inner radius = outer radius (32) minus padding (6) = 26 */
  border-radius: 0 26px 26px 0;
}

/* Transparent "me" cutout video inside the gradient frame. object-fit: contain so
   Andrew is never cropped (head/feet stay in); the brand gradient shows through the
   transparent areas. Bottom-anchored so he stands on the frame floor. */
.c-about__photo-frame .me-vid {
  position: absolute;
  inset: 6px;
  width: calc(100% - 12px);
  height: calc(100% - 12px);
  object-fit: contain;
  object-position: center bottom;
  border-radius: 0 26px 26px 0;
  /* Transparent: the video composites over the gradient frame behind it. */
}
.c-about__photo-frame .me-mobile { display: none; }

@media (max-width: 900px) {
  .c-about { padding: 40px 20px; }
  .c-about__card { grid-template-columns: 1fr; }
  .c-about__copy { padding: 40px 28px 28px; gap: 16px; }
  /* Square photo area so the 1:1 video fills it edge to edge (no letterbox gap
     where the dark section colour was seeping under the gradient). */
  .c-about__photo { min-height: 0; aspect-ratio: 1 / 1; }
  /* Stacked layout gets the 1:1 square crop (the 9:16 would be far too tall here).
     Breakpoint aligned to the card's single-column switch, not 600px. */
  .c-about__photo-frame { border-radius: 0 0 32px 32px; }
  .c-about__photo-frame .me-vid {
    border-radius: 0 0 26px 26px;
    object-fit: cover;              /* fill the square frame edge to edge */
    object-position: center top;    /* keep his head, crop from the bottom if needed */
  }
  .c-about__photo-frame .me-desktop { display: none; }
  .c-about__photo-frame .me-mobile { display: block; }
}

/* == /components/testimonials/style.css == */
/* Testimonials — plain centered quote on the dark stage (no card container).
   Previously a white blob whose text was painted to a canvas (shape-inside);
   the card was dropped, so this is now simple centered text on the page
   background, both desktop and mobile.
   Vars: quote (required), author (required). */
.c-testimonials {
  position: relative;
  background: var(--bg);
  padding: 80px 40px 96px;
  display: flex;
  justify-content: center;
}

.c-testimonials__card {
  position: relative;
  width: 100%;
  max-width: 680px;
  margin: 0 auto;
  text-align: center;
  font-family: 'Nunito', system-ui, sans-serif;
}

.c-testimonials__title {
  margin: 0 0 18px;
  font-family: 'CeraRound', 'Cera Round', 'Nunito', sans-serif;
  font-weight: 900;
  font-size: clamp(28px, 4vw, 40px);
  line-height: 1.1;
  letter-spacing: -0.01em;
  color: var(--text);
}

.c-testimonials__quote {
  margin: 0 0 14px;
  font-size: clamp(17px, 1.6vw, 20px);
  font-weight: 500;
  line-height: 1.6;
  color: var(--text);
}

.c-testimonials__cite {
  display: block;
  font-style: normal;
}
/* Author — matches the hero-testimonial author: brand violet, Nunito 700/16px. */
.c-testimonials__author {
  display: block;
  color: var(--violet);
  font-size: 16px;
  font-weight: 700;
  line-height: 20px;
  font-style: normal;
}

@media (max-width: 720px) {
  .c-testimonials { padding: 56px 20px 72px; }
}

/* == /components/hero-testimonial/style.css?v=6 == */
/* Hero Testimonial — pixel-port of Paper 2QS-0
   Acts as the smooth transition between the dark hero and the white sections below. */
.c-hero-testimonial {
  position: relative;
  /* Transparent so the BODY's dark squiggle shows through (same as the hero).
     This keeps the squiggle continuous across the wavy seams above and below —
     a section-level squiggle would be out of phase with the body at the seam. */
  background: transparent;
  /* Symmetric breathing room — same dark space below the card as above it. */
  padding: 160px 40px 160px;
  display: flex;
  justify-content: center;
  overflow: clip;
}
/* Squiggle now comes from the BODY background (section is transparent), so this
   section-level tile is no longer needed — it would double up / sit out of phase
   with the seams. */
.c-hero-testimonial::before { display: none; }
.c-hero-testimonial > * { position: relative; z-index: 1; }
/* Card background is the organic "Green-Blob-Large" shape from the GDKC brand
   mural. It's applied as an SVG mask on ::before so the card's own layout box
   stays rectangular (content positions normally) while only the white fill is
   cut to the blob silhouette. drop-shadow on the card follows the masked shape. */
.c-hero-testimonial__card {
  display: grid;
  /* Single column while the video-review slot is out (see index.html comment);
     restore `1fr 300px` when the videos ship. */
  grid-template-columns: 1fr;
  column-gap: 32px;
  align-items: center;            /* keep body + media centred in the blob */
  width: 100%;
  max-width: 1100px;
  aspect-ratio: 1.82 / 1;         /* matches the blob's native ratio */
  position: relative;
  /* No drop-shadow: over the dark squiggle its soft 48px halo muted the squiggle
     into a "dark background" ring around the card. The white blob has plenty of
     contrast on its own, so the squiggle now reads cleanly right up to the edge. */
  /* Inscribed safe zone — the blob pinches inward at the upper-left neck
     and top, so left/top padding runs heavier than right/bottom. */
  padding: 110px 96px 120px 140px;
}
.c-hero-testimonial__card::before {
  content: "";
  position: absolute;
  inset: 0;
  background: #FFFFFF;
  -webkit-mask-image: url('/assets/blob-card.svg');
  -webkit-mask-size: 100% 100%;
  -webkit-mask-repeat: no-repeat;
  -webkit-mask-position: center;
          mask-image: url('/assets/blob-card.svg');
          mask-size: 100% 100%;
          mask-repeat: no-repeat;
          mask-position: center;
  z-index: 0;
}
.c-hero-testimonial__card > * { position: relative; z-index: 1; }
.c-hero-testimonial__body {
  /* Card-level padding handles the safe zone now. */
  display: flex;
  flex-direction: column;
  gap: 12px;
  /* With the video slot out, cap the quote's line length and centre the column
     in the blob so the text doesn't stretch the full 1100px card. */
  max-width: 680px;
  justify-self: center;
}
.c-hero-testimonial__header {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}
/* Single KC brand mark (was a row of 5). Sized up so the K+C monogram reads
   clearly instead of looking cramped/"off" at thumbnail size. */
.c-hero-testimonial__badge { display: block; flex-shrink: 0; width: 42px; height: auto; }
/* Highlighted now that the KC marks are reduced to one — this trust line is
   the header's anchor: larger, bolder, brand navy instead of faint grey. */
.c-hero-testimonial__eyebrow {
  color: var(--navy);
  font-family: 'Nunito', system-ui, sans-serif;
  font-size: 13px;
  font-weight: 800;
  letter-spacing: 0.12em;
  line-height: 16px;
  text-transform: uppercase;
}
.c-hero-testimonial__quote {
  margin: 0;
  color: #171717;
  font-family: 'Nunito', system-ui, sans-serif;
  font-size: 20px;
  font-weight: 500;
  line-height: 32px;
  padding-right: 16px;
  font-style: normal;
}
.c-hero-testimonial__quote::before,
.c-hero-testimonial__quote::after { content: ""; }
.c-hero-testimonial__cite {
  display: flex;
  flex-direction: column;
  gap: 2px;
  font-style: normal;
  margin-top: 4px;
}
/* Author — darkened to brand violet at bold weight so it's clearly legible
   on white (the light-purple/teal it used to inherit was too low-contrast). */
.c-hero-testimonial__author {
  color: var(--violet);
  font-family: 'Nunito', system-ui, sans-serif;
  font-size: 16px;
  font-weight: 700;
  line-height: 20px;
}

/* Second instance on a page (the bottom "happy clients" quote) right-aligns its
   quote + author. The general sibling combinator matches only a hero-testimonial
   preceded by another one, so the top quote stays left-aligned. */
.c-hero-testimonial ~ .c-hero-testimonial .c-hero-testimonial__body {
  text-align: right;
}

.c-hero-testimonial__media {
  display: flex;
  flex-direction: column;
  gap: 12px;
  justify-content: center;
}
.c-hero-testimonial__play {
  position: relative;
  aspect-ratio: 4 / 3;            /* fixed shape so it can't expand past the blob */
  display: flex;
  align-items: center;
  justify-content: center;
  background: #F5F3FF;
  border: 1px solid #E8E4F8;
  border-radius: 16px;
  cursor: pointer;
  transition: transform 160ms ease;
}
.c-hero-testimonial__play:active { transform: scale(0.99); }
.c-hero-testimonial__play-circle {
  width: 48px;
  height: 48px;
  border-radius: 50%;
  background: var(--htest-accent, var(--light-purple));
  display: grid;
  place-items: center;
}
.c-hero-testimonial__play-label {
  position: absolute;
  bottom: 12px;
  left: 16px;
  color: var(--htest-accent, var(--light-purple));
  font-family: 'Nunito', system-ui, sans-serif;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.08em;
  line-height: 15px;
  text-transform: uppercase;
}

@media (max-width: 900px) {
  .c-hero-testimonial {
    padding: 120px 20px 120px;
    /* Transparent here too (desktop is) so the body squiggle shows through on
       mobile — a solid var(--bg) here was covering it, leaving the middle dark. */
    background: transparent;
  }
  .c-hero-testimonial__card {
    grid-template-columns: 1fr;
    aspect-ratio: 0.9 / 1;         /* portrait blob on mobile */
    padding: 80px 56px 96px 64px;  /* safe zone inside the narrower blob */
    column-gap: 0;
  }
  .c-hero-testimonial__body { padding: 0; }
  .c-hero-testimonial__media { padding: 0; }
  .c-hero-testimonial__play { aspect-ratio: 16 / 10; }

  /* Mobile layout — Andrew's /edit arrangement, as a robust flow layout so it
     holds at every phone width: original blob, bigger centred KC, no trust
     line, quote, blue author, centred video card. */
  .c-hero-testimonial[data-ht-mobile="fit"] .c-hero-testimonial__card {
    aspect-ratio: auto;
    min-height: 0;
    padding: 40px 60px 48px 50px;
    row-gap: 16px;
  }
  .c-hero-testimonial[data-ht-mobile="fit"] .c-hero-testimonial__card::before {
    -webkit-mask-image: url('/assets/blob-card.svg');
            mask-image: url('/assets/blob-card.svg');
  }
  .c-hero-testimonial[data-ht-mobile="fit"] .c-hero-testimonial__header {
    justify-content: center;
  }
  .c-hero-testimonial[data-ht-mobile="fit"] .c-hero-testimonial__badge { width: 78px; }
  .c-hero-testimonial[data-ht-mobile="fit"] .c-hero-testimonial__eyebrow { display: none; }
  .c-hero-testimonial[data-ht-mobile="fit"] .c-hero-testimonial__quote {
    font-size: 17px; line-height: 26px; padding-right: 0;
  }
  .c-hero-testimonial[data-ht-mobile="fit"] .c-hero-testimonial__author { color: #477ED6; }
  .c-hero-testimonial[data-ht-mobile="fit"] .c-hero-testimonial__media {
    width: 96%;
    margin: 4px auto 0;
  }
  .c-hero-testimonial[data-ht-mobile="fit"] .c-hero-testimonial__play {
    aspect-ratio: 16 / 11;
  }
  /* stack — drop the blob mask entirely; a plain rounded white card that
     flows naturally. Most robust for very long quotes. */
  .c-hero-testimonial[data-ht-mobile="stack"] .c-hero-testimonial__card {
    aspect-ratio: auto;
    min-height: 0;
    padding: 28px 26px 30px;
    row-gap: 20px;
    background: #FFFFFF;
    border-radius: var(--htest-stack-radius, 24px);
  }
  .c-hero-testimonial[data-ht-mobile="stack"] .c-hero-testimonial__card::before {
    display: none;
  }
}

/* == /components/training-in-action/style.css?v=3 == */
/* Training In Action — in-house shoppable reel strip (#58).
   Light-mode section: big dark title + horizontal scroll-snap strip of 9:16
   poster cards; tap opens the .c-reel-box lightbox (built by reel-strip.js).
   Section + title frame carried over from the original Paper 2RD-0 port. */
.c-training-action {
  position: relative;
  background: #FFFFFF;
  /* Bottom padding accounts for the 50px wave-seam overhang from the next
     section, so the strip has visible breathing room above the wave. */
  padding: 32px 40px 96px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 20px;
  overflow: clip;
}
/* display rules beat the hidden attribute; make hidden mean hidden (the
   section ships hidden until reel-strip.js confirms real media exists). */
.c-training-action[hidden] { display: none; }
.c-training-action__title {
  position: relative;
  margin: 0;
  font-family: 'CeraRound', 'Cera Round', 'Nunito', sans-serif;
  font-weight: 900;
  /* Shared section-header size (site-wide type scale). */
  font-size: clamp(38px, 6vw, 60px);
  line-height: 1.08;
  color: var(--bg);
  text-align: center;
}

/* ---- strip ---- */
.c-training-action__strip {
  width: 100%;
  max-width: 1100px;
  display: flex;
  gap: 14px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  -webkit-overflow-scrolling: touch;
  padding: 6px 4px 14px;
  scrollbar-width: none;
}
.c-training-action__strip::-webkit-scrollbar { display: none; }

.c-reel-card {
  position: relative;
  flex: 0 0 auto;
  width: clamp(170px, 44vw, 240px);
  aspect-ratio: 9 / 16;
  border: none;
  padding: 0;
  border-radius: var(--radius-lg);
  overflow: clip;
  background: var(--bg);
  cursor: pointer;
  scroll-snap-align: start;
  box-shadow: 0 10px 26px rgba(10, 9, 26, 0.22);
}
.c-reel-card__poster {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.c-reel-card__play {
  position: absolute;
  top: 50%;
  left: 50%;
  translate: -50% -50%;
  width: 54px;
  height: 54px;
  border-radius: 50%;
  background: #FFFFFF;
  color: var(--bg);
  display: grid;
  place-items: center;
  box-shadow: 0 6px 18px rgba(10, 9, 26, 0.35);
  transition: transform 180ms ease;
}
.c-reel-card__play svg { margin-left: 3px; } /* optical center for the triangle */
@media (hover: hover) {
  .c-reel-card:hover .c-reel-card__play { transform: scale(1.12); }
}
.c-reel-card__caption {
  position: absolute;
  inset: auto 0 0;
  padding: 42px 12px 12px;
  background: linear-gradient(180deg, rgba(10, 9, 26, 0) 0%, rgba(10, 9, 26, 0.82) 100%);
  color: #FFFFFF;
  font-family: 'Nunito', system-ui, sans-serif;
  font-size: 15px;
  font-weight: 700;
  line-height: 1.35;
  text-align: left;
}
.c-reel-card:focus-visible {
  outline: 3px solid var(--teal);
  outline-offset: 3px;
}

/* ---- lightbox (appended to <body> by reel-strip.js) ---- */
body.reel-box-open { overflow: hidden; }

.c-reel-box {
  position: fixed;
  inset: 0;
  z-index: 70;                        /* above the sale toast (60) */
  display: none;
}
.c-reel-box.is-open { display: grid; place-items: center; }
.c-reel-box__scrim {
  position: absolute;
  inset: 0;
  background: rgba(10, 9, 26, 0.88);
}
.c-reel-box__stage {
  position: relative;
  margin: 0;
  aspect-ratio: 9 / 16;
  height: min(86vh, 86dvh);
  max-width: calc(100vw - 20px);
  border-radius: 18px;
  overflow: clip;
  background: var(--bg);
  box-shadow: 0 24px 70px rgba(0, 0, 0, 0.55);
}
.c-reel-box__video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.c-reel-box__close,
.c-reel-box__sound {
  position: absolute;
  top: 12px;
  width: 44px;
  height: 44px;
  border: none;
  border-radius: 50%;
  background: rgba(10, 9, 26, 0.72);
  color: #FFFFFF;
  display: grid;
  place-items: center;
  cursor: pointer;
}
.c-reel-box__close { right: 12px; }
.c-reel-box__sound { left: 12px; }
.c-reel-box__nav {
  position: absolute;
  top: 50%;
  translate: 0 -50%;
  width: 44px;
  height: 44px;
  border: none;
  border-radius: 50%;
  background: rgba(10, 9, 26, 0.72);
  color: #FFFFFF;
  display: grid;
  place-items: center;
  cursor: pointer;
}
.c-reel-box__nav--prev { left: 12px; }
.c-reel-box__nav--next { right: 12px; }
.c-reel-box__nav:disabled { opacity: 0.3; cursor: default; }
.c-reel-box__meta {
  position: absolute;
  inset: auto 0 0;
  padding: 56px 16px calc(16px + env(safe-area-inset-bottom, 0px));
  background: linear-gradient(180deg, rgba(10, 9, 26, 0) 0%, rgba(10, 9, 26, 0.85) 100%);
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 10px;
}
.c-reel-box__caption {
  margin: 0;
  color: #FFFFFF;
  font-family: 'Nunito', system-ui, sans-serif;
  font-size: 16px;
  font-weight: 700;
  line-height: 1.4;
}
.c-reel-box__cta {
  display: inline-block;
  padding: 12px 24px;
  border-radius: var(--radius-pill);
  background: var(--mesh-gradient, linear-gradient(135deg, #A0C7FF 0%, #477ED6 30%, #C77DFF 65%, #9945FF 100%));
  color: #FFFFFF;
  font-family: 'CeraRound', 'Cera Round', 'Nunito', sans-serif;
  font-size: 16px;
  font-weight: 900;
  text-decoration: none;
}
.c-reel-box__close:focus-visible,
.c-reel-box__sound:focus-visible,
.c-reel-box__nav:focus-visible,
.c-reel-box__cta:focus-visible {
  outline: 3px solid var(--teal);
  outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
  .c-reel-card__play { transition: none; }
}
@media (max-width: 640px) {
  .c-training-action { padding: 24px 20px 80px; gap: 14px; }
  /* Keep the nav chevrons clear of the meta bar on small screens. */
  .c-reel-box__stage { height: min(80vh, 80dvh); }
}

/* While the reel section is hidden (no clips in the manifest yet), the home
   boundary above service-cards must read dark-to-dark like the spoke pages:
   hide the white band's top edge (the wavy-seam-bottom that precedes this
   section) and let the body squiggle run down to the service-cards wave.
   Both rules revert automatically the moment reel-strip.js un-hides the
   section — the white band comes back with the clips. */
.c-wavy-seam:has(+ .c-training-action[hidden]) { display: none; }
.c-training-action[hidden] ~ .c-service-cards .c-service-cards__seam-white { fill: transparent; }

/* == /components/why-choose/style.css?v=3 == */
/* Why Choose — Nimiq-foundation rebuild on the dark GDKC stage.
   Editorial two-column: heading/intro on the left, four clean reason cards on the
   right. White space carries the structure; brand color lives only in the gradient
   title accent and the card numbers (color = highlight, not decoration). */
.c-why {
  position: relative;
  background: var(--bg);
  overflow: clip;
  display: flex;
  align-items: center;
}
.c-why__inner {
  position: relative;
  display: grid;
  grid-template-columns: 400px 1fr;
  gap: 72px;
  width: 100%;
  max-width: 1200px;
  margin: 0 auto;
  padding: 112px 80px;
  align-items: center;
  box-sizing: border-box;
}

/* ---- Heading (left) ---- */
.c-why__side {
  display: flex;
  flex-direction: column;
  justify-content: center;
}
.c-why__title {
  margin: 0 0 20px;
  font-family: 'CeraRound', 'Cera Round', 'Nunito', sans-serif;
  font-weight: 900;
  font-size: clamp(40px, 5vw, 60px);
  line-height: 1.04;
  letter-spacing: -0.02em;
  color: var(--text);
  display: flex;
  flex-direction: column;
  gap: 4px;
  text-wrap: balance;
}
.c-why__title-accent {
  background: linear-gradient(90deg, #07EDBE 0%, #9945FF 50%, #FF7EC0 100%);
  background-size: 200% 100%;
  -webkit-background-clip: text;
          background-clip: text;
  color: transparent;
  animation: why-accent-flow 12s ease-in-out infinite;
}
@keyframes why-accent-flow {
  0%, 100% { background-position: 0% 50%; }
  50%      { background-position: 100% 50%; }
}
.c-why__intro {
  margin: 0;
  max-width: 360px;
  color: var(--text-muted);
  font-family: 'Nunito', system-ui, sans-serif;
  font-size: 17px;
  line-height: 26px;
  text-wrap: pretty;
}

/* ---- Reason cards (right) ---- */
.c-why__cards {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
}
.c-why__card {
  display: flex;
  flex-direction: column;
  padding: 28px 28px 30px;
  border-radius: 20px;
  /* Solid outlined card — the site's card language. Four brand border colors
     echo the service-cards set so the two card grids read as a family. */
  border: 2px solid var(--card-accent, var(--light-purple));
  background: var(--bg);
  transition: box-shadow 220ms ease, transform 220ms cubic-bezier(0.25, 0, 0, 1);
}
.c-why__card:nth-child(1) { --card-accent: #9945FF; } /* violet */
.c-why__card:nth-child(2) { --card-accent: #C77DFF; } /* mid-purple */
.c-why__card:nth-child(3) { --card-accent: #477ED6; } /* blue */
.c-why__card:nth-child(4) { --card-accent: #A08CFF; } /* light-purple */
.c-why__card:hover { transform: translateY(-2px); box-shadow: 0 14px 32px rgba(153, 69, 255, 0.20); }
.c-why__num {
  display: block;
  font-family: 'CeraRound', 'Cera Round', 'Nunito', sans-serif;
  font-weight: 900;
  font-size: 40px;
  line-height: 0.9;
  letter-spacing: -0.04em;
  margin-bottom: 16px;
  color: var(--card-accent, var(--light-purple));
}
.c-why__card-title {
  margin: 0 0 10px;
  color: var(--text);
  font-family: 'CeraRound', 'Cera Round', 'Nunito', sans-serif;
  font-weight: 900;
  font-size: 19px;
  line-height: 1.2;
}
.c-why__card-body {
  margin: 0;
  color: var(--text-body);
  font-family: 'Nunito', system-ui, sans-serif;
  font-size: 14px;
  line-height: 1.6;
}

@media (max-width: 1100px) {
  .c-why__inner {
    grid-template-columns: 1fr;
    gap: 40px;
    padding: 80px 40px;
  }
  .c-why__intro { max-width: 520px; }
}
@media (max-width: 560px) {
  .c-why__inner { padding: 64px 20px; }
  .c-why__cards { grid-template-columns: 1fr; }
}

/* == /components/contact-section/style.css == */
/* Contact Section — pixel-port of Paper 10E-0 */
.c-contact {
  background: var(--bg);
  padding: 64px 48px;
  overflow: clip;
  position: relative;
}
.c-contact__inner {
  /* Single centered card since 2026-07-23: the "It all starts here" copy
     column is retired on Andrew's call; the section is just the booking
     card on both A/B arms. */
  display: grid;
  grid-template-columns: 1fr;
  max-width: 640px;
  margin: 0 auto;
}

/* ---- Left column: copy + steps ---- */
.c-contact__copy {
  display: flex;
  flex-direction: column;
  gap: 48px;
  padding: 8px 0;
  justify-content: center;
}
.c-contact__heading {
  display: flex;
  flex-direction: column;
  gap: 16px;
}
.c-contact__title {
  margin: 0;
  font-family: 'CeraRound', 'Cera Round', 'Nunito', sans-serif;
  font-weight: 900;
  font-size: 46px;
  line-height: 1.05;
  letter-spacing: -0.025em;
  color: var(--heading-white);
}
.c-contact__title span { display: block; }
.c-contact__title-accent { color: var(--teal); }

.c-contact__lede {
  margin: 0;
  color: var(--gray-purple);
  font-family: 'Nunito', system-ui, sans-serif;
  font-size: 16px;
  line-height: 1.7;
  max-width: 400px;
}

.c-contact__steps {
  display: flex;
  gap: 28px;
  align-items: stretch;
}
.c-contact__rail {
  flex-shrink: 0;
  width: 2px;
  border-radius: 2px;
  background: linear-gradient(180deg, #9945FF 0%, #07EDBE 50%, #FF7EC0 100%);
}
.c-contact__step-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  flex: 1;
  gap: 32px;
}
.c-contact__step { display: flex; flex-direction: column; gap: 6px; }
.c-contact__step-num {
  font-family: 'Nunito', system-ui, sans-serif;
  font-size: 11px;
  font-weight: 700;
  line-height: 14px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
}
.c-contact__step-title {
  margin: 0;
  color: var(--heading-white);
  font-family: 'CeraRound', 'Cera Round', 'Nunito', sans-serif;
  font-weight: 900;
  font-size: 19px;
  line-height: 1.2;
}
.c-contact__step-body {
  margin: 0;
  color: var(--gray-purple);
  font-family: 'Nunito', system-ui, sans-serif;
  font-size: 14px;
  line-height: 1.65;
}

/* ---- Right column: light form card ---- */
.c-contact__card {
  position: relative;
  background: #FFFFFF;
  border-radius: 20px;
  padding: 36px 32px;
  box-shadow: 0 0 60px rgba(160, 140, 255, 0.15), 0 20px 60px rgba(0, 0, 0, 0.25);
}
/* Gradient outline — replicates Paper's 1.5px masked border */
.c-contact__card::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 20px;
  padding: 1.5px;
  background: linear-gradient(135deg, #9945FF 0%, #07EDBE 50%, #FF7EC0 100%);
  -webkit-mask:
    linear-gradient(#fff 0 0) content-box,
    linear-gradient(#fff 0 0);
  -webkit-mask-composite: xor;
          mask-composite: exclude;
  pointer-events: none;
}
.c-contact__card-title {
  margin: 0 0 24px;
  text-align: center;
  color: var(--bg);
  font-family: 'CeraRound', 'Cera Round', 'Nunito', sans-serif;
  font-weight: 900;
  font-size: 26px;
  line-height: 32px;
  letter-spacing: -0.01em;
}

.c-contact__form { display: flex; flex-direction: column; gap: 12px; }

/* First + last share one row. min-width:0 is load-bearing: inputs carry a
   large intrinsic min-width, so without it the second column overflows the
   card edge instead of shrinking. Stacks below 420px, where two boxes on a
   line leave each one too narrow to read what you typed. */
.c-contact__name-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
}
.c-contact__name-row .c-contact__field { min-width: 0; }
@media (max-width: 420px) {
  .c-contact__name-row { grid-template-columns: 1fr; }
}

.c-contact__field {
  position: relative;
  display: block;
  border-radius: 10px;
  padding: 1.5px;
  background: linear-gradient(135deg, #9945FF 0%, #07EDBE 50%, #FF7EC0 100%);
  transition: box-shadow 160ms ease;
}
.c-contact__field:focus-within {
  box-shadow: 0 0 0 3px rgba(160, 140, 255, 0.25);
}
.c-contact__field > input,
.c-contact__field > textarea {
  display: block;
  width: 100%;
  background: #FFFFFF;
  border: 0;
  border-radius: 9px;
  padding: 13px 15px;
  color: var(--bg);
  font-family: 'Nunito', system-ui, sans-serif;
  font-size: 15px;
  line-height: 18px;
  outline: none;
}
.c-contact__field > input::placeholder,
.c-contact__field > textarea::placeholder {
  color: rgba(10, 9, 26, 0.5);
}
.c-contact__field--textarea > textarea {
  min-height: 88px;
  resize: vertical;
}
.c-contact__label {
  /* Labels visually hidden — placeholders carry the context per Paper design */
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0, 0, 0, 0);
  white-space: nowrap; border: 0;
}

.c-contact__consent {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 4px 0;
  color: rgba(10, 9, 26, 0.5);
  font-family: 'Nunito', system-ui, sans-serif;
  font-size: 12px;
  line-height: 1.6;
}
.c-contact__consent input[type="checkbox"] {
  margin-top: 2px;
  width: 16px;
  height: 16px;
  flex-shrink: 0;
  accent-color: #9945FF;
}

.c-contact__hp {
  position: absolute !important;
  left: -9999px !important;
  width: 1px; height: 1px;
  overflow: hidden;
  opacity: 0;
  pointer-events: none;
}

.c-contact__submit {
  margin-top: 4px;
  border: 0;
  border-radius: 999px;
  padding: 18px 32px;
  background: linear-gradient(135deg, #9945FF 0%, #07EDBE 50%, #FF7EC0 100%);
  color: #FFFFFF;
  font-family: 'Nunito', system-ui, sans-serif;
  font-size: 14px;
  font-weight: 900;
  line-height: 18px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  box-shadow: 0 0 20px rgba(160, 140, 255, 0.3);
  cursor: pointer;
  transition: filter 160ms ease, transform 160ms ease;
}
.c-contact__submit:hover { filter: brightness(1.1); }
.c-contact__submit:active { transform: scale(0.98); }
.c-contact__submit:disabled { opacity: 0.6; cursor: wait; }

.c-contact__error {
  margin: 8px 0 0;
  padding: 10px 14px;
  background: rgba(255, 126, 192, 0.12);
  border: 1px solid var(--pink);
  border-radius: 8px;
  color: #E85C9E;
  font-family: 'Nunito', system-ui, sans-serif;
  font-size: 14px;
}

@media (max-width: 1024px) {
  .c-contact__inner { grid-template-columns: 1fr; }
}
@media (max-width: 560px) {
  .c-contact { padding: 48px 20px; }
  .c-contact__title { font-size: 36px; }
  .c-contact__card { padding: 28px 20px; }
}

/* == /components/faq/style.css?v=2 == */
/* FAQ — pixel-port of Paper J0-1 */
.c-faq {
  position: relative;
  /* Transparent so the body's squiggle tile shows through (#43 — same
     treatment as hero-testimonial). */
  background: transparent;
  overflow: clip;
  padding: 96px 48px;
}
.c-faq__inner {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 48px;
  max-width: 720px;
  margin: 0 auto;
}
.c-faq__header {
  display: flex;
  flex-direction: column;
  gap: 16px;
  text-align: center;
  width: 100%;
}
.c-faq__title {
  margin: 0;
  font-family: 'CeraRound', 'Cera Round', 'Nunito', sans-serif;
  font-weight: 900;
  /* Shared section-header size (site-wide type scale). */
  font-size: clamp(38px, 6vw, 60px);
  line-height: 1.05;
  letter-spacing: -0.02em;
  color: var(--text);
}
.c-faq__title span { display: inline; }
.c-faq__accent { color: var(--light-purple); }
.c-faq__subtitle {
  margin: 0;
  color: rgba(248, 248, 248, 0.55);
  font-family: 'Nunito', system-ui, sans-serif;
  font-size: 18px;
  line-height: 1.6;
}
/* When a page passes an empty subtitle (e.g. the home page), collapse the
   paragraph so it leaves no header gap. */
.c-faq__subtitle:empty { display: none; }

.c-faq__list {
  display: flex;
  flex-direction: column;
  gap: 12px;
  width: 100%;
}
.c-faq__item {
  /* 2px border in every state so open/closed swaps never shift layout. */
  background: var(--surface-card);
  border: 2px solid var(--navy);
  border-radius: 16px;
  overflow: hidden;
  transition: border-color 160ms ease;
}
.c-faq__item:hover { border-color: var(--light-purple); }
/* Expanded: the canonical brand gradient as the border ring (#43) — panel
   fill on padding-box, gradient on border-box, showing through the
   transparent border. */
.c-faq__item[open] {
  border-color: transparent;
  background:
    linear-gradient(var(--surface-card), var(--surface-card)) padding-box,
    linear-gradient(135deg, #9945FF 0%, #07EDBE 50%, #FF7EC0 100%) border-box;
}
.c-faq__item summary {
  list-style: none;
  cursor: pointer;
  padding: 24px 28px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  color: var(--text);
  font-family: 'Nunito', system-ui, sans-serif;
  font-size: 17px;
  line-height: 1.4;
  /* Balanced multi-line wraps: no single-word orphans on phones. */
  text-wrap: balance;
}
.c-faq__item summary::-webkit-details-marker { display: none; }
.c-faq__chev {
  color: var(--light-purple);
  transition: transform 220ms ease;
  flex-shrink: 0;
}
.c-faq__item[open] .c-faq__chev { transform: rotate(180deg); }
.c-faq__body {
  padding: 0 28px 24px;
  color: rgba(248, 248, 248, 0.75);
  font-family: 'Nunito', system-ui, sans-serif;
  font-size: 16px;
  line-height: 1.6;
}
/* Empty-slot items (when q/a are left blank) vanish */
.c-faq__item:has(> summary:empty),
.c-faq__item summary:has(+ .c-faq__body:empty) {
  /* no-op; empty still renders but is hidden via next rule */
}
.c-faq__item summary:empty + .c-faq__body:empty {
  display: none;
}
.c-faq__item summary:empty { display: none; }

@media (max-width: 640px) {
  .c-faq { padding: 64px 20px; }
  /* Type sizes stay at their desktop values on phones (site-wide type scale) —
     only the paddings tighten. */
  .c-faq__item summary { padding: 20px; }
  .c-faq__body { padding: 0 20px 20px; }
}

/* == /components/footer/style.css == */
/* Footer — pixel-port of Paper HJ-1 */
.c-footer {
  position: relative;
  /* Start at the FAQ's exact background (#0A091A) so the seam above is invisible,
     then ease smoothly up through the elevated navy to the lighter #2C2977 at the
     very bottom — one continuous dark-to-light gradient into the footer. */
  background: linear-gradient(180deg, #0A091A 0%, #14122A 22%, #2C2977 100%);
  color: var(--text);
  min-height: 380px;
  display: flex;
  flex-direction: column;
  padding: 64px 120px 0;
  overflow: clip;
}
.c-footer__row {
  flex: 1;
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  gap: 48px;
  align-items: flex-start;
  padding-bottom: 40px;
}

.c-footer__brand {
  display: flex;
  flex-direction: column;
  gap: 12px;
  max-width: 320px;
}
.c-footer__logo {
  display: flex;
  align-items: center;
  gap: 10px;
}
.c-footer__logo img { flex-shrink: 0; }
.c-footer__logo span {
  color: var(--text);
  font-family: 'CeraRound', 'Cera Round', 'Nunito', sans-serif;
  font-weight: 900;
  font-size: 22px;
  line-height: 28px;
  letter-spacing: -0.02em;
}
.c-footer__tagline {
  margin: 0;
  color: rgba(248, 248, 248, 0.5);
  font-family: 'Nunito', system-ui, sans-serif;
  font-size: 15px;
  line-height: 1.6;
}
.c-footer__socials {
  display: flex;
  gap: 20px;
  padding-top: 8px;
}
.c-footer__socials a {
  display: inline-flex;
  color: var(--text);
  transition: transform 160ms ease, opacity 160ms ease;
}
.c-footer__socials a:hover { transform: translateY(-2px); opacity: 0.9; }

.c-footer__eyebrow {
  color: rgba(248, 248, 248, 0.35);
  font-family: 'Nunito', system-ui, sans-serif;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.1em;
  line-height: 14px;
  text-transform: uppercase;
  margin-bottom: 16px;
}

.c-footer__nav ul,
.c-footer__contact ul {
  list-style: none;
  margin: 0;
  padding: 0;
}
.c-footer__nav ul {
  display: flex;
  flex-wrap: wrap;
  gap: 32px;
  align-items: center;
}
.c-footer__nav a {
  color: rgba(248, 248, 248, 0.75);
  text-decoration: none;
  font-family: 'Nunito', system-ui, sans-serif;
  font-size: 15px;
  font-weight: 500;
  line-height: 18px;
  transition: color 160ms ease;
}
.c-footer__nav a:hover { color: var(--teal); }

.c-footer__contact ul {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-bottom: 8px;
}
.c-footer__contact li {
  display: flex;
  align-items: center;
  gap: 10px;
}
.c-footer__contact a {
  color: rgba(248, 248, 248, 0.75);
  text-decoration: none;
  font-family: 'Nunito', system-ui, sans-serif;
  font-size: 15px;
  line-height: 18px;
}
.c-footer__contact a:hover { color: var(--teal); }

.c-footer__cta {
  display: inline-flex;
  align-items: center;
  padding: 2px;
  border-radius: 50px;
  background: linear-gradient(90deg, #9945FF 0%, #07EDBE 100%);
  text-decoration: none;
  margin-top: 8px;
  transition: filter 160ms ease;
}
.c-footer__cta:hover { filter: brightness(1.1); }
.c-footer__cta span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--bg);
  border-radius: 48px;
  padding: 14px 28px;
  color: var(--text);
  font-family: 'Nunito', system-ui, sans-serif;
  font-size: 16px;
  font-weight: 700;
  line-height: 19px;
  letter-spacing: -0.01em;
}

.c-footer__legal {
  padding: 0 0 36px;
}
.c-footer__legal hr {
  border: 0;
  height: 1px;
  background: rgba(160, 140, 255, 0.15);
  margin: 0 0 20px;
}
.c-footer__legal-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  color: rgba(248, 248, 248, 0.3);
  font-family: 'Nunito', system-ui, sans-serif;
  font-size: 13px;
  line-height: 16px;
}

@media (max-width: 1024px) {
  .c-footer { padding: 48px 40px 0; }
  .c-footer__row { grid-template-columns: 1fr; gap: 40px; }
  .c-footer__nav ul { gap: 20px; }
}
@media (max-width: 480px) {
  .c-footer { padding: 40px 24px 0; }
}

/* Hard stop at the footer.
   brand.css adds `body { padding-bottom: max(env(safe-area-inset-bottom), 16px) }`
   for the iPhone home indicator. Because the footer is the last, full-bleed
   element, that padding sat *below* the footer and revealed a strip of the body's
   squiggle background (bigger on notched phones, where the inset is ~34px). Cancel
   it and let the footer's own navy background carry the safe-area inset instead, so
   the footer runs to the true bottom edge with no gap. Kept last so it wins over the
   responsive `padding` shorthands above. */
body { padding-bottom: 0; }
.c-footer { padding-bottom: env(safe-area-inset-bottom, 0px); }

/* == /components/sale-toast/style.css?v=5 == */
/* Sale Toast — the puzzle piece that "separated" from the white You're-not-alone
   band. Its TOP edge is the EXACT wave from wavy-seam-top (same control points,
   via /assets/sale-toast-wave-mask.svg) so it reads as the piece torn off that
   section; it appears only once the user scrolls past that seam (see JS).
   Border = the flowing wavy-seam gradient; surface = the homework band's white +
   light-squiggle tile. --wave = height of the wavy top band. */
.c-sale-toast {
  /* Full-bleed banner: edge to edge and docked to the bottom. The wave band is
     the SAME height as the real seam (100px) and both stretch their 480-unit
     curve across the full viewport width, so the toast's top edge is a 1:1
     copy of the section seam: same amplitude, same phase. */
  --wave: 100px;
  /* STICKY — the TICKET RIP (Andrew 2026-07-22: this is the model, do not
     replace it). The banner starts ATTACHED at the seam (a ticket stapled
     to the section); as the section scrolls up it RIPS off at the dock line
     and rides pinned to the viewport bottom with the user for the rest of
     the wrapper. The compositor drives it: zero scroll lag. JS pulls the
     seam up under it so it takes no flow space. */
  position: -webkit-sticky;
  position: sticky;
  z-index: 60;                        /* above the nav pill (50) */
  /* Sticky TOP pinned at the dock line (viewport height - toast height): in
     flow (attached at the seam) until it rises to the bottom of the screen,
     then pinned there. 100dvh so the dock line follows the collapsing
     mobile URL bar live; JS supplies only --toast-h (measured height). */
  top: calc(100vh - var(--toast-h, 240px));
  top: calc(100dvh - var(--toast-h, 240px));
  width: 100%;
  border-radius: 0;
  /* Own compositor layer: Safari sometimes paints offscreen sticky content
     late (it "pops in" on arrival); promote + will-change keeps it
     pre-rendered. */
  transform: translateZ(0);
  will-change: transform, top;
  transform-origin: var(--genie-x, 50%) var(--genie-y, 100%);
  transition: transform 520ms cubic-bezier(0.55, 0, 0.75, 0.45), opacity 300ms ease 240ms;
  padding: 5px;                       /* = border thickness */
  /* STATIC gradient border (Andrew 2026-07-15: no flow/pulse animation). */
  background: linear-gradient(110deg,
    #07EDBE 0%, #9945FF 30%, #FF7EC0 55%, #9945FF 80%, #07EDBE 100%);
  box-shadow: 0 18px 44px rgba(10, 9, 26, 0.45);
  /* Wavy top edge: the seam curve across the full width, solid below it. */
  -webkit-mask:
    url("/assets/sale-toast-wave-mask.svg") 0 0 / 100% var(--wave) no-repeat,
    linear-gradient(#000, #000) 0 var(--wave) / 100% calc(100% - var(--wave)) no-repeat;
          mask:
    url("/assets/sale-toast-wave-mask.svg") 0 0 / 100% var(--wave) no-repeat,
    linear-gradient(#000, #000) 0 var(--wave) / 100% calc(100% - var(--wave)) no-repeat;
}

/* The genie tuck (Andrew 2026-07-21: "it should look like it's going INTO
   the bone button"): the banner visibly shrinks toward the bubble's spot
   (transform-origin = the bubble center, JS-computed) right where its
   sticky box sits, fading only near the end so the shrink is watchable.
   The sticky box, --toast-h, and the seam's pulled-up margin all stay
   EXACTLY as they are — zero layout impact. Reopening runs it in reverse.
   pointer-events off so the invisible band can't eat taps. */
.c-sale-toast.is-min {
  transform: translateZ(0) scale(0.03);
  opacity: 0;
  pointer-events: none;
}

/* The bubble the banner tucks into: fixed bottom-right, white disc with the
   brand bone, wrapped in the same flowing gradient ring as the toast border
   so it still reads "sale". Independent of the sticky scope on purpose. */
.c-sale-toast-bubble {
  position: fixed;
  right: 16px;
  bottom: calc(16px + env(safe-area-inset-bottom, 0px));
  z-index: 60;                        /* same layer as the toast */
  width: 62px;
  height: 62px;
  padding: 4px;                       /* = ring thickness */
  border: none;
  border-radius: 50%;
  background: linear-gradient(110deg,
    #07EDBE 0%, #9945FF 30%, #FF7EC0 55%, #9945FF 80%, #07EDBE 100%);
  box-shadow: 0 10px 28px rgba(10, 9, 26, 0.35);
  cursor: pointer;
  transform: scale(0);
  opacity: 0;
  pointer-events: none;
  transition: transform 320ms cubic-bezier(0.34, 1.56, 0.64, 1), opacity 200ms ease;
}
.c-sale-toast-bubble.is-on {
  transform: scale(1);
  opacity: 1;
  pointer-events: auto;
}
/* display rules beat the hidden attribute; make hidden mean hidden. */
.c-sale-toast-bubble[hidden] { display: none; }
.c-sale-toast-bubble__disc {
  display: grid;
  place-items: center;
  width: 100%;
  height: 100%;
  border-radius: 50%;
  background: #FFFFFF;
}
.c-sale-toast-bubble__disc img { display: block; }

/* Hamburger menu open: get the sale toast out of the way. It sits above the
   curtain (z 60 > 40), so without this it covers the menu (Andrew 2026-07-14).
   nav-pill.js sets body.nav-pill--menu-open on toggle; fades back on close. */
body.nav-pill--menu-open .c-sale-toast,
body.nav-pill--menu-open .c-sale-toast-bubble {
  opacity: 0;
  pointer-events: none;
}

.c-sale-toast__inner {
  position: relative;
  border-radius: 0;
  background: #FFFFFF url("/assets/squiggle-bg-light.svg") repeat;
  background-size: 480px 480px;
  overflow: hidden;
  /* Same wave on the white panel, scaled to the OUTER geometry (inner is inset
     5px each side, so the mask spans width+10px at -5px) — the two curves stay
     parallel and the gradient shows as a 5px band along the wavy top. */
  -webkit-mask:
    url("/assets/sale-toast-wave-mask.svg") -5px 0 / calc(100% + 10px) var(--wave) no-repeat,
    linear-gradient(#000, #000) 0 var(--wave) / 100% calc(100% - var(--wave)) no-repeat;
          mask:
    url("/assets/sale-toast-wave-mask.svg") -5px 0 / calc(100% + 10px) var(--wave) no-repeat,
    linear-gradient(#000, #000) 0 var(--wave) / 100% calc(100% - var(--wave)) no-repeat;
}
.c-sale-toast__link {
  display: block;
  /* Top padding clears the wave's deepest trough (y=76 of the 100px band);
     bottom padding rides above the iPhone home indicator. */
  padding: 88px 52px calc(18px + env(safe-area-inset-bottom, 0px)) 22px;
  text-decoration: none;
}
.c-sale-toast__title {
  margin: 0 0 4px;
  font-family: 'CeraRound', 'Cera Round', 'Nunito', sans-serif;
  font-weight: 900;
  font-size: 24px;
  line-height: 1.1;
  letter-spacing: -0.01em;
  /* The site's signature gradient on the headline keeps the panel fun. */
  background: linear-gradient(90deg, #07B896 0%, #9945FF 55%, #E8559D 100%);
  -webkit-background-clip: text;
          background-clip: text;
  color: transparent;
  width: fit-content;
}
.c-sale-toast__body {
  margin: 0;
  font-family: 'Nunito', system-ui, sans-serif;
  font-size: 16px;
  line-height: 1.5;
  font-weight: 700;
  color: #171717;
}
.c-sale-toast__code {
  display: inline-block;
  padding: 1px 13px 2px;
  border-radius: 500px;               /* true pill, matching everything round */
  background: #0A091A;
  color: #FFFFFF;
  font-family: 'CeraRound', 'Cera Round', 'Nunito', sans-serif;
  font-weight: 900;
  letter-spacing: 0.06em;
}
/* Two accent pills, color-coded: blue (brand --blue) and pink (#E8559D, NOT a
   brand token; it is this toast's own headline-gradient pink, kept so the pill
   matches the title. Don't copy it elsewhere as if it were --pink). The --boy
   and --girl suffixes are leftovers from the withdrawn discount codes and mean
   nothing now; the component itself is retired and renders on no page. */
.c-sale-toast__code--boy  { background: var(--blue); }
.c-sale-toast__code--girl { background: #E8559D; }
.c-sale-toast__close {
  position: absolute;
  /* Below the wave's trough near the right edge so the pink circle never gets
     clipped by the mask. */
  top: 84px;
  right: 14px;
  width: 36px;
  height: 36px;
  border: none;
  border-radius: 50%;
  background: #0A091A;
  color: #FFFFFF;
  display: grid;
  place-items: center;
  cursor: pointer;
  transition: background 160ms ease;
}
.c-sale-toast__close:hover { background: #1E1B3C; }

@media (prefers-reduced-motion: reduce) {
  /* Minimize still HAPPENS (state lands instantly), it just doesn't animate. */
  .c-sale-toast { animation: none; transition: none; }
  .c-sale-toast-bubble { animation: none; transition: none; }
}
@media (max-width: 560px) {
  .c-sale-toast__title { font-size: 22px; }
  .c-sale-toast__link { padding: 86px 48px calc(16px + env(safe-area-inset-bottom, 0px)) 18px; }
}


/* == /components/pricing-packages/style.css?v=3 == */
/* Pricing & Packages: collectible-card design (2026-07-08). Each tier is an art-forward
   flip "trading card" (inspired by the Discord Wumpus/Phibi cards): big white-outlined dog on
   a top-to-bottom tier gradient with a touching-dot "diamond" texture, a brand tile (top-left)
   + 3 distinct glyphs (top-right), price as the hero, one tagline, and a hero-style gradient
   pill CTA (light-purple ring -> dark gap -> mesh fill -> white-outline label). Tapping
   "what's included" flips to a clean dark panel with the details. Per-tier colour + art/icons
   live in the --four/--six/--eight modifier blocks at the bottom.
   Flip JS: /js/pricing-flip.js. */
.c-pricing {
  position: relative;
  /* Transparent (was an opaque var(--bg)) so the continuous body squiggle shows
     through the gutters around the cards — otherwise this section is a blank dark
     void between the whats-included and lifetime-support squiggle fields. The
     cards, FAQ and CTA keep their own backgrounds, so only the empty gaps change. */
  background: transparent;
  overflow: clip;
}
.c-pricing__inner {
  position: relative;
  width: 100%;
  max-width: 1180px;
  margin: 0 auto;
  padding: 80px 48px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 40px;
  box-sizing: border-box;
}

/* ---- Header ---- */
.c-pricing__header { display: flex; flex-direction: column; align-items: center; }
.c-pricing__title {
  margin: 0;
  font-family: 'CeraRound', 'Cera Round', 'Nunito', sans-serif;
  font-weight: 900;
  /* Shared section-header size (site-wide type scale). */
  font-size: clamp(38px, 6vw, 60px);
  line-height: 1.08;
  letter-spacing: -0.02em;
  text-align: center;
  text-wrap: balance;
  color: var(--text);
}

/* ---- Cards row ---- */
.c-pricing__cards {
  display: flex;
  flex-wrap: wrap;
  gap: 26px;
  justify-content: center;
  width: 100%;
}

/* ---- Flip card ---- */
.c-pricing__card {
  width: 344px;
  max-width: 100%;
  height: 548px;
  perspective: 1600px;
}
.c-pricing__card-inner {
  position: relative;
  width: 100%;
  height: 100%;
  transition: transform 0.6s cubic-bezier(0.4, 0.1, 0.2, 1);
  transform-style: preserve-3d;
}
.c-pricing__card.is-flipped .c-pricing__card-inner { transform: rotateY(180deg); }
/* Midpoint crossfade (see .c-pricing__face comment). pointer-events keeps taps
   off whichever face is hidden. */
.c-pricing__front { opacity: 1; }
.c-pricing__back { opacity: 0; pointer-events: none; }
.c-pricing__card.is-flipped .c-pricing__front { opacity: 0; pointer-events: none; }
.c-pricing__card.is-flipped .c-pricing__back { opacity: 1; pointer-events: auto; }
.c-pricing__face {
  position: absolute;
  inset: 0;
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
  /* iOS WebKit ignores ancestor backface-visibility for children with their own
     filter (the hero art's drop-shadow outline), so the hidden face bled through
     during the rotation. Crossfade the faces around the flip's midpoint (0.6s
     flip; fade runs 240-360ms, centred on the edge-on 300ms mark). Opacity runs
     on the compositor in lockstep with the transform — a delayed visibility
     swap ran on the main thread and could blank the whole card mid-flip. */
  transition: opacity 120ms linear 240ms;
  border-radius: 26px;
  overflow: hidden;
  border: 8px solid var(--c);
  background: var(--bg-elev-1);
}

/* ---- Front: art panel ---- */
.c-pricing__art {
  position: relative;
  height: 52%;
  /* top-to-bottom tier gradient */
  background: linear-gradient(180deg, var(--c-top) 0%, var(--c) 55%, var(--c-deep) 100%);
  overflow: hidden;
}
/* touching dots -> the smooth gradient reads through as little diamonds */
.c-pricing__dots {
  position: absolute;
  inset: 0;
  background-image: radial-gradient(circle at 9px 9px, rgba(16, 14, 38, 0.34) 9px, transparent 9.6px);
  background-size: 18px 18px;
}
.c-pricing__hero {
  position: absolute;
  inset: 8% 11%;
  background: var(--art) center / contain no-repeat;
  /* white keyline (matches the sticker-style dogs) + soft depth shadow.
     16 evenly-spaced directions so the outline stays smooth/round on busy shapes
     (8 directions left visible polygon spikes on Dog-Speak). */
  filter:
    drop-shadow(2.6px 0 0 #fff) drop-shadow(2.4px 0.99px 0 #fff) drop-shadow(1.84px 1.84px 0 #fff) drop-shadow(0.99px 2.4px 0 #fff)
    drop-shadow(0 2.6px 0 #fff) drop-shadow(-0.99px 2.4px 0 #fff) drop-shadow(-1.84px 1.84px 0 #fff) drop-shadow(-2.4px 0.99px 0 #fff)
    drop-shadow(-2.6px 0 0 #fff) drop-shadow(-2.4px -0.99px 0 #fff) drop-shadow(-1.84px -1.84px 0 #fff) drop-shadow(-0.99px -2.4px 0 #fff)
    drop-shadow(0 -2.6px 0 #fff) drop-shadow(0.99px -2.4px 0 #fff) drop-shadow(1.84px -1.84px 0 #fff) drop-shadow(2.4px -0.99px 0 #fff)
    drop-shadow(0 8px 18px rgba(10, 9, 26, 0.4));
}
.c-pricing__tile {
  position: absolute;
  top: 16px; left: 16px;
  width: 54px; height: 54px;
  border-radius: 15px;
  background: rgba(255, 255, 255, 0.92);
  display: grid;
  place-items: center;
}
.c-pricing__tile::after {
  content: "";
  width: 32px; height: 32px;
  background: var(--c-deep);
  -webkit-mask: var(--glyph) center / contain no-repeat;
          mask: var(--glyph) center / contain no-repeat;
}
.c-pricing__strip {
  position: absolute;
  top: 18px; right: 16px;
  display: flex;
  flex-direction: column;
  gap: 13px;
}
.c-pricing__strip span { width: 25px; height: 25px; background: rgba(255, 255, 255, 0.55); }
.c-pricing__strip .s1 { -webkit-mask: var(--g1) center / contain no-repeat; mask: var(--g1) center / contain no-repeat; }
.c-pricing__strip .s2 { -webkit-mask: var(--g2) center / contain no-repeat; mask: var(--g2) center / contain no-repeat; }
.c-pricing__strip .s3 { -webkit-mask: var(--g3) center / contain no-repeat; mask: var(--g3) center / contain no-repeat; }

/* ---- Front: band ---- */
.c-pricing__band {
  height: 48%;
  padding: 20px 22px;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  justify-content: center;
}
.c-pricing__eyebrow {
  font-family: 'CeraRound', 'Cera Round', 'Nunito', sans-serif;
  font-weight: 900;
  font-size: 12px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--c-lt);
}
.c-pricing__price {
  font-family: 'CeraRound', 'Cera Round', 'Nunito', sans-serif;
  font-weight: 900;
  font-size: 50px;
  line-height: 1;
  letter-spacing: -0.03em;
  color: #fff;
  margin: 3px 0 0;
}
/* No box (house rule: no glassmorphism) — just the dot + line. */
.c-pricing__tag {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 14px 0 0;
}
.c-pricing__tag-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--c-lt); flex-shrink: 0; }
.c-pricing__tag b { color: #F8F8F8; font-weight: 800; font-size: 15px; line-height: 1.3; }

/* Gradient-pill CTA — hero button treatment: light-purple ring -> dark gap -> mesh fill
   -> dark label with a thick white outline (paint-order stroke). */
.c-pricing__card-cta {
  margin-top: 18px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 6px;
  border: 5px solid var(--light-purple);
  border-radius: 999px;
  background: var(--bg);
  text-decoration: none;
  transition: filter 160ms ease, transform 160ms ease;
}
.c-pricing__card-cta:hover { filter: brightness(1.08); transform: translateY(-1px); }
.c-pricing__card-cta:active { transform: scale(0.98); }
.c-pricing__card-cta-inner {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  border-radius: 999px;
  padding: 13px;
  background: linear-gradient(135deg, #07EDBE 0%, #9945FF 50%, #FF7EC0 100%);
}
.c-pricing__card-cta-label {
  color: #0A091A;
  font-family: 'CeraRound', 'Cera Round', 'Nunito', sans-serif;
  font-weight: 900;
  font-size: 21px;
  -webkit-text-stroke: 4px #fff;
          text-stroke: 4px #fff;
  paint-order: stroke fill;
}
.c-pricing__flip {
  /* Plain tier-colored text link (Andrew: no pill-under-pill below the CTA) —
     the tier's light color makes it clearly tappable without competing with
     the Get-started pill above it. */
  margin: 12px auto 0;
  background: none;
  border: none;
  color: var(--c-lt);
  font-family: 'Nunito', system-ui, sans-serif;
  font-size: 14px;
  font-weight: 800;
  display: flex;
  align-items: center;
  gap: 7px;
  cursor: pointer;
  transition: filter 160ms ease;
}
.c-pricing__flip:hover { filter: brightness(1.15); }
.c-pricing__flip svg { width: 15px; height: 15px; }

/* ---- Back: clean dark details panel ---- */
.c-pricing__back {
  transform: rotateY(180deg);
  /* Extra bottom padding reserves room for the flip-back button, which is
     pinned to the card's bottom edge (not floated mid-card after the list). */
  padding: 28px 26px 82px;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  justify-content: center;
}
.c-pricing__back-name {
  margin: 0;
  font-family: 'CeraRound', 'Cera Round', 'Nunito', sans-serif;
  font-weight: 900;
  font-size: 26px;
  line-height: 1.2;
  color: #fff;
  text-wrap: balance;
}
.c-pricing__back-price { color: var(--c-lt); font-weight: 900; font-size: 26px; margin: 6px 0 12px; font-family: 'CeraRound', 'Cera Round', 'Nunito', sans-serif; }
.c-pricing__back-note { color: rgba(248, 248, 248, 0.8); font-size: 15px; line-height: 1.5; margin: 0 0 13px; font-family: 'Nunito', system-ui, sans-serif; }
.c-pricing__back-list { list-style: none; margin: 0 0 14px; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.c-pricing__back-list li {
  position: relative;
  padding-left: 19px;
  color: rgba(248, 248, 248, 0.85);
  font-size: 15px;
  line-height: 1.45;
  font-family: 'Nunito', system-ui, sans-serif;
}
.c-pricing__back-list li::before { content: ""; position: absolute; left: 0; top: 5px; width: 7px; height: 7px; border-radius: 50%; background: var(--c-lt); }
/* Back flip control: symbol only, a centered round icon button. */
.c-pricing__flip--back {
  /* Pinned to the bottom edge of the back face so it never floats mid-card
     when the content is short. Tier-colored (see variant styles below). */
  position: absolute;
  bottom: 18px;
  left: 50%;
  transform: translateX(-50%);
  margin: 0;
  width: 46px; height: 46px;
  border-radius: 50%;
  background: transparent;
  border: 2px solid var(--c);
  display: grid;
  place-items: center;
  gap: 0;
  color: var(--c-lt);
  transition: color 160ms ease, background 160ms ease;
}
.c-pricing__flip--back:hover { color: var(--text); background: rgba(255, 255, 255, 0.06); }
.c-pricing__flip--back svg { width: 19px; height: 19px; }

/* ---- Per-tier colour + art/icons ---- */
.c-pricing__card--four {
  --c: #477ED6; --c-top: #5B8FE0; --c-deep: #243a6b; --c-lt: #A0C7FF;
  --art: url("/assets/icons/playground/Dog-Wait.svg");
  --glyph: url("/assets/icons/playground/Paw-Print-Purple.svg");
  --g1: url("/assets/icons/playground/Loop-Teal.svg");
  --g2: url("/assets/icons/playground/Bone-Blue.svg");
  --g3: url("/assets/icons/playground/Dog-House-Blue.svg");
}
.c-pricing__card--six {
  --c: #9945FF; --c-top: #B06BFF; --c-deep: #4b1f80; --c-lt: #C9A6FF;
  --art: url("/assets/icons/playground/Dog-Playing-Catch.svg");
  --glyph: url("/assets/icons/playground/Lightning-Bolt-Purple.svg");
  --g1: url("/assets/icons/playground/Dog-Bone-Blue.svg");
  --g2: url("/assets/icons/playground/Loop-Purple-1.svg");
  --g3: url("/assets/icons/playground/Squiggle-Purple.svg");
}
.c-pricing__card--eight {
  --c: #C77DFF; --c-top: #D9A6FF; --c-deep: #6b3f8f; --c-lt: #E7CCFF;
  --art: url("/assets/icons/playground/Dog-Speak.svg");
  --glyph: url("/assets/icons/playground/Crown-Blue.svg");
  --g1: url("/assets/icons/playground/Shuttlecock.svg");
  --g2: url("/assets/icons/playground/Award.svg");
  --g3: url("/assets/icons/playground/Football-Teal.svg");
}

/* ---- FAQ (pricing logistics) ---- */
.c-pricing__faq {
  width: 100%;
  max-width: 820px;
  padding: 24px 28px 26px;
  border-radius: 16px;
  border: 1px solid var(--surface-border);
  /* Solid (was translucent) so the body squiggle behind the transparent section
     doesn't bleed through and hurt readability. */
  background: var(--bg-elev-1);
  box-sizing: border-box;
}
/* Title reads a full step above the question rows (26px CeraRound vs 16px
   Nunito) so the panel has clear hierarchy. */
.c-pricing__faq-title { margin: 0 0 10px; font-family: 'CeraRound', 'Cera Round', 'Nunito', sans-serif; font-weight: 900; font-size: 26px; line-height: 1.15; color: var(--text); }
.c-pricing__faq-item { border-bottom: 1px solid var(--surface-border); }
.c-pricing__faq-item:last-child { border-bottom: none; }
.c-pricing__faq-item summary {
  display: flex; align-items: center; justify-content: space-between; gap: 14px;
  padding: 13px 2px; cursor: pointer; list-style: none;
  color: var(--text); font-family: 'Nunito', system-ui, sans-serif; font-size: 16px; font-weight: 700;
  /* Balanced two-line wraps: no single-word orphans ("package?", "metro?"). */
  text-wrap: balance;
}
.c-pricing__faq-item summary::-webkit-details-marker { display: none; }
.c-pricing__faq-chev { flex-shrink: 0; color: var(--light-purple); transition: transform 180ms ease; }
.c-pricing__faq-item[open] .c-pricing__faq-chev { transform: rotate(180deg); }
.c-pricing__faq-body { padding: 0 2px 14px; color: rgba(248, 248, 248, 0.68); font-family: 'Nunito', system-ui, sans-serif; font-size: 16px; line-height: 1.6; }

/* ---- Bottom CTA: lead line + a button that matches the card CTAs (ring -> dark gap
   -> mesh fill -> white-outline label), but keeps the animated Paper mesh. ---- */
.c-pricing__cta-row { display: flex; flex-direction: column; align-items: center; gap: 14px; }
.c-pricing__cta-lead {
  margin: 0;
  color: rgba(248, 248, 248, 0.72);
  font-family: 'Nunito', system-ui, sans-serif;
  font-size: 17px;
  font-weight: 700;
  text-align: center;
}
.c-pricing__cta-solid {
  display: inline-flex;
  padding: 6px;
  border: 5px solid var(--light-purple);
  border-radius: 999px;
  background: var(--bg);
  text-decoration: none;
  transition: filter 160ms ease, transform 160ms ease, box-shadow 160ms ease;
}
.c-pricing__cta-solid:hover { filter: brightness(1.08); transform: translateY(-2px); box-shadow: var(--shadow-glow-violet); }
.c-pricing__cta-solid:active { transform: scale(0.98); }
.c-pricing__cta-solid-inner {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 999px;
  padding: 14px 40px;
  overflow: hidden;
  isolation: isolate;
  background: linear-gradient(135deg, #07EDBE 0%, #9945FF 50%, #FF7EC0 100%);
}
.c-pricing__cta-mesh { position: absolute; inset: 0; z-index: 0; border-radius: inherit; pointer-events: none; }
.c-pricing__cta-mesh canvas { display: block; width: 100% !important; height: 100% !important; border-radius: inherit; }
.c-pricing__cta-solid-label {
  position: relative;
  z-index: 1;
  color: #0A091A;
  font-family: 'CeraRound', 'Cera Round', 'Nunito', sans-serif;
  font-weight: 900;
  font-size: 24px;
  -webkit-text-stroke: 4px #fff;
          text-stroke: 4px #fff;
  paint-order: stroke fill;
}

/* ---- Responsive ---- */
@media (max-width: 980px) {
  .c-pricing__inner { padding: 56px 20px; gap: 32px; }
}
/* Phones: cards fill the width (not the fixed 344px), but keep a comfortable
   side margin so they aren't edge-to-edge. */
@media (max-width: 560px) {
  .c-pricing__inner { padding: 56px 26px; }
  .c-pricing__cards { gap: 20px; }
  .c-pricing__card { width: 100%; max-width: 440px; height: 560px; }
}
@media (max-width: 480px) {
  .c-pricing__cta-solid-inner { padding: 13px 24px; }
  .c-pricing__cta-solid-label { font-size: 20px; }
  .c-pricing__faq { padding: 20px 18px 22px; }
}

/* == /components/pain-mirror/style.css == */
/* Pain-Mirror — "Sound familiar?" — behavior-segmented cards.
   DESIGN: pink/coral section accent. The full repeating squiggle is dialled back to a
   soft corner band (radial-masked, low opacity); a big coral blob (top-right) and a
   violet blob (bottom-left) carry the background interest instead. Each behavior group
   keeps its own accent so the categories still read as distinct.
   ANIMATION HOOKS: [data-animate] on header + cards (scroll-reveal / stagger),
   [data-three-blob] on the blob layer (a soft Three.js metaball could replace it later). */
.c-pain-mirror {
  position: relative;
  background: var(--bg);
  overflow: clip;
}
/* coral + violet gradient blobs — the new background interest */
.c-pain-mirror__blobs {
  position: absolute;
  inset: 0;
  pointer-events: none;
  overflow: clip;
}
.c-pain-mirror__blob {
  position: absolute;
  border-radius: 50%;
  filter: blur(70px);
  opacity: 0.45;
}
.c-pain-mirror__blob--coral {
  width: 540px; height: 540px;
  top: -200px; right: -160px;
  background: radial-gradient(circle at 35% 35%, #FF7EC0 0%, rgba(255, 126, 192, 0.35) 45%, transparent 72%);
}
.c-pain-mirror__blob--violet {
  width: 480px; height: 480px;
  bottom: -220px; left: -140px;
  background: radial-gradient(circle at 60% 40%, #9945FF 0%, rgba(153, 69, 255, 0.30) 45%, transparent 72%);
  opacity: 0.35;
}
/* squiggle pattern — kept only as a faded top-right corner wash */
.c-pain-mirror__pattern {
  position: absolute;
  inset: 0;
  background-image: url("/assets/squiggle-bg.svg");
  background-size: 420px 420px;
  opacity: 0.16;
  pointer-events: none;
  -webkit-mask-image: radial-gradient(120% 90% at 100% 0%, #000 0%, rgba(0,0,0,0.45) 38%, transparent 70%);
          mask-image: radial-gradient(120% 90% at 100% 0%, #000 0%, rgba(0,0,0,0.45) 38%, transparent 70%);
}
.c-pain-mirror__inner {
  position: relative;
  width: 100%;
  max-width: 1240px;
  margin: 0 auto;
  padding: 80px 48px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 40px;
  box-sizing: border-box;
}

/* ---- Header ---- */
.c-pain-mirror__header { display: flex; flex-direction: column; align-items: center; gap: 14px; text-align: center; }
.c-pain-mirror__eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 6px 14px;
  background: var(--surface-card);
  border: 1px solid var(--navy);
  border-radius: 100px;
  color: var(--light-purple);
  font-family: 'CeraRound', 'Cera Round', 'Nunito', sans-serif;
  font-weight: 900;
  font-size: 10px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  line-height: 1;
}
.c-pain-mirror__eyebrow-dot {
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--light-purple); flex-shrink: 0;
}
.c-pain-mirror__title {
  margin: 0;
  max-width: 880px;
  font-family: 'CeraRound', 'Cera Round', 'Nunito', sans-serif;
  font-weight: 900;
  font-size: 48px;
  line-height: 1.08;
  letter-spacing: -0.02em;
  color: var(--text);
}
.c-pain-mirror__title-accent {
  background: linear-gradient(92deg, #FF7EC0 0%, #FFA98E 100%);
  -webkit-background-clip: text;
          background-clip: text;
  color: transparent;
}
.c-pain-mirror__eyebrow { color: var(--pink); }
.c-pain-mirror__eyebrow-dot { background: var(--pink); }
.c-pain-mirror__subtitle {
  margin: 0;
  max-width: 620px;
  color: rgba(248, 248, 248, 0.55);
  font-family: 'Nunito', system-ui, sans-serif;
  font-size: 16px;
  line-height: 1.6;
}

/* ---- Grid of behavior cards ---- */
.c-pain-mirror__grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 20px;
  width: 100%;
  align-items: start;
}
.c-pain-mirror__card {
  --accent: var(--light-purple);
  --accent-soft: rgba(160, 140, 255, 0.16);
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 14px;
  padding: 26px 26px 28px;
  border-radius: 20px;
  border: 1px solid var(--surface-border);
  background: linear-gradient(180deg, rgba(20, 18, 42, 0.7) 0%, rgba(20, 18, 42, 0.35) 100%);
  transition: border-color 200ms ease, transform 200ms ease;
}
.c-pain-mirror__card::before {
  content: "";
  position: absolute;
  inset: 0 auto 0 0;
  width: 3px;
  border-radius: 20px 0 0 20px;
  background: var(--accent);
}
.c-pain-mirror__card:hover { border-color: var(--accent-soft); transform: translateY(-3px); }
/* Behavior accents */
.c-pain-mirror__card--reactivity { --accent: var(--pink);        --accent-soft: rgba(255, 126, 192, 0.20); }
.c-pain-mirror__card--aggression { --accent: #E85C9E;           --accent-soft: rgba(232, 92, 158, 0.20); }
.c-pain-mirror__card--fear       { --accent: var(--light-blue);  --accent-soft: rgba(160, 199, 255, 0.20); }
.c-pain-mirror__card--puppy      { --accent: var(--teal);        --accent-soft: rgba(7, 237, 190, 0.20); }
.c-pain-mirror__card--general    { --accent: var(--light-purple); --accent-soft: rgba(160, 140, 255, 0.20); }

.c-pain-mirror__card-title {
  margin: 0;
  font-family: 'CeraRound', 'Cera Round', 'Nunito', sans-serif;
  font-weight: 900;
  font-size: 15px;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--accent);
}
.c-pain-mirror__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.c-pain-mirror__list li {
  position: relative;
  padding-left: 22px;
  color: rgba(248, 248, 248, 0.78);
  font-family: 'Nunito', system-ui, sans-serif;
  font-size: 14.5px;
  line-height: 1.55;
}
.c-pain-mirror__list li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 8px;
  width: 7px; height: 7px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 0 4px var(--accent-soft);
}
.c-pain-mirror__list em { font-style: italic; color: var(--text); }

/* ---- Closer ---- */
.c-pain-mirror__closer {
  margin: 4px 0 0;
  max-width: 720px;
  text-align: center;
  font-family: 'CeraRound', 'Cera Round', 'Nunito', sans-serif;
  font-weight: 900;
  font-size: 22px;
  line-height: 1.4;
  letter-spacing: -0.01em;
  color: rgba(248, 248, 248, 0.85);
}
.c-pain-mirror__closer-accent {
  background: var(--mesh-text-gradient);
  -webkit-background-clip: text;
          background-clip: text;
  color: transparent;
}

/* Animation hooks (markup only — no JS yet): [data-animate="fade-up"|"stagger"] on the
   header / grid / closer; [data-three-blob] on .c-pain-mirror__blobs. */

/* ---- Responsive ---- */
@media (max-width: 980px) {
  .c-pain-mirror__inner { padding: 56px 24px; gap: 32px; }
  .c-pain-mirror__grid { grid-template-columns: 1fr; max-width: 560px; }
  .c-pain-mirror__title { font-size: 36px; }
  .c-pain-mirror__closer { font-size: 19px; }
  .c-pain-mirror__blob--coral { width: 360px; height: 360px; top: -140px; right: -120px; }
  .c-pain-mirror__blob--violet { width: 320px; height: 320px; }
}
@media (max-width: 480px) {
  .c-pain-mirror__title { font-size: 30px; }
  .c-pain-mirror__card { padding: 22px; }
}

/* == /components/pain-mirror-v2/style.css?v=31 == */
/* Pain Mirror v2 — "You're not alone." TWO-ACT layout (Andrew 2026-07-18).
   Act 1 (__moment): the four pain-point quotes LARGE in their blob shapes,
   flowing down the page left/right/left/right so each one springs into place
   as it scrolls into view (per-blob reveal; float personalities unchanged).
   Act 2 (__theater): the arch-framed cutout video at a much bigger size, the
   caption pill above it, the blue sound blob on the frame corner, CTA below.
   Section still runs dark (body squiggle) → white via the oklab gradient. */

.c-pm2 {
  position: relative;
  width: 100%;
  /* 48px top (was 24): Andrew 2026-07-20 — the deck scene crowded the hero
     on approach; "a little bit more space". */
  padding: 48px 0 64px;
  /* Body owns the squiggle pattern. This section is a transparent-to-white
     gradient layered on top: the quote act + theater title sit on the dark
     squiggle, the video frame lands on white. Length stops, not % — the
     fade must complete behind the (opaque) video frame regardless of how
     tall the theater content runs. */
  /* lvh, matching the stage height — svh-based stops started the fade too
     early once the stage grew, washing the theater title zone (Andrew:
     "the spacing got a little janky"). Fade waits until below the title,
     completes behind the opaque video frame. */
  background: linear-gradient(in oklab 180deg,
              transparent 0,
              transparent calc(100lvh + 208px),
              #ffffff calc(100lvh + 548px));
  /* clip, NOT hidden: overflow:hidden would create a scroll box; clip only
     paint-clips the edge-hugging icons. */
  overflow: clip;
}

/* ═══ Act 1 — the pain points: a swipe-per-card deck (stories mode) ═══
   NO scroll-snap and NO sticky pinning (Andrew 2026-07-19: snap made the
   hero exit + deck exit jarring, and the sticky stage still let the page
   visibly scroll behind the cards on his iPhone). Instead the driver in
   pain-mirror-callouts.js LOCKS page scrolling the moment the stage reaches
   the top of the viewport and turns the stage into a fixed overlay: each
   swipe/wheel-step deals exactly one card, and the step after card 4
   simply releases the lock — scrolling is the user's again (Andrew
   2026-07-21: the auto-glide "really whips you down"). While locked the
   page cannot scroll AT ALL, so nothing behind the cards can move. */
.c-pm2__moment {
  position: relative;
  z-index: 2;
  /* Spacer: keeps the page layout identical while the stage inside is
     lifted to position:fixed during the lock. LARGE viewport height: the
     deck captures mid-scroll when Safari's bars are collapsed, so the full
     screen is the real canvas — svh squeezed Andrew's icon column by ~170px
     and crushed his spacing (2026-07-20). */
  height: 100vh;
  height: 100lvh;
}
.c-pm2__stick {
  position: relative;
  height: 100%;
  /* Transparent in flow — the body's own squiggle shows through, so there is
     only ever ONE pattern field on screen (no second copy = no seam). */
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: clamp(24px, 5vh, 56px);
  padding: 0 20px;
}
/* Stories mode: the stage rides the viewport while the driver holds page
   scroll frozen. Under the nav pill (50) and sale toast (60).
   --pm2-settle: the driver starts the overlay at the capture frame's exact
   visual offset (a fast flick overshoots alignment by a frame or two) and
   then transitions it to 0 — the stage settles into place like a
   rubber-band instead of snapping (Andrew 2026-07-21: the align-snap read
   as a harsh jolt). */
.c-pm2__stick.is-locked {
  position: fixed;
  top: var(--pm2-settle, 0px);
  left: 0;
  right: 0;
  height: 100vh;
  height: 100lvh;
  z-index: 40;
  transition: top 340ms cubic-bezier(0.16, 1, 0.3, 1);
}
/* The locked stage paints its own squiggle, phase-matched by the driver
   (--pm2-freeze-y) to the exact pattern the body was showing at lock, so
   the takeover is pixel-invisible. 100lvh + 220px: covers the bottom strip
   that opens when the iOS URL bar is collapsed, PLUS the gap under the
   overlay while it is settling from a negative --pm2-settle offset. */
.c-pm2__stick.is-locked::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: calc(100vh + 220px);
  height: calc(100lvh + 220px);
  z-index: -1;
  background: var(--bg, #0A091A) url("/assets/squiggle-bg.svg") repeat;
  background-size: 480px 480px;
  background-position: 0 var(--pm2-freeze-y, 0px);
}

/* Floating doodle icons — Andrew's hand-made arrangement from
   /deck-playground (saved 2026-07-20). Two layers: __icons rides inside the
   stage (deals/locks with it), __icons--theater rides the theater (around
   the title/video). Positions are CENTER-anchored % straight from his saved
   layout; --sx/--sy carry his flips. */
.c-pm2__icons {
  position: absolute;
  inset: 0;
  pointer-events: none;
}
.c-pm2__icon {
  position: absolute;
  transform: translate(-50%, -50%) rotate(var(--r, 0deg)) scale(var(--sx, 1), var(--sy, 1));
}
/* The bob lives on the inner img and is GSAP-driven (pain-mirror-float.js):
   scrolling ramps it to a stop and settling eases it back in — a CSS
   animation could only pause/resume binary, which read as a harsh jolt
   (Andrew 2026-07-21). The outer div keeps the positioning transform. */
.c-pm2__icon img {
  display: block;
  width: 100%;
  height: auto;
}
/* Andrew authored the MOBILE arrangement; no desktop composition exists yet
   (deck-playground Desktop mode is empty) — hide on big screens until he
   makes one. */
@media (min-width: 820px) {
  .c-pm2__icons { display: none; }
}
.c-pm2__header {
  text-align: center;
  /* "Just a hair" down (Andrew 2026-07-21). Transform, not margin — the
     stage column is flex-centered, so a margin would shift the deck too. */
  transform: translateY(10px);
}
.c-pm2__title {
  margin: 0;
  font-family: 'CeraRound', 'Cera Round', 'Nunito', sans-serif;
  font-weight: 900;
  /* Shared section-header size (matches "How I Can Help" and "From First Call…"). */
  font-size: clamp(38px, 6vw, 60px);
  line-height: 1.02;
  letter-spacing: -0.02em;
  color: var(--text, #F8F8F8);
}
/* "alone" in plain white like the rest of the line (Andrew 2026-07-21 —
   replaced the teal-violet-pink gradient clip). */
.c-pm2__title-accent {
  color: var(--text, #F8F8F8);
}

/* The deck: one shared stage; every card is absolutely centered in it and
   carries a small resting offset + tilt so the pile reads as tossed cards,
   with each earlier card's colored edge peeking out from under the next. */
.c-pm2__deck {
  position: relative;
  /* 76vw: Andrew 2026-07-21 — "just a slight bit" bigger so the quotes fit
     nicely (72 was his 07-20 shrink from 88; don't creep further without
     him). */
  width: min(76vw, 640px);
  aspect-ratio: 380 / 220;
  /* Room for the peeking edges of the offset cards. */
  margin: 4vh 0 6vh;
  /* Whole pile up a touch (Andrew 2026-07-21: "move the blobs up just a
     little bit") — transform, not margin, so the flex layout around it
     stays put. */
  transform: translateY(-14px);
}
.c-pm2__card {
  position: absolute;
  inset: 0;
  transform: translate(var(--deck-x, 0), var(--deck-y, 0)) rotate(var(--deck-r, 0deg));
}
/* THREE cards (Andrew 2026-07-21). Deal order 1 → 3 → 2; DOM order = stack
   order, so no z-index needed. NO offsets/rotations since his hand-drawn
   shapes (/deck-shapes, baked 2026-07-21): the cards were drawn as layers
   in shared deck coordinates, so the peeking edges are composed INTO the
   paths themselves. */

.c-pm2__blob {
  position: absolute;
  inset: 0;
  /* GSAP owns opacity/transform from frame 1; CSS provides the rest-tilt
     fallback for prefers-reduced-motion. */
  opacity: 0;
  transform: rotate(var(--rest-tilt, 0deg));
  filter: drop-shadow(0 12px 24px rgba(10, 9, 26, 0.5));
  will-change: transform, filter;
  /* Graceful fade if GSAP never loads (callouts JS still adds .is-visible). */
  transition: opacity 400ms ease;
}
.c-pm2__blob.is-visible { opacity: 1; }
.c-pm2__blob-shape {
  position: absolute;
  inset: 0;
  /* Andrew's drawn shapes intentionally spill past the deck viewBox —
     don't clip them at the box edge. */
  overflow: visible;
  width: 100%;
  height: 100%;
}
.c-pm2__blob-content {
  position: relative;
  z-index: 1;
  display: flex;
  height: 100%;
  justify-content: center;
  align-items: center;
  text-align: center;
  padding: 8% 12%;
  /* Text reads straight even though the card is tilted (Andrew 2026-07-18):
     undo the deck offset + rest tilt. The float wobble (±1-2°) remains —
     alive, but "pretty straight". */
  transform: rotate(calc((var(--deck-r, 0deg) + var(--rest-tilt, 0deg)) * -1));
}
.c-pm2__blob-quote {
  margin: 0;
  font-family: 'Nunito', system-ui, sans-serif;
  font-weight: 700;
  /* --qs: per-card scale set on the content box so long single-line quotes
     clear the drawn shape edges (Andrew 2026-07-21). */
  font-size: calc(clamp(19px, 4.6vw, 30px) * var(--qs, 1));
  line-height: 1.3;
  color: var(--text, #F8F8F8);
  text-wrap: balance;
  font-style: italic;
}
.c-pm2__blob-quote::before { content: "\201C"; margin-right: 1px; }
.c-pm2__blob-quote::after  { content: "\201D"; margin-left: 1px; }

/* ═══ Act 2 — the video theater ═══ */
.c-pm2__theater {
  position: relative;
  z-index: 1;
  scroll-margin-top: 118px;
  display: flex;
  flex-direction: column;
  align-items: center;
  /* No title above the frame (Andrew cut it 2026-07-21) — the arch leads
     the act, sized so he fits the screen even with Safari's bars showing. */
  margin-top: 24px;
  padding: 0 16px;
}
/* Caption pill: reel-style overlay riding the lower part of the video arch
   (Andrew 2026-07-21 — the above-frame pill pushed the video down and cut him
   off at the fold). The zone is a zero-height anchor line inside the frame;
   the pill bottom-anchors to it so a two-line cue grows upward, staying clear
   of the frame's bottom edge. */
.c-pm2__caption-zone {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 5.5%;
  z-index: 3;
  pointer-events: none;
}
.c-pm2__captions {
  position: absolute;
  bottom: 0;
  left: 50%;
  transform: translateX(-50%);
  width: max-content;
  max-width: 92%;
  /* Andrew 2026-07-21: no pill at all — bare reel captions straight on the
     video. White letters, black outline, sized up now that there is no
     pill to contain them. */
  background: none;
  text-align: center;
  font-family: 'CeraRound', 'Cera Round', 'Nunito', sans-serif;
  font-weight: 900;
  font-size: clamp(27px, 2.9vw, 42px);
  line-height: 1.12;
  letter-spacing: -0.01em;
  color: #FFFFFF;
  -webkit-text-stroke: 6px #0A091A;
          text-stroke: 6px #0A091A;
  paint-order: stroke fill;
  text-wrap: balance;
  opacity: 0;
  transition: opacity 140ms ease;
  pointer-events: none;
}
.c-pm2__captions.is-on { opacity: 1; }

/* Frame — arched/tombstone, gradient border, now the star of its own act:
   roughly full-width on phones, tall on desktop. Exact 9:16 inner so the
   cover-fit video crops nothing. */
.c-pm2__frame {
  position: relative;
  /* 80vw, not 88 (Andrew 2026-07-21: "shrink everything a little bit") —
     with the title gone, a 402px phone fits the whole 9:16 arch inside
     Safari's small viewport (~700px) with the bars up. */
  width: min(80vw, 420px);
  aspect-ratio: 9 / 16;
  padding: 6px;
  background: linear-gradient(90deg, #9945FF 0%, #07EDBE 100%);
  border-radius: 999px 999px 60px 60px;
  box-shadow: 0 30px 80px rgba(153, 69, 255, 0.25);
}
.c-pm2__frame-inner {
  position: relative;
  width: 100%;
  height: 100%;
  border-radius: 993px 993px 54px 54px;
  background: #0A091A;
  overflow: hidden;
}
.c-pm2__video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  z-index: 1;
}
.c-pm2__frame-mesh {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  z-index: 0;
}

/* Sound control — the blue blob rides the frame's bottom-right corner. */
.c-pm2__sound-blob {
  position: absolute;
  right: -34px;
  top: 112px;
  width: 136px;
  aspect-ratio: 380 / 220;
  z-index: 2;
  filter: drop-shadow(0 8px 18px rgba(10, 9, 26, 0.45));
}
.c-pm2__sound-blob .c-pm2__blob-shape { position: absolute; inset: 0; width: 100%; height: 100%; }
.c-pm2__sound {
  position: relative;
  z-index: 1;
  width: 100%;
  height: 100%;
  border: none;
  background: none;
  display: grid;
  place-items: center;
  cursor: pointer;
  filter: drop-shadow(0 3px 10px rgba(10, 9, 26, 0.8));
  transition: transform 140ms ease;
}
.c-pm2__sound svg { width: 40px; height: 40px; }
.c-pm2__sound:hover { transform: scale(1.1); }
.c-pm2__sound:active { transform: scale(0.92); }

/* CTA */
.c-pm2__cta {
  position: relative;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 18px;
  margin-top: 40px;
}
.c-pm2__cta-line {
  margin: 0;
  font-family: 'Nunito', system-ui, sans-serif;
  font-weight: 500;
  font-size: 19px;
  line-height: 28px;
  color: rgba(10, 9, 26, 0.72);
  text-align: center;
}
.c-pm2__cta-pill {
  display: inline-flex;
  align-items: center;
  padding: 18px 36px;
  border-radius: 999px;
  background: linear-gradient(135deg, #07EDBE 0%, #9945FF 50%, #FF7EC0 100%);
  color: #0A091A;
  font-family: 'CeraRound', 'Cera Round', 'Nunito', sans-serif;
  font-weight: 900;
  font-size: 28px;
  letter-spacing: 0.01em;
  text-decoration: none;
  box-shadow: 0 18px 40px rgba(153, 69, 255, 0.35);
  transition: filter 160ms ease, transform 160ms ease;
  /* Thick white border around the label. paint-order draws the stroke first so
     it sits AROUND the dark text instead of eating into the glyphs. */
  -webkit-text-stroke: 6px #FFFFFF;
          text-stroke: 6px #FFFFFF;
  paint-order: stroke fill;
}
.c-pm2__cta-pill:hover  { filter: brightness(1.07); }
.c-pm2__cta-pill:active { transform: scale(0.98); }

/* ─── Desktop ≥1024px ──────────────────────────────────────────────────── */
@media (min-width: 1024px) {
  .c-pm2__theater { margin-top: 16px; }
  .c-pm2__frame { width: min(42vw, 520px); }
  .c-pm2__sound-blob { width: 170px; right: -46px; top: 140px; }
}

/* ─── Small phones ≤360px ───────────────────────────────────────────────── */
@media (max-width: 360px) {
  .c-pm2 { padding: 56px 0 64px; }
  .c-pm2__deck { width: 92vw; }
  .c-pm2__sound-blob { width: 124px; right: -18px; top: 104px; }
  .c-pm2__sound svg { width: 34px; height: 34px; }
  .c-pm2__captions { font-size: 24px; -webkit-text-stroke: 5px #0A091A; text-stroke: 5px #0A091A; }
  .c-pm2__cta-pill { font-size: 23px; padding: 16px 30px; }
}

/* Reduced motion — no lock, no entrances: the finished deck, static */
@media (prefers-reduced-motion: reduce) {
  .c-pm2__moment { height: auto; }
  .c-pm2__stick { position: static; height: auto; padding: 24px 20px; }
  .c-pm2__blob {
    opacity: 1;
    transform: rotate(var(--rest-tilt, 0deg));
    transition: none;
  }
}

/* == /components/my-approach/style.css == */
/* My Approach — philosophy block. DESIGN: violet section accent. Left-edge violet→teal
   vertical wash bleeds in from the start of the section; the repeating squiggle is dialled
   back to a faint diagonal band (linear-masked) instead of a full tile; a violet blob anchors
   the lower-left. Pairs visually with `the-tools` (multicolor sticker set) — same width & rhythm.
   ANIMATION HOOKS: [data-animate] on header / body / pillars; [data-rive-slot="calm-dog"] sits
   in the pillar row (a small Rive "settling dog" loop could live there); [data-three-blob] on
   the blob layer. */
.c-my-approach {
  position: relative;
  background: var(--bg);
  overflow: clip;
}
/* left-edge violet→teal wash */
.c-my-approach__wash {
  position: absolute;
  inset: 0 auto 0 0;
  width: 46%;
  pointer-events: none;
  background: linear-gradient(105deg, rgba(153, 69, 255, 0.16) 0%, rgba(7, 237, 190, 0.07) 50%, transparent 100%);
}
.c-my-approach__blob {
  position: absolute;
  border-radius: 50%;
  filter: blur(80px);
  pointer-events: none;
}
.c-my-approach__blob--violet {
  width: 520px; height: 520px;
  bottom: -260px; left: -120px;
  background: radial-gradient(circle at 50% 40%, #9945FF 0%, rgba(153, 69, 255, 0.30) 45%, transparent 72%);
  opacity: 0.4;
}
.c-my-approach__blob--teal {
  width: 380px; height: 380px;
  top: -180px; right: 8%;
  background: radial-gradient(circle at 50% 50%, #07EDBE 0%, rgba(7, 237, 190, 0.22) 45%, transparent 72%);
  opacity: 0.22;
}
/* squiggle — faint diagonal band only */
.c-my-approach__pattern {
  position: absolute;
  inset: 0;
  background-image: url("/assets/squiggle-bg.svg");
  background-size: 400px 400px;
  opacity: 0.14;
  pointer-events: none;
  -webkit-mask-image: linear-gradient(120deg, transparent 30%, #000 55%, #000 70%, transparent 92%);
          mask-image: linear-gradient(120deg, transparent 30%, #000 55%, #000 70%, transparent 92%);
}
.c-my-approach__inner {
  position: relative;
  width: 100%;
  max-width: 1180px;
  margin: 0 auto;
  padding: 80px 48px;
  display: flex;
  flex-direction: column;
  gap: 36px;
  box-sizing: border-box;
}

/* ---- Header ---- */
.c-my-approach__header { display: flex; flex-direction: column; gap: 16px; }
.c-my-approach__eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 6px 14px;
  background: var(--surface-card);
  border: 1px solid var(--navy);
  border-radius: 100px;
  width: fit-content;
  color: var(--light-purple);
  font-family: 'CeraRound', 'Cera Round', 'Nunito', sans-serif;
  font-weight: 900;
  font-size: 10px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  line-height: 1;
}
.c-my-approach__eyebrow-dot {
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--light-purple); flex-shrink: 0;
}
.c-my-approach__title {
  margin: 0;
  max-width: 880px;
  font-family: 'CeraRound', 'Cera Round', 'Nunito', sans-serif;
  font-weight: 900;
  font-size: 52px;
  line-height: 1.06;
  letter-spacing: -0.02em;
  color: var(--text);
}
.c-my-approach__title-accent {
  background: linear-gradient(92deg, #9945FF 0%, #C77DFF 60%, #07EDBE 100%);
  -webkit-background-clip: text;
          background-clip: text;
  color: transparent;
}

/* ---- Body prose ---- */
.c-my-approach__body {
  max-width: 820px;
  display: flex;
  flex-direction: column;
  gap: 18px;
}
.c-my-approach__body p {
  margin: 0;
  color: rgba(248, 248, 248, 0.72);
  font-family: 'Nunito', system-ui, sans-serif;
  font-size: 17px;
  line-height: 1.7;
}
.c-my-approach__body em { font-style: italic; color: var(--text); }
.c-my-approach__body p:first-child {
  font-size: 18px;
  color: rgba(248, 248, 248, 0.82);
}

/* ---- Pillars ---- */
.c-my-approach__pillars {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 18px;
  margin-top: 8px;
}
.c-my-approach__pillar {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 26px 24px 28px;
  border-radius: 20px;
  border: 1px solid rgba(160, 140, 255, 0.14);
  background: linear-gradient(180deg, rgba(160, 140, 255, 0.06) 0%, rgba(160, 140, 255, 0) 100%);
  overflow: clip;
  transition: border-color 200ms ease, transform 200ms ease;
}
.c-my-approach__pillar:hover { border-color: rgba(160, 140, 255, 0.32); transform: translateY(-3px); }
.c-my-approach__pillar-mark {
  font-family: 'CeraRound', 'Cera Round', 'Nunito', sans-serif;
  font-weight: 900;
  font-size: 56px;
  line-height: 1;
  letter-spacing: -0.04em;
  background: linear-gradient(135deg, rgba(7, 237, 190, 0.45) 0%, rgba(160, 140, 255, 0.25) 100%);
  -webkit-background-clip: text;
          background-clip: text;
  color: transparent;
}
.c-my-approach__pillar-title {
  margin: 0;
  font-family: 'CeraRound', 'Cera Round', 'Nunito', sans-serif;
  font-weight: 900;
  font-size: 18px;
  line-height: 1.25;
  color: var(--text);
}
.c-my-approach__pillar-body {
  margin: 0;
  color: rgba(248, 248, 248, 0.6);
  font-family: 'Nunito', system-ui, sans-serif;
  font-size: 14px;
  line-height: 1.6;
}

/* ---- Responsive ---- */
@media (max-width: 980px) {
  .c-my-approach__inner { padding: 56px 24px; gap: 28px; }
  .c-my-approach__title { font-size: 36px; }
  .c-my-approach__body p, .c-my-approach__body p:first-child { font-size: 16px; }
  .c-my-approach__pillars { grid-template-columns: 1fr; max-width: 480px; }
}
@media (max-width: 480px) {
  .c-my-approach__title { font-size: 30px; }
}

/* == /components/the-tools/style.css == */
/* My go-to tools — Sticker Pinboard direction (Paper QQQ-0 → code).
   Scattered, tilted brand-color stickers on dark #0A091A with brand squiggle BG
   and small organic blob accents. No GSAP yet — idle drift + hover-expand pending
   sign-off. */

.c-the-tools {
  position: relative;
  background: var(--bg);
  padding: clamp(64px, 8vw, 96px) 0 clamp(80px, 9vw, 112px);
  overflow: hidden;
  min-height: 920px;
}

/* Brand squiggle pattern — same asset used by pain-mirror-v2 / my-approach */
.c-the-tools__pattern {
  position: absolute;
  inset: 0;
  background-image: url("/assets/squiggle-bg.svg");
  background-size: 420px 420px;
  opacity: 0.13;
  pointer-events: none;
}

.c-the-tools__inner {
  position: relative;
  width: 100%;
  max-width: 1280px;
  margin: 0 auto;
  padding: 0 80px;
  display: flex;
  flex-direction: column;
  gap: 28px;
  box-sizing: border-box;
}

/* ---- Header ---- */
.c-the-tools__header { display: flex; flex-direction: column; gap: 14px; max-width: 760px; }
.c-the-tools__title {
  margin: 0;
  font-family: 'CeraRound', 'Cera Round', 'Nunito', sans-serif;
  font-weight: 900;
  font-size: clamp(48px, 7vw, 80px);
  line-height: 0.95;
  letter-spacing: -0.025em;
  color: var(--text);
}

/* ---- Pinboard ---- */
.c-the-tools__pinboard {
  position: relative;
  width: 100%;
  height: 760px;
  margin-top: 8px;
  /* Default: allow native scroll. touch-action: none gets applied only on
     desktop (≥1081px) inside the GSAP Draggable media query — below that,
     drag is disabled and the page needs to scroll normally. */
}

@media (min-width: 1081px) {
  .c-the-tools__pinboard { touch-action: none; }
}

/* ---- Sticker card — all cards are the same size now ---- */
.c-tool {
  position: absolute;
  width: 240px;
  height: 312px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 18px;
  border-radius: 18px;
  background: var(--sticker-bg);
  color: #0A091A;
  cursor: grab;
  user-select: none;
  -webkit-user-select: none;
}
.c-tool:active { cursor: grabbing; }

.c-tool__photo {
  width: 100%;
  height: 156px;
  border-radius: 12px;
  background: #0A091A;
  border: 2px solid rgba(10, 9, 26, 0.4);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
.c-tool__photo svg { display: block; }

.c-tool__name {
  margin: 0;
  font-family: 'CeraRound', 'Cera Round', 'Nunito', sans-serif;
  font-weight: 900;
  font-size: 20px;
  line-height: 1.1;
  color: #0A091A;
}
.c-tool__name--light { color: var(--text); }

.c-tool__desc {
  margin: 0;
  font-family: 'Nunito', system-ui, sans-serif;
  font-weight: 600;
  font-size: 12px;
  line-height: 1.4;
  color: #0A091A;
}
.c-tool__desc--light { color: rgba(248, 248, 248, 0.94); }

/* ---- Organic blob badge (shared by "98% of my dogs" + "My go-to") ---- */
.c-tool__blob-badge {
  position: absolute;
  width: 92px;
  height: 68px;
  z-index: 3;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
}
.c-tool__blob-badge svg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}
.c-tool__blob-badge span {
  position: relative;
  font-family: 'CeraRound', 'Cera Round', 'Nunito', sans-serif;
  font-weight: 900;
  font-size: 12px;
  line-height: 1.05;
  color: #0A091A;
  text-align: center;
  letter-spacing: 0.02em;
}

/* Chaser — "98% of my dogs" badge, top-right, slightly raised */
.c-tool__blob-badge:not(.c-tool__blob-badge--mygoto) {
  top: -36px;
  right: -14px;
  transform: rotate(8deg);
}
.c-tool__blob-badge:not(.c-tool__blob-badge--mygoto) span {
  transform: rotate(-6deg);
}

/* Slip leash — "My go-to" badge, top-left */
.c-tool__blob-badge--mygoto {
  top: -28px;
  left: -16px;
  transform: rotate(-12deg);
}
.c-tool__blob-badge--mygoto span {
  transform: rotate(8deg);
  color: #0A091A;
}

/* ---- TOP ROW positioning + colorways ---- */
/* All 9 cards: same 240x312 size. Per-card position + color + rest rotation
   (--tilt) — JS reads --tilt to restore rotation on drop. */

.c-tool--clicker  { --sticker-bg: var(--teal);         --tilt: -3deg; left:   0px; top:  20px; }
.c-tool--treats   { --sticker-bg: var(--pink);         --tilt:  4deg; left: 264px; top:  80px; }
.c-tool--chaser   { --sticker-bg: var(--violet);       --tilt: -2deg; left: 528px; top:   0px; }
.c-tool--slip     { --sticker-bg: var(--light-blue);   --tilt:  3deg; left: 792px; top:  80px; }
.c-tool--dogbed   { --sticker-bg: #F1E0FF;             --tilt: -4deg; left:1056px; top:  20px; }
.c-tool--longline { --sticker-bg: var(--mid-purple);   --tilt:  2deg; left: 132px; top: 400px; }
.c-tool--ecollar  { --sticker-bg: var(--light-purple); --tilt: -3deg; left: 396px; top: 420px; }
.c-tool--kennel   { --sticker-bg: var(--blue);         --tilt:  3deg; left: 660px; top: 400px; }
.c-tool--prong    { --sticker-bg: #F1E0FF;             --tilt: -2deg; left: 924px; top: 420px; }

.c-tool { transform: rotate(var(--tilt, 0deg)); }

/* Cards with light text on saturated dark backgrounds (violet, mid-purple, blue, light-purple) */
.c-tool--chaser .c-tool__name,
.c-tool--chaser .c-tool__desc,
.c-tool--kennel .c-tool__name,
.c-tool--kennel .c-tool__desc { color: var(--text); }
.c-tool--chaser .c-tool__desc,
.c-tool--kennel .c-tool__desc { color: rgba(248, 248, 248, 0.94); }

/* ---- Responsive ---- */

/* Tablet — 3 across, smaller cards */
@media (max-width: 1080px) {
  .c-the-tools__inner { padding: 0 32px; }
  .c-the-tools__pinboard {
    height: auto;
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 20px 14px;
    padding: 24px 0 16px;
    max-width: 720px;
    margin-left: auto;
    margin-right: auto;
  }
  .c-tool {
    position: relative;
    left: auto !important;
    top: auto !important;
    width: 100%;
    height: 270px;
    cursor: default;
  }
  .c-tool__photo { height: 132px; }
  .c-tool__name { font-size: 18px; }
  .c-tool__desc { font-size: 11px; }
}

/* Phone — 2 across, compact so most of the tools fit on screen at once */
@media (max-width: 640px) {
  .c-the-tools__inner { padding: 0 16px; gap: 20px; }
  .c-the-tools__title { font-size: clamp(36px, 11vw, 48px); }
  .c-the-tools__pinboard {
    grid-template-columns: repeat(2, 1fr);
    gap: 14px 10px;
    padding: 16px 0 12px;
    max-width: 100%;
  }
  .c-tool {
    height: 222px;
    padding: 12px;
    border-radius: 14px;
    gap: 8px;
  }
  .c-tool__photo {
    height: 108px;
    border-radius: 10px;
    border-width: 1.5px;
  }
  .c-tool__photo svg { width: 64%; height: auto; }
  .c-tool__name { font-size: 15px; line-height: 1.1; }
  .c-tool__desc { font-size: 10.5px; line-height: 1.35; }
  /* Smaller blob badges so they don't blow out compact cards */
  .c-tool__blob-badge { width: 64px; height: 48px; }
  .c-tool__blob-badge span { font-size: 9px; }
  .c-tool__blob-badge:not(.c-tool__blob-badge--mygoto) { top: -22px; right: -8px; }
  .c-tool__blob-badge--mygoto { top: -18px; left: -8px; }
}

/* Tiny phones — keep 2 across but tighten further */
@media (max-width: 380px) {
  .c-tool { height: 208px; padding: 10px; }
  .c-tool__photo { height: 96px; }
  .c-tool__name { font-size: 14px; }
  .c-tool__desc { font-size: 10px; }
}

/* == /components/homework-into-your-life/style.css == */
/* Homework Built Into Your Life — compact callout block. DESIGN: dark
   mesh-bordered card on a WHITE stage (Andrew, 2026-07-03) with a soft teal
   blob bleeding out from behind it. The squiggle inside the card is dialled
   right down and edge-faded so it reads as texture, not pattern.
   ANIMATION HOOKS: [data-animate] on the card; [data-three-blob] on the blob layer. */
.c-homework {
  position: relative;
  /* Transparent stage: the WHITE + light-squiggle island lives on ::before so
     its bottom edge can be MASKED to transparent (see below). Where the mask
     fades the white out, the body's dark bg + dark squiggle shows straight
     through — so the squiggle field reads as ONE continuous texture from the
     white island down into whats-included, with no opaque-dark band hiding it.
     --fade = height of the bottom dissolve zone. */
  --fade: 420px;
  /* Height of the TOP band where the white island extends up UNDER the wavy
     seam (== the seam's 100px height) so the light squiggle reaches the wave. */
  --seam: 100px;
  background: transparent;
  /* Clip horizontally (blob is 720px wide) but let ::before overflow UP the
     --seam band into the wavy seam above. The blob is contained separately
     (.c-homework__blobs) so it can't bleed vertically now that y is visible. */
  overflow: clip visible;
}
/* The wavy seam above this section, raised so its animated wave LINE renders
   above the homework white island (which now extends up under the seam), but
   still below the card (.c-homework__inner, z-index 1, later in the DOM). */
.c-wavy-seam--homework {
  position: relative;
  z-index: 1;
}
/* Keep the blurred teal blob clipped to the section box (this used to be done by
   .c-homework's own overflow:clip, which is now clip+visible for the ::before). */
.c-homework__blobs {
  position: absolute;
  inset: 0;
  overflow: clip;
  pointer-events: none;
}
/* The white island itself: same 480px light-squiggle tile as before, now on a
   pseudo-element so we can dissolve its BOTTOM edge with a tall, smoothstep-
   eased mask. Opaque at the top so it meets the white wavy-seam above with no
   seam; fades to fully transparent over --fade px at the bottom, revealing the
   continuous dark body squiggle underneath (no opaque-dark overlay, no band). */
.c-homework::before {
  content: "";
  position: absolute;
  /* Extend UP by --seam so the white island reaches under the wavy seam and the
     light squiggle can run right to the wave line. Bottom/sides unchanged. */
  inset: calc(var(--seam) * -1) 0 0 0;
  z-index: 0;
  background: #FFFFFF url("/assets/squiggle-bg-light.svg") repeat;
  background-size: 480px 480px;
  /* Shift the tile down by --seam so the squiggle phase inside the homework band
     is byte-identical to before the upward extension; the extension continues the
     same tile upward = one seamless field from the wave down into the band. */
  background-position: 0 var(--seam);
  pointer-events: none;
  /* Fixed-period wave tile (must match the visible seam line's period == the
     <pattern>/mask 480px tile in wavy-seam-homework). */
  --wave-period: 480px;
  /* Two mask layers, unioned (default `add`):
     (1) wave cut-out over the top --seam band: reveals the squiggle BELOW the
         wave, hides it ABOVE (dark body squiggle shows through to the line).
         The wave mask is a 480px tile REPEATED horizontally (repeat-x) so its
         boundary is the same fixed-period, non-stretched wave as the seam line
         above — identical crest shape on desktop and mobile.
     (2) the original bottom-dissolve, shifted to START at --seam so the homework
         band and its bottom fade are exactly as before, and it stays transparent
         in the top band so it can't fill in above the wave. */
  -webkit-mask-image:
    url("/assets/wavy-seam-homework-mask.svg"),
    linear-gradient(to top,
      rgba(0, 0, 0, 0)    0,
      rgba(0, 0, 0, 0.07) calc(var(--fade) * 0.10),
      rgba(0, 0, 0, 0.16) calc(var(--fade) * 0.20),
      rgba(0, 0, 0, 0.28) calc(var(--fade) * 0.30),
      rgba(0, 0, 0, 0.42) calc(var(--fade) * 0.40),
      rgba(0, 0, 0, 0.57) calc(var(--fade) * 0.50),
      rgba(0, 0, 0, 0.72) calc(var(--fade) * 0.60),
      rgba(0, 0, 0, 0.84) calc(var(--fade) * 0.70),
      rgba(0, 0, 0, 0.93) calc(var(--fade) * 0.80),
      rgba(0, 0, 0, 0.98) calc(var(--fade) * 0.90),
      rgba(0, 0, 0, 1)    var(--fade),
      rgba(0, 0, 0, 1)    100%);
  -webkit-mask-repeat: repeat-x, no-repeat;
  -webkit-mask-position: 0 0, 0 var(--seam);
  -webkit-mask-size: var(--wave-period) var(--seam), 100% calc(100% - var(--seam));
          mask-image:
    url("/assets/wavy-seam-homework-mask.svg"),
    linear-gradient(to top,
      rgba(0, 0, 0, 0)    0,
      rgba(0, 0, 0, 0.07) calc(var(--fade) * 0.10),
      rgba(0, 0, 0, 0.16) calc(var(--fade) * 0.20),
      rgba(0, 0, 0, 0.28) calc(var(--fade) * 0.30),
      rgba(0, 0, 0, 0.42) calc(var(--fade) * 0.40),
      rgba(0, 0, 0, 0.57) calc(var(--fade) * 0.50),
      rgba(0, 0, 0, 0.72) calc(var(--fade) * 0.60),
      rgba(0, 0, 0, 0.84) calc(var(--fade) * 0.70),
      rgba(0, 0, 0, 0.93) calc(var(--fade) * 0.80),
      rgba(0, 0, 0, 0.98) calc(var(--fade) * 0.90),
      rgba(0, 0, 0, 1)    var(--fade),
      rgba(0, 0, 0, 1)    100%);
          mask-repeat: repeat-x, no-repeat;
          mask-position: 0 0, 0 var(--seam);
          mask-size: var(--wave-period) var(--seam), 100% calc(100% - var(--seam));
}
.c-homework__blob {
  position: absolute;
  border-radius: 50%;
  filter: blur(90px);
  pointer-events: none;
}
.c-homework__blob--teal {
  width: 720px; height: 420px;
  top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  background: radial-gradient(50% 50% at 50% 50%, #07EDBE 0%, rgba(7, 237, 190, 0.24) 45%, transparent 75%);
  opacity: 0.26;
}
.c-homework__inner {
  position: relative;
  z-index: 1;              /* card stays above the bottom fade strip */
  width: 100%;
  max-width: 1180px;
  margin: 0 auto;
  /* Extra bottom room so the fade zone lives below the card, not over it
     (the fade's top ~60px overlaps this padding at <5% opacity, invisible). */
  padding: 40px 48px 170px;
  box-sizing: border-box;
}

.c-homework__card {
  position: relative;
  overflow: clip;
  border-radius: 24px;
  border: 6px solid transparent;
  background:
    linear-gradient(var(--bg-elev-1), var(--bg-elev-1)) padding-box,
    linear-gradient(135deg, #07EDBE 0%, #9945FF 55%, #FF7EC0 100%) border-box;
  box-shadow: 0 16px 48px rgba(7, 237, 190, 0.14), 0 16px 48px rgba(153, 69, 255, 0.12);
  padding: 36px 40px 40px;
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.c-homework__card-pattern {
  position: absolute;
  inset: 0;
  background-image: url("/assets/squiggle-bg.svg");
  background-size: 460px 460px;
  opacity: 0.07;
  pointer-events: none;
  -webkit-mask-image: radial-gradient(110% 100% at 100% 0%, #000 0%, transparent 65%);
          mask-image: radial-gradient(110% 100% at 100% 0%, #000 0%, transparent 65%);
}
.c-homework__badge {
  position: relative;
  z-index: 1;
  width: fit-content;
  padding: 6px 14px;
  border-radius: 100px;
  background: var(--surface-card);
  border: 1px solid var(--navy);
  color: var(--teal);
  font-family: 'CeraRound', 'Cera Round', 'Nunito', sans-serif;
  font-weight: 900;
  font-size: 12px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  line-height: 1;
}
.c-homework__title {
  position: relative;
  z-index: 1;
  margin: 0;
  max-width: 760px;
  font-family: 'CeraRound', 'Cera Round', 'Nunito', sans-serif;
  font-weight: 900;
  /* Bigger card headline (32px floor on phones), balanced wrapping so "life"
     never orphans onto its own line. */
  font-size: clamp(32px, 4.6vw, 44px);
  line-height: 1.15;
  letter-spacing: -0.02em;
  color: var(--text);
  text-wrap: balance;
}
.c-homework__title-accent {
  background: var(--mesh-text-gradient);
  -webkit-background-clip: text;
          background-clip: text;
  color: transparent;
}
.c-homework__body {
  position: relative;
  z-index: 1;
  margin: 0;
  max-width: 820px;
  color: rgba(248, 248, 248, 0.72);
  font-family: 'Nunito', system-ui, sans-serif;
  font-size: 17px;
  line-height: 1.7;
}
.c-homework__body em { font-style: italic; color: var(--text); }

/* ---- Responsive ---- */
@media (max-width: 980px) {
  .c-homework { --fade: 300px; }
  .c-homework__inner { padding: 32px 24px 130px; }
  .c-homework__card { padding: 28px 24px 30px; }
  .c-homework__blob--teal { width: 460px; height: 320px; }
}

/* == /components/whats-included/style.css == */
/* What's Included: V1 "gradient border panel" from the 2026-07-07 bake-off, per Andrew:
   - section TRANSPARENT so the global body squiggle backdrop shows around the card (V1 look)
   - centered plain-white headline inside the card (no accent word, no eyebrow, no subtitle)
   - six items: quiet light-blue dots, NO glow
   - guarantee row: Dog-Bone-Blue icon, centered
   Card = house double-background-clip GRADIENT BORDER treatment (from homework-into-your-life),
   blue-register ring over an elevated body, faint corner-masked squiggle inside.
   ANIMATION HOOKS: [data-animate] on panel + list. */
.c-whats-included {
  position: relative;
  /* transparent on purpose: the body's squiggle texture is the backdrop, like the bake-off page */
  background: transparent;
  overflow: clip;
}
.c-whats-included__inner {
  position: relative;
  z-index: 1;
  width: min(100% - 40px, 1060px);
  margin: 0 auto;
  padding: 76px 0;
  box-sizing: border-box;
}

/* ---- The card: house gradient-border panel, blue register ---- */
.c-whats-included__panel {
  position: relative;
  overflow: clip;
  border-radius: 24px;
  border: 6px solid transparent;
  background:
    linear-gradient(var(--bg-elev-1), var(--bg-elev-1)) padding-box,
    linear-gradient(135deg, #A0C7FF 0%, #477ED6 52%, #9945FF 100%) border-box;
  box-shadow: 0 16px 48px rgba(160, 199, 255, 0.12), 0 16px 48px rgba(71, 126, 214, 0.10);
  padding: 40px 44px 44px;
}
.c-whats-included__panel-pattern {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background-image: url("/assets/squiggle-bg.svg");
  background-size: 460px 460px;
  opacity: 0.06;
  -webkit-mask-image: radial-gradient(120% 100% at 100% 0%, #000 0%, transparent 62%);
          mask-image: radial-gradient(120% 100% at 100% 0%, #000 0%, transparent 62%);
}

/* ---- Headline: centered, plain white, inside the card ---- */
.c-whats-included__title {
  position: relative;
  z-index: 1;
  margin: 0 0 30px;
  font-family: 'CeraRound', 'Cera Round', 'Nunito', sans-serif;
  font-weight: 900;
  /* Shared section-header size (site-wide type scale). */
  font-size: clamp(38px, 6vw, 60px);
  line-height: 1.08;
  letter-spacing: -0.02em;
  text-align: center;
  text-wrap: balance;
  color: var(--text);
}

/* ---- List ---- */
.c-whats-included__list {
  position: relative;
  z-index: 1;
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 18px 40px;
}
.c-whats-included__list li {
  display: flex;
  gap: 14px;
  align-items: flex-start;
}
/* Quiet light-blue brand dot. NO glow (per Andrew). */
.c-whats-included__dot {
  flex-shrink: 0;
  width: 9px;
  height: 9px;
  margin-top: 8px;
  border-radius: 50%;
  background: var(--light-blue);
}
.c-whats-included__list p {
  margin: 0;
  color: rgba(248, 248, 248, 0.82);
  font-family: 'Nunito', system-ui, sans-serif;
  font-size: 17px;
  line-height: 1.55;
  /* avoid single-word orphan lines ("lifestyle.") */
  text-wrap: pretty;
}
.c-whats-included__list strong { color: var(--text); font-weight: 800; }

/* ---- Guarantee row: full-width, centered, bone icon ---- */
.c-whats-included__guarantee {
  grid-column: 1 / -1;
  margin-top: 12px;
  padding-top: 24px;
  border-top: 1px solid rgba(160, 199, 255, 0.22);
  justify-content: center;
  align-items: center;
}
.c-whats-included__bone {
  flex-shrink: 0;
  width: 26px;
  height: 26px;
  background: url("/assets/icons/hero/Dog-Bone-Blue.svg") center / contain no-repeat;
}
.c-whats-included__guarantee p {
  font-size: 17.5px;
  color: rgba(248, 248, 248, 0.9);
}

/* ---- Responsive ---- */
@media (max-width: 720px) {
  .c-whats-included__inner { padding: 56px 0; }
  .c-whats-included__panel { padding: 30px 22px 32px; }
  .c-whats-included__list { grid-template-columns: 1fr; gap: 16px; }
  .c-whats-included__guarantee { justify-content: flex-start; text-align: left; }
}

/* == /components/safe-to-start/style.css == */
/* Safe to Start — scannable risk-reversal grid. DESIGN: teal section accent (kept) — a
   calm, "you're covered" register. A teal blob anchors the top-left and a soft light-blue
   blob warms the lower-right; the repeating squiggle is dialled back to a faded top-left
   corner wash. Eyebrow + icon chips run teal so the whole block reads cool/reassuring.
   ANIMATION HOOKS: [data-animate] on header + the grid (stagger); [data-three-blob] on blobs.
   Scoped prefix: .c-safe-to-start__ */
.c-safe-to-start {
  position: relative;
  background: var(--bg);
  overflow: clip;
}
.c-safe-to-start__blob {
  position: absolute;
  border-radius: 50%;
  filter: blur(80px);
  pointer-events: none;
}
.c-safe-to-start__blob--teal {
  width: 520px; height: 520px;
  top: -240px; left: -140px;
  background: radial-gradient(circle at 55% 55%, #07EDBE 0%, rgba(7, 237, 190, 0.26) 45%, transparent 72%);
  opacity: 0.3;
}
.c-safe-to-start__blob--blue {
  width: 380px; height: 380px;
  bottom: -200px; right: 4%;
  background: radial-gradient(circle at 50% 50%, #A0C7FF 0%, rgba(160, 199, 255, 0.20) 45%, transparent 72%);
  opacity: 0.2;
}
.c-safe-to-start__pattern {
  position: absolute;
  inset: 0;
  background-image: url("/assets/squiggle-bg.svg");
  background-size: 420px 420px;
  opacity: 0.14;
  pointer-events: none;
  -webkit-mask-image: radial-gradient(120% 95% at 0% 0%, #000 0%, rgba(0,0,0,0.4) 40%, transparent 72%);
          mask-image: radial-gradient(120% 95% at 0% 0%, #000 0%, rgba(0,0,0,0.4) 40%, transparent 72%);
}
.c-safe-to-start__inner {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: 1100px;
  margin: 0 auto;
  padding: 80px 48px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 40px;
  box-sizing: border-box;
}

/* ---- Header ---- */
.c-safe-to-start__header { display: flex; flex-direction: column; align-items: center; gap: 14px; }
.c-safe-to-start__eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 6px 14px;
  background: var(--surface-card);
  border: 1px solid var(--navy);
  border-radius: 100px;
  color: var(--teal);
  font-family: 'CeraRound', 'Cera Round', 'Nunito', sans-serif;
  font-weight: 900;
  font-size: 10px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  line-height: 1;
}
.c-safe-to-start__eyebrow-dot {
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--teal); flex-shrink: 0;
}
.c-safe-to-start__title {
  margin: 0;
  font-family: 'CeraRound', 'Cera Round', 'Nunito', sans-serif;
  font-weight: 900;
  font-size: 48px;
  line-height: 1.05;
  letter-spacing: -0.02em;
  text-align: center;
  color: var(--text);
}
.c-safe-to-start__title-accent { color: var(--teal); }
.c-safe-to-start__subtitle {
  margin: 0;
  max-width: 520px;
  text-align: center;
  color: rgba(248, 248, 248, 0.55);
  font-family: 'Nunito', system-ui, sans-serif;
  font-size: 16px;
  line-height: 1.6;
}

/* ---- Grid ---- */
.c-safe-to-start__grid {
  list-style: none;
  margin: 0;
  padding: 0;
  width: 100%;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 16px;
}
/* the 7th item: span and center it under the bottom row */
.c-safe-to-start__item:last-child {
  grid-column: 1 / -1;
  max-width: 520px;
  justify-self: center;
}
.c-safe-to-start__item {
  display: flex;
  align-items: flex-start;
  gap: 14px;
  padding: 20px 22px;
  border-radius: 16px;
  border: 1px solid rgba(7, 237, 190, 0.14);
  background: linear-gradient(180deg, rgba(7, 237, 190, 0.05) 0%, rgba(7, 237, 190, 0) 100%);
  transition: border-color 200ms ease, transform 200ms ease;
}
.c-safe-to-start__item:hover { border-color: rgba(7, 237, 190, 0.30); transform: translateY(-3px); }
.c-safe-to-start__icon {
  flex-shrink: 0;
  width: 38px; height: 38px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 11px;
  background: rgba(7, 237, 190, 0.12);
  color: var(--teal);
}
.c-safe-to-start__icon svg { width: 19px; height: 19px; }
.c-safe-to-start__item p {
  margin: 0;
  color: rgba(248, 248, 248, 0.66);
  font-family: 'Nunito', system-ui, sans-serif;
  font-size: 14.5px;
  line-height: 1.55;
}
.c-safe-to-start__item strong { color: var(--text); font-weight: 800; }

/* ---- Responsive ---- */
@media (max-width: 980px) {
  .c-safe-to-start__inner { padding: 56px 24px; gap: 32px; }
  .c-safe-to-start__title { font-size: 36px; }
  .c-safe-to-start__grid { grid-template-columns: 1fr 1fr; }
  .c-safe-to-start__item:last-child { grid-column: 1 / -1; }
  .c-safe-to-start__blob--teal { width: 380px; height: 380px; top: -160px; left: -120px; }
  .c-safe-to-start__blob--blue { width: 300px; height: 300px; }
}
@media (max-width: 640px) {
  .c-safe-to-start__grid { grid-template-columns: 1fr; }
  .c-safe-to-start__item:last-child { max-width: none; }
}
@media (max-width: 480px) {
  .c-safe-to-start__inner { padding: 44px 18px; }
  .c-safe-to-start__title { font-size: 30px; }
}

/* == /components/reviews-badge/style.css == */
/* Reviews Badge — lightweight pill. Used inline inside other components, OR wrapped in a
   __band when it stands alone in a page flow (how-it-works). DESIGN: pink accent moment —
   a small faded pink blob sits behind the centred pill so it doesn't read as a stray chip.
   ANIMATION HOOK: [data-animate] on the pill. Scoped prefix: .c-reviews-badge__ */
.c-reviews-badge__band {
  position: relative;
  background: var(--bg);
  display: flex;
  justify-content: center;
  padding: 28px 24px;
  overflow: clip;
}
.c-reviews-badge__band-blob {
  position: absolute;
  top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  width: 360px; height: 160px;
  border-radius: 50%;
  filter: blur(60px);
  background: radial-gradient(50% 50% at 50% 50%, rgba(255, 126, 192, 0.22) 0%, transparent 75%);
  opacity: 0.7;
  pointer-events: none;
}
.c-reviews-badge {
  position: relative;
  z-index: 1;
}
.c-reviews-badge {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  padding: 10px 18px 10px 14px;
  border-radius: 100px;
  border: 1px solid var(--surface-border-strong);
  background: rgba(20, 18, 42, 0.6);
}
.c-reviews-badge__stars {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  color: var(--pink);
  flex-shrink: 0;
}
.c-reviews-badge__stars svg { width: 16px; height: 16px; }
.c-reviews-badge__text {
  display: flex;
  flex-direction: column;
  gap: 1px;
  line-height: 1.2;
}
.c-reviews-badge__count {
  font-family: 'CeraRound', 'Cera Round', 'Nunito', sans-serif;
  font-weight: 900;
  font-size: 14px;
  color: var(--text);
}
.c-reviews-badge__sub {
  font-family: 'Nunito', system-ui, sans-serif;
  font-size: 12px;
  color: rgba(248, 248, 248, 0.55);
}

@media (max-width: 480px) {
  .c-reviews-badge { gap: 10px; padding: 9px 14px 9px 12px; }
  .c-reviews-badge__stars svg { width: 14px; height: 14px; }
  .c-reviews-badge__count { font-size: 13px; }
}

/* == /components/final-cta/style.css == */
/* Final CTA — the closer. DESIGN: full mesh register (teal→violet→pink). This is the
   "hero-ish" closing moment, so it gets a low-opacity Paper mesh-shader full-bleed wash
   ([data-paper-mesh], used sparingly here and on the hero CTA only), with three converging
   mesh blobs and a faded centre squiggle on top. Headline accent runs the mesh text gradient.
   Button styling mirrors pricing-packages (.c-final-cta__cta--solid / --ghost).
   ANIMATION HOOKS: [data-animate] on the whole inner stack; [data-three-blob] on the blob
   layer (a slow Three.js mesh-gradient plane could replace the paper-mesh wash later).
   Scoped prefix: .c-final-cta__ */
.c-final-cta {
  position: relative;
  background: var(--bg);
  overflow: clip;
}
/* Paper mesh-shader wash — kept subtle so the text stays readable */
.c-final-cta__mesh {
  position: absolute;
  inset: 0;
  z-index: 0;
  opacity: 0.22;
  pointer-events: none;
  background: var(--mesh-gradient);
}
.c-final-cta__mesh canvas { display: block; width: 100% !important; height: 100% !important; }
/* darkening veil so the wash never washes out the copy */
.c-final-cta__veil {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background: radial-gradient(120% 100% at 50% 50%, rgba(10, 9, 26, 0.45) 0%, rgba(10, 9, 26, 0.78) 60%, rgba(10, 9, 26, 0.9) 100%);
}
.c-final-cta__blob {
  position: absolute;
  border-radius: 50%;
  filter: blur(85px);
  pointer-events: none;
  z-index: 0;
}
.c-final-cta__blob--teal   { width: 460px; height: 460px; top: -180px; left: 6%;  background: radial-gradient(circle at 50% 50%, #07EDBE 0%, rgba(7,237,190,0.24) 45%, transparent 72%); opacity: 0.26; }
.c-final-cta__blob--violet { width: 560px; height: 560px; bottom: -240px; left: 50%; transform: translateX(-50%); background: radial-gradient(circle at 50% 50%, #9945FF 0%, rgba(153,69,255,0.26) 45%, transparent 72%); opacity: 0.3; }
.c-final-cta__blob--pink   { width: 420px; height: 420px; top: -120px; right: 4%; background: radial-gradient(circle at 50% 50%, #FF7EC0 0%, rgba(255,126,192,0.22) 45%, transparent 72%); opacity: 0.24; }
.c-final-cta__pattern {
  position: absolute;
  inset: 0;
  z-index: 0;
  background-image: url("/assets/squiggle-bg.svg");
  background-size: 420px 420px;
  opacity: 0.12;
  pointer-events: none;
  -webkit-mask-image: radial-gradient(120% 90% at 50% 50%, transparent 0%, rgba(0,0,0,0.5) 55%, #000 100%);
          mask-image: radial-gradient(120% 90% at 50% 50%, transparent 0%, rgba(0,0,0,0.5) 55%, #000 100%);
}
.c-final-cta__inner {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: 760px;
  margin: 0 auto;
  padding: 92px 48px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 18px;
  text-align: center;
  box-sizing: border-box;
}
.c-final-cta__eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 6px 14px;
  background: var(--surface-card);
  border: 1px solid var(--navy);
  border-radius: 100px;
  color: var(--light-purple);
  font-family: 'CeraRound', 'Cera Round', 'Nunito', sans-serif;
  font-weight: 900;
  font-size: 10px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  line-height: 1;
}
.c-final-cta__eyebrow-dot {
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--light-purple); flex-shrink: 0;
}
.c-final-cta__title {
  margin: 6px 0 0;
  font-family: 'CeraRound', 'Cera Round', 'Nunito', sans-serif;
  font-weight: 900;
  font-size: 52px;
  line-height: 1.04;
  letter-spacing: -0.02em;
  color: var(--text);
}
.c-final-cta__title-accent {
  background: var(--mesh-text-gradient);
  -webkit-background-clip: text;
          background-clip: text;
  color: transparent;
}
.c-final-cta__subtitle {
  margin: 0;
  color: rgba(248, 248, 248, 0.55);
  font-family: 'Nunito', system-ui, sans-serif;
  font-size: 17px;
  line-height: 1.6;
}

/* ---- Buttons ---- */
.c-final-cta__buttons {
  margin-top: 14px;
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
  justify-content: center;
  align-items: center;
}
.c-final-cta__cta {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 54px;
  padding: 0 28px;
  border-radius: 999px;
  font-family: 'CeraRound', 'Cera Round', 'Nunito', sans-serif;
  font-weight: 900;
  font-size: 15px;
  text-decoration: none;
  transition: filter 160ms ease, transform 160ms ease, box-shadow 160ms ease;
}
.c-final-cta__cta--ghost {
  color: var(--text);
  border: 2px solid var(--surface-border-strong);
  background: var(--bg);
}
.c-final-cta__cta--ghost:hover { border-color: var(--light-purple); }
.c-final-cta__cta--solid {
  position: relative;
  color: #fff;
  border: 5px solid var(--light-purple);
  background: var(--bg);
  padding: 0 6px;
  overflow: hidden;
  isolation: isolate;
}
.c-final-cta__cta--solid .c-final-cta__cta-label {
  position: relative;
  z-index: 1;
  padding: 0 22px;
  text-shadow: 0 1px 2px rgba(10, 9, 26, 0.35);
}
.c-final-cta__cta-mesh {
  position: absolute;
  inset: 0;
  z-index: 0;
  border-radius: inherit;
  background: linear-gradient(135deg, #07EDBE 0%, #9945FF 50%, #FF7EC0 100%);
  pointer-events: none;
}
.c-final-cta__cta-mesh canvas { display: block; width: 100% !important; height: 100% !important; border-radius: inherit; }
.c-final-cta__cta--solid:hover { filter: brightness(1.08); transform: translateY(-2px); box-shadow: var(--shadow-glow-violet); }
.c-final-cta__cta--solid:active { transform: scale(0.98); }

/* ---- Microcopy strip ---- */
.c-final-cta__microcopy {
  margin: 18px 0 0;
  color: rgba(248, 248, 248, 0.5);
  font-family: 'Nunito', system-ui, sans-serif;
  font-size: 13.5px;
  line-height: 1.7;
}
.c-final-cta__dot { margin: 0 8px; color: rgba(160, 140, 255, 0.6); }

/* ---- Responsive ---- */
@media (max-width: 980px) {
  .c-final-cta__inner { padding: 68px 24px; }
  .c-final-cta__title { font-size: 40px; }
  .c-final-cta__blob--teal   { width: 320px; height: 320px; top: -120px; }
  .c-final-cta__blob--violet { width: 380px; height: 380px; bottom: -160px; }
  .c-final-cta__blob--pink   { width: 300px; height: 300px; top: -90px; }
}
@media (max-width: 480px) {
  .c-final-cta__inner { padding: 52px 18px; }
  .c-final-cta__title { font-size: 30px; }
  .c-final-cta__buttons { flex-direction: column; align-items: stretch; width: 100%; }
  .c-final-cta__cta { width: 100%; }
  .c-final-cta__dot { display: block; height: 0; overflow: hidden; margin: 4px 0; }
}

/* == /components/consult-embed/style.css == */
/* Consult Embed — full-bleed booking calendar (iframe) on a flat dark section,
   framed by a single gradient border. No background blobs/gradients; the squiggle
   pattern lives inside the embedded calendar, not in this section. */
.c-consult {
  background: var(--bg);
  /* Gradient border runs flush to the left/right screen edges (no horizontal
     gutter). */
  padding: 64px 0;
  overflow: clip;
  position: relative;
}
.c-consult__inner {
  position: relative;
  z-index: 1;
  /* Full-bleed: the gradient-bordered calendar spans the section width
     (heading stays centered via its own text-align). */
  max-width: none;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  gap: 32px;
}

.c-consult__heading {
  display: flex;
  flex-direction: column;
  gap: 14px;
  text-align: center;
  align-items: center;
}
.c-consult__title {
  margin: 0;
  font-family: 'CeraRound', 'Cera Round', 'Nunito', sans-serif;
  font-weight: 900;
  /* Shared section-header size (site-wide type scale). */
  font-size: clamp(38px, 6vw, 60px);
  line-height: 1.05;
  letter-spacing: -0.025em;
  color: var(--heading-white);
}
.c-consult__title span { display: block; }
.c-consult__title-accent { color: var(--teal); }
.c-consult__lede {
  margin: 0;
  color: var(--gray-purple);
  font-family: 'Nunito', system-ui, sans-serif;
  font-size: 17px;
  line-height: 1.7;
  max-width: 560px;
}

/* Iframe card — 6px gradient border matching the "Meet Andrew" frame's weight,
   no glow/shadow. The embedded page is flat var(--bg) with no inner border, so
   this gradient ring is the only outer frame around the calendar. */
.c-consult__frame {
  position: relative;
  border-radius: 20px;
  padding: 6px;
  background: linear-gradient(135deg, #9945FF 0%, #07EDBE 50%, #FF7EC0 100%);
}
.c-consult__iframe {
  display: block;
  width: 100%;
  border: 0;
  /* 14px = frame radius (20) minus the 6px gradient padding, so the ring is a
     uniform 6px all the way around the corners. */
  border-radius: 14px;
  background: var(--bg);
  /* Height is driven by the embedded calendar via postMessage (see the
     auto-size listener in index.html) so the frame hugs the calendar with no
     empty space, and grows for the intake form. min-height is just a floor for
     the brief moment before the first height beacon arrives (or if JS is off);
     keep it BELOW the real calendar height (~428px desktop / ~491px mobile) so
     it never forces empty space under the card. */
  min-height: 400px;
  /* The height beacon lands after the embed loads; ease into the new size
     instead of snapping (the "reshuffle" Andrew saw). */
  transition: height 350ms cubic-bezier(0.16, 1, 0.3, 1);
}

.c-consult__fallback { margin: 0; padding: 24px; text-align: center; }
.c-consult__fallback-link,
.c-consult__alt-link {
  color: var(--teal);
  font-weight: 700;
  text-decoration: none;
}
.c-consult__fallback-link:hover,
.c-consult__alt-link:hover { text-decoration: underline; }

.c-consult__alt {
  margin: 0;
  text-align: center;
  color: var(--gray-purple);
  font-family: 'Nunito', system-ui, sans-serif;
  font-size: 15px;
  line-height: 1.6;
}

@media (max-width: 800px) {
  .c-consult__iframe { min-height: 440px; }
}
@media (max-width: 560px) {
  .c-consult { padding: 48px 0; }
  .c-consult__iframe { min-height: 460px; }
}

/* == /components/quiz-hero/style.css == */
/* Quiz Hero, arm B of the quiz-funnel A/B test.
   Arm switching happens here so there is zero flicker: the inline script in
   partials/head.html stamps html[data-arm] before first paint, and these
   rules decide which hero paints. No data-arm (JS off / assignment disabled)
   means the standard page: the form arm is the safe default. */
.c-quiz { display: none; }
html[data-arm="quiz"] .c-quiz { display: flex; }
html[data-arm="quiz"] .c-hero { display: none; }

.c-quiz {
  position: relative;
  /* Transparent like the hero: the body's squiggle pattern tiles through. */
  background: transparent;
  /* Own the whole first screen: nav clearance on top (measured from the
     real nav pill by quiz.js; the fallback covers no-JS), content centered
     in what remains (svh so iOS URL bars don't push the fold around). */
  padding: var(--quiz-nav-clearance, 112px) 24px 40px;
  min-height: 100vh;
  min-height: 100svh;
  align-items: center;
  justify-content: center;
  overflow: clip;
}
.c-quiz__inner {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: 640px;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
}

/* ---- Floating brand illustrations ----
   Same recipe as the hero (inline left/top/width % + --r, CSS centering),
   reusing Andrew's hand-placed arrangement. Ambient float is CSS-only here
   (the hero's GSAP module is scoped to the hero) with per-icon phase via
   nth-child, honoring prefers-reduced-motion. */
.c-quiz__float {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  overflow-x: clip;
  overflow-y: visible;
}
.c-quiz__group {
  position: absolute;
  inset: 0;
}
.c-quiz__group--mobile { display: none; }
.c-quiz__icon {
  position: absolute;
  transform: translate(-50%, -50%) rotate(var(--r, 0deg));
}
.c-quiz__icon > img {
  display: block;
  width: 100%;
  height: auto;
  user-select: none;
}
@media (prefers-reduced-motion: no-preference) {
  .c-quiz__icon > img { animation: quiz-icon-float 6.4s ease-in-out infinite alternate; }
  .c-quiz__icon:nth-child(2n) > img { animation-duration: 7.6s; animation-delay: -2.1s; }
  .c-quiz__icon:nth-child(3n) > img { animation-duration: 5.7s; animation-delay: -3.4s; }
  .c-quiz__icon:nth-child(5n) > img { animation-duration: 8.3s; animation-delay: -1.2s; }
  @keyframes quiz-icon-float {
    from { transform: translate(0, -4px); }
    to { transform: translate(3px, 5px); }
  }
}
@media (max-width: 820px) {
  .c-quiz__group--desktop { display: none; }
  .c-quiz__group--mobile { display: block; }
}

/* ---- Start stage ---- */
.c-quiz__stage--start {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 28px;
}
.c-quiz__headline {
  margin: 0;
  font-family: 'CeraRound', 'Cera Round', 'Nunito', sans-serif;
  font-weight: 900;
  font-size: clamp(48px, 9vw, 76px);
  line-height: 1.02;
  letter-spacing: -0.025em;
  color: var(--text);
}
.c-quiz__headline span { display: block; }
/* Sticker lettering, same two-layer recipe as the hero headline (see
   components/hero/style.css): white stroke wraps the glyphs via paint-order,
   and the animated gradient paints on a text copy stacked on top (::after
   reads data-text). The rest line is dark fill + thick white border. This is
   what keeps the headline popping over the squiggles and floating icons. */
.c-quiz__accent {
  color: #FFFFFF;
  -webkit-text-stroke: 0.17em #FFFFFF;
          text-stroke: 0.17em #FFFFFF;
  paint-order: stroke fill;
  display: inline-block;
  position: relative;
  z-index: 0;
}
.c-quiz__accent::after {
  content: attr(data-text);
  position: absolute;
  inset: 0;
  background-image: linear-gradient(90deg, #07EDBE 0%, #9945FF 25%, #FF7EC0 50%, #9945FF 75%, #07EDBE 100%);
  background-size: 200% 100%;
  background-position: 0% 50%;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  -webkit-text-stroke: 0;
          text-stroke: 0;
  animation: quiz-accent-flow 12s cubic-bezier(0.45, 0, 0.55, 1) infinite;
}
@keyframes quiz-accent-flow {
  0%, 100% { background-position:   0% 50%; }
  50%      { background-position: 100% 50%; }
}
@media (prefers-reduced-motion: reduce) {
  .c-quiz__accent::after { animation: none; }
}
.c-quiz__rest {
  color: #0A091A;
  -webkit-text-stroke: 0.17em #FFFFFF;
          text-stroke: 0.17em #FFFFFF;
  paint-order: stroke fill;
  display: inline-block;
}
.c-quiz__promise {
  margin: 0;
  color: var(--text-body);
  font-family: 'Nunito', system-ui, sans-serif;
  font-size: 18px;
  font-weight: 700;
}

/* Start CTA, same ring + mesh recipe as the locked hero CTA (CLAUDE.md §2a),
   own class names so the hero stylesheet stays untouched. */
.c-quiz__start {
  border: none;
  cursor: pointer;
  padding: 3px;
  border-radius: var(--radius-pill);
  background: var(--light-purple);
}
.c-quiz__start-inner {
  position: relative;
  display: block;
  border-radius: var(--radius-pill);
  padding: 18px 40px;
  overflow: hidden;
  border: 3px solid var(--bg);
  background: linear-gradient(135deg, #07EDBE 0%, #9945FF 50%, #FF7EC0 100%);
}
.c-quiz__start-mesh { position: absolute; inset: 0; }
.c-quiz__start-label {
  position: relative;
  z-index: 1;
  font-family: 'CeraRound', 'Cera Round', 'Nunito', sans-serif;
  font-weight: 900;
  font-size: 22px;
  color: #fff;
}

/* Skip: quiet ghost pill, never a bare underline. Solid dark fill so the
   floating icons behind it can't bleed through the label. */
.c-quiz__skip {
  display: inline-block;
  padding: 10px 22px;
  border-radius: var(--radius-pill);
  border: 1.5px solid rgba(248, 248, 248, 0.22);
  background: var(--bg);
  color: var(--text-muted);
  text-decoration: none;
  font-family: 'Nunito', system-ui, sans-serif;
  font-size: 14px;
  font-weight: 700;
  transition: border-color 0.15s ease, color 0.15s ease;
}
.c-quiz__skip:hover {
  border-color: var(--light-purple);
  color: var(--text);
}

/* ---- Question / capture card ---- */
.c-quiz__card {
  position: relative;
  width: 100%;
  margin: 0 0 24px;
  background: #FFFFFF;
  border-radius: 20px;
  padding: 32px 28px 28px;
  box-shadow: 0 0 60px rgba(160, 140, 255, 0.15), 0 20px 60px rgba(0, 0, 0, 0.25);
}
.c-quiz__card::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 20px;
  padding: 1.5px;
  background: linear-gradient(135deg, #9945FF 0%, #07EDBE 50%, #FF7EC0 100%);
  -webkit-mask:
    linear-gradient(#fff 0 0) content-box,
    linear-gradient(#fff 0 0);
  -webkit-mask-composite: xor;
          mask-composite: exclude;
  pointer-events: none;
}
.c-quiz__progress {
  height: 6px;
  border-radius: 3px;
  background: rgba(44, 41, 119, 0.12);
  overflow: hidden;
  margin-bottom: 10px;
}
.c-quiz__progress-fill {
  display: block;
  height: 100%;
  width: 33%;
  border-radius: 3px;
  background: linear-gradient(90deg, #07EDBE 0%, #9945FF 100%);
  transition: width 0.3s ease;
}
.c-quiz__count {
  margin: 0 0 18px;
  font-family: 'Nunito', system-ui, sans-serif;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: #6B6890;
}
.c-quiz__question {
  margin: 0 0 6px;
  font-family: 'CeraRound', 'Cera Round', 'Nunito', sans-serif;
  font-weight: 900;
  font-size: 24px;
  line-height: 1.2;
  color: #14122A;
}
.c-quiz__hint {
  margin: 0 0 16px;
  font-family: 'Nunito', system-ui, sans-serif;
  font-size: 13px;
  font-weight: 700;
  color: #6B6890;
}
.c-quiz__question + .c-quiz__chips { margin-top: 14px; }
.c-quiz__chips {
  display: grid;
  grid-template-columns: 1fr;
  gap: 10px;
}
.c-quiz__chip {
  display: block;
  width: 100%;
  text-align: left;
  padding: 15px 18px;
  border-radius: 14px;
  border: 1.5px solid rgba(44, 41, 119, 0.18);
  background: #FBFAFF;
  cursor: pointer;
  font-family: 'Nunito', system-ui, sans-serif;
  font-size: 16px;
  font-weight: 700;
  color: #2C2977;
  transition: border-color 0.15s ease, background 0.15s ease, transform 0.15s ease;
}
.c-quiz__chip:hover { border-color: var(--violet); background: #F5EFFF; }
.c-quiz__chip.is-selected {
  border-color: var(--violet);
  background: #F1E0FF;
  transform: scale(0.99);
}
/* Short-label questions read best as uniform full-width rows: half-width
   cells left some labels one line and some two, which looked ragged. */
.c-quiz__stage[data-qid="quiz_household"] .c-quiz__chips,
.c-quiz__stage[data-qid="quiz_severity"] .c-quiz__chips,
.c-quiz__stage[data-qid="quiz_tried"] .c-quiz__chips {
  grid-template-columns: 1fr;
}
.c-quiz__other { margin-top: 10px; }
.c-quiz__other input {
  width: 100%;
  box-sizing: border-box;
  padding: 13px 14px;
  border-radius: 12px;
  border: 1.5px solid rgba(44, 41, 119, 0.18);
  background: #FBFAFF;
  font-family: 'Nunito', system-ui, sans-serif;
  font-size: 16px;
  color: #14122A;
}
.c-quiz__other input:focus { outline: none; border-color: var(--violet); }
.c-quiz__next {
  margin-top: 16px;
  width: 100%;
  border: none;
  cursor: pointer;
  padding: 14px 24px;
  border-radius: var(--radius-pill);
  background: linear-gradient(135deg, #07EDBE 0%, #9945FF 50%, #FF7EC0 100%);
  font-family: 'CeraRound', 'Cera Round', 'Nunito', sans-serif;
  font-weight: 900;
  font-size: 17px;
  color: #fff;
  transition: opacity 0.15s ease;
}
.c-quiz__next:disabled { opacity: 0.35; cursor: default; }

/* Back: quiet chip with a chevron, no underline anywhere. */
.c-quiz__back {
  margin-top: 16px;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  border: 1.5px solid rgba(44, 41, 119, 0.18);
  border-radius: var(--radius-pill);
  background: none;
  cursor: pointer;
  padding: 7px 16px 7px 12px;
  font-family: 'Nunito', system-ui, sans-serif;
  font-size: 13px;
  font-weight: 800;
  color: #6B6890;
  transition: border-color 0.15s ease, color 0.15s ease;
}
.c-quiz__back:hover { border-color: var(--violet); color: #2C2977; }

/* ---- Capture stage ---- */
.c-quiz__capture-sub {
  margin: 0 0 16px;
  font-family: 'Nunito', system-ui, sans-serif;
  font-size: 15px;
  line-height: 1.6;
  color: #55527A;
}
.c-quiz__form { display: flex; flex-direction: column; gap: 14px; }
.c-quiz__name-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 14px;
}
/* Inputs have a large intrinsic min-width; without these the second grid
   cell overflows the card edge instead of shrinking to its column. */
.c-quiz__name-row .c-quiz__field { min-width: 0; }
.c-quiz__field input { width: 100%; box-sizing: border-box; }
.c-quiz__hp {
  position: absolute;
  left: -9999px;
  top: auto;
  width: 1px;
  height: 1px;
  overflow: hidden;
}
.c-quiz__field { display: flex; flex-direction: column; gap: 6px; }
.c-quiz__label {
  font-family: 'Nunito', system-ui, sans-serif;
  font-size: 13px;
  font-weight: 800;
  color: #2C2977;
}
.c-quiz__field input {
  padding: 13px 14px;
  border-radius: 12px;
  border: 1.5px solid rgba(44, 41, 119, 0.18);
  background: #FBFAFF;
  font-family: 'Nunito', system-ui, sans-serif;
  font-size: 16px;
  color: #14122A;
}
.c-quiz__field input:focus {
  outline: none;
  border-color: var(--violet);
}
.c-quiz__consent {
  display: flex;
  gap: 10px;
  align-items: flex-start;
  font-family: 'Nunito', system-ui, sans-serif;
  font-size: 12px;
  line-height: 1.5;
  color: #6B6890;
}
.c-quiz__consent input { margin-top: 2px; }
.c-quiz__submit {
  border: none;
  cursor: pointer;
  padding: 16px 24px;
  border-radius: var(--radius-pill);
  background: linear-gradient(135deg, #07EDBE 0%, #9945FF 50%, #FF7EC0 100%);
  font-family: 'CeraRound', 'Cera Round', 'Nunito', sans-serif;
  font-weight: 900;
  font-size: 18px;
  color: #fff;
}
.c-quiz__submit:disabled { opacity: 0.6; cursor: default; }
.c-quiz__error {
  margin: 0;
  font-family: 'Nunito', system-ui, sans-serif;
  font-size: 14px;
  color: #C0264B;
}

/* Stage switching. The [hidden] guards matter: these elements set their own
   display, which would otherwise override the browser's hidden handling. */
.c-quiz__card .c-quiz__stage[hidden] { display: none; }
.c-quiz__back[hidden],
.c-quiz__progress[hidden],
.c-quiz__count[hidden] { display: none; }
@media (prefers-reduced-motion: no-preference) {
  .c-quiz__card .c-quiz__stage { animation: quiz-stage-in 0.25s ease; }
  @keyframes quiz-stage-in {
    from { opacity: 0; transform: translateY(6px); }
    to { opacity: 1; transform: none; }
  }
}

@media (min-width: 720px) {
  .c-quiz { padding-top: 140px; }
  .c-quiz__chips { grid-template-columns: 1fr 1fr; }
  .c-quiz__card { padding: 40px 36px 32px; }
}

/* Compact capture on phones: the booking card must fit one screen with
   Safari's bars up, no scrolling to reach the submit button. */
@media (max-width: 719px) {
  .c-quiz__card { padding: 22px 20px 20px; }
  .c-quiz__form { gap: 10px; }
  .c-quiz__name-row { gap: 10px; }
  .c-quiz__field { gap: 4px; }
  /* 16px input font stays: smaller makes iOS zoom the page on focus. */
  .c-quiz__field input { padding: 11px 12px; }
  .c-quiz__capture-sub { display: none; }
  .c-quiz__consent { font-size: 11px; }
  .c-quiz__submit { padding: 14px 24px; font-size: 17px; }
  /* Two-across chips so all 10 problem options + Next fit one screen.
     min-height = two lines so one-line chips match their neighbors. */
  .c-quiz__chips { grid-template-columns: 1fr 1fr; gap: 8px; }
  .c-quiz__chip {
    padding: 8px 12px;
    font-size: 13px;
    min-height: 56px;
    display: flex;
    align-items: center;
  }
  .c-quiz__next { margin-top: 10px; padding: 12px 24px; }
  .c-quiz__count { margin-bottom: 8px; }
  .c-quiz__hint { margin-bottom: 10px; }
  .c-quiz__question { font-size: 21px; }
  .c-quiz__stage[data-qid="quiz_household"] .c-quiz__chips,
  .c-quiz__stage[data-qid="quiz_severity"] .c-quiz__chips,
  .c-quiz__stage[data-qid="quiz_tried"] .c-quiz__chips {
    grid-template-columns: 1fr;
  }
  /* Single-column questions are always one line: shorter uniform chips so
     the whole card, Back included, stays on one screen. */
  .c-quiz__stage[data-qid="quiz_household"] .c-quiz__chip,
  .c-quiz__stage[data-qid="quiz_severity"] .c-quiz__chip,
  .c-quiz__stage[data-qid="quiz_tried"] .c-quiz__chip { min-height: 46px; padding: 8px 14px; }
}

/* ---- two-step capture A/B (2026-08-18) --------------------------------------
   The form is a flex column, so the two arms are pure `order` and `display`.
   No JS layout, no duplicate markup, and the `one` arm renders in exactly the
   field order it had before this test so the control is honest.

   Group 2 holds the dog's name and email; group 1 holds the names and phone.
   Consent sits between them in the DOM because TCPA needs it captured on step
   1, and `order` puts it back at the bottom where it reads correctly.        */
.c-quiz__form > [data-capture-group="1"],
.c-quiz__form > [data-capture-group="2"] {
  display: flex;
  flex-direction: column;
  gap: inherit;
}
.c-quiz__form > [data-capture-group="1"] { order: 1; }
.c-quiz__form > [data-capture-group="2"] { order: 2; }
.c-quiz__form > .c-quiz__consent { order: 3; }
.c-quiz__form > [data-capture-continue],
.c-quiz__form > .c-quiz__submit { order: 4; }
.c-quiz__form > .form-error { order: 5; }

/* `two` arm, before step 1 posts: group 2 is gone and Continue stands in for
   the real submit. [hidden] alone is not enough against the flex display rule
   above, which is why this repeats the selector. */
.c-quiz__form[data-capture-arm="two"][data-capture-at="1"] > [data-capture-group="2"] {
  display: none;
}
.c-quiz__form[data-capture-arm="two"][data-capture-at="1"] > .c-quiz__submit {
  display: none;
}

/* ── The finale ──────────────────────────────────────────────────────────────
 *
 * Andrew, 2026-09-01, holding up gooddogzkc.com after finishing the quiz: "we
 * would remove the button in the text. We'd keep the header and all of the other
 * stuff. We would just replace the text with the best dog training in Kansas
 * City", and on the motion, "I'm thinking about it all just, like, kind of
 * landing and then subtly bouncing."
 *
 * So the finale is this same hero with three things taken off it: the promise
 * line, the Start button and the Skip link. The collage stays, the header stays,
 * everything below the fold stays. The stickers fly in and land.
 *
 * ⚠️ THE GAME ARM HIDES THIS SECTION, which is what makes the finale possible at
 * all: `html[data-arm="game"] .c-quiz { display: none }` in the game's own
 * stylesheet, so the collage is already parsed, already laid out and already in
 * the DOM when the card blanks. Nothing is fetched and nothing is built.
 * The rule below is a plain-specificity override of that one, so it has to name
 * both attributes.
 * ⚠️ THE TWO STYLESHEETS ARE SEPARATE FILES and neither imports the other. If
 * the game's arm rule ever grows a class, this override has to grow with it. A
 * test pins the pairing rather than a comment.
 */
/* 🔴 `flex`, NEVER `block`. `.c-quiz` is a flex column with `align-items` and
 * `justify-content: center`, and `html[data-arm="quiz"] .c-quiz` is the only rule
 * that ever turns it on. Revealing it as `block` drops both centrings: the
 * headline pinned to the top of the section under the nav pill, ran into the
 * shuttlecock and the dog face, and left the whole middle of the collage empty
 * where the button and the skip link used to be. Measured, not guessed. */
html[data-quiz-finale] .c-quiz,
html[data-arm="game"][data-quiz-finale] .c-quiz { display: flex; }

/* The three things he named. `display: none` and not visibility: the start stage
   is a centred flex column, so an invisible button would keep its gap and leave
   the headline sitting high with a hole under it. */
html[data-quiz-finale] .c-quiz__promise,
html[data-quiz-finale] .c-quiz__start,
html[data-quiz-finale] .c-quiz__skip,
html[data-quiz-finale] .c-quiz__card { display: none; }

/* 🔴 BOTH HEADLINES ARE IN THE DOM AND CSS PICKS, AND THE FINALE ONE MUST NOT
   USE THE `hidden` ATTRIBUTE. brand.css:275 is `[hidden] { display: none
   !important }`, so no component rule can ever bring it back: the first version
   of this shipped `hidden` in the markup and the finale drew an empty column
   where the headline goes. A class hides it, and the finale flips the class. */
.c-quiz__headline--finale { display: none; }
html[data-quiz-finale] [data-quiz-headline] { display: none; }
html[data-quiz-finale] .c-quiz__headline--finale { display: block; }

/* ── Size and position, Andrew 2026-09-01 ────────────────────────────────────
 * "could make the text a little bit larger... maybe we could scoot it up and
 * then make it all bigger."
 *
 * The start headline is `clamp(48px, 9vw, 76px)` and it shares that rule with the
 * quiz opener, which sits over a subhead, a button and a skip link. The finale
 * headline is ALONE on the page, so it can carry more weight without crowding
 * anything. One step up: 56 / 10.5vw / 88.
 *
 * ⚠️ THE LIFT IS A MARGIN, NOT A TRANSFORM. `.c-quiz` centres its child with
 * `justify-content: center`, so a bottom margin on the stage moves the content up
 * by half of it and the flex box still owns the layout. A translate would move
 * the painted glyphs off a box that stayed put, which is a headline whose stroke
 * clips against `overflow: clip` on the section at short viewports.
 * 8vh, so the lift is a share of the screen rather than a number tuned to one
 * phone: on a short viewport a fixed 70px is most of the clearance under the nav. */
html[data-quiz-finale] .c-quiz__headline--finale {
  /* ⚠️ 52/9.8vw/82 IS HIS PICK, not the first bump. He asked for "a little bit
     larger", was shown 56/10.5vw/88, and backed it off one step from there: at
     the larger size the third line touches the lightning bolt on the left and the
     green dog on the right, and the collage stops reading as the background. */
  font-size: clamp(52px, 9.8vw, 82px);
}
html[data-quiz-finale] .c-quiz__stage--start { margin-bottom: 8vh; }

/* ── The entrance ────────────────────────────────────────────────────────────
 *
 * 🔴 TWO TRANSFORM LAYERS, AND THAT IS THE WHOLE DESIGN. The ambient float above
 * animates the inner `<img>`; the placement and the rotation live on the
 * `.c-quiz__icon` wrapper. Putting the entrance on the wrapper means the fly-in
 * and the float never touch the same property, so the drift keeps running under
 * the landing instead of being frozen or fought.
 *
 * ⚠️ Do NOT animate the img: the float owns its transform outright and the two
 * would overwrite each other frame by frame, which reads as a stutter, not a
 * bounce.
 */
html[data-quiz-finale] .c-quiz__fade { animation: quiz-finale-fade .5s ease-out both; }

@keyframes quiz-finale-fade {
  from { opacity: 0; }
  to { opacity: 1; }
}

@media (prefers-reduced-motion: no-preference) {
  html[data-quiz-finale] .c-quiz__icon {
    /* --i is the sticker's index, written by quiz-finale.js. nth-child cannot do
       a real stagger across 16 to 23 icons: it repeats a pattern, so a run of
       them lands on the same frame and the whole thing reads as one pop. */
    animation: quiz-finale-drop .62s cubic-bezier(.34, 1.42, .64, 1) both;
    animation-delay: calc(var(--i, 0) * 42ms);
  }

  /* ⚠️ THE ROTATION HAS TO BE CARRIED THROUGH EVERY FRAME. The wrapper's resting
     transform is `translate(-50%,-50%) rotate(var(--r))`, and an animation that
     omits the rotate snaps each sticker upright the moment it starts, which is a
     visible jolt on the fourteen of them that sit at an angle.
     The overshoot is in the easing, not in the keyframes: 1.42 on the third
     control point is a small pass beyond the landing and back. He asked for
     SUBTLE, and a keyframed overshoot on top of a back-out easing bounces twice. */
  @keyframes quiz-finale-drop {
    from {
      opacity: 0;
      transform: translate(-50%, -50%) rotate(calc(var(--r, 0deg) - 14deg)) translateY(-38px) scale(.62);
    }
    to {
      opacity: 1;
      transform: translate(-50%, -50%) rotate(var(--r, 0deg)) translateY(0) scale(1);
    }
  }
}

/* Reduced motion gets the page, never the show. Everything is already in its
   resting place, so there is nothing to state here beyond letting the fade be
   instant. */
@media (prefers-reduced-motion: reduce) {
  html[data-quiz-finale] .c-quiz__fade { animation: none; }
}

/* ── Andrew's second nudge on the finale, 2026-09-01 ─────────────────────────
 *
 * He circled the same two stickers and said "more like this". The first move was
 * 3% each and it is in the inline `top` values.
 *
 * 🔴 MORE IS NOT FREE ON A SHORT PHONE, and that is why this is a media query and
 * not a bigger number. Measured across six viewports with
 * `rive-lab examples/gdkc-quiz-rive/sticker-clearance.mjs`, the binding case is
 * 390x667, an iPhone SE, where the headline eats a far bigger share of the
 * screen. Swept: +4% more leaves the dog head 3px off the letters, +6% puts it
 * 10px INTO them, +8% buries both. So the inline values stay the everywhere-safe
 * ones and the extra travel is spent only where there is room to spend it.
 *
 * ⚠️ 800px AND NOT 750, AND THE REASON IS WIDTH. 360x780 clears the height bar
 * but is NARROW, so the headline wraps taller and eats the same room a short
 * screen does: at 750 it left the dog head 4px off the letters. 800 excludes it
 * and the SE, and still covers every iPhone from the 12 up (844, 852, 874, 932).
 *
 * ⚠️ MARGIN, NOT TRANSFORM. The wrapper's transform is the fly-in entrance
 * (translate + rotate + scale) and a second transform here would replace it, so
 * the sticker would land with no animation and no rotation.
 * ⚠️ NOT a percentage margin either: percentage margins resolve against the
 * containing block's WIDTH, so `margin-top: -5%` on a 390x844 phone moves by 5%
 * of 390, not of 844. svh is the unit that means what it reads as. */
@media (min-height: 800px) {
  /* ⚠️ THE DOG HEAD'S THIRD NUDGE LIVES HERE, NOT INLINE, and that is the whole
     lesson of this pass. Moving its inline top from 77.60 to 75.60 gave the
     extra travel to EVERY viewport including the 390x667 SE, which does not get
     this query and so was the only screen paying for it: its clearance fell from
     30px to 16px while his phone gained nothing it could not have had here.
     -7svh instead, and the inline value goes back. */
  html[data-quiz-finale] .c-quiz__icon--lift { margin-top: -7svh; }
  html[data-quiz-finale] .c-quiz__icon--drop { margin-top: 5svh; }
}

/* == /components/wavy-seam/style.css == */
/* Wavy Seam — standalone block (not an overflow). 100px tall, paints both
   the white-above and dark-below regions internally so it visually IS the
   transition between any pair of light→dark sections. */
.c-wavy-seam {
  display: block;
  width: 100%;
  height: 100px;
  margin: 0;
  padding: 0;
  pointer-events: none;
  /* Bleed each half over the section above/below by 1px so anti-aliasing
     never leaves a hairline gap if the surrounding sections aren't pure
     white / pure --bg. */
  margin-top: -1px;
  margin-bottom: -1px;
}
.c-wavy-seam__svg {
  display: block;
  width: 100%;
  height: 100%;
}
.c-wavy-seam__white { fill: #FFFFFF; }
.c-wavy-seam__dark  { fill: var(--bg); }
.c-wavy-seam__line {
  fill: none;
  /* Non-scaling stroke keeps the wave a uniform pixel thickness even though
     preserveAspectRatio="none" stretches the SVG horizontally to full width. */
  stroke-width: 8;
  vector-effect: non-scaling-stroke;
  stroke-linecap: round;
  stroke-linejoin: round;
  filter: drop-shadow(0 2px 8px rgba(160, 140, 255, 0.5));
}

/* Reduced motion: the gradient flow is SVG SMIL (<animate>), which CSS
   animation-play-state cannot pause (the old rule here was a no-op).
   /js/motion-core.js pauses it for real via svg.pauseAnimations() in the
   shared reduced-motion branch. */
