/* ============================================================
   perfnyc — monochrome, hairline, no-scroll
   Hard rules: border-radius is 0 everywhere. Chroma is 0 everywhere.
   The viewport is the page: nothing ever scrolls.
   ============================================================ */

:root {
  color-scheme: light dark;

  /* achromatic ramp — chroma 0, no warm tint, no cream */
  --ground:      oklch(0.985 0 0);
  --ground-sunk: oklch(0.955 0 0);
  --ink:         oklch(0.175 0 0);
  --ink-soft:    oklch(0.415 0 0);   /* 6.9:1 on ground */
  --ink-faint:   oklch(0.520 0 0);   /* 4.8:1 on ground — meta only */
  --rule:        oklch(0.175 0 0 / 0.15);
  --rule-firm:   oklch(0.175 0 0 / 0.32);
  --flip-bg:     oklch(0.175 0 0);
  --flip-ink:    oklch(0.985 0 0);

  /* L'única color de la interfície. Sis tons a la MATEIXA lluminositat i amb
     el croma just per distingir-se: així els punts es llegeixen pel to i no
     pel pes, i el mapa no deixa de ser fi. L'aigua és el setè, encara més
     apagat, perquè és fons i no dada. */
  --f-performance-art: oklch(0.58 0.13 350);
  --f-dance:           oklch(0.58 0.13  60);
  --f-theatre:         oklch(0.58 0.15  25);
  --f-music:           oklch(0.58 0.13 250);
  --f-nightlife:       oklch(0.58 0.14 300);
  --f-public:          oklch(0.58 0.12 155);
  --water:             oklch(0.93 0.028 236);

  --font-title: ui-serif, "Iowan Old Style", "Palatino Linotype", Palatino, Georgia, "Times New Roman", serif;
  --font-ui: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;

  --row-h: 46px;
  --pad: 20px;
  --hair: 1px;

  --z-overlay: 40;
  --ease: cubic-bezier(0.22, 1, 0.36, 1);
  --dur: 140ms;
}

@media (prefers-color-scheme: dark) {
  :root {
    --ground:      oklch(0.145 0 0);
    --ground-sunk: oklch(0.185 0 0);
    --ink:         oklch(0.960 0 0);
    --ink-soft:    oklch(0.740 0 0);
    --ink-faint:   oklch(0.620 0 0);
    --rule:        oklch(1 0 0 / 0.17);
    --rule-firm:   oklch(1 0 0 / 0.38);
    --flip-bg:     oklch(0.960 0 0);
    --flip-ink:    oklch(0.145 0 0);

    /* A fosc cal pujar la lluminositat dels tons o desapareixen sobre el
       negre, i baixar la de l'aigua o el port llueix més que la ciutat. */
    --f-performance-art: oklch(0.72 0.14 350);
    --f-dance:           oklch(0.75 0.14  60);
    --f-theatre:         oklch(0.70 0.16  25);
    --f-music:           oklch(0.72 0.13 250);
    --f-nightlife:       oklch(0.72 0.15 300);
    --f-public:          oklch(0.74 0.13 155);
    --water:             oklch(0.255 0.035 240);
  }
}

/* hairlines get finer where the display can render them */
@media (min-resolution: 2dppx) { :root { --hair: 0.5px; } }

*, *::before, *::after {
  box-sizing: border-box;
  border-radius: 0 !important;   /* hard rule of the brief */
}

