/* ============================================================================
   SINAN — base
   Tokens, reset, and the two typographic voices the whole site is built from.

   THE LIGHTING LOGIC, in one paragraph, because every gradient in this project
   is an argument about it:

     BLUE IS A MATERIAL, and its value is set by how square a surface is to one
     cool source high on the left. Square to it, a face reads --blue-lit, and
     climbs to --blue-hot only on a specular crest — the hairline where a wall
     meets the polished floor, the near arris of a return wall. Turned away it
     falls through --blue to --blue-shadow. Where nothing reaches it at all —
     the far corners, the occlusion under a lintel — it is --ink, an indigo
     black, never a grey one and never #000.

     RED IS EMITTED, and only ever by an opening: the four reveal faces, the
     back plate, the spill on the wall around a mouth, the pools and mirrored
     columns on the floor, and the top of sections 02 and 03 because the camera
     is inside the opening by then. Around each opening the blue is deliberately
     pulled DOWN, so the red has something to be bright against; a room lit
     evenly has no drama in it.

   HARD RULES that came out of measuring, not taste:
     · --blue-lit and --blue-hot never sit under small text. Soft White at .56
       over #061CDB is 3.55:1 and fails AA.
     · --ember is for EMITTED MARKS ONLY — rules, playheads, lit waveform bars,
       the transport glyph. Never text: 3.0:1 on #5D001D, 3.7:1 on #020666.
     · rgba(0,0,0,x) and #000 appear nowhere. Occlusion is --occlude.

   TYPE
     Inter carries everything that is read: a neo-grotesk whose optical-size
     axis gives a tighter cut at headline sizes. IBM Plex
     Mono carries everything that is *labelled* — indices, coordinates, states.
     Hierarchy is scale and weight. Colour never ranks anything.
   ========================================================================= */

*, *::before, *::after { box-sizing: border-box; }

:root {
  /* ── camera + room geometry (px, room space) ─────────────────────────
     The eye sits 4% left of centre and 5% higher than it did, which opens
     the right return wall and drops the back-wall floor line — the floor
     band it opens up is where the reflections live. Every other number is
     mirrored in ROOM in js/room.js; change one, change both. */
  --frame-w: 1600;
  --frame-h: 900;
  --persp: 1700px;
  --origin-x: 46%;
  --origin-y: 31%;

  --room-w: 2100px;
  --room-h: 1570px;
  --z-back: -1550px;
  --wall-len: 1500px;
  --splay: 46deg;
  --floor-w: 4600px;
  --floor-d: 2600px;

  --fit: 1;
  --pan-x: 0%;
  --pan-y: 0%;
  --dolly: 0px;              /* scroll: camera travels toward the chamber  */
  --tx: 0px; --ty: 0px;      /* scroll: lateral travel                     */
  --sx: 0px; --sy: 0px;      /* pointer: a few px of camera truck          */
  --intro: 0px;              /* entrance: the camera settling              */

  /* ── the ten ─────────────────────────────────────────────────────────
     Nothing on this site may use a colour that is not one of these or an
     alpha of one of them. */
  --blue-shadow:  #020666;   /* Deep Blue        — the unlit side          */
  --blue:         #030A94;   /* Royal Blue       — the average of the room */
  --blue-lit:     #061CDB;   /* Electric Blue    — square to the source    */
  --blue-hot:     #244FF6;   /* Bright Highlight — specular crest only     */

  --red:          #EA031D;   /* Main Chamber Red — an opening's own light  */
  --red-hot:      #EA031D;   /* Pink-Red         — the core of an emission */
  --red-deep:     #A0011C;   /* Deep Red Accent  — red falling off         */
  --red-shadow:   #5D001D;   /* Dark Red Shadow  — red in occlusion        */

  --paper:        #F3F3F8;   /* Soft White                                 */
  --ink:          #090122;   /* Very Dark Shadow — the page ground         */

  /* ── grounds ───────────────────────────────────────────────────────── */
  --ink-blue:     var(--blue-shadow);   /* the cool ground under a section */
  --ink-red:      var(--red-shadow);    /* the ground inside an opening    */

  /* ── light values on those grounds ───────────────────────────────────
     Measured on #020666: dim 10.6:1, faint 5.5:1. On #030A94: 8.9:1, 4.8:1.
     Every ground gains an order of magnitude of luminance in this world, so
     these alphas are load-bearing, not polish. */
  --paper-dim:    rgba(243,243,248, .80);
  --paper-faint:  rgba(243,243,248, .56);
  --paper-ghost:  rgba(243,243,248, .34);
  --hair:         rgba(243,243,248, .22);
  --hair-lit:     rgba(36, 79, 246, .55);

  --ember:        var(--red-hot);       /* EMITTED MARKS ONLY — never text */

  /* ── occlusion: the only shadow colour on the site ─────────────────── */
  --occlude:      rgba(9, 1, 34, .86);
  --occlude-soft: rgba(9, 1, 34, .50);

  /* ── materials ───────────────────────────────────────────────────────
     Generated plates, stripped to luminance so the palette above stays the
     only authority on colour. They modulate value; they never set hue. */
  --mat-hall:  url("../assets/room/hall.webp");

  /* ── rhythm ────────────────────────────────────────────────────────── */
  --gut: clamp(20px, 3.1vw, 52px);
  --seam: clamp(150px, 26vh, 320px);   /* how far a section bleeds upward */
  --ease: cubic-bezier(.16, 1, .3, 1);
  --ease-io: cubic-bezier(.65, 0, .35, 1);
}

