@charset "UTF-8";

/* ============================================================
   THE DISPLAY FACE — Molen Surplus (Nurrontype), self-hosted
   Subset to the glyphs it can actually set: this display cut carries no
   umlauts, so Düsseldorf, Köln and Mülheim fall through per character to the
   next family in --font-display. That fallback is the design, not an accident.
   LOCAL BUILD ONLY — "personal use" as downloaded; a commercial licence is a
   release blocker (docs/design-T4-site.md). font-src 'self' already covers it.
   ============================================================ */
@font-face{
  font-family:"Molen Surplus";
  src:url("fonts/molen-surplus.woff2") format("woff2");
  font-weight:400; font-style:normal; font-display:swap;
}

/* San Toremi (Muflieart) carries everything the display face does not: the
   chips, the buttons, the card detail, the footer. It has the umlauts the
   display cut lacks, so German text sets in one face throughout. */
@font-face{
  font-family:"San Toremi";
  src:url("fonts/san-toremi.woff2") format("woff2");
  font-weight:400; font-style:normal; font-display:swap;
}

/* Metaldar — public site styles.
   Extracted from the prototype so the CSP needs no 'unsafe-inline' (R-S3).
   Tokens, type ramp and spacing scale are documented in SITE.md.
   One palette per colour mode: papier (light), ember (dark). */

/* ============================================================
   PALETTES — five, not nine. Three light, two warm dark.
   A switcher with nine options is indecision; this is a direction.
   Every text pair is verified against WCAG 2.1 AA by the live
   contrast table at the foot of the page.

   Light grounds are warm paper, never clinical white. The two dark
   options are soft brown and charcoal — no pure black anywhere.
   ============================================================ */

/* --- PAPIER : beige ground, oxblood, serif. Fanzine, not dashboard.
       The colours Alex picked out, set like print. DEFAULT. --- */
:root{
  /* Dark ground, one amber accent, air around oversized type — from the
     reference the PO supplied. Hexes live only in the palette blocks (SITE.md);
     contrast for both modes is asserted in tools/check-site.py. */
  --bg:#0E0C0B; --surface:#171413; --raised:#221D1B;
  --text:#F3ECE3; --muted:#A79C90;
  --accent:#E8A33C; --accent-ink:#171413;
  --hot:#D8552F; --hot-ink:#171413;
  --line:#2A2422; --line-strong:#6C625A;
  --flag-dead:#E8756A; --flag-gone:#A79C90;
  --focus:#E8A33C; --bg-fade:rgba(14,12,11,.86);
  --font-display:"Iowan Old Style","Palatino Linotype",Palatino,Georgia,"Times New Roman",serif;
  --font-wordmark:Didot,"Bodoni 72","Bodoni MT","Playfair Display",Palatino,Georgia,serif;
  --display-weight:700; --display-tracking:-0.02em; --display-transform:none;
  --radius:12px; --radius-pill:999px; --card-pad:0px;
}
/* --- TERRAKOTTA : warm off-white, clay red, clean sans. --- */

/* --- OCKER : cream ground, burnt ochre, compact uppercase. Poster. --- */

/* --- EMBER : the light set inverted. Soft brown-black, brick, beige. --- */
@media (prefers-color-scheme: light){
  /* Papier — the editorial direction's light set, for readers whose system asks
     for light. Same roles, warm paper ground. */
  :root{
  --bg:#F4EDE1; --surface:#FBF7F0; --raised:#EAE0CE;
  --text:#1C1714; --muted:#5A5047;
  --accent:#8A1A12; --accent-ink:#FFFFFF;
  --hot:#A03A08; --hot-ink:#FFFFFF;
  --line:#DCD1BE; --line-strong:#8A7D6B;
  --flag-dead:#8A1A12; --flag-gone:#5A5047;
  --focus:#1C1714; --bg-fade:rgba(244,237,225,.82);
  --font-wordmark:Didot,"Bodoni 72","Bodoni MT","Playfair Display",Palatino,Georgia,serif;
  --font-display:"Iowan Old Style","Palatino Linotype",Palatino,Georgia,"Times New Roman",serif;
  --display-weight:700; --display-tracking:-0.015em; --display-transform:none;
  --radius:12px; --radius-pill:999px; --card-pad:0px;
  }
}
/* --- NACHT : lifted charcoal-brown, clay. The softest dark. --- */

