/* ==========================================================================
   Nitta Digital — core stylesheet
   Light editorial system. Oversized grotesk display type on warm paper,
   cyan hairline accent carried through from the logo mark.
   ========================================================================== */

/* Fonts load from a <link> in each page's <head>, NOT an @import here.
   An @import inside this file can only be discovered after this file has been
   fetched and parsed, which serialises the chain: HTML → CSS → font CSS →
   font files, with nothing overlapping. The <link> starts the font request
   alongside this stylesheet instead. Don't move it back. */

/* --------------------------------------------------------------------------
   1. Tokens
   -------------------------------------------------------------------------- */

:root {
  /* Colour — warm paper base, near-black ink, cyan reserved for hairlines.
     Contrast against --paper (measured): ink-2 6.67:1, ink-3 4.57:1 — both
     clear AA for the small text they carry. The accent is only 2.18:1 on
     paper, so it is never used for text: hairlines and dots only. */
  --paper:      #F4F3F0;
  --paper-2:    #EDEAE3;
  --sand:       #E3DED3;  /* warm mid-tone band */
  --surface:    #FBFAF8;  /* raised card, warmer than pure white */
  --ink:        #0B0B0C;
  --ink-2:      #55555B;
  --ink-3:      #6E6E74;
  --line:       #DEDCD6;
  --line-soft:  #E8E6E1;
  --line-sand:  #CFC8B9;  /* borders that read on --sand */
  --accent:     #0FB6D6;
  --dark:       #0B0B0C;
  --on-dark:    #F4F3F0;
  --on-dark-2:  #9A9A9F;
  --danger:     #C0392B;

  /* Spacing — spacious scale */
  --s-1:  8px;
  --s-2:  16px;
  --s-3:  24px;
  --s-4:  40px;
  --s-5:  64px;
  --s-6:  96px;
  --s-7:  140px;

  /* Layout */
  --gutter: clamp(20px, 5vw, 72px);
  --maxw:   1440px;

  /* Type */
  --font-display: 'Archivo', 'Helvetica Neue', Helvetica, Arial, sans-serif;
  --font-body:    'Space Grotesk', 'Helvetica Neue', Helvetica, Arial, sans-serif;
  /* Third voice: used only for quotes, numerals and asides — the editorial
     counterweight to all that bold grotesk. Never for UI or body copy. */
  --font-accent:  'Instrument Serif', 'Iowan Old Style', Georgia, serif;

  /* Motion */
  --ease:      cubic-bezier(0.22, 1, 0.36, 1);
  --ease-in:   cubic-bezier(0.55, 0, 1, 0.45);
  /* Overshoots slightly on the way in — the "pop" in pop-out */
  --spring:    cubic-bezier(0.34, 1.56, 0.64, 1);
  --dur-fast:  180ms;
  --dur:       320ms;
  --dur-slow:  620ms;

  /* Elevation / layers.
     The nav sits ABOVE the drawer on purpose: the toggle becomes the close
     button, so it has to stay visible and clickable while the menu is open. */
  --z-rail:    20;
  --z-menu:    40;
  --z-nav:     50;
  /* Above the nav so it is never clipped, below the veil so a page
     transition covers it like everything else. */
  --z-cursor:  90;
  --z-overlay: 100;
}

/* --------------------------------------------------------------------------
   2. Reset & base
   -------------------------------------------------------------------------- */

*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: 16px;
  font-weight: 400;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;
}

body.is-locked { overflow: hidden; }

/* Film grain over the whole page. Large flat fields of one colour are what
   read as "cheap"; a little tooth stops the paper looking like a screenshot.
   Fixed, non-interactive, and above everything so tints get it too. */
body::after {
  content: '';
  position: fixed;
  inset: 0;
  z-index: 500;
  pointer-events: none;
  opacity: 0.5;
  background-repeat: repeat;
  background-size: 180px 180px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='4' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23n)' opacity='0.055'/%3E%3C/svg%3E");
}

/* height:auto matters: the width/height HTML attributes land as presentational
   hints, so an <img width="500" height="500"> that CSS resizes by width alone
   stays 500px tall and stretches. Anything needing a fixed height sets one. */
img { max-width: 100%; height: auto; display: block; }

a {
  color: inherit;
  text-decoration: none;
}

button {
  font: inherit;
  color: inherit;
  border: 0;
  background: none;
  cursor: pointer;
}

/* Browsers default <figure> to `margin: 1em 40px`, which silently narrows
   any figure that isn't explicitly reset. */
figure { margin: 0; }

h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-weight: 600;
  letter-spacing: -0.03em;
  line-height: 0.98;
  margin: 0;
  text-wrap: balance;
}

p { margin: 0; }

::selection {
  background: var(--ink);
  color: var(--paper);
}

/* Focus — never removed, only restyled */
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: 2px;
}

/* Present for screen readers, absent for everyone else */
.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: absolute;
  top: -100px;
  left: var(--gutter);
  z-index: calc(var(--z-overlay) + 1);
  padding: 12px 20px;
  background: var(--ink);
  color: var(--paper);
  font-size: 13px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  transition: top var(--dur) var(--ease);
}
.skip-link:focus { top: 16px; }

/* --------------------------------------------------------------------------
   3. Layout primitives
   -------------------------------------------------------------------------- */

