/* Self-hosted webfont (latin + latin-ext) for the UI.
   Generated - served same-origin from /assets/fonts/ so the strict
   CSP (default-src 'self') allows it and no third-party request is
   made. font-display:swap is preserved from Google's CSS.

   ONE family: Hanken Grotesk. The six Cormorant Garamond faces that used to
   sit above it were dropped 2026-07-28 together with the display serif itself
   (Alban: "the fatness of typography", "the same simple style" as TrainRouter
   and Castlemap - neither of those renders a serif anywhere; Castlemap still
   declares Fraunces but nothing on the page uses it). Their .woff2 files are
   still in public/assets/fonts, now unreferenced - safe to delete. */

@font-face {
  font-family: 'Hanken Grotesk';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(/assets/fonts/hanken-grotesk-400-normal-latin-ext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Hanken Grotesk';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(/assets/fonts/hanken-grotesk-400-normal-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'Hanken Grotesk';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url(/assets/fonts/hanken-grotesk-500-normal-latin-ext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Hanken Grotesk';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url(/assets/fonts/hanken-grotesk-500-normal-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'Hanken Grotesk';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url(/assets/fonts/hanken-grotesk-600-normal-latin-ext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Hanken Grotesk';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url(/assets/fonts/hanken-grotesk-600-normal-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'Hanken Grotesk';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url(/assets/fonts/hanken-grotesk-700-normal-latin-ext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Hanken Grotesk';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url(/assets/fonts/hanken-grotesk-700-normal-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* ------- Sunshine Map static pages (generated by build_pages.mjs) ------ */
/* Swiss/International-Typographic pass (2026-07): all-grotesk hierarchy —
   bold tight headlines vs quiet uppercase micro-labels, kicker rule bars,
   tick-bar h2s, facts grids, hairline rules, tabular numerals, dot-grid
   paper. The serif survives only in the brand wordmark (matches the globe
   hero). Palette stays the warm sunshine identity: gold on warm black. */
html { scroll-behavior: smooth; }
/* Palette: TrainRouter's neutral system, adopted 2026-07-28 (Alban: "I just
   want the same simple style"). Same values as src/demo.css — the globe and the
   prerendered pages are one site and must not diverge. TrainRouter's index.css
   tokens, converted from HSL:
     dark  --background 222 47% 7% · --card 222 47% 10% · --foreground 210 40% 98%
           --muted-foreground 215 20% 65% · --border 217 33% 20% · --primary 217 91% 60%
     light --background 0 0% 100% · --muted 210 40% 96% · --foreground 222 47% 11%
           --muted-foreground 215 16% 47% · --border 214 32% 91% · --primary 221 83% 53%
   --gold* became --accent* and --btn-gold* became --btn-primary*: a token named
   gold holding #3b82f6 is a trap for whoever reads this next.
   NOT touched: the five metric families (sunny/warm/cold/rainy/snowy) further
   down. Those are data — the ranking pivots, cards and the globe's dot ramps
   all key off them, so they keep their meaning-carrying hues. */
:root {
  color-scheme: dark;
  --bg: #0a101b; --card: #0d1626; --card-2: #111c30; --text: #f8fafc; --bright: #ffffff;
  --tx-rgb: 248,250,252; --bg-rgb: 10,16,27; --accent-rgb: 59,130,246;
  /* Solid cool grey, not an alpha of --text: TrainRouter's muted-foreground.
     Measures 7.5:1 on --bg, so the AA floor the old .58/.72 alphas were
     hand-tuned to reach is now met by the colour itself, in both themes. */
  --dim: #94a3b8;
  --border: #22304a; --border-hi: #35486a;
  --accent: #3b82f6; --accent-soft: #93b4fb; --accent-deep: #1e4fbe;
  /* Primary CTA buttons — TrainRouter's blue with white text, identical in both
     themes (white reads on it either way, so nothing has to flip). White on
     #2563eb measures 5.12:1, better than the 4.57:1 the old orange managed. */
  --btn-primary: #2563eb; --btn-ink: #ffffff; --btn-primary-deep: #1d4ed8;
}
body.sa-page {
  margin: 0; background: var(--bg); color: var(--text);
  font-family: 'Hanken Grotesk', -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased; line-height: 1.65;
  background-image: radial-gradient(rgba(var(--tx-rgb),.035) 1px, transparent 1.15px);
  background-size: 24px 24px;
}
.sa-page ::selection { background: rgba(var(--accent-rgb),.32); }
.sa-page a { color: var(--accent-soft); text-decoration: none; }
.sa-page a:hover { text-decoration: underline; text-underline-offset: 3px; }
.sa-nav {
  display: flex; justify-content: space-between; align-items: center; gap: 1rem;
  padding: .9rem 1.2rem; border-bottom: 1px solid var(--border); flex-wrap: wrap;
  position: sticky; top: 0; z-index: 40;
  background: rgba(var(--bg-rgb),.88); backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
}
/* Hanken Grotesk 700, not Cormorant Garamond 600 — see the .sa-panel-title
   note in src/demo.css. The wordmark is the one place the serif was doing
   brand work, so it takes the heaviest weight rather than the h1's 600. */
.sa-brand { display: inline-flex; align-items: center; gap: .45em; font-weight: 700; font-size: 1.2rem; letter-spacing: -.01em; color: var(--text) !important; white-space: nowrap; }
/* Sized in em so the mark tracks the wordmark, and gold rather than --text:
   the wordmark is ink, the mark is the one spot of brand colour in the nav —
   the same split both sibling atlases use. #c2a878 is exactly what
   public/favicon.svg paints (Alban 2026-07-28: "the same color as the favcon"),
   so the tab icon and the logo are one mark in one colour, and it does not
   flip with the theme — a brand mark that changes colour is two marks. */
.sa-brand .sa-brand-mark { width: 1.05em; height: 1.05em; flex: none; color: #c2a878; }
.sa-brand:hover { text-decoration: none !important; }
/* Tighter gap now the nav carries seven sections rather than two. */
.sa-nav nav { display: flex; gap: .9rem; font-size: .86rem; font-weight: 600; flex-wrap: wrap; }
.sa-nav nav a { color: var(--dim); }
.sa-nav nav a:hover { color: var(--accent-soft); text-decoration: none; }
.sa-nav-right { display: flex; align-items: center; gap: 1.05rem; }
/* Sun/moon theme switch (wired by /theme.js — CSP forbids inline handlers). */
.themetoggle { display: inline-flex; align-items: center; justify-content: center; width: 30px; height: 30px; border-radius: .5rem; border: 1px solid var(--border); background: transparent; color: var(--dim); cursor: pointer; padding: 0; }
.themetoggle:hover { color: var(--bright); border-color: var(--border-hi); }
.themetoggle svg { width: 15px; height: 15px; }
.themetoggle .tt-moon { display: none; }
html.light .themetoggle .tt-sun { display: none; }
html.light .themetoggle .tt-moon { display: block; }
.sa-main { max-width: 62rem; margin: 0 auto; padding: 1.6rem 1.2rem 3.2rem; }
/* Type scale ported from Castlemap 2026-07-26 (Alban: "copy their
   typography"). Both sites already run Hanken Grotesk, so only the scale
   moved. Castlemap's headline is calmer and more editorial — 2.1rem at
   line-height 1.15 with no negative tracking — where this was a compressed
   poster headline (2.45rem / 1.06 / -.028em) that fought the body copy. */
.sa-main h1 { font-weight: 700; font-size: 2.1rem; line-height: 1.15; color: var(--bright); margin: .4rem 0 .5rem; text-wrap: balance; }
.sa-main h2 { display: flex; align-items: center; gap: .6rem; font-size: 1.02rem; font-weight: 700; color: var(--bright); margin: 2rem 0 .7rem; scroll-margin-top: 4.5rem; }
.sa-main h2::before { content: ''; width: 1.15rem; height: 3px; background: var(--accent); flex: none; }
.sa-sub { color: var(--dim); font-size: 1.02rem; margin: .2rem 0 1rem; }
/* Castlemap's kicker: .7rem at .24em tracking — wider and slightly larger
   than the .68/.18em this used, which is what gives it the refined look. */
.sa-crumbs { font-size: .7rem; font-weight: 700; letter-spacing: .24em; text-transform: uppercase; color: var(--dim); margin-top: .5rem; }
.sa-crumbs::before { content: ''; display: inline-block; width: 1.5rem; height: 2px; background: var(--accent); vertical-align: middle; margin-right: .6rem; }
.sa-crumbs a { color: var(--dim); }
.sa-crumbs a:hover { color: var(--accent-soft); text-decoration: none; }
dl.sa-facts {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(9.5rem, 1fr));
  gap: 1rem 1.25rem; margin: 1.6rem 0 1.5rem; padding: 1.25rem 1.35rem;
  border: 1px solid var(--border); border-radius: .6rem; background: var(--card);
}
dl.sa-facts div { margin: 0; }
dl.sa-facts dt { font-size: .64rem; font-weight: 700; letter-spacing: .14em; text-transform: uppercase; color: var(--dim); }
dl.sa-facts dd { font-size: 1.06rem; color: var(--bright); margin: .18rem 0 0; font-variant-numeric: tabular-nums; font-weight: 700; }
.sa-callout { border-left: 3px solid var(--accent); padding: .7rem 1rem; background: var(--card); border-radius: 0; }
/* /privacy/ — the consent controls live in a .sa-callout. Their own class, not
   .sa-btn: that name already belongs to the sitewide orange CTA further down
   this stylesheet, which won on source order and turned both consent buttons
   into loud primary CTAs (2026-07-26). These are a quiet pair on purpose —
   neither "turn it off" nor "turn it on" should look like the thing to do. */
.sa-consentbtn { font: inherit; font-size: .88rem; font-weight: 700; cursor: pointer; padding: .45rem .95rem; margin: .25rem .3rem .25rem 0; border: 1px solid var(--border-hi); border-radius: .4rem; background: var(--bg); color: inherit; }
.sa-consentbtn:hover { color: var(--accent-soft); border-color: var(--accent); }
.sa-callout code { word-break: break-all; }
.sa-photo { margin: 1.4rem 0; }
.sa-photo img { width: 100%; height: auto; aspect-ratio: 16 / 10; max-height: 24rem; object-fit: cover; border-radius: .6rem; border: 1px solid var(--border); background: var(--card); box-shadow: 0 16px 40px rgba(0,0,0,.45); }
.sa-photo figcaption { text-align: right; font-size: .68rem; color: var(--dim); margin-top: .5rem; }
.sa-chart { width: 100%; max-width: 580px; display: block; margin: .6rem auto 1.2rem; }
.sa-chart-base { stroke: var(--border-hi); stroke-width: 1; }
.sa-chart-m { fill: var(--dim); font-size: 9px; font-family: inherit; }
.sa-chart-val { fill: var(--text); font-size: 10px; font-weight: 600; font-family: inherit; }
.sa-dv-chart { width: 100%; max-width: 600px; display: block; margin: .8rem auto 1.4rem; }
.sa-dv-grid { stroke: var(--border-hi); stroke-width: 1; stroke-dasharray: 2 3; opacity: .55; }
.sa-dv-axis { fill: var(--dim); font-size: 9px; font-family: inherit; }
.sa-dv-lbl { fill: var(--text); font-size: 11px; font-family: inherit; }
.sa-dv-conn { stroke: var(--border-hi); stroke-width: 2; }
.sa-dv-lo { fill: #7d8ba1; }
.sa-dv-hi { fill: var(--accent); }
.sa-dv-val { fill: var(--dim); font-size: 9.5px; font-weight: 600; font-family: inherit; }
.sa-dv-valhi { fill: var(--text); }
.sa-more { margin: .3rem 0 1.1rem; }
.sa-more summary { cursor: pointer; color: var(--accent); font-size: .92rem; }
.sa-table { border-collapse: collapse; width: 100%; font-size: .92rem; margin: .6rem 0 1rem; }
/* thead sticks just below the sticky nav (~3.55rem tall on one line). Pages
   without the shared nav (homepage section) have no .sa-page class, so the
   offset only applies where the nav exists. */
body.sa-page .sa-table thead th { position: sticky; top: 3.55rem; background: var(--bg); z-index: 1; box-shadow: 0 1px 0 var(--border-hi); }
.sa-table th { text-align: left; font-weight: 700; color: var(--dim); font-size: .68rem; letter-spacing: .14em; text-transform: uppercase; }
.sa-table tbody tr:nth-child(even) { background: rgba(var(--tx-rgb),.025); }
.sa-table tbody tr:hover { background: rgba(var(--accent-rgb),.08); }
.sa-table th, .sa-table td { padding: .48rem .6rem .48rem 0; border-bottom: 1px solid var(--border); }
td.sa-num { text-align: right; padding-right: 1.1rem; }
.sa-num { font-variant-numeric: tabular-nums; white-space: nowrap; }
.sa-best { background: rgba(var(--accent-rgb),.09); box-shadow: inset 2px 0 0 var(--accent); }
.sa-dim { color: var(--dim); font-size: .85em; }
.sa-nearby, .sa-hubs, .sa-toplist { list-style: none; padding: 0; margin: .4rem 0 1rem; }
.sa-nearby li, .sa-hubs li, .sa-toplist li { padding: .52rem 0; border-top: 1px solid var(--border); }
.sa-nearby li:first-child, .sa-hubs li:first-child, .sa-toplist li:first-child { border-top: 0; }
.sa-nearby a, .sa-hubs a, .sa-toplist a { color: var(--text); font-weight: 600; }
.sa-nearby a:hover, .sa-hubs a:hover, .sa-toplist a:hover { color: var(--accent-soft); }
.sa-cmp-photos { display: flex; gap: .8rem; margin: 1rem 0 1.4rem; }
.sa-cmp-photos figure { flex: 1; margin: 0; min-width: 0; }
.sa-cmp-photos img { width: 100%; aspect-ratio: 3 / 2; object-fit: cover; border-radius: 6px; display: block; }
.sa-cmp-photos figcaption { font-size: .8rem; color: var(--dim); margin-top: .3rem; }
.sa-cols { list-style: none; padding: 0; margin: .3rem 0 1.2rem; column-width: 15rem; column-gap: 2rem; }
.sa-cols li { padding: .18rem 0; break-inside: avoid; }
.sa-pivot { margin: .3rem 0 1.15rem; display: grid; gap: .45rem; }
.sa-pivot-row { display: flex; flex-wrap: wrap; gap: .35rem; align-items: center; }
.sa-pivot-row a, .sa-pivot-row .on { display: inline-block; padding: .34rem .68rem; border: 1px solid var(--border); border-radius: 999px; font-size: .85rem; font-weight: 600; color: var(--dim); line-height: 1; }
.sa-pivot-row a:hover { color: var(--accent-soft); border-color: var(--border-hi); text-decoration: none; }
.sa-pivot-row .on { color: #1c1812; background: var(--accent); border-color: var(--accent); }
/* Family pills painted by feeling (Alban 2026-07-23): sunny=yellow, hot=orange,
   rainy=blue, snowy=light blue. One vivid --feel per family; color-mix keeps the
   resting text legible on either theme (nudged toward --text) and derives the
   border/wash, so a single colour set works in both dark and light mode. Only
   the four family pills carry .sa-fam — the month/scope pills stay neutral. */
.sa-fam-sunny { --feel: #f5b70c; }  /* vivid golden yellow */
.sa-fam-warm  { --feel: #f5682a; }  /* vivid orange — "Hot" pill (family key is 'warm') */
.sa-fam-cold  { --feel: #22c1d6; }  /* bright teal-cyan */
.sa-fam-rainy { --feel: #2b7de6; }  /* deep true blue */
.sa-fam-snowy { --feel: #9dd6f5; }  /* pale ice blue */
.sa-pivot-row a.sa-fam {
  color: color-mix(in srgb, var(--feel) 72%, var(--text));
  border-color: color-mix(in srgb, var(--feel) 45%, transparent);
  background: color-mix(in srgb, var(--feel) 10%, transparent);
}
.sa-pivot-row a.sa-fam:hover {
  color: color-mix(in srgb, var(--feel) 80%, var(--text));
  border-color: var(--feel);
  background: color-mix(in srgb, var(--feel) 18%, transparent);
}
.sa-pivot-row .on.sa-fam { color: #241c0a; background: var(--feel); border-color: var(--feel); }
/* Browse-page CTA family buttons (Sunny/Hot/Cold/Rainy/Snowy): tinted OUTLINE
   style so the label is the feeling COLOUR, never black. On a bright solid fill
   only black ink is legible, which looked wrong in dark mode; instead the bright
   feeling ink reads on the dark page (light mode darkens it, below, for cream).
   A feeling-tinted pressable shadow keeps the button feel + matches the pills. */
.sa-page a.sa-btn-ghost.sa-fam {
  background: color-mix(in srgb, var(--feel) 13%, transparent);
  color: color-mix(in srgb, var(--feel) 82%, var(--text));
  border-color: color-mix(in srgb, var(--feel) 55%, transparent);
  box-shadow: 0 3px 0 color-mix(in srgb, var(--feel), #000 55%);
}
.sa-page a.sa-btn-ghost.sa-fam:hover {
  background: color-mix(in srgb, var(--feel) 22%, transparent);
  color: color-mix(in srgb, var(--feel) 92%, var(--text));
  border-color: var(--feel);
  transform: translateY(2px);
  box-shadow: 0 1px 0 color-mix(in srgb, var(--feel), #000 55%);
}
html.light .sa-page a.sa-btn-ghost.sa-fam { color: color-mix(in srgb, var(--feel) 42%, var(--text)); }
.sa-pivot-scope { color: var(--dim); font-size: .78rem; letter-spacing: .08em; text-transform: uppercase; margin-left: .3rem; }
#embed { scroll-margin-top: 4.5rem; }
/* Destination cards — refined 2026-07-26. Four fixes to what was there:
   (1) cells STRETCH, so a photo-less destination no longer collapses to half
   height and leave the grid ragged (Calama at #1 was 196px against 363px
   neighbours); (2) fact strips are flex+gap instead of " · " glue, so a wrap
   can't strand a separator; (3) the figures line carries --text + tabular
   numerals so numbers read as data, while the place line stays quiet — two
   identical dim lines were hard to scan; (4) a tactile hover matching the rest
   of the site: card lifts, photo eases in, border goes gold. */
/* align-items:start (2026-07-28) so a card is only as tall as what it holds.
   Grid items stretch by default, which made the ~2% of destinations with no
   photo render as a tall empty box next to their photographed neighbours. */
.sa-cards { list-style: none; padding: 0; margin: .5rem 0 1.6rem; display: grid; gap: .85rem; align-items: start; grid-template-columns: repeat(auto-fill, minmax(15.5rem, 1fr)); }
.sa-cards li { display: flex; flex-direction: column; border: 1px solid var(--border); border-radius: .6rem; background: var(--card); overflow: hidden; position: relative; transition: border-color .15s ease, transform .15s ease, box-shadow .15s ease; }
.sa-cards li:hover { border-color: var(--accent); transform: translateY(-2px); box-shadow: 0 10px 22px rgba(0,0,0,.3); }
.sa-cards .rk { position: absolute; top: .5rem; left: .5rem; z-index: 2; background: rgba(var(--bg-rgb),.86); color: var(--accent); font-weight: 700; font-size: .76rem; line-height: 1; padding: .32rem .48rem; min-width: 1.5rem; text-align: center; border-radius: .4rem; border: 1px solid rgba(var(--tx-rgb),.22); font-variant-numeric: tabular-nums; }
.sa-cards li.nophoto .rk { position: static; align-self: flex-start; margin: .7rem 0 -.15rem .8rem; }
.sa-cards .ph { position: relative; display: block; line-height: 0; overflow: hidden; background: rgba(0,0,0,.25); }
.sa-cards .ph img { width: 100%; aspect-ratio: 16/10; object-fit: cover; display: block; transition: transform .35s ease; }
.sa-cards li:hover .ph img { transform: scale(1.035); }
/* Scrim so the rank chip stays legible over a pale photo. */
.sa-cards .ph::after { content: ''; position: absolute; inset: 0 0 auto; height: 3rem; background: linear-gradient(rgba(0,0,0,.4), transparent); pointer-events: none; }
.sa-cards .tx { flex: 1; display: flex; flex-direction: column; gap: .24rem; padding: .7rem .8rem .8rem; }
.sa-cards .t { align-self: flex-start; color: var(--bright); font-weight: 700; font-size: 1rem; line-height: 1.3; letter-spacing: -.005em; }
.sa-cards .t:hover { color: var(--accent-soft); text-decoration: none; }
.sa-cards .t:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: .2rem; }
.sa-cards .meta { display: flex; flex-wrap: wrap; gap: .05rem .78rem; margin: 0; color: var(--dim); font-size: .82rem; }
/* Photo-less destinations stretch to their row like every other card, so
   centre their text rather than leaving it stranded above dead space. */
.sa-cards li.nophoto .tx { justify-content: center; padding-bottom: 1.4rem; }
.sa-cards .meta.nums { color: var(--text); font-variant-numeric: tabular-nums; }
.sa-cards .meta.nums strong { font-weight: 700; color: var(--bright); }
.sa-cards .meta a { color: inherit; text-decoration: underline; text-underline-offset: 2px; text-decoration-color: rgba(var(--tx-rgb),.28); }
.sa-cards .meta a:hover { color: var(--accent-soft); }
.sa-globe-cta { margin: 1.7rem 0; }
.sa-globe-cta a {
  display: inline-block; padding: .66rem 1.15rem; border-radius: .5rem;
  background: var(--btn-primary); color: var(--btn-ink); font-weight: 700;
  box-shadow: 0 3px 0 var(--btn-primary-deep); transition: transform .1s, box-shadow .1s;
}
.sa-globe-cta a:hover { text-decoration: none; transform: translateY(2px); box-shadow: 0 1px 0 var(--btn-primary-deep); }
.sa-prevnext { display: flex; justify-content: space-between; margin: 2.5rem 0 0; gap: 1rem; padding-top: 1.4rem; border-top: 1px solid var(--border); font-size: .9rem; }
.sa-prevnext a { padding: .5rem .95rem; border: 1px solid var(--border-hi); border-radius: .5rem; color: var(--text); font-weight: 600; background: var(--card); }
.sa-prevnext a:hover { border-color: var(--accent); color: var(--accent-soft); text-decoration: none; background: rgba(var(--accent-rgb),.06); }
.sa-home { max-width: 62rem; margin: 0 auto; padding: 2.4rem 1.2rem 1rem; }
/* Homepage headings track the same Castlemap scale as .sa-main above. */
.sa-home h1 { font-weight: 700; font-size: 2.1rem; line-height: 1.15; color: var(--bright); margin: 0 0 .5rem; text-wrap: balance; }
.sa-home h2 { display: flex; align-items: center; gap: .6rem; font-size: 1.02rem; font-weight: 700; color: var(--bright); margin: 2rem 0 .7rem; }
.sa-home h2::before { content: ''; width: 1.15rem; height: 3px; background: var(--accent); flex: none; }
.sa-mgrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(9.5rem, 1fr)); gap: .6rem; }
.sa-mcard { border: 1px solid var(--border); border-radius: .5rem; background: var(--card); padding: .6rem .75rem; display: flex; flex-direction: column; gap: .15rem; }
.sa-mcard:hover { border-color: var(--accent); text-decoration: none; background: rgba(var(--accent-rgb),.05); }
.sa-mcard strong { color: var(--bright); font-weight: 700; font-variant-numeric: tabular-nums; }
.sa-mcard span { color: var(--dim); font-size: .8rem; }
.sa-expand { margin: -.4rem 0 1.2rem; }
.sa-expand summary { cursor: pointer; font-weight: 600; color: var(--accent-soft); padding: .55rem .8rem; border: 1px solid var(--border-hi); border-radius: .5rem; background: var(--card); }
.sa-expand summary:hover { border-color: var(--accent); background: rgba(var(--accent-rgb),.06); }
.sa-expand[open] summary { color: var(--dim); }
.sa-expand .sa-table { margin-top: .2rem; }
.sa-footer { border-top: 1px solid var(--border); margin-top: 2rem; padding: 1.2rem; font-size: .8rem; color: var(--dim); max-width: 62rem; margin-inline: auto; }
.sa-footer a { color: var(--dim); font-weight: 600; }
.sa-footer a:hover { color: var(--accent-soft); }
.sa-foot-months a { margin-right: .55rem; white-space: nowrap; }
.sa-foot-months { margin-bottom: .65rem; line-height: 1.9; }
.sa-cont { border: 1px solid var(--border); border-radius: .55rem; margin: .5rem 0; background: var(--card); scroll-margin-top: 4.5rem; }
.sa-cont > summary { cursor: pointer; padding: .68rem .95rem; font-weight: 600; color: var(--text); list-style: none; display: flex; align-items: center; gap: .45rem; }
.sa-cont > summary::-webkit-details-marker { display: none; }
/* One chevron for every accordion on the site (2026-07-26): drawn in CSS,
   pinned to the right edge so they line up in a column, and rotated on open
   instead of swapping ▾/▴ glyphs. currentColor picks up the hover gold. */
.sa-cont > summary::after { content: ''; flex: none; align-self: center; margin-left: auto; width: .4rem; height: .4rem; border: 2px solid currentColor; border-left: 0; border-top: 0; opacity: .5; transform: rotate(-45deg); transition: transform .18s ease, opacity .12s; }
.sa-cont[open] > summary::after { transform: rotate(45deg); margin-top: -.2rem; }
.sa-cont > summary:hover { color: var(--accent-soft); }
.sa-cont > summary:hover::after { opacity: 1; }
/* /browse/: TrainRouter-pattern hero button + category accordions (2026-07-23). */
/* .sa-page a's gold-soft link color outranks a bare class — pin the button
   colors at .sa-page specificity so the gold CTA keeps its dark label. */
/* Buttons follow TrainRouter's elegant "pressable" style: a solid fill with a
   3px solid drop-shadow in a darker shade; on hover the button sinks 2px and
   the shadow shrinks to 1px, so it reads as a physical press. Text is always
   dark ink — never white — since the fills are bright. */
.sa-btn, .sa-page a.sa-btn { display: inline-flex; align-items: center; background: var(--btn-primary); color: var(--btn-ink); font-weight: 700; font-size: .95rem; line-height: 1.2; padding: .58rem 1.05rem; border-radius: .55rem; border: 1px solid transparent; box-shadow: 0 3px 0 var(--btn-primary-deep); transition: transform .1s, box-shadow .1s, background-color .12s, color .12s; }
.sa-page a.sa-btn:hover { background: var(--btn-primary); color: var(--btn-ink); text-decoration: none; transform: translateY(2px); box-shadow: 0 1px 0 var(--btn-primary-deep); }
.sa-btn-ghost, .sa-page a.sa-btn-ghost { background: none; border: 1px solid var(--border-hi); color: var(--text); box-shadow: 0 3px 0 rgba(0,0,0,.16); }
.sa-page a.sa-btn-ghost:hover { text-decoration: none; transform: translateY(2px); box-shadow: 0 1px 0 rgba(0,0,0,.16); }
.sa-ctarow { display: flex; flex-wrap: wrap; gap: .5rem; margin: 1.1rem 0 .5rem; }
.sa-famrow { margin: .9rem 0; }
.sa-famrow .lb { display: block; font-weight: 700; font-size: .9rem; color: var(--bright); margin-bottom: .3rem; }
.sa-famrow .lb:hover { color: var(--accent-soft); }
.sa-browse-line { color: var(--dim); font-size: .92rem; margin: .4rem 0 1.8rem; }
.sa-cat > summary { display: flex; align-items: baseline; gap: .45rem; flex-wrap: wrap; }
.sa-cat > summary .n { color: var(--accent); font-weight: 600; font-variant-numeric: tabular-nums; }
.sa-cat > summary .tease { color: var(--dim); font-weight: 400; font-size: .88em; }
.sa-cat-body { padding: .15rem .95rem .4rem; border-top: 1px solid var(--border); }
.sa-cat-body .sa-cards { margin-top: .7rem; }
.sa-cat-body .sa-globe-cta { margin: 1rem 0 .6rem; }
/* Photo rows — the ranking lists (every family, tails, accordions). One
   compact horizontal card per destination: rank, lazy thumb, name, facts. */
.sa-rows { list-style: none; margin: .6rem 0 1.4rem; padding: 0; display: flex; flex-direction: column; gap: .5rem; }
.sa-rows li { display: flex; align-items: center; gap: .8rem; border: 1px solid var(--border); border-radius: .6rem; background: var(--card); overflow: hidden; transition: border-color .15s ease; }
.sa-rows li:hover { border-color: var(--border-hi); }
.sa-rows .rk { flex: 0 0 auto; width: 2.9rem; text-align: center; color: var(--accent); font-weight: 700; font-size: .8rem; font-variant-numeric: tabular-nums; }
.sa-rows .ph { flex: 0 0 auto; width: 7.2rem; height: 4.8rem; margin-left: -.8rem; }
.sa-rows .ph img { width: 100%; height: 100%; object-fit: cover; display: block; }
.sa-rows .ph.nop { background: rgba(var(--tx-rgb),.04); }
.sa-rows .tx { min-width: 0; padding: .5rem .9rem .5rem 0; }
.sa-rows .t { margin: 0; font-size: .95rem; }
.sa-rows .t a { font-weight: 700; color: var(--bright); }
.sa-rows .t .c { font-size: .8rem; color: var(--dim); font-weight: 400; margin-left: .35rem; }
.sa-rows .f { margin: .12rem 0 0; font-size: .8rem; color: var(--dim); }
.sa-rows .f strong { color: var(--text); }
@media (max-width: 600px) {
  .sa-rows .rk { width: 2.1rem; font-size: .72rem; }
  .sa-rows .ph { width: 5.4rem; height: 4.2rem; margin-left: -.55rem; }
  .sa-rows .tx { padding-right: .6rem; }
  .sa-rows .t { font-size: .88rem; }
  .sa-rows .f { font-size: .74rem; }
}

/* Section rows, on TrainRouter's /routes/ pattern (Alban 2026-07-26 — "very
   messy over there, TrainRouter is a lot tidier"). The h2 IS the box, so each
   section is one uniform full-width bar: tick, title, gold count, chevron
   pinned to the right edge — all seven line up in a column instead of the old
   ragged run of bare text headings. Kept from the button pass: the site's
   pressable feel (3px solid shadow, sinks 2px on hover, bottoms out on click).
   Closed rows stack tightly as a menu; an open row gets air before the next. */
.sa-group { margin: .8rem 0 0; }
.sa-group[open] + .sa-group { margin-top: 1.9rem; }
.sa-group > summary { cursor: pointer; list-style: none; user-select: none; -webkit-tap-highlight-color: transparent; }
.sa-group > summary::-webkit-details-marker { display: none; }
.sa-group > summary h2 {
  margin: 0; padding: .62rem .95rem; gap: .5rem;
  border: 1px solid var(--border-hi); border-radius: .55rem; background: var(--card);
  box-shadow: 0 3px 0 rgba(0,0,0,.16);
  transition: transform .1s, box-shadow .1s, background-color .12s, border-color .12s, color .12s;
}
.sa-group > summary h2 .n { color: var(--accent); font-weight: 600; font-variant-numeric: tabular-nums; }
.sa-group > summary h2::after {
  content: ''; flex: none; margin-left: auto; width: .44rem; height: .44rem;
  border: 2px solid var(--accent); border-left: 0; border-top: 0; opacity: .75;
  transform: rotate(-45deg); transition: transform .18s ease, opacity .12s;
}
.sa-group[open] > summary h2 { border-color: rgba(var(--accent-rgb),.5); background: rgba(var(--accent-rgb),.09); }
.sa-group[open] > summary h2::after { transform: rotate(45deg); margin-top: -.22rem; }
.sa-group > summary:hover h2 { border-color: var(--accent); background: rgba(var(--accent-rgb),.13); color: var(--accent-soft); transform: translateY(2px); box-shadow: 0 1px 0 rgba(0,0,0,.16); }
.sa-group > summary:hover h2::after { opacity: 1; }
.sa-group > summary:active h2 { transform: translateY(3px); box-shadow: 0 0 0 rgba(0,0,0,.16); }
.sa-group > summary:focus-visible h2 { outline: 2px solid var(--accent); outline-offset: 3px; }
/* An open section's contents hang off a hairline, so the nested category
   accordions read as children of the row above rather than its siblings. */
.sa-group-body { padding: .75rem 0 .3rem .9rem; margin-left: .45rem; border-left: 1px solid var(--border); }
.sa-cont > :not(summary) { margin-left: .95rem; margin-right: .95rem; }
.sa-cont > p:last-child { padding-bottom: .6rem; }
.sa-foot-details { margin-bottom: .65rem; }
.sa-foot-details summary { cursor: pointer; font-weight: 600; color: var(--text); }
.sa-foot-details summary:hover { color: var(--accent-soft); }
.sa-foot-details[open] summary { margin-bottom: .5rem; }
/* "Embed this" box (the widget itself is self-contained in /embed/). */
.sa-embed { display: flex; gap: .5rem; align-items: stretch; margin: .5rem 0 1rem; }
.sa-embed-code { flex: 1; min-width: 0; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: .78rem; line-height: 1.45; color: var(--text); background: rgba(var(--tx-rgb),.04); border: 1px solid var(--border); border-radius: 4px; padding: .5rem .6rem; resize: vertical; white-space: pre; }
.sa-embed-copy { flex: none; align-self: flex-start; cursor: pointer; font-family: inherit; font-size: .85rem; color: var(--btn-ink); background: var(--btn-primary); border: 0; border-radius: 4px; padding: .5rem .95rem; }
.sa-embed-copy:hover { background: var(--btn-primary-deep); }
.sa-embed-preview { display: block; width: 100%; max-width: 420px; height: 460px; border: 1px solid var(--border); border-radius: 8px; margin: .2rem 0 1.2rem; }
.sa-embed-preview.sa-badge-preview { max-width: 340px; height: 208px; }
/* Press kit brand-asset gallery */
.sa-shots { display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: .8rem; margin: .6rem 0 1rem; }
.sa-shots figure { margin: 0; }
.sa-shots img { display: block; width: 100%; height: auto; border: 1px solid var(--border); border-radius: 6px; background: rgba(var(--tx-rgb),.03); }
.sa-shots figcaption { color: var(--dim); font-size: .8rem; margin-top: .35rem; }
.sa-shots figcaption a { white-space: nowrap; }
/* /lifetime-sunshine/ calculator */
.ls-row { display: flex; gap: .6rem; align-items: flex-end; margin: 0 0 .7rem; flex-wrap: wrap; }
.ls-cell { display: flex; flex-direction: column; gap: .25rem; }
.ls-cell label { font-size: .72rem; letter-spacing: .05em; text-transform: uppercase; color: var(--dim); }
.ls-place { position: relative; flex: 1 1 16rem; min-width: 14rem; }
.ls-yr { width: 6.2rem; }
.ls-app input { background: rgba(var(--tx-rgb),.05); border: 1px solid var(--border-hi); border-radius: 4px; color: var(--text); font: inherit; padding: .5rem .65rem; width: 100%; box-sizing: border-box; }
.ls-app input:focus { outline: none; border-color: var(--accent); }
.ls-drop { position: absolute; top: 100%; left: 0; right: 0; z-index: 5; background: var(--card-2); border: 1px solid var(--border-hi); border-radius: 0 0 6px 6px; max-height: 19rem; overflow-y: auto; box-shadow: 0 12px 28px rgba(0,0,0,.5); }
.ls-opt { display: flex; justify-content: space-between; align-items: baseline; gap: .8rem; width: 100%; text-align: left; background: none; border: 0; border-bottom: 1px solid var(--border); color: var(--text); font: inherit; padding: .5rem .65rem; cursor: pointer; }
.ls-opt span { color: var(--dim); font-size: .82rem; white-space: nowrap; }
.ls-opt:hover, .ls-opt.ls-sel { background: rgba(var(--accent-rgb),.14); }
.ls-x { background: none; border: 1px solid var(--border); border-radius: 4px; color: var(--dim); cursor: pointer; font-size: 1rem; line-height: 1; padding: .55rem .6rem; }
.ls-x:hover { color: var(--text); border-color: var(--border-hi); }
.ls-btn { display: inline-block; cursor: pointer; font-family: inherit; font-size: .92rem; font-weight: 700; color: var(--btn-ink) !important; background: var(--btn-primary); border: 0; border-radius: .5rem; padding: .55rem 1.05rem; box-shadow: 0 3px 0 var(--btn-primary-deep); transition: transform .1s, box-shadow .1s; }
.ls-btn:hover { text-decoration: none !important; transform: translateY(2px); box-shadow: 0 1px 0 var(--btn-primary-deep); }
.ls-btn-ghost { background: none; color: var(--accent-soft) !important; border: 1px solid var(--border-hi); box-shadow: none; }
.ls-btn-ghost:hover { background: rgba(var(--tx-rgb),.04); transform: none; box-shadow: none; }
.ls-hero { margin: 1.6rem 0 .4rem; }
.ls-total { font-weight: 700; font-size: 4.1rem; letter-spacing: -.03em; line-height: 1; color: var(--accent-soft); font-variant-numeric: tabular-nums; }
.ls-unit { color: var(--dim); margin-top: .3rem; }
.ls-line { max-width: 44rem; }
.ls-break { list-style: none; padding: 0; margin: .6rem 0 1rem; max-width: 44rem; }
.ls-break li { padding: .28rem 0; border-bottom: 1px solid var(--border); }
.ls-note { color: var(--dim); font-size: .85rem; }
.ls-actions { display: flex; gap: .6rem; flex-wrap: wrap; margin: 1rem 0; }
#ls-cardbox canvas { width: 100%; max-width: 600px; height: auto; border: 1px solid var(--border); border-radius: 6px; display: block; }
/* Seven nav sections need ~730px to stay on one line, and a wrapped nav doubles
   the STICKY header (measured: 65px → 111px at two lines, 141px at three). The
   fix is two-stage, because the old single 560px breakpoint left the whole
   561–729px band — small tablets in portrait, phones in landscape, half-screen
   desktop windows — with a permanently two-line sticky header (2026-07-26).
   Stage one: smaller type buys back ~90px and holds one line to ~640px. */
@media (max-width: 729px) {
  .sa-nav nav { font-size: .78rem; gap: .6rem; }
  .sa-brand { font-size: 1.15rem; }
}
/* Stage two: below that it wraps whatever we do, so the header scrolls away
   instead of sticking. Nothing is hidden — every nav target is in the footer. */
@media (max-width: 640px) {
  .sa-nav { position: static; padding: .7rem 1rem; }
  /* thead's sticky offset assumed a sticky nav above it; with the header
     static there is nothing to clear. */
  body.sa-page .sa-table thead th { top: 0; }
}
@media (max-width: 560px) {
  .sa-main { padding: 1.2rem 1rem 2.5rem; }
  /* Pulled down with the desktop sizes so the jump stays proportional. */
  .sa-main h1 { font-size: 1.72rem; }
  .sa-home h1 { font-size: 1.62rem; }
  dl.sa-facts { grid-template-columns: repeat(2, 1fr); gap: .8rem; padding: 1rem; }
  .sa-prevnext { flex-direction: column; gap: .5rem; }
  /* Ranking tables are ~7 columns: on the narrowest phones they'd clip a few
     px at the right edge — let the table scroll inside itself instead. */
  .sa-table { font-size: .84rem; display: block; overflow-x: auto; -webkit-overflow-scrolling: touch; }
  .sa-table th, .sa-table td { padding-right: .4rem; }
}
/* ── Light mode (html.light via /theme.js, the TrainRouter/Castlemap pattern):
   the daylight twin — warm paper, ink text, golds deepened for contrast.
   Dark stays the identity and the default; light is a per-visitor opt-in.
   Everything var-driven flips from this one block; the few rules below it
   are the spots where a variable swap alone isn't enough. */
/* Light mirrors dark: the page is the lightest surface and cards sit a hair
   below it, the same lift the dark theme gets by putting --card ABOVE --bg. */
html.light {
  color-scheme: light;
  --bg: #ffffff; --card: #f8fafc; --card-2: #f1f5f9; --text: #0f1a29; --bright: #0a101b;
  --tx-rgb: 15,26,41; --bg-rgb: 255,255,255; --accent-rgb: 37,99,235;
  /* --accent-soft is the body-link colour: #1d4ed8 measures 6.66:1 on white. */
  --accent: #2563eb; --accent-soft: #1d4ed8; --accent-deep: #1e40af;
  /* --dim used to need a per-theme alpha (.58 dark, .72 light) to clear the
     4.5:1 AA floor on the cream page — it is the colour of nearly every
     secondary string on the site, 4,300+ elements on one ranking page. Both
     themes now take a solid cool grey that clears AA on its own ground:
     #657589 measures 4.69:1 on white. */
  --dim: #657589;
}
/* The rank badge sets --accent on a chip tinted to the page colour: 2.88:1 in
   light, the worst contrast on a ranking page and on the one element whose
   entire job is to be read at a glance. --accent-deep measures 6.38:1. */
html.light .sa-cards .rk { color: var(--accent-deep); border-color: rgba(var(--tx-rgb),.3); }
/* Feeling pivot pills read too pale on the cream page — darken their tinted
   text in light mode only (dark mode keeps the vivid colour). */
html.light .sa-pivot-row a.sa-fam { color: color-mix(in srgb, var(--feel) 40%, var(--text)); }
html.light .sa-pivot-row a.sa-fam:hover { color: color-mix(in srgb, var(--feel) 55%, var(--text)); }
html.light .sa-photo img { box-shadow: 0 12px 30px rgba(0,0,0,.16); }
html.light .ls-drop { box-shadow: 0 12px 28px rgba(0,0,0,.16); }
