/* ==========================================================================
   Wesal V2 — App Shell + NG1 foundation components
   Only what NG1 needs (shell, navigation, layers, Home widgets). Surface-
   specific styles (Inbox, CRM, Settings, Admin) arrive with their waves.
   ========================================================================== */

* { margin: 0; padding: 0; box-sizing: border-box; }
html { font-size: 16px; }
body {
  font-family: var(--font-ar);
  background: var(--w-canvas);
  color: var(--w-ink);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  overflow-x: hidden;
}
[dir="ltr"] body, body[dir="ltr"] { font-family: var(--font-en); }
button { font: inherit; color: inherit; background: none; border: none; cursor: pointer; }
input, textarea, select { font: inherit; color: inherit; }
img { max-width: 100%; }
a { color: var(--w-teal); }
bdi, .num { font-variant-numeric: tabular-nums; }
.ic { flex-shrink: 0; display: block; }
.btn .ic, .chip .ic { display: inline-block; vertical-align: -4px; }
.desktop-only { display: inline-flex; }
.mobile-only { display: none !important; }

/* ==================== Shell ==================== */
.shell { display: grid; grid-template-rows: var(--shell-top) 1fr; height: 100vh; height: 100dvh; }
.shell-body { display: grid; grid-template-columns: var(--shell-side) 1fr; min-height: 0; }

/* --- Top bar --- */
.topbar {
  display: flex; align-items: center; gap: var(--sp-3);
  background: var(--w-surface); border-bottom: 1px solid var(--w-line);
  padding: 0 var(--sp-4); position: relative; z-index: var(--z-topbar);
}
.brand { display: flex; align-items: center; min-width: calc(var(--shell-side) - 32px); min-height: 24px; text-decoration: none; } /* NG5: 24px target floor (WCAG 2.5.8) — the lockup alone is 22px */
.brand-logo { height: 34px; width: auto; display: block; }
/* dark lockup: CSS background so the 437KB PNG downloads ONLY in dark theme;
   explicit box = intrinsic 1996×624 at 22px height (no distortion, no shift) */
.brand-logo-dark { display: none; height: 22px; width: 71px; background: url('/assets/brand/Wesal_Logo_White_Transparent_AutoCropped_v05.png') center / contain no-repeat; }
[data-theme="dark"] .brand-logo-light { display: none; }
[data-theme="dark"] .brand-logo-dark { display: block; }
.brand-icon { display: none; height: 30px; width: auto; }

.ws-switch {
  display: flex; align-items: center; gap: var(--sp-2); padding: 5px 12px;
  border-radius: var(--r-ctl); border: 1px solid var(--w-line); background: var(--w-surface);
  font-weight: 600; font-size: 13px; min-height: 36px;
}
.ws-switch:hover { border-color: var(--w-line-strong); }

/* NG4.1 WR-03 — the workspace selector.
   The control now shows the tenant name AND the active channel, stacked, so
   the channel is on screen rather than only in the accessibility label. The
   menu is anchored to the control and is logically positioned, so it opens on
   the correct side in both RTL and LTR without a direction-specific rule. */
.ws-wrap { position: relative; }
.ws-switch .ws-text { display: flex; flex-direction: column; align-items: flex-start; line-height: 1.15; min-width: 0; }
.ws-switch .ws-name { font-weight: 600; font-size: 13px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 22ch; unicode-bidi: plaintext; text-align: start; }
.ws-switch .ws-channel { font-weight: 500; font-size: 11px; color: var(--w-ink-2); white-space: nowrap; }
/* P1 (2026-09-02, found in visual acceptance): the workspace menu was OPEN on
   every page. #wsMenu carries the hidden attribute, but .ws-menu sets
   display: flex, and an author class rule outranks the UA stylesheet's
   [hidden] { display: none } — so the attribute did nothing and the menu
   rendered permanently under the control, on the baseline tree too. A global
   [hidden] rule with !important makes the attribute mean what it says for
   every element in the shell, now and for any future display: rule. */
[hidden] { display: none !important; }

