/* ============================================================
   TFM — styles.css
   FRAME. Near-black, greys, white used sparingly, and one colour.

   The organising idea is a contact sheet: the studio shoots, so the page is
   built as a strip of frames. Section eyebrows are frame slates
   (FRAME 03 / 06 — WHAT WE DO); the numbering maps to real position in the
   strip rather than decorating.

   Type does the other half of the work. Monospace is not relegated to captions
   here: every heading, label, price and number is Space Mono, uppercase and
   widely tracked. Inter Tight carries body copy. One Archivo Black statement
   anchors the hero and appears nowhere else.

   Colour discipline: --orange is the ONLY colour on the site. White is
   reserved for headings and the things you are meant to act on. Everything
   else is grey. If a third colour appears, something has gone wrong.
   ============================================================ */

/* ---------- fonts ---------- */
@font-face {
  font-family: 'Instrument Serif';
  src: url('../assets/fonts/serif.woff2') format('woff2');
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'Instrument Serif';
  src: url('../assets/fonts/serif-italic.woff2') format('woff2');
  font-weight: 400; font-style: italic; font-display: swap;
}
@font-face {
  /* Archivo Black — self-hosted because the CSP is font-src 'self'. Used for
     exactly one thing: the TFM mark. A heavy, wide grotesque is what makes a
     channel-split glitch read; the UI sans is too light to hold the offset. */
  font-family: 'Archivo Black';
  src: url('../assets/fonts/display.woff2') format('woff2');
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'Space Mono';
  src: url('../assets/fonts/mono.woff2') format('woff2');
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'Space Mono';
  src: url('../assets/fonts/mono-bold.woff2') format('woff2');
  font-weight: 700; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'Inter Tight';
  src: url('../assets/fonts/sans.woff2') format('woff2');
  font-weight: 300 700; font-style: normal; font-display: swap;
}

/* ---------- tokens ---------- */
:root {
  --void:   #0A0706;   /* the page */
  --panel:  #17100E;   /* raised surfaces */
  --panel-2:#241512;   /* raised, one step further */
  --line:   #2A1A17;   /* hairlines */
  --line-2: #3A2621;   /* hairlines that have to be seen */
  --dim:    #8B817E;   /* de-emphasised — labels, meta. #7A7A7A measured 4.36:1
                          on --ink, under the 4.5 WCAG 1.4.3 minimum. */
  --mid:    #ABA3A0;   /* body copy */
  --white:  #F7F0EC;   /* headings and actions. Sparing. */
  --orange: #E3624C;   /* the accent AS TEXT. Measured 5.85:1 on --void. */

  /* Sampled from the montage. #FF6B35 was never in that footage — the lit
     podium measures #CF3C11 across all 16 frames, roughly half the luminance
     of the old token. Vermilion is a FILL colour: at 4.19:1 it fails as body
     text on every ground, so text uses --orange (coral) above. */
  --vermilion:   #D03E12;   /* fills, rules, graphic marks (3:1 bar) */
  --fill-deep:   #82130A;   /* button fills that carry a white label (9.10:1).
                              NOT named --accent-deep: that name is already an
                              alias of --orange later in this block and would
                              silently win. */
  --fill-lift:   #F79176;   /* brightest specular — focus rings, hover */
  --ash:         #241512;   /* third ground, and the base of the glass */
  /* the lighter tones, measured off the device screens */
  --tint-bone:   #B9998D;
  --tint-lilac:  #AF80BA;
  --tint-blush:  #C38C99;
  --tint-haze:   #DCD6DC;

  /* Glass. A LIGHT glass is unusable here: over the brightest frame of the
     montage it composites to #CEA7A8 and white text lands at 1.24:1. Dark
     glass holds 7.31:1 on white even at the worst point in the footage. */
  --glass-bg:     rgba(36, 21, 18, .72);
  --glass-strong: rgba(20, 12, 10, .82);
  --glass-border: rgba(231, 141, 125, .22);
  --glass-inner:  inset 0 1px 0 rgba(247, 240, 236, .10);
  --glass-shadow: 0 24px 60px -32px rgba(0, 0, 0, .85);   /* the only colour */

  --mono:  'Space Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
  --sans:  'Inter Tight', -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif;
  --display: 'Archivo Black', var(--sans);

  --gut:   clamp(1.25rem, 4vw, 4.5rem);
  --maxw:  82rem;
  --sect-y: clamp(5rem, 11vw, 10rem);
  --ease:  cubic-bezier(.22, 1, .36, 1);

  /* legacy aliases so existing rules keep resolving while the new system lands */
  --black: var(--void); --ink: var(--void); --obsidian: var(--void); --bg1: var(--void);
  --brown: var(--panel); --surface: var(--panel); --graphite: var(--panel); --bg2: var(--panel);
  --plum: var(--panel-2); --panel-3: var(--panel-2);
  --ivory: var(--white); --cream: var(--white); --text: var(--white);
  --soft: var(--white); --warm-white: var(--white); --bone: var(--white);
  --muted: var(--mid); --muted-light: var(--mid); --muted-dark: var(--mid);
  --muted-ink: var(--mid); --pale: var(--mid); --cream-2: var(--mid);
  --gold: var(--orange); --coral: var(--orange); --ember: var(--orange);
  --amber: var(--orange); --wheat: var(--orange); --rust: var(--orange);
  --clay: var(--orange); --copper: var(--orange); --accent: var(--orange);
  --orange-deep: var(--orange); --accent-deep: var(--orange); --copper-deep: var(--orange);
  --bronze: var(--orange); --sand: var(--orange); --champagne: var(--panel);
  --glitch: var(--orange); --glitch-2: var(--orange);
  --rule: var(--line); --rule-light: var(--line); --rule-dark: var(--line);
  --rule-ink: var(--line); --rule-on-ink: var(--line); --rule-strong: var(--line-2);
  --grad: linear-gradient(90deg, var(--orange), var(--orange));
  --molten: var(--grad); --grad-rule: var(--grad);
  --warm-light: none; --warm-dark: none; --glow-field: none;
  --grad-ground: none; --grad-sand: none; --lift: var(--orange);
  --shadow-soft: 0 1px 2px rgba(0,0,0,.5);
  --shadow-lift: 0 24px 60px -32px rgba(0,0,0,.8);
  --grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.82' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23n)' opacity='.5'/%3E%3C/svg%3E");
  --logo-letters: linear-gradient(var(--white), var(--white));
  --logo-flame: linear-gradient(180deg, var(--orange), var(--orange));

  /* ground tokens */
  --on: var(--white);
  --on-muted: var(--mid);
  --on-rule: var(--line);
  --on-accent: var(--orange);
  --ground: var(--void);

  --serif: 'Instrument Serif', 'Times New Roman', Times, serif;
  --sans: 'Inter Tight', -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif;

  --gut: clamp(1.25rem, 4vw, 4.5rem);
  --maxw: 78rem;
  --sect-y: clamp(4.5rem, 9vw, 9rem);
  --ease: cubic-bezier(.22, 1, .36, 1);
}

/* ---------- reset ---------- */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body, h1, h2, h3, h4, p, figure, blockquote, ul, ol, dl, dd { margin: 0; }
ul[class], ol[class] { list-style: none; padding: 0; }
img, video, svg, iframe { display: block; max-width: 100%; }
img, video { height: auto; }
button, input, select, textarea { font: inherit; color: inherit; }
html { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  background: var(--void);
  color: var(--mid);
  font-family: var(--sans);
  font-size: clamp(1rem, .97rem + .16vw, 1.0625rem);
  font-weight: 400;
  line-height: 1.65;
  letter-spacing: -.005em;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

/* Lenis */
html.lenis, html.lenis body { height: auto; }
.lenis.lenis-smooth { scroll-behavior: auto !important; }
.lenis.lenis-stopped { overflow: hidden; }

/* ---------- a11y ---------- */
.visually-hidden {
  position: absolute !important; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0);
  white-space: nowrap; border: 0;
}
.skip-link {
  position: absolute; top: 0; left: 50%; transform: translate(-50%, -110%);
  z-index: 300; background: var(--ink); color: var(--cream);
  padding: .8rem 1.4rem; font: 500 .875rem/1 var(--sans); text-decoration: none;
}
.skip-link:focus-visible { transform: translate(-50%, 0); }

:where(a, button, input, textarea, select, summary, [tabindex]):focus-visible {
  outline: 2px solid var(--on-accent);
  outline-offset: 3px;
}

/* ---------- layout ---------- */
.wrap { width: 100%; max-width: var(--maxw); margin-inline: auto; padding-inline: var(--gut); }
.section { padding-block: var(--sect-y); position: relative; isolation: isolate; }

/* GRAIN — one turbulence tile over every ground, so nothing is a flat block.
   Sits above the background and below the content, and never eats a click. */
.section::after, .hero::after, .cta::after, .page-head::after, .footer::after {
  content: ''; position: absolute; inset: 0; z-index: -1;
  background-image: var(--grain); background-size: 180px 180px;
  opacity: .05; pointer-events: none;
}
.section--ink::after, .section--obsidian::after, .section--graphite::after,
.hero::after, .cta::after, .footer::after { opacity: .085; mix-blend-mode: screen; }

/* One ground, three steps. The page never flips to a light section — contrast
   comes from hairlines, panel steps and the frames themselves. The old
   light/dark class names all resolve to a step so existing markup keeps
   working. */
.section { padding-block: var(--sect-y); position: relative; }
.section--cream, .section--warm, .section--white,
.section--ink, .section--obsidian {
  background: var(--void); --ground: var(--void);
}
.section--sand, .section--champagne, .section--graphite {
  background: var(--panel); --ground: var(--panel);
}
.section--cream, .section--warm, .section--white,
.section--sand, .section--champagne,
.section--ink, .section--obsidian, .section--graphite, .section--flame {
  --on: var(--white); --on-muted: var(--mid);
  --on-rule: var(--line); --on-accent: var(--orange);
  color: var(--mid);
}
/* a hairline between every frame — the strip is continuous */
.section + .section { border-top: 1px solid var(--line); }

/* ---------- type scale ----------
   Headings are monospace. That is the decision the whole page hangs on: it
   reads as a working document rather than a brochure, and it is the studio's
   own register — file names, exposure data, frame numbers. */
h1, h2, h3, .h-xl, .h-lg, .h-md, .h-sm {
  font-family: var(--mono); font-weight: 700;
  text-transform: uppercase; letter-spacing: -.01em;
  color: var(--white); line-height: 1.04;
  text-wrap: balance;
}
.h-xl { font-size: clamp(2.5rem, 6.5vw, 5.5rem); }
.h-lg { font-size: clamp(1.85rem, 4.2vw, 3.25rem); }
.h-md { font-size: clamp(1.35rem, 2.6vw, 1.95rem); }
.h-sm { font-size: clamp(1.05rem, 1.7vw, 1.3rem); letter-spacing: 0; }

em { font-style: normal; color: var(--orange); }

.lede {
  font-family: var(--sans); font-size: clamp(1rem, 1.1vw, 1.125rem);
  line-height: 1.62; color: var(--mid); max-width: 56ch;
  text-transform: none; letter-spacing: 0;
}
.muted { color: var(--dim); }

/* ---------- the frame slate ----------
   Section eyebrows are slates: FRAME 03 / 06 — SERVICES. The number is the
   section's real position in the strip, set from build.py. */
.eyebrow, .slate {
  display: flex; align-items: center; gap: .75rem;
  font-family: var(--mono); font-size: .6875rem; font-weight: 400;
  letter-spacing: .18em; text-transform: uppercase;
  color: var(--dim);
}
.eyebrow::before, .slate::before {
  content: ''; width: 1.75rem; height: 1px; background: var(--orange); flex: none;
}
.slate b { color: var(--orange); font-weight: 400; }

/* emphasis: italic serif first, colour second — a word or two, never a phrase */
em { color: var(--on-accent); font-style: italic; }
.section--ink em, .section--obsidian em, .section--graphite em,
.hero em, .cta em, .page-head--ink em { color: var(--sand); }

.eyebrow {
  font-family: var(--sans);
  font-size: .6875rem; font-weight: 500;
  letter-spacing: .2em; text-transform: uppercase;
  color: var(--on-muted);
  display: flex; align-items: center; gap: .8rem;
}
.eyebrow::before {
  content: ''; width: 1.5rem; height: 1px; flex: none; background: currentColor; opacity: .5;
}
.lede {
  font-size: clamp(1.0625rem, 1.15vw, 1.25rem);
  line-height: 1.6; color: var(--on-muted);
  max-width: 52ch; text-wrap: pretty;
}
.muted { color: var(--on-muted); }
/* the opening paragraph of a service page — larger, and in the body colour
   rather than the ground colour (it used to be an inline var(--ink), which
   inverted into dark-on-dark) */
.lede--intro { color: var(--on); font-size: clamp(1.15rem, 1.5vw, 1.4rem); }
.measure { max-width: 64ch; }

a { color: inherit; }
.link {
  color: var(--on); text-decoration: none;
  border-bottom: 1px solid var(--on-accent);
  padding-bottom: 1px;
  transition: color .3s var(--ease), border-color .3s var(--ease);
}
.link:hover { color: var(--on-accent); }

/* ---------- buttons ----------
   Rectangular, 2px radius, never pills. A copper or ember fill ALWAYS carries
   obsidian text — warm white on copper is only 3.68 and fails. */
.btn {
  --b-face: transparent;
  --b-text: var(--on);
  --b-wipe: var(--copper);
  --b-text-hover: var(--obsidian);
  --b-border: var(--on-rule);
  position: relative; isolation: isolate;
  display: inline-flex; align-items: center; gap: .7rem;
  padding: 1.05rem 1.75rem;
  font: 500 .875rem/1 var(--sans);
  letter-spacing: .04em; text-transform: uppercase;
  text-decoration: none; cursor: pointer;
  background: var(--b-face); color: var(--b-text);
  border: 1px solid var(--b-border); border-radius: 2px;
  overflow: hidden;
  transition: color .38s var(--ease), border-color .38s var(--ease);
}
.btn::before {
  content: ''; position: absolute; inset: 0; z-index: -1;
  background: var(--b-wipe);
  transform: scaleY(0); transform-origin: 50% 100%;
  transition: transform .45s var(--ease);
}
.btn > * { position: relative; }
.btn:hover, .btn:focus-visible { color: var(--b-text-hover); border-color: var(--orange); }
.btn:hover::before, .btn:focus-visible::before { transform: scaleY(1); }
.btn svg { transition: transform .45s var(--ease); flex: none; }
.btn:hover svg { transform: translateX(4px); }

/* primary — the molten gradient, rationed to the main CTA only */
.btn--solid, .btn--molten {
  --b-face: var(--gold); --b-text: var(--black);
  --b-wipe: var(--orange-deep); --b-text-hover: var(--ivory);
  --b-border: var(--gold);
  font-weight: 600;
}
/* no gradient underlay: the brief asks for restraint, and black text over an
   orange gradient stop scores 4.29, under the 4.5 bar */

/* on a dark ground: quiet outline that warms to copper */
.btn--onink, .btn--cream {
  --b-face: transparent; --b-text: var(--ivory);
  --b-wipe: var(--gold); --b-text-hover: var(--black);
  --b-border: rgba(243, 233, 219, .34);
}
/* The secondary button. Every ground is dark now, so this is an outline in the
   text colour that fills with coral on hover — it used to carry --obsidian
   text, which on a violet ground was invisible. */
.btn--ghost {
  --b-face: transparent; --b-text: var(--on);
  --b-wipe: var(--orange-deep); --b-text-hover: var(--ivory);
  --b-border: var(--rule-strong);
}
/* a filled, quieter alternative to the gradient CTA — the lifted surface, not
   the accent, so it never competes with the primary action beside it */
.btn--dark {
  --b-face: var(--black); --b-text: var(--ivory);
  --b-wipe: var(--gold); --b-text-hover: var(--black);
  --b-border: var(--black);
}

/* ---------- nav ---------- */
.nav {
  position: fixed; inset: 0 0 auto 0; z-index: 90;
  padding-block: 1.15rem;
  color: var(--cream);
  transition: background-color .5s var(--ease), color .5s var(--ease),
              box-shadow .5s var(--ease), padding .5s var(--ease),
              transform .45s var(--ease);
}
/* Out of the way when reading down the page, back the moment you scroll up.
   Never hides while the menu is open or while focus is inside the bar. */
.nav.is-tucked { transform: translateY(-100%); }
.nav:focus-within { transform: none; }

/* how far down the page you are — a hairline along the bottom of the bar */
.nav__progress {
  position: absolute; left: 0; right: 0; bottom: 0; height: 2px;
  overflow: hidden; opacity: 0; transition: opacity .4s var(--ease);
}
.nav.is-solid .nav__progress { opacity: 1; }
.nav__progress i {
  display: block; height: 100%; width: 100%;
  transform: scaleX(0); transform-origin: 0 50%;
  background-image: var(--grad);
}
.nav__inner { display: flex; align-items: center; gap: clamp(1rem, 3vw, 2.5rem); }
.nav.is-solid {
  background: rgba(23, 20, 17, .93);
  backdrop-filter: blur(14px) saturate(1.2);
  -webkit-backdrop-filter: blur(14px) saturate(1.2);
  color: var(--warm-white);
  box-shadow: 0 1px 0 var(--rule-dark);
  padding-block: .8rem;
}
.nav__links { display: flex; gap: clamp(1rem, 2.2vw, 2.1rem); margin-left: auto; }
.nav__links a {
  font-size: .875rem; font-weight: 450; text-decoration: none;
  position: relative; padding-block: .3rem;
  /* "FAQ" is the shortest label and measured 23.8px wide — 0.2px under the
     24px WCAG 2.2 AA target minimum (SC 2.5.8). Floor it. */
  min-width: 24px; text-align: center;
}
.nav__links a::after {
  content: ''; position: absolute; left: 0; bottom: 0; height: 1px; width: 100%;
  background-image: var(--grad); transform: scaleX(0); transform-origin: 0 50%;
  transition: transform .45s var(--ease);
}
.nav__links a:hover::after,
.nav__links a:focus-visible::after,
.nav__links a[aria-current="page"]::after { transform: scaleX(1); }
/* leaving a link retracts the rule to the right, so it reads as a sweep
   through rather than a line that just switches off */