/* ============================================================
   TOKENS
   An audit of the previous revision found ~15 distinct font sizes,
   13 padding values, 9 gaps and 10 letter-spacings, all arbitrary.
   That is what "the font sizes are all over the place" looks like
   in the source. Everything below is now one of these values.

   TYPE — six steps, each with one job.
     --t-logo     masthead only
     --t-act      band name. The loudest thing on a card, by a margin.
     --t-section  group headers (Tonight, This weekend, Week of ...)
     --t-primary  venue name, date number. "Where and when."
     --t-second   genre, support, price, hostname. Supporting detail.
     --t-micro    status, weekday labels, counts. These qualify,
                  they do not announce.

   Reading order on a card is therefore unambiguous:
     band name -> where and when -> supporting detail -> qualifiers.

   SPACE — 4px base, six steps. No arbitrary values.
   ============================================================ */
:root{
  --t-act:22px; --t-section:17px; --t-primary:15px; --t-second:12.5px; --t-micro:10px;
  --lh-tight:1.12; --lh-snug:1.3; --lh-body:1.45;

  --s1:4px; --s2:8px; --s3:12px; --s4:16px; --s5:24px; --s6:32px;

  --tr-tight:-.02em; --tr-wide:.14em;

  --ease:cubic-bezier(.2,.75,.3,1); --dur:190ms;
}
@media (min-width:1024px){ :root{ --t-act:25px; --t-section:19px; } }

/* ============================================================
   BASE
   ============================================================ */
*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
body{margin:0;background:var(--bg);color:var(--text);
  font:400 var(--t-primary)/var(--lh-body) -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
  -webkit-font-smoothing:antialiased;padding-bottom:env(safe-area-inset-bottom)}
