/* =============================================================
   PUNTOS RURALES — stylesheet
   Sections: 1 tokens · 2 reset · 3 layout · 4 header · 5 controls
             6 cards · 7 detail · 8 admin · 9 motion · 10 print
   ============================================================= */

/* ---------- 1. Tokens ---------- */
:root {
  color-scheme: dark light;

  /* palette — warm bordeaux / ink, cream ink, brass accent */
  --ink-900: #100a0d;
  --ink-850: #171013;
  --ink-800: #1e1518;
  --ink-700: #2a1e23;
  --ink-600: #3a2b30;
  --paper:   #f4efe7;
  --paper-dim: #cdc3b8;
  --paper-mute: #9b9088;
  --wine:    #8d1c34;
  --wine-lt: #c2455f;
  --brass:   #c9a24a;
  --brass-lt:#e6c477;
  --green:   #5c8f6b;

  --bg: var(--ink-900);
  --bg-elev: var(--ink-850);
  --bg-card: var(--ink-800);
  --line: color-mix(in oklab, var(--paper) 12%, transparent);
  --line-strong: color-mix(in oklab, var(--paper) 22%, transparent);
  --fg: var(--paper);
  --fg-dim: var(--paper-dim);
  --fg-mute: var(--paper-mute);
  --accent: var(--brass);

  /* type */
  --font-display: "Playfair Display", "Iowan Old Style", "Palatino Linotype",
                  Palatino, Georgia, "Times New Roman", serif;
  --font-body: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Inter,
               Roboto, "Helvetica Neue", Arial, sans-serif;
  --font-num: ui-monospace, "SF Mono", "Cascadia Mono", Menlo, Consolas, monospace;

  --step--1: clamp(0.78rem, 0.76rem + 0.1vw, 0.85rem);
  --step-0:  clamp(0.95rem, 0.92rem + 0.15vw, 1.05rem);
  --step-1:  clamp(1.15rem, 1.05rem + 0.4vw, 1.4rem);
  --step-2:  clamp(1.45rem, 1.25rem + 0.9vw, 2.1rem);
  --step-3:  clamp(1.9rem, 1.4rem + 2.2vw, 3.4rem);
  --step-4:  clamp(2.4rem, 1.5rem + 4.4vw, 5.4rem);

  /* space & shape */
  --gap: clamp(0.9rem, 0.5rem + 1.4vw, 1.6rem);
  --pad: clamp(1rem, 0.6rem + 2vw, 2.4rem);
  --r-sm: 8px;
  --r: 14px;
  --r-lg: 22px;
  --shadow-1: 0 1px 2px rgb(0 0 0 / 0.4), 0 6px 18px -8px rgb(0 0 0 / 0.55);
  --shadow-2: 0 2px 6px rgb(0 0 0 / 0.45), 0 22px 48px -18px rgb(0 0 0 / 0.7);
  --ease: cubic-bezier(0.22, 0.68, 0, 1);
  --ease-soft: cubic-bezier(0.4, 0, 0.2, 1);
  --dur: 320ms;
}

/* light theme — user toggle sets data-theme, else follows OS */
:root[data-theme="light"] {
  color-scheme: light;
  --bg: #f7f3ec;
  --bg-elev: #fffdf9;
  --bg-card: #fffdf9;
  --line: color-mix(in oklab, var(--ink-900) 12%, transparent);
  --line-strong: color-mix(in oklab, var(--ink-900) 26%, transparent);
  --fg: #1b1215;
  --fg-dim: #4c3c40;
  --fg-mute: #7a6a6d;
  --accent: #8a6a1f;
  --shadow-1: 0 1px 2px rgb(60 40 30 / 0.1), 0 6px 16px -10px rgb(60 40 30 / 0.3);
  --shadow-2: 0 2px 8px rgb(60 40 30 / 0.12), 0 24px 50px -22px rgb(60 40 30 / 0.4);
}
:root[data-theme="dark"] { color-scheme: dark; }

