/* ============================================================
   WOODY'S — base.css
   Reset · self-hosted Graduate + Space Mono · design tokens ·
   ONE fixed brand palette sampled from the logo (§1.2) · surface
   law (§1.3) · base element styles · layout primitives ·
   utilities · hand-drawn underline · letter-reveal system ·
   keyframes · reduced-motion guard (last).
   Everything self-hosted & root-relative. Zero external calls.
   ============================================================ */

/* ---------- 1. Self-hosted fonts (both OFL) ----------
   Graduate = collegiate/varsity display, chosen to answer the
   block lettering in the logo. Space Mono carries body, prices
   and hours — a mono column is right for a bar menu. */
@font-face{
  font-family:'Graduate';
  font-style:normal;
  font-weight:400;
  font-display:swap;
  src:url('/assets/fonts/graduate-400.woff2') format('woff2');
}
@font-face{
  font-family:'Space Mono';
  font-style:normal;
  font-weight:400;
  font-display:swap;
  src:url('/assets/fonts/space-mono-400.woff2') format('woff2');
}
@font-face{
  font-family:'Space Mono';
  font-style:normal;
  font-weight:700;
  font-display:swap;
  src:url('/assets/fonts/space-mono-700.woff2') format('woff2');
}
@font-face{
  font-family:'Space Mono';
  font-style:italic;
  font-weight:400;
  font-display:swap;
  src:url('/assets/fonts/space-mono-400-italic.woff2') format('woff2');
}
@font-face{
  font-family:'Space Mono';
  font-style:italic;
  font-weight:700;
  font-display:swap;
  src:url('/assets/fonts/space-mono-700-italic.woff2') format('woff2');
}

/* ---------- 2. Reset ---------- */
*,*::before,*::after{ box-sizing:border-box; }
*{ margin:0; }
html{
  -webkit-text-size-adjust:100%;
  text-size-adjust:100%;
  font-size:100%;                 /* 16px base — no 10px trick */
}
body{
  min-height:100svh;
  -webkit-font-smoothing:antialiased;
  text-rendering:optimizeLegibility;
}
img,picture,svg,video,canvas{ display:block; max-width:100%; }
svg{ height:auto; }
input,button,textarea,select{ font:inherit; color:inherit; }
button{ background:none; border:0; cursor:pointer; color:inherit; }
a{ color:inherit; text-decoration:none; }
ul,ol{ list-style:none; padding:0; }
table{ border-collapse:collapse; width:100%; }
h1,h2,h3,h4,h5,h6{ font-size:inherit; font-weight:inherit; line-height:inherit; }
:where(p,li){ text-wrap:pretty; }

