:root {
  --accent: #ffc86e;
  --panel: rgba(10, 11, 28, 0.58);
  --line: rgba(255, 255, 255, 0.09);
  --text: #eceeff;
  --muted: #9ba0cc;
  --ph: #ff6154;                                 /* Product Hunt's brand colour, for the billboard's launch link */
  --live: 114, 230, 162;                         /* the live count's green (rgb parts): the pill and the picker's cards */
  --mono: ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, monospace;
  --jobs-h: 26px;                                /* the Help wanted strip across the top (#jobs) */
  --top: calc(env(safe-area-inset-top) + var(--jobs-h) + 12px);   /* top edge of the title, links and pills, under it */
  --bottom: max(14px, env(safe-area-inset-bottom));   /* bottom edge of the dock */
  --edge: 12px;                                  /* min side gutter of the bottom dock */
  --gutter: max(var(--edge), env(safe-area-inset-left), env(safe-area-inset-right));   /* mirrored: keeps the dock centred between notch insets */
  --btn: 36px;                                  /* icon button size (44px on touch) */
  color-scheme: dark;
}
* { box-sizing: border-box; }
html, body {
  margin: 0; height: 100%; overflow: hidden; background: #05060f; color: var(--text);
  font: 14px/1.4 ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  -webkit-font-smoothing: antialiased;
  overscroll-behavior: none;   /* no pull-to-refresh or rubber-banding when swiping the scene */
}
/* one-finger drags on the scene are the app's (look around, swipe to change city, site/js/app.js); a pinch still zooms */
#screen { position: fixed; inset: 0; display: block; image-rendering: pixelated; touch-action: pinch-zoom; }
button { font: inherit; color: inherit; }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* auto-hiding chrome */
.ui { transition: opacity .6s ease, transform .6s ease; }
body.idle, body.idle * { cursor: none; }
body.idle .ui, body.ui-off .ui { opacity: 0; pointer-events: none; }
body.idle .hud-bottom, body.ui-off .hud-bottom { transform: translate(-50%, 8px); }
/* ?obs (OBS / embed mode): the scene only, for good. No interface, pills or toasts. */
.obs .ui, .obs .pill { display: none !important; }

/* city title */
.hud-city {
  position: fixed; top: var(--top); left: max(18px, env(safe-area-inset-left));
  max-width: calc(100vw - 320px - var(--ph-room, 0px));   /* clear of the links, with one of them opened by a mouse (see #shopLink) */
  text-shadow: 0 1px 14px rgba(0, 0, 0, .7); pointer-events: none;
}
#cityName { margin: 0 0 2px; font-size: 30px; font-weight: 650; letter-spacing: -.01em; line-height: 1.1; }
.sub { margin: 0; color: var(--muted); font-size: 13px; }
.sub time { color: var(--accent); font-family: var(--mono); white-space: nowrap; }
/* live count (site/js/live/live.js): a glowing pill with a blinking pixel, "23 here now · 5 in Tokyo · 480 today · 12,345 all
   time". Frosted like the other panels so it reads over any scene. One row; on phones it is the city card's last row,
   without today and all time (see max-width: 600px). */
.live {
  position: relative; display: grid; grid-auto-flow: column; align-items: center; column-gap: 6px; width: fit-content;
  margin: 10px 0 0; padding: 5px 12px 5px 10px; border-radius: 14px;
  border: 1px solid rgba(var(--live), .32); background: var(--panel);
  -webkit-backdrop-filter: blur(12px) saturate(1.3); backdrop-filter: blur(12px) saturate(1.3);
  box-shadow: 0 0 14px rgba(var(--live), .2), inset 0 0 10px rgba(var(--live), .08);
  color: var(--text); font-size: 12px; line-height: 1.5; text-shadow: none;
}
.live[hidden] { display: none; }
.live::before {
  content: ""; flex: none; width: 6px; height: 6px; margin-right: 2px;
  background: rgb(var(--live)); box-shadow: 0 0 8px rgba(var(--live), .9); animation: live 2.4s ease-in-out infinite;
}
.live::after {   /* the glow breathes with the pixel (opacity only, so it stays off the main thread) */
  content: ""; position: absolute; inset: -1px; border-radius: inherit; pointer-events: none;
  box-shadow: 0 0 22px rgba(var(--live), .35); animation: live 2.4s ease-in-out infinite;
}
.live span { white-space: nowrap; }
.live span + span { color: var(--muted); }
.live span + span::before { content: "·"; margin-right: 6px; }   /* as far from the dot as the gap before it */
@keyframes live { 50% { opacity: .35; } }

/* author links */
#links {
  position: fixed; top: var(--top); right: max(18px, env(safe-area-inset-right));
  display: flex; gap: 2px; padding: 4px; border-radius: 14px; border: 1px solid var(--line); background: var(--panel);
  -webkit-backdrop-filter: blur(12px) saturate(1.3); backdrop-filter: blur(12px) saturate(1.3);
}
#links a { color: var(--muted); transition: color .2s, background .2s; }
#links a:hover, #links a:focus-visible { color: var(--text); }
/* the Product Hunt (its launch week only, site/js/ui/launch.js), shop and coffee links are icons like the rest; a mouse over one
   (or the keyboard on it) slides its words out to the right of the icon (the row is pinned to the right edge, so it
   grows to the left). Touch screens keep the icons. */
