/* static/css/components.css
   Shared, reusable components (header, footer, preloader, crosshairs, marks,
   buttons, cards, rows, legends...). Not shell/layout rules — those belong in
   base.css, and page-specific layout belongs in each page's own stylesheet.

   Geometry is read off the artboards (PDF points == design px at 1920 wide);
   the comments give the artboard coordinate each number lands on. Several
   artboard text boxes are set with ~89% horizontal scaling; negative
   letter-spacing reproduces their measured advance without distorting
   glyphs or wrapping. */

/* ---- Header ------------------------------------------------------------ */
.hd {
  position: relative;                                    /* for .snd */
  display: grid;
  grid-template-columns: calc(712 * var(--u)) 1fr auto;  /* nav at x=767.7 */
  align-items: start;
  height: calc(var(--header-h) + var(--rule-strong) / 2);
  border-bottom: var(--rule-strong) solid var(--ink);    /* rule y=120.8 */
  margin-right: calc(-2.4 * var(--u));                   /* rule ends x=1866.7 */
  padding-right: calc(2.4 * var(--u));
  font-weight: var(--fw-medium);
}
.hd__logo { display: block; line-height: 0; margin: calc(34.8 * var(--u)) 0 0 calc(-4 * var(--u)); }
.hd__logo svg { display: block; width: calc(203.24 * var(--u)); height: auto; }
/* The link is the wordmark and nothing else: not the rest of its grid column. */
.hd__logo, .ico__logo { justify-self: start; width: max-content; }
.hd__center { padding-top: calc(25.1 * var(--u)); }
.hd__edition {
  margin: 0 0 0 calc(2.3 * var(--u));
  font-size: var(--fs-edition);
  line-height: calc(20 * var(--u));
}
.hd__nav {
  display: flex;
  align-items: flex-start;
  gap: calc(21.3 * var(--u));
  margin-top: calc(23.7 * var(--u));
  font-size: var(--fs-nav);
  line-height: calc(20 * var(--u));
}
.hd__nav a {
  display: block;
  color: inherit;
  text-decoration: none;
  padding-bottom: calc(7.5 * var(--u));                  /* underline y=96.8 */
  border-bottom: var(--rule) solid transparent;
}
.hd__nav a[aria-current] { border-bottom-color: var(--ink); }
.hd__sep {                                                /* y 72.1–87.1 */
  flex: none;
  height: calc(15 * var(--u));
  margin-top: calc(3.3 * var(--u));
  border-left: var(--rule) solid var(--ink);
}
.hd__index {
  display: flex;
  align-items: center;
  gap: calc(7.1 * var(--u));
  margin: calc(66 * var(--u)) calc(-4.9 * var(--u)) 0 0;
  font-size: var(--fs-index);
  line-height: calc(20 * var(--u));
}
.hd__target {                                             /* centre (1860.2, 77) */
  flex: none;
  width: calc(18 * var(--u));
  height: calc(18 * var(--u));
  fill: none;
  stroke: currentColor;
  stroke-width: 1;
  vector-effect: non-scaling-stroke;
}
.hd__target * { vector-effect: non-scaling-stroke; }

/* SONIDO on/off (static/js/audio.js): not on the artboards, so it sits
   out of the grid, right-aligned under NOTAS DE CAMPO, in the same type. */
.snd {
  position: absolute;
  right: calc(2.4 * var(--u));
  top: calc(93 * var(--u));
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  font-size: var(--fs-index);
  font-weight: var(--fw-medium);
  line-height: calc(20 * var(--u));
  cursor: pointer;
}
.snd[hidden] { display: none; }
.snd[aria-pressed="false"] { opacity: .55; }
.snd:hover { text-decoration: underline; text-underline-offset: .2em; text-decoration-thickness: var(--rule); }
.hd__toggle { display: none; }                          /* the disclosure nav, below 900px (responsive.css) */

/* ---- Footer ------------------------------------------------------------ */
.ft {
  display: grid;                                          /* dividers x=534.5 / 1326 / 1690.7 */
  grid-template-columns: calc(477.8 * var(--u)) calc(791.5 * var(--u)) calc(364.7 * var(--u)) 1fr;
  align-items: start;
  height: calc(var(--footer-h) + var(--rule-strong) / 2);
  border-top: var(--rule-strong) solid var(--ink);        /* rule y=952.8 */
  margin-inline: calc(-1.2 * var(--u));                   /* rule x 54.5–1865.5 */
  padding-inline: calc(1.2 * var(--u));
  font-size: var(--fs-footer);
  font-weight: var(--fw-medium);
}
.ft__cell { height: calc(62.4 * var(--u)); margin-top: calc(27.2 * var(--u)); }  /* y 980.5–1042.9 */
.ft__cell + .ft__cell { border-left: var(--rule-strong) solid var(--ink); }
.ft__line { margin: 0; line-height: calc(20 * var(--u)); }
.ft__cell--pub { padding-top: calc(3.55 * var(--u)); margin-left: calc(-2.6 * var(--u)); }
.ft__cell--pub .ft__line--b { margin-top: calc(8.6 * var(--u)); font-size: var(--fs-edition); }
.ft__cell--coords {                                       /* LAT x=670.1, LONG x=1001.1 */
  display: grid;
  grid-template-columns: calc(331 * var(--u)) auto;
  align-content: start;
  padding: calc(17.65 * var(--u)) 0 0 calc(134.6 * var(--u));
}
.ft__cell--status { padding: calc(5.95 * var(--u)) 0 0 calc(120.9 * var(--u)); }
.ft__cell--status .ft__line--a { font-size: var(--fs-edition); }
.ft__cell--status .ft__line--b { margin-top: calc(5.9 * var(--u)); }
.ft__cell--brand img {                                    /* logo 1798–1863 x 983–1035 */
  display: block;
  width: calc(73.06 * var(--u));
  height: auto;
  margin: calc(-1.1 * var(--u)) calc(-3.2 * var(--u)) 0 auto;
}

