/* FyreFly Systems: the chrome (fixed header, fixed footer, page dots) and the content
   components for the inner pages.
   Loads after tokens.css and bundle.css (the design system from Claude Design) and
   speaks its language: tokens only (the live look of fyreflysystems.de lives in the token
   overlay of scripts/build-ff-tokens.py), one weight, hairlines that open with the 16px
   accent tick, photos as windows (no shadows, no cards). IBM Plex Mono (--ff-mono) carries
   technical labels: kickers, captions, credits, facts, figures.
   Site-specific rules stay in scientific/scientific.css. */

/* ===== Page: accent, ground and the room between the bars =====
   The design system's --accent* follow the page's --ff-accent* (orange; violet on body[data-page^="alef"]).
   The header and the footer are fixed: the page leaves room for both, and --ff-vh is the
   viewport between them (scientific.js writes the footer's real height into --ff-footer-h). */
html { background: var(--stage-100); }
.ff-page {
  --accent: var(--ff-accent);
  --accent-ink: var(--ff-accent-ink);
  --on-accent: var(--ff-on-accent);
  /* Keyboard focus follows the page's accent (-ink variant: 5:1 on white, 7:1 on the dark ground), so a
     ring is orange on Phonos, violet on Alef, teal on Gimel. Set here, not in tokens, so it resolves
     against the body's own --ff-accent-ink. The black footer keeps its ember ring (bundle.css). */
  --focus: var(--ff-accent-ink);
  accent-color: var(--ff-accent);   /* checkboxes, radios, range sliders */
  --ff-vh: calc(100svh - var(--ff-footer-h));
}
/* Text selection: the accent with its own text colour (6:1 or better in all three accents). */
.ff-page ::selection { background: var(--ff-accent); color: var(--ff-on-accent); }
body.ff-page {
  padding-top: var(--topbar-height);
  padding-bottom: var(--ff-footer-h);
}

/* ===== Layout grid: the same margins and column rhythm everywhere =====
   One grid for the whole site: a page margin (--gutter / --gutter-sm, already used for the
   header, sub-navigation, page heads, sections and the footer) and 12/8/4 columns inside it
   (1100px and 860px are the breakpoints every one of those already uses). --ff-grid-bg turns
   that rhythm into a background image — thin column lines, no element, no JS, nothing content
   can collide with. It is applied below to the plain panels only (page heads, sections, splits,
   the next-page row, legal sheets, the models carousel): anything with its own photo, scene or
   card background (.fi-hero, .gm-hero, .ff-figure, .ff-band, .sci-landing, .sci-grad, …) sets its
   own `background` later in the cascade and so never shows it — no per-component exclusion needed. */
:root {
  --ff-grid-cols: 12;
  --ff-grid-margin: var(--gutter);
  --ff-grid-line: color-mix(in srgb, var(--ink) 6%, transparent);
  --ff-grid-slot: calc((100% - 2 * var(--ff-grid-margin)) / var(--ff-grid-cols));
  --ff-grid-bg: repeating-linear-gradient(to right, var(--ff-grid-line) 0 1px, transparent 1px var(--ff-grid-slot));
}
@media (max-width: 1100px) { :root { --ff-grid-cols: 8; } }
@media (max-width: 860px) { :root { --ff-grid-cols: 4; --ff-grid-margin: var(--gutter-sm); } }
.ff-pagehead, .ff-section, .ff-next, .ff-legal, .ff-contact, .ff-split {
  background-image: var(--ff-grid-bg);
  background-position: var(--ff-grid-margin) 0;
  background-repeat: repeat-x;
}
@media print {
  .ff-pagehead, .ff-section, .ff-next, .ff-legal, .ff-contact, .ff-split { background-image: none; }
}

/* ===== Header: a fixed bar with a soft shadow, the live site's look ===== */
.ff-topbar {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 100;
  gap: var(--space-5);
  height: var(--topbar-height);
  padding: 0 var(--gutter);
  background: var(--ff-bar-bg);
  color: var(--ff-bar-ink);
  box-shadow: var(--ff-bar-shadow);
}
.ff-topbar::after { display: none; }
.ff-wordmark { position: relative; z-index: 2; font-size: 17px; font-weight: 700; letter-spacing: 0; }
.ff-wordmark span { color: var(--ember); }   /* the brand's orange on every page */
.ff-nav { gap: var(--space-5); }
.ff-nav__link {
  padding: 4px 0;
  border-bottom: 2px solid transparent;
  background: none;
  font-size: 0.9rem;
  line-height: 1.3;
  letter-spacing: 1px;
  text-transform: uppercase;
  transition: color var(--dur-hover) var(--ease-plain), border-color var(--dur-hover) var(--ease-plain);
}
.ff-nav__link:hover { color: var(--accent-ink); background: none; }
.ff-nav__link[aria-current="page"] { border-bottom-color: var(--accent-ink); background: none; }
.ff-nav__actions { gap: var(--space-4); }
/* A nav item with a dropdown (Alef: Alef Portal, Gimel). The button reads like a nav link; the
   current page's item inside marks it as current. scientific.js opens and closes it. */
