/**
 * moralgray.love — landing page
 *
 * Direction: "blurry hollow." The ground is blown-out bone, not black. A
 * scanned figure sits at the centre of the page at roughly half opacity and
 * never fully resolves; everything else in the UI is held one step behind
 * focus and only sharpens when the reader attends to it. Nothing has a hard
 * edge — rules are gradients that fade at both ends, and sections bleed into
 * one another instead of being cut apart.
 *
 * This replaces the black/red ransom-note page, which is still live and
 * reachable at site/lab/ransom-landing.html (and at git 7b4481d).
 *
 * The figure ships as a DENSITY MAP, not a picture: the source is a point
 * cloud composited over pure white, so how far a pixel falls below white is
 * its coverage, and the residual colour is near-constant (std 8/1/3 on a mean
 * of 25/0/4). Dropping the colour and using the map as a CSS mask costs
 * nothing visually, halves the asset, and leaves the figure's tint under CSS
 * control.
 *
 * The density lives in the map's ALPHA channel, with RGB pinned to black.
 * That is not an accident and must not be "simplified" to a greyscale file:
 * mask-image defaults to mask-mode: match-source, which for a bitmap means
 * alpha, so a greyscale map masks nothing and the figure renders as a solid
 * black rectangle. mask-mode: luminance fixes it in Chrome and Firefox but
 * Safari only shipped that property in 17.2, and the failure there is the
 * whole hero turning into a black box. Alpha needs no feature detection.
 * Verified 2026-09-20 with a five-way headless probe.
 */

/* ── Tokens ──────────────────────────────────────────────────────────── */
:root {
  /* Ground. Never pure white — the page is fogged, not empty. */
  --ground:      #eceae7;
  --ground-lift: #f5f4f2;

  /* The figure's own colour, recovered from the source by un-premultiplying
     it against white. It is a wine-black, not a neutral. */
  --ink: #1a1014;

  --text:       #2a232a;   /* 12.4:1 on ground */
  --text-soft:  #5f585f;   /*  4.9:1 — body-size safe */
  --text-faint: #837c83;   /*  3.2:1 — large display text only */
  --bruise:     #7a4f5c;   /*  5.2:1 — the old crimson, drained */

  --hairline: rgba(42, 35, 42, 0.14);

  --serif: 'EB Garamond', Georgia, 'Times New Roman', serif;
  --mono:  'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace;

  --gutter:  clamp(1.25rem, 5vw, 5rem);
  --measure: 34rem;
  --ease:    cubic-bezier(0.22, 0.61, 0.36, 1);

  /* Pointer position in px, written by hollow.js. Seeded off-screen so the
     clearing does not sit mid-page before the reader has moved. */
  --lx: -60vw;
  --ly: 50vh;

  --density: url('../img/hollow-density.webp');

  /* Fog. feTurbulence, rasterised once and thereafter only transformed. The
     colour matrix pins RGB to a fixed grey and routes the noise into alpha, so
     each tile is a soft cloud rather than confetti; stitchTiles keeps it
     seamless where it repeats. */
  --fog-soft: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='820' height='820'%3E%3Cfilter id='a' x='0' y='0' width='100%25' height='100%25'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.005' numOctaves='4' seed='11' stitchTiles='stitch'/%3E%3CfeColorMatrix type='matrix' values='0 0 0 0 0.56 0 0 0 0 0.53 0 0 0 0 0.56 0.36 0.36 0.36 0 0'/%3E%3C/filter%3E%3Crect width='820' height='820' filter='url(%23a)'/%3E%3C/svg%3E");
  --fog-fine: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='520' height='520'%3E%3Cfilter id='b' x='0' y='0' width='100%25' height='100%25'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.019' numOctaves='3' seed='5' stitchTiles='stitch'/%3E%3CfeColorMatrix type='matrix' values='0 0 0 0 0.49 0 0 0 0 0.46 0 0 0 0 0.49 0.30 0.30 0.30 0 -0.04'/%3E%3C/filter%3E%3Crect width='520' height='520' filter='url(%23b)'/%3E%3C/svg%3E");
  --grain:    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='190' height='190'%3E%3Cfilter id='c' x='0' y='0' width='100%25' height='100%25'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='1' seed='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='matrix' values='0 0 0 0 0.29 0 0 0 0 0.27 0 0 0 0 0.29 0.55 0.55 0.55 0 -0.30'/%3E%3C/filter%3E%3Crect width='190' height='190' filter='url(%23c)'/%3E%3C/svg%3E");
}