html, body {
  height: 100%;
  margin: 0;
  overflow: hidden;              /* hard rule of the brief */
  overscroll-behavior: none;
  background: var(--ground);
  color: var(--ink);
  font-family: var(--font-ui);
  font-size: 15px;
  line-height: 1.35;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

button, input, select { font: inherit; color: inherit; background: none; border: 0; }
button { cursor: pointer; }
a { color: inherit; text-underline-offset: 3px; text-decoration-thickness: var(--hair); }

:focus-visible { outline: var(--hair) solid var(--ink); outline-offset: 2px; }

/* ============================================================ shell */

.app {
  height: 100dvh;
  display: grid;
  grid-template-rows: auto auto minmax(0, 1fr) auto;
}

/* ---------------------------------------------------- masthead */

.masthead {
  display: flex;
  align-items: baseline;
  gap: 18px;
  padding: 12px var(--pad) 11px;
  border-bottom: var(--hair) solid var(--rule-firm);
}

.wordmark {
  font-family: var(--font-title);
  font-size: 19px;
  font-weight: 400;
  letter-spacing: -0.01em;
  margin: 0;
  white-space: nowrap;
}
.wordmark em { font-style: italic; }

.masthead .tally {
  font-size: 11.5px;
  letter-spacing: 0.04em;
  color: var(--ink-faint);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.masthead .spacer { flex: 1; }

.masthead .contact {
  font-family: var(--font-ui);
  font-size: 11px;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--ink-faint);
  text-decoration: none;
  padding: 3px 10px;
  border: var(--hair) solid var(--rule-firm);
  white-space: nowrap;
  transition: color var(--dur) var(--ease), background var(--dur) var(--ease);
}
.masthead .contact:hover,
.masthead .contact:focus-visible { color: var(--flip-ink); background: var(--flip-bg); }

.masthead .stamp {
  font-size: 11.5px;
  letter-spacing: 0.04em;
  color: var(--ink-faint);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* ---------------------------------------------------- filter band */

.band {
  display: flex;
  align-items: stretch;
  border-bottom: var(--hair) solid var(--rule);
  min-height: 40px;
}

.search {
  flex: 0 0 clamp(180px, 22vw, 300px);
  display: flex;
  align-items: center;
  border-right: var(--hair) solid var(--rule);
  padding: 0 var(--pad);
}
.search input {
  width: 100%;
  font-size: 13px;
  letter-spacing: 0.01em;
  padding: 8px 0;
}
.search input::placeholder { color: var(--ink-faint); opacity: 1; }

.chips {
  display: flex;
  align-items: stretch;
  flex: 1;
  min-width: 0;
}

.chip {
  padding: 0 14px;
  font-size: 11.5px;
  letter-spacing: 0.045em;
  text-transform: lowercase;
  color: var(--ink-faint);
  border-right: var(--hair) solid var(--rule);
  white-space: nowrap;
  transition: color var(--dur) var(--ease), background var(--dur) var(--ease);
}
.chip:hover { color: var(--ink); }
.chip[aria-pressed="true"] {
  background: var(--flip-bg);
  color: var(--flip-ink);
}

.chip.when { letter-spacing: 0.06em; }

/* La pastilla de color a la fitxa ÉS la llegenda del mapa: no cal cap caixa a
   part explicant què vol dir cada to. */
.chip[data-form]::before {
  content: "";
  display: inline-block;
  width: 7px;
  height: 7px;
  margin-right: 7px;
  vertical-align: 0.02em;
  background: var(--chip-hue, var(--ink-faint));
}
.chip[data-form="performance-art"] { --chip-hue: var(--f-performance-art); }
.chip[data-form="dance"]           { --chip-hue: var(--f-dance); }
.chip[data-form="theatre"]         { --chip-hue: var(--f-theatre); }
.chip[data-form="music"]           { --chip-hue: var(--f-music); }
.chip[data-form="nightlife"]       { --chip-hue: var(--f-nightlife); }
.chip[data-form="public"]          { --chip-hue: var(--f-public); }

/* "When" is one choice, "Form" is many. Labelling and separating the two
   groups is the whole fix: unlabelled chips in one row read as one set. */
.chip-label {
  display: flex;
  align-items: center;
  padding: 0 12px 0 14px;
  font-size: 9.5px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-faint);
  border-right: var(--hair) solid var(--rule);
  white-space: nowrap;
  user-select: none;
}
.chip-label.is-firm { border-left: var(--hair) solid var(--rule-firm); }

.band .clear {
  margin-left: auto;
  padding: 0 var(--pad);
  font-size: 11.5px;
  letter-spacing: 0.045em;
  color: var(--ink-faint);
  border-left: var(--hair) solid var(--rule);
}
.band .clear:hover { color: var(--ink); }

.band .filters-toggle { display: none; }

/* ---------------------------------------------------- panes */

.panes {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr);
  min-height: 0;
  overflow: hidden;
}

/* ---------------------------------------------------- map */

.map   { grid-area: map; }
.index { grid-area: index; }
.detail { grid-area: detail; }

.panes { grid-template-areas: "index detail"; }

