/* =====================================================================
   BEDROCK OS — DO NOT EDIT WITHOUT CEO DISCUSSION.
   This file is the OS. Every value in it is a decision Kai has made, and a
   mismatch with the canon document does not license "fixing" either side:
   the mismatch itself goes to Kai (bedrock-os-web-design.md §4).

   CANONICAL FILE: bedrock/standards/os.css — next to the written canon.
   zero.space/assets/os.css and website/assets/os.css are GENERATED copies
   (scripts/sync-os.py; zero.space's _build.py syncs automatically). Edit only
   the canonical; a copy that differs from it is a defect, not a variant.
   One session edits the canonical at a time; if unsure that is you, it is not.
   ===================================================================== */
/* =====================================================================
   Bedrock OS — implementation canon.
   Spec: bedrock/standards/bedrock-os-web-design.md
   One family (Geist), two weights (500/300), three declared sizes plus the
   key title, tracking and 0.8 leading on ALL CAPS only, 1.2 everywhere else,
   margins assigned by frame — screen (narrow) / page (wide) / nested (--r-pad),
   one radius (24) with one nested gap (14), no lines, no shadows, no animation. Blur only.
   Colors are per-brand; everything else is identical across all sites.
   ===================================================================== */

:root {
  /* margins: the screen frame / the page frame (30 / 100 at 1920px).
     §2 assigns by which frame a thing answers to, not by what kind of thing
     it is — chrome and the full-screen hero take the screen frame, and the
     page's contents all take the page frame. The third relation, nesting,
     is --r-pad below. */
  --m-narrow: clamp(16px, 1.6vw, 30px);
  --m-wide: clamp(24px, 5.2vw, 100px);
  --m-v: clamp(32px, 7vh, 72px);

  /* two faces of one family: Sans is prose, Mono is record */
  /* Geist draws Latin, Greek and Cyrillic. For the scripts it does not draw,
     the OS does not pick a second family — it hands the script to the face
     that platform already treats as standard for it (CEO 2026-09-05, the
     approval §2 was waiting on). Fallback is per character, so Latin never
     reaches past Geist and the rule "one family" still holds where Geist can
     hold it. Naming the faces rather than leaning on system-ui is deliberate:
     system-ui follows the reader's locale, not the page's, so a Japanese page
     on an English machine would otherwise fall to a face chosen for English. */
  --font: "Geist",
    "Hiragino Sans", "Yu Gothic", "Noto Sans JP",
    "PingFang SC", "Microsoft YaHei", "Noto Sans SC",
    "Kohinoor Devanagari", "Nirmala UI", "Noto Sans Devanagari",
    "Kohinoor Bangla", "Noto Sans Bengali",
    "Kohinoor Telugu", "Noto Sans Telugu",
    "Geeza Pro", "Noto Sans Arabic",
    -apple-system, BlinkMacSystemFont, "Segoe UI", "Helvetica Neue", Arial, sans-serif;
  --font-mono: "Geist Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;

  /* type scale */
  --fs-body: clamp(20px, 1.85vw, 35px);
  --fs-caption: clamp(12px, 0.95vw, 16px);
  --fs-nav: 13px;                            /* chrome, not content: recessive by size and weight */
  --fs-btn: 15px;                            /* a pressable word: one step under the prose it sits by */
  --fs-big: clamp(22px, 1.7vw, 30px);        /* the dropdown's list links */

  /* tracking: ALL CAPS key titles only. Capitals are drawn to sit beside
     capitals, so they need closing up; lower-case text does not. */
  --track: -0.04em;                          /* key titles only: optical correction for display sizes */

  /* ---- colour, in three layers ----
     1. absolute — raw values with no meaning of their own. Never swap.
     2. role     — what a thing is for. These swap with the mode.
     3. media    — the plate faces. They follow the brightness of the photo
                   underneath, not the mode, so they are built from the
                   absolutes and never swap. A dark photo needs a dark plate
                   in light mode and in dark mode alike. */

  /* 1. absolute */
  --white: #ffffff;
  --black: #000000;
  --gray: #808080;    /* one value serves both modes: 4.0:1 on white, 5.3:1 on black */

  /* 2. role — light mode */
  --bg: var(--white);
  --fg: var(--black);
  --link: #0000ee;                           /* external links only (leaving this site) */
  --chrome: rgba(255, 255, 255, 0.72);       /* nav, dropdown, cookie: glass over the page */
  --veil: rgba(255, 255, 255, 0.22);         /* page dim behind a dropdown */
  --glass-blur: blur(12px) saturate(1.4);

  /* motion: three durations and one curve. The curve never overshoots —
     a bounce is decoration, and decoration is not a reason to move. */
  --bar: 48px;                               /* the bar's height; the page and the hero both measure from it */
  --t-fast: 90ms;                            /* interaction feedback */
  --t-page: 220ms;                           /* anything that opens, closes, or crosses */
  --t-media: 700ms;                          /* one image giving way to the next */
  --ease: cubic-bezier(0.4, 0, 0.2, 1);      /* feedback */
  --ease-out: cubic-bezier(0.32, 0.72, 0, 1); /* opening: leaves and settles without a snap */

  /* Everything is round except a corner that meets the screen. A thing placed
     on its own takes --r; a thing inside a thing takes the concentric
     --r-inner, because a frame has to hold an even thickness the whole way
     round. The photograph is not the exception it used to be — it is round
     too, and the plate on it is the nested case. Anything meeting the screen
     edge stays square there: a curve against the screen's own corner reads as
     a chip. A button goes further and takes the full pill, which is its own
     shape rather than a second radius. */
  --r: 24px;
  --r-pill: 999px;
  --r-pad: 14px;                             /* one gap, wherever a thing sits inside a thing */
  --r-inner: calc(var(--r) - var(--r-pad));  /* nested: concentric with the curve around it */
  --tint: color-mix(in srgb, var(--gray) 16%, var(--bg));       /* a control at rest */
  --tint-deep: color-mix(in srgb, var(--gray) 34%, var(--bg));  /* a card under the pointer */
  /* the awaited photograph: the same 18 points of grey it has always been,
     laid over the slot's own ground instead of the page's — over the bare
     page nothing moves, and inside a card's tint the held space finally
     reads, in both modes. The frame is made the way every frame here is
     made — a surface with a concentric corner — never a line (§3). */
  --ph: color-mix(in srgb, var(--gray) 18%, transparent);

  /* 3. media — fixed in both modes */
  --plate-light: rgba(255, 255, 255, 0.72);
  --plate-dark: rgba(0, 0, 0, 0.30);
  --ink-on-light: var(--black);
  --ink-on-dark: var(--white);
}

