/* Shared docs-site chrome: classic docs layout — sticky sidebar (brand,
 * page navigation, theme toggle) + content column. Linked by every docs
 * page after /core.css, before the page's own <style>, so page styles can
 * override. Page-specific styles live in the pages; fixture pages are
 * test-only and do not link this.
 *
 * Platform features (2026-10-02): CSS Grid and
 * position:sticky — direct use, floors (Chrome 58/91, FF 54/59,
 * Safari 10.1/13) far above the .browserslistrc matrix; narrow screens get
 * a single-column layout from the mobile-first defaults. */

/* Cross-document view transitions (2026-10-29):
 * same-origin page navigations crossfade instead of flashing white.
 * Progressive enhancement: Chrome/Edge 126+, Safari 18.2+; engines without
 * the at-rule ignore it and navigate instantly (Firefox has Level 1 only —
 * no cross-document transitions). No named elements: the JS-rendered
 * sidebar can be absent at the new page's first paint (the deferred
 * site-sidebar.js runs after it), and a named element missing on one side
 * renders its transition layer blank — the "sidebar disappears" flash.
 * Reduced motion: transition frames are drawn via ::view-transition-*
 * pseudo-elements, outside the token motion system — disabled here. */
@view-transition {
  navigation: auto;
}

@media (prefers-reduced-motion: reduce) {
  ::view-transition-group(*),
  ::view-transition-image-pair(*),
  ::view-transition-old(*),
  ::view-transition-new(*) {
    animation: none !important;
  }
}

:root {
  /* Fixed site header height (docs-local layout constant, not a token):
   * offsets the page below the header and clips the sticky sidebar/TOC
   * underneath it. */
  --site-header-size: 3.5rem;
  /* Smooth in-page anchor scrolling; anchors stop below the fixed header
   * instead of flush at the viewport edge. */
  scroll-behavior: smooth;
  scroll-padding-block-start: calc(var(--site-header-size) + 0.5rem);
}

/* Fixed site header across the viewport: brand left; GitHub link, theme
 * toggle and (narrow screens only) the drawer hamburger right
 * (site-sidebar.js). On wide screens the header renders inside the sticky
 * <site-sidebar>, whose stacking context would trap the header at z:auto
 * tree order — later stacking contexts (the timeline marker's z-index
 * pseudo, the indeterminate circle progress's transform animation) painted
 * above it. The sidebar carries the z-index that raises the whole chrome;
 * on narrow screens the header is a direct child of <body>'s flow and
 * raises itself. Overlays and dialogs still top above both via the top
 * layer. */
.site-header {
  position: fixed;
  z-index: 10;
  inset-block-start: 0;
  inset-inline: 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--ui-space-md);
  block-size: var(--site-header-size);
  padding-inline: var(--ui-space-lg);
  background: var(--ui-color-surface);
  border-block-end: 1px solid var(--ui-color-border);
}

/* Navigation sidebar only (brand and toggle live in the fixed header). */
site-sidebar {
  margin-block-end: var(--ui-space-xl);
}

.site-brand {
  font-size: 1.125rem;
  font-weight: 600;
  color: var(--ui-color-text);
  text-decoration: none;
}

/* Header clusters: brand + version badge on the left, GitHub link and
 * theme toggle on the right (the header itself is space-between). */
.site-header-start,
.site-header-end {
  display: flex;
  align-items: baseline;
  gap: var(--ui-space-sm);
  min-block-size: 0;
}

.site-header-end {
  align-items: center;
}

/* The Octicon rides the button font size; spacing comes from .ui-button's
 * built-in flex gap. */
.site-header-end .site-github-mark {
  inline-size: 1em;
  block-size: 1em;
}

.site-nav ul {
  display: flex;
  flex-wrap: wrap;
  gap: var(--ui-space-2xs) var(--ui-space-sm);
  margin: 0;
  padding: 0;
  list-style: none;
}

.site-nav a {
  display: block;
  padding: var(--ui-space-2xs) var(--ui-space-sm);
  border-radius: var(--ui-radius-sm);
  color: var(--ui-color-text);
  text-decoration: none;
}

.site-nav a:hover,
.site-nav a[aria-current='page'] {
  background: var(--ui-color-hover);
}

.site-nav a[aria-current='page'] {
  font-weight: 600;
}

/* Group headings (overline style): one per .site-nav section, rendered by
 * site-sidebar.js. Sections are separated by the core-styled <hr>, whose
 * margins provide all the spacing around a heading — the heading itself
 * adds none. */
.site-nav h2 {
  /* Link text starts at the same inset (links carry the hover background
   * out to the edge, headings align with the text). */
  padding-inline: var(--ui-space-sm);
  font: 600 var(--ui-font-size-xs) / 1.4 var(--ui-font-sans);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ui-color-text-muted);
}

/* Mobile navigation drawer: the nav element itself is the drawer host —
 * site-sidebar.js renders the links a second time with ui-drawer +
 * popover (top layer, light dismiss, Escape — zero JS). The close button
 * docks right; the list is vertical, like the grid sidebar on wide
 * screens. */