/* Wide: three equal columns, map on the far left. */
@media (min-width: 1150px) {
  body[data-map="on"] .panes {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) minmax(0, 1fr);
    grid-template-areas: "map index detail";
  }
}

/* Medium (no room for three columns, but the detail must stay visible):
   the left column splits vertically — map above, list below. */
@media (min-width: 900px) and (max-width: 1149px) {
  body[data-map="on"] .panes {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.05fr);
    grid-template-rows: minmax(0, 1fr) minmax(0, 1.25fr);
    grid-template-areas: "map detail" "index detail";
  }
  body[data-map="on"] .map {
    display: grid;
    border-bottom: var(--hair) solid var(--rule-firm);
  }
}

.map {
  display: none;
  min-height: 0;
  overflow: hidden;
  border-right: var(--hair) solid var(--rule-firm);
  padding: 16px;
  position: relative;
  place-items: center;
}
@media (min-width: 1150px) {
  body[data-map="on"] .map { display: grid; }
}

.map svg {
  width: 100%;
  height: 100%;
  max-height: 100%;
  display: block;
  cursor: grab;
  /* The map owns its gestures: without this, a two-finger pinch would try to
     zoom the document, which is the one thing this page must never do. */
  touch-action: none;
}
.map svg.is-panning { cursor: grabbing; }

.boro {
  fill: var(--ground-sunk);
  stroke: var(--rule-firm);
  stroke-width: 1.4;
  vector-effect: non-scaling-stroke;
  transition: fill var(--dur) var(--ease);
}
.boro.is-lit { fill: var(--ink-faint); fill-opacity: 0.18; }

/* ---- progressive detail: parks, neighbourhoods, streets.
   Every stroke is non-scaling, so a hairline stays a hairline at 60x. */

.lyr { pointer-events: none; }

.park {
  fill: var(--ink-faint);
  fill-opacity: 0.09;
  stroke: none;
}

.nta {
  fill: none;
  stroke: var(--rule-firm);
  stroke-width: 0.6;
  stroke-opacity: 0.75;
  vector-effect: non-scaling-stroke;
}

/* Cap d'aquestes classes declara font-size: la mida la posa el GRUP des de
   JavaScript i els fills l'hereten, que és una escriptura en comptes de dues
   mil a cada fotograma. Si tornes a posar-hi font-size aquí, guanya el CSS i
   les etiquetes es queden clavades a la mida del zoom 1.

   La regió: hi és, però no és el subjecte. Terra un pas més clara que la
   ciutat i el contorn més fi, perquè Nova York segueixi manant la lectura. */
.town {
  fill: var(--ground-sunk);
  fill-opacity: 0.45;
  stroke: var(--rule);
  stroke-width: 0.7;
  vector-effect: non-scaling-stroke;
}

/* L'aigua és el fons de la pàgina: no és una capa que es pinti, és una capa
   que TAPA. Va damunt dels municipis i sota de la ciutat, i amb ella
   desapareixen alhora el port tenyit i la ratlla recta que el partia. */
.water { fill: var(--water); stroke: none; }

.town-label {
  font-family: var(--font-ui);
  letter-spacing: 0.13em;
  text-transform: uppercase;
  fill: var(--ink-faint);
  text-anchor: middle;
  pointer-events: none;
  user-select: none;
  paint-order: stroke;
  stroke: var(--ground);
  stroke-width: 2.5px;
  stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
}

.road { fill: none; vector-effect: non-scaling-stroke; stroke: var(--ink-faint); }
.road.street { stroke-width: 0.5; stroke-opacity: 0.5; }
.road.r30    { stroke-width: 0.6; stroke-opacity: 0.65; }
.road.r20    { stroke-width: 0.7; stroke-opacity: 0.8; }
.road.r10    { stroke-width: 0.9; stroke-opacity: 0.95; }

.boro-label {
  font-family: var(--font-ui);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  fill: var(--ink-faint);
  text-anchor: middle;
  pointer-events: none;
  user-select: none;
  transition: opacity var(--dur) var(--ease);
}

.nta-label {
  font-family: var(--font-ui);
  letter-spacing: 0.09em;
  text-transform: uppercase;
  fill: var(--ink-soft);
  text-anchor: middle;
  pointer-events: none;
  user-select: none;
  paint-order: stroke;
  stroke: var(--ground);
  stroke-width: 2.5px;
  stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
}
.nta-label.is-park { letter-spacing: 0.14em; fill: var(--ink-faint); }

