@import url('brand/tokens.css');
@import url('brand/fonts.css');
@import url('brand/brand.css');

/* console.css — staff console V2 ONLY (console.html). Self-contained: the console no longer loads
   style.css, so the few rules it used from there (tiles, subtitle bubbles, [hidden]) live here too.
   Light theme only (owner's decision). Type scale: 12 / 14 / 17 / 24 px for all UI chrome.
   Hover on controls must change the background or the top border by >= 3:1 (audit measures it
   against a white backdrop), so dark-bar buttons use SOLID colours and a light edge on hover. */

:root {
  color-scheme: light;
  --pg: rgb(var(--color-bg));
  --surface: rgb(var(--color-surface));
  --ink: rgb(var(--color-text));
  --muted: rgb(var(--color-text-muted));
  --line: rgb(var(--color-border));
  --line-strong: rgb(var(--neutral-400));
  --soft: rgb(var(--color-surface-2));
  --soft2: rgb(var(--neutral-200));
  --accent: rgb(var(--color-primary));
  --accent-hover: rgb(var(--color-primary-hover));
  --accent-soft: rgb(var(--color-primary-soft));
  --accent-ink: rgb(var(--color-on-primary));
  --danger: rgb(var(--color-danger-fill));
  --danger-hover: rgb(var(--color-danger));
  --danger-soft: rgb(var(--color-danger-soft));
  --warn: rgb(var(--color-warning));
  --warn-soft: rgb(var(--color-warning-soft));
  --stage: rgb(var(--neutral-950));
  --tile: rgb(var(--neutral-900));
  --tile-ink: rgb(var(--neutral-100));
  --bar: rgb(var(--neutral-900));
  --bar-btn: rgb(var(--neutral-800));
  --bar-btn-ink: rgb(var(--neutral-100));
  --bar-edge: rgb(var(--neutral-100));
  --focus-dark: rgb(var(--brand-300));
  --font: var(--font-sans);
  --fs-s: 12px;
  --fs-m: 14px;
  --fs-l: 17px;
  --fs-xl: 24px;
  --r-s: var(--radius-sm);
  --r: var(--radius-md);
  --shadow-pop: 0 12px 40px rgba(0, 0, 0, .22);
  --hdr-h: 56px;
  --film-h: 104px;
  --film-w: 180px;
  --gap: 10px;
  --ctrl-h: 72px;
  --z-header: 10;
  --z-sheet: 40;
  --z-menu: 60;
  --z-toast: 80;
  --z-lightbox: 90;
  --z-gate: 100;
}

/* ── Base ──────────────────────────────────────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; }
[hidden] { display: none !important; }
html { height: 100%; -webkit-text-size-adjust: 100%; }
body.console {
  --rail-w: clamp(300px, 26vw, 520px); /* right column of .console-main; the lobby banner row stops at it */
  margin: 0;
  height: 100vh;
  height: 100dvh;
  display: grid;
  grid-template-rows: auto auto minmax(0, 1fr);
  grid-template-columns: minmax(0, 1fr);
  overflow: hidden;
  background: var(--pg);
  color: var(--ink);
  font: 400 var(--fs-m)/1.5 var(--font);
}
h1, h2, h3, h4, p { margin: 0; }
button, input, select, textarea { font: inherit; color: inherit; }
img { max-width: 100%; }
a { color: var(--accent); }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.stagebar :focus-visible, .call-controls-panel :focus-visible, #grid :focus-visible,
.cam-dots :focus-visible, .peek:focus-visible, #docLightbox :focus-visible { outline-color: var(--focus-dark); }

.ic {
  width: 1em;
  height: 1em;
  flex: none;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
  vertical-align: -0.125em;
}

