/* Self-hosted, latin subset (Portuguese needs nothing past it), both
   variable: one file holds every weight. SIL Open Font License, in fonts/. */
@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");
}

@font-face {
  font-family: "Martian Mono";
  font-style: normal;
  font-weight: 100 800;
  font-display: swap;
  src: url(fonts/martian-mono-latin.woff2) format("woff2");
}

:root {
  /* Palette: a warm night lit by one hue, the dots' own. Every color on the
     page comes from here; app.js reads the histogram's from it too.
     -raw values are bare channels, for rgba() with an alpha. */
  --night: #000000;          /* the map */
  --ink: #0b0908;            /* opaque surfaces: dialog, sheets, error */
  --ink-raw: 11, 9, 8;
  --glass: rgba(var(--ink-raw), 0.6); /* every floating panel and chip */
  --lamp: #ede3d1;           /* primary text and figures, active states; what dots saturate toward */
  --lamp-raw: 237, 227, 209;
  --soft: #cfc5b4;           /* running text */
  --dim: #8f8473;            /* labels, secondary text */
  --ember: #d9a99f;          /* accent: links, lit bars; the dot color lifted to read as text */
  --ember-raw: 139, 87, 79;  /* the dot color itself, kepler reference */
  --spark-raw: 255, 214, 170; /* the hot core of every glow */
  --hair: rgba(var(--lamp-raw), 0.14);    /* rules and borders */
  --hair-hi: rgba(var(--lamp-raw), 0.32); /* hover and open borders */
  /* The glow of one lit lamp: the wordmark's "l" and the loading dot. */
  --halo: 0 0 6px rgba(var(--spark-raw), 0.8), 0 0 22px rgba(var(--ember-raw), 0.9), 0 0 48px rgba(var(--ember-raw), 0.7);
  /* The faint glow of the type in the dots' own color: the wordmark. */
  --aura: 0 0 8px rgba(var(--ember-raw), 0.9), 0 0 22px rgba(var(--ember-raw), 0.65), 0 0 44px rgba(var(--ember-raw), 0.4);
  /* The same turned down, for the place and the year. */
  --aura-low: 0 0 8px rgba(var(--ember-raw), 0.6), 0 0 22px rgba(var(--ember-raw), 0.35);
  /* A lit thing's smaller glow: active tiles, the loading wire. */
  --lit: 0 0 8px rgba(var(--spark-raw), 0.8), 0 0 24px rgba(var(--ember-raw), 0.9);
  --display: "Bricolage Grotesque", system-ui, sans-serif;
  --mono: "Martian Mono", ui-monospace, monospace;
  --gutter: 20px;
  --rail: 256px;          /* the left-hand column every panel stacks in */
  /* The page runs under the notch and the home bar (viewport-fit=cover):
     every edge keeps its gutter clear of them. */
  --top: calc(var(--gutter) + env(safe-area-inset-top, 0px));
  --right: calc(var(--gutter) + env(safe-area-inset-right, 0px));
  --bottom: calc(var(--gutter) + env(safe-area-inset-bottom, 0px));
  --left: calc(var(--gutter) + env(safe-area-inset-left, 0px));
}

* { box-sizing: border-box; }

[hidden] { display: none !important; }