.ws-menu {
  position: absolute; inset-inline-start: 0; top: calc(100% + 6px); min-width: 220px;
  background: var(--w-surface); border: 1px solid var(--w-line); border-radius: var(--r-sheet);
  box-shadow: var(--e-float); z-index: var(--z-layer); padding: 6px; display: flex; flex-direction: column; gap: 2px;
}
.ws-choice {
  display: flex; align-items: center; gap: var(--sp-2); width: 100%;
  padding: 9px 10px; border-radius: var(--r-ctl); border: 0; background: transparent;
  font-size: 13px; font-weight: 500; color: var(--w-ink); text-align: start; min-height: 40px;
}
.ws-choice:hover { background: var(--w-surface-2); }
.ws-choice.on { background: var(--w-surface-2); font-weight: 600; }
.ws-choice .ws-choice-ico { display: inline-flex; color: var(--w-ink-2); }
.ws-choice.on .ws-choice-ico { color: var(--w-teal); }
.ws-choice .ws-choice-on { margin-inline-start: auto; display: inline-flex; color: var(--w-teal); }

/* A nav badge states a real limit on a destination (OPEN-1: Automation is one
   Salla toggle, not an engine). Deliberately quiet — it informs, it does not
   advertise — and it never pushes the label out of the row. */
.nav-item .nav-badge {
  margin-inline-start: auto; flex: none;
  font-size: 10.5px; font-weight: 600; line-height: 1;
  padding: 3px 6px; border-radius: 999px;
  background: var(--w-surface-2); color: var(--w-ink-2);
  border: 1px solid var(--w-line);
}
.nav-item.active .nav-badge { background: transparent; }

.topbar-search {
  flex: 1; max-width: 460px; display: flex; align-items: center; gap: var(--sp-2);
  background: var(--w-surface-2); border: 1px solid transparent;
  border-radius: var(--r-ctl); padding: 7px 12px; color: var(--w-ink-3); cursor: pointer;
  min-height: 36px;
}
.topbar-search:hover { border-color: var(--w-line-strong); }
.topbar-search kbd {
  font-family: var(--font-en); font-size: 11px; background: var(--w-surface);
  border: 1px solid var(--w-line); border-radius: 5px; padding: 1px 6px;
  color: var(--w-ink-3); margin-inline-start: auto;
}

.topbar-actions { display: flex; align-items: center; gap: var(--sp-2); margin-inline-start: auto; }
.icon-btn {
  width: 36px; height: 36px; display: grid; place-items: center;
  border-radius: var(--r-ctl); color: var(--w-ink-2); position: relative;
}
.icon-btn:hover { background: var(--w-surface-2); color: var(--w-ink); }
.icon-btn .lang-label { font-size: 12px; font-weight: 800; }
.icon-btn .dot {
  position: absolute; top: 7px; inset-inline-end: 7px; width: 8px; height: 8px;
  border-radius: 50%; background: var(--w-danger); border: 2px solid var(--w-surface);
}
.market-chip {
  display: inline-flex; align-items: center; gap: 6px; padding: 5px 10px;
  background: var(--w-surface-2); border-radius: 999px; font-size: 12px; font-weight: 600;
  color: var(--w-ink-2); border: 1px solid var(--w-line); white-space: nowrap;
}
.avatar {
  width: 32px; height: 32px; border-radius: 50%; display: grid; place-items: center;
  background: var(--w-brand-navy); color: #fff; font-size: 12px; font-weight: 700; flex-shrink: 0;
  line-height: 1; overflow: hidden; user-select: none;
}
[data-theme="dark"] .avatar { color: var(--w-ink); background: var(--w-surface-3); }
/* Customer 360 uses the same circle at a larger size. This size class was
   referenced by the markup from day one but had no rule, so C360 silently
   rendered a 32px avatar. */
.avatar.xl { width: 64px; height: 64px; font-size: 22px; }