:is(#phLink, #shopLink, #coffee) { height: var(--btn); display: flex; align-items: center; padding: 0 calc((var(--btn) - 16px) / 2); border-radius: 10px; font-size: 13px; text-decoration: none; }
#links :is(#phLink, #shopLink, #coffee) { transition: color .2s, background .2s, padding .25s ease; }
:is(#phLink, #shopLink, #coffee):hover { background: color-mix(in srgb, var(--accent) 14%, transparent); }
:is(#phLink, #shopLink, #coffee) svg { flex: none; width: 16px; height: 16px; fill: var(--accent); shape-rendering: crispEdges; }
:is(#phLink, #shopLink, #coffee) span { max-width: 0; overflow: hidden; white-space: nowrap; opacity: 0; transition: max-width .25s ease, margin .25s ease, opacity .2s; }
/* not at phone widths (600 px and under), where the city title needs the room */
@media (hover: hover) and (min-width: 601px) {
  :is(#phLink, #shopLink, #coffee):hover { padding-right: 12px; }
  :is(#phLink, #shopLink, #coffee):hover span { max-width: 12em; margin-left: 8px; opacity: 1; }
}
@media (min-width: 601px) {
  :is(#phLink, #shopLink, #coffee):focus-visible { padding-right: 12px; }
  :is(#phLink, #shopLink, #coffee):focus-visible span { max-width: 12em; margin-left: 8px; opacity: 1; }
}
:root:has(#phLink:not([hidden])) { --ph-room: 64px; }   /* the city title keeps clear of its longer words too */

/* Help wanted (site/js/jobs/jobs-ticker.js): a thin strip across the very top, the jobs (a link to jobs/) and a "Post a job"
   button (jobs/post/); the title, links and pills sit under it (--top). Its jobs run right to left by one run's width (the run is there twice, so it loops without a seam:
   every item carries its own gap) and stand still while it's hovered, focused or faded out, or with reduced motion. */
#jobs {
  position: fixed; top: 0; left: 0; right: 0; height: calc(var(--jobs-h) + env(safe-area-inset-top));
  display: flex; align-items: center; gap: 12px;
  padding: env(safe-area-inset-top) max(14px, env(safe-area-inset-right)) 0 max(14px, env(safe-area-inset-left));
  border-bottom: 1px solid var(--line); background: var(--panel);
  -webkit-backdrop-filter: blur(12px) saturate(1.3); backdrop-filter: blur(12px) saturate(1.3);
  font-size: 12px; line-height: 1; white-space: nowrap;
}
#jobs:is(:hover, :focus-within) { background: color-mix(in srgb, var(--accent) 10%, var(--panel)); }
.jobs-main { flex: 1; min-width: 0; align-self: stretch; display: flex; align-items: center; gap: 12px; color: var(--text); text-decoration: none; }
.jobs-main:focus-visible, .jobs-post:focus-visible { outline-offset: -2px; }
.jobs-post {
  flex: none; padding: 3px 10px; border-radius: 999px; font-weight: 600; font-size: 11px; line-height: 1.3; text-decoration: none;
  color: var(--accent); background: color-mix(in srgb, var(--accent) 14%, transparent); border: 1px solid color-mix(in srgb, var(--accent) 45%, transparent);
}
.jobs-post:hover, .jobs-post:focus-visible { color: var(--text); background: color-mix(in srgb, var(--accent) 28%, transparent); }
.jobs-tag { flex: none; font: 600 10px/1 var(--mono); letter-spacing: .2em; text-transform: uppercase; color: var(--accent); }
.jobs-tag::before {   /* a lit pixel, like the live pill's */
  content: ""; display: inline-block; width: 6px; height: 6px; margin-right: 8px; vertical-align: 1px;
  background: var(--accent); box-shadow: 0 0 8px var(--accent);
}
/* the right edge fades what doesn't fit; the left one only while the jobs run in from it, so a line standing still
   (the call before the list comes, reduced motion) keeps its first letters */
.jobs-run {
  flex: 1; min-width: 0; overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg, #000 calc(100% - 24px), transparent);
  mask-image: linear-gradient(90deg, #000 calc(100% - 24px), transparent);
}
#jobs.running .jobs-run {
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 16px, #000 calc(100% - 24px), transparent);
  mask-image: linear-gradient(90deg, transparent, #000 16px, #000 calc(100% - 24px), transparent);
}
.jobs-track { display: inline-flex; }
.jobs-item { position: relative; padding-right: 34px; }
.jobs-item::after {   /* a pixel between the jobs */
  content: ""; position: absolute; right: 15px; top: 50%; width: 4px; height: 4px; margin-top: -2px; background: var(--accent); opacity: .7;
}
#jobs:not(.running) .jobs-item::after { content: none; }
.jobs-item.posted { color: var(--accent); }                  /* posted here, approved: first in the run */
.jobs-cta { color: var(--muted); }
#jobs:not(.running) .jobs-cta { color: var(--text); }
#jobs.running .jobs-track { animation: jobs-run var(--jobs-s, 60s) linear infinite; }
#jobs.running:is(:hover, :focus-within) .jobs-track, body:is(.idle, .ui-off) #jobs.running .jobs-track { animation-play-state: paused; }
@keyframes jobs-run { to { transform: translateX(-50%); } }
.jobs-all { flex: none; display: inline-flex; align-items: center; gap: 6px; color: var(--muted); }
.jobs-all svg { flex: none; transition: transform .18s ease-out; }
.jobs-main:is(:hover, :focus-visible) .jobs-all { color: var(--text); }
.jobs-main:is(:hover, :focus-visible) .jobs-all svg { transform: translateX(3px); }
#jobs:not(.running) .jobs-all { color: var(--accent); }
#jobs:not(.running) .jobs-main { padding-inline: 6px; }
#jobs:not(.running) .jobs-tag::before { background: none; box-shadow: none; border: 1px solid var(--accent); }
#jobs:not(.running) .jobs-main:is(:hover, :focus-visible) .jobs-tag::before { background: var(--accent); }
#jobs:not(.running) .jobs-item { padding-right: 0; }

/* bottom dock */
.hud-bottom {
  position: fixed; left: 50%; bottom: var(--bottom); transform: translateX(-50%);
  width: min(958px, calc(100vw - 2 * var(--gutter))); display: grid;   /* the track title keeps 150px beside every button */ grid-template-columns: minmax(0, 1fr); gap: 8px;
}
/* One row of chips (the city picker, the tour, the weather): centred while they fit; when they don't (the narrowest phones)
   it bleeds into the gutters and swipes. No edge-fade mask: it would switch off the chips' backdrop blur. */
#cities {
  display: flex; gap: 6px; overflow-x: auto; scrollbar-width: none;
  margin-inline: calc(-1 * var(--gutter)); padding: 2px calc(var(--gutter) + 2px);
  scroll-snap-type: x proximity; scroll-padding-inline: calc(var(--gutter) + 24px); scroll-behavior: smooth;
}
#cities::-webkit-scrollbar { display: none; }
.chip {
  flex: none; display: inline-flex; align-items: baseline; gap: 8px; padding: 7px 12px; cursor: pointer;
  border-radius: 999px; border: 1px solid var(--line); background: var(--panel);
  -webkit-backdrop-filter: blur(12px) saturate(1.3); backdrop-filter: blur(12px) saturate(1.3);
  transition: border-color .2s, background .2s, box-shadow .2s; scroll-snap-align: start;
}
.chip:first-child { margin-left: auto; }   /* auto margins centre without clipping the start (justify-content would) */
.chip:last-child { margin-right: auto; }
.chip small { font: 11px var(--mono); color: var(--muted); }
.chip:hover { border-color: rgba(255, 255, 255, .22); }
/* the city on screen opens the picker, lit in its colour; the tour and weather chips are lit (without the glow) while a
   tour runs or a weather is picked */
.menu-chip svg { align-self: center; width: 16px; height: 16px; fill: var(--muted); shape-rendering: crispEdges; }
.menu-chip.on { border-color: color-mix(in srgb, var(--accent) 45%, transparent); }
.menu-chip.on svg { fill: var(--accent); }
.menu-chip.on small { color: var(--accent); }
.menu-chip[aria-expanded="true"] { background: color-mix(in srgb, #fff 10%, var(--panel)); }
#cityBtn {
  border-color: color-mix(in srgb, var(--accent) 75%, transparent);
  background: color-mix(in srgb, var(--accent) 16%, var(--panel));
  box-shadow: 0 0 22px -8px var(--accent);
}
#cityBtn[aria-expanded="true"] { background: color-mix(in srgb, var(--accent) 28%, var(--panel)); }
#cityBtn { flex: 0 1 auto; min-width: 0; }      /* a long name gives way first (the title shows it whole) */
#cityBtnName { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* its hint (site/js/ui/city-roll.js): other cities' names roll up through it and back, over its own (kept, see-through) */
#cityBtnName.rolling { position: relative; color: transparent; }
.name-roll { position: absolute; top: 0; left: 0; width: 100%; display: flex; flex-direction: column; color: var(--text); }
.name-roll span { flex: none; overflow: hidden; text-overflow: ellipsis; }
#cityBtnTime { transition: opacity .2s; }
#cityBtnName.rolling + #cityBtnTime { opacity: 0; }   /* the time is the city on screen's, not the names rolling by */
#cityBtn svg, #cityBtn small { fill: var(--accent); color: var(--accent); }
/* a thin rule between the city and those two chips */
#tourBtn { position: relative; margin-left: 9px; }
#tourBtn::before {
  content: ""; position: absolute; left: -9px; top: 5px; bottom: 5px; width: 1px;
  background: rgba(255, 255, 255, .24); pointer-events: none;
}

#player {
  display: flex; align-items: center; gap: 10px; padding: 8px 10px 8px 8px;
  border-radius: 16px; border: 1px solid var(--line); background: var(--panel);
  -webkit-backdrop-filter: blur(14px) saturate(1.3); backdrop-filter: blur(14px) saturate(1.3);
}
.icon-btn {
  flex: none; width: var(--btn); height: var(--btn); display: grid; place-items: center; padding: 0;
  border: 0; border-radius: 10px; background: transparent; cursor: pointer;
}
.icon-btn:hover { background: rgba(255, 255, 255, .08); }
.icon-btn:disabled { opacity: .35; cursor: default; background: transparent; }
.icon-btn svg { width: 16px; height: 16px; fill: currentColor; shape-rendering: crispEdges; }
#play { background: var(--accent); color: #12121c; }
#play:hover { filter: brightness(1.08); }
#play.pulse { animation: pulse 2.2s ease-in-out infinite; }
@keyframes pulse {
  0%, 100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--accent) 55%, transparent); }
  50% { box-shadow: 0 0 0 9px transparent; }
}
.track { flex: 1; min-width: 0; }
#trackTitle, #trackMeta { display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
#trackTitle { font-weight: 560; }
#trackMeta { font: 11px var(--mono); color: var(--muted); }
.vols { flex: none; display: flex; align-items: center; gap: 10px; }
.vol { flex: none; display: flex; align-items: center; gap: 6px; color: var(--muted); }
.vol svg { flex: none; width: 14px; height: 14px; fill: currentColor; shape-rendering: crispEdges; }
.vol input { width: 84px; accent-color: var(--accent); }
#queueBtn[aria-expanded="true"], #timerBtn[aria-expanded="true"], #vibeBtn[aria-expanded="true"], #mixerBtn[aria-expanded="true"], #saveBtn[aria-expanded="true"], #togetherBtn[aria-expanded="true"], #chatBtn[aria-expanded="true"], #settingsBtn[aria-expanded="true"], #pip[aria-pressed="true"] { background: rgba(255, 255, 255, .1); color: var(--accent); }
#timerBtn.on { color: var(--accent); }   /* a timer is running */
#mixerBtn svg, #togetherBtn svg, #chatBtn svg { width: 18px; }   /* the faders, the two people and the bubble are 9 pixels wide */
/* the mini player's source video: kept in the page for Picture-in-Picture, but never seen */
.pip-source { position: fixed; left: 0; top: 0; width: 1px; height: 1px; opacity: 0; pointer-events: none; }

/* popovers: up next, timers, vibe, together, the city sounds mixer and save open over the chips, the cities, tour and weather
   above them */
.dock { position: relative; }
.pop {
  position: absolute; left: 0; bottom: calc(100% + 8px); width: min(360px, 100%);
  display: flex; flex-direction: column; border-radius: 16px; border: 1px solid var(--line);
  background: rgba(10, 11, 28, 0.74);
  -webkit-backdrop-filter: blur(14px) saturate(1.3); backdrop-filter: blur(14px) saturate(1.3);
  box-shadow: 0 18px 40px -20px rgba(0, 0, 0, .8); animation: pop-in .16s ease-out;
}
@keyframes pop-in { from { opacity: 0; transform: translateY(6px); } }
.pop-head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; padding: 12px 14px 6px; }
.pop-head span { font: 600 11px/1 var(--mono); letter-spacing: .28em; text-transform: uppercase; color: var(--muted); white-space: nowrap; }
.pop-head small { font: 11px var(--mono); color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* up next, the city tour and the weather: lists of row buttons */
#queue, #tour, #weather, #mixer { max-height: min(380px, 55vh); }
#tour, #weather { width: min(320px, 100%); }   /* above their own chips (site/js/app.js placeOver sets left) */
#mixer { left: auto; right: 0; width: min(320px, 100%); }   /* under its button, on the right of the dock */
/* every city: a search and a grid of previews (img/thumbs), centred over the dock; the grid scrolls on short screens */
#cityPicker {   /* --dock-top (site/js/app.js measureDock, again as it opens): it may cover the city title, never the top of the screen */
  left: 0; right: 0; margin-inline: auto; width: min(760px, 100%); max-height: min(640px, calc(var(--dock-top, 80vh) - var(--top) - 8px));
}
#cityFind {
  margin: 2px 10px 8px; padding: 8px 12px; border-radius: 10px; border: 1px solid var(--line);
  background: rgba(255, 255, 255, .06); font: 13px var(--mono); color: var(--text);
}
#cityFind::placeholder { color: var(--muted); }
#cityFind:focus-visible { outline: none; border-color: color-mix(in srgb, var(--accent) 60%, transparent); }
#cityList {
  list-style: none; margin: 0; padding: 0 6px 6px; overflow-y: auto; overscroll-behavior: contain;
  display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 4px;
}
.city-card {
  position: relative; width: 100%; display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: baseline; gap: 0 8px;
  padding: 4px 4px 6px; border: 1px solid transparent; border-radius: 12px; background: transparent; text-align: left; cursor: pointer;
}
.city-card img {
  grid-column: 1 / -1; display: block; width: 100%; height: auto; aspect-ratio: 16 / 9; margin-bottom: 5px;
  border-radius: 8px; background: rgba(255, 255, 255, .06);
}
.city-card span { padding-left: 3px; font-weight: 560; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.city-card small { padding-right: 3px; font: 11px var(--mono); color: var(--muted); }
.city-card:hover, .city-card:focus-visible { background: rgba(255, 255, 255, .08); }
.city-card[aria-current="true"] {
  border-color: color-mix(in srgb, var(--accent) 75%, transparent);
  background: color-mix(in srgb, var(--accent) 16%, transparent);
}
.city-card[aria-current="true"] small { color: var(--accent); }
/* who's in each city (site/js/live/live.js cityLabels): the live pill's pixel and "5 here", dark on the preview's corner */
.card-live {
  position: absolute; top: 9px; left: 9px; display: flex; align-items: center; gap: 5px;
  padding: 0 7px 0 6px; border-radius: 7px; border: 1px solid rgba(var(--live), .32);
  background: rgba(6, 7, 18, .78); box-shadow: 0 0 10px rgba(var(--live), .18);
  font: 500 10.5px/18px var(--mono); color: var(--text); white-space: nowrap; pointer-events: none;
}
.card-live[hidden] { display: none; }
.card-live::before { content: ""; width: 5px; height: 5px; background: rgb(var(--live)); box-shadow: 0 0 6px rgba(var(--live), .9); }
/* the city with the most people right now (site/js/live/live.js topCity), across the top of the grid: its preview fills the first
   column (a subgrid, so it lines up with the cards under it) and the rest reads "Most people right now", its name and
   its local time, lit green like the live pill (or in the accent, like any card, when it's the city on screen) */
.featured-item { grid-column: 1 / -1; display: grid; grid-template-columns: subgrid; }
.featured-item[hidden] { display: none; }
.city-featured {
  grid-column: 1 / -1; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); grid-template-columns: subgrid;
  align-items: center; margin-bottom: 2px; border-color: rgba(var(--live), .26);
  background: linear-gradient(90deg, rgba(var(--live), .1), rgba(var(--live), .02) 70%);
}
.city-featured img { grid-column: 1; margin: 0; }
.city-featured .feat-text {   /* not the cards' one-line name: "Most people right now" takes two lines on phones */
  grid-column: 2 / -1; display: flex; flex-direction: column; gap: 5px; min-width: 0; padding: 0 8px 0 6px; font-weight: 400; white-space: normal;
}
.feat-text em {
  display: flex; align-items: flex-start; gap: 7px; font: 600 10.5px/1.3 var(--mono); letter-spacing: .16em; text-transform: uppercase;
  color: rgb(var(--live)); text-wrap: balance;
}
.feat-text em::before {
  content: ""; flex: none; width: 5px; height: 5px; margin-top: calc((1.3em - 5px) / 2);   /* the middle of the first line */
  background: rgb(var(--live)); box-shadow: 0 0 6px rgba(var(--live), .9);
  animation: live 2.4s ease-in-out infinite;
}
.feat-text strong { font-size: 22px; font-weight: 600; line-height: 1.15; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.feat-text small { font: 11px var(--mono); color: var(--muted); }
.city-featured:not([aria-current]):hover, .city-featured:not([aria-current]):focus-visible { background: linear-gradient(90deg, rgba(var(--live), .16), rgba(255, 255, 255, .06) 70%); }
@media (prefers-reduced-motion: reduce) { .feat-text em::before { animation: none; } }
/* the last card: "Request a city" (a link to Discord), a lit pixel billboard (site/js/ui/request-board.js) glowing in the city's accent */
a.city-card { color: inherit; text-decoration: none; }
.city-request { grid-template-columns: minmax(0, 1fr); }   /* "on Discord" goes under the title: beside it, a 150 px card cuts the title */
.city-request small { padding-left: 3px; }
.req-art {
  grid-column: 1 / -1; aspect-ratio: 16 / 9; margin-bottom: 5px; border-radius: 8px; overflow: hidden;
  background: radial-gradient(90% 80% at 50% 35%, color-mix(in srgb, var(--accent) 18%, #0c0e1d), #06070e 75%);
}
.req-art canvas {
  display: block; width: 100%; height: 100%; image-rendering: pixelated;
  --glow: color-mix(in srgb, var(--accent) 55%, #ffd98a);
  filter: drop-shadow(0 0 3px color-mix(in srgb, var(--glow) 70%, transparent));
  animation: req-glow 3.2s ease-in-out infinite;
}
@keyframes req-glow { 50% { filter: drop-shadow(0 0 6px var(--glow)); } }
.city-request:hover .req-art canvas, .city-request:focus-visible .req-art canvas { animation: none; filter: drop-shadow(0 0 7px var(--glow)); }
@media (prefers-reduced-motion: reduce) { .req-art canvas { animation: none; } }
.pop-list { list-style: none; margin: 0; padding: 0 6px 6px; overflow-y: auto; overscroll-behavior: contain; }
.pop-item {
  width: 100%; display: flex; align-items: center; gap: 10px; padding: 8px; text-align: left;
  border: 0; border-radius: 10px; background: transparent; cursor: pointer;
}
.pop-item:hover, .pop-item:focus-visible { background: rgba(255, 255, 255, .08); }
.pop-text { flex: 1; min-width: 0; }
.pop-title, .pop-meta { display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pop-title { font-weight: 560; }
.pop-meta { font: 11px var(--mono); color: var(--muted); }
.q-n { flex: none; width: 18px; display: grid; place-items: center; font: 11px var(--mono); color: var(--muted); }
.q-n svg { display: none; width: 10px; height: 10px; fill: var(--accent); shape-rendering: crispEdges; }
.pop-item:hover .q-n b, .pop-item:focus-visible .q-n b { display: none; }
.pop-item:hover .q-n svg, .pop-item:focus-visible .q-n svg { display: block; }
li:first-child .q-n { color: var(--accent); }
.q-dur { flex: none; font: 11px var(--mono); color: var(--muted); }
.q-empty, .mix-empty { padding: 10px 8px 12px; font: 12px var(--mono); color: var(--muted); }
.pick-dot { flex: none; width: 18px; display: grid; place-items: center; }
[aria-checked="true"] > .pick-dot::before { content: ""; width: 6px; height: 6px; background: var(--accent); }

/* timers: focus presets and sleep minutes, with skip / stop / off pushed to the right */
.t-row { display: flex; flex-wrap: wrap; gap: 6px; padding: 2px 14px 12px; }
.t-row + .pop-head { border-top: 1px solid var(--line); }
.t-opt {
  min-width: 44px; min-height: 32px; padding: 0 10px; border-radius: 10px; cursor: pointer;
  border: 1px solid var(--line); background: transparent; font: 12px var(--mono); color: var(--text);
  transition: border-color .2s, background .2s, color .2s;
}
.t-opt:hover { border-color: rgba(255, 255, 255, .22); }
.t-opt[aria-pressed="true"] {
  border-color: color-mix(in srgb, var(--accent) 75%, transparent); color: var(--accent);
  background: color-mix(in srgb, var(--accent) 16%, transparent);
}
.t-act { border-color: transparent; color: var(--muted); }
.t-act:hover { border-color: transparent; background: rgba(255, 255, 255, .08); color: var(--text); }
.t-opt:not(.t-act) + .t-act { margin-left: auto; }

/* running timers: stay on screen when the UI idles (sliding up into the corner #links leaves), hidden by H */
#timerPill { display: flex; gap: 14px; cursor: pointer; transition: opacity .6s ease, border-color .2s; }
#timerPill span { display: flex; align-items: center; gap: 8px; white-space: nowrap; }
#timerPill span::before { content: ""; flex: none; width: 6px; height: 6px; background: var(--accent); }
#timerPill span:empty { display: none; }
#timerPill:hover { border-color: rgba(255, 255, 255, .22); }
body.idle #corner { top: var(--top); }
body.idle #timerPill { opacity: .6; }
body.ui-off #timerPill { opacity: 0; pointer-events: none; }

.mix-empty { margin: 0; padding-inline: 0; }

/* mixer rows: name · slider (0-200 %, 100 % = as the city was designed) · value */
#mixReset {
  margin: -4px -6px; padding: 4px 6px; border: 0; border-radius: 6px; background: transparent; cursor: pointer;
  font: 11px var(--mono); color: var(--muted);
}
#mixReset:hover:not(:disabled) { color: var(--text); background: rgba(255, 255, 255, .08); }
#mixReset:disabled { opacity: .4; cursor: default; }
#mixList { padding: 2px 14px 10px; overflow-y: auto; overscroll-behavior: contain; }
.mix-row { display: grid; grid-template-columns: 78px minmax(0, 1fr) 36px; align-items: center; gap: 10px; min-height: 32px; }
.mix-sep { margin-top: 4px; padding-top: 4px; border-top: 1px solid var(--line); }   /* events after the beds */
.mix-name { font-size: 13px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.mix-row input { width: 100%; min-width: 0; margin: 0; accent-color: var(--accent); }
.mix-val { font: 11px var(--mono); color: var(--muted); text-align: right; }
.mix-row.changed .mix-val { color: var(--accent); }

/* vibe: three segmented radio groups (native radios underneath, so arrow keys move within a group) */
/* never taller than the room above the dock (100% is the dock, 8px the gap under the panel): on short screens it scrolls */
#vibe { padding-bottom: 12px; max-height: calc(100dvh - var(--top) - 100% - 8px - var(--bottom)); overflow-y: auto; overscroll-behavior: contain; }
#vibe fieldset, #settings fieldset { min-width: 0; margin: 0; padding: 6px 14px 4px; border: 0; }
#vibe legend, #settings legend { padding: 0; margin-bottom: 6px; font: 11px var(--mono); color: var(--muted); }
.seg { display: flex; gap: 2px; padding: 3px; border-radius: 12px; border: 1px solid var(--line); background: rgba(255, 255, 255, .05); }
.seg-grid { display: grid; grid-template-columns: repeat(3, 1fr); }   /* the nine styles, three to a row */
.seg label { position: relative; flex: 1; min-width: 0; }
.seg input { position: absolute; inset: 0; margin: 0; opacity: 0; cursor: pointer; }
.seg span {
  display: block; padding: 7px 4px; border-radius: 9px; text-align: center; font-size: 13px; white-space: nowrap;
  color: var(--muted); transition: background .15s, color .15s, box-shadow .15s;
}
.seg label:hover span { color: var(--text); }
.seg input:checked + span {
  color: var(--text); background: color-mix(in srgb, var(--accent) 20%, transparent);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent) 60%, transparent);
}
.seg input:focus-visible + span { outline: 2px solid var(--accent); outline-offset: 1px; }
.vibe-note { margin: 8px 14px 0; font: 11px/1.5 var(--mono); color: var(--muted); }
#vibeSkip { padding: 0; border: 0; background: none; font: inherit; color: var(--accent); cursor: pointer; text-decoration: underline; text-underline-offset: 3px; }

/* save this scene: the S and R keys as buttons, so touch screens can reach them */
#saveMenu { left: auto; right: 0; width: min(300px, 100%); }
#saveMenu svg, #together .pop-item > svg { flex: none; width: 16px; height: 16px; fill: var(--accent); shape-rendering: crispEdges; }
#saveMenu a { color: var(--text); text-decoration: none; }

/* settings (the gear): a switch for reactions (and billboards all, city art only or off, as the vibe's segmented rows) */
#settings { left: auto; right: 0; width: min(300px, 100%); padding-bottom: 12px; }
#settings legend kbd { margin-left: 6px; }
#settings .vibe-note { margin-inline: 0; }      /* each note sits in its setting's fieldset, already inset */
#reactionsSetting:not([hidden]) ~ fieldset { padding-top: 14px; }   /* room between two settings shown together */
.set-switch { display: flex; align-items: center; gap: 14px; padding: 4px 14px; cursor: pointer; }
.set-text { flex: 1; min-width: 0; }
.set-note { display: block; margin-top: 3px; font: 11px/1.5 var(--mono); color: var(--muted); }
/* the native checkbox drawn as a track and knob: off grey, on in the accent with the knob to the right */
.set-switch input {
  appearance: none; -webkit-appearance: none; position: relative; flex: none; width: 40px; height: 24px; margin: 0;
  border: 1px solid var(--line); border-radius: 12px; background: rgba(255, 255, 255, .08); cursor: pointer;
  transition: background .15s, border-color .15s;
}
.set-switch input::before {
  content: ""; position: absolute; top: 2px; left: 2px; width: 18px; height: 18px; border-radius: 50%;
  background: var(--muted); transition: transform .15s, background .15s;
}
.set-switch input:checked {
  background: color-mix(in srgb, var(--accent) 35%, transparent); border-color: color-mix(in srgb, var(--accent) 70%, transparent);
}
.set-switch input:checked::before { transform: translateX(16px); background: var(--text); }
.set-switch:hover input:not(:checked)::before { background: var(--text); }
.set-switch input:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* together (README "Together"): who's here, four reactions and a lantern */
#together .pop-head small { color: var(--text); }
.tg-reacts { display: flex; gap: 6px; padding: 4px 14px 8px; }
.tg-react {   /* each in its own colour, the same as its sprite in site/js/live/reactions.js */
  flex: 1; min-height: 40px; display: grid; place-items: center; padding: 0; cursor: pointer;
  border: 1px solid var(--line); border-radius: 10px; background: rgba(255, 255, 255, .03);
  transition: border-color .2s, background .2s;
}
.tg-react[data-kind="heart"] { --c: #ff6b8b; }
.tg-react[data-kind="note"] { --c: #8fd3ff; }
.tg-react[data-kind="star"] { --c: #ffd95e; }
.tg-react[data-kind="moon"] { --c: #fff0b3; }
.tg-react:hover { border-color: color-mix(in srgb, var(--c) 55%, transparent); background: color-mix(in srgb, var(--c) 10%, transparent); }
/* the picked one (what a tap on the scene drops): lit in its colour, like a picked timer or vibe */
.tg-react[aria-pressed="true"] {
  border-color: color-mix(in srgb, var(--c) 75%, transparent); background: color-mix(in srgb, var(--c) 16%, transparent);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--c) 40%, transparent);
}
.tg-react:active { background: color-mix(in srgb, var(--c) 22%, transparent); }
.tg-react svg { width: 21px; height: 21px; fill: var(--c); shape-rendering: crispEdges; }   /* 7 px art at 3x */
.tg-hint { margin: -2px 14px 8px; font: 11px/16px var(--mono); color: var(--muted); }
.tg-hint svg { width: 14px; height: 14px; vertical-align: -3px; fill: var(--c); shape-rendering: crispEdges; }   /* 7 px art at 2x */

/* chat (README "Chat"): the city's last hour, oldest first, a line to write in, and why a message wasn't sent */
#chatBtn { position: relative; }
#chatBtn.unread::after {   /* said while the panel was closed */
  content: ""; position: absolute; top: calc(50% - 11px); right: calc(50% - 13px); width: 6px; height: 6px;
  background: var(--accent); box-shadow: 0 0 6px var(--accent);
}
#chat { width: min(380px, 100%); }
#chat .pop-head small { color: var(--text); }
/* "3 in chat" (site/js/live/chat.js inChat), lit like the live pill when anyone else has it open, then your name, which goes to a
   line of its own when both don't fit (a phone, a long name) */
#chatWho { display: flex; flex-wrap: wrap; justify-content: flex-end; align-items: baseline; gap: 2px 10px; min-width: 0; }
#chatWho span {   /* the header's text, not its title's look (.pop-head span) */
  min-width: 0; overflow: hidden; text-overflow: ellipsis; font: inherit; letter-spacing: normal; text-transform: none; color: var(--text);
}
#chatWho .chat-online { display: inline-flex; align-items: baseline; gap: 6px; color: var(--muted); }
#chatWho .chat-online::before { content: ""; flex: none; align-self: center; width: 5px; height: 5px; background: currentColor; opacity: .5; }
#chatWho .chat-online.on { color: rgb(var(--live)); text-shadow: 0 0 8px rgba(var(--live), .55); }
#chatWho .chat-online.on::before { opacity: 1; box-shadow: 0 0 6px rgba(var(--live), .9); animation: live 2.4s ease-in-out infinite; }
.chat-log {
  list-style: none; margin: 0; padding: 2px 14px 4px; display: flex; flex-direction: column; gap: 6px;
  max-height: min(300px, 38dvh); overflow-y: auto; overscroll-behavior: contain;
}
.chat-log:empty { display: none; }
.chat-msg { font-size: 13px; line-height: 18px; overflow-wrap: anywhere; }
.chat-name { margin-right: 6px; font: 600 11px/18px var(--mono); color: hsl(var(--h, 230) 70% 76%); }
.chat-msg.mine .chat-name { color: var(--accent); }
.chat-city { margin-right: 6px; font: 10.5px/18px var(--mono); color: var(--muted); }   /* the city its author was watching */
button.chat-city {   /* another city: a dotted underline says it goes somewhere, which touch screens can't hover to find */
  padding: 0; border: 0; background: none; cursor: pointer;
  text-decoration: underline dotted; text-underline-offset: 3px; text-decoration-color: color-mix(in srgb, var(--muted) 60%, transparent);
}
button.chat-city:hover, button.chat-city:focus-visible { color: var(--text); text-decoration-style: solid; }
.chat-msg time { margin-left: 6px; font: 10.5px var(--mono); color: var(--muted); white-space: nowrap; }
.chat-hide {   /* shown on hover and focus with a mouse; always, a little dim, on touch screens */
  margin-left: 4px; padding: 0 5px; border: 0; border-radius: 5px; background: transparent; cursor: pointer;
  font: 10.5px/18px var(--mono); color: var(--muted); opacity: 0;
}
.chat-msg:hover .chat-hide, .chat-hide:focus-visible { opacity: 1; }
.chat-hide:hover { color: var(--text); background: rgba(255, 255, 255, .08); }
@media (hover: none) { .chat-hide { opacity: .75; } }
.chat-empty { margin: 0; padding: 4px 14px 8px; font: 12px/1.5 var(--mono); color: var(--muted); }
.chat-form { position: relative; display: flex; gap: 6px; padding: 6px 8px 0 14px; }
#chatText {
  flex: 1; min-width: 0; padding: 8px 12px; border-radius: 10px; border: 1px solid var(--line);
  background: rgba(255, 255, 255, .06); font: inherit; font-size: 14px; color: var(--text);
}
#chatText::placeholder { color: var(--muted); }
#chatText:focus-visible { outline: none; border-color: color-mix(in srgb, var(--accent) 60%, transparent); }
#chatText:disabled { opacity: .6; }
#chatSend { color: var(--accent); }
#chatSend:disabled { color: var(--muted); }
.chat-foot { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; margin: 0; padding: 6px 14px 10px; font: 11px/1.45 var(--mono); color: var(--muted); }
#chatNote.warn { color: #ffb3a1; }
#chatUnhide { flex: none; padding: 0; border: 0; background: none; font: inherit; color: var(--muted); cursor: pointer; text-decoration: underline; text-underline-offset: 3px; }
#chatUnhide:hover { color: var(--text); }
/* emoji (site/js/live/emoji.js): the smiley's popup between the log and the text box, which gives it some of its room, and the
   shortcode list over them, above the text box; drawn by the system's own emoji font */
#chat { --emoji-font: "Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji", sans-serif; }
#chatEmojiBtn { color: var(--muted); }
#chatEmojiBtn:hover:not(:disabled) { color: var(--text); }
#chatEmojiBtn[aria-expanded="true"] { background: rgba(255, 255, 255, .1); color: var(--accent); }
#chat.picking .chat-log { max-height: min(140px, 18dvh); }
.chat-emoji { margin-top: 4px; padding: 0 8px 0 10px; border-top: 1px solid var(--line); }
.emoji-scroll { max-height: min(204px, 28dvh); overflow-y: auto; overscroll-behavior: contain; }
.emoji-sec[hidden] { display: none; }
.emoji-label { margin: 9px 4px 3px; font: 600 10px/1 var(--mono); letter-spacing: .24em; text-transform: uppercase; color: var(--muted); }
.emoji-row { display: grid; grid-template-columns: repeat(auto-fill, minmax(36px, 1fr)); }
.emoji {
  height: 36px; padding: 0; border: 0; border-radius: 9px; background: transparent; cursor: pointer;
  font: 21px/1 var(--emoji-font); color: var(--text);
}
.emoji:hover, .emoji:focus-visible { outline: none; background: rgba(255, 255, 255, .1); }
.emoji:focus-visible { box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent) 60%, transparent); }
.emoji-hint { margin: 0; padding: 6px 4px 2px; border-top: 1px solid var(--line); font: 11px/18px var(--mono); color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.chat-suggest {
  position: absolute; left: 14px; bottom: calc(100% + 6px); z-index: 1; width: min(260px, calc(100% - 22px));
  list-style: none; margin: 0; padding: 4px; border-radius: 12px; border: 1px solid var(--line);
  background: rgba(14, 15, 34, .97); box-shadow: 0 12px 30px -12px rgba(0, 0, 0, .8);
}
.chat-suggest li {
  display: flex; align-items: center; gap: 10px; padding: 3px 8px; border-radius: 8px; cursor: pointer;
  font: 12px/26px var(--mono); color: var(--muted); white-space: nowrap;
}
.chat-suggest li span + span { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.chat-suggest li:hover { color: var(--text); }
.chat-suggest li[aria-selected="true"] { background: rgba(255, 255, 255, .1); color: var(--text); }
.emoji-e { flex: none; width: 22px; text-align: center; font: 18px/1 var(--emoji-font); }
.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }


/* status pills */
.pill {
  position: fixed; top: var(--top); padding: 8px 12px; border-radius: 10px;
  border: 1px solid var(--line); background: var(--panel); font: 12px var(--mono); color: var(--text);
  -webkit-backdrop-filter: blur(12px); backdrop-filter: blur(12px);
}
/* top right, below #links: the running timers, then "tuning in…" */
#corner {
  position: fixed; top: calc(var(--top) + var(--btn) + 18px); right: max(18px, env(safe-area-inset-right));
  display: flex; flex-direction: column; align-items: flex-end; gap: 8px; transition: top .6s ease;
}
#corner .pill { position: static; }
#loading { color: var(--muted); }
#toast { left: 50%; transform: translateX(-50%); min-width: min(360px, calc(100vw - 32px)); max-width: calc(100vw - 32px); }
#toast .progress { display: flex; align-items: center; gap: 10px; margin-top: 6px; }
#toast .bar { flex: 1; height: 3px; border-radius: 2px; overflow: hidden; background: rgba(255, 255, 255, .12); }
#toast .bar i { display: block; height: 100%; width: 0; background: var(--accent); }
#toastCancel {
  flex: none; padding: 3px 10px; font: 11px var(--mono); cursor: pointer;
  border: 1px solid var(--line); border-radius: 8px; background: rgba(255, 255, 255, .06);
}
#toastCancel:hover { background: rgba(255, 255, 255, .12); }
[hidden] { display: none !important; }