.site-drawer-head {
  display: flex;
  justify-content: flex-end;
  margin-block-end: var(--ui-space-md);
}

.ui-drawer.site-nav ul {
  flex-direction: column;
  flex-wrap: nowrap;
}

body {
  max-inline-size: 60rem;
  margin-block: 0;
  margin-inline: auto;
  /* Clear the fixed site header. */
  padding-block-start: var(--site-header-size);
  padding-inline: var(--ui-space-lg);
}

/* Bottom air belongs to the central column, not the body (it would pad
 * every grid column). Every docs page ends with <footer>; the only page
 * without one is the test-only fixture, which does not load this file. */
footer {
  padding-block-end: 8rem;
}

/* Page title block, first child of <main> (static markup — renders without JS). */
.page-header {
  margin-block: 0 var(--ui-space-xl);
}

.page-header p {
  color: var(--ui-color-text-muted);
  font-size: var(--ui-font-size-lg);
}

/* Demo containers: a pre-style border groups the demoed components into a
 * well; hatched backdrop distinguishes demos from the page itself
 * (backdrop experiments: dots, grids, SVG masks, 2026-10-24/25). */
.example {
  --line-color: color-mix(in oklch, var(--ui-color-border) 25%, var(--ui-color-surface) 75%);
  margin-block: var(--ui-space-md);
  padding: var(--ui-space-lg);
  border: 1px solid var(--ui-color-border);
  border-radius: var(--ui-radius-md);
  background-size: 0.75rem 0.75rem;
  background-image: repeating-linear-gradient(
    -45deg,
    var(--line-color) 0,
    var(--line-color) 1px,
    transparent 0,
    transparent 50%
  );
}

/* Docs-page section rhythm: air between sections; core keeps UA margins
 * (layout is host concern). Section-level spacing, not heading-level —
 * headings inside demos (dialog, drawer) are unaffected. */
main > section {
  margin-block-start: 6rem;
}

/* Syntax highlighting (highlight.js, vendor/hljs.min.js). Theme on --ui-*
 * tokens, one rule set for both themes: keyword = link utility, string =
 * text, literal/number = text-muted, comment = muted. Only the classes the
 * registered languages (xml/css/javascript/bash/json) actually emit. */
.hljs-comment,
.hljs-quote {
  color: var(--ui-color-text-muted);
  font-style: italic;
}

.hljs-keyword,
.hljs-selector-tag,
.hljs-tag,
.hljs-name,
.hljs-doctag,
.hljs-meta {
  color: var(--ui-color-link);
}

.hljs-string,
.hljs-regexp,
.hljs-addition {
  color: var(--ui-color-text);
}

.hljs-number,
.hljs-literal,
.hljs-built_in,
.hljs-builtin-name,
.hljs-symbol {
  color: var(--ui-color-text-muted);
}

.hljs-attr,
.hljs-attribute,
.hljs-variable,
.hljs-template-variable,
.hljs-type,
.hljs-selector-class,
.hljs-selector-id,
.hljs-selector-attr,
.hljs-selector-pseudo {
  color: var(--ui-color-attention);
}

.hljs-title,
.hljs-title.class_,
.hljs-title.function_,
.hljs-section {
  color: var(--ui-color-link);
  font-weight: 600;
}

.hljs-deletion {
  color: var(--ui-color-attention);
}

.hljs-emphasis {
  font-style: italic;
}

.hljs-strong {
  font-weight: 600;
}

/* Narrow screens: the header actions collapse to icon squares (the label
 * spans return on wide screens), the hamburger appears, and the nav moves
 * into the drawer — the in-flow copy would duplicate it. */
@media (width < 72rem) {
  .site-nav-toggle {
    display: inline-flex;
  }

  .site-header-end .ui-button:has(.site-button-label) {
    /* Square geometry around the 1rem mark, like the core icon size. */
    padding-inline: calc((2.25rem - 1rem) / 2);
  }

  .site-button-label {
    display: none;
  }

  site-sidebar > .site-nav:not(.ui-drawer) {
    display: none;
  }
}

