/* /recommend — "Ask the Atlas" chat page. Mobile-first (375px), tokens only.
   Shared .page-header / .page-eyebrow / .page-title come from css/app.css.
   Task 9: chat/rail/composer styles — full replace of previous vibe-search CSS. */

/* ─── DARK THEME ───────────────────────────────────────────────────────────── */
/* tokens-dark.css (linked in recommend.html, before this file) supplies
   --cream-dim/--border/--border-strong, matching the other 5 dark pages.
   These three have no site-wide equivalent yet and stay page-local. */
:root {
  --cream-field: rgba(227, 218, 201, 0.07);
  --cream-hover: rgba(227, 218, 201, 0.06);
  --cream-soft:  rgba(227, 218, 201, 0.82);
  --cream-edge:  rgba(227, 218, 201, 0.18); /* input/dropdown edge — brighter than --border */
  /* Skeleton shimmer — low-alpha cream on black. --shimmer-hi sweeps across
     --shimmer-base to read as a highlight travelling over the placeholder. */
  --shimmer-base: rgba(227, 218, 201, 0.05);
  --shimmer-hi:   rgba(227, 218, 201, 0.11);
  /* Sticky composer bar's clearance over the fixed mobile bottom-nav.
     layout.js overrides this with the nav's measured height (which already
     includes its safe-area padding); this is the no-JS fallback. */
  --atlas-nav-h: calc(68px + env(safe-area-inset-bottom));
}
html, body { background: var(--black); color: var(--off-white); }

/* ─── MOTION ───────────────────────────────────────────────────────────────── */
/* Soft fade-in (LLM-style: messages fade, they don't slide in). */
@keyframes atlas-rise {
  from { opacity: 0; }
  to   { opacity: 1; }
}

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

/* ─── SHELL — MOBILE FIRST: single column ──────────────────────────────────── */
.atlas-shell {
  display: block;
  max-width: 1200px;
  margin: 0 auto;
  /* No bottom padding: the composer (.atlas-bottom-bar) is the last item in
     this locked, full-height column and must sit flush above the mobile nav.
     A bottom pad here would reintroduce the dead gap below the composer.
     Desktop restores its own breathing room in the min-width:769px block. */
  padding: 0;
}

/* ─── CHAT VIEWPORT: lock the page — the thread is the only scroller ───────── */
/* The document must NOT scroll on this page. If it can, iOS scrolls the
   window to lift the focused composer above the keyboard, and WebKit (Safari
   and iOS Chrome alike) often leaves that offset stuck after the keyboard
   closes — the fixed .mobile-bottom-nav and sticky .atlas-bottom-bar then
   render ~a keyboard-height above the true bottom with a dead gap below.
   100dvh tracks the visible viewport (100vh is the large viewport on iOS and
   overflows it while browser chrome is showing); overflow:hidden removes
   window scroll entirely so the keyboard has nothing to strand.
   Scoped by :has(.atlas-shell) so no other page is affected. */
html:has(.atlas-shell),
body:has(.atlas-shell) {
  height: 100vh;    /* fallback for pre-dvh browsers */
  height: 100dvh;
  min-height: 0;    /* cancel global min-height:100vh — it would win over the dvh height */
  overflow: hidden;
}
.page-flex-content:has(.atlas-shell) {
  /* Override global flex: 1 0 auto — the wrapper must be allowed to SHRINK to
     the viewport, or the flex chain grows with the conversation and
     .atlas-thread's overflow-y:auto never engages (the document scrolls
     instead, which re-opens the keyboard bug above). */
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
}
.atlas-shell {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
}
.atlas-conversation {
  flex: 1 1 auto;
}

/* ─── CONVERSATION SECTION ─────────────────────────────────────────────────── */
.atlas-conversation {
  display: flex;
  flex-direction: column;
  min-height: 0;
}

/* ─── HEADER ───────────────────────────────────────────────────────────────── */
.atlas-head {
  padding: var(--space-8) var(--space-4) var(--space-5);
  border-bottom: 1px solid var(--border);
}

.atlas-eyebrow {
  font-family: var(--font-ui);
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase;
  color: var(--color-accent);
  margin: 0 0 var(--space-2);
}

.atlas-subhead {
  font-family: var(--font-body);
  font-size: var(--text-body);
  line-height: var(--leading-body);
  color: var(--cream-dim);
  margin: 0;
}

/* ─── THREAD (message list) ────────────────────────────────────────────────── */
.atlas-thread {
  flex: 1 1 auto;
  padding: var(--space-6) 0 var(--space-2);
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
}

/* ─── MESSAGES ─────────────────────────────────────────────────────────────── */
.atlas-msg {
  display: flex;
  gap: var(--space-3);
  margin: 0 var(--space-4) var(--space-6);
  align-items: flex-start;
  animation: atlas-rise 400ms cubic-bezier(0.22, 1, 0.36, 1) both;
}

/* User bubbles sit on the right with their avatar on the far right — row-reverse
   puts the avatar (first DOM child) after the bubble, packed to the right. */
.atlas-msg-user {
  flex-direction: row-reverse;
}

