/* =========================================================================
   PAPER — the shared design language.

   Everything here was built on the home page and proven there first. It is
   de-scoped from `body.page-home` on purpose: any page that links this file
   gets the same nav, the same icons, the same paper and the same tape.

   What stays out of this file: the cutting mat, the paper stack, the mat
   accessories, the hero copy. Those are the home's own composition, not a
   language other pages need.

   Load order: tokens.css → paper.css → the page's own stylesheet.
   ========================================================================= */

/* --- NAV ----------------------------------------------------------------
   Sticky rather than fixed: it stays in flow, so nothing needs a
   compensating top offset.                                                */
.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  padding: 24px 0 34px;
  background: none;
  border-bottom: none;
}

/* The bar is a pseudo-element behind the nav so it can be masked without
   fading the links with it: the fill, the blur and the mask all die off
   together toward the bottom, so the header dissolves into the page instead
   of ending on a rule. */
.site-header::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: linear-gradient(
    to bottom,
    rgb(from var(--bg) r g b / 0.88) 0%,
    rgb(from var(--bg) r g b / 0.7) 52%,
    rgb(from var(--bg) r g b / 0) 100%
  );
  backdrop-filter: blur(14px) saturate(120%);
  -webkit-backdrop-filter: blur(14px) saturate(120%);
  /* Solid until past the baseline of the brand lockup — the fade has to start
     below the type, not through it. */
  -webkit-mask-image: linear-gradient(to bottom, #000 0%, #000 64%, transparent 100%);
  mask-image: linear-gradient(to bottom, #000 0%, #000 64%, transparent 100%);
}

/* The nav lines up with whatever the page's content box is — 1080 on the
   sub-pages, the mat's 1280 on the home, which overrides --nav-max. A fixed
   width here put the lockup 100px outside the content on every sub-page. */
.nav {
  width: 100%;
  max-width: var(--nav-max, var(--max));
  margin: 0 auto;
  padding: 0 24px;
}
.nav-links { font-size: 12.5px; opacity: 0.78; }
.nav-links a:hover { opacity: 1; }

/* --- ICONS --------------------------------------------------------------
   Streamline Freehand, inlined as a <symbol> sprite. The set has no
   directional arrows and no brand marks, so icons only go where they carry
   meaning — never as a decorative arrow after a label. Filled outlines, not
   strokes, so they hold their weight when they scale down and follow
   currentColor like the rest of the ink.                                   */

.ico {
  width: 18px;
  height: 18px;
  flex: none;
  fill: currentColor;
}
.btn .ico { width: 19px; height: 19px; }
.cta-link .ico { width: 20px; height: 20px; }

/* Brand marks are solid silhouettes from a different set — they need less
   box than the freehand icons to read at the same optical weight. */
.ico--brand { width: 15px; height: 15px; }

/* Anything holding an icon next to a label has to be a flex row, or the icon
   rides the baseline. `with-ico` is the utility; the rest are the site's
   existing link classes, kept so their markup needs no edit. */
.with-ico,
.case-link,
.esa-link,
.footer-item,
.cta-link {
  display: inline-flex;
  align-items: center;
  gap: 9px;
}
.case-links { align-items: center; }

/* CC BY 4.0 asks for visible credit. */
.footer-credit {
  margin: 18px 0 0;
  font-size: 10.5px;
  letter-spacing: 0.04em;
  color: rgba(242, 239, 232, 0.3);
  text-align: center;
}
.footer-credit a { text-decoration: underline; text-underline-offset: 2px; }
.footer-credit a:hover { color: rgba(242, 239, 232, 0.6); }

/* --- PAPER --------------------------------------------------------------
   Add `paper-surface` to anything that should read as stock: a note, a
   sheet, a pinned card. Paper is three things at once and one noise layer
   can't be all of them — fibre, specks and a slow unevenness, all three
   multiplied over the fill rather than laid on top of it.                  */
.paper-surface {
  position: relative;
  background: var(--paper);
  color: var(--paper-ink);
  border: 1px solid rgba(34, 29, 51, 0.14);
  border-radius: var(--r-lg);
  overflow: hidden;
  /* Stock is never flat right to the cut: the edge catches more. */
  box-shadow: 0 14px 30px rgba(0, 0, 0, 0.42), inset 0 0 22px rgba(90, 78, 58, 0.12);
}
.paper-surface::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background-image: var(--paper-fleck), var(--paper-fiber), var(--wear-blotch);
  background-size: 200px 200px, 155px 155px, 360px 360px;
  filter: grayscale(1);
  mix-blend-mode: multiply;
  opacity: 0.2;
}

