/* nasa.beer/shows — same palette, type and square edges as the game at /.
   Mobile first: every control is a tap target, nothing needs a keyboard. */

:root{
  --void:#07081a;
  --ink:#e8ecff;
  --dim:#8891c4;
  --amber:#ffd45c;
  --amber-d:#c89428;
  --red:#d8283c;
  --good:#5ce07a;
  --bad:#ff5d5d;
  --line:#2a2f5e;
  --panel:#141838;
  --row:#101534;
  --sel:#1b1c3e;

  /* Type: the site reads in a proportional face and keeps monospace for the
     things monospace is actually for — dates, counts, and the mission-control
     readout. A long bill like "Comedians Interview Experts: Psychology and
     Spirituality with Padma Lakshmi and Lisa Miller" is four hostile lines in
     mono and two readable ones here. */
  --sans:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;
  --mono:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;

  /* Colour means one thing each, so the chips can be read without a legend:
       green  going — voted in, or holding a ticket
       amber  tentative, or something on offer to you
       red    out — passed, sold out
       dim    structure and anything neutral
     Amber is also the brand and the primary action, which is why nothing else
     gets to be amber. */
}
*{box-sizing:border-box;margin:0;padding:0;-webkit-tap-highlight-color:transparent;}
/* .btn sets display:inline-block, which outranks the UA sheet's [hidden] rule —
   without this the sheet's "I'll buy now" shows up for shows with no link. */
[hidden]{display:none !important;}
html{background:var(--void);}
body{
  background:var(--void);
  color:var(--ink);
  font-family:var(--sans);
  font-size:15px;line-height:1.5;
  -webkit-font-smoothing:antialiased;
  overscroll-behavior-y:none;
  padding-bottom:env(safe-area-inset-bottom);
}
/* Everything that is a date, a time, a count or a readout stays monospace —
   figures line up and the mission-control voice survives. */
.when,.tdate,.dwhen,.readout,.tok,.digestbox,.datechip,.stepper .val,
.blist,.card .venue time,.gauge .glabel b{font-family:var(--mono);}

/* ---------- the sky ----------
   Same nebula the game serves from /neb, washed down until it is texture rather
   than picture — the page still has to be readable at a bar. Two fixed layers,
   no scroll cost: the nebula plus its wash, then a tiled starfield drawn in CSS
   so it costs nothing to download. */
body::before{
  content:"";position:fixed;inset:0;z-index:-2;pointer-events:none;
  background:
    linear-gradient(180deg, rgba(7,8,26,.48) 0%, rgba(7,8,26,.86) 55%, rgba(7,8,26,.96) 100%),
    url(/neb/neb1.png) center/cover no-repeat;
  image-rendering:pixelated;
}
body::after{
  content:"";position:fixed;inset:0;z-index:-1;pointer-events:none;
  background-image:
    radial-gradient(1px 1px at 24px 36px,   rgba(232,236,255,.55), transparent),
    radial-gradient(1px 1px at 148px 92px,  rgba(232,236,255,.34), transparent),
    radial-gradient(2px 2px at 64px 176px,  rgba(255,212,92,.40),  transparent),
    radial-gradient(1px 1px at 214px 228px, rgba(232,236,255,.42), transparent),
    radial-gradient(1px 1px at 106px 268px, rgba(232,236,255,.28), transparent),
    radial-gradient(1px 1px at 186px 18px,  rgba(232,236,255,.30), transparent);
  background-size:248px 300px;
}
/* One body from the game's sheet, parked in the corner. Sizes are strict
   multiples of the 48px cell (4x / 3x) and rendering is pixelated: downscaling
   pixel art, or scaling it by a fraction, is what makes it look like mush. */
.worldcorner{
  position:fixed;right:-30px;bottom:-26px;z-index:-1;pointer-events:none;
  width:192px;height:192px;opacity:.32;
  background:url(/shows/assets/planet.png) center/contain no-repeat;
  image-rendering:pixelated;
}
@media (max-width:430px){
  .worldcorner{width:144px;height:144px;right:-22px;bottom:-18px;}
}
#app{
  max-width:560px;margin:0 auto;min-height:100vh;min-height:100svh;
  display:flex;flex-direction:column;
  padding-left:max(10px,env(safe-area-inset-left));
  padding-right:max(10px,env(safe-area-inset-right));
}
a{color:var(--amber);text-decoration:none;}
a:hover{text-decoration:underline;}

/* ---------- chrome ---------- */
.top{
  position:sticky;top:0;z-index:20;
  /* not transparent: cards scroll under this and the stars are not worth an
     unreadable nav */
  background:rgba(7,8,26,.94);
  -webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px);
  padding-top:max(8px,env(safe-area-inset-top));
  border-bottom:3px solid var(--line);
  display:flex;align-items:center;gap:6px;
}
/* The corner mark: the favicon's own Jaguar standing in front of one of the
   game's moons. Both are pixel art at 1:1 — the moon is a 32px sprite drawn at
   32px and the guitar is generated at exactly 56, because a pixel drawing that
   is scaled by anything but a whole number stops being one. */
/* 36px tall, which is what the bar was when it held a 32px moon and three
   lines of small type. A 58px guitar made a handsome mark and a strange menu:
   the tab row is one line, and everything beside it has to live inside that
   line's height or the bar stops looking like a bar. */
.mark{
  flex:0 0 auto;position:relative;display:block;width:40px;height:36px;
  align-self:center;
}
.mark:hover{text-decoration:none;}
.markmoon{
  position:absolute;left:0;top:2px;width:32px;height:32px;
  background-position:center;background-size:32px 32px;background-repeat:no-repeat;
  image-rendering:pixelated;
}
.markjag{
  position:absolute;right:0;top:0;width:14px;height:36px;
  background:url(/shows/assets/jag.png) center/14px 36px no-repeat;
  image-rendering:pixelated;
}
/* The moon dims on hover so the thing you are about to tap reads as one
   object rather than two overlapping stickers. */
.mark:hover .markmoon{filter:brightness(1.25);}
.missionbody{flex:1 1 auto;min-width:0;}
/* Reachable by a screen reader, invisible to everyone else. */
.vh{
  position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);
  clip-path:inset(50%);white-space:nowrap;
}

/* ONE line, always. The tabs scale with the viewport so the four everyone sees
   fit a 375px phone without wrapping; if the two admin tabs push past the edge
   the row scrolls sideways rather than breaking onto a second line. */
