/* THE EDITOR WORKSPACE — §1–§6, §10–§13, §23, §25, §32, §42.
 *
 * ONE screen that fills the viewport and never scrolls as a page. Everything
 * that can be too long for its box scrolls INSIDE its box; the player and the
 * timeline are fixed rows of the grid and therefore cannot be scrolled away,
 * which is the whole of §4 and §10.
 *
 * The four sizes the user controls live in CSS variables on `.ed`, written by
 * the drag in `editor_shell.js` and read back from localStorage on open. There
 * is no second layout for 9:16 — the same grid with different remembered
 * numbers, plus one class, which is what «hardcoded хоёр тусдаа editor битгий
 * хий» asks for.
 */

/* THE PAGE DOES NOT SCROLL WHEN THE EDITOR IS UP. `.main` is the app's own
   scroll container and it has padding; both are wrong for a workspace that is
   supposed to be exactly one viewport tall. */
.main.ed-host { padding: 0; overflow: hidden; height: 100vh; }
.app:has(.ed) { overflow: hidden; }

/* THE PLAYER IS A COLUMN, NOT A CELL.
 *
 * It used to be the last cell of `.ed-main`, which is the row ABOVE the
 * timeline — so the picture stopped where the timeline began and the strip of
 * screen to the right of the timeline was dead space, the gap the reference
 * marks in red. The player is now its own grid COLUMN spanning every row below
 * the top bar, and the timeline occupies only the columns the text panels sit
 * over. Nothing gained a fixed height: the stage is `1fr` of the same rows it
 * always was, it simply spans three of them instead of one. */
.ed {
  /* §24 — TALL ENOUGH FOR ITS SIX ROWS. 258px held the tabs, the toolbar, the
     ruler and four of the six tracks, so the video row — the one with the
     filmstrip on it, the row this release is about — was below the fold on
     every fresh open and had to be found by scrolling. Six 44px rows, a 26px
     ruler, the tab strip and the tool bar come to ~350. The user still drags
     it wherever they like and the number is remembered. */
  --ed-c1: 148px; --ed-c2: 420px; --ed-c3: 520px; --ed-tl: 352px;
  --ed-top: 46px;
  height: 100vh; min-height: 0; display: grid;
  /* minmax(0, 1fr) AND NOT `auto`. A grid column sized `auto` is max-content,
     so a timeline zoomed to a hundred metres widened the column it lives in —
     the scroller grew with its own content, never scrolled, and «fit» had
     nothing to fit into because the viewport was as wide as the film. */
  grid-template-columns: minmax(0, 1fr) 7px var(--ed-c3);
  grid-template-rows: var(--ed-top) minmax(0, 1fr) 7px var(--ed-tl);
  background: var(--bg); color: var(--ink);
  position: relative; overflow: hidden;
}
.ed-top { grid-column: 1 / -1; grid-row: 1; }
.ed-main { grid-column: 1; grid-row: 2; }
.ed-hgrip { grid-column: 1; grid-row: 3; }
.ed-tl { grid-column: 1; grid-row: 4; }
.ed-grip.ed-stagegrip { grid-column: 2; grid-row: 2 / 5; }
.ed-stage { grid-column: 3; grid-row: 2 / 5; }

/* ── top bar (§1.1) ───────────────────────────────────────────────────── */

/* §39 — THE EDITOR'S TOP SHELL IS PART OF THE SAME PRODUCT.
 *
 * Not a redesign: the bar keeps its layout, its controls and every behaviour
 * it had. What changes is which palette it reads — `ashd.css`'s tokens rather
 * than three hard-coded greys — so a user walking from the dashboard into a
 * project does not walk from a 2026 product into an admin panel. The fallbacks
 * are the previous literals, so the editor still renders correctly on any page
 * that loads `editor.css` without the design system. */