.wrap {
  width: 100%;
  max-width: var(--maxw);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.section {
  padding-block: clamp(var(--s-6), 12vw, var(--s-7));
}

.section--tight { padding-block: clamp(var(--s-5), 8vw, var(--s-6)); }

/* ---- Tonal bands. Sections declare their own ground so the page moves
        through paper → tint → sand → ink instead of one flat field. ---- */
.section--tint {
  background: var(--paper-2);
  border-block: 1px solid var(--line);
}


/* Faint column rules — structure you feel more than read */
.section--ruled {
  background-image: linear-gradient(to right, var(--line-soft) 1px, transparent 1px);
  background-size: 25% 100%;
  background-position: 0 0;
}

/* Raised panel */
.card {
  background: var(--surface);
  border: 1px solid var(--line);
  padding: clamp(var(--s-3), 3vw, var(--s-4));
}

.rule {
  height: 1px;
  background: var(--line);
  border: 0;
  margin: 0;
}

/* --------------------------------------------------------------------------
   3b. Wash — a slow tonal drift behind the plain areas
   Sits at z-index -1: above the page canvas, below every block background.
   So it fills the bare paper and is politely covered by the tinted, sand and
   ink bands — colour where the page is empty, nothing where it isn't.
   -------------------------------------------------------------------------- */

.wash {
  position: fixed;
  inset: 0;
  z-index: -1;
  overflow: hidden;
  pointer-events: none;
}

.wash__blob {
  position: absolute;
  display: block;
  border-radius: 50%;
  filter: blur(70px);
  will-change: transform;
}

.wash__blob--1 {
  width: 62vw;
  height: 62vw;
  left: -18vw;
  top: -14vw;
  background: radial-gradient(circle at 50% 50%, rgba(15, 182, 214, 0.13), rgba(15, 182, 214, 0) 68%);
  animation: wash-a 34s ease-in-out infinite alternate;
}

.wash__blob--2 {
  width: 54vw;
  height: 54vw;
  right: -14vw;
  top: 34vh;
  background: radial-gradient(circle at 50% 50%, rgba(92, 86, 72, 0.16), rgba(92, 86, 72, 0) 68%);
  animation: wash-b 44s ease-in-out infinite alternate;
}

.wash__blob--3 {
  width: 46vw;
  height: 46vw;
  left: 26vw;
  bottom: -20vw;
  background: radial-gradient(circle at 50% 50%, rgba(15, 182, 214, 0.09), rgba(15, 182, 214, 0) 68%);
  animation: wash-a 52s ease-in-out infinite alternate-reverse;
}

@keyframes wash-a {
  from { transform: translate3d(0, 0, 0) scale(1); }
  to   { transform: translate3d(6vw, 4vh, 0) scale(1.14); }
}
@keyframes wash-b {
  from { transform: translate3d(0, 0, 0) scale(1.08); }
  to   { transform: translate3d(-5vw, -6vh, 0) scale(1); }
}

/* --------------------------------------------------------------------------
   4. Type utilities
   -------------------------------------------------------------------------- */

.eyebrow {
  font-family: var(--font-body);
  font-size: clamp(10px, 1vw, 11px);
  font-weight: 400;
  letter-spacing: 0.32em;
  text-transform: uppercase;
  color: var(--ink-3);
  line-height: 1.5;
}

.eyebrow--rule {
  display: inline-flex;
  align-items: center;
  gap: 12px;
}
.eyebrow--rule::before {
  content: '';
  width: 28px;
  height: 1px;
  background: var(--accent);
  flex: none;
}


.h2 {
  font-size: clamp(32px, 5.2vw, 68px);
  line-height: 0.98;
  letter-spacing: -0.035em;
}

.h3 {
  font-size: clamp(22px, 2.6vw, 34px);
  line-height: 1.08;
  letter-spacing: -0.02em;
}

.lede {
  font-size: clamp(17px, 1.5vw, 21px);
  line-height: 1.65;
  color: var(--ink-2);
  max-width: 56ch;
}

.body {
  font-size: 16px;
  line-height: 1.7;
  color: var(--ink-2);
  max-width: 62ch;
}

.body + .body { margin-top: var(--s-3); }

.body strong {
  color: var(--ink);
  font-weight: 500;
}

.mono {
  font-size: 12px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-3);
  font-variant-numeric: tabular-nums;
}

/* ---- Serif accent voice ---- */


/* ---- Intro: the paragraph and the facts, side by side ---- */
.intro {
  display: grid;
  gap: var(--s-4);
  align-items: start;
}

.intro__lede .lede { max-width: 44ch; }

.mini {
  margin: var(--s-3) 0 0;
  padding: 0;
}
.mini > div {
  display: grid;
  gap: 2px;
  padding: 14px 0;
  border-top: 1px solid var(--line);
}
.mini > div:first-child { border-top: 0; padding-top: 0; }
.mini dt {
  font-size: 10px;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.mini dd {
  margin: 0;
  font-size: 15px;
  line-height: 1.45;
  color: var(--ink);
}

/* --------------------------------------------------------------------------
   5. Buttons & links
   -------------------------------------------------------------------------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  min-height: 52px;
  padding: 0 30px;
  font-family: var(--font-body);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  cursor: pointer;
  border: 1px solid var(--ink);
  background: var(--ink);
  color: var(--paper);
  transition:
    background var(--dur) var(--ease),
    color var(--dur) var(--ease),
    transform var(--dur-fast) var(--ease);
}
.btn:hover { background: #26262A; border-color: #26262A; }
.btn:active { transform: scale(0.985); }


.btn--on-dark {
  background: var(--paper);
  color: var(--ink);
  border-color: var(--paper);
}
.btn--on-dark:hover { background: #FFFFFF; border-color: #FFFFFF; }

.btn[disabled],
.btn[aria-disabled='true'] {
  opacity: 0.45;
  cursor: not-allowed;
  pointer-events: none;
}

/* Underline link with a wipe-in rule */
.link {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding-block: 4px;
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  cursor: pointer;
}

/* Reach the 44px touch minimum by growing the hit area outward, rather than
   padding the box — padding would drag the underline away from the text. */
.link::before {
  content: '';
  position: absolute;
  inset: -11px -8px;
}
.link::after {
  content: '';
  position: absolute;
  left: 0;
  bottom: 0;
  width: 100%;
  height: 1px;
  background: currentColor;
  transform-origin: right;
  transform: scaleX(1);
  transition: transform var(--dur) var(--ease);
}
.link:hover::after {
  transform-origin: left;
  animation: link-wipe var(--dur-slow) var(--ease);
}
@keyframes link-wipe {
  0%   { transform: scaleX(1); transform-origin: right; }
  49%  { transform: scaleX(0); transform-origin: right; }
  50%  { transform: scaleX(0); transform-origin: left; }
  100% { transform: scaleX(1); transform-origin: left; }
}
.link svg { transition: transform var(--dur) var(--ease); }
.link:hover svg { transform: translateX(4px); }

/* --------------------------------------------------------------------------
   6. Navigation
   -------------------------------------------------------------------------- */

.nav {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: var(--z-nav);
  transition:
    background var(--dur) var(--ease),
    border-color var(--dur) var(--ease),
    transform var(--dur-slow) var(--ease);
  border-bottom: 1px solid transparent;
}

.nav.is-stuck {
  background: rgba(244, 243, 240, 0.82);
  backdrop-filter: saturate(180%) blur(14px);
  -webkit-backdrop-filter: saturate(180%) blur(14px);
  border-bottom-color: var(--line);
}

/* Hide on scroll-down, reveal on scroll-up */
.nav.is-hidden { transform: translate3d(0, -100%, 0); }

.nav__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-3);
  min-height: 76px;
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  padding: 6px 0;
}