/* Buttons: this base also dresses every button console.js builds (kiosk rows, rental actions…). */
button, .btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  min-height: 36px;
  padding: 7px 14px;
  border: 1px solid var(--line);
  border-radius: var(--r-s);
  background: var(--surface);
  color: var(--ink);
  font-size: var(--fs-m);
  font-weight: 600;
  line-height: 1.2;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  transition: background-color .12s, border-color .12s, color .12s;
}
button:hover, .btn:hover { border-color: var(--accent); }
button:active { transform: translateY(1px); }
button:disabled, .btn[disabled] { opacity: .45; cursor: not-allowed; transform: none; }
button:disabled:hover { border-color: var(--line); }
.btn-sm { min-height: 32px; padding: 5px 10px; }
.btn-primary, button.primary, a.primary {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-ink);
}
.btn-primary:hover, button.primary:hover, a.primary:hover { background: var(--accent-hover); border-color: var(--ink); }
button.danger, .btn-danger { background: var(--danger); border-color: var(--danger); color: #fff; }
button.danger:hover, .btn-danger:hover { background: var(--danger-hover); }

select, textarea,
input[type="text"], input[type="search"], input[type="password"], input[type="date"], input[type="number"] {
  min-height: 36px;
  max-width: 100%;
  padding: 6px 10px;
  border: 1px solid var(--line);
  border-radius: var(--r-s);
  background: var(--surface);
  color: var(--ink);
  font-size: var(--fs-m);
}
select { cursor: pointer; }
select:hover, textarea:hover, input[type="text"]:hover, input[type="search"]:hover { border-color: var(--line-strong); }
select:disabled { opacity: .55; cursor: not-allowed; }
input[type="range"] { accent-color: var(--accent); }

.muted { color: var(--muted); }
.hint { font-size: var(--fs-s); color: var(--muted); }
.eyebrow {
  font-size: var(--fs-s);
  font-weight: 600;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--muted);
}
.inline { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.field { display: grid; gap: 5px; }
.field > label { font-size: var(--fs-s); font-weight: 600; }
.opt { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.card { background: var(--surface); border: 1px solid var(--line); border-radius: var(--r); }
/* minmax(0,1fr): an implicit `auto` column grows to the rows' nowrap text (kiosk names), which pushed
   the row's "Gọi" button past the right edge of the rail on PROD (26/09). */
.list { display: grid; grid-template-columns: minmax(0, 1fr); }
.empty { color: var(--muted); padding: 8px 0; }
.card.list > .empty { padding: 12px 16px; }
.status { font-size: var(--fs-s); color: var(--muted); }
.status:empty { display: none; }
.status-err { color: rgb(var(--color-danger)); }

/* Switch: a <button aria-pressed>/.active (console.js writes its text — hidden here) or a checkbox. */
button.tog, input.tog {
  appearance: none;
  -webkit-appearance: none;
  position: relative;
  flex: none;
  width: 40px;
  min-width: 40px;
  height: 24px;
  min-height: 24px;
  margin: 0;
  padding: 0;
  border: 1px solid var(--line-strong);
  border-radius: 999px;
  background: var(--soft2);
  color: transparent;
  font-size: 0;
  overflow: hidden;
  cursor: pointer;
}
button.tog::after, input.tog::after {
  content: "";
  position: absolute;
  top: 3px;
  left: 3px;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 1px 2px rgba(0, 0, 0, .35);
  transition: transform .15s;
}
.tog.active, button.tog[aria-pressed="true"]:not(.off), input.tog:checked { background: var(--accent); border-color: var(--accent); }
.tog.active::after, button.tog[aria-pressed="true"]:not(.off)::after, input.tog:checked::after { transform: translateX(16px); }
button.tog:hover, input.tog:hover { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
input.tog:disabled { opacity: .5; cursor: not-allowed; }

/* ── Header ────────────────────────────────────────────────────────────────────────────── */
.console-header {
  position: relative;
  z-index: var(--z-header);
  display: flex;
  align-items: center;
  gap: 14px;
  min-width: 0;
  min-height: var(--hdr-h);
  padding: 0 16px;
  background: var(--surface);
  border-bottom: 1px solid var(--line);
}
.brand { display: inline-flex; align-items: center; gap: 8px; flex: none; font-size: var(--fs-l); font-weight: 700; }
.brand .ic { width: 22px; height: 22px; color: var(--accent); }
#queueInfo {
  flex: 0 1 auto;
  min-width: 0;
  max-width: 36ch;
  font-size: var(--fs-s);
  color: var(--muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
#queueInfo.conn-lost { max-width: none; color: rgb(var(--color-danger)); font-weight: 600; }
.callinfo { flex: 1 1 auto; min-width: 0; display: flex; align-items: center; justify-content: center; gap: 10px; }
body:not(.console-incall) .callinfo > * { display: none; }
.live-dot { width: 8px; height: 8px; flex: none; border-radius: 50%; background: var(--danger); }
#screenpop { min-width: 0; display: flex; align-items: baseline; gap: 10px; white-space: nowrap; overflow: hidden; }
#screenpop .sp-name { flex: 0 0 auto; max-width: 24ch; font-weight: 600; overflow: hidden; text-overflow: ellipsis; }
#screenpop .sp-sub { min-width: 0; color: var(--muted); overflow: hidden; text-overflow: ellipsis; }
.src-badge {
  display: inline-flex;
  align-items: center;
  flex: none;
  padding: 1px 8px;
  border-radius: 999px;
  background: var(--soft2);
  color: var(--muted);
  font-size: var(--fs-s);
  font-weight: 600;
}
.call-timer { flex: none; color: var(--muted); font-variant-numeric: tabular-nums; }
.hdr-right { display: flex; align-items: center; gap: 8px; flex: none; margin-left: auto; }
/* In a call on a narrower desktop the header centre (kiosk name + timer) needs the room. */
@media (max-width: 1199px) {
  body.console-incall .brand-name, body.console-incall .agent-name { display: none; }
  body.console-incall #queueInfo:not(.conn-lost) { max-width: 18ch; }
}

/* #readyToggle: console.js rewrites its text ("Sẵn sàng"/"Tạm nghỉ"), so the switch is pseudo-elements. */
.ready-toggle {
  position: relative;
  padding: 6px 12px 6px 52px;
  border-radius: 999px;
}
.ready-toggle::before {
  content: "";
  position: absolute;
  top: 50%;
  left: 8px;
  width: 34px;
  height: 20px;
  margin-top: -10px;
  border-radius: 999px;
  background: var(--accent);
  transition: background-color .15s;
}
.ready-toggle::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 10px;
  width: 16px;
  height: 16px;
  margin-top: -8px;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 1px 2px rgba(0, 0, 0, .3);
  transform: translateX(14px);
  transition: transform .15s;
}
.ready-toggle.off::before, .ready-toggle[aria-pressed="false"]::before { background: rgb(var(--neutral-300)); }
.ready-toggle.off::after, .ready-toggle[aria-pressed="false"]::after { transform: none; }
.ready-toggle:hover { border-color: var(--accent); background: var(--accent-soft); }
.ready-toggle.pulse { animation: rt-pulse 1.2s ease-in-out infinite; }
@keyframes rt-pulse { 50% { transform: scale(1.06); } }

.ibtn { width: 36px; padding: 0; border-color: transparent; background: transparent; }
.ibtn .ic { width: 18px; height: 18px; }
.ibtn:hover { border-color: var(--accent); background: var(--soft); }
.ibtn[aria-expanded="true"], .avatar[aria-expanded="true"] { border-color: var(--accent); background: var(--accent-soft); color: var(--accent); }
.ic-ring-off { display: none; }
body.ring-off .ic-ring-on { display: none; }
body.ring-off .ic-ring-off { display: inline; }
.avatar { gap: 8px; padding: 3px 8px 3px 3px; border-radius: 999px; }
.avatar-a {
  display: grid;
  place-items: center;
  width: 28px;
  height: 28px;
  flex: none;
  border-radius: 50%;
  background: var(--accent-soft);
  color: var(--accent);
  font-size: var(--fs-s);
  font-weight: 700;
}
.avatar-a img { display: block; width: 100%; height: 100%; border-radius: 50%; object-fit: cover; }
.agent-name { max-width: 16ch; overflow: hidden; text-overflow: ellipsis; }
#ringBlocked { border-color: var(--warn); background: var(--warn-soft); color: var(--warn); font-size: var(--fs-s); min-height: 32px; }
#ringBlocked:hover { background: var(--warn); color: #fff; }
.phone-grid-btn { display: none; }

/* ── Menus / popovers (position:fixed; console-ui.js sets left/top/max-height) ──────────── */
.menu {
  position: fixed;
  top: 0;
  left: 0;
  z-index: var(--z-menu);
  display: grid;
  align-content: start;
  gap: 10px;
  width: max-content;
  min-width: 240px;
  max-width: min(340px, calc(100vw - 16px));
  overflow: auto;
  overscroll-behavior: contain;
  padding: 14px;
  border: 1px solid var(--line);
  border-radius: var(--r);
  background: var(--surface);
  color: var(--ink);
  box-shadow: var(--shadow-pop);
  font-size: var(--fs-m);
}
.menu-wide { width: min(340px, calc(100vw - 16px)); }
.menu h4 {
  font-size: var(--fs-s);
  font-weight: 600;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: .05em;
}
.menu hr { width: 100%; margin: 2px 0; border: 0; border-top: 1px solid var(--line); }
.menu > .btn { justify-self: start; }
.menu select { width: 100%; }
#menuRing input[type="range"] { width: 130px; }
.avatar-row { display: grid; grid-template-columns: auto 1fr; align-items: center; gap: 6px 12px; }
.avatar-row .status { grid-column: 1 / -1; }
.avatar-lg { width: 56px; height: 56px; font-size: var(--fs-l); }
.avatar-actions { display: flex; flex-wrap: wrap; gap: 6px; }
.ring-tone { display: grid; gap: 6px; padding-top: 8px; border-top: 1px solid var(--line); }
.ring-tone > label { font-size: var(--fs-s); font-weight: 600; }
.ring-tone-pick { display: flex; align-items: center; gap: 6px; }
.menu .ring-tone-pick select { flex: 1 1 auto; width: auto; min-width: 0; }
.ring-tone-actions { display: flex; flex-wrap: wrap; gap: 6px; }
#agentSetup { display: grid; gap: 10px; }
.setup-field-hint { font-size: var(--fs-s); color: var(--muted); }
.ring-ext-row { display: flex; align-items: center; gap: 8px; }
.ring-ext-row input[type="range"] { flex: 1 1 auto; min-width: 0; height: 32px; }
.setup-actions { display: flex; gap: 8px; flex-wrap: wrap; }
body.console-incall #agentSetup, body.console-incall #micSetupBtn { display: none; }
#deviceSwitchPanel .opt > label, #deviceSwitchPanel .opt > span:first-child { min-width: 0; }
.opt .vol { display: inline-flex; align-items: center; gap: 6px; flex: none; }
.opt .vol input { width: 110px; }
.opt .vol span { min-width: 4ch; font-size: var(--fs-s); color: var(--muted); font-variant-numeric: tabular-nums; }
.dev-switch { flex-wrap: nowrap; }
.dev-switch select { flex: 1 1 0; min-width: 0; }
.more-phone { display: none; gap: 8px; }
.confirm { width: min(360px, calc(100vw - 16px)); gap: 12px; padding: 18px; }
.confirm h3 { font-size: var(--fs-l); font-weight: 700; }
.confirm .acts { display: flex; justify-content: flex-end; flex-wrap: wrap; gap: 8px; }
/* K1: in-page confirm (console.js askConfirm), centred above menus, below toasts. */
#actionConfirmScrim { position: fixed; inset: 0; z-index: calc(var(--z-menu) + 4); background: rgb(var(--neutral-950) / .45); animation: brand-fade var(--motion-base) var(--ease-out); }
#actionConfirm {
  position: fixed;
  top: 50%;
  left: 50%;
  z-index: calc(var(--z-menu) + 5);
  display: grid;
  transform: translate(-50%, -50%);
  border: 1px solid var(--line);
  border-radius: var(--r);
  background: var(--surface);
  color: var(--ink);
  box-shadow: var(--shadow-pop);
  font-size: var(--fs-m);
}
#actionConfirmMsg { font-weight: 600; overflow-wrap: anywhere; }

/* ── Banner row: one line; only the first visible banner shows, "+N" chip for the rest ── */
#bannerRow { display: flex; align-items: stretch; min-width: 0; background: var(--surface); }
#bannerRow > :not([hidden]) ~ :not([hidden]) { display: none; }
#bannerRow[data-more]::after {
  content: "+" attr(data-more);
  align-self: center;
  flex: none;
  margin: 0 12px;
  padding: 1px 8px;
  border-radius: 999px;
  background: var(--ink);
  color: #fff;
  font-size: var(--fs-s);
  font-weight: 700;
}
.console-banner {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 5px 10px 5px 16px;
  border-bottom: 1px solid var(--line);
  font-weight: 500;
  white-space: nowrap;
}
.console-banner > .ic { width: 16px; height: 16px; }
.console-banner .bn-text { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
/* U20 (Cowork 19/10): ở Sảnh, banner bật/tắt từng đẩy cả màn lên xuống ~43px ⇒ NV bấm nhầm dòng.
   K2 (Cowork vòng 2): giữ chỗ 43px thì lúc không có banner lại thành dải trắng trống dưới thanh trên.
   Ngoài cuộc #bannerSlot cao 0 (vẫn nằm ngay dưới header dù header cao bao nhiêu), hàng banner NỔI đè
   lên mép trên trang: ẩn ⇒ 0px, hiện ⇒ không xô gì. Trong cuộc giữ như cũ: hàng nằm trong luồng,
   không lấy chỗ của video khi không có banner. */
body.console:not(.console-incall) #bannerSlot { position: relative; z-index: var(--z-header); height: 0; }
body.console:not(.console-incall) #bannerRow { position: absolute; top: 0; left: 0; right: 0; }
/* Two-column lobby: the floating row spans the centre column only, so the rail tabs (Gọi kiosk / Mở cửa /
   Tra đơn) and the "Nhận thay" rows under it stay clickable (code review 20/10). */
@media (min-width: 768px) and (min-height: 501px) {
  body.console:not(.console-incall) #bannerRow { right: var(--rail-w); }
}
/* While a call rings here the CENTRE COLUMN reserves one banner's height (1 line = button 32 + padding 10 +
   border 1; phone up to 2 lines = 2×21 + 11; touch buttons are 44 tall ⇒ 55) and the row keeps floating
   over it: a floating "Có khách ngoài cửa" covered the top ~20px of the ring card (K2b), and putting the row
   back in flow made "Nhận cuộc" jump 43px whenever a banner came or went mid-ring (TE-K2-R, 20/10).
   The slot itself stays 0 so the rail column does not drop when a ring starts (code review 20/10). */
body.console.console-ringing:not(.console-incall) .console-center { padding-top: 43px; }
@media (max-width: 767px) {
  body.console.console-ringing:not(.console-incall) .console-center { padding-top: 53px; }
}
@media (pointer: coarse) {
  body.console.console-ringing:not(.console-incall) .console-center { padding-top: 55px; }
}
/* U21: điện thoại, chữ banner xuống tối đa 2 dòng thay vì cắt. */
@media (max-width: 767px) {
  body.console:not(.console-incall) .console-banner { white-space: normal; line-height: 1.5; }
  body.console:not(.console-incall) .console-banner .bn-text { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; }
  body.console:not(.console-incall) .console-banner > .btn { flex: none; white-space: nowrap; }
}
.console-banner.nudge { background: var(--warn-soft); color: var(--warn); }
.console-banner.failover { background: var(--danger-soft); color: rgb(var(--color-danger)); }
.console-banner.guest-alert { background: var(--accent-soft); color: var(--accent); }
.console-banner.update { background: var(--soft2); color: var(--ink); }
.bn-close { width: 32px; min-height: 32px; padding: 0; border-color: transparent; background: transparent; color: inherit; }
.bn-close:hover { border-color: currentColor; }

/* ── Main frame ────────────────────────────────────────────────────────────────────────── */
.console-main {
  min-height: 0;
  min-width: 0;
  display: grid;
  /* Rail up to 520px on wide screens (owner 26/09: room for the conversation, menus and the guest's
     vehicle instead of empty bands beside a 16:9 cam). 1366px still gets 355px. */
  grid-template-columns: minmax(0, 1fr) var(--rail-w);
}
.console-center { min-height: 0; min-width: 0; display: flex; flex-direction: column; overflow: hidden; background: var(--soft); }
body.console-incall .console-center { background: var(--stage); }

/* ── Lobby (idle + ringing) ────────────────────────────────────────────────────────────── */
#lobby { flex: 1 1 auto; min-height: 0; overflow: auto; padding: 20px; display: flex; flex-direction: column; gap: 16px; }
.calls { display: flex; flex-direction: column; gap: 12px; }
.calls:empty { display: none; }
body.console-ringing #lobbyIdle { display: none; }
.lobby-idle { flex: 1 0 auto; display: grid; justify-items: center; align-content: center; gap: 10px; padding: 32px 16px; text-align: center; }
.lobby-idle .big { width: 72px; height: 72px; display: grid; place-items: center; border-radius: 50%; background: rgb(var(--brand-100)); color: var(--accent); }
.lobby-idle .big .ic { width: 30px; height: 30px; }
.lobby-idle h2 { font-size: var(--fs-xl); font-weight: 600; line-height: 1.25; }
.lobby-idle p { max-width: 44ch; color: var(--muted); }
.idle-off { display: none; }
body.agent-paused .idle-on { display: none; }
body.agent-paused span.idle-off, body.agent-paused svg.idle-off { display: inline; }
body.agent-paused p.idle-off { display: block; }
body.agent-paused button.idle-off { display: inline-flex; }
body.agent-paused .devline, body.agent-paused #lobbyDevBtn { display: none; }
.devline { display: flex; flex-wrap: wrap; justify-content: center; gap: 6px 16px; font-size: var(--fs-s); color: var(--muted); }
.devline > span { display: inline-flex; align-items: center; gap: 6px; }
.idle-actions { display: flex; flex-wrap: wrap; justify-content: center; gap: 8px; }

/* Ringing card (built by console.js renderRinging): the first button is "Nhận cuộc". Card border +
   pulsing avatar are alert red (owner decision, round 2) — accept button stays success green
   ("xanh = nghe, đỏ = gác"). */
.call-card {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 20px 24px;
  padding: 24px 28px;
  border: 2px solid rgb(var(--color-danger-fill));
  border-radius: var(--r);
  background: var(--surface);
  animation: brand-rise var(--motion-slow) var(--ease-out);
}
.ring-pulse {
  position: relative;
  display: grid;
  place-items: center;
  width: 84px;
  height: 84px;
  flex: none;
  border-radius: 50%;
  background: rgb(var(--color-danger-fill));
  color: var(--accent-ink);
}
.ring-pulse .ic { width: 36px; height: 36px; }
.ring-pulse::before { content: ""; position: absolute; inset: -8px; border-radius: 50%; border: 3px solid rgb(var(--color-danger-fill)); opacity: .5; }
@media (prefers-reduced-motion: no-preference) {
  .ring-pulse::before { animation: ring-pulse 1.4s ease-out infinite; }
}
@keyframes ring-pulse { from { transform: scale(.85); opacity: .7; } to { transform: scale(1.25); opacity: 0; } }
.ring-meta { flex: 1 1 240px; min-width: 0; display: grid; gap: 3px; }
.ring-name { margin-top: 4px; font-size: var(--fs-xl); font-weight: 700; line-height: 1.25; overflow-wrap: anywhere; }
.ring-sub { overflow-wrap: anywhere; }
.ring-src { color: var(--muted); }
.btn-accept, .call-card > button {
  flex: none;
  margin-left: auto;
  min-height: 52px;
  padding: 14px 28px;
  border-radius: var(--r);
  border-color: rgb(var(--color-success));
  background: rgb(var(--color-success));
  color: var(--accent-ink);
  font-size: var(--fs-l);
}
.btn-accept .ic { width: 20px; height: 20px; }
.btn-accept:hover, .call-card > button:hover { background: rgb(var(--accent-700)); border-color: var(--ink); }
.queue-next {
  align-self: flex-start;
  padding: 4px 12px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--surface);
  color: var(--muted);
  font-weight: 600;
}
#stealPanel { flex: none; background: var(--surface); border: 1px solid var(--line); border-radius: var(--r); }
.list-h {
  padding: 12px 16px 6px;
  font-size: var(--fs-s);
  font-weight: 600;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: .05em;
}
.steal-row, .kiosk-row { display: flex; align-items: center; gap: 12px; padding: 10px 16px; border-top: 1px solid var(--line); }
.list-h + .steal-row, .card.list > :first-child { border-top: 0; }
.grow { flex: 1 1 auto; min-width: 0; }
.grow b { font-weight: 600; }
.grow div { font-size: var(--fs-s); color: var(--muted); }
.since { flex: none; font-size: var(--fs-s); color: var(--muted); font-variant-numeric: tabular-nums; }
.sdot { width: 9px; height: 9px; flex: none; border-radius: 50%; background: var(--accent); }
.sdot.busy { background: var(--danger); }
.sdot.off { background: rgb(var(--neutral-400)); }
.steal-btn, .kiosk-row button { flex: none; min-height: 32px; padding: 5px 10px; }

/* ── In call: stage bar, stage, control bar ────────────────────────────────────────────── */
#call {
  flex: 1 1 auto;
  min-height: 0;
  display: grid;
  grid-template-rows: auto minmax(0, 1fr) auto auto;
  grid-template-columns: minmax(0, 1fr);
  background: var(--stage);
  color: var(--tile-ink);
}
/* Explicit rows: hiding the stage bar (phone, empty #status2) or the peek line must never shift
   the stage into an `auto` row — it would collapse to 0px. */