@media (min-width: 72rem) {
  body {
    display: grid;
    grid-template-columns: 16rem minmax(0, 48rem) 14rem;
    gap: 0 var(--ui-space-2xl);
    justify-content: center;
    max-inline-size: none;
  }

  /* The drawer trigger only exists for the narrow layout. */
  .site-nav-toggle {
    display: none;
  }

  main,
  footer {
    grid-column: 2;
  }

  /* TOC column: renders only where the page supplies h2 sections; an empty
   * custom element stays collapsed (display: none on :empty). */
  site-toc {
    display: none;
  }

  site-toc:not(:empty) {
    position: sticky;
    /* Stick below the fixed header, not under it. */
    top: var(--site-header-size);
    grid-column: 3;
    grid-row: 1;
    align-self: start;
    display: block;
    max-block-size: calc(100vh - var(--site-header-size));
    overflow: auto;
    font-size: var(--ui-font-size-sm);
    /* Overflow clips at the padding box: keep enough room for the
     * focus ring (2px outline + 2px offset) not to be cut at the edges. */
    padding-block: var(--ui-space-xl) var(--ui-space-xs);
    padding-inline: var(--ui-space-xs);
  }

  site-toc h2 {
    margin-block: 0 var(--ui-space-sm);
    font: 600 var(--ui-font-size-sm) / 1.45 var(--ui-font-sans);
    color: var(--ui-color-text-muted);
  }

  site-toc ul {
    margin: 0;
    padding: 0;
    list-style: none;
    /* Anchor links in the list act as scroll markers: the link to the
     * section currently in view matches :target-current. Progressive
 * enhancement (2026-10-25): Chrome/Edge 140+;
     * engines without support render a plain TOC. */
    scroll-target-group: auto;
  }

  site-toc li + li {
    margin-block-start: var(--ui-space-2xs);
  }

  site-toc a {
    color: var(--ui-color-text-muted);
    text-decoration: none;
  }

  site-toc a:hover {
    color: var(--ui-color-text);
  }

  site-toc a:target-current {
    color: var(--ui-color-text);
    font-weight: 600;
  }

  site-sidebar {
    position: sticky;
    /* Sticky always creates a stacking context: without a z-index the whole
     * chrome (the fixed header included) paints at z:auto tree order, before
     * <main> — stacking contexts in the content covered the header. */
    z-index: 10;
    /* Stick below the fixed header, not under it. */
    top: var(--site-header-size);
    grid-column: 1;
    grid-row: 1 / span 2;
    align-self: start;
    /* Fit between the header and the viewport bottom; the nav scrolls
     * inside what doesn't fit (24 pages of links exceed one screen).
     * border-box: the core sets no global box-sizing, and with the default
     * content-box the padding pushed the scrollbar below the viewport. */
    box-sizing: border-box;
    max-block-size: calc(100vh - var(--site-header-size));
    overflow: auto;
    /* Thin scrollbar: the nav's inner scroll is secondary chrome; engines
     * below the feature floor keep the default width (compatibility.md). */
    scrollbar-width: thin;
    margin-block-end: 0;
    padding-block: var(--ui-space-lg);
    /* Overflow clips at the padding box: keep room on both sides for the
     * focus ring (2px outline + 2px offset) not to be cut at the edges. */
    padding-inline: var(--ui-space-xs);
  }

  .site-nav ul {
    flex-direction: column;
    flex-wrap: nowrap;
    gap: var(--ui-space-2xs);
  }
}

/* ---- Palette widget (site-palette.js) — inline on the Colors page,
 * dogfooding the token system it customizes. ---- */

.palette-fieldset {
  display: grid;
  gap: var(--ui-space-2xs);
  margin: 0 0 var(--ui-space-md);
  padding: var(--ui-space-sm);
  border: 1px solid var(--ui-color-border);
  border-radius: var(--ui-radius-md);
}

.palette-slider {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 0.125rem var(--ui-space-sm);
  font-size: var(--ui-font-size-sm);
}

.palette-slider input {
  grid-column: 1 / -1;
  accent-color: var(--ui-color-brand);
}

.palette-slider output {
  font-variant-numeric: tabular-nums;
  color: var(--ui-color-text-muted);
}

.palette-actions {
  display: flex;
  gap: var(--ui-space-sm);
}

/* Sticky palette actions: the host is a direct child of <main> (a section
 * would bound the sticky range to itself), so the bar pins below the fixed
 * header for the rest of the page and Reset / Copy CSS stay on view while
 * the families below are tuned. Surface background: content scrolls under
 * it once pinned; painted above static content like the fixed header. */
/* Sticky palette actions: the host is the last child of <main> (sticky is
 * bounded by its parent), so with bottom:0 the bar pins to the viewport
 * bottom for the whole page scroll and docks into the flow at the end of
 * the content. Surface background and a top hairline: content scrolls
 * beneath it while pinned. */
site-palette-actions {
  display: block;
  position: sticky;
  bottom: 0;
  background: var(--ui-color-surface);
  padding-block: var(--ui-space-lg);
  border-block-start: 1px solid var(--ui-color-border);
}

.palette-table {
  inline-size: 100%;
  margin-block-end: var(--ui-space-lg);
  border-collapse: collapse;
  font-size: 11px;
  font-variant-numeric: tabular-nums;
}

.palette-table th,
.palette-table td {
  padding: 0.2rem 0.25rem;
  border-block-end: 1px solid var(--ui-color-border);
  text-align: left;
}

.palette-table code {
  font-size: 10px;
}

.palette-pill {
  display: inline-block;
  min-inline-size: 2.25rem;
  padding: 0 0.375rem;
  border-radius: 999px;
  font-size: 10px;
  text-align: center;
}

/* Status colors are widget chrome (not token-covered roles) — same fixed
 * pair as the .experiments/adaptive-colors prototype. */
.palette-pill[data-status='pass'] {
  background: oklch(90% 0.12 150);
  color: oklch(30% 0.1 150);
}

.palette-pill[data-status='fail'] {
  background: oklch(90% 0.12 25);
  color: oklch(30% 0.12 25);
}