/* Consecutive same-speaker messages read as one group: pull the follow-ups up
   toward the previous bubble (their avatar is an inert spacer, not repeated). */
.atlas-msg-grouped {
  margin-top: calc(-1 * var(--space-3));
}

/* No chat bubble box — the user's line reads as a quiet, right-aligned aside. */
.atlas-msg-user .atlas-bubble {
  max-width: 80%;
  text-align: right;
  color: var(--cream-dim);
  font-style: italic;
  padding-top: var(--space-1);
}

.atlas-msg-bot .atlas-bubble {
  max-width: 100%;
}

/* ─── AVATARS ──────────────────────────────────────────────────────────────── */
/* A small disc on every message: the Atlas brand mark for bot turns, a neutral
   cream monogram glyph for the user. First-of-a-group only; grouped follow-ups
   get an empty .atlas-avatar-spacer of the same size to keep bubbles aligned. */
.atlas-avatar {
  flex: 0 0 auto;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}

.atlas-avatar-spacer {
  background: none;
  border: none;
}

/* Bot: brand mark on a near-black disc with a red-accent ring. */
.atlas-avatar-bot {
  background: var(--color-primary, #0f0f0f);
  border: 1px solid var(--color-accent);
  box-shadow: 0 0 0 3px rgba(192, 57, 43, 0.14);
}

.atlas-avatar-mark {
  width: 22px;
  height: 22px;
  display: block;
}

/* User: neutral cream monogram glyph on a low-alpha cream disc. */
.atlas-avatar-user {
  background: var(--cream-field);
  border: 1px solid var(--cream-edge);
  color: var(--cream-soft);
}

.atlas-avatar-glyph {
  width: 18px;
  height: 18px;
  display: block;
}

/* First-run example prompts under the welcome — tap to drop into the composer. */
.atlas-examples {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-top: var(--space-4);
}
.atlas-example {
  font-family: var(--font-ui);
  font-size: var(--text-sm);
  min-height: 36px;
  padding: var(--space-2) var(--space-4);
  border-radius: var(--radius-pill);
  cursor: pointer;
  background: var(--cream-hover);
  color: var(--cream-soft);
  border: 1px solid var(--border);
  transition: border-color var(--dur-fast) var(--ease-out),
              color var(--dur-fast) var(--ease-out);
}
.atlas-example:hover {
  border-color: var(--color-accent);
  color: var(--color-base);
}
.atlas-example:focus-visible {
  outline: 2px solid var(--color-accent);
  outline-offset: 2px;
}

/* ─── BUBBLE TEXT ──────────────────────────────────────────────────────────── */
.atlas-bubble {
  font-family: var(--font-body);
  font-size: var(--text-body);
  line-height: var(--leading-body);
  color: var(--off-white);
}

.atlas-bubble p {
  margin: 0 0 var(--space-2);
}

.atlas-bubble p:last-child {
  margin-bottom: 0;
}

/* ─── FIRST-RUN EXAMPLE PROMPTS ────────────────────────────────────────────── */
/* Sit under the greeting bubble; clicking one fills the composer (composer.js
   'atlas-example' action) so a first-time visitor isn't facing a blank page. */
.atlas-examples {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-top: var(--space-4);
}

.atlas-example {
  font-family: var(--font-ui);
  font-size: var(--text-sm);
  min-height: 36px;
  padding: var(--space-2) var(--space-4);
  border-radius: var(--radius-pill);
  cursor: pointer;
  background: var(--cream-hover);
  color: var(--cream-soft);
  border: 1px solid var(--border);
  transition: border-color var(--dur-fast) var(--ease-out),
              color var(--dur-fast) var(--ease-out);
}

.atlas-example:hover {
  border-color: var(--color-accent);
  color: var(--color-base);
}

.atlas-example:focus-visible {
  outline: 2px solid var(--color-accent);
  outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
  .atlas-example { transition: none; }
}

/* ─── "THINKING" STATUS LINE ───────────────────────────────────────────────── */
/* A crimson thread squiggle flowing beside a status line that walks three
   phases. Replaces the poster-and-rail skeleton (2026-07-29): the posters were
   decorative and said nothing, the status line says what the Atlas is doing. */
.atlas-thinking {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: var(--space-2) var(--space-4);
}

.atlas-thinking-squiggle {
  flex: none;
}
.atlas-thinking-squiggle path {
  stroke: var(--color-accent);
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-dasharray: 5 6;
  animation: atlas-thread-flow 2.4s linear infinite;
}

.atlas-thinking-status {
  font-family: var(--font-ui);
  /* No token at 15px (--text-sm is 14px, --text-body is 16px); this is the
     handoff's specified loader size, not a missed token. */
  font-size: 15px;
  color: var(--color-base);
  animation: atlas-status-breathe 2s ease-in-out infinite;
}

@keyframes atlas-thread-flow {
  to { stroke-dashoffset: -220; }
}
@keyframes atlas-status-breathe {
  /* Floor is 0.7, not the deeper dip this was ported from: this animates
     .atlas-thinking-status, the only text carrying the loader's meaning, and
     cream-on-#0f0f0f dips under the 4.5:1 contrast minimum below ~0.7 at this
     font size. The old, deeper dip belonged to the poster skeleton this
     status line replaced, which lived inside an aria-hidden decorative SVG
     where contrast never applied. Do not restore it here. */
  0%, 100% { opacity: 0.7; }
  50%      { opacity: 0.85; }
}

/* ─── ERROR TURN ───────────────────────────────────────────────────────────── */
.atlas-error {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-4);
  padding: 0 var(--space-4);
}