.ff-nav__group { position: relative; display: inline-flex; }
.ff-nav__toggle {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  color: inherit;
  font: inherit;
  font-size: 0.9rem;
  line-height: 1.3;
  border: 0;
  border-bottom: 2px solid transparent;
  cursor: pointer;
}
.ff-nav__toggle::after {
  content: '';
  width: 6px;
  height: 6px;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: translateY(-2px) rotate(45deg);
  transition: transform var(--dur-hover) var(--ease-plain);
}
.ff-nav__group.is-open > .ff-nav__toggle::after { transform: translateY(1px) rotate(-135deg); }
.ff-nav__toggle:hover { color: var(--accent-ink); }
.ff-nav__group:has(.ff-nav__item[aria-current="page"]) > .ff-nav__toggle { border-bottom-color: var(--accent-ink); }
.ff-nav__menu {
  position: absolute;
  top: calc(100% + 16px);
  left: -14px;
  z-index: 3;
  display: none;
  min-width: 310px;
  padding: 6px;
  background: var(--ff-bar-bg);
  border: 1px solid var(--rule);
  box-shadow: var(--ff-bar-shadow);
}
.ff-nav__group.is-open > .ff-nav__menu { display: block; }
.ff-nav__item {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 10px 12px;
  color: inherit;
  text-decoration: none;
  border-left: 2px solid transparent;
}
.ff-nav__item:hover, .ff-nav__item:focus-visible { background: var(--stage-200); color: var(--accent-ink); }
.ff-nav__item[aria-current="page"] { border-left-color: var(--accent-ink); }
.ff-nav__mark { flex: none; width: 1.4em; font-size: 1.3rem; line-height: 1.1; text-align: center; }
.ff-nav__item--alef .ff-nav__mark { color: var(--alef-ink); }
.ff-nav__item--gimel .ff-nav__mark { color: var(--gimel-ink); }
.ff-nav__name { display: block; font-size: 0.9rem; letter-spacing: 1px; text-transform: uppercase; }
.ff-nav__hint { display: block; margin-top: 2px; color: var(--ink-muted); font-family: var(--ff-mono); font-size: 0.75rem; }
.ff-lang { height: 29px; min-width: 44px; padding: 0 10px; font-size: 0.8rem; letter-spacing: 1px; }
.ff-lang:hover { background: var(--ink); color: var(--stage-100); }

/* Narrow screens: the nav slides in from the right (the live site's drawer). It starts
   below 980px because five links and the language switch need that much room
   (German is the widest: about 900px with the wordmark). scientific.js knows the same number. */
@media (max-width: 980px) {
  .ff-menu-btn { display: inline-flex; position: relative; z-index: 2; width: 32px; height: 32px; padding: 0; }
  .ff-menu-btn span { background: var(--ff-bar-ink); }
  .ff-nav {
    position: fixed;
    top: 0;
    right: 0;
    bottom: auto;
    left: auto;
    z-index: 1;
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    width: min(75vw, 320px);
    height: 100vh;
    height: 100dvh;
    padding: 84px var(--space-6) var(--space-6);
    overflow-y: auto;
    background: var(--ff-bar-bg);
    border: 0;
    box-shadow: var(--ff-drawer-shadow);
    transform: translateX(100%);
    visibility: hidden;
    transition: transform 350ms var(--ease-out-quart), visibility 0s linear 350ms;
  }
  .ff-topbar.is-open { z-index: 115; }   /* the open drawer covers the footer and the cookie banner (the dialog, 120, still wins) */
  .ff-topbar.is-open .ff-nav { transform: none; visibility: visible; transition-delay: 0s; }
  /* The page dims behind the open drawer; a click on it closes the menu (scientific.js). */
  .ff-topbar.is-open::before {
    content: '';
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    height: 100vh;
    background: var(--scrim);
  }
  .ff-nav__link { width: 100%; padding: 14px 0; font-size: 1rem; border-bottom: 1px solid var(--rule); }
  .ff-nav__link[aria-current="page"] { border-bottom: 2px solid var(--accent-ink); }
  /* In the drawer the dropdown opens in place, under its button. */
  .ff-nav__group { display: block; width: 100%; }
  .ff-nav__toggle { justify-content: space-between; text-align: left; }
  .ff-nav__group:has(.ff-nav__item[aria-current="page"]) > .ff-nav__toggle { border-bottom: 1px solid var(--rule); }
  .ff-nav__menu { position: static; min-width: 0; padding: 4px 0 8px; border: 0; border-bottom: 1px solid var(--rule); box-shadow: none; }
  .ff-nav__actions { flex-direction: column; align-items: stretch; gap: var(--space-3); margin-top: var(--space-5); }
  .ff-lang { align-self: flex-start; }
}

/* ===== Footer: a fixed black bar, two rows =====
   Row 1: the legal links (Impressum, Privacy, Cookie settings, the two sets of terms) and the owner line.
   Row 2: the products and pages (Phonos, Alef, Gimel, Contact …), the motion switch and the AI note.
   The same markup, in the same order, sits on every page of the site; scientific.js writes the real
   height into --ff-footer-h, so the rows may wrap. On phones the footer is static (below). */
