/* ==========================================================================
   TW3 STUDIOS — Design System
   Palette derived from the TW3 mark: signal red + brushed silver on near-black.
   ========================================================================== */

:root {
  /* Dark UA chrome. Scrollbars, the native select popup and the arrow glyph inside
     the closed select all follow this. Without it, Windows and Firefox paint a light
     scrollbar track against the ink ground, and the enquiry picker on contact.html
     opens as a white sheet. */
  color-scheme: dark;

  /* --- Brand: sampled from the TW3 logo ---
     Two reds on purpose. --tw3-red is a SURFACE colour (white on it = 5.65:1).
     --tw3-red-bright is a TEXT colour on dark (5.27:1 on ink-900). Swapping them
     breaks WCAG AA, so keep the roles straight. */
  --tw3-red:        #C42B22;   /* button//surface fill, large display type */
  --tw3-red-hover:  #D63A2F;   /* button hover — white still passes at 4.66:1 */
  --tw3-red-bright: #F2544A;   /* small red TEXT on dark surfaces (4.84:1 on cards) */
  --tw3-red-deep:   #8E1C15;   /* pressed / deep accents */

  /* --- Silver (logo "W") --- */
  --silver-100: #F2F3F5;
  --silver-200: #C9CCD1;
  --silver-400: #8A8F98;
  --silver-600: #82878F;   /* muted text — still ≥4.5:1 on every surface */

  /* --- Ink: warm plum-charcoal ramp, never pure #000. The violet-red cast is
     pulled from the films themselves (Merry's magic VFX + firelight), so the
     ground belongs to the studio instead of reading as default dark mode. --- */
  --ink-950: #0E0B10;   /* deepest — hero base, lightbox */
  --ink-900: #151118;   /* page background */
  --ink-800: #1C161E;   /* raised sections */
  --ink-700: #241C26;   /* cards */
  --ink-600: #2E2430;   /* elevated / hover */

  --line: rgba(255, 255, 255, 0.10);
  --line-strong: rgba(255, 255, 255, 0.20);

  /* --- Type --- */
  --font-display: 'Archivo', 'Archivo Fallback', 'Helvetica Neue', Arial, sans-serif;
  --font-body: 'Inter', 'Inter Fallback', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  --font-mono: 'JetBrains Mono', ui-monospace, 'SF Mono', Menlo, monospace;

  /* --- Motion (Expo.out) --- */
  /* Restored: deleting the decorative head marks (1123448) took these two
     with them, but .proc.ledger, .form-sheet and the sprocket rail still
     reference them — an undefined var kills the whole declaration. */
  --rule-ink: rgba(255, 255, 255, .09);
  --sprocket: radial-gradient(circle, rgba(255,255,255,.16) 2.6px, transparent 3.2px);
  --ease: cubic-bezier(0.16, 1, 0.30, 1);
}

/* ==========================================================================
   Fonts — self-hosted
   Previously loaded from fonts.googleapis.com, which cost two sequential network
   hops before the hero could paint in its real face: "MERRY" drew in Arial at
   clamp(2.6rem, 7.5vw, 6.5rem), then reflowed into Archivo at font-stretch 118%.
   Arial's metrics are nothing like extended Archivo 800, so a ~100px word
   visibly changed width on the opening frame. Self-hosting also removes the
   site's last third-party dependency: a network that blocks fonts.gstatic.com
   used to get Arial everywhere.

   Only latin and latin-ext are shipped. The Cyrillic, Greek and Vietnamese
   subsets Google serves are dead weight for an English-language site.
   ========================================================================== */

