/* =========================================================================
   STARSCAPE GROUP — homepage
   Static-first, progressively enhanced. Complete and attractive with
   JavaScript and animation disabled. Selectors scoped to html.js only apply
   once main.js has actually run (see the inline no-js/js swap in <head>);
   html.no-js keeps the equivalent content reachable without it.
   ========================================================================= */

/* ---------- Design tokens ---------- */
:root {
  --paper:       #E9E2D6;   /* mineral light background            */
  --paper-2:     #E2DACC;   /* alt / card                          */
  --paper-line:  rgba(23,18,14,.14);
  --ink:         #17120E;   /* near-black warm                     */
  --ink-2:       #12100D;   /* dark band background                */
  --ink-3:       #0C0A08;   /* deepest                             */
  --cream:       #EDE7DE;   /* text on dark                        */
  --copper:      #A03F17;   /* primary accent (AA on light paper)  */
  --copper-2:    #B4531F;   /* brighter accent                     */
  --copper-lt:   #DB8A57;   /* small copper text on dark (AA)      */
  --rust:        #7E3410;   /* joint-venture band                  */
  --rust-2:      #6E2C0D;

  --muted-d:     rgba(23,18,14,.68);   /* muted on light (AA)      */
  --muted-l:     rgba(237,231,222,.62);/* muted on dark            */
  --hair-l:      rgba(237,231,222,.14);

  --serif:  'Instrument Serif', Georgia, 'Times New Roman', serif;
  --grotesk:'Archivo', system-ui, -apple-system, 'Segoe UI', sans-serif;
  --mono:   'JetBrains Mono', ui-monospace, 'SFMono-Regular', Menlo, monospace;

  --gutter: clamp(20px, 4.4vw, 64px);
  --maxw:   1400px;
  --header-h: 74px;
  /* Width of the right-hand lane the fixed section rail occupies. 0 when the
     rail is hidden, so sections that reserve clearance do it with one
     expression instead of duplicating the rail's breakpoints. */
  --rail-lane: 0px;

  --ease: cubic-bezier(.16, 1, .3, 1);
}

/* ---------- Reset / base ---------- */
*, *::before, *::after { box-sizing: border-box; }
html {
  scroll-behavior: smooth;
  -webkit-text-size-adjust: 100%;
  /* Fixed header must never cover the heading an anchor jumps to. */
  scroll-padding-top: calc(var(--header-h) + 16px);
}
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--grotesk);
  font-size: 16px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

h1, h2, h3, p, ul, ol, figure { margin: 0; }
ul, ol { padding: 0; list-style: none; }
img, svg { display: block; max-width: 100%; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; cursor: pointer; }
em { font-style: italic; }

section[id] { scroll-margin-top: calc(var(--header-h) + 16px); }

::selection { background: var(--copper); color: var(--cream); }

/* ---------- Accessibility helpers ---------- */
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.skip-link {
  position: fixed; top: 8px; left: 8px; z-index: 200;
  background: var(--ink); color: var(--cream);
  padding: 10px 16px; border-radius: 4px;
  font-family: var(--mono); font-size: 12px; letter-spacing: .08em;
  transform: translateY(-160%); transition: transform .2s var(--ease);
}
.skip-link:focus { transform: translateY(0); }