/* The mode has three states: an explicit choice stamps data-theme on the root,
   and the default stamps nothing — so the media query has to carry the
   un-stamped case while still losing to an explicit light choice. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg: var(--black);
    --fg: var(--white);
    --link: #8f9cff;                         /* the light-mode blue is 2.2:1 on black */
    --chrome: rgba(0, 0, 0, 0.72);
    --veil: rgba(0, 0, 0, 0.22);
  }
}
:root[data-theme="dark"] {
  --bg: var(--black);
  --fg: var(--white);
  --link: #8f9cff;
  --chrome: rgba(0, 0, 0, 0.72);
  --veil: rgba(0, 0, 0, 0.22);
}

/* selected text is ink on page, the same two colours everything else uses.
   Written with the role tokens, so it flips with the mode without a second
   declaration, and it holds on a dark plate where the text is already white. */
::selection { background: var(--fg); color: var(--bg); }
::-moz-selection { background: var(--fg); color: var(--bg); }

:root { interpolate-size: allow-keywords; }
*, *::before, *::after { box-sizing: border-box; }

html { scroll-behavior: smooth; }  /* anchor jumps; the wheel is smoothed in JS */

/* a short page still closes with its signature at the bottom edge. This was
   written into seven page-level <style> blocks on bedrock.space and nowhere on
   zero.space, so contact/ left 323px of blank under the footer on a tall
   screen. Layout rhythm is unified (§1), so it belongs here. */
