/* =========================================================
   AZELUS - Y2K VHS STUDIO SITE
   Black + electric-blue + white. Chakra Petch display,
   VT323 machine text (VHS OSD). Translucent glass buttons
   with sheen. VHS overlay sitewide. Scorpion = signature
   interaction: intro title film, background descent, idle motion.
   ========================================================= */

@font-face{ font-family:'Chakra Petch'; font-weight:400; font-style:normal; font-display:swap; src:url('../fonts/chakra-petch-latin-400-normal.woff2') format('woff2'); }
@font-face{ font-family:'Chakra Petch'; font-weight:500; font-style:normal; font-display:swap; src:url('../fonts/chakra-petch-latin-500-normal.woff2') format('woff2'); }
@font-face{ font-family:'Chakra Petch'; font-weight:600; font-style:normal; font-display:swap; src:url('../fonts/chakra-petch-latin-600-normal.woff2') format('woff2'); }
@font-face{ font-family:'Chakra Petch'; font-weight:700; font-style:normal; font-display:swap; src:url('../fonts/chakra-petch-latin-700-normal.woff2') format('woff2'); }
@font-face{ font-family:'Archivo'; font-weight:400; font-style:normal; font-display:swap; src:url('../fonts/archivo-latin-400-normal.woff2') format('woff2'); }
@font-face{ font-family:'Archivo'; font-weight:500; font-style:normal; font-display:swap; src:url('../fonts/archivo-latin-500-normal.woff2') format('woff2'); }
@font-face{ font-family:'Archivo'; font-weight:600; font-style:normal; font-display:swap; src:url('../fonts/archivo-latin-600-normal.woff2') format('woff2'); }
@font-face{ font-family:'VT323'; font-weight:400; font-style:normal; font-display:swap; src:url('../fonts/vt323-latin-400-normal.woff2') format('woff2'); }

:root{
  --bg: #05070d;
  --bg2: #0a0e18;
  --panel: #0c111d;
  --panel-line: rgba(255,255,255,0.12);
  --ink: #ffffff;
  --ink-dim: #c2d3ee;
  --ink-soft: #e6f0ff;   /* a notch under --ink: OSD text, ledes, marquee */
  --ink-mute: #8fa8cc;   /* quietest step: fine print */
  --ink-faint: #6d7c9f;  /* form placeholders and (optional) markers only */

  --blue: #0047ff;
  --blue-deep: #001c66;
  --blue-bright: #29a3ff;

  /* Only used for form validation. A recording light, not a system alert. */
  --warn: #ff4d4d;

  --blue-grad: linear-gradient(150deg, var(--blue-bright) 0%, var(--blue) 55%, var(--blue-deep) 100%);

  --ease-out: cubic-bezier(0.23, 1, 0.32, 1);
  --ease-in-out: cubic-bezier(0.77, 0, 0.175, 1);
  /* hard arrival, no float: the plane hits its stop and stays there */
  --ease-slam: cubic-bezier(0.16, 1, 0.28, 1);

  --radius: 4px;
  --radius-sm: 3px;
  --maxw: 1280px;
}

*{ box-sizing: border-box; }
html{ scroll-behavior: smooth; }

#site, .page{ padding-top: 74px; position: relative; }
@media (max-width: 720px){ #site, .page{ padding-top: 62px; } }

/* Keeps the background scorpion from poking out ABOVE the marquee, without
   pinning a mask to the viewport. A viewport-fixed mask clipped the mark at the
   same screen line forever, so it could never emerge as you scrolled. This band
   fills the page's top padding instead and scrolls away with it, so the animal
   reveals itself from under the ribbon exactly as the ribbon leaves. It sits
   over the fixed z-index:0 scorpion layer and under the z-index:2 marquee, and
   covers only padding, so it can never occlude content. */
.top-guard{
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 74px;
  z-index: 1;
  background: var(--bg);
  pointer-events: none;
}
@media (max-width: 720px){ .top-guard{ height: 62px; } }

body{
  margin:0;
  background: var(--bg);
  color: var(--ink);
  font-family: 'Archivo', system-ui, sans-serif;
  min-height: 100vh;
  position: relative;
  /* `hidden` here would make body a scroll container and break every
     position:sticky descendant. `clip` contains the overflow without one.
     The hidden fallback is for browsers without clip support. */
  overflow-x: hidden;
  overflow-x: clip;
}

/* ---------- browser surfaces ---------- */
::selection{ background: var(--blue); color: #fff; }
:focus-visible{ outline: 2px solid var(--blue-bright); outline-offset: 3px; }
::-webkit-scrollbar{ width: 10px; height: 10px; }
::-webkit-scrollbar-track{ background: var(--bg); }
::-webkit-scrollbar-thumb{ background: var(--blue-deep); border: 2px solid var(--bg); border-radius: var(--radius); }
::-webkit-scrollbar-thumb:hover{ background: var(--blue); }
html{ scrollbar-color: var(--blue-deep) var(--bg); }

/* =========================================================
   VHS OVERLAY
   Only the OSD furniture and a soft vignette live up here. The tape
   texture itself is applied to background surfaces further down, so it
   never sits on top of copy and cost legibility.
   These layers must stay OUTSIDE any transformed/filtered ancestor:
   a transformed ancestor becomes the containing block for position:fixed
   and the whole overlay would scroll away with the page.
   ========================================================= */
.vhs{
  position: fixed;
  inset: 0;
  z-index: 90;
  pointer-events: none;
}
/* the tape signal only arrives once the title line has finished writing */
body.pre-enter .vhs{ opacity: 0; }
body.pre-enter.tape-on .vhs{
  opacity: 1;
  z-index: 250;
  transition: opacity 780ms var(--ease-out);
}
/* vignette + chroma fringe + the dark safe bands the OSD sits in */
.vhs::after{
  content:"";
  position: absolute; inset: 0;
  background:
    linear-gradient(180deg, #05070d 0, #05070d 38px, rgba(5,7,13,0.45) 52px, transparent 68px),
    linear-gradient(0deg, #05070d 0, rgba(5,7,13,0.72) 34px, rgba(5,7,13,0.36) 62px, transparent 104px),
    radial-gradient(124% 124% at 50% 50%, transparent 66%, rgba(0,0,0,0.4) 100%);
  box-shadow:
    inset 3px 0 7px -3px rgba(255,0,60,0.34),
    inset -3px 0 7px -3px rgba(41,163,255,0.38);
}
/* OSD: canonical VCR corners, fixed to the viewport, in their own safe bands */
.vhs-osd{
  position: absolute;
  z-index: 2;
  font-family: 'VT323', monospace;
  font-size: clamp(1.42rem, 1.9vw, 1.9rem);
  letter-spacing: 0.05em;
  line-height: 1.15;
  color: #ffffff;
  text-shadow:
    2px 0 0 rgba(255,0,60,0.5),
    -2px 0 0 rgba(41,163,255,0.6),
    0 0 14px rgba(255,255,255,0.3);
}
.vhs-osd .tri{ font-size: 0.86em; }
.vhs-osd.tl{ top: 8px; left: 26px; }
.vhs-osd.tr{ top: 8px; right: 26px; text-align: right; }
.vhs-osd.br{ bottom: 10px; right: 26px; text-align: right; }
@media (max-width: 720px){
  .vhs-osd{ font-size: 1.18rem; }
  .vhs-osd.tl{ left: 15px; }
  .vhs-osd.tr{ right: 15px; }
  .vhs-osd.br{ right: 15px; }
}

/* =========================================================
   INTRO / LOADING SCREEN (index only)
   ========================================================= */
#intro{
  position: fixed;
  inset: 0;
  z-index: 200;
  background: #000;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 44px;
  padding-top: 16vh;
  transition: opacity 650ms var(--ease-in-out), transform 650ms var(--ease-in-out), filter 650ms var(--ease-in-out);
}
#intro .intro-stage{
  position: relative;
  z-index: 2;
}
/* the mark coming alive behind the title card */
.intro-film{
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  overflow: hidden;
  /* MUST carry the colour it is sitting on. `position` + `z-index` make this
     element a stacking context, which isolates the child's `mix-blend-mode`
     to this box: screen then has nothing to key against and the clip's black
     frame shows as a visible rectangle. Painting the backdrop here gives the
     blend the right base. Do not remove. */
  background: #000;
}
.intro-film video{
  position: absolute;
  top: 30%; left: 50%;
  transform: translate(-50%, -50%);
  width: min(58vh, 62vw);
  height: auto;
  mix-blend-mode: screen;
  opacity: 0.75;
  filter: contrast(2.4) saturate(0);
  /* returning from the seam: slower and softer than the way out */
  transition: opacity 1500ms var(--ease-out);
}
@media (max-width: 720px){
  .intro-film video{ width: 92vw; top: 27%; opacity: 0.5; }
}
#intro .type-line{
  margin: 0;
  font-family: 'VT323', monospace;
  font-size: clamp(1.5rem, 4.6vw, 3.4rem);
  letter-spacing: 0.08em;
  color: var(--ink-soft);
  white-space: nowrap;
  text-shadow: 2px 0 0 rgba(255,0,60,0.5), -2px 0 0 rgba(41,163,255,0.6);
}
#intro .type-line .caret{
  display: inline-block;
  animation: caret-blink 0.9s steps(1) infinite;
}
@keyframes caret-blink{ 0%,55%{ opacity:1; } 56%,100%{ opacity:0; } }
#intro-enter{
  z-index: 2;
  font-family: 'VT323', monospace;
  font-size: 1.6rem;
  letter-spacing: 0.22em;
  color: var(--ink-soft);
  background: rgba(255,255,255,0.07);
  border: 1px solid rgba(255,255,255,0.4);
  border-radius: var(--radius);
  padding: 14px 46px;
  cursor: pointer;
  opacity: 0;
  transform: translateY(14px);
  transition: opacity 400ms var(--ease-out), transform 400ms var(--ease-out), background 200ms ease, border-color 200ms ease;
  text-shadow: 1.5px 0 0 rgba(255,0,60,0.5), -1.5px 0 0 rgba(41,163,255,0.6);
  position: relative;
  overflow: hidden;
}
#intro-enter.show{ opacity: 1; transform: translateY(0); }
#intro-enter:hover{ background: rgba(41,163,255,0.18); border-color: var(--blue-bright); }
#intro-enter:active{ transform: scale(0.97); }
/* big-bang exit: flash core + overlay blows outward */
#intro.exit{
  opacity: 0;
  transform: scale(2.4);
  filter: blur(14px);
  pointer-events: none;
}
#intro .bang{
  position: absolute;
  left: 50%; top: 50%;
  width: 12px; height: 12px;
  border-radius: 50%;
  background: radial-gradient(circle, #ffffff 0%, rgba(41,163,255,0.9) 40%, rgba(0,71,255,0) 70%);
  transform: translate(-50%,-50%) scale(0);
  pointer-events: none;
}
#intro.exit .bang{
  animation: bang 650ms var(--ease-in-out) forwards;
}
@keyframes bang{
  0%{ transform: translate(-50%,-50%) scale(0); opacity: 1; }
  60%{ opacity: 1; }
  100%{ transform: translate(-50%,-50%) scale(220); opacity: 0; }
}
/* site content blooms in after enter */
body.pre-enter #site{ opacity: 0; }
/* `both` would leave transform/filter applied forever, and a transformed
   ancestor breaks position:fixed for every descendant. JS strips the class
   on animationend; forwards-fill is only held for the run itself. */