.ff-footer {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 100;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  grid-template-areas: "legal line" "more note";
  align-items: center;
  gap: 2px var(--space-6);
  min-height: 60px;
  padding: 10px var(--gutter);
  background: var(--ff-footer-bg);
  color: var(--ff-footer-ink);
  border-top: 1px solid var(--ff-footer-rule);
}
:root { --ff-footer-h: 78px; }   /* fallback until scientific.js has measured the bar */
.ff-footer__group { margin: 0; min-width: 0; }
.ff-footer__group--legal { grid-area: legal; }
.ff-footer__group--more { grid-area: more; }
.ff-footer__line { grid-area: line; }
.ff-footer__note { grid-area: note; }
.ff-footer__links { justify-content: flex-start; gap: 2px var(--space-5); }
.ff-footer__links a, .ff-footer__links button {
  color: var(--ff-footer-ink);
  font-size: 0.8rem;
  line-height: 1.5;
  letter-spacing: 1px;
  text-transform: uppercase;
}
/* The second row is quieter: smaller, set in the muted ink; it still reads 7:1 on the black bar. */
.ff-footer__links--more a, .ff-footer__links--more button {
  color: var(--on-night-muted);
  font-size: 0.72rem;
  letter-spacing: 0.8px;
}
.ff-footer__links--more a:hover, .ff-footer__links--more button:hover { color: var(--ff-footer-ink); opacity: 1; }
.ff-footer__links a[aria-current="page"] { text-decoration: underline; text-underline-offset: 5px; text-decoration-thickness: 1px; }
.ff-footer__line, .ff-footer__note {
  margin: 0;
  justify-self: end;
  text-align: right;
  font-family: var(--ff-mono);
  font-size: 0.72rem;
  line-height: 1.5;
  letter-spacing: 0.04em;
  color: var(--on-night-muted);
}

/* Tablets: the links get the full width, the owner line and the AI note share the last row. */
@media (min-width: 861px) and (max-width: 1100px) {
  .ff-footer { grid-template-columns: minmax(0, 1fr) auto; grid-template-areas: "legal legal" "more more" "line note"; row-gap: 4px; padding-top: 8px; padding-bottom: 8px; }
  .ff-footer__line { justify-self: start; text-align: left; }
}

/* ===== Section dots: the right edge, centred between the two bars; the accent follows the page ===== */
.ff-dots {
  right: 30px;
  top: calc(50% + (var(--topbar-height) - var(--ff-footer-h)) / 2);
  gap: var(--space-4);
}
.ff-dots__arrow { font-size: 12px; }

/* ===== Cookie banner and dialog sit above the bars ===== */
/* It sits above the fixed footer, so it may only use the room between the two bars; the text wraps,
   so it never scrolls sideways (a sub-pixel overflow from letter-spacing showed a horizontal bar). */
.ff-consent {
  z-index: 110;
  bottom: calc(var(--ff-footer-h) + var(--space-4));
  max-height: calc(100svh - var(--topbar-height) - var(--ff-footer-h) - 2 * var(--space-4));
  overflow-x: hidden;
  overflow-y: auto;
}
.ff-modal { z-index: 120; }

/* ===== Kicker and mono labels ===== */
.ff-kicker {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin: 0;
  font-family: var(--ff-mono);
  font-size: 12px;
  font-weight: 500;
  line-height: 1.4;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-muted);
}
.ff-kicker::before { content: ''; flex: none; width: var(--space-4); height: 1px; background: var(--accent); }
.ff-mono { font-family: var(--ff-mono); letter-spacing: 0.02em; }

/* ===== Small screens: the bars =====
   The gutter itself (not the nav-drawer trigger, still 980px above) switches to --gutter-sm here,
   at the same breakpoint as page heads, sections and the sub-navigation — so the wordmark lines up
   with the content left edge all the way down, instead of jumping 28px early at 980px. */
@media (max-width: 860px) {
  .ff-topbar { padding: 0 var(--gutter-sm); }
  /* Phones: only the header stays fixed. The footer ends the page like any other block, so it
     no longer takes three lines of every screen; --ff-footer-h is 0 (scientific.js agrees). */
  :root { --ff-footer-h: 0px; }
  .ff-footer {
    position: static;
    min-height: 0;
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas: "legal" "more" "line" "note";
    gap: var(--space-3);
    padding: var(--space-5) var(--gutter-sm) calc(var(--space-5) + env(safe-area-inset-bottom, 0px));
  }
  .ff-footer__line, .ff-footer__note { justify-self: start; text-align: left; }
  .ff-footer__links { gap: 0 var(--space-5); }
  .ff-footer__links a, .ff-footer__links button {
    display: inline-flex;
    align-items: center;
    min-height: 32px;
    padding: 4px 0;
    font-size: 0.8rem;
    letter-spacing: 0.5px;
  }
  /* The cookie banner: a compact bottom sheet that leaves most of the first screen visible. */
  .ff-consent {
    left: var(--space-3);
    right: var(--space-3);
    bottom: calc(var(--space-3) + env(safe-area-inset-bottom, 0px));
    width: auto;
    max-height: 60svh;
    padding: var(--space-4);
  }
  .ff-consent__title { margin-bottom: var(--space-1); font-size: 17px; }
  .ff-consent__text { font-size: 13px; line-height: 1.5; }
  .ff-consent__actions { gap: var(--space-2); margin-top: var(--space-4); }
  .ff-consent__actions .ff-btn { flex: 1 1 auto; justify-content: center; min-height: 44px; }
}