.brand__chip {
  width: 34px;
  height: 34px;
  border-radius: 5px;
  flex: none;
  object-fit: cover;
  transition: transform var(--dur) var(--ease);
}
.brand:hover .brand__chip { transform: rotate(-4deg) scale(1.04); }

.brand__word {
  font-family: var(--font-display);
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  white-space: nowrap;
}

.nav__links {
  display: flex;
  align-items: center;
  gap: var(--s-4);
}

.nav__link {
  position: relative;
  padding: 8px 2px;
  font-size: 12px;
  font-weight: 400;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-2);
  transition: color var(--dur) var(--ease);
}
/* Hit area to 44px without shifting the bar's rhythm */
.nav__link::before {
  content: '';
  position: absolute;
  inset: -6px -8px;
}
.nav__link::after {
  content: '';
  position: absolute;
  left: 0;
  bottom: 2px;
  width: 100%;
  height: 1px;
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: right;
  transition: transform var(--dur) var(--ease);
}
.nav__link:hover { color: var(--ink); }
.nav__link:hover::after,
.nav__link[aria-current='page']::after {
  transform: scaleX(1);
  transform-origin: left;
}
.nav__link[aria-current='page'] { color: var(--ink); }

.nav__cta {
  display: inline-flex;
  transition:
    opacity var(--dur) var(--ease),
    transform var(--dur) var(--ease),
    visibility 0s linear 0s;
}

/* Two identical calls to action on one screen is one too many. While the
   hero's own tile is visible, the nav steps aside. visibility (not just
   opacity) so it also leaves the tab order while it's gone. */
.nav.has-hero-cta .nav__cta {
  opacity: 0;
  visibility: hidden;
  transform: translateY(-8px);
  pointer-events: none;
  transition:
    opacity var(--dur) var(--ease),
    transform var(--dur) var(--ease),
    visibility 0s linear var(--dur);
}

/* Mobile menu toggle */
.nav__toggle {
  display: none;
  width: 48px;
  height: 48px;
  margin-right: -12px;
  align-items: center;
  justify-content: center;
}
.nav__toggle span {
  display: block;
  position: relative;
  width: 22px;
  height: 1px;
  background: var(--ink);
  transition: background var(--dur-fast) var(--ease);
}
.nav__toggle span::before,
.nav__toggle span::after {
  content: '';
  position: absolute;
  left: 0;
  width: 22px;
  height: 1px;
  background: var(--ink);
  transition: transform var(--dur) var(--ease);
}
.nav__toggle span::before { top: -7px; }
.nav__toggle span::after  { top: 7px; }

.nav__toggle[aria-expanded='true'] span { background: transparent; }
.nav__toggle[aria-expanded='true'] span::before { transform: translateY(7px) rotate(45deg); }
.nav__toggle[aria-expanded='true'] span::after  { transform: translateY(-7px) rotate(-45deg); }

/* Mobile drawer */
.menu {
  position: fixed;
  inset: 0;
  z-index: var(--z-menu);
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: var(--gutter);
  background: var(--paper);
  transform: translate3d(0, -100%, 0);
  transition: transform var(--dur-slow) var(--ease);
  visibility: hidden;
}
.menu.is-open {
  transform: translate3d(0, 0, 0);
  visibility: visible;
}

.menu__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
}

.menu__link {
  display: block;
  padding: 10px 0;
  font-family: var(--font-display);
  font-size: clamp(38px, 12vw, 64px);
  font-weight: 600;
  letter-spacing: -0.04em;
  text-transform: uppercase;
  line-height: 1;
  opacity: 0;
  transform: translate3d(0, 24px, 0);
  transition:
    opacity var(--dur-slow) var(--ease),
    transform var(--dur-slow) var(--ease);
}
.menu.is-open .menu__link {
  opacity: 1;
  transform: none;
  transition-delay: calc(90ms + var(--i, 0) * 60ms);
}
.menu__link[aria-current='page'] { color: var(--ink-3); }

.menu__foot {
  margin-top: var(--s-5);
  padding-top: var(--s-2);
  border-top: 1px solid var(--line);
  display: flex;
  flex-direction: column;
}

.menu__foot p { padding-block: 6px; }

.menu__foot a {
  display: inline-block;
  padding-block: 14px; /* 16px line + 28px = 44px touch target */
}

/* --------------------------------------------------------------------------
   7. Scroll rail (desktop progress ticks)
   -------------------------------------------------------------------------- */

.rail {
  position: fixed;
  top: 50%;
  right: 26px;
  z-index: var(--z-rail);
  transform: translateY(-50%);
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 14px;
}

.rail__tick {
  display: block;
  width: 22px;
  height: 1px;
  background: var(--ink);
  opacity: 0.18;
  transition:
    width var(--dur) var(--ease),
    opacity var(--dur) var(--ease),
    background var(--dur) var(--ease);
}
.rail__tick.is-active {
  width: 38px;
  opacity: 1;
  background: var(--accent);
}

/* --------------------------------------------------------------------------
   7b. Cursor ring
   A hairline that trails the pointer a beat behind. Cyan, like every other
   hairline on the page. Mouse-only and motion-optional: the element is never
   built otherwise, so there is nothing here to switch off.
   -------------------------------------------------------------------------- */

.cursor {
  position: fixed;
  top: 0;
  left: 0;
  width: 26px;
  height: 26px;
  margin: -13px 0 0 -13px;  /* centre on the origin, so translate = position */
  border: 1px solid var(--accent);
  border-radius: 50%;
  z-index: var(--z-cursor);
  /* It follows the cursor — it must never be the thing the cursor hits. */
  pointer-events: none;
  opacity: 0;
  /* Opacity only. The transform belongs to the rAF loop and must not be
     transitioned, or it would fight the lerp and drag the ring further behind. */
  transition: opacity var(--dur) var(--ease);
  will-change: transform;
}
.cursor.is-awake { opacity: 0.5; }

/* Over something clickable: widen and drop the fill to a tint, so the ring
   reads as "this responds" rather than as decoration. */
.cursor.is-live {
  opacity: 0.9;
  background: color-mix(in srgb, var(--accent) 12%, transparent);
}

/* --------------------------------------------------------------------------
   8. Reveal animations
   -------------------------------------------------------------------------- */

[data-reveal] {
  opacity: 0;
  transform: translate3d(0, 28px, 0);
  transition:
    opacity 900ms var(--ease),
    transform 900ms var(--ease);
  transition-delay: var(--delay, 0ms);
  will-change: opacity, transform;
}
[data-reveal].is-in {
  opacity: 1;
  transform: none;
}
[data-reveal].is-in { will-change: auto; }

/* Clip-reveal for images */

