/* Galahad design tokens — the single source of truth for the site's theming
   primitives (palette, surfaces, borders, base type). Extracted verbatim from
   index.html's <style> block so the SPA and the static Journal pages share one
   definition. Loaded by index.html AND by public/content.css.

   Keep this in sync with the `stone` palette / fonts / radii declared in
   tailwind.config.js (the utility-generation path). */

/* ---------------------------------------------------------------------------
   Web fonts, self-hosted.

   These three families used to arrive from fonts.googleapis.com +
   fonts.gstatic.com, which meant every visitor's browser opened a connection to
   a US-operated CDN before the page could paint. On a site whose central claim
   is data sovereignty and GDPR posture, that is a contradiction a technical
   buyer reads off the network tab in ten seconds, so the files are served from
   this origin and no other.

   The declarations below are Google's own, copied rule for rule, with only the
   src rewritten to /fonts/. That is deliberate: the weight and unicode-range
   matching is what decides which file the browser picks and at what axis value
   it instantiates a variable face, so reproducing it verbatim is what makes the
   rendered output identical rather than merely similar.

   Dropped subsets: cyrillic, cyrillic-ext, vietnamese, and Geist Mono's
   `symbols2` (box drawing, U+2500-259F). The site is English and French. The
   box-drawing glyphs appear only inside source-code comments in parts.jsx and
   tweaks-panel.jsx, never in rendered markup.

   Kept subsets: latin and latin-ext. latin-ext is not optional here, the French
   Journal lives at /fr/journal/ and latin covers only U+0000-00FF plus a short
   tail, so the extended set is what backs anything past it.

   Each family is ONE variable woff2 per subset: Geist 400 and 500 resolve to
   the same file, as do Geist Mono 300 and 400. Declaring the weights separately
   costs no extra bytes (the browser fetches the file once) and keeps the weight
   selection identical to what shipped before.

   font-display: swap on every face, as before. The swap is sans to sans
   (ui-sans-serif, system-ui), so the reflow is a width nudge and not a face
   change. --------------------------------------------------------------- */

