/* plus60.football — 2026-08-15 build. Hand-written, no bundler.
   Edit these files directly; there is no compile step. */
:root{
  /* ── Chalk and Turf ──────────────────────────────────────────────
     Paper stays light, but the greys are warmed toward green so the
     mown-turf band under the board belongs rather than sits on top.
     Neon is reserved for one meaning: this is on, this is bookable.
     Amber carries "watching it", ink carries "called off". */
  --paper:#F2F0E7; --card:#FFFFFF; --card2:#F6F4EC;
  --ink:#0E1A12; --ink2:#33453A; --mu:#63745F; --mu2:#7C8C78;
  --rule:#D6DCD0; --rule2:#BFC9B8;
  --acid:#D9F035; --acid-dk:#3C6B1F; --acid-soft:#EAF6C8;
  --hot:#B4560C; --hot-soft:#FAECDC; --gone:#97A394;
  /* Fill your game: a one off session plus60 is filling, not a club fixture.
     #BC5F57 is 3.74:1 on paper, so the border clears the 3:1 a non-text
     indicator needs. The border never carries the meaning on its own though:
     colour alone excludes anyone who cannot see it, so every fill row is
     labelled too. */
  --fill:#BC5F57; --fill-soft:#FBEFEE; --fill-ink:#8C332C;
  /* deep pitch green: the header band, section rules, structure */
  --pitch:#1E4D2B; --pitch-2:#173D22; --pitch-ink:#F2F0E7;
  /* the mown stripes, two shades a hair apart */
  --turf-a:#E4EADB; --turf-b:#F2F0E7;
  /* Display is Inter Tight 800 under a single-weight alias, Inter does the rest.
     --osw kept as the variable name so every label rule still points at one place. */
  --blk:'display','Inter Tight',Inter,-apple-system,sans-serif;
  --osw:Inter,-apple-system,'Helvetica Neue',sans-serif;
  --sans:Inter,-apple-system,'Helvetica Neue',sans-serif;
}
*{box-sizing:border-box;margin:0;padding:0;-webkit-tap-highlight-color:transparent}
html{-webkit-text-size-adjust:100%}
body{background:var(--paper);color:var(--ink);font-family:var(--sans);font-size:15px;line-height:1.5;
  -webkit-font-smoothing:antialiased;position:relative;
  /* `overflow-x:hidden` here turns body into a scroll container, and a scroll
     container silently breaks position:sticky for everything inside it. That
     is what stopped the section bar on /legal/ from sticking. `clip` hides the
     same overflow without creating a scroller, so sticky works again. The
     hidden line stays first as the fallback for anything that does not know
     clip; a browser that understands both takes the second. */
  overflow-x:hidden;overflow-x:clip}
