/* ==========================================================================
   Fonts — self-hosted
   --------------------------------------------------------------------------
   These used to load from fonts.googleapis.com. Serving them from Google's
   CDN sends every visitor's IP address to Google before they have consented
   to anything, which is the exact fact pattern the Munich Regional Court
   ruled on in 2022 (LG Munchen I, 3 O 17493/20) when it awarded damages
   against a site operator. Self-hosting removes the third-party request
   entirely, so no consent is needed and no cookie banner is required for it.

   It is also faster: two DNS lookups, two TLS handshakes and a render-
   blocking stylesheet are gone, replaced by files on the same origin.

   Only the seven faces the site actually renders are shipped, confirmed by
   walking every visible element and reading its computed family and weight.
   Adding a weight to the CSS without adding the file here will silently
   synthesise a fake bold, so keep the two in step.
   ========================================================================== */

@font-face {
  font-family: "Archivo";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("../assets/fonts/archivo-latin-700-normal.woff2") format("woff2");
}

@font-face {
  font-family: "Archivo";
  font-style: normal;
  font-weight: 800;
  font-display: swap;
  src: url("../assets/fonts/archivo-latin-800-normal.woff2") format("woff2");
}

@font-face {
  font-family: "IBM Plex Sans";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("../assets/fonts/ibm-plex-sans-latin-400-normal.woff2") format("woff2");
}

@font-face {
  font-family: "IBM Plex Sans";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("../assets/fonts/ibm-plex-sans-latin-500-normal.woff2") format("woff2");
}

@font-face {
  font-family: "IBM Plex Sans";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("../assets/fonts/ibm-plex-sans-latin-600-normal.woff2") format("woff2");
}

@font-face {
  font-family: "IBM Plex Mono";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("../assets/fonts/ibm-plex-mono-latin-400-normal.woff2") format("woff2");
}

@font-face {
  font-family: "IBM Plex Mono";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("../assets/fonts/ibm-plex-mono-latin-500-normal.woff2") format("woff2");
}

/* ==========================================================================
   Spearlight — Design Tokens
   ========================================================================== */

:root {
  /* Dark surface stack — true near-black, no colored glow */
  /* Surfaces sit deliberately above the canvas. They used to be #0d0e10 on
     #050506 — an 8-point step, which is elegant on a calibrated monitor in a
     dark room and completely invisible on a laptop in a bright office, where
     the service and process cards simply vanished. ~16 points of separation
     survives normal viewing conditions without turning the page grey.
     --surface-glass is the translucent equivalent for the blurred panels; it
     resolves to roughly --surface-1 once composited over the canvas, so a
     glass panel and a solid card read as the same elevation. */
  --canvas: #050506;
  --surface-1: #15161a;
  --surface-2: #1e1f25;
  --surface-glass: rgba(29, 31, 37, 0.66);
  --hairline: #32343a;
  --hairline-soft: #202228;
  --ink: #f4f4f1;
  --ink-high: rgba(244, 244, 241, 0.87);
  --ink-med: rgba(244, 244, 241, 0.6);
  --ink-muted: var(--ink-med);

  /* Accent — used sparingly: links, hover, one highlighted word. Never a fill. */
  --accent: #ef4444;
  --accent-soft: rgba(239, 68, 68, 0.12);
  --accent-2: #ff9b52;

  /* Fonts */
  /* Type system: Archivo is the anchor (headlines, section titles), with the
     IBM Plex super-family underneath — Plex Sans for body, Plex Mono for
     labels/numerals. Sans and Mono are designed together, so they read as a
     deliberate pair rather than two grotesques that happen to look alike
     (the previous Inter + Archivo combination was indistinguishable below
     ~24px, which meant the pairing produced no contrast at all). */
  --font-display: "Archivo", "Arial Narrow", sans-serif;
  --font-mono: "IBM Plex Mono", ui-monospace, "SFMono-Regular", monospace;
  --font-body: "IBM Plex Sans", -apple-system, BlinkMacSystemFont, sans-serif;

  /* Type scale */
  --fs-hero: clamp(2.6rem, 1.9rem + 4vw, 5.75rem);
  --fs-display-lg: clamp(2rem, 1.5rem + 2.3vw, 3.4rem);
  --fs-display-md: clamp(1.5rem, 1.3rem + 1vw, 2rem);
  --fs-headline: clamp(1.15rem, 1.05rem + 0.4vw, 1.35rem);
  --fs-subhead: clamp(1.1rem, 1rem + 0.4vw, 1.35rem);
  --fs-body-lg: 1.125rem;
  --fs-body: 1rem;
  --fs-body-sm: 0.9rem;
  --fs-caption: 0.8125rem;
  --fs-micro: 0.75rem;
  --fs-mono-label: 0.75rem;

  /* Radius scale — small and boxy, not pill */
  --radius-xs: 3px;
  --radius-sm: 6px;
  --radius-md: 8px;
  --radius-lg: 12px;
  --radius-xl: 16px;
  /* Reserved for large atmospheric media panels (service/process cards) —
     everything else in the system stays boxy on purpose. */
  --radius-2xl: 20px;

  /* Spacing scale */
  --space-3xs: 4px;
  --space-2xs: 8px;
  --space-xs: 12px;
  --space-sm: 16px;
  --space-md: 24px;
  --space-lg: 32px;
  --space-xl: 48px;
  --space-2xl: 64px;
  --space-3xl: 96px;
  --space-4xl: 144px;

  /* Service panel imagery. The four renders come from different shoots with
     different grades, so they're pulled toward each other here rather than
     re-exported: partial desaturation stops any one accent (the green network
     graph especially) dominating the column, and a slight knock-back keeps the
     panels behind the copy. Full colour returns on hover. Tune these three. */
  --media-saturate: 0.5;
  --media-brightness: 0.82;
  --media-opacity: 0.92;

  --container-max: 1180px;
  --ease: cubic-bezier(0.16, 1, 0.3, 1);

  /* Fractal-noise grain, tiled as a fixed full-page overlay (see body::after) —
     ties the "cinematic" positioning to an actual film-grain cue. */
  --noise: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* ==========================================================================
   Reset
   ========================================================================== */

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

html {
  scroll-behavior: smooth;
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

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

/* Fixed film-grain layer over the whole page — subtle enough not to read
   consciously, but reinforces "cinematic" rather than sitting flat/digital. */
body::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 9999;
  pointer-events: none;
  background-image: var(--noise);
  background-size: 120px 120px;
  opacity: 0.035;
  mix-blend-mode: overlay;
}

@media (prefers-reduced-motion: reduce) {
  body::after {
    display: none;
  }
}

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

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

ul {
  list-style: none;
  margin: 0;
  padding: 0;
}

h1,
h2,
h3,
p {
  margin: 0;
}

button {
  font: inherit;
  cursor: pointer;
}

/* ==========================================================================
   Layout primitives
   ========================================================================== */

.container {
  max-width: var(--container-max);
  margin-inline: auto;
  padding-inline: var(--space-lg);
}

@media (max-width: 600px) {
  .container {
    padding-inline: var(--space-md);
  }
}

/* padding-top only, not padding-block: every section's background is the
   same canvas color, so the visible gap between two sections is whichever
   one number sits between their content — the lower section's padding-top.
   padding-block on both neighbors would sum instead (a tight section next
   to a full one reading as a different gap than two tights in a row). The
   very first section (hero) supplies its own top spacing, and the footer
   supplies its own before the last section. */
/* Section rhythm. The two tiers were 96px / 48px, and because --tight sits on
   six of the eleven sections the page's dominant gap was 48px — smaller than a
   single line of the 54px section titles it was supposed to separate, which is
   what made the whole thing read as cramped. Both tiers are now comfortably
   larger than the display type, and the 1.6:1 ratio between them keeps the
   "these two belong together" pairings legible as a deliberate choice. */
.section {
  background: var(--canvas);
  color: var(--ink);
  padding-top: var(--space-4xl);
}

.section--tight {
  padding-top: 88px;
}

/* Sections that end in flowing text rather than in a bounded panel need
   their own bottom padding. The next section's padding-top alone reads as
   tight when there's no card edge closing the block off — the process
   stepper running straight into the founder panel was the case that
   showed it. */
.section--pb {
  padding-bottom: var(--space-xl);
}

/* Hosts a full-bleed backdrop. The extra bottom padding is what gives the
   scrim's final stops somewhere to land, so the image fades out inside the
   section instead of being cut off at its edge. */
.section--backdrop {
  position: relative;
  overflow: hidden;
  padding-bottom: var(--space-2xl);
}

@media (max-width: 810px) {
  .section {
    padding-top: var(--space-3xl);
  }

  .section--tight {
    padding-top: var(--space-2xl);
  }

  .section--pb {
    padding-bottom: var(--space-lg);
  }
}

@media (max-width: 600px) {
  .section {
    padding-top: 80px;
  }

  .section--tight {
    padding-top: var(--space-xl);
  }
}

.section-head {
  max-width: 620px;
  margin-bottom: var(--space-3xl);
}

@media (max-width: 810px) {
  .section-head {
    margin-bottom: var(--space-2xl);
  }
}

.section-head--center {
  max-width: 640px;
  margin-inline: auto;
  text-align: center;
}

/* Flat poster-tag chip (reference: sanjaya.framer.ai section labels —
   "SERVICES", "OUR WORKS") — a translucent ink wash with square corners
   and a left accent bar, instead of a bordered/rounded pill. */
.eyebrow {
  position: relative;
  display: inline-flex;
  align-items: center;
  font-family: var(--font-mono);
  font-size: var(--fs-mono-label);
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink);
  margin-bottom: var(--space-md);
  padding: 6px 10px 6px 14px;
  border-radius: var(--radius-xs);
  background: rgba(244, 244, 241, 0.08);
}

