/* ==========================================================================
   Puesta del sol hoy — design system.

   THE ONE RULE: every colour means a sun altitude. Nothing is decorative.
   The ramp below runs from astronomical night (-18°) to full daylight, and
   any surface referring to a sun event reads from it — so an amber in the
   legend is provably the same amber on the map.

   Ported from the design preview. Two things are added here that the preview
   did not have, both marked in place: an independent moon (§hero) and mobile
   phase clustering (§complete sun times).
   ========================================================================== */

:root {
  /* --- the sun ramp. Identical in both themes: these ARE the data. ------- */
  --astro:     #6B5CA5;
  --nautical:  #4A6BB5;
  --bluehour:  #4E8AD4;
  --sunrise:   #E8963C;
  --golden:    #F0B429;
  --day:       #7FB5DC;
  --sunset:    #D2553F;
  --shadow:    #8B93A8;

  --display: "Newsreader", Georgia, "Times New Roman", serif;
  --ui:      "Archivo", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  --mono:    "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, monospace;

  --r: 14px; --r-s: 9px; --maxw: 1160px;

  /* --- spacing scale ----------------------------------------------------
     One 4px-based ramp, used everywhere. Before this, padding was picked
     per-component (19px here, 13px there, 17px somewhere else) and then
     shaved again at each breakpoint to stop things overflowing — which is
     what made the phone layout read as packed. The fix is that narrow
     screens reflow (grids drop to fewer columns) instead of compressing:
     --pad-card and --pad-cell hold their value all the way down, and only
     the page gutter and section rhythm step back, by one notch each.       */
  --s1: 4px; --s2: 8px; --s3: 12px; --s4: 16px;
  --s5: 24px; --s6: 32px; --s7: 48px; --s8: 64px;

  --gutter:   var(--s5);  /* page edge — steps to 20/18/16 on narrow      */
  --sec-y:    var(--s8);  /* section rhythm — steps to 56/48              */
  --gap:      var(--s4);  /* between sibling cards in a grid — constant   */
  --pad-card: 20px;       /* card interior — constant at every width      */
  --pad-cell: 16px;       /* dense cells / table-adjacent — constant      */

  /* --- DARK (default) --------------------------------------------------- */
  --night:     #0E1119;
  --surface:   #161A24;
  --raised:    #1D222E;
  --sunk:      #11141C;
  --line:      #262C3A;
  --line-soft: #1E2430;
  --text:      #E9ECF3;
  --muted:     #98A0B2;
  --faint:     #6A7285;
  --grid:      rgba(255,255,255,.07);
  --hover:     rgba(255,255,255,.032);
  --casing:    rgba(8,8,14,.9);
  --sr-dim:    rgba(232,150,60,.13);
  --bh-dim:    rgba(78,138,212,.13);
  --today-fill:rgba(232,150,60,.16);
  --shade:     rgba(0,0,0,.34);
  --ambient:   #E8963C;
  /* On dark, --ambient already measures 7.96:1 — it needs no darker twin. */
  --accent-text: var(--ambient);
  /* Edge for the slider tracks. Brighter on dark, where the band's own night
     ends are all but invisible against the page. */
  --track-ring: rgba(255,255,255,.26);
  --card-lift: 0 1px 2px rgba(0,0,0,.4);
}

/* Light, whichever way the viewer asks for it. The ramp darkens slightly so
   it still passes contrast on white — the hues are the data and do not move,
   but their lightness has to. */
:root[data-theme="light"] {
  --night:     #F2F5F9;
  --surface:   #FFFFFF;
  --raised:    #F8FAFC;
  --sunk:      #EDF1F6;
  --line:      #DCE3EC;
  --line-soft: #E7ECF3;
  --text:      #141922;
  --muted:     #556072;
  --faint:     #7C8697;
  --grid:      rgba(20,25,34,.08);
  --hover:     rgba(20,25,34,.035);
  --casing:    rgba(255,255,255,.92);
  --sr-dim:    rgba(232,150,60,.17);
  --bh-dim:    rgba(78,138,212,.15);
  --today-fill:rgba(232,150,60,.2);
  --shade:     rgba(255,255,255,.7);
  --sunrise:   #C2701A;
  --golden:    #B8860B;
  --sunset:    #B33F2B;
  --bluehour:  #2E6BB8;
  --nautical:  #3A529B;
  --astro:     #574792;
  --day:       #3E86B8;
  --shadow:    #667186;
  --ambient:   #C2701A;

  /* Dark mode separates cards with a cast shadow. On white that reads as
     grime, so light mode separates them with a real border and a hairline
     lift instead — the complaint about cards having no separation in light
     mode was a missing treatment, not a missing shadow. */
  --card-lift: 0 1px 2px rgba(20,25,34,.06), 0 1px 1px rgba(20,25,34,.04);

  /* --ambient is tuned to be seen — the live dot, the slider thumb, focus
     rings, the today marker. At small type on a light page it measures
     3.41:1, which is below AA and is exactly why the phase readout was hard
     to read. Small accent TEXT gets its own darker value; the two stay in
     the same hue family so nothing looks recoloured. */
  --accent-text: #8A4E10;
  /* On white the band's night ends already stand out; the ring only needs to
     define the edge, not rescue it. */
  --track-ring: rgba(20,25,34,.18);
}

*,*::before,*::after { box-sizing: border-box; }
html { scroll-behavior: smooth; -webkit-text-size-adjust: 100%; }
body {
  margin: 0; background: var(--night); color: var(--text);
  font-family: var(--ui); font-size: 16px; line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  transition: background .3s, color .3s;
  overflow-x: hidden;
}
img, svg { max-width: 100%; }

.wrap { width: 100%; max-width: var(--maxw); margin: 0 auto; padding: 0 var(--gutter); }
h1,h2,h3 { margin: 0; line-height: 1.15; text-wrap: balance; }
h1 { font-family: var(--display); font-size: clamp(2rem,4.6vw,2.9rem); font-weight: 500; letter-spacing: -.02em; }
h2 { font-family: var(--display); font-size: clamp(1.4rem,2.7vw,1.85rem); font-weight: 500; letter-spacing: -.015em; }
h3 { font-size: .95rem; font-weight: 600; }
p { margin: 0; }
a { color: inherit; }
.num { font-family: var(--mono); font-variant-numeric: tabular-nums; }

