/* ═══════════════════════════════════════════════════════════════════════
   Semicolon — landing page
   Rebuilt to close the findings in the July 2026 design, UX and
   accessibility audit. Every token below that replaces an audited value
   carries the measured ratio it now achieves.

   Conventions:
   · Logical properties only (padding-inline, margin-block, inset-inline)
     so an Arabic build is a dir="rtl" attribute, not a rewrite. (INT-01)
   · One 8px spacing base. Container 1200px, gutter 24px. (LAY-03)
   · Card height follows content via min-height, never a fixed frame,
     so a user-forced 1.5 line-height cannot overflow it. (LAY-02, SC 1.4.12)
   ═══════════════════════════════════════════════════════════════════════ */

/* ── tokens ──────────────────────────────────────────────────────────── */
:root {
  /* Surfaces — the audit called the neutral scale "genuinely good"; kept. */
  --bg:            #ffffff;   /* card surface        */
  --bg-alt:        #f8f8fa;   /* alt section         */
  --bg-section:    #f0f1f5;   /* section base        */
  --bg-dark:       #0a0a0a;   /* dark section        */
  --bg-dark-card:  #0f0f0f;   /* dark card           */
  --bg-dark-lift:  #171717;   /* dark elevated       */

  /* Text. Two steps, bound to the surface rather than to the section —
     the old single grey measured 4.12:1 to 4.87:1 depending on where it
     landed, and four of those readings failed. (CLR-03) */
  --ink:           #0f1115;   /* 18.7:1 on #F0F1F5 */
  --ink-soft:      #5a5d69;   /*  5.81:1 on #F0F1F5, 6.55:1 on #FFF */
  --ink-dark:      #ffffff;   /* 19.8:1  on #0A0A0A */
  --ink-dark-soft: #a8acb6;   /*  8.44:1 on #0F0F0F */
  --ink-faint:     #8a8a8a;   /*  5.55:1 on #0F0F0F — was 1.52:1 (CLR-04) */

  /* Accent. Two tokens, never interchanged: brand magenta collapses to
     1.54:1 on a dark fill, which is what made the old badge invisible. (CLR-02) */
  --accent-on-light: #990496; /* 7.47:1 on #FFFFFF */
  --accent-on-dark:  #f06cec; /* 7.36:1 on #0F0F0F */

  /* Hero ramp, clamped to the dark half. White body copy reaches 16.87:1
     at the start and 6.74:1 at the end, against 2.08–2.85:1 before. (CLR-01) */
  --hero-from: #2b0a4a;
  --hero-to:   #a3129b;
  --cta-from:  #3e0060;
  --cta-to:    #860082;

  /* Lines. Decorative separators are quiet; anything that bounds an
     interactive control has to reach 3:1. (SC 1.4.11) */
  --line:            #e2e4ea;
  --line-strong:     #6f7380;  /* 4.13:1 on #F8F8FA */
  --line-dark:       #2a2a2a;
  --line-dark-strong:#6a6a6a;  /* 3.47:1 on #0F0F0F */

  /* Type. One scale with no 2.75x hole in it: 16 / 20 / 24 / 32 / 44 / 56 / 96,
     fluid between the two ends of each step. (TYP-02) */
  --fs-body:    1rem;
  --fs-lead:    1.125rem;
  --fs-h4:      1.25rem;   /* 20 */
  --fs-h3:      1.5rem;    /* 24 */
  --fs-h3-lg:   clamp(1.5rem, 1.1rem + 1.4vw, 2rem);     /* 24 → 32 */
  --fs-h2:      clamp(1.75rem, 1.1rem + 2.6vw, 2.75rem); /* 28 → 44 */
  --fs-display: clamp(3rem, 1.2rem + 9vw, 6rem);         /* 48 → 96 */

  /* Line-height, decoupled by size. The old build ran body copy at 1.25 —
     a display value applied to a 16px paragraph. (TYP-01) */
  --lh-display: 1.06;
  --lh-heading: 1.22;
  --lh-body:    1.55;

  --sans: Inter, "Helvetica Neue", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Arial, sans-serif;
  /* Display face slot: drop a neo-grotesque here (Söhne / Aeonik class) to
     give the hero the voice TYP-03 asks for. Falls back to --sans today. */
  --display: var(--sans);
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;

  /* 8px base */
  --s1: .5rem;  --s2: 1rem;   --s3: 1.5rem;  --s4: 2rem;
  --s5: 3rem;   --s6: 4rem;   --s7: 6rem;    --s8: 8rem;

  --container: 1200px;
  --gutter:    1.5rem;   /* 24px — was 12.5px, 3.1% of a column (LAY-03) */
  --nav-h:     4.5rem;

  --r-sm: 8px; --r-md: 14px; --r-lg: 20px; --r-pill: 999px;
  --shadow: 0 1px 2px rgb(12 12 20 / .06), 0 8px 24px rgb(12 12 20 / .06);
  --shadow-lg: 0 24px 64px rgb(12 12 20 / .18);

  --t-fast: 160ms cubic-bezier(.2, .6, .3, 1);
  --t:      280ms cubic-bezier(.2, .6, .3, 1);
  --t-slow: 400ms cubic-bezier(.2, .6, .3, 1);
}

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