@media (max-width: 680px) {
  :root { --density: url('../img/hollow-density-sm.webp'); }
}

*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

html { scroll-behavior: smooth; }

body {
  background: var(--ground);
  color: var(--text);
  font-family: var(--serif);
  font-size: clamp(1rem, 0.94rem + 0.3vw, 1.125rem);
  line-height: 1.75;
  overflow-x: hidden;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

::selection { background: var(--bruise); color: var(--ground-lift); }

:focus-visible { outline: 2px solid var(--bruise); outline-offset: 4px; }

/* ── Atmosphere ──────────────────────────────────────────────────────── */
/* Everything here is fixed and only ever animates transform or opacity, so it
   stays on the compositor and never repaints while the page scrolls. */

.atmos {
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  overflow: hidden;
  background:
    radial-gradient(ellipse 90% 70% at 50% 34%, var(--ground-lift) 0%, transparent 68%),
    radial-gradient(ellipse 70% 60% at 14% 88%, rgba(210, 204, 206, 0.55) 0%, transparent 70%),
    var(--ground);
}

.fog {
  position: absolute;
  inset: -30%;              /* oversized, so drift never exposes an edge */
  background-repeat: repeat;
  mix-blend-mode: multiply;
  will-change: transform;
}

.fog--soft {
  background-image: var(--fog-soft);
  background-size: 118vmax 118vmax;
  opacity: 0.55;
  animation: drift-a 128s ease-in-out infinite;
}

.fog--fine {
  background-image: var(--fog-fine);
  background-size: 52vmax 52vmax;
  opacity: 0.3;
  animation: drift-b 91s ease-in-out infinite;
}

@keyframes drift-a {
  0%, 100% { transform: translate3d(0, 0, 0) scale(1); }
  50%      { transform: translate3d(3.5%, -2.5%, 0) scale(1.08); }
}

@keyframes drift-b {
  0%, 100% { transform: translate3d(0, 0, 0) scale(1.04); }
  50%      { transform: translate3d(-4%, 3%, 0) scale(1); }
}

/* The clearing: a pool of thinner haze that follows the pointer. It is a
   fixed-size element moved with translate3d, not a gradient re-centred every
   frame — same picture, but style-recalc-and-composite instead of a
   full-viewport repaint at 60fps. */
.clearing {
  position: fixed;
  left: 0;
  top: 0;
  width: 56vmax;
  height: 56vmax;
  margin: -28vmax 0 0 -28vmax;
  z-index: 1;
  pointer-events: none;
  background: radial-gradient(circle closest-side,
    rgba(250, 249, 248, 0.82) 0%,
    rgba(250, 249, 248, 0.38) 40%,
    rgba(250, 249, 248, 0.12) 64%,
    transparent 78%);
  transform: translate3d(var(--lx), var(--ly), 0);
  opacity: 0;
  transition: opacity 900ms var(--ease);
  will-change: transform;
}

.has-pointer .clearing { opacity: 1; }

.grain {
  position: fixed;
  inset: -100px;
  z-index: 60;
  pointer-events: none;
  background-image: var(--grain);
  background-repeat: repeat;
  opacity: 0.5;
  mix-blend-mode: multiply;
  animation: grain-jitter 1.1s steps(1) infinite;
}

@keyframes grain-jitter {
  0%   { transform: translate3d(0, 0, 0); }
  20%  { transform: translate3d(-38px, 22px, 0); }
  40%  { transform: translate3d(29px, -31px, 0); }
  60%  { transform: translate3d(-19px, -24px, 0); }
  80%  { transform: translate3d(35px, 17px, 0); }
  100% { transform: translate3d(0, 0, 0); }
}

.vignette {
  position: fixed;
  inset: 0;
  z-index: 61;
  pointer-events: none;
  background: radial-gradient(ellipse 78% 68% at 50% 44%,
    transparent 38%, rgba(124, 116, 122, 0.16) 100%);
}

/* ── Page shell ──────────────────────────────────────────────────────── */

.masthead, main, .colophon { position: relative; z-index: 3; }

.masthead {
  position: fixed;
  inset: 0 0 auto;
  z-index: 40;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 1.15rem var(--gutter);
  transition: transform 420ms var(--ease), opacity 420ms var(--ease);
}

/* Rules never terminate; they fade out at both ends. */
.masthead::after {
  content: '';
  position: absolute;
  inset: auto 0 0;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--hairline) 18%, var(--hairline) 82%, transparent);
  opacity: 0;
  transition: opacity 420ms var(--ease);
}

