/* ============================================================================
   FRAMELITH — framelith.com
   ----------------------------------------------------------------------------
   Hand-written. No framework, no build step, no external requests.
   Depends on tokens.css (the canonical brand token file) loaded before this.

   THREE RULES THIS FILE OBEYS
   1. Content is never hidden by CSS that only JavaScript can undo. Every
      reveal is a scroll-driven CSS animation behind @supports, so with JS off,
      with the script blocked, or in a browser without scroll timelines, the
      page is simply fully visible. There is no class-gating and no flash.
   2. Motion is THE WIPE: directional, with a bright leading edge, and it CUTS
      rather than crossfades. Everything collapses to 0ms under reduced motion.
   3. The signal colour (#FF5D2E) appears roughly once per viewport, on purpose.

   MEASURED CONTRAST against the page ground #0A0A0C (WCAG 2.2):
     #F2EFE8 paper      17.2 : 1   -> AAA, any size
     #97949F ash         6.6 : 1   -> AA any size, AAA large only
     #FF5D2E signal      6.5 : 1   -> AA any size
     #6E8FA8 cyanotype   5.8 : 1   -> AA any size
     #5E5B67 mute        3.0 : 1   -> FAILS text. Never used for text in this
                                      file; borders and inert rules only.
   ========================================================================= */

/* ---------------------------------------------------------------- reset --- */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--fl-ink);
  color: var(--fl-paper);
  font-family: var(--fl-font-ui);
  font-size: var(--fl-text-base);
  font-weight: 400;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;
  font-synthesis-weight: none;
}

h1, h2, h3, h4 { margin: 0; font-weight: 400; line-height: 1.08; text-wrap: balance; }
p { margin: 0; text-wrap: pretty; }
ul, ol { margin: 0; padding: 0; list-style: none; }
img, svg, video { display: block; max-width: 100%; height: auto; }
a { color: inherit; }
:target { scroll-margin-top: 6rem; }

/* The grain. Always present, never loud. Generated in-document, so it costs
   no request and cannot be used to track anyone. */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 100;
  pointer-events: none;
  opacity: var(--fl-grain-opacity);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* ------------------------------------------------------- focus + a11y ---- */
:focus-visible {
  outline: 2px solid var(--fl-signal);
  outline-offset: 3px;
  border-radius: var(--fl-r-sm);
}
.fl-skip {
  position: absolute;
  left: var(--fl-4);
  top: -100%;
  z-index: 200;
  padding: var(--fl-3) var(--fl-6);
  background: var(--fl-signal);
  color: var(--fl-ink);
  font-weight: 600;
  font-size: var(--fl-text-sm);
  letter-spacing: .04em;
  text-transform: uppercase;
  text-decoration: none;
  border-radius: var(--fl-r-sm);
  transition: top var(--fl-dur-cut) var(--fl-ease-cut);
}
.fl-skip:focus { top: var(--fl-4); }

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

/* --------------------------------------------------------- structure ----- */
.fl-shell { width: 100%; max-width: 1180px; margin-inline: auto; padding-inline: var(--fl-6); }
@media (min-width: 900px) { .fl-shell { padding-inline: var(--fl-8); } }

.fl-band { padding-block: var(--fl-24); border-top: 1px solid var(--fl-graphite); }
.fl-band:first-of-type { border-top: 0; }
@media (max-width: 700px) { .fl-band { padding-block: var(--fl-16); } }

/* Section eyebrow: mono, tracked, with the seam pip on its left edge. */
.fl-eyebrow {
  display: flex;
  align-items: center;
  gap: var(--fl-3);
  margin-bottom: var(--fl-8);
  font-family: var(--fl-font-mono);
  font-size: var(--fl-text-xs);
  font-weight: 500;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--fl-ash);
}
.fl-eyebrow::before {
  content: "";
  flex: none;
  width: 2px; height: 1em;
  background: var(--fl-signal);
}
.fl-eyebrow--then { color: var(--fl-cyanotype); }
.fl-eyebrow--then::before { background: var(--fl-cyanotype); }

.fl-h2 {
  font-family: var(--fl-font-display);
  font-size: clamp(2rem, 4.6vw, var(--fl-text-2xl));
  letter-spacing: -.012em;
  max-width: 22ch;
}
.fl-h3 {
  font-family: var(--fl-font-ui);
  font-size: var(--fl-text-lg);
  font-weight: 600;
  letter-spacing: -.008em;
}
.fl-lead {
  margin-top: var(--fl-6);
  max-width: 62ch;
  font-size: clamp(1.0625rem, 1.6vw, var(--fl-text-lg));
  line-height: 1.62;
  color: var(--fl-ash);
}
.fl-body { max-width: 62ch; color: var(--fl-ash); }
.fl-body + .fl-body { margin-top: var(--fl-4); }
.fl-body strong { color: var(--fl-paper); font-weight: 500; }

.fl-mono {
  font-family: var(--fl-font-mono);
  font-size: var(--fl-text-xs);
  letter-spacing: .06em;
  color: var(--fl-ash);
}

/* ---- spacing utilities -------------------------------------------------
   These exist because the page ships a strict CSP with `style-src 'self'`
   and NO 'unsafe-inline', which blocks every inline style attribute. An
   inline `style="margin-top:…"` is silently dropped by the browser and the
   spacing just vanishes. Keeping the CSP strict is the privacy commitment
   the colophon makes, so the spacing comes from classes instead.
   Guarded by tests/guard.mjs -> no-inline-style-attributes.
   --------------------------------------------------------------------- */
.fl-mt-4  { margin-top: var(--fl-4); }
.fl-mt-6  { margin-top: var(--fl-6); }
.fl-mt-8  { margin-top: var(--fl-8); }
.fl-mt-12 { margin-top: var(--fl-12); }
.fl-mt-24 { margin-top: var(--fl-24); }
.fl-mb-6  { margin-bottom: var(--fl-6); }
@media (max-width: 700px) { .fl-mt-24 { margin-top: var(--fl-16); } }

/* ========================================================================
   THE SEAM — the brand's signature gesture, one device at four scales.
   ===================================================================== */