/* wine-type accents */
.t-tinto    { --type: #a52a44; }
.t-blanco   { --type: #c8a83e; }
.t-rosado   { --type: #d4718c; }
.t-espumoso { --type: #7fa88e; }
.t-dulce    { --type: #d09a3c; }

/* ---------- 2. Reset ---------- */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  background: var(--bg);
  color: var(--fg);
  font: var(--step-0)/1.6 var(--font-body);
  min-height: 100dvh;
  overflow-x: hidden;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}
img, svg { display: block; max-width: 100%; }
img { height: auto; }
button, input, select, textarea { font: inherit; color: inherit; }
button { background: none; border: 0; cursor: pointer; }
a { color: inherit; text-decoration-color: color-mix(in oklab, currentColor 40%, transparent); text-underline-offset: 3px; }
h1, h2, h3 { font-family: var(--font-display); font-weight: 600; line-height: 1.1; text-wrap: balance; }
p { text-wrap: pretty; }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 4px; }
::selection { background: var(--wine); color: #fff; }
[hidden] { display: none !important; }

.sr {
  position: absolute; width: 1px; height: 1px; padding: 0;
  margin: -1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap;
}
.skip {
  position: fixed; inset-block-start: 0.5rem; inset-inline-start: 0.5rem;
  z-index: 200; padding: 0.6rem 1rem; border-radius: var(--r-sm);
  background: var(--accent); color: #1b1215; font-weight: 600;
  translate: 0 -200%; transition: translate 200ms var(--ease);
}
.skip:focus { translate: 0 0; }

/* ---------- 3. Layout ---------- */
.wrap { width: min(100% - 2 * var(--pad), 1280px); margin-inline: auto; }
.wrap--narrow { width: min(100% - 2 * var(--pad), 860px); margin-inline: auto; }
main { padding-block: clamp(1.5rem, 1rem + 2vw, 3rem) 5rem; }
.stack > * + * { margin-block-start: var(--flow, 1rem); }

/* ---------- 4. Header ---------- */
.site-head {
  position: sticky; top: 0; z-index: 50;
  background: color-mix(in oklab, var(--bg) 82%, transparent);
  border-bottom: 1px solid var(--line);
  view-transition-name: head;
}
@supports (backdrop-filter: blur(1px)) {
  .site-head { backdrop-filter: blur(14px) saturate(1.3); }
}
.site-head__in {
  display: flex; align-items: center; gap: clamp(0.6rem, 2vw, 1.4rem);
  padding-block: 0.7rem;
}
.brand { display: flex; align-items: center; gap: 0.7rem; text-decoration: none; flex: 0 0 auto; }
.brand__mark {
  display: grid; place-items: center;
  width: 2.35rem; aspect-ratio: 1; border-radius: 50%;
  background: radial-gradient(circle at 32% 28%, var(--wine-lt), var(--wine) 55%, #5c101f);
  color: #fff; font: 700 0.8rem/1 var(--font-num); letter-spacing: 0.02em;
  box-shadow: inset 0 0 0 1px rgb(255 255 255 / 0.18), var(--shadow-1);
}
.brand__txt { display: grid; }
.brand__name { font-family: var(--font-display); font-size: 1.06rem; font-weight: 600; letter-spacing: 0.01em; }
.brand__sub { font-size: 0.7rem; color: var(--fg-mute); letter-spacing: 0.08em; text-transform: uppercase; }

.nav { display: flex; gap: 0.15rem; margin-inline-start: auto; align-items: center; }
.nav__links { display: flex; gap: 0.15rem; align-items: center; }
/* Links must refuse to shrink, otherwise they compress instead of overflowing
   and the fit measurement in app.js can never detect the overflow. */
.nav__links > .nav__link { flex: 0 0 auto; white-space: nowrap; }
.nav__link {
  padding: 0.45rem 0.75rem; border-radius: 999px; text-decoration: none;
  font-size: var(--step--1); color: var(--fg-dim); white-space: nowrap;
  transition: background var(--dur) var(--ease-soft), color var(--dur) var(--ease-soft);
}
.nav__link:hover { background: color-mix(in oklab, var(--fg) 8%, transparent); color: var(--fg); }
.nav__link[aria-current="page"] { color: var(--fg); background: color-mix(in oklab, var(--accent) 18%, transparent); }
.icon-btn {
  display: grid; place-items: center; width: 2.2rem; aspect-ratio: 1;
  border-radius: 50%; color: var(--fg-dim);
  transition: background var(--dur) var(--ease-soft), color var(--dur) var(--ease-soft), rotate 400ms var(--ease);
}
.icon-btn:hover { background: color-mix(in oklab, var(--fg) 10%, transparent); color: var(--fg); }
.icon-btn svg { width: 1.15rem; }
.lang-btn { width: auto; padding-inline: 0.6rem; border-radius: 999px; font: 600 0.72rem/1 var(--font-num); letter-spacing: 0.06em; }

/* ---- nav overflow: measured, not guessed ----
   app.js measures whether the links fit and sets .is-compact on the header.
   Everything below hangs off that class, so the burger appears exactly when
   the links do not fit and never otherwise. This rule must come after
   .icon-btn { display: grid } to win on equal specificity. */
.nav__burger { display: none; }
.is-compact .nav__burger { display: grid; }

.is-compact .nav__links {
  position: absolute; inset-inline-end: 0; inset-block-start: calc(100% + 0.5rem);
  min-width: 12rem;
  flex-direction: column; align-items: stretch; gap: 0.1rem;
  padding: 0.4rem; border-radius: var(--r-lg);
  background: var(--bg-elev); border: 1px solid var(--line);
  box-shadow: var(--shadow-2);
  visibility: hidden; opacity: 0; translate: 0 -0.5rem;
  transition: opacity 180ms var(--ease-soft), translate 180ms var(--ease-soft),
              visibility 180ms;
}
.is-compact .nav__links.is-open { visibility: visible; opacity: 1; translate: 0 0; }
.is-compact .nav__link { padding-block: 0.7rem; font-size: var(--step-0); }
/* the panel is positioned against the nav */
.nav { position: relative; }

/* While measuring, the links are laid out inline but must not be seen. */
.is-measuring .nav__links {
  position: absolute !important; visibility: hidden !important;
  inset-block-start: -9999px; flex-direction: row !important;
}


/* ---------- 4b. Narrow screens ----------
   There was no mobile breakpoint before, which is why the header overflowed on
   a phone: brand + three nav labels + two buttons need ~570px, and an iPhone
   gives ~343px of content width. The excess made the page horizontally
   scrollable, so vertical swipes dragged it sideways.

   Fix has two parts: collapse the nav into a menu, and stop the document
   scrolling sideways at all so a stray wide child can never do this again. */

/* Belt and braces: nothing may cause horizontal scrolling of the document. */
html { overflow-x: hidden; }
body { overflow-x: clip; max-width: 100%; }

@media (max-width: 46rem) {
  /* Nav collapsing is NOT handled here — it is measured in app.js, because a
     width guess is wrong in at least three ways: the labels differ in length
     per language, the user's font size is unknown, and 46rem is arbitrary.
     What remains here is genuinely width-dependent. */

  /* brand: drop the subtitle, it is the least useful thing in a tight row */
  .brand__sub { display: none; }
  .brand__name { font-size: 1rem; }

  /* touch targets */
  .icon-btn { width: 2.5rem; }

  /* the hero heading at --step-4 is 2.4rem minimum, which is a lot on a phone */
  .hero h1 { font-size: clamp(1.9rem, 1.2rem + 5vw, 2.6rem); }
  .hero__lede { font-size: var(--step-0); }
  .hero__stats { gap: 1.1rem 1.6rem; margin-block-start: 1.4rem; }

  /* controls row: let the search take a full line rather than squeezing.
     .controls is itself the flex row (there is no inner wrapper). */
  .search { flex: 1 1 100%; }
  .controls { top: 3.2rem; }
}

@media (max-width: 30rem) {
  /* the score badge shrinks slightly so it does not dominate a small card,
     but stays well above its old desktop size */
  .pts { width: 3.9rem; }
  .pts__n { font-size: 1.84rem; }
  .pts--wide .pts__n { font-size: 1.46rem; }   /* 1.59 touches the ring once lifted */
}

/* ---------- 5. Hero + controls ---------- */
.hero { padding-block: clamp(1.6rem, 1rem + 4vw, 4.5rem) clamp(1rem, 2vw, 2rem); position: relative; }
.hero::before {
  content: ""; position: absolute; inset: -30% -20% auto; height: 60vh; z-index: -1;
  background: radial-gradient(60% 60% at 50% 0%, color-mix(in oklab, var(--wine) 34%, transparent), transparent 70%);
  filter: blur(30px); pointer-events: none;
}
.hero__eyebrow {
  font: 500 var(--step--1)/1 var(--font-body); letter-spacing: 0.18em;
  text-transform: uppercase; color: var(--accent);
}
.hero h1 { font-size: var(--step-4); margin-block: 0.4em 0.3em; letter-spacing: -0.02em; }
.hero h1 em { font-style: italic; color: var(--accent); }
.hero__lede { font-size: var(--step-1); color: var(--fg-dim); max-width: 46ch; }
.hero__stats { display: flex; flex-wrap: wrap; gap: clamp(1rem, 3vw, 2.6rem); margin-block-start: 2rem; }
.stat__n { font: 600 var(--step-2)/1 var(--font-display); color: var(--fg); }
.stat__l { font-size: 0.72rem; letter-spacing: 0.12em; text-transform: uppercase; color: var(--fg-mute); }

.controls {
  position: sticky; top: 3.6rem; z-index: 40;
  display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem;
  padding-block: 0.7rem; margin-block-end: var(--gap);
  background: color-mix(in oklab, var(--bg) 88%, transparent);
  border-block: 1px solid var(--line);
}
@supports (backdrop-filter: blur(1px)) { .controls { backdrop-filter: blur(12px); } }
.search {
  display: flex; align-items: center; gap: 0.5rem; flex: 1 1 12rem; min-width: 0;
  padding: 0.45rem 0.8rem; border-radius: 999px;
  background: color-mix(in oklab, var(--fg) 7%, transparent);
  border: 1px solid transparent; transition: border-color var(--dur) var(--ease-soft);
}
.search:focus-within { border-color: var(--line-strong); }
.search svg { width: 1rem; flex: 0 0 auto; color: var(--fg-mute); }
.search input { flex: 1; min-width: 0; background: none; border: 0; outline: none; }
.search input::placeholder { color: var(--fg-mute); }

.chips { display: flex; gap: 0.35rem; flex-wrap: wrap; }
.chip {
  padding: 0.38rem 0.8rem; border-radius: 999px; font-size: var(--step--1);
  border: 1px solid var(--line); color: var(--fg-dim); white-space: nowrap;
  transition: border-color var(--dur) var(--ease-soft), background var(--dur) var(--ease-soft),
              color var(--dur) var(--ease-soft);
}
.chip:hover { border-color: var(--line-strong); color: var(--fg); }
.chip[aria-pressed="true"] {
  background: color-mix(in oklab, var(--type, var(--accent)) 24%, transparent);
  border-color: color-mix(in oklab, var(--type, var(--accent)) 60%, transparent);
  color: var(--fg);
}
.select {
  padding: 0.4rem 0.7rem; border-radius: 999px; font-size: var(--step--1);
  background: color-mix(in oklab, var(--fg) 7%, transparent);
  border: 1px solid var(--line); color: var(--fg-dim);
}
.view-toggle { display: flex; gap: 0.15rem; padding: 0.15rem; border-radius: 999px; border: 1px solid var(--line); }
.view-toggle button { padding: 0.3rem 0.55rem; border-radius: 999px; color: var(--fg-mute); display: grid; place-items: center; }
.view-toggle button svg { width: 1rem; }
.view-toggle button[aria-pressed="true"] { background: color-mix(in oklab, var(--fg) 12%, transparent); color: var(--fg); }
.count { font-size: var(--step--1); color: var(--fg-mute); margin-inline-start: auto; font-variant-numeric: tabular-nums; }

/* ---------- 6. Cards ---------- */
.grid {
  display: grid; gap: var(--gap);
  grid-template-columns: repeat(auto-fill, minmax(min(15.5rem, 100%), 1fr));
}
.grid--wide { grid-template-columns: repeat(auto-fill, minmax(min(21rem, 100%), 1fr)); }
.grid--list { grid-template-columns: 1fr; gap: 0.7rem; }

.card {
  container-type: inline-size;
  position: relative; isolation: isolate;
  border-radius: var(--r-lg); overflow: clip;
  background: var(--bg-card);
  box-shadow: var(--shadow-1);
  transition: translate var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
.card:hover { translate: 0 -4px; box-shadow: var(--shadow-2); }
.card:has(a:focus-visible) { outline: 2px solid var(--accent); outline-offset: 3px; }
.card__link { position: absolute; inset: 0; z-index: 5; }
.card__link:focus-visible { outline: none; }

.card__media {
  position: relative; aspect-ratio: 4 / 5; overflow: clip;
  background: linear-gradient(160deg, var(--ink-700), var(--ink-900));
}
.card__img {
  width: 100%; height: 100%; object-fit: cover;
  transition: scale 700ms var(--ease), filter 700ms var(--ease);
}
.card:hover .card__img { scale: 1.05; }
.card__media::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(to top, rgb(8 5 7 / 0.92) 4%, rgb(8 5 7 / 0.55) 26%, transparent 58%);
}

/* points badge overlaid on the photo */
/* --track = unfilled part of the ring, kept visible so the filled arc reads as
   a proportion rather than a floating sliver. --ring-w = ring thickness. */
.pts {
  position: absolute; inset-block-start: 0.7rem; inset-inline-end: 0.7rem; z-index: 3;
  /* The numeral and label are cap boxes in normal flow (see .pts__n), so
     centring this column centres the INK — which centring absolute boxes did
     not do. The ring is an absolutely-positioned sibling and stays out of it. */
  display: flex; flex-direction: column;
  align-items: center; justify-content: center;
  text-align: center;
  /* Optical lift. Geometric centring is correct — measured off a screenshot the
     digits sat 3.1px ABOVE the ring centre — but the label below them still
     reads as weight at the bottom, so the pair looks low. Padding at the end of
     the box shifts the centred column up by half its value. In % of the badge
     width, so it scales with every size. Set to 0 for pure geometric centring. */
  padding-block-end: 8.2%;
  width: 4.4rem; aspect-ratio: 1; border-radius: 50%;
  /* stroke width in viewBox units (40x40), so it scales with the badge */
  --ring-w: 3.1;
  --track: rgb(255 255 255 / 0.17);
  --disc: rgb(10 6 8 / 0.9);
  /* plain solid disc — the ring is a separate SVG layer above it, so there is
     no gradient sizing to get wrong */
  background: var(--disc);
  box-shadow: inset 0 0 0 1px rgb(255 255 255 / 0.1), 0 5px 16px rgb(0 0 0 / 0.55);
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
}

/* ---- the score ring, as an SVG stroke arc ---- */
.pts__ring {
  position: absolute; inset: 0; width: 100%; height: 100%; z-index: 0;
  /* the arc is authored from 3 o'clock; rotate so it starts at 12 */
  rotate: -90deg;
  pointer-events: none;
}
.pts__ring circle { fill: none; stroke-width: var(--ring-w); }
.pts__track { stroke: var(--track); }
.pts__arc {
  stroke: var(--type, var(--accent));
  stroke-linecap: round;
  /* dashoffset is set inline per wine; the transition makes it sweep in on
     first paint without depending on @property or a registered custom prop */
  transition: stroke-dashoffset 900ms var(--ease);
}
@media (prefers-reduced-motion: reduce) { .pts__arc { transition: none; } }
/* Numeral and label are BOTH taken out of the flow.
   Why: .pts is a centred grid, so with two in-flow children the *stack* gets
   centred and the number itself sits above the circle's centre — measurably
   6.4px high on a card, 7.7px on the detail badge. Taking the label out of the
   flow puts the number on the true centre and frees the ~1.1rem of badge width
   the label was reserving, so the numeral can also grow ~22%.
   Sizes below are solved against the real Iowan Old Style Bold digit metrics
   (0.594em advance, 0.712em cap) so the glyphs clear the ring's inner circle. */
.pts__n {
  /* above the ring (which is an absolutely-positioned sibling) */
  position: relative; z-index: 1;
  /* line-height 0.712 == this font's cap height, so the line box IS the cap
     box (verified against the real font: top/baseline agree within 0.1px).
     With line-height:1 the box carried ~9.7px of ascender/descender slack on a
     card, and centring the BOX therefore did NOT centre the digits. */
  font: 600 2.1rem/0.712 var(--font-display); color: #fff;
  font-variant-numeric: tabular-nums; letter-spacing: -0.03em;
  text-shadow: 0 1px 3px rgb(0 0 0 / 0.55);
}
.pts__l {
  position: relative; z-index: 1;
  /* also a cap box (0.705 == SF's cap height), so the flow column below holds
     exactly ink + gap + ink and nothing else. Percentage insets are gone: they
     resolved against the badge, not the text, so the two never stayed centred
     together across sizes. */
  font-size: 0.52rem; line-height: 0.705;
  margin-block-start: 0.34em;      /* gap between the two cap boxes */
  letter-spacing: 0.14em; text-transform: uppercase;
  color: rgb(255 255 255 / 0.6);
}

.pts--wide .pts__n { font-size: 1.59rem; letter-spacing: -0.05em; }

.pts--big { width: 7rem; --ring-w: 2.8; }   /* viewBox units: thinner-looking on a bigger circle */
.pts--big .pts__n { font-size: 3.3rem; }
.pts--big .pts__l { font-size: 0.72rem; }
.pts--big.pts--wide .pts__n { font-size: 2.66rem; }

/* A perfect score gets its own treatment: gold ring, gold-tinted number and a
   soft outer glow, so it is distinguishable from a 99 at a glance. */
.pts--perfect {
  --type: var(--brass-lt);
  --track: color-mix(in oklab, var(--brass-lt) 32%, transparent);
  box-shadow:
    inset 0 0 0 1px color-mix(in oklab, var(--brass-lt) 55%, transparent),
    0 0 0 2px color-mix(in oklab, var(--brass-lt) 26%, transparent),
    0 6px 20px rgb(0 0 0 / 0.55);
}
.pts--perfect .pts__n { color: color-mix(in oklab, var(--brass-lt) 30%, #fff); }
.pts--perfect .pts__l { color: color-mix(in oklab, var(--brass-lt) 55%, #fff); }
.fav {
  position: absolute; inset-block-start: 0.85rem; inset-inline-start: 0.85rem; z-index: 3;
  color: var(--brass-lt); filter: drop-shadow(0 2px 4px rgb(0 0 0 / 0.6));
}
.fav svg { width: 1.15rem; }

.card__body {
  position: absolute; inset-inline: 0; inset-block-end: 0; z-index: 2;
  padding: 0.9rem 1rem 1rem; display: grid; gap: 0.35rem;
}
.card__abbr {
  font: 600 0.66rem/1 var(--font-num); letter-spacing: 0.16em;
  color: color-mix(in oklab, var(--type, var(--accent)) 72%, white);
}
.card__name {
  font-family: var(--font-display); font-size: 1.02rem; font-weight: 600; line-height: 1.22;
  color: #fff; text-wrap: balance;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.card__meta {
  display: flex; flex-wrap: wrap; gap: 0.3rem 0.6rem; align-items: center;
  font-size: 0.74rem; color: rgb(255 255 255 / 0.66);
}
.card__meta .dot { width: 3px; aspect-ratio: 1; border-radius: 50%; background: currentColor; opacity: 0.5; }
.card__icons { display: flex; gap: 0.3rem; margin-block-start: 0.15rem; }
.card__icons svg { width: 1.05rem; color: rgb(255 255 255 / 0.78); }
@container (max-width: 13rem) { .card__icons { display: none; } }

/* list layout */
.grid--list .card { border-radius: var(--r); }
.grid--list .card__media { display: none; }
.grid--list .card__body {
  position: static; display: grid; grid-template-columns: auto 1fr auto;
  align-items: center; gap: 0.4rem 1rem; padding: 0.75rem 1rem;
}
.grid--list .card__name { color: var(--fg); grid-column: 2; -webkit-line-clamp: 1; }
.grid--list .card__abbr { grid-row: span 2; align-self: center; }
.grid--list .card__meta { grid-column: 2; color: var(--fg-mute); }
.grid--list .card__icons { display: none; }
.grid--list .pts {
  /* relative, not static: the ring SVG is absolutely positioned and would
     otherwise escape to the nearest positioned ancestor */
  position: relative; grid-column: 3; grid-row: span 2; width: 3.4rem;
  /* ring-w is in viewBox units (40x40), so it is unitless and scales */
  --ring-w: 3.3;
  --track: color-mix(in oklab, var(--fg) 14%, transparent);
  /* the disc behind the number has to follow the theme in list view */
  --disc: var(--bg-card);
}
/* No label in list view, so there is no bottom-heavy weight to correct for and
   the optical lift must be removed — otherwise the lone numeral sits too high. */
.grid--list .pts { padding-block-end: 0; }
/* no label in list view, so the numeral owns the full inner circle */
.grid--list .pts__n { font-size: 1.66rem; color: var(--fg); text-shadow: none; }
.grid--list .pts--wide .pts__n { font-size: 1.30rem; }
.grid--list .pts__l { display: none; }
.grid--list .pts--perfect .pts__n { color: color-mix(in oklab, var(--brass-lt) 45%, var(--fg)); }
.grid--list .fav { position: static; grid-row: span 2; }

.empty { padding: 4rem 1rem; text-align: center; color: var(--fg-mute); }
.empty svg { width: 2.6rem; margin: 0 auto 1rem; opacity: 0.5; }

/* section heads */
.sec-head { display: flex; align-items: baseline; gap: 1rem; margin-block: 2.6rem 1.1rem; }
.sec-head h2 { font-size: var(--step-2); }
.sec-head__line { flex: 1; height: 1px; background: var(--line); }
.sec-head a { font-size: var(--step--1); color: var(--fg-mute); text-decoration: none; white-space: nowrap; }
.sec-head a:hover { color: var(--fg); }

/* ---------- 7. Detail view ---------- */
.detail { padding-block-start: 1rem; }
.back {
  display: inline-flex; align-items: center; gap: 0.4rem; margin-block-end: 1.4rem;
  font-size: var(--step--1); color: var(--fg-mute); text-decoration: none;
}
.back:hover { color: var(--fg); }
.back svg { width: 0.9rem; }

.detail__top {
  display: grid; gap: clamp(1.4rem, 4vw, 3.4rem);
  grid-template-columns: 1fr;
}
@media (min-width: 56rem) { .detail__top { grid-template-columns: minmax(0, 0.85fr) minmax(0, 1fr); align-items: start; } }

.detail__figure {
  position: relative; border-radius: var(--r-lg); overflow: clip;
  background: linear-gradient(160deg, var(--ink-700), var(--ink-900));
  box-shadow: var(--shadow-2);
}
.detail__figure img { width: 100%; aspect-ratio: 4 / 5; object-fit: cover; }
@media (min-width: 56rem) { .detail__figure { position: sticky; top: 5rem; } }

.detail h1 { font-size: var(--step-3); letter-spacing: -0.02em; }
.detail__sub { font-size: var(--step-1); color: var(--fg-dim); margin-block-start: 0.4rem; }
.tag-row { display: flex; flex-wrap: wrap; gap: 0.4rem; margin-block-start: 1rem; }
.tag {
  padding: 0.28rem 0.7rem; border-radius: 999px; font-size: 0.74rem;
  border: 1px solid color-mix(in oklab, var(--type, var(--accent)) 40%, transparent);
  color: color-mix(in oklab, var(--type, var(--accent)) 55%, var(--fg));
  background: color-mix(in oklab, var(--type, var(--accent)) 10%, transparent);
}

.facts {
  display: grid; gap: 1px; margin-block-start: 1.8rem;
  grid-template-columns: repeat(auto-fit, minmax(7.5rem, 1fr));
  background: var(--line); border: 1px solid var(--line); border-radius: var(--r);
  overflow: clip;
}
.fact { background: var(--bg); padding: 0.85rem 1rem; }
.fact dt { font-size: 0.66rem; letter-spacing: 0.12em; text-transform: uppercase; color: var(--fg-mute); }
.fact dd { font: 500 1.02rem/1.3 var(--font-body); margin-block-start: 0.2rem; font-variant-numeric: tabular-nums; }

.notes { font-size: var(--step-1); line-height: 1.7; color: var(--fg-dim); white-space: pre-line; }
.notes::first-line { color: var(--fg); }

/* structure bars */
.bars { display: grid; gap: 0.7rem; }
.bar { display: grid; grid-template-columns: 6.5rem 1fr; gap: 0.8rem; align-items: center; font-size: var(--step--1); }
.bar__track { display: flex; gap: 0.25rem; }
.bar__seg {
  height: 0.42rem; flex: 1; border-radius: 999px;
  background: color-mix(in oklab, var(--fg) 12%, transparent);
}
.bar__seg[data-on] { background: var(--type, var(--accent)); }

/* icon legend */
.legend { display: grid; gap: 0.55rem; grid-template-columns: repeat(auto-fill, minmax(10.5rem, 1fr)); }
.legend__item { display: flex; align-items: center; gap: 0.6rem; font-size: var(--step--1); color: var(--fg-dim); }
.legend__item svg { width: 1.35rem; flex: 0 0 auto; color: var(--type, var(--accent)); }
.icon-group { margin-block-start: 1.2rem; }
.icon-group__h { font-size: 0.66rem; letter-spacing: 0.12em; text-transform: uppercase; color: var(--fg-mute); margin-block-end: 0.5rem; }

.buy { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.buy a, .buy span {
  display: inline-flex; align-items: center; gap: 0.4rem;
  padding: 0.45rem 0.9rem; border-radius: 999px; font-size: var(--step--1);
  border: 1px solid var(--line-strong); text-decoration: none; color: var(--fg-dim);
  transition: background var(--dur) var(--ease-soft), color var(--dur) var(--ease-soft);
}
.buy a:hover { background: color-mix(in oklab, var(--accent) 20%, transparent); color: var(--fg); }
.buy svg { width: 0.85rem; }

.prevnext { display: flex; justify-content: space-between; gap: 1rem; margin-block-start: 3.5rem; padding-block-start: 1.5rem; border-top: 1px solid var(--line); }
.prevnext a { display: grid; gap: 0.2rem; text-decoration: none; font-size: var(--step--1); max-width: 45%; }
.prevnext a:last-child { text-align: right; }
.prevnext .k { color: var(--fg-mute); font-size: 0.68rem; letter-spacing: 0.1em; text-transform: uppercase; }
.prevnext .v { font-family: var(--font-display); font-size: 1rem; color: var(--fg); }

/* ---------- 8. About / admin ---------- */
.prose { max-width: 62ch; }
.prose > * + * { margin-block-start: 1rem; }
.prose h2 { font-size: var(--step-2); margin-block-start: 2.2rem; }
.prose h3 { font-size: var(--step-1); margin-block-start: 1.6rem; }
.prose code { font: 0.88em var(--font-num); background: color-mix(in oklab, var(--fg) 9%, transparent); padding: 0.12em 0.4em; border-radius: 5px; }
.prose ul, .prose ol { padding-inline-start: 1.3rem; }
.prose li + li { margin-block-start: 0.3rem; }

.panel { background: var(--bg-elev); border: 1px solid var(--line); border-radius: var(--r); padding: var(--pad); }
.field { display: grid; gap: 0.35rem; margin-block-end: 1rem; }
.field label { font-size: 0.7rem; letter-spacing: 0.1em; text-transform: uppercase; color: var(--fg-mute); }
.field input, .field select, .field textarea {
  padding: 0.6rem 0.75rem; border-radius: var(--r-sm);
  background: color-mix(in oklab, var(--fg) 6%, transparent);
  border: 1px solid var(--line); outline: none;
}
.field input:focus, .field select:focus, .field textarea:focus { border-color: var(--accent); }
.field textarea { min-height: 7rem; resize: vertical; line-height: 1.6; }
.field small { color: var(--fg-mute); font-size: 0.72rem; }
.row { display: grid; gap: 1rem; grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr)); }
.btn {
  display: inline-flex; align-items: center; gap: 0.45rem; justify-content: center;
  padding: 0.6rem 1.1rem; border-radius: 999px; font-weight: 600; font-size: var(--step--1);
  background: var(--accent); color: #17100c;
  transition: filter var(--dur) var(--ease-soft), translate var(--dur) var(--ease);
}
.btn:hover { filter: brightness(1.1); translate: 0 -1px; }
.btn--ghost { background: none; border: 1px solid var(--line-strong); color: var(--fg-dim); }
.btn--ghost:hover { color: var(--fg); background: color-mix(in oklab, var(--fg) 8%, transparent); }
.btn svg { width: 1rem; }
.pickers { display: grid; gap: 0.4rem; grid-template-columns: repeat(auto-fill, minmax(9.5rem, 1fr)); }
.picker {
  display: flex; align-items: center; gap: 0.5rem; padding: 0.4rem 0.6rem;
  border: 1px solid var(--line); border-radius: var(--r-sm); font-size: 0.78rem; cursor: pointer;
  color: var(--fg-dim);
}
.picker:hover { border-color: var(--line-strong); }
.picker svg { width: 1.2rem; flex: 0 0 auto; }
.picker input { accent-color: var(--accent); }
.picker:has(input:checked) { border-color: var(--accent); background: color-mix(in oklab, var(--accent) 12%, transparent); color: var(--fg); }
.code-out {
  font: 0.78rem/1.55 var(--font-num); white-space: pre; overflow: auto;
  max-height: 22rem; padding: 1rem; border-radius: var(--r-sm);
  background: var(--ink-900); color: #cfe3d0; border: 1px solid var(--line);
}
:root[data-theme="light"] .code-out { background: #241b1e; }

/* footer */
.site-foot {
  border-top: 1px solid var(--line); padding-block: 2.5rem 3.5rem;
  color: var(--fg-mute); font-size: var(--step--1);
}
.site-foot__in { display: flex; flex-wrap: wrap; gap: 1rem 2rem; align-items: center; justify-content: space-between; }

/* ---------- 9. Motion ---------- */
/* scroll-driven reveal where supported, otherwise just visible */
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .reveal {
      animation: reveal-in linear both;
      animation-timeline: view();
      animation-range: entry 5% cover 26%;
    }
    @keyframes reveal-in {
      from { opacity: 0; translate: 0 22px; scale: 0.985; }
      to   { opacity: 1; translate: 0 0; scale: 1; }
    }
  }
}
/* fade-in for the routed panel (View Transitions do the heavy lifting) */
.route-in { animation: fade-up 380ms var(--ease) both; }
@keyframes fade-up { from { opacity: 0; translate: 0 10px; } to { opacity: 1; translate: 0 0; } }

::view-transition-old(root), ::view-transition-new(root) { animation-duration: 260ms; }
::view-transition-group(*) { animation-timing-function: var(--ease); }
::view-transition-old(head), ::view-transition-new(head) { animation: none; mix-blend-mode: normal; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important; animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important; scroll-behavior: auto !important;
  }
  .card:hover { translate: none; }
  .card:hover .card__img { scale: 1; }
  ::view-transition-group(*) { animation: none !important; }
}

/* ---------- 10. Print ---------- */
@media print {
  :root { --bg: #fff; --fg: #000; --fg-dim: #333; --fg-mute: #666; }
  .site-head, .controls, .nav, .nav__links, .nav__burger, .prevnext, .site-foot, .back { display: none !important; }
  body { background: #fff; color: #000; }
  .card, .panel, .detail__figure { box-shadow: none; border: 1px solid #bbb; }
  .card__media::after { display: none; }
}
