*, *::before, *::after {
  margin: 0; padding: 0; box-sizing: border-box;
  -webkit-user-select: none; user-select: none;
  -webkit-tap-highlight-color: transparent;
}

html, body {
  width: 100%; height: 100%; overflow: hidden;
  font-family: var(--text);
  -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  background: var(--shell-bg); color: #f4f2ff;
  transition: background .45s;
}

:root {
  /* Section typography — faces declared in shared/fonts/css/interactive.css. */
  --display: 'Unbounded', 'Nunito', system-ui, sans-serif;
  /* Only one display weight ships — pin it so the browser never fakes a bolder cut. */
  --display-weight: 600;
  --text: 'Nunito', -apple-system, BlinkMacSystemFont, system-ui, sans-serif;
  --mono: 'Roboto Mono', ui-monospace, SFMono-Regular, Menlo, monospace;

  /* App shell geometry */
  --shell-gap: 16px;      /* gutter between the window and the shell edges */
  --header-h: 74px;       /* header row: also the window's top inset */
  --window-radius: 16px;
  --island-gap: 12px;     /* отступ раскрытого сайдбара-«острова» от краёв экрана */
  /* The shell sits a touch under the sidebar so the panel still reads as raised. */
  --shell-bg: color-mix(in srgb, var(--menu-bg) 78%, #05050a);

  --scene-bg: #0a0a14;
  --scene-accent: #6366f1;
  --menu-bg: #0a0a14;
  --menu-orb: #6366f1;
  --menu-orb-fg: #fff;
  --fg: #f4f2ff;
  --fg-a05: rgba(244, 242, 255, 0.05);
  --fg-a08: rgba(244, 242, 255, 0.08);
  --fg-a12: rgba(244, 242, 255, 0.12);
  --fg-a25: rgba(244, 242, 255, 0.25);
  --fg-a40: rgba(244, 242, 255, 0.4);
  --fg-a55: rgba(244, 242, 255, 0.55);
  --fg-a75: rgba(244, 242, 255, 0.75);
  --surface: color-mix(in srgb, var(--scene-bg) 30%, rgba(10, 10, 20, 0.85));
  --surface-solid: color-mix(in srgb, var(--scene-bg) 20%, #111218);
  --sidebar-w: 296px;
  --peek: 10px;
  --dock-h: 118px;
  --transition-fast: .18s;
  --transition-med: .28s cubic-bezier(.2, .8, .2, 1);
}

:root[data-mode="light"] {
  --shell-bg: color-mix(in srgb, var(--menu-bg) 74%, #ffffff);
  --fg: #15151a;
  --fg-a05: rgba(21, 21, 26, 0.05);
  --fg-a08: rgba(21, 21, 26, 0.08);
  --fg-a12: rgba(21, 21, 26, 0.12);
  --fg-a25: rgba(21, 21, 26, 0.25);
  --fg-a40: rgba(21, 21, 26, 0.4);
  --fg-a55: rgba(21, 21, 26, 0.55);
  --fg-a75: rgba(21, 21, 26, 0.75);
  --surface: color-mix(in srgb, var(--scene-bg) 25%, rgba(252, 252, 250, 0.82));
  --surface-solid: color-mix(in srgb, var(--scene-bg) 15%, #fefefe);
  color: var(--fg);
}

.scroll::-webkit-scrollbar { width: 6px; height: 6px; }
.scroll::-webkit-scrollbar-track { background: transparent; }
.scroll::-webkit-scrollbar-thumb { background: var(--fg-a12); border-radius: 3px; }
.scroll::-webkit-scrollbar-thumb:hover { background: var(--fg-a25); }

button { font-family: inherit; color: inherit; border: none; background: none; cursor: pointer; }
button:focus-visible { outline: 2px solid currentColor; outline-offset: 2px; }
iframe { color-scheme: normal; background-color: inherit; border: none; }

/* ===== APP HEADER =====
   The shell's title row: identity on the left, every action on the right.
   It stops at the sidebar's edge, so pinning the list narrows the header and
   the window together and the two right edges stay flush. */
.app-header {
  position: fixed;
  top: 0; left: 0;
  right: var(--stage-right, 0px);
  height: var(--header-h);
  display: flex; align-items: center; gap: 14px;
  padding: 0 var(--shell-gap);
  z-index: 30;
  color: var(--fg);
  /* The row is transparent and reaches over the sidebar's peek strip, so only
     its real contents may take the pointer — otherwise the empty middle of the
     header swallows the hover and the clicks meant for the diamond handle. */
  pointer-events: none;
  transition: right var(--transition-med), height var(--transition-med), opacity .25s;
}
.app-header > * { pointer-events: auto; }

/* A hover-opened sidebar is raised above the header so the action cluster does
   not paint over its own head row — which would then bury a dropdown opened
   from that same cluster. While one is open the header takes the top layer back. */
.app-header:has(.lang-selector.open),
.app-header:has(.scene-help.open) { z-index: 40; }

.header-actions {
  margin-left: auto;
  flex: 0 0 auto;
  display: flex; align-items: center; gap: 6px;
}

/* ===== STAGE — the inset window =====
   The experiment is not full-bleed any more: it is a separate rounded surface
   sitting inside our chrome, which is what makes the whole thing read as one
   application with an app loaded into it. */
.stage {
  position: fixed;
  top: var(--header-h);
  left:   calc(var(--stage-left,   0px) + var(--shell-gap));
  right:  calc(var(--stage-right,  0px) + var(--shell-gap));
  bottom: calc(var(--stage-bottom, 0px) + var(--shell-gap));
  padding: 0;
  background: var(--scene-bg);
  border: 1px solid var(--fg-a05);
  border-radius: var(--window-radius);
  overflow: hidden;
  isolation: isolate;
  box-shadow: 0 30px 70px -30px rgba(0,0,0,.7), 0 2px 12px -6px rgba(0,0,0,.45);
  transition:
    top var(--transition-med), left var(--transition-med),
    right var(--transition-med), bottom var(--transition-med),
    border-radius var(--transition-med), background .6s;
}

.stage-slot {
  position: absolute; inset: 0;
  border-radius: inherit; overflow: hidden;
  opacity: 0;
  transform: scale(1.04);
  filter: blur(12px);
  transition:
    opacity 450ms cubic-bezier(.4, 0, .2, 1),
    transform 600ms cubic-bezier(.4, 0, .2, 1),
    filter 450ms cubic-bezier(.4, 0, .2, 1);
  pointer-events: none;
}
.stage-slot.visible {
  opacity: 1; transform: scale(1); filter: blur(0);
  pointer-events: auto;
}
.stage-slot iframe {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  background: var(--scene-bg);
}

.stage-flash {
  position: absolute; inset: 0;
  background: var(--scene-bg);
  opacity: 0; pointer-events: none;
  transition: opacity 180ms ease-out;
  z-index: 5;
}
.stage-flash.active { opacity: 0.35; }

#spec-frame {
  position: fixed; width: 0; height: 0;
  top: -9999px; left: -9999px; pointer-events: none;
}

/* ===== SCENE LABEL ===== */
.scene-label {
  position: relative; top: auto; left: auto; z-index: auto;
  flex: 1 1 auto; min-width: 0;
  display: flex; align-items: center; gap: 12px;
  padding: 0;
  color: var(--fg);
  text-shadow: none;
  transition: opacity .25s;
}

/* ===== BACK TO THE LAB =====
   Sits immediately left of the current scene's icon and copies its size and shape,
   so the two read as one control: "this scene · leave it". The label unfurls on
   hover (0fr -> 1fr) instead of permanently stealing width from the scene title —
   and because the column is content-sized, it fits every one of the 12 locales. */
.lab-home {
  flex: 0 0 auto;
  height: 36px;
  border-radius: 10px;
  background: var(--fg-a05);
  border: 1px solid var(--fg-a05);
  color: var(--fg-a75);
  text-decoration: none;
  overflow: hidden;
  display: inline-grid;
  grid-template-columns: 36px minmax(0, 0fr);
  align-items: center;
  transition: grid-template-columns var(--transition-med),
    background var(--transition-fast),
    color var(--transition-fast), border-color var(--transition-fast);
}
.lab-home > svg { grid-column: 1; justify-self: center; }
.lab-home-label {
  grid-column: 2;
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
  padding-right: 12px;
  font-size: 12px; font-weight: 600; letter-spacing: .02em;
}
.lab-home:hover,
.lab-home:focus-visible {
  grid-template-columns: 36px minmax(0, 1fr);
  background: var(--fg-a12);
  color: var(--fg);
  border-color: var(--fg-a25);
}
@media (prefers-reduced-motion: reduce) {
  .lab-home { transition: color var(--transition-fast); }
}

.scene-label-icon {
  flex: 0 0 auto;
  width: 36px; height: 36px; border-radius: 10px;
  background: var(--surface);
  backdrop-filter: blur(20px) saturate(1.2);
  -webkit-backdrop-filter: blur(20px) saturate(1.2);
  border: 1px solid var(--fg-a05);
  display: grid; place-items: center;
  font-size: 17px; overflow: hidden;
  position: relative;
}
.scene-label-icon .ico-slot {
  position: absolute; inset: 0;
  display: grid; place-items: center;
  opacity: 0; transform: scale(0.82); filter: blur(4px);
  transition:
    opacity .45s cubic-bezier(.4,0,.2,1),
    transform .5s cubic-bezier(.4,0,.2,1),
    filter .45s cubic-bezier(.4,0,.2,1);
  pointer-events: none;
}
.scene-label-icon .ico-slot.visible { opacity: 1; transform: scale(1); filter: blur(0); }
.scene-label-icon .ico-slot img { width: 100%; height: 100%; object-fit: cover; }

/* The slots inside are absolutely positioned, so the column has no intrinsic
   width of its own — it takes the header's leftover room instead. */
.scene-label-text {
  flex: 1 1 auto; min-width: 0;
  display: flex; flex-direction: column; gap: 1px;
}

.scene-label-name,
.scene-label-meta {
  overflow: hidden; position: relative; white-space: nowrap;
}
.scene-label-name { height: 22px; }
.scene-label-meta { height: 16px; }

/* left+right rather than shrink-to-fit: the slot has to inherit the column's
   width, otherwise it sizes itself to the text, never overflows, and the
   ellipsis never fires — the parent just hard-clips the name mid-letter. */
.label-slot {
  position: absolute; left: 0; right: 0; top: 0;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  opacity: 0;
  transform: translateY(-25%);
  filter: blur(4px);
  transition:
    opacity .45s cubic-bezier(.4,0,.2,1),
    transform .45s cubic-bezier(.4,0,.2,1),
    filter .45s cubic-bezier(.4,0,.2,1);
  pointer-events: none;
}
.label-slot.visible {
  opacity: 1;
  transform: translateY(0);
  filter: blur(0);
}
.label-slot.leaving {
  opacity: 0;
  transform: translateY(25%);
  filter: blur(4px);
}

.scene-label-name .label-slot {
  font-size: 14px; font-weight: 600;
  color: var(--fg); letter-spacing: -.01em;
  max-width: 34vw;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.scene-label-meta .label-slot {
  font-size: 11px; font-family: var(--mono);
  color: var(--fg-a55); letter-spacing: .04em;
}

/* ===== NAV ARROWS =====
   Centred inside the window, not the viewport: the header eats the top inset and
   the dock (on mobile) the bottom one. The duplicated `top` is a deliberate dvh
   progressive enhancement — the vh line is the fallback. */
.nav-arrow {
  position: fixed;
  top: calc((var(--header-h) + 100vh  - var(--stage-bottom, 0px) - var(--shell-gap)) / 2);
  top: calc((var(--header-h) + 100dvh - var(--stage-bottom, 0px) - var(--shell-gap)) / 2);
  transform: translateY(-50%);
  width: 52px; height: 52px; border-radius: 50%;
  background: var(--surface);
  backdrop-filter: blur(20px) saturate(1.2);
  -webkit-backdrop-filter: blur(20px) saturate(1.2);
  border: 1px solid var(--fg-a05);
  color: var(--fg);
  z-index: 20; display: grid; place-items: center;
  transition: background var(--transition-fast), border-color var(--transition-fast),
              color var(--transition-fast), opacity var(--transition-fast),
              transform var(--transition-fast),
              top var(--transition-med), left var(--transition-med), right var(--transition-med);
}
.nav-arrow:hover { background: var(--scene-accent); border-color: var(--scene-accent); color: #fff; }
.nav-arrow:hover:not(:disabled) { transform: translateY(-50%) scale(1.04); }
.nav-arrow:disabled { opacity: 0.25; pointer-events: none; }

.nav-left  { left:  calc(var(--stage-left,  0px) + var(--shell-gap) + 14px); }
.nav-right { right: calc(var(--stage-right, 0px) + var(--shell-gap) + 14px); }

/* Nav hints tooltip */
.nav-tip {
  position: absolute;
  display: flex; flex-direction: column; align-items: center; gap: 3px;
  padding: 7px 10px; border-radius: 8px;
  background: rgba(20, 22, 30, 0.92);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border: 1px solid var(--fg-a12);
  color: var(--fg); font-size: 12px; font-weight: 500;
  white-space: nowrap; pointer-events: none;
  opacity: 0; transition: opacity .2s;
  z-index: 1;
}
.nav-left  .nav-tip { left: calc(100% + 10px); }
.nav-right .nav-tip { right: calc(100% + 10px); }
.nav-tip kbd {
  font-family: var(--mono);
  font-size: 10px; color: var(--fg-a55);
  letter-spacing: .04em;
}
:root:not(.nav-hints-dismissed) .nav-arrow:hover .nav-tip { opacity: 1; }

/* ===== HEADER BUTTONS =====
   The action buttons, the tips button and "open in a new tab" are the same
   control — one bordered square, one hover state. */
.action-btn,
.scene-help-btn,
.scene-open-btn {
  flex: 0 0 auto;
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  width: 36px; height: 36px; padding: 0;
  border-radius: 10px;
  border: 1px solid var(--fg-a05);
  background: var(--fg-a05);
  color: var(--fg);
  font-family: var(--mono);
  font-size: 11px; letter-spacing: .1em;
  box-shadow: none; opacity: 1;
  transition: background .2s, border-color .2s, color .2s;
}
.action-btn:hover,
.scene-help-btn:hover,
.scene-open-btn:hover { background: var(--fg-a12); }
.action-pill { width: auto; padding: 0 10px; }

.action-bar { display: flex; align-items: center; gap: 6px; color: var(--fg); }
.scene-help    { position: relative; }
.scene-open-btn{ position: relative; }
.scene-help[hidden], .scene-open-btn[hidden] { display: none; }
.scene-help.open .scene-help-btn {
  background: color-mix(in srgb, var(--menu-orb) 26%, var(--fg-a08));
  border-color: var(--fg-a25);
}

/* Lang selector */
.lang-selector { position: relative; }
.lang-dropdown {
  position: absolute;
  top: calc(100% + 10px); right: 0; left: auto; bottom: auto;
  width: 240px; max-height: min(420px, 60vh); overflow-y: auto;
  display: flex; flex-direction: column; gap: 1px;
  background: var(--surface-solid);
  border: 1px solid var(--fg-a12);
  border-radius: 14px;
  padding: 6px;
  box-shadow: 0 24px 60px -18px rgba(0,0,0,.55);
  transform-origin: top right;
  opacity: 0; visibility: hidden; transform: translateY(-6px) scale(.98);
  z-index: 40;
  scrollbar-width: thin;
  transition: opacity var(--transition-fast), visibility var(--transition-fast), transform var(--transition-fast);
}
.lang-selector.open .lang-dropdown { opacity: 1; visibility: visible; transform: translateY(0) scale(1); }
.lang-option {
  display: flex; align-items: center; gap: 8px;
  padding: 7px 10px; border-radius: 8px;
  font-size: 13px; color: var(--fg-a75);
  transition: background var(--transition-fast), color var(--transition-fast);
}
.lang-option:hover { background: var(--fg-a08); color: var(--fg); }
.lang-option.active { color: var(--fg); font-weight: 600; }
.lang-option.active::after {
  content: '✓';
  margin-left: auto;
  color: var(--scene-accent);
  font-weight: 700;
}
.flag-icon { width: 18px; height: 14px; object-fit: cover; border-radius: 2px; }

/* ===== SIDEBAR ===== */
.sidebar {
  position: fixed; top: 0; right: 0; bottom: 0;
  width: var(--sidebar-w);
  z-index: 25;
  pointer-events: none;
}
/* Hovered open, the panel slides out across the header row, so it has to win the
   stacking order — otherwise the header's action cluster paints over the
   sidebar's own head. Pinned, the header already stops at the panel's edge, and
   collapsed it must stay under the header so the top-right corner keeps its
   clicks. */
.sidebar.open:not(.pinned) { z-index: 35; }
.sidebar-hover-zone,
.sidebar-handle,
.sidebar-panel { pointer-events: auto; }
.sidebar-hover-zone {
  position: absolute; top: 0; bottom: 0;
  right: 0;
  width: 28px;
  z-index: 0; /* stay under the panel/handle so it never intercepts their clicks */
  transition: width var(--transition-med);
}
.sidebar.open .sidebar-hover-zone { width: calc(var(--sidebar-w) + 22px); }

/* Reveal handle — attached to the left edge of the peek strip when collapsed,
   vertically centred on the header row so it lines up with the chrome. */
.sidebar-handle {
  --size: 30px;
  position: absolute;
  top: calc((var(--header-h) - var(--size)) / 2);
  right: calc(var(--peek) - (var(--size) / 2));
  width: var(--size);
  height: var(--size);
  background: var(--surface);
  border-bottom-left-radius: 4px;
  backdrop-filter: blur(20px) saturate(1.2);
  -webkit-backdrop-filter: blur(20px) saturate(1.2);
  border: 1px solid var(--fg-a05);
  border-right: none;
  color: var(--fg);
  display: grid; place-items: center;
  z-index: 20;
  opacity: 1;
  box-shadow: -4px 8px 20px -6px rgba(0,0,0,0.25);
  transform: rotate(45deg);
  transition:
    opacity .25s,
    top var(--transition-med),
    right var(--transition-med),
    transform var(--transition-med),
    background .35s;
}
.sidebar-handle > svg {
  transform: rotate(-45deg) translateX(-6px);
}
.sidebar-handle:hover { opacity: 0; scale: .95; }
.sidebar.open .sidebar-handle {
  opacity: 0;
  pointer-events: none;
  scale: 0.95;
}
.sidebar.pinned .sidebar-handle { display: none; }

.sidebar-panel {
  position: absolute; top: 0; right: calc(-1 * (var(--sidebar-w) - var(--peek))); bottom: 0;
  width: var(--sidebar-w);
  background: var(--menu-bg);
  backdrop-filter: blur(24px) saturate(1.2);
  -webkit-backdrop-filter: blur(24px) saturate(1.2);
  /* В свёрнутом виде видна только левая кромка; рамка задана целиком, но
     прозрачной, чтобы при раскрытии в «остров» анимировался лишь цвет. */
  border: 1px solid transparent;
  border-left-color: var(--fg-a08);
  border-radius: 0;
  display: flex; flex-direction: column;
  gap: 0;
  overflow: hidden;
  isolation: isolate;
  transition: top var(--transition-med), right var(--transition-med),
    bottom var(--transition-med), border-radius var(--transition-med),
    border-color var(--transition-med), box-shadow var(--transition-med),
    background .35s, backdrop-filter .35s;
}
/* Раскрытая панель — плавающий «остров»: отступы от краёв, скругление и
   приподнятая тень, как у окна сцены. */
.sidebar.open .sidebar-panel {
  top: var(--island-gap); right: var(--island-gap); bottom: var(--island-gap);
  border-radius: var(--window-radius);
  border-color: var(--fg-a05);
  box-shadow: 0 30px 70px -30px rgba(0,0,0,.7);
}
.sidebar.open:not(.pinned) .sidebar-panel {
  backdrop-filter: blur(32px) saturate(1.5);
  -webkit-backdrop-filter: blur(32px) saturate(1.5);
}

/* Orb blobs */
.sidebar-panel::before,
.sidebar-panel::after {
  content: '';
  position: absolute;
  border-radius: 50%;
  filter: blur(60px);
  opacity: 0.45;
  pointer-events: none;
  z-index: -1;
  background: var(--menu-orb);
  transition: background .6s;
}
.sidebar-panel::before { width: 200px; height: 200px; top: -60px; right: -60px; }
.sidebar-panel::after  { width: 160px; height: 160px; bottom: 60px; left: -40px; opacity: 0.3; }

.sidebar-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 18px 16px 14px;
  flex-shrink: 0;
}
.sidebar-brand { display: flex; align-items: center; gap: 10px; min-width: 0; }

.sidebar-logo {
  width: 36px; height: 36px; border-radius: 9px;
  background: var(--menu-orb);
  color: var(--menu-orb-fg);
  display: grid; place-items: center;
  font-size: 16px; font-weight: 700;
  flex-shrink: 0; overflow: hidden;
  position: relative;
  transition: background .6s, color .3s;
}
.sidebar-logo .ico-slot {
  position: absolute; inset: 0;
  display: grid; place-items: center;
  opacity: 0; transform: scale(0.82); filter: blur(4px);
  transition:
    opacity .45s cubic-bezier(.4,0,.2,1),
    transform .5s cubic-bezier(.4,0,.2,1),
    filter .45s cubic-bezier(.4,0,.2,1);
  pointer-events: none;
}
.sidebar-logo .ico-slot.visible { opacity: 1; transform: scale(1); filter: blur(0); }
.sidebar-logo .ico-slot img { width: 100%; height: 100%; object-fit: cover; }
.sidebar-brand-text { min-width: 0; }
.sidebar-title {
  font-size: 14px; font-weight: 700;
  color: var(--fg); letter-spacing: -.01em;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.sidebar-subtitle {
  font-size: 11px; color: var(--fg-a55);
  white-space: nowrap; margin-top: 1px;
}

.sidebar-pin {
  width: 30px; height: 30px; border-radius: 7px;
  display: grid; place-items: center;
  color: var(--fg-a40); flex-shrink: 0;
  transition: background var(--transition-fast), color var(--transition-fast);
}
.sidebar-pin:hover { background: var(--fg-a08); color: var(--fg); }
.sidebar-pin .icon-collapse { display: none; }
.sidebar.pinned .sidebar-pin .icon-pin     { display: none; }
.sidebar.pinned .sidebar-pin .icon-collapse { display: inline; }

/* ===== TAG CLOUD ===== */
.tag-cloud-wrap {
  padding: 4px 14px 8px;
  flex-shrink: 0;
}

.tag-cloud {
  position: relative;
  display: flex; flex-wrap: wrap; gap: 5px;
  padding: 3px;
}

/* Sliding indicator for the "All" chip. JS sets top/left/width/height to the
   active chip's own box, so it tracks a single chip even when the chips wrap
   onto a second row (otherwise it would span the full cloud height and bleed
   over the row below). Opaque, like the segmented control in the 3d section —
   the chip label rides on top of it. */
.filter-indicator {
  position: absolute;
  top: 3px; height: 24px;
  border-radius: 7px;
  background: var(--menu-orb);
  opacity: 1;
  pointer-events: none;
  transition: left .2s cubic-bezier(.2,.8,.2,1), top .2s cubic-bezier(.2,.8,.2,1),
              width .2s cubic-bezier(.2,.8,.2,1), height .2s cubic-bezier(.2,.8,.2,1),
              opacity .2s, background .35s;
  z-index: 0;
}

.tag-chip {
  position: relative; z-index: 1;
  padding: 4px 9px;
  border-radius: 7px;
  font-size: 11px; font-weight: 500;
  color: var(--fg-a75);
  background: var(--fg-a05);
  border: 1px solid var(--fg-a05);
  transition: background var(--transition-fast), color var(--transition-fast),
              border-color var(--transition-fast);
  cursor: pointer;
}
.tag-chip:hover {
  background: var(--fg-a08);
  color: var(--fg);
}
.tag-chip.active {
  background: transparent;
  border-color: transparent;
  color: var(--menu-orb-fg);
  font-weight: 600;
}
/* The sliding pill only ever tracks the "all" chip (the filter is multi-select,
   one pill cannot cover several chips), so every other active tag paints the
   same pill itself — without it the label would sit on bare sidebar and turn
   unreadable on light scenes. */
.tag-chip.active:not([data-tag="all"]) {
  background: var(--menu-orb);
  border-color: var(--menu-orb);
}

/* ===== SIDEBAR CONTENT ===== */
.sidebar-meta {
  display: flex; justify-content: space-between; align-items: center;
  padding: 4px 16px 6px;
  font-size: 11px; color: var(--fg-a40);
  letter-spacing: .04em; text-transform: uppercase;
  flex-shrink: 0;
}
.sidebar-list {
  flex: 1;
  overflow-y: auto; overflow-x: hidden;
  padding: 4px 8px 8px;
  display: flex; flex-direction: column; gap: 2px;
}
/* Подвал острова: слева — действия, языковая пилюля прижата к правому краю. */
.sidebar-footer {
  flex-shrink: 0;
  padding: 10px 12px;
  border-top: 1px solid var(--fg-a05);
}
/* На мобильном панель действий переезжает в шапку — подвал без неё не должен
   оставлять полосу (:empty не сработал бы из-за пробельных узлов). */
.sidebar-footer:not(:has(.action-bar)) { display: none; }
.sidebar-footer .action-bar { display: flex; width: 100%; gap: 6px; }
.sidebar-footer .lang-selector { margin-left: auto; }
/* Панель обрезается overflow:hidden, поэтому список языков открывается вверх
   и остаётся внутри острова; закрытым он спрятан вниз, а не вверх. */
.sidebar-footer .lang-dropdown {
  top: auto; bottom: calc(100% + 10px);
  transform-origin: bottom right;
  transform: translateY(6px) scale(.98);
}

/* Scene list items */
.scene-item {
  display: flex; align-items: center; gap: 14px;
  padding: 10px;
  border-radius: 12px;
  color: var(--fg-a75);
  width: 100%;
  text-align: left;
  transition: background var(--transition-fast), color var(--transition-fast);
}
.scene-item:hover { background: var(--fg-a05); color: var(--fg); }
.scene-item.active {
  background: color-mix(in srgb, var(--menu-orb) 14%, var(--fg-a05));
  color: var(--fg);
}

.scene-thumb {
  width: 82px; height: 54px;
  border-radius: 8px;
  background: var(--sc-bg, #0a0a14);
  outline: 1px solid var(--fg-a08);
  flex-shrink: 0; overflow: hidden;
  position: relative;
  transition: outline .2s;
}
.scene-item.active .scene-thumb {
  outline: 1.5px solid var(--fg-a55);
  outline-offset: 1px;
}
.scene-thumb img {
  width: 100%; height: 100%; object-fit: cover;
  display: block;
}
.scene-thumb-fallback {
  position: absolute; inset: 0;
  display: grid; place-items: center;
  font-size: 22px;
}
.scene-thumb-overlay {
  position: absolute; inset: 0;
  background: linear-gradient(180deg, transparent 40%, rgba(0,0,0,.35) 100%);
}
.scene-thumb.intro {
  background: linear-gradient(135deg, var(--sc-bg, #0a0a14), color-mix(in srgb, var(--sc-accent, #6366f1) 30%, var(--sc-bg, #0a0a14)));
}
.intro-label {
  position: absolute; inset: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 2px; font-size: 10px; font-weight: 600;
  color: var(--fg-a55); letter-spacing: .1em; text-transform: uppercase;
}
.intro-mark { font-size: 18px; }

.scene-info { min-width: 0; flex: 1; }
.scene-name {
  font-size: 12px; font-weight: 600;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  color: inherit;
}
.scene-num {
  font-size: 10px;
  font-family: var(--mono);
  color: var(--fg-a40); letter-spacing: .04em;
  margin-top: 2px;
}

/* Hidden by filter */
.scene-item.hidden, .dock-item.hidden { display: none; }
.scene-item, .dock-item {
  animation: filter-in .28s cubic-bezier(.2,.8,.2,1) both;
}
@keyframes filter-in {
  from { opacity: 0; transform: translateY(5px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* ===== MOBILE DOCK ===== */
.mobile-dock {
  display: none;
  position: fixed; bottom: 0; left: 0; right: 0;
  height: var(--dock-h, 118px);
  z-index: 20;
  background: var(--surface);
  backdrop-filter: blur(20px) saturate(1.2);
  -webkit-backdrop-filter: blur(20px) saturate(1.2);
  border-top: 1px solid var(--fg-a08);
  padding: 10px 0 14px;
}

.mobile-dock-track {
  display: flex; align-items: flex-start; gap: 8px;
  overflow-x: auto; overflow-y: hidden;
  padding: 0 12px;
  height: 100%;
  scroll-snap-type: x mandatory;
}
.dock-item {
  display: flex; flex-direction: column; align-items: center; gap: 4px;
  flex-shrink: 0;
  scroll-snap-align: center;
  padding: 2px;
  border-radius: 10px;
  transition: background var(--transition-fast);
}
.dock-item:hover { background: var(--fg-a05); }
.dock-item.active { background: color-mix(in srgb, var(--menu-orb) 14%, var(--fg-a05)); }

.dock-thumb {
  width: 56px; height: 56px; border-radius: 10px;
  background: var(--sc-bg, #0a0a14);
  border: 1px solid var(--fg-a08);
  overflow: hidden; flex-shrink: 0;
  display: grid; place-items: center;
  font-size: 20px;
}
.dock-thumb.intro {
  background: linear-gradient(135deg, var(--sc-bg, #0a0a14), color-mix(in srgb, var(--sc-accent, #6366f1) 30%, var(--sc-bg, #0a0a14)));
}
.dock-thumb img { width: 100%; height: 100%; object-fit: cover; }
.dock-name {
  font-size: 9px; font-weight: 500; color: var(--fg-a55);
  max-width: 60px; text-align: center;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* ===== SHORTCUTS MODAL ===== */
.modal-backdrop {
  position: fixed; inset: 0;
  z-index: 60;
  background: rgba(0, 0, 0, 0.5);
  backdrop-filter: blur(8px);
  display: grid;
  place-items: center;
  opacity: 0;
  visibility: hidden;
  scale: 1.1;
  filter: blur(8px);
  transition: opacity .18s, visibility .18s, transform .25s, scale .25s, filter .25s;
}
.modal-backdrop.open {
  opacity: 1;
  visibility: visible;
  scale: 1;
  filter: blur(0);
}

.modal {
  background: var(--surface-solid);
  border: 1px solid var(--fg-a12);
  border-radius: 18px;
  padding: 24px;
  width: min(400px, calc(100vw - 32px));
  box-shadow: 0 24px 64px rgba(0,0,0,.5);
}
.modal-head {
  display: flex; justify-content: space-between; align-items: flex-start;
  margin-bottom: 20px;
}
.modal-eyebrow {
  font-size: 10px; font-weight: 600; letter-spacing: .15em;
  text-transform: uppercase; color: var(--fg-a40);
  margin-bottom: 4px;
}
.modal-title { font-size: 20px; font-weight: 700; color: var(--fg); }
.modal-close {
  width: 30px; height: 30px; border-radius: 8px;
  display: grid; place-items: center;
  color: var(--fg-a55);
  transition: background var(--transition-fast), color var(--transition-fast);
}
.modal-close:hover { background: var(--fg-a08); color: var(--fg); }

.shortcut-list { display: flex; flex-direction: column; gap: 6px; }
.shortcut-row {
  display: flex; justify-content: space-between; align-items: center;
  padding: 8px 10px; border-radius: 8px;
  background: var(--fg-a05);
  font-size: 13px; color: var(--fg-a75);
}
.shortcut-row kbd {
  font-family: var(--mono);
  font-size: 11px; color: var(--fg-a55);
  background: var(--fg-a08);
  border: 1px solid var(--fg-a12);
  border-radius: 5px;
  padding: 2px 7px;
}

/* ===== SCENE HELP PANEL =====
   Anchored under the tips button in the header, so it opens downward. */
.scene-help-panel {
  position: absolute;
  top: calc(100% + 10px); right: 0; left: auto; bottom: auto;
  width: 320px; max-width: calc(100vw - 2 * var(--shell-gap));
  background: var(--surface-solid);
  border: 1px solid var(--fg-a12);
  border-radius: 14px;
  padding: 14px 16px 16px;
  box-shadow: 0 24px 60px -18px rgba(0,0,0,.55);
  transform-origin: top right;
  transform: scale(.92); opacity: 0; pointer-events: none;
  display: block;
  z-index: 40;
  transition: opacity .2s cubic-bezier(.2,.8,.2,1), transform .22s cubic-bezier(.2,.8,.2,1);
}
.scene-help.open .scene-help-panel { opacity: 1; transform: scale(1); pointer-events: auto; }

.scene-help-head {
  display: flex; justify-content: space-between; align-items: center;
  margin-bottom: 10px;
}
.scene-help-title { font-size: 13px; font-weight: 600; color: var(--fg); }
.scene-help-close {
  width: 24px; height: 24px; border-radius: 6px;
  display: grid; place-items: center;
  color: var(--fg-a40);
  transition: background var(--transition-fast), color var(--transition-fast);
}
.scene-help-close:hover { background: var(--fg-a08); color: var(--fg); }

.scene-help-list {
  list-style: none; display: flex; flex-direction: column; gap: 6px;
}
.scene-help-list li {
  font-size: 12px; line-height: 1.55; color: var(--fg-a75);
  padding-left: 12px; position: relative;
}
.scene-help-list li::before {
  content: '→';
  position: absolute; left: 0;
  color: var(--scene-accent);
  font-size: 10px;
}

/* ===== TOAST ===== */
.toast {
  position: fixed;
  bottom: calc(var(--stage-bottom, 0px) + var(--shell-gap) + 18px);
  left: 50%;
  transform: translateX(-50%) translateY(20px);
  background: var(--surface-solid);
  border: 1px solid var(--fg-a12);
  border-radius: 12px;
  padding: 10px 16px;
  font-size: 13px; font-weight: 500;
  color: var(--fg);
  z-index: 100;
  opacity: 0; pointer-events: none;
  transition: opacity .22s, transform .22s cubic-bezier(.2,.8,.2,1);
  box-shadow: 0 8px 24px rgba(0,0,0,.3);
  max-width: calc(100vw - 32px);
}
.toast.show {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
  pointer-events: auto;
}
.toast--copy {
  display: flex; align-items: flex-start; gap: 10px;
}
.toast-icon { flex-shrink: 0; margin-top: 1px; }
.toast-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.toast-label { font-weight: 600; }
.toast-url {
  font-size: 11px;
  font-family: var(--mono);
  color: var(--fg-a55);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  max-width: 240px;
}

/* Scene credit in the help panel */
.scene-help-list li.scene-help-credit {
  margin-top: 8px; padding-top: 8px; padding-left: 0;
  border-top: 1px solid var(--fg-a08);
  color: var(--fg-a40); font-size: 11px;
}
.scene-help-list li.scene-help-credit::before { content: none; }

/* ===== КАСТОМНАЯ ПОДСКАЗКА =====
   Единственный элемент на весь документ; позиционируется из JS по
   getBoundingClientRect цели и никогда не выходит за края экрана. */
.ui-tip {
  position: fixed;
  left: 0; top: 0;
  z-index: 120;
  max-width: min(280px, calc(100vw - 16px));
  background: var(--surface-solid);
  border: 1px solid var(--fg-a08);
  border-radius: 8px;
  padding: 6px 10px;
  font-size: 11px; font-weight: 500;
  color: var(--fg);
  box-shadow: 0 12px 32px -14px rgba(0,0,0,.5);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  pointer-events: none;
  opacity: 0;
  transform: translateY(4px) scale(.97);
  transition: opacity .18s cubic-bezier(.2,.8,.2,1), transform .18s cubic-bezier(.2,.8,.2,1);
}
/* Подсказка, перевёрнутая выше цели, въезжает сверху вниз. */
.ui-tip.above { transform: translateY(-4px) scale(.97); }
.ui-tip.visible { opacity: 1; transform: translateY(0) scale(1); }

/* ===== MOBILE ===== */
@media (max-width: 760px) {
  :root { --shell-gap: 10px; --header-h: 58px; --window-radius: 12px; }
  .app-header { right: 0; gap: 8px; padding: 0 var(--shell-gap); }
  .scene-label { gap: 8px; }
  .lab-home, .scene-label-icon { width: 34px; height: 34px; }
  .lab-home { grid-template-columns: 34px minmax(0, 0fr); }
  .lab-home:hover, .lab-home:focus-visible { grid-template-columns: 34px minmax(0, 1fr); }
  .scene-label-name .label-slot { font-size: 12px; max-width: 40vw; }
  .action-btn, .scene-help-btn, .scene-open-btn { width: 32px; height: 32px; border-radius: 9px; }
  /* The language pill is text-sized, not a square. */
  .action-pill { width: auto; }
  #actFullscreen, #actShortcuts { display: none; }
  .sidebar { display: none; }
  .mobile-dock { display: block; }
  .nav-arrow { width: 44px; height: 44px; }
  .nav-tip { display: none; }
}

/* ===== HIDE THE INTERFACE =====
   Один переключатель убирает все слои вокруг сцены, потому что её собственные
   элементы управления часто живут под нашими: окно становится полноэкранным,
   шапка прячется целиком, а в углу остаётся только плавающая кнопка возврата.
   Сам iframe не трогаем. */
.ui-toggle .icon-show { display: none; }
.ui-toggle[aria-pressed="true"] .icon-hide { display: none; }
.ui-toggle[aria-pressed="true"] .icon-show { display: block; }
.ui-toggle[aria-pressed="true"] {
  background: color-mix(in srgb, var(--menu-orb) 20%, var(--fg-a08));
  color: var(--fg);
}

:root.ui-hidden { --header-h: 0px; --shell-gap: 0px; --window-radius: 0px; }
:root.ui-hidden .stage { border-color: transparent; box-shadow: none; }
:root.ui-hidden .app-header { display: none; }
/* Обнулённый --window-radius нужен полноэкранной сцене; плавающий «остров»
   сохраняет своё скругление. */
:root.ui-hidden .sidebar.open .sidebar-panel { border-radius: 16px; }

/* Плавающая кнопка возврата интерфейса: шапки больше нет, поэтому нужен
   отдельный полупрозрачный элемент поверх сцены. Строится из JS. */
.ui-restore {
  position: fixed;
  top: 10px; right: 10px;
  z-index: 45;
  width: 36px; height: 36px;
  display: none;
  align-items: center; justify-content: center;
  border-radius: 10px;
  border: 1px solid var(--fg-a12);
  background: var(--surface);
  backdrop-filter: blur(20px) saturate(1.2);
  -webkit-backdrop-filter: blur(20px) saturate(1.2);
  color: var(--fg);
  opacity: .45;
  transition: opacity var(--transition-fast), background .2s, border-color .2s;
}
:root.ui-hidden .ui-restore { display: inline-flex; }
.ui-restore:hover,
.ui-restore:focus-visible { opacity: 1; background: var(--fg-a12); }

/* Ромб-ручка центрируется по строке шапки — при --header-h: 0 он вылез бы за
   верхний край прямо под кнопку возврата. Опускаем его ниже неё, чтобы у
   сайдбара оставался заметный вход. */
:root.ui-hidden .sidebar-handle { top: 54px; }

/* visibility, not opacity alone: a fully transparent overlay would still eat
   the clicks meant for the scene underneath. */
:root.ui-hidden .nav-arrow,
:root.ui-hidden .mobile-dock {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity var(--transition-fast) ease, visibility 0s var(--transition-fast);
}

/* ===== SECTION TYPOGRAPHY =====
   Unbounded shouts the headlines, Nunito keeps the copy friendly and
   Roboto Mono handles the readouts. Declared in shared/fonts/css/interactive.css. */
.sidebar-title,
.modal-title,
.modal-eyebrow,
.scene-help-title,
.toast-label,
.intro-label,
.scene-label-name .label-slot,
.action-btn.action-pill {
  font-family: var(--display);
  font-weight: var(--display-weight);
}

/* Unbounded is extremely wide: every headline needs a size step down and
   negative tracking, or the single-line labels ellipsis out. */
.sidebar-title { font-size: 12px; letter-spacing: -.02em; }
.scene-label-name .label-slot { font-size: 13px; letter-spacing: -.02em; }
.modal-title { font-size: 17px; letter-spacing: -.03em; }
.modal-eyebrow { font-size: 9px; letter-spacing: .1em; }
.intro-label { letter-spacing: .06em; }

/* Nunito's rounded terminals make it read a shade smaller than Inter did. */
.sidebar-subtitle,
.tag-chip { font-size: 12px; }
