/* ============================================================
   Memodel — single-page site
   Tokens, type, layout, scrub scaffolding, temp-visual chrome.

   Semantic colours: --ember means knowledge the character HAS,
   --stone means knowledge the character LACKS. Neither is used
   as a general UI accent. (The hero's forge sparks use warm
   ember-family tones as *scene content* — fire — not as UI.)
   ============================================================ */

:root {
  /* daylight forge palette: warm paper, iron text, aged gold.
     (--bone/--bone-dim keep their names but are now the dark text
     pair; --ink-2 is the raised white surface.) */
  --paper:     #E8F1FB; /* page background — the hero scene's own
                           backdrop tone, so every section sits in
                           the same light */
  --ink:       #17120C; /* deepest dark — display text over light worlds */
  --ink-2:     #FFFFFF; /* raised surfaces: cards, panels, plates */
  --bone:      #1C1710; /* primary text */
  --bone-dim:  #6A6152; /* body copy */
  --brass:     #96701E; /* primary accent — aged gold, AA on paper */
  --verdigris: #3E7263; /* secondary — patina, kept for the in-head visuals */
  --ember:     #A64C1E; /* in-bounds:  knowledge the character HAS   */
  --stone:     #5C6A70; /* out-of-bounds: knowledge the character LACKS */

  --display: "Space Grotesk", "Helvetica Neue", system-ui, sans-serif;
  --accent-serif: "Instrument Serif", Georgia, serif;
  --body:    "Instrument Sans", "Helvetica Neue", system-ui, sans-serif;
  --mono:    "JetBrains Mono", "SFMono-Regular", Menlo, monospace;

  --gutter: clamp(1.25rem, 6vw, 5.5rem);
  --hairline: 1px solid rgba(26, 21, 14, 0.08);
}

* { box-sizing: border-box; margin: 0; padding: 0; }

html { background: var(--paper); }

body {
  background: var(--paper);
  color: var(--bone-dim);
  font-family: var(--body);
  font-weight: 400;
  font-size: 0.95rem;
  line-height: 1.75;
  -webkit-font-smoothing: antialiased;
}

/* Film grain over everything — one static tile, no motion. */
body::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 40;
  pointer-events: none;
  opacity: 0.04;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='160' height='160'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/><feColorMatrix type='saturate' values='0'/></filter><rect width='160' height='160' filter='url(%23n)'/></svg>");
  background-size: 160px 160px;
}

::selection { background: var(--brass); color: var(--ink); }

h1, h2, h3 {
  font-family: var(--display);
  font-weight: 500;
  color: var(--bone);
}

/* The one emphasis device: serif italic in brass against the
   grotesk headline, at most once per headline. */
h1 em, h2 em, h3 em {
  font-family: var(--accent-serif);
  font-style: italic;
  font-weight: 400;
  font-size: 1.05em;
  color: var(--brass);
}

h1 { font-size: clamp(3.2rem, 8.5vw, 6.6rem); line-height: 0.95; letter-spacing: -0.028em; }
h2 { font-size: clamp(1.9rem, 4.4vw, 3.2rem); line-height: 1.07; letter-spacing: -0.015em; }
h3 { font-size: clamp(1.45rem, 2.8vw, 2rem);  line-height: 1.15; }

a { color: inherit; }

button {
  font: inherit;
  color: inherit;
  background: none;
  border: none;
  cursor: pointer;
}

:focus-visible {
  outline: 2px solid var(--brass);
  outline-offset: 4px;
}

.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;
}

/* Utility type ------------------------------------------------ */

.eyebrow {
  font-family: var(--mono);
  font-weight: 500;
  font-size: 11px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--brass);
  margin-bottom: 1.3rem;
}

/* quest-marker diamond on every eyebrow */
.eyebrow::before {
  content: "◆";
  display: inline-block;
  font-size: 9px;
  margin-right: 0.7rem;
  vertical-align: 1px;
  opacity: 0.9;
}

.ph-tag {
  font-family: var(--mono);
  font-weight: 400;
  font-size: 11px;
  letter-spacing: 0.06em;
  color: var(--bone-dim);
  opacity: 0.75;
}

