/* =====================================================================
   FONTS — VENDORED, and the UI face changed for readability
   =====================================================================

   Two changes here, both for the television.

   1. NOTHING IS FETCHED FROM GOOGLE ANY MORE. A boardroom on whatever
      wifi the meeting happens to have, with fonts.googleapis.com slow or
      blocked, was one stalled request away from showing this whole site
      in Times New Roman. The latin subsets are about 90 KB and travel
      with the page.

   2. THE INTERFACE FACE IS NOW INTER, NOT JOST. Jost is a geometric
      sans — beautiful, and the wrong tool at four metres: its letters
      are near-circles, its x-height is small, and a single-storey "a"
      and an "o" stop being different characters at distance. Inter was
      drawn for screens, with a tall x-height and letterforms that stay
      distinct when they get small or far away. Everything a visitor
      actually READS is set in it.

   Cormorant Garamond stays, for the two display headings only — the
   page title and the card title. Those are 40 px and up, where a
   high-contrast serif is legible and carries the brand. It is not used
   for anything small.
   ===================================================================== */
@font-face { font-family: "Inter"; font-weight: 300; font-style: normal; font-display: swap; src: url("../vendor/fonts/inter-latin-300-normal.woff2") format("woff2"); }
@font-face { font-family: "Inter"; font-weight: 400; font-style: normal; font-display: swap; src: url("../vendor/fonts/inter-latin-400-normal.woff2") format("woff2"); }
@font-face { font-family: "Inter"; font-weight: 500; font-style: normal; font-display: swap; src: url("../vendor/fonts/inter-latin-500-normal.woff2") format("woff2"); }
@font-face { font-family: "Inter"; font-weight: 600; font-style: normal; font-display: swap; src: url("../vendor/fonts/inter-latin-600-normal.woff2") format("woff2"); }
@font-face { font-family: "Cormorant Garamond"; font-weight: 300; font-style: normal; font-display: swap; src: url("../vendor/fonts/cormorant-garamond-latin-300-normal.woff2") format("woff2"); }
@font-face { font-family: "Cormorant Garamond"; font-weight: 400; font-style: normal; font-display: swap; src: url("../vendor/fonts/cormorant-garamond-latin-400-normal.woff2") format("woff2"); }
@font-face { font-family: "Cormorant Garamond"; font-weight: 500; font-style: normal; font-display: swap; src: url("../vendor/fonts/cormorant-garamond-latin-500-normal.woff2") format("woff2"); }

/* =====================================================================
   ALIBAG PROJECT MAP — stylesheet
   =====================================================================
   Sections
     1  Tokens
     2  Reset and page
     3  The map surface (and taming Leaflet's own chrome)
     4  Header
     5  Project rail
     6  Pins
     7  Connectivity lines and landmark chips
     8  The project card
     9  Bottom bar and tools
    10  Editor strip
    11  Small screens and landscape phones
   ===================================================================== */

/* ---------------------------------------------------------------- 1 */
/* Palette carried over from the 360 tour so the two products read as
   one brand — see css/style.css:12.1 of the tour. The map inverts it:
   the tour is ink-on-paper, the map is paper-on-ink. `--gold` is the
   pin colour, and it is the one place the map is allowed to shout. */
:root {
  /* ---------------------------------------------------------------
     ONE DARK DESIGN.

     Deep slate panels on deep slate land, light text, one warm gold
     accent. Everything floating — card, rail, tools, gate, boot — is
     painted from the six --surface tokens and nothing else, so there is
     exactly one place to change the whole interface.
     --------------------------------------------------------------- */

  --ink:        #1E2428;   /* page ground. matches theme.ground so the
                              page never shows a seam behind the canvas */

  --surface:      rgba(26, 32, 36, 0.94);
  --surface-2:    rgba(255, 255, 255, 0.05);
  --surface-3:    rgba(255, 255, 255, 0.10);
  --on-surface:     #E9EEF0;
  --on-surface-dim: #96A2A8;
  --surface-line: rgba(255, 255, 255, 0.13);

  /* Text sitting directly on the map, with no panel behind it. This is
     the headline and the hint, and it is NOT the same as panel text —
     it has the land behind it, not a surface. */
  --on-map:     #EFF3F4;
  --on-map-dim: #A7B3B8;

  --gold:       #D9A441;
  --gold-dim:   rgba(217, 164, 65, 0.55);
  --gold-ghost: rgba(217, 164, 65, 0.13);

  --serif: "Cormorant Garamond", Georgia, serif;
  --sans:  "Inter", "Segoe UI Variable", "Segoe UI", system-ui, Helvetica, Arial, sans-serif;

  --lift: 0 16px 40px rgba(0, 0, 0, 0.45);

  --sl: env(safe-area-inset-left, 0px);
  --sr: env(safe-area-inset-right, 0px);
  --sb: env(safe-area-inset-bottom, 0px);
  --st: env(safe-area-inset-top, 0px);
}

/* If a pale preset is ever chosen in the theme panel, the WHOLE set
   flips — not half of it. A partial flip is what produced light panels
   with light text and a headline nobody could read. */
:root.map-light {
  --ink:        #EFE7D9;
  --surface:      rgba(252, 250, 245, 0.95);
  --surface-2:    rgba(58, 48, 34, 0.055);
  --surface-3:    rgba(58, 48, 34, 0.10);
  --on-surface:     #2C2720;
  --on-surface-dim: #6B6353;
  --surface-line: rgba(58, 48, 34, 0.15);
  --on-map:     #2B2620;
  --on-map-dim: #6A6250;
  --gold:       #8C6A2F;
  --gold-dim:   rgba(140, 106, 47, 0.55);
  --gold-ghost: rgba(140, 106, 47, 0.12);
  --lift: 0 14px 34px rgba(92, 74, 44, 0.16);
}

/* ---------------------------------------------------------------- 2 */
* { box-sizing: border-box; }

html, body {
  margin: 0;
  height: 100%;
  background: var(--ink);
  color: var(--on-surface);
  font-family: var(--sans);
  font-weight: 300;
  -webkit-font-smoothing: antialiased;
  overscroll-behavior: none;   /* stop the pull-to-refresh fighting a pan */
}

button { font: inherit; color: inherit; cursor: pointer; }

/* Every element below that carries a `display` of its own would otherwise
   OUT-SPECIFY the user-agent's [hidden]{display:none} and stay on screen.
   That is why an empty tourUrl still drew a dead "Explore in 360" button
   and why the editor strip was visible on load. One rule, stated once,
   rather than a per-element hidden class. `.card` is the deliberate
   exception directly below it — it needs to stay laid out to fade. */
