/* hermantrip — design tokens + base + components.
 * Tokens documented at docs/design.md. */

:root {
  /* Color — paper base + earth-tone palette */
  --bg: #f6f1ea;
  --surface: #ffffff;
  --text: #1a1815;
  --text-muted: #5a534c;
  --accent: #b56439;       /* terra (primary) — desert, outback */
  --accent-dim: #8c4c2a;
  --earth-sage: #6b8459;   /* jungle, forest, hills */
  --earth-slate: #5d7593;  /* mountains, ocean, sky */
  --earth-ochre: #c8943d;  /* sun, warm, tropical */
  --earth-pale: #cfe0e8;   /* atlas-ocean pale */
  --divider: #e3dccf;
  --error: #993333;

  /* Type */
  --font-family: 'Rubik', system-ui, -apple-system, sans-serif;
  --type-display: 2.5rem;
  --type-h1: 1.75rem;
  --type-h2: 1.25rem;
  --type-body: 1rem;
  --type-small: 0.875rem;

  /* Spacing */
  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 1rem;
  --space-4: 1.5rem;
  --space-5: 2rem;
  --space-6: 3rem;
  --space-7: 4rem;
}

:root { --stage: #efe7da; } /* slideshow stage — light theme */

[data-theme="dark"] {
  --bg: #1b1815;
  --surface: #262220;
  --text: #f3ece1;
  --text-muted: #b3a899;
  --accent: #cf7a4e;
  --accent-dim: #b9633a;
  --divider: #3a3531;
  --error: #c97b6b;
  --stage: #211e1b;
}

body { transition: background-color .2s ease, color .2s ease; }

/* Reset */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-family);
  font-size: var(--type-body);
  font-weight: 300;
  line-height: 1.6;
  font-variant-numeric: tabular-nums;
  min-height: 100vh;
}
img { display: block; max-width: 100%; height: auto; }

/* Layout */
main#app {
  max-width: 64rem;
  margin: 0 auto;
  padding: var(--space-5) var(--space-3);
}
@media (min-width: 769px) {
  main#app { padding: var(--space-6) var(--space-5); }
}

/* Typography */
h1, h2, h3 { font-weight: 500; line-height: 1.2; margin: 0 0 var(--space-3); }
.display {
  font-size: var(--type-display);
  font-weight: 700;
  line-height: 1.1;
  letter-spacing: -0.01em;
  margin: 0 0 var(--space-3);
}
.tagline {
  font-size: var(--type-body);
  color: var(--text-muted);
  margin: 0 0 var(--space-6);
}
.muted { color: var(--text-muted); }
.small { font-size: var(--type-small); }

/* Loading state */
.loading {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  color: var(--text-muted);
  padding: var(--space-5) 0;
}
.loading-spinner {
  width: 1rem;
  height: 1rem;
  border: 2px solid var(--divider);
  border-inline-end-color: var(--accent);
  border-radius: 50%;
  animation: spin 0.8s linear infinite;
}
@keyframes spin {
  to { transform: rotate(360deg); }
}
.loading-text { font-size: var(--type-small); }

/* Error state */
.error {
  background: var(--surface);
  border: 1px solid var(--divider);
  border-inline-start: 3px solid var(--error);
  padding: var(--space-3);
  color: var(--text);
  margin: var(--space-3) 0;
}

/* Home header */
.home-header {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  margin-bottom: var(--space-5);
}
.home-header-text { flex: 1 1 auto; }
.home-globe {
  flex: 0 0 auto;
  width: 4.5rem;
  height: 4.5rem;
}
@media (min-width: 769px) {
  .home-globe { width: 6rem; height: 6rem; }
}

/* Country grid (home) */
.country-grid {
  list-style: none;
  padding: 0;
  margin: 0;
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-3);
}
@media (min-width: 540px) {
  .country-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (min-width: 900px) {
  .country-grid { grid-template-columns: repeat(3, 1fr); }
}

.country-card {
  background: var(--surface);
  border: 1px solid var(--divider);
}
.country-card a {
  display: block;
  color: inherit;
  text-decoration: none;
}
.country-card a:hover,
.country-card a:focus-visible {
  outline: 1px solid var(--accent);
  outline-offset: -1px;
}
.country-thumb {
  display: block;
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  background: var(--earth-pale);
}
.country-thumb-empty {
  background: var(--divider);
}
.country-thumb-broken {
  /* Set by inline onerror when BOTH the lh3 URL and the thumbnailLink
   * fallback fail (typically Chrome's ORB blocking specific Drive files).
   * Render as a pale atlas-ocean block with no broken-image glyph so the
   * card looks intentional rather than failed. R4 fallback path. */
  background:
    repeating-linear-gradient(
      45deg,
      var(--earth-pale) 0 6px,
      var(--bg) 6px 12px
    );
}
.country-thumb-broken::after {
  content: '';
  display: block;
  width: 100%;
  height: 100%;
}
.country-card-meta {
  display: flex;
  align-items: baseline;
  gap: var(--space-2);
  padding: var(--space-3) var(--space-3);
}
.country-card-meta .country-dot {
  flex: 0 0 auto;
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 50%;
  background: var(--accent);
  align-self: center;
}
.country-card-meta .country-name {
  font-weight: 500;
  flex: 1 1 auto;
}
.country-card-meta .country-count {
  color: var(--text-muted);
  font-size: var(--type-small);
  flex: 0 0 auto;
}

.home-coming-soon {
  margin-top: var(--space-6);
  padding: var(--space-3);
  font-size: var(--type-small);
  color: var(--text-muted);
  border-top: 1px solid var(--divider);
}

/* Action links (random slideshow entry points, M17) */
.home-actions {
  margin-bottom: var(--space-4);
}
.action-link {
  display: inline-block;
  color: var(--accent);
  text-decoration: none;
  font-weight: 500;
  border: 1px solid var(--divider);
  border-radius: 4px;
  padding: var(--space-2) var(--space-3);
}
.action-link:hover,
.action-link:focus-visible {
  color: var(--accent-dim);
  border-color: var(--accent);
}

/* Not found */
.notfound {
  text-align: center;
  padding: var(--space-7) 0;
}
.notfound a {
  color: var(--accent);
  text-decoration: none;
  border-bottom: 1px solid currentColor;
}
.notfound a:hover { color: var(--accent-dim); }

/* ---- M4: album list + album grid ---- */

/* Shared view header with a back link */
.view-header {
  margin-bottom: var(--space-5);
}
.back-link {
  display: inline-block;
  color: var(--text-muted);
  text-decoration: none;
  font-size: var(--type-small);
  margin-bottom: var(--space-2);
}
.back-link:hover,
.back-link:focus-visible { color: var(--accent); }
.h1 {
  font-size: var(--type-h1);
  font-weight: 500;
  margin: 0;
}

/* Shared broken-photo placeholder (set by photo-img.js onerror chain).
 * Diagonal hatch, no broken-image glyph — looks intentional. R4 fallback. */
.photo-broken {
  background:
    repeating-linear-gradient(
      45deg,
      var(--earth-pale) 0 6px,
      var(--bg) 6px 12px
    ) !important;
}

/* Album list (cards, like the country grid but album-flavoured) */
.album-grid-list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-3);
}
@media (min-width: 540px) {
  .album-grid-list { grid-template-columns: repeat(2, 1fr); }
}
@media (min-width: 900px) {
  .album-grid-list { grid-template-columns: repeat(3, 1fr); }
}
.album-card {
  background: var(--surface);
  border: 1px solid var(--divider);
}
.album-card a {
  display: block;
  color: inherit;
  text-decoration: none;
}
.album-card a:hover,
.album-card a:focus-visible {
  outline: 1px solid var(--accent);
  outline-offset: -1px;
}
.album-thumb {
  display: block;
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  background: var(--earth-pale);
}
.album-card-meta {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  padding: var(--space-3);
}
.album-card-meta .album-name { font-weight: 500; }
.album-card-meta .album-count {
  color: var(--text-muted);
  font-size: var(--type-small);
}
.album-card-meta .album-dates {
  color: var(--text-muted);
  font-size: var(--type-small);
  font-variant-numeric: tabular-nums;
}
/* Per-album play button (M34 / ask #6): a circular ▶ over the thumbnail's top
   corner. Sibling of the card link (no interactive nesting); anchored to the
   card, which is now position:relative. */