a{color:inherit}
:focus-visible{outline:3px solid var(--focus);outline-offset:2px}
.shell{max-width:1500px;margin:0 auto;padding:0 var(--s4)}
.sr{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
.skip{position:absolute;left:-9999px}
.skip:focus{left:var(--s4);top:var(--s2);z-index:60;background:var(--accent);color:var(--accent-ink);
  padding:var(--s3) var(--s4);position:fixed}

/* ---------- palette switcher (prototype chrome only) ---------- */
.switch{position:sticky;top:0;z-index:50;background:var(--surface);border-bottom:1px solid var(--line)}
.switch-inner{display:flex;gap:var(--s2);align-items:center;padding:var(--s2) var(--s4);
  overflow-x:auto;-webkit-overflow-scrolling:touch}
.switch-label{font:700 var(--t-micro)/1 inherit;letter-spacing:var(--tr-wide);text-transform:uppercase;
  color:var(--muted);flex:0 0 auto}
.swatch{flex:0 0 auto;display:flex;align-items:center;gap:var(--s2);min-height:44px;padding:var(--s2) var(--s3);
  cursor:pointer;background:transparent;color:var(--text);border:1px solid var(--line-strong);
  border-radius:var(--radius-pill);font:600 var(--t-second)/1 inherit;white-space:nowrap}
.swatch[aria-pressed="true"]{background:var(--accent);color:var(--accent-ink);border-color:var(--accent)}

/* ---------- masthead ---------- */
header.mast{padding:var(--s6) 0 var(--s5)}
.logo{margin:0;font-family:var(--font-wordmark);font-weight:var(--display-weight);
  letter-spacing:-0.045em;text-transform:var(--display-transform);
  font-size:clamp(52px,15vw,136px);line-height:.84}
.tagline{margin:var(--s2) 0 0;color:var(--muted);font-size:var(--t-second);max-width:46ch}
.stamp{margin:var(--s2) 0 0;color:var(--muted);font-size:var(--t-micro);letter-spacing:.04em;
  text-transform:uppercase;font-weight:700}
.stamp b{color:var(--text)}
.stale{margin:var(--s3) 0 0;padding:var(--s2) var(--s3);border-radius:var(--radius);
  border:1px solid var(--flag-dead);color:var(--text);font-size:var(--t-second);font-weight:600}

/* ============================================================
   LAYOUT
   <640   one column, filters pinned to the top
   >=1024 sticky left rail: filters + jump nav, always in view
   >=1400 third column: the updates panel, always open

   Desktop does NOT widen the cards or grid them. Chronology is
   one-dimensional and a card grid breaks it into a Z-shaped scan;
   a 1400px-wide card is worse than a narrow one. The extra width
   goes to the two rails instead, so filters and recent changes are
   permanently visible while the list stays a readable column.
   ============================================================ */
.layout{display:block}

.filters{position:sticky;top:var(--h-switch,58px);z-index:40;background:var(--bg);
  border-bottom:1px solid var(--line);padding:var(--s2) 0}
@supports (backdrop-filter:blur(2px)){
  .filters{background:var(--bg-fade);backdrop-filter:blur(14px) saturate(140%)}
}
.chips{display:flex;gap:var(--s2);overflow-x:auto;-webkit-overflow-scrolling:touch;
  margin:0 calc(var(--s4) * -1);padding:0 var(--s4) 2px}
.chip{flex:0 0 auto;display:inline-flex;align-items:center;min-height:44px;padding:0 var(--s3);
  cursor:pointer;background:transparent;color:var(--text);border:1px solid var(--line-strong);
  border-radius:var(--radius-pill);font:600 var(--t-second)/1 inherit;white-space:nowrap}
.chip[aria-pressed="true"]{background:var(--accent);color:var(--accent-ink);border-color:var(--accent)}
.count{margin:var(--s2) 0 0;font-size:var(--t-second);color:var(--muted)}

.bucketnav{display:none}
.bucketnav h2{font:700 var(--t-micro)/1 inherit;letter-spacing:var(--tr-wide);text-transform:uppercase;
  color:var(--muted);margin:0 0 var(--s2)}
.bucketnav a{display:flex;justify-content:space-between;align-items:center;gap:var(--s2);
  min-height:36px;padding:0 var(--s2);border-radius:var(--radius);text-decoration:none;
  font-size:var(--t-second);color:var(--muted);border:1px solid transparent}
.bucketnav a .n{font-variant-numeric:tabular-nums}
.bucketnav a.is-current{color:var(--accent-ink);background:var(--accent);font-weight:700}

/* ---------- group headers ---------- */
.bucket-block{scroll-margin-top:calc(var(--h-stack,118px) + var(--s3))}
.bucket{position:sticky;top:var(--h-stack,118px);z-index:30;background:var(--bg);
  margin:0;padding:var(--s5) 0 var(--s2);border-bottom:1px solid var(--line);
  font-family:var(--font-display);font-weight:var(--display-weight);
  letter-spacing:var(--display-tracking);text-transform:var(--display-transform);
  font-size:var(--t-section);display:flex;justify-content:space-between;align-items:baseline;gap:var(--s3)}
.bucket .n{font-family:inherit;font:700 var(--t-micro)/1 inherit;color:var(--muted);
  letter-spacing:var(--tr-wide);text-transform:uppercase}
.list{display:grid;grid-template-columns:1fr;gap:var(--s2);padding:var(--s3) 0 var(--s1)}

/* ---------- gig card ----------
   Restored to the earlier treatment Alex preferred: a real card with
   its own ground, a border and generous internal padding. The flattened
   aligned rows scanned marginally faster and looked considerably worse.
   Separation between entries is what made the earlier version read as
   clean, so the card wins where the two conflict. */
.gig{display:grid;grid-template-columns:52px minmax(0,1fr);
  grid-template-areas:"date body" "foot foot";gap:var(--s1) var(--s3);
  background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);
  padding:var(--s4);scroll-margin-top:calc(var(--h-stack,118px) + var(--s3))}
.gig.is-cancelled{border-style:dashed;opacity:.8}
.gig.is-target{border-color:var(--accent);box-shadow:0 0 0 1px var(--accent)}