/* ---- Preloader (artboard 1, animated: ruling R28) ------------------------
   The composition builds from artboard 1's own elements, then holds and
   dissolves (static/js/preloader.js sequences the exit):
     0.00-1.13s  HO / eye / star strokes draw in (stroke-dashoffset)
     0.15-0.53s  top meta lines wipe in, left to right, 100ms apart
     0.45-0.85s  the HO——2026 rule extends
     0.60-1.43s  "Hydration Observer" wipes in, then NOTAS DE CAMPO, the tagline
     1.05-1.63s  bottom meta lines wipe in; 1.30-1.70s their rules extend
     1.70-5.20s  hold on the complete composition (pre-hold ends at 5.2s)
     then .pre--out takes it apart again, last in first out, in 0.9s
   Every build animation fills backwards only, so once it ends the element
   is back on its static rule: the final frame is the static composition. */
.pre {
  position: fixed;
  inset: 0;
  z-index: 100;
  background: var(--ground);
  color: var(--ink);
  overflow: hidden;
  container-type: size;             /* the stage measures the overlay, not 100vw */
  animation: pre-cap .6s ease 8s forwards;   /* failsafe if the script never runs */
}
.pre-seen .pre { display: none; }    /* seen this visit: decided before first paint */
/* Scroll lock while the overlay plays. It is an animation, not a plain
   declaration, for two reasons: animations sit above every normal rule in
   the cascade, so it beats the WIDE/FLOW overflow rules (base.css) without
   !important; and it expires by itself at 8.6s, as the pre-cap failsafe
   finishes fading the overlay, so a page whose script died mid-play is
   never left locked. The script removes the class on every dismissal. */
html.is-preloading, html.is-preloading body { animation: pre-lock 8.6s; }
@keyframes pre-lock { from, to { overflow: hidden; } }
/* WIDE and FLOW scroll: keep the scrollbar's gutter while locked, so the
   page does not jump when the lock releases (STAGE never scrolls). */
@media (max-width: 1599.98px), (max-height: 899.98px) {
  html.is-preloading { animation-name: pre-lock-gutter; }
}
@keyframes pre-lock-gutter { from, to { overflow: hidden; scrollbar-gutter: stable; } }
/* The artboard composition on a 1920x1080 stage, centred in the overlay.
   The overlay's box excludes a classic scrollbar, so the stage is sized
   from it (container units) rather than from 100vw. */
.pre__stage[data-stage] { --u: min(calc(100cqw / 1920), calc(100cqh / 1080)); }
.pre__stage {
  position: absolute;
  left: 50%;
  top: 50%;
  width: calc(1920 * var(--u));
  height: calc(1080 * var(--u));
  transform: translate(-50%, -50%);
  animation: pre-hold 5.2s linear;
}
.pre__meta { position: absolute; margin: 0; font-size: var(--fs-pre); font-weight: var(--fw-medium); }
.pre__meta p { margin: 0; line-height: calc(45 * var(--u)); }
.pre__meta--top { left: calc(796 * var(--u)); top: calc(160.5 * var(--u)); }     /* baselines 192.3 / 237.2 / 283.1 */
.pre__meta--top p:last-child { font-weight: var(--fw-regular); }
.pre__meta--bottom { left: calc(781.1 * var(--u)); top: calc(778.9 * var(--u)); } /* baselines 810.7 / 855.6 / 900.5 */
/* HO——2026: the artboard draws the dash as a 27.7px rule, two cells wide. */
.pre__dash {
  display: inline-block;
  width: 2ch;
  color: transparent;
  background: linear-gradient(var(--ink), var(--ink)) no-repeat;
  background-size: calc(27.7 * var(--u)) var(--rule-strong);
  background-position: center calc(50% + 0.5 * var(--u));
}
.pre__dash--short {
  width: 1ch;
  background-size: calc(11.1 * var(--u)) var(--rule);
  background-position: center calc(50% + 2.5 * var(--u));
}  /* © PURE WATER–2026 */
.pre__ho {                                                /* strokes x 452–996.3, y 451.3–577.2 */
  position: absolute;
  left: calc(440.85 * var(--u));
  top: calc(440.15 * var(--u));
  width: calc(566.6 * var(--u));
  height: calc(151 * var(--u));
  overflow: visible;
}
.pre__ho path { stroke-width: 1.076px; }                  /* 3px on the artboard */
.pre__words { position: absolute; left: calc(1035.7 * var(--u)); top: calc(444.65 * var(--u)); }
.pre__name { display: block; width: calc(382.05 * var(--u)); height: auto; }
.pre__sub {
  margin: calc(4.1 * var(--u)) 0 0 calc(2.6 * var(--u));   /* baseline 521.7 */
  font-size: var(--fs-pre);
  font-weight: var(--fw-regular);
  line-height: calc(30 * var(--u));
  letter-spacing: .091em;
}
.pre__tag {
  margin: calc(17.1 * var(--u)) 0 0 calc(2.5 * var(--u));  /* baselines 565.3 / 592.3 */
  max-width: calc(440 * var(--u));
  font-size: var(--fs-pretag);
  font-weight: var(--fw-medium);
  line-height: calc(27 * var(--u));
  letter-spacing: .045em;
}