body {
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font-family: var(--font);
  font-weight: 300;
  font-size: var(--fs-body);
  letter-spacing: normal;
  line-height: 1.2;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/* ---- roles (spec §2.0) ---- */

.display {
  /* key title: CAPS + Medium + 0.8; the text frame spans the full
     width inside the page frame (--m-wide) and the size fills the frame */
  font-weight: 500;
  line-height: 0.8;
  letter-spacing: var(--track);
  text-transform: uppercase;
  font-size: clamp(38px, 8.6vw, 190px);          /* page title — fills the text frame */
  margin: 0;
  /* §3 leaves wrapping to the frame — but a frame can only wrap between words,
     and some languages have words longer than the frame. At 375px the German
     "Datenschutzerklärung" measured 464px against a 327px frame and simply ran
     off the page; Russian did the same (found 2026-09-05, in 6 of 225 checks).
     `hyphens: auto` lets the browser break the word by that language's own
     rules — the same principle, extended to words the frame cannot hold. The
     <html lang> the build already writes is what selects those rules.
     `overflow-wrap` is the floor for languages the browser cannot hyphenate. */
  overflow-wrap: break-word;
  hyphens: auto;
}
.display--xl { font-size: clamp(56px, 12vw, 260px); }    /* a title that is the whole page (404) */

h1, h2, h3, h4, h5, h6 { font-size: inherit; font-weight: inherit; margin: 0; }
.label { font-weight: 500; font-size: var(--fs-body); }

.body { font-weight: 300; }

.caption { font-size: var(--fs-caption); font-weight: 300; }

/* ---- Mono: the register of record ----
   Not a style but a register. Prose is set in Sans; anything that is a
   recorded fact rather than a sentence is set in Mono — quantities, units,
   dates, identifiers, and the registered company name. Same family, so the
   two faces share proportions and the page still reads as one system.
   Mono is never used for a sentence, a heading, or navigation. */
/* Mono has exactly one weight. It carries no hierarchy — a record is neither
   emphasised nor faint — so it needs none. Regular, not the Light the prose
   uses: at caption size the Light mono goes fragile, and 500 makes a date
   shout. Only 400 is loaded, so no other weight can be reached by accident. */
.num, time, .stamp {
  font-family: var(--font-mono);
  font-weight: 400;
  font-variant-numeric: tabular-nums;
  text-transform: uppercase;
}
/* A unit symbol carries its case as meaning, so it opts out of the transform:
   kW is a kilowatt and KW is not an SI symbol at all, and mW and MW differ by
   a factor of a billion but render identically once uppercased. Wrap every
   unit — the record stays exact where being exact is the whole point. */
.unit { text-transform: none; }

/* ---- interaction: two tiers ----
   PRIMARY carries a surface. At rest a grey plane holding ink; on contact the
   plane deepens and the words hold still. One motion for everything that can
   be pressed — a button and a card behaving differently reads as two systems.
   SECONDARY carries none. Ink at rest, grey on contact. Used for getting
   around — navigation, the footer, links inside prose. A bar of filled pills
   shouts louder than the thing it is a route to, so movement stays quiet. */
.btn {
  display: inline-flex;
  align-items: center;
  border: none;
  background: var(--tint);
  color: var(--fg);
  cursor: pointer;
  transition: background-color var(--t-fast) linear;
}
.btn:hover, .btn:focus-visible, .btn:active,
.btn[aria-pressed="true"], .btn[aria-current]:not([aria-current="false"]) { background: var(--tint-deep); }

/* No underline, anywhere. The decision to abolish decorative lines (§3,
   2026-08-16) was applied component by component — `.article a`, `.footer a`,
   and `.card` each turned it off for itself — which left the browser
   default standing wherever a link appeared outside a named component. The
   sitemap's rows were underlined for that reason alone. Stated once, at the
   element, so the next new component inherits the decision instead of having
   to remember it. */
a, .slide-arrow, .mode { color: var(--fg); text-decoration: none; transition: color var(--t-fast) linear; }
/* The tier is decided by whether the thing carries a surface, so a link that
   HAS one must be held out of here. `.btn` and `.card` are both <a>, and
   without the exclusion this rule lands on them at the same time as their own
   surface rule — the plane deepens and the words fade at once, which is the
   two tiers playing on one element. Its worst form is a card: the headline
   greys against an already-darker plane and the card reads as disabled. */
a:not(.btn, .card):hover, a:not(.btn, .card):focus-visible, a:not(.btn, .card):active,
.slide-arrow:hover, .slide-arrow:focus-visible, .slide-arrow:active,
.mode:hover, .mode:focus-visible, .mode:active { color: var(--gray); }
.nav li.is-open > a, .nav li.is-open > .drop, .node.is-open > .big { color: var(--gray); }

/* ---- what is in force ----
   The two tiers above describe only the moment of touching. Neither can say
   the other thing a control has to say: that this one is the one in force,
   after the pointer has gone. Left unstated it gets invented once per place
   and never twice the same way — a word beside the item, an ink-against-grey
   of its own, a second colour that belongs to nothing else. All three were
   already in this site before the rule was written (2026-09-02).

   SELECTION IS THE PRESS, SUSTAINED. What is chosen is simply left in the
   state that touching it produces: the primary tier holds the deepened plane,
   the secondary tier holds the grey. Nothing new is drawn, so there is no
   second language to keep in agreement with the first, and the answer to
   "what does chosen look like" is already known by anyone who has pressed
   anything here once.

   It also lands the right way round in both tiers. The pressed plane is the
   heavier one, and the kind in force should be the heavier of its row. In the
   secondary tier it inverts — what is in force recedes to grey — and that is
   correct there for the same reason: a nav item whose panel is open has done
   its work, and the panel it opened is now the loud thing on screen. The rule
   is one sentence either way, which is the test that it is the right one.

   Not to be confused with grey used for UNAVAILABLE (`.is-off`: a language
   with no translation shipped). Where both facts appear in one list, grey
   cannot carry them both — say the unavailable one in grey and mark the one
   in force some other way, as the language panel does with a word. */
[aria-pressed="true"], [aria-current]:not([aria-current="false"]) { cursor: default; }

/* ---- layout ---- */

main { padding-top: var(--bar); flex: 1 0 auto; }
main.bleed { padding-top: 0; }                 /* a hero starts at the top edge, under the nav */
main.bleed > .hero { min-height: 100svh; }

.hero {
  position: relative;
  min-height: calc(100svh - var(--bar));
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  padding: var(--m-v) var(--m-narrow);
}

.hero .hero-bg {
  position: absolute; inset: 0; z-index: -1;
  background: var(--ph) center / cover no-repeat;
  display: flex; align-items: center; justify-content: center;
  color: var(--gray); font-size: var(--fs-caption); font-weight: 500;
}
.hero .hero-bg img {
  position: absolute; inset: 0;
  width: 100%; height: 100%; object-fit: cover; display: block;
  opacity: 0;
  transition: opacity var(--t-media) linear;
}
.hero .hero-bg img.is-on { opacity: 1; }

/* slideshow controls live inside the plate, so no second surface is needed */
.slide-ui { display: flex; align-items: center; justify-content: space-between; gap: 24px; margin-top: 1.4em; }
.gauge { display: flex; gap: 6px; }
.gauge span { width: 26px; height: 2px; background: currentColor; opacity: 0.3; }
.gauge span.is-on { opacity: 1; }
.slide-arrows { display: flex; gap: 18px; }
.slide-arrow { border: none; background: none; padding: 0; cursor: pointer;
  font-family: inherit; font-size: var(--fs-nav); font-weight: 500; color: currentColor; }
/* long-form display: a full statement carrying the key-title role.
   Sentence case, because ALL CAPS cannot be read at sentence length. */
/* sentence case: it drops the tracking with the capitals, and the leading
   with them too — the 0.8 only works because capitals have no descenders. */
.display--long { text-transform: none; letter-spacing: normal; line-height: 1.2; font-size: clamp(22px, 2.6vw, 52px); }

/* Everything in the document takes the page frame — the title too. The one
   remaining use of the other margin is chrome: the bar, the full-screen hero,
   the footer signature. So the rule is not "which kind of thing is this" but
   "is it in the page at all", which is a question with an obvious answer. */
.page-head { padding: calc(var(--m-v) + 24px) var(--m-wide) var(--m-v); }

.content { padding: 0 var(--m-wide) var(--m-v); }

/* ---- navigation (spec §3: attached, --bar tall, blur only, immediate) ---- */

.nav {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 10;
  height: var(--bar);
  padding: 0 var(--m-narrow);
  display: flex;
  align-items: center;
  justify-content: center;
  gap: clamp(22px, 2.4vw, 44px);
  background: var(--chrome);
  -webkit-backdrop-filter: var(--glass-blur);
  backdrop-filter: var(--glass-blur);
  transition: background-color var(--t-page) var(--ease-out);
}

/* While a sheet is open the surface stops being glass and becomes the page:
   solid, unblurred. Nothing behind it needs reading, so nothing shows through.
   Only the background colour moves — at full opacity the blur is already
   invisible, so it never has to be switched off mid-motion. */
.nav:has(.has-panel:hover), .nav:has(.has-panel.is-open) { background: var(--bg); }

.nav ul {
  display: flex;
  align-items: stretch;
  height: 100%;
  gap: clamp(22px, 2.4vw, 44px);
  margin: 0;
  padding: 0;
  list-style: none;
}

.nav li {
  /* full-height items keep :hover unbroken from link to panel */
  display: flex;
  align-items: center;
  height: 100%;
}

/* a name that opens a sheet is not a link: the sheet holds the link. It is
   styled as one so the bar reads evenly, and carries a button's semantics. */
.nav .drop { cursor: pointer; }
.nav a, .nav .drop, .nav .lang {
  font-size: var(--fs-nav);
  font-weight: 500;
  display: flex;
  align-items: center;
  height: 100%;
}

.mark-link { display: flex; align-items: center; height: 100%; }
.nav .mark { height: 13px; width: auto; display: block; color: var(--fg); }

/* language switch: an ordinary nav item, last in the row */
/* inert until a second language ships: shown, but not a link that goes nowhere */
.nav .lang { display: flex; align-items: center; height: 100%; color: var(--fg); cursor: pointer; }
.nav .lang svg { width: 16px; height: 16px; display: block; }
.lang-label { display: none; }   /* the globe carries it on a wide screen */

/* dropdown panel: full-width sheet attached under the bar */
.panel {
  /* The sheet below carries the surface; the panel carries only its contents,
     so moving from one item to the next resizes the open sheet by the
     difference instead of closing it and opening another. */
  position: fixed;
  top: var(--bar); left: 0; right: 0;
  display: grid;
  visibility: hidden;
  opacity: 0;
  pointer-events: none;
  /* contents wait a beat so the surface is under them before they read */
  transition: opacity var(--t-fast) linear var(--t-fast), visibility 0s linear var(--t-page);
  padding: 44px var(--m-wide) 56px;
}

/* the surface itself: one sheet, always present, its height the animated value */
.sheet {
  position: fixed;
  top: var(--bar); left: 0; right: 0;
  z-index: 9;
  height: 0;
  overflow: hidden;
  pointer-events: none;
  background: var(--chrome);
  -webkit-backdrop-filter: var(--glass-blur);
  backdrop-filter: var(--glass-blur);
  transition: height var(--t-page) var(--ease-out),
              background-color var(--t-page) var(--ease-out);
}
.nav:has(.has-panel:hover) ~ .sheet,
.nav:has(.has-panel:focus-within) ~ .sheet,
.nav:has(.has-panel.is-open) ~ .sheet { background: var(--bg); }

.nav li:hover > .panel,
.nav li:focus-within > .panel,
.nav li.is-open > .panel {
  visibility: visible;
  opacity: 1;
  pointer-events: auto;
  transition: opacity var(--t-fast) linear var(--t-fast), visibility 0s;
}

.panel {
  grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
  column-gap: clamp(32px, 4vw, 80px);
  row-gap: clamp(32px, 4vh, 56px);
}

.panel .col { display: flex; flex-direction: column; align-items: flex-start; gap: 14px; }

/* the lead column says what the section is, in one line, in the section's own
   words. One track: a wider lead pushes everything after it to the right. */
.panel .col--lead { gap: 16px; }
.panel .col--lead p { margin: 0; font-size: var(--fs-caption); }
.panel .col--lead .lead-name { font-weight: 500; }

/* tree disclosure (hover): a node with children carries a plus; hovering it
   opens that node's own column to the right. Repeatable at any depth.
   The child column's hit area reaches back across the gutter so the pointer
   never falls into a dead zone on its way over. Focus opens it for keyboards. */
.panel .node { display: flex; align-items: center; gap: 12px; }
.node-plus { position: relative; flex: none; width: 13px; height: 13px; }
.node-plus::before, .node-plus::after { content: ""; position: absolute; background: var(--fg); }
.node-plus::before { left: 0; top: 6px; width: 13px; height: 1px; }
.node-plus::after { top: 0; left: 6px; width: 1px; height: 13px; }
.node:hover .node-plus::after,
.node.is-open .node-plus::after,
.node:focus-within .node-plus::after { opacity: 0; }

.panel .col.node-panel {
  display: none;
  opacity: 0;
  transition: opacity var(--t-page) var(--ease-out), display var(--t-page) allow-discrete;
  margin-left: calc(-1 * clamp(32px, 4vw, 80px));
  padding-left: clamp(32px, 4vw, 80px);
}
.panel:has(.node:hover) .col.node-panel,
.panel:has(.node.is-open) .col.node-panel,
.panel:has(.node:focus-within) .col.node-panel,
.panel .col.node-panel:hover,
.panel .col.node-panel:focus-within { display: flex; opacity: 1; }
@starting-style {
  .panel:has(.node:hover) .col.node-panel,
  .panel:has(.node.is-open) .col.node-panel { opacity: 0; }
}

.colhead {
  font-size: var(--fs-caption);
  font-weight: 300;
  color: var(--gray);
  margin: 0 0 4px;
}

.panel a.big { font-size: var(--fs-big); font-weight: 500; height: auto; }

/* language panel: names in their own language, inert until a translation ships */
.panel--lang { grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); row-gap: 18px; }
/* A language reads the same whether or not it can be pressed. The rule named
   `span` only, so when shipped languages became links (2026-09-05) they fell
   out of it and sat smaller and lighter than the greyed ones beside them —
   one list in two sizes. The state a row is in is said by its colour, never
   by its size. */