/* Masked line reveal (hero) */
.mask {
  display: block;
  overflow: hidden;
}
.mask__inner {
  display: block;
  transform: translate3d(0, 110%, 0);
  transition: transform 1100ms var(--ease);
  transition-delay: var(--delay, 0ms);
}
.is-ready .mask__inner { transform: translate3d(0, 0, 0); }

/* --------------------------------------------------------------------------
   9. Hero
   -------------------------------------------------------------------------- */

.hero {
  position: relative;
  display: flex;
  flex-direction: column;
  /* Top-anchored and sized to its content. Forcing 100svh and centring left
     ~180px of dead air above the wordmark and ~200px below it; the hero is
     only ~440px of actual content, so the viewport was padding, not design.
     Letting the next section crest the fold also gives a reason to scroll. */
  justify-content: flex-start;
  padding-top: 104px; /* clears the fixed nav, nothing more */
  padding-bottom: clamp(56px, 9vh, 104px);
  overflow: hidden;
}

.hero__grid {
  position: relative;
  z-index: 1; /* above the splatter */
  display: grid;
  /* Gap tracks viewport height so the hero still fits a short laptop */
  gap: clamp(24px, 4vh, 56px);
  align-items: center;
  width: 100%;
}


/* ---- Droplets ----
   Individually generated blobs (see initDrops), each its own element with
   its own outline. Nothing here is cut from a photograph, so no droplet
   repeats and each one smudges on its own terms. */
.drops {
  position: absolute;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
}

.drop {
  position: absolute;
  display: block;
  /* left/top place the droplet's centre, not its corner */
  translate: -50% -50%;
  will-change: transform, filter;
}

.drop svg {
  display: block;
  width: 100%;
  height: 100%;
  overflow: visible;
}

.drop path { fill: var(--ink); }


/* ---- Ink edges ----
   Built by initInk. The black surfaces on this site are ink, so they bleed
   where they meet paper instead of stopping at a ruled line. The bleed sits
   OUTSIDE its host's box (bottom/top: 100%), so it never touches the padding
   the content lives in and can't push text around. */
.ink {
  position: absolute;
  left: 0;
  right: 0;
  height: clamp(30px, 4.4vw, 56px);
  pointer-events: none;
  /* No overflow:hidden — the whole point is that ink escapes the box. */
}
.ink--top    { bottom: 100%; }
/* Same pour, turned over. Flipping the wrapper rather than generating a
   second shape keeps the two edges of a band feeling cut from one spill. */
.ink--bottom { top: 100%; transform: scaleY(-1); }

.ink__edge {
  position: absolute;
  left: 0;
  right: 0;
  bottom: -1px;  /* laps the host by a pixel to kill the subpixel seam */
  width: 100%;
  height: 72%;
  display: block;
}
.ink__edge path { fill: var(--dark); }

.ink__spot {
  position: absolute;
  display: block;
  translate: -50% 0;
}
.ink__spot svg {
  display: block;
  width: 100%;
  height: 100%;
  overflow: visible;
}
.ink__spot path { fill: var(--dark); }

/* The hosts. Both are full-bleed black slabs; relative positioning is what
   lets the ink hang off them. */
.band,
.foot { position: relative; }

.hero__intro {
  font-family: var(--font-body);
  font-size: clamp(11px, 1.05vw, 12px);
  letter-spacing: 0.28em;
  text-transform: uppercase;
  line-height: 2.1;
  color: var(--ink-2);
}
.hero__intro span { display: block; }


/* The oversized wordmark.
   "DIGITAL" measures ~3.63x the font-size in Archivo Bold, so every size here
   is derived from that ratio rather than eyeballed. Stacked single column
   (mobile/tablet) it fills the full measure; from 1024px up the hero splits
   and it only owns the left 7/12, so the desktop rule below shrinks it to
   match. Re-measure if the font or letter-spacing ever changes — the last
   letter clips silently. */
.hero__word {
  font-family: var(--font-display);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: -0.055em;
  line-height: 0.82;
  font-size: clamp(46px, min(23vw, 31vh), 352px);
  margin: 0;
  transform-origin: left bottom;
}

/* ---- Hero tiles: the three destinations ---- */
.hero__nav {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.tile {
  position: relative;
  display: grid;
  /* Explicit areas, not auto-placement: the row-spanning number and arrow
     otherwise push the label into the wrong column. */
  grid-template-columns: auto 1fr auto;
  grid-template-areas:
    'n label arrow'
    'n desc  arrow';
  align-items: center;
  gap: 4px 18px;
  padding: 20px 22px;
  min-height: 88px;
  overflow: hidden;
  background: var(--surface);
  border: 1px solid var(--ink);
  color: var(--ink);
  cursor: pointer;
  transition: color var(--dur) var(--ease), transform var(--dur) var(--ease);
}

/* Ink washes up the tile on hover rather than a flat colour swap */
.tile::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 0;
  background: var(--ink);
  transform: scaleY(0);
  transform-origin: bottom;
  transition: transform 420ms var(--ease);
}
.tile:hover::before,
.tile:focus-visible::before { transform: scaleY(1); }

.tile > * { position: relative; z-index: 1; }

.tile:hover,
.tile:focus-visible { color: var(--paper); }
.tile:active { transform: scale(0.99); }

.tile__n {
  grid-area: n;
  align-self: center;
  font-family: var(--font-accent);
  font-size: 26px;
  line-height: 1;
  color: currentColor;
  opacity: 0.5;
  font-variant-numeric: tabular-nums;
}

.tile__label {
  grid-area: label;
  align-self: end;
  font-family: var(--font-display);
  font-size: clamp(19px, 1.6vw, 23px);
  font-weight: 600;
  letter-spacing: -0.02em;
  line-height: 1.1;
}

.tile__desc {
  grid-area: desc;
  align-self: start;
  font-size: 13px;
  line-height: 1.4;
  color: var(--ink-3);
  transition: color var(--dur) var(--ease);
}
.tile:hover .tile__desc,
.tile:focus-visible .tile__desc { color: var(--on-dark-2); }

.tile__arrow {
  grid-area: arrow;
  align-self: center;
  transition: transform var(--dur) var(--ease);
}
.tile:hover .tile__arrow,
.tile:focus-visible .tile__arrow { transform: translateX(5px); }
.hero__word span { display: block; }

/* Second line optically nudged to sit under the first */
.hero__word .is-indent { padding-left: 0.06em; }




/* --------------------------------------------------------------------------
   11b. Step cards — fan in on entry, pop forward on hover
   Same shape as the gallery it's modelled on: staggered spring entrance,
   resting tilt, lift-and-straighten on hover. Cards hold copy rather than
   photos, so they only overlap slightly and never cover each other's text.
   -------------------------------------------------------------------------- */