/* ---------- 3. Design tokens ---------- */
:root{
  /* font stack */
  --font-mono:'Space Mono', ui-monospace, 'Cascadia Mono', 'Courier New', monospace;
  --font-display:'Graduate', 'Space Mono', ui-monospace, 'Courier New', monospace;

  /* fluid type scale */
  --fs-display:clamp(3rem, 9vw, 8rem);
  --fs-h1:clamp(2rem, 5vw, 3.5rem);
  --fs-h2:clamp(1.5rem, 3vw, 2.25rem);
  --fs-lead:clamp(1.125rem, 1.5vw, 1.5rem);
  --fs-body:clamp(1rem, .92rem + .4vw, 1.125rem);
  --fs-sm:.8125rem;

  /* spacing scale (rem) -> 4..160px */
  --sp-1:.25rem;  --sp-2:.5rem;  --sp-3:.75rem; --sp-4:1rem;
  --sp-5:1.5rem;  --sp-6:2rem;   --sp-7:3rem;   --sp-8:4rem;
  --sp-9:6rem;    --sp-10:8rem;  --sp-11:10rem;

  /* radii */
  --radius-card:1.25rem;
  --radius-pill:999px;

  /* signature stroke */
  --stroke:3px;

  /* timing (§1.4) */
  --dur-blink:.5s;  --dur-pop:.4s;   --dur-bounce:.6s; --dur-spin:6s;
  --dur-frost:.3s;  --dur-reveal:.45s;
  --stagger:.1s;    /* letter reveal step; page titles override to .05s */

  /* chrome metrics (§1.4) */
  --marquee-h:2.75rem;

  /* z-index ladder (§1.4) */
  --z-loader:9999; --z-menu:950; --z-nav:700;
  --z-wordmark:600; --z-hoverimg:640; --z-sticky:500; --z-marquee:400; --z-badge:60;

  /* brand palette — sampled from assets/img/logo/woodys-logo.png (§1.2).
     ONE fixed look; there is no theme cycle. Every surface/text pair in
     the surface law below clears WCAG AA (worst 4.81 — red on bone). */
  --ink:#12100E;      /* logo black #030202, warmed off dead black */
  --bone:#FBF6EC;     /* logo white #FEFEFE, warmed to the paper */
  --gold:#EDB20A;     /* logo beak #FDCF03, deepened for large areas */
  --red:#D4231A;      /* logo flame #F30301, tamed for large areas */
  --rust:#8B3C05;     /* logo letter outlines #7E3505–#944005 */
  --maroon:#7A1B07;   /* the "2.0" */
  --cream:#F5E7CE;    /* light band, tinted off the gold */

  /* default foreground = ink (constant text on light surfaces) */
  --fg:var(--ink);

  /* surface roles — fixed, no longer swapped per load */

  /* PAGE GROUND — the DEFAULT. Was --gold until 2026-08-27; the owner did not
     want the orange/yellow (D38), and then asked for a different ground per page
     (D39, below). This default covers 404.html and the unlinked item template.
     index.html never shows it — it bands every section.
     GOLD IS NOT RETIRED — it is still the hero CTA's hover (pages.css). */
  --bg:var(--cream);
  --band-a:var(--cream);
  --band-b:var(--ink);
  --dark:var(--maroon);
}

/* page background is painted from the same token, pre-paint, no bootstrap */
html{ background:var(--bg); }

/* ---------- 3b. PER-PAGE GROUND (§D39) ----------
   One ground per page, each picked for what the page DOES rather than for
   variety's sake:

     /menu/   --cream  warm paper. The menu sheet is --bone, so the ground has
                       to be a shade DARKER or the sheet stops reading as a
                       sheet. Cream is the only light token that does that.
     /events/ --ink    night. The bone cards punch hardest on it, and it stays
                       distinct from the maroon footer below (maroon would have
                       merged the two into one dark slab).
     /visit/  --bone   clean and practical — hours, address, phone, map.

   Set on BOTH the html and the body:
     - `html:has(...)` colours the real page ground, including the overscroll
       area past the footer.
     - `body.x` is the belt-and-braces half: `body` already paints `var(--bg)`,
       so if :has() ever fails the page body is still right and only the
       overscroll gutter falls back to cream.
   No HTML changes are needed for the ground itself; every page already carries
   its own body class.
   ⚠️ /events/ ALSO needs `band--b` on its <section> — that is what flips its
   text, selection, focus rings and underlines to bone. The ground token alone
   would leave ink text on an ink page. */
body.menu,   html:has(body.menu)   { --bg:var(--cream); }
body.events, html:has(body.events) { --bg:var(--ink); }
body.visit,  html:has(body.visit)  { --bg:var(--bone); }

/* The corner menu button is a SOLID ink pill with an ink border, so on the ink
   ground it disappeared completely — only the bone icon strokes were left
   floating with no pill around them. Invert it, exactly as the hero already
   inverts its solid CTA on a dark band (pages.css): bone pill, ink icon.
   Only the ink page needs this; on cream and bone the ink pill is correct. */
body.events .corner-menu{
  background:var(--bone);
  border-color:var(--bone);
  color:var(--ink);
}
.can-hover body.events .corner-menu:hover{
  background:var(--gold);
  border-color:var(--gold);
  color:var(--ink);
}

/* ---------- 4. SURFACE LAW (§1.3) ----------
   Surfaces are LIGHT (--bg, --band-a, bone) or DARK (--band-b, --dark,
   ink fills). Text on LIGHT is ink; text on DARK is bone. */
.band--a{ background:var(--band-a); }
.band--b{ background:var(--band-b); }
.band--dark, footer{ background:var(--dark); }
.band--b, .band--dark, footer{ --fg:var(--bone); color:var(--bone); }

