/* ==========================================================================
   Bota — reset, typography, grid, and the handful of primitives
   every section is built from.
   ========================================================================== */

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}

/* Anchor jumps have to land past the sticky nav rather than under it. */
:target {
  scroll-margin-top: calc(var(--nav-h) + var(--s6));
}

body {
  margin: 0;
  background: var(--background);
  color: var(--foreground);
  font-family: var(--font-sans);
  font-size: var(--t-body);
  line-height: var(--lh-body);
  letter-spacing: var(--ls-body);
  font-feature-settings: "cv05" 1, "cv08" 1, "ss03" 1;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  overflow-x: clip;
}

/* Inter's default digits are proportional, which makes any column of numbers
   shuffle sideways as it updates. */
.tnum,
.plan,
th,
td {
  font-variant-numeric: tabular-nums;
}

h1,
h2,
h3,
h4 {
  margin: 0;
  font-weight: 600;
  text-wrap: balance;
}

h1,
.t-display {
  font-size: var(--t-display);
  line-height: var(--lh-display);
  letter-spacing: var(--ls-display);
  font-weight: 620;
}

h2,
.t-h2 {
  font-size: var(--t-h2);
  line-height: var(--lh-h2);
  letter-spacing: var(--ls-h2);
}

h3,
.t-h3 {
  font-size: var(--t-h3);
  line-height: var(--lh-h3);
  letter-spacing: var(--ls-h3);
}

h4 {
  font-size: var(--t-h4);
  line-height: 1.4;
  letter-spacing: -0.014em;
}

p {
  margin: 0;
}

ul,
ol {
  margin: 0;
  padding: 0;
  list-style: none;
}

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

code,
kbd,
pre,
samp {
  font-family: var(--font-mono);
  font-feature-settings: "calt" 0;
}

a {
  color: inherit;
  text-decoration: none;
}

button {
  font: inherit;
  color: inherit;
}

::selection {
  background: var(--brand);
  color: var(--brand-foreground);
}

:focus-visible {
  outline: 2px solid var(--ring);
  outline-offset: 3px;
  border-radius: var(--radius-xs);
}

/* ── Display accent ───────────────────────────────────────────────────────
   The serif is rationed: one word in the hero, the chapter numerals, one word
   in the closing call to action. Instrument Serif sits optically smaller than
   Inter at the same size and rides high, so both are corrected here rather
   than being patched at each call site.
   ------------------------------------------------------------------------ */
.serif {
  font-family: var(--font-serif);
  font-weight: 400;
  font-style: italic;
  font-size: 1.09em;
  letter-spacing: -0.018em;
  padding-right: 0.04em;
}

/* ── Layout ───────────────────────────────────────────────────────────────
   `.shell` is the page's measure. The editorial feel comes from things
   starting on the left edge and stopping short of the right one — never from
   centring everything and hoping.
   ------------------------------------------------------------------------ */