.atlas-error-text {
  margin: 0;
  font-family: var(--font-body);
  font-size: var(--text-body);
  line-height: var(--leading-body);
  color: var(--cream-soft);
}

/* ─── COMPOSER (sticky input bar) ──────────────────────────────────────────── */
/* REQUIRED: Clears global .mobile-bottom-nav (68px) on mobile */
/* Sticks the chip row + composer together as one unit, so escape-hatch
   actions (e.g. "Search a different film") are always reachable without
   scrolling — sticking each piece separately would need fragile pixel-math
   to stack their offsets correctly. */
.atlas-bottom-bar {
  /* The page is locked (body: 100dvh + overflow:hidden — see the CHAT VIEWPORT
     block) and .atlas-thread is the only scroller, so the composer is simply
     the last item in the full-height column and rests at the bottom on its own.
     It must NOT be sticky: body's overflow:hidden makes it the sticky scrollport,
     and `bottom: 68px` then stacked on top of body's own 68px nav padding —
     lifting the composer ~a nav-height off the bottom (the dead-gap bug). */
  background: var(--black);
  padding-bottom: var(--space-3);
}

.atlas-composer {
  display: flex;
  gap: var(--space-2);
  align-items: flex-end; /* keep the send button pinned to the bottom as the textarea grows */
  padding: var(--space-3) var(--space-4);
  background: var(--black);
  border-top: 1px solid var(--border);
}

.atlas-input {
  flex: 1 1 auto;
  min-height: 44px;
  max-height: 160px;              /* safety cap; JS caps growth at ~5 rows */
  font-family: var(--font-body);
  font-size: var(--text-body); /* >=16px: prevents iOS auto-zoom */
  line-height: var(--leading-ui);
  color: var(--off-white);
  background: var(--cream-hover);
  border: 1px solid var(--cream-edge);   /* matches the typeahead dropdown's edge */
  border-radius: var(--radius);
  padding: var(--space-3) var(--space-4);
  resize: none;
  overflow-y: hidden;             /* JS flips to auto once content exceeds the cap */
}

.atlas-input::placeholder {
  color: var(--cream-dim);
}

.atlas-input:focus-visible {
  outline: none;
  border-color: var(--color-accent);
  box-shadow: 0 0 0 3px rgba(192, 57, 43, 0.18);
}

.atlas-send {
  flex: 0 0 auto;
  min-width: 44px;
  min-height: 44px;
  background: var(--color-accent);
  color: var(--color-base-bright);
  border: none;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  /* The arrow is an inline SVG, so drop the button's default padding and let
     flex do the centring on its own. font-size no longer matters here: it was
     sizing a "↑" glyph whose font metrics were what pushed the arrow off
     centre in the first place. */
  padding: 0;
  line-height: 0;
  cursor: pointer;
  transition: opacity var(--dur-fast) var(--ease-out),
              transform var(--dur-fast) var(--ease-out);
}

.atlas-send:hover {
  opacity: 0.88;
}

.atlas-send:active {
  transform: scale(0.94);
}

/* ─── RESET BUTTON ("Ask about another film") ──────────────────────────────── */
/* Round icon-only button beside the composer that reuses atlas-search-different
   (clear → greeting → focus input). Shown only while a settled result is on
   screen — results.js toggles [hidden] in setChips(), in step with the chips. */
.atlas-reset {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  padding: 0;
  color: var(--color-accent);            /* the refresh glyph (SVG uses currentColor) */
  background: none;
  border: 1px solid var(--border-strong);
  border-radius: 999px;
  cursor: pointer;
  transition: border-color var(--dur-fast) var(--ease-out);
}
.atlas-reset[hidden] { display: none; }  /* override .atlas-reset's own display */
.atlas-reset:hover { border-color: var(--color-accent); }
.atlas-reset:focus-visible { outline: 2px solid var(--color-accent); outline-offset: 3px; }

.atlas-send:focus-visible {
  outline: 2px solid var(--color-accent);
  outline-offset: 2px;
}

.atlas-send:disabled {
  opacity: 0.5;
  cursor: default;
  transform: none;
}

/* ─── DESKTOP: single centered column (rail removed) ───────────────────────── */
@media (min-width: 769px) {
  .atlas-shell {
    max-width: 820px;
    /* Desktop has no mobile nav; keep a little breathing room below the
       composer (the mobile shell zeroes this so the composer meets the nav). */
    padding: 0 var(--space-6) var(--space-10);
  }

  .atlas-head {
    padding: var(--space-10) 0 var(--space-5);
  }
}

