/* ============================================================================
   SmartStack — Core :: TECHNICAL BROADSHEET
   Reset, the printed-page typography, the visible grid, and the mechanical
   motion primitives. Depends on ss-tokens.css.
   ========================================================================== */

/* ---------------------------------------------------------------------------
   RESET
   --------------------------------------------------------------------------- */

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

html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--nav-height) + var(--space-6));
  scrollbar-gutter: stable;
  /* Wipes and rules start outside their box; clip trims the stray width
     without creating a scroll container (so sticky keeps working). */
  overflow-x: clip;
}

body {
  min-height: 100svh;
  background-color: var(--paper);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: var(--text-body);
  font-variation-settings: 'wdth' var(--width-normal), 'wght' 400;
  line-height: var(--leading-relaxed);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  font-synthesis-weight: none;
  overflow-x: clip;
  position: relative;
}

/* Paper grain over the whole document. Pointer-events off, sits above the
   background but below everything readable. */
body::after {
  content: '';
  position: fixed;
  inset: 0;
  z-index: 9999;
  pointer-events: none;
  background-image: var(--grain);
  background-size: 160px 160px;
  opacity: var(--grain-opacity);
  mix-blend-mode: var(--grain-blend);
}

img, svg, video, canvas, picture { display: block; max-width: 100%; }
img, video { height: auto; }

input, button, textarea, select { font: inherit; color: inherit; }
button { background: none; border: none; }

ul, ol { list-style: none; padding: 0; }
a { color: inherit; text-decoration: none; }

:where(a, button, [role='button'], summary, label[for], select) { cursor: pointer; }

p, h1, h2, h3, h4 { overflow-wrap: break-word; }

/* ---------------------------------------------------------------------------
   FOCUS — a printer's registration box, not a soft glow
   --------------------------------------------------------------------------- */

:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
}
:focus:not(:focus-visible) { outline: none; }

.ss-skip {
  position: absolute;
  top: var(--space-3);
  left: var(--space-3);
  z-index: var(--z-toast);
  padding: var(--space-3) var(--space-5);
  background: var(--ink);
  color: var(--paper);
  font-family: var(--font-mono);
  font-size: var(--text-label);
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  transform: translateY(-200%);
  transition: transform var(--dur-fast) var(--ease-press);
}
.ss-skip:focus-visible { transform: translateY(0); }

/* ---------------------------------------------------------------------------
   TYPOGRAPHY
   --------------------------------------------------------------------------- */

/* Headlines: condensed, very tight, set in caps. This is the voice. */
.ss-mega,
.ss-display,
.ss-display-2,
h1, h2 {
  font-family: var(--font-display);
  font-variation-settings: 'wdth' var(--width-condensed), 'wght' 800;
  font-weight: 800;
  text-transform: uppercase;
  line-height: var(--leading-tight);
  letter-spacing: var(--track-tight);
  color: var(--ink);
  text-wrap: balance;
}

.ss-mega {
  font-size: var(--text-mega);
  line-height: var(--leading-mega);
  letter-spacing: var(--track-mega);
}
.ss-display   { font-size: var(--text-display-1); line-height: var(--leading-tight); letter-spacing: var(--track-mega); }
.ss-display-2 { font-size: var(--text-display-2); }

h1 { font-size: var(--text-display-1); letter-spacing: var(--track-mega); }
h2 { font-size: var(--text-h2); }

h3, h4 {
  font-family: var(--font-display);
  font-variation-settings: 'wdth' 92, 'wght' 700;
  font-weight: 700;
  line-height: var(--leading-snug);
  letter-spacing: var(--track-snug);
  color: var(--ink);
}
h3 { font-size: var(--text-h3); }
h4 { font-size: var(--text-h4); }

p { text-wrap: pretty; }

strong, b { font-variation-settings: 'wdth' var(--width-normal), 'wght' 650; font-weight: 650; }

::selection { background: var(--signal); color: var(--signal-on); }

