/* Showbound — shared app styles. Tokens from marquee-identity.html, verbatim. */
:root{
  --house:#1E1236; --stage:#2A1A47; --stage2:#382458; --line:#4C3372;
  --gold:#F2B93C; --gold-dim:#B98D2B; --gold-text:#F2B93C;
  --plum:#C084FC; --green:#3DDC84; --ink:#F3ECF7; --muted:#B3A0CC;
  --magenta:#FF5CA8; --radius:18px;
}
*{box-sizing:border-box;margin:0;padding:0;-webkit-tap-highlight-color:transparent}
[hidden]{display:none !important}
body{background:var(--house);color:var(--ink);font-family:'Inter',sans-serif;font-size:15px;
  line-height:1.5;max-width:430px;margin:0 auto;padding:0 0 92px}
/* All hyperlinks use the house gold in both themes — the browser default
   blue/purple is unreadable on the dark stage, and purple-visited worse. */
a{color:var(--gold)}
a:visited{color:var(--gold)}
.mono{font-family:'JetBrains Mono',monospace}

/* ===== app bar ===== */
.appbar{position:sticky;top:0;z-index:20;background:var(--house);
  display:flex;align-items:center;justify-content:space-between;padding:14px 16px 8px}
.brandmark{display:flex;align-items:center;gap:12px}
.logo{font-family:'Bricolage Grotesque';font-weight:800;font-size:22px;letter-spacing:.4px}
.brandmark .logo{font-size:28px;letter-spacing:6px;margin-right:-6px}
.logo .q{color:var(--magenta)}
.avatar{position:relative;width:34px;height:34px;border-radius:50%;background:var(--stage2);
  border:1.5px solid var(--gold-dim);display:grid;place-items:center;
  padding:0;cursor:pointer;font:inherit;color:inherit}
/* 44px touch target around the 34px visual */
.avatar::after{content:'';position:absolute;inset:-5px}
.avatar:active{transform:scale(.94)}
@keyframes sweep{to{transform:rotate(360deg)}}
.sweep{transform-origin:32px 32px;animation:sweep 4s linear infinite}
@keyframes ping{0%{opacity:.12}1%{opacity:1}9%{opacity:1}45%{opacity:.12}100%{opacity:.12}}
.blip{animation:ping 4s linear infinite}

/* ===== panes ===== */
.pane{display:none;padding:6px 14px 20px}
.pane.active{display:block}
.buildnote{font-family:'JetBrains Mono',monospace;font-size:10px;letter-spacing:.12em;
  color:var(--muted);text-align:center;margin-top:24px}

/* ===== cards, chips, buttons ===== */
.card{background:var(--stage);border:1px solid var(--line);border-radius:var(--radius);
  padding:15px;margin-bottom:11px}
/* Discover cards sit on a darker, heavier surface than the page so they read
   as objects instead of melting into the background at the top of the feed. */
.card.discover{background:#241539;border-color:#56397F;
  box-shadow:0 10px 26px -14px rgba(0,0,0,.65),inset 0 1px 0 rgba(255,255,255,.05)}
[data-theme="light"] .card.discover{background:#F1E7FA;border-color:#D8C4EC;
  box-shadow:0 12px 26px -16px rgba(64,32,104,.4),inset 0 1px 0 rgba(255,255,255,.6)}
.card.status{display:flex;align-items:center;gap:13px;padding:12px 14px}
.card[role="link"]:focus-visible{outline:3px solid var(--gold);outline-offset:2px}
.card.status b{font-size:13.5px;font-weight:600;display:block}
.statusline{font-size:10.5px;color:var(--muted);margin-top:3px;text-wrap:balance}
.artist{font-family:'Bricolage Grotesque';font-weight:800;font-size:19px;line-height:1.15}
.venue{color:var(--muted);font-size:13px;margin-top:3px}
.row{display:flex;align-items:center;justify-content:space-between;margin-top:12px;gap:8px}
.chip{font-family:'JetBrains Mono',monospace;font-size:10.5px;padding:5px 9px;border-radius:999px;
  border:1px solid var(--line);color:var(--muted)}