html, body {
  height: 100%;
  margin: 0;
  background: var(--night);
  color: var(--lamp);
  overflow: hidden;
  overscroll-behavior: none;
  font-family: var(--display);
  -webkit-font-smoothing: antialiased;
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

#map { position: absolute; top: 0; right: 0; bottom: 0; left: 0; }

/* Basemap is a plain black background; this only softens MapLibre's canvas
   in case a style layer ever sneaks in. */
#map .maplibregl-canvas { outline: none; }
.maplibregl-ctrl-attrib { display: none; }

button {
  font: inherit;
  color: inherit;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}

:focus-visible {
  outline: 1px solid var(--lamp);
  outline-offset: 2px;
}

/* Every floating panel over the map: masthead, light controls, state picker,
   timeline and the loading notice share the same smoked glass. */
.panel {
  background: var(--glass);
  border: 1px solid var(--hair);
  border-radius: 4px;
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
}

/* ---------- rail ---------- */

/* Intro, states and the hover still, top to bottom. */
.rail {
  position: absolute;
  top: var(--top);
  left: var(--left);
  bottom: var(--bottom);
  z-index: 10;
  width: var(--rail);
  display: flex;
  flex-direction: column;
  gap: 8px;
  pointer-events: none;
}

.rail > * { flex: none; pointer-events: auto; }

/* ---------- masthead ---------- */

.masthead { padding: 14px 16px; text-align: center; }

.wordmark {
  margin: 0;
  font-weight: 300;
  font-size: clamp(30px, 4.2vw, 48px);
  line-height: 0.95;
  letter-spacing: -0.035em;
  color: var(--dim);
  /* The whole word glows faintly in the dots' own color. */
  text-shadow: var(--aura);
}

/* The "il" of brasIL / ILuminado is the one lit thing in the type. */
.wordmark .lit {
  font-weight: 800;
  color: var(--lamp);
  text-shadow: var(--halo);
}

.dek {
  margin: 10px 0 0;
  font-size: 14px;
  line-height: 1.4;
  color: var(--dim);
  text-wrap: balance;
}

/* The place and its numbers: a panel of their own, top right, over the
   sliders. */
.readout {
  align-self: stretch;
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: 14px 16px;
}

/* A rule between the place and its figures, and between the figures. */
.readout hr, .sector hr, .fold-rule {
  width: 100%;
  margin: 0;
  border: 0;
  border-top: 1px solid var(--hair);
}

/* The place takes the wordmark's color and its glow: the one lit name
   among the off-white figures. */
.place {
  color: var(--dim);
  font-weight: 800;
  --place: clamp(22px, 2.2vw, 26px);
  font-size: var(--place);
  letter-spacing: -0.02em;
  /* One line always, of one height, so the panels under it keep their
     place: app.js (fitPlace) shrinks the long names to fit. */
  line-height: calc(var(--place) * 1.1);
  white-space: nowrap;
  /* Clipped sideways only, so the glow is free above and below; the
     padding, taken back by the margin, is room for it at the sides. */
  overflow-x: clip;
  text-shadow: var(--aura-low);
  padding: 0 16px;
  margin: 0 -16px;
}

/* The filters' panel: a header that says which one is on, the two selects
   folded under it. */
.filters { align-self: stretch; }

.fold-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  width: 100%;
  padding: 10px 16px;
  border: 0;
  background: none;
  font: inherit;
  text-align: left;
  cursor: pointer;
}

.filters-now {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  text-align: right;
  font-size: 12.5px;
  color: var(--dim);
}

.filters.on .filters-now { color: var(--ember); }

.fold-head::after {
  content: "";
  flex: none;
  width: 6px;
  height: 6px;
  margin-top: -3px;
  border-right: 1.4px solid var(--dim);
  border-bottom: 1.4px solid var(--dim);
  transform: rotate(45deg);
  transition: transform 160ms;
}

.fold-head[aria-expanded="true"]::after { margin-top: 3px; transform: rotate(-135deg); }

/* What a header folds: its height runs between 0 and its own (the row of a
   one-row grid, from 0fr to 1fr), so the panels under it slide instead of
   jumping. Folded, it is out of the tab order too. */
.fold {
  display: grid;
  grid-template-rows: 1fr;
  transition: grid-template-rows 220ms ease;
}

.fold-in {
  min-height: 0;
  overflow: hidden;
  transition: visibility 0s;
}

@media (min-width: 641px) {
  /* Open, a rule sets the selects off from the header. */
  .sector { padding: 0 16px 14px; }
  .filters:not(.unfolded) .fold { grid-template-rows: 0fr; }
  .filters:not(.unfolded) .fold-in { visibility: hidden; transition: visibility 0s 220ms; }
}

/* The filters: quiet selects in the panel's own glass, a caret drawn in
   --dim. The options take the opaque ink (their list is the system's). */
