  /* Legacy production character panel hidden — the mockup Hall is the selector now. */
  #character-panel { display: none !important; }

  /* (Removed: the original visible #bio-panel was deleted — the visible Bio is now
     #bio2-panel. The only remaining #bio-panel is the hidden legacy one inside
     #legacy-prod-shell, so its old visibility overrides are no longer needed.) */

  /* Task #9: helper states for the real-data Lesson Hub + Tutor panels. */
  .lesson-loading-note, .lesson-empty-note {
    padding: 16px 4px; color: rgba(245, 236, 220, 0.72);
    font-size: 14px; line-height: 1.55;
  }
  .lesson-empty-note { color: rgba(245, 236, 220, 0.82); }
  .diag-entry-error {
    margin-top: 12px; padding: 10px 12px; border-radius: 10px;
    background: rgba(180, 60, 50, 0.16); border: 1px solid rgba(180, 60, 50, 0.32);
    color: #f1d6cf; font-size: 13px; line-height: 1.5; display: none;
  }
  .diag-answer-input {
    width: 100%; box-sizing: border-box; margin: 6px 0 14px;
    padding: 12px 14px; border-radius: 12px; resize: vertical; min-height: 96px;
    background: rgba(20, 14, 10, 0.45); border: 1px solid rgba(245, 236, 220, 0.18);
    color: #f5ecdc; font: inherit; font-size: 14px; line-height: 1.55;
  }
  .diag-answer-input:focus { outline: none; border-color: rgba(217, 160, 102, 0.65); }
  .diag-results-summary {
    margin: 0 0 16px; padding: 14px 16px; border-radius: 12px;
    background: rgba(217, 160, 102, 0.12); border: 1px solid rgba(217, 160, 102, 0.28);
    color: #f5ecdc; font-size: 14px; line-height: 1.55;
  }
  .diag-next-steps { margin-top: 8px; font-size: 13px; color: rgba(245, 236, 220, 0.82); }

  /* Task #11: The legacy TimelineUI (TimelineUI.js) injects a floating right-edge
     overlay — a vertical year-button strip (.timeline-year-list-container, fixed,
     z-index:999) plus a detail popup (.timeline-ui-container, z-index:900). These
     sit on top of the right rail (z-index:10) and physically block clicks on every
     rail button (Bio → Tutor). The timeline now lives INSIDE the right menu via the
     mockup slide-in panel (.timeline-panel / #timeline-panel, opened by #rail-timeline
     and populated with real data by renderTimelinePanelReal()), so the legacy overlay
     is fully suppressed here. These class names are unique to TimelineUI.js and do NOT
     collide with the new panel's classes (.timeline-panel, .timeline-strip, .timeline-year). */
  .timeline-year-list-container,
  .timeline-ui-container {
    display: none !important;
    pointer-events: none !important;
  }

  /* Lab UI merge: the mockup shipped "in preparation / lorem" dev banners for
     non-Leonardo legends. Real controllers now drive Bio + Story per character,
     so these placeholder banners are hidden — users never see scaffolding copy. */
  .bio-preparing,
  body:not([data-legend="leonardo"]) .bio-preparing,
  .story-preparing,
  body:not([data-legend="leonardo"]) .story-preparing {
    display: none !important;
  }

  /* Task #5: relocated REAL in-chat media (art/video) + diagnostic slider.
     ChatController toggles .active on #image-content / #video-content and the
     display of #diagnostic-confidence-container; scope visibility to the new
     chat zone so the results render in-line above the prompt row. */
  .chat-zone #image-content,
  .chat-zone #video-content {
    display: none;
    width: 100%;
    max-height: 42vh;
    overflow: auto;
    margin: 6px 0;
  }
  .chat-zone #image-content.active,
  .chat-zone #video-content.active { display: block; }
  .chat-zone #diagnostic-confidence-container { width: 100%; margin: 4px 0 8px; }

  /* Plan B: host inside the chat bar for the relocated REAL mic + volume controls.
     The originals carry their own CSS from styles.css; we only neutralize the big
     "floating" sizing so they sit inline next to the chat field. */
  .lab-control-host {
    display: inline-flex;
    align-items: center;
    gap: 6px;
  }
  .lab-control-host .mic-button-container,
  .lab-control-host .volume-control-container { margin: 0 !important; }
  .lab-control-host .floating-mic-button {
    width: 34px !important;
    height: 34px !important;
    border-width: 1px !important;
  }
  .lab-control-host .floating-mic-button .mic-icon { font-size: 0.85rem; }
  .lab-control-host .floating-side-button { width: 34px !important; height: 34px !important; }

  /* Task #5: "More tools" popover — re-homes the REAL mobile action-wheel
     (Swap Legend / Bio / Story / Text / Questions / Subscribe) out of the
     hidden legacy shell so its quick actions are reachable in the new UI.
     The chat-input is position:relative, so the popover floats just above
     the More-tools (+) button. The action-wheel's own JS (arrows + scroll
     picker + actionMap) keeps working because the node + ids are preserved. */
  /* Wrapper around the + button + popover so the popover anchors to the BUTTON
     itself (not the far-right edge of the chat bar). It keeps tracking the
     button even after the mic is relocated in beside it at boot. */
  .more-tools-wrap { position: relative; display: inline-flex; align-items: center; }

  /* Conversation-style popover. Mirrors the Lab's established .reader-popover
     menu language (narrow vertical list, eyebrow header, Fraunces titles, a
     warm left-accent on the active row) so it feels native to the Lab — but
     stays THEME-AWARE so text is legible in BOTH light and dark mode.
     Anchored just above the + button, growing up-and-right out of it. */
  .more-tools-popover {
    position: absolute;
    bottom: calc(100% + 10px);
    left: 0;
    z-index: 60;
    width: 264px; max-width: calc(100vw - 32px);
    padding: 6px;
    /* Opaque (deliberately NO backdrop-filter blur: this floats over the live
       3D canvas and the Lab perf rule forbids re-blurring the moving scene
       every frame). A near-solid fill keeps it readable in BOTH modes — the
       light-mode fill is overridden just below. */
    background: rgba(22, 26, 33, 0.98);
    border: 1px solid var(--panel-border-hot);
    border-radius: 14px;
    box-shadow: 0 16px 40px rgba(0, 0, 0, 0.5);
    opacity: 0;
    transform: translateY(6px) scale(0.98);
    transform-origin: bottom left;
    pointer-events: none;
    transition: opacity 0.18s ease, transform 0.18s cubic-bezier(0.22, 1, 0.36, 1);
    /* Stay on-screen on short viewports — scroll internally like .reader-popover. */
    max-height: min(70vh, 440px);
    overflow-y: auto;
    overscroll-behavior: contain;
  }
  /* Light mode: cream panel + warm shadow so the dark --text stays legible. */
  body[data-mode="light"] .more-tools-popover {
    background: rgba(252, 247, 238, 0.99);
    box-shadow: 0 16px 40px rgba(74, 54, 30, 0.18);
  }
  .more-tools-popover.is-open {
    opacity: 1;
    transform: translateY(0) scale(1);
    pointer-events: auto;
  }
  .chat-icon-btn.is-active { color: var(--warm-glow); background: var(--hover-tint-strong); }

  /* Re-style the relocated action-wheel for the Tuscan-dusk popover (its
     original styles.css rules were dropped in the merge). Horizontal picker. */
  .more-tools-popover .action-wheel-container {
    display: flex; align-items: center; gap: 4px;
  }
  .more-tools-popover .action-wheel {
    display: flex; flex: 1; gap: 6px;
    overflow-x: auto; scroll-snap-type: x mandatory;
    scrollbar-width: none; padding: 2px;
  }
  .more-tools-popover .action-wheel::-webkit-scrollbar { display: none; }
  .more-tools-popover .action-wheel-item {
    flex: 0 0 auto; scroll-snap-align: center;
  }
  .more-tools-popover .wheel-btn {
    display: inline-flex; align-items: center; justify-content: center; gap: 6px;
    white-space: nowrap;
    padding: 8px 14px;
    font: 500 0.82rem 'Manrope', sans-serif;
    color: var(--text-dim);
    background: var(--hover-tint);
    border: 1px solid var(--panel-border);
    border-radius: 999px;
    cursor: pointer;
    transition: color 0.2s ease, background 0.2s ease, border-color 0.2s ease;
  }
  .more-tools-popover .action-wheel-item.is-active .wheel-btn,
  .more-tools-popover .wheel-btn:hover {
    color: var(--text);
    background: var(--hover-tint-strong);
    border-color: var(--panel-border-hot);
  }
  .more-tools-popover .wheel-btn.subscription-button {
    color: #1a1208; background: var(--premium-gradient); border-color: transparent;
  }
  .more-tools-popover .action-wheel-arrow {
    flex: 0 0 auto; width: 28px; height: 28px;
    display: flex; align-items: center; justify-content: center;
    color: var(--text-dim); background: transparent;
    border: 1px solid var(--panel-border);
    border-radius: 50%; cursor: pointer;
    transition: color 0.2s ease, background 0.2s ease;
  }
  .more-tools-popover .action-wheel-arrow:hover { color: var(--text); background: var(--hover-tint); }
  /* Decorative-only bits from the mobile layout are noise in the popover. */
  .more-tools-popover .action-wheel-fade,
  .more-tools-popover .action-wheel-indicator { display: none; }

  /* ── Conversation-style picker — the SOLE content of the "+" popover.
     Styled to match the Lab's .reader-popover menu: an eyebrow header over a
     tidy vertical list, Fraunces item titles, a warm left-accent on the
     active row (instead of generic bordered cards). ── */
  .more-tools-popover .cstyle-picker {
    display: flex; flex-direction: column;
  }
  .more-tools-popover .cstyle-title {
    padding: 4px 10px 8px;
    font: 600 10px 'Manrope', sans-serif;
    letter-spacing: 0.14em; text-transform: uppercase;
    color: var(--text-dim);
  }
  .more-tools-popover .cstyle-grid {
    display: flex; flex-direction: column; gap: 1px;
  }
  .more-tools-popover .cstyle-opt {
    display: flex; flex-direction: column; align-items: flex-start; gap: 1px;
    width: 100%; text-align: left;
    padding: 7px 10px;
    background: transparent; border: 0;
    border-radius: 9px;
    cursor: pointer;
    transition: background 0.18s ease;
  }
  .more-tools-popover .cstyle-opt:hover { background: var(--hover-tint-strong); }
  .more-tools-popover .cstyle-opt.is-active {
    background: linear-gradient(90deg, var(--warm-glow-soft, rgba(212, 165, 58, 0.16)), transparent);
    box-shadow: inset 2px 0 0 var(--warm-glow);
  }
  .more-tools-popover .cstyle-label {
    font: 500 14px 'Fraunces', serif;
    font-variation-settings: 'opsz' 14;
    color: var(--text);
    line-height: 1.2;
  }
  .more-tools-popover .cstyle-opt.is-active .cstyle-label { color: var(--warm-glow); }
  .more-tools-popover .cstyle-hint {
    font: 400 10.5px 'Manrope', sans-serif;
    color: var(--text-dim);
    line-height: 1.25;
  }

  /* Plan D: the mockup .bio-header already shows the legend's name+tag (updated on
     every legend switch), so hide the relocated legacy bio title to avoid showing
     the name twice in the panel. */
  #bio-panel #bio-character-name { display: none !important; }

  /* ── Lab UI merge fix: the old production top-right control cluster
     (sky-mode toggle + "Sign In" button + signed-in user display) is fully
     replaced by the mockup top-bar (#mode-toggle, #enter-lab, #profile-chip).
     Hide it so it stops rendering ON TOP of the new controls (this was the
     "two day/night buttons" and the old Sign-In bleeding over "Enter the Lab").
     Children are hidden directly (not the wrapper) because the auth scripts
     toggle these children's display by auth state. */
  #sky-mode-toggle,
  #auth-buttons,
  #user-display { display: none !important; }

  /* ── Lab UI merge fix: the mockup's .figure-stage was sized for a static
     PORTRAIT image — a ~520px centered column (min(520px,60vw) × 78vh). But the
     real WebGL renderer (ModelViewer) sizes its canvas to the full window, so the
     3D character got crammed into that narrow box — the "square in the middle".
     When a 3D model is actually mounted, expand the PRIMARY stage to fill the
     viewport so the character fills the scene like the old full-bleed viewer.
     (Only the primary stage; the secondary/ghost stage is untouched.) */
  body.has-3d-model #canvas-container.figure-primary {
    left: 0 !important;
    width: 100vw !important;
    height: 100vh !important;
    max-width: none !important;
    transform: none !important;
    animation: none !important;
  }

  /* ── Lab UI merge fix (Task #1): the rail buttons must ALWAYS be visible.
     The mockup hid the deeper rooms (Story/Museum/Timeline/Lessons/Tutor) for
     anonymous visitors and hid the whole rail while the Hall was open. The
     product wants every rail button shown at all times, so both gating rules
     are overridden here. */
  body:not(.is-signed-in) .rail-btn[data-tier="occasional"],
  body:not(.is-signed-in) .rail-btn.meta {
    opacity: 0.78 !important;
    pointer-events: auto !important;
    max-height: none !important;
    margin: 0 !important;
    padding: 0 !important;
    overflow: visible !important;
  }
  body:not(.is-signed-in) .rail-btn.meta { opacity: 1 !important; }
  body:not(.is-signed-in) .rail-divider {
    opacity: 1 !important;
    pointer-events: auto !important;
    max-height: none !important;
    height: 1px !important;
    margin: 6px 8px !important;
    padding: 0 !important;
    overflow: visible !important;
  }
  /* Keep the rail visible and clickable above the full-screen Hall overlay
     (z-index 90). A capture-phase click handler closes the Hall first. */
  body.hall-open .right-rail {
    opacity: 1 !important;
    pointer-events: auto !important;
    z-index: 95 !important;
  }

  /* ── Empty-stage prompt ─────────────────────────────────────
     Shown when the lab loads with no legend on stage (a returning visitor
     landing on bare /lab with no preselected model). Centered on the scene,
     above the figure stage but below panels/Hall. Hidden via the [hidden]
     attribute when a legend is committed, the Hall opens, or a model loads. */
  .stage-empty {
    position: fixed;
    top: 50%; left: 50%;
    transform: translate(-50%, -50%);
    z-index: 8;
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: 10px;
    max-width: 440px;
    padding: 0 24px;
    pointer-events: none;
  }
  .stage-empty[hidden] { display: none; }
  .stage-empty-eyebrow {
    font-family: 'Fraunces', serif;
    font-style: italic;
    font-size: 14px;
    letter-spacing: 0.04em;
    color: var(--premium, #d4a058);
    opacity: 0.9;
  }
  .stage-empty-title {
    font-family: 'Fraunces', serif;
    font-size: 28px;
    line-height: 1.2;
    margin: 0;
    color: var(--ink, #f1e9da);
  }
  .stage-empty-sub {
    margin: 0;
    font-size: 15px;
    line-height: 1.5;
    color: var(--ink-soft, rgba(241, 233, 218, 0.7));
  }
  .stage-empty-cta {
    pointer-events: auto;
    margin-top: 8px;
    padding: 10px 22px;
    border-radius: 999px;
    border: 1px solid rgba(212, 160, 88, 0.45);
    background: linear-gradient(135deg, rgba(212, 160, 88, 0.22), rgba(20, 24, 31, 0.6));
    color: var(--premium, #d4a058);
    font-family: 'Fraunces', serif;
    font-size: 15px;
    cursor: pointer;
    transition: background 0.3s ease, transform 0.2s ease, box-shadow 0.3s ease;
  }
  .stage-empty-cta:hover {
    background: linear-gradient(135deg, rgba(212, 160, 88, 0.34), rgba(20, 24, 31, 0.5));
    box-shadow: 0 6px 20px rgba(212, 160, 88, 0.2);
    transform: translateY(-1px);
  }
  body[data-mode="light"] .stage-empty-title { color: var(--ink, #2a2018); }
  body[data-mode="light"] .stage-empty-sub { color: rgba(42, 32, 24, 0.7); }
  body[data-mode="light"] .stage-empty-cta {
    color: var(--premium-deep, #8a5e1a);
    border-color: rgba(184, 138, 62, 0.5);
    background: linear-gradient(135deg, rgba(184, 138, 62, 0.22), rgba(255, 250, 240, 0.85));
  }

  /* ── Task #30: Bio2 & Story2 verification panels ──────────────
     Bio2 (#bio2-panel) and Story2 (#story2-panel) reuse the .bio-panel /
     .story classes for IDENTICAL styling, but their visibility must be
     governed by their OWN body-state classes (body.bio2-open / body.story2-open)
     — NOT the originals' (body.bio-open / body.story-open). The base rules
     `body.bio-open .bio-panel` and `body.story-open .story` (no !important)
     would otherwise slide the duplicates in alongside the originals. These id+
     !important overrides win, so each panel opens/closes on its own state only.
     Mirrors the existing #bio-panel override pattern above. */
  body.bio2-open #bio2-panel {
    opacity: 1 !important;
    pointer-events: auto !important;
    transform: translateX(0) !important;
  }
  body:not(.bio2-open) #bio2-panel {
    opacity: 0 !important;
    pointer-events: none !important;
    transform: translateX(110%) !important;
  }
  body.story2-open #story2-panel { transform: translateX(0) !important; }
  body:not(.story2-open) #story2-panel { transform: translateX(100%) !important; }

  /* The Bio2 content lives in a `.panel-content` wrapper. character-panel.css
     hides that class globally (`.panel-content { display: none }`, only revealed
     via `.panel-content.active`), and the Tuscan-dusk panels never add `.active`.
     So force the duplicate's content visible while its panel is open. Scoped to
     #bio2-panel + gated on body.bio2-open so the original Bio panel is untouched. */
  body.bio2-open #bio2-panel .panel-content { display: block !important; }

  /* Same trap, original panels: the live Bio panel and the History panel both
     wrap their content in `.panel-content`, which character-panel.css hides
     globally (only revealed via `.panel-content.active`, never added by the
     Tuscan-dusk panels). Force their content visible while each panel is open.
     Scoped to each panel id + gated on its own body.<state>-open so nothing
     else is affected. This is the same fix Bio2 already uses. */
  body.history-open #history-panel .panel-content { display: block !important; }

  /* Scholar's Journal panel — same global `.panel-content { display:none }` trap;
     force its content visible while body.journal-open. */
  body.journal-open #journal-panel .panel-content { display: block !important; }

  /* Match the figure/chat shift the originals apply, so Bio2/Story2 look and
     behave identically (avatar + chat slide left to clear the panel). */
  body.bio2-open .figure-primary {
    --breathe-base: translateX(calc(-50% - 200px));
    transform: var(--breathe-base);
  }
  body.story2-open .figure-primary {
    --breathe-base: translateX(calc(-50% - 560px / 2));
    transform: var(--breathe-base);
  }
  body.bio2-open .chat-zone {
    width: min(420px, calc(100% - 540px));
    transform: translateX(calc(-50% - 200px));
  }
  body.story2-open .chat-zone {
    width: min(420px, calc(100% - 620px));
    transform: translateX(calc(-50% - 260px));
  }

  /* ── Task #57: Restore chat media & apply the new Tuscan-dusk chat style ──
     The REAL chat renderer (ChatController.addMessageToChat) emits the LEGACY
     classes .chat-message + .user-message/.bot-message with an inner
     .message-content, styled by the old styles.css panel rules. The new chat
     container is .chat-thread. These rules re-skin those legacy classes INSIDE
     .chat-thread so the new typography/colors actually apply, and restyle the
     in-chat keyword images + YouTube videos that ChatController appends under a
     legend's reply so they fit the new design in both light and dark modes.
     (The media containers carry inline .cssText from the JS, so the media rules
     use !important to win over them.) */

  /* —— Message bubbles —— */
  .chat-thread .chat-message {
    max-width: 82%;
    width: auto;
    margin: 0;
    padding: 10px 16px;
    border-radius: 18px;
    font-family: 'Fraunces', serif;
    font-variation-settings: 'opsz' 14;
    font-size: 14.5px;
    line-height: 1.5;
    word-wrap: break-word;
    overflow-wrap: anywhere;
    animation: msg-rise 0.4s cubic-bezier(0.22, 1, 0.36, 1);
  }
  .chat-thread .chat-message .sender {
    display: block;
    font-family: 'Manrope', sans-serif;
    font-style: normal;
    font-size: 11px;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    opacity: 0.55;
    margin-bottom: 4px;
  }
  .chat-thread .chat-message .message-content { display: block; }
  .chat-thread .chat-message .message-content p { margin: 0 0 8px; }
  .chat-thread .chat-message .message-content p:last-child { margin-bottom: 0; }
  .chat-thread .chat-message .message-content a { color: var(--warm-glow); }

  /* User — warm tint, right-aligned (mirrors .chat-msg.user) */
  .chat-thread .chat-message.user-message {
    align-self: flex-end;
    margin-left: auto;
    margin-right: 0;
    min-width: 0;
    background: linear-gradient(135deg, rgba(212, 165, 116, 0.18), rgba(212, 165, 116, 0.08));
    border: 1px solid rgba(212, 165, 116, 0.22);
    color: var(--text);
    border-bottom-right-radius: 4px;
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
  }
  body[data-mode="light"] .chat-thread .chat-message.user-message {
    background: linear-gradient(135deg, rgba(184, 138, 62, 0.22), rgba(184, 138, 62, 0.10));
    border-color: rgba(184, 138, 62, 0.30);
    color: var(--text);
  }

  /* Legend (bot) — parchment-tinted, italic, left-aligned (mirrors .chat-msg.legend) */
  .chat-thread .chat-message.bot-message {
    align-self: flex-start;
    margin-left: 0;
    margin-right: auto;
    background: rgba(28, 34, 44, 0.55);
    backdrop-filter: blur(20px);
    -webkit-backdrop-filter: blur(20px);
    border: 1px solid var(--panel-border);
    color: var(--text);
    font-style: italic;
    border-bottom-left-radius: 4px;
  }
  body[data-mode="light"] .chat-thread .chat-message.bot-message {
    background: rgba(255, 247, 232, 0.85);
    border-color: rgba(31, 24, 16, 0.10);
    color: var(--text);
  }

  /* Status/system message variants stay readable in the new thread */
  .chat-thread .chat-message.error-message {
    align-self: stretch; max-width: 100%; font-style: normal;
    background: rgba(180, 60, 50, 0.16); border: 1px solid rgba(180, 60, 50, 0.32);
    color: #f1d6cf;
  }
  .chat-thread .chat-message.system-message,
  .chat-thread .chat-message.success-message {
    align-self: stretch; max-width: 100%; font-style: normal;
    color: var(--text-dim);
  }

  /* —— In-chat keyword IMAGES (responsive gallery under a bot bubble) —— */
  .chat-thread .keyword-images-container,
  .chat-thread .keyword-videos-container {
    margin-top: 10px !important;
    padding: 0 !important;
    background: transparent !important;
    border-radius: 0 !important;
    width: 100%;
  }
  .chat-thread .embedded-keyword-images {
    display: grid !important;
    grid-template-columns: repeat(auto-fill, minmax(92px, 1fr)) !important;
    gap: 6px !important;
    margin-top: 10px !important;
    padding-top: 10px !important;
    border-top: 1px solid var(--panel-border) !important;
  }
  .chat-thread .embedded-keyword-image {
    position: relative !important;
    border-radius: 10px !important;
    overflow: hidden !important;
    background: var(--hover-tint) !important;
    border: 1px solid var(--panel-border) !important;
    cursor: pointer;
    transition: transform 0.2s ease, box-shadow 0.2s ease, border-color 0.2s ease;
  }
  .chat-thread .embedded-keyword-image img {
    width: 100% !important;
    height: 82px !important;
    object-fit: cover !important;
    display: block !important;
    border-radius: 10px !important;
  }
  .chat-thread .embedded-keyword-image:hover {
    transform: scale(1.02);
    box-shadow: 0 4px 14px rgba(0, 0, 0, 0.28);
    border-color: var(--panel-border-hot) !important;
  }

  /* —— In-chat YouTube VIDEOS (responsive 16:9 embeds under a bot bubble) —— */
  .chat-thread .embedded-keyword-videos {
    display: flex !important;
    flex-direction: column;
    gap: 10px !important;
    margin-top: 10px !important;
    padding-top: 10px !important;
    border-top: 1px solid var(--panel-border) !important;
  }
  .chat-thread .embedded-keyword-video-wrapper {
    position: relative;
    width: 100%;
    border-radius: 12px !important;
    overflow: hidden !important;
    background: rgba(0, 0, 0, 0.42) !important;
    border: 1px solid var(--panel-border) !important;
    box-sizing: border-box;
  }
  .chat-thread .embedded-keyword-video-wrapper .video-keyword-header {
    padding: 7px 12px !important;
    font-family: 'Manrope', sans-serif !important;
    font-style: normal !important;
    font-size: 11px !important;
    font-weight: 600 !important;
    letter-spacing: 0.04em;
    text-transform: capitalize !important;
    color: var(--text-dim) !important;
    background: var(--hover-tint) !important;
  }
  .chat-thread .embedded-video-container {
    position: relative;
    width: 100%;
    padding-bottom: 56.25%;
    height: 0;
    background: #000;
  }
  .chat-thread .embedded-video-container iframe {
    position: absolute !important;
    top: 0; left: 0;
    width: 100% !important;
    height: 100% !important;
    border: none !important;
    border-radius: 0 0 12px 12px !important;
  }
  /* Two-up / three-up layouts when the chat zone is wide enough */
  @media (min-width: 760px) {
    .chat-thread .embedded-keyword-videos.videos-two-up,
    .chat-thread .embedded-keyword-videos.videos-three-up {
      flex-direction: row !important;
      flex-wrap: wrap;
    }
    .chat-thread .embedded-keyword-videos.videos-two-up .embedded-keyword-video-wrapper {
      flex: 1 1 calc(50% - 5px);
    }
    .chat-thread .embedded-keyword-videos.videos-three-up .embedded-keyword-video-wrapper {
      flex: 1 1 calc(33.333% - 7px);
      min-width: 150px;
    }
  }

/* ──────────────────────────────────────────────────────────────────────────
   Tuscan-dusk modal cards vs. Bootstrap's .modal base
   ──────────────────────────────────────────────────────────────────────────
   The mockup modal card uses class="modal" (e.g. #modal-auth → .modal.auth-modal),
   which collides with Bootstrap (bootstrap-agent-dark-theme.min.css) where
   `.modal { position:fixed; top:0; left:0; display:none; height:100%; ... }`.
   lab-shell.css's `.modal` rule never sets display/position, so Bootstrap's
   `display:none` (and full-screen fixed geometry) leak through: the .modal-backdrop
   blur shows but the card is invisible ("blur and nothing else" on sign-in).
   Scope to direct children of .modal-backdrop so REAL Bootstrap modals — whose
   .modal-backdrop is a sibling, not a parent — are untouched. */
.modal-backdrop > .modal {
  display: block;
  position: relative;
  top: auto;
  left: auto;
  height: auto;
  overflow: visible;
  z-index: auto;
}

/* ──────────────────────────────────────────────────────────────────────────
   Tuscan-dusk subscription flow (plan picker + status panel + toast)
   ──────────────────────────────────────────────────────────────────────────
   Injected by static/src/js/modules/BackendSubscriptionChecker.js. Reuses the
   existing .modal-backdrop / .modal / .subscribe-modal shells (no NEW
   backdrop-filter is introduced over the 3D canvas). All colours come from the
   Tuscan tokens so both light ("dusk", default) and dark mode work for free. */

/* Billing-period toggle */
.sub-billing {
  display: inline-flex;
  margin: 22px 0 24px;
  padding: 4px;
  gap: 4px;
  background: var(--hover-tint);
  border: 1px solid var(--panel-border);
  border-radius: 999px;
}
.sub-billing-opt {
  appearance: none;
  border: none;
  background: transparent;
  color: var(--text-dim);
  font-family: 'Manrope', sans-serif;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.01em;
  padding: 8px 18px;
  border-radius: 999px;
  cursor: pointer;
  transition: color 0.2s ease, background 0.2s ease;
  display: inline-flex;
  align-items: center;
  gap: 8px;
}
.sub-billing-opt:hover { color: var(--text); }
.sub-billing-opt.is-active {
  color: #1a1208;
  background: var(--premium-gradient);
  box-shadow: 0 4px 12px rgba(192, 133, 64, 0.28);
}
.sub-billing-save {
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  font-weight: 700;
  color: var(--premium);
}
.sub-billing-opt.is-active .sub-billing-save { color: #1a1208; }

/* Two-tier grid */
.sub-plans.subscribe-modal { max-width: 620px; }
.sub-tiers {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 14px;
  text-align: left;
}
.sub-tier {
  padding: 22px 20px;
  background: var(--hover-tint);
  border: 1px solid var(--panel-border);
  border-radius: 18px;
  position: relative;
  display: flex;
  flex-direction: column;
}
.sub-tier.featured {
  background: linear-gradient(135deg, rgba(212, 160, 88, 0.12), rgba(212, 160, 88, 0.02));
  border-color: rgba(212, 160, 88, 0.35);
  box-shadow: inset 0 0 24px rgba(255, 215, 130, 0.06);
}
.sub-tier-name {
  font-size: 12px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--text-faint);
  font-weight: 600;
}
.sub-tier-price {
  margin-top: 10px;
  font-family: 'Fraunces', serif;
  font-variation-settings: 'opsz' 144;
  font-weight: 400;
  font-size: 34px;
  letter-spacing: -0.02em;
  color: var(--text);
}
.sub-tier-price small { font-size: 14px; color: var(--text-faint); }
.sub-tier-sub {
  margin-top: 4px;
  font-size: 12px;
  color: var(--text-dim);
  min-height: 16px;
}
.sub-tier-feats {
  list-style: none;
  margin: 18px 0 20px;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
  flex: 1;
}
.sub-tier-feats li {
  display: flex;
  align-items: flex-start;
  gap: 9px;
  font-size: 13px;
  line-height: 1.35;
  color: var(--text-dim);
}
.sub-tier-feats li svg {
  width: 15px;
  height: 15px;
  flex-shrink: 0;
  margin-top: 1px;
  color: var(--premium);
}
.sub-tier-cta {
  appearance: none;
  width: 100%;
  border-radius: 12px;
  padding: 12px 16px;
  font-family: 'Manrope', sans-serif;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  transition: all 0.2s ease;
  border: 1px solid var(--panel-border);
}
.sub-tier-cta-free {
  background: transparent;
  color: var(--text-faint);
  cursor: default;
}
.sub-tier-cta-premium {
  border: none;
  background: var(--premium-gradient);
  color: #1a1208;
  box-shadow: 0 6px 18px rgba(192, 133, 64, 0.3);
}
.sub-tier-cta-premium:hover { filter: brightness(1.06); transform: translateY(-1px); }
.sub-tier-cta-premium:disabled { opacity: 0.7; cursor: progress; transform: none; }

.sub-secure {
  margin-top: 22px;
  font-size: 12px;
  color: var(--text-faint);
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
}
.sub-secure svg { width: 13px; height: 13px; }

/* Centered status panel */
.sub-status-modal { max-width: 460px; text-align: center; position: relative; }
.sub-status-badge {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 7px 16px;
  border-radius: 999px;
  background: var(--premium-gradient);
  color: #1a1208;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  box-shadow: 0 6px 18px rgba(192, 133, 64, 0.32);
  margin-bottom: 18px;
}
.sub-status-badge svg { width: 15px; height: 15px; }
.sub-status-modal h2 {
  font-family: 'Fraunces', serif;
  font-weight: 400;
  font-size: 30px;
  font-variation-settings: 'opsz' 144, 'SOFT' 100;
  line-height: 1.05;
  letter-spacing: -0.025em;
  color: var(--text);
}
.sub-status-modal h2 em { font-style: italic; color: var(--warm-glow); }
.sub-status-modal > p {
  margin-top: 10px;
  font-size: 14px;
  color: var(--text-dim);
}
.sub-status-feats {
  list-style: none;
  margin: 22px auto 18px;
  padding: 0;
  display: inline-flex;
  flex-direction: column;
  gap: 11px;
  text-align: left;
}
.sub-status-feats li {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 13px;
  color: var(--text-dim);
}
.sub-status-feats li svg {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
  color: var(--premium);
}
.sub-status-meta {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 12px;
  color: var(--text-faint);
  margin-bottom: 26px;
}
.sub-status-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--premium);
  box-shadow: 0 0 8px var(--premium);
}
.sub-status-actions {
  display: flex;
  gap: 10px;
  justify-content: center;
}
.sub-status-actions .btn { min-width: 130px; }

/* On-brand toast */
.sub-toast {
  position: fixed;
  left: 50%;
  bottom: 32px;
  transform: translate(-50%, 16px);
  z-index: 300;
  max-width: min(440px, 90vw);
  padding: 14px 20px;
  border-radius: 14px;
  background: rgba(28, 34, 44, 0.96);
  color: var(--text);
  border: 1px solid var(--panel-border);
  box-shadow: 0 18px 48px rgba(5, 8, 14, 0.45);
  font-family: 'Manrope', sans-serif;
  font-size: 14px;
  line-height: 1.4;
  text-align: center;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.3s ease, transform 0.3s ease;
}
body[data-mode="light"] .sub-toast {
  background: rgba(255, 247, 232, 0.98);
  color: var(--text);
  box-shadow: 0 18px 48px rgba(80, 50, 20, 0.22);
}
.sub-toast.is-open { opacity: 1; transform: translate(-50%, 0); }
.sub-toast-success { border-color: rgba(212, 160, 88, 0.5); }
.sub-toast-error { border-color: rgba(200, 90, 70, 0.55); }

@media (max-width: 560px) {
  .sub-plans.subscribe-modal { max-width: 94vw; }
  .sub-tiers { grid-template-columns: 1fr; }
  .sub-status-actions { flex-direction: column; }
  .sub-status-actions .btn { width: 100%; }
}