.panel--lang span, .panel--lang a { font-size: var(--fs-body); font-weight: 500; color: var(--fg); }
.panel--lang .is-off { color: var(--gray); }
.panel--lang .now { font-size: var(--fs-caption); font-weight: 300; color: var(--gray); }
.panel a { height: auto; }

/* ---- cookie consent ----
   The third thing that floats over the page, so it takes the same recipe as
   the other two: `--chrome` at 0.72 with the one blur, black ink on white
   glass whatever is behind it (§3.2). It meets the bottom edge, so that
   corner is square — there is nothing on the far side to round against
   (§3.0). Nothing new is drawn: the surface is the chrome, the buttons are
   the pill every other working control takes.

   It asks before the tag loads, not after. A banner that appears while
   analytics is already running is a notice wearing a question's clothes. */
.cookie {
  position: fixed; left: 0; right: 0; bottom: 0;
  z-index: 60;
  display: flex; flex-wrap: wrap; align-items: center;
  gap: 14px clamp(20px, 2.4vw, 40px);
  padding: 18px var(--m-wide);
  background: var(--chrome);
  -webkit-backdrop-filter: var(--glass-blur);
  backdrop-filter: var(--glass-blur);
  color: var(--fg);
  border-radius: 0;
  /* it arrives with the page rather than on top of it: the same page-scale
     interval the sheet uses to open */
  transition: transform var(--t-page) var(--ease), opacity var(--t-page) linear;
}
.cookie[hidden] { display: none; }
.cookie.is-away { transform: translateY(100%); opacity: 0; }
/* the sentence carries the fact; it is chrome, so it takes the chrome scale */
.cookie p { margin: 0; flex: 1 1 22ch; font-size: var(--fs-caption); }
.cookie .btn { font-size: var(--fs-caption); padding: 9px 20px; }

/* On a phone the sentence takes the whole row, so the two answers stay
   together on the next one. Left to wrap on its own, `Accept` rode up beside
   the text and `Reject` fell below it — one question with its two answers on
   different lines reads as two separate controls. */
@media (max-width: 760px) {
  .cookie { padding: 16px var(--m-wide); }
  .cookie p { flex: 1 1 100%; }
}

@media (prefers-reduced-motion: reduce) { .cookie { transition: none; } }

/* page veil: blurs the page only while a dropdown-bearing item is hovered */
.veil {
  position: fixed;
  inset: 0;
  z-index: 8;
  display: none;
  opacity: 0;
  transition: opacity var(--t-fast) var(--ease), display var(--t-fast) allow-discrete;
  background: var(--veil);
  -webkit-backdrop-filter: var(--glass-blur);
  backdrop-filter: var(--glass-blur);
}

.nav:has(.has-panel:hover) ~ .veil,
.nav:has(.has-panel.is-open) ~ .veil { display: block; opacity: 1; }
@starting-style {
  .nav:has(.has-panel:hover) ~ .veil,
  .nav:has(.has-panel.is-open) ~ .veil { opacity: 0; }
}

/* ---- buttons ----
   §3.0 is the canon. The press is stated once, with the tier itself; this
   block gives only the shape. The provisional set (1px outline, R0, invert,
   underline-on-hover) was withdrawn in full — spec §3, 2026-08-31. */

/* a button takes the full pill — its own shape, not a second radius */
.btn {
  padding: 14px 30px;
  border-radius: var(--r-pill);
  font-family: inherit;
  font-size: var(--fs-btn);
  font-weight: 500;
}
/* no second :hover here. The press belongs to the tier, not to the shape:
   a button and a card deepen the same plane by the same amount, or the two
   read as two systems. Stated once, above, with the tier itself. */