.sector {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

/* One filter without its file: no rule between the two either. */
.filter[hidden] + hr, .sector hr:has(+ .filter[hidden]) { display: none; }

/* Each filter under a line saying where its classes come from. */
.filter {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.filter .label { font-size: 9px; letter-spacing: 0.06em; transition: color 160ms; }

/* The filter in use lights up in the accent. */
.filter.on .label { color: var(--ember); }
.filter.on select { border-color: var(--ember); }

.sector select {
  display: block;
  width: 100%;
  padding: 6px 28px 6px 10px;
  line-height: 1.4;
  border: 1px solid var(--hair);
  border-radius: 4px;
  background: rgba(var(--ink-raw), 0.5)
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' fill='none' stroke='%238f8473' stroke-width='1.4'/%3E%3C/svg%3E")
    no-repeat right 10px center / 10px 6px;
  color: var(--lamp);
  font: inherit;
  font-size: 12.5px;
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
}

@media (hover: hover) {
  .sector select:hover { border-color: var(--hair-hi); }
}

.sector select option { background: var(--ink); color: var(--lamp); }

/* Chromium's customizable select (appearance: base-select) draws its own
   arrow over ours. */
.sector select::picker-icon { display: none; }

/* The place's facts: label left, figure right, one a row, so the eye runs
   down the figures. Display face, figures lined up. */
.facts {
  display: flex;
  flex-direction: column;
  gap: 5px;
  font-size: 12.5px;
  line-height: 1.35;
}

.fact {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  color: var(--dim);
}

.fact b {
  flex: none;
  font-weight: 500;
  color: var(--lamp);
  font-variant-numeric: tabular-nums;
}

.facts .note {
  text-align: center;
  font-size: 12px;
  color: var(--dim);
  font-variant-numeric: tabular-nums;
}

.facts hr { margin: 7px 0; }

/* The headline figure, a size up. */
.fact.main b { font-size: 15px; }

.progress {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  z-index: 9;
  pointer-events: none;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.04em;
  color: var(--lamp);
  padding: 18px 22px 16px;
  animation: progress-in 250ms ease-out;
  transition: opacity 700ms ease;
}

.progress.out { opacity: 0; }

@keyframes progress-in {
  from { opacity: 0; }
}

/* One lamp breathing while the dots come down the wire. */
.progress .glow {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--lamp);
  box-shadow: var(--halo);
  animation: breathe 1.6s ease-in-out infinite;
}

@keyframes breathe {
  0%, 100% { opacity: 0.35; transform: scale(0.8); }
  50% { opacity: 1; transform: scale(1.15); }
}

.progress .bar {
  width: 160px;
  height: 1px;
  background: var(--hair);
}

.progress .bar i {
  display: block;
  height: 100%;
  width: 0;
  background: var(--lamp);
  box-shadow: 0 0 6px rgba(var(--spark-raw), 0.8);
  transition: width 80ms linear;
}

/* Nothing to download: a short light runs along the wire instead. */
.progress.busy .bar i {
  width: 30%;
  transition: none;
  animation: sweep 1.1s ease-in-out infinite alternate;
}

@keyframes sweep {
  from { transform: translateX(0); }
  to { transform: translateX(233%); }
}

/* ---------- state picker ---------- */

.picker { position: relative; padding: 12px; }

.picker-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 10px;
}

.label {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--dim);
}

/* Tiles sit roughly where each state sits on the map. Their glow is the
   number of geolocated establishments (log scale), set inline as --glow. */
.tiles {
  display: grid;
  grid-template-columns: repeat(7, 30px);
  grid-template-rows: repeat(8, 30px);
  gap: 3px;
  user-select: none;
  -webkit-user-select: none;
}

.tile {
  --glow: 0;
  position: relative;
  display: grid;
  place-items: center;
  padding: 0;
  border: 1px solid rgba(var(--lamp-raw), 0.07); /* barely there: just edges the dim tiles */
  border-radius: 2px;
  cursor: pointer;
  font-family: var(--mono);
  font-size: 9.5px;
  letter-spacing: 0.02em;
  color: rgba(var(--lamp-raw), calc(0.45 + var(--glow) * 0.55));
  background: rgba(var(--ember-raw), calc(0.12 + var(--glow) * 0.75));
  box-shadow: 0 0 calc(var(--glow) * 14px) rgba(var(--ember-raw), calc(var(--glow) * 0.8));
  transition: background-color 160ms, border-color 160ms, color 160ms;
}

