/* 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; }
/* THE READ-ONLY SOURCE LINE READS LIKE THE EDITABLE ONE. On the stages that
   may not edit it, «Эх мөр» is a div, and it is the same words at the same
   width — so it wraps and breathes the same way rather than running as one
   dense strip under the panel edge. */
.ed-dsrc {
  font-size: 12.5px; color: var(--ink); line-height: 1.45;
  white-space: pre-wrap; overflow-wrap: anywhere; word-break: break-word;
}
/* §1 — THE BOX IS AS TALL AS THE LINE IN IT, AND IT STAYS THAT WAY.
 *
 * THE DEFECT THIS ENDS, reported against DEV: «мөр сонгоход Details-ийн
 * текстийн талбай хэт нарийсч, эх мөр бүтнээрээ харагдахгүй, Монгол хадмал
 * харагдахгүй шахам, мөр болгоныг сонгоод panel-аа гараар сунгах шаардлагатай».
 *
 * `paintCueDetails` wrote `rows="2"` for the source line and `rows="3"` for the
 * Mongolian one, and it rewrites the whole panel on every selection — so a
 * long line was clipped to two lines, and dragging the handle to see it was
 * undone by clicking the next row. Two lines is nothing for the material this
 * product actually carries: a 60-character Chinese reading wraps to three at
 * this width, and a Mongolian sentence to four.
 *
 * THE BOX IS SIZED IN JAVASCRIPT (`growBox` in editor_shell.js), and that is a
 * measured choice rather than a default one. `field-sizing: content` is the
 * declarative way to say this and it does NOT grow a textarea in the Chromium
 * this product runs on: measured on DEV at 1366 wide, a 127px line came back
 * 42px with the property applied and supported (`CSS.supports` true,
 * `computed.fieldSizing === "content"`). A rule that does nothing is worse than
 * no rule, so it is not here. `min-height` remains the floor and `max-height`
 * the ceiling, and both apply to the height the script writes.
 *
 * THE CEILING IS THERE SO THE OTHER FIELD SURVIVES. Without it a long source
 * line pushes the timing inputs, the issues and every button below the fold,
 * which is «Монгол хадмал харагдахгүй шахам» from the other direction. Past it
 * the box scrolls inside itself. */
.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;
  line-height: 1.45;
  resize: vertical;
  min-height: 4.9em;
  max-height: 42vh;
  overflow-y: auto;
  /* Long CJK readings and Mongolian sentences both wrap; neither may widen the
     panel or reach sideways under the buttons. */
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}
/* A HEIGHT THE PERSON CHOSE OUTRANKS THE MEASUREMENT, which is what makes the
   drag handle still mean something once the box sizes itself. The attribute is
   what `growBox` checks before it measures anything, and the ceiling is lifted
   for it — a person who drags a box taller than 42vh has said they want it. */
.ed-dtext[data-kept] { max-height: none; }

.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; }
/* «Огт уншиж амжихгүй» is not a louder «уншиж амжихгүй»: it is the row that has
   to be answered first, so it is a different colour rather than a bigger one. */