body:before{content:'';position:fixed;inset:0;z-index:999;pointer-events:none;
  background-image:radial-gradient(#101010 1px,transparent 1px);background-size:5px 5px;opacity:.045}
img,svg{display:block;max-width:100%}
a{text-decoration:none;color:inherit}
button{font:inherit;color:inherit;border:0;background:none;cursor:pointer}
input,select{font:inherit;color:inherit}
.w{max-width:1120px;margin:0 auto;padding:0 16px}
.blk{font-family:var(--blk);letter-spacing:-.03em}
.osw{font-family:var(--osw)}

/* Visually hidden, still read by screen readers and still a real heading in the
   document outline. The board's two main regions, the feed and the map, had no
   heading at all: the listings are the primary content of the site and nothing
   named them. Not a keyword slot, a label for a region that has one.
   p60vh rather than .vh because bare two-letter class names in this file have
   collided four times already. */
.p60vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;
  clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;border:0}

/* The wordmark, inline in a sentence. The logo is Inter Tight with the 60 sitting
   in an acid block, and a mention of the name inside body copy should look like
   the thing at the top of the page rather than a lowercase word someone forgot to
   capitalise. "plus" inherits the surrounding colour so it works on paper and on
   the pitch alike; the 60 is always ink on acid, exactly as it is in the mark. */
.p60{font-family:var(--blk);font-weight:800;letter-spacing:-.02em;white-space:nowrap;
  text-transform:none}   /* the footer band is uppercase; the wordmark never is */
.p60 i{font-style:normal}
.p60 b{font-weight:inherit;background:var(--acid);color:var(--ink);padding:0 3px 1px;
  -webkit-box-decoration-break:clone;box-decoration-break:clone}

/* ── header ── */
header{position:sticky;top:0;z-index:60;background:var(--pitch);color:var(--pitch-ink);
  border-bottom:3px solid var(--ink)}
/* One band: logo, menu, area. The chip bar used to sit on its own row below,
   which left the logo floating above everything it was meant to sit beside. */
/* One row. Filters, Near me and the two destinations are all the same chip in
   the same bar, so there is nothing for the eye to re-learn between pages. */
header .top{display:flex;align-items:center;gap:18px;padding:12px 0}
.brand{display:block;line-height:0}
.brand svg,.brand img{height:29px;width:auto;display:block}

/* the middle: the board's filter chips and the site's destinations, together */
.hmid{display:flex;align-items:center;gap:5px;flex:1 1 auto;min-width:0;
  overflow-x:auto;scrollbar-width:none;justify-content:center;justify-content:safe center}
.hmid::-webkit-scrollbar{display:none}
.hmid .chips{flex:none;overflow:visible}

@media(max-width:760px){
  header .top{flex-wrap:wrap;gap:10px;padding:11px 0}
  .brand{order:1}
  header .loc{order:2;margin-left:auto}
  .hostin{order:3;margin-left:auto}
  .hmid{order:4;flex:1 0 100%;justify-content:flex-start;padding-bottom:2px}
  /* The chips with an icon came out 42px and the plain ones 40px. One height
     for all four, and 44 rather than 42 so they clear the touch target too.
     min-height alone left the two icon chips at 46: the icon's own line box
     pushes the content taller than the text-only chips. A fixed height with
     border-box settles it, and 44 is above the content in every case. */
  .hmid .chip{height:44px}
  /* At 390 the strip is 603px wide in a 362px box, and it happens to cut clean
     between two chips, so it reads as a finished row rather than a scroller.
     A soft right edge says there is more. A mask rather than a gradient fill
     because the header sits on the striped pitch, not a flat colour. */
  .hmid{-webkit-mask-image:linear-gradient(90deg,#000 calc(100% - 30px),transparent);
    mask-image:linear-gradient(90deg,#000 calc(100% - 30px),transparent)}
}
/* 26px puts the wordmark at 159px, under the 170px minimum in the brand spec.
   Left as it was rather than changed silently, but it applies to the img form
   too so the board and the standalone pages stay identical. */
@media(max-width:560px){.brand svg,.brand img{height:26px}}
header .loc{flex:none;font-family:var(--osw);font-size:10.9px;font-weight:600;letter-spacing:.06em;
  color:var(--pitch-ink);border:1.5px solid rgba(242,240,231,.55);padding:6px 11px;display:flex;
  align-items:center;gap:7px;background:rgba(0,0,0,.14)}
header .loc:hover{border-color:var(--acid)}
/* The acid square that used to sit here was a generic marker. The Jalur Gemilang
   says the same thing and says where. Outlined because the bottom stripe is paper
   coloured and would otherwise dissolve into the header.
   NOT .flag: app.css has owned that since the board's full-width notice bar, and
   a bare .flag here inflated the svg to 31x20 and the header to 81px. */
header .loc .locflag{width:20px;height:10px;flex:none;display:block;
  outline:1px solid rgba(0,0,0,.28);outline-offset:-1px}

/* At 390 the logo, the region and Host login will not share a row, and the
   header was wrapping to three, giving a 165px sticky bar on a phone. The
   region label is the one that can go: the board says "across the Klang
   Valley" in the hero and the filter sheet says it again. */
@media(max-width:560px){ header .loc{display:none} }

.chips{display:flex;gap:5px;overflow-x:auto;scrollbar-width:none;
  min-width:0;justify-content:center;justify-content:safe center}
.chips::-webkit-scrollbar{display:none}
.chip{flex:none;border:1.5px solid transparent;background:var(--card);padding:7px 12px;
  font-family:var(--osw);font-size:11.4px;font-weight:500;letter-spacing:.06em;text-transform:uppercase;
  color:var(--ink2);white-space:nowrap;transition:.12s;display:flex;align-items:center;gap:6px}
.chip:hover{border-color:var(--acid)}
.chip.on{background:var(--acid);border-color:var(--ink);color:var(--ink);font-weight:600}
.chip b{background:var(--ink);color:var(--acid);padding:1px 5px;font-size:9px}
.chip svg{width:12px;height:12px}
.sep{width:1.5px;background:rgba(242,240,231,.3);flex:none;margin:2px 4px}
.vt{display:flex;border:1.5px solid var(--card);flex:none;background:var(--card)}
.vt button{padding:7px 13px;font-family:var(--osw);font-size:11.4px;font-weight:500;letter-spacing:.06em;
  text-transform:uppercase;color:var(--ink2)}
.vt button.on{background:var(--pitch-2);color:var(--acid);font-weight:600}

/* ── board ── */
main{padding-bottom:96px}
/* Mown stripes, two shades a hair apart. Drawn in CSS so it costs nothing and
   stays sharp at any zoom. Only under the board: the hero and the session pages
   stay flat paper so photography and long copy sit on something quiet. */
#listv,#mapv{position:relative}
#listv:before,#mapv:before{content:'';position:absolute;inset:0;z-index:0;pointer-events:none;
  background:repeating-linear-gradient(90deg,var(--turf-a) 0 56px,var(--turf-b) 56px 112px)}
#listv>*,#mapv>*{position:relative;z-index:1}
@media(max-width:560px){
  #listv:before,#mapv:before{background:repeating-linear-gradient(90deg,var(--turf-a) 0 34px,var(--turf-b) 34px 68px)}
}
/* ── the lede is on the pitch ───────────────────────────────────────────────
   Same ground as the password gate and the header: deep green with the mown
   stripes running through it, so arriving at the board feels continuous with
   the way in. The board itself stays on paper, because thirty rows of dense
   type has to be dark on light. */
.pitchtop{position:relative;background:var(--pitch);color:var(--pitch-ink);
  margin-bottom:0;overflow:hidden}
.pitchtop:before{content:'';position:absolute;inset:0;pointer-events:none;
  background:repeating-linear-gradient(90deg,rgba(255,255,255,.030) 0 56px,transparent 56px 112px)}
/* the halfway line and centre circle, faint, drawn once across the band */
.pitchtop:after{content:'';position:absolute;left:50%;top:-40%;width:280px;height:280px;
  transform:translateX(-50%);border:2px solid rgba(255,255,255,.055);border-radius:50%;
  pointer-events:none}
.pitchtop>*{position:relative;z-index:1}
.lede{padding:30px 0 26px;border-bottom:0}
.lede h1{font-family:var(--blk);font-size:clamp(22px,5.2vw,31px);line-height:1.08;letter-spacing:-1px;
  max-width:22ch;text-wrap:balance}
/* second line drops the shout: lighter, smaller, its own line */
.lede h1 .sub{display:block;font-family:var(--sans);font-weight:400;font-size:.58em;letter-spacing:-.1px;
  line-height:1.38;color:#B9C9B4;margin-top:11px;max-width:34ch}
.lede h1:after{content:'';display:block;width:52px;height:5px;background:var(--acid);margin-top:15px}
.lede-r{margin-top:15px;max-width:58ch}
.lede p{font-size:14.5px;line-height:1.62;color:#A8BAA3}
.lede p+p{margin-top:9px}
.lede .lead{font-size:16px;line-height:1.5;color:var(--pitch-ink)}
.lede .lead b{font-weight:700}
/* Under the headline now, not under the chips, so both columns carry weight
   and neither runs out of copy halfway down. */
.lede .lede-cta{margin-top:17px;font-size:15px;font-weight:600;color:var(--pitch-ink);
  line-height:1.55;max-width:40ch}
.lede .lede-cta span{font-weight:400;color:#A8BAA3}
@media(min-width:900px){
  .lede{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:44px;align-items:start;padding:32px 0 28px}
  .lede h1{max-width:none;font-size:33px;line-height:1.08}
  .lede-l{padding-top:2px}
  .lede-r{margin-top:0}
  .lede .lede-cta{font-size:15.5px}
}
.lede p b{color:var(--acid);font-weight:700}

/* ── host login ──
   The board belongs to players. The four people who run a club can find a
   small door in the corner; everybody else should never notice it. */
.hostin{display:inline-flex;align-items:center;font-family:var(--osw);font-size:10px;font-weight:500;
  letter-spacing:.09em;text-transform:uppercase;color:rgba(242,240,231,.52);
  border:1px solid rgba(242,240,231,.22);padding:7px 10px;white-space:nowrap;flex:none;min-height:32px}
.hostin:hover,.hostin:focus-visible{color:var(--acid);border-color:var(--acid);outline:none}
@media(max-width:760px){
  .hostin{font-size:9.4px;padding:8px 9px;min-height:36px}
}
/* ── ad marquee ── */
.adwrap{margin-top:20px}
.adlbl{max-width:1120px;margin:0 auto;padding:0 16px 8px;font-family:var(--osw);font-size:10.4px;
  font-weight:400;letter-spacing:.08em;text-transform:uppercase;color:var(--mu2)}
.ads{border-top:3px solid var(--ink);border-bottom:3px solid var(--ink);background:var(--card);
  overflow:hidden;position:relative;
  /* the strip owns horizontal gestures, the page keeps vertical ones */
  touch-action:pan-y;cursor:grab;-webkit-user-select:none;user-select:none}
.ads.grabbing{cursor:grabbing}
.ads.grabbing .adx{pointer-events:none}
/* Cards enter and leave through a soft edge so the strip reads as a ticker
   even in a still screenshot. */
.ads:after{content:'';position:absolute;inset:0;pointer-events:none;z-index:2;
  background:linear-gradient(90deg,var(--card),transparent 4%,transparent 96%,var(--card))}
/* Driven from app.js so the strip can be grabbed and thrown; a keyframe cannot.
   Hover-to-read, reduced motion and the flick physics all live in marquee(). */
.ads .track{display:flex;gap:12px;padding:12px;width:max-content;will-change:transform}
.adx{-webkit-user-drag:none;user-drag:none}
.adx img{pointer-events:none;-webkit-user-drag:none}
/* Ad units are ratio-locked so a sold slot has one exact artwork size.
   Marquee 2:1, banner 4:1, both the same height so the rail stays level. */
.adx{flex:none;width:280px;height:140px;border:1.5px solid var(--rule2);background:var(--paper);display:flex;
  align-items:stretch;gap:11px;padding:11px;transition:.12s;cursor:pointer;position:relative;color:inherit;
  overflow:hidden}
.adx:hover,.adx:focus-visible{border-color:var(--ink);background:var(--card);box-shadow:3px 3px 0 var(--ink);
  outline:none}
.adx:hover .sq{background:var(--acid)}
.adx .go2{position:absolute;right:9px;bottom:8px;opacity:0;transition:.12s;color:var(--ink)}
.adx .go2 svg{width:13px;height:13px}
.adx:hover .go2,.adx:focus-visible .go2{opacity:1}
.adx .sq{width:52px;flex:none;border:1.5px solid var(--ink);display:flex;align-items:center;justify-content:center;
  font-family:var(--blk);font-size:15px;letter-spacing:-.5px;line-height:1;text-align:center;padding:4px}
.adx b{display:block;font-size:12.5px;font-weight:700;line-height:1.25}
.adx span{display:block;font-family:var(--osw);font-size:9.8px;font-weight:300;letter-spacing:.05em;
  text-transform:uppercase;color:var(--mu);margin-top:5px;line-height:1.6}
.adx.open{border-style:dashed;background:var(--card2)}
.adx.open .sq{background:var(--acid)}
/* Banner slot: two cards wide, with room for a poster rather than an initial.
   Sold as the premium unit; one per rotation keeps it feeling scarce. */
.adx.wide{width:560px;padding:0;gap:0;align-items:stretch}
.adx.wide .art{width:186px;flex:none;border-right:1.5px solid var(--rule2);position:relative;
  overflow:hidden;background:var(--acid-soft);display:flex;align-items:center;justify-content:center}
.adx.wide:hover .art{border-right-color:var(--ink)}
.adx.wide .art b{font-family:var(--blk);font-size:26px;letter-spacing:-1.2px;line-height:1;text-align:center;
  padding:0 10px;color:var(--ink)}
.adx.wide .art i{position:absolute;left:0;top:0;bottom:0;width:6px;background:var(--acid);font-style:normal}
.adx.wide .txt{padding:13px 15px;display:flex;flex-direction:column;justify-content:center;min-width:0}
.adx.wide .txt b{font-size:15px;font-weight:700;line-height:1.25;letter-spacing:-.2px}
.adx.wide .txt span{margin-top:6px}
.adx.wide .tagl{display:inline-block;align-self:flex-start;margin-bottom:8px;font-family:var(--osw);
  font-size:9.3px;font-weight:600;letter-spacing:.08em;text-transform:uppercase;background:var(--ink);
  color:var(--acid);padding:3px 7px}
.adx.wide.open .art{background:repeating-linear-gradient(45deg,var(--card2),var(--card2) 9px,
  var(--paper) 9px,var(--paper) 18px)}
@media(max-width:520px){
  .adx.wide{width:480px}
  .adx.wide .art{width:160px}
  .adx.wide .art b{font-size:20px}
  .adx.wide .txt b{font-size:13.5px}
}
/* ── sponsors ── */
.spwrap{padding:30px 0 4px;border-top:1.5px solid var(--rule);margin-top:34px}
.sec2{font-family:var(--osw);font-size:10.9px;font-weight:600;letter-spacing:.08em;text-transform:uppercase;
  color:var(--pitch);padding-bottom:9px;border-bottom:1.5px solid var(--pitch);margin-bottom:14px}
.spon{display:grid;grid-template-columns:repeat(6,minmax(0,1fr));gap:9px}
@media(max-width:820px){.spon{grid-template-columns:repeat(3,minmax(0,1fr))}}
@media(max-width:460px){.spon{grid-template-columns:repeat(2,minmax(0,1fr))}}
.sp1{border:1.5px solid var(--rule2);background:var(--card);aspect-ratio:3/2;display:flex;align-items:center;
  justify-content:center;text-align:center;padding:8px;font-family:var(--blk);font-size:13px;letter-spacing:-.4px;
  line-height:1.1;color:var(--ink2)}
.sp1.open{border-style:dashed;background:var(--card2);font-family:var(--osw);font-size:9.8px;font-weight:500;
  letter-spacing:.06em;text-transform:uppercase;color:var(--mu2)}
.spnote{margin-top:12px;font-family:var(--osw);font-size:10.4px;font-weight:300;letter-spacing:.06em;
  text-transform:uppercase;color:var(--mu)}
.spnote a{border-bottom:1.5px solid var(--acid);color:var(--ink)}
/* ── session page: header, host card, photo strip ── */
.sp-top{display:flex;align-items:flex-start;gap:20px;flex-wrap:wrap}
.sp-ttl{flex:1 1 320px;min-width:0}
.hostcard{flex:0 0 auto;display:flex;align-items:center;gap:12px;border:1.5px solid var(--ink);
  background:var(--card);padding:11px 13px;transition:.12s;max-width:100%}
.hostcard:hover{box-shadow:4px 4px 0 var(--acid)}
.hostcard .av{font-family:var(--blk);font-size:15px;letter-spacing:-.4px;background:var(--acid);
  border:1.5px solid var(--ink);padding:8px 9px;flex:none}
.hostcard .hc-t{min-width:0}
.hostcard i{display:block;font-style:normal;font-family:var(--osw);font-size:9px;font-weight:500;
  letter-spacing:.09em;text-transform:uppercase;color:var(--mu)}
.hostcard b{display:block;font-family:var(--blk);font-size:15px;letter-spacing:-.3px;margin-top:3px}
.hostcard u{display:block;text-decoration:none;font-family:var(--osw);font-size:9.5px;font-weight:400;
  letter-spacing:.05em;text-transform:uppercase;color:var(--mu);margin-top:4px}
.hostcard .hc-go{flex:none;color:var(--mu)}
.hostcard .hc-go svg{width:15px;height:15px}
.hostcard:hover .hc-go{color:var(--ink)}
@media(max-width:640px){
  .sp-top{gap:14px}
  .hostcard{width:100%;padding:10px 12px}
}
/* photo strip */
.strip{position:relative;border:1.5px solid var(--ink);overflow:hidden;background:var(--card2)}
.strip .track{display:flex;overflow-x:auto;scroll-snap-type:x mandatory;scrollbar-width:none;
  -webkit-overflow-scrolling:touch}
.strip .track::-webkit-scrollbar{display:none}
.shot{flex:0 0 100%;scroll-snap-align:center;aspect-ratio:16/9;cursor:zoom-in;position:relative}
.shot svg,.shot .pimg{width:100%;height:100%;display:block;object-fit:cover}
.sarr{position:absolute;top:50%;transform:translateY(-50%);width:38px;height:38px;z-index:3;
  border:1.5px solid var(--ink);background:var(--paper);display:flex;align-items:center;
  justify-content:center;transition:.12s;opacity:.92}
.sarr svg{width:15px;height:15px}
.sarr.prev{left:10px}.sarr.next{right:10px}
.sarr:hover{background:var(--acid);opacity:1}
.sarr[disabled]{opacity:0;pointer-events:none}
.sdots{position:absolute;left:0;right:0;bottom:10px;z-index:3;display:flex;justify-content:center;gap:5px}
.sdots i{width:7px;height:7px;background:var(--paper);border:1.5px solid var(--ink);cursor:pointer;
  transition:.12s;opacity:.75}
.sdots i.on{background:var(--acid);opacity:1;transform:scale(1.15)}
.strip .gb{position:absolute;right:0;bottom:0;z-index:3;background:var(--acid);
  border-left:1.5px solid var(--ink);border-top:1.5px solid var(--ink);font-family:var(--osw);
  font-size:9.5px;font-weight:600;letter-spacing:.07em;text-transform:uppercase;padding:7px 11px;
  display:flex;align-items:center;gap:6px;cursor:pointer}
.strip .gb svg{width:12px;height:12px}
.strip .gb:hover{background:var(--ink);color:var(--acid)}
@media(hover:none){ .sarr{display:none} }
/* ── session page ── */
#sesv{display:none}
#sesv.on{display:block}
#home.off{display:none}
.backbar{border-bottom:1.5px solid var(--rule);background:var(--paper)}
.backbar .in{max-width:1120px;margin:0 auto;padding:11px 16px;display:flex;align-items:center;gap:10px}
.bk{display:inline-flex;align-items:center;gap:8px;font-family:var(--osw);font-size:10.9px;font-weight:500;
  letter-spacing:.07em;text-transform:uppercase;border:1.5px solid var(--ink);background:var(--card);padding:7px 11px}
.bk:hover{background:var(--acid)}
.bk svg{width:12px;height:12px}
.backbar .sh{margin-left:auto;display:flex;gap:7px}
.shb{display:inline-flex;align-items:center;gap:7px;font-family:var(--osw);font-size:10.9px;font-weight:500;
  letter-spacing:.07em;text-transform:uppercase;border:1.5px solid var(--rule2);background:var(--card);
  padding:7px 11px;color:var(--ink2)}
.shb:hover{border-color:var(--ink);color:var(--ink)}
.shb svg{width:12px;height:12px}
.sp-hd{padding:22px 0 4px}
.sp-hd h1{font-family:var(--blk);font-size:clamp(23px,5.6vw,36px);letter-spacing:-1.2px;line-height:1.03;
  text-transform:uppercase;max-width:20ch}
.sp-hd .mt{font-family:var(--osw);font-size:11.4px;font-weight:400;letter-spacing:.08em;text-transform:uppercase;
  color:var(--mu);margin-top:11px;line-height:1.8}
/* the five things you check before deciding to go, as their own tiles */
.facts{display:grid;grid-template-columns:1.25fr 1.35fr .85fr 1fr .9fr;gap:8px;margin-top:18px}
.facts.six{grid-template-columns:repeat(6,minmax(0,1fr))}
@media(max-width:1000px){.facts.six{grid-template-columns:repeat(3,minmax(0,1fr))}}
@media(max-width:760px){.facts{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media(max-width:360px){.facts{grid-template-columns:minmax(0,1fr)}}
.fact{border:1.5px solid var(--rule2);background:var(--card);padding:10px 11px 11px}
.fact .k{font-family:var(--osw);font-size:9.3px;font-weight:500;letter-spacing:.09em;text-transform:uppercase;
  color:var(--mu)}
.fact .v{font-family:var(--blk);font-size:17px;letter-spacing:-.5px;line-height:1.1;margin-top:7px;
  text-transform:uppercase}
.fact .v small{display:block;font-family:var(--osw);font-size:10.4px;font-weight:400;letter-spacing:.05em;
  color:var(--mu);margin-top:5px;text-transform:uppercase}
.fact.key{border-color:var(--ink);border-left-width:5px}
.fact.cd{background:var(--acid);border-color:var(--ink)}
.fact.cd .k{color:var(--acid-dk)}
@media(max-width:760px){
  .fact .v{font-size:16px}
  .facts{gap:7px;margin-top:15px}
}
.sp-hd .pz{display:flex;align-items:baseline;gap:12px;margin-top:14px;flex-wrap:wrap}
.sp-hd .pz b{font-family:var(--blk);font-size:30px;letter-spacing:-1.2px}
/* ── slots left ────────────────────────────────────────────────────────────
   The count is set at display size beside the price, because it is the other
   number the decision turns on. Colour carries the urgency; the small line
   under it says what the number means. */
.slotbx{display:inline-flex;align-items:center;gap:10px;border:2px solid var(--ink);
  background:var(--card);padding:7px 12px 7px 10px}
.slotbx b,.sp-hd .pz .slotbx b{font-family:var(--blk);font-size:27px;line-height:1;
  letter-spacing:-1px;color:var(--ink)}
.slotbx i{font-style:normal;font-family:var(--osw);font-size:10px;font-weight:600;letter-spacing:.08em;
  text-transform:uppercase;color:var(--mu);line-height:1.35;white-space:nowrap}
.slotbx i u{display:block;text-decoration:none;font-weight:700;color:var(--ink);margin-top:2px}
.slotbx.sb-ok{border-color:var(--acid-dk)}
.slotbx.sb-ok i u{color:var(--acid-dk)}
.slotbx.sb-hot{border-color:var(--hot);background:var(--hot-soft)}
.slotbx.sb-hot b,.slotbx.sb-hot i u{color:var(--hot)}
/* three or fewer: the one state worth shouting about */
.slotbx.sb-crit{border-color:var(--hot);background:var(--hot);box-shadow:3px 3px 0 var(--ink)}
.slotbx.sb-crit b{color:#fff}
.slotbx.sb-crit i{color:rgba(255,255,255,.82)}
.slotbx.sb-crit i u{color:#fff}
.slotbx.sb-gone,.slotbx.sb-off{border-color:var(--gone);background:var(--card2)}
.slotbx.sb-gone b,.slotbx.sb-off b,.sp-hd .pz .slotbx.sb-gone b,.sp-hd .pz .slotbx.sb-off b{
  font-size:19px;color:var(--gone)}
.slotbx.sb-gone i u,.slotbx.sb-off i u{color:var(--mu)}
@media(prefers-reduced-motion:no-preference){
  .slotbx.sb-crit{animation:slotpulse 2.4s ease-in-out infinite}
}
@keyframes slotpulse{
  0%,100%{box-shadow:3px 3px 0 var(--ink)}
  50%{box-shadow:3px 3px 0 var(--ink),0 0 0 5px rgba(180,86,12,.20)}
}
@media(max-width:560px){
  .slotbx b,.sp-hd .pz .slotbx b{font-size:23px}
  .slotbx{padding:6px 10px 6px 9px;gap:8px}
}
.sp-col{display:grid;grid-template-columns:minmax(0,1fr);gap:0}
@media(min-width:900px){
  .sp-col{grid-template-columns:minmax(0,1.15fr) minmax(0,1fr);gap:0 44px;align-items:start}
  .sp-col .cA{grid-column:1;grid-row:1/span 2}
  .sp-col .stwrap{grid-column:2;grid-row:1}
  .sp-col .cB{grid-column:2;grid-row:2}
}
.sbar{position:fixed;left:0;right:0;bottom:0;z-index:80;display:flex;background:var(--paper);
  border-top:3px solid var(--ink);padding:10px 16px calc(10px + env(safe-area-inset-bottom));
  align-items:center;gap:12px}
.sbar .in{max-width:1120px;margin:0 auto;width:100%;display:flex;align-items:center;gap:12px}
.sbar b{font-family:var(--blk);font-size:21px;letter-spacing:-.8px;line-height:1.05;display:block}
.sbar span{font-family:var(--osw);font-size:10.4px;font-weight:300;letter-spacing:.07em;text-transform:uppercase;
  color:var(--mu)}
.sbar .btn{margin-left:auto;min-width:180px}
@media(max-width:560px){.sbar .btn{min-width:0;flex:1}}
/* ── live status ── */
.sp{display:inline-flex;align-items:center;gap:6px;font-family:var(--osw);font-size:9.3px;font-weight:600;
  letter-spacing:.07em;text-transform:uppercase;padding:3px 6px;border:1.5px solid var(--ink);
  background:var(--acid);color:var(--ink);margin-bottom:7px;max-width:100%}
.sp u{text-decoration:none;font-weight:400;opacity:.6;white-space:nowrap}
.sp.watch{background:var(--hot-soft);border-color:var(--hot);color:var(--hot)}
.sp.off{background:var(--ink);border-color:var(--ink);color:var(--paper)}
.stbig{border:1.5px solid var(--ink);background:var(--card);padding:14px;margin:16px 0 2px}
.stbig .hd{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.stbig .lb{font-family:var(--blk);font-size:16px;letter-spacing:-.4px;text-transform:uppercase;
  background:var(--acid);border:1.5px solid var(--ink);padding:5px 9px}
.stbig .ts{font-family:var(--osw);font-size:10.4px;font-weight:400;letter-spacing:.07em;
  text-transform:uppercase;color:var(--mu)}
.stbig p{margin-top:11px;font-size:14px;line-height:1.55;color:var(--ink2)}
.stbig .ft{margin-top:11px;padding-top:10px;border-top:1px solid var(--rule);font-family:var(--osw);
  font-size:9.8px;font-weight:300;letter-spacing:.06em;text-transform:uppercase;color:var(--mu2);line-height:1.7}
.stbig.watch{border-color:var(--hot);background:var(--hot-soft)}
.stbig.watch .lb{background:var(--card);border-color:var(--hot);color:var(--hot)}
.stbig.off{border-color:var(--ink);background:var(--ink)}
.stbig.off .lb{background:var(--paper);color:var(--ink)}
.stbig.off .ts{color:var(--mu2)}
.stbig.off p{color:#E4E0D4}
.stbig.off .ft{border-top-color:#3A3A38;color:#8B8579}
/* ── session description ── */
.desc{font-size:14.5px;line-height:1.62;color:var(--ink2)}
.dmeta{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-top:12px;padding-left:11px;
  border-left:3px solid var(--rule2);font-family:var(--osw);font-size:9.8px;font-weight:400;
  letter-spacing:.07em;text-transform:uppercase;color:var(--mu2)}
.dmeta b{font-weight:600;color:var(--acid-dk);background:var(--acid-soft);border:1px solid var(--rule2);padding:2px 5px}
.flag{border:1.5px solid var(--rule2);border-left:4px solid var(--acid);background:var(--card);
  padding:9px 13px;margin:16px auto 4px;max-width:1088px;width:calc(100% - 32px);
  font-family:var(--osw);font-size:11.4px;letter-spacing:.06em;color:var(--mu);line-height:1.7;text-transform:uppercase}
/* ── day divider ───────────────────────────────────────────────────────────
   Centred and boxed, with the rule running behind it, so scrolling the board
   gives you an unmistakable break between one day and the next rather than a
   line of small caps you have to look for. */
.dayhd{position:relative;display:flex;justify-content:center;margin:34px 0 6px}
.dayhd:before{content:'';position:absolute;left:0;right:0;top:50%;height:3px;
  background:var(--pitch);opacity:.16}
.dayhd .in{position:relative;display:inline-flex;align-items:center;gap:12px;
  background:var(--paper);border:2.5px solid var(--pitch);padding:8px 16px}
.dayhd b{font-family:var(--blk);font-size:17px;letter-spacing:-.5px;text-transform:uppercase;
  line-height:1;color:var(--pitch)}
.dayhd .dt{font-family:var(--osw);font-size:11.4px;font-weight:600;letter-spacing:.09em;
  text-transform:uppercase;color:var(--mu);line-height:1}
.dayhd em{font-style:normal;font-family:var(--osw);font-size:10px;font-weight:600;letter-spacing:.08em;
  text-transform:uppercase;color:var(--mu2);border-left:1.5px solid var(--rule2);padding-left:12px;line-height:1}
/* today is the one you actually came for */
.dayhd.now .in{background:var(--acid);border-color:var(--ink);box-shadow:4px 4px 0 var(--ink)}
.dayhd.now b,.dayhd.now .dt{color:var(--ink)}
.dayhd.now em{color:var(--acid-dk);border-left-color:rgba(14,26,18,.28)}
.dayhd.now:before{background:var(--ink);opacity:.22}
@media(max-width:560px){
  .dayhd{margin:26px 0 4px}
  .dayhd .in{gap:9px;padding:7px 12px;flex-wrap:wrap;justify-content:center}
  .dayhd b{font-size:15px}
  .dayhd .dt{font-size:10.4px}
  .dayhd em{font-size:9.4px;padding-left:9px}
}

.row{position:relative;display:grid;grid-template-columns:70px 148px minmax(0,1fr) 118px 100px;gap:16px;align-items:center;
  padding:15px 0 16px;border-bottom:1.5px solid var(--rule);cursor:pointer;transition:.12s}
.row:hover{background:var(--card2)}
.th{position:relative;border:1.5px solid var(--rule2);background:var(--card2);overflow:hidden;
  aspect-ratio:5/4;cursor:zoom-in;transition:.12s}
.th svg,.th .pimg{width:100%;height:100%;display:block;object-fit:cover}
.th:hover{border-color:var(--ink);box-shadow:2px 2px 0 var(--ink)}
.th .zm{position:absolute;right:0;bottom:0;background:var(--acid);border-left:1.5px solid var(--ink);
  border-top:1.5px solid var(--ink);padding:4px 5px 3px;color:var(--ink);line-height:0}
.th .zm svg{width:12px;height:12px}
.th:hover .zm{background:var(--ink);color:var(--acid)}
.row .t{font-family:var(--blk);font-size:21px;letter-spacing:-1px;line-height:1}
.row .t i{display:block;font-style:normal;font-family:var(--osw);font-size:10.4px;font-weight:300;
  letter-spacing:.05em;color:var(--mu);margin-top:6px}
.row h3{font-family:var(--blk);font-size:15.5px;letter-spacing:-.4px;line-height:1.15;text-transform:uppercase;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.row .meta{font-family:var(--osw);font-size:10.4px;font-weight:300;letter-spacing:.06em;text-transform:uppercase;
  color:var(--mu);margin-top:6px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.row .st{text-align:right;font-family:var(--osw);font-size:11.5px;font-weight:500;letter-spacing:.06em}
.row .st.ok{color:var(--acid-dk)}.row .st.hot{color:var(--hot)}.row .st.full{color:var(--gone)}
.row .st u{display:block;text-decoration:none;font-size:10.5px;font-weight:300;color:var(--mu);
  margin-top:6px;letter-spacing:.1em;white-space:nowrap}
/* a live countdown is the one number that decides whether you leave now */
.row .st u.cd{font-family:var(--osw);font-size:14px;font-weight:600;letter-spacing:.02em;color:var(--ink);
  margin-top:5px}
.row .st.hot u.cd{color:var(--hot)}
.row .pz{text-align:right}
.row .pr{font-family:var(--blk);font-size:17px;letter-spacing:-.6px}
.row .go{display:inline-block;margin-top:7px;font-family:var(--osw);font-size:10.4px;font-weight:500;
  letter-spacing:.08em;padding:6px 12px;background:var(--acid);color:var(--ink);border:1.5px solid var(--ink)}
.row .go.alt{background:var(--card);color:var(--ink2);border-color:var(--rule2)}
.row.gone{opacity:.52}
/* a one off we are filling, marked on the board */
.row.fillgame{border-left:4px solid var(--fill);padding-left:12px;background:var(--fill-soft)}
.row.fillgame:hover{background:#F8E4E2}
.fillmk{display:inline-block;background:var(--fill-soft);border:1px solid var(--fill);
  color:var(--fill-ink);padding:1px 5px;margin-right:7px;font-weight:600;letter-spacing:.1em}
@media(max-width:760px){ .row.fillgame{padding-left:10px;border-left-width:3px} }
.row .meta .ar{display:inline-block;background:var(--acid-soft);border:1px solid var(--rule2);color:var(--acid-dk);
  padding:1px 5px;margin-right:7px;font-weight:500;letter-spacing:.12em}
/* segmented capacity meter — reads as "filling up" at a glance */
.meter{display:inline-flex;gap:2px;vertical-align:middle}
.meter i{width:6px;height:12px;background:var(--card);border:1px solid var(--rule2)}
.meter i.f{background:var(--acid);border-color:var(--ink)}
.meter.hot i.f{background:var(--hot);border-color:var(--hot)}
.meter.full i.f{background:var(--gone);border-color:var(--gone)}
.row .st .meter{display:flex;justify-content:flex-end;margin-top:7px}
.meter.big i{width:11px;height:22px}

.empty{text-align:center;padding:64px 20px;font-family:var(--osw);font-size:11.5px;letter-spacing:.07em;color:var(--mu)}
.empty b{display:block;font-family:var(--blk);color:var(--ink);font-size:20px;margin-bottom:12px;letter-spacing:-.5px}

/* ── map ── */
#mapv{display:none}#mapv.on{display:block}#listv.off{display:none}
.mapbox{border:1.5px solid var(--ink);overflow:hidden;margin:16px auto 0;max-width:1088px;width:calc(100% - 32px)}
.pin{cursor:pointer}
.pin.on rect{stroke-width:4}
.mapnote{font-family:var(--osw);font-size:10.9px;letter-spacing:.08em;color:var(--mu);text-align:center;padding:13px 0;text-transform:uppercase}

/* ── sheet ── */
.scrim{position:fixed;inset:0;z-index:200;background:rgba(16,16,16,.55);opacity:0;transition:.2s;pointer-events:none}
.scrim.on{opacity:1;pointer-events:auto}
.sheet{position:fixed;left:0;right:0;bottom:0;z-index:210;background:var(--paper);border-top:3px solid var(--ink);
  max-height:94dvh;display:flex;flex-direction:column;transform:translateY(102%);pointer-events:none;
  transition:transform .26s cubic-bezier(.2,.85,.3,1)}
.sheet.on{transform:translateY(0);pointer-events:auto}
@media(min-width:760px){
  .sheet{left:50%;right:auto;bottom:auto;top:50%;width:660px;max-height:88vh;border:3px solid var(--ink);
    transform:translate(-50%,-42%);opacity:0;transition:.22s cubic-bezier(.2,.85,.3,1)}
  .sheet.on{transform:translate(-50%,-50%);opacity:1}
}
.shd{display:flex;align-items:flex-start;gap:12px;padding:16px;border-bottom:3px solid var(--ink);flex:0 0 auto}
.shd h2{font-family:var(--blk);font-size:21px;letter-spacing:-.7px;line-height:1.06;text-transform:uppercase}
.shd .sub{font-family:var(--osw);font-size:10.9px;font-weight:300;letter-spacing:.08em;text-transform:uppercase;
  color:var(--mu);margin-top:8px}
.shd .x{margin-left:auto;width:32px;height:32px;border:1.5px solid var(--ink);display:flex;align-items:center;
  justify-content:center;flex:none;background:var(--card)}
/* The only way out of a full-screen sheet on a phone, and it was a 32px square.
   The box stays 32 so the header does not change; the tappable area is grown
   with padding and pulled back with a negative margin. */
@media(max-width:860px){
  .shd .x{width:44px;height:44px;margin-right:-6px}
}
.sbody{flex:1 1 auto;min-height:0;overflow-y:auto;overscroll-behavior:contain;padding:0 16px 16px}
/* ── the sheet's footer ──
   This was called .sfoot, and so is the SITE footer on every page. Two
   unrelated components wearing one class, with the site footer's rule later in
   the file and therefore winning: the booking sheet's footer was being painted
   dark green, in light-on-dark colours meant for a page footer, with
   `padding:34px 0 30px`. The zero is why the price sat flush against the
   sheet's left edge with nothing between it and the border.

   Renamed to .shfoot, beside .shd and .sbody, which is what it should have
   been called. The site footer keeps .sfoot because it is on six pages; this
   is one div and every call site addresses it by #sfoot. */
.shfoot{flex:0 0 auto;position:relative;z-index:2;
  padding:14px 18px calc(14px + env(safe-area-inset-bottom));
  border-top:3px solid var(--ink);background:var(--paper);
  display:flex;align-items:center;gap:16px}
.shfoot:empty{display:none}
/* The price is the thing being agreed to, so it gets room and never shrinks
   under the button beside it. */
.shfoot .pz{flex:0 0 auto;min-width:0}
.shfoot .pz b{font-family:var(--blk);font-size:22px;letter-spacing:-.7px;display:block;
  line-height:1.05;white-space:nowrap}
.shfoot .pz span{display:block;font-family:var(--osw);font-size:10px;font-weight:500;
  letter-spacing:.11em;text-transform:uppercase;color:var(--mu);margin-top:3px}
.shfoot .btn{min-height:50px}
/* Two buttons in a footer: the secondary one takes the width of its label and
   the primary takes the rest, and neither is allowed to be squeezed below a
   tappable size or to lose its border to the edge. */
.shfoot .btn-o{flex:0 0 auto;white-space:nowrap}
.shfoot .btn-a{flex:1 1 auto;min-width:0}

/* The venue row on the confirmation screen is a link now, so it has to look
   like one without breaking the rhythm of the ticks above it. */
.am .r.lk{text-decoration:none;color:inherit;cursor:pointer}
.am .r.lk:hover span:last-child{color:var(--ink)}
.am .r.lk i{display:block;font-style:normal;font-family:var(--osw);font-size:10px;
  font-weight:500;letter-spacing:.09em;text-transform:uppercase;color:var(--mu);margin-top:3px;
  border-bottom:1.5px solid var(--acid);padding-bottom:2px;width:-moz-fit-content;width:fit-content}
.am .r.lk:hover i{color:var(--ink)}
/* Below about 380px the price and a full-width button genuinely do not fit on
   one line, so they stack rather than squeezing the button to a stub. */
@media(max-width:380px){
  .shfoot{flex-wrap:wrap;gap:10px 16px}
  .shfoot .pz{flex:1 1 100%}
  .shfoot .btn{flex:1 1 100%}
}

.blk2{padding:18px 0;border-bottom:1.5px solid var(--rule)}
.blk2:last-child{border-bottom:0}
.blk2 h4{font-family:var(--osw);font-size:10.9px;font-weight:600;letter-spacing:.08em;text-transform:uppercase;
  color:var(--pitch);padding-bottom:9px;border-bottom:1.5px solid var(--pitch);margin-bottom:14px}
.kv{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:15px}
.kv .k{font-family:var(--osw);font-size:10.4px;font-weight:300;letter-spacing:.09em;text-transform:uppercase;color:var(--mu)}
.kv .v{font-family:var(--blk);font-size:16px;letter-spacing:-.4px;margin-top:4px;text-transform:uppercase}
.gauge{display:flex;align-items:center;gap:12px;margin-top:18px;flex-wrap:wrap}
.gauge .meter{flex:none}
/* minimum-to-run: honest scarcity, not theatre */
.needs{margin-top:12px;border:1.5px solid var(--rule2);border-left:4px solid var(--hot);
  background:var(--card);padding:10px 12px;font-size:13px;line-height:1.55;color:var(--ink2)}
.gauge .bar{flex:1;height:6px;background:var(--rule);overflow:hidden;border:1px solid var(--rule2)}
.gauge .bar i{display:block;height:100%;background:var(--acid)}
.gauge .bar.hot i{background:var(--hot)}.gauge .bar.full i{background:var(--gone)}
.gauge .n{font-family:var(--osw);font-size:11px;font-weight:500;letter-spacing:.06em;white-space:nowrap}
.note{border:1.5px solid var(--rule2);border-left:4px solid var(--acid);background:var(--card);
  padding:12px 14px;font-size:13.5px;color:var(--ink2);line-height:1.6}
.note.warn{border-left-color:var(--hot)}
.am{display:flex;flex-direction:column}
.am .r{display:flex;align-items:center;gap:11px;padding:10px 0;border-bottom:1px solid var(--rule);font-size:14.5px}
.am .r:last-child{border-bottom:0}
.am .r .i{width:19px;height:19px;border:1.5px solid var(--ink);display:flex;align-items:center;justify-content:center;
  flex:none;background:var(--acid)}
.am .r.f .i{background:var(--card)}
.am .r.n .i{background:var(--card);border-color:var(--rule2);color:var(--mu2)}
.am .r.n{color:var(--mu)}
.am .r .i svg{width:11px;height:11px}
.am .r .tag{margin-left:auto;font-family:var(--osw);font-size:10.9px;font-weight:500;letter-spacing:.06em;
  text-transform:uppercase;color:var(--mu)}
.am .r.f .tag{color:var(--acid-dk);font-weight:600}
/* ── kit grid ── */
.kit{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:8px}
.kt{background:var(--card);border:1.5px solid var(--rule2);padding:11px 10px 10px;
  display:flex;flex-direction:column;gap:9px;min-height:94px}
.kt .ic{width:30px;height:30px;border:1.5px solid var(--ink);background:var(--acid);flex:none;
  display:flex;align-items:center;justify-content:center}
.kt .ic svg{width:16px;height:16px}
.kt .n{flex:1;font-size:12.5px;font-weight:600;line-height:1.28;letter-spacing:-.1px}
.kt .n i{display:block;font-style:normal;font-family:var(--osw);font-size:9.3px;font-weight:300;
  letter-spacing:.05em;text-transform:uppercase;color:var(--mu);margin-top:4px}
.kt .p{font-family:var(--osw);font-size:9.8px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;color:var(--acid-dk)}
.kt.fee .ic{background:var(--card)}
.kt.fee .p{color:var(--ink);background:var(--acid-soft);align-self:flex-start;padding:2px 5px;border:1px solid var(--rule2)}
.kt.byo{background:var(--card2);border-style:dashed}
.kt.byo .ic{background:transparent;border-style:dashed;border-color:var(--rule2);color:var(--mu2)}
.kt.byo .n{color:var(--mu);font-weight:500}
.kt.byo .p{color:var(--mu2);font-weight:400}
.klg{display:flex;gap:15px;flex-wrap:wrap;margin-top:12px;font-family:var(--osw);font-size:9.8px;
  font-weight:400;letter-spacing:.06em;text-transform:uppercase;color:var(--mu)}
.klg span{display:flex;align-items:center;gap:6px}
.klg i{width:11px;height:11px;border:1.5px solid var(--ink);background:var(--acid);flex:none}
.klg i.f{background:var(--card)}
.klg i.b{background:transparent;border-style:dashed;border-color:var(--rule2)}
.hn{list-style:none}
.hn li{position:relative;padding-left:19px;font-size:13.5px;color:var(--ink2);line-height:1.55;margin-bottom:10px}
.hn li:last-child{margin-bottom:0}
.hn li:before{content:'';position:absolute;left:0;top:6px;width:8px;height:8px;background:var(--acid);border:1.5px solid var(--ink)}
/* ── facilities grid ── */
.fgrid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:8px}
@media(max-width:560px){.fgrid{grid-template-columns:repeat(2,minmax(0,1fr))}}
.ft1{border:1.5px solid var(--rule2);background:var(--card);padding:11px 10px;display:flex;
  flex-direction:column;gap:8px;min-height:84px}
.ft1 .ic{width:26px;height:26px;border:1.5px solid var(--ink);background:var(--acid);flex:none;
  display:flex;align-items:center;justify-content:center}
.ft1 .ic svg{width:14px;height:14px}
.ft1 .n{flex:1;font-size:12.5px;font-weight:600;line-height:1.25}
.ft1 .p{font-family:var(--osw);font-size:9.3px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;
  color:var(--acid-dk)}
.ft1.fee .ic{background:var(--card)}
.ft1.fee .p{color:var(--ink2)}
.ft1.no{background:var(--card2);border-style:dashed}
.ft1.no .ic{background:transparent;border-color:var(--rule2);color:var(--mu2)}
.ft1.no .n{color:var(--mu);font-weight:500}
.ft1.no .p{color:var(--mu2);font-weight:400}
/* ── real map ── */
.omap{border:1.5px solid var(--ink);background:var(--card2);overflow:hidden;
  position:relative;isolation:isolate}
/* The session-page map. This height rule was missing after the switch from a
   Google iframe to Leaflet, so the map drew into a 0px box and looked broken. */
.omap .lmap{width:100%;height:320px}
.omap .of{position:absolute;left:0;bottom:0;background:var(--paper);border-top:1.5px solid var(--ink);
  border-right:1.5px solid var(--ink);font-family:var(--osw);font-size:9.3px;font-weight:400;
  letter-spacing:.05em;text-transform:uppercase;color:var(--mu);padding:4px 8px}
.mapbox{position:relative;isolation:isolate}
#leafmap{height:440px;width:100%}
@media(max-width:640px){#leafmap{height:340px}.omap .lmap{height:250px}}

/* "Where am I" sits over the map on both the board and a session page.
   Top right: Leaflet puts zoom at top left and attribution at bottom right,
   so that corner is the only one free. Its controls go up to z-index 800. */
.locbtn{position:absolute;right:10px;top:10px;z-index:900;display:flex;align-items:center;gap:7px;
  background:var(--card);border:1.5px solid var(--ink);box-shadow:2px 2px 0 var(--ink);padding:7px 10px;
  font-family:var(--osw);font-size:10.4px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;
  color:var(--ink);transition:.12s}
.locbtn:hover{background:var(--acid)}
.locbtn:active{transform:translate(2px,2px);box-shadow:0 0 0 var(--ink)}
.locbtn svg{width:14px;height:14px;flex:none}
@media(max-width:560px){.locbtn span{display:none}.locbtn{padding:9px}}
/* the "you are here" dot */
.mepin{width:18px;height:18px;border-radius:50%;background:var(--acid);border:3px solid var(--ink);
  box-shadow:0 0 0 4px rgba(217,240,53,.3)}
.mapfoot{font-family:var(--osw);font-size:10px;font-weight:400;letter-spacing:.05em;
  text-transform:uppercase;color:var(--mu);padding:9px 2px 0;line-height:1.6}
.mapfoot b{color:var(--ink);font-weight:600}
.mapfail{border:1.5px solid var(--rule2);background:var(--card2);padding:18px;font-size:14px;color:var(--ink2)}
.mapfail a{text-decoration:underline;font-weight:600;color:var(--ink)}
.leaflet-container{background:#E7E2D6!important;font-family:var(--sans)!important}
.pinmk{display:flex;align-items:center;justify-content:center;font-family:var(--osw);font-size:11px;
  font-weight:600;color:var(--ink);background:var(--acid);border:2px solid var(--ink);width:28px;height:28px;
  box-shadow:2px 2px 0 rgba(16,16,16,.35)}
.pinmk.full{background:var(--gone);color:var(--paper)}
.pinmk.on{outline:3px solid var(--ink);outline-offset:1px}
.pinmk.big{width:34px;height:34px}
.pinmk.big svg{width:17px;height:17px}
/* ── organiser profile ── */
.hcover{border:1.5px solid var(--ink);overflow:hidden;position:relative;margin-top:18px;aspect-ratio:16/5}
.hcover svg,.hcover .pimg{width:100%;height:100%;display:block;object-fit:cover}
.vthumb{width:74px;flex:none;border:1.5px solid var(--rule2);overflow:hidden;aspect-ratio:4/3}
.vthumb svg,.vthumb .pimg{width:100%;height:100%;display:block;object-fit:cover}
.hhd{display:flex;align-items:flex-start;gap:16px;flex-wrap:wrap;padding:18px 0 6px}
.hhd .av2{font-family:var(--blk);font-size:26px;letter-spacing:-1px;background:var(--acid);
  border:2px solid var(--ink);padding:14px 16px;flex:none;box-shadow:4px 4px 0 var(--ink)}
.hhd h1{font-family:var(--blk);font-size:clamp(24px,5.6vw,34px);letter-spacing:-1.2px;line-height:1.02;
  text-transform:uppercase}
.hhd .sub{font-family:var(--osw);font-size:10.9px;font-weight:400;letter-spacing:.08em;text-transform:uppercase;
  color:var(--mu);margin-top:9px}
.hstats{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:9px;margin:18px 0 4px}
@media(max-width:560px){.hstats{grid-template-columns:repeat(2,minmax(0,1fr))}}
.hstat{border:1.5px solid var(--rule2);background:var(--card);padding:12px}
.hstat .k{font-family:var(--osw);font-size:9.3px;font-weight:400;letter-spacing:.08em;text-transform:uppercase;color:var(--mu)}
.hstat .v{font-family:var(--blk);font-size:21px;letter-spacing:-.8px;margin-top:6px;line-height:1}
.hostr.link{cursor:pointer;transition:.12s;border:1.5px solid var(--rule2);background:var(--card);padding:12px}
.hostr.link:hover{border-color:var(--ink);box-shadow:3px 3px 0 var(--acid)}
.hostr .arw{margin-left:auto;flex:none;display:flex;align-items:center;gap:7px;font-family:var(--osw);
  font-size:9.8px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;color:var(--mu)}
.hostr .arw svg{width:13px;height:13px}
/* ── photos ── */
.hero{position:relative;border:1.5px solid var(--ink);overflow:hidden;margin-bottom:2px;aspect-ratio:16/7}
.hero svg,.hero .pimg{width:100%;height:100%;display:block;object-fit:cover}
.hero .gb{position:absolute;right:0;bottom:0;background:var(--acid);border-left:1.5px solid var(--ink);
  border-top:1.5px solid var(--ink);font-family:var(--osw);font-size:10.4px;font-weight:600;letter-spacing:.07em;
  text-transform:uppercase;padding:7px 11px;display:flex;align-items:center;gap:6px}
.hero .gb svg{width:12px;height:12px}
.hero{cursor:zoom-in}
.hero:hover .gb{background:var(--ink);color:var(--acid)}
.gsec{font-family:var(--osw);font-size:10.4px;font-weight:500;letter-spacing:.09em;text-transform:uppercase;
  color:var(--mu);padding:16px 0 9px;border-bottom:1.5px solid var(--ink);margin-bottom:12px}
.gal{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px}
@media(min-width:560px){.gal{grid-template-columns:repeat(3,minmax(0,1fr))}}
.gal figure{border:1.5px solid var(--rule2);background:var(--card);margin:0}
.gal .im{overflow:hidden;border-bottom:1.5px solid var(--rule2);aspect-ratio:4/3;
  position:relative;cursor:zoom-in;background:var(--card2)}
.gal .im svg,.gal .im .pimg{width:100%;height:100%;display:block;object-fit:cover}
.gal .im:after{content:'';position:absolute;inset:0;background:var(--ink);opacity:0;transition:.14s}
@media(hover:hover){.gal .im:hover:after{opacity:.14}}
.gal figcaption{font-family:var(--osw);font-size:9.3px;font-weight:400;letter-spacing:.07em;
  text-transform:uppercase;color:var(--mu);padding:7px 8px}
/* the club mark, wherever it appears */
.av{display:inline-flex;align-items:center;justify-content:center;font-family:var(--blk);font-size:17px;
  letter-spacing:-.5px;background:var(--acid);border:1.5px solid var(--ink);padding:9px 10px;flex:none}
.hostr{display:flex;align-items:center;gap:12px}
.hostr .av{font-family:var(--blk);font-size:17px;letter-spacing:-.5px;background:var(--acid);border:1.5px solid var(--ink);
  padding:9px 10px;flex:none}
.hostr b{font-family:var(--blk);font-size:16px;letter-spacing:-.4px;display:block;text-transform:uppercase}
.hostr span{font-family:var(--osw);font-size:10.4px;font-weight:300;letter-spacing:.06em;text-transform:uppercase;
  color:var(--mu);margin-top:4px;display:block}
.hostr .bd{margin-left:auto;font-family:var(--osw);font-size:10.4px;font-weight:600;letter-spacing:.07em;
  padding:6px 10px;background:var(--acid);border:1.5px solid var(--ink)}
.hostr .bd.listed{background:var(--card);border-color:var(--rule2);color:var(--mu)}

/* ── forms ── */
.f{margin-bottom:13px}
.f label{display:block;font-family:var(--osw);font-size:10.4px;font-weight:500;letter-spacing:.09em;
  text-transform:uppercase;color:var(--mu);margin-bottom:6px}
.inp{width:100%;background:var(--card);border:1.5px solid var(--rule2);padding:13px;font-size:16px;
  color:var(--ink);transition:.12s;border-radius:0}
.inp:focus{outline:none;border-color:var(--ink);box-shadow:3px 3px 0 var(--acid)}
.inp::placeholder{color:var(--mu2)}
textarea.inp{resize:vertical;min-height:76px;font-family:inherit;line-height:1.5}
/* stacked label + field, used by the ad enquiry form */
.fld{display:block;margin-bottom:13px;font-family:var(--osw);font-size:10.4px;font-weight:600;
  letter-spacing:.07em;text-transform:uppercase;color:var(--mu)}
.fld .inp{margin-top:6px;text-transform:none;letter-spacing:0;font-weight:400;color:var(--ink)}
/* our own ad, so it reads as house rather than as inventory */
/* our own ad, so it reads as house rather than as inventory */
.adx.house .sq{background:var(--pitch);color:var(--acid);border-color:var(--pitch)}

/* ── a sold slot: the advertiser's artwork, full bleed ──────────────────────
   No border and no padding, so the file fills the exact unit and what they
   designed is what appears. See "Ad artwork" in the README for the sizes. */
.adx.artad{border:0;padding:0;gap:0;background:var(--card2)}
.adx.artad img{width:100%;height:100%;object-fit:cover;display:block}
.adx.artad .go2{display:none}
.adx.artad:hover,.adx.artad:focus-visible{box-shadow:0 0 0 2px var(--ink);outline:none}
.two{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px}
.pay{display:flex;align-items:center;gap:11px;padding:12px;border:1.5px solid var(--rule2);background:var(--card);
  margin-bottom:7px;cursor:pointer;transition:.12s}
.pay.on{border-color:var(--ink);background:var(--acid-soft);box-shadow:3px 3px 0 var(--ink)}
.pay .tg{font-family:var(--osw);font-size:10.4px;font-weight:500;letter-spacing:.05em;padding:5px 7px;
  border:1.5px solid var(--rule2);color:var(--mu);flex:none;min-width:52px;text-align:center}
.pay.on .tg{border-color:var(--ink);background:var(--acid);color:var(--ink);font-weight:600}
/* The accepted-methods badge, under the list. Nothing around it: it is a
   supplied lockup with its own clear space built in, so a border or a tint
   would be fighting it. */
.paybadge{display:block;width:100%;max-width:400px;height:auto;margin:16px auto 2px}
.pay b{font-size:14px;font-weight:700;display:block}
.pay span{font-family:var(--osw);font-size:10.4px;font-weight:300;letter-spacing:.05em;color:var(--mu);
  display:block;margin-top:3px;text-transform:uppercase}
.pay .rd{margin-left:auto;width:16px;height:16px;border:1.5px solid var(--rule2);flex:none;position:relative;background:#fff}
.pay.on .rd{border-color:var(--ink)}
.pay.on .rd:after{content:'';position:absolute;inset:3px;background:var(--ink)}
.sum{border:1.5px solid var(--ink);background:var(--card);padding:13px;margin-bottom:13px}
.sum .l{display:flex;justify-content:space-between;padding:5px 0;font-family:var(--osw);font-size:11px;
  font-weight:300;letter-spacing:.05em;text-transform:uppercase;color:var(--mu)}
.sum .l b{color:var(--ink);font-weight:500}
.sum .tot{border-top:1.5px solid var(--ink);margin-top:9px;padding-top:11px;display:flex;
  justify-content:space-between;align-items:center}
.sum .tot b{font-family:var(--blk);font-size:23px;letter-spacing:-.8px}
.btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;padding:14px 18px;
  font-family:var(--osw);font-size:11.5px;font-weight:600;letter-spacing:.09em;text-transform:uppercase;
  transition:.12s;border:1.5px solid var(--ink)}
.btn-a{background:var(--acid);color:var(--ink)}
.btn-a:hover{box-shadow:3px 3px 0 var(--ink)}
.btn-o{background:var(--card);color:var(--ink)}
.btn-o:hover{box-shadow:3px 3px 0 var(--ink)}
.btn-k{background:var(--ink);color:var(--acid)}
.btn[disabled]{opacity:.4;pointer-events:none}
.btn svg{width:14px;height:14px}
.ok{text-align:center;padding:24px 0}
.ok .ref{display:inline-block;font-family:var(--blk);font-size:46px;letter-spacing:-2px;background:var(--acid);
  border:2.5px solid var(--ink);padding:10px 20px;box-shadow:5px 5px 0 var(--ink)}
.ok h3{font-family:var(--blk);font-size:26px;letter-spacing:-.8px;text-transform:uppercase;margin-top:22px}
.ok p{color:var(--mu);font-family:var(--osw);font-size:11px;font-weight:300;letter-spacing:.06em;
  text-transform:uppercase;margin-top:9px}
.spin{width:30px;height:30px;border:2.5px solid var(--rule2);border-top-color:var(--ink);
  animation:sp .8s linear infinite;margin:0 auto}
@keyframes sp{to{transform:rotate(360deg)}}
.fg{margin-bottom:20px}
.fg h5{font-family:var(--osw);font-size:10.4px;font-weight:500;letter-spacing:.09em;text-transform:uppercase;
  color:var(--mu);margin-bottom:10px;padding-bottom:7px;border-bottom:1.5px solid var(--rule)}
.fo{display:flex;gap:6px;flex-wrap:wrap}
.fo button{border:1.5px solid var(--rule2);background:var(--card);padding:9px 13px;font-family:var(--osw);
  font-size:11.4px;font-weight:400;letter-spacing:.06em;text-transform:uppercase;color:var(--ink2)}
.fo button.on{background:var(--acid);border-color:var(--ink);color:var(--ink);font-weight:600}

.toast{position:fixed;left:50%;transform:translateX(-50%);bottom:88px;z-index:300;background:var(--ink);color:var(--acid);
  padding:12px 17px;font-family:var(--osw);font-size:11px;font-weight:500;letter-spacing:.07em;text-transform:uppercase;
  max-width:calc(100% - 32px);text-align:center;opacity:0;transition:.2s;pointer-events:none}
.toast.on{opacity:1}
/* ══════════════════════════════════════════════════════════════════
   SITE FOOTER
   One component on all three public pages. It was a single row of four
   small-caps links, which is fine as a nav and useless as a footer: no
   mark, no statement of what the site is, nothing for a person landing
   on a session page from a WhatsApp link and wondering who this is.

   The two paragraphs above the baseline are real content, not keyword
   stuffing: a visitor genuinely wants to know which formats run and
   which parts of the valley are covered before they read a listing.
   Every area named is an area we actually have a venue in.
   ══════════════════════════════════════════════════════════════════ */
.sfoot{border-top:3px solid var(--ink);background:var(--pitch);color:var(--pitch-ink);
  margin-top:40px;padding:34px 0 30px}
.sfoot a{color:rgba(242,240,231,.76);transition:color .14s}
.sfoot a:hover{color:var(--acid)}

.sf-top{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,2.1fr);gap:34px;
  align-items:start}
.sf-brand img{height:29px;width:auto}
.sf-brand p{margin-top:13px;font-size:13.4px;line-height:1.6;color:#C9D8C6;max-width:40ch}

.sf-nav{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:20px 16px}
.sf-col{display:flex;flex-direction:column;align-items:flex-start;gap:2px}
/* h2 because these are the footer's section headings and the page above has
   already used h1 once. Styled as a label, still a heading in the outline. */
.sf-col h2{font-family:var(--osw);font-size:9.6px;font-weight:700;letter-spacing:.14em;
  text-transform:uppercase;color:var(--acid);margin-bottom:7px;line-height:1}
.sf-col a,.sf-col .cur{font-family:var(--osw);font-size:11.4px;font-weight:500;
  letter-spacing:.05em;padding:6px 0;display:inline-flex;align-items:center;min-height:32px}
.sf-col .cur{color:rgba(242,240,231,.40);cursor:default}

.sf-key{margin-top:28px;padding-top:20px;border-top:1px solid rgba(242,240,231,.20);
  display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:14px 34px}
.sf-key p{font-size:12.6px;line-height:1.65;color:#AFC2AC;margin:0}
.sf-key b{color:#C9D8C6;font-weight:600}

.sf-base{margin-top:22px;padding-top:17px;border-top:1px solid rgba(242,240,231,.20);
  display:flex;gap:14px 22px;flex-wrap:wrap;align-items:center}
.sf-cp{font-family:var(--osw);font-size:10.4px;letter-spacing:.06em;text-transform:uppercase;
  max-width:72ch;line-height:1.7;
  color:#8B9E88}
/* the Studio 42 credit, reverse variant, per their brand pack */
.sfoot .s42{margin-left:auto;display:inline-flex;align-items:center;gap:8px;font-size:11.5px;
  letter-spacing:.02em;color:#8B9E88;min-height:32px}
.sfoot .s42 b{font-family:Georgia,'Times New Roman',serif;font-weight:600;font-size:12.5px;
  letter-spacing:-.01em;color:#E8E6DC;text-transform:none}
.sfoot .s42 b i{font-style:normal;color:#7FB3A1}
.sfoot .s42:hover b{color:#fff}

@media(max-width:860px){
  .sf-top{grid-template-columns:minmax(0,1fr);gap:26px}
  .sf-brand p{max-width:none}
}
@media(max-width:560px){
  .sfoot{padding:28px 0 34px}
  .sf-nav{grid-template-columns:repeat(2,minmax(0,1fr));gap:18px 14px}
  .sf-key{grid-template-columns:minmax(0,1fr);gap:11px}
  /* 44px targets on a phone, same rule the rest of the site follows */
  .sf-col a,.sf-col .cur{min-height:44px;padding:10px 0}
  .sf-base{gap:12px}
  .sfoot .s42{margin-left:0;min-height:44px}
}
body.onses .mcta{display:none!important}
.mcta{position:fixed;left:0;right:0;bottom:0;z-index:80;display:none;background:var(--paper);
  border-top:3px solid var(--ink);padding:10px 16px calc(10px + env(safe-area-inset-bottom));
  align-items:center;gap:12px}
.mcta .t{font-family:var(--osw);font-size:10.4px;font-weight:300;letter-spacing:.07em;color:var(--mu);
  line-height:1.5;text-transform:uppercase}
.mcta .t b{display:block;font-family:var(--blk);font-size:14px;color:var(--ink);letter-spacing:-.3px}

@media(max-width:860px){
  .row{grid-template-columns:52px 116px minmax(0,1fr) auto;gap:12px;row-gap:8px;padding:14px 0 16px;align-items:start}
  .row .t{font-size:19px;grid-column:1;grid-row:1}
  .row .th{grid-column:2;grid-row:1/3;align-self:center}
  .row h3{white-space:normal;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
  .row .meta{white-space:normal;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;line-height:1.5}
  .row .go{margin-top:6px;padding:5px 10px}
  .row .bd{grid-column:3;grid-row:1}
  .row .st{grid-column:3/5;grid-row:2;text-align:left;display:flex;align-items:center;gap:10px;flex-wrap:wrap}
  .row .st .meter{margin-top:0;justify-content:flex-start}
  .row .st u{margin-top:0}
  .row .pz{grid-column:4;grid-row:1;text-align:right}
  .kit{grid-template-columns:repeat(2,minmax(0,1fr))}
}
@media(max-width:400px){
  /* At 320 the four columns were 46 + 96 + 1fr + auto, and the auto column
     (price and BOOK) takes what it needs, so the title was left with 61px:
     "DOS SANTO..." over four lines and the venue unreadable. The title now
     spans both remaining columns on row one and the price drops beside the
     status on row two, which gives it 146px instead of 61px. */
  .row{grid-template-columns:46px 84px minmax(0,1fr) auto;gap:10px}
  .row .bd{grid-column:3/5;grid-row:1}
  .row .st{grid-column:3;grid-row:2}
  .row .pz{grid-column:4;grid-row:2;text-align:right;align-self:end}
  .row .t{font-size:17px}
  .row h3{font-size:14.5px}
  .mcta{display:flex}
  body{padding-bottom:70px}
  .sp-hd h1{max-width:none}
  .shd h2{font-size:19px}
}


/* ══════════════════════════════════════════════════════════════════
   MOBILE — touch targets, sticky furniture, safe areas
   Everything below assumes a thumb, not a cursor.
   ══════════════════════════════════════════════════════════════════ */

/* Hover styling is a lie on touch. Give every control a real pressed state. */
@media(hover:none){
  .row:hover{background:transparent}
  .row:active{background:var(--card2)}
  .btn:active{box-shadow:2px 2px 0 var(--ink);transform:translate(1px,1px)}
  .chip:active,.bk:active,.shb:active,.th:active{border-color:var(--ink);background:var(--acid-soft)}
  .kt:active,.ft1:active{border-color:var(--ink)}
  .hostr.link:active{border-color:var(--ink);background:var(--acid-soft)}
}

@media(max-width:860px){
  /* 44px is the smallest comfortable target; nothing tappable goes under it.
     A sweep at 320/360/390/430 found six controls still under it, all of them
     things people tap on a phone: the wordmark (which is the way home), the
     board/map toggle, Host login, the format chips, and every form field on
     the two standalone pages. Padding grows the target, not the type. */
  .brand{min-height:44px;display:flex;align-items:center}
  .vt button{min-height:44px}
  .hostin{min-height:44px;padding-top:0;padding-bottom:0}
  .fchip{min-height:44px}
  .btn{padding:15px 18px;min-height:48px}
  .btn.sm{min-height:40px}
  .chip{padding:10px 13px;min-height:40px}
  .vt button{padding:10px 14px}   /* height is set above at 44; do not re-pin it here */
  .bk,.shb{padding:10px 12px;min-height:40px}
  .row{padding:15px 0 17px}
  .row .go{padding:8px 12px;min-height:32px;display:inline-flex;align-items:center}
  header .loc{padding:10px 12px;min-height:40px}
  footer{padding:20px 0 40px}
  footer .in{gap:12px 18px;align-items:center}
  footer .in a{padding:11px 0;display:inline-flex;align-items:center;min-height:44px}
  footer .r{margin-left:0;width:100%;gap:16px;flex-wrap:wrap}
  .fo button{padding:12px 14px;min-height:44px}
  .pay{padding:14px;min-height:60px}

  /* the smallest labels get a floor so they stay readable in daylight */
  .row .meta,.row .t i{font-size:10px}
  .row .st u{font-size:11px}
  .row .st u.cd{font-size:15px}

  .kt .p,.ft1 .p,.klg{font-size:9.5px}
  .adlbl,.spnote{font-size:10px}

  /* On a session page the back button is the only thing worth pinning —
     the brand bar scrolls away so the back bar can own the top. */
  body.onses header{position:static}
  .backbar{position:sticky;top:0;z-index:55;box-shadow:0 2px 0 rgba(16,16,16,.06)}
  .backbar .in{padding:9px 16px}
  .bk svg,.shb svg{width:13px;height:13px}

  /* the sticky book bar must never sit on top of the last block */
  body.onses{padding-bottom:104px}
  .sp-hd{padding:18px 0 2px}
  .sp-hd .mt{font-size:10px;line-height:1.9;margin-top:10px}
  .sp-hd .pz{margin-top:13px;gap:10px}
  .sp-hd .pz b{font-size:27px}
  .sp-hd .pz .btn{width:100%;margin-left:0!important;order:3}
  .stbig{margin:14px 0 0}
  .hero .gb{padding:9px 12px}

  /* organiser profile */
  .hcover{aspect-ratio:16/7}
  .hhd{gap:12px;padding:14px 0 4px}
  .hhd .av2{font-size:21px;padding:11px 13px}

  /* sheets sit above the on-screen keyboard and clear the home indicator */
  .sheet{max-height:92dvh}
  .sbody{padding:0 16px 20px}
  .shfoot{padding:14px 16px calc(16px + env(safe-area-inset-bottom))}
  .shfoot .btn{flex:1}
}

@media(max-width:430px){
  .w{padding:0 14px}
  .backbar .in{padding:9px 14px}
  .sp-hd h1{font-size:26px;letter-spacing:-1px}
  .lede{padding:22px 0 18px}
  .adx{width:240px;height:120px}
  .adx.wide{height:120px}
  .gal{gap:8px}
  .sbar{padding:9px 14px calc(9px + env(safe-area-inset-bottom))}
  .sbar b{font-size:19px}
  .sbar .btn{padding:13px 14px;min-height:46px}
  .mcta{padding:9px 14px calc(9px + env(safe-area-inset-bottom))}
}

/* iOS: stop the rubber-band bounce revealing white behind a fixed bar */
@supports(-webkit-touch-callout:none){
  body{overscroll-behavior-y:none}
}


/* ── lightbox ──────────────────────────────────────────────────────────────
   The gallery grid crops to a tidy 4:3. This is where the photo is shown
   whole: object-fit:contain, above every other layer, nothing on top of the
   image itself. Portrait team photos were the ones losing their heads. */
.lb{position:fixed;inset:0;z-index:400;background:rgba(8,12,9,.96);display:none;
  flex-direction:column;opacity:0;transition:opacity .16s}
.lb.on{display:flex;opacity:1}
.lb-top{flex:0 0 auto;display:flex;align-items:center;gap:14px;padding:14px 16px;
  color:var(--paper);position:relative;z-index:2}
.lb-cap{font-family:var(--osw);font-size:11px;font-weight:600;letter-spacing:.08em;
  text-transform:uppercase;color:#B9C9B4;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.lb-n{margin-left:auto;font-family:var(--osw);font-size:11px;font-weight:600;letter-spacing:.09em;
  color:#B9C9B4;flex:none}
.lb-x{flex:none;width:38px;height:38px;display:grid;place-items:center;color:var(--paper);
  border:1.5px solid rgba(242,240,231,.4)}
.lb-x:hover{border-color:var(--acid);color:var(--acid)}
.lb-x svg{width:18px;height:18px}
/* the stage. min-height:0 is what lets the image shrink inside a flex column */
/* The stage is a plain positioned box and #lbimg is absolutely inset inside it,
   which gives the image a definite height to measure max-height against. A
   percentage height inside a centred flex or grid item does not resolve
   reliably, and the photo renders at full natural size and overflows. */
.lb-stage{flex:1 1 auto;min-height:0;position:relative}
.lb-stage #lbimg{position:absolute;inset:0 12px 12px;display:flex;
  align-items:center;justify-content:center}
.lb-stage #lbimg img,.lb-stage #lbimg svg{max-width:100%;max-height:100%;
  width:auto;height:auto;object-fit:contain;display:block}
.lb-stage img{max-width:100%;max-height:100%;width:auto;height:auto;object-fit:contain;
  display:block;user-select:none;-webkit-user-drag:none}
.lb-stage svg{max-width:100%;max-height:100%;width:auto;height:auto}
.lb-arr{position:absolute;top:50%;transform:translateY(-50%);width:46px;height:46px;z-index:3;
  display:grid;place-items:center;background:rgba(242,240,231,.92);border:1.5px solid var(--ink);
  color:var(--ink);transition:.12s}
.lb-arr:hover{background:var(--acid)}
.lb-arr[disabled]{opacity:.3;pointer-events:none}
.lb-arr.p{left:14px}.lb-arr.n{right:14px}
.lb-arr svg{width:20px;height:20px}
.lb-film{flex:0 0 auto;display:flex;gap:7px;overflow-x:auto;padding:10px 16px calc(10px + env(safe-area-inset-bottom));
  scrollbar-width:none}
.lb-film::-webkit-scrollbar{display:none}
.lb-film button{flex:none;width:64px;height:48px;overflow:hidden;border:1.5px solid rgba(242,240,231,.28);
  background:var(--card2);opacity:.55;transition:.12s}
.lb-film button.on{opacity:1;border-color:var(--acid)}
.lb-film img,.lb-film svg{width:100%;height:100%;object-fit:cover;display:block}
@media(max-width:560px){
  .lb-arr{width:40px;height:40px}.lb-arr.p{left:6px}.lb-arr.n{right:6px}
  .lb-film button{width:52px;height:40px}
  .lb-stage #lbimg{inset:0 6px 8px}
}
@media(prefers-reduced-motion:reduce){.lb{transition:none}}

.galhero{cursor:zoom-in}


/* ── format picker in the lede ─────────────────────────────────────────────
   Moved out of the sticky chip bar so a phone does not have to scroll eight
   chips sideways before it can reach BOARD / MAP. Here it wraps instead. */
.fmtbar{display:flex;flex-wrap:wrap;gap:6px;margin:14px 0 18px}
.fchip{display:inline-flex;align-items:center;gap:9px;flex:none;
  border:1.5px solid rgba(242,240,231,.34);background:rgba(0,0,0,.16);padding:7px 11px;
  font-family:var(--osw);font-size:11.4px;font-weight:600;letter-spacing:.05em;
  text-transform:uppercase;color:var(--ink2);transition:.12s;cursor:pointer;text-align:left}
.fchip .fl{display:block;line-height:1.15}
.fchip .fl em{display:block;font-style:normal;font-size:9.2px;font-weight:400;letter-spacing:.07em;
  color:#AEC0A9;margin-top:3px}
.fchip.on .fl em{color:rgba(14,26,18,.62)}
.fchip i{font-style:normal;font-size:10px;font-weight:700;color:#B9C9B4;
  background:rgba(0,0,0,.22);border:1px solid rgba(242,240,231,.24);padding:1px 5px;min-width:18px;text-align:center}
.fchip{color:var(--pitch-ink)}
.fchip:hover{border-color:var(--acid);color:var(--acid)}
.fchip.on{background:var(--acid);border-color:var(--acid);color:var(--ink)}
.fchip.on i{background:var(--ink);border-color:var(--ink);color:var(--acid)}
@media(max-width:560px){
  .fmtbar{gap:5px;margin:12px 0 16px}
  .fchip{padding:7px 9px;font-size:10.6px}
}

/* ══════════════════════════════════════════════════════════════════
   THE INTRO
   Three tiles settling on +60, then the mark. What is left of the
   password gate after the password went. The markup is in the page
   rather than injected, so it covers the site from the first paint
   with no flash and without hiding anything from a crawler: the
   content is in the DOM and visible, it just has a green sheet over
   it for a few seconds. See intro.js for the timing.
   ══════════════════════════════════════════════════════════════════ */
html.introing,html.introing body{overflow:hidden}
#p60intro{position:fixed;inset:0;z-index:99999;background:var(--pitch);color:var(--pitch-ink);
  display:flex;flex-direction:column;align-items:center;justify-content:center;padding:24px;
  transition:opacity .68s ease,background-color .68s ease,transform .68s cubic-bezier(.4,0,.2,1)}
/* the mown stripes, on their own layer so they can fade with everything else.
   background-image cannot be transitioned, and switching it off at the last
   moment was the pop you could see at the hand-off. */
#p60intro:before{content:'';position:absolute;inset:0;pointer-events:none;transition:opacity .46s ease;
  background:repeating-linear-gradient(90deg,rgba(255,255,255,.028) 0 44px,transparent 44px 88px)}

/* ── the hand-off ──
   One flat fade from a dark green sheet to a paper page is a hard jump in
   brightness, and it reads as a cut rather than an ending. Three things happen
   instead, overlapping: the mark lifts away and goes first, the stripes go with
   it, and the sheet itself washes to the paper colour of the page underneath as
   it dissolves. The last frame before it disappears is already almost the site. */
#p60intro.out{opacity:0;pointer-events:none;background-color:var(--paper);transform:scale(1.02)}
#p60intro.out:before{opacity:0}
#p60intro.out .i-flaps,
#p60intro.out .i-word,
#p60intro.out .i-sub{opacity:0;transform:translateY(-14px);
  transition:opacity .36s ease,transform .48s cubic-bezier(.4,0,.2,1)}

/* the return visit runs at half the length, so every part of the exit is
   shortened in proportion rather than the whole thing being clipped */
#p60intro.quick{transition-duration:.48s}
#p60intro.quick:before{transition-duration:.32s}
#p60intro.quick .i-word{transition:opacity .26s ease}
#p60intro.quick .i-sub{transition:opacity .26s ease .06s}
#p60intro.quick.out .i-flaps,
#p60intro.quick.out .i-word,
#p60intro.quick.out .i-sub{transition:opacity .26s ease,transform .36s cubic-bezier(.4,0,.2,1)}

.i-flaps{display:flex;gap:7px;transition:opacity .26s ease,transform .36s cubic-bezier(.4,0,.2,1)}
.i-flap{position:relative;width:64px;height:86px;border-radius:9px;background:var(--ink);
  display:grid;place-items:center;overflow:hidden;box-shadow:0 6px 0 rgba(0,0,0,.28)}
.i-flap span{font-family:var(--blk);font-size:56px;line-height:1;color:var(--acid);display:block;
  transform-origin:50% 50%}
/* the seam across the middle of a split-flap tile */
.i-flap:after{content:"";position:absolute;left:0;right:0;top:calc(50% - 1.8px);height:3.6px;
  background:var(--pitch-ink);opacity:.4}
@keyframes iflip{0%{transform:scaleY(1)}50%{transform:scaleY(.04)}100%{transform:scaleY(1)}}
.i-flap span.f{animation:iflip .16s linear}

.i-word{margin-top:26px;opacity:0;transition:opacity .5s ease .1s,transform .36s cubic-bezier(.4,0,.2,1)}
.i-word.in{opacity:1}
.i-word img{height:34px;width:auto;display:block}
.i-sub{margin-top:12px;font-family:var(--osw);font-size:12.5px;font-weight:600;letter-spacing:.14em;
  text-transform:uppercase;color:var(--mu2);opacity:0;text-align:center;
  transition:opacity .5s ease .25s,transform .36s cubic-bezier(.4,0,.2,1)}
.i-sub.in{opacity:1}

@media(max-width:560px){
  .i-flap{width:52px;height:70px}
  .i-flap span{font-size:45px}
  .i-word img{height:27px}
  .i-sub{font-size:11px}
}
@media(prefers-reduced-motion:reduce){
  .i-flap span.f{animation:none}
  #p60intro,#p60intro:before,.i-flaps,.i-word,.i-sub{transition:none}
  #p60intro.out{transform:none}
  #p60intro.out .i-flaps,#p60intro.out .i-word,#p60intro.out .i-sub{transform:none}
}

/* The booking that did not happen. Same block as .ok so the shape is familiar,
   but the acid is gone: acid means "this is on, this is bookable", and nothing
   here is. Hot carries the bad news instead. */
.ok.bad{background:var(--hot-soft);border-color:var(--hot)}
.ok.bad h3{color:var(--hot)}
.ok.bad .ref{display:none}


/* ═════════════════════════════════════════════════════════════════════
   PRESSED, on the player side
   Same reasoning as the console: a phone has no hover, so a tap needs to
   answer for itself at the moment the finger lands.
   ═════════════════════════════════════════════════════════════════════ */
.btn, .chip, .fbtn, .pay, .seg button, .mcta .btn{
  transition: background-color .09s ease, color .09s ease, border-color .09s ease,
              transform .06s ease;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}
.btn:active, .chip:active, .fbtn:active, .pay:active, .seg button:active, .mcta .btn:active{
  transform: translateY(1px);
  background: var(--ink);
  color: var(--paper);
  border-color: var(--ink);
}
.btn-a:active{ background: var(--ink); color: var(--acid); }
.chip.on, .seg button.on{ background: var(--ink); color: var(--paper); font-weight:600 }
.pay.on{ border-color: var(--ink); box-shadow: inset 0 0 0 1.5px var(--ink) }
.btn:focus-visible, .chip:focus-visible, .pay:focus-visible, .seg button:focus-visible{
  outline: 2px solid var(--ink); outline-offset: 2px;
}
@media (prefers-reduced-motion: reduce){
  .btn, .chip, .fbtn, .pay, .seg button{ transition:none }
  .btn:active, .chip:active, .fbtn:active, .pay:active, .seg button:active{ transform:none }
}


/* ══════════════════════════════════════════════════════════════════════════
   THE GALLERY (gal2)
   A big frame with a real thumbnail rail under it. The rail is the point:
   a dot tells you there is another picture, a thumbnail tells you whether
   you want it. Crossfade rather than scroll, so the autoplay never fights
   a reader who is mid-swipe.
   Every .pimg carries its own object-position from FOCAL in data.js; nothing
   here may set one, or it would override the measured crop.
   ══════════════════════════════════════════════════════════════════════════ */
.gal2{margin-top:2px}
.g-stage{position:relative;aspect-ratio:16/8;background:var(--ink);overflow:hidden;
  border:1.5px solid var(--ink)}
.g-fr{position:absolute;inset:0;margin:0;opacity:0;transition:opacity .45s ease}
.g-fr.on{opacity:1}
.g-fr svg,.g-fr .pimg{width:100%;height:100%;display:block;object-fit:cover}
.g-tap{position:absolute;inset:0;width:100%;height:100%;border:0;background:transparent;
  cursor:pointer;z-index:2;padding:0}
.g-tap:focus-visible{outline:3px solid var(--acid);outline-offset:-3px}
.g-cap{position:absolute;left:0;right:64px;bottom:0;z-index:3;pointer-events:none;
  padding:30px 14px 11px;color:var(--pitch-ink);font-size:12.5px;line-height:1.4;
  background:linear-gradient(to top,rgba(14,26,18,.88),transparent)}
.g-ct{position:absolute;right:10px;bottom:10px;z-index:3;pointer-events:none;
  background:rgba(14,26,18,.72);color:var(--pitch-ink);font-family:var(--osw);
  font-size:10.5px;font-weight:700;letter-spacing:.08em;padding:5px 8px}

.g-rail{display:flex;gap:6px;margin-top:6px;align-items:stretch;overflow-x:auto;
  scrollbar-width:none;-webkit-overflow-scrolling:touch}
.g-rail::-webkit-scrollbar{display:none}
.g-th{flex:1 1 0;min-width:54px;padding:0;background:var(--card2);cursor:pointer;
  border:1.5px solid var(--rule2);height:62px;overflow:hidden;transition:border-color .12s}
.g-th svg,.g-th .pimg{width:100%;height:100%;display:block;object-fit:cover}
.g-th.on{border:2.5px solid var(--ink)}
.g-th:hover{border-color:var(--ink)}
.g-all{flex:0 0 84px;border:1.5px solid var(--ink);background:var(--card);cursor:pointer;
  height:62px;display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:2px;font-family:var(--osw);font-size:10px;font-weight:700;letter-spacing:.06em;
  text-transform:uppercase;color:var(--ink);line-height:1.2}
.g-all svg{width:15px;height:15px}
.g-all i{display:block;font-style:normal;font-weight:500;color:var(--mu)}
.g-all:hover{background:var(--acid)}
@media(max-width:640px){
  .g-stage{aspect-ratio:4/3}
  .g-th{min-width:50px;height:54px}
  .g-all{flex:0 0 62px;height:54px;font-size:9px}
}
@media(prefers-reduced-motion:reduce){ .g-fr{transition:none} }

/* ══════════════════════════════════════════════════════════════════════════
   SESSION PAGE, TICKET LAYOUT
   Content on the left, a sticky ticket on the right holding everything that
   decides the booking. Below 980px the ticket stops being sticky and sits
   inline right under the title, so the price and the button are on screen
   before anyone scrolls.
   ══════════════════════════════════════════════════════════════════════════ */
.sp2{display:flex;flex-wrap:wrap;gap:40px;align-items:flex-start;padding:0 0 40px}
.sp2-main{flex:999 1 560px;min-width:0}
.sp2-side{flex:1 1 320px;min-width:300px;position:sticky;top:18px}
@media(max-width:979px){
  .sp2{gap:0;flex-direction:column}
  .sp2-side{position:static;order:-1;width:100%;min-width:0;margin-bottom:28px}
  .sp2-main{width:100%;flex:1 1 auto}
}

.tkt{border:2px solid var(--ink);background:var(--card)}
.tkt-top{padding:20px;border-bottom:1.5px dashed var(--rule2)}
.tkt-pz{display:flex;align-items:baseline;gap:8px}
.tkt-pz b{font-family:var(--blk);font-size:40px;letter-spacing:-.03em;line-height:1}
.tkt-g{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:14px;margin-top:18px}
.tkt-g .k{font-family:var(--osw);font-size:10px;font-weight:600;letter-spacing:.12em;
  text-transform:uppercase;color:var(--mu)}
.tkt-g .v{font-family:var(--blk);font-size:22px;letter-spacing:-.02em;margin-top:3px;line-height:1.1}
.tkt-mid{padding:18px 20px}
.tkt-row{display:flex;align-items:center;justify-content:space-between}
.tkt-row span{font-family:var(--osw);font-size:10px;font-weight:600;letter-spacing:.12em;
  text-transform:uppercase;color:var(--mu)}
.tkt-row b{font-size:13px;font-weight:700}
.tkt-m{display:flex;gap:3px;margin-top:9px}
.tkt-m i{display:block;flex:1 1 0;height:19px;border:1.5px solid var(--ink);background:transparent}
.tkt-m i.f{background:var(--acid)}
.tkt-m i.c{background:var(--hot-soft);border-color:var(--hot)}
.tkt-why{font-size:12px;color:var(--mu);margin-top:9px;line-height:1.5}
.tkt-mid .btn{width:100%;margin-top:16px;padding:17px}
.tkt-free{font-size:11.5px;color:var(--mu);text-align:center;margin-top:10px;line-height:1.5}
.tkt-host{border-top:1.5px dashed var(--rule2);padding:14px 20px;background:var(--card2);
  display:flex;align-items:center;gap:10px;text-decoration:none;color:inherit}
.tkt-host .av{font-family:var(--blk);width:34px;height:34px;background:var(--pitch);
  color:var(--acid);display:flex;align-items:center;justify-content:center;font-size:12px;flex:none}
.tkt-host .t{min-width:0;flex:1 1 auto}
.tkt-host .t b{display:block;font-size:13.5px;font-weight:700}
.tkt-host .t span{display:block;font-size:11px;color:var(--mu);margin-top:1px}
.tkt-host .go{font-family:var(--osw);font-size:10.5px;font-weight:700;letter-spacing:.07em;
  text-transform:uppercase;color:var(--pitch);white-space:nowrap}
.tkt-host:hover{background:var(--acid-soft)}

.refbox{border-left:3px solid var(--acid);background:var(--card2);padding:14px 16px;margin-top:16px}
.refbox h4{font-family:var(--osw);font-size:10px;font-weight:600;letter-spacing:.12em;
  text-transform:uppercase;color:var(--mu);margin:0 0 9px}
.refbox table{width:100%;border-collapse:collapse;font-size:12.5px}
.refbox td{padding:4px 0;color:var(--ink2)}
.refbox td+td{text-align:right;font-weight:700;color:var(--ink)}
.refbox p{font-size:12px;line-height:1.55;color:var(--mu);margin:10px 0 0}

.vcard{border:1.5px solid var(--rule2);background:var(--card);display:flex;flex-wrap:wrap}
.vcard .vmap{flex:1 1 230px;min-height:190px;border-right:1.5px solid var(--rule2);position:relative}
.vcard .vbody{flex:999 1 300px;min-width:0;padding:18px}
.vcard h3{font-family:var(--blk);font-size:19px;letter-spacing:-.02em;line-height:1.2;margin:0}
.vcard .addr{font-size:12.5px;color:var(--mu);margin-top:5px;line-height:1.5}
.vcard .kv{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:12px;margin-top:16px}
@media(max-width:560px){ .vcard .kv{grid-template-columns:repeat(2,minmax(0,1fr))}
  .vcard .vmap{flex:1 1 100%;border-right:0;border-bottom:1.5px solid var(--rule2);min-height:150px} }
.vcard .kv .k{font-family:var(--osw);font-size:10px;font-weight:600;letter-spacing:.12em;
  text-transform:uppercase;color:var(--mu)}
.vcard .kv .v{font-size:13px;font-weight:600;margin-top:3px}
.vacts{display:flex;gap:9px;margin-top:17px}
.vacts a{flex:1 1 0;text-align:center;padding:13px;font-family:var(--osw);font-size:11.5px;
  font-weight:700;letter-spacing:.09em;text-transform:uppercase;border:1.5px solid var(--ink);
  box-sizing:border-box;min-height:44px;display:inline-flex;align-items:center;justify-content:center}
.vacts a.k{background:var(--ink);color:var(--paper)}
.vacts a.k:hover{background:var(--pitch)}
.vacts a.o:hover{background:var(--acid)}

.hcard2{border:1.5px solid var(--rule2);background:var(--card);padding:20px;
  display:flex;flex-wrap:wrap;gap:20px;align-items:flex-start;text-decoration:none;color:inherit}
.hcard2:hover{border-color:var(--ink)}
.hcard2 .who{display:flex;align-items:center;gap:13px;flex:0 0 auto}
.hcard2 .av{font-family:var(--blk);width:52px;height:52px;background:var(--pitch);color:var(--acid);
  display:flex;align-items:center;justify-content:center;font-size:17px;flex:none}
.hcard2 .nm{font-family:var(--blk);font-size:21px;letter-spacing:-.02em}
.hcard2 .sub{font-family:var(--osw);font-size:10px;font-weight:600;letter-spacing:.12em;
  text-transform:uppercase;color:var(--mu);margin-top:3px}
.hcard2 .bl{flex:999 1 280px;min-width:0}
.hcard2 .bl p{font-size:14.5px;line-height:1.6;color:var(--ink2);margin:0}
.hcard2 .tags{display:flex;flex-wrap:wrap;gap:7px;margin-top:14px}
.hcard2 .tags span{font-family:var(--osw);font-size:11px;font-weight:600;letter-spacing:.05em;
  padding:5px 9px;border:1.5px solid var(--rule2);background:var(--card2);color:var(--ink2)}
.hcard2 .tags em{font-style:normal;font-family:var(--osw);font-size:11px;font-weight:700;
  letter-spacing:.07em;text-transform:uppercase;padding:5px 9px;border:1.5px solid var(--ink);color:var(--ink)}

/* session page title block, replacing .sp-hd's fact grid: the ticket carries
   those numbers now, so the headline gets the width to itself */
.sp-hd2{padding:26px 0 20px}
.sp-hd2 .mt{font-family:var(--osw);font-size:10.4px;font-weight:600;letter-spacing:.12em;
  text-transform:uppercase;color:var(--mu);margin-bottom:9px}
.sp-hd2 h1{font-family:var(--blk);font-size:clamp(26px,4.4vw,40px);line-height:1.04;
  letter-spacing:-.03em;max-width:22ch;text-wrap:balance;margin:0}
@media(max-width:979px){ .sp-hd2{padding:20px 0 16px} }

/* ══════════════════════════════════════════════════════════════════════════
   VENUE PAGE  (#/v/<id>)
   Same two-column skeleton as the session page, so a visitor who has already
   read one knows where everything is. The difference is what the right-hand
   card holds: a session's ticket is a decision, a venue's panel is a summary,
   so it does not stick and it has no button.
   ══════════════════════════════════════════════════════════════════════════ */
.vpl{display:flex;flex-wrap:wrap;gap:40px;align-items:flex-start;padding:0 0 10px}
.vpl-main{flex:999 1 560px;min-width:0}
.vpl-side{flex:1 1 320px;min-width:300px}
@media(max-width:979px){
  .vpl{gap:0;flex-direction:column}
  .vpl-side{order:-1;width:100%;min-width:0;margin-bottom:28px}
  .vpl-main{width:100%;flex:1 1 auto}
}
.vpl .tkt-bt{padding:16px 20px}

/* The ground's photography. One lead frame at full width because a pitch is a
   wide subject and a 4:3 grid cell is not, then a grid for the rest. */
.vgal{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:10px;margin:0 0 34px}
.vgal .vg{position:relative;margin:0;border:1.5px solid var(--rule2);background:var(--card);
  overflow:hidden;cursor:zoom-in}
.vgal .vg.lead{grid-column:1/-1}
.vgal .vg .pimg,.vgal .vg svg{width:100%;height:100%;display:block;object-fit:cover;
  aspect-ratio:4/3;transition:transform .5s cubic-bezier(.2,.7,.2,1)}
.vgal .vg.lead .pimg,.vgal .vg.lead svg{aspect-ratio:16/9}
.vgal .vg:hover .pimg{transform:scale(1.035)}
.vgal .vg figcaption{position:absolute;left:0;right:0;bottom:0;padding:16px 12px 9px;
  font-family:var(--osw);font-size:9.6px;font-weight:600;letter-spacing:.14em;
  text-transform:uppercase;color:#fff;
  background:linear-gradient(to top,rgba(14,26,18,.76),rgba(14,26,18,0))}
.vgal .vg.lead figcaption{font-size:11px;padding:30px 16px 13px}
.vgal .vg:focus-visible{outline:3px solid var(--acid);outline-offset:2px}
@media(max-width:640px){
  .vgal{grid-template-columns:repeat(2,minmax(0,1fr));gap:8px;margin-bottom:26px}
  .vgal .vg.lead .pimg,.vgal .vg.lead svg{aspect-ratio:4/3}
}

/* The board's rows carry real anchors now (see the router note in app.js:
   a crawler follows anchors and nothing else). They have to look exactly
   like the text and the button they replaced. */
.row .meta a.ml{color:inherit;text-decoration:none;border-bottom:1px solid transparent}
.row .meta a.ml:hover{border-bottom-color:currentColor}
.row .go{text-decoration:none}
a.go,a.go:hover,a.go:visited{text-decoration:none}

/* The board leaves the document when a game or a ground is showing, so a
   crawler reads one h1 per page rather than the board's on all of them. An
   explicit display beats the user agent's [hidden] rule, hence !important. */
#home[hidden]{display:none !important}

/* ═══════════════════════════════════════════════════════════════════════
   WHATSAPP SUPPORT BUTTON
   Fixed bottom right on the public pages. Not on /console/, which is the
   host's working tool and has its own bottom bar within thumb reach, and not
   on /rate/, which carries a feedback token in the URL.

   The hover is meant to read as a tap rather than a glow: the button lifts a
   little, a single ring pushes out from under it and dies, and pressing it
   drives the whole thing down into its own shadow, which is the same physical
   press every other button on the site uses. All of it is off under
   prefers-reduced-motion, where the button simply darkens its rule.
   ═══════════════════════════════════════════════════════════════════════ */
.wafab{position:fixed;z-index:50;right:18px;
  bottom:calc(18px + env(safe-area-inset-bottom));
  width:56px;height:56px;border-radius:50%;
  display:flex;align-items:center;justify-content:center;
  background:var(--acid);color:var(--ink);border:2px solid var(--ink);
  box-shadow:4px 4px 0 var(--ink);
  transition:transform .14s cubic-bezier(.2,.9,.3,1.3), box-shadow .14s ease}
.wafab svg{width:27px;height:27px;display:block;position:relative;z-index:1}
.wafab:hover{transform:translate(-1px,-2px);box-shadow:6px 7px 0 var(--ink)}
.wafab:active{transform:translate(3px,3px);box-shadow:1px 1px 0 var(--ink)}
.wafab:focus-visible{outline:3px solid var(--pitch);outline-offset:4px}

/* the ring. One pass on hover, nothing on idle, so it reads as a response to
   the pointer rather than as an animation running forever in the corner. */
.wafab:before{content:'';position:absolute;inset:-2px;border-radius:50%;
  border:2px solid var(--ink);opacity:0;pointer-events:none}
.wafab:hover:before{animation:wapulse .62s cubic-bezier(.2,.7,.3,1) 1}
@keyframes wapulse{
  0%{transform:scale(1);opacity:.55}
  70%{opacity:.12}
  100%{transform:scale(1.55);opacity:0}
}

/* the label, desktop only: a 56px circle in a corner does not say what it is */
.wafab i{position:absolute;right:68px;top:50%;transform:translateY(-50%) translateX(6px);
  font-family:var(--osw);font-size:10.4px;font-weight:600;letter-spacing:.12em;
  text-transform:uppercase;font-style:normal;white-space:nowrap;
  background:var(--ink);color:var(--paper);padding:8px 11px;
  opacity:0;pointer-events:none;transition:opacity .14s ease, transform .14s ease}
.wafab:hover i,.wafab:focus-visible i{opacity:1;transform:translateY(-50%) translateX(0)}
@media(max-width:700px){ .wafab i{display:none} }
@media(max-width:560px){
  .wafab{width:52px;height:52px;right:14px;bottom:calc(14px + env(safe-area-inset-bottom))}
  .wafab svg{width:25px;height:25px}
}

/* Out of the way while the booking sheet is up: the sheet owns the screen and
   its PAY button sits exactly where this does. */
body.sheet-open .wafab{opacity:0;pointer-events:none;transform:translateY(8px)}

@media(prefers-reduced-motion:reduce){
  .wafab,.wafab i{transition:none}
  .wafab:hover{transform:none;box-shadow:4px 4px 0 var(--ink);border-color:var(--pitch)}
  .wafab:hover:before{animation:none}
}

/* ── the WhatsApp composer ──
   Anchored to the button rather than centred, because it belongs to the
   button and a centred modal over a policy page reads as an interruption.
   Full width on a phone, where a 360px card in a corner is just a cramped
   card in a corner. */
.wapanel{position:fixed;z-index:51;right:18px;
  bottom:calc(86px + env(safe-area-inset-bottom));
  width:360px;max-width:calc(100vw - 36px);max-height:calc(100vh - 140px);
  overflow-y:auto;background:var(--paper);border:2px solid var(--ink);
  box-shadow:6px 6px 0 var(--ink);
  opacity:0;transform:translateY(10px) scale(.98);pointer-events:none;
  transition:opacity .16s ease, transform .16s cubic-bezier(.2,.9,.3,1.2)}
.wapanel.on{opacity:1;transform:none;pointer-events:auto}
@media(max-width:560px){
  .wapanel{right:10px;left:10px;width:auto;max-width:none;
    bottom:calc(78px + env(safe-area-inset-bottom));max-height:calc(100vh - 118px)}
}

.wa-hd{display:flex;align-items:center;justify-content:space-between;gap:10px;
  padding:13px 15px;background:var(--pitch);color:var(--pitch-ink);
  border-bottom:2px solid var(--ink);position:sticky;top:0;z-index:1}
.wa-hd b{font-family:var(--blk);font-size:16px;letter-spacing:-.4px}
.wa-x{background:none;border:0;color:var(--pitch-ink);font-size:24px;line-height:1;
  cursor:pointer;padding:0 2px;opacity:.75}
.wa-x:hover{opacity:1}

.wa-bd{padding:15px}
.wa-l{display:block;font-family:var(--osw);font-size:9.6px;font-weight:700;
  letter-spacing:.12em;text-transform:uppercase;color:var(--mu);margin-bottom:6px}
.wa-f{margin-top:13px}
.wa-f:first-child{margin-top:0}
.wa-row{display:grid;grid-template-columns:minmax(0,1fr);gap:0}
@media(min-width:420px){ .wa-row{grid-template-columns:repeat(2,minmax(0,1fr));gap:11px}
  .wa-row .wa-f{margin-top:13px} }

.wapanel input,.wapanel textarea{width:100%;background:var(--card);color:var(--ink);
  border:1.5px solid var(--rule2);padding:10px 11px;font-family:var(--sans);
  font-size:15px;line-height:1.4;border-radius:0}
.wapanel textarea{resize:vertical;min-height:72px}
.wapanel input:focus,.wapanel textarea:focus{outline:0;border-color:var(--ink);
  box-shadow:0 0 0 3px var(--acid-soft)}

/* The three-topic picker that used to sit here is gone. The same button
   serves a player chasing a refund and a club owner asking about the monthly
   plan, and no list of three covers both without growing into a list of eight
   that nobody reads. One optional Subject line does the same job. */
.wa-hd span{display:block;font-family:var(--osw);font-size:9.6px;font-weight:600;
  letter-spacing:.12em;text-transform:uppercase;color:#B9C9B4;margin-top:3px}
.wa-l em{font-style:normal;color:var(--mu2);font-weight:400;letter-spacing:.08em}

.wa-err{min-height:16px;margin-top:10px;font-family:var(--osw);font-size:10.4px;
  font-weight:600;letter-spacing:.06em;text-transform:uppercase;color:var(--hot)}
.wa-go{width:100%;min-height:48px;margin-top:4px;cursor:pointer;
  background:var(--acid);color:var(--ink);border:2px solid var(--ink);
  font-family:var(--osw);font-size:12px;font-weight:600;letter-spacing:.14em;
  text-transform:uppercase;box-shadow:3px 3px 0 var(--ink);transition:.12s}
.wa-go:hover{box-shadow:5px 5px 0 var(--ink);transform:translate(-1px,-1px)}
.wa-go:active{box-shadow:1px 1px 0 var(--ink);transform:translate(2px,2px)}
.wa-note{margin:11px 0 0;font-size:11.6px;line-height:1.5;color:var(--mu)}

/* While the panel is up the button is pressed in rather than rotated: a
   WhatsApp mark turned on its side just reads as broken, and the pressed
   state already means "this is the thing that is open". */
body.wa-open .wafab{transform:translate(3px,3px);box-shadow:1px 1px 0 var(--ink)}
body.wa-open .wafab:hover{transform:translate(3px,3px);box-shadow:1px 1px 0 var(--ink)}
body.wa-open .wafab:hover:before{animation:none}
body.wa-open .wafab i{display:none}
@media(prefers-reduced-motion:reduce){
  .wapanel,.wa-go{transition:none}
}

/* A session page puts a fixed BOOK A SLOT bar across the bottom at z-index 80,
   which is exactly where the WhatsApp button lives. Left alone the bar sits on
   top of the button and swallows the tap, so on a session page the button and
   its panel step up above the bar. Caught by the browser test, not by eye. */
body.sess-open .wafab{bottom:calc(92px + env(safe-area-inset-bottom))}
body.sess-open .wapanel{bottom:calc(160px + env(safe-area-inset-bottom))}
@media(max-width:560px){
  body.sess-open .wafab{bottom:calc(88px + env(safe-area-inset-bottom))}
  body.sess-open .wapanel{bottom:calc(152px + env(safe-area-inset-bottom));
    max-height:calc(100vh - 196px)}
}