/* ─── REDUCED MOTION ───────────────────────────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
  .atlas-send,
  .atlas-reset,
  .atlas-input {
    transition: none;
  }
  .atlas-msg {
    animation: none;
  }
  /* Hold a static, fully legible state: no marching dashes, no breathing.
     The status line stays on its first phase (thread.js skips the timer). */
  .atlas-thinking-squiggle path,
  .atlas-thinking-status {
    animation: none;
  }
  .atlas-thinking-status {
    opacity: 1;
  }
}

/* ─── Composer typeahead drop-UP ──────────────────────────────────────────── */
/* The composer is pinned to the viewport bottom (and the keyboard sits right
   below it on mobile), so suggestions open UPWARD into the conversation area —
   the only direction with guaranteed room. column-reverse keeps the #1 match
   visually adjacent to the input (Slack/Discord pattern) while the DOM (and
   screen-reader order) stays best-match-first. */
.atlas-suggest {
  position: absolute; bottom: 100%; left: 0; right: 0; margin-bottom: var(--space-2);
  background: var(--color-primary); border: 1px solid rgba(227,218,201,0.18);
  border-radius: 10px; z-index: 20;
  display: flex; flex-direction: column-reverse;
  max-height: min(320px, 45dvh);
  overflow-y: auto;
}
/* Explicit display above would defeat the hidden attribute — restore it. */
.atlas-suggest[hidden] { display: none; }
.atlas-opt {
  display: flex; flex-direction: column; gap: var(--space-1); width: 100%; text-align: left;
  padding: var(--space-3) var(--space-4); background: transparent; border: none; cursor: pointer;
  color: var(--color-base);
  /* Reversed stack: each row's border-TOP is the separator from the row shown
     above it; the first (best, bottom-most) row draws none at the panel edge. */
  border-top: 1px solid rgba(227,218,201,0.08);
}
.atlas-opt:first-child { border-top: none; }
.atlas-opt:hover, .atlas-opt-active { background: rgba(227,218,201,0.06); }
.atlas-opt-t { font-family: var(--font-body); font-size: var(--text-body); }
.atlas-opt-m { font-family: var(--font-ui); font-size: var(--text-xs); color: var(--cream-dim); }

/* ─── ONE-AT-A-TIME RESULTS (lineage thread + shelf) ────────────────────────── */
.atlas-badge-row {
  display: flex; align-items: center; gap: var(--space-2);
  margin-bottom: var(--space-4);
}
/* One eyebrow treatment for every turn (vibe / by-feel / lineage) so the
   thread reads consistently — the label text is what distinguishes them. */
.atlas-badge {
  font-family: var(--font-ui); font-size: var(--text-xs);
  letter-spacing: var(--tracking-eyebrow); text-transform: uppercase;
  color: var(--color-accent); font-weight: var(--weight-medium);
}
.atlas-badge-dot {
  width: 4px; height: 4px; border-radius: 999px; background: var(--cream-dim);
}
.atlas-badge-meta { font-family: var(--font-ui); font-size: var(--text-xs); color: var(--cream-dim); }

.atlas-bridge {
  font-family: var(--font-body); font-size: var(--text-bridge);
  line-height: var(--leading-bridge); margin: 0 0 var(--space-4); max-width: 56ch;
}

/* ─── HYBRID TURN: grounded RAG answer above the film picks ──────────────────
   Prepended into the same turn node ABOVE the recommender's shelf. Editorial
   prose (Lora / --font-body) on the black/red dark theme, separated from the
   picks below by a hairline rule. Additive — absent entirely when the RAG
   answer is off or ungrounded, so the shelf reads exactly as it does today. */
.atlas-answer {
  margin: 0 0 var(--space-5); padding: 0 0 var(--space-5);
  border-bottom: 1px solid var(--border);
}
.atlas-answer-body {
  font-family: var(--font-body); font-size: var(--text-bridge);
  line-height: var(--leading-bridge); color: var(--color-base); max-width: 60ch;
}
.atlas-answer-body p { margin: 0 0 var(--space-3); }
.atlas-answer-body p:last-child { margin-bottom: 0; }

/* Citation chips — the cited films. Smaller than the action chips; a tap opens
   the existing slide-in card (atlas-open-card) for that film_id. */
.atlas-cite-row {
  display: flex; align-items: center; gap: var(--space-2);
  flex-wrap: wrap; margin-top: var(--space-4);
}
.atlas-cite-label {
  font-family: var(--font-ui); font-size: var(--text-xs);
  letter-spacing: var(--tracking-eyebrow); text-transform: uppercase;
  color: var(--cream-dim); margin-right: var(--space-1);
}
.atlas-cite {
  font-family: var(--font-ui); font-size: var(--text-xs);
  padding: var(--space-1) var(--space-3); min-height: 32px;
  border-radius: var(--radius-pill); cursor: pointer;
  background: transparent; color: var(--cream-dim);
  border: 1px solid var(--border-strong);
}
.atlas-cite:hover { border-color: var(--color-accent); color: var(--color-accent); }
.atlas-cite:focus-visible { outline: 2px solid var(--color-accent); outline-offset: 2px; }

/* Ungrounded fallback line (no relevant material / guide briefly down). Quiet
   and non-alarming — the film shelf below is the real answer. */