.btn{display:inline-block;font-family:'JetBrains Mono',monospace;font-size:11.5px;font-weight:700;
  color:#241505;background:var(--gold);padding:9px 14px;border-radius:10px;border:none;cursor:pointer}
.btn.ghost{background:transparent;color:var(--gold-text);border:1px solid var(--gold-dim)}
.btn.sm{padding:7px 11px;font-size:10.5px}
.btn.subtle{background:transparent;color:var(--muted);border:none;font-size:10px;padding:6px 8px}
.btn.subtle.danger{color:#e0705f}
.btn.danger-solid{background:#a83a2e;border-color:#a83a2e;color:#fff}
.btn:disabled{opacity:.35;cursor:default;box-shadow:none}

/* One-shot toast for confirmations (report-broken-link, etc.). */
#marqueeToast{position:fixed;left:50%;bottom:76px;transform:translateX(-50%) translateY(8px);
  background:var(--stage);border:1px solid var(--gold-dim);color:var(--ink);
  font-size:12.5px;padding:10px 16px;border-radius:12px;opacity:0;pointer-events:none;
  transition:opacity .18s ease,transform .18s ease;z-index:200;max-width:88vw;text-align:center}
#marqueeToast.on{opacity:1;transform:translateX(-50%) translateY(0)}

/* ===== Markie moments / empty states ===== */
.moment{background:var(--stage);border:1px solid var(--line);border-radius:var(--radius);
  padding:14px;margin-bottom:12px}
.moment.empty{display:flex;flex-direction:column;align-items:center;text-align:center;
  padding:26px 18px;gap:6px}
.moment.empty b{font-family:'Bricolage Grotesque';font-weight:800;font-size:17px}
.moment.empty p{color:var(--muted);font-size:13.5px;max-width:260px}
.moment.empty .btn{margin-top:8px}

/* ===== artists tab ===== */
.hintbar{font-family:'JetBrains Mono',monospace;font-size:10px;letter-spacing:.06em;
  color:var(--gold-dim);border:1px dashed var(--gold-dim);border-radius:10px;
  padding:9px 12px;margin-bottom:12px;text-align:center}
.addbox{display:flex;gap:8px;margin-bottom:14px}
.addbox input{width:100%;background:var(--stage);border:1px solid var(--line);border-radius:10px;
  color:var(--ink);font-family:'Inter';font-size:14px;padding:11px 12px}
.addbox input:focus{outline:2px solid var(--gold-dim);outline-offset:1px}
.suggest{position:absolute;left:0;right:0;top:100%;z-index:15;background:var(--stage2);
  border:1px solid var(--line);border-radius:12px;overflow:hidden;display:none;margin-top:4px}
.suggest.open{display:block}
.sug-item{padding:11px 12px;font-size:14px;cursor:pointer;border-bottom:1px solid var(--line);
  display:flex;justify-content:space-between;align-items:center;gap:8px}
.sug-item:last-child{border-bottom:none}
.sug-item:active{background:var(--stage)}
.sug-item .sub{font-family:'JetBrains Mono',monospace;font-size:10px;color:var(--muted);
  flex:none;text-align:right}
.sug-item.trackanyway{color:var(--gold)}
.sug-item.none{cursor:default;color:var(--muted)}
.sug-item.none:active{background:none}
.artist-row{display:flex;align-items:center;justify-content:space-between;gap:10px}
.srcbadges{display:flex;gap:5px;margin-top:7px;flex-wrap:wrap}
.srcbadge{font-family:'JetBrains Mono',monospace;font-size:9.5px;padding:3px 7px;border-radius:6px;
  border:1px solid var(--line);color:var(--muted)}
.srcbadge.ok{color:var(--gold-text);border-color:var(--gold-dim)}
.artist-actions{display:flex;align-items:center;gap:4px;flex:none}

/* toggle */
.tgl{width:44px;height:26px;border-radius:999px;background:var(--stage2);border:1px solid var(--line);
  position:relative;cursor:pointer;flex:none;transition:background .15s}
.tgl::after{content:'';position:absolute;top:2px;left:2px;width:20px;height:20px;border-radius:50%;
  background:var(--muted);transition:all .15s}
.tgl.on{background:var(--gold)}
.tgl.on::after{left:20px;background:#241505}

/* ===== tab bar ===== */
.tabbar{position:fixed;bottom:0;left:50%;transform:translateX(-50%);width:100%;max-width:430px;
  background:var(--house);border-top:1px solid var(--line);
  display:flex;justify-content:space-around;padding:10px 2px calc(10px + env(safe-area-inset-bottom));z-index:30}
.tab{display:flex;flex-direction:column;align-items:center;gap:4px;color:var(--muted);
  font-size:9.5px;font-family:'JetBrains Mono',monospace;letter-spacing:.02em;cursor:pointer;
  border:none;background:none}
.tab svg{width:21px;height:21px}
.tab.active{color:var(--gold-text)}
/* The count of claims waiting on you. Magenta, not gold: gold is reserved for
   "near you" and this is not a proximity signal. Positioned on the tab rather
   than the icon so it survives the icon being swapped. */
.tab{position:relative}
.tab-badge{position:absolute;top:-3px;right:calc(50% - 20px);min-width:16px;height:16px;
  padding:0 4px;border-radius:999px;background:var(--magenta);color:#1A0B14;
  font-size:9.5px;line-height:16px;font-weight:700;text-align:center}

@media (prefers-reduced-motion:reduce){.sweep,.blip{animation:none!important}.blip{opacity:1}}

/* ===== settings: watch areas (step 4) ===== */
.set-group{margin-bottom:20px}
.set-head{font-family:"JetBrains Mono",monospace;font-size:11px;letter-spacing:.16em;color:var(--gold-text);
  text-transform:uppercase;margin:0 2px 10px}
.set-row{display:flex;align-items:center;justify-content:space-between;gap:10px;
  background:var(--stage);border:1px solid var(--line);border-radius:14px;padding:12px 14px;margin-bottom:8px}
.set-row .t{font-size:14px;font-weight:500}
.set-row .t.nowrap{white-space:nowrap}
.nowrap{white-space:nowrap}
/* Standalone caption under a settings page's controls. */
.page-note{font-size:11.5px;color:var(--muted);font-family:'JetBrains Mono',monospace;
  margin-top:12px;line-height:1.55}
.set-row .s{font-size:11.5px;color:var(--muted);font-family:"JetBrains Mono",monospace;margin-top:2px}
.set-row.disabled{opacity:.45}
.diag-out{font-family:'JetBrains Mono',monospace;font-size:11px;line-height:1.45;color:var(--ink);
  background:var(--stage2);border:1px solid var(--line);border-radius:12px;padding:10px 12px;margin:0 0 12px;
  white-space:pre-wrap;overflow-wrap:anywhere;max-height:55vh;overflow:auto;user-select:text;-webkit-user-select:text}
.set-row.disabled .tgl{cursor:not-allowed}
.addarea{display:flex;gap:8px;align-items:center;margin-top:4px}
.addarea input{width:100%;background:var(--stage);border:1px solid var(--line);border-radius:10px;
  color:var(--ink);font-size:14px;padding:10px 12px}
.areaform{background:var(--stage);border:1px solid var(--gold-dim);border-radius:14px;
  padding:13px;margin-top:10px}
.areaform input[type=text]{width:100%;background:var(--house);border:1px solid var(--line);
  border-radius:10px;color:var(--ink);font-size:14px;padding:10px 12px;margin-bottom:10px}
.radius-row{display:flex;flex-direction:column;gap:4px}
.radius-label{font-family:"JetBrains Mono",monospace;font-size:11px;color:var(--muted)}
.slider{width:100%;accent-color:var(--gold)}

/* ===== upcoming event cards ===== */
.chip.date{color:var(--ink);border-color:#4A3E29}
.chip.onsale{color:#241505;background:var(--gold);border-color:var(--gold);font-weight:700}
.chip.presale{color:#F0E4FF;background:rgba(155,95,208,.18);border-color:var(--plum)}
.meta{display:flex;gap:6px;flex-wrap:wrap}
.price{font-family:"JetBrains Mono",monospace;font-weight:700;font-size:16px;color:var(--gold-text)}
.price small{color:var(--muted);font-weight:500;font-size:10.5px;display:block;text-align:right}

/* ===== artist images ===== */
.thumb{width:42px;height:42px;border-radius:12px;object-fit:cover;flex:none;
  border:1px solid var(--line);background:var(--stage2)}
.thumb.lg{width:50px;height:50px;border-radius:14px}
.thumb.sm{width:30px;height:30px;border-radius:9px}
.thumb.ph{display:grid;place-items:center;font-family:"Bricolage Grotesque";font-weight:800;
  font-size:18px;color:var(--gold-dim)}

/* ===== discover (step 7) ===== */
.date-filter-wrap{position:relative;display:flex;gap:6px;margin:0 0 12px;z-index:10}
.date-filter-btn{flex:1;display:flex;align-items:center;justify-content:space-between;gap:10px;
  min-height:40px;padding:9px 12px;border-radius:10px;border:1px solid var(--line);
  background:var(--stage);color:var(--ink);font-family:"JetBrains Mono",monospace;
  font-size:11px;letter-spacing:.06em;cursor:pointer;text-align:left}
.date-filter-btn[aria-expanded="true"]{border-color:var(--gold-dim);color:var(--gold-text)}
.date-filter-btn span:first-child{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.date-filter-clear{width:40px;min-height:40px;border-radius:10px;border:1px solid var(--line);
  background:var(--stage);color:var(--gold-text);font-size:20px;line-height:1;cursor:pointer}
.date-popover{position:absolute;top:calc(100% + 6px);left:0;right:0;padding:12px;
  background:var(--stage2);border:1px solid var(--gold-dim);border-radius:14px;
  box-shadow:0 18px 48px rgba(0,0,0,.42);z-index:40}
.date-quick-actions{display:flex;gap:6px;margin-bottom:8px}
.date-quick-actions .btn{flex:1;white-space:nowrap}
.date-popover .cal.compact{margin:0;padding:8px;background:transparent;border:0}
.date-popover .cal-day{padding:7px 0 12px}
@media(max-width:600px){
  .date-popover{position:fixed;top:auto;left:0;right:0;bottom:0;width:100%;
    padding:14px 14px calc(16px + env(safe-area-inset-bottom));border-radius:18px 18px 0 0;
    max-height:76vh;overflow:auto}
}
.search{background:var(--stage);border:1px solid var(--line);border-radius:var(--radius);
  padding:13px;margin-bottom:14px}
.search input{width:100%;background:var(--house);border:1px solid var(--line);border-radius:10px;
  color:var(--ink);font-family:"Inter";font-size:14px;padding:10px 12px;margin-bottom:8px;
  color-scheme:dark}
.search .split{display:flex;gap:8px}
.search .split input{margin-bottom:0}
.search .actions{display:flex;justify-content:space-between;align-items:center;margin-top:10px}
.dayhead{font-family:"JetBrains Mono",monospace;font-size:10px;letter-spacing:.2em;color:var(--gold-text);
  text-transform:uppercase;margin:16px 2px 8px}
.localtag{font-size:10.5px;color:var(--muted);font-family:"JetBrains Mono",monospace;margin-top:8px}
.chip.star{color:var(--gold-text);border-color:var(--gold-dim);font-size:9.5px;vertical-align:middle}
.chip.owner{color:#241505;background:var(--gold);border-color:var(--gold);font-weight:700;font-size:9.5px;vertical-align:middle}
.scanwrap{display:flex;flex-direction:column;align-items:center;gap:12px;padding:28px 0}
.scanlabel{font-family:"JetBrains Mono",monospace;font-size:11px;color:var(--muted);letter-spacing:.08em}
@keyframes ringk{0%{transform:scale(.3);opacity:0}1%{transform:scale(.4);opacity:.9}
  20%{transform:scale(2.1);opacity:0}100%{transform:scale(2.1);opacity:0}}
.ring{transform-box:fill-box;transform-origin:center;animation:ringk 4s linear infinite}
.d2{animation-delay:-2.7s}.d3{animation-delay:-1.53s}

/* calendar */
.cal{background:var(--stage);border:1px solid var(--line);border-radius:var(--radius);
  padding:14px;margin-bottom:12px}
.cal-head{display:flex;justify-content:space-between;align-items:center;margin-bottom:12px}
.cal-head .m{font-family:"Bricolage Grotesque";font-weight:800;font-size:17px}
.cal-head button{background:none;border:1px solid var(--line);border-radius:8px;color:var(--gold-text);
  font-size:15px;padding:4px 11px;cursor:pointer}
.cal-grid{display:grid;grid-template-columns:repeat(7,1fr);gap:4px;text-align:center}
.cal-dow{font-family:"JetBrains Mono",monospace;font-size:9px;color:var(--muted);padding:4px 0;letter-spacing:.06em}
.cal-day{position:relative;padding:9px 0 14px;border:0;border-radius:10px;background:transparent;
  font:inherit;font-size:13.5px;cursor:pointer;color:var(--ink)}
.cal-day:focus-visible{outline:2px solid var(--gold);outline-offset:1px}
.cal-day.blank{cursor:default}
.cal-day.dim{color:#5A5044}
.cal-day.today{border:1px solid var(--gold-dim)}
.cal-day.sel{background:var(--gold);color:#241505;font-weight:700}
.cal-day .dot{position:absolute;bottom:5px;left:50%;transform:translateX(-50%);
  width:5px;height:5px;border-radius:50%;background:var(--gold)}
.cal-day .trk{position:absolute;bottom:3px;left:50%;transform:translateX(-50%);
  font-size:8px;color:var(--gold-text);line-height:1}
.cal-day.sel .dot{background:#241505}
.cal-day.sel .trk{color:#241505}
.cal-legend{display:flex;gap:14px;margin-top:10px;font-family:"JetBrains Mono",monospace;
  font-size:9.5px;color:var(--muted)}
.scopebar{display:flex;align-items:center;justify-content:space-between;gap:8px;
  margin:0 2px 10px;min-height:22px}
.scopebar .mono{font-size:10px;letter-spacing:.1em;color:var(--muted)}
.scopebar .btn.subtle{color:var(--gold-text);font-size:10px;padding:4px 6px}

/* The offline notice. Deliberately muted and un-glowing: gold means "near you",
   and a lost connection is not a show. Hidden entirely until body.offline. */
.offline-note{display:none}
body.offline .offline-note:not([hidden]){display:flex;flex-direction:column;gap:2px;
  background:var(--surf-sunk);border:1px solid var(--line);border-radius:12px;
  padding:9px 12px;margin:0 2px 10px;color:var(--muted);font-size:12.5px}
body.offline .offline-note:not([hidden]) .mono{font-family:"JetBrains Mono",monospace;
  font-size:9.5px;letter-spacing:.1em;color:var(--ink)}

/* ===== stubs (step 9) ===== */
.prompt{background:var(--stage);border:1px solid var(--gold-dim);border-radius:var(--radius);
  padding:14px;margin-bottom:14px;display:flex;gap:12px;align-items:flex-start}
.prompt b{display:block;font-size:14px;margin-bottom:2px}
.prompt p{color:var(--muted);font-size:13px}
.prompt .acts{display:flex;gap:8px;margin-top:10px}
.statrow{display:flex;gap:8px;margin-bottom:14px}
.stat{flex:1;background:var(--stage);border:1px solid var(--line);border-radius:14px;
  padding:10px;text-align:center}
.stat .n{font-family:"JetBrains Mono",monospace;font-weight:700;font-size:18px;color:var(--gold-text)}
.stat .l{font-size:10px;color:var(--muted);font-family:"JetBrains Mono",monospace;letter-spacing:.06em}
/* The tiles are buttons: each opens its ranking. Equal thirds, whatever is inside. */
button.stat{font:inherit;color:inherit;cursor:pointer;display:flex;flex-direction:column;align-items:center;
  gap:0;flex:1 1 0;min-width:0;-webkit-tap-highlight-color:transparent}
button.stat:active{transform:scale(.98)}
button.stat:focus-visible{outline:2px solid var(--gold);outline-offset:2px}
.stat .n,.stat .l,.stat .sub{display:block}
.stat .sub{font-size:10px;color:var(--muted);font-family:"JetBrains Mono",monospace;letter-spacing:.06em;margin-top:2px;opacity:.85}
.stat .top3{display:flex;justify-content:center;align-items:center;margin-top:8px}
.stat .top3 .bub{width:26px;height:26px;flex:none;border-radius:50%;overflow:hidden;display:grid;place-items:center;
  margin-left:-10px;background:var(--stage2);border:2px solid var(--stage);box-shadow:0 1px 3px rgba(0,0,0,.3);
  font-family:'Bricolage Grotesque';font-weight:800;font-size:12px;color:var(--gold-text);position:relative}
.stat .top3 .bub:first-child{margin-left:0}
.stat .top3 .bub.r1{width:30px;height:30px;font-size:13px;border-color:var(--gold);z-index:3;
  box-shadow:0 0 8px -2px rgba(242,185,60,.7)}
.stat .top3 .bub.r2{z-index:2}
.stat .top3 .bub img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;display:block}
.stat .top3 .none{color:var(--muted);font-family:"JetBrains Mono",monospace;font-size:14px}
/* Rankings sheet */
.rank-sheet{padding:18px 18px 6px;display:flex;flex-direction:column;min-height:0}
.rank-head{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;margin-bottom:6px}
.rank-head .t{font-family:'Bricolage Grotesque';font-weight:800;font-size:20px}
.rank-head .s{font-size:11px;color:var(--muted);font-family:"JetBrains Mono",monospace;letter-spacing:.06em;margin-top:2px}
.rank-list{overflow:auto;margin:0 -18px;padding:0 18px 12px;list-style:none}
.rank-row{display:flex;align-items:center;gap:12px;padding:11px 0;border-top:1px solid var(--line)}
.rank-row .rk{font-family:"JetBrains Mono",monospace;font-size:12px;color:var(--muted);width:20px;text-align:right;flex:none}
.rank-row .av{width:34px;height:34px;border-radius:50%;flex:none;display:grid;place-items:center;overflow:hidden;position:relative;
  background:var(--stage2);color:var(--gold-text);font-weight:700;font-family:'Bricolage Grotesque';border:1px solid var(--line)}
.rank-row .av img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}
.rank-row .who{flex:1;min-width:0}
.rank-row .nm{font-weight:600;font-size:15px;overflow-wrap:anywhere;line-height:1.25}
.rank-row .meta{font-size:11px;color:var(--muted);font-family:"JetBrains Mono",monospace;margin-top:2px}
.rank-row .ct{font-family:"JetBrains Mono",monospace;font-weight:700;font-size:17px;color:var(--gold-text);flex:none;text-align:right}
.rank-row .ct small{display:block;font-size:9px;font-weight:500;color:var(--muted);letter-spacing:.06em}
.rank-row.top .ct{text-shadow:var(--glow-gold)}
.rank-empty{color:var(--muted);font-size:14px;padding:14px 0 8px;border-top:1px solid var(--line)}
/* ===== Stubs — the ticket wall (Phil 2026-09-19) ===== */
.yeargroup{margin-bottom:14px}
.yg-head{display:flex;align-items:center;gap:10px;width:100%;background:var(--stage);
  border:1px solid var(--line);border-radius:14px;padding:10px 12px;cursor:pointer;
  color:var(--ink);font:inherit;text-align:left}
.yg-head .yg-tab{width:5px;align-self:stretch;border-radius:3px;background:var(--gold)}
.yg-head .yg-year{font-family:"JetBrains Mono",monospace;font-weight:700;font-size:19px}
.yg-head .yg-count{font-size:12px;color:var(--muted)}
.yg-head .yg-thumbs{display:flex;margin-left:auto}
.yg-head .yg-thumbs img,.yg-head .yg-thumbs .yg-fb{width:30px;height:30px;border-radius:50%;
  object-fit:cover;border:2px solid var(--stage);margin-left:-9px;background:#d9cba6}
.yg-head .yg-chev{color:var(--gold);font-size:15px;transition:transform .25s}
.yg-head[aria-expanded="false"] .yg-chev{transform:rotate(-90deg)}
.yg-body{display:grid;grid-template-rows:1fr;transition:grid-template-rows .3s ease}
.yg-body.closed{grid-template-rows:0fr}
.yg-body > div{overflow:hidden;min-height:0}
.yg-tickets{padding:10px 2px 2px;display:flex;flex-direction:column;gap:17px}
/* drop-shadow lives on the wrapper: it follows the torn clip-path, while a
   box-shadow on the clipped element itself would be cut off. */
.twrap{filter:drop-shadow(0 6px 12px rgba(0,0,0,.30));margin:2px 4px}
[data-theme="light"] .twrap{filter:drop-shadow(0 6px 12px rgba(60,40,90,.20))}
/* The ticket itself: cream paper in both themes, torn zigzag edges. */
.ticket{position:relative;display:flex;background:#F3E7C9;border-radius:6px;color:#3A2A1A;
  -webkit-touch-callout:none;user-select:none;
  /* Torn edges are cut at runtime by applyTornEdges() (public/app.js):
     one haphazardly torn edge (right, seeded per ticket so each rip is unique
     but stable), straight everywhere else — like a real stub ripped from the
     book. Without clip-path support the border-radius above is the clean-card
     fallback. */}
/* The hold-to-tear wind-up. The ticket eases down toward the tear over the hold
   duration, so a press started by accident while scrolling is visible long
   before it fires and can be abandoned. Transform only — it composites on the
   GPU and never reflows a list of clipped tickets mid-scroll. */
/* Selector shape mirrors the base rotation below deliberately: .twrap:nth-child
   () .ticket outranks a bare .ticket.tearing, so a lower-specificity wind-up
   would silently never apply to half the wall. */
.ticket{transition:transform .12s ease-out}
.twrap:nth-child(odd) .ticket.tearing,
.twrap:nth-child(even) .ticket.tearing{transition:transform .62s cubic-bezier(.35,0,.7,1)}
.twrap:nth-child(odd) .ticket.tearing{transform:scale(.955) rotate(-1.4deg)}
.twrap:nth-child(even) .ticket.tearing{transform:scale(.955) rotate(1.4deg)}
@media (prefers-reduced-motion:reduce){
  /* No travel, but the wind-up must still be perceivable — fade instead. */
  .twrap:nth-child(odd) .ticket.tearing,
  .twrap:nth-child(even) .ticket.tearing{transition:opacity .62s linear;opacity:.72}
  .twrap:nth-child(odd) .ticket.tearing{transform:rotate(-.8deg)}
  .twrap:nth-child(even) .ticket.tearing{transform:rotate(.8deg)}
}
.twrap:nth-child(odd) .ticket{transform:rotate(-.8deg)}
.twrap:nth-child(even) .ticket{transform:rotate(.8deg)}
/* ---- colour band: the factory edge, keyed to year ----
   Hue comes from stubBandHue() in app.js as an inline --band, so the ramp lives
   in one place. Muted on purpose: a saturated band against cream paper reads as
   a toy, and it must not compete with the gold that means "near you". */
.ticket::before{content:"";position:absolute;left:0;top:0;bottom:0;width:13px;
  background:var(--band,#7FA8C9);z-index:3}

/* ---- left rail: the vertical rotated text of a real GA stub ----
   One rail, not two. At 390px there is not room for art + date + name +
   perforation + stub AND rails on both edges — the artist name is what loses,
   and the artist name is the point. */
.ticket .rail-l{position:absolute;left:13px;top:0;bottom:0;width:15px;z-index:3;
  display:flex;align-items:center;justify-content:center;pointer-events:none;
  border-right:1px dashed rgba(120,95,55,.38)}
.ticket .rail-l span{writing-mode:vertical-rl;transform:rotate(180deg);white-space:nowrap;
  font-family:"JetBrains Mono",monospace;font-size:7.4px;font-weight:700;
  letter-spacing:.16em;color:#6E5A42}

.ticket .tart{position:relative;width:64px;flex:none;margin:12px 0 12px 31px;border-radius:3px;
  overflow:hidden;background:#e2d3ab;min-height:98px;z-index:2}
.ticket .tart img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  filter:saturate(.86) contrast(1.03)}
.ticket .tart .tfb{position:absolute;inset:0;display:grid;place-items:center;text-align:center;
  font-size:10px;color:#8a7a5c;padding:8px;line-height:1.35;
  background:repeating-linear-gradient(45deg,#e8dab8 0 10px,#dfcfa4 10px 20px)}
/* Tucked into the picture's corner and mostly transparent: at 64px wide the art
   is mostly a face, and a solid gold badge sat on it. It is an affordance for
   the rare moment you want to replace the artwork, not a permanent fixture, so
   it recedes until touched. The ::after extends the hit area to ~44px without
   growing the visible dot. */
.ticket .artedit{position:absolute;bottom:3px;right:3px;width:20px;height:20px;border-radius:50%;
  background:rgba(36,21,5,.28);color:rgba(243,231,201,.85);border:0;font-size:10px;line-height:1;
  display:grid;place-items:center;cursor:pointer;z-index:3;padding:0;
  /* A hairline of paper-cream so the dot still separates on DARK artwork, where
     a translucent dark fill and a light glyph would otherwise both sink in.
     Test fixtures have no real photos, so this covers the case they can't. */
  box-shadow:0 0 0 1px rgba(243,231,201,.38);
  backdrop-filter:blur(2px);transition:background .15s,color .15s,box-shadow .15s}
.ticket .artedit::after{content:"";position:absolute;inset:-12px}
.ticket .artedit:hover,.ticket .artedit:focus-visible{background:rgba(36,21,5,.6);
  color:#F3E7C9;outline:none;box-shadow:0 0 0 1px rgba(243,231,201,.7)}
/* Touch has no hover, so the press state is what confirms the tap landed. */
.ticket .artedit:active{background:#C98D2E;color:#241505}
.ticket .artedit.is-busy{opacity:.4;pointer-events:none}

/* ---- native file-input doors --------------------------------------------
   iOS WebKit drops the picked file when the photo picker is opened via
   input.click() on a hidden input (picker opens, selection vanishes, no
   change event). Every image door is therefore a <label class="filepick">
   wrapping its own real file input: the user's tap lands on the input
   itself. The input must stay RENDERED (opacity:0, never display:none) or
   iOS won't route the tap to it. */
.filepick{position:relative;overflow:hidden}
.filepick-input{position:absolute;inset:0;width:100%;height:100%;opacity:0;cursor:pointer}

/* ---- the date, as the hero it is on a vintage stub ----
   Big numeral, month set vertically beside it, year as stacked single digits. */
.ticket .tdate-block{display:flex;align-items:center;gap:2px;flex:none;padding:0 4px 0 3px;z-index:2}
.ticket .tdate-block .mon{writing-mode:vertical-rl;font-family:"JetBrains Mono",monospace;
  font-weight:700;font-size:8.6px;letter-spacing:.28em;color:#3A2A1A}
.ticket .tdate-block .num{font-weight:800;font-size:33px;line-height:.82;color:#3A2A1A}
.ticket .tdate-block .yr{display:flex;flex-direction:column;font-family:"JetBrains Mono",monospace;
  font-size:8.4px;font-weight:700;line-height:1.05;color:#6E5A42}

/* min-width:0 is load-bearing: without it this flex item refuses to shrink
   below its longest word and the name clips instead of wrapping. */
.ticket .tinfo{flex:1 1 auto;padding:12px 6px 10px 8px;min-width:0;z-index:2;
  display:flex;flex-direction:column;justify-content:center}
/* No overflow-wrap:anywhere — it breaks TURNSTILE into TURNSTIL/E. A long word
   gets a smaller size instead, chosen by stubNameClass(). */
.ticket .tinfo h3{font-size:19px;line-height:1.02;margin:0;color:#3A2A1A;font-weight:800;
  letter-spacing:-.4px;text-transform:uppercase;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.ticket .tinfo h3.small{font-size:15.5px;line-height:1.06}
.ticket .tinfo h3.tiny{font-size:13.5px;line-height:1.1;letter-spacing:-.2px}
.ticket .trule{height:1px;background:rgba(120,95,55,.45);margin:5px 0 4px}
/* One line with an ellipsis beats two lines guillotined mid-word: a venue name
   that does not fit should look deliberately abbreviated, not broken. */
.ticket .tvenue{font-size:11.2px;color:#6E5A42;line-height:1.3;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.ticket .twith{font-family:"JetBrains Mono",monospace;font-size:9.2px;font-weight:700;
  color:#A66A1F;margin-top:4px;letter-spacing:.04em;white-space:nowrap;overflow:hidden;
  text-overflow:ellipsis}
.ticket .tperf{width:11px;flex:none;margin:10px 0;z-index:2;
  background-image:radial-gradient(circle,rgba(120,95,55,.75) 2.3px,transparent 2.9px);
  background-size:11px 16px;background-repeat:repeat-y;background-position:center}
/* padding-right is the tear's working room: clip-path cuts children, so without
   a gutter the rip eats the serial number. */
.ticket .tstub{width:66px;flex:none;display:flex;flex-direction:column;align-items:center;
  justify-content:center;gap:3px;padding:10px 15px 10px 2px;text-align:center;z-index:2}
.ticket .tstub .admit{font-family:"JetBrains Mono",monospace;font-size:9px;font-weight:700;
  letter-spacing:.13em;color:#3A2A1A;line-height:1.5}
.ticket .tserial{font-family:"JetBrains Mono",monospace;font-size:13px;font-weight:700;color:#A66A1F}
.ticket .tcoll{font-family:"JetBrains Mono",monospace;font-size:7px;letter-spacing:.1em;
  color:#6E5A42;line-height:1.45}
/* ===== stub detail sheet (PR-2a) ===== */
#stubSheet .modal{padding:0;overflow:hidden;max-width:430px;width:100%}
.ssheet-hero{position:relative;height:150px;background:#2A1A47;overflow:hidden}
/* Crop from near the top: an artist promo shot puts the face in the upper
   third, and centre-cropping a tall photo into a 150px strip cuts the head off. */
.ssheet-hero img{width:100%;height:100%;object-fit:cover;object-position:center 22%;display:block}
.ssheet-noart{height:100%;display:grid;place-items:center;color:var(--muted);font-size:12.5px;
  background:repeating-linear-gradient(45deg,#2A1A47 0 12px,#33215C 12px 24px)}
/* The hero can be a bright photo or a dark tile, so the close button carries its
   own scrim rather than trusting either. */
.ssheet-close{position:absolute;top:9px;right:9px;width:34px;height:34px;border-radius:50%;
  background:rgba(12,6,24,.58);color:#fff;border:0;font-size:20px;line-height:1;cursor:pointer;
  display:grid;place-items:center;backdrop-filter:blur(3px)}
.ssheet-body{padding:14px 16px 18px}
.ssheet-artist{font-family:'Bricolage Grotesque',sans-serif;font-weight:800;font-size:21px;
  line-height:1.1;margin:0 0 4px}
.ssheet-facts{color:var(--muted);font-size:12.8px;line-height:1.45;margin-bottom:4px}
/* The facts are the record, but a record can be wrong. The affordance stays
   quiet — it is a rare action, not a fixture. */
.ssheet-facts{position:relative;padding-right:46px}
.ssheet-factedit{position:absolute;top:-1px;right:0;background:none;border:0;padding:2px 4px;
  color:var(--muted);font-size:11px;cursor:pointer;text-decoration:underline;
  text-underline-offset:2px}
.ssheet-factedit:hover,.ssheet-factedit:focus-visible{color:var(--plum);outline:none}
.ssheet-facts.editing{display:flex;flex-direction:column;gap:7px;padding:0;margin-bottom:6px}
.ssheet-facts.editing input{width:100%;background:var(--house);border:1px solid var(--line);
  border-radius:9px;color:var(--ink);font-family:'Inter',sans-serif;font-size:13px;padding:8px 10px}
.ssheet-facts.editing input:focus{border-color:var(--plum);outline:none}
.ssheet-facts-act{display:flex;gap:7px;margin-top:1px}

.ssheet-section{margin-top:17px}
.who-label{font-family:"JetBrains Mono",monospace;font-size:10.5px;letter-spacing:.12em;
  text-transform:uppercase;color:var(--muted);display:block;margin-bottom:7px}
.who-label span{color:var(--gold-dim);letter-spacing:.06em;text-transform:none}
.who-group{margin-top:11px}
.who-chips{display:flex;flex-wrap:wrap;gap:6px}
.who-empty{color:var(--muted);font-size:12.5px}
.who-chip{font-family:'Inter',sans-serif;font-size:12.5px;padding:7px 11px;border-radius:999px;
  background:transparent;color:var(--ink);border:1px solid var(--line);cursor:pointer;
  min-height:34px;transition:background .12s,border-color .12s}
.who-chip:hover{border-color:var(--plum)}
/* Chosen chips are plum, not gold: gold means "near you" everywhere else and a
   companion is not a proximity signal. */
.who-chip.on{background:rgba(192,132,252,.16);border-color:var(--plum);color:#F0E4FF}
.who-chip.on span{color:var(--muted);margin-left:2px}
/* Confirmed: they said yes. A tick, not a colour change — a claimed chip and a
   confirmed one are both legitimately on your stub, and recolouring the
   unconfirmed one would make a friend who has not opened the app yet look like
   a mistake. Nothing ever marks a decline. */
.who-chip .tick{color:var(--gold-text);margin-left:4px;font-size:11px}

/* Claims waiting on you. Built from .roadie-row so it inherits that pane's
   rhythm rather than inventing a second one. */
.confirm-row{display:flex;align-items:center;gap:11px;padding:10px 0}
.confirm-row + .confirm-row{border-top:1px solid var(--line)}
.confirm-art{width:42px;height:42px;border-radius:8px;flex:none;overflow:hidden;
  background:var(--stage);border:1px solid var(--line)}
.confirm-art img{width:100%;height:100%;object-fit:cover;display:block}
.confirm-who{flex:1;min-width:0}
.confirm-who .t{font-size:14.5px;font-weight:600}
.confirm-who .s{font-size:11.5px;color:var(--muted);font-family:"JetBrains Mono",monospace;margin-top:2px;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* Who is claiming you gets its own line. On one line with the venue it was the
   half that got ellipsed away, and it is the half that matters. */
.confirm-who .s.who{color:var(--plum)}
.confirm-actions{display:flex;gap:6px;flex:none}

/* Share sits in the PHOTOS heading row, so the label has to stop being a plain
   block. Subtle by default — it is an offer, not the main action on this sheet. */
.who-label{display:flex;align-items:center;gap:6px}
.ssheet-share{margin-left:auto;font-family:'JetBrains Mono',monospace;font-size:10.5px;
  letter-spacing:.04em;text-transform:uppercase;padding:5px 10px;border-radius:999px;
  background:transparent;color:var(--plum);border:1px solid var(--line);cursor:pointer;min-height:28px}
.ssheet-share:hover:not(:disabled){border-color:var(--plum)}
.ssheet-share:disabled{color:var(--muted);cursor:default}

/* Photos someone else handed you. Plum-edged so they read as not-yet-yours
   against your own tiles, which carry no border. */
.soffers{margin-top:14px}
.soffer{border:1px solid var(--plum);position:relative}
.soffer img{width:100%;height:100%;object-fit:cover;display:block}
.soffer-from{position:absolute;left:0;right:0;top:0;padding:3px 6px;font-size:10px;
  font-family:'JetBrains Mono',monospace;color:#F0E4FF;background:rgba(30,18,54,.72);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.soffer-acts{position:absolute;left:0;right:0;bottom:0;display:flex;gap:4px;justify-content:center;
  padding:5px 4px;background:rgba(30,18,54,.72)}
.soffer-acts .btn{min-height:26px;padding:3px 9px;font-size:11px}
/* Matinee: the fill stays pale lavender in both themes, so near-white text
   disappears into it. Dark plum instead — checked against the light ground,
   not assumed from the dark one. */
[data-theme="light"] .who-chip.on{background:rgba(124,58,190,.14);color:#42107A;
  border-color:#8E4FD0}
[data-theme="light"] .who-chip.on span{color:#6B4B95}
[data-theme="light"] .who-chip{color:var(--ink)}
/* Dashed, so it reads as an action sitting among the people rather than as
   another person. */
.who-add-chip{border-style:dashed;color:var(--muted)}
.who-add-chip:hover,.who-add-chip:focus-visible{color:var(--ink);border-color:var(--plum);
  border-style:solid;outline:none}
.who-add{display:flex;gap:7px;margin-top:11px}
.who-add input{flex:1;min-width:0;background:var(--house);border:1px solid var(--line);
  border-radius:10px;color:var(--ink);font-size:13px;padding:9px 11px}
.ssheet-danger{margin-top:20px;padding-top:14px;border-top:1px solid var(--line);
  display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.ssheet-danger span{color:var(--muted);font-size:11.5px;flex:1;min-width:140px}
/* Outlined, not filled. The base .btn is a gold pill, so setting only the border
   left the tear-up button as the loudest thing on the sheet — a destructive
   action reading as the primary one. It stays plainly visible (the standing
   rule) without competing with Save. */
.ssheet-danger .btn.danger{background:transparent;color:var(--magenta);
  border:1px solid var(--magenta)}
.ssheet-danger .btn.danger:hover,.ssheet-danger .btn.danger:focus-visible{
  background:rgba(255,92,168,.14);outline:none}

/* ---- stub photos (2b) ---- */
.ssheet-body .who-label span{color:var(--muted);font-weight:500;letter-spacing:0}
.sphotos{display:grid;grid-template-columns:repeat(3,1fr);gap:8px;margin-top:8px}
.sphoto{position:relative;aspect-ratio:1;border-radius:12px;overflow:hidden;padding:0;
  border:1px solid var(--line);background:rgba(255,255,255,.04);
  display:flex;align-items:center;justify-content:center}
/* The tile itself opens the photo; the × is a sibling on top of it. */
.sphoto-open{position:absolute;inset:0;padding:0;border:0;background:none;cursor:pointer}
.sphoto img{width:100%;height:100%;object-fit:cover;display:block}
.sphoto-open:focus-visible{outline:2px solid var(--plum);outline-offset:-2px}
/* Same corner badge as the ✎ on ticket artwork: low-opacity dark ground with a
   cream hairline, so it still separates on a bright photo. Top-right, because
   that is where a "remove this" reads. */
.sphoto-del{position:absolute;top:4px;right:4px;width:22px;height:22px;border-radius:50%;
  background:rgba(12,6,20,.46);color:rgba(243,231,201,.9);border:0;font-size:13px;line-height:1;
  display:grid;place-items:center;cursor:pointer;z-index:3;padding:0;
  box-shadow:0 0 0 1px rgba(243,231,201,.45)}
/* Hit area padded well past the dot — it is a 22px target otherwise. */
.sphoto-del::after{content:"";position:absolute;inset:-12px}
.sphoto-del:hover,.sphoto-del:focus-visible{background:rgba(12,6,20,.75);color:#F3E7C9;
  outline:none;box-shadow:0 0 0 1px rgba(243,231,201,.8)}
/* Touch has no hover, so the press state is what confirms the tap landed. */
.sphoto-del:active{background:var(--magenta);color:#1B0A14}
/* A row whose file went missing shows a mark, not a broken-image glyph. */
.sphoto.missing img{display:none}
.sphoto.missing::after{content:"unavailable";color:var(--muted);font-size:10px;letter-spacing:.04em}
.sphoto.add{flex-direction:column;gap:2px;border-style:dashed;color:var(--muted);cursor:pointer}
.sphoto.add span{font-size:22px;line-height:1}
.sphoto.add small{font-size:9.5px;letter-spacing:.04em;text-transform:uppercase}
.sphoto.add:hover,.sphoto.add:focus-visible{color:var(--ink);border-color:var(--plum);outline:none}
.sphoto.adding{color:var(--muted);font-size:10px;border-style:dashed}
/* At the cap the add tile is replaced by the reason, never a silent replace. */
.sphoto-full{grid-column:span 3;color:var(--muted);font-size:11px;padding-top:2px}

/* ---- photo lightbox ---- */
/* Above the sheet it opens from, and darker: the photo is the whole point, so
   the plum chrome of the sheet underneath should not compete with it. */
.modal-scrim.lightbox{z-index:75;background:rgba(4,2,10,.94);padding:0}
.lb-frame{position:relative;width:100%;height:100%;display:flex;
  align-items:center;justify-content:center}
.lb-frame img{max-width:100%;max-height:100%;object-fit:contain;display:block;
  transform:scale(.985);transition:transform .22s ease-out}
.modal-scrim.lightbox.open .lb-frame img{transform:scale(1)}
.lb-bar{position:absolute;left:0;right:0;bottom:0;display:flex;align-items:center;
  justify-content:space-between;gap:12px;padding:14px 16px calc(14px + env(safe-area-inset-bottom));
  background:linear-gradient(to top,rgba(0,0,0,.72),transparent)}
/* The chrome sits on the photo, over a near-black scrim, in BOTH themes — so
   it is light by value, not by token. --ink flips dark in Matinee and the close
   glyph disappeared entirely against the scrim. */
.lb-count{color:rgba(255,255,255,.72);font-size:11px;letter-spacing:.06em}
.lb-btn{background:rgba(255,255,255,.1);border:1px solid rgba(255,255,255,.22);
  color:#fff;border-radius:999px;padding:7px 14px;font-size:13px;cursor:pointer}
.lb-btn:focus-visible{outline:2px solid var(--plum);outline-offset:2px}
.lb-btn.danger{color:#FF7FBC;border-color:#FF7FBC;background:transparent}
.lb-nav{position:absolute;top:50%;transform:translateY(-50%);background:rgba(0,0,0,.42);
  border:0;color:#fff;font-size:30px;line-height:1;width:44px;height:64px;cursor:pointer;
  display:flex;align-items:center;justify-content:center}
.lb-nav.prev{left:0;border-radius:0 8px 8px 0}
.lb-nav.next{right:0;border-radius:8px 0 0 8px}
.lb-nav:focus-visible{outline:2px solid var(--plum);outline-offset:-4px}
@media (prefers-reduced-motion:reduce){
  .lb-frame img,.modal-scrim.lightbox.open .lb-frame img{transform:none;transition:none}
}
/* Matinee: the lightbox chrome sits on the photo, not on the page, so it keeps
   its dark treatment in both themes — but the tiles belong to the sheet. */
[data-theme="light"] .sphoto{background:rgba(0,0,0,.05)}

/* old stub card styles below are superseded by the ticket wall */
#stubForm input{margin-bottom:8px}

/* ===== step 10: prefs rows ===== */
.threshrow{display:flex;align-items:center;gap:8px;margin-top:9px;flex-wrap:wrap}
.threshrow label{font-size:12.5px;color:var(--muted);display:flex;align-items:center;gap:4px}
.threshrow input[type=number]{background:var(--house);border:1px solid var(--line);border-radius:8px;
  color:var(--ink);font-family:"JetBrains Mono",monospace;font-size:13px;padding:7px 8px;text-align:center}
.threshrow select{background:var(--house);border:1px solid var(--line);border-radius:8px;
  color:var(--ink);font-family:"JetBrains Mono",monospace;font-size:12px;padding:7px 8px}
.chip.src{color:var(--muted);font-size:9.5px}


/* ===== Matinee — the same theater with the house lights on ===== */



/* ===== Matinee — Neon, house lights on ===== */
[data-theme="light"]{
  --house:#F6F0FA; --stage:#FFFFFF; --stage2:#EDE3F5; --line:#E0D2EC;
  --gold:#E9A82A; --gold-dim:#B98D2B; --gold-text:#8A4FC0;
  --plum:#8B3FD0; --green:#0E9A52; --ink:#241A2E; --muted:#7A6A88;
  --magenta:#D62F8A;
  color-scheme:light;
}
[data-theme="light"] .chip.drop{color:#fff}
[data-theme="light"] .chip.onsale{color:#231206}
[data-theme="light"] .avatar{background:var(--stage2)}

/* ===== Neon flourishes (both themes) ===== */
.logo .q{color:var(--magenta)}
.chip.presale{color:#fff;background:linear-gradient(90deg,var(--plum),var(--magenta));border:none}
.chip.star{color:var(--magenta);border-color:var(--magenta)}

/* ===== add-source-by-URL ===== */
.addsource{display:flex;gap:8px}
.addsource input{flex:1;background:var(--stage);border:1px solid var(--line);border-radius:10px;
  color:var(--ink);font-size:14px;padding:10px 12px}
.addsource input:focus{outline:2px solid var(--gold-dim);outline-offset:1px}
.addsource-hint{font-size:11.5px;color:var(--muted);margin-top:7px;line-height:1.45}
.addsource-hint.ok{color:var(--green)}
.addsource-hint.err{color:var(--magenta)}
/* Added, but with nowhere to put it: the shows are stored and will appear as
   soon as anything can place the venue. Not an error, not a clean success. */
.addsource-hint.warn{color:var(--gold)}
/* Collapsed power-feature disclosure in Your scene */
.src-disclosure{margin:10px 0 8px}
.src-disclosure summary{cursor:pointer;list-style:none;font-size:13px;font-weight:500;
  color:var(--muted);padding:8px 2px;user-select:none}
.src-disclosure summary::-webkit-details-marker{display:none}
.src-disclosure summary::before{content:"+";display:inline-block;width:16px;color:var(--gold)}
.src-disclosure[open] summary::before{content:"–"}
.src-disclosure summary:hover{color:var(--ink)}

/* Settings menu list: tap a row to drill into that section's sub-page,
   like a native settings app. Admin rows live last, inside
   #settingsAdminMenu. */
.set-menu-row{display:flex;align-items:center;gap:14px;width:100%;
  padding:15px 6px;background:none;border:none;border-bottom:1px solid var(--rule);
  color:var(--ink);font:inherit;font-size:16px;text-align:left;cursor:pointer;
  -webkit-tap-highlight-color:transparent}
.set-menu-row svg{width:23px;height:23px;color:var(--gold);flex:none}
.set-menu-row .menu-chev{margin-left:auto;color:var(--gold);font-size:22px;line-height:1}
/* New-reply dot on the My reports menu row. */
.menu-dot{width:9px;height:9px;border-radius:50%;background:var(--gold);margin-left:8px;flex:none}
.menu-dot[hidden]{display:none}
/* Notification dot on the header settings gear: lights when a report in
   My reports has an unread owner message. Warm red reads against the gold gear. */
.gear-dot{position:absolute;top:-1px;right:-1px;width:11px;height:11px;border-radius:50%;
  background:#ff5a4e;border:2px solid #1d1033;z-index:1;pointer-events:none}
.gear-dot[hidden]{display:none}
/* Triage status chips on My reports cards. */
.kind-chip.status-new{background:rgba(140,140,160,.15);color:#b9b9c7}
.kind-chip.status-accepted{background:rgba(120,200,120,.15);color:#9fd89f}
.kind-chip.status-declined{background:rgba(220,120,120,.15);color:#e0a0a0}
.kind-chip.status-icebox{background:rgba(212,175,55,.15);color:var(--gold)}
.set-menu-row:active{background:var(--surf-1)}
/* Beta: the bug-report row sits first in the Settings menu and stands out. */
.set-menu-row.bug-row{border:1px solid var(--gold-dim);border-radius:14px;
  background:rgba(242,185,60,.08);padding:15px 14px;margin-bottom:10px}
.beta-tag{font-size:10px;font-weight:700;letter-spacing:.08em;color:var(--gold-text);
  border:1px solid var(--gold-dim);border-radius:999px;padding:2px 7px;
  margin-left:8px;vertical-align:2px;white-space:nowrap}
.set-menu-label{font-family:"JetBrains Mono",monospace;font-size:11px;
  letter-spacing:.16em;color:var(--muted);margin:22px 0 2px}
/* Settings sub-page: back chevron + centered section title */
.set-detail-head{display:flex;align-items:center;padding:6px 0 16px}
.set-back{background:var(--stage);border:1px solid var(--line);color:var(--ink);
  font-size:24px;line-height:1;width:44px;height:44px;flex:none;border-radius:50%;
  display:grid;place-items:center;padding:0 0 2px;cursor:pointer;-webkit-tap-highlight-color:transparent}
.set-back:active{transform:scale(.94)}
.set-back-spacer{visibility:hidden;width:44px;flex:none}
.set-detail-title{flex:1;text-align:center;font-size:17px;font-weight:600}

/* ===== local-source filter row with Clear ===== */
.srcfilter-row{display:flex;gap:8px;align-items:center;margin:10px 0 8px}
.srcfilter-row input{flex:1;background:var(--stage);border:1px solid var(--line);border-radius:10px;
  color:var(--ink);font-size:14px;padding:10px 12px}
.srcfilter-row input:focus{outline:2px solid var(--gold-dim);outline-offset:1px}

/* ===== website-monitored artist cards ===== */
.monitor-link{display:inline-block;color:var(--magenta);font-size:13px;font-weight:600;
  text-decoration:none;margin-top:2px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:200px}
.monitor-link:active{opacity:.7}
.monitor-sub{font-size:11px;color:var(--muted);font-family:"JetBrains Mono",monospace;
  letter-spacing:.03em;margin-top:2px}

/* ===== star / save-to-Upcoming ===== */
.star-btn{background:none;border:none;cursor:pointer;flex:none;padding:2px 4px;
  font-size:22px;line-height:1;color:var(--muted);transition:color .15s,transform .1s}
.star-btn.on{color:var(--gold)}
.star-btn:active{transform:scale(.85)}

/* ===== SIGNATURE: backlit marquee panels (Upcoming) =====
   The glow is semantic, not decoration: a panel lights up only when the show
   falls inside a watch area. Out-of-range shows sit dark, so the list can be
   read at a glance by which panels are lit. */
.panel{position:relative;border-radius:20px;overflow:hidden;margin-bottom:16px;
  border:1px solid rgba(242,185,60,.8);min-height:196px;display:flex;align-items:flex-end;
  background:linear-gradient(140deg,#5B3A8E,#2A1A47);
  box-shadow:0 0 0 1px rgba(242,185,60,.35),0 0 26px -4px rgba(242,185,60,.55),
             0 10px 30px -8px rgba(0,0,0,.7)}
.panel-trigger{position:relative;z-index:1;width:100%;min-height:196px;padding:0;border:0;
  display:flex;align-items:flex-end;background:transparent;color:inherit;text-align:left;font:inherit;cursor:pointer}
.panel-trigger:focus-visible{outline:3px solid var(--gold);outline-offset:-4px;border-radius:19px}
.panel .bg{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}
.panel .scrim{position:absolute;inset:0;background:linear-gradient(to top,
  rgba(16,8,32,.95) 18%,rgba(16,8,32,.62) 48%,rgba(16,8,32,.38) 80%,rgba(16,8,32,.30) 100%)}
/* The gold treatment below is the house treatment for EVERY upcoming card —
   "near you" vs "on your list" now reads from the pill text, not the card. */

/* Deep-link arrival pulse: the card a notification pointed at.

   Cream, not gold and not magenta. Gold is the house treatment on every
   upcoming card now, so a gold flash would read as card state instead of a
   one-shot arrival signal. Magenta was the first attempt and failed in
   preview: --sunset is an orange-to-magenta gradient, so a magenta ring
   vanished into the card it was meant to pick out. Cream is the one hue that
   reads against every card surface here and claims no meaning of its own.
   It is a transient animation, never a class that sticks, so it cannot
   be mistaken for a state. */
@keyframes cardflash{
  0%  {box-shadow:0 0 0 3px rgba(243,236,247,.95),0 0 34px -2px rgba(243,236,247,.5),0 10px 30px -8px rgba(0,0,0,.7)}
  55% {box-shadow:0 0 0 3px rgba(243,236,247,.55),0 0 26px -4px rgba(243,236,247,.25),0 10px 30px -8px rgba(0,0,0,.7)}
  100%{box-shadow:0 0 0 0 rgba(243,236,247,0),0 10px 30px -8px rgba(0,0,0,.7)}
}
.panel.flash{animation:cardflash 2.4s ease-out 1}
@media (prefers-reduced-motion:reduce){
  .panel.flash{animation:none;outline:3px solid var(--ink);outline-offset:2px}
}

.bignum{position:absolute;top:10px;left:14px;line-height:.82;pointer-events:none;z-index:1}
.bignum .d{display:block;font-family:'Bricolage Grotesque';font-weight:800;font-size:58px;
  color:transparent;-webkit-text-stroke:2px var(--gold);letter-spacing:-.02em;
  text-shadow:0 0 22px rgba(242,185,60,.55)}
.bignum .m{display:block;font-family:'JetBrains Mono',monospace;font-weight:700;font-size:11px;
  letter-spacing:.22em;color:var(--gold);margin-top:6px;opacity:1;
  text-shadow:0 1px 8px rgba(0,0,0,.9),0 0 3px rgba(0,0,0,.85)}

.star-n{position:absolute;top:14px;right:14px;width:38px;height:38px;border-radius:50%;
  background:rgba(16,8,32,.6);border:1px solid rgba(243,236,247,.22);color:var(--gold);
  font-size:20px;line-height:1;cursor:pointer;display:grid;place-items:center;z-index:2;
  -webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px);
  text-shadow:0 0 12px rgba(242,185,60,.8);transition:transform .1s}
.star-n:active{transform:scale(.88)}

.pcontent{display:block;position:relative;padding:14px 15px;width:100%;z-index:1}
.pname{display:block;font-family:'Bricolage Grotesque';font-weight:800;font-size:25px;line-height:1.08;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;color:#F3ECF7;
  text-shadow:0 2px 14px rgba(0,0,0,.85),0 1px 3px rgba(0,0,0,.9),0 0 26px rgba(242,185,60,.35)}
.pwhere{display:block;font-size:13px;color:rgba(243,236,247,.8);margin-top:3px;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
  text-shadow:0 1px 8px rgba(0,0,0,.9),0 1px 3px rgba(0,0,0,.85)}
.prow{display:flex;align-items:center;justify-content:space-between;gap:10px;margin-top:11px}
.pill{font-family:'JetBrains Mono',monospace;font-size:9.5px;letter-spacing:.12em;
  padding:5px 10px;border-radius:999px;border:1px solid var(--gold);
  color:#241505;font-weight:700;background:var(--gold);
  box-shadow:0 0 16px -2px rgba(242,185,60,.7)}

/* Roadies slot — empty in v1, fills in v2 with no layout change */
.roadies{display:flex;align-items:center;gap:5px}
.roadies .lbl{font-family:'JetBrains Mono',monospace;font-size:9px;letter-spacing:.12em;
  color:rgba(243,236,247,.6)}

/* ===== artist modal ===== */
.modal-scrim{position:fixed;inset:0;z-index:60;background:rgba(10,4,22,.78);
  display:grid;place-items:center;padding:18px;opacity:0;transition:opacity .2s;
  -webkit-backdrop-filter:blur(3px);backdrop-filter:blur(3px)}
.modal-scrim.open{opacity:1}
.modal{width:100%;max-width:392px;background:var(--stage);border-radius:22px;overflow:hidden;
  max-height:86vh;display:flex;flex-direction:column;border:1px solid rgba(255,92,168,.35);
  box-shadow:0 0 40px -6px rgba(255,92,168,.35),0 24px 60px -10px rgba(0,0,0,.8);
  transform:translateY(14px) scale(.98);transition:transform .22s ease-out}
.modal-scrim.open .modal{transform:translateY(0) scale(1)}
.mhero{position:relative;min-height:190px;display:flex;align-items:flex-end;
  background:linear-gradient(140deg,#5B3A8E,#2A1A47)}
.mhero .bg{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}
.mhero .fade{position:absolute;inset:0;background:linear-gradient(to top,
  var(--stage) 4%,rgba(42,26,71,.75) 32%,transparent 72%)}
.mhero .cap{position:relative;padding:0 18px 12px;width:100%;z-index:1}
.mname{font-family:'Bricolage Grotesque';font-weight:800;font-size:30px;line-height:1;
  text-shadow:0 0 30px rgba(255,92,168,.4);color:#F3ECF7}
.modal-close{position:absolute;top:12px;right:12px;width:36px;height:36px;border-radius:50%;
  background:rgba(16,8,32,.65);border:1px solid rgba(243,236,247,.25);color:#F3ECF7;
  font-size:17px;line-height:1;cursor:pointer;display:grid;place-items:center;z-index:3;
  -webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px)}
.mbody{padding:6px 16px calc(18px + env(safe-area-inset-bottom));overflow-y:auto}
.mstats{font-family:'JetBrains Mono',monospace;font-size:10.5px;color:var(--muted);
  letter-spacing:.08em;margin-top:2px}
.mact{display:flex;gap:8px;margin:14px 0 6px;flex-wrap:wrap}
.sheet-loading{color:var(--muted);font-size:13.5px;padding:18px 2px;text-align:center}

/* ---------- first-run onboarding overlay ---------- */
.ob-body{padding:24px 22px 20px}
.ob-eyebrow{font-size:11px;letter-spacing:.14em;opacity:.65;margin-bottom:10px}
.ob-title{font-family:'Bricolage Grotesque';font-weight:800;font-size:26px;line-height:1.15;
  margin:0 0 12px;color:#F3ECF7}
.ob-line{margin:0 0 10px;line-height:1.5;opacity:.9}
.ob-sub{margin:0 0 14px;line-height:1.5;opacity:.85}
.ob-dots{display:flex;gap:6px;margin-bottom:14px}
.ob-dots span{width:22px;height:4px;border-radius:2px;background:rgba(243,236,247,.18)}
.ob-dots span.on{background:#FF5CA8}
.ob-cta{width:100%;margin-top:14px}
.ob-quiet{width:100%;margin-top:8px}
.ob-foot{display:flex;justify-content:space-between;align-items:center;margin-top:16px;gap:8px}
.ob-saved{margin-bottom:12px;padding:10px 12px;border-radius:12px;font-size:14px;
  background:rgba(120,255,170,.08);border:1px solid rgba(120,255,170,.25)}
.ob-tabs{display:grid;gap:8px;margin:4px 0 6px}
.ob-tab{display:flex;align-items:baseline;gap:10px;padding:10px 12px;border-radius:12px;
  background:rgba(243,236,247,.05);border:1px solid rgba(243,236,247,.1)}
.ob-tab b{min-width:86px}
.ob-tab span{opacity:.75;font-size:14px}
.ob-body .addarea{margin-bottom:4px}
.ob-body .areaform{margin-top:10px}

/* ---- live walkthrough: coach marks over the real UI ---- */
/* No scrim: the page stays interactive so the tour's interactive stops
   (artist search, watch-area controls) work mid-tour. */
/* ===== Onboarding spotlight ===== */
/* The dim drops everything except the spotlighted feature into shadow so the
   highlighted element reads instantly. It never intercepts taps — interactive
   stops (artist search, watch areas) keep their controls usable — while the
   .ob-spot target lifts above it. */
#obDim{position:fixed;inset:0;background:rgba(8,5,12,.62);z-index:55;
  pointer-events:none;animation:obDimIn .25s ease}
@keyframes obDimIn{from{opacity:0}to{opacity:1}}
.ob-spot{position:relative;z-index:60;outline:3px solid var(--gold);outline-offset:4px;
  border-radius:12px;animation:obPulse 1.6s ease-in-out infinite}
@keyframes obPulse{0%,100%{box-shadow:0 0 0 0 rgba(242,185,60,.55),0 0 26px 4px rgba(242,185,60,.35)}
  50%{box-shadow:0 0 0 10px rgba(242,185,60,0),0 0 26px 4px rgba(242,185,60,.35)}}
/* The staged tour preview card is honest about being staged. */
#obPreviewCard{position:relative}
.ob-preview-chip{position:absolute;top:10px;right:10px;z-index:2;
  font-size:10px;font-weight:700;letter-spacing:.12em;
  background:rgba(8,5,12,.72);color:var(--gold);border:1px solid var(--gold);
  border-radius:999px;padding:3px 9px;pointer-events:none}
/* Markie guides the tour from inside the caption bubble: the bust on every
   stop except the intro, the pointing pose on card-spotlight stops, and the
   full-body peace-sign greeting above the bubble on the intro stop. Entrance hop
   plays once per stop, then a gentle idle bob; the point bounce leans
   toward the spotlighted card. All transforms are cheap compositor work. */
.ob-guide{display:flex;align-items:center;gap:10px;margin:2px 0 8px}
.ob-markie{width:64px;height:64px;flex:none;object-fit:contain;
  filter:drop-shadow(0 2px 10px rgba(0,0,0,.55));
  animation:obHop .55s cubic-bezier(.2,.9,.3,1.2),
    obBob 2.6s ease-in-out .55s infinite}
.ob-markie.ob-pointing{
  animation:obHop .55s cubic-bezier(.2,.9,.3,1.2),
    obPoint .7s ease-in-out .55s 2,
    obBob 2.6s ease-in-out 1.95s infinite}
.ob-hero{position:absolute;left:16px;bottom:calc(100% - 4px);width:104px;
  pointer-events:none;filter:drop-shadow(0 10px 22px rgba(0,0,0,.5));
  animation:obHop .6s cubic-bezier(.2,.9,.3,1.2),
    obBob 3s ease-in-out .6s infinite}
@keyframes obBob{0%,100%{transform:translateY(0)}50%{transform:translateY(-7px)}}
@keyframes obHop{0%{transform:translateY(24px) scale(.7);opacity:0}
  55%{transform:translateY(-8px) scale(1.05);opacity:1}
  100%{transform:translateY(0) scale(1);opacity:1}}
@keyframes obPoint{0%,100%{transform:translateX(0) rotate(0)}
  30%{transform:translateX(14px) rotate(3deg)}
  60%{transform:translateX(7px) rotate(-2deg)}}
@media (prefers-reduced-motion:reduce){
  .ob-markie,.ob-hero{animation:none}}
/* The intro card's caption is a speech bubble: a tail points up to the
   full-body Markie greeting above it, so the words read as Markie talking. */
.ob-bubble.ob-intro::before{content:'';position:absolute;top:-9px;left:48px;
  width:18px;height:18px;background:#1E1626;
  border-left:1px solid rgba(243,236,247,.16);
  border-top:1px solid rgba(243,236,247,.16);
  border-top-left-radius:4px;transform:rotate(45deg);pointer-events:none}
.ob-guide-text{min-width:0}
.ob-bubble{position:fixed;z-index:70;max-width:min(340px,calc(100vw - 24px));
  background:#1E1626;border:1px solid rgba(243,236,247,.16);border-radius:16px;
  padding:14px 14px 12px;box-shadow:0 12px 40px rgba(0,0,0,.5)}
.ob-bubble.docked{left:12px;right:12px;bottom:calc(76px + env(safe-area-inset-bottom));
  max-width:none;top:auto}
/* first-run setup sheet: centered modal card above the tour chrome */
.ob-bubble.setup-sheet{left:50%;top:50%;transform:translate(-50%,-50%);z-index:72;
  width:min(340px,calc(100vw - 24px))}
#setupDim{position:fixed;inset:0;background:rgba(8,5,12,.62);z-index:71;
  pointer-events:none}
.ob-note{font-size:13px;line-height:1.45;margin:0 0 10px;padding:10px 12px;
  border-radius:10px;background:rgba(242,185,60,.12);
  border:1px solid rgba(242,185,60,.35)}
.ob-x{position:absolute;top:6px;right:8px;background:none;border:0;color:#F3ECF7;
  opacity:.6;font-size:16px;cursor:pointer;padding:6px;line-height:1}
.ob-x:hover{opacity:1}
.ob-step{font-size:11px;letter-spacing:.12em;opacity:.6;margin:2px 0 6px}
.ob-title-sm{font-weight:800;font-size:17px;margin:0 0 6px;color:#F3ECF7;padding-right:24px}
.ob-body-sm{margin:0 0 10px;line-height:1.5;opacity:.9;font-size:14px}

.tour-list{margin-top:10px}
.tour-row{display:flex;align-items:center;gap:12px;padding:12px 2px;position:relative;
  border-bottom:1px solid rgba(76,51,114,.6)}
.tour-row.near{background:linear-gradient(90deg,rgba(242,185,60,.16),rgba(242,185,60,0) 72%);
  margin:0 -10px;padding-left:14px;padding-right:10px;border-radius:12px}
.tour-row.near::before{content:'';position:absolute;left:2px;top:10px;bottom:10px;width:3px;
  border-radius:2px;background:var(--gold);box-shadow:0 0 12px 1px rgba(242,185,60,.85)}
.tdate{width:46px;flex:none;text-align:center}
.tdate .m{font-family:'JetBrains Mono',monospace;font-size:9.5px;letter-spacing:.1em;color:var(--muted)}
.tdate .d{font-family:'Bricolage Grotesque';font-weight:800;font-size:20px;line-height:1.05}
.tour-row.near .tdate .d{color:var(--gold);text-shadow:0 0 14px rgba(242,185,60,.6)}
.tinfo{flex:1;min-width:0}
.tv{font-size:14px;font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.tc{font-size:12px;color:var(--muted);margin-top:2px}
.tmi{font-family:'JetBrains Mono',monospace;font-size:9.5px;color:var(--gold);letter-spacing:.06em}
.thumb.ph.lg{width:64px;height:64px;border-radius:14px;font-size:24px}

/* candidate site picker — richer rows so a bad pick is obvious up front */
.cand{display:flex;align-items:flex-start;gap:10px;padding:11px 12px;cursor:pointer;
  border-bottom:1px solid var(--line)}
.cand:last-child{border-bottom:none}
.cand:active{background:var(--stage)}
.cand-t{font-size:14px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.cand-u{font-family:'JetBrains Mono',monospace;font-size:10.5px;color:var(--magenta);
  margin-top:2px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.cand-s{font-size:11.5px;color:var(--muted);margin-top:3px;line-height:1.35;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
/* A full sentence in the suggestion list (follow by name) — never clamped. */
.cand-note{font-size:12.5px;color:var(--muted);line-height:1.45}
.cand-note b{color:var(--ink)}
.cand-peek{flex:none;color:var(--muted);font-size:15px;padding:2px 4px;text-decoration:none}

/* Matinee: the house lights are on, so pull the neon back */
[data-theme="light"] .panel{border-color:rgba(242,185,60,.8);
  box-shadow:0 0 0 1px rgba(242,185,60,.5),0 6px 20px -6px rgba(0,0,0,.28)}
[data-theme="light"] .modal{border-color:var(--line);
  box-shadow:0 20px 50px -12px rgba(40,20,70,.4)}
[data-theme="light"] .mhero .fade{background:linear-gradient(to top,
  var(--stage) 4%,rgba(255,255,255,.78) 34%,transparent 74%)}
[data-theme="light"] .mname{color:#2A1A47;text-shadow:none}
[data-theme="light"] .pname{color:#F3ECF7}

@media (prefers-reduced-motion:reduce){
  .modal,.modal-scrim,.star-n{transition:none !important}
}

/* ============================================================
   AFTER HOURS — the treatment, applied app-wide.

   Discipline: GRADIENTS carry the mood (surfaces, rules, buttons).
   GLOW is the house treatment — every upcoming card glows gold, and so do
   the active tab and gold CTAs. "Near you" now reads from the pill text,
   not from the card treatment.
   Both themes drive the same rules from these tokens.
   ============================================================ */
:root{
  --top-bg:#2B1A50;
  --body-bg:radial-gradient(125% 62% at 50% 0%, #2B1A50 0%, #1E1236 58%);
  --surf-1:linear-gradient(158deg,#33215C 0%,#2A1A47 58%,#261641 100%);
  --surf-2:linear-gradient(158deg,#402B66,#332150);
  --surf-sunk:linear-gradient(158deg,#241640,#1F1338);
  --rule:linear-gradient(90deg,rgba(242,185,60,.55),rgba(255,92,168,.32),transparent);
  --btn-grad:linear-gradient(135deg,#F7C64F,#E09A2B);
  --edge:inset 0 1px 0 rgba(255,255,255,.055);
  --card-shadow:0 6px 20px -12px rgba(0,0,0,.75);
  --glow-gold:0 0 18px -5px rgba(242,185,60,.65);
  --glow-mag:0 0 18px -5px rgba(255,92,168,.6);
}
[data-theme="light"]{
  --top-bg:#FFFFFF;
  --body-bg:radial-gradient(125% 62% at 50% 0%, #FFFFFF 0%, #F4ECFA 58%);
  --surf-1:linear-gradient(158deg,#FFFFFF 0%,#FBF6FE 60%,#F6EEFC 100%);
  --surf-2:linear-gradient(158deg,#F5ECFC,#EDE3F5);
  --surf-sunk:linear-gradient(158deg,#F9F3FD,#F2E9F9);
  --rule:linear-gradient(90deg,rgba(214,47,138,.42),rgba(233,168,42,.34),transparent);
  --btn-grad:linear-gradient(135deg,#F2BE45,#DE9722);
  --edge:inset 0 1px 0 rgba(255,255,255,.92);
  --card-shadow:0 5px 16px -10px rgba(58,28,92,.30);
  --glow-gold:0 0 14px -5px rgba(217,150,30,.45);
  --glow-mag:0 0 14px -5px rgba(214,47,138,.40);
}

/* ---- base canvas: lit from above, like a stage wash ---- */
body{background:var(--body-bg);background-attachment:fixed}
.appbar{background:var(--top-bg)}
.tabbar{background:var(--house);border-top:none;
  box-shadow:0 -1px 0 var(--line), 0 -14px 28px -20px rgba(0,0,0,.7)}
.tabbar::before{content:'';position:absolute;top:0;left:0;right:0;height:1px;
  background:var(--rule);opacity:.75}
.tab.active{text-shadow:0 0 14px rgba(242,185,60,.45)}
[data-theme="light"] .tab.active{text-shadow:none}
.tab.active svg{filter:drop-shadow(0 0 7px rgba(242,185,60,.5))}
[data-theme="light"] .tab.active svg{filter:none}

/* ---- surfaces ---- */
.card,.moment,.set-row,.stat{background:var(--surf-1);
  box-shadow:var(--edge),var(--card-shadow)}
.suggest{background:var(--surf-2);box-shadow:var(--edge),0 14px 30px -14px rgba(0,0,0,.6)}
.addbox input,.addarea input,.addsource input,.srcfilter-row input,.set-row input{
  background:var(--surf-sunk)}
.avatar{background:var(--surf-2);box-shadow:var(--edge)}

/* ---- section rules: the hairline carries the palette ---- */
.dayhead,.set-head{display:flex;align-items:center;gap:10px}
.dayhead::after,.set-head::after{content:'';flex:1;height:1px;background:var(--rule)}

/* ---- calls to action: lit from above, weighted at the base ---- */
.btn{background:var(--btn-grad);
  box-shadow:var(--glow-gold),inset 0 1px 0 rgba(255,255,255,.38),inset 0 -2px 5px rgba(122,62,8,.28)}
.btn:active{transform:translateY(1px)}
.btn.ghost{background:transparent;box-shadow:none}
.btn.subtle{background:transparent;box-shadow:none}
.tgl.on{background:var(--btn-grad);box-shadow:var(--glow-gold)}

/* ---- chips: solid states earn their glow ---- */
.chip.onsale{background:var(--btn-grad);border-color:transparent;box-shadow:var(--glow-gold)}
.chip.presale{box-shadow:var(--glow-mag)}
.chip.drop{background:linear-gradient(135deg,#57E89A,#28C46F);border-color:transparent}

/* ---- placeholder art tiles read as album art, not empty boxes ---- */
.thumb.ph{background:linear-gradient(140deg,#6B44A8,#3B2568);color:rgba(255,255,255,.55);
  font-family:'Bricolage Grotesque';font-weight:800}
[data-theme="light"] .thumb.ph{background:linear-gradient(140deg,#C9A6F0,#9B6FD0);color:#fff}

/* ---- the radar status card, lit ---- */
.card.status{background:var(--surf-2)}

/* ---- Matinee keeps the panels legible: art stays dark under the scrim ---- */
[data-theme="light"] .panel .pwhere{color:rgba(243,236,247,.85)}
[data-theme="light"] .bignum .m{color:var(--gold);opacity:1}
[data-theme="light"] .panel .scrim{background:linear-gradient(to top,
  rgba(30,18,54,.94) 20%,rgba(30,18,54,.62) 52%,rgba(30,18,54,.34) 82%,rgba(30,18,54,.30) 100%)}
[data-theme="light"] .modal-close{background:rgba(16,8,32,.55);color:#fff}

/* site host on the artist card is a label, not a link — tapping the card
   opens the modal, and the real link lives in there */
.monitor-host{font-size:13px;font-weight:600;color:var(--magenta);margin-top:2px;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:200px}

/* ============================================================
   DUSK — the sky behind the marquee.

   Read the app top-to-bottom as a sunset: a warm sign-glow behind
   the app bar, deep grape through the middle (so cards and body text
   keep their contrast), and an ember horizon down at the tab bar.
   The warmth lives in the CANVAS, not on the reading surfaces.
   ============================================================ */
:root{
  --ember:#FF8A3D;
  --rose:#FF5CA8;

  --top-bg:#50286C;      /* composited colour at the very top of the sky */
  --bottom-bg:#572B43;   /* the horizon, behind the tab bar */

  --body-bg:
    radial-gradient(120% 30% at 50% 100%, rgba(255,138,61,.16) 0%, rgba(255,92,168,.11) 38%, transparent 72%),
    radial-gradient(110% 26% at 50% -4%, rgba(255,92,168,.14) 0%, rgba(192,132,252,.10) 45%, transparent 75%),
    linear-gradient(180deg,#2A1950 0%,#231544 45%,#1E1236 100%);

  /* surfaces pick up a hint of the warmth without losing legibility */
  --surf-1:linear-gradient(158deg,#3A2560 0%,#2C1B4A 58%,#271744 100%);
  --surf-2:linear-gradient(158deg,#482E6B,#3A2456);
  --surf-sunk:linear-gradient(158deg,#261844,#20143A);

  --rule:linear-gradient(90deg,rgba(255,138,61,.60),rgba(255,92,168,.40),transparent);
  --btn-grad:linear-gradient(180deg,#F9CD5E 0%,#F0B73B 48%,#E2982C 100%);
  --glow-ember:0 0 18px -5px rgba(255,138,61,.6);
  --sunset:linear-gradient(140deg,#FF8A3D 0%,#C2478F 44%,#3A2560 100%);
}
[data-theme="light"]{
  --ember:#E8722A;
  --rose:#D62F8A;

  --top-bg:#FAE1ED;
  --bottom-bg:#F7D4DC;

  --body-bg:
    radial-gradient(120% 30% at 50% 100%, rgba(255,150,90,.16) 0%, rgba(255,120,180,.10) 40%, transparent 72%),
    radial-gradient(110% 26% at 50% -4%, rgba(255,140,190,.12) 0%, rgba(192,132,252,.08) 45%, transparent 75%),
    linear-gradient(180deg,#FFF8F4 0%,#FAF2FB 45%,#F4ECFA 100%);

  --surf-1:linear-gradient(158deg,#FFFFFF 0%,#FDF6FB 60%,#F9EFF9 100%);
  --surf-2:linear-gradient(158deg,#FBEDF6,#F3E5F3);
  --surf-sunk:linear-gradient(158deg,#FDF5FA,#F6EDF7);

  --rule:linear-gradient(90deg,rgba(232,114,42,.50),rgba(214,47,138,.38),transparent);
  --btn-grad:linear-gradient(180deg,#F6C653 0%,#EFB135 48%,#DD9423 100%);
  --glow-ember:0 0 14px -5px rgba(232,114,42,.42);
  --sunset:linear-gradient(140deg,#FFA765 0%,#D96FA8 44%,#9B6FD0 100%);
}

/* the horizon sits behind the tab bar */
.tabbar{background:var(--bottom-bg)}

/* a band without a photo gets a real sunset rather than a flat block */
.panel{background:var(--sunset)}
.mhero{background:var(--sunset)}
.thumb.ph{background:var(--sunset);color:rgba(255,255,255,.72)}
[data-theme="light"] .thumb.ph{background:var(--sunset);color:#fff}

/* the Q catches the last of the light */
.logo .q{color:var(--ember);text-shadow:0 0 16px rgba(255,138,61,.55)}
[data-theme="light"] .logo .q{color:var(--rose);text-shadow:none}

/* Matinee tab bar: the horizon is pale, so the labels darken to stay readable
   at 9.5px (the rosy tint alone left them under the contrast floor) */
[data-theme="light"] .tab{color:#5C4B6B}
[data-theme="light"] .tab.active{color:#6B2FA8}

/* ============================================================
   FULL SKY — the gradient runs the whole app, top to bottom.

   Read as a real dusk: night above, violet through the middle,
   ember at the horizon. The app bar and tab bar become glass so the
   sky shows through them instead of capping it off with flat blocks.
   Cards keep their own surfaces, so body text never sits on the sunset.
   ============================================================ */
:root{
  /* Dusk, desaturated at the horizon: violet through the middle, ember
     cooling to cocoa at the tab bar. Extra stops keep the ramp smooth so
     phone displays don't band it; a film-grain overlay (below) dithers
     whatever banding remains. */
  --body-bg:linear-gradient(180deg,
    #1C1138 0%,
    #231546 18%,
    #2F1B52 34%,
    #42225C 48%,
    #552A5C 60%,
    #653152 72%,
    #6E3C4C 84%,
    #6B403F 100%);
  --chrome:rgba(24,13,44,.72);
  --chrome-line:rgba(255,255,255,.07);
}
[data-theme="light"]{
  --body-bg:linear-gradient(180deg,
    #F8F3FD 0%,
    #FAF1FA 22%,
    #FCEEF6 45%,
    #FDEAEE 65%,
    #FDE4E0 82%,
    #FBDCCF 100%);
  --chrome:rgba(255,250,252,.80);
  --chrome-line:rgba(90,50,120,.10);
}

body{background:var(--body-bg);background-attachment:fixed;background-size:100% 100%}

/* Film grain over the sky: dithers gradient banding on phone displays.
   Fixed so it never repaints on scroll; pointer-transparent and faint
   enough to sit over chrome and sheets without dulling text. */
body::after{content:'';position:fixed;inset:0;z-index:9999;pointer-events:none;opacity:.05;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E")}

/* chrome as glass — the sky reads continuously behind it */
.appbar{background:var(--chrome);
  -webkit-backdrop-filter:blur(16px) saturate(1.15);backdrop-filter:blur(16px) saturate(1.15)}
.tabbar{background:var(--chrome);
  -webkit-backdrop-filter:blur(16px) saturate(1.15);backdrop-filter:blur(16px) saturate(1.15);
  box-shadow:0 -1px 0 var(--chrome-line), 0 -14px 30px -22px rgba(0,0,0,.6)}

/* Safari/Firefox without backdrop-filter: fall back to opaque chrome
   so text never lands directly on the bright horizon */
@supports not (backdrop-filter: blur(2px)){
  .appbar{background:#241546}
  .tabbar{background:#653152}
  [data-theme="light"] .appbar{background:#FAF1FA}
}

/* ===== the leaving flow (v13) ===== */

/* "Did you go?" — past shows wait here until they become a stub or get tossed.
   Deliberately quieter than a panel: these are chores, not the main event. */
.didyougo{margin-bottom:18px}
/* Stacked, not side by side: at phone width two buttons beside the text
   truncated the venue to "Hayden Homes Amphitheater · B…" and wrapped
   "View stub" onto two lines. The venue is the part you need to recognise
   the show, so it gets the full width. */
.wentrow{display:flex;flex-direction:column;gap:10px;
  background:var(--stage);border:1px solid var(--line);border-radius:14px;
  padding:12px 14px;margin-bottom:9px;
  transition:transform .3s ease,opacity .3s ease}
/* NOT .meta — that is an existing global (display:flex), which laid the name
   and venue out side by side instead of stacked. */
.wentrow .wmeta{min-width:0}
.wentrow .wmeta b{display:block;font-family:'Bricolage Grotesque';font-weight:800;font-size:16px}
.wentrow .wmeta span{display:block;font-size:12px;color:var(--muted);margin-top:2px}
.wentrow .acts{display:flex;gap:7px;justify-content:flex-end}
.wentrow .btn{white-space:nowrap}
/* A lone button (View stub) still sits right, without stretching. */
.wentrow > .btn{align-self:flex-end}

/* Leaving: a lift and a fade toward the tab bar. The spec's clone-translate-
   scale-rotate was dropped on purpose — it is fiddly on a phone and this tells
   the same story. The stub's arrival is marked by the cream flash already used
   for notification deep links. */
.wentrow.leaving{transform:translateY(-10px) scale(.97);opacity:0}

/* The destination tab pulses, so the card visibly went somewhere. */
@keyframes tabpulse{
  0%,100%{transform:translateY(0)}
  30%{transform:translateY(-4px)}
  60%{transform:translateY(0)}
}
.tab.pulse{animation:tabpulse .9s ease-out 1}
.tab.pulse svg{color:var(--gold)}

/* ===== expanded Upcoming card =====
   This is deliberately in the list, not a modal. The artist image remains the
   full card background and the stronger lower gradient keeps every control
   readable without frosting/obscuring the rest of the app. */
.panel.expanded{min-height:370px;align-items:stretch;cursor:default;
  border-color:rgba(242,185,60,.82);box-shadow:0 16px 40px -18px rgba(0,0,0,.85)}
.panel.expanded > .panel-trigger,.panel.expanded > .star-n{display:none}
.panel.expanded > .scrim{background:rgba(16,8,32,.3)}
.upcoming-detail{position:relative;z-index:3;width:100%;min-height:370px;display:flex;
  align-items:flex-end;overflow:hidden;border-radius:19px}
.upx-bg{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;z-index:-3}
.upx-fallback{position:absolute;inset:0;z-index:-3;display:grid;place-items:center;
  background:linear-gradient(145deg,#5B3A8E,#24143f);color:rgba(243,236,247,.16);
  font-family:'Bricolage Grotesque';font-weight:800;font-size:150px}
.upx-shade{position:absolute;inset:0;z-index:-2;background:linear-gradient(to top,
  rgba(16,8,32,.98) 0%,rgba(16,8,32,.86) 43%,rgba(16,8,32,.45) 72%,rgba(16,8,32,.24) 100%)}
.upx-close{position:absolute;top:12px;right:12px;width:36px;height:36px;border-radius:50%;
  border:1px solid rgba(243,236,247,.35);background:rgba(16,8,32,.78);color:#F3ECF7;
  display:grid;place-items:center;font-size:15px;cursor:pointer}
.upx-body{width:100%;padding:92px 18px 18px;color:#F3ECF7}
.upx-name{font-family:'Bricolage Grotesque';font-weight:800;font-size:32px;line-height:1.02;
  text-shadow:0 2px 18px rgba(0,0,0,.75)}
.upx-when{font-family:'JetBrains Mono',monospace;font-size:11px;font-weight:700;
  letter-spacing:.13em;text-transform:uppercase;color:var(--gold);margin-top:10px}
.upx-where{font-size:15px;font-weight:600;margin-top:8px}
.upx-distance{font-size:12px;color:rgba(243,236,247,.76);margin-top:3px}
.upx-distance.near{color:var(--gold)}
.upx-description{font-size:13px;line-height:1.45;color:rgba(243,236,247,.8);margin:12px 0 0}
.upx-actions{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:9px;margin-top:18px}
.upx-actions .btn{min-width:0;text-align:center;justify-content:center}
.upx-actions .upx-primary{grid-column:1/-1;background:var(--gold);border-color:var(--gold);color:#241505;
  font-weight:800;box-shadow:0 0 20px -8px rgba(242,185,60,.8)}
@media(max-width:390px){.panel.expanded,.upcoming-detail{min-height:350px}.upx-body{padding:72px 14px 14px}}

@media (prefers-reduced-motion:reduce){
  .wentrow,.wentrow.leaving{transition:none}
  .tab.pulse{animation:none}
}

/* ===== Upcoming list controls (v2.2) ===== */
.upcontrols{display:flex;gap:10px;align-items:center;margin:0 0 14px}
/* NOT .chip / .chips — those are already the Discover pills (.chip.onsale,
   .chip.presale, .chip.date, .chip.star, .chip.src). Redefining the base .chip
   here would have restyled every one of them across the app. */
.fchips{display:flex;gap:7px;flex:1;min-width:0;overflow-x:auto;scrollbar-width:none}
.fchips::-webkit-scrollbar{display:none}
.fchip{flex:none;font-family:'JetBrains Mono',monospace;font-size:10px;letter-spacing:.1em;
  text-transform:uppercase;padding:7px 12px;border-radius:999px;cursor:pointer;
  background:transparent;color:var(--muted);border:1px solid var(--line)}
/* The selected filter stays plum — gold is the house treatment on every
   upcoming card now, so plum keeps the active filter distinct. */
.fchip.on{background:var(--stage2);color:var(--ink);border-color:var(--plum)}
.sortsel{flex:none;font-family:'JetBrains Mono',monospace;font-size:10px;letter-spacing:.08em;
  text-transform:uppercase;padding:7px 9px;border-radius:10px;cursor:pointer;
  background:var(--stage);color:var(--ink);border:1px solid var(--line)}

/* Sticky month headers, only while sorted by date. */
.monthhead{position:sticky;top:0;z-index:5;
  font-family:'JetBrains Mono',monospace;font-size:10px;letter-spacing:.2em;
  text-transform:uppercase;color:var(--gold-text);
  background:var(--house);padding:9px 0 7px;margin-bottom:4px}

/* "TONIGHT" / "IN 3 DAYS". Plum outline stays distinct from the house gold —
   it needs a transparent fill now that the base pill is gold. */
.pill.soon{border-color:var(--plum);color:var(--plum);background:transparent;box-shadow:none}

/* ===== compact Local Scene controls ===== */
.local-scene-card{background:var(--stage);border:1px solid var(--line);border-radius:14px;
  padding:8px 9px;margin-bottom:9px}
.local-scene-head{display:flex;align-items:center;justify-content:space-between;gap:8px;
  font-family:'JetBrains Mono',monospace;font-size:9px;font-weight:700;letter-spacing:.11em;color:var(--muted);line-height:1}
.location-toggle-label{display:flex;align-items:center;gap:6px;letter-spacing:.03em;text-transform:none}
.mini-switch{position:relative;width:34px;height:20px;padding:0;border:1px solid var(--line);border-radius:999px;
  background:var(--house);cursor:pointer;flex:none;transition:background .15s,border-color .15s}
.mini-switch span{position:absolute;top:2px;left:2px;width:14px;height:14px;border-radius:50%;
  background:var(--muted);transition:transform .15s,background .15s}
.mini-switch.on{background:var(--stage2);border-color:var(--plum)}
.mini-switch.on span{transform:translateX(14px);background:var(--plum)}
.mini-switch:focus-visible,.location-icon-btn:focus-visible,.location-status-dot:focus-visible,.scene-manage-link:focus-visible,.scope-chip:focus-visible{
  outline:2px solid var(--gold);outline-offset:2px}
/* Collapsed scope chip: one-line area summary; the full controls expand below it. */
.scope-chip-row{display:flex;align-items:center;gap:6px}
.scope-chip{flex:1;min-width:0;display:flex;align-items:center;justify-content:space-between;gap:6px;
  padding:7px 9px;border-radius:8px;border:1px solid var(--line);background:var(--house);
  color:var(--ink);font:12.5px 'Inter',sans-serif;cursor:pointer;text-align:left}
.scope-chip-label{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.scope-chip-chev{flex:none;color:var(--muted);font-size:11px;transition:transform .15s}
.scope-chip[aria-expanded="true"] .scope-chip-chev{transform:rotate(180deg)}
.local-scene-expanded{margin-top:8px}
.local-scene-manage{display:flex;justify-content:flex-end;margin-top:4px}
/* ===== the way into Scene =====
   A one-line strip between the Local Scene card and the scope bar. It echoes
   .scopebar's mono caption so it reads as part of that band of chrome, but it
   is a real control: tappable, gold, chevroned. It carries a COUNT, because the
   count is the whole mechanism — "11 nearby" is the fact the user did not have,
   and it is the reason to tap. Deliberately not a pill: Discover already has a
   pill row that FILTERS the feed, and this replaces it. */
.scene-strip{display:flex;align-items:center;justify-content:space-between;gap:8px;width:100%;
  margin:0 0 10px;padding:9px 11px;border-radius:10px;cursor:pointer;
  background:var(--stage);border:1px solid var(--line);color:var(--gold-text);text-align:left}
.scene-strip .mono{font-family:'JetBrains Mono',monospace;font-size:10px;letter-spacing:.1em;
  text-transform:uppercase;line-height:1.35}
.scene-strip .mono b{color:var(--ink);font-weight:700}
.scene-strip-chev{flex:none;font-size:15px;color:var(--gold-text)}
.scene-strip:active{transform:translateY(1px)}
.scene-back{display:flex;align-items:center;gap:8px;margin:2px 0 12px;padding:6px 2px;
  background:none;border:0;color:var(--gold-text);font:inherit;cursor:pointer}
.scene-back span:first-child{font-size:17px;line-height:1}
.local-scene-controls{display:flex;align-items:center;gap:5px;margin-top:7px;position:relative}
.local-scene-city{position:relative;flex:1;min-width:0}
.local-scene-city input{width:100%;height:34px;padding:6px 9px;border-radius:8px;border:1px solid var(--line);
  background:var(--house);color:var(--ink);font:13px 'Inter',sans-serif;margin:0}
.local-scene-city input:focus{outline:2px solid var(--gold-dim);outline-offset:1px}
.local-scene-city .suggest{top:34px}
.location-icon-btn{width:32px;height:32px;padding:0;border-radius:8px;border:1px solid var(--line);
  background:var(--house);color:var(--gold-text);font-size:17px;line-height:1;cursor:pointer;flex:none}
.location-icon-btn:disabled{opacity:.3;cursor:default}
.local-scene-radius{display:flex;gap:2px;flex:none;overflow:visible}
.local-scene-radius .fchip{min-width:28px;padding:6px 5px;border-radius:7px;font-size:8.5px;letter-spacing:0}
.location-status-dot{width:28px;height:28px;margin:-7px 0;padding:0;border:0;background:transparent;cursor:pointer;line-height:1;flex:none}
.location-status-dot span{font-size:14px}
.scene-manage-link{padding:5px 2px;border:0;background:transparent;color:var(--gold-text);font:inherit;cursor:pointer;text-decoration:underline;flex:none}
.location-sharing-row{padding:9px 12px}
.location-sharing-row .s{font-size:9.5px}

/* Favorite artists can be worth a road trip; keep this separate from the
   tight Local Scene venue radius. */
.fav-radius-controls{display:flex;align-items:center;justify-content:flex-end;gap:8px;margin:-2px 0 10px}
.fav-radius-controls[hidden]{display:none}
.fav-radius-label{font:9px 'JetBrains Mono',monospace;letter-spacing:.1em;color:var(--muted)}

/* ===== bug report beetle ===== */
/* Outline stag beetle, no color: currentColor in both themes. Small round button
   at the top-right of every card, next to the save star. States stay neutral
   — hover brightens, active presses; never red. */
.card-actions{display:flex;align-items:center;gap:2px;flex:none}
.bug-btn{background:none;border:1px solid var(--line);border-radius:50%;
  width:30px;height:30px;display:grid;place-items:center;cursor:pointer;
  color:var(--muted);padding:5px;flex:none}
.bug-btn svg{width:100%;height:100%;display:block}
.bug-btn:hover{color:var(--ink);border-color:var(--muted)}
.bug-btn:active{transform:scale(.88)}
/* ===== bug report sheet ===== */
.bug-sheet-body{padding:18px;display:flex;flex-direction:column;gap:12px;min-height:0}
/* min-height:0 lets the sheet shrink inside .modal (flex column, 86vh max),
   so #updatesList can scroll instead of pushing the action buttons off-screen. */
.bug-sheet-body .t{font-family:'Bricolage Grotesque',serif;font-weight:800;font-size:20px}
.bug-sheet-body .s{font:9px 'JetBrains Mono',monospace;letter-spacing:.12em;color:var(--muted)}
/* "Fresh on Showbound" sheet: full-body Markie announces the changelog entries. */
.updates-head{display:flex;gap:14px;align-items:center}
.updates-head .updates-close{margin-left:auto}
.updates-markie{width:76px;height:auto;flex:none;filter:drop-shadow(0 4px 10px rgba(0,0,0,.35))}
#updatesList{overflow-y:auto;min-height:0}
.update-entry{padding:10px 2px;border-top:1px solid var(--line)}
.update-entry:first-child{border-top:0;padding-top:2px}
.update-date{font:9px 'JetBrains Mono',monospace;letter-spacing:.12em;color:var(--muted)}
.update-title{font-weight:700;margin:3px 0 4px;font-size:15px}
.update-body{font-size:14px;line-height:1.5;color:var(--text-dim,#cfc6e0);white-space:pre-line}
/* pre-line: consolidated digest entries ("N updates tonight") render one
   highlight per line. */
.seg{display:flex;background:var(--stage2,#2A1A47);border:1px solid var(--line);
  border-radius:12px;padding:3px;gap:3px}
.seg button{flex:1;background:none;border:none;border-radius:9px;padding:9px 0;
  font:700 12px 'JetBrains Mono',monospace;color:var(--muted);cursor:pointer}
.seg button.on{background:var(--gold);color:#241505}
.chip-toggle{background:none;border:1px solid var(--gold-dim);border-radius:12px;
  padding:10px 12px;font:600 13px 'Inter',sans-serif;color:var(--gold);cursor:pointer;
  text-align:center;width:100%}
.chip-toggle.on{border-color:var(--gold);color:var(--gold-text,var(--gold));background:rgba(212,175,55,.08)}
.chip-toggle[hidden]{display:none}
.shot-strip{display:flex;gap:8px;flex-wrap:wrap;margin:2px 0 8px}
.shot-strip[hidden]{display:none}
.shot{position:relative;width:72px;height:72px;border-radius:10px;overflow:hidden;
  border:1px solid var(--line);flex:none}
.shot img{width:100%;height:100%;object-fit:cover;display:block}
.shot button{position:absolute;top:2px;right:2px;width:22px;height:22px;border-radius:50%;
  border:none;background:rgba(0,0,0,.65);color:#fff;font-size:14px;line-height:1;cursor:pointer}
.bug-attach-row{align-items:center}
.bug-attach-row .s{margin-left:auto}
/* Owner triage: read every report in-app before the pull. */
.triage-list{display:flex;flex-direction:column;gap:10px;margin:8px 0 16px}
.triage-empty{color:var(--ink-dim);font-size:13px;padding:6px 2px}
.triage-card{border:1px solid var(--line);border-radius:14px;padding:12px 14px;
  background:var(--surf-1)}
.triage-head{display:flex;align-items:center;gap:8px;margin-bottom:6px}
.kind-chip{font-size:10px;font-weight:700;letter-spacing:.08em;border-radius:6px;
  padding:2px 7px;border:1px solid var(--gold-dim);color:var(--gold-text)}
.kind-chip.idea{border-color:#6aa5ff;color:#9cc0ff}
.kind-chip.broken{border-color:#e0705f;color:#e0705f}
.triage-meta{margin-left:auto;font-size:12px;color:var(--ink-dim)}
.triage-note{margin:0 0 6px;font-size:14px;white-space:pre-wrap}
.triage-ctx{font-size:12px;color:var(--ink-dim);margin-bottom:8px;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.triage-shots{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:8px}
.triage-shots img{width:72px;height:72px;object-fit:cover;border-radius:10px;
  border:1px solid var(--line)}
.triage-actions{display:flex;gap:8px;flex-wrap:wrap}
.triage-decline{margin-top:8px;display:flex;flex-direction:column;gap:8px}
.triage-decline[hidden]{display:none}
.triage-decline input{background:var(--stage2,#2A1A47);border:1px solid var(--line);
  border-radius:10px;color:var(--ink);font:400 14px 'Inter',sans-serif;padding:9px 12px}
/* Owner reply on a triage card + the reply composer. */
.triage-response{margin-top:8px;padding:8px 10px;border:1px solid var(--line);border-radius:10px;
  background:rgba(212,175,55,.08);font-size:13px;color:var(--ink);white-space:pre-wrap}
/* Conversation thread on a report card: reporter follow-ups and owner
   replies, oldest-first. Owner messages get the gold tint. */
.triage-thread{margin-top:8px;display:flex;flex-direction:column;gap:6px}
.triage-msg{padding:8px 10px;border:1px solid var(--line);border-radius:10px;
  background:var(--stage2,#2A1A47);font-size:13px;color:var(--ink);white-space:pre-wrap}
.triage-msg .who{font-weight:700}
.triage-msg .when{font-weight:400;opacity:.6}
.triage-msg.owner{background:rgba(212,175,55,.08)}
.triage-replybox{margin-top:8px;display:flex;flex-direction:column;gap:8px}
.triage-replybox textarea{background:var(--stage2,#2A1A47);border:1px solid var(--line);
  border-radius:10px;color:var(--ink);font:400 14px 'Inter',sans-serif;padding:9px 12px;min-height:52px;resize:vertical}
.triage-replybox .triage-actions{justify-content:flex-end}
.kind-chip.newreply{background:#ff5a4e;border-color:#ff5a4e;color:#fff}
.triage-respond{margin-top:8px;display:flex;flex-direction:column;gap:8px}
.triage-respond[hidden]{display:none}
.triage-respond textarea{background:var(--stage2,#2A1A47);border:1px solid var(--line);
  border-radius:10px;color:var(--ink);font:400 14px 'Inter',sans-serif;padding:9px 12px;min-height:64px;resize:vertical}
/* Full-size triage screenshot: fixed overlay, tap anywhere to close. */
#shotViewer{position:fixed;inset:0;z-index:200;background:rgba(0,0,0,.88);
  display:flex;align-items:center;justify-content:center;padding:16px}
#shotViewer[hidden]{display:none}
#shotViewer img{max-width:94vw;max-height:94vh;border-radius:12px}
#bugNote{width:100%;background:var(--stage2,#2A1A47);border:1px solid var(--line);
  border-radius:12px;color:var(--ink);font:400 14px 'Inter',sans-serif;
  padding:10px 12px;resize:vertical;min-height:72px}
#bugNote:focus{outline:2px solid var(--gold-dim);outline-offset:1px;border-color:var(--gold-dim)}
.sheet-row{display:flex;gap:8px;justify-content:flex-end}

/* ===== roadies (beta) ===== */
.roadie-code{font-size:19px;font-weight:700;letter-spacing:1px;font-family:'JetBrains Mono',monospace}
/* Roadies D: the QR stays black on white in both themes — phone cameras read
   dark-on-light most reliably, and the quiet zone is part of the code. */
.roadie-qr{background:#fff;border-radius:14px;padding:10px;margin:10px auto 4px;width:min(260px,100%);aspect-ratio:1}
.roadie-qr svg{display:block;width:100%;height:100%}
.roadie-qr-code{text-align:center;margin:8px 0 14px}
#roadieQrSheet .rank-head .s{font-family:'Inter',sans-serif;text-transform:none;letter-spacing:0;font-size:13px;line-height:1.4;margin-top:4px}
.roadie-note{margin-top:8px}
.roadie-av{position:relative;flex:none;width:42px;height:42px;display:inline-block}
.roadie-av .thumb{position:absolute;inset:0;width:100%;height:100%}
.roadie-row{display:flex;align-items:center;gap:11px;padding:9px 0}
.roadie-row + .roadie-row{border-top:1px solid var(--line)}
.roadie-tap{display:flex;align-items:center;gap:11px;min-width:0;flex:1;cursor:pointer}
.roadie-who{min-width:0;flex:1}
.roadie-actions{display:flex;gap:6px;flex:none}
.roadie-card{padding:10px 12px;margin-bottom:8px}
.roadie-head{display:flex;align-items:center;gap:12px}
.roadie-detail-name{font-size:18px;font-weight:600}
.roadie-show{margin-bottom:8px}
.roadie-row .t,.roadie-show .t,.roadie-head .t,.roadie-tap .t{font-size:14.5px;font-weight:600}
.roadie-row .s,.roadie-show .s,.roadie-head .s,.roadie-tap .s{font-size:11.5px;color:var(--muted);font-family:"JetBrains Mono",monospace;margin-top:2px}

/* ===== branded dialogs (replace native alert/confirm/prompt) ===== */
.dlg-overlay{position:fixed;inset:0;z-index:100;display:flex;align-items:center;justify-content:center;
  background:rgba(12,5,24,.72);backdrop-filter:blur(3px);-webkit-backdrop-filter:blur(3px);padding:24px}
.dlg-card{width:100%;max-width:340px;background:var(--stage);border:1px solid var(--line);
  border-radius:var(--radius);padding:20px;box-shadow:0 18px 60px rgba(0,0,0,.55)}
.dlg-title{font-family:'Bricolage Grotesque',sans-serif;font-weight:800;font-size:17px;margin-bottom:8px}
.dlg-msg{font-size:14.5px;line-height:1.55;color:var(--ink);white-space:pre-line;overflow-wrap:break-word}
.dlg-input{width:100%;margin-top:12px;background:var(--house);border:1px solid var(--line);
  border-radius:10px;color:var(--ink);font-size:15px;padding:10px 12px;font-family:inherit}
.dlg-input:focus{outline:none;border-color:var(--magenta)}
.dlg-actions{display:flex;justify-content:flex-end;gap:10px;margin-top:18px}

/* ===== Stubs PR-3: three add doors (import card, add menu, add sheet) ===== */
/* The single add door. It sits above the stats so it is the first thing on the
   tab, rather than three buttons stranded below the whole ticket wall. */
.stub-add-all{width:100%;margin:0 0 12px}

/* The chooser rows inside the sheet. */
.addrows{display:flex;flex-direction:column;gap:8px}
.addrow{display:flex;align-items:flex-start;gap:11px;width:100%;text-align:left;
  padding:13px 14px;border-radius:14px;border:1px solid var(--line);
  background:var(--house);color:var(--ink);cursor:pointer;position:relative;overflow:hidden}
.addrow:hover,.addrow:focus-within,.addrow:focus-visible{border-color:var(--plum);outline:none}
.addrow:active{background:rgba(192,132,252,.1)}
.addrow-i{font-size:17px;line-height:1.2;flex:none}
.addrow-t{display:block;min-width:0}
.addrow-t b{display:block;font-size:14px;margin-bottom:2px}
.addrow-t small{display:block;font-size:11.5px;color:var(--muted);line-height:1.45}
/* The photo row is the hero — it is the one that adds years in a single go. */
.addrow:first-child{border-color:rgba(192,132,252,.45);background:rgba(192,132,252,.07)}
#addSheet .modal{padding:0;max-height:86vh;display:flex;flex-direction:column}
.addsheet-head{display:flex;align-items:center;justify-content:space-between;
  padding:14px 16px 10px;border-bottom:1px solid var(--line)}
.addsheet-head b{font-size:16px}
.addsheet-main{padding:14px 16px 16px;overflow-y:auto}
.qa-form input[type=text],.qa-form input[type=date]{margin-bottom:8px}
.qa-another{display:flex;align-items:center;gap:8px;font-size:13px;color:var(--muted);margin:2px 0 4px}
.qa-photo{width:100%;max-height:220px;object-fit:contain;border-radius:10px;
  border:1px solid var(--line);margin-bottom:10px;background:var(--house)}
.ocr-status{text-align:center;padding:18px 8px;color:var(--muted);font-size:13.5px;line-height:1.5}
.ocr-status .row{justify-content:center;margin-top:10px}
.ob-spin{width:26px;height:26px;margin:0 auto 10px;border:3px solid var(--line);
  border-top-color:var(--gold);border-radius:50%;animation:obspin .8s linear infinite}
@keyframes obspin{to{transform:rotate(360deg)}}
.ocr-lede{font-size:13px;color:var(--muted);line-height:1.5;margin:0 0 10px}
.ocr-rows{display:flex;flex-direction:column;gap:8px}
.ocr-row{display:flex;gap:10px;align-items:flex-start;background:var(--house);
  border:1px solid var(--line);border-radius:12px;padding:10px;cursor:pointer}
.ocr-row.is-dupe{opacity:.55;cursor:default}
.ocr-check{margin-top:6px;flex:none;width:18px;height:18px;accent-color:var(--gold)}
.ocr-fields{flex:1;min-width:0;display:flex;flex-direction:column;gap:6px}
.ocr-fields input[type=text],.ocr-fields input[type=date]{width:100%;background:var(--stage);
  border:1px solid var(--line);border-radius:8px;color:var(--ink);font-size:13.5px;padding:7px 9px}
.ocr-fields input:disabled{opacity:.6}
.ocr-sub{display:flex;gap:6px}
.ocr-sub input[type=date]{max-width:150px;flex:none}
.ocr-dupe{font-size:11px;color:var(--gold-text);font-family:'JetBrains Mono',monospace}
/* The raw OCR text, collapsed. A wrong row is hard to explain without it. */
.ocr-raw{margin-top:10px}
.ocr-raw summary{color:var(--muted);font-size:11.5px;cursor:pointer}
.ocr-raw pre{margin:6px 0 0;padding:9px 10px;border-radius:9px;background:var(--house);
  border:1px solid var(--line);color:var(--muted);font-size:10.5px;line-height:1.5;
  white-space:pre-wrap;word-break:break-word;max-height:190px;overflow:auto}
.ocr-note{font-size:11px;color:var(--muted);font-style:italic}
.search-row{display:flex;gap:10px;align-items:center;background:var(--house);
  border:1px solid var(--line);border-radius:12px;padding:10px;margin-bottom:8px}
.search-thumb{width:44px;height:44px;flex:none;border-radius:10px;object-fit:cover;background:var(--stage)}
.search-thumb.search-fallback{display:grid;place-items:center;font-size:20px;font-weight:800;color:var(--gold-text)}
.search-meta{flex:1;min-width:0;display:flex;flex-direction:column;gap:1px;font-size:13px}
.search-meta b{font-size:14px}
.search-meta span{color:var(--muted);font-size:12px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.search-date{font-family:'JetBrains Mono',monospace}

/* ===== artist image override =====
   The ✎ sits on the thumbnail the way it does on a stub's artwork, so "this
   picture is changeable" reads the same in both places. */
.artist-art{position:relative;flex:none}
.artist-art .artedit{position:absolute;bottom:-3px;right:-3px;width:20px;height:20px;
  border-radius:50%;background:var(--stage2);color:var(--ink);border:1px solid var(--line);
  font-size:10px;line-height:1;display:grid;place-items:center;cursor:pointer;padding:0;z-index:2;
  transition:background .15s,color .15s,border-color .15s}
.artist-art .artedit::after{content:"";position:absolute;inset:-10px}
.artist-art .artedit:hover,.artist-art .artedit:focus-visible{background:var(--plum);
  color:#fff;border-color:var(--plum);outline:none}

.artist-imgpick{padding:10px 0 2px;border-top:1px solid var(--line);margin-top:10px}
/* A horizontal strip rather than a grid: five candidates at phone width would
   otherwise push the card taller than the artist it belongs to. */
.artist-imgrow{display:flex;gap:8px;overflow-x:auto;padding:8px 0 2px;scrollbar-width:none}
.artist-imgrow::-webkit-scrollbar{display:none}
.artist-imgopt{flex:none;width:64px;height:64px;padding:0;border-radius:12px;overflow:hidden;
  border:1px solid var(--line);background:var(--stage2);cursor:pointer}
.artist-imgopt img{width:100%;height:100%;object-fit:cover;display:block}
/* Plum, not gold: gold is the "near you" signal and a picked thumbnail is not
   that kind of meaning. */
.artist-imgopt.on{border-color:var(--plum);box-shadow:0 0 0 1px var(--plum)}

/* Venue cards — Find venues results and Your scene share one look (Phil,
   2026-10-07: "I like the look of the top 15 better than the your scene list"). */
.venue-card{display:flex;gap:12px;align-items:flex-start;padding:12px;margin-bottom:10px}
.venue-card-body{flex:1;min-width:0}
.venue-card-head{display:flex;align-items:flex-start;justify-content:space-between;gap:10px}
.venue-card-name{font-weight:700;font-size:16px;line-height:1.25;color:var(--ink);text-decoration:none;
  overflow-wrap:anywhere}
a.venue-card-name:visited{color:var(--ink)}
.venue-card-head .tgl{flex:none;margin-top:1px}
.venue-card-sub{font-family:'JetBrains Mono',monospace;font-size:11px;color:var(--muted);margin-top:3px;
  overflow-wrap:anywhere}
.venue-card-site{display:inline-block;font-size:12px;margin-top:4px;white-space:nowrap}
.venue-card-status{font-family:'JetBrains Mono',monospace;font-size:10px;color:var(--muted);opacity:.8;
  margin-top:3px;text-transform:uppercase;letter-spacing:.04em}
.venue-card-actions{display:flex;flex-wrap:wrap;align-items:center;gap:8px;margin-top:8px}
.venue-card-actions.artist-actions{gap:2px;margin:4px 0 0 -8px}
.venue-following{font-family:'JetBrains Mono',monospace;font-size:11px;color:var(--green)}
.venue-logo{position:relative;overflow:hidden}
.venue-logo img{position:absolute;inset:0;width:100%;height:100%;object-fit:contain;background:#fff;padding:3px}
.venue-card.unreadable{opacity:.6}
.scene-hidden-toggle{display:block;width:100%;margin:6px 0 10px;padding:10px 12px;border-radius:var(--radius);
  background:transparent;border:1px dashed var(--line);color:var(--muted);text-align:left;
  font-family:'JetBrains Mono',monospace;font-size:11px;cursor:pointer}

/* Fav Spots (Phil, 2026-10-08): a star on each Your scene card, the top three
   starred at the head of the page, the rest in the ranking sheet. */
.venue-card-controls{display:flex;align-items:center;gap:6px;flex:none}
.fav-star{background:transparent;border:none;color:var(--muted);font-size:22px;line-height:1;
  padding:2px 4px;cursor:pointer;flex:none}
.fav-star.on{color:var(--gold)}
.fav-spot-row{display:flex;align-items:center;gap:10px;padding:8px 10px;margin-bottom:6px;
  background:var(--stage);border:1px solid var(--line);border-radius:var(--radius)}
.fav-spot-body{flex:1;min-width:0}
.fav-spot-name{font-weight:700;font-size:14px;color:var(--ink);text-decoration:none;overflow-wrap:anywhere}
a.fav-spot-name:visited{color:var(--ink)}
.fav-spot-sub{font-family:'JetBrains Mono',monospace;font-size:10.5px;color:var(--muted);margin-top:2px}
.fav-spot-all{background:transparent;border:none;color:var(--gold);font-size:12px;padding:4px 2px;cursor:pointer}
.rank-row .fav-star{font-size:18px;margin-left:4px}

/* Your scene follows you (PR 3): areas you have left, folded at the bottom,
   and the one-time offer for somewhere new. */
.saved-area{display:flex;align-items:center;gap:8px;margin-bottom:8px}
.saved-area-head{flex:1;display:flex;justify-content:space-between;align-items:center;padding:10px 12px;
  background:var(--stage);border:1px solid var(--line);border-radius:var(--radius);color:var(--ink);
  font-size:14px;font-weight:600;cursor:pointer;text-align:left}
.area-offer-actions{display:flex;flex-wrap:wrap;gap:8px;align-items:center;margin:12px 0 4px}
#areaOfferSheet .rank-head .s{font-family:'Inter',sans-serif;text-transform:none;letter-spacing:0;font-size:13px;line-height:1.4;margin-top:4px}