.shell {
  width: 100%;
  max-width: calc(var(--shell) + var(--gutter) * 2);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.shell--narrow {
  max-width: calc(var(--shell-narrow) + var(--gutter) * 2);
}

.section {
  padding-block: var(--section-y);
  position: relative;
}

.section--tight {
  padding-block: var(--section-y-tight);
}

.section--sunken {
  background: var(--background-sunken);
}

/* Sections still meet on a hairline; the tint underneath them is what keeps a
   long page from reading as one sheet. Bands are only a problem when they are
   loud enough to be counted — these are a couple of percent of warmth. */
.section--ruled {
  border-top: 1px solid var(--rule);
}

/* The <defs>-only SVG that holds the mark. `display: none` would stop Safari
   resolving <use> against it, so it is taken out of flow at zero size instead. */
.sprite {
  position: absolute;
  width: 0;
  height: 0;
  overflow: hidden;
}

/* ── Ground ──────────────────────────────────────────────────────────────
   The alternating band. Three layers in one background, no pseudo-element.
   Top to bottom: a vignette that closes the edges so a full-bleed band has a
   horizon rather than four corners; an ember falling from the top edge so the
   surface has a direction instead of being a flat fill; the warm ground.
   ----------------------------------------------------------------------- */
.section--warm {
  background:
    radial-gradient(120% 80% at 50% 0%, transparent 46%, var(--vignette) 100%),
    linear-gradient(to bottom, var(--ember), transparent 42%),
    var(--surface-warm);
}

/* An ember behind the two moments the page asks you to type. A wide, low
   ellipse rather than a circle — a glow with a legible round edge is a blob,
   and blobs are the other AI tell.

   `isolation` is doing real work: it makes the section a stacking context, so
   the ::after can sit at z-index -1 — above the section's own background,
   below every one of its children — without a single content element needing
   to be lifted out of the way. */
.glow {
  position: relative;
  overflow: clip;
  isolation: isolate;
}

.glow::after {
  content: "";
  position: absolute;
  left: 50%;
  top: var(--glow-y, 38%);
  z-index: -1;
  width: min(1180px, 132vw);
  aspect-ratio: 2.4 / 1;
  translate: -50% -50%;
  pointer-events: none;
  background: radial-gradient(
    closest-side,
    var(--ember-strong),
    color-mix(in srgb, var(--ember-strong) 38%, transparent) 54%,
    transparent 78%
  );
}

/* ── Editorial primitives ────────────────────────────────────────────────── */

/* Small mono label. Section eyebrows, and anything the machine says. */
.label {
  font-family: var(--font-mono);
  font-size: var(--t-label);
  font-weight: 500;
  line-height: 1;
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  color: var(--faint);
}

.label--brand {
  color: var(--brand);
}

/* Eyebrow with a leading rule — the page's recurring section mark. */
.eyebrow {
  display: flex;
  align-items: center;
  gap: var(--s3);
  margin-bottom: var(--s5);
}

.eyebrow::before {
  content: "";
  width: 28px;
  height: 1px;
  background: var(--rule-strong);
  flex: none;
}

/* ── Chapter head ────────────────────────────────────────────────────────
   Every numbered band opens the same way: a serif numeral, a mono name, and a
   hairline that runs to the right edge of the measure. It is the one device
   that repeats down the page, and repeating exactly one device is what makes
   a page read as typeset rather than as decorated.
   ------------------------------------------------------------------------ */
.chapter {
  margin-bottom: clamp(40px, 5.2vw, 80px);
}

.chapter__n {
  display: flex;
  align-items: center;
  gap: var(--s4);
  margin-bottom: var(--s5);
}

.chapter__n .serif {
  font-size: clamp(1.625rem, 1.1rem + 1.5vw, 2.375rem);
  line-height: 0.9;
  color: var(--brand);
  padding: 0;
}

.chapter__n::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--rule);
}

.chapter__title {
  font-size: var(--t-h2);
  line-height: var(--lh-h2);
  letter-spacing: var(--ls-h2);
  max-width: 22ch;
}

.chapter .lede {
  margin-top: var(--s5);
}

.lede {
  font-size: var(--t-lead);
  line-height: 1.55;
  letter-spacing: -0.014em;
  color: var(--muted-foreground);
  text-wrap: pretty;
}

.measure {
  max-width: 58ch;
}

.measure--tight {
  max-width: 46ch;
}

hr,
.rule {
  border: 0;
  height: 1px;
  background: var(--rule);
  margin: 0;
}

/* ── Buttons ──────────────────────────────────────────────────────────────
   Compact and squared-off. No pill radius, no trailing arrow — both are
   template signatures. Depth comes from a one-pixel inner highlight and a
   real pressed state, not from a glow.
   ------------------------------------------------------------------------ */
.btn {
  --btn-py: 9px;
  --btn-px: 16px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s2);
  padding: var(--btn-py) var(--btn-px);
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  font-size: var(--t-sm);
  font-weight: 520;
  letter-spacing: -0.008em;
  white-space: nowrap;
  cursor: pointer;
  user-select: none;
  transition: background var(--dur-fast) var(--ease-crisp),
    border-color var(--dur-fast) var(--ease-crisp),
    color var(--dur-fast) var(--ease-crisp),
    transform var(--dur-fast) var(--ease-crisp),
    box-shadow var(--dur-fast) var(--ease-crisp);
}

.btn:active {
  transform: translateY(0.5px);
}

.btn--primary {
  background: var(--brand);
  color: var(--brand-foreground);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.14), var(--shadow-sm);
}

.btn--primary:hover {
  background: var(--brand-hover);
}

.btn--outline {
  background: var(--card);
  border-color: var(--border-strong);
  color: var(--foreground);
  box-shadow: var(--shadow-sm);
}

.btn--outline:hover {
  border-color: var(--faint);
  background: var(--background);
}

.btn--quiet {
  background: transparent;
  color: var(--muted-foreground);
}

.btn--quiet:hover {
  color: var(--foreground);
  background: var(--accent);
}

.btn--lg {
  --btn-py: 13px;
  --btn-px: 22px;
  font-size: var(--t-body);
}

.btn--block {
  width: 100%;
}

/* Text link with a rule that grows from the left on hover. Underline-slide is
   worth the two lines: it makes links feel operated rather than styled. */
.link {
  position: relative;
  color: var(--foreground);
  font-weight: 500;
  padding-bottom: 1px;
}

.link::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: 0;
  width: 100%;
  height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--dur-base) var(--ease-out);
}

.link:hover::after {
  transform: scaleX(1);
}