/* ===== Type ===== */
.ff-display {
  font-size: clamp(44px, 5.4vw, 72px);
  line-height: 1.02;
  letter-spacing: -0.03em;
  font-weight: 400;
  text-wrap: balance;
}
/* Zero margins at zero specificity, so stacking rules (.ff-section__head > * + *,
   .ff-stack > * + *) still space these blocks out. */
:where(.ff-display, .ff-h3, .ff-list, .ff-faq, .ff-note, .ff-pagehead__title) { margin: 0; }
.ff-pagehead__title { font-weight: 400; }
.ff-headline, .ff-title { text-wrap: balance; }
.ff-h3 { font-size: 20px; line-height: 1.3; letter-spacing: -0.01em; font-weight: 400; }
.ff-num { font-variant-numeric: tabular-nums; }

/* ===== Skip link ===== */
.ff-skip {
  position: fixed;
  top: var(--space-3);
  left: var(--space-3);
  z-index: 200;
  padding: var(--space-3) var(--space-5);
  background: var(--ink);
  color: var(--stage-100);
  border-radius: var(--radius-sm);
  font-size: 14px;
  text-decoration: none;
  transform: translateY(-200%);
}
.ff-skip:focus { transform: none; }

/* ===== Inner page head: the page's name set large, its lede beside it ===== */
.ff-pagehead {
  position: relative;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-8);
  align-items: end;
  padding: var(--space-9) calc(var(--gutter) + var(--space-7)) var(--space-8) var(--gutter);
  background-color: var(--stage-100);   /* not the shorthand: it would wipe the column grid set above */
}
.ff-pagehead > * { min-width: 0; }
.ff-pagehead__lede > * + * { margin-top: var(--space-5); }

/* ===== Photo band: a full-width window under a page head ===== */
.ff-band {
  position: relative;
  margin: 0;
  height: clamp(280px, 46vw, 620px);
  background: var(--stage-200);
  overflow: hidden;
}
.ff-band img { width: 100%; height: 100%; object-fit: cover; }
.ff-band--short { height: clamp(220px, 30vw, 420px); }

/* ===== Figure: an image window inside a section ===== */
.ff-figure {
  position: relative;
  margin: 0;
  background: var(--stage-200);
  border-radius: 0;   /* pictures are square-cornered everywhere */
  overflow: hidden;
  aspect-ratio: 4 / 3;
  max-width: 100%;
}
.ff-figure img { width: 100%; height: 100%; object-fit: cover; }
.ff-figure--square { aspect-ratio: 1; }
.ff-figure--wide { aspect-ratio: 16 / 9; }
.ff-figure--tall { aspect-ratio: 4 / 5; }
.ff-figure--drawing img { object-fit: cover; }
.ff-figure figcaption {
  position: absolute;
  left: var(--space-4);
  bottom: var(--space-4);
  max-width: calc(100% - 2 * var(--space-4));
  padding: var(--space-1) var(--space-2);
  border-radius: 0;
  background: var(--paper);
  color: var(--ink);
  font-size: 13px;
  line-height: 1.4;
}
/* Pexels credit, bottom right of every photo (.ff-hero__credit's sibling). */
.ff-credit {
  position: absolute;
  right: var(--space-4);
  bottom: var(--space-4);
  z-index: 1;
  display: inline-flex;
  align-items: center;
  min-height: 24px;   /* WCAG 2.5.8 target size */
  padding: 2px var(--space-2);
  border-radius: 0;
  background: color-mix(in srgb, var(--paper) 82%, transparent);
  color: var(--ink);
  font-size: 12px;
  line-height: 1.5;
  text-decoration: none;
  transition: background var(--dur-hover) var(--ease-plain);
}
.ff-credit:hover { background: var(--paper); color: var(--accent-ink); }
.ff-figure figcaption + .ff-credit,
.ff-figure .ff-credit { bottom: var(--space-4); }

/* ===== Single-column section: head on top, content runs full width below ===== */
.ff-section--wide { grid-template-columns: 1fr; gap: var(--space-7); }
.ff-section--wide .ff-section__head { max-width: 62ch; }
.ff-section > * { min-width: 0; }
.ff-section__body > * + * { margin-top: var(--space-6); }

/* ===== Grid of items ===== */
.ff-grid {
  display: grid;
  gap: var(--space-7) var(--space-8);
  grid-template-columns: repeat(2, minmax(0, 1fr));
}
.ff-grid--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.ff-grid--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--space-6); }

/* ===== Item: a titled block under a ticked hairline (features, pillars, models) ===== */
.ff-item {
  position: relative;
  padding-top: var(--space-5);
}
.ff-item::before {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  height: 1px;
  background: linear-gradient(to right, var(--accent) 0 var(--space-4), var(--rule) var(--space-4));
}
.ff-item h3, .ff-item .ff-item__title { font-size: 20px; line-height: 1.3; letter-spacing: -0.01em; font-weight: 400; margin: 0; }
.ff-item p { margin: var(--space-2) 0 0; font-size: 15px; line-height: 1.6; color: var(--ink-muted); max-width: 52ch; }
.ff-item__meta { display: block; margin-top: var(--space-2); font-size: 13px; line-height: 1.5; color: var(--ink-muted); }
.ff-item .ff-figure { margin-bottom: var(--space-5); }
.ff-item .ff-cta { margin-top: var(--space-4); }