.cards {
  display: grid;
  gap: var(--s-2);
}

.card-step {
  position: relative;
  z-index: 1;
  background: var(--surface);
  border: 1px solid var(--ink);
  padding: clamp(20px, 2.4vw, 30px);
  opacity: 0;
  transform: translate3d(0, 46px, 0) scale(0.94);
  transition:
    opacity 640ms var(--ease),
    transform 720ms var(--spring),
    box-shadow 380ms var(--ease);
  transition-delay: calc(var(--i, 0) * 110ms);
  will-change: transform, opacity;
}

.cards.is-in .card-step {
  opacity: 1;
  transform: translate3d(0, 0, 0) scale(1) rotate(var(--r, 0deg));
}

/* Must out-specify `.cards.is-in .card-step`, or the resting tilt wins
   and the hover never lands. */
.cards.is-in .card-step:hover,
.cards.is-in .card-step:focus-within {
  z-index: 10;
  transform: translate3d(0, -14px, 0) scale(1.05) rotate(0deg);
  box-shadow: 0 40px 70px -28px rgba(11, 11, 12, 0.5);
  transition-delay: 0ms;
}

.card-step__n {
  font-family: var(--font-accent);
  font-size: 40px;
  line-height: 1;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}

.card-step__label {
  display: block;
  margin: 12px 0 8px;
  font-size: 10px;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.card-step h3 {
  font-size: clamp(19px, 1.5vw, 22px);
  line-height: 1.15;
  margin-bottom: 10px;
}

.card-step p {
  font-size: 14px;
  line-height: 1.6;
  color: var(--ink-2);
}

.card-step__rule {
  display: block;
  width: 26px;
  height: 2px;
  background: var(--accent);
  margin-bottom: 4px;
}

/* --------------------------------------------------------------------------
   12. Service block
   -------------------------------------------------------------------------- */

.service {
  display: grid;
  gap: var(--s-4);
}

.service__head {
  display: grid;
  align-items: end;
  gap: var(--s-4);
}

.service__title {
  font-size: clamp(38px, 7vw, 96px);
  line-height: 0.94;
  letter-spacing: -0.045em;
  text-transform: uppercase;
  font-weight: 600;
}

.tags {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  padding: 0;
  margin: 0;
  list-style: none;
}
.tags li {
  padding: 8px 16px;
  border: 1px solid var(--line);
  border-radius: 999px;
  font-size: 11px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-2);
}

/* --------------------------------------------------------------------------
   13. Dark statement band
   -------------------------------------------------------------------------- */

.band {
  background: var(--dark);
  color: var(--on-dark);
  padding-block: clamp(var(--s-6), 14vw, 180px);
}
.band .eyebrow { color: var(--on-dark-2); }
.band .body    { color: var(--on-dark-2); }
.band .lede    { color: var(--on-dark-2); }

.band__quote {
  font-family: var(--font-accent);
  font-size: clamp(34px, 5.4vw, 76px);
  font-weight: 400;
  line-height: 1.08;
  letter-spacing: -0.01em;
  max-width: 18ch;
}

.band__grid {
  display: grid;
  gap: var(--s-5);
  margin-top: var(--s-5);
}

/* --------------------------------------------------------------------------
   14. CTA
   -------------------------------------------------------------------------- */



/* --------------------------------------------------------------------------
   15. About page
   -------------------------------------------------------------------------- */




.figure {
  margin: 0;
}


.figure__cap {
  margin-top: var(--s-2);
  padding-top: var(--s-2);
  border-top: 1px solid var(--line);
  font-size: 14px;
  line-height: 1.65;
  color: var(--ink-2);
  max-width: 46ch;
}
.figure__cap em {
  font-family: var(--font-accent);
  font-style: italic;
  font-size: 19px;
  line-height: 1.4;
  color: var(--ink);
}


/* --------------------------------------------------------------------------
   15b. About hero — type and photo set against each other
   -------------------------------------------------------------------------- */

.about-hero {
  position: relative;
  padding-top: 150px;
  padding-bottom: clamp(var(--s-5), 8vw, var(--s-6));
}

.about-hero__grid {
  display: grid;
  gap: var(--s-4);
  align-items: center;
}

.about-hero__name {
  font-family: var(--font-display);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: -0.05em;
  line-height: 0.86;
  font-size: clamp(44px, 8.4vw, 128px);
  margin: var(--s-3) 0 0;
}

.about-hero__meta {
  margin-top: var(--s-4);
  padding-top: var(--s-3);
  border-top: 1px solid var(--line);
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-1) var(--s-3);
}

/* --------------------------------------------------------------------------
   15c. Living photos — parallax shell, tilted inner, cursor sheen
   The three jobs sit on three elements on purpose: parallax writes transform
   on .photo, tilt writes transform on .photo__inner, and the collage angle
   uses the standalone `rotate` property so it composes with both instead of
   being overwritten.
   -------------------------------------------------------------------------- */

.photo {
  position: relative;
  perspective: 1000px;
  will-change: transform;
}

.photo__inner {
  position: relative;
  overflow: hidden;
  background: var(--paper-2);
  transform-style: preserve-3d;
  box-shadow: 0 1px 3px rgba(11, 11, 12, 0.05);
  transition: box-shadow 600ms var(--ease);
  will-change: transform;
}

.photo:hover .photo__inner {
  box-shadow: 0 34px 70px -26px rgba(11, 11, 12, 0.34);
}

.photo__inner img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* Light follows the cursor across the surface */
.photo__sheen {
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  opacity: 0;
  transition: opacity 500ms var(--ease);
  background: radial-gradient(
    340px circle at var(--mx, 50%) var(--my, 50%),
    rgba(255, 255, 255, 0.22),
    rgba(255, 255, 255, 0) 62%
  );
}
.photo:hover .photo__sheen { opacity: 1; }

.photo--angled { rotate: -1.6deg; }

.about-hero__photo {
  position: relative;
}
.about-hero__photo .photo__inner { aspect-ratio: 4 / 3; }
.about-hero__photo .photo__inner img { object-position: center 30%; }

.photo__tag {
  position: absolute;
  z-index: 3;
  bottom: -14px;
  left: -14px;
  padding: 10px 16px;
  background: var(--ink);
  color: var(--paper);
  font-size: 10px;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  white-space: nowrap;
}