/* ── Topbar action pills (Main website & Logout) ───────────────────────── */
.topbar-pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 0 12px;
  border-radius: var(--r-ctl);
  font-size: 12.5px;
  font-weight: 600;
  text-decoration: none;
  border: 1px solid var(--w-line);
  background: var(--w-surface);
  color: var(--w-ink-2);
  transition: all 0.15s ease;
  cursor: pointer;
  height: 34px;
  white-space: nowrap;
}
.topbar-pill:hover {
  background: var(--w-surface-2);
  color: var(--w-teal);
  border-color: var(--w-teal-ring);
}
.topbar-pill.topbar-logout {
  color: var(--w-danger);
  border-color: rgba(179, 56, 45, 0.2);
}
.topbar-pill.topbar-logout:hover {
  background: var(--w-danger-soft);
  color: var(--w-danger);
  border-color: var(--w-danger);
}
.topbar-pill .tp-ico {
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

/* ── Account menu (topbar) ──────────────────────────────────────────────
   The signed-in person's own menu: the public site, sign out. */
.acct-wrap { position: relative; display: flex; }
.avatar.acct-btn { cursor: pointer; border: 0; padding: 0; font: inherit; font-size: 12px; font-weight: 700; }
.avatar.acct-btn:hover { filter: brightness(1.08); }
.avatar.acct-btn:focus-visible { outline: 2px solid var(--w-teal); outline-offset: 2px; }
.acct-menu {
  inset-inline-start: auto;
  inset-inline-end: 0;
  min-width: 220px;
  padding: 8px 6px;
  border-radius: var(--r-card);
  box-shadow: 0 10px 25px -5px rgba(11, 37, 69, 0.15), 0 0 0 1px var(--w-line);
}
.acct-head { padding: 8px 10px 6px; display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.acct-name { font-size: 13px; font-weight: 700; color: var(--w-ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.acct-sub { font-size: 12px; color: var(--w-ink-3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.acct-menu .sheet-sep { margin: 4px 0; }
.ws-choice.acct-danger, .ws-choice.acct-danger .ws-choice-ico { color: var(--w-danger); }
.ws-choice.acct-danger:hover { background: color-mix(in srgb, var(--w-danger) 10%, transparent); }
.sheet-item.si-danger { color: var(--w-danger); }

/* ── NG2.1 customer avatar palette ───────────────────────────────────────
   Chosen deterministically from the OPAQUE conversation id (see
   public/v2/avatar.js), so one customer keeps one color across the list row,
   the thread header, Customer 360 and the Home work queue.

   These colors are IDENTITY ONLY. They deliberately reuse none of the
   semantic tokens (--w-success / --w-danger / --w-warn): conversation state
   and channel stay in their own chips and badges, so a color can never be
   misread as "resolved" or "failed". Every pair below clears 4.5:1 for the
   initials, in both themes. */
.avatar[class*="av-c"] { color: #fff; }
.avatar.av-c0 { background: #1D4ED8; }
.avatar.av-c1 { background: #6D28D9; }
.avatar.av-c2 { background: #0F766E; }
.avatar.av-c3 { background: #9D174D; }
.avatar.av-c4 { background: #155E75; }
.avatar.av-c5 { background: #86198F; }
.avatar.av-c6 { background: #4338CA; }
.avatar.av-c7 { background: #0C4A6E; }
[data-theme="dark"] .avatar[class*="av-c"] { color: #06232B; }
[data-theme="dark"] .avatar.av-c0 { background: #60A5FA; }
[data-theme="dark"] .avatar.av-c1 { background: #A78BFA; }
[data-theme="dark"] .avatar.av-c2 { background: #5EEAD4; }
[data-theme="dark"] .avatar.av-c3 { background: #FDA4AF; }
[data-theme="dark"] .avatar.av-c4 { background: #67E8F9; }
[data-theme="dark"] .avatar.av-c5 { background: #F0ABFC; }
[data-theme="dark"] .avatar.av-c6 { background: #A5B4FC; }
[data-theme="dark"] .avatar.av-c7 { background: #7DD3FC; }
@media (prefers-contrast: more) {
  .avatar[class*="av-c"] { outline: 2px solid var(--w-ink); outline-offset: -2px; }
}

/* --- Sidebar --- */
.sidenav {
  background: var(--w-surface); border-inline-end: 1px solid var(--w-line);
  overflow-y: auto; padding: var(--sp-3) 10px var(--sp-5);
  display: flex; flex-direction: column; gap: 2px;
}
.nav-group-label {
  font-size: 11px; font-weight: 700; color: var(--w-ink-3);
  letter-spacing: .3px; padding: 14px 12px 6px; text-transform: uppercase;
}
.nav-item {
  display: flex; align-items: center; gap: 10px; width: 100%;
  padding: 8.5px 12px; border-radius: var(--r-ctl);
  color: var(--w-ink-2); font-weight: 500; font-size: 14px;
  position: relative; text-align: start; transition: background var(--motion-fast);
  text-decoration: none;
}
.nav-item:hover { background: var(--w-surface-2); color: var(--w-ink); }
.nav-item.active { background: var(--w-teal-soft); color: var(--w-teal-strong); font-weight: 700; }
[data-theme="dark"] .nav-item.active { color: var(--w-teal); }
.nav-item.active::before {
  content: ""; position: absolute; inset-inline-start: -10px; top: 6px; bottom: 6px;
  width: 3px; border-radius: 3px; background: var(--w-thread-v);
}
.nav-item .n-ico { width: 20px; display: grid; place-items: center; flex-shrink: 0; }
.nav-item .n-count {
  margin-inline-start: auto; background: var(--w-surface-3); color: var(--w-ink-2);
  border-radius: 999px; font-size: 11px; font-weight: 700; padding: 1px 8px;
}
.nav-item.active .n-count { background: var(--w-teal); color: #fff; }
[data-theme="dark"] .nav-item.active .n-count { color: #04252B; }

/* --- Main --- */
.main { min-width: 0; min-height: 0; display: flex; flex-direction: column; overflow: hidden; }
.page { flex: 1; overflow-y: auto; padding: var(--sp-5) var(--sp-6) 40px; }

/* NG2.1 — full-bleed surfaces (the inbox) own their own internal scrolling.
   `.page` alone is a BLOCK box, so `flex: 1` on a child like `.ibx` was inert:
   the grid grew to the height of the transcript, `.ibx-msgs` never became
   shorter than its content, and its `overflow-y: auto` therefore never
   engaged — the whole page scrolled instead. Making the full-bleed page a
   height-constrained flex container is the missing link in the chain
   .shell(100dvh) → .shell-body → .main → .page.full-bleed → .ibx → .ibx-thread
   → .ibx-thread-wrap → .ibx-msgs. `min-height: 0` is required at every step:
   a flex/grid item's default `min-height: auto` refuses to shrink below its
   content and would silently restore the old behavior. */
.page.full-bleed {
  flex: 1;
  min-height: 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  padding: 0;
  overflow: hidden;
}
.page-inner { max-width: var(--content-max); margin: 0 auto; }
.page-head { display: flex; align-items: flex-start; gap: var(--sp-4); flex-wrap: wrap; margin-bottom: var(--sp-5); }
.crumbs { font-size: 12px; color: var(--w-ink-3); margin-bottom: 2px; display: flex; gap: 6px; align-items: center; }
.crumbs a { color: inherit; text-decoration: none; }
.crumbs a:hover { color: var(--w-teal); }
.page-title { font-size: var(--fs-title); font-weight: 700; line-height: 1.25; }
.page-sub { color: var(--w-ink-2); font-size: 13.5px; margin-top: 2px; }
.page-head .actions { margin-inline-start: auto; display: flex; gap: var(--sp-2); align-items: center; flex-wrap: wrap; }

/* ==================== Primitives ==================== */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  padding: 8px 16px; border-radius: var(--r-ctl); font-weight: 600; font-size: 14px;
  border: 1px solid transparent; transition: all var(--motion-fast);
  white-space: nowrap; text-decoration: none;
}
.btn-primary { background: var(--w-teal); color: #fff; }
.btn-primary:hover { background: var(--w-teal-strong); }
[data-theme="dark"] .btn-primary { color: #04252B; }
.btn-secondary { background: var(--w-surface); border-color: var(--w-line-strong); color: var(--w-ink); }
.btn-secondary:hover { background: var(--w-surface-2); }
.btn-ghost { color: var(--w-ink-2); }
.btn-ghost:hover { background: var(--w-surface-2); color: var(--w-ink); }
.btn.sm { padding: 5px 11px; font-size: 12.5px; }

.chip {
  display: inline-flex; align-items: center; gap: 5px; padding: 2.5px 10px;
  border-radius: 999px; font-size: 11.5px; font-weight: 600; line-height: 1.5;
}
.chip.success { background: var(--w-success-soft); color: var(--w-success); }
.chip.warn { background: var(--w-warn-soft); color: var(--w-warn); }
.chip.danger { background: var(--w-danger-soft); color: var(--w-danger); }
.chip.info { background: var(--w-info-soft); color: var(--w-info); }
.chip.neutral { background: var(--w-surface-3); color: var(--w-ink-2); }
.chip.teal { background: var(--w-teal-soft); color: var(--w-teal-strong); }
[data-theme="dark"] .chip.teal { color: var(--w-teal); }
.chip.wa { background: var(--ch-whatsapp-soft); color: var(--ch-whatsapp); }
.chip.ig { background: var(--ch-instagram-soft); color: var(--ch-instagram-ink); }
.chip.fb { background: var(--ch-messenger-soft, #e8f0ff); color: var(--ch-messenger-ink, #1b4fd8); }

.card { background: var(--w-surface); border-radius: var(--r-card); box-shadow: var(--e-raised); padding: 18px; }
.card-title { font-size: 13px; font-weight: 700; color: var(--w-ink-2); margin-bottom: 10px; display: flex; align-items: center; gap: 8px; }
.side-sec { border-top: 1px solid var(--w-line); margin-top: 14px; padding-top: 12px; }

.input {
  width: 100%; padding: 8px 12px; border-radius: var(--r-ctl);
  border: 1px solid var(--w-line-strong); background: var(--w-surface);
  font-size: 14px; color: var(--w-ink);
}
.input::placeholder { color: var(--w-ink-3); }
.input:focus { outline: 2px solid var(--w-teal); outline-offset: 0; border-color: transparent; }

.seg { display: inline-flex; background: var(--w-surface-2); border-radius: var(--r-ctl); padding: 3px; gap: 2px; }
.seg button { padding: 5px 12px; border-radius: 8px; font-size: 12.5px; font-weight: 600; color: var(--w-ink-2); }
.seg button.active { background: var(--w-surface); color: var(--w-ink); box-shadow: var(--e-raised); }

.thread-bar { height: 3px; background: var(--w-thread); border-radius: 3px; }

/* KPI card */
.kpi {
  background: var(--w-surface); border-radius: var(--r-card); box-shadow: var(--e-raised);
  padding: 16px 18px; display: flex; flex-direction: column; gap: 4px;
  cursor: pointer; border: 1px solid transparent; text-align: start;
  transition: border-color var(--motion-fast); text-decoration: none; color: inherit;
}
.kpi:hover { border-color: var(--w-teal); }
.kpi .k-label { font-size: 12.5px; font-weight: 600; color: var(--w-ink-2); }
.kpi .k-value { font-size: 1.65rem; font-weight: 700; font-variant-numeric: tabular-nums; }
.kpi .k-def { font-size: 12px; color: var(--w-ink-3); }
.kpi.absent { cursor: default; }
.kpi.absent:hover { border-color: transparent; }
.kpi .k-absent { font-size: 13px; color: var(--w-ink-3); }

/* queue rows */
.queue-item { display: flex; gap: 10px; align-items: center; padding: 10px 0; border-bottom: 1px solid var(--w-line); }
.queue-item:last-child { border-bottom: none; }
.queue-item .q-body { flex: 1; min-width: 0; }
.queue-item .q-name { display: block; font-weight: 600; font-size: 13.5px; }
.queue-item .q-sub { display: block; font-size: 12.5px; color: var(--w-ink-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.av-wrap { position: relative; flex-shrink: 0; }
.av-badge {
  position: absolute; bottom: -2px; inset-inline-start: -2px;
  width: 16px; height: 16px; border-radius: 50%; display: grid; place-items: center;
  color: #fff; border: 2px solid var(--w-surface);
}
.av-badge.wa { background: var(--ch-whatsapp); }
.av-badge.ig { background: var(--ch-instagram); }
.av-badge .ic { width: 9px; height: 9px; }

.ready-item { display: flex; gap: 9px; align-items: center; padding: 6px 0; font-size: 13px; }
.ready-item .ok { color: var(--w-success); display: inline-flex; }
.ready-item .todo { color: var(--w-ink-3); display: inline-flex; }

/* states */
.empty {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 8px; padding: 36px 20px; text-align: center; color: var(--w-ink-2);
}
.empty .e-ico { width: 48px; height: 48px; border-radius: 14px; background: var(--w-surface-2); display: grid; place-items: center; }
.empty .e-title { font-weight: 700; color: var(--w-ink); }
.empty .e-sub { font-size: 12.5px; max-width: 340px; }
.skel { border-radius: 8px; background: linear-gradient(90deg, var(--w-surface-2) 25%, var(--w-surface-3) 50%, var(--w-surface-2) 75%); background-size: 200% 100%; animation: shimmer 1.4s infinite; }
@keyframes shimmer { to { background-position: -200% 0; } }
.banner {
  display: flex; align-items: center; gap: 10px; padding: 10px 14px;
  border-radius: var(--r-ctl); font-size: 13px; font-weight: 500;
}
.banner.warn { background: var(--w-warn-soft); color: var(--w-warn); }
.banner.danger { background: var(--w-danger-soft); color: var(--w-danger); }
.banner.info { background: var(--w-info-soft); color: var(--w-info); }

/* ==================== Layers ==================== */
.scrim { position: fixed; inset: 0; background: rgba(11, 21, 38, 0.5); z-index: var(--z-scrim); display: none; }
.scrim.open { display: block; }
.dialog {
  position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%);
  width: min(440px, calc(100vw - 32px)); background: var(--w-surface);
  border-radius: var(--r-sheet); box-shadow: var(--e-float); z-index: var(--z-layer);
  padding: 22px; display: none;
}
.dialog.open { display: block; }
.dialog h2 { font-size: 16px; margin-bottom: 6px; }
.dialog p { font-size: 13px; color: var(--w-ink-2); margin-bottom: 16px; }
.dialog .d-actions { display: flex; gap: 8px; justify-content: flex-end; }
.drawer {
  position: fixed; top: 0; bottom: 0; inset-inline-end: 0; width: min(380px, 92vw);
  background: var(--w-surface); box-shadow: var(--e-float); z-index: var(--z-layer);
  transform: translateX(calc(var(--drawer-dir, -1) * 105%)); transition: transform var(--motion-panel);
  display: flex; flex-direction: column;
}
[dir="rtl"] .drawer { --drawer-dir: -1; }
[dir="ltr"] .drawer { --drawer-dir: 1; }
.drawer.open { transform: translateX(0); }
.drawer .dr-head { display: flex; align-items: center; gap: 10px; padding: 16px; border-bottom: 1px solid var(--w-line); font-weight: 700; }
.drawer .dr-head .dr-close { margin-inline-start: auto; }
.drawer .dr-body { flex: 1; overflow-y: auto; padding: 16px; }

.cmdk {
  position: fixed; top: 12vh; left: 50%; transform: translateX(-50%);
  width: min(560px, calc(100vw - 32px)); background: var(--w-surface);
  border-radius: var(--r-sheet); box-shadow: var(--e-float); z-index: var(--z-layer);
  overflow: hidden; display: none;
}
.cmdk.open { display: block; }
.cmdk input { width: 100%; border: none; outline: none; background: transparent; padding: 16px 18px; font-size: 15px; border-bottom: 1px solid var(--w-line); color: var(--w-ink); }
.cmdk .ck-list { max-height: 300px; overflow-y: auto; padding: 8px; }
.cmdk .ck-item { display: flex; gap: 10px; align-items: center; width: 100%; padding: 10px 12px; border-radius: 10px; font-size: 14px; text-align: start; color: var(--w-ink); }
.cmdk .ck-item:hover, .cmdk .ck-item.sel { background: var(--w-teal-soft); }
.cmdk .ck-hint { font-size: 11px; color: var(--w-ink-3); padding: 8px 14px; border-top: 1px solid var(--w-line); }

.sheet {
  position: fixed; inset-inline: 0; bottom: 0; z-index: var(--z-layer);
  background: var(--w-surface); border-radius: var(--r-sheet) var(--r-sheet) 0 0;
  box-shadow: var(--e-float); transform: translateY(110%); transition: transform var(--motion-panel);
  padding: 6px 14px calc(14px + env(safe-area-inset-bottom));
  max-height: 78vh; overflow-y: auto;
}
.sheet.open { transform: translateY(0); }
.sheet-grip { width: 36px; height: 4px; border-radius: 2px; background: var(--w-line); margin: 6px auto 8px; }
.sheet-title { font-size: 12px; font-weight: 700; color: var(--w-ink-3); padding: 8px 8px 4px; }
.sheet-item {
  display: flex; align-items: center; gap: 12px; width: 100%; min-height: 48px;
  padding: 11px 8px; border-radius: 12px; font-size: 14.5px; font-weight: 600;
  color: var(--w-ink); text-align: start; text-decoration: none;
}
.sheet-item:hover { background: var(--w-surface-2); }
.sheet-item .si-sub { margin-inline-start: auto; font-size: 12.5px; color: var(--w-ink-3); font-weight: 500; display: inline-flex; gap: 6px; align-items: center; }
.sheet-sep { height: 1px; background: var(--w-line); margin: 6px 0; }

.toast {
  position: fixed; bottom: 20px; inset-inline-start: 50%; transform: translateX(50%);
  background: var(--w-brand-navy); color: #fff; padding: 10px 18px; border-radius: 12px;
  font-size: 13px; z-index: var(--z-toast); box-shadow: var(--e-float); display: none;
}
[dir="ltr"] .toast { transform: translateX(-50%); }
[data-theme="dark"] .toast { background: var(--w-surface-3); color: var(--w-ink); }
.toast.open { display: block; }

/* mobile tab bar */
.m-tabbar { display: none; }

/* ==================== Home grid ==================== */
.home-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px; }
.home-row { display: grid; grid-template-columns: 2fr 1fr; gap: 14px; margin-top: 14px; align-items: start; }

/* ==================== Responsive ==================== */
@media (max-width: 1180px) {
  .home-grid { grid-template-columns: repeat(2, 1fr); }
  .home-row { grid-template-columns: 1fr; }
}
@media (max-width: 1023px) {
  .shell-body { grid-template-columns: var(--shell-side-rail) 1fr; }
  .sidenav .nav-group-label, .sidenav .nav-item > span:not(.n-ico), .sidenav .nav-item .n-count { display: none; }
  .nav-item { justify-content: center; padding: 12px 0; }
}
@media (max-width: 767px) {
  .desktop-only { display: none !important; }
  .mobile-only { display: inline-flex !important; }

  .shell { grid-template-rows: var(--shell-top-mobile) 1fr; }
  .shell-body { grid-template-columns: 1fr; }
  .sidenav { display: none; }
  .topbar { padding: 0 var(--sp-3); gap: var(--sp-2); }
  .brand { min-width: 0; }
  .brand-logo { display: none !important; }
  .brand-icon { display: block; }
  .ws-switch { min-width: 0; overflow: hidden; max-width: 55vw; }
  .ws-switch .ws-name { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-size: 13px; }
  .topbar-search { display: none; }
  .page { padding: var(--sp-4) var(--sp-4) 90px; }
  .page-head .actions { margin-inline-start: auto; }
  .home-grid { grid-template-columns: repeat(2, 1fr); gap: 10px; }
  .kpi .k-value { font-size: 1.4rem; }

  .m-tabbar {
    display: flex; position: fixed; bottom: 0; inset-inline: 0; z-index: var(--z-tabbar);
    background: var(--w-surface); border-top: 1px solid var(--w-line);
    padding: 4px 8px calc(6px + env(safe-area-inset-bottom));
  }
  .m-tabbar a, .m-tabbar button {
    flex: 1; display: flex; flex-direction: column; align-items: center; gap: 2px;
    font-size: 11px; font-weight: 600; color: var(--w-ink-3); padding: 4px 0;
    border-radius: 10px; min-height: var(--touch-min); text-decoration: none;
  }
  .m-tabbar .active { color: var(--w-teal-strong); }
  [data-theme="dark"] .m-tabbar .active { color: var(--w-teal); }

  .btn, .icon-btn { min-height: var(--touch-min); }
  .icon-btn { min-width: var(--touch-min); }
}
@media (max-width: 420px) {
  .home-grid { grid-template-columns: 1fr 1fr; }
}

/* NG4 review: coarse-pointer target floor.

   Audited at 390x844 with a coarse pointer, which is where the 44px
   contract actually applies — the earlier "20 controls" figure came from a
   1440 desktop measurement with a fine pointer, where it does not. Three
   shared-shell controls fell short and every one of them surrounds each
   NG4 surface:

     #wsSwitch    115.4 x 36    workspace switcher, used constantly
     #brandLink    28.6 x 30    home link in the header
     #skipLink    121.4 x 38.4  keyboard skip link

   Fixed centrally rather than per control, and only under coarse pointer so
   desktop density is untouched. */
@media (pointer: coarse) {
  .ws-switch,
  .topbar .brand,
  .skip-link,
  /* NG4.1 — the selector's own choices are actionable controls and belong
     under the same floor as everything else the thumb has to hit. */
  .ws-choice {
    min-block-size: 44px;
  }
  .topbar .brand,
  .ws-switch {
    display: inline-flex;
    align-items: center;
  }
}
