/* ============================================================
   TradeMetriq — support.css
   Shared design tokens + base components for all 34 screens.
   Zero external requests: fonts served locally from ./fonts/.
   Visual language: Direction B (LOCKED) — broken-white on cool-gray.
   ============================================================ */

/* ---------- FONTS (local woff2, offline) ---------- */
@font-face{font-family:'DM Sans';font-style:normal;font-weight:400;font-display:swap;src:url('fonts/dm-sans-400.woff2') format('woff2')}
@font-face{font-family:'DM Sans';font-style:normal;font-weight:500;font-display:swap;src:url('fonts/dm-sans-500.woff2') format('woff2')}
@font-face{font-family:'DM Sans';font-style:normal;font-weight:600;font-display:swap;src:url('fonts/dm-sans-600.woff2') format('woff2')}
@font-face{font-family:'DM Sans';font-style:normal;font-weight:700;font-display:swap;src:url('fonts/dm-sans-700.woff2') format('woff2')}
@font-face{font-family:'Inter';font-style:normal;font-weight:400;font-display:swap;src:url('fonts/inter-400.woff2') format('woff2')}
@font-face{font-family:'Inter';font-style:normal;font-weight:500;font-display:swap;src:url('fonts/inter-500.woff2') format('woff2')}
@font-face{font-family:'Inter';font-style:normal;font-weight:600;font-display:swap;src:url('fonts/inter-600.woff2') format('woff2')}
@font-face{font-family:'Inter';font-style:normal;font-weight:700;font-display:swap;src:url('fonts/inter-700.woff2') format('woff2')}
@font-face{font-family:'DM Mono';font-style:normal;font-weight:400;font-display:swap;src:url('fonts/dm-mono-400.woff2') format('woff2')}
@font-face{font-family:'DM Mono';font-style:normal;font-weight:500;font-display:swap;src:url('fonts/dm-mono-500.woff2') format('woff2')}

/* ---------- TOKENS — Tenant (Direction B, light, default) ---------- */
:root{
  /* surface */
  --bg:#E8EAEE; --panel:#FBFAF6; --card:#FBFAF6; --card-2:#FFFFFF; --card-border:#E6E3DC;
  /* Ground-5 (2026-07-29, pre-Azam-Pesa-board-pitch accessibility audit): --muted/--amber/--green
     were failing WCAG AA text contrast against their own standard backgrounds (muted on --card
     measured 3.14:1, amber on --amber-soft 2.69:1, green on --green-soft 3.13:1 — all need 4.5:1
     for normal text). Darkened each just enough to clear AA with margin (5.7/6.2/6.4:1
     respectively), keeping the same hue family so nothing LOOKS like a different color, just a
     more legible shade of it. --amber-soft/--green-soft/--card unchanged — only the text tokens.
  */
  --ink:#1A2235; --ink-soft:#49526A; --muted:#5B6472;
  --line:#E6E3DC; --line-soft:#F0EEE7;
  /* brand */
  --primary:#0B4F8A; --primary-soft:rgba(11,79,138,.08);
  --accent:#0A7C6E; --accent-soft:rgba(10,124,110,.10);
  --amber:#9A3412; --amber-soft:rgba(217,119,6,.12);
  --ember:#B91C1C; --ember-soft:rgba(185,28,28,.10);
  --green:#065F46; --green-soft:rgba(5,150,105,.12);
  --info:#2563EB; --info-soft:rgba(37,99,235,.10);
  --purple:#7C3AED; --purple-soft:rgba(124,58,237,.10);
  /* hierarchy badge colors */
  --h-company:#0B4F8A; --h-zone:#0A7C6E; --h-supervisor:#D97706; --h-agent:#6B7280;
  /* sidebar/topbar */
  --side-bg:#FCFBF8; --side-fg:#1A2235; --side-muted:#8A8F9C; --side-active:#0B4F8A; --side-line:#EAE6DE;
  --top-bg:#FCFBF8; --top-fg:#1A2235;
  /* shape */
  --radius:12px; --radius-sm:9px; --radius-lg:16px;
  --shadow:0 1px 2px rgba(16,24,40,.05), 0 4px 14px rgba(16,24,40,.04);
  --shadow-lg:0 18px 50px rgba(15,25,41,.18);
  --grid-line:rgba(16,24,40,.05);
  --num-weight:700;
  /* type */
  --font-display:'DM Sans',system-ui,sans-serif;
  --font-body:'Inter',system-ui,sans-serif;
  --font-mono:'DM Mono',ui-monospace,monospace;
}

/* ---------- TOKENS — Super Admin (dark command center) ---------- */
[data-theme="dark"]{
  --bg:#0F1929; --panel:#1A2740; --card:#1A2740; --card-2:#16223A; --card-border:#27344E;
  --ink:#EAF1F8; --ink-soft:#9FB1C8; --muted:#6E7F98;
  --line:#27344E; --line-soft:#1E2B45;
  --primary:#3B82F6; --primary-soft:rgba(59,130,246,.14);
  --accent:#14B8A6; --accent-soft:rgba(20,184,166,.14);
  --amber:#F59E0B; --amber-soft:rgba(245,158,11,.16);
  --ember:#F0506E; --ember-soft:rgba(240,80,110,.16);
  --green:#34D399; --green-soft:rgba(52,211,153,.15);
  --info:#60A5FA; --info-soft:rgba(96,165,250,.14);
  --purple:#A78BFA; --purple-soft:rgba(167,139,250,.15);
  --side-bg:#0B1422; --side-fg:#EAF1F8; --side-muted:#6E7F98; --side-active:#D97706; --side-line:rgba(255,255,255,.07);
  --top-bg:#0B1422; --top-fg:#EAF1F8;
  --card-border:#27344E; --grid-line:rgba(255,255,255,.06);
  --shadow:0 1px 2px rgba(0,0,0,.3), 0 8px 24px rgba(0,0,0,.28);
}

/* ---------- TOKENS — Dusk (mid-tone, third theme) ----------
   ⭐NEW (2026-08-10, owner request): a third theme between the light default and the dark
   Super Admin command-center — not a mechanical 50% blend (which reads muddy), but its own
   deliberate identity: an evening-sky slate-blue surface with a warm terracotta accent for
   active/highlight states, distinct from light's blue sidebar-active and dark's amber one.
   Same brand hue family throughout (primary stays blue, accent stays teal) — only brightness
   and the signature highlight color shift, so it reads as a genuine sibling of both existing
   themes rather than an unrelated fourth palette. */
[data-theme="dusk"]{
  --bg:#2E3A4E; --panel:#38455C; --card:#38455C; --card-2:#414F68; --card-border:#4A5872;
  --ink:#EDF0F5; --ink-soft:#B8C2D4; --muted:#8590A6;
  --line:#4A5872; --line-soft:#414F68;
  --primary:#5B9BD9; --primary-soft:rgba(91,155,217,.16);
  --accent:#3FC2AC; --accent-soft:rgba(63,194,172,.16);
  --amber:#E8A33D; --amber-soft:rgba(232,163,61,.16);
  --ember:#E8677A; --ember-soft:rgba(232,103,122,.15);
  --green:#4ECBA0; --green-soft:rgba(78,203,160,.15);
  --info:#7EB0EE; --info-soft:rgba(126,176,238,.15);
  --purple:#B49EF0; --purple-soft:rgba(180,158,240,.15);
  --h-company:#5B9BD9; --h-zone:#3FC2AC; --h-supervisor:#E8A33D; --h-agent:#8590A6;
  --side-bg:#232E40; --side-fg:#EDF0F5; --side-muted:#7C879C; --side-active:#E0835F; --side-line:rgba(255,255,255,.07);
  --top-bg:#232E40; --top-fg:#EDF0F5;
  --grid-line:rgba(255,255,255,.05);
  --shadow:0 1px 2px rgba(10,15,25,.25), 0 8px 24px rgba(10,15,25,.22);
}

/* ---------- BASE ---------- */
*{box-sizing:border-box}
html,body{margin:0;padding:0}
html{overflow-x:hidden}
body{background:var(--bg);color:var(--ink);font-family:var(--font-body);font-size:15px;-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility}
h1,h2,h3,h4{font-family:var(--font-display);font-weight:700;margin:0;letter-spacing:-.02em}
a{color:inherit;text-decoration:none}
::-webkit-scrollbar{width:10px;height:10px}
::-webkit-scrollbar-thumb{background:rgba(120,130,145,.28);border-radius:20px;border:3px solid transparent;background-clip:content-box}
::-webkit-scrollbar-track{background:transparent}
.mono{font-family:var(--font-mono)}