.ed-dissue.critical { background: var(--red, #ff5d5d); color: #fff; }
.ed-rowbadge.crit { background: var(--red, #ff5d5d); color: #fff; }

/* ── уншигдах хугацаа (Details) ───────────────────────────────────────────
   The reading verdict, its two numbers and its repair, in the panel the rest
   of the editor already uses. No link out: the previous generation's
   «Монгол хэлний чанар» page is not part of this workflow. */
.ed-drt { display: grid; gap: 6px; margin-top: 8px; padding-top: 8px;
  border-top: 1px solid var(--line); }
.ed-drtstate { font-size: 12px; color: var(--amber); font-weight: 600; }
.ed-drt.critical .ed-drtstate { color: var(--red, #ff5d5d); }
.ed-drtnums { display: flex; flex-wrap: wrap; gap: 4px 14px; font-size: 11.5px;
  color: var(--muted); font-variant-numeric: tabular-nums; }
.ed-drtnums b { color: var(--ink); font-variant-numeric: tabular-nums; }
.ed-dacts { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 6px; }
/* PHASE D — THE PRIMARY DUBBING ACTIONS, ABOVE THE SCROLL.
   `.ed-dbody` is the scrolling half of this panel; this row is OUTSIDE it and
   `flex: none`, so «Дахин үүсгэх» and «Бүгдийг үүсгэх» stay on screen whatever
   the panel's height is. Phase C had them at the bottom of the scrolled body,
   which on a ~1000px display put the main act of the screen below the fold. */
.ed-dtop {
  display: flex; flex-wrap: wrap; gap: 5px; flex: none;
  padding: 7px 10px 0;
}
/* What the bulk press would do, in one line, before it is pressed. Amber is
   deliberately NOT used: this is not a warning, it is a count. */
.ed-dplan {
  flex: none; margin: 6px 10px 0; padding: 5px 8px; border-radius: 5px;
  font-size: 11px; line-height: 1.4; color: var(--muted);
  background: color-mix(in srgb, var(--ink) 6%, transparent);
  border-left: 2px solid var(--line);
}
.ed-dplan.ok { color: var(--muted); border-left-color: var(--green); }
.ed-dplan.run { color: var(--ink); border-left-color: var(--accent); }
.ed-dmeta { font-size: 10.5px; color: var(--muted); margin-top: 4px; }
/* PHASE E - the recording block, inside the dubbing Inspector rather than on a
   screen of its own. A hairline and a tint, so it reads as one act within the
   panel and not as a second panel wedged into it. */
.ed-drec {
  margin-top: 8px; padding: 7px 8px; border-radius: 6px;
  border: 1px solid var(--line);
  background: color-mix(in srgb, var(--ink) 4%, transparent);
  display: grid; gap: 4px;
}
.ed-drec .ed-drow { align-items: center; gap: 6px; }
.ed-drec audio { max-width: 100%; }
/* PHASE C — the Dubbing Audio Inspector's three controls. Deliberately the
   same metrics as `.ed-dtext` above rather than a look of their own: this is
   the Details panel, and a second visual language inside it would read as a
   second panel. `field-sizing` is not used — it computes and does not grow
   (measured), so the widths are stated. */
.ed-dsel, .ed-dnum {
  background: #0f1115; color: var(--ink); border: 1px solid var(--line);
  border-radius: 6px; padding: 5px 7px; font-size: 12.5px; font-family: inherit;
  box-sizing: border-box; max-width: 100%;
}
.ed-dsel { width: 100%; }
.ed-dnum { width: 96px; }
.ed-dsel:focus, .ed-dnum:focus { outline: none; border-color: var(--accent); }
.ed-drow { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
/* A warning that is one line and one colour. The Inspector is not a QA screen
   and Phase C deliberately surfaces only what `duration_preflight` and the
   generation record already say. */
.ed-dwarnrow {
  font-size: 11.5px; line-height: 1.4; color: var(--amber);
  background: color-mix(in srgb, var(--amber) 12%, transparent);
  border-left: 2px solid var(--amber); border-radius: 0 5px 5px 0;
  padding: 5px 8px; margin: 2px 0;
}
/* 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;
}
/* The selected stretch of film — what «Сонгосон хэсгийг дахин уншуулах» will
   read. On the ruler, under the ticks, so it reads as a span of TIME. */
.etl-range {
  position: absolute; top: 0; bottom: 0; pointer-events: none;
  background: color-mix(in srgb, var(--accent) 24%, transparent);
  border-left: 2px solid var(--accent); border-right: 2px solid var(--accent);
  box-sizing: border-box;
}
.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; }

/* ── PHASE B — THE DUBBING AUDIO ROW ────────────────────────────────────────
 *
 * Same plate, same geometry, same restraint as §25/§26: the lane is meant to
 * be READ ALONGSIDE the Mongolian row above it, and a row of five saturated
 * colours would win every glance and tell the user nothing they were looking
 * for. So the block is a quiet slate plate, and the state is a DOT at its head
 * plus a border — one accent, in the same place on every block, which is what
 * actually reads at a timeline's width.
 *
 * The dot is deliberately the loudest part: at the zoom a whole film fits in,
 * a two-second take is fourteen pixels wide and the label is gone. The dot is
 * still there, and «which of my lines have no audio» is answerable by scanning
 * one row for gaps and pale dots without reading a single word.
 */
.etl-t-dub { background: #12151d; }
/* NO HORIZONTAL PADDING ON THE BLOCK ITSELF — THE INSET IS THE DOT'S.
 *
 * THE DEFECT THIS ENDS, measured on DEV at fit zoom on a 228-second film.
 * `* { box-sizing: border-box }` means a `padding-left: 6px` plus a 1px border
 * on each side is a FLOOR: an element told to be 6.8px wide renders 8px. The
 * ruler places these blocks by their seconds, so a lane of short takes had
 * every block overrunning its neighbour by more than a pixel — eighteen
 * overlapping pairs out of 103, and FOUR blocks whose own centre belonged to
 * the block after them, because the later sibling paints on top.
 *
 * A click there selected the NEXT line, and everything downstream was then
 * faithful to the wrong one: the Inspector named it, «Энэ мөр рүү очих» went
 * to it, and «Өөрөө бичих» recorded over it — measured, a take meant for
 * seg-00031 was saved to seg-00032 with nothing anywhere saying so. That is
 * §10's «no audio block may silently bind to the neighbouring cue», reached
 * through the pointer instead of through the pairing.
 *
 * The 6px stays; it is a MARGIN on the dot, which does not floor the parent.
 * A block narrower than its own dot now clips it — `overflow: hidden` already
 * does that to the label — instead of growing over the line beside it.
 */
.etl-dub {
  position: absolute; top: 5px; height: calc(var(--etl-h, 44px) - 12px);
  border-radius: 6px; overflow: hidden;
  background: linear-gradient(180deg, #1c2430, #161d27);
  border: 1px solid #37424f;
  display: flex; align-items: center; gap: 5px;
  cursor: pointer; box-shadow: 0 1px 2px rgba(0, 0, 0, .35);
}
.etl-dubdot {
  flex: 0 0 auto; width: 7px; height: 7px; border-radius: 50%; margin-left: 6px;
  background: #6b7789; pointer-events: none;
}
/* CURRENT — the take on the row is the take for the row. Green, and no
   stripe: «nothing to do here» must not draw the eye. */
.etl-dub.st-current { border-color: color-mix(in srgb, var(--green) 52%, #1b2333); }
.etl-dub.st-current .etl-dubdot { background: var(--green); }
/* MISSING — nothing was ever kept. An OUTLINE rather than a plate, because an
   absence should not look like a thing that is present. */
.etl-dub.st-missing {
  background: none; border-style: dashed;
  border-color: color-mix(in srgb, #7c8798 55%, #1b2333);
}
.etl-dub.st-missing .etl-dubdot { background: none; box-shadow: inset 0 0 0 1.5px #7c8798; }
.etl-dub.st-missing .etl-cuetext { color: #93a0b3; }
/* DIRTY — a take exists and is no longer this row's. Amber, the same word the
   subtitle rows use for «needs a look», and a stripe: this one IS a to-do. */
.etl-dub.st-dirty { border-color: color-mix(in srgb, var(--amber) 62%, #2a2415); }
.etl-dub.st-dirty .etl-dubdot { background: var(--amber); }
.etl-dub.st-dirty::before,
.etl-dub.st-failed::before,
.etl-dub.st-generating::before {
  content: ""; position: absolute; left: 0; right: 0; top: 0; height: 3px;
  pointer-events: none;
}
.etl-dub.st-dirty::before { background: var(--amber); }
.etl-dub.st-failed { border-color: color-mix(in srgb, var(--red) 66%, #2a1618); }
.etl-dub.st-failed .etl-dubdot { background: var(--red); }
.etl-dub.st-failed::before { background: var(--red); }
/* GENERATING — the only state that is about this second, so it is the only one
   that moves. Slow enough to read as «working», not as a warning light. */
.etl-dub.st-generating { border-color: color-mix(in srgb, var(--accent) 62%, #1b2333); }
.etl-dub.st-generating::before { background: var(--accent); }
.etl-dub.st-generating .etl-dubdot {
  background: var(--accent); animation: etl-dubpulse 1.4s ease-in-out infinite;
}
@keyframes etl-dubpulse { 0%, 100% { opacity: 1; } 50% { opacity: .25; } }
@media (prefers-reduced-motion: reduce) {
  .etl-dub.st-generating .etl-dubdot { animation: none; }
}
.etl-dub.sel {
  box-shadow: 0 0 0 2px var(--accent), 0 2px 8px rgba(0, 0, 0, .5); z-index: 3;
}
.etl-dub .etl-cuetext { padding: 0 6px 0 0; color: #dbe2ee; }
/* PHASE C — A WINDOW SOMEBODY SET BY HAND, and a grip to set it with.
   The dashes read as «this length is a decision, not the plan», which is the
   one thing a second person needs to know before changing it back. */
.etl-dub.pinned { border-style: dashed; }
.etl-dub .etl-grab { z-index: 2; }

.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; }
/* A row whose Mongolian now lives inside the joined neighbour: its own words,
   dimmed, so the list never reads as if the translation vanished. */
.ed-rowjoined { color: var(--muted); 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 FILM'S OWN MARKS, AND THE PREVIEW DOES NOT
   PRETEND TO REMOVE THEM.

   The removal is an ffmpeg filter — `removelogo` under a measured mask, or
   `delogo` — and the browser has no equivalent of either. A box painted to
   look like the filled picture would be lying about the one thing the tool
   exists for, so the region is a warm dashed frame with its name on it and
   a soft plate underneath: present, obviously an instruction, obviously not
   the finished frame. The panel says the same thing in words.

   The container does not take pointers and its children do, so a click on
   the picture between two regions still reaches the layer and clears the
   selection — §15, which a full-bleed overlay would have broken. */
.ep-logos { position: absolute; inset: 0; pointer-events: none; }
.ep-logos > .ep-obj { pointer-events: auto; }
.ep-logo { border-radius: 2px; }
.ep-logofill { position: absolute; inset: 0; display: block; border-radius: 2px;
  pointer-events: none;
  border: 1.5px dashed rgba(255, 176, 74, .85);
  background: rgba(255, 176, 74, .10);
  backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px); }
.ep-logo.sel > .ep-logofill { border-style: solid;
  border-color: rgba(255, 201, 120, 1); background: rgba(255, 176, 74, .17); }
/* Off, or not on at this second: still drawn, because hiding a region takes
   away the only thing a person can grab to bring it back. */
.ep-logo.ep-logo-off > .ep-logofill { border-style: dotted; opacity: .45;
  background: transparent;
  backdrop-filter: none; -webkit-backdrop-filter: none; }
.ep-logo.ep-logo-later > .ep-logofill { opacity: .6; }
.ep-logotag { position: absolute; left: 0; top: -16px; font-size: 10px;
  font-weight: 600; letter-spacing: .04em; white-space: nowrap;
  padding: 1px 6px; border-radius: 5px 5px 0 0; pointer-events: none;
  background: rgba(120, 70, 10, .92); color: #ffe2b8; }
.ep-logo > .ep-h { background: #ffd39a; border-color: #b8792f; }
/* THE LINE BOX IS NOT A STYLESHEET'S OPINION — AND IT IS NOT A CONSTANT EITHER.
   libass advances one line by exactly ASS `Fontsize`, and `Fontsize` is the
   FACE's own `usWinAscent + usWinDescent` box: 1.1172 for Liberation Sans,
   1.2207 for Carlito, 1.5190 for Noto Sans. This said 1.22, then 1.1172, and
   both were one face's number standing in for fourteen.
   `editor_picture.js::faceRatio` sets it per paint from `font_css.em_ratio`,
   which the server reads out of the file the render will open; what is left
   here is only the value before the first payload lands.
   AND THE MARK NEEDS ONE TOO. It is one line and never wraps, but it hangs from
   the BOTTOM of its box — so the box's height is exactly what decides where its
   letters sit, and its face is usually not the caption's. */
/* `> span` — THE OUTER ONE. `.ep-subline` is a span inside `.ep-sub` too, so an
   unscoped selector set ITS line height as well, and a rule beats an inherited
   value: the plate boxes came out 1.1172 em tall inside slots the export makes
   `em_ratio` tall, so on Carlito they were 48.9px in a 53.5px slot and the
   plates showed a 4.5px gap between them instead of tiling. Measured on DEV
   against `32c8c80`. The line spans inherit the outer's unitless line-height,
   which is what `editor_picture.js` sets per paint from the face's own ratio. */
.ep-mark > span, .ep-sub > span { display: block; white-space: pre-wrap;
  line-height: 1.1172; }
/* THE MARK IS ONE LINE AND THE FILE GIVES IT NO CHOICE. `build_ass` writes
   «ASHD Kino» as a single `Dialogue` under `WrapStyle: 2`, so libass lets it
   hang off the edge rather than break it. `pre-wrap` above let the browser break
   it at its space instead: measured on a 540-wide frame, the editor drew the
   mark over TWO lines — a 141px-tall box against the file's 70px — and its
   centre landed 0.028 of the frame above where the export put it. */
.ep-mark > span { white-space: nowrap; }
/* «ASHD Kino» — THE BRONZE METAL LOOK (2026-09-17, from a reference frame).
   Montserrat 800, a bronze-to-grey vertical gradient clipped to the glyphs, a
   hairline dark stroke, and a light-above / dark-below drop shadow for the
   bevel. `!important` because editor_picture.js and final_edit.js write
   colour, text-shadow, stroke and face onto the node inline on every paint;
   the gradient needs the fill transparent and the inline text-shadow OFF,
   or the shadow paints over the gradient inside the glyphs. Both previews —
   the editor's `.ep-mark` and Бичлэг янзлах's `.fe-mark` — are one rule so
   they cannot disagree. PREVIEW ONLY: `build_ass` still burns the mark from
   the model's own colour, so the exported file does not carry this look. */
.ep-mark > span, .fe-mark {
  /* THE FACE IS A FILE NOW, NOT A REQUEST TO GOOGLE. `subtitle_fonts.py` ships
     Montserrat-ExtraBold.ttf beside the four subtitle faces and
     `subtitle_fonts.css` declares it, so the preview, the packaged EXE and the
     render all open the same outlines — see `MARK_FONT` for what the old
     `fonts.googleapis.com` link did on a machine that could not reach it. */
  font-family: "Montserrat ExtraBold", "Segoe UI", Arial, sans-serif !important;
  font-weight: 800 !important;
  letter-spacing: .035em !important;
  background: linear-gradient(180deg, #d3cbc3 0%, #a99a8e 20%, #75665d 43%,
    #4b3e38 55%, #8b796e 73%, #382e2a 100%);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  color: transparent !important;
  text-shadow: none !important;
  /* NO STROKE. A text-stroke is centred on the outline, so with the fill
     transparent its inner half lay over the gradient and every contour of
     the glyph showed as a line — «A» read as strokes glued together. The
     bevel is the two offset drop-shadows below; the stroke is zeroed so the
     renderers' inline outline cannot bring it back. */
  -webkit-text-stroke: 0 !important;
  /* The softer bevel: one dark edge below and a wider soft shadow; the
     white highlight above was the third look shown and the one not chosen.
     IN EMS, AND THAT IS THE WHOLE POINT. These were 1px, 2px and 3px — a
     hairline at any size, so the same mark at 13 px and at 49 px was two
     different pictures and the export could never match the preview at a
     resolution the preview was not being shown at. 0.075em × 13.2px = 0.99px,
     so the look approved at the default mark size is the look that is still
     drawn there. `final_edit.py` MARK_EDGE_DY / MARK_SHADOW_DY /
     MARK_SHADOW_BLUR carry the same three numbers and
     `tests/test_final_edit_mark.py` reads this file to prove they still do. */
  filter: drop-shadow(0 .075em 0 rgba(40, 29, 24, .85))
    drop-shadow(0 .15em .225em rgba(0, 0, 0, .5));
  /* «БИЧГИЙН ТОДРОЛ», WHICH THIS LOOK HAD TAKEN AWAY.
     The slider's number reaches the mark as an ALPHA IN A COLOUR — that is
     the rule the whole of editor_picture.js keeps, so the fill, the outline
     and the shadow can fade by their own amounts the way ASS fades them. The
     gradient above ignores it: the fill has to be transparent for
     `background-clip: text` to show through, so the alpha the renderers wrote
     into `color` landed on nothing and the mark stayed fully opaque at every
     position of the slider.
     The gradient, the zeroed stroke and the bevel are ONE image, and the
     slider scales all three by the same factor — which is exactly what
     `markAlpha` already did to the three alphas separately. So the factor is
     read here, from a property the two renderers write beside the size and
     the face; the number still has one owner and there is no second copy of
     the look. Falls back to 1 so a mark painted before the property is
     written is visible, never invisible. */
  opacity: var(--ashd-mark-alpha, 1);
}
/* ONE BOX PER LINE, SHRINK-TO-FIT, NO RE-WRAP — AND THE BOXES TILE.
   `BorderStyle: 3` plates each LINE tight to its glyphs, not the paragraph, so a
   plate painted on the block above was as wide as «Mөрийн өргөн» whatever the
   line said — 720px against the file's 322px on the user's own settings.
   `inline-block` is what makes it tight; `nowrap` is the stylesheet half of the
   ASS header's `WrapStyle: 2`, because the breaks are `wrapText`'s and the
   browser may not invent others.
   NO VERTICAL PADDING AND NO NEGATIVE MARGIN: the export pads sideways only
   (`\ybord1`) and `\clip`s each plated line to its own slot one line box tall,
   so the plates MEET rather than overlap — two translucent plates that overlap
   compound into a darker strip, which is what `d697bd1` fixed. The box is
   exactly `line-height` tall and the plate fills it. */
.ep-sub .ep-subline { display: inline-block; white-space: nowrap; }

/* §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. */
/* `> span` — THE OUTER ONE ONLY. The lines are their own spans now, and an
   unscoped selector faded the caption twice (.74² = .55) and drew a dashed
   outline round every line instead of round the block. */
.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; }

/* «Лого арилгах» — the regions, listed. A row is a button because
   picking one is the whole of what it does, and the name on it is the name
   on the box on the picture. */
.ep-logohead { display: flex; align-items: center; justify-content: space-between;
  gap: 8px; margin-bottom: 7px; font-size: 11px; color: var(--muted); }
.ep-loglist { display: grid; gap: 4px; margin-bottom: 9px; }
.ep-logitem { display: flex; align-items: center; justify-content: space-between;
  gap: 8px; width: 100%; text-align: left; cursor: pointer;
  background: var(--panel2); color: var(--muted);
  border: 1px solid var(--line); border-radius: 7px;
  padding: 5px 9px; font-size: 11px; }
.ep-logitem:hover { border-color: #b8792f; }
.ep-logitem.on { border-color: #b8792f; background: #2a2116; color: #ffe2b8; }
.ep-logitem.off { opacity: .55; }
.ep-logitem em { font-style: normal; font-size: 10px; opacity: .8; }

/* «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 8: over `.ep-layer` (the blur band and ASHD Kino, which must not be
 * grabbable while a band is being drawn) and over the two things that also
 * float on the picture — `.ed-localchip` and `.ed-canvas.tooled`, both 6. It
 * WAS 3, which is under both. Still under `.ed-overlaypanel` (40) and the
 * right-click menus (90): those are deliberately on top of everything. */
.ed-region { position: absolute; inset: 0; z-index: 8; 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; }

/* WHILE THE BAND IS BEING PLACED, NOTHING ELSE IS ON THE PICTURE.
 *
 * THE DEFECT THIS ENDS, reported in the user's own words: «хадмал байршлаа
 * тохируулаад батлах гэсэн нь уншиж байгаа хэсгийн ард нь орчихоор ... дарж
 * чадахгүй байна» — the band was drawn, «Хадмал байршил батлах» appeared, and
 * it could not be pressed.
 *
 * IT WAS NEVER A DRAWING BUG. `#stJobs` — «Ажлын явц», the panel that reports
 * the reading in progress — is `position: fixed; bottom: 18px; z-index: 60`
 * from an inline style in `studio.js`, lifted to `bottom: 96px` on this screen
 * by the rule further down this file. A subtitle lives at the BOTTOM of the
 * frame, so `editor_region.js` puts the two buttons at the bottom of the
 * picture, which is precisely where a fixed panel at z-index 60 is. Raising
 * the layer cannot answer that: 60 belongs to a fixed box on `document.body`
 * and the picker lives inside the workspace's own stacking context.
 *
 * So the panels step aside for as long as the gesture lasts. Selection mode is
 * entered and left on purpose and takes seconds; `#stJobs` polls and comes
 * back with the same job, and the local chip is redrawn by the next
 * `paintStage`. Losing sight of a progress bar for that long is not comparable
 * to losing the button the whole mode exists for.
 *
 * BOTH OF THEM, because both are the same bug: `.ed-localchip` is z-index 6 at
 * the bottom-left of the same picture, over the same buttons whenever a film
 * is still going up. */
body.ed-region-on #stJobs { display: none !important; }
.ed.regionon .ed-localchip { display: 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); }

/* «Автоматаар зассан» — the list behind the number, with «Буцаах» on every row. */
.ed-qahist { margin: 4px 0 6px; font-size: 12px; }
.ed-qahist > summary { cursor: pointer; color: var(--green); font-weight: 600; }
.ed-qahrow { padding: 4px 0 4px 8px; border-left: 2px solid var(--line, #3a3f4a); margin: 4px 0; }
.ed-qahhead { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.ed-qahhead .btn { margin-left: auto; }
.ed-qahchange { color: var(--muted, #9aa0aa); margin-top: 2px; word-break: break-word; }
.ed-qahchange s { opacity: .7; }