.stagebar { grid-row: 1; }
.stage { grid-row: 2; }
.peek { grid-row: 3; }
.call-controls-panel { grid-row: 4; }
.stagebar { container-type: inline-size; display: flex; align-items: center; gap: 10px; min-width: 0; padding: 10px 14px; }
.seg { display: inline-flex; flex: none; gap: 2px; padding: 3px; border-radius: 10px; background: rgb(var(--neutral-950)); }
.seg button {
  min-height: 32px;
  padding: 5px 11px;
  border: 2px solid rgb(var(--neutral-800));
  border-radius: 8px;
  background: rgb(var(--neutral-800));
  color: rgb(var(--neutral-300));
  font-size: var(--fs-s);
}
.seg button .ic { width: 15px; height: 15px; }
.seg button:hover { border-color: var(--bar-edge); color: #fff; }
.seg button[aria-pressed="true"], .seg button.active { border-color: #fff; background: #fff; color: rgb(var(--neutral-950)); }
.seg button[aria-pressed="true"]:hover, .seg button.active:hover { border-color: var(--accent); }
#status2 { min-width: 0; font-size: var(--fs-s); color: rgb(var(--neutral-300)); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
#status2:empty { display: none; }
.stage-hint { font-size: var(--fs-s); color: rgb(var(--neutral-400)); white-space: nowrap; }
.stagebar .sp { flex: 1 1 auto; }
.sv-btn {
  flex: none;
  min-height: 32px;
  padding: 5px 10px;
  border: 2px solid var(--bar-btn);
  background: var(--bar-btn);
  color: var(--bar-btn-ink);
  font-size: var(--fs-s);
}
.sv-btn:hover { border-color: var(--bar-edge); }
.ic-sv-off { display: none; }
.sv-btn[data-state="off"] .ic-sv-on { display: none; }
.sv-btn[data-state="off"] .ic-sv-off { display: inline; }
@container (max-width: 720px) { .stage-hint { display: none; } }
@container (max-width: 520px) { .sv-label { display: none; } }

/* Stage = size container: tile sizes use cq units. The PiP is absolute to the stage (not to
   #grid) so on the phone it stays put while the carousel scrolls. */
.stage {
  position: relative;
  container-type: size;
  min-height: 0;
  min-width: 0;
  display: grid;
  grid-template-rows: minmax(0, 1fr) auto;
  grid-template-columns: minmax(0, 1fr);
  padding: 0 14px 10px;
}

/* #grid: tiles are rtc.js's direct children. console-ui.js sets data-layout/data-slot/order. */
#grid { min-height: 0; min-width: 0; display: flex; flex-wrap: wrap; align-content: center; gap: var(--gap); overflow: hidden; }
#grid > .tile {
  position: relative;
  flex: 1 1 45%;
  min-width: 0;
  height: 50cqh;
  border-radius: 10px;
  overflow: hidden;
  background: var(--tile);
  outline: 2px solid transparent;
  outline-offset: -2px;
  cursor: pointer;
  transition: outline-color .12s;
}
#grid > .tile:hover { outline-color: rgba(255, 255, 255, .55); }
body[data-zone="inside"] #grid > .tile[data-cam="cam:desk"],
body[data-zone="outside"] #grid > .tile[data-cam="cam:door"] { outline-color: rgb(var(--brand-300)); }

/* Auto: one big cam (row 1), the rest in the film strip (row 2). Split: desk + door side by side.
   The big tiles hug a 16:9 frame (kiosk cams are 16:9) and sit centred, so the whole picture shows
   with no empty bands beside it (owner 26/09: "giảm chiều rộng, hiện full góc nhìn"). */
#grid:not([data-phone]):is([data-layout="auto"], [data-layout="split"]) { justify-content: center; }
#grid[data-layout="auto"] > .tile[data-slot="main"] {
  --main-h: min(calc(100cqh - var(--film-h) - 2 * var(--gap)), 56.25cqw);
  flex: 0 0 auto;
  width: min(100%, calc(var(--main-h) * 16 / 9));
  height: var(--main-h);
}
#grid[data-layout="auto"]:not(:has(> .tile[data-slot="film"])) > .tile[data-slot="main"] { --main-h: min(calc(100cqh - var(--gap)), 56.25cqw); }
#grid[data-layout="split"] > .tile:is([data-slot="main"], [data-slot="main2"]) {
  --main-h: min(calc(100cqh - var(--film-h) - 2 * var(--gap)), calc((50cqw - var(--gap) / 2) * 9 / 16));
  flex: 0 0 auto;
  width: min(calc(50% - var(--gap) / 2), calc(var(--main-h) * 16 / 9));
  height: var(--main-h);
}
#grid[data-layout="split"]:not(:has(> .tile[data-slot="film"])) > .tile:is([data-slot="main"], [data-slot="main2"]) {
  --main-h: min(calc(100cqh - var(--gap)), calc((50cqw - var(--gap) / 2) * 9 / 16));
}
/* Line break between the big tiles (order 1–2) and the film strip (order 10+, self 99) now that the
   big tiles no longer fill the row. It is an empty flex line, so it adds one row gap — the --main-h
   formulas above subtract it. */
#grid:not([data-phone]):is([data-layout="auto"], [data-layout="split"])::after {
  content: '';
  order: 5;
  flex: 0 0 100%;
  height: 0;
}
#grid > .tile[data-slot="film"] { flex: 1 1 0; max-width: 170px; height: var(--film-h); }
/* Grid: every cam, 2 columns; with 3 cams the first spans both rows. */
#grid[data-layout="grid"] { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); grid-auto-rows: minmax(0, 1fr); align-content: stretch; }
#grid[data-layout="grid"][data-n="1"] { grid-template-columns: minmax(0, 1fr); }
#grid[data-layout="grid"]:is([data-n="5"], [data-n="6"]) { grid-template-columns: repeat(3, minmax(0, 1fr)); }
#grid[data-layout="grid"][data-n="3"] > .tile[data-slot="main"] { grid-row: span 2; }
#grid[data-layout="grid"] > .tile { height: auto; max-width: none; }

/* Staff self view = PiP: a small corner overlay, or — when there is a film strip — the last cell of
   that strip (in the flow, pushed right), so it never covers a kiosk cam. */
#grid:not([data-phone]) > #tile-local {
  position: absolute;
  right: 24px;
  bottom: 20px;
  z-index: 3;
  width: clamp(96px, 16cqw, 168px);
  height: auto;
  aspect-ratio: 4 / 3;
  border: 2px solid rgba(255, 255, 255, .7);
  box-shadow: 0 6px 20px rgba(0, 0, 0, .4);
  cursor: default;
}
#grid:not([data-phone]):is([data-layout="auto"], [data-layout="split"]):has(> .tile[data-slot="film"]) > #tile-local {
  position: relative;
  right: auto;
  bottom: auto;
  flex: 0 0 calc(var(--film-h) * 4 / 3);
  width: auto;
  height: var(--film-h);
  aspect-ratio: auto;
  margin-left: auto;
}
#grid[data-self="off"] > #tile-local { display: none; }
/* Wide stage (Auto with small cams): the small cams stack in a column to the RIGHT of the big cam,
   which then takes the full stage height (owner 26/09: "cam nhỏ sang cột phải"). Flex column-wrap:
   the big tile's block margins fill its column so the small cams always wrap into column 2. Below
   1.6:1 the film strip stays underneath, where it gives the bigger picture. */