.album-card { position: relative; }
.country-card { position: relative; }  /* anchor the random-play overlay (M41) */
.album-play {
  position: absolute;
  top: var(--space-2);
  inset-inline-end: var(--space-2);
  z-index: 2;
  width: 2.75rem;               /* ≥44px touch target */
  height: 2.75rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0 0 0 2px;           /* optical-centre the ▶ glyph */
  border: none;
  border-radius: 50%;
  background: rgba(20, 17, 14, 0.6);
  color: #f2ece2;
  font-size: 1rem;
  line-height: 1;
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
}
.album-play:hover,
.album-play:focus-visible { background: var(--earth-ochre); color: #fff; }

/* Labelled "play the album" button on the album page (M40 / #2). */
.album-page-play {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  margin: 0 0 var(--space-4);
  padding: var(--space-2) var(--space-4);
  background: var(--accent);
  color: #fff;
  border: none;
  border-radius: 999px;
  font-family: var(--font-family);
  font-size: var(--type-body);
  line-height: 1;
  cursor: pointer;
}
.album-page-play:hover,
.album-page-play:focus-visible { background: var(--earth-ochre); }
.album-page-play-icon { font-size: 0.8em; }

/* "Next album" link at the bottom of an album page (M55 / #6). A quiet,
   full-width footer link to the next album in the viewing country. */
.album-next {
  display: block;
  margin: var(--space-6) auto var(--space-5);
  padding: var(--space-3) var(--space-4);
  max-width: 32rem;
  text-align: center;
  background: var(--surface, #efe7da);
  color: var(--accent);
  border: 1px solid var(--accent);
  border-radius: 999px;
  font-family: var(--font-family);
  font-size: var(--type-body);
  text-decoration: none;
}
.album-next:hover,
.album-next:focus-visible { background: var(--accent); color: #fff; }

/* Album day groups (M14): a date header above each day's photo grid. */
.day-group { margin-bottom: var(--space-4); }
.day-header {
  position: sticky;
  top: 0;
  z-index: 5;
  background: var(--bg);
  color: var(--accent);
  font-size: var(--type-h2);
  font-weight: 500;
  margin: 0 0 var(--space-2);
  padding: var(--space-1) 0;
  font-variant-numeric: tabular-nums;
}

/* Album grid — uniform-width tiles in an auto-fill grid so EVERY photo (incl.
   the last row of each day) is exactly the same width; full rows fill the row,
   the last row simply leaves trailing space rather than slimming its tiles.
   Fixed row height + object-fit:cover (the manifest has no per-photo w/h; true
   aspect-justified rows remain a follow-up needing build-manifest dimensions). */
.photo-grid {
  list-style: none;
  padding: 0;
  margin: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
  gap: var(--space-1);
}
.photo-tile { margin: 0; }
.photo-tile a {
  display: block;
  outline-offset: -2px;
}
.photo-tile a:hover,
.photo-tile a:focus-visible {
  outline: 2px solid var(--accent);
}
.album-photo {
  display: block;
  width: 100%;
  height: 150px;
  object-fit: cover;
  border-radius: 4px;
  background: var(--earth-pale);
}
@media (max-width: 768px) {
  .photo-grid { grid-template-columns: repeat(auto-fill, minmax(108px, 1fr)); }
  .album-photo { height: 110px; }
}

/* ---- M5: slideshow ---- */
.slideshow-shell {
  position: fixed;
  inset: 0;
  z-index: 100;
  /* M5: the stage is ALWAYS the warm charcoal, in both themes — a photo
     viewer wants a neutral dark surround regardless of the site theme. The
     local --stage override beats the light/dark token so the slideshow never
     turns paper-white in light mode. */
  --stage: #211e1b;
  background: var(--stage);
  display: flex;
  flex-direction: column;
}
.slideshow-stage {
  position: relative;
  flex: 1 1 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 0;                /* let the photo shrink within flex */
  overflow: hidden;
}
.slideshow-photo {
  /* Fill the stage (M11): contain keeps aspect, but the image now scales up
     to use all available space instead of being capped at its natural size
     (which left black margins on large/fullscreen viewports). */
  width: 100%;
  height: 100%;
  object-fit: contain;
  user-select: none;
  -webkit-user-drag: none;
}
.slideshow-photo.photo-broken {
  width: 60vw;
  height: 40vh;
}

/* Slide transitions (M31 / ask #1). The shell carries a tr-<name> class; the
   photo is recreated on every navigation, so these *entry* animations replay
   automatically when the new slide mounts. `none` has no animation (instant
   cut). kenburns runs across the autoplay dwell (--kb-dwell, set inline). */
@keyframes ss-fade { from { opacity: 0; } to { opacity: 1; } }
@keyframes ss-zoom { from { opacity: 0; transform: scale(1.06); } to { opacity: 1; transform: scale(1); } }
@keyframes ss-slide { from { opacity: 0; transform: translateX(6%); } to { opacity: 1; transform: translateX(0); } }
@keyframes ss-kenburns { from { transform: scale(1); } to { transform: scale(1.08); } }
.slideshow-shell.tr-fade .slideshow-photo { animation: ss-fade 0.45s ease both; }
.slideshow-shell.tr-zoom .slideshow-photo { animation: ss-zoom 0.5s ease both; }
.slideshow-shell.tr-slide .slideshow-photo { animation: ss-slide 0.45s ease both; }
.slideshow-shell.tr-kenburns .slideshow-photo {
  animation: ss-kenburns var(--kb-dwell, 6000ms) ease-out both;
  will-change: transform;
}
@media (prefers-reduced-motion: reduce) {
  .slideshow-shell .slideshow-photo { animation: none !important; }
}
/* Invisible tap zones: left 25% = next (RTL), right 25% = prev, with a NEUTRAL
   middle 50% that doesn't navigate (slideshow-ux-3 #1) — a tap there just
   reveals the controls. */
.slideshow-zone {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 25%;
  /* Invisible click/touch target. The random slideshow renders these zones as
     <button> (JS-driven nav), and a bare <button> paints the UA default
     ButtonFace background (~#f0f0f0) — which covered 80% of the photo area in
     pale grey. Reset every UA control style so the dark shell shows through and
     the full, uncropped photo reads edge-to-edge. */
  margin: 0;
  padding: 0;
  border: 0;
  background: transparent;
  color: inherit;
  font: inherit;
  appearance: none;
  -webkit-appearance: none;
  cursor: pointer;
  /* M33 / ask #8 — a long-press on a tap-zone of a LIVE slideshow used to feel
     like the side "captured" the press: iOS popped the link callout / a text
     selection, Android the context menu. Suppress all of that so a long-press
     does nothing; a normal tap still navigates. (The contextmenu event is also
     swallowed in main.js as the explicit no-op handle.) */
  -webkit-touch-callout: none;
  user-select: none;
  -webkit-user-select: none;
  touch-action: manipulation;
}
.slideshow-zone-next { inset-inline-start: 0; }   /* left in RTL */
.slideshow-zone-prev { inset-inline-end: 0; }      /* right in RTL */
/* M5 + slideshow-ux #3: the control row AND the on-demand filmstrip live in ONE
   bottom DOCK that overlays the photo and auto-hides after idle (windowed +
   fullscreen). The filmstrip sits ABOVE the bar inside the dock, so it can never
   collide with the (wrapping, multi-row on phone) control bar. main.js toggles
   .controls-visible from the pure controls-timer predicate (windowedAutoHide). */
.slideshow-dock {
  position: absolute;
  inset-inline: 0;
  bottom: 0;
  z-index: 2;
  display: flex;
  flex-direction: column;       /* filmstrip on top, bar below */
  /* auto-hide default state; .controls-visible reveals it */
  opacity: 0;
  transform: translateY(100%);
  pointer-events: none;
  transition: opacity 0.25s ease, transform 0.25s ease;
}
.slideshow-shell.controls-visible .slideshow-dock {
  opacity: 1;
  transform: none;
  pointer-events: auto;
}
@media (prefers-reduced-motion: reduce) {
  .slideshow-dock { transition: opacity 0.25s ease; }
}
/* Hide the cursor while the controls are hidden — immersive, both modes. */
.slideshow-shell:not(.controls-visible) { cursor: none; }

.slideshow-bar {
  display: flex;
  align-items: center;
  /* WRAP so every control stays visible on a narrow phone (M30 / ask #2):
     the control GROUPS reflow onto a second centred row rather than clipping
     the end buttons on a ~390px portrait screen, each ≥44px touch target
     intact. On ≥600px the row has room and never wraps. */
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--space-2) var(--space-3);
  padding: var(--space-3) var(--space-3);
  color: #f2ece2;
  /* plain gradient scrim (design.md: no blur/glassmorphism) so controls read
     over bright photos. */
  background: linear-gradient(to top, rgba(0, 0, 0, 0.62), rgba(0, 0, 0, 0));
  font-size: var(--type-small);
  /* keep clear of the iOS home indicator / notch */
  padding-bottom: max(var(--space-3), env(safe-area-inset-bottom));
}

/* Control groups: visually cluster nav / config / actions within the one bar. */
.slideshow-group {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
}
.slideshow-nav-btn {
  flex: 0 0 auto;
  appearance: none;
  -webkit-appearance: none;
  background: none;
  border: none;
  color: #f2ece2;
  font-size: 1.4rem;
  line-height: 1;
  text-decoration: none;
  cursor: pointer;
  width: 2.75rem;               /* ≥44px touch target */
  height: 2.75rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.slideshow-nav-btn:hover,
.slideshow-nav-btn:focus-visible { color: #fff; }
.slideshow-strip-btn {
  flex: 0 0 auto;
  appearance: none;
  -webkit-appearance: none;
  background: none;
  border: none;
  color: #f2ece2;
  font-size: 1.05rem;
  line-height: 1;
  cursor: pointer;
  min-width: 2.5rem;
  height: 2.75rem;             /* ≥44px touch target */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-family);
}
.slideshow-strip-btn:hover,
.slideshow-strip-btn:focus-visible { color: #fff; }
.slideshow-strip-btn[aria-expanded="true"] { color: var(--earth-ochre); }

/* On-demand filmstrip (slideshow-ux #2/#3/#4): a horizontally-scrollable rail of
   the album's photos, full-width ABOVE the bar inside the dock. main.js builds
   it lazily on toggle, persists open/closed across slide advances, and adds
   drag-to-scroll. NO scrollbar — scroll by two-finger / drag / swipe instead. */
.slideshow-filmstrip {
  display: flex;
  gap: var(--space-1);
  width: 100%;
  overflow-x: auto;
  overflow-y: hidden;
  padding: var(--space-2) var(--space-3);
  background: linear-gradient(to top, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0));
  cursor: grab;
  user-select: none;
  -webkit-user-select: none;
  touch-action: pan-x;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;                 /* Firefox: no scrollbar */
}
.slideshow-filmstrip::-webkit-scrollbar { display: none; }  /* WebKit/Blink: no scrollbar */
.slideshow-filmstrip.is-dragging { cursor: grabbing; }
.slideshow-filmstrip[hidden] { display: none; }
.filmstrip-thumb {
  flex: 0 0 auto;
  display: block;
  width: 4.5rem;
  height: 3rem;
  border-radius: 3px;
  overflow: hidden;
  /* fully opaque — every thumbnail reads at full colour (slideshow-ux #4);
     the current photo is marked only by the accent outline. */
  outline: 2px solid transparent;
  -webkit-user-drag: none;   /* drag scrolls the rail, not a ghost image (#2b) */
}
.filmstrip-thumb.is-active { outline-color: var(--earth-ochre); }
.filmstrip-thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  -webkit-user-drag: none;
}
.slideshow-close {
  flex: 0 0 auto;
  color: #f2ece2;
  text-decoration: none;
  font-size: 1.25rem;
  line-height: 1;
  width: 2.75rem;               /* ≥44px touch target */
  height: 2.75rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.slideshow-close:hover,
.slideshow-close:focus-visible { color: #fff; }
.slideshow-play {
  flex: 0 0 auto;
  appearance: none;
  background: none;
  border: none;
  color: #f2ece2;
  font-size: 0.9rem;
  line-height: 1;
  cursor: pointer;
  width: 2.75rem;               /* ≥44px touch target */
  height: 2.75rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-family);
}
.slideshow-play:hover,
.slideshow-play:focus-visible { color: #fff; }
.slideshow-play[aria-pressed="true"] { color: var(--earth-ochre); }

/* M9: shared bar control (speed / fullscreen / download / info) */
.slideshow-speed-btn,
.slideshow-tr-btn,
.slideshow-loop-btn,
.slideshow-fs,
.slideshow-dl,
.slideshow-info > summary,
.slideshow-share > summary {
  flex: 0 0 auto;
  appearance: none;
  -webkit-appearance: none;
  background: none;
  border: none;
  color: #f2ece2;
  font-size: 0.95rem;
  line-height: 1;
  cursor: pointer;
  min-width: 2.5rem;
  height: 2.75rem;            /* ≥44px touch target */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  text-decoration: none;
  font-family: var(--font-family);
  list-style: none;           /* hide default <summary> marker */
}
.slideshow-speed-btn { font-variant-numeric: tabular-nums; font-size: 0.8rem; }
.slideshow-tr-btn { font-size: 0.8rem; }
.slideshow-loop-btn { font-size: 1.05rem; }
/* "continue" mode is the active (non-default) state — tint it like play's on-state */
.slideshow-loop-btn[aria-pressed="true"] { color: var(--earth-ochre); }
/* Vertically mirror the "next album" glyph in continue mode (M44 / #7). */
.slideshow-loop-btn .loop-glyph { display: inline-block; }
.slideshow-loop-btn[aria-pressed="true"] .loop-glyph { transform: scaleX(-1); }
.slideshow-info > summary::-webkit-details-marker { display: none; }
.slideshow-share > summary::-webkit-details-marker { display: none; }
.slideshow-speed-btn:hover, .slideshow-speed-btn:focus-visible,
.slideshow-tr-btn:hover, .slideshow-tr-btn:focus-visible,
.slideshow-fs:hover, .slideshow-fs:focus-visible,
.slideshow-dl:hover, .slideshow-dl:focus-visible,
.slideshow-share > summary:hover,
.slideshow-info > summary:hover { color: #fff; }

/* Share menu (M42 / #4) — pops above the bar like the info panel. */
.slideshow-share { position: relative; }
.slideshow-share[open] > summary { color: var(--earth-ochre); }
.slideshow-share-menu {
  position: fixed;
  left: 50%;
  bottom: 6.5rem;
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  min-width: 12rem;
  max-width: calc(100vw - 2 * var(--space-3));
  background: rgba(20, 17, 14, 0.96);
  border: 1px solid rgba(242, 236, 226, 0.2);
  border-radius: 4px;
  padding: var(--space-2);
  gap: 2px;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.4);
}
.slideshow-share-item {
  appearance: none;
  -webkit-appearance: none;
  background: none;
  border: none;
  color: #f2ece2;
  font-family: var(--font-family);
  font-size: var(--type-small);
  text-align: start;
  padding: var(--space-2) var(--space-3);
  border-radius: 3px;
  cursor: pointer;
}
.slideshow-share-item:hover,
.slideshow-share-item:focus-visible { background: rgba(242, 236, 226, 0.12); }
@media (min-width: 600px) {
  .slideshow-share-menu {
    position: absolute; left: auto; bottom: 3rem;
    inset-inline-start: 0; transform: none;
  }
}
/* Transient copy/share confirmation toast. */
.slideshow-toast {
  position: fixed;
  left: 50%;
  bottom: 7.5rem;
  transform: translateX(-50%) translateY(0.5rem);
  background: rgba(20, 17, 14, 0.95);
  color: #f2ece2;
  border: 1px solid rgba(242, 236, 226, 0.2);
  border-radius: 999px;
  padding: var(--space-2) var(--space-4);
  font-size: var(--type-small);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s ease, transform 0.2s ease;
  z-index: 5;
}
.slideshow-toast.is-visible { opacity: 1; transform: translateX(-50%) translateY(0); }

/* Info panel: pops up above the bar from the ⓘ summary */
.slideshow-info { position: relative; }
.slideshow-info[open] > summary { color: var(--earth-ochre); }
/* Phone base (M30 / ask #2): anchor the panel to the VIEWPORT, horizontally
   centred, instead of to the ⓘ summary. Summary-anchored absolute positioning
   pushed the panel off the screen edge whenever the ⓘ sat near the inline
   edge of the (now wrapping) bar. Fixed + centred guarantees it's always
   fully on-screen and clears a one- or two-row bar; it scrolls if tall. */
.slideshow-info .info-body {
  position: fixed;
  left: 50%;
  bottom: 6.5rem;
  transform: translateX(-50%);
  margin: 0;
  width: max-content;
  max-width: calc(100vw - 2 * var(--space-3));
  max-height: 60vh;
  overflow-y: auto;
  background: rgba(20, 17, 14, 0.96);
  border: 1px solid rgba(242, 236, 226, 0.2);
  border-radius: 4px;
  padding: var(--space-3);
  color: #f2ece2;
  font-size: var(--type-small);
  line-height: 1.5;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.4);
}
/* ≥600px: enough room to anchor the panel to the ⓘ button again (nicer,
   contextual) — the bar never wraps at this width so it can't clip. */
@media (min-width: 600px) {
  .slideshow-info .info-body {
    position: absolute;
    left: auto;
    bottom: 3rem;
    inset-inline-start: 0;
    transform: none;
    width: auto;
    min-width: 16rem;
    max-width: 78vw;
    max-height: none;
    overflow-y: visible;
  }
}
.slideshow-info .info-row {
  display: flex;
  gap: var(--space-2);
  padding: 2px 0;
}
.slideshow-info .info-row dt {
  flex: 0 0 4rem;
  color: rgba(242, 236, 226, 0.6);
}
.slideshow-info .info-row dd { margin: 0; flex: 1 1 auto; }
/* Position counter "35 / 74" + size "5215KB" keep LTR digit order but align to
   the RIGHT like every other value (#5), instead of LTR's default left. */
.slideshow-info .info-count,
.slideshow-info .info-size { text-align: right; }
.slideshow-counter {
  flex: 0 0 auto;
  font-variant-numeric: tabular-nums;
  opacity: 0.85;
}
/* Random-viewer place buttons (slideshow-ux-2 #6): album name (+ country name
   for "random all") as VISIBLE pills with a background, so they read over a
   bright photo instead of disappearing as bare light text. */
.slideshow-place-btn {
  flex: 0 1 auto;
  max-width: 42vw;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: #f2ece2;
  text-decoration: none;
  background: rgba(0, 0, 0, 0.45);
  border: 1px solid rgba(242, 236, 226, 0.25);
  border-radius: 16px;
  padding: 0.35em 0.8em;
  font-size: var(--type-small);
  line-height: 1.2;
}
.slideshow-place-btn:hover,
.slideshow-place-btn:focus-visible { background: rgba(0, 0, 0, 0.65); color: #fff; }
.slideshow-country { font-weight: 500; }

/* ── Map view (M18) ─────────────────────────────────────────── */
.map-page {
  display: flex;
  flex-direction: column;
  height: 100dvh;
  /* Prevent body scroll while the map fills the screen */
  overflow: hidden;
}
.map-header {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3);
  border-bottom: 1px solid var(--divider);
  background: var(--surface);
}
.map-back {
  font-size: var(--type-small);
  color: var(--accent);
  white-space: nowrap;
}
.map-title {
  font-size: var(--type-h2);
  font-weight: 500;
  flex: 1;
}
.map-container {
  flex: 1 1 auto;
  /* Leaflet needs explicit size — 100% of flex parent works when parent has
     a defined height (provided by .map-page height:100dvh). */
  width: 100%;
  /* Reset Leaflet z-index layering inside our stacking context */
  isolation: isolate;
}

/* Leaflet attribution RTL fix (float:right → float:left in our RTL page) */
.leaflet-control-attribution {
  direction: ltr !important;
}

/* Hebrew country labels on the (label-free) base map (M58 / #2). */
.map-country-label-wrap {
  background: transparent !important;
  border: none !important;
  pointer-events: none;
}
.map-country-label {
  display: inline-block;
  transform: translate(-50%, -50%);
  white-space: nowrap;
  color: #5a4632;
  font-family: var(--font-family);
  font-weight: 700;
  font-size: 0.95rem;
  letter-spacing: 0.04em;
  text-shadow:
    0 0 3px #fff, 0 0 3px #fff, 0 0 6px #fff, 0 1px 2px rgba(255, 255, 255, 0.9);
}

/* Custom pin marker */
.map-pin-wrapper {
  background: transparent !important;
  border: none !important;
}
.map-pin {
  width: 14px;
  height: 14px;
  border-radius: 50%;
  border: 2px solid rgba(255,255,255,0.85);
  box-shadow: 0 1px 4px rgba(0,0,0,0.35);
  cursor: pointer;
  transition: transform 0.12s;
}
.map-pin:hover,
.map-pin:focus {
  transform: scale(1.35);
}
/* Empty opening stop (e.g. גבעת שמואל) — hollow pin, no album link (M27). */
.map-pin-empty {
  background: transparent !important;
  border: 2px solid var(--text-muted);
  box-shadow: none;
}
/* Non-link label inside a popup (empty stop) */
.map-popup-label {
  display: block;
  color: var(--text-muted);
  line-height: 1.4;
}

/* Map popup */
.map-popup {
  font-family: var(--font-family);
  font-size: var(--type-small);
  direction: rtl;
  text-align: right;
  min-width: 120px;
}
.map-popup-link {
  color: var(--accent);
  font-weight: 500;
  text-decoration: none;
  display: block;
  line-height: 1.4;
}
.map-popup-link:hover {
  text-decoration: underline;
}

/* Cluster marker (M21) — multiple albums at one location */
.map-pin-cluster {
  width: 24px;
  height: 24px;
  border-radius: 50%;
  border: 2px solid rgba(255,255,255,0.9);
  box-shadow: 0 1px 5px rgba(0,0,0,0.4);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 11px;
  font-weight: 700;
  color: #fff;
  cursor: pointer;
  transition: transform 0.12s;
}
.map-pin-cluster:hover { transform: scale(1.25); }

/* Map/Globe toggle (M21) */
.map-toggle {
  display: flex;
  border: 1px solid var(--divider);
  border-radius: 6px;
  overflow: hidden;
  margin-inline-start: auto;
}
.map-toggle-btn {
  padding: var(--space-1) var(--space-3);
  border: none;
  background: var(--surface);
  font-family: var(--font-family);
  font-size: var(--type-small);
  cursor: pointer;
  transition: background 0.12s, color 0.12s;
}
.map-toggle-btn.active {
  background: var(--accent);
  color: #fff;
}
.map-toggle-btn:not(.active):hover { background: var(--bg); }

/* Globe container (M21) */
.globe-container {
  position: relative;    /* anchor the loading overlay (#4) */
  flex: 1 1 auto;
  width: 100%;
  min-height: 0;         /* let it shrink in a flex column (landscape phone #9) */
  background: #0a0a12;   /* deep space */
  isolation: isolate;
  overflow: hidden;      /* clip the WebGL canvas to its box */
}
.globe-container canvas { display: block; }
/* The map/timeline/game theme toggles sit at the far (inline-end) edge. */
.tl-header .slim-toggle { margin-inline-start: auto; }

/* Globe loading overlay (M57 / #4): a starfield + Hebrew caption shown while
   globe.gl + three.js download and the scene builds, instead of a blank box. */
.globe-loading {
  position: absolute;
  inset: 0;
  z-index: 3;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-4);
  background: #05070d;   /* near-black space */
  overflow: hidden;
}
/* Three layered fields of tiny star dots, each a different size/offset, gently
   twinkling. Pure CSS — no images. */
.globe-stars,
.globe-stars::before,
.globe-stars::after {
  content: "";
  position: absolute;
  inset: 0;
  background-repeat: repeat;
  background-image:
    radial-gradient(1.5px 1.5px at 20px 30px, #ffffff 99%, transparent),
    radial-gradient(1.5px 1.5px at 90px 80px, #cfe0ff 99%, transparent),
    radial-gradient(1px 1px at 150px 50px, #ffffff 99%, transparent),
    radial-gradient(1px 1px at 200px 120px, #e9f0ff 99%, transparent);
  background-size: 220px 180px;
  animation: globe-twinkle 3.6s ease-in-out infinite alternate;
}
.globe-stars::before { background-size: 320px 260px; opacity: 0.7; animation-delay: 1.2s; }
.globe-stars::after  { background-size: 160px 140px; opacity: 0.5; animation-delay: 2.4s; }
@keyframes globe-twinkle {
  from { opacity: 0.45; }
  to   { opacity: 1; }
}
.globe-loading-text {
  position: relative;
  z-index: 1;
  color: #eaf0ff;
  font-family: var(--font-family);
  font-size: var(--type-h2, 1.25rem);
  letter-spacing: 0.02em;
  text-shadow: 0 1px 8px rgba(0, 0, 0, 0.6);
}
@media (prefers-reduced-motion: reduce) {
  .globe-stars,
  .globe-stars::before,
  .globe-stars::after { animation: none; }
}

/* "Choose which album" picker for a globe city visited 2+ times (M38 / #10). */
.globe-picker-backdrop {
  position: fixed;
  inset: 0;
  z-index: 120;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(10, 10, 18, 0.6);
  padding: var(--space-4);
}
.globe-picker {
  position: relative;
  max-width: min(22rem, 92vw);
  width: 100%;
  background: var(--surface);
  border: 1px solid var(--divider);
  border-radius: 6px;
  padding: var(--space-4) var(--space-4) var(--space-3);
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5);
}
.globe-picker-close {
  position: absolute;
  top: var(--space-2);
  inset-inline-end: var(--space-2);
  width: 2.25rem;
  height: 2.25rem;
  border: none;
  background: none;
  color: var(--text-muted);
  font-size: 1.1rem;
  cursor: pointer;
  border-radius: 4px;
}
.globe-picker-close:hover { color: var(--text); }
.globe-picker-title {
  margin: 0 0 var(--space-3);
  font-weight: 500;
  font-size: var(--type-body);
}
.globe-picker-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-1); }
.globe-picker-link {
  display: block;
  padding: var(--space-2) var(--space-3);
  color: var(--accent);
  text-decoration: none;
  border-radius: 4px;
}
.globe-picker-link:hover,
.globe-picker-link:focus-visible { background: var(--earth-pale); }

/* ── Game view (M19) ────────────────────────────────────────────── */
.game-shell {
  /* Full-viewport takeover (M35 / ask #5) so the photo can truly fill the
     screen. Previously min-height:100dvh sat INSIDE main#app's vertical
     padding, so the shell ran 100dvh + that padding and pushed the answer
     grid below the fold. position:fixed escapes the page padding (same pattern
     as the slideshow shell); overflow-y keeps it usable on very short screens. */
  position: fixed;
  inset: 0;
  z-index: 50;
  display: flex;
  flex-direction: column;
  background: var(--bg);
  overflow-y: auto;
}
.game-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--space-3);          /* M68.3: keep score/toggle from crowding each other */
  padding: var(--space-3);
  border-bottom: 1px solid var(--divider);
  background: var(--surface);
  font-size: var(--type-small);
  color: var(--text-muted);
}
.game-score { font-weight: 700; color: var(--accent); }
.game-back { color: var(--accent); text-decoration: none; white-space: nowrap; }
.game-back:hover, .game-back:focus-visible { color: var(--earth-ochre); }
/* M68.2: the theme toggle must NOT stretch in the game header — the global
   portrait rule sets .slim-nav{flex:1}; keep it a compact icon pill so the
   header items (toggle · score · round · restart · back) space out evenly. */
.game-header .slim-toggle { flex: 0 0 auto; padding: .25em .5em; }
/* M68.4: restart — compact icon button just left of "חזרה"; reuses the replay
   action. The header's gap gives it spacing from the back link. */
.game-restart {
  display: inline-flex;
  align-items: center;
  flex: 0 0 auto;
  padding: .15em .35em;
  background: none;
  border: none;
  color: var(--accent);
  font-size: 1.2em;
  line-height: 1;
  cursor: pointer;
}
.game-restart:hover, .game-restart:focus-visible { color: var(--earth-ochre); }
/* M7: slim progress track under the header; the bar fills ∝ roundNum/total. */
.game-progress {
  flex: 0 0 auto;
  height: 4px;
  background: var(--divider);
  overflow: hidden;
}
.game-progress-bar {
  height: 100%;
  background: var(--accent);
  transition: width 0.3s ease;
}
/* M7: body holds the photo + the answer rail. Column by default (photo on top,
   options below); flips to a row in landscape (see the orientation media query
   at the end of this section) so the options sit beside the photo. */
.game-body {
  flex: 1 1 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
}
.game-answers {
  display: flex;
  flex-direction: column;
  min-height: 0;
}
.game-stage {
  /* M35 / ask #5 — maximise the photo: the stage GROWS to take all vertical
     space the header / prompt / answer grid leave, instead of being hard-
     capped at 45dvh. flex-basis MUST be 0 (not auto): with auto, the stage's
     basis inflates to the image's intrinsic pixel height and the answer grid
     gets pushed off the bottom. basis 0 means the stage takes only the
     leftover slack, so everything fits within the viewport and the photo
     still fills it. */
  flex: 1 1 0;
  min-height: 0;
  position: relative;           /* anchor the absolutely-positioned photo */
  background: #14110e;
  overflow: hidden;
}
.game-photo {
  /* Absolutely filled so the <img> contributes ZERO to the stage's layout
     height — otherwise its automatic min-content size pushes the answer grid
     off the bottom. The stage takes pure flex leftover; the photo fills it. */
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
}
.game-prompt {
  padding: var(--space-3);
  font-size: var(--type-body);
  font-weight: 500;
  text-align: center;
}
.game-correct { color: #2e7d32; }
.game-wrong   { color: var(--error); }

/* Country pick grid: 2×2 on phone, 4 in a row on wider (only 4 options — M68.1) */
.game-country-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--space-2);
  padding: var(--space-2) var(--space-3) var(--space-3);
}
@media (min-width: 600px) {
  .game-country-grid { grid-template-columns: repeat(4, 1fr); }
}
.game-country-btn {
  padding: var(--space-2) var(--space-1);
  border: 1px solid var(--divider);
  border-radius: 6px;
  background: var(--surface);
  color: var(--text);
  font-family: var(--font-family);
  font-size: var(--type-small);
  cursor: pointer;
  transition: background 0.12s, border-color 0.12s;
}
.game-country-btn:hover,
.game-country-btn:focus {
  border-color: var(--accent);
  background: #f0e8df;
}