/* 1. HERO SCALE — the operable Monolith.
   ----------------------------------------------------------------------------
   The seam position is expressed as CONCRETE values — a percentage in the
   clip-path and a percentage in `left` — never as a custom property inside a
   calc(). `clip-path: inset(0 0 0 calc(var(--seam) * 1%))` resolves once and
   then never re-resolves when the property changes: getComputedStyle reports
   the new number while the rendered seam sits still, so the whole scrubber
   silently did nothing. Registering --seam with @property did not fix it.
   Measured, not assumed — see the note on .fl-geo__strip for the identical
   failure in the platform diagram.
   The declared 50% IS the no-JS state, and the no-JS state is the logo. */
.seam {
  position: relative;
  aspect-ratio: 9 / 16;
  width: 100%;
  max-width: 340px;
  border: 1px solid var(--fl-graphite);
  border-radius: var(--fl-r-slab);
  background: var(--fl-carbon);
  overflow: hidden;
  touch-action: pan-y;
  isolation: isolate;
}
.seam__plate { position: absolute; inset: 0; }

/* THEN — the archive. Cool, scanlined, contact-print. */
.seam__then {
  background:
    repeating-linear-gradient(0deg, rgb(10 10 12 / .38) 0 1px, transparent 1px 3px),
    var(--fl-then-grad);
  filter: contrast(1.04) saturate(.82);
}
/* NOW — the render. Warm, clean, lit. */
.seam__now {
  background: var(--fl-now-grad);
  filter: saturate(1.04);
  clip-path: inset(0 0 0 50%);
}
/* The scrub head: a bright leading edge with a paper tick top and bottom. */
.seam__edge {
  position: absolute;
  top: 0; bottom: 0;
  left: 50%;
  width: 2px;
  margin-left: -1px;
  background: var(--fl-paper);
  box-shadow: 0 0 14px 1px rgb(255 93 46 / .55);
}
.seam__edge::before,
.seam__edge::after {
  content: "";
  position: absolute;
  left: -3px;
  width: 8px; height: 2px;
  background: var(--fl-paper);
}
.seam__edge::before { top: 8%; }
.seam__edge::after  { bottom: 8%; }

/* Corner registration marks — a film-lab tell, pure decoration. */
.seam__reg {
  position: absolute;
  inset: var(--fl-3);
  pointer-events: none;
  background:
    linear-gradient(var(--fl-paper) 0 0) 0 0 / 9px 1px no-repeat,
    linear-gradient(var(--fl-paper) 0 0) 0 0 / 1px 9px no-repeat,
    linear-gradient(var(--fl-paper) 0 0) 100% 100% / 9px 1px no-repeat,
    linear-gradient(var(--fl-paper) 0 0) 100% 100% / 1px 9px no-repeat;
  opacity: .3;
}

/* The real control. Disabled in markup; site.js enables it, so with no JS it
   is inert and unfocusable rather than a control that lies. */
.seam__range {
  position: absolute;
  inset: 0;
  width: 100%; height: 100%;
  margin: 0;
  opacity: 0;
  cursor: ew-resize;
  -webkit-appearance: none;
  appearance: none;
  background: transparent;
}
.seam__range:disabled { cursor: default; }
.seam__range::-webkit-slider-thumb { -webkit-appearance: none; width: 44px; height: 100%; }
.seam__range::-moz-range-thumb { width: 44px; height: 100%; border: 0; background: transparent; }
.seam:has(.seam__range:focus-visible) {
  outline: 2px solid var(--fl-signal);
  outline-offset: 3px;
}

/* THE ENTRY WIPE. The render field arrives once, as a cut-like reveal, and then
   it stops for good. It never loops and it never pulses.
   The keyframes animate the concrete clip-path and offset, not a custom
   property, for the invalidation reason described above. No fill-mode, so once
   the 680ms entry has played the declared 50% applies again and the inline
   values JS writes during a drag take over cleanly. */
@media (prefers-reduced-motion: no-preference) {
  .seam__now  { animation: fl-seam-in   var(--fl-dur-scrub) var(--fl-ease-scrub); }
  .seam__edge { animation: fl-seam-edge var(--fl-dur-scrub) var(--fl-ease-scrub); }
}
@keyframes fl-seam-in   { from { clip-path: inset(0 0 0 97%); } to { clip-path: inset(0 0 0 50%); } }
@keyframes fl-seam-edge { from { left: 97%; } to { left: 50%; } }

.seam__legend {
  display: flex;
  justify-content: space-between;
  gap: var(--fl-4);
  margin-top: var(--fl-3);
  max-width: 340px;
  font-family: var(--fl-font-mono);
  font-size: var(--fl-text-xs);
  letter-spacing: .14em;
  text-transform: uppercase;
}
.seam__legend b { font-weight: 500; color: var(--fl-cyanotype); }
.seam__legend i { font-style: normal; font-weight: 500; color: var(--fl-signal); }

/* 2. DIVIDER SCALE — the seam as a hairline whose bright edge travels once. */
.fl-rule {
  position: relative;
  height: 1px;
  background: var(--fl-graphite);
  overflow: hidden;
}
.fl-rule::after {
  content: "";
  position: absolute;
  inset-block: 0;
  left: 0;
  width: 22%;
  background: linear-gradient(90deg, transparent, var(--fl-signal));
}

/* 3. ROW SCALE — every catalogue row carries a seam pip on its leading edge. */
/* 4. MASTHEAD SCALE — the sticky border fills with scroll progress. */

/* ========================================================================
   MASTHEAD
   ===================================================================== */
/* Solid ground, no translucency and no backdrop-filter: translucency plus a
   backdrop blur IS glassmorphism, which the brand forbids. Declaring otherwise
   would not change what renders. The 1px hairline is the only separation. */