/* ---------- 5. Base element styles ---------- */
body{
  font-family:var(--font-mono);
  font-size:var(--fs-body);
  line-height:1.5;
  background:var(--bg);
  color:var(--fg);
}
p{ line-height:1.6; }
strong,b{ font-weight:700; }
em,i{ font-style:italic; }
small{ font-size:var(--fs-sm); }
::selection{ background:var(--ink); color:var(--bone); }

/* dark surfaces flip selection for legibility */
.band--b ::selection, .band--dark ::selection, footer ::selection{ background:var(--bone); color:var(--ink); }

/* visible keyboard focus everywhere — ink on light, bone on dark */
:focus-visible{ outline:var(--stroke) solid var(--ink); outline-offset:3px; }
.band--b :focus-visible, .band--dark :focus-visible, footer :focus-visible{ outline-color:var(--bone); }

/* skip link for keyboard users */
.skip-link{
  position:absolute; left:var(--sp-3); top:-999px;
  z-index:var(--z-loader);
  background:var(--ink); color:var(--bone);
  padding:var(--sp-2) var(--sp-4);
  border-radius:var(--radius-pill);
  font-weight:700; text-transform:uppercase; letter-spacing:.02em;
}
.skip-link:focus{ top:var(--sp-3); }

/* ---------- 6. Layout primitives ---------- */
.wrap{
  width:100%;
  max-width:1200px;
  margin-inline:auto;
  padding-inline:clamp(1.25rem, 4vw, 4rem);
}
.wrap--wide{ max-width:1440px; }
.wrap--narrow{ max-width:820px; }

/* generic vertical section rhythm (4–10rem) */
.section{ padding-block:clamp(var(--sp-8), 8vw, var(--sp-11)); }
.section--tight{ padding-block:clamp(var(--sp-6), 5vw, var(--sp-8)); }

/* ---------- 7. Typographic utilities ----------
   Display type is Graduate. It ships a single weight, so these carry
   font-weight:400 deliberately — asking for 700 makes the browser
   synthesise a smeared fake bold over an already-heavy collegiate face.
   Weight comes from size and caps, not from the bold button. */
.t-display{
  font-family:var(--font-display);
  font-size:var(--fs-display); line-height:.95;
  font-weight:400; letter-spacing:.01em; text-transform:uppercase;
}
.t-h1{
  font-family:var(--font-display);
  font-size:var(--fs-h1); line-height:1.06;
  font-weight:400; letter-spacing:.015em; text-transform:uppercase;
}
.t-h2{
  font-family:var(--font-display);
  font-size:var(--fs-h2); line-height:1.14;
  font-weight:400; letter-spacing:.02em; text-transform:uppercase;
}
.t-lead{ font-size:var(--fs-lead); line-height:1.4; }
.t-sm{ font-size:var(--fs-sm); line-height:1.4; }
.u-bold{ font-weight:700; }
.u-caps{ text-transform:uppercase; letter-spacing:.02em; }
.u-center{ text-align:center; }
.u-italic{ font-style:italic; }

/* visually-hidden but screen-reader available */
.sr-only{
  position:absolute!important; width:1px; height:1px;
  padding:0; margin:-1px; overflow:hidden;
  clip:rect(0,0,0,0); white-space:nowrap; border:0;
}

/* ---------- 8. Hand-drawn underline (<u> / .u-mark / .u-wave) ---------- */
/* Chunky marker underline — clones across wrapped lines, wobble-friendly. */
u,.u-mark{
  text-decoration:none;
  background:linear-gradient(var(--ink),var(--ink)) no-repeat;
  background-position:0 100%;
  background-size:100% .16em;
  padding-bottom:.06em;
  -webkit-box-decoration-break:clone;
  box-decoration-break:clone;
}
/* on dark surfaces the marker uses bone so it stays visible */
.band--b u, .band--b .u-mark,
.band--dark u, .band--dark .u-mark,
footer u, footer .u-mark{
  background-image:linear-gradient(var(--bone),var(--bone));
}
/* wavy variant — native hand-inked squiggle */
.u-wave{
  text-decoration-line:underline;
  text-decoration-style:wavy;
  text-decoration-color:var(--ink);
  text-decoration-thickness:2px;
  text-underline-offset:.28em;
  background:none;
  padding-bottom:0;
}
.band--b .u-wave, .band--dark .u-wave, footer .u-wave{ text-decoration-color:var(--bone); }

