/* ==========================================================================
   Delphic shared site header

   One geometry and interaction contract for the landing page, Knowledge
   Index, Answer Objects and reports. The landing and KI use different page
   layout systems; the header deliberately depends on neither.
   ========================================================================== */

/* The shared header survives full-document navigation visually, so its type
   cannot be allowed to swap from a fallback after first paint. Keep the small
   regular Playfair face local and preloaded on every document; `block` prevents
   a fallback wordmark from briefly painting with different metrics. */
@font-face {
  font-family: "Delphic Header Serif";
  src: url("/assets/fonts/delphic-wordmark-playfair.woff2") format("woff2");
  font-style: normal;
  font-weight: 400;
  font-display: block;
}

.site-header {
  --site-header-u: min(1px, calc((100vw - 140px) / 1440));
  display: block !important;
  visibility: visible !important;
  opacity: 1 !important;
  position: fixed !important;
  inset: 0 0 auto !important;
  z-index: 900;
  width: 100% !important;
  max-width: none !important;
  height: calc(84 * var(--site-header-u)) !important;
  overflow: hidden;
  border: 0;
  /* The tint is ALWAYS a layer, never a background-color, and never swapped
     between the two. Previously the landing switched from background-color to
     a ::before layer the moment script.js attached data-tone, which repainted
     the whole bar - and with the logo on its own compositing layer that read
     as the logo flickering (Tarak 2026-07-27). Every state now moves the same
     two variables, so nothing is ever exchanged for anything else. */
  background: transparent;
  -webkit-backdrop-filter: blur(18px) saturate(1.15);
  backdrop-filter: blur(18px) saturate(1.15);
  transform: none !important;
}