/* ===== Chips: small labels for inputs, outputs, formats ===== */
.ff-chips { display: flex; flex-wrap: wrap; gap: var(--space-2); margin: var(--space-4) 0 0; padding: 0; list-style: none; }
.ff-chips li {
  padding: 2px var(--space-2);
  border: 1px solid var(--rule);
  border-radius: var(--radius-sm);
  font-size: 13px;
  line-height: 1.5;
  color: var(--ink);
}
.ff-chips li.is-accent { border-color: var(--accent); color: var(--accent-ink); }

/* ===== Plain list with hairlines ===== */
.ff-list { padding: 0; list-style: none; }
.ff-list li {
  padding: var(--space-3) 0;
  border-top: 1px solid color-mix(in srgb, var(--rule) 60%, transparent);
  font-size: 15px;
  line-height: 1.6;
}
.ff-list li:last-child { border-bottom: 1px solid color-mix(in srgb, var(--rule) 60%, transparent); }
.ff-list strong { font-weight: 400; color: var(--ink); }
.ff-list span { color: var(--ink-muted); }

/* ===== Table: figures that line up ===== */
.ff-table-wrap { overflow-x: auto; max-width: 100%; }
.ff-table { width: 100%; border-collapse: collapse; font-size: 15px; line-height: 1.5; font-variant-numeric: tabular-nums; }
.ff-table caption { text-align: left; padding-bottom: var(--space-3); font-size: 13px; color: var(--ink-muted); }
.ff-table th, .ff-table td {
  text-align: left;
  vertical-align: top;
  padding: var(--space-3) var(--space-5) var(--space-3) 0;
  border-top: 1px solid color-mix(in srgb, var(--rule) 60%, transparent);
}
.ff-table thead th { font-size: 13px; font-weight: 400; color: var(--ink-muted); border-top: 1px solid var(--rule); }
.ff-table tbody tr:last-child td, .ff-table tbody tr:last-child th { border-bottom: 1px solid color-mix(in srgb, var(--rule) 60%, transparent); }
.ff-table tbody th { font-weight: 400; color: var(--ink); }
.ff-table td { color: var(--ink-muted); }

/* ===== Questions and answers ===== */
.ff-faq details { border-top: 1px solid color-mix(in srgb, var(--rule) 60%, transparent); }
.ff-faq details:last-child { border-bottom: 1px solid color-mix(in srgb, var(--rule) 60%, transparent); }
.ff-faq summary {
  display: flex;
  justify-content: space-between;
  gap: var(--space-5);
  padding: var(--space-5) 0;
  font-size: 18px;
  line-height: 1.4;
  cursor: pointer;
  list-style: none;
}
.ff-faq summary::-webkit-details-marker { display: none; }
.ff-faq summary::after { content: '+'; color: var(--accent-ink); flex: none; }
.ff-faq details[open] summary::after { content: '−'; }
.ff-faq details > div { padding: 0 0 var(--space-5); max-width: 62ch; color: var(--ink-muted); font-size: 15px; line-height: 1.65; }
.ff-faq details > div > * + * { margin-top: var(--space-3); }

/* ===== Note: a quiet qualification under a claim ===== */
.ff-note { font-size: 13px; line-height: 1.5; color: var(--ink-muted); max-width: 62ch; }

/* ===== Next page: the "where to go from here" row at the end of a page ===== */
.ff-next {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: var(--space-6);
  padding: var(--space-8) calc(var(--gutter) + var(--space-7)) var(--space-8) var(--gutter);
  background-color: var(--stage-200);   /* not the shorthand: keeps the column grid */
}
.ff-next a {
  display: block;
  padding-top: var(--space-4);
  border-top: 1px solid var(--rule);
  color: var(--ink);
  text-decoration: none;
  font-size: 20px;
  line-height: 1.3;
  letter-spacing: -0.01em;
  transition: color var(--dur-hover) var(--ease-plain);
}
.ff-next a:hover { color: var(--accent-ink); }
.ff-next a span { display: block; margin-top: var(--space-2); font-size: 14px; line-height: 1.5; color: var(--ink-muted); }

/* ===== Legal sheet: paper for reading ===== */
.ff-legal {
  padding: var(--space-9) calc(var(--gutter) + var(--space-7)) var(--space-9) var(--gutter);
  background-color: var(--stage-100);   /* not the shorthand: keeps the column grid */
}
.ff-legal__sheet {
  max-width: 860px;
  padding: var(--space-8);
  background: var(--paper);
  color: var(--ink);
  font-size: 15px;
  line-height: 1.7;
}
.ff-legal__sheet h1 { font-size: clamp(32px, 4vw, 48px); line-height: 1.08; letter-spacing: -0.02em; font-weight: 400; margin: 0 0 var(--space-6); }
.ff-legal__sheet h2 { font-size: 22px; line-height: 1.3; font-weight: 400; margin: var(--space-7) 0 var(--space-3); }
.ff-legal__sheet h3 { font-size: 18px; line-height: 1.35; font-weight: 400; margin: var(--space-6) 0 var(--space-2); }
.ff-legal__sheet h4 { font-size: 16px; line-height: 1.4; font-weight: 400; margin: var(--space-5) 0 var(--space-2); }
.ff-legal__sheet p, .ff-legal__sheet ul, .ff-legal__sheet ol { margin: 0 0 var(--space-4); }
.ff-legal__sheet strong, .ff-legal__sheet b { font-weight: 400; color: var(--ink); text-decoration: underline; text-decoration-color: var(--rule); text-underline-offset: 3px; }
.ff-legal__sheet a { color: var(--accent-ink); }
.ff-legal__sheet table { width: 100%; border-collapse: collapse; margin: 0 0 var(--space-5); font-size: 14px; }
.ff-legal__sheet th, .ff-legal__sheet td { text-align: left; vertical-align: top; padding: var(--space-2) var(--space-3) var(--space-2) 0; border-top: 1px solid color-mix(in srgb, var(--rule) 60%, transparent); }
.ff-legal__sheet .ff-table-wrap { margin-bottom: var(--space-5); }