/* Reveal-on-intersect (static sections only; scrubbed copy is
   driven by scroll progress in script.js) ------------------- */

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

/* ── site loader ────────────────────────────────────────────────
   Sits above the nav (20) and indicator, beneath the film grain
   (40) so the texture reads through. script.js reveals the page
   once every embedded asset app is live.                        */

body.is-loading { overflow: hidden; }

.loader {
  position: fixed;
  inset: 0;
  z-index: 30;
  background: var(--paper);
  display: grid;
  place-items: center;
  clip-path: circle(120% at 50% 50%);
  transition: clip-path 0.9s cubic-bezier(0.6, 0, 0.3, 1), opacity 0.4s ease 0.55s;
}

/* the loader exits the way the worlds hand off: an iris */
.loader.is-done {
  clip-path: circle(0% at 50% 50%);
  opacity: 0;
  pointer-events: none;
}

/* wordmark sits exactly where the nav's will appear */
.loader__wordmark {
  position: absolute;
  top: 1.1rem;
  left: var(--gutter);
}

.loader__stage {
  position: relative;
  display: grid;
  place-items: center;
}

.loader__rings {
  width: min(56vmin, 440px);
  aspect-ratio: 1;
  transform: rotate(-90deg);
  animation: loader-turn 46s linear infinite;
}

@keyframes loader-turn {
  to { transform: rotate(270deg); }
}

/* each ring draws itself closed when its subsystem comes online */
.loader__ring {
  fill: none;
  stroke: rgba(26, 21, 14, 0.10);
  stroke-width: 0.75;
}

.loader__ring.is-done {
  stroke: var(--brass);
  stroke-dasharray: 100;
  stroke-dashoffset: 100;
  animation: ring-draw 1.1s cubic-bezier(0.5, 0, 0.2, 1) forwards;
}

@keyframes ring-draw {
  to { stroke-dashoffset: 0; }
}

.loader__count {
  position: absolute;
  font-family: var(--display);
  font-weight: 500;
  font-size: clamp(3.4rem, 11vmin, 6.5rem);
  letter-spacing: -0.03em;
  color: var(--bone);
  font-variant-numeric: tabular-nums;
  line-height: 1;
}

.loader__count em {
  font-family: var(--accent-serif);
  font-style: italic;
  font-weight: 400;
  font-size: 0.52em;
  color: var(--brass);
  margin-left: 0.06em;
}

@media (prefers-reduced-motion: reduce) {
  .loader { transition: none; }
  .loader__rings { animation: none; }
  .loader__ring.is-done { animation: none; stroke-dashoffset: 0; }
}

/* ── 00 · fixed nav ─────────────────────────────────────────── */

.nav {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 20;
  display: flex;
  align-items: baseline;
  padding: 1.1rem var(--gutter);
  /* difference blend with a LIGHT ink: renders near-black over the
     paper sections and light over the dark Unity descent */
  mix-blend-mode: difference;
  color: #E8E4DC;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.06em;
}

.nav__wordmark {
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  text-decoration: none;
  white-space: nowrap;
}



/* ── Memodel wordmark — "the cut counter" ─────────────────────────
   mem◆del: Space Grotesk 500, lowercase, natural fit. One move:
   the counter of the central o — the hinge letter where "memo"
   fuses into "model" — is re-cut as the site's quest diamond.
   The letter's outer contour is Space Grotesk 500's own o
   (path extracted from the font: advance 615, ink 52..563 ×
   −14..507 at 1000 upm), so the mark sits in running type as a
   true glyph; only its interior is intervened. Solid evenodd
   fill, no strokes — it antialiases exactly like the type
   around it at nav size.
   Nav variant rides currentColor throughout (difference-blend
   header); loader variant may colour: word in bone, o in brass. */

.logo-lockup {
  font-family: var(--display);
  font-weight: 500;
  font-size: 20px;          /* ascender span ≈ 25px — nav-scale */
  line-height: 1;
  letter-spacing: normal;   /* resets the nav/loader 0.18em tracking */
  text-transform: none;     /* resets the nav/loader uppercase */
  white-space: nowrap;
}