.navrow{
  display:flex;align-items:center;flex-wrap:nowrap;gap:3px;padding:4px 0 7px;
  overflow-x:auto;scrollbar-width:none;-webkit-overflow-scrolling:touch;
}
.navrow::-webkit-scrollbar{display:none;}
.nav{
  font-size:clamp(11px, 3.2vw, 13px);
  letter-spacing:.01em;font-weight:600;color:var(--dim);
  padding:7px clamp(6px, 2vw, 11px);
  border:2px solid transparent;white-space:nowrap;flex:0 0 auto;
}
.nav:hover{color:var(--ink);text-decoration:none;}
.nav.on{color:#231400;background:var(--amber);border-color:var(--amber);font-weight:700;}
.nav.admin{color:var(--red);border-color:var(--line);}
.nav.admin.on{color:#2a0007;background:var(--red);border-color:var(--red);}
.navspace{flex:1 0 6px;}
.whoami{
  font-family:inherit;font-size:clamp(11px, 3.2vw, 13px);
  letter-spacing:.01em;font-weight:600;
  background:transparent;border:2px solid var(--line);color:var(--amber);
  padding:6px clamp(6px, 2vw, 11px);cursor:pointer;white-space:nowrap;flex:0 0 auto;
}
.whoami:hover{border-color:var(--amber);}

main{flex:1 1 auto;padding:12px 0 26px;}
footer.readout{
  border-top:3px solid var(--line);padding:8px 0 calc(10px + env(safe-area-inset-bottom));
  font-size:10px;color:var(--dim);letter-spacing:.06em;
  display:flex;align-items:center;gap:6px;
}
footer.readout::before{content:"\25B8";color:var(--amber);}

/* ---------- headings ---------- */
h1{font-size:23px;letter-spacing:-.01em;font-weight:700;line-height:1.2;}
h2.month{
  font-size:11px;letter-spacing:.14em;color:var(--dim);text-transform:uppercase;
  font-weight:600;margin:20px 0 8px;border-bottom:2px solid var(--line);padding-bottom:5px;
}
h2.month:first-child{margin-top:0;}
.sub{font-size:11px;letter-spacing:.12em;color:var(--dim);text-transform:uppercase;font-weight:600;}
.muted{color:var(--dim);}
.tiny{font-size:12px;}
/* body copy that has to be read rather than scanned */
.lead{font-size:14px;color:var(--dim);margin-top:5px;line-height:1.5;}
.lead b{color:var(--amber);}
ul.plain{list-style:none;margin:14px 0 0;font-size:13px;color:var(--dim);}
ul.plain li{margin-bottom:6px;padding-left:14px;position:relative;}
ul.plain li::before{content:"\25B8";position:absolute;left:0;color:var(--amber);}
ul.plain b{color:var(--ink);font-weight:700;}

/* ---------- cards ---------- */
/* translucent so the sky shows through the board without washing out the text */
.card{
  background:rgba(16,21,52,.82);border:2px solid var(--line);
  padding:11px;margin-bottom:8px;
}
.card.pinned{border-color:var(--amber-d);}
/* The date is a label, not the headline: small, mono, quiet. The act is. */
.card .when{
  font-size:11px;letter-spacing:.08em;color:var(--dim);text-transform:uppercase;
  font-variant-numeric:tabular-nums;
}
.card .who-line{font-size:12px;color:var(--dim);margin-top:3px;}
.card h3{font-size:19px;font-weight:700;line-height:1.2;margin:3px 0 2px;letter-spacing:-.01em;}
.card h3 a{color:var(--ink);}
.card .venue{font-size:13px;color:var(--dim);}
.card.past{opacity:.72;}
.card.review{border-left:4px solid var(--line);}
.sheetnote{font-size:11px;color:var(--dim);margin-top:5px;font-style:italic;}

/* ---------- person chips ---------- */
/* One scale, learnable without a legend:
     filled green  holds a ticket — the strongest state there is
     outline green voted in, no ticket yet
     outline amber down to go, tentative
     dim struck    passed
     dashed amber  a spare going begging, i.e. something on offer to you     */
.chips{display:flex;flex-wrap:wrap;gap:5px;margin-top:9px;}
.chip{
  font-size:12px;letter-spacing:.01em;font-weight:600;
  padding:3px 8px;border:1.5px solid var(--line);color:var(--dim);
  white-space:nowrap;background:rgba(7,8,26,.5);border-radius:11px;
}
.chip.tix{background:var(--good);border-color:var(--good);color:#06210e;}
.chip.in{border-color:var(--good);color:var(--good);}
.chip.maybe{border-color:var(--amber-d);color:var(--amber);}
.chip.pass{color:#5a6088;text-decoration:line-through;}
.chip.guest{border-style:dashed;color:var(--ink);}
.chip.spare{border-color:var(--amber);color:var(--amber);border-style:dashed;}

/* ---------- buttons ---------- */
button,.btn{
  font-family:inherit;font-size:13px;letter-spacing:.01em;font-weight:600;
  background:var(--panel);color:var(--dim);
  border:2px solid var(--line);border-radius:0;
  padding:10px 12px;cursor:pointer;
  display:inline-block;text-align:center;
}
button:hover,.btn:hover{color:var(--ink);border-color:var(--dim);text-decoration:none;}
button.primary,.btn.primary{background:var(--amber);color:#2a1c00;border-color:#8a6a20;font-weight:700;}
.btn.big,button.big{font-size:13px;padding:15px 20px;letter-spacing:.16em;}
button.primary:hover{color:#2a1c00;}
button:disabled{opacity:.45;cursor:default;}
.btnrow{display:flex;gap:5px;margin-top:8px;}
.btnrow>*{flex:1 1 0;min-height:40px;}
.btnrow.tight>*{flex:0 0 auto;}

/* the three votes, always in the same order and the same place, and coloured
   the same as the chips they produce */
.vote.on[data-vote="in"]{background:var(--good);border-color:var(--good);color:#06210e;font-weight:700;}
.vote.on[data-vote="maybe"]{border-color:var(--amber-d);color:var(--amber);background:rgba(200,148,40,.12);}
.vote.on[data-vote="pass"]{border-color:var(--bad);color:var(--bad);}


/* ---------- date rail ---------- */
.rail{display:flex;flex-wrap:wrap;gap:5px;margin-top:8px;}
.datechip{
  font-size:10px;letter-spacing:.08em;text-transform:uppercase;
  padding:7px 8px;border:2px solid var(--line);background:var(--panel);color:var(--dim);
  cursor:pointer;font-family:inherit;font-variant-numeric:tabular-nums;
}
.datechip .n{color:var(--amber);font-weight:700;}
.datechip.mine{border-color:var(--amber-d);color:var(--ink);}
.datechip.best{border-color:var(--good);}
.datechip.pinned{background:var(--amber);border-color:var(--amber);color:#231400;font-weight:700;}
.datechip.pinned .n{color:#231400;}

/* ---------- tickets ---------- */
.purchase{border:2px solid var(--line);background:rgba(20,24,56,.85);padding:9px;margin-top:7px;}
.purchase .head{
  display:flex;align-items:baseline;gap:6px;font-size:10px;
  letter-spacing:.1em;text-transform:uppercase;color:var(--dim);
}
.purchase .head b{color:var(--amber);}
.purchase .note{font-size:11px;color:var(--dim);margin-top:3px;}

/* ---------- forms ---------- */
label.f{display:block;margin-top:10px;}
label.f>span{display:block;font-size:9px;letter-spacing:.2em;color:var(--dim);text-transform:uppercase;margin-bottom:3px;}
input[type=text],input[type=date],input[type=time],input[type=number],textarea,select.f{
  width:100%;font-family:inherit;font-size:13px;
  background:var(--row);color:var(--ink);border:2px solid var(--line);
  padding:9px 8px;border-radius:0;
}
input:focus,textarea:focus,select:focus{outline:none;border-color:var(--amber);}
.stepper{display:flex;align-items:center;gap:6px;}
/* only the +/- keys are square; scoping this matters, or the submit button in
   the same row gets squashed to 42px and its label spills out */
.stepper button[data-step]{width:42px;min-height:42px;font-size:15px;}
.stepper .val{font-size:22px;font-weight:700;color:var(--amber);min-width:2ch;text-align:center;}

/* ---------- misc ---------- */
.notice{border:2px solid var(--amber-d);background:rgba(26,23,51,.88);padding:9px;font-size:11px;margin-bottom:10px;}
.notice.bad{border-color:var(--bad);}
.empty{border:2px dashed var(--line);padding:26px 12px;text-align:center;color:var(--dim);font-size:12px;background:rgba(16,21,52,.55);letter-spacing:.1em;text-transform:uppercase;}
.empty::before{
  content:"";display:block;width:96px;height:96px;margin:0 auto 14px;
  background:url(/shows/assets/planet2.png) center/contain no-repeat;
  image-rendering:pixelated;opacity:.9;
}
.grid2{display:grid;grid-template-columns:1fr 1fr;gap:5px;}
hr.rule{border:none;border-top:2px solid var(--line);margin:16px 0;}
code.tok{
  display:block;word-break:break-all;background:var(--row);border:2px solid var(--line);
  padding:8px;font-size:11px;color:var(--amber);margin-top:4px;
}
ol.steps{margin:6px 0 0 18px;font-size:11px;color:var(--dim);}
ol.steps li{margin-bottom:4px;}
.flash{
  position:fixed;left:50%;bottom:16px;transform:translateX(-50%);
  background:var(--amber);color:#2a1c00;font-size:10px;letter-spacing:.14em;
  text-transform:uppercase;font-weight:700;padding:8px 14px;z-index:60;
  border:2px solid #8a6a20;
}
@media (prefers-reduced-motion:no-preference){
  .flash{animation:flashin .18s ease-out;}
  @keyframes flashin{from{opacity:0;transform:translate(-50%,6px);}to{opacity:1;transform:translate(-50%,0);}}
}

/* ---------- triage ----------
   A power-user list: 400 rows, one line each, and the row you just acted on
   greys out in place rather than vanishing — a list that reflows under your
   thumb costs more than it saves. */
.filters{display:flex;flex-wrap:wrap;align-items:center;gap:5px;margin-top:10px;}
.pill{
  font-size:10px;letter-spacing:.12em;text-transform:uppercase;
  padding:6px 9px;border:2px solid var(--line);color:var(--dim);
  background:rgba(20,24,56,.7);white-space:nowrap;
}
.pill:hover{color:var(--ink);border-color:var(--dim);text-decoration:none;}
.pill.on{background:var(--amber);border-color:var(--amber);color:#231400;font-weight:700;}
.venuepick{
  flex:1 1 140px;min-width:140px;width:auto;font-size:11px;padding:6px;
  background:rgba(20,24,56,.7);
}
.keyhelp{display:none;}
@media (hover:hover) and (pointer:fine){ .keyhelp{display:block;margin-top:12px;} }
.keyhelp b{color:var(--amber);font-weight:700;}

.trows{list-style:none;margin:10px 0 0;border-top:2px solid var(--line);}
.trow{
  display:flex;align-items:center;gap:8px;
  padding:7px 6px;border-bottom:2px solid var(--line);
  background:rgba(16,21,52,.55);outline:none;
}
.trow:focus,.trow.sel{background:var(--sel);box-shadow:inset 3px 0 0 var(--amber);}
.trow.done{opacity:.4;}
.trow.done .tact{visibility:hidden;}
.tdate{
  flex:0 0 74px;font-size:10px;letter-spacing:.08em;color:var(--amber);
  text-transform:uppercase;font-variant-numeric:tabular-nums;
}
.tmain{flex:1 1 auto;min-width:0;}
.tart{display:block;font-size:13px;font-weight:700;line-height:1.25;
      overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
.tven{display:block;font-size:10px;color:var(--dim);
      overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
.tbadge{
  display:inline-block;margin-left:5px;padding:0 4px;font-size:9px;font-weight:700;
  letter-spacing:.08em;text-transform:uppercase;border:1px solid var(--line);color:var(--dim);
}
.tbadge.new{color:#231400;background:var(--amber);border-color:var(--amber);}
.tbadge.out{color:var(--bad);border-color:var(--bad);}
.tbadge.low{color:var(--dim);}
.tacts{flex:0 0 auto;display:flex;gap:4px;}
.tact{
  width:34px;min-height:34px;padding:0;font-size:13px;line-height:32px;
  background:rgba(20,24,56,.9);
}
.tact.yes:hover{color:var(--good);border-color:var(--good);}
.tact.no:hover{color:var(--bad);border-color:var(--bad);}
.trow[data-status="shortlisted"] .tact.yes{color:var(--good);border-color:var(--good);}
.trow[data-status="skipped"] .tact.no{color:var(--bad);border-color:var(--bad);}
.unplaced{display:flex;align-items:center;gap:6px;margin-top:7px;font-size:11px;}
.unplaced button{padding:4px 7px;font-size:9px;}

/* ---------- deck ----------
   Every card is a form with three buttons; the swipe layer is added by script
   and hides them. If shows.js never loads, this is still a usable one-card-at-
   a-time voting page. */
.deckcount{margin-bottom:10px;}
.deck{position:relative;height:min(62vh,430px);margin-bottom:10px;}
.dcard{
  position:absolute;inset:0;display:none;flex-direction:column;
  background:rgba(16,21,52,.95);border:2px solid var(--line);
  padding:14px;overflow:hidden;
}
.dcard:first-of-type{display:flex;}
.dcard.wild{border-style:dashed;border-color:var(--amber-d);}
.deck.js .dcard{display:none;}
.deck.js .dcard:nth-of-type(-n+3){display:flex;}
/* touch-action:none only on the card being dragged — "up = maybe" and page
   scrolling cannot both own a vertical drag */
.deck.js .dcard:nth-of-type(1){z-index:3;cursor:grab;touch-action:none;}
.deck.js .dcard:nth-of-type(2){z-index:2;transform:translateY(12px) scale(.96);opacity:.65;}
.deck.js .dcard:nth-of-type(3){z-index:1;transform:translateY(24px) scale(.92);opacity:.35;}
.deck.js .dform{display:none;}
.dcard.fly{transition:transform .3s ease-out, opacity .3s ease-out;}

.dwhen{font-size:11px;letter-spacing:.14em;color:var(--amber);text-transform:uppercase;}
.dart{
  font-size:26px;line-height:1.15;font-weight:700;margin:8px 0 4px;
  display:-webkit-box;-webkit-line-clamp:4;-webkit-box-orient:vertical;overflow:hidden;
}
.dven{font-size:13px;color:var(--dim);}
.dbadges{display:flex;flex-wrap:wrap;gap:4px;margin-top:9px;}
.tbadge.wildb{color:#231400;background:var(--amber-d);border-color:var(--amber-d);}
.tbadge.rec{color:var(--good);border-color:var(--good);}
.dvotes{margin-top:auto;display:flex;flex-wrap:wrap;gap:4px;padding-top:10px;}
.dlinks{display:flex;gap:14px;margin-top:10px;font-size:11px;}
.dform{display:flex;gap:5px;margin-top:10px;}
.dform>button{flex:1 1 0;min-height:42px;}

.dstamps{position:absolute;inset:0;pointer-events:none;z-index:4;}
.dstamp{
  position:absolute;top:16px;padding:4px 12px;opacity:0;
  font-size:15px;font-weight:700;letter-spacing:.16em;text-transform:uppercase;
  border:3px solid;background:rgba(7,8,26,.6);
}
.dstamp.in{right:14px;color:var(--good);border-color:var(--good);transform:rotate(11deg);}
.dstamp.pass{left:14px;color:var(--bad);border-color:var(--bad);transform:rotate(-11deg);}
.dstamp.maybe{left:50%;margin-left:-3.2em;color:var(--amber);border-color:var(--amber);}

/* Three equal columns: Back in the first, the decisions in the middle one, the
   third left empty so the trio sits dead centre whatever Back's width is. */
.dbar{
  display:none;grid-template-columns:1fr auto 1fr;align-items:center;margin-top:4px;
}
.dgroup{display:flex;gap:8px;align-items:center;}
.dbtn{
  /* one height for all four — a row of buttons at three different heights was
     the first thing anyone noticed. The widths scale down a little on narrow
     phones so the centred trio never grows into Back's space on the left. */
  height:54px;width:clamp(48px, 14.5vw, 58px);padding:0;font-size:20px;line-height:1;
  background:rgba(20,24,56,.9);border:2px solid var(--line);
}
.dbtn.pass:hover{color:var(--bad);border-color:var(--bad);}
.dbtn.maybe:hover{color:var(--amber);border-color:var(--amber-d);}
.dbtn.in{color:var(--good);border-color:#2f8f4a;}
.dbtn.in:hover{background:var(--good);color:#06210e;}
.dbtn:disabled{opacity:.3;}

/* ---------- the swipe hint ----------
   Over the first card only, and only when the swipe layer actually exists —
   with no JavaScript there is nothing to swipe and the hint would be a lie. */
.dhint{display:none;}
.deck.js .dhint{
  position:absolute;inset:0;z-index:5;pointer-events:none;
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:18px;
  background:rgba(7,8,26,.86);padding:18px;text-align:center;
}
.dhrow{display:flex;width:100%;justify-content:space-between;align-items:center;}
.dh{
  display:flex;align-items:center;gap:7px;
  font-size:12px;letter-spacing:.14em;text-transform:uppercase;color:var(--ink);
}
.dh b{font-size:24px;line-height:1;color:var(--amber);}
.dh.pass b{color:var(--bad);}
.dh.in b{color:var(--good);}
.dh.maybe{flex-direction:column;gap:2px;}
.dhnote{font-size:10px;letter-spacing:.1em;text-transform:uppercase;color:var(--dim);}
@media (prefers-reduced-motion:no-preference){
  .deck.js .dhint{animation:hintin .3s ease-out;}
  .dh b{animation:nudge 1.9s ease-in-out infinite;}
  .dh.pass b{animation-name:nudgeleft;}
  .dh.maybe b{animation-name:nudgeup;}
  @keyframes hintin{from{opacity:0;}to{opacity:1;}}
  @keyframes nudge    {0%,100%{transform:translateX(0);}50%{transform:translateX(5px);}}
  @keyframes nudgeleft{0%,100%{transform:translateX(0);}50%{transform:translateX(-5px);}}
  @keyframes nudgeup  {0%,100%{transform:translateY(0);}50%{transform:translateY(-5px);}}
}
/* two of the four buttons say what they do; the tick and the cross do not need to */
.dbtn.word{width:auto;min-width:clamp(66px, 20vw, 80px);font-size:11px;letter-spacing:.12em;}
/* Back is deliberately the smallest of the four and sits out on the left rail;
   it undoes, it does not decide. */
.dbtn.word.undo{min-width:clamp(56px, 16vw, 64px);color:var(--dim);justify-self:start;}

/* ---------- launch gauge ----------
   The shortlist is the climb; the unvetted tail is what is out there once you
   make orbit. It exists so nobody starts swiping 1,700 unvetted shows while
   the vetted ones are still waiting on them. */
.gauge{margin:6px 0 14px;}
.gtrack{
  position:relative;height:30px;
}
.gtrack::after{
  content:"";position:absolute;left:14px;right:16px;top:50%;
  border-top:2px dashed var(--line);
}
/* launch pad at the left, a star to aim at on the right */
.gpad{
  position:absolute;left:0;top:50%;transform:translateY(-50%);
  width:10px;height:14px;background:var(--line);
}
.gstar{
  position:absolute;right:0;top:50%;transform:translate(0,-50%) rotate(45deg);
  width:10px;height:10px;background:var(--line);
}
.grocket{
  position:absolute;top:50%;transform:translate(-50%,-50%) rotate(-12deg);
  line-height:0;z-index:2;
  transition:left .5s cubic-bezier(.3,.8,.4,1);
}

.gauge.orbit .gtrack::after{border-top-color:var(--amber-d);}
.gauge.orbit .gstar{background:var(--amber);}
.gauge.orbit .grocket{transform:translate(-50%,-50%) rotate(-30deg);}
.glabel{margin-top:2px;}
@media (prefers-reduced-motion:no-preference){
  .gflame{animation:burn .28s steps(2) infinite;transform-origin:6px 8px;}
  @keyframes burn{0%{transform:scaleX(1);}100%{transform:scaleX(1.5);}}
}

/* ---------- which-nights picker ----------
   Only ever appears for a run with more than one night, and only after an in or
   a maybe: saying yes to a residency without saying which night is half an
   answer, and the overlap count on the show page depends on the other half. */
.dpick{
  position:fixed;inset:0;z-index:60;
  display:flex;align-items:center;justify-content:center;padding:18px;
  background:rgba(7,8,26,.86);
}
.dpick[hidden]{display:none;}
.dpinner{
  width:100%;max-width:420px;
  background:var(--row);border:2px solid var(--amber-d);padding:14px;
}
.dptitle{font-size:14px;font-weight:700;letter-spacing:.02em;}
.dpshow{font-size:12px;color:var(--dim);margin-top:2px;}
.dpchips{display:flex;flex-wrap:wrap;gap:6px;margin-top:12px;}
.dpchips .datechip{min-height:42px;}

/* ---------- the ? and the explainer ---------- */
.helpbtn{
  width:26px;height:26px;padding:0;border-radius:50%;
  font-size:12px;font-weight:700;line-height:1;
  color:var(--amber);border-color:var(--amber-d);background:rgba(20,24,56,.9);
  flex:0 0 auto;
}
.gauge .helpbtn{position:absolute;right:0;top:0;}
.gauge{position:relative;}
h2.month .helpbtn{vertical-align:-7px;margin-left:6px;}
.explain{
  position:fixed;inset:0;z-index:70;
  display:flex;align-items:center;justify-content:center;padding:18px;
  background:rgba(7,8,26,.88);
}
.explain[hidden]{display:none;}
.exinner{width:100%;max-width:440px;background:var(--row);border:2px solid var(--amber-d);padding:16px;}
.exlist{list-style:none;margin:12px 0 0;}
.exlist li{display:flex;gap:10px;align-items:flex-start;margin-bottom:11px;font-size:13px;line-height:1.45;}
.exlist b:first-child{font-size:20px;line-height:1.1;width:1em;flex:0 0 auto;text-align:center;}
.exin{color:var(--good);}
.exmaybe{color:var(--amber);}
.expass{color:var(--bad);}
.exlist span b{color:var(--ink);}

/* ---------- vote bar on a board card ---------- */
.card .votebar{margin-top:9px;}
.card .votebar>*{min-height:38px;font-size:10px;}

/* ---------- the after-vote sheet ---------- */
.dpsection{margin-top:14px;border-top:2px solid var(--line);padding-top:10px;}
.dpacts{display:flex;flex-wrap:wrap;gap:6px;margin-top:8px;}
.dpacts>*{flex:1 1 auto;min-height:44px;}
.dphaveqty{margin-top:10px;border:2px solid var(--line);background:rgba(7,8,26,.5);padding:9px;}
.dphaveqty .stepper button[data-hstep]{width:42px;min-height:42px;font-size:15px;}
.dpick .sub{margin-bottom:2px;}
.dspare{
  position:absolute;right:12px;top:12px;z-index:3;
  font-size:9px;letter-spacing:.1em;text-transform:uppercase;font-weight:700;
  color:var(--bad);border:2px dashed var(--bad);padding:2px 5px;background:rgba(7,8,26,.6);
}

/* the softer answer inside the "you're in" sheet */
.dpdownsec{margin-top:12px;border-top:2px dashed var(--line);padding-top:10px;}
.dpdownsec button{width:100%;min-height:44px;border-color:var(--amber-d);color:var(--amber);}

/* ---------- ticket status ---------- */
.cardbadges{display:flex;flex-wrap:wrap;gap:4px;margin-top:5px;}
.tbadge.onsale{color:var(--good);border-color:var(--good);}
.tbadge.dice{color:var(--amber);border-color:var(--amber-d);}
.tixline{display:flex;flex-wrap:wrap;align-items:center;gap:10px;font-size:12px;margin-top:4px;}
.tixline a.hot{color:var(--amber);font-weight:700;}

/* ---------- digest ---------- */
.digestbox{
  width:100%;margin-top:12px;font-family:inherit;font-size:12px;line-height:1.5;
  background:var(--row);color:var(--ink);border:2px solid var(--line);
  padding:10px;border-radius:0;resize:vertical;
}
.digestbox:focus{outline:none;border-color:var(--amber);}

/* ---------- design pass: proportional type, quieter chrome ----------
   Added last so it wins over the older rules it replaces. */
.tbadge{
  font-family:var(--sans);font-size:11px;font-weight:600;letter-spacing:.01em;
  text-transform:none;padding:2px 7px;border-radius:10px;border:1.5px solid var(--line);
}
.dwhen{font-size:12px;letter-spacing:.08em;color:var(--dim);}
.dart{font-size:30px;line-height:1.12;letter-spacing:-.02em;-webkit-line-clamp:5;}
.dven{font-size:15px;color:var(--dim);margin-top:2px;}
.dstamp{font-family:var(--sans);font-size:17px;letter-spacing:.04em;font-weight:800;}
.dbtn.word{font-size:13px;letter-spacing:.01em;}
.dspare{font-family:var(--sans);font-size:11px;letter-spacing:.01em;text-transform:none;
        color:var(--amber);border-color:var(--amber);border-radius:10px;padding:2px 7px;}
.pill{font-size:12px;letter-spacing:.01em;text-transform:none;font-weight:600;}
.tart{font-size:15px;letter-spacing:-.01em;}
.tven{font-size:12px;}
.tdate{font-size:11px;color:var(--dim);flex-basis:80px;}
.dptitle{font-size:19px;letter-spacing:-.01em;}
.dpshow{font-size:14px;margin-top:3px;}
.datechip{font-size:12px;letter-spacing:.02em;text-transform:none;}
.exlist li{font-size:14px;}
.dhnote,.dh{font-family:var(--sans);letter-spacing:.01em;text-transform:none;}
.dh{font-size:14px;}
footer.readout{font-size:11px;letter-spacing:.04em;}
.empty{font-size:13px;letter-spacing:.02em;text-transform:none;}
.sheetnote{font-size:12px;}

.purchase .head{font-size:12px;letter-spacing:.02em;text-transform:none;}
.purchase .head b{color:var(--ink);}
label.f>span{font-size:11px;letter-spacing:.1em;}
.helpbtn{font-family:var(--sans);font-size:13px;}

/* the ? sat on top of the rocket at 100%; put it in the label line instead */
.gauge .helpbtn{position:static;margin-left:8px;vertical-align:-7px;}
.gtrack{margin-right:0;}
/* Let the card's content sit together under the headline and pin only the
   links to the bottom — the old rule pushed the votes down and left a hole
   through the middle of every card. */
.dvotes{margin-top:14px;}
.dlinks{margin-top:auto;padding-top:12px;}
.deck{height:min(58vh,400px);}

/* ---------- top bar, tightened ---------- */
.top{gap:9px;padding-bottom:1px;}
/* Narrower tabs and a much smaller name chip: with six items plus a name, every
   pixel of padding is the difference between one line and a scroll. */
.navrow{gap:2px;padding:3px 0 6px;}
.nav{
  font-size:clamp(11px, 3vw, 13px);
  padding:6px clamp(4px, 1.4vw, 9px);
}
.whoami{
  font-size:clamp(10px, 2.7vw, 12px);
  padding:5px clamp(5px, 1.5vw, 9px);
  text-transform:none;letter-spacing:0;
  border-color:var(--amber-d);
}
/* five pixels over with the admin tab in; this is the five pixels */
.nav{padding:6px clamp(3px, 1.25vw, 9px);}
.whoami{padding:5px clamp(4px, 1.3vw, 9px);}

/* ---------- who is going, in words ---------- */
.who{margin-top:10px;display:flex;flex-direction:column;gap:6px;}
.whorow{display:flex;align-items:baseline;gap:8px;flex-wrap:wrap;}
.wholab{
  flex:0 0 auto;min-width:68px;
  font-size:11px;letter-spacing:.1em;text-transform:uppercase;
  font-weight:700;color:var(--dim);
}
.whopills{display:flex;flex-wrap:wrap;gap:5px;}
.nobody{font-size:13px;color:#626a93;font-style:italic;}
.venuelink{color:var(--dim);border-bottom:1px dotted var(--line);}
.venuelink:hover{color:var(--amber);text-decoration:none;border-bottom-color:var(--amber);}

/* dates were disappearing into the card; they are the second thing you read */
.card .when,.dwhen,.tdate{color:#b9c2f0;font-weight:600;}
.card .when{font-size:12px;letter-spacing:.06em;}
.dwhen{font-size:13px;letter-spacing:.06em;}

/* bigger words on the board's buttons, same button */
.card .votebar>*{min-height:38px;font-size:13px;padding:6px 8px;}

/* ---------- calendar view ----------
   A month at a glance over the same board. Tapping a day jumps to its cards —
   the grid is for orientation, the cards are where you can actually do
   something. */
.calhead{display:flex;align-items:center;justify-content:space-between;gap:10px;margin-bottom:8px;}
.calmonth{font-size:13px;letter-spacing:.14em;font-weight:700;color:var(--ink);}
.calnav{
  width:38px;height:34px;line-height:30px;text-align:center;
  border:2px solid var(--line);color:var(--amber);font-size:15px;
}
.calnav:hover{border-color:var(--amber);text-decoration:none;}
.calgrid{
  display:grid;grid-template-columns:repeat(7,1fr);gap:3px;
  margin-bottom:18px;
}
.caldow{
  text-align:center;font-size:10px;letter-spacing:.1em;font-weight:700;
  color:var(--dim);padding-bottom:3px;
}
.calday{
  position:relative;display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:3px;min-height:42px;
  border:2px solid transparent;background:rgba(16,21,52,.55);
  font-family:var(--mono);font-size:13px;color:#626a93;
}
.calday.blank{background:transparent;}
.calday.today{border-color:var(--line);color:var(--ink);}
a.calday.has{color:var(--ink);background:rgba(20,24,56,.95);border-color:var(--line);}
a.calday.has:hover{border-color:var(--amber);text-decoration:none;}
.caldots{display:flex;gap:2px;height:4px;}
.caldots i{width:4px;height:4px;background:var(--good);border-radius:50%;}
.btn.on{background:var(--amber);color:#2a1c00;border-color:#8a6a20;font-weight:700;}
/* jumping to a card should not tuck it under the sticky header */
.card[id]{scroll-margin-top:70px;}

/* ---------- clarity round 2 ---------- */
/* label and names as real columns, so every row lines up */
.who{display:grid;grid-template-columns:auto 1fr;gap:7px 10px;align-items:baseline;margin-top:10px;}
.wholab{min-width:0;padding-top:2px;}
/* the venue matters as much as the date; it was a whisper */
.card .venue,.venuelink{color:#b9c2f0;font-weight:600;}
.card .venue{font-size:13px;}
.venuelink{border-bottom:1px dotted #4c5798;}
.dven a.venuelink{font-size:15px;}
/* prominent without being a slab of yellow */
.btn.primary.quiet{
  background:rgba(255,212,92,.10);color:var(--amber);border-color:var(--amber);font-weight:700;
}
.btn.primary.quiet:hover{background:rgba(255,212,92,.2);color:var(--amber);}
/* two decisions, so they can afford words */
.dgroup .dbtn.word{min-width:96px;}
.dbtn.in.word{color:var(--good);border-color:#2f8f4a;}
.dbtn.in.word:hover{background:var(--good);color:#06210e;}
.dbtn.pass.word:hover{color:var(--bad);border-color:var(--bad);}
/* the sheet's way out */
.dpinner{position:relative;}
.dpx{
  position:absolute;top:8px;right:8px;width:34px;height:34px;padding:0;
  font-size:15px;line-height:1;color:var(--dim);background:transparent;border-color:var(--line);
}
.dpx:hover{color:var(--bad);border-color:var(--bad);}
.dptitle{padding-right:40px;}
.dpacts{flex-direction:column;}
.dpacts>*{width:100%;}
.curating{
  border:2px solid var(--amber-d);background:rgba(200,148,40,.08);
  padding:8px 10px;margin:0 0 10px;font-size:12px;
}
.curating b{color:var(--amber);}

/* ---------- who: inline, flowing ----------
   The label is part of the line, not a column, so "In" and "Interested" both
   sit right against their names and the run wraps like a sentence. */
.who{display:block;margin-top:10px;}
.whorow{
  display:block;line-height:2;
  margin-top:2px;
}
.whorow .wholab{
  min-width:0;margin-right:7px;
  font-size:11px;letter-spacing:.1em;text-transform:uppercase;font-weight:700;color:var(--dim);
}
.whorow .chip{margin-right:4px;}
.whorow .nobody{margin-left:0;}
/* free shows are the easiest yes there is — say so loudly */
.tbadge.free{color:#06210e;background:var(--good);border-color:var(--good);font-weight:700;}

/* ---------- let the sky actually show ----------
   The nebula used to sit under a gradient that was 86% black by mid-screen, so
   it only ever appeared in the overscroll stretch. Four layers now, back to
   front: nebula, a light wash for legibility, stars, then the corner planet.
   Everything above them is translucent enough to see through. */
.sky{
  position:fixed;inset:0;z-index:-4;pointer-events:none;
  background-position:center;background-size:cover;background-repeat:no-repeat;
  image-rendering:pixelated;
}
body::before{
  z-index:-3;
  background:linear-gradient(180deg,
    rgba(7,8,26,.30) 0%, rgba(7,8,26,.45) 45%, rgba(7,8,26,.66) 100%);
}
/* more stars, and bright enough to read as stars */
body::after{
  z-index:-2;
  background-image:
    radial-gradient(1.2px 1.2px at 24px 36px,   rgba(255,255,255,.85), transparent),
    radial-gradient(1px 1px   at 148px 92px,    rgba(255,255,255,.6),  transparent),
    radial-gradient(2px 2px   at 64px 176px,    rgba(255,212,92,.75),  transparent),
    radial-gradient(1.2px 1.2px at 214px 228px, rgba(255,255,255,.7),  transparent),
    radial-gradient(1px 1px   at 106px 268px,   rgba(255,255,255,.5),  transparent),
    radial-gradient(1px 1px   at 186px 18px,    rgba(255,255,255,.55), transparent),
    radial-gradient(1.4px 1.4px at 40px 120px,  rgba(184,214,255,.7),  transparent),
    radial-gradient(1px 1px   at 232px 60px,    rgba(255,255,255,.45), transparent),
    radial-gradient(1px 1px   at 130px 210px,   rgba(255,255,255,.5),  transparent);
  background-size:248px 300px;
}
.worldcorner{z-index:-1;opacity:.55;}

/* chrome you can see through */
.top{background:rgba(7,8,26,.62);-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);}
footer.readout{background:rgba(7,8,26,.5);-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);}
.card{background:rgba(12,16,44,.70);-webkit-backdrop-filter:blur(3px);backdrop-filter:blur(3px);}
.dcard{background:rgba(12,16,44,.80);-webkit-backdrop-filter:blur(3px);backdrop-filter:blur(3px);}
.calday{background:rgba(12,16,44,.55);}
a.calday.has{background:rgba(16,21,52,.8);}
.trow{background:rgba(12,16,44,.6);}
/* The body's own opaque background paints OVER its negative-z-index children,
   which is what was hiding the nebula. The void stays on <html> as the base
   colour behind the image; body itself must be see-through. */
body{background:transparent;}
/* Kevin's own doors, marked so they read as his and not the group's */
.admintab{color:var(--red);border-color:var(--red);background:rgba(216,40,60,.10);font-weight:700;}
.admintab:hover{background:rgba(216,40,60,.22);color:var(--red);}
.gaugetab{padding:4px 10px;font-size:11px;margin-left:6px;vertical-align:2px;}
/* the claim link rides beside the spare count */


/* ---- up: on the board, no opinion (admin only) ------------------------- */
/* Amber, because it is the same act as a shortlist everywhere else in here,
   and deliberately not green: nobody is going yet, that is the point of it. */
.dstamp.board{
  left:50%;top:16px;transform:translateX(-50%) rotate(-3deg);
  color:var(--amber);border-color:var(--amber);white-space:nowrap;
}
.exboard{color:var(--amber);}
.dbtn.word.board{color:var(--amber);border-color:var(--amber-d);}
.dbtn.word.board:hover{background:var(--amber);color:#1b1405;}
/* Three buttons only fit on a phone if they stop insisting on 96px each. */
.dgroup:has(.dbtn.board) .dbtn.word{min-width:clamp(62px, 19vw, 96px);}

/* ---- triage sweep mode: scrolling past a row is the no ------------------ */
/* With no ✗ to place, the ✓ takes both slots. It is the only thing left to
   aim at, so it should be the size of the decision. */
.trows.sweep .tact.no{display:none;}
.trows.sweep .tact.yes{width:76px;font-size:17px;color:var(--good);border-color:#2f8f4a;}
.trows.sweep .tact.yes:hover{background:var(--good);color:#06210e;}
.trows.sweep .trow{padding-top:9px;padding-bottom:9px;}
/* Dimmed but still live — scroll back up and one tap takes it back. */
.trow.sweptrow{opacity:.42;}
.trow.sweptrow .tact.yes{opacity:1;}
.pill.sweeptog{font-family:var(--sans);}
.sweepnote{font-size:11px;color:var(--dim);align-self:center;line-height:1.35;}
.sweepbar{
  position:sticky;bottom:10px;z-index:5;display:flex;gap:10px;align-items:center;
  margin-top:12px;padding:9px 11px;font-size:12px;
  border:2px solid var(--bad);background:rgba(26,14,20,.94);
}
.sweepbar #sweepcount{flex:1 1 auto;}
.sweepbar button{padding:5px 12px;font-size:11px;}

/* ---- the gauge flies a real ship now ----------------------------------- */
/* One of the pong game's five launchers, at its own rendered size. No width
   or height here on purpose: the PNG is already one image pixel per art
   pixel at an integer 2x, and pixelated keeps the grid square after that. */
.grocket img{
  display:block;image-rendering:pixelated;
  filter:drop-shadow(0 0 6px rgba(7,8,26,.9));
}
/* Rendered at an integer 2x, so up to 42px tall — the track makes room for
   the big ones rather than letting them hang out of it. */
.gtrack{height:48px;}
/* The ships are pixel art: no tilt, because a 12° rotation resamples the grid
   and turns clean blocks into mush. It flies level, like the game draws it. */
.grocket{transform:translate(-50%,-50%);}
.gauge.orbit .grocket{transform:translate(-50%,-50%);}

/* ---- admin: take a show off the board ---------------------------------- */
/* Top-right of the card, in Kevin's red, and deliberately not big: it is the
   destructive one, so it should be easy to find and hard to hit by accident. */
.card{position:relative;}
.unboard{
  position:absolute;top:6px;right:6px;z-index:2;
  width:26px;min-height:26px;padding:0;line-height:24px;font-size:11px;
  color:var(--red);border-color:rgba(216,40,60,.45);background:rgba(216,40,60,.08);
}
.unboard:hover{background:var(--red);color:#fff;border-color:var(--red);}
/* The date sits under it, so it needs the room. */
.card .when{padding-right:30px;}

/* ---- the button row must never widen the page -------------------------- */
/* Flex items will not shrink below their own text, so a fourth button (the
   admin Triage one) pushed the row past 375px and made the whole document
   horizontally scrollable — an accidental left swipe while reading the board
   dragged the page sideways. Wrapping is the fix: the row gets a second line
   instead of the page getting a scrollbar. */
.btnrow{flex-wrap:wrap;}
.btnrow>*{flex:1 1 auto;}

/* ---- search on the board ----------------------------------------------- */
.btn.searchbtn.on{color:var(--amber);border-color:var(--amber);background:rgba(255,212,92,.10);}
.searchbox{margin:0 0 12px;}
#searchq{
  width:100%;font-family:inherit;font-size:16px;   /* 16px or iOS zooms the page */
  padding:11px 12px;color:var(--ink);
  background:rgba(7,8,26,.7);border:2px solid var(--amber-d);border-radius:0;
}
#searchq:focus{outline:none;border-color:var(--amber);}
.searchout{margin-top:8px;}
.sresult{
  display:block;padding:9px 10px;margin-bottom:6px;
  background:rgba(12,16,44,.70);border:2px solid var(--line);
  -webkit-backdrop-filter:blur(3px);backdrop-filter:blur(3px);
}
.sresult:hover{border-color:var(--amber-d);text-decoration:none;}
.swhen{
  display:block;font-family:var(--mono);font-size:10px;letter-spacing:.08em;
  color:var(--amber);text-transform:uppercase;
}
.sart{display:block;font-size:14px;font-weight:700;color:var(--ink);line-height:1.3;margin-top:1px;}
.sven{display:block;font-size:11px;color:var(--dim);margin-top:2px;}
.tbadge.onboard{color:#06210e;background:var(--good);border-color:var(--good);font-weight:700;}
.tbadge.skippedb{color:var(--bad);border-color:var(--bad);}
.searchnone{padding:14px 2px;font-size:13px;color:var(--dim);}
/* Four buttons (what everyone but Kevin sees) came to 353px in a 355px row —
   two pixels from wrapping. The row's own buttons give back a little side
   padding so that is not decided by one long venue name or a wider phone font. */
.btnrow.tight>*{padding-left:9px;padding-right:9px;}

/* ---- guest ------------------------------------------------------------- */
/* First on the who-are-you screen and the only outlined thing on it, because
   it is the one answer that is not a name in the grid below. */
.guestbtn{
  display:block;width:100%;margin-top:14px;min-height:52px;
  font-size:14px;font-weight:700;
  color:var(--amber);border-color:var(--amber);background:rgba(255,212,92,.08);
}
.guestbtn:hover{background:var(--amber);color:#231400;border-color:var(--amber);}
/* Dashed in the top bar: a name you have not given yet. */
.whoami.guest{border-style:dashed;color:var(--dim);}
.whoami.guest:hover{color:var(--amber);border-color:var(--amber);}

/* ---- the board, at half height ----------------------------------------- */
/* Kevin has triaged one month and the board already runs to 47 cards. None of
   this shrinks the type — the date, the venue and the button words were all
   made bigger on purpose. It takes out lines and space instead: where/when on
   one row, no row at all when nobody has answered, and less air around it. */
.card{padding:8px 9px;margin-bottom:6px;}
.card .when{
  display:flex;flex-wrap:wrap;align-items:baseline;gap:5px;line-height:1.45;
}
.card .when .wsep{color:var(--line);}
/* The venue keeps its own voice inside the date line: not uppercase, not mono,
   and the same size it had when it owned a row. */
.card .when .venue{
  font-size:13px;letter-spacing:.01em;text-transform:none;font-family:var(--sans);
}
.card h3{margin:1px 0 0;line-height:1.18;}
.card .who{margin-top:5px;gap:2px;}
.card .whorow{line-height:1.75;}
.card .cardbadges{margin-top:4px;}
.card .votebar{margin-top:6px;}
.card .votebar>*{min-height:32px;}
.card .sheetnote{margin-top:4px;}
/* The X was absolutely positioned, so the date line reserved 30px for it on
   every line — which pushed the venue onto a second row on nine cards out of
   47. A float only shortens the line it sits on, and a plain block (not flex)
   date line is what lets the text flow back to full width underneath it. */
.card{position:relative;}
.card .when{display:block;padding-right:0;}
.card .when .venue{display:inline;}
.unboard{
  position:static;float:right;width:24px;min-height:24px;line-height:22px;
  margin:0 0 2px 7px;
}
/* The last of the air: shorter vote buttons and tighter padding. Nothing here
   touches type size — the date, venue and button words were all deliberately
   made bigger, and taking that back would undo the point of them. */
.card{padding:6px 9px 7px;}
.card .votebar{margin-top:5px;}
.card .votebar>*{min-height:28px;}
/* In and Interested flow into each other as one line rather than stacking two.
   Kevin already picked inline-flowing text over a label column for the same
   reason: the labels are uppercase and small, so they read as signposts inside
   the run, and a card with two short answers stops costing two rows. */
.card .who{display:block;}
.card .whorow{display:inline;}
.card .whorow .wholab{margin-left:8px;}
.card .whorow:first-child .wholab{margin-left:0;}

/* ---- naming the seats as you log the purchase -------------------------- */
.seatpick{display:flex;flex-wrap:wrap;gap:5px;margin:7px 0 10px;}
.seat{
  font-size:12px;font-weight:600;padding:7px 10px;min-height:34px;
  border:2px solid var(--line);background:rgba(7,8,26,.5);color:var(--dim);
  border-radius:11px;
}
.seat:hover{border-color:var(--dim);color:var(--ink);}
/* Filled green is "holds a ticket" everywhere else on the board; a seat you
   have named is exactly that, so it gets the same colour here. */
.seat.mine{background:var(--good);border-color:var(--good);color:#06210e;}
.steplab{
  font-size:10px;letter-spacing:.1em;text-transform:uppercase;font-weight:700;
  color:var(--dim);margin-right:2px;
}
/* The separator before the venue was drawn in the border colour, so the date
   line had a dot on one side of the time and nothing on the other. Same ink as
   the rest of the line. */
.card .when .wsep{color:inherit;}
/* The row is inline now, and there is no whitespace between the time, the dot
   and the venue in the markup — so the dot has to carry its own air, the way
   the flex gap used to. */
.card .when .wsep{margin:0 5px;}

/* ---- tickets you can actually edit ------------------------------------- */
/* A way into the seats from the board, on the end of the names line so it
   costs no height. Open to everyone: the seats are a shared list. */
.tixedit{
  margin-left:9px;font-size:11px;font-weight:700;letter-spacing:.04em;
  color:var(--amber);border-bottom:1px dotted var(--amber-d);white-space:nowrap;
}
.tixedit:hover{text-decoration:none;border-bottom-color:var(--amber);}
.qtyedit{display:inline-flex;align-items:center;gap:5px;margin:0 2px;}
.qtyedit .tiny{padding:1px 7px;font-size:12px;line-height:1.5;min-height:0;}
.qtyval{font-family:var(--mono);font-size:13px;min-width:1.2em;text-align:center;}

/* Three lines of artist is plenty — past that it is a festival bill, and the
   card is a pointer to the show page, not the show page. */
.card h3 a{
  display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;
  overflow:hidden;
}

/* ---- the ? stops stretching the line it sits on ------------------------ */
/* It is a 26px circle in an 11px heading, so it was setting that line's
   height on its own and leaving a band of dead space under every "ARE YOU
   IN?". Smaller, centred by flex rather than a vertical-align nudge, and with
   negative block margins so it cannot grow the line box past the text. */
h2.month{display:flex;align-items:center;gap:7px;}
h2.month .helpbtn{
  width:21px;height:21px;font-size:11px;line-height:1;
  vertical-align:baseline;margin:-5px 0;
}
.gauge .helpbtn{width:21px;height:21px;font-size:11px;margin:-5px 0 -5px 8px;vertical-align:-5px;}

/* ---- who is on these tickets ------------------------------------------- */
/* The same roster you tapped when you logged the purchase, doing the same
   thing afterwards: tap a name on, tap it off. It replaced one dropdown per
   seat, which asked which seat before it asked who — and "which seat" is a
   question nobody in this group has ever had. */
.seatrow{display:flex;flex-wrap:wrap;gap:5px;margin-top:8px;}
.seatrow .seat{display:inline-block;text-align:center;}
.seatrow .seat.guest{border-style:dashed;}
.addguest{color:var(--amber);border-color:var(--amber-d);border-style:dashed;}
.addguest:hover{color:#231400;background:var(--amber);border-color:var(--amber);}
.seatsum{
  margin-top:7px;font-size:10px;letter-spacing:.09em;text-transform:uppercase;
  color:var(--dim);font-weight:700;
}

/* ---- triage rows show the whole bill ----------------------------------- */
/* They were one line each with an ellipsis, which hid exactly the thing you
   are deciding on: a residency's openers are often the reason to go. Rows are
   no longer the same height as each other, and that is fine — the list is for
   reading, not for looking tidy. */
.tart{white-space:normal;overflow:visible;text-overflow:clip;line-height:1.3;}
.tven{white-space:normal;overflow:visible;text-overflow:clip;line-height:1.4;}
.trow{align-items:flex-start;}
.tdate{padding-top:2px;}
.tacts{position:sticky;top:8px;}

/* ---- the board's date line never wraps --------------------------------- */
/* A long venue name was taking a second row on cards that had nothing else to
   say. The date is first and always survives; the venue gets clipped with an
   ellipsis. overflow:hidden also makes this a block formatting context, so it
   sits beside the floated X instead of running under it. */
.card .when{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}

/* Tapping a bill in triage opens that show — the names are the link. */
a.tart{color:var(--ink);}
a.tart:hover{color:var(--amber);text-decoration:none;}
/* "Man/Woman/Chainsaw" has no space to break at, so it ran out under the ✓.
   Break anywhere rather than overflow — a clipped band name is unreadable,
   a hyphenless wrap is merely ugly. */
.tart,.tven{overflow-wrap:anywhere;}

/* ---- preview: seeing it the way the group does ------------------------- */
/* Fixed to the top so it survives scrolling a long board — the exit has to be
   reachable from wherever you are, not from wherever the page started. */
.previewbar{
  /* Sticky, not fixed: in the flow it reserves its own space, so it can wrap to
     two lines on a narrow phone without covering the header. The fixed version
     needed a matching padding-top on #app and got it wrong the moment the text
     wrapped. */
  position:sticky;top:0;z-index:80;
  display:flex;gap:8px;align-items:center;justify-content:center;flex-wrap:wrap;
  padding:7px 10px;font-size:11px;font-weight:600;letter-spacing:.02em;
  color:#1b1405;background:var(--amber);
  box-shadow:0 2px 0 rgba(0,0,0,.35);
}
.previewbar b{text-transform:uppercase;letter-spacing:.12em;}
.previewbar a{
  color:#1b1405;border:2px solid rgba(27,20,5,.5);padding:2px 9px;font-weight:700;
}
.previewbar a:hover{background:#1b1405;color:var(--amber);text-decoration:none;border-color:#1b1405;}

/* "8 nights" / "+2 more" sits with the date, not as a badge on its own row. */
.card .when .nights{
  margin-left:7px;padding:1px 6px;font-size:10px;font-weight:700;letter-spacing:.06em;
  color:var(--amber);border:1px solid var(--amber-d);border-radius:9px;
  text-transform:uppercase;
}
/* Empty jump targets for the extra nights a residency card answers for. */
.daymark{display:block;height:0;scroll-margin-top:12px;}

/* ---- the board on a laptop -------------------------------------------- */
/* Kevin's friends are on phones; Kevin triages on a desktop, where the old
   spreadsheet fitted a month on one screen and this board fitted eight shows.
   Nothing below changes the phone. Above 900px the column stops being 560px
   wide and every card turns into one spreadsheet row: date, venue, bill, who,
   and the three buttons, in fixed columns that line up down the page so the
   eye can run down any one of them. */
@media (min-width:900px) {
  #app.wide{max-width:1140px;}

  #app.wide .card{
    display:grid;
    /* Fixed first and last columns are what makes this scannable: the dates
       line up, the buttons line up, and only the two middle columns flex. */
    /* 176px, not 152: "SAT SEP 26 · 10:30 PM" is 21 mono characters with
       letter-spacing on top, and at 152 every 10-o'clock show wrapped to two
       lines and grew its row. */
    grid-template-columns:176px 164px minmax(0,1.1fr) minmax(0,1.2fr) 214px;
    grid-template-areas:
      "date venue title who acts"
      "date venue badge who acts"
      "note note  note  note acts";
    align-items:center;
    column-gap:13px;row-gap:0;
    padding:5px 10px;margin-bottom:4px;
  }
  /* .when stops being a box and hands its three children straight to the grid.
     The dot between them is doing a job only an inline row needs. */
  #app.wide .card .when{display:contents;}
  #app.wide .card .when .wsep{display:none;}
  #app.wide .card .dt{
    grid-area:date;white-space:normal;line-height:1.35;align-self:center;
    letter-spacing:.05em;
  }
  #app.wide .card .when .venue{
    grid-area:venue;align-self:center;
    white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
  }
  #app.wide .card h3{
    grid-area:title;margin:0;font-size:16px;line-height:1.25;align-self:center;
  }
  /* Two lines here, not three: a row is a pointer to the show page and three
     lines of festival bill would set the height of the whole line. */
  #app.wide .card h3 a{-webkit-line-clamp:2;}
  #app.wide .card .cardbadges{grid-area:badge;margin:2px 0 0;}
  #app.wide .card .who{grid-area:who;margin:0;align-self:center;}
  #app.wide .card .sheetnote{grid-area:note;margin:3px 0 0;}
  #app.wide .card .votebar{grid-area:acts;margin:0;align-self:center;}
  #app.wide .card .votebar>*{min-height:30px;}
  /* The X was floating inside the date line, which a grid card has no room for.
     Back to the corner, out of the columns entirely. */
  #app.wide .card .unboard{
    position:absolute;top:2px;right:2px;float:none;margin:0;
    width:20px;min-height:20px;line-height:18px;font-size:11px;opacity:.55;
  }
  #app.wide .card .unboard:hover{opacity:1;}
  #app.wide .card{padding-right:24px;}
  /* Rows this tight need a line between them more than they need a box around
     each one — a 2px border per row was 100px of border down a full board. */
  #app.wide .card{
    border-width:0 0 1px 0;border-color:rgba(122,134,196,.22);
    background:rgba(16,21,52,.55);margin-bottom:0;
  }
  #app.wide .card:hover{background:rgba(26,33,74,.75);}
  #app.wide .card.pinned{border-left:3px solid var(--amber-d);padding-left:8px;}
  #app.wide .card.review{border-left:3px solid var(--line);}
  /* The month heading keeps its own air; the rows under it have none to spare. */
  #app.wide h2.month{margin:18px 0 2px;}
  #app.wide h2.month:first-child{margin-top:0;}
}
/* Narrow laptops and landscape tablets: the same rows, minus the venue column,
   which is the one piece the show page repeats anyway. */
@media (min-width:900px) and (max-width:1060px) {
  #app.wide .card{
    grid-template-columns:150px minmax(0,1.15fr) minmax(0,1.2fr) 200px;
    grid-template-areas:
      "date title who acts"
      "date venue who acts"
      "date badge who acts"
      "note note  note acts";
  }
  #app.wide .card .when .venue{white-space:nowrap;}
}

/* ---- add a show: the search comes first -------------------------------- */
#addq{
  width:100%;font-family:inherit;font-size:16px;   /* 16px or iOS zooms the page */
  padding:11px 12px;color:var(--ink);
  background:rgba(7,8,26,.7);border:2px solid var(--amber-d);border-radius:0;
}
#addq:focus{outline:none;border-color:var(--amber);}
.addsearch{margin:12px 0 18px;}
/* The result and the two buttons under it are one object, so the border goes
   round the pair rather than round the link alone. */
.aresult{
  margin-bottom:8px;border:2px solid var(--line);
  background:rgba(12,16,44,.70);
  -webkit-backdrop-filter:blur(3px);backdrop-filter:blur(3px);
}
.aresult .sresult{border:0;margin:0;background:none;-webkit-backdrop-filter:none;backdrop-filter:none;}
.aresult:hover{border-color:var(--amber-d);}
.aresult .addvote{margin:0;padding:0 8px 8px;gap:6px;}
.aresult .addvote>*{flex:1 1 0;min-height:34px;font-size:13px;}
/* Dealt with. The list stays put — you might be adding three shows — so a row
   you have answered has to stop looking like one you have not. */
.aresult.done{border-color:var(--good);opacity:.72;}
.aresult.done .addvote{display:none;}
.aresult.done .sresult::after{
  content:"on the board";display:inline-block;margin-top:4px;
  font-size:10px;letter-spacing:.09em;text-transform:uppercase;font-weight:700;color:var(--good);
}
/* The typed-in form, folded away under the search. */
.addmanual{border-top:2px solid var(--line);padding-top:10px;margin-top:6px;}
.addmanual>summary{
  cursor:pointer;font-size:13px;font-weight:700;color:var(--amber);
  letter-spacing:.02em;padding:6px 0;
}
.addmanual>summary:hover{color:var(--ink);}
.howfs{border:2px solid var(--line);padding:9px 11px 11px;margin-top:12px;}
.howfs>legend{
  font-size:10px;letter-spacing:.12em;text-transform:uppercase;font-weight:700;
  color:var(--dim);padding:0 5px;
}
.howopt{display:flex;align-items:flex-start;gap:8px;padding:5px 0;font-size:14px;cursor:pointer;}
.howopt input{margin-top:3px;accent-color:var(--amber);}
.howopt b{color:var(--ink);font-weight:700;}
.howopt span{color:var(--dim);}
@media (min-width:900px){
  #app.wide .addsearch,#app.wide .addmanual{max-width:720px;}
}

/* ---- a run's nights, once each ----------------------------------------- */
/* The date leads every row, then what state it is in, then the way in. Eight
   nights read as eight nights instead of eight copies of the same panel. */
.nightix{margin-top:8px;border-top:1px solid rgba(122,134,196,.22);}
.nightrow{
  display:flex;align-items:center;gap:9px;flex-wrap:wrap;
  padding:7px 2px;border-bottom:1px solid rgba(122,134,196,.22);
}
.nwhen{
  flex:0 0 auto;font-family:var(--mono);font-size:11px;letter-spacing:.07em;
  color:#b9c2f0;font-weight:600;text-transform:uppercase;font-variant-numeric:tabular-nums;
}
.nbadge{flex:1 1 auto;min-width:0;}
.nbadge .tbadge{margin:0 4px 0 0;}
.nact{flex:0 0 auto;margin-left:auto;}
.nact .btn{padding:6px 11px;min-height:30px;font-size:12px;}
@media (max-width:430px){
  .nwhen{flex:1 1 100%;}
  .nact{margin-left:0;}
}

/* ---- whose money it was ------------------------------------------------ */
/* A select rather than a name, because the name is the thing most likely to be
   wrong: this group buys for each other and whoever logs it is often not who
   paid. Styled to read as the name it shows until you go near it. */
.buyerpick{
  font-family:inherit;font-size:13px;font-weight:700;color:var(--ink);
  background:transparent;border:0;border-bottom:1px dotted var(--dim);
  padding:1px 2px;margin-right:2px;max-width:11em;
}
.buyerpick:hover,.buyerpick:focus{border-bottom-color:var(--amber);color:var(--amber);outline:none;}
.buyerpick option{background:var(--row);color:var(--ink);}
.pnight{
  margin-left:9px;font-family:var(--mono);font-size:10px;letter-spacing:.07em;
  color:var(--dim);text-transform:uppercase;font-variant-numeric:tabular-nums;
}
.logrow{display:flex;gap:10px;flex-wrap:wrap;margin-top:7px;}
.logrow .f{flex:1 1 170px;margin:0;}
.logrow select{
  width:100%;font-family:inherit;font-size:15px;padding:8px 9px;
  color:var(--ink);background:rgba(7,8,26,.7);border:2px solid var(--line);border-radius:0;
}
.logrow select:focus{outline:none;border-color:var(--amber);}
/* Somebody holding more than one seat on the same batch. The chip says how
   many; tapping it hands one back and the count comes down. */
.seat .seatx{font-family:var(--mono);font-size:11px;opacity:.75;margin-left:2px;}

/* The Me page has no row styles of its own any more: it renders the board's
   cards, which is the point — a ticket should look the same wherever you meet
   it. The .tixrow/.tx* rules that used to live here went with them. */
/* Prose does not want the full width even on a page whose list does. */
@media (min-width:900px){
  #app.wide .lead,#app.wide ul.plain,#app.wide .tok{max-width:720px;}
}

/* ---- the board reads like the ticket list ------------------------------ */
/* Kevin picked the Me page's card out of the two and asked for it here: the
   amber mono date leading, the venue on the same line in the quieter colour,
   and a slightly smaller bill under them. The date was the same blue-grey as
   the venue, which made the line one undifferentiated string — colour is doing
   the job the eye actually wants, which is finding the date first. */
.card .when .dt{color:var(--amber);}
.card h3{font-size:16px;}
@media (min-width:900px){
  /* Date and venue share a column again rather than owning one each. It costs
     nothing in height, it puts them back in the order you read them in, and it
     hands the width to the two columns that were short of it. */
  #app.wide .card{
    grid-template-columns:300px minmax(0,1.15fr) minmax(0,1.15fr) 214px;
    grid-template-areas:
      "when title who acts"
      "when badge who acts"
      "note note  note acts";
  }
  #app.wide .card .when{
    display:block;grid-area:when;align-self:center;
    white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
  }
  #app.wide .card .when .wsep{display:inline;margin:0 5px;}
  #app.wide .card .when .venue{display:inline;}
  /* The date had white-space:normal from back when it owned a narrow column of
     its own and a residency span needed two lines in it. Sharing a line with
     the venue, that is what let "SAT SEP 26 · 2:00 / PM · Under the K Bridge
     Park" break across two rows and grow the row. The line clips now. */
  #app.wide .card .dt{letter-spacing:.06em;white-space:nowrap;}
  #app.wide .card h3{font-size:15px;}
}
/* The narrow-laptop variant loses its separate venue row for the same reason. */
@media (min-width:900px) and (max-width:1060px){
  #app.wide .card{
    grid-template-columns:270px minmax(0,1.2fr) 200px;
    grid-template-areas:
      "when title acts"
      "when who   acts"
      "when badge acts"
      "note note  acts";
  }
  #app.wide .card .who{grid-area:who;margin-top:2px;}
}

/* ---- you: the header row and the two switches -------------------------- */
.youhead{display:flex;align-items:baseline;flex-wrap:wrap;gap:9px;}
.youhead h1{margin-right:2px;}
.btn.tiny{
  padding:4px 9px;min-height:0;font-size:11px;font-weight:700;letter-spacing:.03em;
  align-self:center;
}
/* Checkboxes, not buttons: two independent questions, either or both. A link
   underneath, so the answer is in the URL and survives a reload. */
.switches{display:flex;flex-wrap:wrap;gap:8px;margin:14px 0 4px;}
.chk{
  display:inline-flex;align-items:center;gap:7px;
  font-size:13px;font-weight:600;color:var(--dim);
  border:2px solid var(--line);padding:6px 11px 6px 9px;
  background:rgba(7,8,26,.5);
}
.chk:hover{color:var(--ink);border-color:var(--dim);text-decoration:none;}
.chk .box{
  width:14px;height:14px;flex:0 0 14px;border:2px solid var(--line);
  background:transparent;position:relative;
}
.chk.on{color:var(--amber);border-color:var(--amber-d);}
.chk.on .box{background:var(--amber);border-color:var(--amber);}
.chk.on .box::after{
  content:"";position:absolute;left:3px;top:0;width:4px;height:8px;
  border:solid #231400;border-width:0 2px 2px 0;transform:rotate(45deg);
}

/* ---- who is actually using it ------------------------------------------ */
/* A table, because five numbers per person compared across ten people is what
   a table is for. It scrolls sideways on a phone rather than reflowing into
   cards — Kevin reads this one on a laptop. */
.acttable{margin-top:8px;overflow-x:auto;}
.actrow{
  display:grid;grid-template-columns:minmax(96px,1.1fr) 92px 92px minmax(120px,1fr) 62px;
  align-items:center;gap:10px;padding:6px 8px;min-width:480px;
  border-bottom:1px solid rgba(122,134,196,.22);font-size:12px;color:var(--dim);
}
.acthead{
  font-size:10px;letter-spacing:.1em;text-transform:uppercase;font-weight:700;
  color:var(--dim);border-bottom:2px solid var(--line);
}
.actwho{font-size:14px;font-weight:700;color:var(--ink);}
/* A week without opening it. The row goes red rather than the name, because
   the whole row is the reason you are looking. */
.actrow.cold{color:var(--bad);}
.actrow.cold .actwho{color:var(--bad);}
.actbar{
  position:relative;display:block;height:18px;background:rgba(7,8,26,.6);
  border:1px solid var(--line);
}
.actfill{position:absolute;left:0;top:0;bottom:0;background:var(--amber-d);opacity:.55;}
.actbar b{
  position:relative;display:block;text-align:center;line-height:18px;
  font-family:var(--mono);font-size:10px;color:var(--ink);font-weight:700;
}

/* ======================================================================== */
/* ---- boldness pass -----------------------------------------------------
   Kevin, looking at the after-a-swipe sheet: "a lot of the text is just very
   not distinct."

   He was right, and it was one decision made once and inherited everywhere:
   the base button rule set its label to var(--dim). Dim is the right colour
   for a caption sitting next to something louder — it is the wrong colour for
   the words ON a control, where there is nothing louder to sit next to and the
   word IS the thing. "Already Have Tickets" and "Interested (don't commit
   yet)" were 13px of #8891c4 on #141838, which is about 3.2:1 — under the 4.5
   a body of text wants, in a bar, at night.

   So: labels on controls go to ink and get heavier, and the two structural
   colours come up a step. Nothing here changes a size or a layout; it is the
   same site with the contrast turned up. */

:root{
  /* #8891c4 -> #a6aedd. Still plainly secondary to --ink (#e8ecff), but a
     caption now reads as text rather than as a watermark. */
  --dim:#a6aedd;
  /* Borders were nearly the panel they sat on. This is the "boxes could be
     bolder" half of it. */
  --line:#3b4282;
}

/* The word on a button is the button. */
button,.btn{color:var(--ink);font-weight:700;}
button:hover,.btn:hover{border-color:var(--amber-d);}
/* Except the ones that are deliberately quiet: undo, and anything muted. */
.dbtn.word.undo,.btn.quiet{color:var(--dim);font-weight:600;}

/* Sheet: the three things you came here to choose between. */
.dpacts>*{font-size:14px;letter-spacing:.01em;}
.dptitle{font-weight:800;}
.dpshow{color:var(--ink);font-weight:600;}
/* Section labels inside the sheet and the show page — small caps carrying a
   question, so they need weight rather than size. */
.sub{color:#c2c8ee;font-weight:700;}

/* Night chips are choices, not captions. */
.datechip{color:var(--ink);font-weight:600;}
.datechip:hover{border-color:var(--amber-d);}

/* A name is a person. Nobody on this board should be grey. */
.chip{color:#c9cef0;border-width:2px;}
.seat{color:var(--ink);font-weight:600;}

/* The empty states say the only thing on the screen; they were the faintest. */
.empty{color:var(--dim);}
/* Lead paragraphs carry the explanations — the same argument as the buttons. */
.lead{color:#b6bde6;}
ul.plain{color:#b6bde6;}

/* Form labels and the inputs under them. */
label.f>span{color:#c2c8ee;font-weight:700;}

/* ---- the gauge is a journey -------------------------------------------- */
/* A world at each end, drawn at their native 32px, and the dashed line running
   between them. The old launch pad and star were two small grey shapes doing
   the same job with none of the charm, and the track is tall enough for real
   sprites now that the ships are in it. */
.gworld{
  position:absolute;top:50%;transform:translateY(-50%);
  width:32px;height:32px;
  background-position:center;background-size:32px 32px;background-repeat:no-repeat;
  image-rendering:pixelated;z-index:1;
}
.gworld.from{left:0;}
.gworld.to{right:0;opacity:.85;}
/* Line starts and ends inside the two worlds rather than butting against them. */
.gtrack::after{left:26px;right:26px;}
.gauge.orbit .gworld.to{opacity:1;filter:drop-shadow(0 0 6px rgba(255,212,92,.55));}

/* The count, the ? and Triage on one centre line. */
.glabel{display:flex;align-items:center;gap:9px;flex-wrap:wrap;margin-top:4px;}
.gauge .helpbtn{
  position:static;margin:0;vertical-align:baseline;flex:0 0 auto;
  width:24px;height:24px;font-size:12px;line-height:1;
}
.gaugetab{margin-left:0;vertical-align:baseline;}

/* ---- the stamp you drag towards --------------------------------------- */
/* It is the confirmation that the gesture is working, read out of the corner
   of your eye halfway through a thumb movement. It was 17px. */
.dstamp{
  font-size:26px;font-weight:900;letter-spacing:.02em;
  padding:6px 16px;border-width:4px;background:rgba(7,8,26,.82);
}
@media (max-width:380px){ .dstamp{font-size:22px;padding:5px 12px;} }

/* ---- the explainer now explains the game, not just the gestures --------- */
.exnote{margin-top:8px;}
.exnote p{font-size:14px;line-height:1.5;color:#b6bde6;margin-bottom:9px;}
.exnote p:last-child{margin-bottom:0;}
.exnote b{color:var(--amber);}
/* Two sections now, so it can outgrow a phone screen. */
.exinner{max-height:88vh;overflow-y:auto;-webkit-overflow-scrolling:touch;}

/* ---- the swipe hint stops hiding the show ------------------------------ */
/* This was the real answer to "a lot of the text is very not distinct": the
   hint is an overlay across the whole first card at 86% opacity, so the first
   show anybody sees on this page — the artist, the venue, the date — is read
   through a near-solid black sheet. The gesture is worth teaching; it is not
   worth the card.

   The scrim comes down to a wash, and the words get their own backing instead,
   so the hint is legible because of what is behind the hint rather than what is
   behind the whole card. Bigger and heavier while we are here: they are read
   out of the corner of an eye, mid-thumb. */
.deck.js .dhint{
  background:linear-gradient(rgba(7,8,26,.22), rgba(7,8,26,.62) 42%, rgba(7,8,26,.22));
  gap:14px;
}
.dh{
  font-size:20px;font-weight:800;letter-spacing:.02em;
  background:rgba(7,8,26,.86);border:2px solid var(--line);padding:7px 12px;
  text-transform:none;
}
.dh b{font-size:28px;}
.dh.pass{border-color:var(--bad);}
.dh.in{border-color:var(--good);}
.dhnote{
  font-size:12px;letter-spacing:.02em;text-transform:none;color:var(--ink);font-weight:600;
  background:rgba(7,8,26,.86);border:2px solid var(--line);padding:7px 11px;
  max-width:88%;
}
.dhnote b{color:var(--amber);}
@media (max-width:380px){
  .dh{font-size:17px;padding:6px 10px;}
  .dh b{font-size:24px;}
}
/* The card you are reading is opaque. It was 80%, which let the NEXT card in
   the stack — offset twelve pixels down and still carrying a four-line festival
   bill — show through behind the artist name as grey ghost text. The stack is
   still visible, because card two peeks out at the bottom where it is supposed
   to, rather than through the middle of card one. */
.deck.js .dcard:nth-of-type(1){background:rgba(13,17,45,.985);}

/* ---- waiting for a ticket that does not exist yet ---------------------- */
/* Dashed amber, the same language as SPARE: both mean pending. Green is
   reserved for a ticket that exists, and a waitlist place is precisely not
   one. */
.chip.waiting{
  border-color:var(--amber-d);color:var(--amber);border-style:dashed;
  background:rgba(255,212,92,.08);
}
.waitbar{margin-top:10px;}
.waitrow{
  display:flex;align-items:center;gap:9px;flex-wrap:wrap;
  padding:8px 2px;border-bottom:1px solid rgba(122,134,196,.22);
}
.waitwho{flex:1 1 180px;min-width:0;display:flex;align-items:center;gap:6px;flex-wrap:wrap;}
.waitwho .sub{margin-right:2px;}
.waitbtn,.soldbtn{flex:0 0 auto;padding:6px 10px;font-size:11px;min-height:32px;}
.waitbtn.on{color:var(--amber);border-color:var(--amber-d);border-style:dashed;}
.soldbtn{color:var(--dim);}
.soldbtn.on{color:var(--bad);border-color:var(--bad);}
/* In the sheet, the waitlist button is the quiet option next to Buy Now. */
#dpwait.on{color:var(--amber);border-color:var(--amber-d);border-style:dashed;}

/* ---- badges ride with the bill ----------------------------------------- */
/* They live inside the h3 now, so the heading is the flex row: the title is
   one item and the badges are another. A short name like DIIV keeps them on
   its own line, where there was already empty space; a four-line festival bill
   pushes them underneath, which is the only case that ever wanted a row.

   The title keeps its three-line clamp — that lives on the <a>, which is still
   its own box inside the flex row. */
.card h3{display:flex;flex-wrap:wrap;align-items:baseline;gap:4px 7px;}
.card h3 .cardbadges{
  display:inline-flex;flex-wrap:wrap;gap:4px;margin:0;
  /* Pulled up a touch: the badges are small caps in a 16px heading, and on a
     shared baseline they hang low against the cap height of the title. */
  position:relative;top:-1px;
}
@media (min-width:900px){
  /* No badge row in the grid any more; the title cell carries them. */
  #app.wide .card{
    grid-template-areas:
      "when title who acts"
      "note note  note acts";
  }
  #app.wide .card .cardbadges{grid-area:auto;margin:0;}
}
@media (min-width:900px) and (max-width:1060px){
  #app.wide .card{
    grid-template-areas:
      "when title acts"
      "when who   acts"
      "note note  acts";
  }
}

/* ---- two shows, one night ---------------------------------------------- */
/* Amber, not red: this is not an error and it is not a block. A 7pm show and a
   10:30pm DJ set are a perfectly good evening, and the only person who can
   judge that is the one holding both tickets. It just has to be said BEFORE
   the buying, which is why it sits above the buttons in the sheet rather than
   under them. */
.notice.warn{
  border:2px solid var(--amber-d);background:rgba(255,212,92,.10);
  color:var(--ink);padding:9px 11px;margin:8px 0 0;font-size:13px;line-height:1.45;
}
.notice.warn b{color:var(--amber);}
.dpclash{
  margin-top:10px;padding:8px 10px;font-size:13px;line-height:1.4;
  border:2px solid var(--amber-d);background:rgba(255,212,92,.10);color:var(--ink);
}
.dpclash b{color:var(--amber);font-weight:700;}

/* ---- something is quietly broken --------------------------------------- */
/* Red, full width, above everything including the nav, on every page Kevin
   loads. The preview bar taught the pattern: sticky rather than fixed, so it
   reserves its own space and can wrap to two lines on a phone without covering
   the header. */
.alarmbar{
  position:sticky;top:0;z-index:90;
  display:flex;gap:8px;align-items:baseline;flex-wrap:wrap;
  padding:8px 12px;font-size:12px;line-height:1.4;
  color:#fff;background:var(--red);box-shadow:0 2px 0 rgba(0,0,0,.35);
}
.alarmbar b{font-size:13px;font-weight:800;letter-spacing:.01em;}
.alarmbar span{opacity:.92;}
.alarmbar a{
  margin-left:auto;flex:0 0 auto;color:#fff;font-weight:700;
  border:2px solid rgba(255,255,255,.6);padding:2px 9px;
}
.alarmbar a:hover{background:#fff;color:var(--red);text-decoration:none;border-color:#fff;}
@media (prefers-reduced-motion:no-preference){
  .alarmbar{animation:alarmin .35s ease-out;}
  @keyframes alarmin{from{transform:translateY(-100%);}to{transform:translateY(0);}}
}

/* ---- the machinery, on the admin page ---------------------------------- */
.health{margin-top:8px;}
.hrow{
  display:grid;grid-template-columns:minmax(120px,auto) 92px minmax(0,1fr);
  align-items:baseline;gap:10px;padding:7px 9px;
  border-left:4px solid var(--line);border-bottom:1px solid rgba(122,134,196,.22);
  font-size:12px;color:var(--dim);
}
.hrow.ok{border-left-color:var(--good);}
.hrow.bad{border-left-color:var(--bad);background:rgba(255,93,93,.08);}
.hwhat{font-size:14px;font-weight:700;color:var(--ink);}
.hwhen{font-family:var(--mono);font-size:11px;color:var(--ink);font-variant-numeric:tabular-nums;}
.hrow.bad .hwhen,.hrow.bad .hwhat{color:var(--bad);}
@media (max-width:430px){
  .hrow{grid-template-columns:1fr auto;}
  .hnote{grid-column:1 / -1;}
}

/* ---- what the gauge is for --------------------------------------------- */
/* One line under the rocket. Amber on the bold half so it reads as the
   objective rather than as more instructions, and small enough that it never
   competes with the card below it. */
.gaim{
  margin:3px 0 0;font-size:12px;line-height:1.4;color:var(--dim);
  max-width:46em;
}
.gaim b{color:var(--amber);font-weight:700;}

/* ---- the veto ---------------------------------------------------------- */
/* Down is the one direction that takes a show away from everyone, so the stamp
   is the loudest of the four and the button is the smallest: easy to find on
   purpose, hard to hit by accident — the same bargain the X on a board card
   makes. */
.dstamp.veto{
  left:50%;bottom:16px;top:auto;transform:translateX(-50%) rotate(-3deg);
  color:var(--bad);border-color:var(--bad);
}
.dbtn.veto{
  width:44px;min-width:0;flex:0 0 auto;padding:0;
  font-size:15px;line-height:1;color:var(--bad);border-color:#7a2230;
}
.dbtn.veto:hover{background:var(--bad);color:#2a0007;border-color:var(--bad);}

/* ---- several people want it, nobody has bought -------------------------- */
/* The label counts its own group and goes green; the Buy tag sits on the end
   of the same line, dashed amber like a spare ticket, because it is the same
   kind of thing — something going that nobody has taken. */
.wholab.hot{color:var(--good);}
.chip.buy{
  border-color:var(--amber);color:var(--amber);border-style:dashed;
  font-weight:700;white-space:nowrap;
}
.chip.buy:hover{
  background:var(--amber);color:#231400;border-color:var(--amber);
  border-style:solid;text-decoration:none;
}
/* The bill is the thing you are reading; one size up on both layouts. */
.card h3{font-size:17px;}
@media (min-width:900px){ #app.wide .card h3{font-size:16px;} }


/* Kevin's Shortlist button fades while the card on top is already shortlisted —
   the up-swipe does nothing there, and a button that looks live and does
   nothing is how Hans's fifteen yeses went missing. */
#deck:has(> .dcard:first-of-type:not([data-status0="wildcard"])) ~ .dbar .dbtn.board[data-board]{
  opacity:.3;
}
.exveto{color:var(--bad);}

/* Admin roster: the one button on that row that cannot be taken back. */
button.danger{border-color:var(--bad);color:var(--bad);}

/* ---- desktop names line, and rows with no buttons ---------------------- */
@media (min-width:900px){
  /* Each label travels with its own names as one group, and the groups wrap
     as units. Inline text flow let a line break anywhere — Shannon alone on a
     second line, "Edit tickets" orphaned, SPARE indented by a stray margin —
     and the rows stopped lining up with each other. */
  #app.wide .card .who{display:flex;flex-direction:row;flex-wrap:wrap;align-items:center;
                       justify-content:flex-start;justify-self:stretch;gap:5px 14px;}
  #app.wide .card .who wbr{display:none;}   /* break points are the gaps now */
  #app.wide .card .whorow{display:inline-flex;flex-wrap:wrap;align-items:center;gap:4px;line-height:normal;}
  #app.wide .card .whorow .wholab,
  #app.wide .card .whorow:first-child .wholab{margin:0 3px 0 0;padding-top:0;}
  #app.wide .card .whorow .chip{margin-right:0;}
  #app.wide .card .who .tixedit{margin-left:0;}

  /* The Me page and the archive have no vote buttons, and were still paying
     for a 214px column to hold them — the names got 266px of a 1,140px row. */
  #app.wide .card.noacts{
    grid-template-columns:300px minmax(0,1fr) minmax(0,1.5fr);
    grid-template-areas:
      "when title who"
      "note note  note";
  }
}
@media (min-width:900px) and (max-width:1060px){
  #app.wide .card.noacts{
    grid-template-columns:270px minmax(0,1fr);
    grid-template-areas:
      "when title"
      "when who"
      "note note";
  }
}
/* The two buttons beside your name are the same kind of control as the two
   switches under it, so they are the same size. */
.youhead .btn.tiny{padding:6px 11px;font-size:13px;font-weight:600;min-height:36px;display:inline-flex;align-items:center;}
@media (min-width:1061px){
  /* Names now wrap as whole groups, which needs a little more room per line
     than loose inline text did; titles clamp at two lines and can spare it. */
  #app.wide .card:not(.noacts){grid-template-columns:300px minmax(0,.95fr) minmax(0,1.35fr) 214px;}
}

/* ---- the night planner: LCD Soundsystem only (lib/plan.php) ------------ */
/* One row per night: the label, four rating buttons, then who said what. */
.pnight{padding:9px 0 10px;border-bottom:1px solid rgba(122,134,196,.22);}
.pnight .plabel{font-weight:700;font-size:14px;letter-spacing:.02em;color:var(--ink);}
.pnight .who{margin-top:7px;}
.plevels{display:grid;grid-template-columns:repeat(4,1fr);gap:5px;margin-top:7px;}
.plevels:has(.plv.in){grid-template-columns:auto repeat(4,1fr);}
.plv{
  min-height:34px;padding:5px 4px;font-size:12px;font-weight:700;letter-spacing:.02em;
  background:var(--panel);color:var(--dim);border:2px solid var(--line);border-radius:0;cursor:pointer;
}
.plv.lb.on{border-color:var(--bad);color:var(--bad);}
.plv.l1.on{border-color:var(--ink);color:var(--ink);}
.plv.l2.on{border-color:var(--amber-d);color:var(--amber);}
.plv.l3.on{border-color:var(--amber);background:var(--amber);color:#1a1300;}
.plv.in{display:inline-flex;align-items:center;justify-content:center;padding:5px 10px;
  background:var(--good);border-color:var(--good);color:#06210e;cursor:default;}
/* Rating chips: the more someone wants the night, the louder their name. */
.chip.lv3{background:var(--amber);border-color:var(--amber);color:#1a1300;}
.chip.lv2{border-color:var(--amber-d);color:var(--amber);}
.chip.lv1{border-style:dashed;}

.rushplan{margin:6px 0 4px;padding-left:22px;}
.rushplan li{padding:6px 0;border-bottom:1px solid rgba(122,134,196,.18);}
.rushplan li.alt{opacity:.7;}
.rushplan b{color:var(--ink);}
.rushn{margin-left:8px;font-size:11px;font-weight:700;letter-spacing:.05em;text-transform:uppercase;
  color:#1a1300;background:var(--amber);padding:1px 6px;}
.rushwho{display:block;font-size:13px;margin-top:2px;}

.plansum{margin-top:6px;font-size:13px;color:var(--dim);}
.planbar{margin-top:6px;}
@media (min-width:900px){
  #app.wide .card .plansum{grid-area:who;margin:0;align-self:center;}
  #app.wide .card .planbar{grid-area:acts;margin:0;align-self:center;}
}

/* The picker sheet Swipe and the List open: every night, scrolling. */
.plansheet{
  position:fixed;inset:0;z-index:60;background:rgba(3,4,14,.72);
  display:flex;align-items:flex-end;justify-content:center;
}
.psbox{
  width:100%;max-width:560px;max-height:88vh;overflow-y:auto;
  background:#0c1030;border:2px solid var(--line);border-bottom:0;padding:12px 14px 18px;
}
.pshead{display:flex;align-items:center;justify-content:space-between;gap:10px;}
.pshead b{font-size:18px;}
.psdone{padding:5px 12px;font-size:12px;min-height:0;}

/* ---- LCD: the date heatmap ---------------------------------------------- */
/* One tile per night. --a is how wanted the night is (0 to .9), so the tile
   goes from bare panel to solid amber; past halfway the text flips dark. */
.heat{display:grid;grid-template-columns:repeat(auto-fill,minmax(78px,1fr));gap:5px;margin:8px 0 6px;}
.htile{
  --a:0;position:relative;display:flex;flex-direction:column;align-items:flex-start;
  min-height:92px;padding:6px 7px;text-decoration:none;color:var(--ink);
  background:linear-gradient(rgba(255,212,92,var(--a)),rgba(255,212,92,var(--a))),var(--panel);
  border:2px solid rgba(255,212,92,calc(var(--a) + .12));
}
.htile:hover{text-decoration:none;border-color:var(--amber);}
.htile.hot{color:#1a1300;}
.hdow{font-size:10px;font-weight:700;letter-spacing:.1em;opacity:.8;}
.hmd{font-size:14px;font-weight:800;letter-spacing:.02em;white-space:nowrap;}
.hroom{font-size:10px;letter-spacing:.03em;opacity:.75;white-space:nowrap;}
.hcount{margin-top:auto;font-size:20px;font-weight:800;line-height:1;}
.hcount small{font-size:11px;font-weight:700;margin-left:2px;opacity:.75;}
.hbuy{
  position:absolute;right:5px;bottom:6px;white-space:nowrap;
  font-size:10px;font-weight:800;letter-spacing:.06em;text-transform:uppercase;
  padding:1px 5px;background:#1a1300;color:var(--amber);
}
.htile:not(.hot) .hbuy{background:var(--amber);color:#1a1300;}
.pnight{scroll-margin-top:70px;}
#planner > h2.month:first-child{margin-top:22px;}

/* ---- heatmap tile footer: count left, BUY right, one row --------------- */
.htile .hfoot{margin-top:auto;width:100%;display:flex;align-items:flex-end;justify-content:space-between;gap:4px;}
.htile .hcount{margin-top:0;white-space:nowrap;}
.htile .hbuy{position:static;flex:none;}

/* ---- LCD on the List: the two buttons side by side, row height normal --- */
.planbar{display:grid;grid-template-columns:1fr auto;gap:6px;}
.planbar > *{min-height:30px;padding-top:4px;padding-bottom:4px;display:flex;align-items:center;justify-content:center;}
#app.wide .card.planner .plansum{line-height:1.45;}

/* ---- LCD on the List: the highlight of the year ------------------------
   A slowly turning rainbow border, mirror-ball light spots drifting across
   the card, and a shimmer on the name. All of it stops for anyone who asked
   their phone for less motion. */
@property --disco{syntax:'<angle>';initial-value:0deg;inherits:false;}
#app .card.planner,
#app.wide .card.planner{
  position:relative;overflow:hidden;isolation:isolate;
  border:2px solid transparent;
  margin:6px 0;
  background:
    linear-gradient(rgba(20,12,46,.94),rgba(20,12,46,.94)) padding-box,
    conic-gradient(from var(--disco),#ff4fd8,#ffd45c,#5cf2ff,#8a5cff,#ff4fd8) border-box;
  box-shadow:0 0 22px rgba(255,79,216,.28),0 0 44px rgba(92,242,255,.12);
  animation:discospin 7s linear infinite;
}
#app.wide .card.planner:hover{
  background:
    linear-gradient(rgba(30,18,64,.94),rgba(30,18,64,.94)) padding-box,
    conic-gradient(from var(--disco),#ff4fd8,#ffd45c,#5cf2ff,#8a5cff,#ff4fd8) border-box;
}
@keyframes discospin{to{--disco:360deg;}}
/* The mirror ball: a scatter of soft coloured spots, drifting. */
.card.planner::after{
  content:'';position:absolute;inset:-40%;z-index:-1;pointer-events:none;
  background:
    radial-gradient(circle at 10% 30%,rgba(255,79,216,.35) 0 3px,transparent 4px),
    radial-gradient(circle at 30% 70%,rgba(92,242,255,.35) 0 2px,transparent 3px),
    radial-gradient(circle at 55% 20%,rgba(255,212,92,.40) 0 3px,transparent 4px),
    radial-gradient(circle at 75% 60%,rgba(138,92,255,.35) 0 2px,transparent 3px),
    radial-gradient(circle at 90% 35%,rgba(255,255,255,.30) 0 2px,transparent 3px),
    radial-gradient(circle at 45% 85%,rgba(255,79,216,.30) 0 2px,transparent 3px);
  background-size:180px 120px;
  animation:discodrift 14s linear infinite;
}
@keyframes discodrift{to{transform:translate(180px,60px);}}
.card.planner h3 a{
  background:linear-gradient(90deg,#fff 0%,#ffd45c 25%,#ff4fd8 50%,#5cf2ff 75%,#fff 100%);
  background-size:200% 100%;
  -webkit-background-clip:text;background-clip:text;color:transparent;
  animation:discoshine 5s linear infinite;
}
@keyframes discoshine{to{background-position:-200% 0;}}
@media (prefers-reduced-motion:reduce){
  .card.planner,.card.planner::after,.card.planner h3 a{animation:none;}
}

/* Sweep mode skips a row once it is fully above the screen, which the last
   screenful of a list can never be — the page ends first — so every session
   left its last eight or ten shows untriaged, waiting for next time. A
   screen of runway after the list lets the last row scroll past too. */
.trows.sweep{padding-bottom:100vh;}

/* Heatmap: tickets in hand for the night — green, like every ticket on the site. */
.htix{
  margin-top:3px;align-self:flex-start;white-space:nowrap;
  font-size:11px;font-weight:800;line-height:1.2;padding:1px 5px;
  background:var(--good);color:#06210e;
}

/* LCD night rows: the label on the left, its box office link on the right. */
.pnight .phead{display:flex;align-items:center;justify-content:space-between;gap:10px;}
.pnight .pacts{display:flex;align-items:center;gap:6px;flex:none;}
.ptix{
  font-size:12px;font-weight:800;letter-spacing:.03em;white-space:nowrap;text-decoration:none;
  padding:4px 9px;background:var(--amber);color:#1a1300;border:2px solid var(--amber);
}
.ptix:hover{text-decoration:none;background:transparent;color:var(--amber);}
.pcal{font-size:18px;line-height:1;text-decoration:none;}

/* Heatmap, take two: three solid steps by head count instead of a blend.
   s0 nobody · s1 one person · s2 two or three · s4 four or more. Solid
   colours keep every label readable; the blend made muddy tans. */
.htile{background:var(--panel);border-color:var(--line);color:var(--ink);}
.htile.s1{border-color:var(--amber);}
.htile.s2{background:#b8913a;border-color:#b8913a;color:#1a1300;}
.htile.s3{background:var(--amber);border-color:var(--amber);color:#1a1300;}
.htile .hbuy{background:var(--amber);color:#1a1300;}
.htile.s2 .hbuy,.htile.s3 .hbuy{background:#1a1300;color:var(--amber);}
.htile.s2 .hroom,.htile.s3 .hroom,.htile.s2 .hdow,.htile.s3 .hdow{opacity:.8;}
.htix{text-transform:uppercase;letter-spacing:.05em;}

/* LCD night rows: the name lines were touching. Slimmer tags, a little air. */
.pnight .who{display:flex;flex-direction:column;gap:8px;margin-top:9px;}
.pnight .whorow{display:flex;flex-wrap:wrap;align-items:center;gap:5px;line-height:1.2;}
.pnight .chip{padding:2px 9px;line-height:1.3;}
.chip.tix.guest{border-style:dashed;border-color:#2f8f4a;background:rgba(94,220,130,.18);color:var(--good);}
.pnight .who wbr{display:none;}