#site.bloom{
  animation: bloom 850ms var(--ease-out);
}
@keyframes bloom{
  0%{ opacity: 0; transform: scale(0.965); filter: blur(10px); }
  100%{ opacity: 1; transform: scale(1); filter: blur(0); }
}
@media (prefers-reduced-motion: reduce){
  #intro{ display: none !important; }
  body.pre-enter #site{ opacity: 1; }
  #site.bloom{ animation: none; }
}

/* =========================================================
   SCORPION GAIT
   The mark is a single continuous outline whose limbs interlock: measured
   across the artwork there is exactly one fully-empty row between the left
   limbs, so no straight cut separates them without slicing a stroke. Any
   piecewise rig therefore visibly breaks apart. So the whole animal is
   animated as one intact path instead: a two-beat gait built from a body
   bob, a weight-shift roll, and a small skew that flexes the frame the way
   a walking scorpion's does. Nothing is cut, so nothing can come apart.
   ========================================================= */
.scorp .gait{
  transform-box: view-box;
  transform-origin: 960px 700px;
  animation: gait 2.8s var(--ease-in-out) infinite;
}
/* skewY displaces a point vertically in proportion to its horizontal distance
   from the origin. With the origin on the body axis, the stinger and core sit
   dead still while the left and right limbs rise and fall in opposition: an
   alternating gait, from a single affine transform on one uncut path. */
@keyframes gait{
  0%, 100%{ transform: skewY(0deg); }
  25%{ transform: skewY(0.85deg); }
  50%{ transform: skewY(0deg); }
  75%{ transform: skewY(-0.85deg); }
}

/* ---------- background scorpion: translucent, shimmering, descends on scroll ---------- */
/* outer div carries the scroll descent; inner svg carries the idle drift,
   so the two transforms never fight over one element */
/* Three nested jobs, deliberately kept apart:
   #scorpion-bg  - a fixed, untransformed viewport layer that carries the MASK
   .scorp-descend - the scroll descent (JS writes transform here)
   svg            - the idle drift animation (CSS transform)
   The mask has to live on an element that never moves, or it would travel with
   the descent instead of staying pinned to the top of the screen. It keeps the
   mark out of the OSD safe band and out of the marquee ribbon, where its tail
   was showing above the slider. */
#scorpion-bg{
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  overflow: hidden;
}
.scorp-descend{
  position: absolute;
  top: 0;
  left: 50%;
  transform: translate(-50%, -110vh);
  will-change: transform;
}
#scorpion-bg svg{
  display: block;
  height: 104vh;
  width: auto;
  color: #ffffff;
  /* sits under the vignette, so it needs real presence to read
     while still staying behind the copy */
  opacity: 0.3;
  filter: drop-shadow(0 0 34px rgba(41,163,255,0.5));
  animation: idle-drift 6.4s var(--ease-in-out) infinite;
  transform-origin: 50% 45%;
}
@keyframes idle-drift{
  0%, 100%{ transform: translateY(0); }
  30%{ transform: translateY(-4px); }
  70%{ transform: translateY(3px); }
}
@media (prefers-reduced-motion: reduce){
  #scorpion-bg{ display: none; }
  .scorp .gait{ animation: none; }
}

/* ---------- cursor glow (fine pointers only) ---------- */
/* top/left must be set: a fixed box with auto offsets falls back to its
   static position, which for a body-appended node is the bottom of the page. */
#cursor-glow{
  position: fixed;
  top: 0; left: 0;
  width: 190px; height: 190px;
  margin: -95px 0 0 -95px;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(41,163,255,0.3) 0%, rgba(0,71,255,0.14) 42%, rgba(0,71,255,0) 70%);
  pointer-events: none;
  z-index: 1;
  opacity: 0;
  transition: opacity 260ms ease;
  will-change: transform;
}
@media (hover: hover) and (pointer: fine){
  body:hover #cursor-glow{ opacity: 1; }
}

/* ---------- background scorpion film ----------
   The supplied clip is white-on-black, so `screen` keys the black out
   without needing an alpha channel. It drifts slowly across the page. */
.scorp-film{
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  overflow: hidden;
  /* The background paint that used to be load-bearing for the blend is gone:
     the artwork has real transparency now, so there is nothing to key. */
}
/* An <img>, not a <video>. The animated WebP carries its own alpha channel,
   so there is no black frame to key out and no blend mode involved — which is
   what makes it behave identically on iOS, where video cannot be blended at
   all. `filter` still applies: unlike blending, filters work on any element.
   Keep `pointer-events` off the parent so this never intercepts a click. */
.scorp-film video,
.scorp-film img{
  position: absolute;
  top: 50%; left: 50%;
  width: min(112vh, 96vw);
  height: auto;
  transform: translate3d(-50%, -50%, 0);
  opacity: 0.26;
  filter: contrast(1.15) saturate(0) brightness(1.02);
  animation: film-drift 46s ease-in-out infinite;
  will-change: transform;
  /* Matches the intro: slow, soft return from the loop seam. Asymmetric on
     purpose - easing out is quicker than easing back in, so the cut is hidden
     but the animal does not appear to hesitate before it walks again. */
  transition: opacity 1500ms var(--ease-out);
}

/* Held across the loop join by JS watching the real playhead. The base opacity
   here is 0.26, not 1, so this fades 0.26 -> 0 -> 0.26 and never flashes. */
.scorp-film video.seam{
  opacity: 0;
  transition: opacity 1000ms var(--ease-in-out);
}
@media (prefers-reduced-motion: reduce){
  .scorp-film video,
  .scorp-film img{ animation: none; }
}
/* ---------- the loop seam ----------
   The clip finishes its last movement and then hard-cuts back to frame one.
   JS watches the real playhead and holds `.seam` across that join, so the
   mark eases out on the last beat and eases back in once the loop has
   restarted. The animal is never seen to snap. */
.intro-film video.seam{
  opacity: 0;
  transition: opacity 1000ms var(--ease-in-out);
}
@keyframes film-drift{
  0%   { transform: translate(-58%, -54%) scale(1); }
  25%  { transform: translate(-44%, -47%) scale(1.05); }
  50%  { transform: translate(-52%, -58%) scale(1.02); }
  75%  { transform: translate(-60%, -45%) scale(1.06); }
  100% { transform: translate(-58%, -54%) scale(1); }
}
@media (prefers-reduced-motion: reduce){
  .intro-film video{ animation: none; }
}

/* ---------- tape texture: background surfaces only, never over copy ---------- */
.tape-tex{ position: relative; }
.tape-tex::after{
  content:"";
  position: absolute; inset: 0;
  pointer-events: none;
  z-index: 1;
  background:
    repeating-linear-gradient(0deg, rgba(0,0,0,0.34) 0 1px, transparent 1px 3px),
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='150' height='150'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.5'/%3E%3C/svg%3E");
  background-size: auto, 150px 150px;
  opacity: 0.55;
}
/* media frames keep their label and play control above the texture */
.ph-frame > *{ position: relative; z-index: 2; }

/* ---------- technical grid ground ---------- */
.grid-field{
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background-image:
    repeating-linear-gradient(90deg, rgba(255,255,255,0.045) 0 1px, transparent 1px 120px),
    repeating-linear-gradient(0deg, rgba(255,255,255,0.045) 0 1px, transparent 1px 120px);
  mask-image: linear-gradient(180deg, black, transparent 88%);
}