.date{grid-area:date;min-width:0;text-align:center;padding-top:2px}
.date .d{display:block;font:600 var(--t-primary)/1.1 inherit;color:var(--text);
  font-variant-numeric:tabular-nums;letter-spacing:-.01em}
.date .d.range{font-size:var(--t-second);letter-spacing:var(--tr-tight)}
.date .w,.date .m{display:block;font:700 var(--t-micro)/1 inherit;letter-spacing:var(--tr-wide);
  text-transform:uppercase;color:var(--muted);margin-top:var(--s1)}

.body{grid-area:body;min-width:0}
.head{display:flex;align-items:baseline;gap:var(--s2)}
.act{margin:0;flex:1 1 auto;min-width:0;font-family:var(--font-display);font-weight:var(--display-weight);
  letter-spacing:var(--display-tracking);text-transform:var(--display-transform);
  font-size:var(--t-act);line-height:var(--lh-tight);overflow-wrap:anywhere;hyphens:auto}
.is-cancelled .act{text-decoration:line-through;text-decoration-thickness:2px;color:var(--muted)}

/* Status has to be noticeable, not large — it changes whether you would go
   at all. A tracked micro word in a distinct colour does that without
   competing with the headliner. No fill, no pill. The strike-through on a
   cancelled title is the non-colour cue, so this never relies on hue alone. */
.flags{flex:0 0 auto;display:flex;align-items:baseline;gap:var(--s2)}
.flag{font:700 var(--t-micro)/1 inherit;letter-spacing:var(--tr-wide);text-transform:uppercase;white-space:nowrap}
.flag.dead{color:var(--flag-dead)}
.flag.gone{color:var(--flag-gone)}

/* Venue name carries the maps link. City is small plain text beside it,
   not a chip — it is not the primary filter control, so it need not look
   tappable. The 44px hit area belongs to the link, not to a visible box. */
.where{margin:var(--s1) 0 0;font-size:var(--t-primary);line-height:var(--lh-snug)}
.where .vname{color:var(--text);font-weight:600;text-decoration:underline;
  text-underline-offset:2px;text-decoration-color:var(--line-strong)}
.where .vname::after{content:"";display:inline-block;width:0;height:44px;vertical-align:middle}
.city{color:var(--muted);font-size:var(--t-second)}
.city::before{content:"·";margin:0 var(--s1);color:var(--line-strong)}

.meta{margin:var(--s1) 0 0;font-size:var(--t-second);color:var(--muted);line-height:var(--lh-snug);
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}

.foot{grid-area:foot;display:flex;flex-wrap:wrap;gap:var(--s2) var(--s3);align-items:center;
  justify-content:space-between;margin:var(--s3) 0 0;padding-top:var(--s3);border-top:1px solid var(--line)}
.price{font-size:var(--t-second);color:var(--muted);font-variant-numeric:tabular-nums}
.btn{display:inline-flex;align-items:center;justify-content:center;min-height:44px;padding:0 var(--s4);
  border-radius:var(--radius);background:var(--accent);color:var(--accent-ink);border:1px solid var(--accent);
  font:700 var(--t-second)/1 inherit;letter-spacing:.03em;text-decoration:none;cursor:pointer}
.btn[aria-disabled="true"]{background:transparent;color:var(--muted);border-color:var(--line-strong);cursor:default}
.notice{font-size:var(--t-second);color:var(--muted);flex:1 1 100%;margin:0}

/* destination hostname beside every ticket link — the reader sees where the
   link goes before clicking. Quiet when known, marked when not. */
.buywrap{display:inline-flex;align-items:center;gap:var(--s2);flex-wrap:wrap}
.host{font:400 var(--t-second)/1 inherit;color:var(--muted);white-space:nowrap}
.host-unknown{color:var(--flag-dead);font-weight:700}

/* ---------- empty state ---------- */
.empty{border:1px dashed var(--line-strong);border-radius:var(--radius);padding:var(--s6) var(--s4);
  text-align:center;margin:var(--s5) 0}
.empty h2{margin:0 0 var(--s2);font-family:var(--font-display);font-weight:var(--display-weight);
  text-transform:var(--display-transform);font-size:var(--t-section)}