.atlas-rag-note {
  font-family: var(--font-ui); font-size: var(--text-sm);
  color: var(--cream-dim); font-style: italic;
  margin: 0 0 var(--space-4); max-width: 56ch;
}

.atlas-trail { display: flex; flex-direction: column; gap: var(--space-4); margin-bottom: var(--space-4); }
.atlas-trail-item { opacity: 0.55; display: flex; align-items: baseline; gap: var(--space-3); flex-wrap: wrap; }
.atlas-trail-title { font-family: var(--font-display); font-size: var(--text-body); font-weight: var(--weight-semibold); }
.atlas-trail-meta { font-family: var(--font-ui); font-size: var(--text-sm); color: var(--cream-dim); }

.atlas-stop-label, .atlas-tease-label {
  font-family: var(--font-ui); font-size: var(--text-xs);
  letter-spacing: var(--tracking-eyebrow); text-transform: uppercase; color: var(--cream-dim);
  display: block; margin-bottom: var(--space-3);
}
/* No bottom margin here — the chip row used to render inline right after
   this block, so this margin separated content from chips. Now the chip
   row lives in the persistent #atlas-chip-bar outside this element, and
   .atlas-msg's own margin-bottom (--space-8) plus .atlas-thread's bottom
   padding already provide the gap before the divider; stacking this on
   top of those left a much larger gap here than below the divider. */
.atlas-current-stop, .atlas-terminus { margin-bottom: 0; }
.atlas-stop-body { display: flex; flex-direction: column; gap: var(--space-4); }
/* Mobile: a compact centered poster so the title + synopsis below it stay in
   view without scrolling once an answer lands (poster-above-copy stack per the
   mobile-first DNA pattern, just smaller). Desktop restores the larger poster
   in the row layout below. */
.atlas-stop-poster { width: 100%; max-width: 130px; margin: 0 auto; }
/* The terminus renders a bare <img> (real anchor poster, not a tile_html
   card) — give it the same aspect-ratio/border treatment the stop tiles
   above it get, so it doesn't look inconsistent at the end of the thread.
   The rail's terminus tile renders the same bare <img>, so it shares the
   selector. */
.atlas-stop-poster > img,
.atlas-rail-tile > img {
  width: 100%; aspect-ratio: 2 / 3; object-fit: cover;
  border-radius: var(--radius-sm); border: 1px solid var(--border);
}
/* .film-card's box/overlay CSS isn't in the shared components/film-card.css
   (that file is overlay-position only) — tile_html reused here needs its
   own copy or the poster renders unconstrained (natural image size) with
   the title/meta overlay flowing as plain text instead of an absolute
   gradient overlay. */
.atlas-stop-poster .film-card-link,
.atlas-rail-tile .film-card-link,
.atlas-strip-tile .film-card-link {
  width: 100%; display: block; text-decoration: none; color: inherit;
}
.atlas-stop-poster .film-card,
.atlas-rail-tile .film-card,
.atlas-strip-tile .film-card {
  width: 100%; aspect-ratio: 2 / 3; position: relative; overflow: hidden;
  border-radius: var(--radius-sm); background: var(--color-primary);
  border: 1px solid var(--border);
}
.atlas-stop-poster .film-card-placeholder,
.atlas-rail-tile .film-card-placeholder,
.atlas-strip-tile .film-card-placeholder {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  padding: var(--space-4); background: rgba(242, 237, 228, 0.08);
}
.atlas-stop-poster .film-card-placeholder-text,
.atlas-rail-tile .film-card-placeholder-text,
.atlas-strip-tile .film-card-placeholder-text {
  font-family: var(--font-display); font-size: var(--text-body); font-style: italic;
  color: var(--cream-dim); text-align: center; line-height: var(--leading-ui);
}
.atlas-stop-poster .film-card-info,
.atlas-rail-tile .film-card-info,
.atlas-strip-tile .film-card-info {
  min-height: 0; padding: var(--space-6) var(--space-3) var(--space-3);
  background: linear-gradient(to bottom,
    rgba(10, 10, 10, 0) 0%, rgba(10, 10, 10, 0.5) 50%, rgba(10, 10, 10, 0.92) 100%);
}
.atlas-stop-poster .film-card-title,
.atlas-rail-tile .film-card-title,
.atlas-strip-tile .film-card-title {
  font-family: var(--font-display); font-size: var(--text-h3); font-style: italic;
  color: var(--off-white); line-height: var(--leading-snug); margin-bottom: var(--space-1);
  overflow: hidden; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
}
.atlas-stop-poster .film-card-meta,
.atlas-rail-tile .film-card-meta,
.atlas-strip-tile .film-card-meta {
  font-family: var(--font-ui); font-size: var(--text-sm); color: var(--cream-dim);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.atlas-stop-title { font-family: var(--font-display); font-size: var(--text-h2); font-weight: var(--weight-bold); line-height: var(--leading-tight); }
.atlas-stop-meta { font-family: var(--font-ui); font-size: var(--text-sm); color: var(--cream-dim); margin-top: var(--space-1); }
.atlas-stop-blurb { font-family: var(--font-body); font-size: var(--text-body); line-height: var(--leading-body); color: rgba(227, 218, 201, 0.85); margin: var(--space-2) 0 0; max-width: 44ch; }
.atlas-poster-placeholder {
  aspect-ratio: 2 / 3; border-radius: var(--radius-sm); border: 1px solid var(--border);
  background: var(--cream-hover); display: flex; align-items: center; justify-content: center;
  padding: var(--space-4); text-align: center; font-family: var(--font-display); color: var(--cream-dim);
}

.atlas-next-tease { opacity: 0.55; }
.atlas-tease-title { font-family: var(--font-display); font-size: var(--text-h3); font-weight: var(--weight-semibold); }

.atlas-chip-row { display: flex; align-items: center; gap: var(--space-3); flex-wrap: wrap; border-top: 1px solid var(--border); padding-top: var(--space-5); }
/* #atlas-chip-bar is the persistent chip-row slot inside .atlas-bottom-bar
   (see recommend.html) — results.js renders each turn's chips into it, so
   they're always reachable without scrolling, sticky alongside the composer. */
#atlas-chip-bar { padding: var(--space-6) var(--space-4) var(--space-4); margin: 0; }
#atlas-chip-bar[hidden] { display: none; }
.atlas-chip {
  font-family: var(--font-ui); font-size: var(--text-sm); min-height: 44px;
  padding: var(--pad-button); border-radius: var(--radius-pill); cursor: pointer;
  background: transparent; color: var(--color-base); border: 1px solid var(--border-strong);
}
.atlas-chip:hover { border-color: var(--color-accent); color: var(--color-accent); }
.atlas-chip:focus-visible { outline: 2px solid var(--color-accent); outline-offset: 2px; }
.atlas-chip-primary { background: var(--color-accent); color: var(--color-base-bright); border-color: var(--color-accent); }
/* .atlas-chip:hover's text color (--color-accent) is meant for secondary
   chips (transparent background) — on a primary chip, whose background is
   already --color-accent, that made the text invisible on hover. */
.atlas-chip-primary:hover { color: var(--color-base-bright); opacity: 0.88; }

/* Quiet escape-hatch link — see chipLink() in results.js. No pill/border;
   keeps a 44px tap target via padding for touch accessibility. */

.atlas-entering { animation: atlas-turn-enter var(--dur) ease-out both; }
@keyframes atlas-turn-enter {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: translateY(0); }
}
@media (prefers-reduced-motion: reduce) {
  .atlas-entering { animation: none; }
}