.is-scrolled .masthead::after { opacity: 1; }
.is-scrolled .masthead { backdrop-filter: blur(7px); }
.masthead.is-gone { transform: translateY(-100%); opacity: 0; }

.mark {
  font-family: var(--mono);
  font-weight: 200;
  font-size: 0.8rem;
  letter-spacing: 0.42em;
  text-transform: uppercase;
  color: var(--text-soft);
  text-decoration: none;
  transition: color 320ms var(--ease), letter-spacing 420ms var(--ease);
}

.mark:hover { color: var(--text); letter-spacing: 0.5em; }

.wayfinding {
  display: flex;
  gap: clamp(1rem, 3vw, 2.4rem);
  list-style: none;
}

/* Links sit one step out of focus and resolve when attended to — the page's
   whole thesis, applied to the navigation. */
.wayfinding a {
  position: relative;
  display: inline-block;
  padding: 0.2rem 0;
  font-family: var(--mono);
  font-weight: 200;
  font-size: 0.72rem;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  /* --text-faint would be 3.2:1 here, under AA for text this small, and a
     resting blur costs more contrast again — so small UI text resolves by
     colour and tracking only. The blur trick stays on the plate titles, which
     are large enough to carry it. */
  color: var(--text-soft);
  opacity: 0.72;
  text-decoration: none;
  transition: color 320ms var(--ease), opacity 320ms var(--ease), letter-spacing 420ms var(--ease);
}

.wayfinding a::after {
  content: '';
  position: absolute;
  inset: auto 0 0;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--bruise), transparent);
  transform: scaleX(0);
  transition: transform 420ms var(--ease);
}

.wayfinding a:hover,
.wayfinding a:focus-visible {
  color: var(--text);
  opacity: 1;
  letter-spacing: 0.34em;
}

.wayfinding a:hover::after,
.wayfinding a:focus-visible::after { transform: scaleX(1); }

/* ── Hero ────────────────────────────────────────────────────────────── */

.hero {
  position: relative;
  min-height: 100vh;
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  padding: 0 var(--gutter);
  overflow: hidden;
}

/* The wordmark sits behind the figure, in the upper third, so the figure's
   haze passes across its lower edge. */
.hero__mark {
  position: absolute;
  inset: clamp(5.5rem, 15vh, 9.5rem) var(--gutter) auto;
  z-index: 1;
  text-align: center;
  font-family: var(--mono);
  font-weight: 200;
  font-size: clamp(1.9rem, 9vw, 7rem);
  line-height: 1;
  letter-spacing: 0.26em;
  text-indent: 0.26em;      /* tracking adds a trailing gap; recentre the word */
  text-transform: uppercase;
  color: var(--text-faint);
  transition: color 900ms var(--ease), letter-spacing 1200ms var(--ease);
}

.hero:hover .hero__mark { color: var(--text-soft); letter-spacing: 0.29em; }

/* ── The figure ──────────────────────────────────────────────────────── */