.editbar[hidden],
.card__media[hidden],
.card__conn[hidden],
.card__loc[hidden],
.card__note[hidden],
.card__cta[hidden],
.card__facts[hidden],
.theme[hidden],
.tool[hidden] { display: none !important; }

/* ---------------------------------------------------------------- 3 */
/* The map fills the viewport and everything else floats. `fixed` rather
   than `absolute` so the address bar sliding away on a phone does not
   leave a strip of body colour under the tiles. */
#map {
  position: fixed;
  inset: 0;
  z-index: 0;
  background: var(--ink);
  outline: none;
}

.maplibregl-canvas-container canvas { outline: none; }

/* MapLibre's default controls are a white browser-chrome box. Rebuilt to
   match everything else, and moved up so they clear the bottom bar. */
.maplibregl-ctrl-bottom-right { bottom: calc(44px + var(--sb)); }
.maplibregl-ctrl-bottom-left  { bottom: calc(44px + var(--sb)); }

.maplibregl-ctrl-group {
  background: var(--surface) !important;
  border: 1px solid var(--surface-line);
  border-radius: 4px;
  box-shadow: var(--lift) !important;
  backdrop-filter: blur(8px);
  overflow: hidden;
}
.maplibregl-ctrl-group button + button { border-top: 1px solid var(--surface-line); }
.maplibregl-ctrl-group button { width: 32px; height: 32px; background: none; }
.maplibregl-ctrl-group button:hover { background: var(--surface-3) !important; }
.maplibregl-ctrl-group button:not(:disabled) .maplibregl-ctrl-icon {
  /* The control icons ship as dark SVGs meant for a light chrome. One
     filter flips the whole set rather than shipping replacements. */
  filter: invert(1) brightness(0.78);
}
.maplibregl-ctrl button:disabled .maplibregl-ctrl-icon { opacity: 0.25; filter: invert(1); }

/* Attribution is a licence condition of OpenStreetMap. Toned down, never
   removed. */
.maplibregl-ctrl-attrib {
  background: var(--surface) !important;
  color: var(--on-surface-dim) !important;
  font-size: 10px;
  backdrop-filter: blur(6px);
  border-radius: 3px;
}
.maplibregl-ctrl-attrib a { color: var(--on-surface) !important; }
.maplibregl-ctrl-attrib-button { filter: invert(1) brightness(0.8); }

/* The MapLibre wordmark is not a licence condition — the OSM credit
   above is. It is removed to keep the corner to one line. */
.maplibregl-ctrl-logo { display: none !important; }

/* MapLibre positions markers with its own transform on the wrapper, so a
   marker's own element must not carry one of its own or the two fight. */
.maplibregl-marker { will-change: transform; }

/* THE VIGNETTE IS GONE.

   It was three stacked gradients darkening the top, the bottom and the
   corners, designed for white text over a dark basemap. Over pale land
   it did not read as a vignette at all — it read as a huge grey-to-black
   wash lying across the map, which is exactly what it looked like.

   Text on the map is dark now and needs no help to be read. If a future
   palette ever needs it back, a single very soft top gradient is the
   most that should return.
   ------------------------------------------------------------------ */

/* ---------------------------------------------------------------- 4 */
.head {
  position: fixed;
  top: calc(18px + var(--st));
  left: calc(26px + var(--sl));
  z-index: 600;
  max-width: min(46ch, 40vw);
  pointer-events: none;         /* the header must never block a drag */
}
.head * { pointer-events: auto; }

.brand { display: flex; align-items: center; gap: 10px; margin-bottom: clamp(14px, 2vw, 30px); }
.brand__logo { width: clamp(120px, 8.4vw, 200px); display: block; }
.brand__text { line-height: 1.15; }
.brand__top  { font-size: clamp(9px, 0.62vw, 12px); letter-spacing: 0.30em; color: var(--on-map-dim); }
.brand__main { font-family: var(--serif); font-size: clamp(19px, 1.5vw, 30px); letter-spacing: 0.06em; color: var(--on-map); }
.brand__sub  { font-size: clamp(8px, 0.55vw, 11px); letter-spacing: 0.34em; color: var(--on-map-dim); }

.eyebrow {
  margin: 0 0 10px;
  font-size: clamp(9px, 0.64vw, 12px);
  letter-spacing: 0.26em;
  text-transform: uppercase;
  /* --gold-on-map, NOT --gold. This line sits directly on a satellite
     photograph with no panel behind it, so it needs the palette's MAP
     accent, not its panel accent. On a pale scheme those two are
     opposites: cream reads over green fields and disappears on a cream
     card; the brown does the reverse. Falls back to --gold, so every
     dark scheme is unchanged. */
  color: var(--gold-on-map, var(--gold));
}
.title {
  margin: 0 0 12px;
  font-family: var(--serif);
  font-weight: 300;
  font-size: clamp(30px, 3.4vw, 62px);
  line-height: 1.04;
  white-space: pre-line;        /* the \n in config becomes a real break */
  color: var(--on-map);
}
.desc {
  margin: 0;
  font-size: clamp(12px, 0.82vw, 16px);
  line-height: 1.6;
  color: var(--on-map-dim);
  max-width: 34ch;
}

/* ---------------------------------------------------------------- 5 */
/* Mirrors the tour's #point-rail: a label, then one row per item. */
.rail {
  position: fixed;
  left: calc(26px + var(--sl));
  bottom: calc(78px + var(--sb));
  z-index: 600;
}
.rail__label {
  margin: 0 0 10px;
  font-size: 9px; letter-spacing: 0.32em; color: var(--on-map-dim);
}
.rail__list { display: flex; flex-direction: column; gap: 8px; }

.rail__btn {
  display: flex; align-items: center; gap: 11px;
  padding: 9px 16px 9px 12px;
  background: var(--surface);
  border: 1px solid var(--surface-line);
  border-radius: 999px;
  backdrop-filter: blur(10px);
  transition: background 0.25s, border-color 0.25s, transform 0.25s;
  text-align: left;
}
/* A HIGHLIGHT IS LAYERED OVER THE SURFACE, NOT SWAPPED FOR IT.

   --surface-3 is a TINT: 12% of something, meant to sit on top of the
   panel. Assigning it to `background` replaced the panel instead, so a
   selected row lost its plate and its dark text ended up on bare
   satellite imagery. That never showed while every scheme was dark — a
   dark tint over a photograph still reads dark — and it broke the
   moment Ivory became the default on 4 September 2026.

   Two backgrounds, tint first: the gradient is a flat fill of the tint
   painted over the surface underneath it. */