/* --- Geist: the body face. ------------------------------------------------ */
@font-face {
  font-family: 'Geist';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/fonts/geist-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Geist';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/fonts/geist-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Geist';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('/fonts/geist-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Geist';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('/fonts/geist-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* --- Geist Mono: eyebrows, metadata, the diagram labels. ------------------ */
@font-face {
  font-family: 'Geist Mono';
  font-style: normal;
  font-weight: 300;
  font-display: swap;
  src: url('/fonts/geist-mono-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Geist Mono';
  font-style: normal;
  font-weight: 300;
  font-display: swap;
  src: url('/fonts/geist-mono-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Geist Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/fonts/geist-mono-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Geist Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/fonts/geist-mono-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* --- Space Grotesk: the brand display face. -------------------------------
   One variable file. Its own wght axis runs 300-700 (fontTools on the woff2);
   we expose 300 to 500, which is the range ui-guidelines allows: 300 light for
   the display sizes, 500 medium for .display-3 and the Journal's headings. 400
   is banned on this face. Not a serif: Fraunces was tried once and reverted. */
@font-face {
  font-family: 'Space Grotesk';
  font-style: normal;
  font-weight: 300 500;
  font-display: swap;
  src: url('/fonts/space-grotesk-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Space Grotesk';
  font-style: normal;
  font-weight: 300 500;
  font-display: swap;
  src: url('/fonts/space-grotesk-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

:root {
  /* Pure white, not the off-white this was. The shipped consumer of the light
     ground is the Journal (the SPA carries `dark` and takes the floor below),
     and an off-white page is what made its controls read as grey-on-grey: a
     glass pill needs a ground brighter than itself or it is just a slab.

     Every light token re-measured on the new ground before moving it, ratios
     against the ground itself:

       text   --fg        18.96 -> 19.81      all three tiers GAIN
              --fg-muted   7.31 ->  7.63
              --fg-faint   4.59 ->  4.80      the AA floor it was sized to
       rules  --border-subtle  1.132 -> 1.129   hairlines hold, none vanish
              --border-default 1.230 -> 1.237
              --border-strong  1.419 -> 1.412
       fills  --surface-1      1.045 -> 1.091   both read BETTER on white
              --surface-sunken 1.110 -> 1.160

     The one token this breaks is --surface-0, which was #ffffff and is now the
     ground itself: 1.044 -> 1.000, so `.bg-surface-0` would paint nothing on a
     Journal page. Retuned rather than left inert, because a token that resolves
     to the page ground is what the next reader reaches for when they want a
     faint surface, and they would lose an hour to it. See below. */
  --bg: #ffffff;
  /* #fafaf9, the ground this page used to have, is now its faintest surface:
     1.044 against white, exactly the separation --surface-1 carried against
     the old ground, so the tier is as real as it ever was. That completes a
     monotonic light ramp, #ffffff -> #fafaf9 -> #f5f5f4 -> #efeeec.

     Note the two ladders run in OPPOSITE directions and always did: on dark,
     the tiers climb away from the floor (#101012 -> #1c1c1e -> #242428); on
     light they descend from it. That is not an inconsistency to fix. A panel
     rises off a white page with a rim and a shadow, never with a lighter
     fill, since there is nothing lighter than the ground. The tint is what
     separates it, and the direction it has to move is down.

     The only light-side consumer was content.css's .back-link background, and
     that control is glass now, so nothing shipped changes shade here. */
  --surface-0: #fafaf9;
  --surface-1: #f5f5f4;
  --surface-sunken: #efeeec;
  --fg: #0a0a09;
  --fg-muted: #57534e;
  /* #a8a29e is 2.41:1 on this --bg, and 2.48:1 measured off rendered glyphs
     with the film grain in. It carries REAL TEXT on the Journal, which is live:
     the article eyebrow, the language toggle, figure captions, the asterism
     rule, the index entry meta and the footer copyright, all mono at 10.5px,
     against the 4.5:1 WCAG AA asks of text under 18px. Raised here rather than
     repointed in content.css, because sending those six at --fg-muted would
     collapse the Journal's three ink tiers into two: the entry meta would
     match the entry description, the eyebrow would match the dek. This is the
     same warm stone ramp one step down, stone-400 -> stone-500 in
     tailwind.config.js, so no new colour enters the palette: 4.59:1 on --bg,
     still a clear third tier under --fg-muted at 7.30:1. Only :root moves. The
     SPA ships <html class="dark theme-dark"> and takes the .dark value below,
     so the shipped consumers of THIS one are the Journal pages, which carry no
     dark class. Same fix the .dark block already took. */
  --fg-faint: #78716c;
  --border-subtle: rgba(15,15,15,0.06);
  --border-default: rgba(15,15,15,0.10);
  --border-strong: rgba(15,15,15,0.16);
  /* Tracks --bg, as the dark value below tracks its own floor. */
  --glass: rgba(255,255,255,0.72);
}
.dark {
  /* The page floor, and it must equal theme-dark.css's --elev-floor. That file
     paints <html> with --elev-floor (#101012) while this one painted <body>
     with --bg: the body box covers the content, the html box covers the
     overscroll, so the page was black with a #101012 band above and below it
     on every rubber-band scroll. --elev-floor is the intended value, so --bg
     yields to it. Only `.dark` moves: the Journal pages carry no `dark` class
     (they pull this file through content.css), so their floor is untouched. */
  --bg: #101012;
  /* The ladder ran BACKWARDS. --surface-0 was #0a0a09, DARKER than the
     #101012 floor, so every panel built on it sank instead of rising:
     measured, the contact card painted #0b0b0a against a floor of #0e0e10 and
     the pillar diagram panel #0a0a09 against #0d0d0e, both a step down. These
     are theme-dark.css's --elev-0 and --elev-1 (the product's dark surfaces),
     which is the ladder the rest of the dark system already climbs.
     Consumers checked before moving them: .rim-light (the contact card),
     .pillar-diagram-panel's gradient and .trust-card__icon all want to rise,
     and .trust-card:hover no longer reads --surface-0 at all since
     sections.css:379 took it to --elev-1. Nothing here wants to sink.
     --surface-sunken is the one tier that does, so it stays below the floor.
     Only `.dark` moves: the Journal pulls the :root values above. */
  --surface-0: #1c1c1e;
  --surface-1: #242428;
  --surface-sunken: #0a0a09;
  --fg: #fafaf9;
  --fg-muted: #a8a29e;
  /* #57534e is 2.5:1 on the floor and 2.6:1 on the contact card, and this
     token carries REAL TEXT: the form's own field labels and legal note, the
     section eyebrows, the pillar numerals, the footer copyright. Measured
     rendered glyphs before: 2.51 / 2.56 / 2.37 / 1.75 / 1.78:1, against the
     4.5:1 WCAG AA asks of text under 18px. theme-dark.css keeps a SEPARATE
     non-text tier (--ink-faint, rules and decoration), so the honest fix here
     is to raise this one until it passes rather than to document a restriction
     parts.jsx does not follow. Same warm stone hue, sized against the RAISED
     surface (#1c1c1e) and not the floor, because that is what the form's own
     labels sit on and it is the harder of the two: 4.6:1 there, 5.2:1 on the
     floor. Still a clear third tier under --fg-muted, which measures 6.7:1 and
     7.5:1 on the same two backgrounds. */
  --fg-faint: #8a857d;
  --border-subtle: rgba(255,255,255,0.05);
  --border-default: rgba(255,255,255,0.09);
  --border-strong: rgba(255,255,255,0.16);
  --glass: rgba(0,0,0,0.72);
}
html, body { background: var(--bg); color: var(--fg); }
body {
  font-family: 'Geist', ui-sans-serif, system-ui;
  font-feature-settings: 'ss01','cv11';
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* ===========================================================================
   .cta-glass — THE glass control. One definition, two tunings.

   This lived in theme-dark.css, which the SPA loads and the Journal does not,
   so every Journal control fell through to a flat rule and read as, in the
   founder's words, black and white and not premium. Copying the recipe into
   content.css would have made a second thing to keep in step: this file
   already records what that costs, the display font stack is written in three
   places by hand. So the recipe moves HERE, the one stylesheet both stacks
   load, and only the PAINT is per-theme. Structure, geometry, states and
   affordance are written once.

   The dark tuning below is theme-dark.css's numbers, value for value. Nothing
   about the SPA changes, which is verified by pixel and by computed style.

   THE LIGHT TUNING IS NOT THE DARK ONE INVERTED. Dropped on white, the dark
   lens (brightness 0.62 over a black core stop) yields a muddy grey pill,
   which is exactly the complaint. Two things differ on a light page:

     - The lens can barely stop anything. White is the ceiling: to reach the
       3:1 a control edge wants, the FILL would have to go to #949494, which
       is a grey slab and not glass. So the fill stays a whisper (243/255,
       1.10:1) and the EDGE carries the identification instead, at 3.07:1,
       the same bar --ctl-edge meets on the dark floor.
     - There is nothing behind it to refract on a flat article body. The
       transmission is real only on the header bar, which sits over scrolling
       content. Everywhere else what reads as glass is the edge: a fine rim, a
       bright bevel along the top, a local specular, and a shadow with enough
       spread to lift the control off the page. That is where the light
       numbers are spent.

   Applying the dark tuning to a subtree is `class="... dark"`: the block
   above already means exactly that, and the Journal header uses it.

   ---------------------------------------------------------------------------
   WHAT THE MATERIAL IS, and the four rules the dark tuning is built on. Taken
   from Apple's own statements on Liquid Glass (WWDC25 "Meet Liquid Glass",
   the HIG Materials chapter, the June 2025 newsroom post), not from a look:

     1. GLASS GATHERS LIGHT, IT NEVER SUBTRACTS IT. The material "dynamically
        bends, shapes and concentrates light in real time" and "reflects and
        refracts its surroundings". A backdrop filter with brightness() below
        1.0 does the opposite: it is a smoked filter, not a lens. The dark
        tuning below is BANNED from going under 1.0, and the site's own
        .glass-bar (theme-dark.css) has always been at brightness(1.18).
     2. THE LENSING LIVES AT THE EDGE. Separation and layering come from
        "lensing", light bending at the boundary, not from a flat blur across
        the middle. Hence two lenses here, not one: a calm centre and a much
        stronger rim.
     3. LEGIBILITY IS BOUGHT WITH DYNAMIC RANGE, NOT WITH A DARK FILL. "The
        amount of tint and the dynamic range shift to always ensure buttons
        remain legible, while letting as much of the content through as
        possible." That is what contrast() below 1.0 does: it pulls a blown
        photo highlight back toward the middle so near-white ink keeps its
        4.5:1, instead of painting a black slab over the picture.
     4. IT IS CHROME, AND IT FLOATS. Glass "is best reserved for the
        navigation layer that floats above the content", and glass on glass is
        called out as a mistake. One control in the header, nothing else.

   WHAT THIS REPLACED, and why the founder read it as "a goofy black thing":
   the dark lens was blur(4px) saturate(215%) brightness(0.62) contrast(1.06)
   with a linear-gradient(rgba(0,0,0,0.37), rgba(0,0,0,0.43)) core fill painted
   over the darkened result, under a 0 16px 40px -12px black shadow. Measured
   on the shipped build at 1280x800 over the hero photo: the button interior
   read L=0.0076 against L=0.0384 for the page 40px to its left, five times
   DARKER than the picture it floats on, and rgb(0,0,0), literally black, once
   scrolled onto the floor. Nothing about that is a lens. The same two patches
   now read L=0.0306..0.1425 inside against L=0.0265..0.1109 outside, brighter
   on all twelve samples taken.
   ========================================================================= */

:root {
  /* Light tuning, measured against the #ffffff ground above. */
  --glass-ink: var(--fg);
  /* Fill lands at 246.8/255 through the lens, and the core stop takes the
     middle to ~234 (#eaeaea): 6.34:1 under the muted mono label, 4.5 being
     the bar. saturate() does nothing over flat white and everything over an
     image scrolling under the header bar. */
  --glass-lens: blur(9px) saturate(150%) brightness(0.968);
  /* brightness() below 1 is correct HERE and banned on dark, which is not an
     inconsistency: white is the ceiling, so on a white ground the only
     direction a lens can move a backdrop at all is down. The dark tuning has a
     floor under it instead, and up is the only way off it.

     The rim lens. On a flat article body there is nothing behind the control
     to bend, so this stays a whisper and the light edge is carried by the
     bevel and the shell, as the block comment above sets out. It earns its
     keep on the Journal header, which scrolls over live content. */
  /* No feather is wanted on dark (see below); on white the elliptical stop is
     what keeps the fill from reading as a bevelled plastic key, so the mask is
     a token and the light tuning keeps the one it was built with. */
  --glass-core-mask: radial-gradient(116% 132% at 50% 48%, #000 0 26%, rgba(0,0,0,0.55) 64%, transparent 92%);
  /* FLAT, not a vertical ramp, and this is the whole difference between glass
     and a glossy plastic key on a light page. On the dark floor a top-to-
     bottom black ramp reads as a lens thickening; on white the same ramp is a
     lit dome with a shaded underside, which is skeuomorphism and the thing
     that made the first pass look cheap. The elliptical feather on ::before
     already stops the middle and clears the rim, so the lens read comes from
     the MASK and the fill stays even. */
  --glass-core: rgba(15,15,15,0.055);
  /* Lit along both edges rather than shaded along the bottom. The resting
     control must not look pressed, or the language toggle's selected chip,
     which IS pressed, has nothing left to say. */
  --glass-bevel: linear-gradient(180deg, rgba(255,255,255,1), rgba(255,255,255,0) 42%, rgba(255,255,255,0.55));
  /* Unchanged from the resting bevel, and it has to be DECLARED rather than
     left to fall back: :hover redefines --glass-bevel from this token, and a
     var() that resolves to nothing would drop the ring's whole background.
     White is already the ceiling on a light page, so the light control
     escalates on the shell and the tint instead, which is what its own
     --glass-shell-hover is spent on. */
  --glass-bevel-hover: linear-gradient(180deg, rgba(255,255,255,1), rgba(255,255,255,0) 42%, rgba(255,255,255,0.55));
  --glass-spec: rgba(255,255,255,1), rgba(255,255,255,0.62) 30%, rgba(255,255,255,0.14) 62%, transparent 80%;
  /* No cursor hook runs on the Journal (these pages ship no JS), so the
     hotspot never moves. Parked at the top edge, where a light source belongs,
     rather than dead centre, which lights the left and right rim and reads as
     a lit strip rather than a highlight. */
  --glass-mx: 50%; --glass-my: 0%;
  /* THE EDGE IS THE CONTROL. The rim measures 2.13:1 on white, under the 3:1
     --ctl-edge holds on the dark floor, and that is deliberate rather than
     sloppy: a 1px rule at 3:1 on white is #949494, a drawn outline that turns
     the pill into a form field. Identification is carried by the three
     together, rim plus the fill step plus the contact shadow, which is the
     same bargain the dark .cta-glass already makes (its own rim is 1.5:1 and
     the lens does the rest). Hover raises the rim to 2.6:1 and doubles the
     lift, so the affordance strengthens under the pointer as well. */
  --glass-shell:
    inset 0 1px 0 0 rgba(255,255,255,1),
    inset 0 0 0 1px rgba(255,255,255,0.50),
    0 0 0 1px rgba(15,15,15,0.32),
    0 1px 1.5px rgba(15,15,15,0.045),
    0 6px 14px -6px rgba(15,15,15,0.13);
  --glass-shell-hover:
    inset 0 1px 0 0 rgba(255,255,255,1),
    inset 0 0 0 1px rgba(255,255,255,0.60),
    0 0 0 1px rgba(15,15,15,0.42),
    0 1px 2px rgba(15,15,15,0.05),
    0 10px 22px -8px rgba(15,15,15,0.18);
  --glass-shell-focus:
    inset 0 1px 0 0 rgba(255,255,255,1),
    inset 0 0 0 1px rgba(255,255,255,0.50),
    0 0 0 5px rgba(255,255,255,0.92),
    0 6px 14px -6px rgba(15,15,15,0.13);
  /* Flat washes, for the same reason the core stop is flat. */
  --glass-tint-hover: rgba(255,255,255,0.50);
  --glass-tint-active: rgba(15,15,15,0.09);
  --glass-opaque: rgba(246,246,245,0.97);
  --glass-flat: #f2f2f1;
}
.dark {
  /* Dark tuning: theme-dark.css's values, verbatim. The fallbacks are for a
     subtree marked `dark` on a Journal page, where theme-dark.css never
     loaded and these tokens resolve to nothing. */
  --glass-ink: var(--ink, #fafafa);
  /* THE CENTRE LENS, and the only backdrop-filter on the control. It lifts and
     never subtracts: brightness 1.14, banned from going under 1.0. contrast
     0.86 is rule 3's dynamic-range compression, and it is what buys the label
     its AA on a photograph, pulling a blown highlight back toward the middle so
     the interior cannot run away from the ink. saturate 190% sits beside the
     site's own .glass-bar at 180% and keeps the colour of what is behind.

     THE BLUR IS NOT DECORATION, it is the same compression done spatially: 10px
     averages a wide enough neighbourhood to flatten the photo's peaks and lift
     its holes. Tried at 7px, the worst interior pixel fell to 4.27:1, under the
     AA bar, and the transmission test below dropped to 8 of 12. Both recover at
     10.

     Measured on the built site at 1280x800, a 7px glyph-free column inside the
     control against the page 40px to its left, 12 samples spanning the hero's
     rotation: the interior runs L=0.0306 to L=0.1425, tracking the picture
     behind it 4.7x, and it is brighter than the page beside it on 12 of 12.
     Over the dark floor, scrolled: L=0.0245 against the header bar's L=0.0094.
     Worst-case label contrast 5.22:1 mean and 4.73:1 at the brightest interior
     pixel, against the 4.5:1 WCAG AA asks of 14px text. */
  --glass-lens: blur(10px) saturate(190%) brightness(1.14) contrast(0.86);
  /* WHITE, and a whisper. This was rgba(0,0,0,0.37 -> 0.43), an opaque black
     fill over an already-darkened backdrop, and between them they are the
     entire complaint. A veil this light is the "tint" of rule 3: enough to
     hold the control off a dark floor, not enough to stop the picture. It
     pairs with the brightness above and the two trade: brightness SCALES the
     backdrop, so it moves a bright frame about five times as far as a dark
     one, while the veil is a constant and moves both the same. Buying AA
     margin is therefore brightness down and veil up, which is what took the
     worst pixel from 4.54:1 to 4.73:1 without losing a single slide on the
     transmission test. */
  --glass-core: rgba(255,255,255,0.10);
  /* No feather on dark. The light tuning needs one because a flat fill on
     white reads as a plastic key; on the floor the veil is a whisper and the
     rim is drawn by the shell, so the lens wants uniform coverage, which is
     also what a real lens has. An opaque mask is the no-op. */
  --glass-core-mask: linear-gradient(#000 0 0);
  /* THE RIM, rule 2, and what it is NOT. The plan was a second, much stronger
     backdrop-filter on the ::after ring alone, so the backdrop went sharper and
     hotter at the boundary while the middle stayed soft. It cannot be built.
     Chromium does not clip backdrop-filter to the element's mask: the filter
     runs over the whole border box and only the PAINT is masked to the ring,
     so a ring carrying a filter blurs everything under the control, label
     included. Measured on the Journal's back-link, which sits over a white
     page and made it obvious: the words came out smeared. Both attempts at an
     edge-only lens are therefore dead in a browser, this one and the scaled
     ring below.

     So there is ONE lens, and it sits on ::before at z-index -1, BEHIND the
     label, which is also the only place a full-box filter is harmless. The rim
     is carried by paint instead: the bevel, the local specular and the shell's
     two lit edges. What a real edge lens would need is an SVG
     feDisplacementMap behind `backdrop-filter: url(#...)`, which needs a
     filter node in the document, which is a markup change:
     docs/glass-markup-handoff.md.

     WHAT ELSE WAS TRIED AND DOES NOT WORK, so nobody spends the afternoon
     again: laying the ring out small and scaling it back out, on the theory
     that the backdrop snapshot travels with the element's transform. It does
     not. Probed in Chromium over a 6px stripe field at scale 1.12 and 1.5, on
     the host and on the pseudo: the stripes inside the band stay in phase with
     the page and keep their width, every time. */
  /* THE RIM LIGHTING, and it lives here rather than in the shell. Bright along
     the top edge, a dimmer bounce along the bottom, nothing black anywhere: the
     bevel this replaces ended on rgba(0,0,0,0.13), a shaded underside, which is
     a lit dome and not a piece of glass.

     It was drawn twice for a while. sections.css restated the whole ring at
     (0,2,1) in a later sheet, so this token reached every consumer EXCEPT the
     header CTA, and the two lit edges had to be smuggled in as 1px box-shadow
     insets on --glass-shell to reach it at all. That restatement is deleted and
     those insets are back down to the 0.16 the site's own .glass-bar carries,
     so the edge is one thing in one place again. */
  --glass-bevel: linear-gradient(180deg, rgba(255,255,255,0.72), rgba(255,255,255,0.14) 22%, rgba(255,255,255,0.04) 55%, rgba(255,255,255,0.10) 78%, rgba(255,255,255,0.38));
  /* Hover moves the light around the material rather than just adding more of
     it, which is the interaction Apple describes. Swapped by redefining
     --glass-bevel on the host: ::after inherits it, so the ring repaints
     without the background stack being restated. */
  --glass-bevel-hover: linear-gradient(180deg, rgba(255,255,255,0.95), rgba(255,255,255,0.22) 22%, rgba(255,255,255,0.07) 55%, rgba(255,255,255,0.16) 78%, rgba(255,255,255,0.52));
  --glass-spec: rgba(255,255,255,0.92), rgba(255,255,255,0.30) 34%, rgba(255,255,255,0.04) 66%, transparent 82%;
  /* Parked at the top edge at rest, where a light source belongs. The SPA's
     cursor hook overwrites the pair inline; the Journal ships no JS. */
  --glass-mx: 50%; --glass-my: 0%;
  /* The shell carries the two rings, the contact and the lift. It does NOT
     carry the rim lighting any more, that is --glass-bevel: the 1px insets are
     the same 0.16 the site's own .glass-bar uses, a hairline that keeps the
     edge crisp under the bevel's 3px band rather than standing in for it.
     The `inset 0 -1px 1px rgba(0,0,0,0.34)` all of this replaces was a shadow
     drawn INSIDE the material, which is the one thing glass cannot have.
     The lift is 6 16px -8px, down from 16 40px -12px: a 40px black blur under
     a 37px control is a smudge on the photograph, and on the hero it is the
     other half of what reads as "a black thing behind the button". */
  --glass-shell:
    inset 0 1px 0 0 rgba(255,255,255,0.16),
    inset 0 -1px 0 0 rgba(255,255,255,0.10),
    inset 0 0 0 1px rgba(255,255,255,0.10),
    0 0 0 1px rgba(255,255,255,0.26),
    0 1px 2px rgba(0,0,0,0.28),
    0 6px 16px -8px rgba(0,0,0,0.45);
  --glass-shell-hover:
    inset 0 1px 0 0 rgba(255,255,255,0.24),
    inset 0 -1px 0 0 rgba(255,255,255,0.14),
    inset 0 0 0 1px rgba(255,255,255,0.16),
    0 0 0 1px rgba(255,255,255,0.38),
    0 1px 2px rgba(0,0,0,0.30),
    0 10px 24px -10px rgba(0,0,0,0.50);
  /* Over a bright photo a white focus outline would vanish, so it is backed
     by a dark halo sized to sit under the outline's offset. */
  --glass-shell-focus:
    inset 0 1px 0 0 rgba(255,255,255,0.16),
    inset 0 -1px 0 0 rgba(255,255,255,0.10),
    inset 0 0 0 1px rgba(255,255,255,0.10),
    0 0 0 5px rgba(8,8,10,0.80),
    0 6px 16px -8px rgba(0,0,0,0.45);
  /* Both states BRIGHTEN. "When you interact with Liquid Glass, the material
     illuminates from within as a form of feedback": a press that darkens is
     the ink-on-paper gesture, not the glass one, and the pair this replaces
     ran to rgba(0,0,0,0.22) at the bottom of the press. */
  --glass-tint-hover: rgba(255,255,255,0.10);
  --glass-tint-active: rgba(255,255,255,0.18);
  /* Sized to what the lens actually renders now, not to the old black fill:
     the live control measures L=0.0245 over the floor and #2c2c2e is 0.0265,
     so the accessibility fallbacks land on the value the material does instead
     of a step darker. */
  --glass-opaque: rgba(44,44,46,0.96);
  --glass-flat: var(--elev-2, #2c2c2e);
}

.cta-glass {
  /* Resting hotspot, before the pointer. useCursorGlow (motion.jsx) overwrites
     the pair inline on the SPA; on the Journal nothing does. */
  --mx-px: var(--glass-mx, 50%); --my-px: var(--glass-my, 50%);
  /* 3px, down from 4, because the control lost 7px of height and the band is
     read as a PROPORTION of it. Tried at 5px on the 37px shell and it stopped
     being an edge: the rim became a metal bezel with a separate button sitting
     inside it, which is the same failure 9px produced on the 44px control. */
  --rim: 3px;
  /* Geometry, retunable by a modifier: the Journal's mono chips are the same
     material at a smaller type size.
     37px, not 44. Glass is a floating control and floating controls are small:
     at 44px with 22px gutters and a 16px label this was the widest object in
     the header, competing with the wordmark. The hit box is not what shrank,
     see the pointer:coarse rule below. */
  --glass-h: 37px;
  --glass-px: 17px;
  /* 18px on a 37px box is a capsule, which is the shape the material wants. */
  --glass-r: var(--r-2xl, 18px);
  --glass-font: 500 14px/1 var(--font-sans, 'Geist', ui-sans-serif, system-ui, -apple-system, sans-serif);
  --glass-track: -0.01em;
  /* The specular's reach, DERIVED, because it is geometry and it went stale the
     last time the height moved: a hardcoded 58px sized for the 44px control was
     still being painted on the 37px one, wider than the button is tall, which
     lights the whole band and turns the highlight into metal trim. 0.8 of the
     height keeps it an arc at any size, including the 44px the coarse-pointer
     rule below restores. Declared HERE and not in the theme blocks on purpose:
     a custom property resolves its own var()s on the element that declares it,
     so `calc(var(--glass-h) * 0.8)` written on :root would resolve against a
     --glass-h that does not exist there and land invalid. */
  --glass-spec-r: calc(var(--glass-h) * 0.8);
  position: relative;
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  min-height: var(--glass-h); padding: 0 var(--glass-px);
  border: 0; border-radius: var(--glass-r);
  font: var(--glass-font); letter-spacing: var(--glass-track);
  color: var(--glass-ink);
  text-decoration: none;
  cursor: pointer; user-select: none;
  -webkit-tap-highlight-color: transparent;
  /* NO backdrop-filter on the shell. It moved to ::before, which carries the
     veil and the mask as well, so the lens and its tint are one layer and one
     thing to reason about. Keeping the host unfiltered is also what leaves the
     door open: an element carrying backdrop-filter IS a backdrop root, and a
     descendant's own backdrop-filter then samples that root instead of the
     page and renders as nothing. Probed, ring inside a filtered host over a
     striped field, the band came out indistinguishable from the centre. So
     anything added to ::after later (the SVG displacement route) needs the
     shell to stay clean. */
  background: none;
  backdrop-filter: var(--glass-lens);
  -webkit-backdrop-filter: var(--glass-lens);
  box-shadow: var(--glass-shell);
  transition: background var(--dur-state, 150ms) var(--ease, cubic-bezier(0.16,1,0.3,1)),
              box-shadow var(--dur-state, 150ms) var(--ease, cubic-bezier(0.16,1,0.3,1)),
              transform  var(--dur-state, 150ms) var(--ease, cubic-bezier(0.16,1,0.3,1));
}
/* The control is 37px to the eye and 44px to a finger. Shrinking a tap target
   below 44 is not on the table, so the size is spent where there is a pointer
   and returned where there is not. The SPA hides this control under 768px
   anyway; the Journal's chips ship on phones and are what this is for. */
@media (pointer: coarse) {
  .cta-glass { --glass-h: 44px; }
}
.cta-glass::before,
.cta-glass::after { content: ''; position: absolute; border-radius: inherit; pointer-events: none; }
.cta-glass::before {                      /* the veil, over the lens, under the label */
  /* z-index auto, deliberately. The lens is the host's backdrop-filter and it
     composites behind the host's background; a negative z-index here would put
     the veil BEHIND that and it would stop doing anything. Normal flow order
     puts it above the lens and below the label, which is where a tint belongs. */
  inset: 0;
  background: var(--glass-core);
  /* Feathered on light, uniform on dark: see --glass-core-mask. */
  -webkit-mask: var(--glass-core-mask);
          mask: var(--glass-core-mask);
}
/* NO SVG DISPLACEMENT, and this is a measured result rather than an omission.
   An feDisplacementMap behind `backdrop-filter: url(#...)` is the only way a
   browser bends a backdrop, and it was built, shipped into index.html and
   measured here before being taken back out.

   It works in isolation: on a plain div over a 4px stripe field the same filter
   magnifies the backdrop 1.127x against the 1.154x its scale predicts, and a
   deliberately broken reference (`url(#nonexistent)`) drops the whole
   backdrop-filter, confirming both that the mechanism is real and that the
   failure mode is total.

   It does not work through this control. Measuring the bend properly, a hard
   vertical black-to-white edge behind the button and the sub-pixel 50% crossing
   read inside against outside, at three positions across the width:

     on ::before, scale 11   +1.48 / +2.80 / +2.14 px   (want +3.08 / 0 / -3.08)
     on the host, scale 11   +1.67 / +1.15 / +0.21 px
     on the host, scale 44   -0.01 / +1.15 / +1.45 px, and one edge jumped 11.8

   The middle row is the right SHAPE, monotonic across the control, but a 1.5px
   spread where the map predicts 6.2. Raising the scale four times over did not
   scale it four times: it inverted the trend. The map is not landing on the
   element box the way the filter region says it should, so the effect is neither
   correct nor tunable, and what it actually paints is a 1 to 2px sideways
   misregistration of the backdrop, which is an artifact and not a lens.

   A wrong lens is worse than an honest one, so the rim stays paint: the bevel,
   the local specular and the shell's rings. Anyone retrying this needs the
   filter to be the ONLY thing on the element, and should re-measure with the
   edge test above rather than trusting that a resolving reference is a working
   one. It resolves and still does the wrong thing. */
.cta-glass::after {                       /* the rim: specular + bevel, no filter */
  inset: 0;
  padding: var(--rim);
  /* The specular is LOCAL, and that is what makes it read as a highlight
     rather than as trim. At a 160px radius it lights the entire band and the
     button becomes a brushed metal bezel; at --glass-spec-r it is an arc
     sitting where the pointer is, leaving the rest of the rim transmitting. */
  background:
    radial-gradient(var(--glass-spec-r, 30px) circle at var(--mx-px, 50%) var(--my-px, 50%), var(--glass-spec)),
    var(--glass-bevel);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
          mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
          mask-composite: exclude;
}
/* The bevel is swapped by redefining the token on the host: ::after inherits it
   and repaints, so the ring's background stack is written once. Falls back to
   the resting bevel wherever no hover value is tuned, which is the light path. */
.cta-glass:hover  { background: var(--glass-tint-hover); box-shadow: var(--glass-shell-hover); --glass-bevel: var(--glass-bevel-hover); }
.cta-glass:active { background: var(--glass-tint-active); transform: scale(0.98); }
.cta-glass:focus-visible {
  box-shadow: var(--glass-shell-focus);
  outline: var(--focus-w, 2px) solid var(--focus-color, var(--glass-ink));
  outline-offset: var(--focus-off, 2px);
}
.cta-glass:disabled, .cta-glass[aria-disabled="true"] {
  opacity: 0.4; cursor: not-allowed; pointer-events: none; transform: none;
}
@supports (corner-shape: superellipse) {
  /* the two lens layers stay concentric with the shell they sit inside */
  .cta-glass, .cta-glass::before, .cta-glass::after { corner-shape: superellipse(1.8); }
}
/* No backdrop-filter, no optical floor: fall back to an opaque control. Both
   lenses live on the pseudos now, so hiding them is what removes the material;
   the shell's own box-shadow carries the edges and it is a complete traced
   control on its own. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .cta-glass { background: var(--glass-opaque); }
  .cta-glass::before, .cta-glass::after { display: none; }
}
@media (prefers-reduced-motion: reduce) {
  /* States still change, they just no longer travel. */
  .cta-glass:active { transform: none; }
  /* Pinned on the pseudo, not on the element: the hook writes --mx-px inline
     on the element, where nothing in a stylesheet can outrank it, but a
     declaration on ::after shadows what the pseudo inherits. */
  .cta-glass::after { --mx-px: 50%; --my-px: 0%; }
}
@media (prefers-reduced-transparency: reduce) {
  /* "Reduced Transparency makes Liquid Glass frostier and obscures more of the
     content behind it": here it goes all the way to opaque. With no lens
     behind them the veil is a grey smear and the specular a white bar, so both
     layers go, and the element's own box-shadow carries the two lit edges and
     the ring. --glass-flat is sized to what the lens renders (#2c2c2e against
     a measured L=0.0282), so the control does not change value when the
     setting is on, only material. */
  .cta-glass { background: var(--glass-flat); backdrop-filter: none; -webkit-backdrop-filter: none; }
  .cta-glass::before, .cta-glass::after { display: none; }
}


/* Token-consuming utility classes (hand-written, not Tailwind-generated) */
.border-subtle  { border-color: var(--border-subtle); }
.border-default { border-color: var(--border-default); }
.border-strong  { border-color: var(--border-strong); }
.bg-surface-0      { background: var(--surface-0); }
.bg-surface-1      { background: var(--surface-1); }
.bg-surface-sunken { background: var(--surface-sunken); }
.text-fg        { color: var(--fg); }
.text-fg-muted  { color: var(--fg-muted); }
.text-fg-faint  { color: var(--fg-faint); }

/* The four header nav links. Registering `fg` in tailwind.config.js is what
   makes `hover:text-fg` exist at all, and it is enough for the four footer
   links and the contact mailto, which measured rgb(168,162,158) in both states
   before and pick up rgb(250,250,249) on hover after. The nav does NOT pick it
   up, because parts.jsx writes `dark:text-stone-300` on the very same element:
   Tailwind emits `.hover\:text-fg:hover` and `.dark\:text-stone-300:is(.dark *)`
   at the SAME specificity (0,2,0) and prints the dark rule last, measured at
   byte 34013 against 41058 in the built sheet, so the resting colour painted
   the hover state too and the link measured rgb(214,211,209) either way. One
   notch of specificity settles it. Scoped to .dark: the Journal pages pull
   this file through content.css and carry no dark class, and the hero's own
   `header.glass.over-hero ... !important` overrides still outrank it over the
   photo, where the nav already had a working hover. */
.dark .hover\:text-fg:hover { color: var(--fg); }

/* Focus indicator for the token-styled form fields (the contact form).
   parts.jsx writes `focus:border-strong` on them and Tailwind never emits it:
   `strong` is not a registered border colour, so focused and resting fields
   were byte-identical. Registering the colour would not fix it either, since
   --border-default -> --border-strong is 0.09 -> 0.16 alpha on a 1px rule:
   invisible, and still short of the 3:1 WCAG 1.4.11 asks of a focus indicator.
   So the state is drawn here instead, with theme-dark.css's focus token trio.
   Fallbacks are for the Journal pages, which pull tokens.css through
   content.css without the dark system. */
.focus\:border-strong:focus {
  outline: var(--focus-w, 2px) solid var(--focus-color, var(--fg));
  outline-offset: var(--focus-off, 2px);
  border-color: var(--focus-color, var(--fg));
}

/* Same trio, for a plain <a>. theme-dark.css draws focus for .link / .nav-link
   / .card-link / .row / .btn-* / .cta-glass and index.html's <style> draws it
   for .focus-ring, but parts.jsx writes none of those on the contact aside's
   mailto, so it fell through to the UA outline: currentColor at rgb(16,16,16),
   invisible on the floor. Those classes are excluded so the ring is never
   drawn twice, and :focus-visible keeps it off a mouse click. Scoped to .dark
   because content.css already rings the Journal's anchors. */
.dark a:focus-visible:not(.focus-ring, .link, .nav-link, .card-link, .row, .btn-primary, .btn-secondary, .cta-glass, .lang-seg) {
  outline: var(--focus-w, 2px) solid var(--focus-color, var(--fg));
  outline-offset: var(--focus-off, 2px);
  border-radius: var(--r-sm, 4px);
}

/* ---------------------------------------------------------------------------
   .cta-glass--lang, the EN / FR switch. One piece of glass, two segments, and
   a selected chip that travels between them.

   ONE SHELL AND NOT TWO CHIPS, and that is forced rather than preferred. The
   lens is a backdrop-filter, an element carrying one IS a backdrop root, and a
   descendant's own backdrop-filter then samples that root instead of the page
   and renders as nothing. Measured on the header bar, see index.html's .glass
   note. So the selected state cannot be a second .cta-glass nested in the
   first. It is paint on the shell: a wash and three inset edges, no filter,
   which is also what Apple means by "glass on glass is a mistake". The
   Journal's toggle (content.css .lang-toggle) IS two separate chips, and it can
   be: those pages have no moving parts, this one slides.

   SELECTED SINKS, and on the dark tuning it sinks by DARKENING, the one place
   this file's "the material gathers light, it never darkens" rule is
   deliberately not followed. That rule governs the LENS. This is a 34px state
   indicator painted on top of it, and the direction is arithmetic rather than
   taste: the primitive holds 4.73:1 at its brightest interior pixel over the
   hero photo, 4.5 being the bar for this text. Any lightening fill under the
   label spends that margin, and --glass-tint-active's rgba(255,255,255,0.18)
   spends all of it, landing the selected label at 3.65:1 on the brightest
   frame. A wash the other way puts it at 6.9:1 instead.

   THE CHIP IS THE ONLY CUE, and that is the same calculation. Muting the
   unselected label is not available: over the brightest hero frame it may not
   drop below 0.88 opacity without failing AA, and 0.88 is not a difference
   anyone sees. Nor is a weight step, Geist ships 400/500 only and 600 would
   synthesize. So both labels stay at full --glass-ink and the chip carries the
   state twice over: the wash reads on a bright ground, the white hairline reads
   on a dark one.
   --------------------------------------------------------------------------- */
.cta-glass--lang {
  /* 30px against the Journal control's 37. This is a setting, not a call to
     action, and it must not compete with the CTA beside it. --rim moves with
     the height or the band becomes a bezel: 2 on 30 is the 3-on-37 ratio. */
  --glass-h: 30px;
  --glass-r: 15px;
  --rim: 2px;
  /* Not a label gutter here: on this control --glass-px is the TRACK INSET, the
     margin the chip keeps around itself on all four sides. */
  --glass-px: 3px;
  --glass-font: 500 12px/1 var(--font-sans, 'Geist', ui-sans-serif, system-ui, -apple-system, sans-serif);
  --glass-track: 0.04em;
  /* Both segments are laid out at a FIXED width rather than flexed, because the
     chip travels exactly one of them: translateX(100%) is only the next segment
     if EN and FR measure the same, and at these letterforms they do not. */
  --lang-seg-w: 34px;
  --lang-sink: rgba(15,15,15,0.09);
  --lang-sink-shell:
    inset 0 1px 2px 0 rgba(15,15,15,0.16),
    inset 0 0 0 1px rgba(255,255,255,0.35);
  gap: 0;
  /* The shell is the group. The segments are the controls, so the hand belongs
     to them and not to the 6px of track between them. */
  cursor: default;
}
.dark .cta-glass--lang {
  --lang-sink: rgba(0,0,0,0.18);
  /* Top shade, lit hairline, bounce along the bottom: a recess with light
     falling into it, not a hole cut in the glass. */
  --lang-sink-shell:
    inset 0 1px 3px 0 rgba(0,0,0,0.30),
    inset 0 0 0 1px rgba(255,255,255,0.16),
    inset 0 -1px 0 0 rgba(255,255,255,0.10);
}
.lang-seg__chip {
  position: absolute;
  top: var(--glass-px); bottom: var(--glass-px); left: var(--glass-px);
  width: var(--lang-seg-w);
  border-radius: calc(var(--glass-r) - var(--glass-px));
  background: var(--lang-sink);
  box-shadow: var(--lang-sink-shell);
  pointer-events: none;
  /* 150ms on the house curve: reversible interaction, so it travels rather than
     cuts, and it is transform-only so the move is compositor work. */
  transition: transform var(--dur-state, 150ms) var(--ease, cubic-bezier(0.16,1,0.3,1));
}
.lang-seg {
  /* Positioned so it paints over the chip, which is the shell's first child. */
  position: relative;
  display: inline-flex; align-items: center; justify-content: center;
  width: var(--lang-seg-w); align-self: stretch;
  border-radius: calc(var(--glass-r) - var(--glass-px));
  color: var(--glass-ink); text-decoration: none;
  cursor: default;
}
a.lang-seg { cursor: pointer; }
/* Inset, because an outside ring on a 30px shell would sit half in the header
   hairline. -3px lands it on the chip's own radius, so the focused segment
   reads as the same object the selection uses. */
.lang-seg:focus-visible {
  outline: var(--focus-w, 2px) solid var(--focus-color, var(--glass-ink));
  outline-offset: -3px;
}
/* The other language does not exist on this page. Present rather than removed,
   so the switch keeps its shape and the site is legibly bilingual, and not
   focusable, because there is nothing to activate: a <span> gets both for free.
   WCAG 1.4.3 exempts a disabled control, which is what pays for the opacity. */
.lang-seg[aria-disabled="true"] { opacity: 0.42; cursor: not-allowed; }
/* index.html shadows every <a> on the bar over the hero and exempts .cta-glass,
   which reaches this shell but not the anchor inside it. That sheet loads AFTER
   this one, so the exemption has to out-specify it rather than follow it. */
header.glass.over-hero .cta-glass--lang .lang-seg { text-shadow: none; }
@media (prefers-reduced-motion: reduce) {
  .lang-seg__chip { transition: none; }
}
/* 30px to the eye, 44 to a finger. The primitive restores --glass-h at coarse
   and that is wrong here: it would make the setting taller than the Journal
   control beside it, which is the hierarchy this switch exists not to break. So
   the height stays and a transparent pad overhangs the shell instead. */
@media (pointer: coarse) {
  .cta-glass--lang { --lang-seg-w: 44px; }
  .lang-seg::after {
    content: ''; position: absolute; left: 0; right: 0;
    top: 50%; height: 44px; transform: translateY(-50%);
  }
}