/* `.btn-text` — a word with an arrow after it — was withdrawn in full
   (CEO 2026-09-04). The tiers are two, and it was a third: no surface, so
   not the primary tier, yet marked with a glyph no plain link carries. The
   arrow is an affordance drawn on, which is the decoration §3 abolished
   everywhere else. It also split one thing in two — About offered Team and
   Careers as arrows while the top page offered All news as a pill, and the
   two are the same act.

   ONE QUESTION SETTLES IT: does the word stand on its own, or does it sit
   inside something? Standing on its own it is a button and takes the pill,
   whether it acts or travels — a button that goes is still a button. Inside
   prose, the nav, or the footer it is a plain link and takes nothing. */

/* ---- long-form article: no width cap. Text runs to the frame;
   the only division allowed is the centered duo gutter. ---- */

/* One step, and it is 1em. Heading to prose, prose to prose, caption to prose
   — the same gap every time, because a page that spaces its parts by five
   different amounts is claiming five kinds of relatedness it cannot name.

   A section supplies its own edges, so the first thing inside one takes no
   space above it and the last takes none below. Until 2026-09-02 this was
   done by hand: every heading on the site carried `style="margin: 0 0 1em"`
   because `.article h2` opened with 2.2em that landed on top of the section's
   padding. Ninety-three inline margins in eight different values were the
   accumulated cost of that one wrong opening value, and the rule underneath
   them had never once applied. */
.article h2 { margin: 2.2em 0 1em; }
.article p { margin: 0 0 1em; }
.content > :first-child, .page-head > :first-child { margin-top: 0; }
.content > :last-child { margin-bottom: 0; }

/* ---- news ----
   A story is a picture with a date and a headline under it. The newest runs
   wide across the frame; the rest fall into a grid that reflows by width.
   The card carries its surface from the start, which binds the picture to the
   words under it as one object and says it can be pressed before anyone has
   to hover to find out. On contact the surface deepens rather than inverting:
   a card holds a photograph, and a black slab beside one shouts over it. The
   step is about twice the smallest one that reads. */

/* ---- kinds: narrowing a list to one of its sorts ----
   A kind is pressed, not travelled to. Nothing moves and nowhere is left —
   the list under it is rewritten in place — so this is the primary tier and
   takes the button's own shape, the full pill. The bar of pills withdrawn
   from the nav (2026-08-25) was navigation wearing a control's clothes; this
   is the opposite case, and one question sorts both: does it act, or does it
   go? A row that acts may carry surfaces. A row that goes may not.

   The one in force holds the press, stated once above with the tier. There is
   no rule for it here, and there must not be one. */
.kinds { display: flex; flex-wrap: wrap; gap: 8px; margin: 1.6em 0 0; }
.kinds .btn { font-size: var(--fs-caption); padding: 9px 20px; }

/* What a list says when the narrowing leaves nothing in it. Prose, not a
   panel: a held space would promise a picture that is not coming. */
.empty { color: var(--gray); font-size: var(--fs-caption); margin: 1.6em 0 0; }

/* A card carries `hidden` while a kind is in force. `.card` sets its own
   display, which outranks the attribute's rule in the browser's sheet, so the
   attribute has to be said again here — otherwise the card stays on screen
   while claiming to be hidden, to a screen reader as much as to the eye. */
.card[hidden] { display: none; }

/* People. A person is photographed upright, so the frame that holds one is the
   only portrait frame the OS declares: 4:5. The three landscape ratios frame
   things and places (§3); a person gets the fourth, and it is declared here
   rather than taken from whatever the photographer handed over — the rule is
   still that the frame decides, not the material.

   Standalone, so the corner is `--r` (§3.0). Until 2026-09-02 this whole grid
   lived in inline styles on one page, which is why its pictures were square
   while every other picture on the site was round: markup that never meets a
   rule cannot drift back on its own. */
.people {
  display: grid;
  /* one width, not two. Leadership had 240px and the advisers 300px because
     each grid was written where it was needed; a list does not get to choose
     its own measure any more than it gets to choose its own layout (§3.1.2).
     300 gave three columns and a portrait 494px tall — half a screen per
     person, so seventeen people read as a wall of faces rather than a team.
     220 gives four, and a face at 355; measured against 185, which gives five
     and quiets the pictures further but narrows the prose under them to the
     point where a two-line role wraps to three. A portrait is sized by how
     many belong on the page, not by how large one of them can be. */
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: clamp(32px, 3.6vw, 56px);
  align-items: start;
  margin: 1.6em 0 0;   /* the same step a grid takes below its column head */
}
/* Everyone gets the frame, whether or not the photograph has been taken yet.
   A list where only some people have pictures ranks them by who was
   photographed, which is not a fact about the company; and the ones who do
   have pictures then read as the important ones purely because the others
   are text. The held space is the same one a card uses (§3.0) — a surface
   with the same corner, never an outline — so an empty frame says "awaited"
   rather than "missing". */
.people img, .people .ph {
  display: block; width: 100%;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  border-radius: var(--r);
  /* the gap under a picture belongs to the picture, not to whatever follows
     it — the same rule the card learned in §3.0 */
  margin: 0 0 14px;
}
.people .ph { background: var(--ph); }
/* the block principle (§2.0): the first line names, the lines under it
   describe. Spacing comes from the block, so no person carries their own */
.people p { margin: 0; }
.people .label { margin: 0 0 2px; }
.people .label + .caption { margin: 0 0 0.9em; }

/* A phone gets two. The desktop minimum falls to one column at 375px, and a
   portrait then takes half the screen — seventeen people become thirteen
   screens of scrolling. Two columns is not a smaller version of the desktop
   grid; it is the same rule (a portrait is sized by how many belong on the
   page) applied to a frame that holds less. */
@media (max-width: 760px) {
  .people { grid-template-columns: repeat(2, 1fr); gap: clamp(20px, 5vw, 32px); }
}

/* One shape for every list of cards, whatever it lists: the first item takes
   the whole frame, the rest reflow in a grid under it. News, products, the
   parts of a product, projects, the library — a reader who has learned one
   of these has learned all of them, and a page that lists things does not
   get to invent its own rhythm for doing so.

   Named for what it is, not for where it was first needed. It was `.news-*`
   while five of the pages using it were not news, which is how a name stops
   being read and a second layout gets written next to it (renamed
   2026-09-02). */