.eyebrow::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 2px;
  background: var(--accent);
}

.section-title {
  font-family: var(--font-display);
  font-size: var(--fs-display-lg);
  font-weight: 800;
  line-height: 1.05;
  letter-spacing: -0.02em;
  /* Evens out the rag on multi-line headings instead of leaving a long first
     line and an orphaned last one. Ignored by browsers that don't support it. */
  text-wrap: balance;
}

.section-title--sm {
  font-size: var(--fs-display-md);
}

.section-sub {
  font-size: var(--fs-body-lg);
  color: var(--ink-muted);
  margin-top: var(--space-sm);
  max-width: 52ch;
  /* Evens the rag so a sub can't end on a single orphaned word — the pricing
     sub was breaking as "...in the same / range.". `pretty` doesn't catch
     this case in current Chromium, `balance` does. */
  text-wrap: balance;
}

/* ==========================================================================
   Typography helpers
   ========================================================================== */

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

.mono {
  font-family: var(--font-mono);
}

/* ==========================================================================
   Buttons — boxy, monospace label, no pills
   ========================================================================== */

.btn {
  --btn-scale: 1;
  display: inline-flex;
  align-items: center;
  gap: var(--space-2xs);
  padding: 12px 20px;
  border-radius: var(--radius-sm);
  font-family: var(--font-mono);
  font-size: var(--fs-mono-label);
  font-weight: 500;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  border: 1px solid transparent;
  transform: scale(var(--btn-scale));
  transition: transform 0.25s var(--ease), background 0.2s var(--ease), border-color 0.2s var(--ease), color 0.2s var(--ease);
  white-space: nowrap;
}

.btn:active {
  --btn-scale: 0.97;
}

.btn-primary {
  background: var(--ink);
  color: var(--canvas);
  border-color: var(--ink);
}

.btn-primary:hover {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--canvas);
}

.btn-secondary {
  background: transparent;
  color: var(--ink);
  border-color: var(--hairline);
}

.btn-secondary:hover {
  border-color: var(--accent);
  color: var(--accent);
}

/* Sliding chevron — same duplicate-layer trick as the work-card CTA, kept
   here at the shared .btn level so every button on the site gets the same
   micro-interaction without touching each variant's color/weight. */
.btn-arrow {
  display: inline-block;
  overflow: hidden;
  width: 14px;
  height: 14px;
}

.btn-arrow-track {
  display: flex;
  align-items: center;
  gap: 6px;
  width: max-content;
  transition: transform 0.3s var(--ease);
}

.btn-arrow-track svg {
  flex-shrink: 0;
}

.btn:hover .btn-arrow-track {
  transform: translateX(-20px);
}

/* ==========================================================================
   Nav
   ========================================================================== */

.nav {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 100;
  height: 64px;
  display: flex;
  align-items: center;
  background: rgba(5, 5, 6, 0.78);
  backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--hairline-soft);
  transition: background 0.4s var(--ease), backdrop-filter 0.4s var(--ease), border-color 0.4s var(--ease);
}

/* While the hero is in view (toggled in main.js), the nav blends into its
   image instead of sitting on its own bar. */
.nav--transparent {
  background: transparent;
  backdrop-filter: none;
  border-bottom-color: transparent;
}

.nav-inner {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.nav-logo {
  display: flex;
  align-items: center;
}

.nav-logo-img {
  height: 28px;
  width: auto;
  display: block;
}

.nav-links {
  display: flex;
  align-items: center;
  gap: var(--space-lg);
  font-family: var(--font-mono);
  font-size: var(--fs-mono-label);
  letter-spacing: 0.03em;
  color: var(--ink-muted);
}

.nav-links a:hover {
  color: var(--ink);
}

.availability {
  display: flex;
  align-items: center;
  gap: var(--space-2xs);
  font-family: var(--font-mono);
  font-size: var(--fs-mono-label);
  color: var(--ink-muted);
  letter-spacing: 0.02em;
  white-space: nowrap;
}

.availability-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: #3ddc73;
  box-shadow: 0 0 0 0 rgba(61, 220, 115, 0.6);
  animation: availability-pulse 2s ease-out infinite;
}

/* Quarter is full. Amber rather than green, and the pulse stops: the badge
   still says something true and still invites contact, it just stops
   implying "start tomorrow". */
.availability-dot.is-full {
  background: #e0a33c;
  animation: none;
  box-shadow: none;
}

@keyframes availability-pulse {
  0% { box-shadow: 0 0 0 0 rgba(61, 220, 115, 0.55); }
  70% { box-shadow: 0 0 0 6px rgba(61, 220, 115, 0); }
  100% { box-shadow: 0 0 0 0 rgba(61, 220, 115, 0); }
}

.nav-cta {
  display: flex;
  align-items: center;
  gap: var(--space-lg);
}

.nav-toggle {
  display: none;
  background: none;
  border: none;
  color: var(--ink);
  padding: var(--space-2xs);
}

@media (max-width: 810px) {
  .nav-links {
    position: fixed;
    top: 64px;
    left: 0;
    right: 0;
    background: var(--canvas);
    border-bottom: 1px solid var(--hairline-soft);
    flex-direction: column;
    align-items: flex-start;
    gap: 0;
    padding: var(--space-sm) var(--space-md);
    transform: translateY(-8px);
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.2s var(--ease), transform 0.2s var(--ease);
  }

  .nav-links a {
    width: 100%;
    padding: var(--space-sm) 0;
    border-bottom: 1px solid var(--hairline-soft);
  }

  .nav-links.is-open {
    opacity: 1;
    transform: translateY(0);
    pointer-events: auto;
  }

  .nav-toggle {
    display: block;
  }

  .availability {
    display: none;
  }
}

/* Nav CTA and hero pill responsive swaps live at the end of this file, so
   they win the cascade against the base rules declared alongside them. */

/* ==========================================================================
   Hero
   ========================================================================== */

.hero {
  position: relative;
  min-height: 100dvh;
  overflow: hidden;
  display: flex;
}

.hero-media {
  position: absolute;
  inset: 0;
  z-index: 0;
}

.hero-bg {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 65%;
}

/* Two jobs: hold contrast under the nav and headline, and dissolve the video
   into the page. The last stop has to reach full opacity in the canvas colour
   — it previously stopped at 0.92, which left a faint but visible seam where
   the hero ended and the next section began. The extra stop at 78% keeps the
   ramp gradual so the fade reads as atmosphere rather than a band. */
.hero-scrim {
  position: absolute;
  inset: 0;
  background: linear-gradient(
    180deg,
    rgba(5, 5, 6, 0.7) 0%,
    rgba(5, 5, 6, 0.2) 30%,
    rgba(5, 5, 6, 0.28) 55%,
    rgba(5, 5, 6, 0.72) 78%,
    rgba(5, 5, 6, 0.95) 92%,
    rgba(5, 5, 6, 1) 100%
  );
}

/* With .hero-top removed there's only one child left, so the old
   space-between has nothing to space — flex-end keeps the eyebrow, headline
   and CTAs anchored to the bottom of the frame and lets the video hold the
   whole upper two-thirds uninterrupted. */
.hero-inner {
  position: relative;
  z-index: 1;
  width: 100%;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  padding-top: calc(64px + var(--space-xl));
  padding-bottom: var(--space-2xl);
}

/* The eyebrow moved out of .hero-top and now sits directly above the
   headline, where it labels what the studio does at the moment the reader
   is already looking. It keeps the standard eyebrow treatment (ink wash,
   left accent bar, square corners) — only the bottom margin differs, since
   here it's spacing itself off a display-size headline. */
.hero-eyebrow {
  margin-bottom: var(--space-md);
  color: var(--ink-high);
}

