/* ============================================================================
 * site/styles/base.css — global primitives
 * Cascade position 2 of 5 (tokens → base → components → sections → responsive).
 *
 * PUBLISH ROOT: `site/` is the only publishable directory in this repository.
 * Nothing here may reference the private research directories, the
 * repository-root legacy page, the older landing seeds, or the raw design
 * deliveries. All paths inside `site/` are relative.
 *
 * CONTRACT
 * - Carries NO token values. `styles/tokens.css` is the sole token carrier;
 *   everything below references a role through `var()`.
 * - Owns document-level primitives only: reset, document surface, typographic
 *   defaults, link and focus behavior, the skip link, the layout utilities the
 *   shell needs.
 * - Component anatomy belongs in `components.css`; section layout belongs in
 *   `sections.css`; per-width behavior belongs in `responsive.css`.
 * - Loaded before `components.css`, so any component rule of equal specificity
 *   wins over a primitive here.
 *
 * The literals in this file that are NOT design values — `0`, `100%`, `none`,
 * and the `1px` and `inset(50%)` of the visually-hidden clip technique — are
 * structural CSS mechanics with no token role, alongside the plain CSS keywords
 * (`auto`, `inherit`, `border-box`, `nowrap`, `block`, `absolute`). No colour,
 * size, radius, shadow, duration or spacing value is written literally.
 *
 * OWNERSHIP: Task 02 creates it; Tasks 04–05 add section needs; Task 06 owns
 * final responsive/accessibility hardening.
 * ========================================================================= */

/* --- runtime step aliases --------------------------------------------------
 * Desktop-first defaults. `responsive.css` re-points these to the accepted
 * `-tablet` / `-mobile` roles at each breakpoint, so no rule below has to be
 * duplicated per width and no width value is ever hard-coded outside a media
 * query condition. These are references, not values. */
:root {
  --page-gutter: var(--gutter);
  --page-section-y: var(--section-y);
  --page-card-pad: var(--card-pad);
  --page-band-inset: var(--band-inset);
  --page-h1-size: var(--text-h1-size);
  --page-h2-size: var(--text-h2-size);

  /* Fragment landing offset. `site-header` is the sticky element, so a bare
   * `#id` jump would park the target's first content under it. This alias is
   * the header's own maximum block size at each step, composed from spacing
   * roles rather than restated as a literal, and `responsive.css` re-points it
   * with the other aliases. */
  --page-header-offset: calc(var(--space-12) + var(--space-2));
}

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

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

ul,
ol {
  padding: 0;
}

/* Lists used as layout containers lose their marker; content lists in prose
 * re-declare their own. */
ul[class],
ol[class] {
  list-style: none;
}

/* --- document ------------------------------------------------------------- */
/* `scroll-padding` on the root element applies to the viewport scrollport, so
 * every owned same-page anchor — and the skip link, whose target takes focus —
 * lands clear of the sticky header instead of behind it. It is layout, not
 * motion: no smooth-scroll behavior is declared, so a reduced-motion visitor
 * and a visitor with JavaScript off both get the same corrected landing. */
html {
  -webkit-text-size-adjust: 100%;
  scroll-padding-block-start: var(--page-header-offset);
}

body {
  min-height: 100%;
  background-color: var(--surface-bone);
  color: var(--text-primary);
  font-family: var(--font-sans);
  font-size: var(--text-body-size);
  font-weight: var(--weight-regular);
  line-height: var(--text-body-lh);
  letter-spacing: var(--tracking-normal);
  -webkit-font-smoothing: antialiased;
}

/* Product-story fixtures deliberately contain dense rows. Their local clips
 * may scroll, but no decorative vector or rail may widen the document. */
main {
  overflow-x: clip;
}

/* --- typographic defaults -------------------------------------------------
 * Discrete token steps, never `clamp()`, so the three evidence widths are
 * exactly reproducible. Heading levels are never skipped and there is exactly
 * one `h1` on the page. */
h1,
h2,
h3,
h4 {
  font-family: var(--font-display);
  font-weight: var(--weight-bold);
  color: var(--text-primary);
}

h1 {
  font-size: var(--page-h1-size);
  line-height: var(--text-h1-lh);
  letter-spacing: var(--tracking-display);
}

h2 {
  font-size: var(--page-h2-size);
  line-height: var(--text-h2-lh);
  letter-spacing: var(--tracking-display);
}

h3 {
  font-size: var(--text-h3-size);
  line-height: var(--text-h3-lh);
  letter-spacing: var(--tracking-heading);
}

h4 {
  font-size: var(--text-h4-size);
  line-height: var(--text-tight-lh);
  letter-spacing: var(--tracking-heading);
}