/* -- the build -- */
/* Strokes: --len is each path's length, set by preloader.js; the fallback
   is longer than any path, so without it the marks still end drawn. */
.pre__ho path { animation: pre-draw .5s cubic-bezier(.4, 0, .2, 1) backwards; }
.pre__ho path:nth-child(2) { animation-delay: .04s; }     /* H: verticals, then bars */
.pre__ho path:nth-child(3) { animation-delay: .08s; }
.pre__ho path:nth-child(4) { animation-delay: .12s; }
.pre__ho path:nth-child(5) { animation-delay: .16s; }
.pre__ho path:nth-child(6) { animation-delay: .2s; }
.pre__ho path:nth-child(n+7):nth-child(-n+9) { animation-duration: .3s; }
.pre__ho path:nth-child(7) { animation-delay: .38s; }
.pre__ho path:nth-child(8) { animation-delay: .42s; }
.pre__ho path:nth-child(9) { animation-delay: .46s; }
.pre__ho path:nth-child(n+10):nth-child(-n+12) { animation-duration: .7s; }   /* O: inner ring out */
.pre__ho path:nth-child(10) { animation-delay: .15s; }
.pre__ho path:nth-child(11) { animation-delay: .21s; }
.pre__ho path:nth-child(12) { animation-delay: .27s; }
.pre__ho path:nth-child(13) { animation-delay: .35s; animation-duration: .65s; }   /* eye */
.pre__ho path:nth-child(n+14):nth-child(-n+20) { animation-delay: .55s; }         /* the drop */
.pre__ho path:nth-child(17), .pre__ho path:nth-child(18) { animation-delay: .65s; animation-duration: .3s; }
.pre__ho path:nth-child(n+21) { animation-duration: .45s; }                        /* star */
.pre__ho path:nth-child(21) { animation-delay: .5s; }
.pre__ho path:nth-child(22) { animation-delay: .56s; }
.pre__ho path:nth-child(23) { animation-delay: .62s; }
.pre__ho path:nth-child(24) { animation-delay: .68s; }
/* Text and the wordmark: one left-to-right wipe, in reading order. */
.pre__meta p, .pre__name, .pre__sub, .pre__tag {
  animation: pre-wipe .38s cubic-bezier(.4, 0, .2, 1) backwards;
}
.pre__meta--top p:nth-child(1) { animation-delay: .15s; }
.pre__meta--top p:nth-child(2) { animation-delay: .25s; }
.pre__meta--top p:nth-child(3) { animation-delay: .35s; }
.pre__name { animation-delay: .6s; animation-duration: .55s; }
.pre__sub { animation-delay: .85s; }
.pre__tag { animation-delay: .95s; animation-duration: .48s; }
.pre__meta--bottom p:nth-child(1) { animation-delay: 1.05s; }
.pre__meta--bottom p:nth-child(2) { animation-delay: 1.15s; }
.pre__meta--bottom p:nth-child(3) { animation-delay: 1.25s; }
/* The rules extend from their centre once their line is in. */
.pre__dash { animation: pre-rule .4s cubic-bezier(.4, 0, .2, 1) .45s backwards; }
.pre__meta--bottom .pre__dash { animation-delay: 1.3s; }
.pre__dash--short, .pre__meta--bottom .pre__dash--short {
  animation-name: pre-rule-short;
  animation-duration: .25s;
  animation-delay: 1.45s;
}

/* -- the exit (preloader.js adds .pre--out) --
   Each build keyframe mirrored, under its own name, with the build's
   easing mirrored too (cubic-bezier(.4,0,.2,1) -> (.8,0,.6,1)) and
   forwards, so each element holds its undrawn, unwiped, retracted state.
   The names have to differ from the build's: a CSS animation keeps the
   start time its name was first applied at, so reusing pre-draw here
   only re-timed an animation that finished during the build, and the
   composition vanished in one frame instead of coming apart.
   Each delay is its build delay mirrored and compressed, so the
   composition comes apart last in, first out, in 0.9s:
     0.00s  the (c) PURE WATER rule retracts, bottom meta lines un-wipe
     0.03s  the drop and the star un-draw
     0.13s  the tagline, NOTAS DE CAMPO, then the wordmark un-wipe
     0.16s  the eye, the O's inner rings, then the H
     0.25s  the HO--2026 rule retracts, top meta lines un-wipe
     0.60s  the black behind it all fades last (pre-cap again, 0.3s)
   Every selector here carries both .pre and .pre--out: the build's own
   per-group rules are specificity (0,3,1), and these have to outrank them
   rather than tie. */
.pre.pre--out { animation: pre-fade .3s ease .6s forwards; pointer-events: none; }