/* An index is a list that cannot hold a photograph — a sitemap, a list of open
   positions. `.lead`/`.cards` below is the shape for lists that can, so the two
   never compete: the question is whether there is a picture, not which layout
   is wanted. The rows are secondary (§3.0) and take their hover from the global
   rule; nothing is added here.

   No marker and no indent. A bullet is a mark the palette never declared, and
   the browser's 40px indent would put a second line inside the page frame,
   which §3.3 forbids. The frame is the head of the row. Added 2026-09-02;
   until then these lists carried no rule at all and rendered as browser
   default discs. */
.index {
  display: flex; flex-direction: column;
  /* in em, so the rhythm follows the text rather than a second scale */
  gap: 0.6em;
  margin: 1.6em 0 0;
  padding: 0;
  list-style: none;
}

.lead { display: grid; margin: 1.6em 0 clamp(40px, 4vw, 72px); }
.cards {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
  gap: clamp(36px, 3.4vw, 64px) clamp(24px, 2.4vw, 40px);
  margin: 1.6em 0 0;
}

.card {
  display: block;
  padding: var(--r-pad);
  /* no negative margin. The frame is the page's structural line, and what sits
     on it is the object — the surface. Bleeding the surface outward to put the
     card's picture on the line instead puts two surfaces of the same tier on
     two different lines, since a button's surface starts at the frame. The
     card's contents indent by one gap, exactly as a button's word does. */
  border-radius: var(--r);
  background: var(--tint);
  color: var(--fg);
  /* only the surface moves: the words stay put, which keeps the picture and
     its caption reading as one unchanged object under the pointer */
  transition: background-color var(--t-fast) linear;
}
.card:hover, .card:focus-visible, .card:active,
.card[aria-current]:not([aria-current="false"]) { background: var(--tint-deep); }

/* a card still waiting for its photograph holds the placeholder ground;
   ratio and corner already come from `.card img, .card .ph` below */
.card .ph { background: var(--ph); }

.card img, .card .ph {
  display: block; width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  /* nested, so concentric: the frame keeps an even thickness all the way round */
  border-radius: var(--r-inner);
}
/* where the subject sits in the frame — a fact about the picture, not a
   style, so it travels with the image rather than with the component */
.focus-low { object-position: center 78%; }
.focus-high { object-position: center 12%; }
.lead .card img, .lead .card .ph { aspect-ratio: 21 / 9; }

.card time {   /* mono, 400, uppercase already come from `.num, time, .stamp` */
  display: block;
  font-size: var(--fs-caption);
  color: var(--gray);
  margin: 0 0 10px;
}
/* What sort of thing this is. Above the date because it is the coarser fact,
   and in the sans rather than the mono the date wears — a kind is a word, not
   a record (§2.1). Grey, so the headline is still read first. */
.card .kind { display: block; font-size: var(--fs-caption); color: var(--gray); margin: 0 0 4px; }
.card .head {
  display: block;
  font-weight: 500;
  font-size: var(--fs-body);
  line-height: 1.2;
  max-width: 34ch;
}
.card .stand {
  display: block;
  font-weight: 300;
  font-size: var(--fs-caption);
  color: var(--gray);
  margin: 10px 0 0;
  max-width: 54ch;
}

/* A card resets what it holds, exactly as a plate does — otherwise a <p>
   arrives with the browser's own margin and the frame stops being one value.
   The gap under the picture belongs to the PICTURE, not to the date: carried
   on `.card time`, a card without a <time> had its headline flush against the
   photograph — which is every card on the products page. */
.card > * { margin: 0; }
.card img + *, .card .ph + * { margin-top: 18px; }

/* ---- plate: the base that carries text over media ----
   Same glass as every other floating surface. It is the nested case: one
   nesting gap in from the picture's edge, with the concentric corner. The
   hero is the single exception, written as one below. Its own text sits one
   screen margin in from the plate edge, which is a typographic indent rather
   than a frame and so keeps its own value.
   Works over any image because the blur normalises whatever is behind it. */

.media { position: relative; }  /* the plate positions against the media box */
.plate {
  /* nested inside a framed picture: the nesting gap, concentric corner */
  border-radius: var(--r-inner);
  position: absolute;
  left: var(--r-pad);
  bottom: var(--r-pad);
  width: fit-content;
  max-width: calc(100% - var(--r-pad) * 2);   /* containment, not a measure */
  padding: var(--m-narrow);
  -webkit-backdrop-filter: var(--glass-blur);
  backdrop-filter: var(--glass-blur);
}
/* Two faces, identical geometry. The glass matches the media it sits on, and the
   text opposes the glass — glass is translucent, so it pulls the backdrop toward its
   own tint rather than replacing it. Inverting lands the composite in mid-grey where
   neither text holds. Measured crossover: media luma 90 of 255.
     media luma <  90  ->  .plate--dark  (white text)
     media luma >= 90  ->  .plate--light (black text; never below 6.9:1, so the safe default) */
.plate, .plate--light { background: var(--plate-light); color: var(--ink-on-light); }
.plate--dark { background: var(--plate-dark); color: var(--ink-on-dark); }
.plate > * { margin: 0; }
.plate > * + * { margin-top: 0.6em; }

/* alignment grid — five lines across any media: both edges, the centre,
   and the midpoint on each side. A plate may end or begin on any line. */
.plate--to-2, .plate--to-3, .plate--to-4,
.plate--from-2, .plate--from-3, .plate--from-4 { width: auto; max-width: none; }
/* A plate keeps the same gap from every line it meets that it keeps from the
   media edge — the nesting gap here, the screen margin in the hero override —
   so a plate that stops at the centre and one that starts there leave twice
   that gap between them (28px inside a band).
   from-* is declared first so a from/to pair spans line to line; on its own it
   runs to the far frame edge, mirroring to-* which starts at the near one. */
.plate--from-2 { left: calc(25% + var(--r-pad)); right: var(--r-pad); }
.plate--from-3 { left: calc(50% + var(--r-pad)); right: var(--r-pad); }
.plate--from-4 { left: calc(75% + var(--r-pad)); right: var(--r-pad); }
.plate--to-2 { right: calc(75% + var(--r-pad)); }   /* stops short of line 2 (25%) */
.plate--to-3 { right: calc(50% + var(--r-pad)); }   /* stops short of line 3 (centre) */
.plate--to-4 { right: calc(25% + var(--r-pad)); }   /* stops short of line 4 (75%) */