/* ---------- committed blue plane ---------- */
.blue-plane{
  position: absolute;
  z-index: 0;
  background: var(--blue-grad);
  clip-path: polygon(46% 0, 100% 0, 100% 100%, 24% 100%);
  top: 0; right: 0; width: 54%; height: 100%;
  opacity: 0.9;
  /* Slams out to the right on scroll down, back in on scroll up. A TRANSITION,
     not a keyframe, so a change of scroll direction retargets from wherever the
     plane currently is instead of restarting. transform only, so it stays on
     the compositor. */
  transform: translate3d(0, 0, 0);
  transition: transform 420ms var(--ease-slam);
  will-change: transform;
}
.blue-plane.out{ transform: translate3d(15%, 0, 0); }
@media (prefers-reduced-motion: reduce){
  .blue-plane{ transition: none; }
  .blue-plane.out{ transform: translate3d(0, 0, 0); }
}
.blue-plane::after{
  content:"";
  position:absolute; inset:0;
  background:
    repeating-linear-gradient(0deg, rgba(0,0,0,0.26) 0 1px, transparent 1px 3px),
    repeating-linear-gradient(115deg, rgba(255,255,255,0.09) 0 2px, transparent 2px 34px);
}

/* ---------- typography ---------- */
.display{
  font-family: 'Chakra Petch', system-ui, sans-serif;
  font-weight: 700;
  line-height: 1.04;
  letter-spacing: 0.01em;
  text-transform: uppercase;
  color: var(--ink);
}
.measure{ max-width: 62ch; }
.label{
  font-family: 'Chakra Petch', system-ui, sans-serif;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  font-size: 0.72rem;
  color: var(--ink-dim);
}
/* The three step headings on the enquiry form are <h2> so the document goes
   h1 > h2 > h3 rather than skipping a level, which is what a screen reader
   navigates by. `1em` reproduces a <p>'s default margin exactly at this
   element's own font-size, so promoting the tag changes nothing visually. */
h2.label{ margin: 1em 0; }
.bracket{
  font-family: 'Chakra Petch', sans-serif;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.22em;
  font-size: 0.8rem;
  color: var(--blue-bright);
}
.mono-osd{
  font-family: 'VT323', monospace;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-dim);
}

/* Subtitles: the line under a section title, set like VHS caption text.
   VT323 at caption scale with the tape's chroma bleed, so it reads as part
   of the same signal as the OSD without costing legibility. */
.subtitle{
  font-family: 'VT323', monospace;
  font-size: clamp(1.28rem, 1.85vw, 1.62rem);
  line-height: 1.4;
  letter-spacing: 0.045em;
  color: var(--ink-soft);
  text-shadow:
    1.5px 0 0 rgba(255,0,60,0.34),
    -1.5px 0 0 rgba(41,163,255,0.42);
}
/* The note that sits under a block and comments on it. One treatment for all
   three of them (numbers strip, transformation, final CTA) so they read as a
   pattern rather than three one-offs. */
.section-note{
  margin: 32px auto 0;
  max-width: 60ch;
  text-align: center;
}

/* Lead: longer descriptive copy. Stays in the workhorse face for reading,
   but larger and brighter than before so it holds its own on the tape. */
.lead{
  font-size: 1.12rem;
  line-height: 1.72;
  color: var(--ink-dim);
}
@media (max-width: 720px){
  .lead{ font-size: 1.05rem; }
}

/* ---------- wordmark ---------- */
.wordmark{ display:block; fill: currentColor; }

/* ---------- layout ---------- */
.wrap{ max-width: var(--maxw); margin: 0 auto; padding: 0 32px; position: relative; z-index: 1; }
.section{ padding: 110px 0; position: relative; z-index: 1; }

/* ---------- ticker ---------- */
.marquee{
  position: relative;
  z-index: 2;
  overflow: hidden;
  white-space: nowrap;
  /* Fades up into the page ground at the top so the ribbon has no hard edge
     against the dark band above it, and stays solid at the bottom so it still
     reads as a rule separating itself from the nav. */
  background:
    linear-gradient(180deg,
      var(--bg) 0%,
      rgba(0,28,102,0.55) 34%,
      var(--blue-deep) 62%,
      var(--blue-deep) 100%),
    var(--bg);
  border-bottom: 1px solid rgba(255,255,255,0.15);
  padding: 11px 0 8px;
}
.marquee-track{ display: inline-flex; animation: scroll 52s linear infinite; }
.marquee-track span{
  font-family: 'VT323', monospace;
  font-size: 1.18rem;
  letter-spacing: 0.06em;
  color: var(--ink-soft);
  text-transform: uppercase;
}
/* The rule between items lives on the item, so it travels with it and the
   spacing stays even across the loop join. */
.marquee-track span::after{
  content: "|";
  padding: 0 22px;
  color: rgba(255,255,255,0.34);
}
/* The track carries FOUR copies of the list and travels by half its width, so
   the two halves are identical and the join is seamless. Two copies was not
   enough: on a wide monitor one copy is narrower than the viewport, and the
   tail of the loop showed as a large empty gap. Keep four. */
@keyframes scroll{ 0%{ transform: translateX(0); } 100%{ transform: translateX(-50%); } }
@media (prefers-reduced-motion: reduce){
  .marquee-track{ animation: none; }
}

/* ---------- nav ---------- */
.nav{
  position: relative; z-index: 2;
  display: flex; align-items: center; justify-content: space-between;
  padding: 20px 0;
  min-height: 64px;
}
.logo{
  color: var(--ink);
  text-decoration: none;
  display:flex; align-items:center; gap:11px;
}
.logo .logo-mark{ height: 42px; width: auto; color: var(--ink); }
/* The real wordmark has lighter strokes than the tracing it replaced, so it
   needs a touch more height to hold its own beside the 34px mark. */
.logo .logo-word{ height: 21px; width: auto; fill: var(--ink); }
.nav-links{ display:flex; gap: 10px; align-items:center; }
.nav-links a{
  color: var(--ink-dim);
  text-decoration: none;
  font-family:'Chakra Petch', sans-serif;
  font-weight: 600;
  font-size: 0.74rem;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  padding: 11px 20px;
  border-radius: var(--radius);
  border: 1px solid var(--panel-line);
  transition: border-color 200ms ease, color 200ms ease, background 200ms ease;
  white-space: nowrap;
}
.nav-links a:hover{ color:var(--ink); border-color: var(--blue-bright); }
.nav-links a.cta{
  background: rgba(0,71,255,0.35);
  color:#fff;
  border:1px solid rgba(41,163,255,0.5);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
}
.nav-links a.cta:hover{ background: rgba(0,71,255,0.6); border-color: var(--blue-bright); }
.nav-links a.keep svg{ width:18px; height:18px; display:block; }

/* =========================================================
   BUTTONS: translucent glass, shimmery
   ========================================================= */
.btn{
  display:inline-flex; align-items:center; gap:9px;
  font-family:'Chakra Petch', sans-serif;
  font-weight: 600;
  font-size: 0.8rem;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  padding: 17px 30px;
  border-radius: var(--radius);
  text-decoration:none;
  cursor:pointer;
  transition: transform 160ms var(--ease-out), background 200ms ease, border-color 200ms ease, box-shadow 200ms ease;
  position: relative;
  overflow: hidden;
  white-space: nowrap;
}
.btn:hover{ transform: translateY(-2px); }
.btn:active{ transform: translateY(0) scale(0.97); }
.btn::after{
  content:"";
  position:absolute; top:0; left:-60%; width:40%; height:100%;
  background: linear-gradient(115deg, transparent, rgba(255,255,255,0.5), transparent);
  /* The sweep used to animate `left`, which is a layout property: every frame
     forced the browser to recalculate geometry on the main thread, on every
     button on the page, forever. Lighthouse flagged it as the site's only
     remaining non-composited animation. Same movement, expressed as a
     transform, runs on the compositor for free.

     475% rather than 190%: translateX on a pseudo-element is a percentage of
     its OWN width (40% of the button), so covering 190% of the button needs
     190 / 0.4. */
  transform: translateX(0) skewX(-20deg);
  animation: sheen 4.5s ease-in-out infinite;
  will-change: transform;
}
@media (prefers-reduced-motion: reduce){
  .btn::after{ animation: none; }
}
@keyframes sheen{
  0%, 60%{ transform: translateX(0) skewX(-20deg); }
  100%   { transform: translateX(475%) skewX(-20deg); }
}
/* chrome glass: translucent white, frosted */
.btn-chrome{
  background: linear-gradient(135deg, rgba(255,255,255,0.2), rgba(255,255,255,0.08));
  border: 1px solid rgba(255,255,255,0.4);
  color: #ffffff;
  backdrop-filter: blur(12px) saturate(150%);
  -webkit-backdrop-filter: blur(12px) saturate(150%);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.5), 0 10px 26px rgba(10,20,50,0.35);
}
.btn-chrome:hover{
  background: linear-gradient(135deg, rgba(255,255,255,0.3), rgba(255,255,255,0.14));
  border-color: rgba(255,255,255,0.65);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.6), 0 16px 34px rgba(10,20,50,0.45);
}
/* blue glass */
.btn-blue{
  background: linear-gradient(135deg, rgba(41,163,255,0.4), rgba(0,71,255,0.35));
  border: 1px solid rgba(41,163,255,0.55);
  color: #fff;
  backdrop-filter: blur(12px) saturate(150%);
  -webkit-backdrop-filter: blur(12px) saturate(150%);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.35), 0 10px 28px rgba(0,71,255,0.35);
}
.btn-blue:hover{
  background: linear-gradient(135deg, rgba(41,163,255,0.6), rgba(0,71,255,0.55));
  border-color: var(--blue-bright);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.45), 0 16px 38px rgba(41,163,255,0.45);
}
.btn-ghost{
  background: transparent;
  border: 1.5px solid var(--panel-line);
  color: var(--ink);
}
.btn-ghost::after{ display:none; }
.btn-ghost:hover{ border-color: var(--blue-bright); color: var(--blue-bright); }
.filter-btn.active{ border-color: var(--blue-bright); color: var(--blue-bright); box-shadow: 0 0 0 1px var(--blue-bright) inset; }