@media (hover: hover) {
  .tile:hover {
    border-color: var(--hair-hi);
    color: var(--lamp);
  }
}

.tile[aria-pressed="true"] {
  background: var(--lamp);
  color: var(--night);
  box-shadow: var(--lit);
}

.tile:disabled {
  cursor: not-allowed;
  background: transparent;
  border: 1px dashed var(--hair);
  color: var(--dim);
  box-shadow: none;
}

.tile-br {
  width: auto;
  height: 24px;
  padding: 0 10px;
  font-size: 10px;
  --glow: 1;
}

/* Pops up right under the picker. */
.peek {
  position: absolute;
  left: 0;
  right: 0;
  top: calc(100% + 8px);
  background: var(--night);
  border: 1px solid var(--hair);
  border-radius: 4px;
  overflow: hidden;
  pointer-events: none;
}

/* Crop the bottom strip of the stills, which carries an old basemap credit. */
.peek img {
  display: block;
  width: 100%;
  aspect-ratio: 4 / 2.8;
  object-fit: cover;
  object-position: top;
}

.peek-text {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 8px 10px 10px;
}

.peek-text strong { font-weight: 800; font-size: 15px; }

.peek-text span {
  font-family: var(--mono);
  font-weight: 300;
  font-size: 10px;
  color: var(--dim);
}

/* The dock only exists on phones. */
.dock { display: none; }

/* ---------- light controls ---------- */

/* The right column: the readout, the sliders, the chips centered under them. */
.light {
  position: absolute;
  top: var(--top);
  right: var(--right);
  z-index: 10;
  width: var(--rail);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
}

.chips {
  display: flex;
  gap: 6px;
}

/* The three actions in one row, inside the panel's width. */
.chips .chip { padding: 0 9px; }

/* luz only shows on short screens, where the sliders fold away. */
#light-toggle { display: none; }

.chip {
  height: 28px;
  padding: 0 12px;
  border: 1px solid var(--hair);
  border-radius: 14px;
  background: var(--glass);
  font-family: var(--mono);
  font-size: 9px;
  letter-spacing: 0.04em;
  cursor: pointer;
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}

.chip[aria-expanded="true"] { border-color: var(--hair-hi); }

/* The actions carry an icon before the word: a plane, tilted or flat, a
   pin for the names and a ringed question mark. Phones keep only the icons. */
#tilt, #names, #about-open {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
}

#tilt::before {
  content: "";
  width: 11px;
  height: 7px;
  border: 1.2px solid currentColor;
  border-radius: 1px;
  transition: transform 160ms;
}

#tilt[aria-pressed="true"]::before { transform: skewX(-24deg); }

/* The pin fills in while the names are on. */
#names::before {
  content: "";
  width: 7px;
  height: 7px;
  margin: 0 1px 2px;
  border: 1.2px solid currentColor;
  border-radius: 50% 50% 50% 0;
  transform: rotate(-45deg);
}

#names[aria-pressed="true"] { border-color: var(--hair-hi); }
#names[aria-pressed="true"]::before { background: currentColor; }

#about-open::before {
  content: "?";
  display: grid;
  place-items: center;
  width: 12px;
  height: 12px;
  border: 1.2px solid currentColor;
  border-radius: 50%;
  font-size: 8px;
  line-height: 1;
  letter-spacing: 0;
}

@media (hover: hover) {
  .chip:hover { border-color: var(--hair-hi); }
}

/* The sliders fold under a header like the filters do, but start open. */
.light-panel { width: 100%; }
.light-body { padding: 0 16px 10px; }
.light-body .fold-rule { margin-bottom: 12px; }

/* Only where the panel sits in the column: folded behind luz (short
   screens) or as a sheet (phones), the sliders are always there. */
@media (min-width: 641px) and (min-height: 861px) {
  .light-panel.folded .fold { grid-template-rows: 0fr; }
  .light-panel.folded .fold-in { visibility: hidden; transition: visibility 0s 220ms; }
}

.knob {
  display: block;
  margin-bottom: 10px;
}

