/* ============================================================================
   bouly.io — home.css — styles for the Constellation landing ("/" and "/fr/").
   Self-contained (the landing intentionally does NOT load styles.css). Loaded
   after topbar.css so the landing-only #topbar overrides win. Was inlined in
   static/index.html; extracted for readability.
   ============================================================================ */
/* ─── TOKENS — DARK (default) ───────────────────────────────── */
:root {
  --bg:          #0b0f17;
  --panel:       #0f1420;
  --surface:     #141926;
  --border:      #1e2640;
  --border-hi:   #293358;
  --text:        #e9e5df;
  --text-muted:  #8994a4;
  --text-dim:    #52606e;

  /* v3 palette — azure / rose / emerald */
  --azure:       #3b82f6;
  --rose:        #ec4899;
  --emerald:     #10b981;

  --azure-dim:   rgba(59,130,246,0.14);
  --rose-dim:    rgba(236,72,153,0.14);
  --emerald-dim: rgba(16,185,129,0.14);

  --glow-azure:   0 0 18px rgba(59,130,246,0.22);
  --glow-rose:    0 0 18px rgba(236,72,153,0.22);
  --glow-emerald: 0 0 18px rgba(16,185,129,0.22);

  --radius-sm:   4px;
  --radius-md:   8px;
  --radius-lg:   12px;

  --font-sans:  "IBM Plex Sans", system-ui, sans-serif;
  --font-mono:  "IBM Plex Mono", monospace;

  /* topbar gradient uses bg color */
  --topbar-grad: rgba(11,15,23,0.95);
}

/* ─── TOKENS — LIGHT ────────────────────────────────────────── */
:root[data-theme="light"] {
  --bg:          #f6f7f9;
  --panel:       #eef0f4;
  --surface:     #e8eaf0;
  --border:      #cdd2de;
  --border-hi:   #b0b8ca;
  --text:        #1a2030;
  --text-muted:  #4a5568;
  --text-dim:    #8896a8;

  /* light-mode accents: slightly shifted for contrast on light bg */
  --azure:       #2563eb;
  --rose:        #db2777;
  --emerald:     #059669;

  --azure-dim:   rgba(37,99,235,0.10);
  --rose-dim:    rgba(219,39,119,0.10);
  --emerald-dim: rgba(5,150,105,0.10);

  --topbar-grad: rgba(246,247,249,0.95);
}

/* ─── RESET ─────────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

/* Skip link — first tab stop, jumps keyboard users to the content. */
.skip-link {
  position: fixed; left: 0.75rem; top: -60px; z-index: 200;
  background: var(--azure); color: var(--bg);   /* var(--bg) inverts per theme → AA in both (5.09:1 dark / 4.82:1 light) */
  font-family: var(--font-mono); font-size: 0.8rem; font-weight: 600;
  padding: 8px 14px; border-radius: var(--radius-sm);
  transition: top 0.15s;
}
.skip-link:focus { top: 0.75rem; outline: 2px solid var(--bg); outline-offset: 2px; }
/* Visible keyboard focus on every interactive element (styles.css isn't loaded here). */
:focus-visible { outline: 2px solid var(--azure); outline-offset: 2px; border-radius: var(--radius-sm); }
html { scroll-behavior: smooth; }
html, body { width: 100%; background: var(--bg); color: var(--text); font-family: var(--font-sans); }
body { overflow-x: clip; }  /* clip, not hidden — does not create a scroll container that breaks descendant position:sticky/fixed */
/* "Explore the graph" mode = a full-screen interactive graph tool → lock the page. */
body.in-graph { overflow: hidden; height: 100%; }

/* ─── CANVAS ─────────────────────────────────────────────────── */
/* Fixed, opaque backdrop (it paints its own --bg fill). The hero sits over it;
   the scroll narrative (#portrait) scrolls up over it on a solid background. */
#canvas { display: block; position: fixed; inset: 0; z-index: 0; cursor: crosshair; }
#canvas.dragging { cursor: grabbing; }
#canvas.panning  { cursor: grab; }