.fl-masthead {
  position: sticky;
  top: 0;
  z-index: 50;
  background: var(--fl-ink);
  border-bottom: 1px solid var(--fl-graphite);
}
.fl-masthead__in {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--fl-6);
  padding-block: var(--fl-4);
}
/* padding-block keeps the home link at the 24px WCAG 2.2 target minimum */
.fl-wordmark { display: flex; align-items: center; gap: var(--fl-3); padding-block: 3px; text-decoration: none; }
.fl-wordmark svg { width: 22px; height: 22px; flex: none; }
.fl-wordmark span {
  font-size: var(--fl-text-sm);
  font-weight: var(--fl-wordmark-weight);
  letter-spacing: var(--fl-wordmark-tracking);
  text-transform: uppercase;
}
.fl-nav { display: none; gap: var(--fl-6); align-items: center; }
@media (min-width: 860px) { .fl-nav { display: flex; } }
.fl-nav a {
  position: relative;
  padding-block: var(--fl-1);
  font-size: var(--fl-text-sm);
  color: var(--fl-ash);
  text-decoration: none;
  transition: color var(--fl-dur-cut) var(--fl-ease-cut);
}
.fl-nav a::after {
  content: "";
  position: absolute;
  left: 0; right: 100%; bottom: -2px;
  height: 1px;
  background: var(--fl-signal);
  transition: right var(--fl-dur-wipe) var(--fl-ease-wipe);
}
.fl-nav a:hover { color: var(--fl-paper); }
.fl-nav a:hover::after { right: 0; }

/* Scroll-progress seam under the masthead. CSS-only; no listener. */
.fl-progress {
  height: 1px;
  background: var(--fl-signal);
  transform-origin: 0 50%;
  transform: scaleX(0);
}
@supports (animation-timeline: scroll()) {
  @media (prefers-reduced-motion: no-preference) {
    .fl-progress {
      animation: fl-progress linear both;
      animation-timeline: scroll(root block);
    }
  }
}
@keyframes fl-progress { from { transform: scaleX(0); } to { transform: scaleX(1); } }

/* ========================================================================
   HERO
   ===================================================================== */
.fl-hero { padding-block: var(--fl-24) var(--fl-16); }
@media (max-width: 700px) { .fl-hero { padding-block: var(--fl-12) var(--fl-12); } }

.fl-hero__grid {
  display: grid;
  gap: var(--fl-12);
  align-items: center;
}
@media (min-width: 900px) {
  .fl-hero__grid { grid-template-columns: minmax(0, 1.35fr) minmax(0, .65fr); gap: var(--fl-16); }
}

.fl-hero__eyebrow {
  font-family: var(--fl-font-mono);
  font-size: var(--fl-text-xs);
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--fl-ash);
}
.fl-hero h1 {
  margin-top: var(--fl-6);
  font-family: var(--fl-font-display);
  font-size: clamp(2.75rem, 8.4vw, var(--fl-text-4xl));
  letter-spacing: -.022em;
  line-height: .98;
}
.fl-hero h1 em { font-style: italic; }
.fl-hero__sub {
  margin-top: var(--fl-6);
  max-width: 54ch;
  font-size: clamp(1.0625rem, 1.7vw, var(--fl-text-lg));
  line-height: 1.6;
  color: var(--fl-ash);
}
.fl-hero__sub strong { color: var(--fl-paper); font-weight: 500; }

/* COMPLIANCE: the hero disclosure. Full text colour (17.2:1), 13px, above the
   buttons. Never restyle to --fl-ash or --fl-mute, never shrink below 12px, and
   never move it below the CTAs. Guarded by tests/guard.mjs. */
.fl-hero__disclosure {
  margin-top: var(--fl-8);
  max-width: 56ch;
  padding-left: var(--fl-4);
  border-left: 2px solid var(--fl-ember);
  font-family: var(--fl-font-mono);
  font-size: 0.8125rem;
  line-height: 1.7;
  color: var(--fl-paper);
}
.fl-hero__disclosure a { color: var(--fl-ember); text-decoration-thickness: 1px; text-underline-offset: 3px; }

.fl-ctas { display: flex; flex-wrap: wrap; gap: var(--fl-4); margin-top: var(--fl-8); }
.fl-cat__foot { margin-top: var(--fl-6); max-width: 76ch; line-height: 1.7; }

/* ------------------------------------------------------------- buttons --- */
.fl-btn {
  --btn-bg: transparent;
  --btn-fg: var(--fl-paper);
  --btn-bd: var(--fl-graphite);
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: var(--fl-2);
  padding: var(--fl-3) var(--fl-6);
  border: 1px solid var(--btn-bd);
  border-radius: var(--fl-r-sm);
  background: var(--btn-bg);
  color: var(--btn-fg);
  font-family: inherit;
  font-size: var(--fl-text-sm);
  font-weight: 500;
  letter-spacing: .02em;
  text-decoration: none;
  cursor: pointer;
  overflow: hidden;
  transition: border-color var(--fl-dur-cut) var(--fl-ease-cut),
              color var(--fl-dur-cut) var(--fl-ease-cut);
}
/* The wipe: a leading edge sweeps the button, it does not fade in. */
.fl-btn::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: var(--fl-now-grad);
  transform: translateX(-100%);
  transition: transform var(--fl-dur-wipe) var(--fl-ease-wipe);
}
.fl-btn--primary {
  --btn-bg: var(--fl-signal);
  --btn-fg: var(--fl-ink);
  --btn-bd: var(--fl-signal);
  font-weight: 600;
}
.fl-btn--primary:hover::before { transform: translateX(0); }
.fl-btn--ghost:hover { border-color: var(--fl-ash); }
.fl-btn__arrow { transition: transform var(--fl-dur-cut) var(--fl-ease-cut); }
.fl-btn:hover .fl-btn__arrow { transform: translateX(3px); }

/* ========================================================================
   DISCLOSURE — a compliance requirement, not a design element.
   Full contrast, full width, no motion, present before any script runs.
   Shrinking, greying, collapsing or moving this below the fold is a
   BLOCKING regression. See tests/guard-compliance.mjs.
   ===================================================================== */
.fl-disclosure {
  border-block: 1px solid var(--fl-graphite);
  border-left: 2px solid var(--fl-signal);
  background: var(--fl-carbon);
}
.fl-disclosure__in {
  display: grid;
  gap: var(--fl-4);
  padding-block: var(--fl-8);
}
@media (min-width: 860px) {
  .fl-disclosure__in { grid-template-columns: 15rem minmax(0, 1fr); gap: var(--fl-8); align-items: start; }
}
.fl-disclosure h2 {
  font-family: var(--fl-font-mono);
  font-size: var(--fl-text-xs);
  font-weight: 500;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--fl-signal);
}
.fl-disclosure p {
  max-width: 68ch;
  font-size: var(--fl-text-base);
  color: var(--fl-paper);
}
.fl-disclosure p + p { margin-top: var(--fl-3); }

