/* ==========================================================================
   base.css - element defaults, landmarks, and the four layout primitives.

   Element rules are wrapped in :where() wherever a component might reasonably
   need to override them, so they carry zero specificity and the cascade stays
   predictable: a class ALWAYS beats a default here. Global invariants that must
   never be overridden (focus, reduced motion, [hidden]) are written at normal
   specificity on purpose.
   ========================================================================== */

*,
*::before,
*::after {
  box-sizing: border-box;
}

:where(body, h1, h2, h3, h4, p, figure, blockquote, dl, dd, ul, ol, pre) {
  margin: 0;
}

:where(ul, ol) {
  padding-left: 1.25em;
}

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* Anchored sections must clear the sticky header. */
  scroll-padding-top: calc(var(--header-h) + var(--sp-6));
}

body {
  min-height: 100vh;
  background: var(--bg);
  color: var(--fg);
  font-family: var(--font-sans);
  font-size: var(--step-1);
  font-weight: 400;
  line-height: var(--lh-body);
  font-optical-sizing: auto;
  text-rendering: optimizeLegibility;
}

/* ---- headings ----------------------------------------------------------- */

:where(h1, h2, h3, h4) {
  color: var(--fg-strong);
  line-height: var(--lh-head);
  text-wrap: balance;
}

:where(h1) {
  font-size: var(--step-4);
  font-weight: 900;
  letter-spacing: var(--track-display);
  line-height: var(--lh-display);
}

:where(h2) {
  font-size: var(--step-3);
  font-weight: 800;
  letter-spacing: var(--track-head);
}

:where(h3) {
  font-size: var(--step-2);
  font-weight: 700;
  letter-spacing: var(--track-sub);
}

:where(h4) {
  font-size: var(--step-1);
  font-weight: 600;
  letter-spacing: var(--track-sub);
}

:where(p) {
  text-wrap: pretty;
}

:where(strong, b) {
  font-weight: 600;
  color: var(--fg-strong);
}

/* No italic file is shipped; <em> falls back to a synthesised oblique. */
:where(em, i) {
  font-style: italic;
}

/* ---- links -------------------------------------------------------------- */

:where(a) {
  color: inherit;
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
  text-decoration-color: var(--border-strong);
  transition: text-decoration-color var(--dur-fast) var(--ease);
}

:where(a:hover) {
  text-decoration-color: var(--gold);
  text-decoration-thickness: 2px;
}

/* ---- media -------------------------------------------------------------- */

:where(img, svg, video) {
  display: block;
  max-width: 100%;
}

:where(img) {
  height: auto;
}

/* ---- code --------------------------------------------------------------- */

:where(code, pre, samp, kbd) {
  font-family: var(--font-mono);
  font-size: .875em;
  font-variant-numeric: tabular-nums;
}

/* ---- forms -------------------------------------------------------------- */

:where(button, input, select, textarea) {
  font: inherit;
  color: inherit;
}

:where(button) {
  cursor: pointer;
  background: none;
  border: 0;
  padding: 0;
}

:where(hr) {
  height: 1px;
  border: 0;
  background: var(--border);
  margin: var(--sp-8) 0;
}

::selection {
  background: var(--gold-solid);
  color: var(--on-accent);
}

/* ==========================================================================
   Global invariants - normal specificity, deliberately.
   ========================================================================== */

/* Visible focus everywhere, never removed. The 2px corner is applied at zero
   specificity so a pill or a card keeps its own radius while focused. */
:focus-visible {
  outline: var(--focus-ring);
  outline-offset: var(--focus-offset);
}

:where(:focus-visible) {
  border-radius: var(--r-xs);
}

/* JS may set [hidden] on the nav; nothing in this stylesheet may out-specify it.
   hidden="until-found" is DELIBERATELY excluded. It is a different feature wearing the
   same attribute: the UA rule is `content-visibility: hidden`, which keeps the element
   in the box tree so find-in-page can still reach the text, fire `beforematch` and
   expand the row. `display: none !important` out-specifies that and switches the
   mechanism off - which silently broke the cheatsheet filter's whole Ctrl+F guarantee
   (plan section 8.8): 272 of 308 symbols became unfindable the moment anyone typed in
   the box, with both files looking correct in isolation. */
[hidden]:not([hidden="until-found" i]) {
  display: none !important;
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ==========================================================================
   Layout primitives - used by every page including the stubs.
   ========================================================================== */

.wrap {
  width: 100%;
  max-width: var(--wrap);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

/* Monospace numerals. The shared primitive for anything that reads as a figure:
   tabular so a column of them lines up. The prose measure is NOT a class - it is
   `max-width: var(--measure)` applied per component, which is why there is no
   .measure anywhere in this file. */

.skip-link {
  position: absolute;
  left: var(--sp-2);
  top: var(--sp-2);
  z-index: 100;
  transform: translateY(-150%);
  padding: var(--sp-3) var(--sp-5);
  background: var(--gold-solid);
  color: var(--on-accent);
  font-weight: 600;
  letter-spacing: var(--track-ui);
  border-radius: var(--r-md);
  text-decoration: none;
  transition: transform var(--dur-fast) var(--ease);
}

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

/* Screen-reader-only text. The `left/top` pair is not cosmetic and must not be dropped:
   without an offset the element keeps its STATIC position, and its containing block is
   whatever is positioned above it - usually nothing, i.e. the initial containing block.
   Placed inside an `overflow-x: auto` box it then escapes that box's clip and reports
   a position measured from the page's left edge, so a 1px invisible span sitting 984px
   along a scrolling <pre> extended the whole document's scrollable width and the PAGE
   scrolled sideways at 375px and 768px. Anchoring it removes that whole class of bug.
   Reading order is DOM order for assistive tech, so the offset changes nothing else. */
.visually-hidden {
  position: absolute;
  left: 0;
  top: 0;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* The skip link is a keyboard affordance and there is no keyboard on paper. It lived
   in the cheatsheet's print block; it belongs beside .skip-link. */
@media print {
  .skip-link { display: none; }
}
