/* NYC Sound as a New York record shop, the look the owner chose on 14 October 2026: the city is
   the label of a black LP, the five boroughs wear the shop's bin colors, and every panel, label and
   page is the white of an inner sleeve. Thick ink outlines and hard shadows. */

/* Self-hosted so the site depends on no font service. Licenses are in fonts/licenses. Londrina
   Solid has no letters beyond these: the one name on the map that needs one, Jonas Žukas, takes
   its Ž from the fallback. Shrikhand writes only the sign, so it needs no more. */
@font-face {
  font-family: 'Londrina Solid';
  font-style: normal;
  font-weight: 900;
  font-display: swap;
  src: url('fonts/londrina-solid-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Shrikhand';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('fonts/shrikhand-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Caveat Brush';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('fonts/caveat-brush-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Caveat Brush';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('fonts/caveat-brush-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Bricolage Grotesque';
  font-style: normal;
  font-weight: 200 800;
  font-display: swap;
  src: url('fonts/bricolage-grotesque-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Bricolage Grotesque';
  font-style: normal;
  font-weight: 200 800;
  font-display: swap;
  src: url('fonts/bricolage-grotesque-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

:root {
  /* Black vinyl for the water and the sign over the door; the white of an inner sleeve for every
     panel, label and page; and five bin colors, like the dot stickers a record shop prices its
     bins with, one per borough. Ink reads on all five: 5.1:1 on red, the least. */
  --vinyl: #1C1815;
  --sleeve: #FFFDF8;
  --ink: #15110E;
  --ink-soft: #5A524B;     /* small text: 7.5:1 on sleeve white, 6.6:1 on pale gold */
  --red: #F04B2C;          /* Manhattan, and the sign's paint */
  --gold: #FFBE1F;         /* Brooklyn, and what is on: a pressed genre, a focused row */
  --green: #21A85C;        /* Queens */
  --blue: #3D84F5;         /* the Bronx */
  --rose: #FF86B9;         /* Staten Island */
  /* Red for small writing on white: 5.3:1 where --red, for fills, is 3.6:1. */
  --red-text: #C7321A;
  --gold-soft: #FFEDB8;    /* a row under the pointer */

  /* Four faces, each with one job. Londrina Solid, hand-drawn capitals: the names on the map,
     headings, the initials of a face with no photo. Shrikhand: the sign over the door, and only
     that. Caveat Brush, the staff's handwriting: the tagline, a place under a face, the kind of a
     tie. Bricolage Grotesque: buttons, lists and every sentence. */
  --display: 'Londrina Solid', 'Arial Narrow', sans-serif;
  --sign: 'Shrikhand', 'Londrina Solid', serif;
  --marker: 'Caveat Brush', 'Comic Sans MS', cursive;
  --body: 'Bricolage Grotesque', system-ui, sans-serif;
  /* Read by the script, which measures names in the same face they are drawn in. */
  --name-font: 900 100px "Londrina Solid";

  --popup: 330px;
  --bar: 56px;     /* the bar of controls: app.js sets its real height, and the phones' blocks give theirs so nothing jumps then */
}

/* One bin color per borough, matching the map (see js/palette.js). Neighbors differ in hue as
   well as lightness: Brooklyn's gold against Queens's green, the Bronx's blue between Manhattan's
   red and Queens's green. Red and rose, the closest pair, are on boroughs that never touch.
   `--on-hue` is the text color that reads on the fill: ink, on all five. */
.b-manhattan     { --hue: var(--red);   --on-hue: var(--ink); }
.b-brooklyn      { --hue: var(--gold);  --on-hue: var(--ink); }
.b-queens        { --hue: var(--green); --on-hue: var(--ink); }
.b-bronx         { --hue: var(--blue);  --on-hue: var(--ink); }
.b-staten-island { --hue: var(--rose);  --on-hue: var(--ink); }

*, *::before, *::after { box-sizing: border-box; }
html, body { height: 100%; margin: 0; }

/* The map's page is the black of the record, under it and round it; a page to read is sleeve white (body.page). */
body {
  overflow: hidden;
  background: var(--vinyl);
  color: var(--ink);
  font-family: var(--body);
  font-size: 14px;
  line-height: 1.4;
  -webkit-font-smoothing: antialiased;
}

button { font: inherit; color: inherit; }
:focus-visible { outline: 3px solid var(--ink); outline-offset: 2px; }
[hidden] { display: none !important; }

/* ---------- Map and everything drawn over it ---------- */

#map { position: fixed; inset: var(--bar) 0 0 0; background: var(--vinyl); font: inherit; }
.maplibregl-canvas, .maplibregl-canvas:focus-visible { outline: none; }
/* The map is the first Tab stop and the keyboard can move it: a ring inside its edges, since it fills
   the map area. Ink and white together, as an ink ring alone was lost on the black record and a
   white one would be on the white panel beside it. Over the names and faces too. */
#map:has(.maplibregl-canvas:focus-visible)::after {
  content: ''; position: absolute; inset: 0; z-index: 4; pointer-events: none;
  box-shadow: inset 0 0 0 3px var(--ink), inset 0 0 0 6px var(--sleeve);
}

/* Lives inside the map's canvas container, so gestures on a name or a face still reach the map. */
.overlay { position: absolute; left: 0; top: 0; overflow: hidden; pointer-events: none; }
.overlay svg { position: absolute; inset: 0; width: 100%; height: 100%; }
.overlay button { position: absolute; left: 0; top: 0; padding: 0; pointer-events: auto; cursor: pointer; }

/* Names: lettered capitals, cut out like a sticker in the borough's bin color, with an edge of
   that color 9 px wide round every letter. On its own borough the edge vanishes into the land;
   where a name runs out over the black water, its letters stay on color. A name is never ink on
   black. The owner chose the record store look with one complaint (14 October 2026): "I just dont
   like the black text on a black background on that one". This edge is the answer to it, and it
   also lets the letters stand on the streets that run through them. */
.name, .name-edge {
  font-family: var(--display);
  font-weight: 900;
  letter-spacing: 0.02em;
  text-anchor: middle;
  text-transform: uppercase;
  pointer-events: auto;
  cursor: pointer;
}
/* The edge is its own copy of the name, in a layer under every name's letters (overlay.js): the
   letters were drawn under their own 9 px edge on the owner's phone, which ignored the order asked
   of it, and a name's edge could cover the end of the name beside it. */
.name { fill: var(--on-hue); }
.name-edge { fill: var(--hue); stroke: var(--hue); stroke-width: 9px; stroke-linejoin: round; }
/* Chosen: what the panel shows, white on an ink edge, which reads on the land and the water alike.
   Nothing else changes. */
.name.lit { fill: var(--sleeve); }
.name-edge.lit { fill: var(--ink); stroke: var(--ink); stroke-width: 4.5px; }

/* People: record sleeves. A person on the map is always a square sleeve, ink-edged, its corners
   worn a hair round, with its record peeking out of the open side and the glare of the shrink-wrap
   across the cover. A place is never square: a neighborhood is a round sticker and a divider card.
   The owner, 14 October 2026: "We need to distinguish neighborhoods better from artists icons".
   With no photo, or while one fails to load, the sleeve is the shop's plain black one, its die-cut
   hole showing the record's label in the borough's color, with the initials on it in ink.
   `--side` is the sleeve's side and `--peek` how far its record comes out of it (js/layout.js). */
.sleeve { position: relative; display: block; width: 100%; height: 100%; transition: transform 0.12s; }
/* The record, behind the sleeve: grooves, the two wedges of light they catch, a label in the borough's color. */
.sleeve::before {
  content: ''; position: absolute; z-index: 0; top: 5%; left: calc(10% + var(--peek, 8%)); width: 90%; height: 90%; border-radius: 50%;
  background:
    radial-gradient(circle closest-side, var(--vinyl) 0 5%, var(--hue, var(--red)) 6% 33%, #0B0908 34% 37%, transparent 38%),
    conic-gradient(from 35deg, transparent 0 7%, rgba(255, 253, 248, 0.22) 11%, transparent 15% 57%, rgba(255, 253, 248, 0.22) 61%, transparent 65%),
    repeating-radial-gradient(circle closest-side, #1A1613 0 1px, #2C2622 1.4px 2.2px);
  transition: transform 0.22s cubic-bezier(.3, 1.4, .6, 1);
}
.sleeve-photo {
  position: relative; z-index: 1; display: grid; place-items: center; width: 100%; height: 100%; overflow: hidden;
  border: 2px solid var(--ink); border-radius: 2px; box-shadow: 2.5px 2.5px 0 var(--ink);
  /* The plain sleeve's worn corner and edges, under the photo: over the black water they keep it
     square, where it would otherwise read as its round label alone. */
  background:
    linear-gradient(135deg, rgba(255, 253, 248, 0.45) 0 12%, transparent 12.5%),
    radial-gradient(circle closest-side, var(--hue, var(--red)) 0 62%, #0B0908 63% 67%, #221D19 68% 85%, #0B0908 86% 89%, transparent 90%),
    #3A332D;
}
.sleeve-label { font-family: var(--display); font-weight: 900; font-size: calc(var(--side, 46px) * 0.3); line-height: 1; letter-spacing: 0.02em; color: var(--ink); }
/* The photo covers the plain sleeve; it is removed when it fails to load, and the sleeve shows. */
.sleeve-photo img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: 50% 20%; }
/* The shrink-wrap's glare across the cover. */
.sleeve-photo::after {
  content: ''; position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background: linear-gradient(118deg, transparent 0 34%, rgba(255, 253, 248, 0.2) 40%, rgba(255, 253, 248, 0.06) 47%, transparent 52%);
}
/* Chosen: what the panel shows, a white edge inside an ink one, as a chosen name is white on ink. */
.pair.lit .sleeve-photo, .face.lit .sleeve-photo, .tuck .sleeve.lead .sleeve-photo { border-color: var(--sleeve); box-shadow: 0 0 0 2px var(--ink), 2.5px 2.5px 0 2px var(--ink); }

/* From afar, the sleeve beside a name, level with it: its record peeks out toward the name. */
.pair { border: 0; background: none; will-change: transform; --peek: 14%; }
.pair .sleeve-photo { border-width: 1.5px; box-shadow: 1.5px 1.5px 0 var(--ink); }
.pair.lit, .face.lit { z-index: 2; }

/* Up close, an artist with a place of their own: a sleeve with a price dot in the borough's color
   on its corner, and under it a price label stuck on askew, the name in capitals and the place in
   handwriting, as written on a label. */
.face { border: 0; background: none; will-change: transform; }
.overlay .face .sleeve::after {
  content: ''; position: absolute; z-index: 2; top: -3px; right: -3px; width: 12px; height: 12px;
  border: 1.5px solid var(--ink); border-radius: 50%; background: var(--hue, var(--red));
}
.face-tag {
  position: absolute; left: 50%; top: calc(100% + 6px); transform: translateX(-50%) rotate(-2deg);
  /* Turned on its top right corner, so that its top edge never rises above where the layout hangs it. */
  transform-origin: 100% 0;
  padding: 2px 6px 3px; background: var(--sleeve); color: var(--ink); border: 1.5px solid var(--ink); border-radius: 2px; box-shadow: 1.5px 1.5px 0 var(--ink);
  white-space: nowrap; text-align: center;
}
.face-tag b { display: block; font-family: var(--display); font-size: 12px; font-weight: 900; line-height: 1.1; letter-spacing: 0.04em; text-transform: uppercase; }
.face-tag i { display: block; font-family: var(--marker); font-style: normal; font-size: 13px; line-height: 1.05; letter-spacing: 0; color: var(--red-text); }
.face.lit .face-tag { background: var(--ink); color: var(--sleeve); }
.face.lit .face-tag i { color: var(--gold); }

/* A neighborhood up close: its drawn emblem on a round white sticker, slapped on askew, with a few
   of its people's sleeves filed behind its edge, and under them its divider card. */
.stack { display: flex; flex-direction: column; align-items: center; gap: 5px; border: 0; background: none; will-change: transform; }
.stack.lit { z-index: 2; }
.pile { position: relative; display: block; }
.disc {
  position: absolute; left: 0; top: 0; z-index: 4; display: grid; place-items: center; width: 52px; height: 52px; overflow: hidden;
  border: 2px solid var(--ink); border-radius: 50%; background: var(--sleeve); box-shadow: 2px 2px 0 var(--ink);
  transform: rotate(-6deg); transition: transform 0.12s;
}
/* The drawing stays on its sticker: a few run past their own frame (a piano's notes, a skyline). */
.disc .emblem-holder { width: 36px; height: 36px; }
.tuck .sleeve { position: absolute; width: 28px; height: 28px; --side: 28px; }
.tuck .sleeve.lead { width: 40px; height: 40px; --side: 40px; }
/* Filed side by side, their records stay in the sleeves. */
.tuck .sleeve::before { display: none; }
.tuck .sleeve .sleeve-photo { box-shadow: 2px 2px 0 var(--ink); }
/* The divider card: a tab round on top, the name lettered on it, the count on a dot in the borough's color. */
.stack-tag {
  display: flex; align-items: center; gap: 6px; padding: 2px 3px 2px 8px;
  border: 2px solid var(--ink); border-radius: 8px 8px 2px 2px; background: var(--sleeve); color: var(--ink); box-shadow: 2px 2px 0 var(--ink);
  font-family: var(--display); font-weight: 900; font-size: 12.5px; letter-spacing: 0.05em; line-height: 1.15; text-transform: uppercase; white-space: nowrap;
}
.stack-tag span {
  min-width: 18px; padding: 0 5px; border: 1.5px solid var(--ink); border-radius: 999px;
  background: var(--hue); color: var(--on-hue); text-align: center;
  font-family: var(--body); font-size: 11px; font-weight: 800; letter-spacing: 0; line-height: 13px;
}
.stack.lit .stack-tag { background: var(--ink); color: var(--sleeve); }

/* Landmarks: places with people attached. The marker shape says which kind. Sleeve white with
   an ink edge: they were once a borough's color, and a school tag there was lost on its own land. */
.mark {
  display: flex; align-items: center; gap: 5px; padding: 2px 6px 2px 4px !important;
  border: 2px solid var(--ink); background: var(--sleeve); box-shadow: 2px 2px 0 var(--ink);
  font-size: 9.5px; font-weight: 700; letter-spacing: 0.07em; line-height: 1.2; text-transform: uppercase; white-space: nowrap;
}
.mark::before { content: ''; width: 7px; height: 7px; background: var(--ink); }
.mark.project::before { border-radius: 50%; }
.mark.street::before { width: 9px; height: 3px; }
.mark span { padding: 0 4px; background: var(--ink); color: var(--sleeve); }
/* The landmark whose list is open, lit like everything else that is chosen. */
.mark.lit { z-index: 2; background: var(--ink); color: var(--sleeve); }
.mark.lit::before { background: var(--sleeve); }
.mark.lit span { background: var(--sleeve); color: var(--ink); }

/* Someone playing New York this week (js/shows.js): a gold LIVE sticker, the day of their show on it
   and a recording light's red dot, slapped on the end of their name from afar and on their sleeve's
   corner up close, leaning, with a hard shadow. Its shape, sides leaning, is the price sticker the
   owner chose ("i live the design of the stickers!", meaning love). js/layout.js keeps the same sizes (STICKER),
   and on a phone everything in it is four fifths of the size. */
.live { border: 0; background: none; z-index: 4; filter: drop-shadow(2px 2px 0 var(--ink)); will-change: transform; }
.live-edge { display: block; padding: 2px; background: var(--ink); clip-path: polygon(7% 0, 100% 0, 93% 100%, 0 100%); transform: rotate(-7deg); transform-origin: 0 100%; }
.live-face {
  display: flex; align-items: center; gap: 5px; height: 13px; padding: 0 10px 0 9px;
  background: var(--gold); color: var(--ink); clip-path: polygon(7% 0, 100% 0, 93% 100%, 0 100%);
  font-family: var(--body); font-size: 10px; font-weight: 800; line-height: 1; letter-spacing: 0.08em; text-transform: uppercase; white-space: nowrap;
}
.live-face::before { content: ''; flex: none; width: 6px; height: 6px; border-radius: 50%; background: var(--red); box-shadow: 0 0 0 1.5px var(--ink); }
.live.narrow { filter: drop-shadow(1.6px 1.6px 0 var(--ink)); }
.live.narrow .live-edge { padding: 1.6px; }
.live.narrow .live-face { gap: 4px; height: 10.4px; padding: 0 8px 0 7.2px; font-size: 8px; }
.live.narrow .live-face::before { width: 4.8px; height: 4.8px; box-shadow: 0 0 0 1.2px var(--ink); }

/* Where an open card's artist plays (js/layout.js, venueMarks): a gold ticket over the venue on an
   ink stem from a gold dot at its point, notched like a ticket stub, with the LIVE sticker's dot and
   letters; the artist's sleeve travels there along a dotted gold route and stands on it, and where
   they are drawn stays outlined in dashed gold, their sleeve and name there gone pale. The owner's
   pick, 15 October 2026: "1, with the card from 3 moving to the venue". On a phone the ticket is
   drawn at full size and scaled, as the layout measures it. None of it takes a press. */
.venue { position: absolute; inset: 0; pointer-events: none; }
.venue > * { position: absolute; left: 0; top: 0; }
.venue-ticket { z-index: 1; transform-origin: 0 0; filter: drop-shadow(2px 2px 0 var(--ink)); will-change: transform; }
.venue-ticket-edge {
  display: block; padding: 2px; background: var(--ink);
  -webkit-mask: radial-gradient(circle at 0 50%, transparent 6px, #000 6.5px) left / 51% 100% no-repeat, radial-gradient(circle at 100% 50%, transparent 6px, #000 6.5px) right / 51% 100% no-repeat;
          mask: radial-gradient(circle at 0 50%, transparent 6px, #000 6.5px) left / 51% 100% no-repeat, radial-gradient(circle at 100% 50%, transparent 6px, #000 6.5px) right / 51% 100% no-repeat;
}
.venue-ticket-face {
  display: flex; align-items: center; gap: 5px; height: 18px; padding: 0 13px;
  background: var(--gold); color: var(--ink);
  -webkit-mask: radial-gradient(circle at 0 50%, transparent 4.5px, #000 5px) left / 51% 100% no-repeat, radial-gradient(circle at 100% 50%, transparent 4.5px, #000 5px) right / 51% 100% no-repeat;
          mask: radial-gradient(circle at 0 50%, transparent 4.5px, #000 5px) left / 51% 100% no-repeat, radial-gradient(circle at 100% 50%, transparent 4.5px, #000 5px) right / 51% 100% no-repeat;
  font-family: var(--body); font-size: 10px; font-weight: 800; line-height: 1; letter-spacing: 0.08em; text-transform: uppercase; white-space: nowrap;
}
.venue-ticket-face::before { content: ''; flex: none; width: 6px; height: 6px; border-radius: 50%; background: var(--red); box-shadow: 0 0 0 1.5px var(--ink); }
/* The traveller is the open card's artist, so it is lit as they are: a white edge inside an ink one. */
.venue-sleeve { z-index: 2; --peek: 14%; will-change: transform; }
.venue-sleeve .sleeve-photo { border-color: var(--sleeve); box-shadow: 0 0 0 2px var(--ink), 2.5px 2.5px 0 2px var(--ink); }
.venue-home { z-index: 0; border: 3px dashed var(--gold); border-radius: 3px; box-shadow: 0 0 0 2px var(--ink), inset 0 0 0 2px var(--ink); }
.venue-route path { fill: none; stroke-linecap: round; }
.venue-route .casing { stroke: var(--ink); stroke-width: 7; stroke-dasharray: 0 10; }
.venue-route .dots { stroke: var(--gold); stroke-width: 4; stroke-dasharray: 0 10; }
.venue-route line { stroke: var(--ink); stroke-width: 2.5; }
.venue-route circle { fill: var(--gold); stroke: var(--ink); stroke-width: 2; }
.overlay .away { opacity: 0.4; }
.overlay .live.away { display: none; }

/* ---------- Title and controls ---------- */

/* A bar above the map, never on it. The controls used to float over the map's top
   left corner; the owner: "this is a dumb spot and blocks the map". The map starts
   below the bar: app.js keeps --bar equal to the bar's real height.
   The bar is no taller than its buttons need: 77 px, as it once was, is a ninth of a laptop
   screen. It lies over what drops from it: the list of genres is above the shade under it, and
   on a phone the sheet slides out from under the bar.
   It is the black sign over a record shop's door: the shop's own record, the name painted
   with a shade in a second color, the tagline in the staff's handwriting, and along its foot
   the five bin colors, one per borough, where an ink rule used to be. */
.masthead {
  position: fixed; top: 0; right: 0; left: 0; z-index: 10; display: flex; align-items: center; gap: 16px; height: 56px; padding: 0 18px 0 16px;
  background: var(--vinyl);
  border-bottom: 5px solid var(--ink);
  border-image: linear-gradient(90deg, var(--red) 0 20%, var(--gold) 20% 40%, var(--green) 40% 60%, var(--blue) 60% 80%, var(--rose) 80%) 1;
}
/* On the black sign the focus ring is gold (10.6:1), where ink would be lost. */
.masthead :focus-visible { outline-color: var(--gold); }
/* But the list of genres is a white box hanging from the sign: gold was 1.6:1 on its white and
   nothing at all on the pressed genre's gold, where the keyboard lands first. Ink reads on both. */
.masthead .menu :focus-visible { outline-color: var(--ink); }
.title-card {
  flex: none;
  display: flex; align-items: center; gap: 10px;
  /* It is a link: the way home. */
  color: var(--sleeve);
  text-decoration: none;
}
/* The shop's own record: grooves, the two wedges of light they catch, and a red label. It turns
   while the map loads, and under the pointer. */
.title-card::before {
  content: ''; flex: none; width: 36px; height: 36px; border-radius: 50%;
  background:
    radial-gradient(circle closest-side, var(--vinyl) 0 4%, var(--red) 5% 33%, #0B0908 34% 36%, transparent 37%),
    conic-gradient(from 35deg, transparent 0 7%, rgba(255, 253, 248, 0.2) 11%, transparent 15% 57%, rgba(255, 253, 248, 0.2) 61%, transparent 65%),
    repeating-radial-gradient(circle closest-side, #1A1613 0 1px, #2C2622 1.4px 2.2px);
  box-shadow: 0 0 0 1.5px #3B332C;
}
@keyframes spin { to { transform: rotate(360deg); } }
html:has(#loading) .title-card::before { animation: spin 1.6s linear infinite; }
.title-card h1, .title-card .h1 { margin: 0; font-family: var(--sign); font-weight: 400; font-size: 25px; line-height: 1; letter-spacing: 0.01em; white-space: nowrap; color: var(--sleeve); text-shadow: 2px 2px 0 var(--red); }
.tagline { margin: 1px 0 0; font-family: var(--marker); font-size: 14px; line-height: 1; letter-spacing: 0.01em; white-space: nowrap; color: var(--gold); }

/* The genres and the neighborhoods each drop from one button in the bar. The owner, 11 October:
   "Neighborhoods and genres need to both be dropdowned from a button in the top panel". The
   genres used to be a row of buttons across the bar, which on a phone scrolled sideways, most
   of them out of sight; on a phone the Neighborhoods button was a bar under the map. */
.drop { position: relative; flex: none; align-self: stretch; display: flex; align-items: center; margin-right: auto; }
/* In one row, the name of a genre that is on gives way to an ellipsis before anything is pushed off
   the end of the bar: a phone held sideways has just the width for the title, the zoom buttons and
   the rest, and a long name such as Folk & Country could take it. */
.masthead .drop, #genre, #genre-name { flex-shrink: 1; min-width: 0; }
#genre-name { overflow: hidden; text-overflow: ellipsis; }
.chip {
  flex: none;
  padding: 6px 9px;
  border: 2px solid var(--ink);
  background: var(--sleeve);
  box-shadow: 2px 2px 0 var(--ink);
  font-size: 11px;
  font-weight: 700;
  line-height: 1;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  white-space: nowrap;
  cursor: pointer;
}
/* On the black sign a hard shadow in ink would be lost: the sign's red instead. */
.masthead .chip { border-radius: 5px; box-shadow: 2px 2px 0 var(--red); }
/* The two buttons that something drops from: the tabs of a record bin's divider cards, round on
   top. They are larger than the other controls, with a heavier shadow, and each has the caret of
   a menu. Neighborhoods is the one flat red thing in the bar, and carries the magnifier of the
   search field its panel opens on; its shadow is white, as red on red would not show. Genres
   names the genre that is on, in gold, the color of a pressed genre. Open, a button is pressed
   in, in the white of what hangs from it. */
.chip.door {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  height: 36px; padding: 0 14px;
  border-radius: 10px 10px 4px 4px;
  font-size: 12.5px; letter-spacing: 0.08em;
}
.masthead .chip.door { box-shadow: 3px 3px 0 var(--red); }
.chip.hoods { background: var(--red); }
.masthead .chip.hoods { box-shadow: 3px 3px 0 var(--sleeve); }
.chip.door.on { background: var(--gold); color: var(--ink); }
.chip.door[aria-expanded="true"], .masthead .chip.door[aria-expanded="true"] { background: var(--sleeve); color: var(--ink); box-shadow: none; transform: translate(2px, 2px); }
.chip.door.on[aria-expanded="true"] { background: var(--gold); }
.caret { flex: none; width: 10px; height: 6px; margin-left: -1px; fill: none; stroke: currentColor; stroke-width: 2.2; transition: transform 0.12s; }
.door[aria-expanded="true"] .caret { transform: rotate(180deg); }
/* The list of genres, hanging from the bar under its button, as high as the panel hangs:
   19 px under the button's row is the bar's 5 px rule and the panel's 14 px gap. Its corners are
   rounded as the panel's are, beside which it can hang. */
.menu {
  position: absolute; top: calc(100% + 19px); left: -4px; display: grid; min-width: calc(100% + 8px);
  max-height: calc(100vh - var(--bar) - 32px); overflow-y: auto;
  padding: 6px 0; background: var(--sleeve); border: 4px solid var(--ink); border-radius: 8px; box-shadow: 8px 8px 0 var(--ink);
}
/* As short a window as a phone held sideways has no room for one column: two. */
@media (max-height: 430px) { .menu { grid-auto-flow: column; grid-template-rows: repeat(5, auto); } }
.option { padding: 9px 18px; border: 0; background: none; font-size: 12.5px; font-weight: 700; letter-spacing: 0.07em; line-height: 1.1; text-align: left; text-transform: uppercase; white-space: nowrap; cursor: pointer; }
.option[aria-pressed="true"] { background: var(--gold); color: var(--ink); }
.option:focus-visible { outline-offset: -3px; }
/* This week: who plays New York in the next seven days (js/shows.js), first in the bar, there only
   when somebody does. A door like Genres, gold while their LIVE stickers are on the map and white
   once switched off, with the stickers' red dot and how many play. Its list of the week's shows
   hangs from it by date, under the switch, a pressed option like a genre. */
.masthead .week-drop { flex: none; margin-right: 0; }
.chip.week::before { content: ''; flex: none; width: 8px; height: 8px; border-radius: 50%; background: var(--red); box-shadow: 0 0 0 1.5px var(--ink); }
.week-count { display: inline-grid; place-items: center; min-width: 19px; height: 19px; padding: 0 4px; border-radius: 3px; background: var(--ink); color: var(--sleeve); font-size: 11px; letter-spacing: 0; }
.chip.week.on .week-count { color: var(--gold); }
.menu.weeklist { display: block; width: 320px; padding: 0 0 10px; }
.week-switch { display: flex; align-items: center; gap: 8px; width: 100%; padding: 13px 18px; border-bottom: 3px solid var(--ink); }
.week-switch::before { content: ''; flex: none; width: 8px; height: 8px; border-radius: 50%; background: var(--sleeve); box-shadow: 0 0 0 1.5px var(--ink); }
.week-switch[aria-pressed="true"]::before { background: var(--red); }
.week-day h3 { margin: 12px 18px 0; font-family: var(--display); font-weight: 900; font-size: 19px; line-height: 1; letter-spacing: 0.03em; text-transform: uppercase; color: var(--red-text); }
.weeklist .rows { padding: 2px 0 4px; }
.weeklist .row { padding: 6px 18px; text-transform: none; letter-spacing: 0; font-weight: 400; }
.week-source { margin: 4px 18px 0; color: var(--ink-soft); font-size: 11px; }
/* Under an open list of genres and over the map, invisible: a press beside the list only puts it away.
   It takes a finger's drag itself, so that the drag can put the list away too. */
.shade { position: fixed; inset: 0; z-index: 9; touch-action: none; }
/* The magnifier, here and in the search field. */
.glass { flex: none; width: 14px; height: 14px; fill: none; stroke: currentColor; stroke-width: 2.6; }
/* Plus and minus, in the bar with the other controls rather than on the map. They are also
   the sign, without a word, that the map goes deeper: the mouse wheel takes fifteen notches
   to reach the faces, and nothing else on the first screen says they are there. Like the ?
   beside them they are round, the buttons of a turntable, ringed in white on the black sign
   so that the shop's name leads. */
.zoom { flex: none; display: flex; gap: 7px; }
.zoom .chip { width: 30px; height: 30px; padding: 0 0 1px; font-size: 18px; line-height: 1; }
.masthead .zoom .chip, .masthead .chip.ask, .masthead .chip.street-map { border-color: var(--sleeve); border-radius: 50%; background: var(--vinyl); color: var(--sleeve); box-shadow: none; }
.chip[aria-disabled="true"] { box-shadow: none; opacity: 0.4; cursor: default; }
/* On the black sign, half: white at 40% was 3.8:1 there, dim enough to read as off but hard to read. */
.masthead .chip[aria-disabled="true"] { opacity: 0.5; }
/* The switch between the record and the street map (js/streetmap.js), beside them: a round button
   of the turntable's with a folded street map on it, gold while the street map is on, as a pressed
   genre is. Where the bar has two rows it is a square in the credits corner instead (further down). */
.chip.street-map { display: inline-grid; place-items: center; width: 30px; height: 30px; padding: 0; }
.chip.street-map svg { width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-linejoin: round; }
.chip.street-map .fold { stroke-width: 1.8; }
.chip.street-map .crease { stroke-width: 1.4; }
.masthead .chip.street-map[aria-pressed="true"] { border-color: var(--gold); background: var(--gold); color: var(--ink); }
/* While the street map is fetched, the first time it is asked for. */
.chip.street-map[aria-busy="true"] { opacity: 0.6; cursor: progress; }

/* ---------- Neighborhoods pop-up ---------- */

/* The crate: a box of sleeve white, its corners rounded a little, as the reference has it. A divider
   card's color is kept inside them. */
.popup {
  position: fixed; top: calc(var(--bar) + 14px); right: 18px; z-index: 8; display: flex; flex-direction: column;
  width: var(--popup); max-height: calc(100vh - var(--bar) - 32px); overflow: hidden;
  background: var(--sleeve); border: 4px solid var(--ink); border-radius: 8px; box-shadow: 8px 8px 0 var(--ink);
}
/* The heading stays; the rows scroll under it. */
.popup-body { flex: 1 1 auto; min-height: 0; overflow: auto; }
/* The ×: a round white button with an ink ring, as the turntable buttons on the sign are round. It
   reads on the white of a card and on every bin color of a divider card alike. */
.popup-close {
  position: absolute; top: 10px; right: 10px; z-index: 2; display: grid; place-items: center; width: 30px; height: 30px; padding: 0 0 2px;
  border: 2px solid var(--ink); border-radius: 50%; background: var(--sleeve); color: var(--ink);
  font-size: 20px; font-weight: 600; line-height: 1; cursor: pointer;
}
.popup-head { flex: none; padding: 18px 44px 12px 18px; border-bottom: 3px solid var(--ink); }
/* A heading takes the focus when what the pop-up shows changes, so the keyboard and a screen
   reader start from it; it is not something to press, and needs no ring. */
.popup-head h2:focus { outline: none; }
.popup-head h2 { margin: 0; font-family: var(--display); font-weight: 900; font-size: 34px; line-height: 0.95; letter-spacing: 0.02em; text-transform: uppercase; color: var(--ink); }
.popup-head p { margin: 4px 0 0; color: var(--ink-soft); font-size: 12.5px; }
.popup-head .kind { margin: 0 0 2px; font-family: var(--marker); font-size: 17px; line-height: 1.1; color: var(--red-text); }
/* The search field: one ink-edged pill and a magnifier, no words. It runs the full width of the
   heading, under the × rather than beside it. */
.find { position: relative; margin: 10px -26px 0 0; }
.find input {
  display: block; width: 100%; height: 36px; padding: 0 12px 0 37px;
  border: 2px solid var(--ink); border-radius: 999px; background: #ffffff; box-shadow: 2px 2px 0 var(--ink);
  color: var(--ink); font: inherit; font-size: 14px; font-weight: 600;
  -webkit-appearance: none; appearance: none;
}
.find input:focus-visible { outline-offset: 1px; }
/* The browser's own way of emptying a search field, drawn in ink instead of its blue. */
.find input::-webkit-search-cancel-button {
  -webkit-appearance: none; appearance: none; width: 18px; height: 18px; cursor: pointer;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M3 3l10 10M13 3L3 13' stroke='%2315110E' stroke-width='2.5'/%3E%3C/svg%3E") center / 12px no-repeat;
}
.find .glass { position: absolute; left: 14px; top: 50%; z-index: 1; margin-top: -7px; pointer-events: none; }
/* The way back, named for where it goes: a school's long name wraps, from the left as it reads. */
.back { margin: 0 0 8px; padding: 0; border: 0; background: none; font-size: 11px; font-weight: 700; letter-spacing: 0.04em; text-align: left; text-transform: uppercase; cursor: pointer; }
.rows { list-style: none; margin: 0; padding: 6px 0; }
.row { display: grid; align-items: center; gap: 10px; width: 100%; padding: 8px 18px; border: 0; background: none; text-align: left; cursor: pointer; }
.row:focus-visible { background: var(--gold); }
.row:focus-visible { outline-offset: -3px; }
/* minmax(0, 1fr), not 1fr: a one-line description wider than the row would otherwise widen
   it and scroll the whole list sideways, instead of ending in the ellipsis the text asks for. */
.row.place { grid-template-columns: 30px minmax(0, 1fr) 76px 30px; }
.row.person { grid-template-columns: 46px minmax(0, 1fr); }
/* A person in a list is their sleeve, small, its record peeking out toward their name. */
.row.person > .sleeve { width: 40px; height: 40px; --side: 40px; --peek: 14%; }
.row b { display: block; font-weight: 750; font-size: 14px; }
.row small { display: block; overflow: hidden; color: var(--ink-soft); font-size: 12.5px; white-space: nowrap; text-overflow: ellipsis; }
/* A neighborhood's drawn emblem (js/emblem.js; pipeline/lib/emblems.mjs): ink lines, the borough's
   color as its main fill, sleeve white for the light parts and a gold accent. The same rules sit in
   each SVG file, with blue for the fill, for when one is opened by itself. Brooklyn's color
   is the gold, so there the accent is red. */
.emblem-holder { display: inline-flex; flex: none; width: 30px; height: 30px; color: var(--hue, var(--blue)); }
.emblem-holder svg { width: 100%; height: 100%; overflow: visible; }
.emblem .ink { stroke: var(--emblem-ink, var(--ink)); stroke-linecap: round; stroke-linejoin: round; }
.emblem .solid { fill: var(--emblem-ink, var(--ink)); }
.emblem .hue { fill: currentColor; }
.emblem .paper { fill: var(--emblem-paper, var(--sleeve)); }
.emblem .paper-line { stroke: var(--emblem-paper, var(--sleeve)); stroke-linecap: round; stroke-linejoin: round; }
.emblem .accent { fill: var(--emblem-accent, var(--gold)); }
.b-brooklyn { --emblem-accent: var(--red); }
/* An opened neighborhood heads its crate with its divider card, in its borough's bin color: the way
   back, its emblem on a round white sticker slapped on askew, its name in big capitals, and its
   borough and count, all in ink, which reads on the five. The name is lettered as large as its
   longest word allows (--longest, js/format.js): Williamsburg is one word of twelve. */
.popup-head.divider { background: var(--hue); color: var(--on-hue); container-type: inline-size; }
.popup-head.divider p { color: inherit; font-size: 13px; }
.place-title { display: flex; align-items: center; gap: 12px; margin-top: 2px; }
.place-title .emblem-holder {
  width: 52px; height: 52px; padding: 6px; overflow: hidden; transform: rotate(-6deg);
  background: var(--sleeve); border: 2px solid var(--ink); border-radius: 50%; box-shadow: 2px 2px 0 var(--ink);
}
.popup-head.divider h2 { min-width: 0; font-size: 30px; overflow-wrap: break-word; }
/* The fitted size only where the browser has container units: in one without them a size that uses
   them falls back to the page's 14 px, not to the size before it. 30 px there fits Williamsburg.
   Never under 12 px, however long a word: past that it breaks instead. */
@supports (width: 1cqi) {
  .popup-head.divider h2 { font-size: max(12px, min(40px, (100cqi - 64px) / var(--longest, 6) / 0.52)); }
}
/* How many: the records in the bin, standing on edge and seen from the side, on the bin's floor. */
.bar { display: block; height: 14px; border-bottom: 2px solid var(--ink); background: repeating-linear-gradient(90deg, var(--ink) 0 2px, transparent 2px 4px); }
.num { font-family: var(--display); font-size: 18px; font-weight: 900; line-height: 1; text-align: right; font-variant-numeric: tabular-nums; }
.empty { margin: 0; padding: 18px; color: var(--ink-soft); }

/* Flip the crate: an opened neighborhood's or landmark's people are the sleeves in its crate,
   standing side by side, three to a row (four on a phone), each with the name under it and what
   they do cut short. Each record stands in its sleeve; with a mouse a sleeve lifts under the pointer
   and its record rises out of the top. The keyboard's focus lifts it too, inside an ink ring, its
   record left in: risen, it ran through the ring. */
.popup .crate { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 18px 12px; padding: 20px 16px 22px; }
.popup .crate .row.person { position: relative; display: flex; flex-direction: column; align-items: stretch; gap: 7px; padding: 0; background: none; transition: transform 0.15s; }
.popup .crate .row .sleeve { width: 100%; height: auto; aspect-ratio: 1; --side: 88px; --peek: -5%; }
.popup .crate .sleeve-photo { box-shadow: 3px 3px 0 var(--ink); }
/* A name is never cut short: Oscar Hammerstein II lost his numeral to a two-line limit. Nor is it
   broken inside a word, which left a letter or two on a line of their own (Louis Armstron/g,
   Rachmaninof/f): a name whose longest word is too long for the sleeve's width is lettered smaller,
   by that word (--longest, js/format.js; 0.63 em a letter covers the widest, Consequence's), down to
   10 px. Only a word too long even for that breaks. */
.popup .crate .row > span:not(.sleeve) { container-type: inline-size; }
.popup .crate .row b { display: block; font-size: 12.5px; line-height: 1.15; overflow-wrap: break-word; }
@supports (width: 1cqi) {
  .popup .crate .row b { font-size: max(10px, min(12.5px, 100cqi / var(--longest, 6) / 0.63)); }
}
.popup .crate .row small { margin-top: 1px; font-size: 11px; }
.popup .crate .row:focus-visible { background: none; outline-offset: 4px; transform: translateY(-3px); }
/* Scrolled into sight with room for that ring and the lift: brought just to the edge, a sleeve at
   the fold lost the bottom of its ring under the edge of the crate. The lift takes the ring 10 px
   above the sleeve's place and 4 below it, so a row needs 15 px more than its height, not 20. */
.popup .crate .row { scroll-margin-block: 10px 5px; }

/* ---------- Artist card ---------- */

/* Drawn in the pop-up, where the list was: its photo and name stay in place as the heading,
   and the rest scrolls under them like a list's rows. */
.card-body { padding: 14px 18px 18px; }
/* The head is the artist's record sleeve, as on the map, with its record half out of it, and their
   name beside it like a title on a sleeve. Opening the card pulls the record out of the sleeve,
   turning, until it comes to a stop. */
#popup[data-view^="artist"] .popup-head { padding-right: 14px; }
.card-head { display: flex; align-items: flex-start; }
.card-head .sleeve { flex: none; width: 90px; height: 90px; --side: 90px; --peek: 30%; }
.card-head .sleeve::before { animation: pull 0.9s cubic-bezier(.2, .8, .25, 1) both; }
@keyframes pull { from { transform: translateX(-36%) rotate(-220deg); } }
.card-head .sleeve-photo { border-width: 2.5px; box-shadow: 3px 3px 0 var(--ink); }
/* A sleeve that has been played: a worn corner, the record's ring rubbed into the cover, and the
   shrink-wrap's glare across it. */
.card-head .sleeve-photo::after {
  background:
    linear-gradient(135deg, rgba(255, 253, 248, 0.55) 0 6px, transparent 6.5px),
    linear-gradient(118deg, transparent 0 34%, rgba(255, 253, 248, 0.16) 40%, rgba(255, 253, 248, 0.05) 47%, transparent 52%),
    radial-gradient(circle closest-side, transparent 0 84%, rgba(255, 253, 248, 0.3) 87%, rgba(255, 253, 248, 0.1) 91%, transparent 94%);
  mix-blend-mode: screen;
}
/* The name, clear of the record: it wraps between words, and is lettered as large as its longest
   word allows (--longest, js/format.js), so that a long one-word name neither breaks inside itself
   nor runs under the ×, down to 12 px: a word too long even for that breaks rather than shrink further. Its first line leaves the × its corner, under the way back too: on a phone
   the way back is shorter than the ×, and the name came up beside it. So does the way back itself. */
.card-head > div { flex: 1; min-width: 0; margin-left: 39px; container-type: inline-size; --clear: 32px; }
.card-head > div::before { content: ''; float: right; width: var(--clear); height: var(--clear-down, 30px); }
#popup[data-view^="artist"] .back { margin-right: 32px; }
.popup-head .card-name { margin: 0; font-family: var(--display); font-weight: 900; font-size: var(--name-most, 28px); line-height: 0.95; letter-spacing: 0.02em; text-transform: uppercase; overflow-wrap: break-word; color: var(--ink); }
@supports (width: 1cqi) {
  .popup-head .card-name { font-size: max(12px, min(var(--name-most, 28px), (100cqi - var(--clear)) / var(--longest, 6) / 0.52)); }
}
/* Under .popup-head, or the heading's own `.popup-head p` outranks it. */
.popup-head .card-about { margin: 6px 0 0; color: var(--ink-soft); font-size: 13px; line-height: 1.3; }
/* The next New York shows: a gold ticket at the top of the card, each show's date over its venue, and
   its own way to tickets. Gold is the shop's color for what is on; the red dot is a recording light. */
.card-ticket { margin: 0 0 14px; padding: 8px 12px 4px; background: var(--gold); border: 2px solid var(--ink); border-radius: 3px; box-shadow: 3px 3px 0 var(--ink); }
.ticket-head { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; margin: 0 0 2px; }
.ticket-head span { display: inline-flex; align-items: center; gap: 6px; font-size: 10.5px; font-weight: 800; letter-spacing: 0.08em; text-transform: uppercase; }
.ticket-head span::before { content: ''; width: 7px; height: 7px; border-radius: 50%; background: var(--red); box-shadow: 0 0 0 1.5px var(--ink); }
.ticket-head small { font-size: 11px; }
.card-ticket ul { list-style: none; margin: 0; padding: 0; }
.card-ticket li { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: 10px; padding: 6px 0; }
/* Perforated, between two shows. */
.card-ticket li + li { border-top: 2px dashed var(--ink); }
.ticket-when { font-size: 13px; line-height: 1.25; }
.ticket-when b { display: block; font-family: var(--display); font-weight: 900; font-size: 18px; line-height: 1.05; letter-spacing: 0.03em; text-transform: uppercase; }
/* Its way to tickets is a round-ended sticker, as the card's other buttons are. */
.ticket-link { padding: 6px 12px; border: 2px solid var(--ink); border-radius: 999px; background: var(--ink); color: var(--sleeve); font-size: 11px; font-weight: 800; letter-spacing: 0.06em; text-decoration: none; text-transform: uppercase; white-space: nowrap; }
/* On gold the ring is ink, a little out from the ink button. */
.ticket-link:focus-visible { outline-offset: 3px; }
/* The staff pick: how they are tied to the city, handwritten on a gold card with a star, ink-edged
   and stuck on askew, as a record shop clips its picks to the shelf; the page it was read from beside it. */
.card-tie {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 8px; width: fit-content; max-width: 100%;
  margin: 2px 0 16px; padding: 6px 12px 6px 10px;
  background: var(--gold); border: 2px solid var(--ink); border-radius: 3px; box-shadow: 3px 3px 0 var(--ink);
  transform: rotate(-1.5deg); font-size: 11.5px;
}
.card-tie span { font-family: var(--marker); font-size: 19px; line-height: 1.05; color: var(--ink); }
.card-tie .card-tie-star { margin-right: -3px; font-family: var(--body); font-size: 13px; }
/* The facts as the back cover's track list: each a track, A1, A2 and B1 in red lettering (trackLabels,
   js/format.js), under a solid ink rule, with a dashed one between tracks. */
.card-facts { display: grid; margin: 0 0 16px; border-top: 2px solid var(--ink); }
.card-facts div { display: grid; grid-template-columns: 82px minmax(0, 1fr); gap: 8px; padding: 7px 0 6px; border-bottom: 1.5px dashed rgba(21, 17, 14, 0.3); }
.card-facts dt { display: flex; align-items: baseline; gap: 6px; padding-top: 1px; font-size: 11px; font-weight: 750; letter-spacing: 0.08em; text-transform: uppercase; }
.track { flex: none; width: 20px; font-family: var(--display); font-weight: 900; font-size: 15px; line-height: 1; letter-spacing: 0; color: var(--red-text); }
.card-facts dd { margin: 0; font-size: 13px; }
.card-place { padding: 0; border: 0; background: none; text-decoration: underline; text-underline-offset: 2px; cursor: pointer; }
.card-cite { color: inherit; font-weight: 700; white-space: nowrap; }
/* The listening station: the player set in a black plinth with round corners, ink-edged with a hard
   shadow. The player keeps the 152 px its layout is made for inside the plinth's edge. */
.card-body iframe { display: block; width: 100%; height: 166px; border: 7px solid var(--vinyl); border-radius: 20px; background: var(--vinyl); box-shadow: 0 0 0 2px var(--ink), 3px 3px 0 2px var(--ink); }
/* The bio reads as the liner notes: a little larger and more open than the facts above it. */
.card-bio { margin: 12px 0 0; font-size: 13.5px; line-height: 1.5; }
.card-bio:empty { display: none; }
/* Room for the eight lines a bio usually takes, while it is on its way. */
.card-bio.pending { display: block; min-height: 12em; }
/* A button is a hype sticker on the shrink-wrap: round-ended, red, ink-edged with a hard shadow. */
.card-link { display: inline-block; margin-top: 12px; padding: 8px 15px; border: 2px solid var(--ink); border-radius: 999px; background: var(--red); box-shadow: 3px 3px 0 var(--ink); color: var(--ink); font-size: 12px; font-weight: 750; letter-spacing: 0.05em; text-decoration: none; text-transform: uppercase; }
.card-source { margin: 12px 0 0; color: var(--ink-soft); font-size: 11px; }
.card-source a { color: inherit; }
/* The strip at the card's foot, under what scrolls and never over it, so in sight however far the card
   is scrolled (js/social.js): Share, a round-ended gold sticker, at one end, and at the other a round
   white sticker for each of the artist's own accounts, in its site's own glyph, in ink. As slim as the
   buttons allow: on a phone it is a second bar under the sheet. */
.card-strip { flex: none; display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 9px 16px 10px 18px; border-top: 3px solid var(--ink); background: var(--sleeve); }
.share-sticker {
  display: inline-flex; align-items: center; gap: 7px; height: 30px; padding: 0 13px 0 11px;
  border: 2px solid var(--ink); border-radius: 999px; background: var(--gold); box-shadow: 3px 3px 0 var(--ink); color: var(--ink);
  font-size: 12px; font-weight: 750; letter-spacing: 0.06em; line-height: 1; text-transform: uppercase; white-space: nowrap; cursor: pointer;
}
/* The arrow out of a box that phones draw for their share sheet. */
.share-glyph { flex: none; width: 13px; height: 13px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.socials { display: flex; gap: 8px; }
.social { display: grid; place-items: center; width: 30px; height: 30px; border: 2px solid var(--ink); border-radius: 50%; background: var(--sleeve); box-shadow: 2px 2px 0 var(--ink); color: var(--ink); }
.social-glyph { width: 15px; height: 15px; fill: currentColor; }
/* Where the panel is short, a phone's sheet or a phone held sideways, the strip is slimmer still, 46 px,
   the least it can be: its 3 px rule, the 30 px stickers, 7 px under them for a finger's 44 px, and 6 px
   over them, so that the focus ring stays clear of the rule. Even so it costs the player: on a sheet
   this short the card's own part is 74 to 120 px at 320 by 568 and 114 to 160 px at 360 by 640, less
   than the player's 166 px, which showed whole at 360 by 640 before the strip, and at 320 by 568 beside
   a name of one line (nor is it whole now beside a name of two lines at 375 by 667 or 360 by 740). Two
   pixels less would not bring it back. Only a taller sheet (app.js frames the map below it, SHEET), a
   smaller player, or a strip that scrolls away with the card would, and each changes what the owner
   chose, so each is his to decide: option c's mockup named this its weakest part, "cutting into the
   player and the list". */
@media (max-height: 430px), (max-width: 720px) and (max-height: 700px) { .card-strip { padding-top: 6px; padding-bottom: 7px; } }
/* An opened neighborhood's divider card: its borough and count, and the same Share at the end of the line,
   round and without its word, under the ×. The line runs on under the ×, whose column is clear that far
   down: beside a Share with its word, a genre's count ("Manhattan · 18 Folk & Country artists") wrapped
   at every width, and on a short phone's sheet (320 by 568) the taller heading cut the crate's first row.
   The sticker reaches a little above and below the line, which grows by 4 px. On Brooklyn's gold a gold
   sticker would be lost: it is white there, as the × is on every divider card. */
.place-line { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin: 4px -34px 0 0; }
.popup-head .place-line p { margin: 0; }
.place-line .share-sticker { justify-content: center; width: 30px; padding: 0; margin: -4px 0; box-shadow: 2px 2px 0 var(--ink); }
.place-line .share-word { display: none; }
.place-line .share-glyph { width: 14px; height: 14px; }
.divider.b-brooklyn .share-sticker { background: var(--sleeve); }
/* Where nothing could copy the address, it is shown in a field in Share's place, selected, until the focus
   leaves it (js/social.js, showAddress). On a card the accounts stay beside it, so that Tab goes on to
   them; on a divider card it has the line to itself. */
.share-address {
  flex: 1; min-width: 0; height: 30px; padding: 0 12px;
  border: 2px solid var(--ink); border-radius: 999px; background: #ffffff; box-shadow: 2px 2px 0 var(--ink);
  color: var(--ink); font: inherit; font-size: 13px; font-weight: 600;
}
.place-line:has(.share-address) p { display: none; }
/* Where the clipboard cannot be written directly, the address is selected out of sight and copied (js/social.js). */
.copy-field { position: fixed; top: 0; left: -9999px; white-space: pre; -webkit-user-select: text; user-select: text; }

/* Suggest a correction */
.fix-toggle { margin-top: 10px; padding: 0; border: 0; background: none; font-size: 12px; font-weight: 700; text-decoration: underline; text-underline-offset: 2px; cursor: pointer; }
/* Rounded a little, its fields too, as the card's corners are around the round-ended Send. */
.fix { display: grid; gap: 9px; margin-top: 10px; padding: 12px; border: 2px solid var(--ink); border-radius: 6px; background: #ffffff; }
.fix label { display: grid; gap: 4px; font-size: 11px; font-weight: 700; letter-spacing: 0.05em; text-transform: uppercase; }
.fix textarea, .fix input { width: 100%; padding: 7px 8px; border: 2px solid var(--ink); border-radius: 4px; background: #ffffff; color: var(--ink); font: inherit; font-size: 13px; font-weight: 400; letter-spacing: 0; text-transform: none; }
.fix textarea { resize: vertical; }
/* The browser's own grey read at 4.1:1 on the fields, short of the 4.5 small text needs. */
.fix ::placeholder { color: var(--ink-soft); opacity: 1; }
.fix-trap { position: absolute; left: -9999px; width: 1px !important; }
.fix-status { margin: 0; color: var(--ink-soft); font-size: 11.5px; }
.fix-status:empty { display: none; }
.fix-status.bad { color: var(--ink); font-weight: 700; }
.fix .card-link { margin-top: 0; justify-self: start; cursor: pointer; }
.fix .card-link:disabled { opacity: 0.5; cursor: default; }

/* ---------- Tooltip, credits, messages ---------- */

.tip { position: fixed; z-index: 20; max-width: 260px; padding: 6px 9px; background: var(--sleeve); border: 2px solid var(--ink); box-shadow: 3px 3px 0 var(--ink); font-size: 12px; pointer-events: none; }
.tip strong { display: block; font-size: 13px; }
.tip span { color: var(--ink-soft); }

/* The credits: one line, in full when the page opens, folded to the © square once the map is
   used, and opened again by pressing the square. The line used to stay across the bottom of
   the map for good, the last thing left lying on it. */
.credits { position: fixed; left: 22px; bottom: 12px; z-index: 5; display: flex; align-items: flex-end; max-width: calc(100vw - 44px); font-size: 11px; }
.credits-mark { position: relative; flex: none; width: 28px; height: 28px; padding: 0; border: 2px solid var(--ink); background: var(--sleeve); box-shadow: 2px 2px 0 var(--ink); font-size: 15px; font-weight: 700; line-height: 1; cursor: pointer; }
/* Open: the square is pressed in, gold, and the line runs on from it as one box. In ink it was
   lost on the black of the record. */
.credits-mark[aria-expanded="true"] { background: var(--gold); color: var(--ink); box-shadow: none; }
.credits p { min-height: 28px; margin: 0; padding: 5px 8px 4px; background: var(--sleeve); border: 2px solid var(--ink); border-left: 0; line-height: 1.35; }
.credits a { color: inherit; }
/* The credits and the list links lie over the map, black water or a bin color: an ink ring round a
   white band, as the map's own rings are. The white carries it on the black, the ink on all five
   colors. Gold with an ink edge, before, was lost on Brooklyn's gold. */
.credits :focus-visible, .lists :focus-visible { outline-color: var(--ink); box-shadow: 0 0 0 2px var(--sleeve); }
/* Beside the open panel, never under it: in a narrow window the line wraps instead. */
.popup-open .credits { max-width: calc(100vw - var(--popup) - 62px); }
/* The switch between the record and the street map where the bar's two rows have no room for it, on a
   phone held upright (further down): a square beside the ©, a picture of the other map with its name
   under it, as a map app's button for its layers is. The one control on the map, beside the one
   already there. Elsewhere the switch is the round button in the bar. */
.credits-street-map {
  display: none; position: relative; flex: none; width: 46px; height: 46px; margin-right: 6px; padding: 0; overflow: hidden;
  border: 2px solid var(--ink); border-radius: 3px; box-shadow: 2px 2px 0 var(--ink); cursor: pointer;
  /* The street map, small: paper, white streets, a blue river, a green park. */
  background:
    linear-gradient(118deg, transparent 0 62%, #A6CBE6 62.5%),
    radial-gradient(circle at 26% 30%, #CFE3B8 0 15%, transparent 16%),
    repeating-linear-gradient(28deg, transparent 0 7px, #FFFFFF 7px 9px),
    repeating-linear-gradient(-62deg, transparent 0 9px, #FFFFFF 9px 10.5px),
    #EFE9E1;
}
/* On the street map, the record: its grooves, the two wedges of light, the sign's red label. */
.streets-on .credits-street-map {
  background:
    radial-gradient(circle at 50% 50%, var(--vinyl) 0 4%, var(--red) 5% 20%, #0B0908 21% 23%, transparent 24%),
    conic-gradient(from 35deg at 50% 50%, transparent 0 7%, rgba(255, 253, 248, 0.22) 11%, transparent 15% 57%, rgba(255, 253, 248, 0.22) 61%, transparent 65%),
    repeating-radial-gradient(circle at 50% 50%, #1A1613 0 1px, #2C2622 1.4px 2.2px);
}
.credits-street-map span {
  position: absolute; right: 0; bottom: 0; left: 0; padding: 1px 0 2px;
  background: var(--ink); color: var(--sleeve); font-size: 8.5px; font-weight: 800; letter-spacing: 0.06em; line-height: 1.1; text-align: center; text-transform: uppercase;
}
.credits-street-map[aria-busy="true"] { opacity: 0.6; cursor: progress; }

/* In the middle of where the map will be, until its first names are drawn. */
.loading { position: fixed; inset: var(--bar) 0 0 0; z-index: 4; display: grid; place-items: center; margin: 0; font-family: var(--display); font-weight: 900; font-size: 26px; letter-spacing: 0.04em; text-transform: uppercase; color: var(--sleeve); pointer-events: none; }

/* Read out, never shown. */
.status, .visually-hidden { position: absolute; width: 1px; height: 1px; margin: 0; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
/* The map page's links to the lists (index.html), shown while the keyboard is on one so that a
   link never has the focus unseen: under the bar at the top left, and left of an open panel, so
   they cover neither, nor the credits at the bottom however far those run. The genres drop there
   too, but close as the focus leaves them. On a phone held upright the sheet takes the top, and
   they go to the bottom instead (further down). Above a notice too (z-index 30), which offers
   the same links itself. */
.lists:focus-within { position: fixed; top: calc(var(--bar) + 14px); left: 16px; z-index: 31; display: flex; flex-wrap: wrap; gap: 8px; width: auto; max-width: calc(100vw - 32px); height: auto; overflow: visible; clip-path: none; }
.popup-open .lists:focus-within { max-width: calc(100vw - var(--popup) - 62px); }
.lists a { color: inherit; text-decoration: none; }

.notice { position: fixed; inset: 0; z-index: 30; display: grid; place-items: center; padding: 24px; background: var(--sleeve); text-align: center; }
.notice a { color: inherit; text-underline-offset: 2px; }
.notice p { max-width: 420px; margin: 0; font-size: 16px; }

/* ---------- The questions page (faq.html) ---------- */

/* A plain page that scrolls, under the same bar as the map. */
body.page { overflow: auto; background: var(--sleeve); }
/* Whatever the page is scrolled to, a link the keyboard moves back to, a word found or an anchor,
   stops below the bar, its focus ring clear of it: brought to the top edge, a sleeve on a genre's page
   had its top third and the top of its ring under the bar. 64 px under a phone's bar (below). */
html:has(> body.page) { scroll-padding-top: 72px; }
.page .masthead { justify-content: space-between; }
.back-to-map { color: inherit; text-decoration: none; }
.faq { max-width: 640px; margin: 0 auto; padding: calc(56px + 34px) 20px 64px; }
.faq h1 { margin: 0 0 22px; font-family: var(--display); font-weight: 900; font-size: 50px; line-height: 0.95; letter-spacing: 0.02em; text-transform: uppercase; color: var(--ink); }
/* Its boxes are the pages' (pages.css): ink-edged with a hard shadow, their corners rounded a little, as the panel's are. */
.faq section { margin: 0 0 26px; padding: 16px 18px 4px; background: var(--sleeve); border: 3px solid var(--ink); border-radius: 6px; box-shadow: 5px 5px 0 var(--ink); }
/* A link to one answer (faq#ties) lands a little below the page's scroll padding, clear of the bar. */
.faq section[id] { scroll-margin-top: 8px; }
.faq h2 { margin: 0 0 8px; font-family: var(--display); font-weight: 900; font-size: 26px; line-height: 1; letter-spacing: 0.02em; text-transform: uppercase; color: var(--ink); }
.faq p { margin: 0 0 12px; font-size: 15px; line-height: 1.5; }
.faq a { color: inherit; text-underline-offset: 2px; }
@media (hover: hover) {
  .back-to-map:hover { background: var(--gold); }
  .faq a:hover { color: var(--red-text); }
}

/* The way to the questions page from the map: a button beside the zoom buttons, no words. */
.chip.ask { display: inline-grid; place-items: center; width: 30px; height: 30px; padding: 0; color: inherit; font-size: 14px; text-decoration: none; }
/* Pay what you want: the one gold thing on the sign that is not a pressed genre, as tall as the
   zoom buttons beside it. The heart says giving, where "Support" alone could be the help desk;
   red as small writing is on white, 3.6:1 on the gold. */
.chip.support { display: inline-flex; align-items: center; justify-content: center; gap: 6px; height: 30px; padding: 0 12px; background: var(--gold); color: var(--ink); text-decoration: none; }
.heart { flex: none; width: 13px; height: 12px; fill: var(--red-text); }
/* Not taking payments yet, but shown where it will be, in its own gold: a faded chip read as broken. */
.chip.support[aria-disabled="true"] { opacity: 1; cursor: default; }

/* ---------- Near me ---------- */

/* What is around a visitor who shares where they are (js/near.js, js/nearme.js): the mockup's B, a door
   in the bar beside Neighborhoods, gold, with the sign every map app gives "where I am": a ring with a
   red dot and its ticks. Its word turns to "Locating" while it waits for the browser's answer, in the
   same width, so nothing beside it moves. Open, it is pressed in, still gold. */
.locate { position: relative; flex: none; width: 15px; height: 15px; border: 2.4px solid currentColor; border-radius: 50%; }
.locate::before { content: ''; position: absolute; inset: 2.2px; border-radius: 50%; background: var(--red); box-shadow: 0 0 0 1.4px var(--ink); }
.locate::after { content: ''; position: absolute; left: 50%; top: -6px; bottom: -6px; width: 2.4px; margin-left: -1.2px; background: linear-gradient(currentColor 0 4px, transparent 4px calc(100% - 4px), currentColor calc(100% - 4px)); }
.chip.door.near, .masthead .chip.door.near[aria-expanded="true"] { background: var(--gold); color: var(--ink); }
.near-word { display: inline-grid; }
.near-word > span { grid-area: 1 / 1; }
.near-word > span + span, .asking .near-word > span:first-child { visibility: hidden; }
.asking .near-word > span + span { visibility: visible; }
/* Waiting: the sign beats, and its dot goes white, which says it still where motion is turned off. */
@keyframes locating { 50% { transform: scale(0.7); } }
.asking .locate { animation: locating 0.9s ease-in-out infinite; }
.asking .locate::before { background: var(--sleeve); }
/* Where the bar is short of room it is a gold square of the sign, its words read out (further down). */

/* The same, as a row under the search field of the list of neighborhoods, for anyone who opens the list
   first (the mockup's A): a gold pill the width of the field. */
.near-entry {
  display: flex; align-items: center; gap: 10px; width: calc(100% + 26px); height: 36px; margin: 10px -26px 0 0; padding: 0 14px;
  border: 2px solid var(--ink); border-radius: 999px; background: var(--gold); box-shadow: 2px 2px 0 var(--ink); color: var(--ink);
  font-size: 12.5px; font-weight: 800; letter-spacing: 0.08em; line-height: 1; text-transform: uppercase; white-space: nowrap; cursor: pointer;
}
.near-entry:focus-visible { outline-offset: 1px; }

/* The panel: where the visitor is, as an opened neighborhood is headed, its divider card in its borough's
   color; then tonight's shows, the week's, the artists' places and the neighborhood's crate, each in
   its bands of walking time. The kind of heading ("You are in") is in ink on the card's color. */
.popup-head.divider .kind { color: inherit; }
/* Near two neighborhoods, neither of which the city's outline backs: their names, smaller, as a line of the card. */
.popup-head.divider h2.near-two { font-size: 24px; line-height: 1; }
.near-here { position: relative; }
.near-here::before { content: ''; position: absolute; inset: 9px; border-radius: 50%; background: var(--gold); border: 2.5px solid var(--ink); }
.near-here::after { content: ''; position: absolute; left: 50%; top: 50%; width: 9px; height: 9px; margin: -4.5px 0 0 -4.5px; border-radius: 50%; background: var(--red); box-shadow: 0 0 0 1.5px var(--ink); }
.near-sec { padding: 0 0 4px; }
.near-sec h3 { margin: 14px 18px 0; font-family: var(--display); font-weight: 900; font-size: 19px; line-height: 1; letter-spacing: 0.03em; text-transform: uppercase; color: var(--red-text); }
/* A band: the ring's own dotted gold groove, small, and its minutes. */
/* A heading (h4) of the section's, set as a label. */
.near-band { display: flex; align-items: center; gap: 7px; margin: 9px 18px 0; font-size: 10.5px; font-weight: 800; letter-spacing: 0.08em; line-height: 1.2; text-transform: uppercase; }
.ring-key { flex: none; width: 13px; height: 13px; border: 3px dotted var(--gold); border-radius: 50%; box-shadow: 0 0 0 1.5px var(--ink), inset 0 0 0 1.5px var(--ink); }
.near-band.further { color: var(--ink-soft); }
.near-rows { padding: 0 0 2px; }
.near-rows .row { padding-top: 6px; padding-bottom: 6px; }
/* When, where and how far may take two lines, rather than lose the walk at their end. */
.near-rows small { white-space: normal; }
/* A show: what and when beside its Tickets, which is a link out, on Ticketmaster. */
.near-show { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: 6px; padding-right: 18px; }
.near-show > .row { padding-right: 0; }
.near-show > div.row { cursor: default; }
/* A listing's own name can run long ("Robert Glasper X Questlove + Special Guest Bilal"): two lines at most. */
.near-show > div.row b { display: -webkit-box; overflow: hidden; -webkit-box-orient: vertical; -webkit-line-clamp: 2; }
.near-show .ticket-link { padding: 5px 9px; font-size: 10.5px; }
/* A show with none of the map's artists on its bill: a small gold ticket, notched like the venue's on the map. */
.near-ticket {
  width: 40px; height: 26px; border: 2px solid var(--ink); background: var(--gold);
  -webkit-mask: radial-gradient(circle at 0 50%, transparent 5px, #000 5.5px) left / 51% 100% no-repeat, radial-gradient(circle at 100% 50%, transparent 5px, #000 5.5px) right / 51% 100% no-repeat;
          mask: radial-gradient(circle at 0 50%, transparent 5px, #000 5.5px) left / 51% 100% no-repeat, radial-gradient(circle at 100% 50%, transparent 5px, #000 5.5px) right / 51% 100% no-repeat;
}
/* An act on the map: the neighborhood they are tied to, on its borough's color, in handwriting. Tied to, never from. */
.near-tie { display: inline-block; margin-left: 7px; padding: 0 6px 1px; border: 1.5px solid var(--ink); border-radius: 999px; background: var(--hue); color: var(--on-hue); font-family: var(--marker); font-size: 13px; font-weight: 400; line-height: 1.15; letter-spacing: 0; white-space: nowrap; vertical-align: 1px; }
/* The kind of an artist's place, as the map's tags mark it: a square for a school, a dot for a development, a
   bar for a street, and for a home a roof. */
.near-kind { display: inline-block; width: 7px; height: 7px; margin: 0 6px 1px 0; background: var(--ink); vertical-align: middle; }
.near-kind.project { border-radius: 50%; }
.near-kind.street { width: 9px; height: 3px; }
.near-kind.home { width: 9px; height: 8px; clip-path: polygon(50% 0, 100% 45%, 85% 45%, 85% 100%, 15% 100%, 15% 45%, 0 45%); }
/* A music spot is a place, so round: its kind's glyph on a white sticker, as on its sign. */
.near-disc { display: grid; place-items: center; width: 40px; height: 40px; border: 2px solid var(--ink); border-radius: 50%; background: var(--sleeve); box-shadow: 2px 2px 0 var(--ink); transform: rotate(-6deg); }
.near-disc .emblem-holder { width: 28px; height: 28px; }
.near-more { display: block; margin: 0 18px 4px; padding: 6px 0; border: 0; background: none; font-size: 12px; font-weight: 750; text-decoration: underline; text-underline-offset: 2px; cursor: pointer; }
.near-source { margin: 10px 18px 2px; }
.near-crate .crate { padding-top: 14px; }
.popup-head .near-note { color: var(--ink); font-size: 14px; }
.near-actions { display: flex; flex-wrap: wrap; gap: 10px 12px; padding: 16px 18px 20px; }
.near-actions .card-link { display: inline-flex; align-items: center; gap: 8px; margin: 0; cursor: pointer; }
.near-again { background: var(--gold); }

/* My block (js/myblock.js, js/block.js): at the end of Near me's first line, "You are in", short of the ×,
   a gold sticker with the share sheet's arrow and its name, as Share is on a card, and like a divider card's
   Share white on Brooklyn's gold. At the end of the count's line it wrapped a genre's count ("Manhattan · 18
   Folk & Country artists") onto two lines at every width. It reaches above and below the handwriting, and
   the name under it stands a little lower to keep clear of it. Pressed, its preview: the post and the story
   side by side on a white sleeve over the dimmed page, each with its own Share on a phone or Save image on
   a laptop, Copy link under them on a laptop. Where the panel is a sheet it rises from the foot of the screen. */
.near-kicker { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.popup-head .near-kicker .kind { margin: 0; }
.near-kicker .block-sticker { flex: none; margin: -6px 6px -6px 0; }
.near-kicker:has(.block-sticker) + .place-title { margin-top: 9px; }
/* As wide as the two images, which are as large as the window allows. */
.block-preview {
  width: fit-content; max-width: calc(100% - 32px); max-height: calc(100% - 32px); padding: 0; border: 0;
  background: none; color: var(--ink); overflow: visible;
}
.block-preview::backdrop { background: rgba(21, 17, 14, 0.62); }
.block-box { position: relative; max-height: calc(100dvh - 32px); overflow: auto; padding: 18px 20px 20px; border: 4px solid var(--ink); background: var(--sleeve); box-shadow: 8px 8px 0 var(--ink); }
.block-box h2 { margin: 0 44px 12px 0; font-family: var(--marker); font-size: 24px; font-weight: 400; line-height: 1.1; color: var(--red-text); }
/* As large as the window allows, up to 400 px tall: the post that tall, the story 9 by 16 beside it. */
.block-images {
  --tall: min(400px, calc(100dvh - 216px), calc((min(760px, 100vw - 32px) - 66px) / 1.5625));
  display: flex; align-items: flex-start; gap: 18px;
}
.block-images figure { margin: 0; }
.block-frame { display: block; border: 3px solid var(--ink); background: var(--vinyl); box-shadow: 4px 4px 0 var(--ink); }
.block-post .block-frame { width: var(--tall); height: var(--tall); }
.block-story .block-frame { width: calc(var(--tall) * 9 / 16); height: var(--tall); }
.block-frame img { display: block; width: 100%; height: 100%; }
.block-images figcaption { display: flex; flex-direction: column; align-items: flex-start; gap: 7px; margin-top: 10px; font-size: 11px; font-weight: 800; letter-spacing: 0.08em; line-height: 1.2; text-transform: uppercase; color: var(--ink-soft); }
/* No wider than its image: at 280 px "Save image" ran 13 px off the screen beside the story. */
.block-go { max-width: 100%; margin: 0; background: var(--gold); cursor: pointer; }
.block-go[aria-disabled="true"] { opacity: 0.45; cursor: progress; }
.block-foot { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 16px; margin: 14px 0 0; }
.block-foot:not(:has(button)):has(.block-status:empty) { margin: 0; }
.block-copy { padding: 0; border: 0; background: none; font-size: 12px; font-weight: 700; text-decoration: underline; text-underline-offset: 2px; cursor: pointer; }
.block-foot .share-address { flex: 0 1 340px; }
.block-status { font-size: 12.5px; font-weight: 700; }
@media (max-width: 720px) and (min-height: 431px), (max-width: 620px) {
  .block-preview { width: 100%; max-width: none; max-height: calc(100% - 16px); margin: auto 0 0; }
  .block-box { max-height: calc(100dvh - 16px); padding: 14px 14px max(18px, env(safe-area-inset-bottom)); border-width: 4px 0 0; box-shadow: none; }
  .block-box h2 { margin-bottom: 10px; }
  .block-images { --tall: min(400px, calc(100dvh - 160px), calc((100vw - 40px) / 1.5625)); gap: 12px; }
}

/* On the map: the visitor as the gold label of a record with a red dot in it, and round them dotted gold
   grooves at 5, 10 and 15 minutes' walk, under the names and faces, each with its minutes on a white tag. */
.near-layer { position: absolute; left: 0; top: 0; overflow: hidden; pointer-events: none; }
.near-layer > svg { position: absolute; inset: 0; width: 100%; height: 100%; }
.near-top > * { position: absolute; left: 0; top: 0; }
.near-you { width: 0; height: 0; }
.near-you::before { content: ''; position: absolute; left: -15px; top: -15px; width: 30px; height: 30px; border-radius: 50%; background: radial-gradient(circle closest-side, var(--gold) 0 82%, var(--ink) 83% 88%, var(--gold) 89%); border: 3px solid var(--ink); box-shadow: 2px 2px 0 var(--ink); }
.near-you::after { content: ''; position: absolute; left: -5px; top: -5px; width: 10px; height: 10px; border-radius: 50%; background: var(--red); box-shadow: 0 0 0 2px var(--ink); }
.near-ring-fill { fill: rgba(255, 253, 248, 0.12); }
.near-ring-casing { fill: none; stroke: var(--ink); stroke-width: 7; stroke-dasharray: 0 10; stroke-linecap: round; }
.near-ring { fill: none; stroke: var(--gold); stroke-width: 4; stroke-dasharray: 0 10; stroke-linecap: round; }
.near-ring-label {
  padding: 2px 6px 1px; border: 2px solid var(--ink); background: var(--sleeve); box-shadow: 2px 2px 0 var(--ink); color: var(--ink);
  font-size: 10px; font-weight: 800; letter-spacing: 0.08em; line-height: 1.2; text-transform: uppercase; white-space: nowrap;
}

/* ---------- Music spots: street signs (js/spots.js, js/signs.js, js/spotpanel.js) ---------- */

/* The owner's pick of the music spots mockups, "I like A" (`mockups/spots`, Option A). Each spot a street
   sign on its own post, in the shop's black and white: a blade of sleeve white with an ink edge and a
   hard shadow, the short name lettered in Londrina, the year in an ink box, the glyph on a round white
   sticker standing proud of its left end. Never a borough's color: a glyph takes nothing from the land. */
.spot-glyph { color: var(--ink); }

/* The posts, behind the sleeves and the neighborhoods: ink, from a white dot in an ink ring at the point. */
.overlay .sign-posts { position: absolute; inset: 0; width: 100%; height: 100%; }
.sign-post line { stroke: var(--ink); stroke-linecap: round; }
.sign-post circle { fill: var(--sleeve); stroke: var(--ink); stroke-width: 2; }
.sign-corners { position: absolute; inset: 0; }
/* A corner: its blades hung one under another on the post, oldest at the top (js/spots.js, BLADE). On a
   phone the whole corner is drawn at full size and scaled to four fifths, as the layout measures it. */
.sign-corner { position: absolute; left: 0; top: 0; display: flex; flex-direction: column; gap: 3px; padding-left: 13px; transform-origin: 0 0; will-change: transform; }
.sign-corner[data-align="left"] { align-items: flex-end; }
.sign-corner[data-align="center"] { align-items: center; }
.sign-corner[data-align="right"] { align-items: flex-start; }
.overlay .sign-corner .sign-blade {
  position: relative; display: flex; align-items: center; flex: none; height: 20px; padding: 0 4px 0 20px;
  border: 2px solid var(--ink); background: var(--sleeve); color: var(--ink); box-shadow: 2px 2px 0 var(--ink);
  font-family: var(--display); font-weight: 900; font-size: 12px; letter-spacing: 0.04em; line-height: 1; text-transform: uppercase; white-space: nowrap;
  transform: rotate(var(--tilt, 0deg));
}
/* The ▶ stands 11 px past the blade's end with its ring and shadow: a margin keeps that in the corner's
   width, which the layout keeps on the screen (js/signs.js, PLAY_OUT). */
.overlay .sign-corner .sign-blade:has(.blade-play) { padding-right: 14px; margin-right: 11px; }
/* The glyph on its round white sticker, slapped on askew. */
.blade-sticker, .corner-sticker, .place-sign .sign-sticker, .spot-sign .sign-sticker {
  display: grid; place-items: center; border: 2px solid var(--ink); border-radius: 50%; background: var(--sleeve); box-shadow: 1.5px 1.5px 0 var(--ink); transform: rotate(-6deg);
}
.blade-sticker { position: absolute; left: -15px; top: 50%; width: 30px; height: 30px; margin-top: -15px; }
.blade-sticker .emblem-holder, .corner-sticker .emblem-holder { width: 21px; height: 21px; }
/* Four fifths on a phone would leave the glyph at 17 px: the sticker is drawn a little larger, to read at 26. */
.sign-corner.narrow .blade-sticker { left: -17px; width: 32.5px; height: 32.5px; margin-top: -16.25px; }
.sign-corner.narrow .blade-sticker .emblem-holder { width: 23px; height: 23px; }
/* Dated history, never "here now": the year where a tag has its count. */
.blade-year { margin-left: 6px; padding: 2px 4px 1px; background: var(--ink); color: var(--sleeve); font-size: 11.5px; letter-spacing: 0.03em; }
/* Footage: a vinyl-black ▶ sticker at the right end. Red would vanish on Manhattan, and gold says "tonight". */
.blade-play {
  position: absolute; right: -11px; top: 50%; display: grid; place-items: center; width: 20px; height: 20px; margin-top: -10px; padding-left: 2px;
  border-radius: 50%; background: var(--vinyl); color: var(--sleeve); box-shadow: 0 0 0 2px var(--ink), 1.5px 1.5px 0 2px var(--ink); font-family: var(--body); font-size: 8.5px;
}
.overlay .sign-corner .sign-blade.more { padding: 0 7px; }
/* A school's, development's or street's tag, hung on a spot's post: its own marker and count. */
.overlay .sign-corner .sign-blade.tag { gap: 5px; padding: 0 6px 0 4px; font-family: var(--body); font-size: 9.5px; font-weight: 700; letter-spacing: 0.07em; }
.blade-marker, .sign-marker { flex: none; width: 7px; height: 7px; background: var(--ink); }
.k-project > .blade-marker, .k-project > .sign-marker { border-radius: 50%; }
.k-street > .blade-marker, .k-street > .sign-marker { width: 9px; height: 3px; }
.blade-count { padding: 0 4px; background: var(--ink); color: var(--sleeve); }
/* Lit: the open spot, and the open card's artist's: an ink blade with white letters and a white year box. */
.overlay .sign-corner .sign-blade.lit { z-index: 1; background: var(--ink); color: var(--sleeve); }
.sign-blade.lit .blade-year { background: var(--sleeve); color: var(--ink); }
/* The small form: the stickers alone, fanned on a stub of post, no name. */
.sign-corner.small { display: block; height: 30px; padding: 0; }
.overlay .corner-sticker { position: absolute; top: 0; width: 30px; height: 30px; }
.overlay .corner-sticker.lit { box-shadow: 0 0 0 2px var(--sleeve), 0 0 0 4px var(--ink); }
/* A small corner's "+N": its count on the last sticker, which is filed behind the others with only its
   right end showing (js/spots.js, SMALL.more): the count is set there, so that it can be read. */
.overlay .corner-sticker.more { justify-items: end; padding: 0 3px 0 0; font-family: var(--display); font-weight: 900; font-size: 11px; line-height: 1; letter-spacing: -0.02em; color: var(--ink); }

/* The spot's view: its heading sleeve white, as a landmark's, with its sign full width under its kind. */
.popup-head.sign-head { padding-bottom: 16px; }
.spot-sign {
  position: relative; display: flex; margin: 8px 0 0 20px; padding: 9px 12px 10px 38px;
  border: 3px solid var(--ink); background: var(--sleeve); box-shadow: 4px 4px 0 var(--ink); transform: rotate(-1deg);
}
.spot-sign .sign-sticker { position: absolute; left: -24px; top: 50%; width: 52px; height: 52px; margin-top: -26px; border-width: 2.5px; box-shadow: 2px 2px 0 var(--ink); }
.spot-sign .sign-sticker .emblem-holder { width: 36px; height: 36px; }
.sign-words { flex: 1; min-width: 0; container-type: inline-size; }
/* The full name, wrapping between words, lettered smaller only when its longest word must be. */
.popup-head .spot-sign h2 { font-size: 30px; line-height: 0.95; overflow-wrap: break-word; }
@supports (width: 1cqi) {
  .popup-head .spot-sign h2 { font-size: max(14px, min(30px, 100cqi / var(--longest, 6) / 0.52)); }
}
.sign-year { display: inline-block; margin-top: 7px; padding: 2px 6px 1px; background: var(--ink); color: var(--sleeve); font-family: var(--display); font-weight: 900; font-size: 15px; letter-spacing: 0.04em; }
/* Its note in full, at a bio's size, never cut, since its last words name its source; then its sources,
   small, with no label; then Watch for footage; then its people's sleeves. */
.spot-body { padding: 14px 18px 16px; border-bottom: 2px solid var(--ink); }
.spot-note { margin: 0; font-size: 13.5px; line-height: 1.5; }
.spot-sources { margin: 9px 0 0; color: var(--ink-soft); font-size: 11px; line-height: 1.6; }
.spot-sources a { color: inherit; font-weight: 700; white-space: nowrap; text-underline-offset: 2px; }
.spot-watch { display: inline-flex; align-items: center; gap: 7px; }
.spot-watch b { font-size: 10px; line-height: 1; }

/* A place as a small sign, in a card's Places row and at the front of a crate: the sticker and the short name. */
.place-signs { display: flex; flex-wrap: wrap; gap: 9px 8px; margin: 0; padding: 2px 0 2px 11px; list-style: none; }
.place-signs li { display: flex; min-width: 0; }
.place-sign {
  position: relative; display: inline-flex; align-items: center; min-width: 0; height: 22px; padding: 0 7px 0 19px;
  border: 2px solid var(--ink); background: var(--sleeve); color: var(--ink); box-shadow: 2px 2px 0 var(--ink);
  font-family: var(--display); font-weight: 900; font-size: 11.5px; letter-spacing: 0.04em; line-height: 1; text-transform: uppercase; white-space: nowrap; cursor: pointer;
}
.place-sign .sign-text { overflow: hidden; text-overflow: ellipsis; }
.place-sign .sign-sticker { position: absolute; left: -11px; top: 50%; width: 26px; height: 26px; margin-top: -13px; }
.place-sign .sign-sticker .emblem-holder { width: 18px; height: 18px; }
.place-sign.other { gap: 5px; padding: 0 7px 0 6px; margin-left: -11px; font-family: var(--body); font-size: 9.5px; font-weight: 700; letter-spacing: 0.07em; }
.place-sign.more { padding: 0 8px; margin-left: -11px; }
.place-sign:focus-visible { outline-offset: 3px; }
/* In a card's narrow column a long name wraps onto a second line rather than lose its end. */
.card-signs .place-sign { height: auto; min-height: 22px; padding-top: 3px; padding-bottom: 2px; line-height: 1.05; text-align: left; white-space: normal; }
.card-signs .place-sign .sign-text { overflow: visible; }
.card-facts dd.places-row { margin: 1px 0 2px; }
/* At the front of the crate, under the divider card, the track list's dashed rule between them and the sleeves. */
.crate-signs { padding: 16px 16px 14px 18px; border-bottom: 1.5px dashed rgba(21, 17, 14, 0.3); }
@media (hover: hover) {
  .sign-corner:hover { z-index: 3; }
  .overlay .sign-corner .sign-blade:not(.lit):hover, .overlay .corner-sticker:hover { background: var(--gold); }
  .place-sign:hover { background: var(--gold-soft); }
}

/* On a phone the sheet's sign is smaller, its name 26 px, the year riding on the name's line where it
   fits; the crate's signs go two to a line. Under 360 px the sign is lettered smaller still, so that the
   heading is no taller than a neighborhood's: at 320 px it left Harlem World's note 113 px of the sheet. */
@media (max-width: 720px) and (min-height: 431px), (max-width: 620px) {
  .popup-head.sign-head { padding-bottom: 12px; }
  .spot-sign { margin: 6px 0 0 18px; padding: 7px 10px 8px 30px; }
  .spot-sign .sign-sticker { left: -20px; width: 44px; height: 44px; margin-top: -22px; }
  .spot-sign .sign-sticker .emblem-holder { width: 30px; height: 30px; }
  .spot-sign .sign-words { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 8px; }
  .popup-head .spot-sign h2 { flex: 0 1 auto; font-size: 26px; }
  @supports (width: 1cqi) { .popup-head .spot-sign h2 { font-size: max(13px, min(26px, 100cqi / var(--longest, 6) / 0.52)); } }
  .sign-year { margin-top: 0; font-size: 13px; }
  .spot-body { padding: 12px 14px 14px; }
  .crate-signs { padding: 14px 14px 12px 16px; }
  .crate-list { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 9px 18px; }
  .crate-list .place-sign { font-size: 10.5px; }
}
@media (max-width: 359px) {
  .popup-head.sign-head { padding-bottom: 9px; }
  .spot-sign { margin: 4px 0 0 16px; padding: 5px 8px 5px 26px; box-shadow: 3px 3px 0 var(--ink); }
  .popup-head .spot-sign h2 { font-size: 19px; }
  @supports (width: 1cqi) { .popup-head .spot-sign h2 { font-size: max(12px, min(19px, 100cqi / var(--longest, 6) / 0.52)); } }
  .spot-sign .sign-sticker { left: -16px; width: 34px; height: 34px; margin-top: -17px; }
  .spot-sign .sign-sticker .emblem-holder { width: 23px; height: 23px; }
  .sign-year { font-size: 12px; }
  /* Two to a line in a column 100 px wide, a long name wraps as it does in a card's narrow column, rather
     than lose its end: "“A Great Day in Harl…" and "Harlem Cultural Fe…" were cut mid-word. */
  .crate-list .place-sign { height: auto; min-height: 22px; padding-top: 3px; padding-bottom: 2px; line-height: 1.05; text-align: left; white-space: normal; }
  .crate-list .place-sign .sign-text { overflow: visible; }
}
/* A window 430 px tall or less, a phone held sideways: the sign smaller still, its year on the name's line.
   At full size it took 200 px of the 265 px panel at 740 by 360, and the note under it was out of sight. */
@media (max-height: 430px) {
  .popup-head.sign-head { padding-top: 10px; padding-bottom: 10px; }
  .popup-head.sign-head .kind { font-size: 15px; }
  .spot-sign { margin: 4px 0 0 18px; padding: 5px 10px 6px 28px; box-shadow: 3px 3px 0 var(--ink); }
  .spot-sign .sign-sticker { left: -18px; width: 38px; height: 38px; margin-top: -19px; }
  .spot-sign .sign-sticker .emblem-holder { width: 26px; height: 26px; }
  .spot-sign .sign-words { display: flex; flex-wrap: wrap; align-items: center; gap: 3px 8px; }
  .popup-head .spot-sign h2 { flex: 0 1 auto; font-size: 22px; }
  @supports (width: 1cqi) { .popup-head .spot-sign h2 { font-size: max(12px, min(22px, 100cqi / var(--longest, 6) / 0.52)); } }
  .sign-year { margin-top: 0; font-size: 12px; }
  .spot-body { padding: 10px 14px 12px; }
}

/* ---------- Phones ---------- */

@media (max-width: 720px) {
  :root { --bar: 50px; }
  .masthead { gap: 10px; height: 50px; padding: 0 9px; }
  html:has(> body.page) { scroll-padding-top: 64px; }
  .title-card::before { width: 30px; height: 30px; }
  .title-card h1, .title-card .h1 { font-size: 21px; }
  .tagline { font-size: 13px; }
  .chip { padding: 9px 10px; }
  .popup-head { padding: 12px 44px 10px 14px; }
  .popup-head h2 { font-size: 30px; }
  /* 16 px: a phone zooms the whole page in on a field with smaller type. */
  .find { margin-right: -30px; }
  .find input { height: 40px; font-size: 16px; }
  .share-address { font-size: 16px; }
  .row { padding: 10px 14px; }
  .near-sec h3, .near-band, .near-more, .near-source { margin-left: 14px; margin-right: 14px; }
  .near-show { padding-right: 14px; }
  .near-actions { padding: 14px 14px 18px; }
  .near-entry { width: calc(100% + 30px); height: 40px; margin-right: -30px; }
  .card-head { --name-most: 32px; }
  /* The credits keep the wide screen's 11 px: at 9.5 px they were hard to read. They wrap
     here, so their lines are a little further apart. */
  .credits { left: 8px; bottom: 6px; max-width: calc(100vw - 16px); }
  .credits p { line-height: 1.45; }
}
@keyframes drop { from { transform: translateY(-100%); } }
/* Where the bar is short of room, This week is a square of its dot and count, its words read out: in
   one row beside the zoom buttons, and on a phone at the head of the second row. With Support beside
   them as well it is a square up to 1180 px: at 1024 its words left Genres no room for its own. */
@media (max-width: 900px) {
  .chip.week { gap: 6px; padding: 0 10px; }
  .chip.week .week-label { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
  .chip.week .caret { display: none; }
}
@media (min-width: 901px) and (max-width: 1180px) {
  /* The sign's tagline goes under its name, as it does under 900 px, to make room for This week. */
  .masthead:has(.week-drop:not([hidden])) .title-card { display: grid; grid-template-columns: auto auto; column-gap: 9px; row-gap: 0; }
  .masthead:has(.week-drop:not([hidden])) .title-card::before { grid-row: span 2; }
  .masthead:has(.week-drop:not([hidden])) .title-card h1 { padding-top: 3px; line-height: 0.95; }
  .masthead:has(.support:not([hidden])) .chip.week { gap: 6px; padding: 0 10px; }
  .masthead:has(.support:not([hidden])) .chip.week .week-label { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
  .masthead:has(.support:not([hidden])) .chip.week .caret { display: none; }
}
/* Near me: where one row is short of room, as it is beside This week's words, a gold square of the sign, its words
   read out; on a phone held upright, in the second row (further down). */
@media (max-width: 1180px) {
  .masthead .chip.near { width: 38px; padding: 0; gap: 0; }
  .masthead .chip.near .near-word { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
}
/* Just over 900 px the street map's switch leaves Genres short of its name: the tagline goes under the
   sign's name without This week too. */
@media (min-width: 901px) and (max-width: 960px) {
  .masthead:has(.street-map:not([hidden])) .title-card { display: grid; grid-template-columns: auto auto; column-gap: 9px; row-gap: 0; }
  .masthead:has(.street-map:not([hidden])) .title-card::before { grid-row: span 2; }
  .masthead:has(.street-map:not([hidden])) .title-card h1 { padding-top: 3px; line-height: 0.95; }
}
/* With This week as well, up to 1000 px the bar closes up and the two doors a little, so that a long
   genre such as Folk & Country has the room beside the switch that it had without it; and just over
   1180 px, where This week has its words again, the bar closes up a little. */
@media (min-width: 901px) and (max-width: 1000px) {
  .masthead:has(.week-drop:not([hidden])) { gap: 10px; }
  .masthead:has(.week-drop:not([hidden])) .chip.door { padding: 0 12px; }
}
@media (min-width: 1181px) and (max-width: 1240px) { .masthead:has(.week-drop:not([hidden])) { gap: 13px; } }
/* Where one row is short of room, the sign's tagline goes under its name, the record beside both.
   Beside it, the bar's one row needs 780 px, and some 850 with a genre such as Folk & Country on. */
@media (max-width: 900px) {
  .title-card { display: grid; grid-template-columns: auto auto; column-gap: 9px; row-gap: 0; }
  .title-card::before { grid-row: span 2; }
  .title-card h1, .title-card .h1 { padding-top: 3px; line-height: 0.95; }
  /* Support is a round gold heart, its word read out but not shown: the word's 74 px came out of
     the Genres button, which lost its own name to an ellipsis at 800 px. */
  .masthead .chip.support { width: 30px; padding: 0; border-radius: 50%; }
  .support-word { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
}
/* Under 360 px the sign is smaller, and at 306 px and less it leaves off its record. Full size it is
   173 px wide: on a phone 320 px wide it pushed its half of the map's bar wider than the other, so
   the zoom buttons touched it and Neighborhoods lost its caret off the screen; at 280 px the minus
   lay over the ?, and a page's bar was wider than the screen. From 301 to 306 px, with the record, the
   sign touched the plus in a window with a mouse. */
@media (max-width: 359px) {
  .title-card { column-gap: 7px; }
  .title-card::before { width: 24px; height: 24px; }
  .title-card h1, .title-card .h1 { font-size: 19px; }
  .tagline { font-size: 12px; }
  /* The card's sleeve is smaller, to leave its name the room for "Xaviersobased" on a line. */
  .card-head .sleeve { width: 76px; height: 76px; --side: 76px; }
  .card-head > div { margin-left: 33px; }
}
@media (max-width: 306px) {
  .title-card { grid-template-columns: auto; }
  .title-card::before { display: none; }
}
/* In one row under 900 px the heart's room comes out of the gaps, and on a phone held sideways out
   of the two buttons' padding as well, rather than out of the name Genres. */
@media (min-width: 721px) and (max-width: 900px) { .masthead:has(.support:not([hidden])) { gap: 12px; } }
/* With This week as well, the bar and the two doors close up, so that Genres keeps its name beside the
   street map's switch, and a long genre as much of it as it had without the switch. */
@media (min-width: 821px) and (max-width: 900px) {
  .masthead:has(.week-drop:not([hidden])) { gap: 8px; }
  .masthead:has(.week-drop:not([hidden])) .chip.door { padding: 0 10px; }
}
@media (min-width: 621px) and (max-width: 720px) and (max-height: 430px) { .masthead:has(.support:not([hidden])) .chip.door { padding: 0 10px; } }
/* So does This week's square, held sideways: the two doors close up, and Neighborhoods leaves off its
   magnifier, so that Genres keeps its name. */
@media (min-width: 621px) and (max-width: 720px) and (max-height: 430px) {
  .masthead:has(.week-drop:not([hidden])) .chip.door { padding: 0 10px; }
  .masthead:has(.week-drop:not([hidden])) .hoods .glass { display: none; }
  /* And with Support too, the sign leaves off its record, as it does at 300 px. */
  .masthead:has(.week-drop:not([hidden])):has(.support:not([hidden])) .title-card { grid-template-columns: auto; }
  .masthead:has(.week-drop:not([hidden])):has(.support:not([hidden])) .title-card::before { display: none; }
}
/* In one row just over 720 px, the street map's switch leaves Genres short of room too: the bar closes
   up, and Neighborhoods leaves off its magnifier; with This week and Support as well, the doors' words
   are the size they are in a phone's second row, and the sign leaves off its record. */
@media (min-width: 721px) and (max-width: 820px) {
  .masthead:has(.street-map:not([hidden])) { gap: 10px; }
  .masthead:has(.street-map:not([hidden])) .chip.door { padding: 0 10px; }
  .masthead:has(.street-map:not([hidden])) .hoods .glass { display: none; }
  .masthead:has(.week-drop:not([hidden])):has(.support:not([hidden])) { gap: 6px; }
  .masthead:has(.week-drop:not([hidden])):has(.support:not([hidden])) .chip.door { padding: 0 8px; font-size: 12px; letter-spacing: 0.06em; }
  .masthead:has(.week-drop:not([hidden])):has(.support:not([hidden])) .title-card { grid-template-columns: auto; }
  .masthead:has(.week-drop:not([hidden])):has(.support:not([hidden])) .title-card::before { display: none; }
}
/* Under 660 px that is still not enough, and Neighborhoods leaves off its magnifier, as it does at 300 px. */
@media (min-width: 621px) and (max-width: 660px) and (max-height: 430px) { .masthead:has(.support:not([hidden])) .hoods .glass { display: none; } }
/* With the street map's switch in that row as well, everything in it closes up: the doors' words are
   the size they are in a phone's second row, Neighborhoods leaves off its magnifier, and the gaps are 4 px. */
@media (min-width: 621px) and (max-width: 720px) and (max-height: 430px) {
  .masthead:has(.street-map:not([hidden])) { gap: 4px; }
  .masthead:has(.street-map:not([hidden])) .chip.door { font-size: 12px; letter-spacing: 0.06em; }
  .masthead:has(.street-map:not([hidden])) .hoods .glass { display: none; }
}

/* Near me in one row, as a gold square (further up), takes room that a long genre named in Genres was
   using: so while a genre is named, and only then, the bar closes up to give it back, Neighborhoods leaves
   off its magnifier, as it does at 300 px, and in the narrowest one-row bars the doors close up and their
   words are a size smaller. Measured at every width from 280 to 1440 px with Folk & Country, the longest. */
@media (min-width: 1181px) and (max-width: 1340px) {
  /* Beside This week's words it is a square here too. */
  .masthead:has(.week-drop:not([hidden])) .chip.near { width: 38px; padding: 0; gap: 0; }
  .masthead:has(.week-drop:not([hidden])) .chip.near .near-word { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
  .masthead:has(.week-drop:not([hidden])):has(#genre.on) { gap: 10px; }
  .masthead:has(.week-drop:not([hidden])):has(#genre.on) .hoods .glass { display: none; }
}
@media (min-width: 621px) and (max-width: 1180px) { .masthead:has(#genre.on) .hoods .glass { display: none; } }
@media (min-width: 1001px) and (max-width: 1180px) { .masthead:has(#genre.on) { gap: 11px; } }
/* Up to 1000 px the sign's tagline goes under its name, as it does up to 960 px: Genres was short of room. */
@media (min-width: 961px) and (max-width: 1000px) {
  .masthead:has(#near) .title-card { display: grid; grid-template-columns: auto auto; column-gap: 9px; row-gap: 0; }
  .masthead:has(#near) .title-card::before { grid-row: span 2; }
  .masthead:has(#near) .title-card h1 { padding-top: 3px; line-height: 0.95; }
}
@media (min-width: 901px) and (max-width: 960px) { .masthead:has(#near) { gap: 15px; } }
@media (min-width: 901px) and (max-width: 1000px) {
  /* Beside This week the bar and its doors close up whatever the genre: "Genres" itself was short of room. */
  .masthead:has(#near):has(.week-drop:not([hidden])) { gap: 7px; }
  .masthead:has(#near):has(.week-drop:not([hidden])) .chip.door { padding: 0 10px; }
  .masthead:has(#genre.on) { gap: 11px; }
  .masthead:has(.week-drop:not([hidden])):has(#genre.on) { gap: 6px; }
}
@media (min-width: 821px) and (max-width: 900px) {
  .masthead:has(#near):has(.week-drop:not([hidden])) { gap: 7px; }
  .masthead:has(#genre.on) { gap: 8px; }
  .masthead:has(.week-drop:not([hidden])):has(#genre.on) { gap: 5px; }
}
@media (min-width: 721px) and (max-width: 820px) {
  .masthead:has(#near) { gap: 6px; }
  .masthead:has(#genre.on) { gap: 6px; }
  .masthead:has(.week-drop:not([hidden])):has(#genre.on) { gap: 4px; }
}
/* In the narrowest one-row bars, a phone held sideways, the square is narrower, the bar and its doors close
   up whatever the genre, and This week's square leaves off its dot, as it does at 300 px. */
@media (min-width: 721px) and (max-width: 820px), (min-width: 621px) and (max-width: 720px) and (max-height: 430px) {
  .masthead:has(#near) .chip.near { width: 30px; }
}
@media (min-width: 621px) and (max-width: 640px) and (max-height: 430px) { .masthead:has(#near) .chip.near { width: 27px; } }
@media (min-width: 621px) and (max-width: 720px) and (max-height: 430px) {
  .masthead:has(#near) { gap: 2px; }
  .masthead:has(#near) .chip.door { padding: 0 8px; }
  .masthead:has(#near) .chip.week::before { display: none; }
}
@media (min-width: 721px) and (max-width: 820px), (min-width: 621px) and (max-width: 720px) and (max-height: 430px) {
  .masthead:has(#genre.on) :is(#genre, .chip.hoods) { padding: 0 6px; }
  .masthead:has(#genre.on) .chip.door.week { padding: 0 6px; }
  .masthead:has(#genre.on) .chip.door { font-size: 11px; }
}
@media (min-width: 621px) and (max-width: 720px) and (max-height: 430px) { .masthead:has(#genre.on) { gap: 2px; } }

/* Where app.js (fitBar) has measured the room for them in the bar's one row, Near me's word and
   Neighborhoods' magnifier come back over the rules above that leave them off by width alone. */
.masthead.roomy #near.chip.near { width: auto; padding: 0 14px; gap: 8px; }
.masthead.roomy #near .near-word { position: static; width: auto; height: auto; overflow: visible; clip-path: none; }
.masthead.glassy #hoods .glass { display: block !important; }

/* Fingers: targets about 40 px tall, without changing what is drawn. The negative margins
   and the invisible ::after give the room back, so nothing moves. */
@media (pointer: coarse) {
  .chip { padding: 13px 10px; }
  .zoom .chip, .chip.ask, .chip.street-map { width: 41px; height: 41px; }
  .chip.door, .chip.support { height: 41px; }
  @media (max-width: 900px) { .masthead .chip.support { width: 41px; } }
  .option { padding: 13px 20px; }
  .back { padding: 12px 10px 12px 0; margin: -12px 0 -4px; }
  .card-place, .card-cite, .card-source a { padding: 11px 0; margin: -11px 0; }
  /* Except a card's neighborhoods, which wrap: 40 px targets on lines 18 px apart overlapped, and a tap
     on one opened the one below it (Peter Steele's Red Hook opened Bensonhurst). Each is as tall as
     its own line here, 24 px, a finger's least, and the lines are that far apart; the row keeps its
     outer spacing. At 30 px the second line stood further off than the next fact, a row of its own. */
  .card-facts .card-place { padding: 3px 0; margin: 0; }
  .card-facts dd:has(.card-place) { margin: -3px 0; }
  .ticket-link { padding: 11px 12px; margin: -5px 0; }
  /* Share and the accounts are drawn as on a laptop, and an invisible edge, inside the strip, makes each
     target 44 px tall and as wide as the gap beside it allows: the strip stays as slim as it is there. */
  .socials { gap: 10px; }
  .share-sticker, .social { position: relative; }
  .share-sticker::after, .social::after { content: ''; position: absolute; inset: -7px -5px; }
  /* On the narrowest phones, 280 px wide, Share and four accounts ran into the strip's edge: they close up. */
  @media (max-width: 300px) { .card-strip .socials { gap: 7px; } .social::after { inset: -7px -3px; } }
  /* 40 px drawn, and a finger's 46 px with its invisible edge; the headings keep clear of it. */
  .popup-close { top: 6px; right: 6px; width: 40px; height: 40px; font-size: 24px; }
  .popup-close::after { content: ''; position: absolute; inset: -5px; }
  .popup-head { padding-right: 52px; }
  .find { margin-right: -38px; }
  .near-entry { width: calc(100% + 38px); margin-right: -38px; }
  /* A divider card's Share stands centred under the larger ×. */
  .place-line { margin-right: -41px; }
  /* As far down as the × reaches, which a finger's × does further: the second line of a long name
     ran into its ring (Gabriel Garzón-Montano, The Notorious B.I.G.). */
  .card-head > div { --clear: 40px; --clear-down: 34px; }
  #popup[data-view^="artist"] .back { margin-right: 44px; }
  .mark::after { content: ''; position: absolute; inset: -10px 0; }
  .credits-mark::after { content: ''; position: absolute; inset: -8px; }
}
/* A phone held sideways has one row for everything: with the zoom buttons at full size, a long
   genre such as Folk & Country lost its end at 640 px wide. Round, they are as tall as they are
   wide, and an invisible edge keeps a finger's target 42 px tall. */
@media (pointer: coarse) and (max-width: 720px) and (max-height: 430px) {
  .masthead { gap: 6px; }
  .zoom .chip, .chip.ask, .masthead .chip.support { position: relative; width: 34px; height: 34px; }
  .zoom .chip::after, .chip.ask::after, .chip.support::after { content: ''; position: absolute; inset: -4px 0; }
}
/* Wherever a finger has the bar in one row, the street map's switch is in it too, and the round
   buttons are drawn as on a laptop, 30 px across: an invisible edge keeps each target 42 px tall and
   reaches into the gaps beside it. At a finger's 41 px the switch left Genres no room for its own
   name on a tablet held upright 834 px wide, nor on the wider phones held sideways for Folk & Country. */
@media (pointer: coarse) and (min-width: 721px), (pointer: coarse) and (min-width: 621px) and (max-height: 430px) {
  .masthead :is(.zoom .chip, .chip.ask, .chip.street-map, .chip.support) { position: relative; width: 30px; height: 30px; }
  .masthead :is(.zoom .chip, .chip.ask, .chip.street-map, .chip.support)::after { content: ''; position: absolute; inset: -6px -2px; }
  /* Over 900 px Support has its word, and only its height changes. */
  @media (min-width: 901px) { .masthead .chip.support { width: auto; } }
}

/* Hover colors only where a pointer hovers. A finger does not, and a tap left the hover color
   on what it touched: a genre pressed and released again stayed gold, a tapped name white.
   A pressed genre and the open Neighborhoods button keep their own color under the pointer. */
@media (hover: hover) {
  .name.hover { fill: var(--sleeve); }
  .name-edge.hover { fill: var(--ink); stroke: var(--ink); stroke-width: 4.5px; }
  .pair:hover, .face:hover, .stack:hover { z-index: 3; }
  .live:hover .live-edge { transform: rotate(-3deg) scale(1.08); }
  .pair:hover .sleeve { transform: scale(1.12); }
  /* Under the pointer a sleeve's record slides out, turning, and a sticker is pressed down again. */
  .face:hover .sleeve::before { transform: translateX(30%) rotate(40deg); }
  .stack:hover .disc { transform: rotate(-12deg) scale(1.06); }
  .stack:hover .stack-tag { background: var(--gold); color: var(--ink); }
  .mark:hover, .card-link:hover { background: var(--gold); }
  /* Share goes white under the pointer, as Support does in the bar; on a divider card ink, as its × does. */
  .share-sticker:hover { background: var(--sleeve); }
  .divider .share-sticker:hover { background: var(--ink); color: var(--sleeve); }
  .social:hover { background: var(--gold); }
  .ticket-link:hover { background: var(--sleeve); color: var(--ink); }
  .row:hover { background: var(--gold-soft); }
  .popup .crate .row:hover { background: none; transform: translateY(-3px); }
  .popup .crate .row:hover .sleeve::before { transform: translateY(-26%); }
  .popup .crate .row:focus-visible:hover .sleeve::before { transform: none; }
  .chip:not(.door):not([aria-disabled="true"]):hover, .chip.door:not(.on):not([aria-expanded="true"]):hover, .option:not([aria-pressed="true"]):hover { background: var(--gold); }
  .title-card:hover::before { animation: spin 1.6s linear infinite; }
  .masthead .zoom .chip:not([aria-disabled="true"]):hover, .masthead .chip.ask:hover { border-color: var(--gold); background: var(--gold); color: var(--ink); }
  /* The street map's switch only rings in gold: filled, it would look switched on under the pointer
     that has just switched it off. */
  .masthead .chip.street-map:not([aria-pressed="true"]):hover { border-color: var(--gold); background: var(--vinyl); color: var(--gold); }
  .masthead .chip.support:hover { background: var(--sleeve); }
  .credits-mark:not([aria-expanded="true"]):hover { background: var(--gold); }
  .credits-street-map:hover span { background: var(--gold); color: var(--ink); }
  .popup-close:hover { background: var(--gold); }
  /* "Put on" a neighborhood goes gold under the pointer, as it is while it plays; on Brooklyn's gold, white. */
  .put-on:not([aria-pressed="true"]):hover { background: var(--gold); color: var(--ink); }
  .divider.b-brooklyn .put-on:not([aria-pressed="true"]):hover { background: var(--sleeve); }
  .deck .deck-order-option:not([aria-pressed="true"]):hover { background: var(--sleeve); color: var(--ink); }
  .deck :is(.deck-back, .deck-next, .deck-stop):not([aria-disabled="true"]):hover { background: var(--gold); border-color: var(--gold); color: var(--ink); }
  /* Over a divider card, ink with a white ×: gold was lost on Brooklyn's gold, and read the same on all five. */
  .popup:has(> .popup-head.divider) .popup-close:hover { background: var(--ink); color: var(--sleeve); }
  .back:hover, .card-place:hover, .card-cite:hover, .fix-toggle:hover { color: var(--red-text); }
  /* On a divider card's color, and on the staff pick's gold, red writing would be lost: underlined instead. */
  .divider .back:hover, .card-tie .card-cite:hover { color: inherit; text-decoration: underline; text-decoration-thickness: 2px; text-underline-offset: 3px; }
}
/* With a mouse, a sleeve in a neighborhood's pile opens its artist's card (js/overlay.js, stackNode):
   it lifts under the pointer, and the neighborhood's sticker and card stay as they are. */
@media (hover: hover) and (pointer: fine) {
  .stack .tuck .sleeve:hover { z-index: 9 !important; transform: translateY(-4px) scale(1.12); }
  .stack:has(.tuck .sleeve:hover) .disc { transform: rotate(-6deg); }
  .stack:has(.tuck .sleeve:hover) .stack-tag { background: var(--sleeve); }
}

/* On a phone held upright the bar has two rows: the title and the ?, and under them the two
   buttons side by side, the full width of the screen. In one row there was no room for the title,
   both buttons and the name of a genre that is on, short of type too small to read. The two rows
   take less of the screen than the bar and the Neighborhoods bar under the map that they replace.
   The panel is a sheet the full width of the screen, dropped from the bar over the top of the
   map; it used to rise from the bottom. Held sideways the phone is too short for half its height
   to go to a sheet: there the bar is one row and the panel hangs at the right, as on a wide screen.
   A window narrower than that one row, however short, has the two rows and the sheet as well: a
   laptop's at 300% zoom, 427 by 240, had the Neighborhoods button off its right edge. So does the
   smallest phone held sideways, 568 by 320, where one row with the zoom buttons has no room. */
@media (max-width: 720px) and (min-height: 431px), (max-width: 620px) {
  :root { --bar: 97px; }
  .controls { display: grid; grid-template: minmax(48px, auto) 44px / 1fr 1fr; align-items: stretch; height: auto; padding: 0; gap: 0; }
  /* The sign's name over its handwriting, the record beside both. A title made taller by a
     reader's own text spacing makes the first row taller. */
  .controls .title-card { grid-area: 1 / 1; justify-self: start; align-self: center; margin-left: 10px; }
  .controls .chip.ask { grid-area: 1 / 2; justify-self: end; align-self: center; margin-right: 9px; }
  /* Plus and minus beside the ?, as they are in one row: not everyone can pinch. They used to be
     left out on a phone, and on a laptop's screen at 200% zoom. The margin is the ?'s width and a gap. */
  .controls .zoom { grid-area: 1 / 2; justify-self: end; align-self: center; margin-right: 48px; }
  @media (pointer: coarse) { .controls .zoom { margin-right: 60px; } }
  /* On the narrowest phones, 280 px wide, chips that size pushed into the title's half of the bar. */
  @media (pointer: coarse) and (max-width: 300px) { .zoom .chip, .chip.ask { width: 34px; height: 34px; } .controls .zoom { margin-right: 53px; } }
  /* Support, once it is on, sits between them and the ?, and the zoom buttons move along by its
     width and a gap. */
  .controls .chip.support { grid-area: 1 / 2; justify-self: end; align-self: center; margin-right: 48px; }
  .controls:has(.support:not([hidden])) .zoom { margin-right: 87px; }
  @media (pointer: coarse) { .controls .chip.support { margin-right: 60px; } .controls:has(.support:not([hidden])) .zoom { margin-right: 111px; } }
  /* Under 390 px, four buttons of a finger's width pushed into the title's half, and at 360 px
     off the screen: with Support on, they are drawn 32 px across, and an invisible edge keeps
     each target 42 px tall. */
  @media (pointer: coarse) and (max-width: 389px) {
    .controls:has(.support:not([hidden])) :is(.zoom .chip, .chip.ask, .chip.support) { position: relative; width: 32px; height: 32px; }
    .controls:has(.support:not([hidden])) :is(.zoom .chip, .chip.ask, .chip.support)::after { content: ''; position: absolute; inset: -5px 0; }
    .controls:has(.support:not([hidden])) .zoom { gap: 6px; margin-right: 85px; }
    .controls .chip.support { margin-right: 47px; }
  }
  /* At 280 px they left 3 px between the title and the plus, and at 320 px 12: under 360 px,
     where the title is smaller too, 30 px and a little closer together. */
  @media (pointer: coarse) and (max-width: 359px) {
    .controls:has(.support:not([hidden])) :is(.zoom .chip, .chip.ask, .chip.support) { width: 30px; height: 30px; }
    .controls:has(.support:not([hidden])) :is(.zoom .chip, .chip.ask, .chip.support)::after { inset: -6px 0; }
    .controls:has(.support:not([hidden])) .chip.ask { margin-right: 8px; }
    .controls:has(.support:not([hidden])) .zoom { gap: 5px; margin-right: 78px; }
    .controls .chip.support { margin-right: 43px; }
  }
  /* No room for the street map's switch in the first row: it is in the credits corner here. */
  .controls .chip.street-map { display: none; }
  .credits-street-map { display: block; }
  .controls .drop { grid-area: 2 / 1; align-items: stretch; margin: 0; }
  .controls .chip.hoods { grid-area: 2 / 2; }
  /* With This week, the second row is three: its square, then Genres, then Neighborhoods at its own
     width, magnifier and all; Genres takes what is left. The first row's things span all three. */
  .controls:has(.week-drop:not([hidden])) { grid-template-columns: 54px minmax(0, 1fr) max-content; }
  .controls:has(.week-drop:not([hidden])) > :is(.title-card, .zoom, .chip.support, .chip.ask) { grid-column: 1 / -1; }
  .controls .drop.week-drop { grid-area: 2 / 1; }
  .controls:has(.week-drop:not([hidden])) .drop:not(.week-drop) { grid-area: 2 / 2; }
  .controls:has(.week-drop:not([hidden])) .chip.hoods { grid-area: 2 / 3; padding: 0 12px; }
  /* Near me is a gold square of its sign beside Neighborhoods, its words read out (the mockup's B): the
     second row is Genres, the square and Neighborhoods at its own width, and This week's square first when
     it is there. The first row's things span them all. */
  .controls { grid-template-columns: minmax(0, 1fr) var(--near-square) max-content; --near-square: 40px; }
  .controls > :is(.title-card, .zoom, .chip.support, .chip.ask) { grid-column: 1 / -1; }
  .controls .chip.near { grid-area: 2 / 2; width: auto; justify-content: center; padding: 0; border-right-width: 3px; }
  .controls .chip.near .near-word { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
  .controls .chip.hoods { grid-area: 2 / 3; }
  .controls:has(.week-drop:not([hidden])) { grid-template-columns: 50px minmax(0, 1fr) var(--near-square) max-content; }
  .controls:has(.week-drop:not([hidden])) .chip.near { grid-area: 2 / 3; }
  .controls:has(.week-drop:not([hidden])) .chip.hoods { grid-area: 2 / 4; }
  /* The square's room comes out of the doors beside it, which close up, and while a genre is named in
     Genres, Neighborhoods leaves off its magnifier, as it does at 300 px: so a long genre such as Folk &
     Country keeps its name wherever it had it. */
  .controls #genre, .controls .chip.hoods, .controls:has(.week-drop:not([hidden])) .chip.hoods { gap: 6px; padding: 0 10px; }
  .controls:has(#genre.on) .hoods .glass { display: none; }
  .controls .chip.week { justify-content: center; padding: 0; }
  .controls #week { border-right-width: 3px; }
  /* Its list drops the full width of the screen, as the sheet does. */
  .controls .menu.weeklist { position: fixed; top: var(--bar); right: 0; left: 0; width: auto; min-width: 0; max-height: calc((100vh - var(--bar)) * 0.7); max-height: calc((100dvh - var(--bar)) * 0.7); border-width: 0 0 4px; border-radius: 0 0 8px 8px; box-shadow: none; }
  .controls .weeklist .row { padding: 6px 14px; }
  .controls .week-switch { padding: 14px; }
  .controls .week-day h3 { margin: 12px 14px 0; }
  .controls .week-source { margin: 4px 14px 0; }
  /* Under 360 px everything in the row closes up a little, so that Genres keeps its name. */
  @media (max-width: 359px) {
    .controls:has(.week-drop:not([hidden])) { grid-template-columns: 34px minmax(0, 1fr) var(--near-square) max-content; }
    .controls:has(.week-drop:not([hidden])) .chip.door { letter-spacing: 0.03em; }
    .controls:has(.week-drop:not([hidden])) .chip.hoods { gap: 6px; padding: 0 8px; }
    .controls:has(.week-drop:not([hidden])) #genre { gap: 6px; padding: 0 8px; }
    /* With Near me's square beside them as well, This week's square leaves off its dot, as it does at 300
       px, the doors close up further, and their words are a size smaller (further down). */
    .controls .chip.week::before { display: none; }
    .controls #genre, .controls .chip.hoods, .controls:has(.week-drop:not([hidden])) :is(#genre, .chip.hoods) { padding: 0 6px; }
  }
  /* At 300 px and less the square leaves off its dot, as Neighborhoods does its magnifier: the ring
     inside it, thinner and closer in there, cut through the dot. */
  @media (max-width: 300px) {
    .controls:has(.week-drop:not([hidden])) { grid-template-columns: 34px minmax(0, 1fr) var(--near-square) max-content; }
    .controls .chip.week::before { display: none; }
  }
  /* The two buttons are the second row itself, edge to edge, over the bin colors, with an ink line
     between: a pressed genre's gold ran on into the gold of the strip under it. */
  .controls .chip.door, .masthead.controls .chip.door[aria-expanded="true"] { flex: 1; min-width: 0; height: auto; border-width: 3px 0 2px; border-color: var(--ink); border-radius: 0; box-shadow: none; transform: none; font-size: 12px; letter-spacing: 0.06em; }
  .controls #genre { border-right-width: 3px; }
  /* Under 360 px, beside Near me's square, the doors' words are a size smaller (further up). */
  @media (max-width: 359px) { .controls .chip.door, .masthead.controls .chip.door[aria-expanded="true"] { font-size: 11px; } }
  /* Focused, ringed inside their own edges: around them the ring fell on the bar's own lines and
     was lost. Ink, which reads on white, red and gold alike. */
  .controls .chip.door:focus-visible { outline-color: var(--ink); outline-offset: -7px; }
  /* The round buttons' ring hugs them: 2 px out, on a phone 360 px wide it ran off the top of the
     screen and under the row below. */
  .controls .zoom .chip:focus-visible, .controls .chip.ask:focus-visible, .controls .chip.support:focus-visible { outline-offset: 0; }
  .controls .menu { top: calc(100% + 5px); left: 0; min-width: 100%; border-width: 0 4px 4px 0; border-radius: 0 0 8px 0; box-shadow: 6px 6px 0 var(--ink); }
  /* 55% of the map under the bar: of the whole window, the taller bar left 45 px less map
     below the sheet than the old layout did. dvh where the browser has it: on a phone, vh is
     the height with the browser's bars hidden, and a sheet sized from it reaches lower than
     the script counts on. Where the map is short, at least 259 px of it, while that leaves 100 px
     of map under the sheet (app.js, SHEET_LEAST): at 320 by 460, an iPhone SE of the first kind in
     Safari, 55% was 200 px and an opened neighborhood showed no whole name. 259 px is what a 320 by
     568 phone has had, so every taller window is as it was. */
  .popup { top: var(--bar); right: 0; left: 0; width: auto; max-height: max(calc((100vh - var(--bar)) * 0.55), min(259px, calc(100vh - var(--bar) - 100px))); max-height: max(calc((100dvh - var(--bar)) * 0.55), min(259px, calc(100dvh - var(--bar) - 100px))); border-width: 0 0 4px; border-radius: 0 0 8px 8px; box-shadow: none; animation: drop 0.18s ease-out; }
  /* While the search field is in use the sheet runs from the bar down to the keyboard, so
     what is found shows above the keys rather than behind them. */
  .popup.searching { bottom: var(--keyboard, 0px); max-height: none; }
  /* The crate four to a row across the sheet, so that a neighborhood of one shows its name above its
     fold. Under 360 px, three: four sleeves 65 px wide left a long name too little room to be read whole. */
  .popup .crate { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 16px 10px; padding: 18px 14px 20px; }
  .popup .crate .row .sleeve { --side: 80px; }
  @media (max-width: 359px) { .popup .crate { grid-template-columns: repeat(3, minmax(0, 1fr)); } .popup .crate .row .sleeve { --side: 88px; } }
  /* A sheet wider than a phone held upright (a phone on its side, a narrow window) files more to a
     row, rather than four sleeves 150 px wide, one row of them filling the sheet. */
  @media (min-width: 480px) { .popup .crate { grid-template-columns: repeat(auto-fill, minmax(84px, 1fr)); } }
  /* A short phone (320 by 568) has a sheet of about 260 px: at full size the heading took half of it,
     and a school's list showed one row of sleeves cut by the sheet's edge. The heading tightens. */
  @media (max-height: 700px) {
    .popup-head { padding-top: 10px; padding-bottom: 8px; }
    /* The list's Near me row closes up too, so that the list keeps a row more above the sheet's edge. */
    .near-entry { height: 34px; margin-top: 8px; }
    .place-title { gap: 9px; }
    .place-title .emblem-holder { width: 38px; height: 38px; padding: 4px; }
    .popup-head.divider h2 { font-size: 28px; }
    @supports (width: 1cqi) { .popup-head.divider h2 { font-size: max(12px, min(28px, (100cqi - 50px) / var(--longest, 6) / 0.52)); } }
    .popup-head h2 { font-size: 24px; }
    .popup-head .kind { font-size: 15px; }
    .card-head .sleeve { width: 68px; height: 68px; --side: 68px; }
    .card-head > div { margin-left: 30px; }
    /* The heading starts higher here, so the × reaches further down beside the name, and the line
       under a one-line name ran under its ring: the corner kept clear of it reaches down with it. */
    .card-head > div { --clear-down: 36px; }
    @media (pointer: coarse) { .card-head > div { --clear-down: 42px; } }
    .popup .crate { padding-top: 12px; }
    /* Three to a row, a sleeve as wide as its column, 91 px, made a row taller than the crate's part of
       the sheet: a name of three lines went under its edge (Carroll Gardens), and a focused sleeve's ring
       was cut at both ends. The sleeve is drawn smaller than its column; the name keeps the column's width. */
    @media (max-width: 359px) { .popup .crate .row .sleeve { width: 72px; --side: 72px; } }
  }
  /* The map left below the sheet is too small to share with them. */
  .popup-open .credits { display: none; }
  /* The list links, focused: at the bottom, below where the sheet hangs and above the credits,
     which wrap to five lines at most beside the street map's square, 93 px high on a phone 280 px
     wide. Two rows where one is too wide. */
  .lists:focus-within, .popup-open .lists:focus-within { top: auto; right: 8px; bottom: 112px; left: 8px; max-width: none; }
  /* With the sheet open the credits are hidden, and on a short phone the links go down to the window's
     foot, under the sheet: 112 px up, in two rows 90 px tall, they lay over an opened neighborhood's first
     sleeves at 375 by 548, and wholly inside the sheet at 320 by 460. From 558 px tall they clear it as
     they were. */
  @media (max-height: 557px) { .popup-open .lists:focus-within { bottom: 8px; } }
  /* At 300 px and less the Neighborhoods button is too narrow for its magnifier and caret: the caret
     ran off the screen and the inset focus ring through the magnifier. The search field keeps its own. */
  @media (max-width: 300px) {
    .controls .hoods .glass { display: none; }
    /* Neighborhoods filled its button to 4 px of each side, and the ring inside cut through its
       N and its caret: the letters close up a little, and the ring is thinner. */
    .controls .chip.door { letter-spacing: 0.02em; }
    .controls .chip.door:focus-visible { outline-width: 2px; outline-offset: -6px; }
  }
}
/* Narrow and short as well, the map under the two rows is so low that 55% of it would not hold even
   the sheet's heading: there the sheet covers the whole map, and scrolls as one (app.js frames things
   as though it were closed). The list of genres, which hangs from the bar here too, reaches the
   bottom of the window. */
@media (max-width: 620px) and (max-height: 430px) {
  .popup { max-height: calc(100vh - var(--bar)); max-height: calc(100dvh - var(--bar)); overflow-y: auto; }
  .popup-body { flex: none; overflow: visible; }
  /* The card's strip stays at the foot of the sheet as it scrolls, after the card's end, never over it.
     What scrolls passes under it, so the keyboard's focus stops above it: a focused link was left under
     the strip, wholly or in part, with nothing scrolled. Its 46 px and room for the focus ring. */
  .card-strip { position: sticky; bottom: 0; z-index: 1; }
  .popup:has(> .card-strip) { scroll-padding-bottom: 54px; }
  .menu { max-height: calc(100vh - var(--bar)); }
  /* Too short for them to fit between the bar and the credits: they go under the bar, over the credits. */
  .lists:focus-within, .popup-open .lists:focus-within { top: calc(var(--bar) + 8px); bottom: auto; }
  /* The ? is narrower on a phone held sideways (above), and the zoom buttons stay beside it. */
  @media (pointer: coarse) { .controls .zoom, .controls .chip.support { margin-right: 53px; } .controls:has(.support:not([hidden])) .zoom { margin-right: 97px; } }
}

/* A window as short as a phone held sideways, at any width: an opened neighborhood's divider card
   tightens and its sleeves file closer, so that the first row's names show above the panel's edge.
   At full size the card left the panel some 116 px, and the first row of sleeves ran out of it with
   no name in sight: in the panel at the right (740 by 360) and in the sheet (568 by 320). */
@media (max-height: 430px) {
  .popup-head.divider { padding-top: 10px; padding-bottom: 8px; }
  .place-title { gap: 9px; }
  .place-title .emblem-holder { width: 34px; height: 34px; padding: 4px; }
  .popup-head.divider h2 { font-size: 28px; }
  @supports (width: 1cqi) { .popup-head.divider h2 { font-size: max(12px, min(28px, (100cqi - 46px) / var(--longest, 6) / 0.52)); } }
  .popup .crate { grid-template-columns: repeat(auto-fill, minmax(76px, 1fr)); gap: 14px 10px; padding-top: 10px; }
  /* The sheet, under the bar's two rows, has the least room: a name of one line just showed above the
     bottom of the window, and the second line of a longer one went under it, so a neighborhood of one
     showed no name whole (Maspeth's Fanny Crosby at 568 by 320). The sleeves are drawn smaller than their
     columns there, and the names keep the columns' width, so no word breaks. */
  @media (max-width: 620px) { .popup .crate { padding-top: 8px; } .popup .crate .row .sleeve { width: 64px; --side: 64px; } }
  /* In the panel at the right a row with a name of two lines was taller than the crate's part of the
     panel less the room for a focused sleeve's ring, which lost its top (740 by 360). */
  @media (min-width: 621px) { .popup .crate .row .sleeve { width: 72px; --side: 72px; } }
}

/* With a mouse a sleeve lifts and its record rises some 20 px out of the top of it: the crate keeps
   that much room above its first row wherever its top is tightened, or the record was cut flat under
   the divider card (a narrow window 650 px tall). */
@media (hover: hover) { .popup .crate { padding-top: 22px; } }

/* ---------- Put on a neighborhood ---------- */

/* "Put on Harlem" (js/station.js): a neighborhood's artists one after another in Spotify's player, the
   owner's pick B of mockups/tool/station, a listening station of its own. A record, as the sign's own:
   grooves, the two wedges of light, a label in the borough's color with a play mark on it, which turns
   while the station plays. */
.record {
  position: relative; display: block; flex: none; border-radius: 50%;
  background:
    radial-gradient(circle closest-side, var(--vinyl) 0 5%, var(--hue, var(--red)) 6% 34%, #0B0908 35% 37%, transparent 38%),
    conic-gradient(from 35deg, transparent 0 7%, rgba(255, 253, 248, 0.24) 11%, transparent 15% 57%, rgba(255, 253, 248, 0.24) 61%, transparent 65%),
    repeating-radial-gradient(circle closest-side, #1A1613 0 1px, #2C2622 1.4px 2.2px);
}
.record-label { position: absolute; left: 50%; top: 50%; width: 0; height: 0; margin: -4px 0 0 -2px; border-left: 7px solid var(--ink); border-top: 4px solid transparent; border-bottom: 4px solid transparent; }
.playing .record { animation: spin 1.8s linear infinite; }
/* Asked to play, before the player says it plays: the deck's record still, its play mark breathing. */
.deck.waiting .deck-record .record-label { animation: waiting 0.9s ease-in-out infinite alternate; }
@keyframes waiting { to { opacity: 0.25; } }
.playing .record-label { display: none; }

/* On an opened neighborhood's divider card, under its borough and count: a black sticker with the record,
   gold while it plays. On Brooklyn's gold it is white then, as Share is there. */
.put-on {
  display: inline-flex; align-items: center; gap: 8px; max-width: 100%; margin-top: 10px; padding: 4px 14px 4px 5px;
  border: 2px solid var(--ink); border-radius: 999px; background: var(--vinyl); color: var(--sleeve); box-shadow: 2px 2px 0 var(--ink);
  font-size: 11.5px; font-weight: 800; letter-spacing: 0.07em; line-height: 1.15; text-align: left; text-decoration: none; text-transform: uppercase; cursor: pointer;
}
.put-on .record { width: 24px; height: 24px; box-shadow: 0 0 0 1.5px var(--sleeve); }
.put-on[aria-pressed="true"] { background: var(--gold); color: var(--ink); }
.put-on[aria-pressed="true"] .record { box-shadow: 0 0 0 1.5px var(--ink); }
.divider.b-brooklyn .put-on[aria-pressed="true"] { background: var(--sleeve); }
/* A line of its own under the borough and count, which keep Share at their end. Where the panel is short,
   a phone's sheet or a window as short as a phone held sideways, it is a round record beside Share, its
   words read out: on its own line it left a 320 by 568 phone's sheet no room for the crate under the deck. */
.place-line:has(.put-on-line) { flex-wrap: wrap; }
.put-on-line { order: 1; flex: 0 0 100%; }
@media (max-width: 720px) and (max-height: 700px), (max-height: 430px) {
  .put-on-line { order: 0; flex: none; margin-left: auto; }
  .place-line .put-on { justify-content: center; width: 30px; height: 30px; margin: -4px 0; padding: 0; }
  .place-line .put-on .record { width: 26px; height: 26px; box-shadow: none; }
  .put-on-word { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
}
/* And on any phone's sheet while a neighborhood plays: the deck in the bar leaves every sheet short (360 by
   740: a 60 px strip of the crate under the heading; 390 by 844, 117 px). */
@media (max-width: 720px) and (min-height: 431px), (max-width: 620px) {
  html.on-air .put-on-line { order: 0; flex: none; margin-left: auto; }
  html.on-air .place-line .put-on { justify-content: center; width: 30px; height: 30px; margin: -4px 0; padding: 0; }
  html.on-air .place-line .put-on .record { width: 26px; height: 26px; box-shadow: none; }
  html.on-air .put-on-word { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
}

/* The deck: the turntable's controls, round buttons ringed in white as the sign's are, and Spotify's own
   player under them, never covered or restyled (its terms): its own rounded corners, on the black. Where
   the panel is a sheet, and in a window as short as a phone held sideways, it is a row of the bar. */
.deck { position: relative; color: var(--sleeve); background: var(--vinyl); }
.deck-row { display: flex; align-items: center; gap: 3px; height: 40px; }
.deck button { position: relative; display: inline-grid; place-items: center; flex: none; padding: 0; border: 0; background: none; color: inherit; font: inherit; cursor: pointer; }
.deck button[aria-disabled="true"] { opacity: 0.4; cursor: default; }
.deck-disc .record { width: 32px; height: 32px; box-shadow: 0 0 0 2px var(--sleeve); }
.deck-disc { margin-right: 2px; border-radius: 50%; }
.deck :is(.deck-back, .deck-next, .deck-stop) { width: 28px; height: 28px; border: 2px solid var(--sleeve); border-radius: 50%; }
.deck-back svg, .deck-next svg { width: 12px; height: 12px; fill: currentColor; }
.deck .deck-stop { padding-bottom: 2px; font-size: 19px; font-weight: 600; line-height: 1; }
.deck-count { flex: none; padding: 0 2px; font-size: 11.5px; font-weight: 800; font-variant-numeric: tabular-nums; white-space: nowrap; }
/* Best known or oldest first: two words on one pill, the one on in gold, as a pressed genre is. */
.deck-order { flex: none; display: inline-flex; margin-left: auto; border: 2px solid var(--sleeve); border-radius: 999px; overflow: hidden; }
.deck .deck-order-option { padding: 5px 6px; font-size: 9.5px; font-weight: 800; letter-spacing: 0.05em; line-height: 1.1; text-transform: uppercase; white-space: nowrap; }
.deck .deck-order-option[aria-pressed="true"] { background: var(--gold); color: var(--ink); }
.deck .deck-order-option:focus-visible { outline-offset: -4px; }
.deck .deck-order-option[aria-pressed="true"]:focus-visible { outline-color: var(--ink); }
.deck-player { height: 80px; margin-top: 6px; }
.booth { display: block; width: 100%; height: 100%; border: 0; border-radius: 12px; background: #282828; }
.deck-tab { display: none; }

/* On a laptop, a listening station under the panel at the right, the panel's width, its neighborhood's
   divider card standing up from it, which says what is on while the panel shows something else. It stays
   when the panel closes, over the map's corner, where nothing is named (app.js, underDeck). The panel
   above it is shorter by the deck, its divider card and a gap; the credits keep clear of it. In a window
   under 761 px tall, a common laptop's (1366 by 657), that left the panel one row of the crate and a card
   170 px: there the deck is a row of the bar instead, below. */
@media (min-width: 721px) and (min-height: 761px) {
  .deck {
    position: fixed; right: 18px; bottom: 18px; z-index: 8; width: var(--popup); padding: 6px 8px 8px;
    border: 4px solid var(--ink); border-radius: 0 8px 8px 8px; box-shadow: 8px 8px 0 var(--ink);
  }
  .deck-tab {
    position: absolute; left: -4px; bottom: 100%; display: flex; align-items: center; gap: 7px; max-width: calc(100% + 8px); margin: 0; padding: 4px 14px 2px 6px;
    border: 4px solid var(--ink); border-bottom: 0; border-radius: 10px 10px 0 0; background: var(--hue); color: var(--on-hue);
    font-family: var(--display); font-weight: 900; font-size: 16px; line-height: 1; letter-spacing: 0.04em; text-transform: uppercase; white-space: nowrap;
  }
  .deck-tab span { overflow: hidden; text-overflow: ellipsis; }
  .deck-tab .emblem-holder { width: 24px; height: 24px; padding: 2px; background: var(--sleeve); border: 1.5px solid var(--ink); border-radius: 50%; }
  /* Searching too: the search field's .searching lifts the sheet's height limit on a phone, and here it put
     the panel's last rows behind the deck, out of reach. */
  html.on-air .popup { max-height: calc(100vh - var(--bar) - 32px - var(--deck-h, 150px) - 40px); }
  html.on-air .credits { max-width: calc(100vw - var(--popup) - 62px); }
}

/* The panel's crate: whoever is on, their sleeve lit, its record risen out of the top and turning while it
   plays, on a pale gold mark. A row of a list (what the search found) is marked in the same gold. */
.row.person.on-air { background: var(--gold-soft); }
.popup .crate .row.on-air { background: var(--gold-soft); box-shadow: 0 0 0 6px var(--gold-soft); }
.popup .crate .row.on-air .sleeve-photo { border-color: var(--sleeve); box-shadow: 0 0 0 2px var(--ink), 3px 3px 0 2px var(--ink); }
.popup .crate .row.on-air .sleeve::before { --out: translateY(-18%); transform: var(--out); }
/* On the map: their sleeve's record out and turning, wherever they are drawn. From afar the name is to the
   right of the sleeve, so there it comes out of the left side; up close, and in a pile, out of the right. */
.overlay .on-air .sleeve::before, .overlay .tuck .sleeve.on-air::before { --out: translateX(38%); display: block; transform: var(--out); }
.overlay .pair.on-air .sleeve::before { --out: translateX(-80%); }
.overlay .pair.on-air, .overlay .face.on-air { z-index: 3; }
.station-playing :is(.overlay .on-air .sleeve, .overlay .tuck .sleeve.on-air, .popup .crate .row.on-air .sleeve)::before { animation: on-air 1.8s linear infinite; }
@keyframes on-air { from { transform: var(--out) rotate(0deg); } to { transform: var(--out) rotate(360deg); } }

/* Where the panel is a sheet, on a phone held upright, the deck is a third row of the bar, over its bin
   colors, and the map and the sheet start under it; the genres hang below it. */
@media (max-width: 720px) and (min-height: 431px), (max-width: 620px) {
  .controls:has(.deck) { grid-template-rows: minmax(48px, auto) 44px auto; }
  .controls .deck { grid-column: 1 / -1; grid-row: 3; padding: 4px 10px 9px; border-top: 3px solid var(--ink); }
  .controls:has(.deck) .menu:not(.weeklist) { top: calc(100% + 5px + var(--deck-h, 0px)); }
  /* Fingers: each button's target about 40 px tall, without changing what is drawn. */
  .deck button::after { content: ''; position: absolute; inset: -5px -3px; }
  .deck .deck-order-option::after { inset: -7px 0; }
  /* Under 360 px everything in its row closes up, so that it stays one line. */
  @media (max-width: 359px) {
    .deck-row { gap: 3px; }
    .deck-disc .record { width: 30px; height: 30px; }
    .deck :is(.deck-back, .deck-next, .deck-stop) { width: 27px; height: 27px; }
    .deck-count { padding: 0; font-size: 11px; }
    .deck .deck-order-option { padding: 5px 5px; font-size: 9px; letter-spacing: 0.04em; }
  }
}
/* Where the deck leaves the panel little room, a short phone's sheet (320 by 568: 181 px under the deck) or a
   window as short as a phone held sideways, the whole panel scrolls, as it does in a window both narrow and
   short, rather than its heading leaving the crate a sliver; a card's strip stays at its foot. */
@media (max-width: 720px) and (min-height: 431px) and (max-height: 700px), (max-width: 620px) and (max-height: 700px), (min-width: 621px) and (max-height: 430px) {
  html.on-air .popup { overflow-y: auto; }
  html.on-air .popup-body { flex: none; overflow: visible; }
  html.on-air .card-strip { position: sticky; bottom: 0; z-index: 1; }
  html.on-air .popup:has(> .card-strip) { scroll-padding-bottom: 54px; }
}
/* On a taller phone too, an opened neighborhood and a card: under its divider card a 360 by 740 phone's sheet
   left the crate a 60 px strip that cut through the sleeves, and the panel did not scroll. The list of all,
   with its search field, and what is near keep their heading, as without the deck. */
@media (max-width: 720px) and (min-height: 701px) {
  html.on-air .popup:is([data-view^="place "], [data-view^="artist "]) { overflow-y: auto; }
  html.on-air .popup:is([data-view^="place "], [data-view^="artist "]) > .popup-body { flex: none; overflow: visible; }
  html.on-air .popup[data-view^="artist "] > .card-strip { position: sticky; bottom: 0; z-index: 1; }
  html.on-air .popup[data-view^="artist "]:has(> .card-strip) { scroll-padding-bottom: 54px; }
}
/* As short a window as a phone held sideways, or a laptop's under 761 px tall: one row of the bar, the
   controls beside the player, under the bar's first row. Where the bar has one row (a panel at the right)
   the bar grows by it, and the menus that hang from the bar hang below it. On a laptop the neighborhood's
   divider card heads the row, folded into it: it says what is on while the panel shows something else. */
@media (max-height: 430px), (min-width: 721px) and (max-height: 760px) {
  .masthead .deck { display: flex; align-items: center; gap: 12px; }
  .masthead .deck-row { flex: none; }
  .masthead .deck-player { flex: 1 1 auto; min-width: 0; margin-top: 0; }
  .deck .deck-order { margin-left: 4px; }
  @media (min-width: 721px) and (min-height: 431px) {
    .masthead .deck-tab {
      display: flex; flex: 0 1 auto; align-items: center; gap: 7px; min-width: 0; max-width: 240px; margin: 0; padding: 4px 14px 4px 6px;
      border: 3px solid var(--ink); border-radius: 10px; background: var(--hue); color: var(--on-hue);
      font-family: var(--display); font-weight: 900; font-size: 16px; line-height: 1; letter-spacing: 0.04em; text-transform: uppercase; white-space: nowrap;
    }
    .masthead .deck-tab span { overflow: hidden; text-overflow: ellipsis; }
    .masthead .deck-tab .emblem-holder { flex: none; width: 24px; height: 24px; padding: 2px; background: var(--sleeve); border: 1.5px solid var(--ink); border-radius: 50%; }
  }
  @media (min-width: 621px) {
    .masthead:has(.deck) { flex-wrap: wrap; align-content: flex-start; height: auto; }
    .masthead:has(.deck) > .title-card { min-height: 56px; }
    .masthead .deck { flex: 0 0 100%; padding: 0 0 9px; }
    .masthead:has(.deck) .menu { top: calc(100% + 19px + var(--deck-h, 0px)); }
  }
  @media (min-width: 621px) and (max-width: 720px) { .masthead:has(.deck) > .title-card { min-height: 50px; } }
}

/* The sign's record turns in a ::before, which `*` alone does not reach. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { transition: none !important; animation: none !important; }
}