/* Two sheets cut from one roll would otherwise show the identical fleck
   pattern. Offset siblings into different parts of the same noise. */
.paper-surface:nth-of-type(2)::after { background-position: 63px 21px, 40px 90px, 120px 60px; }
.paper-surface:nth-of-type(3)::after { background-position: 17px 88px, 130px 35px, 40px 190px; }
.paper-surface:nth-of-type(4)::after { background-position: 104px 52px, 75px 160px, 220px 20px; }

/* Ink on paper. */
.paper-surface .mono-label {
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: rgba(34, 29, 51, 0.45);
}

/* --- TAPE ---------------------------------------------------------------
   Add `taped` to stick a panel down at two opposite corners. Grain only and
   desaturated: over a nearly transparent fill the raw fractal noise keeps
   its colour and the strips read as glitter instead of matte tape.         */
.taped { position: relative; }
.taped::before,
.taped::after {
  content: "";
  position: absolute;
  width: 96px;
  height: 26px;
  z-index: 3;
  background-color: rgba(233, 228, 214, 0.72);
  background-image: var(--wear-grain);
  background-size: 90px 90px;
  background-blend-mode: soft-light;
  /* The grain is an opaque rect, so it sealed the layer no matter how low the
     fill's alpha was — the strips read as solid blocks. Translucency has to
     come from the element's own opacity, which takes the grain with it and
     lets the card edge underneath actually show through. */
  opacity: 0.42;
  /* Translucent tape lifts whatever is under it: light goes through the strip,
     hits the surface and comes back. `screen` is what makes the covered corner
     read as being beneath the tape instead of merely behind it — without it
     the strip just sits there, overlapping nothing in particular. */
  mix-blend-mode: screen;
  border-left: 1px solid rgba(255, 255, 255, 0.14);
  border-right: 1px solid rgba(255, 255, 255, 0.14);
  box-shadow: 0 3px 10px rgba(0, 0, 0, 0.28);
  filter: grayscale(1);
}
.taped::before { top: -13px; left: -24px; transform: rotate(-24deg); }
.taped::after { bottom: -13px; right: -24px; transform: rotate(-24deg); }

@media (max-width: 900px) {
  .taped::before,
  .taped::after { display: none; }
}

/* --- WELL ---------------------------------------------------------------
   Imagery mounted inside a card instead of running to its edge.           */
.well {
  border-radius: var(--r-md);
  overflow: hidden;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.05),
    inset 0 0 70px rgba(0, 0, 0, 0.38);
}

/* --- THE MAT ------------------------------------------------------------
   The cutting mat, as a class any page can drop a hero onto. Drawn in CSS
   rather than shipped as artwork: a mat is a measuring instrument, and a
   bitmap of one stops measuring the moment it scales — the same cell would
   be 20px on a desktop and 6px on a phone. Fixed in px, it gains and loses
   squares the way a real one does when you trim it.                       */
.mat {
  --mat-ink: 208 236 224;
  --mat-cell: 20px;
  position: relative;
  padding: 56px 54px;
  border-radius: var(--r-xl);
  overflow: hidden;
  background-color: var(--mat-surface);
  box-shadow:
    0 40px 90px rgba(0, 0, 0, 0.5),
    inset 0 0 130px rgba(0, 0, 0, 0.4);
}

/* The printed frame, and the ruling inside it. The margin between the cut
   edge and the border stays bare: on a real mat the grid starts at the
   frame, it doesn't run off the side. Centred, so the offcut splits evenly
   instead of dumping one cut row at the bottom. */
.mat::before {
  content: "";
  position: absolute;
  inset: 20px;
  pointer-events: none;
  border: 1px solid rgb(var(--mat-ink) / 0.32);
  border-radius: 2px;
  background-clip: padding-box;
  background-position: center center;
  background-image:
    repeating-linear-gradient(to right, rgb(var(--mat-ink) / 0.13) 0 1px, transparent 1px var(--mat-cell)),
    repeating-linear-gradient(to bottom, rgb(var(--mat-ink) / 0.13) 0 1px, transparent 1px var(--mat-cell));
}

/* Painted after the ruling so it actually knocks it back under the type. */
.mat::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(
    100deg,
    rgba(18, 42, 35, 0.82) 0%,
    rgba(18, 42, 35, 0.48) 34%,
    transparent 62%
  );
}

.mat > * { position: relative; z-index: 1; }