html {
  scroll-behavior: smooth;
  /* Anchored sections used to land under the fixed nav in 22 of 62 frames.
     Every scroll target now clears it, focus included. (SC 2.4.11) */
  scroll-padding-block-start: calc(var(--nav-h) + 1.5rem);
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--sans);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

h1, h2, h3, h4 { line-height: var(--lh-heading); margin: 0; text-wrap: balance; }
p { margin: 0; }
ul, ol { margin: 0; padding: 0; list-style: none; }
img, svg, video { display: block; max-inline-size: 100%; height: auto; }
a { color: inherit; }

/* Figures are tabular everywhere, so prices and stats align. (TYP-03) */
.num, .stat-num, .tier-price b, .count { font-variant-numeric: tabular-nums; }

/* Focus is visible and never clipped. The recording was mouse-driven, so
   no focus state existed to audit — this is the state that has to exist. */
:focus-visible {
  outline: 3px solid var(--accent-on-light);
  outline-offset: 3px;
  border-radius: 4px;
}
.section-dark :focus-visible,
.hero :focus-visible,
.footer :focus-visible { outline-color: var(--accent-on-dark); }

.sr-only {
  position: absolute; inline-size: 1px; block-size: 1px;
  padding: 0; margin: -1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap;
}

/* No skip link existed on a long single-page site with a persistent nav. (SC 2.4.1) */
.skip-link {
  position: fixed; inset-block-start: .5rem; inset-inline-start: .5rem;
  z-index: 200;
  padding: .75rem 1.25rem;
  background: var(--bg-dark); color: #fff;
  border-radius: var(--r-sm); font-weight: 600;
  transform: translateY(-150%);
  transition: transform var(--t-fast);
}
.skip-link:focus { transform: none; }