@media (min-width: 769px) {
  .atlas-stop-body { flex-direction: row; align-items: flex-start; gap: var(--space-8); }
  .atlas-stop-poster { flex: 0 0 220px; margin: 0; }
}

/* Legacy counter kept for restored-state safety; superseded by .atlas-carousel. */
.atlas-shelf-counter {
  font-family: var(--font-ui); font-size: var(--text-xs); color: var(--cream-dim);
}

/* ─── SHELF: layered deck + prev/next carousel (ported from staging) ────────── */
/* Prev/next controls + a "3 / 12" position (trailing "+" when the server still
   has more to fetch), pushed to the right of the chip row so it's obvious the
   shelf continues and is easy to shuffle through. */
.atlas-carousel {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  margin-left: auto;
}
.atlas-carousel-btn {
  flex: 0 0 auto;
  width: 36px;
  height: 36px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--text-body);
  line-height: 1;
  border-radius: 50%;
  cursor: pointer;
  background: transparent;
  color: var(--color-base);
  border: 1px solid var(--border-strong);
  transition: border-color var(--dur-fast) var(--ease-out),
              color var(--dur-fast) var(--ease-out);
}
.atlas-carousel-btn:hover:not(:disabled) {
  border-color: var(--color-accent);
  color: var(--color-accent);
}
.atlas-carousel-btn:focus-visible {
  outline: 2px solid var(--color-accent);
  outline-offset: 2px;
}
.atlas-carousel-btn:disabled {
  opacity: 0.4;
  cursor: default;
}
.atlas-carousel-pos {
  font-family: var(--font-ui);
  font-size: var(--text-xs);
  font-variant-numeric: tabular-nums;
  color: var(--cream-dim);
  min-width: 3.5ch;
  text-align: center;
}

/* Layered peek: a faint offset card edge behind the current poster's right
   side, hinting the next film is stacked behind it. Only when more remain. */
.atlas-current-stop.atlas-has-next .atlas-stop-poster {
  position: relative;
}
.atlas-current-stop.atlas-has-next .atlas-stop-poster::after {
  content: "";
  position: absolute;
  top: 6px;
  bottom: 6px;
  right: -8px;
  width: 10px;
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  background: var(--cream-field);
  border: 1px solid var(--border);
  border-left: none;
  z-index: -1;
  pointer-events: none;
}

@media (prefers-reduced-motion: reduce) {
  .atlas-carousel-btn,
  .atlas-example { transition: none; }
}

/* ─── SHELF MINI-CAROUSEL ──────────────────────────────────────────────────── */
/* Prev/next controls + a "3 / 12" position indicator (trailing "+" when the
   server still has more to fetch), pushed to the right of the chip row. Makes
   it obvious at a glance that the shelf continues and is easy to browse. */