.ed-top {
  display: flex; align-items: center; gap: 10px; padding: 0 10px;
  border-bottom: 1px solid var(--a-border, var(--line)); min-width: 0;
  background: linear-gradient(180deg, rgba(14,18,32,.96), rgba(8,11,20,.96));
}
.ed-grow { flex: 1 1 auto; }
.ed-menu {
  border: 1px solid var(--a-border, var(--line));
  background: var(--a-surface, var(--panel2)); color: var(--a-text, var(--ink));
  border-radius: var(--a-r-sm, 8px); padding: 5px 11px; font-size: 12.5px; flex: none;
}
.ed-menu:hover { border-color: var(--a-border-strong, #3a4560); }
/* §13 — IMPORT SITS BESIDE THE MENU, and is styled like it rather than like a
   primary action: bringing a file in is navigation, not a commitment. */
.ed-import {
  border: 1px solid var(--line); background: var(--panel2); color: var(--ink);
  border-radius: 8px; padding: 5px 11px; font-size: 12.5px; flex: none;
}
.ed-import:hover { border-color: var(--accent); color: #fff; }
.ed-file { display: none; }
.ed-save { font-size: 11.5px; color: var(--muted); flex: none; min-width: 108px; }
.ed-save.saving { color: var(--amber); }
.ed-save.saved { color: var(--green); }
.ed-save.failed { color: var(--red); }
.ed-name {
  font-size: 12.5px; color: var(--ink); font-weight: 600; flex: none;
  max-width: 190px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.ed-stages { display: flex; gap: 4px; min-width: 0; overflow: hidden; }
.ed-stagebtn {
  border: 1px solid transparent; background: transparent; color: var(--muted);
  border-radius: 7px; padding: 5px 9px; font-size: 12px; white-space: nowrap;
}
.ed-stagebtn:hover { background: #1b1f28; color: var(--ink); }
.ed-stagebtn.on {
  color: #fff; border-color: rgba(34,211,238,.45);
  background: linear-gradient(180deg, rgba(34,211,238,.16), rgba(34,211,238,.05));
}
/* THE TWO THAT ARE NOT STEPS. «Хадмал зэрэгцүүлэх» and «Монгол хэлний чанар»
   are ways of working on the document rather than rungs of the four-step
   sequence beside them, so they carry an icon instead of a number and a rule
   to say where the sequence ends. */
.ed-stagebtn.extra { margin-left: 2px; }
.ed-stagebtn.extra:first-of-type { margin-left: 8px; }
.ed-stages .ed-stagebtn.extra { border-left: 1px solid var(--line); border-radius: 0 7px 7px 0; }
.ed-clip select {
  background: var(--panel2); color: var(--ink); border: 1px solid var(--line);
  border-radius: 7px; padding: 5px 8px; font-size: 12px; max-width: 220px;
}
.ed-export {
  border: 1px solid transparent; color: #05131a;
  background: linear-gradient(100deg, var(--a-cyan, #5b8cff),
              var(--a-violet, #7c5cff) 58%, var(--a-magenta, #7c5cff));
  border-radius: var(--a-r-sm, 8px); padding: 6px 14px; font-size: 12.5px;
  font-weight: 700; flex: none;
}
.ed-export:hover { filter: brightness(1.08); }

/* ── the five panels (§3) ─────────────────────────────────────────────── */

/* Rail | list | Details. Details is what is LEFT — `minmax(0, 1fr)` and not a
   third fixed width — so dragging the list/Details divider to the right takes
   room from Details and never from the picture. The floors (a list that stays
   readable, a Details that stays a column rather than a sliver) are enforced by
   the drag in `editor_shell.js`, because a `minmax(140px, …)` here would make
   the row overflow on a narrow window instead of re-fitting. */
.ed-main {
  display: grid; min-height: 0; min-width: 0;
  grid-template-columns: var(--ed-c1) 7px var(--ed-c2) 7px minmax(0, 1fr);
}
.ed-rail, .ed-list, .ed-details, .ed-stage { min-width: 0; min-height: 0; }

/* THE GRIPS. Seven pixels of hit area with a one-pixel line drawn in it: a
   divider you have to aim at is a divider nobody drags. */
.ed-grip {
  cursor: col-resize; position: relative; background: transparent;
}
.ed-grip::after {
  content: ""; position: absolute; inset: 0 3px; background: var(--line);
}
.ed-grip:hover::after, .ed-grip.on::after { background: var(--accent); }
.ed-hgrip {
  cursor: row-resize; position: relative; background: transparent;
}
.ed-hgrip::after {
  content: ""; position: absolute; inset: 3px 0; background: var(--line);
}
.ed-hgrip:hover::after, .ed-hgrip.on::after { background: var(--accent); }

/* ── rail (§8) ────────────────────────────────────────────────────────── */

.ed-rail {
  border-right: 1px solid var(--line); background: #12141a;
  padding: 8px 7px; display: flex; flex-direction: column; gap: 5px;
  overflow-y: auto;
}
.ed-count {
  display: flex; flex-direction: column; align-items: flex-start; gap: 1px;
  border: 1px solid var(--line); background: var(--panel); color: var(--ink);
  border-radius: 9px; padding: 6px 9px; text-align: left; width: 100%;
}
.ed-count:hover { border-color: #3a4560; }
.ed-count.on { border-color: var(--accent); background: #1c2333; }
.ed-count b { font-size: 17px; font-variant-numeric: tabular-nums; line-height: 1.1; }
.ed-count span { font-size: 10.5px; color: var(--muted); }
.ed-count.g b { color: var(--green); }
.ed-count.w b { color: var(--amber); }
.ed-count.r b { color: var(--red); }
.ed-railgap { flex: 1 1 auto; min-height: 8px; }

/* §8 — ○ not yet · ● running · ✓ done · · could not run. Four tones over one
   shape, because a progress list in five colours is a list nobody reads. */
.ed-srcstep.todo { color: var(--muted); opacity: .55; }
.ed-srcstep.live { color: var(--accent); font-weight: 600; }

/* §2 — the source details drawer. Anchored to the rail rather than centred:
   it explains the panel it opens from and belongs beside it. */
/* `.ed-overlaypanel.ed-srcpanel`, not `.ed-srcpanel`: the base rule sets `top`
   and lives further down this file, so at equal specificity it won this and the
   drawer stretched the whole height of the window. */
.ed-overlaypanel.ed-srcpanel {
  left: 8px; top: auto; bottom: 12px; width: 268px; padding: 10px 12px;
  font-size: 11.5px; max-height: 60vh; overflow: auto; min-width: 0;
}
.ed-srdhead {
  display: flex; align-items: center; justify-content: space-between;
  font-weight: 700; margin-bottom: 6px;
}
.ed-srdstate { margin-bottom: 6px; color: var(--muted); }
.ed-srdstate b { color: var(--text); }
.ed-srdnote {
  margin: 0 0 8px; padding: 6px 8px; border-radius: 6px;
  background: var(--panel2); color: var(--muted); line-height: 1.35;
}
.ed-srdrow {
  display: flex; justify-content: space-between; gap: 10px; padding: 3px 0;
  border-top: 1px solid var(--line); color: var(--muted);
}
.ed-srdrow b { color: var(--text); font-variant-numeric: tabular-nums; }
.ed-srdfoot { margin-top: 8px; text-align: right; }

/* §17 — THE THREE-WAY SUMMARY AND §14's EVIDENCE VIEWER.
   The chips are a filter over one panel: a user checking whether an automatic
   fix was right has not left the timeline, and a route change would lose where
   they were standing. */
.ed-srdsum { display: flex; gap: 6px; margin: 8px 0 4px; flex-wrap: wrap; }
.ed-srdchip {
  flex: 1 1 auto; min-width: 0; padding: 5px 8px; border-radius: 7px;
  border: 1px solid var(--line); background: var(--panel2); color: var(--muted);
  font-size: 11px; cursor: pointer; text-align: left; white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis;
}
.ed-srdchip b { color: var(--text); margin-left: 4px; font-variant-numeric: tabular-nums; }
.ed-srdchip.on { border-color: var(--accent); background: var(--panel); color: var(--text); }
.ed-srdbreak {
  display: flex; flex-wrap: wrap; gap: 4px 10px; margin: 2px 0 6px;
  color: var(--muted); font-size: 11px;
}
.ed-srdbreak b { color: var(--text); font-variant-numeric: tabular-nums; }
.ed-srdempty { color: var(--muted); padding: 8px 0; font-size: 11px; }
/* Bounded and scrollable: the drawer holds the state panel above it, and a
   long list of fixes must not push that off the screen. */
.ed-srdfixes { max-height: 46vh; overflow-y: auto; margin: 4px 0 2px; }
.ed-afcard {
  border: 1px solid var(--line); border-radius: 8px; padding: 8px;
  margin-bottom: 6px; background: var(--panel2);
}
.ed-afhead {
  display: flex; justify-content: space-between; gap: 8px; align-items: baseline;
  margin-bottom: 5px;
}
.ed-afhead .muted { color: var(--muted); font-variant-numeric: tabular-nums; font-size: 11px; }
.ed-afrow { display: flex; gap: 8px; padding: 2px 0; font-size: 11px; line-height: 1.35; }
.ed-afrow > span { flex: 0 0 58px; color: var(--muted); }
.ed-afrow > i, .ed-afrow > b { flex: 1 1 auto; min-width: 0; word-break: break-word; }
.ed-afrow > i { font-style: normal; color: var(--muted); }
.ed-afrow > b { color: var(--text); }
.ed-aftags { display: flex; flex-wrap: wrap; gap: 4px; margin: 6px 0 4px; }
.ed-afok, .ed-afwarn {
  padding: 1px 6px; border-radius: 999px; font-size: 10px; white-space: nowrap;
}
.ed-afok { background: var(--panel); color: var(--muted); border: 1px solid var(--line); }
.ed-afwarn { background: var(--warn-bg, #4a3a12); color: var(--warn, #f5c451); }
.ed-afwhy { color: var(--muted); font-size: 11px; line-height: 1.35; margin-bottom: 6px; }
.ed-afacts { display: flex; gap: 5px; justify-content: flex-end;
             align-items: center; flex-wrap: wrap; }
.ed-afnote { color: var(--muted); font-size: 10px; line-height: 1.3;
             flex: 1 1 100%; text-align: left; }
/* §26 — the separator above the two always-available actions. Fixed, not
   growing: the panel above it is the point and must keep its room. */
.ed-railgap.sm { flex: 0 0 10px; min-height: 10px; }
.ed-railacts { display: flex; flex-direction: column; gap: 5px; }
.ed-railacts .btn { width: 100%; text-align: center; }

/* ── list (§35) ───────────────────────────────────────────────────────── */

.ed-list {
  border-right: 1px solid var(--line); display: flex; flex-direction: column;
  background: var(--bg);
}
.ed-listhead {
  display: flex; align-items: baseline; gap: 8px; padding: 7px 10px;
  border-bottom: 1px solid var(--line); font-size: 12.5px; flex: none;
}
.ed-listhead .muted { color: var(--muted); font-size: 11px; }
/* §30 — the full list's search. Last in the row and allowed to shrink, so on a
   narrow panel it gives way to the title and the count rather than pushing
   either of them out. */
.ed-listsearch {
  margin-left: auto; min-width: 60px; max-width: 180px; flex: 0 1 140px;
  padding: 2px 7px; font-size: 11px; border-radius: 6px;
  border: 1px solid var(--line); background: var(--panel2); color: inherit;
}
.ed-listsearch:focus { outline: 1px solid var(--accent); outline-offset: 0; }
.ed-busy { color: var(--amber); font-size: 11px; margin-left: auto; }
.ed-listport { flex: 1 1 auto; min-height: 0; overflow-y: auto; position: relative; }
.ed-listpad { position: relative; }
.ed-listrows { position: absolute; inset: 0; }
.ed-row {
  position: absolute; left: 0; right: 0; height: 46px;
  display: flex; align-items: center; gap: 8px; padding: 0 10px;
  border-bottom: 1px solid var(--line); cursor: pointer;
}
.ed-row:hover { background: #1a1f29; }
.ed-row.sel { background: #232c3f; }
.ed-row.warn { box-shadow: inset 2px 0 0 var(--amber); }
.ed-rown { color: var(--muted); font-size: 10.5px; min-width: 34px; flex: none; }
.ed-rowtx { flex: 1 1 auto; min-width: 0; display: grid; gap: 1px; }
.ed-rowtx b { font-size: 12.5px; font-weight: 500;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ed-rowtx i {
  font-style: normal; font-size: 11px; color: var(--muted);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.ed-rowt { color: var(--muted); font-size: 10.5px; flex: none;
  font-variant-numeric: tabular-nums; }
.ed-rowbadge {
  flex: none; font-size: 10px; color: #1b1200; background: var(--amber);
  border-radius: 20px; padding: 2px 7px; max-width: 130px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.ed-rowok { color: var(--green); flex: none; }
/* A verdict that is «decided» is not a warning. Same pill, green, so the eye
   can sweep a language-quality list for what is still open. */
.ed-rowbadge.ok { background: rgba(60, 200, 130, .18); color: var(--green); }
/* The language stage's own block in Details: the detector's verdict, the
   problems it names, and the proposal — if one has already been produced. */
.ed-dlq { display: grid; gap: 6px; margin-top: 8px; padding-top: 8px;
  border-top: 1px solid var(--line); }
.ed-dlqstate { font-size: 12px; color: var(--muted); }
.ed-dlqstate.warn { color: var(--amber); }
.ed-dlqstate.ok { color: var(--green); }
.ed-gaphead {
  position: absolute; left: 0; right: 0; height: 46px; display: flex;
  align-items: center; padding: 0 10px; color: var(--muted); font-size: 11px;
  background: #151922; border-bottom: 1px solid var(--line);
}
.ed-gaprow { box-shadow: inset 2px 0 0 var(--accent2); }

/* ── details (§32) ────────────────────────────────────────────────────── */

.ed-details {
  display: flex; flex-direction: column; background: var(--panel);
  border-right: 1px solid var(--line);
}
/* Squeezed to its floor the labels have nowhere to go, so they stop competing
   for the width the values need. */
.ed-details.tight .ed-dtime { display: grid; gap: 5px; }
.ed-details.tight .ed-dhead { font-size: 11.5px; }
.ed-dhead {
  padding: 7px 10px; border-bottom: 1px solid var(--line); font-size: 12.5px;
  font-weight: 600; display: flex; align-items: center; gap: 8px; flex: none;
}
.ed-dbody { padding: 9px 10px; overflow-y: auto; display: grid; gap: 6px;
  align-content: start; min-height: 0; }
.ed-dempty { padding: 14px 12px; color: var(--muted); font-size: 12px;
  font-style: italic; }
.ed-dk { font-size: 10px; letter-spacing: .06em; text-transform: uppercase;
  color: var(--muted); margin-top: 4px; }
.ed-dsrc { font-size: 12.5px; color: var(--ink); word-break: break-word; }
.ed-dtext {
  width: 100%; background: #10131a; color: var(--ink); border: 1px solid var(--line);
  border-radius: 8px; padding: 7px 9px; font-family: inherit; font-size: 13px;
  resize: vertical;
}
.ed-dtext:focus { outline: none; border-color: var(--accent); }
.ed-dtime { display: flex; gap: 8px; }
.ed-dtime label { flex: 1 1 0; font-size: 10px; color: var(--muted);
  display: grid; gap: 3px; }
.ed-dtime input {
  background: #10131a; color: var(--ink); border: 1px solid var(--line);
  border-radius: 7px; padding: 5px 7px; font-size: 12px; width: 100%;
  font-variant-numeric: tabular-nums;
}
.ed-dissues { display: grid; gap: 4px; }
.ed-dissue {
  font-size: 11.5px; color: #1b1200; background: var(--amber);
  border-radius: 7px; padding: 5px 8px;
}
.ed-dissue.audio { background: #7c5cff; color: #fff; }
.ed-dacts { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 6px; }
.ed-dmeta { font-size: 10.5px; color: var(--muted); margin-top: 4px; }
/* PHASE 5 REPAIR — the seam between a band's own seconds and the style every
   timeline shares. A rule with a label, because the Inspector is now showing
   two things owned by two documents and a user is entitled to know which. */
.ed-dsplit {
  margin: 12px 0 0; padding-top: 9px; border-top: 1px solid var(--line);
  font-size: 10px; letter-spacing: .06em; text-transform: uppercase;
  color: var(--muted);
}
/* `renderControls` writes its own header, which is right when it IS the panel
   and is a second «Blur» under the first one when it is a section of one. The
   rule above already names the section. */
[data-epcontrols] > .ed-dhead { display: none; }
.btn.danger { border-color: #5a2a2a; color: #ffb4b4; }
.btn.danger:hover { border-color: var(--red); }

/* ── stage / player (§5, §25, §26) ────────────────────────────────────── */

.ed-stage {
  display: flex; flex-direction: column; min-width: 0; min-height: 0;
  background: #0b0d12;
}
.ed-screen {
  flex: 1 1 auto; min-height: 0; position: relative;
  display: flex; align-items: center; justify-content: center;
  background: #000; overflow: hidden;
}
/* THE PICTURE KEEPS ITS SHAPE, AND THE ELEMENT FILLS THE PANEL.
 *
 * `object-fit: contain` is what stops a resize squashing a 9:16 film into a
 * 16:9 box — the acceptance line «video aspect ratio эвдрэхгүй».
 *
 * The element is stretched to the panel ON PURPOSE, rather than left at its
 * intrinsic size. Everything drawn over the film — the blur band, ASHD Kino,
 * the Mongolian line — is placed as a fraction of the FRAME, and the frame is
 * computed by fitting the film's shape into the element's box. With `width:
 * auto` a small film left the element smaller than the panel, the frame was
 * computed against the panel, and every overlay was drawn wider than the
 * picture it was supposed to sit on. */
.ed-video { width: 100%; height: 100%; display: block; object-fit: contain; }
/* THE ROUGH MONGOLIAN LINE IS GONE. `.ed-subs` was a second, approximate copy
   of the subtitle drawn by the shell on the stages the picture layer did not
   cover — a different size, a different shadow and a different wrap from the
   one the export produces. The overlay layer draws the real one on every stage
   now, so there is nothing left for a stand-in to do (§1, §36).

   The video track's eye. The PICTURE goes; the element, its size and its
   position do not, so nothing reloads and `currentTime` is untouched. */
.ed.novideo .ed-video { visibility: hidden; }
.ed-mediafail, .ed-medianote {
  position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);
  background: rgba(18, 20, 26, .96); border: 1px solid var(--line);
  border-radius: 12px; padding: 14px 18px; text-align: center; max-width: 78%;
}
.ed-mediafail .muted, .ed-medianote .muted { color: var(--muted); font-size: 12px;
  margin-top: 4px; }
.ed-transport {
  flex: none; display: flex; align-items: center; gap: 8px; padding: 5px 9px;
  border-top: 1px solid var(--line); background: #12141a;
}
.ed-play {
  border: 1px solid var(--line); background: var(--panel2); color: var(--ink);
  border-radius: 7px; width: 30px; height: 26px; font-size: 12px;
}
.ed-time { font-size: 11.5px; color: var(--muted); font-variant-numeric: tabular-nums; }

/* §12 — WHERE YOU ARE OUT OF HOW LONG, and the speed you are going. The
   current position is the loud half because that is the number a user reads
   twenty times a minute; the duration is context. */
.ed-tc { font-size: 11.5px; color: var(--muted); font-variant-numeric: tabular-nums;
  white-space: nowrap; }
.ed-tc b { color: var(--ink); font-weight: 600; }
.ed-speed { display: flex; align-items: center; gap: 3px; }
.ed-speed button {
  border: 1px solid var(--line); background: var(--panel2); color: var(--muted);
  border-radius: 6px; padding: 3px 7px; font-size: 11px;
  font-variant-numeric: tabular-nums;
}
.ed-speed button.on { background: var(--accent); border-color: var(--accent); color: #fff; }
/* THE LIVE RATE, whatever set it. `video_keys.js` steps 1.15 / 1.25 / 1.35 /
   1.50 and none of those is a button here, so a bar that only lit buttons
   would say nothing at all while the film ran at 1.35. */
.ed-rate { font-style: normal; font-size: 11px; color: var(--ink);
  font-variant-numeric: tabular-nums; margin-left: 4px; min-width: 30px; }
/* §22 — [Эх] / [Монгол]: WHICH subtitle the picture draws. Styled as
   the aspect switch is, because it is the same kind of control — one
   of two states, not a thing that hides a layer. */
.ed-aspect, .ed-subsw, .ed-subtrack { display: flex; align-items: center; gap: 3px;
  font-size: 10.5px; color: var(--muted); }
.ed-aspect button, .ed-subsw button, .ed-subtrack button {
  border: 1px solid var(--line); background: var(--panel2); color: var(--muted);
  border-radius: 6px; padding: 3px 8px; font-size: 11px;
}
.ed-aspect button.on, .ed-subsw button.on, .ed-subtrack button.on {
  background: var(--accent); border-color: var(--accent); color: #fff;
}

/* §25 — PLAYBACK HIDES THE EDITING FURNITURE. While the film plays the
   selection ring, the drag handles and the guides go away, so what the user
   checks is what the export will look like. */
.ed.playing .etl-cue.sel, .ed.playing .etl-clip.sel { box-shadow: none; }
.ed.playing .etl-grab { opacity: 0; }
.ed.playing .etl-guide { display: none !important; }

/* ── popovers ─────────────────────────────────────────────────────────── */

.ed-overlaypanel {
  position: absolute; top: calc(var(--ed-top) + 4px); left: 8px; z-index: 40;
  background: #161a22; border: 1px solid var(--line); border-radius: 12px;
  box-shadow: 0 18px 48px rgba(0, 0, 0, .55); min-width: 246px;
  max-height: calc(100vh - var(--ed-top) - 24px); overflow-y: auto;
}
.ed-exportpanel { left: auto; right: 8px; min-width: 288px; }
.ed-menuinner, .ed-exinner { padding: 7px; display: grid; gap: 3px; }
.ed-menuitem {
  display: flex; align-items: center; gap: 10px; width: 100%; text-align: left;
  border: 0; background: transparent; color: var(--ink); border-radius: 8px;
  padding: 8px 10px; font-size: 12.5px;
}
.ed-menuitem:hover { background: #1e2330; }
.ed-menuitem.on { background: #232a3a; color: #fff; }
.ed-menuic { width: 18px; text-align: center; opacity: .85; }
.ed-menusep { display: block; height: 1px; background: var(--line); margin: 5px 8px; }
.ed-exhead {
  display: flex; align-items: center; justify-content: space-between;
  font-weight: 600; font-size: 13px; padding: 4px 6px 8px;
}
.ed-exclose { border: 0; background: transparent; color: var(--muted); font-size: 14px; }
.ed-exsec {
  font-size: 10px; letter-spacing: .06em; text-transform: uppercase;
  color: var(--muted); margin: 8px 6px 3px;
}
.ed-exwin { font-size: 11.5px; color: var(--muted); margin: 0 6px 5px;
  font-variant-numeric: tabular-nums; }
.ed-exnote { font-size: 10.5px; margin: 4px 6px 0; }
.ed-exinner .btn { width: 100%; text-align: left; }
.ed-exwin { font-size: 11px; color: var(--muted); padding: 0 2px 4px; }
.ed-exnote { font-size: 11px; padding: 4px 2px 0; line-height: 1.45; }

/* §13/§14 — THE MEDIA BIN. One row per file, and the row says whether the file
   was imported or is the project's own — because «✕» must not offer to remove
   the film the project was made from. */
.ed-importpanel { left: 8px; right: auto; min-width: 320px; max-width: 380px; }
.ed-binrow {
  display: flex; align-items: center; gap: 6px; padding: 4px 6px;
  border: 1px solid var(--line); border-radius: 7px; background: var(--panel2);
  font-size: 11.5px; min-width: 0;
}
.ed-binrow.bad { border-color: var(--red); }
.ed-binrow:hover { border-color: var(--accent); }
.ed-binname {
  flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis;
  white-space: nowrap; color: var(--ink);
}
.ed-binmeta { flex: none; color: var(--muted); font-size: 10.5px; }
.ed-binrow .btn.sm { width: auto; flex: none; padding: 2px 6px; font-size: 10.5px; }
.ed-binempty { font-size: 11px; padding: 2px 4px 4px; }

/* ── the timeline (§10–§13, §16, §27, §28, §31) ───────────────────────── */

/* Same rule as the grid above, one level down: every box between the grid and
   the horizontal scroller has to refuse to grow, or the scroller never scrolls. */
/* ── §21–§26 — THE TIMELINE, MADE READABLE ───────────────────────────────────
 *
 * WHAT WAS WRONG, measured off a screenshot of the running editor: the panel
 * ground was #101319 and a track was #0f1218 — four points of luminance apart,
 * which is no separation at all. Six rows of «almost the same black» with a
 * one-pixel line between them is the «хэт бараан, бүдэг, blur мэт» the brief
 * names, and it is why nobody could tell the Mongolian track from the source
 * one without reading the labels.
 *
 * The fix is a LADDER rather than more colour: the panel is the darkest thing
 * on screen, a track surface stands clearly above it, and alternate tracks
 * step once more so the eye can count rows without help. Every value below is
 * still dark — this is a dark editor and stays one — and nothing is neon:
 * saturation is spent on the two subtitle families and on state, which is where
 * it means something.
 */
.ed-tl { min-height: 0; min-width: 0; overflow: hidden;
  border-top: 1px solid var(--line); background: #080a0f; }
.etl { height: 100%; display: flex; flex-direction: column;
  min-height: 0; min-width: 0; overflow: hidden; }

/* §5 — THE TAB STRIP. Above the tools, because what it changes is which
   document those tools are pointed at. The active tab is joined to the toolbar
   under it — a tab that floats is a tab nobody reads as «this is what is
   below». */
.etl-tabs {
  flex: none; display: flex; align-items: stretch; gap: 2px; padding: 3px 8px 0;
  background: #0f1116; border-bottom: 1px solid var(--line); overflow-x: auto;
  scrollbar-width: thin;
}
.etl-tab {
  border: 1px solid transparent; border-bottom: none; background: transparent;
  color: var(--muted); border-radius: 7px 7px 0 0; padding: 4px 10px 5px;
  font-size: 12px; white-space: nowrap; flex: none; display: flex;
  align-items: center; gap: 6px;
}
.etl-tab:hover { color: var(--ink); background: #171b24; }
.etl-tab.on {
  background: #12141a; border-color: var(--line); color: var(--ink);
  font-weight: 600; margin-bottom: -1px; padding-bottom: 6px;
}
.etl-tabx {
  font-style: normal; font-size: 10px; opacity: .45; border-radius: 4px;
  padding: 0 2px;
}
.etl-tabx:hover { opacity: 1; background: #3a2029; color: var(--red); }
.etl-tabname {
  background: #0b0d12; border: 1px solid var(--accent); color: var(--ink);
  border-radius: 6px; padding: 3px 7px; font-size: 12px; width: 132px;
}
.etl-tabadd {
  border: 1px dashed var(--line); background: transparent; color: var(--muted);
  border-radius: 7px 7px 0 0; padding: 4px 10px; font-size: 13px; flex: none;
}
.etl-tabadd:hover { color: #fff; border-color: var(--accent); background: #171b24; }

.etl-bar {
  flex: none; display: flex; align-items: center; gap: 3px; padding: 4px 8px;
  border-bottom: 1px solid var(--line); background: #12141a;
}
.etl-tool {
  border: 1px solid transparent; background: transparent; color: var(--ink);
  border-radius: 6px; width: 26px; height: 24px; font-size: 12.5px; line-height: 1;
}
.etl-tool:hover:not(:disabled) { background: #1e2330; border-color: var(--line); }
.etl-tool.on { background: #233046; border-color: var(--accent); color: #fff; }
.etl-tool:disabled { opacity: .32; cursor: not-allowed; }
.etl-sep { width: 1px; height: 16px; background: var(--line); margin: 0 4px; }
.etl-grow { flex: 1 1 auto; }
.etl-zoom { width: 116px; accent-color: var(--accent); }

.etl-body { flex: 1 1 auto; min-height: 0; min-width: 0; display: flex;
  overflow: hidden; }
/* §21 — THE LABELS ARE A COLUMN, NOT A MARGIN. They step with the rows they
   name, so «which row am I on» is answerable from either side of the panel. */
.etl-labels {
  flex: none; width: 128px; border-right: 1px solid #2b3142;
  background: #0f1219; overflow: hidden;
}
.etl-lrow {
  height: var(--etl-h, 44px); display: flex; align-items: center; gap: 4px;
  padding: 0 8px; border-bottom: 1px solid #232838;
  font-size: 11px; color: #b6c0d4; background: #14171f;
}
.etl-lrow:nth-child(even) { background: #171b24; }
.etl-lruler {
  height: var(--etl-ruler, 26px); font-size: 10px; background: #10131a;
  color: #9fabc4;
}
.etl-lname { flex: 1 1 auto; min-width: 0; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap; }
.etl-eye, .etl-lock, .etl-mute {
  border: 0; background: transparent; color: var(--muted); font-size: 10px;
  padding: 1px 2px; opacity: .5; flex: none;
}
.etl-eye.on, .etl-lock.on, .etl-mute.on { opacity: 1; color: var(--ink); }

/* THE EYE IS A STATE, NOT A DISAPPEARANCE.
 *
 * Hiding a track used to remove its row — name, eye and all — so the control
 * that would turn it back on went with the thing it controlled and there was no
 * way back. The row, the name and the eye now stay exactly where they were; the
 * eye is drawn crossed, the name goes quiet, and only the CONTENT is left out. */
.etl-eye { position: relative; }
.etl-eye:not(.on) { opacity: .78; }
.etl-eye:not(.on)::after {
  content: ""; position: absolute; left: 0; right: 0; top: 50%;
  height: 1px; background: var(--red); transform: rotate(-24deg);
}
.etl-lrow.off .etl-lname { opacity: .45; text-decoration: line-through; }

/* The row keeps its height and its background; a faint hatch says the content
   is hidden rather than absent. */
.etl-track.off {
  background-image: repeating-linear-gradient(45deg,
    rgba(255, 255, 255, .028) 0 6px, transparent 6px 12px);
}

.etl-scroll {
  flex: 1 1 auto; min-width: 0; overflow-x: auto; overflow-y: hidden;
  position: relative; touch-action: none;
}
.etl-canvas { position: relative; min-height: 100%; }
/* §21 — THE SCALE EVERYTHING IS MEASURED ON, and it is allowed to be seen.
   Subtle is not the same as invisible: the ticks were #2b3140 on #12141a,
   which is a line you can only find if you know it is there. */
.etl-ruler {
  height: var(--etl-ruler, 26px); position: relative;
  border-bottom: 1px solid #2b3142;
  background: #10131a;
}
.etl-tick {
  position: absolute; top: 5px; font-style: normal; font-size: 10px;
  color: #9fabc4; padding-left: 4px; border-left: 1px solid #3b445c;
  height: 17px; white-space: nowrap; pointer-events: none;
}
.etl-track {
  height: var(--etl-h, 44px); position: relative;
  border-bottom: 1px solid #232838;
  background: #14171f;
}
/* PHASE 5 §11/§28 — THE ROW HEIGHT IS THE TRACK'S, NOT THE MODULE'S.
 *
 * `editor_timeline.js` publishes `--etl-h-<key>` for any track that declares
 * its own height and the same list feeds `EditorGeometry.trackRows`, so the
 * painter and the hit-tester cannot disagree about where a row is. Only the
 * film asks for one today; the brief is explicit that the subtitles must NOT
 * grow with it. */
.etl-t-video { height: var(--etl-h-video, 84px); }
.etl-t-video .etl-clip { height: calc(var(--etl-h-video, 84px) - 10px); }
.etl-t-video .etl-film { inset: 4px 0 4px 0; }
/* §22 — ONE STEP, ALTERNATING, so six rows can be counted rather than parsed.
   Nothing else distinguishes «the fourth row» from «the fifth» at a glance. */
.etl-track:nth-child(even) { background: #171b24; }
.etl-track.locked { background: #1b1e27; opacity: .8; }
/* The picture row is the one row whose CONTENT is the point, so it is the
   darkest surface in the stack — the frames have to be the brightest thing on
   it, not the plate behind them (§23). */
.etl-t-video { background: #0b0d12; }

/* ── §25 — THE TWO SUBTITLE FAMILIES ─────────────────────────────────────────
 *
 * The film's own words are COOL — the blue-cyan the design system already
 * spends on «this is what is there» — and the Mongolian is VIOLET, which is
 * `--accent2` and is what this product has meant by «our work» everywhere else.
 * Neither is hard-coded past these two lines: both are mixed from the tokens,
 * so a theme change moves them together with the rest of the product.
 *
 * A block is a PLATE with a coloured left edge, not a slab of colour. Twenty
 * saturated rectangles in a row is what makes a timeline tiring to look at, and
 * the state accents below have to be able to outshout the track colour — which
 * they cannot if the track colour is already at full volume.
 */
.etl-cue {
  position: absolute; top: 5px; height: calc(var(--etl-h, 44px) - 12px);
  border-radius: 6px; overflow: hidden;
  background: linear-gradient(180deg, #253150, #1e2740);
  border: 1px solid #38445f;
  display: flex; align-items: center; cursor: pointer;
  box-shadow: 0 1px 2px rgba(0, 0, 0, .35);
}
/* THE FILM'S OWN WORDS — cool. */
.etl-cue.tr-src {
  background: linear-gradient(180deg,
    color-mix(in srgb, var(--accent) 34%, #10151f),
    color-mix(in srgb, var(--accent) 20%, #0d1119));
  border-color: color-mix(in srgb, var(--accent) 62%, #1b2333);
}
/* THE MONGOLIAN — violet. */
.etl-cue.tr-mn {
  background: linear-gradient(180deg,
    color-mix(in srgb, var(--accent2) 34%, #14111f),
    color-mix(in srgb, var(--accent2) 20%, #0f0d18));
  border-color: color-mix(in srgb, var(--accent2) 62%, #221b33);
}
/* …AND A SOLID EDGE ON THE LEFT, which is what actually reads at a glance.
   A tinted fill is a difference you have to look for; a 3px bar of the track's
   own colour, in the same place on every block, is one you cannot miss — and it
   survives the state stripe sitting on the top edge above it. */
.etl-cue.tr-src::after,
.etl-cue.tr-mn::after {
  content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 3px;
  pointer-events: none;
}
.etl-cue.tr-src::after { background: var(--accent); }
.etl-cue.tr-mn::after { background: var(--accent2); }
/* The grab handle sits over it, so a drag still starts where it always did. */
.etl-cue .etl-grab.s { z-index: 2; }
.etl-cue.ok { border-color: color-mix(in srgb, var(--green) 55%, #1b2333); }
/* ── §26 — STATE, AS A STRIPE AND A BORDER, NEVER AS A FILL ─────────────── */
.etl-cue.st-review,
.etl-cue.warn { border-color: color-mix(in srgb, var(--amber) 62%, #2a2415); }
.etl-cue.st-error { border-color: color-mix(in srgb, var(--red) 66%, #2a1618); }
.etl-cue.st-review::before,
.etl-cue.st-error::before,
.etl-cue.st-fixed::before {
  content: ""; position: absolute; left: 0; right: 0; top: 0; height: 3px;
  pointer-events: none;
}
.etl-cue.st-review::before { background: var(--amber); }
.etl-cue.st-error::before { background: var(--red); }
/* AUTO_FIXED is good news and is a MARK, not a warning: a thin teal top edge
   that says «the engine already dealt with this» without asking for a look. */
.etl-cue.st-fixed::before {
  background: color-mix(in srgb, var(--green) 78%, var(--accent));
  height: 2px;
}
.etl-cue.sel {
  box-shadow: 0 0 0 2px var(--accent), 0 2px 8px rgba(0, 0, 0, .5); z-index: 3;
}
.etl-cue.dragging { z-index: 5; opacity: .92; }
.etl-cuetext {
  flex: 1 1 auto; min-width: 0; overflow: hidden; white-space: nowrap;
  text-overflow: ellipsis; font-size: 11.5px; padding: 0 7px; color: #eef1f8;
  pointer-events: none; line-height: 1.2;
}
/* §26 — «↔» / «✂»: provenance, at the head of the block, quiet. */
.etl-op {
  flex: none; font-style: normal; font-size: 10.5px; margin-left: 5px;
  color: #cdd6ea; opacity: .85; pointer-events: none;
}
.etl-pen {
  flex: none; font-style: normal; font-size: 9.5px; margin-right: 4px;
  color: color-mix(in srgb, var(--accent2) 70%, #fff); pointer-events: none;
}
.etl-grab {
  position: absolute; top: 0; bottom: 0; width: 7px; cursor: ew-resize;
  background: rgba(255, 255, 255, .16);
}
.etl-grab.s { left: 0; border-radius: 5px 0 0 5px; }
.etl-grab.e { right: 0; border-radius: 0 5px 5px 0; }
.etl-grab:hover { background: var(--accent); }
.etl-mark {
  position: absolute; right: 3px; top: 3px; width: 6px; height: 6px;
  border-radius: 50%; background: var(--amber); pointer-events: none;
}
.etl-mark.audio { background: var(--accent2); }
/* §4/§6 — THE OVERLAY BLOCKS. Wider and flatter than a cue: they are spans,
   not lines, and the eye should read them as «this is on from here to here»
   rather than as another subtitle. */
.etl-ov {
  position: absolute; top: 6px; height: calc(var(--etl-h, 44px) - 14px);
  border-radius: 6px;
  background: linear-gradient(180deg, #3b2f63, #2c2450);
  border: 1px solid #5b4aa6; display: flex; align-items: center;
  cursor: pointer; overflow: hidden;
  box-shadow: 0 1px 2px rgba(0, 0, 0, .35);
}
.etl-ov.sel { box-shadow: 0 0 0 2px var(--accent); z-index: 3; }
.etl-ov.off { opacity: .4; border-style: dashed; }
.etl-ov.dragging { z-index: 5; opacity: .92; }
.etl-ovlabel {
  flex: 1 1 auto; min-width: 0; overflow: hidden; white-space: nowrap;
  text-overflow: ellipsis; font-size: 10.5px; padding: 0 8px; color: #ded7f6;
  pointer-events: none;
}
.etl-t-blur { background: #10131b; }
.etl-t-mark { background: #10131b; }

.etl-gap {
  position: absolute; top: 8px; height: 18px; border-radius: 4px;
  background: repeating-linear-gradient(45deg, #3a2f63 0 5px, #2b2450 5px 10px);
  border: 1px solid #55479b; cursor: pointer;
}

.etl-clip {
  position: absolute; top: 4px; height: calc(var(--etl-h, 44px) - 10px);
  border-radius: 6px;
  border: 1px solid #46608f; background-color: #1b2333; overflow: hidden;
  cursor: pointer;
}
.etl-clip.sel { box-shadow: 0 0 0 2px var(--accent); z-index: 3; }
/* PHASE 5 §18 — SCOPED IS NOT SELECTED.
 *
 * `S.clipId` is «which clip the cue list below is filtered to». It used to be
 * drawn as a SELECTION and, worse, read as one by Ctrl+C — so a clip of the
 * film ended up on the clipboard beside the subtitles the person had chosen.
 *
 * Both facts are worth showing and they are not the same fact. Selection keeps
 * the accent ring; scope gets a quiet bar along the bottom edge, which reads as
 * «the list is about this scene» and never as «this is what Delete will take». */
.etl-clip.scoped { box-shadow: inset 0 -3px 0 color-mix(in srgb, var(--accent) 55%, transparent); }
.etl-clip.sel.scoped {
  box-shadow: 0 0 0 2px var(--accent),
              inset 0 -3px 0 color-mix(in srgb, var(--accent) 55%, transparent);
}
.etl-clip.trimmed { border-style: dashed; }
/* §23 — THE NAME AND THE LENGTH STAY READABLE OVER THE FRAMES.
   A plate under the words rather than a dim over the whole clip: the strip is
   the point of the row and must not be greyed out to make a label legible. */
.etl-cliplabel {
  position: absolute; left: 0; right: 0; bottom: 0; font-size: 10.5px;
  padding: 2px 6px; color: #f2f5fb;
  background: linear-gradient(180deg, rgba(6, 8, 12, 0), rgba(6, 8, 12, .82) 55%);
  text-shadow: 0 1px 2px rgba(0, 0, 0, .9);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  pointer-events: none;
}
.etl-cut { color: var(--amber); font-style: normal; }

/* ── PHASE 5 §11/§14/§29 — THE FILM BLOCK, MADE READABLE ─────────────────────
 *
 * §29 asks for the clutter to go and §11 for the boundaries, the name and the
 * state to be obvious. Those pull in opposite directions if the answer is «add
 * more chrome», so the answer here is «give the chrome somewhere to be»: an
 * 84px row has room for the picture AND a name bar under it, where 44px did
 * not and the label sat on top of the frames.
 */
.etl-t-video .etl-cliplabel {
  font-size: 11.5px; padding: 3px 8px; letter-spacing: .1px;
  background: linear-gradient(180deg, rgba(6, 8, 12, 0), rgba(6, 8, 12, .9) 42%);
}
/* §11 — WHERE ONE CLIP ENDS AND THE NEXT BEGINS.
 *
 * On a magnetic track the clips TOUCH, so a 1px border between two of them is
 * a single shared line and the eye reads one long block. A bright inset edge on
 * each side is what makes three pieces of the same film look like three pieces
 * of the same film. */
.etl-t-video .etl-clip {
  border-color: #4a6699;
  box-shadow: inset 1px 0 0 rgba(255, 255, 255, .22),
              inset -1px 0 0 rgba(0, 0, 0, .55);
}
.etl-t-video .etl-clip.sel {
  border-color: var(--accent);
  box-shadow: 0 0 0 2px var(--accent), inset 0 0 0 1px rgba(255, 255, 255, .18);
  z-index: 3;
}
/* §14/§15 — THE HANDLES ARE FOR THE SELECTED CLIP.
 *
 * «Hover alone must not add excessive visual noise»: a row of six clips each
 * sprouting two bars as the pointer crosses them is exactly that. So they are
 * dim until the clip is picked, and unmistakable after — which is also what
 * makes trim and move visibly different gestures rather than two outcomes of
 * the same one. */
.etl-t-video .etl-grab { width: 9px; background: rgba(255, 255, 255, .10); }
.etl-t-video .etl-clip.sel .etl-grab {
  background: var(--accent);
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .35);
}
.etl-t-video .etl-clip.sel .etl-grab::after {
  content: ""; position: absolute; left: 3px; right: 3px; top: 38%; bottom: 38%;
  border-radius: 2px; background: rgba(255, 255, 255, .85);
}

/* ── PHASE 5 §8 — WHERE THE DRAGGED CLIP WILL LAND ───────────────────────────
 *
 * Three things, and no more than three: a line at the boundary, a wash over the
 * gap it will occupy, and a ghost of the clip itself. The user must know the
 * result BEFORE releasing, which is §8's whole sentence, and they must not have
 * to decode four new colours to know it.
 *
 * All three are positioned from `EditorGeometry`'s answer in timeline seconds,
 * never from a DOM offset, so scroll, zoom and a resized header cannot move
 * them relative to the film.
 */
.etl-insert {
  position: absolute; width: 3px; margin-left: -1.5px; border-radius: 2px;
  background: var(--amber, #f0a92b);
  box-shadow: 0 0 0 1px rgba(0, 0, 0, .55), 0 0 10px 2px rgba(240, 169, 43, .55);
  pointer-events: none; z-index: 8; display: none;
}
.etl-insert::before, .etl-insert::after {
  content: ""; position: absolute; left: 50%; width: 0; height: 0;
  transform: translateX(-50%);
  border-left: 5px solid transparent; border-right: 5px solid transparent;
}
.etl-insert::before { top: -1px; border-top: 6px solid var(--amber, #f0a92b); }
.etl-insert::after { bottom: -1px; border-bottom: 6px solid var(--amber, #f0a92b); }
/* THE GAP THE CLIP IS GOING INTO. A wash, not a fill: the frames underneath are
   still what tells the user which cut this is. */
.etl-dropgap {
  position: absolute; border-radius: 6px; pointer-events: none; z-index: 6;
  background: rgba(240, 169, 43, .16);
  border: 1px dashed rgba(240, 169, 43, .75);
  display: none;
}
/* THE GHOST. The real block stays where it is — which is the point: the user
   compares «where it is» with «where it would go» in one glance. */
.etl-ghost {
  position: absolute; border-radius: 6px; pointer-events: none; z-index: 7;
  border: 1px solid var(--amber, #f0a92b);
  background: rgba(240, 169, 43, .10);
  box-shadow: 0 2px 10px rgba(0, 0, 0, .5);
  overflow: hidden; display: none;
}
.etl-ghostlabel {
  position: absolute; left: 0; right: 0; bottom: 0; font-size: 11px;
  padding: 2px 6px; color: #fdf3e2; white-space: nowrap; overflow: hidden;
  text-overflow: ellipsis; background: rgba(6, 8, 12, .78);
}
/* While a magnetic drag is in flight the clip being moved recedes, so the ghost
   is unambiguously the answer and the original is unambiguously the question. */
.etl-clip.lifting { opacity: .34; filter: saturate(.5); }

/* ── the filmstrip (§27) ──────────────────────────────────────────────── */

/* A LAYER UNDER THE BLOCKS, not a background on them. `editor_timeline.js`
   re-parents the very same <img> nodes on every render, so the strip survives a
   re-render already decoded — which is why scrolling and zooming do not flash
   and playback is not asked to share the decoder. */
.etl-film { position: absolute; inset: 3px 0 3px 0; overflow: hidden;
  pointer-events: none; }
/* PHASE 5 §12 — ONE CLIP BOX PER PIECE OF FILM.
   The strip is cut in whole cells and a clip's length rarely is, so without
   this the last frame of one clip overhangs the first frame of the next — which
   only became visible when the film became a MAGNETIC sequence and the clips
   started touching. */
.etl-filmclip { position: absolute; top: 0; bottom: 0; overflow: hidden; }
/* §23 — FULL STRENGTH. The frames used to be drawn at 92% over a near-black
   plate and then had a translucent block laid over them, which is «black/dim
   overlay хэт их тавьж thumbnail-г бүдгэрүүлэхгүй» in three steps. */
.etl-filmimg {
  position: absolute; top: 0; height: 100%; display: block;
  object-fit: fill; image-rendering: auto; opacity: 1;
}
.etl-filmimg.gone { display: none; }

/* The block over the strip is a BOUNDARY, not a fill: a clip is legible by its
   edges and its name, and painting it opaque would hide the frames that are the
   whole point of the row. */
.etl-clip { background-color: rgba(27, 35, 51, .12); }
/* 1.6.6 §1 — THE WHOLE-FILM BLOCK IS A THING YOU CAN CLICK.
   It carried `pointer-events: none`, which is the CSS half of «video clip дээр
   дараад идэвхжүүлж чадахгүй байна»: the JS was ready to select it and the
   pointer went straight through to the track underneath. Still transparent —
   the block is a boundary around the filmstrip, not a fill over it. */
.etl-clip.whole { border-color: #2a3346; background-color: transparent; }
.etl-clip.whole.sel { border-color: var(--accent); }
.etl-wave { display: block; }
.etl-wave path { stroke: #4d6ea8; stroke-width: 1; fill: none; }
.etl-empty { font-size: 10.5px; color: var(--muted); padding: 9px 10px; }

/* §22 — THE PLAYHEAD IS THE ONE THING THAT MUST NEVER BE HUNTED FOR.
   A head at the top so it is findable at any scroll position, and a glow so it
   survives crossing a bright filmstrip. */
.etl-playhead {
  position: absolute; top: 0; bottom: 0; width: 2px; margin-left: -1px;
  background: #ff4d4f; pointer-events: none; z-index: 6;
  box-shadow: 0 0 0 1px rgba(0, 0, 0, .55), 0 0 7px rgba(255, 77, 79, .55);
}
.etl-playhead::before {
  content: ""; position: absolute; left: -4px; top: 0;
  border-left: 5px solid transparent; border-right: 5px solid transparent;
  border-top: 7px solid #ff4d4f;
}
/* §3 — THE GUIDE APPEARS ONLY WHEN AN EDGE ACTUALLY SNAPPED, and it stands at
   the TARGET. A line that followed the pointer everywhere would tell the user
   nothing; this one says which boundary the edge locked onto. Brighter and two
   pixels wide, because it has to be readable against the red playhead it will
   most often be standing on. */
.etl-guide {
  position: absolute; top: 0; bottom: 0; width: 1px; background: var(--accent);
  display: none; pointer-events: none; z-index: 5;
}
.etl-guide.snap {
  width: 2px; margin-left: -1px; background: var(--green);
  box-shadow: 0 0 6px rgba(63, 185, 128, .7);
}
/* §13 — a file dragged over the timeline lands in the bin and on the row. */
.etl-scroll.dropping { outline: 2px dashed var(--accent); outline-offset: -3px; }

/* MANUAL REMEDIATION — THE SELECT TOOL'S RUBBER BAND.
 *
 * Drawn inside the canvas so it scrolls and zooms with the blocks it is
 * choosing, and `pointer-events: none` so the pointer it is following is never
 * captured by the rectangle it is drawing. */
.etl-band {
  position: absolute; z-index: 6; pointer-events: none;
  border: 1px solid var(--accent);
  background: color-mix(in srgb, var(--accent) 14%, transparent);
  border-radius: 2px;
}
/* The crosshair is the only thing on screen that says which mode is on besides
   the pressed button, and it says it where the user's attention already is. */
.etl-scroll.banding { cursor: crosshair; }

/* §15 — a video or audio ROW on a stored timeline. Not a subtitle: it carries a
   filmstrip behind its label, so the label needs a plate to stay readable. */
.etl-cue.media { background: #1b2536; border-color: #33507a; }
.etl-cue.media .etl-cuetext {
  background: rgba(10, 12, 18, .66); border-radius: 3px; padding: 0 4px;
}
.etl-tip {
  position: absolute; top: 24px; z-index: 8; background: #1b2130;
  border: 1px solid var(--accent); border-radius: 6px; padding: 3px 8px;
  font-size: 10.5px; color: var(--ink); white-space: nowrap; pointer-events: none;
  font-variant-numeric: tabular-nums;
}
.etl-tip.warn { border-color: var(--amber); color: var(--amber); }

/* ── 9:16 (§5) ────────────────────────────────────────────────────────── */

/* ONE adaptive layout. Portrait does not get a different editor — it gets a
   narrower pair of text columns, because a vertical film needs the height and
   the lists do not. Every divider still drags, and the sizes are remembered
   under their own key. */
.ed.portrait .ed-rowtx i { display: none; }
.ed.portrait .ed-listhead .muted { display: none; }

/* A short window (a 768px laptop) gives the timeline its floor back rather
   than letting a remembered height eat the picture. */
/* The row height is NOT changed here. `editor_shell.js` positions every row
   at `index * 46` and sizes the scroll pad from the same number — a stylesheet
   that disagreed with it would put the rows and the scrollbar out of step, and
   the list would drift further from its own scrollbar the longer the film. */
@media (max-height: 820px) {
  .ed { --ed-tl: min(var(--ed-tl), 226px); }
}

.ed-rowempty { color: var(--muted); font-style: italic; font-weight: 400; }

/* §42 — THE APP'S OWN SIDEBAR HANDLE IS NOT A CONTROL ON THIS SCREEN.
   The workspace has a Menu of its own in the top bar; a second way to open a
   navigation the editor does not use is exactly the duplicated entry point the
   clean-up is about, and it sits on top of the Menu button. */
.main.ed-host ~ * #navReopen, body:has(.main.ed-host) #navReopen { display: none; }

/* ── the overlay layer (§1, §3, §5, §9, §15) ──────────────────────────── */

/* THE LAYER IS ALWAYS THERE. It used to be created when you entered «Бичлэг
 * янзлах» and destroyed when you left, so a blur band placed in step 4 was
 * invisible in steps 1–3 — the picture you checked a subtitle against was not
 * the picture you were making. It is mounted for as long as the project is
 * open, and every stage draws the same frame.
 *
 * The three objects are positioned against the FRAME rather than against the
 * element — `object-fit: contain` letterboxes, and placing a band against the
 * element puts it in the letterbox on any film whose shape is not the panel's.
 * `editor_picture.js` does that arithmetic with `final_edit.js`'s own
 * `contentRect`. */
.ep-layer { position: absolute; inset: 0; pointer-events: auto; }
.ep-obj { position: absolute; cursor: move; }

/* THE BAND'S PICTURE IS AN INNER ELEMENT, AND THE HANDLES ARE NOT INSIDE IT.
 *
 * ROOT CAUSE OF «the top and bottom edges cannot be dragged». The feather is
 * previewed as a CSS `mask-image` — the same alpha ramp the exported PNG mask
 * carries — and a mask applies to an element AND EVERY CHILD OF IT. The eight
 * handles were children, so at the default feather of 55 the `n`, `s` and the
 * four corner handles were drawn at alpha 0 along the very edges the mask
 * fades, and a masked-out pixel does not hit-test either: invisible AND
 * ungrabbable. The left and right handles survived because `feather_edges`
 * keeps a full-width band's sides hard — which is exactly the symptom that was
 * reported. So everything that paints lives on `.ep-blurfill` and the object
 * that carries the outline and the handles is never masked. */
.ep-blur { border-radius: 2px; }
.ep-blurfill { position: absolute; inset: 0; display: block; border-radius: 2px;
  pointer-events: none; }
/* THE LINE BOX IS NOT A STYLESHEET'S OPINION. libass advances one line by
   exactly ASS `Fontsize` — the type size times `ASS_EM_RATIO`, 1.1172 — so a
   hard-coded 1.22 here drew a two-line caption nine per cent taller than the
   export would. `editor_picture.js` sets it from the server's own constant,
   multiplied by «Мөр хоорондын зай»; this is only the value before the first
   paint. The mark is one line and never wraps, so its own box does not
   matter. */
.ep-mark span, .ep-sub span { display: block; white-space: pre-wrap;
  line-height: 1.1172; }
.ep-sub span { border-radius: 4px; }

/* §7 — THE SOURCE STANDING IN FOR A TRANSLATION THAT IS NOT THERE YET.
   Drawn, because a player showing nothing over a film that has just been read
   says «the reading found nothing»; and drawn DIFFERENTLY, because a source
   line styled as the export's Mongolian caption would be a preview of a file
   that does not exist. Dimmed and outlined: present, legible, and obviously
   not the finished subtitle. */
.ep-sub.ep-sub-source span { opacity: .74; font-style: italic;
  outline: 1px dashed rgba(255, 255, 255, .34); outline-offset: 2px; }

/* A HOVER SAYS «THIS IS DRAGGABLE»; A SELECTION SAYS «THIS IS WHAT THE PANEL
   IS ABOUT». Nothing is outlined while the film plays — see §25 below. */
.ep-obj:hover { outline: 1.5px dashed rgba(91, 140, 255, .55); outline-offset: 1px; }
.ep-obj.sel { outline: 1.5px solid var(--accent); outline-offset: 1px; }

/* ── the eight handles (§3, §5, §9) ───────────────────────────────────── */

/* ONLY ON THE SELECTED OBJECT. A picture with twenty-four handles on it is a
   picture you cannot see, which is what §15 is about. The hit area is bigger
   than the dot: a handle you have to aim at is a handle nobody grabs. */
/* THREE PIXELS INSIDE THE EDGE, NOT ON IT.
 *
 * They used to be centred exactly ON the object's boundary, and on production
 * that made three of the eight ungrabbable. The picture fills the stage to its
 * right edge, the stage ends where `.app` ends, and `body.wd-docked` holds a
 * 34px gutter open beside it for the work drawer — so `e`, `ne` and `se` had
 * their centres at x = the app's own right edge and every hit test at that
 * point resolved to the BODY behind them. Measured on 88777a0cb17b: the app
 * ends at 1566 and all three handle centres were at 1566.
 *
 * The dot still straddles the edge, because that is what a resize handle
 * should look like. Only its anchor point moved inside, which is enough: at any
 * band size above the 8px floor the two rows stay apart, and every one of the
 * eight answers a mouse wherever the object is on the frame. */
.ep-h { position: absolute; width: 11px; height: 11px; margin: 0;
  transform: translate(-50%, -50%);
  border-radius: 3px; background: #fff; border: 1.5px solid var(--accent);
  box-shadow: 0 1px 4px rgba(0, 0, 0, .5); display: none; z-index: 3; }
.ep-obj.sel > .ep-h { display: block; }
.ep-h-nw { left: 3px; top: 3px; cursor: nwse-resize; }
.ep-h-n  { left: 50%; top: 3px; cursor: ns-resize; }
.ep-h-ne { left: calc(100% - 3px); top: 3px; cursor: nesw-resize; }
.ep-h-e  { left: calc(100% - 3px); top: 50%; cursor: ew-resize; }
.ep-h-se { left: calc(100% - 3px); top: calc(100% - 3px); cursor: nwse-resize; }
.ep-h-s  { left: 50%; top: calc(100% - 3px); cursor: ns-resize; }
.ep-h-sw { left: 3px; top: calc(100% - 3px); cursor: nesw-resize; }
.ep-h-w  { left: 3px; top: 50%; cursor: ew-resize; }

/* «Effect» — ASHD Kino's six looks. Words rather than swatches, because what
   separates «Кино» from «Мөнгөлөг» is a shadow and an alpha, and neither is
   legible in an 18px square. */
.ep-effect { border: 1px solid var(--line); background: var(--panel2);
  color: var(--fg); border-radius: 7px; padding: 5px 9px; font-size: 12px;
  cursor: pointer; }
.ep-effect:hover { border-color: var(--accent); }
.ep-effect.on { border-color: var(--accent); background: var(--accent);
  color: #fff; }

/* ── the guides (§3, §9) ──────────────────────────────────────────────── */

/* Drawn only while a drag is actually ON the line, so a guide means «you are
   there» rather than «here is where the middle is». */
.ep-guide { position: absolute; display: none; pointer-events: none; z-index: 2; }
.ep-guide.on { display: block; }
.ep-guide-v { width: 1px; background: var(--accent2); box-shadow: 0 0 6px var(--accent2); }
.ep-guide-h { height: 1px; background: var(--accent2); box-shadow: 0 0 6px var(--accent2); }
.ep-guide-safe { height: 1px; background: var(--green);
  box-shadow: 0 0 6px rgba(60, 200, 130, .8); }

/* §25 — PLAYBACK IS A PREVIEW. While the film plays the outlines, the handles
   and the guides go away, so what the user checks is what the export will look
   like. Pausing brings the selected object's handles back. */
.ed.playing .ep-obj, .ed.playing .ep-obj.sel, .ed.playing .ep-obj:hover {
  outline: none; cursor: default;
}
.ed.playing .ep-h, .ed.playing .ep-guide { display: none !important; }

/* ── the overlay panels (§3, §5, §7, §8) ──────────────────────────────── */

.ep-title { font-size: 11px; letter-spacing: .06em; text-transform: uppercase;
  color: var(--muted); margin-bottom: 4px; }
.ep-sec { font-size: 10px; letter-spacing: .06em; text-transform: uppercase;
  color: var(--muted); margin: 10px 0 5px; }
.ep-controls { display: grid; gap: 7px; }
.ep-row { display: grid; gap: 3px; font-size: 11px; color: var(--muted); }
.ep-row > span { display: flex; justify-content: space-between; align-items: baseline; }
.ep-row i { font-style: normal; color: var(--ink);
  font-variant-numeric: tabular-nums; }
.ep-row input[type="range"] { width: 100%; accent-color: var(--accent); }
.ep-row input[type="text"], .ep-row select, .ep-row textarea {
  background: #10131a; color: var(--ink); border: 1px solid var(--line);
  border-radius: 7px; padding: 5px 7px; font-size: 12px; width: 100%;
  font-family: inherit;
}
.ep-colour { grid-template-columns: 1fr auto; align-items: center; }
.ep-colour input[type="color"] {
  width: 40px; height: 24px; padding: 0; border: 1px solid var(--line);
  border-radius: 6px; background: transparent;
}
.ep-bool { display: flex; flex-direction: row; align-items: center; gap: 7px;
  color: var(--ink); font-size: 12px; }
.ep-align { display: flex; gap: 4px; }
.ep-align button {
  flex: 1 1 0; border: 1px solid var(--line); background: var(--panel2);
  color: var(--muted); border-radius: 6px; padding: 4px 0; font-size: 12px;
}
.ep-align button.on { background: var(--accent); border-color: var(--accent); color: #fff; }

/* §7 — the presets, drawn AS THEMSELVES. Each swatch is the style it applies,
   so the picker needs no legend and no rendered thumbnails. */
.ep-presets { display: flex; flex-wrap: wrap; gap: 5px; }
.ep-preset {
  width: 38px; height: 30px; border-radius: 7px; border: 1px solid var(--line);
  font-size: 14px; font-weight: 700; line-height: 1; cursor: pointer;
  paint-order: stroke fill;
}
.ep-preset.on { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent); }
.ep-acts { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 10px; }
.ep-acts .btn { flex: 1 1 auto; }

/* ── «＋ Хэсэг болгох» (§19) ──────────────────────────────────────────── */

/* A BAR, NOT A MODAL. It sits above the timeline with the film still visible
   behind it, because the only way to know whether a range is the scene you
   meant is to be able to see the scene while you mark it. */
.ed-markbar {
  position: absolute; left: 50%; transform: translateX(-50%);
  bottom: calc(var(--ed-tl) + 12px); z-index: 30;
  display: flex; align-items: center; gap: 7px; padding: 7px 11px;
  background: #161a22; border: 1px solid var(--accent); border-radius: 11px;
  box-shadow: 0 14px 36px rgba(0, 0, 0, .55); font-size: 12px;
}
.ed-markbar span { color: var(--muted); font-variant-numeric: tabular-nums; }

/* ═══ 1.6.6 — SELECT, SPLIT, THE MENU AND THE MEDIA LIBRARY ═══════════════ */

/* §2 — «Хуваах» is a word, not a glyph: two scissor-shaped icons side by side
   is what made Cut and Split indistinguishable. */
.etl-tool.wide { width: auto; padding: 0 9px; font-size: 11.5px; font-weight: 600; }

/* §3 — the right-click menu. On `document.body` because a timeline row is
   inside a scroller with `overflow:hidden`, and a menu clipped by the track it
   was opened on is a menu with two entries missing. */
.etl-menu {
  position: fixed; z-index: 90; min-width: 168px; padding: 5px;
  background: var(--panel); border: 1px solid var(--line); border-radius: 9px;
  box-shadow: 0 14px 34px rgba(0, 0, 0, .5); display: grid; gap: 2px;
}
.etl-mi {
  display: flex; align-items: center; justify-content: space-between; gap: 14px;
  width: 100%; text-align: left; border: 0; background: transparent;
  color: var(--ink); border-radius: 7px; padding: 7px 9px; font-size: 12.5px;
}
.etl-mi:hover:not(:disabled) { background: #1e2330; }
.etl-mi:disabled { opacity: .34; cursor: not-allowed; }
.etl-mi i { font-style: normal; color: var(--muted); font-size: 10.5px; }
/* PHASE 4 — the cross-timeline verbs sit below a rule, because «Хуулах» and
   «Timeline руу хуулах» are two different acts and a menu that runs them
   together invites the wrong one. */
.etl-msep { height: 1px; margin: 4px 6px; background: var(--line); }

/* §5 — [＋ Import] is three buttons and nothing else. */
.ed-impick { min-width: 190px; }
.ed-impk {
  display: flex; align-items: center; gap: 10px; width: 100%; text-align: left;
  border: 0; background: transparent; color: var(--ink); border-radius: 8px;
  padding: 9px 11px; font-size: 13px;
}
.ed-impk:hover { background: #1e2330; }

/* §6/§7/§8 — the media library, in the Details panel. */
.ed-dclose { margin-left: auto; border: 0; background: transparent;
  color: var(--muted); font-size: 14px; }
.ed-libadd { width: 100%; margin-bottom: 4px; }
.ed-librow {
  display: flex; align-items: center; gap: 7px; padding: 4px 6px;
  border: 1px solid var(--line); border-radius: 7px; background: var(--panel2);
  font-size: 11.5px; min-width: 0;
}
.ed-librow.bad { border-color: var(--red); }
.ed-librow:hover { border-color: var(--accent); }
.ed-libthumb {
  flex: none; width: 44px; height: 26px; border-radius: 4px; background: #0d0f14;
  border: 1px solid var(--line); object-fit: cover; display: block;
}
.ed-libicon { flex: none; width: 22px; text-align: center; font-size: 13px; }
.ed-libname {
  flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis;
  white-space: nowrap; color: var(--ink);
}
.ed-libmeta { flex: none; color: var(--muted); font-size: 10.5px;
  font-variant-numeric: tabular-nums; }
.ed-librow .btn.sm { width: auto; flex: none; padding: 2px 7px; font-size: 11px; }

/* §45–§48 — bulk select, ordering and the drop target. */
.ed-librow[draggable="true"] { cursor: grab; }
.ed-librow.picked { border-color: var(--accent); background: rgba(34,211,238,.10); }
.ed-libtick { flex: none; width: 14px; height: 14px; accent-color: #22d3ee;
  margin: 0; cursor: pointer; }
.ed-binbar {
  display: flex; align-items: center; gap: 6px; padding: 2px 0 4px;
  font-size: 11px; color: var(--muted);
}
.ed-binbar label { flex: none; }
.ed-binbar select {
  flex: 1 1 auto; min-width: 0; background: var(--panel2); color: var(--ink);
  border: 1px solid var(--line); border-radius: 6px; padding: 3px 6px;
  font-size: 11px;
}
.ed-binbar .btn.sm { width: auto; flex: none; }
/* The bulk bar sticks to the bottom of the library so a selection made at the
   top of a long bin does not scroll its own action off the screen. */
.ed-binbulk {
  position: sticky; bottom: 0; display: flex; align-items: center; gap: 6px;
  margin-top: 6px; padding: 7px 6px; border-radius: 8px;
  background: linear-gradient(180deg, rgba(13,15,20,.86), rgba(13,15,20,.98));
  border: 1px solid var(--accent); backdrop-filter: blur(8px);
}
.ed-binbulk .n { flex: none; font-size: 11px; color: var(--accent); font-weight: 600; }
.ed-binbulk select {
  flex: 1 1 auto; min-width: 0; background: var(--panel2); color: var(--ink);
  border: 1px solid var(--line); border-radius: 6px; padding: 3px 6px; font-size: 11px;
}
.ed-binbulk .btn { flex: none; padding: 4px 10px; font-size: 11.5px; }
/* While something is being dragged over it, the timeline says so. Outline
   rather than border: a border would move every track by a pixel. */
.ed-dropping { outline: 2px dashed var(--accent); outline-offset: -2px; }

/* ── «⚙ Хадмал байршил тохируулах» (§6) ───────────────────────────────────
 *
 * A LAYER THAT IS EITHER ABSENT OR IN CHARGE. While it is off it is `hidden`
 * and takes no pointer at all, so the overlay objects and the player behave
 * exactly as they do on every other stage. While it is on it covers the
 * picture, wears the crosshair, and is the only thing a click can reach —
 * because a half-armed selection mode, where some clicks draw and some seek,
 * is the confusion this replaced.
 *
 * z-index 3: over `.ep-layer` (the blur band and ASHD Kino, which must not be
 * grabbable while a band is being drawn) and under `.ed-mediafail`. */
.ed-region { position: absolute; inset: 0; z-index: 3; cursor: crosshair; }
.ed-region[hidden] { display: none; }
.ed-region-dim { position: absolute; inset: 0; background: rgba(6, 8, 12, .34); }
.ed-region-box {
  position: absolute; border: 1.5px solid var(--accent);
  background: rgba(91, 140, 255, .16);
  box-shadow: 0 0 0 9999px rgba(6, 8, 12, .34);
  pointer-events: none;
}
/* The rectangle carries the dimming once there is one, so the band the user
   drew is the bright part of the picture rather than one more blue box on it.
   `.hasbox` rather than a sibling selector: the dim element comes BEFORE the
   box in the DOM, and CSS has no way back up the list. */
.ed-region.hasbox .ed-region-dim { display: none; }
.ed-region-hint {
  position: absolute; left: 50%; top: 12px; transform: translateX(-50%);
  background: rgba(18, 20, 26, .94); border: 1px solid var(--line);
  border-radius: 8px; padding: 6px 12px; font-size: 12px; color: var(--ink);
  pointer-events: none; white-space: nowrap; max-width: 92%; overflow: hidden;
  text-overflow: ellipsis;
}
.ed-region-acts {
  position: absolute; display: flex; gap: 6px; z-index: 4;
  background: rgba(18, 20, 26, .96); border: 1px solid var(--line);
  border-radius: 9px; padding: 5px;
}
.ed-region-acts[hidden] { display: none; }
.ed-region-acts .btn { flex: none; }

/* ── §1/§4 — the reading button, and the empty list that has a reason ────── */

/* WHAT THE BUTTON WILL ACTUALLY DO, under the button. «Дахин гаргах» is one
   word for two very different minutes — restoring a finished reading and
   reading the second half of a film — and the difference belongs where the
   press happens, not in a toast afterwards. */
.ed-acthint {
  font-size: 10.5px; color: var(--muted); line-height: 1.35;
  margin: -2px 0 2px; padding: 0 2px;
}
/* Selection mode is ON: the button that armed it says so, because a crosshair
   over a picture is not, by itself, an explanation. */
.ed-railacts .btn.ghost.on {
  border-color: var(--accent); color: var(--accent);
}
.ed-emptycard {
  position: absolute; left: 10px; right: 10px; top: 10px;
  display: grid; gap: 7px; justify-items: start;
  border: 1px solid var(--line); border-radius: 10px;
  background: var(--panel2); padding: 12px 14px;
}
.ed-emptycard b { font-size: 13px; }
.ed-emptycard .muted { font-size: 11.5px; line-height: 1.45; color: var(--muted); }
/* §P8b — «WE HAVE NOT ASKED YET» IS NOT A FINDING, so it does not wear a
   finding's box. One faint line where the rows are about to be, for the frame
   or two before they arrive; a bordered card that appears and disappears on
   every tab click is a flicker, which is the thing this is fixing. */
.ed-loadingcard {
  position: absolute; left: 10px; right: 10px; top: 10px;
  padding: 12px 14px; font-size: 11.5px; color: var(--muted);
}
.ed-emptyfacts {
  display: grid; grid-template-columns: auto 1fr; gap: 2px 10px;
  margin: 2px 0 0; font-size: 11px; width: 100%;
}
.ed-emptyfacts dt { color: var(--muted); }
.ed-emptyfacts dd { margin: 0; font-variant-numeric: tabular-nums; }
.ed-acthint.warn { color: var(--amber); }

/* §P3R — AN EXPLANATION THE USER ASKS FOR.
 *
 * The rail used to carry a paragraph under every button describing what the
 * button did, so the workspace was mostly prose. These are those paragraphs:
 * a «?» the width of a character, and the sentence when it is opened. Errors,
 * progress and cost are NOT in here — they are still `.ed-acthint`, still
 * always visible, because a person cannot ask about a problem nobody has told
 * them they have. */
.ed-why { margin: -2px 0 4px; padding: 0 2px; }
.ed-why > summary {
  display: inline-block; cursor: pointer; list-style: none;
  width: 15px; height: 15px; line-height: 14px; text-align: center;
  border: 1px solid var(--line); border-radius: 50%;
  font-size: 10px; color: var(--muted); user-select: none;
}
.ed-why > summary::-webkit-details-marker { display: none; }
.ed-why > summary:hover { color: var(--fg); border-color: var(--muted); }
.ed-why[open] > summary { color: var(--fg); border-color: var(--muted); }
.ed-whytext {
  font-size: 10.5px; color: var(--muted); line-height: 1.35;
  margin: 4px 0 0; padding: 0 2px;
}
.ed-scanbar {
  height: 4px; border-radius: 3px; background: var(--panel2);
  border: 1px solid var(--line); overflow: hidden; margin: 1px 0 3px;
}
.ed-scanbar i { display: block; height: 100%; background: var(--accent); }

/* ── §18/§19: the source pipeline's one screen and its one queue ─────────
 *
 * Deliberately plain. What replaced two pages of amber warning rows should not
 * itself look like a dashboard — the whole claim of this stage is «the machine
 * did the work; here are the few things it could not settle», and a panel
 * dense with meters would contradict the sentence it is showing. */

.ed-srcsteps { display: grid; gap: 3px; margin: 3px 0 1px; }
.ed-srcstep { font-size: 11px; color: var(--green); line-height: 1.35; }
.ed-srcready {
  font-size: 12.5px; font-weight: 600; margin: 4px 0 2px;
}
.ed-srccounts { display: grid; gap: 2px; font-size: 11px; color: var(--muted); }
.ed-srccounts b { color: var(--fg, #e8ecf3); font-variant-numeric: tabular-nums; }

/* The queue REPLACES the list rather than sitting under it, so it scrolls with
   the panel and is not windowed: a queue long enough to need recycling is a
   pipeline that has failed at its job, and hiding that behind smooth scrolling
   would be the wrong fix. */
.ed-queue { position: relative; display: grid; gap: 8px; padding: 8px; }
.ed-qhead {
  display: flex; align-items: center; gap: 8px;
  font-size: 12px; padding-bottom: 4px; border-bottom: 1px solid var(--line);
}
.ed-qempty { color: var(--muted); font-size: 12px; padding: 14px 4px; }
.ed-qrow {
  display: grid; gap: 5px; padding: 10px 12px;
  border: 1px solid var(--line); border-radius: 10px; background: var(--panel2);
}
.ed-qrtime {
  font-size: 11px; color: var(--muted); font-variant-numeric: tabular-nums;
}
.ed-qrdetail { font-size: 12.5px; line-height: 1.4; }
.ed-qrheard { font-size: 12px; color: var(--muted); }
.ed-qrheard b { color: var(--fg, #e8ecf3); }
.ed-qrtext { font-size: 12px; line-height: 1.4; }
.ed-qracts { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 2px; }

/* §19 — WHAT SORT OF QUESTION THIS ROW IS, on the timestamp line where the eye
   already is. Small and quiet: it groups the queue, it is not the headline. */
.ed-qrkind {
  margin-left: 8px; padding: 1px 7px; border-radius: 999px;
  background: var(--panel); border: 1px solid var(--line);
  color: var(--muted); font-size: 10.5px; letter-spacing: .2px;
}

/* §17 — THE MARK ON A ROW THE ENGINE CHANGED. Two glyphs beside the row
   number, the same weight as the number: noticeable when looked for and
   invisible when not, which is what «маш жижиг indicator» asks for. */
.ed-rowop { margin-left: 5px; color: var(--accent, #6aa6ff); font-size: 11px; }

/* §17/§40 — the reasons, wherever they are printed. */
.ed-dop { margin-top: 10px; padding-top: 8px; border-top: 1px solid var(--line); }
.ed-dopk { font-size: 10.5px; letter-spacing: .4px; color: var(--muted);
           text-transform: uppercase; }
.ed-doph { font-size: 12.5px; margin: 3px 0 4px;
           font-variant-numeric: tabular-nums; }
.ed-dopwhy { margin: 0; padding-left: 16px; color: var(--muted);
             font-size: 11.5px; line-height: 1.55; }

/* §39 — «Автомат засвар», two counted lines above the review counter. */
.ed-srcfix { margin: 8px 0 4px; font-size: 12px; }
.ed-srcfixh { font-size: 10.5px; letter-spacing: .4px; color: var(--muted);
              text-transform: uppercase; margin-bottom: 3px; }
.ed-srcfixr { color: var(--muted); }
.ed-srcfixr b { color: var(--fg, #e8ecf3); font-variant-numeric: tabular-nums; }
.btn.xs {
  padding: 3px 9px; font-size: 11px; line-height: 1.5; border-radius: 7px;
  width: auto; flex: none;
}
/* A stage that has not run yet, in the same list as the ones that have. Never a
   ✓ and never green: the difference between «checked» and «not asked» is the
   whole point of showing it at all. */
.ed-srcstep.pending { color: var(--amber); }

/* ── §39: the Mongolian check's whole main screen ──────────────────────────
 *
 * Three lines and a button. The reference is explicit that nothing else
 * belongs here — «Үүнээс илүү олон warning/counter үндсэн дэлгэц дээр
 * хэрэггүй» — so there is no room reserved for a fourth number and no style
 * for a severity chip: adding one later means changing this block, which is
 * the point of not having it. */
.ed-qasum { display: grid; gap: 3px; margin: 2px 0 4px; }
.ed-qaok { font-size: 12px; color: var(--green); line-height: 1.4; }
.ed-qaneed { font-size: 12.5px; }
.ed-qaneed b { font-variant-numeric: tabular-nums; }

/* The suggestion and the reason, on a review card. The suggestion is the thing
   the eye should land on — it is what the button will write — so it is the
   only line here that is not muted. */
.ed-qrprop { font-size: 12px; line-height: 1.4; color: var(--muted); }
.ed-qrprop b { color: var(--green); }
.ed-qrwhy { font-size: 11px; color: var(--muted); line-height: 1.35; }

/* §7 — a row whose headline is the FILM'S words because the translation does
   not exist yet. Legible and obviously not Mongolian, the same distinction the
   overlay draws over the picture. */
.ed-rowtx b[data-layer="src"] { font-weight: 500; opacity: .82; }

/* ── §12/§18 — WHAT LANGUAGE THE FILM IS IN ──────────────────────────────────
 *
 * A control, on the rail, beside the button that reads the picture. It is here
 * because the reader cannot know: nothing detects a film's language from its
 * pixels, and until this existed every project was read with the Chinese
 * recogniser — invisible on a Chinese film, and total on a Korean one.
 */
.ed-langpick {
  display: grid; gap: 4px; margin: 2px 0 6px;
}
.ed-langpick > span {
  font-size: 10.5px; color: var(--muted); letter-spacing: .01em;
}
.ed-langpick select {
  width: 100%; box-sizing: border-box;
  background: var(--panel2); color: var(--text);
  border: 1px solid var(--line); border-radius: 8px;
  padding: 6px 8px; font: inherit; font-size: 12px; line-height: 1.2;
}
.ed-langpick select:hover { border-color: var(--line2, var(--line)); }
.ed-langpick select:focus-visible {
  outline: none; border-color: var(--accent);
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent) 30%, transparent);
}

/* ── §8/§36 — THE BLANK STAGE ────────────────────────────────────────────────
 *
 * A timeline with nothing on it, and a project whose film has not arrived yet,
 * are the same picture: nothing. What must NOT be there is the last film that
 * was — which is what the player used to keep, `src` and all, when «＋» made a
 * second timeline. Quiet on purpose: this is a state the user created, not a
 * fault, so it is one button and one line and no warning colour.
 */
.ed-emptystage {
  position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);
  display: grid; gap: 8px; justify-items: center; text-align: center;
  pointer-events: auto;
  /* OVER `.ep-layer`, WHICH COVERS THE WHOLE SCREEN AND TAKES POINTERS.
   *
   * MANUAL REMEDIATION. The overlay layer is mounted whether or not there is a
   * film now — a timeline holding a transferred band and no clip is an ordinary
   * state and used to get no overlay layer at all — so this note is the one
   * thing on a blank stage that a click must still reach. Both were
   * `position: absolute` with no z-index and the layer is appended after the
   * note, which put «＋ Видео оруулах» underneath a transparent rectangle.
   * There is nothing on the picture to select when there is no picture. */
  z-index: 2;
}
.ed-emptystage .muted { color: var(--muted); font-size: 12px; }

/* ═══ §39–§43 — THE CANVAS, THE FRAME AND THE TWO DRAG LAYERS ═══════════════
 *
 * `.plain` is the default state and is EXACTLY what the screen was before
 * framing existed: a box the size of the stage with the film letterboxed into
 * it by `object-fit: contain`. Every other rule here applies only once a
 * person has reframed something, which is why an existing project's picture
 * cannot have changed.
 */
.ed-canvas {
  position: absolute; inset: 0; margin: auto; overflow: hidden;
  display: flex; align-items: center; justify-content: center;
}
.ed-canvas:not(.plain) {
  inset: 0; width: auto; height: auto;
  max-width: 100%; max-height: 100%;
  /* `aspect-ratio` is set inline from the canvas the person chose. The two
     maxima keep it inside the stage whichever way round it is. */
  background: #000; border-radius: 4px;
  box-shadow: 0 0 0 1px rgba(255,255,255,.08);
}
.ed-canvas.ed-canvas-bars { background: #000; }
.ed-frame { position: absolute; inset: 0; overflow: hidden; }
.ed-canvas.plain .ed-frame { position: static; width: 100%; height: 100%; }
.ed-video.framed { position: absolute; object-fit: fill; }

/* §43 — the safe area, shown only while somebody is placing things. Two lines,
   not a shaded mask: a mask over the picture is exactly what a person framing
   a shot cannot see through. */
.ed-safe {
  position: absolute; left: 0; right: 0; pointer-events: none;
  border-top: 1px dashed rgba(251,191,36,.55);
  border-bottom: 1px dashed rgba(251,191,36,.55);
}
.ed-safe::after {
  content: "Хадмалын аюулгүй бүс"; position: absolute; right: 4px; bottom: 3px;
  font-size: 9.5px; letter-spacing: .06em; color: rgba(251,191,36,.85);
}

/* §41 — the transform handles. `.ed-fx` covers the canvas and is transparent
   to pointers except where a handle is, so a click on the picture still
   reaches the subtitle overlay underneath. */
.ed-canvas.tooled { z-index: 6; }
.ed-fx { position: absolute; inset: 0; z-index: 2; }
.ed-fx.transform { cursor: default; }
.ed-fxbody {
  position: absolute; inset: 6%; cursor: move;
  outline: 1px solid rgba(34,211,238,.75); outline-offset: -1px;
  background: rgba(34,211,238,.04);
}
.ed-fxh {
  position: absolute; width: 13px; height: 13px; border-radius: 3px;
  background: #22d3ee; box-shadow: 0 0 0 2px rgba(4,18,26,.75);
}
.ed-fxh.nw { left: calc(6% - 6px); top: calc(6% - 6px); cursor: nwse-resize; }
.ed-fxh.ne { right: calc(6% - 6px); top: calc(6% - 6px); cursor: nesw-resize; }
.ed-fxh.sw { left: calc(6% - 6px); bottom: calc(6% - 6px); cursor: nesw-resize; }
.ed-fxh.se { right: calc(6% - 6px); bottom: calc(6% - 6px); cursor: nwse-resize; }
/* §41 — WHILE THE FILM PLAYS THERE IS NOTHING ON IT BUT THE FILM. `.playing`
   is the class the timeline and the overlay layer already read. */
.ed.playing .ed-fx,
.ed.playing .ed-safe { display: none; }

.ed-fx.crop { cursor: crosshair; }
.ed-croprect {
  position: absolute; border: 1px solid #22d3ee;
  box-shadow: 0 0 0 9999px rgba(0,0,0,.5);
}

/* §37 — the transport's four value buttons, and the list each opens. */
.ed-pick {
  display: inline-flex; align-items: center; gap: 5px; flex: none;
  padding: 4px 9px; border-radius: 7px; cursor: pointer;
  background: var(--panel2); border: 1px solid var(--line); color: var(--ink);
  font-size: 11.5px; line-height: 1;
}
.ed-pick:hover { border-color: var(--accent); }
.ed-pick.on { border-color: var(--accent); color: var(--accent); }
.ed-pick u { text-decoration: none; opacity: .5; font-size: 9px; }
.ed-pick .ed-rate { font-style: normal; font-variant-numeric: tabular-nums; }
.ed-picklist {
  position: fixed; z-index: 90; min-width: 168px; padding: 4px;
  border-radius: 9px; background: var(--panel); border: 1px solid var(--line);
  box-shadow: 0 14px 38px rgba(0,0,0,.55);
}
.ed-picklist button {
  display: block; width: 100%; text-align: left; border: 0; cursor: pointer;
  background: transparent; color: var(--ink); padding: 7px 10px;
  border-radius: 6px; font-size: 12px;
}
.ed-picklist button:hover { background: var(--panel2); }
.ed-picklist button.on { color: var(--accent); }
.ed-picklist button b { display: block; font-weight: 600; }
.ed-picklist button small { display: block; color: var(--muted); font-size: 10.5px; }

/* §19 — «🟢 Sara · одоо засварлаж байна», and the read-only bar beside it. */
.ed-lock {
  display: inline-flex; align-items: center; gap: 7px; flex: none;
  padding: 3px 10px; border-radius: 999px; font-size: 11.5px;
  background: rgba(52,211,153,.12); border: 1px solid rgba(52,211,153,.35);
  color: var(--ink);
}
.ed-lock.readonly {
  background: rgba(251,191,36,.12); border-color: rgba(251,191,36,.4);
}
.ed-lock .who { font-weight: 600; }

/* ── §F/§M — LOCAL PREVIEW AND THE UPLOAD STATE ─────────────────────────────
   A file is in the project the moment it is chosen: the bin draws the row with
   a percentage on it, and the player shows the file off this machine while the
   bytes go up. Neither is a modal — «Upload must not block basic editing» is
   the whole point, and a dialog over the editor is exactly what blocks it. */

.ed-localchip{
  position:absolute;left:12px;bottom:12px;z-index:6;display:flex;
  align-items:center;gap:10px;max-width:calc(100% - 24px);
  padding:8px 12px;border-radius:10px;font-size:12px;
  color:#e8ecf6;background:rgba(9,12,22,.86);
  border:1px solid rgba(120,200,255,.3);backdrop-filter:blur(10px);
}
.ed-localchip b{font-size:12.5px;white-space:nowrap;overflow:hidden;
  text-overflow:ellipsis;max-width:220px}
.ed-localchip span{opacity:.72}

.ed-libup{
  display:block;font-style:normal;font-size:11px;margin-top:2px;
  color:var(--a-cyan,#22d3ee);
}
.ed-libup.bad{color:var(--a-danger,#f87171)}
.ed-librow.uploading{opacity:.92}
.ed-librow.uploading .ed-libthumb{outline:1px dashed rgba(120,200,255,.45)}

/* §A/§O — «АЖЛЫН ЯВЦ» MUST NOT SIT ON THE TRANSPORT.
   `#stJobs` is fixed at bottom:18px by an inline style in studio.js, which on
   this screen is exactly where the play button, the clock and the speed
   readout are. `final_edit.css` already lifts it for its own editor and for
   the same reason; this is the workspace's copy of that rule, and it needs
   `!important` for the same reason too. `.ed-host` is set on `.main` when the
   workspace mounts, so the lift applies only while it is on screen. */
body:has(.ed-host) #stJobs{bottom:96px !important;max-height:44vh !important}

/* ── §1/§2/§3 — the review queue as a place you can actually work ────────── */

/* THE COUNTER IS A CONTROL. It reads as one now: a pointer, a hover, and a
   focus ring, because the reported «I clicked it and nothing happened» was a
   user pressing the number rather than the button underneath it. */
.ed-srccounts.act, .ed-qaneed.act { cursor: pointer; border-radius: 8px; }
.ed-srccounts.act { padding: 4px 8px; margin: 0 -8px;
  border: 1px solid var(--warn-bg, #4a3a12); }
.ed-qaneed.act { padding: 4px 8px; margin: 0 -8px; }
.ed-srccounts.act:hover, .ed-qaneed.act:hover {
  background: var(--panel2); border-color: var(--accent);
}
.ed-srccounts.act:focus-visible, .ed-qaneed.act:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 1px;
}

/* THE CARD THE REST OF THE SCREEN IS SHOWING. One selection, said once. */
.ed-qrow { cursor: pointer; }
.ed-qrow.on { border-color: var(--accent); background: var(--panel); }

/* THE FINDING, IN DETAILS, beside the line it is about. Bordered off from the
   editable fields above it: this half is EVIDENCE and the half above is the
   document, and a user must never be unsure which one they are typing into. */
.ed-dreview {
  display: grid; gap: 5px; margin-top: 10px; padding: 10px;
  border: 1px solid var(--warn-bg, #4a3a12); border-radius: 10px;
  background: var(--panel2);
}
.ed-drwhy { font-size: 12.5px; line-height: 1.4; }
.ed-drtime, .ed-drnb {
  font-size: 11px; color: var(--muted); font-variant-numeric: tabular-nums;
}
.ed-drtext, .ed-drheard { font-size: 12.5px; line-height: 1.4; }
.ed-drheard { color: var(--muted); }
.ed-dracts { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 4px; }

/* The readiness headline when a speaker pass is still outstanding. Same shape
   as «бэлэн», a different colour, because it is a different claim. */
.ed-srcready.pending { color: var(--warn, #f5c451); }