.rail__btn:hover {
  background: linear-gradient(var(--surface-3), var(--surface-3)), var(--surface);
  transform: translateX(3px);
}
.rail__btn--on {
  border-color: var(--gold-dim);
  background: linear-gradient(var(--surface-3), var(--surface-3)), var(--surface);
}

.rail__ic { width: 17px; height: 17px; display: block; flex: 0 0 auto; color: var(--sage); }
.rail__btn--on .rail__ic { color: var(--gold); }

.rail__name { font-size: 12px; letter-spacing: 0.16em; }
.rail__sub  { font-size: 9.5px; letter-spacing: 0.10em; color: var(--on-surface-dim); display: block; margin-top: 2px; }

/* ---------------------------------------------------------------- 6 */
/* Pins are plain DOM inside a Leaflet divIcon, so they can be animated
   with CSS instead of being redrawn. */
.pin {
  position: relative;
  width: 34px; height: 46px;
  cursor: pointer;
  transform-origin: 50% 100%;
  transition: transform 0.28s cubic-bezier(.2,.9,.3,1.4);
}
.pin:hover    { transform: scale(1.12); }
.pin--on      { transform: scale(1.16); }
.pin__svg     { width: 34px; height: 46px; display: block; filter: drop-shadow(0 6px 12px rgba(0,0,0,0.55)); }
.pin__body    { fill: var(--gold); }
.pin__hole    { fill: #ffffff; }

/* The halo pulses only while nothing is selected — once the visitor is
   reading a card, a throbbing pin is noise. */
.pin__halo {
  position: absolute; left: 50%; top: 13px;
  width: 34px; height: 34px; margin-left: -17px;
  border-radius: 50%;
  background: var(--gold);
  opacity: 0.30;
  animation: halo 2.6s ease-out infinite;
  pointer-events: none;
}
.pin--on .pin__halo, .pin--quiet .pin__halo { animation: none; opacity: 0; }
@keyframes halo {
  0%   { transform: scale(0.45); opacity: 0.42; }
  70%  { transform: scale(2.1);  opacity: 0;    }
  100% { transform: scale(2.1);  opacity: 0;    }
}

/* The name that rides beside the pin. Yellow, letterspaced, sitting on
   nothing — the same treatment as the reference. */
/* --tag-dy is written by placeTags() when two pins sit close enough for
   their names to collide. Nudging the LABEL rather than the pin keeps the
   pin on its real coordinate, which is the one thing that must not move. */
.pin__tag {
  position: absolute;
  left: 40px; top: 12px;
  white-space: nowrap;
  font-size: 11px;
  letter-spacing: 0.22em;
  color: var(--gold);
  text-shadow: 0 2px 10px rgba(0,0,0,0.85), 0 0 3px rgba(0,0,0,0.9);
  pointer-events: none;
  transform: translateY(var(--tag-dy, 0px));
  transition: transform 0.2s ease;
}
.pin--flip .pin__tag { left: auto; right: 40px; }

/* A hairline from the pin out to a nudged label, so a name that has been
   pushed clear still reads as belonging to its pin. */
.pin__leader {
  position: absolute; left: 30px; top: 20px;
  width: 12px; height: 1px;
  background: var(--gold-dim);
  transform-origin: 0 50%;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.2s;
}
.pin--nudged .pin__leader { opacity: 1; }
.pin--flip .pin__leader { left: auto; right: 30px; transform-origin: 100% 50%; }

/* The accuracy ring and the connectivity lines are no longer DOM — they
   are GL layers defined in js/map.js, because they have to lie ON the
   ground and follow the terrain when the map is tilted, which is the one
   thing that must NOT stay upright. Their colours live there. */

/* Motion is disabled wholesale for visitors who ask for that. */
@media (prefers-reduced-motion: reduce) {
  .pin, .pin__halo, .leaflet-fade-anim .leaflet-tile { animation: none !important; transition: none !important; }
}

/* ---------------------------------------------------------------- 7 */
.landmark {
  display: flex; align-items: center; gap: 6px;
  padding: 4px 10px 4px 7px;
  background: var(--surface);
  border: 1px solid var(--surface-line);
  border-radius: 999px;
  font-size: 10px;
  letter-spacing: 0.13em;
  color: var(--on-surface-dim);
  white-space: nowrap;
  backdrop-filter: blur(6px);
  transition: color 0.25s, border-color 0.25s;
  /* No translate here: the marker wrapper is anchored "center" and owns
     the positioning. A transform on this element would be composed on top
     of MapLibre's and throw the chip half a box off its point. */
}
.landmark__ic { width: 12px; height: 12px; color: var(--sage); flex: 0 0 auto; }
.landmark--on { color: var(--gold); border-color: var(--gold-dim); }
.landmark--on .landmark__ic { color: var(--gold); }

/* Travelling dashes on the connectivity lines. The dash pattern is set
   in JS (config.connectivity.dash); only the offset animates here, which
   is the cheap half. */

/* Distance pill sitting at the midpoint of each line. */
.conn-tag {
  font-size: 9.5px;
  letter-spacing: 0.14em;
  color: var(--gold);
  background: var(--surface);
  border: 1px solid var(--gold-ghost);
  border-radius: 999px;
  padding: 2px 8px;
  white-space: nowrap;
  backdrop-filter: blur(6px);   /* see the note on .landmark: no transform */
}
.conn-tag--approx { color: var(--on-surface-dim); border-color: var(--line); }

/* The pin cursor changes only in editor mode, so an ordinary visitor is
   never invited to drag something that will not move. */
.pin--draggable { cursor: grab; }
.pin--draggable:active { cursor: grabbing; }

/* ---------------------------------------------------------------- 8 */
.card {
  position: fixed;
  right: calc(26px + var(--sr));
  top: calc(50% + var(--st) / 2);
  transform: translateY(-50%);
  z-index: 700;
  width: min(360px, 34vw);
  max-height: min(78vh, 720px);
  overflow: auto;
  padding: 26px 26px 24px;
  background: var(--surface);
  border: 1px solid var(--surface-line);
  border-radius: 4px;
  box-shadow: var(--lift);
  backdrop-filter: blur(16px);

  /* Same visibility mechanism as the tour's .level — kept in flow so the
     measurements inside it are never taken at 0x0. */
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.4s ease, transform 0.4s ease, visibility 0.4s;
}
.card[hidden] { display: block; }        /* [hidden] would kill the fade */
.card--on { opacity: 1; visibility: visible; transform: translateY(-50%) translateX(0); }
.card:not(.card--on) { transform: translateY(-50%) translateX(14px); }

.card__close {
  position: absolute; right: 12px; top: 8px;
  background: none; border: 0; font-size: 24px; line-height: 1;
  color: var(--on-surface-dim); padding: 4px 8px;
}
.card__close:hover { color: var(--gold); }

/* THE 360 DOCKS HERE.

   This is not an image any more, it is a reserved hole. When a project
   card opens, js/map.js measures this box and flies the corner 360 card
   into it, so the tour becomes the card's header without ever being
   moved in the DOM — moving an iframe between parents destroys and
   reloads it, and the whole design of this page is that the tour loads
   once and never again.

   16:9 of the card's own width, so it holds its shape at every UI
   scale, and pulled out to the card's edges so it reads as the card's
   top rather than as a picture sitting inside it. */
.card__media {
  height: 0; padding-top: 52%;
  margin: -26px -26px 20px;
  background: #0D1214;
  border-radius: 3px 3px 0 0;
}
.card__eyebrow { margin: 0 0 8px; font-size: 9px; letter-spacing: 0.30em; color: var(--gold); }
.card__title   { margin: 0 0 10px; font-family: var(--serif); font-weight: 400; font-size: 30px; letter-spacing: 0.06em; color: var(--on-surface); }
.card__desc    { margin: 0 0 20px; font-size: 13px; line-height: 1.65; color: var(--on-surface-dim); }

.card__facts { display: grid; grid-template-columns: auto 1fr; gap: 9px 18px; margin-bottom: 20px; }
.card__fkey  { font-size: 10px; letter-spacing: 0.20em; color: var(--on-surface-dim); text-transform: uppercase; align-self: center; }
.card__fval  { font-size: 14px; color: var(--on-surface); }

.card__conn { border-top: 1px solid var(--surface-line); padding-top: 16px; }
.card__connlabel { margin: 0 0 10px; font-size: 9px; letter-spacing: 0.28em; color: var(--on-surface-dim); }
.card__connlist { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.card__connlist li { display: flex; justify-content: space-between; gap: 14px; font-size: 12px; color: var(--on-surface-dim); }
.card__connlist b { font-weight: 400; color: var(--on-surface); }
.card__connlist span { color: var(--gold); white-space: nowrap; }
.card__connlist span.approx { color: var(--muted); }

/* The provenance line. Deliberately visible rather than tucked in a
   comment: a pin that is a guess should say so on the page it is on. */
.card__note {
  margin: 16px 0 0; padding: 9px 11px;
  border-left: 2px solid var(--gold-dim);
  background: rgba(245, 197, 24, 0.06);
  font-size: 10.5px; line-height: 1.55; color: var(--on-surface-dim);
}

.card__cta {
  display: block; margin-top: 20px; padding: 13px 18px;
  text-align: center; text-decoration: none;
  border: 1px solid var(--gold-dim); color: var(--gold);
  font-size: 11px; letter-spacing: 0.24em;
  transition: background 0.25s, color 0.25s;
}
.card__cta:hover { background: var(--gold); color: var(--ink); }

/* ---------------------------------------------------------------- 9 */
.bar {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: 600;
  display: flex; align-items: center; justify-content: space-between;
  gap: 16px;
  padding: 12px calc(26px + var(--sr)) calc(12px + var(--sb)) calc(26px + var(--sl));
  pointer-events: none;
}
.bar * { pointer-events: auto; }
.bar__hint { margin: 0; font-size: 12px; color: var(--on-map-dim); letter-spacing: 0.06em; }
.bar__tools { display: flex; gap: 8px; }

.tool {
  padding: 8px 15px;
  background: var(--surface);
  border: 1px solid var(--surface-line);
  border-radius: 999px;
  font-size: 10.5px; letter-spacing: 0.18em; text-transform: uppercase;
  color: var(--on-surface-dim);
  backdrop-filter: blur(10px);
  transition: color 0.25s, border-color 0.25s, background 0.25s;
}
/* Layered, not swapped — same reason as .rail__btn--on above. */
.tool:hover {
  color: var(--on-surface);
  background: linear-gradient(var(--surface-3), var(--surface-3)), var(--surface);
}
.tool[aria-pressed="true"] { color: var(--gold); border-color: var(--gold-dim); }

/* ---- Location block on the card ---- */
.card__loc { border-top: 1px solid var(--surface-line); padding-top: 16px; margin-top: 16px; }

/* The coordinate is a button, not text, because the useful thing to do
   with a coordinate is take it somewhere else. */
.card__coord {
  display: block; width: 100%; text-align: left;
  padding: 8px 11px; margin-bottom: 9px;
  background: var(--surface-2);
  border: 1px solid var(--surface-line); border-radius: 3px;
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 11.5px; letter-spacing: 0.03em; color: var(--on-surface);
  transition: border-color 0.2s, color 0.2s;
}
.card__coord:hover { border-color: var(--gold-dim); color: var(--gold); }
.card__coord::after { content: " ⧉"; opacity: 0.5; }
.card__coord--copied { color: var(--gold); border-color: var(--gold-dim); }
.card__coord--copied::after { content: " copied"; font-size: 9.5px; letter-spacing: 0.14em; }

.card__locbtns { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.card__lbtn {
  padding: 9px 10px; text-align: center; text-decoration: none;
  border: 1px solid var(--surface-line); border-radius: 3px;
  font-size: 10px; letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--on-surface-dim); transition: color 0.2s, border-color 0.2s, background 0.2s;
}
.card__lbtn:hover { color: var(--gold); border-color: var(--gold-dim); background: var(--gold-ghost); }

/* --------------------------------------------------------------- 10 */
/* THEME PANEL
   A design tool that happens to live in the product. It sits on the LEFT
   so it never covers the project card on the right — the two are open at
   the same time constantly while picking colours, and a panel that hides
   the thing you are colouring is useless. */
.theme {
  position: fixed;
  left: calc(26px + var(--sl));
  top: calc(18px + var(--st));
  bottom: calc(70px + var(--sb));
  z-index: 800;
  width: 292px;
  display: flex; flex-direction: column;
  padding: 0 0 14px;
  background: var(--surface);
  border: 1px solid var(--surface-line);
  border-radius: 5px;
  box-shadow: var(--lift);
  backdrop-filter: blur(18px);
  overflow: hidden auto;
}

.theme__head {
  position: sticky; top: 0; z-index: 2;
  display: flex; align-items: center; justify-content: space-between;
  padding: 13px 14px 11px;
  background: inherit;
  border-bottom: 1px solid var(--surface-line);
}
.theme__title { font-size: 10px; letter-spacing: 0.30em; color: var(--gold); }
.theme__close { background: none; border: 0; font-size: 20px; line-height: 1; color: var(--on-surface-dim); padding: 0 4px; }
.theme__close:hover { color: var(--gold); }

.theme__presets { display: flex; flex-wrap: wrap; gap: 6px; padding: 12px 14px 4px; }
.theme__preset {
  padding: 5px 11px;
  background: var(--surface-2);
  border: 1px solid var(--surface-line); border-radius: 999px;
  font-size: 10px; letter-spacing: 0.12em; color: var(--on-surface-dim);
  transition: color 0.2s, border-color 0.2s;
}
.theme__preset:hover { color: var(--gold); border-color: var(--gold-dim); }

.theme__section { padding: 12px 14px 0; }
.theme__label { margin: 0 0 9px; font-size: 9px; letter-spacing: 0.28em; color: var(--on-surface-dim); }

.theme__grid { display: grid; grid-template-columns: 1fr 1fr; gap: 7px 10px; }

.theme__row { display: flex; align-items: center; gap: 8px; min-width: 0; }
.theme__swatch {
  /* A native colour input, stripped of its chrome so it reads as a
     swatch. -webkit-color-swatch-wrapper is the only way to kill the
     inset padding Chrome adds. */
  appearance: none; -webkit-appearance: none;
  width: 22px; height: 22px; flex: 0 0 auto;
  padding: 0; border: 1px solid var(--surface-line); border-radius: 3px;
  background: none; cursor: pointer;
}
.theme__swatch::-webkit-color-swatch-wrapper { padding: 0; }
.theme__swatch::-webkit-color-swatch { border: 0; border-radius: 2px; }
.theme__swatch::-moz-color-swatch { border: 0; border-radius: 2px; }
.theme__name {
  font-size: 10.5px; color: var(--on-surface-dim); letter-spacing: 0.04em;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

.theme__sliders { display: flex; flex-direction: column; gap: 11px; }
.theme__srow { display: grid; grid-template-columns: 1fr auto; gap: 3px 8px; }
.theme__sname { font-size: 10.5px; color: var(--on-surface-dim); }
.theme__sval  { font-size: 10.5px; color: var(--gold); font-variant-numeric: tabular-nums; }
.theme__range {
  grid-column: 1 / -1;
  appearance: none; -webkit-appearance: none;
  width: 100%; height: 3px; padding: 0;
  background: rgba(255,255,255,0.13); border-radius: 999px; cursor: pointer;
}
.theme__range::-webkit-slider-thumb {
  appearance: none; -webkit-appearance: none;
  width: 13px; height: 13px; border-radius: 50%;
  background: var(--gold); border: 0; cursor: grab;
}
.theme__range::-moz-range-thumb {
  width: 13px; height: 13px; border-radius: 50%;
  background: var(--gold); border: 0; cursor: grab;
}

.theme__foot { display: flex; gap: 8px; padding: 16px 14px 0; }
.theme__btn {
  flex: 1; padding: 9px 10px;
  background: var(--surface-2);
  border: 1px solid var(--surface-line); border-radius: 3px;
  font-size: 10px; letter-spacing: 0.16em; text-transform: uppercase; color: var(--on-surface-dim);
  transition: color 0.2s, border-color 0.2s, background 0.2s;
}
.theme__btn:hover { color: var(--on-surface); }
.theme__btn--go { color: var(--gold); border-color: var(--gold-dim); }
.theme__btn--go:hover { background: var(--gold); color: var(--ink); }

.theme__hint { margin: 10px 14px 0; font-size: 9.5px; line-height: 1.5; color: var(--on-surface-dim); }
.theme__hint code { color: var(--on-surface); }

/* --------------------------------------------------------------- 10b */
.editbar {
  position: fixed; left: 50%; top: calc(14px + var(--st));
  transform: translateX(-50%);
  z-index: 900;
  display: flex; align-items: center; gap: 9px;
  padding: 8px 16px;
  background: rgba(245, 197, 24, 0.12);
  border: 1px solid var(--gold-dim);
  border-radius: 999px;
  font-size: 11px; letter-spacing: 0.10em; color: var(--gold);
  backdrop-filter: blur(10px);
}
.editbar__sel {
  background: rgba(0,0,0,0.28);
  border: 1px solid var(--gold-dim);
  border-radius: 3px;
  color: var(--gold);
  font: inherit; font-size: 11px;
  padding: 2px 5px; margin: 0 2px;
}
.editbar__sel option { background: #21282B; color: #EEF1F5; }
.editbar b { font-weight: 500; }

.editbar__dot { width: 7px; height: 7px; border-radius: 50%; background: var(--gold); animation: halo 1.4s ease-out infinite; }

/* --------------------------------------------------------------- 11 */
/* Fluid clamps do most of the work. These are the two cases clamps
   cannot solve: not enough WIDTH for a side card, and not enough HEIGHT
   on a landscape phone — the height case is the one that bit the tour
   (handbook 12.3), so it is handled explicitly here rather than left to
   a width query that will not fire. */
@media (max-width: 900px) {
  .head { max-width: none; right: calc(26px + var(--sr)); }
  .desc { display: none; }

  /* The card becomes a sheet rising from the bottom. Position is reset
     in full so nothing from the desktop transform survives. */
  .card {
    left: 0; right: 0; top: auto; bottom: 0;
    width: auto; max-height: 62vh;
    border-radius: 14px 14px 0 0;
    transform: translateY(100%);
    padding-bottom: calc(24px + var(--sb));
  }
  .card--on { transform: translateY(0); }
  .card:not(.card--on) { transform: translateY(100%); }
  .card__media { margin-top: -26px; }

  .rail { bottom: calc(70px + var(--sb)); }
  .rail__btn { padding: 7px 13px 7px 10px; }
  .bar__hint { display: none; }
}

/* Below this width the eyebrow wraps to two lines and eats a third of the
   map. It is the least load-bearing line on the page, so it goes. */
@media (max-width: 620px) {
  .eyebrow { display: none; }
  .card { max-height: 56vh; }
}

/* The theme panel on a phone. It is a design tool, so when it is open it
   simply takes the screen — a 292px column beside a 390px viewport would
   leave neither the panel nor the map usable. The tools row also wraps
   here, because four buttons do not fit on one line. */
@media (max-width: 700px) {
  .theme {
    left: 0; right: 0; top: auto; bottom: 0;
    width: auto; max-height: 74vh;
    border-radius: 14px 14px 0 0;
    padding-bottom: calc(14px + var(--sb));
  }
  .theme__grid { grid-template-columns: 1fr 1fr; }
  .bar { flex-wrap: wrap; }
  .bar__tools { flex-wrap: wrap; justify-content: flex-end; }
}

/* Under ~360px the two-column swatch grid clips its labels. */
@media (max-width: 380px) {
  .theme__grid { grid-template-columns: 1fr; }
}

@media (max-height: 520px) {
  /* Landscape phone. The title and the rail cannot both have the left
     column, so the rail wins — it is the control, the title is decoration. */
  .title { font-size: 24px; }
  .eyebrow { display: none; }
  .brand { margin-bottom: 8px; }
  .rail { bottom: calc(58px + var(--sb)); }
  .rail__sub { display: none; }
  .card { max-height: 84vh; }
}

@media (max-width: 480px) {
  .head { top: calc(12px + var(--st)); left: calc(16px + var(--sl)); }
  .rail { left: calc(16px + var(--sl)); }
  .title { font-size: 26px; }
  .pin__tag { font-size: 10px; letter-spacing: 0.16em; }
}

/* =====================================================================
   12  LOADING, FOCUS, AND THE TOUR GATE
   ===================================================================== */

/* ---- Boot screen ----
   A map is not "loaded" when the page is; it is loaded when the style
   has parsed and the first tiles have arrived. Before that the visitor
   sees a coloured rectangle with two pins floating on nothing, which
   looks broken rather than slow. This holds the door shut until there is
   something worth showing, and — importantly — fades rather than cuts,
   so a fast connection does not produce a flash. */
.boot {
  position: fixed; inset: 0; z-index: 9500;
  display: flex; align-items: center; justify-content: center;
  background: var(--ink);
  transition: opacity 0.55s ease, visibility 0.55s;
}
.boot--gone { opacity: 0; visibility: hidden; pointer-events: none; }

.boot__inner { text-align: center; width: min(280px, 70vw); }
.boot__mark  { margin-bottom: 26px; }
.boot__mark img { width: 190px; max-width: 100%; }
.boot__mark .brand__text { color: var(--on-map); }

.boot__bar {
  height: 2px; border-radius: 2px;
  background: var(--surface-3);
  overflow: hidden;
}
.boot__bar span {
  display: block; height: 100%; width: 0%;
  background: var(--gold);
  transition: width 0.45s ease;
}
.boot__msg {
  margin: 14px 0 0;
  font-size: 10px; letter-spacing: 0.28em; text-transform: uppercase;
  color: var(--on-map-dim);
}

/* ---- Focus ----
   With a project open, the headline is competing with the card for the
   same attention. It steps back rather than disappearing, so the page
   still reads as the same page. */
/* With a project open the headline steps BACK. It does not go away.
   0.22 was effectively invisible — the note that it "is hidden" was
   right, and a masthead that vanishes makes the page look broken rather
   than focused. The sub-line, which is an instruction the visitor has
   already followed, is the part that can go. */
/* With a project open, only the two lines that have done their job go:
   the sub-line is an instruction the visitor has already followed, and
   the bottom hint says the same thing again. THE MASTHEAD STAYS AT FULL
   STRENGTH. Fading it was my idea and it was wrong — a title at 22%
   does not read as "focused", it reads as broken, which is exactly what
   it looked like. */
body.is-focused .desc      { opacity: 0; pointer-events: none; }
body.is-focused .bar__hint { opacity: 0; }
.desc, .bar__hint { transition: opacity 0.45s ease; }

/* ---- The tour gate ---- */
.gate {
  position: fixed; inset: 0; z-index: 9000;
  display: flex; align-items: center; justify-content: center;
  opacity: 0; visibility: hidden;
  transition: opacity 0.35s ease, visibility 0.35s;
}
.gate[hidden] { display: flex; }          /* [hidden] would kill the fade */
.gate--on { opacity: 1; visibility: visible; }

.gate__scrim {
  position: absolute; inset: 0;
  background: rgba(58, 46, 28, 0.48);
  backdrop-filter: blur(5px);
}

.gate__panel {
  position: relative;
  width: min(460px, calc(100vw - 40px));
  padding: 40px 40px 34px;
  text-align: center;
  background: var(--surface);
  border: 1px solid var(--surface-line);
  border-radius: 5px;
  box-shadow: var(--lift);
  transform: translateY(14px) scale(0.985);
  transition: transform 0.35s cubic-bezier(.2,.9,.3,1.05);
}
.gate--on .gate__panel { transform: none; }

.gate__close {
  position: absolute; right: 14px; top: 10px;
  background: none; border: 0; font-size: 24px; line-height: 1;
  color: var(--on-surface-dim); padding: 4px 8px;
}
.gate__close:hover { color: var(--gold); }

.gate__eyebrow { margin: 0 0 12px; font-size: 9px; letter-spacing: 0.34em; color: var(--gold); }
.gate__title {
  margin: 0 0 14px;
  font-family: var(--serif); font-weight: 300;
  font-size: clamp(30px, 3.2vw, 44px); letter-spacing: 0.05em;
  color: var(--on-surface);
}
.gate__desc { margin: 0 0 8px; font-size: 13.5px; line-height: 1.65; color: var(--on-surface-dim); }
.gate__meta { margin: 0 0 26px; font-size: 10.5px; letter-spacing: 0.2em; text-transform: uppercase; color: var(--on-surface-dim); }

.gate__go {
  display: block; padding: 15px 20px;
  background: var(--gold); color: var(--ink);
  border: 1px solid var(--gold);
  text-decoration: none;
  font-size: 11.5px; letter-spacing: 0.26em; text-transform: uppercase;
  transition: filter 0.2s;
}
.gate__go:hover { filter: brightness(1.08); }

.gate__back {
  margin-top: 14px; background: none; border: 0;
  font-size: 10.5px; letter-spacing: 0.18em; text-transform: uppercase;
  color: var(--on-surface-dim);
}
.gate__back:hover { color: var(--on-surface); }

@media (max-width: 620px) {
  .gate__panel { padding: 32px 24px 26px; }
}

/* The landmark chips are GL symbols in normal use; these are the
   temporary HTML stand-ins the pin editor puts up so they can be
   dragged. Deliberately obvious — you should be able to see at a glance
   that you are in an editing mode. */
.landmark--draggable {
  cursor: grab;
  padding: 5px 11px;
  background: var(--surface);
  border: 1px dashed var(--gold);
  border-radius: 999px;
  font-size: 11px; letter-spacing: 0.12em;
  color: var(--gold);
  white-space: nowrap;
  box-shadow: var(--lift);
}
.landmark--draggable:active { cursor: grabbing; }

/* =====================================================================
   16. THE 360, IN THE CORNER  (and the panel it opens into)
   =====================================================================

   The mirror of what the retired present.html did. There the tour filled
   the screen and the map was a corner card; here the MAP takes priority
   — it is the thing the client wanted first — and the tour is the small
   one, opening into a sheet down the left with the project card still
   readable on the right.

   ONE ELEMENT, TWO SIZES. `.tourwrap` holds one iframe. `--mini` is the
   corner card, `--panel` is the sheet, and everything in between is a
   transition on that one box. The frame is never rebuilt, so opening the
   tour is not a page load and there is no second progress bar in front
   of a client.
   ===================================================================== */

.tourwrap {
  position: fixed;
  z-index: 650;
  overflow: hidden;
  background: var(--ink);
  border: 1px solid var(--surface-line);
  box-shadow: var(--lift);
  transition:
    left 0.6s cubic-bezier(0.22, 0.9, 0.24, 1),
    right 0.6s cubic-bezier(0.22, 0.9, 0.24, 1),
    top 0.6s cubic-bezier(0.22, 0.9, 0.24, 1),
    bottom 0.6s cubic-bezier(0.22, 0.9, 0.24, 1),
    width 0.6s cubic-bezier(0.22, 0.9, 0.24, 1),
    height 0.6s cubic-bezier(0.22, 0.9, 0.24, 1),
    border-radius 0.6s cubic-bezier(0.22, 0.9, 0.24, 1),
    border-color 0.35s ease;
}

/* Corner card, bottom RIGHT. It started bottom-left, under the project
   rail; the client asked for it on the same side as everything else you
   read. That corner had to be cleared first — see the note on the
   MapLibre controls in js/map.js, and `body.card-open` further down. */
.tourwrap--mini {
  right: calc(26px + var(--sr));
  bottom: calc(78px + var(--sb));
  left: auto; top: auto;
  width: clamp(200px, 20vw, 400px);
  height: var(--tour-h);
  border-radius: 6px;
  cursor: pointer;
}
.tourwrap--mini:hover { border-color: var(--gold-dim); }

/* THE PANEL OPENS ON THE RIGHT.

   It used to open on the left and stop short of the project card. It
   does not have to any more: opening the tour hides that card, and
   picking a project shrinks the tour back to its corner, so the two are
   never on screen together and the panel can have the whole right-hand
   side. What stays visible down the left is the brand, the title and the
   map itself — enough that the tour reads as a panel over the map rather
   than as a different page. */
.tourwrap--panel {
  z-index: 720;             /* over the card, which fades but stays laid out */
  left: max(34%, 420px);
  top: calc(20px + var(--st));
  /* Stops above the bottom bar rather than over it: the bar is where
     Connectivity, 2D view and the basemap toggle live, and clipping the
     left end of that row is worse than a 60-pixel shorter tour. */
  bottom: calc(72px + var(--sb));
  right: calc(20px + var(--sr));
  width: auto; height: auto;
  border-radius: 10px;
  cursor: default;
}
@media (max-width: 1100px) {
  .tourwrap--panel { left: calc(20px + var(--sl)); }
}

.tourwrap__frame { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; display: block; }

/* ---- The cover ----
   A live 360 in a 300-pixel box is a moving smudge, and it costs a WebGL
   context and a stream of texture uploads for something nobody can read.
   So the corner shows a still of the first vantage point with a play
   mark on it, and the frame behind only starts when it is opened. */
.tourwrap__cover {
  position: absolute; inset: 0; z-index: 2;
  background-size: cover; background-position: 50% 50%;
  display: flex; align-items: flex-end;
  transition: opacity 0.45s ease;
}
.tourwrap__cover::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(to top, rgba(8, 12, 14, 0.88) 0%, rgba(8, 12, 14, 0.15) 55%, rgba(8, 12, 14, 0.3) 100%);
}
.tourwrap--panel .tourwrap__cover { opacity: 0; pointer-events: none; }

/* A LABEL, NOT A PLAY TRIANGLE.

   The triangle is the universal sign for "video", and this is not a
   video — it is a place you walk into. Across a boardroom a 46px glyph
   is also barely a shape, whereas two words are still two words. */
.tourwrap__cta {
  position: absolute; left: 50%; top: 46%; transform: translate(-50%, -50%);
  z-index: 2;
  display: flex; align-items: center; gap: 0.5em;
  padding: 0.75em 1.4em;
  background: rgba(12, 16, 18, 0.62);
  border: 1px solid rgba(255, 255, 255, 0.34);
  border-radius: 999px;
  backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px);
  font-size: 12px; font-weight: 500; letter-spacing: 0.22em; text-transform: uppercase;
  line-height: 1; color: var(--on-map); white-space: nowrap;
  transition: border-color 0.25s, background 0.25s, color 0.25s;
}
.tourwrap__cta i { font-style: normal; font-size: 1.35em; line-height: 0; margin-top: -0.08em; }
.tourwrap--mini:hover .tourwrap__cta {
  border-color: var(--gold); background: rgba(217, 164, 65, 0.28); color: #fff;
}

.tourwrap__tag {
  position: relative; z-index: 1;
  display: flex; flex-direction: column; gap: 3px;
  padding: 12px 14px;
}
.tourwrap__eyebrow { font-size: 9px; letter-spacing: 0.3em; color: var(--gold); }
.tourwrap__name { font-family: var(--serif); font-size: 18px; letter-spacing: 0.07em; color: var(--on-map); line-height: 1; }

/* BOTTOM-RIGHT, and it took three tries to find a corner that was free.
   The tour puts its brand top-left, its destination toggles top-centre,
   its MENU top-right, the compass below that, the point rail down the
   left and the facts panel bottom-left. Bottom-right is the one corner
   it does not use. A labelled pill rather than a bare cross, because
   this is read from across a room. */
.tourwrap__close {
  position: absolute; right: 18px; bottom: 18px; z-index: 3;
  display: none; align-items: center; gap: 0.6em;
  padding: 0.7em 1.2em;
  background: var(--surface); border: 1px solid var(--surface-line); border-radius: 999px;
  font-size: 12px; letter-spacing: 0.24em; text-transform: uppercase;
  line-height: 1; color: var(--on-surface);
  backdrop-filter: blur(10px);
  cursor: pointer;
  zoom: var(--ui, 1);
  transition: border-color 0.25s, color 0.25s;
}
.tourwrap--panel .tourwrap__close { display: flex; }
.tourwrap__close:hover { border-color: var(--gold-dim); color: var(--gold); }
.tourwrap__close span { font-size: 15px; line-height: 0.8; }

/* With the tour open the rail and the bottom bar would sit on top of the
   sheet. They fade rather than vanish, so the screen does not lurch. */
/* THE CARD AND THE TOUR ARE NEVER BOTH OPEN.

   The panel now owns the right-hand side, which is where the card lives.
   Rather than shuffle the card somewhere it does not belong, the two
   simply take turns: opening the tour fades the card out, and picking a
   project (a pin, or a row in the rail) shrinks the tour back to its
   corner and brings the card back. js/map.js drives the second half of
   that; this is the first. */
body.tour-open .rail,
body.tour-open .card,
body.tour-open .bar__hint { opacity: 0; pointer-events: none; transition: opacity 0.35s ease; }

/* The rail has the bottom-left corner to itself again, now that the 360
   card has moved across. */
:root { --tour-h: clamp(124px, 12.5vw, 250px); }

/* DOCKED — the third state, and the answer to "don't let it disappear".

   The corner card and the project card both want the bottom-right, and
   the project card is too tall on a television to stack anything under
   it. Hiding the 360 was the first answer and the wrong one: the tour is
   the thing being sold, and it vanished at the exact moment somebody
   showed interest in a project.

   So instead of hiding, it MOVES. js/map.js measures `.card__media` and
   sets these four numbers, and the same box that was sitting in the
   corner slides up and becomes the card's header image. Nothing is
   re-parented, so the iframe inside it never reloads — which is the only
   reason this is possible at all.

   No `zoom` here: the geometry comes from getBoundingClientRect, which
   already reports real viewport pixels, and zooming it again would
   double-apply the UI scale. */
.tourwrap--docked {
  /* ABOVE THE CARD. The card is z-index 700 and this box is 650, so
     docked into the card's own header hole it was drawn behind it — a
     dark empty rectangle where the 360 should be. It only needs to win
     while it is sitting inside the card. */
  z-index: 750;
  border-radius: 3px 3px 0 0;
  cursor: pointer;
  box-shadow: none;
  border-color: transparent;
}
.tourwrap--docked:hover { border-color: var(--gold-dim); }


/* =====================================================================
   17. TV SIZING
   =====================================================================

   This map is shown on a boardroom television, read from across a table,
   and every size in this stylesheet was chosen for a laptop at arm's
   length. `--ui` is the one number that fixes that: `ui.scale` in
   js/config.js writes it, and everything the visitor reads is scaled by
   it in one place.

   WHY `zoom` AND NOT A FONT SIZE. These panels are laid out in pixels —
   paddings, gaps, icon sizes, the card's width. Scaling only the type
   would give big words in small boxes. `zoom` scales the whole box and
   its insets together, which is exactly what "make it bigger" means
   here, and it costs one line per panel instead of touching ninety
   values. Chrome, Edge and Safari have supported it for years; Firefox
   since 126. In a browser that ignores it, everything is simply the
   laptop size it was before — no layout breaks either way.

   `.bar` is NOT in the list: it spans the full width, so zooming it
   would make it wider than the screen. Its two children are zoomed
   instead, which gets the same result.

   The map's own labels are not CSS at all — they are drawn by the GPU —
   so they follow `ui.mapScale`, applied in js/map.js. */
.head, .rail, .card, .editbar, .theme, .tourwrap--mini {
  zoom: var(--ui, 1);
}
/* ...but never the docked state: its box comes from
   getBoundingClientRect, which is already in real viewport pixels. */
.tourwrap--docked { zoom: 1; }
.bar__tools, .bar__hint { zoom: var(--ui, 1); }

/* =====================================================================
   18. THE COLOUR MENU
   =====================================================================
   Client-facing, not a developer tool: the palettes were sent to be
   looked at, so they are on the map rather than in a config file. Top
   right, above the map's own zoom buttons, which are pushed down to
   make room.
   ===================================================================== */

.pal { position: fixed; z-index: 760; right: calc(26px + var(--sr)); top: calc(20px + var(--st)); zoom: var(--ui, 1); }

.pal__btn {
  display: flex; align-items: center; gap: 0.65em;
  padding: 0.62em 1.05em;
  background: var(--surface); border: 1px solid var(--surface-line); border-radius: 999px;
  font-size: 11px; letter-spacing: 0.22em; text-transform: uppercase;
  color: var(--on-surface-dim);
  backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
  transition: color 0.22s, border-color 0.22s;
}
.pal__btn:hover, .pal__btn[aria-expanded="true"] { color: var(--on-surface); border-color: var(--gold-dim); }
.pal__dot { width: 0.85em; height: 0.85em; border-radius: 50%; background: var(--gold); flex: none;
            box-shadow: 0 0 0 1px rgba(255,255,255,0.22); }

.pal__list {
  margin-top: 8px;
  padding: 6px;
  background: var(--surface); border: 1px solid var(--surface-line); border-radius: 8px;
  box-shadow: var(--lift);
  backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
  min-width: 190px;
}
.pal__item {
  display: flex; align-items: center; gap: 0.7em; width: 100%;
  padding: 0.55em 0.7em;
  background: none; border: 0; border-radius: 5px;
  font-size: 11px; letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--on-surface-dim); text-align: left;
  transition: background 0.18s, color 0.18s;
}
.pal__item:hover { background: var(--surface-2); color: var(--on-surface); }
.pal__item.on { color: var(--on-surface); background: var(--gold-ghost); }

/* Three swatches per row — the accent and both project colours. It is
   the only honest preview: a single dot cannot tell you that a scheme's
   two projects are hard to tell apart. */
.pal__sw { display: flex; flex: none; }
.pal__sw i { display: block; width: 11px; height: 16px; }
.pal__sw i:first-child { border-radius: 3px 0 0 3px; }
.pal__sw i:last-child  { border-radius: 0 3px 3px 0; }

/* The map's own controls move down so the menu can have the corner. */
.maplibregl-ctrl-top-right { top: calc(58px + var(--st)); }