@font-face {
  font-family: 'Archivo';
  font-style: normal;
  font-weight: 800;
  font-stretch: 118%;
  font-display: swap;
  src: url('../fonts/archivo-800-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Archivo';
  font-style: normal;
  font-weight: 800;
  font-stretch: 118%;
  font-display: swap;
  src: url('../fonts/archivo-800-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../fonts/inter-400-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../fonts/inter-400-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* One file serves the 400-500 range: the "500" woff2s Google served were
   byte-identical to the 400s (same md5), so declaring them separately cost a
   duplicate 31 KB download per page for zero visual difference. */
@font-face {
  font-family: 'JetBrains Mono';
  font-style: normal;
  font-weight: 400 500;
  font-display: swap;
  src: url('../fonts/jetbrains-mono-400-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'JetBrains Mono';
  font-style: normal;
  font-weight: 400 500;
  font-display: swap;
  src: url('../fonts/jetbrains-mono-400-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* The swap only stops being visible if the fallback occupies the same space.
   These overrides scale Arial to Archivo's metrics, so the hero headline does
   not change width when the real face arrives. */
@font-face {
  font-family: 'Archivo Fallback';
  src: local('Arial');
  size-adjust: 112%;
  ascent-override: 88%;
  descent-override: 22%;
  line-gap-override: 0%;
}
@font-face {
  font-family: 'Inter Fallback';
  src: local('Arial');
  size-adjust: 107%;
  ascent-override: 90%;
  descent-override: 22%;
  line-gap-override: 0%;
}

/* ==========================================================================
   Base
   ========================================================================== */

html { scroll-behavior: smooth; }

body {
  background: var(--ink-900);
  color: var(--silver-100);
  font-family: var(--font-body);
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

/* Film grain — a fixed, near-invisible layer of photographic noise that keeps
   large dark areas from reading as flat vector black. Sits above content but
   below the nav (z-100), mobile nav (z-99) and lightbox (z-200). */
body::after {
  content: '';
  position: fixed; inset: 0;
  z-index: 95;
  pointer-events: none;
  opacity: .05;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size: 160px 160px;
}

/* ==========================================================================
   Scenes — section grounds. Each scene sits on the warm ramp and carries its
   own ambient light, so the page reads as a sequence of lit sets rather than
   one continuous black surface.
   ========================================================================== */

.scene { position: relative; isolation: isolate; background: var(--ink-900); }
.scene::before {
  content: ''; position: absolute; inset: 0; z-index: -1; pointer-events: none;
}

/* Ember — firelight from the top corner, like the torch glow in the stills */
.scene-ember::before {
  background:
    radial-gradient(1000px 560px at 88% -10%, rgba(224, 96, 42, .13), transparent 62%),
    radial-gradient(720px 480px at -8% 108%, rgba(196, 43, 34, .09), transparent 58%);
}

/* Violet — the magic-VFX cast from Merry's snowfield flight */
.scene-violet::before {
  background:
    radial-gradient(900px 540px at 8% 0%, rgba(139, 92, 246, .13), transparent 60%),
    radial-gradient(760px 500px at 104% 82%, rgba(216, 70, 160, .08), transparent 58%);
}

/* Raised — lighter ground with a soft top edge-light */
.scene-raised { background: var(--ink-800); }
.scene-raised::before {
  background:
    linear-gradient(to bottom, rgba(255,255,255,.045), transparent 140px),
    radial-gradient(820px 480px at 50% 118%, rgba(196, 43, 34, .06), transparent 60%);
}

::selection { background: var(--tw3-red); color: #fff; }

/* Visible focus for keyboard nav — never removed */
:focus-visible {
  outline: 2px solid var(--tw3-red-bright);
  outline-offset: 3px;
  border-radius: 2px;
}

/* Skip link */
.skip-link {
  position: absolute; left: -9999px; top: 0; z-index: 200;
  background: var(--tw3-red); color: #fff; padding: 12px 20px;
  font-family: var(--font-mono); font-size: 12px; letter-spacing: .1em;
  text-transform: uppercase;
}
.skip-link:focus { left: 0; }

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

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

/* Wide, poster-weight display type — the studio's voice */
.display {
  font-family: var(--font-display);
  font-weight: 800;
  font-stretch: 118%;
  letter-spacing: -0.02em;
  line-height: 0.92;
  text-transform: uppercase;
  /* Long single words (CHARACTERS, PRODUCTION) must never breach the column.
     overflow-wrap alone is enough; word-break lowers min-content width and lets
     grid cells force mid-word breaks, which is the more destructive of the two. */
  overflow-wrap: break-word;
}

.display-md { font-size: clamp(1.6rem, 3.2vw, 2.75rem); }

/* Mono eyebrow labels — [ 01 ] section markers */
.eyebrow {
  font-family: var(--font-mono);
  font-size: 0.72rem;
  font-weight: 500;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--silver-400);
}
.eyebrow--red { color: var(--tw3-red-bright); }

/* An eyebrow sitting on photography rather than flat ink. --tw3-red-bright is
   specced for dark SURFACES (4.84:1 on cards); over the home hero's fire ring
   the brightest pixel under these glyphs is rgb(248,219,189), which drags an
   11.52px red line down to 2.31:1 at 390px. No amount of scrim fixes that
   without blacking out the image, so the type changes instead of the picture.
   Two classes so it wins over .eyebrow--red regardless of source order. */
.eyebrow.eyebrow--on-art { color: var(--silver-100); }

.lede {
  font-size: clamp(1rem, 1.35vw, 1.2rem);
  line-height: 1.65;
  color: var(--silver-200);
  /* 89 characters per line at 1600px was the widest measure on the site.
     62ch is the top of the comfortable range and costs nothing. */
  max-width: 62ch;
}

/* Page title. Subpage <h1>s used the exact same clamp as every <h2> beneath
   them, so a page's name carried no more weight than a section label and the
   top of every subpage had no hierarchy. This sits between the hero (~128px)
   and section headings (42px), which was an empty rung on the scale. */
.page-title { font-size: clamp(2.3rem, 5vw, 4rem); }

/* ==========================================================================
   Hazard stripe — lifted from the logo's corner detail. Brand signature.
   ========================================================================== */

.hazard {
  background-image: repeating-linear-gradient(
    -45deg,
    var(--tw3-red) 0 10px,
    transparent 10px 20px
  );
}
.hazard-thin { height: 6px; }

/* ==========================================================================
   Buttons
   ========================================================================== */

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: .6rem;
  font-family: var(--font-mono); font-size: .78rem; font-weight: 500;
  letter-spacing: .14em; text-transform: uppercase;
  padding: 1rem 2rem;
  min-height: 48px;              /* touch target ≥44px */
  cursor: pointer;
  transition: background-color .25s var(--ease), color .25s var(--ease),
              border-color .25s var(--ease), transform .25s var(--ease);
}
.btn:active { transform: scale(.975); }

.btn-primary { background: var(--tw3-red); color: #fff; }
.btn-primary:hover { background: var(--tw3-red-hover); }

.btn-ghost {
  border: 1px solid var(--line-strong);
  color: var(--silver-100);
  background: transparent;
}
.btn-ghost:hover { border-color: var(--tw3-red); background: rgba(196,43,34,.12); }

/* ==========================================================================
   Header
   ========================================================================== */

.site-header {
  position: fixed; inset: 0 0 auto 0; z-index: 100;
  transition: background-color .35s var(--ease), backdrop-filter .35s var(--ease),
              border-color .35s var(--ease);
  border-bottom: 1px solid transparent;
}
.site-header.is-stuck {
  background: rgba(14, 11, 16, 0.82);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border-bottom-color: var(--line);
}

.nav-link {
  font-family: var(--font-mono); font-size: .74rem; font-weight: 500;
  letter-spacing: .16em; text-transform: uppercase;
  color: var(--silver-200);
  padding: .5rem 0;
  position: relative;
  transition: color .25s var(--ease);
}
.nav-link::after {
  content: ''; position: absolute; left: 0; bottom: 0;
  width: 100%; height: 2px; background: var(--tw3-red);
  transform: scaleX(0); transform-origin: left;
  transition: transform .3s var(--ease);
}
.nav-link:hover { color: #fff; }
.nav-link:hover::after,
/* Subpages mark the parent section aria-current="true" (merry → Projects,
   tom-walsh → Team); style both values or sighted users lose the wayfinding
   that screen readers are already announcing. */
.nav-link[aria-current="page"]::after,
.nav-link[aria-current="true"]::after { transform: scaleX(1); }
.nav-link[aria-current="page"],
.nav-link[aria-current="true"] { color: #fff; }

/* Mobile drawer */
.mobile-nav {
  position: fixed; inset: 0; z-index: 99;
  background: var(--ink-900);
  display: flex; flex-direction: column; justify-content: center;
  opacity: 0; pointer-events: none;
  transition: opacity .3s var(--ease);
}
.mobile-nav.is-open { opacity: 1; pointer-events: auto; }

/* ==========================================================================
   Hero — rotating Merry stills with slow Ken Burns
   ========================================================================== */

.hero-slide {
  position: absolute; inset: 0;
  background-size: cover; background-position: center;
  opacity: 0;
  /* Transform must transition too. The zoom lives on an animation tied to
     .is-active; when that class is removed the transform reverts instantly,
     so the outgoing slide jumped ~7% smaller mid-crossfade. */
  transition: opacity 1.6s var(--ease), transform 1.6s var(--ease);
  will-change: opacity, transform;
}
.hero-slide.is-active {
  opacity: 1;
  animation: kenburns 14s linear forwards;
}

@keyframes kenburns {
  from { transform: scale(1.02); }
  to   { transform: scale(1.13); }
}

/* A gentler push for slides whose subject is a hard-edged rectangle. The dub
   stage shots are a projection screen inside a room: the 1.02 -> 1.13 travel
   above is designed for atmosphere (a forest, a library) where losing an edge
   costs nothing, but here it clips the screen itself — roughly a quarter of
   the width by the end of the cycle. These barely move instead. */
@keyframes kenburns-framed {
  from { transform: scale(1.0); }
  to   { transform: scale(1.035); }
}

/* The film page's own hero runs the scene rather than a frame of it. Desktop
   gets the clip, phones get the still: a 6 MB loop is not a fair ask on
   cellular, and the portrait crop reads better on a tall screen anyway. Only
   one of the two is ever in the layout, so they cannot both paint. */
/* Ambient clips are decoration, never players. Without pointer-events:none a
   refused autoplay on iOS leaves a tappable element: the native control bar
   appears, and on the projects card it would sit on top of the link, so a tap
   would neither start the clip nor open the film. Taps pass through instead. */
.ambient-clip,
.hero-film { pointer-events: none; }

.hero-film {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  pointer-events: none;   /* see .ambient-clip below */
  /* Phones crop a 16:9 frame to roughly its middle third. Merry rides the
     right of frame, so a centred crop loses her; bias the crop toward her. */
  object-position: 68% center;
}
@media (min-width: 768px) { .hero-film { object-position: center; } }

/* Legibility scrim. Density lives ONLY where the text block sits (left third,
   plus a bottom anchor) — the centre and right of the frame stay open so the
   subject reads clearly. Don't widen these gradients globally to fix contrast;
   deepen the LEFT stops instead. */
.hero-scrim {
  position: absolute; inset: 0;
  background:
    /* bottom-heavy: text is anchored to the bottom band, so density lives there;
       the upper two-thirds stays near-clear for the image */
    /* The 26/52/72% stops were lifted (.62/.16/.06 -> .72/.30/.14) after
       measuring 11.52px eyebrow text against the brightest pixel under its
       actual glyphs at 390px: the back-link and the presents line landed at
       4.13:1 and 4.30:1 against the 4.5:1 AA floor. Only the mid band moved,
       so the image still reads through the upper two-thirds. */
    linear-gradient(to top,
      rgba(14,11,16,.94) 0%,
      rgba(14,11,16,.72) 26%,
      rgba(14,11,16,.30) 52%,
      rgba(14,11,16,.14) 72%,
      rgba(14,11,16,.64) 100%),
    /* Text wash: strong on the left, gone before mid-frame. Raised from
       .72/.50/.22 because the eyebrow line sits directly over the fire ring at
       1440 (brightest pixel under its glyphs is rgb(248,219,189)). Carrying the
       correction here rather than in the vertical band keeps the darkening on
       the left column where the type lives, instead of dimming the whole
       middle of the frame. */
    linear-gradient(to right,
      rgba(14,11,16,.90) 0%,
      rgba(14,11,16,.78) 34%,
      rgba(14,11,16,.50) 52%,
      rgba(14,11,16,.24) 66%,
      transparent 78%);
}

/* Portrait screens: text lines run nearly full-width, so the left wash stops
   protecting line ends and the vertical band has to carry everything. Stops
   measured against the 8K cloud portrait — the brightest art in the rotation. */
@media (max-width: 767px) {
  /* Portrait art fills the frame edge to edge, so the left wash protects
     nothing — the vertical band carries all of it. Stops measured against
     the 8K cloud portrait, the brightest art in the rotation. */
  .hero-scrim {
    background:
      linear-gradient(to top,
        rgba(14,11,16,.94) 0%,
        rgba(14,11,16,.86) 34%,
        rgba(14,11,16,.79) 58%,
        rgba(14,11,16,.68) 78%,
        rgba(14,11,16,.70) 100%);
  }

  /* 100svh on a phone means the hero IS the screen — nothing hints the page
     continues, and half the frame was empty art above the text. Trimming it
     lets the next section break the fold, which is what invites the scroll. */
  /* section[data-hero], not [data-hero]: the element carries Tailwind's
     h-[100svh] utility, which ties on specificity and wins on source order
     because tailwind.css loads after this file. The element qualifier breaks
     the tie without !important. */
  section[data-hero] { height: 78svh; }
}


/* Scroll cue — subtle drifting chevron, bottom centre */
.hero-scroll {
  position: absolute;
  left: 50%;
  bottom: 1.6rem;
  transform: translateX(-50%);
  z-index: 2;
  display: flex; align-items: center; justify-content: center;
  width: 48px; height: 48px;          /* touch target */
  padding: 0; border: none; background: none;
  color: var(--tw3-red-bright);
  cursor: pointer;
  transition: color .25s var(--ease);
}
.hero-scroll:hover { color: #fff; }
.hero-scroll svg { animation: chevron-drift 2s var(--ease) infinite; }

@keyframes chevron-drift {
  0%, 100% { transform: translateY(-3px); opacity: .5; }
  50%      { transform: translateY(4px);  opacity: 1; }
}

/* Slide progress indicators */
.hero-dot {
  width: 34px; height: 3px;
  /* .28 over the scrim measured 2.43:1, below the 3:1 minimum for a UI
     indicator, and an inactive dot was near-indistinguishable from an active
     one at the top of each slide (the red fill starts at scaleX(0)). */
  background: rgba(255,255,255,.5);
  position: relative;
  cursor: pointer; border: none; padding: 0;
}
/* The bar is deliberately 3px, so the tap target comes from a transparent
   expander rather than padding — box-sizing: border-box would floor a padded
   3px box to zero height and the bar would vanish. Adjacent boxes meet across
   the 12px gap. overflow is NOT hidden here or it would clip this back to 3px;
   ::after is inset:0 with scaleX(<=1) so it can never exceed the box. */
.hero-dot::before { content: ''; position: absolute; inset: -21px -6px; }
.hero-dot::after {
  content: ''; position: absolute; inset: 0;
  background: var(--tw3-red-bright);
  transform: scaleX(0); transform-origin: left;
}
.hero-dot.is-active::after { animation: dotfill 6s linear forwards; }
@keyframes dotfill { from { transform: scaleX(0); } to { transform: scaleX(1); } }


/* Gallery captions reveal on hover — but touch screens have no hover, so
   the labels were unreachable on phones. Show them wherever hover cannot. */
@media (hover: none) {
  [data-gallery] button .eyebrow { opacity: 1; }
}

/* ==========================================================================
   Cards
   ========================================================================== */

/* Slate cards. The bottom-right corner is cut like a clapperboard, with a red
   tick along the cut — no uniform 1px border box. Depth comes from a layered
   warm gradient and shadow, not an outline. */
.card {
  position: relative;
  background:
    linear-gradient(165deg, rgba(255,255,255,.055) 0%, rgba(255,255,255,.012) 55%, rgba(196,43,34,.06) 100%),
    var(--ink-700);
  border: none;
  clip-path: polygon(0 0, 100% 0, 100% calc(100% - 22px), calc(100% - 22px) 100%, 0 100%);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.07),
    0 18px 40px -22px rgba(0,0,0,.65);
  transition: transform .3s var(--ease), box-shadow .3s var(--ease),
              background-color .3s var(--ease);
}
/* red tick riding the clapperboard cut */
.card::after {
  content: ''; position: absolute; right: 0; bottom: 0;
  width: 34px; height: 34px; pointer-events: none;
  background: linear-gradient(135deg,
    transparent 46%, var(--tw3-red) 46%, var(--tw3-red) 60%, transparent 60%);
}
.card:hover {
  transform: translateY(-4px);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.07),
    0 0 0 1px rgba(242,84,74,.35),
    0 24px 48px -20px rgba(196,43,34,.28);
}

/* Call sheets. Panels read like a production call sheet: red spine, mono
   labels, dotted leaders running to right-aligned values. */
.sheet {
  position: relative;
  border-left: 3px solid var(--tw3-red);
  background:
    linear-gradient(115deg, rgba(196,43,34,.10), transparent 42%),
    linear-gradient(165deg, rgba(255,255,255,.04), transparent 60%),
    var(--ink-800);
}
.sheet dl > div { display: flex; align-items: baseline; gap: .75rem; }
.sheet dt { flex: none; margin-bottom: 0 !important; }
.sheet dd {
  flex: 1; display: flex; align-items: baseline; justify-content: flex-end;
  gap: .75rem; text-align: right; min-width: 0;
}
.sheet dd::before {
  content: ''; flex: 1; min-width: 1.25rem;
  border-bottom: 1px dotted rgba(255,255,255,.22);
  transform: translateY(-.3em);
}

/* Read-bio disclosure — native <details>, keyboard-accessible for free */
.bio summary {
  display: inline-flex; align-items: center; gap: .5rem;
  cursor: pointer; list-style: none;
  font-family: var(--font-mono); font-size: .72rem; font-weight: 500;
  letter-spacing: .16em; text-transform: uppercase;
  color: var(--silver-400);
  transition: color .2s var(--ease);
  /* The label is only 17px tall on its own, which is well under a comfortable
     tap target and this control appears six times on the team page. Padding
     grows the hit area without moving the text: the negative margin pulls the
     block back so the visual rhythm of the card is unchanged. */
  padding-block: .85rem;
  margin-block: -.85rem;
}
.bio summary::-webkit-details-marker { display: none; }
.bio summary:hover { color: #fff; }
.bio summary::after {
  content: '+';
  color: var(--tw3-red-bright);
  font-size: .95rem; line-height: 1;
  transition: transform .25s var(--ease);
}
.bio[open] summary::after { transform: rotate(45deg); }
.bio p {
  margin-top: .65rem;
  font-size: .875rem; line-height: 1.65;
  color: var(--silver-400);
}

.media-zoom { overflow: hidden; }
.media-zoom img,
.media-zoom video {
  transition: transform .7s var(--ease);
  will-change: transform;
}
.card:hover .media-zoom img,
.media-zoom:hover img { transform: scale(1.06); }


/* One-sheet artwork. A portrait poster left unconstrained runs nearly two
   screens tall on a phone, so it is capped until lg, where it has its own
   column and should fill it. Named here rather than composed from utilities
   because lg:max-w-none is not in the pre-built Tailwind file. */
.poster {
  display: block;
  width: 100%;
  max-width: 300px;
  margin-inline: auto;
  border: 1px solid rgba(255, 255, 255, .10);
}
@media (min-width: 1024px) { .poster { max-width: none; } }

/* Team portraits. The six headshots come from six different cameras, rooms and
   decades — a shared duotone flattens that spread into one editorial set.
   Colour returns on hover so the real photograph is still there. */
.portrait { position: relative; background: var(--ink-800); }
.portrait img {
  filter: grayscale(1) contrast(1.06) brightness(.94);
  transition: transform .7s var(--ease), filter .6s var(--ease);
}
.portrait::after {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    linear-gradient(180deg, rgba(196,43,34,.14) 0%, transparent 45%),
    linear-gradient(0deg, rgba(14,11,16,.55) 0%, transparent 55%);
  transition: opacity .6s var(--ease);
}
.card:hover .portrait img { filter: grayscale(.15) contrast(1.02) brightness(1); }

/* Touch devices never fire :hover, so phone visitors saw permanently grey
   headshots with no way to reach the colour. Meet them partway: still a
   unified set, but the faces read as photographs rather than greyscale. */
@media (hover: none) {
  .portrait img { filter: grayscale(.45) contrast(1.04) brightness(.97); }
}

/* Division plates. Three real rooms shot on three days under three lighting
   setups: measured, they run 81.3 to 97.3 mean luminance. Unlike .portrait,
   these stay in FULL COLOUR — the earlier set included a blue-lit control room
   that forced a desaturating grade to hold together, and with that gone the
   remaining three sit neutral-to-warm and cohere on their own.

   What is left is the part that still earns its place: exposure normalised
   toward a common mid so no plate reads brighter than its neighbours, and a
   shared cast so three rooms look lit by one studio. */
.plate { position: relative; background: var(--ink-800); }
.plate img {
  filter: contrast(1.04) brightness(.98) saturate(1.02);
  transition: transform .7s var(--ease), filter .6s var(--ease);
}
/* Closing the measured exposure gap: 97.3 and 94.0 come down, 81.3 comes up. */
.plate--bright img { filter: contrast(1.04) brightness(.88) saturate(1.02); }
.plate--dark   img { filter: contrast(1.04) brightness(1.08) saturate(1.02); }

/* A shared cast, so three rooms read as lit by one studio. Lighter than
   .portrait's, because it is sitting over colour rather than greyscale. */
.plate::after {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    linear-gradient(180deg, rgba(196,43,34,.07) 0%, transparent 40%),
    linear-gradient(0deg, rgba(14,11,16,.42) 0%, transparent 55%);
}
/* Hover lifts the exposure slightly rather than restoring colour — there is no
   colour to restore now, so the card still acknowledges the pointer. */
.card:hover .plate img          { filter: contrast(1.02) brightness(1.04) saturate(1.06); }
.card:hover .plate--bright img  { filter: contrast(1.02) brightness(.94) saturate(1.06); }
.card:hover .plate--dark img    { filter: contrast(1.02) brightness(1.14) saturate(1.06); }

.card:hover .portrait::after { opacity: .35; }

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

/* Focus list — capability rows with a red tick instead of a disc, and a
   hairline between each so the group reads as a ruled index. */
.focus-list li {
  position: relative;
  padding-left: 1.5rem;
  padding-block: .55rem;
  border-bottom: 1px solid rgba(255,255,255,.07);
}
.focus-list li:last-child { border-bottom: 0; }
.focus-list li::before {
  content: '';
  position: absolute;
  left: 0; top: 1.15rem;
  width: 8px; height: 1px;
  background: var(--tw3-red);
}

/* ==========================================================================
   Development process — four sequential stages
   ========================================================================== */

/* The stages are chronological, so each carries a small mono marker: it tells a
   scanning reader this is an ordered process, not four parallel capabilities.
   Hairline rules separate the columns; nothing else is added. */
.proc { display: grid; gap: 2.5rem 0; }
@media (min-width: 768px)  { .proc { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1024px) { .proc { grid-template-columns: repeat(4, 1fr); gap: 0; } }

.proc-step { padding-right: 1.9rem; }
@media (min-width: 1024px) {
  .proc-step + .proc-step {
    padding-left: 1.9rem;
    border-left: 1px solid rgba(255,255,255,.09);
  }
}

.proc-step h3 { line-height: 1.25; margin-bottom: .65rem; }
@media (min-width: 1024px) { .proc-step h3 { min-height: 2.5em; } }

/* ==========================================================================
   Section archetypes — rhythm
   ==========================================================================
   Every section on this site used the same shape: max-w-[1600px], left
   aligned, identical padding. Twenty-one of them in a row reads as a template
   no matter how good the components are. These two archetypes break that
   pattern by changing the two things the standard section never changes —
   container width and how content meets the viewport edge.
   ========================================================================== */

/* ARCHETYPE: BLEED — the media column runs off the right edge of the viewport
   instead of stopping at the container. Needs no new asset; it just stops the
   image from sitting politely inside the same box as everything else. */
@media (min-width: 1024px) {
  .bleed-right {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.08fr);
    align-items: center;
    gap: 4.5rem;
  }
  /* Push the media exactly to the viewport's right edge. The offset is the
     container's own right gutter plus whatever margin the 1600px max-width
     leaves once the viewport is wider than that — calc(50% …) would resolve
     against the grid cell rather than the container and overshoot. */
  .bleed-right > .bleed-media {
    margin-right: calc(-1 * (max(0px, (100vw - 1600px) / 2) + 3rem));
  }

  /* Featured-Merry variant: the halves interlock instead of abutting.
     The media slides left into the old column gap and dissolves into the
     panel through an ink-coloured feather, while the title crosses the
     seam the other way. The feather doubles as a scrim, so the title
     lands on veiled swamp trees, never on open artwork — and the film's
     logo (centre-right of the resting frame) stays untouched. Desktop
     only: the stacked mobile layout has no seam to hide. */
  .bleed-right--merge { gap: 0; }
  .bleed-right--merge > .bleed-media { margin-left: -4.5rem; position: relative; }
  .bleed-right--merge > .bleed-media::before {
    content: '';
    position: absolute; inset: 0; z-index: 1; pointer-events: none;
    background: linear-gradient(90deg,
      #151118 0%, rgba(21,17,24,.85) 8%, rgba(21,17,24,.45) 15%, transparent 24%);
  }
  .bleed-right--merge > .merge-copy { position: relative; z-index: 2; }
  .bleed-right--merge .merge-title { margin-right: -5.5rem; position: relative; }

  /* Mirror image, so pages that both use a bleed don't read as the same page. */
  .bleed-left {
    display: grid;
    grid-template-columns: minmax(0, 1.08fr) minmax(0, 1fr);
    align-items: center;
    gap: 4.5rem;
  }
  .bleed-left > .bleed-media {
    margin-left: calc(-1 * (max(0px, (100vw - 1600px) / 2) + 3rem));
  }
}
.bleed-media img { width: 100%; height: 100%; object-fit: cover; }

/* ARCHETYPE: FULL BLEED — content spans the entire viewport with no container
   at all. Used for the gallery grid, where the pictures are the whole point
   and a 1600px box around them just makes them smaller. */
.bleed-full {
  width: 100vw;
  margin-left: calc(50% - 50vw);
  margin-right: calc(50% - 50vw);
}

/* Offices. Ruled rows in the same register as .detail-row, not cards — the
   old Wix layout was two grey office cards and the owner called it out. The
   first block carries no top rule because the section heading already sits
   above it. */
.office-block { padding-block: 2.1rem; border-top: 1px solid rgba(255,255,255,.09); }
.office-block:first-child { border-top: 0; padding-top: 0; }
.office-block:last-child { border-bottom: 1px solid rgba(255,255,255,.09); }
.office-links { display: flex; flex-wrap: wrap; gap: 1.9rem; margin-top: 1.4rem; }
.office-links a {
  font-family: var(--font-mono);
  font-size: .72rem;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--silver-200);
  transition: color .25s var(--ease);
}
.office-links a:hover { color: var(--tw3-red-bright); }

/* The building photo is a vertical phone shot whose lower half is parking
   lot. The square crop with a raised focal point keeps the gold tower and
   the entrance and drops the asphalt. */
.office-photo { object-position: center 22%; }

/* The map arrives light-themed from OpenStreetMap; inverting it on the
   element keeps street labels legible while sitting it into the page's dark
   palette. The shell supplies ink behind the iframe while it loads. */
.map-shell { background: var(--ink-950); }
/* The focus ring goes on the shell, not the iframe. `filter` applies to an
   element's entire rendered output including its outline, so a ring drawn on
   .map-frame would come back inverted along with the map tiles. */
.map-shell:focus-within {
  outline: 2px solid var(--tw3-red-bright);
  outline-offset: 2px;
}
.map-frame:focus-visible { outline: none; }
.map-frame {
  display: block;
  width: 100%;
  height: clamp(320px, 42vh, 460px);
  border: 0;
  filter: grayscale(1) invert(92%) hue-rotate(180deg) contrast(.92);
}

/* Contact detail rows. The old version was a bordered .sheet panel of
   label/value pairs — the exact stock-component look this site set out to
   avoid. Un-boxed and ruled instead, matching the focus list. */
.detail-row {
  display: grid;
  grid-template-columns: 8.5rem 1fr;
  gap: 1rem;
  align-items: baseline;
  padding-block: .95rem;
  border-bottom: 1px solid rgba(255,255,255,.09);
}
.detail-row:first-child { border-top: 1px solid rgba(255,255,255,.09); }
.detail-row dt {
  font-family: var(--font-mono);
  font-size: .68rem;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--silver-600);
}
.detail-row dd { margin: 0; color: var(--silver-100); }
.detail-row a { color: var(--silver-100); transition: color .25s var(--ease); }
.detail-row a:hover { color: var(--tw3-red-bright); }

@media (max-width: 480px) {
  .detail-row { grid-template-columns: 1fr; gap: .3rem; }
}

/* Hero slide artwork. Landscape crops for wide screens, portrait crops for
   phones. A 2560x1440 still cover-cropped into a 375x812 viewport renders at
   1444x812 CSS px — on a 3x device that needs 4332px of width from a source
   that has far less vertical resolution, so it scales up and goes soft. The
   portrait files are cut from the same 4K originals at full height. */
/* Only the first slide loads with the page. The rotator waits 6s before its
   first transition, so slides 2-4 are attached after load instead — roughly
   900KB the visitor no longer waits on before seeing the hero. Readers with
   reduced motion never rotate, so they never download them at all. */
/* The class number is the slide's ORDER; the filename is its content. Slides 2
   and 4 are named rather than numbered because they were swapped in later —
   the older numbered files still exist and are still used on About, Projects
   and the Merry stills grid, so they could not simply be overwritten. A name
   that says what the picture is beats a number that no longer lines up. */
.hero-slide--1 { background-image: url('../img/hero-cloud.jpg'); }
.hero-ready .hero-slide--2 { background-image: url('../img/hero-santa.jpg'); }
.hero-ready .hero-slide--3 { background-image: url('../img/hero-amphitheatre.jpg'); }
.hero-ready .hero-slide--4 { background-image: url('../img/hero-icecream.jpg'); }
.hero-ready .hero-slide--5 { background-image: url('../img/hero-elf.jpg'); }
.hero-ready .hero-slide--6 { background-image: url('../img/hero-session.jpg'); }

@media (max-width: 767px) {
  .hero-slide--1 { background-image: url('../img/hero-cloud-portrait.jpg'); }
  .hero-ready .hero-slide--2 { background-image: url('../img/hero-santa-portrait.jpg'); }
  .hero-ready .hero-slide--3 { background-image: url('../img/hero-amphitheatre-portrait.jpg'); }
  .hero-ready .hero-slide--4 { background-image: url('../img/hero-icecream-portrait.jpg'); }
  .hero-ready .hero-slide--5 { background-image: url('../img/hero-elf-portrait.jpg'); }
  .hero-ready .hero-slide--6 { background-image: url('../img/hero-session-portrait.jpg'); }
}

/* Anchor targets sit below the fixed 80px header, so jumps land on the heading
   rather than tucking it underneath. */
:target { scroll-margin-top: 6.5rem; }

/* Menu toggle. The button already writes aria-expanded, so the icon can key off
   it in CSS with no extra JS. Previously the hamburger stayed a hamburger with
   the drawer open, leaving no visible way to close it. */
/* The menu icon itself. It was carrying a class with no rule at all on eight
   pages — only its two children were styled. flex:none stops the SVG being
   squeezed by the button's flex context on narrow screens. */
.nav-icon { display: block; flex: none; }
.nav-icon-close { display: none; }
[data-nav-toggle][aria-expanded="true"] .nav-icon-bars { display: none; }
[data-nav-toggle][aria-expanded="true"] .nav-icon-close { display: inline; }

/* Closing-CTA scrim. A named primitive rather than a Tailwind opacity utility:
   the arbitrary-opacity class this replaced was never emitted into the built
   stylesheet, so the div was fully transparent and white display type sat on an
   unmuted photograph. Flat and near-opaque on purpose — unlike .hero-scrim, no
   part of the image needs to read through here. */
.cta-scrim { position: absolute; inset: 0; background: rgba(21, 17, 24, 0.92); }

/* Studio CTA band. These used to sit on a Merry still under a 92%-opaque
   scrim: at that opacity the photograph was invisible, so the page paid a
   download for a texture nobody could see — and pointed a "contact the studio"
   panel at one particular film. Replaced with the studio's own mark, an ember
   bloom from the same family as .scene-ember, and the hazard motif. The film
   pages keep their own photography; this is for the studio-level bands. */
.cta-studio {
  position: relative;
  overflow: hidden;
  background: var(--ink-950);
  isolation: isolate;
}

/* Every closing CTA band, whether it carries the studio mark or a film still.
   Composed inline this was py-14 lg:py-16 — a third vertical scale on a site
   that needs two — so the rhythm is named once here instead. Deliberately
   tighter than a standard section: it holds an eyebrow, a line and a button. */
.cta-band { padding-block: 3.5rem; }
@media (min-width: 1024px) { .cta-band { padding-block: 4rem; } }
/* Oversized ghost mark, bleeding off the right edge so it reads as scenery
   rather than a logo someone forgot to size. This was set type — the word
   TW3 in the display face — but a 300px letter T has no curve or diagonal to
   identify it, so at ghost opacity it read as a stray rectangle sitting
   behind the headline. The real mark carries the bracket frame and the
   hazard corners, which stay recognisable cropped and at low contrast.
   Source is only 340px wide; at this opacity you read silhouette, not
   detail, so the upscale costs nothing visible. */
.cta-studio::before {
  content: '';
  position: absolute;
  top: 50%;
  right: -6%;
  transform: translateY(-50%);
  width: min(46%, 620px);
  aspect-ratio: 340 / 162;
  z-index: -1;
  background: url('../img/logo-tw3.png') no-repeat center / contain;
  opacity: .07;
  /* The mark's bracket frame has a hard left edge, which drew a vertical line
     straight through the headline — the same "border that stops dead" the
     ledger rules were rewritten away from. Dissolve that edge so the mark
     enters from the right like scenery instead of butting up against the
     copy. */
  -webkit-mask-image: linear-gradient(to right, transparent 0%, #000 46%);
          mask-image: linear-gradient(to right, transparent 0%, #000 46%);
  pointer-events: none;
  user-select: none;
}
@media (max-width: 767px) {
  /* Narrow bands leave no clear ground beside the copy; the mark would sit
     directly under the headline instead of beside it. */
  .cta-studio::before { width: 62%; right: -20%; opacity: .05; }
}
.cta-studio::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background:
    radial-gradient(115% 85% at 6% 50%, rgba(196, 43, 34, .17), transparent 60%),
    linear-gradient(to right, rgba(14, 11, 16, .85) 0%, transparent 55%);
}
@media (prefers-reduced-motion: no-preference) {
  .cta-studio::before { transition: opacity .6s var(--ease); }
  .cta-studio:hover::before { opacity: .1; }
}

/* On phones the centred scroll cue's hit box lands on top of the fourth slide
   dot (dots end 196px in; the cue spans 164-212 at 375px), so tapping that dot
   scrolled the page instead of changing slide. Park the cue in the corner
   below 480px. transform:none cancels the centring translate; the drift
   animation lives on the inner svg, so it is unaffected. */
@media (max-width: 480px) {
  .hero-scroll { left: auto; right: .75rem; transform: none; }
}

/* Keyboard focus must not land under the fixed 80px header. :target already
   has this; focusable elements did not, so tabbing to a link low on screen
   could scroll it beneath the bar. */
a:focus-visible, button:focus-visible, summary:focus-visible,
input:focus-visible, select:focus-visible, textarea:focus-visible {
  scroll-margin-top: 6.5rem;
  scroll-margin-bottom: 2rem;
}

/* Display type sets in very few words per line, so a one-word last line is a
   constant risk. Let the browser balance the rag instead. */
.display, .page-title, .lede { text-wrap: pretty; }
h1.display, h2.display { text-wrap: balance; }

/* ==========================================================================
   Print — the site is near-black with white type, which prints as a solid
   sheet of ink or, with backgrounds off, white on white. Give it a readable
   paper version: drop the furniture, invert to black on white, and expose
   link targets so a printed page is still usable.
   ========================================================================== */
@media print {
  body::after { display: none !important; }            /* film grain */
  .site-header, .mobile-nav, .hero-scroll, .hero-dot,
  .skip-link, .lb, .cta-scrim { display: none !important; }

  html, body { background: #fff !important; color: #000 !important; }
  .scene, .scene::before, .card, .sheet { background: none !important; }
  .scene::before { display: none !important; }

  .display, .page-title, h1, h2, h3, .lede, p, li, dd, dt, address {
    color: #000 !important;
  }
  .eyebrow, .text-silver-400, .text-silver-600, .text-silver-200 { color: #333 !important; }
  a { color: #000 !important; text-decoration: underline; }

  /* A printed link with no address is a dead end. */
  main a[href^="http"]::after { content: " (" attr(href) ")"; font-size: .85em; }

  .reveal { opacity: 1 !important; transform: none !important; }
  .hero-slide, .bleed-media, .portrait { filter: none !important; }
  section { padding-block: 1.5rem !important; break-inside: avoid; }
  img { max-width: 100% !important; }
}

/* Form errors. The native validation bubble is white, rounded, system-font and
   carries a stock warning icon — the one visual element on this site that came
   from nobody's design, appearing at the worst moment: a distributor mistyping
   an email. Same reasoning as color-scheme: dark for the select popup. */
.field[aria-invalid="true"] {
  border-color: var(--tw3-red-bright);
  background: rgba(196, 43, 34, .07);
}
.field[aria-invalid="true"]:focus-visible {
  outline-color: var(--tw3-red-bright);
}
.field-error {
  display: block;
  margin-top: .5rem;
  font-family: var(--font-mono);
  font-size: .68rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--tw3-red-bright);
}
.field-error[hidden] { display: none; }

/* The status line is a role=status live region, so it must stay rendered from
   page load — display:none regions announce unreliably when first unhidden.
   Empty, it collapses to zero height instead; :empty gives this the
   specificity to beat the utility border/padding classes on the element. */
[data-form-status]:empty { border: 0; padding: 0; margin: 0; }

/* Carousel pause. WCAG 2.2.2 (Level A) requires an in-content way to stop
   motion that starts automatically and lasts more than five seconds;
   prefers-reduced-motion does not satisfy it. */
.hero-pause {
  width: 34px; height: 34px;
  display: inline-flex; align-items: center; justify-content: center;
  background: none; border: 0; padding: 0; cursor: pointer;
  color: rgba(255,255,255,.6);
  transition: color .25s var(--ease);
  /* Sits slightly apart from the run of dots so it reads as a control rather
     than a fifth slide. Set here because ml-2 is not in the built Tailwind. */
  margin-left: .5rem;
  position: relative;
}
/* 34px visual, 46px thumb target — same trick the dots use */
.hero-pause::before { content: ''; position: absolute; inset: -6px; }
.hero-pause:hover { color: #fff; }
.hero-pause .icon-play { display: none; }
.hero-pause[aria-pressed="true"] .icon-pause { display: none; }
.hero-pause[aria-pressed="true"] .icon-play { display: block; }

/* Same control, video edition — WCAG 2.2.2 for the two looping ambient clips
   (film-page hero, projects featured card). Anchors to the nearest relative
   container; the scrim over each video eats pointer events, so this sits
   above it. Square, like everything else on this site. */
.clip-pause {
  position: absolute; right: 1.25rem; bottom: 1.25rem; z-index: 5;
  width: 34px; height: 34px;
  display: inline-flex; align-items: center; justify-content: center;
  background: rgba(14,11,16,.55); border: 1px solid rgba(255,255,255,.18);
  padding: 0; cursor: pointer;
  color: rgba(255,255,255,.75);
  transition: color .25s var(--ease), border-color .25s var(--ease);
}
.clip-pause::before { content: ''; position: absolute; inset: -6px; }
.clip-pause:hover { color: #fff; border-color: rgba(255,255,255,.4); }
.clip-pause .icon-play { display: none; }
.clip-pause[aria-pressed="true"] .icon-pause { display: none; }
.clip-pause[aria-pressed="true"] .icon-play { display: block; }
/* Stop the progress bar filling toward a slide change that is not coming. */
.is-paused .hero-dot.is-active::after { animation-play-state: paused; }

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

.reveal {
  opacity: 0;
  transform: translateY(22px);
  transition: opacity .7s var(--ease), transform .7s var(--ease);
}
.reveal.is-visible { opacity: 1; transform: none; }

/* ==========================================================================
   Forms
   ========================================================================== */

.field {
  width: 100%;
  background: var(--ink-700);
  border: 1px solid var(--line);
  color: var(--silver-100);
  padding: .95rem 1.1rem;
  min-height: 48px;
  font-family: var(--font-body); font-size: 1rem;
  transition: border-color .25s var(--ease), background-color .25s var(--ease);
}
.field::placeholder { color: var(--silver-600); }
.field:focus { border-color: var(--tw3-red); background: var(--ink-600); outline: none; }
.field:focus-visible { outline: 2px solid var(--tw3-red-bright); outline-offset: 2px; }

.field-label {
  display: block; margin-bottom: .5rem;
  font-family: var(--font-mono); font-size: .7rem;
  letter-spacing: .16em; text-transform: uppercase;
  color: var(--silver-400);
}

/* ==========================================================================
   Accessibility — honour reduced motion everywhere
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
  }
  .hero-slide.is-active { animation: none; transform: none; }
  .reveal { opacity: 1; transform: none; }
}

/* ==========================================================================
   Accessibility hardening
   ========================================================================== */

/* Closed drawer must leave the tab order — opacity/pointer-events alone don't.
   visibility flips instantly on open, and waits for the fade on close. */
.mobile-nav { visibility: hidden; transition: opacity .3s var(--ease), visibility .3s var(--ease); }
.mobile-nav.is-open { visibility: visible; }

/* The slate card's clip-path clips an offset outline entirely — draw the
   keyboard focus ring INSIDE the card instead. */
a.card:focus-visible {
  outline: 2px solid var(--tw3-red-bright);
  outline-offset: -4px;
}

/* ==========================================================================
   Creative details — filmic dressing around the content, never replacing it
   ========================================================================== */

/* Film-frame figure: sprocket-hole strips + slate caption bar */
.film-frame {
  background: var(--ink-950);
  padding: 14px 22px 0;
}
.film-frame { position: relative; }
.film-frame::before,
.film-frame::after {
  content: ''; position: absolute; top: 0; bottom: 0; width: 22px;
  background-image: radial-gradient(circle, rgba(255,255,255,.16) 2.6px, transparent 3.2px);
  background-size: 22px 18px;
  background-position: center 4px;
}
.film-frame::before { left: 0; }
.film-frame::after  { right: 0; }
.film-frame-caption {
  display: flex; align-items: center; justify-content: space-between;
  gap: 1rem; flex-wrap: wrap;
  padding: .85rem .1rem;
}

/* Film-leader countdown — the 404 signature. Crosshairs run past the circle
   like an academy leader; the red sweep rotates (frozen by reduced-motion). */
.leader {
  position: relative;
  display: inline-grid; place-items: center;
  width: clamp(180px, 26vw, 250px); aspect-ratio: 1;
  border: 1px solid var(--line-strong); border-radius: 50%;
}
.leader::before, .leader::after {
  content: ''; position: absolute; background: rgba(255,255,255,.14);
}
.leader::before { left: 50%; top: -14%; bottom: -14%; width: 1px; }
.leader::after  { top: 50%; left: -14%; right: -14%; height: 1px; }
.leader-sweep {
  position: absolute; inset: 0; border-radius: 50%;
  background: conic-gradient(rgba(196,43,34,.30) 0 32deg, transparent 32deg);
  animation: leader-spin 6s linear infinite;
}
.leader-num { position: relative; z-index: 1; font-size: clamp(3rem, 7vw, 4.5rem); }
@keyframes leader-spin { to { transform: rotate(360deg); } }

/* The second ground channel. Declared once for every new section class so the
   individual rules below only ever have to supply `background`. */

/* ==========================================================================
   2. THE LEDGER BAND — about.html, "Development Activities"
   ==========================================================================
   Six designs were rejected here: photographs, a same-frame breakdown, SVG
   diagrams, outlined numerals. Nothing is added to, removed from or drawn over
   the four text items. What changes is what they are standing on.

   The columns become a ruled ledger: stock under them, a rule closing the band
   top and bottom, and a 2px red index tick opening each column. The tick is
   .focus-list li::before's exact vocabulary — a measure mark, not a numeral
   and not a symbol, so there is nothing to decode. The column hairlines were
   already there; they simply gain the height to become ledger rules.
   ========================================================================== */

/* The band. Padding-block is the only box-model change in this whole file: the
   closing rules need somewhere to sit, and four items in a band need air or
   the band is a table. */
.proc.ledger { position: relative; padding-block: 1.9rem; }
@media (min-width: 1024px) { .proc.ledger { padding-block: 2.6rem; } }

/* Closed with rules that FADE OUT at both ends rather than borders that stop
   dead. A hard border top and bottom would box the group, which is the stock
   -component look this section was rewritten away from once already. The FADE
   is what keeps them from boxing the group, so they can stay at --rule-ink and
   still read as structure rather than as a table edge — the ruled stock behind
   them sits at .038, well below, so the two never compete. Absolutely
   positioned so they are never grid items and never create a track. */
.proc.ledger::before,
.proc.ledger::after {
  content: '';
  position: absolute;
  left: 0; right: 0;
  height: 1px;
  pointer-events: none;
  background: linear-gradient(to right,
    transparent, var(--rule-ink) 6%, var(--rule-ink) 88%, transparent);
}
.proc.ledger::before { top: 0; }
.proc.ledger::after  { bottom: 0; }

/* The staff row went from four to five. lg:grid-cols-5 does not exist in the
   prebuilt tailwind.css — an unbuilt utility silently does nothing — so the
   five-track rule lives here. Five across keeps one clean row; four would
   leave a single orphan card on a second row. */
@media (min-width: 1024px) {
  /* div.team-grid, not .team-grid: the element also carries Tailwind's
     grid-cols-2 for the phone layout, which ties on specificity and wins on
     source order because tailwind.css loads after this file. Both the staff
     row and the affiliates row use it, so a partner card is exactly as wide
     as a staff card instead of a third wider. */
  div.team-grid { grid-template-columns: repeat(5, minmax(0, 1fr)); }
}

/* Two separate alignment problems in these rows.
   1. items-start let every card size to its own content, so a card whose role
      wrapped to three lines at one width and two at another made the row
      ragged. The class is gone from the markup; grid's default stretch now
      squares the card BOXES at every width.
   2. Equal boxes do not align what is inside them — Read Bio sat wherever the
      role text happened to end, and the roles wrap to one, two or three lines
      depending on card width. Rather than guess a min-height per breakpoint,
      pin Read Bio to the bottom of the card: it then lines up across a row at
      every width, and the slack collects above it where it reads as air. */
.team-grid .card { display: flex; flex-direction: column; }
.team-grid .card > div:last-child { flex: 1; display: flex; flex-direction: column; }
.team-grid .card details.bio { margin-top: auto; padding-top: .5rem; }

/* Development slate as a horizontal rail. Four titles sit in the row and the
   fifth is reached by sliding, rather than wrapping to a second line where a
   lone card sits by itself. Scroll-snap rather than a JS carousel: native
   momentum, real keyboard scrolling, and nothing to break. Track width is
   sized so four fill the row and a slice of the fifth stays visible at the
   right edge. That peek is the affordance: a rail that ends flush at the
   container edge looks like a finished grid and nobody thinks to slide it. */
.slate-rail {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 78%;
  gap: 1.5rem;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
  padding-bottom: .75rem;
  scrollbar-width: thin;
  scrollbar-color: rgba(255,255,255,.18) transparent;
}
.slate-rail > * { scroll-snap-align: start; }
@media (min-width: 640px)  { .slate-rail { grid-auto-columns: 43%; } }
@media (min-width: 1024px) { .slate-rail { grid-auto-columns: calc((100% - 4.5rem) / 4.25); } }
.slate-rail::-webkit-scrollbar { height: 6px; }

/* Rail arrows: two adjoining squares sharing a border, same family as the
   pause controls. Disabled = you're at that end of the rail. */
.rail-arrow {
  width: 40px; height: 40px;
  display: inline-flex; align-items: center; justify-content: center;
  background: none; border: 1px solid rgba(255,255,255,.18);
  padding: 0; cursor: pointer;
  color: rgba(255,255,255,.75);
  transition: color .25s var(--ease), border-color .25s var(--ease);
}
.rail-arrow + .rail-arrow { margin-left: -1px; }
.rail-arrow:hover:not(:disabled) { color: #fff; border-color: rgba(255,255,255,.4); }
.rail-arrow:disabled { color: rgba(255,255,255,.25); cursor: default; }
.slate-rail::-webkit-scrollbar-track { background: transparent; }
.slate-rail::-webkit-scrollbar-thumb {
  background: rgba(255,255,255,.16);
  border-radius: 3px;
}
.slate-rail:focus-visible {
  outline: 2px solid var(--tw3-red-bright);
  outline-offset: 4px;
}

/* A card whose art is not 16:9. Rather than crop a portrait one-sheet down to
   a letterbox — which would cut its own title off — the painting is contained
   and a blurred, darkened copy fills the frame behind it. Reads as deliberate
   instead of as a mismatched asset. */
.art-fit { position: relative; background: var(--ink-800); }
.art-fit::before {
  content: '';
  position: absolute; inset: -10%;
  background: var(--art) center / cover no-repeat;
  filter: blur(20px) brightness(.42) saturate(.75);
}
.art-fit img {
  position: relative;
  width: 100%; height: 100%;
  object-fit: contain;
}

/* Released-title size lives here, NOT as an arbitrary Tailwind utility. The
   first attempt used text-[clamp(1.4rem,2.4vw,2.1rem)], which is not in the
   prebuilt tailwind.css and therefore did nothing at all — the heading fell
   back to a 16px browser default and rendered SMALLER than the paragraph
   under it. Third time this build has bitten; a named rule cannot silently
   fail. Sits between the section heading (25.6px) and the featured film
   (41.6px), so a delivered legacy title reads as real without competing with
   the flagship. */
.released-title { font-size: clamp(1.5rem, 2.3vw, 2rem); }

/* "Next in development" — a title with no publishable artwork yet. Deliberately
   a rule-and-arrow line rather than a fifth card: the row above is four equal
   cards, and a fifth carrying a soft 303px scan would read as the weak one.
   The arrow does the work a picture would: it points forward. */
.next-up {
  display: flex;
  align-items: center;
  gap: 1.1rem;
  flex-wrap: wrap;
}
.next-up .eyebrow { flex: none; }
.next-up-arrow {
  flex: none;
  display: inline-flex;
  color: var(--tw3-red-bright);
  transition: transform .4s var(--ease);
}
.next-up-title {
  font-size: clamp(1.15rem, 2vw, 1.6rem);
  color: var(--silver-100);
}
@media (hover: hover) {
  .next-up:hover .next-up-arrow { transform: translateX(6px); }
}
@media (prefers-reduced-motion: reduce) {
  .next-up-arrow { transition: none; }
  .next-up:hover .next-up-arrow { transform: none; }
}

/* No index tick above the headings. It was the only VERTICAL red mark on the
   site — every other one is a short horizontal dash sitting on its own line of
   text — and floating above a heading, attached to nothing, it read as a stray
   artefact rather than a marker. The fading top/bottom rules and the hairline
   column dividers already say "ordered group". */

/* ==========================================================================
   3. RULED INDEXES — about.html focus list, contact.html detail rows + list
   ==========================================================================
   Both lists were hard 1px hairlines running the full width, which is what
   makes a list look like a table with the borders left on. The rule now fades
   as it runs right, so the group reads as ruled rather than boxed. This is the
   whole treatment: no spine, no head rule, no second red element. The red tick
   already on each row is the only mark either list needs.
   ========================================================================== */

.focus-list li { border-bottom: 0; }
.focus-list li::after {
  content: '';
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 1px;
  pointer-events: none;
  background: linear-gradient(to right,
    rgba(255,255,255,.15), rgba(255,255,255,.045) 62%, transparent);
}
.focus-list li:last-child::after { display: none; }

/* Same hand rules both columns of contact.html. .detail-row is a grid with no
   position of its own, so it gets one here. */
.detail-row { position: relative; border-bottom: 0; }
.detail-row::after {
  content: '';
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 1px;
  pointer-events: none;
  background: linear-gradient(to right,
    rgba(255,255,255,.15), rgba(255,255,255,.045) 62%, transparent);
}
.detail-row:first-child { border-top: 0; }
.detail-row:first-child::before {
  content: '';
  position: absolute;
  left: 0; right: 0; top: 0;
  height: 1px;
  pointer-events: none;
  background: linear-gradient(to right,
    rgba(255,255,255,.15), rgba(255,255,255,.045) 62%, transparent);
}

/* ==========================================================================
   4. THE HOLD FRAME — projects/merry.html, "First look"
   ==========================================================================
   881px of bordered nothing, holding 131 characters, on the page for the
   studio's flagship film. It is now what an empty frame actually looks like in
   a camera department: a groundglass in a gate with the lamp up and no picture
   in it. Perforated film runs down both inside edges (the .film-frame sprocket
   again, at frame scale), rule-of-thirds guides and safe-action / safe-title
   rectangles cross the field, corner crop marks sit on the frame, and a
   stopped burn-in reads TCR 00:00:00:00 — because there is no picture yet.

   The copy is untouched and now reads as the title card threaded into the
   machine rather than a caption floating in an empty box. An earlier pass ran
   a full-width footage ruler along the bottom edge; rendered, it was the
   loudest object in the frame and read as a video-editor timeline. Cut.
   ========================================================================== */

div.hold-frame {
  position: relative;
  isolation: isolate;                 /* keeps the caption's scrim inside */
  overflow: hidden;
  /* Owned here, not by aspect-video: that utility loads after this file, and
     the ratio has to open up on phones or the caption meets the overflow. */
  aspect-ratio: 16 / 9;
  background-color: var(--ink-950);
  background-image:
    /* rule-of-thirds framing guides */
    repeating-linear-gradient(to right,  rgba(255,255,255,.055) 0 1px, transparent 1px 33.3333%),
    repeating-linear-gradient(to bottom, rgba(255,255,255,.055) 0 1px, transparent 1px 33.3333%),
    /* the lamp, up behind the gate with nothing in it. Everything else on this
       site is lit from somewhere; a frame of pure line-work would read as a
       HUD overlay rather than as a groundglass. */
    radial-gradient(58% 80% at 50% 46%, rgba(196,43,34,.15), transparent 68%),
    radial-gradient(74% 88% at 50% 44%, rgba(255,238,214,.055), transparent 70%),
    /* lens falloff — nothing a camera makes is evenly lit to its corners */
    radial-gradient(120% 120% at 50% 46%, transparent 40%, rgba(0,0,0,.5));
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.10);
}
@media (max-width: 640px) { div.hold-frame { aspect-ratio: 4 / 3; } }

/* The film in the gate. Same perforation as .film-frame and as the projects
   head rail — one material, three scales, which is a design language; a shared
   STRUCTURE is what made the four heads a template. */
div.hold-frame::before,
div.hold-frame::after {
  content: '';
  position: absolute;
  top: 0; bottom: 0;
  width: 22px;
  pointer-events: none;
  background-color: rgba(0,0,0,.5);
  background-image: var(--sprocket);
  background-size: 22px 18px;
  box-shadow: inset 1px 0 0 rgba(255,255,255,.05),
              inset -1px 0 0 rgba(255,255,255,.05);
}
div.hold-frame::before { left: 0; }
div.hold-frame::after  { right: 0; }
@media (max-width: 767px) {
  div.hold-frame::before,
  div.hold-frame::after { width: 15px; }
}

/* Corner crop marks: eight 1px bars, edge-anchored, one element. */
.hold-marks {
  --brk: linear-gradient(rgba(255,255,255,.3), rgba(255,255,255,.3));
  position: absolute;
  inset: 0;
  pointer-events: none;
  background-image: var(--brk), var(--brk), var(--brk), var(--brk),
                    var(--brk), var(--brk), var(--brk), var(--brk);
  background-size: 22px 1px, 1px 22px, 22px 1px, 1px 22px,
                   22px 1px, 1px 22px, 22px 1px, 1px 22px;
  background-position:
    left 34px top 14px,     left 34px top 14px,
    right 34px top 14px,    right 34px top 14px,
    left 34px bottom 14px,  left 34px bottom 14px,
    right 34px bottom 14px, right 34px bottom 14px;
  background-repeat: no-repeat;
}

/* Safe action and safe title, at true percentage insets so they stay real
   ratios of the frame at any width. z-index:-1 is load-bearing: it drops them
   into .hold-frame's negative layer, where the caption's scrim — also at -1
   but later in tree order — paints OVER them. Without it the safe-title line
   crosses in FRONT of the words "TRAILER IN THE WORKS". */
.hold-marks::before,
.hold-marks::after {
  content: '';
  position: absolute;
  z-index: -1;
  pointer-events: none;
}
.hold-marks::before { inset: 5.2%;  border: 1px solid rgba(255,255,255,.07); }
.hold-marks::after  { inset: 10.5%; border: 1px solid rgba(255,255,255,.045); }

/* Stopped timecode. Generated content on an aria-hidden element, so it never
   reaches the accessibility tree and no copy changes in the document. Same
   register as the TCR burn-in on the studio's own dub-stage photograph. */
.hold-tcr {
  position: absolute;
  /* Inside safe action (5.2%) and clear of the bottom-right crop mark, which is
     where a real window burn sits. */
  right: 2.6rem;
  bottom: 2.4rem;
  pointer-events: none;
}
.hold-tcr::after {
  content: 'TCR 00:00:00:00';
  font-family: var(--font-mono);
  font-size: .62rem;
  font-weight: 500;
  letter-spacing: .18em;
  color: rgba(130,135,143,.85);
}
/* On a phone the frame is ~327px wide and the caption fills it; the burn-in
   would land on the last line of copy. A burn-in is a big-frame detail. */
@media (max-width: 767px) { .hold-tcr { display: none; } }

/* The lamp housing — the one thing in the frame catching the light. Halation,
   light blooming sideways through emulsion, is why the glow spills past the
   box instead of stopping at its edge. */
.hold-lamp {
  /* mx-auto / w-16 / h-16 were removed from the markup, so the housing owns
     its own box here rather than depending on utilities that load later. */
  width: 4rem; height: 4rem; margin-inline: auto;
  position: relative;
  border: 1px solid rgba(255,236,214,.28);
  background: rgba(14,11,16,.5);
  box-shadow: inset 0 0 22px -6px rgba(255,226,196,.34);
}
.hold-lamp::before {
  content: '';
  position: absolute;
  inset: -28px;
  z-index: -1;
  border-radius: 50%;
  pointer-events: none;
  background: radial-gradient(circle, rgba(242,84,74,.17), transparent 66%);
}

/* The copy keeps a quiet pocket of ink so no guide runs through a letterform. */
.hold-caption { position: relative; max-width: 34rem; }
.hold-caption::before {
  content: '';
  position: absolute;
  inset: -2.25rem -2.75rem;
  z-index: -1;
  pointer-events: none;
  background: radial-gradient(ellipse closest-side at 50% 50%,
    rgba(14,11,16,.9) 0 34%, rgba(14,11,16,.66) 58%, rgba(14,11,16,0) 100%);
}

/* ==========================================================================
   5. THE SUBMISSION SHEET — contact.html, form + sidebar
   ==========================================================================
   A form is the one place on this site where drawing on top of the content
   costs the studio a distributor's enquiry, so nothing is drawn on it. An
   earlier pass laid a 96px measure grid behind this section; rendered, it was
   the same graph-paper tell that was cut from the gallery head. Replaced with
   light: a warm practical low and left the way a desk lamp falls, a cold fill
   returning from the top right.
   ========================================================================== */

/* The sheet's head rule, with the studio's red index segment on it. */
.form-sheet {
  position: relative;
  border-top: 1px solid var(--rule-ink);
  padding-top: 2.25rem;
}
.form-sheet::before {
  content: '';
  position: absolute;
  top: -1px; left: 0;
  width: 3.5rem; height: 2px;
  background: var(--tw3-red);
}

/* Every label opens with the same 8px red measure tick the ledger and the
   focus list use. Set with padding + an absolute tick, NOT display:flex: the
   Company label carries an inline <span>(optional)</span>, and a flex context
   would promote that span to a flex item and blow the word space out from
   ~4px to the gap value. */
.form-sheet .field-label {
  position: relative;
  padding-left: 1.1rem;
}
.form-sheet .field-label::before {
  content: '';
  position: absolute;
  left: 0; top: .55em;
  width: 8px; height: 1px;
  background: rgba(196,43,34,.7);
}

/* Ruled entries. The box stays for affordance, but three sides drop back and
   the baseline carries the weight — a writing line, not a box. Deliberately
   sets NO background: .field[aria-invalid="true"] uses the `background`
   SHORTHAND, which would wipe any background-image set here the moment the
   field errors. Depth comes from box-shadow, which nothing else touches. */
.field {
  border-color: rgba(255,255,255,.07);
  border-bottom-color: rgba(255,255,255,.22);
  box-shadow: inset 0 1px 0 rgba(0,0,0,.3), inset 0 -1px 0 rgba(255,255,255,.04);
}

/* Focus is lit rather than merely re-bordered — the same light-through
   -emulsion bloom as the gate lamp, and a far clearer affordance than a 1px
   colour change. NOTE THE ABSENT `outline`: site.css deliberately orders
   `.field:focus { outline: none }` BEFORE `.field:focus-visible { outline: 2px
   solid var(--tw3-red-bright) }` at identical specificity, so the keyboard
   ring survives only on source order. A second `.field:focus { outline: none }`
   appended here would land after that restore and silently strip the focus
   ring from all six fields on the studio's only conversion path. Do not add
   one. */
.field:focus {
  border-color: var(--tw3-red);
  border-bottom-color: var(--tw3-red);
  box-shadow: inset 0 1px 0 rgba(0,0,0,.28), 0 0 30px -8px rgba(242,84,74,.75);
}

/* One line, and the buttons stop being the only unlit objects on a page full
   of lit ones. Site-wide; .btn already transitions nothing that fights it. */
.btn-primary { transition: background-color .25s var(--ease), color .25s var(--ease),
                           border-color .25s var(--ease), transform .25s var(--ease),
                           box-shadow .3s var(--ease); }
.btn-primary:hover { box-shadow: 0 0 30px -8px rgba(242,84,74,.7); }

/* ==========================================================================
   6. SPEC STRIPS — merry.html fact bar, index.html partner strip
   ==========================================================================
   The two thinnest bands on the site, both a single row of type. They get the
   archive's two smallest marks and no new structure at all.
   ========================================================================== */

/* Each field of the fact bar opens with the ledger's red index tick, so the
   film's spec strip and the studio's development ledger read as sheets from
   one drawer. Offset at lg to match divide-x's lg:px-10, for the same reason
   the ledger tick is offset: the mark belongs on the text edge, not the rule. */
.spec-bar > div { position: relative; }
.spec-bar > div::before {
  content: '';
  position: absolute;
  top: 0; left: 0;
  width: 2px; height: 12px;
  background: var(--tw3-red);
}
@media (min-width: 1024px) {
  .spec-bar > div:not(:first-child)::before { left: 2.5rem; }
}

/* A footage ruler along the top edge of the homepage's closing band. Held to
   the left 30% and dropped to .16/.09: a full-width run of bright ticks reads
   as an editing timeline, a short one reads as a measure mark on a sheet.
   Painted on ::after so scene-raised's edge-light is untouched. */
section.strip-measure::after {
  content: '';
  position: absolute;
  left: 0; right: 0; top: 0;
  height: 11px;
  z-index: -1;
  pointer-events: none;
  background-image:
    repeating-linear-gradient(to right, rgba(255,255,255,.16) 0 1px, transparent 1px 60px),
    repeating-linear-gradient(to right, rgba(255,255,255,.09) 0 1px, transparent 1px 12px);
  background-size: 30% 11px, 30% 6px;
  background-position: left top, left top;
  background-repeat: no-repeat, no-repeat;
}

/* ==========================================================================
   7. MOTION
   ==========================================================================
   One ambient animation on the entire site, and it is opacity on a single
   28px-inset radial. gallery.html — the image-heaviest page — gets none, on
   purpose. A page head that moves is a page head that looks like a template
   with a plugin on it.

   The keyframe is declared INSIDE prefers-reduced-motion: no-preference rather
   than leaning on the global `animation-duration: .001ms !important` reset at
   the top of this file. That reset reverts an element to its SPECIFIED values,
   which is only the correct resting state by luck; scoping the declaration
   means a reduced-motion reader gets a correct still frame, not a frozen one.
   ========================================================================== */

@keyframes lamp-breathe { 0%, 100% { opacity: .74; } 50% { opacity: 1; } }

@media (prefers-reduced-motion: no-preference) {
  .hold-lamp::before { animation: lamp-breathe 6.5s ease-in-out infinite; }
}

@media (prefers-reduced-motion: reduce) {
  .btn-primary, .field { transition: none; }
}

/* ==========================================================================
   8. PRINT
   ==========================================================================
   The archive is line-work and light on a near-black ground; on paper it is
   noise. Kill the furniture — and give back real borders for the rules that
   are now drawn as backgrounds, because print drops backgrounds and a printed
   enquiry list must still be a list.
   ========================================================================== */
@media print {
  div.hold-frame, div.hold-frame::before, div.hold-frame::after,
  .hold-lamp, .field {
    background: none !important;
    box-shadow: none !important;
  }
  .form-sheet { border-color: #999 !important; }
  .focus-list li, .detail-row { border-bottom: 1px solid #bbb !important; }
  .focus-list li:last-child { border-bottom: 0 !important; }
  .detail-row:first-child { border-top: 1px solid #bbb !important; }
}

/* ==========================================================================
   PAGE HEAD
   ==========================================================================
   The eyebrow label that sat above each h1 ("The Slate", "Imagery", "Key
   People & Affiliates") is gone, and so are the four decorative head grounds.
   With the label removed the title is the first thing in the block, so the
   old padding left it stranded — this tightens the whole head and unifies
   five pages that were each using a slightly different pair of utilities
   (pb-14/lg:pb-20 vs pb-16).

   Owned here rather than composed from utilities because the pre-built
   tailwind.css has no pt-28 / pb-10 / pb-12 to tighten to — only pt-32 and
   lg:pt-40 — so a utility version could not have moved at all. Top padding
   still clears the 5rem fixed header with room to spare. */
.page-head {
  padding-top: 7.25rem;
  padding-bottom: 2.75rem;
}
@media (min-width: 1024px) {
  .page-head {
    padding-top: 9rem;
    padding-bottom: 3.75rem;
  }
}
