/* ==========================================================================
   Reset and base typography
   ========================================================================== */

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

* { margin: 0; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: 6rem;
}

body {
  min-height: 100svh;
  background-color: var(--bg);
  color: var(--ink);
  font-family: var(--font-sans);
  font-size: var(--step-0);
  line-height: var(--leading-normal);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: clip;
  transition: background-color var(--dur-base) var(--ease-out), color var(--dur-base) var(--ease-out);
}

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

img { height: auto; }

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

button { background: none; border: none; cursor: pointer; }

/* ---- links ---------------------------------------------------------------
   Underlines stay on for real prose links — this is an editorial design and
   removing them would cost more in legibility than it gains in tidiness. The
   underline sits low and thin so it reads as typesetting, not as a button. */
a {
  color: inherit;
  text-decoration-color: color-mix(in oklab, currentColor 32%, transparent);
  text-underline-offset: 0.24em;
  text-decoration-thickness: 1px;
  transition: color var(--dur-fast) var(--ease-out), text-decoration-color var(--dur-fast) var(--ease-out);
}

a:hover { text-decoration-color: currentColor; }

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

/* ---- headings ------------------------------------------------------------
   Fraunces throughout, with its optical-size axis doing real work: the
   browser picks a lighter, more finely-detailed cut at display sizes and a
   sturdier one at small sizes, which is the whole point of an opsz font.

   WONK (the swashy alternate forms) is on for headings and off for small
   display text — see the individual components.                           */
h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-optical-sizing: auto;
  font-variation-settings: var(--wonk-on);
  line-height: var(--leading-tight);
  letter-spacing: var(--tracking-tight);
  font-weight: 600;
  text-wrap: balance;
}

h4 { font-variation-settings: var(--wonk-off); }

p { text-wrap: pretty; }

code, kbd, samp {
  font-family: var(--font-mono);
  font-size: 0.88em;
  font-variant-ligatures: none;
}

/* ---- the readout voice ---------------------------------------------------
   Every label, eyebrow, chip and piece of metadata on this site is set in
   letterspaced uppercase mono. It is the single most consistent signal in the
   design, so it lives in one place rather than being re-specified on each
   component.                                                               */
.readout {
  font-family: var(--font-mono);
  font-size: var(--step--2);
  font-weight: 500;
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  font-variant-ligatures: none;
}

/* Numerals that need to line up in a column — chart tables, stat rows. */
.tabular { font-variant-numeric: tabular-nums; }

/* SVG icon defaults: the icon set is stroked, not filled, unless a rule
   opts a specific icon back into fills (the GitHub mark, for instance). */
svg {
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.icon-github, .card__repo-icon svg, .site-footer__github svg, .contact-card__icon svg[viewBox="0 0 16 16"] {
  fill: currentColor;
  stroke: none;
}

::selection {
  background: color-mix(in oklab, var(--accent) 30%, transparent);
  color: var(--ink);
}

/* ---- focus ---------------------------------------------------------------
   A single, always-visible focus ring. Keyboard users get a strong indicator;
   mouse users never see it thanks to :focus-visible.                        */
:focus { outline: none; }

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

.skip-link {
  position: fixed;
  top: var(--space-s);
  left: var(--space-s);
  z-index: 200;
  padding: 0.7rem 1.15rem;
  background: var(--accent);
  color: var(--accent-ink);
  font-family: var(--font-mono);
  font-size: var(--step--2);
  font-weight: 600;
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  text-decoration: none;
  transform: translateY(-160%);
  transition: transform var(--dur-base) var(--ease-spring);
}

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

/* ---- utilities ---------------------------------------------------------- */
.u-visually-hidden {
  position: absolute !important;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

[hidden] { display: none !important; }

/* ---- reduced motion ------------------------------------------------------
   Honour the OS setting properly: kill the ambient animation entirely rather
   than merely speeding it up, and make every reveal start already-visible.  */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }

  .backdrop__blob, .backdrop__particles { animation: none !important; }
  .backdrop__particles { display: none; }
  [data-reveal] { opacity: 1 !important; transform: none !important; }
  .split-word__inner { transform: none !important; }
}