@media (max-width: 900px) {
  .mat { padding: 40px 26px; border-radius: var(--r-lg); }
  .mat::before { inset: 12px; }
}

/* --- TYPE ---------------------------------------------------------------
   Three voices, and each one has a job. Amber is annotation, the display
   serif is for statements, mono is for anything that measures or labels.  */
/* A page that is a child of another page gets a way back, above the title
   and out of the nav. The icon sprite has no directional arrows on purpose,
   so this is a literal arrow character, matching `.section-link`. */
.hero-back {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 40px;
  font-size: 12px;
  letter-spacing: 0.06em;
  color: var(--muted-2);
  transition: color 160ms ease;
}
.hero-back:hover { color: var(--text-muted); }

.hero-eyebrow,
.eyebrow {
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--accent-amber);
}

.display { font-family: var(--display); font-weight: 800; letter-spacing: -0.01em; }

.mono-label {
  font-family: var(--mono);
  font-size: 10.5px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
}

/* Section heads: a dot, then the label. */
.section-label {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent);
}
.section-label::before {
  content: "";
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--accent);
  flex: none;
}

/* --- ON THE MAT ---------------------------------------------------------
   Lavender is the interactive accent on the page's own dark ground. On the
   green it buzzes: the two sit almost opposite on the wheel at a similar
   value. Anything accented on the mat moves to amber or cream, which is
   what a green surface actually supports.

   Specificity is deliberate — these have to beat each page's own `.hero-*`
   rules, which live in an inline <style> that loads after this file.      */
.mat .hero-eyebrow,
.mat .eyebrow,
.mat .hero-acronym,
.mat .section-label { color: var(--accent-amber); }
.mat .section-label::before { background: var(--accent-amber); }

.mat .hero-title .accent,
.mat h1 .accent,
.mat h2 .accent { color: var(--paper); }

/* Chips read as pressed into the surface rather than drawn on it. */
.mat .pill-tag,
.mat .tag {
  border-color: rgba(232, 240, 235, 0.28);
  background: rgba(15, 44, 36, 0.5);
  color: rgba(238, 243, 239, 0.86);
}

/* Cream on green is the strongest pairing available, and it echoes the paper
   elsewhere on the page. */
.mat .btn-primary,
.mat .btn.primary {
  background: var(--paper);
  color: #17362d;
  border-color: var(--paper);
  box-shadow: 0 3px 12px rgba(0, 0, 0, 0.34);
}
.mat .btn-ghost,
.mat .btn.secondary {
  background: rgba(15, 44, 36, 0.78);
  border-color: rgba(232, 240, 235, 0.34);
  color: #eef3ef;
}

/* --- STICKER ------------------------------------------------------------
   The other paper language: cut out and drawn, rather than photographed.
   Where `paper-surface` imitates stock — fibre, specks, a soft shadow —
   `sticker` draws it: flat fill, a thick dark outline, and a hard offset
   shadow with no blur at all. That last one is what does the work; a blurred
   shadow reads as a UI card lifting off a page, a solid one reads as a
   cut-out lying on top of it.                                             */
.sticker {
  position: relative;
  background: var(--paper);
  color: var(--paper-ink);
  border: 1.5px solid var(--paper-ink);
  border-radius: var(--r-lg);
  box-shadow: 4px 4px 0 rgba(0, 0, 0, 0.3);
  /* No texture overlay: the fill is flat on purpose. */
}

.sticker:hover,
.sticker.is-active {
  box-shadow: 6px 6px 0 rgba(0, 0, 0, 0.36);
}

/* Blocks inside a sticker are drawn the same way — a flat panel with the
   same outline weight, not a sunken well. */
.sticker .sticker-block {
  background: rgba(34, 29, 51, 0.1);
  border: 2px solid var(--paper-ink);
  border-radius: var(--r-sm);
}

/* --- PINNED -------------------------------------------------------------
   A pin is what says "board". Without it a card with a hard shadow is just
   a cut-out floating on a colour; with it, the surface behind is implied
   even before it is drawn.

   The head sits inside the card's top edge rather than straddling it, so it
   survives `overflow: hidden` and never collides with a rotated neighbour. */
.pinned { position: relative; }
.pinned::after {
  content: "";
  position: absolute;
  top: 11px;
  left: 50%;
  width: 13px;
  height: 13px;
  z-index: 3;
  border-radius: 50%;
  background: var(--accent-red);
  /* Offset ring, not a blur: the pin has to belong to the same flat-shadow
     world as the card it holds down. */
  box-shadow:
    inset -2px -2px 0 rgba(0, 0, 0, 0.22),
    2px 3px 0 rgba(0, 0, 0, 0.4);
  transform: translateX(-50%);
}