/* THE ONE EXCEPTION. The hero is not a framed picture — it runs to all four
   screen edges, so there is no frame for its plate to be nested in, only the
   screen. It takes the screen's own margin and keeps the full radius, since
   an inset panel never reaches the screen's corner to chip it. Written here
   as an override rather than as a token both places read, because it is one
   case and an exception should look like one. */
.hero .plate { border-radius: var(--r); left: var(--m-narrow); bottom: var(--m-narrow); }
.hero .plate--to-2 { right: calc(75% + var(--m-narrow)); }
.hero .plate--to-3 { right: calc(50% + var(--m-narrow)); }
.hero .plate--to-4 { right: calc(25% + var(--m-narrow)); }
.hero .plate--from-2 { left: calc(25% + var(--m-narrow)); right: var(--m-narrow); }
.hero .plate--from-3 { left: calc(50% + var(--m-narrow)); right: var(--m-narrow); }
.hero .plate--from-4 { left: calc(75% + var(--m-narrow)); right: var(--m-narrow); }

/* ---- imagery (two tiers, proposal 2026-08-15) ----
   Full bleed is reserved for the hero background only.
   All other images sit on the text margin system:
   The frame is no longer a choice. A picture sits on the same line as the
   text around it — one line down the page, not two — so the frame lives on
   .media itself. What is left to choose is the ratio. */

/* auto width, never width:100% — with margin-inline that would overflow the frame */
.media { display: block; margin: 0 0 var(--m-v); margin-inline: var(--m-wide); }
.media img { display: block; width: 100%; height: auto; }
/* ratio only — the frame is common */
.media .ph {
  display: flex; align-items: center; justify-content: center;
  background: var(--ph); color: var(--gray);
  font-size: var(--fs-caption); font-weight: 500;
}
/* the placeholder and the real image share one set of ratios, so dropping an
   image in never changes the layout around it */
.media .ph, .media img { aspect-ratio: 21 / 9; object-fit: cover; border-radius: var(--r); }
/* nested twice over: a framed picture inside a card is still the card's
   nesting, and these selectors sit later than `.card img` at equal weight */
.card .media .ph, .card .media img { border-radius: var(--r-inner); }
/* scoped to beat `.media img`, which is one specificity point heavier */
.media .ph--flat, .media img.ph--flat { aspect-ratio: 3 / 1; }   /* flat band */
/* the figure already carries its tier as margin-inline, so a horizontal
   padding here would indent the caption past its own picture's left edge */
figcaption { font-size: var(--fs-caption); font-weight: 300; padding: var(--r-pad) 0 0; }

/* ---- motion (spec §3.1) ----
   Movement is allowed when it explains position or continuity, and at no
   other time. Crossing between documents, scrolling, revealing what a page
   sits on: all of these answer "where did that go". Elements arriving as
   they scroll into view answer nothing, and stay forbidden. */
@view-transition { navigation: auto; }

::view-transition-old(root), ::view-transition-new(root) {
  animation-duration: var(--t-page);
  animation-timing-function: var(--ease);
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

/* ---- footer (stacked columns + signature in the narrow frame) ----
   Links stand in vertical columns; the ZERO wordmark closes the page
   inside the narrow frame (full bleed stays reserved for the hero). */

.footer { padding: 0; }
.footer .foot-body {
  display: flex;
  flex-wrap: wrap;
  gap: clamp(48px, 8vw, 140px);
  align-items: flex-start;
  padding: calc(var(--m-v) * 1.5) var(--m-wide) var(--m-v);
}
.footer .foot-col { display: flex; flex-direction: column; gap: 12px; }
.footer a { font-size: var(--fs-caption); font-weight: 500; }
.footer .mode {
  border: none; background: none; padding: 0; margin: 0; cursor: pointer;
  font-family: inherit; font-size: var(--fs-caption); font-weight: 500;
  text-align: left;
}
.footer .stamp { font-size: var(--fs-caption); margin: 0 0 0 auto; align-self: flex-end; }
.footer .sig-wrap { padding: 0 var(--m-narrow) var(--m-narrow); }
.footer .sig { display: block; width: 100%; height: auto; aspect-ratio: 79.5 / 14.02;   /* the ink, not the box: the artwork stops short of the viewBox */ color: var(--fg); margin: 0; }

/* ---- layout patterns (provisional set, 2026-08-14) ----
   Reusable section compositions for web and future apps. */

/* P0 duo: two texts side by side; the gutter is centered, 50px each side
   of the center line (100px total = the wide margin value at 1920). */
.duo {
  display: grid;
  grid-template-columns: 1fr 1fr;
  column-gap: var(--m-wide);
  padding: var(--m-v) var(--m-wide);
}
@media (max-width: 800px) { .duo { grid-template-columns: 1fr; row-gap: var(--m-v); } }

/* P4 card grid: uniform tiles (news, shop, team) */
.grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 48px;
  padding: 0 var(--m-wide) var(--m-v);
}

/* Leaving the site is blue; internal navigation stays ink. Every scheme that
   hands the reader to something else counts, not only another web page: mail
   and telephone leave the browser altogether, which is a larger departure than
   a link to another site. They were missing until 2026-09-04, so an address in
   the middle of a paragraph was black on black with no underline (§3 abolished
   those) — nothing at all said it could be pressed. In prose the colour is the
   only cue a link has left, and prose here holds no internal links: every one
   is mail or external, so half of them were invisible.

   `tel:` is here before a telephone number is. The rule must not depend on
   someone remembering it on the day one appears — §4, on the cache-buster: a
   step that gets forgotten is not a step, it is a defect.

   An address standing on its own does not need the blue and does not get it:
   it is a word standing alone, so it takes the pill (CEO 2026-09-04), and the
   surface says what the colour would have said. The guard below is what makes
   that work — the same lesson §3.0 states for the hover rule: a second-tier
   colour must not land on a primary-tier surface. */
a:not(.btn, .card)[href^="http://"], a:not(.btn, .card)[href^="https://"],
a:not(.btn, .card)[href^="mailto:"], a:not(.btn, .card)[href^="tel:"] { color: var(--link); }

/* ---- the bar on a phone ----
   Seven items and a globe do not fit in 375px — measured at 438px, so the
   mark fell off one end and the language control off the other. Below the
   breakpoint the bar holds the mark and one control; everything else moves
   into a full-height list. Rows with children stay closed until tapped, and
   they open with the same plus the desktop dropdown uses: one device, both
   platforms, nothing new to learn. */