/* ========================================================================
   SPEC ROWS + CATALOGUE
   ===================================================================== */
.fl-cols {
  display: grid;
  gap: var(--fl-8);
  margin-top: var(--fl-12);
}
@media (min-width: 760px)  { .fl-cols--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 900px)  { .fl-cols--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (min-width: 1000px) { .fl-cols--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); } }

.fl-card {
  padding: var(--fl-6);
  border: 1px solid var(--fl-graphite);
  border-radius: var(--fl-r-md);
  background: var(--fl-carbon);
}
.fl-card__n {
  font-family: var(--fl-font-mono);
  font-size: var(--fl-text-xs);
  letter-spacing: .14em;
  color: var(--fl-cyanotype);
}
.fl-card h3 { margin-top: var(--fl-4); font-size: var(--fl-text-base); font-weight: 600; }
.fl-card p { margin-top: var(--fl-3); font-size: var(--fl-text-sm); color: var(--fl-ash); }

/* The catalogue: accession numbers hanging off a vertical seam spine. */
.fl-cat { margin-top: var(--fl-12); border-top: 1px solid var(--fl-graphite); }
.fl-cat__row {
  display: grid;
  grid-template-columns: 3.25rem minmax(0, 1fr);
  gap: var(--fl-4);
  align-items: baseline;
  padding-block: var(--fl-6);
  border-bottom: 1px solid var(--fl-graphite);
}
@media (min-width: 780px) {
  .fl-cat__row { grid-template-columns: 3.25rem minmax(0, 1fr) 12rem; gap: var(--fl-6); }
}
.fl-cat__n {
  font-family: var(--fl-font-mono);
  font-size: var(--fl-text-xs);
  letter-spacing: .1em;
  color: var(--fl-cyanotype);
}
.fl-cat__t {
  font-family: var(--fl-font-display);
  font-size: clamp(1.25rem, 2.4vw, var(--fl-text-xl));
  letter-spacing: -.01em;
}
.fl-cat__m {
  font-family: var(--fl-font-mono);
  font-size: var(--fl-text-xs);
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--fl-ash);
}
@media (min-width: 780px) { .fl-cat__m { text-align: right; } }

/* Spec table — the frame-geometry plate. */
.fl-spec { margin-top: var(--fl-12); width: 100%; border-collapse: collapse; text-align: left; }
.fl-spec caption {
  margin-bottom: var(--fl-4);
  font-family: var(--fl-font-mono);
  font-size: var(--fl-text-xs);
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--fl-ash);
  text-align: left;
}
.fl-spec th, .fl-spec td {
  padding: var(--fl-4) var(--fl-3);
  border-bottom: 1px solid var(--fl-graphite);
  vertical-align: baseline;
}
.fl-spec thead th {
  font-family: var(--fl-font-mono);
  font-size: var(--fl-text-xs);
  font-weight: 500;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--fl-ash);
  white-space: nowrap;
}
.fl-spec tbody th { font-size: var(--fl-text-sm); font-weight: 600; }
.fl-spec td { font-family: var(--fl-font-mono); font-size: var(--fl-text-sm); color: var(--fl-ash); }
.fl-spec td b { color: var(--fl-paper); font-weight: 500; }
/* The seam as the divider between the platform column and the numbers. */
.fl-spec th:first-child, .fl-spec td:first-child { border-right: 1px solid var(--fl-graphite); padding-left: 0; }
.fl-spec__wrap { overflow-x: auto; }

/* Refusals list — what the studio will not do. */
.fl-refuse { margin-top: var(--fl-12); display: grid; gap: 0; }
.fl-refuse li {
  display: grid;
  grid-template-columns: 1.5rem minmax(0, 1fr);
  gap: var(--fl-4);
  padding-block: var(--fl-4);
  border-bottom: 1px solid var(--fl-graphite);
  color: var(--fl-ash);
  font-size: var(--fl-text-sm);
}
.fl-refuse li::before {
  content: "\2715";
  color: var(--fl-refuse);
  font-family: var(--fl-font-mono);
  font-size: var(--fl-text-xs);
  line-height: 1.7;
}
.fl-refuse b { color: var(--fl-paper); font-weight: 500; }

/* ========================================================================
   MORPH DEMONSTRATOR — a cut, versus a dissolve. Pure CSS, no likeness.
   ===================================================================== */
