/* ═══════════════════════════════════════════════════════════════
   GOLDFINGER · header common law · one file, every forum
   ───────────────────────────────────────────────────────────────
   Canonical copy lives at 00_canonical/. Each site root holds a
   byte-identical copy. Never edit a site copy: edit here and
   redistribute, or the six rooms drift apart again.

   The estate grew four header naming patterns before this file
   existed. BILS, AIO and gbxcircle use .gbx-header / .gbx-mark /
   .gbx-key / .gbx-cta. CGTI and DDIF use .hdr / .hdr-mark /
   .hdr-key / .hdr-cta. MEVO uses .hdr-cta with .key-glyph. SCLI
   uses .hdr with .mark / .lx-key-eye / .hcta. Rather than rewrite
   four sites' markup, this file binds the one choreography to all
   four sets of hooks.

   Requires: goldfinger-tokens.css for --gold, --gold-hover, --ease
   Pairs with: goldfinger-header-common.js which drives the classes
   ═══════════════════════════════════════════════════════════════ */

/* ── 1 · the CTA carries no underline ────────────────────────────
   .gbx-cta never set text-decoration. The component only reset it
   on .gbx-nav a, so the browser default underlined every "request
   access" link on BILS, CGTI, DDIF, MEVO and SCLI. AIO and
   gbxcircle had it right, which is why it read as a per-site quirk
   rather than a missing line in the shared component.
   !important is deliberate here and in section 2: this file has to
   win over seven sites of legacy page CSS whose load order varies. */
.gbx-cta, .gbx-cta:link, .gbx-cta:visited, .gbx-cta:hover, .gbx-cta:focus,
.hdr-cta, .hdr-cta:link, .hdr-cta:visited, .hdr-cta:hover, .hdr-cta:focus,
.hcta,    .hcta:link,    .hcta:visited,    .hcta:hover,    .hcta:focus,
.gbx-cta a, .hdr-cta a, .hcta a {
  text-decoration: none !important;
  border-bottom: 0 !important;
}

/* ── 2 · no hairline under the header ────────────────────────────
   The full-width rule under the header read as a seam between the
   header and the room rather than as structure. The header now
   separates by ground and by blur on scroll, which is quieter and
   holds at every width. Hairlines elsewhere on the page are
   untouched: this removes the header's own bottom edge only. */
header.gbx-header, header.hdr, .gbx-header, .hdr,
header.gbx-header.gbx-scrolled, header.hdr.scrolled,
.gbx-header.gbx-scrolled, .hdr.scrolled,
.gbx-header[data-mode="light"], .hdr[data-mode="light"] {
  border-bottom: 0 !important;
}

/* ═══ 3 · MOTION ═══ choreography: load -> ambient -> arrival -> hover -> idle
   Timing is the BILS index reference: eye blink 6s, key turn 6s
   offset 3.6s, load 1.2s. Every forum now runs the same clock. */

.gbx-mark svg, .gbx-mark img,
.hdr-mark svg, .hdr-mark img,
.hdr .mark img, .hdr-brand svg, .hdr-brand img {
  transform-origin: 50% 50%;
  will-change: transform, opacity;
}
.gbx-key, .hdr-key, .key-glyph, .lx-key-eye,
.gbx-cta svg, .hdr-cta svg, .hcta svg {
  transform-origin: 50% 27%;
  will-change: transform;
}
.gbx-key .pupil, .hdr-key .pupil, .key-glyph .pupil {
  transform-box: fill-box;
  transform-origin: center;
}

@keyframes gbxOpen      { from{opacity:0;transform:scale(.5) rotate(-14deg)} to{opacity:1;transform:none} }
@keyframes gbxKeyLoad   { 0%{transform:rotate(0);opacity:1} 42%{transform:rotate(90deg);opacity:0} 60%{transform:rotate(0);opacity:0} 100%{transform:rotate(0);opacity:1} }
@keyframes gbxBlink     { 0%,92%,100%{transform:scaleY(1)} 96%{transform:scaleY(.06)} }
@keyframes gbxBlinkSlow { 0%,90%,100%{transform:scaleY(1)} 95%{transform:scaleY(.06)} }
@keyframes gbxKeyTurn   { 0%,84%,100%{transform:rotate(0)} 92%{transform:rotate(90deg)} }
@keyframes gbxKeyPupil  { 0%,100%{opacity:1} 50%{opacity:.32} }
@keyframes gbxPop       { 0%{transform:scale(1)} 45%{transform:scale(1.14)} 100%{transform:scale(1)} }
@keyframes gbxUnlock    { 0%{transform:rotate(0)} 40%{transform:rotate(-16deg)} 100%{transform:rotate(0)} }