/* ---------- 9. Letter-reveal system (§B16) ----------
   .ltr = one letter (HTML span or SVG <g>). Carries --i (stagger index)
   and optional art-direction vars --tx/--rot/--dy (hero wordmark).
   Hidden only when JS is running and the reveal hasn't fired; the
   ltr-bail dead-man forces letters visible at 4.5s no matter what. */
.ltr{
  display:inline-block;
  transform:translate(var(--tx,0px),var(--dy,0px)) rotate(var(--rot,0deg));
  transform-box:fill-box;
  transform-origin:50% 50%;
}
.js body:not(.revealed) .ltr{
  opacity:0;
  animation:ltr-bail 0s 4.5s linear forwards;
}
.js body.revealed .ltr{
  animation:pop-reveal var(--dur-pop) ease-out both;
  animation-delay:calc(var(--i,0)*var(--stagger));
}
@media (prefers-reduced-motion:no-preference){ html{ scroll-behavior:smooth; } }

/* ---------- 10. Keyframes (§1.5 — the full inventory) ---------- */
/* Bottoms out at 0 — a hard on/off blink, like a neon sign.
   It floored at .22 for a while (D17) to stop a label being stranded faded when
   the pointer left. That was the wrong fix: it treated the symptom, the strand
   still happened, and it turned the tell into a dim instead of a blink. The
   real cause was that a blinking element's RESTING opacity was owned by another
   animation's fill rather than by the cascade — see .overlay-menu__link in
   components.css. With that corrected, every element that blinks has a plain,
   unanimated resting opacity of 1, so releasing the pointer restores it
   unconditionally and this can safely go all the way to 0 again. See D28. */
@keyframes blink{ 0%,49%{ opacity:1 } 50%,100%{ opacity:0 } }

@keyframes pop{ 0%,100%{ transform:scale(1) } 50%{ transform:scale(1.14) } }

@keyframes bounce{ 0%,100%{ transform:translateY(0) } 50%{ transform:translateY(-12%) } }

/* `spin` was removed 2026-08-27 (D34) with its only user, the drawn map's
   compass rose. Re-add it if something needs a rotation again — it was
   `to{ transform:rotate(360deg) }`. */

/* letter build — every frame carries the art-direction vars so the
   pop composes with each letter's pinned offset/rotation */
@keyframes pop-reveal{
  0%{   opacity:0; transform:translate(var(--tx,0px),calc(var(--dy,0px) + 14px)) rotate(var(--rot,0deg)) scale(.55); }
  60%{  opacity:1; transform:translate(var(--tx,0px),var(--dy,0px)) rotate(var(--rot,0deg)) scale(1.14); }
  100%{ opacity:1; transform:translate(var(--tx,0px),var(--dy,0px)) rotate(var(--rot,0deg)) scale(1); }
}

@keyframes rise-in{
  from{ opacity:0; transform:translateY(14px) scale(.98); }
  to{   opacity:1; transform:none; }
}

/* Same movement, NO opacity. For elements that also blink on hover: if their
   entrance animates opacity with a fill, that fill becomes the resting value,
   and anything that disturbs the animation strands them faded. Leaving opacity
   alone here keeps the resting value in the cascade, where it cannot be
   stranded. Only the overlay menu links need this today (D28). */
@keyframes rise-in-y{
  from{ transform:translateY(14px) scale(.98); }
  to{   transform:none; }
}

@keyframes marquee{ to{ transform:translateX(-100%) } }

/* dead-man switches (§1.10) — survive a woody.js failure */
@keyframes loader-bail{ to{ opacity:0; visibility:hidden; } }
@keyframes ltr-bail{ to{ opacity:1; } }

/* ---------- 11. Reduced-motion guard (stays last) ---------- */
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{
    animation-duration:.001ms!important;
    animation-iteration-count:1!important;
    animation-delay:0ms!important;
    transition-duration:.001ms!important;
    scroll-behavior:auto!important;
  }
}