/* type scale */
.tm-display{font-family:var(--font-display);font-weight:700;font-size:40px;line-height:1.05;letter-spacing:-.03em}
.tm-h1{font-family:var(--font-display);font-weight:700;font-size:30px;line-height:1.08;letter-spacing:-.025em}
.tm-h2{font-family:var(--font-display);font-weight:700;font-size:22px;line-height:1.2;letter-spacing:-.02em}
.tm-h3{font-family:var(--font-display);font-weight:700;font-size:17px;line-height:1.25;letter-spacing:-.01em}
.tm-eyebrow{font-size:10px;letter-spacing:.13em;text-transform:uppercase;color:var(--muted);font-weight:700;overflow-wrap:break-word}
.tm-sub{font-size:13.5px;color:var(--ink-soft)}
.tm-muted{color:var(--muted)}

/* ---------- APP SHELL ---------- */
.tm-app{display:flex;min-height:100vh}
.tm-side{width:248px;flex:0 0 248px;background:var(--side-bg);color:var(--side-fg);display:flex;flex-direction:column;position:sticky;top:0;height:100vh;border-right:1px solid var(--side-line)}
.tm-side-brand{padding:22px 20px 18px;display:flex;align-items:center;gap:11px;border-bottom:1px solid var(--side-line)}
.tm-side-nav{padding:14px 12px;display:flex;flex-direction:column;gap:2px;flex:1;overflow-y:auto}
.tm-side-group{font-size:10px;letter-spacing:.13em;text-transform:uppercase;color:var(--side-muted);padding:14px 12px 6px;font-weight:600}
.tm-nav{display:flex;align-items:center;gap:12px;padding:10px 12px;border-radius:9px;color:var(--side-fg);font-size:14px;background:transparent;border:none;cursor:pointer;font-family:var(--font-body);width:100%;text-align:left;position:relative;text-decoration:none}
.tm-nav:hover{background:rgba(120,130,145,.10)}
.tm-nav.active{background:var(--side-active);color:#fff;font-weight:600}
.tm-nav.active::before{content:'';position:absolute;left:0;top:8px;bottom:8px;width:3px;border-radius:3px;background:#fff;opacity:.9}
.tm-nav .badge{margin-left:auto}
.tm-nav.active .tm-badge{color:#fff;background:rgba(255,255,255,.22)}
.tm-side-user{padding:14px;border-top:1px solid var(--side-line);display:flex;align-items:center;gap:11px}
/* Live-audit finding (2026-08-06): the trailing role badge (.tm-hier, e.g. #sideHierBadge) was
   sized for a short abbreviation ("Zone Mgr", "HoS", "CEO") but TmRoleLabels correctly
   overwrites its text with the tenant's REAL configured role name, which can be much longer
   ("Zone Sales Manager") — with no width/wrap constraint, that text wrapped inside the badge,
   grew taller than the row, and visually overlapped the name/role caption sitting beside it in
   this tight sidebar-footer layout. Cap it to a sane width and truncate with an ellipsis rather
   than let it collide with its neighbour; flex-shrink:0 keeps the name/caption side (already
   flex:1;min-width:0) as the one that shrinks/wraps first, matching the layout's own intent. */
/* Live-audit finding, resolved over 3 passes — recording all 3 since a narrower fix at any one
   step regressed a different way (found live via screenshot each time, real "Zone Sales
   Manager" tenant-override text on a 247px-wide sidebar footer):
   1. The badge (.tm-hier here) had no width cap, so a long tenant-configured role name wrapped
      inside it and visually overlapped the name/caption beside it.
   2. Capping the badge's width (flex-shrink:0) alone just relocated the collision: its sibling
      column (#sideUserName/#sideUserRole) had no overflow protection, so IT then wrapped and
      rendered behind the now-fixed-width badge.
   3. Truncating the name/role column with an ellipsis (no minimum width) fixed the overlap but
      over-truncated the name to a single character ("A…") in the ~164px left after the avatar —
      technically non-overlapping but unreadable, arguably worse. Final balance: the name/role
      column gets a real floor (min-width) so it always shows a meaningful fragment, and the
      badge's own cap shrinks slightly to leave room for it — the badge already truncates
      gracefully by design, so a truncated badge is the right side to give up space first. */
.tm-side-user .tm-hier{flex-shrink:0;max-width:80px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:inline-block}
/* !important is required here: the element carries an inline style="min-width:0;flex:1" across
   every page (a plain flexbox-shrink reset), which otherwise always wins over an external
   stylesheet rule regardless of selector specificity. */
.tm-side-user>div{min-width:70px!important}
.tm-side-user #sideUserName,
.tm-side-user #sideUserRole{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.tm-main{flex:1;min-width:0;display:flex;flex-direction:column}
.tm-topbar{position:sticky;top:0;z-index:25;background:var(--top-bg);color:var(--top-fg);border-bottom:1px solid var(--line);display:flex;align-items:center;flex-wrap:wrap;gap:14px;padding:11px 24px}
.tm-content{padding:22px 26px 48px;display:flex;flex-direction:column;gap:18px}

/* ---------- CARD ---------- */
.tm-card{background:var(--card);border:1px solid var(--card-border);border-radius:var(--radius);box-shadow:var(--shadow)}
.tm-card-pad{padding:18px 19px}
.tm-card-head{padding:16px 18px 13px;border-bottom:1px solid var(--line);display:flex;align-items:center;justify-content:space-between;gap:12px}

/* KPI */
.tm-kpi{background:var(--card);border:1px solid var(--card-border);border-radius:var(--radius);box-shadow:var(--shadow);padding:18px 19px;display:flex;flex-direction:column;gap:13px;transition:transform .14s ease,box-shadow .14s ease}
.tm-kpi.clickable{cursor:pointer}
.tm-kpi.clickable:hover{transform:translateY(-2px);box-shadow:0 3px 6px rgba(16,24,40,.06),0 12px 28px rgba(16,24,40,.10)}
.tm-kpi-num{font-family:var(--font-display);font-weight:var(--num-weight);font-size:38px;letter-spacing:-.03em;line-height:1}
.tm-kpi-ico{width:34px;height:34px;border-radius:50%;display:flex;align-items:center;justify-content:center}
.tm-bar{height:6px;border-radius:6px;background:var(--line-soft);overflow:hidden}
.tm-bar>i{display:block;height:100%;border-radius:6px}

/* ---------- BUTTONS ---------- */
.tm-btn{display:inline-flex;align-items:center;justify-content:center;gap:7px;font-family:var(--font-body);font-size:13px;font-weight:600;padding:9px 15px;border-radius:10px;cursor:pointer;border:1px solid transparent;transition:filter .12s ease,background .12s ease;white-space:nowrap}
.tm-btn-primary{background:var(--primary);color:#fff}
.tm-btn-primary:hover{filter:brightness(1.06)}
.tm-btn-accent{background:var(--accent);color:#fff}
.tm-btn-danger{background:var(--ember);color:#fff}
.tm-btn-outline{background:transparent;color:var(--primary);border-color:var(--line)}
.tm-btn-ghost{background:transparent;color:var(--ink-soft);border-color:var(--line)}
.tm-btn-sm{padding:6px 11px;font-size:12px;border-radius:8px}
.tm-icon-btn{width:39px;height:39px;border-radius:10px;border:1px solid var(--line);background:var(--card);display:flex;align-items:center;justify-content:center;cursor:pointer;color:var(--ink-soft)}

/* ---------- BADGES / PILLS ---------- */
.tm-badge{display:inline-flex;align-items:center;gap:5px;font-size:10.5px;font-weight:700;letter-spacing:.04em;text-transform:uppercase;padding:3px 8px;border-radius:7px}
.tm-badge.crit{color:var(--ember);background:var(--ember-soft)}
.tm-badge.watch{color:var(--amber);background:var(--amber-soft)}
.tm-badge.ok,.tm-badge.stable{color:var(--green);background:var(--green-soft)}
.tm-badge.info{color:var(--info);background:var(--info-soft)}
.tm-badge.neutral{color:var(--ink-soft);background:var(--line-soft)}
.tm-pill{display:inline-flex;align-items:center;gap:6px;font-size:12px;font-weight:600;padding:5px 11px;border-radius:20px;border:1px solid var(--line);background:var(--card);color:var(--ink-soft)}
.tm-pill.on,.tm-pill.active{background:var(--primary);color:#fff;border-color:var(--primary)}
.tm-delta{display:inline-flex;align-items:center;gap:3px;font-size:11px;font-weight:700;padding:3px 7px;border-radius:7px}
.tm-delta.up{color:var(--accent);background:var(--accent-soft)}
.tm-delta.down{color:var(--ember);background:var(--ember-soft)}

/* hierarchy badges — consistent across every screen */
.tm-hier{display:inline-flex;align-items:center;gap:5px;font-size:10.5px;font-weight:700;padding:3px 8px 3px 6px;border-radius:7px;color:#fff}
.tm-hier svg{width:12px;height:12px}
.tm-hier.company{background:var(--h-company)}
.tm-hier.zone{background:var(--h-zone)}
.tm-hier.supervisor{background:var(--h-supervisor)}
.tm-hier.agent{background:var(--h-agent)}
.tm-hier.ghost{background:transparent;border:1px solid currentColor}
.tm-hier.ghost.company{color:var(--h-company)}.tm-hier.ghost.zone{color:var(--h-zone)}.tm-hier.ghost.supervisor{color:var(--h-supervisor)}.tm-hier.ghost.agent{color:var(--h-agent)}

/* avatar */
.tm-av{border-radius:50%;display:flex;align-items:center;justify-content:center;font-weight:700;color:#fff;flex:0 0 auto}

/* ---------- FORMULA CHIP (trust mechanism) ---------- */
.tm-fx{display:inline-flex;align-items:center;gap:4px;font-family:var(--font-mono);font-weight:700;font-size:10.5px;color:var(--purple);background:var(--purple-soft);border:1px solid transparent;padding:1px 6px;border-radius:6px;cursor:help;vertical-align:middle;user-select:none}
.tm-fx::before{content:'\0192(x)'}
.tm-fx-row{display:flex;align-items:center;gap:7px;background:var(--line-soft);border-radius:7px;padding:6px 9px}
.tm-fx-row .tm-fx{background:transparent;padding:0;border:none}
.tm-fx-row span{font-family:var(--font-mono);font-size:11px;color:var(--ink-soft);line-height:1.4}
.tm-fx-tip{position:absolute;z-index:200;max-width:280px;background:#0F1929;color:#EAF1F8;font-family:var(--font-body);font-size:11.5px;line-height:1.5;padding:9px 12px;border-radius:9px;box-shadow:0 10px 30px rgba(15,25,41,.3);opacity:0;transform:translateY(-4px);pointer-events:none;transition:opacity .14s ease,transform .14s ease}
.tm-fx-tip.show{opacity:1;transform:none}
/* Info tooltip — a plain "?" glyph reusing the SAME data-fx hover/click mechanism as .tm-fx above
   (no JS change needed), for "what does this metric mean" copy rather than a math formula. */
/* Was a 15px dot with an invisible expanded hit-area — still reported as hard to hit
   ("have to zoom in", "multiple rounds of trying to click"). Direct feedback: make the
   VISIBLE circle itself bigger, not just an invisible zone around a tiny glyph a
   fingertip can't even aim at. 22px glyph + a still-larger invisible ::after on top. */
.tm-info-tip{position:relative;display:inline-flex;align-items:center;justify-content:center;width:22px;height:22px;border-radius:50%;background:var(--line-soft);color:var(--muted);font-size:13px;font-weight:700;cursor:help;vertical-align:middle;user-select:none;flex:0 0 auto}
.tm-info-tip::before{content:'?'}
/* Expands the tap target further beyond the now-larger visible circle, to comfortably
   clear the accessibility touch-target minimum (~44px) with margin to spare. */
.tm-info-tip::after{content:'';position:absolute;inset:-12px}

/* ── Location-filter <select> ("All locations" + Zone/Region/Street optgroups) ──
   Reported live: the closed (unopened) control looks "awkwardly big" with "a whole lot of
   padding" above/below the text, on every page carrying one (check-in, territory map, My
   Book, visit history). The inline padding each page set (4px 8px) was already modest — the
   real culprit is that a native <select>'s own UA chrome (built-in vertical padding around
   its native dropdown arrow) is NOT fully overridden by a plain `padding` declaration on
   several mobile browsers/WebViews, so the box renders taller than its CSS says. Removing the
   native appearance and drawing our own chevron gives full control over the closed-state
   height; the open dropdown list itself was never the complaint and is untouched.
   Each page keeps its OWN inline font-size/color/border (real, intentional differences) —
   only padding/appearance/line-height/chevron move here, one definition, every page. */
.tm-area-select{
  -webkit-appearance:none;-moz-appearance:none;appearance:none;
  line-height:1.3;
  padding:4px 26px 4px 8px;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23888' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
  background-repeat:no-repeat;
  background-position:right 6px center;
  background-size:12px;
}

/* ---------- BRAND TOPBAR (PWA) — blue, org name left, status badge right ---------- */
.tm-sync{display:flex;align-items:center;justify-content:space-between;gap:8px;padding:10px 16px;width:100%;flex:0 0 auto;background:#0B4F8A}
.tm-sync .sync-org{font-size:13px;font-weight:700;color:#EAF1F8;flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
/* Ground-5 accessibility fix: sync-badge sets its own hardcoded text colors rather than using
   the --green/--amber tokens above, so it needed the same fix applied separately — was #059669
   (3.77:1 on white, fails AA) / #D97706, now the same accessible shades the tokens use. The small
   status .dot is a non-text indicator (WCAG's easier 3:1 UI-component bar, already clears it) so
   it's left as the original brand color. */
.tm-sync .sync-badge{display:flex;align-items:center;gap:5px;font-size:11px;font-weight:600;padding:3px 10px;border-radius:20px;background:#fff;color:#065F46;white-space:nowrap;flex-shrink:0}
.tm-sync .dot{width:6px;height:6px;border-radius:50%;background:#059669}
.tm-sync.syncing .sync-badge{background:#fff;color:#9A3412}
.tm-sync.syncing .dot{background:#D97706;animation:tm-pulse 1.3s infinite}
.tm-sync.offline .sync-badge{background:#fff;color:#B91C1C}
.tm-sync.offline .dot{background:#B91C1C}
/* Keep all states blue — only badge colour changes */
.tm-sync.online,.tm-sync.syncing,.tm-sync.offline,.tm-sync.synced{background:#0B4F8A}

/* ---------- WATERMARK (data protection) ---------- */
.tm-watermark{position:absolute;inset:0;pointer-events:none;z-index:1;overflow:hidden;
  background-image:repeating-linear-gradient(-30deg, transparent, transparent 120px, rgba(26,34,53,.012) 120px, rgba(26,34,53,.012) 240px)}
.tm-watermark::before{content:attr(data-mark);position:absolute;inset:-40% -10%;color:rgba(26,34,53,.035);font-family:var(--font-display);font-weight:700;font-size:26px;line-height:170px;letter-spacing:.3em;transform:rotate(-30deg);white-space:pre-wrap;word-spacing:60px}
.tm-watermark.locked::before{color:rgba(185,28,28,.06)}
body.tm-dp-active .tm-watermark::before{color:rgba(26,34,53,.055)}

/* Persistent user stamp — bottom-right corner of every protected screen */
.tm-user-stamp{
  position:fixed;bottom:12px;right:14px;z-index:9998;
  font-family:var(--font-mono);font-size:10px;font-weight:600;
  color:rgba(26,34,53,.28);letter-spacing:.02em;
  pointer-events:none;user-select:none;
  white-space:nowrap;
}
body.tm-dp-active .tm-user-stamp{color:rgba(26,34,53,.38)}

/* Screenshot-alert overlay — shown on detected screenshot attempt */
.tm-screenshot-alert{
  display:none;position:fixed;inset:0;z-index:99999;
  background:rgba(11,79,138,.96);
  align-items:center;justify-content:center;flex-direction:column;gap:16px;
  color:#fff;font-family:var(--font-body);text-align:center;padding:32px;
}
.tm-screenshot-alert.visible{display:flex}
.tm-screenshot-alert h3{font-size:22px;font-weight:700;margin:0}
.tm-screenshot-alert p{font-size:15px;opacity:.85;margin:0;max-width:380px;line-height:1.6}
.tm-screenshot-alert .tm-btn{margin-top:8px;padding:12px 28px;border-radius:10px;border:none;background:#0A7C6E;color:#fff;font-size:15px;font-weight:700;cursor:pointer}

/* Request access modal */
.tm-dp-modal{
  display:none;position:fixed;inset:0;z-index:10000;
  background:rgba(15,25,41,.7);backdrop-filter:blur(4px);
  align-items:center;justify-content:center;
}
.tm-dp-modal.open{display:flex}
.tm-dp-modal-box{
  background:#fff;border-radius:16px;padding:32px;max-width:420px;width:90%;
  box-shadow:0 24px 64px rgba(0,0,0,.2);
}
.tm-dp-modal-box h3{margin:0 0 8px;font-size:18px;color:var(--navy)}
.tm-dp-modal-box p{font-size:14px;color:var(--muted);margin:0 0 20px;line-height:1.6}
.tm-dp-modal-box textarea{width:100%;box-sizing:border-box;border:1.5px solid var(--line);border-radius:10px;padding:10px 12px;font-size:14px;resize:vertical;min-height:80px;font-family:var(--font-body)}
.tm-dp-modal-actions{display:flex;gap:10px;margin-top:16px;justify-content:flex-end}

/* Print suppression — blocks printing for all users by default */
@media print {
  body.tm-dp-active *{display:none !important;visibility:hidden !important}
  body.tm-dp-active::after{
    display:block !important;visibility:visible !important;
    content:'This document is protected. Print access requires authorisation from your tenant administrator.';
    position:fixed;inset:0;padding:60px;font-size:18px;text-align:center;color:#000;
  }
}

/* Prevent text selection on protected content areas */
body.tm-dp-active .tm-protected-content{
  -webkit-user-select:none;-moz-user-select:none;user-select:none;
}

/* ---------- TABLE ---------- */
.tm-table{width:100%;border-collapse:collapse;font-size:13px}
.tm-table thead th{font-size:10px;letter-spacing:.06em;text-transform:uppercase;color:var(--muted);font-weight:700;text-align:left;padding:11px 16px;border-bottom:1px solid var(--line)}
.tm-table tbody td{padding:13px 16px;border-bottom:1px solid var(--line-soft)}
.tm-table tbody tr:hover{background:var(--primary-soft)}
.tm-row-click{cursor:pointer;transition:background .12s ease}

/* ---------- INPUTS ---------- */
.tm-input,.tm-select,.tm-textarea{width:100%;border:1px solid var(--line);background:var(--card);color:var(--ink);border-radius:10px;padding:9px 13px;font-size:13.5px;font-family:var(--font-body);outline:none}
.tm-input:focus,.tm-select:focus,.tm-textarea:focus{border-color:var(--primary);box-shadow:0 0 0 3px var(--primary-soft)}
.tm-textarea{resize:vertical;min-height:58px;line-height:1.5}
.tm-label{font-size:12px;font-weight:600;color:var(--ink-soft);margin-bottom:6px;display:block}
.tm-switch{width:42px;height:24px;border-radius:20px;background:var(--line);position:relative;cursor:pointer;border:none;flex:0 0 42px;transition:background .15s ease}
.tm-switch::after{content:'';position:absolute;top:3px;left:3px;width:18px;height:18px;border-radius:50%;background:#fff;transition:left .15s ease;box-shadow:0 1px 3px rgba(0,0,0,.2)}
.tm-switch.on{background:var(--accent)}
.tm-switch.on::after{left:21px}

/* ---------- TOAST ---------- */
.tm-toast{position:fixed;bottom:26px;left:50%;transform:translate(-50%,12px);z-index:300;background:#0F1929;color:#fff;padding:13px 20px;border-radius:12px;box-shadow:0 14px 40px rgba(15,25,41,.35);font-size:13.5px;font-weight:500;opacity:0;transition:opacity .25s ease,transform .25s ease;max-width:90vw}
.tm-toast.show{opacity:1;transform:translate(-50%,0)}

/* ---------- SKELETON / EMPTY ---------- */
.tm-skel{background:linear-gradient(90deg,var(--line-soft) 25%,var(--line) 37%,var(--line-soft) 63%);background-size:400% 100%;animation:tm-shimmer 1.4s ease infinite;border-radius:8px}
.tm-empty{display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;padding:48px 24px;gap:6px}
.tm-empty h4{font-family:var(--font-display);font-weight:700;font-size:16px;margin:8px 0 0}
.tm-empty p{font-size:13px;color:var(--muted);max-width:320px;line-height:1.5;margin:0}

/* ---------- MISC ---------- */
.tm-divider{height:1px;background:var(--line);border:none;margin:0}
.tm-scope-banner{display:flex;align-items:center;gap:10px;background:var(--primary-soft);border:1px solid var(--line);border-radius:11px;padding:9px 14px;font-size:12.5px;color:var(--ink-soft)}

/* ---------- ANIMATIONS ---------- */
@keyframes tm-pulse{0%{box-shadow:0 0 0 0 rgba(185,28,28,.45)}70%{box-shadow:0 0 0 7px rgba(185,28,28,0)}100%{box-shadow:0 0 0 0 rgba(185,28,28,0)}}
@keyframes tm-shimmer{0%{background-position:100% 50%}100%{background-position:0 50%}}
@keyframes tm-rise{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}
@keyframes tm-slide{from{transform:translateX(30px);opacity:0}to{transform:none;opacity:1}}
.tm-rise{animation:tm-rise .2s ease}

/* leaflet font (if used in production) */
.leaflet-container{font-family:var(--font-body)}

/* ============================================================
   RESPONSIVE — phone → laptop → boardroom projection (55"–80")
   Inherited by every screen that uses the shared shell classes.
   ============================================================ */

/* Boardroom / CEO-office big screens: cap line length, scale type + spacing
   so the UI fills the wall and reads from across the room. */
@media (min-width:1900px){
  body{font-size:16.5px}
  .tm-content{max-width:1780px;margin-inline:auto;width:100%;padding:30px 44px 64px}
  .tm-h1{font-size:34px}.tm-display{font-size:46px}.tm-h2{font-size:25px}.tm-h3{font-size:19px}
  .tm-kpi-num{font-size:44px}
  .tm-card-pad{padding:22px 24px}
  .tm-nav{font-size:14.5px}
}
@media (min-width:2560px){            /* 4K / very large projection */
  body{font-size:19px}
  .tm-content{max-width:2280px;margin-inline:auto;padding:44px 64px 90px;gap:24px}
  .tm-h1{font-size:42px}.tm-display{font-size:58px}.tm-h2{font-size:30px}.tm-h3{font-size:22px}
  .tm-kpi-num{font-size:56px}
  .tm-side{width:300px;flex-basis:300px}
  .tm-nav{font-size:16px;padding:13px 15px}
  .tm-btn{font-size:14.5px;padding:11px 18px}
}

/* Tablet */
@media (max-width:1024px){
  .tm-content{padding:18px 18px 40px}
}

/* Phone: collapse the sidebar to an icon rail; let the topbar wrap. */
@media (max-width:760px){
  .tm-side{width:62px;flex-basis:62px}
  .tm-side-brand{justify-content:center;padding:18px 0}
  .tm-side-brand>div{display:none}
  .tm-side-group{font-size:0;padding:8px 0;height:12px}
  .tm-nav{justify-content:center;font-size:0;gap:0;padding:11px 0}
  .tm-nav svg{flex:0 0 auto}
  .tm-nav .badge{position:absolute;top:3px;right:7px;margin:0}
  .tm-side-user{justify-content:center;padding:12px 0}
  .tm-side-user>div,.tm-side-user>.tm-hier{display:none}
  .tm-content{padding:14px 12px 36px}
  .tm-topbar{padding:9px 12px;gap:8px;flex-wrap:wrap}
  .tm-topbar>div:first-child{flex:1 1 100% !important;max-width:100% !important;order:-1}
}
@media (max-width:430px){
  .tm-side{width:62px;flex-basis:62px;overflow:hidden;border:none}
}

/* ── Mobile sidebar drawer (≤760px) ──────────────────────────────────────── */
#tm-mob-toggle{display:none;align-items:center;justify-content:center;width:36px;height:36px;border-radius:9px;border:1px solid var(--line);background:var(--card);cursor:pointer;flex:0 0 36px;margin-right:4px}
@media(max-width:760px){
  #tm-mob-toggle{display:flex}
  .tm-app{position:relative}
  .tm-side{
    position:fixed;top:0;left:0;bottom:0;
    transform:translateX(-100%);
    transition:transform .22s ease;
    z-index:200;
    width:248px!important;flex-basis:248px!important;
    overflow-y:auto;overflow-x:hidden;
  }
  /* restore hidden labels on drawer open — scoped to .tm-app.sidebar-open so the
     closed-state icon rail (declared above, unconditional at <=760px) is untouched;
     an earlier version of this block was unscoped and relied solely on translateX
     to hide the now-full-size nav, which broke layout the instant anything (e.g. a
     focus outline, a screenshot tool) rendered it while nominally "closed". */
  .tm-app.sidebar-open .tm-side .tm-side-brand>div,
  .tm-app.sidebar-open .tm-side .tm-side-group,
  .tm-app.sidebar-open .tm-side .tm-side-user>div,
  .tm-app.sidebar-open .tm-side .tm-side-user>.tm-hier,
  .tm-app.sidebar-open .tm-side .tm-nav span{display:initial}
  /* The block above only restores display — .tm-nav/.tm-side-group still inherit
     font-size:0 from the icon-rail rules above (real client bug, found live
     2026-08-04: the drawer opened but every nav label rendered at 0 size, so it
     looked icon-only). Restore the real desktop sizing/layout so labels are
     actually visible once the drawer is open, not just present in the DOM. */
  .tm-app.sidebar-open .tm-side .tm-nav{justify-content:flex-start;font-size:14px;gap:12px;padding:10px 12px}
  .tm-app.sidebar-open .tm-side .tm-side-group{font-size:10px;padding:14px 12px 6px;height:auto}
  .tm-app.sidebar-open .tm-side{transform:translateX(0)}
  #tm-side-backdrop{display:none;position:fixed;inset:0;background:rgba(0,0,0,.45);z-index:199}
  .tm-app.sidebar-open #tm-side-backdrop{display:block}
}

/* ============================================================
   PWA — 390px field app (offline-first). Phone frame + chrome.
   ============================================================ */
.pwa-stage{min-height:100vh;display:flex;align-items:flex-start;justify-content:center;background:#0E1726;padding:22px 14px}
.phone{width:390px;max-width:100%;background:var(--bg);border-radius:32px;overflow:hidden;box-shadow:0 30px 90px rgba(0,0,0,.45);position:relative;height:834px;display:flex;flex-direction:column}
/* On a real phone or installed PWA: lock to viewport, native feel */
@media (max-width:480px),(display-mode:standalone),(display-mode:fullscreen){
  /* SCOPED TO THE PHONE SHELL ON PURPOSE. This lock exists so `.pwa-body` can be the inner
     scroller inside `.phone`. Applied to html/body globally — as it was — it ALSO froze the
     57 pages built on the `.tm-app` shell (the CEO board, every tenant-* dashboard, every
     super-admin-* page), which have NO inner scroller: their content simply overflowed a
     locked body and NOTHING could scroll. On the CEO board that stranded 4,200px of content
     — the HoS table, zone table, gap table, territory map — behind an unscrollable first
     screen. Worse, `(display-mode:standalone)` fires at ANY width once installed, so this
     was not merely a small-screen bug.
     If :has() is unsupported the rule drops and `.phone` pages fall back to normal body
     scrolling — a cosmetic regression, versus 57 unusable pages. That is the safe direction. */
  html:has(.phone), body:has(.phone){height:100%;overflow:hidden;margin:0}
  .pwa-stage{padding:0;background:var(--bg)}
  .phone{position:fixed;inset:0;width:100%;height:100%;border-radius:0;box-shadow:none;overflow:hidden;
    padding-top:env(safe-area-inset-top);
    padding-bottom:env(safe-area-inset-bottom)}
  .pwa-body{-webkit-overflow-scrolling:touch}
  .pwa-status{display:none}
  /* Blue background fills the safe-area-inset-top (notch/status bar area) */
  .phone::before{content:'';position:absolute;top:0;left:0;right:0;height:env(safe-area-inset-top);background:#0B4F8A;z-index:100}
}
.pwa-status{display:flex;align-items:center;justify-content:space-between;padding:10px 22px 3px;font-size:12.5px;font-weight:700;color:var(--ink);flex:0 0 auto}
/* padding-top adds env(safe-area-inset-top) ON TOP OF the existing 8px (not replacing it) — on a
   plain rectangular-screen device the env() resolves to 0 and this is identical to before. On a
   notched/Dynamic-Island phone launched as an installed PWA (standalone display mode has no browser
   chrome reserving that space itself), .pwa-top is the actual first element on every page, and
   without this it can render partially UNDER the notch — reported as a back-button on a detail
   drawer looking "clipped ~80% from the top" (only a sliver visible). Requires viewport-fit=cover
   on the page's own <meta name="viewport"> — WITHOUT that, env(safe-area-inset-top) always
   evaluates to 0 and this rule is a harmless no-op, so both must ship together. */
.pwa-top{display:flex;align-items:center;gap:12px;padding:calc(5px + env(safe-area-inset-top)) 18px 7px;flex:0 0 auto}
.pwa-body{flex:1;overflow-y:auto;padding:2px 16px 94px;position:relative}
.pwa-tabs{position:absolute;bottom:0;left:0;right:0;background:var(--card);border-top:1px solid var(--line);display:flex;padding:9px 6px 16px;z-index:10}
.pwa-tab{flex:1;display:flex;flex-direction:column;align-items:center;gap:4px;font-size:9.5px;color:var(--muted);font-weight:600;text-decoration:none;background:none;border:none;cursor:pointer;font-family:var(--font-body)}
.pwa-tab.on{color:var(--primary)}

/* ══════════════════════════════════════════════════════════════════════════════════════════════
   ONE APP, TWO SHAPES — the PWA becomes a real desktop application.

   ⭐THE PROBLEM THIS SOLVES
   `.phone` is a FIXED 390x834 frame with a 32px radius and a drop shadow, centred on a dark stage.
   That is a design MOCKUP, not an application. And FIVE OF THE SIX ROLES live on it — Field Officer,
   Supervisor, Region Manager, Zone Manager, Head of Sales. So a Head of Sales opening the platform
   on their laptop saw a phone-shaped toy floating in the middle of a 27-inch monitor, with content
   locked to 834px that could not grow. Only the CEO (`.tm-app`) got a real desktop layout.

   A field-force platform is used in BOTH places: the officer is on a phone in a shop; their manager
   is at a desk with a spreadsheet open. Forcing the manager into a phone frame is not a compromise,
   it is a defect.

   ⭐THE APPROACH
   Progressive enhancement in CSS ONLY — no page is rewritten, all 32 PWA pages inherit this:

     < 768px   the phone. Unchanged: full-bleed, bottom tab bar. This is the field.
     ≥ 768px   the frame dissolves: full width, full height, no fake bezel. Tablet / small laptop.
     ≥ 1024px  the bottom tab bar BECOMES A LEFT SIDEBAR, styled exactly like the CEO's `.tm-side`.

   That last step is the point: after it, EVERY role — officer to CEO — has the SAME navigation
   language. A sidebar on a computer, tabs under your thumb on a phone. One product, not two.
   ══════════════════════════════════════════════════════════════════════════════════════════════ */

/* ── ≥768px: dissolve the phone frame ─────────────────────────────────────────────────────── */
@media (min-width: 768px) {
  .pwa-stage {
    padding: 0;
    background: var(--bg);          /* the dark "stage" was a showcase backdrop, not a UI */
    align-items: stretch;
    min-height: 100vh;
  }
  .phone {
    width: 100%;
    max-width: none;
    height: 100vh;
    border-radius: 0;
    box-shadow: none;               /* no fake bezel on a real screen */
  }
  .pwa-body { padding-left: 22px; padding-right: 22px; }
}

/* ── ≥1024px: the tab bar becomes a sidebar. Same language as the CEO's shell. ─────────────── */
@media (min-width: 1024px) {
  /* Reserve a gutter and pin the nav into it. Deliberately NOT CSS Grid: the pages have a varying
     number of static children (sync bar, page header, body…) and a two-row grid template silently
     pushed the third one into an implicit row BELOW the content — the page header landed at the
     bottom of the screen. A gutter + a pinned rail leaves normal flow, and therefore DOM order,
     completely untouched across all 32 pages.

     The gutter is a transparent BORDER, not padding, and that distinction is the whole point.
     An absolutely-positioned element resolves `inset: 0` against its ancestor's PADDING box —
     which includes the padding but EXCLUDES the border. With `padding-left: 248px` the full-bleed
     overlays (.ov, .ag-detail, .bc-overlay, .fs-overlay, .zm-brief, .create-overlay,
     .form-overlay, .tm-sheet …) still began at x=0 and slid UNDERNEATH the rail: every row was
     sliced off on the left and the overlay's back button was buried under the nav, so a manager
     who opened Churn on a laptop could not get back out. A border-left moves the padding box
     itself, so every absolute overlay — including ones not yet written — is offset for free.

     The rail must then anchor to the VIEWPORT rather than that shifted padding box, so it is
     position:fixed. `.phone` is full-bleed at this width, so viewport-left == phone-left. */
  .phone {
    border-left: 248px solid transparent;
    background-clip: padding-box;   /* don't paint the phone's bg into the rail's gutter */
  }

  .phone > .pwa-tabs {
    position: fixed;
    top: 0;
    bottom: 0;
    left: 0;
    right: auto;
    width: 248px;
    flex-direction: column;
    align-items: stretch;
    justify-content: flex-start;
    gap: 2px;
    padding: 16px 12px;
    background: var(--side-bg);
    border-top: none;
    border-right: 1px solid var(--side-line, var(--line));
    overflow-y: auto;
  }

  /* A tab becomes a nav row — icon left, label beside it. Identical language to .tm-nav, so a
     supervisor's sidebar and the CEO's sidebar are the same object. */
  .phone > .pwa-tabs .pwa-tab {
    flex: 0 0 auto;
    flex-direction: row;
    align-items: center;
    justify-content: flex-start;
    gap: 12px;
    padding: 10px 12px;
    border-radius: 9px;
    font-size: 14px;
    font-weight: 500;
    color: var(--side-fg);
    text-align: left;
    position: relative;
  }
  .phone > .pwa-tabs .pwa-tab svg { width: 19px; height: 19px; flex: 0 0 19px; }
  .phone > .pwa-tabs .pwa-tab:hover { background: rgba(127,127,127,.10); }
  .phone > .pwa-tabs .pwa-tab.on {
    background: var(--side-active);
    color: #fff;
    font-weight: 600;
  }
  .phone > .pwa-tabs .pwa-tab.on::before {
    content: '';
    position: absolute; left: 0; top: 8px; bottom: 8px;
    width: 3px; border-radius: 3px; background: #fff; opacity: .9;
  }

  /* The 94px bottom gutter existed only to clear the tab bar, which is no longer at the bottom. */
  .pwa-body { padding: 18px 28px 28px; }

  /* Content was authored for a 390px column. Un-cramp it, but do not let a KPI card stretch to
     1400px and look absurd — a readable measure, generously set. */
  .pwa-body > * { max-width: 1180px; }
}

/* ── ≥1440px: give the content room to breathe on a large monitor ──────────────────────────── */
@media (min-width: 1440px) {
  .pwa-body { padding-left: 40px; padding-right: 40px; }
}
.pwa-bigbtn{width:100%;min-height:56px;border-radius:16px;border:none;font-size:16px;font-weight:700;font-family:var(--font-body);cursor:pointer;display:flex;align-items:center;justify-content:center;gap:9px}
.pwa-card,.pwa-tile{background:var(--card);border:1px solid var(--card-border);border-radius:15px;box-shadow:var(--shadow);padding:15px 16px}
.tap{min-height:48px}

/* ============================================================
   FINAL (Authority Edition) additions — Gate Zero locked tokens
   + new component classes. Brand: Metriq Teal / Warm Amber / Deep Navy.
   ============================================================ */
:root{
  --metriq-teal:#0A7C6E; --metriq-teal-dk:#065F53; --metriq-blue:#0B4F8A;
  --deep-navy:#0F1929; --warm-amber:#D97706; --amber-light:#FEF3C7;
  --broken-white:#F9F7F4; --churn-red:#DC2626; --churn-red-light:#FEE2E2;
  --forest:#16A34A; --forest-light:#DCFCE7;
}

/* ---- SCORE PILL (agent self-score) ---- */
.tm-score-pill{display:inline-flex;align-items:center;gap:6px;font-family:var(--font-display);font-weight:700;font-size:13px;padding:5px 12px;border-radius:20px;color:#fff;white-space:nowrap}
.tm-score-pill.good{background:var(--metriq-teal)}
.tm-score-pill.warn{background:var(--warm-amber)}
.tm-score-pill.bad{background:var(--churn-red)}
.tm-score-pill .n{font-size:15px}

/* ---- COACHING BANNER ---- */
.tm-coach{display:flex;gap:12px;align-items:flex-start;background:var(--amber-light);border-left:4px solid var(--warm-amber);border-radius:11px;padding:12px 14px;position:relative;animation:tm-rise .25s ease}
.tm-coach.red{background:var(--churn-red-light);border-left-color:var(--churn-red)}
.tm-coach .ic{flex:0 0 auto;font-size:18px;line-height:1.2}
.tm-coach h5{font-family:var(--font-display);font-weight:700;font-size:13px;margin:0 0 2px}
.tm-coach p{margin:0;font-size:12px;color:var(--ink-soft);line-height:1.45}
.tm-coach .acts{display:flex;align-items:center;gap:8px;margin-top:8px;flex-wrap:wrap}
.tm-coach .x{position:absolute;top:8px;right:9px;border:none;background:transparent;color:var(--muted);cursor:pointer;font-size:16px;line-height:1;padding:2px}

/* ---- GAUGE (target likelihood, progress) ---- */
.tm-gauge{height:13px;border-radius:9px;background:var(--line-soft);overflow:hidden;position:relative}
.tm-gauge>i{display:block;height:100%;border-radius:9px;transition:width .5s ease}
.tm-gauge.green>i{background:var(--forest)}.tm-gauge.amber>i{background:var(--warm-amber)}.tm-gauge.red>i{background:var(--churn-red)}

/* ---- CUSTOM-METRIC TILE (Merchant 360 Industry Metrics) ---- */
.tm-metric-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(132px,1fr));gap:10px}
.tm-metric-tile{background:var(--card-2);border:1px solid var(--card-border);border-radius:11px;padding:12px 13px}
.tm-metric-tile .lbl{font-size:10.5px;letter-spacing:.04em;text-transform:uppercase;color:var(--muted);font-weight:700}
.tm-metric-tile .val{font-family:var(--font-display);font-weight:700;font-size:19px;letter-spacing:-.02em;margin-top:5px}
.tm-metric-tile .trend{font-size:11px;font-weight:700;margin-top:4px;display:inline-flex;align-items:center;gap:3px}

/* ---- MINI BOTTOM SHEET (PWA map dot tap) ---- */
.tm-sheet-scrim{position:absolute;inset:0;background:rgba(15,25,41,.35);z-index:40;opacity:0;pointer-events:none;transition:opacity .2s ease}
.tm-sheet-scrim.open{opacity:1;pointer-events:auto}
.tm-sheet{position:absolute;left:0;right:0;bottom:0;background:var(--card);border-radius:20px 20px 0 0;box-shadow:0 -10px 40px rgba(15,25,41,.25);z-index:41;transform:translateY(110%);transition:transform .26s cubic-bezier(.2,.7,.2,1);padding:8px 16px 18px}
.tm-sheet.open{transform:none}
.tm-sheet .grip{width:38px;height:4px;border-radius:4px;background:var(--line);margin:6px auto 12px}

/* ---- LANGUAGE SWITCHER (N-language) ---- */
.tm-langsel{position:relative;display:inline-flex;align-items:center;gap:6px;border:1px solid var(--line);background:var(--card);border-radius:9px;padding:6px 10px;cursor:pointer;font-size:12.5px;font-weight:700;color:var(--ink-soft);user-select:none}
.tm-langsel .tm-langsel-cur{letter-spacing:.04em}
.tm-langsel .caret{transition:transform .16s ease}
.tm-langsel.open .caret{transform:rotate(180deg)}
.tm-langsel-menu{position:absolute;top:calc(100% + 6px);right:0;min-width:148px;background:var(--card);border:1px solid var(--line);border-radius:11px;box-shadow:var(--shadow-lg);padding:5px;z-index:120;display:none;flex-direction:column;gap:2px}
.tm-langsel.open .tm-langsel-menu{display:flex}
.tm-langsel-opt{display:flex;align-items:center;gap:10px;border:none;background:transparent;cursor:pointer;border-radius:8px;padding:8px 10px;font-family:var(--font-body);text-align:left;width:100%}
.tm-langsel-opt:hover{background:var(--primary-soft)}
.tm-langsel-code{font-weight:700;font-size:12px;color:var(--primary);width:24px;flex:0 0 24px}
.tm-langsel-name{font-size:13px;color:var(--ink)}

/* ---- COMPETITION PODIUM ---- */
.tm-podium{display:flex;align-items:flex-end;justify-content:center;gap:10px}
.tm-podium .pos{flex:1;max-width:120px;text-align:center}
.tm-podium .pos .name{font-family:var(--font-display);font-weight:700;font-size:13px;line-height:1.2;margin-bottom:6px}
.tm-podium .pos .score{font-family:var(--font-display);font-weight:700;font-size:18px}
.tm-podium .step{border-radius:10px 10px 0 0;display:flex;flex-direction:column;align-items:center;justify-content:flex-start;padding-top:10px;color:#fff}
.tm-podium .step.gold{background:linear-gradient(180deg,#F4B740,#D97706)}
.tm-podium .step.silver{background:linear-gradient(180deg,#A8B3C4,#7C8AA0)}
.tm-podium .step.bronze{background:linear-gradient(180deg,#C98A5E,#A2643C)}
.tm-podium .pos.me .step{outline:3px solid var(--metriq-teal);outline-offset:2px;animation:tm-podpulse 1.8s infinite}
@keyframes tm-podpulse{0%,100%{outline-color:rgba(10,124,110,.9)}50%{outline-color:rgba(10,124,110,.35)}}

/* ---- LEADERBOARD ROW ---- */
.tm-lb-row{display:flex;align-items:center;gap:12px;padding:11px 13px;border-radius:11px;border:1px solid transparent}
.tm-lb-row.me{background:var(--accent-soft);border-color:rgba(10,124,110,.3)}
.tm-lb-row .rank{font-family:var(--font-display);font-weight:700;font-size:15px;width:24px;text-align:center;color:var(--muted)}
.tm-lb-row.me .rank{color:var(--metriq-teal)}

/* ---- SEGMENTED TABS ---- */
.tm-seg{display:inline-flex;background:var(--line-soft);border-radius:10px;padding:3px;gap:2px}
.tm-seg button{border:none;background:transparent;font-family:var(--font-body);font-weight:600;font-size:12.5px;color:var(--ink-soft);padding:7px 14px;border-radius:8px;cursor:pointer;white-space:nowrap}
.tm-seg button.on{background:var(--card);color:var(--primary);box-shadow:var(--shadow)}

/* ---- DUAL-REGISTER TAGLINE ---- */
.tm-tagline .sw{font-family:var(--font-display);font-weight:700;font-size:24px;letter-spacing:-.02em;line-height:1.15}
.tm-tagline .en{font-size:14px;opacity:.6;margin-top:4px}

/* ---- TROPHY / ACHIEVEMENT CARD ---- */
.tm-ach{flex:0 0 200px;border-radius:14px;padding:14px;color:#fff;position:relative;overflow:hidden}
.tm-ach.gold{background:linear-gradient(135deg,#D97706,#B45309)}
.tm-ach.star{background:linear-gradient(135deg,#0A7C6E,#065F53)}
.tm-ach.trend{background:linear-gradient(135deg,#0B4F8A,#0A3A66)}

/* ---- CHALLENGE BANNER ---- */
.tm-challenge{background:var(--amber-light);border:1px solid rgba(217,119,6,.3);border-radius:13px;padding:14px 15px}
.tm-vs{display:grid;grid-template-columns:1fr auto 1fr;gap:10px;align-items:center;margin-top:10px}
.tm-vs .vs{font-family:var(--font-display);font-weight:700;color:var(--warm-amber);font-size:13px}

/* ---- FLOATING MAP TOGGLE BUTTONS ---- */
.tm-mapfab{position:absolute;right:12px;display:flex;flex-direction:column;gap:8px;z-index:20}
.tm-mapfab button{width:40px;height:40px;border-radius:12px;border:1px solid var(--line);background:var(--card);box-shadow:var(--shadow);display:flex;align-items:center;justify-content:center;cursor:pointer;color:var(--ink-soft)}
.tm-mapfab button.on{background:var(--metriq-teal);color:#fff;border-color:var(--metriq-teal)}

/* ---- KPI ALERT / ESCALATION ---- */
.tm-escalation-trail{display:flex;flex-direction:column;gap:0}
.tm-esc-step{display:flex;gap:10px;position:relative;padding-bottom:14px}
.tm-esc-step:not(:last-child)::before{content:'';position:absolute;left:15px;top:32px;bottom:0;width:2px;background:var(--line)}
.tm-esc-dot{width:32px;height:32px;border-radius:50%;display:flex;align-items:center;justify-content:center;flex:0 0 32px;font-size:13px;font-weight:700;color:#fff}
.tm-esc-dot.open{background:var(--amber)}.tm-esc-dot.escalated{background:var(--ember)}.tm-esc-dot.resolved{background:var(--green)}.tm-esc-dot.deferred{background:var(--muted)}
.tm-esc-body{flex:1;padding-top:4px}
.tm-esc-who{font-size:12.5px;font-weight:600;color:var(--ink)}
.tm-esc-when{font-size:11px;color:var(--muted);margin-top:1px}
.tm-esc-note{font-size:12px;color:var(--ink-soft);margin-top:5px;font-style:italic}

/* ---- CHURN RISK METER ---- */
.tm-churn-meter{height:8px;border-radius:6px;background:var(--line-soft);overflow:hidden;position:relative}
.tm-churn-meter>i{display:block;height:100%;border-radius:6px}
.tm-churn-meter.low>i{background:var(--forest);width:var(--pct)}
.tm-churn-meter.med>i{background:var(--warm-amber);width:var(--pct)}
.tm-churn-meter.high>i{background:var(--churn-red);width:var(--pct);animation:tm-pulse 1.6s infinite}

/* ---- [x-cloak] ---- */
[x-cloak]{display:none!important}

/* ============================================================
   MOBILE RESPONSIVENESS — comprehensive fix block
   Covers all tenant / super-admin / PWA / auth pages.
   ============================================================ */

/* ── P0: iOS Safari auto-zoom prevention ──────────────────── */
/* Font-size < 16px on any focused input triggers a viewport zoom on iOS.
   Resetting to 16px on mobile prevents the jarring zoom across all 34+ screens. */
@media(max-width:760px){
  .tm-input,.tm-select,.tm-textarea{font-size:16px}
}

/* ── P0: Canonical modal + bg overlay ─────────────────────── */
.tm-modal-bg{position:fixed;inset:0;background:rgba(15,25,41,.45);z-index:900;display:flex;align-items:center;justify-content:center;padding:16px}
.tm-modal{background:var(--card);border:1px solid var(--card-border);border-radius:var(--radius-lg);width:100%;max-width:520px;max-height:90vh;overflow-y:auto;padding:24px;box-shadow:var(--shadow-lg)}
.tm-modal-footer{display:flex;gap:10px;justify-content:flex-end;padding-top:16px;border-top:1px solid var(--line-soft);flex-wrap:wrap}
@media(max-width:480px){
  .tm-modal{padding:16px;border-radius:var(--radius);max-height:96vh}
  .tm-modal-footer{justify-content:stretch}
  .tm-modal-footer .tm-btn{flex:1}
}

/* ── P0: Table horizontal scroll wrapper ──────────────────── */
.tm-table-wrap{overflow-x:auto;-webkit-overflow-scrolling:touch}
@media(max-width:760px){
  .tm-table{font-size:12px}
  .tm-table thead th,.tm-table tbody td{padding:9px 12px}
}

/* ── P0: Topbar search/date hide utility ──────────────────── */
/* Add class tm-topbar-search or tm-topbar-date to any topbar element
   that should be hidden on mobile to prevent horizontal overflow. */
@media(max-width:760px){
  .tm-topbar-search,.tm-topbar-date{display:none!important}
  .tm-topbar .tm-input{display:none!important}
}

/* ── P1: KPI number font scale-down ───────────────────────── */
@media(max-width:760px){.tm-kpi-num{font-size:28px}}
@media(max-width:430px){.tm-kpi-num{font-size:24px}}

/* ── P1: Toast safe-area on notched phones ────────────────── */
@media(max-width:480px){
  .tm-toast{bottom:max(26px,calc(env(safe-area-inset-bottom) + 12px))}
}

/* ── P1: Segmented tabs overflow-x scroll on mobile ─────────── */
@media(max-width:480px){
  .tm-seg{overflow-x:auto;-webkit-overflow-scrolling:touch;max-width:100%;display:flex}
  .tm-seg button{flex-shrink:0}
}

/* ── P1: Button row + card head wrapping ──────────────────── */
.tm-btn-row{display:flex;gap:8px;flex-wrap:wrap;align-items:center}
@media(max-width:480px){
  .tm-card-head{flex-wrap:wrap;gap:8px}
  .tm-card-head>:last-child{margin-left:auto}
}

/* ── P1: Canvas global guard ──────────────────────────────── */
canvas{display:block;max-width:100%}
.tm-chart-wrap{position:relative;overflow:hidden;min-width:0}
@media(max-width:760px){.tm-chart-wrap{min-height:160px}}

/* ── P1: Typography scale-down on small phones ────────────── */
@media(max-width:480px){
  .tm-display{font-size:30px;letter-spacing:-.02em}
  .tm-h1{font-size:22px}
  .tm-h2{font-size:18px}
}

/* ── P1: Achievement card horizontal-scroll row ───────────── */
.tm-ach-row{display:flex;gap:12px;overflow-x:auto;-webkit-overflow-scrolling:touch;padding-bottom:4px;scrollbar-width:none}
.tm-ach-row::-webkit-scrollbar{display:none}
@media(max-width:480px){.tm-ach{flex:0 0 160px}}

/* ── P1: Auth pages — formpane & formcard scroll fix ─────── */
/* When soft keyboard raises on mobile, centered-flex layout traps the form
   above the fold. overflow-y:auto lets it scroll into view. */
.formpane{overflow-y:auto}
.formcard{padding-bottom:max(24px,env(safe-area-inset-bottom,16px))}

/* ── P1: PWA canvas elements must never overflow ─────────── */
.pwa-body canvas,.pwa-tile canvas,.pwa-card canvas{width:100%!important;display:block}

/* ── P1: PWA install banner — wrap on small phones ─────────── */
#pwa-install-banner{flex-wrap:wrap}
#pwa-install-banner>div{min-width:0;flex:1}

/* ── P1: Offline page CSS variable aliases ────────────────── */
.offline-card{background:var(--card)}

/* ── P1: pwa-supervisor-scorecard promotion ring ─────────── */
.promo-ring .val,#promo-score{font-size:clamp(18px,6.5vw,28px)}

/* ── P1: pwa-install-flow step labels on stacked mobile ─── */
@media(max-width:480px){
  .step-label{position:relative;top:0;left:0;transform:none;text-align:center;display:block;margin-bottom:8px}
}

/* ── P2: Sidebar shrink at 320px ─────────────────────────── */
@media(max-width:430px){
  .tm-side{width:56px;flex-basis:56px}
  .tm-nav{padding:10px 0}
  .tm-nav svg{width:22px;height:22px}
}

/* ── P2: .tm-content overflow guard ──────────────────────── */
@media(max-width:760px){
  .tm-content{overflow-x:hidden;max-width:100vw}
}

/* ── P2: Metric grid on ultra-narrow ─────────────────────── */
@media(max-width:430px){
  .tm-metric-grid{grid-template-columns:1fr 1fr}
}

/* ── P2: Pill overflow truncation ────────────────────────── */
@media(max-width:480px){
  .tm-pill{max-width:calc(50% - 4px);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
}

/* ── P2: Scope banner truncation ─────────────────────────── */
@media(max-width:760px){
  .tm-scope-banner{flex-wrap:wrap}
  .tm-scope-banner>span:last-child{display:none}
}

/* ── P2: Scrollbar thinning on touch screens ─────────────── */
@media(max-width:760px){
  ::-webkit-scrollbar{width:4px;height:4px}
  ::-webkit-scrollbar-thumb{border:none}
}

/* ── P2: Podium slot names — truncate on mobile ──────────── */
.podium-slot .name,.podium .pos .name{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:100%}

/* ── P2: Level switcher tab labels — no wrapping ─────────── */
.level-switcher .tab{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}

/* ── P2: PWA profile name display — truncate ─────────────── */
#pf-name-display{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

/* ── P2: PWA language button fill row equally ────────────── */
.lang-btn{flex:1;text-align:center}

/* ── P2: Merchant/issue request button min height ─────────── */
.pwa-card.tap[data-mr],.pwa-card.tap[data-if]{min-height:56px}

/* ── P2: Filter strip webkit scrollbar hidden ─────────────── */
.filter-strip::-webkit-scrollbar,[style*='overflow-x:auto']::-webkit-scrollbar{display:none}

/* ── P2: Password strength bar min segment width ─────────── */
.strength-seg{min-width:16px}

/* ── P2: SLA violation rows wrapping ─────────────────────── */
@media(max-width:480px){
  .vrow{flex-wrap:wrap}
  .vrow .tm-btn{flex-shrink:0}
}

/* ── P2: Super-admin tenant slide panel KPI ─────────────── */
@media(max-width:480px){
  .t-panel-kpi{grid-template-columns:1fr 1fr!important}
}

/* ── P2: Super-admin RBAC bottom two-panel ───────────────── */
@media(max-width:640px){
  .rbac-bottom-grid{grid-template-columns:1fr!important}
}

/* ── P2: Feature flags header search ─────────────────────── */
@media(max-width:760px){
  .ff-wrap header input[type=search]{max-width:100%;width:100%}
}

/* ── P2: Super-admin security topbar badge ───────────────── */
@media(max-width:600px){
  .sec-topbar-badge{display:none!important}
}

/* ── P2: NPS survey grid — 4 cols for balanced layout ────── */
.nps-grid{grid-template-columns:repeat(4,1fr)!important}

/* ── Global topbar search: override any fixed 280-320px inline width ── */
@media(max-width:760px){
  #tm-search-wrap{flex:1 1 100%!important;max-width:100%!important}
}

/* Floating menu affordance for .tm-app pages that have no .tm-topbar to host it
   (support.js appends this when it finds no topbar). Sits clear of content. */
.tm-mob-toggle-float{display:none}
@media(max-width:760px){
  .tm-mob-toggle-float{
    display:flex!important;position:fixed;top:12px;left:12px;z-index:198;
    width:40px;height:40px;box-shadow:0 2px 10px rgba(0,0,0,.14);
  }
  /* keep page content from sliding under the floating button */
  .tm-app:has(.tm-mob-toggle-float) .tm-main{padding-top:58px}
}

/* Wide tables scroll INSIDE their own box; the page body never scrolls sideways.
   tenant-users' org table was 574px wide on a 390px screen and dragged the whole
   document with it. */
@media(max-width:760px){
  .tm-main table,.tm-content table{
    display:block;width:100%;max-width:100%;
    overflow-x:auto;-webkit-overflow-scrolling:touch;
  }
}

/* ── Vertical chrome: an activation-model tenant (mobile money, tracks_sales=0) sells no
   stock, so every revenue hero/tile/column/trend marked [data-tm-revenue] is hidden, and
   any activation-only element marked [data-tm-activation] is revealed. Stamped on <html>
   by TmAPI.init (data-tracks-sales). FMCG/subscription (tracks-sales=1) are unaffected. */
:root[data-tracks-sales="0"] [data-tm-revenue] { display: none !important; }

/* THREE states, not two: unknown / money-free ("0") / revenue-tracking ("1").
   The attribute only lands once org/field-config resolves, so on a first-ever load (empty
   localStorage, nothing to pre-stamp from) there is a window with NO attribute at all. If the
   default for that window is "visible", a money-free tenant flashes currency before the gate
   closes — which is exactly what a live demo sees. So money is revealed only once we
   AFFIRMATIVELY know tracks-sales="1"; anything else (unknown, or "0") withholds it.

   Unknown uses visibility, not display: the element keeps its box, so the reveal costs no
   reflow and revenue tenants see a fade-in rather than a layout jump. Once the tenant is
   confirmed money-free, the rule above takes it out of layout for real. Revealing-then-hiding
   is the leak; hiding-then-revealing is merely a beat late. */
:root:not([data-tracks-sales="1"]):not([data-tracks-sales="0"]) [data-tm-revenue] {
  visibility: hidden !important;
}

[data-tm-activation] { display: none; }
:root[data-tracks-sales="0"] [data-tm-activation] { display: revert !important; }

/* ⭐FIX (2026-08-09, Vuka Pesa adversarial audit): [data-tm-revenue] above protects every
   REVENUE-ONLY element (permanently display:none once a tenant is confirmed money-free). But
   the CEO/HoS hero's #hero-rev/#hero-target/#hero-bar/#hero-pct/#hero-forecast are VERTICAL-
   DEPENDENT, not revenue-only — pwa-ceo-day.html/pwa-hos-day.html's own renderHero() writes a
   real revenue figure into them for a sales-tracking org, or a composite score for a money-free
   one. [data-tm-revenue]'s display:none would be WRONG here (it would blank the score too), so
   these elements were left untagged entirely — with no CSS backstop at all.
   Live-caught: renderHero() runs on DOMContentLoaded via this page's OWN analytics fetch
   (executive-summary/strategic-overview), completely unsequenced against tm-api.js's separate
   org/field-config fetch (the one that actually confirms tracks_sales and stamps this attribute).
   Confirmed on dev.trademetriq.solutions as CEO (Vuka Pesa, org4, tracks_sales=0): when the
   analytics fetch resolves first, renderHero() reads the still-"unknown" attribute, takes the
   revenue branch, and paints "National revenue · TSh 0 · of TSh 0 target · 0% to target · Full-
   year forecast: TSh 0" — a fabricated-looking board number in front of a money-free tenant's own
   CEO. A later org/field-config response CAN self-heal it (renderHero() re-runs on the
   'tm:vertical' event), but nothing repaints it if that request is merely slow or fails outright —
   exactly the network conditions real field/office connectivity in Tanzania has, not just a test
   artifact. [data-tm-vertical-pending] hides ONLY the true-unknown window (visibility, like the
   rule above) and never applies once EITHER confirmed state lands, so whichever branch actually
   rendered — revenue or score — is simply revealed, unlike [data-tm-revenue] which would erase
   the score branch too. */
:root:not([data-tracks-sales="1"]):not([data-tracks-sales="0"]) [data-tm-vertical-pending] {
  visibility: hidden !important;
}

/* A hidden [data-tm-revenue] KPI tile inside a fixed grid would leave an empty column; collapse it
   out of the grid entirely for a no-sales org so the remaining tiles reflow cleanly. */
:root[data-tracks-sales="0"] .pwa-tile[data-tm-revenue] { display: none !important; }

/* H68 fix: the HoS zone-drill drawer's own 3-column KPI grid (Revenue/Coverage/At-risk) has
   the same "empty column" problem as .pwa-tile above, but under a different class name that the
   original fix didn't cover — display:none on the Revenue cell removes IT from grid flow, but a
   fixed grid-template-columns:1fr 1fr 1fr still reserves 3 tracks regardless of child count, so
   the 2 remaining tiles filled columns 1-2 and column 3 rendered as a bare, differently-colored
   empty box (the grid container's own border-color background, with no card-colored .c tile
   painted over it — a visible blank placeholder rather than a clean 2-tile row). */
:root[data-tracks-sales="0"] .zd-kpis { grid-template-columns: 1fr 1fr; }
