/* ==========================================================================
   Marketing Wala — site.css (v5)

   Direction: high-contrast dark/light rhythm with real depth.
   - The page alternates dark and light sections so each boundary lands.
   - Dark surfaces carry an animated mesh gradient and a faint grid, so they
     read as lit space rather than a flat black rectangle.
   - Cards tilt in 3D toward the cursor; the hero visual is scroll-linked.
   - Inter Tight tightly tracked, JetBrains Mono for labels and figures.

   Master scale is one line: `html { font-size: 120% }`.
   ========================================================================== */

html { font-size: 120%; }

/* ---------- 1. Tokens ---------------------------------------------------- */

:root {
  /* Light surfaces */
  --bg:        #FFFFFF;
  --bg-2:      #F7F7F9;
  --bg-3:      #EFEFF3;

  /* Dark surfaces */
  --d-bg:      #08080B;
  --d-bg-2:    #101017;
  --d-line:    rgba(255, 255, 255, 0.11);
  --d-line-2:  rgba(255, 255, 255, 0.2);

  /* Text */
  --ink:       #09090B;
  --ink-2:     #52525B;
  --ink-3:     #82828C;
  --d-ink:     rgba(255, 255, 255, 0.72);
  --d-ink-2:   rgba(255, 255, 255, 0.56);

  --line:      #E6E6EA;
  --line-2:    #D8D8DE;

  /* Brand — sampled from the logo, plus a lifted tint that survives on black */
  --brand:      #603090;
  --brand-2:    #7B45B0;
  --brand-3:    #9A6BD4;
  --brand-lit:  #B78BF0;
  --brand-wash: rgba(96, 48, 144, 0.07);

  --ok: #17795E;
  --ok-lit: #4ADE9E;

  --sans: "Inter Tight", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;

  --t-mono: 0.688rem;
  --t-xs:   0.75rem;
  --t-sm:   0.8125rem;
  --t-base: 0.9375rem;
  --t-md:   1rem;
  --t-lg:   1.125rem;
  --t-xl:   clamp(1.25rem, 1.15rem + 0.4vw, 1.5rem);
  --t-2xl:  clamp(1.5rem, 1.3rem + 0.85vw, 2rem);
  --t-3xl:  clamp(1.7rem, 1.42rem + 1.2vw, 2.5rem);
  --t-4xl:  clamp(1.95rem, 1.5rem + 2vw, 3rem);

  --s-1: 0.25rem; --s-2: 0.5rem;  --s-3: 0.75rem; --s-4: 1rem;
  --s-5: 1.25rem; --s-6: 1.5rem;  --s-7: 2rem;    --s-8: 2.75rem;
  --section: clamp(2.25rem, 1.5rem + 2.2vw, 3.25rem);

  --gutter: clamp(1.15rem, 0.5rem + 3.2vw, 4.5rem);
  --wrap: 1090px;
  --wrap-narrow: 720px;

  --r-sm: 6px; --r: 10px; --r-lg: 14px; --r-xl: 22px;

  --shadow-sm: 0 1px 2px rgba(9, 9, 11, 0.05);
  --shadow:    0 1px 2px rgba(9, 9, 11, 0.05), 0 8px 24px -8px rgba(9, 9, 11, 0.12);
  --shadow-lg: 0 1px 2px rgba(9, 9, 11, 0.05), 0 24px 56px -16px rgba(9, 9, 11, 0.18);
  --glow:      0 0 0 1px rgba(154, 107, 212, 0.3), 0 18px 60px -12px rgba(122, 66, 190, 0.45);

  --ease: cubic-bezier(0.22, 0.61, 0.36, 1);
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);

  --nav-h: 3.6rem;
}

/* ---------- 2. Base ------------------------------------------------------ */

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--nav-h) + 0.5rem);
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--sans);
  font-size: var(--t-base);
  line-height: 1.6;
  letter-spacing: -0.006em;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;
}

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

h1, h2, h3, h4 {
  margin: 0; font-weight: 600; letter-spacing: -0.032em; line-height: 1.1;
  color: var(--ink); text-wrap: balance;
}
p { margin: 0; text-wrap: pretty; }
a { color: inherit; }
button, input, select, textarea { font: inherit; color: inherit; }

/* Grid and flex children default to min-width:auto, which lets long text and
   wide inputs push past the viewport. This is the single most common cause of
   horizontal overflow on phones. */
input, select, textarea { min-width: 0; max-width: 100%; }