/* the intervened letter, sized to the font's own o box so its
   advance (0.052 + 0.511 + 0.052 = 0.615em) equals the glyph it
   replaces — spacing is the font's, not ours */
.logo-o {
  display: inline-block;
  width: 0.511em;             /* o ink width  */
  height: 0.521em;            /* o ink height */
  margin: 0 0.052em;          /* o sidebearings */
  vertical-align: -0.014em;   /* o baseline overshoot */
}

/* nav: no colour declared anywhere — text inherits the header's
   #E8E4DC and the path fills currentColor, so the difference
   blend inverts the whole lockup as one object */

/* loader: known paper background, so the one-emphasis-device rule
   applies — word in bone, the marked letter in brass */
.logo-lockup--loader { color: var(--bone); }
.logo-lockup--loader .logo-o { color: var(--brass); }

/* while the page loads, the marked letter breathes on the same
   2.6s pulse as the hero's "Begin" cue */
@media (prefers-reduced-motion: no-preference) {
  .logo-lockup--loader .logo-o {
    animation: logo-breathe 2.6s ease-in-out infinite;
  }
}

@keyframes logo-breathe {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.4; }
}

/* self-contained visually-hidden text so the nav link keeps the
   accessible name "Memodel" */
.logo-sr {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}


/* ── asset slots & temp-visual chrome ───────────────────────── */

.asset {
  position: relative;
  overflow: hidden;
  background: var(--ink-2);
}

.asset__canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
}




/* dev annotations: not worth colliding with copy on small screens */
@media (max-width: 719.98px), (max-height: 560px) {
  }

/* ── 01 · hero ──────────────────────────────────────────────── */

.hero {
  position: relative;
  height: 100vh;
  height: 100svh;
  /* the copy is centred as a flow child rather than pinned to the
     bottom — .reveal animates transform, so transform-based
     centring on the copy itself would be clobbered on reveal */
  display: flex;
  align-items: center;
  justify-content: center;
}

.asset--hero {
  position: absolute;
  inset: 0;
  /* two-tone scene light: forge below-left, cold rim above-right */
  background:
    radial-gradient(120vw 90vh at 16% 110%, rgba(201, 100, 42, 0.10), transparent 56%),
    radial-gradient(90vw 70vh at 88% -12%, rgba(78, 140, 125, 0.07), transparent 62%),
    var(--ink-2);
}

/* legibility scrim behind the hero copy (dark forge fallback) */
.asset--hero::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(to top, rgba(232, 241, 251, 0.9) 0%, rgba(232, 241, 251, 0) 46%);
}

/* with motion allowed, the hero is the embedded light-world scene:
   copy flips dark and the scrim goes white. Under reduced motion the
   iframe never shows, so the forge treatment above stands. */
@media (prefers-reduced-motion: no-preference) {
  .asset--hero::after {
    background: linear-gradient(to top, rgba(232, 241, 251, 0.9) 0%, rgba(232, 241, 251, 0) 46%);
  }

  .hero__copy h1 { color: var(--ink); }
  .hero__copy h1 em { color: color-mix(in srgb, var(--brass), var(--ink) 30%); }
}

.asset__embed--hero {
  background: #E8F1FB;
}

/* the Unity head scene: transparent while it boots so the contour
   etching shows through, then its canvas fades itself in */
.asset__embed--head {
  /* the Unity build ships a saturated purple world; grayscale plus
     the screen-blend layer below turn it into a light azure duotone
     that sits inside the site's palette */
  filter: grayscale(1) brightness(1.05);
  background: transparent;
}

/* duotone: a screen-blend azure lifts the scene's blacks to a muted
   blue-gray — the darkest pixel becomes this tint, whites stay
   white, so the whole world reads inside the site's palette */
#asset-head-zoom::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 2;
  background: #93A9C6;
  mix-blend-mode: screen;
  pointer-events: none;
}

/* the scene is light now — the descent copy stays in site colours
   with the same azure halo the feature copy uses */