.pin-label {
  font-family: var(--font-ui);
  letter-spacing: 0.02em;
  fill: var(--ink);
  text-anchor: middle;
  pointer-events: none;
  user-select: none;
  paint-order: stroke;
  stroke: var(--ground);
  stroke-width: 2.5px;
  stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
}

.map-zoom {
  position: absolute;
  top: 16px; right: 16px;
  display: grid;
  border: var(--hair) solid var(--rule-firm);
  background: var(--ground);
}
.map-zoom button {
  width: 26px; height: 26px;
  font-size: 13px;
  line-height: 1;
  color: var(--ink-faint);
  background: none;
  border: 0;
  border-bottom: var(--hair) solid var(--rule);
  cursor: pointer;
}
.map-zoom button:last-child { border-bottom: 0; font-size: 10px; }
.map-zoom button:hover { color: var(--ink); background: var(--ground-sunk); }
.map-zoom button:disabled { opacity: 0.32; cursor: default; background: none; }

.pin {
  fill: none;
  stroke: var(--ink-soft);
  stroke-width: 8;
  stroke-linecap: square;
  vector-effect: non-scaling-stroke;
  transition: stroke-width var(--dur) var(--ease);
}
/* El to diu QUÈ és; la mida diu si és exacte i si està triat. Res més. */
.pin[data-form="performance-art"] { stroke: var(--f-performance-art); }
.pin[data-form="dance"]           { stroke: var(--f-dance); }
.pin[data-form="theatre"]         { stroke: var(--f-theatre); }
.pin[data-form="music"]           { stroke: var(--f-music); }
.pin[data-form="nightlife"]       { stroke: var(--f-nightlife); }
.pin[data-form="public"]          { stroke: var(--f-public); }

.pin.is-approx { stroke-width: 6; stroke-opacity: 0.45; }
.pin.is-lit { stroke-width: 13; stroke-opacity: 1; }

/* Tot el que fa es rebre el ratolí: no pinta res. */
.pin-hit {
  fill: none;
  stroke: transparent;
  stroke-width: 22;
  stroke-linecap: square;
  vector-effect: non-scaling-stroke;
  cursor: pointer;
}

/* La creu passa per damunt del punt que assenyala. Sense això s'emporta el
   clic que anava al punt, i clicar al mapa no seleccionava res. */
.crosshair {
  stroke: var(--ink);
  stroke-width: 1;
  vector-effect: non-scaling-stroke;
  pointer-events: none;
}

.map-note {
  position: absolute;
  left: 16px; bottom: 12px;
  margin: 0;
  font-size: 10.5px;
  letter-spacing: 0.05em;
  color: var(--ink-faint);
  font-variant-numeric: tabular-nums;
}

.map-toggle {
  padding: 0 14px;
  font-size: 11.5px;
  letter-spacing: 0.045em;
  color: var(--ink-faint);
  border-left: var(--hair) solid var(--rule);
  white-space: nowrap;
}
.map-toggle:hover { color: var(--ink); }
.map-toggle[aria-pressed="true"] { background: var(--flip-bg); color: var(--flip-ink); }

/* The map never covers the list: where there is no room beside it, it takes
   a share of the height instead. */

.index {
  min-height: 0;
  overflow: hidden;
  border-right: var(--hair) solid var(--rule-firm);
  display: flex;
  flex-direction: column;
}

/* La vista de tres setmanes és l'única que corre — i corre DINS del panell,
   mai el document: la pàgina segueix sense fer scroll a cap format. */
body[data-flow="scroll"] .rows {
  overflow-y: auto;
  scrollbar-width: thin;
  scrollbar-color: var(--rule-firm) transparent;
}
body[data-flow="scroll"] .pager .step,
body[data-flow="scroll"] .pager .keys kbd:nth-child(3),
body[data-flow="scroll"] .pager .keys kbd:nth-child(4) { display: none; }

.wk {
  position: sticky;
  top: 0;
  z-index: 2;
  background: var(--ground);
  padding: 10px 12px 5px;
  font-family: var(--font-ui);
  font-size: 10px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-faint);
  border-bottom: var(--hair) solid var(--rule-firm);
}
.wk:first-child { padding-top: 4px; }