.knob span {
  display: flex;
  justify-content: space-between;
  font-family: var(--mono);
  font-size: 10px;
  color: var(--dim);
}

.knob output, .light-foot output { color: var(--lamp); font-variant-numeric: tabular-nums; }

/* The sliders drawn in the palette: a hairline track lit in ember up to a
   small lit thumb. --fill (set from app.js) is the lit part, for WebKit;
   Gecko has ::-moz-range-progress. The pseudo-elements stay in twin rules,
   since a browser drops a whole rule over a selector it does not know. */
.knob input[type="range"] {
  --fill: 0.5;
  display: block;
  width: 100%;
  height: 14px;
  margin: 4px 0 0;
  background: transparent;
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
}

.knob input[type="range"]:disabled { opacity: 0.4; cursor: default; }

.knob input[type="range"]::-webkit-slider-runnable-track {
  height: 2px;
  border-radius: 1px;
  background: linear-gradient(to right, var(--ember) calc(var(--fill) * 100%), var(--hair) 0);
}

.knob input[type="range"]::-moz-range-track {
  height: 2px;
  border-radius: 1px;
  background: var(--hair);
}

.knob input[type="range"]::-moz-range-progress {
  height: 2px;
  border-radius: 1px;
  background: var(--ember);
}

.knob input[type="range"]::-webkit-slider-thumb {
  width: 12px;
  height: 12px;
  margin-top: -5px;
  border: 0;
  border-radius: 50%;
  background: var(--lamp);
  box-shadow: 0 0 6px rgba(var(--spark-raw), 0.8), 0 0 14px rgba(var(--ember-raw), 0.9);
  -webkit-appearance: none;
}

.knob input[type="range"]::-moz-range-thumb {
  width: 12px;
  height: 12px;
  border: 0;
  border-radius: 50%;
  background: var(--lamp);
  box-shadow: 0 0 6px rgba(var(--spark-raw), 0.8), 0 0 14px rgba(var(--ember-raw), 0.9);
}

.light-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-family: var(--mono);
  font-size: 10px;
  color: var(--dim);
}

.light-tools { display: flex; align-items: center; gap: 6px; }

/* The lock: open while the sliders follow what the screen holds, closed and
   lit when the look is held. */
.lock {
  display: grid;
  place-items: center;
  width: 22px;
  height: 22px;
  margin: -4px 0 -4px -5px;
  padding: 0;
  border: 0;
  background: none;
  color: var(--dim);
  cursor: pointer;
}

.lock svg {
  width: 12px;
  height: 12px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.2;
  stroke-linecap: round;
  overflow: visible;
}

.lock .shackle {
  transform-origin: 8px 5.5px;
  transform: rotate(38deg);
  transition: transform 160ms;
}

.lock[aria-pressed="true"] { color: var(--lamp); filter: drop-shadow(0 0 4px rgba(var(--spark-raw), 0.7)); }
.lock[aria-pressed="true"] rect { fill: currentColor; }
.lock[aria-pressed="true"] .shackle { transform: none; }

@media (hover: hover) {
  .lock:hover { color: var(--lamp); }
}

/* ---------- timeline ---------- */

/* Sits on the floor of the map, centered on the screen and as wide as it
   can be without reaching under the rail on either side.
   --p is the playhead's place along the track, 0..1, set from app.js. */
.timeline {
  --p: 1;
  --thumb: 14px;
  --track: 56px;
  /* The playhead: a lit wire with a lamp at its foot. */
  --playhead:
    radial-gradient(circle at 50% calc(100% - 4px), var(--lamp) 0 3.5px, transparent 4.5px),
    linear-gradient(var(--lamp), var(--lamp)) center / 2px 100% no-repeat;
  --playhead-glow: drop-shadow(0 0 5px rgba(var(--spark-raw), 0.9)) drop-shadow(0 0 14px rgba(var(--ember-raw), 0.9));
  position: absolute;
  bottom: var(--bottom);
  left: 0;
  right: 0;
  width: min(780px, calc(100vw - 2 * (var(--rail) + var(--gutter) + 8px)));
  min-width: 430px;
  margin: 0 auto;
  z-index: 10;
  padding: 12px 14px 8px;
}