@container (min-aspect-ratio: 8 / 5) {
  #grid:not([data-phone])[data-layout="auto"]:has(> .tile[data-slot="film"]) {
    flex-direction: column;
    flex-wrap: wrap;
    align-content: center;
    justify-content: center;
  }
  #grid:not([data-phone])[data-layout="auto"]:has(> .tile[data-slot="film"])::after { display: none; }
  #grid:not([data-phone])[data-layout="auto"]:has(> .tile[data-slot="film"]) > .tile[data-slot="main"] {
    --main-h: min(100cqh, calc((100cqw - var(--film-w) - var(--gap)) * 9 / 16));
    width: calc(var(--main-h) * 16 / 9);
    height: var(--main-h);
    margin-block: calc((100cqh - var(--main-h)) / 2);
  }
  #grid:not([data-phone])[data-layout="auto"]:has(> .tile[data-slot="film"]) > :is(.tile[data-slot="film"], #tile-local) {
    flex: 0 0 auto;
    width: var(--film-w);
    max-width: none;
    height: calc(var(--film-w) * 9 / 16);
    margin: 0;
  }
}

/* Tile internals (rtc.js: .tile > .tile-media > video + .label). */
.tile-media { position: absolute; inset: 0; transform-origin: 0 0; }
.tile-media.cz-active { will-change: transform; touch-action: none; }
.tile video { display: block; width: 100%; height: 100%; object-fit: cover; }
.tile.fit-contain video { object-fit: contain; }
/* Kiosk cams on a computer show the WHOLE frame by default (no top/bottom crop); the ⛶ button
   (console.js czBuildBar, toggles .fit-contain) then switches that tile to fill instead. */
#grid:not([data-phone]) > .tile[data-cam^="cam:"] video { object-fit: contain; }
#grid:not([data-phone]) > .tile[data-cam^="cam:"].fit-contain video { object-fit: cover; }
.tile .label {
  position: absolute;
  left: 8px;
  bottom: 8px;
  z-index: 1;
  max-width: calc(100% - 16px);
  padding: 3px 9px;
  border-radius: 999px;
  background: rgb(var(--neutral-950) / .72);
  color: #fff;
  font-size: var(--fs-s);
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  pointer-events: none;
}
/* Friendly names over rtc.js's raw track names (cam:desk…) without touching the DOM: the raw
   label box stays (invisible) and the chip is its ::before. */
.tile:is([data-cam="cam:desk"], [data-cam="cam:door"], [data-cam="cam:doc"]) .label, #tile-local .label {
  visibility: hidden;
  overflow: visible;
  padding: 3px 0;
  background: none;
}
.tile:is([data-cam="cam:desk"], [data-cam="cam:door"], [data-cam="cam:doc"]) .label::before, #tile-local .label::before {
  visibility: visible;
  position: absolute;
  left: 0;
  bottom: 0;
  padding: 3px 9px;
  border-radius: 999px;
  background: rgb(var(--neutral-950) / .72);
  color: #fff;
  white-space: nowrap;
}
.tile[data-cam="cam:desk"] .label::before { content: "Cam bàn · trong"; }
.tile[data-cam="cam:door"] .label::before { content: "Cam cửa · ngoài"; }
.tile[data-cam="cam:doc"] .label::before { content: "Cam tài liệu"; }
#tile-local .label::before { content: "Bạn"; }
body[data-zone="inside"] .tile[data-cam="cam:desk"] .label::before { content: "Cam bàn · trong · đang nói"; }
body[data-zone="outside"] .tile[data-cam="cam:door"] .label::before { content: "Cam cửa · ngoài · đang nói"; }
#grid > .tile[data-pin][data-cam="cam:desk"] .label::before { content: "Cam bàn · trong · đã ghim"; }
#grid > .tile[data-pin][data-cam="cam:door"] .label::before { content: "Cam cửa · ngoài · đã ghim"; }
#grid > .tile[data-pin][data-cam="cam:doc"] .label::before { content: "Cam tài liệu · đã ghim"; }

/* Per-tile bars: zoom (console.js .cz-bar, + pin from console-ui) top-right, brightness top-left.
   Shown on hover/focus with a mouse; always on touch; never on film/PiP tiles. */