/* ─── INTRO OVERLAY ──────────────────────────────────────────── */
#intro {
  /* First viewport: the hero text over the live constellation. In flow now
     (was fixed) so the page scrolls down into the #portrait narrative. */
  position: relative; min-height: 100svh;
  display: flex; flex-direction: column; align-items: flex-start; justify-content: center;
  /* Hero LEFT, constellation RIGHT and usable. This scrim is click-through
     (pointer-events:none) so pan / zoom / hover / drag reach the canvas — only
     the CTAs capture clicks. A horizontal scrim keeps the left (text) legible
     while the right (graph) stays clear. No filter bar / zoombar here (those
     return in the Explore / full view). */
  pointer-events: none;
  background: linear-gradient(to right,
              var(--bg) 0%,
              color-mix(in srgb, var(--bg) 92%, transparent) 32%,
              color-mix(in srgb, var(--bg) 52%, transparent) 56%,
              transparent 80%);
  z-index: 2;
  padding: 2rem clamp(1.75rem, 6vw, 6.5rem);
  text-align: left;
  transition: opacity 0.6s var(--ease-out), visibility 0.6s var(--ease-out);
}
#intro.hidden { opacity: 0; visibility: hidden; }
#intro .cta { pointer-events: auto; }   /* CTAs stay clickable over the live graph */

/* Explore the graph — bottom-right, mirrors the in-graph home button (→ at the end).
   Reuses .topbar-brand for identical pill styling. Hidden once in the graph. */
.explore-cta {
  position: fixed; bottom: 1.25rem; right: 1.25rem;
  z-index: 110;                 /* above the scrim (100), below the topbar (120) */
  color: var(--text-muted);     /* match the in-graph home-button brightness */
  transition: opacity 0.4s var(--ease-out), visibility 0.4s var(--ease-out), color 0.15s, border-color 0.15s, background 0.15s;
}
.explore-cta .go-glyph {
  font-size: 0.65rem;
  opacity: 0.7;
  transform: translateX(-2px);
  transition: opacity 0.2s, transform 0.2s;
}
.explore-cta:hover .go-glyph { opacity: 1; transform: translateX(2px); }
body.in-graph .explore-cta { opacity: 0; visibility: hidden; pointer-events: none; }

.intro-eyebrow {
  font-family: var(--font-mono);
  font-size: 0.7rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--text-muted);
  margin-bottom: 1.5rem;
}
.intro-h1 {
  font-size: clamp(1.75rem, 4vw, 3rem);
  font-weight: 700;
  line-height: 1.08;
  letter-spacing: -0.025em;
  color: var(--text);
  max-width: 640px;
  margin-bottom: 1.25rem;
}
.intro-h1 .accent { color: var(--azure); }
/* Legibility halo so the hero stays crisp over the constellation backdrop */
.intro-eyebrow, .intro-h1, .intro-line { text-shadow: 0 1px 18px var(--bg), 0 0 5px var(--bg); }
.intro-line {
  font-size: clamp(0.9rem, 1.5vw, 1.05rem);
  font-weight: 400;
  color: var(--text-muted);
  max-width: 520px;
  line-height: 1.65;
  margin-bottom: 2.5rem;
}
.cta-row {
  display: flex; gap: 1rem; flex-wrap: wrap; justify-content: flex-start;
  margin-bottom: 2rem;
}
.cta {
  display: inline-flex; align-items: center; gap: 0.5rem;
  padding: 0.7rem 1.5rem;
  border-radius: var(--radius-md);
  font-size: 0.875rem;
  font-weight: 600;
  cursor: pointer;
  border: 1.5px solid transparent;
  transition: background 0.15s, border-color 0.15s, transform 0.1s;
  letter-spacing: 0.01em;
  text-decoration: none;
}
.cta:active { transform: scale(0.97); }
/* Border + tint carry the colour-coding; label stays --text so 14px/600 clears
   AA in both themes (azure-on-tint was 4.48/4.21, emerald-on-tint 6.21/3.12 — failed). */
.cta-build {
  background: var(--azure-dim);
  border-color: var(--azure);
  color: var(--text);
}
.cta-build:hover { background: rgba(59,130,246,0.22); }
.cta-work {
  background: var(--emerald-dim);
  border-color: var(--emerald);
  color: var(--text);
}
.cta-work:hover { background: rgba(16,185,129,0.22); }
.cta-enter {
  background: transparent;
  border-color: var(--border-hi);
  color: var(--text-muted);
  font-size: 0.8rem;
}
.cta-enter:hover { border-color: var(--text-muted); color: var(--text); }
/* Hero CTAs — both the cta-build azure: one filled, one ghost. Label stays
   --text so 14px/600 clears AA in both themes (azure-on-tint failed). */