/* --------------------------------------------------------------------------
   15d. Expand — the photo starts as a slice on the right and opens leftward
   over the copy. The image spans the whole block and never moves; only the
   clip travels, so faces stay put instead of sliding as it widens.
   --w is the single source of truth for the clip, the seam and the handle.
   -------------------------------------------------------------------------- */

.expand {
  --w: 44%;
  position: relative;
  aspect-ratio: 16 / 10;
  min-height: 520px;
}

.expand__text {
  position: absolute;
  inset: 0 auto 0 0;
  z-index: 1;
  width: 54%;
  padding-right: var(--s-4);
  display: flex;
  flex-direction: column;
  justify-content: center;
}

.expand__media {
  position: absolute;
  inset: 0;
  z-index: 2;
  overflow: hidden;
  background: var(--paper-2);
  clip-path: inset(0 0 0 calc(100% - var(--w)));
  transition: clip-path 240ms var(--ease);
}

.expand__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 34%;
  pointer-events: none;
  -webkit-user-drag: none;
}

/* The border and shadow can't live on .expand__media: clip-path clips an
   element's own shadow, so it would never render. This frame traces the same
   rectangle as the clip but is never clipped itself, so the photo casts a
   real shadow across the copy underneath and reads as lifted off the page. */
.expand__frame {
  position: absolute;
  top: 0;
  bottom: 0;
  right: 0;
  left: calc(100% - var(--w));
  z-index: 3;
  pointer-events: none;
  border: 1px solid var(--ink);
  box-shadow:
    0 2px 6px rgba(11, 11, 12, 0.10),
    -18px 30px 60px -24px rgba(11, 11, 12, 0.42),
    -40px 70px 120px -50px rgba(11, 11, 12, 0.34);
  transition: left 240ms var(--ease);
}

.expand__handle {
  position: absolute;
  top: 50%;
  /* At 100% the seam sits at x=0, which would hang half the handle outside
     the photo. Hold it against the edge instead. */
  left: max(30px, calc(100% - var(--w)));
  z-index: 4;
  width: 54px;
  height: 54px;
  margin: -27px 0 0 -27px;
  border-radius: 50%;
  background: var(--paper);
  color: var(--ink);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: ew-resize;
  touch-action: none;
  box-shadow: 0 6px 22px -6px rgba(11, 11, 12, 0.45);
  transition: left 240ms var(--ease), transform var(--dur) var(--ease);
}
.expand__handle:hover { transform: scale(1.09); }
.expand__handle:active { transform: scale(0.97); }
.expand__handle:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }

/* While dragging, the slider must track the finger exactly — easing here
   would feel like lag rather than polish. */
.expand.is-dragging .expand__media,
.expand.is-dragging .expand__frame,
.expand.is-dragging .expand__handle { transition: none; }

.expand__hint {
  position: absolute;
  top: 50%;
  left: max(64px, calc(100% - var(--w)));
  z-index: 4;
  margin-top: 40px;
  transform: translateX(-50%);
  padding: 8px 14px;
  background: rgba(11, 11, 12, 0.82);
  color: var(--paper);
  font-size: 10px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  white-space: nowrap;
  pointer-events: none;
  transition: opacity 400ms var(--ease), left 240ms var(--ease);
}
.expand.is-touched .expand__hint { opacity: 0; }

/* --------------------------------------------------------------------------
   15e. Pin — three panels sharing one screen, advanced by scroll
   The section is tall so there is scroll to spend; the inner sticky layer is
   one viewport, so it occupies 3 screens of scrolling but only ever shows one.
   -------------------------------------------------------------------------- */

.pin {
  position: relative;
  height: 300vh;
  background: var(--sand);
  border-block: 1px solid var(--line-sand);
}

.pin__sticky {
  position: sticky;
  top: 0;
  height: 100svh;
  display: flex;
  align-items: center;
  overflow: hidden;
}

.pin__grid {
  display: grid;
  gap: var(--s-4);
  width: 100%;
  align-items: center;
}