.empty p{margin:0 0 var(--s4);color:var(--muted);font-size:var(--t-second)}

footer.end{margin:var(--s6) 0;padding:var(--s4) 0 var(--s6);border-top:1px solid var(--line);
  color:var(--muted);font-size:var(--t-second)}
footer.end p{margin:var(--s1) 0}

/* ============================================================
   BREAKPOINTS
   ============================================================ */
@media (min-width:1024px){
  .shell{padding:0 var(--s5)}
  .layout{display:grid;grid-template-columns:224px minmax(0,1fr);gap:var(--s5);align-items:start}
  .rail{grid-column:1;grid-row:1;position:sticky;top:calc(var(--h-switch,58px) + var(--s3))}
  main{grid-column:2;grid-row:1;min-width:0;max-width:640px}
  .filters{position:static;background:none;backdrop-filter:none;border:0;padding:0}
  .chips{flex-direction:column;overflow:visible;margin:0;padding:0;gap:var(--s1)}
  .chip{width:100%;min-height:40px}
  .count{margin:var(--s3) 0 var(--s4)}
  .bucketnav{display:block;border-top:1px solid var(--line);padding-top:var(--s3)}
  .bucket{padding-top:var(--s2)}
}
@media (min-width:1400px){
}

/* ============================================================
   MOTION — all of it is switched off by the reduced-motion block.
   None of it gates the first paint of the gig list.
   ============================================================ */
.chip,.btn,.swatch,.bucketnav a,.gig{
  transition:transform var(--dur) var(--ease),background-color var(--dur) var(--ease),
             border-color var(--dur) var(--ease),color var(--dur) var(--ease)}
.chip:active,.swatch:active{transform:scale(.94)}
.btn:active{transform:scale(.97)}
@media (hover:hover){
  .btn:hover{transform:translateY(-2px)}
  .chip:hover{border-color:var(--text)}
  .bucketnav a:hover{color:var(--text);border-color:var(--line-strong)}
  .gig:hover{border-color:var(--line-strong)}
}
.animate .bucket{animation:rise 200ms var(--ease) both}
.animate .gig{animation:rise 250ms var(--ease) both;animation-delay:calc(var(--i,0) * 24ms)}
@keyframes rise{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:none}}
.bucket.is-stuck{border-bottom-color:var(--accent)}
@supports (backdrop-filter:blur(2px)){
  .bucket{background:transparent}
  .bucket.is-stuck{background:var(--bg-fade);backdrop-filter:blur(14px) saturate(140%)}
}
.gig{content-visibility:auto;contain-intrinsic-size:auto 180px}
html{scroll-behavior:smooth}

@media (prefers-reduced-motion:reduce){
  *{animation:none!important;transition:none!important;scroll-behavior:auto!important}
}

/* ============================================================
   T4 REFINEMENT — 2026-09-18
   What the first look on a wide screen showed, and the fix for each:
     · content sat flush against the viewport edge      -> real gutters
     · amber filled every jump link                     -> amber is for actions only
     · the ticket button overlapped its host label      -> button above, host beneath
     · "Recent changes" printed twice                   -> one heading per breakpoint
     · cards ran wider than they read                   -> column capped
   Kept in one block so the inherited rules above stay reviewable.
   ============================================================ */

/* gutters that hold at every width, on the two full-bleed strips */
.shell{ padding-inline:clamp(16px,4vw,56px) }
.switch-inner{ padding-inline:clamp(16px,4vw,56px) }
.chips{ margin:0; padding:0 0 2px }

/* the wordmark keeps the stage; everything near it recedes */
.mast{ border-bottom:1px solid var(--line) }
.tagline{ max-width:38ch }
.stamp{ color:var(--muted) }

/* a warning should be a rule in the margin, not a boxed alarm */
.stale{ border:0; border-left:3px solid var(--accent); border-radius:0;
  background:var(--surface); color:var(--muted); font-weight:500;
  padding:var(--s2) var(--s3) }

/* navigation is text. Only the current section takes the accent, as a rule */
.bucketnav a{ border:0; border-left:2px solid transparent; border-radius:0;
  padding-left:var(--s2); background:transparent }