/* .hero-sub and .hero-top removed along with the top-right line.
   .hero-pill removed — the "7+ Years" claim it carried is already stated,
   more precisely, by the trust strip immediately below the hero. */

.hero-headline {
  font-family: var(--font-display);
  font-size: clamp(2.75rem, 2.1rem + 4vw, 5.5rem);
  font-weight: 800;
  line-height: 1.02;
  letter-spacing: -0.03em;
  position: relative;
}

.hero-headline .frag {
  display: block;
  opacity: 0;
  filter: blur(10px);
  transform: translateY(0.4em);
  transition: opacity 0.9s var(--ease), transform 0.9s var(--ease), filter 0.9s var(--ease);
}

.hero-headline.is-visible .frag {
  opacity: 1;
  filter: blur(0);
  transform: translateY(0);
}

.hero-headline .frag:nth-child(1) { transition-delay: 0.05s; }
.hero-headline .frag:nth-child(2) { transition-delay: 0.15s; }

.hero-headline .accent-text {
  color: var(--accent);
}

.hero-actions {
  display: flex;
  justify-content: flex-start;
  gap: var(--space-sm);
  margin-top: var(--space-xl);
  flex-wrap: wrap;
}

@media (max-width: 600px) {
  .hero-inner {
    padding-top: calc(64px + var(--space-lg));
  }
}

/* The .trust-strip stat trio was removed from index.html; its styles went
   with it. The client logos below are what this section carries now. */

/* Client logo marquee */

.marquee-label {
  margin-top: var(--space-xl);
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink-muted);
}

.marquee {
  overflow: hidden;
  position: relative;
  margin-top: var(--space-md);
  -webkit-mask-image: linear-gradient(90deg, transparent, black 8%, black 92%, transparent);
  mask-image: linear-gradient(90deg, transparent, black 8%, black 92%, transparent);
}

.marquee-track {
  display: flex;
  align-items: center;
  width: max-content;
  gap: var(--space-3xl);
  animation: marquee-scroll 22s linear infinite;
}

.marquee:hover .marquee-track {
  animation-play-state: paused;
}

.marquee-item {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--fs-headline);
  letter-spacing: -0.01em;
  color: var(--ink-muted);
  white-space: nowrap;
}

/* Every logo is exported onto an identical 72px-tall canvas with its artwork
   pre-scaled to a matched ink area, so setting one height here preserves the
   optical balance instead of making whichever logo has the tallest bounding
   box dominate. grayscale() is gone — the source files are pure white now. */
.marquee-logo {
  height: clamp(22px, 2.6vw, 30px);
  width: auto;
  object-fit: contain;
  opacity: 0.72;
  transition: opacity 0.3s var(--ease);
}

.marquee:hover .marquee-logo {
  opacity: 0.95;
}

@keyframes marquee-scroll {
  from {
    transform: translateX(0);
  }
  to {
    transform: translateX(-50%);
  }
}

@media (prefers-reduced-motion: reduce) {
  .marquee-track {
    animation: none;
  }
}

@media (max-width: 700px) {
  .marquee-track {
    gap: var(--space-2xl);
  }

  .marquee-item {
    font-size: var(--fs-body-lg);
  }
}

/* ==========================================================================
   Showreel
   ========================================================================== */

.showreel-shell {
  padding: 10px;
  border-radius: calc(var(--radius-md) + 10px);
  background: linear-gradient(155deg, var(--surface-2) 0%, var(--surface-1) 100%);
  border: 1px solid var(--hairline);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.06);
}

.showreel-frame {
  position: relative;
  aspect-ratio: 16 / 9;
  border-radius: var(--radius-md);
  overflow: hidden;
  background: var(--surface-1);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.05), 0 20px 50px rgba(0, 0, 0, 0.45);
  display: flex;
  align-items: center;
  justify-content: center;
}

.showreel-frame video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* The reel carries no audio track, so the native volume control is dead UI: it
   invites a click that changes nothing, which reads as a broken player. Chrome
   does not drop the control on its own when a file has no audio (verified in
   Chromium against a pair of test files, with and without a track), so it is
   removed here. WebKit pseudo-elements cover Chrome, Edge and Safari; Firefox
   has no equivalent and keeps its own control, which is the acceptable
   fallback. Delete this whole rule the day a reel with sound ships. */
.showreel-frame video.is-silent::-webkit-media-controls-mute-button,
.showreel-frame video.is-silent::-webkit-media-controls-volume-slider,
.showreel-frame video.is-silent::-webkit-media-controls-volume-control-container {
  display: none !important;
}

.showreel-caption {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  margin-top: var(--space-md);
  color: var(--ink-muted);
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  letter-spacing: 0.02em;
  text-transform: uppercase;
}

/* ==========================================================================
   Portfolio — 2-up grid, media locked to 16:9 (the ratio most of the real
   stills/renders will actually be delivered in, so the crop stays honest).
   Anatomy reuses the same numbered-row language as Services so the two
   sections read as one family instead of two different components.

   Full-bleed on purpose: this is the one section whose entire job is
   "show the work," so it's allowed to break past --container-max while
   the heading above it stays in the normal container — everything else
   on the page keeps the standard reading-width rhythm.
   ========================================================================== */

.work-grid-wrap {
  width: 100%;
  /* Meaningfully wider than --container-max (1180px) everywhere, but capped
     so the section doesn't turn into oversized wallpaper on ultrawide/4K
     displays — a ceiling, not a return to the standard reading width. */
  max-width: 1800px;
  margin-inline: auto;
  padding-inline: var(--space-lg);
}

@media (max-width: 600px) {
  .work-grid-wrap {
    padding-inline: var(--space-md);
  }
}

.work-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--space-lg);
}

.work-card {
  position: relative;
  display: flex;
  flex-direction: column;
  background: var(--surface-1);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-2xl);
  overflow: hidden;
}

.work-card-media {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9;
}

.work-card-media-img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.work-arrow {
  position: absolute;
  top: var(--space-md);
  right: var(--space-md);
  z-index: 2;
  width: 30px;
  height: 30px;
  /* Diamond facet instead of a generic circle — rhymes with the logomark. */
  clip-path: polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%);
  border: 1px solid rgba(255, 255, 255, 0.3);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--ink);
  font-size: 0.85rem;
  opacity: 0;
  transform: translate(-4px, 4px);
  transition: opacity 0.2s var(--ease), transform 0.2s var(--ease);
}

.work-card:hover .work-arrow {
  opacity: 1;
  transform: translate(0, 0);
}

.work-card-body {
  position: relative;
  z-index: 2;
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  padding: var(--space-lg);
}

.work-card-meta {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
}

.work-tag {
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--accent);
}

.work-card-title {
  font-family: var(--font-display);
  font-size: var(--fs-headline);
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--ink);
  margin-top: var(--space-sm);
}

.work-card-desc {
  font-size: var(--fs-body-sm);
  color: var(--ink-muted);
  margin-top: var(--space-2xs);
  margin-bottom: var(--space-md);
  line-height: 1.5;
}

/* Standalone button, deliberately not the sitewide .btn — a quieter, filled
   chip (reference: sanjaya.framer.ai "View Case Study") instead of the
   bordered/mono/uppercase treatment used for primary site CTAs. */
.work-card-cta {
  margin-top: auto;
  align-self: flex-start;
  display: inline-flex;
  align-items: center;
  gap: var(--space-2xs);
  padding: 12px 16px;
  border-radius: var(--radius-md);
  background: rgba(244, 244, 241, 0.08);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: var(--fs-body-sm);
  font-weight: 500;
  transition: background 0.25s var(--ease);
}

.work-card:hover .work-card-cta {
  background: rgba(244, 244, 241, 0.14);
}

.work-card-cta-label {
  display: inline-block;
  overflow: hidden;
  height: 1.3em;
  line-height: 1.3em;
}

.work-card-cta-label-track {
  display: flex;
  flex-direction: column;
  transition: transform 0.3s var(--ease);
}

.work-card-cta-label-track span {
  height: 1.3em;
  line-height: 1.3em;
  white-space: nowrap;
}

.work-card:hover .work-card-cta-label-track {
  transform: translateY(-1.3em);
}

.work-card-cta-arrows {
  display: inline-block;
  overflow: hidden;
  width: 14px;
  height: 14px;
}

.work-card-cta-arrows-track {
  display: flex;
  align-items: center;
  gap: 6px;
  width: max-content;
  transition: transform 0.3s var(--ease);
}

.work-card-cta-arrows-track svg {
  flex-shrink: 0;
}

.work-card:hover .work-card-cta-arrows-track {
  transform: translateX(-20px);
}

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

/* The .ph-1 and .ph-3 placeholder media treatments lived here as stand-ins
   until real footage arrived. All four work cards now carry a poster plus a
   hover loop, so nothing referenced them and they are gone. */