.cta-azure {
  background: var(--azure-dim);
  border-color: var(--azure);
  color: var(--text);
}
.cta-azure:hover { background: rgba(59,130,246,0.22); }
.cta-azure-ghost {
  background: transparent;
  border-color: var(--azure);
  color: var(--text);
}
.cta-azure-ghost:hover { background: var(--azure-dim); }
/* ─── TOP BAR ────────────────────────────────────────────────────
   Shared styling lives in /assets/css/topbar.css (single source — same bar
   on every page). Landing-only overrides below: the bar is a FIXED overlay
   over the full-screen canvas, and lets clicks fall through between controls.
   (.topbar-brand / .btn-sm / #lang-toggle / #theme-toggle → topbar.css) */
#topbar {
  position: fixed;
  pointer-events: none;
}
#topbar > * { pointer-events: auto; }

/* ─── ZOOM CONTROLS ──────────────────────────────────────────── */
#zoombar {
  position: fixed; bottom: 4.5rem; right: 1.25rem;
  display: flex; flex-direction: column; gap: 0.25rem;
  z-index: 50;
}
.zoom-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 2rem; height: 2rem;
  border-radius: var(--radius-sm);
  font-family: var(--font-mono);
  font-size: 0.85rem;
  font-weight: 600;
  cursor: pointer;
  background: var(--surface);
  border: 1px solid var(--border);
  color: var(--text-muted);
  transition: border-color 0.15s, color 0.15s, background 0.15s;
}
.zoom-btn:hover { border-color: var(--border-hi); color: var(--text); }
#zoom-fit {
  font-size: 0.5rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  width: auto;
  padding: 0 0.4rem;
  height: 1.6rem;
}

/* ─── FILTER BAR ─────────────────────────────────────────────── */
#filterbar {
  position: fixed; bottom: 1.25rem; left: 50%; transform: translateX(-50%);
  display: flex; align-items: center; gap: 0.5rem;
  background: color-mix(in srgb, var(--panel) 90%, transparent);
  backdrop-filter: blur(8px);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 0.4rem 0.75rem;
  z-index: 50;
  flex-wrap: wrap; justify-content: center;
}
.filter-btn {
  display: inline-flex; align-items: center; gap: 0.35rem;
  padding: 0.3rem 0.75rem;
  border-radius: 9999px;
  font-size: 0.75rem;
  font-weight: 500;
  cursor: pointer;
  border: 1.5px solid transparent;
  transition: background 0.15s, color 0.15s, border-color 0.15s;
  background: transparent;
  color: var(--text-muted);
}
.filter-btn .dot { width: 7px; height: 7px; border-radius: 50%; }
.filter-btn[data-type="project"]    { border-color: rgba(59,130,246,0.4); }
.filter-btn[data-type="experience"] { border-color: rgba(236,72,153,0.4); }
.filter-btn[data-type="skill"]      { border-color: rgba(16,185,129,0.4); }
.filter-btn[data-type="project"].on    { background: var(--azure-dim);   color: var(--azure);   border-color: var(--azure); }
.filter-btn[data-type="experience"].on { background: var(--rose-dim);    color: var(--rose);    border-color: var(--rose); }
.filter-btn[data-type="skill"].on      { background: var(--emerald-dim); color: var(--emerald); border-color: var(--emerald); }
.filter-btn[data-type="project"] .dot    { background: var(--azure); }
.filter-btn[data-type="experience"] .dot { background: var(--rose); }
.filter-btn[data-type="skill"] .dot      { background: var(--emerald); }
.filter-divider { width: 1px; height: 18px; background: var(--border); }
.filter-audience-btn {
  display: inline-flex; align-items: center; gap: 0.35rem;
  padding: 0.3rem 0.75rem;
  border-radius: 9999px;
  font-size: 0.75rem;
  font-weight: 500;
  cursor: pointer;
  border: 1.5px solid var(--border-hi);
  background: transparent;
  color: var(--text-muted);
  transition: background 0.15s, color 0.15s, border-color 0.15s;
}
.filter-audience-btn:hover { color: var(--text); border-color: var(--text-muted); }
.filter-audience-btn.active-build { border-color: var(--azure); color: var(--azure); background: var(--azure-dim); }
.filter-audience-btn.active-work  { border-color: var(--emerald);  color: var(--emerald);  background: var(--emerald-dim); }