@media (prefers-reduced-motion: no-preference) {

  /* page load · "you are admitted" */
  html.gbx-booting .gbx-mark svg,  html.gbx-booting .gbx-mark img,
  html.gbx-booting .hdr-mark svg,  html.gbx-booting .hdr-mark img,
  html.gbx-booting .hdr .mark img, html.gbx-booting .hdr-brand svg {
    animation: gbxOpen .9s var(--ease, cubic-bezier(.2,.7,.2,1)) both;
  }
  html.gbx-booting .gbx-key, html.gbx-booting .hdr-key,
  html.gbx-booting .key-glyph, html.gbx-booting .lx-key-eye {
    animation: gbxKeyLoad 1.2s var(--ease, cubic-bezier(.2,.7,.2,1)) both;
  }

  /* ambient · "we are present" · the key never stops */
  html.gbx-ambient .gbx-mark svg,  html.gbx-ambient .gbx-mark img,
  html.gbx-ambient .hdr-mark svg,  html.gbx-ambient .hdr-mark img,
  html.gbx-ambient .hdr .mark img, html.gbx-ambient .hdr-brand svg {
    animation: gbxBlink 6s ease-in-out infinite;
  }
  html.gbx-ambient .gbx-key, html.gbx-ambient .hdr-key,
  html.gbx-ambient .key-glyph, html.gbx-ambient .lx-key-eye {
    animation: gbxKeyTurn 6s var(--ease, cubic-bezier(.2,.7,.2,1)) infinite;
    animation-delay: -3.6s;
  }
  html.gbx-ambient .gbx-key .pupil, html.gbx-ambient .hdr-key .pupil,
  html.gbx-ambient .key-glyph .pupil {
    animation: gbxKeyPupil 3.6s ease-in-out infinite;
  }

  /* idle 10s · "waiting, unhurried" · the eye slows, the key does not */
  html.gbx-ambient.gbx-idle .gbx-mark svg,  html.gbx-ambient.gbx-idle .gbx-mark img,
  html.gbx-ambient.gbx-idle .hdr-mark svg,  html.gbx-ambient.gbx-idle .hdr-mark img,
  html.gbx-ambient.gbx-idle .hdr .mark img, html.gbx-ambient.gbx-idle .hdr-brand svg {
    animation: gbxBlinkSlow 9s ease-in-out infinite;
  }

  /* section arrival · "this room opens" */
  .gbx-header.gbx-arrive .gbx-mark svg, .gbx-header.gbx-arrive .gbx-mark img,
  .hdr.gbx-arrive .hdr-mark svg, .hdr.gbx-arrive .hdr-mark img,
  .hdr.gbx-arrive .mark img, .hdr.gbx-arrive .hdr-brand svg {
    animation: gbxPop .55s var(--ease, cubic-bezier(.2,.7,.2,1));
  }
  .gbx-header.gbx-arrive .gbx-key, .hdr.gbx-arrive .hdr-key,
  .hdr.gbx-arrive .key-glyph, .hdr.gbx-arrive .lx-key-eye {
    animation: gbxUnlock .55s var(--ease, cubic-bezier(.2,.7,.2,1));
  }

  /* hover on the CTA · "step forward" */
  .gbx-header:has(.gbx-cta:hover) .gbx-mark svg,
  .gbx-header:has(.gbx-cta:hover) .gbx-mark img,
  .hdr:has(.hdr-cta:hover) .hdr-mark svg,
  .hdr:has(.hdr-cta:hover) .hdr-mark img,
  .hdr:has(.hdr-cta:hover) .hdr-brand svg,
  .hdr:has(.hcta:hover) .mark img {
    animation: none;
    transform: scale(1.12);
  }
  .gbx-header:has(.gbx-cta:hover) .gbx-key,
  .hdr:has(.hdr-cta:hover) .hdr-key,
  .hdr:has(.hdr-cta:hover) .key-glyph,
  .hdr:has(.hcta:hover) .lx-key-eye {
    animation: none;
    transform: rotate(90deg);
    color: var(--gold-hover, #cda861);
    filter: drop-shadow(0 0 7px rgba(186,153,51,.55));
  }
}

@media (prefers-reduced-motion: reduce) {
  .gbx-mark svg, .gbx-mark img, .gbx-key,
  .hdr-mark svg, .hdr-mark img, .hdr-key,
  .hdr .mark img, .hdr-brand svg, .key-glyph, .lx-key-eye {
    animation: none !important;   /* resting state */
  }
}

/* ═══════════════════════════════════════════════════════════════════════
   MEDIA CONTROLS · one sound control, every forum
   ─────────────────────────────────────────────────────────────────────
   Measured 2026-09-13: eleven hero videos across the estate, and the
   sound control existed on one of them, bils/index. Carousel videos told
   the same story. BILS wired 8 pages with data-snd and .snd-toggle. CGTI,
   DDIF, MEVO and AIO had none on any page, so 26 pages played footage a
   visitor could not hear and could not ask to hear.

   The markup lived in the pages, which is why it never spread. It lives
   here now, next to the header it ships with, so a page gets the control
   by loading the kit rather than by being edited.

   Values are BILS's, verbatim. This is a port, not a redesign.
   ═══════════════════════════════════════════════════════════════════════ */

.snd-toggle, .hero-sound {
  position: absolute; z-index: 30;
  background: rgba(17,22,22,.55);
  border: .5px solid rgba(186,153,51,.2);
  color: rgba(243,246,249,0.52);
  font-family: var(--sans, 'Jost', system-ui, sans-serif);
  font-size: 8px; letter-spacing: .16em; text-transform: uppercase;
  font-weight: 300; padding: 8px 14px; cursor: pointer;
  display: flex; align-items: center; gap: 8px;
  transition: all .2s; backdrop-filter: blur(4px);
}
.snd-toggle { bottom: 18px; right: 18px; }
.hero-sound { bottom: var(--sp4, 21px); right: var(--sp5, 34px); z-index: 10; }

.snd-toggle:hover, .hero-sound:hover {
  color: var(--cashmere, #F3F6F9);
  border-color: rgba(186,153,51,.45);
}
.snd-toggle:focus-visible, .hero-sound:focus-visible {
  outline: 1px solid var(--gold, #ba9933); outline-offset: 3px;
}

/* A carousel video answers a click. The cursor has to say so before the
   click, not after. Set by script only where the click is ours to take:
   a video inside a link belongs to the link. */
video.gbx-clickable { cursor: pointer; }

/* ═══════════════════════════════════════════════════════════════════════
   ORGANISATION MARQUEE · the scrolling logo strip
   ─────────────────────────────────────────────────────────────────────
   Measured 2026-09-13: SCLI carried this on 9 of 10 pages and CGTI and
   MEVO had it nowhere. It was page CSS, which is why it never travelled.

   Values are SCLI's verbatim. The spacing reads from each forum's own
   tokens, so it keeps that forum's rhythm rather than importing SCLI's:
   --sp5 is 55px on CGTI and 34px on MEVO, and both are correct there.

   The track holds the logo list TWICE. slide moves it -50%, so the
   second copy is exactly where the first began and the loop has no seam.
   Removing the duplicate list breaks the loop, not just the length.
   ═══════════════════════════════════════════════════════════════════════ */

.marquee {
  overflow: hidden; position: relative; z-index: 2;
  border-top: 0.5px solid var(--g2, rgba(186,153,51,0.236));
  border-bottom: 0.5px solid var(--g2, rgba(186,153,51,0.236));
  padding: var(--sp5, 34px) 0;
}
.track {
  display: flex; width: max-content;
  gap: var(--sp7, 89px);
  animation: gbx-marquee 46s linear infinite;
}
.track img {
  height: 26px; width: auto;
  filter: brightness(0) invert(1);
  opacity: .42;
  transition: opacity .3s var(--ease, cubic-bezier(.22,1,.36,1));
}
.track img:hover { opacity: .85; }

@keyframes gbx-marquee { from { transform: translateX(0) } to { transform: translateX(-50%) } }

/* A strip that never stops is the exact thing this media query exists
   for. It holds at the start rather than jumping to a random offset. */
@media (prefers-reduced-motion: reduce) {
  .track { animation: none; }
}

/* ═══════════════════════════════════════════════════════════════════════
   TAP TARGETS · 44 by 44, without redrawing a single mark
   ─────────────────────────────────────────────────────────────────────
   171 findings at 375 across five forums: footer socials at 28x28, the
   header burger at 22x14, the mark at 30x30, lockups, hamburgers.
   Every one is an icon control small enough to miss with a thumb.

   THE MARKS DO NOT GET BIGGER. The estate's restraint is the point, and
   a 44px gold square in a footer would be a different design.

   Each control becomes a 44x44 BOX. What is drawn stays its own size,
   either because it is a child element that keeps its dimensions, or
   because the visible border moves to ::before. A negative margin pulls
   the layout footprint back to what it was, so nothing moves on the
   page: margin shrinks the space an element occupies, never the element,
   so the hit area and getBoundingClientRect stay 44x44.

   !important because the inline <style> block loads after this file.
   Measured, not assumed: see the load order in any forum index. */

/* footer socials. Two markups across the estate for the same control:
   .fsoc at 28x28 on five forums, and an unclassed `.soc a` at 30x30 on
   SCLI. Both are a bordered square holding a one or two letter glyph. */
.soc a {
  width: 44px !important; height: 44px !important;
  border: 0 !important;
  margin: -7px !important;
  position: relative;
  display: flex !important; align-items: center; justify-content: center;
}
.soc a::before {
  content: ''; position: absolute; top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  width: 30px; height: 30px;
  border: 0.5px solid var(--g2, rgba(186,153,51,0.236));
  transition: border-color .2s;
  pointer-events: none;
}
.soc a:hover::before { border-color: var(--gold, #ba9933); }

/* .fsoc · the 28x28 bordered square is drawn by ::before */
.fsoc {
  width: 44px !important; height: 44px !important;
  border: 0 !important;
  margin: -8px !important;
  position: relative;
  display: flex !important; align-items: center; justify-content: center;
}
.fsoc::before {
  content: ''; position: absolute; top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  width: 28px; height: 28px;
  border: 0.5px solid var(--g2, rgba(186,153,51,0.236));
  transition: border-color .2s;
  pointer-events: none;
}
.fsoc:hover::before { border-color: var(--gold, #ba9933); }

/* header mark and lockup · the child keeps its own size
   ─────────────────────────────────────────────────────────────────────
   SECOND TIME THIS RULE HAS SHIPPED A BUG, and the same mistake twice.
   It pinned the container to a FIXED 44px and forced EVERY child to
   30x30. On CGTI and DDIF the brand is .hdr-brand, so nothing happened.
   On MEVO the brand IS .hdr-mark and it holds the mark AND the wordmark,
   so the container was capped at 44px wide and the word "mevo" was
   squashed into a 30x30 box. Patrick saw it as a header that did not
   match the others.

   A tap target rule may GROW A BOX. It may not cap one, it may not
   decide display, and it may not resize what is inside. The 30x30 now
   names the mark itself, img svg picture, and leaves text alone.

   The forced display stays here, unlike on the burger, because .hdr-mark
   and .gbx-lockup are never hidden by any page in the estate. Checked
   across every page and stylesheet on 2026-09-14, not assumed. */
.hdr-mark, .gbx-lockup {
  min-width: 44px !important; min-height: 44px !important;
  margin: -7px !important;
  display: flex !important; align-items: center;
}
.hdr-mark > img, .hdr-mark > svg, .hdr-mark > picture,
.gbx-lockup > img, .gbx-lockup > svg, .gbx-lockup > picture {
  width: 30px; height: 30px; flex-shrink: 0;
}

/* burgers and hamburgers · the bars keep their size, the box grows
   ─────────────────────────────────────────────────────────────────────
   THIS RULE CARRIED "display: flex !important" AND IT SHIPPED A BUG.
   Every forum hides its burger at desktop with .hdr-burger{display:none}
   and un-hides it inside a mobile media query. An !important display
   beats both, at every width, so on 2026-09-14 all six production sites
   showed the mobile hamburger in the desktop header. On DDIF it sits
   inline in the nav, so it read as a stray white bar beside "the
   conversation". Patrick saw it before any gate did.

   A tap target rule may only GROW A BOX. It must never decide whether an
   element exists. align-items and justify-content are inert unless the
   page has already made it a flex box, which the mobile rule does, so
   the centring still applies exactly where it is wanted. */
.hdr-burger, .burger, .gbx-hamburger {
  min-width: 44px !important; min-height: 44px !important;
  align-items: center; justify-content: center;
  margin: -11px -8px !important;
  background: none; border: 0;
}
.hdr-burger > span, .gbx-hamburger > span { width: 22px; }

/* A skip link is visually hidden until it takes focus, so it is not a
   thumb target in normal use. It still gets the box, because when it IS
   focused it is the first thing a keyboard or switch user lands on. */
.gbx-skip:focus, .gbx-skip:focus-visible {
  min-width: 44px; min-height: 44px;
  display: inline-flex; align-items: center; justify-content: center;
}

/* ═══════════════════════════════════════════════════════════════════════
   THE REVEAL · PART 24 section 05, "In the room"
   ─────────────────────────────────────────────────────────────────────
   Ruled geometry: tile by tile, 90ms apart, capped at six steps. The
   engine was pasted into 45 pages and missing from ten, which is how the
   Curated for grids shipped static on five. It belongs in the kit.

   SCOPED TO .gf-reveal on purpose. Forty-five pages carry their own .rev
   rules and their own observer. This adds a resting state to nothing they
   own, and the kit observer only ever ADDS .in, which is what their own
   observers already do. Convergent, never conflicting.

   THE RESTING STATE HIDES, SO IT IS GATED ON THE SCRIPT. html.gf-rev-on
   is written by the kit JS. Without JS the class never lands and every
   cell renders visible. A reveal that fails closed is invisible content,
   and this estate has shipped invisible content before.
   ═══════════════════════════════════════════════════════════════════════ */
/* MEASURED 2026-09-14 AND UNIFIED. This block ran .5s on --ease over 8px
   while .rev ran .72s on --ease-enter over 14px, so the Curated for grids
   entered on a different motion from every other section in the estate.
   Two staggers is correct and ruled, a section ladder and a 90ms grid
   sweep. Two ENTRANCE motions is drift.
   The transition now comes from the one component below. Only the stagger
   is this block's own, written per tile by the kit JS. */
html.gf-rev-on .gf-reveal > .in { opacity: 1; transform: none; }

/* ═══════════════════════════════════════════════════════════════════════
   THE LIGHT REGISTER AND THE MOTION CURVE · defaults, not overrides
   ─────────────────────────────────────────────────────────────────────
   Measured 2026-09-14. BILS reads var(--gold-ink) nine times and
   var(--gold-lit) nine times and declares neither. DDIF the same.
   gbxcircle reads --ink eight times, --ink-body six and --gold-ink
   eight, and declares none of them.

   An unresolved var() is invalid at computed-value time, so
   "--gold: var(--gold-ink)" on a light island does not fall back, it
   UNSETS the rebinding and the island keeps the dark gold. CURRENT LAW
   2026-09-09 rules gold is never text on light and #ba9933 measures
   2.21:1 on linen. That protection has been inert on two forums. The
   same shape unlit the dark islands on SCLI in September.

   WHY :where() AND NOT :root. This stylesheet is linked BELOW the page's
   own <style> on every property, line 825 on bils index. A plain :root
   here would WIN on equal specificity and silently overwrite the
   per-forum values CGTI and SCLI already tuned to their own grounds.
   :where() has zero specificity, so any page declaration beats it
   whatever the source order. Defaults, never overrides.

   VALUES ARE FROM INSIDE THE ESTATE. #7e6418, #141414, 0.72 and 0.66 are
   the CGTI and SCLI declarations and the CURRENT LAW table. Nothing here
   comes from the Fable kit, and NO TYPE TOKEN IS DECLARED HERE. The type
   sequence is 17 / 15 / 10 and it is not this file's business.

   --ink-body and --ink-dim default to the --deep rgb. A forum that wants
   its own ground tint declares it locally, as CGTI and SCLI do.
   ═══════════════════════════════════════════════════════════════════════ */
:where(:root) {
  --ink:       #141414;
  --ink-body:  rgba(21, 19, 19, 0.72);
  --ink-dim:   rgba(21, 19, 19, 0.66);
  --gold-ink:  #7e6418;
  --gold-lit:  var(--gold);
  --ease:      cubic-bezier(.2, .7, .2, 1);
  /* the lockup tracking. Declared on 18 pages and absent on MEVO,
     which is why its wordmark fell back to an invented value. */
  --ls-mark:   0.40em;
}

/* ═══════════════════════════════════════════════════════════════════════
   THE REVEAL COMPONENT · .rev · ONE animation, estate wide
   ─────────────────────────────────────────────────────────────────────
   Measured 2026-09-14, before this existed. The reveal was pasted into
   56 pages and had become NINE different animations:

     16 pages  translateY(14px) .72s cubic-bezier(.22,1,.36,1)
      9 pages  translateY(24px) .7s ease
      7 pages  translateY(26px) .9s ease
      8 pages  opacity:0 and NO transition at all, so the element POPS
     15 pages  resting at opacity:1, so they never fade, only slide
      1 page   transform:none;transition:none, switched off entirely
   and two delay ladders, .12/.25/.38/.52 against .1/.2/.3/.4.

   That is not drift around one rule. Several pages had no fade and one
   had no reveal. The house motion signature did not exist.

   THE VALUES ARE THE ESTATE'S OWN DOMINANT ONES, not a new invention.
   translateY(14px), .72s and cubic-bezier(.22,1,.36,1) are the most
   declared geometry, and .12/.25/.38/.52 is the most declared ladder.
   The opacity:1 resting states are treated as the defect they are: a
   reveal that does not reveal.

   TWO CURVES, TWO JOBS. --ease-enter is the entrance curve, an ease out
   expo that settles long. --ease is the interaction curve for hover and
   state. They were competing as one, 85 declarations against 41. They
   are not rivals, they do different work.

   THE RESTING STATE HIDES, SO IT IS GATED ON html.gf-rev-on, written by
   the kit JS. No script, no class, everything renders visible. This
   estate has shipped invisible content before.
   ═══════════════════════════════════════════════════════════════════════ */
:where(:root) { --ease-enter: cubic-bezier(.22, 1, .36, 1); }

html.gf-rev-on .rev,
html.gf-rev-on .rv,
html.gf-rev-on .reveal,
html.gf-rev-on .gf-reveal > * {
  opacity: 0;
  transform: translateY(14px);
  transition: opacity .72s ease,
              transform .72s var(--ease-enter, cubic-bezier(.22, 1, .36, 1));
}
html.gf-rev-on .rev.in,      html.gf-rev-on .rev.visible,
html.gf-rev-on .rv.in,       html.gf-rev-on .rv.visible,
html.gf-rev-on .reveal.in,   html.gf-rev-on .reveal.visible { opacity: 1; transform: none; }

/* THREE VOCABULARIES, ONE COMPONENT. .rev on 612 elements, .rv on 112,
   .reveal on 66, and two lit-state classes, .in and .visible. They are
   the same idea named three times. The kit answers to all of them so no
   page has to be re-marked, which is the cheap half of the migration.
   Re-marking 178 elements onto .rev is the tidy half and is not worth a
   regression today.

   SCLI'S REVEAL WAS DEAD. index.html declared .rv at opacity:0 on line
   245 and again at opacity:1;transform:none on line 263. The later rule
   won, on all nine pages. 112 elements were marked to reveal and none
   did. That override is what an emergency looks like when a reveal
   fails closed and somebody turns it off rather than gates it. The kit
   gates it on html.gf-rev-on instead, so it cannot fail closed. */

html.gf-rev-on .d1 { transition-delay: .12s; }
html.gf-rev-on .d2 { transition-delay: .25s; }
html.gf-rev-on .d3 { transition-delay: .38s; }
html.gf-rev-on .d4 { transition-delay: .52s; }

@media (prefers-reduced-motion: reduce) {
  html.gf-rev-on .rev, html.gf-rev-on .rv, html.gf-rev-on .reveal,
  html.gf-rev-on .gf-reveal > *,
  html.gf-rev-on .d1, html.gf-rev-on .d2,
  html.gf-rev-on .d3, html.gf-rev-on .d4 {
    opacity: 1; transform: none; transition: none; transition-delay: 0s;
  }
}

/* ═══════════════════════════════════════════════════════════════════════
   THE HEADER BAR · transparent on entry, a scrim once you scroll
   ─────────────────────────────────────────────────────────────────────
   Taken from aiocircle.com, which Patrick named as correct on
   2026-09-15. Measured off the live .lx-header rather than invented:
     entry   background rgba(0,0,0,0) · no blur · transparent border
     scroll  ground at .86 · blur(16px) saturate(1.1) · gold hairline
     move    background .4s, border-color .4s, backdrop-filter .4s

   WHY THIS WAS THE LAST PIECE OF DRIFT. The kit owned tokens, the mark
   animation, media controls, the reveal and lazy video, and it styled
   the header bar with ZERO rules. Every site owned its own, so seven
   properties ran four different entry behaviours:
     AIO SCLI   transparent, then a scrim. Correct.
     CGTI DDIF  a scrim from the first frame
     MEVO       toggles the class, nothing responds
     BILS GBX   FULLY OPAQUE at entry and translucent on scroll, which
                is backwards, and is the hard edge over the BILS film
   It ships the gbx-scrolled hook and nothing ever answered it. This is
   the answer.

   THE GROUND COMES FROM THE FORUM. var(--ground) means BILS scrims warm
   and SCLI pine without a per-site rule. --g2 is the one hairline.

   HEIGHT IS NOT SET HERE. Seven properties run 52, 68, 89, 89, 98, 102
   and 131. That is a separate ruling and changing it moves the first
   frame of every site.
   ═══════════════════════════════════════════════════════════════════════ */
.gbx-header, .hdr, .lx-header {
  background: rgba(0, 0, 0, 0) !important;
  backdrop-filter: none !important;
  -webkit-backdrop-filter: none !important;
  border-bottom: 1px solid rgba(0, 0, 0, 0) !important;
  transition: background .4s var(--ease, cubic-bezier(.2, .7, .2, 1)),
              border-color .4s var(--ease, cubic-bezier(.2, .7, .2, 1)),
              backdrop-filter .4s var(--ease, cubic-bezier(.2, .7, .2, 1)) !important;
}

.gbx-header.gbx-on-light, .hdr.gbx-on-light, .lx-header.gbx-on-light,
.gbx-header.gbx-scrolled, .hdr.gbx-scrolled, .lx-header.gbx-scrolled {
  /* the solid ground first, for anything without color-mix. That is what
     these headers already served, so the fallback is today's behaviour. */
  background: var(--ground, #151313) !important;
  background: color-mix(in srgb, var(--ground, #151313) 86%, transparent) !important;
  backdrop-filter: blur(16px) saturate(1.1) !important;
  -webkit-backdrop-filter: blur(16px) saturate(1.1) !important;
  border-bottom: 1px solid var(--g2, rgba(186, 153, 51, .236)) !important;
}

/* A header that is transparent at entry has to SIT OVER the film, not
   above it. BILS and gbxcircle are sticky, so they hold their own space
   and the hero starts below them, which would show the page floor in the
   gap rather than the footage. */
.gbx-header { position: fixed !important; top: 0; left: 0; right: 0; }

@media (prefers-reduced-motion: reduce) {
  .gbx-header, .hdr, .lx-header { transition: none !important; }
}

/* ═══════════════════════════════════════════════════════════════════════
   THE HEADER · size, sub-header and position · AIO's, ruled estate wide
   ─────────────────────────────────────────────────────────────────────
   Proven on BILS first, approved by Patrick 2026-09-15, then bibled here.
   Values measured off live aiocircle.com at 1440x900, not invented.

     bar      padding 21px 89px · justify-content space-between
     nav      centred between the lockup and the CTA
     item     12px · 300 · .12em · lowercase · padding 22px 0
     panel    14px 0 · blur(18px) · items .14em

   12px, NOT AIO's 10px. Patrick ruled it up for an older readership and
   the reason is x-height, not nominal size. The three house faces measure
   0.52 Helvetica Neue, 0.46 Jost, 0.39 Cormorant, so the same number
   renders three different sizes. Jost at 10px puts only 4.6px of ink on
   screen. 12px gives 5.52, a fifth more, and still sits at 63 percent of
   body copy at 17px Helvetica Neue, which measures 8.77. 16 or 17px would
   have been 84 to 89 percent and the navigation would have competed with
   the argument. WCAG sets no minimum font size; the 16px convention is
   for body copy, which this estate already meets.

   CENTRING NEEDS THE AUTO MARGINS, not space-between alone. .gbx-nav
   carried a fixed margin-left that pinned it beside the lockup while the
   CTA carried margin-left:auto and ate the rest. Auto on both sides of
   the nav centres it BETWEEN the brand and the CTA, which is what AIO
   does: its nav centre sits at 689 on a 1440 page, 31px left of true
   centre, for exactly that reason.

   THREE VOCABULARIES. .gbx-* on BILS and gbxcircle, .hdr with .nav-top
   and .nav-dd on CGTI, DDIF and MEVO, and bare .ni and .dd on SCLI. All
   keyed, and the SCLI ones scoped under .hdr so a bare .dd elsewhere on a
   page is never touched.

   MOBILE IS BIBLE AND IS NOT TOUCHED. Everything sits above 900px. Below
   it every site keeps the height, padding, drawer and arrangement it has
   today. Measured before and after on all six.
   ═══════════════════════════════════════════════════════════════════════ */
@media (min-width: 901px) {

  .gbx-header, .hdr {
    padding: 21px 89px !important;
    justify-content: space-between !important;
    /* CGTI pinned height:89px and MEVO and SCLI pin their own. With
       border-box that caps the bar no matter what the padding says, which
       is why the first pass left 107 / 89 / 89 / 68 / 68 standing with
       every other value already identical. The bar sizes to what it
       holds: 21 + 65 + 21. */
    height: auto !important;
  }

  .gbx-nav, .hdr-nav, .hdr > .nav {
    margin-left: auto !important;
    margin-right: auto !important;
  }
  .gbx-cta, .hdr-cta, .hdr-req { margin-left: 0 !important; }

  .gbx-nav-top, .nav-top, .hdr .ni > a {
    font-size: 12px !important;
    letter-spacing: .12em !important;
    /* VERTICAL ONLY. This is what makes the bar one height: the padding
       on the bar is the same everywhere but the item inside it was not,
       22px on BILS, 20 on DDIF, 17 on CGTI and MEVO, none on SCLI. That
       is where the 107 / 89 / 89 / 68 / 68 spread came from, not the bar.
       Horizontal is left alone: CGTI and MEVO carry a 26px right padding
       that spaces their items, and wiping it would collide them. */
    padding-top: 22px !important;
    padding-bottom: 22px !important;
  }

  /* SCLI ONLY, and scoped deliberately. Its nav links carry no class and
     are inline, where vertical padding does not affect layout: its nav
     measured 21px tall while its own items measured 62, which is why it
     sat at 68 when the other four reached 107.
     BLANKET display:block WAS WRONG AND MEASURED SO. BILS took it and
     went 107 to 120, because .gbx-nav-top.gated is a flex box holding the
     key glyph beside the label and block dropped the glyph onto its own
     line. The four that already compute block need nothing. */
  .hdr .ni > a { display: block !important; }

  .gbx-nav-dd, .nav-dd, .hdr .dd {
    padding: 14px 0 !important;
    backdrop-filter: blur(18px) !important;
    -webkit-backdrop-filter: blur(18px) !important;
  }
  .gbx-nav-dd a, .nav-dd a, .hdr .dd a { letter-spacing: .14em !important; }
}