/* ==========================================================================
   Services — sticky intro column + stacked numbered rows, each pairing a
   feature list with an atmospheric media panel (reference: sanjaya.framer.ai
   "Built to Simplify Operations")
   ========================================================================== */

/* The intro rail was a fixed 300px, which forced "One studio, the full visual
   pipeline" to break across four lines with a ragged edge. Widening the rail
   and stepping the title down one size lets it set in two. */
.services-layout {
  display: grid;
  grid-template-columns: minmax(340px, 400px) 1fr;
  gap: var(--space-xl);
  align-items: start;
}

.services-intro {
  position: sticky;
  top: 96px;
}

.services-intro .section-title {
  font-size: clamp(1.9rem, 1.4rem + 1.5vw, 2.65rem);
  text-wrap: balance;
}

.services-intro .section-sub {
  max-width: 34ch;
}

.services-intro .industry-row {
  margin-top: var(--space-xl);
}

.services-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-md);
}

/* Text column now leads the media panel — at 1fr/1.1fr the copy column was
   ~340px, which wrapped "Product Visualization" and "Scientific
   Visualization" onto two lines. */
/* Same construction as .founder-panel: the media is flush to the panel edge
   and full height rather than floating inset with padding around it, so the
   card's own border-radius does the clipping. Mirrored, though — the founder
   photo sits left, service media sits right. */
.service-row {
  display: flex;
  align-items: stretch;
  gap: 0;
  overflow: hidden;
  border: 1px solid var(--hairline);
  border-radius: var(--radius-2xl);
  background: var(--surface-1);
  transition: background 0.3s var(--ease), border-color 0.3s var(--ease);
}

/* Padding lives on the copy now, not the panel, or the flush media would be
   inset by it. */
.service-row-text {
  flex: 1;
  min-width: 0;
  padding: var(--space-lg);
}

.service-row:hover {
  background: var(--surface-2);
  border-color: var(--hairline);
}

.service-row-num {
  display: block;
  font-family: var(--font-mono);
  font-size: var(--fs-mono-label);
  letter-spacing: 0.04em;
  color: var(--ink-muted);
}

.service-row-title {
  font-family: var(--font-display);
  /* One step below --fs-display-md: these are service names inside a card,
     not section headings, and the smaller cap lets the two long ones set on
     a single line. */
  font-size: clamp(1.35rem, 1.15rem + 0.6vw, 1.75rem);
  font-weight: 700;
  line-height: 1.15;
  letter-spacing: -0.01em;
  text-wrap: balance;
  margin-top: var(--space-2xs);
}

.service-row-sub {
  font-size: var(--fs-body-sm);
  color: var(--ink-muted);
  line-height: 1.5;
  margin-top: var(--space-2xs);
}

.service-row-features {
  list-style: none;
  margin: var(--space-md) 0 0;
  padding: 0;
}

.service-row-features li {
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--ink-muted);
  padding: 10px 0;
  border-top: 1px solid var(--hairline-soft);
}

.service-row-media {
  --media-size: clamp(200px, 22vw, 300px);
  flex-shrink: 0;
  width: var(--media-size);
  border-left: 1px solid var(--hairline);
  overflow: hidden;
}

/* Square masters, centre-cropped. The panel runs from a 0.57 portrait on
   desktop to a 1.60 banner on mobile, so cover is doing real work here. */
.service-row-media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  filter: saturate(var(--media-saturate)) brightness(var(--media-brightness));
  opacity: var(--media-opacity);
  transition: filter 0.45s var(--ease), opacity 0.45s var(--ease);
}

/* Hovering the row restores the render to full colour — the image is proof of
   the service, so it should reward attention rather than stay muted. */
.service-row:hover .service-row-media img {
  filter: saturate(1) brightness(1);
  opacity: 1;
}

@media (prefers-reduced-motion: reduce) {
  .service-row-media img {
    transition: none;
  }
}

/* Staggered entrance, same cascade rhythm as the portfolio grid. */
.service-row:nth-child(1) { transition-delay: 0s; }
.service-row:nth-child(2) { transition-delay: 0.08s; }
.service-row:nth-child(3) { transition-delay: 0.16s; }
.service-row:nth-child(4) { transition-delay: 0.24s; }

/* Placeholder media treatments — stand-ins until real stills/footage are
   supplied, deliberately distinct from the portfolio grid's .ph-* set above
   so the two sections don't read as reusing the same tiles. */
.sv-ph-1 { background: radial-gradient(ellipse at 25% 75%, #1c2f4a 0%, #06070a 60%); }
.sv-ph-2 { background: linear-gradient(200deg, #33261a 0%, #0a0908 60%); }
.sv-ph-3 {
  background:
    repeating-linear-gradient(135deg, rgba(255, 155, 82, 0.1) 0 1px, transparent 1px 40px),
    #0a0a0c;
}
.sv-ph-4 { background: radial-gradient(ellipse at 70% 20%, #2a1030 0%, #0a0a0d 65%); }

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

  .services-intro {
    position: static;
  }
}

@media (max-width: 700px) {
  /* Stacked: media becomes a banner across the top, so the divider moves from
     the left edge to the bottom and the fixed width is released. */
  .service-row {
    flex-direction: column;
  }

  .service-row-media {
    order: -1;
    width: 100%;
    aspect-ratio: 16 / 10;
    border-left: none;
    border-bottom: 1px solid var(--hairline);
  }
}

/* ==========================================================================
   Industries — inline tag row
   ========================================================================== */

.industry-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2xs);
  margin-top: var(--space-lg);
}

.industry-badge {
  padding: 6px 14px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--hairline);
  font-family: var(--font-mono);
  font-size: var(--fs-mono-label);
  letter-spacing: 0.02em;
  color: var(--ink-muted);
}

.industry-badge--lead {
  border-color: var(--accent);
  color: var(--accent);
}

/* ==========================================================================
   About / Founder
   ========================================================================== */

.founder-panel {
  display: flex;
  align-items: stretch;
  gap: 0;
  border: 1px solid var(--hairline);
  border-radius: var(--radius-lg);
  overflow: hidden;
  background: var(--surface-glass);
  backdrop-filter: blur(14px);
}

.founder-photo {
  --photo-size: clamp(220px, 24vw, 320px);
  flex-shrink: 0;
  width: var(--photo-size);
  height: auto;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--surface-2);
  border-right: 1px solid var(--hairline);
}

.founder-photo-img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.founder-photo-placeholder {
  color: var(--accent);
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 3rem;
  letter-spacing: -0.02em;
}

.founder-copy {
  min-width: 0;
  padding: var(--space-xl);
}

.founder-copy .section-sub {
  max-width: 62ch;
}

@media (max-width: 700px) {
  .founder-panel {
    flex-direction: column;
    align-items: stretch;
  }

  .founder-photo {
    width: 100%;
    height: auto;
    aspect-ratio: 1 / 1;
    border-right: none;
    border-bottom: 1px solid var(--hairline);
  }
}

/* --- Featured in ----------------------------------------------------------
   A wordmark row sitting under the tool badges in the about panel. It is
   deliberately quieter than the client marquee: peer credibility supports the
   client logos, it does not compete with them.

   The hairline above is the whole separation device. No card, no background,
   no border box — another bordered block inside an already bordered panel
   starts to look like a form.

   Marks are type, not images. Real logos for these three share no weight,
   width or optical size, so a monochrome row of them reads as a mess, while
   one face at one weight reads as a row. Kept at ink-med so the row is a
   texture at a glance and only resolves into names when read. */

.featured-in {
  margin-top: var(--space-lg);
  padding-top: var(--space-md);
  border-top: 1px solid var(--hairline-soft);
}

.featured-in-label {
  font-family: var(--font-mono);
  font-size: var(--fs-mono-label);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-med);
  opacity: 0.7;
  margin: 0 0 var(--space-xs);
}

.featured-in-list {
  display: flex;
  flex-wrap: wrap;
  /* Centres, not baselines. An <img> takes its baseline from its bottom edge,
     which sat it 3px above the text marks in a mixed row. Centring is stable
     whatever mix of logos and text the row ends up holding.
     Column gap carries the separators, so it is wide; row gap only has to
     keep two wrapped lines off each other. */
  align-items: center;
  column-gap: var(--space-lg);
  row-gap: var(--space-xs);
  list-style: none;
  margin: 0;
  padding: 0;
}

/* Flex, not the default list-item box. The anchor is inline-flex, so inside a
   normal li it lands on that li's text baseline and a logo sits ~3px above the
   text marks. Centring inside the item removes that. Changing display on an li
   is what drops list semantics in Safari, but list-style: none already did
   that, so the ul carries role="list" to put them back. */