.atlas-carousel {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  margin-left: auto;
}

.atlas-carousel-btn {
  flex: 0 0 auto;
  width: 36px;
  height: 36px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--text-body);
  line-height: 1;
  border-radius: 50%;
  cursor: pointer;
  background: transparent;
  color: var(--color-base);
  border: 1px solid var(--border-strong);
  transition: border-color var(--dur-fast) var(--ease-out),
              color var(--dur-fast) var(--ease-out);
}

.atlas-carousel-btn:hover:not(:disabled) {
  border-color: var(--color-accent);
  color: var(--color-accent);
}

.atlas-carousel-btn:focus-visible {
  outline: 2px solid var(--color-accent);
  outline-offset: 2px;
}

.atlas-carousel-btn:disabled {
  opacity: 0.4;
  cursor: default;
}

.atlas-carousel-pos {
  font-family: var(--font-ui);
  font-size: var(--text-xs);
  font-variant-numeric: tabular-nums;
  color: var(--cream-dim);
  min-width: 3.5ch;
  text-align: center;
}

/* Peek affordance: a faint offset card edge behind the current poster's right
   side, hinting the next film is stacked behind it. Only when more remain. */
.atlas-current-stop.atlas-has-next .atlas-stop-poster {
  position: relative;
}
.atlas-current-stop.atlas-has-next .atlas-stop-poster::after {
  content: "";
  position: absolute;
  top: 6px;
  bottom: 6px;
  right: -8px;
  width: 10px;
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  background: var(--cream-field);
  border: 1px solid var(--border);
  border-left: none;
  z-index: -1;
  pointer-events: none;
}

/* Recommended film's title rendered as an open-the-card link (reuses the
   slide-in card). Reads as the same display heading, gains a hover accent. */
.atlas-stop-title-link {
  display: inline;
  padding: 0;
  background: none;
  border: none;
  text-align: left;
  cursor: pointer;
  color: inherit;
  font: inherit;
  transition: color var(--dur-fast) var(--ease-out);
}
.atlas-stop-title-link:hover { color: var(--color-accent); }
.atlas-stop-title-link:focus-visible {
  outline: 2px solid var(--color-accent);
  outline-offset: 2px;
}

/* A cited film named inline in the grounded answer — a text link into its card,
   marked with a subtle accent underline so it reads as tappable prose. */
.atlas-answer-link {
  padding: 0;
  background: none;
  border: none;
  cursor: pointer;
  font: inherit;
  color: var(--color-base);
  text-decoration: underline;
  text-decoration-color: var(--color-accent);
  text-underline-offset: 2px;
  transition: color var(--dur-fast) var(--ease-out);
}
.atlas-answer-link:hover { color: var(--color-accent); }
.atlas-answer-link:focus-visible {
  outline: 2px solid var(--color-accent);
  outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
  .atlas-carousel-btn,
  .atlas-stop-title-link,
  .atlas-answer-link { transition: none; }
}

.atlas-opt-hint {
  font-family: var(--font-ui); font-size: var(--text-xs); color: var(--cream-dim);
  margin-left: auto; white-space: nowrap;
}
.atlas-opt { justify-content: space-between; flex-direction: row; align-items: center; flex-wrap: wrap; }

/* ─── HAND-OFF FROM DISCOVER ───────────────────────────────────────────────── */
/* Marks the seam where a homepage composer submit becomes an Atlas turn. */
.atlas-handoff-divider {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: var(--space-4) 0 var(--space-2);
  animation: atlas-turn-in 420ms var(--ease-out, ease-out) both;
}
.atlas-handoff-label {
  flex: none;
  font-family: var(--font-ui);
  font-size: var(--text-xs);
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase;
  color: var(--color-accent);
}
.atlas-handoff-rule {
  flex: 1;
  height: 1px;
  background: var(--border);
}

@keyframes atlas-turn-in {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  .atlas-handoff-divider { animation: none; }
}

/* Hand-off turns rise in sequence so the eye reads divider → question →
   thinking, rather than three things appearing at once. .atlas-msg normally
   animates with atlas-rise (not atlas-turn-enter), so the hand-off's user
   bubble and pending/loader bubble get atlas-turn-enter applied explicitly,
   staggered after the divider.

   Adjacent-sibling (+) chains, not the general sibling combinator (~): the
   divider is never removed mid-conversation (thread.js's clearTurns() only
   drops it on an explicit reset, and a user can send a second, locally-typed
   turn without triggering a reset at all), so a `~` rule would keep matching
   every later .atlas-msg-user/.atlas-msg-bot for the rest of the session.
   `+` only ever matches the single element immediately after the divider
   (handoff.js appends the divider, then composer.js's send() appends exactly
   one user bubble and then exactly one pending/bot bubble, in that order —
   verified against the live DOM), so a second local turn's bubbles are no
   longer directly adjacent to the divider and fall through to the default
   atlas-rise entrance untouched. */