.pre.pre--out .pre__ho path {
  animation: pre-undraw .35s cubic-bezier(.8, 0, .6, 1) forwards;
}
.pre.pre--out .pre__ho path:nth-child(1) { animation-delay: .34s; }   /* H, last out */
.pre.pre--out .pre__ho path:nth-child(2) { animation-delay: .32s; }
.pre.pre--out .pre__ho path:nth-child(3) { animation-delay: .3s; }
.pre.pre--out .pre__ho path:nth-child(4) { animation-delay: .28s; }
.pre.pre--out .pre__ho path:nth-child(5) { animation-delay: .26s; }
.pre.pre--out .pre__ho path:nth-child(6) { animation-delay: .24s; }
.pre.pre--out .pre__ho path:nth-child(7) { animation-delay: .15s; }   /* its bars */
.pre.pre--out .pre__ho path:nth-child(8) { animation-delay: .13s; }
.pre.pre--out .pre__ho path:nth-child(9) { animation-delay: .11s; }
.pre.pre--out .pre__ho path:nth-child(10) { animation-delay: .27s; }  /* O: inner ring */
.pre.pre--out .pre__ho path:nth-child(11) { animation-delay: .24s; }
.pre.pre--out .pre__ho path:nth-child(12) { animation-delay: .21s; }
.pre.pre--out .pre__ho path:nth-child(13) { animation-delay: .17s; }  /* eye */
.pre.pre--out .pre__ho path:nth-child(n+14):nth-child(-n+20) { animation-delay: .07s; }  /* drop */
.pre.pre--out .pre__ho path:nth-child(17),
.pre.pre--out .pre__ho path:nth-child(18) { animation-delay: .02s; }
.pre.pre--out .pre__ho path:nth-child(21) { animation-delay: .09s; }  /* star, first out */
.pre.pre--out .pre__ho path:nth-child(22) { animation-delay: .06s; }
.pre.pre--out .pre__ho path:nth-child(23) { animation-delay: .03s; }
.pre.pre--out .pre__ho path:nth-child(24) { animation-delay: 0s; }
/* Text un-wipes the way it arrived: the clip closes back to the left. */
.pre.pre--out .pre__meta p,
.pre.pre--out .pre__name,
.pre.pre--out .pre__sub,
.pre.pre--out .pre__tag {
  animation: pre-unwipe .3s cubic-bezier(.8, 0, .6, 1) forwards;
}
.pre.pre--out .pre__meta--top p:nth-child(1) { animation-delay: .33s; }
.pre.pre--out .pre__meta--top p:nth-child(2) { animation-delay: .3s; }
.pre.pre--out .pre__meta--top p:nth-child(3) { animation-delay: .28s; }
.pre.pre--out .pre__name { animation-delay: .21s; }
.pre.pre--out .pre__sub { animation-delay: .15s; }
.pre.pre--out .pre__tag { animation-delay: .13s; }
.pre.pre--out .pre__meta--bottom p:nth-child(1) { animation-delay: .1s; }
.pre.pre--out .pre__meta--bottom p:nth-child(2) { animation-delay: .08s; }
.pre.pre--out .pre__meta--bottom p:nth-child(3) { animation-delay: .05s; }
/* The rules retract into the centres they grew from. */
.pre.pre--out .pre__dash {
  animation: pre-unrule .3s cubic-bezier(.8, 0, .6, 1) .25s forwards;
}
.pre.pre--out .pre__meta--bottom .pre__dash { animation-delay: .04s; }
.pre.pre--out .pre__dash--short,
.pre.pre--out .pre__meta--bottom .pre__dash--short {
  animation-name: pre-unrule-short;
  animation-duration: .25s;
  animation-delay: 0s;
}

@keyframes pre-draw {
  from { stroke-dasharray: var(--len, 1000); stroke-dashoffset: var(--len, 1000); }
  to   { stroke-dasharray: var(--len, 1000); stroke-dashoffset: 0; }
}
@keyframes pre-wipe {
  from { clip-path: inset(-.5em 100% -.5em -.5em); }
  to   { clip-path: inset(-.5em -.5em -.5em -.5em); }
}
@keyframes pre-rule { from { background-size: 0 var(--rule-strong); } }
@keyframes pre-rule-short { from { background-size: 0 var(--rule); } }
@keyframes pre-hold { to { visibility: visible; } }       /* a timeline only: build + hold */
@keyframes pre-cap { to { opacity: 0; visibility: hidden; } }
/* The exit's mirrors of the four build keyframes, plus the black's own
   fade (pre-cap is already on .pre as the failsafe, so the exit cannot
   reuse that name either). */
@keyframes pre-undraw {
  from { stroke-dasharray: var(--len, 1000); stroke-dashoffset: 0; }
  to   { stroke-dasharray: var(--len, 1000); stroke-dashoffset: var(--len, 1000); }
}
/* Both ends spelled out, as pre-wipe does: the static value is
   clip-path: none, and none -> inset() does not interpolate -- it would
   flip discretely at 50% and the text would cut rather than wipe. */
@keyframes pre-unwipe {
  from { clip-path: inset(-.5em -.5em -.5em -.5em); }
  to   { clip-path: inset(-.5em 100% -.5em -.5em); }
}
@keyframes pre-unrule { to { background-size: 0 var(--rule-strong); } }
@keyframes pre-unrule-short { to { background-size: 0 var(--rule); } }
@keyframes pre-fade { to { opacity: 0; visibility: hidden; } }

@media (prefers-reduced-motion: reduce) {
  .pre { display: none; }
}

/* ---- Crosshair motif ---------------------------------------------------- */
/* Thin '+' drawn as two hairlines. The container sets --xh-size and
   --xh-inset (distance from its padding edge to the mark's box). */
.xh {
  position: absolute;
  width: var(--xh-size, calc(21 * var(--u)));
  height: var(--xh-size, calc(21 * var(--u)));
  pointer-events: none;
}
.xh::before, .xh::after { content: ""; position: absolute; background: var(--ink); }
.xh::before { left: 0; right: 0; top: calc(50% - var(--rule) / 2); height: var(--rule); }
.xh::after { top: 0; bottom: 0; left: calc(50% - var(--rule) / 2); width: var(--rule); }
.xh--tl { top: var(--xh-inset, 0); left: var(--xh-inset, 0); }
.xh--tr { top: var(--xh-inset, 0); right: var(--xh-inset, 0); }
.xh--bl { bottom: var(--xh-inset, 0); left: var(--xh-inset, 0); }
.xh--br { bottom: var(--xh-inset, 0); right: var(--xh-inset, 0); }