:focus-visible { outline: 2px solid var(--brand-3); outline-offset: 2px; border-radius: 3px; }
::selection { background: var(--brand); color: #fff; }

/* ---------- 3. Sections & contrast rhythm --------------------------------- */

.wrap { width: min(var(--wrap), 100% - var(--gutter) * 2); margin-inline: auto; position: relative; z-index: 1; }
.wrap--narrow { width: min(var(--wrap-narrow), 100% - var(--gutter) * 2); }

.section { padding-block: var(--section); position: relative; }
.section--tint { background: var(--bg-2); }
.section--roomy { padding-block: clamp(3rem, 2rem + 3vw, 4.5rem); }

/* Dark sections. The page alternates so every boundary is a real change of
   ground rather than a slightly different grey. */
.sec--dark {
  background: var(--d-bg);
  color: var(--d-ink);
  position: relative;
  isolation: isolate;
  overflow: hidden;
}
.sec--dark h1, .sec--dark h2, .sec--dark h3 { color: #fff; }
.sec--dark .lede { color: var(--d-ink-2); }
.sec--dark .label { color: var(--brand-lit); }
.sec--dark .tlink { color: var(--brand-lit); }

/* A lit edge where a dark section meets a light one */
.sec--dark::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 1px;
  background: linear-gradient(90deg, transparent, rgba(154, 107, 212, 0.55), transparent);
  z-index: 3;
}

/* ---------- 4. Atmosphere: mesh, grid, glow ------------------------------- */

/* Animated mesh gradient. Several soft radial fields drifting on long, offset
   loops — built from gradients rather than blurred boxes so there is no
   large-surface blur for the compositor to chew on every frame. */
.mesh { position: absolute; inset: -20% -10%; z-index: 0; pointer-events: none; }
.mesh i {
  position: absolute; border-radius: 50%;
  width: clamp(360px, 46vw, 760px); aspect-ratio: 1;
  will-change: transform;
}
.mesh i:nth-child(1) { top: -6%;  right: 2%;  background: radial-gradient(circle, rgba(123, 69, 176, 0.55), transparent 62%); }
.mesh i:nth-child(2) { top: 26%;  left: -8%;  background: radial-gradient(circle, rgba(74, 33, 122, 0.6), transparent 64%); }
.mesh i:nth-child(3) { bottom: -18%; right: 26%; background: radial-gradient(circle, rgba(154, 107, 212, 0.34), transparent 66%); }
.mesh i:nth-child(4) { bottom: 4%; left: 24%;  background: radial-gradient(circle, rgba(38, 92, 168, 0.3), transparent 66%); }

@media (prefers-reduced-motion: no-preference) {
  .mesh i:nth-child(1) { animation: mesh-a 24s ease-in-out infinite alternate; }
  .mesh i:nth-child(2) { animation: mesh-b 30s ease-in-out infinite alternate; }
  .mesh i:nth-child(3) { animation: mesh-c 27s ease-in-out infinite alternate; }
  .mesh i:nth-child(4) { animation: mesh-d 33s ease-in-out infinite alternate; }
}
@keyframes mesh-a { from { transform: translate3d(0,0,0) scale(1); }    to { transform: translate3d(-8%, 10%, 0) scale(1.15); } }
@keyframes mesh-b { from { transform: translate3d(0,0,0) scale(1.1); }  to { transform: translate3d(10%, -8%, 0) scale(1); } }
@keyframes mesh-c { from { transform: translate3d(0,0,0) scale(1); }    to { transform: translate3d(-11%, -7%, 0) scale(1.18); } }
@keyframes mesh-d { from { transform: translate3d(0,0,0) scale(1.05); } to { transform: translate3d(7%, 6%, 0) scale(1); } }

/* Faint engineering grid over dark ground, fading out downward */
.grid-bg {
  position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background-image:
    linear-gradient(rgba(255,255,255,.055) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255,255,255,.055) 1px, transparent 1px);
  background-size: 64px 64px;
  mask-image: radial-gradient(ellipse 90% 70% at 50% 0%, #000 30%, transparent 78%);
  -webkit-mask-image: radial-gradient(ellipse 90% 70% at 50% 0%, #000 30%, transparent 78%);
}

/* ---------- 5. Headings --------------------------------------------------- */

.label {
  display: inline-flex; align-items: center; gap: 0.5em;
  font-family: var(--mono); font-size: var(--t-mono); font-weight: 500;
  letter-spacing: 0.08em; text-transform: uppercase; color: var(--brand);
  margin-bottom: var(--s-3);
}
.label::before { content: ""; width: 14px; height: 1px; background: currentColor; opacity: 0.55; }

.head { max-width: 46ch; margin-bottom: var(--s-5); }
.head-row { display: flex; align-items: flex-end; justify-content: space-between; gap: var(--s-5); flex-wrap: wrap; margin-bottom: var(--s-5); }
.head-row .head { margin-bottom: 0; }

.h2 { font-size: var(--t-3xl); }
.h3 { font-size: var(--t-xl); }

.lede {
  font-size: var(--t-md); color: var(--ink-2); line-height: 1.55;
  margin-top: var(--s-3); max-width: 58ch; letter-spacing: -0.008em;
}

/* ---------- 6. Buttons ---------------------------------------------------- */

.btn {
  position: relative; isolation: isolate; overflow: hidden;
  display: inline-flex; align-items: center; justify-content: center; gap: 0.45em;
  height: 2.5rem; padding-inline: 1.1rem;
  border: 1px solid transparent; border-radius: var(--r-sm);
  background: var(--ink); color: #fff;
  font-size: var(--t-sm); font-weight: 500; letter-spacing: -0.008em;
  text-decoration: none; white-space: nowrap; cursor: pointer;
  transition: transform 0.22s var(--ease), box-shadow 0.3s var(--ease), border-color 0.2s var(--ease);
}
/* Light sweeps across on hover */
.btn::after {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background: linear-gradient(105deg, transparent 30%, rgba(255,255,255,.28) 50%, transparent 70%);
  transform: translateX(-120%);
  transition: transform 0.75s var(--ease-out);
}
.btn:hover::after { transform: translateX(120%); }
.btn:hover { transform: translateY(-2px); }
.btn:active { transform: translateY(0); }
.btn__arrow { transition: transform 0.25s var(--ease-out); flex: none; }
.btn:hover .btn__arrow { transform: translateX(3px); }

/* Primary: living gradient + glow */
.btn--brand {
  background: linear-gradient(120deg, var(--brand) 0%, var(--brand-2) 45%, var(--brand-3) 100%);
  background-size: 200% 100%;
  box-shadow: 0 6px 22px -8px rgba(122, 66, 190, 0.75);
  transition: transform 0.22s var(--ease), box-shadow 0.3s var(--ease), background-position 0.6s var(--ease);
}
.btn--brand:hover {
  background-position: 100% 0;
  box-shadow: 0 12px 34px -10px rgba(122, 66, 190, 0.95);
}

.btn--ghost { background: var(--bg); color: var(--ink); border-color: var(--line-2); }
.btn--ghost:hover { background: var(--bg-2); border-color: var(--ink-3); }

/* Any button placed on dark ground gets dark-appropriate contrast
   automatically. Previously a .btn--ghost (near-black text, pale border) or a
   default .btn (near-black fill) sat on the dark hero effectively invisible
   until hovered — scoping it here means that can't happen again wherever a
   button is dropped. */
.hero .btn--ghost, .sec--dark .btn--ghost {
  background: rgba(255, 255, 255, 0.07);
  color: #fff;
  border-color: rgba(255, 255, 255, 0.3);
}
.hero .btn--ghost:hover, .sec--dark .btn--ghost:hover {
  background: rgba(255, 255, 255, 0.15);
  border-color: rgba(255, 255, 255, 0.5);
}
.hero .btn:not(.btn--brand):not(.btn--ghost):not(.btn--onDark),
.sec--dark .btn:not(.btn--brand):not(.btn--ghost):not(.btn--onDark) {
  background: #fff; color: var(--ink);
}
.nav .btn:not(.btn--brand) { background: #fff; color: var(--ink); }

.btn--onDark { background: #fff; color: var(--ink); }
.btn--onDark:hover { box-shadow: 0 10px 30px -10px rgba(255,255,255,.4); }

.btn--ghostDark { background: rgba(255,255,255,.06); color: #fff; border-color: var(--d-line-2); }
.btn--ghostDark:hover { background: rgba(255,255,255,.12); }

.btn--lg { height: 2.9rem; padding-inline: 1.4rem; font-size: var(--t-base); }
.btn--block { width: 100%; }

.btn-row { display: flex; flex-wrap: wrap; gap: var(--s-3); align-items: center; }

.tlink { display: inline-flex; align-items: center; gap: 0.35em; font-size: var(--t-sm); font-weight: 500; color: var(--brand); text-decoration: none; }
.tlink:hover { text-decoration: underline; text-underline-offset: 3px; }

/* ---------- 7. Reveal & motion -------------------------------------------- */

.js [data-reveal] {
  opacity: 0; transform: translateY(26px) scale(0.985);
  transition: opacity 0.7s var(--ease-out) var(--d, 0s), transform 0.7s var(--ease-out) var(--d, 0s);
}
.js [data-reveal].is-in { opacity: 1; transform: none; }
.js [data-reveal="fade"] { transform: none; }

.js [data-stagger] > * {
  opacity: 0; transform: translateY(22px);
  transition: opacity 0.6s var(--ease-out), transform 0.6s var(--ease-out);
}
.js [data-stagger].is-in > * { opacity: 1; transform: none; }
.js [data-stagger].is-in > *:nth-child(1) { transition-delay: 0.02s; }
.js [data-stagger].is-in > *:nth-child(2) { transition-delay: 0.08s; }
.js [data-stagger].is-in > *:nth-child(3) { transition-delay: 0.14s; }
.js [data-stagger].is-in > *:nth-child(4) { transition-delay: 0.2s; }
.js [data-stagger].is-in > *:nth-child(5) { transition-delay: 0.26s; }
.js [data-stagger].is-in > *:nth-child(6) { transition-delay: 0.32s; }
.js [data-stagger].is-in > *:nth-child(7) { transition-delay: 0.38s; }
.js [data-stagger].is-in > *:nth-child(8) { transition-delay: 0.44s; }

/* 3D tilt. --rx/--ry are written by the pointer handler; --p is scroll
   progress through the viewport, written by the scroll handler. */
.tilt {
  transform:
    perspective(1100px)
    rotateX(calc(var(--rx, 0deg) + var(--rx-base, 0deg)))
    rotateY(calc(var(--ry, 0deg) + var(--ry-base, 0deg)))
    translate3d(0, var(--py, 0px), 0);
  transform-style: preserve-3d;
  transition: transform 0.5s var(--ease-out);
}
.tilt.is-tracking { transition: transform 0.12s linear; }

html.no-anim *, html.no-anim *::before, html.no-anim *::after {
  transition-duration: 0.001ms !important; animation-duration: 0.001ms !important;
  transition-delay: 0s !important; animation-delay: 0s !important;
}
html.no-anim [data-reveal], html.no-anim [data-stagger] > * { opacity: 1 !important; transform: none !important; }
html.no-anim .faq__a { display: block !important; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .js [data-reveal], .js [data-stagger] > * { opacity: 1 !important; transform: none !important; }
  .tilt { transform: none !important; }
  *, *::before, *::after {
    animation-duration: 0.001ms !important; animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important; transition-delay: 0s !important; animation-delay: 0s !important;
  }
}

/* ---------- 8. Nav -------------------------------------------------------- */

/* Fully transparent while sitting on the hero — a translucent bar over a dark
   section just reads as a grey stripe. The blur and fill only arrive once the
   page has scrolled and the nav actually needs to separate from content. */
/* Fixed, not sticky. A sticky nav stays in normal flow, so it occupies a band
   ABOVE the hero rather than sitting over it — and a transparent background
   there reveals the white <body>, not the dark hero. The hero pays for the
   overlap with matching top padding; html already carries scroll-padding-top
   so anchor targets don't land underneath. */
.nav {
  position: fixed; top: 0; left: 0; right: 0; z-index: 100;
  background: transparent;
  border-bottom: 1px solid transparent;
  transition: border-color .3s var(--ease);
}
/* The scrolled bar's tint and blur live on a pseudo-element, NOT on .nav.
   An element carrying backdrop-filter becomes the containing block for its
   position:fixed descendants — and .nav__scrim and .nav__links are both fixed
   children of .nav. With the filter on .nav itself, the moment the page
   scrolled and .is-stuck applied, the drawer stopped resolving against the
   viewport and collapsed into the 64px bar: the sidebar opened clipped and the
   scrim only covered the header. At scroll-top there was no filter, so it
   looked correct — which is why this only ever reproduced part-way down a page.
   ::before is a sibling box, not an ancestor, so the effect is pixel-identical
   while the drawer and scrim stay anchored to the viewport at any scroll depth. */
.nav::before {
  content: ""; position: absolute; inset: 0; z-index: -2;
  background: rgba(8, 8, 11, 0.86);
  opacity: 0; pointer-events: none;
  transition: opacity .3s var(--ease);
}
.nav.is-stuck::before {
  opacity: 1;
  backdrop-filter: blur(14px) saturate(1.5);
  -webkit-backdrop-filter: blur(14px) saturate(1.5);
}
.nav.is-stuck {
  border-bottom-color: var(--d-line);
}

.nav__inner { display: flex; align-items: center; justify-content: space-between; gap: var(--s-5); height: var(--nav-h); }

.brand { display: inline-flex; align-items: center; gap: 0.5rem; text-decoration: none; flex: none; }
.brand img { width: 1.6rem; height: 1.6rem; object-fit: contain; }
.brand__name { font-size: var(--t-base); font-weight: 600; letter-spacing: -0.028em; color: #fff; }

.nav__links { display: flex; align-items: center; gap: clamp(0.9rem, 0.3rem + 1.2vw, 1.6rem); list-style: none; margin: 0; padding: 0; }
/* Nav links sit on the near-black hero, so muted --d-ink-2 (56% white) read as
   dull grey rather than as restraint. 84% keeps the hierarchy below the brand
   mark while still looking lit; the underline carries the hover state so the
   colour shift no longer has to do that job on its own. */
.nav__links a {
  position: relative; text-decoration: none;
  font-size: var(--t-sm); font-weight: 480; letter-spacing: -0.012em;
  color: rgba(255, 255, 255, 0.84);
  transition: color .18s var(--ease);
}
.nav__links a::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: -0.42rem; height: 1.5px;
  background: linear-gradient(90deg, var(--brand-3), var(--brand-lit));
  border-radius: 2px;
  transform: scaleX(0); transform-origin: left;
  transition: transform .28s var(--ease-out);
}
.nav__links a:hover { color: #fff; }
.nav__links a:hover::after, .nav__links a:focus-visible::after { transform: scaleX(1); }
/* Inner pages mark their own nav entry. The underline is already the hover
   affordance, so holding it open costs no new vocabulary. */
.nav__links a[aria-current="page"] { color: #fff; }
.nav__links a[aria-current="page"]::after { transform: scaleX(1); }

.nav__cta { display: flex; align-items: center; gap: var(--s-3); flex: none; }

/* No visible box. The button keeps a 44px touch target (the accessibility
   minimum) but the bars themselves are 17px, so it reads as an icon rather than
   as a bordered widget sitting in the corner. */
.nav__toggle {
  /* Column flex, NOT grid. Grid gives each bar its own auto row, and
     align-content defaults to stretch — the rows expand to fill the button and
     push the bars ~17px apart, far enough that the X arms never meet. Flex
     items keep their natural height, so the pitch stays 1.5px + 4px margin. */
  display: none; width: 2.5rem; height: 2.5rem;
  margin-right: -0.55rem;
  border: 0; background: transparent;
  border-radius: var(--r-sm); cursor: pointer; padding: 0;
  flex-direction: column; align-items: center; justify-content: center;
  -webkit-tap-highlight-color: transparent;
}
.nav__toggle span {
  display: block; width: 16px; height: 1.5px; border-radius: 2px; background: #fff;
  transition: transform .34s var(--ease-out), opacity .18s var(--ease);
}
.nav__toggle span + span { margin-top: 4px; }
.nav__toggle[aria-expanded="true"] span:nth-child(1) { transform: translateY(5.5px) rotate(45deg); }
.nav__toggle[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
.nav__toggle[aria-expanded="true"] span:nth-child(3) { transform: translateY(-5.5px) rotate(-45deg); }

/* Dims the page behind the drawer and gives a tap-anywhere-to-close target.
   z-index -1 puts it at the bottom of the nav's own stacking context, so it
   sits under the bar and the drawer but still above every page section. */
.nav__scrim {
  position: fixed; inset: 0; z-index: -1;
  background: rgba(4, 4, 8, 0.62);
  backdrop-filter: blur(2px); -webkit-backdrop-filter: blur(2px);
  opacity: 0; visibility: hidden;
  transition: opacity .35s var(--ease), visibility .35s;
}
.nav.is-menu-open .nav__scrim { opacity: 1; visibility: visible; }
@media (min-width: 881px) { .nav__scrim { display: none; } }

.progress {
  position: absolute; left: 0; bottom: -1px; height: 2px; width: 100%;
  transform: scaleX(0); transform-origin: left; z-index: 2;
  background: linear-gradient(90deg, var(--brand-2), var(--brand-lit));
  box-shadow: 0 0 12px rgba(183, 139, 240, 0.8);
}

/* Hidden by class, not by :last-child. The horizontal bar has its own CTA, so
   the drawer's copies must not appear on desktop — and keying that to
   :last-child broke the moment a second drawer-only item was added, letting the
   duplicate "Start a project" back into the header. */
@media (min-width: 881px) { .nav__drawer-only { display: none; } }

@media (max-width: 880px) {
  .nav__toggle { display: flex; }
  .nav__cta > .btn { display: none; }
  /* Side drawer, not a dropdown: full height off the right edge, so it reads as
     a panel the page slides under rather than a menu unrolling over the hero.
     Top padding clears the fixed bar, which stays above it and keeps the X tappable. */
  .nav__links {
    position: fixed; top: 0; right: 0; bottom: 0; left: auto;
    width: min(80vw, 19rem);
    flex-direction: column; align-items: stretch; justify-content: flex-start; gap: 0;
    background: var(--d-bg-2);
    border-left: 1px solid var(--d-line);
    box-shadow: -34px 0 70px -24px rgba(0, 0, 0, 0.7);
    padding: calc(var(--nav-h) + var(--s-2)) var(--s-5) var(--s-5);
    transform: translateX(100%); visibility: hidden;
    transition: transform .42s var(--ease-out), visibility .42s;
    overflow-y: auto; overscroll-behavior: contain;
  }
  .nav__links.is-open { transform: none; visibility: visible; }
  .nav__links li { border-bottom: 1px solid var(--d-line); }
  /* No margin-top:auto. Pinning the CTA to the floor of a panel holding only
     five links leaves a dead void down the middle; it sits under the list. */
  .nav__links li:last-child { border-bottom: 0; }
  .nav__links .nav__drawer-only { border-bottom: 0; padding-top: var(--s-5); }
  /* Scoped to the plain nav rows, not to every anchor with exceptions carved
     out. Styling all anchors and excluding with :not() pushed this rule to
     (0,2,1) — above both the CTA and the contact rows — so it silently forced
     them to display:block, voiding the flex centring each of them depends on.
     Matching only the rows it actually means keeps it out of their way. */
  .nav__links li:not(.nav__drawer-only) a { display: block; padding: 0.58rem 0; font-size: var(--t-base); color: #fff; }
  .nav__links .btn { height: 2.6rem; font-size: var(--t-base); }

  /* Anchored to the floor of the panel, with a rule above it so the space
     between reads as a deliberate footer zone rather than a layout accident —
     bottom-anchored without the divider just looked like a gap. UK/US enquiries
     come by email far more than by phone, so the address gets the lead slot. */
  .nav__reach {
    display: grid; gap: 0.15rem;
    margin-top: auto; padding-top: var(--s-4);
    border-top: 1px solid var(--d-line);
  }
  /* min-height, not padding alone: these were 36px tall and every touch target
     has to clear 44px. Icons carry the meaning that a written label was doing
     badly — an envelope and the WhatsApp mark need no heading above them. */
  .nav__reach a {
    display: flex; align-items: center; gap: 0.6rem;
    min-height: 44px; padding: 0.2rem 0;
    font-size: var(--t-sm); color: var(--d-ink);
  }
  .nav__reach svg { flex: none; opacity: .7; }
  .nav__reach a:first-of-type { color: var(--brand-lit); }
  .nav__reach a:first-of-type svg { opacity: 1; }
  /* The underline indicator belongs to the horizontal bar; in a stacked drawer
     it would sit across the row below it. */
  .nav__links a::after { content: none; }

  /* Links stagger in behind the panel so the drawer has some life to it. */
  .nav__links.is-open li {
    animation: drawerIn .4s var(--ease-out) both;
    animation-delay: calc(0.1s + var(--n, 0) * 0.045s);
  }
  @keyframes drawerIn {
    from { opacity: 0; transform: translateX(14px); }
    to   { opacity: 1; transform: none; }
  }
}

/* ---------- 9. Hero ------------------------------------------------------- */

.hero {
  position: relative; isolation: isolate; overflow: hidden;
  background: var(--d-bg); color: var(--d-ink);
  padding-block: calc(var(--nav-h) + clamp(2.25rem, 1.2rem + 3.4vw, 4rem)) clamp(2.5rem, 1.5rem + 3vw, 4rem);
}
.hero h1 { color: #fff; font-size: var(--t-4xl); letter-spacing: -0.04em; line-height: 1.04; }
.hero h1 em {
  font-style: normal;
  background: linear-gradient(100deg, var(--brand-lit), #E9D9FF 55%, var(--brand-3));
  -webkit-background-clip: text; background-clip: text; color: transparent;
}

.hero__grid { display: grid; gap: clamp(1.5rem, 0.8rem + 2.6vw, 2.75rem); align-items: center; }
@media (min-width: 1000px) { .hero__grid { grid-template-columns: minmax(0, 0.88fr) minmax(0, 1.12fr); } }

.hero__pill {
  display: inline-flex; align-items: center; gap: 0.45rem;
  height: 1.7rem; padding-inline: 0.7rem;
  border: 1px solid var(--d-line-2); border-radius: 100px;
  background: rgba(255,255,255,.05);
  font-size: var(--t-xs); color: var(--d-ink); margin-bottom: var(--s-4);
}
.hero__pill b { color: #fff; font-weight: 550; }
.dot { width: 6px; height: 6px; border-radius: 50%; background: var(--ok-lit); flex: none; box-shadow: 0 0 10px var(--ok-lit); }

.hero__lede { font-size: var(--t-md); color: var(--d-ink-2); line-height: 1.55; margin-top: var(--s-4); max-width: 44ch; }
.hero__cta { margin-top: var(--s-5); }

.hero__meta {
  display: flex; flex-wrap: wrap; gap: 0.3rem 1rem; list-style: none;
  margin: var(--s-5) 0 0; padding: 0;
  font-family: var(--mono); font-size: var(--t-mono); letter-spacing: .02em; color: var(--d-ink-2);
}
.hero__meta li { display: flex; align-items: center; gap: 0.4rem; }
.hero__meta li::before { content: ""; width: 3px; height: 3px; border-radius: 50%; background: var(--brand-lit); flex: none; }

/* ---------- 10. Hero deck ------------------------------------------------- */

/* The hero visual is a stack of pages dropped into one shared 3D space. The
   deck is turned so its left edge sits nearer the reader and the right edge
   recedes; every card behind the front one steps back in Z (the perspective
   does the shrinking) with a small nudge up and right so its corner peeks out,
   plus a degree of rotation each so it reads as dropped by hand, not machined.

   Stack position is driven entirely by --i (0 = front). JS only rewrites that
   one number, so the load-in and the shuffle-on-advance are the same motion —
   there is no second animation that could drift out of sync with the first. */

/* Padding buys the room the deck grows into: cards step up and to the right, so
   the stage is pulled down and left by roughly the distance the backmost card
   travels, keeping it clear of the hero's right edge. */
.cycler { position: relative; padding: 9% 10% 0 0; perspective: 1600px; perspective-origin: 62% 42%; }

.cycler__stage {
  position: relative;
  aspect-ratio: 16 / 10;
  transform-style: preserve-3d;
  --rx-base: 6deg;
  --ry-base: 13deg;
}
/* Overrides .tilt deliberately: same rotation, minus its perspective() function.
   A second projection inside a preserve-3d parent flattens the children, which
   would collapse every card's translateZ back to zero and kill the depth. */
.cycler .cycler__stage.tilt {
  transform:
    rotateX(calc(var(--rx, 0deg) + var(--rx-base, 0deg)))
    rotateY(calc(var(--ry, 0deg) + var(--ry-base, 0deg)))
    translate3d(0, var(--py, 0px), 0);
}

/* --deal is registered so it can be animated as a number. That is the whole
   trick here: a normal @keyframes on `transform` would replace the stack
   transform outright and freeze every card at the front of the deck. Driving a
   variable instead lets the entrance and the stack position live in one
   transform and compose cleanly. Browsers without @property ignore the
   keyframes and the cards simply appear in place — no broken state. */
@property --deal {
  syntax: '<number>';
  initial-value: 0;
  inherits: false;
}

.cycler__slide {
  --i: 0;
  position: absolute; inset: 0;
  container-type: inline-size;
  z-index: calc(10 - var(--i));
  border: 1px solid rgba(255,255,255,.16);
  border-radius: var(--r-lg);
  overflow: hidden;
  background: #0C0C12;
  box-shadow: 0 40px 90px -30px rgba(0,0,0,.9), 0 0 0 1px rgba(255,255,255,.05);
  opacity: calc(1 - var(--deal));
  /* Offsets must beat the perspective shrink, and the shrink applies to them
     too — a step is projected at the card's own scale, so it buys less room the
     further back it sits. These clear the front card by ~100px right and ~55px
     top at i=3; halve them and the stack collapses into a single panel. */
  transform:
    translate3d(calc(var(--i) * 9%), calc(var(--i) * -8%), calc(var(--i) * -70px))
    rotate(calc(var(--i) * -1.5deg))
    translate3d(calc(var(--deal) * -7%), calc(var(--deal) * 58%), 0)
    rotate(calc(var(--deal) * 7deg))
    scale(calc(1 - var(--deal) * 0.1));
  transition: transform .85s cubic-bezier(.22, 1, .36, 1);
}

/* Depth shading. A tint overlay rather than filter: brightness() — a filter
   forces its element out of the parent's preserve-3d context, which would
   flatten the whole deck into paint order and undo the stacking above. */
.cycler__slide::after {
  content: ""; position: absolute; inset: 0; pointer-events: none; z-index: 5;
  background: linear-gradient(200deg, rgba(6,6,10,.18), rgba(6,6,10,.78));
  opacity: calc(var(--i) * 0.22);
  transition: opacity .85s var(--ease);
}

/* Cards deal in back-to-front, so the front page lands last and on top. */
@media (prefers-reduced-motion: no-preference) {
  .js .cycler__slide {
    animation: deal 1s cubic-bezier(.22, 1, .36, 1) both;
    animation-delay: calc(0.3s + (3 - var(--i)) * 0.13s);
  }
}
@keyframes deal {
  from { --deal: 1; }
  to   { --deal: 0; }
}

/* Optional image layer. Drop 01–04 into assets/img/hero/ and each card upgrades
   from the CSS mockup to the artwork with no markup change; if a file is absent
   the img removes itself on error and the mockup underneath stays visible. */
.cycler__img {
  position: absolute; inset: 0; z-index: 3;
  width: 100%; height: 100%; object-fit: cover; object-position: 50% 0;
}

@media (max-width: 720px) {
  .cycler { padding: 9% 12% 0 0; perspective: 1100px; }
  .cycler__stage { --rx-base: 4deg; --ry-base: 8deg; }
  .cycler__slide {
    transform:
      translate3d(calc(var(--i) * 8%), calc(var(--i) * -7%), calc(var(--i) * -45px))
      rotate(calc(var(--i) * -1deg))
      translate3d(calc(var(--deal) * -7%), calc(var(--deal) * 58%), 0)
      rotate(calc(var(--deal) * 7deg))
      scale(calc(1 - var(--deal) * 0.1));
  }
}

.cycler__tabs { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); margin-top: var(--s-4); border-top: 1px solid var(--d-line); }
.cycler__tab {
  position: relative; text-align: left; background: none; border: 0;
  border-top: 1.5px solid transparent; margin-top: -1px;
  padding: 0.6rem 0.5rem 0.6rem 0; cursor: pointer; color: var(--d-ink-2);
  transition: color .2s var(--ease), border-color .3s var(--ease);
}
.cycler__tab:hover { color: var(--d-ink); }
.cycler__tab[aria-selected="true"] { color: #fff; border-top-color: var(--brand-lit); }
.cycler__n { display: block; font-family: var(--mono); font-size: var(--t-mono); letter-spacing: .06em; color: var(--d-ink-2); margin-bottom: 0.15rem; }
.cycler__tab[aria-selected="true"] .cycler__n { color: var(--brand-lit); }
.cycler__t { display: block; font-size: var(--t-sm); font-weight: 500; letter-spacing: -0.012em; line-height: 1.25; }

@media (max-width: 620px) { .cycler__tabs { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0 var(--s-4); } }

/* ---------- 11. Marquee --------------------------------------------------- */

.marquee {
  position: relative; overflow: hidden;
  padding-block: var(--s-5);
  border-top: 1px solid var(--d-line);
  mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
}
.marquee__track { display: flex; width: max-content; gap: clamp(2rem, 4vw, 4rem); align-items: center; }
@media (prefers-reduced-motion: no-preference) {
  .marquee__track { animation: slide 36s linear infinite; }
  .marquee:hover .marquee__track { animation-play-state: paused; }
}
@keyframes slide { from { transform: translateX(0); } to { transform: translateX(-50%); } }
.marquee__item {
  display: flex; align-items: center; gap: 0.55rem; flex: none;
  color: rgba(255,255,255,.42); font-size: var(--t-sm); font-weight: 500; white-space: nowrap;
  transition: color .25s var(--ease);
}
.marquee__item:hover { color: #fff; }
.marquee__item svg { width: 1.05rem; height: 1.05rem; flex: none; }

/* ---------- 12. Services grid --------------------------------------------- */

.svc-grid {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 1px; background: var(--line);
  border: 1px solid var(--line); border-radius: var(--r-lg); overflow: hidden;
}
@media (max-width: 940px) { .svc-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 480px) { .svc-grid { grid-template-columns: 1fr; } }

.svc {
  display: block; background: var(--bg); padding: var(--s-4);
  text-decoration: none; position: relative; isolation: isolate;
  transition: background .2s var(--ease);
}
.svc:hover { background: var(--bg-2); }
.svc::after {
  content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none;
  background: radial-gradient(240px circle at var(--mx, 50%) var(--my, 50%), rgba(96, 48, 144, 0.1), transparent 70%);
  opacity: 0; transition: opacity .3s var(--ease);
}
.svc:hover::after { opacity: 1; }

.svc__n { font-family: var(--mono); font-size: var(--t-mono); letter-spacing: .06em; color: var(--ink-3); transition: color .2s var(--ease); }
.svc:hover .svc__n { color: var(--brand); }
.svc__ico {
  width: 1.9rem; height: 1.9rem; border-radius: var(--r-sm);
  background: var(--brand-wash); color: var(--brand);
  display: grid; place-items: center; margin: var(--s-3) 0 var(--s-2);
  transition: background .25s var(--ease), color .25s var(--ease), transform .35s var(--ease-out);
}
.svc__ico svg { width: 1rem; height: 1rem; }
.svc:hover .svc__ico { background: var(--brand); color: #fff; transform: translateY(-2px) scale(1.06); }
.svc__t { display: block; font-size: var(--t-base); font-weight: 550; letter-spacing: -0.02em; color: var(--ink); line-height: 1.25; }
.svc__d { display: block; font-size: var(--t-sm); color: var(--ink-2); line-height: 1.5; margin-top: 0.3rem; }
.svc__go {
  display: inline-flex; align-items: center; gap: 0.3rem; margin-top: var(--s-3);
  font-size: var(--t-xs); font-weight: 500; color: var(--brand);
  opacity: 0; transform: translateX(-4px);
  transition: opacity .2s var(--ease), transform .25s var(--ease-out);
}
.svc:hover .svc__go, .svc:focus-visible .svc__go { opacity: 1; transform: none; }
@media (hover: none) { .svc__go { opacity: 1; transform: none; } }

/* ---------- 13. Work ------------------------------------------------------ */

.work-filter { margin: 0 0 var(--s-5); }

.work-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--s-4); }
@media (max-width: 940px) { .work-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 620px) { .work-grid { grid-template-columns: 1fr; } }

.work-card {
  display: block; text-decoration: none;
  border: 1px solid var(--d-line); border-radius: var(--r-lg);
  background: var(--d-bg-2); overflow: hidden;
  transition: box-shadow .35s var(--ease), border-color .3s var(--ease);
}
.work-card:hover { border-color: rgba(154,107,212,.5); box-shadow: var(--glow); }

.shot { border-bottom: 1px solid var(--d-line); overflow: hidden; }
.shot__bar { display: flex; align-items: center; gap: 4px; padding: 0.4rem 0.55rem; background: rgba(255,255,255,.05); border-bottom: 1px solid var(--d-line); }
.shot__bar i { width: 6px; height: 6px; border-radius: 50%; background: rgba(255,255,255,.22); flex: none; }
.shot__url { margin-left: 0.4rem; min-width: 0; font-family: var(--mono); font-size: 0.6rem; color: var(--d-ink-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.shot img {
  width: 100%; aspect-ratio: 3 / 2; object-fit: cover; object-position: top center;
  display: block; background: var(--bg-3); transition: transform .55s var(--ease-out);
}
@media (min-width: 941px) { .work-card:hover .shot img { transform: scale(1.04); } }

.work-card__body { padding: var(--s-4); display: flex; align-items: flex-start; justify-content: space-between; gap: var(--s-3); }
.work-card__t { display: block; font-size: var(--t-base); font-weight: 600; letter-spacing: -0.024em; color: #fff; }
.work-card__m { display: block; font-family: var(--mono); font-size: var(--t-mono); color: var(--d-ink-2); margin-top: 0.25rem; letter-spacing: .03em; }
.work-card__go { flex: none; color: var(--d-ink-2); margin-top: 0.2rem; transition: color .2s var(--ease), transform .25s var(--ease-out); }
.work-card:hover .work-card__go { color: var(--brand-lit); transform: translate(2px, -2px); }

/* ---------- 14. Performance ----------------------------------------------- */

.perf { display: grid; gap: var(--s-6); align-items: center; }
@media (min-width: 900px) { .perf { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); } }

.perf-panel { border: 1px solid var(--line); border-radius: var(--r-lg); background: var(--bg); padding: var(--s-5); box-shadow: var(--shadow-sm); }

/* Core Web Vitals readout, shaped like the PageSpeed report a client already
   recognises. A dial gave one number twice — this shows the score plus the
   three metrics Google actually ranks on, which is different information from
   the comparison bars beside it instead of a restatement of them. Dark panel on
   a light section so it is the thing the eye lands on first. */
.psi {
  background: var(--d-bg-2);
  border-color: rgba(255, 255, 255, 0.1);
  color: var(--d-ink);
  box-shadow: 0 30px 70px -34px rgba(0, 0, 0, 0.6);
}
.psi__head { display: flex; align-items: center; justify-content: space-between; gap: var(--s-3); }
.psi__title { font-size: var(--t-sm); font-weight: 550; color: #fff; letter-spacing: -0.015em; }
.psi__chip {
  font-family: var(--mono); font-size: var(--t-mono); color: var(--d-ink-2);
  border: 1px solid var(--d-line-2); border-radius: 100px; padding: 0.14rem 0.6rem;
}

.psi__score { position: relative; width: 9.5rem; margin: var(--s-5) auto var(--s-5); }
.ring { display: block; width: 100%; height: auto; transform: rotate(-90deg); }
.ring__track { fill: none; stroke: rgba(255, 255, 255, 0.08); stroke-width: 9; }
/* r=52 → circumference 326.7. Offset 6.5 leaves 98% drawn. */
.ring__fill {
  fill: none; stroke: var(--ok-lit); stroke-width: 9; stroke-linecap: round;
  stroke-dasharray: 326.7; stroke-dashoffset: 326.7;
  filter: drop-shadow(0 0 9px rgba(74, 222, 158, 0.45));
  transition: stroke-dashoffset 1.7s var(--ease-out) .25s;
}
.perf-panel.is-in .ring__fill { stroke-dashoffset: 6.5; }

.psi__num { position: absolute; inset: 0; display: grid; place-content: center; text-align: center; margin: 0; }
.psi__num b { display: block; font-family: var(--mono); font-size: var(--t-3xl); font-weight: 500; color: #fff; letter-spacing: -0.045em; line-height: 1; }
.psi__num i { font-style: normal; font-family: var(--mono); font-size: var(--t-mono); color: var(--d-ink-2); }

.psi__list { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--s-4); }
.psi__row { display: grid; grid-template-columns: 2.6rem 4.4rem minmax(0, 1fr); align-items: center; gap: var(--s-3); }
.psi__k { font-family: var(--mono); font-size: var(--t-mono); letter-spacing: .07em; color: var(--d-ink-2); }
.psi__v { font-family: var(--mono); font-size: var(--t-sm); color: #fff; font-variant-numeric: tabular-nums; }
.psi__v i { font-style: normal; font-size: var(--t-mono); color: var(--d-ink-2); }

/* --g and --a are Google's good / needs-improvement boundaries for that metric,
   placed on the row so each meter carries its own real thresholds. */
.psi__meter {
  position: relative; display: block; height: 7px; border-radius: 100px;
  background: linear-gradient(90deg,
    #2FA57C 0 var(--g), #E8B84B var(--g) var(--a), #D96C5F var(--a) 100%);
  opacity: .5;
}
.psi__mark {
  position: absolute; top: 50%; left: 0; width: 3px; height: 16px; border-radius: 2px;
  background: #fff; box-shadow: 0 0 0 2.5px rgba(16, 16, 23, 0.9);
  transform: translate(-50%, -50%);
  transition: left 1.2s var(--ease-out) .45s;
}
.perf-panel.is-in .psi__mark { left: var(--pos); }

.psi__foot {
  margin: var(--s-5) 0 0; padding-top: var(--s-4);
  border-top: 1px solid var(--d-line);
  font-size: var(--t-xs); color: var(--d-ink-2); line-height: 1.5;
}

.race { display: grid; gap: var(--s-4); }
.race__row { display: grid; grid-template-columns: minmax(0, 14ch) minmax(0, 1fr) auto; align-items: center; gap: var(--s-4); }
@media (max-width: 560px) {
  .race__row { grid-template-columns: minmax(0,1fr) auto; }
  .race__label { grid-column: 1 / -1; margin-bottom: -0.3rem; }
}
.race__label { font-size: var(--t-sm); color: var(--ink-2); }
.race__track { display: block; height: 8px; border-radius: 100px; background: var(--bg-3); overflow: hidden; }
.race__bar { display: block; height: 100%; width: 0; border-radius: 100px; background: #D2D2DA; transition: width 1.1s var(--ease-out) var(--d, 0s); }
.race__row.is-in .race__bar { width: var(--w); }
.race__row--win .race__label { color: var(--ink); font-weight: 550; }
.race__row--win .race__bar { background: linear-gradient(90deg, var(--brand), var(--brand-3)); box-shadow: 0 0 16px rgba(122,66,190,.5); }
.race__time { font-family: var(--mono); font-size: var(--t-sm); color: var(--ink-2); font-variant-numeric: tabular-nums; min-width: 4ch; text-align: right; }
.race__row--win .race__time { color: var(--brand); font-weight: 500; }

.perf-foot { margin-top: var(--s-5); padding-top: var(--s-4); border-top: 1px solid var(--line); font-size: var(--t-xs); color: var(--ink-3); }

/* Names the turn in the argument: the bars show the gap, the panel shows the
   standard, and these three show what the gap costs. Without the label the
   stat cards read as trivia bolted to the bottom. */
.perf-bridge { margin-top: var(--s-7); padding-top: var(--s-5); border-top: 1px solid var(--line); }

.stat-cards { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--s-4); margin-top: var(--s-4); }
@media (max-width: 700px) { .stat-cards { grid-template-columns: 1fr; } }
.stat-card { border: 1px solid var(--line); border-radius: var(--r); padding: var(--s-4); background: var(--bg); }
.stat-card b { display: block; font-family: var(--mono); font-size: var(--t-xl); font-weight: 500; color: var(--brand); letter-spacing: -0.02em; }
.stat-card span { display: block; font-size: var(--t-sm); color: var(--ink-2); line-height: 1.45; margin-top: 0.3rem; }
.stat-card em { font-style: normal; color: var(--ink-3); }

/* ---------- 15. Pricing (on dark) ----------------------------------------- */

.cur { display: inline-flex; gap: 2px; padding: 2px; background: rgba(255,255,255,.07); border: 1px solid var(--d-line); border-radius: var(--r-sm); margin-top: var(--s-4); }
.cur button {
  border: 0; background: transparent; border-radius: 4px; padding: 0.3rem 0.7rem;
  font-family: var(--mono); font-size: var(--t-mono); letter-spacing: .04em;
  color: var(--d-ink-2); cursor: pointer; transition: background .2s var(--ease), color .2s var(--ease);
}
.cur button[aria-pressed="true"] { background: #fff; color: var(--ink); }

.tiers { display: grid; gap: var(--s-5); grid-template-columns: repeat(3, minmax(0, 1fr)); align-items: stretch; }
@media (max-width: 900px) { .tiers { grid-template-columns: 1fr; max-width: 26rem; margin-inline: auto; } }

.tier {
  position: relative;
  border: 1px solid var(--d-line); border-radius: var(--r-xl);
  /* Tall on purpose: generous top padding and roomy internal rhythm */
  padding: var(--s-8) var(--s-6) var(--s-6);
  background: linear-gradient(180deg, rgba(255,255,255,.05), rgba(255,255,255,.015));
  display: flex; flex-direction: column; gap: var(--s-5);
  transition: transform .45s var(--ease-out), box-shadow .4s var(--ease), border-color .3s var(--ease);
}
@media (min-width: 901px) {
  .tier:hover { transform: translateY(-8px); border-color: rgba(154,107,212,.55); box-shadow: var(--glow); }
}

/* Featured tier: lifted surface, gradient rim and a permanent glow so it is
   unmistakably the recommended one. */
.tier--pick {
  background: linear-gradient(180deg, rgba(123,69,176,.28), rgba(123,69,176,.06));
  border-color: transparent;
  box-shadow: var(--glow);
}
.tier--pick::before {
  content: ""; position: absolute; inset: 0; border-radius: inherit; padding: 1px;
  background: linear-gradient(150deg, var(--brand-lit), rgba(154,107,212,.25) 45%, rgba(255,255,255,.1));
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor; mask-composite: exclude;
  pointer-events: none;
}
@media (min-width: 901px) { .tier--pick { transform: translateY(-10px); } .tier--pick:hover { transform: translateY(-16px); } }

/* The badge sits on its own line above the plan name — it used to overlap it */
.tier__flag {
  align-self: flex-start;
  font-family: var(--mono); font-size: var(--t-mono); letter-spacing: .05em; text-transform: uppercase;
  color: #fff; background: linear-gradient(120deg, var(--brand-2), var(--brand-3));
  padding: 0.2rem 0.55rem; border-radius: 100px; line-height: 1.5;
  box-shadow: 0 4px 14px -4px rgba(154,107,212,.9);
}

.tier__name { display: block; font-size: var(--t-lg); font-weight: 600; letter-spacing: -0.024em; color: #fff; }
.tier__for { display: block; font-size: var(--t-sm); color: var(--d-ink-2); margin-top: 0.3rem; }
.tier__price { display: flex; align-items: baseline; gap: 0.35rem; padding-block: var(--s-4); border-block: 1px solid var(--d-line); }
.tier__amt { font-family: var(--mono); font-size: var(--t-2xl); font-weight: 500; letter-spacing: -0.03em; color: #fff; font-variant-numeric: tabular-nums; transition: opacity .15s var(--ease); }
.tier__amt.is-swapping { opacity: 0; }
.tier__per { font-size: var(--t-xs); color: var(--d-ink-2); }

.tier__list { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.85rem; flex: 1; align-content: start; }
.tier__list li { display: grid; grid-template-columns: auto minmax(0,1fr); gap: 0.55rem; font-size: var(--t-sm); color: var(--d-ink); line-height: 1.45; }
.tier__list svg { color: var(--brand-lit); margin-top: 0.32em; flex: none; }

.price-note {
  margin-top: var(--s-5);
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--s-3);
  font-size: var(--t-sm); color: var(--d-ink-2);
  padding: var(--s-4); border: 1px solid var(--d-line); border-radius: var(--r); background: rgba(255,255,255,.03);
}

/* ---------- 16. Process timeline ------------------------------------------ */

.timeline { position: relative; display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--s-5); }
.timeline::before {
  content: ""; position: absolute; top: 1.1rem; left: 12.5%; right: 12.5%; height: 1px;
  background: linear-gradient(90deg, var(--brand), var(--brand-3));
  transform: scaleX(0); transform-origin: left; transition: transform .9s var(--ease-out);
}
.timeline.is-in::before { transform: scaleX(1); }
@media (max-width: 860px) { .timeline { grid-template-columns: repeat(2, minmax(0,1fr)); row-gap: var(--s-6); } .timeline::before { left: 25%; right: 25%; } }
@media (max-width: 520px) { .timeline { grid-template-columns: 1fr; } .timeline::before { display: none; } }

.tstep { position: relative; text-align: center; display: flex; flex-direction: column; align-items: center; }
.tstep__dot {
  position: relative; z-index: 1;
  width: 2.2rem; height: 2.2rem; border-radius: 50%;
  border: 1px solid var(--line); background: var(--bg);
  display: grid; place-items: center; color: var(--brand);
  transition: background .45s var(--ease), color .45s var(--ease), border-color .45s var(--ease), box-shadow .45s var(--ease);
}
.tstep__dot svg { width: 1rem; height: 1rem; }
.timeline.is-in .tstep__dot {
  background: linear-gradient(140deg, var(--brand), var(--brand-3));
  border-color: transparent; color: #fff;
  box-shadow: 0 6px 18px -6px rgba(122,66,190,.8);
}
.timeline.is-in .tstep:nth-child(1) .tstep__dot { transition-delay: .18s; }
.timeline.is-in .tstep:nth-child(2) .tstep__dot { transition-delay: .34s; }
.timeline.is-in .tstep:nth-child(3) .tstep__dot { transition-delay: .5s; }
.timeline.is-in .tstep:nth-child(4) .tstep__dot { transition-delay: .66s; }

.tstep__day {
  display: inline-block; margin-top: var(--s-4);
  font-family: var(--mono); font-size: var(--t-mono); letter-spacing: .06em; text-transform: uppercase;
  color: var(--brand); background: var(--brand-wash); border-radius: 100px; padding: 0.15rem 0.5rem;
}
.tstep h3 { font-size: var(--t-md); margin-top: var(--s-3); letter-spacing: -0.024em; }
.tstep p { font-size: var(--t-sm); color: var(--ink-2); margin-top: 0.35rem; line-height: 1.5; max-width: 30ch; }

/* ---------- 17. Founder --------------------------------------------------- */

.founder { display: grid; gap: clamp(1.5rem, 1rem + 2.4vw, 2.75rem); align-items: center; }
@media (min-width: 820px) { .founder { grid-template-columns: minmax(0, 0.6fr) minmax(0, 1fr); } }

.founder__media {
  position: relative; aspect-ratio: 4 / 5;
  border: 1px solid var(--line); border-radius: var(--r-lg);
  background: var(--bg-3); overflow: hidden;
}
/* Stays portrait on phones — a wide, short crop of a person looks wrong.
   `width: 100%` is required: auto inline margins cancel grid stretch, and with
   the photo absent (initials are absolutely positioned) the box would have no
   in-flow content left to size itself from, collapsing to nothing. */
@media (max-width: 819px) {
  .founder__media { width: 100%; max-width: 17rem; margin-inline: auto; }
}
.founder__media img { width: 100%; height: 100%; object-fit: cover; object-position: center 22%; display: block; position: relative; z-index: 1; }
.founder__initials {
  position: absolute; inset: 0; display: grid; place-items: center;
  font-family: var(--mono); font-size: var(--t-4xl); color: var(--brand);
  background: var(--brand-wash); letter-spacing: .04em;
}
.founder__name { display: block; font-size: var(--t-xl); font-weight: 600; letter-spacing: -0.028em; }
.founder__role { display: inline-block; margin-top: 0.35rem; font-family: var(--mono); font-size: var(--t-mono); letter-spacing: .05em; text-transform: uppercase; color: var(--brand); }
.founder__quote {
  font-size: var(--t-md); line-height: 1.55; color: var(--ink); letter-spacing: -0.014em;
  margin-top: var(--s-4); padding-left: var(--s-4);
  border-left: 2px solid; border-image: linear-gradient(180deg, var(--brand), var(--brand-3)) 1;
}
.facts { list-style: none; margin: var(--s-5) 0 0; padding: 0; display: grid; gap: var(--s-4); }
.facts li { display: grid; grid-template-columns: auto minmax(0,1fr); gap: 0.6rem; font-size: var(--t-sm); color: var(--ink-2); line-height: 1.5; }
.facts svg { color: var(--brand); margin-top: 0.3em; flex: none; }
.facts b { color: var(--ink); font-weight: 550; }

/* ---------- 18. FAQ ------------------------------------------------------- */

.faq { border-top: 1px solid var(--line); }
.faq__item { border-bottom: 1px solid var(--line); }
.faq__q {
  width: 100%; display: flex; align-items: center; justify-content: space-between; gap: var(--s-4);
  text-align: left; background: none; border: 0; padding: 0.85rem 0; cursor: pointer;
  font-size: var(--t-base); font-weight: 500; letter-spacing: -0.018em; color: var(--ink);
  transition: color .2s var(--ease);
}
.faq__q:hover { color: var(--brand); }
.faq__icon { flex: none; color: var(--ink-3); transition: transform .3s var(--ease-out), color .2s; }
.faq__q[aria-expanded="true"] .faq__icon { transform: rotate(45deg); color: var(--brand); }
.faq__a { display: grid; grid-template-rows: 0fr; transition: grid-template-rows .3s var(--ease-out); }
.faq__a[data-open="true"] { grid-template-rows: 1fr; }
.faq__a > div { overflow: hidden; }
.faq__a p { padding-bottom: 0.9rem; font-size: var(--t-sm); color: var(--ink-2); line-height: 1.6; max-width: 72ch; }
html:not(.js) .faq__a { display: block; }

/* ---------- 19. CTA + form ------------------------------------------------ */

.cta { display: grid; gap: clamp(1.75rem, 1rem + 3vw, 3rem); align-items: start; }
@media (min-width: 880px) { .cta { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); } }
/* Both columns must be allowed to shrink or the form pushes the page wide */
.cta > * { min-width: 0; }
.cta h2 { font-size: var(--t-2xl); }
.cta__list { list-style: none; margin: var(--s-5) 0 0; padding: 0; display: grid; gap: 0.55rem; }
.cta__list li { display: grid; grid-template-columns: auto minmax(0,1fr); gap: 0.5rem; font-size: var(--t-sm); color: var(--d-ink-2); }
.cta__list svg { color: var(--brand-lit); margin-top: 0.3em; flex: none; }

.contact-row { display: grid; gap: var(--s-3); margin-top: var(--s-5); }
@media (min-width: 460px) { .contact-row { grid-template-columns: 1fr 1fr; } }
.contact-btn {
  display: flex; align-items: center; gap: 0.6rem; min-width: 0;
  padding: 0.7rem 0.85rem;
  border: 1px solid var(--d-line); border-radius: var(--r-sm);
  background: rgba(255,255,255,.05); text-decoration: none; color: #fff;
  transition: background .2s var(--ease), border-color .2s var(--ease), transform .2s var(--ease);
}
.contact-btn:hover { background: rgba(255,255,255,.1); border-color: var(--d-line-2); transform: translateY(-2px); }
.contact-btn svg { flex: none; color: var(--brand-lit); }
.contact-btn b { display: block; font-size: var(--t-sm); font-weight: 550; }
.contact-btn span { display: block; font-family: var(--mono); font-size: var(--t-mono); color: var(--d-ink-2); margin-top: 0.1rem; overflow: hidden; text-overflow: ellipsis; }

.form { display: grid; gap: var(--s-4); min-width: 0; }
.field { display: grid; gap: 0.3rem; min-width: 0; }
.field label { font-family: var(--mono); font-size: var(--t-mono); letter-spacing: .05em; text-transform: uppercase; color: var(--d-ink-2); }
.field input, .field select, .field textarea {
  width: 100%; background: rgba(255,255,255,.05);
  border: 1px solid var(--d-line); border-radius: var(--r-sm);
  padding: 0.65rem 0.75rem; font-size: var(--t-sm); color: #fff;
  transition: border-color .18s var(--ease), background .18s var(--ease), box-shadow .18s var(--ease);
}
.field textarea { min-height: 5.5rem; resize: vertical; }
.field input::placeholder, .field textarea::placeholder { color: rgba(255,255,255,.32); }
.field input:focus, .field select:focus, .field textarea:focus {
  outline: none; border-color: var(--brand-3); background: rgba(255,255,255,.09);
  box-shadow: 0 0 0 3px rgba(154,107,212,.2);
}
.field select option { background: #17171C; color: #fff; }
.field-row { display: grid; gap: var(--s-4); min-width: 0; }
@media (min-width: 520px) { .field-row { grid-template-columns: minmax(0,1fr) minmax(0,1fr); } }

.form__msg { font-size: var(--t-sm); min-height: 1.3em; }
.form__msg[data-state="ok"] { color: #6EE7B7; }
.form__msg[data-state="err"] { color: #FCA5A5; }
.form__note { font-family: var(--mono); font-size: var(--t-mono); color: rgba(255,255,255,.4); line-height: 1.6; }
.hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

/* ---------- 20. Footer ---------------------------------------------------- */

.footer { padding-block: var(--s-7) var(--s-5); background: var(--d-bg); color: var(--d-ink-2); }
.footer__grid { display: grid; gap: var(--s-6); grid-template-columns: repeat(auto-fit, minmax(min(100%, 170px), 1fr)); margin-bottom: var(--s-7); }
.footer__bio { font-size: var(--t-sm); color: var(--d-ink-2); margin-top: var(--s-3); max-width: 32ch; }
.footer h4 { font-family: var(--mono); font-size: var(--t-mono); letter-spacing: .07em; text-transform: uppercase; color: var(--d-ink-2); font-weight: 500; margin-bottom: var(--s-3); }
.footer ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.35rem; }
.footer ul a { text-decoration: none; font-size: var(--t-sm); color: var(--d-ink-2); transition: color .2s var(--ease); }
.footer ul a:hover { color: #fff; }
.footer__bar {
  display: flex; flex-wrap: wrap; gap: var(--s-3) var(--s-5);
  align-items: center; justify-content: space-between;
  padding-top: var(--s-4); border-top: 1px solid var(--d-line);
  font-size: var(--t-xs); color: var(--d-ink-2);
}
.footer__bar a { text-decoration: none; }
.footer__bar a:hover { color: #fff; }

/* ---------- 21. Floating actions ------------------------------------------ */
/* Plain links, no entrance animation, never dependent on a script. */
.float { position: fixed; right: clamp(0.7rem, 0.4rem + 1vw, 1.1rem); bottom: clamp(0.7rem, 0.4rem + 1vw, 1.1rem); z-index: 90; display: grid; gap: 0.5rem; }
.float a {
  width: 2.5rem; height: 2.5rem; border-radius: 50%;
  display: grid; place-items: center; color: #fff; text-decoration: none;
  box-shadow: 0 8px 24px -8px rgba(0,0,0,.5);
  transition: transform .2s var(--ease), box-shadow .2s var(--ease);
}
.float a:hover { transform: scale(1.08) translateY(-2px); }
.float__wa { background: #25D366; }
.float__call { background: #1F1F27; border: 1px solid var(--d-line-2); }
.float__mail { background: linear-gradient(140deg, var(--brand), var(--brand-3)); box-shadow: 0 8px 26px -8px rgba(122,66,190,.9); }

/* ---------- 22. Utilities -------------------------------------------------- */

.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
.skip {
  position: absolute; left: 50%; translate: -50% -140%; z-index: 200;
  background: var(--brand); color: #fff; padding: 0.5rem 0.9rem;
  border-radius: 0 0 var(--r-sm) var(--r-sm); text-decoration: none; font-size: var(--t-sm);
  transition: translate .25s var(--ease);
}
.skip:focus { translate: -50% 0; }
.center { text-align: center; }

/* ---------- 23. Contact page ---------------------------------------------- */

/* The three channels live in the hero, not in a section below it. The one
   thing somebody opened this page for should never cost them a scroll. */

.reach { display: grid; gap: var(--s-3); }

.reach__card {
  display: grid; grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center; gap: var(--s-4);
  padding: var(--s-4);
  border: 1px solid var(--d-line-2); border-radius: var(--r);
  background: rgba(255, 255, 255, 0.04);
  text-decoration: none; color: var(--d-ink);
  transition: transform .28s var(--ease-out), border-color .25s var(--ease),
              background .25s var(--ease);
}
.reach__card:hover {
  transform: translateY(-2px);
  border-color: rgba(255, 255, 255, 0.32);
  background: rgba(255, 255, 255, 0.08);
}
/* Email leads deliberately: UK and US enquiries arrive that way far more
   often than by phone, so it carries the brand tint and the others don't. */
.reach__card--lead { border-color: rgba(154, 107, 212, 0.45); background: rgba(122, 66, 190, 0.14); }
.reach__card--lead:hover { border-color: var(--brand-3); background: rgba(122, 66, 190, 0.22); }

.reach__ico {
  display: grid; place-items: center;
  width: 2.6rem; height: 2.6rem;
  border-radius: var(--r-sm);
  background: rgba(255, 255, 255, 0.07); color: #fff;
}
.reach__card--lead .reach__ico { background: rgba(154, 107, 212, 0.25); color: var(--brand-lit); }

.reach__body { display: grid; gap: 0.1rem; min-width: 0; }
.reach__body b { color: #fff; font-size: var(--t-sm); font-weight: 550; }
/* anywhere, not break-word: the address has no spaces to break on, and at
   375px it is wider than the column it sits in. */
.reach__val {
  font-family: var(--mono); font-size: var(--t-sm); color: var(--brand-lit);
  overflow-wrap: anywhere;
}
.reach__note { font-size: var(--t-xs); color: var(--d-ink-2); line-height: 1.45; }

.reach__go { color: var(--d-ink-2); transition: transform .28s var(--ease-out), color .2s; }
.reach__card:hover .reach__go { transform: translateX(3px); color: #fff; }

.reach__foot { margin: var(--s-2) 0 0; font-size: var(--t-xs); color: var(--d-ink-2); line-height: 1.55; }
.reach__foot b { color: var(--d-ink); font-weight: 550; }

.field__opt {
  font-family: var(--mono); font-size: var(--t-mono);
  letter-spacing: .03em; color: var(--d-ink-2); margin-left: 0.4rem;
}

@media (max-width: 480px) {
  .reach__card { gap: var(--s-3); padding: var(--s-3); }
  .reach__go { display: none; }
}

/* Footer links are 19px tall and sit flush against each other — on a phone
   that is a mis-tap generator. Padding brings every row to the 44px minimum;
   a taller footer is a fair trade for the last element on the page. */
@media (max-width: 880px) {
  .footer__grid ul a, .footer__bar a { display: inline-block; padding-block: 0.66rem; }
}

/* ---------- 24. Inner pages ------------------------------------------------ */

/* The homepage hero is sized around the deck standing beside the copy. Inner
   pages have no visual column, so the same padding leaves them looking hollow —
   this trims the block and drops the headline one step down the scale. */
.hero--short {
  padding-block:
    calc(var(--nav-h) + clamp(1.75rem, 1rem + 2.6vw, 3rem))
    clamp(1.75rem, 1rem + 2.4vw, 2.75rem);
}
.hero--short h1 { font-size: var(--t-3xl); }
.hero--short .head { margin-bottom: var(--s-4); }

/* Two even columns above 900px, stacked below. Deliberately not reusing .perf:
   that one centres its tracks for the gauge sitting next to the bars, which
   misaligns two lists of unequal length. */
.cols2 { display: grid; gap: var(--s-5) var(--s-6); align-items: start; }
@media (min-width: 900px) { .cols2 { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.cols2 > .facts { margin-top: 0; }
/* Grid items default to min-width:auto, so a child carrying max-width:46ch
   (.head does) sizes the single-column track to ~363px and pushes 32px of text
   outside a 331px phone. body{overflow-x:hidden} hides the scrollbar, so this
   presents as silently clipped text rather than as a visible overflow. */
.cols2 > * { min-width: 0; }

/* A fanned stack of real screenshots — the hero counterpart to the browsable
   grid below it. Same 3D language as the homepage deck, but static: no cycling,
   no JS, and the cards never change order. */
.fan { position: relative; padding: 7% 9% 0 0; perspective: 1500px; perspective-origin: 60% 42%; }
.fan__stage { position: relative; aspect-ratio: 16 / 11; transform-style: preserve-3d; --rx-base: 6deg; --ry-base: 12deg; }
/* Overrides .tilt for the same reason the deck does: its perspective() function
   would open a second projection and flatten every card's translateZ to zero. */
.fan .fan__stage.tilt {
  transform:
    rotateX(calc(var(--rx, 0deg) + var(--rx-base, 0deg)))
    rotateY(calc(var(--ry, 0deg) + var(--ry-base, 0deg)))
    translate3d(0, var(--py, 0px), 0);
}

.fan__card {
  --i: 0;
  position: absolute; inset: 0; z-index: calc(10 - var(--i));
  border: 1px solid rgba(255, 255, 255, 0.16); border-radius: var(--r-lg);
  overflow: hidden; background: #0C0C12;
  box-shadow: 0 36px 80px -28px rgba(0, 0, 0, 0.9), 0 0 0 1px rgba(255, 255, 255, 0.05);
  /* Steps must beat the perspective shrink, which also scales them down the
     further back a card sits — same arithmetic as the homepage deck. */
  transform:
    translate3d(calc(var(--i) * 8.5%), calc(var(--i) * -7.5%), calc(var(--i) * -80px))
    rotate(calc(var(--i) * -1.7deg));
}
.fan__card img { width: 100%; height: 100%; object-fit: cover; object-position: top center; display: block; }
.fan__card::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(200deg, rgba(6, 6, 10, 0.15), rgba(6, 6, 10, 0.78));
  opacity: calc(var(--i) * 0.26);
}

@media (prefers-reduced-motion: no-preference) {
  .js .fan__card { animation: deal 1s cubic-bezier(.22, 1, .36, 1) both; animation-delay: calc(0.3s + (2 - var(--i)) * 0.14s); }
}

@media (max-width: 720px) {
  .fan { padding: 8% 11% 0 0; perspective: 1000px; }
  .fan__stage { --rx-base: 4deg; --ry-base: 8deg; }
  .fan__card {
    transform:
      translate3d(calc(var(--i) * 7%), calc(var(--i) * -6%), calc(var(--i) * -50px))
      rotate(calc(var(--i) * -1.2deg));
  }
}

/* ---------- 25. Legal pages ------------------------------------------------ */

/* Long-form prose, so it gets a measure rather than the full container width —
   past roughly 70 characters the eye loses its place returning to the next line. */
.legal { max-width: 68ch; }
.legal h2 {
  font-size: var(--t-lg); letter-spacing: -0.028em;
  margin: var(--s-6) 0 var(--s-3);
  padding-top: var(--s-5); border-top: 1px solid var(--line);
}
.legal h2:first-of-type { margin-top: var(--s-4); }
.legal p { color: var(--ink-2); line-height: 1.65; margin: 0 0 var(--s-3); }
.legal ul { margin: 0 0 var(--s-3); padding: 0; list-style: none; display: grid; gap: 0.55rem; }
.legal li {
  position: relative; padding-left: 1.15rem;
  color: var(--ink-2); line-height: 1.6;
}
.legal li::before {
  content: ""; position: absolute; left: 0; top: 0.62em;
  width: 5px; height: 5px; border-radius: 50%; background: var(--brand-3);
}
.legal a { color: var(--brand); font-weight: 500; }
.legal__meta {
  margin-top: var(--s-6); padding-top: var(--s-4); border-top: 1px solid var(--line);
  font-family: var(--mono); font-size: var(--t-mono); letter-spacing: .03em; color: var(--ink-3);
}

/* A single mockup standing on its own, outside the homepage deck. .mk-shell
   supplies the container-query context the mockups measure themselves in; this
   supplies the window it sits in. */
.mk-frame {
  border: 1px solid rgba(255, 255, 255, 0.16); border-radius: var(--r-lg);
  overflow: hidden; background: #0C0C12;
  box-shadow: 0 40px 90px -30px rgba(0, 0, 0, 0.9), 0 0 0 1px rgba(255, 255, 255, 0.05);
}

/* ---------- 25. Success dialog -------------------------------------------- */
/* Every form used to confirm with a line of text under the button — easy to
   miss on a phone, and it left the visitor with nothing to do next. This is the
   shared confirmation: it states what happens now, and offers the next step. */

.succ {
  position: fixed; inset: 0; z-index: 200;
  display: grid; place-items: center;
  padding: var(--s-4);
  background: rgba(4, 4, 8, 0.72);
  backdrop-filter: blur(4px); -webkit-backdrop-filter: blur(4px);
  opacity: 0; visibility: hidden;
  transition: opacity .28s var(--ease), visibility .28s;
}
.succ.is-open { opacity: 1; visibility: visible; }

.succ__card {
  width: min(30rem, 100%);
  max-height: calc(100dvh - 2 * var(--s-4));
  overflow-y: auto;
  position: relative;
  background: linear-gradient(170deg, var(--d-bg-2), var(--d-bg));
  border: 1px solid var(--d-line-2);
  border-radius: 20px;
  box-shadow: 0 40px 90px -30px rgba(0, 0, 0, .95);
  padding: clamp(1.5rem, 5vw, 2.1rem);
  text-align: center;
  transform: translateY(14px) scale(.97);
  transition: transform .34s var(--ease-out);
}
.succ.is-open .succ__card { transform: none; }

/* The tick draws itself once. Motion here is doing a job — it marks the moment
   the submission completed — so it is the one thing that animates. */
.succ__mark {
  width: 3.5rem; height: 3.5rem;
  margin: 0 auto var(--s-4);
  display: grid; place-items: center;
  border-radius: 50%;
  background: rgba(74, 222, 158, .13);
  border: 1px solid rgba(74, 222, 158, .34);
  /* --ok (#17795E) is the green for LIGHT surfaces; on this dark card it read
     as near-black and the tick looked missing. --ok-lit is the dark-surface pair. */
  color: var(--ok-lit, #4ADE9E);
}
/* The tick is VISIBLE by default and the draw-on is an enhancement. Keying the
   resting state to `stroke-dashoffset: 26` meant the mark was an empty circle
   whenever the animation did not run — reduced-motion, a paint the browser
   skipped, or a screenshot taken mid-delay. `backwards` supplies the hidden
   state during the delay, and it returns to visible when the animation ends. */
.succ__mark svg { stroke-dasharray: 26; stroke-dashoffset: 0; }
.succ.is-open .succ__mark svg { animation: succ-tick .45s var(--ease-out) .12s backwards; }
@keyframes succ-tick { from { stroke-dashoffset: 26; } to { stroke-dashoffset: 0; } }

.succ__title {
  margin: 0 0 var(--s-3);
  font-size: var(--t-xl); font-weight: 600;
  letter-spacing: -0.028em; color: #fff;
}
.succ__body {
  margin: 0; color: var(--d-ink);
  font-size: var(--t-sm); line-height: 1.6;
}
.succ__meta {
  margin: var(--s-4) 0 0; padding: var(--s-3) var(--s-4);
  border: 1px solid var(--d-line); border-radius: 12px;
  background: rgba(255, 255, 255, .03);
  font-family: var(--mono); font-size: var(--t-mono);
  color: var(--d-ink-2); word-break: break-word;
}

.succ__actions {
  display: grid; gap: var(--s-3);
  margin-top: var(--s-5);
}
@media (min-width: 420px) {
  .succ__actions { grid-auto-flow: column; grid-auto-columns: 1fr; }
}

/* Close is a real button in the corner, not only an outside-click, so the way
   out is visible rather than something you have to guess at. */
.succ__close {
  position: absolute; top: .7rem; right: .7rem;
  width: 40px; height: 40px;          /* full touch target */
  display: grid; place-items: center;
  border: 0; border-radius: 50%;
  background: rgba(255, 255, 255, .06);
  color: var(--d-ink-2);
  cursor: pointer;
  transition: background .18s var(--ease), color .18s var(--ease);
}
.succ__close:hover { background: rgba(255, 255, 255, .13); color: #fff; }

@media (prefers-reduced-motion: reduce) {
  .succ, .succ__card { transition: none; }
  .succ__card { transform: none; }
  .succ.is-open .succ__mark svg { animation: none; stroke-dashoffset: 0; }
}

/* ---------- 26. Invalid fields -------------------------------------------- */
/* The forms told people to "fill in the highlighted fields" while nothing was
   ever highlighted — the only feedback was one small line of red text under the
   button, which on a phone is often below the fold. Pressing submit with an
   empty required field therefore looked like the button was dead. */

.field.is-invalid > input,
.field.is-invalid > select,
.field.is-invalid > textarea,
.field.is-invalid .contact-btn {
  border-color: #F0796B;
  background: rgba(240, 121, 107, 0.07);
}
.field.is-invalid > input:focus,
.field.is-invalid > select:focus,
.field.is-invalid > textarea:focus {
  outline: 2px solid rgba(240, 121, 107, 0.55);
  outline-offset: 1px;
}

/* Colour alone must not carry the meaning, so the label gets a marker too. */
.field.is-invalid > label { color: #FCA5A5; }
.field.is-invalid > label::after {
  content: " — required";
  font-family: var(--sans);
  text-transform: none;
  letter-spacing: 0;
  opacity: .85;
}

/* The summary line is the last resort, not the only signal. */
.form__msg[data-state="err"] {
  color: #FCA5A5;
  display: flex;
  align-items: flex-start;
  gap: .4rem;
  font-weight: 500;
}