.figure {
  position: absolute;
  left: 50%;
  bottom: 0;
  z-index: 2;
  width: min(62vh, 74vw, 620px);
  aspect-ratio: 1100 / 1335;
  display: block;
  text-decoration: none;
  /* It navigates now, so it wears a pointer. The crosshair said "instrument",
     which was true when its only behaviour was the scatter. */
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  /* Pointer parallax and the recede-on-scroll, both written by hollow.js. */
  transform: translate3d(calc(-50% + var(--par-x, 0px)),
                         calc(var(--par-y, 0px) + var(--sink, 0px)), 0);
  will-change: transform;
}

.figure__layer {
  position: absolute;
  inset: 0;
  background-color: var(--ink);
  -webkit-mask-image: var(--density);
          mask-image: var(--density);
  -webkit-mask-size: 100% 100%;
          mask-size: 100% 100%;
  -webkit-mask-repeat: no-repeat;
          mask-repeat: no-repeat;
}

/* The smear: a blurred copy drifting slightly out of register with the body,
   which is what gives a still image the feel of something not holding still. */
.figure__layer--ghost {
  opacity: calc(0.42 * (1 - var(--dissolve, 0)));
  filter: blur(11px);
  animation: smear 23s ease-in-out infinite;
}

@keyframes smear {
  0%, 100% { transform: translate3d(-6px, 3px, 0) scale(1.012); }
  50%      { transform: translate3d(7px, -5px, 0) scale(1.024); }
}

/* The body gains presence as the pointer nears it (--near, 0…1) and fades as
   the hero scrolls away (--dissolve). It never reaches full opacity: the
   figure is hollow, and resolving it completely would be the wrong ending. */
.figure__layer--body {
  opacity: calc((0.78 + var(--near, 0) * 0.22) * (1 - var(--dissolve, 0)));
  filter: blur(calc((1 - var(--near, 0)) * 1.6px + var(--dissolve, 0) * 9px));
  transition: opacity 620ms var(--ease), filter 620ms var(--ease);
}

/* The scatter canvas renders at low resolution on purpose and is blown up
   here: the upscale plus a blur turns 1px points into soft motes, which is
   both cheaper and closer to the source than crisp particles would be. */
.scatter {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 3;
  opacity: 0;
  pointer-events: none;
  filter: blur(2.4px);
  transition: opacity 160ms linear;
}

.is-scattered .scatter { opacity: 1; }
.is-scattered .figure__layer { opacity: 0; transition: opacity 160ms linear; }

/* The haze bank at the foot of the hero. It swallows the bottom of the figure,
   which is where the source scan runs out of frame — so the crop edge never
   shows and the figure reads as sinking into fog rather than being cut off. */
.hero__bank {
  position: absolute;
  inset: auto 0 0;
  height: 46%;
  z-index: 3;
  pointer-events: none;
  background: linear-gradient(to top,
    var(--ground) 0%,
    rgba(236, 234, 231, 0.96) 22%,
    rgba(236, 234, 231, 0.70) 46%,
    rgba(236, 234, 231, 0.28) 72%,
    transparent 100%);
}

.hero__foot {
  position: relative;
  z-index: 4;
  padding-bottom: clamp(2.5rem, 9vh, 5.5rem);
  text-align: center;
}

.hero__line {
  font-style: italic;
  font-size: clamp(1.05rem, 2.6vw, 1.5rem);
  color: var(--text-soft);
  letter-spacing: 0.04em;
  margin-bottom: 2.1rem;
}

/* ── The way in ──────────────────────────────────────────────────────── */

.threshold {
  position: relative;
  display: inline-block;
  padding: 0.85rem 2.6rem;
  font-family: var(--mono);
  font-weight: 200;
  font-size: 0.78rem;
  letter-spacing: 0.4em;
  text-indent: 0.4em;
  text-transform: uppercase;
  color: var(--text-soft);
  text-decoration: none;
  background: rgba(250, 249, 248, 0.34);
  border: 1px solid var(--hairline);
  transition: color 420ms var(--ease), background 420ms var(--ease),
              letter-spacing 620ms var(--ease), text-indent 620ms var(--ease),
              box-shadow 620ms var(--ease), border-color 420ms var(--ease);
}