/* Landing: the graph is a non-interactive backdrop — hide the graph controls
   (they'd otherwise bleed through the translucent scrim edges). Shown on Explore. */
body:not(.in-graph) #filterbar,
body:not(.in-graph) #zoombar { display: none; }

/* ─── CARD PANEL ──────────────────────────────────────────────── */
#card {
  position: fixed; top: 60px; right: 1.25rem;
  width: 300px;
  background: color-mix(in srgb, var(--panel) 95%, transparent);
  backdrop-filter: blur(12px);
  border: 1px solid var(--border-hi);
  border-radius: var(--radius-lg);
  padding: 1.1rem 1.2rem;
  z-index: 110;   /* above the landing scrim (100) so node cards show on the landing too */
  opacity: 0; visibility: hidden;
  transform: translateX(8px);
  transition: opacity 0.2s, visibility 0.2s, transform 0.2s;
  pointer-events: none;
}
#card.visible {
  opacity: 1; visibility: visible; transform: translateX(0);
  pointer-events: auto;
}
.card-badge {
  display: inline-flex; align-items: center; gap: 0.3rem;
  font-family: var(--font-mono);
  font-size: 0.62rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  padding: 0.2rem 0.5rem;
  border-radius: var(--radius-sm);
  margin-bottom: 0.7rem;
}
.card-badge.project    { background: var(--azure-dim);   color: var(--azure);   border: 1px solid rgba(59,130,246,0.3); }
.card-badge.experience { background: var(--rose-dim);    color: var(--rose);    border: 1px solid rgba(236,72,153,0.3); }
.card-badge.skill      { background: var(--emerald-dim); color: var(--emerald); border: 1px solid rgba(16,185,129,0.3); }
.card-title { font-size: 1rem; font-weight: 600; color: var(--text); line-height: 1.3; margin-bottom: 0.4rem; }
.card-meta  { font-family: var(--font-mono); font-size: 0.7rem; color: var(--text-muted); margin-bottom: 0.65rem; letter-spacing: 0.04em; }
.card-desc  { font-size: 0.82rem; color: var(--text-muted); line-height: 1.6; margin-bottom: 0.75rem; }
.card-link {
  display: inline-flex; align-items: center; gap: 0.3rem;
  font-family: var(--font-mono); font-size: 0.68rem; letter-spacing: 0.08em;
  text-decoration: none; color: var(--azure); transition: color 0.15s;
}
.card-link:hover { color: var(--text); }
.card-neighbors { margin-top: 0.7rem; padding-top: 0.7rem; border-top: 1px solid var(--border); }
.card-neighbors-label {
  font-family: var(--font-mono); font-size: 0.6rem; letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--text-muted); margin-bottom: 0.4rem;
}
.card-neighbor-tags { display: flex; flex-wrap: wrap; gap: 0.3rem; }
.card-neighbor-tag {
  font-size: 0.7rem; padding: 0.15rem 0.45rem; border-radius: 9999px;
  background: var(--surface); border: 1px solid var(--border);
  color: var(--text-muted); cursor: pointer;
}
.card-neighbor-tag:hover { border-color: var(--border-hi); color: var(--text); }
.card-close {
  position: absolute; top: 0.6rem; right: 0.6rem;
  background: none; border: none; cursor: pointer;
  color: var(--text-muted); font-size: 1rem; line-height: 1; padding: 0.2rem;
  transition: color 0.15s;
}
.card-close:hover { color: var(--text); }

/* ─── LIST VIEW (FALLBACK) ───────────────────────────────────── */
#listview {
  display: none;
  position: fixed; inset: 0;
  overflow-y: auto;
  background: var(--bg);
  padding: 4rem 1.25rem 6rem;
  z-index: 40;
}
#listview.visible { display: block; }
.list-section { margin-bottom: 2.5rem; }
.list-section-title {
  display: flex; align-items: center; gap: 0.6rem;
  font-family: var(--font-mono);
  font-size: 0.7rem; letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--text-muted); margin-bottom: 1rem;
  padding-bottom: 0.5rem; border-bottom: 1px solid var(--border);
}
.list-item {
  padding: 0.9rem 1rem;
  border: 1px solid var(--border); border-radius: var(--radius-md);
  margin-bottom: 0.5rem; transition: border-color 0.15s;
}
.list-item:hover { border-color: var(--border-hi); }
.list-item-title { font-size: 0.9rem; font-weight: 600; margin-bottom: 0.2rem; }
.list-item-meta  { font-family: var(--font-mono); font-size: 0.65rem; color: var(--text-muted); margin-bottom: 0.4rem; }
.list-item-desc  { font-size: 0.8rem; color: var(--text-muted); line-height: 1.55; }
.list-item.project    { border-left: 3px solid var(--azure); }
.list-item.experience { border-left: 3px solid var(--rose); }
.list-item.skill      { border-left: 3px solid var(--emerald); }