.featured-in-item {
  display: flex;
  align-items: center;
  margin: 0;
}

.featured-in-link {
  display: inline-flex;
  align-items: center;
  text-decoration: none;
  /* Underline drawn as a border so it can be animated and so it clears the
     descenders, which text-decoration would cut through. */
  border-bottom: 1px solid transparent;
  padding-bottom: 3px;
  transition: border-color 0.2s ease;
}

.featured-in-link:hover,
.featured-in-link:focus-visible {
  border-bottom-color: var(--accent);
}

/* Logos are white PNGs; opacity does the tone, matching .marquee-logo. Height
   comes from --mark-h set per item in the markup, because equal pixel height
   is not equal optical weight: a chunky 4:1 wordmark at 24px overpowers a
   light one at the same height. Size each until the row reads level. */
.featured-in-logo {
  height: var(--mark-h, 20px);
  width: auto;
  object-fit: contain;
  display: block;
  opacity: 0.72;
  transition: opacity 0.2s ease;
}

.featured-in-link:hover .featured-in-logo,
.featured-in-link:focus-visible .featured-in-logo {
  opacity: 1;
}

/* A .featured-in-mark text fallback lived here for features with no logo file.
   Both current items are logos, so it was dead CSS and is gone. If a feature
   ever has to run as text, it needs Archivo 700 at 1.125rem / line-height 1 in
   --ink-med to sit level with the logos; anything lighter drops below them. */

@media (max-width: 480px) {
  .featured-in-list {
    column-gap: var(--space-md);
  }
}

/* The guarantee strip was removed from index.html — the diamond clip-path
   was destroying the badge's border, and the offer itself is being reworked.
   Its styles are gone with it; reinstate from git history if it returns. */

/* ==========================================================================
   Process — 3-card grid, each an atmospheric media panel with a floating
   day-tag and a numbered caption below (reference: sanjaya.framer.ai
   "How It Works")
   ========================================================================== */

/* Vertical stepper. Rows on a rail, not a card grid — the pricing section
   directly above is already a three-column card row, and repeating that
   shape here made the two read as one long undifferentiated block. */
.process-steps {
  position: relative;
  max-width: 860px;
  margin-inline: auto;
}

.process-list {
  list-style: none;
  margin: 0;
  padding: 0;
}

/* The rail is absolutely positioned behind the steps and spans only the
   first-to-last dot, so it never dangles past the ends of the list. */
.process-rail {
  position: absolute;
  left: 27px;
  top: 0.55em;
  bottom: 0;
  width: 1px;
  background: var(--hairline-soft);
}

.process-rail-fill {
  display: block;
  width: 100%;
  height: 0;
  background: var(--accent);
  transform-origin: top;
  transition: height 0.15s linear;
}

.process-step {
  position: relative;
  display: flex;
  gap: var(--space-lg);
  padding-bottom: var(--space-2xl);
}

.process-step:last-child {
  padding-bottom: 0;
}

.process-step-index {
  position: relative;
  flex-shrink: 0;
  width: 56px;
  display: flex;
  align-items: baseline;
  justify-content: flex-start;
}

.process-step-num {
  font-family: var(--font-mono);
  font-size: var(--fs-mono-label);
  letter-spacing: 0.1em;
  color: var(--ink-med);
  transition: color 0.4s var(--ease);
}

/* Sits on the rail. Canvas-filled so the rail appears to pass behind it
   rather than through it. */
.process-step-dot {
  position: absolute;
  left: 23px;
  top: 0.3em;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--canvas);
  border: 1px solid var(--hairline);
  transition: background 0.4s var(--ease), border-color 0.4s var(--ease),
    box-shadow 0.4s var(--ease);
}

.process-step-body {
  flex: 1;
  min-width: 0;
}

.process-step-tag {
  display: inline-block;
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-med);
  transition: color 0.4s var(--ease);
}

.process-step-title {
  font-family: var(--font-display);
  font-size: var(--fs-display-md);
  font-weight: 700;
  letter-spacing: -0.01em;
  margin-top: var(--space-3xs);
  color: var(--ink-med);
  transition: color 0.4s var(--ease);
}

.process-step-desc {
  font-size: var(--fs-body);
  color: var(--ink-med);
  line-height: 1.65;
  margin-top: var(--space-xs);
  max-width: 56ch;
  text-wrap: pretty;
  transition: color 0.4s var(--ease);
}

/* The step nearest the viewport's reading line. Everything lifts together:
   number, tag, title and body. Dimming the inactive steps is what makes the
   section feel like it's being walked through rather than just scrolled. */
.process-step.is-active .process-step-num,
.process-step.is-active .process-step-tag {
  color: var(--accent);
}

.process-step.is-active .process-step-title {
  color: var(--ink);
}

.process-step.is-active .process-step-desc {
  color: var(--ink-high);
}

.process-step.is-active .process-step-dot {
  background: var(--accent);
  border-color: var(--accent);
  box-shadow: 0 0 0 4px var(--accent-soft);
}

@media (max-width: 700px) {
  .process-rail {
    left: 26px;
  }

  .process-step {
    gap: var(--space-md);
    padding-bottom: var(--space-xl);
  }

  .process-step-index {
    width: 46px;
  }

  .process-step-dot {
    left: 22px;
  }

  .process-step-desc {
    font-size: var(--fs-body-sm);
  }
}

/* Reduced motion: no rail animation, no dimming. Every step reads as active
   so nothing is hidden from someone who never triggers the scroll handler. */
@media (prefers-reduced-motion: reduce) {
  .process-rail-fill {
    transition: none;
  }

  .process-step-title {
    color: var(--ink);
  }

  .process-step-desc {
    color: var(--ink-high);
  }
}

/* ==========================================================================
   FAQ
   ========================================================================== */

.faq-layout {
  display: grid;
  grid-template-columns: 1fr 280px;
  gap: var(--space-2xl);
  align-items: start;
}

.faq-main {
  min-width: 0;
}

.faq-cta-card {
  background: var(--surface-glass);
  backdrop-filter: blur(14px);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-lg);
  padding: var(--space-lg);
  position: sticky;
  top: calc(64px + var(--space-lg));
}

.faq-cta-card h3 {
  font-family: var(--font-display);
  font-size: var(--fs-headline);
  font-weight: 700;
  letter-spacing: -0.01em;
}

.faq-cta-card p {
  font-size: var(--fs-body-sm);
  color: var(--ink-muted);
  margin-top: var(--space-2xs);
  margin-bottom: var(--space-md);
}

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

  .faq-cta-card {
    position: static;
  }
}

.faq-list {
  border-top: 1px solid var(--hairline-soft);
}

.faq-item {
  border-bottom: 1px solid var(--hairline-soft);
}

.faq-item:nth-child(1) { transition-delay: 0s; }
.faq-item:nth-child(2) { transition-delay: 0.08s; }
.faq-item:nth-child(3) { transition-delay: 0.16s; }
.faq-item:nth-child(4) { transition-delay: 0.24s; }
.faq-item:nth-child(5) { transition-delay: 0.32s; }
.faq-item:nth-child(6) { transition-delay: 0.4s; }

.faq-question {
  width: 100%;
  background: none;
  border: none;
  color: var(--ink);
  text-align: left;
  padding: var(--space-md) 0;
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-family: var(--font-body);
  font-size: var(--fs-body-lg);
  font-weight: 500;
  gap: var(--space-md);
}

.faq-icon {
  flex-shrink: 0;
  width: 24px;
  height: 24px;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* The glyph rotates, not its 24px slot. Rotating the slot pushed its corners
   about 5px past the button's right edge (a 24px square is ~34px across the
   diagonal), which showed up as phantom horizontal overflow on whichever
   item was open. Rotating a box sized to the "+" itself keeps it inside. */
.faq-icon-glyph {
  display: block;
  line-height: 1;
  font-family: var(--font-mono);
  color: var(--accent);
  transition: transform 0.25s var(--ease);
}

.faq-item.is-open .faq-icon-glyph {
  transform: rotate(45deg);
}

.faq-answer {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.3s var(--ease);
}

.faq-answer p {
  padding-bottom: var(--space-md);
  color: var(--ink-muted);
  max-width: 64ch;
  line-height: 1.6;
}

/* ==========================================================================
   Final CTA band
   ========================================================================== */

/* The band is now just a content wrapper. Its border, radius and clipped
   background all went when the image moved out to full bleed: a bordered box
   floating on top of a backdrop that runs past it reads as two competing
   frames. The hero has no box either, and this section is mirroring it. */
.cta-band {
  position: relative;
  z-index: 1;
  padding-block: var(--space-2xl);
}

/* Full-bleed backdrop. Absolute against the section rather than against
   .container, which is what makes it span the viewport. */