.visually-hidden {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ---------------- top bar: search + theme toggle ---------------------- */

.topbar {
  position: sticky; top: 0; z-index: 900;
  background: color-mix(in srgb, var(--night) 88%, transparent);
  backdrop-filter: blur(14px);
  border-bottom: 1px solid var(--line);
}
.topbar-in { display: flex; align-items: center; gap: 16px; padding: 11px 22px; max-width: var(--maxw); margin: 0 auto; }
.brand {
  display: flex; align-items: center; gap: 9px; text-decoration: none;
  font-family: var(--display); font-size: 19px; font-weight: 600;
  letter-spacing: -.01em; white-space: nowrap;
}
.brand .bmark {
  width: 19px; height: 19px; border-radius: 50%;
  background: radial-gradient(circle at 34% 32%, #FFE0A8, var(--sunrise) 62%, var(--sunset));
  box-shadow: 0 0 11px var(--sr-dim);
}

.navlink {
  flex: 0 0 auto; text-decoration: none; white-space: nowrap;
  font-family: var(--mono); font-size: 11.5px; letter-spacing: .1em;
  text-transform: uppercase; color: var(--muted);
  padding: 8px 10px; border-radius: 8px; transition: color .15s, background .15s;
}
.navlink:hover { color: var(--text); background: var(--raised); }
.navlink:focus-visible { outline: 2px solid var(--ambient); outline-offset: 2px; }
/* On a phone the search bar already takes its own row; the link would push
   the toggle off the first one, so it moves to sit beside the search. */
@media (max-width: 760px) { .navlink { order: 4; } }

.searchwrap { position: relative; flex: 1; max-width: 520px; margin: 0 auto; }
.searchwrap input {
  width: 100%; padding: 10px 15px 10px 38px; border-radius: 10px;
  background: var(--raised); border: 1px solid var(--line); color: var(--text);
  font-family: var(--ui); font-size: 14.5px;
  transition: border-color .15s, box-shadow .15s;
}
.searchwrap input::placeholder { color: var(--faint); }
.searchwrap input:focus { outline: none; border-color: var(--ambient); box-shadow: 0 0 0 3px var(--sr-dim); }
.searchwrap .sicon { position: absolute; left: 13px; top: 50%; transform: translateY(-50%); color: var(--faint); pointer-events: none; display: flex; }

.results {
  position: absolute; left: 0; right: 0; top: calc(100% + 6px);
  background: var(--surface); border: 1px solid var(--line);
  border-radius: 11px; overflow: hidden;
  box-shadow: 0 14px 40px rgba(0,0,0,.4); display: none; z-index: 950;
}
.results.open { display: block; }
.results button {
  display: flex; justify-content: space-between; gap: 12px; width: 100%;
  text-align: left; padding: 10px 14px; background: none; border: 0;
  border-bottom: 1px solid var(--line-soft); color: var(--text);
  font-family: var(--ui); font-size: 14px; cursor: pointer;
}
.results button:last-child { border-bottom: 0; }
.results button:hover, .results button[aria-selected="true"] { background: var(--hover); }
.results .rc { color: var(--faint); font-size: 12.5px; white-space: nowrap; }
.results .rnote { padding: 9px 14px; font-family: var(--mono); font-size: 11px; letter-spacing: .06em; color: var(--faint); border-bottom: 1px solid var(--line-soft); }

.tgl { display: flex; gap: 2px; padding: 3px; border-radius: 9px; background: var(--raised); border: 1px solid var(--line); }
.tgl button { width: 31px; height: 27px; border: 0; border-radius: 6px; background: none; color: var(--faint); cursor: pointer; display: grid; place-items: center; }
.tgl button[aria-pressed="true"] { background: var(--ambient); color: var(--night); }
.tgl button:focus-visible { outline: 2px solid var(--ambient); outline-offset: 2px; }

/* ---------------- section frame --------------------------------------- */

.sec { padding: var(--sec-y) 0; border-top: 1px solid var(--line-soft); }
.sec-head { display: flex; flex-direction: column; gap: var(--s2); margin-bottom: var(--s5); }
/* Every eyebrow is the accent, everywhere. --faint was deliberately quiet and
   at 10.5px on dark it fell under AA; --accent-text is the one value tuned for
   small type in BOTH themes (the ambient amber on dark, a darker twin of the
   same hue on light), so the label reads as the page's own voice instead of a
   grey caption — and the rule stays the rule: the amber still means the sun. */
.eyebrow {
  font-family: var(--mono); font-size: 11.5px; font-weight: 600;
  letter-spacing: .22em; text-transform: uppercase;
  color: var(--accent-text);
  display: flex; align-items: center; gap: 10px;
}
.eyebrow::before { content: ""; width: 16px; height: 1px; background: currentColor; }


/* Body copy, not a caption. 14.5px grey was set when every .sec-sub was one
   line under a heading; the homepage now carries real paragraphs in it, and at
   that size they were work to read. 15.5/1.65 is the reading setting. */
.sec-sub { color: var(--muted); font-size: 15.5px; line-height: 1.65; max-width: 68ch; }
.card { background: var(--surface); border: 1px solid var(--line); border-radius: var(--r); box-shadow: var(--card-lift); }

/* ---------------- 1. hero --------------------------------------------- */

/* The hero sits on the page's own background now. It used to carry the sky
   as a full-bleed layer, which put a moving gradient behind the site's
   margins — the one band of the page that is not aligned to the content
   column — and forced every label on top of it to be white regardless of
   whether the sky behind it was noon-pale or midnight-dark. */
.hero { position: relative; background: var(--night); border-bottom: 1px solid var(--line); }
.hero-sky { position: absolute; inset: 0; transition: background 1s linear; }
.hero-stars {
  position: absolute; inset: 0; opacity: var(--stars,0); transition: opacity 1s linear;
  background-image:
    radial-gradient(1.4px 1.4px at 12% 18%,#fff,transparent),
    radial-gradient(1.1px 1.1px at 31% 9%,#fff,transparent),
    radial-gradient(1.3px 1.3px at 58% 22%,#fff,transparent),
    radial-gradient(1.5px 1.5px at 77% 12%,#fff,transparent),
    radial-gradient(1.1px 1.1px at 89% 31%,#fff,transparent),
    radial-gradient(1.2px 1.2px at 22% 38%,#fff,transparent),
    radial-gradient(1px 1px at 66% 41%,#fff,transparent);
}
/* The scrim is gone with the full-bleed sky it existed to fade out. */

/* The animated box. A real grid child of .hero-top, and the only thing on
   the page that carries the sky — everything outside it is theme-coloured,
   which is what keeps the surrounding text readable at every hour. */
.hero-track {
  position: relative; min-height: 260px; pointer-events: none;
  border-radius: var(--r); overflow: hidden;
  border: 1px solid var(--line);
  background: var(--sunk);   /* what shows before the first paint */
}
.hero-dot { position: absolute; width: 3px; height: 3px; border-radius: 50%; background: rgba(255,255,255,.24); transform: translate(-50%,50%); }
.hero-dot.on { width: 5px; height: 5px; background: var(--body-lt,#fff); box-shadow: 0 0 10px 2px var(--glow); }
/* The horizon rule that used to sit at the foot of the track is gone. It
   drew a hard edge across an otherwise continuous sky, which is exactly the
   seam this scene should not have — the gradient already reads as ground
   meeting sky without a line asserting where. */

/* --- the two bodies ---------------------------------------------------
   ADDED, not ported. The preview had a single `.hero-body` that recoloured
   itself from gold to grey once the sun was far enough down, so the sun
   appeared to travel along the arc and turn into the moon. There are two
   bodies in the sky and they keep their own schedules, so there are two
   elements here and neither reads the other's position. */

.hero-body {
  position: absolute;
  left: calc(var(--sx,.5)*100%); bottom: calc(var(--sy,.5)*100%);
  transform: translate(-50%,50%);
  border-radius: 50%;
  transition: left .35s linear, bottom .35s linear, opacity .5s linear;
}

/* Set directly by sky-scene.js (plain left/bottom, not the --sx/--sy pair
   .hero-body uses) because it tracks the sun on its own schedule — fading
   in through the disc's own dusk and out again past dawn, not merely
   mirroring it. Sits earlier in the DOM than the two bodies so it always
   paints behind them. */
.hero-glow {
  position: absolute;
  left: 50%; bottom: 30%;
  width: 240px; height: 240px;
  transform: translate(-50%,50%);
  border-radius: 50%;
  background: radial-gradient(circle, var(--glow, rgba(232,150,60,.5)) 0%, transparent 70%);
  opacity: 0;
  transition: left .35s linear, bottom .35s linear, opacity .5s linear;
  pointer-events: none;
}

.hero-sun {
  width: 50px; height: 50px;
  background: radial-gradient(circle at 50% 42%, #FFFDF3 0%, #FFE9A8 38%, #FFB347 72%, #FF8C32 100%);
  /* The inset rim is a contrast casing. At solar noon the sky behind the sun
     is at its brightest and a pale gold disc on a pale gold sky all but
     disappears — which is exactly what went wrong in light mode. The rim
     keeps an edge on the disc at every sky brightness, the same trick the
     compass bearings use to stay legible over pale map tiles. */
  box-shadow:
    0 0 var(--gblur,44px) var(--gspread,10px) var(--glow, rgba(232,150,60,.5)),
    inset 0 0 0 1.5px rgba(150,74,12,.45);
}

.hero-moon { width: 38px; height: 38px; }
/* Rotated by the position angle of the bright limb, so a crescent tips the
   way the real one does instead of always sitting upright. */
.moon-disc {
  position: absolute; inset: 0; border-radius: 50%; overflow: hidden;
  background: radial-gradient(circle at 38% 34%, #FDFDFF 0%, #E4E7F2 45%, #C3C8DA 78%, #A7AEC6 100%);
  box-shadow: 0 0 24px 5px rgba(214,220,240,.3), inset 0 0 0 1px rgba(70,76,96,.35);
}
/* A disc of the same size slid across the moon: fully overlapping is a new
   moon, slid clear is a full one, half way is a quarter. */
.moon-shadow { position: absolute; inset: 0; border-radius: 50%; background: rgba(18,20,32,.9); transition: transform .42s linear; }

/* padding-block, NOT the `padding: 28px 0 38px` shorthand this replaced.
   This element is `class="wrap hero-in"`, and .wrap supplies the page
   gutter. Both are single-class selectors, so the shorthand — arriving
   later in the file — silently reset the horizontal padding to zero and
   the hero alone escaped the site's margins. On desktop the centred
   max-width hid it; on any viewport under 1160px the hero ran edge to edge
   while every other section stayed inset. */
.hero-in { position: relative; padding-block: 28px 38px; }

/* Upper band: identity and clock on the left, the animation beside them.
   `minmax(0,…)` on both tracks so a long city name shrinks its own column
   instead of pushing the animation off the grid. */
/* Two columns of comparable weight: the reading on the left, the picture of
   it on the right. 46% rather than 42% because the right column now carries
   the slider and its readouts too, not just the animation. */
.hero-top { display: grid; grid-template-columns: minmax(0,1fr) minmax(0,46%); gap: var(--s6); align-items: center; }
.hero-content { min-width: 0; }

/* The animation and the control that drives it, stacked as one unit. */
.hero-stage { min-width: 0; display: flex; flex-direction: column; gap: var(--s3); }

/* Lower band. Separated by space alone — the gap does the work a rule was
   doing, without drawing a line across an open sky. */
.hero-bottom { margin-top: 40px; }
/* All of the hero's text now sits on the theme background rather than on a
   moving sky, so it takes the theme's own colours. The white-with-a-
   text-shadow treatment these used to carry existed only to survive the
   gradient behind them, and it is what made them wash out at noon in light
   mode. No text on this page is painted over the animation any more. */
.crumb { font-family: var(--mono); font-size: 11px; letter-spacing: .1em; text-transform: uppercase; color: var(--muted); display: flex; gap: 8px; flex-wrap: wrap; }
.crumb span:not(:last-child)::after { content: " /"; opacity: .45; }
.crumb a { text-decoration: none; }
.hero-h { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 10px 18px; margin: 13px 0 5px; }
.hero-sub { color: var(--muted); font-size: 14.5px; }
.hero h1 { color: var(--text); }

.livepill { display: inline-flex; align-items: center; gap: 8px; padding: 5px 12px 5px 9px; border-radius: 999px; background: var(--raised); border: 1px solid var(--line); font-family: var(--mono); font-size: 12px; color: var(--muted); }
.livedot { width: 6px; height: 6px; border-radius: 50%; background: var(--ambient); box-shadow: 0 0 8px 1px var(--ambient); animation: pulse 2.6s ease-in-out infinite; }
@keyframes pulse { 0%,100%{opacity:1} 50%{opacity:.35} }

.hero-clock { font-family: var(--mono); font-size: clamp(2.5rem,6.6vw,4rem); font-weight: 400; letter-spacing: -.03em; line-height: 1; color: var(--text); }
.hero-phase { font-family: var(--mono); font-size: 11px; letter-spacing: .2em; text-transform: uppercase; color: var(--accent-text); margin-top: 6px; }

.btn { font-family: var(--ui); font-size: 13.5px; font-weight: 500; color: var(--text); background: var(--raised); border: 1px solid var(--line); border-radius: 9px; padding: 9px 14px; cursor: pointer; transition: background .15s, border-color .15s; }
.btn:hover { background: var(--surface); border-color: var(--ambient); }
.btn:focus-visible { outline: 2px solid var(--ambient); outline-offset: 2px; }
.datebar { display: flex; flex-wrap: wrap; align-items: center; gap: 9px; margin-top: 24px; }
.datebar input[type=date] {
  font-family: var(--mono); font-size: 13.5px; color: var(--text);
  background: var(--raised); border: 1px solid var(--line);
  border-radius: 9px; padding: 9px 12px; min-height: 40px;
}
/* Only invert the picker glyph on dark, where it ships black-on-black. */
:root[data-theme="dark"] .datebar input[type=date]::-webkit-calendar-picker-indicator { filter: invert(1); }
.datebar input[type=date]::-webkit-calendar-picker-indicator { opacity: .7; cursor: pointer; }

/* --- the day scrubber -------------------------------------------------
   SLIMMED. This used to be its own padded, backdrop-blurred card — heavy
   enough to compete with the sky animation it drives for the same visual
   weight. It is a control, not a panel: one thin track, one line of live
   state underneath, no chrome of its own. Nothing it showed was cut — the
   phase, the moon, the time and the Now button are all still here, just
   read left to right instead of stacked in two rows inside a box. */

/* Full width of the lower band: it drives the animation above it, so its
   track reads as a timeline for the whole hero rather than a stub under
   one column. */
.scrub { margin: 0; }

/* The span this track covers, named at both ends. Without these the slider
   is 0–24h against nothing; with them it reads as "this is the stretch of
   daylight, and you are here inside it". */
.scrub-caps { display: flex; align-items: flex-end; justify-content: space-between; gap: var(--s3); margin-bottom: var(--s2); }
.scrub-cap { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.scrub-cap-end { text-align: right; }
.scrub-cap-l { font-family: var(--mono); font-style: normal; font-size: 9.5px; letter-spacing: .16em; text-transform: uppercase; color: var(--muted); }
.scrub-cap b { font-family: var(--mono); font-size: 13px; font-weight: 500; color: var(--text); }
.scrub-span { font-family: var(--mono); font-size: 10px; letter-spacing: .14em; text-transform: uppercase; color: var(--accent-text); white-space: nowrap; padding-bottom: 2px; }

/* The track is painted with the day's own light — night at the ends,
   twilight bands, daylight in the middle. It doubles as a chart, so it
   stays thin rather than being padded out into a slab. */
.scrub input[type=range] {
  width: 100%; height: 5px; -webkit-appearance: none; appearance: none;
  border-radius: 99px; background: var(--band,#333); cursor: pointer;
  /* The track IS the day, so both its ends are night — and on a dark page
     night-coloured pixels on a near-black background give no edge at all:
     the reader cannot see how far the slider still has to travel. A hairline
     ring restores the extent without lightening the band itself, which has
     to stay honest because its colours are the twilight data. */
  box-shadow: inset 0 0 0 1px var(--track-ring);
}
.scrub input[type=range]::-webkit-slider-thumb { -webkit-appearance: none; width: 15px; height: 15px; margin-top: -5px; border-radius: 50%; background: #fff; border: 3px solid var(--ambient); cursor: grab; box-shadow: 0 1px 6px rgba(0,0,0,.5); }
.scrub input[type=range]::-moz-range-thumb { width: 15px; height: 15px; border-radius: 50%; background: #fff; border: 3px solid var(--ambient); cursor: grab; }
.scrub input[type=range]:focus-visible { outline: 2px solid var(--ambient); outline-offset: 3px; }

.scrub-row { display: flex; align-items: baseline; gap: 12px; margin-top: 8px; }
/* Live state, lit like live state — the phase line is what changes as the
   slider moves, so it gets the room; time and the button are secondary. */
.scrub-phase { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-family: var(--mono); font-size: 11.5px; letter-spacing: .04em; color: var(--accent-text); }
.scrub-time { flex: 0 0 auto; font-family: var(--mono); font-size: 12.5px; font-weight: 500; color: var(--text); }
.scrub-now { flex: 0 0 auto; font-family: var(--mono); font-size: 10.5px; letter-spacing: .1em; text-transform: uppercase; padding: 4px 10px; border-radius: 6px; background: var(--raised); border: 1px solid var(--line); color: var(--text); cursor: pointer; }
.scrub-now:hover { background: var(--surface); border-color: var(--ambient); }
.scrub-now:focus-visible { outline: 2px solid var(--ambient); outline-offset: 2px; }

/* Four across, explicitly. `auto-fit` wrapped these 2x2 the moment the
   available width dropped below 4x206px, which is exactly what happened
   while they were inside the narrow left column. They are one comparable
   set — sunrise, sunset, length, noon — so they belong on one row. */
.heroCards { display: grid; grid-template-columns: repeat(4,minmax(0,1fr)); gap: var(--gap); margin-top: 0; }
/* Plain surface cards now. The translucency and backdrop-blur existed to
   let the sky show through them; there is no sky behind them any more. */
.hcard { position: relative; padding: var(--pad-card); border-radius: var(--r); background: var(--surface); border: 1px solid var(--line); overflow: hidden; color: var(--text); box-shadow: var(--card-lift); }
.hcard::before { content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 3px; background: var(--c); }
.hcard-l { font-family: var(--mono); font-size: 10.5px; letter-spacing: .18em; text-transform: uppercase; opacity: .72; }
.hcard-v { font-family: var(--mono); font-size: 2.05rem; font-weight: 500; letter-spacing: -.03em; margin-top: 6px; line-height: 1; }
.hcard-m { font-size: 12.5px; opacity: .7; margin-top: 7px; }

/* ---------------- right now ------------------------------------------- */

.nowgrid { display: grid; grid-template-columns: repeat(auto-fit,minmax(158px,1fr)); gap: 1px; background: var(--line); border: 1px solid var(--line); border-radius: var(--r); overflow: hidden; margin: 0; }
.nowcell { background: var(--surface); padding: var(--pad-card); }
.nowcell dt { font-family: var(--mono); font-size: 10.5px; letter-spacing: .16em; text-transform: uppercase; color: var(--faint); }
.nowcell dd { margin: 6px 0 0; font-family: var(--mono); font-size: 1.45rem; letter-spacing: -.02em; }
.nowcell small { display: block; font-family: var(--ui); font-size: 12px; color: var(--muted); margin-top: 4px; }

/* ---------------- complete sun times ---------------------------------- */

.stgroup + .stgroup { margin-top: 22px; }
/* Mañana / Mediodía / Tarde. Full text contrast rather than --faint or the
   amber: these are structural headers, and the accent is already spoken for by
   the eyebrows one level up. The tick carries the meaning instead — it is the
   group's own phase colour (--gc), so the header is coded by altitude exactly
   like the cards under it, at every width rather than only on phones. */
.stlabel {
  font-family: var(--mono); font-size: 11.5px; font-weight: 600;
  letter-spacing: .2em; text-transform: uppercase;
  color: var(--text); margin-bottom: 11px;
  display: flex; align-items: center; gap: 10px;
}
.stlabel::before { content: ""; flex: 0 0 auto; width: 14px; height: 2px; border-radius: 2px; background: var(--gc, var(--ambient)); }
.stlabel .stcount { margin-left: auto; color: var(--faint); font-weight: 400; letter-spacing: .1em; }
/* 240 rather than 196: with the name and the time now sharing a row, a
   196px card left the name ~79px and wrapped "Astronomical dawn" onto two
   lines — which put back the height the two-column meta had just saved.
   Four wider cards read better than five that wrap. */
.stgrid { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(auto-fill,minmax(240px,1fr)); gap: var(--gap); }
/* Three children — the accent bar, the sky, the meta — in a two-column grid.
   Auto-placement therefore put the bar at (1,1), the sky at (1,2) and the
   meta at (2,1): the 3px column. The meta was laid out 3px wide and simply
   overflowed its box, which is why every name and note wrapped a word or a
   character at a time no matter how much room the card had. The bar now
   spans every row and the two content blocks are pinned to column 2. */
.stcard { display: grid; grid-template-columns: 3px minmax(0,1fr); border: 1px solid var(--line); border-radius: var(--r-s); overflow: hidden; background: var(--raised); }
.stcard::before { content: ""; background: var(--c); grid-column: 1; grid-row: 1 / -1; }
.stsky { grid-column: 2; position: relative; height: 88px; overflow: hidden; background: linear-gradient(180deg,var(--st),var(--sb)); }
.ststars { position: absolute; inset: 0; opacity: var(--stars,0); background-image: radial-gradient(1.1px 1.1px at 22% 28%,#fff,transparent),radial-gradient(1px 1px at 54% 16%,#fff,transparent),radial-gradient(1.1px 1.1px at 79% 32%,#fff,transparent); }
.stdisc { position: absolute; left: var(--dx); bottom: var(--dy); transform: translate(-50%,50%); width: 46px; height: 46px; border-radius: 50%; overflow: hidden; border: 1.5px solid var(--rim); box-shadow: 0 0 var(--bl) var(--sp) var(--gl); }
.stfill { position: absolute; left: 0; right: 0; bottom: 0; height: var(--fill); background: linear-gradient(180deg,var(--lt),var(--dk)); }
.stridge { position: absolute; left: 0; right: 0; bottom: 0; height: 30px; background: var(--ridge); clip-path: polygon(0 100%,10% 56%,22% 78%,36% 36%,50% 70%,64% 46%,78% 74%,90% 52%,100% 72%,100% 100%); }
/* Name and note stacked on the left, time on the right.
   These three used to be one vertical stack, which on a narrow card wrapped
   the name onto two lines, put the time on two more, and left a ragged
   column of dead space down the right-hand side. Two columns spend that
   space instead and cut the card's height roughly in half. */
.stmeta {
  grid-column: 2;
  padding: var(--pad-cell);
  display: grid;
  grid-template-columns: minmax(0,1fr) auto;
  grid-template-areas: "name time" "note time";
  align-items: center;
  column-gap: var(--s3);
  row-gap: 2px;
}
.stname { grid-area: name; margin: 0; font-size: 12.5px; color: var(--muted); }
/* nowrap: "4:35 AM" breaking after the digits was half of the wasted height */
.sttime { grid-area: time; margin: 0; align-self: center; white-space: nowrap; font-family: var(--mono); font-size: 1.25rem; font-weight: 500; letter-spacing: -.02em; }
.stnote { grid-area: note; margin: 0; font-size: 11.5px; color: var(--faint); }

/* ---------------- charts ---------------------------------------------- */

.chartbox { padding: var(--pad-card); }
.chartbox svg { display: block; width: 100%; height: auto; }
.chart-grid { stroke: var(--grid); stroke-width: 1; }
.chart-tick { fill: var(--faint); font-family: var(--mono); font-size: 10.5px; }
.chart-label { fill: var(--text); font-family: var(--mono); font-size: 11px; }
.chart-hover-wrap { position: relative; }
.chart-tip { position: absolute; pointer-events: none; max-width: calc(100% - 16px); background: var(--surface); border: 1px solid var(--line); border-radius: 9px; padding: 9px 12px; font-family: var(--mono); font-size: 12px; box-shadow: 0 10px 30px rgba(0,0,0,.4); white-space: nowrap; z-index: 5; }
.chart-tip[hidden] { display: none; }
.chart-tip strong { display: block; }
.chart-tip span { display: block; color: var(--muted); }
.chart-tip .tt-d { color: var(--faint); font-size: 10.5px; letter-spacing: .1em; text-transform: uppercase; margin-bottom: 5px; }
.chart-tip .tt-r { color: var(--sunrise); }
.chart-tip .tt-s { color: var(--sunset); }
.chart-tip .tip-phase { color: var(--ambient); }
.legend { display: flex; flex-wrap: wrap; gap: 8px 20px; margin-top: 14px; padding-top: 14px; border-top: 1px solid var(--line-soft); font-size: 12.5px; color: var(--muted); }
.legend i { display: inline-block; width: 16px; height: 3px; border-radius: 2px; margin-right: 8px; vertical-align: middle; }

/* ---------------- map -------------------------------------------------- */

.maprow { display: grid; grid-template-columns: 1fr 292px; gap: 16px; }
.mapstage { position: relative; height: 470px; border-radius: var(--r); overflow: hidden; border: 1px solid var(--line); background: var(--sunk); cursor: grab; touch-action: none; user-select: none; -webkit-user-select: none; }
.mapstage.is-panning { cursor: grabbing; }
/* Tiles are <img>. Without this a drag grabs the image itself and the
   browser shows the "no drop" cursor instead of panning the map. */
.mapstage img, .mapstage a { -webkit-user-drag: none; user-drag: none; }

/* Tiles are printed for white paper. Take them down to the night palette
   without inverting, so roads and water stay recognisable. Light mode leaves
   them alone — the filter was previously unconditional, which is why the map
   looked wrong the moment a light theme existed. */
:root[data-theme="dark"] .leaflet-tile { filter: brightness(.68) saturate(.72) contrast(1.06); }
:root[data-theme="dark"] .leaflet-control-attribution { background: rgba(14,17,25,.82) !important; color: var(--muted) !important; }
:root[data-theme="dark"] .leaflet-control-attribution a { color: var(--muted) !important; }
:root[data-theme="dark"] .leaflet-control-zoom a { background: #1D222E; color: #E9ECF3; border-color: #262C3A; }

/* Rotation lives on a wrapper, so Leaflet's own transforms are never
   touched. Its size is set in JS to the stage's own diagonal — a square
   that big circumscribes the stage at every angle, so no corner can ever
   rotate into view. A fixed percentage only works for the one aspect ratio
   it was tuned against; 200% here is only the pre-JS fallback. */
.map-rotor { position: absolute; left: 50%; top: 50%; width: 200%; height: 200%; transform: translate(-50%,-50%) rotate(var(--rot,0deg)); transform-origin: 50% 50%; }
#sunMap { position: absolute; inset: 0; }

/* The bearing overlay is pinned to the true centre of the stage, so every
   line starts dead-centre on the observer instead of drifting. */
.sunoverlay { position: absolute; inset: 0; pointer-events: none; z-index: 500; }
.sunoverlay svg { position: absolute; inset: 0; width: 100%; height: 100%; }

.compass {
  position: absolute; right: 14px; bottom: 14px; z-index: 700;
  width: 74px; height: 74px; border-radius: 50%; padding: 0;
  background: var(--casing); border: 1px solid rgba(0,0,0,.2);
  box-shadow: 0 3px 14px rgba(0,0,0,.3); cursor: grab; touch-action: none;
}
.compass:active { cursor: grabbing; }
.compass:focus-visible { outline: 2px solid var(--ambient); outline-offset: 3px; }
.compass svg { width: 100%; height: 100%; transform: rotate(var(--rot,0deg)); }
.compass-reset { position: absolute; right: 14px; bottom: 96px; z-index: 700; font-family: var(--mono); font-size: 10px; letter-spacing: .1em; text-transform: uppercase; padding: 5px 9px; border-radius: 7px; background: var(--casing); color: var(--text); border: 1px solid rgba(0,0,0,.2); cursor: pointer; opacity: 0; transition: opacity .2s; pointer-events: none; }
.compass-reset.show { opacity: 1; pointer-events: auto; }

.mapside { display: flex; flex-direction: column; gap: var(--s3); }
.bearcard { padding: 13px 14px; border-radius: var(--r-s); background: var(--raised); border: 1px solid var(--line); border-left: 3px solid var(--c); }
.bearcard dt { font-family: var(--mono); font-size: 10px; letter-spacing: .16em; text-transform: uppercase; color: var(--faint); }
.bearcard dd { margin: 5px 0 0; display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
.bearcard .b-t { font-family: var(--mono); font-size: 1.2rem; }
.bearcard .b-d { font-family: var(--mono); font-size: 12px; color: var(--muted); }

.mapslider { padding: 15px; border-radius: var(--r-s); background: var(--sunk); border: 1px solid var(--line); }
.mapslider input[type=range] { width: 100%; height: 8px; -webkit-appearance: none; appearance: none; border-radius: 99px; background: var(--band,#333); cursor: pointer; box-shadow: inset 0 0 0 1px var(--track-ring); }
.mapslider input[type=range]::-webkit-slider-thumb { -webkit-appearance: none; width: 18px; height: 18px; border-radius: 50%; background: #fff; border: 3px solid var(--ambient); box-shadow: 0 1px 5px rgba(0,0,0,.45); }
.mapslider input[type=range]::-moz-range-thumb { width: 18px; height: 18px; border-radius: 50%; background: #fff; border: 3px solid var(--ambient); }
.mapslider-h { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 9px; }
.mapslider-h b { font-family: var(--mono); font-size: 1.25rem; font-weight: 500; }
.mapslider-h span { font-family: var(--mono); font-size: 10px; letter-spacing: .16em; text-transform: uppercase; color: var(--faint); }
.mapslider .row { display: flex; justify-content: space-between; align-items: center; margin-top: 10px; gap: 10px; }
.mapslider .row .sliderphase { font-family: var(--mono); font-size: 11px; letter-spacing: .12em; text-transform: uppercase; color: var(--ambient); }
.qbtn { font-family: var(--mono); font-size: 11px; padding: 5px 10px; border-radius: 7px; background: var(--raised); border: 1px solid var(--line); color: var(--muted); cursor: pointer; }
.qbtn:hover { border-color: var(--ambient); color: var(--text); }

/* ---------------- controls (the restored pickers) ---------------------- */

.controls { display: flex; flex-wrap: wrap; gap: 12px; align-items: flex-end; margin-bottom: 16px; }
.field { display: flex; flex-direction: column; gap: 6px; }
.field label { font-family: var(--mono); font-size: 10px; letter-spacing: .16em; text-transform: uppercase; color: var(--faint); }
.field select, .field input {
  background: var(--raised); border: 1px solid var(--line); color: var(--text);
  border-radius: 9px; padding: 9px 12px; font-family: var(--ui); font-size: 14px; min-height: 40px;
}
.field select:focus, .field input:focus { outline: none; border-color: var(--ambient); box-shadow: 0 0 0 3px var(--sr-dim); }
.go { background: var(--ambient); color: var(--night); border: 0; border-radius: 9px; padding: 10px 18px; font-family: var(--ui); font-size: 14px; font-weight: 600; cursor: pointer; min-height: 40px; }
.go:focus-visible { outline: 2px solid var(--text); outline-offset: 2px; }
.summary-card { padding: var(--pad-card); margin-bottom: var(--gap); }
.summary-card h3 { font-family: var(--display); font-size: 1.15rem; font-weight: 500; }
.readout { display: grid; grid-template-columns: repeat(auto-fit,minmax(160px,1fr)); gap: var(--gap); margin-top: var(--s3); }
.readout > div { display: flex; flex-direction: column; gap: 3px; }
.readout .k, .readout .label { font-family: var(--mono); font-size: 10px; letter-spacing: .14em; text-transform: uppercase; color: var(--faint); }
.readout .v, .readout .value { font-family: var(--mono); font-size: 1.05rem; }

/* ---------------- tables ----------------------------------------------- */

.table-scroll { overflow: auto; border-radius: var(--r); border: 1px solid var(--line); }
table { border-collapse: collapse; width: 100%; font-family: var(--mono); font-size: 12.5px; font-variant-numeric: tabular-nums; }
th,td { padding: 10px var(--s3); text-align: right; white-space: nowrap; border-bottom: 1px solid var(--line-soft); background: var(--surface); }
th:first-child, td:first-child { text-align: left; }
thead th { position: sticky; top: 0; background: var(--sunk); color: var(--faint); font-weight: 500; font-size: 10px; letter-spacing: .13em; text-transform: uppercase; border-bottom: 1px solid var(--line); z-index: 2; }
tbody tr:hover td { background: var(--hover); }
td.rise { color: var(--sunrise); }
td.set { color: var(--sunset); }
tr.is-today td { background: var(--today-fill); font-weight: 600; }
tr.is-today td:first-child { color: var(--ambient); }
.delta-up { color: var(--golden); }
.delta-dn { color: var(--bluehour); }

.year-table thead th.month-head { text-align: center; border-left: 1px solid var(--line); }
.year-table td.day-num { color: var(--faint); position: sticky; left: 0; background: var(--sunk); z-index: 1; }
.year-table thead th:first-child { left: 0; z-index: 3; }
.year-table td.rise { border-left: 1px solid var(--line-soft); }
.year-table .season-summer { background-image: linear-gradient(var(--sr-dim),var(--sr-dim)); }
.year-table .season-winter { background-image: linear-gradient(var(--bh-dim),var(--bh-dim)); }
.year-table thead th.season-summer { color: var(--sunrise); }
.year-table thead th.season-winter { color: var(--bluehour); }
.year-table td.is-today { box-shadow: inset 0 0 0 1.5px var(--ambient); font-weight: 700; }
.seasonkey { display: flex; flex-wrap: wrap; gap: 10px 20px; margin-top: 13px; font-size: 12.5px; color: var(--muted); }
.seasonkey i { display: inline-block; width: 22px; height: 11px; border-radius: 3px; margin-right: 8px; vertical-align: -1px; border: 1px solid var(--line); }

/* ---------------- prose / faq / cities --------------------------------- */

.prose { display: grid; grid-template-columns: 1.35fr 1fr; gap: 26px; }
.prose p { color: var(--muted); font-size: 15px; max-width: 66ch; }
.prose p + p { margin-top: 12px; }
.prose b { color: var(--text); font-weight: 600; }
.factlist { list-style: none; margin: 0; padding: 0; }
.factlist li { display: flex; justify-content: space-between; gap: 14px; padding: 10px 0; border-bottom: 1px solid var(--line-soft); font-size: 13.5px; }
.factlist li:last-child { border-bottom: 0; }
.factlist .k { color: var(--muted); }
.factlist .v { font-family: var(--mono); }

.faq { border-top: 1px solid var(--line); }
.faq details { border-bottom: 1px solid var(--line); }
.faq summary { padding: 17px 40px 17px 0; cursor: pointer; font-size: 16px; font-weight: 500; position: relative; list-style: none; }
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after { content: "+"; position: absolute; right: 6px; top: 50%; transform: translateY(-50%); font-family: var(--mono); font-size: 19px; color: var(--ambient); }
.faq details[open] summary::after { content: "\2212"; }
.faq summary:focus-visible { outline: 2px solid var(--ambient); outline-offset: -2px; }
.faq .a { padding: 0 40px 20px 0; color: var(--muted); font-size: 15.5px; line-height: 1.65; max-width: 70ch; }
.faq .a b { color: var(--text); font-weight: 600; }

.citygrid { display: grid; grid-template-columns: repeat(auto-fill,minmax(214px,1fr)); gap: var(--gap); }

/* --- index grids: countries, and a country's full city list -------------
   A denser relative of .citygrid for rows that are a name and nothing else.
   Deliberately not .citygrid: those cards carry times and earn their size,
   these are navigation and 240 of them at card size would be a scroll with
   no shape to it. */
/* The country blurb, under the country name.
   The measure is wide (~100ch) rather than the 65ch that suits running prose,
   because this is two sentences and the brief was two LINES — at a normal
   reading measure the same text wrapped to three. Still capped, so it never
   runs the full width of a large monitor. */
.country-about { max-width: 100ch; margin-top: var(--s3); font-size: 15.5px; line-height: 1.55; color: var(--muted); }

/* /countries/ — the continent label is a heading in the page's own voice: a
   notch under h1, in the display face, at full text contrast in both themes.
   It used to borrow .stlabel, whose mono micro-caps belong to the sun-phase
   groups and read as a caption here. */
.continent-h {
  font-family: var(--display); font-weight: 500; letter-spacing: -.015em;
  font-size: clamp(1.35rem, 2.4vw, 1.7rem); line-height: 1.15;
  color: var(--accent-text); text-transform: none;
  display: flex; align-items: baseline; gap: var(--s3);
}
.continent-h .stcount {
  margin-left: auto; font-family: var(--mono); font-size: 11px;
  letter-spacing: .1em; font-weight: 400; color: var(--faint);
}

/* The country name inside a link card. h3 for the crawl outline; the visual
   weight stays exactly what the card had. */
.linkgrid h3 { font-size: 14px; font-weight: 500; margin: 0; line-height: 1.35; }

.linkgrid { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(auto-fill,minmax(190px,1fr)); gap: var(--s2); }
.linkgrid a {
  display: flex; align-items: center; justify-content: space-between; gap: var(--s2);
  padding: 10px 13px; border-radius: var(--r-s); text-decoration: none;
  background: var(--raised); border: 1px solid var(--line);
  font-size: 14px; color: var(--text);
  transition: border-color .15s, background .15s;
}
.linkgrid a:hover { border-color: var(--ambient); background: var(--surface); }
.linkgrid a:focus-visible { outline: 2px solid var(--ambient); outline-offset: 2px; }
/* The count, or a "capital" flag — secondary, so it never competes with the
   name it annotates. */
.lg-tag {
  flex: 0 0 auto; font-family: var(--mono); font-style: normal;
  font-size: 10px; letter-spacing: .08em; color: var(--faint);
}
.citycard { display: block; text-decoration: none; padding: var(--pad-cell); border-radius: var(--r-s); background: var(--raised); border: 1px solid var(--line); transition: border-color .15s, transform .15s; }
.citycard:hover { border-color: var(--ambient); transform: translateY(-2px); }
.citycard:focus-visible { outline: 2px solid var(--ambient); outline-offset: 2px; }
.citycard .cc-n { font-weight: 600; font-size: 14.5px; }
.citycard .cc-c { font-size: 12px; color: var(--faint); margin-top: 1px; }
.citycard .cc-t { display: flex; gap: 12px; margin-top: 10px; font-family: var(--mono); font-size: 12.5px; }
.citycard .cc-t .r { color: var(--sunrise); }
.citycard .cc-t .s { color: var(--sunset); }
.tabs { display: flex; gap: 6px; margin-bottom: 15px; flex-wrap: wrap; }
.mbtn { font-family: var(--mono); font-size: 12px; padding: 7px 12px; border-radius: 8px; background: var(--raised); border: 1px solid var(--line); color: var(--muted); cursor: pointer; }
.mbtn[aria-pressed="true"] { background: var(--ambient); border-color: transparent; color: var(--night); font-weight: 600; }
.mbtn:focus-visible { outline: 2px solid var(--ambient); outline-offset: 2px; }

footer { border-top: 1px solid var(--line); padding: var(--s6) 0 60px; color: var(--faint); font-size: 12.5px; }
footer a { color: var(--muted); }
.callout { margin-top: 14px; padding: 13px 16px; border-left: 2px solid var(--ambient); background: var(--sunk); border-radius: 0 var(--r-s) var(--r-s) 0; font-size: 13.5px; color: var(--muted); }
.callout b { color: var(--text); }

.state { padding: 16px 18px; border-radius: var(--r-s); background: var(--sunk); border: 1px solid var(--line); color: var(--muted); font-size: 14px; }

/* ======================================================================
   RESPONSIVE
   Two rules drive everything below:
   1. Nothing may widen the page. Wide things scroll inside their own box.
   2. Dense data never gets squeezed below legibility — a chart shrunk to
      phone width renders its labels at ~3px, so it re-lays-out instead.
   ====================================================================== */

#arcChart, #yearChart { overflow: visible; }
#arcChart .chart-hover-wrap, #yearChart .chart-hover-wrap { margin: 0 auto; }
#arcChart svg, #yearChart svg { display: block; margin: 0 auto; }

.scrollhint { display: none; font-family: var(--mono); font-size: 10.5px; letter-spacing: .14em; text-transform: uppercase; color: var(--faint); margin-top: 9px; align-items: center; gap: 7px; }
.scrollhint::before { content: "←→"; letter-spacing: 0; }

@media (max-width: 1100px) {
  .maprow { grid-template-columns: 1fr; }
  .mapside { display: grid; grid-template-columns: repeat(auto-fit,minmax(168px,1fr)); align-items: start; }
  .mapslider { grid-column: 1/-1; }
}

/* tablet */
@media (max-width: 860px) {
  :root { --gutter: 20px; --sec-y: 56px; }
  .prose { grid-template-columns: 1fr; }
  .mapstage { height: 420px; }
  .scrollhint { display: flex; }
  /* No room for two columns: the animation and its slider stack under the
     clock they belong to. Four cards across would be ~140px each here, so
     they go two-up. */
  .hero-top { grid-template-columns: minmax(0,1fr); gap: var(--s5); }
  .hero-track { min-height: 200px; }
  .heroCards { grid-template-columns: repeat(2,minmax(0,1fr)); }
}

/* large phone / small tablet */
@media (max-width: 760px) {
  :root { --gutter: 18px; --sec-y: var(--s7); }
  .topbar-in { flex-wrap: wrap; gap: 10px 12px; padding: 10px 16px; }
  .brand { order: 1; }
  .tgl { order: 2; margin-left: auto; }
  .searchwrap { order: 3; flex: 1 0 100%; max-width: none; margin: 0; }
  .hero-in { padding-block: 22px 30px; }
  .hero-track { min-height: 170px; }
  .hero-sun { width: 40px; height: 40px; }
  .hero-moon { width: 31px; height: 31px; }
  .datebar { gap: 7px; }
  .datebar .btn { padding: 8px 12px; font-size: 13px; }
  .mapstage { height: 400px; }
  .faq summary { font-size: 14.5px; padding: 14px 34px 14px 0; }
  .faq .a { padding-right: 0; font-size: 14px; }
  .controls { gap: 10px; }
}

/* ----------------------------------------------------------------------
   MOBILE PHASE CLUSTERS

   ADDED, not ported. On a phone the eleven sun-time cards are one long
   scroll with no sense of where in the day you are. Below 720px each phase
   becomes its own scroll section with a header that sticks while you move
   through that phase's times and is pushed off by the next one.

   Sticky rather than collapsible on purpose: nothing is hidden behind a tap,
   the scroll gesture is the only interaction, and the label always answers
   "which part of the day am I reading" without the reader asking.
   ---------------------------------------------------------------------- */
@media (max-width: 720px) {
  .stgroup { margin: 0; }
  .stgroup + .stgroup { margin-top: 0; }

  .stlabel {
    position: sticky;
    /* clears the sticky topbar, which is ~49px on phones */
    top: 48px;
    z-index: 6;
    /* bleeds to the page edge, so it must track the gutter exactly */
    margin: 0 calc(var(--gutter) * -1) var(--s3);
    padding: var(--s3) var(--gutter);
    background: color-mix(in srgb, var(--night) 92%, transparent);
    backdrop-filter: blur(10px);
    border-bottom: 1px solid var(--line-soft);
    color: var(--text);
    font-size: 11px;
    display: flex;
    align-items: center;
    gap: 9px;
  }
  /* A tick in the phase's own colour, so the header carries the same
     altitude coding as the cards under it. */
  .stlabel::before { content: ""; width: 14px; height: 2px; border-radius: 2px; background: var(--gc, var(--ambient)); }
  .stlabel .stcount { margin-left: auto; color: var(--faint); font-weight: 400; letter-spacing: .1em; }

  .stgroup + .stgroup .stlabel { margin-top: var(--s5); }
  .stgrid { padding-bottom: 4px; }
}

/* phone */
@media (max-width: 560px) {
  /* Type steps down and grids drop columns. Padding does NOT move — the
     card interiors here are the same 20px they are on a 27" display. */
  h1 { font-size: 1.85rem; }
  .hero-clock { font-size: 2.4rem; }
  .heroCards { grid-template-columns: 1fr 1fr; }
  .hcard-v { font-size: 1.45rem; }
  .hcard-l { font-size: 9.5px; }
  .hcard-m { font-size: 10.5px; }
  .nowgrid { grid-template-columns: 1fr 1fr; }
  .nowcell dd { font-size: 1.2rem; }
  /* One per row, laid out sideways: thumbnail beside the text rather than
     above it. Two-up at this width leaves ~128px for the meta, which is not
     enough for a name and a time on one line — so the card turns instead of
     being squeezed, and ends up shorter AND wider than the stacked version
     it replaces. */
  .stgrid { grid-template-columns: 1fr; }
  .stcard { grid-template-columns: 3px 116px minmax(0,1fr); }
  .stsky { grid-column: 2; height: 100%; min-height: 84px; }
  .stmeta { grid-column: 3; }
  .stdisc { width: 36px; height: 36px; }
  .sttime { font-size: 1.2rem; }
  .stname { font-size: 12px; }
  .stnote { font-size: 11px; }
  .mapstage { height: 340px; }
  .mapside { grid-template-columns: 1fr 1fr; }
  .compass { width: 60px; height: 60px; right: 10px; bottom: 10px; }
  .compass-reset { right: 10px; bottom: 78px; }
  .citygrid { grid-template-columns: 1fr 1fr; }
  /* The table is the one place that may still scroll: it keeps real cell
     padding and overflows horizontally rather than crushing to 6px. */
  table { font-size: 11.5px; }
  .field select, .field input { font-size: 13.5px; padding: 10px 12px; min-height: 40px; }
  .go { padding: 10px var(--s4); font-size: 13.5px; min-height: 40px; }
  .readout { grid-template-columns: 1fr 1fr; }
  .legend, .seasonkey { font-size: 11.5px; gap: var(--s2) var(--gap); }
  footer { font-size: 11.5px; padding: var(--s6) 0 var(--s7); }
}

/* small phone */
@media (max-width: 390px) {
  :root { --gutter: var(--s4); }
  .heroCards { grid-template-columns: 1fr; }
  .nowgrid { grid-template-columns: 1fr; }
  .stgrid { grid-template-columns: 1fr; }
  /* Narrower thumbnail so the time still fits beside the name at 360px. */
  .stcard { grid-template-columns: 3px 96px minmax(0,1fr); }
  .stmeta { grid-column: 3; }
  .citygrid { grid-template-columns: 1fr; }
  .mapside { grid-template-columns: 1fr; }
  .readout { grid-template-columns: 1fr; }
  .brand { font-size: 17px; }
  .hero-clock { font-size: 2.1rem; }
  .mapstage { height: 300px; }
}

/* coarse pointers: bigger hit targets, no hover-only affordances */
@media (pointer: coarse) {
  .scrub input[type=range]::-webkit-slider-thumb,
  .mapslider input[type=range]::-webkit-slider-thumb { width: 24px; height: 24px; }
  .btn, .qbtn, .mbtn, .go, .scrub-now { min-height: 40px; }
  .compass { width: 68px; height: 68px; }
}

@media (prefers-reduced-motion: reduce) {
  * { animation: none !important; transition: none !important; }
  html { scroll-behavior: auto; }
}

/* ==========================================================================
   §navigation loader

   Every page but the homepage is a heavy document — the city template ships a
   full solar model and the country indexes run to hundreds of rows — so the
   gap between a tap and the next paint is long enough that the tap reads as
   ignored. This covers that gap, and nothing else: it is a navigation
   indicator, not a page-load splash. It never shows on first paint.

   The delay below matters as much as the animation. Showing instantly makes
   fast navigations flash a spinner, which reads as slower, not faster.
   ========================================================================== */

.navload {
  position: fixed; inset: 0; z-index: 90;
  display: grid; place-items: center;
  background: color-mix(in srgb, var(--night) 82%, transparent);
  backdrop-filter: blur(3px);
  opacity: 0; visibility: hidden;
  transition: opacity .18s ease, visibility .18s;
}
.navload[data-on] { opacity: 1; visibility: visible; }

/* The hairline at the top edge is the part that reads on a phone, where the
   centred mark can sit below the thumb. It is indeterminate on purpose: the
   real duration is unknowable, and a fake percentage is a lie. */
.navload-bar { position: fixed; left: 0; top: 0; height: 2px; width: 100%; overflow: hidden; background: transparent; }
.navload-bar::after {
  content: ""; display: block; height: 100%; width: 34%;
  background: linear-gradient(90deg, transparent, var(--ambient), transparent);
  animation: navload-sweep 1.15s ease-in-out infinite;
}

/* Sun and moon, the site's own two bodies: the moon tracks across the disc and
   off again, so the mark is a transit rather than a generic spinner. */
.navload-mark { position: relative; width: 76px; height: 76px; margin: 0 auto; }
.navload-rays { position: absolute; inset: 0; animation: navload-spin 9s linear infinite; }
.navload-rays::before, .navload-rays::after {
  content: ""; position: absolute; inset: 0; border-radius: 50%;
  border: 1.5px dashed color-mix(in srgb, var(--ambient) 55%, transparent);
}
.navload-rays::after { inset: 9px; border-style: dotted; opacity: .6; animation: navload-spin 6s linear infinite reverse; }
.navload-sun {
  position: absolute; inset: 22px; border-radius: 50%;
  background: radial-gradient(circle at 34% 32%, var(--golden), var(--sunrise) 68%, var(--sunset));
  box-shadow: 0 0 22px color-mix(in srgb, var(--ambient) 45%, transparent);
  animation: navload-pulse 1.9s ease-in-out infinite;
}
.navload-moon {
  position: absolute; top: 50%; left: 50%; width: 15px; height: 15px; margin: -7.5px 0 0 -7.5px;
  border-radius: 50%; background: var(--shadow);
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--night) 70%, transparent);
  animation: navload-transit 2.6s cubic-bezier(.45,0,.55,1) infinite;
}
.navload-t { text-align: center; margin: var(--s4) 0 0; font-family: var(--mono); font-size: 10.5px; letter-spacing: .22em; text-transform: uppercase; color: var(--accent-text); }

@keyframes navload-spin  { to { transform: rotate(360deg); } }
@keyframes navload-pulse { 0%,100% { transform: scale(1); } 50% { transform: scale(.92); } }
@keyframes navload-sweep { 0% { transform: translateX(-100%); } 100% { transform: translateX(390%); } }
@keyframes navload-transit {
  0%   { transform: translateX(-46px); opacity: 0; }
  18%  { opacity: 1; }
  82%  { opacity: 1; }
  100% { transform: translateX(46px); opacity: 0; }
}

@media (max-width: 560px) {
  .navload-mark { width: 62px; height: 62px; }
  .navload-sun { inset: 18px; }
  .navload-t { font-size: 9.5px; letter-spacing: .18em; }
}

/* Motion is the whole mechanism here, so the reduced-motion path does not just
   slow it down — it drops to a static mark plus the text, which still answers
   "did my tap register". */
@media (prefers-reduced-motion: reduce) {
  .navload-rays, .navload-rays::after, .navload-sun, .navload-moon, .navload-bar::after { animation: none; }
  .navload-moon { opacity: .9; transform: translateX(26px); }
}

/* ==========================================================================
   §homepage content

   The homepage stopped being a menu. These are the sections that carry the
   answer, the concepts and the method — everything the city pages assume the
   reader already knows and no page actually explained.
   ========================================================================== */

/* --- the answer block ---------------------------------------------------
   Deliberately the loudest thing on the page. The figures are the reason
   anyone arrived; the skeleton state is dimmed rather than hidden so the
   layout never jumps when the real values land. */
.answerblock[data-state="loading"] .ans-figs { opacity: .45; }
.answerblock[data-state="ask"] .ans-note::after {
  content: " Escribe tu ciudad abajo para el dato exacto.";
}
.answerblock .ans-figs { transition: opacity .2s ease; }

.ansCard { padding: var(--pad-card); margin-top: var(--s2); }
.ans-top { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--s4); flex-wrap: wrap; margin-bottom: var(--s5); }
.ans-place { font-family: var(--display); font-size: 1.35rem; font-weight: 500; letter-spacing: -.015em; margin: 0; }
.ans-note { color: var(--muted); font-size: 13px; margin: 6px 0 0; max-width: 62ch; }

.ans-precise {
  flex: 0 0 auto; cursor: pointer;
  font-family: var(--mono); font-size: 11px; letter-spacing: .12em; text-transform: uppercase;
  padding: 10px 14px; border-radius: var(--r-s);
  background: transparent; color: var(--accent-text);
  border: 1px solid color-mix(in srgb, var(--ambient) 45%, transparent);
  transition: background .15s, border-color .15s;
}
.ans-precise:hover:not(:disabled) { background: var(--hover); border-color: var(--ambient); }
.ans-precise:disabled { opacity: .55; cursor: default; }
.ans-precise:focus-visible { outline: 2px solid var(--ambient); outline-offset: 2px; }

.ans-figs { display: grid; grid-template-columns: repeat(auto-fit,minmax(148px,1fr)); gap: var(--gap); margin: 0; }
.ans-fig { position: relative; padding-left: var(--s3); border-left: 3px solid var(--c, var(--ambient)); }
.ans-fig dt { font-family: var(--mono); font-size: 10.5px; letter-spacing: .16em; text-transform: uppercase; color: var(--faint); }
.ans-fig dd { margin: 6px 0 0; font-family: var(--mono); font-size: clamp(1.6rem, 4vw, 2.05rem); font-weight: 500; letter-spacing: -.03em; line-height: 1; }

.ans-link { display: inline-block; margin-top: var(--s5); font-size: 14px; color: var(--accent-text); }

/* --- hoy en el mundo ---------------------------------------------------- */
.wt-grid { display: grid; grid-template-columns: repeat(auto-fit,minmax(220px,1fr)); gap: var(--gap); }
.wt-card { background: var(--surface); border: 1px solid var(--line); border-radius: var(--r); box-shadow: var(--card-lift); padding: var(--pad-card); }
.wt-l { font-family: var(--mono); font-size: 10.5px; letter-spacing: .16em; text-transform: uppercase; color: var(--faint); margin: 0; }
.wt-v { font-family: var(--mono); font-size: 1.7rem; font-weight: 500; letter-spacing: -.03em; margin: 8px 0 0; line-height: 1; }
.wt-s { color: var(--muted); font-size: 14.5px; margin: 10px 0 0; line-height: 1.55; }
.wt-s a { color: var(--text); text-decoration-color: var(--line); }
.wt-a { display: inline-block; margin-top: 11px; font-size: 13px; color: var(--accent-text); }
/* Holds the section's height before the data lands, so nothing below it jumps. */
.wt-skeleton { min-height: 132px; background: var(--sunk); border-style: dashed; box-shadow: none; }

/* --- the concept list ---------------------------------------------------
   The angle is the definition, so it gets the same weight as the term and
   sits in the mono face the rest of the site uses for measured values. */
.notegrid { display: grid; grid-template-columns: repeat(auto-fit,minmax(300px,1fr)); gap: var(--gap); }
.notecard { padding: var(--pad-card); }
.notecard h3 { font-size: 15.5px; font-weight: 600; }
.notecard p { color: var(--muted); font-size: 15.5px; margin: 10px 0 0; line-height: 1.65; }

/* --- method -------------------------------------------------------------- */
.methodgrid { display: grid; grid-template-columns: repeat(auto-fit,minmax(320px,1fr)); gap: var(--gap); }
.methodcard { padding: var(--pad-card); }
.methodcard h3 { font-size: 15.5px; font-weight: 600; margin-bottom: 10px; }
.methodcard p { color: var(--muted); font-size: 15.5px; line-height: 1.65; margin: 0 0 11px; }
.methodcard b { color: var(--text); font-weight: 600; }
.tightlist { margin: 0 0 13px; padding-left: 18px; color: var(--muted); font-size: 15.5px; line-height: 1.65; }
.tightlist li + li { margin-top: 8px; }

.srcgrid { margin: 0; }
.srcrow { display: flex; gap: var(--s4); padding: 9px 0; border-top: 1px solid var(--line-soft); }
.srcrow:first-child { border-top: 0; }
.srcrow dt { flex: 0 0 40%; font-family: var(--mono); font-size: 10.5px; letter-spacing: .12em; text-transform: uppercase; color: var(--faint); padding-top: 2px; }
.srcrow dd { margin: 0; font-size: 14.5px; line-height: 1.55; color: var(--text); }
.fineprint { color: var(--faint); font-size: 12.5px; margin-top: var(--s4); line-height: 1.55; }

/* --- clusters ------------------------------------------------------------ */
.clusters { display: grid; gap: var(--s6); }
.cluster h3 { font-family: var(--display); font-size: 1.2rem; font-weight: 500; letter-spacing: -.015em; }
.cluster-note { color: var(--muted); font-size: 15px; line-height: 1.6; margin: 6px 0 var(--s4); max-width: 70ch; }
.linkgrid h4 { margin: 0; font-size: 14px; font-weight: 500; line-height: 1.35; }

@media (max-width: 560px) {
  .ans-top { flex-direction: column; }
  .ans-precise { width: 100%; text-align: center; }
  .ans-figs { grid-template-columns: repeat(2,1fr); }
  .phaseitem { flex-direction: column; gap: var(--s2); }
  .ph-a { text-align: left; min-width: 0; }
  .srcrow { flex-direction: column; gap: 3px; }
  .srcrow dt { flex-basis: auto; }
}

/* --- the day, as a picture ----------------------------------------------
   Four numbers tell you when; the strip tells you where you are in the day.
   Painted from getDayBands(), the same split the city page's slider track
   uses, so the homepage cannot contradict the page it links to. */
.ans-band { margin-top: var(--s5); }
.ans-strip {
  position: relative; height: 16px; border-radius: 999px;
  border: 1px solid var(--track-ring);
  background: var(--sunk);
  transition: background .3s;
}
.ans-band { position: relative; }
.ans-now {
  position: absolute; top: -4px; width: 2px; height: 24px;
  background: var(--text); border-radius: 2px; left: 50%;
  box-shadow: 0 0 0 2px var(--casing);
  transition: left .3s ease;
}
.ans-now b {
  position: absolute; top: -20px; left: 50%; transform: translateX(-50%);
  font-size: 10.5px; letter-spacing: .04em; color: var(--text); white-space: nowrap;
}
.ans-scale {
  display: flex; justify-content: space-between; margin-top: 7px;
  font-family: var(--mono); font-size: 10px; letter-spacing: .1em; color: var(--faint);
}
/* Nothing to point at until the figures resolve. */
.answerblock:not([data-state="ready"]) .ans-now { opacity: 0; }

/* --- concept cards -------------------------------------------------------
   The thumbnail is the definition. .stsky and its children are the city
   page's own painting primitives, reused verbatim — see Concepts.astro. */
.conceptgrid {
  list-style: none; margin: 0 0 var(--s6); padding: 0;
  display: grid; grid-template-columns: repeat(auto-fit,minmax(280px,1fr)); gap: var(--gap);
}
.conceptcard {
  display: flex; flex-direction: column;
  border: 1px solid var(--line); border-radius: var(--r);
  background: var(--surface); box-shadow: var(--card-lift); overflow: hidden;
}
.cc-sky { height: 122px; border-bottom: 1px solid var(--line); }
.cc-angle {
  position: absolute; left: 12px; top: 10px; z-index: 2;
  font-size: 15px; font-weight: 500; letter-spacing: -.01em;
  color: #fff; text-shadow: 0 1px 6px rgba(0,0,0,.6);
}
.cc-body { padding: var(--pad-card); border-left: 3px solid var(--c); flex: 1; }
.cc-body h3 { font-size: 15.5px; font-weight: 600; }
.cc-body p { color: var(--muted); font-size: 15px; line-height: 1.6; margin: 8px 0 0; }

/* --- cluster cards -------------------------------------------------------
   The times arrive from home.js; until they do the row holds its height so
   nothing below it jumps. */
.cluster + .cluster { margin-top: var(--s6); }
.citycard[data-tz] .cc-t { opacity: 0; transition: opacity .2s; }
.citycard[data-timed] .cc-t { opacity: 1; }
.citycard .cc-t .s { color: var(--sunset); }
/* The country line must wrap rather than push out of the card — some of these
   names are eight words long. */
.citycard .cc-c { overflow-wrap: anywhere; }

@media (max-width: 720px) {
  .altsvg { height: 232px; }
  .notefig { height: 78px; }
}

/* --- the altitude diagram, and the four note figures ---------------------
   Both are inline SVG on the shared tokens, so they re-theme with the page
   and cost nothing to load. Their type is set here rather than inside the
   SVGs: an SVG that carries its own font sizes stops matching the page the
   moment the page's type changes.

   Uniform scaling (preserveAspectRatio="xMidYMid meet") means the labels
   inside scale with the drawing, so the sizes below are the sizes at full
   width and shrink proportionally on narrow screens. */
.altfig {
  margin: 0 0 var(--s6);
  border: 1px solid var(--line); border-radius: var(--r);
  background: var(--surface); box-shadow: var(--card-lift);
  padding: var(--s5) var(--s5) var(--s4);
}
.altsvg { display: block; width: 100%; height: 300px; }
.altfig figcaption {
  margin-top: var(--s4); color: var(--muted);
  font-size: 14.5px; line-height: 1.6; max-width: 78ch;
}

.alt-h, .alt-band {
  font-family: var(--mono); font-size: 10px; letter-spacing: .14em;
  text-transform: uppercase; fill: var(--text); opacity: .72;
}
.alt-band { opacity: .8; }
.alt-deg {
  font-family: var(--mono); font-size: 12px; font-weight: 500;
  letter-spacing: -.01em; fill: var(--text);
}

.notefig {
  display: block; width: 100%; height: 96px;
  margin-bottom: var(--s3);
  border-radius: var(--r-s); background: var(--sunk);
  border: 1px solid var(--line-soft);
  padding: 0;
}
.nf-l {
  font-family: var(--mono); font-size: 8.5px; letter-spacing: .16em;
  text-transform: uppercase; fill: var(--faint);
}
.nf-v { font-family: var(--mono); font-size: 11px; font-weight: 500; fill: var(--text); }
.nf-t { font-family: var(--ui); font-size: 9.5px; fill: var(--muted); }