/* ─── PORTRAIT (scroll narrative — distilled from brand/PORTRAIT.md) ───────
   Who I am, revealed on scroll. Sits over the fixed constellation on a solid
   background (legibility / WCAG AA); the top edge blends out of the live graph. */
#portrait {
  position: relative;
  z-index: 2;                       /* above the fixed canvas backdrop (z 0) */
  /* Identical fade to the hero (#intro) so the story blocks sit on the live
     constellation exactly like the hero does. Contrast base is preserved: the body's
     solid --bg sits behind the transparent canvas, so the text never loses its --bg
     backing — the fade only controls how much the graph bleeds in on the right. */
  background: linear-gradient(to right,
              var(--bg) 0%,
              color-mix(in srgb, var(--bg) 92%, transparent) 32%,
              color-mix(in srgb, var(--bg) 52%, transparent) 56%,
              transparent 80%);
  padding: 0 clamp(1.75rem, 6vw, 6.5rem);
}
.p-section {
  max-width: 680px;
  min-height: 60vh;   /* tightened from 78vh — less dead vertical space between statements */
  display: flex; flex-direction: column; justify-content: center;
  padding: 3.5rem 0;
  opacity: 0; transform: translateY(12px);
  transition: opacity 0.6s var(--ease-out), transform 0.6s var(--ease-out);
}
.p-section.in { opacity: 1; transform: none; }
.p-eyebrow {
  display: inline-flex; align-items: center; gap: 0.6rem;
  font-family: var(--font-mono);
  font-size: 0.72rem; letter-spacing: 0.2em; text-transform: uppercase;
  color: var(--text-muted);
  margin-bottom: 1.1rem;
}
.p-eyebrow::before {                /* palette dot — decorative, non-text → no AA constraint */
  content: ""; flex: none; width: 8px; height: 8px; border-radius: 50%;
  background: var(--azure); color: var(--azure);   /* solid structural dot — glow stripped (no decorative status-dot glow) */
}
.p-section.accent-rose    .p-eyebrow::before { background: var(--rose);    color: var(--rose); }
.p-section.accent-emerald .p-eyebrow::before { background: var(--emerald); color: var(--emerald); }
.p-h {
  font-size: clamp(1.55rem, 3.4vw, 2.5rem);
  font-weight: 700; line-height: 1.14; letter-spacing: -0.02em;
  color: var(--text); margin-bottom: 1.15rem;
}
.p-line {
  font-size: clamp(0.98rem, 1.5vw, 1.12rem);
  line-height: 1.7; color: var(--text-muted); max-width: 58ch;
}
.p-chips { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-top: 1.6rem; list-style: none; }
.p-chip {
  font-family: var(--font-mono); font-size: 0.72rem; letter-spacing: 0.03em;
  padding: 0.4rem 0.8rem; border-radius: 9999px;
  background: var(--surface); border: 1px solid var(--border-hi); color: var(--text);
}
.p-closing { min-height: 54vh; }
.p-cta-row { display: flex; gap: 1rem; flex-wrap: wrap; margin-top: 2.25rem; }

/* Hero scroll affordance — decorative (aria-hidden), fades once the page moves. */
.p-scroll-cue {
  position: absolute; left: clamp(1.75rem, 6vw, 6.5rem); bottom: 1.75rem;
  display: inline-flex; align-items: center; gap: 0.5rem;
  font-family: var(--font-mono); font-size: 0.62rem; letter-spacing: 0.18em; text-transform: uppercase;
  color: var(--text-muted); pointer-events: none;
  transition: opacity 0.4s var(--ease-out);
}
.p-scroll-cue .chev { font-size: 0.95rem; animation: cueBob 1.8s ease-in-out infinite; }
@keyframes cueBob { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(5px); } }
body.scrolled .p-scroll-cue { opacity: 0; }
/* .explore-cta now stays through the scroll — the constellation is live on the
   right of the story blocks, so the "Explore the graph" affordance stays reachable
   (it's still hidden in-graph via body.in-graph above). */