/* ===== Motion: the design system's vocabulary, carried into the inner pages =====
   Same curves and gestures as the homepage stage: slot letters with the accent sweep,
   images that grow with scaleX from their inner edge, headings that rise 20px with the
   body trailing, hairlines that draw themselves. All of it is scrubbed by --ff-p, which
   FyreFly.reveal() sets on every [data-ff-reveal] element (1 under reduced motion; unset,
   and therefore at rest, without JavaScript). */

/* Page-head slot headline: one per page, the inner page's name. */
.ff-slot--page { font-size: clamp(44px, 5.4vw, 72px); line-height: 1.02; letter-spacing: -0.03em; }
/* Letters land one after another, so only the last one rolls: no fixed width needed,
   which keeps the proportional spacing of the landed word. */
.ff-slot--page .ff-letter { min-width: 0; }
/* Lines of the built headline sit as close as the plain text it replaces (no row gap), so a
   two-line title keeps its height when the script takes over: no layout shift. */
.ff-slot--page .ff-slot__row { row-gap: 0; }
.ff-pagehead:hover .ff-slot--page .ff-letter { color: var(--accent); }
.ff-pagehead .ff-slot--page .ff-letter:nth-child(odd) { transition-delay: 30ms; }

/* Section: the ticked hairline draws from the left, head rises, body trails. */
.ff-section[data-ff-reveal]::before,
.ff-contact[data-ff-reveal]::before,
.ff-pagehead[data-ff-reveal]::before {
  transform: scaleX(var(--ff-p, 1));
  transform-origin: left center;
}
.ff-pagehead[data-ff-reveal]::before {
  content: '';
  position: absolute;
  left: var(--gutter);
  right: 0;
  bottom: 0;
  height: 1px;
  background: linear-gradient(to right, var(--accent) 0 var(--space-4), var(--rule) var(--space-4));
}
[data-ff-reveal] > .ff-section__head,
[data-ff-reveal] .ff-pagehead__title {
  opacity: min(calc(var(--ff-p, 1) * 1.5), 1);
  transform: translateY(calc(20px - var(--ff-p, 1) * 20px));
}
[data-ff-reveal] > .ff-section__body,
[data-ff-reveal] > .ff-section__head + :not(.ff-section__head):not([data-ff-reveal]),
[data-ff-reveal] .ff-pagehead__lede {
  --ff-q: clamp(0, calc((var(--ff-p, 1) - 0.15) * 1.6), 1);
  opacity: var(--ff-q);
  transform: translateY(calc(20px - var(--ff-q) * 20px));
}
/* Phones: sections are several screens tall, so --ff-p grows slowly; the body has to be fully
   there long before the section ends. A form being filled in is never dimmed. */
@media (max-width: 860px) {
  [data-ff-reveal] > .ff-section__body,
  [data-ff-reveal] > .ff-section__head + :not(.ff-section__head):not([data-ff-reveal]),
  [data-ff-reveal] .ff-pagehead__lede { --ff-q: clamp(0, calc((var(--ff-p, 1) - 0.1) * 3.2), 1); }
}
[data-ff-reveal] > form { opacity: 1 !important; }   /* outranks the long body selector above */

/* Figures and bands: the window opens with scaleX from its inner edge (as .ff-split__media). */
.ff-figure[data-ff-reveal], .ff-band[data-ff-reveal] {
  transform: scaleX(var(--ff-p, 1));
  transform-origin: left center;
  opacity: min(calc(var(--ff-p, 1) * 2), 1);
}
.ff-figure--from-right[data-ff-reveal], .ff-band--from-right[data-ff-reveal] { transform-origin: right center; }

/* Item grids: each tick hairline draws in turn, the copy follows it. */
[data-ff-reveal] .ff-item { --ff-i: 0; }
[data-ff-reveal] .ff-item:nth-child(2) { --ff-i: 1; }
[data-ff-reveal] .ff-item:nth-child(3) { --ff-i: 2; }
[data-ff-reveal] .ff-item:nth-child(4) { --ff-i: 3; }
[data-ff-reveal] .ff-item:nth-child(5) { --ff-i: 4; }
[data-ff-reveal] .ff-item:nth-child(6) { --ff-i: 5; }
[data-ff-reveal] .ff-item:nth-child(n+7) { --ff-i: 6; }
[data-ff-reveal] .ff-item {
  --ff-q: clamp(0, calc((var(--ff-p, 1) - var(--ff-i) * 0.07) * 1.8), 1);
}
[data-ff-reveal] .ff-item::before { transform: scaleX(var(--ff-q)); transform-origin: left center; }
[data-ff-reveal] .ff-item > * {
  opacity: var(--ff-q);
  transform: translateY(calc(12px - var(--ff-q) * 12px));
}