.pin__side {
  display: flex;
  flex-direction: column;
  gap: var(--s-3);
}
.pin__side .eyebrow { color: #5C5648; }
.pin__side .eyebrow--rule::before { background: var(--ink); }

.pin__count {
  display: flex;
  align-items: baseline;
  gap: 8px;
  font-family: var(--font-accent);
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.pin__count b {
  font-size: clamp(56px, 7vw, 92px);
  font-weight: 400;
  line-height: 0.9;
}
.pin__count span { font-size: 18px; color: #5C5648; }

.pin__bar {
  position: relative;
  width: 100%;
  max-width: 230px;
  height: 1px;
  background: rgba(11, 11, 12, 0.16);
  overflow: hidden;
}
.pin__bar i {
  position: absolute;
  inset: 0;
  background: var(--ink);
  transform: scaleX(0.333);
  transform-origin: left;
  transition: transform 500ms var(--ease);
}

.pin__steps {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.pin__steps li {
  font-size: 11px;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  /* 0.62 not 0.34: the lighter tint measured 2.19:1 on sand. Inactive still
     reads as inactive via weight and the indent, not by being unreadable. */
  color: rgba(11, 11, 12, 0.62);
  font-weight: 400;
  transition: color var(--dur) var(--ease), transform var(--dur) var(--ease);
}
.pin__steps li.is-active {
  color: var(--ink);
  font-weight: 500;
  transform: translateX(6px);
}

/* Grid stacking: every panel occupies the same cell, so the stage sizes to
   the tallest one automatically — no measuring, no absolute positioning. */
.pin__stage { display: grid; }

.pin__panel {
  grid-area: 1 / 1;
  opacity: 0;
  transform: translate3d(0, 28px, 0);
  transition: opacity 520ms var(--ease), transform 520ms var(--ease);
  pointer-events: none;
  background: var(--surface);
  border: 1px solid var(--line-sand);
  padding: clamp(var(--s-3), 3.4vw, var(--s-5));
  box-shadow: 0 30px 60px -34px rgba(11, 11, 12, 0.4);
}
.pin__panel.is-active {
  opacity: 1;
  transform: none;
  pointer-events: auto;
}

.pin__label {
  display: inline-block;
  margin-bottom: var(--s-2);
  padding: 6px 12px;
  background: var(--ink);
  color: var(--paper);
  font-size: 10px;
  letter-spacing: 0.24em;
  text-transform: uppercase;
}

.pin__panel h3 { margin-bottom: var(--s-2); }

/* --------------------------------------------------------------------------
   15b. Portfolio page (placeholder)
   A page with nothing on it yet, which is the honest state of the portfolio.
   So the type carries the whole page and the ink at the footer does the rest —
   no filler, no fake "case studies coming" grid of empty boxes.
   -------------------------------------------------------------------------- */

.soon {
  /* Fills the viewport so the footer lands at the bottom edge rather than
     floating halfway up a short page. svh, not vh: mobile browser chrome. */
  min-height: calc(100svh - 150px);
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding-top: 150px;
  padding-bottom: clamp(var(--s-5), 8vw, var(--s-6));
}

.soon__title {
  font-family: var(--font-display);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: -0.05em;
  line-height: 0.88;
  /* No nowrap here — unlike .contact-hero__title this breaks to three lines,
     so it can size to the viewport without having to clear a single measure. */
  font-size: clamp(44px, 12vw, 172px);
  margin: var(--s-3) 0 0;
}
.soon__title span { display: block; }

.soon__note {
  max-width: 46ch;
  margin-top: var(--s-4);
  color: var(--ink-2);
}

/* --------------------------------------------------------------------------
   16. Contact page
   -------------------------------------------------------------------------- */

/* ---- Contact head: the title carries the page, no standfirst under it ---- */
.contact-hero {
  padding-top: 150px;
  padding-bottom: clamp(var(--s-4), 5vw, var(--s-5));
}

.contact-hero__title {
  /* Measured: "CONTACT ME" is 6.15x the font-size in Archivo Bold. 17vw
     overflowed around 1000px wide — 13.5vw clears the measure at every
     width including 320px, and 200px caps it once .wrap stops growing
     (200 x 6.15 = 1230, inside the 1296 column). */
  font-family: var(--font-display);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: -0.05em;
  line-height: 0.9;
  font-size: clamp(40px, 13.5vw, 200px);
  margin: var(--s-3) 0 0;
  white-space: nowrap;
}

.contact {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--s-5);
  padding-bottom: clamp(var(--s-5), 8vw, var(--s-6));
}

.contact__meta {
  display: grid;
  gap: var(--s-3);
  align-content: start;
}

.contact__k {
  font-size: 10px;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--ink-3);
  margin-bottom: 6px;
}

.contact__v {
  font-size: 15px;
  line-height: 1.5;
  color: var(--ink);
}

.form__row {
  display: grid;
  gap: 0 var(--s-3);
}

/* ---- The address, set large, closing the page ---- */
.mailto {
  padding-block: clamp(var(--s-4), 5vw, var(--s-5));
  border-top: 1px solid var(--line);
}

.mailto__link {
  display: inline-block;
  font-family: var(--font-display);
  font-weight: 700;
  letter-spacing: -0.035em;
  line-height: 1;
  /* The address is 22 characters; 6vw keeps it on one line to ~1440 */
  font-size: clamp(21px, 6vw, 72px);
  color: var(--ink);
  transition: opacity var(--dur) var(--ease);
}
.mailto__link:hover { opacity: 0.6; }

.field {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-bottom: var(--s-4);
}

.field__label {
  font-size: 11px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--ink-3);
  transition: color var(--dur) var(--ease);
}
/* Ink, not accent — the cyan only reaches 2.18:1 on paper */
.field__label .req { color: var(--ink-2); }

.field__input,
.field__area {
  width: 100%;
  min-height: 52px;
  padding: 14px 0;
  font-family: var(--font-body);
  font-size: 16px;
  color: var(--ink);
  background: transparent;
  border: 0;
  border-bottom: 1px solid var(--line);
  border-radius: 0;
  transition: border-color var(--dur) var(--ease);
  appearance: none;
}
.field__area {
  min-height: 132px;
  resize: vertical;
  line-height: 1.6;
}
.field__input::placeholder,
.field__area::placeholder { color: var(--ink-3); opacity: 1; }

/* :focus-visible, not :focus — a plain .field__input:focus (0,2,0) outranks
   the global :focus-visible (0,1,0) and was silently killing the focus ring
   for keyboard users. Mouse clicks still get just the darker underline;
   keyboard focus keeps the accent outline everything else on the site uses. */
.field__input:focus,
.field__area:focus {
  border-bottom-color: var(--ink);
}
.field__input:focus:not(:focus-visible),
.field__area:focus:not(:focus-visible) {
  outline: none;
}
.field:focus-within .field__label { color: var(--ink); }


.field__err {
  display: none;
  align-items: center;
  gap: 6px;
  font-size: 13px;
  color: var(--danger);
  line-height: 1.4;
}
.field.has-error .field__err { display: flex; }
.field.has-error .field__input,
.field.has-error .field__area { border-bottom-color: var(--danger); }
.field.has-error .field__label { color: var(--danger); }

.form__foot {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  flex-wrap: wrap;
  margin-top: var(--s-4);
}


/* Submit states */
.form__status {
  margin-top: var(--s-3);
  padding: var(--s-3);
  border: 1px solid var(--line);
  font-size: 14px;
  line-height: 1.6;
  color: var(--ink-2);
  display: none;
}
.form__status.is-shown { display: block; }
.form__status.is-ok    { border-color: var(--ink); color: var(--ink); }
.form__status.is-bad   { border-color: var(--danger); color: var(--danger); }

.spinner {
  width: 14px;
  height: 14px;
  border: 1.5px solid currentColor;
  border-top-color: transparent;
  border-radius: 50%;
  animation: spin 700ms linear infinite;
  display: none;
}
.btn.is-busy .spinner { display: block; }
@keyframes spin { to { transform: rotate(360deg); } }

/* Contact aside */



/* --------------------------------------------------------------------------
   17. Footer
   -------------------------------------------------------------------------- */

.foot {
  background: var(--dark);
  color: var(--on-dark);
  padding-block: var(--s-5) var(--s-4);
}

.foot__top {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: var(--s-4);
  flex-wrap: wrap;
  padding-bottom: var(--s-5);
}

.foot__brand {
  display: flex;
  align-items: center;
  gap: 14px;
}
.foot__brand img {
  width: 44px;
  height: 44px;
  border-radius: 6px;
}
.foot__brand span {
  font-family: var(--font-display);
  font-size: 14px;
  font-weight: 600;
  letter-spacing: 0.2em;
  text-transform: uppercase;
}

.foot__nav {
  display: flex;
  gap: var(--s-4);
  flex-wrap: wrap;
}
.foot__nav a {
  display: inline-block;
  padding-block: 13px; /* 19px line + 26px = 45px touch target */
  font-size: 12px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--on-dark-2);
  transition: color var(--dur) var(--ease);
}
.foot__nav a:hover { color: var(--on-dark); }

.foot__bottom {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--s-3);
  flex-wrap: wrap;
  padding-top: var(--s-3);
  border-top: 1px solid rgba(244, 243, 240, 0.14);
}
.foot__bottom p {
  font-size: 12px;
  letter-spacing: 0.06em;
  color: var(--on-dark-2);
}