:focus-visible {
  outline: 2px solid var(--copper-2);
  outline-offset: 3px;
  border-radius: 2px;
}
/* On dark backgrounds, brighten the focus ring */
.showcase :focus-visible,
.venture :focus-visible,
.site-footer :focus-visible,
.section-rail :focus-visible,
.site-header :focus-visible { outline-color: #E6A06E; }

/* External-link affordance (real off-site destinations only) */
.ext-ic { font-size: .78em; margin-left: 3px; opacity: .7; }
.link-arrow--ext { }

/* ---------- Shared typography ---------- */
.eyebrow {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: rgba(23,18,14,.72);
  margin: 0;
}
.eyebrow--copper { color: var(--copper); }

.section-title {
  font-family: var(--serif);
  font-weight: 400;
  font-size: clamp(2.1rem, 3.6vw, 3.5rem);
  line-height: 1.02;
  letter-spacing: -.028em;
}
.section-title em { color: rgba(23,18,14,.5); }
.section-lead {
  max-width: 34ch;
  font-size: 15px;
  line-height: 1.7;
  color: var(--muted-d);
  text-wrap: pretty;
}

/* ---------- Buttons ---------- */
.btn {
  display: inline-flex; align-items: center; gap: 22px;
  font-family: var(--mono); font-size: 10px; letter-spacing: .18em;
  text-transform: uppercase; white-space: nowrap;
  padding: 15px 20px; border-radius: 2px;
  border: 1px solid transparent;
  transition: background .3s var(--ease), color .3s var(--ease), border-color .3s var(--ease);
}
.btn--lg { padding: 20px 26px; gap: 30px; font-size: 10.5px; }
.btn--copper { background: var(--copper); color: var(--cream); }
.btn--copper:hover, .btn--copper:focus-visible { background: var(--ink); color: var(--cream); }
.btn--cream { background: var(--cream); color: var(--ink); }
.btn--cream:hover, .btn--cream:focus-visible { background: var(--ink); color: var(--cream); }
.btn--underline {
  padding: 15px 4px; border-bottom: 1px solid var(--paper-line); color: var(--muted-d);
  border-radius: 0;
}
.btn--underline:hover, .btn--underline:focus-visible { color: var(--ink); border-bottom-color: var(--ink); }
.btn--underline-cream {
  padding: 15px 4px; border-bottom: 1px solid var(--hair-l); color: var(--muted-l); border-radius: 0;
}
.btn--underline-cream:hover, .btn--underline-cream:focus-visible { color: var(--cream); border-bottom-color: var(--cream); }

.link-arrow {
  display: inline-flex; align-items: center; gap: 10px;
  font-family: var(--mono); font-size: 10px; letter-spacing: .16em;
  text-transform: uppercase; color: var(--ink);
  padding-bottom: 5px; border-bottom: 1px solid currentColor; width: max-content;
  transition: gap .3s var(--ease), color .3s var(--ease);
}
.link-arrow:hover, .link-arrow:focus-visible { gap: 16px; color: var(--copper); }

/* =========================================================================
   SCROLL PROGRESS
   ========================================================================= */
.scroll-progress {
  position: fixed; top: 0; left: 0; right: 0; height: 2px; z-index: 120;
  background: rgba(23,18,14,.10);
}
.scroll-progress__bar {
  display: block; height: 100%; width: 0;
  background: var(--copper); transition: width .1s linear;
}

/* =========================================================================
   HEADER
   ========================================================================= */
.site-header {
  position: fixed; top: 0; left: 0; right: 0; z-index: 100;
  height: var(--header-h);
  display: flex; align-items: center; justify-content: space-between;
  gap: 24px; padding: 0 var(--gutter);
  background: rgba(233,226,214,.72);
  backdrop-filter: blur(18px) saturate(1.1);
  -webkit-backdrop-filter: blur(18px) saturate(1.1);
  border-bottom: 1px solid transparent;
  transition: background .4s var(--ease), border-color .4s var(--ease);
}
.site-header.is-scrolled {
  background: rgba(233,226,214,.85);
  border-bottom-color: var(--paper-line);
}

.brand { display: flex; align-items: center; gap: 11px; }
.brand__mark { display: grid; place-items: center; }
.brand__word { display: flex; flex-direction: column; line-height: 1; }
/* Sans-serif wordmark — matches the hero headline family, one identity system
   with the flat/dimensional S mark (see header + hero + favicon). */
.brand__name { font-family: var(--grotesk); font-weight: 600; font-size: 21px; letter-spacing: -.01em; }
.brand__name--light { color: var(--cream); }
.brand__sub {
  font-family: var(--mono); font-size: 8px; letter-spacing: .34em;
  text-transform: uppercase; opacity: .5; margin-top: 3px;
}

.site-nav { display: flex; align-items: center; }
.nav-list {
  display: flex; align-items: center; gap: 30px;
  font-family: var(--mono); font-size: 10px; letter-spacing: .16em; text-transform: uppercase;
}
.nav-list a { color: var(--muted-d); transition: color .25s var(--ease); }
.nav-list a:hover, .nav-list a:focus-visible { color: var(--ink); }
.nav-list__cta {
  display: inline-flex; align-items: center; gap: 7px;
  color: var(--ink) !important; border: 1px solid rgba(23,18,14,.24);
  border-radius: 100px; padding: 9px 16px;
  transition: background .25s var(--ease), color .25s var(--ease), border-color .25s var(--ease);
}
.nav-list__cta:hover, .nav-list__cta:focus-visible { background: var(--ink); color: var(--cream) !important; border-color: var(--ink); }

.site-header__est {
  font-family: var(--mono); font-size: 10px; letter-spacing: .2em;
  text-transform: uppercase; color: var(--muted-d);
}

/* Hamburger only ever appears once JS has run (it drives the toggle) — a
   no-js visitor gets the nav list plainly reachable instead (see breakpoint
   rules below), never a dead button. */
.nav-toggle { display: none; }
.js .nav-toggle {
  width: 44px; height: 44px; border: 0; background: none;
  flex-direction: column; align-items: center; justify-content: center; gap: 6px;
}
.nav-toggle__bar { display: block; width: 22px; height: 2px; background: var(--ink); transition: transform .3s var(--ease), opacity .3s var(--ease); }
.nav-toggle[aria-expanded="true"] .nav-toggle__bar:nth-child(1) { transform: translateY(4px) rotate(45deg); }
.nav-toggle[aria-expanded="true"] .nav-toggle__bar:nth-child(2) { transform: translateY(-4px) rotate(-45deg); }

/* =========================================================================
   SECTION RAIL
   ========================================================================= */
/* One component, two sizes. Every dimension is a custom property, so the full
   and compact states are value swaps rather than a duplicated component.
   Sizes are set explicitly rather than via `transform: scale()` — a scaled
   rail would blur 9px mono type and shrink the click targets. */
.section-rail {
  --rail-right: 20px;
  --rail-gap: 36px;          /* marker pitch, centre to centre */
  --rail-num: 9px;
  --rail-line: 22px;
  --rail-line-active: 48px;
  --rail-num-w: 16px;        /* fixed, so the numbers form a true column */
  --rail-label-w: 84px;      /* fits TRANSACTIONS uncropped at --rail-num */
  --rail-max-h: 58vh;
  display: none;             /* the two states below opt in */
  position: fixed; right: var(--rail-right); top: 50%; transform: translateY(-50%);
  max-height: var(--rail-max-h);
  z-index: 90;
}
/* JS layout-fit check (see main.js): pulls the rail whenever the measured
   height cannot keep 32px clear of the header and the viewport bottom. */
.section-rail.is-unfit { display: none !important; }
.section-rail { transition: opacity .45s var(--ease); }
/* The row is a fixed three-column track (number / tick / label) rather than a
   shrink-to-fit flex row. Fixed columns are what let the numbers line up and
   every tick start on the same x — which in turn gives the vertical
   connecting rail something to attach to. */
.section-rail ol {
  position: relative; display: flex; flex-direction: column;
  width: calc(var(--rail-num-w) + var(--rail-line-active) + var(--rail-label-w) + 20px);
}
/* Vertical connecting rail: spans centre-of-first-marker to
   centre-of-last, sitting exactly where every tick begins. */
.section-rail ol::before {
  content: ''; position: absolute; z-index: -1;
  left: calc(var(--rail-num-w) + 10px);
  top: calc(var(--rail-gap) / 2); height: calc(100% - var(--rail-gap));
  width: 1px; background: rgba(23,18,14,.16);
  transition: background .4s var(--ease);
}
/* Fixed row height, so --rail-gap IS the marker spacing rather than the
   leftover space between two rows of unknown height. */
.section-rail li { display: flex; align-items: center; height: var(--rail-gap); }
.section-rail a {
  display: flex; align-items: center; justify-content: flex-start; gap: 10px;
  font-family: var(--mono); font-size: var(--rail-num); letter-spacing: .18em; text-transform: uppercase;
  color: rgba(23,18,14,.4);
  transition: color .4s var(--ease);
}
.section-rail__num { flex: none; width: var(--rail-num-w); text-align: right; }
.section-rail__label { flex: none; white-space: nowrap; }
.section-rail__label { opacity: 0; transition: opacity .4s var(--ease); }
.section-rail__line {
  display: block; flex: none; height: 1px;
  width: var(--rail-line); background: currentColor;
  transition: width .45s var(--ease);
}
.section-rail a:hover .section-rail__label,
.section-rail a:focus-visible .section-rail__label { opacity: 1; }
.section-rail a.is-active { color: var(--copper); }
.section-rail a.is-active .section-rail__label { opacity: 1; }
.section-rail a.is-active .section-rail__line { width: var(--rail-line-active); }

/* ---- State 2: compact rail, laptop widths ------------------------------
   Shown from 1200px up, so a 1366x768 or 1440x900 laptop keeps the rail
   instead of losing it to a large-desktop-only breakpoint. Both states
   require enough HEIGHT, because browser chrome, OS scaling and zoom eat
   vertical space independently of width. */
/* 1340 x 560. The width number has moved twice, both times from measurement:
   the brief said 1200, a 14" 2880x1800 laptop at 250% Windows scaling reports
   a 1152px viewport, and at that size the rail's reserved lane cost the
   showcase and the domain index more than the rail was worth. Client call:
   omit it below a large laptop rather than squeeze the content. 1340 is above
   every 14"-at-scale viewport we have measured and below 1366.
   The HEIGHT gate stays 560: a 1366x768 screen is a ~630-660px viewport once
   browser chrome is subtracted, so the brief's 700 hid it on real hardware.
   fitRail() remains the backstop for anything that still cannot hold it. */
@media (min-width: 1340px) and (min-height: 560px) {
  .section-rail { display: block; }
  /* Lane = rail width + right offset + buffer, so reserving it genuinely
     clears the component rather than just most of it. */
  :root { --rail-lane: 196px; }
}
/* A shrunken "mini" rail was built for 1120-1339 and measured: it left the
   portfolio card identical (500x257 either way, since the card is capped) but
   still cost the domain index 112px, which pushed its category column to two
   lines. So below 1340 the rail is omitted rather than squeezed — client
   decision, and the measurement supports it. Recover the mini variant from
   commit 1992ee6 if it is ever wanted. */
/* ---- State 1: full rail, large desktop ---- */
@media (min-width: 1440px) and (min-height: 760px) {
  .section-rail {
    --rail-right: clamp(24px, 3vw, 64px);
    --rail-gap: 48px;
    --rail-num: 10px;
    --rail-line: 30px;
    --rail-line-active: 72px;
    --rail-num-w: 18px;
    --rail-label-w: 94px;
    --rail-max-h: 64vh;
  }
  :root { --rail-lane: 276px; }
}
/* The sculpture grows with the viewport and only reaches the rail's lane on
   genuinely large screens. Measured overlap with the S silhouette: 3px at
   1512, 9px at 1470, 15px at 1440 — but 112px at 1680 and 73px at 1920. So
   between 1440 and 1599 the rail simply moves a little closer to the edge
   (still inside the safe area, still within the brief's 24-64px range), which
   clears the sculpture outright and lets the rail stay visible from first
   paint. A 14" laptop should not have to scroll to discover it. */
@media (min-width: 1440px) and (max-width: 1599px) and (min-height: 760px) {
  .section-rail { --rail-right: clamp(24px, 1.6vw, 30px); }
}
/* Only from 1600px up is the overlap big enough to be worth hiding for. The
   rail idles over the hero there and returns the moment the hero is scrolled
   past. Kept in the focus order — tabbing to it brings it straight back. */
@media (min-width: 1600px) and (min-height: 760px) {
  .section-rail.is-idle { opacity: 0; pointer-events: none; }
  .section-rail.is-idle:focus-within { opacity: 1; pointer-events: auto; }
}
/* Without JS the rail cannot track the active section, and nothing would idle
   it over the hero — so it would sit on the sculpture as six inert, unlit
   ticks. The header nav carries every one of these links, so drop it. */
.no-js .section-rail { display: none !important; }
/* If the rail is gone — fit check or no-JS — the reserved lane goes with it. */
html.rail-unfit, html.no-js { --rail-lane: 0px; }
/* State 3 (hidden below 1200px wide or 700px tall) needs no rule of its own:
   it is the base `display: none`, which only the two states above lift. */
/* rail colour adapts on dark sections */
.section-rail.on-dark a { color: rgba(237,231,222,.4); }
.section-rail.on-dark a.is-active { color: #E6A06E; }
.section-rail.on-dark ol::before { background: rgba(237,231,222,.16); }

/* =========================================================================
   HERO
   ========================================================================= */
.hero {
  position: relative;
  min-height: 100svh;
  padding: calc(var(--header-h) + clamp(28px,5vw,70px)) var(--gutter) clamp(40px,5vw,72px);
  background:
    radial-gradient(120% 90% at 78% 8%, rgba(180,83,31,.10) 0%, rgba(233,226,214,0) 58%),
    linear-gradient(180deg, #EFE9DE 0%, var(--paper) 60%);
  display: flex; align-items: center;
  overflow: hidden;
}
.hero__inner {
  width: 100%; max-width: var(--maxw); margin: 0 auto;
  display: grid; grid-template-columns: minmax(0, 42%) minmax(0, 58%);
  align-items: center; gap: clamp(24px, 4vw, 64px);
}

.hero__copy { display: flex; flex-direction: column; align-items: flex-start; gap: 26px; max-width: 700px; }
.hero__title {
  font-family: var(--grotesk); font-weight: 600;
  font-size: clamp(2.5rem, 4.7vw, 4.9rem);
  line-height: 1; letter-spacing: -.035em; color: var(--ink);
  margin-top: 6px; text-wrap: balance;
}
.hero__lead { font-size: clamp(15px, 1.2vw, 17px); line-height: 1.66; color: var(--muted-d); max-width: 40ch; text-wrap: pretty; }
.hero__accent { font-size: 15px; color: var(--copper); font-weight: 500; }
.hero__actions { display: flex; align-items: center; gap: 16px; flex-wrap: wrap; margin-top: 4px; }

/* -------------------------------------------------------------------------
   3D "S" sculpture render.
   Deliberately NOT a card: no border, no radius, no shadow, no separate
   container colour. The media is part of the hero composition — on wide
   screens it bleeds to the hero's top/bottom/right edges and its left edge is
   dissolved into the mineral background with a mask, so text always sits on
   calm, uninterrupted paper.
   Three layers share one box (so switching source can never shift layout):
     z0 static poster · z1 assembly reveal · z2 ambient loop
   ------------------------------------------------------------------------- */
.hero__figure { position: relative; min-width: 0; }

/* Wide, landscape-ish screens: the media leaves the grid and bleeds to the
   hero's top, bottom and right edges, so it reads as part of the composition
   rather than a picture sitting in a column. Its left edge is dissolved into
   the paper, which keeps the headline on calm background at every width.
   The aspect-ratio gate matters: on a tall/portrait viewport a full-height
   column is far narrower than the 16:9 source, and `cover` would crop the
   sculpture down to an unreadable fragment. Those widths take the horizontal
   band below instead. */
@media (min-width: 881px) and (min-aspect-ratio: 6/5) {
  .hero__copy { position: relative; z-index: 1; }
  .hero__figure {
    --hero-mask-left: linear-gradient(90deg, transparent 0%, #000 22%, #000 100%);
    position: absolute;
    top: var(--hero-media-top, 0); right: 0; bottom: 0;
    width: var(--hero-media-w, 58vw); max-width: none;
    -webkit-mask-image: var(--hero-mask-left);
            mask-image: var(--hero-mask-left);
  }
}

/* Laptop framing (≈881–1599px).
   The sculpture fills 5.6%–95% of the source frame's height, so on a laptop —
   where the media column is nearly square — `cover` is height-bound and scales
   the S up until its upper arm sits under the fixed header. Shortening the box
   from the top is the only lever that actually shrinks it (cover scale is
   max(W/1920, H/1080), and height binds here): dropping the top by ~96px takes
   roughly 11–13% off the rendered S *and* moves it down clear of the header in
   one move. A larger object-position-x then slides the sculpture left, away
   from the right edge. 1600px and above keeps the bold full-bleed framing. */
@media (min-width: 881px) and (max-width: 1599px) and (min-aspect-ratio: 6/5) {
  .hero__figure {
    --hero-media-top: 96px;
    --hero-media-w: 62vw;
    /* The top edge is now inset, so fade it into the paper as well — the point
       is an integrated composition, not a media box with a visible edge. */
    -webkit-mask-image: var(--hero-mask-left), linear-gradient(180deg, transparent 0%, #000 11%, #000 100%);
            mask-image: var(--hero-mask-left), linear-gradient(180deg, transparent 0%, #000 11%, #000 100%);
    -webkit-mask-composite: source-in;
            mask-composite: intersect;
  }
  .hero-s { --hero-focus-x: 80%; }
}

.hero-s { position: relative; width: 100%; height: 100%; overflow: hidden; }
.hero-s__render {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: var(--hero-fit, cover);
  object-position: var(--hero-focus-x, 62%) var(--hero-focus-y, 46%);
  /* Zoom about the sculpture itself, so tighter crops stay centred on the S
     instead of drifting to the middle of the room. Moving the origin toward
     the top makes a zoom crop the base rather than both ends at once. */
  transform: translateX(var(--hero-shift, 0)) scale(var(--hero-zoom, 1));
  transform-origin: var(--hero-origin-x, 58.5%) var(--hero-origin-y, 53%);
}
.hero-s__poster { z-index: 0; }
.hero-s__video {
  z-index: 1; opacity: 0;
  transition: opacity var(--hero-xfade, 420ms) linear;
}
[data-hero-video="loop"] { z-index: 2; }
/* Whichever layer the inline head script chose is opaque from first paint. */
.hero-reveal .hero-s__video[data-hero-video="reveal"],
.hero-loop   .hero-s__video[data-hero-video="loop"],
.hero-s__video.is-on { opacity: 1; }
/* Retired layers are removed outright so they can never be composited. */
.hero-s__video[hidden] { display: none; }

/* =========================================================================
   TICKER (marquee + cycler)
   ========================================================================= */
.ticker {
  display: grid; grid-template-columns: auto 1fr; align-items: center; gap: clamp(20px,3vw,48px);
  padding: 16px var(--gutter);
  background: var(--paper-2);
  border-top: 1px solid var(--paper-line);
  border-bottom: 1px solid var(--paper-line);
}
.ticker__cycler { display: flex; align-items: center; gap: 14px; white-space: nowrap; }
.ticker__name {
  font-family: var(--serif); font-size: 22px; letter-spacing: -.01em; color: var(--ink);
}
.ticker__marquee { overflow: hidden; -webkit-mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent); mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent); }
.ticker__track { display: flex; width: max-content; animation: marquee 46s linear infinite; }
.ticker__group { display: flex; align-items: center; }
.ticker__group span {
  font-family: var(--serif); font-size: 22px; letter-spacing: -.01em; color: rgba(23,18,14,.66); white-space: nowrap;
  padding: 0 20px;
}
.ticker__group i { display: block; width: 5px; height: 5px; border-radius: 50%; background: var(--copper); }
@keyframes marquee { from { transform: translateX(0); } to { transform: translateX(-50%); } }

/* =========================================================================
   OPERATING BUSINESSES SHOWCASE (dark)
   ========================================================================= */
.showcase {
  background: var(--ink-2); color: var(--cream);
  padding: clamp(70px,7vw,120px) var(--gutter);
  display: grid; grid-template-columns: minmax(0, 300px) minmax(0, 1fr);
  gap: clamp(32px, 5vw, 80px);
  align-items: start;
}
.showcase__intro { display: flex; flex-direction: column; gap: 16px; }
.showcase .eyebrow--copper { color: var(--copper-lt); }
.showcase__year { font-family: var(--serif); font-size: clamp(3rem, 5vw, 4.6rem); line-height: .9; letter-spacing: -.02em; }
.showcase__desc { max-width: 26ch; font-size: 14px; line-height: 1.7; color: var(--muted-l); }

.showcase__stage { display: flex; flex-direction: column; gap: 30px; min-width: 0; }
.showcase__slides { position: relative; display: flex; flex-direction: column; gap: clamp(48px,6vw,88px); }
/* Only JS hides the inactive slides (via the hidden property) — see main.js.
   Without it, all three stack here, in document order, fully readable. */
.slide[hidden] { display: none; }
.slide {
  display: grid;
  /* The copy column caps at 320px on wide screens but yields proportionally
     when the stage is tight. A hard 320px meant every pixel the stage lost
     came off the browser card and none off the text, which is how the card
     ended up at 142px on a 1152px laptop. */
  grid-template-columns: minmax(0, min(320px, 38%)) minmax(0, 1fr);
  gap: clamp(24px, 3vw, 56px); align-items: center;
}
.slide__meta { display: flex; flex-direction: column; gap: 14px; }
.slide__index { font-family: var(--mono); font-size: 12px; color: var(--copper-lt); }
.slide__name { color: #E8E1D6; font-family: var(--serif); font-weight: 400; font-size: clamp(1.8rem, 3vw, 2.7rem); line-height: 1; letter-spacing: -.02em; }
.slide__cat { font-family: var(--mono); font-size: 10px; letter-spacing: .18em; text-transform: uppercase; color: #9D968D; }
.slide__blurb { font-size: 14.5px; line-height: 1.65; color: #AAA49C; max-width: 34ch; }
.slide__meta .link-arrow { color: var(--cream); margin-top: 6px; }
.slide__meta .link-arrow:hover, .slide__meta .link-arrow:focus-visible { color: #E6A06E; }

/* Browser frame + representative product mock */
.slide__media { min-width: 0; }
.browser {
  /* One Starscape component. Only the header colour changes per property —
     structure, radius, border, padding and aspect ratio are identical, so the
     three cards read as one system rather than three designs. */
  border-radius: 6px; overflow: hidden; background: #fff;
  border: 1px solid rgba(232,225,214,.5);
  /* Restrained ambient shadow only, to lift the card off the black section. */
  box-shadow: 0 18px 40px rgba(0,0,0,.34);
}
.browser__bar {
  display: flex; align-items: center; gap: 14px; padding: 10px 16px;
  background: var(--brand, #17252b);
}
/* Decorative window furniture — NOT carousel state. Identical in every card
   and in every carousel position, uniform colour, no hover, no animation,
   and hidden from assistive tech in the markup. */
.browser__dots { display: flex; gap: 6px; }
.browser__dots i {
  width: 8px; height: 8px; border-radius: 50%;
  background: rgba(232,225,214,.48);
}
.browser__url {
  font-family: var(--mono); font-size: 11px; letter-spacing: .04em;
  color: #E8E1D6;
  background: var(--brand-pill, rgba(0,0,0,.2));
  padding: 3px 11px; border-radius: 100px;
}
/* The frame matches the source EXACTLY: all three screenshots are 1600x679
   (uniform via the Higgsfield outpaint pass). At 16/9 the cover crop threw
   away 25% of each capture's width and scaled what remained to 48%, which is
   why the page UI looked oversized and a dead white band appeared mid-card.
   At the source's own ratio there is no crop, the whole page is visible, and
   it renders ~25% smaller and ~20% shorter. */
.browser__view { position: relative; aspect-ratio: 1600 / 679; background: #f4f2ee; }
.browser__shot { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: top; }
.browser__shot:not([src]) { display: none; }

/* Representative mock UI (shown when no screenshot supplied) */
.mock { position: absolute; inset: 0; display: flex; flex-direction: column; padding: 0; font-family: var(--grotesk); }
.mock__topnav {
  display: flex; align-items: center; gap: 16px; padding: 12px 18px; color: #fff;
  font-size: 11px; letter-spacing: .02em;
}
.mock__topnav b { font-size: 13px; margin-right: 8px; }
.mock__topnav span { opacity: .78; font-size: 10px; }
.mock__hero { height: 46%; margin: 0; background-size: cover; background-position: center; }
.mock__grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; padding: 14px 18px; }
.mock__grid--2 { grid-template-columns: repeat(2, 1fr); }
.mock__grid span { height: 60px; background: rgba(23,18,14,.08); border-radius: 4px; }
.mock__aside { position: absolute; right: 18px; top: 58px; width: 34%; background: #fff; border-radius: 6px; box-shadow: 0 12px 24px rgba(0,0,0,.14); padding: 12px; }
.mock__aside em { display: block; font-size: 10px; font-style: normal; letter-spacing: .12em; text-transform: uppercase; color: #fff; background: var(--m-accent,#154); margin: -12px -12px 10px; padding: 8px 12px; border-radius: 6px 6px 0 0; }
.mock__aside u { display: block; height: 8px; margin: 8px 0; background: rgba(23,18,14,.10); border-radius: 3px; }
.mock__feature { display: flex; gap: 14px; padding: 18px; align-items: center; }
.mock__feature i { width: 42%; aspect-ratio: 4/3; border-radius: 6px; background: var(--m-accent,#334); }
.mock__lines { flex: 1; display: flex; flex-direction: column; gap: 10px; }
.mock__lines u { height: 10px; background: rgba(23,18,14,.10); border-radius: 3px; }
.mock__lines u:nth-child(2){ width: 82%; } .mock__lines u:nth-child(3){ width: 64%; }
.mock__tiles { display: grid; grid-template-columns: repeat(4,1fr); gap: 8px; padding: 16px 18px; }
.mock__tiles span { aspect-ratio: 3/4; border-radius: 5px; background: linear-gradient(180deg, var(--m-accent,#733), rgba(23,18,14,.12)); }
.mock__row { display: flex; gap: 10px; padding: 0 18px 16px; }
.mock__row u { flex: 1; height: 40px; border-radius: 5px; background: rgba(23,18,14,.08); }

/* ---- Property identity colours -------------------------------------------
   Each property contributes exactly ONE colour, and it appears only in the
   browser chrome and that property's active carousel state. Never in the
   section background, body copy, large titles, arrows or the screenshot.
   --brand-pill is a darker tone of the same hue, so the URL pill belongs to
   the property rather than being a generic black chip.
   --brand-ui is the same colour tuned for small text on the black section;
   only Authors needed it (see the contrast note below). */
.browser[data-brand="soccernews"]   { --brand: #139688; --brand-pill: #0E6F65; }
.browser[data-brand="authors"]      { --brand: #6B7F76; --brand-pill: #4E6058; }
.browser[data-brand="ticketcenter"] { --brand: #EC7502; --brand-pill: #9A4700; }

.mock--soccer  { --m-accent: #0f5a44; }
.mock--soccer .mock__hero { background: linear-gradient(135deg,#0f5a44,#0a2f2a 70%); }
.mock--soccer .mock__topnav { background: #0d332c; }
.mock--authors { --m-accent: #3b2f66; }
.mock--authors .mock__topnav { background: #241d38; color: #efeaf7; }
.mock--tickets { --m-accent: #9a5116; }
.mock--tickets .mock__topnav { background: #2c1a0b; }

/* Controls (progressive enhancement only; harmless/inert without JS) */
.showcase__controls {
  display: flex; align-items: center; justify-content: space-between; gap: 24px;
  border-top: 1px solid var(--hair-l); padding-top: 22px; flex-wrap: wrap;
}
.showcase__tabs { display: flex; gap: 26px; flex-wrap: wrap; }
.tab {
  background: none; border: 0; padding: 4px 0;
  font-family: var(--mono); font-size: 10px; letter-spacing: .14em; text-transform: uppercase;
  color: var(--muted-l); display: inline-flex; align-items: center; gap: 8px;
  border-bottom: 1px solid transparent; transition: color .3s var(--ease), border-color .3s var(--ease);
}
.tab__num { color: rgba(237,231,222,.6); }
/* The numbered navigation is the carousel's state indicator — the browser
   dots are not. The active item takes the property's identity colour on the
   number and the underline; the label stays warm mineral so the hierarchy
   remains Starscape's. */
.tab[data-brand="soccernews"]   { --brand-ui: #139688; }
.tab[data-brand="authors"]      { --brand-ui: #7C9187; } /* lightened from #6B7F76: the
                                     source sits at 4.4:1 on this background, just under
                                     AA for small text. Same hue, contrast-corrected. */
.tab[data-brand="ticketcenter"] { --brand-ui: #EC7502; }
.tab[aria-selected="true"] { color: #E8E1D6; border-bottom-color: var(--brand-ui, var(--copper-2)); }
.tab[aria-selected="true"] .tab__num { color: var(--brand-ui, var(--copper-lt)); }
/* Hover must not repaint the selected tab — otherwise pointing at the active
   item shifts it off the warm-mineral active colour. */
.tab:not([aria-selected="true"]):hover { color: var(--cream); }
.showcase__arrows { display: flex; gap: 10px; }
.arrow {
  width: 46px; height: 46px; border-radius: 50%;
  border: 1px solid var(--hair-l); background: none; color: var(--cream);
  display: grid; place-items: center; font-size: 16px;
  transition: background .3s var(--ease), color .3s var(--ease), border-color .3s var(--ease);
}
.arrow:hover, .arrow:focus-visible { background: var(--cream); color: var(--ink); border-color: var(--cream); }
/* Arrows stay warm mineral in every slide — only the hover outline picks up
   the active property, so they never fragment into three button styles. */
.showcase__stage:has(.tab[data-brand="soccernews"][aria-selected="true"])   .arrow:hover { border-color: #139688; }
.showcase__stage:has(.tab[data-brand="authors"][aria-selected="true"])      .arrow:hover { border-color: #7C9187; }
.showcase__stage:has(.tab[data-brand="ticketcenter"][aria-selected="true"]) .arrow:hover { border-color: #EC7502; }

/* =========================================================================
   PROCESS (light) — pinned intro + steps that step forward and indent
   progressively, one emphasised at a time as it nears the viewport centre.
   ========================================================================= */
.process {
  background: var(--paper); padding: clamp(70px,8vw,130px) var(--gutter);
  display: grid; grid-template-columns: minmax(0,340px) minmax(0,1fr);
  gap: clamp(40px,6vw,110px); align-items: start;
}
.process__intro { position: sticky; top: 120px; display: flex; flex-direction: column; gap: 20px; }
.process__steps { display: flex; flex-direction: column; }
.step {
  position: relative; padding: clamp(28px,3vw,44px) 0;
  border-top: 1px solid rgba(23,18,14,.16);
  transition: border-color .5s var(--ease), transform .5s var(--ease);
}
.process__steps .step:last-child { border-bottom: 1px solid rgba(23,18,14,.16); }
/* Progressive horizontal indentation, one step further right each time */
.step[data-step="0"] { margin-left: 0; }
.step[data-step="1"] { margin-left: clamp(0px, 4vw, 64px); }
.step[data-step="2"] { margin-left: clamp(0px, 8vw, 128px); }
.step[data-step="3"] { margin-left: clamp(0px, 12vw, 192px); }
/* Oversized ghost numeral, ranged behind the copy */
.step__num {
  position: absolute; right: 0; top: clamp(14px,1.6vw,22px);
  font-family: var(--mono); font-weight: 500;
  font-size: clamp(4rem,7vw,7.5rem); line-height: 1;
  color: rgba(23,18,14,.07); pointer-events: none;
}
.step__title { position: relative; font-family: var(--serif); font-weight: 400; font-size: clamp(1.7rem,2.8vw,2.6rem); letter-spacing: -.02em; margin-bottom: 14px; }
.step__text { position: relative; max-width: 420px; font-size: 14px; line-height: 1.7; color: var(--muted-d); }
/* One stage receiving attention at a time (IntersectionObserver toggles
   this). Emphasis lives in the border and ghost-numeral colour only — never
   in text opacity, so copy stays fully AA-legible whether active or not. */
.js .step.is-active { border-top-color: var(--copper); }
.js .step.is-active .step__num { color: rgba(160,63,23,.16); }
.js .step.is-active .step__title { color: var(--copper); }

/* =========================================================================
   SELECTED DOMAIN INDEX (light, inverting rows + fixed detail panel)
   ========================================================================= */
.index { background: var(--paper-2); padding: clamp(70px,8vw,130px) var(--gutter); }
.index__head {
  max-width: var(--maxw); margin: 0 auto 44px;
}
.index__head .section-title { margin-top: 18px; }

.index__body {
  max-width: var(--maxw); margin: 0 auto;
  display: grid; grid-template-columns: minmax(0,1fr) 300px; gap: 40px; align-items: start;
}
.index__table { min-width: 0; }
.index__row {
  display: grid;
  grid-template-columns: 60px minmax(0,1.5fr) minmax(0,1fr) 130px 30px;
  gap: 16px; align-items: center;
  padding: 26px 20px;
  border-bottom: 1px solid rgba(23,18,14,.12);
  color: var(--ink);
  transition: background .5s var(--ease), color .4s var(--ease), padding-left .5s var(--ease);
}
.index__row--head {
  padding: 0 20px 14px; border-bottom: 1px solid rgba(23,18,14,.24);
  font-family: var(--mono); font-size: 9px; letter-spacing: .2em; text-transform: uppercase; color: rgba(23,18,14,.66);
}
.index__num { font-family: var(--mono); font-size: 11px; color: var(--copper); }
.index__name { font-family: var(--serif); font-size: clamp(1.4rem,2.2vw,2rem); line-height: 1.05; letter-spacing: -.02em; }
.index__cat { font-size: 13px; color: var(--muted-d); }
.index__status { display: flex; align-items: center; gap: 9px; font-family: var(--mono); font-size: 9.5px; letter-spacing: .14em; text-transform: uppercase; color: var(--muted-d); }
.dot { width: 6px; height: 6px; border-radius: 50%; background: var(--copper); }
.dot--available { background: rgba(23,18,14,.34); }
.dot--operating { background: var(--copper); }
.dot--venture { background: var(--copper-2); }
.index__go { text-align: right; font-size: 15px; color: rgba(23,18,14,.4); }

a.index__row:hover, a.index__row:focus-visible {
  background: var(--ink); color: var(--cream); padding-left: 34px; outline-offset: -2px;
}
a.index__row:hover .index__cat, a.index__row:focus-visible .index__cat,
a.index__row:hover .index__status, a.index__row:focus-visible .index__status,
a.index__row:hover .index__go, a.index__row:focus-visible .index__go { color: rgba(237,231,222,.7); }

.index__foot {
  max-width: var(--maxw); margin: 22px auto 0;
  display: flex; align-items: center; justify-content: space-between; gap: 24px;
  font-family: var(--mono); font-size: 9.5px; letter-spacing: .16em; text-transform: uppercase; color: var(--muted-d);
}

/* Fixed detail panel — anchored beside the rows, NOT cursor-following.
   Sticky within the section so it stays visible while scrolling the table,
   and updates its text content only (no positioning math). */
.index__detail {
  position: sticky; top: 120px;
  background: var(--rust); color: var(--cream);
  border: 1px solid rgba(237,231,222,.16);
  padding: 24px; display: flex; flex-direction: column; gap: 14px;
  box-shadow: 0 20px 44px rgba(0,0,0,.22);
}
.index__detail-eyebrow { font-family: var(--mono); font-size: 9px; letter-spacing: .2em; text-transform: uppercase; color: rgba(237,231,222,.82); }
.index__detail-num { font-family: var(--mono); font-size: 11px; color: rgba(237,231,222,.82); margin-top: -6px; }
.index__detail-name { font-family: var(--serif); font-size: 30px; line-height: 1.05; letter-spacing: -.02em; }
.index__detail-desc { font-size: 12.5px; line-height: 1.6; color: rgba(237,231,222,.78); }
.index__detail-rule { height: 1px; background: rgba(237,231,222,.22); }
.index__detail-status { font-family: var(--mono); font-size: 9px; letter-spacing: .2em; text-transform: uppercase; }

/* =========================================================================
   JOINT VENTURES (rust)
   ========================================================================= */
.venture {
  background:
    radial-gradient(120% 100% at 0% 0%, rgba(0,0,0,.22), rgba(0,0,0,0) 55%),
    linear-gradient(135deg, var(--rust) 0%, var(--rust-2) 100%);
  color: var(--cream);
  padding: clamp(70px,8vw,130px) var(--gutter);
  display: grid; grid-template-columns: minmax(0,360px) minmax(0,1fr);
  gap: clamp(40px,6vw,110px); align-items: start;
}
.venture .eyebrow { color: rgba(237,231,222,.6); }
.venture .section-title { color: var(--cream); }
.venture .section-title em { color: rgba(237,231,222,.55); }
.venture .section-lead { color: rgba(237,231,222,.72); max-width: 30ch; }
.venture__intro { display: flex; flex-direction: column; gap: 20px; }
.venture__actions { display: flex; flex-direction: column; align-items: flex-start; gap: 12px; margin-top: 6px; }

.venture__feature { display: flex; flex-direction: column; gap: 20px; min-width: 0; }
.venture__namerow { display: flex; align-items: baseline; justify-content: space-between; gap: 24px; flex-wrap: wrap; }
.venture__name { font-family: var(--serif); font-size: clamp(2.6rem,5.4vw,5.4rem); line-height: .95; letter-spacing: -.03em; }
.venture__badge { font-family: var(--mono); font-size: 10px; letter-spacing: .2em; text-transform: uppercase; color: rgba(237,231,222,.6); }
.venture__tagline { font-size: 15px; color: rgba(237,231,222,.78); max-width: 40ch; }
.venture__media { position: relative; width: 100%; aspect-ratio: 16 / 6.2; overflow: hidden; background: rgba(0,0,0,.22); border-radius: 4px; }
.venture__img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.venture__cats {
  display: grid; grid-template-columns: repeat(4, minmax(0,1fr)); gap: 1px;
  background: rgba(237,231,222,.2); border: 1px solid rgba(237,231,222,.2);
}
.venture__cats li {
  background: var(--rust); padding: 16px 14px;
  font-family: var(--mono); font-size: 9.5px; letter-spacing: .18em; text-transform: uppercase; color: rgba(237,231,222,.72);
}

/* =========================================================================
   TRANSACTIONS (light)
   ========================================================================= */
.deals {
  background: var(--paper); padding: clamp(70px,8vw,130px) var(--gutter);
  display: grid; grid-template-columns: minmax(0,360px) minmax(0,1fr);
  gap: clamp(40px,6vw,110px); align-items: start;
}
.deals__intro { display: flex; flex-direction: column; gap: 20px; }
.deals__body { display: flex; flex-direction: column; gap: 26px; }
.deals__eyebrow { color: rgba(23,18,14,.7); }
.deals__names {
  display: grid; grid-template-columns: repeat(2, minmax(0,1fr));
  border-top: 1px solid var(--paper-line); border-bottom: 1px solid var(--paper-line);
}
.deals__name { padding: clamp(30px,3.4vw,54px) 0; display: flex; align-items: center; color: var(--ink); }
.deals__name--serif { font-family: var(--serif); font-size: clamp(1.9rem,3.4vw,3.2rem); letter-spacing: -.02em; border-right: 1px solid var(--paper-line); }
.deals__name--mono { font-weight: 500; font-size: clamp(1rem,1.5vw,1.35rem); letter-spacing: .14em; text-transform: uppercase; padding-left: clamp(20px,3vw,48px); }
.deals__disclaimer { max-width: 62ch; font-family: var(--mono); font-size: 9.5px; line-height: 1.9; letter-spacing: .05em; text-transform: uppercase; color: rgba(23,18,14,.64); }

/* =========================================================================
   CONTACT (light)
   ========================================================================= */
.contact { background: var(--paper-2); padding: clamp(70px,8vw,130px) var(--gutter) clamp(60px,6vw,100px); }
.contact > .eyebrow { margin-bottom: 34px; }
.contact__head {
  max-width: var(--maxw); margin: 0 auto clamp(50px,6vw,90px);
  display: grid; grid-template-columns: minmax(0,1fr) auto; align-items: end; gap: 40px;
}
.contact__title { font-family: var(--serif); font-weight: 400; font-size: clamp(2.4rem,6vw,6rem); line-height: .98; letter-spacing: -.03em; max-width: 15ch; }
.contact__title em { color: rgba(23,18,14,.5); }
.contact__routes {
  max-width: var(--maxw); margin: 0 auto;
  display: grid; grid-template-columns: repeat(3, minmax(0,1fr)); gap: 1px;
  background: var(--paper-line); border-top: 1px solid var(--paper-line);
}
.route {
  background: var(--paper-2); padding: 30px 24px; display: flex; flex-direction: column; gap: 12px;
  transition: background .4s var(--ease), padding-left .4s var(--ease);
}
.route:first-child { padding-left: 0; }
.route:hover, .route:focus-visible { background: #DED5C6; padding-left: 22px; }
.route:first-child:hover, .route:first-child:focus-visible { padding-left: 16px; }
.route__title { display: flex; align-items: center; justify-content: space-between; gap: 16px; font-family: var(--serif); font-size: 25px; letter-spacing: -.015em; }
.route__title span { font-family: var(--grotesk); font-size: 15px; opacity: .5; }
.route__text { font-size: 13px; line-height: 1.6; color: var(--muted-d); max-width: 30ch; }

/* =========================================================================
   FOOTER (dark)
   ========================================================================= */
.site-footer { background: var(--ink-2); color: var(--cream); padding: clamp(56px,6vw,96px) var(--gutter) 30px; }
.site-footer__grid {
  max-width: var(--maxw); margin: 0 auto;
  display: grid;
  /* The Contact column carries a CTA that must not wrap on desktop, so it gets
     a wider track than the three link columns. */
  grid-template-columns: minmax(0,1.6fr) repeat(3, minmax(0,1fr)) minmax(0,1.4fr);
  gap: clamp(24px,3vw,48px); padding-bottom: clamp(40px,5vw,72px);
}
.site-footer__brand { display: flex; flex-direction: column; gap: 16px; }
.site-footer__brand p { max-width: 26ch; font-size: 14px; line-height: 1.7; color: var(--muted-l); }
/* 14px floor for footer running text. The mono column labels stay small:
   they are eyebrows, and every eyebrow on the site is 9-10px mono — matching
   14px here would break that convention in one place only. */
.footcol { display: flex; flex-direction: column; gap: 12px; font-size: 14px; }
.footcol__head { font-family: var(--mono); font-size: 10px; letter-spacing: .2em; text-transform: uppercase; color: rgba(237,231,222,.62); margin-bottom: 4px; }
/* Supporting copy in a footer column — deliberately not a heading. */
.footcol__note { color: rgba(237,231,222,.62); line-height: 1.55; max-width: 22ch; }
.footcol a, .footcol span { color: rgba(237,231,222,.7); transition: color .25s var(--ease); }
.footcol a:hover, .footcol a:focus-visible { color: var(--cream); }
/* Footer CTA — one compact link, never a full-width column item.
   align-self is what actually fixes it: .footcol is a column flex container,
   so without this the link stretches to the column's full width and a wrapped
   label pushes the arrow out to the far right edge.
   The two spans carry NO whitespace between them in the markup, so there is no
   break opportunity: when the label does wrap on a narrow column, the arrow
   still travels with the final word instead of stranding on a line of its own. */
.footcol__cta {
  display: inline-flex; align-items: center; gap: .5rem;
  align-self: flex-start; width: fit-content; max-width: 100%;
  font-family: var(--mono); font-size: 11px; letter-spacing: .06em;
  text-transform: uppercase; color: var(--cream);
  border-bottom: 1px solid rgba(237,231,222,.28); padding-bottom: 3px;
  transition: color .25s var(--ease), border-color .25s var(--ease);
}
.footcol__cta:hover, .footcol__cta:focus-visible { color: var(--cream); border-bottom-color: var(--copper-lt); }
.footcol__cta .ext-ic { transition: transform .25s var(--ease); }
.footcol__cta:hover .ext-ic, .footcol__cta:focus-visible .ext-ic { transform: translate(1px, -1px); }
/* One line wherever the column can hold it. Below that the label may take two
   lines, but the arrow stays attached to the last word (see markup note). */
@media (min-width: 1000px) {
  .footcol__cta { white-space: nowrap; }
}
.site-footer__legal {
  max-width: var(--maxw); margin: 0 auto;
  display: flex; align-items: center; justify-content: space-between; gap: 24px; flex-wrap: wrap;
  padding-top: 24px; border-top: 1px solid var(--hair-l);
  font-family: var(--mono); font-size: 12px; letter-spacing: .1em; text-transform: uppercase; color: rgba(237,231,222,.62);
}

/* Back to top */
.to-top {
  position: fixed; right: 22px; bottom: 22px; z-index: 90;
  width: 50px; height: 50px; border-radius: 50%;
  background: var(--ink); color: var(--cream); border: 0;
  display: grid; place-items: center; font-size: 18px;
  opacity: 0; visibility: hidden; transform: translateY(10px);
  transition: opacity .3s var(--ease), transform .3s var(--ease), background .3s var(--ease);
  box-shadow: 0 12px 30px rgba(0,0,0,.28);
}
.to-top.is-visible { opacity: 1; visibility: visible; transform: translateY(0); }
.to-top:hover, .to-top:focus-visible { background: var(--copper); }

/* =========================================================================
   CONTACT PAGE (/contact/) — enquiry form
   Warm mineral ground, graphite text, copper only as an accent. Controls are
   square-cornered underlined rules rather than filled rounded boxes, so the
   form reads as editorial stationery and not as a SaaS card.
   ========================================================================= */
.enquiry {
  background: var(--paper); color: var(--ink);
  padding: calc(var(--header-h) + clamp(44px,6vw,92px)) var(--gutter) clamp(44px,5vw,76px);
  display: grid; grid-template-columns: minmax(0,420px) minmax(0,1fr);
  gap: clamp(40px,7vw,120px); align-items: start;
}
.enquiry__intro { display: flex; flex-direction: column; gap: 20px; position: sticky; top: 120px; }
.enquiry__intro .section-lead { max-width: 34ch; }
/* Divider retained above the block. No address, phone or location lives here:
   the form is the only public contact route. */
.enquiry__direct {
  margin-top: 14px; padding-top: 22px; border-top: 1px solid var(--paper-line);
  display: flex; flex-direction: column; gap: 12px;
}
.enquiry__direct-label {
  font-family: var(--mono); font-size: 10px; letter-spacing: .18em;
  text-transform: uppercase; color: var(--muted-d); margin-bottom: 2px;
}
/* Secondary to the page heading, matching the left column's supporting scale. */
.enquiry__note { font-size: 13.5px; line-height: 1.7; color: var(--muted-d); max-width: 34ch; }

.enquiry__form-wrap { min-width: 0; max-width: 620px; }
.enquiry__form { display: flex; flex-direction: column; gap: 22px; }

/* Honeypot: removed from sight and from the tab order, but NOT via
   display:none — some bots skip fields that are display:none, which is
   exactly the population this is meant to catch. */
.hp {
  position: absolute; left: -9999px; width: 1px; height: 1px;
  overflow: hidden; opacity: 0; pointer-events: none;
}

.field { display: flex; flex-direction: column; gap: 7px; }
.field__label {
  font-family: var(--mono); font-size: 10.5px; letter-spacing: .16em;
  text-transform: uppercase; color: var(--ink);
}
.field__req { color: var(--muted-d); letter-spacing: .1em; }
.field__input {
  width: 100%; min-height: 46px;           /* comfortable touch target */
  padding: 12px 2px; border: 0; border-bottom: 1px solid rgba(23,18,14,.28);
  border-radius: 0; background: transparent;
  font-family: var(--grotesk); font-size: 15px; color: var(--ink);
  transition: border-color .3s var(--ease), background .3s var(--ease);
}
.field__input::placeholder { color: rgba(23,18,14,.38); }
.field__input:hover { border-bottom-color: rgba(23,18,14,.5); }
.field__input:focus { outline: 0; border-bottom-color: var(--copper); background: rgba(255,255,255,.34); }
/* Keep a visible ring for keyboard users specifically — the colour change
   above is not, on its own, a sufficient focus indicator. */
.field__input:focus-visible { outline: 2px solid var(--copper-2); outline-offset: 3px; }
/* Lands at the bottom of the 180-210px the brief asked for. Worth recording
   why it went UP: the field measured 169px, not the 250-280px estimated, so
   cutting 20-25% would have put it near 130px — well under the brief's own
   target and too small for "a serious enquiry". The page-height the brief
   actually wanted came from the section padding and form gaps instead. */
.field__textarea { min-height: 186px; resize: vertical; line-height: 1.6; }
.field__select {
  appearance: none;
  /* Chevron drawn inline so no network request and no icon font. */
  background-image: linear-gradient(45deg, transparent 50%, var(--ink) 50%),
                    linear-gradient(135deg, var(--ink) 50%, transparent 50%);
  background-position: right 12px center, right 6px center;
  background-size: 6px 6px, 6px 6px;
  background-repeat: no-repeat;
  padding-right: 30px;
}
.field__select:focus {
  background-image: linear-gradient(45deg, transparent 50%, var(--copper) 50%),
                    linear-gradient(135deg, var(--copper) 50%, transparent 50%);
  background-position: right 12px center, right 6px center;
  background-size: 6px 6px, 6px 6px;
  background-repeat: no-repeat;
}
.field__help { font-size: 12.5px; line-height: 1.6; color: var(--muted-d); }
.field__error {
  font-family: var(--mono); font-size: 11.5px; line-height: 1.6;
  color: #8C2F0E;                          /* 6.4:1 on --paper */
  padding-left: 14px; position: relative;
}
.field__error::before { content: '!'; position: absolute; left: 0; font-weight: 700; }
.field--invalid .field__input { border-bottom-color: #8C2F0E; border-bottom-width: 2px; }

/* Checkbox: a real control, sized for touch, never a styled div. */
.field--check {
  display: grid; grid-template-columns: auto 1fr; gap: 6px 12px;
  align-items: start; padding-top: 4px;
}
.check__box {
  width: 22px; height: 22px; margin: 1px 0 0; flex: none;
  accent-color: var(--copper); border-radius: 0; cursor: pointer;
}
.check__box:focus-visible { outline: 2px solid var(--copper-2); outline-offset: 3px; }
.check__label { font-size: 14px; line-height: 1.55; color: var(--ink); cursor: pointer; }
.field--check .field__error { grid-column: 1 / -1; }

/* Secondary explanation under the acknowledgement, not part of the label. */
.enquiry__privacy { font-size: 12.5px; line-height: 1.6; color: var(--muted-d);
  margin-top: -12px; padding-left: 34px; }
.enquiry__privacy a { color: var(--ink); border-bottom: 1px solid var(--copper); }
.enquiry__privacy a:hover, .enquiry__privacy a:focus-visible { color: var(--copper); }

/* ~10% wider than the natural label width, per the brief. Never full-width
   on desktop; the mobile rule below takes it full-width. */
.enquiry__submit { align-self: flex-start; min-height: 52px; min-width: 172px; }
.enquiry__submit[disabled] { opacity: .6; cursor: progress; }

/* Submission feedback */
.formmsg {
  margin-bottom: 28px; padding: 16px 18px;
  border-left: 3px solid var(--copper);
  background: rgba(255,255,255,.42);
  font-size: 14.5px; line-height: 1.65; color: var(--ink);
}
.formmsg:focus-visible { outline: 2px solid var(--copper-2); outline-offset: 3px; }
.formmsg--error { border-left-color: #8C2F0E; }
.formmsg a { color: var(--ink); border-bottom: 1px solid var(--copper); }

/* Legal pages (privacy) reuse the same measure and rhythm. */
.legal {
  background: var(--paper); color: var(--ink);
  padding: calc(var(--header-h) + clamp(48px,7vw,110px)) var(--gutter) clamp(70px,8vw,130px);
}
.legal__inner { max-width: 68ch; margin: 0 auto; display: flex; flex-direction: column; gap: 22px; }
.legal__inner h2 {
  font-family: var(--serif); font-weight: 400; font-size: clamp(1.3rem,2.2vw,1.8rem);
  margin-top: 22px; letter-spacing: -.01em;
}
.legal__inner p, .legal__inner li { font-size: 15px; line-height: 1.75; color: var(--muted-d); }
.legal__inner ul { padding-left: 20px; display: flex; flex-direction: column; gap: 8px; }
.legal__inner a { color: var(--ink); border-bottom: 1px solid var(--copper); }
.legal__updated { font-family: var(--mono); font-size: 11px; letter-spacing: .14em; text-transform: uppercase; color: var(--muted-d); }

@media (max-width: 900px) {
  .enquiry { grid-template-columns: 1fr; gap: 40px; }
  .enquiry__intro { position: static; }
}
@media (max-width: 640px) {
  /* Full-width submit on mobile only. */
  .enquiry__submit { align-self: stretch; width: 100%; }
  .enquiry__privacy { padding-left: 0; margin-top: -6px; }
}

/* =========================================================================
   SECTION RAIL CLEARANCE
   Every scrolling section reserves the lane the fixed rail occupies, so the
   rail sits in the page's safe area instead of floating over copy, imagery,
   the carousel arrows or the CTAs. --rail-lane collapses to 0 whenever the
   rail is hidden (narrow, short, or pulled by the fit check), so these rules
   cost nothing on tablet and mobile and need no breakpoints of their own.

   The hero is deliberately absent: it is the one full-bleed section and the
   sculpture cannot give up a lane, so the rail idles over it instead
   (.section-rail.is-idle). Must come after each section's own `padding`
   shorthand to win on source order.
   ========================================================================= */
.showcase, .process, .index, .venture, .deals, .contact, .site-footer {
  padding-right: calc(var(--gutter) + var(--rail-lane));
}

/* =========================================================================
   RESPONSIVE
   ========================================================================= */
/* The showcase keeps its original three-column reading — intro, copy, card —
   at every width from 901px up. The card starving to 142px on a 1152px laptop
   was NOT caused by that arrangement: it was .slide__meta being a fixed 320px,
   so every pixel the stage lost came off the card and none off the text. With
   the copy column yielding proportionally (see .slide above) the card measures
   ~430-440px from 1152 to 1440 and grows from there, with no stacking and no
   width cap needed. */

/* =========================================================================
   CONTACT PAGE (/contact/) — enquiry form
   Warm mineral ground, graphite text, copper only as an accent. Controls are
   square-cornered underlined rules rather than filled rounded boxes, so the
   form reads as editorial stationery and not as a SaaS card.
   ========================================================================= */
.enquiry {
  background: var(--paper); color: var(--ink);
  padding: calc(var(--header-h) + clamp(44px,6vw,92px)) var(--gutter) clamp(44px,5vw,76px);
  display: grid; grid-template-columns: minmax(0,420px) minmax(0,1fr);
  gap: clamp(40px,7vw,120px); align-items: start;
}
.enquiry__intro { display: flex; flex-direction: column; gap: 20px; position: sticky; top: 120px; }
.enquiry__intro .section-lead { max-width: 34ch; }
/* Divider retained above the block. No address, phone or location lives here:
   the form is the only public contact route. */
.enquiry__direct {
  margin-top: 14px; padding-top: 22px; border-top: 1px solid var(--paper-line);
  display: flex; flex-direction: column; gap: 12px;
}
.enquiry__direct-label {
  font-family: var(--mono); font-size: 10px; letter-spacing: .18em;
  text-transform: uppercase; color: var(--muted-d); margin-bottom: 2px;
}
/* Secondary to the page heading, matching the left column's supporting scale. */
.enquiry__note { font-size: 13.5px; line-height: 1.7; color: var(--muted-d); max-width: 34ch; }

.enquiry__form-wrap { min-width: 0; max-width: 620px; }
.enquiry__form { display: flex; flex-direction: column; gap: 22px; }

/* Honeypot: removed from sight and from the tab order, but NOT via
   display:none — some bots skip fields that are display:none, which is
   exactly the population this is meant to catch. */
.hp {
  position: absolute; left: -9999px; width: 1px; height: 1px;
  overflow: hidden; opacity: 0; pointer-events: none;
}

.field { display: flex; flex-direction: column; gap: 7px; }
.field__label {
  font-family: var(--mono); font-size: 10.5px; letter-spacing: .16em;
  text-transform: uppercase; color: var(--ink);
}
.field__req { color: var(--muted-d); letter-spacing: .1em; }
.field__input {
  width: 100%; min-height: 46px;           /* comfortable touch target */
  padding: 12px 2px; border: 0; border-bottom: 1px solid rgba(23,18,14,.28);
  border-radius: 0; background: transparent;
  font-family: var(--grotesk); font-size: 15px; color: var(--ink);
  transition: border-color .3s var(--ease), background .3s var(--ease);
}
.field__input::placeholder { color: rgba(23,18,14,.38); }
.field__input:hover { border-bottom-color: rgba(23,18,14,.5); }
.field__input:focus { outline: 0; border-bottom-color: var(--copper); background: rgba(255,255,255,.34); }
/* Keep a visible ring for keyboard users specifically — the colour change
   above is not, on its own, a sufficient focus indicator. */
.field__input:focus-visible { outline: 2px solid var(--copper-2); outline-offset: 3px; }
/* Lands at the bottom of the 180-210px the brief asked for. Worth recording
   why it went UP: the field measured 169px, not the 250-280px estimated, so
   cutting 20-25% would have put it near 130px — well under the brief's own
   target and too small for "a serious enquiry". The page-height the brief
   actually wanted came from the section padding and form gaps instead. */
.field__textarea { min-height: 186px; resize: vertical; line-height: 1.6; }
.field__select {
  appearance: none;
  /* Chevron drawn inline so no network request and no icon font. */
  background-image: linear-gradient(45deg, transparent 50%, var(--ink) 50%),
                    linear-gradient(135deg, var(--ink) 50%, transparent 50%);
  background-position: right 12px center, right 6px center;
  background-size: 6px 6px, 6px 6px;
  background-repeat: no-repeat;
  padding-right: 30px;
}
.field__select:focus {
  background-image: linear-gradient(45deg, transparent 50%, var(--copper) 50%),
                    linear-gradient(135deg, var(--copper) 50%, transparent 50%);
  background-position: right 12px center, right 6px center;
  background-size: 6px 6px, 6px 6px;
  background-repeat: no-repeat;
}
.field__help { font-size: 12.5px; line-height: 1.6; color: var(--muted-d); }
.field__error {
  font-family: var(--mono); font-size: 11.5px; line-height: 1.6;
  color: #8C2F0E;                          /* 6.4:1 on --paper */
  padding-left: 14px; position: relative;
}
.field__error::before { content: '!'; position: absolute; left: 0; font-weight: 700; }
.field--invalid .field__input { border-bottom-color: #8C2F0E; border-bottom-width: 2px; }

/* Checkbox: a real control, sized for touch, never a styled div. */
.field--check {
  display: grid; grid-template-columns: auto 1fr; gap: 6px 12px;
  align-items: start; padding-top: 4px;
}
.check__box {
  width: 22px; height: 22px; margin: 1px 0 0; flex: none;
  accent-color: var(--copper); border-radius: 0; cursor: pointer;
}
.check__box:focus-visible { outline: 2px solid var(--copper-2); outline-offset: 3px; }
.check__label { font-size: 14px; line-height: 1.55; color: var(--ink); cursor: pointer; }
.field--check .field__error { grid-column: 1 / -1; }

/* Secondary explanation under the acknowledgement, not part of the label. */
.enquiry__privacy { font-size: 12.5px; line-height: 1.6; color: var(--muted-d);
  margin-top: -12px; padding-left: 34px; }
.enquiry__privacy a { color: var(--ink); border-bottom: 1px solid var(--copper); }
.enquiry__privacy a:hover, .enquiry__privacy a:focus-visible { color: var(--copper); }

/* ~10% wider than the natural label width, per the brief. Never full-width
   on desktop; the mobile rule below takes it full-width. */
.enquiry__submit { align-self: flex-start; min-height: 52px; min-width: 172px; }
.enquiry__submit[disabled] { opacity: .6; cursor: progress; }

/* Submission feedback */
.formmsg {
  margin-bottom: 28px; padding: 16px 18px;
  border-left: 3px solid var(--copper);
  background: rgba(255,255,255,.42);
  font-size: 14.5px; line-height: 1.65; color: var(--ink);
}
.formmsg:focus-visible { outline: 2px solid var(--copper-2); outline-offset: 3px; }
.formmsg--error { border-left-color: #8C2F0E; }
.formmsg a { color: var(--ink); border-bottom: 1px solid var(--copper); }

/* Legal pages (privacy) reuse the same measure and rhythm. */
.legal {
  background: var(--paper); color: var(--ink);
  padding: calc(var(--header-h) + clamp(48px,7vw,110px)) var(--gutter) clamp(70px,8vw,130px);
}
.legal__inner { max-width: 68ch; margin: 0 auto; display: flex; flex-direction: column; gap: 22px; }
.legal__inner h2 {
  font-family: var(--serif); font-weight: 400; font-size: clamp(1.3rem,2.2vw,1.8rem);
  margin-top: 22px; letter-spacing: -.01em;
}
.legal__inner p, .legal__inner li { font-size: 15px; line-height: 1.75; color: var(--muted-d); }
.legal__inner ul { padding-left: 20px; display: flex; flex-direction: column; gap: 8px; }
.legal__inner a { color: var(--ink); border-bottom: 1px solid var(--copper); }
.legal__updated { font-family: var(--mono); font-size: 11px; letter-spacing: .14em; text-transform: uppercase; color: var(--muted-d); }

@media (max-width: 900px) {
  .enquiry { grid-template-columns: 1fr; gap: 40px; }
  .enquiry__intro { position: static; }
}
@media (max-width: 640px) {
  /* Full-width submit on mobile only. */
  .enquiry__submit { align-self: stretch; width: 100%; }
  .enquiry__privacy { padding-left: 0; margin-top: -6px; }
}

/* =========================================================================
   SECTION RAIL CLEARANCE
   Every scrolling section reserves the lane the fixed rail occupies, so the
   rail sits in the page's safe area instead of floating over copy, imagery,
   the carousel arrows or the CTAs. --rail-lane collapses to 0 whenever the
   rail is hidden (narrow, short, or pulled by the fit check), so these rules
   cost nothing on tablet and mobile and need no breakpoints of their own.

   The hero is deliberately absent: it is the one full-bleed section and the
   sculpture cannot give up a lane, so the rail idles over it instead
   (.section-rail.is-idle). Must come after each section's own `padding`
   shorthand to win on source order.
   ========================================================================= */
.showcase, .process, .index, .venture, .deals, .contact, .site-footer {
  padding-right: calc(var(--gutter) + var(--rail-lane));
}

/* =========================================================================
   RESPONSIVE
   ========================================================================= */

/* (The rail's old max-width:1180px hide rule lived here. It is gone on
   purpose: the rail is now hidden by default and opted into by the two
   state queries above, so a stale second threshold can't drift out of sync
   with the real 1200px / 700px gates.) */

/* The hero keeps its split layout well past the point the rest of the page
   stacks — down to 880px — so a tablet never gets a small boxed video sitting
   under the copy. Below that (or on any portrait-ish viewport, however wide)
   it becomes a full-bleed horizontal band: still edge-to-edge, never a card. */
@media (max-width: 880px), (max-aspect-ratio: 6/5) {
  .hero { min-height: auto; padding-top: calc(var(--header-h) + 28px); padding-bottom: 8px; }
  /* Brand → proposition → supporting copy → visual object: copy stays first
     in document order at narrow widths (no reordering above the message). */
  .hero__inner { grid-template-columns: 1fr; gap: clamp(18px, 3.5vw, 30px); }
  .hero__figure {
    /* Full-bleed band, edge to edge — never a card inset in the column.
       Tall enough that the sculpture reads whole with only a slight crop top
       and bottom; a shorter band at these widths slices it mid-body. */
    margin-inline: calc(-1 * var(--gutter));
    height: clamp(300px, 44vw, 460px);
  }
  /* Anchored above centre: from ~600px up this band is wider than 16:9, so the
     source overflows it vertically and a centred crop would shave the upper
     arm. Biasing up keeps the arm and spends the crop on the base instead. */
  .hero-s { --hero-zoom: 1; --hero-focus-x: 58%; --hero-focus-y: 22%; }
}

/* Phone (<768px). A cover crop cannot work here: the sculpture fills ~90% of
   the source frame's height, so any crop tight enough to fill a short band
   slices the upper arm or the lower return — which is exactly what went wrong.
   So switch to `contain`: the whole frame is shown, nothing is cropped, and the
   apparent scale drops naturally. The band itself has no background, so the
   letterbox area is the hero's own gradient and no media box appears.
   A small zoom + horizontal shift then brings the sculpture — which sits
   right-of-centre in frame — to the optical centre of the band.
   Both <video>s and the poster share this class, so framing is identical and
   the reveal -> loop handoff cannot jump. */
@media (max-width: 767px) {
  .hero__figure {
    height: clamp(230px, 60vw, 280px);
    background: none;
    border: 0;
    border-radius: 0;
    box-shadow: none;
  }
  .hero-s {
    --hero-fit: contain;
    --hero-zoom: 1.12;
    --hero-shift: -7%;
    --hero-focus-x: 54%;
    --hero-focus-y: 46%;
    --hero-origin-y: 50%;
    background: none;
  }
  /* Keep the two CTAs reading as one group directly above the media, rather
     than the second one floating between the buttons and the animation. */
  .hero__actions { gap: 10px; }
}

@media (max-width: 1000px) {
  .showcase { grid-template-columns: 1fr; }
  .slide { grid-template-columns: 1fr; }
  .slide__media { order: -1; }
  .process { grid-template-columns: 1fr; }
  .process__intro { position: static; top: auto; }
  .step[data-step="1"] { margin-left: clamp(0px, 3vw, 32px); }
  .step[data-step="2"] { margin-left: clamp(0px, 5vw, 56px); }
  .step[data-step="3"] { margin-left: clamp(0px, 7vw, 80px); }
  .venture, .deals { grid-template-columns: 1fr; }
  .index__body { grid-template-columns: 1fr; }
  .index__detail { position: static; top: auto; }
  .contact__head { grid-template-columns: 1fr; }
  .site-footer__grid { grid-template-columns: 1fr 1fr; }
  .site-footer__brand { grid-column: 1 / -1; }
}

/* Tablet nav breakpoint moved up from 720 → 900: the full desktop nav read
   as cramped at ~820px (review feedback), so the compact/drawer nav now
   covers tablet widths too. */
@media (max-width: 900px) {
  :root { --header-h: 64px; }
  .js .nav-toggle { display: flex; }
  .site-header__est { display: none; }
  .site-nav { position: static; }

  /* Base (no-js-safe) appearance: a plain, fully visible dropdown-style
     panel — reachable with zero script. .js below adds the closed/open
     toggle behaviour on top of this same panel. */
  .nav-list {
    position: fixed; inset: var(--header-h) 0 auto 0;
    flex-direction: column; align-items: stretch; gap: 0;
    background: rgba(233,226,214,.98);
    backdrop-filter: blur(18px); -webkit-backdrop-filter: blur(18px);
    border-bottom: 1px solid var(--paper-line);
    padding: 8px var(--gutter) 20px;
    font-size: 12px;
  }
  .nav-list li { border-bottom: 1px solid var(--paper-line); }
  .nav-list a { display: block; padding: 16px 2px; }
  .nav-list__cta { justify-content: space-between; border: 0; border-radius: 0; padding: 16px 2px; }
  .nav-list__cta:hover, .nav-list__cta:focus-visible { background: none; color: var(--copper) !important; }

  /* Only once JS has run does the panel start closed-by-default (and only
     then is there a toggle to open it) — visibility (not just opacity) so
     closed-state links can't be tabbed into (review: AT reachability). */
  .js .nav-list:not(.is-open) {
    opacity: 0; visibility: hidden; pointer-events: none;
    transform: translateY(-8px);
    transition: opacity .28s var(--ease), transform .28s var(--ease), visibility 0s linear .28s;
  }
  .js .nav-list.is-open {
    opacity: 1; visibility: visible; pointer-events: auto; transform: translateY(0);
    transition: opacity .28s var(--ease), transform .28s var(--ease);
  }

  .ticker { grid-template-columns: 1fr; gap: 12px; }
  .ticker__cycler { justify-content: space-between; }
}

@media (max-width: 720px) {
  .process__steps .step { margin-left: 0 !important; }

  .index__row {
    grid-template-columns: 40px minmax(0,1fr) auto;
    grid-template-areas: "num name go" "num cat go2" "num status status";
    row-gap: 6px; padding: 20px 4px;
  }
  a.index__row:hover, a.index__row:focus-visible { padding-left: 12px; }
  .index__num { grid-area: num; align-self: start; }
  .index__name { grid-area: name; }
  .index__cat { grid-area: cat; }
  .index__status { grid-area: status; }
  .index__go { grid-area: go; }
  .index__row--head { display: none; }

  .deals__names { grid-template-columns: 1fr; }
  .deals__name--serif { border-right: 0; border-bottom: 1px solid var(--paper-line); }
  .deals__name--mono { padding-left: 0; }

  .contact__routes { grid-template-columns: 1fr; }
  .route, .route:first-child { padding: 22px 0; border-top: 1px solid var(--paper-line); }
  .route:hover, .route:focus-visible { padding-left: 12px; }

  .site-footer__grid { grid-template-columns: 1fr 1fr; }

  .to-top { right: 16px; bottom: 16px; }
}

@media (max-width: 460px) {
  .hero__actions { flex-direction: column; align-items: stretch; }
  .btn { justify-content: space-between; }
  .site-footer__grid { grid-template-columns: 1fr; }
  .showcase__controls { flex-direction: column; align-items: stretch; gap: 18px; }
  .showcase__arrows { justify-content: flex-end; }
}

/* =========================================================================
   404 — PAGE NOT FOUND (/404.html)

   The same two-column hero logic as the homepage, one step quieter: the
   headline is capped below .hero__title, the sculpture is a close crop rather
   than the full render, and the only motion is a slow light drift and a single
   line reveal.

   The frame has three states because one crop cannot serve all of them:
     - tall desktop   4:5 frame, s-crop-portrait  (close crop, arm leaves frame)
     - short laptop   5:4 frame, s-crop-landscape (a 620px portrait frame does
                      not fit a 595px viewport, and cover-cropping the portrait
                      file into a landscape box trims the S away at the sides)
     - tablet/mobile  shallow frame, s-crop-landscape, decorative labels hidden
   ========================================================================= */
.notfound {
  background: var(--paper); color: var(--ink);
  padding: calc(var(--header-h) + clamp(34px, 5vw, 80px)) var(--gutter) clamp(48px, 6vw, 96px);
  max-width: calc(1400px + 2 * var(--gutter));
  margin-inline: auto;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(260px, .72fr);
  gap: clamp(32px, 5vw, 88px);
  align-items: center;
}

.notfound__copy {
  display: flex; flex-direction: column; align-items: flex-start;
  gap: clamp(16px, 1.8vw, 24px);
  max-width: 620px;
}

/* Deliberately below .hero__title's clamp — an interior page never out-shouts
   the homepage hero. */
.notfound__title {
  font-family: var(--serif); font-weight: 400;
  font-size: clamp(2.2rem, 4vw, 3.6rem);
  line-height: 1.02; letter-spacing: -.028em;
}
/* Same secondary emphasis as every .section-title on the site. */
.notfound__title em { color: rgba(23,18,14,.5); }

/* Matches .section-lead exactly (5.8:1 on --paper). 46ch keeps the measure
   inside the 38–52 character band at every clamp step. */
.notfound__lead {
  font-size: 15px; line-height: 1.7; color: var(--muted-d);
  max-width: 46ch; text-wrap: pretty;
}

.notfound__actions {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: clamp(12px, 1.6vw, 24px);
  margin-top: 4px;
}
/* .btn--underline computes to exactly 44px tall; state it rather than rely on
   the line-height arithmetic staying put. */
.notfound__actions .btn { min-height: 44px; }

/* ---- Route echo -------------------------------------------------------- */
.notfound__route {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 12px;
  font-family: var(--mono); font-size: 10px; letter-spacing: .18em;
  text-transform: uppercase;
  max-width: 100%;
}
.notfound__route-label { color: rgba(23,18,14,.72); }
.notfound__route-value {
  color: var(--copper); text-transform: none; letter-spacing: .04em;
  overflow-wrap: anywhere; min-width: 0;
}

/* ---- Figure ------------------------------------------------------------ */
.notfound__figure {
  position: relative; overflow: hidden;
  aspect-ratio: 4 / 5;
  max-height: min(62vh, 620px);
  width: 100%; margin-left: auto;
  background: var(--paper-2);
  border-radius: 2px;
}
.notfound__figure picture { display: block; height: 100%; }
.notfound__img { width: 100%; height: 100%; object-fit: cover; object-position: 50% 30%; }

/* Slow light drift across the stone. Contained by the frame's overflow. */
.notfound__sheen {
  position: absolute; inset: -18%; pointer-events: none;
  background: radial-gradient(40% 46% at 32% 28%, rgba(255,242,228,.22), rgba(255,242,228,0) 68%);
  mix-blend-mode: screen;
  animation: nf-sheen 26s var(--ease) infinite alternate;
}
@keyframes nf-sheen {
  from { transform: translate3d(-5%, -3%, 0); }
  to   { transform: translate3d(7%, 5%, 0); }
}

/* Bottom scrim. Two jobs: it grounds the crop, and it guarantees the mono
   labels clear AA (7.5:1) whichever crop is showing — the narrow crop puts
   pale wall exactly where the wide crop puts dark stone. */
.notfound__figure::after {
  content: ''; position: absolute; left: 0; right: 0; bottom: 0; height: 34%;
  background: linear-gradient(to bottom, rgba(12,10,8,0), rgba(12,10,8,.72));
  pointer-events: none;
}

/* The interruption: a measuring line that sets out toward the sculpture and
   stops short. The mark itself is never broken, shattered or distorted. */
/* Inset from the frame edge. At left:0 the mono label reads as clipped rather
   than as a deliberate margin note, and the line loses its start. */
.notfound__trace {
  position: absolute; left: clamp(18px, 4%, 26px); bottom: 76px; z-index: 1;
  display: flex; align-items: center;
  width: 52%; max-width: 240px;
  pointer-events: none;
}
.notfound__trace-line {
  display: block; flex: 1; height: 1px; background: var(--copper-lt);
  transform-origin: left center;
  animation: nf-draw 1s .45s var(--ease) both;
}
/* The projected continuation, fading out before it arrives. */
.notfound__trace-gap {
  display: block; width: 46px; height: 1px; flex: none;
  background: linear-gradient(to right, var(--copper-lt), rgba(219,138,87,0));
  animation: nf-draw 1s .75s var(--ease) both;
  transform-origin: left center;
}
@keyframes nf-draw { from { transform: scaleX(0); } to { transform: scaleX(1); } }

.notfound__marker {
  position: absolute; left: clamp(18px, 4%, 26px); bottom: 44px; z-index: 1;
  font-family: var(--mono); font-size: 9px; letter-spacing: .2em;
  text-transform: uppercase; color: var(--cream);
}

/* ---- Entrance ---------------------------------------------------------- */
/* `both` fill matters: the global reduced-motion block collapses the duration
   to .001ms, and the fill is what leaves every element at its visible end
   state instead of stuck at opacity 0. */
.notfound__copy > * { animation: nf-rise .7s var(--ease) both; }
.notfound__copy > *:nth-child(1) { animation-delay: .04s; }
.notfound__copy > *:nth-child(2) { animation-delay: .12s; }
.notfound__copy > *:nth-child(3) { animation-delay: .20s; }
.notfound__copy > *:nth-child(4) { animation-delay: .28s; }
.notfound__copy > *:nth-child(5) { animation-delay: .36s; }
@keyframes nf-rise {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: none; }
}

/* ---- Short laptop ------------------------------------------------------ */
/* A 14" laptop reports roughly 1150x595 of viewport. A portrait frame cannot
   fit there and keep both CTAs above the fold, so the frame turns landscape
   and <picture> hands over s-crop-landscape to match. */
@media (min-width: 901px) and (max-height: 760px) {
  .notfound { padding-top: calc(var(--header-h) + 28px); padding-bottom: 32px; }
  .notfound__figure { aspect-ratio: 5 / 4; max-height: 56vh; }
  .notfound__trace { bottom: 64px; }
  .notfound__marker { bottom: 34px; }
}

/* ---- Tablet and below -------------------------------------------------- */
@media (max-width: 900px) {
  .notfound {
    grid-template-columns: 1fr;
    gap: clamp(28px, 5vw, 44px);
    align-items: start;
    padding-top: calc(var(--header-h) + 32px);
  }
  .notfound__copy { max-width: none; }
  .notfound__figure { aspect-ratio: auto; margin-inline: auto; }
  .notfound__img { object-position: 50% 42%; }
  /* Purely decorative technical labels — they read as clutter at this width. */
  .notfound__trace, .notfound__marker { display: none; }
  .notfound__figure::after { height: 24%; }
}

/* Tablet needs its own frame width, not just its own height. A full-width
   frame at 768px is 734x430 — a 1.7 ratio against a 1.23 file, so object-fit
   would throw away a third of the sculpture's height and take the top arm with
   it. Capping the width keeps the frame near the crop's own proportions. */
@media (min-width: 601px) and (max-width: 900px) {
  .notfound__figure { height: clamp(300px, 42vh, 440px); max-width: 620px; }
}

@media (max-width: 600px) {
  .notfound__figure { height: clamp(210px, 36vh, 320px); }
}

@media (max-width: 460px) {
  /* Matches the homepage's mobile button system. */
  .notfound__actions { flex-direction: column; align-items: stretch; width: 100%; }
  .notfound__actions .btn { justify-content: space-between; }
}

/* =========================================================================
   REDUCED MOTION
   ========================================================================= */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
  .ticker__track { animation: none; transform: none; }
}

/* Print */
@media print {
  .scroll-progress, .section-rail, .to-top, .nav-toggle { display: none !important; }
  body { background: #fff; color: #000; }
}