.nav-toggle {
  display: none;
  position: absolute; right: var(--m-narrow); top: 0;
  width: 22px; height: var(--bar); padding: 0;
  border: none; background: none; cursor: pointer;
  color: var(--fg);
}
.nav-toggle i, .nav-toggle i::before, .nav-toggle i::after {
  position: absolute; left: 0; width: 22px; height: 1px;
  background: currentColor; content: "";
  transition: transform var(--t-page) var(--ease-out), opacity var(--t-fast) linear;
}
.nav-toggle i { top: 50%; }
.nav-toggle i::before { top: -6px; }
.nav-toggle i::after { top: 6px; }
.nav.is-menu-open .nav-toggle i { transform: rotate(45deg); }
.nav.is-menu-open .nav-toggle i::before { transform: translateY(6px) rotate(-90deg); }
.nav.is-menu-open .nav-toggle i::after { opacity: 0; }

@media (max-width: 760px) {
  .nav-toggle { display: block; }

  .mark-link {
    position: absolute; left: var(--m-narrow); top: 0;
    height: var(--bar);
  }

  /* Scoped to the main list: the language switch is a second list that stays
     in the bar, so it must not be turned into a full-screen sheet with it. */
  .nav > #nav-list {
    /* the bar carries a backdrop-filter, which makes it the containing block
       for its fixed children — so bottom:0 would resolve inside --bar. The
       height is stated instead. */
    position: fixed; top: var(--bar); left: 0; right: 0;
    display: flex; flex-direction: column; align-items: stretch;
    height: calc(100dvh - var(--bar));
    gap: 0; padding: 12px var(--m-wide) 48px;
    background: var(--bg);
    overflow-y: auto;
    visibility: hidden;
    clip-path: inset(0 0 100% 0);
    transition: clip-path var(--t-page) var(--ease-out),
                visibility 0s linear var(--t-page);
  }
  .nav.is-menu-open > #nav-list {
    visibility: visible;
    clip-path: inset(0 0 0 0);
    transition: clip-path var(--t-page) var(--ease-out), visibility 0s;
  }

  .nav li { display: block; height: auto; }
  .nav > #nav-list > li > a, .nav > #nav-list > li > .drop {
    height: auto; padding: 16px 0;
    font-size: clamp(24px, 6.4vw, 32px); font-weight: 500;
  }
  .nav > #nav-list > li.has-panel > .drop { display: flex; justify-content: space-between; align-items: center; }

  /* the same plus the desktop uses, at the end of a row that has children */
  .nav > #nav-list > li.has-panel > .drop::after {
    content: ""; flex: none; width: 14px; height: 14px; margin-left: 16px;
    background:
      linear-gradient(currentColor, currentColor) center/14px 1px no-repeat,
      linear-gradient(currentColor, currentColor) center/1px 14px no-repeat;
    transition: transform var(--t-page) var(--ease-out);
  }
  .nav > #nav-list > li.has-panel.is-open > .drop::after { transform: rotate(45deg); }

  /* ---- language: in the bar, beside the toggle (Apple's placement) ----
     A phone bar holds two controls, not seven. The globe is the second, so it
     sits where a second control is looked for: next to the button that opens
     the first. It is NOT a row in the menu — a switch that changes the whole
     site is not one of the site's destinations. */
  .nav-lang {
    position: absolute; top: 0; height: var(--bar);
    right: calc(var(--m-narrow) + 22px + 20px);
    z-index: 1;
  }
  .nav .lang svg { width: 20px; height: 20px; }
  .lang-label { display: none; }   /* the globe carries it, as it does on a wide screen */

  /* while the list is open the bar is part of it: solid, unblurred, so the
     top --bar stops showing the page through a sheet that is otherwise opaque */
  .nav.is-menu-open {
    background: var(--bg);
    -webkit-backdrop-filter: none; backdrop-filter: none;
  }

  /* a 3:1 band is a wide-screen shape — on a phone it is a 114px strip with
     no room for the plate that sits in it */
  .media .ph--flat, .media img.ph--flat { aspect-ratio: 4 / 3; }

  /* a panel is no longer a sheet: it is the part of the list under its name */
  .panel {
    position: static;
    display: grid !important;
    grid-template-columns: 1fr;
    visibility: visible;
    background: none;
    -webkit-backdrop-filter: none; backdrop-filter: none;
    padding: 0 0 0 18px;
    row-gap: 0;
    height: 0; overflow: hidden;
    clip-path: none;
    transition: height var(--t-page) var(--ease-out);
  }
  .nav > #nav-list > li.has-panel.is-open > .panel { height: auto; padding-bottom: 10px; }
  .panel .col { gap: 0; }
  .panel .col.node-panel { display: flex; opacity: 1; margin: 0; padding: 0 0 0 18px; }
  .panel a.big { font-size: clamp(18px, 4.6vw, 22px); font-weight: 300; padding: 11px 0; }
  .panel .colhead { display: none; }
  .panel .col--lead { display: none; }
  .node-plus { display: none; }
  .panel--lang .col { padding: 6px 0; }

  /* the language list is not part of the menu, so it opens on its own — the
     same clip the menu uses, from the same edge, so there is one motion */
  .nav-lang .panel--lang {
    position: fixed; top: var(--bar); left: 0; right: 0;
    height: calc(100dvh - var(--bar));
    align-content: start;
    padding: 12px var(--m-wide) var(--bar);
    background: var(--bg);
    overflow-y: auto;
    visibility: hidden;
    clip-path: inset(0 0 100% 0);
    transition: clip-path var(--t-page) var(--ease-out),
                visibility 0s linear var(--t-page);
  }
  .nav-lang li.is-open > .panel--lang {
    height: calc(100dvh - var(--bar));
    visibility: visible;
    clip-path: inset(0 0 0 0);
    transition: clip-path var(--t-page) var(--ease-out), visibility 0s;
  }
  /* while it is open the bar belongs to it, exactly as it does for the menu */
  .nav:has(.nav-lang li.is-open) {
    background: var(--bg);
    -webkit-backdrop-filter: none; backdrop-filter: none;
  }

  /* the alignment lines are a wide-screen device: a quarter of a phone is
     not a column, so every plate takes the whole frame. What it does NOT do is
     change the gap: a plate in a framed picture keeps the nesting gap on a
     phone exactly as it has it on a desktop, or the frame would thicken at the
     one width where there is least room for it. */
  .plate,
  .plate--to-2, .plate--to-3, .plate--to-4,
  .plate--from-2, .plate--from-3, .plate--from-4 {
    left: var(--r-pad); right: var(--r-pad);
    width: auto; max-width: none;
  }
  .hero .plate { left: var(--m-narrow); right: var(--m-narrow); }

  .sheet, .veil { display: none; }
}
