/*
 * Behavioural base layer. Tailwind's preflight already handles the reset —
 * this file only carries body defaults, the glass surface recipe and its
 * mandatory fallbacks, focus visibility, reduced-motion/-transparency, and
 * a couple of small utility classes that don't belong in Tailwind config.
 *
 * Every value here must be a token reference (var(...)). Raw hex/px/ms
 * literals are enforced out by test/lint/css_token_lint_test.rb.
 */

/*
 * Establish the cascade-layer order before Tailwind's build declares its own.
 * Rules below sit in `components` so single-purpose utilities (bg-*, rounded-*,
 * shadow-*) can still override a surface class on the same element.
 */
@layer theme, base, components, utilities;

@layer components {

body {
  font-family: var(--font-sans);
  color: var(--color-ink);
  background: var(--color-bg);
  font-size: var(--text-sm);
  line-height: var(--text-sm--line-height);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/*
 * Glass surface recipe — the single mixin every card/panel uses.
 *
 * `backdrop-filter` is not only a paint effect: a non-`none` value makes the
 * element the containing block for its `position: fixed` descendants and the
 * root of a stacking context, so anything fixed inside a glass card resolves
 * its coordinates against the card and cannot be painted outside it. Overlays
 * that need the viewport have to leave via the top layer rather than fixed
 * positioning — see popover_controller.js#promoteToTopLayer and
 * `.skip-link.is-demo` below.
 */
.surface-glass {
  background: var(--color-surface);
  backdrop-filter: blur(var(--glass-blur));
  -webkit-backdrop-filter: blur(var(--glass-blur));
  border: 1px solid var(--color-border-glass);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-xs);
}

/* Inset variant — inputs, chips, avatar frames inside cards. */
.surface-inset {
  background: var(--color-surface-inset);
  backdrop-filter: blur(var(--glass-blur-sm));
  -webkit-backdrop-filter: blur(var(--glass-blur-sm));
}

/*
 * Stacked glass (spec §1.7): any glass surface on another glass surface drops
 * the translucency — stacked blur turns to mud and costs paint time.
 */
.surface-glass .surface-glass {
  background: var(--color-surface-solid);
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}

.surface-glass .surface-inset {
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}

/* Mandatory fallback: no backdrop-filter support → solid fills, zero blur. */
@supports not (backdrop-filter: blur(1px)) {
  .surface-glass {
    background: var(--color-surface-solid);
  }

  .surface-inset {
    background: var(--color-surface-inset-solid);
  }
}

/*
 * .perf-lite — toggled on <body> by the perf-lite Stimulus controller when
 * navigator.hardwareConcurrency <= 4. Collapses the blur to 0 and swaps
 * glass fills for their solid equivalents, matching the @supports fallback.
 */
.perf-lite {
  --glass-blur: 0px;
  --glass-blur-sm: 0px;
}

.perf-lite .surface-glass {
  background: var(--color-surface-solid);
}

.perf-lite .surface-inset {
  background: var(--color-surface-inset-solid);
}

@media (prefers-reduced-transparency: reduce) {
  body {
    --glass-blur: 0px;
    --glass-blur-sm: 0px;
  }

  .surface-glass {
    background: var(--color-surface-solid);
  }

  .surface-inset {
    background: var(--color-surface-inset-solid);
  }
}

/*
 * Focus visibility — one treatment, everywhere (spec §4.1). Focus is never
 * removed; :focus-visible carries the aesthetics.
 *
 * --focus-halo is a documented hook: filled controls set
 * `box-shadow: var(--focus-halo)` on their own :focus-visible rule so the
 * ring reads against both canvas and glass, without every component
 * re-deriving the halo value.
 */
:root {
  --focus-halo: 0 0 0 4px var(--color-accent-ring);
}

/*
 * Deviation from spec §4.1's literal `border-radius: inherit`: on the focused
 * element itself, `inherit` takes the PARENT's radius and visibly reshapes the
 * control on focus. Outlines already follow the element's own border-radius in
 * every modern browser, which is what the spec intends.
 */
:focus-visible {
  outline: 2px solid var(--color-accent-pressed);
  outline-offset: 2px;
}

/* Reduced motion (spec §4.5) — verbatim. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/*
 * .force-reduced-motion — styleguide interaction toggle (spec §5.3/5.4).
 * Duplicates the prefers-reduced-motion query above verbatim so reviewers
 * can force the reduced-motion state without changing OS settings.
 */
.force-reduced-motion *, .force-reduced-motion *::before, .force-reduced-motion *::after {
  animation-duration: 0.01ms !important;
  animation-iteration-count: 1 !important;
  transition-duration: 0.01ms !important;
  scroll-behavior: auto !important;
}

/*
 * .force-zoom-200 — styleguide interaction toggle (spec §5.3/5.4). Scoped to
 * the showcase content only (not the toolbar itself) so reviewers can
 * eyeball "no horizontal scroll at 200%" without the toggle row itself
 * ballooning out of reach.
 */
.force-zoom-200 .styleguide-content {
  zoom: 2;
}

/*
 * .keyboard-hint-mode — styleguide interaction toggle (spec §5.3/5.4).
 * Outlines every focusable element so keyboard-only navigation can be
 * eyeballed. Outline only — deliberately no tab-order numbering, since CSS
 * counters follow DOM order rather than actual tab order (tabindex can
 * reorder it), so numbering would be dishonest.
 */
.keyboard-hint-mode a[href],
.keyboard-hint-mode button,
.keyboard-hint-mode input,
.keyboard-hint-mode select,
.keyboard-hint-mode textarea,
.keyboard-hint-mode summary,
.keyboard-hint-mode [tabindex]:not([tabindex="-1"]) {
  outline: 2px dashed var(--color-violet);
  outline-offset: 2px;
}

.numeric-tabular {
  font-variant-numeric: var(--numeric-tabular);
}

/* [hidden] must win over author display values (e.g. inline-grid on buttons) — the UA default alone is too weak to override component display rules */
[hidden],
.is-share-unsupported {
  display: none !important;
}

/* Visually hidden until focused, then a fixed pill top-left, tokens only. */
.skip-link {
  position: fixed;
  top: var(--space-2);
  left: var(--space-2);
  z-index: var(--z-toast);
  transform: translateY(-200%);
  padding: var(--space-2) var(--space-4);
  border-radius: var(--radius-pill);
  background: var(--color-surface-solid);
  color: var(--color-accent-pressed);
  box-shadow: var(--shadow-md);
  transition: transform var(--duration-fast) var(--ease-out);
}

.skip-link:focus {
  transform: translateY(0);
}

/*
 * Styleguide-only forced state: a fixed-position skip link inside a glass card
 * gets its containing block hijacked by backdrop-filter, so demos render it
 * statically instead.
 */
.skip-link.is-demo {
  position: static;
  transform: none;
}

/* Form column cap (spec §3.2, standing rule 4) — form cards never exceed 640px. */
.form-column {
  max-width: var(--form-column);
}

} /* @layer components */