/* Una fila FIXADA porta una barra a l'esquerra. Sense cap marca, el lector no
   pot saber per què el mapa ha deixat de respondre-li — i la resposta és que
   ho ha demanat ell. Clicar-la altra vegada la deixa anar. */
.row.is-pinned { box-shadow: inset 3px 0 0 var(--ink); }

/* La marca del final del que hi ha dibuixat. Quan arriba a la vista, es
   construeix el tram següent — i mentrestant diu quantes en queden. */
.more {
  padding: 14px 12px;
  font-family: var(--font-ui);
  font-size: 10px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-faint);
  border-top: var(--hair) solid var(--rule);
}

.index-head,
.row {
  display: grid;
  grid-template-columns: 136px minmax(0, 1fr) minmax(0, 170px) 92px;
  align-items: center;
  gap: 18px;
  padding: 0 var(--pad);
}

.index-head {
  height: 26px;
  font-size: 10px;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: var(--ink-faint);
  border-bottom: var(--hair) solid var(--rule);
  flex: 0 0 auto;
}

.rows { flex: 1 1 auto; min-height: 0; overflow: hidden; }

.row {
  height: var(--row-h);
  width: 100%;
  text-align: left;
  border-bottom: var(--hair) solid var(--rule);
  transition: background var(--dur) var(--ease);
}
.row:hover { background: var(--ground-sunk); }
.row[aria-current="true"] {
  background: var(--flip-bg);
  color: var(--flip-ink);
}
.row[aria-current="true"] .r-venue,
.row[aria-current="true"] .r-form,
.row[aria-current="true"] .r-when { color: var(--flip-ink); opacity: 0.72; }