/* ---------- pill ---------- */
.pill{
  display:inline-flex; align-items:center; gap:7px;
  font-family:'Chakra Petch', sans-serif;
  font-weight: 600;
  /* 11px floor for functional text. 0.66rem is 10.6px, which fails on small
     viewports and high-DPI screens regardless of how well it fits the ramp. */
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  padding: 8px 15px;
  border-radius: var(--radius);
  border: 1px solid var(--panel-line);
  color: var(--ink-dim);
}

/* ---------- showreel frame ---------- */
.showreel{
  position: relative;
  aspect-ratio: 16/9;
  border: 1px solid var(--panel-line);
  overflow: hidden;
  transition: border-color 250ms ease;
  flex-direction: column;
  gap: 26px;
}
.showreel:hover{ border-color: var(--blue-bright); }
.showreel .play-icon{
  width: 74px; height: 74px;
  transition: transform 200ms var(--ease-out);
}
.showreel:hover .play-icon{ transform: scale(1.08); }

/* ---------- showreel: click to load ----------
   The film is the heaviest thing on the site, so nothing is fetched until
   someone actually asks for it. Until then this is a poster frame and a
   button: no <video> element, no `preload`, no bytes. JS swaps the real
   player in on click. Do not replace this with an autoplaying video. */
.showreel.has-reel{
  display: flex;
  align-items: center;
  justify-content: center;
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
}
.showreel.has-reel::before{
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  background: linear-gradient(180deg, rgba(5,7,13,0.28), rgba(5,7,13,0.66));
  transition: background 300ms var(--ease-out);
}
.showreel.has-reel:hover::before{
  background: linear-gradient(180deg, rgba(5,7,13,0.20), rgba(5,7,13,0.56));
}
.reel-play{
  position: relative;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 18px;
  padding: 0;
  border: 0;
  background: none;
  color: var(--ink);
  font: inherit;
  cursor: pointer;
}
.reel-play:focus-visible{ outline: 2px solid var(--blue-bright); outline-offset: 8px; }
.reel-label{ font-size: 0.95rem; letter-spacing: 0.14em; }
/* the real player, once it exists */
.showreel video{
  position: absolute;
  inset: 0;
  z-index: 3;
  width: 100%;
  height: 100%;
  object-fit: contain;
  background: #000;
}
.showreel.playing::before,
.showreel.playing .crop{ display: none; }

/* ---------- work row ---------- */
.work-row{
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(320px, 420px);
  gap: 22px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  padding-bottom: 18px;
  scrollbar-width: thin;
}
.work-row > *{ scroll-snap-align: start; }
.work-card{
  background: var(--panel);
  border: 1px solid var(--panel-line);
  border-radius: var(--radius);
  overflow: hidden;
  position: relative;
  transition: transform 300ms var(--ease-out), border-color 300ms ease;
}
.work-card:hover{ transform: translateY(-4px); border-color: var(--blue-bright); }
.work-card .meta{
  display:flex; justify-content: space-between; align-items: baseline; gap: 12px;
  padding: 18px 20px 22px;
  border-top: 1px solid var(--panel-line);
}
.work-card .meta h3{
  margin:0;
  font-family:'Chakra Petch', sans-serif; font-weight:700; font-size: 1rem;
  text-transform: uppercase;
  transition: color 200ms ease;
}
.work-card:hover .meta h3{ color: var(--blue-bright); }
.work-card .meta span{
  font-family: 'VT323', monospace;
  color: var(--ink-dim); font-size: 1.15rem; text-transform: uppercase; letter-spacing: 0.05em;
  white-space: nowrap;
}

/* ---------- card (portfolio grid) ---------- */
.card{
  background: var(--panel);
  border: 1px solid var(--panel-line);
  border-radius: var(--radius);
  overflow: hidden;
  position: relative;
  transition: transform 300ms var(--ease-out), border-color 300ms ease;
}
.card:hover{ transform: translateY(-4px); border-color: var(--blue-bright); }
.card-thumb{ position: relative; display:flex; align-items:center; justify-content:center; }
.card-body{ padding: 20px 22px 24px; border-top: 1px solid var(--panel-line); }
.card-body h3{ margin: 0 0 6px; font-family:'Chakra Petch', sans-serif; font-weight:700; font-size: 0.98rem; text-transform: uppercase; transition: color 200ms ease; }
.card:hover .card-body h3{ color: var(--blue-bright); }
.card-body p{ margin:0; color: var(--ink-dim); font-size: 0.96rem; line-height:1.6; }

.play-icon{
  width:50px; height:50px; border-radius:50%;
  background: rgba(255,255,255,0.94);
  display:flex; align-items:center; justify-content:center;
  position: relative; z-index: 2;
  box-shadow: 0 8px 20px rgba(0,0,0,0.4);
}
.play-icon::after{
  content:"";
  border-style: solid;
  border-width: 9px 0 9px 15px;
  border-color: transparent transparent transparent #05070d;
  margin-left: 4px;
}

/* ---------- crop corners ---------- */
.crop{
  position: absolute;
  width: 22px; height: 22px;
  border-color: rgba(255,255,255,0.35);
  z-index: 2;
  pointer-events: none;
}
.crop.tl{ top: 18px; left: 18px; border-top: 1.5px solid; border-left: 1.5px solid; }
.crop.tr{ top: 18px; right: 18px; border-top: 1.5px solid; border-right: 1.5px solid; }
.crop.bl{ bottom: 18px; left: 18px; border-bottom: 1.5px solid; border-left: 1.5px solid; }
.crop.br{ bottom: 18px; right: 18px; border-bottom: 1.5px solid; border-right: 1.5px solid; }

/* ---------- placeholder frame ---------- */
.ph-frame{
  position: relative;
  display: flex; align-items: center; justify-content: center;
  background:
    repeating-linear-gradient(45deg, rgba(255,255,255,0.02) 0 1px, transparent 1px 14px),
    repeating-linear-gradient(90deg, rgba(255,255,255,0.05) 0 1px, transparent 1px 44px),
    repeating-linear-gradient(0deg, rgba(255,255,255,0.05) 0 1px, transparent 1px 44px),
    var(--bg2);
}
.ph-frame .crop{ width:14px; height:14px; border-color: rgba(255,255,255,0.3); }
.ph-frame .crop.tl{ top:10px; left:10px; }
.ph-frame .crop.tr{ top:10px; right:10px; }
.ph-frame .crop.bl{ bottom:10px; left:10px; }
.ph-frame .crop.br{ bottom:10px; right:10px; }
.ph-label{
  font-family:'VT323', monospace;
  font-size: 1.28rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-soft);
  text-align: center;
  border: 1px solid var(--panel-line);
  background: rgba(5,7,13,0.7);
  padding: 7px 14px;
  position: relative; z-index: 2;
}
.ph-frame .play-icon{ position:absolute; z-index:2; bottom:20px; right:20px; width:40px; height:40px; }
.ph-frame .play-icon::after{ border-width:7px 0 7px 11px; margin-left:3px; }

/* ---------- service pillars ---------- */
.pillars{
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 0;
  border-top: 1px solid var(--panel-line);
  border-bottom: 1px solid var(--panel-line);
}
.pillar{
  padding: 44px 34px 48px;
  border-left: 1px solid var(--panel-line);
  transition: background 250ms ease;
}
/* Two columns, now four cells. The left rule has to reset on every row start,
   not just the first cell, and the second row needs a divider above it. */
.pillar:nth-child(2n + 1){ border-left: none; }
.pillar:nth-child(n + 3){ border-top: 1px solid var(--panel-line); }
.pillar:hover{ background: rgba(0,71,255,0.09); }
.pillar h3{
  margin: 0 0 14px;
  font-family:'Chakra Petch', sans-serif; font-weight: 700;
  font-size: 1.15rem; text-transform: uppercase;
  transition: color 200ms ease;
}
.pillar:hover h3{ color: var(--blue-bright); }
.pillar p{ margin:0 0 16px; color: var(--ink-soft); font-size: 1.05rem; line-height: 1.62; }
.pillar ul{ margin: 0; padding: 0; list-style: none; }
.pillar li{
  color: var(--ink-dim); font-size: 0.98rem; line-height: 1.6;
  padding: 7px 0 7px 22px;
  position: relative;
}
.pillar li::before{
  content:"";
  position: absolute; left: 0; top: 14px;
  width: 10px; height: 2px;
  background: var(--blue-bright);
}
.pillar .pillar-mark{ height: 26px; width: auto; fill: var(--blue-bright); margin-bottom: 20px; display:block; }

