/* ==========================================================================
   Fonts — self-hosted (no CDN at the venue). latin + latin-ext subsets so
   Ł (U+0141) and ¥ (U+00A5) render correctly. font-display:swap.
   ========================================================================== */
@font-face {
  font-family: 'Space Grotesk'; font-weight: 400; font-style: normal; font-display: swap;
  src: url('/fonts/space-grotesk-latin-400-normal.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Space Grotesk'; font-weight: 400; font-style: normal; font-display: swap;
  src: url('/fonts/space-grotesk-latin-ext-400-normal.woff2') format('woff2');
  unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Space Grotesk'; font-weight: 500; font-style: normal; font-display: swap;
  src: url('/fonts/space-grotesk-latin-500-normal.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Space Grotesk'; font-weight: 500; font-style: normal; font-display: swap;
  src: url('/fonts/space-grotesk-latin-ext-500-normal.woff2') format('woff2');
  unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Space Grotesk'; font-weight: 600; font-style: normal; font-display: swap;
  src: url('/fonts/space-grotesk-latin-600-normal.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Space Grotesk'; font-weight: 600; font-style: normal; font-display: swap;
  src: url('/fonts/space-grotesk-latin-ext-600-normal.woff2') format('woff2');
  unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Space Grotesk'; font-weight: 700; font-style: normal; font-display: swap;
  src: url('/fonts/space-grotesk-latin-700-normal.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Space Grotesk'; font-weight: 700; font-style: normal; font-display: swap;
  src: url('/fonts/space-grotesk-latin-ext-700-normal.woff2') format('woff2');
  unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'IBM Plex Mono'; font-weight: 400; font-style: normal; font-display: swap;
  src: url('/fonts/ibm-plex-mono-latin-400-normal.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'IBM Plex Mono'; font-weight: 400; font-style: normal; font-display: swap;
  src: url('/fonts/ibm-plex-mono-latin-ext-400-normal.woff2') format('woff2');
  unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'IBM Plex Mono'; font-weight: 500; font-style: normal; font-display: swap;
  src: url('/fonts/ibm-plex-mono-latin-500-normal.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'IBM Plex Mono'; font-weight: 500; font-style: normal; font-display: swap;
  src: url('/fonts/ibm-plex-mono-latin-ext-500-normal.woff2') format('woff2');
  unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'IBM Plex Mono'; font-weight: 600; font-style: normal; font-display: swap;
  src: url('/fonts/ibm-plex-mono-latin-600-normal.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'IBM Plex Mono'; font-weight: 600; font-style: normal; font-display: swap;
  src: url('/fonts/ibm-plex-mono-latin-ext-600-normal.woff2') format('woff2');
  unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* ==========================================================================
   Design tokens — settled in prototype/veld2026schedule.html. Do not change.
   ========================================================================== */
:root{
  --ink:#0A0514;
  --panel:#150C28;
  --panel2:#1D1136;
  --line:#2E2050;
  --text:#F0EAFB;
  --dim:#9385B5;
  --main:#FF5324;
  --bass:#17E0D2;
  --sirkus:#FF2E88;
  --clash:#FFC53D;
  --ppm:1.25;
}

*{box-sizing:border-box;-webkit-tap-highlight-color:transparent;}
html,body{margin:0;padding:0;}
body{
  background:var(--ink);
  color:var(--text);
  font-family:'Space Grotesk',system-ui,-apple-system,sans-serif;
  font-size:15px;
  line-height:1.35;
  overscroll-behavior-y:none;
  -webkit-text-size-adjust:100%;
}
body::before{
  content:'';position:fixed;inset:0;pointer-events:none;z-index:0;
  background:
    radial-gradient(120% 55% at 8% 0%, rgba(255,83,36,.10), transparent 60%),
    radial-gradient(120% 55% at 92% 0%, rgba(255,46,136,.10), transparent 60%),
    radial-gradient(140% 40% at 50% 100%, rgba(23,224,210,.07), transparent 65%);
}
/* padding-bottom reserves room for the fixed .bottomstack (day control +
   tab bar); --bottomh is measured live by syncChromeHeights() in app.js so
   it tracks actual content (long day labels, safe-area inset) instead of
   guessing. The 96px fallback covers pre-JS paint / --bottomh unset. */
#app{position:relative;z-index:1;max-width:720px;margin:0 auto;padding-bottom:calc(var(--bottomh, 96px) + 20px);}

button{font-family:inherit;}
:focus-visible{outline:2px solid var(--bass);outline-offset:2px;}

/* ---------- header ---------- */
/* Slimmed to the brand row only (Phase C thumb-zone redesign) — day switcher
   and view tabs moved to the fixed bottom stack (see .bottomstack below),
   both within one thumb-reachable block. */
header{
  position:sticky;top:0;z-index:40;
  background:rgba(10,5,20,.93);
  backdrop-filter:blur(14px);
  border-bottom:1px solid var(--line);
  padding-top:env(safe-area-inset-top,0px);
}
.brand{
  display:flex;align-items:baseline;gap:10px;
  padding:10px 14px 8px;
}
.brand h1{
  margin:0;font-size:19px;font-weight:700;letter-spacing:.14em;
}
.brand h1 em{font-style:normal;color:var(--main);}
.brand span{
  font-family:'IBM Plex Mono',monospace;font-size:11px;
  letter-spacing:.16em;color:var(--dim);text-transform:uppercase;
}
.brand .grow{flex:1;}
/* Phase C chrome budget: the header row's height used to be driven by
   #menuBtn's own 44x44 box (a real touch-target minimum) — with the day
   switcher and view tabs gone, that button alone was keeping the slimmed
   header taller than needed. Same fix already used for .chip below: the
   VISIBLE box matches .menu-glyph (30x30), and a ::after pseudo-element
   expands the actual tappable area to 44x44 without adding to layout height. */
#menuBtn{
  position:relative;
  appearance:none;border:0;background:transparent;color:var(--text);
  width:30px;height:30px;padding:0;font-size:16px;cursor:pointer;line-height:1;
  align-self:center;flex-shrink:0;
  display:flex;align-items:center;justify-content:center;
}
#menuBtn::after{
  content:'';position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);
  width:44px;height:44px;
}
.menu-glyph{
  position:relative;
  display:inline-flex;align-items:center;justify-content:center;
  width:30px;height:30px;border:1px solid var(--line);border-radius:8px;
}
.menu-dot{
  position:absolute;top:1px;right:1px;width:8px;height:8px;border-radius:50%;
  background:var(--main);animation:menuPulse 1.6s ease-out infinite;
}
.menu-dot[hidden]{display:none;}
@keyframes menuPulse{
  0%{box-shadow:0 0 0 0 rgba(255,83,36,.55);}
  70%{box-shadow:0 0 0 7px rgba(255,83,36,0);}
  100%{box-shadow:0 0 0 0 rgba(255,83,36,0);}
}
/* Sync/offline pill — relocated from the old .meta row into the brand row,
   right after the location text (item 3: "sync pill relocates next to the
   brand span"). */
.sync-pill{
  font-family:'IBM Plex Mono',monospace;font-size:11px;letter-spacing:.02em;
  color:var(--dim);white-space:nowrap;flex-shrink:0;
  opacity:1;transition:opacity .3s ease;
}
.sync-pill.synced{color:var(--bass);}
.sync-pill.fading{opacity:0;}
.sync-pill[hidden]{display:none;}

/* ---------- grid-top meta line ---------- */
/* "N sets · N picked" — was the header .meta row's #metatext; now a slim,
   non-sticky line at the top of the grid area (scrolls away with content,
   per item 3's grid-area-top option). Clash count moved to the Grid tab
   badge (see .tab-badge below) since the old #clashbtn is gone. */
.gridmeta{
  padding:10px 14px 2px;
  font-family:'IBM Plex Mono',monospace;font-size:12px;color:var(--dim);
}

/* ---------- crew header chip (Crew view only) ---------- */
/* Crew switcher pill (was header .meta's #groupPill) + Invite button (item
   5), shown only while viewing an active crew. */
.crew-header{display:flex;align-items:center;gap:8px;margin:12px 14px 0;}
.crew-header[hidden]{display:none;}
.group-pill{
  appearance:none;border:1px solid var(--line);background:var(--panel2);color:var(--text);
  font-family:'IBM Plex Mono',monospace;font-size:12px;letter-spacing:.02em;
  padding:7px 11px;border-radius:20px;cursor:pointer;white-space:nowrap;
}
.btn-invite{
  appearance:none;border:1px solid var(--main);background:rgba(255,83,36,.12);color:var(--main);
  font-family:'IBM Plex Mono',monospace;font-size:11.5px;font-weight:700;letter-spacing:.04em;
  padding:7px 13px;border-radius:20px;cursor:pointer;white-space:nowrap;
}

/* ---------- fixed bottom chrome: day control + tab bar ---------- */
/* One thumb-reachable block (Phase C): the day segmented control docks
   directly above the 4-tab bottom tab bar. Same translucent-ink + blur
   treatment as the header, mirrored (border-top instead of border-bottom). */
.bottomstack{
  position:fixed;left:0;right:0;bottom:0;z-index:60;
  max-width:720px;margin:0 auto;
  background:rgba(10,5,20,.93);
  backdrop-filter:blur(14px);
  border-top:1px solid var(--line);
}
.daybar{
  display:grid;grid-template-columns:repeat(3,1fr);gap:6px;
  padding:7px 10px;border-bottom:1px solid var(--line);
}
.daybar .day{
  appearance:none;border:1px solid var(--line);background:transparent;
  color:var(--dim);font-family:'Space Grotesk',sans-serif;
  font-size:12.5px;font-weight:600;letter-spacing:.1em;
  padding:6px 4px;border-radius:8px;cursor:pointer;
  transition:background .16s,color .16s,border-color .16s;
}
.daybar .day .d2{display:block;font-family:'IBM Plex Mono',monospace;font-size:9.5px;letter-spacing:.08em;opacity:.8;margin-top:1px;font-weight:400;}
.daybar .day[aria-selected="true"]{background:var(--text);color:var(--ink);border-color:var(--text);}

.tabbar{display:grid;grid-template-columns:repeat(4,1fr);padding-bottom:env(safe-area-inset-bottom,0px);}
.tabbar button{
  appearance:none;border:0;background:transparent;color:var(--dim);
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px;
  padding:8px 4px 9px;min-height:48px;cursor:pointer;
  font-family:'Space Grotesk',sans-serif;
  transition:color .16s;
}
.tabbar button[aria-selected="true"]{color:var(--text);}
.tabbar button:focus-visible{outline:2px solid var(--bass);outline-offset:-2px;}
.tabbar .tab-icon{position:relative;display:inline-flex;align-items:center;justify-content:center;}
.tabbar .tab-label{font-size:10.5px;font-weight:600;letter-spacing:.02em;}
.tab-badge{
  position:absolute;top:-5px;right:-9px;min-width:16px;height:16px;padding:0 4px;
  border-radius:8px;background:var(--clash);color:#3A2600;
  font-family:'IBM Plex Mono',monospace;font-size:10px;font-weight:700;line-height:1;
  display:flex;align-items:center;justify-content:center;
}
.tab-badge[hidden]{display:none;}
.tab-dot{
  position:absolute;top:-3px;right:-7px;width:8px;height:8px;border-radius:50%;
  background:var(--bass);animation:menuPulse 1.6s ease-out infinite;
}
.tab-dot[hidden]{display:none;}

/* ---------- banners (schedule diff) ---------- */
#banners{position:relative;z-index:35;}
.banner{
  display:flex;align-items:flex-start;gap:8px;
  margin:8px 14px 0;padding:10px 12px;border-radius:10px;
  border:1px solid var(--line);background:var(--panel2);
  font-size:12.5px;line-height:1.5;color:var(--text);
}
.banner.amber{border-color:rgba(255,197,61,.5);background:rgba(255,197,61,.10);}
.banner-msg{flex:1;}
.banner-close{
  appearance:none;border:0;background:transparent;color:var(--dim);
  font-size:16px;line-height:1;cursor:pointer;padding:0 2px;
}
/* CTA pill for a banner with an action (post-join claim nudge) — mirrors
   .myset-nudge-btn's visual language (same border-main/bg-tint/color-main
   treatment already used elsewhere for a secondary-but-important action),
   just adapted to sit inside the generic top-of-page banner slot. */
.banner-cta{
  display:block;margin-top:8px;
  appearance:none;border:1px solid var(--main);background:rgba(255,83,36,.12);color:var(--main);
  font-family:'IBM Plex Mono',monospace;font-size:11.5px;font-weight:700;letter-spacing:.02em;
  padding:8px 12px;border-radius:20px;cursor:pointer;white-space:nowrap;
}
.banner-cta:hover, .banner-cta:focus-visible{background:rgba(255,83,36,.2);}

/* ---------- now/next strip ---------- */
#nownextwrap{position:sticky;top:var(--headh,0);z-index:34;}
.nownext{
  display:grid;grid-template-columns:repeat(3,1fr);gap:1px;
  background:var(--line);border-bottom:1px solid var(--line);
}
.nn-cell{background:var(--ink);padding:8px 10px;}
.nn-stage{
  font-family:'IBM Plex Mono',monospace;font-size:10px;letter-spacing:.12em;
  color:var(--stage-color);text-transform:uppercase;font-weight:600;
}
.nn-now{font-size:13px;font-weight:600;margin-top:2px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
.nn-next{font-family:'IBM Plex Mono',monospace;font-size:11px;color:var(--dim);margin-top:2px;}

/* ---------- group tab: empty states ---------- */
.group-status{
  margin:10px 14px 0;padding:9px 12px;border-radius:10px;
  border:1px solid var(--line);background:var(--panel2);
  font-size:12.5px;color:var(--dim);
}
.group-status[hidden]{display:none;}
.group-status strong{color:var(--text);}
.group-empty{
  margin:20px 14px 0;padding:30px 22px;text-align:center;
  border:1px dashed var(--line);border-radius:14px;
}
.group-empty[hidden]{display:none;}
.group-empty h2{font-size:16px;margin:0 0 8px;}
.group-empty p{color:var(--dim);font-size:13px;line-height:1.5;margin:0 0 18px;}
.group-empty .sheet-actions{max-width:320px;margin:0 auto;flex-direction:column;}
.group-empty-hint{color:var(--dim);font-size:12px;margin-top:12px;}

/* ---------- stage header ---------- */
.stagehead{
  position:sticky;top:var(--stackh,148px);z-index:30;
  display:grid;grid-template-columns:44px repeat(3,1fr);
  background:rgba(10,5,20,.95);backdrop-filter:blur(14px);
  border-bottom:1px solid var(--line);
}
.stagehead div{
  padding:9px 6px;text-align:center;
  font-family:'IBM Plex Mono',monospace;font-size:11px;
  letter-spacing:.12em;font-weight:600;
}
.stagehead[hidden]{display:none;}

/* ---------- grid ---------- */
.gridwrap{padding:0 0 24px;}
.grid{
  position:relative;
  display:grid;grid-template-columns:44px repeat(3,1fr);
  padding:10px 8px 0 0;
}
.gutter{position:relative;}
.tick{
  position:absolute;left:0;width:44px;
  font-family:'IBM Plex Mono',monospace;font-size:10.5px;
  color:var(--dim);text-align:right;padding-right:7px;
  transform:translateY(-5px);letter-spacing:.02em;
}
.tick.half{opacity:.55;font-size:9.5px;}
.rule{
  position:absolute;left:44px;right:8px;height:1px;
  background:var(--line);opacity:.5;
}
.rule.half{opacity:.22;}
.col{position:relative;padding:0 3px;}

.set{
  position:absolute;left:3px;right:3px;
  border-radius:7px;border:1px solid;
  padding:6px 7px;overflow:hidden;
  cursor:pointer;text-align:left;
  background:var(--panel);
  font-family:'Space Grotesk',sans-serif;
  color:var(--text);
  display:flex;flex-direction:column;gap:2px;
  transition:transform .12s ease, background .16s;
  width:100%;
  /* -webkit-user-select is the property iOS Safari's text-selection loupe
     actually honors — plain user-select alone still shows the magnifier on
     press-and-hold. touch-action:manipulation keeps scrolling but drops
     double-tap-zoom heuristics that add tap latency. */
  -webkit-touch-callout:none;-webkit-user-select:none;user-select:none;
  touch-action:manipulation;
}
.set:active{transform:scale(.985);}
/* Long-press "charging" feedback (150ms into a live hold): visibly distinct
   from the quick :active tap squeeze — sinks deeper and glows. */
.set.holding{transform:scale(.94);filter:brightness(1.25);transition:transform .28s ease, filter .28s ease;}
.set .nm{
  font-size:13px;font-weight:600;line-height:1.2;
  overflow:hidden;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;
  /* Slim heart reserve — the heart SVG carries its own whitespace, so 16px
     keeps the longest one-word names (Panteros666) on one line at 390px.
     overflow-wrap:anywhere lives ONLY in the ≤360px media block below:
     as a blanket rule it mid-word-broke names ("DIRTYHAPP/Y") at widths
     where they actually fit. */
  padding-right:16px;
}
.set .tm{
  font-family:'IBM Plex Mono',monospace;font-size:11px;
  color:var(--dim);letter-spacing:-.01em;margin-top:auto;
}
/* Direct pick toggle (replaces the old .pin dot — the filled glyph below
   carries the same "picked" signal, now a real tappable control). Outline
   by default; filled + currentColor once picked, which resolves to that
   block's own stage ink via .set[data-picked="true"]{color:...} below — the
   same currentColor convention .pin used, just on an actual heart now. */
.set .heart{
  position:absolute;top:5px;right:5px;width:18px;height:18px;z-index:7;
  display:flex;align-items:center;justify-content:center;
  color:rgba(240,234,251,.55);
  cursor:pointer;transition:transform .1s ease;
}
.set .heart svg{width:100%;height:100%;display:block;}
/* Expand the tap area to >=40x40 without changing the visible glyph size —
   same technique as .chip::after above. */
.set .heart::after{
  content:'';position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);
  width:40px;height:40px;
}
.set .heart:active{transform:scale(.8);}
.set[data-picked="true"] .heart{color:inherit;}

.set[data-stage="main"]{border-color:rgba(255,83,36,.5);}
.set[data-stage="bass"]{border-color:rgba(23,224,210,.5);}
.set[data-stage="sirkus"]{border-color:rgba(255,46,136,.5);}

.set[data-stage="main"][data-picked="true"]{background:var(--main);border-color:var(--main);color:#1A0500;}
.set[data-stage="bass"][data-picked="true"]{background:var(--bass);border-color:var(--bass);color:#00201E;}
.set[data-stage="sirkus"][data-picked="true"]{background:var(--sirkus);border-color:var(--sirkus);color:#25000F;}
.set[data-picked="true"] .tm{color:inherit;opacity:.92;}

.set[data-clash="true"]{box-shadow:0 0 0 2px var(--clash);}
.set:has(.chip-row){padding-top:28px;}

/* clash band — the signature overlay. --clash is reserved for this only. */
.band{
  position:absolute;left:44px;right:8px;
  background:repeating-linear-gradient(135deg,
     rgba(255,197,61,.16) 0 6px, rgba(255,197,61,0) 6px 12px);
  border-top:1px dashed rgba(255,197,61,.55);
  border-bottom:1px dashed rgba(255,197,61,.55);
  pointer-events:none;z-index:5;
}
.band b{
  position:absolute;top:50%;right:4px;transform:translateY(-50%);
  font-family:'IBM Plex Mono',monospace;font-size:10.5px;font-weight:700;
  color:var(--clash);background:var(--ink);padding:1px 4px;border-radius:3px;
  letter-spacing:.05em;
}

.nowline{position:absolute;left:44px;right:8px;height:2px;background:#fff;z-index:20;pointer-events:none;}
.nowline b{
  position:absolute;left:-40px;top:-6px;font-family:'IBM Plex Mono',monospace;
  font-size:10px;background:#fff;color:var(--ink);padding:2px 5px;border-radius:3px;font-weight:700;
}

/* ---------- group overlay + comment-count chips ---------- */
/* Shared absolute-positioned wrapper so the heat chip and the 💬 comment
   chip can sit side by side without either one needing to know whether the
   other is present — each chip below is position:relative (a static flex
   child of this row), not self-positioned. */
.chip-row{
  position:absolute;top:4px;left:4px;z-index:6;
  display:flex;align-items:center;gap:4px;
}
.chip{
  position:relative;
  appearance:none;border:1.5px solid rgba(240,234,251,.45);border-radius:20px;
  padding:3px 8px;min-height:20px;display:flex;align-items:center;gap:5px;cursor:pointer;
  font-family:'IBM Plex Mono',monospace;font-size:11px;font-weight:700;
  color:#fff;background:rgba(10,5,20,.82);
}
/* Expand the tap area to >=40x40 without changing the visible chip size —
   the chip itself is often much smaller than a comfortable touch target. */
.chip::after{
  content:'';position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);
  width:40px;height:40px;
}
.chip-n{color:var(--bass);}
.chip-i{letter-spacing:.02em;}
.chip.heat-1{border-color:rgba(240,234,251,.45);}
.chip.heat-2{border-color:rgba(240,234,251,.65);}
.chip.heat-3{border-color:rgba(23,224,210,.8);box-shadow:0 0 0 1px rgba(23,224,210,.25);}
.chip.heat-4{border-color:var(--bass);box-shadow:0 0 6px rgba(23,224,210,.45);}
.chip.heat-5{background:var(--bass);border-color:var(--bass);color:#00201E;box-shadow:0 0 8px rgba(23,224,210,.6);}
.chip.heat-5 .chip-n{color:inherit;}
.chip.heat-6{background:var(--bass);border-color:#fff;color:#00201E;box-shadow:0 0 10px rgba(23,224,210,.85),0 0 0 1px #fff;}
.chip.heat-6 .chip-n{color:inherit;}

/* 💬 comment-count chip — same visual language as .chip (pill, mono digits,
   ::after tap-target trick) but its own class: NOT a heat-tiered indicator,
   so it never needs .chip.heat-N's color/glow escalation. */
.chip-comment{
  position:relative;
  appearance:none;border:1.5px solid rgba(240,234,251,.45);border-radius:20px;
  padding:3px 7px;min-height:20px;display:flex;align-items:center;gap:3px;cursor:pointer;
  font-family:'IBM Plex Mono',monospace;font-size:11px;font-weight:700;
  color:#fff;background:rgba(10,5,20,.82);
}
.chip-comment::after{
  content:'';position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);
  width:40px;height:40px;
}
.chip-comment-n{color:var(--bass);}

/* ---------- Now view (bottom-nav 4th tab) ---------- */
.nowview{padding:16px 14px 0;}
.nowview[hidden]{display:none;}
.now-empty{
  border:1px dashed var(--line);border-radius:12px;
  padding:30px 22px;text-align:center;color:var(--dim);
}
.now-empty h2{color:var(--text);font-size:16px;font-weight:600;margin:0 0 8px;line-height:1.4;}
.now-empty p{margin:0;font-size:13px;}
.now-empty-counts{
  list-style:none;margin:10px 0 0;padding:0;font-size:13px;
  display:inline-block;text-align:left;
}
.now-empty-counts li{padding:3px 0;}

.now-hero{
  border-radius:14px;padding:16px;margin-bottom:16px;
  background:var(--panel2);border:1px solid var(--stage-color);
  box-shadow:0 0 0 1px rgba(255,255,255,.02), 0 8px 24px rgba(0,0,0,.3);
}
.now-hero-label{
  font-family:'IBM Plex Mono',monospace;font-size:10.5px;letter-spacing:.12em;
  text-transform:uppercase;color:var(--stage-color);font-weight:600;
}
.now-hero-artist{font-size:19px;font-weight:700;margin-top:5px;}
.now-hero-when{font-family:'IBM Plex Mono',monospace;font-size:12px;color:var(--dim);margin-top:5px;}

.now-stages{display:flex;flex-direction:column;gap:12px;}
.now-stage{
  border:1px solid var(--line);border-left-width:3px;border-left-color:var(--stage-color);
  border-radius:10px;padding:13px 14px;background:var(--panel);
}
.now-stage-name{
  font-family:'IBM Plex Mono',monospace;font-size:11px;letter-spacing:.1em;
  color:var(--stage-color);text-transform:uppercase;font-weight:600;
}
.now-current{margin-top:7px;}
.now-current-name{font-size:16px;font-weight:700;}
.now-current--picked .now-current-name{color:var(--stage-color);}
.now-current-time{font-family:'IBM Plex Mono',monospace;font-size:11.5px;color:var(--dim);margin-top:2px;}
.now-current--empty{color:var(--dim);font-size:14px;margin-top:7px;}
.now-progress{height:4px;border-radius:2px;background:var(--line);margin-top:9px;overflow:hidden;}
.now-progress-bar{height:100%;background:var(--stage-color);border-radius:2px;}
.now-next-line{font-family:'IBM Plex Mono',monospace;font-size:11.5px;color:var(--dim);margin-top:9px;}

/* ---------- route ---------- */
.route{padding:16px 14px 0;}
.empty{
  border:1px dashed var(--line);border-radius:12px;
  padding:26px 20px;text-align:center;color:var(--dim);
}
.empty strong{display:block;color:var(--text);font-size:15px;margin-bottom:6px;}
.empty span{font-size:13px;line-height:1.5;}

.leg{display:flex;gap:11px;margin-bottom:0;}
.leg .time{
  flex:0 0 58px;font-family:'IBM Plex Mono',monospace;font-size:11px;
  color:var(--dim);padding-top:12px;text-align:right;
}
.leg .card{
  flex:1;border:1px solid var(--line);border-left-width:3px;border-left-color:var(--stage-color);
  border-radius:9px;padding:11px 12px;background:var(--panel);
}
.leg .card h3{margin:0 0 3px;font-size:15px;font-weight:600;}
.leg .card h3 .alias{font-size:12px;font-weight:400;color:var(--dim);}
.leg-artist-btn{
  appearance:none;border:0;border-bottom:1px dashed transparent;background:transparent;
  padding:0;margin:0;font:inherit;font-weight:inherit;color:inherit;cursor:pointer;text-align:left;
}
.leg-artist-btn:hover, .leg-artist-btn:focus-visible{border-bottom-color:var(--dim);}
.leg .card p{
  margin:0;font-family:'IBM Plex Mono',monospace;font-size:11.5px;
  color:var(--dim);letter-spacing:.04em;text-transform:uppercase;
}
.leg-enrich{
  margin:5px 0 0;font-size:12px;color:var(--dim);
}
.leg .card button[data-remove]{
  appearance:none;border:0;background:transparent;color:var(--dim);
  font-family:'IBM Plex Mono',monospace;font-size:11px;padding:7px 0 0;
  cursor:pointer;text-decoration:underline;text-underline-offset:2px;
}
.gap{
  display:flex;gap:11px;align-items:center;
  font-family:'IBM Plex Mono',monospace;font-size:11px;
  color:var(--dim);padding:7px 0;
}
.gap .time{flex:0 0 58px;}
.gap .bar{flex:1;display:flex;align-items:center;gap:8px;}
.gap .bar::before{content:'';width:3px;height:16px;background:var(--line);margin-left:0;}
.gap.warn{color:var(--clash);}
.gap.warn .bar::before{background:var(--clash);}

/* ---------- My Set action row + sync nudge ---------- */
/* Two menu-buried actions surfaced right where they're relevant: the My Set
   view itself. Panel bg + line border (matches .leg .card / .now-stage in
   this same view) rather than the sheet's .btn-primary/.btn-secondary — this
   sits in page flow, not inside a modal. */
.myset-actions{display:flex;gap:10px;margin:0 0 14px;}
.myset-action-btn{
  flex:1;display:flex;align-items:center;justify-content:center;gap:8px;
  min-height:46px;padding:11px 10px;
  border:1px solid var(--line);border-radius:12px;background:var(--panel);
  color:var(--text);font-family:'Space Grotesk',sans-serif;
  font-size:13px;font-weight:600;line-height:1.2;
  cursor:pointer;transition:border-color .16s,background .16s;
}
.myset-action-btn svg{flex-shrink:0;width:19px;height:19px;}
.myset-action-btn:hover, .myset-action-btn:focus-visible{border-color:var(--bass);}
.myset-action-btn:active{opacity:.7;}

/* Slim, dismissible-per-session card nudging an anonymous user to claim their
   email — never shown once claimed. CTA pill mirrors .btn-invite's visual
   language (same border-main/bg-tint/color-main treatment already used
   elsewhere for a secondary-but-important action). */
.myset-nudge{
  display:flex;align-items:center;gap:10px;
  margin:0 0 16px;padding:12px 10px 12px 14px;
  border:1px solid var(--line);border-radius:12px;background:var(--panel2);
}
.myset-nudge-text{flex:1;min-width:0;}
.myset-nudge-text strong{display:block;font-size:13px;font-weight:600;color:var(--text);}
.myset-nudge-text span{display:block;font-size:12px;color:var(--dim);margin-top:2px;line-height:1.4;}
.myset-nudge-btn{
  flex-shrink:0;appearance:none;border:1px solid var(--main);background:rgba(255,83,36,.12);color:var(--main);
  font-family:'IBM Plex Mono',monospace;font-size:11.5px;font-weight:700;letter-spacing:.02em;
  padding:9px 12px;border-radius:20px;cursor:pointer;white-space:nowrap;
}
.myset-nudge-dismiss{
  flex-shrink:0;appearance:none;border:0;background:transparent;color:var(--dim);
  font-size:18px;line-height:1;cursor:pointer;padding:0;width:28px;height:28px;
  display:flex;align-items:center;justify-content:center;
}
.myset-nudge-dismiss:hover, .myset-nudge-dismiss:focus-visible{color:var(--text);}

/* ---------- footnote / footer ---------- */
.note{
  margin:26px 14px 0;padding:13px 14px;border-radius:10px;
  border:1px solid var(--line);background:var(--panel);
  font-size:12px;line-height:1.55;color:var(--dim);
}
.note strong{color:var(--text);font-weight:600;}
footer{padding:18px 14px max(8px, env(safe-area-inset-bottom));}
.disclaimer{
  font-family:'IBM Plex Mono',monospace;font-size:11px;line-height:1.6;
  color:var(--dim);text-align:center;letter-spacing:.02em;
}

/* ---------- bottom sheet ---------- */
/* Body scroll lock while any sheet is open. See ui.js openSheet/cleanupSheet
   for the scrollY save/restore that keeps this from jumping the page on
   close. */
body.sheet-open{overflow:hidden;}
.sheet-overlay{
  position:fixed;inset:0;z-index:100;background:rgba(10,5,20,.6);
  display:flex;align-items:flex-end;justify-content:center;
  animation:fadeIn .18s ease;
}
.sheet-overlay.closing{animation:fadeOut .18s ease forwards;}
.sheet-overlay.closing .sheet{animation:slideDown .18s ease forwards;}
.sheet{
  position:relative;
  width:100%;max-width:720px;overflow-y:auto;
  max-height:86vh; /* fallback for browsers without dvh support */
  max-height:86dvh;
  background:var(--panel);border:1px solid var(--line);border-bottom:none;
  border-radius:18px 18px 0 0;padding:10px 18px;
  padding-bottom:max(26px, env(safe-area-inset-bottom));
  animation:slideUp .2s cubic-bezier(.22,.9,.36,1);
}
.sheet-close{
  position:absolute;top:2px;right:2px;z-index:5;
  width:44px;height:44px;appearance:none;border:0;background:transparent;
  color:var(--dim);font-size:20px;line-height:1;cursor:pointer;
  display:flex;align-items:center;justify-content:center;border-radius:50%;
}
.sheet-close:hover, .sheet-close:focus-visible{color:var(--text);}
.sheet-header{touch-action:none;padding-right:44px;}
.sheet-handle{width:36px;height:4px;border-radius:2px;background:var(--line);margin:4px auto 12px;}
.sheet-title{font-size:16px;font-weight:600;margin-bottom:12px;}
.sheet-hint{color:var(--dim);font-size:13px;line-height:1.5;margin:0 0 12px;}
.sheet-note{color:var(--dim);font-size:12px;min-height:1.4em;margin-top:8px;}
.sheet-actions{display:flex;gap:10px;margin-top:16px;}
input[type="text"], input[type="email"]{
  width:100%;padding:12px 14px;border-radius:10px;border:1px solid var(--line);
  background:var(--ink);color:var(--text);font-size:16px;font-family:inherit;margin-bottom:12px;
  appearance:none;-webkit-appearance:none;
}
input[inputmode="numeric"]{
  font-family:'IBM Plex Mono',monospace;letter-spacing:.3em;text-align:center;font-size:22px;
  appearance:none;-webkit-appearance:none;
}
.btn-primary, .btn-secondary, .btn-danger{
  appearance:none;border-radius:10px;padding:12px 16px;font-size:14px;font-weight:600;
  cursor:pointer;font-family:inherit;flex:1;
}
.btn-primary{border:1px solid var(--main);background:var(--main);color:#1A0500;}
.btn-secondary{border:1px solid var(--line);background:transparent;color:var(--text);}
.btn-danger{border:1px solid var(--sirkus);background:transparent;color:var(--sirkus);}

.group-list, .roster-list, .menu-list, .who-list{list-style:none;margin:0;padding:0;}
.group-row{display:flex;align-items:stretch;gap:6px;}
.group-row + .group-row{margin-top:8px;}
.group-open{
  flex:1;min-width:0;display:flex;justify-content:space-between;align-items:center;gap:8px;
  padding:12px 14px;border:1px solid var(--line);border-radius:10px;background:var(--panel2);
  color:var(--text);cursor:pointer;
}
.group-name{font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
.group-count{font-family:'IBM Plex Mono',monospace;font-size:11px;color:var(--dim);white-space:nowrap;flex-shrink:0;}
.group-details{
  flex:0 0 44px;display:flex;align-items:center;justify-content:center;
  border:1px solid var(--line);border-radius:10px;background:transparent;
  color:var(--dim);font-size:20px;cursor:pointer;
}
.empty-inline{color:var(--dim);font-size:13px;padding:14px 0;}
.roster-code{
  font-family:'IBM Plex Mono',monospace;font-size:12px;color:var(--dim);
  margin:-4px 0 14px;letter-spacing:.04em;
}
.roster-code strong{color:var(--text);letter-spacing:.15em;}

.roster-row{
  display:flex;justify-content:space-between;padding:10px 0;border-bottom:1px solid var(--line);
}
.roster-row.pending .roster-status{color:var(--dim);}
.roster-status{font-family:'IBM Plex Mono',monospace;font-size:11px;color:var(--text);}

.menu-list li + li:not(.menu-sep){margin-top:6px;}
.menu-list button{
  width:100%;min-height:46px;text-align:left;padding:13px 14px;border-radius:10px;border:1px solid var(--line);
  background:transparent;color:var(--text);font-size:14px;cursor:pointer;
  display:flex;align-items:center;gap:12px;
}
.menu-item svg{flex-shrink:0;color:var(--dim);}
/* Section separator between the four menu groups — a bare rule, no heading
   (see openMenu() in app.js). Own <li> so it sits inside the same list the
   screen reader already walks; aria-hidden keeps it out of the a11y tree. */
.menu-sep{height:1px;margin:10px 4px;background:var(--line);list-style:none;}
.menu-account{
  padding:10px 14px 2px;font-family:'IBM Plex Mono',monospace;font-size:11.5px;
  color:var(--dim);letter-spacing:.02em;
}

.who-list li{padding:9px 0;border-bottom:1px solid var(--line);font-size:14px;}

/* ---------- socials row — artist detail sheet + My Set cards ---------- */
.socials-row{display:flex;gap:8px;flex-wrap:wrap;margin:14px 0 4px;}
.social-btn{
  appearance:none;text-decoration:none;
  display:inline-flex;align-items:center;justify-content:center;
  min-width:42px;height:44px;padding:0 12px;
  border:1px solid var(--line);border-radius:20px;
  background:var(--panel2);color:var(--text);
  font-family:'IBM Plex Mono',monospace;font-size:12px;font-weight:700;letter-spacing:.06em;
  transition:border-color .16s,background .16s;
}
.social-btn:hover, .social-btn:focus-visible{border-color:var(--bass);color:var(--bass);}
.social-btn--icon{min-width:44px;padding:0;width:44px;}
.social-btn--icon svg{display:block;}
.socials-row--compact{margin:6px 0 0;gap:6px;}
.socials-row--compact .social-btn{min-width:0;height:24px;padding:0 8px;font-size:10px;border-radius:14px;}
.socials-row--compact .social-btn--icon{width:28px;padding:0;}
.socials-row--compact .social-btn--icon svg{width:14px;height:14px;}
/* Icon + visible text variant (the Listen row's Spotify/SoundCloud buttons —
   distinct from .social-btn--icon, which is icon-only at a fixed 44px). */
.social-btn--text{gap:6px;}

/* Small uppercase mono label above a row of controls — same look
   .artist-from already used inline; shared here so any row (Listen, Crew
   notes, …) can reuse it instead of repeating the style. */
.row-label{
  font-family:'IBM Plex Mono',monospace;font-size:11px;letter-spacing:.08em;
  text-transform:uppercase;color:var(--dim);margin:14px 0 4px;
}

/* ---------- artist detail sheet ---------- */
.artist-detail{padding-top:2px;}
.artist-name{margin:2px 0 4px;font-size:22px;font-weight:700;line-height:1.15;}
.artist-alias{margin:0 0 6px;font-size:13.5px;color:var(--dim);}
.artist-from{
  margin:0 0 10px;font-family:'IBM Plex Mono',monospace;font-size:11px;
  color:var(--dim);letter-spacing:.08em;text-transform:uppercase;
}
.artist-when{
  margin:0 0 4px;font-family:'IBM Plex Mono',monospace;font-size:12px;
  color:var(--dim);letter-spacing:.02em;line-height:1.7;
}
.artist-when .artist-stage{color:var(--stage-color);font-weight:600;}

/* ---------- crew notes (artist pane) + crew board (Crew view) ---------- */
/* Shared by artist.js's per-set section and app.js's crew-board panel — both
   mount comments.renderCommentThread() into a plain container, so the
   thread's own markup (composer/list/rows) below is identical either way. */
.crew-notes{margin-top:16px;padding-top:14px;border-top:1px solid var(--line);}
.crew-notes-title{
  margin:0 0 10px;font-size:13px;font-weight:600;color:var(--text);
}
.comment-composer{display:flex;gap:8px;align-items:flex-start;margin-bottom:4px;}
.comment-composer input[type="text"]{margin-bottom:0;flex:1;}
.comment-composer .btn-primary{flex:0 0 auto;padding:12px 16px;}
.comment-error{color:var(--sirkus);}
.comment-error[hidden], .comment-empty[hidden]{display:none;}
.comment-empty{margin:10px 0 0;}
.comment-list{list-style:none;margin:6px 0 0;padding:0;}
.comment-row{padding:11px 0;border-bottom:1px solid var(--line);}
.comment-row:last-child{border-bottom:none;}
.comment-meta{display:flex;align-items:baseline;gap:8px;flex-wrap:wrap;}
.comment-author{font-size:13px;font-weight:600;color:var(--text);}
.comment-time{
  font-family:'IBM Plex Mono',monospace;font-size:11px;color:var(--dim);letter-spacing:.02em;
}
.comment-body{margin:5px 0 8px;font-size:14px;line-height:1.5;white-space:pre-wrap;overflow-wrap:anywhere;}
.comment-votes{display:flex;align-items:center;gap:8px;}
.comment-vote{
  appearance:none;border:1px solid var(--line);background:var(--panel2);border-radius:8px;
  width:32px;height:32px;display:flex;align-items:center;justify-content:center;
  color:var(--dim);font-size:12px;cursor:pointer;
}
.comment-vote:hover, .comment-vote:focus-visible{border-color:var(--bass);color:var(--bass);}
.comment-vote[aria-pressed="true"]{border-color:var(--bass);background:rgba(23,224,210,.14);color:var(--bass);}
.comment-score{
  font-family:'IBM Plex Mono',monospace;font-size:13px;font-weight:700;min-width:1.4em;text-align:center;
}
.comment-delete{
  appearance:none;border:0;background:transparent;color:var(--dim);
  font-size:11.5px;letter-spacing:.02em;cursor:pointer;margin-left:auto;padding:6px 0;
}
.comment-delete:hover, .comment-delete:focus-visible{color:var(--sirkus);}

/* ---------- crew board panel (top of Crew view, below the crew header) ---------- */
.crew-board{margin:12px 14px 0;border:1px solid var(--line);border-radius:12px;background:var(--panel);overflow:hidden;}
.crew-board[hidden]{display:none;}
.crew-board-toggle{
  appearance:none;border:0;background:transparent;width:100%;
  display:flex;align-items:center;justify-content:space-between;
  padding:12px 14px;color:var(--text);font-size:13.5px;font-weight:600;cursor:pointer;
  font-family:inherit;
}
.crew-board-toggle:hover, .crew-board-toggle:focus-visible{color:var(--bass);}
.crew-board-chevron{
  color:var(--dim);font-size:18px;line-height:1;transition:transform .16s ease;
}
.crew-board-toggle[aria-expanded="true"] .crew-board-chevron{transform:rotate(90deg);}
.crew-board-body{padding:0 14px 14px;border-top:1px solid var(--line);padding-top:12px;}
.crew-board-body[hidden]{display:none;}

/* ---------- festival info sheet ---------- */
.finfo-venue{margin:0 0 4px;font-size:15px;font-weight:600;}
.finfo-badges{display:flex;gap:8px;flex-wrap:wrap;margin:0 0 14px;}
.finfo-badge{
  font-family:'IBM Plex Mono',monospace;font-size:11px;font-weight:700;letter-spacing:.06em;
  padding:4px 10px;border-radius:20px;border:1px solid var(--main);color:var(--main);
  background:rgba(255,83,36,.1);
}
.finfo-note{margin:0 0 10px;font-size:12.5px;line-height:1.5;color:var(--dim);}
.finfo-note strong{color:var(--text);font-weight:600;}
.finfo-section{margin:16px 0 0;}
.finfo-section h4{
  margin:0 0 8px;font-size:11px;font-weight:600;text-transform:uppercase;
  letter-spacing:.1em;color:var(--dim);
}
.finfo-list{list-style:none;margin:0;padding:0;}
.finfo-list li{padding:8px 0;border-bottom:1px solid var(--line);font-size:14px;}
.finfo-list li:last-child{border-bottom:none;}
.finfo-plain{margin:0;font-size:13.5px;}

.share-sheet{text-align:center;}
.qr-canvas{display:block;margin:0 auto 14px;border-radius:10px;background:var(--text);padding:12px;}
.share-code{
  font-family:'IBM Plex Mono',monospace;font-size:24px;font-weight:600;letter-spacing:.15em;
  margin-bottom:10px;
}
.share-url{
  font-family:'IBM Plex Mono',monospace;font-size:11px;color:var(--dim);
  word-break:break-all;padding:10px;border:1px solid var(--line);border-radius:8px;margin-bottom:6px;
}

.claim-success p{margin:0 0 10px;line-height:1.5;}

.ios-steps{margin:0;padding-left:20px;line-height:1.8;font-size:14px;}

/* ---------- guided tour (spotlight / coach-mark) ---------- */
/* z-index set inline by tour.js (OVERLAY_Z) — above .bottomstack (60),
   below .sheet-overlay (100). Appended directly to <body>, same as sheets,
   so it stacks at the root level regardless of #app's own z-index:1
   context — see tour.js's header comment. */
.tour-overlay{position:fixed;inset:0;pointer-events:none;}
.tour-blocker{position:absolute;pointer-events:auto;background:transparent;}
.tour-cutout{
  position:absolute;border-radius:14px;pointer-events:none;
  box-shadow:0 0 0 9999px rgba(10,5,20,.82);
  outline:2px solid rgba(240,234,251,.55);outline-offset:2px;
}
.tour-cutout.no-target{
  position:fixed;inset:0;border-radius:0;outline:none;
  box-shadow:none;background:rgba(10,5,20,.82);
}
.tour-card{
  position:absolute;pointer-events:auto;
  width:calc(100% - 32px);max-width:300px;
  background:var(--panel2);border:1px solid var(--line);border-radius:14px;
  padding:16px 18px;box-shadow:0 12px 40px rgba(0,0,0,.5);
  animation:fadeIn .18s ease;
}
.tour-card.centered{position:fixed;left:50%;top:50%;transform:translate(-50%,-50%);}
.tour-dots{display:flex;gap:6px;margin-bottom:12px;}
.tour-dots span{width:6px;height:6px;border-radius:50%;background:var(--line);display:inline-block;}
.tour-dots span.on{background:var(--main);}
.tour-title{font-size:16px;font-weight:700;margin:0 0 6px;}
.tour-copy{font-size:13px;color:var(--dim);line-height:1.5;margin:0 0 16px;}
.tour-actions{display:flex;align-items:center;justify-content:space-between;gap:14px;}
.tour-skip{
  appearance:none;border:0;background:transparent;color:var(--dim);
  font-size:12.5px;font-family:inherit;cursor:pointer;padding:10px 2px;flex-shrink:0;
}
.tour-next{flex:0 0 auto;padding:10px 20px;}

/* ---------- toast ---------- */
.toast{
  position:fixed;left:50%;bottom:24px;transform:translateX(-50%) translateY(20px);
  background:var(--text);color:var(--ink);padding:10px 16px;border-radius:20px;
  font-size:13px;font-weight:600;opacity:0;pointer-events:none;transition:opacity .18s,transform .18s;
  z-index:200;
}
.toast.show{opacity:1;transform:translateX(-50%) translateY(0);}

/* ---------- install hint ---------- */
/* Docks ABOVE the fixed bottom stack (day control + tab bar), not under it —
   .bottomstack already reserves the safe-area inset internally (.tabbar's
   own padding-bottom), so this only needs a small gap above it, not its own
   safe-area math. #app needs the hint's height added on top of --bottomh so
   the last grid/route rows never sit behind either fixed layer. */
body.has-install-hint #app{padding-bottom:calc(var(--bottomh, 96px) + 76px);}
.install-hint{
  position:fixed;left:12px;right:12px;bottom:calc(var(--bottomh, 96px) + 10px);z-index:90;
  display:flex;align-items:center;gap:10px;
  background:var(--panel2);border:1px solid var(--line);border-radius:12px;
  padding:12px 14px;font-size:12.5px;color:var(--text);
  box-shadow:0 8px 30px rgba(0,0,0,.4);
}
.install-hint button[data-install-go]{
  appearance:none;border:1px solid var(--main);background:var(--main);color:#1A0500;
  border-radius:8px;padding:7px 12px;font-weight:600;font-size:12px;cursor:pointer;flex-shrink:0;
}
.install-hint button[data-install-dismiss]{
  appearance:none;border:0;background:transparent;color:var(--dim);font-size:16px;cursor:pointer;flex-shrink:0;
}
/* A menu-triggered tour replay (2nd+ visit) can otherwise coexist with this
   z-index:90 bar, sitting above the tour's own z-index:65 overlay — see
   tour.js's startTour()/teardown(). The auto-start path never hits this
   (first-ever visit is always below the hint's own 2-visit threshold). */
body.touring .install-hint{display:none;}

/* ---------- pressed feedback (touch) ---------- */
.tabbar button:active,
.day:active,
.menu-list button:active,
.chip:active{opacity:.7;}

@keyframes fadeIn{from{opacity:0}to{opacity:1}}
@keyframes fadeOut{from{opacity:1}to{opacity:0}}
@keyframes slideUp{from{transform:translateY(100%)}to{transform:translateY(0)}}
@keyframes slideDown{from{transform:translateY(0)}to{transform:translateY(100%)}}

@media (prefers-reduced-motion:reduce){
  *{transition:none!important;animation:none!important;}
}
@media (max-width:360px){
  .set .nm{font-size:11.5px;overflow-wrap:anywhere;} /* columns too narrow for one-word names — mid-break beats clipping here */
  .set .heart{width:16px;height:16px;}
  .stagehead div{font-size:8.5px;letter-spacing:.1em;}
  /* Chips go count-only at narrow widths — initials get dropped before they
     have a chance to overlap the artist name below them. */
  .chip{padding:3px 6px;gap:0;}
  .chip-i{display:none;}
  .set:has(.chip){padding-top:30px;}
  /* Bottom stack: labels and day dates are the first things to crowd at
     360px — trim before anything wraps or clips. */
  .tabbar .tab-label{font-size:9.5px;}
  .daybar .day{font-size:11px;letter-spacing:.06em;}
  .daybar .day .d2{font-size:9px;}
}

/* ---------- read-only mini grid (plan.html) ---------- */
.readonly .set{cursor:default;}
/* plan.html reuses schedule.js's renderGrid() as-is (a friend's shared plan,
   picks from their data not localStorage) — every block still gets a heart,
   but plan-page.js wires no click handler for [data-heart] at all. Without
   this, the heart would keep its cursor:pointer + 40x40 tap zone and look
   tappable while silently doing nothing. Still shown (conveys picked state,
   same job the old .pin dot did here), just not interactive. */
.readonly .set .heart{cursor:default;pointer-events:none;}
.buildtag{font-size:9.5px;opacity:.55;letter-spacing:.06em;}