.threshold:hover,
.threshold:focus-visible {
  color: var(--text);
  background: rgba(252, 251, 251, 0.72);
  border-color: rgba(42, 35, 42, 0.26);
  letter-spacing: 0.5em;
  text-indent: 0.5em;
  /* Breath on glass, not a drop shadow. */
  box-shadow: 0 0 0 1px rgba(250, 249, 248, 0.6),
              0 12px 44px -18px rgba(42, 35, 42, 0.5);
}

.cue {
  position: absolute;
  left: 50%;
  bottom: 1.1rem;
  z-index: 4;
  width: 1px;
  height: clamp(28px, 5vh, 44px);
  transform: translateX(-50%);
  background: linear-gradient(to bottom, transparent, var(--text-faint), transparent);
  animation: cue-breathe 4.2s ease-in-out infinite;
}

@keyframes cue-breathe {
  0%, 100% { opacity: 0.25; transform: translateX(-50%) scaleY(0.72); }
  50%      { opacity: 0.8;  transform: translateX(-50%) scaleY(1); }
}

/* ── Sections ────────────────────────────────────────────────────────── */

.strata { padding: clamp(5rem, 14vh, 9rem) var(--gutter); }

.strata--works {
  background: linear-gradient(to bottom, transparent,
    rgba(247, 246, 245, 0.66) 30%, rgba(247, 246, 245, 0.66) 70%, transparent);
}

.strata--about {
  background: linear-gradient(to bottom, transparent,
    rgba(216, 211, 210, 0.44) 34%, rgba(216, 211, 210, 0.44) 66%, transparent);
}

.strata__label {
  display: block;
  margin-bottom: clamp(2.5rem, 6vh, 4rem);
  text-align: center;
  font-family: var(--mono);
  font-weight: 200;
  font-size: clamp(0.72rem, 1.4vw, 0.85rem);
  letter-spacing: 0.52em;
  text-indent: 0.52em;
  text-transform: uppercase;
  color: var(--text-soft);
}

.strata__label::after {
  content: '';
  display: block;
  width: min(220px, 46vw);
  height: 1px;
  margin: 1.1rem auto 0;
  background: linear-gradient(90deg, transparent, var(--hairline), transparent);
}

.shelf {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(clamp(240px, 30vw, 300px), 1fr));
  gap: clamp(1.25rem, 3vw, 2rem);
  max-width: 1080px;
  margin: 0 auto;
}

.plate {
  position: relative;
  display: block;
  padding: 2rem 1.9rem 1.8rem;
  text-decoration: none;
  color: inherit;
  background: rgba(250, 249, 248, 0.42);
  border: 1px solid var(--hairline);
  backdrop-filter: blur(5px);
  transition: background 520ms var(--ease), border-color 520ms var(--ease),
              transform 520ms var(--ease), box-shadow 520ms var(--ease),
              backdrop-filter 520ms var(--ease);
}

a.plate:hover,
a.plate:focus-visible {
  background: rgba(253, 252, 252, 0.8);
  border-color: rgba(42, 35, 42, 0.24);
  transform: translateY(-4px);
  backdrop-filter: blur(0px);
  box-shadow: 0 22px 60px -30px rgba(42, 35, 42, 0.55);
}

.plate__kind {
  font-family: var(--mono);
  font-weight: 200;
  font-size: 0.64rem;
  letter-spacing: 0.34em;
  text-transform: uppercase;
  color: var(--bruise);
  margin-bottom: 0.9rem;
}

.plate__name {
  font-size: clamp(1.5rem, 3.4vw, 2rem);
  font-weight: 400;
  line-height: 1.15;
  margin-bottom: 0.85rem;
  color: var(--text);
  filter: blur(0.6px);      /* held just out of focus until attended to */
  transition: filter 520ms var(--ease);
}

a.plate:hover .plate__name,
a.plate:focus-visible .plate__name { filter: blur(0); }

.plate__gloss {
  font-style: italic;
  font-size: 0.98rem;
  line-height: 1.7;
  color: var(--text-soft);
}