/* Lists and steps: rows draw their hairline and slide in after one another. */
[data-ff-reveal] .ff-steps li, [data-ff-reveal] .ff-defs > div { --ff-i: 0; }
[data-ff-reveal] .ff-steps li:nth-child(2), [data-ff-reveal] .ff-defs > div:nth-child(2) { --ff-i: 1; }
[data-ff-reveal] .ff-steps li:nth-child(3), [data-ff-reveal] .ff-defs > div:nth-child(3) { --ff-i: 2; }
[data-ff-reveal] .ff-steps li:nth-child(n+4), [data-ff-reveal] .ff-defs > div:nth-child(n+4) { --ff-i: 3; }
[data-ff-reveal] .ff-steps li, [data-ff-reveal] .ff-defs > div {
  --ff-q: clamp(0, calc((var(--ff-p, 1) - var(--ff-i) * 0.08) * 1.8), 1);
  opacity: var(--ff-q);
  transform: translateX(calc(16px - var(--ff-q) * 16px));
}
[data-ff-reveal] .ff-steps__n { transform: scale(calc(0.6 + var(--ff-q, 1) * 0.4)); }

/* Next-page row: the hairline above each link draws on hover, the house curve. */
.ff-next a { background: linear-gradient(var(--accent), var(--accent)) left top / 0 1px no-repeat; transition: color var(--dur-hover) var(--ease-plain), background-size var(--dur-cta) var(--ease-out-quart); }
.ff-next a:hover { background-size: 100% 1px; }

/* Figures lift their image a touch on hover, inside the still window. */
.ff-figure img { transition: transform var(--dur-panel) var(--ease-out-quart); }
.ff-figure:hover img { transform: scale(1.03); }

/* Hue drift for generated gradient panels (the Phonos model carousel), ±6deg. */
@keyframes ff-drift { from { filter: hue-rotate(-6deg); } to { filter: hue-rotate(6deg); } }
.ff-drift { animation: ff-drift var(--dur-drift) var(--ease-plain) infinite alternate; }

@media (prefers-reduced-motion: reduce) {
  .ff-drift { animation: none; }
  .ff-figure:hover img { transform: none; }
}

/* ===== Technical labels in IBM Plex Mono =====
   Captions, credits, facts, table heads, step numbers and meta lines: the small print that
   names a thing. Prose, headings and buttons stay in Host Grotesk. */
.ff-figure figcaption, .ff-credit, .ff-hero__credit, .ff-split__credit,
.ff-item__meta, .ff-defs__role, .ff-chips li, .ff-steps__n,
.ff-facts dt, .ff-table caption, .ff-table thead th, .ff-num {
  font-family: var(--ff-mono);
  letter-spacing: 0.02em;
}
.ff-figure figcaption, .ff-credit, .ff-hero__credit, .ff-split__credit { font-size: 12px; }
.ff-chips li { font-size: 12px; }
.ff-item__meta, .ff-defs__role, .ff-facts dt { font-size: 12px; }
.ff-table caption, .ff-table thead th { font-size: 12px; text-transform: uppercase; letter-spacing: 0.06em; }
.ff-steps__n { font-size: 12px; }

/* ===== Small screens ===== */
@media (max-width: 1100px) {
  .ff-grid--4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .ff-grid--3 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 860px) {
  .ff-pagehead { grid-template-columns: 1fr; gap: var(--space-5); padding: var(--space-8) var(--gutter-sm) var(--space-7); }
  .ff-grid, .ff-grid--3, .ff-grid--4 { grid-template-columns: 1fr; gap: var(--space-6); }
  .ff-next { padding: var(--space-7) var(--gutter-sm); }
  .ff-legal { padding: var(--space-7) var(--gutter-sm); }
  .ff-legal__sheet { padding: var(--space-6) var(--space-5); }
  .ff-figure figcaption { left: var(--space-3); bottom: var(--space-3); }
  .ff-credit { right: var(--space-3); bottom: var(--space-3); }
  /* Stacked layout: an image as wide as the screen that opens and closes with scaleX while
     scrolling reads as a book flapping. Here pictures only fade in, and never squeeze. */
  .ff-split__media,
  .ff-figure[data-ff-reveal], .ff-band[data-ff-reveal] { transform: none; }
}


/* ===== Grid system, 2026-10-27: shared with Phonos (phonos static/css/brutalist.css) =====
   Same tokens as the Phonos app: one cell (--ff-cell, 32px; 16px on phones), a stronger
   line every 4 cells, 12/8/4 columns. The background is now the same square field as Phonos
   (it was column lines only). Page margins, section paddings and gaps are whole cells;
   two-column layouts round the first column down to whole cells and give the remainder to the
   last, and sections add mod(100%, cell) to their right padding, so the content box is whole
   cells wide. Heights depend on content: grid-snap.js (loaded by scientific.js) rounds each
   block of <main> up to whole cells, so every section starts on a grid line. */