/* --- links ---------------------------------------------------------------- */
a {
  color: inherit;
  text-decoration-thickness: var(--focus-width);
  text-underline-offset: var(--focus-offset);
  transition: color var(--duration-fast) var(--ease-standard);
}

a:hover,
a:active {
  color: var(--accent-strong);
}

/* --- focus ----------------------------------------------------------------
 * Every focusable element shows the ring. It is never removed, never animated,
 * and never relies on a colour change alone: the ring is a 2px band that
 * appears where nothing was drawn before, so it is a shape change first and a
 * colour second. `--focus-ring-on-ink` is applied by the ink-surface rules in
 * `components.css`; `--focus-ring` measures 17.23:1 on `--surface-bone` and
 * 16.80:1 on `--surface-cream`, `--focus-ring-on-ink` 16.41:1 on
 * `--surface-ink` and 17.40:1 on `--surface-ink-panel`.
 *
 * `--focus-offset` deliberately draws the ring OUTSIDE the control's own box,
 * so it is measured against the surface behind the control rather than against
 * the control's fill, and no fill change can reduce it. Nothing in this
 * stylesheet or any later one sets `outline: none` on a focusable element. */
:focus-visible {
  outline: var(--focus-width) var(--focus-style) var(--focus-ring);
  outline-offset: var(--focus-offset);
}

/* --- replaced content ----------------------------------------------------- */
img,
svg,
video {
  display: block;
  max-width: 100%;
  height: auto;
}

/* --- tabular data ---------------------------------------------------------
 * Fixture rows that are genuinely tabular ship as a real `table`, so the
 * collapsed border model is a document primitive rather than a component
 * detail. Added by Task 04 with the first such fixture. */
table {
  border-collapse: collapse;
}

/* --- native disclosure ----------------------------------------------------
 * `details`/`summary` is the system's only disclosure mechanism — the mobile
 * navigation here and the FAQ later — because it works
 * with JavaScript disabled and the platform supplies `aria-expanded`. */
summary {
  cursor: pointer;
}

/* --- form and control inheritance ----------------------------------------- */
button,
input,
select,
textarea {
  font: inherit;
  color: inherit;
}

/* --- utilities ------------------------------------------------------------ */

/* Visually hidden but announced. The `1px` values are the standard clip
 * technique, not a design measurement. */
.u-visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* Centred content column. Bands cap wider; prose caps narrower. */
.u-container {
  width: 100%;
  max-width: calc(var(--container-content) + (var(--page-gutter) * 2));
  margin-inline: auto;
  padding-inline: var(--page-gutter);
}

/* Page rhythm. Every section keeps its padding in every state, so a withheld
 * module changes what a section says, never whether it occupies the page. */
.u-section {
  padding-block: var(--page-section-y);
}

/* --- skip link ------------------------------------------------------------
 * First focusable element in the document, visually hidden until focused,
 * targets the `hero` marker. It is a real anchor, so it works with JavaScript
 * disabled. */
.skip-link {
  position: absolute;
  z-index: var(--z-toast);
  inset-block-start: var(--space-2);
  inset-inline-start: var(--space-2);
  padding: var(--space-3) var(--space-5);
  background-color: var(--surface-card);
  color: var(--text-primary);
  border: var(--border-control);
  border-radius: var(--radius-control);
  box-shadow: var(--shadow-float);
  font-size: var(--text-body-size);
  font-weight: var(--weight-medium);
  text-decoration: none;
  transform: translateY(calc(-100% - var(--space-8)));
}

/* The skip link's own state set. It is off-screen until focused, so focus is
 * the state that matters and it is carried by position — the link arrives on
 * screen — before it is carried by the ring. Hover and press only apply once
 * it is on screen, and both keep `--text-primary` at 15.80:1 / 14.19:1 on
 * their fills rather than restating the link colour. */
.skip-link:focus-visible {
  transform: translateY(0);
}

.skip-link:hover {
  background-color: var(--state-hover-surface);
  color: var(--text-primary);
}

/* A bordered control, so it presses to `--state-hover-surface`, never to
 * `--state-active-surface`, where `--border-control` would fall to 2.84:1.
 * The press translate is qualified on `:focus-visible` because the resting
 * transform is what holds the link off screen: an unqualified `:active`
 * translate would win over it on source order and pull a pressed-but-unfocused
 * link into view. A skip link can only be pressed once it is focused, so the
 * qualified rule covers every reachable case. */
.skip-link:active {
  background-color: var(--state-hover-surface);
  color: var(--text-primary);
}

.skip-link:focus-visible:active {
  transform: translateY(var(--press-distance));
}