.r-when {
  font-size: 11.5px;
  letter-spacing: 0.03em;
  color: var(--ink-soft);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: clip;
  min-width: 0;
}
.r-title {
  font-family: var(--font-title);
  font-size: 16px;
  line-height: 1.2;
  letter-spacing: -0.005em;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.r-venue, .r-form {
  font-size: 11.5px;
  letter-spacing: 0.03em;
  color: var(--ink-faint);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.r-form { text-align: right; }

.rows .empty {
  padding: calc(var(--pad) * 2) var(--pad);
  font-size: 13px;
  color: var(--ink-faint);
  max-width: 46ch;
}

/* ---------------------------------------------------- detail */

.detail {
  min-height: 0;
  overflow: hidden;
  padding: 26px calc(var(--pad) + 6px);
  display: flex;
  flex-direction: column;
  gap: 14px;
}

/* Image of the piece — the ONE thing on the page that keeps its colour. A
   production photograph is information, not decoration: the palette of a
   piece is part of what you are deciding to go and see. Everything around it
   stays achromatic, so the photograph carries all of it.
   El marc de línia fina segueix sent l'únic ornament. */
.shot {
  margin: 0;
  flex: 0 0 auto;
  height: clamp(110px, 21vh, 240px);
  border: var(--hair) solid var(--rule-firm);
  overflow: hidden;
  background: var(--ground-sunk);
}
.shot img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.detail .kicker {
  font-size: 10.5px;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: var(--ink-faint);
  display: flex;
  gap: 10px;
  align-items: center;
  flex: 0 0 auto;
}
.detail .kicker span { white-space: nowrap; }
.detail .kicker i { flex: 1; height: var(--hair); background: var(--rule); font-style: normal; }

.detail h2 {
  font-family: var(--font-title);
  font-weight: 400;
  font-size: clamp(22px, 2.6vw, 34px);
  line-height: 1.12;
  letter-spacing: -0.018em;
  margin: 0;
  text-wrap: balance;
  flex: 0 0 auto;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.facts {
  display: grid;
  grid-template-columns: 96px minmax(0, 1fr);
  gap: 0;
  border-top: var(--hair) solid var(--rule);
  flex: 0 0 auto;
}
.facts dt, .facts dd {
  margin: 0;
  padding: 7px 0;
  border-bottom: var(--hair) solid var(--rule);
  font-size: 12.5px;
  min-width: 0;
}
.facts dt {
  font-size: 10.5px;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--ink-faint);
  padding-top: 9px;
}
.facts dd { color: var(--ink-soft); overflow: hidden; text-overflow: ellipsis; }

.blurb {
  font-size: 13.5px;
  line-height: 1.5;
  color: var(--ink-soft);
  max-width: 68ch;
  margin: 0;
  /* Height is set in px by fitBlurb() to an exact number of lines. Letting
     flex size this box is what produced sliced half-lines. */
  flex: 0 0 auto;
  min-height: 0;
  display: -webkit-box;
  -webkit-line-clamp: var(--blurb-lines, 6);
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.detail .go {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  gap: 10px;
  align-self: flex-start;
  padding: 9px 16px;
  border: var(--hair) solid var(--rule-firm);
  font-size: 11.5px;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  text-decoration: none;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}
.detail .go:hover { background: var(--flip-bg); color: var(--flip-ink); }

.detail .provenance {
  flex: 0 0 auto;
  font-size: 10.5px;
  letter-spacing: 0.04em;
  color: var(--ink-faint);
  border-top: var(--hair) solid var(--rule);
  padding-top: 9px;
}

.detail.is-empty { justify-content: center; }
.detail.is-empty .placeholder {
  font-family: var(--font-title);
  font-size: 15px;
  font-style: italic;
  color: var(--ink-faint);
  max-width: 34ch;
}

.detail .close { display: none; }

/* ---------------------------------------------------- pager */

.pager {
  display: flex;
  align-items: center;
  gap: 4px;
  border-top: var(--hair) solid var(--rule-firm);
  padding: 0 var(--pad);
  min-height: 38px;
}
.pager .step {
  padding: 9px 12px;
  font-size: 11.5px;
  letter-spacing: 0.05em;
  color: var(--ink-soft);
  transition: color var(--dur) var(--ease);
}
.pager .step:hover:not(:disabled) { color: var(--ink); }
.pager .step:disabled { color: var(--ink-faint); opacity: 0.4; cursor: default; }
.pager .count {
  font-size: 11.5px;
  letter-spacing: 0.05em;
  color: var(--ink-soft);
  font-variant-numeric: tabular-nums;
  padding: 0 8px;
}
.pager .keys {
  margin-left: auto;
  font-size: 10.5px;
  letter-spacing: 0.05em;
  color: var(--ink-faint);
  white-space: nowrap;
}
.pager .keys kbd {
  font: inherit;
  border: var(--hair) solid var(--rule);
  padding: 1px 5px;
  margin: 0 1px;
}

/* ============================================================ 4:3 and squarer
   Less horizontal room: drop the form column, tighten the split. */

@media (max-aspect-ratio: 3/2) and (min-width: 900px) {
  .panes { grid-template-columns: minmax(0, 1fr) minmax(0, 0.92fr); }
  .index-head, .row {
    grid-template-columns: 122px minmax(0, 1fr) minmax(0, 132px);
    gap: 14px;
  }
  .r-form { display: none; }
}

/* With the map taking a third, the list loses the form column so the title
   keeps room to breathe. */
@media (min-width: 1150px) {
  body[data-map="on"] .index-head,
  body[data-map="on"] .row {
    grid-template-columns: 122px minmax(0, 1fr) minmax(0, 128px);
    gap: 14px;
  }
  body[data-map="on"] .r-form { display: none; }
}

/* ============================================================ narrow / phone
   One column. Detail becomes a full-viewport overlay, still no scroll. */

@media (max-width: 899px) {
  /* Denser rows: smaller type buys roughly a third more listings per screen,
     which matters most here because the map takes half the height. */
  :root { --row-h: 44px; --pad: 14px; }

  .masthead .tally { display: none; }
  .masthead { padding-top: 10px; padding-bottom: 9px; }
  .wordmark { font-size: 17px; }
  .masthead .stamp { font-size: 10px; }
  /* Al telèfon la data de construcció importa menys que poder escriure. */
  .masthead .contact { font-size: 10px; padding: 2px 8px; }

  /* Map above, list below. The list gets the larger share so that hiding the
     map is an option, not a necessity. */
  body[data-map="on"] .panes {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: minmax(0, 0.92fr) minmax(0, 1.08fr);
    grid-template-areas: "map" "index";
  }
  body[data-map="on"] .map {
    display: grid;
    border-right: 0;
    border-bottom: var(--hair) solid var(--rule-firm);
    padding: 10px;
  }
  body[data-map="on"] .map-note { left: 12px; bottom: 6px; font-size: 9.5px; }

  /* Landscape phone: stacking would leave three rows visible. Side by side
     instead — the map is squarish, so it costs width, not height. */
  @media (min-aspect-ratio: 1/1) {
    body[data-map="on"] .panes {
      grid-template-columns: minmax(0, 0.75fr) minmax(0, 1fr);
      grid-template-rows: minmax(0, 1fr);
      grid-template-areas: "map index";
    }
    body[data-map="on"] .map {
      border-bottom: 0;
      border-right: var(--hair) solid var(--rule-firm);
    }
  }

  .band { min-height: 44px; }
  .search { flex: 1; border-right: 0; }
  .chips { display: none; }
  .band .clear { display: none; }
  .band .filters-toggle,
  .band .map-toggle {
    display: block;
    padding: 0 var(--pad);
    font-size: 11.5px;
    letter-spacing: 0.05em;
    border-left: var(--hair) solid var(--rule);
    color: var(--ink-soft);
  }

  .panes { grid-template-columns: minmax(0, 1fr); }
  .index { border-right: 0; }

  .index-head { display: none; }

  .row {
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-rows: auto auto;
    gap: 1px 10px;
    align-content: center;
    padding-top: 6px;
    padding-bottom: 6px;
  }
  .r-when { grid-column: 2; grid-row: 1; text-align: right; font-size: 10.5px; }
  .r-title { grid-column: 1; grid-row: 1; font-size: 14.5px; line-height: 1.15; }
  .r-venue { grid-column: 1 / -1; grid-row: 2; font-size: 10.5px; }
  .r-form { display: none; }

  .detail {
    position: fixed;
    inset: 0;
    z-index: var(--z-overlay);
    background: var(--ground);
    padding: 18px var(--pad) calc(18px + env(safe-area-inset-bottom));
    transform: translateY(100%);
    visibility: hidden;
    transition: transform 220ms var(--ease), visibility 220ms;
  }
  .detail.is-open { transform: translateY(0); visibility: visible; }
  .detail.is-empty { display: none; }

  .detail .close {
    display: block;
    align-self: flex-start;
    padding: 8px 0;
    font-size: 11.5px;
    letter-spacing: 0.07em;
    text-transform: uppercase;
    color: var(--ink-faint);
    flex: 0 0 auto;
  }

  .pager { min-height: 46px; }
  .pager .keys { display: none; }

  /* filters open as a full-viewport sheet — a grid, never a scroller */
  .sheet {
    position: fixed;
    inset: 0;
    z-index: var(--z-overlay);
    background: var(--ground);
    display: none;
    grid-template-rows: auto minmax(0, 1fr) auto;
  }
  .sheet.is-open { display: grid; }
  .sheet-head, .sheet-foot {
    display: flex; align-items: center; justify-content: space-between;
    padding: 14px var(--pad);
    font-size: 11.5px; letter-spacing: 0.07em; text-transform: uppercase;
    color: var(--ink-faint);
  }
  .sheet-head { border-bottom: var(--hair) solid var(--rule-firm); }
  .sheet-foot { border-top: var(--hair) solid var(--rule-firm); }
  .sheet-body {
    min-height: 0; overflow: hidden;
    display: grid; grid-template-columns: 1fr 1fr;
    align-content: start;
  }
  .sheet-body .chip {
    display: block; width: 100%; text-align: left;
    padding: 15px var(--pad);
    border-bottom: var(--hair) solid var(--rule);
    border-right: var(--hair) solid var(--rule);
    font-size: 13px; text-transform: none; letter-spacing: 0.02em;
  }
  .sheet-body .chip-label {
    grid-column: 1 / -1;
    padding: 14px var(--pad) 6px;
    border-right: 0;
    border-top: var(--hair) solid var(--rule-firm);
  }
  .sheet-body .chip-label:first-child { border-top: 0; }
}

/* very short viewports (landscape phone): shrink the furniture, keep the rules */
@media (max-height: 460px) {
  :root { --row-h: 38px; }
  .masthead { padding-top: 7px; padding-bottom: 6px; }
  .wordmark { font-size: 16px; }
  .detail { padding-top: 14px; gap: 9px; }
  .detail h2 { -webkit-line-clamp: 2; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    transition-duration: 1ms !important;
    animation-duration: 1ms !important;
  }
}