/* the city's billboard: an invisible button over its face (placed by site/js/app.js), lit up with a label on hover; while
   the face says "post a job for free", a link to jobs/post/ in its place, and during the Product Hunt launch week,
   while the face shows the launch, a link to it, lit in Product Hunt's orange */
:is(#pitchSpot, #phSpot, #jobSpot) { --spot: var(--accent); position: fixed; padding: 0; border: 0; border-radius: 3px; background: transparent; cursor: pointer; transition: box-shadow .2s; touch-action: pinch-zoom; }
:is(#phSpot, #jobSpot) { -webkit-user-drag: none; -webkit-touch-callout: none; }   /* links, yet a drag pans the view */
#phSpot { --spot: var(--ph); }
:is(#pitchSpot, #phSpot, #jobSpot) span {
  position: absolute; left: 50%; top: calc(100% + 8px); transform: translateX(-50%); padding: 5px 10px; border-radius: 10px;
  border: 1px solid var(--line); background: rgba(10, 11, 28, .78); font: 11px var(--mono); color: var(--text); white-space: nowrap;
  opacity: 0; pointer-events: none; transition: opacity .2s;
}
@media (hover: hover) {
  :is(#pitchSpot, #phSpot, #jobSpot):hover { box-shadow: 0 0 0 2px color-mix(in srgb, var(--spot) 70%, transparent), 0 0 28px -6px var(--spot); }
  :is(#pitchSpot, #phSpot, #jobSpot):hover span { opacity: 1; }
}
:is(#pitchSpot, #phSpot, #jobSpot):focus-visible span { opacity: 1; }
body.idle :is(#pitchSpot, #phSpot, #jobSpot), body.ui-off :is(#pitchSpot, #phSpot, #jobSpot) { box-shadow: none; }
body.idle :is(#pitchSpot, #phSpot, #jobSpot) span, body.ui-off :is(#pitchSpot, #phSpot, #jobSpot) span { opacity: 0; }

/* about panel (the text inside is written by tools/seo/seo.mjs). site/js/app.js makes it tabbed (.tabbed): a fixed-height panel,
   the tabs and close button on top, one section below that scrolls on its own. Without JS the sections simply stack. */
#about {
  width: min(640px, calc(100vw - 24px)); max-height: min(860px, calc(100dvh - 32px)); padding: 0; overflow: auto;
  overscroll-behavior: contain; border: 1px solid var(--line); border-radius: 16px; color: var(--text);
  background: rgba(10, 11, 28, .86); -webkit-backdrop-filter: blur(18px) saturate(1.3); backdrop-filter: blur(18px) saturate(1.3);
  box-shadow: 0 24px 80px -20px rgba(0, 0, 0, .8); scrollbar-width: thin; scrollbar-color: rgba(255, 255, 255, .18) transparent;
}
#about.tabbed { height: min(820px, calc(100dvh - 32px)); overflow: hidden; }   /* same size on every tab, so nothing jumps */
#about::backdrop { background: rgba(3, 4, 12, .5); }
.about-inner { padding: 22px 24px 26px; }
.tabbed .about-inner { height: 100%; padding: 0; display: grid; grid-template: auto minmax(0, 1fr) / minmax(0, 1fr) auto; }
.about-close { color: var(--muted); }
.about-close:hover { color: var(--text); }
.tabbed .about-close { grid-area: 1 / 2; align-self: center; margin: 4px 10px 0 4px; }
.about-tabs { grid-area: 1 / 1; display: flex; padding: 8px 0 0 12px; overflow-x: auto; scrollbar-width: none; }
.about-tabs::-webkit-scrollbar { display: none; }
#about:not(.tabbed) .about-tabs { display: none; }
.about-tabs [role="tab"] {
  flex: none; position: relative; padding: 13px 10px 14px; border: 0; background: none; cursor: pointer;
  font: 600 11px/1 var(--mono); letter-spacing: .2em; text-transform: uppercase; color: var(--muted); transition: color .2s;
}
.about-tabs [role="tab"]:hover, .about-tabs [aria-selected="true"] { color: var(--text); }
.about-tabs [aria-selected="true"]::after { content: ""; position: absolute; left: 10px; right: calc(10px + .2em); bottom: 0; height: 2px; background: var(--accent); }
.about-tabs [role="tab"]:focus-visible { outline-offset: -4px; border-radius: 8px; }   /* the row clips anything outside it */
.tabbed .about-body {
  grid-area: 2 / 1 / 3 / 3; overflow-y: auto; overscroll-behavior: contain; padding: 20px 24px 20px; border-top: 1px solid var(--line);
  scrollbar-width: thin; scrollbar-color: rgba(255, 255, 255, .18) transparent;
}
.tabbed .about-panel > h3 { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }   /* the tab says it */
#about h2 { margin: 0 0 8px; font-size: 20px; font-weight: 650; letter-spacing: -.01em; line-height: 1.2; }
#about h3 { margin: 26px 0 10px; font: 600 11px/1 var(--mono); letter-spacing: .28em; text-transform: uppercase; color: var(--muted); }
#about p, #about li, #about dd { color: #cdd0ee; line-height: 1.55; }
#about p { margin: 0 0 10px; }
#about a { color: var(--accent); text-underline-offset: 3px; }
#about b { color: var(--text); font-weight: 600; }
#aboutCity { padding-bottom: 18px; margin-bottom: 22px; border-bottom: 1px solid var(--line); }
/* cities: a card per city in its own accent (--c from the scene); the whole card switches city, the one on screen is lit */
.city-list { margin: 0; padding: 0; list-style: none; display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 240px), 1fr)); gap: 8px; }
.city-list li {
  --c-: var(--c, var(--accent)); position: relative; padding: 11px 13px 12px; border-radius: 12px;
  border: 1px solid var(--line); background: rgba(255, 255, 255, .03); transition: border-color .2s, background .2s, box-shadow .2s;
}
.city-list li:hover { border-color: color-mix(in srgb, var(--c-) 45%, transparent); background: color-mix(in srgb, var(--c-) 7%, transparent); }
.city-list li:has([aria-current]) {
  border-color: color-mix(in srgb, var(--c-) 75%, transparent); background: color-mix(in srgb, var(--c-) 13%, transparent);
  box-shadow: 0 0 22px -10px var(--c-);
}
.city-list li:has(a:focus-visible) { outline: 2px solid var(--c-); outline-offset: 2px; }
#about .city-list a { font-weight: 600; text-decoration: none; color: var(--c-); }
.city-list a::after { content: ""; position: absolute; inset: 0; border-radius: inherit; }
.city-list a:focus-visible { outline: none; }
.city-list span { display: block; margin-top: 1px; font: 11px var(--mono); color: var(--muted); }
#about .city-list p { margin: 6px 0 0; font-size: 13px; line-height: 1.5; }
.keys { margin: 0; display: grid; gap: 6px; }
.keys div { display: grid; grid-template-columns: 120px 1fr; gap: 12px; align-items: baseline; }
.keys dt { white-space: nowrap; }
.keys dd { margin: 0; }
kbd {
  display: inline-block; min-width: 22px; padding: 2px 6px; text-align: center; font: 11px/1.4 var(--mono); color: var(--text);
  border: 1px solid rgba(255, 255, 255, .16); border-bottom-width: 2px; border-radius: 6px; background: rgba(255, 255, 255, .06);
}
/* FAQ: questions fold open, one at a time (<details name>) */
.faq details { border-bottom: 1px solid var(--line); }
.faq summary {
  display: flex; align-items: baseline; justify-content: space-between; gap: 16px; padding: 11px 2px;
  font-weight: 600; cursor: pointer; list-style: none;
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after { content: "+"; flex: none; font: 15px/1 var(--mono); color: var(--muted); transition: color .2s; }
.faq summary:hover::after { color: var(--text); }
.faq details[open] summary::after { content: "−"; color: var(--accent); }
.faq summary:focus-visible { outline-offset: -2px; border-radius: 6px; }
#about .faq p { margin: -2px 24px 14px 2px; }
.about-foot { margin-top: 16px !important; }
/* What's new: the latest changes at the end of the About tab (tools/seo/seo.mjs), a day and a line each; whats-new/ has them all */
.news { margin: 0; padding: 0; list-style: none; }
.news li { display: grid; grid-template-columns: 52px 1fr; gap: 10px; align-items: baseline; padding: 8px 0; border-bottom: 1px solid var(--line); }
#about .news li { font-size: 14px; line-height: 1.5; }
.news time { font: 11px var(--mono); color: var(--muted); white-space: nowrap; }

/* billboard card: what the billboard opens (the text is written by tools/seo/seo.mjs), in the city's accent */
#pitchCard {
  width: min(420px, calc(100vw - 24px)); padding: 0; border: 1px solid var(--line); border-radius: 16px; color: var(--text);
  background: rgba(10, 11, 28, .86); -webkit-backdrop-filter: blur(18px) saturate(1.3); backdrop-filter: blur(18px) saturate(1.3);
  box-shadow: 0 24px 80px -20px rgba(0, 0, 0, .8);
}
#pitchCard::backdrop { background: rgba(3, 4, 12, .5); }
.pitch-inner { position: relative; padding: 22px 24px 20px; }
#pitchCard .about-close { position: absolute; top: 10px; right: 10px; }
.pitch-kicker { margin: 0 40px 12px 0; font: 600 11px/1.4 var(--mono); letter-spacing: .2em; text-transform: uppercase; color: var(--accent); }
#pitchCard h2 { margin: 0 0 8px; font-size: 20px; font-weight: 650; letter-spacing: -.01em; line-height: 1.2; }
#pitchCard p:not([class]) { margin: 0 0 18px; color: #cdd0ee; line-height: 1.55; }
.pitch-cta {
  display: inline-flex; align-items: center; gap: 6px; min-height: 40px; padding: 0 16px; border-radius: 10px;
  font-weight: 600; text-decoration: none; color: #12121c; background: var(--accent); transition: filter .2s;
}
.pitch-cta:hover { filter: brightness(1.1); }
.pitch-note { margin: 12px 0 0; font: 11px/1.5 var(--mono); color: var(--muted); }

/* touch: finger-sized targets */
@media (pointer: coarse) {
  :root { --btn: 44px; }
  .chip { padding: 9px 14px; }
  .vol input, .mix-row input { height: 32px; }
  .mix-row { min-height: 40px; }
  .about-tabs [role="tab"] { padding-block: 17px 18px; }
  .t-opt { min-height: 40px; padding-inline: 12px; }
  .seg span { padding-block: 11px; }
  .set-switch { min-height: 48px; }
  #toastCancel { min-height: 36px; padding-inline: 14px; }
  #saveMenu kbd, #together kbd, #settings kbd { display: none; }
  .tg-react { min-height: 48px; }
  #cityFind { font-size: 16px; }                  /* iOS Safari zooms the page into a field with smaller text */
  #chatText { font-size: 16px; }   /* iOS zooms into a text box whose text is smaller */
}
/* mouse and trackpad on wider windows: a mouse needs less room than a thumb, so denser FAQ and shortcut rows keep every
   question and key in view in a 720px panel */
@media (pointer: fine) and (min-width: 601px) {
  #about.tabbed { height: min(720px, calc(100dvh - 32px)); }
  .faq summary { padding-block: 7px; }
  .keys { gap: 4px; }
}
/* tablets and narrow windows (one row would squeeze the track title away): the volume sliders get their own row under
   the track, with the vibe, timer, together, chat and save buttons */
@media (max-width: 940px) {
  #player { flex-wrap: wrap; gap: 2px 6px; }
  .vols { order: 1; flex: 1 0 calc(100% - 5 * (var(--btn) + 6px)); min-width: 0; gap: 18px; padding: 0 6px; }   /* min-width: range inputs have a wide intrinsic minimum */
  #vibeBtn, #timerBtn, #togetherBtn, #chatBtn, #saveBtn { order: 2; }   /* share the volume row, so the track title keeps its room */
  .vol { flex: 1; min-width: 0; }
  .vol input { flex: 1; width: auto; min-width: 0; }
}
/* phones in portrait */
@media (max-width: 600px) {
  :root { --edge: 8px; --jobs-h: 22px; --top: calc(env(safe-area-inset-top) + var(--jobs-h) + 8px); }   /* the strip nudges the city card down less */
  /* the city card: name, tagline, time and the live count in one frosted card as wide as the dock. #links sit in its
     top right corner without their own panel (the ::before keeps their room beside the name and tagline), the running
     timers under it (--title-h, site/js/app.js). */
  .hud-city {
    --links-w: calc(4 * var(--btn)); --links-h: var(--btn);
    left: var(--gutter); right: var(--gutter); max-width: none;
    display: grid; grid-template-columns: minmax(0, 1fr) var(--links-w); grid-template-rows: auto 1fr auto; align-items: start;
    padding: 11px 14px; border-radius: 16px; border: 1px solid var(--line); background: var(--panel);
    -webkit-backdrop-filter: blur(14px) saturate(1.3); backdrop-filter: blur(14px) saturate(1.3); text-shadow: none;
  }
  .hud-city::before { content: ""; grid-area: 1 / 2 / 3; height: var(--links-h); }
  #cityName { grid-column: 1; margin-bottom: 3px; font-size: 23px; }
  .sub { grid-column: 1; }
  .sub-sep { display: none; }                   /* the tagline and the time on lines of their own */
  #tagline, .sub time { display: block; }
  .sub time { margin-top: 2px; font-size: 12px; }
  #links {
    top: calc(var(--top) + 6px); right: calc(var(--gutter) + 6px); gap: 0; padding: 0;
    border: 0; background: none; -webkit-backdrop-filter: none; backdrop-filter: none;
  }
  #corner { top: calc(var(--top) + var(--title-h, 150px) + 8px); }
  /* the live count: the card's last row, "23 here now · 5 in Tokyo" ("480 here today · 12,345 all time" while no one
     else is here) */
  .live {
    grid-column: 1 / -1; width: auto; justify-content: start; margin: 10px 0 0; padding: 9px 0 0;
    border: 0; border-top: 1px solid var(--line); border-radius: 0; background: none; box-shadow: none;
    -webkit-backdrop-filter: none; backdrop-filter: none;
  }
  .live::after { content: none; }
  .live:has(.live-now) :is(.live-today, .live-all) { display: none; }
  .jobs-all { display: none; }                  /* the strip itself is the link to the jobs; they get the room */
  :root:has(#jobs:not(.running)) { --jobs-h: 45px; }
  #jobs:not(.running) .jobs-tag { display: none; }
  #jobs:not(.running) .jobs-all { display: inline-flex; }
  #jobs:not(.running) .jobs-run { mask-image: none; -webkit-mask-image: none; }
  #jobs:not(.running) .jobs-cta { font-size: 11px; }
  .jobs-post { padding: 2px 8px; font-size: 10px; line-height: 1.2; }   /* fits the 22px strip */
  #links:has(#phLink:not([hidden])) [data-network="github"] { display: none; }   /* the launch week: still four icons */
  .chip { padding-inline: 12px; gap: 6px; }
  #timerPill { flex-direction: column; gap: 4px; }   /* one timer per line, clear of the city title */
  /* a third row: the sliders get row 2 (the settings gear at its end, as the third row is full at 320 px), the vibe,
     timer, together, chat, mixer and save buttons go below them */
  .vols { display: contents; }
  #player::before, #player::after { content: ""; flex-basis: 100%; }   /* line breaks around the sliders */
  #player::before { order: 1; }
  .vol { order: 2; padding-inline: 6px; }
  #player::after { order: 3; }
  #settingsBtn { order: 2; }
  #vibeBtn, #timerBtn, #togetherBtn, #chatBtn, #mixerBtn, #saveBtn { order: 4; }
  .pop, #tour, #weather, #mixer, #saveMenu, #settings, #cityPicker, #chat { width: 100%; }
  #cityBtnTime { display: none; }               /* the title shows the local time: the three chips fit one row */
  #cityList { grid-template-columns: repeat(auto-fill, minmax(130px, 1fr)); }   /* two columns down to 320 px */
  .feat-text strong { font-size: 19px; }
  #vibe fieldset, #settings fieldset { padding-inline: 10px; }
  .seg span { padding-inline: 2px; }            /* every row's labels fit down to 320 px */
  #queue .pop-head small, #tour .pop-head small, #weather .pop-head small { display: none; }
  .about-inner { padding: 18px 16px 22px; }
  #about.tabbed { height: min(860px, calc(100dvh - 32px)); }   /* phones: nearly full height */
  .tabbed .about-inner { padding: 0; }
  .tabbed .about-body { padding: 16px 16px 18px; }
  .about-tabs { padding-left: 6px; }
  .about-tabs [role="tab"] { padding-inline: 5px; letter-spacing: .08em; }   /* all five tabs fit beside the close button from 360px */
  .about-tabs [aria-selected="true"]::after { left: 5px; right: calc(5px + .08em); }
  .tabbed .about-close { margin-right: 6px; }
  .keys div { grid-template-columns: 96px 1fr; }
  .pitch-inner { padding: 18px 16px; }
}
/* short screens (phones in landscape): tighter title and dock so more of the scene shows */
@media (max-height: 500px) {
  :root { --jobs-h: 22px; --top: calc(env(safe-area-inset-top) + var(--jobs-h) + 10px); --bottom: max(8px, env(safe-area-inset-bottom)); }
  .jobs-post { padding: 2px 8px; font-size: 10px; line-height: 1.2; }
  #cityName { margin: 0; font-size: 22px; }
  .sub { font-size: 12px; }
  .live { margin-top: 6px; padding-block: 3px; font-size: 11px; }
  .hud-bottom { gap: 6px; }
  #player { padding-block: 6px; }
}
@media (prefers-reduced-motion: reduce) {
  .jobs-all svg { transition: none; }
  .ui, #corner, #timerPill { transition: none; }
  #play.pulse, .pop, .live::before, .live::after, #jobs.running .jobs-track, #chatWho .chat-online.on::before { animation: none; }
  #jobs.running .jobs-run { -webkit-mask-image: linear-gradient(90deg, #000 calc(100% - 24px), transparent); mask-image: linear-gradient(90deg, #000 calc(100% - 24px), transparent); }   /* standing still: no left fade */
  #links :is(#phLink, #shopLink, #coffee), :is(#phLink, #shopLink, #coffee) span { transition: none; }
  .seg span, .set-switch input, .set-switch input::before { transition: none; }
  #cities { scroll-behavior: auto; }
}

/* Below 400px the tour and weather chips drop their state (still lit while on; their menus say which), so the three
   chips fit one row. */
@media (max-width: 399px) {
  #tourState, #weatherState { display: none; }
}
/* On the narrowest phones, keep room for city names beside the four links. */
@media (max-width: 360px) {
  .jobs-tag { font-size: 0; }                   /* the lit pixel alone: the jobs keep room beside Post a job */
  .jobs-tag::before { margin-right: 0; }
  #player { column-gap: 4px; }   /* the third row's six buttons fit beside each other down to 320 px */
  #links { display: grid; grid-template-columns: repeat(2, var(--btn)); }
  .hud-city { --links-w: calc(2 * var(--btn)); --links-h: calc(2 * var(--btn)); }   /* the card keeps room for two rows of them */
}
/* Below 360px (down to 320px) the About tabs tighten again so all five still fit. */
@media (max-width: 359px) {
  .about-tabs [role="tab"] { padding-inline: 3.5px; letter-spacing: 0; }
  .about-tabs [aria-selected="true"]::after { left: 3.5px; right: 3.5px; }
}
