/* BeefyDan portfolio - base. Owner: F0.
   Reset, the two self-hosted faces, the twin-page skeleton (bar / page / stage /
   band / strip / card), the sr-only utility and the reduced-motion structure.
   Piece sheets (header, stage, strip, card, ...) load after this file and win
   on equal specificity by cascade order. */

@font-face {
  font-family: "Instrument Sans";
  src: url("../fonts/InstrumentSans-latin.woff2") format("woff2");
  font-weight: 400 700;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Fragment Mono";
  src: url("../fonts/FragmentMono-Regular.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

/* ---- reset ---- */
*, *::before, *::after { box-sizing: border-box; }

html {
  background: var(--ground);
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  scrollbar-gutter: auto;
}

body {
  margin: 0;
  min-height: 100svh;
  background: var(--ground);
  color: var(--ink);
  font: 400 var(--fs-14) / 1.4 var(--font-voice);
  letter-spacing: var(--track-voice);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
}

h1, h2, h3, p, ul, ol, figure { margin: 0; }
ul, ol { padding: 0; list-style: none; }
img, canvas, video, svg { display: block; max-width: 100%; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; letter-spacing: inherit; background: none; border: 0; padding: 0; margin: 0; cursor: pointer; text-align: inherit; }
[hidden] { display: none !important; }

:focus-visible {
  outline: 1px solid var(--ink);
  outline-offset: 3px;
}

::selection { background: var(--ink); color: var(--ground); }

/* ---- utilities ---- */
.sr-only {
  position: absolute !important;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.skip { z-index: calc(var(--z-bar) + 1); }
.skip:focus {
  position: fixed !important;
  top: var(--s-2); left: var(--s-2);
  width: auto; height: auto;
  margin: 0; padding: var(--s-2) var(--s-3);
  clip: auto; clip-path: none;
  background: var(--ground); color: var(--ink);
  border: 1px solid var(--ink);
  font: 400 var(--fs-12) / 1 var(--font-readout);
  text-transform: uppercase;
  letter-spacing: var(--track-readout);
}

.readout {
  font-family: var(--font-readout);
  font-size: var(--fs-12);
  line-height: 1;
  letter-spacing: var(--track-readout);
  text-transform: uppercase;
  font-variant-numeric: tabular-nums;
}

.voice {
  font-family: var(--font-voice);
  font-weight: 500;
  letter-spacing: var(--track-voice);
}

/* ---- bar: name / readout / twin switch ---- */
.bar {
  position: sticky;
  top: 0;
  z-index: var(--z-bar);
  height: var(--bar-h);
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  column-gap: var(--s-4);
  padding-inline: var(--gutter);
  background: var(--ground);
  border-bottom: 1px solid var(--hairline);
}

.bar__lattice {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: -1;
  pointer-events: none;
}

.bar__name,
.bar__switch {
  font-family: var(--font-voice);
  font-weight: 500;
  font-size: var(--fs-14);
  line-height: 1;
  letter-spacing: var(--track-voice);
  padding-block: var(--s-2);
}

.bar__name { justify-self: start; }

.bar__switch {
  justify-self: end;
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  transition: opacity var(--dur-micro) var(--ease);
}
.bar__switch:hover { opacity: 0.72; }
.bar__switch-arrow { font-family: var(--font-readout); }

.bar__readout {
  justify-self: center;
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  font-family: var(--font-readout);
  font-size: var(--fs-12);
  line-height: 1;
  letter-spacing: var(--track-readout);
  text-transform: uppercase;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.bar__live {
  width: calc(var(--pitch) + var(--cell-size));
  height: calc(var(--pitch) + var(--cell-size));
  color: var(--red);
  flex: none;
}

/* ---- page / stage / band ---- */
.page {
  position: relative;
  /* 130svh of document: the sticky bar's 48px + this. Scroll range = 30svh exactly. */
  height: calc(130svh - var(--bar-h));
}

.stage {
  position: sticky;
  top: var(--bar-h);
  z-index: var(--z-stage);
  height: calc(100svh - var(--bar-h));
  overflow: hidden;
  /* ground: the dot lattice, in the ground block below */
}

.stage__lattice {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

.stage__noscript {
  position: absolute;
  inset: 0;
  display: grid;
  place-content: center;
  padding: var(--gutter);
  font-family: var(--font-voice);
  font-weight: 500;
  font-size: var(--fs-44);
  line-height: 1.05;
  letter-spacing: var(--track-voice);
  text-align: center;
  text-wrap: balance;
}

.showcase {
  position: absolute;
  inset: 0;
  z-index: var(--z-showcase);
}

.band {
  position: relative;
  z-index: var(--z-band);
  height: var(--band-h);
  border-top: 1px solid var(--hairline);
}

/* ---- the ground: one fine dot lattice on every surface (spec §3, revised) ----
   Exactly the build board's texture, which Dan approved on sight: one round dot
   of --cell, 1.1px radius, at the centre of every pitch-sized tile (8px on the
   desktop, 6px on the phone - --pitch, tokens.css) on --ground. Not a mesh, no
   wells, nothing animates: quiet enough that the eye rests on the content.
   CSS paints it wherever CSS can; a canvas that must paint its own ground (the
   bar, a placeholder card, the showcase) gets the identical tile from
   lattice.js paintLattice(), so canvas and CSS surfaces are indistinguishable.
   Tiles start at each surface's padding-box origin: the bar is 48px = a whole
   number of tiles at both pitches, so the stage's rows continue the page's.
   --lat-dot is the dot's tone - --cell on both pages; the white page may take
   one step darker (#D2D2CF) if the dots vanish there. lattice.js reads the
   same property, so a change here reaches every canvas.
   `.band[data-band]` is deliberately more specific than strip.css's `.band`:
   its `background:` shorthand would otherwise erase the dots. */
:root { --lat-dot: var(--cell); }
/* Measured, not guessed: at 1:1 (1440) and on the phone (390) the spec's white
   --cell #DCDCD9 dots all but vanish on #F2F2F0 (1.23:1) while the black twin's
   field reads clearly (1.37:1). One step darker (#D2D2CF, ~1.31:1 - the value
   spec §3 names for exactly this case) gives the white page the same presence,
   inverted, and text still sits on it without a squint. */
html[data-polarity="white"] { --lat-dot: #D2D2CF; }

body,
.stage,
.band[data-band],
.showcase {
  background-color: var(--ground);
  background-image: radial-gradient(var(--lat-dot) 1.1px, transparent 1.2px);
  background-size: var(--pitch) var(--pitch);
}

/* ---- strip skeleton (P3 strip.css refines mechanics) ---- */
.strip {
  height: 100%;
  overflow-x: auto;
  overflow-y: hidden;
  overscroll-behavior-x: contain;
  scrollbar-width: none;
}
.strip::-webkit-scrollbar { display: none; }

.strip__track {
  display: flex;
  align-items: stretch;
  height: 100%;
  width: max-content;
}

/* ---- card skeleton (P4 card.css refines the look) ---- */
.card {
  --media-h: calc(var(--card-h) - var(--caption-h));
  position: relative;
  flex: none;
  height: var(--card-h);
  width: calc(var(--media-h) * var(--ar, 1));
  max-width: 100vw;
  background: var(--ground);
  border-inline-end: 1px solid var(--hairline);
}

.card__hit {
  display: flex;
  flex-direction: column;
  width: 100%;
  height: 100%;
}
.card__hit:focus-visible { outline-offset: -3px; }

.card__media {
  position: relative;
  display: block;
  width: 100%;
  height: var(--media-h);
  overflow: hidden;
  background: var(--ground);
}

.card__img,
.card__placeholder {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.card__index {
  position: absolute;
  top: var(--s-2);
  left: var(--s-2);
  padding: 3px var(--s-1);
  background: var(--ground);
  color: var(--ink);
  font-family: var(--font-readout);
  font-size: var(--fs-12);
  line-height: 1;
  letter-spacing: var(--track-readout);
  font-variant-numeric: tabular-nums;
}
.card[data-current="true"] .card__index { color: var(--red); }

.card__flag {
  position: absolute;
  top: var(--s-2);
  right: var(--s-2);
  padding: 3px var(--s-1);
  background: var(--ground);
  color: var(--gray);
  font-family: var(--font-readout);
  font-size: var(--fs-12);
  line-height: 1;
  letter-spacing: var(--track-readout);
  text-transform: uppercase;
}

.card__caption {
  display: flex;
  align-items: center;
  height: var(--caption-h);
  padding-inline: var(--s-2);
  border-top: 1px solid var(--hairline);
  color: var(--ink);
  font-family: var(--font-readout);
  font-size: var(--fs-12);
  line-height: 1;
  letter-spacing: var(--track-readout);
  text-transform: uppercase;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.strip__empty {
  display: grid;
  place-content: center;
  height: 100%;
  padding: var(--gutter);
  color: var(--gray);
  font-family: var(--font-readout);
  font-size: var(--fs-12);
  letter-spacing: var(--track-readout);
  text-transform: uppercase;
}

/* ---- reduced motion: no scroll tax, band pre-revealed (spec §5) ---- */
@media (prefers-reduced-motion: reduce) {
  .page { height: calc(100svh - var(--bar-h)); }
  .band { margin-top: calc(-1 * var(--band-h)); }
}