/* The editorial voice: an italic serif line that cuts against all the
   machined grotesque. Used sparingly — one per section at most. */
.ss-serif {
  font-family: var(--font-serif);
  font-style: italic;
  font-weight: 400;
  font-size: var(--text-serif-lead);
  line-height: 1.26;
  letter-spacing: -0.01em;
  text-transform: none;
  color: var(--ink);
}

/* Mono label — section indices, captions, data, every small thing. */
.ss-label {
  font-family: var(--font-mono);
  font-size: var(--text-label);
  font-weight: 400;
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  line-height: 1;
  color: var(--ink-mid);
}
.ss-label--ink { color: var(--ink); }
.ss-label--signal { color: var(--signal); }

.ss-lead {
  font-size: var(--text-lead);
  line-height: var(--leading-relaxed);
  color: var(--ink-mid);
  max-width: 58ch;
}

.ss-sig { color: var(--signal); }

/* A word set in signal with a hard underline — the one flourish allowed. */
.ss-mark {
  color: var(--signal);
  position: relative;
  white-space: nowrap;
}

/* ---------------------------------------------------------------------------
   THE GRID
   The design's structure is literally visible: a container that draws its own
   column rules, and a margin column carrying the section index.
   --------------------------------------------------------------------------- */

.ss-wrap {
  width: 100%;
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: var(--space-gutter);
}

.ss-wrap--text { max-width: calc(var(--container-text) + var(--space-gutter) * 2); }

.ss-section {
  position: relative;
  padding-block: var(--space-section);
}
.ss-section--sm { padding-block: var(--space-section-sm); }
.ss-section--tint { background: var(--paper-tint); }

/* Every section is topped by a full-bleed hairline: the fold between stories. */
.ss-section--ruled { border-top: 1px solid var(--rule); }

/* A row with the index/label in the left margin and content on the right.
   Below 900px the margin column collapses and the label sits above. */
.ss-row {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-6);
}
@media (min-width: 900px) {
  .ss-row {
    grid-template-columns: minmax(120px, var(--margin-col)) 1fr;
    gap: clamp(1.5rem, 0.5rem + 3vw, 4rem);
  }
}

.ss-row__margin {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  align-items: flex-start;
}
@media (min-width: 900px) {
  .ss-row__margin { position: sticky; top: calc(var(--nav-height) + var(--space-6)); align-self: start; }
}

/* The section number, big, in the margin. */
.ss-index {
  font-family: var(--font-mono);
  font-size: var(--text-label);
  letter-spacing: var(--track-label);
  color: var(--signal);
}