.link--brand {
  color: var(--brand);
}

/* ══════════════════ Controls ══════════════════
   Every demonstration on this page is operated by a real radio or checkbox
   wrapped in its own visible label, and switched in CSS. That is not purity
   for its own sake: it means the demos work before the module loads, keep
   working if it fails, arrow-key between options because they are a radio
   group, and are announced as choices rather than as decoration.

   The input is invisible but still focusable — `opacity: 0`, never
   `display: none` — and the label paints both the checked and the focus
   state for it.
   ═══════════════════════════════════════════════ */
.chip > input,
.tab > input,
.swatch > input,
.tick > input,
.run > input,
.remix__go > input {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: 0;
  opacity: 0;
  pointer-events: none;
}

/* Pill. The active one is filled with the brand's own subtle tint rather than
   solid brand — a row of chips where one is a saturated button reads as a
   call to action, and these are choices. */
.chip {
  display: inline-flex;
  position: relative;
  cursor: pointer;
}

.chip > span {
  display: block;
  padding: 5px 11px;
  border: 1px solid var(--rule-strong);
  border-radius: 100px;
  font-size: var(--t-xs);
  letter-spacing: -0.008em;
  color: var(--muted-foreground);
  background: transparent;
  transition: border-color var(--dur-fast) var(--ease-crisp),
    color var(--dur-fast) var(--ease-crisp),
    background var(--dur-fast) var(--ease-crisp);
}

.chip:hover > span {
  border-color: var(--faint);
  color: var(--foreground);
}

.chip > input:checked + span {
  border-color: var(--brand-line);
  background: var(--brand-subtle);
  color: var(--brand);
}

.chip > input:focus-visible + span {
  outline: 2px solid var(--ring);
  outline-offset: 3px;
}

.chip--sm > span {
  padding: 4px 9px;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0;
}

/* Swatch. The label is a colour first and a word second, so the word is set
   below it rather than inside — a colour chip with text on top has to solve
   contrast against every swatch, which is a fight for no benefit. */
.swatch {
  display: grid;
  justify-items: center;
  gap: 7px;
  cursor: pointer;
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--faint);
  position: relative;
  transition: color var(--dur-fast) var(--ease-crisp);
}

.swatch::before {
  content: "";
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: var(--sw);
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.12);
  transition: box-shadow var(--dur-base) var(--ease-out),
    transform var(--dur-base) var(--ease-out);
}

.swatch:hover::before {
  transform: scale(1.06);
}

.swatch:has(input:checked) {
  color: var(--foreground);
}

.swatch:has(input:checked)::before {
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.12), 0 0 0 2px var(--background),
    0 0 0 3.5px var(--sw);
}

.swatch:has(input:focus-visible)::before {
  outline: 2px solid var(--ring);
  outline-offset: 4px;
}

/* ── Accessibility helpers ────────────────────────────────────────────────── */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.skip-link {
  position: fixed;
  top: var(--s3);
  left: var(--s3);
  z-index: 200;
  padding: 10px 16px;
  background: var(--foreground);
  color: var(--background);
  border-radius: var(--radius-sm);
  font-size: var(--t-sm);
  font-weight: 520;
  transform: translateY(-200%);
  transition: transform var(--dur-base) var(--ease-out);
}

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

/* ── Reveal ───────────────────────────────────────────────────────────────
   Deliberately small: 10px and a fade. Big translate-up reveals on every
   element are the most recognisable generated-page motion there is, so this
   is used sparingly and never on more than the first element of a group —
   the rest inherit a stagger through --i.

   The hidden state is scoped to `.js`, which the <head> script removes again
   if the module has not checked in — so a blocked or broken script leaves a
   readable page rather than a blank one. Without any JavaScript at all the
   class is never added in the first place.
   ------------------------------------------------------------------------ */
.js .reveal {
  opacity: 0;
  transform: translateY(10px);
  transition: opacity var(--dur-slow) var(--ease-out),
    transform var(--dur-slow) var(--ease-out);
  transition-delay: calc(var(--i, 0) * 70ms);
}

.js .reveal.is-in {
  opacity: 1;
  transform: none;
}

/* ── Motion preferences ───────────────────────────────────────────────────
   Everything on this page is either explanatory or decorative; under
   `reduce`, the explanatory parts jump straight to their finished state and
   the decorative parts stop existing. Nothing is left mid-way.
   ------------------------------------------------------------------------ */
@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  /* The negative delay matters as much as the duration: several things on
     this page are staged with `animation-delay` and `both` fill, and zeroing
     only the duration would leave them waiting out a two-second cue before
     appearing. Pulled backwards, they are simply already finished. */
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-delay: -1ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }

  .reveal {
    opacity: 1;
    transform: none;
  }
}