/* Album pick: 2×2 on phone, 4 in a row wider */
.game-album-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--space-2);
  padding: var(--space-2) var(--space-3) var(--space-3);
}
@media (min-width: 769px) {
  .game-album-grid { grid-template-columns: repeat(4, 1fr); }
}
.game-album-btn {
  padding: var(--space-2);
  border: 1px solid var(--divider);
  border-radius: 6px;
  background: var(--surface);
  color: var(--text);
  font-family: var(--font-family);
  font-size: var(--type-small);
  text-align: center;
  cursor: pointer;
  transition: background 0.12s, border-color 0.12s;
}
.game-album-btn:hover,
.game-album-btn:focus {
  border-color: var(--accent);
  background: #f0e8df;
}
/* Correct/wrong chips keep their light tint in both themes, so pin a dark text
   colour on them for legibility (M68.1). */
.game-album-btn.correct { background: #e8f5e9; border-color: #2e7d32; color: #14110e; }
.game-album-btn.wrong   { background: #ffebee; border-color: #c62828; color: #14110e; }

/* Dark mode (M68.1): native <button>s don't inherit colour (handled above with
   color: var(--text)); here we make the resting border + hover readable on the
   dark surface — the subtle --divider border vanishes otherwise. */
[data-theme="dark"] .game-country-btn,
[data-theme="dark"] .game-album-btn { border-color: var(--text-muted); }
[data-theme="dark"] .game-country-btn:hover,
[data-theme="dark"] .game-country-btn:focus,
[data-theme="dark"] .game-album-btn:hover,
[data-theme="dark"] .game-album-btn:focus {
  border-color: var(--accent);
  background: var(--divider);
}

/* Result */
.game-result-info {
  padding: var(--space-3);
  text-align: center;
}
.game-result-album { font-size: var(--type-body); margin-bottom: var(--space-1); }
.game-result-points { font-size: var(--type-small); color: var(--text-muted); }
.game-result-actions { display: flex; justify-content: center; padding: var(--space-3); }
.game-next-btn {
  padding: var(--space-2) var(--space-4, 2rem);
  background: var(--accent);
  color: #fff;
  border: none;
  border-radius: 6px;
  font-family: var(--font-family);
  font-size: var(--type-body);
  font-weight: 500;
  cursor: pointer;
}
.game-next-btn:hover { background: var(--accent-dim); }

/* Done screen */
.game-done-content {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-3);
  padding: var(--space-4, 2rem) var(--space-3);
  text-align: center;
}
.game-done-title { font-size: var(--type-display); font-weight: 700; }
.game-done-score { font-size: 2rem; font-weight: 700; color: var(--accent); }
.game-done-pct   { font-size: var(--type-body); color: var(--text-muted); }
.game-done-actions { display: flex; gap: var(--space-3); flex-wrap: wrap; justify-content: center; }
.game-replay-btn {
  padding: var(--space-2) var(--space-4, 2rem);
  background: var(--accent);
  color: #fff;
  border: none;
  border-radius: 6px;
  font-family: var(--font-family);
  font-size: var(--type-body);
  font-weight: 500;
  cursor: pointer;
}
.game-home-btn {
  padding: var(--space-2) var(--space-4, 2rem);
  border: 1px solid var(--accent);
  border-radius: 6px;
  color: var(--accent);
  font-size: var(--type-body);
  font-weight: 500;
}

/* M68.1: by default (PC + portrait phone/tablet) the options sit BELOW the
   photo — the natural, symmetric, photo-centred layout. ONLY a short landscape
   screen (a phone on its side) has no room below, so there the body flips to a
   row and the 4 options stack as a single-column side rail (4 rows × 1 button).
   PC is also "landscape" orientation, hence the max-height gate keeps PC on the
   below layout. */
@media (orientation: landscape) and (max-height: 500px) {
  .game-body { flex-direction: row; }
  .game-stage { flex: 1 1 0; }
  /* fixed-ish side rail, vertically centred, scrolls if the options overflow */
  .game-answers {
    flex: 0 0 clamp(200px, 34%, 360px);
    justify-content: center;
    overflow-y: auto;
  }
  /* one button per row — overrides the 2/4-column grids above */
  .game-answers .game-country-grid,
  .game-answers .game-album-grid { grid-template-columns: 1fr; }
  /* M68.2: keep the top line but place it nicely — toggle+score (left),
     round (centre), back (right). DOM order is back·round·score·toggle, so
     auto-margins on round split the free space either side of it. */
  .game-round { margin-inline: auto; }
}

/* M68.2: PC / tall-landscape — drop the header BAR and tuck the chrome into the
   stage's top corners (the photo isn't 16:9-wide, so the corners are free),
   letting the photo take the full height. toggle+score sit in the left corner,
   round+back in the right; the thin progress bar stays at the very top edge. */
@media (orientation: landscape) and (min-height: 501px) {
  .game-header {
    position: absolute;
    inset: var(--space-1) 0 auto 0;
    z-index: 3;
    background: transparent;
    border-bottom: none;
  }
  /* DOM order back·round·score·toggle → an auto start-margin on score packs
     back+round to the right corner and score+toggle to the left corner. */
  .game-score { margin-inline-start: auto; }
  /* M68.3: each label rides its own solid scrim chip so it stays legible over
     ANY photo (white-bg photos included) — a functional photo scrim, NOT a
     backdrop-filter blur (anti-AI forbids glassmorphism). */
  .game-header .game-round,
  .game-header .game-score,
  .game-header .game-back,
  .game-header .game-restart {
    background: rgba(20, 17, 14, 0.58);
    padding: 0.2em 0.6em;
    border-radius: 7px;
  }
  .game-round { color: #f3ece1; }   /* fixed light on the dark chip (theme-independent) */
  .game-back  { color: #f3ece1; }
  .game-restart { color: #f3ece1; }
  .game-score { color: #f0c08a; }   /* warm light, legible on the dark chip */
}

/* M68.2: end-of-game confetti (fired by renderGameDone when celebrate). Pure
   CSS — absolutely-positioned pieces fall and tumble; colours from the trip
   palette, varied per piece via :nth-child. */
.game-confetti {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
  z-index: 10;
}
.game-confetti span {
  position: absolute;
  top: -8%;
  width: 9px;
  height: 9px;
  border-radius: 2px;
  opacity: 0;
  animation: game-confetti-fall 3s linear infinite;
}
/* fade in at the top, drift sideways + tumble on the way down, fade out at the
   bottom so pieces don't pop out of existence. --drift/--spin vary per piece. */
@keyframes game-confetti-fall {
  0%   { transform: translate3d(0, -12vh, 0) rotate(0deg); opacity: 0; }
  8%   { opacity: 1; }
  88%  { opacity: 1; }
  100% { transform: translate3d(var(--drift, 0px), 112vh, 0) rotate(var(--spin, 540deg)); opacity: 0; }
}
/* shape variety: circles, square chips, and a few thin streamers */
.game-confetti span:nth-child(3n)   { border-radius: 50%; }
.game-confetti span:nth-child(7n)   { width: 5px; height: 13px; border-radius: 1px; }
.game-confetti span:nth-child(5n+2) { width: 12px; height: 12px; }
.game-confetti span:nth-child(5n+4) { width: 7px;  height: 7px; }
/* colours (5-cycle, trip palette) */
.game-confetti span:nth-child(5n+1) { background: var(--accent); }
.game-confetti span:nth-child(5n+2) { background: #d99a2b; }
.game-confetti span:nth-child(5n+3) { background: #2e7d32; }
.game-confetti span:nth-child(5n+4) { background: #3d6ea5; }
.game-confetti span:nth-child(5n+5) { background: #b5485f; }
/* horizontal start (10-cycle, ~4 pieces each at 40 pieces) */
.game-confetti span:nth-child(10n+1) { left: 4%; }
.game-confetti span:nth-child(10n+2) { left: 14%; }
.game-confetti span:nth-child(10n+3) { left: 24%; }
.game-confetti span:nth-child(10n+4) { left: 34%; }
.game-confetti span:nth-child(10n+5) { left: 45%; }
.game-confetti span:nth-child(10n+6) { left: 55%; }
.game-confetti span:nth-child(10n+7) { left: 66%; }
.game-confetti span:nth-child(10n+8) { left: 76%; }
.game-confetti span:nth-child(10n+9) { left: 86%; }
.game-confetti span:nth-child(10n)   { left: 95%; }
/* drift sideways + tumble + speed + stagger (6-cycle) so it never marches in lockstep */
.game-confetti span:nth-child(6n+1) { --drift:  34px; --spin:  680deg; animation-duration: 2.7s; animation-delay: 0s;   }
.game-confetti span:nth-child(6n+2) { --drift: -42px; --spin: -520deg; animation-duration: 3.3s; animation-delay: 0.5s; }
.game-confetti span:nth-child(6n+3) { --drift:  18px; --spin:  760deg; animation-duration: 2.4s; animation-delay: 1.1s; }
.game-confetti span:nth-child(6n+4) { --drift: -26px; --spin:  600deg; animation-duration: 3.5s; animation-delay: 0.3s; }
.game-confetti span:nth-child(6n+5) { --drift:  48px; --spin: -640deg; animation-duration: 2.9s; animation-delay: 0.8s; }
.game-confetti span:nth-child(6n)   { --drift: -14px; --spin:  500deg; animation-duration: 3.1s; animation-delay: 1.4s; }
@media (prefers-reduced-motion: reduce) {
  .game-confetti { display: none; }
}

/* ── Timeline view (M20) ────────────────────────────────────────── */
.tl-page {
  max-width: 860px;
  /* Cancel main#app's top padding so the (first-child) slider pins at y=0 from
     scroll 0 and never shifts as you scroll (#1a). */
  margin: calc(-1 * var(--space-5)) auto 0;
  padding-bottom: var(--space-4, 2rem);
}
@media (min-width: 769px) {
  .tl-page { margin-top: calc(-1 * var(--space-6)); }
}
.tl-header {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3);
  border-bottom: 1px solid var(--divider);
  background: var(--surface);
  /* M36 / ask #11 — NOT sticky. It used to be sticky at top:0 while the slider
     stuck at top:48px, but the header is actually ~73px tall, so the slider sat
     25px UNDER it and day headings hid behind the "← חזרה / ציר זמן" line. The
     back/title bar doesn't need pinning; it scrolls away and only the slider
     (the useful navigator) stays sticky at the very top. */
}
.tl-back  { font-size: var(--type-small); color: var(--accent); white-space: nowrap; }
.tl-title { font-size: var(--type-h2); font-weight: 500; }
.tl-sub   { font-size: var(--type-small); font-weight: 300; color: var(--text-muted); margin-inline-start: .35em; }

/* ── M8: textured chronological scrubber ─────────────────────────── */
.tl-motif-defs { position: absolute; left: 0; top: 0; width: 0; height: 0; overflow: hidden; }
.tl-scrubber {
  display: flex;
  flex-direction: column;      /* track + labels (bar) / vertical track (rail) */
  cursor: pointer;
  touch-action: none;          /* press-and-hold scrub without the page panning */
  user-select: none;           /* M69.5: a drag mustn't select the labels/feed text */
  -webkit-user-select: none;
}
.tl-scrubber:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* desktop + landscape phone: a horizontal slider STICKY at the very top — the
   sole navigator (M69.1); stays visible while the header + feed scroll under it.
   M69.2: an opaque toolbar so the country labels below the track stay readable. */
.tl-scrubber[data-orient="bar"] {
  position: sticky;
  top: 0;
  z-index: 40;
  background: var(--surface);
  border-bottom: 1px solid var(--divider);
  padding: var(--space-2) var(--space-3) var(--space-1);
}
/* portrait phone: a 22px vertical rail pinned to the right edge (top = trip
   start, bottom = end), always visible; the page reserves a column for it (see
   the portrait media query below) so it never overlaps the photos. */
.tl-scrubber[data-orient="rail"] {
  width: 22px;
  position: fixed;
  top: 28px;          /* M69.4: shorter rail — ~2.3× the M69.3 edge gap (#3) */
  bottom: 28px;
  right: 4px;
  z-index: 40;
  padding: 0;
  background: none;
  border: none;
}
/* the track = the coloured/textured segment bar (anchors the thumb). */
.tl-scrub-track {
  position: relative;
  display: flex;
  overflow: hidden;
  background: var(--divider);
}
.tl-scrubber[data-orient="bar"] .tl-scrub-track {
  flex-direction: row;
  height: 18px;
  border-radius: 9px;
}
.tl-scrubber[data-orient="rail"] .tl-scrub-track {
  flex-direction: column;
  flex: 1 1 auto;
  border-radius: 11px;          /* rounded floating pill (#4) */
}
/* slider THUMB — a raised rounded knob that reads as a draggable handle (M69.2);
   main.js positions it to mirror the current scroll/jump position. */
.tl-scrubber-handle {
  position: absolute;
  background: #fff;
  border: 2px solid var(--accent);
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.4);
  pointer-events: none;
  border-radius: 7px;
}
.tl-scrubber[data-orient="bar"] .tl-scrubber-handle {
  top: 50%; right: 0; width: 14px; height: 26px; transform: translate(50%, -50%);
}
.tl-scrubber[data-orient="rail"] .tl-scrubber-handle {
  left: 50%; top: 0; width: 30px; height: 14px; transform: translate(-50%, -50%);
}
/* country names under the track (bar only); each cell flex-grows like its
   segment so it sits under it. Narrow slivers clip to nothing. */
.tl-scrub-labels {
  display: flex;
  flex-direction: row;
  margin-top: 3px;
}
.tl-scrub-label {
  flex-basis: 0;
  min-width: 0;
  text-align: center;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: clip;
  font-size: 10px;
  color: var(--text-muted);
}
/* M69.3: a too-narrow segment shows a short "ת'" that's allowed to spill its
   cell (otherwise it would clip to nothing). */
.tl-scrub-label.is-mini {
  overflow: visible;
  flex-basis: auto;
  color: var(--accent);
  font-weight: 500;
}
.tl-scrubber[data-orient="rail"] .tl-scrub-labels { display: none; }
.tl-seg {
  flex-basis: 0;
  flex-shrink: 1;
  position: relative;
  min-width: 0;
  min-height: 0;
}
.tl-seg-tex {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}
.tl-tip {
  position: fixed;
  z-index: 60;
  background: rgba(20, 17, 14, 0.9);
  color: #fff;
  padding: 0.3em 0.6em;
  border-radius: 6px;
  font-size: var(--type-small);
  font-weight: 500;
  pointer-events: none;
  white-space: nowrap;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.35);
}
.tl-tip[hidden] { display: none; }

/* M69.2: on a real desktop, stretch the slider toward the full screen width
   (it otherwise caps at .tl-page's 860px) — full-bleed ~92vw, centred. */
@media (min-width: 1000px) {
  .tl-scrubber[data-orient="bar"] {
    width: 92vw;
    max-width: none;
    margin-inline: calc(50% - 46vw);
  }
}
/* M69.2: short landscape phones — make the slider full-bleed edge-to-edge (it
   was boxed inside the page padding) + drop the labels row so the photo feed
   keeps its height. */
@media (orientation: landscape) and (max-height: 500px) {
  .tl-scrubber[data-orient="bar"] {
    width: 94vw;                       /* wide, but with a margin from each edge (#4) */
    max-width: none;
    margin-inline: calc(50% - 47vw);
    padding-inline: 0;
  }
  .tl-scrub-labels { display: none; }
}

.tl-feed { padding: var(--space-3) var(--space-3) 0; }

.tl-day {
  margin-bottom: var(--space-4, 2rem);
}
/* M69.3: the day's date floats at the top as you scroll (like the album
   day-headers). --tl-bar-h (set by main.js) clears the sticky scrubber bar on
   desktop/landscape; it's 0 in portrait (the scrubber is a side rail there). */
.tl-day-heading {
  position: sticky;
  top: var(--tl-bar-h, 0px);
  z-index: 5;
  background: var(--bg);
  font-size: var(--type-h2);
  font-weight: 500;
  margin-bottom: var(--space-2);
  padding: var(--space-1) 0;
  display: flex;
  align-items: baseline;
  gap: var(--space-2);
}
.tl-day-count {
  font-size: var(--type-small);
  font-weight: 300;
  color: var(--text-muted);
}

.tl-photo-strip {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-1);
  align-items: flex-start;
}
.tl-album-tag {
  width: 100%;
  font-size: var(--type-small);
  color: var(--text-muted);
  padding: var(--space-1) 0;
}
.tl-thumb-link {
  display: block;
  flex: 0 0 auto;
}
.tl-thumb {
  width: 80px;
  height: 60px;
  object-fit: cover;
  border-radius: 3px;
  display: block;
  background: var(--divider);
}
@media (min-width: 600px) {
  .tl-thumb { width: 110px; height: 80px; }
}
@media (min-width: 1200px) {
  .tl-thumb { width: 140px; height: 105px; }
}

.tl-more-wrap {
  display: flex;
  justify-content: center;
  padding: var(--space-3);
}
.tl-more-btn {
  padding: var(--space-2) var(--space-4, 2rem);
  border: 1px solid var(--accent);
  border-radius: 6px;
  background: transparent;
  color: var(--accent);
  font-family: var(--font-family);
  font-size: var(--type-body);
  cursor: pointer;
}
.tl-more-btn:hover { background: #f0e8df; }

/* (The M22 date slider was removed in M69.1 — the textured scrubber above is
   now the sole timeline navigator.) */

/* ── Map trip trail (M24) ───────────────────────────────────────── */
.trail-arrow-wrapper { background: none !important; border: none !important; }
.trail-arrow {
  font-size: 14px;
  line-height: 16px;
  text-align: center;
  text-shadow: 0 0 2px rgba(255,255,255,0.9);
  pointer-events: none;
}

/* ── Timeline overhaul (M25) ────────────────────────────────────── */
/* M69.4: a jumped-to day lands exactly where its sticky heading pins — at the
   scrubber-bar height (desktop/landscape) or the very top (portrait). Matching
   scroll-margin to --tl-bar-h stops the PREVIOUS day's sticky heading from
   peeking above the current one after a slide (#2). */
.tl-day { scroll-margin-top: var(--tl-bar-h, 0px); }
/* Empty strip keeps page height ~stable before a day hydrates. */
.tl-photo-strip { min-height: 64px; }
@media (min-width: 600px)  { .tl-photo-strip { min-height: 84px; } }
@media (min-width: 1200px) { .tl-photo-strip { min-height: 109px; } }
/* M69.1/.3: portrait reserves a right column for the fixed scrubber rail; the
   photos/dates start to its left. M69.3 tightens the margins so the 3-up photo
   grid fills almost the whole width (small gap from the left edge + the rail). */
@media (max-width: 768px) and (orientation: portrait) {
  main#app:has(.tl-page) { padding-left: 6px; padding-right: 0; }
  .tl-page { padding-right: 28px; }       /* clears the rail (right:4 + 22) with a small gap (#5) */
  .tl-feed { padding: var(--space-2) 0 0; }
  .tl-photo-strip {
    display: grid;
    grid-template-columns: repeat(3, 1fr);  /* 3 per line, filling the width (#5) */
    gap: 3px;
  }
  .tl-album-tag { grid-column: 1 / -1; }
  .tl-thumb { width: 100%; height: auto; aspect-ratio: 4 / 3; }
}

/* Slim header — shared across screens */
.slim-header {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--space-3);
  background: color-mix(in srgb, var(--bg) 85%, var(--surface));
  border-bottom: 1px solid var(--divider);
  padding: var(--space-2) var(--space-3);
}
.slim-title-wrap { min-width: 0; }
.slim-title { font-size: var(--type-h1); font-weight: 700; margin: 0; min-width: 0; overflow-wrap: anywhere; }
.slim-sub { font-size: var(--type-small); font-weight: 300; color: var(--text-muted); margin-inline-start: var(--space-2); }
.slim-back { display: block; font-size: var(--type-small); color: var(--accent-dim); text-decoration: none; }
.slim-actions { display: flex; gap: var(--space-2); align-items: center; }
.nav-icon { vertical-align: -0.12em; }

/* Home — fit all 7 on one screen */
.home-header { /* slim; shares .slim-header */ }
.home-fit {
  height: calc(100svh - 3rem);  /* minus the slim header */
  overflow: hidden;
  display: flex; flex-direction: column;
  padding: var(--space-1); gap: var(--space-1);
}
/* The trip's 4 parts (np·in / vn·cn / au·nz / th); each part is a row of tiles. */
.home-part { display: flex; gap: var(--space-1); min-width: 0; min-height: 0; }
.home-part .country-tile { flex: 1; }

.country-tile {
  flex: 1; position: relative; min-width: 0; border-radius: 6px; overflow: hidden;
  background-size: cover; background-position: center; text-decoration: none;
  display: block;
}
.country-tile-scrim { position: absolute; inset: 0; background: linear-gradient(0deg, rgba(20,18,15,.62), rgba(20,18,15,0) 58%); }
.country-tile-name { position: absolute; bottom: var(--space-2); inset-inline-start: var(--space-2); color: #fff; font-weight: 700; font-size: var(--type-h2); text-shadow: 0 1px 4px rgba(0,0,0,.6); z-index: 2; transition: bottom .15s ease; }
.country-tile-count { position: absolute; bottom: var(--space-2); inset-inline-start: var(--space-2); color: #fff; font-size: var(--type-small); font-weight: 300; text-shadow: 0 1px 4px rgba(0,0,0,.6); z-index: 2; opacity: 0; transition: opacity .15s; }
/* on hover the count fades in at the bottom and the name lifts ~one line up so they never collide */
.country-tile:hover .country-tile-name, .country-tile:focus-within .country-tile-name { bottom: calc(var(--space-2) + 1.35em); }
.country-tile:hover .country-tile-count, .country-tile:focus-within .country-tile-count { opacity: .95; }

/* default (phone portrait): show the phone stack, hide the desktop grid */
[data-layers="desktop"] { display: none; }
[data-layers="phone"] { display: flex; }
.home-parts[data-layers="phone"] { flex: 1; flex-direction: column; gap: var(--space-1); min-height: 0; }
.home-parts[data-layers="phone"] .home-part { flex: 1; }
/* desktop + landscape phone (wide): show the 2x2 parts grid, hide the phone stack */
@media (min-width: 769px), (orientation: landscape) {
  [data-layers="phone"] { display: none; }
  .home-parts[data-layers="desktop"] {
    display: grid; flex: 1 1 auto; min-height: 0;
    grid-template-columns: 1fr 1fr; grid-template-rows: 1fr 1fr; gap: var(--space-2);
  }
  .home-parts[data-layers="desktop"] .home-part { min-height: 0; }
}
/* nav: icon+label pills; phone shows a compact row */
.slim-nav { display: inline-flex; align-items: center; gap: .3em; font-size: var(--type-small); color: var(--accent-dim); text-decoration: none; background: var(--surface); border: 1px solid var(--divider); border-radius: 16px; padding: .25em .7em; white-space: nowrap; }
.slim-toggle { cursor: pointer; }
.slim-toggle .nav-icon:last-child { display: none; }       /* show moon in light */
[data-theme="dark"] .slim-toggle .nav-icon:first-child { display: none; }
[data-theme="dark"] .slim-toggle .nav-icon:last-child { display: inline; } /* sun in dark */
@media (max-width: 768px) and (orientation: portrait) {
  .home-header { flex-direction: column; align-items: stretch; gap: var(--space-1); }
  .slim-actions { justify-content: space-between; }
  .slim-nav { flex: 1; justify-content: center; padding: .35em .2em; }
  .nav-long { display: none; }  /* phone: short labels so 4 fit one row */
  [data-layers="desktop"] { display: none; }  /* keep desktop set hidden in portrait (explicit, after the wide query so the guard test matches) */
  [data-layers="phone"] { display: flex; }
  /* Sub-screen slim headers (country/album): drop the count·dates to its own
     line under the title so the header never forces horizontal overflow (#3). */
  /* Sub-screen slim headers (country/album): the count·dates sub drops to its
     own line under the title, kept to exactly ONE line (no wrap). On the album
     header, portrait shows the date span only — the photo count (.sub-count,
     which carries the trailing " · ") is hidden; landscape/desktop keep it. */
  .slim-sub { display: block; margin-inline-start: 0; white-space: nowrap; font-size: var(--type-small); }
  .sub-count { display: none; }
}
/* Home no-scroll fit — escape main#app's page padding + 64rem max-width so the
   7 tiles fill the viewport edge-to-edge. The header is flex:0 (natural height),
   the fit flex:1, so the fill is robust to the taller phone-portrait header
   without a magic calc() offset (the base .home-fit calc is the no-:has fallback). */
main#app:has(.home-fit) {
  padding: 0; max-width: none; height: 100svh; overflow: hidden;
  display: flex; flex-direction: column;
}
main#app:has(.home-fit) .home-header { margin: 0; flex: 0 0 auto; }
main#app:has(.home-fit) .home-fit { flex: 1 1 auto; height: auto; }


/* Country page — featured-first overlay album grid (M3).
   Escapes main#app's page padding/max-width so the grid + slim header run
   edge-to-edge; the page scrolls normally (no fixed height). */
main#app:has(.country-page) { padding: 0; max-width: none; }
.country-page {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--space-2);
  padding: var(--space-3);
}
@media (min-width: 769px) {
  .country-page { grid-template-columns: repeat(3, 1fr); }
  /* Wide/short screens (desktop + phone-landscape): the first album is just a
     normal 3-col cell so several albums show above the fold without scrolling.
     The full-width 21/9 featured banner is kept only on tall phone-portrait.
     Two-class selector so it beats the base .album-tile-featured rule that
     follows it in source order (media queries add no specificity). */
  .country-page .album-tile-featured { grid-column: auto; aspect-ratio: 4 / 3; }
}
.album-tile {
  position: relative; display: block; min-width: 0;
  aspect-ratio: 4 / 3; border-radius: 6px; overflow: hidden;
  background: var(--divider); text-decoration: none;
}
.album-tile-featured { grid-column: 1 / -1; aspect-ratio: 21 / 9; }
.album-tile-img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.album-tile-scrim { position: absolute; inset: 0; background: linear-gradient(0deg, rgba(20,18,15,.66), rgba(20,18,15,0) 55%); }
/* Name + sub stack in one bottom-anchored flex column so a long sub (count·dates)
   that wraps to two lines never collides with the name — the column just grows
   upward and the name stays on top (M65.2 fix). */
.album-tile-label { position: absolute; bottom: var(--space-2); inset-inline-start: var(--space-3); inset-inline-end: var(--space-3); z-index: 2; display: flex; flex-direction: column; gap: 1px; }
.album-tile-name { color: #fff; font-weight: 700; font-size: var(--type-h2); text-shadow: 0 1px 4px rgba(0,0,0,.6); }
.album-tile-sub { color: #fff; font-size: var(--type-small); font-weight: 300; text-shadow: 0 1px 4px rgba(0,0,0,.6); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
@media (max-width: 768px) {
  .album-tile-name { font-size: var(--type-body); }
}