/* ---- Marks ------------------------------------------------------------- */
.mark, .legend__mark, .card__mark { color: var(--ink); fill: none; stroke: currentColor; }

/* ---- Focus ------------------------------------------------------------- */
/* The artboards specify no focus state; without one the site is unusable by
   keyboard. Drawn in the system's own vocabulary. */
:where(a, button, [tabindex]):focus-visible {
  outline: var(--rule) solid var(--ink);
  outline-offset: calc(4 * var(--u));
}

/* Visually hidden, still announced (e.g. "opens in a new tab" cues). */
.vh {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ---- Page title (Home/Editorial "INSIDE THE BOTTLE.", Archivo "ARCHIVO") - */
.hero {                                   /* first baseline 223.9 on artboards 2, 3 and 4 */
  margin: 0 0 0 calc(-2 * var(--u));
  font-size: var(--fs-hero);
  font-weight: var(--fw-medium);
  line-height: calc(70.1 * var(--u));
}
.hero__stand {                            /* baselines 351.7 / 383.6 on artboards 2 and 4 */
  margin: calc(21.6 * var(--u)) 0 0 calc(-0.9 * var(--u));
  font-size: var(--fs-standfirst);
  line-height: calc(31.9 * var(--u));
  letter-spacing: -.0676em;
}

/* ---- Card (Home: featured + compact PREFRAME cards) --------------------- */
.card {
  /* compact defaults; artboard card #167 at x 52.9–274.7, y 670.9–917.9 */
  --mark-w: calc(34.3 * var(--u));      /* width of the rule under the icon */
  --mark-h: calc(40.7 * var(--u));      /* icon top to that rule */
  --mark-size: calc(57 * var(--u));     /* sprite box; glyph reads ~32px */
  --mark-cy: calc(16 * var(--u));       /* icon centre below the head top */
  --id-top: calc(9 * var(--u));
  position: relative;
  display: flex;
  flex-direction: column;
  min-width: 0;
  border: var(--rule) solid var(--ink);
  padding: calc(16.6 * var(--u)) calc(15 * var(--u)) calc(21.8 * var(--u)) calc(23.6 * var(--u));
}
/* On a compact card this '+' is a link to the PREFRAME's Archivo row, drawn
   exactly as the decorative mark it replaces. .xh is pointer-events: none,
   being decorative everywhere else, so this one has to take them back. */
.card--compact > .xh--br { --xh-size: calc(21 * var(--u)); right: calc(14 * var(--u)); bottom: calc(16 * var(--u)); }
.card__plus { pointer-events: auto; }
.card__head { display: flex; align-items: flex-start; gap: calc(10.3 * var(--u)); }
.card__mark-wrap {
  position: relative;
  flex: none;
  display: block;
  width: var(--mark-w);
  height: calc(var(--mark-h) + var(--rule));
  border-bottom: var(--rule) solid var(--ink);
}
.card__mark {
  position: absolute;
  left: calc(50% - var(--mark-size) / 2);
  top: calc(var(--mark-cy) - var(--mark-size) / 2);
  width: var(--mark-size);
  height: var(--mark-size);
  overflow: visible;
}
.card__id {
  margin: var(--id-top) 0 0;
  font-size: var(--fs-label);
  font-weight: var(--fw-medium);
  line-height: calc(16 * var(--u));
  letter-spacing: -.0165em;
  white-space: nowrap;            /* keeps the head one line when type hits its floor */
}
/* On the featured card the title links to the PREFRAME's Archivo row (a
   compact card uses its '+' instead); at rest it reads exactly as the
   artboard's plain text. */
.card__id-link { color: inherit; text-decoration: none; }
.card__id-link:hover {
  text-decoration: underline;
  text-underline-offset: .2em;
  text-decoration-thickness: var(--rule);
}
.card__body {
  margin: calc(15 * var(--u)) 0 0;
  font-size: var(--fs-card);
  line-height: calc(16 * var(--u));
  letter-spacing: -.029em;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 6;          /* last-defence clamp, see spec §8 */
  overflow: hidden;
}
.card__rule {                     /* dashed, x 77–216.7 at y=843.6 */
  flex: none;
  width: calc(139.7 * var(--u));
  height: max(1px, calc(1.5 * var(--u)));
  margin: auto 0 0;
  border: 0;
  background: repeating-linear-gradient(to right,
    var(--ink) 0 calc(3.04 * var(--u)), transparent calc(3.04 * var(--u)) calc(6.08 * var(--u)));
}
.card__foot { margin-top: calc(13.75 * var(--u)); }
.card__src-label {
  margin: 0;
  font-size: var(--fs-label);
  line-height: calc(16 * var(--u));
  letter-spacing: -.029em;
}
.card__src {
  margin: calc(3.5 * var(--u)) 0 0;
  font-size: var(--fs-src);
  font-weight: var(--fw-semibold);
  line-height: calc(18 * var(--u));
  letter-spacing: -.034em;
}
.card--featured {                 /* artboard box 1151–1864 x 201–566 */
  --mark-w: calc(34.2 * var(--u));
  --mark-h: calc(43.5 * var(--u));
  --mark-size: calc(61 * var(--u));
  --mark-cy: calc(17.8 * var(--u));
  --id-top: calc(11.7 * var(--u));
  border: 0;
  padding: calc(26.5 * var(--u)) 0 calc(19.9 * var(--u)) calc(51.6 * var(--u));
}
.card--featured .card__head { gap: calc(10.7 * var(--u)); }
.card--featured .card__body {
  max-width: calc(290 * var(--u));
  margin-top: calc(13.55 * var(--u));
  font-size: var(--fs-featured);
  line-height: calc(28 * var(--u));
  letter-spacing: -.0673em;
  -webkit-line-clamp: 5;
}
.card--featured .card__foot { margin-top: calc(16.15 * var(--u)); }
.card--featured .card__src-label {
  font-size: var(--fs-src-label);
  line-height: calc(18 * var(--u));
  letter-spacing: -.065em;
}
.card--featured .card__src {
  margin-top: calc(2.25 * var(--u));
  font-size: var(--fs-source);
  font-weight: var(--fw-regular);
  line-height: calc(22 * var(--u));
  letter-spacing: -.063em;
}

/* ---- Button (Home: VERIFY link on the featured card) --------------------- */
.btn {                            /* artboard 1203.8–1403.3 x 438.4–485.7 */
  display: flex;
  align-items: center;
  justify-content: space-between;
  align-self: flex-start;
  flex: none;
  width: calc(200.5 * var(--u));
  height: calc(48.3 * var(--u));
  margin-top: auto;
  padding: 0 calc(23.9 * var(--u)) 0 calc(22.6 * var(--u));
  border: var(--rule) solid var(--ink);
  color: inherit;
  text-decoration: none;
  font-size: var(--fs-verify);
  font-weight: var(--fw-regular);
  line-height: calc(24 * var(--u));
  letter-spacing: -.0587em;
}
.btn:hover { background: var(--ink); color: var(--ground); }
/* A longer label than VERIFY (6 chars) never fits .btn's fixed 200.5u
   width at any --u, because width and font-size scale together (review
   finding, task 14 fix round 1). .btn--auto keeps VERIFY's box (width,
   height, padding, arrow) pixel-identical everywhere else and only
   changes width to fit its own content, on one line, wherever a longer
   label is needed (the error pages' "VOLVER AL OBSERVATORIO"). */
.btn--auto {
  width: auto;
  gap: calc(12 * var(--u));
  white-space: nowrap;
}
.btn__arrow, .panel__arrow {
  flex: none;
  width: calc(15.2 * var(--u));
  height: calc(12.9 * var(--u));
  fill: none;
  stroke: currentColor;
  stroke-width: 1;
  overflow: visible;
}
.btn__arrow path, .panel__arrow path { vector-effect: non-scaling-stroke; }

/* ---- Legend (Home: stage key beside the featured card) ------------------ */
.legend {                         /* rows x 1626.2–1819.1, first row top y=217.6 */
  list-style: none;
  margin: 0;
  padding: calc(14.6 * var(--u)) 0 0 calc(56.7 * var(--u));
}
.legend__row {
  display: flex;
  align-items: center;
  gap: calc(13.2 * var(--u));
  width: calc(192.9 * var(--u));
  height: calc(66.4 * var(--u));
}
.legend__row:nth-child(4) { height: calc(62.4 * var(--u)); }  /* the artboard's short row */
.legend__row + .legend__row {
  background: repeating-linear-gradient(to right,
    var(--ink) 0 calc(2.756 * var(--u)), transparent calc(2.756 * var(--u)) calc(5.512 * var(--u)))
    top left / 100% var(--rule) no-repeat;
}
.legend__mark { flex: none; width: calc(61 * var(--u)); height: calc(61 * var(--u)); margin-left: calc(-9.2 * var(--u)); }
.legend__label {
  max-width: calc(90 * var(--u));
  font-size: var(--fs-legend);
  font-weight: var(--fw-medium);
  line-height: calc(20 * var(--u));
  letter-spacing: -.029em;
}

/* ---- Project panel (Home: "EL PROYECTO") --------------------------------- */
.panel {                          /* artboard 1060.9–1863.2 x 670.9–917.9 */
  display: grid;
  grid-template-columns: calc(199.9 * var(--u)) calc(407.3 * var(--u)) 1fr;
  align-items: start;
  height: calc(249 * var(--u));
  padding-top: calc(53.7 * var(--u));   /* inner dividers y 725.6–838.7 */
  border: var(--rule-strong) solid var(--ink);
}
.panel__mark {
  display: block;
  width: calc(122.7 * var(--u));
  height: calc(116.1 * var(--u));
  margin: calc(-1.55 * var(--u)) 0 0 calc(41.35 * var(--u));
}
.panel__mark path { stroke-width: 7.68px; }             /* 3px at this scale */
.panel__text {
  height: calc(113.1 * var(--u));
  padding-left: calc(33.1 * var(--u));
  border-left: var(--rule-strong) solid var(--ink);
}
.panel__text h3 {
  margin: calc(12.05 * var(--u)) 0 0;
  font-size: var(--fs-panel);
  font-weight: var(--fw-medium);
  line-height: calc(24 * var(--u));
  letter-spacing: -.067em;
}
.panel__text h3::after {          /* short rule x 1299.1–1332.4 at y=770.9 */
  content: "";
  display: block;
  width: calc(33.3 * var(--u));
  height: var(--rule-strong);
  margin: calc(8.25 * var(--u)) 0 0 calc(2.2 * var(--u));
  background: var(--ink);
}
.panel__text p {
  margin: calc(3.75 * var(--u)) 0 0 calc(2.2 * var(--u));
  font-size: var(--fs-body);
  line-height: calc(20 * var(--u));
  letter-spacing: -.059em;
}
.panel__cta {
  display: flex;
  align-items: center;
  gap: calc(4.3 * var(--u));
  height: calc(113.1 * var(--u));
  padding: 0 0 calc(4.6 * var(--u)) calc(32.3 * var(--u));
  border-left: var(--rule-strong) solid var(--ink);
  color: inherit;
  text-decoration: none;
  font-size: var(--fs-panel);
  font-weight: var(--fw-medium);
  line-height: calc(23.8 * var(--u));
  letter-spacing: -.064em;
}
.panel__arrow { width: calc(17.2 * var(--u)); }

/* ---- Empty state (Home: zero published PREFRAMEs) ------------------------ */
.empty { margin: calc(24 * var(--u)); font-size: var(--fs-body); }

/* ---- VERIFY, archivo row size (artboard 3: 819.8–971.3 x 591.3–640.1) ---- */
.btn--row {
  width: calc(151.5 * var(--u));
  height: calc(48.8 * var(--u));
  margin-top: calc(15.8 * var(--u));
  margin-left: calc(-1 * var(--u));
  padding: 0 calc(23.5 * var(--u)) calc(1.5 * var(--u)) calc(22.8 * var(--u));
  border-width: var(--rule-strong);
  font-size: var(--fs-button);
  font-weight: var(--fw-medium);
  letter-spacing: -.016em;
}
.btn--row .btn__arrow { width: calc(17.2 * var(--u)); height: calc(12.8 * var(--u)); }

/* ---- Archivo row (artboard 3: box 52.7–1310.4 x 489.1–708.5) ------------- */
/* Offsets are from the row's inner top (y=491.1). The three dividers stop
   short of the box (y 517.8–685.6), so they are drawn, not borders.
   Ruling R36: a row grows to fit its whole observation. The artboard's
   219.4 is the floor, every offset stays anchored to the top, and the
   dividers keep their 20.9 inset from the bottom edge as the row grows. */
.row {
  position: relative;
  flex: none;
  display: grid;
  grid-template-columns: calc(203.7 * var(--u)) calc(507.1 * var(--u)) calc(262.6 * var(--u)) 1fr;
  min-height: calc(219.4 * var(--u));
  border: var(--rule-strong) solid var(--ink);
}
.row > .xh { --xh-size: calc(19 * var(--u)); }
.row > .xh--tr { top: calc(10.7 * var(--u)); right: calc(12.5 * var(--u)); }     /* centre (1286.1, 511.1) */
.row > .xh--bl { bottom: calc(14.8 * var(--u)); left: calc(11.9 * var(--u)); }   /* centre (75.8, 682.7) */
.row__idcol, .row__textcol, .row__evidence, .row__source { position: relative; min-width: 0; }
.row__textcol::before, .row__evidence::before, .row__source::before {
  content: "";
  position: absolute;
  left: 0;
  top: calc(26.7 * var(--u));
  bottom: calc(20.9 * var(--u));           /* 167.8 tall in a floor-height row */
  width: var(--rule-strong);
  background: var(--ink);
}
.row__num, .row__id, .row__label, .row__src-label, .row__src { margin: 0; }
.row__num {                               /* x 76.1, baseline 537.4 */
  padding: calc(14.2 * var(--u)) 0 0 calc(21.4 * var(--u));
  font-size: var(--fs-rownum);
  font-weight: var(--fw-medium);
  line-height: calc(40 * var(--u));
  letter-spacing: -.013em;
}
.row__mark {                              /* glyph centred near (152, 601) */
  position: absolute;
  left: calc(34.3 * var(--u));
  top: calc(46.9 * var(--u));
  width: calc(126 * var(--u));
  height: calc(126 * var(--u));
  color: var(--ink);
}
/* The bottom padding is the gap under a three-line body in a floor-height
   row, so a longer observation grows the row by exactly its extra lines. */
.row__textcol { padding: calc(23.65 * var(--u)) calc(24 * var(--u)) calc(54 * var(--u)) calc(49.9 * var(--u)); }
.row__id, .row__label {                   /* baselines 529.2 / 562.4 */
  font-size: var(--fs-meta);
  font-weight: var(--fw-medium);
  line-height: calc(20 * var(--u));
  letter-spacing: -.0185em;
}
.row__id::after, .row__label::after {     /* 34.3-wide rule, 6.8 under the line box */
  content: "";
  display: block;
  width: calc(34.3 * var(--u));
  height: var(--rule-strong);
  margin-top: calc(5.55 * var(--u));
  background: var(--ink);
}
.row__body {                              /* baselines 583.4 / 613.4 / 643.5 */
  margin: calc(16.35 * var(--u)) 0 0;
  --row-lh: calc(30 * var(--u));
  /* Never clamped: the row grows to fit (R36). Plex Mono's glyph box is
     1.3em tall, taller than the line box, so the last line's box would hang
     past the paragraph; the padding takes it back inside. */
  padding-bottom: max(0px, (1.3em - var(--row-lh)) / 2);
  font-size: var(--fs-rowbody);
  line-height: var(--row-lh);
  letter-spacing: -.0785em;
}
.row__evidence { padding: calc(56.85 * var(--u)) 0 0 calc(55.3 * var(--u)); }
.row__source { padding: calc(90.65 * var(--u)) calc(16 * var(--u)) 0 calc(46.8 * var(--u)); }
.row__src-label, .row__src {              /* baselines 596.2 / 615.0 */
  font-size: var(--fs-row-src);
  font-weight: var(--fw-medium);
  line-height: calc(18.8 * var(--u));
  letter-spacing: -.0185em;
}

/* ---- Error pages (404/500: no artboard, derived from the system) -------- */
.err {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr);   /* bounded track: long titles wrap instead of overflowing */
  align-content: center;
  justify-items: start;
  gap: calc(28 * var(--u));
  height: 100%;
  padding: calc(24 * var(--u));
}
.err__code { font-size: calc(120 * var(--u)); font-weight: var(--fw-medium);
             line-height: 1; margin: 0; }