.fl-morph { display: grid; gap: var(--fl-8); margin-top: var(--fl-12); }
@media (min-width: 760px) { .fl-morph { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

.fl-tile { border: 1px solid var(--fl-graphite); border-radius: var(--fl-r-md); background: var(--fl-carbon); overflow: hidden; }
.fl-tile__stage { position: relative; aspect-ratio: 16 / 10; overflow: hidden; }
/* The same two brand plates as the hero, so the demonstration is visibly the
   same object as the mark. Already fetched for the hero, so this costs nothing.
   Abstract surfaces only — no likeness, nothing to attribute. */
.fl-tile__a, .fl-tile__b { position: absolute; inset: 0; background-size: cover; background-position: center; }
.fl-tile__a {
  background-image:
    repeating-linear-gradient(0deg, rgb(10 10 12 / .22) 0 1px, transparent 1px 4px),
    url("/assets/brand/plate-then.webp");
  filter: contrast(1.03) saturate(.9);
}
.fl-tile__b { background-image: url("/assets/brand/plate-now.webp"); }
.fl-tile__cap { padding: var(--fl-4) var(--fl-6) var(--fl-6); }
.fl-tile__cap h3 { font-size: var(--fl-text-base); font-weight: 600; }
.fl-tile__cap p { margin-top: var(--fl-2); font-size: var(--fl-text-sm); color: var(--fl-ash); }
.fl-tile__tag {
  display: inline-block;
  margin-bottom: var(--fl-3);
  padding: 2px var(--fl-2);
  border: 1px solid var(--fl-graphite);
  border-radius: var(--fl-r-sm);
  font-family: var(--fl-font-mono);
  font-size: 10px;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--fl-ash);
}
.fl-tile--good .fl-tile__tag { color: var(--fl-signal); border-color: var(--fl-signal); }

/* GOOD: a hard-edged wipe. The b-plate is revealed by a moving edge. */
.fl-tile--good .fl-tile__b { clip-path: inset(0 0 0 100%); }
.fl-tile--good .fl-tile__edge {
  position: absolute; top: 0; bottom: 0; left: 0; width: 2px;
  background: var(--fl-paper);
  box-shadow: 0 0 14px 1px rgb(255 93 46 / .6);
  opacity: 0;
}
/* BAD: a dissolve. Both plates visible at once, muddy. Labelled as such. */
.fl-tile--bad .fl-tile__b { opacity: 0; }

@media (prefers-reduced-motion: no-preference) {
  .fl-tile--good .fl-tile__b { animation: fl-wipe 3.6s var(--fl-ease-scrub) infinite; }
  .fl-tile--good .fl-tile__edge { animation: fl-wipe-edge 3.6s var(--fl-ease-scrub) infinite; }
  .fl-tile--bad  .fl-tile__b { animation: fl-dissolve 3.6s linear infinite; }
}
@keyframes fl-wipe {
  0%, 12%   { clip-path: inset(0 0 0 100%); }
  38%, 62%  { clip-path: inset(0 0 0 0); }
  88%, 100% { clip-path: inset(0 0 0 100%); }
}
@keyframes fl-wipe-edge {
  0%, 12%   { left: 100%; opacity: 1; }
  38%       { left: 0;    opacity: 1; }
  39%, 87%  { opacity: 0; }
  88%       { left: 100%; opacity: 1; }
  100%      { left: 100%; opacity: 1; }
}
@keyframes fl-dissolve {
  0%, 12%   { opacity: 0; }
  38%, 62%  { opacity: 1; }
  88%, 100% { opacity: 0; }
}

/* ========================================================================
   CONTACT
   ===================================================================== */
.fl-contact { text-align: left; }
.fl-contact__mail {
  display: inline-block;
  margin-top: var(--fl-8);
  font-family: var(--fl-font-display);
  font-size: clamp(1.5rem, 5vw, var(--fl-text-3xl));
  letter-spacing: -.015em;
  color: var(--fl-signal);
  text-decoration: none;
  border-bottom: 1px solid rgb(255 93 46 / .3);
  transition: border-color var(--fl-dur-cut) var(--fl-ease-cut);
  overflow-wrap: anywhere;
}
.fl-contact__mail:hover { border-color: var(--fl-signal); }
.fl-contact__note { margin-top: var(--fl-6); max-width: 56ch; font-size: var(--fl-text-sm); color: var(--fl-ash); }

/* ========================================================================
   FOOTER / COLOPHON
   ===================================================================== */
.fl-foot { border-top: 1px solid var(--fl-graphite); padding-block: var(--fl-16) var(--fl-12); }
.fl-foot__line {
  font-family: var(--fl-font-display);
  font-size: clamp(1.5rem, 4vw, var(--fl-text-xl));
  font-style: italic;
  color: var(--fl-paper);
}
.fl-foot__meta {
  display: flex;
  flex-wrap: wrap;
  gap: var(--fl-2) var(--fl-6);
  margin-top: var(--fl-12);
  font-family: var(--fl-font-mono);
  font-size: var(--fl-text-xs);
  letter-spacing: .06em;
  color: var(--fl-ash);
}
.fl-foot__meta p { max-width: 70ch; }

/* ========================================================================
   REVEALS — scroll-driven, CSS-only. No JS, no class gating, no flash.
   If the browser lacks scroll timelines, or the visitor asked for reduced
   motion, content is simply already visible.
   ===================================================================== */
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .fl-reveal {
      animation: fl-reveal var(--fl-dur-wipe) var(--fl-ease-wipe) both;
      animation-timeline: view();
      animation-range: entry 5% cover 22%;
    }
  }
}
@keyframes fl-reveal {
  from { opacity: 0; transform: translateY(14px); clip-path: inset(0 0 100% 0); }
  to   { opacity: 1; transform: none;            clip-path: inset(0 0 0 0); }
}

/* The house contract: motion is decoration, content is not. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0s !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0s !important;
    scroll-behavior: auto !important;
  }
  .fl-tile--good .fl-tile__b { clip-path: inset(0 0 0 0); }
  .fl-tile--bad  .fl-tile__b { opacity: .5; }
  .fl-tile--good .fl-tile__edge { opacity: 0; }
  .fl-progress { transform: scaleX(0); }
}

/* ========================================================================
   HERO SLAB furniture — vertical edge labels + the capability-keyed hint
   ===================================================================== */
.fl-slab { margin: 0; display: grid; justify-items: center; }
@media (min-width: 900px) { .fl-slab { justify-items: end; } }

.fl-slab__labels { display: none; }
@media (min-width: 520px) {
  .fl-slab { position: relative; }
  .fl-slab__labels {
    display: block;
    position: absolute;
    inset-block: 0;
    left: 50%;
    width: min(340px, 100%);
    transform: translateX(-50%);
    pointer-events: none;
  }
  @media (min-width: 900px) { .fl-slab__labels { left: auto; right: 0; transform: none; } }
  .fl-slab__lab {
    position: absolute;
    top: 0;
    writing-mode: vertical-rl;
    font-family: var(--fl-font-mono);
    font-size: var(--fl-text-xs);
    font-weight: 500;
    letter-spacing: .16em;
    text-transform: uppercase;
    white-space: nowrap;
  }
  .fl-slab__lab--then { left: -1.75rem; rotate: 180deg; bottom: 0; top: auto; color: var(--fl-cyanotype); }
  .fl-slab__lab--now  { right: -1.75rem; color: var(--fl-paper); }
}

.seam__plate img { width: 100%; height: 100%; object-fit: cover; }
.seam__then img { filter: contrast(1.03) saturate(.9); }

.fl-slab__hint {
  margin-top: var(--fl-2);
  max-width: 340px;
  font-family: var(--fl-font-mono);
  font-size: var(--fl-text-xs);
  letter-spacing: .08em;
  color: var(--fl-ash);
}
/* Keyed off the real capability, not a script-added class: site.js enables the
   range input, so the hint that promises dragging only appears when dragging
   actually works. If :has() is unsupported the honest static caption stays. */