.tl-head {
  display: flex;
  align-items: center;
  gap: 14px;
  margin-bottom: 8px;
}

.tl-play {
  flex: none;
  display: grid;
  place-items: center;
  width: 32px;
  height: 32px;
  padding: 0;
  border: 1px solid var(--hair);
  border-radius: 50%;
  background: rgba(var(--ember-raw), 0.18);
  cursor: pointer;
  transition: background-color 160ms, border-color 160ms, box-shadow 160ms;
}

@media (hover: hover) {
  .tl-play:hover {
    border-color: var(--hair-hi);
    background: rgba(var(--ember-raw), 0.4);
  }
}

.tl-play.on { box-shadow: 0 0 10px rgba(var(--ember-raw), 0.9); }

.tl-play svg { width: 12px; height: 12px; fill: var(--lamp); }
.tl-play .i-pause { display: none; }
.tl-play.on .i-play { display: none; }
.tl-play.on .i-pause { display: block; }

.tl-read {
  flex: none;
  display: flex;
  flex-direction: column;
  min-width: 78px;
}

.tl-lead {
  font-family: var(--mono);
  font-size: 9px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--dim);
}

.tl-year {
  font-weight: 800;
  font-size: 28px;
  line-height: 1;
  letter-spacing: -0.03em;
  font-variant-numeric: tabular-nums;
  color: var(--dim);
  text-shadow: var(--aura-low);
}

.tl-sub {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
  font-family: var(--mono);
  font-weight: 300;
  font-size: 10px;
  line-height: 1.5;
  color: var(--dim);
}

.tl-count b { font-weight: 400; color: var(--lamp); font-variant-numeric: tabular-nums; }
.tl-note { opacity: 0.75; }

.tl-now { flex: none; }
.tl-now:disabled { opacity: 0.35; cursor: default; border-color: var(--hair); }

/* The histogram is drawn behind a transparent range input, so a click or
   drag anywhere on the bars scrubs; the thumb is a full-height playhead. */
.tl-track {
  position: relative;
  height: var(--track);
}

.tl-bars {
  position: absolute;
  top: 0;
  left: calc(var(--thumb) / 2);
  width: calc(100% - var(--thumb));
  height: 100%;
}

.tl-slider {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  background: transparent;
  cursor: ew-resize;
  -webkit-appearance: none;
  appearance: none;
  touch-action: none;
}

.tl-slider:focus { outline: none; }
.tl-slider:focus-visible { outline: 1px solid var(--lamp); outline-offset: 2px; }

/* WebKit and Gecko pseudo-elements cannot share a selector list (a browser
   drops the whole rule over the one it does not know), so they stay twins. */
.tl-slider::-webkit-slider-runnable-track { height: var(--track); background: transparent; }
.tl-slider::-moz-range-track { height: var(--track); background: transparent; }

.tl-slider::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: var(--thumb);
  height: var(--track);
  border: 0;
  border-radius: 0;
  background: var(--playhead);
  filter: var(--playhead-glow);
}

.tl-slider::-moz-range-thumb {
  width: var(--thumb);
  height: var(--track);
  border: 0;
  border-radius: 0;
  background: var(--playhead);
  filter: var(--playhead-glow);
}

.tl-axis {
  position: relative;
  height: 14px;
  margin-top: 4px;
  font-family: var(--mono);
  font-size: 9px;
  color: var(--dim);
}

.tl-axis span {
  position: absolute;
  top: 0;
  left: calc(var(--at) * (100% - 14px) + 7px);
  transform: translateX(-50%);
  font-variant-numeric: tabular-nums;
}

/* ---------- about ---------- */

.about {
  max-width: 520px;
  width: calc(100vw - 2 * var(--gutter));
  max-height: calc(100vh - 2 * var(--gutter));
  max-height: calc(100dvh - 2 * var(--gutter));
  padding: 28px 28px 22px;
  background: var(--ink);
  color: var(--lamp);
  border: 1px solid var(--hair);
  border-radius: 4px;
}

.about::backdrop { background: rgba(var(--ink-raw), 0.7); }