.contact-backdrop {
  position: absolute;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
}

.contact-backdrop-img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 35%;
  display: block;
}

/* Solid canvas at both ends. The top stop kills the seam with the section
   above; the bottom stop means the image has already resolved to the page
   colour before the footer starts, so the two never meet at an edge.
   Heavier through the middle than the hero's scrim, because form controls
   sit on this one and their hairline borders need a stable ground. */
.contact-backdrop-scrim {
  position: absolute;
  inset: 0;
  background: linear-gradient(
    180deg,
    rgba(5, 5, 6, 1) 0%,
    rgba(5, 5, 6, 0.89) 8%,
    rgba(5, 5, 6, 0.71) 30%,
    rgba(5, 5, 6, 0.75) 58%,
    rgba(5, 5, 6, 0.93) 84%,
    rgba(5, 5, 6, 1) 100%
  );
}

.cta-band-title {
  font-family: var(--font-display);
  font-size: clamp(1.75rem, 1.3rem + 1.8vw, 2.7rem);
  font-weight: 800;
  /* Without this it inherited the body's 1.5, which at display size meant
     line boxes half again too tall. */
  line-height: 1.05;
  letter-spacing: -0.02em;
  margin-top: var(--space-sm);
  position: relative;
  text-wrap: balance;
}

.cta-band-sub {
  color: var(--ink-muted);
  font-size: var(--fs-body-lg);
  margin-top: var(--space-sm);
  max-width: 44ch;
  position: relative;
  /* balance, not pretty: `pretty` only pulls up a lone last word, and this
     paragraph was ending on a 100px stub in the stacked layout. */
  text-wrap: balance;
}

/* Capacity block.
   ------------------------------------------------------------------------
   Sits at the foot of the contact column, where it is the last thing read
   before the form. The pips do the persuading and the sentence does the
   informing: a visitor with a deadline needs the date, not the metaphor.

   Rendered from the CAPACITY object in js/main.js. Nothing here assumes a
   particular slot count, so changing slots from 4 to 6 needs no CSS change. */
.capacity {
  margin-top: var(--space-lg);
  position: relative;
}

.capacity-label {
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-med);
}

.capacity-pips {
  display: flex;
  gap: 6px;
  margin-top: var(--space-2xs);
}

/* Deliberately bars rather than dots: a row of dots reads as a carousel
   control or a loading state. Bars read as a gauge. */
.capacity-pip {
  width: 34px;
  height: 6px;
  border-radius: 2px;
  border: 1px solid var(--hairline);
  background: transparent;
}

.capacity-pip.is-taken {
  background: var(--accent);
  border-color: var(--accent);
}

.capacity-line {
  margin-top: var(--space-xs);
  font-size: var(--fs-body-sm);
  color: var(--ink-high);
  line-height: 1.6;
  text-wrap: pretty;
}

/* ==========================================================================
   Contact form
   ========================================================================== */

/* Copy on the left, form on the right. The argument stays on screen while
   the form is being filled, which a stacked layout loses the moment the
   first field is focused. */
.contact-layout {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr);
  gap: var(--space-2xl);
  align-items: start;
  text-align: left;
}

.contact-intro {
  padding-top: var(--space-2xs);
}

.contact-direct {
  margin-top: var(--space-xs);
  font-size: var(--fs-body-sm);
  color: var(--ink-med);
}

.contact-direct a {
  color: var(--ink);
  border-bottom: 1px solid var(--hairline);
  padding-bottom: 1px;
  transition: color 0.25s var(--ease), border-color 0.25s var(--ease);
}

.contact-direct a:hover {
  color: var(--accent);
  border-bottom-color: var(--accent);
}

.contact-form {
  display: flex;
  flex-direction: column;
  gap: var(--space-md);
}

/* Off-screen rather than display:none — some bots skip anything that isn't
   rendered, and the point is that they fill it in. */
.contact-hp {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

.field-row {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-md);
}

.field {
  display: flex;
  flex-direction: column;
  gap: var(--space-3xs);
  min-width: 0;
}

.field label {
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-med);
}

.field-req {
  color: var(--accent);
}

.field input,
.field select,
.field textarea {
  width: 100%;
  font-family: var(--font-body);
  font-size: var(--fs-body);
  color: var(--ink);
  background: rgba(5, 5, 6, 0.6);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-sm);
  padding: 11px 13px;
  transition: border-color 0.2s var(--ease), background 0.2s var(--ease);
  /* Safari otherwise ignores the font stack on form controls entirely. */
  -webkit-appearance: none;
  appearance: none;
}

.field textarea {
  resize: vertical;
  min-height: 120px;
  line-height: 1.55;
}

/* Native select arrow is gone with appearance:none, so it's redrawn as a
   background chevron. Encoded inline to avoid a request for 200 bytes. */
.field select {
  padding-right: 38px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%23f4f4f1' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' opacity='.55'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 13px center;
  cursor: pointer;
}

/* The option list is drawn by the OS, which does not inherit the page's
   colours — without this, options render as dark text on dark on some
   platforms. */
.field select option {
  background: var(--surface-1);
  color: var(--ink);
}

.field input:hover,
.field select:hover,
.field textarea:hover {
  border-color: var(--ink-med);
}

.field input:focus-visible,
.field select:focus-visible,
.field textarea:focus-visible {
  outline: none;
  border-color: var(--accent);
  background: rgba(5, 5, 6, 0.85);
}

/* Only styled once the field has actually been marked invalid by the submit
   handler. :invalid alone would paint every required field red on page load,
   before anyone has typed a thing. */
.field.is-invalid input,
.field.is-invalid select,
.field.is-invalid textarea {
  border-color: var(--accent);
}

.field-hint,
.field-error {
  font-size: var(--fs-caption);
  line-height: 1.45;
}

.field-hint {
  color: var(--ink-med);
}

.field-error {
  color: var(--accent);
}

.contact-submit {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-sm) var(--space-md);
  margin-top: var(--space-2xs);
}

.contact-privacy {
  flex: 1;
  min-width: 16ch;
  font-size: var(--fs-caption);
  color: var(--ink-med);
  line-height: 1.45;
}

.contact-form.is-sending .contact-submit-label {
  opacity: 0.6;
}

.contact-status {
  font-size: var(--fs-body-sm);
  line-height: 1.55;
}

.contact-status:empty {
  display: none;
}

.contact-status.is-error {
  color: var(--accent);
}

/* Success replaces the form rather than sitting under it, so there is no
   half-filled form left on screen inviting a second submission. */
.contact-success {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-xs);
  padding: var(--space-lg);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-lg);
  background: var(--surface-1);
}

.contact-success-mark {
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--accent);
}

.contact-success h3 {
  font-family: var(--font-display);
  font-size: var(--fs-display-md);
  font-weight: 700;
  letter-spacing: -0.01em;
}

.contact-success p {
  color: var(--ink-muted);
  font-size: var(--fs-body-sm);
  line-height: 1.6;
  max-width: 44ch;
}

/* Two-column only: anchor the small print to the bottom of the intro column.
   The form is roughly 400px taller than the copy beside it, which left a
   block of dead space under "Prefer email?" and made the column read as
   unfinished rather than as deliberate whitespace. Pinning the capacity note
   and the email line to the bottom edge makes the two columns start and end
   together, and the air lands in the middle where it belongs. */
@media (min-width: 1101px) {
  .contact-layout {
    align-items: stretch;
  }

  .contact-intro {
    display: flex;
    flex-direction: column;
  }

  /* The eyebrow is an inline-flex pill, but as a flex child it stretches to
     the column width and its background runs the full 450px. Shrink just
     this one back to its content. */
  .contact-intro .eyebrow {
    align-self: flex-start;
  }

  .capacity {
    margin-top: auto;
    /* Keeps a floor under the gap if the copy ever grows to fill the column. */
    padding-top: var(--space-2xl);
  }
}

/* Collapses at 1100 rather than 900. Between those two widths the left column
   is under 420px, which is not enough for the headline to break into two lines
   however it is sized. Stacked, it has the full band width and rags cleanly. */
@media (max-width: 1100px) {
  .contact-layout {
    grid-template-columns: 1fr;
    gap: var(--space-xl);
  }

  .cta-band-sub {
    max-width: none;
  }
}

@media (max-width: 560px) {
  .cta-band {
    padding: var(--space-xl) var(--space-md);
  }

  .field-row {
    grid-template-columns: 1fr;
  }

  .contact-submit .btn {
    width: 100%;
    justify-content: center;
  }
}

/* ==========================================================================
   Footer
   ========================================================================== */
/* Legal links sit where the location line used to. Kept as a small row so
   the footer baseline stays a two-item layout at every width. */
.footer-legal {
  display: inline-flex;
  flex-wrap: wrap;
  gap: var(--space-md);
}



