/* La Lampara — tokens and primitives.
 *
 * The whole site follows from one rule: nothing here is shaded, everything is
 * printed twice. The second pass is the same shape in darker pigment, offset
 * and rotated half a degree out of register, the way a hand-painted sign is.
 * It is not a shadow. It must not blur, spread, soften with distance, or move.
 *
 * If you find yourself reaching for a blur radius, a gradient standing in for
 * light, or a translucent panel, that is this identity breaking. See
 * css/design-system.md.
 */

:root {
  /* ── ground. surfaces, never marks ──────────────────────────────
     A saturated Ligurian ochre. The pale tone below is a MARK, not a page:
     limewash laid onto the wall. Inverting that is how this site avoids
     looking like every other warm-cream-and-serif page. */
  --muro: #D9B87A;
  --muro-scuro: #C29A5C;
  --muro-chiaro: #E4C994;
  --calce: #F2E9D4;

  /* ── pigment. marks, never surfaces ─────────────────────────────
     Two reds on purpose: --rosso clears 3:1 on the wall and is for display
     sizes only; anything under 24px uses --rosso-scuro, which clears 4.5:1.
     --ink-spento was #7E6537 until the audit measured it at 2.91:1 behind a
     struck-out species, against a 3:1 floor. Measure, do not eyeball. */
  --ink: #241A10;
  --ink-2: #54401F;
  --ink-spento: #6E5730;
  --rosso: #8E3520;
  --rosso-scuro: #6E2716;
  --verde: #2F4F3A;

  /* food, drawn only — these never carry text, so they answer to legibility
     against each other rather than to a contrast ratio */
  --rosso-cupo: #7C2C18;
  --corallo: #B4553A;
  --argento: #9AA2A0;
  --perla: #E3DCCB;
  --viola: #C9B6C6;
  --burro: #E0C88E;
  --ocra: #A8681C;
  --oliva: #4A5230;

  /* ── the second pass ────────────────────────────────────────────
     Neither ground nor pigment. One value, one offset, everywhere. */
  --passata: rgba(58, 32, 12, .34);
  --passo: 9px;
  --passo-y: 11px;

  --font-display: Fraunces, Georgia, serif;
  --font-body: Karla, system-ui, sans-serif;

  /* multiples of four. an arbitrary 13px is a tell */
  --s1: 4px;  --s2: 8px;  --s3: 12px; --s4: 16px; --s5: 24px;
  --s6: 32px; --s7: 48px; --s8: 64px; --s9: 96px; --s10: 128px;

  --misura: 66ch;          /* prose measure, inside the 45–75ch band */
  --larghezza: 1180px;
}

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

/* clip, never hidden: hidden would break the fixed grain layer */
html, body { overflow-x: clip; }

html { -webkit-text-size-adjust: 100%; }

body {
  background: var(--muro);
  color: var(--ink);
  font: 400 17px/1.6 var(--font-body);
  position: relative;
  min-height: 100vh;
}

/* Instant, never faded in — a keyboard user needs the indicator now. */
:focus-visible {
  outline: 3px solid var(--rosso-scuro);
  outline-offset: 3px;
}

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

a { color: var(--rosso-scuro); }

::selection { background: var(--rosso); color: var(--calce); }

/* ── the grain ────────────────────────────────────────────────────
   Plaster, generated rather than photographed, and same-origin so it costs
   the CSP nothing. */
.grana {
  position: fixed;
  inset: 0;
  z-index: 30;
  pointer-events: none;
  opacity: .6;
  mix-blend-mode: multiply;
}

/* ── printed twice ────────────────────────────────────────────────
   Two copies of the same text; the under-copy is the first pass. */
.doppia { position: relative; display: inline-block; }
.doppia .sotto {
  position: absolute;
  left: 0;
  top: 0;
  color: var(--passata);
  transform: translate(var(--passo), var(--passo-y)) rotate(.5deg);
  transform-origin: 0 100%;
  user-select: none;
}
.doppia .sopra { position: relative; }

/* Anything with a body rather than a shape gets the same treatment as a
   hard offset. Never a box-shadow with blur. */
.stampato { box-shadow: var(--passo) var(--passo-y) 0 var(--passata); }

/* The offset is a constant in pixels, so on display sizes it lands proportionally
   smaller and on the wordmark it would otherwise read as a blur rather than a
   second pass. The wordmark gets its own, tighter. */
.marchio .sotto { transform: translate(5px, 6px) rotate(.4deg); }

/* ── type ─────────────────────────────────────────────────────────
   Fraunces does the work a third family would otherwise do: opsz 144 for the
   wordmark down to opsz 9 for the eyebrows. No italic on display type, ever
   — an italicised word inside upright display is one of the loudest tells
   there is. Emphasis comes from weight and from --rosso-scuro. */
