/* ==========================================================================
   tarnovski.eu — site layer
   Components used only by the generated pages. Loaded after tarnovski.css,
   which stays the frozen design-system stylesheet from the approved design.
   ========================================================================== */

/* The hidden attribute must beat a display rule (the ledger rows are display:grid). */
[hidden] { display: none !important; }

.page-title {
  font-size: var(--step-display);
  font-weight: 600;
  letter-spacing: -0.035em;
  line-height: var(--leading-display);
  margin: var(--space-4) 0 0;
  text-wrap: balance;
}

/* The lede sits under a display-size title on every inner page, where the 8px
   step the base rule was written for (the hero) reads as a collision. */
.page-title + .hero__lede { margin-top: var(--space-4); }

.meta-panel {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: var(--space-6);
  border: var(--rule);
  background: var(--canvas-paper);
  padding: var(--space-6);
}

.meta-panel p {
  margin: var(--space-2) 0 0;
  font-size: var(--step-sm);
  color: var(--on-surface);
}

.points {
  list-style: none;
  margin: 0;
  padding: 0;
  border-top: var(--rule);
}

.points li {
  display: grid;
  grid-template-columns: 2.5rem 1fr;
  gap: var(--space-4);
  padding-block: var(--space-4);
  border-bottom: var(--rule);
  font-size: var(--step-sm);
  color: var(--on-surface-var);
}

.points li > span:first-child {
  font-family: var(--font-mono);
  font-size: var(--step-nano);
  letter-spacing: 0.1em;
  color: var(--muted);
}

.cta-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-4);
  margin: 0;
}

.related {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3) var(--space-6);
}

.chip-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

/* Unselected chip: the base .chip rule is written for the pressed state. */
.chip[aria-pressed="false"] {
  border-color: var(--hairline-strong);
  color: var(--on-surface-var);
  background: transparent;
}

@media (max-width: 720px) {
  .points li { grid-template-columns: 2rem 1fr; }
}

/* --------------------------------------------------------------------------
   Client review round, 2026-10-17
   Overrides layered on top of the frozen design system (tarnovski.css).
   -------------------------------------------------------------------------- */

/* The hero now carries the statement alone, at a much larger scale; the register
   summary moved out of the hero into its own hairline strip further down. */
.hero__statement { display: grid; gap: var(--space-6); }

.hero h1 {
  font-size: clamp(2.75rem, 1rem + 7.2vw, 6rem);
  letter-spacing: -0.045em;
  line-height: 0.98;
}

.hero .micro { font-size: var(--step-micro); letter-spacing: 0.18em; }

.hero__lede {
  margin: var(--space-2) 0 0;
  max-width: 46ch;
  font-size: clamp(1.125rem, 0.85rem + 1vw, 1.5rem);
  line-height: 1.45;
}

.hero__actions {
  margin-top: var(--space-6);
  gap: var(--space-8);
}
.hero__actions .action { font-size: var(--step-mono); }

/* register summary — hairline grid of key/value cells, below the hero */
.spec-strip {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
  border-top: var(--rule);
  border-left: var(--rule);
}

.spec-strip__cell {
  display: grid;
  gap: var(--space-2);
  padding: var(--space-4);
  border-right: var(--rule);
  border-bottom: var(--rule);
}

.spec-strip__value {
  font-family: var(--font-mono);
  font-size: var(--step-sm);
  letter-spacing: 0.02em;
  font-variant-numeric: tabular-nums;
}

@media (max-width: 620px) {
  .spec-strip { grid-template-columns: repeat(2, 1fr); }
}

/* Ledger: description and metadata read from the same left edge.
   nowrap (from the design system) is dropped so the role lines can wrap and stop
   squeezing the description column. */
.ledger__desc { text-align: left; max-width: 58ch; }
.ledger__meta { text-align: left; white-space: normal; }

/* Column balance is a desktop refinement, so it must stay inside a media query.
   Unwrapped it also beat the design system's ≤900px stacking rule — same
   specificity, later stylesheet — which left entry titles in a ~119px column
   on a phone while still fitting the viewport, so no overflow check caught it. */
@media (min-width: 901px) {
  .ledger__row { grid-template-columns: 2.5rem minmax(0, 1fr) minmax(0, 1.4fr) minmax(0, 0.9fr); }
}

/* ≤620px: a single column, so a long entry title — a heading, set at 20px —
   keeps the full measure instead of breaking one word per line. */
@media (max-width: 620px) {
  .ledger__row { grid-template-columns: minmax(0, 1fr); row-gap: var(--space-3); }
  .ledger__row > .ledger__desc,
  .ledger__row > .ledger__meta { grid-column: auto; }
}

/* Live clock in the telemetry strip: digits must not shift as they tick. */
.refstrip__clock {
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.08em;
}

/* Profile (bio pages): portrait beside the prose, tight caption, no dead space. */
.profile {
  display: grid;
  grid-template-columns: minmax(0, 340px) minmax(0, 1fr);
  gap: var(--space-10);
  align-items: start;
}

.profile__figure {
  margin: 0;
  display: grid;
  gap: var(--space-3);
}

.profile__img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  border: var(--rule);
  background: var(--canvas-paper);
  filter: grayscale(1);
}

.profile__figure figcaption { letter-spacing: 0.1em; }