/* A backdrop section already ends in solid canvas, so the footer's usual
   top gap would just add empty space after a transition that has finished.
   The fade lands directly on the footer instead. */
.section--backdrop + .footer {
  margin-top: 0;
}

.footer {
  margin-top: var(--space-4xl);
  padding-top: var(--space-2xl);
  padding-bottom: var(--space-2xl);
  border-top: 1px solid var(--hairline-soft);
}

@media (max-width: 810px) {
  .footer {
    margin-top: var(--space-3xl);
  }
}

.footer-inner {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  flex-wrap: wrap;
  gap: var(--space-xl);
}

.footer-brand {
  max-width: 380px;
}

.footer-logo-img {
  height: 26px;
  width: auto;
  display: block;
}

.footer-statement {
  font-family: var(--font-display);
  font-size: clamp(1.75rem, 1.4rem + 1.8vw, 2.75rem);
  font-weight: 800;
  line-height: 1.05;
  letter-spacing: -0.02em;
  margin-top: var(--space-md);
}

.footer-statement .accent-text {
  color: var(--accent);
}

.footer-tag {
  color: var(--ink-muted);
  font-size: var(--fs-body-sm);
  margin-top: var(--space-md);
  max-width: 32ch;
}

.footer-links {
  display: flex;
  gap: var(--space-2xl);
}

.footer-col-label {
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  color: var(--ink-muted);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  margin-bottom: var(--space-sm);
  font-weight: 500;
}

.footer-col a {
  display: block;
  font-size: var(--fs-body-sm);
  padding-block: 6px;
  color: var(--ink);
}

.footer-col a:hover {
  color: var(--accent);
}

.footer-col--connect a {
  padding-block: 0;
  margin-bottom: var(--space-sm);
}

.footer-social-row {
  display: flex;
  gap: var(--space-2xs);
  margin-top: var(--space-2xs);
}

.footer-col .footer-social-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  padding-block: 0;
  margin-bottom: 0;
  border-radius: 50%;
  border: 1px solid var(--hairline);
  background: var(--surface-1);
  color: var(--ink-muted);
  transition: border-color 0.25s var(--ease), color 0.25s var(--ease), background 0.25s var(--ease);
}

.footer-social-btn span {
  font-family: var(--font-mono);
  font-size: 0.7rem;
  letter-spacing: 0.02em;
}

.footer-col .footer-social-btn:hover {
  border-color: var(--accent);
  color: var(--accent);
  background: var(--accent-soft);
}

.footer-bottom {
  margin-top: var(--space-2xl);
  padding-block: var(--space-lg);
  border-top: 1px solid var(--hairline-soft);
  display: flex;
  justify-content: space-between;
  color: var(--ink-muted);
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  flex-wrap: wrap;
  gap: var(--space-sm);
}

/* ==========================================================================
   Standalone document pages (privacy policy, legal notice)
   ========================================================================== */

.doc-shell {
  max-width: 720px;
}

.doc-body h2 {
  font-family: var(--font-display);
  font-size: var(--fs-display-md);
  font-weight: 800;
  letter-spacing: -0.01em;
  margin-top: var(--space-2xl);
  margin-bottom: var(--space-md);
}

.doc-body h2:first-child {
  margin-top: 0;
}

.doc-body ol,
.doc-body ul {
  padding-left: 1.25em;
  display: flex;
  flex-direction: column;
  gap: var(--space-md);
}

.doc-body ol {
  list-style: decimal;
}

.doc-body ul {
  list-style: disc;
}

.doc-body li {
  color: var(--ink-muted);
  line-height: 1.6;
  max-width: 62ch;
}

.doc-body li strong {
  color: var(--ink);
  font-weight: 600;
}

/* .doc-body started life on a page that only needed headings and lists.
   These add the paragraph, link and definition-list styles a privacy policy
   actually needs. */
.doc-body p {
  color: var(--ink-muted);
  line-height: 1.7;
  max-width: 62ch;
  margin-bottom: var(--space-md);
  text-wrap: pretty;
}

.doc-body p:last-child {
  margin-bottom: 0;
}

.doc-body h3 {
  font-family: var(--font-display);
  font-size: var(--fs-headline);
  font-weight: 700;
  letter-spacing: -0.01em;
  margin-top: var(--space-lg);
  margin-bottom: var(--space-2xs);
}

.doc-body strong {
  color: var(--ink);
  font-weight: 600;
}

.doc-body a {
  color: var(--ink);
  border-bottom: 1px solid var(--hairline);
  padding-bottom: 1px;
  transition: color 0.25s var(--ease), border-color 0.25s var(--ease);
}

.doc-body a:hover {
  color: var(--accent);
  border-bottom-color: var(--accent);
}

/* Key/value block for the company details on the legal notice. */
.doc-facts {
  display: grid;
  grid-template-columns: minmax(9rem, max-content) 1fr;
  gap: var(--space-xs) var(--space-lg);
  margin: 0 0 var(--space-md);
  max-width: 62ch;
}

.doc-facts dt {
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-med);
  padding-top: 4px;
}

.doc-facts dd {
  margin: 0;
  color: var(--ink);
  line-height: 1.6;
}

@media (max-width: 560px) {
  .doc-facts {
    grid-template-columns: 1fr;
    gap: var(--space-3xs) 0;
  }

  .doc-facts dd {
    margin-bottom: var(--space-sm);
  }
}

.doc-updated {
  margin-top: var(--space-2xl);
  padding-top: var(--space-md);
  border-top: 1px solid var(--hairline-soft);
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-med);
}

/* ==========================================================================
   Scroll reveal utility
   ========================================================================== */

.reveal {
  opacity: 0;
  transform: translateY(24px);
  transition: opacity 0.35s var(--ease), transform 0.35s var(--ease);
}

.reveal.is-visible {
  opacity: 1;
  transform: translateY(0);
}

.reveal-scale {
  opacity: 0;
  transform: scale(0.96);
  filter: brightness(0.85);
  transition: opacity 0.32s var(--ease), transform 0.32s var(--ease), filter 0.32s var(--ease);
}

.reveal-scale.is-visible {
  opacity: 1;
  transform: scale(1);
  filter: brightness(1);
}

/* ==========================================================================
   Skip link — keyboard users shouldn't have to tab the whole nav
   ========================================================================== */

.skip-link {
  position: absolute;
  left: var(--space-md);
  top: -100px;
  z-index: 200;
  background: var(--ink);
  color: var(--canvas);
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 10px 16px;
  border-radius: var(--radius-sm);
  transition: top 0.15s var(--ease);
}

.skip-link:focus {
  top: var(--space-md);
}

/* ==========================================================================
   Small-screen swaps
   ========================================================================== */

/* "Book a Call" inside the menu — hidden on desktop, where the button in the
   nav bar is already visible. */
.nav-links .nav-links-cta { display: none; }

@media (max-width: 700px) {
  /* Logo, CTA and hamburger were competing for one row. The CTA already
     lives in the open menu, so drop the duplicate from the bar. */
  .nav-cta > .btn { display: none; }

  .nav-links .nav-links-cta {
    display: block;
    border-bottom: none;
  }
}

/* ==========================================================================
   Pricing — scope bands, not fixed packages. Each card states a floor so a
   visitor can self-qualify before a call. The middle card is flagged and
   lifted a step, since the launch package is the common case.
   ========================================================================== */

.tier-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-md);
  /* Stretch, not start: the three cards carry different numbers of list items
     now, and a ragged bottom edge with three floating CTAs reads as broken.
     .tier-link's margin-top:auto pins every CTA to the same baseline. */
  align-items: stretch;
}

.tier-card {
  position: relative;
  display: flex;
  flex-direction: column;
  padding: var(--space-lg);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-2xl);
  background: var(--surface-1);
  transition: background 0.3s var(--ease), border-color 0.3s var(--ease);
}

.tier-card:hover {
  background: var(--surface-2);
}

/* The common case gets the emphasis: a step lighter, an accent hairline, and
   a flag. No colour fill — the accent stays a signal, never a surface. */
.tier-card--lead {
  background: var(--surface-2);
  border-color: var(--accent);
}

.tier-flag {
  position: absolute;
  top: 0;
  right: var(--space-lg);
  transform: translateY(-50%);
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--accent);
  background: var(--canvas);
  border: 1px solid var(--accent);
  border-radius: var(--radius-xs);
  padding: 4px 9px;
}

.tier-name {
  font-family: var(--font-display);
  font-size: var(--fs-display-md);
  font-weight: 700;
  letter-spacing: -0.01em;
  margin-top: var(--space-2xs);
}

.tier-price {
  font-family: var(--font-display);
  font-size: clamp(1.7rem, 1.3rem + 1.4vw, 2.4rem);
  font-weight: 800;
  letter-spacing: -0.02em;
  line-height: 1.1;
  margin-top: var(--space-sm);
}