.bucketnav a.is-current{ background:transparent; color:var(--text);
  border-left-color:var(--accent) }

/* the ticket control and its destination, stacked so they can never collide */
.foot{ flex-direction:column; align-items:flex-start; gap:var(--s2) }
.buywrap{ flex-direction:column; align-items:flex-start; gap:var(--s1) }
.host{ color:var(--muted); font-weight:500 }
.host-unknown{ color:var(--flag-dead); font-weight:700 }

/* air between cards, and a frame that stays quiet */
.list{ gap:var(--s3) }
.gig{ padding:var(--s4) var(--s4) var(--s3) }
.date{ padding-top:4px }


@media (min-width:1024px){
  /* chronology reads in a column, not across a wall */
  .list, .bucket, .empty{ max-width:760px }
  .foot{ flex-direction:row; align-items:center; justify-content:space-between; gap:var(--s4) }
  .buywrap{ flex-direction:row; align-items:center; gap:var(--s2) }
}

/* --- second pass, after looking at the rendered page ----------------------
   The unknown-host marker was shouting in red on every card — most venues are
   not known ticketers, so red was the common case, which makes it mean nothing.
   The punycode glyph carries the real alarm instead. The card foot goes back to
   one row so a card stays compact, and the changes panel drops below the list
   on narrow screens, where it was pushing the gigs off the first screen. */
.host-unknown{ color:var(--muted); font-weight:500; text-decoration:underline dotted }
.foot{ flex-direction:row; flex-wrap:wrap; align-items:center;
  justify-content:space-between; gap:var(--s2) var(--s3) }
.buywrap{ flex-direction:row; align-items:center; gap:var(--s2) }
.date .d{ font-size:var(--t-act); line-height:1 }

@media (max-width:1023px){
  .layout{ display:flex; flex-direction:column }
  #gigs{ order:1 }
}

/* The section header pins under the region bar. Its offset was the region bar
   plus the filter bar, but on narrow screens the filters scroll away with the
   rail, which left the header hanging mid-card. Solid ground too, so a card's
   ticket button cannot bleed through it. */
.bucket{ background:var(--bg) }
@media (max-width:1023px){
  .bucket{ top:var(--h-switch,74px) }
  .gig{ scroll-margin-top:calc(var(--h-switch,74px) + var(--s3)) }
}

/* The running gig count comes off the page: every section header already carries
   its own count, so the line only repeated them. It stays in the DOM as the
   aria-live region, so filtering, the empty result and a failed load are still
   announced to screen readers — visually hidden, not deleted. */
#count{ position:absolute; width:1px; height:1px; margin:-1px; padding:0;
  overflow:hidden; clip-path:inset(50%); white-space:nowrap; border:0 }

/* Filters, made easier to use: labelled groups that wrap instead of scrolling
   out of reach, a count on every option so you can see where the gigs are, and
   one clear-filters control that only appears when something is filtered. */
.chips{ flex-direction:column; align-items:stretch; flex-wrap:nowrap;
  overflow:visible; gap:var(--s3) }
.chipgroup{ display:flex; flex-wrap:wrap; align-items:center; gap:var(--s2) }
.chiplabel{ flex:0 0 auto; font:700 var(--t-micro)/1 inherit;
  letter-spacing:var(--tr-wide); text-transform:uppercase; color:var(--muted) }
.chip .n{ margin-left:var(--s1); opacity:.6; font-variant-numeric:tabular-nums }
.chip[aria-pressed="true"] .n{ opacity:.8 }
.chip-reset{ min-height:44px; padding:0 var(--s2); background:none; border:0;
  color:var(--muted); font:500 var(--t-second)/1 inherit; cursor:pointer;
  text-decoration:underline; text-underline-offset:3px }
.chip-reset:hover{ color:var(--text) }

/* Selection reads as an outline, not a fill: amber border, amber label. The one
   thing that stays filled is the ticket button, because that is an action rather
   than a state, and the difference should be visible at a glance. */
.chip[aria-pressed="true"], .swatch[aria-pressed="true"]{
  background:transparent; color:var(--accent); border-color:var(--accent);
  box-shadow:inset 0 0 0 1px var(--accent) }