.fl-hint-js { display: none; }
body:has(#seam-range:not(:disabled)) .fl-hint-js  { display: block; }
body:has(#seam-range:not(:disabled)) .fl-hint-nojs { display: none; }

/* ========================================================================
   WALL LABEL
   ===================================================================== */
.fl-label { border-left: 2px solid var(--fl-graphite); padding-left: var(--fl-6); }
@media (min-width: 900px) { .fl-label { padding-left: var(--fl-8); margin-left: var(--fl-8); } }

/* ========================================================================
   STANDING STATEMENTS
   ===================================================================== */
.fl-disclosure { border-left-color: var(--fl-ember); border-left-width: 3px; background: var(--fl-slate-deep); }
.fl-statements { display: grid; gap: var(--fl-8); }
@media (min-width: 960px) { .fl-statements { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
.fl-statement p { font-size: var(--fl-text-base); line-height: 1.7; color: var(--fl-paper); }
.fl-statement p + p { margin-top: var(--fl-3); }
.fl-statement__n {
  font-family: var(--fl-font-mono);
  font-size: var(--fl-text-xs) !important;
  font-weight: 500;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--fl-ember) !important;
  margin-bottom: var(--fl-3);
}

/* ========================================================================
   PLATES — "does not claim", "what we are not", "on price"
   ===================================================================== */
.fl-plate {
  padding: var(--fl-6);
  border: 1px solid var(--fl-graphite);
  border-radius: var(--fl-r-md);
  background: var(--fl-slate-deep);
}
.fl-plate--warn { border-left: 2px solid var(--fl-caution); }
.fl-plate__h {
  font-family: var(--fl-font-mono);
  font-size: var(--fl-text-xs);
  font-weight: 500;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--fl-ash);
}
.fl-plate__b { margin-top: var(--fl-4); max-width: 68ch; font-size: var(--fl-text-base); color: var(--fl-paper); }
.fl-plate__b + .fl-plate__b { margin-top: var(--fl-3); }

/* ========================================================================
   PIPELINE STAGES
   ===================================================================== */
.fl-stages { display: grid; gap: 0; margin-top: var(--fl-12); border-top: 1px solid var(--fl-graphite); }
@media (min-width: 880px) {
  .fl-stages { grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: var(--fl-12); }
}
.fl-stages li {
  display: grid;
  grid-template-columns: 2.5rem minmax(0, 1fr);
  gap: var(--fl-4);
  align-items: baseline;
  padding-block: var(--fl-4);
  border-bottom: 1px solid var(--fl-graphite);
  font-size: var(--fl-text-sm);
  color: var(--fl-ash);
}
.fl-stages__n { font-family: var(--fl-font-mono); font-size: var(--fl-text-xs); letter-spacing: .1em; color: var(--fl-cyanotype); }
.fl-stages b { color: var(--fl-paper); font-weight: 600; }

/* ========================================================================
   FRAME GEOMETRY — radio-driven, zero JavaScript
   ===================================================================== */
.fl-geo__set { margin: var(--fl-12) 0 0; padding: 0; border: 0; }
.fl-geo__body {
  display: grid;
  gap: var(--fl-8);
  align-items: start;
}
@media (min-width: 720px) { .fl-geo__body { grid-template-columns: minmax(0, 1fr) 172px; gap: var(--fl-12); } }

.fl-geo__labels { display: grid; gap: 0; border-top: 1px solid var(--fl-graphite); }
.fl-geo__labels label {
  display: flex;
  justify-content: space-between;
  gap: var(--fl-4);
  padding: var(--fl-4) 0;
  border-bottom: 1px solid var(--fl-graphite);
  border-left: 2px solid transparent;
  padding-left: var(--fl-4);
  font-size: var(--fl-text-sm);
  color: var(--fl-ash);
  cursor: pointer;
  transition: color var(--fl-dur-cut) var(--fl-ease-cut),
              border-color var(--fl-dur-cut) var(--fl-ease-cut);
}
.fl-geo__labels label:hover { color: var(--fl-paper); }
.fl-geo__labels label span { font-family: var(--fl-font-mono); font-size: var(--fl-text-xs); letter-spacing: .08em; }

/* THE RESERVED STRIP, as literal percentages of the 1920px frame.
   ----------------------------------------------------------------------------
   These are written out rather than derived from a custom property on purpose.
   `height: calc(var(--reserved) / 1920 * 100%)` resolves ONCE in Chrome and then
   never re-resolves when the property changes — getComputedStyle reports the new
   number while layout keeps the old one, so every platform silently rendered an
   identical strip. Registering --reserved with @property did not fix it. A
   literal percentage invalidates layout correctly.
   Each value is <reserved px> / 1920. Keep them in step with the table and with
   machine/platforms.json — tests/guard.mjs asserts the arithmetic. */
#geo-yt:checked ~ .fl-geo__body .fl-geo__strip { height: 17.7083%; }  /* 340 / 1920 */
#geo-fb:checked ~ .fl-geo__body .fl-geo__strip { height: 20.8333%; }  /* 400 / 1920 */
#geo-ig:checked ~ .fl-geo__body .fl-geo__strip { height: 21.8750%; }  /* 420 / 1920 */
#geo-tt:checked ~ .fl-geo__body .fl-geo__strip { height: 27.0833%; }  /* 520 / 1920 */

#geo-yt:checked ~ .fl-geo__body .fl-geo__clear { bottom: 17.7083%; }
#geo-fb:checked ~ .fl-geo__body .fl-geo__clear { bottom: 20.8333%; }
#geo-ig:checked ~ .fl-geo__body .fl-geo__clear { bottom: 21.8750%; }
#geo-tt:checked ~ .fl-geo__body .fl-geo__clear { bottom: 27.0833%; }

#geo-yt:checked ~ .fl-geo__body label[for="geo-yt"],
#geo-fb:checked ~ .fl-geo__body label[for="geo-fb"],
#geo-ig:checked ~ .fl-geo__body label[for="geo-ig"],
#geo-tt:checked ~ .fl-geo__body label[for="geo-tt"] {
  color: var(--fl-paper);
  border-left-color: var(--fl-ember);
}
#geo-yt:focus-visible ~ .fl-geo__body label[for="geo-yt"],
#geo-fb:focus-visible ~ .fl-geo__body label[for="geo-fb"],
#geo-ig:focus-visible ~ .fl-geo__body label[for="geo-ig"],
#geo-tt:focus-visible ~ .fl-geo__body label[for="geo-tt"] {
  outline: 2px solid var(--fl-signal);
  outline-offset: 2px;
}