/* ---------- results data strip ---------- */
/* The hook column. On phones the last line of the hook was landing inside the
   VHS overlay's bottom safe band, so the sector line ran underneath the fixed
   clock. Reserve room for the band rather than shortening the copy. */
.hook-wrap{ padding-bottom: 32px; }

@media (max-width: 720px){
  .hook-wrap{ padding-bottom: 96px; }
}

/* ---------- specialist sectors ---------- */
.spec-row{
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}
.spec-row span{
  /* Grow to fill the row so the set ends flush with the section edge, the same
     line the panels above and below sit on. `flex-basis: auto` keeps the
     relative widths content-led, so TECH does not get the same width as
     INFLUENCER & PERSONAL BRANDS. */
  flex: 1 1 auto;
  text-align: center;
  padding: 12px 18px;
  border: 1px solid var(--panel-line);
  border-radius: var(--radius);
  font-family: 'Chakra Petch', sans-serif;
  font-weight: 600;
  font-size: 0.86rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-soft);
  background: var(--panel);
  transition: border-color 220ms ease, color 220ms ease;
}
@media (hover: hover) and (pointer: fine){
  .spec-row span:hover{ border-color: var(--blue-bright); color: var(--blue-bright); }
}

/* The one link on the page that has to be found, not discovered. */
/* Specificity note: the generic `a[href^="mailto:"]` rule below scores the same
   as a plain `a.mail-cta` and appears later in the file, so it was winning and
   painting this link white. Matching the attribute here outranks it. */
a.mail-cta[href^="mailto:"],
a.mail-cta[href^="mailto:"]:visited{
  color: var(--blue-bright);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  text-decoration: none;
  border-bottom: 1px solid rgba(41,163,255,0.45);
  transition: color 200ms ease, border-color 200ms ease;
}
a.mail-cta[href^="mailto:"]:hover{ color: var(--ink); border-bottom-color: var(--ink); }