.atlas-handoff-divider { animation-delay: 0ms; }
.atlas-handoff-divider + .atlas-msg-user {
  animation: atlas-turn-enter var(--dur) var(--ease-out) both;
  animation-delay: 80ms;
}
.atlas-handoff-divider + .atlas-msg-user + .atlas-msg-bot {
  animation: atlas-turn-enter var(--dur) var(--ease-out) both;
  animation-delay: 220ms;
}

/* These two selectors are more specific than the blanket `.atlas-msg {
   animation: none; }` reduced-motion rule above, and they're declared later
   in the file, so they win the cascade on both counts and would otherwise
   still stagger a translateY on the hand-off's bubbles for reduced-motion
   users. Kept next to the rules they override so the relationship stays
   obvious. */
@media (prefers-reduced-motion: reduce) {
  .atlas-handoff-divider + .atlas-msg-user,
  .atlas-handoff-divider + .atlas-msg-user + .atlas-msg-bot {
    animation: none;
  }
}

/* ─── TWO-PANE: chat column + film rail (≥900px) / film strip (<900px) ────── */
.atlas-main {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
}
.atlas-conversation { min-width: 0; }

.atlas-film-rail { display: none; }
@media (min-width: 900px) {
  /* Two-pane goes full-bleed: the 820px shell cap belongs to the retired
     single-column layout and starves the conversation once the rail takes
     its share. Uncapping the shell puts the rail against the right viewport
     edge — exactly where the film card slides out from, so the card reads
     as the rail expanding. Reading measure is preserved by capping the
     inner columns (head, thread, chips, composer), not the shell. */
  /* margin:0 (not auto): a cross-axis auto margin on a flex item defeats
     align-items:stretch and shrink-wraps the shell to its content width. */
  /* padding-bottom 0: the 769px block's 40px "breathing room" predates the
     full-bleed layout; the bottom bar's own padding is the breathing room now,
     and the extra 40px read as a dead gap under the composer. */
  .atlas-shell { max-width: none; width: 100%; margin: 0; padding: 0; }
  .atlas-head,
  .atlas-thread {
    width: 100%;
    max-width: 820px;
    margin-left: auto;
    margin-right: auto;
  }
  #atlas-chip-bar,
  .atlas-composer {
    width: 100%;
    max-width: 860px;
    margin-left: auto;
    margin-right: auto;
  }
  .atlas-film-rail {
    display: block;
    flex: 0 0 360px;
    min-height: 0;
    overflow-y: auto;
    border-left: 1px solid var(--border);
    padding: var(--space-5) var(--space-4);
    background: rgba(227, 218, 201, 0.02);
  }
  .atlas-film-rail[hidden] { display: none; }
  .atlas-film-strip { display: none !important; }
}

.atlas-film-strip {
  flex: 0 0 auto;
  display: flex;
  gap: var(--space-2);
  overflow-x: auto;
  padding: var(--space-2) var(--space-3);
  border-top: 1px solid var(--border);
  scroll-snap-type: x proximity;
}
.atlas-film-strip[hidden] { display: none; }
.atlas-strip-tile {
  flex: 0 0 84px;
  scroll-snap-align: center;
  border-radius: var(--radius-sm);
}
.atlas-strip-tile.is-current {
  outline: 2px solid var(--color-accent);
  outline-offset: 2px;
}

/* Rail film block */
.atlas-rail-label {
  font-family: var(--font-ui);
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase;
  color: var(--cream-dim);
  margin: 0 0 var(--space-3);
}
.atlas-rail-tile { width: 100%; max-width: 200px; margin: 0 auto var(--space-3); }
.atlas-rail-info .atlas-stop-title { display: block; }
.atlas-rail-pager {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-3);
  margin-top: var(--space-4);
}
.atlas-rail-pager .atlas-carousel-btn {
  min-width: 44px;
  min-height: 44px;
}

/* ─── STRIP ACCESSIBILITY AND MOTION POLISH ──────────────────────────────── */
.atlas-film-strip .film-card-link:focus-visible,
.atlas-film-rail .film-card-link:focus-visible,
.atlas-carousel-btn:focus-visible {
  outline: 2px solid var(--color-accent);
  outline-offset: 2px;
}
@media (prefers-reduced-motion: reduce) {
  .atlas-film-strip { scroll-behavior: auto; }
}

/* ─── RAIL DISMISS / REOPEN ────────────────────────────────────────────────── */
.atlas-rail-close {
  position: absolute;
  top: var(--space-2);
  right: var(--space-2);
  min-width: 44px;
  min-height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: none;
  border-radius: var(--radius-pill);
  color: var(--cream-dim);
  cursor: pointer;
}
.atlas-rail-close:hover { color: var(--color-base); }
.atlas-film-rail { position: relative; }

.atlas-rail-toggle {
  min-width: 44px;
  min-height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-pill);
  color: var(--cream-dim);
  cursor: pointer;
  flex-shrink: 0;
}
.atlas-rail-toggle.is-open { color: var(--color-accent); border-color: var(--color-accent); }
.atlas-rail-toggle:focus-visible,
.atlas-rail-close:focus-visible { outline: 2px solid var(--color-accent); outline-offset: 2px; }
.atlas-rail-toggle[hidden] { display: none; }  /* override .atlas-rail-toggle's own display: flex */