.container {
  inline-size: 100%;
  max-inline-size: var(--container);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

/* ── typography scale ────────────────────────────────────────────────── */
.h2 { font-family: var(--display); font-size: var(--fs-h2); letter-spacing: -.02em; font-weight: 700; max-inline-size: 34ch; }
.h3 { font-size: var(--fs-h3-lg); letter-spacing: -.015em; font-weight: 700; }
.h4 { font-size: var(--fs-h4); letter-spacing: -.01em; font-weight: 650; }
.lede { margin-block-start: var(--s2); font-size: var(--fs-lead); color: var(--ink-soft); max-inline-size: 68ch; }
.section-dark .lede { color: var(--ink-dark-soft); }
.link { color: var(--accent-on-light); text-decoration: underline; text-underline-offset: 3px; font-weight: 500; }
.section-dark .link, .footer .link { color: var(--accent-on-dark); }

/* ── buttons: one primary, one secondary, one inverse ────────────────
   The audit counted eight labels and four treatments for a single
   function. Two labels, three treatments, and every target ≥44px.
   (CMP-01, SC 2.5.8, SC 3.2.4) */
.btn {
  --btn-bg: var(--bg-dark); --btn-fg: #fff; --btn-line: var(--bg-dark);
  display: inline-flex; align-items: center; justify-content: center; gap: .5rem;
  min-block-size: 2.75rem;                /* 44px */
  padding: .625rem 1.25rem;
  background: var(--btn-bg); color: var(--btn-fg);
  border: 1.5px solid var(--btn-line); border-radius: var(--r-pill);
  font: inherit; font-weight: 600; text-decoration: none; cursor: pointer;
  transition: transform var(--t-fast), background var(--t-fast), color var(--t-fast), border-color var(--t-fast);
}
.btn:hover { transform: translateY(-2px); }
.btn-primary { --btn-bg: var(--bg-dark); --btn-fg: #fff; --btn-line: var(--bg-dark); }   /* 20.4:1 */
.btn-ghost   { --btn-bg: transparent; --btn-fg: var(--ink); --btn-line: var(--line-strong); }
.btn-ghost:hover { --btn-line: var(--ink); }
.btn-invert  { --btn-bg: #fff; --btn-fg: #0a0a0a; --btn-line: #fff; }                    /* 20.8:1 */
.section-dark .btn-ghost, .hero .btn-ghost { --btn-fg: #fff; --btn-line: var(--line-dark-strong); }
.section-dark .btn-ghost:hover, .hero .btn-ghost:hover { --btn-line: #fff; }
.btn-lg { min-block-size: 3rem; padding-inline: 1.5rem; font-size: 1.0625rem; }
.btn-block { inline-size: 100%; }

/* ── badges: one component, three variants, defined on both surfaces ──
   The old set had four unrelated treatments, one of them at 1.54:1. (CMP-03, CLR-02) */
.badge {
  display: inline-block;
  padding: .25rem .625rem;
  border-radius: var(--r-sm);
  font-size: .75rem; font-weight: 700; letter-spacing: .04em; text-transform: uppercase;
}
.badge-neutral { background: var(--bg-section); color: var(--ink-soft); }
.badge-accent  { background: rgb(153 4 150 / .12); color: var(--accent-on-light); }  /* 7.0:1 on the tint */
.badge-inverse { background: var(--bg-dark); color: #fff; }
.section-dark .badge-neutral { background: var(--bg-dark-lift); color: var(--ink-dark-soft); }
.section-dark .badge-accent  { background: rgb(240 108 236 / .14); color: var(--accent-on-dark); }

/* ── one card component, light and dark variants sharing every metric ─
   Light sections used white cards with shadows and no borders while dark
   sections used bordered cards with no shadow: two systems interleaved. (LAY-04, CMP-03) */
.card {
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  box-shadow: var(--shadow);
  padding: var(--s3);
}
.section-dark .card {
  background: var(--bg-dark-card);
  border-color: var(--line-dark);
  box-shadow: none;
}

/* ── nav ─────────────────────────────────────────────────────────────── */
.nav {
  position: fixed; inset-block-start: 0; inset-inline: 0; z-index: 100;
  background: rgb(10 10 10 / .82);
  backdrop-filter: blur(14px);
  border-block-end: 1px solid rgb(255 255 255 / .1);
  transition: transform var(--t);
}
.nav[data-hidden="true"] { transform: translateY(-100%); }
.nav:focus-within { transform: none; }         /* never hide a focused control */
.nav-inner {
  inline-size: 100%; max-inline-size: var(--container);
  margin-inline: auto; padding: .75rem var(--gutter);
  min-block-size: var(--nav-h);
  display: flex; align-items: center; gap: var(--s3);
  color: #fff;
}
.wordmark {
  font-family: var(--display); font-size: 1.25rem; font-weight: 700;
  letter-spacing: -.02em; text-decoration: none; white-space: nowrap;
}
.wordmark span { color: var(--accent-on-dark); }
.nav-links { display: flex; gap: .25rem; margin-inline-start: auto; }
.nav-links a {
  display: inline-flex; align-items: center; min-block-size: 2.75rem;
  padding-inline: .875rem; border-radius: var(--r-pill);
  color: #fcfcfc; text-decoration: none; font-weight: 500;   /* 20.5:1 */
  transition: background var(--t-fast);
}
.nav-links a:hover { background: rgb(255 255 255 / .12); }
.nav-cta { min-block-size: 2.625rem; padding-inline: 1.125rem; --btn-bg: #fff; --btn-fg: #0a0a0a; --btn-line: #fff; }
.nav-toggle {
  display: none;
  inline-size: 2.75rem; block-size: 2.75rem; margin-inline-start: auto;
  background: none; border: 1.5px solid var(--line-dark-strong); border-radius: var(--r-sm);
  cursor: pointer; color: #fff;
}
.nav-toggle-bars, .nav-toggle-bars::before, .nav-toggle-bars::after {
  content: ""; display: block; inline-size: 18px; block-size: 2px;
  background: currentColor; margin-inline: auto; border-radius: 2px;
}
.nav-toggle-bars::before { transform: translateY(-6px); }
.nav-toggle-bars::after  { transform: translateY(4px); }
.mobile-menu { padding: var(--s2) var(--gutter) var(--s3); border-block-start: 1px solid rgb(255 255 255 / .1); }
.mobile-menu[hidden] { display: none; }
.mobile-menu ul { display: grid; gap: .25rem; margin-block-end: var(--s2); }
.mobile-menu a { display: flex; align-items: center; min-block-size: 2.75rem; color: #fff; text-decoration: none; font-weight: 500; }

/* ── hero ────────────────────────────────────────────────────────────── */
.hero {
  position: relative; isolation: isolate;
  padding-block: calc(var(--nav-h) + var(--s7)) var(--s7);
  background: var(--bg-dark); color: #fff;
  overflow: hidden;
}
.hero-bg {
  position: absolute; inset: 0; z-index: -1;
  background: linear-gradient(155deg, var(--hero-from) 0%, #6a0f6b 55%, var(--hero-to) 100%);
}
/* The animated element is the glow, not the colour behind the text, so the
   text's contrast is constant while it moves. (CLR-01, MOT-01) */
.hero-glow {
  position: absolute; inset-block-start: -30%; inset-inline-end: -10%;
  inline-size: min(40rem, 80%); aspect-ratio: 1;
  /* Measured from the rendered pixels: at .5 alpha this lifted the area
     behind the capability list to #9E2B9B, where the mono index digits
     dropped to 3.74:1. At .34 the worst sampled background stays dark
     enough for every foreground in the hero. (CLR-01) */
  background: radial-gradient(circle, rgb(240 108 236 / .34), transparent 62%);
  animation: drift 18s ease-in-out infinite alternate;
}
@keyframes drift {
  from { transform: translate3d(0, 0, 0) scale(1); }
  to   { transform: translate3d(-6%, 6%, 0) scale(1.12); }
}
.hero-inner {
  display: grid; gap: var(--s5);
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: end;
}
.eyebrow {
  font-size: .8125rem; font-weight: 650; letter-spacing: .12em; text-transform: uppercase;
  color: #f4d9f3;                       /* 11.6:1 on the clamped ramp — was 1.42:1 */
}
.hero-title {
  font-family: var(--display);
  font-size: var(--fs-display); line-height: var(--lh-display);
  letter-spacing: -.035em; font-weight: 700;
  margin-block: var(--s2) var(--s2);
}
.hero-semi { color: var(--accent-on-dark); }
.hero-lede { font-size: clamp(1.0625rem, .95rem + .4vw, 1.25rem); max-inline-size: 46ch; color: #fff; }
.hero-actions { display: flex; flex-wrap: wrap; gap: var(--s2); margin-block-start: var(--s4); }
.hero-note { margin-block-start: var(--s3); color: #f0dcef; font-size: .9375rem; }

.hero-side { display: grid; gap: var(--s4); justify-items: end; align-content: end; }
.hero-render {
  inline-size: min(24rem, 100%);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-lg);
}

.capabilities { display: grid; gap: .25rem; text-align: end; }
.capabilities button {
  inline-size: 100%;
  display: flex; align-items: center; justify-content: flex-end; gap: .75rem;
  min-block-size: 2.75rem; padding: .375rem .75rem;
  background: none; border: 0; border-inline-end: 2px solid transparent;
  color: #f0dcef; font: inherit; font-weight: 500; cursor: pointer;
  transition: color var(--t-fast), border-color var(--t-fast);
}
.capabilities button:hover { color: #fff; }
.capabilities button[aria-expanded="true"] {
  color: #fff; font-weight: 650; border-inline-end-color: var(--accent-on-dark);
}
.cap-index { font-family: var(--mono); font-size: .8125rem; color: #f0dcef; }

/* ── clients ─────────────────────────────────────────────────────────── */
.clients { padding-block: var(--s5); background: var(--bg); border-block-end: 1px solid var(--line); }
.clients-claim {
  font-size: .9375rem; font-weight: 600; letter-spacing: .02em;
  color: var(--ink-soft); text-align: center;
}
.client-list {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: center;
  gap: var(--s3) var(--s4); margin-block-start: var(--s3);
}
/* The client's own artwork, height-normalised. Kept at full opacity: these
   logos are the page's proof, and the audited build's dark-surface knockouts
   read unevenly. One strip, one surface. (IA-04) */
.client-list img {
  /* Normalised optically, not by one dimension: a wide wordmark and a
     two-line lockup at the same height read as wildly different sizes. */
  block-size: 2.25rem; inline-size: auto;
  max-inline-size: 9.5rem; object-fit: contain; object-position: center;
}
@media (max-width: 48rem) { .client-list img { block-size: 1.75rem; max-inline-size: 7rem; } }

/* ── section shell: the label column is real, 220px, and sticky ──────── */
.section { padding-block: var(--s7); background: var(--bg-alt); }
.section + .section { border-block-start: 1px solid var(--line); }
.section-dark {
  background: var(--bg-dark); color: var(--ink-dark);
  border-block-start: 0 !important;
}
.section-dark .h2, .section-dark .h3, .section-dark .h4 { color: #fff; }

/* LAY-01, option (b): the label sits directly above the heading and both
   start at the container's left edge, so the page has ONE vertical axis.
   The audited build pinned the label far left and began the heading at 41%
   of the container — about 290px of load-bearing void, with the copy
   squeezed into what was left. A sticky 220px column was tried here first
   and read the same way: as waste. */
.section-grid { display: grid; gap: var(--s2); }
.section-label {
  display: inline-flex; align-items: center; gap: .5rem;
  font-size: .8125rem; font-weight: 700; letter-spacing: .1em; text-transform: uppercase;
  color: var(--ink-soft);
}
.section-dark .section-label { color: var(--ink-dark-soft); }
/* One metaphor for every section label instead of six clip-art icons. (CMP-03) */
.section-label .dot {
  inline-size: .5rem; block-size: .5rem; border-radius: 50%;
  background: var(--accent-on-light); flex: none;
}
.section-dark .section-label .dot { background: var(--accent-on-dark); }
.section-body > * + * { margin-block-start: var(--s3); }
.section-more { margin-block-start: var(--s4); }

/* ── stats ───────────────────────────────────────────────────────────── */
.stats { display: grid; gap: var(--s2); grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr)); }
/* Content-driven height: the old cards held 250px of nothing between the
   figure and its label. (LAY-02) */
.stat { display: grid; align-content: start; gap: .5rem; min-block-size: 0; }
.stat-num { font-family: var(--display); font-size: 2.75rem; font-weight: 700; letter-spacing: -.03em; line-height: 1; color: var(--accent-on-light); }
.stat-label { font-size: var(--fs-h4); font-weight: 650; }
.stat-note { color: var(--ink-soft); font-size: .9375rem; }

/* ── CTA card ────────────────────────────────────────────────────────── */
.cta-card { position: relative; isolation: isolate; border-radius: var(--r-lg); overflow: hidden; }
.cta-card-bg {
  position: absolute; inset: 0; z-index: -1;
  background: linear-gradient(120deg, var(--cta-from), var(--cta-to));
  background-size: 160% 160%;
  animation: pan 22s ease-in-out infinite alternate;
}
@keyframes pan { from { background-position: 0% 50%; } to { background-position: 100% 50%; } }
.cta-card-inner {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: var(--s3); padding: var(--s5) var(--s4);
}
.cta-card .h3 { color: #fff; max-inline-size: 28ch; }   /* 8.99–15.29:1 */

/* ── projects ────────────────────────────────────────────────────────── */
.projects { display: grid; gap: var(--s2); grid-template-columns: repeat(auto-fill, minmax(16rem, 1fr)); }
.project { padding: 0; overflow: hidden; }
.project > a {
  display: grid; block-size: 100%; text-decoration: none;
  position: relative; isolation: isolate;
  cursor: pointer;                     /* every card that looks like a link is one (MOT-03) */
}
.project-media {
  display: block;
  aspect-ratio: 4 / 3;                 /* reserved box: no layout shift on load */
  background: var(--bg-dark-lift);
  overflow: hidden;
}
.project-media img {
  inline-size: 100%; block-size: 100%;
  object-fit: cover;
  transition: scale var(--t);
}
.project > a:hover .project-media img { scale: 1.04; }

/* The designed no-media state LAY-02 asks for: a card without a picture has
   to look intended, not like the same box with a hole in it. */
.project-nomedia > a {
  align-content: end;
  min-block-size: 15rem;
  background: linear-gradient(165deg, var(--bg-dark-lift), var(--bg-dark-card) 70%);
}
.project-nomedia .project-body { background: transparent; }
.project-body {
  display: grid; gap: .25rem; padding: var(--s2);
  background: var(--bg-dark-card);      /* the title keeps its 19.17:1 bar */
}
.project-name { color: #fff; font-weight: 650; font-size: var(--fs-h4); }
.project-outcome { color: var(--ink-dark-soft); font-size: .875rem; }
/* Hover darkens instead of blurring, so the title never drops to 3.34:1,
   and the chip is centred inside its own bounds. (CMP-05) */
.project > a::after {
  content: ""; position: absolute; inset: 0; z-index: 1;
  background: rgb(10 10 10 / 0);
  transition: background var(--t);
  pointer-events: none;
}
.project > a:hover::after, .project > a:focus-visible::after { background: rgb(10 10 10 / .55); }
.project-chip {
  position: absolute; inset-block-start: 50%; inset-inline-start: 50%;
  z-index: 2; translate: -50% -50%;
  padding: .5rem 1rem; border-radius: var(--r-pill);
  background: #fff; color: #0a0a0a; font-weight: 650; font-size: .875rem;
  opacity: 0; transition: opacity var(--t);
  pointer-events: none; white-space: nowrap;
}
.project > a:hover .project-chip, .project > a:focus-visible .project-chip { opacity: 1; }

/* ── services ────────────────────────────────────────────────────────── */
.services { display: grid; gap: var(--s2); grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr)); }
.service { display: grid; align-content: start; gap: .625rem; }
.service p { color: var(--ink-dark-soft); font-size: .9375rem; }

/* ── process ─────────────────────────────────────────────────────────── */
.steps { display: grid; gap: var(--s2); grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr)); }
.step { display: grid; align-content: start; gap: .5rem; }
/* Decorative numerals: kept visually, marked aria-hidden in the markup, and
   lifted off 1.32:1 because they are still rendered text. (CLR-04) */
.step-index { font-family: var(--mono); font-size: .875rem; font-weight: 700; color: var(--accent-on-light); }
.step p:last-child { color: var(--ink-soft); font-size: .9375rem; }

/* ── testimonials ────────────────────────────────────────────────────── */
.quotes { display: grid; gap: var(--s2); grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr)); }
.quote { display: grid; align-content: start; gap: var(--s2); }
.quote-flag {
  align-self: start; padding: .25rem .5rem; border-radius: var(--r-sm);
  background: var(--bg-section); color: var(--ink-soft);
  font-size: .6875rem; font-weight: 700; letter-spacing: .06em; text-transform: uppercase;
}
.quote blockquote { margin: 0; }
.quote blockquote p { font-size: 1.0625rem; }
.quote-by { display: grid; }
.quote-by b { font-weight: 650; }
.quote-by span { color: var(--ink-soft); font-size: .875rem; }

/* ── pricing ─────────────────────────────────────────────────────────── */
.tiers { display: grid; gap: var(--s2); grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr)); }
/* name → price → features → CTA. The old cards put the CTA above the
   feature list, and the list rendered outside the card. (CNV-01) */
.tier { display: grid; align-content: start; gap: var(--s2); }
.tier-kind { display: flex; flex-wrap: wrap; gap: .375rem; }
.tier-name { font-size: var(--fs-h3); }
.tier-price { display: flex; align-items: baseline; gap: .5rem; flex-wrap: wrap; }
.tier-price b { font-family: var(--display); font-size: 2.25rem; font-weight: 700; letter-spacing: -.03em; line-height: 1; }
.tier-price span { color: var(--ink-soft); font-size: .9375rem; font-weight: 600; }
.tier-desc { color: var(--ink-soft); font-size: .9375rem; }
.tier-featured { border-color: var(--accent-on-light); box-shadow: 0 0 0 1px var(--accent-on-light), var(--shadow-lg); }
.ticks { display: grid; gap: .5rem; }
.ticks li { position: relative; padding-inline-start: 1.625rem; font-size: .9375rem; }
.ticks li::before {
  content: ""; position: absolute; inset-inline-start: 0; inset-block-start: .45em;
  inline-size: .875rem; block-size: .5rem;
  border-inline-start: 2px solid var(--accent-on-light);
  border-block-end: 2px solid var(--accent-on-light);
  rotate: -45deg;
}
.tier-cta { margin-block-start: auto; }

/* ── FAQ ─────────────────────────────────────────────────────────────── */
.faq { display: grid; gap: .625rem; }
/* Rows are interactive, so their boundary owes 3:1 against the section —
   the old rows separated at 1.06:1. (SC 1.4.11) */
.faq-item {
  background: var(--bg);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-md);
  overflow: hidden;
}
.faq-item h3 { margin: 0; font-size: inherit; }
.faq-q {
  inline-size: 100%;
  display: flex; align-items: center; justify-content: space-between; gap: var(--s2);
  min-block-size: 3.5rem; padding: var(--s2);
  background: none; border: 0;
  font: inherit; font-size: 1.0625rem; font-weight: 650; text-align: start;
  color: var(--ink); cursor: pointer;
}
.faq-q:hover { color: var(--accent-on-light); }
/* The open state is carried by rotation and a fill, not by colour alone. (SC 1.4.1) */
.faq-icon {
  position: relative; flex: none;
  inline-size: 1.75rem; block-size: 1.75rem; border-radius: 50%;
  background: var(--bg-dark);
  transition: rotate var(--t), background var(--t-fast);
}
.faq-icon::before, .faq-icon::after {
  content: ""; position: absolute; inset-block-start: 50%; inset-inline-start: 50%;
  translate: -50% -50%;
  background: #fff; border-radius: 2px;
}
.faq-icon::before { inline-size: .75rem; block-size: 2px; }
.faq-icon::after  { inline-size: 2px; block-size: .75rem; transition: opacity var(--t-fast); }
.faq-q[aria-expanded="true"] .faq-icon { rotate: 135deg; background: var(--accent-on-light); }
.faq-q[aria-expanded="true"] .faq-icon::after { opacity: 0; }
.faq-a { display: grid; grid-template-rows: 0fr; transition: grid-template-rows var(--t); }
.faq-a > p {
  overflow: hidden;
  padding-inline: var(--s2);
  color: var(--ink-soft);
  visibility: hidden;
}
.faq-item[data-open="true"] .faq-a { grid-template-rows: 1fr; }
.faq-item[data-open="true"] .faq-a > p { visibility: visible; padding-block-end: var(--s2); }
.faq-item[data-open="true"] { border-color: var(--accent-on-light); }

/* ── contact + forms ─────────────────────────────────────────────────── */
.contact-grid { display: grid; gap: var(--s4); grid-template-columns: repeat(auto-fit, minmax(19rem, 1fr)); }
.contact-direct { display: grid; gap: .625rem; margin-block-start: var(--s3); }
.contact-direct li { display: flex; flex-wrap: wrap; gap: .5rem; color: var(--ink-dark-soft); }
.contact-direct span { min-inline-size: 4.5rem; color: var(--ink-dark-soft); font-weight: 600; }

.form { display: grid; gap: var(--s2); align-content: start; }
.form-hint { color: var(--ink-dark-soft); font-size: .875rem; }
.field { display: grid; gap: .375rem; }
.field label { font-weight: 600; font-size: .9375rem; }
.section-dark .field label, .footer .field label { color: #fff; }
.req { color: var(--accent-on-dark); }
/* Placeholder-only fields failed SC 3.3.2 and sat at 3.87–3.98:1; every
   field now has a real label, so no placeholder is load-bearing. */
input, textarea {
  inline-size: 100%; min-block-size: 2.75rem;
  padding: .625rem .75rem;
  background: var(--bg-dark-lift); color: #fff;
  border: 1.5px solid var(--line-dark-strong);   /* 3.47:1 boundary, was 1.06:1 */
  border-radius: var(--r-sm);
  font: inherit;
}
textarea { min-block-size: 6rem; resize: vertical; }
input:hover, textarea:hover { border-color: #8a8a8a; }
input[aria-invalid="true"], textarea[aria-invalid="true"] { border-color: #ff8fa3; }
.err { color: #ffb3c1; font-size: .875rem; font-weight: 500; }   /* 9.6:1 on #171717 */
.form-status { font-weight: 600; min-block-size: 1.5rem; }
.form-status[data-state="ok"]  { color: #7ce0b0; }
.form-status[data-state="bad"] { color: #ffb3c1; }

/* ── footer ──────────────────────────────────────────────────────────── */
.footer {
  position: relative; overflow: hidden;
  background: var(--bg-dark-card); color: var(--ink-dark-soft);
  padding-block: var(--s6) var(--s3);
}
.footer-inner {
  display: grid; gap: var(--s4);
  grid-template-columns: minmax(14rem, 1fr) minmax(0, 2fr) minmax(15rem, 1fr);
}
.footer-brand p { margin-block-start: var(--s2); font-size: .9375rem; max-inline-size: 26ch; }
.footer-brand .wordmark { color: #fff; }
.footer-cols { display: grid; gap: var(--s3); grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr)); }
.footer-h { font-size: .8125rem; font-weight: 700; letter-spacing: .1em; text-transform: uppercase; color: #fff; }
.footer-cols ul { margin-block-start: var(--s2); display: grid; gap: .125rem; }
.footer-cols a, .footer-legalish a {
  display: inline-flex; align-items: center; min-block-size: 2.25rem;
  color: var(--ink-dark-soft); text-decoration: none; font-size: .9375rem;
}
.footer-cols a:hover, .footer-legalish a:hover { color: #fff; text-decoration: underline; text-underline-offset: 3px; }
.newsletter p { font-size: .9375rem; margin-block: var(--s1) var(--s2); }
.newsletter-row { display: flex; flex-wrap: wrap; gap: .5rem; }
.newsletter-row input { flex: 1 1 12rem; }
.footer-base {
  display: flex; flex-wrap: wrap; gap: var(--s2); justify-content: space-between;
  margin-block-start: var(--s5); padding-block-start: var(--s3);
  border-block-start: 1px solid var(--line-dark);
}
.copyright { color: var(--ink-faint); font-size: .875rem; }   /* 5.55:1, was 1.52:1 */
.footer-ghost {
  position: absolute; inset-block-end: -2.5rem; inset-inline-start: 50%;
  translate: -50% 0;
  font-family: var(--display); font-size: clamp(4rem, 18vw, 12rem); font-weight: 700;
  letter-spacing: -.04em; color: #282828; line-height: 1;
  pointer-events: none; user-select: none;
}

/* ── reveal: the fix for the audit's worst motion finding ─────────────
   The old build animated heading colour from #DFE0E4 to #0F0F0F, so a
   heading at rest measured 1.16:1 — legible-but-unreadable. Now the text
   is either absent (opacity 0) or fully legible; nothing in between, and
   the final colour is the only colour. (MOT-01, blocker 4)
   Without JS the .js gate never applies, so everything renders visible. */
.js .reveal > span {
  display: inline-block;
  opacity: 0;
  translate: 0 12px;
  transition: opacity var(--t-slow), translate var(--t-slow);
  transition-delay: var(--d, 0ms);
}
.js .reveal[data-shown="true"] > span { opacity: 1; translate: 0 0; }

.js .rise {
  opacity: 0; translate: 0 16px;
  transition: opacity var(--t-slow), translate var(--t-slow);
  transition-delay: var(--d, 0ms);
}
.js .rise[data-shown="true"] { opacity: 1; translate: 0 0; }

/* ── reduced motion: end states rendered, nothing scrubbed or looping ──
   The audit's single most important live test was whether reduced motion
   left headings permanently grey. Here it renders them, then stops. (MOT-02) */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
  }
  .js .reveal > span, .js .rise { opacity: 1 !important; translate: none !important; }
  .hero-glow, .cta-card-bg { animation: none !important; }
  .btn:hover { transform: none; }
}

/* ── responsive ──────────────────────────────────────────────────────── */
@media (max-width: 60rem) {
  .hero-inner { grid-template-columns: 1fr; }
  .hero-side { justify-items: stretch; }
  .hero-render { inline-size: 100%; }
  .capabilities { text-align: start; }
  .capabilities button { justify-content: flex-start; border-inline-end: 0; border-inline-start: 2px solid transparent; }
  .capabilities button[aria-expanded="true"] { border-inline-start-color: var(--accent-on-dark); }
  .footer-inner { grid-template-columns: 1fr; }
}
@media (max-width: 48rem) {
  :root { --s7: 4rem; --s6: 3rem; }
  .nav-links, .nav-cta { display: none; }
  .nav-toggle { display: grid; place-items: center; }
  .cta-card-inner { padding: var(--s4) var(--s3); }
}
@media (min-width: 48rem) {
  .mobile-menu { display: none !important; }
}

/* Print: the page is a proposal attachment often enough to matter — and a
   reveal left at opacity 0 would print a blank column. */
@media print {
  .js .reveal > span, .js .rise { opacity: 1 !important; translate: none !important; }
  .nav, .skip-link, .footer-ghost, .hero-glow { display: none !important; }
  body { color: #000; }
  .section, .section-dark, .hero, .footer { background: #fff !important; color: #000 !important; }
  .section-dark .h2, .section-dark .h3, .section-dark .h4, .hero-title { color: #000 !important; }
}