h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-style: normal;
  font-weight: 600;
  line-height: 1.1;
  letter-spacing: -.02em;
  overflow-wrap: anywhere;
  min-width: 0;
  font-variation-settings: "SOFT" 50, "WONK" 1, "opsz" 60;
}
h1 { font-size: clamp(34px, 4.6vw, 60px); }
h2 { font-size: clamp(26px, 3.2vw, 40px); }
h3 { font-size: clamp(20px, 2vw, 25px); font-weight: 500; }
h4 { font-size: 19px; font-weight: 500; }

p, li { max-width: var(--misura); }

.occhiello {
  font-family: var(--font-display);
  font-size: 12.5px;
  letter-spacing: .34em;
  text-transform: uppercase;
  color: var(--ink-2);
  font-variation-settings: "opsz" 9;
}

.nota { color: var(--ink-2); font-size: 15.5px; }

/* ── the one button ───────────────────────────────────────────────
   Eight states live here so no component has to reinvent them. */
.bottone {
  display: inline-block;
  background: var(--rosso-scuro);
  color: var(--calce);
  font: 700 15px/1 var(--font-body);
  letter-spacing: .04em;
  padding: var(--s4) var(--s5);
  text-decoration: none;
  border: 0;
  cursor: pointer;
  white-space: nowrap;
  box-shadow: var(--passo) var(--passo-y) 0 var(--passata);
}
.bottone:hover { background: var(--rosso); }
.bottone:active { box-shadow: 4px 5px 0 var(--passata); }
.bottone[disabled], .bottone[aria-disabled="true"] {
  opacity: .55;
  cursor: not-allowed;
  background: var(--ink-spento);
}

.bottone-piano {
  background: none;
  color: var(--rosso-scuro);
  box-shadow: none;
  /* a <button> carries a default border; .bottone kills it, so this must too
     or the flat variant renders as a box */
  border: 0;
  border-bottom: 3px solid var(--rosso-scuro);
  padding: var(--s2) 0;
}
.bottone-piano:hover { background: none; color: var(--rosso); border-color: var(--rosso); }

/* ── layout ───────────────────────────────────────────────────────*/
.wrap { max-width: var(--larghezza); margin: 0 auto; padding: 0 var(--s7); }
@media (max-width: 520px) { .wrap { padding: 0 var(--s5); } }

.solo-lettori {
  position: absolute;
  width: 1px; height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.salta {
  position: absolute;
  left: var(--s5);
  top: -100px;
  z-index: 40;
  background: var(--rosso-scuro);
  color: var(--calce);
  padding: var(--s3) var(--s5);
  font-weight: 700;
  text-decoration: none;
}
.salta:focus { top: var(--s3); }

/* ── the plate ────────────────────────────────────────────────────
   Flat planes stacked along Z. The unit on --z is not optional: a unitless
   value makes translateZ() invalid, the transform computes to none, the layer
   leaves the preserve-3d context and Firefox paints it un-rotated a thousand
   pixels away — with getBoundingClientRect still reporting the right box.
   And do not put transform-style: preserve-3d on .strato: it flattens the
   whole stack. Anything that must counter-rotate lives outside .scena. */
.scena { perspective: 1250px; perspective-origin: 50% 40%; }
.piatto {
  transform-style: preserve-3d;
  transform: rotateX(58deg) rotateZ(-20deg);
  width: min(320px, 70vw);
  aspect-ratio: 1;
  position: relative;
  margin: 0 auto;
}
.strato { position: absolute; inset: 0; transform: translateZ(var(--z)); }
.strato svg { width: 100%; height: 100%; overflow: visible; }

/* The offsets are keyed by position in the stack rather than written into a
   style attribute, because `style-src 'self'` refuses inline styles — which
   would leave --z empty and trigger exactly the failure described above.
   Counted with :nth-child, never :nth-of-type: that counts per tag name, so a
   div among the layers would be both unreachable and wrongly first. */
.strato:nth-child(1) { --z: 0px; }
.strato:nth-child(2) { --z: 34px; }
.strato:nth-child(3) { --z: 74px; }
.strato:nth-child(4) { --z: 110px; }

/* The shelf the plate sits on: painted, and its second pass is the only thing
   under it. */
.mensola { height: 10px; background: var(--muro-scuro); margin: -44px 10px 0; position: relative; }
.mensola::after {
  content: "";
  position: absolute;
  left: var(--passo); right: calc(var(--passo) * -1);
  top: 100%; height: 10px;
  background: var(--passata);
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
  }
}