.about h2 {
  margin: 0 0 14px;
  font-weight: 800;
  font-size: 26px;
  letter-spacing: -0.02em;
}

.about p {
  margin: 0 0 12px;
  font-size: 15px;
  line-height: 1.5;
  color: var(--soft);
}

.about em { color: var(--lamp); }
.about a { color: var(--ember); }

.about .fine {
  margin-top: 18px;
  font-family: var(--mono);
  font-weight: 300;
  font-size: 10px;
  line-height: 1.7;
  color: var(--dim);
}

.about .close {
  position: absolute;
  top: 10px;
  right: 12px;
  border: 0;
  background: none;
  font-size: 22px;
  color: var(--dim);
  cursor: pointer;
}

.error {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  z-index: 20;
  max-width: calc(100vw - 2 * var(--gutter));
  padding: 14px 18px;
  background: var(--ink);
  border: 1px solid var(--ember);
  border-radius: 4px;
  font-family: var(--mono);
  font-size: 11px;
  line-height: 1.6;
}

/* Touch devices: the glass blur is recomputed every frame over a map that
   repaints all the time (the twinkle), which a phone GPU pays for in frame
   rate and battery. A darker glass reads the same without it. */
@media (max-width: 640px), (pointer: coarse) {
  :root { --glass: rgba(var(--ink-raw), 0.86); }
  .panel, .chip {
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }
}

/* Short screens: the column would run off the bottom, so the intro loses its
   line and the sliders fold behind luz, as on phones. */
@media (min-width: 641px) and (max-height: 860px) {
  .dek { display: none; }
  #light-toggle { display: block; }
  /* With luz the four chips outgrow the panel's width: one row, flush right. */
  .light { width: auto; align-items: flex-end; }
  .light-panel { display: none; width: var(--rail); }
  .light-panel.open { display: block; }
  /* luz does the folding here: no header, the sliders always under it. */
  .light-panel .fold-head, .light-panel .fold-rule { display: none; }
  .light-body { padding-top: 12px; }
}

/* ---------- phones ---------- */