/* .err__title reuses .hero (above, "Page title") for its type scale,
   including the narrow-viewport override in responsive.css; only the
   safety net differs here — a long Spanish word must break, not overflow,
   at narrow widths. */
.err__title { margin: 0; overflow-wrap: anywhere; }
.err__note { font-size: var(--fs-standfirst); margin: 0 0 calc(18 * var(--u)); }

/* ---- Pager (Archivo rail; Iconos reuses it) ------------------------------ */
/* Artboard 3: arrows 1405.5 / 1851.2–1868.3, labels 1445.8 / 1604.8 / 1787.4,
   baseline 202.4, rule y=236.5. An unavailable end is drawn exactly like an
   available one (artboard 3 shows PREVIOUS on page 01 at full ink); it is
   simply not a link. */
.pager {
  display: grid;
  grid-template-columns: calc(201.3 * var(--u)) auto 1fr;
  align-items: center;
  padding-bottom: calc(27.6 * var(--u));
  border-bottom: var(--rule-strong) solid var(--ink);
  font-size: var(--fs-pager);
  font-weight: var(--fw-medium);
  line-height: calc(24 * var(--u));
}
.pager__link {
  display: flex;
  align-items: center;
  gap: calc(23.1 * var(--u));
  justify-self: start;
  padding-left: calc(2 * var(--u));
  color: inherit;
  text-decoration: none;
}
.pager__link--next { justify-self: end; gap: calc(22.1 * var(--u)); padding-left: 0; margin-right: calc(-3.6 * var(--u)); }
a.pager__link:hover { text-decoration: underline; text-underline-offset: .2em; text-decoration-thickness: var(--rule); }
.pager__count { margin: 0; }
.pager__arrow {
  flex: none;
  width: calc(17.2 * var(--u));
  height: calc(12.9 * var(--u));
  fill: none;
  stroke: currentColor;
  stroke-width: 1;
  overflow: visible;
}
.pager__arrow path { vector-effect: non-scaling-stroke; }