:root {
  --ff-cell: 32px;
  --ff-cell-major: 4;
  --ff-cols: 12;
  --ff-gap: var(--ff-cell);
  --ff-pad: 16px;
  --ff-major: calc(var(--ff-cell) * var(--ff-cell-major));
  --gutter: calc(2 * var(--ff-cell));    /* 64px page margin */
  --gutter-sm: var(--ff-cell);           /* 16px on phones */
  --topbar-height: 64px;                 /* 2 cells, so <main> starts on a line */
  --ff-grid-margin: var(--gutter);
  --ff-grid-minor: color-mix(in srgb, var(--ink) 5%, transparent);
  --ff-grid-major: color-mix(in srgb, var(--ink) 10%, transparent);
  --ff-grid-bg:
    linear-gradient(var(--ff-grid-major) 1px, transparent 1px),
    linear-gradient(90deg, var(--ff-grid-major) 1px, transparent 1px),
    linear-gradient(var(--ff-grid-minor) 1px, transparent 1px),
    linear-gradient(90deg, var(--ff-grid-minor) 1px, transparent 1px);
  --ff-grid-size: var(--ff-major) var(--ff-major), var(--ff-major) var(--ff-major), var(--ff-cell) var(--ff-cell), var(--ff-cell) var(--ff-cell);
  --ff-track2: round(down, calc((100% - var(--ff-col-gap, 0px)) / 2), var(--ff-cell));
}
@media (max-width: 1100px) { :root { --ff-cols: 8; } }
@media (max-width: 860px)  { :root { --ff-cell: 16px; --ff-cols: 4; --ff-grid-margin: var(--gutter-sm); } }

.ff-pagehead, .ff-section, .ff-next, .ff-legal, .ff-contact, .ff-split, .sci-carousel {
  background-image: var(--ff-grid-bg);
  background-size: var(--ff-grid-size);
  background-position: 0 0;
  background-repeat: repeat;
}

/* Sections: whole-cell paddings, whole-cell content box, rounded first column. */
.ff-section, .ff-contact, .ff-pagehead {
  --ff-col-gap: calc(2 * var(--ff-cell));
  gap: var(--ff-col-gap);
  padding-right: calc(var(--gutter) + 2 * var(--ff-cell) + mod(100%, var(--ff-cell)));
  grid-template-columns: round(down, calc((100% - var(--ff-col-gap)) / 2), var(--ff-cell)) minmax(0, 1fr);
}
.ff-section--wide { grid-template-columns: minmax(0, 1fr); gap: calc(1.5 * var(--ff-col-gap)); }
.ff-split { grid-template-columns: round(down, 50%, var(--ff-cell)) minmax(0, 1fr); }
.ff-split__text { padding: calc(3 * var(--ff-cell)) calc(var(--gutter) + 2 * var(--ff-cell)) calc(3 * var(--ff-cell)) calc(2 * var(--ff-cell)); }
.ff-next {
  gap: var(--ff-gap);
  padding-right: calc(var(--gutter) + 2 * var(--ff-cell) + mod(100%, var(--ff-cell)));
  grid-template-columns: repeat(auto-fit, minmax(calc(7 * var(--ff-cell)), 1fr));
}
.ff-legal { padding-right: calc(var(--gutter) + 2 * var(--ff-cell) + mod(100%, var(--ff-cell))); }
.ff-legal__sheet { max-width: calc(27 * var(--ff-cell)); padding: calc(2 * var(--ff-cell)); }

/* Item grids: whole-cell gutters, columns rounded to whole cells, the last one takes the rest. */
.ff-grid {
  gap: calc(2 * var(--ff-cell)) calc(2 * var(--ff-cell));
  grid-template-columns: round(down, calc((100% - 2 * var(--ff-cell)) / 2), var(--ff-cell)) minmax(0, 1fr);
}
.ff-grid--3 { grid-template-columns: repeat(2, round(down, calc((100% - 4 * var(--ff-cell)) / 3), var(--ff-cell))) minmax(0, 1fr); }
.ff-grid--4 { gap: var(--ff-gap); grid-template-columns: repeat(3, round(down, calc((100% - 3 * var(--ff-cell)) / 4), var(--ff-cell))) minmax(0, 1fr); }
.sci-models { gap: calc(2 * var(--ff-cell)); }
.ff-section__body > * + * { margin-top: var(--ff-cell); }

@media (max-width: 1100px) {
  .ff-grid--3, .ff-grid--4 { grid-template-columns: round(down, calc((100% - var(--ff-cell)) / 2), var(--ff-cell)) minmax(0, 1fr); gap: var(--ff-gap); }
}
@media (max-width: 860px) {
  .ff-section, .ff-contact, .ff-pagehead {
    grid-template-columns: minmax(0, 1fr);
    gap: calc(2 * var(--ff-cell));
    padding-left: var(--gutter-sm);
    padding-right: calc(var(--gutter-sm) + mod(100%, var(--ff-cell)));
  }
  .ff-split { grid-template-columns: minmax(0, 1fr); }
  .ff-split__text { padding: calc(4 * var(--ff-cell)) var(--gutter-sm); padding-right: calc(var(--gutter-sm) + mod(100%, var(--ff-cell))); }
  .ff-next, .ff-legal { padding-left: var(--gutter-sm); padding-right: calc(var(--gutter-sm) + mod(100%, var(--ff-cell))); }
  .ff-legal__sheet { padding: calc(2 * var(--ff-cell)) var(--ff-cell); }
  .ff-grid, .ff-grid--3, .ff-grid--4 { grid-template-columns: minmax(0, 1fr); gap: calc(2 * var(--ff-cell)); }
}