.data-strip{
  border: 1px solid var(--panel-line);
  display: grid;
  /* auto-fit rather than a fixed count: the strip holds three or four figures
     depending on what is worth showing, and reflows to two-up on tablets
     without a bespoke breakpoint. */
  grid-template-columns: repeat(auto-fit, minmax(215px, 1fr));
  background: var(--panel);
}
.data-cell{
  padding: 32px 30px;
  border-left: 1px solid var(--panel-line);
  transition: background 250ms ease;
  position: relative;
  overflow: hidden;
}
.data-cell:first-child{ border-left: none; }
.data-cell:hover{ background: rgba(0,71,255,0.14); }
.data-cell .num{ font-size: 2.4rem; color: var(--blue-bright); margin: 0 0 10px; transition: color 200ms ease; }
.data-cell:hover .num{ color: #fff; }
.data-cell p{ margin: 0; color: var(--ink-dim); font-size: 1rem; line-height: 1.6; }

/* ---------- transformation (REW / FF) ---------- */
.transform-grid{
  display: grid;
  grid-template-columns: 1fr 72px 1fr;
  gap: 0;
  border: 1px solid var(--panel-line);
  background: var(--panel);
  align-items: stretch;
}
.tf-col{ padding: 40px 36px 44px; }
.tf-col.from{ }
.tf-col.to{ background: rgba(0,71,255,0.1); }
.tf-tag{
  font-family: 'VT323', monospace;
  font-size: 1.5rem;
  letter-spacing: 0.12em;
  margin: 0 0 18px;
  color: var(--ink-dim);
}
.tf-col.to .tf-tag{ color: var(--blue-bright); }
.tf-col ul{ margin:0; padding:0; list-style:none; }
.tf-col li{
  padding: 11px 0;
  border-bottom: 1px solid rgba(255,255,255,0.07);
  color: var(--ink-dim);
  font-size: 1.05rem;
  transition: color 200ms ease, transform 200ms var(--ease-out);
}
.tf-col li:last-child{ border-bottom: none; }
.tf-col.to li{ color: var(--ink-dim); }
.tf-col li:hover{ color: #fff; transform: translateX(8px); }
.tf-arrow{
  display:flex; align-items:center; justify-content:center;
  border-left: 1px solid var(--panel-line);
  border-right: 1px solid var(--panel-line);
  color: var(--blue-bright);
}
.tf-arrow svg{ width: 26px; height: 26px; }
@media (max-width: 860px){
  .transform-grid{ grid-template-columns: 1fr; }
  .tf-arrow{ border: none; border-top: 1px solid var(--panel-line); border-bottom: 1px solid var(--panel-line); padding: 12px 0; }
  .tf-arrow svg{ transform: rotate(90deg); }
}

/* ---------- footer ---------- */
footer{
  position: relative; z-index:1;
  margin-top: 24px;
  border-top: 1px solid var(--panel-line);
  /* extra bottom room so the fixed date OSD never lands on footer content */
  padding: 30px 0 96px;
  background: var(--bg);
}
@media (max-width: 720px){
  footer{ padding: 24px 0 92px; }
}
.footer-row{ display:flex; align-items:center; justify-content:space-between; flex-wrap: wrap; gap: 20px; }
/* The enquiries address was inheriting the browser default link style, which
   rendered it underlined royal blue — and, once clicked, browser-visited
   purple, which is close to unreadable on this ground. Scope this to EVERY
   mailto on the site, not just the footer: the address also appears under the
   inquiry form, and that instance was being missed. */
a[href^="mailto:"]{
  color: var(--ink-soft);
  text-decoration: none;
  border-bottom: 1px solid rgba(255,255,255,0.28);
  transition: color 200ms ease, border-color 200ms ease;
}
a[href^="mailto:"]:visited{ color: var(--ink-soft); }
a[href^="mailto:"]:hover{
  /* white, not blue: one of these links sits on the blue CTA panel, where a
     blue hover state would all but disappear. White reads on both grounds. */
  color: var(--ink);
  border-bottom-color: currentColor;
}
footer a[href^="mailto:"]{ color: var(--ink-dim); }
footer a[href^="mailto:"]:visited{ color: var(--ink-dim); }

/* Stacked, not inline: the studio account reads first, the personal one
   sits under it rather than competing beside it. */
.social-row{ display:flex; flex-direction: column; gap: 8px; align-items:flex-start; }
.social-row a{
  display:inline-flex; align-items:center; gap:8px;
  padding: 9px 13px;
  border-radius: var(--radius);
  border:1px solid var(--panel-line);
  color: var(--ink); text-decoration:none;
  font-family:'Chakra Petch', sans-serif; font-weight:600; font-size:0.7rem;
  text-transform: uppercase; letter-spacing:0.08em;
  transition: border-color 200ms ease, color 200ms ease;
}
.social-row a svg{ width:15px; height:15px; }
.social-row a:hover{ border-color: var(--blue-bright); color: var(--blue-bright); }

/* =========================================================
   SCROLL ENTRANCES: reveal, fold, stagger
   ========================================================= */
.reveal{
  opacity: 0;
  transform: translateY(22px);
  transition: opacity 700ms var(--ease-out), transform 700ms var(--ease-out);
}
.reveal.in{ opacity: 1; transform: translateY(0); }
.fold{
  opacity: 0;
  transform: perspective(1100px) rotateX(-13deg) translateY(46px);
  transform-origin: 50% 0%;
  transition: opacity 750ms var(--ease-out), transform 750ms var(--ease-out);
}
.fold.in{ opacity: 1; transform: perspective(1100px) rotateX(0deg) translateY(0); }
[data-stagger] > *{
  opacity: 0;
  transform: translateY(26px);
  transition: opacity 650ms var(--ease-out), transform 650ms var(--ease-out);
}
[data-stagger].in > *{ opacity: 1; transform: translateY(0); }
@media (prefers-reduced-motion: reduce){
  .reveal, .fold, [data-stagger] > *{ opacity: 1; transform: none; transition: none; }
}

/* ---------- section grids ---------- */
/* Sized to content and centred as a pair: the bio caps at its measure, so a
   1fr text column would leave a wide dead margin on the right. */
.profile-grid{
  display:grid;
  /* 70ch keeps the heading on one line; .measure still caps the body at 62ch,
     so the paragraphs stay comfortable to read. */
  grid-template-columns:250px minmax(0, 70ch);
  gap:64px;
  align-items:center;
  justify-content:center;
}

/* The hook is three beats, so each sentence holds its own line rather than
   wrapping wherever the measure happens to run out. */
.hook span{ display: block; }

/* ---------- polaroid: a living portrait, not a player ----------
   The supplied clip carries no audio, so it runs as a silent looping
   portrait rather than a click-to-play video. No controls, nothing to
   press: it just moves, which suits the tape world better. */
.polaroid{
  background: var(--ink);
  padding: 14px 14px 40px;
  transform: rotate(-3deg);
  box-shadow: 0 24px 50px rgba(0,0,0,0.45);
  justify-self: center;
  width: 250px;
  margin: 0;
}
.polaroid-media{
  position: relative;
  aspect-ratio: 9 / 16;
  overflow: hidden;
  background: var(--bg);
}
.polaroid-media video{
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.polaroid figcaption{
  font-family: 'VT323', monospace;
  color: var(--bg);
  font-size: 1.05rem;
  text-align: center;
  margin-top: 10px;
}
@media (prefers-reduced-motion: reduce){
  .polaroid{ transform: none; }
}

/* ---------- responsive ---------- */
@media (max-width: 860px){
  .blue-plane{ clip-path: polygon(0 88%, 100% 74%, 100% 100%, 0 100%); width:100%; }
  .profile-grid{ grid-template-columns:1fr; gap:44px; }
  .profile-grid figure{ justify-self:start !important; }
  .pillars{ grid-template-columns: 1fr; }
  .pillar{ border-left: none; border-top: 1px solid var(--panel-line); }
  .pillar:first-child{ border-top: none; }
  .data-strip{ grid-template-columns: 1fr; }
  .data-cell{ border-left: none; border-top: 1px solid var(--panel-line); }
  .data-cell:first-child{ border-top: none; }
  .work-row{ grid-auto-columns: minmax(270px, 85vw); }
  #scorpion-bg svg{ height: 72vh; }
}
@media (max-width: 720px){
  .section{ padding: 64px 0; }
  .nav-links a:not(.cta):not(.keep){ display:none; }
  .nav-links a.keep span{ display:none; }
  .nav-links a.keep{ padding: 10px 12px; color: var(--blue-bright); border-color: rgba(41,163,255,0.55); }
  .nav-links a.cta{ font-size: 0.7rem; padding: 10px 13px; }
  .logo .logo-mark{ height: 32px; }
  .logo .logo-word{ height: 16px; }
  .footer-row{ flex-direction: column; align-items:flex-start; }
  #intro .type-line{ white-space: normal; text-align: center; padding: 0 20px; }
}


/* =========================================================
   CHOICE CARDS (Work With Us)
   They pop onto the screen on load and grow when highlighted.
   ========================================================= */
.choice-grid{
  display: grid;
  /* auto-FILL, not auto-fit: with five cards the last row holds one, and
     auto-fit would collapse the empty track and stretch "Not sure yet" to full
     width — making the fallback the most visually dominant option on the step.
     auto-fill keeps the empty track so every card stays the same size. */
  grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
  gap: 18px;
  margin-top: 30px;
}
.choice-card{
  position: relative;
  border: 1.5px solid var(--panel-line);
  border-radius: var(--radius);
  padding: 26px 24px 28px;
  cursor: pointer;
  background: var(--panel);
  text-align: left;
  overflow: hidden;
  transform-origin: center;
  transition:
    transform 320ms var(--ease-out),
    border-color 220ms ease,
    box-shadow 320ms var(--ease-out),
    background 220ms ease;
  /* pop-in */
  opacity: 0;
  transform: translateY(20px) scale(0.94);
  animation: card-pop 620ms var(--ease-out) forwards;
}
.choice-card:nth-child(1){ animation-delay: 60ms; }
.choice-card:nth-child(2){ animation-delay: 140ms; }
.choice-card:nth-child(3){ animation-delay: 220ms; }
@keyframes card-pop{
  to{ opacity: 1; transform: translateY(0) scale(1); }
}
/* a blue wash that rises from the base on highlight */
.choice-card::before{
  content:"";
  position: absolute; inset: 0;
  background: linear-gradient(180deg, transparent 30%, rgba(0,71,255,0.22));
  opacity: 0;
  transition: opacity 300ms ease;
  pointer-events: none;
}
@media (hover: hover) and (pointer: fine){
  .choice-card:hover{
    transform: scale(1.045);
    border-color: var(--blue-bright);
    box-shadow: 0 18px 46px rgba(0,71,255,0.32);
    z-index: 2;
  }
  .choice-card:hover::before{ opacity: 1; }
  .choice-card:hover .icon-tile{
    color: #fff;
    border-color: var(--blue-bright);
    background: rgba(41,163,255,0.18);
    transform: translateY(-2px) scale(1.06);
  }
}
.choice-card:active{ transform: scale(1.01); }
.choice-card.selected{
  border-color: var(--blue-bright);
  box-shadow: 0 0 0 2px rgba(41,163,255,0.42) inset, 0 14px 38px rgba(0,71,255,0.28);
}
.choice-card.selected::before{ opacity: 1; }
.choice-card h3{
  margin: 0 0 7px;
  font-family: 'Chakra Petch', sans-serif; font-weight: 700;
  font-size: 1rem; text-transform: uppercase; letter-spacing: 0.01em;
  position: relative; z-index: 1;
}
.choice-card p{
  margin: 0; color: var(--ink-dim); font-size: 0.92rem; line-height: 1.55;
  position: relative; z-index: 1;
}
.icon-tile{
  width: 46px; height: 46px;
  border: 1.5px solid var(--panel-line);
  border-radius: var(--radius);
  display: flex; align-items: center; justify-content: center;
  color: var(--blue-bright);
  margin-bottom: 18px;
  position: relative; z-index: 1;
  transition: transform 300ms var(--ease-out), color 220ms ease,
              border-color 220ms ease, background 220ms ease;
}
.icon-tile svg{ width: 23px; height: 23px; }
@media (prefers-reduced-motion: reduce){
  .choice-card{ animation: none; opacity: 1; transform: none; }
  .choice-card:hover{ transform: none; }
}

/* recommended-field note */
.rec-note{
  margin: 8px 0 0;
  font-family: 'VT323', monospace;
  font-size: 1.02rem;
  letter-spacing: 0.04em;
  color: var(--ink-mute);
}
.rec-star{ color: var(--blue-bright); }

/* =========================================================
   PORTFOLIO: CLIENTS
   Tabs across the top select a client; each panel pairs that client's
   best work with a standing info bar describing what we did and what it
   achieved. The bar sticks while the work scrolls, so the context never
   leaves the screen.
   ========================================================= */
.client-tabs{
  display: flex;
  gap: 0;
  flex-wrap: wrap;
  border-bottom: 1px solid var(--panel-line);
  margin-bottom: 34px;
}
.client-tab{
  appearance: none;
  background: transparent;
  border: none;
  border-bottom: 2px solid transparent;
  color: var(--ink-mute);
  font-family: 'Chakra Petch', system-ui, sans-serif;
  font-weight: 700;
  font-size: 1.05rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 14px 22px 13px;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 9px;
  transition: color 200ms ease, border-color 200ms ease, background 200ms ease;
}
.client-tab:hover{ color: var(--ink); background: rgba(255,255,255,0.04); }
/* the transport cue only lights on the selected channel */
.client-tab .tab-cue{
  font-size: 0.7em;
  color: var(--blue-bright);
  opacity: 0;
  transform: translateX(-4px);
  transition: opacity 220ms var(--ease-out), transform 220ms var(--ease-out);
}
.client-tab.active{ color: var(--ink); border-bottom-color: var(--blue); }
.client-tab.active .tab-cue{ opacity: 1; transform: translateX(0); }

.client-panel{
  display: grid;
  grid-template-columns: minmax(0, 1fr) 320px;
  gap: 34px;
  align-items: start;
}
.client-panel[hidden]{ display: none; }

.work-grid{
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 18px;
}
.work-item{ margin: 0; }
.work-item .ph-frame{ width: 100%; height: 100%; }
.work-item img, .work-item video{
  width: 100%; height: 100%;
  object-fit: cover;
  display: block;
}
.work-item.r-wide{ grid-column: span 2; aspect-ratio: 16 / 9; }
.work-item.r-band{ grid-column: span 2; aspect-ratio: 16 / 9; }
.work-item.r-square{ aspect-ratio: 1 / 1; }
.work-item.r-portrait{ aspect-ratio: 9 / 16; }
.work-item.r-45{ aspect-ratio: 4 / 5; }
.work-item.r-classic{ aspect-ratio: 4 / 3; }
.work-item picture{ display: block; width: 100%; height: 100%; }

/* ---------- video cell + sound toggle ----------
   Portfolio clips run silent and looping like the rest of the tape world.
   Sound is opt-in per clip, and only one clip can be audible at a time so
   two soundtracks never talk over each other. */
.work-media{ position: relative; width: 100%; height: 100%; }
.sound-toggle{
  position: absolute;
  right: 12px; bottom: 12px;
  width: 42px; height: 42px;
  display: grid; place-items: center;
  padding: 0;
  cursor: pointer;
  color: var(--ink);
  background: rgba(5,7,13,0.62);
  border: 1px solid rgba(255,255,255,0.28);
  border-radius: var(--radius);
  backdrop-filter: blur(6px);
  transition: background 200ms ease, border-color 200ms ease, transform 200ms var(--ease-out);
}
.sound-toggle:hover{ background: rgba(0,71,255,0.5); border-color: var(--blue-bright); transform: scale(1.06); }
.sound-toggle svg{ width: 20px; height: 20px; display: block; }
.sound-toggle .ic{ grid-area: 1 / 1; display: block; transition: opacity 160ms ease; }
.sound-toggle .ic.on{ opacity: 0; }
.sound-toggle[aria-pressed="true"]{ background: var(--blue); border-color: var(--blue-bright); }
.sound-toggle[aria-pressed="true"] .ic.off{ opacity: 0; }
.sound-toggle[aria-pressed="true"] .ic.on{ opacity: 1; }

.work-info{ align-self: stretch; }
.work-info-inner{
  position: sticky;
  top: 96px;
  border: 1px solid var(--panel-line);
  background: var(--panel);
  padding: 26px 24px 28px;
}
.work-info h2{ font-size: 1.9rem; margin: 14px 0 14px; }
.work-did{ color: var(--ink-dim); font-size: 1.05rem; line-height: 1.6; margin: 0 0 20px; }
.work-did:last-child{ margin-bottom: 0; }

/* Headline numbers first, then the story. Only shown for clients who have
   figures worth leading with. */
.work-wins{
  list-style: none;
  margin: 0 0 22px;
  padding: 0 0 20px;
  border-bottom: 1px solid rgba(255,255,255,0.09);
}
.work-wins li{
  position: relative;
  padding: 7px 0 7px 20px;
  color: var(--ink);
  font-size: 1.05rem;
  line-height: 1.45;
}
.work-wins li::before{
  content: "";
  position: absolute;
  left: 0; top: 1.05em;
  width: 9px; height: 2px;
  background: var(--blue-bright);
}

@media (max-width: 980px){
  /* minmax(0,1fr), not 1fr. A bare `1fr` is minmax(auto,1fr), and `auto` takes
     its floor from the widest unbreakable child - which pushed this track to
     332px inside a 320px screen and gave portfolio.html horizontal scroll on a
     small phone. Zero as the floor lets the track shrink and hands overflow
     back to the children, which know how to handle it. */
  .client-panel{ grid-template-columns: minmax(0, 1fr); gap: 26px; }
  /* the context should be read before the work on a small screen */
  .work-info{ order: -1; }
  .work-info-inner{ position: static; }
}
@media (max-width: 560px){
  .work-grid{ grid-template-columns: 1fr; }
  .work-item.r-wide, .work-item.r-band{ grid-column: span 1; }
  .client-tab{ padding: 12px 15px 11px; font-size: 0.92rem; white-space: nowrap; }
  /* Scroll the client row rather than letting it wrap into a ragged block. */
  .client-tabs{
    flex-wrap: nowrap;
    overflow-x: auto;
    scrollbar-width: none;
    scroll-snap-type: x proximity;
    -webkit-overflow-scrolling: touch;
  }
  .client-tabs::-webkit-scrollbar{ display: none; }
  .client-tab{ scroll-snap-align: start; flex: 0 0 auto; }
}

/* =========================================================
   KSI PANEL: linked films + page-turn briefs
   ========================================================= */

/* ---------- linked film cards ----------
   The films live on YouTube rather than being re-hosted, so these are links
   dressed as players. The thumbnail comes from YouTube; if it fails to load
   the card still reads correctly, because the frame underneath carries the
   play mark and the label on its own. */
.yt-card{
  position: relative;
  display: block;
  text-decoration: none;
  color: var(--ink);
  border: 1px solid var(--panel-line);
  background: var(--panel);
  overflow: hidden;
  transition: border-color 220ms ease, transform 260ms var(--ease-out);
}
.yt-card:hover{ border-color: var(--blue-bright); transform: translateY(-3px); }
.yt-shot{
  position: relative;
  aspect-ratio: 16 / 9;
  background:
    radial-gradient(120% 120% at 50% 40%, rgba(41,163,255,0.14), transparent 70%),
    var(--bg2);
  display: grid;
  place-items: center;
  overflow: hidden;
}
.yt-shot img{
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  display: block;
}
.yt-play{
  position: relative;
  z-index: 2;
  width: 62px; height: 62px;
  display: grid; place-items: center;
  border-radius: 50%;
  background: rgba(5,7,13,0.66);
  border: 1px solid rgba(255,255,255,0.45);
  backdrop-filter: blur(4px);
  transition: background 220ms ease, border-color 220ms ease, transform 260ms var(--ease-out);
}
.yt-play svg{ width: 22px; height: 22px; margin-left: 3px; fill: var(--ink); }
.yt-card:hover .yt-play{ background: var(--blue); border-color: var(--blue-bright); transform: scale(1.08); }
.yt-meta{ padding: 16px 18px 18px; }
.yt-meta h3{
  font-family: 'Chakra Petch', system-ui, sans-serif;
  font-weight: 700; font-size: 1.05rem;
  text-transform: uppercase; letter-spacing: 0.03em;
  margin: 0 0 6px;
}
.yt-meta p{ margin: 0; color: var(--ink-mute); font-size: 0.92rem; }
.yt-meta .out{ color: var(--blue-bright); }

/* ---------- page-turn brief ----------
   The PDF is pre-rendered to page images, so no PDF library ships and a page
   costs about as much as a photo. Pages are stacked; turning rotates the
   leaving page about its spine so it reads as paper rather than a slideshow. */
.brief{
  grid-column: span 2;
  margin: 0;
  border: 1px solid var(--panel-line);
  background: var(--bg2);
  padding: 22px 22px 16px;
}
.brief-stage{
  position: relative;
  width: 100%;
  max-width: 520px;
  margin: 0 auto;
  aspect-ratio: 1100 / 1554;
  perspective: 1800px;
}
.brief-page{
  position: absolute; inset: 0;
  transform-origin: left center;
  transform-style: preserve-3d;
  backface-visibility: hidden;
  box-shadow: 0 18px 40px rgba(0,0,0,0.5);
  visibility: hidden;
  z-index: 1;
}
.brief-page img{ width: 100%; height: 100%; object-fit: contain; display: block; background: #000; }
.brief-page.on{ visibility: visible; z-index: 2; }
.brief-page.under{ visibility: visible; z-index: 1; }   /* revealed behind the turn */
.brief-page.turn-out{
  visibility: visible; z-index: 3;
  animation: page-out 620ms var(--ease-in-out) forwards;
}
.brief-page.turn-in{
  visibility: visible; z-index: 3;
  animation: page-in 620ms var(--ease-in-out) forwards;
}
@keyframes page-out{
  0%{ transform: rotateY(0deg); filter: brightness(1); }
  100%{ transform: rotateY(-158deg); filter: brightness(0.35); }
}
@keyframes page-in{
  0%{ transform: rotateY(-158deg); filter: brightness(0.35); }
  100%{ transform: rotateY(0deg); filter: brightness(1); }
}

.brief-bar{
  display: flex; align-items: center; justify-content: space-between;
  gap: 14px;
  margin-top: 16px;
}
.brief-label{
  font-family: 'Chakra Petch', system-ui, sans-serif;
  font-weight: 600; font-size: 0.8rem;
  text-transform: uppercase; letter-spacing: 0.09em;
  color: var(--ink-mute);
}
.brief-nav{ display: flex; align-items: center; gap: 10px; }
.brief-btn{
  width: 38px; height: 38px;
  display: grid; place-items: center;
  padding: 0; cursor: pointer;
  color: var(--ink);
  background: rgba(255,255,255,0.06);
  border: 1px solid var(--panel-line);
  border-radius: var(--radius);
  transition: background 200ms ease, border-color 200ms ease, opacity 200ms ease;
}
.brief-btn:hover:not(:disabled){ background: var(--blue); border-color: var(--blue-bright); }
.brief-btn:disabled{ opacity: 0.3; cursor: default; }
.brief-btn svg{ width: 17px; height: 17px; }
.brief-count{
  font-family: 'VT323', monospace;
  font-size: 1.05rem;
  letter-spacing: 0.08em;
  color: var(--ink-dim);
  min-width: 62px;
  text-align: center;
}
@media (prefers-reduced-motion: reduce){
  .brief-page.turn-out, .brief-page.turn-in{ animation: none; }
}
@media (max-width: 560px){
  .brief{ grid-column: span 1; padding: 14px 14px 12px; }
}

/* ============ Enquiry form: sending state ============
   A form POST navigates the page away, so there is no progress to measure and
   nothing to report back. An indeterminate sweep is the honest signal: it says
   "working", not "37% done", and it stops the second click that would send a
   duplicate enquiry. */
.sending{ margin: 24px 0 0; }
.sending-bar{
  position: relative; height: 3px; overflow: hidden;
  background: rgba(255,255,255,0.12);
}
.sending-bar span{
  position: absolute; top: 0; bottom: 0; left: 0; width: 36%;
  background: var(--blue-bright);
  animation: sending-sweep 1150ms cubic-bezier(0.65, 0, 0.35, 1) infinite;
}
@keyframes sending-sweep{
  from{ transform: translateX(-110%); }
  to  { transform: translateX(320%); }
}
.sending-label{ margin: 11px 0 0; color: var(--ink-dim); letter-spacing: 0.14em; }
@media (prefers-reduced-motion: reduce){
  .sending-bar span{ animation: none; width: 100%; opacity: 0.45; }
}

/* ============================================================
   FAIL-SAFE: what the page looks like when the JavaScript never runs
   ------------------------------------------------------------
   Every heading and paragraph starts at opacity 0 and is faded in by the
   scroll-reveal code. That is fine while the code runs. When it does not —
   a blocked request, a bad upload, a browser extension refusing the file,
   a hostile corporate proxy — the text is still in the page but invisible
   forever, and the site looks empty rather than plain.

   `js-failed` is put on <html> either by the script tag's own onerror
   handler (fires the instant the file fails to load) or by a watchdog timer
   that gives up if main.js has not checked in. Either way, everything the
   JavaScript was going to reveal is simply shown.

   The page loses its animations. It does not lose its content.
   ============================================================ */
html.js-failed .reveal,
html.js-failed .fold,
html.js-failed [data-stagger],
html.js-failed [data-stagger] > *{
  opacity: 1 !important;
  transform: none !important;
  transition: none !important;
}
/* The intro gate on the landing page hides the whole site behind a loading
   screen that only JavaScript can dismiss. Without JS that screen is a dead
   end, so remove it and show the site. */
html.js-failed body.pre-enter #site,
html.js-failed #site{ opacity: 1 !important; }
html.js-failed #intro{ display: none !important; }
/* Same reasoning for anyone browsing with JavaScript switched off entirely. */


/* ============================================================
   Intrinsic sizing
   ------------------------------------------------------------
   Every <img> now carries width and height attributes taken from the file
   itself. That is what lets the browser reserve the correct box before a
   single byte of the image arrives — the difference between a page that
   settles and a page that jumps. The rule below keeps those attributes as a
   RATIO rather than a size, so the layout still governs how big things are.
   ============================================================ */
img{ max-width: 100%; height: auto; }

/* ============================================================
   SKELETONS
   ------------------------------------------------------------
   What these do and do not fix, stated plainly.

   They do NOT fix layout shift. Every one of these containers already
   reserves its box — the work grid and flipbook via aspect-ratio, every
   <img> via width/height attributes — so nothing moves when content arrives,
   with or without a skeleton. What they fix is the empty hole in between: a
   lazy image below the fold is a blank rectangle until it decodes, and on a
   slow connection that reads as broken rather than loading.

   The sweep is a TRANSFORM on a pseudo-element, not an animated
   background-position. The first version of this animated background-position
   and Lighthouse correctly flagged every work-item as a non-composited
   animation: background-position repaints the element on every frame, on the
   main thread, which cost 0.8s of Speed Index across the grid. A translated
   overlay runs on the compositor and costs nothing.
   ============================================================ */
.skeleton{
  position: relative;
  overflow: hidden;
  background-color: rgba(255,255,255,0.045);
}
.skeleton::after{
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(
    100deg,
    rgba(255,255,255,0)    0%,
    rgba(255,255,255,0.07) 50%,
    rgba(255,255,255,0)   100%
  );
  transform: translate3d(-100%, 0, 0);
  animation: skeleton-sweep 1500ms linear infinite;
  will-change: transform;
}
@keyframes skeleton-sweep{
  from{ transform: translate3d(-100%, 0, 0); }
  to  { transform: translate3d(100%, 0, 0); }
}
/* The moment real content paints, the placeholder stops being one. */
.skeleton.is-loaded{ background-color: transparent; }
.skeleton.is-loaded::after{ display: none; animation: none; }
/* No shimmer for anyone who has asked for less motion. The holding tone stays
   — it is the movement that is the problem, not the box. */
@media (prefers-reduced-motion: reduce){
  .skeleton::after{ animation: none; display: none; }
}

/* =========================================================
   LEGAL PAGES (privacy, terms) + FAQ ACCORDION
   ========================================================= */

/* ---------- legal ---------- */
.legal-head{ padding: 132px 0 46px; }
.legal{ padding: 0 0 96px; }
.legal-body{
  max-width: 68ch;
  color: var(--ink-dim);
  font-size: 1.02rem;
  line-height: 1.72;
}
.legal-updated{
  font-family:'Chakra Petch', sans-serif; font-weight:600;
  font-size: 0.72rem; letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--ink-mute); margin: 0 0 34px;
  padding-bottom: 18px; border-bottom: 1px solid var(--panel-line);
}
.legal-body h2{
  font-family:'Chakra Petch', sans-serif; font-weight:700;
  font-size: 1.24rem; letter-spacing: 0.01em; color: var(--ink);
  margin: 42px 0 12px;
}
.legal-body h2:first-of-type{ margin-top: 0; }
.legal-body p{ margin: 0 0 16px; }
.legal-body ul{ margin: 0 0 20px; padding-left: 22px; }
.legal-body li{ margin: 0 0 9px; }
.legal-body strong{ color: var(--ink-soft); font-weight: 600; }
.legal-body a{ color: var(--blue-bright); text-decoration: underline; text-underline-offset: 3px; }
.legal-body a:hover{ color: var(--ink); }

/* footer legal row */
.footer-legal{
  margin-top: 30px; padding-top: 18px;
  border-top: 1px solid var(--panel-line);
  display: flex; flex-wrap: wrap; gap: 8px 20px; align-items: center;
  font-size: 0.8rem; color: var(--ink-mute);
}
.footer-legal a{ color: var(--ink-mute); }
.footer-legal a:hover{ color: var(--blue-bright); }

/* ---------- FAQ accordion ---------- */
.faq{ padding: 40px 0 112px; }
.faq-list{ max-width: 74ch; margin: 34px 0 0; border-top: 1px solid var(--panel-line); }
.faq-item{ border-bottom: 1px solid var(--panel-line); }

/* A real <button>: focusable, space/enter operable and announced as expandable
   without a line of JavaScript to fake any of it. */
.faq-q{
  width: 100%;
  display: flex; align-items: flex-start; justify-content: space-between; gap: 20px;
  /* 22px block padding puts the row well past the 44px minimum target */
  padding: 22px 2px;
  background: none; border: 0; cursor: pointer; text-align: left;
  font-family:'Chakra Petch', sans-serif; font-weight: 600;
  font-size: 1.06rem; line-height: 1.4; color: var(--ink);
  transition: color 200ms ease;
}
.faq-q:hover{ color: var(--blue-bright); }
.faq-icon{
  flex: 0 0 auto; width: 15px; height: 15px; margin-top: 4px;
  position: relative;
}
.faq-icon::before, .faq-icon::after{
  content:""; position:absolute; inset:0; margin:auto;
  background: var(--blue-bright);
}
.faq-icon::before{ width: 15px; height: 2px; }
.faq-icon::after{
  width: 2px; height: 15px;
  transform: scaleY(1); transform-origin: center;
  transition: transform 240ms var(--ease-out);
}
.faq-q[aria-expanded="true"] .faq-icon::after{ transform: scaleY(0); }

/* grid-template-rows 0fr -> 1fr is the only way to animate to auto height
   while the answer stays in normal flow. */
.faq-a{
  display: grid; grid-template-rows: 0fr;
  transition: grid-template-rows 260ms var(--ease-out);
}
.faq-item.open .faq-a{ grid-template-rows: 1fr; }
.faq-a > div{ overflow: hidden; }
.faq-a p{
  margin: 0 0 22px; max-width: 62ch;
  color: var(--ink-dim); font-size: 1rem; line-height: 1.68;
}
.faq-a p:first-child{ padding-top: 2px; }

@media (prefers-reduced-motion: reduce){
  .faq-a{ transition: none; }
  .faq-icon::after{ transition: none; }
}

@media (max-width: 640px){
  .legal-head{ padding: 108px 0 34px; }
  .faq{ padding: 24px 0 84px; }
  .faq-q{ font-size: 0.99rem; }
}

/* =========================================================
   MOBILE / ACCESSIBILITY PASS
   ========================================================= */

/* ---------- iOS input zoom ----------
   Safari on iOS zooms the whole page when a focused field's text is under 16px,
   and it does not zoom back out afterwards. 16px exactly, on every control that
   can take focus. Inline links in prose are exempt from the target-size rule and
   are deliberately left alone; these are the actual controls. */
.field input,
.field select,
.field textarea,
input[type="text"], input[type="email"], input[type="tel"],
input[type="url"], input[type="date"], select, textarea{
  font-size: 16px;
}

/* ---------- tap targets ----------
   WCAG 2.5.8 asks for 44x44 CSS px on controls. These were all short in the
   cross-axis only, so a min-height plus centring fixes them without moving
   anything sideways. */
.nav-links a,
.nav-links a.cta{
  min-height: 44px;
  display: inline-flex;
  align-items: center;
}
.nav-links a.keep{ min-width: 44px; justify-content: center; }
.nav .logo{ min-height: 44px; display: inline-flex; align-items: center; }
.sound-toggle{ min-width: 44px; min-height: 44px; }
.faq-q{ min-height: 44px; }
.client-tab{ min-height: 44px; }
.footer-legal a{ min-height: 44px; display: inline-flex; align-items: center; }

/* ---------- focus ----------
   One visible ring on everything focusable, keyboard only, so a mouse click
   does not leave a ring behind but a tab stop is never invisible. */
a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
[tabindex]:focus-visible{
  outline: 2px solid var(--blue-bright);
  outline-offset: 3px;
  border-radius: 2px;
}

/* A bare `.btn` had no colour of its own: every existing use pairs it with
   btn-chrome, btn-blue or btn-ghost, so the gap never showed. Used alone it
   fell through to the browser's default link blue on a near-black page, at a
   2.14:1 contrast ratio. A base colour here means that can never happen again. */
.btn{ color: var(--ink); }

/* The footer logo and the two social links sit outside .nav, so the tap-target
   rule above did not reach them. */
footer .logo{ min-height: 44px; display: inline-flex; align-items: center; }
.social-row a{ min-height: 44px; display: inline-flex; align-items: center; }

/* Visible to screen readers, invisible on screen. Not display:none and not
   visibility:hidden - both of those remove it from the accessibility tree,
   which defeats the point. */
.sr-only{
  position: absolute !important;
  width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
}

/* The drifting scorpion sits directly behind body copy on the legal pages,
   which is fine over headlines and distracting over a paragraph. Half strength
   there; untouched everywhere else. */
.legal-page .scorp-film video,
.legal-page .scorp-film img{ opacity: 0.12; }