.fl-geo__stage { display: grid; gap: var(--fl-3); justify-items: start; }
.fl-geo__phone {
  position: relative;
  width: 100%;
  max-width: 172px;
  aspect-ratio: 9 / 16;
  border: 1px solid var(--fl-graphite);
  border-radius: var(--fl-r-md);
  background: var(--fl-carbon);
  overflow: hidden;
  /* The two regions are absolutely positioned against this box, whose height is
     definite via aspect-ratio, so `calc(var(--reserved) / 1920 * 100%)` resolves
     unambiguously and RE-resolves whenever --reserved changes.
     Two earlier attempts failed and were caught by measuring the rendered ratio
     rather than trusting the screenshot:
       1. height:% on a grid item inside an `auto` row -> collapsed to ~1%;
       2. grid-template-rows with the calc -> resolved once at 520 and then
          never re-resolved when --reserved changed.
     What renders now is the true 340/400/420/520-of-1920 proportion. */
  position: relative;
}
.fl-geo__clear {
  position: absolute;
  top: 0; left: 0; right: 0;
  bottom: 27.0833%;              /* default = TikTok; overridden per selection */
  display: grid;
  place-items: center;
  overflow: hidden;
  background:
    repeating-linear-gradient(0deg, rgb(10 10 12 / .3) 0 1px, transparent 1px 3px),
    var(--fl-then-grad);
  /* No transition. Switching platform is a CUT, per the house rule — and a
     tweening strip reads as a gauge animating rather than a spec changing. */
}
.fl-geo__clear span,
.fl-geo__strip span {
  font-family: var(--fl-font-mono);
  font-size: 9px;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--fl-paper);
  opacity: .8;
  text-align: center;
  padding-inline: var(--fl-2);
}
.fl-geo__strip {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 27.0833%;              /* default = TikTok; overridden per selection */
  display: grid;
  place-items: center;
  overflow: hidden;
  background: rgb(255 162 58 / .16);
  border-top: 2px solid var(--fl-ember);
  /* No transition — see .fl-geo__clear. The strip cuts to its new height. */
}
.fl-geo__now { font-family: var(--fl-font-mono); font-size: var(--fl-text-xs); letter-spacing: .06em; color: var(--fl-ash); }
.fl-geo__now span { display: none; }
#geo-yt:checked ~ .fl-geo__body .fl-geo__now span[data-for="geo-yt"],
#geo-fb:checked ~ .fl-geo__body .fl-geo__now span[data-for="geo-fb"],
#geo-ig:checked ~ .fl-geo__body .fl-geo__now span[data-for="geo-ig"],
#geo-tt:checked ~ .fl-geo__body .fl-geo__now span[data-for="geo-tt"] { display: inline; }

/* ========================================================================
   PROVENANCE LEDGER — schema only, never specimen rows
   ===================================================================== */
.fl-refused { border-left: 2px solid rgb(224 82 62 / .45); padding-left: var(--fl-6); }
.fl-ledger {
  margin-top: var(--fl-12);
  padding: var(--fl-8);
  border: 1px solid var(--fl-graphite);
  border-radius: var(--fl-r-md);
  background: var(--fl-slate-deep);
}
.fl-ledger__h {
  font-family: var(--fl-font-mono);
  font-size: var(--fl-text-xs);
  font-weight: 500;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--fl-cyanotype);
  padding-bottom: var(--fl-4);
  border-bottom: 1px solid var(--fl-graphite);
}
.fl-ledger dl { margin: 0; }
.fl-ledger dt {
  margin-top: var(--fl-6);
  padding-left: var(--fl-4);
  border-left: 2px solid var(--fl-graphite);
  font-family: var(--fl-font-mono);
  font-size: var(--fl-text-xs);
  font-weight: 500;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--fl-cyanotype);
}
/* functional colour: this field's values are the accepted set */
.fl-ledger__ok { border-left-color: var(--fl-verified) !important; }
.fl-ledger dd {
  margin: var(--fl-2) 0 0;
  padding-left: var(--fl-4);
  border-left: 2px solid transparent;
  max-width: 64ch;
  font-size: var(--fl-text-sm);
  color: var(--fl-paper);
}

/* ========================================================================
   HOUSE RULES
   ===================================================================== */
.fl-rules { display: grid; gap: var(--fl-8); margin-top: var(--fl-12); }
@media (min-width: 900px) { .fl-rules { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--fl-8) var(--fl-12); } }
.fl-rule-item { padding-left: var(--fl-4); border-left: 2px solid var(--fl-cyanotype); }
.fl-rule-item h3 {
  font-family: var(--fl-font-ui);
  font-size: var(--fl-text-xs);
  font-weight: 600;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--fl-paper);
}
.fl-rule-item p { margin-top: var(--fl-3); max-width: 46ch; font-size: var(--fl-text-sm); color: var(--fl-ash); }

/* ========================================================================
   STUDIO + THE NAME
   ===================================================================== */
.fl-studio { display: grid; gap: var(--fl-16); }
@media (min-width: 960px) { .fl-studio { grid-template-columns: minmax(0, 1fr) minmax(0, .85fr); gap: var(--fl-16); align-items: start; } }
.fl-name__split { display: grid; gap: var(--fl-6); margin-top: var(--fl-8); }
@media (min-width: 560px) {
  .fl-name__split { grid-template-columns: minmax(0, 1fr) 2px minmax(0, 1fr); gap: var(--fl-6); align-items: stretch; }
}
.fl-name__seam { display: none; background: linear-gradient(180deg, var(--fl-cyanotype) 0 50%, var(--fl-ember) 50% 100%); }
@media (min-width: 560px) { .fl-name__seam { display: block; } }
.fl-name__half h3 { font-family: var(--fl-font-display); font-size: var(--fl-text-xl); }
.fl-name__half--then h3 { color: var(--fl-cyanotype); }
.fl-name__half--now h3 { color: var(--fl-ember); }
.fl-name__half p { margin-top: var(--fl-3); font-size: var(--fl-text-sm); color: var(--fl-ash); }

