/* The console's palette and shapes, copied from web/dj.html: dark #0e0e10,
   elevated panels, accent #ff2d6f, uppercase rail labels, and a rounded
   image card for the header. The product is dark; these pages were not. */
@font-face{font-family:Geist;src:url(/fonts/Geist-Variable.woff2) format('woff2-variations');
font-weight:100 900;font-display:swap}
/* The swap used to be visible: every line painted in the system face and then
   resized a moment later when Geist arrived. The face is preloaded in the head
   so it is usually there before first paint, and this metric-matched stand-in
   covers the times it is not - same cap height and line box, so nothing moves. */
@font-face{font-family:"Geist stand-in";src:local("Helvetica Neue"),local("Arial"),local("Roboto");
size-adjust:104%;ascent-override:95%;descent-override:24%;line-gap-override:0%}
:root{
  color-scheme:dark;
  --sans:Geist,"Geist stand-in",-apple-system,BlinkMacSystemFont,"SF Pro Text",system-ui,sans-serif;
  --mono:"Geist Mono",ui-monospace,"SF Mono",Menlo,monospace;
  --bg:#0e0e10; --bg-elevated:#1a1a1d; --bg-elevated-2:#202024;
  --label:#f2f2f4; --label-secondary:#a3a3ac; --label-tertiary:#77777f;
  --separator:rgba(255,255,255,.09); --fill:rgba(255,255,255,.07);
  --fill-hover:rgba(255,255,255,.12);
  --accent:#ff2d6f; --success:#34c759; --danger:#ff3b30;
  --shadow:0 18px 50px rgba(0,0,0,.24), 0 1px 0 rgba(255,255,255,.04) inset;
  --r-sm:10px; --r-md:14px; --r-lg:20px; --r-pill:980px;
}
*{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
body{margin:0;background:var(--bg);color:var(--label);font-family:var(--sans);
font-size:15px;line-height:1.45;font-synthesis:none}

/* The scrollbar. These pages are shown inside the Mac's dark window, where the
   platform default paints a wide light-grey bar down the seam - which is what
   it looked like: a grey gutter between the night and the room. Thin, dark,
   and out of the way, matching the console's own. */
html{scrollbar-width:thin;scrollbar-color:rgba(255,255,255,.16) transparent;
color-scheme:dark}
::-webkit-scrollbar{width:9px;height:9px}
::-webkit-scrollbar-track{background:transparent}
::-webkit-scrollbar-thumb{background:rgba(255,255,255,.16);border-radius:99px;
border:2px solid transparent;background-clip:padding-box}
::-webkit-scrollbar-thumb:hover{background:rgba(255,255,255,.3);background-clip:padding-box}
::-webkit-scrollbar-corner{background:transparent}

/* The header is a card, not a band: an image with the name on it, inset from
   the edges and rounded, the way the console's cover sits. */
.hero{position:relative;max-width:1180px;margin:20px auto 0;padding:0 20px}
/* The same box the console draws: same height curve, same corner, same scrim,
   so a DJ moving between the app and the site is looking at one thing. */
.hero .cover{position:relative;min-height:clamp(200px,21vw,300px);display:flex;
align-items:flex-end;padding:28px 24px 20px;border-radius:var(--r-lg);overflow:hidden;
background:linear-gradient(135deg,#3a1f2a,#1d1a22);background-size:cover;
background-position:center;box-shadow:var(--shadow)}
/* Two scrims, because a photograph of a party is busy exactly where the words
   go. The flat one keeps the top tools readable; the second pools in the
   bottom-left corner the title and date actually sit in - a crowd shot with
   stage lights in it will otherwise eat a 15px line whole. */
.hero .cover::after{content:'';position:absolute;inset:0;pointer-events:none;
background:linear-gradient(180deg,rgba(0,0,0,.18),rgba(0,0,0,.30) 45%,rgba(0,0,0,.62)),
radial-gradient(120% 90% at 0% 100%,rgba(0,0,0,.66),rgba(0,0,0,0) 62%)}
.hero .cover.bare::after{background:none}
/* Remove, top right, only once there is something to remove. */
/* Back with the other actions on the right; the left corner belongs to the
   brand, which is the way home from anywhere. */
/* One cluster of three in the corner: shuffle, upload, remove. The neighbours
   are .coveractions - right:20px, 72px wide - not .toptools, which is what I
   measured against twice and got wrong twice; at 26px the remove button sat
   exactly on top of upload, so upload looked like it had been deleted.
   100px = 20 + 72 + an 8px gap. */
.coverx{position:absolute;top:20px;right:100px;width:32px;height:32px;z-index:4;
border-radius:50%;display:grid;place-items:center;padding:0;border:0;
background:rgba(18,18,22,.5);-webkit-backdrop-filter:blur(20px);backdrop-filter:blur(20px);
box-shadow:inset 0 0 0 1px rgba(255,255,255,.16);color:#fff;font-size:15px;cursor:pointer}
.coverx:hover{background:rgba(18,18,22,.68)}
.cover.bare .coverx{display:none}
.hero:has(.coverx) .toptools{right:92px}
.hero:has(.cover.bare) .toptools{right:46px}
/* The when and the where, typed into the line that shows them. They look like
   the text they replace until you put a cursor in them - a form that announces
   itself under a photograph is a form nobody reads. */
.subedit{display:inline-flex;align-items:center;gap:8px;flex-wrap:wrap}
.subedit input[type=date],.subedit [contenteditable]{font:inherit;color:inherit;
background:transparent;border:0;border-radius:6px;padding:1px 4px;outline:none;
min-width:2ch}
/* The date reads as the date - "Sat 8 Aug", not 08/08/2026 - and the picker
   hides behind it. A heading should look like a heading until you touch it. */
.dayedit{position:relative;display:inline-flex;align-items:center;cursor:pointer;
border-radius:6px;padding:1px 4px}
.dayedit:hover{background:rgba(0,0,0,.28)}
.dayedit input[type=date]{position:absolute;inset:0;opacity:0;width:100%;height:100%;
padding:0;cursor:pointer}
.subedit [contenteditable]:empty::before{content:attr(data-empty);opacity:.6}
.subedit input[type=date]:hover,.subedit [contenteditable]:hover{background:rgba(0,0,0,.28)}
.subedit input[type=date]:focus,.subedit [contenteditable]:focus{background:rgba(0,0,0,.42);
box-shadow:inset 0 0 0 1px rgba(255,255,255,.22)}
.hero .titles{position:relative;z-index:1}
.hero h1{font-size:clamp(34px,3.4vw,46px);font-weight:800;line-height:1.04;
letter-spacing:-.03em;color:#fff;margin:0 0 4px;overflow-wrap:anywhere}
.hero h1 [contenteditable]{outline:none;display:inline-block;min-width:2ch;
border-radius:var(--r-sm);padding:0 2px}
.hero h1 [contenteditable]:focus{background:rgba(0,0,0,.35);
box-shadow:inset 0 0 0 1px rgba(255,255,255,.25)}
.fieldedit{width:34px;height:34px;padding:0;margin-left:10px;border-radius:50%;
display:inline-grid;place-items:center;vertical-align:middle;border:0;cursor:pointer;
background:rgba(0,0,0,.35);box-shadow:inset 0 0 0 1px rgba(255,255,255,.16);
color:rgba(255,255,255,.72)}
.fieldedit:hover{background:rgba(255,255,255,.18);color:#fff}
.fieldedit svg{width:15px;height:15px;display:block}
.coversays{position:absolute;right:24px;bottom:66px;z-index:3;font-size:12px;
color:rgba(255,255,255,.85)}
.coversays.bad{color:#ff7a7a}
.hero .sub{margin:0;color:rgba(255,255,255,.72);font-weight:700;font-size:15px}
.toptools{position:absolute;top:26px;right:46px;display:flex;gap:8px;z-index:2}
/* The way home, in the corner every site puts it. */
.brandchip{position:absolute;top:26px;left:46px;z-index:3;display:inline-flex;
align-items:center;gap:7px;height:38px;padding:0 16px;border-radius:var(--r-pill);
background:rgba(0,0,0,.45);color:#fff;font-size:14px;font-weight:750;
-webkit-backdrop-filter:blur(18px);backdrop-filter:blur(18px);
border:1px solid rgba(255,255,255,.14)}
.brandchip:hover{text-decoration:none;background:rgba(0,0,0,.62)}
@media (max-width:520px){.brandchip{left:26px}}
.toptools a{display:grid;place-items:center;min-width:38px;height:38px;padding:0 14px;
border-radius:var(--r-pill);background:rgba(0,0,0,.45);color:#fff;font-size:13px;
font-weight:650;text-decoration:none;-webkit-backdrop-filter:blur(18px);
backdrop-filter:blur(18px);border:1px solid rgba(255,255,255,.14)}
.toptools a:hover{text-decoration:none;background:rgba(0,0,0,.62)}

main{max-width:680px;margin:0 auto;padding:28px 20px 96px}
main.wide{max-width:940px}
/* A city calendar is a scanning surface, not prose. It earns the horizontal
   space the browser gives it; other reading and editing pages keep their
   deliberately shorter measure. */
main.citywide{max-width:1720px;padding-left:36px;padding-right:36px;font-size:17px}
.withrail{max-width:1180px;margin:0 auto;padding:28px 20px 96px;
display:grid;grid-template-columns:minmax(0,1fr) 320px;gap:40px;align-items:start}
/* The Mac shows this page in a frame beside its own room controls, so the
   window it gets is narrower than a browser's. The rail gives up width before
   it gives up existing - standing beside the night is the whole point of it. */
@media (max-width:1080px){
  .withrail{grid-template-columns:minmax(0,1fr) 260px;gap:28px}
}
.rail{position:sticky;top:24px;display:grid;gap:26px}

h1{font-size:26px;font-weight:800;letter-spacing:-.015em;margin:0 0 4px}
h2{font-size:17px;font-weight:700;letter-spacing:-.01em;margin:32px 0 12px}
/* Rail headings are the console's eyebrows, not headlines. */
/* A heading with its action on the same line. */
/* The trailing hint drops under the heading rather than being squeezed beside
   it: at phone width "Following"/"Their nights show up on your home page" was
   two columns of four words each. */
.sectionhead{display:flex;align-items:center;justify-content:space-between;
gap:4px 16px;flex-wrap:wrap;margin:32px 0 12px}
.sectionhead h2{margin:0}
.rail h2{margin:0 0 12px;font-size:11px;font-weight:700;letter-spacing:.05em;
text-transform:uppercase;color:var(--label-tertiary)}
p{margin:0 0 12px}
a{color:var(--accent);text-decoration:none;font-weight:600}
a:hover{text-decoration:underline}
.muted{color:var(--label-secondary);font-size:13px;font-weight:400}
a.muted{color:var(--label-secondary)}

.card{display:block;background:var(--bg-elevated);border:1px solid var(--separator);
  border-radius:var(--r-md);padding:16px;margin:0 0 12px;color:inherit;text-decoration:none}
.lede{font-size:16px;color:var(--label-secondary);max-width:58ch;margin:0 0 24px}
.citygrid{display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));gap:10px}
.citycard{display:flex;flex-direction:column;gap:5px;margin:0;padding:14px}
.citycard strong{font-size:16px}
.citycard:hover{border-color:var(--accent);text-decoration:none}
.eventlist{display:grid;gap:8px}
.eventline{display:grid;grid-template-columns:64px 92px minmax(0,1fr);gap:12px;align-items:center;margin:0;padding:10px 14px}
.grouped-consumer-event{padding:0}
.grouped-eventline{grid-template-columns:52px minmax(0,1fr);align-items:center;padding:8px 14px}
.grouped-eventline > span{display:flex;align-items:baseline;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.grouped-eventline > .grouped-text{display:flex;gap:0}
.grouped-eventline .eventthumb{width:52px;height:44px}
.grouped-eventline .eventvenue,.grouped-eventline .eventtitle{display:inline !important;font-size:16px;min-width:0;overflow:hidden;text-overflow:ellipsis}
.grouped-eventline .eventvenue{color:var(--label-secondary);font-weight:550}
.grouped-eventline .eventtitle{color:var(--label);font-weight:750}
.grouped-eventline .eventvenue{flex:0 0 200px;max-width:32%;white-space:nowrap}
.grouped-eventline .eventtitle{flex:1 1 auto;white-space:nowrap}
.grouped-eventline .eventvenue::after{content:"";display:inline-block;width:8px}
.grouped-eventline small{display:inline;margin-left:8px}
.cityschedule{border:1px solid var(--separator);border-radius:var(--r-md);overflow:hidden}
.schedule-row{display:grid;grid-template-columns:64px 164px 220px minmax(520px,1.8fr) minmax(260px,.8fr) 74px;column-gap:18px;align-items:center;padding:8px 16px;margin:0;border:0;border-bottom:1px solid var(--separator);background:var(--bg-elevated);min-width:0;position:relative}
.schedule-row[hidden],.calendar-day[hidden],.blank[hidden]{display:none!important}
.schedule-row:nth-child(even){background:color-mix(in srgb,var(--bg-elevated) 72%,var(--fill))}
.schedule-row:hover{background:var(--fill-hover)}
.schedule-row:last-child{border-bottom:0}
.schedule-fields{display:contents}
.recurring-row{cursor:default}
.schedule-row .eventthumb,.schedule-row .schedule-image-slot{grid-column:1;width:64px;height:56px}
.schedule-row .schedule-image-slot{display:block;overflow:hidden;border:1px solid var(--separator);border-radius:var(--r-sm);background:var(--fill)}
.schedule-row .schedule-image-slot .eventthumb{display:block;width:100%;height:100%;border:0;border-radius:calc(var(--r-sm) - 1px);object-fit:cover}
.schedule-row .eventvenue{grid-column:3;color:var(--label-secondary);font-size:17px;font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.schedule-row .eventtitle{grid-column:4;color:var(--label);font-size:19px;font-weight:750;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.venue-link{color:var(--label-secondary);text-decoration:underline;text-decoration-color:color-mix(in srgb,var(--label-secondary) 55%,transparent);text-underline-offset:3px;cursor:pointer}
.venue-link:hover{color:var(--label);text-decoration-color:var(--accent)}
.schedule-event-link,.consumer-event a.eventtitle{color:var(--label);text-decoration:none;cursor:pointer}
.schedule-event-link:hover,.consumer-event a.eventtitle:hover{color:var(--accent);text-decoration:none}
.venue-link:focus-visible,.schedule-event-link:focus-visible,.consumer-event a.eventtitle:focus-visible{outline:2px solid var(--accent);outline-offset:4px;border-radius:3px}
.schedule-time{grid-column:2;min-width:0;overflow:hidden;text-overflow:ellipsis;color:var(--label-secondary);font-size:17px;font-weight:650;font-variant-numeric:tabular-nums;white-space:nowrap}
.schedule-details{grid-column:5;color:var(--label-secondary);font-size:17px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.schedule-source{grid-column:6;position:relative;z-index:2;display:inline-flex;align-items:center;justify-content:center;justify-self:start;min-width:60px;height:36px;padding:0 12px;border-radius:var(--r-pill);color:var(--label-secondary);font-size:15px;font-weight:650;cursor:pointer}
.schedule-source:hover{background:var(--fill);color:var(--label);text-decoration:none}
.calendar-day .cityschedule{margin-bottom:22px}
.city-calendar-controls{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin:0 0 4px}
.city-calendar-controls .datepresets{margin:0}
.calendar-scopes{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.calendar-scope-toggle{display:inline-flex;align-items:center;gap:8px;min-height:40px;padding:0 14px;border:1px solid var(--separator);border-radius:var(--r-pill);background:var(--fill);color:var(--label-secondary);font-size:15px;font-weight:700;cursor:pointer;user-select:none}
.calendar-scope-toggle:hover{background:var(--fill-hover);color:var(--label)}
.calendar-scope-toggle:has(input:checked){border-color:color-mix(in srgb,var(--accent) 60%,var(--separator));background:color-mix(in srgb,var(--accent) 16%,var(--fill));color:var(--label)}
.calendar-scope-toggle.disabled{opacity:.45;cursor:not-allowed}
.calendar-scope-toggle input{width:17px;height:17px;margin:0;accent-color:var(--accent)}
.city-calendar-tools{display:flex;align-items:flex-end;gap:8px;margin:0 0 16px;position:sticky;top:0;z-index:5;padding:10px 0;background:color-mix(in srgb,var(--bg) 92%,transparent);backdrop-filter:blur(18px)}
.city-calendar-tools label{display:grid;gap:4px;color:var(--label-secondary);font-size:11px;font-weight:650}
.city-calendar-tools input{box-sizing:border-box;background:var(--fill-hover);border:1px solid var(--separator);border-radius:var(--r-sm);color:var(--label);padding:9px 11px;font:inherit}
.city-calendar-tools input[type=search]{width:100%;min-width:180px}
.city-calendar-tools .grow{flex:1}.city-calendar-tools .grow input{width:100%}
.city-back{margin:8px 0 14px}.city-back a{color:var(--label-secondary);font-size:15px}
.citypage-head{display:flex;align-items:center;justify-content:space-between;gap:12px;margin:12px 0 10px}.citypage-head h1{margin:0}
.citywide .citypage-head h1{font-size:38px}
.citywide .citypage-head .muted{font-size:15px}
.citywide .catalognav a{font-size:16px}
.citywide .datepresets .btn.small{font-size:15px;min-height:40px}
.citywide .city-calendar-tools label{font-size:14px}
.citywide .city-calendar-tools input{min-height:48px;font-size:17px}
.citypage-head+.citypick{margin-bottom:10px}
.eventline time{color:var(--label-secondary);font-variant-numeric:tabular-nums;font-weight:500}
.eventline span{min-width:0;display:grid;gap:3px}
.eventline b{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.consumer-event .eventline{color:var(--label);text-decoration:none}
.consumer-event .eventline b{color:var(--label);font-weight:700}
.consumer-event .eventline .eventvenue{color:var(--label-secondary);font-weight:550}
.consumer-event .eventline .eventtitle{color:var(--label);font-weight:750}
.eventline small{color:var(--label-secondary)}
@media (max-width:1500px){
  .schedule-row{grid-template-columns:58px 148px 190px minmax(320px,1fr) minmax(190px,.72fr) 64px;column-gap:14px}
  .schedule-details,.schedule-details-label{display:none}
  .schedule-row .eventthumb,.schedule-row .schedule-image-slot{width:58px;height:50px}
  .schedule-source{grid-column:6}.recurring-row .eventtitle{grid-column:4/6}
}
@media (max-width:900px){
  .schedule-row{grid-template-columns:48px 132px 160px minmax(180px,1fr) 56px}
  .schedule-details{display:none}
  .schedule-row .eventthumb,.schedule-row .schedule-image-slot{width:48px;height:42px}
  .schedule-source{grid-column:5}.schedule-time{grid-column:2}.schedule-row .eventvenue{grid-column:3}.schedule-row .eventtitle,.recurring-row .eventtitle{grid-column:4}
}
@media (max-width:640px){
  .grouped-eventline .eventvenue{flex-basis:130px;max-width:38%}
  main.citywide{padding-left:16px;padding-right:16px}
  .schedule-row{grid-template-columns:56px 116px minmax(90px,1fr) 44px;column-gap:8px;padding-left:10px;padding-right:10px}
  .schedule-row .eventthumb,.schedule-row .schedule-image-slot{display:none}
  .schedule-time{grid-column:1}.schedule-row .eventvenue{grid-column:2}.schedule-row .eventtitle,.recurring-row .eventtitle{grid-column:3}.schedule-source{grid-column:4}
  .schedule-row .eventvenue{font-size:14px}.schedule-row .eventtitle{font-size:15px}.schedule-time{font-size:13px}.schedule-source{min-width:42px;height:30px;padding:0 6px;font-size:12px}
  .citypage-head{align-items:baseline}.citypage-head h1{font-size:24px}
}
.eventhero,.eventthumb{display:block;box-sizing:border-box;width:100%;min-width:0;max-width:100%;height:auto;
object-fit:contain;object-position:center;background:var(--bg-elevated-2);border-radius:var(--r-sm);
overflow:hidden}
/* Source posters are frequently huge, oddly proportioned, or served at their
   original pixel size. Keep them in a bounded frame so one bad asset cannot
   widen the page or make the catalog unusably tall. */
.eventhero{height:min(520px,62vw);min-height:180px}
.eventthumb{height:52px;object-fit:cover;margin:0;border-radius:8px}
.consumer-event{overflow:hidden;min-width:0}
.calendar-day{margin:26px 0}.calendar-day>h2{position:sticky;top:0;z-index:2;
margin:0 0 10px;padding:9px 0;background:color-mix(in srgb,var(--bg) 92%,transparent);
backdrop-filter:blur(16px);font-size:15px}
.consumer-actions .active{box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--accent) 65%,transparent)}
.citydirectory{display:grid;gap:8px;margin:16px 0 24px}
.cityrow{display:flex;justify-content:space-between;align-items:center;margin:0;padding:14px 16px}
.cityrow:hover{border-color:var(--accent);text-decoration:none}
a.card:hover{text-decoration:none;background:var(--bg-elevated-2)}
.when{font-size:12px;color:var(--label-tertiary);font-variant-numeric:tabular-nums;
font-weight:650;letter-spacing:.02em}
.card strong{display:block;font-size:16px;font-weight:700;margin:2px 0}

.actionbar{display:flex;align-items:center;gap:14px;width:100%;
background:var(--accent);color:#fff;border:none;border-radius:var(--r-md);
padding:15px 18px;margin:18px 0 10px;font:inherit;font-size:16px;font-weight:750;
cursor:pointer;text-decoration:none;transition:filter .15s}
.actionbar:hover{text-decoration:none;filter:brightness(1.06)}
.actionbar .tile{display:grid;place-items:center;width:42px;height:42px;flex:0 0 42px;
border-radius:12px;background:rgba(255,255,255,.2);font-size:20px}
.actionbar .lines{display:grid;gap:1px;text-align:left;min-width:0}
.actionbar .lines small{font-weight:550;font-size:12px;opacity:.88}
.actionbar.quiet{background:var(--bg-elevated);color:var(--label);
border:1px solid var(--separator)}
.actionbar.quiet .tile{background:var(--fill)}

.btn{display:inline-flex;align-items:center;justify-content:center;min-height:40px;
padding:11px 20px;border:none;border-radius:var(--r-pill);background:var(--accent);
color:#fff;font:inherit;font-size:15px;font-weight:700;cursor:pointer;
transition:filter .15s}
.btn:hover{text-decoration:none;filter:brightness(1.06)}
.btn.plain{background:var(--fill);color:var(--label);border:1px solid var(--separator)}
.btn.plain:hover{background:var(--fill-hover)}
.btn.small{min-height:34px;padding:8px 14px;font-size:13px}
:focus-visible{outline:2px solid var(--accent);outline-offset:2px}

input[type=email],input[type=text]{width:100%;min-height:44px;padding:11px 14px;
border-radius:var(--r-sm);border:1px solid var(--separator);background:var(--bg-elevated);
color:var(--label);font:inherit;font-size:15px;outline:none}
input::placeholder{color:var(--label-tertiary)}
input:focus{border-color:var(--accent)}
form.join{display:flex;gap:8px;flex-wrap:wrap;margin:16px 0 8px}
form.join input{flex:1 1 200px;min-width:0;width:auto}
.row{display:flex;gap:8px;flex-wrap:wrap;align-items:center}

.post{background:var(--bg-elevated);border:1px solid var(--separator);
border-radius:var(--r-md);padding:14px;margin:0 0 10px}
.post .who{font-weight:700;font-size:14px}
.post .who a{color:inherit;font-weight:inherit}
.posthead{display:flex;align-items:center;gap:10px;margin-bottom:8px}
.posthead .avatar{width:34px;height:34px;flex:0 0 34px;font-size:13px;margin:0}
.posthead .grow{min-width:0}
.postmedia{display:block;width:100%;max-height:520px;object-fit:cover;margin-top:10px;
border-radius:var(--r-sm);background:var(--bg-elevated-2)}

/* Saying something, with or without a picture, the way the console's party
   feed does it: one box, the camera on the left, Post on the right. */
form.say{background:var(--bg-elevated);border:1px solid var(--separator);
border-radius:var(--r-md);padding:14px;margin:0 0 14px;display:grid;gap:10px}
form.say textarea{width:100%;min-height:64px;padding:11px 14px;border-radius:var(--r-sm);
border:1px solid var(--separator);background:var(--bg-elevated-2);color:var(--label);
font:inherit;font-size:15px;outline:none;resize:vertical}
form.say textarea:focus{border-color:var(--accent)}
form.say .sayrow{display:flex;gap:10px;align-items:center;justify-content:space-between}
form.say .pickfile{display:inline-flex;align-items:center;gap:8px;min-height:40px;
padding:0 16px;border-radius:var(--r-pill);background:var(--accent);color:#fff;
font-size:14px;font-weight:700;cursor:pointer}
form.say .pickfile input{display:none}
form.say .picked{font-size:12px;color:var(--label-secondary)}
footer{max-width:1180px;margin:48px auto 0;padding:20px;
border-top:1px solid var(--separator);font-size:13px;display:flex;gap:20px;
align-items:center;justify-content:space-between;flex-wrap:wrap}
footer.citywide-footer{max-width:1720px;padding-left:36px;padding-right:36px}
@media (max-width:640px){footer.citywide-footer{padding-left:16px;padding-right:16px}}

form.newnight{display:grid;gap:10px;margin:16px 0 28px;padding:16px;
background:var(--bg-elevated);border:1px solid var(--separator);border-radius:var(--r-md)}
form.newnight .row input{flex:1 1 140px;width:auto}
form.newnight .btn{justify-self:start}

.linkrow{display:flex;gap:8px;align-items:center;margin:10px 0}
.linkbox{flex:1 1 auto;min-width:0;font-size:12px;padding:9px 12px;min-height:0;
color:var(--label-secondary);border-radius:var(--r-sm);font-family:var(--mono)}

/* Participants, as the console lists them: a disc, a name, what they are. */
.avatars{display:flex;align-items:center;flex-wrap:wrap;margin:0 0 12px}
.avatar{width:34px;height:34px;border-radius:50%;display:grid;place-items:center;
margin-left:-7px;border:2px solid var(--bg-elevated);
background:linear-gradient(135deg,#ff2d6f,#ff8a4c);color:#fff;font-size:12px;
font-weight:800}
.avatar:first-child{margin-left:0}
.avatar.more{background:var(--fill);color:var(--label-secondary)}
.avatar{overflow:hidden}
.avatar img{width:100%;height:100%;object-fit:cover;display:block}
.avatar.big{width:52px;height:52px;flex:0 0 52px;font-size:18px;margin:0}
.who-list{display:grid;gap:12px;margin:0;padding:0;list-style:none}
.who-list li{display:flex;align-items:center;gap:10px}
.who-list .avatar{width:32px;height:32px;font-size:12px;margin:0;flex:0 0 32px}
.who-list b{display:block;font-size:14px;font-weight:650}
.who-list b a{color:inherit;font-weight:inherit}
.who-list small{display:block;font-size:11px;color:var(--label-tertiary);
letter-spacing:.04em;text-transform:uppercase}
.who-list small.at{text-transform:none;letter-spacing:0;font-size:12px;
font-family:var(--mono)}
/* A section per kind of person, the way the guest's phone heads a DJ above the
   room listening to them. */
.whogroup + .whogroup{margin-top:18px}
.whohead{display:flex;align-items:baseline;gap:6px;margin:0 0 10px;font-size:11px;
font-weight:700;letter-spacing:.05em;text-transform:uppercase;color:var(--label-secondary)}
.whohead small{font-size:11px;color:var(--label-tertiary);font-weight:600}

/* "About You", as the console draws it: a round picture you can replace, your
   name and a line about you side by side, and the three link pills under them.
   Optional throughout - a profile with nothing filled in is a finished one. */
.you{background:var(--bg-elevated);border:1px solid var(--separator);
border-radius:var(--r-md);padding:18px;margin:0 0 14px}
.yourow{display:flex;gap:16px;align-items:flex-start;flex-wrap:wrap}
.yourow .grow{flex:1 1 190px;min-width:0;display:grid;gap:10px}
.twoup{display:grid;grid-template-columns:1fr 1fr;gap:10px}
/* Sized by what is in it, not pinned to the disc: a fixed 76px box left the
   "Add a photo" line hanging outside it, over whatever wrapped underneath. */
.avatarpick{position:relative;flex:0 0 76px;width:76px;cursor:pointer;display:block}
.avatarpick .disc{width:76px;height:76px;border-radius:50%;overflow:hidden;
display:grid;place-items:center;background:linear-gradient(135deg,#ff2d6f,#ff8a4c);
color:#fff;font-size:26px;font-weight:800;border:1px solid var(--separator)}
.avatarpick .disc img{width:100%;height:100%;object-fit:cover;display:block}
.avatarpick input{position:absolute;inset:0;opacity:0;cursor:pointer}
.avatarpick .hintline{display:block;margin-top:6px;text-align:center;font-size:11px;
color:var(--label-tertiary)}
.dropx{position:absolute;top:-4px;right:-4px;width:24px;height:24px;border-radius:50%;
display:grid;place-items:center;background:rgba(0,0,0,.72);color:#fff;border:0;
font-size:12px;cursor:pointer;z-index:2}
/* Three across, as the console has them. The minimum is what one pill needs
   for its label plus a readable field, not what looks comfortable alone -
   set any higher and the third wraps onto a row of its own. */
.socials{display:grid;grid-template-columns:repeat(auto-fit,minmax(148px,1fr));gap:10px}
.pill{display:flex;align-items:center;gap:0;background:var(--bg-elevated-2);
border:1px solid var(--separator);border-radius:var(--r-pill);padding:0 6px 0 14px;
min-height:44px;overflow:hidden}
.pill span{flex:0 0 auto;font-size:14px;font-weight:650;color:var(--label-secondary);
padding-right:10px;margin-right:10px;border-right:1px solid var(--separator)}
.pill input{border:0;background:transparent;min-height:40px;padding:0;
border-radius:0;font-size:14px}
.pill input:focus{border:0}
.youbar{display:flex;gap:10px;align-items:center;margin-top:14px;flex-wrap:wrap}
.youbar .muted{margin:0}
/* What the @name field has to say about itself, while it is still in front of
   the person typing it. */
.handlesays{font-size:13px;font-weight:650;color:var(--label-tertiary)}
/* A party in a list: the date above the name, the way a diary reads. */
.partyrow{display:flex;align-items:center;gap:14px}
.partyrow .grow{min-width:0}
.tag{display:inline-block;margin:6px 6px 0 0;padding:2px 9px;border-radius:var(--r-pill);
font-size:11px;font-weight:700;letter-spacing:.02em;background:var(--fill);
color:var(--label-secondary)}
.tag.quiet{background:transparent;box-shadow:inset 0 0 0 1px var(--separator)}
.tag.live{background:rgba(255,45,111,.16);color:var(--accent)}
/* A night has a colour. Derived from the cover's own name rather than its
   pixels - a Worker has no image pipeline, and a stable hue per picture is the
   honest version of the same idea: every party looks like itself, and looks the
   same every time you open it. */
.nightlit{--night:var(--accent)}
.nightlit .hero .cover{box-shadow:var(--shadow),0 0 90px -30px var(--night)}
.nightlit h2{color:var(--label)}
.nightlit .entry:hover,.nightlit .people li:hover{
background:color-mix(in srgb,var(--night) 7%,var(--bg-elevated))}
.nightlit .addline:focus-within{border-color:var(--night)}
.nightlit .addline:focus-within button,.nightlit button.onfocus{background:var(--night)}

/* Photos first: a night is mostly pictures, and a grid is how you look back at
   one. Two up on a phone, three where there is room. */
.roll{display:grid;grid-template-columns:repeat(auto-fill,minmax(140px,1fr));
gap:6px;margin:0 0 16px}
.roll figure{margin:0;position:relative;border-radius:var(--r-sm);overflow:hidden;
background:var(--bg-elevated);aspect-ratio:1}
.roll img,.roll video{width:100%;height:100%;object-fit:cover;display:block}
.roll figcaption{position:absolute;left:0;right:0;bottom:0;padding:16px 10px 8px;
font-size:12px;color:#fff;background:linear-gradient(transparent,rgba(0,0,0,.72));
overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

/* An empty space says what belongs in it, not that it is empty. */
.blank{margin:0 0 10px;padding:14px 12px;border-radius:var(--r-sm);
background:var(--bg-elevated);color:var(--label-tertiary);font-size:14px;line-height:1.5}

/* Somebody you know, and the last night you saw them at - the fact this page
   exists to answer, with their face on it like everywhere else. */
.seen{display:grid;grid-template-columns:36px minmax(0,1fr) auto;gap:12px;
align-items:center;padding:13px 12px;border-bottom:1px solid var(--separator);
text-decoration:none;color:var(--label)}
.seen:hover{background:var(--bg-elevated);text-decoration:none}
.seen .entrybody b{font-size:16px}

/* Starting a night: the name is the page, and the two answered things sit
   under it as one quiet row. */
.startnight{display:grid;gap:12px;margin:14px 0}
.startnight input.bigname{width:100%;border:0;background:none;padding:0;min-height:0;
font:inherit;font-size:30px;font-weight:800;letter-spacing:-.025em;
color:var(--label);outline:none;box-shadow:none}
.startnight input.bigname::placeholder{color:var(--label-tertiary)}
.startrow{display:flex;gap:8px;flex-wrap:wrap}
.startrow input{flex:1 1 150px;min-width:0;width:auto;min-height:44px;padding:11px 14px;
border-radius:var(--r-sm);border:1px solid var(--separator);background:var(--bg-elevated);
color:var(--label);font:inherit;font-size:15px;outline:none}
.startrow input:focus{border-color:var(--accent)}
.startnight .btn{justify-self:start}

/* The capture line. The sentence the app exists for goes in here without
   scrolling to find the right section: type the names or the tracks, say what
   they are. The sections below are for correcting, not for entering. */
.capture{position:sticky;top:8px;z-index:5;margin:0 0 26px;padding:10px 12px;
border-radius:var(--r-md);background:var(--bg-elevated-2);
box-shadow:0 8px 24px -18px #000;backdrop-filter:blur(18px)}
.capture input{width:100%;border:0;background:none;padding:4px 2px;min-height:32px;
font:inherit;font-size:16px;color:var(--label);outline:none}
.capture input::placeholder{color:var(--label-tertiary)}
.as{display:flex;gap:6px;margin-top:6px}
.as button{flex:1 1 0;border:0;border-radius:var(--r-pill);padding:8px 4px;
background:var(--bg-elevated);color:var(--label-secondary);font:inherit;
font-size:13px;font-weight:650;cursor:pointer}
.as button:hover{background:var(--night,var(--accent));color:#fff}

/* The welcome, folded down to one line. */
details.welcome{margin:0 0 18px}
details.welcome summary .avatar{flex:0 0 auto}
details.welcome summary{display:flex;align-items:center;gap:12px;cursor:pointer;
padding:10px 12px;border-radius:var(--r-md);list-style:none}
details.welcome summary::-webkit-details-marker{display:none}
details.welcome summary:hover{background:var(--bg-elevated)}
details.welcome summary span{display:grid;gap:1px;min-width:0}
details.welcome summary b{font-size:15px}
details.welcome summary small{font-size:13px;color:var(--label-tertiary)}
details.welcome[open] summary{margin-bottom:6px}

/* One scale, everywhere. Three sections were designed on three different days
   and it read like it: headings at four sizes, secondary text at three. */
h1{font-size:clamp(28px,4.4vw,34px);letter-spacing:-.025em;line-height:1.08}
h2{font-size:19px;letter-spacing:-.02em}
.muted{font-size:14px;line-height:1.5}

/* Motion, of the kind you notice only when it is missing: entries settle in
   rather than appearing, and each one a beat after the last. Nothing moves for
   somebody who asked for less. */
@keyframes settle{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}
.entry,.people li,.setlist li{animation:settle .28s cubic-bezier(.22,.61,.36,1) both}
.entry:nth-child(2){animation-delay:.03s}
.entry:nth-child(3){animation-delay:.06s}
.entry:nth-child(4){animation-delay:.09s}
.entry:nth-child(n+5){animation-delay:.12s}
.btn,.entry,.people li,.x,.addline{transition:background .14s ease,color .14s ease,
border-color .14s ease,opacity .14s ease}
@media (prefers-reduced-motion:reduce){
  .entry,.people li,.setlist li{animation:none}
}

/* Home as a journal timeline. A row in a table tells you nothing; an entry
   says when, where, and what is in it, and is a whole tap target. */
.entries{display:grid;margin:0 0 8px;border-top:1px solid var(--separator)}
.entry{display:grid;grid-template-columns:88px minmax(0,1fr) auto;gap:14px;
align-items:baseline;padding:16px 12px;border-bottom:1px solid var(--separator);
text-decoration:none;color:var(--label)}
.entry:hover{background:var(--bg-elevated);text-decoration:none}
.entrywhen{font-size:13px;font-weight:650;color:var(--label-tertiary);
font-variant-numeric:tabular-nums;line-height:1.5}
.entrybody{display:grid;gap:3px;min-width:0}
.entrybody b{font-size:17px;letter-spacing:-.01em;line-height:1.25}
.entrywhere{font-size:14px;color:var(--label-secondary)}
.entryinside{font-size:13px;color:var(--label-tertiary);overflow:hidden;
text-overflow:ellipsis;white-space:nowrap}
@media (max-width:520px){
  .entry{grid-template-columns:minmax(0,1fr) auto;gap:4px 10px;padding:14px 10px}
  .entry .entrywhen{grid-column:1/-1;order:-1}
}
.tracker{margin-top:4px}
.tracker h2:first-child{margin-top:18px}
.wentrow{display:flex;align-items:center;gap:10px;font-size:15px;font-weight:650}
.wentrow input{width:20px;height:20px;accent-color:var(--accent)}
.notemini{display:flex;gap:6px;margin-top:6px;flex-wrap:wrap}
.notemini input[type=text]{flex:1 1 200px;min-width:0;width:auto;min-height:36px;
padding:7px 12px;font-size:13px}
.who-list li{align-items:flex-start}
.eventfield{display:grid;gap:6px}
.eventfield span{font-size:12px;font-weight:700;letter-spacing:.03em;
text-transform:uppercase;color:var(--label-tertiary)}
/* Two facts side by side, one under the other when there is no room for two.
   A person's public address and the account behind it were a sentence before,
   which is a bad shape for the one thing on the page you copy and send. */
.factrow{display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));
gap:8px 20px;margin:2px 0 10px}
.factrow .linkrow{margin:0}
/* How many tracks a night is about to gain, which is the number somebody is
   actually reading, so it is not a grey aside at the end of a date. */
.importnight{display:flex;align-items:baseline;justify-content:space-between;gap:12px}
.importnight .tag{margin:0;flex:0 0 auto}
textarea{width:100%;padding:11px 14px;border-radius:var(--r-sm);
border:1px solid var(--separator);background:var(--bg-elevated);color:var(--label);
font:inherit;font-size:15px;outline:none;resize:vertical}
textarea:focus{border-color:var(--accent)}
input[type=datetime-local],input[type=search]{width:100%;min-height:44px;padding:11px 14px;
border-radius:var(--r-sm);border:1px solid var(--separator);background:var(--bg-elevated);
color:var(--label);font:inherit;font-size:15px;outline:none}
input[type=datetime-local]:focus,input[type=search]:focus{border-color:var(--accent)}
/* The record, as a journal rather than a form.
   Nothing here announces itself as an input until it is touched: a note reads
   as the note it holds, an empty one as grey placeholder text, and the borders
   and the Save button appear on focus. Four stacked controls per person is
   what a form looks like; one line with a name on it is what a page you write
   on looks like. */
.tracker h2{font-size:19px;letter-spacing:-.02em;margin:34px 0 10px}
.people{list-style:none;padding:0;margin:0 0 6px;display:grid;gap:2px}
.people li{display:grid;grid-template-columns:36px minmax(0,1fr);gap:12px;
align-items:start;padding:10px 12px;border-radius:var(--r-sm)}
.people li:hover{background:var(--bg-elevated)}
.personline{display:grid;gap:2px;min-width:0}
.nameline{display:flex;align-items:center;gap:8px}
.nameline a{font-weight:700;text-decoration:none;color:var(--label)}
.nameline a:hover{color:var(--accent)}
.x{margin-left:auto;border:0;background:none;color:var(--label-tertiary);
font-size:13px;line-height:1;padding:4px 6px;border-radius:var(--r-sm);
cursor:pointer;opacity:0;transition:opacity .12s}
.people li:hover .x,.x:focus{opacity:1}
input.quiet{width:100%;border:0;background:none;padding:2px 0;min-height:0;
font:inherit;font-size:14px;color:var(--label-secondary);outline:none}
input.quiet::placeholder{color:var(--label-tertiary)}
input.quiet:focus{color:var(--label)}
/* The save only exists once you are typing. */
button.onfocus{display:none;justify-self:start;margin-top:6px;border:0;
background:var(--accent);color:#fff;font:inherit;font-size:13px;font-weight:700;
padding:6px 14px;border-radius:var(--r-pill);cursor:pointer}
.personline:focus-within button.onfocus{display:block}

/* One line to add anything: type, press +. */
.addline{display:flex;flex-wrap:nowrap;align-items:center;gap:8px;margin:0 0 4px;
padding:9px 12px;border-radius:var(--r-sm);border:1px dashed var(--separator)}
.addline:focus-within{border-style:solid;border-color:var(--accent)}
.addline input{flex:1 1 auto;min-width:0;width:auto;border:0;background:none;
padding:0;min-height:26px;font:inherit;font-size:15px;color:var(--label);outline:none}
.addline.two input:last-of-type{flex:0 1 38%;font-size:14px;color:var(--label-secondary)}
.addline button{flex:0 0 auto;width:30px;height:30px;border:0;border-radius:50%;
background:var(--bg-elevated-2);color:var(--label-secondary);font-size:17px;
line-height:1;cursor:pointer}
/* A track that is a picture. The screenshot leads the row at a size you can
   actually read a track name off, with anything typed beside it. */
.setlist li.shot{align-items:center;gap:12px}
.shotwrap{flex:0 0 auto;display:block;width:96px;border-radius:var(--r-sm);
overflow:hidden;background:var(--bg-elevated-2)}
.shotwrap img{display:block;width:100%;height:auto}
.addtrack{margin-top:10px}
.addtrack .camera{width:32px;height:32px;border-radius:50%;flex:0 0 auto;border:0;
background:var(--fill);color:var(--label-secondary);display:grid;place-items:center;
cursor:pointer;padding:0}
.addtrack .camera:hover{background:var(--fill-hover);color:var(--label)}
.addtrack .camera svg{width:18px;height:18px}

/* The composer. A box you write in, with its actions along the bottom - the
   shape the console had, which is a place to write rather than a field to
   fill. It lights up when a photo is over it. */
.composer{border:1px dashed var(--separator);border-radius:var(--r-md);
padding:10px 12px 8px;margin:0 0 12px;display:grid;gap:8px;
transition:border-color .14s ease,background .14s ease}
.composer:focus-within{border-style:solid;border-color:var(--accent)}
.composer.dropping{border-style:solid;border-color:var(--accent);
background:color-mix(in srgb,var(--accent) 8%,transparent)}
.composer textarea{width:100%;border:0;background:none;outline:none;resize:vertical;
min-height:44px;font:inherit;font-size:15px;color:var(--label)}
.composer textarea::placeholder{color:var(--label-tertiary)}
.composerbar{display:flex;align-items:center;gap:10px}
.composer .camera{width:34px;height:34px;border:0;border-radius:50%;flex:0 0 auto;
background:var(--fill);color:var(--label-secondary);display:grid;place-items:center;
cursor:pointer;padding:0}
.composer .camera:hover{background:var(--fill-hover);color:var(--label)}
.composer .camera svg{width:19px;height:19px}
.composer .grow{flex:1 1 auto}

/* Adding to a list in the rail: the field, then a plus. One row - the two-word
   answers it used to need went away with the question. */
.addwho{margin-top:12px}

/* "I was there" is a phrase, not a plus sign: it needs a pill it fits inside,
   or the round icon button squashes it onto three lines. */
.wasthere{margin-top:14px}
.wasthere button{width:auto;height:34px;padding:0 16px;border-radius:var(--r-pill);
white-space:nowrap;font-size:14px;font-weight:700;background:var(--accent);color:#fff}
.addline:focus-within button{background:var(--accent);color:#fff}
.seenby{display:flex;flex-wrap:wrap;gap:8px;margin:0 0 8px}
/* The visibility picker, always open. A class called seen is already a person-entry
   grid elsewhere in this sheet, and naming this one the same turned the three
   choices into three stacked circles - what a collision looks like from the
   outside. (No backticks in here: the stylesheet is a template literal.) */
.seenpick{margin:0 0 18px}
.seenpick .muted{margin:0}
hr.soft{border:0;border-top:1px solid var(--separator);margin:34px 0}

/* What was played, in the order it was played. Numbers in the margin so the
   list reads as a record rather than as another form. */
.setlist{list-style:none;counter-reset:song;padding:0;margin:0 0 12px;display:grid;gap:2px}
.setlist li{counter-increment:song;display:flex;align-items:center;gap:10px;
padding:9px 12px;border-radius:var(--r-sm);min-width:0}
.setlist li:nth-child(odd){background:var(--bg-elevated)}
.setlist li::before{content:counter(song);font-variant-numeric:tabular-nums;
font-size:12px;font-weight:700;color:var(--label-tertiary);min-width:1.4em}
.setlist .grow{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.setlist form{margin:0;flex:0 0 auto}
.setlist li:hover .x,.setlist .x:focus{opacity:1}
.addline .camera{background:none;color:var(--label-tertiary);width:30px;height:30px;
display:grid;place-items:center}
.addline .camera svg{width:19px;height:19px}
.addline .camera:hover{color:var(--label)}
.handlesays[data-state="ok"]{color:var(--success)}
.handlesays[data-state="bad"]{color:var(--accent)}

/* A room that is playing right now, and the way back into it. */
.nowplaying{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin:0 0 14px;
padding:12px 16px;border-radius:var(--r-sm);background:rgba(255,45,111,.12);
border:1px solid rgba(255,45,111,.32);font-weight:700}
.nowplaying .dot{width:9px;height:9px;border-radius:50%;background:var(--accent);
box-shadow:0 0 0 0 rgba(255,45,111,.55);animation:pulse 1.8s ease-out infinite}
@keyframes pulse{70%{box-shadow:0 0 0 9px rgba(255,45,111,0)}
100%{box-shadow:0 0 0 0 rgba(255,45,111,0)}}
@media (prefers-reduced-motion:reduce){.nowplaying .dot{animation:none}}
.linklist{list-style:none;padding:0;margin:0 0 14px;display:flex;flex-wrap:wrap;gap:8px}
.linklist a{display:inline-block;padding:7px 14px;border-radius:var(--r-pill);
background:var(--bg-elevated);border:1px solid var(--separator);
font-size:14px;font-weight:650;text-decoration:none;max-width:100%;
overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
details.edit{margin:0}
details.edit summary{padding:5px 0}
/* Who may see it, as one chip with the night. */
/* One row of quiet controls under the night, not a stack of them. Either can
   open, and opening one takes the whole row's width. */
.nightbar{display:flex;flex-wrap:wrap;align-items:center;gap:12px;margin:0 0 6px}
.nightbar details[open]{flex:1 1 100%}
details.seen{display:inline-block;border:0}
details.seen summary{display:inline-flex;align-items:center;gap:7px;cursor:pointer;
list-style:none;font-size:13px;font-weight:600;color:var(--label-secondary);
padding:5px 12px;border-radius:var(--r-pill);background:var(--bg-elevated)}
details.seen summary::-webkit-details-marker{display:none}
details.seen summary:hover{color:var(--label)}
.dotv{width:7px;height:7px;border-radius:50%;background:var(--label-tertiary)}
.dotv.link{background:#f0b429}
.dotv.public{background:var(--success,#3ddc84)}
details.seen[open]{display:block;margin-bottom:10px}
details.edit summary{cursor:pointer;font-size:13px;font-weight:600;
color:var(--label-secondary);padding:6px 0;list-style:none}
details.edit summary::-webkit-details-marker{display:none}
details.edit summary::before{content:'\\2699\\FE0E';padding-right:8px}
details.edit summary:hover{color:var(--label)}
details.edit[open] summary{margin-bottom:12px}
/* Once a photo is waiting, Save is the only thing left to do. */
@keyframes nudge{0%,100%{transform:scale(1)}50%{transform:scale(1.05)}}
.btn.nudge{animation:nudge .9s ease-in-out 2}
@media (prefers-reduced-motion:reduce){.btn.nudge{animation:none}}
.btn:disabled{opacity:.45;cursor:not-allowed;filter:none}
.formerror{margin:0 0 14px;padding:11px 14px;border-radius:var(--r-sm);
background:rgba(255,45,111,.12);border:1px solid rgba(255,45,111,.35);
color:var(--label);font-size:14px;font-weight:650}
.handlepill{display:inline-flex;align-items:center;background:var(--bg-elevated-2);
border:1px solid var(--separator);border-radius:var(--r-pill);padding:0 14px;
min-height:44px;font-weight:700}
.handlepill span{color:var(--label-tertiary);padding-right:2px}
.handlepill input{border:0;background:transparent;min-height:42px;padding:0;
font-weight:700;width:auto;flex:1 1 auto}
.handlepill input:focus{border:0}

/* Changing the picture on a cover, the way the console does it: the buttons
   sit on the image itself rather than in a settings drawer below it. */
.coveractions{position:absolute;right:26px;bottom:26px;display:flex;gap:8px;z-index:2}
.coveractions{right:20px;bottom:auto;top:20px}
.coveractions button{width:32px;height:32px;padding:0;border-radius:50%;
background:rgba(0,0,0,.34);color:rgba(255,255,255,.78);font:inherit;font-size:15px;
cursor:pointer;-webkit-backdrop-filter:blur(18px);backdrop-filter:blur(18px);
border:1px solid rgba(255,255,255,.14)}
.coveractions button:hover{background:rgba(0,0,0,.62)}
.coveractions input{display:none}

/* Nights as a schedule. */
.timeline{position:relative;margin:8px 0 4px;padding-left:22px}
.timeline::before{content:'';position:absolute;left:5px;top:6px;bottom:6px;width:2px;
background:var(--separator);border-radius:2px}
.tl{position:relative;display:block;padding:0 0 18px;color:inherit;text-decoration:none}
.tl::before{content:'';position:absolute;left:-21px;top:6px;width:12px;height:12px;
border-radius:50%;background:var(--accent);border:2px solid var(--bg)}
.tl.past::before{background:var(--label-tertiary)}
.tl:hover{text-decoration:none}
.tl:hover .tlname{text-decoration:underline}
.tlname{display:block;font-size:16px;font-weight:700}

details.settings{margin-top:44px;border-top:1px solid var(--separator)}
details.settings summary{cursor:pointer;padding:16px 0;color:var(--label-secondary);
font-weight:650;list-style:none}
details.settings summary::-webkit-details-marker{display:none}
details.settings summary::before{content:"› ";display:inline-block;transition:transform .15s}
details.settings[open] summary::before{transform:rotate(90deg)}
details.settings h2{font-size:15px;margin:24px 0 6px}
details.tinyhelp summary{cursor:pointer;font-size:12px;font-weight:600;
color:var(--label-tertiary);margin-top:6px}
details.tinyhelp p{margin:8px 0 0}

@media (max-width:760px){
  .withrail{grid-template-columns:minmax(0,1fr);gap:8px}
  .rail{position:static}
}
@media (max-width:520px){
  .hero{padding:0 12px}
  /* The cover becomes a column on a phone. Left as a bottom-aligned row, a
     two-line title runs straight under the Shuffle/Upload buttons pinned in
     the corner - there is no room for both on 375px, so the buttons stop
     floating and take a line of their own under the name. */
  .hero .cover{min-height:180px;padding:16px;flex-direction:column;
  align-items:stretch;justify-content:flex-end;gap:14px}
  .hero h1{font-size:30px}
  .hero .cover .titles{margin-top:56px}
  .coveractions{right:14px;top:14px}
  .coversays{position:static;order:-1}
  .toptools{top:16px;right:16px}
  .brandchip{top:16px;left:16px}
  .coverx{top:16px;right:16px}
  .hero:has(.coverx) .toptools{right:62px}
  .hero:has(.cover.bare) .toptools{right:16px}
}
/* Pencil and ink. A suggested card is visibly provisional - dashed edge,
   quieter surface - and the amber tag is the pencil mark every unconfirmed
   field wears, wherever it appears. Ink is just the ordinary page. */
.card.suggest{border-style:dashed;border-color:rgba(255,214,90,.28);
background:rgba(255,214,90,.03)}
.tag.pencil{background:rgba(255,214,90,.14);color:#ffd65a}
.acts{display:flex;gap:8px;margin-top:12px}
/* Asking which room, when several are in reach. The order IS the confidence,
   so it reads top-down and the likeliest is already chosen. */
.whichone{display:grid;gap:2px;margin-top:10px}
.whichone .muted{font-size:12px}
.pick{display:flex;align-items:baseline;gap:8px;padding:6px 0;font-size:14px;
cursor:pointer}
.pick input{accent-color:var(--accent);margin:0}
.pick .muted{font-size:12px}
.suggestedit{margin-top:10px}
.suggestedit summary{cursor:pointer;color:var(--label-tertiary);font-size:13px}
.suggestedit[open] summary{margin-bottom:8px}
.suggestedit label{display:grid;gap:4px;margin:0 0 10px;font-size:13px;
color:var(--label-secondary)}
.suggestedit input{background:var(--fill);border:1px solid var(--separator);
border-radius:var(--r-sm);color:var(--label);padding:9px 11px;font:inherit}
.offer{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin-top:10px;
padding:10px 12px;border:1px dashed rgba(255,214,90,.28);border-radius:var(--r-sm);
background:rgba(255,214,90,.03)}
.offer .tag{margin:0}
.offer .muted{flex:1;min-width:140px}
.candidate-events{display:grid;gap:4px;margin:12px 0 0;padding:10px 12px;
border:1px solid var(--separator);border-radius:var(--r-sm)}
.candidate-events legend{padding:0 5px;color:var(--label-secondary);font-size:12px;
font-weight:750}
.candidate-events .pick{align-items:flex-start;border-radius:10px;padding:8px}
.candidate-events .pick:hover{background:var(--fill)}
.candidate-events .pick span{display:grid;gap:2px;min-width:0}
.candidate-events .pick small{color:var(--label-secondary);font-size:12px;
white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.suggestion-evidence{display:flex;align-items:center;gap:6px;flex-wrap:wrap;margin-top:10px;
color:var(--label-secondary);font-size:12px}
.suggestion-evidence .tag{margin:0;text-transform:none;letter-spacing:0}
/* The catalog lists: each row is a direct link to the venue, artist,
   or event detail page. */
.catrow[href]{display:flex;align-items:baseline;justify-content:space-between;gap:8px;flex-wrap:wrap}
.catrow .catsum{flex:1;min-width:220px;font-size:15px}
.catrow .catbadges{display:flex;gap:8px;flex-wrap:wrap;justify-content:flex-end}
.catrow.retired{opacity:.55}
.catday{margin:24px 0 8px;font-size:14px;color:var(--label-secondary);font-weight:750;letter-spacing:.01em}
.catday:first-child{margin-top:8px}
.catrow label{display:grid;gap:4px;margin:10px 0 0;font-size:13px;color:var(--label-secondary)}
.catrow input,.catrow textarea,.catrow select{width:100%;box-sizing:border-box;
background:var(--fill);border:1px solid var(--separator);border-radius:var(--r-sm);
color:var(--label);padding:9px 11px;font:inherit}
.catrow input[type=checkbox]{width:auto;justify-self:start}
.catfilter{display:flex;gap:8px;flex-wrap:wrap;margin:0 0 16px}
.datepresets{display:flex;gap:8px;flex-wrap:wrap;margin:0 0 12px}
/* The Today picker puts a label and a hint on the same row as the control. */
.citypick{align-items:center;margin-top:4px}
.catfilter input[type=search],.catfilter select{background:var(--fill);
border:1px solid var(--separator);border-radius:var(--r-sm);color:var(--label);
padding:9px 11px;font:inherit}
.catfilter input[type=search]{flex:1;min-width:180px}
.catalognav{display:flex;gap:6px;overflow-x:auto;margin:-4px 0 28px;padding:4px 0 8px;
scrollbar-width:none}.catalognav::-webkit-scrollbar{display:none}
.catalognav a{flex:0 0 auto;padding:8px 12px;border-radius:var(--r-pill);color:var(--label-secondary);
font-size:13px;font-weight:700}.catalognav a:hover{text-decoration:none;background:var(--fill)}
.catalognav a.active{background:var(--accent);color:white}
.subnav{display:flex;gap:7px;overflow-x:auto;margin:0 0 16px;padding:0 0 4px;scrollbar-width:none}
.subnav::-webkit-scrollbar{display:none}.subnav a{flex:0 0 auto;border:1px solid var(--separator);
border-radius:var(--r-pill);padding:7px 11px;color:var(--label-secondary);font-size:12px;font-weight:700}
.subnav a:hover{text-decoration:none;background:var(--fill)}.subnav a.active{color:var(--label);background:var(--fill)}
.decision{border-color:rgba(255,214,90,.28)}.decision h3{font-size:15px;margin:0 0 4px}
.decision .acts form,.decision form .acts{margin-top:10px}.sourcefoot{display:flex;gap:8px;flex-wrap:wrap;
align-items:center;margin:10px 0 0}.sourcefoot a{font-size:12px}.metric{font-variant-numeric:tabular-nums}
.activity{display:grid;grid-template-columns:minmax(110px,150px) 1fr;gap:14px;align-items:start}
.activity .when{padding-top:2px}.activity p:last-child{margin-bottom:0}
@media(max-width:560px){.catalognav{margin-left:-4px;margin-right:-4px}.activity{grid-template-columns:1fr;gap:4px}}
@media (prefers-reduced-motion:reduce){*{transition:none !important}}