@media (prefers-reduced-motion: no-preference) {
  .scrub__sticky.head-live .descent-line {
    text-shadow:
      0 0 8px rgba(232, 241, 251, 0.95),
      0 0 18px rgba(232, 241, 251, 0.9),
      0 0 32px rgba(232, 241, 251, 0.8);
  }
}

/* title-screen composition: centred, like a game's opening menu */
.hero__copy {
  position: relative;
  z-index: 2;
  max-width: 60rem;
  text-align: center;
  padding: 0 1.5rem;
  /* optical lift: type centred by the numbers reads slightly low,
     and this seats the headline against the character's face
     (a centred flex child rises by half its bottom margin) */
  margin-bottom: 6vh;
}

/* On wide screens the character holds the left third, and his
   silhouette is WIDEST at mid-height — exactly where the centred
   copy now sits — so the copy is displaced right to clear his face.
   The scene is height-driven, so he eats a larger share of the width
   as the viewport narrows (37% at 1680px, 44% at 1100px); the
   headline therefore also steps down in size below ~1430px, where
   full-size type can no longer fit beside him. At 1430px and up the
   6.6rem cap still applies, so wide desktop is unchanged. */
/* the floor is set so the longest line still fits a 390px phone
   without wrapping */
.hero__copy h1 { font-size: clamp(2.55rem, 8.2vw, 6.6rem); }

/* Below 1100px there is no room beside the character — he fills the
   frame — so the copy returns to the lower third, which is where the
   legibility scrim lives (it is a bottom-up wash). Centring it here
   would strand the headline across his face with no contrast behind
   it. The scrim is also lifted to cover the copy's band while
   leaving his head, in the upper 38%, untouched. */
@media (max-width: 1099.98px) {
  .hero { align-items: flex-end; padding-bottom: 15vh; }
  .hero__copy { margin-bottom: 0; }

  .asset--hero::after {
    background: linear-gradient(
      to top,
      rgba(232, 241, 251, 0.95) 0%,
      rgba(232, 241, 251, 0.80) 30%,
      rgba(232, 241, 251, 0) 62%
    );
  }
}

/* 1100–1400px: he takes ~44% of the width here, so the headline
   steps down a size to sit beside him with a real gutter */
@media (min-width: 1100px) and (max-width: 1399.98px) {
  .hero__copy { margin-left: 42vw; }
  .hero__copy h1 { font-size: clamp(2.6rem, 6.6vw, 5.6rem); }
}

/* 1400px and up: full-size type, the 6.6rem cap unchanged */
@media (min-width: 1400px) {
  .hero__copy { margin-left: 38vw; }
  .hero__copy h1 { font-size: clamp(2.9rem, 7.4vw, 6.6rem); }
}


/* ── colour bridge: hero azure → head-world ambient (#B7C5D7,
   sampled from the scene's sky). Kept short so the transition
   reads quickly; the first 20% still holds pure page azure so
   nothing shifts while the hero fills the view. */
.bridge {
  height: 35vh;
  background: linear-gradient(
    to bottom,
    #E8F1FB 0%,
    #E8F1FB 20%,
    #D6E1EF 55%,
    #B7C5D7 100%
  );
}

/* ── 02 + 03 · scrubbed sequence ────────────────────────────────
   700vh = 100vh pinned viewport + 600vh of travel
   (200vh head-zoom + 400vh model-features).                    */

.scrub {
  position: relative;
  height: 700vh;
}

.scrub__sticky {
  position: sticky;
  top: 0;
  height: 100vh;
  /* entrance: script.js scales this open from a rounded card into
     the full-bleed world as the section arrives */
  transform-origin: center center;
  /* lvh, not svh: during the 600vh pinned sequence the mobile
     toolbar is retracted, so the visible viewport is the large one —
     svh would leave a bare strip under the canvas the whole way */
  height: 100lvh;
  overflow: hidden;
}

.asset--scrub {
  position: absolute;
  inset: 0;
  z-index: 1;
  background:
    radial-gradient(90vw 80vh at 50% 50%, rgba(78, 140, 125, 0.05), transparent 65%),
    var(--ink-2);
}