.ss-cols {
  display: grid;
  gap: clamp(1rem, 0.6rem + 1.4vw, 2rem);
  grid-template-columns: 1fr;
}
@media (min-width: 700px)  { .ss-cols--2 { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 700px)  { .ss-cols--3 { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1040px) { .ss-cols--3 { grid-template-columns: repeat(3, 1fr); } }
@media (min-width: 700px)  { .ss-cols--4 { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1040px) { .ss-cols--4 { grid-template-columns: repeat(4, 1fr); } }

.ss-split {
  display: grid;
  gap: clamp(1.5rem, 0.8rem + 3vw, 4rem);
  grid-template-columns: 1fr;
  align-items: start;
}
@media (min-width: 940px) {
  .ss-split { grid-template-columns: 1fr 1fr; }
  .ss-split--wide { grid-template-columns: 1.15fr 0.85fr; }
  .ss-split--narrow { grid-template-columns: 0.85fr 1.15fr; }
}

/* Full-bleed rule that sits flush to the viewport edges. */
.ss-rule {
  height: 1px;
  width: 100%;
  background: var(--rule);
  border: 0;
}
.ss-rule--strong { background: var(--rule-strong); }
.ss-rule--thick { height: 3px; background: var(--ink); }

/* ---------------------------------------------------------------------------
   MOTION PRIMITIVES
   Everything is a clip, a wipe, a draw or a roll. Nothing floats or fades
   upward. CSS owns the transforms; JS only toggles state.
   --------------------------------------------------------------------------- */

/* --- 1. WIPE: content is revealed by a hard edge travelling across it --- */
[data-wipe] {
  clip-path: inset(0 100% 0 0);
  transition: clip-path var(--dur-wipe) var(--ease-cut) var(--wipe-delay, 0ms);
  will-change: clip-path;
}
[data-wipe='up']    { clip-path: inset(100% 0 0 0); }
[data-wipe='down']  { clip-path: inset(0 0 100% 0); }
[data-wipe='left']  { clip-path: inset(0 0 0 100%); }
[data-wipe].is-in   { clip-path: inset(0 0 0 0); }

/* --- 2. HEADLINE LINES: each line slides up from behind a mask, with a
       small horizontal kick so it reads as a press plate landing --- */
.ss-lines { display: block; }
.ss-line {
  display: block;
  overflow: hidden;
  padding-bottom: 0.06em;
  margin-bottom: -0.06em;
}
.ss-line > span {
  display: block;
  transform: translate3d(-0.14em, 105%, 0);
  transition: transform var(--dur-slow) var(--ease-cut) calc(var(--i, 0) * 85ms);
  will-change: transform;
}
.is-in > .ss-line > span { transform: translate3d(0, 0, 0); }

/* --- 3. DRAWN RULES: hairlines scale in from their origin --- */
[data-draw] {
  transform: scaleX(0);
  transform-origin: 0 50%;
  transition: transform var(--dur-slow) var(--ease-cut) var(--wipe-delay, 0ms);
}
[data-draw='y'] { transform: scaleY(0); transform-origin: 50% 0; }
[data-draw].is-in { transform: scale(1); }

/* --- 4. STAGGER: children arrive in sequence, wiping not fading --- */
[data-seq] > * {
  opacity: 0;
  transform: translate3d(0, 14px, 0);
  transition:
    opacity var(--dur-base) var(--ease-press) calc(var(--i, 0) * var(--seq-step, 60ms)),
    transform var(--dur-base) var(--ease-press) calc(var(--i, 0) * var(--seq-step, 60ms));
}
[data-seq].is-in > * { opacity: 1; transform: none; }

/* --- 5. ODOMETER: digits roll in a masked strip, like a split-flap board --- */
.ss-odo {
  display: inline-flex;
  align-items: baseline;
  font-variant-numeric: tabular-nums;
}
.ss-odo__reel {
  display: inline-block;
  /* Clip only top and bottom (that is the reel window). The figures run at
     negative tracking, so each glyph is wider than its reel; overflow:hidden
     would shave its right edge. */
  clip-path: inset(0 -0.25em);
  height: 1em;
  line-height: 1;
  vertical-align: baseline;
}
.ss-odo__strip {
  display: block;
  transform: translateY(var(--roll, 0%));
  transition: transform 1.1s var(--ease-cut) calc(var(--i, 0) * 70ms);
  will-change: transform;
}
.ss-odo__strip > span { display: block; height: 1em; line-height: 1; }

/* --- 6. IMAGE PLATE: photographs arrive as a hard horizontal wipe --- */
.ss-plate {
  position: relative;
  overflow: hidden;
  background: var(--paper-tint);
}
/* The <picture> wrapper is inline by default, which leaves the image's
   height:100% with nothing to resolve against — the photo then sits at its
   own ratio and the plate's tint shows below it. Make it fill the plate. */
.ss-plate > picture { display: block; height: 100%; }
.ss-plate > img,
.ss-plate > picture > img,
.ss-plate > canvas {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  transform: scale(1.06);
  transition: transform 1.2s var(--ease-cut);
}
.ss-plate.is-in > img,
.ss-plate.is-in > picture > img,
.ss-plate.is-in > canvas { transform: scale(1); }

/* The wiping shutter that uncovers the plate. */
.ss-plate::after {
  content: '';
  position: absolute;
  inset: 0;
  background: var(--ink);
  transform-origin: 100% 50%;
  transform: scaleX(1);
  transition: transform var(--dur-wipe) var(--ease-cut) var(--wipe-delay, 0ms);
}
.ss-plate.is-in::after { transform: scaleX(0); }

/* --- 7. PARALLAX: decorative layers only; JS writes --py --- */
[data-parallax] { transform: translate3d(0, var(--py, 0px), 0); will-change: transform; }

/* ---------------------------------------------------------------------------
   PAGE TRANSITION — THE SHUTTER
   Seven ink panels sweep down to cover the page, then up to uncover the next.
   A press closing and opening.
   --------------------------------------------------------------------------- */

.ss-shutter {
  position: fixed;
  inset: 0;
  z-index: var(--z-shutter);
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  pointer-events: none;
  visibility: hidden;
}
.ss-shutter__panel {
  background: var(--c-ink-900);
  /* Seven columns rarely divide the viewport into whole pixels; overlap by
     one so no hairline of the page shows between panels. */
  box-shadow: 1px 0 0 var(--c-ink-900);
  transform: scaleY(0);
  transform-origin: 50% 0;
}

/* Closing: panels drop in sequence, left to right. */
.ss-shutter.is-closing { visibility: visible; }
.ss-shutter.is-closing .ss-shutter__panel {
  transform: scaleY(1);
  transition: transform 340ms var(--ease-cut) calc(var(--i) * 30ms);
}

/* Opening: they retract upward, right to left, faster than they arrived —
   after the mark has started to clear. */
.ss-shutter.is-opening { visibility: visible; }
.ss-shutter.is-opening .ss-shutter__panel {
  transform: scaleY(0);
  transform-origin: 50% 100%;
  transition: transform 320ms var(--ease-cut) calc(150ms + (6 - var(--i)) * 26ms);
}

/* Arriving: the inline boot script sets this before first paint, so the new
   page opens on a closed shutter with the mark already printed — no flash
   of the page between the two halves of the transition. */
.ss-arriving .ss-shutter { visibility: visible; }
.ss-arriving .ss-shutter__panel { transform: scaleY(1); }

/* ---------------------------------------------------------------------------
   THE MARK — the logo, printed on the closed shutter.
   Closing: each layer is drawn as a hairline, then ink floods it from the
   bottom — base first, then the top layer stacked onto it.
   Opening: the stack clears top layer first, wiping upward with the panels.
   --------------------------------------------------------------------------- */

.ss-shutter__mark {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  visibility: hidden;
}
.ss-mark {
  width: clamp(64px, 5vw + 40px, 104px);
  height: auto;
  overflow: visible;
  /* The same lift the masthead mark gets on a dark ground. */
  filter: brightness(1.45) saturate(1.15);
}
.ss-mark__layer--base .ss-mark__ink { fill: #0267c2; }
.ss-mark__layer--top  .ss-mark__ink { fill: #02b0c1; }
.ss-mark__ink {
  clip-path: inset(100% 0 0 0);
}
.ss-mark__line {
  fill: none;
  stroke: var(--c-stock-100);
  stroke-width: 5;
  stroke-linejoin: round;
  stroke-dasharray: 1 1;
  stroke-dashoffset: 1;
  opacity: 0;
}

.ss-shutter.is-closing .ss-shutter__mark,
.ss-shutter.is-opening .ss-shutter__mark,
.ss-arriving .ss-shutter__mark { visibility: visible; }

/* Closing — draw, then flood. The middle panels land around 430ms. */
.ss-shutter.is-closing .ss-mark__line {
  stroke-dashoffset: 0;
  opacity: 1;
  transition: stroke-dashoffset 300ms var(--ease-cut) var(--draw-at),
              opacity 1ms linear var(--draw-at);
}
.ss-shutter.is-closing .ss-mark__ink {
  clip-path: inset(0 0 0 0);
  transition: clip-path 240ms var(--ease-cut) var(--ink-at);
}
.ss-shutter.is-closing .ss-mark__layer--base { --draw-at: 200ms; --ink-at: 430ms; }
.ss-shutter.is-closing .ss-mark__layer--top  { --draw-at: 290ms; --ink-at: 510ms; }

/* Once the ink is down, the hairline has done its job. */
.ss-shutter.is-closing .ss-mark__layer .ss-mark__line {
  animation: ss-mark-line-out 120ms linear forwards;
  animation-delay: calc(var(--ink-at) + 200ms);
}
@keyframes ss-mark-line-out { to { opacity: 0; } }

/* Arriving — printed and still. */
.ss-arriving .ss-mark__ink { clip-path: inset(0 0 0 0); }

/* Opening — the stack clears, top layer first. */
.ss-shutter.is-opening .ss-mark__ink {
  clip-path: inset(0 0 100% 0);
  transition: clip-path 260ms var(--ease-cut) var(--clear-at);
}
.ss-shutter.is-opening .ss-mark__layer--top  { --clear-at: 0ms; }
.ss-shutter.is-opening .ss-mark__layer--base { --clear-at: 70ms; }

/* First paint: hold the page until fonts settle, then run the reveals. */
.ss-boot main, .ss-boot footer, .ss-boot .ss-nav { opacity: 0; }
.ss-ready main, .ss-ready footer, .ss-ready .ss-nav {
  opacity: 1;
  transition: opacity 260ms linear;
}

/* Reading-progress rule pinned under the nav. */
.ss-progress {
  position: fixed;
  top: 0; left: 0;
  z-index: calc(var(--z-nav) + 1);
  height: 2px;
  width: 100%;
  background: var(--signal);
  transform: scaleX(var(--progress, 0));
  transform-origin: 0 50%;
  pointer-events: none;
}

/* ---------------------------------------------------------------------------
   UTILITIES
   --------------------------------------------------------------------------- */

.ss-vh {
  position: absolute !important;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.ss-actions { display: flex; flex-wrap: wrap; gap: var(--space-3); align-items: center; }
.ss-stack-2 > * + * { margin-top: var(--space-2); }
.ss-stack-4 > * + * { margin-top: var(--space-4); }
.ss-stack-6 > * + * { margin-top: var(--space-6); }
.ss-scroll-x { overflow-x: auto; overscroll-behavior-x: contain; }

/* ---------------------------------------------------------------------------
   REDUCED MOTION — one switch, everything mechanical stops
   --------------------------------------------------------------------------- */

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

  [data-wipe], [data-seq] > *, .ss-line > span, [data-draw] {
    clip-path: none !important;
    opacity: 1 !important;
    transform: none !important;
  }
  .ss-plate::after { transform: scaleX(0) !important; }
  .ss-plate > img, .ss-plate > picture > img, .ss-plate > canvas { transform: none !important; }
  .ss-odo__strip { transition: none !important; }
  .ss-shutter { display: none !important; }
  .ss-boot main, .ss-boot footer, .ss-boot .ss-nav { opacity: 1 !important; }
}

/* No JS: nothing stays hidden. */
.no-js [data-wipe], .no-js [data-seq] > *, .no-js [data-draw] {
  clip-path: none !important; opacity: 1 !important; transform: none !important;
}
.no-js .ss-plate::after { transform: scaleX(0) !important; }
.no-js .ss-line > span { transform: none !important; }

/* ---------------------------------------------------------------------------
   PRINT — it already looks like print; just strip the furniture
   --------------------------------------------------------------------------- */

@media print {
  body::after, .ss-nav, .ss-shutter, .ss-progress, .ss-ticker, .ss-cookie { display: none !important; }
  body { background: #fff; color: #000; }
  .ss-plate::after { display: none; }
  a[href^='http']::after { content: ' (' attr(href) ')'; font-size: 0.75em; }
}