.site-header::before {
  content: "";
  position: absolute;
  inset: 0;
  background: color-mix(in srgb, #fff calc(var(--hdr-lum, 1) * 100%), #0b0b0b);
  opacity: var(--hdr-veil, 0.56);
  transition: opacity 140ms linear, background-color 140ms linear;
  pointer-events: none;
}

.site-header > .site-header__frame {
  z-index: 1;
  position: relative;
  width: calc(1440 * var(--site-header-u));
  height: calc(84 * var(--site-header-u)) !important;
  margin: 0 auto;
}

.site-header .site-header__brand {
  position: absolute;
  top: calc(26 * var(--site-header-u));
  left: calc(81 * var(--site-header-u));
  display: inline-flex;
  align-items: center;
  gap: calc(12 * var(--site-header-u));
  color: #333;
  text-decoration: none;
}

.site-header .site-header__brand img {
  display: block;
  width: calc(30 * var(--site-header-u));
  height: calc(22 * var(--site-header-u));
  /* An identity filter, declared on BOTH sides on purpose. The landing drives
     this property continuously, which promotes the mark to its own compositing
     layer; without the same declaration here the Knowledge Index composited it
     differently and the shared logo visibly re-rendered across a navigation
     (Tarak 2026-07-27). */
  filter: invert(0);
}

.site-header .site-header__brand .site-header__wordmark {
  font-family: "Delphic Header Serif", "Playfair Display", Georgia, serif;
  font-size: calc(24 * var(--site-header-u));
  line-height: 1.33;
  letter-spacing: 0.18em;
  background: linear-gradient(90deg, #666 0%, #000 54%);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  color: #000;
}

.site-header .site-header__nav {
  position: absolute;
  top: 0;
  right: calc(66 * var(--site-header-u));
  display: flex;
  align-items: center;
  height: 100%;
}

.site-header .site-header__nav .site-header__index {
  display: inline-flex;
  align-items: center;
  gap: calc(9 * 0.85 * var(--site-header-u));
  padding: calc(6 * 0.85 * var(--site-header-u))
    calc(16 * 0.85 * var(--site-header-u))
    calc(7 * 0.85 * var(--site-header-u));
  border: 1px solid #b5b3ad;
  border-radius: 999px;
  font-family: "Delphic Header Serif", "Playfair Display", Georgia, serif;
  font-size: calc(18 * 0.85 * var(--site-header-u));
  line-height: normal;
  white-space: nowrap;
  color: #000 !important;
  background: transparent;
  text-decoration: none;
  transition: color 180ms ease, background-color 180ms ease, border-color 180ms ease;
}

.site-header .site-header__index .pd {
  position: static;
  flex: 0 0 auto;
  width: calc(9 * 0.85 * var(--site-header-u));
  height: calc(9 * 0.85 * var(--site-header-u));
  background: #000;
  transition: background-color 180ms ease;
}

.site-header .site-header__index:hover {
  border-color: #000;
  color: #fff !important;
  background: #000;
}

.site-header .site-header__index:hover .pd { background: #fff; }

.site-header .site-header__index:focus-visible,
.site-header .site-header__brand:focus-visible {
  outline: 2px solid #000;
  outline-offset: 3px;
}

.site-header.is-over-dark:not([data-tone]),
.ki-machine-world .site-header {
  --hdr-lum: 0;
  --hdr-veil: 0.76;
}

/* On the Knowledge Index the bar changes with the machine pane, so it borrows
   the pane's own 260ms rather than the landing's scroll-speed 140ms. */
.ki-page .site-header::before {
  transition: opacity 260ms ease, background-color 260ms ease;
}

/* Machine-view selectors mirror the BASE rule structure on purpose. The short
   form (.ki-machine-world .site-header__wordmark, 0-2-0) lost to the base
   .site-header .site-header__brand .site-header__wordmark (0-3-0), so in machine
   view the wordmark kept its dark gradient and the pill stayed black-on-dark
   while the panel and logo mark inverted correctly - the mark only escaped
   because its selectors tie at 0-2-1 and source order broke it (Tarak
   2026-07-28). The is-over-dark half never had this problem: :not([data-tone])
   already pushes it to 0-4-0. */
.site-header.is-over-dark:not([data-tone]) .site-header__wordmark,
.ki-machine-world .site-header .site-header__brand .site-header__wordmark {
  background: linear-gradient(90deg, #b9b9b9 0%, #fff 54%);
  -webkit-background-clip: text;
  background-clip: text;
}

.site-header.is-over-dark:not([data-tone]) .site-header__brand img,
.ki-machine-world .site-header .site-header__brand img {
  filter: invert(1);
}

.site-header.is-over-dark:not([data-tone]) .site-header__index,
.ki-machine-world .site-header .site-header__nav .site-header__index {
  border-color: rgba(255, 255, 255, 0.5);
  color: #fff !important;
}

.site-header.is-over-dark:not([data-tone]) .site-header__index .pd,
.ki-machine-world .site-header .site-header__nav .site-header__index .pd {
  background: #fff;
}

.site-header.is-over-dark:not([data-tone]) .site-header__index:hover,
.ki-machine-world .site-header .site-header__nav .site-header__index:hover {
  border-color: #fff;
  color: #000 !important;
  background: #fff;
}

.site-header.is-over-dark:not([data-tone]) .site-header__index:hover .pd,
.ki-machine-world .site-header .site-header__nav .site-header__index:hover .pd {
  background: #000;
}

.site-header.is-over-dark:not([data-tone]) .site-header__index:focus-visible,
.site-header.is-over-dark:not([data-tone]) .site-header__brand:focus-visible,
.ki-machine-world .site-header .site-header__nav .site-header__index:focus-visible,
.ki-machine-world .site-header .site-header__brand:focus-visible {
  outline-color: #fff;
}

/* --- continuous tone (Tarak 2026-07-27) -----------------------------------
   The is-over-dark rules above stay: the Knowledge Index machine world and the
   journey-nav theme toggle both set that class, and it is the correct discrete
   fallback with no JS. But as the ONLY mechanism it made the header snap
   between two definitive states while crossing a black-to-white gradient.

   script.js publishes its luminance sample as --hdr-lum / --hdr-ink /
   --hdr-veil and marks the header data-tone="live". These rules sit after the
   class rules at equal specificity, so the live probe wins wherever it runs and
   nothing changes where it does not. Every value below interpolates: there is
   no threshold anywhere in this block. */

/* The panel itself is declared once, unconditionally, above. data-tone only
   changes what feeds it. */

.site-header[data-tone="live"] .site-header__wordmark {
  background: linear-gradient(90deg,
    color-mix(in srgb, #666 calc(var(--hdr-ink, 1) * 100%), #b9b9b9) 0%,
    color-mix(in srgb, #000 calc(var(--hdr-ink, 1) * 100%), #fff) 54%);
  -webkit-background-clip: text;
  background-clip: text;
}

.site-header[data-tone="live"] .site-header__brand img {
  filter: invert(calc((1 - var(--hdr-ink, 1)) * 100%));
}

.site-header[data-tone="live"] .site-header__index {
  color: color-mix(in srgb, #000 calc(var(--hdr-ink, 1) * 100%), #fff) !important;
  border-color: color-mix(in srgb,
    #b5b3ad calc(var(--hdr-ink, 1) * 100%), rgb(255 255 255 / 0.5));
}

.site-header[data-tone="live"] .site-header__index .pd {
  background: color-mix(in srgb, #000 calc(var(--hdr-ink, 1) * 100%), #fff);
}

/* hover inverts against whatever the pill currently is */
.site-header[data-tone="live"] .site-header__index:hover {
  background: color-mix(in srgb, #000 calc(var(--hdr-ink, 1) * 100%), #fff);
  border-color: color-mix(in srgb, #000 calc(var(--hdr-ink, 1) * 100%), #fff);
  color: color-mix(in srgb, #fff calc(var(--hdr-ink, 1) * 100%), #000) !important;
}

.site-header[data-tone="live"] .site-header__index:hover .pd {
  background: color-mix(in srgb, #fff calc(var(--hdr-ink, 1) * 100%), #000);
}

.site-header[data-tone="live"] .site-header__index:focus-visible,
.site-header[data-tone="live"] .site-header__brand:focus-visible {
  outline-color: color-mix(in srgb, #000 calc(var(--hdr-ink, 1) * 100%), #fff);
}

.ki-page { padding-top: calc(84 * min(1px, calc((100vw - 140px) / 1440))); }

@media (max-width: 900px) {
  .site-header {
    position: relative !important;
    inset: auto !important;
    height: 84px !important;
    --hdr-lum: 1;
    --hdr-veil: 1;
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }

  .site-header > .site-header__frame {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    height: 84px !important;
    padding: 22px 20px 18px;
  }

  /* 44px hit area inside a 36px content box. sections.css:635 already asks
     for min-height:44px on .hdr .brand, but both selectors are specificity
     (0,2,0) and this file loads later, so 36px silently won and the brand
     measured 139x36. The negative block margin buys the missing 8px as touch
     target without moving the wordmark inside the 84px header. */
  .site-header .site-header__brand {
    position: static;
    min-height: 44px;
    margin-block: -4px;
    gap: 9px;
  }

  .site-header .site-header__brand img {
    width: 28px;
    height: 22px;
  }

  /* Match the desktop selector's specificity. The shorter selector lost to
     `.site-header .site-header__brand .site-header__wordmark`, leaving the
     mobile wordmark tied to --site-header-u and rendering it at ~4px. */
  .site-header .site-header__brand .site-header__wordmark {
    font-size: 19px;
    letter-spacing: 0.16em;
  }

  .site-header .site-header__nav { display: none; }
  .ki-page { padding-top: 0; }
  .ki-machine-world .site-header { --hdr-lum: 0; --hdr-veil: 1; }
}

@media (max-width: 900px) and (max-height: 620px) {
  .site-header,
  .site-header > .site-header__frame {
    height: 60px !important;
  }

  .site-header > .site-header__frame {
    padding-top: 14px;
    padding-bottom: 11px;
  }
}

/* --- KI machine-view tone: animate a NUMBER (Tarak 2026-07-28) -------------
   The human/machine swap snapped because only the ::before panel had a
   transition; the wordmark, logo, pill and dot had none and flipped at t=0
   while the background dissolved behind them. Re-timing WHEN the class lands
   can never fix parts that do not animate.

   --ki-tone is a KI-ONLY registered number (0 human, 1 machine) and IT
   transitions; the colours below are computed from it, so every part moves
   together. Deliberately NOT --hdr-ink: registering that variable stops
   color-mix() accepting it, and the landing's scroll-driven tone is built on
   11 color-mix declarations that read it - registering it globally is exactly
   what broke the landing logo over dark sections earlier today.

   Arithmetic rather than color-mix for the same reason: a registered property
   cannot be a color-mix percentage. */
@property --ki-tone {
  syntax: "<number>";
  inherits: true;
  initial-value: 0;
}

.ki-page .site-header {
  --ki-tone: 0;
  transition: --ki-tone 240ms ease;
}

.ki-machine-world .site-header { --ki-tone: 1; }

.ki-page .site-header .site-header__brand img {
  filter: invert(calc(var(--ki-tone) * 100%));
}

.ki-page .site-header .site-header__brand .site-header__wordmark {
  background: linear-gradient(90deg,
    rgb(calc(102 + 83 * var(--ki-tone)) calc(102 + 83 * var(--ki-tone)) calc(102 + 83 * var(--ki-tone))) 0%,
    rgb(calc(255 * var(--ki-tone)) calc(255 * var(--ki-tone)) calc(255 * var(--ki-tone))) 54%);
  -webkit-background-clip: text;
  background-clip: text;
}

.ki-page .site-header .site-header__nav .site-header__index {
  color: rgb(calc(255 * var(--ki-tone)) calc(255 * var(--ki-tone)) calc(255 * var(--ki-tone))) !important;
  border-color: rgb(
    calc(181 + 74 * var(--ki-tone))
    calc(179 + 76 * var(--ki-tone))
    calc(173 + 82 * var(--ki-tone))
    / calc(1 - 0.5 * var(--ki-tone)));
}

.ki-page .site-header .site-header__nav .site-header__index .pd {
  background: rgb(calc(255 * var(--ki-tone)) calc(255 * var(--ki-tone)) calc(255 * var(--ki-tone)));
}

/* The pill and dot must NOT run their own colour transitions on KI pages.
   Their colour is already derived from --ki-tone, which animates; a second
   240ms transition on top tries to chase every intermediate value and stalls,
   leaving the pill sitting at its old colour. This is what made it look like
   the pill "would not interpolate" - it was two animations fighting, not a
   cascade failure. (Diagnosed 2026-07-28: an inline `rgb(255 255 255)
   !important` also read back as black, which no cascade can do - it was the
   transition returning the start value.) */
.ki-page .site-header .site-header__nav .site-header__index,
.ki-page .site-header .site-header__nav .site-header__index .pd {
  transition: none;
}

/* Hover inverts against whatever tone has arrived. Required because the
   tone-derived colour above is (0-4-0) + !important and outranks the base
   hover rule at (0-3-0) - so the pill's background flipped to black while its
   text stayed black, and the label became unreadable on both the KI index
   ("The Full Story") and every answer object ("Our Knowledge Index")
   (Tarak 2026-07-28). Regression from the --ki-tone change earlier today.

   text = 255 * (1 - tone)  -> white on a light page, black on a dark one
   fill = 255 * tone        -> the colour the text just had */
.ki-page .site-header .site-header__nav .site-header__index:hover,
.ki-page .site-header .site-header__nav .site-header__index:focus-visible {
  color: rgb(calc(255 * (1 - var(--ki-tone))) calc(255 * (1 - var(--ki-tone))) calc(255 * (1 - var(--ki-tone)))) !important;
  background: rgb(calc(255 * var(--ki-tone)) calc(255 * var(--ki-tone)) calc(255 * var(--ki-tone)));
  border-color: rgb(calc(255 * var(--ki-tone)) calc(255 * var(--ki-tone)) calc(255 * var(--ki-tone)));
}

.ki-page .site-header .site-header__nav .site-header__index:hover .pd,
.ki-page .site-header .site-header__nav .site-header__index:focus-visible .pd {
  background: rgb(calc(255 * (1 - var(--ki-tone))) calc(255 * (1 - var(--ki-tone))) calc(255 * (1 - var(--ki-tone))));
}