@media (max-width: 640px) {
  :root { --gutter: 16px; --dock: 56px; }

  /* The column keeps only the intro, top left, with the readout right under
     it; everything else is a sheet over the dock, one at a time. */
  .rail {
    bottom: auto;
    width: min(240px, calc(100vw - 2 * var(--gutter)));
    gap: 6px;
  }
  .light { display: contents; }

  .masthead { padding: 10px 14px; }
  .dek { display: none; }

  /* The readout, out of the dissolved right column, to under the intro (52px
     tall). Folded to the place and its count so the map stays clear; a tap
     opens the rest. Its filters are a sheet of their own. */
  .readout {
    position: absolute;
    top: calc(var(--top) + 58px);
    left: var(--left);
    z-index: 10;
    /* Fixed to the intro's width, whatever the place's name. */
    width: min(240px, calc(100vw - 2 * var(--gutter)));
    gap: 6px;
    padding: 9px 30px 10px 14px;
    cursor: pointer;
  }

  .readout > hr { display: none; }

  /* The filters' panel dissolves: its box is a sheet of the dock. */
  .filters { display: contents; }
  .filters[hidden], .fold-head, .fold-rule { display: none; }
  /* No folding in a sheet: the wrappers step aside (the filters' box is
     fixed to the screen, and must not be clipped by them). */
  .fold, .fold-in { display: contents; }
  .light-body { padding: 0; }
  .place { --place: 20px; }
  .readout:not(.open) .facts > :not(.main) { display: none; }

  /* A caret says there is more under it. */
  .readout::after {
    content: "";
    position: absolute;
    top: 16px;
    right: 13px;
    width: 6px;
    height: 6px;
    border-right: 1.4px solid var(--dim);
    border-bottom: 1.4px solid var(--dim);
    transform: rotate(45deg);
    transition: transform 160ms;
  }

  .readout.open::after { transform: translateY(3px) rotate(-135deg); }

  /* The dock: one button per sheet on the left, the two actions as round
     buttons on the right, all a thumb tall. */
  /* One row: the dock stops short of the three round buttons (and a 6px
     gap) and its four buttons share what is left. */
  :root { --round: 38px; --round-gap: 6px; }
  .dock {
    display: flex;
    gap: 4px;
    position: absolute;
    left: var(--left);
    right: calc(var(--right) + 3 * var(--round) + 2 * var(--round-gap) + 6px);
    bottom: var(--bottom);
    z-index: 13;
  }

  .dock .chip { position: relative; flex: 1 1 auto; min-width: 0; height: 40px; padding: 0 4px; border-radius: 20px; letter-spacing: 0.02em; }
  .dock .chip[aria-expanded="true"] { background: var(--lamp); color: var(--night); }

  /* A lit dot on filtros while a filter is on. */
  .dock .chip.on::after {
    content: "";
    position: absolute;
    top: 7px;
    right: 6px;
    width: 5px;
    height: 5px;
    border-radius: 50%;
    background: var(--ember);
    box-shadow: 0 0 6px rgba(var(--spark-raw), 0.8);
  }

  .chips {
    position: absolute;
    right: var(--right);
    bottom: var(--bottom);
    z-index: 13;
    gap: var(--round-gap);
  }

  /* Icons instead of words: a plane, tilted or flat, a pin and a question
     mark. The words stay for screen readers. */
  .chips .chip {
    display: grid;
    place-items: center;
    width: var(--round);
    height: 40px;
    padding: 0;
    border-radius: 20px;
    font-size: 0;
  }

  #tilt, #names, #about-open { gap: 0; }
  #names::before { width: 9px; height: 9px; border: 1.4px solid var(--lamp); }
  #names[aria-pressed="true"]::before { background: var(--lamp); }
  #tilt::before { width: 14px; height: 9px; border: 1.4px solid var(--lamp); }
  #about-open::before { width: auto; height: auto; border: 0; font-size: 14px; }

  /* Sheets: opaque, sliding up from under the dock, one open at a time.
     visibility keeps their layout (the timeline canvas measures itself).
     fixed: the picker and the filters sit inside positioned parents. */
  .picker, .sector, .light-panel, .timeline {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 12;
    width: auto;
    margin: 0;
    background: var(--ink);
    border: 1px solid var(--hair);
    border-width: 1px 0 0;
    border-radius: 8px 8px 0 0;
    padding: 10px var(--gutter) calc(var(--bottom) + var(--dock));
    cursor: default;
    transform: translateY(100%);
    visibility: hidden;
    transition: transform 220ms ease, visibility 0s 220ms;
  }

  .picker.open, .sector.open, .light-panel.open, .timeline.open {
    transform: none;
    visibility: visible;
    transition: transform 220ms ease;
  }

  /* The handle: drag it down, or tap the map, to put the sheet away. */
  .picker::before, .sector::before, .light-panel::before, .timeline::before {
    content: "";
    display: block;
    flex: none;
    align-self: center;
    width: 36px;
    height: 4px;
    margin: 0 auto 14px;
    border-radius: 2px;
    background: var(--hair-hi);
  }

  .picker { display: flex; flex-direction: column; align-items: center; }
  .picker-head { width: 100%; max-width: 280px; }
  .tiles { grid-template-columns: repeat(7, 36px); grid-template-rows: repeat(8, 36px); }
  .peek { display: none !important; }

  /* The filters' sheet: thumb-sized selects. */
  .sector { gap: 14px; }
  .sector::before { margin-bottom: 0; }
  .sector select { padding: 12px 30px 12px 12px; font-size: 15px; }
  .filter { gap: 6px; }

  .timeline { --track: 44px; min-width: 0; }
  .tl-head { gap: 10px; margin-bottom: 6px; }
  .tl-year { font-size: 24px; }
  .tl-note { display: none; }
}

/* Narrow phones: smaller round buttons and tighter words, so the row still
   fits. */
@media (max-width: 379px) {
  :root { --round: 32px; --round-gap: 4px; }
  .dock { gap: 3px; }
  .dock .chip { padding: 0 2px; font-size: 8px; letter-spacing: 0; }
}

@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; }
  .progress, .progress .glow { animation: none; }
  .progress.busy .bar i { width: 100%; animation: none; }
}
