/* ─── page-level: pages/homepage.html (sha=73fd2fe) ─── */
/* Wide-screen knob (#20) — single source for the outer-frame cap on
   this composed page. Every section frame uses max-width:
   var(--tenki-max, 1400px); change this one value to re-cap the whole
   page. Long reading columns stay narrow (they don't use this token). */
:root { --tenki-max: 1400px; }

/* 2026-06-06: fixed the hero "Tenki for born" card clipping its heading on
   short / browser-zoomed viewports — the cap (78vh) could fall below the card
   stack. Real fix is a min-height floor in hero/hero.html (NOT the wide-screen
   token above, which wasn't the cause). This note also advances the homepage
   shell SHA so the ?v= cache-bust picks up the rebuilt bundle. */

/* ────────────────────────────────────────────────────────────────────
   Page-level styles for #tenki-page-homepage.

   This block ONLY contains rules that need to be at the PAGE level —
   i.e. the page wrapper, the page-level build chip, and inter-section
   spacing.  Section-specific styles live in each section's own file
   and get concatenated into dist/homepage.css after this block.

   The cascade therefore looks like:
     1. these page-level rules
     2. hero's CSS  (from hero/hero.html)
     3. meaning's CSS
     4. pillars's CSS
     5. timeline's CSS
     6. social's CSS
   Sections style their own scope with prefixed class names
   (.tenki-hero-*, .tenki-meaning-*, .dashboard-*, .tenki-social-*, etc.)
   so concatenation doesn't leak between them. */

#tenki-page-homepage {
  position: relative;
  /* We control the entire vertical rhythm now — no SQS section padding
     to fight.  The single Code Block that holds this composed shell
     should still respect the SQS page's outer margins, but we own
     everything inside. */

  /* Reveal-on-CSS-loaded.  The inline <style> at the top of the shell
     starts the wrapper at opacity:0 so the wall-of-text flash never
     happens before the CDN bundle lands.  Because this CDN bundle is
     loaded AFTER that inline style, the cascade picks this rule by
     source order + the same selector wins — flipping opacity to 1 and
     fading the page in over the inline transition (0.35 s). */
  opacity: 1;
}
/* Dismiss the boot splash the instant this bundle's CSS applies — pairs with the
   inline .tenki-boot-loader in the shell <head>, so the success path needs no JS.
   (The 10 s inline failsafe also clears it if the CDN never responds.) */
.tenki-boot-loader { display: none !important; }
/* Don't animate the section reveals individually until the page
   wrapper itself has finished fading in — otherwise the first
   section "races" the wrapper and looks jittery on slow connections.
   The reveal IntersectionObserver still fires, but the transition
   inherits the wrapper's eased ramp. */

/* Page-level build chip — same look as the per-section chips so it's
   visually consistent. */
#tenki-page-homepage .tenki-page-build-chip {
  position: absolute; top: 8px; right: 12px;
  font: 600 10px/1 monospace; padding: 3px 8px; border-radius: 4px;
  background: #1A1A1A; color: #fff; opacity: .85;
  display: none; pointer-events: none; z-index: 10000;
}
#tenki-page-homepage[data-debug="1"] .tenki-page-build-chip { display: block; }

/* Inter-section vertical rhythm.  We're free to pick whatever spacing
   reads best now that SQS isn't padding between us. */
#tenki-page-homepage > * + * { margin-top: 0; }
/* Specific overrides if a particular section needs more / less air: */
/* Meaning section keeps its OWN margin-top — its CSS pulls it UP via
   negative margin (~ -240 px) so the glass card overlays the bottom-
   right of the hero photo.  Don't override that here. */
/* #tenki-page-homepage .tenki-meaning-container { ... } */
#tenki-page-homepage .tenki-pillars-container         { margin-top: 32px; }
#tenki-page-homepage .dashboard-container             { margin-top: 32px; }
#tenki-page-homepage .tenki-funnel-container          { margin-top: 32px; }
#tenki-page-homepage .tenki-social-parallax-section   { margin-top: 24px; }
#tenki-page-homepage .tenki-newsletter-section        { margin-top: 0; }
/* Footer is NOT composed into this shell — it lives in the global
   SQS footer (one paste, every page).  See footer/footer.html for
   the source + dist/footer.shell.html for the paste payload. */

/* ── Section reveal animation ─────────────────────────────────────
   Every major composed section starts invisible + translated down
   8 px; when it scrolls into view, IntersectionObserver flips a
   `.is-revealed` class which slides + fades it into place.  This
   masks the staggered shell-then-CDN-then-API content cascade so
   the page reads as a deliberate sequence rather than a clunky
   pop-in flurry.

   .respect-motion exempts users with prefers-reduced-motion. */
#tenki-page-homepage .tenki-pillars-container,
#tenki-page-homepage .dashboard-container,
#tenki-page-homepage .tenki-funnel-container,
#tenki-page-homepage .tenki-social-parallax-section,
#tenki-page-homepage .tenki-newsletter-section,
#tenki-page-homepage .tenki-meaning-container {
  opacity: 0;
  transform: translateY(12px);
  transition: opacity 0.7s cubic-bezier(0.22, 0.61, 0.36, 1),
              transform 0.7s cubic-bezier(0.22, 0.61, 0.36, 1);
  will-change: opacity, transform;
}
#tenki-page-homepage .tenki-pillars-container.is-revealed,
#tenki-page-homepage .dashboard-container.is-revealed,
#tenki-page-homepage .tenki-funnel-container.is-revealed,
#tenki-page-homepage .tenki-social-parallax-section.is-revealed,
#tenki-page-homepage .tenki-newsletter-section.is-revealed,
#tenki-page-homepage .tenki-meaning-container.is-revealed {
  opacity: 1;
  transform: none;
}
@media (prefers-reduced-motion: reduce) {
  #tenki-page-homepage .tenki-pillars-container,
  #tenki-page-homepage .dashboard-container,
  #tenki-page-homepage .tenki-funnel-container,
  #tenki-page-homepage .tenki-social-parallax-section,
  #tenki-page-homepage .tenki-newsletter-section,
  #tenki-page-homepage .tenki-meaning-container {
    opacity: 1;
    transform: none;
    transition: none;
  }
}

/* Hide the per-section build chips when composed — only the page-level
   chip should be visible to avoid stacking ~5 chips in the same spot.
   Per-section chips can still be inspected by removing `display: none`
   from devtools. */
#tenki-page-homepage .tenki-hero-build-chip,
#tenki-page-homepage .tenki-meaning-build-chip,
#tenki-page-homepage .tenki-pillars-build-chip,
#tenki-page-homepage .tenki-build-chip,
#tenki-page-homepage .tenki-funnel-build-chip,
#tenki-page-homepage .tenki-social-build-chip,
#tenki-page-homepage .tenki-newsletter-build-chip {
  display: none !important;
}

/* ─── hero: hero/hero.html (sha=3a638ed) ─── */
/* Tenki Hero Section
     Full-bleed (escapes Squarespace's container max-width via 100vw +
     margin-left:-50vw trick) photo with an overlay card on the right.
     CSS scoped via the .tenki-hero class prefix; no globals affected. */
  .tenki-hero {
    --hero-text:  #ffffff;
    --hero-shadow: 0 4px 18px rgba(0, 0, 0, 0.35);
    --hero-cta-bg:    #ffffff;
    --hero-cta-text:  #1A1A1A;
    --hero-cta-shadow: 0 6px 18px rgba(0, 0, 0, 0.18);

    font-family: 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
    position: relative;
    width: 100vw;
    /* Full-bleed horizontal + flush against the nav bar above.
       Squarespace section wrappers add their own vertical padding
       (typically 17 px top / 17 px bottom).  We compensate by
       PULLING UP with a negative top margin equal to that padding
       so the hero sits visually right against the nav.  Some SQS
       templates use a larger top pad; if there's still a gap on
       your specific page, either bump this -68px to -90px / -110px
       OR enable the .sqs-block-code:has() override below. */
    /* Full-bleed via calc margins — robust to SQS's padded content column.
       The old left:50%/right:50% relative offset miscalculated there and
       clipped content on the right on mobile. */
    margin: -68px 0 0;
    margin-left: calc(50% - 50vw);
    margin-right: calc(50% - 50vw);
    /* Aspect ratio matched to the source SQS hero: roughly 16:7 on
       desktop, taller on mobile so the photo doesn't compress.  The
       photo is set as a background-image inside `.tenki-hero-image` so
       background-position can be tuned without changing the markup. */
    aspect-ratio: 16 / 7;
    min-height: 320px;
    max-height: 78vh;
    overflow: hidden;
    isolation: isolate;
    z-index: 1;
    box-sizing: border-box;
  }
  /* Floor the hero height so the meaning-card stack (shown ≥641px) is never
     clipped by the 78vh / 70vh max-height cap on short or zoomed-in viewports.
     min-height wins over max-height when they conflict, so on a short window
     the hero grows to fit the card instead of cropping its heading. Only binds
     when the aspect-driven height would fall below the content — wide screens
     keep their taller aspect height. (<641px the card hides → mobile uses the
     standalone meaning section, so no floor needed there.) */
  @media (min-width: 641px) {
    .tenki-hero { min-height: 640px; }
  }
  .tenki-hero *,
  .tenki-hero *::before,
  .tenki-hero *::after { box-sizing: border-box; }

  /* The photo layer — fills the entire hero, behind the overlay card */
  .tenki-hero-image {
    position: absolute;
    inset: 0;
    z-index: 1;
    background-position: center 32%;   /* bias slightly UP so faces stay in frame on wide viewports */
    background-size: cover;
    background-repeat: no-repeat;
    /* Fallback colour while the photo is loading — deep Tenki blue so
       an unloaded hero reads as a deliberate dark panel rather than
       blank whitespace under floating headline text.  Replaced by the
       photo as soon as it arrives. */
    background-color: #00243f;
  }

  /* Hide the headline + meaning card until the hero photo has loaded
     (JS adds .is-hero-loaded on the hero root when the Image() preloader
     fires onload).  Until then the deep-blue fallback shows alone — no
     orphan text on a blank panel.  3-second failsafe in the JS guarantees
     the overlay reveals even if the photo can't load (offline / CDN
     hiccup) so we never trap the visitor on a faceless hero. */
  .tenki-hero .tenki-hero-overlay {
    opacity: 0;
    transition: opacity 0.45s ease-out;
  }
  .tenki-hero.is-hero-loaded .tenki-hero-overlay { opacity: 1; }
  @media (prefers-reduced-motion: reduce) {
    .tenki-hero .tenki-hero-overlay { transition: none; }
  }
  /* Soft right-side vignette that boosts headline contrast without
     darkening the whole image.  Adjusts per .data-align variant below. */
  .tenki-hero[data-align="right"] .tenki-hero-image::after {
    content: '';
    position: absolute;
    inset: 0;
    background: linear-gradient(to left,
                rgba(0, 0, 0, 0.45) 0%,
                rgba(0, 0, 0, 0.30) 25%,
                rgba(0, 0, 0, 0.08) 55%,
                rgba(0, 0, 0, 0)    80%);
    pointer-events: none;
  }
  .tenki-hero[data-align="center"] .tenki-hero-image::after {
    content: '';
    position: absolute;
    inset: 0;
    background: linear-gradient(to bottom,
                rgba(0, 0, 0, 0)    0%,
                rgba(0, 0, 0, 0.18) 50%,
                rgba(0, 0, 0, 0.55) 100%);
    pointer-events: none;
  }
  .tenki-hero[data-align="left"] .tenki-hero-image::after {
    content: '';
    position: absolute;
    inset: 0;
    background: linear-gradient(to right,
                rgba(0, 0, 0, 0.45) 0%,
                rgba(0, 0, 0, 0.30) 25%,
                rgba(0, 0, 0, 0.08) 55%,
                rgba(0, 0, 0, 0)    80%);
    pointer-events: none;
  }

  /* Overlay container — positions the card per data-align */
  .tenki-hero-overlay {
    position: absolute;
    inset: 0;
    z-index: 2;
    display: flex;
    align-items: center;
    padding: 5%;
    pointer-events: none;
  }
  .tenki-hero[data-align="right"]  .tenki-hero-overlay { justify-content: flex-end; }
  .tenki-hero[data-align="center"] .tenki-hero-overlay { justify-content: center; align-items: flex-end; padding-bottom: 9%; }
  .tenki-hero[data-align="left"]   .tenki-hero-overlay { justify-content: flex-start; }

  /* Stack wrapper — meaning card sits ABOVE the headline+CTA on the
     right side.  align-items: flex-end keeps both children right-
     aligned (matches the data-align="right" pattern). */
  .tenki-hero-stack {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 24px;
    pointer-events: auto;
    max-width: 560px;
  }

  /* The "Tenki for born" glass card overlay.  Translucent white +
     backdrop-filter blur reads as layered over the photo without
     obscuring it.  Higher opacity (0.92 vs prev 0.84) so the body
     text is comfortably readable against the busy photo behind.
     Hover lift + soft shadow growth matches the bounce animation
     the rest of the site's cards use (pillars, deep-dive, etc.),
     inviting desktop users to engage with it. */
  .tenki-hero-meaning {
    width: 100%;
    max-width: 500px;
    padding: 26px 32px;
    background-color: rgba(255, 255, 255, 0.96);   /* nearly opaque — body text fully legible */
    backdrop-filter: blur(18px) saturate(140%);
    -webkit-backdrop-filter: blur(18px) saturate(140%);
    border-radius: 14px;
    border-left: 5px solid #005A9C;
    box-shadow: 0 14px 36px rgba(0, 0, 0, 0.32),
                0 0 0 1px rgba(255, 255, 255, 0.6) inset;
    text-align: left;
    color: #111;
    transition: transform 0.28s ease, box-shadow 0.28s ease;
    cursor: default;
    animation: tenkiHeroMeaningIn 0.7s ease-out 0.15s both;
  }
  .tenki-hero-meaning:hover {
    transform: translateY(-4px);
    box-shadow: 0 22px 48px rgba(0, 0, 0, 0.36),
                0 0 0 1px rgba(255, 255, 255, 0.65) inset;
  }
  @keyframes tenkiHeroMeaningIn {
    from { opacity: 0; transform: translateY(8px); }
    to   { opacity: 1; transform: translateY(0); }
  }
  .tenki-hero-meaning-title {
    margin: 0 0 6px 0;
    color: #005A9C;
    font-size: 1.6rem;          /* was 1.4 — bigger, more confident */
    font-weight: 800;
    text-transform: uppercase;
    letter-spacing: 1.2px;
  }
  .tenki-hero-meaning-subtitle {
    margin: 0 0 14px 0;
    color: #111;
    font-size: 1.1rem;          /* was 1.0 — more readable italic */
    font-weight: 500;
    font-style: italic;
  }
  .tenki-hero-meaning-divider {
    width: 48px;
    height: 3px;
    background-color: #005A9C;
    border-radius: 2px;
    margin-bottom: 14px;
  }
  .tenki-hero-meaning-text {
    margin: 0;
    color: #1a1a1a;             /* darker for higher contrast */
    font-size: 1.02rem;         /* was 0.92 — comfortable reading */
    line-height: 1.6;
    font-weight: 500;
  }
  .tenki-hero-meaning-text strong { color: #000; font-weight: 800; }

  /* The card — headline + CTA stacked.  Transparent background to keep
     the photo behind it visible; text + shadow do the lift.
     Gentle fade-in so it appears in sync with the meaning card above
     (reduces the staggered "stuff popping in" load feel). */
  .tenki-hero-card {
    max-width: 560px;
    color: var(--hero-text);
    text-align: right;
    pointer-events: auto;
    animation: tenkiHeroCardIn 0.8s ease-out 0.35s both;
  }
  @keyframes tenkiHeroCardIn {
    from { opacity: 0; transform: translateY(6px); }
    to   { opacity: 1; transform: translateY(0); }
  }
  .tenki-hero[data-align="center"] .tenki-hero-card { text-align: center; }
  .tenki-hero[data-align="left"]   .tenki-hero-card { text-align: left;  }

  .tenki-hero-headline {
    margin: 0 0 28px 0;
    font-size: clamp(1.6rem, 3.6vw, 3rem);
    font-weight: 400;
    line-height: 1.18;
    letter-spacing: 0.2px;
    color: var(--hero-text);
    text-shadow: var(--hero-shadow);
    /* Allow the headline to wrap naturally to 2-3 lines on most viewports */
    text-wrap: balance;
  }
  .tenki-hero-headline strong,
  .tenki-hero-headline em {
    font-weight: 700;
    font-style: normal;
  }

  .tenki-hero-cta {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 14px 32px;
    background: var(--hero-cta-bg);
    color: var(--hero-cta-text);
    text-decoration: none;
    border-radius: 4px;
    font-weight: 600;
    font-size: clamp(0.92rem, 1.4vw, 1.05rem);
    letter-spacing: 0.4px;
    box-shadow: var(--hero-cta-shadow);
    transition: transform 0.2s ease, box-shadow 0.2s ease, background 0.2s ease;
    -webkit-tap-highlight-color: transparent;
  }
  .tenki-hero-cta:hover,
  .tenki-hero-cta:focus-visible {
    transform: translateY(-2px);
    box-shadow: 0 10px 26px rgba(0, 0, 0, 0.26);
    background: #f8fafc;
    outline: none;
  }
  .tenki-hero-cta:active {
    transform: translateY(0);
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.20);
  }

  /* Build chip — only visible with ?debug=1 (toggled via .show-build) */
  .tenki-hero-build-chip {
    position: absolute;
    top: 10px;
    right: 12px;
    z-index: 5;
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 10px;
    color: #fff;
    background: rgba(0, 90, 156, 0.85);
    padding: 3px 8px;
    border-radius: 10px;
    letter-spacing: 0.3px;
    display: none;
  }
  .tenki-hero.show-build .tenki-hero-build-chip { display: inline-block; }

  /* Responsive — narrower viewports get a taller hero + overlay shifts
     to bottom for thumb-friendly button placement.  Below 640 px the
     headline gets a darker bottom gradient so it stays legible against
     the body of the photo. */
  @media (max-width: 960px) {
    .tenki-hero {
      aspect-ratio: 4 / 3;
      max-height: 70vh;
    }
    .tenki-hero[data-align="right"] .tenki-hero-overlay,
    .tenki-hero[data-align="left"]  .tenki-hero-overlay {
      align-items: flex-end;
      padding-bottom: 8%;
    }
    .tenki-hero-card { text-align: right; }
  }
  @media (max-width: 640px) {
    .tenki-hero {
      aspect-ratio: 3 / 4;     /* tall portrait on phone */
      max-height: 80vh;
    }
    /* Phone-portrait hero is too tall + narrow to host both the
       meaning card AND the headline overlay — hide the meaning card
       (it still renders below via the standalone meaning section in
       the page composer, which mobile shows in-flow). */
    .tenki-hero-meaning { display: none; }
    .tenki-hero-stack { gap: 0; }
    .tenki-hero-image::after,
    .tenki-hero[data-align="right"] .tenki-hero-image::after,
    .tenki-hero[data-align="left"]  .tenki-hero-image::after {
      background: linear-gradient(to bottom,
                  rgba(0, 0, 0, 0)    35%,
                  rgba(0, 0, 0, 0.35) 65%,
                  rgba(0, 0, 0, 0.70) 100%) !important;
    }
    .tenki-hero-overlay {
      padding: 6%;
      align-items: flex-end;
      justify-content: center !important;
    }
    .tenki-hero-card {
      text-align: center !important;
      max-width: 100%;
    }
    .tenki-hero-cta { padding: 12px 28px; }
  }

/* ─── meaning: meaning/meaning.html (sha=de3426e) ─── */
.tenki-meaning-container {
    --tenki-blue:  #005A9C;
    --tenki-black: #1A1A1A;
    --tenki-white: #FFFFFF;
    --text-light:  #333333;

    font-family: 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
    /* This standalone .tenki-meaning-container is now MOBILE-ONLY for
       the homepage — desktop carries the meaning card inline INSIDE
       the hero (see hero/hero.html, .tenki-hero-meaning).  This
       version still ships in the page composer so phones (where the
       hero is portrait + can't host an overlay card) see the
       meaning content as a normal in-flow card below the hero. */
    max-width: 800px;
    margin: 16px auto 24px;
    background-color: var(--tenki-white);
    border-radius: 16px;
    padding: 34px 28px;
    box-shadow: 0 10px 40px rgba(0, 90, 156, 0.08);
    border-left: 8px solid var(--tenki-blue);
    position: relative;
    overflow: hidden;
    box-sizing: border-box;
  }
  /* Desktop: hide the standalone in-flow meaning card — its content
     now lives INSIDE the hero (see .tenki-hero-meaning in hero.html).
     Showing both would be duplicate content. */
  @media (min-width: 769px) {
    .tenki-meaning-container { display: none; }
  }
  .tenki-meaning-container *,
  .tenki-meaning-container *::before,
  .tenki-meaning-container *::after { box-sizing: border-box; }

  /* Decorative oversized quote mark behind the content */
  .tenki-meaning-container::before {
    content: '"';
    position: absolute;
    top: -20px;
    left: 30px;
    font-size: 150px;
    color: rgba(0, 90, 156, 0.05);
    font-family: Georgia, serif;
    line-height: 1;
    z-index: 0;
  }

  .tenki-meaning-content {
    position: relative;
    z-index: 1;
  }

  .tenki-meaning-title {
    color: var(--tenki-blue);
    font-size: 1.55rem;
    font-weight: 800;
    margin: 0 0 4px 0;
    text-transform: uppercase;
    letter-spacing: 1px;
  }
  .tenki-meaning-subtitle {
    color: var(--tenki-black);
    font-size: 1rem;
    font-weight: 400;
    font-style: italic;
    margin: 0 0 14px 0;
  }
  .tenki-meaning-divider {
    width: 48px;
    height: 3px;
    background-color: var(--tenki-blue);
    border-radius: 2px;
    margin-bottom: 14px;
  }
  .tenki-meaning-text {
    color: var(--text-light);
    font-size: 0.92rem;
    line-height: 1.55;
    margin: 0;
  }
  .tenki-meaning-text strong {
    color: var(--tenki-black);
    font-weight: 700;
  }
  .tenki-meaning-text em {
    font-style: italic;
  }

  /* Build chip — visible only with ?debug=1 */
  .tenki-meaning-build-chip {
    position: absolute;
    top: 10px;
    right: 12px;
    z-index: 5;
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 10px;
    color: #fff;
    background: rgba(0, 90, 156, 0.85);
    padding: 3px 8px;
    border-radius: 10px;
    letter-spacing: 0.3px;
    display: none;
  }
  .tenki-meaning-container.show-build .tenki-meaning-build-chip { display: inline-block; }

  @media (max-width: 768px) {
    /* Mobile: revert to a normal in-flow card BELOW the hero — the
       floating-glass overlay pattern doesn't make sense on a 390 px
       phone screen.  No backdrop-filter (perf hit on mobile + the
       card no longer floats over a photo).  Restore generous
       in-flow margin. */
    .tenki-meaning-container {
      max-width: 100%;
      padding: 28px 22px;
      margin: 16px 16px 24px;
      background-color: var(--tenki-white);
      backdrop-filter: none;
      -webkit-backdrop-filter: none;
      box-shadow: 0 8px 24px rgba(0, 90, 156, 0.10);
    }
    .tenki-meaning-title    { font-size: 1.55rem; }
    .tenki-meaning-subtitle { font-size: 1rem; }
    .tenki-meaning-text     { font-size: 0.95rem; line-height: 1.6; }
    .tenki-meaning-container::before {
      left: 15px;
      font-size: 120px;
    }
  }