/* --------------------------------------------------------------------------
   18. Page transition overlay
   -------------------------------------------------------------------------- */

/* Page transition: the page washes out to its own background colour, which
   is barely a transition at all — and that is the point. Fading to black
   meant every click punched a dark hole in the screen. Paper on paper reads
   as the content simply stepping aside.
   Rest state is transparent, so a failed script leaves nothing covering the
   page — which is also why there is no arrival animation. */
.veil {
  position: fixed;
  inset: 0;
  z-index: var(--z-overlay);
  background: var(--paper);
  opacity: 0;
  pointer-events: none;
  will-change: opacity;
}

.veil.is-covering {
  opacity: 1;
  transition: opacity 200ms var(--ease-in);
}

.veil.is-lifting {
  opacity: 0;
  transition: opacity 240ms var(--ease);
}

/* --------------------------------------------------------------------------
   19. Breakpoints
   -------------------------------------------------------------------------- */

@media (min-width: 768px) {
  .form__row { grid-template-columns: 1fr 1fr; }

  .band__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (min-width: 1024px) {
  /* Meta narrow on the left, form wide on the right */
  .contact {
    grid-template-columns: minmax(0, 3fr) minmax(0, 8fr);
    gap: var(--s-6);
  }

  /* Title holds the measure, supporting copy sits beside its baseline */
  .service__head {
    grid-template-columns: minmax(0, 1fr) minmax(0, 380px);
    gap: var(--s-5);
  }

  /* Photo overlaps the name block rather than sitting politely beside it */
  .about-hero__grid {
    grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
    gap: var(--s-5);
  }
  .about-hero__photo { margin-left: calc(var(--s-5) * -1); }

  .intro {
    grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
    gap: var(--s-6);
  }

  .pin__grid {
    grid-template-columns: minmax(0, 4fr) minmax(0, 8fr);
    gap: var(--s-6);
  }

  /* Hero splits: wordmark left, destinations right */
  .hero__grid {
    grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
    gap: var(--s-5);
  }
  /* The word now owns 7/12 of the measure, not all of it.
     12.5vw x 3.63 stays inside that column at every width; the 190px
     ceiling holds it there once .wrap caps at 1440. */
  .hero__word { font-size: min(12.5vw, 190px); }

  .hero__nav { gap: 12px; }

  /* Four across, overlapping just enough to read as a fanned set */
  .cards {
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 0;
  }
  .cards .card-step + .card-step { margin-left: -12px; }
  .card-step:nth-child(1) { --r: -1.6deg; }
  .card-step:nth-child(2) { --r: 1.2deg; }
  .card-step:nth-child(3) { --r: -0.9deg; }
  .card-step:nth-child(4) { --r: 1.8deg; }
}

@media (max-width: 860px) {
  /* The drawer carries the nav below this width — the bar keeps only
     the brand and the toggle so the CTA can't strand mid-bar. */
  .nav__links,
  .nav__cta { display: none; }
  .nav__toggle { display: inline-flex; }
  .rail { display: none; }

  .hero { padding-top: 96px; }
  .hero__grid { gap: var(--s-4); }
  .tile { min-height: 76px; padding: 16px 18px; }
  .tile__desc { display: none; } /* the label carries it at this size */
  /* Droplets are a cursor-driven flourish; there's no cursor here. */
  .drops { display: none; }

  .contact-hero { padding-top: 124px; }
}

/* --------------------------------------------------------------------------
   20. Reduced motion — honour the system preference
   -------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }

  /* !important on purpose: these are the resets that guarantee content is
     actually visible when motion is off. They must not lose a cascade race
     to the animated defaults above. */
  [data-reveal] { opacity: 1 !important; transform: none !important; }
  .mask__inner  { transform: none !important; }
  /* Cards land flat and still — no fan, no spring, no tilt */
  .card-step {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
  }
  .cards.is-in .card-step:hover,
  .cards.is-in .card-step:focus-within { transform: none !important; }
  /* Droplets still render — they're just ink on paper — but they hold still */
  .drop { transform: none !important; filter: none !important; }

  .hero__word { opacity: 1 !important; transform: none !important; }
  .veil { display: none !important; }

  /* Photos hold still. The expand slider keeps working — dragging it is a
     deliberate act, not motion inflicted on the reader — but it loses the
     tilt, the sheen and the collage angle. */
  .photo,
  .photo__inner { transform: none !important; }
  .photo__sheen { display: none !important; }
  .photo--angled { rotate: none !important; }
  .photo:hover .photo__inner { box-shadow: 0 1px 3px rgba(11, 11, 12, 0.05) !important; }

  /* Scroll-driven panel swapping is motion the reader didn't ask for.
     Unpin it and show all three at once. */
  .pin { height: auto !important; padding-block: var(--s-6); }
  .pin__sticky { position: static !important; height: auto !important; overflow: visible !important; }
  .pin__stage { display: block !important; }
  .pin__panel {
    opacity: 1 !important;
    transform: none !important;
    pointer-events: auto !important;
    margin-top: var(--s-3);
  }
  .pin__steps { display: none; }
}

@media (max-width: 860px) {
  .about-hero { padding-top: 128px; }
  .about-hero__photo { margin-top: var(--s-2); }
  .photo__tag { bottom: -10px; left: -8px; }

  /* No room to slide a photo over the copy on a phone, and a drag that
     buries the text with no way back would be a trap. Stack instead. */
  .expand {
    --w: 100%;
    aspect-ratio: auto;
    min-height: 0;
  }
  .expand__text {
    position: static;
    width: auto;
    padding-right: 0;
  }
  .expand__media {
    position: relative;
    clip-path: none;
    aspect-ratio: 4 / 3;
    margin-top: var(--s-4);
    /* No clip here, so the shadow can sit on the media itself */
    border: 1px solid var(--ink);
    box-shadow: -10px 22px 44px -20px rgba(11, 11, 12, 0.42);
  }
  .expand__frame,
  .expand__handle,
  .expand__hint { display: none; }

  /* A 300vh pinned section on a phone is a long hostage-taking. Let it flow. */
  .pin {
    height: auto;
    padding-block: var(--s-5);
  }
  .pin__sticky {
    position: static;
    height: auto;
    overflow: visible;
  }
  .pin__stage { display: block; }
  .pin__panel {
    opacity: 1;
    transform: none;
    pointer-events: auto;
    margin-top: var(--s-3);
  }
  .pin__steps { display: none; }
}