/* Video embeds (YouTube privacy-enhanced domain) — the only third-party frame on the site */
.embed {
  border: var(--rule);
  aspect-ratio: 16 / 9;
  background: var(--canvas-bone);
}
.embed iframe {
  display: block;
  width: 100%;
  height: 100%;
  border: 0;
}

@media (max-width: 900px) {
  .profile { grid-template-columns: 1fr; gap: var(--space-8); }
  .profile__figure { max-width: 420px; }
}

/* --------------------------------------------------------------------------
   Palette adjustment — client request, 2026-10-18: the page paper a touch
   lighter and warmer.

   #fafaee -> #fdfbee: red +3, green +1, blue unchanged. Green carries most of
   the perceptual luminance, so this reads slightly lighter; keeping blue down
   and letting red lead green by 2 points turns the cast from lemon toward
   cream. It lives here rather than in tarnovski.css so the approved design
   system stays the untouched reference — revert by deleting this block.
   `--canvas-paper`, `--paper-tint` and `--canvas-bone` are deliberately left
   alone: they are steps *inside* the paper (panels, hovers, embeds), and
   moving them too would change the hierarchy rather than the paper.
   -------------------------------------------------------------------------- */
:root { --surface: #fdfbee; }

/* --------------------------------------------------------------------------
   Abstract plates — the cover language of symbolon.studio's portfolio,
   re-authored as SVG (see site/_illustrations.py) and inverted into this
   palette: bone paper instead of near-black, ink hairlines instead of
   white-alpha, one accent mark per plate.

   Colour lives here, not in the markup, so a plate follows the design tokens.
   Strokes are 1px with non-scaling-stroke in the SVG, keeping the hairline
   discipline at every size. Nothing here animates, so there is no motion to
   reduce.
   -------------------------------------------------------------------------- */

.mark {
  display: block;
  width: 100%;
  height: auto;                 /* height comes from the ratio below, not the SVG default */
  aspect-ratio: 4 / 1;          /* the plate's viewBox is 960x240; stated here so the box
                                   never falls back to the 150px replaced-element height */
  background: var(--canvas-paper);
  border-block: var(--rule);
}

.mark__field { fill: var(--canvas-paper); }
.mark__grid  { stroke: var(--hairline-soft); stroke-width: 1; }
.mark__frame { fill: none; stroke: var(--ink); stroke-width: 1; }
.mark__muted { fill: none; stroke: var(--hairline-strong); stroke-width: 1; }
.mark__rule  { stroke: var(--ink); stroke-width: 1; }
.mark__accent { fill: var(--accent); }

/* --------------------------------------------------------------------------
   Client review, round three (2026-10-17, night) — spacing and mobile measure
   -------------------------------------------------------------------------- */

/* 1. Spacing has to be CSS-only on this site. `_headers` sends
   `style-src 'self'`, which blocks inline style attributes outright, so the
   browser discarded every spacing declaration the templates used to carry (305
   of them across 101 pages) and fell back to default paragraph margins. It never
   showed locally, because `python3 -m http.server` does not apply `_headers` —
   only the deployed site enforces the policy. These classes replace them, and
   `audit.py` now fails if an inline style reappears. */

.mt-2  { margin-top: var(--space-2); }
.mt-3  { margin-top: var(--space-3); }
.mt-4  { margin-top: var(--space-4); }
.mt-8  { margin-top: var(--space-8); }
.mt-10 { margin-top: var(--space-10); }

.mono--sm    { font-size: var(--step-sm); }
.mono--micro { font-size: var(--step-micro); }

.section-head--bare { border-bottom: 0; padding-bottom: 0; margin-bottom: var(--space-4); }

.registry-empty { padding-block: var(--space-8); border-bottom: var(--rule); }

.note-block { margin-top: var(--space-6); max-width: 72ch; }

/* A .micro or .ledger__desc used on a <p> should not drag the UA paragraph
   margin into the rhythm. Every one of them is positioned by an mt-* utility or
   by its band, and the leftover 11–16px was showing up as, say, a 50px band gap
   next to 40px everywhere else. :where() holds specificity at zero, so the block
   rules above and below still win. */
:where(p.micro),
:where(p.ledger__desc) { margin-block: 0; }

/* Inside the hero statement the grid's own gap is the rhythm, so the margins its
   children carry were stacking on top of it — 8px on the lede, 24px on the
   action row — and the heading cluster read differently there than on any inner
   page. The grid gap alone now separates them. */
.hero__statement > .hero__lede,
.hero__statement > .hero__actions { margin-top: 0; }

/* 2. One vertical rhythm for every band on every generated page. Each band used
   to carry its own symmetric padding-block, so adjacent bands stacked theirs
   into a 96–128px gap — four times the gaps inside a band, and varying with
   whichever `--tight` variant a template happened to pick. Bands now share one
   value, and only the first one keeps a top padding (plus the band that follows
   the hero, which sets its own larger scale), so every boundary on a page reads
   at the same distance. Bands that were `<section class="shell">` without
   `.section` sat outside the rhythm entirely and are now classed in. */
main > .section,
main > .section--tight { padding-block: var(--space-10); }

main > .section + .section,
main > .hero + .section { padding-top: 0; }

@media (min-width: 720px) {
  main > .section,
  main > .section--tight { padding-block: var(--space-12); }
}

/* On small screens the hero drops to the band rhythm so the hero/first-band
   boundary is the same 40px as every other one; at desktop widths it keeps its
   own opening scale. */
@media (max-width: 900px) {
  main > .hero { padding-block: var(--space-10); }
}