/* Explore mode hides the scroll story; the graph owns the screen. */
body.in-graph #portrait { display: none; }

/* ─── FOOTER (end of scroll — mirrors partials/footer_full.html, self-contained
   since the landing doesn't load styles.css; in flow here, not fixed) ──────── */
.lp-footer {
  position: relative; z-index: 2;            /* above the fixed canvas backdrop */
  background: var(--bg);
  border-top: 1px solid var(--border);
  padding: 3rem clamp(1.75rem, 6vw, 6.5rem) 1.5rem;
  color: var(--text-muted);
}
.lp-footer-top {
  display: flex; flex-wrap: wrap; gap: 2.5rem; justify-content: space-between;
  max-width: 1100px; margin: 0 auto;
}
.lp-footer-brand { max-width: 320px; }
.lp-foot-wordmark {
  font-weight: 700; letter-spacing: -0.02em; font-size: 1.05rem;
  color: var(--text); text-decoration: none;
}
.lp-foot-wordmark:hover { color: var(--azure); }
.lp-footer-tagline {
  margin-top: 0.9rem; font-family: var(--font-mono);
  font-size: 0.78rem; line-height: 1.6; color: var(--text-muted);
}
.lp-footer-links { display: flex; gap: 2.5rem; flex-wrap: wrap; }
.lp-footer-col { display: flex; flex-direction: column; gap: 0.5rem; }
.lp-footer-col .h { color: var(--text); font-weight: 600; font-size: 0.85rem; margin-bottom: 2px; }
.lp-footer-col a { color: var(--text-muted); font-size: 0.9rem; text-decoration: none; transition: color 0.15s; }
.lp-footer-col a:hover { color: var(--azure); }
.lp-footer-bottom {
  display: flex; flex-wrap: wrap; gap: 1rem; justify-content: space-between;
  max-width: 1100px; margin: 2.5rem auto 0; padding-top: 1.25rem;
  border-top: 1px solid var(--border); font-size: 0.85rem;
}
.lp-mono-note { font-family: var(--font-mono); font-size: 0.75rem; color: var(--text-muted); }
body.in-graph .lp-footer { display: none; }   /* Explore owns the screen */

/* ─── REDUCED MOTION ─────────────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  #intro { transition: none; }
  #card  { transition: none; }
  .p-section { opacity: 1; transform: none; transition: none; }
  .p-scroll-cue { transition: none; }
  .p-scroll-cue .chev { animation: none; }
  .explore-cta, .explore-cta .go-glyph { transition: none; }
}

/* ─── MOBILE ─────────────────────────────────────────────────── */
@media (max-width: 640px) {
  /* No canvas on mobile → the page becomes a normal vertical scroll: hero first,
     then the static list (the DESIGN.md fallback). Previously #intro was a fixed
     full-screen scrim that physically covered #listview, so the list was
     unreachable. Make both flow in the document instead. */
  html, body { overflow-y: auto; overflow-x: clip; height: auto; }
  #canvas   { display: none; }
  #filterbar{ display: none; }
  #card     { display: none; }
  #zoombar  { display: none; }
  .explore-cta { display: none; }
  #topbar { padding: 0 0.75rem; }
  .topbar-controls { gap: 0.35rem; }
  #intro {
    position: relative; inset: auto; min-height: 100svh;
    align-items: center; text-align: center;
    padding-left: 1.75rem; padding-right: 1.75rem;
    background: var(--bg);
  }
  #listview { display: block; position: relative; inset: auto; z-index: 1; padding-top: 2rem; }
  .cta-row { justify-content: center; }
  /* Portrait narrative flows between the hero and the list; centred, no scroll cue. */
  #portrait { padding: 0 1.75rem; background: var(--bg); }
  .p-section { min-height: auto; padding: 2.75rem 0; align-items: center; text-align: center; max-width: 540px; margin: 0 auto; }
  .p-chips { justify-content: center; }
  .p-cta-row { justify-content: center; }
  .p-scroll-cue { display: none; }
  .lp-footer { padding: 2.5rem 1.75rem 1.5rem; }
  .lp-footer-top { gap: 1.75rem; }
  .lp-footer-links { gap: 1.75rem; }
}
.nav-link { text-decoration: none; }