.nav__links a:not(:hover)::after { transform-origin: 100% 50%; }
.nav .btn { padding: .72rem 1.15rem; font-size: .75rem; }
.nav .btn--onink { --b-text: var(--cream); }
/* the quote button is the one prominent thing in the bar, per the brief */
.nav .btn--nav, .nav.is-solid .btn--onink {
  --b-face: var(--gold); --b-text: var(--black);
  --b-wipe: var(--orange-deep); --b-text-hover: var(--ivory);
  --b-border: var(--gold);
  font-weight: 600;
}

/* ---------- logo ----------
   The supplied lettermark, keyed into TWO masks: the letterforms and the
   flame. Each is filled with its own gradient, so the mark fades rather than
   sitting there as one block colour — letters cream-to-bone on dark grounds
   and ink-to-umber on light ones, flame ember-yellow down to deep orange.
   The wordmark is part of the artwork now, so there is no TFM text beside it.

   Hover: the flame's gradient travels upward inside its own mask, which reads
   as the flame licking up, and a warm bloom gathers behind the mark. */
.logo { display: inline-flex; align-items: center; text-decoration: none; flex: none; position: relative; }


/* Every ground is dark now, so the mark only ever needs its light treatment.
   Kept as an explicit rule rather than folded into :root because the sheen
   stop list is easier to reason about in one place. */