/* ========================================================================
   CONTACT
   ===================================================================== */
.fl-contactband {
  position: relative;
  border-top: 1px solid var(--fl-graphite);
  isolation: isolate;
}
.fl-contactband::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: url("/assets/brand/plate-atmosphere.webp") center / cover no-repeat;
  opacity: .5;
  mask-image: linear-gradient(180deg, rgb(0 0 0 / .9), transparent 78%);
}
.fl-contactband .fl-band { border-top: 0; }

.fl-brief { display: grid; gap: 0; margin-top: var(--fl-8); border-top: 1px solid var(--fl-graphite); max-width: 42rem; }
.fl-brief li {
  display: grid;
  grid-template-columns: 2.5rem minmax(0, 1fr);
  gap: var(--fl-4);
  align-items: baseline;
  padding-block: var(--fl-4);
  border-bottom: 1px solid var(--fl-graphite);
  font-size: var(--fl-text-sm);
  color: var(--fl-ash);
}
.fl-brief span { font-family: var(--fl-font-mono); font-size: var(--fl-text-xs); letter-spacing: .1em; color: var(--fl-cyanotype); }
.fl-brief b { color: var(--fl-paper); font-weight: 600; }

.fl-mailbox {
  margin-top: var(--fl-12);
  padding: var(--fl-8);
  border: 1px solid var(--fl-graphite);
  border-radius: var(--fl-r-md);
  background: rgb(20 20 25 / .82);
}
.fl-mailbox .fl-contact__mail { margin-top: 0; }

/* ========================================================================
   THE STOP — the seam's fourth scale. It has stopped moving.
   ===================================================================== */
.fl-stop { display: grid; justify-items: center; margin-bottom: var(--fl-8); }
.fl-stop__rule { width: 2px; height: 96px; background: var(--fl-paper); }
.fl-stop__foot { width: 32px; height: 2px; background: var(--fl-paper); }

.fl-foot { text-align: center; }
.fl-foot__line { max-width: 30ch; margin-inline: auto; }
.fl-foot__grid {
  display: grid;
  gap: var(--fl-6);
  justify-items: center;
  margin-top: var(--fl-16);
  padding-top: var(--fl-8);
  border-top: 1px solid var(--fl-graphite);
  position: relative;
}
/* the page's third and final, quietest use of the accent */
.fl-foot__grid::before {
  content: "";
  position: absolute;
  top: -1px; left: 0;
  width: 6px; height: 2px;
  background: var(--fl-signal);
}
@media (min-width: 760px) { .fl-foot__grid { grid-template-columns: auto auto; justify-content: space-between; justify-items: start; align-items: center; } }
.fl-foot__mark {
  font-size: var(--fl-text-sm);
  font-weight: var(--fl-wordmark-weight);
  letter-spacing: var(--fl-wordmark-tracking);
  text-transform: uppercase;
}
.fl-foot__nav { display: flex; flex-wrap: wrap; gap: var(--fl-2) var(--fl-4); justify-content: center; }
.fl-foot__nav a {
  /* WCAG 2.2 2.5.8: 24px minimum target. The mono type is 12px, so the padding
     is doing the work — measured at 28px, not assumed. */
  display: inline-block;
  padding-block: 6px;
  font-family: var(--fl-font-mono);
  font-size: var(--fl-text-xs);
  letter-spacing: .08em;
  color: var(--fl-ash);
  text-decoration: none;
  border-bottom: 1px solid transparent;
}
.fl-foot__nav a:hover { color: var(--fl-paper); border-bottom-color: var(--fl-signal); }
.fl-foot__meta { text-align: left; }
.fl-foot__meta strong { color: var(--fl-paper); font-weight: 500; }
.fl-foot__meta a { color: var(--fl-ash); }
.fl-foot__meta a:hover { color: var(--fl-paper); }
/* a colophon sets each family name in its own family */
.fl-set-display { font-family: var(--fl-font-display); font-size: 1.15em; }
.fl-set-ui { font-family: var(--fl-font-ui); }
.fl-set-mono { font-family: var(--fl-font-mono); }

/* The crossfade stamp, baked into the demonstration cell so a cropped
   screenshot cannot separate the label from the thing it labels. */
.fl-tile__stamp {
  position: absolute;
  inset: 0;
  z-index: 3;
  display: grid;
  place-content: center;
  text-align: center;
  font-family: var(--fl-font-mono);
  font-size: var(--fl-text-xs);
  font-weight: 500;
  letter-spacing: .16em;
  line-height: 1.9;
  text-transform: uppercase;
  color: var(--fl-paper);
  text-shadow: 0 1px 10px rgb(10 10 12 / .95), 0 0 3px rgb(10 10 12 / .9);
}

/* ========================================================================
   404 — same furniture, no navigation to get lost in
   ===================================================================== */
.fl-404 {
  min-height: 100svh;
  display: grid;
  align-content: center;
  justify-items: start;
  padding-block: var(--fl-16);
  max-width: 44rem;
}
.fl-404 .fl-stop { justify-items: start; margin-bottom: var(--fl-8); }
.fl-404 .fl-stop__rule { height: 64px; }
.fl-404__code {
  font-family: var(--fl-font-mono);
  font-size: var(--fl-text-xs);
  font-weight: 500;
  letter-spacing: .22em;
  color: var(--fl-signal);
}
.fl-404__line {
  margin-top: var(--fl-4);
  font-family: var(--fl-font-display);
  font-size: clamp(2.25rem, 7vw, var(--fl-text-3xl));
  letter-spacing: -.018em;
}
.fl-404__body { margin-top: var(--fl-6); max-width: 46ch; font-size: var(--fl-text-lg); color: var(--fl-ash); }
.fl-404__ctas { margin-top: var(--fl-8); }
.fl-404__mark { margin-top: var(--fl-16); }

/* -------------------------------------------------- print (leave usable) - */
@media print {
  body::before, .fl-masthead, .seam__range { display: none; }
  body { background: #fff; color: #000; }
  .fl-lead, .fl-body, .fl-mono, .fl-cat__m, .fl-spec td { color: #222; }
}