/* ---- Quiet motion (static/js/motion.js) ----------------------------------
   Every waiting state is scoped to html.motion, which only motion.js sets
   (and never under prefers-reduced-motion), so without the script the page
   is simply drawn. Marks draw like the preloader's: a dash as long as the
   stroke, offset away and back. A redraw runs the line out forwards, then
   draws it in again. None of this moves a box: only dash offsets, clip-paths
   and opacity change. */
.motion .m-draw :is(path, circle, line, polyline, polygon, rect, ellipse) {
  stroke-dasharray: var(--len, 4000) var(--len, 4000);
}
.motion .m-draw.m-wait :is(path, circle, line, polyline, polygon, rect, ellipse) {
  stroke-dashoffset: var(--len, 4000);
}
.motion .m-draw.m-in :is(path, circle, line, polyline, polygon, rect, ellipse) {
  animation: m-draw-in 1.6s cubic-bezier(.45, 0, .25, 1) calc(var(--i, 0) * 60ms) both;
}
.motion .m-draw.m-again :is(path, circle, line, polyline, polygon, rect, ellipse) {
  animation: m-draw-again 4s cubic-bezier(.45, 0, .25, 1) calc(var(--i, 0) * 40ms) both;
}
/* The logo on hover or focus: the same run-out and redraw, brisker. */
.motion .m-draw.m-hover :is(path, circle, line, polyline, polygon, rect, ellipse) {
  animation: m-draw-again 1.2s cubic-bezier(.45, 0, .25, 1) calc(var(--i, 0) * 15ms) both;
}
@keyframes m-draw-in {
  from { stroke-dashoffset: var(--len, 4000); }
  to   { stroke-dashoffset: 0; }
}
@keyframes m-draw-again {
  0%     { stroke-dashoffset: 0; }
  45%    { stroke-dashoffset: calc(-1 * var(--len, 4000)); }
  45.01% { stroke-dashoffset: var(--len, 4000); }
  100%   { stroke-dashoffset: 0; }
}