.nav, .footer, .menu, .hero, .cta, .boot, .page-head--ink,
.section--ink, .section--obsidian, .section--graphite,
.section--cream, .section--warm, .section--white,
.section--sand, .section--champagne {
  --logo-letters: linear-gradient(100deg,
    #DCD3E6 0%, var(--text) 26%, #FFFFFF 34%, var(--text) 44%, #DCD3E6 100%);
}

.nav__toggle { display: none; }
.nav__burger { display: inline-grid; gap: 4px; margin-left: .6rem; }
.nav__burger i {
  display: block; width: 16px; height: 1.5px; background: currentColor;
  transition: transform .4s var(--ease), width .4s var(--ease);
}
.nav__toggle[aria-expanded="true"] .nav__burger i:first-child { transform: translateY(2.75px) rotate(45deg); }
.nav__toggle[aria-expanded="true"] .nav__burger i:last-child { transform: translateY(-2.75px) rotate(-45deg); }
.nav__toggle:hover .nav__burger i:last-child { width: 10px; }
@media (max-width: 62rem) {
  .nav__links, .nav .btn--nav { display: none; }
  .nav__toggle {
    display: inline-flex; align-items: center; margin-left: auto;
    background: none; border: 1px solid currentColor; border-radius: 2px;
    padding: .6rem 1rem; font: 500 .75rem/1 var(--sans);
    letter-spacing: .12em; text-transform: uppercase; cursor: pointer;
  }
  .menu {
    position: fixed; inset: 0; z-index: 95;
    background: var(--ink); color: var(--cream);
    display: flex; flex-direction: column; justify-content: center;
    gap: .1rem; padding: var(--gut);
  }
  .menu[hidden] { display: none; }
  .menu a {
    font-family: var(--serif); font-size: clamp(2rem, 8vw, 2.75rem);
    text-decoration: none; padding-block: .3rem; line-height: 1.15;
  }
  .menu__close {
    position: absolute; top: 1.2rem; right: var(--gut);
    background: transparent; border: 1px solid var(--rule-strong); color: var(--text);
    border-radius: 2px; padding: .6rem 1rem;
    font: 500 .75rem/1 var(--sans); letter-spacing: .12em;
    text-transform: uppercase; cursor: pointer;
  }
  .menu__meta { margin-top: 2.5rem; font-size: .9375rem; color: var(--muted-ink); display: grid; gap: .35rem; }
  .menu__meta a { font-family: var(--sans); font-size: .9375rem; padding: 0; }
}
@media (min-width: 62.0625rem) { .menu { display: none; } }

/* ---------- hero ---------- */
.hero {
  position: relative; min-height: 100svh;
  display: grid; grid-template-rows: 1fr auto; align-items: end;
  background-color: var(--ink); background-image: var(--glow-field);
  color: var(--cream); overflow: clip; isolation: isolate;
  --on: var(--cream); --on-muted: var(--muted-ink);
  --on-rule: var(--rule-ink); --on-accent: var(--wheat);
}
.hero__media { position: absolute; inset: 0; z-index: 0; background: var(--ink); }
/* The still is the FLOOR of the hero: it is always in the DOM behind the clips,
   so if video is skipped or torn down the hero still has its picture and no
   native play-button overlay ever appears. */
.hero__still { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.hero__clip {
  position: absolute; inset: 0; z-index: 1;
  opacity: 0; transition: opacity 1.1s ease-in-out;
}
.hero__media video, .hero__media img {
  width: 100%; height: 100%; object-fit: cover;
  /* pulled to monochrome and then pushed back warm, so the footage is lit by
     the same amber light as the rest of the page — the shot's defining move. */
  /* No filter at all — the footage plays as shot. */
  filter: none;
}

.hero__inner {
  position: relative; z-index: 2; width: 100%;
  display: grid; place-items: center; min-height: 100%;
  /* No scrim behind any of this, so every glyph carries its own halo. It hugs
     the letterforms rather than covering the footage — the only way to stay
     readable over a moving bright streak without putting a panel back. */
  /* Nothing is painted behind the hero copy — no scrim, no vignette, no panel.
     The video plays clean and legibility comes entirely from this halo, which
     hugs the glyphs instead of covering the footage. */
  /* A tight shadow only. The old third layer (0 4px 30px at 70% black) threw
     a 30px halo off every line, and across a block of copy those halos
     merged into what looked like a faded black box behind the text. This
     keeps the copy legible over the video without painting a panel. */
  text-shadow: 0 1px 2px rgba(0,0,0,.72), 0 1px 6px rgba(0,0,0,.45);
  padding-block: clamp(7rem, 13vh, 9rem) clamp(1.5rem, 4vh, 2.75rem);
}
.hero h1 { margin-block: clamp(1rem, 2.6vh, 1.75rem) clamp(1rem, 2.4vh, 1.5rem); max-width: 17ch; }
/* With no scrim the lede sits straight on the footage, so it takes the full
   ivory rather than the muted grey it used when a dark panel was behind it. */
.hero__lede { max-width: 46ch; color: var(--ivory); }
.hero__cta {
  display: flex; flex-wrap: wrap; gap: .75rem;
  margin-top: clamp(1.5rem, 3.4vh, 2.5rem);
}
/* ---------- section heads ---------- */
.sechead { display: grid; gap: 1.35rem; margin-bottom: clamp(2.5rem, 5vw, 4rem); }
.sechead__row { display: grid; gap: 1.5rem; }
@media (min-width: 58rem) {
  .sechead__row { grid-template-columns: 1.1fr .9fr; align-items: end; gap: 3.5rem; }
}

/* ---------- about ---------- */
.about { display: grid; gap: clamp(2rem, 4vw, 4rem); align-items: center; }
@media (min-width: 58rem) { .about { grid-template-columns: 1fr 1fr; } }
.about__media { position: relative; overflow: hidden; }
.about__media img {
  width: 100%; aspect-ratio: 4 / 3; object-fit: cover;
  filter: none;
}
.about__points { display: grid; gap: 1.5rem; margin-top: 2.25rem; }
.about__point { display: grid; gap: .4rem; padding-top: 1.25rem; border-top: 1px solid var(--on-rule); }
.about__point h3 { font-family: var(--sans); font-size: .9375rem; font-weight: 600; letter-spacing: 0; }
.about__point p { color: var(--on-muted); font-size: .9375rem; }

/* ---------- services ----------
   A card per service: photograph, number, name, one line, and a way through
   to its own page. Six items, so the grid always fills. */
.svcgrid {
  display: grid; gap: 1px; background: var(--line);
  border: 1px solid var(--line); grid-template-columns: 1fr;
}

.svc {
  display: flex; flex-direction: column; text-decoration: none;
  background: var(--void); transition: background-color .45s var(--ease);
}
.svc__media { display: block; overflow: hidden; aspect-ratio: 3 / 2; background: var(--panel); }

.svc__body {
  display: grid; gap: .45rem; align-content: start;
  padding: 1.4rem clamp(1.25rem, 2.2vw, 1.6rem) 1.6rem; flex: 1;
}
.svc__name {
  font-family: var(--mono); font-weight: 700; text-transform: uppercase;
  font-size: .9375rem; letter-spacing: .04em; color: var(--white);
}
.svc__blurb { font-family: var(--sans); font-size: .8125rem; color: var(--dim); line-height: 1.55; }
.svc__go {
  display: inline-flex; align-items: center; gap: .45rem;
  margin-top: auto; padding-top: 1rem;
  font-family: var(--mono); font-size: .5625rem; letter-spacing: .2em;
  text-transform: uppercase; color: var(--white);
}
.svc__go svg { transition: transform .4s var(--ease); }
.svc:hover .svc__go { color: var(--orange); }
.svc:hover .svc__go svg { transform: translateX(4px); }

/* ============================================================
   IMAGERY
   Full colour, always. Photographs are shown as shot — nothing waits for a
   cursor to become itself.
   ============================================================ */
.svc__media img, .pfitem__shot img, .about__media img,
.svchero__media img, .workcard img {
  filter: none;
  transition: transform 1.1s var(--ease);
}
.svc:hover .svc__media img,
.pfitem:hover .pfitem__shot img,
.about__media:hover img,


/* ---------- services ----------
   A plain three-column index. No boxes, no images, no hairline cells — just
   small, evenly set type. The photographs live on the service pages, where
   there is room to show them properly. */
.svcgrid {
  list-style: none; margin: 0; padding: 0;
  display: grid; gap: clamp(1.75rem, 3.5vw, 3rem) clamp(2rem, 5vw, 4.5rem);
  grid-template-columns: 1fr;
  background: none; border: 0;
}
@media (min-width: 40rem) { .svcgrid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 64rem) { .svcgrid { grid-template-columns: repeat(3, 1fr); } }

.svc { background: none; padding: 0; display: block; }
.svc a {
  display: grid; gap: .3rem; text-decoration: none;
  padding-top: .9rem; border-top: 1px solid var(--line);
  transition: border-color .4s var(--ease);
}
.svc a:hover, .svc a:focus-visible { border-color: var(--orange); }
.svc__n {
  font-family: var(--mono); font-size: .5625rem; letter-spacing: .22em;
  color: var(--orange);
}
.svc__name {
  font-family: var(--mono); font-weight: 700; text-transform: uppercase;
  font-size: .8125rem; letter-spacing: .06em; color: var(--white);
  transition: color .35s var(--ease);
}
.svc a:hover .svc__name, .svc a:focus-visible .svc__name { color: var(--orange); }
.svc__blurb {
  font-family: var(--sans); font-size: .8125rem; color: var(--dim);
  line-height: 1.5; max-width: 34ch;
}

/* ---------- pricing ---------- */
.price {
  display: grid; gap: clamp(2rem, 4vw, 3.5rem);
  border: 1px solid var(--on-rule); padding: clamp(1.75rem, 4vw, 3.5rem);
  background: transparent;
}
/* graphite card on the obsidian ground — the brief's "cards" surface */
.section--ink .price, .section--obsidian .price {
  background-image: linear-gradient(160deg, var(--plum) 0%, var(--surface) 100%);
}
.section--warm .price, .section--cream .price, .section--white .price,
.section--champagne .price, .section--sand .price {
  /* on light grounds the card is a raised sheet, not a second tint — the two
     light grounds are close enough now that a flat fill would vanish */
  background-image: linear-gradient(165deg, color-mix(in srgb, var(--ground) 92%, var(--soft)) 0%, var(--ground) 100%);
  border-color: var(--rule);
  box-shadow: var(--shadow-soft);
}
@media (min-width: 58rem) { .price { grid-template-columns: 1fr 1fr; align-items: start; } }
.price__list { display: grid; gap: 1rem; }
.price__list li { display: flex; gap: .85rem; align-items: baseline; font-size: .9375rem; }
.price__list li::before {
  content: ''; flex: none; width: 6px; height: 1px; background: var(--on-accent); margin-top: .65rem;
}

/* ---------- work / client preview ---------- */
.workcard {
  display: grid; gap: 1.5rem; align-items: center;
  border: 1px solid var(--on-rule); padding: clamp(1.25rem, 2.5vw, 1.75rem);
  background-image: linear-gradient(168deg, color-mix(in srgb, var(--ground) 94%, var(--soft)) 0%, var(--ground) 100%);
  text-decoration: none; color: inherit;
  transition: border-color .4s var(--ease), transform .4s var(--ease);
  max-width: 34rem;
}
@media (min-width: 34rem) { .workcard { grid-template-columns: 8.5rem 1fr; } }
.workcard:hover { border-color: var(--ink); transform: translateY(-2px); }
.workcard__shot {
  aspect-ratio: 16 / 9; overflow: hidden; background: var(--ink);
  display: grid; place-items: center;
}
.workcard__shot img { width: 100%; height: 100%; object-fit: cover; object-position: top center; }
.workcard__ph {
  width: 100%; height: 100%;
  display: grid; place-content: center; gap: .3rem; text-align: center; padding: .6rem;
  background: linear-gradient(150deg, var(--surface), var(--bg1));
  color: var(--muted-ink); font-size: .625rem; letter-spacing: .1em; text-transform: uppercase;
}
.workcard h3 { font-size: 1.35rem; }
.workcard__meta { font-size: .8125rem; color: var(--on-muted); margin-top: .3rem; }
.workcard__go {
  font-size: .6875rem; letter-spacing: .14em; text-transform: uppercase;
  color: var(--on-accent); margin-top: .7rem; display: inline-flex; gap: .4rem; align-items: center;
}

/* ---------- contact ---------- */
.contact { display: grid; gap: clamp(2.5rem, 5vw, 4.5rem); }
@media (min-width: 62rem) { .contact { grid-template-columns: .8fr 1.2fr; } }
.contact__lines { display: grid; gap: 1.6rem; margin-top: 2rem; }
.contact__lines dt {
  font-size: .6875rem; letter-spacing: .18em; text-transform: uppercase;
  color: var(--on-muted); margin-bottom: .35rem;
}
.contact__lines dd { margin: 0; font-size: 1.0625rem; }
.contact__lines a { text-decoration: none; border-bottom: 1px solid var(--on-accent); }
.contact__lines a:hover { color: var(--on-accent); }

.form { display: grid; gap: 1.35rem; }
.field { display: grid; gap: .5rem; }
.field > label, .fieldset > legend {
  font-size: .6875rem; letter-spacing: .18em; text-transform: uppercase; color: var(--on-muted);
}
.field input, .field textarea, .field select {
  width: 100%; background: var(--soft); color: var(--on);
  border: 1px solid var(--on-rule); border-radius: 2px;
  padding: .85rem .95rem; font-size: 1rem;
  transition: border-color .3s var(--ease), box-shadow .3s var(--ease);
}
.section--ink .field input, .section--ink .field textarea, .section--ink .field select { background: var(--ink-2); }
.field input:hover, .field textarea:hover, .field select:hover { border-color: var(--on); }
.field input:focus, .field textarea:focus, .field select:focus {
  outline: none; border-color: var(--on-accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--on-accent) 22%, transparent);
}
.field textarea { resize: vertical; min-height: 7.5rem; }
.fieldset { border: 0; padding: 0; margin: 0; display: grid; gap: .75rem; }
.fieldset legend { padding: 0; margin-bottom: .3rem; }
.chips { display: flex; flex-wrap: wrap; gap: .5rem; }
.chip { position: relative; }
.chip input { position: absolute; inset: 0; opacity: 0; width: 100%; height: 100%; cursor: pointer; }
.chip span {
  display: inline-block; padding: .6rem 1rem; border-radius: 2px;
  border: 1px solid var(--on-rule); font-size: .875rem;
  transition: background-color .3s, color .3s, border-color .3s;
}
.chip input:checked + span {
  background-image: var(--grad); color: var(--bg1);
  border-color: transparent; font-weight: 600;
}

.chip input:focus-visible + span { outline: 2px solid var(--on-accent); outline-offset: 3px; }
.consent { display: flex; gap: .8rem; align-items: flex-start; font-size: .875rem; color: var(--on-muted); }
/* 24px, not 17. WCAG 2.5.8 sets 24x24 as the minimum target and this is the
   one control on the site that was under it — and the one people actually
   have to hit on a phone before they can send the form. */
.consent input {
  margin-top: .15rem; width: 1.5rem; height: 1.5rem;
  accent-color: var(--orange); flex: none;
}
.form__hp { position: absolute; left: -9999px; }
.form__status { font-size: .875rem; min-height: 1.4em; }
.form__status[data-state="error"] { color: #9B2C12; font-weight: 500; }
.section--ink .form__status[data-state="error"] { color: #E8A98F; }

/* ---------- page head (inner pages) ---------- */
.page-head {
  padding-block: clamp(8rem, 15vw, 11rem) clamp(2.5rem, 5vw, 3.5rem);
  position: relative; isolation: isolate;
  background-color: var(--soft); --ground: var(--soft);
  --on: var(--black); --on-muted: var(--muted-light);
  --on-rule: var(--rule-light); --on-accent: var(--orange-deep);
  color: var(--black);
  background-image: radial-gradient(85% 80% at 12% 0%, rgba(198,90,50,.06), transparent 64%);
}
.page-head--ink { background-color: var(--ink); background-image: var(--glow-field); color: var(--cream);
  --on: var(--cream); --on-muted: var(--muted-ink); --on-rule: var(--rule-ink); --on-accent: var(--wheat); }
.crumbs { font-size: .75rem; letter-spacing: .1em; text-transform: uppercase; color: var(--on-muted); }
.crumbs a { text-decoration: none; }
.crumbs a:hover { color: var(--on-accent); }

/* ---------- service page ---------- */
.svchero { display: grid; gap: clamp(2rem, 4vw, 3.5rem); align-items: start; }
@media (min-width: 58rem) { .svchero { grid-template-columns: 1.05fr .95fr; } }
.svchero__media img {
  width: 100%; aspect-ratio: 3 / 2; object-fit: cover;
  filter: none;
}
.deliver { display: grid; gap: 1px; background: var(--on-rule); border: 1px solid var(--on-rule); }
@media (min-width: 44rem) { .deliver { grid-template-columns: repeat(2, 1fr); } }
.deliver > div { background: var(--ground); padding: clamp(1.35rem, 2.4vw, 2rem); display: grid; gap: .5rem; align-content: start; }
.deliver h3 { font-family: var(--sans); font-size: .9375rem; font-weight: 600; letter-spacing: 0; }
.deliver p { color: var(--on-muted); font-size: .9375rem; }
.faq { display: grid; border-top: 1px solid var(--on-rule); }
.faq details { border-bottom: 1px solid var(--on-rule); }
.faq summary {
  display: flex; align-items: center; justify-content: space-between; gap: 1.5rem;
  padding-block: clamp(1.1rem, 2vw, 1.5rem); cursor: pointer; list-style: none;
  font-family: var(--serif); font-size: clamp(1.15rem, 1.8vw, 1.45rem); line-height: 1.2;
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after {
  content: ''; flex: none; width: .7rem; height: .7rem;
  border-right: 1px solid var(--on-accent); border-bottom: 1px solid var(--on-accent);
  transform: rotate(45deg) translate(-2px, -2px); transition: transform .35s var(--ease);
}
.faq details[open] summary::after { transform: rotate(-135deg) translate(-2px, -2px); }
.faq__a { padding-bottom: 1.5rem; color: var(--on-muted); max-width: 64ch; }

/* ---------- portfolio ---------- */
/* ---------- portfolio ----------
   A plain, even card grid. It used to alternate a wide screenshot with a text
   column on every other row, which looked considered with three projects and
   would have been a mess with eight. Equal cards are easier to scan, easier to
   compare, and stay right however many go up. */
.pfgrid {
  display: grid; gap: clamp(1.5rem, 2.6vw, 2.25rem);
  grid-template-columns: 1fr;
}

.pfitem {
  display: flex; flex-direction: column;
  border: 1px solid var(--on-rule); border-radius: 3px; overflow: hidden;
  background-image: linear-gradient(168deg,
    color-mix(in srgb, var(--ground) 94%, var(--soft)) 0%, var(--ground) 100%);
  transition: transform .5s var(--ease), box-shadow .5s var(--ease), border-color .5s var(--ease);
}
.pfitem:hover {
  transform: translateY(-3px);
  border-color: color-mix(in srgb, var(--on-accent) 42%, transparent);
  box-shadow: var(--shadow-lift);
}

.pfitem__shot {
  aspect-ratio: 16 / 9; overflow: hidden; background: var(--ink);
  border-bottom: 1px solid var(--on-rule);
}
.pfitem__shot img {
  width: 100%; height: 100%; object-fit: cover; object-position: center top;
  transition: transform 1.2s var(--ease);
}
.pfitem:hover .pfitem__shot img { transform: scale(1.03); }
.pfitem__ph {
  width: 100%; height: 100%; display: grid; place-content: center; gap: .5rem;
  text-align: center; padding: 1.5rem;
  background: repeating-linear-gradient(45deg, #1C0F33 0 10px, #160B2A 10px 20px);
  color: var(--muted-dark);
}
.pfitem__ph b { font-family: var(--serif); font-size: 1.25rem; font-weight: 400; color: var(--cream); display: block; }
.pfitem__ph span { font-size: .6875rem; letter-spacing: .16em; text-transform: uppercase; }

.pfitem__meta {
  display: flex; flex-direction: column; flex: 1;
  padding: clamp(1.25rem, 2.2vw, 1.6rem);
}
/* tag above the name, always — side by side it wrapped on the longer titles
   and only some cards, which made the row look accidental */
.pfitem__head { display: flex; flex-direction: column; align-items: flex-start; gap: .7rem; }
.pfitem__head h2 { font-weight: 400; }
.pfitem__sector {
  margin-top: .45rem; font-size: .6875rem; letter-spacing: .1em;
  text-transform: uppercase; color: var(--on-muted);
}
.pfitem__note { margin-top: .9rem; font-size: .9375rem; color: var(--on-muted); }
.pfitem__link { margin-top: auto; padding-top: 1.25rem; }

.tag {
  font-size: .625rem; letter-spacing: .14em; text-transform: uppercase;
  border: 1px solid var(--on-rule); padding: .3rem .55rem; color: var(--on-muted);
  border-radius: 2px; white-space: nowrap;
}
.tag--live {
  border-color: transparent; color: var(--black);
  background: var(--gold); font-weight: 600;
}

/* ---------- footer ---------- */
.footer {
  background: var(--ink); color: var(--cream); padding-block: clamp(3.5rem, 7vw, 5.5rem) 2rem;
  --on: var(--cream); --on-muted: var(--muted-ink); --on-rule: var(--rule-ink); --on-accent: var(--wheat);
}
.footer__top { display: grid; gap: 2.5rem; padding-bottom: 2.75rem; border-bottom: 1px solid var(--rule-ink); }
@media (min-width: 58rem) { .footer__top { grid-template-columns: 1.5fr 1fr 1fr 1fr; } }
.footer .footer__h, .footer h4 {
  font-family: var(--sans); font-weight: 500; font-size: .6875rem;
  letter-spacing: .18em; text-transform: uppercase; color: var(--muted-ink); margin-bottom: 1.1rem;
}
.footer ul { display: grid; gap: .6rem; }
.footer ul a { text-decoration: none; font-size: .9375rem; color: var(--muted-dark); }
.footer ul a:hover { color: var(--cream); }
.footer__bottom {
  display: flex; flex-wrap: wrap; gap: 1rem; justify-content: space-between;
  padding-top: 1.75rem; font-size: .75rem; color: var(--muted-ink);
}

/* ---------- legal ---------- */
.legal { padding-block: clamp(3rem, 6vw, 4.5rem); }
.legal__body { max-width: 46rem; }
.legal__body h2 {
  font-size: clamp(1.5rem, 2.6vw, 2rem); margin-top: 3.25rem; margin-bottom: 1rem;
  padding-top: 1.75rem; border-top: 1px solid var(--rule);
}
.legal__body h3 { font-family: var(--sans); font-size: 1rem; font-weight: 600; margin-top: 1.85rem; margin-bottom: .5rem; }
.legal__body p, .legal__body li { color: var(--muted-light); }
.legal__body p + p { margin-top: 1rem; }
.legal__body ul, .legal__body ol { margin: 1rem 0 0; padding-left: 1.3rem; display: grid; gap: .5rem; }
.legal__body ul { list-style: disc; }
.legal__body ol { list-style: decimal; }
.legal__body a { color: var(--bronze); }
.legal__body code { font-family: ui-monospace, Menlo, monospace; font-size: .875em; background: rgba(198,90,50,.12); padding: .1em .35em; border-radius: 2px; }
.legal__body table { width: 100%; border-collapse: collapse; margin-top: 1.25rem; font-size: .9375rem; }
.legal__body th, .legal__body td { text-align: left; padding: .8rem .85rem; border: 1px solid var(--rule); vertical-align: top; }
.legal__body th { background: rgba(198,90,50,.10); font-weight: 600; color: var(--on); }
.legal__scroll { overflow-x: auto; }
.callout {
  margin-top: 1.5rem; padding: 1.15rem 1.35rem;
  border-left: 2px solid var(--coral);
  background: rgba(198,90,50,.07); border-radius: 0 3px 3px 0;
  font-size: .9375rem; color: var(--on);
}
.toc { margin-top: 2rem; display: grid; gap: .5rem; font-size: .9375rem; }
.toc a { color: var(--bronze); }

/* ---------- cursor ----------
   One ring, no centre dot. It SHRINKS over anything clickable so it can never
   cover the thing you are about to click.

   Visibility does NOT depend on knowing which sections are dark — that approach
   kept missing surfaces (the CTA band, dark screenshots sitting on a cream
   page). Instead the ring is a dark / white / dark sandwich: a white border with
   a dark halo outside it and a dark line inside it. One of the three always
   contrasts, so it survives cream, near-black, photographs and mid-grey alike.
   `mix-blend-mode: difference` was tried first and is cleaner, but it goes
   invisible against mid-grey — which the graded hero video is full of. */
.cursor, .cursor-dot { display: none; }
@media (hover: hover) and (pointer: fine) {
  body.has-cursor { cursor: none; }
  body.has-cursor a, body.has-cursor button,
  body.has-cursor summary, body.has-cursor label { cursor: none; }
  body.has-cursor input, body.has-cursor textarea { cursor: text; }
  body.has-cursor input[type="checkbox"] { cursor: none; }

  .cursor-dot { display: none !important; }   /* removed by request */

  .cursor {
    display: block; position: fixed; top: 0; left: 0; z-index: 300;
    width: 30px; height: 30px; margin: -15px 0 0 -15px;
    border: 1.5px solid rgba(255, 255, 255, .95); border-radius: 50%;
    box-shadow: 0 0 0 1px rgba(0, 0, 0, .55), inset 0 0 0 1px rgba(0, 0, 0, .45);
    pointer-events: none; will-change: transform;
    transition: width .3s var(--ease), height .3s var(--ease),
                margin .3s var(--ease), background-color .3s, opacity .3s;
  }
  /* smaller on clickables — never larger */
  body.cursor-hover .cursor {
    width: 12px; height: 12px; margin: -6px 0 0 -6px;
    background: #FFFFFF; border-color: #FFFFFF;
    box-shadow: 0 0 0 1.5px rgba(0, 0, 0, .55);
  }
}
@media (prefers-reduced-motion: reduce) {
  .cursor, .cursor-dot { display: none !important; }
  body.has-cursor, body.has-cursor * { cursor: auto !important; }
}

/* ---------- reveals ---------- */
.rv { opacity: 0; transform: translateY(22px); }
.rv.is-in { opacity: 1; transform: none; transition: opacity .85s var(--ease), transform .85s var(--ease); }
.rv-d1.is-in { transition-delay: .07s; }
.rv-d2.is-in { transition-delay: .14s; }
.rv-d3.is-in { transition-delay: .21s; }
@media (prefers-reduced-motion: reduce) { .rv { opacity: 1; transform: none; transition: none; } }

.line { display: block; overflow: hidden; }
.line > span { display: block; transform: translateY(105%); }
.is-ready .line > span { transform: none; transition: transform 1.05s var(--ease); }
.is-ready .line:nth-child(2) > span { transition-delay: .09s; }
.is-ready .line:nth-child(3) > span { transition-delay: .18s; }
@media (prefers-reduced-motion: reduce) { .line > span { transform: none; transition: none; } }

/* ---------- boot ----------
   Replaced the burn-in. This is a calm upward wipe on the site's own ink
   ground with a hairline that tracks real asset progress, then the whole
   panel lifts away. --p is driven from JS, 0% to 100%. */
.boot {
  position: fixed; inset: 0; z-index: 500;
  background-color: var(--ink);
  background-image: var(--glow-field);
  display: grid; place-items: center; --p: 0%;
}
.boot::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background-image: var(--grain); opacity: .05; mix-blend-mode: overlay;
}

.boot__stage { position: relative; width: min(64vw, 19rem); display: grid; gap: 1.4rem; }


/* the hairline. scaleX is set from JS as assets land. */
.boot__bar {
  height: 1px; width: 100%; overflow: hidden;
  background: rgba(247, 242, 234, .14);
}
.boot__bar i {
  display: block; height: 100%; width: 100%;
  transform: scaleX(0); transform-origin: 0 50%;
  background-image: var(--grad);
  transition: transform .45s var(--ease);
}


.boot.is-out {
  transform: translateY(-100%);
  transition: transform .64s var(--ease);
  pointer-events: none;
}
@media (prefers-reduced-motion: reduce) {
  
  .boot__bar i { transition: none; }
  .boot.is-out { transform: none; opacity: 0; transition: opacity .3s linear; }
}


/* ---------- button rows + closing CTA band ---------- */
.btnrow { display: flex; flex-wrap: wrap; gap: .75rem; align-items: center; }

.cta {
  background-color: var(--black); color: var(--ivory);
  padding-block: clamp(4rem, 9vw, 7rem);
  --on: var(--ivory); --on-muted: var(--muted-dark);
  --on-rule: var(--rule-dark); --on-accent: var(--gold);
}
.cta__inner { display: grid; gap: clamp(1.75rem, 3vw, 2.5rem); }
@media (min-width: 62rem) {
  .cta__inner { grid-template-columns: 1.05fr auto; align-items: center; }
  .cta__or { grid-column: 1 / -1; }
}
.cta h2 { color: var(--cream); }
.cta .lede { color: var(--muted-ink); max-width: 40ch; }
.cta__actions { display: flex; flex-wrap: wrap; gap: .75rem; align-content: center; }
.cta__or { font-size: .9375rem; color: var(--muted-ink); margin-top: .25rem; }
.cta__or .link { color: var(--cream); }

/* "other services" list on a service page */
.alsolist { display: grid; gap: 1px; background: var(--rule); border-block: 1px solid var(--rule); }
@media (min-width: 46rem) { .alsolist { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 72rem) { .alsolist { grid-template-columns: repeat(4, 1fr); } }
.alsolist li { background-color: var(--ground); background-image: linear-gradient(168deg, color-mix(in srgb, var(--ground) 94%, var(--soft)) 0%, var(--ground) 100%); }
.alsolist a {
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  padding: 1.15rem 1.25rem; text-decoration: none;
  font-family: var(--serif); font-size: 1.15rem; letter-spacing: -.01em;
  transition: background-color .3s var(--ease), padding-left .3s var(--ease);
}
.alsolist a::after { content: '\2192'; font-family: var(--sans); font-size: .95rem; opacity: .45; transition: transform .3s var(--ease), opacity .3s; }
.alsolist a:hover { background: color-mix(in srgb, var(--ground) 88%, var(--orange)); padding-left: 1.6rem; }
.alsolist a:hover::after { transform: translateX(4px); opacity: 1; }


/* ---------- pricing page ----------
   Tier cards read as a menu: three equal columns, the recommended one lifted a
   step rather than shouted. "Recommended" is TFM's own recommendation — there
   is no client data behind it and it must never be relabelled "most popular". */
.tiers {
  display: grid; gap: clamp(1rem, 2vw, 1.5rem);
  grid-template-columns: 1fr;
  align-items: stretch;
}

.tier {
  position: relative; display: flex; flex-direction: column;
  padding: clamp(1.5rem, 2.6vw, 2.25rem);
  border: 1px solid var(--on-rule); border-radius: 3px;
  background-image: linear-gradient(168deg,
    color-mix(in srgb, var(--ground) 94%, var(--soft)) 0%, var(--ground) 100%);
  transition: transform .5s var(--ease), box-shadow .5s var(--ease), border-color .5s var(--ease);
}
.tier:hover {
  transform: translateY(-3px);
  border-color: color-mix(in srgb, var(--on-accent) 45%, transparent);
  box-shadow: var(--shadow-lift);
}
.tier--pick {
  border-color: color-mix(in srgb, var(--on-accent) 55%, transparent);
  box-shadow: var(--shadow-lift);
}
.tier__flag {
  position: absolute; top: 0; left: clamp(1.5rem, 2.6vw, 2.25rem);
  transform: translateY(-50%);
  background: var(--gold); color: var(--black);
  font: 600 .6875rem/1 var(--sans); letter-spacing: .14em; text-transform: uppercase;
  padding: .45rem .7rem; border-radius: 2px;
}
.tier__name {
  font-family: var(--sans); font-size: .8125rem; font-weight: 600;
  letter-spacing: .16em; text-transform: uppercase; color: var(--on-muted);
}
.tier__price { margin-top: .75rem; display: flex; align-items: baseline; flex-wrap: wrap; gap: .5rem; }
.tier__num { font-family: var(--serif); font-size: clamp(2.1rem, 4.2vw, 2.75rem); line-height: 1; }
.tier__unit { font-size: .8125rem; color: var(--on-muted); letter-spacing: .02em; }
.tier__blurb { margin-top: 1rem; font-size: .9375rem; color: var(--on-muted); }

.tier__list { display: grid; gap: .6rem; margin-top: 1.5rem; list-style: none; padding: 0; }
.tier__list li {
  position: relative; padding-left: 1.35rem; font-size: .9375rem; line-height: 1.5;
}
.tier__list li::before {
  content: ""; position: absolute; left: 0; top: .55em;
  width: .5rem; height: .5rem; border-radius: 50%;
  background-image: var(--grad);
}
.tier__list--no li::before {
  background: none; border-top: 1px solid var(--on-muted);
  height: 0; width: .6rem; border-radius: 0; top: .72em;
}
.tier__not {
  margin-top: 1.15rem; padding-top: 1.15rem; border-top: 1px solid var(--on-rule);
  font-size: .875rem; color: var(--on-muted);
}
.tier__meta {
  margin-top: .9rem; font-size: .75rem; letter-spacing: .1em;
  text-transform: uppercase; color: var(--on-muted);
}
.tier__cta { margin-top: auto; align-self: start; margin-block-start: 1.75rem; }

/* single-price panel — hosting */
.onep {
  display: grid; gap: clamp(2rem, 4vw, 3.5rem);
  border: 1px solid var(--on-rule); border-radius: 3px;
  padding: clamp(1.75rem, 4vw, 3.25rem);
  background-image: linear-gradient(165deg, color-mix(in srgb, var(--ground) 92%, var(--soft)) 0%, var(--ground) 100%);
  box-shadow: var(--shadow-soft);
}
@media (min-width: 58rem) { .onep { grid-template-columns: .85fr 1.15fr; align-items: start; } }
.onep__price { display: flex; align-items: baseline; gap: .6rem; flex-wrap: wrap; }
.onep__num { font-family: var(--serif); font-size: clamp(3.4rem, 8vw, 5rem); line-height: .9; }
.onep__unit { font-size: .9375rem; color: var(--on-muted); }
.onep__alt { margin-top: .9rem; font-size: .9375rem; }
.onep__day { margin-top: 1.25rem; font-size: .9375rem; color: var(--on-muted); max-width: 34ch; }
.onep__fig .btn { margin-top: 1.75rem; }
.onep__cols { display: grid; gap: clamp(1.75rem, 3vw, 2.5rem); }
@media (min-width: 40rem) { .onep__cols { grid-template-columns: 1fr 1fr; } }
.onep__h {
  font-family: var(--sans); font-size: .8125rem; font-weight: 600;
  letter-spacing: .16em; text-transform: uppercase; color: var(--on-muted);
}

/* add-ons */
.addons { display: grid; gap: 0; margin-top: 1.25rem; }
.addon {
  display: flex; justify-content: space-between; align-items: baseline; gap: 1.5rem;
  padding: .95rem 0; border-top: 1px solid var(--on-rule); font-size: .9375rem;
}
.addon:last-child { border-bottom: 1px solid var(--on-rule); }
.addon__p { font-family: var(--serif); font-size: 1.15rem; white-space: nowrap; }

/* the paid-ads notice */
.notice {
  border: 1px solid var(--on-rule); border-left: 3px solid transparent;
  border-image: var(--grad) 1;
  border-radius: 0;
  padding: clamp(1.5rem, 3vw, 2.5rem);
  background-image: linear-gradient(100deg,
    color-mix(in srgb, var(--on-accent) 7%, transparent) 0%, transparent 60%);
}

/* day rate */
.daybox {
  margin-top: clamp(2rem, 4vw, 3rem);
  display: flex; gap: clamp(1.25rem, 3vw, 2.5rem); flex-wrap: wrap; align-items: center;
  padding: clamp(1.5rem, 3vw, 2.25rem);
  border: 1px solid var(--on-rule); border-radius: 3px;
  background-image: linear-gradient(150deg, #2A211B 0%, var(--brown) 100%);
}
.daybox__num {
  font-family: var(--serif); font-size: clamp(2.6rem, 6vw, 3.6rem); line-height: .9;
  display: flex; align-items: baseline; gap: .55rem;
}
.daybox__num span { font-family: var(--sans); font-size: .875rem; color: var(--on-muted); }
.daybox__note { font-size: .9375rem; color: var(--on-muted); max-width: 34ch; }

/* plain-English small print */
.plainrow { display: grid; gap: clamp(1.5rem, 3vw, 2.25rem); margin-top: 2rem; }
@media (min-width: 46rem) { .plainrow { grid-template-columns: 1fr 1fr; } }
.plainrow p { font-size: .9375rem; margin-top: .5rem; }

/* home pricing teaser — four "from" cards that hand off to the full list */
.fromgrid { display: grid; gap: clamp(.75rem, 1.5vw, 1rem); grid-template-columns: 1fr; }
@media (min-width: 38rem) { .fromgrid { grid-template-columns: 1fr 1fr; } }
@media (min-width: 64rem) { .fromgrid { grid-template-columns: repeat(4, 1fr); } }
.fromcard {
  display: grid; align-content: start; gap: .35rem; text-decoration: none;
  padding: clamp(1.25rem, 2.2vw, 1.75rem);
  border: 1px solid var(--on-rule); border-radius: 3px;
  background-image: linear-gradient(168deg,
    color-mix(in srgb, var(--ground) 92%, var(--soft)) 0%, var(--ground) 100%);
  transition: transform .5s var(--ease), border-color .5s var(--ease), box-shadow .5s var(--ease);
}
.fromcard:hover, .fromcard:focus-visible {
  transform: translateY(-3px);
  border-color: color-mix(in srgb, var(--on-accent) 50%, transparent);
  box-shadow: var(--shadow-lift);
}
.fromcard__svc {
  font-size: .75rem; font-weight: 600; letter-spacing: .14em;
  text-transform: uppercase; color: var(--on-muted);
}
.fromcard__price { font-family: var(--serif); font-size: clamp(1.7rem, 3.4vw, 2.15rem); line-height: 1.05; }
.fromcard__unit { font-size: .8125rem; color: var(--on-muted); }
.fromnote { margin-top: 1.5rem; font-size: .9375rem; color: var(--on-muted); max-width: 52ch; }

/* ---------- services grid ----------
   Every service shows its own photograph. Three across on desktop, two on
   tablet, one on a phone — six items so the grid always fills. Editorial
   rather than card-y: a hairline, a big picture, and type doing the work. */
.svcgrid {
  display: grid; gap: clamp(1.5rem, 3vw, 2.5rem);
  grid-template-columns: 1fr;
}

.svc { display: flex; flex-direction: column; text-decoration: none; }
.svc__media {
  display: block; overflow: hidden; aspect-ratio: 4 / 3;
  background: var(--brown); border: 1px solid var(--on-rule);
}
.svc__media img {
  width: 100%; height: 100%; object-fit: cover;
  transition: transform 1.1s var(--ease), filter .6s var(--ease);
}
.svc:hover .svc__media img, .svc:focus-visible .svc__media img { transform: scale(1.04); }

.svc__body {
  display: grid; gap: .4rem;
  padding-top: 1.1rem; margin-top: 1.1rem;
  border-top: 1px solid var(--on-rule);
  position: relative;
}
/* the rule above the title draws in flame on hover — the one flash of colour */
.svc__body::before {
  content: ''; position: absolute; top: -1px; left: 0; right: 0; height: 1px;
  background: var(--orange); transform: scaleX(0); transform-origin: 0 50%;
  transition: transform .55s var(--ease);
}
.svc:hover .svc__body::before, .svc:focus-visible .svc__body::before { transform: scaleX(1); }

.svc__n {
  font-size: .6875rem; font-weight: 600; letter-spacing: .16em;
  color: var(--on-muted); font-variant-numeric: tabular-nums;
}
.svc__name {
  font-family: var(--serif); font-size: clamp(1.4rem, 2.4vw, 1.75rem); line-height: 1.1;
  transition: color .4s var(--ease);
}
.svc:hover .svc__name, .svc:focus-visible .svc__name { color: var(--on-accent); }
.svc__blurb { font-size: .9375rem; color: var(--on-muted); }

@media (prefers-reduced-motion: reduce) {
  .svc__media img, .svc__body::before, .svc__name { transition: none; }
  .svc:hover .svc__media img { transform: none; }
}

/* ---------- contact: reach cards ----------
   Two large targets before the form. Both are real links — tel: dials, mailto:
   opens the mail app — so on a phone the primary action is one tap, which is
   how most of this audience will actually get in touch. */
.reach { display: grid; gap: clamp(1rem, 2vw, 1.5rem); grid-template-columns: 1fr; }
@media (min-width: 46rem) { .reach { grid-template-columns: 1fr 1fr; } }

.reach__card {
  display: flex; gap: clamp(1rem, 2vw, 1.35rem); align-items: flex-start;
  padding: clamp(1.4rem, 2.6vw, 2rem);
  border: 1px solid var(--on-rule); border-radius: 3px; text-decoration: none;
  background-image: linear-gradient(165deg, color-mix(in srgb, var(--ground) 92%, var(--soft)) 0%, var(--ground) 100%);
  box-shadow: var(--shadow-soft);
  transition: transform .5s var(--ease), box-shadow .5s var(--ease), border-color .5s var(--ease);
}
.reach__card:hover, .reach__card:focus-visible {
  transform: translateY(-3px);
  border-color: color-mix(in srgb, var(--on-accent) 48%, transparent);
  box-shadow: var(--shadow-lift);
}
.reach__ico {
  flex: none; width: 2.75rem; height: 2.75rem; display: grid; place-items: center;
  border-radius: 50%; background-image: var(--grad); color: var(--ink);
}
.reach__ico svg { width: 1.3rem; height: 1.3rem; }
.reach__body { display: grid; gap: .3rem; min-width: 0; }
.reach__label {
  font-size: .6875rem; font-weight: 600; letter-spacing: .16em;
  text-transform: uppercase; color: var(--on-muted);
}
.reach__value {
  font-family: var(--serif); font-size: clamp(1.35rem, 2.8vw, 1.75rem); line-height: 1.15;
  overflow-wrap: anywhere;
}
.reach__value--sm { font-size: clamp(1rem, 2vw, 1.2rem); }
.reach__note { font-size: .875rem; color: var(--on-muted); margin-top: .25rem; }
.reach__foot {
  margin-top: clamp(1.5rem, 3vw, 2rem); font-size: .9375rem;
  color: var(--on-muted); max-width: 56ch;
}
.contact--form { margin-top: clamp(3rem, 6vw, 5rem); }


/* ---------- cinematic grade ----------
   CSS filters cannot do a duotone, so every photograph is desaturated and
   darkened by its own filter and then graded by a blended layer on its
   container: purple lifting the shadows, coral and orange warming the
   highlights. That is what makes stock photography sit inside the interface
   instead of on top of it. */
.about__media, .pfitem__shot, .svcpreview, .svcrow__thumb, .svchero__media {
  position: relative; isolation: isolate;
}
/* the hero is deliberately NOT in this list — it stays untinted */
.hero__media { position: absolute; inset: 0; z-index: 0; background: var(--black); }
.about__media::after, .pfitem__shot::after,
.svcpreview::after, .svcrow__thumb::after, .svchero__media::after {
  content: ''; position: absolute; inset: 0; z-index: 2; pointer-events: none;
  background-image:
    linear-gradient(152deg, rgba(217,154,50,.26) 0%, transparent 48%,
                    rgba(198,90,50,.26) 80%, rgba(198,90,50,.30) 100%);
  mix-blend-mode: soft-light;
}
/* a second, quieter pass in screen mode so the shadows carry violet ambience
   rather than going dead black */
.about__media::before, .pfitem__shot::before,
.svcpreview::before, .svcrow__thumb::before, .svchero__media::before {
  content: ''; position: absolute; inset: 0; z-index: 2; pointer-events: none;
  background-image: radial-gradient(120% 90% at 20% 0%,
    rgba(217,154,50,.12) 0%, transparent 62%);
  mix-blend-mode: screen;
}
/* The grade layers live INSIDE .hero__media, which has its own stacking
   context (isolation: isolate), so they can never escape it. The scrim keeps
   its original z-index 1 — raising it put it over .hero__inner (z-index 2)
   and dimmed the headline. */

/* the package a portfolio piece corresponds to, so the work maps to a price */
.pfitem__tags { display: flex; flex-wrap: wrap; gap: .4rem; }
.tag--pkg {
  border-color: var(--rule-strong); color: var(--on);
  background: transparent; font-weight: 600;
}

/* ---------- pricing: the two monthly blocks ---------- */
.pricepair { display: grid; gap: clamp(1rem, 2.4vw, 1.75rem); grid-template-columns: 1fr; }
.priceblock {
  display: flex; flex-direction: column; gap: .75rem;
  padding: clamp(1.6rem, 3vw, 2.5rem);
  border: 1px solid var(--on-rule);
  background-image: linear-gradient(168deg,
    color-mix(in srgb, var(--ground) 94%, var(--soft)) 0%, var(--ground) 100%);
}
.priceblock__name {
  font-size: .75rem; font-weight: 600; letter-spacing: .16em;
  text-transform: uppercase; color: var(--on-muted);
}
.priceblock__fig { display: flex; align-items: baseline; gap: .6rem; flex-wrap: wrap; }
.priceblock__num { font-family: var(--serif); font-size: clamp(2.6rem, 6vw, 3.6rem); line-height: .95; }
.priceblock__unit { font-size: .9375rem; color: var(--on-muted); }
.priceblock__blurb { font-size: .9375rem; color: var(--on-muted); max-width: 40ch; }
.priceblock .btn { margin-top: auto; align-self: start; margin-block-start: 1.5rem; }
.priceblock .tier__list { margin-top: .5rem; }


/* ---------- closing band: its own montage ----------
   Same failsafe shape as the hero — a still underneath that is never removed,
   and the clips are torn out entirely rather than left showing a play button.
   It only starts loading when the band is actually near the viewport. */
.cta { position: relative; isolation: isolate; overflow: clip; }
.cta__media { position: absolute; inset: 0; z-index: 0; background: var(--black); }
.cta__still { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.cta__clip {
  position: absolute; inset: 0; z-index: 1;
  width: 100%; height: 100%; object-fit: cover;
  opacity: 0; transition: opacity 1.1s var(--ease);
}
.cta__clip.is-on { opacity: 1; }
.cta__media img, .cta__media video {
  filter: none;
}
/* Heavy where the copy is, open on the right so the montage is actually
   visible. Same trade the hero makes. */
.cta__scrim {
  position: absolute; inset: 0; z-index: 1;
  background:
    linear-gradient(90deg, rgba(23,20,17,.94) 0%, rgba(23,20,17,.86) 34%,
                    rgba(23,20,17,.46) 68%, rgba(23,20,17,.30) 100%),
    linear-gradient(180deg, rgba(23,20,17,.55) 0%, rgba(23,20,17,.20) 45%, rgba(23,20,17,.70) 100%);
}
.cta__inner { position: relative; z-index: 2; }
.cta__media[data-video="off"] .cta__clip { display: none; }

/* The [to be confirmed] markers sit inside a callout, which sits on a section
   that already carries the warm bloom — two tints stacked. --orange-deep
   lands on 4.43 against that compounded ground, so these take a darker step. */
.callout em, .legal__body em { color: var(--orange); font-style: normal; }


/* ============================================================
   THE STRIP
   ============================================================ */

/* ---------- ticks: the micro-type that runs the page ---------- */
.tick {
  /* Was Space Mono — a typewriter face that read as dated next to everything
     else and belonged to no other element on the page. The site already has a
     voice for small uppercase labels (.eyebrow): Inter Tight, 500, .2em. This
     matches it, so the strip stops looking like a leftover.
     tabular-nums keeps the clock's digits from reflowing every minute, which
     is the one thing the monospace face was genuinely doing for us.
     The 2px inset lines the text's left edge up with the LOGO'S INK rather
     than its box: the mark's artwork carries 2.14% of transparent padding down
     its left side, so a shared box edge left the two looking out of step. */
  font-family: var(--sans); font-size: .6875rem; font-weight: 500;
  letter-spacing: .2em; text-transform: uppercase; color: var(--dim);
  white-space: nowrap; font-variant-numeric: tabular-nums;
}
.hero__top .tick:first-child { padding-left: 2px; }
.tick--r { color: var(--dim); }

/* ============================================================
   HERO
   ============================================================ */
.hero {
  position: relative; min-height: 100svh;
  display: grid; grid-template-rows: auto 1fr auto;
  overflow: clip; background: var(--void);
}
.hero__media { position: absolute; inset: 0; z-index: 0; background: var(--void); }
.hero__still, .hero__clip {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
}

.hero__clip { z-index: 1; opacity: 0; transition: opacity 1.4s var(--ease); }

/* SCRIM. The hero copy sits directly on moving footage, so it needs a
   guaranteed dark ground rather than whatever frame happens to be playing.
   Measured against the still with no scrim, the 13px body copy ran at 1.3:1
   average and 1:1 at worst — nowhere near the 4.5:1 AA needs — because the
   crop now (correctly) puts the lit laptop screen behind the text. The old
   crop hid this by pointing at black backdrop instead; the failure was always
   there, it just had nothing bright under it.
   Weighted to the bottom, where the lede, body copy and buttons live, and
   lifted further on phones where the text spans the full width. Sits at
   z-index 2: above both clips, below .hero__inner at 3. */
.hero__media::after {
  content: ''; position: absolute; inset: 0; z-index: 2; pointer-events: none;
  background-image: linear-gradient(180deg,
    rgba(10, 7, 6, .58) 0%,
    rgba(10, 7, 6, .34) 26%,
    rgba(10, 7, 6, .60) 62%,
    rgba(10, 7, 6, .86) 100%);
}
@media (max-width: 46rem) {
  .hero__media::after {
    background-image: linear-gradient(180deg,
      rgba(10, 7, 6, .62) 0%,
      rgba(10, 7, 6, .58) 30%,
      rgba(10, 7, 6, .80) 62%,
      rgba(10, 7, 6, .92) 100%);
  }
}
/* autoplay refused and we are waiting for a gesture: stay on the still */
.hero__media[data-video="waiting"] .hero__clip,
.hero__media[data-video="off"] .hero__clip { opacity: 0; }
.hero__clip.is-on { opacity: 1; }
/* the footage is desaturated so the only colour on the page stays the accent */


.hero__top, .hero__foot {
  position: relative; z-index: 3;
  display: flex; align-items: center; justify-content: space-between; gap: 1.5rem;
  padding: 1.1rem var(--gut);
}
/* the nav is fixed over this, so the top bar starts below it */
.hero__top {
  border-bottom: 1px solid rgba(250,250,250,.07);
  padding-top: clamp(4.5rem, 7vw, 5.5rem);
}
.hero__foot {
  border-top: 1px solid rgba(250,250,250,.07); flex-wrap: wrap;
  /* the pause control wraps onto its own line whenever the service list fills
     the row, which is most widths. A full 1.5rem row-gap there pushed the hero
     past 100svh on a short laptop, so the vertical gap is tightened while the
     gap BETWEEN the two on one line stays as it was. */
  row-gap: .5rem;
}

.hero__inner { position: relative; z-index: 3; display: grid; align-content: center; }

/* The statement. Three lines, the middle one enormous in the display face —
   the only place Archivo Black appears on the entire site. */
.hero__h { margin: 0; display: grid; gap: .12em; max-width: 22ch; }
.hero__stmt {
  display: block; font-family: var(--mono); font-weight: 700;
  /* revealed by a clip, so the real text is always in the DOM */
  /* the clip has to reach below the baseline or it shears the descenders off
     the bottom line ("judged", "things") — hence the negative bottom inset */
  clip-path: inset(-0.06em 100% -0.22em 0);
  animation: stmt-in .9s var(--ease) forwards;
  font-size: clamp(1.35rem, 3.2vw, 2.5rem);
  letter-spacing: .01em; color: var(--white); line-height: 1.18;
  text-transform: none;
}
.hero__stmt:nth-child(2) { animation-delay: .12s; }
.hero__stmt:nth-child(3) { animation-delay: .24s; }
@keyframes stmt-in { to { clip-path: inset(-0.06em 0 -0.22em 0); } }
.hero__lede { margin-top: clamp(1.5rem, 3vw, 2rem); max-width: 46ch; }
.hero__acts { display: flex; flex-wrap: wrap; gap: .75rem; margin-top: clamp(1.75rem, 3.5vw, 2.5rem); }

/* the services strip along the bottom edge of the frame */
.hero__svcs {
  list-style: none; margin: 0; padding: 0;
  display: flex; flex-wrap: wrap; gap: 0 1.75rem;
}
.hero__svcs a {
  font-family: var(--mono); font-size: .625rem; letter-spacing: .18em;
  text-transform: uppercase; color: var(--dim); text-decoration: none;
  padding-block: .35rem; position: relative;
  transition: color .35s var(--ease);
}
.hero__svcs a::after {
  content: ''; position: absolute; left: 0; right: 0; bottom: 0; height: 1px;
  background: var(--orange); transform: scaleX(0); transform-origin: 0 50%;
  transition: transform .4s var(--ease);
}
.hero__svcs a:hover, .hero__svcs a:focus-visible { color: var(--white); }
.hero__svcs a:hover::after, .hero__svcs a:focus-visible::after { transform: scaleX(1); }

@media (max-width: 46rem) {
  .hero__foot { flex-direction: column; align-items: flex-start; gap: .75rem; }
  .hero__svcs { gap: 0 1.1rem; }
}

@media (prefers-reduced-motion: reduce) {
  .hero__stmt { animation: none; clip-path: none; }
}

/* ============================================================
   IMAGERY
   Everything is monochrome until you touch it. That keeps --orange the only
   colour on the page, and for a studio that sells photography the work
   returning to full colour on hover is the point rather than a trick.
   ============================================================ */
.svc__media img, .pfitem__shot img, .about__media img,
.svchero__media img, .workcard img {
  filter: none;
  transition: filter .55s var(--ease), transform 1.1s var(--ease);
}
.svc:hover .svc__media img,
.pfitem:hover .pfitem__shot img,
.about__media:hover img,


/* ---------- services: a strip of frames ---------- */
.svcgrid { display: grid; gap: 1px; background: var(--line); border-block: 1px solid var(--line); }
@media (min-width: 42rem) { .svcgrid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 68rem) { .svcgrid { grid-template-columns: repeat(3, 1fr); } }

.svc {
  display: flex; flex-direction: column; text-decoration: none;
  background: var(--void); padding: 0;
  transition: background-color .45s var(--ease);
}
.svc:hover, .svc:focus-visible { background: var(--panel); }
.svc__media { display: block; overflow: hidden; aspect-ratio: 3 / 2; border: 0; background: var(--panel); }
.svc__media img { width: 100%; height: 100%; object-fit: cover; }
.svc:hover .svc__media img { transform: scale(1.03); }

.svc__body {
  display: grid; gap: .5rem; padding: 1.5rem clamp(1.25rem, 2.2vw, 1.75rem) 1.75rem;
  border: 0; margin: 0;
}
.svc__body::before { display: none; }
.svc__n {
  font-family: var(--mono); font-size: .625rem; letter-spacing: .2em;
  color: var(--orange);
}
.svc__name {
  font-family: var(--mono); font-weight: 700; text-transform: uppercase;
  font-size: clamp(.9375rem, 1.5vw, 1.0625rem); letter-spacing: 0;
  color: var(--white);
}
.svc__blurb { font-family: var(--sans); font-size: .875rem; color: var(--dim); line-height: 1.55; }

/* ---------- pricing ---------- */
.tiers { display: grid; gap: 1px; background: var(--line); border: 1px solid var(--line); }
@media (min-width: 56rem) { .tiers { grid-template-columns: repeat(3, 1fr); } }
.tier {
  background: var(--void); border: 0; border-radius: 0;
  padding: clamp(1.75rem, 3vw, 2.5rem);
  display: flex; flex-direction: column; box-shadow: none;
  transition: background-color .45s var(--ease);
}
.tier:hover { transform: none; background: var(--panel); box-shadow: none; border: 0; }
.tier--pick { background: var(--panel); box-shadow: none; border: 0; }
.tier__flag {
  position: static; transform: none; align-self: flex-start;
  background: var(--orange); color: var(--void);
  font-family: var(--mono); font-size: .5625rem; font-weight: 700;
  letter-spacing: .2em; padding: .35rem .6rem; border-radius: 0; margin-bottom: 1.25rem;
}
.tier__name {
  font-family: var(--mono); font-size: .6875rem; letter-spacing: .22em;
  text-transform: uppercase; color: var(--dim); font-weight: 400;
}
.tier__price { margin-top: .85rem; display: flex; align-items: baseline; gap: .5rem; flex-wrap: wrap; }
.tier__num { font-family: var(--mono); font-weight: 700; font-size: clamp(2.1rem, 4.5vw, 3rem); color: var(--white); letter-spacing: -.02em; }
.tier__unit { font-family: var(--mono); font-size: .625rem; letter-spacing: .18em; text-transform: uppercase; color: var(--dim); }
.tier__blurb { font-family: var(--sans); margin-top: 1rem; font-size: .875rem; color: var(--mid); line-height: 1.6; }
.tier__list { display: grid; gap: .55rem; margin-top: 1.5rem; list-style: none; padding: 0; }
.tier__list li { position: relative; padding-left: 1.15rem; font-family: var(--sans); font-size: .875rem; color: var(--mid); line-height: 1.5; }
.tier__list li::before {
  content: ''; position: absolute; left: 0; top: .6em;
  width: .4rem; height: 1px; background: var(--orange); border-radius: 0;
}
.tier__not { margin-top: 1.15rem; padding-top: 1.15rem; border-top: 1px solid var(--line); font-family: var(--sans); font-size: .8125rem; color: var(--dim); }
.tier__meta { margin-top: .85rem; font-family: var(--mono); font-size: .5625rem; letter-spacing: .18em; text-transform: uppercase; color: var(--dim); }
.tier__cta { margin-top: auto; align-self: stretch; margin-block-start: 1.75rem; justify-content: center; }

/* the monthly pair + single-price panel */
.pricepair { display: grid; gap: 1px; background: var(--line); border: 1px solid var(--line); }
@media (min-width: 52rem) { .pricepair { grid-template-columns: 1fr 1fr; } }
.priceblock { background: var(--void); border: 0; }
.priceblock__num { font-family: var(--mono); font-weight: 700; color: var(--white); }
.priceblock__name, .priceblock__unit { font-family: var(--mono); letter-spacing: .2em; color: var(--dim); }
.onep { border: 1px solid var(--line); border-radius: 0; background: var(--void); box-shadow: none; background-image: none; }
.onep__num { font-family: var(--mono); font-weight: 700; color: var(--white); }
.onep__h { font-family: var(--mono); letter-spacing: .2em; color: var(--dim); }
.addon { border-color: var(--line); font-family: var(--sans); }
.addon__p { font-family: var(--mono); color: var(--white); }

/* ---------- portfolio ---------- */
.pfgrid { display: grid; gap: 1px; background: var(--line); border: 1px solid var(--line); }
@media (min-width: 44rem) { .pfgrid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 72rem) { .pfgrid { grid-template-columns: repeat(3, 1fr); } }
.pfitem { background: var(--void); border: 0; border-radius: 0; box-shadow: none; background-image: none; }
.pfitem:hover { transform: none; background: var(--panel); box-shadow: none; border: 0; }
.pfitem__shot { border: 0; border-bottom: 1px solid var(--line); background: var(--panel); }
.pfitem__meta { padding: clamp(1.25rem, 2.2vw, 1.6rem); }
.tag {
  font-family: var(--mono); font-size: .5625rem; letter-spacing: .2em;
  border-color: var(--line-2); color: var(--dim); border-radius: 0;
}
.tag--live { background: var(--orange); color: var(--void); border-color: transparent; }
.tag--pkg { border-color: var(--line-2); color: var(--dim); background: transparent; }
.pfitem__sector { font-family: var(--mono); letter-spacing: .16em; color: var(--dim); }
.pfitem__note { font-family: var(--sans); color: var(--mid); }

/* ---------- page heads ---------- */
.page-head {
  background: var(--void); background-image: none;
  border-bottom: 1px solid var(--line);
  padding-block: clamp(8rem, 15vw, 11rem) clamp(2.5rem, 5vw, 3.5rem);
}
.crumbs { font-family: var(--mono); font-size: .625rem; letter-spacing: .2em; color: var(--dim); }
.crumbs a { color: var(--dim); }
.crumbs a:hover { color: var(--orange); }

/* ---------- buttons ---------- */
.btn {
  --b-face: transparent; --b-text: var(--white);
  --b-wipe: var(--orange); --b-text-hover: var(--void);
  --b-border: var(--line-2);
  font-family: var(--mono); font-size: .625rem; font-weight: 700;
  letter-spacing: .2em; text-transform: uppercase;
  padding: 1rem 1.5rem; border-radius: 0;
}
.btn--solid, .btn--molten {
  --b-face: var(--orange); --b-text: var(--void);
  --b-wipe: var(--white); --b-text-hover: var(--void);
  --b-border: var(--orange);
}
.btn--ghost, .btn--onink, .btn--cream, .btn--dark {
  --b-face: transparent; --b-text: var(--white);
  --b-wipe: var(--orange); --b-text-hover: var(--void);
  --b-border: var(--line-2);
}
.btn:hover, .btn:focus-visible { border-color: var(--orange); }

/* ---------- nav ---------- */
.nav { padding-block: 1.1rem; color: var(--white); }
.nav.is-solid {
  background: rgba(10,10,10,.92);
  backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
  box-shadow: 0 1px 0 var(--line);
}
.nav__links a {
  font-family: var(--mono); font-size: .625rem; letter-spacing: .18em;
  text-transform: uppercase; color: var(--dim); font-weight: 400;
}
.nav__links a:hover, .nav__links a[aria-current="page"] { color: var(--white); }
.nav__links a::after { background: var(--orange); }
.nav .btn--nav, .nav.is-solid .btn--onink {
  --b-face: var(--orange); --b-text: var(--void);
  --b-wipe: var(--white); --b-text-hover: var(--void);
  --b-border: var(--orange);
}
.nav__progress i { background: var(--orange); }

/* ---------- footer + closing band ---------- */
.footer { background: var(--void); border-top: 1px solid var(--line); color: var(--mid); }
.footer__h, .footer h2 { font-family: var(--mono); font-size: .625rem; letter-spacing: .22em; color: var(--dim); }
.footer ul a { font-family: var(--sans); color: var(--mid); }
.footer ul a:hover { color: var(--orange); }
.cta { background: var(--void); border-top: 1px solid var(--line); }
.cta__scrim {
  background:
    linear-gradient(90deg, rgba(10,10,10,.95) 0%, rgba(10,10,10,.86) 38%, rgba(10,10,10,.5) 100%),
    linear-gradient(180deg, rgba(10,10,10,.6) 0%, rgba(10,10,10,.3) 45%, rgba(10,10,10,.8) 100%);
}


/* ---------- forms ---------- */
.field input, .field textarea, .field select {
  background: var(--panel); border: 1px solid var(--line-2); border-radius: 0;
  color: var(--white); font-family: var(--sans);
}
.field input:focus, .field textarea:focus { border-color: var(--orange); outline: none; box-shadow: 0 0 0 2px rgba(255,107,53,.28); }
.field > label, .fieldset > legend { font-family: var(--mono); letter-spacing: .2em; color: var(--dim); }
.chip span { border: 1px solid var(--line-2); border-radius: 0; font-family: var(--mono); font-size: .625rem; letter-spacing: .14em; color: var(--mid); }
.chip input:checked + span { background: var(--orange); color: var(--void); border-color: var(--orange); }

/* ---------- reach cards (contact) ---------- */
.reach { gap: 1px; background: var(--line); border: 1px solid var(--line); }
.reach__card {
  background: var(--void); background-image: none; border: 0; border-radius: 0;
  box-shadow: none;
}
.reach__card:hover { transform: none; background: var(--panel); box-shadow: none; border: 0; }
.reach__ico { background: var(--orange); color: var(--void); border-radius: 0; }
.reach__label { font-family: var(--mono); letter-spacing: .2em; color: var(--dim); }
.reach__value { font-family: var(--mono); font-weight: 700; color: var(--white); }
.reach__note { font-family: var(--sans); color: var(--dim); }

/* ---------- from-cards on the home pricing teaser ---------- */
.fromgrid { gap: 1px; background: var(--line); border: 1px solid var(--line); }
.fromcard {
  background: var(--void); background-image: none; border: 0; border-radius: 0;
  box-shadow: none;
}
.fromcard:hover { transform: none; background: var(--panel); box-shadow: none; border: 0; }
.fromcard__svc { font-family: var(--mono); letter-spacing: .2em; color: var(--dim); }
.fromcard__price { font-family: var(--mono); font-weight: 700; color: var(--white); }
.fromcard__unit { font-family: var(--mono); font-size: .5625rem; letter-spacing: .16em; color: var(--dim); }
.fromnote { font-family: var(--sans); color: var(--dim); }

/* ---------- faq ---------- */
.faq details { border-top: 1px solid var(--line); }
.faq summary { font-family: var(--mono); text-transform: uppercase; letter-spacing: .04em; color: var(--white); font-size: .875rem; }
.faq__a p { font-family: var(--sans); color: var(--mid); }


/* letterforms — white, and briefly orange as the scan crosses them */

/* the flame — always orange. This is the signature. */


/* the scan bar itself: a hairline of orange that travels the mark on hover */


  
  

/* the letters take the colour as the bar passes, then give it back */

  


/* nothing may crowd the mark */
.nav__inner { display: flex; align-items: center; gap: clamp(1.25rem, 3vw, 2.5rem); }
/* .logo was the old SVG mark's class; the mark is now .tfmlogo. Without
   this the nav lost its spacer and the whole row bunched to the left. */
.nav .tfmlogo--nav { margin-right: auto; }
.nav__links { margin-left: 0; }

/* Emphasis is a colour change, never a slant. Space Mono's italic is loose at
   heading size and reads as a mistake next to the upright caps. This sits last
   because earlier duplicate `em` rules from previous palettes still linger in
   this file — see the note in README about deduping it. */
em, .section em, .hero em, .cta em { font-style: normal; color: var(--orange); }


/* ---------- prices ----------
   Figures are set in the serif, not the monospace. Space Mono is right for
   labels and data but reads blocky and machine-like on a number somebody is
   deciding whether to spend; the serif carries it better. */
.tier__num, .priceblock__num, .onep__num, .fromcard__price, .addon__p {
  font-family: var(--serif); font-weight: 400;
  letter-spacing: -.01em; font-feature-settings: "lnum" 1;
}
.tier__num { font-size: clamp(2.6rem, 5.5vw, 3.75rem); line-height: .95; }
.priceblock__num { font-size: clamp(2.6rem, 6vw, 3.6rem); }
.onep__num { font-size: clamp(2.4rem, 5.5vw, 3.4rem); }
.fromcard__price { font-size: clamp(1.7rem, 3.4vw, 2.2rem); }
.addon__p { font-size: 1.2rem; }

/* Nothing on this site is desaturated. Appended last because duplicate rules
   from earlier palettes still linger further up this file. */
.hero__media img, .hero__media video,
.cta__media img, .cta__media video,
.svc__media img, .pfitem__shot img, .about__media img,
.svchero__media img, .workcard img,
.svcrow__thumb img, .svcpreview__img { filter: none; }

/* the plain-English line under the hero copy: what this business actually is */
.hero__what {
  margin-top: 1.1rem; max-width: 52ch;
  font-family: var(--sans); font-size: .8125rem; line-height: 1.6;
  color: var(--dim);
}

/* ---------- other services (service pages) ----------
   Was a row of bare text boxes that read as empty. Now the same card the home
   page uses, at a smaller size: picture, name, one line. */
.alsogrid {
  display: grid; gap: 1px; background: var(--line);
  border: 1px solid var(--line); grid-template-columns: 1fr;
}
@media (min-width: 44rem) { .alsogrid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 68rem) { .alsogrid { grid-template-columns: repeat(5, 1fr); } }

.alsocard {
  display: flex; flex-direction: column; text-decoration: none;
  background: var(--void); transition: background-color .4s var(--ease);
}
.alsocard:hover, .alsocard:focus-visible { background: var(--panel); }
.alsocard__media { display: block; overflow: hidden; aspect-ratio: 4 / 3; background: var(--panel); }
.alsocard__media img { width: 100%; height: 100%; object-fit: cover; transition: transform 1s var(--ease); }
.alsocard:hover .alsocard__media img { transform: scale(1.05); }
.alsocard__body { display: grid; gap: .3rem; padding: .95rem 1rem 1.15rem; }
.alsocard__name {
  font-family: var(--mono); font-weight: 700; text-transform: uppercase;
  font-size: .6875rem; letter-spacing: .12em; color: var(--white);
}
.alsocard:hover .alsocard__name { color: var(--orange); }
.alsocard__blurb { font-family: var(--sans); font-size: .75rem; color: var(--dim); line-height: 1.45; }

/* a short silent loop at the top of a service page, where footage exists */
.svcloop {
  width: 100%; aspect-ratio: 3 / 2; object-fit: cover; display: block;
  background: var(--panel); border: 1px solid var(--line);
}


/* ---------- hero footage exposure ----------
   The hero carries no scrim, no vignette and no panel — the video runs clean
   to the edges and nothing is painted behind the words. But footage bright
   enough to compete with the copy has to be brought down at source, so the
   clip itself is exposed darker. This is a grade on the video, not a shape
   over it: there is no box, no shading and no edge anywhere on the page. */
/* Nothing is painted behind the hero copy — no scrim, no vignette, no panel —
   so legibility rests on the footage being dark to begin with. All four clips
   are intrinsically dim, which is why this only needs a gentle pull rather
   than the heavy one the code clip demanded. */
.hero__media video, .hero__media img { filter: brightness(.58) contrast(1.05); }


.logo { position: relative; display: inline-flex; align-items: center; flex: none; text-decoration: none; }


/* HOVER — a shutter firing. The mark dips as if the button is pressed, the
   frame flashes, and an orange bloom comes off the aperture as it opens again.
   Fast on purpose: a shutter is not a swoosh. */


.boot { position: fixed; inset: 0; z-index: 500; background: var(--void); display: grid; place-items: center; }
.boot__stage { position: relative; width: min(72vw, 22rem); display: grid; gap: 1.6rem; justify-items: center; }


/* the hairline reads as the focus confirmation once it completes */
.boot__bar { height: 1px; width: 100%; overflow: hidden; background: rgba(250,250,250,.12); }

.boot.is-out { opacity: 0; transform: scale(1.02); transition: opacity .5s var(--ease), transform .5s var(--ease); pointer-events: none; }

@media (prefers-reduced-motion: reduce) {
  
  .boot.is-out { transform: none; }
  }

.mark { position: relative; display: block; line-height: 0; }
@keyframes sheen {
  0%   { opacity: 0; transform: translateX(0); }
  14%  { opacity: 1; }
  86%  { opacity: 1; }
  100% { opacity: 0; transform: translateX(232px); }
}

/* ============================================================
   BOOT — the ring sweeps into place around the wordmark
   The loader runs the header logo's hover animation, verbatim: one
   revolution on the same easing, the same warmed glow, the same sheen. The
   ring is masked by the letterforms, so it sweeps behind a clean gap at the
   T and the M rather than over them.
   The letters land inside it in the first third of a second, so the wordmark
   is readable however quickly the page is released.
   ============================================================ */
.boot { position: fixed; inset: 0; z-index: 500; background: var(--void); display: grid; place-items: center; }
.boot[hidden] { display: none; }
.boot__stage { position: relative; width: min(46vw, 14.5rem); display: grid; gap: 1.9rem; justify-items: center; }

.boot__halo {
  position: absolute; left: 50%; top: 42%;
  width: 76%; aspect-ratio: 1; transform: translate(-50%,-50%);
  border-radius: 50%; pointer-events: none;
  background: radial-gradient(circle,
      rgba(255,140,70,.20) 0%, rgba(255,95,35,.07) 50%, rgba(255,95,35,0) 72%);
  filter: blur(18px); opacity: 0; will-change: opacity;
  animation: halo-warm .9s ease-out .1s both;
}

.mark--boot { width: 100%; }

@keyframes letter-in {
  0%   { opacity: 0; transform: translateY(10%) scale(.9); }
  100% { opacity: 1; transform: none; }
}
@keyframes halo-warm {
  0%   { opacity: 0; }
  100% { opacity: .6; }
}

.boot__bar { height: 1px; width: 100%; overflow: hidden; background: rgba(250,250,250,.12); }
.boot__bar i { display: block; height: 100%; width: 100%; transform: scaleX(0); transform-origin: 0 50%;
               background: var(--orange); transition: transform .45s var(--ease); }
.boot.is-out { opacity: 0; transition: opacity .5s var(--ease); pointer-events: none; }

@media (prefers-reduced-motion: reduce) {
  .logo:hover .tfm__sweepbar, .logo:focus-visible .tfm__sweepbar { animation: none; }
  .mark--boot .tfm__sweepbar { animation: none; opacity: 0; }
  .mark--boot .tfm__l { animation: none; opacity: 1; transform: none; }
  .boot__halo { animation: none; opacity: .6; transform: translate(-50%,-50%); }
  .boot__bar i { transition: none; }
}

/* the nav mark */
.logo .mark { height: clamp(2.6rem, 3.4vw, 3.15rem); }

.svcbtn {
  /* .34rem (not .24) so the tap target clears the 24px WCAG 2.2 AA minimum
     (SC 2.5.8). The type is untouched — this only grows the hit area. */
  display: block; padding: .34rem 0; text-align: center;
  font-family: var(--mono); font-size: .5625rem; letter-spacing: .15em;
  line-height: 1.5; text-transform: uppercase; text-decoration: none;
  color: var(--mid); background: none; border: 0;
  text-shadow: 0 1px 3px rgba(0,0,0,.95), 0 0 12px rgba(0,0,0,.8);
  transition: color .2s var(--ease);
}
.svcbtn:hover, .svcbtn:focus-visible { color: var(--white); }
.svcbtn--all { color: var(--orange); margin-top: .45rem; }
.svcbtn--all:hover, .svcbtn--all:focus-visible { color: var(--white); }

/* the burger panel lists the six outright rather than nesting them behind
   another tap — there is room, and a dropdown inside a drawer is a chore */
.menu .menu__label {
  font-family: var(--mono); font-size: .625rem; letter-spacing: .18em;
  text-transform: uppercase; color: var(--dim); margin-bottom: .15rem;
  line-height: 1.4;
}
.menu .menu__svcs { display: grid; gap: .35rem; margin-bottom: .8rem; max-width: 22rem; }
.menu .menu__svc {
  font-family: var(--mono); font-size: .6875rem; line-height: 1.3;
  letter-spacing: .12em; text-transform: uppercase;
  color: var(--mid); text-decoration: none;
  padding: .62rem .8rem; border: 1px solid var(--line); background: var(--panel-2);
}
.menu .menu__svc:hover, .menu .menu__svc:focus-visible {
  color: var(--white); border-color: var(--orange);
}

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


/* Email addresses are not underlined. Scoped to mail links by attribute so
   the privacy-notice and phone links keep their rule — this is (0,1,1), which
   clears .link at (0,1,0) and ties .contact__lines a, and it is later. */
a[href^="mailto:"] {
  border-bottom: 0; text-decoration: none; padding-bottom: 0;
}

/* ============================================================
   CRAWLABILITY — content must never need JavaScript to be visible
   .rv starts at opacity:0 and is revealed by an IntersectionObserver. That is
   fine for people, but it makes every revealed section conditional on a script
   running to completion: if the observer never fires — a render budget cut
   short, a script error, a crawler that does not scroll — the text is still in
   the DOM but painted at zero, and Google treats content hidden by CSS as
   lower confidence.

   So the hidden state is gated behind a .js class set on <html> before first
   paint. No JS, no hiding: the page renders fully visible, which is exactly
   what a crawler should see. With JS the gate applies and the reveals behave
   as designed, with no flash, because the class lands before the first paint.
   ============================================================ */
html:not(.js) .rv { opacity: 1 !important; transform: none !important; }
html:not(.js) .line > span { transform: none !important; }
html:not(.js) .boot { display: none !important; }

/* ============================================================
   PARTNERS BAND
   A seamless marquee. The track holds the logo run six times and travels
   exactly one run's width (16.667%), so the frame it lands on is identical to
   the frame it started on — a logo sliding off the left is the same logo
   arriving on the right, with no jump at the wrap. Six copies, because the
   track has to be at least the viewport plus one run or the row runs dry at
   the right-hand edge on a wide screen.

   The edges are masked to transparent instead of being left hard: logos
   snapping into existence at the boundary is the thing that makes a marquee
   look cheap.
   ============================================================ */
.partners {
  position: relative; overflow: hidden;
  padding: clamp(1.6rem, 3vw, 2.4rem) 0;
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 9%, #000 91%, transparent);
          mask-image: linear-gradient(90deg, transparent, #000 9%, #000 91%, transparent);
}
.partners__track {
  display: flex; align-items: center; gap: clamp(3rem, 7vw, 6rem);
  margin: 0; padding: 0; list-style: none; width: max-content;
  animation: partners-roll 34s linear infinite;
  will-change: transform;
}
.pmark { flex: none; display: block; }

@keyframes partners-roll {
  from { transform: translateX(0); }
  to   { transform: translateX(-16.6667%); }   /* exactly one run of six */
}

/* black and white, and held back until you look at them */
.plogo {
  display: block; height: clamp(2.4rem, 4vw, 3.1rem); width: auto;
  /* the band used to be forced monochrome; each client's own colourway now
     shows instead — ProFocus's cream, Claudio's accent blue, Zee's neon red */
  opacity: .88;
  transition: opacity .35s var(--ease);
}
.pmark:hover .plogo { opacity: 1; }

.plogo text { fill: var(--white); }
.plogo__sub {
  font-family: var(--sans); font-size: 10px; font-weight: 500;
  letter-spacing: 3.1px; fill: var(--mid);
}
.plogo__main { font-family: var(--sans); font-size: 34px; font-weight: 800; letter-spacing: -.4px; }
.plogo__dot  { fill: #2F8FE0; }      /* Coaching by Claudio's accent blue */

.plogo__zee { font-family: var(--sans); font-size: 30px; font-weight: 700; letter-spacing: 1px; }
.plogo__zeesub {
  font-family: var(--mono); font-size: 15px; letter-spacing: 5.4px; fill: var(--mid);
}
.plogo__rule { fill: var(--line-2); }

.plogo__ap { fill: #F9F6F1; }        /* ProFocus's own cream */
.plogo__pro {
  font-family: var(--sans); font-size: 19px; font-weight: 700; letter-spacing: 1.6px;
}
.plogo__realty {
  font-family: var(--mono); font-size: 11px; letter-spacing: 6.2px; fill: var(--mid);
}

@media (prefers-reduced-motion: reduce) {
  .partners__track { animation: none; }
  .plogo { transition: none; }
}

.plogo__tlc { font-family: var(--sans); font-size: 32px; font-weight: 800; letter-spacing: 1px; }
.plogo__tlcsub { font-family: var(--mono); font-size: 15px; letter-spacing: 5.4px; fill: var(--mid); }

/* what the job was for, and what the package actually covered */
.pfitem__brief {
  font-family: var(--mono); font-size: .6875rem; letter-spacing: .1em;
  text-transform: uppercase; color: var(--orange); margin-top: .85rem;
}
.pfitem__inc {
  list-style: none; margin: 1rem 0 0; padding: 0;
  display: flex; flex-wrap: wrap; gap: .4rem;
}
.pfitem__inc li {
  font-family: var(--mono); font-size: .625rem; letter-spacing: .09em;
  text-transform: uppercase; color: var(--mid);
  border: 1px solid var(--line); background: var(--panel-2);
  padding: .34rem .6rem;
}
.tag--soon { border-color: var(--orange); color: var(--orange); }
/* A third state, one step further back than "going live shortly": the client is
   real but there is no design to show yet. Quieter than the orange so the two
   are not mistaken for each other at a glance. */
.tag--design { border-color: var(--tint-lilac); color: var(--tint-lilac); }

/* ============================================================
   OUR WORK — previews
   The screenshot was running the full width of the card, which made each
   entry read as a picture with some notes under it. The point of the page is
   what the build was and what it cost, so the preview is now a fixed-width
   thumbnail sitting beside the text and the words carry the card.
   ============================================================ */
.pfitem__clip { width: 100%; height: 100%; object-fit: cover; display: block; }

@media (min-width: 760px) {
  /* Once the card becomes a horizontal row, the list has to be ONE column.
     Leaving .pfgrid at 2/3 columns squeezed the text column to nothing and
     .pfitem's overflow:hidden then clipped the description on the right. */
  .pfgrid { grid-template-columns: 1fr; gap: 0; }
  .pfitem {
    display: grid;
    grid-template-columns: minmax(0, 300px) minmax(0, 1fr);
    gap: clamp(1.4rem, 3vw, 2.4rem);
    align-items: start;
    padding: clamp(1.2rem, 2.4vw, 1.8rem);
    border-bottom: 1px solid var(--line);
  }
  .pfitem__shot {
    border: 1px solid var(--line); border-bottom: 1px solid var(--line);
    align-self: start;
  }
  .pfitem__meta { padding: 0; min-width: 0; }
  .pfitem__note, .pfitem__head h2 { overflow-wrap: anywhere; }
}
@media (prefers-reduced-motion: reduce) {
  .pfitem__clip { display: none; }
}

/* outline at one weight, so it stays legible at band size where a solid mark
   turns into a blob */
.plogo__sciss {
  fill: none; stroke: var(--white); stroke-width: 2.7;
  stroke-linecap: round; stroke-linejoin: round;
}

/* an unfilled legal detail must look unfinished, not like a design choice */
.todo { color: var(--orange); font-style: normal; border-bottom: 1px dotted var(--orange); }

/* ============================================================
   TAP TARGETS — WCAG 2.2 AA (2.5.8 Target Size, Minimum)
   The footer link lists rendered at 18px tall, under the 24px minimum. These
   are list links rather than links inside a sentence, so the "inline"
   exception does not cover them. Padding lifts the hit area past 24px without
   moving the type. Under the Equality Act this is a duty, not polish.
   ============================================================ */
.footer nav ul a,
.footer ul a {
  display: inline-block;
  padding-block: .28rem;
  min-height: 24px;
}

/* the published trading address — the E-Commerce Regs disclosure, and the
   "A" in the name/address/phone triplet local search matches on */
.nap {
  font-style: normal; margin-top: 1.4rem;
  font-family: var(--mono); font-size: .8125rem; line-height: 1.9;
  letter-spacing: .04em; color: var(--dim);
}
.nap strong { color: var(--mid); font-weight: 400; }

/* ============================================================
   INLINE-STYLE UTILITIES
   These were style="" attributes. A CSP of style-src 'self' blocks inline
   style attributes, so on production every one of them was silently dropped
   and the spacing collapsed — visible only after deploy. Promoting them to
   classes keeps the strict policy instead of loosening it to unsafe-inline.
   ============================================================ */
.u-margin-block-1-35rem-872d { margin-block:1.35rem; }
.u-margin-bottom-1-25rem-d403 { margin-bottom:1.25rem; }
.u-margin-top-9rem-padding-top-0-bord-d1a3 { margin-top:.9rem;padding-top:0;border:0; }
.u-margin-top-1-1rem-max-width-30ch-f-0958 { margin-top:1.1rem;max-width:30ch;font-size:.9375rem; }
.u-margin-top-1-25rem-1f36 { margin-top:1.25rem; }
.u-margin-top-1-4rem-5a77 { margin-top:1.4rem; }
.u-margin-top-1-5rem-font-size-875rem-fa26 { margin-top:1.5rem;font-size:.875rem; }
.u-margin-top-1-5rem-font-size-9375re-70f6 { margin-top:1.5rem;font-size:.9375rem;max-width:56ch; }
.u-margin-top-1-75rem-max-width-38ch-b3b8 { margin-top:1.75rem;max-width:38ch; }
.u-margin-top-1rem-9dae { margin-top:1rem; }
.u-margin-top-1rem-max-width-40ch-fon-5060 { margin-top:1rem;max-width:40ch;font-size:.9375rem; }
.u-margin-top-1rem-text-transform-non-4d3b { margin-top:1rem;text-transform:none;letter-spacing:0;font-size:.875rem; }
.u-margin-top-2-5rem-0a6e { margin-top:2.5rem; }
.u-margin-top-2rem-831a { margin-top:2rem; }
.u-margin-top-2rem-font-size-9375rem-66d1 { margin-top:2rem;font-size:.9375rem; }
.u-margin-top-clamp-2-5rem-5vw-3-5rem-e70a { margin-top:clamp(2.5rem,5vw,3.5rem); }
.u-margin-top-clamp-2-5rem-5vw-4rem-6eb0 { margin-top:clamp(2.5rem,5vw,4rem); }
.u-margin-top-clamp-2rem-4vw-3rem-6fb8 { margin-top:clamp(2rem,4vw,3rem); }
.u-max-width-26rem-42af { max-width:26rem; }
.u-max-width-56rem-2d75 { max-width:56rem; }
.u-min-height-74svh-display-grid-alig-41a4 { min-height:74svh;display:grid;align-content:center; }
.u-text-transform-none-letter-spacing-6fb1 { text-transform:none;letter-spacing:0; }

/* Netlify's honeypot. Off-screen rather than display:none so a bot that checks
   for visibility still fills it in; aria-hidden + tabindex keep it away from
   anyone real. */
.u-hp { position: absolute !important; left: -9999px !important; width: 1px; height: 1px; overflow: hidden; }


/* ============================================================
   TFM wordmark — angular italic lockup, chevron in the M
   ============================================================ */
.tfm { width: 100%; height: auto; overflow: visible; }
.tfm__l path { fill: url(#tfmChrome); }
.tfm__v { fill: url(#tfmFlame); }
.tfm__sweepbar { fill: url(#tfmSweep); mix-blend-mode: screen; opacity: 0; }

/* nav mark */
.logo .mark { display: block; width: clamp(5.4rem, 7.6vw, 7rem); }
.logo .tfm__v { transition: transform .45s var(--ease); transform-box: fill-box; transform-origin: 50% 0%; }
.logo:hover .tfm__v { transform: translateY(4%) scaleY(1.08); }
.logo:hover .tfm__sweepbar { animation: sheen 1.15s cubic-bezier(.4,.1,.3,1) 1; }

/* boot mark — letters stagger in, chevron drops, sheen crosses */
.mark--boot { width: 100%; }
.mark--boot .tfm { width: 100%; }
.mark--boot .tfm__l { animation: letter-in .58s cubic-bezier(.2,.85,.25,1) both; }
.mark--boot .tfm__l--t { animation-delay: .10s; }
.mark--boot .tfm__l--f { animation-delay: .20s; }
.mark--boot .tfm__l--m { animation-delay: .30s; }
.mark--boot .tfm__v {
  animation: chev-drop .62s cubic-bezier(.2,.85,.25,1) .42s both;
  transform-box: fill-box; transform-origin: 50% 0%;
  filter: drop-shadow(0 0 10px rgba(255,107,53,.55));
  will-change: transform, opacity;
}
.mark--boot .tfm__sweepbar {
  animation: sheen 1.15s cubic-bezier(.4,.1,.3,1) .55s 1;
  will-change: transform, opacity;
}
@keyframes chev-drop {
  0%   { opacity: 0; transform: translateY(-24%) scaleY(.6); }
  100% { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .mark--boot .tfm__l,
  .mark--boot .tfm__v { animation: none; opacity: 1; transform: none; }
  .mark--boot .tfm__sweepbar { animation: none; opacity: 0; }
  .logo .tfm__v { transition: none; }
}

/* ============================================================
   THE TFM MARK
   One component for the nav, the footer and the loading screen.

   The flame is five ribbons cut from the supplied artwork along
   curves that follow its own sweep. The cuts are hard and tile
   exactly, so with every ribbon at rest the flame is bit-identical
   to the source file — verified pixel-for-pixel. The split exists
   only so the streams can fly in independently and converge.

   Every animated property is transform, opacity or filter, so the
   whole thing composites on the GPU and never triggers layout.
   ============================================================ */
.tfmlogo {
  display: inline-block;
  line-height: 0;
  text-decoration: none;
  -webkit-tap-highlight-color: transparent;
}
.tfmlogo__stack {
  position: relative;
  display: block;
  width: 100%;
  aspect-ratio: 840 / 457;          /* reserves the box — no layout shift */
}
.tfmlogo__letters,
.tfmlogo__flame,
.tfmlogo__ribbon {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}
.tfmlogo__letters,
.tfmlogo__ribbon { object-fit: contain; }
.tfmlogo__flame { display: block; }

/* ---------- sizes: a touch smaller than before, still responsive ---------- */
.tfmlogo--nav    { width: clamp(74px, 7.4vw, 92px); }
.tfmlogo--footer { width: clamp(88px, 9vw, 108px); }
/* The mark fills the boot stage rather than carrying its own width. It was
   272px inside a 232px stage, which overflowed and pushed it 20px right of
   centre — the one place the brief asks for it to be dead centre. Sharing the
   stage's width also lines the mark up with the progress hairline beneath it. */
.tfmlogo--boot   { width: 100%; justify-self: center; }
.tfmlogo--small  { width: 66px; }

/* ---------- position: anchored left ----------
   The nav sat inside the 78rem content wrap while the hero's ticker is
   full-bleed on var(--gut), so at 1920px the mark landed 322px right of
   "THE FLAME MAKERS · UK" beneath it. Dropping the max-width puts both on
   the same gutter, so the mark sits directly above that line at every width.

   Measured: the artwork has zero transparent padding on its left edge — the
   T meets the box — so no optical compensation is needed. Sharing the gutter
   is enough for the mark and the text to line up exactly. */
.nav .wrap.nav__inner { max-width: none; }

/* ============================================================
   FLOW — the shared motion language
   Each ribbon arrives from its own direction along its own curve,
   at its own speed, and they converge. Three-stage keyframes give
   the path its bend; nothing travels in a straight line.
   ============================================================ */
@keyframes tfm-flow-0 {   /* lower-left tail: in from the left, riding up */
  0%   { opacity: 0; transform: translate(-46%, 26%) rotate(-13deg) scale(.72); }
  45%  { opacity: 1; transform: translate(-14%, 9%) rotate(-5deg) scale(.9); }
  75%  { transform: translate(3%, -2%) rotate(1.4deg) scale(1.02); }
  100% { opacity: 1; transform: none; }
}
@keyframes tfm-flow-1 {   /* mid stream: up from below, curving right */
  0%   { opacity: 0; transform: translate(-24%, 40%) rotate(9deg) scale(.76); }
  45%  { opacity: 1; transform: translate(-7%, 13%) rotate(3.5deg) scale(.93); }
  75%  { transform: translate(2.5%, -3%) rotate(-1.2deg) scale(1.025); }
  100% { opacity: 1; transform: none; }
}
@keyframes tfm-flow-2 {   /* the long sweep: in high from the right, folding down */
  0%   { opacity: 0; transform: translate(38%, -30%) rotate(11deg) scale(.74); }
  45%  { opacity: 1; transform: translate(12%, -10%) rotate(4deg) scale(.92); }
  75%  { transform: translate(-3%, 2.5%) rotate(-1.5deg) scale(1.028); }
  100% { opacity: 1; transform: none; }
}
@keyframes tfm-flow-3 {   /* lower mid: rising, curling over */
  0%   { opacity: 0; transform: translate(-10%, 46%) rotate(-8deg) scale(.78); }
  45%  { opacity: 1; transform: translate(-3%, 15%) rotate(-3deg) scale(.94); }
  75%  { transform: translate(1.5%, -3.5%) rotate(1deg) scale(1.022); }
  100% { opacity: 1; transform: none; }
}
@keyframes tfm-flow-4 {   /* lower right: in from the side, settling under */
  0%   { opacity: 0; transform: translate(34%, 22%) rotate(-10deg) scale(.75); }
  45%  { opacity: 1; transform: translate(11%, 7%) rotate(-4deg) scale(.93); }
  75%  { transform: translate(-2.5%, -2%) rotate(1.3deg) scale(1.024); }
  100% { opacity: 1; transform: none; }
}
@keyframes tfm-letters-in {
  0%   { opacity: 0; transform: translateY(-5%) scale(.978); filter: blur(3px); }
  60%  { filter: blur(0); }
  100% { opacity: 1; transform: none; filter: blur(0); }
}
/* the settle: a single small exhale, then completely still */
@keyframes tfm-settle {
  0%   { transform: scale(1.012); }
  100% { transform: none; }
}

/* ---------- loading screen ---------- */
.tfmlogo--boot .tfmlogo__ribbon,
.tfmlogo--boot .tfmlogo__letters { will-change: transform, opacity; }

/* an easing with a long, soft tail — the last 20% barely moves, so nothing snaps */
.tfmlogo--boot.is-animated .tfmlogo__ribbon { animation-fill-mode: both; }
.tfmlogo--boot.is-animated .tfmlogo__ribbon--0 { animation: tfm-flow-0 .80s cubic-bezier(.16,.78,.22,1) .30s both; }
.tfmlogo--boot.is-animated .tfmlogo__ribbon--1 { animation: tfm-flow-1 .84s cubic-bezier(.16,.78,.22,1) .22s both; }
.tfmlogo--boot.is-animated .tfmlogo__ribbon--2 { animation: tfm-flow-2 .88s cubic-bezier(.16,.78,.22,1) .14s both; }
.tfmlogo--boot.is-animated .tfmlogo__ribbon--3 { animation: tfm-flow-3 .82s cubic-bezier(.16,.78,.22,1) .26s both; }
.tfmlogo--boot.is-animated .tfmlogo__ribbon--4 { animation: tfm-flow-4 .86s cubic-bezier(.16,.78,.22,1) .18s both; }
.tfmlogo--boot.is-animated .tfmlogo__letters {
  animation: tfm-letters-in .66s cubic-bezier(.2,.85,.25,1) .34s both;
}
.tfmlogo--boot.is-animated .tfmlogo__stack {
  animation: tfm-settle .42s cubic-bezier(.33,0,.2,1) 1.06s both;
}

/* ============================================================
   HOVER / FOCUS — the same language, roughly a third of the length
   The ribbons break formation a little, swirl, and reform.
   Pointer-only, so a tap never leaves it stuck mid-flow.
   ============================================================ */
@media (hover: hover) and (pointer: fine) {
  .tfmlogo[href] .tfmlogo__stack { transition: transform .38s cubic-bezier(.22,.85,.3,1); }
  .tfmlogo[href]:hover .tfmlogo__stack,
  .tfmlogo[href]:focus-visible .tfmlogo__stack { transform: translateY(-1px) scale(1.015); }

  .tfmlogo[href] .tfmlogo__ribbon {
    transition: transform .40s cubic-bezier(.22,.85,.3,1), filter .40s ease;
  }
  /* each ribbon drifts a different way, then eases home — a brief breath of
     the loading animation rather than a separate effect */
  .tfmlogo[href]:hover .tfmlogo__ribbon--0 { transform: translate(-2.4%, 1.6%) rotate(-2deg) scale(1.03); }
  .tfmlogo[href]:hover .tfmlogo__ribbon--1 { transform: translate(-1.2%, 2.2%) rotate(1.6deg) scale(1.035); }
  .tfmlogo[href]:hover .tfmlogo__ribbon--2 { transform: translate(2.2%, -1.8%) rotate(1.8deg) scale(1.04); }
  .tfmlogo[href]:hover .tfmlogo__ribbon--3 { transform: translate(-0.8%, 2.4%) rotate(-1.4deg) scale(1.03); }
  .tfmlogo[href]:hover .tfmlogo__ribbon--4 { transform: translate(1.8%, 1.4%) rotate(-1.7deg) scale(1.035); }
  .tfmlogo[href]:hover .tfmlogo__ribbon { filter: saturate(1.1) brightness(1.04); }
}
.tfmlogo[href]:focus-visible {
  outline: 2px solid var(--orange);
  outline-offset: 6px;
  border-radius: 4px;
}
/* touch: one quiet press, no lingering state */
.tfmlogo[href]:active .tfmlogo__stack { transform: scale(.988); transition: transform .12s ease; }

@media (prefers-reduced-motion: reduce) {
  .tfmlogo--boot.is-animated .tfmlogo__ribbon,
  .tfmlogo--boot.is-animated .tfmlogo__letters,
  .tfmlogo--boot.is-animated .tfmlogo__stack {
    animation: none; opacity: 1; transform: none; filter: none;
  }
  .tfmlogo[href] .tfmlogo__stack,
  .tfmlogo[href] .tfmlogo__ribbon { transition: opacity .2s linear; }
  .tfmlogo[href]:hover .tfmlogo__stack,
  .tfmlogo[href]:hover .tfmlogo__ribbon,
  .tfmlogo[href]:focus-visible .tfmlogo__stack { transform: none; filter: none; }
}

/* a little more room for the mark on the loading screen, still centred by
   .boot's place-items — this is the only context where it is centred */
.boot .boot__stage { width: min(58vw, 18rem); }

/* A client logo supplied as artwork rather than drawn as SVG. Zee Visuals'
   signature is a neon raster on their own site, so it is used as-is — their
   red is the identity and is not filtered or recoloured. */
.plogo--art {
  display: block;
  width: auto;
  /* was height:100% — with no sized parent that resolves to auto, so the image
     fell back to its intrinsic width (440px) and blew out the band on a phone,
     and reserved the wrong space while it was still downloading. Matching the
     base .plogo clamp keeps it the same size as its inline-SVG siblings and
     holds the correct box before the file arrives. */
  height: clamp(2.4rem, 4vw, 3.1rem);
  max-height: 62px;
  object-fit: contain;
}

/* The nav group sits hard right: the mark takes the free space, so the links
   and the quote button always finish on the gutter rather than drifting
   towards the middle at wider viewports. */
.nav__inner > .nav__links { margin-left: auto; }

/* ---------- pricing: add-ons table ---------- */
.extras { width: 100%; border-collapse: collapse; margin-top: clamp(1.5rem, 3vw, 2.25rem); }
.extras th, .extras td {
  text-align: left; padding: .95rem 1rem;
  border-bottom: 1px solid var(--on-rule); vertical-align: top;
}
.extras thead th {
  font-family: var(--mono); font-size: .625rem; letter-spacing: .2em;
  text-transform: uppercase; color: var(--on-muted); font-weight: 400;
  border-bottom-color: var(--line-2);
}
.extras tbody th { font-weight: 500; color: var(--cream); width: 34%; }
.extras tbody td { color: var(--on-muted); font-size: .9375rem; }
.extras__price {
  font-family: var(--mono); color: var(--cream); white-space: nowrap;
  text-align: right !important; width: 1%;
}
.extras tbody tr:last-child th, .extras tbody tr:last-child td { border-bottom: 0; }
/* on a phone the three columns stop being a table and stack per row */
@media (max-width: 46rem) {
  .extras thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
  .extras tr { display: grid; grid-template-columns: 1fr auto; gap: .15rem .9rem;
               padding: .95rem 0; border-bottom: 1px solid var(--on-rule); }
  .extras th, .extras td { border: 0; padding: 0; }
  .extras tbody th { width: auto; }
  .extras tbody td:first-of-type { grid-column: 1 / -1; }
  .extras__price { text-align: right !important; }
}

/* ---------- pricing: the Kickstarter package ---------- */
.kick {
  display: grid; gap: clamp(1.75rem, 4vw, 3rem);
  border: 1px solid var(--on-rule); border-radius: 4px;
  padding: clamp(1.5rem, 4vw, 2.75rem);
  background-image: linear-gradient(168deg,
    color-mix(in srgb, var(--ground) 92%, var(--soft)) 0%, var(--ground) 100%);
}
@media (min-width: 56rem) { .kick { grid-template-columns: minmax(0, 24rem) minmax(0, 1fr); align-items: start; } }
.kick__fig { display: flex; align-items: baseline; gap: .8rem; margin: 1.25rem 0 1.5rem; flex-wrap: wrap; }
.kick__num { font-family: var(--serif); font-size: clamp(2.4rem, 6vw, 3.4rem); color: var(--cream); line-height: 1; }
.kick__meta { font-family: var(--mono); font-size: .6875rem; letter-spacing: .18em;
              text-transform: uppercase; color: var(--on-muted); }
.kick__list { list-style: none; margin: 0; padding: 0; display: grid; gap: 1.15rem; counter-reset: kick; }
.kick__list li {
  display: grid; gap: .3rem; padding-left: 2.4rem; position: relative;
  counter-increment: kick;
}
.kick__list li::before {
  content: counter(kick, decimal-leading-zero);
  position: absolute; left: 0; top: .1rem;
  font-family: var(--mono); font-size: .6875rem; letter-spacing: .1em; color: var(--orange);
}
.kick__list strong { font-weight: 500; color: var(--cream); }
.kick__list span { color: var(--on-muted); font-size: .9375rem; }

/* ---------- service loops: still-first ----------
   The photograph is the content; the loop is decoration layered over it once
   it is actually running. If autoplay is refused (iOS Low Power Mode) or the
   file never arrives (poor connection), the video stays transparent and the
   visitor simply sees the picture — there is no play button to press, because
   the <video> is never what they are looking at. */
.svcmedia { position: relative; aspect-ratio: 3 / 2; overflow: hidden;
            background: var(--panel); border: 1px solid var(--line); }
.svcmedia__still,
.svcmedia .svcloop {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; display: block;
}
.svcmedia .svcloop {
  opacity: 0; border: 0; background: none;
  transition: opacity .6s var(--ease);
}
.svcmedia.is-playing .svcloop { opacity: 1; }
@media (prefers-reduced-motion: reduce) {
  .svcmedia .svcloop { display: none; }      /* the photograph only */
}

/* Mirror the hero: a CTA clip that is waiting on permission is transparent, so
   the still underneath is what the visitor sees rather than a paused video. */
.cta__media[data-video="waiting"] .cta__clip { opacity: 0; }

/* ---------- hero: pause control ----------
   WCAG 2.2.2 (Pause, Stop, Hide): the hero montage starts on its own and runs
   past five seconds alongside the copy, so it needs a control. Sits low-right
   of the hero, quiet until hovered or focused. */
.heroctl {
  /* Lives inside .hero__foot, which is a space-between flex row. That keeps it
     on the same band as the service list on wide screens — where it always
     sat — and lets it WRAP onto its own line on a phone instead of being
     pinned over the list. Absolutely positioning it here used to drop the
     button straight on top of the wrapped service rows at 375px, which read
     as the last item being cut off. */
  position: relative; z-index: 4;
  margin-left: auto; flex: none; align-self: center;
  display: inline-flex; align-items: center; gap: .55rem;
  padding: .5rem .8rem;
  font-family: var(--mono); font-size: .625rem; letter-spacing: .16em;
  text-transform: uppercase; color: var(--mid);
  background: rgba(10, 10, 10, .55);
  border: 1px solid rgba(250, 250, 250, .16); border-radius: 2px;
  cursor: pointer;
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
  transition: color .3s var(--ease), border-color .3s var(--ease), background-color .3s var(--ease);
}
.heroctl:hover, .heroctl:focus-visible { color: var(--white); border-color: rgba(250,250,250,.4); background: rgba(10,10,10,.75); }
.heroctl:focus-visible { outline: 2px solid var(--orange); outline-offset: 3px; }
.heroctl__icon {
  width: 8px; height: 9px; flex: none;
  border-left: 3px solid currentColor; border-right: 3px solid currentColor;
}
/* becomes a play triangle once paused */
.heroctl[aria-pressed="true"] .heroctl__icon {
  border: 0; width: 0; height: 0;
  border-top: 5px solid transparent; border-bottom: 5px solid transparent;
  border-left: 8px solid currentColor;
}
@media (max-width: 46rem) { .heroctl__txt { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); } }
/* no motion to pause when the visitor has asked for none */
@media (prefers-reduced-motion: reduce) { .heroctl { display: none; } }

/* ---------- Zee's mark: never a gap in the band ----------
   The other three partner logos are inline SVG and need no network. This one
   is a raster file, so on a slow connection it can still be downloading while
   the band scrolls past. The name sits behind it as type and is covered once
   the image decodes — so the band is complete either way. */
.plogo--zee {
  position: relative; display: inline-flex; align-items: center;
  justify-content: center;
  height: clamp(2.4rem, 4vw, 3.1rem);
  /* The artwork is out of flow, so the wrapper used to take its width from the
     fallback TEXT. A global max-width:100% on images then squashed the mark to
     the text's width and object-fit letterboxed it, so Zee's logo rendered
     ~41px tall next to 50px siblings. Reserving the file's own 300x122 ratio
     fixes the height AND holds the correct slot in the band while the image is
     still on the wire, so nothing shifts when it lands. */
  width: calc(clamp(2.4rem, 4vw, 3.1rem) * 300 / 122);
  max-width: calc(62px * 300 / 122);
}
.plogo--zee__fallback {
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  font-family: var(--sans); font-weight: 700;
  font-size: clamp(.8rem, 1.35vw, 1.05rem);
  letter-spacing: -.01em; color: #FF2D2D; white-space: nowrap;
  transition: opacity .3s var(--ease);
}
.plogo--zee .plogo--art {
  position: absolute; inset: 0; transform: none;
  width: 100%; height: 100%; max-height: none;
  opacity: 0; transition: opacity .35s var(--ease);
}
.plogo--zee.is-loaded .plogo--art { opacity: 1; }
.plogo--zee.is-loaded .plogo--zee__fallback { opacity: 0; }

/* ============================================================
   GLASS
   Measured against the montage: a light glass composites to
   #CEA7A8 over the brightest frame and white text lands at
   1.24:1 — unreadable. Dark glass over the same frame holds
   7.31:1 on white, so that is what this uses. Any text sitting
   on glass that overlays video must be --white; --mid drops to
   3.32:1 and --dim to 2.17:1 at the worst point.
   ============================================================ */
.nav {
  background: var(--glass-bg);
  -webkit-backdrop-filter: blur(20px) saturate(115%);
  backdrop-filter: blur(20px) saturate(115%);
  border-bottom: 1px solid var(--glass-border);
  box-shadow: var(--glass-inner);
}
/* once it leaves the hero the backdrop is the page, not footage, so it can
   sit a little denser and read as a solid bar */
.nav.is-solid {
  background: var(--glass-strong);
  -webkit-backdrop-filter: blur(24px) saturate(120%);
  backdrop-filter: blur(24px) saturate(120%);
  box-shadow: var(--glass-inner), var(--glass-shadow);
}
/* white only, per the measurement above */
.nav .nav__links a { color: var(--white); }
.nav .nav__links a:hover { color: var(--fill-lift); }

/* ---------- glass buttons ---------- */
.btn--glass {
  background: var(--glass-bg);
  -webkit-backdrop-filter: blur(16px) saturate(115%);
  backdrop-filter: blur(16px) saturate(115%);
  border: 1px solid var(--glass-border);
  color: var(--white);
  box-shadow: var(--glass-inner);
  transition: background-color .3s var(--ease), border-color .3s var(--ease),
              transform .3s var(--ease);
}
.btn--glass:hover, .btn--glass:focus-visible {
  background: var(--glass-strong);
  border-color: rgba(247, 145, 118, .42);
  transform: translateY(-1px);
}
/* The primary fill is --accent-deep, not the measured vermilion: #D03E12
   carries a white label at only 4.25:1 and a dark one at 4.19:1 — there is no
   label colour that clears 4.5 on it. #82130A with white is 9.10:1. */
/* Higher specificity than the earlier .btn--solid rules, which were still
   resolving to the coral. Measured: white on coral is 3.05:1 and a dark label
   on it is 4.19:1 — no label colour clears 4.5 on that fill. #82130A takes
   white at 9.10:1. */
.btn.btn--solid, .btn.btn--molten {
  background: var(--fill-deep); color: var(--white); border-color: transparent;
}
.btn.btn--solid:hover, .btn.btn--molten:hover { background: #93170C; }
.btn.btn--solid span, .btn.btn--molten span { color: var(--white); }
/* the nav action takes the bright specular with a dark label — 8.86:1 */
.btn.btn--onink.btn--nav { background: var(--fill-lift); color: var(--void); }
.btn.btn--onink.btn--nav span { color: var(--void); }
.btn.btn--onink.btn--nav:hover { background: #FFA98F; }

/* ---------- hero framing ----------
   The new footage puts its brightest element (the lit device screen) near the
   centre, which is exactly where the headline sits. Shifting the frame right
   keeps the copy over the dark studio falloff instead of over the screen —
   legibility from composition rather than from a scrim, since a panel behind
   the text is what we deliberately removed. */
/* WHICH part of the frame survives the crop.
   A 16:9 clip in a 100svh hero loses width on any portrait viewport: at
   390x844 the cover scale is 1.17, the full height survives and only 26% of
   the frame's WIDTH is visible. Geometry, not a bug — but it makes the choice
   of centre the whole ballgame on a phone.
   These percentages were tuned for the previous footage, whose subject sat on
   the right, and were never revisited when the montage was replaced. On the
   current clip 86% is the empty black backdrop past the right-hand panel,
   which is why the mobile hero rendered as a flat black rectangle while
   desktop looked fine — on a viewport wider than 16:9 the crop is VERTICAL,
   so the X value did nothing there and the fault stayed hidden.
   The laptop screen sits at 29%-56% of the frame. Centring on 43% puts the lit
   screen in the middle of the mobile crop window (30%-56%) instead. */
.hero__clip, .hero__still { object-position: 50% center; }
@media (max-width: 62rem) { .hero__clip, .hero__still { object-position: 46% center; } }
@media (max-width: 40rem) { .hero__clip, .hero__still { object-position: 43% center; } }

/* ============================================================
   SERVICES — re-laid out
   Was six 3:2 image panels stacked 3x2. The photographs are all
   low-key, so at that size they read as empty rectangles and the
   section ran to ~1470px with the names pushed to the bottom of
   each cell. This turns each card on its side: a compact square
   thumbnail leads, the name and blurb sit beside it, and the row
   is a glass panel. Half the height, and the words come first.
   ============================================================ */
@media (min-width: 46rem) {
  .svcgrid {
    grid-template-columns: repeat(2, minmax(0, 1fr)) !important;
    gap: clamp(.75rem, 1.4vw, 1rem) !important;
    background: none !important;
    border: 0 !important;
  }
}
@media (max-width: 45.99rem) {
  .svcgrid {
    grid-template-columns: 1fr !important;
    gap: .7rem !important;
    background: none !important;
    border: 0 !important;
  }
}
.svcgrid .svc {
  display: grid;
  grid-template-columns: clamp(88px, 11vw, 124px) minmax(0, 1fr);
  align-items: stretch;
  gap: clamp(1rem, 1.8vw, 1.4rem);
  background: var(--glass-bg);
  -webkit-backdrop-filter: blur(14px) saturate(112%);
  backdrop-filter: blur(14px) saturate(112%);
  border: 1px solid var(--glass-border);
  border-radius: 3px;
  box-shadow: var(--glass-inner);
  padding: clamp(.7rem, 1.2vw, .9rem);
  transition: background-color .4s var(--ease), border-color .4s var(--ease),
              transform .4s var(--ease);
}
.svcgrid .svc:hover {
  background: var(--glass-strong);
  border-color: rgba(247, 145, 118, .4);
  transform: translateY(-2px);
}
.svcgrid .svc__media {
  aspect-ratio: 1 / 1;
  border-radius: 2px;
  align-self: stretch;
  height: 100%;
}
.svcgrid .svc__media img { width: 100%; height: 100%; object-fit: cover; }
.svcgrid .svc__body {
  padding: .25rem .35rem .3rem 0;
  gap: .3rem;
  align-content: center;
}
/* the number becomes a quiet marker beside the name rather than a line of its own */
.svcgrid .svc__n {
  font-family: var(--mono); font-size: .5625rem; letter-spacing: .2em;
  color: var(--vermilion); display: block; margin-bottom: .1rem;
}
.svcgrid .svc__name { font-size: 1rem; letter-spacing: .02em; }
.svcgrid .svc__blurb { color: var(--mid); font-size: .875rem; }
.svcgrid .svc__go { padding-top: .6rem; margin-top: .35rem; }
.svcgrid .svc:hover .svc__go { color: var(--fill-lift); }
@media (prefers-reduced-motion: reduce) {
  .svcgrid .svc, .svcgrid .svc:hover { transition: none; transform: none; }
}

/* Thumbnail exposure. Measured mean luminance of the six service photographs:
   14, 86, 12, 10, 12, 40 out of 255 — four of them are effectively black at
   131px and read as empty boxes. The site's rule is "shown as shot", and that
   still holds for the full-size imagery on the service pages; this lift applies
   only where the picture is a 131px decorative thumbnail carrying no detail. */
.svcgrid .svc__media img {
  filter: brightness(2.5) contrast(1.08) saturate(1.12);
  transition: filter .5s var(--ease), transform 1.1s var(--ease);
}
.svcgrid .svc:hover .svc__media img { filter: brightness(2.9) contrast(1.1) saturate(1.2); }

/* Thumbnails removed from the services grid.
   Measured mean luminance of the six photographs: 14, 86, 12, 10, 12, 40 out
   of 255. Lifting them 2.5x only reached 28, 182, 22, 21, 19, 88 — four of the
   six still read as black squares, and pushing harder yields grey noise rather
   than detail. Six empty boxes is worse than none, so the card is typographic
   and the photographs keep doing their job full-size on the service pages. */
.svcgrid .svc { grid-template-columns: minmax(0, 1fr); }
.svcgrid .svc__media { display: none; }
.svcgrid .svc__body { padding: clamp(.9rem, 1.6vw, 1.2rem); align-content: start; }
.svcgrid .svc__name { font-size: 1.0625rem; }
.svcgrid .svc__blurb { max-width: 46ch; }
/* a hairline in the accent, so each card still carries the brand colour */
.svcgrid .svc { position: relative; overflow: hidden; }
.svcgrid .svc::after {
  content: ''; position: absolute; left: 0; top: 0; bottom: 0; width: 2px;
  background: var(--vermilion); opacity: .55;
  transition: opacity .4s var(--ease), width .4s var(--ease);
}
.svcgrid .svc:hover::after { opacity: 1; width: 3px; }
@media (prefers-reduced-motion: reduce) { .svcgrid .svc::after { transition: none; } }

/* ============================================================
   GLASS, v2 — brighter, rounder, and actually reactive
   The montage reads sunset orange, a little ember purple, black
   and a grey just short of black. These rules let that through
   rather than sitting a flat dark panel on top of it.
   ============================================================ */
:root {
  --r-sm: 10px;
  --r-md: 14px;
  --r-lg: 18px;
  /* the montage's own range, used for glare and for text gradients */
  --sun-hi:  #F79176;   /* specular */
  --sun-mid: #D03E12;   /* lit podium */
  --sun-low: #82130A;   /* falloff */
  --ember:   #AF80BA;   /* the purple hint off the device screens */
}

/* ---------- the banner ----------
   Alpha drops from .72 to .56 — the measured floor for white text over the
   brightest frame of the montage (4.5:1). Everything gained goes to
   saturate(), so the bar genuinely takes its colour from whatever frame is
   behind it: warm over the podium, near-neutral over the studio black. */
.nav {
  background: rgba(28, 16, 14, .56);
  -webkit-backdrop-filter: blur(22px) saturate(180%) brightness(1.08);
  backdrop-filter: blur(22px) saturate(180%) brightness(1.08);
  border-bottom: 1px solid rgba(247, 145, 118, .20);
}
.nav.is-solid {
  background: rgba(20, 12, 10, .70);
  -webkit-backdrop-filter: blur(26px) saturate(150%);
  backdrop-filter: blur(26px) saturate(150%);
}

/* ---------- buttons: outlined glass ---------- */
.btn, .btn.btn--solid, .btn.btn--molten, .btn.btn--ghost,
.btn.btn--onink, .btn.btn--onink.btn--nav {
  border-radius: var(--r-sm);
  background: rgba(247, 240, 236, .06);
  -webkit-backdrop-filter: blur(14px) saturate(160%);
  backdrop-filter: blur(14px) saturate(160%);
  border: 1px solid rgba(247, 240, 236, .28);
  color: var(--white);
  box-shadow: inset 0 1px 0 rgba(247, 240, 236, .12);
  transition: background-color .35s var(--ease), border-color .35s var(--ease),
              box-shadow .35s var(--ease), transform .35s var(--ease);
}
.btn span, .btn.btn--solid span, .btn.btn--molten span,
.btn.btn--onink.btn--nav span { color: var(--white); }
/* the primary keeps a warm tint so there is still a clear first action, but it
   is a tint on glass rather than a solid slab */
.btn.btn--solid, .btn.btn--molten {
  background: rgba(208, 62, 18, .30);
  border-color: rgba(247, 145, 118, .55);
}
.btn:hover, .btn:focus-visible {
  background: rgba(247, 240, 236, .13);
  border-color: rgba(247, 145, 118, .70);
  box-shadow: inset 0 1px 0 rgba(247, 240, 236, .18),
              0 10px 30px -18px rgba(208, 62, 18, .8);
  transform: translateY(-1px);
}
.btn.btn--solid:hover, .btn.btn--molten:hover { background: rgba(208, 62, 18, .44); }
.btn::before { display: none; }   /* the old wipe fill fought the glass */

/* ---------- text that carries the montage's own fade ---------- */
.h-lg em, .h-md em, h1 em, h2 em, .hero__stmt--accent, .tick, .eyebrow {
  background-image: linear-gradient(96deg, var(--sun-hi) 0%, var(--sun-mid) 52%, var(--ember) 100%);
  -webkit-background-clip: text; background-clip: text;
  color: transparent; -webkit-text-fill-color: transparent;
}
/* a gradient cannot be contrast-tested, so anywhere the fade is used the
   darkest stop is still above 4.5:1 on --void: #D03E12 is 4.19, so the mid
   stop is lifted for text use only */
.h-lg em, .h-md em, h1 em, h2 em { --sun-mid: #E3624C; }
@supports not ((-webkit-background-clip: text) or (background-clip: text)) {
  .h-lg em, .h-md em, h1 em, h2 em, .tick, .eyebrow {
    color: var(--orange); -webkit-text-fill-color: var(--orange);
  }
}

/* ============================================================
   SERVICES — glass cards, pictures restored
   The photographs come back (they were pulled when they measured
   10-14/255 and read as black squares). They are lifted and then
   warmed by a golden-hour wash, so the montage's sunset carries
   through the card instead of six dark rectangles.
   ============================================================ */
.svcgrid .svc {
  grid-template-columns: minmax(0, 1fr) !important;
  grid-template-rows: auto auto;
  gap: 0 !important;
  padding: 0 !important;
  border-radius: var(--r-md);
  overflow: hidden;
  background: rgba(247, 240, 236, .045);
  -webkit-backdrop-filter: blur(16px) saturate(150%);
  backdrop-filter: blur(16px) saturate(150%);
  border: 1px solid rgba(247, 240, 236, .16);
  box-shadow: inset 0 1px 0 rgba(247, 240, 236, .10);
  position: relative;
}
/* the golden-hour glare — a low sun striking the top-left of the pane */
.svcgrid .svc::before {
  content: ''; position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background:
    radial-gradient(120% 80% at 8% 0%, rgba(247, 145, 118, .22) 0%, rgba(247, 145, 118, 0) 58%),
    radial-gradient(90% 70% at 100% 100%, rgba(175, 128, 186, .12) 0%, rgba(175, 128, 186, 0) 60%);
  transition: opacity .45s var(--ease);
  opacity: .9;
}
.svcgrid .svc:hover::before { opacity: 1; }
.svcgrid .svc::after {
  left: 0; top: auto; bottom: 0; width: 100%; height: 2px;
  background: linear-gradient(90deg, var(--sun-hi), var(--sun-mid) 55%, transparent);
  opacity: .5;
}
.svcgrid .svc:hover::after { opacity: .95; width: 100%; height: 2px; }

/* the picture is back */
.svcgrid .svc__media {
  display: block !important;
  aspect-ratio: 16 / 9;
  position: relative; z-index: 1;
  border-radius: 0; overflow: hidden;
  border-bottom: 1px solid rgba(247, 240, 236, .12);
}
.svcgrid .svc__media img {
  width: 100%; height: 100%; object-fit: cover;
  /* measured 10-14/255 on four of the six — lifted so there is a picture
     rather than a black panel, then warmed to sit with the montage */
  filter: brightness(2.6) contrast(1.06) saturate(1.25);
  transition: transform 1.1s var(--ease), filter .5s var(--ease);
}
.svcgrid .svc:hover .svc__media img { transform: scale(1.04); filter: brightness(3) contrast(1.08) saturate(1.35); }
/* the sunset laid over the photograph, tying it to the hero */
.svcgrid .svc__media::after {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(168deg,
    rgba(247, 145, 118, .20) 0%,
    rgba(208, 62, 18, .10) 45%,
    rgba(10, 7, 6, .55) 100%);
}
.svcgrid .svc__body {
  position: relative; z-index: 1;
  padding: clamp(1rem, 1.8vw, 1.35rem) !important;
  align-content: start;
}
@media (prefers-reduced-motion: reduce) {
  .svcgrid .svc__media img, .svcgrid .svc:hover .svc__media img { transform: none; transition: none; }
}

/* round the rest of the furniture so nothing is a sharp box */
.tier, .pfitem, .kick, .priceblock, .svcmedia, .extras,
.workcard, .about__media, .svchero__media, .plogo--art { border-radius: var(--r-md); }
.chip, .tag, .form input, .form textarea, .form select { border-radius: var(--r-sm); }
.svcmedia, .svchero__media, .about__media { overflow: hidden; }

/* Back to a compact horizontal card. The 16:9 band pushed the section to
   2066px — taller than the version that had no pictures at all, which defeats
   the point. Picture left, words right: the photograph is visible and the
   section stays short. */
.svcgrid .svc {
  grid-template-columns: clamp(122px, 15vw, 170px) minmax(0, 1fr) !important;
  grid-template-rows: auto;
}
.svcgrid .svc__media {
  aspect-ratio: auto !important;
  height: 100%;
  border-bottom: 0;
  border-right: 1px solid rgba(247, 240, 236, .12);
}
/* lighter wash so the picture reads through it */
.svcgrid .svc__media::after {
  background: linear-gradient(150deg,
    rgba(247, 145, 118, .16) 0%,
    rgba(208, 62, 18, .06) 50%,
    rgba(10, 7, 6, .30) 100%);
}
.svcgrid .svc__body { align-content: center; }
@media (max-width: 30rem) {
  .svcgrid .svc { grid-template-columns: 104px minmax(0, 1fr) !important; }
}

/* The fade is for display type only. On .tick and .eyebrow — 10-11px — a
   gradient sets color:transparent, which makes the contrast unverifiable and
   leaves nothing if background-clip:text ever fails. Small functional text
   goes back to a solid colour that can be measured. */
.tick, .eyebrow {
  background-image: none;
  -webkit-background-clip: border-box; background-clip: border-box;
  color: var(--mid);
  -webkit-text-fill-color: var(--mid);
}
.tick--r, .tick--r * { color: var(--dim); -webkit-text-fill-color: var(--dim); }
.eyebrow { color: var(--orange); -webkit-text-fill-color: var(--orange); }

/* ---------- the display fade, lifted ----------
   The first pass ran #F79176 -> #E3624C -> #AF80BA. Both later stops are
   darker than the solid colour they replaced, so the accent read as lifeless
   over bright footage. These stops keep the sunset-to-ember character but sit
   much higher: measured on --void they are 12.7, 9.0 and 9.4 to 1. */
.h-lg em, .h-md em, h1 em, h2 em, .hero__stmt--accent {
  background-image: linear-gradient(96deg,
    #FFC9A6 0%,
    #FF9A6E 46%,
    #E7A6D2 100%) !important;
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent; color: transparent;
}
@supports not ((-webkit-background-clip: text) or (background-clip: text)) {
  .h-lg em, .h-md em, h1 em, h2 em, .hero__stmt--accent {
    color: #FF9A6E; -webkit-text-fill-color: #FF9A6E;
  }
}

/* ---------- content creation: dim the flash ----------
   That frame has a studio light firing straight at the lens. At the 2.6x lift
   the other five need, its highlight clips. This is the only card that gets
   less, and the step is small enough to read as the same treatment. */
.svcgrid .svc[href*="content-creation"] .svc__media img {
  filter: brightness(1.85) contrast(1.02) saturate(1.15);
}
.svcgrid .svc[href*="content-creation"]:hover .svc__media img {
  filter: brightness(2.0) contrast(1.04) saturate(1.22);
}

/* ---------- the display fade: saturated, not pale ----------
   The previous stops (#FFC9A6 / #FF9A6E / #E7A6D2) were bright but washed —
   raising luminance had drained the colour, so the accent read as translucent
   grey-pink rather than sunset. These are the same hues at full strength:
   brighter than the original AND properly saturated. */
.h-lg em, .h-md em, h1 em, h2 em, .hero__stmt--accent {
  background-image: linear-gradient(94deg,
    #FFA24E 0%,
    #FF6B2C 44%,
    #FF4D6D 74%,
    #C86BE8 100%) !important;
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent; color: transparent;

  /* THE fix for the washed-out look. The heading carries a legibility
     text-shadow (black at 72%) so it survives bright frames of the montage.
     Paint order puts a background BEFORE text-shadow, so on a glyph whose
     fill is transparent that black lands ON TOP of the clipped gradient and
     mutes every stop. Drop it here and rebuild the same legibility with
     drop-shadow(), which filters the composited element and therefore sits
     BEHIND it. Tight dark pass for contrast, warm pass for the bloom. */
  text-shadow: none;
  /* No filter here either. drop-shadow() on an element that is using
     background-clip:text takes the element's background BOX as its input, not
     the glyph alpha, so the "shadow" came out as a visible dark rectangle
     behind the words. The stops measure 6.25:1 to 10.07:1 on --void — well
     past the 3:1 large-text minimum — so nothing is needed to hold them up. */
  filter: none;
}
@supports not ((-webkit-background-clip: text) or (background-clip: text)) {
  .h-lg em, .h-md em, h1 em, h2 em, .hero__stmt--accent {
    color: #FF6B2C; -webkit-text-fill-color: #FF6B2C; filter: none;
  }
}

/* The one piece of hero copy that still failed after the scrim. --dim (#8B817E)
   measured 3.4:1 at its worst point over the footage against the 4.5:1 that
   13px body text needs. --mid takes the same spot to 5.2:1 without touching the
   muted grey used everywhere else on the site, where the ground is flat panel
   colour and --dim is perfectly legible. */
.hero__what { color: var(--mid); }