.cz-bar, .cam-adj-bar {
  position: absolute;
  top: 8px;
  z-index: 2;
  display: flex;
  align-items: center;
  gap: 4px;
  padding: 4px;
  border-radius: 10px;
  background: rgb(var(--neutral-950) / .72);
  color: #fff;
  opacity: 0;
  transition: opacity .12s;
}
.cz-bar { right: 8px; }
.cam-adj-bar { left: 8px; gap: 6px; padding: 4px 8px; }
#grid > .tile:hover :is(.cz-bar, .cam-adj-bar), #grid > .tile:focus-within :is(.cz-bar, .cam-adj-bar) { opacity: 1; }
@media (hover: none) { .cz-bar, .cam-adj-bar { opacity: 1; } }
#grid:not([data-phone]) > .tile:is([data-slot="film"], [data-slot="pip"]) :is(.cz-bar, .cam-adj-bar) { display: none; }
.lb-btn {
  min-width: 38px;
  height: 38px;
  min-height: 38px;
  padding: 0 10px;
  border: 1px solid rgba(255, 255, 255, .25);
  border-radius: 10px;
  background: rgb(var(--neutral-800));
  color: #fff;
  font-size: var(--fs-l);
  line-height: 1;
}
.lb-btn:hover { border-color: #fff; background: #fff; color: rgb(var(--neutral-950)); }
.cz-bar .lb-btn, .cam-adj-bar .lb-btn { min-width: 30px; height: 30px; min-height: 30px; padding: 0 6px; border-radius: 7px; }
.cz-bar .cz-level, .cam-adj-bar .lb-btn { font-size: var(--fs-s); }
.cz-bar .cz-level { min-width: 44px; }
.cam-adj-bar .ca-label { width: 16px; height: 16px; }
.cam-adj-bar .camAdjRange { width: 92px; accent-color: #fff; }
.tile-pin .ic { width: 16px; height: 16px; }
.tile-pin .ic-unpin { display: none; }
.tile-pin[aria-pressed="true"] { border-color: #fff; background: #fff; color: rgb(var(--neutral-950)); }
.tile-pin[aria-pressed="true"]:hover { border-color: var(--accent); }
.tile-pin[aria-pressed="true"] .ic-pin { display: none; }
.tile-pin[aria-pressed="true"] .ic-unpin { display: inline; }

.cam-dots { display: flex; justify-content: center; gap: 6px; padding: 6px 0 0; }
.cam-dot { width: 8px; min-height: 8px; height: 8px; padding: 0; border: 0; border-radius: 50%; background: rgb(var(--neutral-500)); }
.cam-dot[aria-current="true"] { width: 20px; border-radius: 999px; background: #fff; }

.peek { display: none; }

/* Control bar under the video. */
.call-controls-panel {
  container-type: inline-size;
  container-name: ctrl;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-width: 0;
  padding: 10px 14px 14px;
  background: var(--bar);
}
.cbtn {
  position: relative;
  display: inline-grid;
  justify-items: center;
  align-content: center;
  gap: 3px;
  min-width: 72px;
  min-height: 54px;
  padding: 7px 10px;
  border: 2px solid var(--bar-btn);
  border-radius: 12px;
  background: var(--bar-btn);
  color: var(--bar-btn-ink);
  font-size: var(--fs-s);
  font-weight: 500;
}
.cbtn .ic { width: 20px; height: 20px; }
.cbtn:hover { border-color: var(--bar-edge); color: #fff; }
.cbtn[aria-expanded="true"] { border-color: #fff; background: #fff; color: rgb(var(--neutral-950)); }
.cbtn[aria-expanded="true"]:hover { border-color: var(--accent); }
.cbtn:disabled:hover { border-color: var(--bar-btn); }
.cbtn.end { min-width: 96px; border-color: var(--danger); background: var(--danger); color: #fff; }
.cbtn.end:hover { border-color: #fff; background: var(--danger-hover); }
.zone {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 5px 6px 5px 12px;
  border-radius: 12px;
  background: var(--bar-btn);
  color: rgb(var(--neutral-300));
  font-size: var(--fs-s);
}
.zone .seg button { min-height: 40px; }
.ctrl-divider { width: 1px; height: 38px; margin: 0 4px; background: rgb(var(--neutral-700)); }
.zone-m, .l-short { display: none; }
.zt-in { display: none; }
body[data-zone="inside"] .zt-in { display: inline; }
body[data-zone="inside"] .zt-out { display: none; }
@container ctrl (max-width: 820px) {
  .zone-label, .ctrl-divider { display: none; }
  .zone { padding-left: 6px; }
}
@container ctrl (max-width: 640px) {
  .cbtn { min-width: 60px; padding: 6px; }
  .cbtn.end { min-width: 80px; }
  .l-long { display: none; }
  .l-short { display: inline; }
}

/* ── Right column: conversation + one tab bar + panes ──────────────────────────────────── */
#convoRail {
  container-type: inline-size;
  container-name: rail;
  min-height: 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  border-left: 1px solid var(--line);
  background: var(--surface);
}
#sheetHandle { display: none; justify-items: center; padding: 8px 0 4px; cursor: grab; touch-action: none; flex: none; }
#sheetHandle i { display: block; width: 40px; height: 5px; border-radius: 999px; background: var(--line-strong); }

#subs { flex: 0 0 42%; min-height: 0; display: flex; flex-direction: column; border-bottom: 1px solid var(--line); }
body:not(.console-incall) #subs { display: none; }
body.convo-guide-active #subs { flex-basis: 30%; }
.sub-head { display: flex; align-items: center; gap: 8px; flex: none; min-width: 0; padding: 12px 14px 6px; font-weight: 600; }
.sub-head .ic { width: 16px; height: 16px; }
.sub-head-title { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.head-en, .head-sep { display: none; }
.lang-pair {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  flex: none;
  margin-left: auto;
  padding: 2px 9px;
  border-radius: 999px;
  background: var(--soft);
  color: var(--muted);
  font-size: var(--fs-s);
  font-weight: 600;
  line-height: 1.4;
  white-space: nowrap;
  cursor: help;
}
.lang-auto, .lang-detecting { font-size: var(--fs-s); line-height: 1; }
.lang-detecting { font-weight: 500; opacity: .75; }
.sub-feed { flex: 1 1 auto; min-height: 0; overflow-y: auto; display: flex; flex-direction: column; gap: 8px; padding: 4px 14px 12px; }
.sub-bubble {
  max-width: 88%;
  padding: 7px 11px;
  border-radius: 14px;
  color: var(--ink);
  font-size: var(--fs-m);
  line-height: 1.45;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  transition: opacity .18s ease;
}
.sub-bubble.in { align-self: flex-start; background: var(--accent-soft); border-radius: 14px 14px 14px 4px; }
.sub-bubble.out { align-self: flex-end; background: var(--soft2); border-radius: 14px 14px 4px 14px; }
.sub-bubble.live { opacity: .72; }
.sub-bubble.revised { animation: sub-revised 600ms ease; }
@keyframes sub-revised { 30% { opacity: .2; } }
/* 🔴 display:block is required: a dir="rtl" inline span would still be aligned by the ltr bubble. */
.sub-pri { display: block; }
.sub-sec { display: block; margin-top: 2px; font-size: var(--fs-s); line-height: 1.35; opacity: .62; transition: opacity .18s ease; }
.sub-bubble:not(:has(.sub-pri)) .sub-sec { margin-top: 0; font-size: var(--fs-m); line-height: 1.45; opacity: 1; }
.sub-live { flex: none; display: flex; flex-direction: column; gap: 6px; padding: 6px 14px 10px; border-top: 1px solid var(--line); }
.subs-feed .sub-live:not(:has(.sub-line.typing)) { display: none; }
.sub-line { display: none; flex-direction: column; }
.sub-line.typing { display: flex; }
.sub-line.out { align-items: flex-end; }
.sub-line.in { align-items: flex-start; }
.sub-line .who { margin-bottom: 2px; font-size: var(--fs-s); font-weight: 600; color: var(--muted); }
.sub-line .txt { display: inline-block; max-width: 88%; padding: 7px 11px; border-radius: 14px; font-size: var(--fs-m); white-space: pre-wrap; overflow-wrap: anywhere; }
.sub-line.out .txt { background: var(--soft2); }
.sub-line.in .txt { background: var(--accent-soft); }
.sub-log { overflow-y: auto; }
.sub-log .line { padding: 4px 0; border-bottom: 1px solid var(--line); white-space: pre-wrap; }

/* Tab bar: one bar, the tab set follows body.console-incall. Never clipped (gate). */
#convoTabs { flex: none; display: flex; gap: 2px; min-width: 0; padding: 8px 8px 0; border-bottom: 1px solid var(--line); overflow: hidden; }
.convo-tab {
  flex: 1 1 auto;
  min-width: 0;
  gap: 5px;
  min-height: 40px;
  padding: 8px 5px;
  border: 1px solid transparent;
  border-bottom-width: 2px;
  border-radius: 8px 8px 0 0;
  background: transparent;
  color: var(--muted);
  font-size: var(--fs-m);
}
.convo-tab .ic { width: 15px; height: 15px; }
.convo-tab:hover { border-color: var(--accent); color: var(--ink); }
.convo-tab[aria-selected="true"], .convo-tab.active { border-bottom-color: var(--accent); color: var(--accent); }
.tab-dot { width: 7px; height: 7px; flex: none; align-self: flex-start; border-radius: 50%; background: var(--danger); }
.lbl-call { display: none; }
body.console-incall .lbl-lobby { display: none; }
body.console-incall .lbl-call { display: inline; }
body:not(.console-incall) .convo-tab:is([data-group="docs"], [data-group="guide"], [data-group="ai"]),
body.console-incall .convo-tab:is([data-group="dial"], [data-group="door"]) { display: none; }
@media (max-width: 1279px) { .convo-tab .ic { display: none; } }
@container rail (max-width: 339px) { .convo-tab .ic { display: none; } }

#convoTabbody { flex: 1 1 0; min-height: 0; display: grid; grid-template-columns: minmax(0, 1fr); grid-template-rows: minmax(0, 1fr); }
#convoTabbody > .pane {
  display: none;
  flex-direction: column;
  gap: 12px;
  min-height: 0;
  min-width: 0;
  overflow: auto;
  overscroll-behavior: contain;
  padding: 14px;
}
#convoTabbody[data-group="dial"] > .pane[data-group="dial"],
#convoTabbody[data-group="door"] > .pane[data-group="door"],
#convoTabbody[data-group="lookup"] > .pane[data-group="lookup"],
#convoTabbody[data-group="docs"] > .pane[data-group="docs"],
#convoTabbody[data-group="guide"] > .pane[data-group="guide"],
#convoTabbody[data-group="ai"] > .pane[data-group="ai"] { display: flex; animation: brand-fade 150ms var(--ease-out); }
/* Fallback when console-tabs.js never ran (404/throw): every pane in the flow, no tab bar. */
body:not(.convo-tabs-ready) .pane { display: block; }
body:not(.convo-tabs-ready) #convoTabs, body:not(.convo-tabs-ready) .subseg { display: none; }
body:not(.convo-tabs-ready) #convoTabbody { display: block; overflow: auto; }
body:not(.convo-tabs-ready) .pane[data-group="docs"] > section:not([hidden]) { display: flex; }
body:not(.console-incall) #convoTabbody > .pane:is([data-group="docs"], [data-group="guide"], [data-group="ai"]),
body.console-incall #convoTabbody > .pane:is([data-group="dial"], [data-group="door"]) { display: none; }
.pane-hint { display: none; color: var(--muted); }
#guidePanel[hidden] + .pane-hint, #aiPanel[hidden] + .pane-hint { display: block; }

/* Docs pane: one sub-panel at a time (data-active), an empty one shows its hint line. */
.subseg { display: flex; flex-wrap: wrap; gap: 6px; }
.subseg button { gap: 4px; min-height: 30px; padding: 4px 11px; border-radius: 999px; color: var(--muted); font-size: var(--fs-s); }
.subseg button.has { color: var(--ink); }
.subseg button:hover { border-color: var(--accent); color: var(--accent); }
.subseg button[aria-pressed="true"], .subseg button.active { border-color: var(--accent); background: var(--accent-soft); color: var(--accent); }
body.convo-tabs-ready .pane[data-group="docs"] > :is(#docPanel, #qrPanel, #photoPreview, #chatLog, .pane-hint) { display: none; }
#convoTabbody[data-active="docPanel"] #docPanel:not([hidden]),
#convoTabbody[data-active="qrPanel"] #qrPanel:not([hidden]),
#convoTabbody[data-active="photoPreview"] #photoPreview:not(:empty),
#convoTabbody[data-active="chatLog"] #chatLog:not(:empty) { display: flex; }
#convoTabbody[data-active="docPanel"] #docPanel[hidden] + .pane-hint,
#convoTabbody[data-active="qrPanel"] #qrPanel[hidden] + .pane-hint,
#convoTabbody[data-active="photoPreview"] #photoPreview:empty + .pane-hint,
#convoTabbody[data-active="chatLog"] #chatLog:empty + .pane-hint,
#convoTabbody:not([data-active="docPanel"]):not([data-active="qrPanel"]):not([data-active="photoPreview"]):not([data-active="chatLog"]) .pane-hint[data-for="docs"] { display: block; }
#hidePhotoBtn { align-self: flex-start; }

#docPanel { flex-direction: column; gap: 10px; }
.doc-panel-head { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.doc-panel-title { font-weight: 600; }
.doc-meta { padding: 2px 9px; border-radius: 999px; background: var(--soft); color: var(--muted); font-size: var(--fs-s); overflow-wrap: anywhere; }
.doc-panel-actions { display: flex; gap: 8px; margin-left: auto; }
.doc-img-wrap { display: flex; justify-content: center; overflow: hidden; border-radius: 10px; background: var(--soft2); }
#docPhotoImg { display: block; max-width: 100%; max-height: min(40vh, 320px); object-fit: contain; cursor: zoom-in; }
#qrPanel { flex-direction: column; align-items: center; gap: 10px; }
#qrPanel .doc-panel-head { align-self: stretch; justify-content: space-between; }
#qrImg { width: 200px; max-width: 100%; height: auto; }
#qrLinkText { max-width: 100%; white-space: normal; word-break: break-all; }
.stack-col { flex-direction: column; gap: 10px; }
.photo-pending-card { flex-direction: column; align-items: stretch; padding: 10px; border: 1px solid var(--line); border-radius: 10px; }
.photo-pending-img { max-width: 100%; max-height: 220px; object-fit: contain; border-radius: 8px; }
.photo-card-actions { display: flex; gap: 8px; }
.chat-entry { display: flex; align-items: center; gap: 10px; padding: 8px; border: 1px solid var(--line); border-radius: 10px; }
.chat-entry-img { width: 72px; height: 54px; object-fit: cover; border-radius: 6px; }

/* Guide pane: #guideBody is the only scroller; Trước/Tiếp/Ẩn stay visible at the bottom. */
#convoTabbody > .pane[data-group="guide"] { overflow: hidden; }
#guidePanel { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; gap: 10px; }
.guide-head { display: flex; align-items: center; gap: 8px; flex: none; }
#guideProcSelect { flex: 1 1 auto; min-width: 0; }
.guide-chips { display: flex; flex-wrap: wrap; gap: 6px; flex: none; max-height: 96px; margin: 0; padding: 0; overflow-y: auto; list-style: none; }
.guide-chip {
  display: flex;
  align-items: center;
  gap: 4px;
  padding: 3px 9px;
  border: 1px solid transparent;
  border-radius: 999px;
  background: var(--soft);
  color: var(--muted);
  font-size: var(--fs-s);
  cursor: pointer;
}
.guide-chip:hover { border-color: var(--accent); }
.guide-chip.active { background: var(--accent); color: var(--accent-ink); }
/* Guide media bar (console-guidemedia.js): now-playing card on top (mic warning), then the video + QR
   buttons (capped at 2 rows, 1 on a phone). #guideBody gives up its height first (it was the panel's
   only shrinking item, so its large shrink changes nothing without the bar); only when it is already
   0 (phone sheet, 1280×720) does the bar shrink and scroll — the list goes out of view before the
   card, and Trước/Tiếp/Ẩn never leave the panel. */
.guide-media { display: flex; flex-wrap: wrap; align-items: flex-start; gap: 6px; flex: 0 1 auto; min-height: 0; overflow-y: auto; }
#guidePanel > #guideBody { flex-shrink: 1000; }
.gm-list { display: flex; flex-wrap: wrap; gap: 6px; flex: 1 1 auto; min-width: 0; max-height: 72px; overflow-y: auto; }
.gm-video { max-width: 100%; white-space: normal; text-align: left; }
.guide-video-now { flex: 1 1 100%; display: flex; flex-direction: column; gap: 4px; padding: 6px 8px; border: 1px solid var(--line); border-radius: var(--r-s); background: var(--soft); }
.gm-now-head { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 8px; }
/* 8ch floor: when Dừng + Phát lại both show (unsupported/error) the second button wraps instead of
   crushing the title to a sliver. */
.gm-now-title { flex: 1 1 0; min-width: 8ch; overflow: hidden; font-weight: 600; white-space: nowrap; text-overflow: ellipsis; }
.gm-now-progress { flex: none; font-size: var(--fs-s); color: var(--muted); font-variant-numeric: tabular-nums; }
/* Muted copy of what the customer is watching (L1d), BELOW the mic warning so the warning never scrolls out
   of view; fixed height so a vertical 9:16 clip stays small (1366×768 console, visual pass 27/09). */
.gm-preview { display: block; width: 100%; height: 160px; object-fit: contain; background: #000; border-radius: var(--r-s); }
.gm-warn { padding: 4px 8px; border: 1px solid var(--warn); border-radius: var(--r-s); background: var(--warn-soft); font-size: var(--fs-s); font-weight: 600; }
.guide-video-now:is([data-phase="playing"], [data-phase="unsupported"]) .gm-status { color: var(--warn); }
.guide-video-now[data-phase="error"] .gm-status { color: rgb(var(--color-danger)); }
.guide-video-now:is([data-phase="ended"], [data-phase="stopped"]) .gm-status { color: var(--accent); }
.gc-num { font-weight: 600; }
.gc-mode { font-size: var(--fs-s); }
#guideBody { flex: 1 1 auto; min-height: 0; overflow-y: auto; display: flex; flex-direction: column; gap: 8px; }
.guide-cur-title { font-weight: 600; }
.guide-note-box { display: flex; flex-direction: column; gap: 6px; }
.guide-staff-note { min-height: 40px; padding: 10px 12px; border: 1px solid var(--line); border-radius: var(--r-s); background: var(--soft); color: var(--muted); white-space: pre-wrap; }
#guideStaffImg { max-height: 150px; object-fit: contain; border: 1px solid var(--line); border-radius: var(--r-s); cursor: zoom-in; }
.guide-controls { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; flex: none; padding-top: 8px; border-top: 1px solid var(--line); }
.guide-counter { min-width: 64px; text-align: center; font-size: var(--fs-s); color: var(--muted); }
.guide-spacer { flex: 1 1 auto; }
.guide-seen { flex: 0 0 100%; font-size: var(--fs-s); color: var(--muted); }
.guide-seen[data-state="seen"] { color: var(--accent); }
.guide-seen[data-state="partial"] { color: var(--warn); }
.guide-seen[data-state="error"] { color: rgb(var(--color-danger)); }
body.guide-assist #guideStaffImgWrap { display: none !important; }
.assist-chip { flex: none; margin-left: auto; padding: 2px 8px; border: 1px solid var(--line); border-radius: 999px; color: var(--muted); font-size: var(--fs-s); white-space: nowrap; }
.assist-chip[data-state="auto"] { border-color: var(--accent); background: var(--accent-soft); color: var(--accent); }
.assist-chip[data-state="yield"] { border-color: var(--warn); color: var(--warn); }
body.guide-assist #guideNoteBox { padding-top: 6px; }
.assist-shown { display: flex; flex-direction: column; gap: 4px; }
#assistShownImg { align-self: flex-start; max-width: 100%; max-height: 150px; object-fit: contain; border: 2px solid var(--accent); border-radius: var(--r-s); cursor: zoom-in; }
.guide-head.assist-pulse { animation: assist-pulse 1.2s ease-out 1; }
/* Opacity only: a scale pulse would push the chip past the panel edge while it runs. */
@keyframes assist-pulse { 30% { opacity: .45; } }
.assist-shown-none, .assist-next { color: var(--muted); }
.assist-meta, .assist-reason { font-size: var(--fs-s); color: var(--muted); }
.assist-reason { flex: none; color: var(--accent); }
.assist-suggest { display: flex; flex-direction: column; gap: 6px; flex: none; padding: 8px 10px; border: 1px solid var(--warn); border-radius: var(--r-s); background: var(--warn-soft); }
.assist-suggest-btns { display: flex; justify-content: flex-end; gap: 8px; }
.assist-link { font-size: var(--fs-s); white-space: nowrap; }

/* Lookup pane (rental + vehicles) — the pane scrolls; #rentalResult never gets a max-height. */
#kioskDial, #doorPanel, #rentalPanel, #vehiclePanel { display: flex; flex-direction: column; gap: 12px; }
.pane-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.kiosk-row { padding: 10px 12px; }
.kiosk-dot { width: 9px; height: 9px; flex: none; border-radius: 50%; background: var(--accent); font-size: 0; overflow: hidden; }
.kiosk-dot.busy, .kiosk-dot.off { background: var(--danger); }
#standaloneDoorDot:not(:empty) { width: auto; height: auto; background: none; font-size: var(--fs-s); overflow: visible; }
.kiosk-info { flex: 1 1 auto; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.door-panel-row { display: flex; align-items: center; gap: 8px; }
#standaloneDoorSelect { flex: 1 1 auto; min-width: 0; }
.rental-row { flex-wrap: nowrap; }
/* K3: × inside the input (right edge); the input always keeps room for it ⇒ "Tra" never moves. */
.rental-input-wrap { position: relative; flex: 1 1 auto; min-width: 0; display: flex; }
#rentalQuery { flex: 1 1 auto; min-width: 0; width: 100%; padding-right: 36px; }
#rentalClearBtn { position: absolute; top: 50%; right: 4px; width: 28px; min-height: 28px; height: 28px; padding: 0; transform: translateY(-50%); border-color: transparent; background: transparent; color: var(--muted); }
#rentalClearBtn:hover { border-color: var(--line); color: var(--ink); }
#rentalClearBtn .ic { width: 16px; height: 16px; }
.result { display: grid; gap: 6px; padding: 12px; border: 1px solid var(--line); border-radius: 10px; }
.rental-kv { margin: 0; }
.rental-kv dt { margin-top: 10px; font-size: var(--fs-s); text-transform: uppercase; letter-spacing: .02em; color: var(--muted); }
.rental-kv dt:first-of-type { margin-top: 0; }
.rental-kv dd { margin: 2px 0 0; }
.rental-asset-sum { color: var(--muted); }
.rental-asset { margin-top: 2px; }
#rentalActionBox { margin-top: 6px; display: grid; gap: 8px; justify-items: start; }
.late-badge { display: inline-block; padding: 2px 8px; border-radius: 999px; font-size: var(--fs-s); font-weight: 600; }
.late-badge.late { background: var(--danger-soft); color: rgb(var(--color-danger)); }
.late-badge.ok { background: var(--soft); color: var(--muted); }
.handled-row { display: flex; flex-direction: column; align-items: flex-start; gap: 6px; padding: 10px 12px; border-top: 1px solid var(--line); }
.handled-info { line-height: 1.5; }
.vehicle-head { display: grid; gap: 6px; }
.vehicle-head .inline { flex-wrap: nowrap; }
.vehicle-head select { flex: 1 1 auto; min-width: 0; }
.vehicle-table-wrap { overflow-x: auto; }
table.mini { width: 100%; border-collapse: collapse; }
table.mini td, table.mini th { padding: 6px 4px; border-bottom: 1px solid var(--line); text-align: left; }
table.mini th { font-size: var(--fs-s); color: var(--muted); text-transform: uppercase; letter-spacing: .04em; }

/* AI pane (console-ai.js). */
#aiPanel { position: relative; display: flex; flex-direction: column; gap: 8px; min-height: 0; }
.ai-panel-head { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 8px; flex: none; }
.ai-usd { font-size: var(--fs-s); color: var(--muted); }
.ai-replay-bar { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; font-size: var(--fs-s); }
.ai-replay-bar select { max-width: 220px; }
.ai-strip { flex: none; max-height: 80px; overflow-y: auto; font-size: var(--fs-s); color: var(--muted); }
.ai-strip:empty { display: none; }
.ai-cols { display: flex; gap: 10px; flex: 1; min-height: 0; }
.ai-col { flex: 1; min-width: 0; min-height: 0; display: flex; flex-direction: column; gap: 4px; padding: 6px; border: 1px solid var(--line); border-radius: var(--r-s); }
.ai-col-head { flex: none; font-size: var(--fs-s); font-weight: 600; color: var(--muted); }
.ai-col-body { flex: 1; min-height: 0; overflow-y: auto; display: flex; flex-direction: column; gap: 4px; font-size: var(--fs-s); }
.ai-row { padding-bottom: 3px; border-bottom: 1px dashed var(--line); }
.ai-row-time { margin-right: 4px; color: var(--muted); }
.ai-row-badge, .ai-row-say { margin-right: 4px; font-weight: 600; }
.ai-row details summary { cursor: pointer; color: var(--muted); }
.ai-handoff-banner { max-width: 100%; }

/* ── Overlays ──────────────────────────────────────────────────────────────────────────── */
.toast {
  position: fixed;
  left: 50%;
  bottom: 24px;
  z-index: var(--z-toast);
  max-width: calc(100vw - 32px);
  padding: 10px 16px;
  border-radius: 10px;
  background: var(--ink);
  color: #fff;
  font-weight: 500;
  box-shadow: 0 8px 30px rgba(0, 0, 0, .3);
  opacity: 0;
  pointer-events: none;
  transform: translate(-50%, 8px);
  transition: opacity .16s, transform .16s;
}
.toast.show { opacity: 1; transform: translate(-50%, 0); }
body.console-incall .toast { bottom: 104px; }

#sheetScrim { position: fixed; top: 0; left: 0; right: 0; bottom: var(--ctrl-h); z-index: 39; background: rgb(var(--neutral-950) / .45); animation: brand-fade var(--motion-base) var(--ease-out); }

#docLightbox { position: fixed; inset: 0; z-index: var(--z-lightbox); display: none; flex-direction: column; background: rgba(15, 17, 21, .93); }
#docLightbox.show { display: flex; animation: brand-fade var(--motion-base) var(--ease-out); }
.lb-bar { display: flex; align-items: center; gap: 10px; flex: none; padding: 10px 14px; background: rgba(0, 0, 0, .35); color: #fff; }
.lb-bar .lb-meta { font-size: var(--fs-s); color: rgba(255, 255, 255, .78); }
.lb-bar .lb-spacer { margin-left: auto; }
.lb-bar .ic { width: 18px; height: 18px; }
#lbZoomLevel { min-width: 62px; font-size: var(--fs-m); }
.lb-stage { position: relative; flex: 1; overflow: hidden; touch-action: none; cursor: grab; }
.lb-stage.grabbing { cursor: grabbing; }
#docLightboxImg { position: absolute; top: 0; left: 0; max-width: none; transform-origin: 0 0; user-select: none; -webkit-user-drag: none; }
#docLightbox.show #docLightboxImg { will-change: transform; }
#guideImgOverlay { position: fixed; inset: 0; z-index: var(--z-lightbox); display: flex; align-items: center; justify-content: center; background: rgba(0, 0, 0, .85); animation: brand-fade var(--motion-base) var(--ease-out); }
#guideImgOverlayImg { max-width: 94vw; max-height: 94vh; object-fit: contain; animation: brand-pop 200ms var(--ease-out); }

/* ── Staff login gate (staff-gate.js) — opaque, covers the shell until /api/staff/me says 200 ── */
body.console.staff-gate-open { overflow: hidden; }
body.console #staffGate {
  position: fixed;
  inset: 0;
  z-index: var(--z-gate);
  display: flex;
  justify-content: center;
  padding: 24px 16px;
  overflow-y: auto;
  background: var(--pg);
}
body.console .staff-gate-card {
  width: 100%;
  max-width: 380px;
  margin: auto;
  padding: 24px 22px;
  border: 1px solid var(--line);
  border-radius: 16px;
  background: var(--surface);
  box-shadow: var(--shadow-pop);
  animation: brand-rise var(--motion-slow) var(--ease-out);
}
body.console .staff-gate-state { display: flex; flex-direction: column; gap: 8px; }
body.console .staff-gate-title { margin-bottom: 4px; font-size: var(--fs-l); font-weight: 700; }
body.console .staff-gate-msg { color: var(--muted); }
body.console .staff-gate-tabs { display: flex; gap: 6px; margin-bottom: 6px; padding: 4px; border-radius: 999px; background: var(--soft2); }
body.console .staff-gate-tabs button { flex: 1 1 0; min-width: 0; min-height: 44px; border: 0; border-radius: 999px; background: transparent; color: var(--muted); }
body.console .staff-gate-tabs button.on { background: var(--surface); color: var(--accent); box-shadow: 0 1px 3px rgba(0, 0, 0, .12); }
body.console .staff-gate-label { font-size: var(--fs-s); font-weight: 600; color: var(--muted); }
body.console #staffGate input { width: 100%; min-height: 44px; padding: 10px 12px; border: 1px solid var(--line-strong); border-radius: var(--r-s); background: var(--surface); }
body.console .staff-gate-error { min-height: 18px; font-size: var(--fs-s); font-weight: 600; color: rgb(var(--color-danger)); }
body.console .staff-gate-error:empty { min-height: 0; }
body.console .staff-gate-submit { min-height: 46px; border: 0; border-radius: var(--r); background: var(--accent); color: var(--accent-ink); font-weight: 700; }
body.console .staff-gate-submit:hover { background: var(--accent-hover); }
body.console .staff-gate-submit:disabled { opacity: .6; cursor: default; }
body.console .staff-gate-hint { margin-top: 2px; font-size: var(--fs-s); color: var(--muted); }
body.console .staff-gate-hint.staff-gate-hint-ok {
  margin-top: 8px;
  padding: 8px 10px;
  border-left: 3px solid var(--accent);
  border-radius: 6px;
  background: var(--accent-soft);
  color: var(--ink);
  font-weight: 600;
}

/* ── Touch: finger-sized targets ───────────────────────────────────────────────────────── */
@media (pointer: coarse) {
  .btn, .convo-tab, .ibtn, .avatar, .ready-toggle, .kiosk-row button, .steal-btn, .subseg button, .bn-close { min-height: 44px; }
  .ibtn, .bn-close { min-width: 44px; }
  .cz-bar .lb-btn, .cam-adj-bar .lb-btn { min-width: 44px; height: 44px; min-height: 44px; }
}

/* ── Phone (and short landscape screens) ───────────────────────────────────────────────── */
@media (max-width: 767px), (max-height: 500px) {
  :root { --hdr-h: 48px; --film-h: 72px; --ctrl-h: calc(68px + env(safe-area-inset-bottom)); }
  select, input[type="text"], input[type="search"], input[type="password"] { font-size: 16px; }
  .brand-name, .agent-name, .stage-hint { display: none; }
  .console-header { flex-wrap: wrap; gap: 8px; padding: 0 10px; }
  #queueInfo { order: 5; flex: 1 0 100%; max-width: none; padding-bottom: 4px; }
  .call-card { padding: 18px; }
  .btn-accept, .call-card > button { flex: 1 1 100%; margin-left: 0; }

  /* Lobby on a phone: one column, the whole main area scrolls. */
  .console-main { display: block; overflow: auto; }
  .console-center, #lobby, #convoRail { overflow: visible; }
  #convoRail { border-left: 0; border-top: 1px solid var(--line); }
  #convoTabbody { display: block; }
  #convoTabbody > .pane { overflow: visible; }
  #convoTabbody > .pane[data-group="guide"] { overflow: visible; }
  .gm-list { max-height: 44px; }
  .gm-now-title { min-width: 0; } /* phone: keep the one-row card as it was (visual pass 27/09) */
  .gm-preview { height: 140px; }

  /* Phone app shell in a call (body.m-ui). */
  body.m-ui.console-incall .console-header { flex-wrap: nowrap; }
  body.m-ui.console-incall .console-header > .brand,
  body.m-ui.console-incall .hdr-right > :not(#phoneGridBtn):not(#ringBlocked),
  body.m-ui.console-incall #queueInfo:not(.conn-lost) { display: none; }
  body.m-ui.console-incall #queueInfo.conn-lost { order: 0; flex: 0 1 auto; padding: 0; }
  body.m-ui.console-incall .callinfo { justify-content: flex-start; }
  body.m-ui.console-incall #screenpop .sp-sub, body.m-ui.console-incall #screenpop .src-badge { display: none; }
  body.m-ui.console-incall .phone-grid-btn { display: inline-flex; width: auto; padding: 0 10px; gap: 6px; font-size: var(--fs-s); }
  .phone-grid-btn .ic-swipe { display: none; }
  .phone-grid-btn[data-view="stack"] .ic-grid { display: none; }
  .phone-grid-btn[data-view="stack"] .ic-swipe { display: inline; }
  body.m-ui.console-incall .console-main { display: grid; grid-template-columns: minmax(0, 1fr); overflow: hidden; }
  body.m-ui.console-incall .console-center { overflow: hidden; }
  body.m-ui .stagebar { padding: 4px 10px; }
  body.m-ui .stagebar > :not(#status2) { display: none; }
  body.m-ui .stagebar:not(:has(#status2:not(:empty))) { display: none; }
  body.m-ui .stage { padding: 0; }
  body.m-ui #grid[data-phone] { align-content: stretch; }
  body.m-ui #grid[data-phone]::after { content: none; }
  body.m-ui #grid[data-phone="carousel"] {
    flex-wrap: nowrap;
    gap: 0;
    overflow-x: auto;
    overflow-y: hidden;
    overscroll-behavior-x: contain;
    scroll-snap-type: x mandatory;
    scrollbar-width: none;
  }
  body.m-ui #grid[data-phone="carousel"]::-webkit-scrollbar { display: none; }
  body.m-ui #grid[data-phone="carousel"] > .tile:not(#tile-local) {
    flex: 0 0 100%;
    width: 100%;
    max-width: none;
    height: 100%;
    border-radius: 0;
    scroll-snap-align: center;
  }
  /* A portrait slide showing a 16:9 cam with cover would cut off most of the width — a guest at the
     edge of the door cam disappears. Show the whole frame; the zoom bar still fills on demand. */
  body.m-ui #grid[data-phone="carousel"] > .tile:not(#tile-local) video { object-fit: contain; background: #000; }
  body.m-ui #grid[data-phone="stack"] { display: grid; grid-template-columns: minmax(0, 1fr); grid-auto-rows: minmax(0, 1fr); gap: 6px; padding: 0 6px; }
  body.m-ui #grid[data-phone="stack"] > .tile:not(#tile-local) { height: auto; max-width: none; grid-row: auto; }
  body.m-ui #grid[data-phone] > #tile-local {
    position: absolute;
    top: 8px;
    right: 8px;
    z-index: 3;
    width: 96px;
    height: 72px;
    border: 2px solid rgba(255, 255, 255, .75);
    border-radius: 10px;
    cursor: default;
  }
  body.m-ui #grid[data-phone="stack"] :is(.cz-bar, .cam-adj-bar), body.m-ui #grid[data-phone] .cam-adj-bar,
  body.m-ui #grid[data-phone] > #tile-local .cz-bar { display: none; }
  /* The PiP owns the top-right corner on the phone (the label the bottom-left): zoom bar top-left. */
  body.m-ui #grid[data-phone] .cz-bar { right: auto; left: 8px; }
  body.m-ui .peek {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    min-height: 36px;
    padding: 8px 14px;
    border: 0;
    border-radius: 0;
    background: rgb(var(--neutral-800));
    color: rgb(var(--neutral-100));
    font-size: var(--fs-s);
    font-weight: 500;
    text-align: left;
  }
  body.m-ui .peek:hover { background: rgb(var(--neutral-700)); }
  body.m-ui .peek .peek-text { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  body.m-ui.no-sheets .peek { display: none; }
  body.m-ui .call-controls-panel {
    flex-wrap: nowrap;
    justify-content: space-around;
    gap: 4px;
    height: var(--ctrl-h);
    padding: 6px 6px calc(6px + env(safe-area-inset-bottom));
  }
  body.m-ui .call-controls-panel > :is(.zone, .ctrl-divider, #photoBtn, #langMenuBtn) { display: none; }
  body.m-ui .zone-m { display: inline-grid; }
  body.m-ui .cbtn { flex: 1 1 0; min-width: 0; max-width: 76px; min-height: 52px; padding: 6px 2px; }
  body.m-ui .cbtn.end { min-width: 0; max-width: 84px; }
  body.m-ui .l-long { display: none; }
  body.m-ui .l-short { display: inline; }
  body.m-ui .more-phone { display: flex; }
  body.m-ui.console-incall .toast { top: calc(var(--hdr-h) + 8px); bottom: auto; }

  /* Conversation drawer: closed ⇒ #convoRail computed display:none (console.js revealConvoSheet
     reads exactly that to auto-open it when a photo arrives). It stops above the control bar so
     "Kết thúc" stays reachable. */
  body.m-ui.console-incall:not(.no-sheets) #convoRail { display: none; }
  body.m-ui.console-incall.sheet-convo:not(.no-sheets) #convoRail {
    position: fixed;
    left: 0;
    right: 0;
    bottom: var(--ctrl-h);
    z-index: var(--z-sheet);
    display: flex;
    height: min(70dvh, calc(100dvh - var(--ctrl-h) - 56px));
    overflow: hidden;
    border: 0;
    border-radius: 18px 18px 0 0;
    box-shadow: 0 -8px 30px rgba(0, 0, 0, .35);
    animation: brand-rise var(--motion-slow) var(--ease-out);
  }
  body.m-ui.console-incall.sheet-convo:not(.no-sheets) #sheetHandle { display: grid; }
  body.m-ui.console-incall:not(.no-sheets) #subs { flex-basis: 32%; }
  body.m-ui.console-incall:not(.no-sheets) #convoTabbody { display: grid; }
  body.m-ui.console-incall:not(.no-sheets) #convoTabbody > .pane { overflow: auto; }
  body.m-ui.console-incall:not(.no-sheets) #convoTabbody > .pane[data-group="guide"] { overflow: hidden; }

  /* mconvo (console.js gắn body.mconvo; ?mconvo=0 bỏ ⇒ đúng ngăn kéo phủ ở trên): mở Hội thoại =
     CHIA MÀN, không phủ video. Dọc: sân khấu video CỐ ĐỊNH --mc-video-h; ngăn nằm TRONG LUỒNG ở hàng 2
     của .console-main và ăn phần còn lại — banner "Có bản cập nhật" / dòng trạng thái (#status2) hiện
     thêm thì NGĂN co lại, video không mất. Thanh điều khiển ghim đáy (chỗ của nó giữ bằng padding).
     Ngang/thấp: xem khối landscape. */
  body.mconvo.m-ui.console-incall.sheet-convo:not(.no-sheets) { --mc-video-h: 45dvh; }
  body.mconvo.m-ui.console-incall.sheet-convo:not(.no-sheets) .console-main { grid-template-rows: auto minmax(0, 1fr); padding-bottom: var(--ctrl-h); }
  body.mconvo.m-ui.console-incall.sheet-convo:not(.no-sheets) #call { grid-template-rows: auto var(--mc-video-h) 0 0; }
  body.mconvo.m-ui.console-incall.sheet-convo:not(.no-sheets) .call-controls-panel { position: fixed; left: 0; right: 0; bottom: 0; z-index: var(--z-sheet); }
  body.mconvo.m-ui.console-incall.sheet-convo:not(.no-sheets) #sheetConvoBtn { display: none; }
  body.mconvo.m-ui.console-incall.sheet-convo:not(.no-sheets) #convoRail {
    position: static;
    height: auto;
    border-top: 1px solid var(--line);
    border-radius: 0;
    box-shadow: none;
    animation: none;
  }
  body.mconvo.m-ui.console-incall.sheet-convo:not(.no-sheets) #subs { flex-basis: 50%; }
  /* Tab Hướng dẫn trong ngăn chia màn (đo 19/10 ở 360×640 có banner + dòng trạng thái: ngăn 167px, 0/4 nút
     QR ngón tay chạm được). 4 nút QR = HÀNG RIÊNG luôn thấy ở đầu tab (console-guidemedia.js dời chúng vào
     #guideQrRow chỉ ở chế độ này), một hàng, ≥44px, dính trên cùng; phần dưới (video, bước, nội dung) giữ
     cỡ thật và CUỘN trong #guidePanel ⇒ không gì kẹt sau thanh điều khiển. Ngăn quá thấp thì phụ đề co
     trước (khung tab giữ tối thiểu hàng QR + mép). */
  body.mconvo.m-ui.console-incall.sheet-convo.convo-guide-active:not(.no-sheets) #subs { flex: 0 1 26%; }
  body.mconvo.m-ui.console-incall.sheet-convo.convo-guide-active:not(.no-sheets) #convoTabbody { min-height: 76px; }
  body.mconvo.m-ui.console-incall.sheet-convo:not(.no-sheets) #convoTabbody > .pane[data-group="guide"] { padding: 8px 10px; }
  body.mconvo.m-ui.console-incall.sheet-convo:not(.no-sheets) #guidePanel { overflow-y: auto; overscroll-behavior: contain; gap: 8px; }
  body.mconvo.m-ui.console-incall.sheet-convo:not(.no-sheets) #guidePanel > *,
  body.mconvo.m-ui.console-incall.sheet-convo:not(.no-sheets) #guidePanel > #guideBody { flex-shrink: 0; }
  body.mconvo.m-ui.console-incall.sheet-convo:not(.no-sheets) .gm-qr-row {
    position: sticky;
    top: 0;
    z-index: 1;
    display: flex;
    flex-wrap: nowrap;
    gap: 6px;
    padding-bottom: 6px;
    background: var(--surface);
  }
  body.mconvo.m-ui.console-incall.sheet-convo:not(.no-sheets) .gm-qr-row > :is(#guideQrBtn, .gm-qr) {
    flex: 1 1 0;
    min-width: 0;
    min-height: 44px;
    padding: 2px 4px;
    white-space: normal;
    line-height: 1.15;
    overflow-wrap: anywhere;
  }
  body.mconvo.sheet-convo #sheetScrim { display: none; }
  /* Ảnh về khi ngăn đóng: chấm đỏ trên biểu tượng (console.js .convo-unread; mở ngăn thì gỡ). Chấm
     .tab-dot của console-tabs.js nhường để không thành 2 chấm. */
  body.m-ui #sheetConvoBtn.convo-unread { position: relative; }
  body.m-ui #sheetConvoBtn.convo-unread::after {
    content: "";
    position: absolute;
    top: 5px;
    left: 26px;
    width: 10px;
    height: 10px;
    border-radius: 50%;
    background: var(--danger);
    box-shadow: 0 0 0 2px rgb(var(--neutral-800));
  }
  body.m-ui #sheetConvoBtn.convo-unread .tab-dot { display: none; }

  /* ?mobile=0 (no .m-ui) and ?sheets=0 (.no-sheets): plain stacked page that scrolls. */
  body.console:not(.m-ui), body.console.m-ui.no-sheets { display: block; height: auto; min-height: 100dvh; overflow: visible; }
  body.console:not(.m-ui) .console-main, body.console.m-ui.no-sheets .console-main { overflow: visible; }
  body.console:not(.m-ui) .stage, body.console.m-ui.no-sheets .stage { height: min(62vh, 75vw); }
  body.console:not(.m-ui) .console-center, body.console.m-ui.no-sheets .console-center { overflow: visible; }
}
@media (max-width: 767px) and (orientation: landscape), (max-height: 500px) and (orientation: landscape) {
  body.m-ui #grid[data-phone="stack"] { grid-template-columns: none; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); grid-template-rows: minmax(0, 1fr); }
  /* mconvo ngang/thấp: ngăn Hội thoại thành cột phải trong luồng của .console-main (video trái ~50%). */
  body.mconvo.m-ui.console-incall.sheet-convo:not(.no-sheets) .console-main { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); grid-template-rows: minmax(0, 1fr); padding-bottom: 0; }
  body.mconvo.m-ui.console-incall.sheet-convo:not(.no-sheets) #call { grid-template-rows: auto minmax(0, 1fr) auto auto; }
  body.mconvo.m-ui.console-incall.sheet-convo:not(.no-sheets) .call-controls-panel { position: static; }
  body.mconvo.m-ui.console-incall.sheet-convo:not(.no-sheets) #convoRail {
    border-top: 0;
    border-left: 1px solid var(--line);
  }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation: none !important; transition: none !important; }
}

/* cctv — shop cams (public/cctv.js). Tiles reuse .tile / .tile-media / .cz-bar (zoom + pin);
   this block only adds the 16:9 picture box, the status overlay, the HD button and the lobby panel. */
/* Picture = a 16:9 box centred in the tile (whole frame, no crop); ⛶ (.fit-contain) fills the tile.
   Default for SD and HD: the SD sub-stream is 704×576 with SAR/DAR N/A (P0(f), measured 28/09) ⇒
   shown raw it is squeezed, `fill` stretches it back to 16:9; HD 1920×1080 is 16:9 already. To flip
   (a cam that sends its own aspect): `fill` → `contain` in the object-fit line below.
   (!important: the phone carousel forces contain on every tile video.) */
.cctv-tile .tile-media { container-type: size; }
.cctv-tile video {
  --w: min(100cqw, 100cqh * 16 / 9);
  --h: min(100cqh, 100cqw * 9 / 16);
  position: absolute;
  left: calc(50cqw - var(--w) / 2);
  top: calc(50cqh - var(--h) / 2);
  width: var(--w);
  height: var(--h);
  object-fit: fill !important;
}
.cctv-tile.fit-contain video { --w: max(100cqw, 100cqh * 16 / 9); --h: max(100cqh, 100cqw * 9 / 16); }
.cctv-tile video.cctv-next { opacity: 0; } /* SD↔HD: the new stream plays hidden until it has a frame */
.cctv-over {
  position: absolute;
  inset: 0;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 8px;
  pointer-events: none;
}
.cctv-msg {
  max-width: 100%;
  padding: 3px 10px;
  border-radius: 999px;
  background: rgb(var(--neutral-950) / .72);
  color: #fff;
  font-size: var(--fs-s);
  font-weight: 600;
  text-align: center;
}
.cctv-play {
  pointer-events: auto;
  width: 48px;
  height: 48px;
  min-height: 48px;
  padding: 0;
  justify-content: center;
  border: 1px solid rgba(255, 255, 255, .5);
  border-radius: 50%;
  background: rgb(var(--neutral-950) / .72);
  color: #fff;
  font-size: var(--fs-l);
}
.cctv-play:hover { border-color: #fff; background: #fff; color: rgb(var(--neutral-950)); }
.cz-bar .cctv-hd { font-size: var(--fs-s); font-weight: 700; }
.cz-bar .cctv-hd[aria-pressed="true"] { border-color: #fff; background: #fff; color: rgb(var(--neutral-950)); }
/* camhd — HD button (+ 📸 door shot) on the kiosk door/doc tiles (console.js hdPaint; only when the kiosk
   declares the `camhd` attribute). Same look as .cctv-hd. The "HD" chip is a STATIC ::after (no
   animation), bottom-right, mirroring the name chip bottom-left. */
.cz-bar .cam-hd { font-size: var(--fs-s); font-weight: 700; }
.cz-bar .door-shot { font-size: var(--fs-m); }
.cz-bar .cam-hd[aria-pressed="true"] { border-color: #fff; background: #fff; color: rgb(var(--neutral-950)); }
.cz-bar .cam-hd:disabled { cursor: progress; }
.tile[data-hd="on"]::after {
  content: "HD";
  position: absolute;
  right: 8px;
  bottom: 8px;
  z-index: 1;
  padding: 3px 9px;
  border-radius: 999px;
  background: rgb(var(--neutral-950) / .72);
  color: #fff;
  font-size: var(--fs-s);
  font-weight: 700;
  pointer-events: none;
}
/* HD only on the big tile (phone carousel: every slide is big). */
#grid:not([data-phone="carousel"]) > .tile[data-kind="cctv"]:not([data-slot="main"], [data-slot="main2"]) .cctv-hd,
.cctv-lobby .tile:not(.cctv-big) .cctv-hd { display: none; }

/* Lobby panel: site buttons + the cams of ONE site; double-click a tile = full-width frame. */
#lobby.cctv-open .lobby-idle { flex: 0 0 auto; padding: 4px 16px; gap: 6px; }
#lobby.cctv-open .lobby-idle :is(.big, p, .devline) { display: none; }
.cctv-lobby { display: grid; gap: 10px; padding: 12px; }
.cctv-lhead { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.cctv-lhead h3 { margin-right: auto; font-size: var(--fs-l); font-weight: 600; }
.cctv-sites { display: flex; flex-wrap: wrap; gap: 6px; }
.cctv-lclose { flex: none; }
.cctv-lhint { margin: 0; }
.cctv-sites button[aria-pressed="true"] { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }
.cctv-lgrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 280px), 1fr)); gap: 10px; }
.cctv-lobby .tile {
  position: relative;
  aspect-ratio: 16 / 9;
  min-width: 0;
  border-radius: 10px;
  overflow: hidden;
  background: var(--tile);
  cursor: zoom-in;
}
.cctv-lobby .tile.cctv-big { grid-column: 1 / -1; cursor: default; }
.cctv-lobby .tile:hover .cz-bar, .cctv-lobby .tile:focus-within .cz-bar { opacity: 1; }