/* azure mist that clears as the head world opens */
.scrub-veil {
  position: fixed;
  inset: 0;
  z-index: 15; /* over content, under the nav (20) */
  width: 100%;
  height: 100%;
  pointer-events: none;
}

@media (prefers-reduced-motion: reduce) {
  .scrub-veil { display: none; }
}

/* model-features slot starts hidden; script.js crossfades it in
   at the 03→04 boundary so the sequence reads as one move.
   It hosts the embedded 3D scene, which lives in a white world —
   the crossfade reads as surfacing into the light. */
.asset--model {
  opacity: 0;
  visibility: hidden;
  background: #E8F1FB;
}

/* the scene's renderer clears to opaque white, so a multiply layer
   maps its whites onto the hero azure while leaving the dark
   geometry untouched (white x azure = azure, black x azure = black) */
.asset--model::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 2;
  background: #E8F1FB;
  mix-blend-mode: multiply;
  pointer-events: none;
}

/* the embedded, same-origin 3D scene (./model/). pointer-events
   none: the parent page owns scrolling; script.js scrubs the
   iframe's internal scroll through setModelFeaturesProgress */
.asset__embed {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
  display: block;
  pointer-events: none;
  background: #ffffff;
}

/* dark chrome + copy over the white scene, only while scrubbed —
   under reduced motion the copy stacks on the dark page instead */
@media (prefers-reduced-motion: no-preference) {
  .feature h3 { color: var(--ink); }
  .feature p { color: rgba(18, 14, 10, 0.68); }
  .feature .eyebrow { color: color-mix(in srgb, var(--brass), var(--ink) 36%); }
  .feature .specline { color: rgba(18, 14, 10, 0.62); }
  .feature .ph-tag { color: rgba(18, 14, 10, 0.62); }

  /* the scene's near-black geometry drifts under the copy, so the
     block carries its own patch of white world: a feathered scrim
     plus a white halo on every line */
  .feature {
    padding: 2rem 2.2rem;
    background: radial-gradient(
      110% 110% at 50% 50%,
      rgba(232, 241, 251, 0.94),
      rgba(232, 241, 251, 0.74) 58%,
      rgba(232, 241, 251, 0) 100%
    );
  }

  .feature h3,
  .feature p,
  .feature .eyebrow {
    text-shadow:
      0 0 8px rgba(232, 241, 251, 0.95),
      0 0 18px rgba(232, 241, 251, 0.9),
      0 0 32px rgba(232, 241, 251, 0.8);
  }
}

.descent-line {
  position: absolute;
  z-index: 2;
  left: var(--gutter);
  bottom: 8vh;
  text-shadow: 0 0 24px rgba(255, 255, 255, 0.85);
}

/* features only ever sit over the white scene (scrubbed) or the
   page background (reduced motion) — no shadow needed either way */
.feature {
  position: absolute;
  z-index: 2;
  top: 50%;
  transform: translateY(-50%);
  width: min(30rem, 42vw);
  opacity: 0;
  visibility: hidden;
}

.feature--left  { left: var(--gutter); }
.feature--right { right: var(--gutter); text-align: right; }

.feature h3 { margin-bottom: 1rem; }

.specline {
  margin-top: 1.2rem;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.06em;
  color: var(--bone-dim);
}

/* ── 05 · cast ──────────────────────────────────────────────── */

.cast { padding: 20vh 0 0; }

.cast__head { text-align: center; padding: 0 var(--gutter); margin-bottom: 8vh; }

/* full-bleed scrub: 560vh of travel + 100vh pinned viewport —
   long on purpose: the era experience consumes wheel input at its
   own pace, and this ratio keeps one-wheel-step-per-frame pumping
   in lockstep with real scrolling */
.cast-scrub {
  position: relative;
  height: 660vh;
}

.cast-scrub__sticky {
  position: sticky;
  top: 0;
  height: 100vh;
  height: 100lvh;
  overflow: hidden;
}