/* "FROM" sits on its own line above the figure rather than inline: at display
   weight an inline "from" competes with the number, and the tiers read as a
   ladder only if the three figures align on the same optical line. */
.tier-price-from {
  display: block;
  font-family: var(--font-mono);
  font-size: var(--fs-mono-label);
  font-weight: 400;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-med);
  margin-bottom: 2px;
}


/* Runtime, directly under the price. The ladder sorts on finished runtime, so
   this is the number that decides which tier a buyer is in, and it has to be
   readable in the same glance as the figure above it.

   Deliberately NOT display type: a second large number under the price would
   compete with it and break the three-figure optical line the tiers rely on.
   Mono at full ink instead, which outranks the muted feature list below
   without outranking the price. The hairline separates it from the price
   rather than boxing it, matching how the rest of the card divides. */
.tier-runtime {
  display: flex;
  align-items: baseline;
  gap: var(--space-2xs);
  margin-top: var(--space-xs);
  padding-top: var(--space-xs);
  border-top: 1px solid var(--hairline-soft);
  font-family: var(--font-mono);
  font-size: var(--fs-mono-label);
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--ink);
}

/* The label is spelled out because the value on its own, under a price and
   above a card that also says "Typical delivery: 2 to 3 weeks", reads as a
   lead time rather than a length of film. */
.tier-runtime-label {
  color: var(--ink-med);
  opacity: 0.75;
}

.tier-desc {
  font-size: var(--fs-body-sm);
  color: var(--ink-muted);
  line-height: 1.5;
  margin-top: var(--space-sm);
}

/* Section heading inside a tier card ("What you get" / "Best for"). Full-ink
   at micro size so it separates from the ink-med list beneath it without
   spending the accent — the accent is already carrying the /02 flag here. */
.tier-block-label {
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink);
  margin-top: var(--space-md);
}

.tier-block-label:first-of-type {
  margin-top: var(--space-lg);
}

/* Same construction as .service-row-features — the mono/hairline list is the
   page's established way of enumerating deliverables. */
.tier-features {
  list-style: none;
  margin: var(--space-xs) 0 0;
  padding: 0;
}

/* Only the final list needs to clear the pinned CTA; the first one is
   followed by the next block label, which brings its own margin. */
.tier-features:last-of-type {
  margin-bottom: var(--space-lg);
}

/* .is-inherit styled the "Everything in The Launch Film" line back when the
   ladder was cumulative. The tiers are now self-contained runtime bands, so
   no element carries the class and the rule is gone. */

.tier-features li {
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--ink-muted);
  padding: 10px 0;
  border-top: 1px solid var(--hairline-soft);
}

.tier-link {
  margin-top: auto;
  align-self: flex-start;
  font-family: var(--font-mono);
  font-size: var(--fs-mono-label);
  font-weight: 500;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink);
  padding-bottom: 3px;
  border-bottom: 1px solid var(--hairline);
  transition: color 0.25s var(--ease), border-color 0.25s var(--ease);
}

.tier-link:hover {
  color: var(--accent);
  border-bottom-color: var(--accent);
}

/* The retainer, sized between the tier cards and the notes.
   ------------------------------------------------------------------------
   Rules above and below with no fill and no border: border-plus-surface is
   the card vocabulary used by the tiers, the service rows and the founder
   panel, so borrowing it here would make this read as a fourth product. A
   pair of hairlines is a typographic device instead, which interrupts the
   page enough to be noticed without joining the menu.

   The hierarchy is carried by the size jump on .tier-afterward-lead, not by
   a box. That line is display type at headline size, well below the tier
   prices and well above the notes around it. */
.tier-afterward {
  margin-top: var(--space-2xl);
  padding-block: var(--space-lg);
  border-top: 1px solid var(--hairline);
  border-bottom: 1px solid var(--hairline);
  max-width: 68ch;
  margin-inline: auto;
  text-align: center;
}

.tier-afterward-label {
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--accent);
}

.tier-afterward-lead {
  font-family: var(--font-display);
  font-size: var(--fs-headline);
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--ink);
  margin-top: var(--space-2xs);
  text-wrap: balance;
}

.tier-afterward-desc {
  margin-top: var(--space-xs);
  font-size: var(--fs-body-sm);
  color: var(--ink-med);
  line-height: 1.65;
  text-wrap: pretty;
}

.tier-notes {
  margin-top: var(--space-xl);
  display: flex;
  flex-direction: column;
  gap: var(--space-2xs);
}

.tier-notes p {
  text-align: center;
  font-size: var(--fs-body-sm);
  color: var(--ink-med);
  max-width: 66ch;
  margin-inline: auto;
  /* Keeps a note from wrapping to a lone word on narrow phones. */
  text-wrap: balance;
}

.tier-notes a {
  color: var(--ink);
  border-bottom: 1px solid var(--hairline);
  padding-bottom: 1px;
  transition: color 0.25s var(--ease), border-color 0.25s var(--ease);
}

.tier-notes a:hover {
  color: var(--accent);
  border-bottom-color: var(--accent);
}

@media (max-width: 900px) {
  .tier-grid {
    grid-template-columns: 1fr;
    gap: var(--space-lg);
  }

  .tier-flag {
    right: auto;
    left: var(--space-lg);
  }
}

/* ==========================================================================
   Work card proof row — the evidence line under each project's description.
   A studio site's job is to make claims checkable, and "we made this" is a
   weaker claim than "we made this, it was featured here, in this year, and
   you can go look at it." Mono + hairline, matching the deliverable lists in
   Services and Pricing so the vocabulary stays consistent.

   The row is optional: a card with no honest proof to show simply omits the
   <ul> rather than displaying an empty slot. Never pad this with a weak
   number — a visible "1.2k views" costs more credibility than silence.
   ========================================================================== */

.work-proof {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-xs) var(--space-md);
  width: 100%;
  margin: 0 0 var(--space-md);
  padding-top: var(--space-sm);
  border-top: 1px solid var(--hairline-soft);
}

.work-proof-item {
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--ink-med);
  white-space: nowrap;
}

/* A hard number or a named publication — the item that actually does the
   convincing. Accent-marked, one per card at most. */
.work-proof-item--key {
  color: var(--ink);
}

.work-proof-item--key::before {
  content: "→";
  color: var(--accent);
  margin-right: 6px;
}

/* Pushes the year (or any trailing item) to the right edge of the row. */
.work-proof-item--end {
  margin-left: auto;
  color: var(--ink-3, rgba(244, 244, 241, 0.42));
}

/* ==========================================================================
   Statement block — a plain-language description of the offer, set at display
   size and broken across lines by its own width rather than by <br>. Reference:
   achxstudio.com. The inline thumbnail that originally interrupted the
   sentence was removed — the line reads cleaner as pure type.
   ========================================================================== */

/* Centres the eyebrow chip over the statement. .eyebrow is inline-flex, so it
   needs a text-align context rather than margin-inline: auto. */
.statement-block {
  text-align: center;
  margin-bottom: var(--space-3xl);
}

.statement {
  font-family: var(--font-display);
  font-size: clamp(1.5rem, 1.05rem + 1.6vw, 2.5rem);
  font-weight: 700;
  line-height: 1.32;
  letter-spacing: -0.015em;
  color: var(--ink-high);
  max-width: min(100%, 26ch);
  margin-inline: auto;
  text-align: center;
  /* balance rather than pretty: centred text lives or dies on even line
     lengths, and balance evens them instead of only fixing the last line. */
  text-wrap: balance;
}

/* Wide enough to breathe without becoming a paragraph. 30ch tipped the
   sentence onto a third line anywhere between ~820px and ~1100px — a very
   common windowed-browser range — so the measure widens in one step instead
   of two. Below 811px it stays narrow: forcing two lines on a phone would
   mean shrinking the type past the point where it reads as a statement. */
@media (min-width: 811px) {
  .statement {
    max-width: 36ch;
  }
}

.statement .accent-text {
  color: var(--accent);
}

@media (max-width: 700px) {
  .statement-block {
    margin-bottom: var(--space-2xl);
  }
}

/* ==========================================================================
   Glitch word — periodic character scramble on a single word.

   The visible face is aria-hidden and paired with a visually-hidden copy of
   the real word, so assistive tech always reads "complex" and never catches a
   scrambled frame. JS locks the face's width once webfonts have loaded, so
   swapping glyphs can never reflow the sentence around it.
   ========================================================================== */

.glitch-word {
  position: relative;
}

.glitch-word-face {
  display: inline-block;
  white-space: pre;
  text-align: left;
}

/* Standard visually-hidden: removed from view, still read aloud. */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}