/* --- NAV ICONS ----------------------------------------------------------
   The icon starts sitting on the label, invisible, and rises out of it on
   hover. Starting it *under* the text rather than already above is what
   makes it read as coming out of the word instead of just fading in
   somewhere nearby.                                                       */
.nav-links a { position: relative; }

.nav-ico {
  position: absolute;
  left: 50%;
  bottom: 100%;
  width: 18px;
  height: 18px;
  /* bottom:100% already puts it above the label; a negative margin here was
     dragging it back down onto the word. 6px of air instead. */
  margin-bottom: 6px;
  fill: currentColor;
  opacity: 0;
  pointer-events: none;
  transform: translate(-50%, 10px) scale(0.7);
  transition: transform 220ms cubic-bezier(0.2, 0.8, 0.3, 1), opacity 160ms ease;
}

.nav-links a:hover .nav-ico,
.nav-links a:focus-visible .nav-ico {
  opacity: 1;
  transform: translate(-50%, 0) scale(1);
}

@media (prefers-reduced-motion: reduce) {
  .nav-ico { transition: opacity 160ms ease; }
  .nav-links a:hover .nav-ico { transform: translate(-50%, 0) scale(1); }
}

/* The mobile menu is a full-screen overlay with no hover to speak of. */
@media (max-width: 640px) {
  .nav-ico { display: none; }
}

/* --- BRAND MARK ---------------------------------------------------------
   Ø in a ring, drawn in three beats: the ring circles, the oval strokes
   itself inside it, then the slash enters along its own axis and overshoots
   slightly as it lands — the bounce is what makes it read as a stroke being
   placed rather than a shape fading in.

   The drawn mark is the DEFAULT state and .is-drawing is what animates. CSS
   cannot replay an animation that has already finished, so scripts/brand.js
   toggles that class: once on load, again on hover. Without this inversion a
   visitor with JS off would get a logo stuck mid-draw.

   The dash offsets repaint rather than composite. Fine here and only here:
   a 26px element that runs on load and on hover, never in a loop. The slash
   moves on transform, which is free.

   Geometry is derived, not eyeballed. Ring r=17 -> 2*pi*r = 106.8. Oval
   7.6x10.2 -> 56.2 by Ramanujan. Slash (26,8.5)->(14,31.5) is length 25.9,
   so its entry offset is that vector reversed and overshot by 2 units.
   Change the SVG and these numbers have to be recomputed.               */
.brand-logo {
  width: 26px;
  height: 26px;
  overflow: visible;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  flex: none;
}

/* The ring carries a wash of the ink so the mark reads as a disc, the way
   the sprite icons sit on a tint rather than floating as bare line work. */
.brand-ring {
  fill: currentColor;
  fill-opacity: 0.12;
  stroke-width: 1.5;
}

.brand-slash { stroke-width: 2.1; }

/* --- the three beats, only while .is-drawing is on ---------------------- */
.brand-logo.is-drawing .brand-ring {
  stroke-dasharray: 108;
  animation: brand-ring 520ms cubic-bezier(0.3, 0.7, 0.3, 1) 60ms backwards;
}
.brand-logo.is-drawing .brand-o {
  stroke-dasharray: 58;
  animation: brand-o 420ms cubic-bezier(0.3, 0.7, 0.3, 1) 440ms backwards;
}
.brand-logo.is-drawing .brand-slash {
  animation: brand-slash 520ms cubic-bezier(0.34, 1.8, 0.5, 1) 800ms backwards;
}

@keyframes brand-ring {
  from { stroke-dashoffset: 108; fill-opacity: 0; }
  60%  { fill-opacity: 0; }
  to   { stroke-dashoffset: 0; fill-opacity: 0.12; }
}
@keyframes brand-o {
  from { stroke-dashoffset: 58; }
  to   { stroke-dashoffset: 0; }
}
@keyframes brand-slash {
  0%   { opacity: 0; transform: translate(12.9px, -24.8px); }
  30%  { opacity: 1; }
  100% { opacity: 1; transform: translate(0, 0); }
}

/* Reduced motion gets the mark, not the performance. brand.js checks the
   same query and never adds the class, but the guard is cheap. */
@media (prefers-reduced-motion: reduce) {
  .brand-logo.is-drawing .brand-ring,
  .brand-logo.is-drawing .brand-o,
  .brand-logo.is-drawing .brand-slash { animation: none; }
}