.asset--cast {
  position: absolute;
  inset: 0;
  background: #0A0524; /* the embed's own deep navy */
}

/* static era frame: reduced-motion stand-in and loading backdrop */
.asset--cast .asset__still {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* the embed's own splash.css supplies the monochrome scenes-only
   look; here only the boot fade-in is ours */
.asset__embed--cast {
  opacity: 0;
  transition: opacity 0.8s ease;
}

.asset--cast .asset__still {
  filter: grayscale(1) contrast(1.05);
}

/* ── 08 · close ─────────────────────────────────────────────── */

.close { padding: 24vh var(--gutter) 0; }

.close__grid {
  display: grid;
  grid-template-columns: 1.15fr 0.85fr;
  gap: clamp(2rem, 6vw, 5rem);
  align-items: end;
}

.close__label {
  font-family: var(--mono);
  font-weight: 500;
  font-size: 11px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--brass);
  margin-bottom: 1rem;
}

.close__mail {
  display: inline-block;
  margin-top: 1.2rem;
  font-family: var(--mono);
  font-size: 1.05rem;
  letter-spacing: 0.06em;
  color: var(--bone);
  text-decoration: none;
  border-bottom: 1px solid var(--brass);
  padding-bottom: 3px;
}

.footer {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 2rem;
  margin-top: 18vh;
  /* bottom clearance keeps the fixed scroll-indicator plate off
     the tagline at every width */
  padding: 2rem 0 3.6rem;
  border-top: var(--hairline);
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.06em;
  color: var(--bone-dim);
}

.footer__wordmark {
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--bone);
}

/* ── responsive ─────────────────────────────────────────────── */

@media (max-width: 719.98px) {

  /* alternating alignment collapses to all-left */
  .feature,
  .feature--right {
    left: var(--gutter);
    right: var(--gutter);
    width: auto;
    text-align: left;
  }

  
  .close__grid { grid-template-columns: 1fr; align-items: start; }

}

/* ── reduced motion: hard requirement ───────────────────────────
   Scrubbed sections collapse to static states — each temp visual
   draws its final frame once (script.js), readouts read 100% /
   state 3, and the copy stacks conventionally.                  */

@media (prefers-reduced-motion: reduce) {
  .reveal {
    opacity: 1;
    transform: none;
    transition: none;
  }

  body::after { opacity: 0.04; }

  .scrub { height: auto; }

  .scrub__sticky {
    position: static;
    height: auto;
    overflow: visible;
  }

  .asset--scrub {
    position: relative;
    height: 72vh;
    opacity: 1 !important;
    visibility: visible !important;
  }

  .descent-line {
    position: static;
    opacity: 1 !important;
    visibility: visible !important;
    padding: 10vh var(--gutter);
    text-shadow: none;
  }

  .feature {
    position: static;
    transform: none;
    opacity: 1 !important;
    visibility: visible !important;
    width: auto;
    max-width: 30rem;
    margin: 10vh var(--gutter);
    text-shadow: none;
  }

  .feature--right { margin-left: auto; }

  .scrub__sticky { padding-bottom: 2vh; }

  .cast-scrub { height: auto; }
  .cast-scrub__sticky { position: static; height: 72vh; }


}

@media (prefers-reduced-motion: reduce) and (max-width: 719.98px) {
  .feature--right { margin-left: var(--gutter); }
}

/* ── game chrome ────────────────────────────────────────────────
   Diegetic game-UI treatment: riveted double-border plates,
   menu-selector carets, dialogue nameplates. Colour tokens, type
   scale, and copy are untouched.                                */

/* riveted plate: outer hairline + inner hairline + corner studs */
.close__contact {
  position: relative;
  border: 1px solid rgba(26, 21, 14, 0.22);
}

.close__contact::after {
  content: "";
  position: absolute;
  inset: 4px;
  border: 1px solid rgba(26, 21, 14, 0.07);
  pointer-events: none;
}

.close__contact {
  background-color: var(--ink-2);
  padding: 1.6rem;
}

.close__mail::before { content: "▸ "; color: var(--brass); }