html { background: var(--ink); scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  background: var(--ink);
  color: var(--paper);
  font-family: var(--sans);
  font-synthesis: none;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}
a { color: inherit; text-decoration: none; }
img { max-width: 100%; }
::selection { background: var(--red); color: var(--paper); }

/* ── type families ────────────────────────────────────────────────────── */
:root {
  /* A neo-grotesk, as the typography reference asks: Inter's optical-size
     axis gives the tighter Display cut at headline sizes, and it falls back
     to the Helvetica/Arial line it was drawn against. */
  --display: "Inter", "Helvetica Neue", Helvetica, Arial, sans-serif;
  --sans: "Inter", "Helvetica Neue", Helvetica, Arial, sans-serif;
  --mono: "IBM Plex Mono", ui-monospace, "SFMono-Regular", monospace;
}

/* ── the label voice ──────────────────────────────────────────────────
   Every index, coordinate, state and caption on the site. One size, one
   tracking; only its opacity changes with importance.
   ------------------------------------------------------------------- */
.tag {
  font-family: var(--mono);
  font-size: clamp(10px, .74vw, 12px);
  font-weight: 500;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--paper-dim);
}
.tag--faint { color: var(--paper-faint); }

/* a tag preceded by a hairline — the site's standard section mark */
.mark { display: flex; align-items: center; gap: 14px; }
.mark .rule { display: block; width: clamp(28px, 3.4vw, 54px); height: 1px; background: currentColor; opacity: .45; }

/* A mark standing in a chamber's light. The LABEL stays Soft White — ember
   as text measures 3.0:1 and fails — and the hairline beside it carries the
   emission instead. This rule must stay AFTER `.mark .rule`: both selectors
   are (0,2,0) and source order is the only thing that decides. */
.tag--ember { color: var(--paper); }
.tag--ember .rule { background: var(--ember); opacity: 1; }

/* ── the display voice ────────────────────────────────────────────────
   Inter, heavy and tracked in, always uppercase. Section
   headings are the same face one step down; nothing else competes.
   ------------------------------------------------------------------- */
.display {
  margin: 0;
  font-family: var(--display);
  font-weight: 800;
  font-variation-settings: "opsz" 32;
  text-transform: uppercase;
  line-height: .82;
  letter-spacing: -.026em;
}

.h-section {
  margin: 0;
  font-family: var(--display);
  font-weight: 800;
  font-variation-settings: "opsz" 32;
  font-size: clamp(44px, 7.4vw, 132px);
  line-height: .84;
  letter-spacing: -.028em;
  text-transform: uppercase;
}

/* ── the reading voice ────────────────────────────────────────────── */
.body {
  margin: 0;
  font-weight: 400;
  font-size: clamp(14px, 1.06vw, 16.5px);
  line-height: 1.6;
  color: var(--paper-dim);
}
.lead-in {
  margin: 0;
  font-weight: 350;
  font-size: clamp(19px, 1.8vw, 28px);
  line-height: 1.44;
  letter-spacing: -.014em;
  color: rgba(243,243,248, .88);
}

/* ── shared primitives ────────────────────────────────────────────── */
.hair { height: 1px; background: var(--hair); border: 0; margin: 0; }

.link { position: relative; display: inline-block; padding-bottom: 3px; transition: color .5s var(--ease); }
.link::after {
  content: ""; position: absolute; left: 0; bottom: 0; height: 1px; width: 100%;
  background: currentColor; opacity: .5;
  transform: scaleX(0); transform-origin: 0 50%;
  transition: transform .6s var(--ease);
}
.link:hover { color: var(--paper); }
.link:hover::after { transform: scaleX(1); }

/* ── reveal on entry ───────────────────────────────────────────────────
   One mechanism for the whole page: js/site.js adds .in when the element
   crosses into view, and --d staggers siblings. Transform only.
   ------------------------------------------------------------------- */
.rise {
  opacity: 0;
  transform: translateY(18px);
  transition:
    opacity  1000ms var(--ease) calc(var(--d, 0) * 1ms),
    transform 1100ms var(--ease) calc(var(--d, 0) * 1ms);
}
.rise.in { opacity: 1; transform: none; }

.draw { transform: scaleX(0); transform-origin: 0 50%; transition: transform 1400ms var(--ease) calc(var(--d, 0) * 1ms); }
.draw.in { transform: none; }

.mask { display: block; overflow: hidden; }
.mask > * { display: block; transform: translateY(108%); transition: transform 1250ms var(--ease) calc(var(--d, 0) * 1ms); }
.mask.in > * { transform: none; }

@media (prefers-reduced-motion: reduce) {
  .rise, .draw, .mask > * { transition-duration: 520ms; transition-property: opacity; transform: none; }
  .rise { transform: none; }
  .draw { transform: none; }
}

:focus-visible { outline: 2px solid var(--paper); outline-offset: 3px; }