/* ─── pillars: pillars/pillars.html (sha=70b181f) ─── */
:root {
    --tenki-blue:  #005A9C;
    --tenki-green: #008C45;
    --tenki-black: #1A1A1A;
    --tenki-white: #FFFFFF;
    /* White-theme accents — matches deepdive-page.html's theme-white palette
       so the SOS pillar card on the homepage visually rhymes with the
       deep-dive page it links to.  Dark glyph + dashed cream-stroke accents
       (white-on-white would be invisible). */
    --tenki-white-dark:   #2A2A2A;
    --tenki-white-cream:  #FAF6EE;
    --tenki-white-stroke: #C0C5CC;
    --bg-light:    #F8F9FA;
    --text-dark:   #222222;
    --text-light:  #555555;
  }

  body { font-family: 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
         background-color: var(--tenki-white); margin: 0; padding: 20px; box-sizing: border-box; }
  *, *::before, *::after { box-sizing: inherit; }

  .infographic-container { max-width: var(--tenki-max, 1400px); margin: 0 auto;
                           background-color: var(--bg-light); border-radius: 16px;
                           padding: 40px; box-shadow: 0 10px 30px rgba(0,0,0,.05); }

  .infographic-header { text-align: center; margin-bottom: 50px; }
  .infographic-header h2 { color: var(--tenki-black); font-size: 2.5rem;
                           margin: 0 0 15px; text-transform: uppercase;
                           letter-spacing: 1px; line-height: 1.2; }
  .infographic-header p { color: var(--text-light); font-size: 1.2rem;
                          max-width: 800px; margin: 0 auto; line-height: 1.6; }

  /* Loader / error */
  #loading-spinner { text-align: center; padding: 50px;
                     color: var(--tenki-blue); font-weight: bold; font-size: 1.2rem; }
  #loading-spinner.error { color: #b91c1c; }

  .pillars-wrapper { display: none;
                     grid-template-columns: repeat(auto-fit, minmax(min(100%, 320px), 1fr));
                     gap: 30px; align-items: start; }

  .pillar-card { background-color: var(--tenki-white); border-radius: 12px;
                 padding: 30px; border-top: 6px solid;
                 display: flex; flex-direction: column;
                 position: relative; cursor: pointer;  /* whole card is clickable */
                 transition: transform .4s cubic-bezier(0.175, 0.885, 0.32, 1.275),
                             box-shadow .4s ease, outline-color .2s ease; }
  .pillar-card:hover { transform: translateY(-4px);
                       box-shadow: 0 12px 30px rgba(0,0,0,.08); }
  .pillar-card:focus-visible { outline: 3px solid var(--tenki-blue); outline-offset: 4px; }
  /* Subtle chevron in the top-right indicates the card expands */
  .pillar-chevron { position: absolute; top: 18px; right: 18px;
                    width: 28px; height: 28px; border-radius: 50%;
                    display: flex; align-items: center; justify-content: center;
                    font-size: 14px; color: #888; background: rgba(0,0,0,.04);
                    transition: transform .35s ease, background .2s ease, color .2s ease;
                    pointer-events: none; /* clicks pass through to the card */ }
  .pillar-card:hover .pillar-chevron { background: rgba(0,0,0,.08); color: #444; }
  .pillar-card.is-expanded .pillar-chevron { transform: rotate(180deg); color: #444; }
  /* Subtle "click to expand" hint that fades out on hover */
  .pillar-click-hint { font-size: 10px; color: #999; text-align: center;
                       margin: 10px 0 -6px; letter-spacing: .5px;
                       text-transform: uppercase; font-weight: 600;
                       transition: opacity .2s ease; }
  .pillar-card.is-expanded .pillar-click-hint { opacity: 0; }
  .pillar-card:hover .pillar-click-hint { color: #555; }

  /* ── Smooth drawer using grid-template-rows: 0fr→1fr (no display:none hacks) ── */
  .pillar-expanded-drawer { display: grid; grid-template-rows: 0fr;
                            transition: grid-template-rows .4s ease, opacity .35s ease;
                            opacity: 0; margin-top: 0; }
  .pillar-expanded-drawer > .drawer-inner { overflow: hidden; min-height: 0; }
  .pillar-card.is-expanded .pillar-expanded-drawer {
    grid-template-rows: 1fr; opacity: 1;
    margin-top: 15px; border-top: 1px dashed #EAEAEA; padding-top: 20px;
  }

  /* Pillar themes */
  .card-blue  { border-top-color: var(--tenki-blue);
                background: linear-gradient(180deg, rgba(0,90,156,.04) 0%, rgba(255,255,255,1) 220px); }
  .card-blue .icon-wrapper       { background-color: var(--tenki-blue); }
  .card-blue .section-title      { color: var(--tenki-blue); }
  .card-blue .program-list li::before { color: var(--tenki-blue); }
  .card-blue .learn-more-btn     { background-color: var(--tenki-blue); color: var(--tenki-white); }
  .card-blue .learn-more-btn:hover { background-color: #004578; }
  .card-blue .explore-toggle-btn { background-color: #F0F4F8; color: var(--tenki-blue); }
  .card-blue .explore-toggle-btn:hover { background-color: #E1EBF5; }

  .card-green { border-top-color: var(--tenki-green);
                background: linear-gradient(180deg, rgba(0,140,69,.04) 0%, rgba(255,255,255,1) 220px); }
  .card-green .icon-wrapper       { background-color: var(--tenki-green); }
  .card-green .section-title      { color: var(--tenki-green); }
  .card-green .program-list li::before { color: var(--tenki-green); }
  .card-green .learn-more-btn     { background-color: var(--tenki-green); color: var(--tenki-white); }
  .card-green .learn-more-btn:hover { background-color: #006B34; }
  .card-green .explore-toggle-btn { background-color: #E8F5E9; color: var(--tenki-green); }
  .card-green .explore-toggle-btn:hover { background-color: #C8E6C9; }

  /* White theme — mirrors deepdive-page.html's theme-white palette so
     the SOS pillar card visually rhymes with its deep-dive landing page.
     Dashed cream-stroke top border, dark glyph on dark icon-wrapper
     (white-on-white would be invisible), dark button bg with white text. */
  .card-white { border-top: 6px dashed var(--tenki-white-stroke);
                background-color: #FDFCF8; }
  .card-white .icon-wrapper       { background-color: var(--tenki-white-dark); }
  .card-white .section-title      { color: var(--tenki-white-dark); }
  .card-white .program-list li::before { color: var(--tenki-white-dark); }
  .card-white .learn-more-btn     { background-color: var(--tenki-white-dark); color: var(--tenki-white); }
  .card-white .learn-more-btn:hover { background-color: #111; }
  .card-white .explore-toggle-btn { background-color: var(--tenki-white-cream); color: var(--tenki-white-dark); }
  .card-white .explore-toggle-btn:hover { background-color: #EFEAD8; }

  .card-black { border-top: 6px dashed var(--tenki-black);
                background: linear-gradient(180deg, rgba(26,26,26,.03) 0%, rgba(255,255,255,1) 220px); }
  .card-black .icon-wrapper       { background-color: var(--tenki-black); }
  .card-black .section-title      { color: var(--tenki-black); }
  .card-black .program-list li::before { color: var(--tenki-black); }
  .card-black .learn-more-btn     { background-color: var(--tenki-black); color: var(--tenki-white); }
  .card-black .learn-more-btn:hover { background-color: #333; }
  .card-black .explore-toggle-btn { background-color: #EEEEEE; color: var(--tenki-black); }
  .card-black .explore-toggle-btn:hover { background-color: #DDDDDD; }

  .card-header-flex { display: flex; justify-content: space-between;
                      align-items: center; min-height: 80px;
                      margin-bottom: 25px; gap: 15px; }
  .icon-wrapper { width: 80px; height: 80px; border-radius: 50%;
                  display: flex; align-items: center; justify-content: center;
                  font-size: 38px; color: var(--tenki-white); flex-shrink: 0;
                  box-shadow: 0 4px 10px rgba(0,0,0,.1);
                  transition: transform .4s cubic-bezier(0.175, 0.885, 0.32, 1.275); }
  .pillar-card:hover .icon-wrapper { transform: scale(1.08); }

  .status-badge { padding: 6px 12px; border-radius: 20px;
                  font-size: .72rem; font-weight: 700; text-transform: uppercase;
                  letter-spacing: .5px; text-align: center; display: inline-block;
                  max-width: 65%; line-height: 1.3; }
  .badge-active { background-color: #e8f5e9; color: var(--tenki-green); border: 1px solid #c8e6c9; }
  .badge-future { background-color: #eeeeee; color: var(--tenki-black); border: 1px solid #ccc; }

  .pillar-title { font-size: 1.4rem; color: var(--tenki-black);
                  margin: 0 0 15px; font-weight: 700; line-height: 1.3; }
  .pillar-subtitle { margin: -10px 0 15px; font-style: italic;
                     font-size: .95rem; color: var(--text-light); }

  .pillar-section { margin-bottom: 20px; width: 100%; }
  .section-title { font-weight: 700; text-transform: uppercase;
                   font-size: .9rem; letter-spacing: .5px; margin-bottom: 8px; }
  .pillar-text { font-size: .95rem; color: var(--text-light);
                 line-height: 1.6; margin: 0 0 10px; }

  .media-wrapper { width: 100%; height: 180px; margin: 10px 0 15px;
                   border-radius: 8px; overflow: hidden;
                   box-shadow: 0 2px 8px rgba(0,0,0,.05); background-color: #eaeaea; }
  .pillar-image, .pillar-video { width: 100%; height: 100%; object-fit: cover; }

  .program-list { list-style: none; padding: 0; margin: 0 0 15px; width: 100%; }
  .program-list li { font-size: .95rem; color: var(--text-light); line-height: 1.5;
                     margin-bottom: 12px; padding-left: 20px; position: relative; }
  .program-list li::before { content: '•'; position: absolute; left: 0;
                             font-size: 1.2rem; font-weight: bold; }
  .split-list { display: grid; grid-template-columns: 1fr 1fr; gap: 5px; margin-bottom: 15px; }

  .learn-more-btn { align-self: center; display: flex;
                    justify-content: center; align-items: center; gap: 8px;
                    margin: 25px auto 15px; padding: 14px 28px;
                    border-radius: 8px; text-decoration: none;
                    font-weight: 700; text-transform: uppercase;
                    font-size: .85rem; letter-spacing: .5px;
                    width: auto; min-width: 200px; max-width: 100%;
                    transition: background-color .2s ease, transform .2s ease; }
  .learn-more-btn::after { content: '→'; font-size: 1.1rem;
                           transition: transform .2s ease; margin-left: 4px; }
  .learn-more-btn:hover { transform: translateY(-2px); }
  .learn-more-btn:hover::after { transform: translateX(4px); }

  .explore-toggle-btn { align-self: center; width: auto;
                        min-width: 200px; max-width: 100%;
                        display: flex; flex-direction: column; justify-content: center; align-items: center; gap: 3px;
                        margin-top: auto; padding: 12px 24px;
                        border-radius: 8px; border: none;
                        font-weight: 700; text-transform: uppercase;
                        font-size: .85rem; letter-spacing: .5px;
                        cursor: pointer;
                        transition: background-color .2s ease, transform .2s ease; }
  .explore-toggle-btn:hover { transform: translateY(-1px); }
  /* Reading-time hint riding on the Explore button — secondary to the action label,
     so it clearly describes the content revealed on expand (not the card copy).
     Hidden once expanded (the content is then visible). */
  .explore-toggle-readtime { text-transform: none; font-size: .68rem; font-weight: 600;
                             letter-spacing: .1px; opacity: .72; }
  .pillar-card.is-expanded .explore-toggle-readtime { display: none; }

  /* Funding boxes */
  .funding-container { display: none; gap: 20px; margin-top: 40px; }
  .funding-box { flex: 1; padding: 25px; border-radius: 12px;
                 display: flex; align-items: center; gap: 20px;
                 box-shadow: 0 4px 10px rgba(0,0,0,.03);
                 transition: transform .3s ease, box-shadow .3s ease;
                 text-decoration: none; }
  .funding-box:hover { transform: translateY(-3px); box-shadow: 0 8px 20px rgba(0,0,0,.06); }
  .funding-icon { font-size: 2.5rem; flex-shrink: 0; transition: transform .3s ease; }
  .funding-box:hover .funding-icon { transform: scale(1.1); }
  .funding-text h4 { margin: 0 0 5px; font-size: 1.1rem;
                     text-transform: uppercase; letter-spacing: .5px; }
  .funding-text p { margin: 0; font-size: .95rem; line-height: 1.5; }
  .funding-current { background-color: #eef5fb; border: 2px solid #b3d4f0; }
  .funding-current h4 { color: var(--tenki-blue); }
  .funding-current p { color: #2C4A68; }
  .funding-future  { background-color: #f5f5f5; border: 2px dashed #ccc; }
  .funding-future h4 { color: var(--tenki-black); }
  .funding-future p { color: var(--text-light); }

  /* ── Card extras ────────────────────────────────────────────────────────── */
  /* Subtle "recent activity" tag — same gentle styling for any pillar that has it. */
  .recent-activity-tag { display: inline-flex; align-items: center; gap: 4px;
                         font-size: .65rem; font-weight: 700; text-transform: uppercase;
                         letter-spacing: .5px; color: #166534;
                         background: #f0fdf4; border: 1px solid #bbf7d0;
                         padding: 2px 8px; border-radius: 10px;
                         margin: 4px 0 0; align-self: flex-start; }
  .recent-activity-dot { width: 6px; height: 6px; border-radius: 50%;
                         background: var(--tenki-green); animation: gentlePulse 2s ease-in-out infinite; }
  @keyframes gentlePulse { 0%, 100% { opacity: 1; } 50% { opacity: .4; } }

  /* Closed-card teaser (Task 5): stat = bold in the card's theme color; note = muted.
     (Reading-time moved onto the Explore button — see .explore-toggle-readtime.) */
  .pillar-teaser { margin: 2px 0 12px; font-size: .82rem; line-height: 1.3; }
  .pillar-teaser-stat { font-weight: 700; color: var(--tenki-black); }
  .card-blue  .pillar-teaser-stat { color: var(--tenki-blue); }
  .card-green .pillar-teaser-stat { color: var(--tenki-green); }
  .pillar-teaser-note { color: var(--text-light); font-weight: 600; }
  /* Single-sourced deep-dive impact stat (Task 6): a deliberate key-stat block —
     a big brand-color number with a concise uppercase caption, set off from the
     body copy by a hairline + spacing so it reads as a metric, not a sentence. */
  .pillar-teaser-metric { margin: 16px 0 6px; padding-top: 13px; border-top: 1px solid rgba(0, 0, 0, .07); }
  .pillar-teaser-metric .pillar-teaser-big { display: block; font-size: 1.85rem; font-weight: 800;
                                             line-height: 1.05; letter-spacing: -.02em; color: var(--tenki-black); }
  .card-blue  .pillar-teaser-metric .pillar-teaser-big { color: var(--tenki-blue); }
  .card-green .pillar-teaser-metric .pillar-teaser-big { color: var(--tenki-green); }
  .pillar-teaser-metric .pillar-teaser-cap { display: block; margin-top: 4px; font-size: .67rem; font-weight: 700;
                                             letter-spacing: .06em; line-height: 1.4; text-transform: uppercase;
                                             color: var(--text-light); }
  /* Future-pillar clarifier (Task 8) — quiet, supportive, not a hard sell. */
  .pillar-future-note { margin: 2px 0 12px; font-size: .76rem; line-height: 1.35;
                        color: var(--text-light); font-style: italic; }

  /* ── Optional element-level links (Icon, Title, Section Title, Media …) ──
     When an editor sets an "X Link URL" field on the sheet, the matching
     element wraps in an <a>.  These styles keep the visual exactly the same
     as the non-linked version — no default underline, native colors — but
     reveal a small ↗ glyph on hover so users know it leads somewhere. */
  .pillar-elem-link { display: inline-block; color: inherit; text-decoration: none;
                      position: relative; transition: opacity .15s; }
  .pillar-elem-link:hover { opacity: .85; }
  .pillar-elem-link.link-heading::after,
  .pillar-elem-link.link-title::after { content: ' ↗'; font-size: .7em;
                                        opacity: 0; transition: opacity .15s;
                                        color: var(--tenki-blue); }
  .pillar-elem-link.link-heading:hover::after,
  .pillar-elem-link.link-title:hover::after { opacity: 1; }
  .pillar-elem-link.link-media { display: block; position: relative; cursor: pointer; }
  .pillar-elem-link.link-media::after {
    content: '↗'; position: absolute; top: 12px; right: 12px;
    width: 26px; height: 26px; border-radius: 50%;
    background: rgba(0,0,0,.55); color: #fff;
    display: flex; align-items: center; justify-content: center;
    font-size: 13px; opacity: 0; transition: opacity .2s;
  }
  .pillar-elem-link.link-media:hover::after { opacity: 1; }
  .pillar-elem-link.link-icon { display: inline-block; border-radius: 50%; }
  .pillar-elem-link.link-icon:hover .icon-wrapper { transform: scale(1.12); }

  /* Share button in the top-right of each card (next to the chevron) */
  .share-btn { position: absolute; top: 18px; right: 54px;
               width: 28px; height: 28px; border-radius: 50%;
               background: rgba(0,0,0,.04); color: #666;
               border: none; cursor: pointer; padding: 0;
               display: flex; align-items: center; justify-content: center;
               transition: background .2s, color .2s, opacity .2s;
               opacity: .35; /* always faintly visible; brightens on hover */ }
  .pillar-card:hover .share-btn,
  .share-btn:focus-visible { opacity: 1; }
  .share-btn:hover { background: rgba(0,0,0,.08); color: var(--tenki-blue); }
  .share-btn.copied { background: var(--tenki-green); color: #fff; }
  .share-btn.copied svg { display: none; }
  .share-btn.copied::after { content: '✓'; font-size: 14px; font-weight: bold; }

  /* First-visit chevron pulse — auto-disables after first interaction */
  @keyframes chevronAttention {
    0%, 100% { transform: scale(1); box-shadow: 0 0 0 0 rgba(0,90,156,0); }
    50%      { transform: scale(1.18); box-shadow: 0 0 0 6px rgba(0,90,156,.15); }
  }
  .pillar-card.first-visit-pulse .pillar-chevron { animation: chevronAttention 1.5s ease-in-out 2; }

  /* ── Image skeleton placeholder ─────────────────────────────────────────── */
  .pillar-image, .pillar-video { transition: opacity .4s ease; }
  .pillar-image:not(.loaded), .pillar-video:not(.loaded) { opacity: 0; }
  .media-wrapper { position: relative; }
  .media-wrapper.loading::before {
    content: ''; position: absolute; inset: 0;
    background: linear-gradient(90deg, #eaeaea 0%, #f3f4f6 50%, #eaeaea 100%);
    background-size: 200% 100%; animation: skeleton 1.4s ease-in-out infinite;
  }
  @keyframes skeleton { 0% { background-position: 200% 0; } 100% { background-position: -200% 0; } }

  /* ── Funding progress bar ───────────────────────────────────────────────── */
  .funding-progress { width: 100%; margin-top: 10px; }
  .funding-progress-bar { width: 100%; height: 8px; background: rgba(0,0,0,.06);
                          border-radius: 4px; overflow: hidden; }
  .funding-progress-fill { height: 100%; border-radius: 4px;
                           transition: width .6s ease; }
  .funding-current .funding-progress-fill { background: var(--tenki-blue); }
  .funding-future  .funding-progress-fill { background: #999; }
  .funding-progress-labels { display: flex; justify-content: space-between;
                             font-size: .7rem; margin-top: 4px;
                             font-weight: 600; }
  .funding-current .funding-progress-labels { color: #2C4A68; }
  .funding-future  .funding-progress-labels { color: var(--text-light); }

  /* ── Inline donation/embed iframe ───────────────────────────────────────── */
  .funding-embed { width: 100%; margin-top: 14px; border: none;
                   border-radius: 8px; background: #fff;
                   min-height: 240px; }

  /* ── Newsletter banner (after engagement threshold) ─────────────────────── */
  #newsletter-banner { display: none; max-width: var(--tenki-max, 1400px); margin: 30px auto 0;
                       background: #fff; border-radius: 12px; padding: 28px;
                       box-shadow: 0 4px 20px rgba(0,0,0,.08);
                       border-top: 4px solid var(--tenki-blue);
                       position: relative; }
  #newsletter-banner.show { display: block; animation: bannerSlide .5s ease-out; }
  @keyframes bannerSlide { from { opacity: 0; transform: translateY(20px); }
                            to   { opacity: 1; transform: translateY(0); } }
  #newsletter-banner h3 { margin: 0 0 8px; font-size: 1.2rem; color: var(--tenki-black);
                          text-transform: uppercase; letter-spacing: .5px; }
  #newsletter-banner p { margin: 0 0 14px; color: var(--text-light);
                         font-size: .95rem; line-height: 1.5; }
  #newsletter-close { position: absolute; top: 10px; right: 14px;
                      background: none; border: none; cursor: pointer;
                      font-size: 18px; color: #999; line-height: 1; padding: 4px 8px; }
  #newsletter-close:hover { color: var(--tenki-black); }

  /* Honor user system setting — turn off the bouncy/parallax transitions */
  @media (prefers-reduced-motion: reduce) {
    .pillar-card, .pillar-card:hover, .icon-wrapper, .funding-box,
    .pillar-chevron, .pillar-expanded-drawer, .funding-icon {
      transition: none !important; transform: none !important; animation: none !important;
    }
    html { scroll-behavior: auto !important; }
  }
  html { scroll-behavior: smooth; } /* used by deep-link + scroll-into-view */

  @media (max-width: 900px) { .funding-container { flex-direction: column; } }
  @media (max-width: 768px) {
    body { padding: 10px; }
    .infographic-container { padding: 25px 15px; }
    .infographic-header { margin-bottom: 35px; }
    .infographic-header h2 { font-size: 1.8rem; }
    .infographic-header p  { font-size: 1rem; }
    .pillar-card  { padding: 20px; }
    .pillar-title { font-size: 1.25rem; }
    .card-header-flex { height: auto; flex-direction: row;
                        justify-content: space-between; margin-bottom: 15px; }
    .status-badge { max-width: 100%; }
    .icon-wrapper { width: 65px; height: 65px; font-size: 30px; }
    .funding-box  { flex-direction: column; text-align: center; padding: 20px; gap: 10px; }
    .split-list   { grid-template-columns: 1fr; }
  }

/* ─── timeline: timeline/timeline.html (sha=73fd2fe) ─── */
:root {
    --tenki-blue: #005A9C;
    --tenki-blue-light: #eef5fb;
    --tenki-green: #008C45;
    --tenki-green-light: #e8f5e9;
    --tenki-black: #1A1A1A;
    --tenki-white: #FFFFFF;
    /* Tenki SOS (white pillar) — uses charcoal as the actual stroke color
       since pure white would be invisible on the white timeline background */
    --tenki-white-stroke: #2A2A2A;
    --tenki-white-light:  #FAF6EE;
    --tenki-white-border: #C0C5CC;
    --bg-light: #F8F9FA;
    --text-dark: #222222;
    --text-light: #555555;
    --timeline-line: #E2E8F0;

    --phase-accomplished-bg: #e8f5e9;
    --phase-accomplished-text: #2e7d32;
    --phase-planning-bg: #e3f2fd;
    --phase-planning-text: #1565c0;
    --phase-execution-bg: #fff8e1;
    --phase-execution-text: #f57f17;
    --phase-future-bg: #f5f5f5;
    --phase-future-text: #616161;
  }

  body {
    font-family: 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
    background-color: var(--tenki-white);
    margin: 0;
    padding: 20px;
    box-sizing: border-box;
  }

  *, *::before, *::after { box-sizing: inherit; }

  .dashboard-container {
    /* Wide-screen token (#20). The desktop @media below intentionally
       goes WIDER than --tenki-max (min(1600px,96vw)) — the timeline
       spine + map need the extra room; don't regress that to 1400. */
    max-width: var(--tenki-max, 1400px);
    margin: 30px auto;
    background-color: var(--bg-light);
    border-radius: 16px;
    padding: 40px;
    box-shadow: 0 10px 30px rgba(0,0,0,0.03);
    display: flex;
    flex-direction: column;
    position: relative;
    z-index: 10;
    /* Create our own stacking context so siblings of the embedding
       Squarespace section cannot paint into our content area.  The
       mobile @media block below also sets `isolation: isolate` for
       its own reasons (immersive mode + Maya-quote overlap fix
       documented at lines ~877-895).  Lifting it to the base rule
       makes the same defense apply on desktop, where it was missing
       and the social section's masked-bg was painting over the
       bottom of the timeline. */
    isolation: isolate;
    /* Option C — desktop scroll snap.  When the user scrolls down the
       homepage and the dashboard comes into view, the page snaps so the
       whole section fills the viewport.  `proximity` is gentle — won't
       trap the user; they can scroll past freely.  Pair with the
       compressed-fit sizing below so the snapped view actually shows
       the whole timeline + map without overflow. */
    scroll-snap-align: start;
    scroll-margin-top: 0;
  }
  /* Desktop sizing — split into two media queries.  We suggest
     viewport-fit on tall screens but DON'T enforce it on shorter
     ones, where the previous `max-height: calc(100vh - 60px)` was
     crushing the timeline events down to ~120 px (user-reported
     map-overlapping-timeline on common 800-900 px laptop viewports). */
  @media (min-width: 769px) {
    .dashboard-container {
      /* Wider envelope on desktop so the timeline + map both have
         breathing room.  Was 1200 — user-reported the section felt
         cramped on common laptop screens.  Now scales up to 1600 px
         (or 96vw on ultra-wide monitors, capping the line length so
         it doesn't read as a strip across the screen). */
      max-width: min(1600px, 96vw);
      /* Scroll-lock: BOUND the section to the viewport (was `min-height`,
         which let it grow taller than the screen on short laptops + with
         the map's old 380 px floor → overflow).  Now it's a definite
         height and the map-interface-grid below flexes to FIT — shrinks on
         short screens, grows on tall ones — so the whole dashboard (header
         + map + sidebar + cards) always fits one screen.  dvh tracks mobile
         browser-chrome; on desktop it's ~vh. */
      height: calc(100dvh - 60px);
      margin: 16px auto;       /* was 30 — pulls section up */
      padding: 14px 32px 18px; /* was 24/32/24 — top trimmed to feed
                                  ~30 px down into map/cards/sidebar */
    }

    /* The LIST view (default desktop mode) and the DETAILED view both
       RELEASE the viewport lock — their content (a vertical list of every
       event / every card expanded inline) is far taller than one screen,
       and the fixed height was silently clipping it: rows spilled past
       the container bottom (painting into the next homepage section, the
       funnel) with NO way to scroll them, and the header/filter chips
       ended up visually stranded at the bottom.  These modes now grow
       naturally and the PAGE scrolls through all items.  The fixed
       height above stays as the baseline for the one-screen map+cards
       dashboard layout. */
    .dashboard-container.list-view,
    .dashboard-container:not(.simplified-view) {
      height: auto;
      min-height: calc(100dvh - 60px);
    }

    /* ── Desktop timeline cards: always full height, NO hover lift ──
       2026-05-28 redesign: every card shows its full content inline
       at all times.  Map is sized smaller (clamp 200/28vh/320) so
       cards have room below it without any "come forward on hover"
       gymnastics — text never reflows, never scrunches, never
       jitters.  Click-to-lock the .active / .focused state still
       paints a subtle outline so the user sees which card the
       sidebar is currently describing. */
    .timeline-block {
      position: relative;
      z-index: 5;
      /* Block sizes to its card (which is now auto-height with the
         chip-only layout).  Without align-self:flex-start the block
         stretches to the tallest sibling in the row — left a 100-px
         band of empty card below the content. */
      align-self: flex-start;
    }
    .timeline-card  {
      /* No max-height clamp — card grows to fit its content.  Box-
         shadow + transform transitions kept only so the .active
         outline below animates cleanly on click. */
      transition: box-shadow .25s ease;
      position: relative;        /* anchor the absolute-positioned share-btn (see below) */
    }

    /* ── Compact location chip (was a wide button at the bottom of the
       card) ─────────────────────────────────────────────────────────
       In detailed view the sidebar already shows the region prominently
       under the title, so a second region row at the bottom of the card
       wastes vertical space.  Re-style .click-indicator as a small
       icon-only chip pinned to the top-LEFT of the card.  Tap target
       stays 28 px so it's still hittable.  The full region name still
       lives in the chip's title="" attribute for hover discovery. */
    .timeline-card .click-indicator {
      position: absolute;
      top: 8px; left: 8px;
      width: 28px; height: 28px;
      min-width: 0;
      padding: 0 !important;
      margin: 0 !important;
      font-size: 0.95rem !important;
      background: rgba(0,0,0,0.05) !important;
      color: var(--text-light) !important;
      border-radius: 50%;
      border: 1px solid rgba(0,0,0,0.10);
      display: inline-flex;
      align-items: center;
      justify-content: center;
      /* Hide the region text — only the 📍 icon shows.  Title attribute
         (added by trackIconHTML render path) is the hover tooltip with
         the full region name. */
      overflow: hidden;
      text-indent: -9999px;
      white-space: nowrap;
    }
    .timeline-card .click-indicator::before {
      content: '📍';
      position: absolute;
      inset: 0;
      display: flex;
      align-items: center;
      justify-content: center;
      text-indent: 0;
      font-size: 0.95rem;
      line-height: 1;
    }
    .timeline-card .click-indicator:hover {
      background: rgba(0, 90, 156, 0.12) !important;
      border-color: rgba(0, 90, 156, 0.30);
    }
    /* Make room for the corner chip — title block gets a left padding
       so the icon doesn't overlap the title text. */
    .timeline-card > .time-marker,
    .timeline-card > .duration-span,
    .timeline-card h3 {
      padding-left: 36px;
    }

    /* ── Title clamp REMOVED on desktop (2026-05-29) ──────────────────
       User wants the full activity name always visible on desktop
       cards — no ellipses, no two-line cap.  Title now flows to as
       many lines as the content needs.  The card itself has no
       max-height clamp, so it grows in lockstep.
       (Mobile keeps a clamp via the @media (max-width:768px) block
        further down, where vertical space is tighter.) */
    .timeline-card h3 {
      word-break: break-word;
    }
    /* The in-flow card no longer renders a body <p> (description was
       merged into the sidebar text).  Any rogue <p> that does sneak
       in still gets clamped to a single line as a safety net. */
    .timeline-card p {
      display: -webkit-box;
      -webkit-line-clamp: 1;
      -webkit-box-orient: vertical;
      overflow: hidden;
    }
    .timeline-card .click-indicator {
      max-width: 100%;
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
    }
    /* Sidebar body paragraphs (merged desc + sidebarText).  Plain
       block paragraphs in normal flow — let the flex column stack
       them with each other and with the locations list below.  No
       forced min-height (was overflowing into the next sibling) and
       no -webkit-box display (was collapsing to zero on some flows). */
    .map-details-sidebar .details-content-view p,
    .map-details-sidebar #dynamic-sidebar-view  p {
      display: block;
      margin: 0 0 12px 0;
      line-height: 1.5;
      font-size: 0.92rem;
      color: var(--text-light);
      overflow: visible;
      white-space: normal;
      -webkit-line-clamp: none;
    }
    .map-details-sidebar #dynamic-sidebar-view p + p {
      margin-top: 0;
    }
    /* Pin the locations list and CTAs into normal flow so they
       always sit BELOW the body paragraphs (was sometimes painting
       over them — the user's overlap report). */
    .map-details-sidebar .locations-list-container,
    .map-details-sidebar .details-cta-group,
    .map-details-sidebar .details-region {
      position: relative;
      z-index: 1;
      clear: both;
    }

    /* Share button: pinned to top-right of the card (timeline AND
       sidebar both).  Previously rendered as a white pill which read
       as an "ugly box."  Now: NO background, NO border, NO shadow by
       default — just the icon floating in place.  On hover, a soft
       translucent grey wash appears so the user knows it's tappable.
       Icon-only at all times (label hidden) so the affordance is
       compact and never overlaps adjacent content. */
    .timeline-card > .share-btn,
    .timeline-card .card-badge-row > .share-btn,
    .details-content-view > .share-btn,
    .details-content-view .share-btn {
      position: absolute;
      top: 6px;
      right: 6px;
      background: transparent !important;
      border: 0 !important;
      box-shadow: none !important;
      padding: 6px !important;
      z-index: 4;
      opacity: 0.55;
      transition: opacity .15s ease, background .15s ease;
    }
    .timeline-card > .share-btn span,
    .timeline-card .card-badge-row > .share-btn span,
    .details-content-view .share-btn span {
      display: none;     /* icon-only — keeps the share affordance compact */
    }
    .timeline-card > .share-btn:hover,
    .timeline-card .card-badge-row > .share-btn:hover,
    .details-content-view .share-btn:hover {
      background: rgba(0, 90, 156, 0.10) !important;
      opacity: 1;
    }
    .timeline-card > .share-btn:hover svg,
    .timeline-card .card-badge-row > .share-btn:hover svg,
    .details-content-view .share-btn:hover svg {
      fill: var(--tenki-blue) !important;
      color: var(--tenki-blue) !important;
    }
    /* Sidebar share-btn needs its container relatively positioned to
       anchor the absolute share-btn correctly. */
    .details-content-view { position: relative; }
    /* Bottom-fade ::after removed — cards are full-height now, so
       there's nothing hidden underneath to hint at. */
    .timeline-card::after { display: none !important; }

    /* Active / focused (click-locked) — visible selection cue:
         - 3-px solid outline around the card, COLOURED TO MATCH THE
           CARD'S TRACK (blue / green / black / white) so the cue
           reinforces the track identity instead of always reading
           Tenki-blue regardless of pillar
         - softer interior border ring + bigger lifted shadow (also
           track-tinted via the per-track rules below)
         - the "✓ SELECTED" pill in the top-right corner picks up the
           same track colour
       No transform — layout doesn't shift, neighbour cards stay put.
       Per-track overrides are below; this base rule provides the
       Tenki-blue fallback for any card without a recognised track. */
    .timeline-block.active .timeline-card,
    .timeline-block.focused .timeline-card {
      box-shadow: 0 10px 28px rgba(0,90,156,0.18), 0 0 0 1px rgba(0,90,156,0.20);
    }
    .timeline-block.active .timeline-card {
      outline: 3px solid var(--tenki-blue);
      outline-offset: -1px;
    }
    /* Tiny "selected" chevron in the top-right corner so the cue reads
       even when several similarly-coloured cards are next to each other. */
    .timeline-block.active .timeline-card::before {
      content: '✓ Selected';
      position: absolute;
      top: 8px; right: 10px;
      font: 700 0.6rem/1 'Segoe UI', Roboto, sans-serif;
      letter-spacing: 0.5px;
      text-transform: uppercase;
      color: #fff;
      background: var(--tenki-blue);
      padding: 4px 8px 4px 7px;
      border-radius: 999px;
      z-index: 5;
      pointer-events: none;
      box-shadow: 0 2px 6px rgba(0,90,156,0.30);
    }

    /* ── Per-track overrides for the selection cue ──────────────────
       data-track lives on .timeline-block (set by the render path),
       so the cascade reaches both the .timeline-card outline AND the
       ::before pill via descendant selectors. */
    .timeline-block.active[data-track="green"] .timeline-card,
    .timeline-block.focused[data-track="green"] .timeline-card {
      box-shadow: 0 10px 28px rgba(0,140,69,0.18), 0 0 0 1px rgba(0,140,69,0.20);
    }
    .timeline-block.active[data-track="green"] .timeline-card {
      outline-color: var(--tenki-green);
    }
    .timeline-block.active[data-track="green"] .timeline-card::before {
      background: var(--tenki-green);
      box-shadow: 0 2px 6px rgba(0,140,69,0.30);
    }

    .timeline-block.active[data-track="black"] .timeline-card,
    .timeline-block.focused[data-track="black"] .timeline-card {
      box-shadow: 0 10px 28px rgba(26,26,26,0.22), 0 0 0 1px rgba(26,26,26,0.20);
    }
    .timeline-block.active[data-track="black"] .timeline-card {
      outline-color: var(--tenki-black);
    }
    .timeline-block.active[data-track="black"] .timeline-card::before {
      background: var(--tenki-black);
      box-shadow: 0 2px 6px rgba(26,26,26,0.30);
    }

    .timeline-block.active[data-track="white"] .timeline-card,
    .timeline-block.focused[data-track="white"] .timeline-card {
      box-shadow: 0 10px 28px rgba(42,42,42,0.20), 0 0 0 1px var(--tenki-white-border);
    }
    .timeline-block.active[data-track="white"] .timeline-card {
      outline-color: var(--tenki-white-stroke);
    }
    .timeline-block.active[data-track="white"] .timeline-card::before {
      background: var(--tenki-white-stroke);
      box-shadow: 0 2px 6px rgba(42,42,42,0.30);
    }
    /* Blue is already the default — no override needed, the base rule
       above paints var(--tenki-blue). */
  }
  /* Scroll-snap the dashboard into the viewport on ALL desktop heights.
     2026-06-16: the section is now bounded to the viewport
     (`.dashboard-container { height: calc(100dvh - 60px) }`) and the
     map-interface-grid flexes to fit, so the whole dashboard fits one
     screen — which makes the lock meaningful at every desktop height.
     The old `min-height: 900px` gate left it OFF on common 768–900 px
     laptops (the "not locking" the user reported); removed.  `proximity`
     stays gentle — pulls the section into place without trapping scroll
     past it to the hero above / social below. */
  @media (min-width: 769px) {
    html { scroll-snap-type: y proximity; }
  }
  /* Detailed-view safety: the cards section must always claim its
     natural height so the map below can't paint over its bottom edge.
     `.map-interface-grid` is already `flex-shrink: 0`; matching the
     cards row to it makes both honour their content. */
  @media (min-width: 769px) {
    .timeline-outer-wrapper { flex-shrink: 0; }
  }

  .dashboard-header {
    text-align: center;
    margin-bottom: 8px;
    order: 1;
    position: relative;
    z-index: 10;
  }

  .dashboard-header h2 {
    color: var(--tenki-black);
    font-size: 1.5rem;            /* tightened so section heading doesn't dominate the carousel below */
    text-transform: uppercase;
    letter-spacing: 0.5px;
    margin: 0 0 2px 0;
    font-weight: 800;
    line-height: 1.1;
  }

  .dashboard-header p {
    color: var(--text-light);
    font-size: 0.9rem;
    max-width: 900px;             /* wider so the single-line lede stays one line on most viewports */
    margin: 0 auto;
    line-height: 1.35;
    white-space: nowrap;          /* hard-force one line; the line is short enough */
    overflow: hidden;
    text-overflow: ellipsis;
  }
  /* On narrow viewports allow the lede to wrap rather than ellipsis-clip */
  @media (max-width: 720px) {
    .dashboard-header p {
      white-space: normal;
      font-size: 0.85rem;
    }
  }
  /* Laptop heights: the dashboard is locked to the viewport height, so the full
     section header + lede steals vertical room the cards / map / sidebar need.
     On short viewports compact the heading and drop the decorative lede (kept on
     tall screens where there's room).  Desktop-only — mobile has its own layout. */
  @media (min-width: 769px) and (max-height: 860px) {
    .dashboard-header { margin-bottom: 2px; }
    .dashboard-header h2 { font-size: 1.15rem; letter-spacing: 0.3px; }
    .dashboard-header p  { display: none; }
  }

  .system-state-container {
    text-align: center;
    padding: 60px 20px;
    order: 2;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    min-height: 200px;
  }

  .spinner {
    width: 40px;
    height: 40px;
    border: 4px solid rgba(0, 90, 156, 0.1);
    border-left-color: var(--tenki-blue);
    border-radius: 50%;
    animation: spin 1s linear infinite;
    margin-bottom: 15px;
  }

  @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }

  .state-message { font-weight: 600; color: var(--text-light); font-size: 1.1rem; }
  .error-state { color: #d32f2f; }
  .error-icon { font-size: 2rem; margin-bottom: 10px; }
  .diagnostic-info { display: block; font-size: 0.85rem; color: #555; margin-top: 10px; font-weight: normal; background: #f5f5f5; padding: 10px; border-radius: 6px;}

  /* Control Bar */
  .dashboard-controls {
    display: none;
    flex-direction: column;
    align-items: center;
    gap: 15px;
    margin-bottom: 14px;          /* was 30 — tighter to feed more room down */
    order: 3;
    position: relative;
    width: 100%;
    z-index: 150;
  }

  .filters-scroll-wrapper {
    position: relative;
    width: 100%;
    overflow: visible;
  }

  .timeline-filters {
    display: flex;
    justify-content: center;
    gap: 12px;
    flex-wrap: wrap;
    width: 100%;
  }

  .dropdown-wrapper { position: relative; display: inline-block; }

  .filter-btn {
    background-color: var(--tenki-white); border: 2px solid var(--timeline-line);
    color: var(--text-light); padding: 8px 20px; border-radius: 30px;
    font-family: inherit; font-size: 0.85rem; font-weight: 700;
    text-transform: uppercase; letter-spacing: 0.5px; cursor: pointer;
    transition: all 0.2s ease;
    height: 38px;
    line-height: 1.2;
    box-sizing: border-box;
  }
  .filter-btn:hover { border-color: #CCCCCC; color: var(--text-dark); }

  /* "↻ Clear filter" — single unified reset CTA.  Combines the old
     "All Impact" reset chip and "↕ Expand all years" button into one.
     Filled Tenki-blue so the user spots it as the action out of any
     filtered / collapsed state.  Hidden by default; JS reveals it
     whenever any sub-filter is active OR any year is collapsed. */
  .filter-btn.clear-filter-btn {
    background: var(--tenki-blue);
    border-color: var(--tenki-blue);
    color: #fff;
  }
  .filter-btn.clear-filter-btn:hover {
    background: #00477a;
    border-color: #00477a;
    color: #fff;
  }
  .filter-btn.clear-filter-btn[hidden] { display: none !important; }

  /* ── Track-color resting state for filter dropdowns ──────────────────
     Even when a filter chip isn't the active one, tint its border + text
     in its track color so the legend (Clinic = blue, Literacy = green,
     Engine = black, Tenki Org = neutral) is always visible.  Active
     state below switches to the solid-color flip. */
  .dropdown-wrapper[data-filter="Clinic Track"]    .dropdown-toggle-btn:not(.active) {
    border-color: rgba(0,90,156,0.55);
    color: var(--tenki-blue);
    background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23005A9C'%3e%3cpath d='M7 10l5 5 5-5z'/%3e%3c/svg%3e");
  }
  .dropdown-wrapper[data-filter="Clinic Track"]    .dropdown-toggle-btn:not(.active):hover {
    background-color: var(--tenki-blue-light);
    border-color: var(--tenki-blue);
  }
  .dropdown-wrapper[data-filter="Literacy Track"]  .dropdown-toggle-btn:not(.active) {
    border-color: rgba(0,140,69,0.55);
    color: var(--tenki-green);
    background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23008C45'%3e%3cpath d='M7 10l5 5 5-5z'/%3e%3c/svg%3e");
  }
  .dropdown-wrapper[data-filter="Literacy Track"]  .dropdown-toggle-btn:not(.active):hover {
    background-color: var(--tenki-green-light);
    border-color: var(--tenki-green);
  }
  .dropdown-wrapper[data-filter="The Engine"]      .dropdown-toggle-btn:not(.active) {
    border-color: rgba(26,26,26,0.55);
    color: var(--tenki-black);
    background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%231A1A1A'%3e%3cpath d='M7 10l5 5 5-5z'/%3e%3c/svg%3e");
  }
  .dropdown-wrapper[data-filter="The Engine"]      .dropdown-toggle-btn:not(.active):hover {
    background-color: #f1f1f1;
    border-color: var(--tenki-black);
  }
  /* Tenki Organization = the "white" track in event data.  Use a soft
     neutral with dashed border to echo the dashed top-border treatment
     on white-track cards. */
  .dropdown-wrapper[data-filter="Tenki Organization"] .dropdown-toggle-btn:not(.active) {
    border-color: var(--tenki-white-stroke);
    border-style: dashed;
    color: var(--text-dark);
    background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23999999'%3e%3cpath d='M7 10l5 5 5-5z'/%3e%3c/svg%3e");
  }
  .dropdown-wrapper[data-filter="Tenki Organization"] .dropdown-toggle-btn:not(.active):hover {
    background-color: var(--tenki-white-light);
  }

  .dropdown-toggle-btn {
    padding-right: 32px !important;
    background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23555555'%3e%3cpath d='M7 10l5 5 5-5z'/%3e%3c/svg%3e");
    background-repeat: no-repeat;
    background-position: right 12px center;
    background-size: 16px;
  }

  .dropdown-menu-options {
    display: none;
    position: absolute;
    top: calc(100% + 6px);
    left: 0;
    background: var(--tenki-white) !important;
    border: 1px solid var(--timeline-line);
    border-radius: 12px;
    box-shadow: 0 10px 30px rgba(0,0,0,0.2) !important;
    min-width: 240px;
    padding: 6px 0;
    max-height: 260px;
    overflow-y: auto;
    z-index: 2010;
  }

  .dropdown-menu-options.open { display: block; }

  .dropdown-opt-item {
    padding: 10px 20px; font-size: 0.85rem; font-weight: 600; color: var(--text-dark);
    cursor: pointer; text-transform: none; transition: background-color 0.15s ease, color 0.15s ease;
  }
  .dropdown-opt-item:hover { background-color: var(--bg-light); color: var(--tenki-blue); }

  /* (Old "All Impact" reset chip CSS removed 2026-05-29 — the chip is
     gone; the unified .clear-filter-btn above handles both jobs.) */

  .dropdown-wrapper[data-filter="Clinic Track"] .dropdown-toggle-btn.active {
    background-color: var(--tenki-blue); border-color: var(--tenki-blue); color: var(--tenki-white);
    background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23ffffff'%3e%3cpath d='M7 10l5 5 5-5z'/%3e%3c/svg%3e");
  }
  .dropdown-wrapper[data-filter="Literacy Track"] .dropdown-toggle-btn.active {
    background-color: var(--tenki-green); border-color: var(--tenki-green); color: var(--tenki-white);
    background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23ffffff'%3e%3cpath d='M7 10l5 5 5-5z'/%3e%3c/svg%3e");
  }
  .dropdown-wrapper[data-filter="The Engine"] .dropdown-toggle-btn.active,
  .dropdown-wrapper[data-filter="Tenki Organization"] .dropdown-toggle-btn.active {
    background-color: var(--tenki-black); border-color: var(--tenki-black); color: var(--tenki-white);
    background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23ffffff'%3e%3cpath d='M7 10l5 5 5-5z'/%3e%3c/svg%3e");
  }

  /* ── Depth toggle (Simplified ⇆ Full Story) — MOBILE ONLY ─────────────
     Desktop uses the repurposed Map Expand toggle (see .map-expand-toggle
     below) as the depth switch.  On mobile that toggle is hidden, so we
     surface a compact pill in the dashboard-header instead so phone
     visitors can also collapse the heavy detail to a glance view.
     Persists via localStorage shared with the desktop toggle. */
  .dashboard-header { position: relative; }
  .depth-toggle {
    display: none;   /* desktop default — only shows on mobile via media query */
    align-items: center;
    gap: 6px;
    padding: 7px 14px 7px 11px;
    background: var(--tenki-white);
    color: var(--tenki-black);
    border: 1px solid rgba(0,0,0,0.08);
    border-radius: 22px;
    font: 700 0.78rem/1 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
    letter-spacing: 0.4px;
    cursor: pointer;
    box-shadow: 0 4px 14px rgba(0,0,0,0.08);
    transition: transform .15s ease, background .15s ease, box-shadow .15s ease;
    z-index: 6;
  }
  .depth-toggle:hover {
    transform: translateY(-1px);
    background: var(--bg-light);
    box-shadow: 0 6px 18px rgba(0,0,0,0.12);
  }
  .depth-toggle-icon { font-size: 0.95rem; line-height: 1; }
  /* Hint badge retired — the Map Expand button (desktop) and the
     header pill (mobile) both carry an obvious label so a separate
     pulsing hint just added clutter. */
  .depth-hint { display: none !important; }

  @media (max-width: 768px) {
    /* ── Mobile enter-screen centering (homepage) ─────────────────────
       The "Tap to explore" overlay (.tenki-explore-overlay) is
       position:absolute spanning .dashboard-container and centres its
       card within that box.  On the composed homepage the section's
       wrapper can let .dashboard-container grow wider than the phone
       viewport, so the card centred inside a too-wide box → shoved right
       and clipped (reported 2026-06).  Cap the container to the viewport
       so the overlay equals the viewport width and the card centres on
       screen; bound the card itself so it can never clip regardless of
       the wrapper's width. */
    .dashboard-container { max-width: 100vw; }
    .tenki-explore-overlay-card { max-width: min(320px, calc(100vw - 28px)); }

    /* 2026-05-29 (round 3 — user feedback): pulled OUT of the header
       entirely.  Lives inside the timeline-tab-drawer mirror (built
       below) which uses the same position: absolute + JS-positioned
       top pattern as the map-tab-drawer.  Hidden when sitting in
       the header (default DOM home) — shown only when JS has moved
       it into the drawer. */
    .depth-toggle {
      display: none;        /* default-hidden in the header */
    }
    /* Once relocated into the timeline-tab-drawer, the toggle
       fills the drawer (no pill shape).  User-requested 2026-05-29:
       "doesn't need the pill box shape, it should take up the size
       of the mini drawer." */
    #timeline-tab-drawer .depth-toggle {
      display: flex !important;
      width: 100% !important;
      height: 100% !important;
      padding: 0 !important;
      font-size: 0.78rem !important;
      font-weight: 700 !important;
      border-radius: 0 0 16px 16px !important;
      background: transparent !important;
      border: 0 !important;
      box-shadow: none !important;
      color: var(--tenki-blue) !important;
      align-items: center !important;
      justify-content: center !important;
    }
    /* No header padding-right reservation needed — the toggle isn't
       in the header on mobile. */
    .dashboard-header h2 { padding-right: 0; }
    /* Drop the lede paragraph entirely on phones — the H2 alone
       reads as the section header. */
    .dashboard-header p  { display: none !important; }
  }

  /* ── Simplified-view state ────────────────────────────────────────
     Hides the sidebar pane + heavy details from each card, leaving:
       - Year strip + month ticks + spine + node circles
       - Each card: title + date + duration line ONLY (no badges,
         no description, no CTAs, no share button, no map-focus
         button, no mobile-inline-details)
       - Map fills the full width of the map-interface-grid */
  .dashboard-container.simplified-view .map-interface-grid {
    grid-template-columns: 1fr !important;
  }
  .dashboard-container.simplified-view .map-details-sidebar {
    display: none !important;
  }
  /* Cards collapse to compact strips — title + date + nothing else.
     The bottom-fade overlay also goes since there's no hidden content
     to hint at. */
  .dashboard-container.simplified-view .timeline-card {
    max-height: 88px !important;
    padding: 12px 14px !important;
  }
  .dashboard-container.simplified-view .timeline-card::after {
    display: none !important;
  }
  .dashboard-container.simplified-view .timeline-card .card-badge-row,
  .dashboard-container.simplified-view .timeline-card .share-btn,
  .dashboard-container.simplified-view .timeline-card .duration-span-row,
  .dashboard-container.simplified-view .timeline-card p,
  .dashboard-container.simplified-view .timeline-card .click-indicator,
  .dashboard-container.simplified-view .timeline-card .mobile-inline-details {
    display: none !important;
  }
  .dashboard-container.simplified-view .timeline-card h3 {
    font-size: 1.05rem !important;
    line-height: 1.22 !important;
    margin: 0 0 4px 0 !important;
    font-weight: 800 !important;
    display: flex !important;
    align-items: flex-start !important;
    gap: 4px !important;
  }
  .dashboard-container.simplified-view .timeline-card .time-marker {
    font-size: 0.7rem !important;
    color: var(--text-light) !important;
    letter-spacing: 0.4px !important;
  }
  /* Hover-grow removed in simplified mode too (2026-05-28) — see the
     desktop block above for rationale.  Click to activate is the only
     way to expand a card now; hover does nothing visually. */
  /* When a card becomes active in simplified mode, switch BACK to
     full content for THAT card so the user can read it without
     toggling the whole mode.  Other cards stay compact. */
  .dashboard-container.simplified-view .timeline-block.active .timeline-card,
  .dashboard-container.simplified-view .timeline-block.focused .timeline-card {
    max-height: 640px !important;
    padding: 16px !important;
  }
  .dashboard-container.simplified-view .timeline-block.active .timeline-card .card-badge-row,
  .dashboard-container.simplified-view .timeline-block.focused .timeline-card .card-badge-row,
  .dashboard-container.simplified-view .timeline-block.active .timeline-card .share-btn,
  .dashboard-container.simplified-view .timeline-block.focused .timeline-card .share-btn,
  .dashboard-container.simplified-view .timeline-block.active .timeline-card p,
  .dashboard-container.simplified-view .timeline-block.focused .timeline-card p,
  .dashboard-container.simplified-view .timeline-block.active .timeline-card .click-indicator,
  .dashboard-container.simplified-view .timeline-block.focused .timeline-card .click-indicator {
    display: inherit !important;
  }
  .dashboard-container.simplified-view .timeline-block.active .timeline-card h3,
  .dashboard-container.simplified-view .timeline-block.focused .timeline-card h3 {
    font-size: 1.1rem !important;
  }

  /* Structural Hide Classes */
  .filtered-out { display: none !important; }
  /* Bare `.collapsed-by-year` (used on things like year-divider) still
     hides outright.  But .timeline-block.collapsed-by-year (below) is
     overridden to a "shrunk-to-just-the-node" state so the user can
     SEE the number of events in the collapsed year at a glance. */
  .collapsed-by-year { display: none !important; }
  .year-badge.dimmed { opacity: 0.5; background-color: var(--text-light) !important; color: #FFF; box-shadow: inset 0 2px 4px rgba(0,0,0,0.2) !important; }
  /* Third click on year badge: fully hide even the collapsed chips */
  .year-badge.super-dimmed { opacity: 0.25 !important; background-color: #777 !important; color: #FFF; box-shadow: inset 0 2px 4px rgba(0,0,0,0.25) !important; }
  .timeline-block.super-hidden-by-year { display: none !important; }

  /* ── Year-collapsed block: shrink to just the node circle ─────────
     User wanted to STILL see the number of activities Tenki has done
     in a collapsed year — so each collapsed event renders as a small
     dot on the spine instead of vanishing.  Multiple dots in a row
     read as "Tenki had N events in this year" without taking up the
     full card real estate.
     This rule overrides the bare `.collapsed-by-year` hide above
     because the `.timeline-block.collapsed-by-year` selector has
     higher specificity (two classes vs one).  Cards, duration bars,
     stems, connectors, and labels are all hidden — only the node
     remains.  The block itself shrinks to ~36 px so a year's worth
     of events shows as a tight cluster of small dots. */
  .timeline-block.collapsed-by-year {
    display: flex !important;
    flex: 0 0 auto !important;
    width: 36px !important;
    min-width: 36px !important;
    max-width: 36px !important;
    padding: 0 !important;
    margin: 0 !important;
    align-items: center !important;
    justify-content: center !important;
    overflow: visible !important;
    cursor: default !important;
    opacity: 0.6;
    transition: opacity .15s ease, transform .15s ease;
  }
  .timeline-block.collapsed-by-year:hover {
    opacity: 1;
    transform: translateY(-1px);
  }
  /* Hide everything inside the collapsed block EXCEPT the node circle */
  .timeline-block.collapsed-by-year .timeline-card,
  .timeline-block.collapsed-by-year .collapsed-label,
  .timeline-block.collapsed-by-year .expanded-title-card,
  .timeline-block.collapsed-by-year .duration-line-ext,
  .timeline-block.collapsed-by-year .duration-stem,
  .timeline-block.collapsed-by-year .duration-dot,
  .timeline-block.collapsed-by-year .node-card-connector {
    display: none !important;
  }
  /* Pin the collapsed node ON THE SPINE rather than letting it sit in
     normal flow (which was dropping it to the block's vertical centre,
     well below the spine — user reported "the circle is dropping off
     the timeline").  Same y-coordinate as a regular node (top: -33px)
     so the dot lines up with the spine across collapsed + expanded
     years; horizontally centred in the 36-px block. */
  .timeline-block.collapsed-by-year .timeline-node {
    position: absolute !important;
    top: -33px !important;
    left: 50% !important;
    transform: translateX(-50%) !important;
    width: 10px !important;
    height: 10px !important;
    border-width: 2px !important;
    opacity: 0.9 !important;
  }
  /* Active-state transform on the node ramps from translateX(-50%)
     to also include scale(1.35) — defined further down — but we don't
     need that here; the hover lift on the collapsed BLOCK below is
     enough feedback. */
  .timeline-block.collapsed-by-year .timeline-node::before,
  .timeline-block.collapsed-by-year .timeline-node::after {
    display: none !important;
  }
  /* Mobile (vertical timeline): collapsed blocks become a thin
     row of dots stacked vertically.  The 36-px block shrinks to
     ~26 px tall and the dot sits centered. */
  @media (max-width: 768px) {
    .timeline-block.collapsed-by-year {
      width: auto !important;
      min-width: 0 !important;
      max-width: none !important;
      min-height: 26px !important;
      height: 26px !important;
    }
    /* The desktop .collapsed-by-year .timeline-node rule pins the
       dot at left:50% (horizontally centred in the 36-px block) —
       correct for the horizontal desktop spine, WRONG for the
       vertical mobile spine where every other node sits at
       left:-32px (anchored to the LEFT spine column).  Without
       this override the collapsed dot floated in the middle of
       the screen instead of staying ON the spine.  User-flagged
       2026-05-29. */
    .timeline-block.collapsed-by-year .timeline-node {
      left: -32px !important;
      top: 50% !important;
      transform: translateY(-50%) !important;
      width: 8px !important;
      height: 8px !important;
    }
  }

  /* Map & Sidebar Desktop Environments */
  .map-interface-grid {
    display: grid;
    grid-template-columns: 1fr 460px;   /* was 420 — sidebar gets +40 more for the merged body */
    gap: 30px;
    height: 500px;
    order: 5;
    position: relative;
    z-index: 10;
  }
  /* Desktop compressed-fit — when the dashboard is locked to viewport
     height, the map + timeline below it need to SHARE that height
     instead of map taking a fixed 500 px + timeline overflowing.
     Map gets ~45 vh, timeline gets the remaining flex space.  Both
     scroll internally if their content exceeds the allotted height. */
  @media (min-width: 769px) {
    .map-interface-grid {
      /* 2026-05-29 (round 3): switched from a fixed clamp height
         to flex-grow.  Now the cards row stays at content height
         (flex: 0 0 auto on .timeline-outer-wrapper above) and the
         map absorbs ALL the remaining vertical space within the
         dashboard's `min-height: calc(100vh - 60px)` envelope.
         Effect on real viewports:
           900 px laptop  → map gets ~420 px (cards ~280, chrome ~200)
           1080 p screen  → map gets ~580 px
           1440 p desktop → map gets ~880 px
         Lower bound 340 px so a very compressed viewport still
         shows a usable map; upper bound 760 px so the map doesn't
         dwarf the sidebar's content on truly enormous monitors.
         When .dashboard-container.map-expanded is set, the map
         takes its own override — see the .map-expanded rules. */
      flex: 1 1 auto;
      height: auto;             /* override the base 500px so flex controls the height */
      /* Elastic band: the map + sidebar absorb ALL the slack inside the
         viewport-locked dashboard.  min-height:0 (not 340) lets the grid
         SHRINK below its content on short screens (flex-grow alone never
         shrinks); a small floor on the canvas keeps the map usable.  No
         max-height so it GROWS to fill tall screens (user-requested:
         "shorter or taller to fit the user's screen"). */
      min-height: 0;
      position: relative;       /* anchor the expand-toggle button below */
    }
    /* When map is expanded (scroll-lock PRESERVED — keeps the
       app-feel the user wanted):
       1. Map-interface-grid loses its 380 px sidebar column — map
          fills full width.  Sidebar card hidden.
       2. Timeline-outer-wrapper shrinks to ~110 px (year strip + a
          single row of title-only chips below it).
       3. The full event CARDS are hidden but each block still shows
          its .collapsed-label — a small track-colored chip with the
          event title — same mobile-style bubble the user asked for.
       4. Map-interface-grid expands to fill the remaining height
          inside the existing scroll-locked container — `flex: 1` so
          the flex parent allocates the leftover space to it.  No
          scroll-lock override needed.
       5. Floating nav stays visible + lifted above the expanded
          map so the user can use ← / → arrows + All Tracks
          dropdown while browsing pins. */
    .dashboard-container.map-expanded .map-interface-grid {
      grid-template-columns: 1fr !important;
      height: auto !important;
      max-height: none !important;
      flex: 1 1 auto !important;          /* take whatever the dashboard envelope has left */
      min-height: 0 !important;           /* elastic: shrink to fit the viewport-locked envelope on short screens (flex fills it on normal/tall) — was 380, which overflowed sub-820px laptops */
    }
    .dashboard-container.map-expanded .map-details-sidebar { display: none !important; }
    .dashboard-container.map-expanded .timeline-outer-wrapper {
      max-height: 150px !important;
      min-height: 150px !important;
      flex: 0 0 150px !important;
      overflow: visible !important;       /* let scaled-up active card escape vertically */
      margin-bottom: 8px !important;
      transition: max-height .35s ease, flex-basis .35s ease;
      /* Sit ABOVE the map-interface-grid (z:10) so the active card
         growing past its row paints in front of the map below, not
         behind it.  The growing card also has its own z:30 below. */
      position: relative !important;
      z-index: 30 !important;
    }
    .dashboard-container.map-expanded .timeline-scroll-wrapper,
    .dashboard-container.map-expanded .timeline-track {
      overflow-y: visible !important;     /* don't clip the focal scale */
    }
    /* The inner scroll-wrapper has 25 px vertical padding + 40 px
       margin-bottom in its default styles — fine in the normal
       desktop layout (the spine + duration bars need that room) but
       in expanded mode it caused the title cards to overflow the
       strip and visually touch the map.  Zero out the vertical
       padding + margin so the strip envelope is honest about its
       size. */
    .dashboard-container.map-expanded .timeline-scroll-wrapper {
      padding-top: 0 !important;
      padding-bottom: 0 !important;
      margin-bottom: 0 !important;
    }
    /* 2026-05-28 (round 8): user preferred the prior design — title
       cards take the place of the timeline circles on the spine row
       rather than the spine being a separate rail above the cards.
       So we go back to hiding spine + circles + duration scaffolding;
       the .expanded-title-card IS the visual element on the row. */
    .dashboard-container.map-expanded .duration-line-ext,
    .dashboard-container.map-expanded .duration-stem,
    .dashboard-container.map-expanded .duration-dot,
    .dashboard-container.map-expanded .tl-month-tick,
    .dashboard-container.map-expanded .timeline-block .timeline-node,
    .dashboard-container.map-expanded .timeline-card,
    .dashboard-container.map-expanded .timeline-track::before {
      display: none !important;
    }
    /* The block itself stays visible — but at title-chip size, NOT
       290 px wide.  Track-color tinted chip with the event title.
       Same vocabulary the mobile UI already uses (mobile shows these
       chips when years collapse), promoted to desktop in this state.  */
    .dashboard-container.map-expanded .timeline-block {
      flex: 0 0 auto !important;
      width: auto !important;
      min-width: 0 !important;
      padding: 0 !important;
    }
    /* Hide the old single-line collapsed-label in expanded mode —
       the new richer `.expanded-title-card` replaces it.  (Mobile
       collapsed-by-year UX still uses .collapsed-label so we don't
       repurpose it globally.) */
    .dashboard-container.map-expanded .timeline-block .collapsed-label {
      display: none !important;
    }
    .dashboard-container.map-expanded .timeline-track {
      padding-top: 12px !important;       /* tight strip — cards ARE the row, no separate spine above */
      gap: 14px !important;               /* a bit wider than the original 12 so focal scale has room */
      align-items: center !important;     /* cards sit on the row, centered vertically */
      /* 2026-05-28 (round 6): simplified view now reads as a CAROUSEL.
         Drop the "spread to full width" overrides — items keep their
         intrinsic widths, the row overflows the wrapper, and the
         existing #slide-left / #slide-right buttons (defined at the
         dashboard root) scroll the row by ~350 px per click.  Mouse
         wheel + drag-to-scroll also work via the existing handlers. */
      min-width: max-content !important;
      width: auto !important;
      justify-content: flex-start !important;
    }
    /* Wrapper: horizontal scroll snap so each event chip lands cleanly
       under the next/prev buttons. */
    .dashboard-container.map-expanded .timeline-scroll-wrapper {
      overflow-x: auto !important;
      overflow-y: hidden !important;       /* contain the lifted-card animations to the strip */
      scroll-snap-type: x mandatory;
      scroll-padding: 0 60px;              /* leave room for the carousel arrows on either edge */
      cursor: grab;
      -webkit-overflow-scrolling: touch;
      scrollbar-width: none;               /* Firefox */
    }
    .dashboard-container.map-expanded .timeline-scroll-wrapper::-webkit-scrollbar {
      display: none;                       /* Chrome/Safari */
    }
    /* Every scrollable item snaps to the start.  collapsed-year dots
       are tiny — they get a wider 90-px slot in carousel mode so the
       dot has visual breathing room and snap-stops feel even. */
    .dashboard-container.map-expanded .timeline-block.collapsed-by-year {
      flex: 0 0 90px !important;
      max-width: 90px !important;
      scroll-snap-align: center;
    }
    .dashboard-container.map-expanded .timeline-block:not(.collapsed-by-year) {
      scroll-snap-align: start;
    }
    .dashboard-container.map-expanded .year-divider {
      flex: 0 0 80px !important;       /* wider than the default 60 so the bubble has its own slot */
      scroll-snap-align: start;
      /* Visual breathing room on both sides — the year bubble itself
         is ~80 px wide so this keeps it from kissing the cards. */
      margin: 0 10px !important;
      position: relative;
    }
    /* Year bubble z-index lifted ABOVE the cards so it's never
       obscured when the next chip sits right against the divider.
       The bubble itself is `position: absolute; top: -37px` inside
       the divider — so it floats above the spine and needs the
       z-index to stay visually on top. */
    .dashboard-container.map-expanded .year-badge {
      z-index: 8 !important;
      /* In simplified view there's no spine above to dock to — drop
         the bubble down so it sits at the same vertical row as the
         cards rather than floating up near the dashboard header. */
      top: 50% !important;
      transform: translateY(-50%) !important;
    }
    /* ── Carousel focal-card effect ───────────────────────────────────
       The "in focus" card (.active / .focused) scales UP and the
       neighbours sit at their natural size — gives the row the
       cover-flow feel the user asked for.  The active card centres
       under the map via the existing smoothScrollToCard() helper
       (already wired). */
    .dashboard-container.map-expanded .expanded-title-card {
      transform: scale(0.96);
      transform-origin: center;
      opacity: 0.85;
      transition: transform .35s ease, opacity .35s ease, box-shadow .35s ease, border-color .35s ease;
    }
    .dashboard-container.map-expanded .timeline-block.active .expanded-title-card,
    .dashboard-container.map-expanded .timeline-block.focused .expanded-title-card {
      transform: scale(1.08);
      opacity: 1;
      z-index: 200 !important;            /* well above map (z:10) + neighbour cards */
      position: relative;
      box-shadow: 0 14px 32px rgba(0,0,0,0.18) !important;
      max-height: none !important;
      overflow: visible !important;
    }
    /* Focused-card title: drop the line-clamp ENTIRELY so the user
       always reads the full title (no ellipsis, no hidden text). */
    .dashboard-container.map-expanded .timeline-block.active .expanded-title-card .etc-title,
    .dashboard-container.map-expanded .timeline-block.focused .expanded-title-card .etc-title {
      display: block !important;
      -webkit-line-clamp: none !important;
      -webkit-box-orient: initial !important;
      overflow: visible !important;
      max-height: none !important;
      white-space: normal !important;
    }
    /* Body content lives in the DETAILED-view sidebar — the simplified-
       view focal card stays compact (title + meta + chips only). */
    /* Lift the active block + outer-wrapper to a stacking layer that
       sits ABOVE the map-interface-grid so the scaled card paints
       cleanly over the map (the screenshot showed the bottom of TBOW
       being clipped behind the pins).  isolation:isolate creates a
       fresh stacking context so the elevated z-index here doesn't
       have to fight ancestor contexts. */
    .dashboard-container.map-expanded .timeline-block.active,
    .dashboard-container.map-expanded .timeline-block.focused {
      z-index: 200 !important;
      position: relative !important;
      isolation: isolate;
    }
    .dashboard-container.map-expanded .timeline-outer-wrapper {
      z-index: 100 !important;
      isolation: isolate;
    }
    /* Carousel arrows: bump them above the title strip so they sit at
       the edges of the simplified-view band rather than disappearing
       behind the map below.  Same .scroll-btn base styling; just
       reposition for the squeezed envelope. */
    .dashboard-container.map-expanded .scroll-btn {
      display: flex !important;
      top: 70px;                            /* mid-card vertically in the 150-px strip */
      transform: none;
      width: 36px; height: 36px;
      background: rgba(255,255,255,0.96);
      border-color: rgba(0,0,0,0.08);
      box-shadow: 0 4px 14px rgba(0,0,0,0.15);
      z-index: 25;
    }
    .dashboard-container.map-expanded .scroll-btn svg { width: 18px; height: 18px; }
    .dashboard-container.map-expanded .prev-btn { left: 6px; }
    .dashboard-container.map-expanded .next-btn { right: 6px; }
    /* Subtle edge-fade hints so the user sees there's more to scroll
       on either side.  Hidden when the wrapper is scrolled all the
       way to that edge (JS toggles .left-hint-active /
       .right-hint-active classes on the scroll-wrapper). */
    .dashboard-container.map-expanded .timeline-outer-wrapper::before,
    .dashboard-container.map-expanded .timeline-outer-wrapper::after {
      content: '';
      position: absolute;
      top: 0; bottom: 0;
      width: 48px;
      pointer-events: none;
      z-index: 20;
      opacity: 0;
      transition: opacity .2s ease;
    }
    .dashboard-container.map-expanded .timeline-outer-wrapper::before {
      left: 0;
      background: linear-gradient(to right, var(--bg-light), transparent);
    }
    .dashboard-container.map-expanded .timeline-outer-wrapper::after {
      right: 0;
      background: linear-gradient(to left, var(--bg-light), transparent);
    }
    .dashboard-container.map-expanded .timeline-outer-wrapper:has(.timeline-scroll-wrapper.left-hint-active)::before  { opacity: 1; }
    .dashboard-container.map-expanded .timeline-outer-wrapper:has(.timeline-scroll-wrapper.right-hint-active)::after  { opacity: 1; }
    /* Squeeze the empty band between the filter chips and the title
       strip in expanded mode — the original 30 px margin made sense
       when the cards needed a duration spine above them, but in
       expanded mode there's no spine, so the gap was just wasted space. */
    .dashboard-container.map-expanded .dashboard-controls {
      margin-bottom: 10px !important;
    }
    .dashboard-container.map-expanded .dashboard-header {
      margin-bottom: 14px !important;
    }
    /* Suppress any 'system state' container in expanded mode — the
       map IS the visible state at this point. */
    .dashboard-container.map-expanded .system-state-container {
      display: none !important;
    }

    /* ── Expanded title card ──────────────────────────────────────────
       Three-row chip per event, surfacing the hardest-hitting punch
       info for at-a-glance reading while the user explores the map:

         Row 1: phase pill + funding pill (track-tinted)
         Row 2: title (bold, ellipsis-trimmed)
         Row 3: date · region (small + muted)

       Hidden by default (display:none) — only ever rendered when
       the dashboard is in .map-expanded.  Track-color tinted card
       body matches the bubble vocabulary of the mobile
       collapsed-label so the visual language stays consistent. */
    .expanded-title-card { display: none; }
    .dashboard-container.map-expanded .expanded-title-card {
      display: flex !important;
      flex-direction: column;
      gap: 4px;
      min-width: 220px;
      max-width: 280px;
      padding: 8px 12px;
      border-radius: 12px;
      border: 1px solid rgba(0, 0, 0, 0.08);
      background: var(--tenki-white);
      cursor: pointer;
      transition: transform .15s ease, box-shadow .15s ease, background .15s ease;
    }
    .dashboard-container.map-expanded .expanded-title-card:hover {
      /* Hover-lift removed — was causing scrunched text + jitter in
         the title strip.  Just deepen the shadow slightly for a
         passive "hoverable" cue. */
      box-shadow: 0 4px 12px rgba(0,0,0,0.12);
    }
    /* Active / focused only — no hover z-index promotion (matches the
       "no hover lift" rule for the in-flow cards above).  Click to
       select; hover does nothing. */
    .dashboard-container.map-expanded .timeline-block.active .expanded-title-card,
    .dashboard-container.map-expanded .timeline-block.focused .expanded-title-card {
      z-index: 50;
    }
    /* ── etc-pills as a uniform mini-table ───────────────────────────
       User feedback: the chips on the title card were "too busy" — each
       badge had its own colour + shape so the eye read it as decoration
       instead of data.  Normalize all three (tag, phase, funding) into
       chips of identical size, shape, and weight so they scan as a
       compact data row.  The TEXT inside still carries the meaning;
       the TAG chip alone keeps its track-colour as a subtle category
       cue (left-most). */
    .etc-pills {
      /* flex-wrap: wrap so a long funding badge ("PARTIALLY FUNDED ·
         SCOPE LIMITED") drops to a second row inside the table
         instead of overflowing the card edge. */
      display: flex; flex-wrap: wrap; gap: 0; align-items: stretch;
      min-height: 18px;
      border: 1px solid rgba(0,0,0,0.12);
      border-radius: 4px;
      overflow: hidden;
      background: rgba(0,0,0,0.02);
    }
    .etc-pills .details-tag,
    .etc-pills .phase-badge,
    .etc-pills .funding-badge {
      font-size: 0.58rem !important;
      padding: 3px 6px !important;
      letter-spacing: 0.4px !important;
      border-radius: 0 !important;
      border: 0 !important;
      border-right: 1px solid rgba(0,0,0,0.10) !important;
      color: var(--text-dark) !important;
      font-weight: 700 !important;
      text-transform: uppercase !important;
      box-shadow: none !important;
      /* `flex: 1 1 auto` so chips stretch to share each row's width.
         Without this, `0 0 auto` left short chips at content-width and
         the empty remainder of a wrapped row showed the parent's white
         (focused-card override) background — the "ugly white box at
         the end" the user flagged 2026-05-29.  With 1 1 auto:
           - Single-row case: chips share row width equally, hairline
             dividers still read as a mini-table.
           - Wrap case: row 1's chips expand to fill row 1, row 2's
             chip fills row 2.  No empty white space.
         text-align: center keeps the label visually centred inside
         the wider cell. */
      flex: 1 1 auto;
      text-align: center;
      justify-content: center;
      line-height: 1.2 !important;
      white-space: nowrap;
      max-width: 100%;
      overflow: hidden;
      text-overflow: ellipsis;
      display: inline-flex;
      align-items: center;
    }
    /* Hide the hairline divider on the visually-last chip of each row.
       Without the `:last-child` rule the rightmost chip on a wrapped
       row 1 still draws its right border into the (now empty) edge of
       the table.  We keep that last-child reset PLUS strip the divider
       on the wrap edge by also catching elements that are followed by
       a wrapped sibling via order-based selectors below. */
    .etc-pills > *:last-child {
      border-right: 0 !important;
    }
    /* TAG chip — subtle track-colour wash (category cue) */
    .etc-pills .details-tag.tag-blue   { background: rgba(0, 90,156, 0.12) !important; color: var(--tenki-blue)  !important; }
    .etc-pills .details-tag.tag-green  { background: rgba(0,140, 69, 0.12) !important; color: var(--tenki-green) !important; }
    .etc-pills .details-tag.tag-black  { background: rgba(26, 26, 26, 0.10) !important; color: var(--tenki-black) !important; }
    .etc-pills .details-tag.tag-white  { background: rgba(192,197,204, 0.20) !important; color: var(--tenki-white-stroke) !important; }
    /* PHASE chip — semantic colour per state (status of the project). */
    .etc-pills .phase-badge.phase-planning     { background: #FFF6E3 !important; color: #946100 !important; }
    .etc-pills .phase-badge.phase-execution    { background: #E3F2FD !important; color: #0D47A1 !important; }
    .etc-pills .phase-badge.phase-accomplished { background: #E8F5E9 !important; color: #2E7D32 !important; }
    .etc-pills .phase-badge.phase-future       { background: rgba(0,0,0,0.05) !important; color: var(--text-light) !important; }
    /* FUNDING chip — semantic colour per state (financial status). */
    .etc-pills .funding-badge.funding-seeking  { background: #FFF0F0 !important; color: #C62828 !important; }
    .etc-pills .funding-badge.funding-partial  { background: #FFF3E0 !important; color: #E65100 !important; }
    .etc-pills .funding-badge.funding-full     { background: #E8F5E9 !important; color: #2E7D32 !important; }
    .etc-pills .funding-badge.funding-active   { background: #E3F2FD !important; color: #0D47A1 !important; }
    /* Focused-card mini-table gets a solid white background so the
       chips read as a table-on-card, not a transparent strip dissolving
       into the card colour beneath it. */
    .dashboard-container.map-expanded .timeline-block.active .expanded-title-card .etc-pills,
    .dashboard-container.map-expanded .timeline-block.focused .expanded-title-card .etc-pills {
      background: rgba(255,255,255,0.98) !important;
      border-color: rgba(0,0,0,0.18) !important;
      box-shadow: 0 1px 2px rgba(0,0,0,0.06) !important;
    }

    /* ── Detailed-view card-badge-row mirrors the simplified-view
       mini-table treatment so the chips read consistently across both
       depth modes.  Same uniform sizing + hairline-divider container. */
    .timeline-card .card-badge-row > div:first-child {
      display: flex !important;
      flex-wrap: wrap !important;          /* same wrap behaviour as etc-pills */
      gap: 0 !important;
      align-items: stretch !important;
      border: 1px solid rgba(0,0,0,0.12);
      border-radius: 4px;
      overflow: hidden;
      background: rgba(0,0,0,0.02);
    }
    .timeline-card .card-badge-row .details-tag,
    .timeline-card .card-badge-row .phase-badge,
    .timeline-card .card-badge-row .funding-badge {
      font-size: 0.6rem !important;
      padding: 3px 8px !important;
      letter-spacing: 0.4px !important;
      border-radius: 0 !important;
      border: 0 !important;
      border-right: 1px solid rgba(0,0,0,0.10) !important;
      color: var(--text-dark) !important;
      font-weight: 700 !important;
      text-transform: uppercase !important;
      box-shadow: none !important;
      /* `flex: 1 1 auto` so chips stretch to fill each row — matches
         the etc-pills (simplified-view) treatment and prevents the
         empty-remainder-of-row showing the card background as a white
         box when the funding badge wraps to row 2. */
      flex: 1 1 auto;
      text-align: center;
      justify-content: center;
      line-height: 1.3 !important;
      display: inline-flex;
      align-items: center;
      white-space: nowrap;
      max-width: 100%;
      overflow: hidden;
      text-overflow: ellipsis;
    }
    .timeline-card .card-badge-row > div:first-child > *:last-child {
      border-right: 0 !important;
    }
    .timeline-card .card-badge-row .details-tag.tag-blue   { background: rgba(0, 90,156, 0.12) !important; color: var(--tenki-blue)  !important; }
    .timeline-card .card-badge-row .details-tag.tag-green  { background: rgba(0,140, 69, 0.12) !important; color: var(--tenki-green) !important; }
    .timeline-card .card-badge-row .details-tag.tag-black  { background: rgba(26, 26, 26, 0.10) !important; color: var(--tenki-black) !important; }
    .timeline-card .card-badge-row .details-tag.tag-white  { background: rgba(192,197,204, 0.20) !important; color: var(--tenki-white-stroke) !important; }
    .timeline-card .card-badge-row .phase-badge.phase-planning     { background: #FFF6E3 !important; color: #946100 !important; }
    .timeline-card .card-badge-row .phase-badge.phase-execution    { background: #E3F2FD !important; color: #0D47A1 !important; }
    .timeline-card .card-badge-row .phase-badge.phase-accomplished { background: #E8F5E9 !important; color: #2E7D32 !important; }
    .timeline-card .card-badge-row .phase-badge.phase-future       { background: rgba(0,0,0,0.05) !important; color: var(--text-light) !important; }
    .timeline-card .card-badge-row .funding-badge.funding-seeking  { background: #FFF0F0 !important; color: #C62828 !important; }
    .timeline-card .card-badge-row .funding-badge.funding-partial  { background: #FFF3E0 !important; color: #E65100 !important; }
    .timeline-card .card-badge-row .funding-badge.funding-full     { background: #E8F5E9 !important; color: #2E7D32 !important; }
    .timeline-card .card-badge-row .funding-badge.funding-active   { background: #E3F2FD !important; color: #0D47A1 !important; }
    /* ── Click-gate: chips on non-active cards are passive labels.
       The user has to focus the card first before any chip (especially
       the funding-badge funding-modal trigger) becomes interactive.
       This stops accidental modal opens while the user is just
       scrolling the carousel. */
    .dashboard-container.map-expanded .timeline-block:not(.active):not(.focused) .etc-pills * {
      pointer-events: none !important;
    }
    .dashboard-container.map-expanded .timeline-block.active .etc-pills *,
    .dashboard-container.map-expanded .timeline-block.focused .etc-pills * {
      pointer-events: auto !important;
    }

    .etc-title {
      font-size: 1.02rem;   /* was 0.82 — much scannable at a glance now that the sidebar's gone */
      font-weight: 800;
      line-height: 1.22;
      color: var(--text-dark);
      /* 3-line clamp by default so long titles ("First Maternal & Child
         Health Training Conference") wrap cleanly instead of ellipsising
         the meaning away — the focused card removes the clamp entirely
         so the user can ALWAYS read the full title. */
      display: -webkit-box;
      -webkit-line-clamp: 3;
      -webkit-box-orient: vertical;
      overflow: hidden;
    }
    .etc-meta {
      display: flex; flex-wrap: wrap; gap: 8px;
      font-size: 0.72rem;   /* was 0.66 — match the bigger title */
      color: var(--text-light);
      font-weight: 600;
      letter-spacing: 0.2px;
    }
    .etc-date { text-transform: uppercase; letter-spacing: 0.4px; }
    .etc-region { color: var(--text-light); }

    /* Track-color tint on the chip body (subtle so the pills inside
     * still pop).  Matches the existing mobile collapsed-label tints. */
    .dashboard-container.map-expanded .timeline-block[data-track="blue"]  .expanded-title-card {
      background: var(--tenki-blue-light);  border-color: rgba(0,90,156,0.2);
    }
    .dashboard-container.map-expanded .timeline-block[data-track="green"] .expanded-title-card {
      background: var(--tenki-green-light); border-color: rgba(0,140,69,0.2);
    }
    .dashboard-container.map-expanded .timeline-block[data-track="black"] .expanded-title-card {
      background: #f5f5f5;                  border-color: rgba(0,0,0,0.12);
    }
    .dashboard-container.map-expanded .timeline-block[data-track="white"] .expanded-title-card {
      background: var(--tenki-white-light); border-color: var(--tenki-white-border);
    }

    /* Active / focused: solid track color, white text.  Same flip
     * pattern the timeline cards use when selected. */
    .dashboard-container.map-expanded .timeline-block.active .expanded-title-card,
    .dashboard-container.map-expanded .timeline-block.focused .expanded-title-card {
      color: #fff !important;
      box-shadow: 0 6px 15px rgba(0,0,0,0.18) !important;
      border-color: transparent !important;
    }
    .dashboard-container.map-expanded .timeline-block.active .expanded-title-card .etc-title,
    .dashboard-container.map-expanded .timeline-block.focused .expanded-title-card .etc-title {
      color: #fff !important;
    }
    .dashboard-container.map-expanded .timeline-block.active .expanded-title-card .etc-meta,
    .dashboard-container.map-expanded .timeline-block.focused .expanded-title-card .etc-meta {
      /* Was rgba(255,255,255,0.85) — 85 % white reads as muddy grey on
         the solid Tenki-blue Clinic Track card.  Fully opaque white +
         subtle shadow gives it clear separation from the dark bg. */
      color: #fff !important;
      text-shadow: 0 1px 2px rgba(0,0,0,0.25);
    }
    /* Region pin emoji + track-track icon emoji on dark active cards:
       emojis are full-colour glyphs and their native palette (mostly
       red 📍 / pastel emojis) can disappear into the dark blue/black
       backgrounds.  A pale white halo around the glyph lifts it out
       without recolouring it. */
    .dashboard-container.map-expanded .timeline-block.active .expanded-title-card .etc-region,
    .dashboard-container.map-expanded .timeline-block.focused .expanded-title-card .etc-region,
    .dashboard-container.map-expanded .timeline-block.active .expanded-title-card .tenki-track-icon,
    .dashboard-container.map-expanded .timeline-block.focused .expanded-title-card .tenki-track-icon {
      filter: drop-shadow(0 0 3px rgba(255,255,255,0.55))
              drop-shadow(0 1px 1px rgba(0,0,0,0.25));
    }
    /* And the same on the in-flow timeline cards when they go active
       (detailed view), which now also carry the per-track outline
       and matching shadow — emoji glyphs in `.click-indicator` 📍 +
       the title's track-icon get the same legibility halo. */
    .timeline-block.active .timeline-card .click-indicator::before,
    .timeline-block.focused .timeline-card .click-indicator::before,
    .timeline-block.active .timeline-card .tenki-track-icon,
    .timeline-block.focused .timeline-card .tenki-track-icon {
      filter: drop-shadow(0 0 2px rgba(255,255,255,0.6))
              drop-shadow(0 1px 1px rgba(0,0,0,0.15));
    }
    .dashboard-container.map-expanded .timeline-block.active[data-track="blue"]  .expanded-title-card,
    .dashboard-container.map-expanded .timeline-block.focused[data-track="blue"] .expanded-title-card {
      background: var(--tenki-blue) !important;
    }
    .dashboard-container.map-expanded .timeline-block.active[data-track="green"]  .expanded-title-card,
    .dashboard-container.map-expanded .timeline-block.focused[data-track="green"] .expanded-title-card {
      background: var(--tenki-green) !important;
    }
    /* Active black-track chip: subtle diagonal gradient instead of a
       solid black slab.  Goes from deep Tenki black at the top-left
       to a slightly lighter blue-tinted black at the bottom-right.
       Adds depth so foundational events like "Tenki is founded" feel
       like a card rather than a punched-out hole, and quietly ties
       the Engine/foundational track to the Tenki blue palette. */
    .dashboard-container.map-expanded .timeline-block.active[data-track="black"]  .expanded-title-card,
    .dashboard-container.map-expanded .timeline-block.focused[data-track="black"] .expanded-title-card {
      background: linear-gradient(135deg,
        #1A1A1A 0%,
        #232B36 55%,
        #2C3A52 100%) !important;
    }
    /* Floating nav stays visible + lifts above the expanded map so
       the user can use the ← / → arrows + All Tracks dropdown while
       browsing pins. */
    .dashboard-container.map-expanded .floating-nav-container {
      display: flex !important;
      z-index: 700;
    }
    /* ── Depth toggle (was "Expand map") ──────────────────────────────
       This button is the canonical Simplified ⇆ Full Story switch on
       desktop.  When `.simplified-view` AND `.map-expanded` are active
       together, the section reads as a glanceable map with title-only
       event cards above the spine.  Clicking the button removes both
       classes → returns to the full sidebar + detailed cards view. */
    .map-expand-toggle {
      position: absolute !important;
      top: 12px !important;
      right: 12px !important;
      z-index: 1000 !important;            /* above leaflet zoom (1000) + everything else */
      background: #1A1A1A !important;      /* literal hex — don't depend on a var that
                                              might not be in scope on every section */
      color: #ffffff !important;
      border: 2px solid #ffffff !important; /* white outline so the pill pops on any map */
      border-radius: 22px !important;
      padding: 9px 16px 9px 14px !important;
      font: 700 0.82rem/1 'Segoe UI', Roboto, sans-serif !important;
      letter-spacing: 0.4px !important;
      cursor: pointer !important;
      box-shadow: 0 6px 18px rgba(0, 0, 0, 0.35) !important;
      transition: background .15s ease, transform .15s ease, box-shadow .15s ease;
      display: inline-flex !important;
      visibility: visible !important;
      opacity: 1 !important;
      pointer-events: auto !important;
      align-items: center;
      gap: 6px;
    }
    .map-expand-toggle:hover {
      transform: translateY(-1px);
      background: #333;
      box-shadow: 0 8px 22px rgba(0, 0, 0, 0.28);
    }
    .map-expand-toggle-icon {
      display: inline-block; font-size: 1rem; line-height: 1;
    }
    /* When the dashboard is already in simplified+expanded mode the
       button label flips to "Full story" (see setupDepthToggle in JS).
       Give it a subtle accent so the user can tell at a glance which
       mode they're in. */
    .dashboard-container.simplified-view .map-expand-toggle {
      background: var(--tenki-blue);
      color: #fff;
      border-color: transparent;
    }
    .dashboard-container.simplified-view .map-expand-toggle:hover {
      background: #00477a;
    }
  }
  @media (max-width: 768px) {
    /* Mobile uses the dedicated mobile-map-view tab toggle for the same
       intent — the desktop "Expand map" button would be redundant + visually
       noisy alongside the map drawer + back-handle UI. */
    .map-expand-toggle { display: none !important; }
  }
  @media (min-width: 769px) {
    /* keep this empty media query open so subsequent rules can fall under
       the same desktop wrapper if needed in the future. */
    .timeline-outer-wrapper {
      /* 2026-05-29 (round 6 — DevTools-confirmed root cause):
         was `flex: 1 1 auto` which let the cards row GROW to absorb
         any slack from the dashboard's `min-height: calc(100vh -
         60px)`.  Combined with `align-self: flex-start` on the
         blocks inside, that pinned the cards to the TOP of the
         grown row and left empty dead space at the BOTTOM —
         visible as a fixed gap between the visible cards bottom
         and the map (even though the row's actual margin-to-map
         was 1 px).
         Switched to `flex: 0 0 auto` so the cards row stays at
         its content height.  The map-interface-grid below now
         carries `flex: 1 1 auto` and absorbs the slack INTO ITSELF
         — on taller viewports the map + sidebar grow proportionally
         to fill the available space (user-requested 2026-05-29:
         "take advantage of it to resize the map and sidebar when
         the scroll lock gives more space"). */
      flex: 0 0 auto;
      /* `overflow-x: clip` still clips the >100%-wide horizontal
         track without creating a scrollbar, BUT `overflow-y: visible`
         allows hover-expanded event cards to extend DOWNWARD past
         the wrapper's bottom edge — overlaying the map section
         below it (which has z-index: 10 vs. the lifted card's 50).
         Previously `overflow: hidden` was clipping the lifted card
         and the user perceived "cards stuck behind the map." */
      overflow-x: clip;
      overflow-y: visible;
      order: 5;
    }
    /* Scroll-wrapper sizes to its content now (no 100%-of-parent
       clamp).  The horizontal scroll for >100%-wide tracks still
       works — overflow-x: auto on the base rule covers it. */
  }

  /* Wrap around the leaflet canvas so the desktop tap-to-engage
     overlay can sit absolutely positioned over it without being
     stretched by the .map-interface-grid's grid track sizing. */
  .map-canvas-wrap {
    position: relative;
    height: 100%;
    min-height: 0;
  }
  #leaflet-map-canvas {
    border-radius: 12px; box-shadow: inset 0 2px 10px rgba(0,0,0,0.02);
    border: 1px solid rgba(0,0,0,0.05); height: 100%; z-index: 1;
    background-color: #f1f3f4;
  }

  /* ── Desktop map tap-to-engage overlay ────────────────────────────
     Translucent panel that covers the map until the user explicitly
     clicks it.  Prevents scroll-wheel-zoom from hijacking the page
     scroll for visitors who are just passing through.  Dismissed
     for the rest of the session on tap; refresh restores it.
     Hidden on mobile (mobile uses its own full-dashboard overlay
     at the .tenki-explore-overlay level). */
  .tenki-desktop-map-overlay {
    position: absolute;
    inset: 0;
    z-index: 50;          /* above leaflet (z:1), below floating-nav */
    display: flex;
    align-items: center;
    justify-content: center;
    border: none;
    padding: 24px;
    background: linear-gradient(135deg,
                rgba(238, 245, 251, 0.82) 0%,
                rgba(252, 252, 252, 0.78) 50%,
                rgba(238, 245, 251, 0.82) 100%);
    backdrop-filter: blur(4px) saturate(1.05);
    -webkit-backdrop-filter: blur(4px) saturate(1.05);
    cursor: pointer;
    border-radius: 12px;
    transition: opacity 0.35s ease, visibility 0s linear 0.35s;
    -webkit-tap-highlight-color: transparent;
    font-family: inherit;
  }
  .tenki-desktop-map-overlay.dismissed {
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
  }
  .tenki-desktop-map-overlay-card {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 10px;
    padding: 28px 36px;
    background: var(--tenki-white);
    border-radius: 14px;
    box-shadow: 0 14px 40px rgba(0, 90, 156, 0.18);
    border-top: 5px solid var(--tenki-blue);
    max-width: 380px;
    text-align: center;
    pointer-events: none;
    transform: translateY(0);
    animation: tenkiDesktopMapBob 3.4s ease-in-out infinite;
  }
  .tenki-desktop-map-overlay:hover .tenki-desktop-map-overlay-card {
    box-shadow: 0 16px 48px rgba(0, 90, 156, 0.26);
  }
  .tenki-desktop-map-overlay-icon {
    font-size: 2.2rem;
    line-height: 1;
    animation: tenkiDesktopMapPulse 1.9s ease-in-out infinite;
  }
  .tenki-desktop-map-overlay-title {
    font-size: 1.05rem;
    font-weight: 800;
    color: var(--tenki-blue);
    letter-spacing: 0.3px;
  }
  .tenki-desktop-map-overlay-sub {
    font-size: 0.82rem;
    color: var(--text-light);
    font-weight: 600;
    line-height: 1.4;
    max-width: 280px;
  }
  @keyframes tenkiDesktopMapBob {
    0%, 100% { transform: translateY(0); }
    50%      { transform: translateY(-4px); }
  }
  @keyframes tenkiDesktopMapPulse {
    0%, 60%, 100% { transform: scale(1); opacity: 0.92; }
    30%           { transform: scale(1.10); opacity: 1; }
  }
  @media (prefers-reduced-motion: reduce) {
    .tenki-desktop-map-overlay-card { animation: none; }
    .tenki-desktop-map-overlay-icon  { animation: none; }
  }

  /* Desktop Map Sidebar Detail View */
  .map-details-sidebar {
    background-color: var(--tenki-white); border-radius: 12px; padding: 18px;
    box-shadow: 0 4px 15px rgba(0,0,0,0.02); display: flex; flex-direction: column;
    border: 1px solid rgba(0,0,0,0.05); overflow-y: auto; min-height: 0;   /* shrink + scroll inside the elastic grid instead of forcing it taller */
  }

  .details-placeholder { margin: auto; color: var(--text-light); padding: 6px 4px; }
  .details-placeholder svg { width: 50px; height: 50px; fill: #CCCCCC; margin-bottom: 12px; }

  /* Welcome card — first-load state of the sidebar before any event /
     pin is selected.  Replaces the previously-empty placeholder that
     only had a single sentence "Select an event…" line — now reads as
     an actual intro to the section. */
  .placeholder-welcome { text-align: left; line-height: 1.5; }
  .placeholder-eyebrow {
    font-size: 0.7rem; font-weight: 800; letter-spacing: 1.2px;
    text-transform: uppercase; color: var(--tenki-blue);
    margin-bottom: 8px;
  }
  .placeholder-title {
    font-size: 1.25rem; font-weight: 800; color: var(--tenki-black);
    margin: 0 0 12px 0; letter-spacing: 0.2px;
  }
  .placeholder-blurb {
    font-size: 0.92rem; color: var(--text-light);
    margin: 0 0 18px 0;
  }
  .placeholder-stats {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 10px;
    margin-bottom: 18px;
  }
  .placeholder-stat {
    background: var(--bg-light);
    border-left: 3px solid var(--tenki-blue);
    border-radius: 4px;
    padding: 10px 12px;
    text-align: center;
  }
  .placeholder-stat-num {
    display: block; font-size: 1.4rem; font-weight: 800;
    color: var(--tenki-black); line-height: 1.1;
  }
  .placeholder-stat-label {
    display: block; font-size: 0.7rem; font-weight: 700;
    text-transform: uppercase; letter-spacing: 0.6px;
    color: var(--text-light); margin-top: 4px;
  }
  .placeholder-cta-row {
    border-top: 1px dashed rgba(0,0,0,0.1);
    padding-top: 14px;
    margin-top: 4px;
  }
  .placeholder-cta-hint {
    font-size: 0.85rem; color: var(--text-light); margin: 0;
    display: flex; align-items: flex-start; gap: 8px;
  }
  .placeholder-pin {
    flex-shrink: 0; font-size: 1.05rem; line-height: 1.3;
  }

  .details-content-view { display: none; flex-direction: column; height: 100%; }
  .details-content-view.active { display: flex; }

  .details-content-view h3 { margin: 0 0 4px 0; font-size: 1.1rem; color: var(--text-dark); }
  .details-region { font-size: 0.78rem; font-weight: 600; color: var(--text-light); margin-bottom: 9px; text-transform: uppercase; letter-spacing: 0.3px; }
  .details-content-view p { margin: 0 0 12px 0; font-size: 0.9rem; line-height: 1.5; color: var(--text-light); }

  /* Desktop Floating Nav */
  .floating-nav-container {
    display: flex;
    position: absolute;
    bottom: 30px;
    left: 30px;
    z-index: 1000;
    flex-direction: column;
    animation: expandFadeIn 0.3s ease;
  }

  .floating-controls-group { display: flex; align-items: center; gap: 8px; }
  /* Prev / next event-cycling arrows.  Previously hidden on desktop
     (only the All Tracks button showed); user wants them surfaced so
     they can step through pins / events alongside the dropdown.  Mobile
     CSS at @media (max-width: 768px) takes over with its own sizing. */
  .nav-arrow {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 38px;
    height: 38px;
    border-radius: 50%;
    border: 1px solid rgba(0, 0, 0, 0.08);
    background: var(--tenki-white);
    color: var(--tenki-black);
    font-size: 1.05rem;
    font-weight: 800;
    cursor: pointer;
    box-shadow: 0 3px 10px rgba(0, 0, 0, 0.12);
    transition: transform .15s ease, background .15s ease, color .15s ease;
  }
  .nav-arrow:hover {
    background: var(--tenki-blue);
    color: var(--tenki-white);
    transform: translateY(-1px);
  }
  .nav-arrow:disabled {
    opacity: 0.4;
    cursor: not-allowed;
    box-shadow: none;
  }

  .all-tracks-reset-btn {
    background: var(--tenki-black); color: var(--tenki-white); border: none;
    padding: 10px 20px; border-radius: 30px; font-weight: 700; font-size: 0.85rem;
    text-transform: uppercase; box-shadow: 0 4px 15px rgba(0,0,0,0.18);
    cursor: pointer; display: flex; align-items: center; gap: 10px;
    transition: transform 0.2s ease, background-color 0.2s ease;
  }
  .all-tracks-reset-btn:hover { background: #333; transform: translateY(-2px); }
  .all-tracks-reset-btn img { height: 18px; width: auto; object-fit: contain; border-radius: 2px; }
  .all-tracks-reset-btn svg { transition: transform 0.3s ease; }
  .floating-nav-container.menu-open .all-tracks-reset-btn svg { transform: rotate(180deg); }

  .floating-nav-menu {
    /* Dropdown opens UP-LEFT from the All Tracks button.  Pinning
       BOTH left:0 and a sensible max-width keeps it inside the
       viewport even when the all-tracks button is near the right
       edge of the screen on mobile.  JS in `openFloatingNavMenu`
       flips it to `right: 0; left: auto` when the button's left
       edge is within (menu-width + 16px) of the viewport's right
       edge — preventing the off-screen render the user reported. */
    position: absolute; bottom: calc(100% + 10px); left: 0; background: var(--tenki-white);
    border-radius: 12px; box-shadow: 0 8px 25px rgba(0,0,0,0.15); padding: 8px 0;
    display: flex; flex-direction: column; min-width: 240px; max-width: calc(100vw - 32px);
    max-height: 55vh; overflow-y: auto;
    scrollbar-width: thin; opacity: 0; pointer-events: none; transform: translateY(10px);
    transition: all 0.2s ease; border: 1px solid rgba(0,0,0,0.05);
  }
  /* Right-pinned variant — when JS detects the button is too close to
     the viewport's right edge, this class flips the dropdown so it
     opens leftward instead of rightward. */
  .floating-nav-menu.is-right-pinned { left: auto; right: 0; }
  .floating-nav-menu::-webkit-scrollbar { width: 6px; }
  .floating-nav-menu::-webkit-scrollbar-thumb { background-color: rgba(0,0,0,0.1); border-radius: 4px; }
  .floating-nav-container.menu-open .floating-nav-menu { opacity: 1; pointer-events: auto; transform: translateY(0); }

  .floating-nav-item {
    padding: 12px 20px; font-size: 0.85rem; font-weight: 700; color: var(--text-dark);
    cursor: pointer; transition: background 0.2s; display: flex; align-items: center; gap: 10px;
  }
  .floating-nav-item:hover { background: var(--bg-light); color: var(--tenki-blue); }
  .floating-nav-item.sub-track { padding-left: 42px; font-size: 0.78rem; font-weight: 600; color: var(--text-light); padding-top: 8px; padding-bottom: 8px; }

  /* Map Markers — teardrop pin shape (was circles).  The .custom-map-pin
     wrapper just sizes + animates; the actual pin visual is an inline
     SVG injected via the Leaflet divIcon's HTML (see buildPinSVG() in
     the JS block below).  Track color is baked into the SVG fill at
     build-marker time — no CSS variables on the body, which is needed
     because SVG fill attributes don't reliably resolve var() in older
     WebKit (we hit this in the mini-map drawer originally).  Drop-
     shadow filter follows the actual pin alpha so the shadow hugs the
     teardrop edge rather than a phantom square. */
  .custom-map-pin {
    width: 24px; height: 32px;
    transition: transform 0.18s ease, filter 0.18s ease;
    filter: drop-shadow(0 3px 5px rgba(0,0,0,0.3));
    transform-origin: 50% 100%;     /* scale from the pin's POINT, not center */
  }
  .custom-map-pin svg { display: block; width: 100%; height: 100%; }
  /* Track-color classes kept for backwards compatibility with the
     activeMapPin() helper that may still toggle them — the SVG fill
     drives the actual color, but other code paths still flip these
     class names.  No paint impact since the SVG carries the color. */
  .pin-blue, .pin-green, .pin-white, .pin-black { /* color in SVG */ }

  /* ── Diagonal SVG connector from spine-positioned node to card top
       — desktop-only.  In default view, the node sits at the actual
       date position on the spine (might be far from the block's flex
       slot) while the card body stays at its evenly-spaced flex
       position.  Without a visible connector the two read as
       disconnected; this dashed line traces the relationship. */
  .node-card-connector { display: none; }
  @media (min-width: 769px) {
    .node-card-connector { display: block; color: var(--tenki-black); }
    .node-card-connector.node-blue  { color: var(--tenki-blue); }
    .node-card-connector.node-green { color: var(--tenki-green); }
    .node-card-connector.node-white { color: var(--tenki-white-stroke); }
    .node-card-connector.node-black { color: var(--tenki-black); }
    /* Hide the connector in map-expanded mode — the cards are then
       just title-chips and the spine is hidden, so there's nothing
       meaningful to connect. */
    .dashboard-container.map-expanded .node-card-connector { display: none; }
    /* Hover / active / focused: the line stays DASHED (user feedback:
       "all connectors should have the dotted line feature") — earlier
       version flipped to solid at this state, which made the black
       Tenki Organization track read as a solid line.  We just brighten
       opacity + thicken stroke so the connector still emphasizes
       attention. */
    .timeline-block:hover .node-card-connector line,
    .timeline-block.active .node-card-connector line,
    .timeline-block.focused .node-card-connector line {
      opacity: 0.95;
      stroke-width: 2.8;
    }
  }
  .custom-map-pin.active-pin {
    transform: scale(1.35);
    filter: drop-shadow(0 6px 10px rgba(0,0,0,0.42));
    z-index: 1000 !important;
  }

  /* ── Marker cluster styling — white circle, dark count, colored border
     where border tone reflects the most-common track in the cluster.
     Class names follow Leaflet.markercluster's convention; we override
     the defaults so the badge reads as Tenki-branded.  The inline
     iconCreateFunction (see JS) sets data-track-* attributes which
     these selectors hook into for border color. */
  .tenki-cluster {
    background: #fff;
    border-radius: 50%;
    width: 38px !important;
    height: 38px !important;
    line-height: 38px;
    text-align: center;
    font-family: 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
    font-weight: 800;
    font-size: 0.95rem;
    color: var(--tenki-black);
    border: 3px solid var(--tenki-black);
    box-shadow: 0 3px 8px rgba(0,0,0,0.22), 0 0 0 1.5px rgba(255,255,255,0.9);
    transition: transform 0.15s ease;
  }
  .tenki-cluster:hover { transform: scale(1.08); }
  .tenki-cluster[data-track="blue"]  { border-color: var(--tenki-blue);  }
  .tenki-cluster[data-track="green"] { border-color: var(--tenki-green); }
  .tenki-cluster[data-track="black"] { border-color: var(--tenki-black); }
  .tenki-cluster[data-track="white"] { border-color: #888; }
  /* Suppress markercluster default styles — the .marker-cluster wrapper
     has its own bg color we don't want; only our inner .tenki-cluster
     should show. */
  .leaflet-marker-icon.marker-cluster,
  .leaflet-marker-icon.marker-cluster div {
    background: transparent !important;
    box-shadow: none !important;
    border: 0 !important;
  }

  .tag-container { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; flex: 1 1 auto;}
  .details-tag {
    font-size: 0.72rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.5px;
    padding: 3px 8px; border-radius: 4px; display: inline-block; align-self: flex-start;
  }
  .tag-blue { background-color: var(--tenki-blue-light); color: var(--tenki-blue); }
  .tag-green { background-color: var(--tenki-green-light); color: var(--tenki-green); }
  .tag-white { background-color: var(--tenki-white-light); color: var(--tenki-white-stroke); border: 1px solid var(--tenki-white-border); }
  .tag-black { background-color: #F4F4F4; color: var(--tenki-black); }

  .locations-list-container { margin: 15px 0; padding: 12px; background: rgba(0,0,0,0.02); border-radius: 8px; border-left: 3px solid var(--timeline-line); }
  .locations-list-container h4 { margin: 0 0 8px 0; font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.5px; color: var(--text-light); }
  .locations-list { margin: 0; padding-left: 20px; font-size: 0.85rem; color: var(--text-dark); max-height: 180px; overflow-y: auto; }
  .locations-list li { margin-bottom: 4px; }
  .locations-list li.interactive-loc { cursor: pointer; text-decoration: underline; text-decoration-color: transparent; transition: all 0.2s ease; }
  .locations-list li.interactive-loc:hover { color: var(--tenki-blue); text-decoration-color: var(--tenki-blue); }

  .details-cta-group { margin-top: auto; padding-top: 15px; display: flex; flex-direction: column; gap: 10px; width: 100%; }
  .details-cta-link {
    display: block; width: 100%; padding: 12px;
    background-color: var(--tenki-black); color: var(--tenki-white); text-align: center; text-decoration: none;
    font-weight: 700; font-size: 0.88rem; text-transform: uppercase; letter-spacing: 0.5px; border-radius: 6px;
    transition: all 0.2s ease;
  }
  .details-cta-link.link-blue { background-color: var(--tenki-blue); }
  .details-cta-link.link-green { background-color: var(--tenki-green); }
  .details-cta-link.link-white { background-color: var(--tenki-white-stroke); color: var(--tenki-white); }
  .details-cta-link.secondary-btn { background-color: transparent; color: var(--text-dark); border: 2px solid var(--timeline-line); }
  .details-cta-link.secondary-btn:hover { border-color: var(--tenki-black); color: var(--tenki-black); }

  /* Desktop Timeline Horizontal Rail Section */
  .timeline-outer-wrapper { position: relative; width: 100%; order: 4; overflow: hidden; z-index: 10; }

  /* Mobile-only compact list view (the new Simplified view, 2026-05-29).
     Hidden by default / on desktop — only the mobile @media block + the
     .list-view container class flip it on (see rule near the .tenki-prev-*
     styles). */
  .tenki-mobile-list { display: none; }

  .scroll-btn {
    display: none; align-items: center; justify-content: center; position: absolute;
    top: 50%; transform: translateY(-50%); width: 44px; height: 44px;
    background-color: var(--tenki-white); border: 2px solid var(--timeline-line); border-radius: 50%;
    cursor: pointer; z-index: 20; box-shadow: 0 4px 10px rgba(0,0,0,0.05); transition: all 0.2s ease;
  }
  .scroll-btn svg { width: 24px; height: 24px; fill: var(--text-light); transition: fill 0.2s ease; }
  .scroll-btn:hover { background-color: var(--tenki-black); border-color: var(--tenki-black); }
  .scroll-btn:hover svg { fill: var(--tenki-white); }
  .prev-btn { left: -22px; }
  .next-btn { right: -22px; }
  @media (min-width: 769px) { .scroll-btn { display: flex; } }

  .timeline-scroll-wrapper {
    overflow-x: auto;
    /* Explicitly allow vertical ink-overflow so hover-expanded event
       cards (z-index:50) can paint OVER the map below them.  Modern
       Chrome / Safari respect this combo (overflow-x:auto + overflow-y:
       visible) as "scroll horizontally, paint outside vertically" —
       Firefox may treat overflow-y as auto, in which case the JS
       fallback in timeline-block:hover handlers escalates the card to
       position:fixed so it still escapes the clipping ancestor. */
    overflow-y: visible;
    /* Asymmetric padding (2026-05-29 round 3 — full audit of the
       cards→map gap):
         padding-top: 25 px    spine + year-divider bubbles sit at the
                               top of the track, so the slack above is
                               structural — don't trim.
         padding-bottom: 0     the bottom slack was purely decorative
                               and contributed ~25 px of dead space
                               between the card bottom edge and the
                               map top edge.  Was 25, then 25 (I left
                               it), now zero — card bottom now butts
                               against the map's drop-shadow.
         margin-bottom: 0      was 40 → 10 → now 0 for the same reason.
       The visual separation between the two rows now comes solely
       from the map's drop-shadow + 1 px border. */
    padding: 25px 10px 0; scrollbar-width: none;
    -webkit-overflow-scrolling: touch; margin-bottom: 0;
    touch-action: pan-y pinch-zoom; scroll-padding-left: 20px; cursor: grab;
  }
  .timeline-scroll-wrapper::-webkit-scrollbar { display: none; }
  .timeline-scroll-wrapper.is-dragging { cursor: grabbing; user-select: none; }

  .timeline-track { display: flex; gap: 25px; position: relative; padding-top: 65px; min-width: max-content; }
  .timeline-track::before { content: ''; position: absolute; height: 4px; background-color: var(--timeline-line); top: 40px; left: 0; right: 0; z-index: 1; }
  /* Detailed view (Option A): the spine carried ~65px of dead space above it
     (track padding-top 65 + scroll padding-top 25), reading as a large gap
     between the filter buttons and the timeline.  Pull the spine + cards up,
     keeping the spine→card offset (track padding-top − spine top = 25px). */
  .dashboard-container:not(.simplified-view) .timeline-scroll-wrapper { padding-top: 6px !important; }
  .dashboard-container:not(.simplified-view) .timeline-track { padding-top: 36px !important; }
  .dashboard-container:not(.simplified-view) .timeline-track::before { top: 11px !important; }
  /* Detailed view: drop the floating "← All Tracks →" cluster.  It's absolutely
     positioned over the map (bottom/left, z-index 1000) and ate map space without
     real value here — you navigate by clicking pins/cards in this view.  The
     simplified-view carousel still uses it, so this is scoped to detailed only. */
  .dashboard-container:not(.simplified-view) #floating-nav-container { display: none !important; }

  /* ════════ Desktop Simplified = activity list + right-side map drawer ════════
     (2026-06-20) The desktop Simplified view is now a compact, scannable list
     (parity with mobile) instead of the titles-only carousel.  The main map is
     re-cast as a right-side slide-in drawer — JS moves #dashboard-map to <body>
     while in list-view so position:fixed anchors to the viewport (Squarespace
     section transforms would otherwise trap it).  Detailed view is unchanged. */
  @media (min-width: 769px) {
    .dashboard-container.list-view .timeline-outer-wrapper { display: none !important; }
    .dashboard-container.list-view #floating-nav-container { display: none !important; }
    .dashboard-container.list-view #dashboard-map { display: none; }   /* moved to <body> by JS; guards a pre-JS flash */

    /* Explicit flex order — the container's flex column orders its children
       (header:1 · state:2 · controls:3).  Without an order here the toolbar
       + list default to order:0 and sort BEFORE the header, which stranded
       "OUR JOURNEY & FOOTPRINT" + the filter chips at the BOTTOM of the
       section (user-reported).  4/5 puts them after the header + chips. */
    .dashboard-container.list-view #tenki-list-toolbar { order: 4; display: flex; justify-content: flex-end; align-items: center; gap: 10px; max-width: 880px; margin: 0 auto 8px; padding: 0 12px; width: 100%; box-sizing: border-box; }
    .tenki-list-toolbar button { display: inline-flex; align-items: center; gap: 6px; font-weight: 600; font-size: 0.88rem; padding: 9px 16px; border-radius: 999px; border: 1.5px solid #cbd5e1; background: #fff; color: #334155; cursor: pointer; transition: border-color .15s ease, color .15s ease, background .15s ease; }
    .tenki-list-toolbar button:hover { border-color: var(--tenki-blue); color: var(--tenki-blue); }
    .tenki-list-toolbar #tenki-list-mapbtn { border-color: var(--tenki-blue); color: var(--tenki-blue); background: #eef6fc; }
    body.tenki-listmap-open .tenki-list-toolbar #tenki-list-mapbtn { background: var(--tenki-blue); color: #fff; }

    .dashboard-container.list-view .tenki-mobile-list { order: 5; display: block; width: 100%; max-width: 880px; margin: 0 auto; padding: 2px 12px 44px; box-sizing: border-box; }
    .dashboard-container.list-view .tenki-mlist-rail { position: relative; display: flex; flex-direction: column; gap: 10px; padding-left: 0; }
    .dashboard-container.list-view .tenki-mlist-rail::before { display: none; }
    .dashboard-container.list-view .tenki-mlist-row { background: #fff; border: 1px solid #e6e9ef; border-left: 4px solid #1A1A1A; border-radius: 12px; overflow: hidden; transition: box-shadow .18s ease, transform .18s ease; }
    .dashboard-container.list-view .tenki-mlist-row:hover { box-shadow: 0 6px 20px rgba(0,0,0,.09); transform: translateY(-1px); }
    .dashboard-container.list-view .tenki-mlist-row[data-track="blue"]  { border-left-color: var(--tenki-blue); }
    .dashboard-container.list-view .tenki-mlist-row[data-track="green"] { border-left-color: var(--tenki-green); }
    .dashboard-container.list-view .tenki-mlist-row[data-track="black"] { border-left-color: var(--tenki-black); }
    .dashboard-container.list-view .tenki-mlist-row[data-track="white"] { border-left-color: var(--tenki-white-border); }
    .dashboard-container.list-view .tenki-mlist-head { display: flex; align-items: center; gap: 12px; padding: 14px 18px; cursor: pointer; }
    .dashboard-container.list-view .tenki-mlist-dot { width: 10px; height: 10px; border-radius: 50%; flex: 0 0 auto; }
    .dashboard-container.list-view .tenki-mlist-icon { font-size: 1.15rem; line-height: 1; flex: 0 0 auto; }
    .dashboard-container.list-view .tenki-mlist-title { flex: 1 1 auto; min-width: 0; font-weight: 700; font-size: 1.02rem; color: #1A1A1A; }
    .dashboard-container.list-view .tenki-mlist-date { flex: 0 0 auto; font-size: 0.85rem; color: #64748b; white-space: nowrap; }
    .dashboard-container.list-view .tenki-mlist-chevron { flex: 0 0 auto; display: flex; color: #94a3b8; transition: transform .2s ease; }
    .dashboard-container.list-view .tenki-mlist-row.expanded .tenki-mlist-chevron { transform: rotate(180deg); }
    .dashboard-container.list-view .tenki-mlist-body { display: none; flex-direction: column; gap: 10px; padding: 0 18px 16px; }
    .dashboard-container.list-view .tenki-mlist-row.expanded .tenki-mlist-body { display: flex; }
    .dashboard-container.list-view .tenki-mlist-meta { display: flex; flex-wrap: wrap; gap: 6px 14px; font-size: 0.82rem; color: #64748b; }
    .dashboard-container.list-view .tenki-mlist-desc { margin: 0; font-size: 0.95rem; line-height: 1.6; color: #334155; }
    .dashboard-container.list-view .tenki-mlist-cta { align-self: flex-start; padding: 8px 16px; border-radius: 8px; background: var(--tenki-blue); color: #fff; text-decoration: none; font-size: 0.88rem; font-weight: 600; }
    .dashboard-container.list-view .tenki-mlist-row[data-track="green"] .tenki-mlist-cta { background: var(--tenki-green); }
    .dashboard-container.list-view .tenki-mlist-row[data-track="black"] .tenki-mlist-cta { background: var(--tenki-black); }
  }
  .tenki-list-toolbar { display: none; }

  /* Map drawer — #dashboard-map is moved to <body> in desktop list-view.
     body.tenki-listmap = drawer mounted (off-screen); .tenki-listmap-open = shown.
     Inset below the top of the viewport (top: 64px) so the section's
     "Detailed view | Map" toggle pills stay visible + clickable while the
     drawer is open — it used to cover the very control that opened it. */
  body.tenki-listmap #dashboard-map {
    position: fixed; top: 64px; right: 0; height: calc(100vh - 64px); width: min(540px, 92vw);
    z-index: 100000; background: #fff; box-shadow: -10px 0 40px rgba(0,0,0,.22);
    display: block; grid-template-columns: 1fr;
    border-radius: 14px 0 0 0;
    transform: translateX(100%); transition: transform .33s cubic-bezier(.4,0,.2,1);
  }
  body.tenki-listmap.tenki-listmap-open #dashboard-map { transform: translateX(0); }
  body.tenki-listmap #dashboard-map .map-details-sidebar,
  body.tenki-listmap #dashboard-map #map-expand-toggle,
  body.tenki-listmap #dashboard-map #tenki-desktop-map-overlay { display: none !important; }
  body.tenki-listmap #dashboard-map .map-canvas-wrap { width: 100%; height: 100%; }
  body.tenki-listmap #leaflet-map-canvas { width: 100%; height: calc(100vh - 64px) !important; }
  .tenki-listmap-backdrop { position: fixed; inset: 0; background: rgba(15,23,42,.42); z-index: 99999; opacity: 0; pointer-events: none; transition: opacity .3s ease; }
  body.tenki-listmap-open .tenki-listmap-backdrop { opacity: 1; pointer-events: auto; }
  .tenki-listmap-close { position: fixed; top: 74px; right: 14px; z-index: 100001; width: 40px; height: 40px; border-radius: 50%; border: none; background: rgba(255,255,255,.96); box-shadow: 0 2px 12px rgba(0,0,0,.25); color: #334155; font-size: 1.3rem; line-height: 1; cursor: pointer; display: none; }
  body.tenki-listmap-open .tenki-listmap-close { display: flex; align-items: center; justify-content: center; }
  /* Drawer context header — names what the map is showing (the selected
     event, else the whole footprint) so the drawer never opens anonymous.
     Sits above the Leaflet panes (their controls top out ~z 1000). */
  #tenki-listmap-header {
    position: absolute; top: 10px; left: 10px; max-width: calc(100% - 120px);
    z-index: 1200; pointer-events: none;
    background: rgba(255,255,255,.95); border-radius: 10px;
    box-shadow: 0 2px 10px rgba(0,0,0,.18);
    padding: 8px 14px;
    font-weight: 800; font-size: .92rem; color: #00243f;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  /* ── Month tick marks ────────────────────────────────────────────────
     Bold-enough notches at every month boundary along the spine so the
     eye can read elapsed time at a glance.  Quarter marks (Jan/Apr/Jul/
     Oct = months 0/3/6/9) are noticeably longer + darker so quarters
     pop.  Year boundaries (month 0) are skipped here — the year-badge
     pill serves that role.  Pointer-events: none so they never block
     clicks on events / spine. */
  .tl-month-tick {
    position: absolute;
    width: 2px;
    height: 14px;
    top: 33px;                  /* crosses the spine (top:40, height:4) */
    /* Tinted with the spine's own colour (Tenki blue) so the ticks
       feel part of the timeline rather than a separate gray sub-grid.
       Was rgba(0,0,0,0.42). */
    background: rgba(0, 90, 156, 0.45);
    pointer-events: none;
    z-index: 0;                 /* under everything; spine cuts through it */
    border-radius: 1px;
  }
  .tl-month-tick.is-quarter {
    width: 2px;
    height: 22px;
    top: 29px;
    background: rgba(0, 90, 156, 0.75);  /* darker variant for quarter ticks */
  }

  .year-divider { position: relative; flex: 0 0 60px; display: flex; justify-content: center; scroll-snap-align: start; }
  .year-badge {
    position: absolute; top: -37px; background-color: var(--tenki-black); color: var(--tenki-white);
    font-weight: 800; font-size: 1.05rem; padding: 6px 16px; border-radius: 20px; z-index: 5;
    letter-spacing: 1px; box-shadow: 0 4px 10px rgba(0,0,0,0.15); cursor: pointer; transition: all 0.2s;
  }
  .year-badge:hover { opacity: 0.8; }

  .timeline-block {
    position: relative; flex: 0 0 290px; transition: opacity 0.3s ease; scroll-snap-align: start; cursor: pointer;
  }
  .timeline-block:focus-visible { outline: 3px solid var(--tenki-blue); outline-offset: 4px; border-radius: 10px; }
  .timeline-block * { pointer-events: none; }
  .timeline-block .details-cta-group *, .timeline-block .locations-list-container *, .timeline-block .funding-badge, .timeline-block .share-btn, .timeline-block .click-indicator { pointer-events: auto; }

  /* ── Event marker (node) ─────────────────────────────────────────────
     The colored circle that anchors each event to the spine.  Resized
     down to 12 px (was 18) + 3 px ring (was 4) so it matches the new
     month-tick scale — a giant 26 px outer-diameter node dwarfed the
     spine and made the timeline read as crowded.  --node-color is the
     CSS custom property that drives both the border color and the
     stem-to-card connector below.  Each .node-* class overrides it. */
  .timeline-node {
    --node-color: var(--tenki-black);
    width: 12px; height: 12px; position: absolute; border-radius: 50%;
    background-color: var(--tenki-white); border: 3px solid var(--node-color);
    /* left:20 puts the outer-circle center at x=29 — the same x the
       JS-driven .duration-dot (left:24 + 5 = 29) and .duration-stem
       (left:27 + 2 = 29) center on, so node + dot + stem now share
       a single vertical axis instead of being 4 px out of phase. */
    top: -33px; left: 20px; z-index: 3;
    transition: transform 0.2s ease, background-color 0.2s ease;
    pointer-events: auto !important;
  }
  .timeline-node.node-blue  { --node-color: var(--tenki-blue); }
  .timeline-node.node-green { --node-color: var(--tenki-green); }
  .timeline-node.node-black { --node-color: var(--tenki-black); }
  .timeline-node.node-white { --node-color: var(--tenki-white-stroke); }

  /* The OLD vertical stem (a 2 px straight line dropping from the node
     to the card top) is RETIRED for desktop — the SVG diagonal
     `.node-card-connector` now handles that visual relationship, which
     correctly anchors to the spine-positioned node regardless of where
     the card sits in its flex slot.  Hidden on desktop; mobile still
     uses it (since on mobile cards stack vertically below their node
     and a straight stem is the right shape).
     The CSS rules below were the old stem; they remain so mobile keeps
     its behavior.  Desktop-specific override at the top of the file
     hides the pseudo-element. */
  @media (min-width: 769px) {
    .timeline-node::after { display: none !important; }
  }
  .timeline-node::after {
    content: '';
    position: absolute;
    top: calc(100% + 3px);      /* just below the node ring                       */
    left: 50%;
    transform: translateX(-50%);
    width: 2px;
    height: 13px;               /* lands flush on the card's 5 px top border-color */
    background: var(--node-color);
    opacity: 0.55;
    border-radius: 1px;
    transition: height 0.2s ease, opacity 0.2s ease, width 0.2s ease;
    pointer-events: none;
  }
  .timeline-block:hover .timeline-node::after {
    opacity: 0.85;
    width: 3px;
  }
  .timeline-block.active .timeline-node::after,
  .timeline-block.focused .timeline-node::after {
    opacity: 1;
    width: 3px;
    height: 15px;               /* extends slightly into the card top border-color */
  }

  .timeline-block.focused .timeline-node, .timeline-block.active .timeline-node { transform: scale(1.35); background-color: var(--node-color); }

  .timeline-card {
    background-color: var(--tenki-white); border-radius: 10px; padding: 12px 14px 14px;
    box-shadow: 0 4px 12px rgba(0,0,0,0.03); border-top: 5px solid var(--tenki-black);
    display: flex; flex-direction: column;
    /* height: auto (default) — card sizes to its content so the new
       lean layout (time-marker + title + chip row + optional location
       button) reads as a tight unit instead of being stretched up to
       the row's tallest sibling.  Block stretch is removed below via
       align-self: flex-start on the block itself. */
    transition: transform 0.3s ease, box-shadow 0.3s ease;
  }

  /* ── Track icon (declutter pass) ─────────────────────────────────────
     A small per-track glyph (🩺 / 📚 / 🌱 / 🏢) rendered just before
     the event title.  Pairs with the track-color top border so viewers
     who don't yet know the colour code still get a visual hint about
     which pillar the event belongs to.  Sits to the left of the title
     in BOTH .timeline-card h3 and .expanded-title-card .etc-title. */
  .tenki-track-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.25em;
    height: 1.25em;
    margin-right: 6px;
    font-size: 1em;
    line-height: 1;
    vertical-align: -0.05em;
    flex-shrink: 0;
  }
  .timeline-card h3 .tenki-track-icon,
  .expanded-title-card .etc-title .tenki-track-icon {
    /* keep the glyph aligned with the title's baseline so a long title
       wrapping to a second line doesn't drag the icon downward. */
    align-self: flex-start;
  }

  /* ── Declutter: drop the phase/funding badge row from the timeline
     card so the SAME info doesn't render twice (it's already on the
     sidebar detail card to the right + on the expanded-title card
     when in simplified mode).  Track is now conveyed by icon + color.
     Badges still show in the .mobile-inline-details block on phones
     (where the sidebar doesn't render). */
  @media (min-width: 769px) {
    /* 2026-05-28 redesign (round 3): chips live ON the activity card
       now (tag + phase + funding) instead of in the sidebar.  The card
       becomes "title + date + chips" — clean, glance-able.  The verbose
       description was merged into the sidebar text so the card body is
       just chrome metadata.  See the JS render block for the markup
       change. */
    .timeline-card .card-badge-row {
      margin-bottom: 8px;       /* tighter than the original 10 */
      gap: 6px;                 /* tighter chips */
      align-items: center;
    }
    .timeline-card .card-badge-row .phase-badge,
    .timeline-card .card-badge-row .funding-badge,
    .timeline-card .card-badge-row .details-tag {
      font-size: 0.6rem;        /* the card real-estate is tight */
      padding: 3px 7px;
      letter-spacing: 0.3px;
    }
  }
  .card-blue-track { border-top-color: var(--tenki-blue); }
  .card-green-track { border-top-color: var(--tenki-green); }
  .card-white-track { border-top-color: var(--tenki-white-stroke); border-top-style: dashed; }
  .card-black-track { border-top-color: var(--tenki-black); }

  /* Active card: stays in place (no transform lift) — outline + soft
     shadow defined in the desktop @media block above handle the
     selected-state affordance.  Removed the translateY(-4px) that
     used to nudge the card up on selection — it caused layout shift
     + interacted poorly with the no-hover design. */
  .timeline-block.active .timeline-card { box-shadow: 0 8px 20px rgba(0,0,0,0.08); }

  .card-badge-row { display: flex; justify-content: space-between; align-items: flex-start;
                     margin-bottom: 10px; width: 100%;
                     gap: 14px;          /* bumped 10 → 14 so share-btn never visually kisses the right-most badge */
                     min-width: 0; }     /* allow children to shrink properly */
  .card-badge-row > div { min-width: 0; flex: 1 1 auto; }   /* tag wrapper shrinks too */
  .card-badge-row .share-btn {
    flex-shrink: 0;
    /* Tighter padding + label suppressed at narrow card widths so the
       button doesn't muscle into the badge column.  See media query
       below for the responsive trim. */
    padding: 3px 6px;
    align-self: flex-start;
  }
  /* Narrow desktop cards (~210 px collapsed): hide the "Share" label,
     keep just the icon — eliminates the cramping where the long
     funding-badge text + "Share" label fought for the same row. */
  @media (min-width: 769px) {
    .timeline-block:not(.active):not(.focused) .card-badge-row .share-btn span {
      display: none;
    }
  }

  .phase-badge, .funding-badge {
    display: inline-block; font-size: 0.65rem; font-weight: 800; text-transform: uppercase;
    padding: 4px 8px; border-radius: 4px; letter-spacing: 0.5px;
    align-self: flex-start; text-decoration: none;
  }
  button.funding-badge { transition: transform 0.2s ease, box-shadow 0.2s ease; cursor: pointer; }
  button.funding-badge:hover { transform: translateY(-1px); box-shadow: 0 2px 6px rgba(0,0,0,0.08); }

  .share-btn {
    background: none; border: none; color: #555 !important; cursor: pointer;
    display: inline-flex !important; align-items: center; gap: 4px;
    font-size: 0.75rem; font-weight: 600; text-transform: uppercase;
    transition: color 0.2s, background 0.2s;
    padding: 4px 8px; border-radius: 4px;
    pointer-events: auto; visibility: visible !important; opacity: 1 !important;
  }
  .share-btn:hover { color: var(--tenki-blue) !important; background: var(--bg-light); }
  .share-btn:hover svg { fill: var(--tenki-blue) !important; }
  /* Belt-and-suspenders: force the inline SVG inside the share button to
     render at a guaranteed visible size + color even if a Squarespace global
     CSS rule tries to zero them out. */
  .share-btn svg { width: 16px !important; height: 16px !important;
                   display: inline-block !important; flex-shrink: 0;
                   color: #555 !important; }
  .share-btn svg path { fill: currentColor; }

  .phase-accomplished { background-color: var(--phase-accomplished-bg); color: var(--phase-accomplished-text); }
  .phase-planning { background-color: var(--phase-planning-bg); color: var(--phase-planning-text); }
  .phase-execution { background-color: var(--phase-execution-bg); color: var(--phase-execution-text); }
  .phase-future { background-color: var(--phase-future-bg); color: var(--phase-future-text); }

  .funding-seeking { background-color: #fff0f0; color: #d32f2f; border: 1px solid rgba(211, 47, 47, 0.2); }
  .funding-partial { background-color: #fff9e6; color: #e65100; border: 1px solid rgba(230, 81, 0, 0.2); }
  .funding-full { background-color: #e8f5e9; color: #2e7d32; border: 1px solid rgba(46, 125, 50, 0.2); }
  .funding-active { background-color: #e3f2fd; color: #0d47a1; font-weight: 900; border: 1px dashed #0d47a1; }

  .time-marker { font-size: 0.72rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.5px; margin-bottom: 6px; display: block;}

  /* ── Duration Span ─────────────────────────────── */
  .duration-span {
    margin-bottom: 8px; display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
  }
  .duration-dates {
    font-size: 0.68rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.4px;
    color: var(--text-light); display: flex; align-items: center; gap: 4px;
  }
  .duration-dates .dur-arrow { color: #bbb; }
  .duration-pill {
    font-size: 0.62rem; font-weight: 800; text-transform: uppercase; letter-spacing: 0.3px;
    padding: 2px 7px; border-radius: 10px; background: rgba(0,0,0,0.06); color: var(--text-light);
    white-space: nowrap;
  }
  .card-blue-track .duration-pill { background: var(--tenki-blue-light); color: var(--tenki-blue); }
  .card-green-track .duration-pill { background: var(--tenki-green-light); color: var(--tenki-green); }
  .card-white-track .duration-pill { background: var(--tenki-white-light); color: var(--tenki-white-stroke); border: 1px solid var(--tenki-white-border); }
  /* Chip duration suffix */
  .chip-duration { font-size: 0.72em; font-weight: 600; opacity: 0.7; margin-left: 4px; }

  /* ── Duration Line Extension (desktop: rightward, ABOVE the spine) ──────── */
  /* Track padding-top:65px, spine top:40px → block-relative spine = -25px.   */
  /* Lane 0 at -47px clears year-badge top (≈ -37px) by 5px — no overlap.    */
  /* Bar left/top/width are ALL overridden by updateDurationLines() per event. */
  /* Bar starts at event startDate track-position, ends at endDate position.   */
  .duration-line-ext {
    position: absolute;
    top: -47px;   /* lane-0 default; JS overrides per lane                      */
    left: 0;      /* JS sets to startDate track-pos relative to block left       */
    height: 7px;
    width: 0;     /* set dynamically                                             */
    border-radius: 4px;
    opacity: 0.75;
    transition: opacity 0.3s ease;
    pointer-events: none;
    z-index: 2;
  }
  /* Vertical stem: drops from bar bottom to the spine. left/top/height set by JS. */
  .duration-stem {
    position: absolute;
    width: 4px;
    border-radius: 0 0 3px 3px;
    opacity: 0.95;
    pointer-events: none;
    z-index: 3;
    /* Pull up 3 px so the stem overlaps the bottom of the duration bar
       — without this nudge the bar's translucent edge and the stem's
       fully-opaque top sit on adjacent pixel rows and read as a
       visual gap.  With the overlap they fuse cleanly. */
    margin-top: -3px;
  }
  /* Colored circle at spine level, anchoring bar to event node. left/top set by JS. */
  .duration-dot {
    position: absolute;
    width: 10px;
    height: 10px;
    border-radius: 50%;
    opacity: 0.9;
    pointer-events: none;
    z-index: 3;
  }
  .timeline-block[data-track="blue"]  .duration-line-ext,
  .timeline-block[data-track="blue"]  .duration-stem,
  .timeline-block[data-track="blue"]  .duration-dot  { background: var(--tenki-blue); }
  .timeline-block[data-track="green"] .duration-line-ext,
  .timeline-block[data-track="green"] .duration-stem,
  .timeline-block[data-track="green"] .duration-dot  { background: var(--tenki-green); }
  .timeline-block[data-track="black"] .duration-line-ext,
  .timeline-block[data-track="black"] .duration-stem,
  .timeline-block[data-track="black"] .duration-dot  { background: var(--tenki-black); }
  .timeline-block[data-track="white"] .duration-line-ext,
  .timeline-block[data-track="white"] .duration-stem,
  .timeline-block[data-track="white"] .duration-dot  { background: var(--tenki-white-stroke); }

  /* ── Ongoing bars (End Date = "Ongoing"/"present"/"now") ─────────────
     The trailing edge of an ongoing bar fades to transparent + pulses
     gently so visitors register "this is still going" without text. */
  /* ── Duration-bar end-cap indicators ─────────────────────────────────
     Two visual states for the trailing edge of each bar:
       • data-ongoing="1"  → ▶  arrow at the end (still happening)
       • default (bounded) → ■  small square cap (defined end date)
     Renders via ::after on the bar — desktop AND mobile.  Helps the
     user distinguish "still active" vs "wrapped up" without reading
     the text labels.  Skipped on bars too short to make the cap
     readable (.short-bar — set by JS when duration < 2 months). */
  .duration-line-ext::after {
    content: '';
    position: absolute;
    z-index: 4;
    pointer-events: none;
  }
  /* Bounded — small filled square at the trailing edge */
  .duration-line-ext:not([data-ongoing="1"])::after {
    right: -3px; top: 50%;
    transform: translateY(-50%);
    width: 7px; height: 7px;
    background: inherit;
    border-radius: 1px;
    box-shadow: 0 0 0 1.5px rgba(255, 255, 255, 0.9);
  }
  /* Ongoing — arrow glyph at the trailing edge.  Uses a CSS triangle
     (border trick) tinted to match the bar.  Sits OVER the bar's
     fading edge so it reads as "still going". */
  .duration-line-ext[data-ongoing="1"]::after {
    right: -6px; top: 50%;
    transform: translateY(-50%);
    width: 0; height: 0;
    border-top: 6px solid transparent;
    border-bottom: 6px solid transparent;
    border-left: 9px solid currentColor;
    color: inherit;
    background: transparent;
    border-radius: 0;
    /* The bar's background-color is inherited by border-left via
       currentColor — we set color: same as bg in the track variants
       below. */
  }
  .timeline-block[data-track="blue"]  .duration-line-ext[data-ongoing="1"]::after { border-left-color: var(--tenki-blue);   color: var(--tenki-blue); }
  .timeline-block[data-track="green"] .duration-line-ext[data-ongoing="1"]::after { border-left-color: var(--tenki-green);  color: var(--tenki-green); }
  .timeline-block[data-track="black"] .duration-line-ext[data-ongoing="1"]::after { border-left-color: var(--tenki-black);  color: var(--tenki-black); }
  .timeline-block[data-track="white"] .duration-line-ext[data-ongoing="1"]::after { border-left-color: var(--tenki-white-stroke); color: var(--tenki-white-stroke); }
  /* On mobile the timeline is VERTICAL — flip the indicators so they
     point DOWN (next month) for ongoing, and the square sits at the
     BOTTOM edge of the bar. */
  @media (max-width: 768px) {
    .duration-line-ext:not([data-ongoing="1"])::after {
      right: 50%; top: auto; bottom: -3px;
      transform: translateX(50%);
      width: 7px; height: 7px;
    }
    .duration-line-ext[data-ongoing="1"]::after {
      right: 50%; top: auto; bottom: -8px;
      transform: translateX(50%);
      border-top: 9px solid currentColor;
      border-bottom: 0;
      border-left: 6px solid transparent;
      border-right: 6px solid transparent;
    }
  }
  /* Hide both indicators on very short bars where they'd dominate */
  .duration-line-ext.short-bar::after { display: none; }

  .duration-line-ext[data-ongoing="1"] {
    mask-image: linear-gradient(to right,
                                rgba(0,0,0,1) 0%,
                                rgba(0,0,0,1) 78%,
                                rgba(0,0,0,0) 100%);
    -webkit-mask-image: linear-gradient(to right,
                                rgba(0,0,0,1) 0%,
                                rgba(0,0,0,1) 78%,
                                rgba(0,0,0,0) 100%);
    animation: tenkiOngoingPulse 2.6s ease-in-out infinite;
  }
  @keyframes tenkiOngoingPulse {
    0%, 100% { opacity: 0.75; }
    50%      { opacity: 0.95; }
  }
  /* "→ present" label gets a subtle italic + tenki-blue so the present-
     ness reads even on the funding popup / sidebar without an icon. */
  .duration-dates .dur-present {
    font-style: italic;
    color: var(--tenki-blue);
    font-weight: 600;
  }
  /* Pill on ongoing events: green-ish "Active" prefix needs the same
     tenki-blue treatment to read as live. */
  .duration-span.is-ongoing .duration-pill {
    background: var(--tenki-blue-light);
    color: var(--tenki-blue);
    font-weight: 700;
  }
  .timeline-block.active  .duration-line-ext,
  .timeline-block.focused .duration-line-ext { opacity: 0.78; }
  .timeline-block.collapsed-by-year    .duration-stem,
  .timeline-block.collapsed-by-year    .duration-dot  { opacity: 0 !important; }
  .timeline-block.super-hidden-by-year .duration-stem,
  .timeline-block.super-hidden-by-year .duration-dot  { display: none !important; }

  /* ── Tab Intro Bounce ──────────────────────────── */
  @keyframes tabIntroBounce {
    0%   { transform: scale(1); }
    20%  { transform: scale(1.18); color: var(--tenki-blue); }
    40%  { transform: scale(0.93); }
    60%  { transform: scale(1.08); }
    80%  { transform: scale(0.97); }
    100% { transform: scale(1); }
  }
  .mobile-tab.intro-bounce { animation: tabIntroBounce 0.7s ease forwards; }
  /* Hidden on desktop; shown via mobile media query */
  .mobile-tab-hint { display: none; }
  /* Tab-attached drawers: mobile-only — desktop never shows them */
  .map-tab-drawer,
  .timeline-tab-drawer { display: none; }
  /* Mobile-map back-handle: mobile-only.  Top-level rule (outside
     any media query) hides it everywhere by default; the mobile
     media query at ~line 2105 then turns it back on conditionally
     when .dashboard-container.mobile-map-view is active.  Without
     this top-level rule the default <button> renders on desktop
     as a horizontal pill with the inner "← timeline" text
     visible — see the rogue bar at the top of the timeline section. */
  .mobile-map-back-handle { display: none; }
  /* Same default-hide for the right-edge "Move to Map" handle (added
     2026-05-29 as part of the mobile slide-pager).  Without this base
     rule the button rendered as a horizontal banner at the top of the
     desktop dashboard because its @media (max-width: 768px) :not()
     visibility rule wasn't being suppressed by anything above 768 px. */
  .mobile-timeline-fwd-handle { display: none; }
  /* Tap-to-explore overlay: mobile-only — desktop never shows it.
     Resets default <button> chrome so the panel reads as a tap target. */
  .tenki-explore-overlay { display: none; background: none; border: 0; padding: 0; font: inherit; color: inherit; }
  /* Immersive-mode exit chips: mobile-only.  Desktop ignores immersive
     state entirely (enterImmersive bails on `window.innerWidth > BP_MOBILE`),
     but defensively hide the chips here so they never flash if they did. */
  .tenki-immersive-exit,
  .tenki-immersive-x { display: none; }

  /* PROTECTED DESKTOP HEADERS */
  .timeline-card h3 { margin: 0 0 4px 0 !important; font-size: 0.95rem !important; color: var(--text-dark) !important; font-weight: 700 !important; line-height: 1.2 !important; }
  .timeline-card p { margin: 0 !important; font-size: 0.84rem !important; line-height: 1.4 !important; color: var(--text-light) !important; }
  /* Detailed view (Option A): the carousel cards are compact NAV chips — date +
     title + status only.  The full event description lives in the detail panel
     (sidebar), so hide it on the card + tighten the chip (less padding, drop the
     redundant click hint) to free vertical room for the map + detail panel. */
  .dashboard-container:not(.simplified-view) .timeline-card { padding: 8px 12px !important; }
  .dashboard-container:not(.simplified-view) .timeline-card p,
  .dashboard-container:not(.simplified-view) .timeline-card .click-indicator { display: none !important; }
  .click-indicator { margin-top: auto; padding-top: 15px; font-size: 0.72rem; font-weight: 700; text-transform: uppercase; color: #999999; }
  button.click-indicator { background: none; border: none; display: block; width: 100%; text-align: left; cursor: pointer; }
  button.click-indicator:hover { color: var(--tenki-blue); }

  /* Desktop Protection for Hidden Elements */
  .collapsed-label { display: none !important; }
  .mobile-inline-details { display: none !important; }
  .return-to-map-btn { display: none !important; }
  .mobile-tab-bar { display: none; }

  /* Mobile View Framework Implementations */
  @media (max-width: 950px) {
    .map-interface-grid { grid-template-columns: 1fr; height: auto; gap: 20px; }
    #leaflet-map-canvas { height: 350px; }
    .map-details-sidebar { min-height: 220px; }
    /* Desktop tap-to-engage overlay is hidden below tablet width —
       mobile has its own full-section .tenki-explore-overlay that
       covers the entire dashboard, so we don't want two competing
       overlays at the same time. */
    .tenki-desktop-map-overlay { display: none; }
    .map-canvas-wrap { height: 350px; }
  }

  @media (max-width: 768px) {
    /* 100dvh Layout locks strictly to the screen limits.
       Also: isolate the stacking context (z-index + isolation:isolate) so
       the next Squarespace section below the embed can't visually paint
       OVER the bottom of our timeline (reported case: Maya Angelou quote
       block overlapping the 2027 year area on mobile homepage).  The SQS
       quote block uses position:relative with no z-index, which lets its
       background/border render at a layer that bleeds into our content
       when our z-index stack is muddled.  isolation:isolate creates a new
       stacking context boundary that the parent SQS section can't cross. */
    .dashboard-container {
      padding: 0; margin: 0; border-radius: 0; height: 100dvh !important; max-height: 100dvh !important;
      display: flex; flex-direction: column; overflow: hidden; position: relative;
      border: none; background-color: var(--bg-light);
      isolation: isolate;
      z-index: 1;
      /* Belt-and-suspenders: force the embed's containing Code Block to
         take the full claimed height — Squarespace's Fluid Engine sometimes
         lets the .sqs-block-code wrapper auto-shrink to content height,
         which is what allows the next section to draw on top. */
      min-height: 100dvh !important;
    }
    /* Reach UP into the SQS wrapper so the embed's Code Block claims the
       layout space its child needs.  These selectors are SQS-specific but
       safe to no-op on other markup. */
    .sqs-block-code:has(> div > #dashboard-container),
    .sqs-block.sqs-block-code:has(#dashboard-container) {
      min-height: 100dvh;
      display: block;
    }

    /* ── Immersive mode (mobile only) ────────────────────────────────────
       When the user explicitly engages with the timeline/map (taps an
       event OR opens the Map tab), the dashboard takes over the WHOLE
       viewport so scrolling to other parts of the homepage no longer
       competes with horizontal timeline scroll + map drag.  Feels like a
       dedicated app for the duration of the interaction; an exit chip
       (see `.tenki-immersive-exit`) is the only way out.
       Triggered by adding `.is-immersive` to .dashboard-container and
       `.tenki-immersive` to <body> (the latter locks page scroll). */
    .dashboard-container.is-immersive {
      position: fixed !important;
      top: 0 !important; left: 0 !important; right: 0 !important; bottom: 0 !important;
      width: 100vw !important;
      height: 100dvh !important; max-height: 100dvh !important;
      z-index: 9999 !important;
      border-radius: 0 !important;
      /* Force opaque background so nothing from the page below can
         bleed through into the scroll-locked view (user-reported
         2026-05-29: "sustainable funding stream…" funnel text was
         visible at the top of the immersive view).  --bg-light is
         already the dashboard's normal background; the !important
         guarantees no transparent override from elsewhere in the
         cascade. */
      background-color: var(--bg-light) !important;
      /* Pad the bottom so the exit chip never overlaps timeline rows or
         map controls — the chip itself is ~52 px tall. */
      padding-bottom: 60px !important;
      box-sizing: border-box !important;
      /* Stop content from overflowing the immersive viewport — the
         user scrolls WITHIN the dashboard, not the page. */
      overflow-y: auto !important;
      overflow-x: hidden !important;
    }
    /* Body scroll lock — applied to <body> by JS.  Belt-and-suspenders:
       overflow:hidden stops natural page scroll, touch-action:none stops
       iOS rubber-band, position:fixed preserves scrollY when re-engaged.
       Documented gotcha: position:fixed on body causes the viewport to
       jump to top — JS captures window.scrollY first and restores it on
       exit by scrolling back to that y. */
    body.tenki-immersive {
      overflow: hidden !important;
      touch-action: none !important;
      overscroll-behavior: none !important;
    }
    /* (REMOVED 2026-05-29) — the body.tenki-immersive::before
       opaque-underlay I added in the previous commit was the wrong
       fix.  Instead of underlaying the dashboard, it painted ON TOP
       of the dashboard content (the dashboard's transform-trapped
       containing block put its z-index BELOW the pseudo's effective
       paint position).  Net effect: blank white viewport during
       immersive.  Reverted; we'll address the funnel-bleed via the
       X-button placement per the user's diagnosis instead. */
    /* Exit chip — appears only in immersive mode.  Bottom-center,
       full-width band with a clear call to "release me, let me scroll."
       Tap target ≥ 48 px tall (Apple HIG mobile minimum). */
    .tenki-immersive-exit {
      display: none;
      position: fixed;
      left: 0; right: 0; bottom: 0;
      z-index: 10000;
      padding: 12px 16px calc(12px + env(safe-area-inset-bottom)) 16px;
      background: linear-gradient(to top, var(--tenki-blue) 0%, #0073c4 100%);
      color: #fff;
      font-size: 0.9rem; font-weight: 800;
      text-align: center;
      letter-spacing: 0.4px;
      cursor: pointer;
      border: none;
      width: 100%;
      box-shadow: 0 -4px 16px rgba(0,0,0,0.18);
      -webkit-tap-highlight-color: transparent;
    }
    /* Entry pulse — when immersive engages, the exit chip pulses bright
       blue for ~5 seconds so the user CAN'T miss it.  Replaces the
       earlier subtle dark chip that users were reporting they didn't
       notice.  Goal: bottom-of-screen attention magnet that says
       "here's how you get out" loud and clear. */
    body.tenki-immersive .tenki-immersive-exit { animation: tenkiExitEntrance 5s ease-out 1; }
    @keyframes tenkiExitEntrance {
      0%   { transform: translateY(80%);    box-shadow: 0 -4px 16px rgba(0, 90, 156, 0); }
      18%  { transform: translateY(0);      box-shadow: 0 -6px 26px rgba(0, 90, 156, 0.65); }
      30%  { transform: translateY(-3px);   box-shadow: 0 -8px 32px rgba(0, 90, 156, 0.80); }
      45%  { transform: translateY(0);      box-shadow: 0 -6px 24px rgba(0, 90, 156, 0.55); }
      60%  { transform: translateY(-2px);   box-shadow: 0 -8px 30px rgba(0, 90, 156, 0.70); }
      75%  { transform: translateY(0);      box-shadow: 0 -6px 22px rgba(0, 90, 156, 0.40); }
      100% { transform: translateY(0);      box-shadow: 0 -4px 16px rgba(0, 0, 0, 0.18); }
    }
    @media (prefers-reduced-motion: reduce) {
      body.tenki-immersive .tenki-immersive-exit { animation: none; }
    }
    body.tenki-immersive .tenki-immersive-exit { display: block !important; }
    .tenki-immersive-exit:active { background: linear-gradient(to top, rgba(0,0,0,1) 0%, rgba(0,0,0,0.9) 100%); }
    .tenki-immersive-exit .tenki-immersive-exit-icon {
      display: inline-block; margin-right: 6px; font-size: 0.95rem;
      animation: tenki-immersive-chev 1.5s ease-in-out infinite;
    }
    @keyframes tenki-immersive-chev {
      0%, 100% { transform: translateY(0); opacity: 0.85; }
      50%      { transform: translateY(2px); opacity: 1; }
    }
    /* Top-corner ✕ exit — compact circular button pinned to the top-right
       of the viewport, shown only in immersive mode.  (Earlier removed
       over a "funnel bleed" worry, but that was actually fixed by the
       reparent-to-<body> trick in enterImmersive(); the ✕ is itself a
       body-injected fixed node so it never causes bleed.)  Deliberately
       tiny — uses minimal screen real-estate as requested.  Pairs with
       the bottom "↓ Tap to exit" band. */
    .tenki-immersive-x { display: none; }
    body.tenki-immersive .tenki-immersive-x {
      display: flex !important;
      position: fixed;
      top: calc(8px + env(safe-area-inset-top));
      right: 10px;
      z-index: 10001;
      width: 32px; height: 32px;
      align-items: center;
      justify-content: center;
      padding: 0;
      border: none;
      border-radius: 50%;
      background: rgba(15, 27, 38, 0.55);
      color: #fff;
      font-size: 15px;
      font-weight: 700;
      line-height: 1;
      cursor: pointer;
      box-shadow: 0 2px 8px rgba(0,0,0,0.30);
      backdrop-filter: blur(4px);
      -webkit-backdrop-filter: blur(4px);
      -webkit-tap-highlight-color: transparent;
    }
    body.tenki-immersive .tenki-immersive-x:active { background: rgba(15, 27, 38, 0.85); }

    /* Compact Headings */
    .dashboard-header {
      background: #FFFFFF; margin: 0; padding: 10px 15px 5px 15px;
      z-index: 10 !important; position: relative; flex-shrink: 0; border-radius: 10px 10px 0 0;
    }
    .dashboard-header p { display: none !important; }
    .dashboard-header h2 { font-size: 1.2rem; margin: 0; }

    /* Control Bar boosted Z-index for upward dropdown overlays */
    .dashboard-controls {
      padding: 5px 0px 10px 0px; margin-bottom: 0; gap: 10px; z-index: 99999 !important;
      position: relative; background: #FFFFFF; border-bottom: none; flex-shrink: 0;
    }

    .filters-scroll-wrapper { width: 100%; overflow: visible !important; z-index: 99999 !important;}

    .filters-scroll-wrapper::before, .filters-scroll-wrapper::after {
      content: ''; position: absolute; top: 0; width: 45px; height: 38px; z-index: 160; pointer-events: none; transition: opacity 0.2s ease; opacity: 0;
    }
    .filters-scroll-wrapper::before { left: 0; background: linear-gradient(to right, #FFFFFF 40%, rgba(255,255,255,0) 100%); }
    .filters-scroll-wrapper::after { right: 0; background: linear-gradient(to left, #FFFFFF 40%, rgba(255,255,255,0) 100%); }
    .filters-scroll-wrapper.left-hint-active::before { opacity: 1; }
    .filters-scroll-wrapper.right-hint-active::after { opacity: 1; }

    .timeline-filters {
      flex-wrap: nowrap !important; justify-content: flex-start !important; overflow-x: auto !important;
      padding: 0 45px 0 15px !important; gap: 8px; width: 100%; scrollbar-width: none; -webkit-overflow-scrolling: touch; overflow-y: visible !important;
      z-index: 99999 !important;
    }
    .timeline-filters::-webkit-scrollbar { display: none !important; }

    .dropdown-wrapper { flex: 0 0 auto; display: inline-block; overflow: visible !important; }
    .filter-btn { white-space: nowrap; padding: 6px 14px; font-size: 0.78rem; }

    /* Mobile dropdowns — anchor to right edge of the viewport so they
       never clip off-screen.  The filter chips live at the top of the
       timeline section in a horizontal scroll row; when the last chip
       (e.g. "Sort") opens its dropdown, the default left:0 anchor was
       letting the menu render past the right edge of the screen
       (unselectable).  left:auto + right:0 fixes the rightmost
       dropdowns; for safety, also cap max-width to viewport. */
    .dropdown-menu-options {
      z-index: 999999 !important;
      max-width: calc(100vw - 32px) !important;
    }
    /* If the dropdown's parent .dropdown-wrapper is in the right half
       of the filter row, render the menu right-aligned so it stays
       on-screen.  Detected via :nth-last-child(-n+2) — the last 1-2
       dropdowns in the row. */
    .timeline-filters .dropdown-wrapper:nth-last-child(-n+2) .dropdown-menu-options {
      left: auto !important;
      right: 0 !important;
    }

    /* MAP FLEX WRAPPER - Hidden by default, shown via Map tab */
    .map-interface-grid {
      position: relative !important; display: none !important; flex-direction: column !important;
      flex: 1 1 auto !important; height: auto !important; width: 100% !important;
      z-index: 10; padding: 0; margin: 0; transition: flex 0.3s ease;
    }

    #leaflet-map-canvas {
      flex: 1; width: 100%; height: 100% !important; border-radius: 0; border: none; z-index: 1;
    }

    .map-details-sidebar { display: none !important; }

    /* Native Map Controls Moved Down Slightly to clear track buttons */
    .leaflet-top.leaflet-left { top: 75px !important; left: 10px !important; transform: none !important; }

    /* FLOATING NAV COMMAND CENTER (Card bar fixed to bottom) */
    /* ── Mobile floating nav — stacked right-side up/down jumpers ─────
       Was a bottom-centered pill bar that the exit-immersive chip
       covered.  Reworked to a vertical RIGHT-edge stack with the
       prev/next arrows as round buttons + the filter chip BELOW them.
       Sits at vertical center of the timeline area so the user's
       thumb reaches it naturally. */
    /* Simplified view (the mobile-default carousel) has its OWN slide arrows,
       so hide this floating ←/→ + "All Tracks" control here (2026-06-05).
       Kept in Detailed view + on desktop.  The carousel's #slide-left/right
       still synthesise .click() on the hidden prev/next, so nav keeps working. */
    .dashboard-container.simplified-view #floating-nav-container { display: none !important; }
    .floating-nav-container {
      display: flex !important;
      flex-direction: column !important;
      align-items: stretch !important;
      gap: 10px !important;
      position: fixed !important;
      right: 12px !important;
      left: auto !important;
      /* 2026-05-29: moved off top: 50% (collided with the new
         "Move to Map" right-edge handle which occupies the middle
         60vh of the right edge).  Anchor below the handle, just
         above the tab bar + Simplified-toggle drawer.  ~125 px
         from the bottom clears the 46-px tab bar plus the 46-px
         timeline-tab-drawer + a small gap. */
      bottom: calc(125px + env(safe-area-inset-bottom, 0px)) !important;
      top: auto !important;
      transform: none !important;
      z-index: 9000 !important;
      background: transparent !important;
      padding: 0 !important;
      box-shadow: none !important;
      animation: none !important;
      width: auto !important;
      max-width: none !important;
    }

    /* The arrow group: tight vertical pair so prev/next read as a unit */
    .floating-controls-group {
      display: flex !important;
      flex-direction: column !important;
      align-items: center !important;
      gap: 4px !important;
      width: 48px !important;
      padding: 4px !important;
      background: rgba(255, 255, 255, 0.96) !important;
      border-radius: 24px !important;
      box-shadow: 0 4px 14px rgba(0, 0, 0, 0.12), 0 0 0 1px rgba(0, 0, 0, 0.06) !important;
      backdrop-filter: blur(10px);
      -webkit-backdrop-filter: blur(10px);
      border: none;
    }

    .nav-arrow {
      display: flex !important;
      background: transparent !important;
      border: none;
      color: var(--tenki-blue) !important;
      width: 40px !important;
      height: 40px !important;
      border-radius: 20px !important;
      align-items: center;
      justify-content: center;
      font-weight: 900;
      transition: background 0.15s, transform 0.15s;
      cursor: pointer;
      padding: 0;
      font-size: 1.25rem !important;
      pointer-events: auto;
      flex-shrink: 0;
    }
    /* Rotate ← → glyphs so they read as ↑ ↓ on the vertical mobile
       timeline.  prev-btn (top of stack) shows ↑ — earlier events
       are HIGHER UP on the vertical track, so up = back in time.
       next-btn (bottom of stack) shows ↓ — later events are LOWER
       on the track.  CSS:
         &larr; (←) → rotate(90deg)  = ↑   (the prev button)
         &rarr; (→) → rotate(90deg)  = ↓   (the next button)
       Note rotate(90deg) NOT -90 like before — earlier version had
       the arrows backwards (prev pointed down). */
    #floating-prev-btn { transform: rotate(90deg); }
    #floating-next-btn { transform: rotate(90deg); }
    .nav-arrow:active {
      background: rgba(0, 90, 156, 0.12) !important;
      transform: rotate(90deg) scale(0.94);
    }
    .nav-arrow:disabled {
      color: #c0cdd8 !important;
      opacity: 1 !important;
      pointer-events: none;
    }
    /* Small label hint between the buttons — "prev / next event"
       so first-time users grok what they do. */
    .floating-controls-group::before {
      content: '↕';
      display: block;
      width: 0;
      height: 0;
      overflow: hidden;
      position: absolute;
    }

    /* Filter button sits BELOW the arrow stack as a separate pill */
    .all-tracks-reset-btn {
      box-shadow: 0 4px 14px rgba(0, 0, 0, 0.12), 0 0 0 1px rgba(0, 0, 0, 0.06) !important;
      margin: 0 !important;
      background: rgba(255, 255, 255, 0.96) !important;
      color: var(--tenki-black) !important;
      padding: 8px 10px !important;
      width: 48px !important;
      height: auto !important;
      border-radius: 12px !important;
      display: flex !important;
      flex-direction: column !important;
      align-items: center !important;
      justify-content: center !important;
      gap: 3px !important;
      font-size: 0.62rem !important;
      letter-spacing: 0.4px !important;
      backdrop-filter: blur(10px);
      -webkit-backdrop-filter: blur(10px);
      line-height: 1.15 !important;
      text-transform: uppercase;
      font-weight: 700;
    }
    .all-tracks-reset-btn img { display: none !important; }
    .all-tracks-reset-btn:hover { background: rgba(255,255,255,1) !important; transform: none; }
    .all-tracks-reset-btn svg {
      display: inline-flex !important;
      width: 12px !important;
      height: 12px !important;
      color: var(--tenki-blue);
    }
    .floating-nav-menu { display: none !important; }
    /* When the filter dropdown is open, render it as a TALL, SKINNY
       vertical column anchored to the viewport's right edge so it
       can't clip off-screen on any phone.  Each entry is generously
       tall (44px+) for thumb-friendly tapping.  Width is narrow so
       the map stays mostly visible behind it.
       `position: fixed` (not absolute) — anchors to the viewport so
       a wide dashboard-container's right edge doesn't push it off.
       User-reported: prior version popped off the right side of
       the viewport and was unusable. */
    .floating-nav-container.menu-open .floating-nav-menu {
      display: flex !important;
      flex-direction: column !important;
      position: fixed !important;
      right: 70px !important;          /* just left of the floating-nav buttons */
      top: 50% !important;
      bottom: auto !important;
      transform: translateY(-50%) !important;
      max-height: 70vh !important;
      width: 160px !important;          /* skinny */
      max-width: 50vw !important;
      background: #fff !important;
      border-radius: 14px !important;
      box-shadow: 0 8px 28px rgba(0, 0, 0, 0.18), 0 0 0 1px rgba(0,0,0,0.05) !important;
      padding: 6px 0 !important;
      overflow-y: auto !important;
      z-index: 9100 !important;        /* above the floating-nav arrows */
    }
    /* Each entry in the popup — full-width, tall, easy to tap. */
    .floating-nav-container.menu-open .floating-nav-menu > * {
      min-height: 44px !important;
      padding: 10px 14px !important;
      font-size: 0.85rem !important;
      font-weight: 700 !important;
      border-radius: 0 !important;
      width: 100% !important;
      display: flex !important;
      align-items: center !important;
      gap: 8px !important;
      white-space: nowrap !important;
      overflow: hidden !important;
      text-overflow: ellipsis !important;
    }

    /* TIMELINE FLOW CONTAINER: Standard Document Flex Rules below Map */
    .timeline-outer-wrapper {
      position: relative !important; flex: 1 1 auto !important; width: 100% !important;
      display: flex !important; flex-direction: column !important; background: #F8F9FA !important;
      box-shadow: inset 0 4px 10px rgba(0,0,0,0.02) !important; border: none !important; margin: 0 !important;
      transform: none !important; overflow: hidden !important;
    }

    .timeline-scroll-wrapper {
      flex: 1 1 auto !important; width: 100%; overflow-x: hidden !important; overflow-y: auto !important;
      height: auto !important; max-height: none !important;
      /* Edge-to-edge on mobile — was padding:15px 15px 95px 15px which
         inset the timeline 15 px from the viewport edges, making the
         visual NOT match the tap-to-explore overlay (which is full
         width).  Now both are edge-to-edge.  The 28 px spine offset
         that the timeline track needs is moved INTO the track's own
         padding-left below. */
      padding: 15px 0 95px 0 !important;
      -webkit-overflow-scrolling: touch;
    }

    .timeline-track {
      display: flex !important; flex-direction: column !important; gap: 15px !important;
      padding-top: 5px !important; min-width: auto !important;
      /* Track needs left padding for the spine + right padding for
         visual breathing room.  Replaces what the scroll-wrapper was
         doing before, so events still don't kiss the screen edges.
         Bumped 28 → 56 so concurrent events' duration-bar lanes (which
         stack LEFT of the spine at MOB_STEP px each) have room to
         render before clipping the viewport edge — was hiding the
         second lane (TBOW vs OB Ultrasound). */
      padding-left: 56px !important;
      /* Right gutter widened 15 → 56 px so the right-edge "Move to Map"
         handle (44 px, z:12) always has a clear strip to live in and never
         overlaps card content.  Matches the left spine inset for symmetry. */
      padding-right: 56px !important;
    }

    .timeline-track::before {
      /* Sharper, more distinct spine — was 4 px @ 30 % black, hard to
         distinguish from duration bars sitting next to it.  Now 5 px
         solid black with a thin white outline so it reads as the
         "main axis" while the colored bars are secondary tracks. */
      width: 5px !important; height: 100% !important; top: 0 !important; bottom: 0 !important; left: 10px !important;
      background-color: var(--tenki-black) !important;
      box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.95) !important;
      z-index: 1;
      border-radius: 2px;
    }
    /* ── Spine-to-node connector stem ──────────────────────────────
       Bridges the visual gap between the vertical spine (left:10) and
       each event's circle (left:-32 relative to its block, but the
       block starts after a 28 px track padding-left → node ends up
       roughly at the same horizontal position as the spine on the
       left side of the card row).  A small horizontal pill connects
       them so the eye reads "node BELONGS to spine" instead of
       "floating dots beside the line". */
    .timeline-block .timeline-node::before {
      content: '';
      position: absolute;
      left: 100%;
      top: 50%;
      /* 2026-05-29: stem width bumped 14 → 40 px so the connector
         spans from the node's right edge (now centered ON the spine)
         all the way to the card's left edge.  Geometry:
           Node right edge:  block-left − 40  (node at −48, width 8)
           Card left edge:    block-left + 0
           → stem needs to span 40 px to reach the card.
         User-reported: "the duration bar beginning does not touch
         the activity stem" — same root cause: stem ended in mid-air
         instead of connecting to the card. */
      width: 40px;
      height: 2px;
      background: var(--tenki-black);
      border-radius: 1px;
      transform: translateY(-50%);
      pointer-events: none;
      z-index: 1;
    }
    .timeline-block[data-track="blue"]  .timeline-node::before { background: var(--tenki-blue); }
    .timeline-block[data-track="green"] .timeline-node::before { background: var(--tenki-green); }
    .timeline-block[data-track="black"] .timeline-node::before { background: var(--tenki-black); }
    .timeline-block[data-track="white"] .timeline-node::before { background: var(--tenki-white-stroke); }
    /* Mobile: ticks rotate 90° — horizontal strokes crossing the vertical spine.
       Bolder than the old subtle 1 px version so they read on small screens
       without forcing the user to lean in. */
    .tl-month-tick {
      width: 14px !important; height: 2px !important;
      top: auto !important; left: 5px !important;
      background: rgba(0, 0, 0, 0.42) !important;
      border-radius: 1px !important;
    }
    .tl-month-tick.is-quarter {
      width: 22px !important; height: 2px !important; left: 1px !important;
      background: rgba(0, 0, 0, 0.65) !important;
    }
    /* On mobile the node sits to the LEFT of the card row (left:-32px) — a
       downward stem from the node doesn't connect to anything visible,
       so hide it.  The mobile layout uses the bubble itself as the
       visual link. */
    .timeline-node::after { display: none !important; }

    .timeline-block {
      position: relative !important; flex: 0 0 auto !important; width: 100% !important; max-width: none !important;
      display: flex !important; align-items: center !important; scroll-snap-align: none !important; min-height: 40px !important; margin-bottom: 12px !important; cursor: pointer;
    }

    /* Hide card when not active */
    /* Default mobile behaviour (Simplified view) hides every non-active
       card so only the user's selection shows.  In Detailed view we
       want ALL cards visible — override below. */
    .timeline-block:not(.active) .timeline-card { display: none !important; }
    /* Detailed view (mobile): override the hide so EVERY card shows
       its full content inline.  User-requested 2026-05-29: "the
       detailed view on mobile should expand all activities with all
       data." */
    .dashboard-container:not(.simplified-view) .timeline-block:not(.active) .timeline-card,
    .dashboard-container:not(.simplified-view) .timeline-block.active .timeline-card {
      display: flex !important;
      flex-direction: column !important;
      visibility: visible !important;
      opacity: 1 !important;
    }
    .dashboard-container:not(.simplified-view) .timeline-block { cursor: default !important; }
    .dashboard-container:not(.simplified-view) .timeline-block .timeline-card {
      border: 1px dashed rgba(0, 90, 156, 0.35) !important;
    }
    /* Critical: HIDE the .expanded-title-card chip in Detailed view.
       The desktop rule at line ~1155 (`.dashboard-container.map-
       expanded .expanded-title-card { display: flex !important }`)
       has higher specificity than the bare .expanded-title-card
       hide and was leaking even on mobile when map-expanded
       happened to also be set.  In Detailed view we don't want the
       simplified-style chip at all — full cards carry the title. */
    .dashboard-container:not(.simplified-view) .expanded-title-card {
      display: none !important;
    }

    /* ── 2026-05-29: Simplified-view chip → proper preview CARD ─────────
       User spec: "I like the chip concept but it needs to be on a
       window/card with a layout that makes sense (title at the top)."
       The old layout was a transparent flex-ROW (pills | title | meta)
       with no container — it read as scattered text floating next to
       the spine.  Rebuild it as a real card: white panel, track-colored
       left accent, rounded corners, soft shadow, and a VERTICAL stack
       with the bold event TITLE first, then the date/region meta line,
       then the status pills.  Tapping it still flips the block to
       .active → reveals the SAME full detailed card (handled by the
       rule at line ~3023).  No separate title pill — this card is the
       one and only collapsed representation. */
    .dashboard-container.simplified-view .expanded-title-card {
      display: flex !important;
      flex-direction: column !important;
      align-items: stretch !important;
      gap: 8px !important;
      min-width: 0 !important;
      max-width: none !important;
      width: 100% !important;
      padding: 14px 16px !important;
      margin-left: 0 !important;
      transform: none !important;
      opacity: 1 !important;
      background: #fff !important;
      border: 1px solid rgba(0,0,0,0.10) !important;
      border-left: 4px solid var(--tenki-blue) !important;  /* track accent (per-track below) */
      border-radius: 14px !important;
      box-shadow: 0 2px 10px rgba(0,0,0,0.07) !important;
      cursor: pointer !important;
    }
    /* Title FIRST (flex order), bold + larger so it leads the card. */
    .dashboard-container.simplified-view .expanded-title-card .etc-title {
      order: 1 !important;
      font-size: 18px !important;
      font-weight: 700 !important;
      line-height: 1.25 !important;
      color: var(--text-dark) !important;
      white-space: normal !important;
    }
    /* Date · region meta line second. */
    .dashboard-container.simplified-view .expanded-title-card .etc-meta {
      order: 2 !important;
      display: flex !important;
      flex-wrap: wrap !important;
      align-items: center !important;
      gap: 4px 12px !important;
      font-size: 13px !important;
      color: var(--text-light) !important;
    }
    /* Status pills (tag / phase / funding) last, wrapping under the meta. */
    .dashboard-container.simplified-view .expanded-title-card .etc-pills {
      order: 3 !important;
      display: flex !important;
      flex-wrap: wrap !important;
      align-items: center !important;
      gap: 6px !important;
    }
    /* Per-track left-accent so each card is colour-coded to its pillar. */
    .dashboard-container.simplified-view .timeline-block[data-track="blue"]  .expanded-title-card { border-left-color: var(--tenki-blue)  !important; }
    .dashboard-container.simplified-view .timeline-block[data-track="green"] .expanded-title-card { border-left-color: var(--tenki-green) !important; }
    .dashboard-container.simplified-view .timeline-block[data-track="black"] .expanded-title-card { border-left-color: var(--tenki-black) !important; }
    .dashboard-container.simplified-view .timeline-block[data-track="white"] .expanded-title-card { border-left-color: var(--tenki-white-border) !important; }
    /* The legacy timeline-card is suppressed entirely in Simplified
       on mobile — the expanded-title-card replaces it. */
    .dashboard-container.simplified-view .timeline-block .timeline-card {
      display: none !important;
    }

    /* ── 2026-05-29: Simplified view = "compact title bubbles, click for
       the full card" ─────────────────────────────────────────────────
       User spec: show only the compact title bubbles for all events
       until one is selected, then open the SAME full detailed card the
       Detailed view uses — and drop the redundant left title box.

       (a) Kill the legacy .collapsed-label pill entirely in Simplified.
           It was rendering to the LEFT of the .expanded-title-card chip,
           duplicating the title.  The chip is now the only bubble. */
    .dashboard-container.simplified-view .timeline-block .collapsed-label {
      display: none !important;
    }
    /* (a2) Detailed view shows EVERY event's full card, so the legacy
            .collapsed-label title pill (rule ~line 3148 flips it on for
            non-active blocks) is a redundant bubble sitting next to the
            card.  Kill it here too — one card per event, no extra pill.
            Specificity 4 (.dashboard-container + :not + .timeline-block +
            .collapsed-label) beats the 3-class show rule below. */
    .dashboard-container:not(.simplified-view) .timeline-block .collapsed-label {
      display: none !important;
    }
    /* (b) When an event is selected (active/focused), hide its compact
           chip bubble and reveal the full detailed card instead. */
    .dashboard-container.simplified-view .timeline-block.active .expanded-title-card,
    .dashboard-container.simplified-view .timeline-block.focused .expanded-title-card {
      display: none !important;
    }
    .dashboard-container.simplified-view .timeline-block.active .timeline-card,
    .dashboard-container.simplified-view .timeline-block.focused .timeline-card {
      display: flex !important;
      flex-direction: column !important;
      max-height: none !important;
      overflow: visible !important;
      height: auto !important;
    }

    /* Show card when active.  Critical: NO max-height clamp, NO
       overflow: hidden so the card expands to fit ALL content (body
       text, locations list, MCHTC DAY buttons, etc).  Also override
       the timeline-block itself + the inline-details container so
       NONE of the active card's ancestors clip vertically. */
    .timeline-block.active .timeline-card {
      display: flex !important;
      flex-direction: column !important;
      margin-top: 5px;
      max-height: none !important;
      overflow: visible !important;
      height: auto !important;
    }
    .timeline-block.active {
      max-height: none !important;
      overflow: visible !important;
      height: auto !important;
    }
    .timeline-block.active .mobile-inline-details {
      max-height: none !important;
      overflow: visible !important;
      height: auto !important;
    }

    .timeline-block:not(.active) { display: flex !important; align-items: center !important; cursor: pointer; }

    /* 2026-05-29: node centered ON the spine.
       Math:
         Track padding-left = 56 px → block content starts at track-left + 56.
         Spine center is at track-left + 12.5 (spine `left:10` + half its 5 px width).
         Node = 8 px wide → for node center to coincide with spine center:
           node-left = (track-left + 12.5) − (block-left + 4) = 12.5 − 56 − 4 = −47.5
         Rounded to −48 px within block.
       Previously was −32 px (15.5 px right of spine — user-reported
       circles not coincident with the timebar). */
    .timeline-block .timeline-node { top: 50% !important; transform: translateY(-50%) !important; left: -48px !important; position: absolute !important;}
    .timeline-block.active .timeline-node, .timeline-block.focused .timeline-node { transform: translateY(-50%) scale(1.3) !important; }

    .year-divider {
      position: relative; flex: 0 0 auto !important; display: flex !important; justify-content: flex-start !important;
      margin-left: -28px !important; margin-top: 15px !important; margin-bottom: 5px !important;
    }

    .year-badge { position: relative !important; top: 0 !important; font-size: 0.95rem !important; }

    .timeline-card { background: var(--tenki-white) !important; box-shadow: 0 4px 15px rgba(0,0,0,0.05) !important; padding: 15px !important; }
    /* 2026-05-28: chip suppression LIFTED.  Now that the timeline-tab-
       drawer is retired, the activity card is the only place these
       chips can live on mobile.  Show tag + phase + funding inline
       just like on desktop, with the same compact sizing. */
    .card-badge-row .details-tag,
    .card-badge-row .phase-badge,
    .card-badge-row .funding-badge {
      font-size: 0.6rem !important;
      padding: 3px 7px !important;
      letter-spacing: 0.3px !important;
    }
    .card-badge-row { display: flex !important; flex-direction: row !important;
                       align-items: stretch !important; gap: 8px !important;
                       justify-content: space-between !important;
                       flex-wrap: wrap !important; }
    /* Mobile badge mini-table — matches the desktop treatment so the
       chips read as a unified data row instead of three free-floating
       pills.  Hairline border + zero gap + stretched cells with
       internal dividers.  Apply ONLY to the first child (the inline-
       styled chip wrapper that the render code emits) — the share
       button is a direct child too and shouldn't get the border. */
    .card-badge-row > div:first-child {
      flex: 1 1 auto !important;
      min-width: 0 !important;
      display: flex !important;
      flex-wrap: wrap !important;
      align-items: stretch !important;
      gap: 0 !important;
      border: 1px solid rgba(0,0,0,0.12) !important;
      border-radius: 4px !important;
      overflow: hidden !important;
      background: rgba(0,0,0,0.02) !important;
    }
    /* Each chip stretches to share row width (matches desktop
       behaviour — prevents the "ugly white box at end of wrapped row"
       and gives a clean table read on phones).  Hairline divider
       between cells via border-right. */
    .card-badge-row > div:first-child .details-tag,
    .card-badge-row > div:first-child .phase-badge,
    .card-badge-row > div:first-child .funding-badge {
      flex: 1 1 auto !important;
      text-align: center !important;
      justify-content: center !important;
      border-radius: 0 !important;
      border: 0 !important;
      border-right: 1px solid rgba(0,0,0,0.10) !important;
      letter-spacing: 0.3px !important;
      box-shadow: none !important;
      white-space: nowrap !important;
      max-width: 100% !important;
      overflow: hidden !important;
      text-overflow: ellipsis !important;
      display: inline-flex !important;
      align-items: center !important;
    }
    .card-badge-row > div:first-child > *:last-child {
      border-right: 0 !important;
    }
    /* Semantic colour fills — same palette as desktop so the cue
       reads consistently across screen sizes. */
    .card-badge-row > div:first-child .details-tag.tag-blue   { background: rgba(0, 90,156, 0.12) !important; color: var(--tenki-blue)  !important; }
    .card-badge-row > div:first-child .details-tag.tag-green  { background: rgba(0,140, 69, 0.12) !important; color: var(--tenki-green) !important; }
    .card-badge-row > div:first-child .details-tag.tag-black  { background: rgba(26, 26, 26, 0.10) !important; color: var(--tenki-black) !important; }
    .card-badge-row > div:first-child .details-tag.tag-white  { background: rgba(192,197,204, 0.20) !important; color: var(--tenki-white-stroke) !important; }
    .card-badge-row > div:first-child .phase-badge.phase-planning     { background: #FFF6E3 !important; color: #946100 !important; }
    .card-badge-row > div:first-child .phase-badge.phase-execution    { background: #E3F2FD !important; color: #0D47A1 !important; }
    .card-badge-row > div:first-child .phase-badge.phase-accomplished { background: #E8F5E9 !important; color: #2E7D32 !important; }
    .card-badge-row > div:first-child .phase-badge.phase-future       { background: rgba(0,0,0,0.05) !important; color: var(--text-light) !important; }
    .card-badge-row > div:first-child .funding-badge.funding-seeking  { background: #FFF0F0 !important; color: #C62828 !important; }
    .card-badge-row > div:first-child .funding-badge.funding-partial  { background: #FFF3E0 !important; color: #E65100 !important; }
    .card-badge-row > div:first-child .funding-badge.funding-full     { background: #E8F5E9 !important; color: #2E7D32 !important; }
    .card-badge-row > div:first-child .funding-badge.funding-active   { background: #E3F2FD !important; color: #0D47A1 !important; }
    .card-badge-row .share-btn {
      flex: 0 0 auto !important;
      align-self: flex-start !important;
      margin-left: auto !important;
    }

    /* Bubble Formatting Protected & Colored by Track */
    .timeline-block:not(.active) .collapsed-label {
       display: block !important; font-size: 0.85rem !important; font-weight: 700 !important; padding: 10px 16px !important;
       border-radius: 20px !important; white-space: normal !important; overflow: hidden !important; text-overflow: ellipsis !important;
       max-width: 90% !important; border: 1px solid rgba(0,0,0,0.1) !important; transition: all 0.2s ease !important; line-height: 1.4 !important;
    }

    .timeline-block.active .collapsed-label, .timeline-block.focused .collapsed-label { color: #fff !important; box-shadow: 0 6px 15px rgba(0,0,0,0.15) !important; border-color: transparent !important;}
    .timeline-block.active[data-track="blue"] .collapsed-label, .timeline-block.focused[data-track="blue"] .collapsed-label { background: var(--tenki-blue) !important; }
    .timeline-block.active[data-track="green"] .collapsed-label, .timeline-block.focused[data-track="green"] .collapsed-label { background: var(--tenki-green) !important; }
    .timeline-block.active[data-track="black"] .collapsed-label, .timeline-block.focused[data-track="black"] .collapsed-label { background: var(--tenki-black) !important; }
    .timeline-block.active[data-track="white"] .collapsed-label, .timeline-block.focused[data-track="white"] .collapsed-label { background: var(--tenki-white-stroke) !important; }

    /* Non-active bubbles carry a soft tint of their track color */
    .timeline-block:not(.active):not(.focused)[data-track="blue"] .collapsed-label { background: var(--tenki-blue-light) !important; color: var(--tenki-blue) !important; border-color: rgba(0,90,156,0.2) !important; }
    .timeline-block:not(.active):not(.focused)[data-track="green"] .collapsed-label { background: var(--tenki-green-light) !important; color: var(--tenki-green) !important; border-color: rgba(0,140,69,0.2) !important; }
    .timeline-block:not(.active):not(.focused)[data-track="black"] .collapsed-label { background: #f0f0f0 !important; color: var(--tenki-black) !important; border-color: rgba(0,0,0,0.12) !important; }
    .timeline-block:not(.active):not(.focused)[data-track="white"] .collapsed-label { background: var(--tenki-white-light) !important; color: var(--tenki-white-stroke) !important; border-color: var(--tenki-white-border) !important; }

    /* STRICT LOCAL YEAR COLLAPSE CSS overrides */
    html body .timeline-block.collapsed-by-year .collapsed-label,
    html body .timeline-block.collapsed-by-year[data-track] .collapsed-label,
    html body .timeline-block.collapsed-by-year:not(.active)[data-track] .collapsed-label {
        display: none !important;
    }
    .timeline-block.collapsed-by-year { min-height: 20px !important; margin-bottom: 5px !important; }

    /* ── Duration Line (mobile: downward from node bottom) ── */
    /* Sibling of .timeline-node; node sits at top:50%/left:-32px/18×18.      */
    /* Node visual bottom = 50%+9px; left/height overridden by JS per lane.   */
    .duration-line-ext {
      top: calc(50% + 9px);  /* node visual bottom — JS also sets top:auto    */
      left: -25px;            /* lane-0 default; JS overrides per lane         */
      width: 5px;
      height: 0;              /* set dynamically by updateDurationLines()      */
      border-radius: 0 0 3px 3px;
      opacity: 0.28;
    }
    /* Stem and dot are desktop-only — hide on mobile */
    .duration-stem,
    .duration-dot { display: none; }

    /* ── Mobile lane-stem connector ──────────────────────────────────
       Connects each duration bar's TOP to the event's node circle
       when the bar is offset into lane 1, 2, 3+ (i.e. when this
       event's duration overlaps another concurrent event so the bar
       gets shifted LEFT of the node to its own lane).  Lane 0 bars
       sit roughly under the node — no stem needed there.
       Width is set via the --tl-mob-stem-w CSS variable from the
       lane-assignment JS pass.  Color uses currentColor inherited
       from per-track rules below. */
    .duration-line-ext::before {
      content: '';
      position: absolute;
      top: 0;
      /* Stem extends LEFT from the bar's left edge to the node center,
         so the bar always intersects (touches) its activity's stem. */
      left: calc(-1 * var(--tl-mob-stem-w, 0));
      width: var(--tl-mob-stem-w, 0);
      height: 3px;
      background-color: currentColor;
      border-radius: 2px;
      pointer-events: none;
    }
    /* currentColor on a pseudo reads the CASCADED `color` value, so
       set color to the track tint via per-track selectors below. */
    .timeline-block[data-track="blue"]  .duration-line-ext { color: var(--tenki-blue); }
    .timeline-block[data-track="green"] .duration-line-ext { color: var(--tenki-green); }
    .timeline-block[data-track="black"] .duration-line-ext { color: var(--tenki-black); }
    .timeline-block[data-track="white"] .duration-line-ext { color: var(--tenki-white-stroke); }
    .timeline-block.active  .duration-line-ext,
    .timeline-block.focused .duration-line-ext { opacity: 0.75; }
    .timeline-block.collapsed-by-year   .duration-line-ext { opacity: 0 !important; }
    .timeline-block.super-hidden-by-year .duration-line-ext { display: none !important; }

    /* ── Expanded Details Mobile Logic ─────────────────────────────────
       2026-05-29 (user-requested):
       - Detailed view (default, no .simplified-view class):
           EVERY card shows its full mobile-inline-details so the user
           sees all the data without needing to tap individually.
           Selected for: "the detailed view on mobile should expand
           all activities with all data".
       - Simplified view (.simplified-view):
           ONLY the .active card shows its details — tap a card to
           expand it, tap another to swap.  Selected for: "user should
           be able to tap on the selected activity and the additional
           details for the card (like the sidebar card opens)".  Note
           the simplified-view's blanket "hide mobile-inline-details"
           rule at line ~700 is OVERRIDDEN on .active cards via the
           specificity bump below. */

    /* Detailed view → ALL cards expanded inline. */
    .dashboard-container:not(.simplified-view) .timeline-block .mobile-inline-details {
      display: block !important;
      margin-top: 12px !important;
      padding-top: 12px !important;
      border-top: 1px solid rgba(226, 232, 240, 0.6) !important;
    }
    /* Simplified view → only the active card expanded. */
    .dashboard-container.simplified-view .timeline-block.active .timeline-card .mobile-inline-details {
      display: block !important;
      margin-top: 12px !important;
      padding-top: 12px !important;
      border-top: 1px solid rgba(226, 232, 240, 0.6) !important;
    }
    /* Backward-compat: keep the bare .active rule too for any code path
       that classes a block .active without changing the view mode. */
    .timeline-block.active .mobile-inline-details {
      display: block !important; margin-top: 12px !important; padding-top: 12px !important; border-top: 1px solid rgba(226, 232, 240, 0.6) !important;
    }
    .mobile-inline-details p { margin-bottom: 10px !important; font-size: 0.9rem !important; color: var(--text-light) !important; line-height: 1.4 !important; white-space: normal !important; }
    .mobile-inline-details .details-region { font-size: 0.8rem !important; font-weight: 700 !important; color: var(--text-light) !important; margin-bottom: 8px !important; text-transform: uppercase !important; letter-spacing: 0.5px !important; }
    .mobile-inline-details .locations-list { max-height: 140px !important; }
    .mobile-inline-details .details-cta-group { margin-top: 5px !important; flex-direction: row !important; flex-wrap: wrap !important; gap: 8px !important; }
    .mobile-inline-details .details-cta-link { padding: 8px 12px !important; font-size: 0.75rem !important; width: auto !important; flex: 1; min-width: 120px; }
    /* The OLD in-card mini-map is suppressed on mobile in favor of the new
       map-tab-drawer below the Map tab button.  Keeping the markup in DOM
       so any external CSS targeting it doesn't error — just hide it. */
    .mobile-mini-map-host { display: none !important; }

    .return-to-map-btn { display: none !important; } /* Stripped completely from Mobile UI */

    /* ── Tap-to-explore overlay (mobile only) ───────────────────────────
       Shown over the timeline section by default.  User must tap this
       overlay to enter immersive mode — the deliberate gesture replaces
       the earlier "tap any event → suddenly fullscreen" surprise.
       Reset button styling so the <button> looks like a panel. */
    .tenki-explore-overlay {
      display: flex !important;
      position: absolute;
      /* JS sets `top` to the bottom of the mobile-tab-bar.  Filter
         chips + title sit ABOVE the overlay so they remain interactive.
         (Filter clicks also call enterImmersive — see the click-
         capture in positionTabDrawers below.)  Falls back to 240 px
         while JS is booting. */
      top: 240px;
      left: 0; right: 0; bottom: 0;
      width: 100%;
      /* border-box is REQUIRED: with content-box, width:100% + the 20px side
         padding made the overlay 40px WIDER than the (margin:auto-centered)
         dashboard, anchored at left:0 → its centre sat ~20px right of the
         viewport centre, so the flex-centred card + enter prompt rendered
         shoved right / clipped (the "entry overlay offset" bug; the earlier
         max-width:100vw cap addressed only the over-wide case, not this).
         border-box makes the overlay exactly match the centered dashboard so
         the card centres on screen. Do NOT remove. */
      box-sizing: border-box;
      /* Anchor the card NEAR THE TOP of the masked region (just below the
         filter chips), not centered: on a tall phone the overlay spans
         top→bottom of the dashboard, so centering floated the card low with a
         big empty gap beneath it (reported 2026-06).  flex-start + a top pad
         keeps it over the timeline content where the eye already is. */
      align-items: flex-start;
      justify-content: center;
      padding: 28px 20px;
      /* Near-opaque clean canvas (no blur) so the live timeline/map behind
         is fully masked — the rich teaser is the purpose-built
         .tenki-explore-preview mini-render drawn ON TOP of this. */
      background: #f8f9fa;
      border: none;
      cursor: pointer;
      z-index: 99998;
      transition: opacity 0.25s ease, visibility 0s linear 0.25s;
      -webkit-tap-highlight-color: transparent;
    }
    /* When immersive mode is active, hide the overlay (user has already
       "entered" — no more invitation needed).  Visibility flip is delayed
       so the fade-out finishes before the overlay leaves the layout. */
    .dashboard-container.is-immersive .tenki-explore-overlay,
    .tenki-explore-overlay.dismissed {
      opacity: 0;
      visibility: hidden;
      pointer-events: none;
    }
    /* ── Shrunk timeline preview behind the explore card ───────────────
       A miniature render of the real timeline (one mini-row per event,
       track-coloured node on a faint spine) so the visitor sees the
       depth of content awaiting them.  Top-anchored; the lower portion
       fades out (mask) so the "Tap to explore" card sits over calm
       space.  pointer-events:none — the overlay button captures taps. */
    .tenki-explore-preview {
      position: absolute;
      top: 0; left: 0; right: 0; bottom: 0;
      padding: 14px 16px 0;
      overflow: hidden;
      pointer-events: none;
      -webkit-mask-image: linear-gradient(to bottom, #000 0%, #000 34%, rgba(0,0,0,0.28) 60%, rgba(0,0,0,0.05) 100%);
              mask-image: linear-gradient(to bottom, #000 0%, #000 34%, rgba(0,0,0,0.28) 60%, rgba(0,0,0,0.05) 100%);
    }
    .tenki-explore-preview-rail {
      position: relative;
      padding-left: 20px;
      display: flex;
      flex-direction: column;
      gap: 7px;
    }
    .tenki-explore-preview-rail::before {
      content: '';
      position: absolute;
      left: 6px; top: 6px; bottom: 6px;
      width: 2px;
      background: linear-gradient(to bottom, rgba(0,90,156,0.40), rgba(0,90,156,0.06));
      border-radius: 2px;
    }
    .tenki-prev-row {
      position: relative;
      display: flex;
      align-items: center;
      gap: 8px;
      padding: 6px 10px;
      background: #fff;
      border-radius: 9px;
      box-shadow: 0 1px 4px rgba(0,0,0,0.07);
    }
    .tenki-prev-dot {
      position: absolute;
      left: -16px; top: 50%;
      transform: translateY(-50%);
      width: 9px; height: 9px;
      border-radius: 50%;
      box-shadow: 0 0 0 2px #fff;
    }
    .tenki-prev-title {
      font-size: 0.76rem;
      font-weight: 700;
      color: #1a2b3c;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
      min-width: 0;
    }
    .tenki-prev-date {
      font-size: 0.6rem;
      font-weight: 800;
      letter-spacing: 0.3px;
      text-transform: uppercase;
      color: var(--text-light);
      margin-left: auto;
      flex: 0 0 auto;
      white-space: nowrap;
    }

    /* ── 2026-05-29 BIG SWAP: mobile Simplified view = compact tappable
       list ───────────────────────────────────────────────────────────
       The former Simplified carousel is now the Detailed view; this
       glanceable list (mirrors the tap-to-explore teaser format) becomes
       the new Simplified default.  It shows only when .list-view is set
       AND we're on the timeline tab (not the map tab).  Tapping a row
       expands it inline to reveal date range / region / detail / CTA. */
    .dashboard-container.list-view:not(.mobile-map-view) .timeline-outer-wrapper { display: none !important; }
    .dashboard-container.list-view:not(.mobile-map-view) .tenki-mobile-list { display: block; }
    .tenki-mobile-list {
      width: 100%;
      /* Top padding clears the map-peek tab (.map-tab-drawer.is-low, ~46px
         tall, z-30, top-right) so it doesn't sit over / intercept taps on
         the first row. */
      padding: 54px 14px calc(24px + env(safe-area-inset-bottom));
      box-sizing: border-box;
      order: 5;
    }
    .tenki-mlist-rail {
      position: relative;
      padding-left: 22px;
      display: flex;
      flex-direction: column;
      gap: 9px;
    }
    .tenki-mlist-rail::before {
      content: '';
      position: absolute;
      left: 7px; top: 12px; bottom: 12px;
      width: 2px;
      background: linear-gradient(to bottom, rgba(0,90,156,0.40), rgba(0,90,156,0.10));
      border-radius: 2px;
    }
    .tenki-mlist-row {
      position: relative;
      background: #fff;
      border-radius: 12px;
      box-shadow: 0 1px 5px rgba(0,0,0,0.08);
      border-left: 4px solid var(--tenki-blue);
      overflow: hidden;
    }
    .tenki-mlist-row[data-track="blue"]  { border-left-color: var(--tenki-blue); }
    .tenki-mlist-row[data-track="green"] { border-left-color: var(--tenki-green); }
    .tenki-mlist-row[data-track="black"] { border-left-color: var(--tenki-black); }
    .tenki-mlist-row[data-track="white"] { border-left-color: var(--tenki-white-border); }
    .tenki-mlist-head {
      display: flex;
      align-items: center;
      gap: 9px;
      padding: 12px;
      min-height: 44px;
      box-sizing: border-box;
      cursor: pointer;
      -webkit-tap-highlight-color: transparent;
    }
    .tenki-mlist-dot {
      position: absolute;
      left: -19px; top: 22px;
      width: 11px; height: 11px;
      border-radius: 50%;
      box-shadow: 0 0 0 2px #fff;
    }
    .tenki-mlist-icon { font-size: 1rem; line-height: 1; flex: 0 0 auto; }
    .tenki-mlist-title {
      font-size: 0.95rem;
      font-weight: 700;
      color: #1a2b3c;
      line-height: 1.25;
      min-width: 0;
      flex: 1 1 auto;
    }
    .tenki-mlist-date {
      font-size: 0.62rem;
      font-weight: 800;
      letter-spacing: 0.3px;
      text-transform: uppercase;
      color: var(--text-light);
      flex: 0 0 auto;
      white-space: nowrap;
    }
    .tenki-mlist-chevron {
      flex: 0 0 auto;
      display: flex;
      align-items: center;
      justify-content: center;
      width: 18px; height: 18px;
      color: var(--text-light);
      transition: transform 0.25s ease;
    }
    .tenki-mlist-row.expanded .tenki-mlist-chevron { transform: rotate(180deg); }
    .tenki-mlist-body {
      display: none;
      padding: 0 14px 14px 14px;
      flex-direction: column;
      gap: 8px;
    }
    .tenki-mlist-row.expanded .tenki-mlist-body { display: flex; }
    .tenki-mlist-meta {
      display: flex;
      flex-wrap: wrap;
      align-items: center;
      gap: 4px 12px;
      font-size: 0.78rem;
      color: var(--text-light);
      font-weight: 600;
    }
    .tenki-mlist-range { color: var(--text-dark); }
    .tenki-mlist-desc {
      font-size: 0.86rem;
      line-height: 1.5;
      color: #34465a;
      margin: 0;
      white-space: pre-line;
    }
    .tenki-mlist-cta {
      align-self: flex-start;
      display: inline-flex;
      align-items: center;
      gap: 6px;
      padding: 9px 16px;
      border-radius: 999px;
      background: var(--tenki-blue);
      color: #fff;
      font-size: 0.82rem;
      font-weight: 700;
      text-decoration: none;
      min-height: 40px;
      box-sizing: border-box;
    }
    .tenki-mlist-row[data-track="green"] .tenki-mlist-cta { background: var(--tenki-green); }
    .tenki-mlist-row[data-track="black"] .tenki-mlist-cta { background: var(--tenki-black); }
    .tenki-mlist-row[data-track="white"] .tenki-mlist-cta { background: #555; }

    .tenki-explore-overlay-card {
      display: flex;
      flex-direction: column;
      align-items: center;
      gap: 8px;
      padding: 22px 26px;
      background: var(--tenki-white);
      border-radius: 18px;
      box-shadow: 0 12px 36px rgba(0, 90, 156, 0.18);
      border-top: 4px solid var(--tenki-blue);
      max-width: 320px;
      text-align: center;
      pointer-events: none;     /* parent button captures the tap */
      transform: translateY(0);
      animation: tenkiExploreBob 2.6s ease-in-out infinite;
    }
    .tenki-explore-overlay-icon {
      font-size: 1.8rem;
      line-height: 1;
      animation: tenkiExploreTap 1.6s ease-in-out infinite;
    }
    .tenki-explore-overlay-title {
      font-size: 1rem;
      font-weight: 800;
      color: var(--tenki-blue);
      letter-spacing: 0.3px;
    }
    .tenki-explore-overlay-sub {
      font-size: 0.78rem;
      font-weight: 600;
      color: var(--text-light);
      line-height: 1.35;
    }
    @keyframes tenkiExploreBob {
      0%, 100% { transform: translateY(0); }
      50%      { transform: translateY(-4px); }
    }
    @keyframes tenkiExploreTap {
      0%, 60%, 100% { transform: scale(1); opacity: 0.9; }
      30%           { transform: scale(1.15); opacity: 1; }
    }

    /* ── Map preview drawer (attached to the Map tab) ──────────────────
       Hidden by default — populated + expanded when a timeline event is
       activated and has at least one pin.  Non-interactive country-zoom
       Leaflet render; the whole drawer is the click target → opens the
       full Map tab.  Lives between the tab bar (order:4) and the
       timeline scroll area (order:5) so it visually emerges from BELOW
       the Map tab button. */
    /* ── Tab-attached drawers (overlay model) ──────────────────────────
       Both drawers float OVER the top of the timeline content using
       position:absolute anchored to the dashboard-container's clip
       region.  They do NOT push the timeline rows down — the user keeps
       reading the timeline below them.  Bottom corners rounded so each
       drawer reads as a fabric pull / bookmark hanging from the tab bar.

       Position math:
         The dashboard's mobile layout (top-down) is:
           dashboard-header  (~60 px)
           dashboard-controls (~60 px filters)
           mobile-tab-bar     (~46 px Timeline | Map)
           timeline-outer-wrapper  ← drawers hang OVER the top of this
         The drawers' `top` is JS-driven (positionTabDrawers()) so they
         always sit immediately below the tab bar regardless of how the
         filter row scrolls horizontally. */
    /* ── Three-state drawer system ─────────────────────────────────────
       hidden  = max-height:0, opacity:0  (no event selected)
       is-low  = small (~40 px), shows label only
       is-full = tall, shows rich content (map / tags)
       Drawer handle (.drawer-handle) at the bottom lets the user
       step DOWN: full → low → hidden.  Tab buttons show event-derived
       labels in is-full state (see the .has-event-label rules). */
    /* 2026-05-29 (proper drawer this time): timeline-tab-drawer is
       now a real drawer mirroring the map-tab-drawer pattern — but
       on the LEFT half, under the Timeline tab.  position: absolute
       via the same positionTabDrawers() JS that places map-tab-
       drawer + tenki-explore-overlay.  Hosts ONLY the relocated
       Simplified ⇆ Full Story toggle button.  Default state is
       is-low (always visible when on the Timeline tab); hidden via
       state-class removal when on the Map tab. */
    .timeline-tab-drawer {
      position: absolute;
      width: 50%;
      left: 0;
      right: auto;
      top: 0;            /* JS overrides via positionTabDrawers() */
      z-index: 30;
      background: rgba(255, 255, 255, 0.82);
      backdrop-filter: blur(8px) saturate(1.05);
      -webkit-backdrop-filter: blur(8px) saturate(1.05);
      overflow: hidden;
      opacity: 0;
      max-height: 0;
      pointer-events: none;
      transition: max-height 0.32s ease, opacity 0.22s ease, transform 0.32s ease;
      transform: translateY(-4px);
      border-radius: 0 0 16px 16px;
      border: 1px solid rgba(226, 232, 240, 0.7);
      border-top: none;
      box-shadow: 0 12px 24px rgba(0, 0, 0, 0.10);
      display: flex !important;
      align-items: center;
      justify-content: center;
      padding: 0 10px;
    }
    .timeline-tab-drawer.is-low {
      opacity: 1;
      pointer-events: auto;
      transform: translateY(0);
      max-height: 50px;
    }
    /* When the user is on the Map tab, hide our drawer entirely so
       the map gets a clean stage.  Map drawer takes over the right
       half. */
    .dashboard-container.mobile-map-view .timeline-tab-drawer {
      opacity: 0 !important;
      max-height: 0 !important;
      pointer-events: none !important;
    }
    /* Hide the legacy children inside this drawer — we ONLY host
       the relocated depth-toggle now.  Also hide the .drawer-handle
       grip — the timeline drawer is a single-state chip, no
       cycle-state to advertise. */
    .timeline-tab-drawer .tab-drawer-low-label,
    .timeline-tab-drawer .timeline-tab-drawer-tags,
    .timeline-tab-drawer .drawer-handle { display: none !important; }
    /* When the depth-toggle has been moved INTO the timeline-tab-drawer,
       size it neatly and let it be the entire visible payload. */
    .timeline-tab-drawer .depth-toggle {
      position: static !important;
      top: auto !important; right: auto !important;
      bottom: auto !important; left: auto !important;
      margin: 0 !important;
      box-shadow: none !important;
      z-index: auto !important;
    }
    /* Hide the title-in-tab-button on the CURRENTLY-ACTIVE tab — its
       value is "what's selected on the OTHER tab" so the user can see
       what event they're returning to.  Showing it on the active tab
       just repeats the title already on the card / drawer below.  */
    .mobile-tab.active .mobile-tab-event-label { display: none !important; }
    .mobile-tab.active.has-event-label > :not(.mobile-tab-event-label) {
      display: inline-flex !important;
    }
    /* The .expanded-title-card is a desktop-only construct (simplified
       view's title chip strip).  On mobile it was leaking into the
       active card column when the user toggled Simplified mode,
       double-printing every event title.  Hard-hide on mobile. */
    .expanded-title-card { display: none !important; }
    .map-tab-drawer {
      position: absolute;
      left: 0; right: 0;
      top: 0;
      z-index: 30;
      background: rgba(255, 255, 255, 0.82);
      backdrop-filter: blur(8px) saturate(1.05);
      -webkit-backdrop-filter: blur(8px) saturate(1.05);
      overflow: hidden;
      opacity: 0;
      max-height: 0;
      pointer-events: none;
      transition: max-height 0.32s ease, opacity 0.22s ease, transform 0.32s ease;
      transform: translateY(-4px);
      border-radius: 0 0 16px 16px;
      border: 1px solid rgba(226, 232, 240, 0.7);
      border-top: none;
      box-shadow: 0 12px 24px rgba(0, 0, 0, 0.10);
      display: block !important;
    }
    .map-tab-drawer.is-low,
    .timeline-tab-drawer.is-low,
    .map-tab-drawer.is-full,
    .timeline-tab-drawer.is-full {
      opacity: 1;
      pointer-events: auto;
      transform: translateY(0);
    }
    /* Hide all the FULL-only content elements while in is-low */
    .map-tab-drawer.is-low .map-tab-drawer-frame,
    .timeline-tab-drawer.is-low .timeline-tab-drawer-tags { display: none !important; }
    /* Hide the LOW-only label while in is-full */
    .map-tab-drawer.is-full .tab-drawer-low-label,
    .timeline-tab-drawer.is-full .tab-drawer-low-label { display: none !important; }

    /* Drawer handle — small grip pill at the bottom edge.  Tap to
       cycle the drawer's state down (full → low → hidden).  Sized as
       a 44 px tappable hit target.  Now animated with a subtle pulse
       so users see it AS an interactive element instead of dismissing
       it as a passive divider. */
    .drawer-handle {
      display: flex;
      align-items: center;
      justify-content: center;
      width: 100%;
      height: 22px;
      background: transparent;
      cursor: pointer;
      border: none;
      padding: 0;
      position: relative;
    }
    .drawer-handle::after {
      content: '';
      display: block;
      width: 44px;
      height: 4px;
      border-radius: 2px;
      background: rgba(100, 116, 139, 0.45);
      transition: background 0.15s ease, width 0.15s ease;
      /* Finite pulse — 3 cycles total = 8.4 s, then stops.  Earlier
         `infinite` was nauseating combined with the CTA pulse below.
         The pulse only fires when the drawer FIRST appears (via the
         keyframe start), so users still get the "interactive" cue. */
      animation: drawerHandlePulse 2.8s ease-in-out 3;
    }
    .drawer-handle:hover::after,
    .drawer-handle:focus-visible::after {
      background: var(--tenki-blue);
      width: 52px;
      animation: none;
    }
    .drawer-handle:focus-visible { outline: none; }
    /* Gentle pulse so the user sees the handle is interactive.  Steps
       through opacity + width so the pill "breathes" — never gets so
       big it crowds the drawer below, never so small it disappears. */
    @keyframes drawerHandlePulse {
      0%, 100% {
        opacity: 0.55;
        width: 44px;
        background: rgba(100, 116, 139, 0.45);
      }
      50% {
        opacity: 1;
        width: 56px;
        background: rgba(0, 90, 156, 0.55);
      }
    }
    @media (prefers-reduced-motion: reduce) {
      .drawer-handle::after { animation: none; }
    }
    /* Low-state label row — shown only in is-low.  Compact pill with
       the contextual label (event title / region / "Sierra Leone"). */
    .tab-drawer-low-label {
      display: flex;
      align-items: center;
      gap: 8px;
      padding: 6px 14px 8px;
      font-size: 0.78rem;
      font-weight: 700;
      color: var(--tenki-blue);
      letter-spacing: 0.15px;
      line-height: 1.25;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
    }
    .tab-drawer-low-label-icon { font-size: 0.9rem; flex-shrink: 0; }
    .tab-drawer-low-label-text {
      flex: 1;
      overflow: hidden;
      text-overflow: ellipsis;
    }
    /* ── Right drawer (Map tab) ─────────────────────────────
       Holds the country-zoom mini-map.  Caption is now just the visual
       under-frame border-radius — the pin-count + region/location
       label moves UP onto the Map tab button itself (see the
       map-tab-loc-chip rule + JS populateMapTabDrawer). */
    .map-tab-drawer {
      width: 50%;
      left: auto;
      right: 0;
      cursor: pointer;
    }
    .map-tab-drawer.is-low  { max-height: 50px; }
    .map-tab-drawer.is-full { max-height: 175px; }
    /* 2026-05-29: Mini-map drawer cleanup —
       (1) drop the pull-bar grip ("bar toggle") so the map drawer is one
           clean tap target (tap = open the full map), mirroring how the
           Detailed-view (timeline-tab) drawer already hides its handle;
       (2) match the map drawer's LOW height to the Detailed-view drawer so
           the two tabs hang symmetrically below the tab bar. */
    .map-tab-drawer .drawer-handle { display: none !important; }
    .timeline-tab-drawer.is-low,
    .map-tab-drawer.is-low {
      height: 46px !important;
      max-height: 46px !important;
    }
    /* Vertically center the region label now that the pull bar no longer
       occupies the bottom of the low-state drawer. */
    .map-tab-drawer.is-low {
      display: flex !important;
      align-items: center !important;
      justify-content: center !important;
    }
    .map-tab-drawer.is-low .tab-drawer-low-label { padding: 0 14px !important; }
    .map-tab-drawer:hover { background: rgba(255, 255, 255, 0.92); }
    .map-tab-drawer:focus-visible { outline: 2px solid var(--tenki-blue); outline-offset: -2px; }
    .map-tab-drawer-frame {
      width: 100%; height: 140px;
      background: rgba(243, 244, 246, 0.65);
      position: relative;
      /* 2026-05-29: was pointer-events:none (the whole drawer acted as a
         click-to-open-full-map button).  The mini-map is now interactive,
         so the frame must accept pan / pinch / tap.  The drawer's click
         handler ignores taps inside this frame when is-full. */
      pointer-events: auto;
    }
    /* Keep the attribution badge hidden, but SHOW the zoom +/- control
       (added 2026-05-29 when the drawer map became interactive). */
    .map-tab-drawer-frame .leaflet-control-attribution { display: none !important; }
    .map-tab-drawer-frame .leaflet-control-zoom {
      margin: 8px 8px 0 0 !important;
      box-shadow: 0 1px 4px rgba(0,0,0,0.25) !important;
    }
    .map-tab-drawer-frame .leaflet-control-zoom a {
      width: 28px !important; height: 28px !important; line-height: 28px !important;
      font-size: 18px !important;
    }
    /* Map-tab BUTTON label overlay — when an event with locations is
       active, this chip overlays the "Map" text in the tab bar showing
       "📍 Bo Region" / "📍 Kambia" / "📍 3 pins" (whichever is most
       descriptive — see populateMapTabDrawer for the JS logic).  This
       replaces the pin-count caption that USED to sit under the mini-
       map; freed-up vertical space lets the map render taller. */
    /* ── Tab-button event-label overlay ─────────────────────────────
       Both tabs gain an absolute-positioned chip that swaps in over
       the original "Timeline" / "Map" text when the drawer is in
       is-full state.  Shows the event-derived label (title for
       Timeline, region/location for Map).  CSS replaces the entire
       button content via opacity/visibility — no layout shift. */
    .mobile-tab-event-label {
      display: none;
      position: absolute;
      left: 4px; right: 4px;
      top: 0; bottom: 0;
      align-items: center;
      justify-content: center;
      gap: 5px;
      font-size: 0.72rem; font-weight: 800;
      color: var(--tenki-blue);
      background: rgba(238, 245, 251, 0.96);
      letter-spacing: 0.1px;
      padding: 4px 6px;
      line-height: 1.15;
      text-align: center;
      overflow: hidden;
      pointer-events: none;
      border-radius: 5px;
    }
    /* Container has-event-label on each tab.  Toggled by drawer JS. */
    .mobile-tab.has-event-label { position: relative; }
    .mobile-tab.has-event-label .mobile-tab-event-label { display: flex; }
    .mobile-tab.has-event-label > svg,
    .mobile-tab.has-event-label > :not(.mobile-tab-event-label) {
      opacity: 0;
      transition: opacity .15s ease;
    }
    .mobile-tab-event-label-icon { font-size: 0.85rem; flex-shrink: 0; align-self: flex-start; margin-top: 1px; }
    .mobile-tab-event-label-text {
      overflow: hidden;
      max-width: 100%;
      /* Allow up to 2 lines so long event names don't get truncated with
         "…" in the tab button.  -webkit-line-clamp:2 + word-break give
         a graceful fallback if the name is still too long for two lines. */
      display: -webkit-box;
      -webkit-line-clamp: 2;
      -webkit-box-orient: vertical;
      white-space: normal;
      word-break: break-word;
      line-height: 1.15;
    }
    /* Legacy alias for the old map-tab-loc-chip selector (left here
       in case any inline JS still toggles it). */
    .map-tab-loc-chip { display: none !important; }

    /* ── Left drawer (Timeline tab) ────────────────────────
       Carries the active event's title (wrappable across 2 lines) + a
       row of phase/funding tags BELOW it.  These tags used to live on
       the activity card itself — moving them here declutters the card
       and gives the drawer real content to justify its size. */
    .timeline-tab-drawer {
      width: 50%;
      left: 0;
      right: auto;
      cursor: default;
      background: rgba(247, 251, 255, 0.85);
    }
    .timeline-tab-drawer.is-low  { max-height: 50px; }
    /* Full state now matches the map drawer's 175 px so the two visually
       balance — and the inner row scrolls if the content is taller than
       the drawer (more tags / updated-on line / future expansion). */
    .timeline-tab-drawer.is-full { max-height: 195px; }
    .timeline-tab-drawer-row {
      display: flex;
      flex-direction: column;
      gap: 6px;
      padding: 10px 14px 22px;        /* extra bottom padding clears the handle */
      font-size: 0.86rem;
      font-weight: 800;
      color: var(--tenki-blue);
      line-height: 1.2;
      letter-spacing: 0.15px;
      max-height: 175px;
      overflow-y: auto;
      -webkit-overflow-scrolling: touch;
    }
    /* Scrollbar styling — slim + tenki-blue tinted, only shows when
       there's overflow.  Webkit + Firefox both supported. */
    .timeline-tab-drawer-row::-webkit-scrollbar { width: 4px; }
    .timeline-tab-drawer-row::-webkit-scrollbar-thumb {
      background: rgba(0, 90, 156, 0.3);
      border-radius: 2px;
    }
    .timeline-tab-drawer-row { scrollbar-width: thin; scrollbar-color: rgba(0,90,156,0.3) transparent; }
    .timeline-tab-drawer-title-row {
      display: flex;
      align-items: flex-start;
      gap: 6px;
    }
    .timeline-tab-drawer-icon {
      flex-shrink: 0;
      font-size: 0.92rem;
      line-height: 1.3;
    }
    .timeline-tab-drawer-text {
      flex: 1;
      /* Allow up to 2 lines with ellipsis fallback for very long titles */
      display: -webkit-box;
      -webkit-line-clamp: 2;
      -webkit-box-orient: vertical;
      overflow: hidden;
      white-space: normal;
      word-break: break-word;
      line-height: 1.2;
    }
    .timeline-tab-drawer-tags {
      display: flex;
      flex-wrap: wrap;
      gap: 4px 6px;
      padding-left: 19px;        /* aligns under the title text */
    }
    .timeline-tab-drawer-tags:empty { display: none; }
    /* Compact pill versions of phase/funding badges for the drawer.
       Use the same color tokens as the card-side badges so the visual
       language stays consistent across the two locations. */
    .ttd-tag {
      display: inline-flex;
      align-items: center;
      gap: 4px;
      font-size: 0.78rem;          /* was 0.58 — bumped for readability */
      font-weight: 800;
      text-transform: uppercase;
      letter-spacing: 0.4px;
      padding: 5px 11px;            /* was 2px 7px — more breathing room */
      border-radius: 5px;
      /* Allow text to wrap when the badge would otherwise clip past
         the drawer's right edge — "PARTIALLY FUNDED · SCOPE LIMITED"
         was being truncated to "PARTIALLY FUNDED »" on narrow phone
         drawers.  word-break ensures the · separator can break a
         line cleanly without splitting individual words. */
      white-space: normal;
      word-break: break-word;
      max-width: 100%;
      line-height: 1.3;
    }
    .ttd-tag-icon { font-size: 0.85rem; line-height: 1; }
    .ttd-tag.phase-accomplished { background: var(--phase-accomplished-bg); color: var(--phase-accomplished-text); }
    .ttd-tag.phase-planning     { background: var(--phase-planning-bg);     color: var(--phase-planning-text); }
    .ttd-tag.phase-execution    { background: var(--phase-execution-bg);    color: var(--phase-execution-text); }
    .ttd-tag.phase-future       { background: var(--tenki-blue-light);      color: var(--tenki-blue); }
    .ttd-tag.funding-seeking    { background: #fff0f0; color: #d32f2f; border: 1px solid rgba(211, 47, 47, 0.2); }
    .ttd-tag.funding-partial    { background: #fff9e6; color: #e65100; border: 1px solid rgba(230, 81, 0, 0.2); }
    .ttd-tag.funding-full       { background: #e8f5e9; color: #2e7d32; border: 1px solid rgba(46, 125, 50, 0.2); }
    .ttd-tag.funding-active     { background: #e3f2fd; color: #0d47a1; border: 1px dashed #0d47a1; font-weight: 900; }
    /* When the funding tag is rendered as a clickable <button> (mobile
       drawer — see populateTimelineTabDrawer), strip the browser's
       default button chrome and add cursor + subtle hover so it reads
       as a tappable chip rather than a label. */
    button.ttd-tag {
      font-family: inherit; font-size: inherit; line-height: inherit;
      cursor: pointer;
      transition: transform .15s ease, box-shadow .15s ease, filter .15s ease;
      -webkit-tap-highlight-color: rgba(0, 90, 156, 0.15);
    }
    button.ttd-tag:active { transform: scale(0.95); }
    button.ttd-tag:hover  { filter: brightness(0.96); box-shadow: 0 2px 6px rgba(0,0,0,0.08); }
    /* Tiny "tap me" affordance — a chevron after the funding badge
       text on mobile so the click target reads as actionable */
    button.ttd-tag.funding-badge::after {
      content: ' ›';
      font-weight: 800;
      opacity: 0.7;
      margin-left: 2px;
    }

    /* ── Pillar pill — shows which pillar this event belongs to ───────
       Colored by track (blue/green/black/white).  Sits alongside the
       phase + funding tags in the full drawer state.  Tap → eventually
       routes to the pillar's deep-dive page (not wired yet — placeholder). */
    .ttd-pillar-pill {
      display: inline-flex;
      align-items: center;
      gap: 5px;
      font-size: 0.78rem;
      font-weight: 800;
      letter-spacing: 0.3px;
      padding: 5px 11px;
      border-radius: 5px;
      white-space: nowrap;
      line-height: 1.3;
      border: 1px solid transparent;
    }
    .ttd-pillar-pill.track-blue  { background: var(--tenki-blue-light);  color: var(--tenki-blue);  border-color: rgba(0,90,156,0.15); }
    .ttd-pillar-pill.track-green { background: var(--tenki-green-light); color: var(--tenki-green); border-color: rgba(0,140,69,0.15); }
    .ttd-pillar-pill.track-black { background: #f4f4f4;                  color: var(--tenki-black); border-color: rgba(0,0,0,0.10); }
    .ttd-pillar-pill.track-white { background: var(--tenki-white-light); color: var(--tenki-white-stroke); border-color: var(--tenki-white-border); }
    .ttd-pillar-pill-icon { font-size: 0.95rem; line-height: 1; }
    /* Pillar pill is a link → underline-on-hover + subtle shift */
    a.ttd-pillar-pill {
      text-decoration: none;
      transition: transform 0.15s ease, box-shadow 0.15s ease;
    }
    a.ttd-pillar-pill:hover,
    a.ttd-pillar-pill:active {
      transform: translateY(-1px);
      box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
    }

    /* Updated/freshness chip — neutral gray pill with clock icon */
    .ttd-updated {
      display: inline-flex;
      align-items: center;
      gap: 5px;
      font-size: 0.72rem;
      font-weight: 700;
      color: var(--text-light);
      background: rgba(0, 0, 0, 0.04);
      padding: 4px 10px;
      border-radius: 5px;
      letter-spacing: 0.2px;
      white-space: nowrap;
      line-height: 1.3;
    }
    .ttd-updated-icon { font-size: 0.85rem; }

    /* ── Engagement CTA — surfaced in the full drawer when the event
         has unfunded scope OR when the event's pillar has a Givebutter
         campaign.  Bold accent color (track-tinted) so it pulls the
         eye toward action.  Subtle pulse on first appearance so the
         user knows it's new + interactive. */
    .ttd-cta {
      display: flex;
      align-items: center;
      justify-content: center;
      gap: 6px;
      width: 100%;
      padding: 9px 14px;
      margin-top: 4px;
      background: linear-gradient(135deg, var(--tenki-blue) 0%, #0073c4 100%);
      color: #fff;
      font-size: 0.85rem;
      font-weight: 800;
      letter-spacing: 0.4px;
      border: none;
      border-radius: 8px;
      cursor: pointer;
      text-decoration: none;
      box-shadow: 0 3px 10px rgba(0, 90, 156, 0.22);
      transition: transform 0.15s ease, box-shadow 0.15s ease;
      -webkit-tap-highlight-color: transparent;
    }
    .ttd-cta:hover, .ttd-cta:active {
      transform: translateY(-1px);
      box-shadow: 0 5px 14px rgba(0, 90, 156, 0.32);
    }
    .ttd-cta-arrow { font-size: 1rem; font-weight: 900; }
    .ttd-cta.track-green { background: linear-gradient(135deg, var(--tenki-green) 0%, #00a352 100%);
                           box-shadow: 0 3px 10px rgba(0, 140, 69, 0.22); }
    .ttd-cta.track-green:hover { box-shadow: 0 5px 14px rgba(0, 140, 69, 0.32); }
    .ttd-cta.track-black { background: linear-gradient(135deg, var(--tenki-black) 0%, #333 100%);
                           box-shadow: 0 3px 10px rgba(0, 0, 0, 0.22); }
    .ttd-cta.track-white { background: linear-gradient(135deg, #5f6c75 0%, #788591 100%);
                           box-shadow: 0 3px 10px rgba(95, 108, 117, 0.22); }
    /* First-appearance pulse to catch the eye when an event newly opens */
    @keyframes ttdCtaPulse {
      0%, 100% { transform: scale(1); box-shadow: 0 3px 10px rgba(0, 90, 156, 0.22); }
      50%      { transform: scale(1.03); box-shadow: 0 5px 16px rgba(0, 90, 156, 0.40); }
    }
    /* CTA pulse — single cycle then stops.  Two cycles + the drawer
       handle pulse combined was overwhelming.  One pulse is enough
       to draw the eye on first appearance. */
    .ttd-cta.is-fresh { animation: ttdCtaPulse 1.6s ease-in-out 1; }
    @media (prefers-reduced-motion: reduce) {
      .ttd-cta.is-fresh { animation: none; }
    }

    /* When map view is active, hide BOTH drawers — full map is visible. */
    .dashboard-container.mobile-map-view .map-tab-drawer,
    .dashboard-container.mobile-map-view .timeline-tab-drawer { display: none !important; }

    /* ── Mobile Tab Bar ──────────────────────────────── */
    .mobile-tab-bar {
      display: flex; flex-shrink: 0; position: relative; z-index: 20;
      background: #fff; border-bottom: 1px solid var(--timeline-line);
      order: 4; /* Sits between controls (order 3) and timeline content */
    }
    .mobile-tab {
      flex: 1; display: flex; align-items: center; justify-content: center; gap: 6px;
      padding: 10px 8px; border: none; background: none; cursor: pointer;
      font-size: 0.85rem; font-weight: 600; color: var(--text-light);
      border-bottom: 3px solid transparent;
      transition: color 0.2s ease, border-color 0.2s ease;
    }
    .mobile-tab.active { color: var(--tenki-blue); border-bottom-color: var(--tenki-blue); }
    .mobile-tab svg { flex-shrink: 0; }

    /* Map tab active: show map, hide timeline */
    .dashboard-container.mobile-map-view .map-interface-grid {
      display: flex !important;
      flex: 1 1 auto !important;
      /* Was height:auto — but auto in flex contexts can collapse if no
         child has intrinsic height.  100% so it fills the parent
         dashboard-container's allotted vertical space. */
      height: 100% !important;
      min-height: 0 !important;
      position: relative !important;
    }
    .dashboard-container.mobile-map-view .map-canvas-wrap {
      /* canvas-wrap was added recently for the DESKTOP tap-to-engage
         overlay.  On mobile it now also wraps the leaflet canvas
         when the map view is active — make it fill the parent. */
      flex: 1 1 auto !important;
      width: 100% !important;
      height: 100% !important;
      min-height: 0 !important;
    }
    .dashboard-container.mobile-map-view #leaflet-map-canvas {
      width: 100% !important;
      height: 100% !important;
      min-height: 280px !important;
    }
    .dashboard-container.mobile-map-view .timeline-outer-wrapper { display: none !important; }

    /* "Back to Timeline" affordance on the mobile map view.  Pinned at
       the top-left of the map area with a pulsing right-arrow + label,
       plus a one-time "Swipe right to go back" hint that fades after a
       few seconds.  Combined, this teaches the visitor BOTH the visual
       click affordance AND the gesture so they don't get stuck on map. */
    /* The old top-left "← Back to Timeline" chip + hint were replaced
       by the tall vertical drag-handle declared in HTML at the top of
       the dashboard-container.  Keeping these pseudo-element rules
       commented (not deleted) so a future tweak can revive them.
       .dashboard-container.mobile-map-view::before { … }
       .dashboard-container.mobile-map-view::after  { … } */

    /* Mobile-map back-handle — thick vertical bar pinned to the left
       edge of the viewport, visible ONLY in mobile-map-view.  This is
       now a SIMPLE tap target: tap anywhere on the bar to return to
       the timeline.  Removed the drag-to-dismiss gesture (was getting
       hijacked by the mobile browser's back-swipe), the grip lines,
       and the continuous nudge animation (was annoying).  The label
       reads clearly "TAP TO RETURN" so the affordance is obvious. */
    .mobile-map-back-handle {
      display: none;
      position: fixed;
      top: 50%;
      left: 0;
      transform: translateY(-50%);
      width: 44px;                     /* was 22 — twice the tap target width */
      height: 60vh;
      max-height: 420px;
      min-height: 240px;
      padding: 14px 4px;
      border: 0;
      border-radius: 0 14px 14px 0;
      background: linear-gradient(135deg, rgba(0, 90, 156, 0.96) 0%, rgba(0, 115, 196, 0.96) 100%);
      color: #fff;
      cursor: pointer;
      z-index: 9500;
      box-shadow: 4px 0 18px rgba(0, 0, 0, 0.28), 0 0 0 1px rgba(0, 0, 0, 0.08);
      backdrop-filter: blur(10px);
      -webkit-backdrop-filter: blur(10px);
      align-items: center;
      justify-content: center;
      flex-direction: column;
      gap: 8px;
      /* touch-action: manipulation = enable taps, suppress the
         browser's double-tap zoom / edge-swipe-back interpretation. */
      touch-action: manipulation;
      -webkit-tap-highlight-color: transparent;
      transition: background .15s ease, box-shadow .15s ease,
                  width .15s ease;
      /* No animation — the user found the periodic nudge annoying. */
    }
    .mobile-map-back-handle:active {
      background: linear-gradient(135deg, rgba(0, 80, 140, 1) 0%, rgba(0, 100, 175, 1) 100%);
      width: 48px;                     /* subtle press feedback */
    }
    .dashboard-container.mobile-map-view .mobile-map-back-handle { display: flex; }

    /* ── Mirror handle on the TIMELINE view's RIGHT edge ───────────────
       "Move to Map" — visible when in the default timeline view (not
       mobile-map-view).  Tap triggers switchMobileTab('map').  Visual
       twin of the left handle but anchored to the right edge, with the
       gradient mirrored (so the brighter side faces inward).  Shares
       the same dimensions + label styling. */
    .mobile-timeline-fwd-handle {
      display: none;
      position: fixed;
      /* 2026-05-29: top moved 50% → 40% so the handle sits in the
         upper-middle of the right edge, leaving clean space below
         for the floating track-filter pill.  Height also shrunk
         (60vh → 40vh, max 320 → 260) for the same reason. */
      top: 40%;
      right: 0;
      left: auto;
      transform: translateY(-50%);
      width: 44px;
      height: 40vh;
      max-height: 260px;
      min-height: 180px;
      padding: 14px 4px;
      border: 0;
      border-radius: 14px 0 0 14px;
      background: linear-gradient(225deg, rgba(0, 90, 156, 0.96) 0%, rgba(0, 115, 196, 0.96) 100%);
      color: #fff;
      cursor: pointer;
      /* 2026-05-29 (round 2): z-index 4 dropped the handle BELOW the
         timeline-outer-wrapper (z:10), so it vanished from view entirely.
         Restored to z:12 (above the wrapper) so the "Move to Map" tab is
         always visible.  To keep it from covering card content — the
         reason it was lowered in the first place — the .timeline-track now
         reserves a permanent ~56 px right gutter (padding-right below) so
         cards never extend under the handle's right-edge strip. */
      z-index: 12;
      box-shadow: -4px 0 18px rgba(0, 0, 0, 0.28), 0 0 0 1px rgba(0, 0, 0, 0.08);
      backdrop-filter: blur(10px);
      -webkit-backdrop-filter: blur(10px);
      align-items: center;
      justify-content: center;
      flex-direction: column;
      gap: 8px;
      touch-action: manipulation;
      -webkit-tap-highlight-color: transparent;
      transition: background .15s ease, box-shadow .15s ease, width .15s ease;
    }
    .mobile-timeline-fwd-handle:active {
      background: linear-gradient(225deg, rgba(0, 80, 140, 1) 0%, rgba(0, 100, 175, 1) 100%);
      width: 48px;
    }
    /* Visible only in the default (timeline) view — i.e. NOT mobile-map-
       view.  Use the negation so we don't have to flip it on a class
       JS sets only when the view is timeline. */
    .dashboard-container:not(.mobile-map-view) .mobile-timeline-fwd-handle { display: flex; }
    /* IntersectionObserver shared with the left handle: when the section
       scrolls off-screen, hide the right handle too. */
    body.tenki-back-handle-out .mobile-timeline-fwd-handle {
      display: none !important;
    }
    /* When the user scrolls AWAY from the timeline section, hide the
       back-handle even if mobile-map-view is still active.  The handle
       is position:fixed, so without this it stayed pinned to the
       viewport on every other section of the page (the user-reported
       bug).  Body class is toggled by the IntersectionObserver in
       bindMapViewBackAffordances. */
    body.tenki-back-handle-out .mobile-map-back-handle {
      display: none !important;
    }

    /* Big vertical "TAP TO RETURN" label so the affordance is obvious.
       Bigger + bolder than the old grip-line + label combo. */
    .mobile-map-back-handle-label {
      writing-mode: vertical-rl;
      transform: rotate(180deg);
      font-size: 0.82rem;
      font-weight: 900;
      letter-spacing: 1.6px;
      text-transform: uppercase;
      color: #fff;
      white-space: nowrap;
      text-shadow: 0 1px 2px rgba(0, 0, 0, 0.25);
    }

    /* ── Horizontal pager: timeline = LEFT page, map = RIGHT page ─────
       2026-05-29 redesign: the old vertical down-slide entry felt
       disconnected from the back-out direction.  Now both transitions
       run on the same horizontal axis so the user gets a consistent
       "two pages side-by-side" mental model.

         Tap "Map" tab / right-edge handle  → timeline slides LEFT off,
                                              map slides IN from RIGHT
         Tap "Timeline" tab / left handle   → map slides RIGHT off,
                                              timeline slides IN from LEFT

       Four classes, four animations.  JS sets the appropriate
       outgoing/incoming class pair around the actual view swap. */

    /* Map ENTERS from right (when arriving in mobile-map-view) */
    @keyframes mobileMapSlideInRight {
      from { transform: translateX(100%); }
      to   { transform: translateX(0); }
    }
    .dashboard-container.mobile-map-view .map-interface-grid {
      animation: mobileMapSlideInRight .32s cubic-bezier(0.22, 0.61, 0.36, 1) both;
    }
    /* Map EXITS to right (when leaving for timeline) */
    @keyframes mobileMapSlideOutRight {
      from { transform: translateX(0); }
      to   { transform: translateX(110%); }
    }
    .dashboard-container.mobile-map-leaving .map-interface-grid {
      animation: mobileMapSlideOutRight .28s cubic-bezier(0.55, 0.06, 0.68, 0.19) both;
    }

    /* Timeline ENTERS from left (when arriving back from map) */
    @keyframes mobileTimelineSlideInLeft {
      from { transform: translateX(-100%); }
      to   { transform: translateX(0); }
    }
    .dashboard-container.mobile-timeline-arriving .timeline-outer-wrapper {
      animation: mobileTimelineSlideInLeft .32s cubic-bezier(0.22, 0.61, 0.36, 1) both;
    }
    /* Timeline EXITS to left (when leaving for map) */
    @keyframes mobileTimelineSlideOutLeft {
      from { transform: translateX(0); }
      to   { transform: translateX(-110%); }
    }
    .dashboard-container.mobile-timeline-leaving .timeline-outer-wrapper {
      animation: mobileTimelineSlideOutLeft .28s cubic-bezier(0.55, 0.06, 0.68, 0.19) both;
    }

    @media (prefers-reduced-motion: reduce) {
      .mobile-map-back-handle { animation: none; }
      .mobile-timeline-fwd-handle { animation: none; }
      .dashboard-container.mobile-map-view .map-interface-grid,
      .dashboard-container.mobile-map-leaving .map-interface-grid,
      .dashboard-container.mobile-timeline-arriving .timeline-outer-wrapper,
      .dashboard-container.mobile-timeline-leaving .timeline-outer-wrapper { animation: none; }
    }

    /* Map tab: keep the nav bar visible so users can navigate pins + filter tracks.
       Re-enable the dropdown menu and chevron (both suppressed on the timeline tab). */
    .dashboard-container.mobile-map-view .floating-nav-menu { display: flex !important; }
    .dashboard-container.mobile-map-view .all-tracks-reset-btn svg { display: inline-flex !important; }

    /* Map tab discovery hint — sits between tab bar and timeline content */
    .mobile-tab-hint {
      display: block; font-size: 0.68rem; font-weight: 700; color: var(--tenki-blue);
      letter-spacing: 0.3px; text-align: center; padding: 4px 0 3px;
      opacity: 0; transition: opacity 0.4s ease; pointer-events: none;
      flex-shrink: 0; order: 4; width: 100%; background: #f0f4f8;
      border-bottom: 1px solid rgba(0,90,156,0.1);
    }
    .mobile-tab-hint.visible { opacity: 1; }

    /* Push timeline below the hint strip (hint order: 4, tab bar: 4 earlier in DOM, timeline: 5) */
    .timeline-outer-wrapper { order: 5 !important; }
  }

  /* ── Mobile Landscape Layout ─────────────────────── */
  @media (max-width: 1024px) and (max-height: 500px) and (orientation: landscape) {
    .mobile-tab-bar { display: none !important; }

    .dashboard-container {
      display: grid !important;
      grid-template-areas: "header map" "controls map" "timeline map";
      grid-template-columns: 52% 48%;
      grid-template-rows: auto auto 1fr;
      height: 100dvh !important; max-height: 100dvh !important;
      overflow: hidden; padding: 0 !important; border-radius: 0 !important;
    }

    .dashboard-header { grid-area: header; padding: 6px 12px 4px !important; }
    .dashboard-header h2 { font-size: 0.95rem !important; }
    .dashboard-controls { grid-area: controls; }
    #system-state { grid-column: 1 / -1; }

    .map-interface-grid {
      grid-area: map; display: flex !important; flex-direction: column !important;
      height: 100% !important; flex: none !important; width: 100% !important;
      position: relative !important; border-bottom: none !important;
      border-left: 2px solid var(--timeline-line);
    }

    .timeline-outer-wrapper {
      grid-area: timeline; display: flex !important; position: relative !important;
      height: 100% !important; overflow: hidden !important; flex: none !important;
    }

    .floating-nav-container { display: none !important; }

    /* In landscape, always show both panels regardless of tab state */
    .dashboard-container.mobile-map-view .map-interface-grid { display: flex !important; }
    .dashboard-container.mobile-map-view .timeline-outer-wrapper { display: flex !important; }
    .dashboard-container.mobile-map-view .floating-nav-container { display: none !important; }
  }

  /* ── Funding Detail Modal ──────────────────────── */
  .funding-modal-overlay {
    position: fixed; inset: 0;
    background: rgba(0,0,0,0.5);
    z-index: 9100; display: none;
    align-items: center; justify-content: center;
    padding: 20px;
  }
  .funding-modal-overlay.open { display: flex; }
  .funding-modal-panel {
    background: #fff; border-radius: 16px;
    max-width: 560px; width: 100%;
    max-height: 85vh; overflow-y: auto;
    padding: 28px; position: relative;
    box-shadow: 0 8px 40px rgba(0,0,0,0.2);
  }
  .funding-modal-close {
    position: absolute; top: 16px; right: 16px;
    background: none; border: none; cursor: pointer;
    font-size: 1.5rem; color: #555; line-height: 1;
  }
  .funding-modal-title { font-size: 1.1rem; font-weight: 700; margin: 0 0 4px; }
  .funding-modal-subtitle { font-size: 0.85rem; color: var(--text-light); margin: 0 0 20px; }
  .funding-chart-wrap { margin: 0 0 20px; }
  .funding-chart-label {
    display: flex; justify-content: space-between;
    font-size: 0.8rem; color: var(--text-light); margin-bottom: 6px;
  }
  .funding-bar-track {
    background: #e2e8f0; border-radius: 6px; height: 18px;
    overflow: hidden; margin-bottom: 8px;
  }
  .funding-bar-fill { height: 100%; border-radius: 6px; transition: width 0.8s ease; }
  .funding-bar-fill.raised { background: var(--tenki-green); }
  .funding-bar-fill.goal { background: var(--tenki-blue); }
  .funding-bar-fill.donated { background: #f59e0b; }
  .impact-metrics-grid {
    display: grid; grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
    gap: 12px; margin-bottom: 20px;
  }
  .impact-metric-card {
    background: var(--bg-light); border-radius: 10px;
    padding: 12px 10px; text-align: center;
  }
  .impact-metric-icon { font-size: 1.4rem; }
  .impact-metric-value { font-size: 1.15rem; font-weight: 700; color: var(--text-dark); }
  .impact-metric-label { font-size: 0.72rem; color: var(--text-light); }
  .impact-section-heading {
    font-size: 0.85rem; font-weight: 700; text-transform: uppercase;
    letter-spacing: 0.5px; color: var(--text-light); margin: 0 0 8px;
  }
  .impact-bullets { list-style: none; padding: 0; margin: 0 0 20px; }
  .impact-bullets li {
    padding: 4px 0 4px 20px; position: relative;
    font-size: 0.875rem; color: var(--text-dark);
  }
  .impact-bullets li::before { content: '✓'; position: absolute; left: 0; color: var(--tenki-green); font-weight: 700; }
  /* Team-members-involved strip on the event detail / funding popout.
     Photos are sourced from the cross-joined Team sheet; clicking jumps
     to /about-1#team-member-<slug>.  Tightly packed avatars with the
     name underneath — same shape as the org chart thumbnails. */
  .event-team-strip { display: flex; flex-wrap: wrap; gap: 12px;
                       margin: 0 0 20px; }
  .event-team-member { display: flex; flex-direction: column; align-items: center;
                        gap: 4px; padding: 6px 4px; border-radius: 8px;
                        text-decoration: none; color: inherit; cursor: pointer;
                        min-width: 78px;
                        transition: transform .25s cubic-bezier(0.175, 0.885, 0.32, 1.275),
                                    background-color .2s ease; }
  .event-team-member:hover { transform: translateY(-2px); background-color: #f0f7fb; }
  .event-team-member img,
  .event-team-avatar-fallback {
    width: 56px; height: 56px; border-radius: 50%;
    object-fit: cover; object-position: center top;
    background: #ddd; border: 2px solid #fff;
    box-shadow: 0 2px 6px rgba(0,0,0,0.15);
  }
  .event-team-avatar-fallback { display: flex; align-items: center; justify-content: center;
                                  background: #3BA9E8; color: #fff; font-weight: 700;
                                  font-size: 18px; }
  .event-team-name { font-size: 11px; font-weight: 600; color: #333;
                      text-align: center; max-width: 76px; line-height: 1.2; }
  /* Members in the sheet without a matching Team row — render dimmed so
     the editor sees the typo / rename without breaking the rest of the strip. */
  .event-team-member.missing img,
  .event-team-member.missing .event-team-avatar-fallback {
    opacity: 0.4; filter: grayscale(1);
  }
  .event-team-member.missing .event-team-name { color: #b91c1c; font-style: italic; }

  /* "Powered By" partner strip — sibling of the team strip but with org
     logos in a wider plate.  Clicking opens the partner's website. */
  .event-partners-strip { display: flex; flex-wrap: wrap; gap: 14px;
                            margin: 0 0 20px; }
  .event-partner { display: flex; flex-direction: column; align-items: center;
                     gap: 4px; padding: 8px 10px; border-radius: 8px;
                     text-decoration: none; color: inherit; cursor: pointer;
                     min-width: 110px; max-width: 150px;
                     background: #fafafa; border: 1px solid #f0f0f0;
                     transition: transform .25s cubic-bezier(0.175, 0.885, 0.32, 1.275),
                                 box-shadow .25s ease, background-color .2s ease; }
  .event-partner:hover { transform: translateY(-2px);
                          box-shadow: 0 6px 14px rgba(0,0,0,.06);
                          background: #fff; }
  .event-partner img,
  .event-partner-logo-fallback {
    width: 88px; height: 50px; object-fit: contain;
    background: #fff; border-radius: 4px;
    padding: 4px;
  }
  .event-partner-logo-fallback {
    display: flex; align-items: center; justify-content: center;
    color: #1A1A1A; font-weight: 700; font-size: 11px;
    text-align: center; line-height: 1.1;
  }
  .event-partner-name { font-size: 11px; font-weight: 600; color: #333;
                          text-align: center; max-width: 130px; line-height: 1.2; }
  .event-partner-tier { font-size: 9px; font-weight: 700;
                          text-transform: uppercase; letter-spacing: .4px;
                          color: #888; }
  .event-partner.missing img,
  .event-partner.missing .event-partner-logo-fallback {
    opacity: 0.4; filter: grayscale(1);
  }
  .event-partner.missing .event-partner-name { color: #b91c1c; font-style: italic; }
  .scope-missed-box {
    background: #fff5f5; border-left: 4px solid #e53e3e;
    border-radius: 6px; padding: 12px 14px; margin-bottom: 20px;
  }
  .scope-missed-box h4 { font-size: 0.85rem; color: #c53030; margin: 0 0 6px; }
  .scope-missed-box p { font-size: 0.85rem; color: var(--text-dark); margin: 0; }
  /* Equipment & supplies list — the concrete public ask beside the funding badge */
  .event-equip-list { list-style: none; margin: 0 0 20px; padding: 0; }
  .event-equip-list li { font-size: 0.88rem; color: var(--text-dark); padding: 6px 0; border-bottom: 1px solid var(--border, #eee); display: flex; align-items: center; gap: 8px; }
  .event-equip-list li:last-child { border-bottom: 0; }
  .event-equip-list li::before { content: "🔧"; font-size: 0.9rem; }
  .event-equip-list li.needs { font-weight: 600; }
  .event-equip-need { font-size: 0.7rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.03em; color: #854d0e; background: #fef9c3; border-radius: 999px; padding: 2px 8px; margin-left: auto; }
  .funding-modal-cta {
    display: flex; align-items: center; justify-content: center;
    width: 100%; padding: 14px;
    border: none; border-radius: 10px; cursor: pointer;
    font-size: 1rem; font-weight: 700; color: #fff;
    text-align: center; text-decoration: none; margin: 8px auto 0;
    box-sizing: border-box;
  }
  .funding-modal-cta.donate { background: var(--tenki-blue); }
  .funding-modal-cta.collaborate { background: var(--tenki-green); }
  .funding-disclaimer {
    font-size: 0.71rem; color: var(--text-light);
    text-align: center; margin: 10px 0 4px; font-style: italic;
  }

  /* ── CTA Return Toast ─────────────────────── */
  .link-toast {
    position: fixed; bottom: 30px; left: 50%;
    transform: translateX(-50%) translateY(20px);
    background: var(--tenki-black); color: #fff;
    border-radius: 30px; padding: 11px 22px;
    display: flex; align-items: center; gap: 12px;
    font-size: 0.82rem; font-weight: 600;
    box-shadow: 0 4px 20px rgba(0,0,0,0.3);
    z-index: 9500; opacity: 0; pointer-events: none;
    transition: transform 0.3s ease, opacity 0.3s ease;
    max-width: 92vw;
  }
  .link-toast.visible { transform: translateX(-50%) translateY(0); opacity: 1; pointer-events: auto; }
  .link-toast-close { background: none; border: none; color: rgba(255,255,255,0.65); cursor: pointer; font-size: 1.1rem; line-height: 1; padding: 0; }
  .link-toast-close:hover { color: #fff; }

  /* ── CTA hint below button group ─────────── */
  .cta-hint {
    font-size: 0.71rem; color: var(--text-light);
    text-align: center; margin: 6px 0 0; letter-spacing: 0.2px;
  }

/* ─── funnel: funnel/funnel.html (sha=46621b1) ─── */
/* Base Container Setup */
  .tenki-funnel-container {
    max-width: var(--tenki-max, 1400px);
    /* Tighter bottom margin so the social section's photo background
       (which extends UP behind us via a negative top margin) reads as
       a continuous bleed instead of a wide empty gap. */
    margin: 32px auto 18px;
    padding: 30px;
    /* IMPORTANT: no background-color and no mask-image on the container
       itself.  Earlier this section had a mask that faded the WHOLE
       container including the donate CTA box — making the headline
       call-to-action ghost out into the photo below.  We now put the
       gray card background on a ::before pseudo-element so the MASK
       only affects the card BACKDROP, never the content (CTAs, pillar
       chips, payment-method line) sitting above it.  Result: card
       backdrop dissolves into the photo, content stays sharp. */
    background-color: transparent;
    border-radius: 12px;
    font-family: 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
    box-sizing: border-box;
    position: relative;
    /* New layered model:
       - .tenki-funnel-container::before  → the gray card background, with
                                            the bottom-fade mask so it
                                            dissolves into the social
                                            photo below.
       - .tenki-funnel-container > *      → real content, fully opaque,
                                            sits on top via z-index.

       z-index lifted to 2 (above the social section's z:1) so the
       funnel content sits in front of the photo — only the ::before
       backdrop fades, revealing photo IN BETWEEN content elements at
       the bottom while the donate CTA stays sharp on top. */
    z-index: 2;
    isolation: isolate;
  }
  .tenki-funnel-container::before {
    content: '';
    position: absolute;
    inset: 0;
    background-color: #F8F9FA;
    border-radius: 12px;
    box-shadow: 0 8px 25px rgba(0,0,0,0.02);
    /* The fade is on this layer only — content above (z:1) is unaffected.
       Mask starts dissolving early (30 %) so the social photo bleeds UP
       through the entire bottom half of the funnel, not just the bottom
       sliver.  At 30 % the backdrop is still essentially solid; by 95 %
       it's gone, letting the photo read continuously across the funnel's
       full width (matching the bleed already visible in the gutters). */
    -webkit-mask-image: linear-gradient(to bottom,
                          black 0%, black 30%, transparent 95%);
            mask-image: linear-gradient(to bottom,
                          black 0%, black 30%, transparent 95%);
    z-index: -1;
    pointer-events: none;
  }
  /* All direct children get bumped to z:1 so they paint above the
     ::before backdrop without inheriting its mask. */
  .tenki-funnel-container > * {
    position: relative;
    z-index: 1;
  }

  .tenki-funnel-container *,
  .tenki-funnel-container *::before,
  .tenki-funnel-container *::after {
    box-sizing: inherit;
  }

  /* Build chip — hidden by default, shown only on ?debug=1.  The shared
     showBuildChip() script (added inline below) flips it on. */
  .tenki-funnel-build-chip {
    position: absolute; top: 8px; right: 12px;
    font-size: 10px; font-family: ui-monospace, SFMono-Regular, monospace;
    color: #6b7280; background: #fff; padding: 2px 6px; border-radius: 4px;
    border: 1px solid #e5e7eb; display: none;
  }
  .tenki-funnel-container.show-build .tenki-funnel-build-chip { display: inline-block; }

  /* Funnel Header Structure */
  .funnel-header {
    text-align: center;
    margin-bottom: 30px;
  }

  /* Logo banner — respects the Tenki mark's natural 3:1 aspect ratio
     (1536 × 512 source).  No inner padding since the new logo already
     has its own black background + green rounded border baked in, so
     it fills the box edge-to-edge.  object-fit:contain prevents any
     distortion if the underlying asset's aspect ratio is ever swapped. */
  .funnel-logo-box {
    position: relative;
    width: clamp(180px, 24vw, 240px);
    aspect-ratio: 3 / 1;
    margin: 0 auto 14px auto;
    border-radius: 10px;
    overflow: hidden;
    box-shadow: 0 4px 14px rgba(0, 0, 0, 0.10);
    isolation: isolate;            /* contain z-index stack */
  }
  .funnel-logo-box img {
    position: relative;
    z-index: 2;
    width: 100%;
    height: 100%;
    object-fit: contain;
    display: block;
  }

  /* ── Sierra-Leone flag backdrop (hint layer) ──────────────────────
     The original Tenki mark didn't show its SL-flag-color heritage so
     we drew a fluttering green/white/blue banner behind it for
     ambience.  The NEW mark bakes those colors directly into the
     letters (green T-e, white n, blue ki) on a solid black ground,
     so the banner behind it is mostly hidden.  Kept at very low
     opacity as a hint layer that peeks around if a future logo asset
     uses transparency — invisible otherwise.  Trivial to crank back
     up to 0.18 if you ever want the flag to read through the logo. */
  .funnel-flag-bg {
    position: absolute;
    inset: -10%;
    z-index: 1;
    background: linear-gradient(
      to bottom,
      #1eb53a 0%,    #1eb53a 33.3%,
      #ffffff 33.3%, #ffffff 66.6%,
      #0072c6 66.6%, #0072c6 100%
    );
    opacity: 0.08;                 /* faint hint — logo's bg covers it */
    filter: blur(0.8px);
    transform-origin: center;
    animation: tenkiFlagFlutter 7s ease-in-out infinite;
    pointer-events: none;
  }
  /* Tiny shear + scale loop simulates fabric sway.  Kept under ±2°
     and ±1.5% so it's "subtle" — not a swinging banner. */
  @keyframes tenkiFlagFlutter {
    0%   { transform: skewX(-1.5deg) skewY(0.3deg) scale(1.015); }
    25%  { transform: skewX( 0.8deg) skewY(-0.4deg) scale(1.008); }
    50%  { transform: skewX( 1.6deg) skewY(0.5deg) scale(1.020); }
    75%  { transform: skewX(-0.4deg) skewY(-0.3deg) scale(1.010); }
    100% { transform: skewX(-1.5deg) skewY(0.3deg) scale(1.015); }
  }
  /* Honor the user's reduced-motion preference — flag stays static */
  @media (prefers-reduced-motion: reduce) {
    .funnel-flag-bg { animation: none; }
  }

  .funnel-header h2 {
    color: #1A1A1A;
    font-size: 2rem;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    margin: 0 0 10px 0;
    font-weight: 800;
  }

  .funnel-header-divider {
    width: 50px;
    height: 4px;
    background-color: #008C45;
    margin: 0 auto 15px auto;
    border-radius: 2px;
  }

  .funnel-intro {
    color: #555555;
    font-size: 1.05rem;
    max-width: 680px;
    margin: 0 auto;
    line-height: 1.6;
  }

  .funnel-inline-link {
    color: #005A9C;
    text-decoration: underline;
    font-weight: 700;
    transition: color 0.2s ease;
  }

  .funnel-inline-link:hover {
    color: #008C45;
  }

  /* Grid Layout mechanics */
  .funnel-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
    gap: 20px;
    margin-bottom: 30px;
  }

  /* Compact Card Rules */
  .funnel-card {
    background-color: #FFFFFF;
    border-radius: 10px;
    padding: 24px;
    text-decoration: none;
    display: flex;
    flex-direction: column;
    position: relative;
    border-top: 5px solid #1A1A1A;
    transition: transform 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275), box-shadow 0.3s ease;
  }

  /* Theme Mapping */
  .card-blue-track {
    border-top-color: #005A9C;
    background: linear-gradient(180deg, rgba(0, 90, 156, 0.03) 0%, rgba(255, 255, 255, 1) 120px);
    box-shadow: 0 4px 15px rgba(0, 90, 156, 0.04);
  }
  .card-green-track {
    border-top-color: #008C45;
    background: linear-gradient(180deg, rgba(0, 140, 69, 0.03) 0%, rgba(255, 255, 255, 1) 120px);
    box-shadow: 0 4px 15px rgba(0, 140, 69, 0.04);
  }
  .card-black-track {
    border-top-color: #1A1A1A;
    background: linear-gradient(180deg, rgba(26, 26, 26, 0.02) 0%, rgba(255, 255, 255, 1) 120px);
    box-shadow: 0 4px 15px rgba(26, 26, 26, 0.03);
  }
  .card-white-track {
    border-top-color: #475569;
    background: linear-gradient(180deg, rgba(71, 85, 105, 0.04) 0%, rgba(255, 255, 255, 1) 120px);
    box-shadow: 0 4px 15px rgba(71, 85, 105, 0.05);
  }
  .card-white-track:hover { box-shadow: 0 10px 20px rgba(71, 85, 105, 0.09); }
  .card-white-track .pillar-logo-slot { background: rgba(71, 85, 105, 0.06); }
  .card-white-track .pill-amount { background-color: #eef2f6; color: #475569; }
  .card-white-track .card-footer-action { color: #475569; }

  .funnel-card:hover {
    transform: translateY(-4px);
  }
  .card-blue-track:hover  { box-shadow: 0 10px 20px rgba(0, 90, 156, 0.1); }
  .card-green-track:hover { box-shadow: 0 10px 20px rgba(0, 140, 69, 0.1); }
  .card-black-track:hover { box-shadow: 0 10px 20px rgba(26, 26, 26, 0.08); }

  /* ── Pillar logo placeholder slot ─────────────────────────────────
     Reserved spot at the top of each pillar card for a future per-
     pillar logo.  The slot is sized to gracefully accept either a
     circle badge OR a banner-style mark like the Tenki master logo:
       • Square / circle:  72 × 72 px (centered, max 64 × 64 inner)
       • Wide banner:      up to ~140 × 56 px (logo's natural ratio)
     Today the slot displays the existing pillar emoji styled as a
     soft tinted circle.  When real logos arrive, replace the inner
     placeholder span with <img class="pillar-logo-img" ...> and the
     slot styles do the rest. */
  .pillar-logo-slot {
    position: relative;
    width: 72px;
    height: 72px;
    margin: 0 auto 14px auto;
    border-radius: 16px;
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
    /* Subtle inner border + ring so the slot reads as "intentional
       brand mark" not "empty container".  Track color comes from the
       card's parent .card-*-track override below. */
    background: rgba(0, 0, 0, 0.02);
    box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.04),
                0 2px 6px rgba(0, 0, 0, 0.04);
    transition: transform 0.3s ease, box-shadow 0.3s ease;
  }
  .funnel-card:hover .pillar-logo-slot { transform: scale(1.04); }
  /* Per-track tints for the placeholder background */
  .card-blue-track  .pillar-logo-slot { background: rgba(0, 90, 156, 0.07); }
  .card-green-track .pillar-logo-slot { background: rgba(0, 140, 69, 0.07); }
  .card-black-track .pillar-logo-slot { background: rgba(26, 26, 26, 0.05); }

  /* Inner placeholder — the emoji that lives in the slot until a real
     logo arrives.  Sized + colored so it doesn't look like a hack. */
  .pillar-logo-placeholder {
    font-size: 1.9rem;
    line-height: 1;
    filter: saturate(0.95);
    pointer-events: none;
    user-select: none;
  }
  /* Future <img> replacement — use this class once the asset lands.
     `object-fit: contain` works for both circle badges and banner
     marks because the slot's 72 × 72 frame has equal inner padding. */
  .pillar-logo-slot .pillar-logo-img {
    max-width: 88%;
    max-height: 88%;
    object-fit: contain;
    display: block;
  }
  /* If the future asset is explicitly a wide banner (like Tenki's
     master mark), opt it into a wider crop with the .pillar-logo-img
     --wide modifier. */
  .pillar-logo-slot .pillar-logo-img.wide {
    max-width: 94%;
    max-height: 56%;
  }

  .card-top-accent { margin-bottom: 12px; }

  .pill-amount {
    font-size: 0.72rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    padding: 3px 8px;
    border-radius: 4px;
  }

  .card-blue-track .pill-amount  { background-color: #EEF5FB; color: #005A9C; }
  .card-green-track .pill-amount { background-color: #E8F5E9; color: #008C45; }
  .card-black-track .pill-amount { background-color: #F4F4F4; color: #1A1A1A; }

  .funnel-card h3 {
    margin: 0 0 8px 0;
    font-size: 1.15rem;
    color: #1A1A1A;
    font-weight: 700;
    line-height: 1.3;
  }

  .impact-desc {
    font-size: 0.9rem;
    line-height: 1.45;
    color: #555555;
    margin: 0 0 15px 0;
  }

  .card-footer-action {
    margin-top: auto;
    font-size: 0.8rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    display: flex;
    align-items: center;
    gap: 4px;
    transition: gap 0.2s ease;
  }

  .card-blue-track .card-footer-action  { color: #005A9C; }
  .card-green-track .card-footer-action { color: #008C45; }
  .card-black-track .card-footer-action { color: #1A1A1A; }

  .card-footer-action::after { content: '→'; font-size: 0.9rem; }
  .funnel-card:hover .card-footer-action { gap: 8px; }

  /* Master CTA Layout block */
  .funnel-cta-banner {
    background-color: #1A1A1A;
    border-radius: 10px;
    padding: 25px 30px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 25px;
    box-shadow: 0 6px 20px rgba(0,0,0,0.12);
  }

  .banner-text { flex: 1; }

  .banner-text h4 {
    margin: 0 0 6px 0;
    font-size: 1.25rem;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    color: #008C45;
    font-weight: 800;
  }

  .banner-text p {
    margin: 0;
    font-size: 0.92rem;
    line-height: 1.5;
    color: #E2E8F0;
  }

  /* Payment methods affordance — text only, no logos so it stays small
     and doesn't trigger trademark issues.  Lives under the trust copy. */
  .banner-methods {
    margin-top: 6px !important;
    font-size: 0.82rem !important;
    color: #A0AEC0 !important;
    letter-spacing: 0.3px;
  }

  .master-donate-btn {
    display: inline-block;
    padding: 12px 28px;
    background-color: #008C45;
    color: #FFFFFF;
    text-decoration: none;
    border-radius: 30px;
    font-weight: 800;
    font-size: 0.9rem;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    white-space: nowrap;
    transition: transform 0.2s ease, box-shadow 0.2s ease, background-color 0.2s ease;
    border: 2px solid #008C45;
  }

  .master-donate-btn:hover {
    transform: translateY(-2px);
    background-color: transparent;
    color: #008C45;
    box-shadow: 0 4px 12px rgba(0, 140, 69, 0.25);
  }

  /* Mobile responsive adaptations */
  @media (max-width: 900px) {
    .funnel-cta-banner {
      flex-direction: column;
      text-align: center;
      padding: 20px;
    }
    .master-donate-btn { width: 100%; text-align: center; }
  }

  @media (max-width: 768px) {
    .tenki-funnel-container { padding: 20px 15px; margin: 25px auto; }
    .funnel-header h2 { font-size: 1.5rem; }
    .funnel-intro    { font-size: 0.92rem; }
    .funnel-grid     { grid-template-columns: 1fr; gap: 15px; }
    .banner-methods  { font-size: 0.76rem !important; }
    /* Card CTAs get a 44px touch target on phones */
    .funnel-card { padding: 22px 18px; min-height: 44px; }
    .master-donate-btn { padding: 14px 28px; }
  }

/* ─── social: social/social.html (sha=3a638ed) ─── */
/* Tenki — Social & Feeds section
     Lives below the timeline embed on the homepage.  Self-contained
     scoped styles (prefix `tenki-social-` and `fb-`) so it can't bleed
     into other Code Blocks. */
  .tenki-social-parallax-section {
    --tenki-blue: #005A9C;
    --tenki-green: #008C45;
    --tenki-black: #1A1A1A;
    --tenki-white: #FFFFFF;
    --text-light: #555555;

    font-family: 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
    position: relative;
    /* Tight internal padding so the section visually butts up against
       the timeline above without a chasm.  Top padding minimal (20 px)
       so the photographer's "pointing into the sky" composition lands
       right under the timeline; bottom padding slightly larger so the
       fade-out doesn't crash into whatever comes next.

       NO negative top margin.  We had `margin: -16px -50vw 0` for a
       while to close a perceived gap between this section and the
       timeline above, but because this section has
       `isolation: isolate; z-index: 1` (creating its own stacking
       context) AND the masked background image fills the section
       absolutely from top:0, the 16-pixel pull-up caused the bg image
       to *paint over* the bottom of the timeline.  The Squarespace
       section above already provides comfortable padding; if a gap
       reappears it's better solved via the `docs/squarespace-page-
       overrides.md` PHCI snippet (zero out section padding for the
       timeline + social block-IDs) than by overlapping siblings here.

       `overflow: hidden` is belt-and-suspenders: even if a child ever
       tries to extend past the top edge (e.g. an absolutely-positioned
       decoration), it gets clipped at the section bounds. */
    /* Padding-top + negative margin-top combo extends the section
       upward so the photo background bleeds UP behind the bottom of
       the funnel section above.  Pulled WAY up so a substantial
       portion of the photo sits behind the funnel's whole bottom
       half — the funnel's ::before backdrop fades to reveal the
       photo through the gaps between content elements, while the
       donate CTA + pillar chips stay sharp on top.
       Padding-top bumped in lockstep so the inner content (Maya
       quote + feeds) lands at the same screen position. */
    /* 2026-05-29: pulled UP further (-400 → -520) so the photo
       overlaps a larger portion of the funnel section above.  The
       18 % top-mask fade dissolves into the funnel as a soft
       transition; without enough overlap the fade only reaches the
       very bottom of the funnel and the photo still reads as a
       separate slab.  Padding-top bumped in lockstep so the inner
       content (Maya quote + feeds) lands at the same screen
       position as before. */
    padding: 530px 20px 40px;
    /* Full-bleed via calc margins — robust to SQS's padded content column
       (old left:50%/right:50% offset clipped content right on mobile). */
    margin: -520px 0 0;
    margin-left: calc(50% - 50vw);
    margin-right: calc(50% - 50vw);
    box-sizing: border-box;
    width: 100vw;
    overflow: hidden;
    /* Isolate stacking context so the next section below can't paint
       into ours (same defensive pattern as .dashboard-container). */
    isolation: isolate;
    z-index: 1;
  }

  .tenki-social-masked-bg {
    position: absolute;
    top: 0; left: 0; right: 0; bottom: 0;
    background-repeat: no-repeat;
    background-size: cover;
    background-position: center center;
    z-index: 1;
    /* Critical for the top overlap with the funnel section: even
       though the mask makes the top 15 % transparent, the div is
       still a hit target.  Without this the masked-out region
       would intercept clicks on whatever funnel content sits in
       the same coordinate space (donate CTA, pillar chips). */
    pointer-events: none;
    /* 2026-05-29: ADDED a top-edge fade.  Previously the mask was
       `black 0%, black 95%, transparent 100%` — solid top edge,
       which painted a HARD horizontal line where the photo met the
       funnel's donate CTA above.  User-reported: "top of social
       picture is still not visible and does not blend into the
       funnel."  New gradient runs:
         0%  → transparent  (top edge fully invisible)
         18% → black        (photo fully visible from here down)
         95% → black
         100% → transparent (existing bottom soften into newsletter)
       Now the photo materialises softly into whatever sits above
       (the funnel's donate CTA + bottom of its gray backdrop) and
       the join with the funnel reads as a continuous transition,
       not a cut. */
    -webkit-mask-image: linear-gradient(to bottom,
                          transparent 0%, black 18%, black 95%, transparent 100%);
            mask-image: linear-gradient(to bottom,
                          transparent 0%, black 18%, black 95%, transparent 100%);
  }

  .tenki-social-inner-content {
    position: relative;
    z-index: 2;
    max-width: var(--tenki-max, 1400px);
    margin: 0 auto;
  }

  /* Inline mini-Tenki-logo inside the FB/IG card subtitles.
     Replaces the old large logo banner that used to sit at the top
     of the section — that banner was redundant against the footer
     logo on the same page and competed with the photo background
     for attention.  The inline placement brands the feed cards as
     specifically Tenki's (vs. generic Facebook / Instagram) while
     taking up only ~22 px of vertical space and letting the photo
     above breathe.

     The drop-shadow gives the logo a little lift off the white
     card surface — same "depth" treatment we used to apply to the
     banner version, just scaled down. */
  .fb-inline-tenki {
    display: inline-block;
    height: 22px;
    width: auto;
    vertical-align: -6px;        /* baseline tweak — matches the cap height of the subtitle */
    margin: 0 4px;
    filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.22))
            drop-shadow(0 1px 1px rgba(0, 0, 0, 0.14));
    /* PNG is already RGBA with transparent corners post-crop, so no
       background / border-radius needed — the alpha channel handles
       the rounded look against the card's white surface. */
  }
  @media (max-width: 768px) {
    .fb-inline-tenki { height: 18px; vertical-align: -5px; }
  }

  /* Quote card */
  .tenki-social-quote-container {
    background-color: var(--tenki-white);
    border-radius: 16px;
    padding: 32px 40px;
    box-shadow: 0 15px 45px rgba(0, 0, 0, 0.06);
    text-align: center;
    position: relative;
    margin-bottom: 30px;
    border-top: 5px solid var(--tenki-blue);
  }
  .tenki-social-quote-container::before {
    content: '"';
    position: absolute;
    top: -15px; left: 40px;
    font-size: 140px;
    color: rgba(0, 90, 156, 0.04);
    font-family: Georgia, serif;
    line-height: 1;
  }
  .tenki-social-quote-text {
    font-size: 1.6rem;
    line-height: 1.5;
    color: var(--tenki-black);
    font-weight: 600;
    font-style: italic;
    margin: 0 0 10px 0;
  }
  .tenki-social-quote-author {
    font-size: 1.1rem;
    color: var(--tenki-blue);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 1px;
    margin: 0;
  }

  /* Feed columns */
  .tenki-feeds-grid-wrapper {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 40px;
    align-items: start;
  }
  .tenki-feed-column-card {
    background-color: var(--tenki-white);
    border-radius: 16px;
    box-shadow: 0 15px 40px rgba(0, 0, 0, 0.05);
    box-sizing: border-box;
    width: 100%;
    border-top: 6px solid var(--tenki-blue);
    overflow: hidden;
    transition: transform 0.3s ease, box-shadow 0.3s ease;
  }
  .tenki-feed-column-card:hover {
    transform: translateY(-2px);
    box-shadow: 0 18px 45px rgba(0, 0, 0, 0.08);
  }
  .tenki-feed-column-card.ig-card { border-top-color: var(--tenki-green); }

  .fb-card-header-trigger {
    display: flex;
    align-items: center;
    gap: 15px;
    padding: 25px;
    cursor: pointer;
    user-select: none;
    transition: background-color 0.2s ease;
    min-height: 48px;  /* touch target */
  }
  .fb-card-header-trigger:hover { background-color: #FAFAFA; }
  .fb-icon-circle {
    width: 45px;
    height: 45px;
    border-radius: 50%;
    background-color: #eef5fb;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 20px;
    flex-shrink: 0;
  }
  /* Platform icons rendered via CSS `content:` instead of literal
     emoji characters in the HTML markup.  Lives in the CDN-served
     CSS (correct UTF-8 headers always) so Squarespace's Code Block
     paste can't mojibake the icons even when it mangles inline
     unicode in the shell.  \1F4F1 = 📱, \1F4F8 = 📸. */
  .fb-icon-circle[data-platform-icon="facebook"]::before  { content: '\1F4F1'; }
  .fb-icon-circle[data-platform-icon="instagram"]::before { content: '\1F4F8'; }
  .tenki-feed-column-card.ig-card .fb-icon-circle { background-color: #eefbf3; }
  .fb-header-text { flex-grow: 1; }
  .fb-header-text h3 {
    margin: 0;
    color: var(--tenki-black);
    font-size: 1.15rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.5px;
  }
  .fb-header-text p {
    margin: 2px 0 0 0;
    color: var(--text-light);
    font-size: 0.85rem;
    font-weight: 600;
    transition: color 0.2s ease;
  }
  .tenki-feed-column-card:hover .fb-header-text p { color: var(--tenki-blue); }
  .tenki-feed-column-card.ig-card:hover .fb-header-text p { color: var(--tenki-green); }

  /* Expandable drawer */
  .fb-iframe-container-drawer {
    display: none;
    opacity: 0;
    width: 100%;
    justify-content: center;
    overflow-y: auto;
    border-top: 1px dashed #EAEAEA;
    height: 550px;
    padding: 15px 10px;
    position: relative;
    background-color: #FAFAFA;
    box-sizing: border-box;
    transition: opacity 0.35s ease;
  }
  .tenki-feed-column-card.active .fb-iframe-container-drawer {
    display: flex;
    opacity: 1;
  }
  .fb-iframe-container-drawer iframe {
    width: 340px;
    height: 500px;
    border: none;
    overflow: hidden;
    pointer-events: auto;
  }
  .fb-iframe-container-drawer .elfsight-app-a618fcce-28d6-49e5-87f9-efbfd761ba01 {
    width: 100%;
    height: auto;
  }

  /* Build chip — visible only with ?debug=1 (toggled via .show-build) */
  .tenki-social-build-chip {
    position: absolute;
    top: 8px;
    right: 12px;
    z-index: 5;
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 10px;
    color: #fff;
    background: rgba(0, 90, 156, 0.85);
    padding: 3px 8px;
    border-radius: 10px;
    letter-spacing: 0.3px;
    display: none;
  }
  .tenki-social-parallax-section.show-build .tenki-social-build-chip { display: inline-block; }

  @media (max-width: 900px) {
    .tenki-feeds-grid-wrapper {
      grid-template-columns: 1fr;
      gap: 30px;
    }
    .tenki-social-parallax-section {
      /* Mobile keeps the same blend pattern as desktop (funnel bottom
         fades into photo) but at smaller scale.  Top padding still
         leaves ~80 px of photo above the quote card so the lush-jungle
         backdrop reads as the visual lead-in. */
      padding: 100px 15px 30px;
      margin-top: -80px;
    }
    .tenki-social-quote-container {
      padding: 30px 20px;
    }
    .tenki-social-quote-text {
      font-size: 1.3rem;
    }
  }

/* ─── newsletter: newsletter/newsletter.html (sha=01c06db) ─── */
/* Tenki newsletter section — full-bleed below the social section.
     The visual goal: airy white space, oversized brand statement on
     the left, focused signup card on the right.  No competing photo
     background — leaves the social section above as the visual
     bookend so this reads as the "next step" rather than another
     decorative photo block. */
  .tenki-newsletter-section {
    --tn-blue:    #005A9C;
    --tn-blue-deep: #003a66;
    --tn-black:   #1A1A1A;
    --tn-ink:     #222;
    --tn-muted:   #6b7280;
    --tn-line:    #e2e8f0;

    font-family: 'proxima-nova', 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
    position: relative;
    /* NOT full-bleed (intentionally — do NOT reintroduce width:100vw).
       iOS Safari/WebKit mis-PAINTS text inside a `width:100vw` section that
       rides Squarespace's scroll-reveal compositing layer: the headline GLYPHS
       render shifted left and clip at the viewport edge, even though layout
       coordinates report the box correctly (so it's invisible to JS measurement
       and unaffected by the earlier 100vw+calc-margin and text-wrap fixes).
       Reproduced in a real WebKit engine; only dropping the 100vw clears it.
       The section background is white and the page background is also white, so
       a normal-width section is visually seamless and keeps the headline inside
       the column. */
    width: auto;
    padding: 80px 24px 96px;
    background: #fff;
    box-sizing: border-box;
    /* Same defensive pattern as the social section: own stacking
       context so the next sibling can't paint into ours, and so we
       don't paint into the timeline above us. */
    isolation: isolate;
    z-index: 1;
  }

  .tenki-newsletter-build-chip {
    position: absolute; top: 8px; right: 12px;
    font: 600 10px/1 monospace; padding: 3px 8px; border-radius: 4px;
    background: var(--tn-black); color: #fff; opacity: .55;
    display: none; pointer-events: none; z-index: 2;
  }
  [data-debug="1"] .tenki-newsletter-build-chip,
  body.tenki-debug .tenki-newsletter-build-chip { display: block; }

  .tenki-newsletter-inner {
    max-width: var(--tenki-max, 1400px);
    margin: 0 auto;
    display: grid;
    grid-template-columns: 1.05fr 1fr;
    gap: 64px;
    align-items: center;
  }

  .tenki-newsletter-headline {
    margin: 0 0 12px;
    /* Softer than the original 800-weight tightly-tracked treatment —
       this is an inspirational statement, not a battle cry.  Serif
       face + medium weight + relaxed line-height gives it the warmth
       of a hand-written letter rather than an enterprise call-out. */
    font-family: Georgia, 'Iowan Old Style', 'Palatino Linotype', serif;
    font-size: clamp(1.55rem, 2.8vw, 2.35rem);
    line-height: 1.35;
    font-weight: 500;
    color: #2a2a2a;
    letter-spacing: 0.005em;
    text-wrap: balance;
  }
  .tenki-newsletter-attribution {
    margin: 0;
    font-size: 0.95rem;
    color: var(--tn-muted);
    font-style: italic;
  }
  .tenki-newsletter-attribution:empty { display: none; }

  .tenki-newsletter-right {
    background: #fafbfc;
    border: 1px solid var(--tn-line);
    border-radius: 16px;
    padding: 28px 28px 24px;
    box-shadow: 0 1px 3px rgba(0,0,0,.04), 0 6px 18px rgba(0,0,0,.04);
  }
  .tenki-newsletter-signup-title {
    margin: 0 0 8px;
    font-size: 1.15rem;
    font-weight: 700;
    color: var(--tn-blue);
  }
  .tenki-newsletter-signup-title:empty { display: none; }
  .tenki-newsletter-signup-body {
    margin: 0 0 18px;
    font-size: 1rem;
    line-height: 1.5;
    color: var(--tn-ink);
  }

  .tenki-newsletter-form { display: flex; flex-direction: column; gap: 10px; }
  .tenki-newsletter-label {
    /* Visually hidden — kept for screen readers */
    position: absolute; width: 1px; height: 1px;
    padding: 0; margin: -1px; overflow: hidden;
    clip: rect(0,0,0,0); border: 0;
  }
  .tenki-newsletter-form input[type="email"] {
    padding: 13px 16px;
    border: 1.5px solid var(--tn-line);
    border-radius: 10px;
    font-size: 15px;
    font-family: inherit;
    outline: none;
    background: #fff;
    color: var(--tn-ink);
    transition: border-color .15s, box-shadow .15s;
    min-height: 44px;
  }
  .tenki-newsletter-form input[type="email"]:focus {
    border-color: var(--tn-blue);
    box-shadow: 0 0 0 3px rgba(0, 90, 156, .12);
  }
  .tenki-newsletter-form input[type="email"].is-invalid {
    border-color: #dc2626;
  }
  .tenki-newsletter-btn {
    padding: 13px 22px;
    border: 0;
    border-radius: 10px;
    background: var(--tn-blue-deep);
    color: #fff;
    font-size: 15px;
    font-weight: 700;
    font-family: inherit;
    cursor: pointer;
    transition: background .15s, transform .12s;
    min-height: 44px;
    letter-spacing: .01em;
  }
  .tenki-newsletter-btn:hover { background: var(--tn-blue); transform: translateY(-1px); }
  .tenki-newsletter-btn:active { transform: translateY(0); }
  .tenki-newsletter-btn:disabled { opacity: .6; cursor: not-allowed; transform: none; }
  .tenki-newsletter-btn.is-success { background: #16a34a; }

  .tenki-newsletter-status {
    margin-top: 4px;
    font-size: 0.9rem;
    line-height: 1.4;
    min-height: 1.2em;
  }
  .tenki-newsletter-status.is-ok  { color: #16a34a; font-weight: 600; }
  .tenki-newsletter-status.is-err { color: #dc2626; }

  /* Mobile — stack into a single column, tighten the vertical rhythm */
  @media (max-width: 768px) {
    .tenki-newsletter-section {
      padding: 48px 16px 64px;
    }
    .tenki-newsletter-inner {
      grid-template-columns: 1fr;
      gap: 32px;
    }
    .tenki-newsletter-headline {
      font-size: clamp(1.4rem, 6vw, 1.85rem);
    }
  }