.plate__go {
  display: inline-block;
  margin-top: 1.5rem;
  font-family: var(--mono);
  font-weight: 200;
  font-size: 0.68rem;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: var(--text-soft);
  transition: transform 520ms var(--ease), letter-spacing 520ms var(--ease), color 520ms var(--ease);
}

a.plate:hover .plate__go,
a.plate:focus-visible .plate__go {
  transform: translateX(8px);
  letter-spacing: 0.38em;
  color: var(--bruise);
}

/* The unmade work: present, unreadable — which is the honest state of it. */
.plate--unmade {
  background: rgba(250, 249, 248, 0.16);
  border-style: dashed;
  border-color: rgba(42, 35, 42, 0.1);
}

.plate--unmade .plate__name,
.plate--unmade .plate__gloss { filter: blur(2.4px); opacity: 0.55; }
.plate--unmade .plate__kind { color: var(--text-faint); }

.creed {
  max-width: var(--measure);
  margin: 0 auto;
  text-align: center;
  font-style: italic;
  font-size: clamp(1.1rem, 2.4vw, 1.42rem);
  line-height: 1.95;
  color: var(--text);
}

.colophon { padding: 3rem var(--gutter) 3.5rem; text-align: center; }

.colophon::before {
  content: '';
  display: block;
  width: min(420px, 70vw);
  height: 1px;
  margin: 0 auto 2.2rem;
  background: linear-gradient(90deg, transparent, var(--hairline), transparent);
}

.colophon p {
  font-family: var(--mono);
  font-weight: 200;
  font-size: 0.64rem;
  letter-spacing: 0.34em;
  text-transform: uppercase;
  color: var(--text-soft);   /* not --text-faint: too small for 3.2:1 */
}

/* ── Surfacing ───────────────────────────────────────────────────────── */
/* Content arrives out of focus and settles. Gated on .js so that with
   scripting off everything is simply visible rather than permanently hidden. */

.js [data-surface] {
  opacity: 0;
  filter: blur(14px);
  transform: translateY(22px);
  transition: opacity 1100ms var(--ease), filter 1100ms var(--ease), transform 1100ms var(--ease);
}

.js [data-surface].is-surfaced {
  opacity: 1;
  filter: blur(0);
  transform: none;
}

/* ── Reduced motion ──────────────────────────────────────────────────── */
/* Drift, grain jitter and the scatter are suppressed. The pointer clearing and
   the hover resolutions stay: they are reader-initiated, carry no vestibular
   load, and they are the page's actual affordances. */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

  .fog--soft, .fog--fine, .grain, .figure__layer--ghost, .cue {
    animation: none !important;
  }

  .cue { opacity: 0.45; }

  .js [data-surface] {
    opacity: 1;
    filter: none;
    transform: none;
    transition: none;
  }
}

/* ── Small screens ───────────────────────────────────────────────────── */

@media (max-width: 680px) {
  .masthead { padding: 0.9rem 1.1rem; }
  .wayfinding { gap: 0.9rem; }
  .wayfinding a { font-size: 0.64rem; letter-spacing: 0.22em; }
  .mark { font-size: 0.7rem; letter-spacing: 0.3em; }

  .hero__mark {
    inset: clamp(4.5rem, 17vh, 9.5rem) 1.25rem auto;
    letter-spacing: 0.16em;
    text-indent: 0.16em;
  }

  /* Bleed past the viewport and let .hero's overflow crop it. The source has
     about 8% of empty margin on each side (content runs x 1426–2756 inside a
     1590-wide crop), so 118vw trims the transparent padding and almost nothing
     else — without it the figure is width-bound on a portrait screen, ends up
     half the height of the one below it, and leaves a dead field of fog
     between the wordmark and the figure's head. */
  .figure { width: min(118vw, 74vh); }
  .hero__bank { height: 50%; }
  .strata { padding: 4rem 1.25rem; }
  .plate { padding: 1.6rem 1.4rem 1.4rem; }
}

/* Coarse pointers get no clearing — there is no hover to follow. */
@media (hover: none) {
  .clearing { display: none; }
}