.chip[aria-pressed="true"] .n{ color:var(--accent); opacity:.7 }

/* Cards, tightened so more of the evening fits on one screen: less padding, the
   foot sitting on the same rhythm instead of behind its own rule, and a smaller
   date block. Touch targets stay at 44px on touch devices and drop to 36 only
   where there is a pointer. */
.list{ gap:var(--s2) }
.gig{ padding:var(--s3); gap:0 var(--s3); border-radius:10px }
.act{ font-size:19px }
.where{ margin-top:2px; font-size:var(--t-second) }
.meta{ margin-top:2px; -webkit-line-clamp:1 }
.foot{ margin-top:var(--s2); padding-top:var(--s2); gap:var(--s1) var(--s3) }
.date{ padding-top:1px }
.date .d{ font-size:19px }
.date .w, .date .m{ font-size:9px }
.bucket{ padding:var(--s4) 0 var(--s1) }
@media (hover:hover){
  .btn{ min-height:36px; padding:0 var(--s3) }
  .chip, .swatch{ min-height:36px }
  .chip-reset{ min-height:36px }
}
@media (min-width:1024px){
  .gig{ grid-template-columns:44px minmax(0,1fr) auto;
        grid-template-areas:"date body foot" }
  .foot{ margin-top:0; padding-top:0; border-top:0; flex-direction:column;
         align-items:flex-end; justify-content:center; gap:2px }
}

/* The band name carries the Metal Archives lookup, but it should not look like a
   link until you reach for it: the name is the loudest thing on the card and an
   underline on every one of them turns the list into noise. */
.act a{ color:inherit; text-decoration:none }
.act a:hover, .act a:focus-visible{ text-decoration:underline;
  text-decoration-thickness:1px; text-underline-offset:4px; text-decoration-color:var(--accent) }

/* Tighter still: the card was 165px, which is two-and-a-bit gigs per phone
   screen. Line heights and the foot's own spacing were most of it. */
.act{ line-height:1.1 }
.head{ margin:0; min-height:0 }
.where{ line-height:1.25 }
.meta{ line-height:1.25 }
.foot{ margin-top:var(--s1); padding-top:var(--s1) }
.gig{ padding:var(--s3) var(--s3) var(--s2) }
.date .w{ margin-top:1px }

/* The region switch sits under the masthead now — nothing stands above the
   title. It still pins to the top once you scroll past it, and it bleeds to the
   window edges while its buttons stay on the page's own gutter. */
.switch{ margin-inline:calc(clamp(16px,4vw,56px) * -1); padding-inline:clamp(16px,4vw,56px);
  background:var(--bg); border-top:1px solid var(--line) }
.switch-inner{ padding-inline:0; justify-content:flex-start }
.mast{ border-bottom:0 }

/* The calendar control: an icon in the card's top right corner. Quiet until
   pointed at, and the card reserves that corner so nothing runs under it. */
.gig{ position:relative }
.cal{ position:absolute; top:6px; right:6px; z-index:2;
  display:inline-flex; align-items:center; justify-content:center;
  width:34px; height:34px; min-height:0; padding:0;
  border:1px solid transparent; border-radius:10px;
  background:transparent; color:var(--muted); cursor:pointer }
.cal svg{ width:18px; height:18px; display:block }
.cal:hover, .cal:focus-visible{ color:var(--accent); border-color:var(--line-strong);
  background:var(--raised) }
.head{ padding-right:34px }
@media (hover:none){ .cal{ width:40px; height:40px } .head{ padding-right:40px } }

/* The wordmark is one word, set once. The per-letter tilts that stood here were
   a pastiche of a display face and read as a mistake at every size; the weight,
   the squeeze and the tight fit are doing the work instead. */
.logo{ transform:scaleX(.92); transform-origin:left center; letter-spacing:-.045em;
  font-feature-settings:"liga" 1,"dlig" 1 }

/* The wordmark's ink is taller than its line box at this line-height, so the
   masthead carries the space rather than the type. */