/* Rules draw left to right once: the hr itself, or a heading's ::after. */
.motion :is(.hero__dashes, .arch__dashes).m-wait,
.motion :is(.ed__head, .ed__step-note).m-wait::after { clip-path: inset(0 100% 0 0); }
.motion :is(.hero__dashes, .arch__dashes).m-in {
  animation: m-rule 1.2s cubic-bezier(.45, 0, .25, 1) .2s both;
}
.motion :is(.ed__head, .ed__step-note).m-in::after {
  animation: m-rule 1.2s cubic-bezier(.45, 0, .25, 1) .3s both;
}
@keyframes m-rule {
  from { clip-path: inset(0 100% 0 0); }
  to   { clip-path: inset(0 0 0 0); }
}

/* PREFRAME symbols surface, a few at a time. */
.motion .m-fade.m-wait { opacity: 0; }
.motion .m-fade.m-in { animation: m-fade .9s ease-out calc(var(--i, 0) * 45ms) both; }
@keyframes m-fade { from { opacity: 0; } to { opacity: 1; } }

@media (prefers-reduced-motion: reduce) {
  .motion .m-wait, .motion .m-wait::after { opacity: 1; clip-path: none; }
  .motion .m-draw :is(path, circle, line, polyline, polygon, rect, ellipse) {
    stroke-dasharray: none; stroke-dashoffset: 0; animation: none;
  }
  .motion .m-in, .motion .m-in::after { animation: none; }
}
