    /* Self-hosted Inter. One variable file spans 100-900, which is why a single
       @font-face covers every weight the page uses (400/500/600/700/800/900).
       Latin subset only: it is the sole subset the browser ever fetched, since
       the page is English. The one glyph outside it is the arrow (U+2192), and
       no Inter subset carries that anyway - it has always come from a fallback
       font. unicode-range is kept so the browser skips this file entirely for
       text it cannot serve, e.g. the emoji in the service card icons. */
    @font-face {
      font-family: 'Inter';
      font-style: normal;
      font-weight: 100 900;
      font-display: swap;
      src: url('./fonts/inter-latin-var.woff2') format('woff2');
      unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6,
        U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122,
        U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
    }

    :root {
      --purple-50: #faf5ff;
      --purple-100: #f3e8ff;
      --purple-200: #e9d5ff;
      --purple-400: #c084fc;
      --purple-500: #a855f7;
      --purple-600: #9333ea;
      --purple-700: #7c3aed;
      --purple-800: #6d28d9;
      --purple-900: #4c1d95;
      --purple-950: #2e1065;
      /* Neutral ramp. Type and primary surfaces moved off the purple scale:
         near-black on warm paper reads calmer and more grown-up, and pulling
         purple back to an accent is what makes the remaining purple mean
         something. Warm greys (not the blue-tinted default) so the page reads
         as paper rather than as screen. */
      --ink: #141414;
      --ink-2: #37343c;
      /* Neutrals lean very slightly violet rather than warm. Warm paper suits a
         monochrome palette, but every accent here is purple - icons, tags,
         headings - and a beige ground reads as tan fighting lilac. A few points
         of blue in the greys is enough to make the accents look at home. */
      --paper: #faf9fc;
      --paper-2: #f4f2f9;
      --line: #e7e3f0;

      --gray-400: #9ca3af;
      --gray-500: #6b7280;
      --gray-600: #4b5563;
    }

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

    html {
      scroll-behavior: smooth;
    }

    body {
      font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
      background: var(--paper);
      color: var(--ink);
      -webkit-font-smoothing: antialiased;
      -moz-osx-font-smoothing: grayscale;
      overflow-x: hidden;
    }

    /* ─── NAV ─── */
    nav {
      position: fixed;
      inset: 0 0 auto 0;
      z-index: 100;
      padding: 18px 48px;
      display: flex;
      align-items: center;
      justify-content: space-between;
      /* Opaque, not frosted. At 0.8 alpha the hero headline read straight
         through the bar as it scrolled under; 0.95 still ghosted. Solid also
         means no backdrop-filter, which drops a compositing pass. */
      background: var(--paper-2);
      border-bottom: 1px solid rgba(124, 58, 237, 0.06);
    }

    .logo {
      font-size: 17px;
      font-weight: 800;
      letter-spacing: -0.4px;
      color: var(--purple-900);
      text-decoration: none;
      display: flex;
      align-items: center;
      gap: 6px;
    }

    .logo img {
      width: 44px;
      height: 44px;
      object-fit: contain;
      mix-blend-mode: multiply;
      border-radius: 10px;
    }

    .logo em {
      font-style: normal;
      color: var(--purple-700);
      margin-left: -2px;
    }

    /* Groups the section links with the CTA so nav's space-between keeps the
       logo hard left and all of this hard right. */
    .nav-right {
      display: flex;
      align-items: center;
      gap: 28px;
    }

    /* Matches the footer Quick Links: 14px, gray-600, normal weight, purple on
       hover. Keeps the links quieter than the CTA sitting next to them. */
    .nav-link {
      font-size: 14px;
      color: var(--gray-600);
      text-decoration: none;
      white-space: nowrap;
      transition: color 0.15s;
    }

    .nav-link:hover {
      color: var(--purple-700);
    }

    .nav-cta {
      display: inline-flex;
      align-items: center;
      padding: 9px 20px;
      background: var(--purple-900);
      color: white;
      font-size: 14px;
      font-weight: 600;
      border-radius: 8px;
      text-decoration: none;
      transition: background 0.15s ease, transform 0.1s ease;
      letter-spacing: -0.1px;
      white-space: nowrap;
    }

    .nav-cta:hover {
      background: var(--purple-800);
      transform: translateY(-1px);
    }

    /* ─── HERO ─── */
    .hero {
      /* Was 100svh. With the current short hero copy that reserved most of a
         viewport of empty space above the fold seam, which read as a void when
         scrolling rather than as breathing room. */
      /* 88svh, not 74: at 74 the next section's heading cleared the fold by
         80px, which made the page read as short. The band below carries 112px
         of top padding, so any hero at >=88svh pushes that heading off-screen
         on viewports up to ~930px tall without the hero itself going hollow. */
      min-height: 88svh;
      display: flex;
      align-items: center;
      justify-content: center;
      /* Top-heavier than the bottom on purpose: the hero centres its content
         with flex, so a larger top pad walks the headline down the screen
         rather than just adding a gap above it. */
      padding: 150px 48px 80px;
      text-align: center;
      position: relative;
      /* The ramp lands on warm paper now that the rest of the page does; the
         violet bloom stays, lighter, so the brand colour still greets you at
         the top without the whole hero reading as a cool-toned page on a warm
         one. */
      background:
        radial-gradient(ellipse 80% 60% at 50% -10%, rgba(167, 139, 250, 0.15) 0%, transparent 70%),
        /* Tint at the top so the nav dissolves into it, white at the bottom so
           the first band's tint reads as a real edge rather than a colour shift. */
        linear-gradient(180deg, var(--paper-2) 0%, var(--paper) 55%, #ffffff 100%);
      overflow: hidden;
    }

    .hero-inner {
      position: relative;
      z-index: 2;
      /* 980, not 800: the unbreakable first line runs 936px at the 68px cap, so
         an 800px box left it overflowing its own container. .hero-sub carries
         its own 640px measure, so widening this does not loosen the paragraph. */
      max-width: 980px;
    }

    .hero-eyebrow {
      display: inline-flex;
      align-items: center;
      gap: 7px;
      background: rgba(124, 58, 237, 0.08);
      color: var(--purple-700);
      padding: 5px 14px 5px 10px;
      border-radius: 100px;
      font-size: 12.5px;
      font-weight: 600;
      letter-spacing: 0.1px;
      margin-bottom: 28px;
      border: 1px solid rgba(124, 58, 237, 0.12);
    }

    .hero-dot {
      width: 6px;
      height: 6px;
      background: var(--purple-600);
      border-radius: 50%;
      animation: dot-pulse 2.4s ease-in-out infinite;
    }

    @keyframes dot-pulse {
      0%, 100% { opacity: 1; transform: scale(1); }
      50% { opacity: 0.4; transform: scale(0.75); }
    }

    .hero-headline {
      /* clamp, not min(): min() capped the top but had no floor, so the
         headline computed to 18.75px on a 375px phone - smaller than the
         paragraph under it. */
      font-size: clamp(34px, 6.2vw, 68px);
      font-weight: 800;
      line-height: 1.0;
      /* Relative, not px: font-size is fluid, so fixed tracking that reads as
         tight at the 50px cap becomes -0.13em at mobile sizes and closes up the
         word spaces entirely. -0.04em is exactly -2px at 50px, so the desktop
         headline is unchanged. */
      letter-spacing: -0.045em;
      color: var(--purple-900);
      margin-bottom: 34px;
    }

    .hero-headline span {
      display: block;
    }

    .hero-headline span.line1 {
      color: var(--purple-900);
      white-space: nowrap;
    }

    .hero-headline span.line2 {
      color: var(--purple-700);
    }

    /* Accent half of the one-row headline. display:inline is required, not
       decorative: `.hero-headline span { display: block }` above would otherwise
       drop "goals." onto its own line. Scoped to .hero-headline rather than
       changing that base rule, which general.html's two-line hero still needs. */
    .hero-headline .headline-accent {
      display: inline;
      color: var(--purple-700);
    }

    /* Rotating goal word. Selectors are scoped to .hero-headline so they outrank
       `.hero-headline span { display: block }` above — the rotator has to stay
       inline or "goals." drops to its own line.
       The rotator takes its width from whichever word is in flow, so it always
       hugs the active word exactly — no measuring, no fixed width, nothing to
       keep in sync. Only the active word is static; the rest are pulled out of
       flow so they neither widen the box nor push "goals." along. */
    /* inline-grid stacks every word into a single cell, so the rotator is
       always as wide as the LONGEST word rather than the current one. Two things
       fall out of that: "to smash" stops sliding sideways on every rotation
       (the words range 337-486px, which moved it ~75px in a centred headline),
       and .headline-line1's nowrap now has a box whose width never changes. */
    /* inline-block with absolutely-positioned words, NOT inline-grid: a grid
       container establishes its own formatting context, so its box is sized to
       the font's full ascent+descent rather than the headline's 1.0 line-height,
       which inflated the line box and blew the gap between lines wide open.
       min-width is what holds the width constant instead - see below. */
    .hero-headline .goal-rotator {
      display: inline-block;
      position: relative;
    }

    /* The rotating word and "to smash" are one unbreakable unit. Left to wrap
       naturally the line breaks after "to", orphaning "smash" on a line of its
       own, which reads as a mistake. Released at mobile, where the phrase
       genuinely cannot fit on one line and three lines is the right answer. */
    .hero-headline .headline-line1 {
      /* display:inline is required, not decorative: `.hero-headline span
         { display: block }` above would otherwise make this a block, at which
         point it fills the container and nowrap has nothing to act on. */
      display: inline;
      white-space: nowrap;
    }

    /* Leaving word: out of flow, quick exit, no delay. nowrap keeps a word from
       ever breaking across lines once it's absolutely positioned. */
    .hero-headline .goal-rotator > .goal-word {
      position: absolute;
      top: 0;
      left: 0;
      white-space: nowrap;
      opacity: 0;
      transform: translateY(0.16em);
      transition: opacity 220ms ease, transform 220ms ease;
    }

    /* Entering word: back in flow to define the width, and delayed so it starts
       only once the outgoing word has cleared. Two words crossfading in the same
       spot reads as smeared text, so these are sequenced rather than overlapped.
       The width change lands inside that gap, while no word is visible. */
    /* Two attributes, deliberately separate: data-flow decides which word sizes
       the rotator, data-active decides which one you can see. Keeping them apart
       lets the outgoing word finish fading BEFORE the box resizes - swapping
       both at once resized the rotator while a 642px word was still painted,
       so it spilled over "to smash" for the length of the fade. */
    .hero-headline .goal-rotator > .goal-word[data-flow] {
      position: static;
    }

    .hero-headline .goal-rotator > .goal-word[data-active] {
      opacity: 1;
      transform: none;
      transition: opacity 320ms ease, transform 320ms ease;
    }

    /* 640px, not the old 540px: the tagline measures 596px at the 19px cap, so
       540 wrapped it and orphaned "teams." on a second line. Still well inside
       .hero-inner's 800px, and the line does not wrap at desktop anyway, so the
       usual reason to keep a subhead measure narrow does not apply. */
    .hero-sub {
      font-size: clamp(16px, 2vw, 19px);
      line-height: 1.5;
      color: var(--gray-500);
      max-width: 640px;
      margin: 0 auto 48px;
      font-weight: 400;
    }

    .hero-actions {
      display: flex;
      align-items: center;
      justify-content: center;
      gap: 20px;
      flex-wrap: wrap;
    }

    .btn-primary {
      display: inline-flex;
      align-items: center;
      padding: 14px 28px;
      background: var(--purple-900);
      color: white;
      font-size: 15.5px;
      font-weight: 600;
      border-radius: 10px;
      text-decoration: none;
      letter-spacing: -0.2px;
      box-shadow: 0 4px 14px rgba(76, 29, 149, 0.24), 0 0 0 1px rgba(76, 29, 149, 0.10);
      transition: background 0.15s, transform 0.12s, box-shadow 0.15s;
    }

    .btn-primary:hover {
      background: var(--purple-800);
      transform: translateY(-2px);
      box-shadow: 0 8px 28px rgba(124, 58, 237, 0.42), 0 0 0 1px rgba(124,58,237,0.2);
    }

    .btn-ghost {
      font-size: 15px;
      font-weight: 600;
      color: var(--purple-700);
      text-decoration: none;
      display: inline-flex;
      align-items: center;
      gap: 5px;
      transition: gap 0.15s;
    }

    .btn-ghost:hover {
      gap: 9px;
    }

    .hero-microcopy {
      margin-top: 22px;
      font-size: 13.5px;
      line-height: 1.5;
      color: var(--gray-500);
      letter-spacing: -0.1px;
    }

    /* ─── HERO GRAPHIC ─── */
    .hero-graphic {
      position: absolute;
      bottom: -40px;
      right: -80px;
      width: 480px;
      height: 540px;
      opacity: 0.22;
      pointer-events: none;
      transform: rotate(-3deg);
    }


    @media (max-width: 900px) {
      .hero-graphic {
        width: 300px;
        height: 340px;
        right: -40px;
        bottom: -20px;
        opacity: 0.14;
      }
    }

    /* ─── VIDEO ─── */
    .video-section {
      padding: 96px 48px;
      background: linear-gradient(180deg, #f5f0ff 0%, #ffffff 100%);
      text-align: center;
    }

    .video-section .section-header {
      margin-bottom: 48px;
    }

    .video-placeholder {
      max-width: 760px;
      margin: 0 auto;
      aspect-ratio: 16 / 9;
      background: linear-gradient(135deg, #1e1040 0%, #3b1d8a 50%, #5b21b6 100%);
      border-radius: 18px;
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      gap: 16px;
      position: relative;
      overflow: hidden;
      box-shadow: 0 20px 60px rgba(76, 29, 149, 0.25), 0 0 0 1px rgba(124,58,237,0.15);
      cursor: pointer;
    }

    .video-placeholder::before {
      content: '';
      position: absolute;
      inset: 0;
      background: radial-gradient(ellipse 80% 60% at 50% 100%, rgba(124,58,237,0.3) 0%, transparent 70%);
    }

    .play-btn {
      width: 72px;
      height: 72px;
      background: rgba(255,255,255,0.15);
      border: 2px solid rgba(255,255,255,0.3);
      border-radius: 50%;
      display: flex;
      align-items: center;
      justify-content: center;
      backdrop-filter: blur(8px);
      transition: background 0.2s, transform 0.15s;
      position: relative;
      z-index: 2;
    }

    .video-placeholder:hover .play-btn {
      background: rgba(255,255,255,0.25);
      transform: scale(1.08);
    }

    .play-icon {
      width: 0;
      height: 0;
      border-style: solid;
      border-width: 11px 0 11px 20px;
      border-color: transparent transparent transparent white;
      margin-left: 4px;
    }

    .video-label {
      font-size: 14px;
      font-weight: 600;
      color: rgba(255,255,255,0.7);
      letter-spacing: 0.2px;
      position: relative;
      z-index: 2;
    }

    /* ─── ABOUT ─── */
    .about {
      padding: 96px 48px;
      background: #ffffff;
    }

    .about-inner {
      max-width: 900px;
      margin: 0 auto;
      display: grid;
      grid-template-columns: 260px 1fr;
      gap: 64px;
      align-items: center;
    }

    @media (max-width: 768px) {
      .about-inner {
        grid-template-columns: 1fr;
        gap: 40px;
        text-align: center;
      }
      .about-photo-wrap {
        margin: 0 auto;
      }
    }

    .about-photo-wrap {
      position: relative;
      width: 220px;
    }

    .about-photo {
      width: 220px;
      height: 220px;
      border-radius: 18px;
      object-fit: cover;
      object-position: center top;
      display: block;
      box-shadow: 0 12px 40px rgba(76, 29, 149, 0.18);
    }

    .about-photo-badge {
      position: absolute;
      bottom: -12px;
      right: -12px;
      background: var(--purple-700);
      color: white;
      font-size: 11px;
      font-weight: 700;
      letter-spacing: 0.8px;
      text-transform: uppercase;
      padding: 6px 12px;
      border-radius: 100px;
      box-shadow: 0 4px 12px rgba(124,58,237,0.4);
    }

    .about-content {
    }

    .about-label {
      font-size: 11.5px;
      font-weight: 700;
      letter-spacing: 1.8px;
      text-transform: uppercase;
      color: var(--purple-600);
      margin-bottom: 12px;
    }

    .about-name {
      font-size: clamp(28px, 3.5vw, 40px);
      font-weight: 800;
      letter-spacing: -1.2px;
      color: var(--purple-950);
      margin-bottom: 16px;
      line-height: 1.1;
    }

    .about-bio {
      font-size: 16.5px;
      line-height: 1.7;
      color: var(--gray-500);
    }

    .about-bio strong {
      color: var(--purple-900);
      font-weight: 600;
    }

    /* Only inline prose link on the page; underline stays faint until hover so
       it reads as text, not as a button. */
    .about-bio a {
      color: var(--purple-700);
      font-weight: 500;
      text-decoration: underline;
      text-decoration-thickness: 1px;
      text-decoration-color: rgba(124, 58, 237, 0.35);
      text-underline-offset: 2px;
      transition: color 160ms ease, text-decoration-color 160ms ease;
    }

    .about-bio a:hover {
      color: var(--purple-900);
      text-decoration-color: currentColor;
    }

    /* ─── SERVICES ─── */
    .services {
      padding: 112px 48px;
      background: #ffffff;
      position: relative;
    }

    .services::before {
      content: '';
      position: absolute;
      inset: 0;
      background: radial-gradient(ellipse 60% 40% at 50% 0%, rgba(124,58,237,0.04) 0%, transparent 70%);
      pointer-events: none;
    }

    .section-header {
      text-align: center;
      max-width: 560px;
      margin: 0 auto 64px;
    }

    /* Wider than the 560px default so the section title holds one line.
       "Your operational data, centralized." measures 697px at the 44px cap,
       so 680px wrapped it and orphaned "centralized." on line two; 740px
       clears it with room to spare. Opt-in modifier because the archived
       legacy/ pages have shorter titles that are fine at 560px. Still wraps on
       narrow viewports, where the clamp floor pins the font at 30px. */
    .section-header--wide {
      max-width: 740px;
    }

    .section-label {
      font-size: 11.5px;
      font-weight: 700;
      letter-spacing: 1.8px;
      text-transform: uppercase;
      color: var(--purple-600);
      margin-bottom: 14px;
    }

    .section-title {
      font-size: clamp(32px, 4.4vw, 52px);
      font-weight: 800;
      /* Relative like the hero, so tracking that reads tight at the 52px cap
         does not close up the word spaces at mobile sizes. */
      letter-spacing: -0.035em;
      color: var(--ink);
      line-height: 1.02;
      margin-bottom: 14px;
    }

    .section-desc {
      font-size: 16.5px;
      line-height: 1.65;
      color: var(--gray-500);
    }

    .services-grid {
      max-width: 1120px;
      margin: 0 auto;
      display: grid;
      grid-template-columns: repeat(6, 1fr);
      gap: 20px;
    }

    /* Row 1: 3 cards each spanning 2 of 6 columns */
    .services-grid .service-card:nth-child(-n+3) {
      grid-column: span 2;
    }

    /* Row 2: 2 cards each spanning 3 of 6 columns, centered */
    .services-grid .service-card:nth-child(4) {
      grid-column: 1 / span 3;
    }

    .services-grid .service-card:nth-child(5) {
      grid-column: 4 / span 3;
    }

    @media (max-width: 900px) {
      .services-grid {
        grid-template-columns: repeat(2, 1fr);
      }
      .services-grid .service-card {
        grid-column: span 1 !important;
      }
    }

    @media (max-width: 640px) {
      .services-grid {
        grid-template-columns: 1fr;
      }
    }

    /* One card per row. Declared after the media queries above on purpose:
       same specificity as `.services-grid`, so source order is what keeps this
       single-column at every width instead of reverting to 2-up at 900px.
       Narrower than the 1120px grid because a full-width card holding three
       short bullets reads as broken, not roomy. Opt-in modifier so
       general.html keeps the 3+2 grid. */
    .services-grid--stacked {
      max-width: 780px;
      grid-template-columns: 1fr;
    }

    /* :nth-child(n) only to match the specificity of the span rules above,
       which would otherwise create implicit columns in a 1-column grid. */
    .services-grid--stacked .service-card:nth-child(n) {
      grid-column: 1 / -1;
    }

    /* Cards carry weight at rest, not only on hover: four flat outlines read as
       placeholder. The accent bar wipes in from the left on hover rather than
       fading, which reads as deliberate instead of as a colour flicker. */
    .service-card {
      position: relative;
      overflow: hidden;
      background: linear-gradient(158deg, #ffffff 0%, #fdfaff 100%);
      border: 1px solid rgba(124, 58, 237, 0.12);
      border-radius: 16px;
      padding: 30px 28px;
      box-shadow: 0 1px 2px rgba(46, 16, 101, 0.04),
                  0 10px 26px -14px rgba(124, 58, 237, 0.18);
      transition: transform 0.2s ease, box-shadow 0.2s ease, border-color 0.2s ease;
    }

    .service-card::after {
      content: '';
      position: absolute;
      left: 0;
      top: 0;
      height: 3px;
      width: 0;
      background: linear-gradient(90deg, var(--purple-600), var(--purple-400));
      transition: width 0.28s ease;
    }

    .service-card:hover {
      transform: translateY(-5px);
      border-color: rgba(124, 58, 237, 0.28);
      box-shadow: 0 2px 4px rgba(46, 16, 101, 0.05),
                  0 20px 42px -16px rgba(124, 58, 237, 0.28);
    }

    .service-card:hover::after { width: 100%; }

    .service-icon-wrap {
      width: 48px;
      height: 48px;
      border-radius: 13px;
      background: linear-gradient(140deg, #f5edff 0%, #e9defe 100%);
      border: 1px solid rgba(124, 58, 237, 0.12);
      color: var(--purple-700);
      display: flex;
      align-items: center;
      justify-content: center;
      margin-bottom: 20px;
      font-size: 19px;
      line-height: 1;
    }

    /* Stroke icons, sized here rather than per-SVG so all four stay optically
       equal. currentColor lets the wrap own the colour. */
    .service-icon-wrap svg {
      width: 23px;
      height: 23px;
      display: block;
    }

    .service-card h3 {
      font-size: 16.5px;
      font-weight: 700;
      letter-spacing: -0.3px;
      color: var(--purple-950);
      margin-bottom: 9px;
      line-height: 1.25;
    }

    .service-card p {
      font-size: 14px;
      line-height: 1.6;
      color: var(--gray-500);
    }

    /* ─── AGENTS ─── */
    .agents {
      padding: 112px 48px;
      background: #ffffff;
      position: relative;
    }

    .agents::before {
      content: '';
      position: absolute;
      inset: 0;
      background: radial-gradient(ellipse 60% 40% at 50% 0%, rgba(124,58,237,0.04) 0%, transparent 70%);
      pointer-events: none;
    }

    .agents-grid {
      max-width: 1120px;
      margin: 0 auto;
      display: grid;
      grid-template-columns: repeat(3, 1fr);
      gap: 20px;
    }

    @media (max-width: 900px) {
      .agents-grid { grid-template-columns: 1fr 1fr; }
    }

    @media (max-width: 640px) {
      .agents-grid { grid-template-columns: 1fr; }
    }

    .agent-card {
      background: var(--paper);
      border: 1px solid rgba(124, 58, 237, 0.1);
      border-radius: 14px;
      padding: 28px;
      transition: transform 0.18s ease, box-shadow 0.18s ease, border-color 0.18s;
    }

    .agent-card:hover {
      transform: translateY(-5px);
      box-shadow: 0 14px 36px rgba(124, 58, 237, 0.1);
      border-color: rgba(124, 58, 237, 0.2);
    }

    .agent-card h3 {
      font-size: 15.5px;
      font-weight: 700;
      letter-spacing: -0.3px;
      color: var(--purple-950);
      margin-bottom: 16px;
      line-height: 1.25;
    }

    .agent-features {
      list-style: none;
      display: flex;
      flex-direction: column;
      gap: 10px;
    }

    .agent-features li {
      font-size: 14px;
      line-height: 1.5;
      color: var(--gray-500);
      padding-left: 18px;
      position: relative;
    }

    .agent-features li::before {
      content: '→';
      position: absolute;
      left: 0;
      color: var(--purple-600);
      font-size: 11px;
      top: 1px;
    }

    /* Two-part features: a label with a context note under it. Opt-in modifier
       so general.html's plain single-line agent lists keep their tighter
       spacing. The arrow's top:1px above already aligns to the label line. */
    .agent-features--detailed {
      gap: 18px;
    }

    .agent-features--detailed .feature-label {
      display: block;
      font-weight: 600;
      color: var(--purple-950);
      margin-bottom: 3px;
    }

    .agent-features--detailed .feature-note {
      display: block;
      color: var(--gray-500);
    }

    /* ─── CONTACT ─── */
    .contact {
      padding: 112px 48px;
      background: linear-gradient(140deg, #3b0f8a 0%, #5b21b6 38%, #7c3aed 70%, #9333ea 100%);
      text-align: center;
      position: relative;
      overflow: hidden;
    }

    .contact-orb-1 {
      position: absolute;
      width: 600px;
      height: 600px;
      border-radius: 50%;
      background: rgba(255,255,255,0.04);
      top: -200px;
      right: -150px;
      pointer-events: none;
    }

    .contact-orb-2 {
      position: absolute;
      width: 400px;
      height: 400px;
      border-radius: 50%;
      background: rgba(255,255,255,0.03);
      bottom: -180px;
      left: -100px;
      pointer-events: none;
    }

    .contact-inner {
      position: relative;
      z-index: 2;
      max-width: 560px;
      margin: 0 auto;
    }

    .contact-tag {
      display: inline-block;
      background: rgba(255,255,255,0.12);
      color: #e9d5ff;
      padding: 5px 14px;
      border-radius: 100px;
      font-size: 11.5px;
      font-weight: 700;
      letter-spacing: 1.5px;
      text-transform: uppercase;
      margin-bottom: 20px;
      border: 1px solid rgba(255,255,255,0.12);
    }

    .contact-title {
      font-size: clamp(32px, 5vw, 56px);
      font-weight: 800;
      letter-spacing: -0.04em;
      color: #ffffff;
      line-height: 1.0;
      margin-bottom: 16px;
    }

    /* Label tier above the heading. Deliberately not a third invitation - the
       heading asks and the button acts, so this one just names the section and
       lets the eye land somewhere before the big type. */
    .contact-eyebrow {
      display: block;
      font-size: 12.5px;
      font-weight: 700;
      letter-spacing: 0.12em;
      text-transform: uppercase;
      color: rgba(255, 255, 255, 0.6);
      margin-bottom: 18px;
    }

    .contact-sub {
      font-size: 16.5px;
      line-height: 1.6;
      color: #c4b5fd;
      margin-bottom: 44px;
    }

    .contact-form {
      display: flex;
      justify-content: center;
      gap: 10px;
      max-width: 430px;
      margin: 0 auto 20px;
    }

    .contact-email {
      flex: 1;
      padding: 13px 18px;
      background: rgba(255,255,255,0.13);
      border: 1px solid rgba(255,255,255,0.18);
      border-radius: 9px;
      color: white;
      font-size: 14.5px;
      font-family: inherit;
      outline: none;
      transition: background 0.15s, border-color 0.15s;
    }

    .contact-email::placeholder {
      color: rgba(255,255,255,0.42);
    }

    .contact-email:focus {
      background: rgba(255,255,255,0.2);
      border-color: rgba(255,255,255,0.35);
    }

    .contact-btn {
      padding: 15px 48px;
      background: white;
      color: var(--purple-800);
      font-size: 15.5px;
      font-weight: 700;
      font-family: inherit;
      border: none;
      border-radius: 10px;
      cursor: pointer;
      transition: transform 0.12s, box-shadow 0.15s;
      white-space: nowrap;
      letter-spacing: -0.1px;
      text-decoration: none;
      display: inline-block;
    }

    .contact-btn:hover {
      transform: translateY(-2px);
      box-shadow: 0 6px 20px rgba(0,0,0,0.2);
    }

    .contact-note {
      font-size: 13px;
      color: #a78bfa;
    }

    /* ─── FOOTER ─── */
    footer {
      background: var(--paper-2);
      border-top: 1px solid #ede9fe;
      /* Symmetric now that the footer is a single row; 64/32 was balanced
         against the brand block that used to sit above it. */
      padding: 34px 48px;
    }

    .footer-top {
      display: grid;
      /* auto, not a second fraction: the link column has ~115px of content, so
         a fractional track left it floating mid-row with 300px of dead space to
         its right. Shrinking it to content anchors it flush right, which is
         also how .footer-bottom already pins its two halves. */
      grid-template-columns: 1fr auto;
      gap: 48px;
      max-width: 1120px;
      margin: 0 auto 48px;
    }

    .footer-logo {
      font-size: 17px;
      font-weight: 800;
      color: var(--purple-950);
      letter-spacing: -0.4px;
      display: flex;
      align-items: center;
      gap: 6px;
      margin-bottom: 14px;
      text-decoration: none;
    }

    .footer-logo img {
      width: 44px;
      height: 44px;
      object-fit: contain;
      border-radius: 10px;
    }

    .footer-logo em {
      font-style: normal;
      color: #7c3aed;
      margin-left: -2px;
    }

    .footer-tagline {
      font-size: 14px;
      line-height: 1.6;
      color: #6b7280;
      max-width: 260px;
      margin-bottom: 24px;
    }

    .footer-contact-link {
      font-size: 13.5px;
      color: #7c3aed;
      text-decoration: none;
      font-weight: 500;
      transition: color 0.15s;
    }

    .footer-contact-link:hover {
      color: var(--purple-950);
    }

    .footer-col-title {
      font-size: 11px;
      font-weight: 700;
      letter-spacing: 1.6px;
      text-transform: uppercase;
      color: #9ca3af;
      margin-bottom: 20px;
    }

    .footer-links {
      list-style: none;
      display: flex;
      flex-direction: column;
      gap: 13px;
    }

    .footer-links a {
      font-size: 14px;
      color: #4b5563;
      text-decoration: none;
      transition: color 0.15s;
    }

    .footer-links a:hover {
      color: #7c3aed;
    }

    /* One row now that the brand block and link column are gone. Grid rather
       than space-between: with three items of unequal width, space-between
       distributes the slack and the middle item lands off-centre. Equal 1fr
       flanks put the email dead centre regardless of what sits either side.
       The old border-top went with the block it used to separate. */
    .footer-bottom {
      max-width: 1120px;
      margin: 0 auto;
      display: grid;
      grid-template-columns: 1fr auto 1fr;
      align-items: center;
      gap: 16px;
    }

    .footer-bottom .footer-copy { justify-self: start; }
    .footer-bottom .footer-contact-link { justify-self: center; }
    .footer-bottom .footer-location { justify-self: end; }

    @media (max-width: 768px) {
      .footer-bottom {
        grid-template-columns: 1fr;
        gap: 10px;
        text-align: center;
      }
      .footer-bottom > * { justify-self: center; }
    }

    .footer-copy {
      font-size: 13px;
      color: #9ca3af;
    }

    .footer-location {
      font-size: 12px;
      color: #9ca3af;
      letter-spacing: 0.3px;
    }

    /* ─── RESPONSIVE ─── */
    @media (max-width: 768px) {
      nav { padding: 16px 24px; }
      .hero { padding: 88px 24px 60px; }
      .services { padding: 80px 24px; }
      .contact { padding: 80px 24px; }
      .contact-form { flex-direction: column; max-width: 100%; }
      .contact-btn { width: 100%; }
      footer { padding: 48px 24px 24px; }
      .footer-top { grid-template-columns: 1fr 1fr; }
      .footer-brand { grid-column: 1 / -1; }
    }

    /* Below this the section links crowd the logo - 26px of clearance at 520px,
       none at all by 414px. Drops back to logo + CTA, and both sections stay
       reachable by scrolling or from the footer links. */
    @media (max-width: 600px) {
      .nav-link { display: none; }
    }

    @media (max-width: 480px) {
      nav { padding: 14px 16px; }
      .logo { font-size: 15px; }
      .logo img { width: 32px; height: 32px; }
      .nav-cta { font-size: 13px; padding: 8px 14px; }
      .hero { padding: 72px 16px 48px; }
      .services { padding: 64px 16px; }
      .contact { padding: 64px 16px; }
      footer { padding: 20px 16px; }
    }

    /* The solutions section and About are both white, so their paddings merge
       into a single gap. Left alone, the white above the About content is the
       sum of the two (208px at desktop) while below it is only About's own
       96px, which reads as badly off-centre. Zeroing this lets About's
       symmetric padding define the space on both sides by itself.
       Declared after the media queries above, and as a single property rather
       than a shorthand, so it still wins at every breakpoint — the responsive
       .services rules set padding on all four sides. */
    .services {
      padding-bottom: 0;
    }

    @media (prefers-reduced-motion: reduce) {
      *, *::before, *::after {
        animation-duration: 0.001ms !important;
        transition-duration: 0.001ms !important;
      }
    }

    :focus-visible {
      outline: 2px solid var(--purple-700);
      outline-offset: 3px;
    }

    /* ─── CONTENT BANDS (2026-08-19 rebuild) ───
       Generic section wrapper replacing the single .services block. Deliberately
       NOT reusing .services: that class carries a blanket `padding-bottom: 0`
       tied to its old adjacency with the white About section, which would
       collapse the gap under every band if it were reused here.
       Tones alternate tint / white / tint so the stacked sections read as
       separate rather than one long scroll. */
    .band {
      padding: 112px 48px;
      background: #ffffff;
      position: relative;
      isolation: isolate;
    }

    /* Section texture. Three layers, all decorative and all pointer-inert:
       a radial bloom at the top of each band (echoing the hero's own gradient),
       a hairline seam that fades out at both ends so the boundary is felt
       rather than ruled, and on tinted bands a soft inset so the section reads
       as a layer sitting under the one above it. Without these, white-on-white
       band boundaries scroll past as one continuous void. */
    .band::before {
      content: '';
      position: absolute;
      inset: 0 0 auto 0;
      height: 460px;
      z-index: 0;
      background: radial-gradient(ellipse 68% 100% at 50% 0%,
                  rgba(124, 58, 237, 0.06) 0%, transparent 72%);
      pointer-events: none;
    }

    .band::after {
      content: '';
      position: absolute;
      top: 0;
      left: 0;
      right: 0;
      height: 1px;
      z-index: 0;
      background: linear-gradient(90deg, transparent 0%,
                  rgba(124, 58, 237, 0.18) 24%, rgba(124, 58, 237, 0.18) 76%,
                  transparent 100%);
      pointer-events: none;
    }

    /* ::before is positioned, so it would otherwise paint over the in-flow
       content below it. */
    .band > * {
      position: relative;
      z-index: 1;
    }

    .band--tint {
      background: var(--paper-2);
      box-shadow: inset 0 22px 34px -30px rgba(20, 20, 20, 0.10);
    }

    /* ─── PROBLEM ───
       No card chrome on purpose. Three bordered cards here would read as three
       offers; these are three symptoms, and the section below is cards. */
    .problem-grid {
      max-width: 1000px;
      margin: 0 auto;
      display: grid;
      grid-template-columns: repeat(3, 1fr);
      gap: 44px;
    }

    .problem-item h3 {
      font-size: 17px;
      font-weight: 700;
      letter-spacing: -0.3px;
      color: var(--purple-950);
      line-height: 1.3;
      margin-bottom: 10px;
      padding-top: 16px;
      border-top: 2px solid var(--purple-200);
    }

    .problem-item p {
      font-size: 14.5px;
      line-height: 1.65;
      color: var(--gray-500);
    }

    /* ─── WHO WE SERVE ───
       4-up. .agents-grid is 3-up, so this needs its own column count; the cards
       themselves reuse .service-card for chrome. */
    .vert-grid {
      max-width: 1120px;
      margin: 0 auto;
      display: grid;
      grid-template-columns: repeat(4, 1fr);
      gap: 20px;
    }

    /* ─── HOW WE HELP ───
       Reuses .agents-grid (3-up, already responsive) and .service-card. Only
       the numeral treatment is new. */
    .step-num {
      font-size: 17px;
      font-weight: 800;
      color: var(--purple-700);
    }

    /* 4-up only while the grid sits at its 1120px cap, which needs roughly a
       1220px viewport once section padding is taken out. Below that the cards
       narrow enough that every one-line blurb wraps and "Commercial Services"
       breaks across two lines, so drop to 2-up before that happens rather
       than after. */
    /* ─── SCORECARD TEMPLATES (How We Help) ───
       Richer than .service-card: each holds a name, the question in the buyer's
       own voice, the systems it joins, and the payoff. The question is the point
       of the section - showing what the scorecard answers rather than describing
       a process. Flex column so the payoff pins to the bottom and the three
       cards read as one row despite unequal question lengths. */
    .score-grid {
      max-width: 1120px;
      margin: 0 auto;
      display: grid;
      grid-template-columns: repeat(3, 1fr);
      gap: 22px;
      align-items: stretch;
    }

    .score-card {
      position: relative;
      overflow: hidden;
      display: flex;
      flex-direction: column;
      background: linear-gradient(158deg, #ffffff 0%, #fdfaff 100%);
      border: 1px solid rgba(124, 58, 237, 0.12);
      border-radius: 16px;
      padding: 30px 28px;
      box-shadow: 0 1px 2px rgba(46, 16, 101, 0.04),
                  0 10px 26px -14px rgba(124, 58, 237, 0.18);
    }

    .score-card h3 {
      font-size: 17px;
      font-weight: 800;
      letter-spacing: -0.35px;
      color: var(--purple-950);
      margin-bottom: 14px;
    }

    /* Block labels inside a scorecard ("Answers" / "Sources"). Deliberately the
       quietest type on the card so they organise without competing with the
       question, which is the persuasive element. */
    .score-label {
      display: block;
      font-size: 10.5px;
      font-weight: 700;
      letter-spacing: 1.2px;
      text-transform: uppercase;
      color: var(--gray-400);
      margin-bottom: 7px;
    }

    /* The buyer's question, set apart because it is the persuasive element. */
    /* min-height reserves 4 lines so the block does not change height when a
       question wraps to a 4th line at narrower 3-up widths. Without it the rule
       below re-aligns per card between roughly 1050 and 1220px. Costs one line
       of air at wide widths, applied equally to all three, in exchange for the
       rules matching at every width. */
    .score-q {
      font-size: 14.5px;
      line-height: 1.6;
      min-height: 6.4em;
      color: var(--purple-800);
      font-style: italic;
      padding-left: 14px;
      border-left: 2px solid var(--purple-200);
      margin-bottom: 18px;
    }

    .score-sys {
      display: flex;
      flex-wrap: wrap;
      gap: 6px;
      margin-bottom: 16px;
    }

    .score-sys span {
      font-size: 11.5px;
      font-weight: 600;
      letter-spacing: 0.3px;
      color: var(--purple-700);
      background: #f5edff;
      border: 1px solid rgba(124, 58, 237, 0.12);
      border-radius: 999px;
      padding: 4px 10px;
      white-space: nowrap;
    }

    /* NOT margin-top:auto. Pinning the payoff to the card's bottom edge made its
       top border float with its own line count (3/5/4 lines put the rule at
       277/233/255px), so the three rules read as ragged even though the cards
       are identical height and everything above the rule is pixel-identical.
       Top-aligning instead lands every rule at the same y; the slack falls to
       the bottom of the shorter cards, where empty space is invisible. */
    .score-val {
      padding-top: 18px;
      border-top: 1px solid rgba(124, 58, 237, 0.1);
      font-size: 14px;
      line-height: 1.6;
      color: var(--gray-500);
    }

    .score-val em {
      font-style: normal;
      font-weight: 700;
      color: var(--purple-950);
    }

    /* Sits under the grid to stop the three cards reading as a fixed menu. */
    .score-note {
      max-width: 720px;
      margin: 34px auto 0;
      text-align: center;
      font-size: 15px;
      line-height: 1.65;
      color: var(--gray-500);
    }

    /* ─── WHY NOW ───
       Numerals rather than icon tiles or the Problem section's top rule, so the
       page carries three visually distinct treatments instead of three grids
       that look the same. */
    .why-grid {
      max-width: 1080px;
      margin: 0 auto;
      display: grid;
      grid-template-columns: repeat(3, 1fr);
      gap: 40px;
    }

    .why-num {
      display: block;
      font-size: 13px;
      font-weight: 800;
      letter-spacing: 1.4px;
      color: var(--purple-400);
      margin-bottom: 10px;
    }

    .why-item h3 {
      font-size: 17.5px;
      font-weight: 700;
      letter-spacing: -0.3px;
      color: var(--purple-950);
      line-height: 1.3;
      margin-bottom: 10px;
    }

    .why-item p {
      font-size: 14.5px;
      line-height: 1.68;
      color: var(--gray-500);
    }

    @media (max-width: 1219px) {
      .vert-grid { grid-template-columns: repeat(2, 1fr); }
    }

    /* 1219px to match .vert-grid, not 1050px. Below ~1220 a 3-up card is too
       narrow for four data-source pills on one row, and a wrapped pill row
       pushes that card's rule 30px down, breaking the alignment across the
       three. Stacking earlier keeps the row uniform at every width and costs
       nothing, since the page already changes layout at this breakpoint. */
    @media (max-width: 1219px) {
      .score-grid { grid-template-columns: 1fr; max-width: 620px; }
    }

    @media (max-width: 900px) {
      .problem-grid { grid-template-columns: 1fr; gap: 30px; }
      .why-grid { grid-template-columns: 1fr; gap: 34px; }
    }

    @media (max-width: 768px) {
      .band { padding: 80px 24px; }
    }

    @media (max-width: 640px) {
      .vert-grid { grid-template-columns: 1fr; }
    }

    @media (max-width: 480px) {
      .band { padding: 64px 16px; }
    }

    /* ═══ WHAT WE DO — flip cards ═══════════════════════════════════════════
       The card is the positioning context and the only thing with a height;
       .flip-inner and both faces are absolutely positioned inside it. Faces
       can't contribute height when they're out of flow, which is why the
       min-height is set once here and sized to the taller (back) face. */
    .flip-grid {
      max-width: 1120px;
      margin: 0 auto;
      display: grid;
      grid-template-columns: repeat(4, 1fr);
      gap: 22px;
    }

    .flip-card {
      position: relative;
      /* Sized to the tallest BACK face at the narrowest column the 4-up grid
         produces (264px), where the six bullets wrap the most. Measured, not
         guessed - at 438px three of the four backs overflowed by 25px. Re-check
         this if a card gains a bullet or the copy gets longer. */
      min-height: 412px;
      perspective: 1400px;
    }

    .flip-inner {
      position: absolute;
      inset: 0;
      transform-style: preserve-3d;
      transition: transform 680ms cubic-bezier(0.2, 0.7, 0.2, 1);
    }

    .flip-card.is-flipped .flip-inner { transform: rotateY(180deg); }

    /* Fine pointer: the whole card is the trigger, so there is nothing to press
       and leaving flips it back. :focus-within is the keyboard equivalent — JS
       makes the card itself focusable in this mode so Tab can reach it. The
       Back control is dead weight here, and the front's label stops being
       clickable because hovering has already done its job. */
    @media (hover: hover) and (pointer: fine) {
      .flip-card:hover .flip-inner,
      .flip-card:focus-within .flip-inner { transform: rotateY(180deg); }

      .flip-card:focus-visible {
        outline: 2px solid var(--purple-700);
        outline-offset: 4px;
        border-radius: 24px;
      }

      .flip-btn--back { display: none; }
      .flip-front .flip-btn { pointer-events: none; }
    }

    .flip-face {
      position: absolute;
      inset: 0;
      display: flex;
      flex-direction: column;
      padding: 30px 26px;
      border: 1px solid var(--line);
      border-radius: 24px;
      background: #ffffff;
      box-shadow: 0 2px 3px rgba(20, 20, 20, 0.05);
      backface-visibility: hidden;
      -webkit-backface-visibility: hidden;
    }

    /* backface-visibility hides the reverse side visually but leaves it
       focusable and readable by screen readers. The `inert` attribute is what
       removes it, toggled in JS - deliberately not `visibility`, because a
       transition delay on visibility means focus() lands on a still-hidden
       element and silently fails whenever the tab is throttled. */
    .flip-back { transform: rotateY(180deg); }

    .flip-icon {
      display: inline-flex;
      align-items: center;
      justify-content: center;
      width: 46px;
      height: 46px;
      margin-bottom: 20px;
      border-radius: 12px;
      background: var(--purple-50);
      color: var(--purple-700);
    }

    .flip-icon svg { width: 23px; height: 23px; }

    .flip-face h3 {
      font-size: 20px;
      font-weight: 700;
      letter-spacing: -0.01em;
      color: var(--purple-950);
      margin-bottom: 12px;
    }

    .flip-front p {
      font-size: 15px;
      line-height: 1.62;
      color: var(--gray-500);
    }

    /* Pins the affordance to the bottom of the front face regardless of how
       long the blurb runs, so all four read as one row. */
    .flip-front .flip-btn { margin-top: auto; }

    .flip-btn {
      align-self: flex-start;
      padding: 0;
      border: 0;
      background: none;
      font: inherit;
      font-size: 14.5px;
      font-weight: 600;
      color: var(--purple-700);
      cursor: pointer;
      transition: color 160ms ease;
    }

    .flip-btn:hover { color: var(--purple-900); }
    .flip-btn:focus-visible,
    .flip-cta:focus-visible,
    .carousel-btn:focus-visible {
      outline: 2px solid var(--purple-700);
      outline-offset: 3px;
      border-radius: 4px;
    }

    .flip-list {
      list-style: none;
      margin: 2px 0 0;
      padding: 0;
      display: flex;
      flex-direction: column;
      gap: 9px;
    }

    .flip-list li {
      position: relative;
      padding-left: 17px;
      font-size: 14.5px;
      line-height: 1.5;
      color: var(--gray-600);
    }

    .flip-list li::before {
      content: "";
      position: absolute;
      top: 0.58em;
      left: 0;
      width: 5px;
      height: 5px;
      border-radius: 50%;
      background: var(--purple-400);
    }

    .flip-actions {
      margin-top: auto;
      padding-top: 20px;
      display: flex;
      flex-direction: column;
      gap: 12px;
      align-items: stretch;
    }

    .flip-cta {
      display: inline-flex;
      align-items: center;
      justify-content: center;
      gap: 7px;
      padding: 11px 18px;
      border-radius: 10px;
      background: var(--purple-900);
      color: #ffffff;
      font-size: 14.5px;
      font-weight: 600;
      text-decoration: none;
      transition: background 160ms ease;
    }

    .flip-cta:hover { background: var(--purple-800); }
    .flip-btn--back { font-size: 13.5px; color: var(--gray-500); }
    .flip-btn--back:hover { color: var(--purple-700); }

    /* ═══ EXAMPLES — scroll-snap carousel ═══════════════════════════════════
       Native overflow does the scrolling; the buttons only nudge scrollLeft.
       That keeps touch, trackpad, and keyboard behaviour for free. */
    .carousel {
      max-width: 1120px;
      margin: 0 auto;
    }

    .carousel-track {
      display: flex;
      gap: 22px;
      overflow-x: auto;
      scroll-snap-type: x mandatory;
      scroll-padding: 0 2px;
      padding: 4px 2px 20px;
      -webkit-overflow-scrolling: touch;
      scrollbar-width: thin;
      scrollbar-color: var(--purple-200) transparent;
    }

    .carousel-track:focus-visible {
      outline: 2px solid var(--purple-700);
      outline-offset: 4px;
      border-radius: 12px;
    }

    .ex-card {
      flex: 0 0 clamp(270px, 30%, 350px);
      scroll-snap-align: start;
      display: flex;
      flex-direction: column;
      padding: 28px 26px;
      border: 1px solid var(--line);
      border-radius: 24px;
      background: #ffffff;
      box-shadow: 0 2px 3px rgba(20, 20, 20, 0.05);
    }

    .ex-cat {
      display: inline-block;
      align-self: flex-start;
      margin-bottom: 14px;
      padding: 5px 11px;
      border-radius: 999px;
      background: var(--purple-50);
      color: var(--purple-700);
      font-size: 11.5px;
      font-weight: 700;
      letter-spacing: 0.04em;
      text-transform: uppercase;
    }

    .ex-title {
      font-size: 18.5px;
      font-weight: 700;
      letter-spacing: -0.01em;
      color: var(--purple-950);
      margin-bottom: 11px;
    }

    .ex-body {
      font-size: 14.5px;
      line-height: 1.65;
      color: var(--gray-500);
    }

    .ex-tags {
      margin-top: auto;
      padding-top: 20px;
      display: flex;
      flex-wrap: wrap;
      gap: 7px;
    }

    .ex-tags span {
      padding: 4px 10px;
      border: 1px solid var(--line);
      border-radius: 7px;
      font-size: 12px;
      font-weight: 500;
      color: var(--gray-500);
    }

    .carousel-nav {
      display: flex;
      justify-content: flex-end;
      gap: 10px;
      margin-top: 6px;
    }

    .carousel-btn {
      width: 42px;
      height: 42px;
      border: 1px solid var(--purple-200);
      border-radius: 50%;
      background: #ffffff;
      color: var(--purple-700);
      font-size: 16px;
      line-height: 1;
      cursor: pointer;
      transition: background 160ms ease, border-color 160ms ease;
    }

    .carousel-btn:hover {
      background: var(--purple-50);
      border-color: var(--purple-400);
    }

    /* ─── Responsive ─── */
    @media (max-width: 1100px) {
      .flip-grid { grid-template-columns: repeat(2, 1fr); max-width: 760px; }
    }

    @media (max-width: 768px) {
      .ex-card { flex-basis: 82%; }
    }

    /* Below this the first line cannot fit at any readable size, so the
       nowrap is released and the headline is allowed its natural three lines. */
    @media (max-width: 600px) {
      .hero-headline .headline-line1 { white-space: normal; }
    }

    @media (max-width: 640px) {
      .flip-grid { grid-template-columns: 1fr; max-width: 460px; }
      /* Back needs 368px at a 343px card; 392 leaves headroom. */
      .flip-card { min-height: 392px; }
      .ex-card { flex-basis: 88%; }
      .carousel-nav { justify-content: center; }
    }

    /* No 3D rotation when motion is unwanted: the faces cross-fade in place and
       every other behaviour (focus move, Escape, aria-expanded) is unchanged. */
    @media (prefers-reduced-motion: reduce) {
      .flip-inner { transition: none; }
      .flip-card.is-flipped .flip-inner { transform: none; }
      /* With no rotation, both faces point at the viewer and the back would
         paint over the front, so opacity does the hiding here instead. */
      .flip-back { transform: none; opacity: 0; }
      .flip-card.is-flipped .flip-front { opacity: 0; }
      .flip-card.is-flipped .flip-back  { opacity: 1; }
      .carousel-track { scroll-behavior: auto; }
    }