.logo{ line-height:.9 }
header.mast{ padding:var(--s6) 0 var(--s4) }

/* Door time sits beside the city, in the same muted register, with the figures
   lining up down the list. */
.time{ color:var(--muted); font-size:var(--t-second); font-variant-numeric:tabular-nums }
.time::before{ content:"·"; margin:0 var(--s1); color:var(--line-strong) }

/* The wordmark's ink is taller than its line box at this line-height, so the
   masthead carries the space rather than the type. */
.logo{ line-height:.9; transform:scaleX(.92); transform-origin:left center;
  letter-spacing:-.045em }
header.mast{ padding:var(--s6) 0 var(--s4) }

/* The wordmark is the word set in Molen Surplus and converted to outlines by
   tools/wordmark-from-font.py — no font file is served, and the display cut's
   missing umlauts do not matter for eight letters. It takes currentColor, so
   both palettes get it free.
   LICENCE: that cut is "personal use only". A commercial licence from
   Nurrontype is a release blocker; see docs/design-T4-site.md. */
.logo{ margin:0; line-height:0 }
.logo .wordmark{ display:block; width:100%; max-width:min(540px, 92%); height:auto;
  color:var(--text) }
@media (min-width:1024px){ .logo .wordmark{ max-width:600px } }

/* Molen carries the headings as well as the title. It is a condensed display
   cut with a small apparent size, so the type steps up and the tracking opens. */
:root{ --font-display:"Molen Surplus","Iowan Old Style","Palatino Linotype",Palatino,Georgia,serif;
       --display-weight:400; --display-tracking:.01em }
.bucket{ font-size:27px }
.empty h2{ font-size:27px }
@media (min-width:1024px){ .bucket{ font-size:31px } }

/* Band names are the thing people actually read down the list, so the display
   face stops at the section headings: names go back to the text serif. */
.act{ font-family:"Iowan Old Style","Palatino Linotype",Palatino,Georgia,"Times New Roman",serif;
  font-weight:700; font-size:19px; line-height:1.1; letter-spacing:-.02em }
@media (min-width:1024px){ .act{ font-size:21px } }

/* Filter groups fold. The label is the button and the chips are its panel; a
   folded group still names what it is filtering on, so nothing can be applied
   invisibly. The chevron is drawn in CSS — no icon font, no request. */
.chipgroup{ display:block }
.chiplabel{ display:flex; align-items:center; gap:var(--s2); width:100%; min-height:38px;
  padding:0; background:none; border:0; cursor:pointer; text-align:left; color:var(--muted);
  font:700 var(--t-micro)/1 inherit; letter-spacing:var(--tr-wide); text-transform:uppercase }
.chiplabel:hover{ color:var(--text) }
.chiplabel-v{ color:var(--accent); font-size:var(--t-second); letter-spacing:.02em;
  text-transform:none }
.chev{ margin-left:auto; flex:0 0 auto; width:8px; height:8px;
  border-right:2px solid currentColor; border-bottom:2px solid currentColor;
  transform:rotate(-45deg); transition:transform var(--dur) var(--ease) }
.chiplabel[aria-expanded="true"] .chev{ transform:rotate(45deg) }
.chiprow{ display:flex; flex-wrap:wrap; gap:var(--s2); padding:0 0 var(--s3) }
.chiprow[hidden]{ display:none }

/* The masthead is the wordmark alone now. */
header.mast{ padding:var(--s6) 0 var(--s3) }

/* San Toremi takes the rest of the page. One family for every control and every
   line of detail; the serif keeps only the band names, where reading speed
   matters most. Its lowercase runs small, so the base size steps up a point. */
:root{ --font-ui:"San Toremi",-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,
       Helvetica,Arial,sans-serif; --t-primary:16px; --t-second:13.5px; --t-micro:11px }
body{ font-family:var(--font-ui) }
button, input, select, textarea{ font-family:inherit }
.chip, .swatch, .btn, .cal, .chip-reset, .chiplabel, .bucketnav a, .count,
.where, .meta, .price, .foot, .end, .notice, .empty p{ font-family:var(--font-ui) }
header.mast{ padding:var(--s6) 0 var(--s4) }
