/* ChatAI Control Center — professional SaaS design system (UX1).
   Token-driven, generic (not coupled to any tenant brand). No remote runtime dependency; icons are inline SVG. */

/* ---- tokens ---- */
:root{
  /* color */
  --brand:#4f46e5; --brand-d:#4338ca; --brand-050:#eef2ff; --brand-100:#e0e7ff;
  --ink:#0f172a; --ink-2:#334155; --muted:#64748b; --muted-2:#94a3b8;
  --line:#e5e9f0; --line-2:#eef2f7; --bg:#f6f8fb; --card:#ffffff; --panel:#ffffff;
  --ok:#15803d; --ok-bg:#dcfce7; --ok-dot:#22c55e;
  --warn:#92400e; --warn-bg:#fef3c7; --warn-dot:#f59e0b;
  --no:#b91c1c; --no-bg:#fee2e2; --no-dot:#ef4444;
  --off:#475569; --off-bg:#eef2f7; --off-dot:#94a3b8;
  --nav:#0b1220; --nav-2:#111a2e; --nav-ink:#c7d2e6; --nav-ink-2:#7c8aa5; --nav-active:#4f46e5;
  /* type */
  --f-sans:system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;
  --fs-11:11px; --fs-12:12px; --fs-13:13px; --fs-14:14px; --fs-15:15px; --fs-16:16px; --fs-18:18px; --fs-22:22px; --fs-28:28px;
  /* space */
  --s-1:4px; --s-2:8px; --s-3:12px; --s-4:16px; --s-5:20px; --s-6:24px; --s-8:32px;
  /* radius / shadow */
  --r-sm:8px; --r:12px; --r-lg:16px; --r-pill:999px;
  --sh-1:0 1px 2px rgba(15,23,42,.04),0 1px 3px rgba(15,23,42,.06);
  --sh-2:0 4px 12px rgba(15,23,42,.08); --sh-3:0 12px 40px rgba(15,23,42,.14);
  --gutter:24px; --content-max:1120px; --sidebar-w:252px;
}
*{box-sizing:border-box}
html,body{margin:0;padding:0;max-width:100%;overflow-x:hidden}
body{font:var(--fs-15)/1.55 var(--f-sans);color:var(--ink);background:var(--bg);-webkit-font-smoothing:antialiased}
a{color:var(--brand);text-decoration:none}
a:hover{text-decoration:underline}
h1,h2,h3{line-height:1.25;color:var(--ink)}
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);border:0}
.skip{position:absolute;left:-999px;top:0;background:#fff;padding:8px 12px;border-radius:8px;z-index:100}
.skip:focus{left:8px;top:8px}
:focus-visible{outline:2px solid var(--brand);outline-offset:2px;border-radius:6px}
.muted{color:var(--muted)}
.small{font-size:var(--fs-12)}
svg.ic{width:18px;height:18px;flex:0 0 auto;stroke:currentColor;fill:none;stroke-width:1.9;stroke-linecap:round;stroke-linejoin:round;vertical-align:middle}
svg.ic.sm{width:15px;height:15px}

/* ---- auth / error (bare) ---- */
body.bare{display:flex;align-items:center;justify-content:center;min-height:100vh;background:radial-gradient(1200px 500px at 50% -10%,var(--brand-050),var(--bg))}
.card-center{background:var(--card);padding:32px;border-radius:var(--r-lg);box-shadow:var(--sh-3);width:min(410px,92vw)}
.card-center h1{margin:.2em 0 .6em;font-size:var(--fs-22)}
.brand{font-weight:800;letter-spacing:.2px;display:flex;align-items:center;gap:8px}
.brand .logo{width:26px;height:26px;border-radius:7px;background:linear-gradient(135deg,var(--brand),#7c3aed);display:inline-flex;align-items:center;justify-content:center;color:#fff}
.brand span{color:var(--brand)}
.brand.big{font-size:var(--fs-18);margin-bottom:8px}

/* ---- app shell ---- */
.app{display:grid;grid-template-columns:var(--sidebar-w) 1fr;min-height:100vh}
.sidebar{background:linear-gradient(180deg,var(--nav),var(--nav-2));color:var(--nav-ink);padding:16px 12px;position:sticky;top:0;height:100vh;display:flex;flex-direction:column;gap:6px;overflow:auto}
.sidebar .brand{color:#fff;font-size:var(--fs-16);padding:6px 8px 14px;border-bottom:1px solid rgba(255,255,255,.06);margin-bottom:6px}
.sidebar .brand span{color:#c7b8ff}
.sidebar nav ul{list-style:none;margin:0;padding:0}
.sidebar nav a{display:flex;align-items:center;gap:10px;color:var(--nav-ink);padding:9px 11px;border-radius:9px;margin:2px 0;font-size:var(--fs-14);font-weight:500}
.sidebar nav a:hover{background:rgba(255,255,255,.06);text-decoration:none;color:#fff}
.sidebar nav a.active{background:var(--nav-active);color:#fff;box-shadow:var(--sh-1)}
.sidebar nav a .ic{color:inherit;opacity:.9}
/* META-SOCIAL-UI-FOUNDATION-01 — the sidebar's first expandable section. Deliberately reuses the leaf link's
   metrics so a parent and a leaf sit on the same rhythm; only the caret and the indented panel are new. */
.sidebar nav .nav-toggle{display:flex;align-items:center;gap:10px;width:100%;color:var(--nav-ink);background:none;border:0;padding:9px 11px;border-radius:9px;margin:2px 0;font-size:var(--fs-14);font-weight:500;font-family:inherit;text-align:left;cursor:pointer}
.sidebar nav .nav-toggle:hover{background:rgba(255,255,255,.06);color:#fff}
.sidebar nav .nav-toggle .nav-caret{margin-left:auto;transition:transform .15s ease;opacity:.7}
.sidebar nav .nav-parent.open>.nav-toggle .nav-caret{transform:rotate(180deg)}
.sidebar nav .nav-parent.open>.nav-toggle{color:#fff}
.sidebar nav .nav-sub{margin:0 0 4px;padding:0 0 0 34px}
.sidebar nav .nav-sub a{padding:7px 11px;font-weight:400;font-size:var(--fs-13,13px)}

.nav-group{padding:14px 11px 4px;font-size:var(--fs-11);font-weight:700;letter-spacing:.09em;text-transform:uppercase;color:var(--nav-ink-2)}
.nav-group:first-of-type{padding-top:4px}
.side-foot{margin-top:auto;padding:10px 8px 4px;color:var(--nav-ink-2);font-size:var(--fs-11);border-top:1px solid rgba(255,255,255,.06)}

.main-wrap{display:flex;flex-direction:column;min-width:0}
/* UI04-CORR-05 §16-18: the topbar must NOT use backdrop-filter — it creates a containing block for position:fixed
   descendants, so the notification popover (re-anchored fixed by cc.js) was positioned/clipped relative to the ~50px
   topbar instead of the viewport (root cause of the cut-off popover + hidden counts). Use an opaque background. */
.topbar{display:flex;justify-content:space-between;align-items:center;gap:12px;background:#fff;border-bottom:1px solid var(--line);padding:12px 24px;position:sticky;top:0;z-index:15}
.crumb h1{font-size:var(--fs-18);margin:0}
.crumb .ws{display:flex;align-items:center;gap:6px;font-size:var(--fs-12);color:var(--muted);font-weight:500;margin-top:1px}
.user{display:flex;align-items:center;gap:10px}
.user .who{display:flex;flex-direction:column;align-items:flex-end;line-height:1.2}
.user .who .email{font-size:var(--fs-13);color:var(--ink-2);font-weight:600}
.user .who .role{font-size:var(--fs-11);color:var(--muted)}
.avatar{width:34px;height:34px;border-radius:50%;background:var(--brand-100);color:var(--brand-d);display:flex;align-items:center;justify-content:center;font-weight:700;font-size:var(--fs-14)}
.tenant-switch select{padding:7px 10px;border:1px solid var(--line);border-radius:9px;background:#fff;font:inherit;color:var(--ink-2)}
.content{padding:var(--gutter);max-width:var(--content-max);width:100%;margin:0 auto;min-width:0;overflow-x:clip}
.main-wrap{max-width:100%}
.cards>*,.card{min-width:0}
.nav-toggle{display:none}
.scrim{display:none}

/* ---- page header ---- */
.page-head{display:flex;justify-content:space-between;align-items:flex-start;gap:16px;margin:2px 0 18px;flex-wrap:wrap}
.page-head .lead{font-size:var(--fs-13);color:var(--muted);margin:4px 0 0}
.page-head h2{margin:0;font-size:var(--fs-22)}

/* ---- cards / metrics ---- */
.cards{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:14px;margin-bottom:18px}
.card,.card-link .card{background:var(--card);border:1px solid var(--line);border-radius:var(--r);padding:16px 18px;box-shadow:var(--sh-1)}
.card-link{display:block}
.card-link:hover{text-decoration:none}
.card-link:hover .card{border-color:var(--brand-100);box-shadow:var(--sh-2);transform:translateY(-1px)}
.card{transition:.15s ease}
.card-ico{width:36px;height:36px;border-radius:9px;background:var(--brand-050);color:var(--brand-d);display:flex;align-items:center;justify-content:center;margin-bottom:10px}
.card-t{font-size:var(--fs-13);color:var(--muted);font-weight:500}
.card-v{font-size:var(--fs-28);font-weight:800;margin:4px 0;letter-spacing:-.5px}
.card-v.sm{font-size:var(--fs-18)}
.card-s{font-size:var(--fs-12);color:var(--muted)}
.card.card-err{border-style:dashed;border-color:#fca5a5}
.card.card-err .card-v{color:var(--muted)}

/* ---- panels / sections ---- */
.panel{background:var(--panel);border:1px solid var(--line);border-radius:var(--r);padding:20px;margin-bottom:16px;box-shadow:var(--sh-1)}
.panel-head{display:flex;justify-content:space-between;align-items:center;gap:12px;margin-bottom:14px;flex-wrap:wrap}
.panel h2{font-size:var(--fs-16);margin:0 0 12px;display:flex;align-items:center;gap:8px}
.panel-head h2{margin:0}
.panel-head-actions{display:flex;align-items:center;gap:8px}
/* FINAL-CORR01 §10 — Opportunity modal sections + sticky footer save */
.opp-form .opp-sec{border:1px solid var(--line);border-radius:var(--r-sm);padding:12px 14px;margin:0 0 12px}
.opp-form .opp-sec legend{font-size:var(--fs-12);font-weight:650;color:var(--brand-d);padding:0 6px}
.opp-form .opp-unmapped{margin-top:8px}
.cw-modal-foot{position:sticky;bottom:0;display:flex;justify-content:flex-end;gap:10px;padding:12px 0 2px;background:var(--card);border-top:1px solid var(--line-2);margin-top:4px}
.cw-modal-foot .btn.primary{min-width:96px}
.setup-banner{background:linear-gradient(180deg,var(--brand-050),#fff);border-color:var(--brand-100)}
.setup-row{display:flex;justify-content:space-between;align-items:center;gap:16px;flex-wrap:wrap}

/* ---- tables ---- */
.table-wrap{overflow-x:auto;border-radius:var(--r-sm)}
.table{width:100%;border-collapse:collapse;font-size:var(--fs-14)}
.table th,.table td{text-align:left;padding:11px 10px;border-bottom:1px solid var(--line-2);vertical-align:middle}
.table thead th{color:var(--muted);font-weight:600;font-size:var(--fs-12);text-transform:uppercase;letter-spacing:.04em;background:var(--line-2)}
.table tbody tr:hover{background:var(--brand-050)}
.table tbody tr:last-child td{border-bottom:0}
code{background:var(--line-2);padding:1px 6px;border-radius:6px;font-size:var(--fs-13);font-family:ui-monospace,SFMono-Regular,Menlo,monospace}

/* ---- forms ---- */
.form label{display:block;font-weight:600;margin:12px 0 5px;font-size:var(--fs-14)}
.form input,.form textarea,.form select{width:100%;padding:10px 12px;border:1px solid #cbd5e1;border-radius:9px;font:inherit;background:#fff;transition:.12s}
.form input:focus,.form textarea:focus,.form select:focus{border-color:var(--brand);box-shadow:0 0 0 3px var(--brand-050);outline:none}
.form .hint{font-size:var(--fs-12);color:var(--muted);margin:4px 0 0}
.form.grid2{display:grid;grid-template-columns:1fr 1fr;gap:2px 18px}
.form.grid2 .col2{grid-column:1/3}
.form.grid2 .actions{margin-top:14px}
.check{margin:12px 0}
.check label{display:flex;align-items:center;gap:9px;font-weight:500}
.check input{width:auto}
.check.disabled{opacity:.55}

/* ---- buttons ---- */
.btn{display:inline-flex;align-items:center;justify-content:center;gap:7px;padding:9px 15px;min-height:40px;border:1px solid var(--line);border-radius:9px;background:#fff;cursor:pointer;font:inherit;font-weight:600;color:var(--ink-2);transition:.12s;line-height:1.25;white-space:normal;text-align:center;max-width:100%}
.btn:hover{text-decoration:none;background:var(--line-2);border-color:#d7deea}
.btn.primary{background:var(--brand);border-color:var(--brand);color:#fff}
.btn.primary:hover{background:var(--brand-d);border-color:var(--brand-d)}
.btn.ghost{background:transparent;border-color:transparent;color:var(--brand-d)}
.btn.ghost:hover{background:var(--brand-050)}
.btn.danger-btn{color:var(--no);border-color:#fecaca;background:#fff}
.btn.danger-btn:hover{background:var(--no-bg)}
.btn.sm{min-height:32px;padding:6px 11px;font-size:var(--fs-13)}
.btn.disabled,.btn[aria-disabled=true]{opacity:.5;pointer-events:none}
.icon-btn{display:inline-flex;align-items:center;justify-content:center;width:36px;height:36px;border-radius:9px;border:1px solid var(--line);background:#fff;cursor:pointer;color:var(--ink-2)}
.icon-btn:hover{background:var(--line-2)}
.inline{display:inline-flex;margin-right:8px}
.actions{display:flex;gap:8px;flex-wrap:wrap}

/* ---- badges (dot + text; never color-only) ---- */
.badge{display:inline-flex;align-items:center;gap:6px;padding:3px 10px;border-radius:var(--r-pill);font-size:var(--fs-12);font-weight:600;line-height:1.6}
.badge::before{content:"";width:7px;height:7px;border-radius:50%;background:currentColor;opacity:.9}
.badge.ok{background:var(--ok-bg);color:var(--ok)}
.badge.no{background:var(--no-bg);color:var(--no)}
.badge.warn{background:var(--warn-bg);color:var(--warn)}
.badge.off{background:var(--off-bg);color:var(--off)}
.badge.muted{background:var(--line-2);color:var(--muted)}
.badge.plain::before{display:none}

/* ---- alerts / empty ---- */
.alert{display:flex;gap:9px;padding:11px 14px;border-radius:var(--r-sm);margin:10px 0;font-size:var(--fs-14);border:1px solid transparent}
.alert .ic{margin-top:1px}
.alert.error{background:var(--no-bg);color:var(--no);border-color:#fecaca}
.alert.ok{background:var(--ok-bg);color:var(--ok);border-color:#bbf7d0}
.alert.warn{background:var(--warn-bg);color:var(--warn);border-color:#fde68a}
.empty{text-align:center;padding:34px 20px;color:var(--muted)}
.empty .ic{width:34px;height:34px;color:var(--muted-2);margin-bottom:8px}
.empty p{margin:0 0 12px}

/* ---- action menu (details/summary, no JS dep) ---- */
.menu{position:relative;display:inline-block}
.menu>summary{list-style:none;cursor:pointer}
.menu>summary::-webkit-details-marker{display:none}
.menu[open]>.menu-pop{display:block}
.menu-pop{display:none;position:absolute;right:0;top:calc(100% + 6px);background:#fff;border:1px solid var(--line);border-radius:10px;box-shadow:var(--sh-2);min-width:190px;padding:6px;z-index:20}
.menu-pop a,.menu-pop button{display:flex;align-items:center;gap:9px;width:100%;text-align:left;padding:9px 10px;border-radius:8px;border:0;background:none;font:inherit;color:var(--ink-2);cursor:pointer}
.menu-pop a:hover,.menu-pop button:hover{background:var(--line-2);text-decoration:none}
.menu-pop .danger{color:var(--no)}

/* ---- pagination ---- */
.pager{display:flex;justify-content:space-between;align-items:center;margin-top:14px;gap:12px}

/* ---- onboarding / progress ---- */
.progress{height:9px;background:#e2e8f0;border-radius:var(--r-pill);overflow:hidden;margin-bottom:10px}
.progress .bar{height:100%;background:linear-gradient(90deg,var(--brand),#7c3aed)}
.onb{list-style:none;padding:0;margin:0;display:grid;gap:10px}
.onb-item{border:1px solid var(--line);border-radius:11px;padding:13px 15px}
.onb-h{display:flex;align-items:center;gap:10px;font-weight:600}

/* ---- channels as cards ---- */
.channel-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:14px}
.channel-card{border:1px solid var(--line);border-radius:var(--r);padding:16px;background:#fff;box-shadow:var(--sh-1);display:flex;flex-direction:column;gap:10px}
.channel-top{display:flex;align-items:center;gap:12px}
.channel-ico{width:42px;height:42px;border-radius:11px;display:flex;align-items:center;justify-content:center;color:#fff;flex:0 0 auto}
.channel-ico.website{background:linear-gradient(135deg,#4f46e5,#7c3aed)}
.channel-ico.facebook{background:linear-gradient(135deg,#1877f2,#0a5fd0)}
.channel-ico.zalo{background:linear-gradient(135deg,#0068ff,#0047b3)}
.channel-ico.telegram{background:linear-gradient(135deg,#2aabee,#1c93d1)}
.channel-name{font-weight:700}
.channel-acc{font-size:var(--fs-12);color:var(--muted)}
.channel-note{font-size:var(--fs-13);color:var(--ink-2)}
.channel-foot{display:flex;justify-content:space-between;align-items:center;gap:10px;margin-top:auto;border-top:1px solid var(--line-2);padding-top:10px}

/* ---- conversations ---- */
.filter-bar{display:flex;gap:12px;flex-wrap:wrap;align-items:flex-end;background:var(--card);border:1px solid var(--line);border-radius:var(--r);padding:14px 16px;margin-bottom:14px;box-shadow:var(--sh-1)}
.filter-bar label{display:block;font-size:var(--fs-12);color:var(--muted);margin-bottom:4px}
.filter-bar select,.filter-bar input{padding:9px 10px;border:1px solid #cbd5e1;border-radius:9px;font:inherit;background:#fff}
.filter-bar .filter-actions{margin-left:auto;display:flex;gap:8px}
.table.conversations td{vertical-align:middle}
.conv-cell{display:flex;align-items:flex-start;gap:11px;min-width:0}
.conv-cell>span:not(.conv-avatar){min-width:0;flex:1}
.conv-avatar{width:34px;height:34px;border-radius:50%;background:var(--brand-050);color:var(--brand-d);display:flex;align-items:center;justify-content:center;flex:0 0 auto}
/* ZALO-PROFILE-ENRICHMENT-01 §14 — the real customer picture sits ON TOP of the generated initial, filling the
   same circle. CSP forbids an inline onerror handler, so the fallback is structural rather than scripted: a
   broken, blocked or 404 image paints nothing and simply reveals the letter underneath, at identical size. The
   circle never changes dimensions, so a failed avatar cannot shift a single row of the list. */
.conv-avatar{position:relative;overflow:hidden;font-weight:600;font-size:14px;line-height:1}
.conv-avatar.has-img>img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;border-radius:50%}
/* CORR07 - ONE covering rule for EVERY avatar box.
   The queue row, the overview row and the thread header now render through Pages::customerAvatar(), which paints
   the initial as the box content and lays the <img> over it. Each surface keeps its own sizing class, so the
   positioning context and the cover rule have to apply to all of them - otherwise the picture loads and simply
   is not seen, which is exactly the failure this ticket is about. Listed explicitly rather than via a shared
   class so no existing markup had to change. */
.q-avatar,.ov-avatar,.cw-ava{position:relative;overflow:hidden}
.q-avatar.has-img>img,.ov-avatar.has-img>img,.cw-ava.has-img>img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;border-radius:50%}
/* the thread header avatar: same circle as the queue, one size up, never shrinking beside a long name */
.cw-ava{flex:0 0 auto;width:36px;height:36px;border-radius:50%;background:var(--brand-050);color:var(--brand-d);display:flex;align-items:center;justify-content:center;font-weight:600;font-size:14px;line-height:1;text-transform:uppercase}
@media (max-width:640px){.cw-ava{width:32px;height:32px;font-size:13px}}
.conv-link{display:block;color:inherit;min-width:0}
.conv-link:hover{text-decoration:none}
.conv-who{font-weight:600;color:var(--ink)}
.conv-prev{margin-top:2px;max-width:58ch;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.table.responsive td{overflow:hidden}
.conv-link:hover .conv-who{color:var(--brand-d)}
.chan-tag{display:inline-flex;align-items:center;gap:6px;color:var(--muted);font-size:var(--fs-13)}

/* ---- transcript ---- */
.conv-head{display:flex;justify-content:space-between;align-items:flex-start;gap:12px}
.conv-head h2{margin:0 0 3px}
.transcript{display:flex;flex-direction:column;gap:2px;padding:4px 0}
/* CORR02 §F/§G — CONVERSATION DENSITY.
   Measured before: gap 12px between EVERY bubble + 10/13 padding + a footer row that was reserved even though
   the timestamp inside it is opacity:0 until hover. A one-line "ok" therefore cost ~59px of column. Chat apps
   sit near half that. The gap drops to 2px and becomes the WITHIN-GROUP spacing; the larger separation is
   reintroduced below only where the speaker actually changes, which is the signal a reader uses. Font sizes are
   untouched — the height came from padding and reserved rows, not from type. */
/* META-REVIEW-25A — the App Review demo banner (renders ONLY in the env-designated review workspace). */
.spc-demo-note{margin:0 0 12px;padding:10px 14px;border:1px solid #f59e0b;border-radius:10px;background:#fffbeb;color:#92400e;font-size:13px;line-height:1.5}

/* UI-POLISH-23 SSB — bubble width: 76% keeps visual air on the opposite side even for a very long message
   (ticket band 75-80%); short messages still size to content via align-self, long ones wrap at the cap. */
.msg{position:relative;max-width:76%;padding:6px 10px;border-radius:12px;border:1px solid var(--line);box-shadow:var(--sh-1)}
/* §G UI-ONLY GROUPING. data-direction is already on every bubble and is emitted by BOTH the page render and the
   /delta poll, so sibling selectors group appended messages identically to reloaded ones with no new markup, no
   server round-trip and no change to canonical data. */
.msg[data-direction="inbound"]+.msg[data-direction="outbound"],
.msg[data-direction="outbound"]+.msg[data-direction="inbound"]{margin-top:10px}
/* consecutive same-sender bubbles tighten their inner corners, the usual grouped-chat cue */
.msg.in+.msg.in{border-top-left-radius:6px}
.msg.out+.msg.out{border-top-right-radius:6px}
.msg .msg-meta{margin-bottom:3px;display:flex;align-items:center;gap:6px}
/* P3C-S2R2: compact bubble footer — time hidden until hover (desktop); exceptional delivery state stays visible. */
.msg .msg-foot{display:flex;align-items:center;gap:6px;justify-content:flex-end;min-height:0;margin-top:0}
/* CORR02 §F — the timestamp was invisible (opacity:0) yet still reserved ~13px on EVERY bubble: the worst of
   both. Lifting it out of flow removes that row entirely; the footer then collapses to zero height whenever
   there is no delivery state (.msg-state:empty is already display:none), and an exceptional state still renders
   in flow exactly as before. It keeps its own background so it stays readable in the 2px gap it now hovers over,
   and pointer-events:none so it can never intercept a click on the bubble beneath. */
.msg .msg-time{position:absolute;top:100%;right:10px;margin-top:1px;z-index:4;font-size:11px;line-height:1.4;
  color:var(--muted,#6b7280);background:var(--card,#fff);padding:0 4px;border-radius:6px;
  opacity:0;transition:opacity .12s ease;pointer-events:none}
.msg.in .msg-time{right:auto;left:10px}
.msg:hover .msg-time,.msg:focus-within .msg-time{opacity:.75}
.msg .msg-state{font-size:11px}
.msg .msg-state:empty{display:none}
/* sound toggle (compact, unobtrusive) */
.snd-toggle{display:inline-flex;align-items:center;gap:6px;border:1px solid var(--line-2,#e5e7eb);background:#fff;border-radius:999px;padding:4px 10px;font-size:12px;cursor:pointer;color:var(--ink,#111)}
.snd-toggle.is-off{color:var(--muted,#9ca3af)}
.snd-toggle .snd-ic{width:15px;height:15px}
.q-bar{display:flex;justify-content:flex-end;padding:4px 6px}
/* P3C-S2R2: right-column tabs (Khách hàng | Nhãn | Sản phẩm) */
.cw-tabs{display:flex;flex-direction:column}
.cw-tabbar{display:flex;gap:2px;border-bottom:1px solid var(--line-2,#e5e7eb);margin-bottom:10px;position:sticky;top:0;background:#fff;z-index:1}
.cw-tab{appearance:none;border:0;background:none;padding:8px 10px;font:inherit;font-size:13px;color:var(--muted,#6b7280);cursor:pointer;border-bottom:2px solid transparent;margin-bottom:-1px}
.cw-tab.is-active{color:var(--brand,#2563eb);border-bottom-color:var(--brand,#2563eb);font-weight:600}
.cw-tab:focus-visible{outline:2px solid var(--brand,#2563eb);outline-offset:-2px}
.cw-tabpanel>.panel{border:0;padding:0;margin:0 0 10px;box-shadow:none}
/* CRM-UX-CONSOLIDATION-01 §2.3 — the [hidden] attribute (server- or JS-set) must always win: exactly one panel shows. */
.cw-tabpanel[hidden]{display:none}
/* CRM-UX-CONSOLIDATION-V1 §4.2 — the ONE reusable CRM modal shell (Lead Contact/Opportunity, Customer edit). The
   [hidden] attribute (server-emitted, JS-toggled) fully hides it; open = a fixed scrim + centered card that scrolls
   its own body. CSP-safe (behaviour is delegated cc.js, no inline handlers). */
.cw-modal[hidden]{display:none}
.cw-modal{position:fixed;inset:0;z-index:1000;display:flex;align-items:center;justify-content:center;padding:16px}
.cw-modal-scrim{position:absolute;inset:0;background:rgba(15,23,42,.45)}
.cw-modal-panel{position:relative;z-index:1;background:var(--card);border:1px solid var(--line);border-radius:var(--r-lg);box-shadow:var(--sh-3);width:min(560px,96vw);max-height:90vh;display:flex;flex-direction:column;overflow:hidden}
.cw-modal-head{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:14px 18px;border-bottom:1px solid var(--line-2)}
.cw-modal-title{margin:0;font-size:var(--fs-16);font-weight:600;color:var(--ink)}
.cw-modal-x{border:0;background:transparent;font-size:22px;line-height:1;color:var(--muted);cursor:pointer;padding:2px 6px;border-radius:var(--r-sm)}
.cw-modal-x:hover{background:var(--line-2);color:var(--ink)}
.cw-modal-body{padding:16px 18px;overflow:auto}
html.cw-modal-open{overflow:hidden}
.cw-prod-soon{margin-top:8px;line-height:1.5}
/* HARDENING-04 §emoji — a DISPLAY fix for a display defect.
   Outbound hearts are stored U+2764 U+FE0F and render red; an inbound Instagram heart is stored bare
   U+2764 and renders as black text. Both are exactly the bytes their sender supplied, so the stored
   content is CORRECT and is not rewritten — appending FE0F to customer text would corrupt canonical
   content to fix a font choice, and would do it to every other codepoint that shares the pattern.
   U+FE0F is a variation selector: absent it, the default presentation for these codepoints is text.
   Two layers, because neither alone covers every browser we support:
     font-variant-emoji:emoji  asks the engine directly (Chrome 131+, Firefox). The correct property;
                               ignored where unsupported, which is why it is not the whole answer.
     emoji fonts FIRST         the portable fallback. These faces carry no Latin coverage, so ordinary
                               text falls straight through to inherit and only emoji codepoints are
                               claimed. Covers Safari and older Chromium/Firefox.
   Scoped to message text; it changes no layout, no colour and no stored byte. */
.msg-body{white-space:normal;word-break:break-word;overflow-wrap:anywhere;font-family:"Apple Color Emoji","Segoe UI Emoji","Noto Color Emoji",inherit;font-variant-emoji:emoji}
/* UI-POLISH-23 SSD/SSE — one link, one phone, visually. The tel anchor is nowrap so a number can NEVER split
   across lines (the reported digit-shredding); URLs stay under the body's overflow-wrap so a long href wraps
   inside the bubble instead of overflowing the panel. Colors keep contrast on both bubble backgrounds. */
.msg-body a.msg-link{color:var(--brand);text-decoration:underline;text-underline-offset:2px}
.msg-body a.msg-tel{color:inherit;text-decoration:underline;text-underline-offset:2px;white-space:nowrap}
/* UI-POLISH-23 SSC — the origin label reads ONCE per consecutive native run: every bubble still ships its
   label (delta-poll appends stay dumb), but a native bubble immediately followed by another native bubble
   hides its copy, leaving the label under the LAST of the cluster. A CHOTSALE/AI bubble has no .native class,
   so it breaks the run and the truthful label re-appears after it. Old engines without :has simply show every
   label — the pre-23 behaviour, a safe degradation. */
.msg.native:has(+ .msg.native) .msg-native{display:none}
.msg.in{align-self:flex-start;background:#fff;border-bottom-left-radius:4px}
.msg.out{align-self:flex-end;background:var(--brand-050);border-color:var(--brand-100);border-bottom-right-radius:4px}

/* ---- account ---- */
.profile{display:flex;align-items:center;gap:14px}
.profile .avatar{width:52px;height:52px;font-size:var(--fs-18)}
.kv{display:grid;grid-template-columns:auto 1fr;gap:6px 16px;font-size:var(--fs-14)}
.kv dt{color:var(--muted)}
.facts{line-height:1.9;margin:8px 0 0;padding-left:18px}

/* ---- preview / embed (widget) ---- */
.preview-banner{display:flex;align-items:center;gap:8px;background:#fff7ed;border:1px solid #fed7aa;color:#9a3412;padding:9px 13px;border-radius:9px;font-weight:600;margin-bottom:12px}
.preview-frames{display:flex;gap:18px;flex-wrap:wrap}
.pf{border:1px solid var(--line);border-radius:12px;overflow:hidden;background:#fff;box-shadow:var(--sh-1)}
.pf-tag{display:block;background:var(--line-2);padding:6px 10px;font-size:var(--fs-12);color:var(--muted);border-bottom:1px solid var(--line)}
.pf iframe{border:0;display:block;background:#fff}
.pf.desktop iframe{width:520px;height:420px}
.pf.mobile iframe{width:320px;height:520px}
.embed pre{background:#0b1220;color:#e2e8f0;padding:14px;border-radius:10px;overflow:auto}
/* CORR-01 §12 embed code block: readable, contrasty, horizontally scrollable, bounded height; small docked Copy */
.embed-code{position:relative;margin:6px 0}
.embed-code pre{margin:0;background:#0f172a;color:#f1f5f9;border-radius:10px;padding:12px 14px;padding-right:104px;overflow-x:auto;max-height:160px;font:13px/1.6 ui-monospace,SFMono-Regular,Menlo,Consolas,"Liberation Mono",monospace;white-space:pre}
.embed-code pre code{background:none;color:inherit;white-space:pre;font:inherit}
.embed-copy{position:absolute;top:8px;right:8px;background:#f8fafc}
@media (max-width:560px){.embed-code pre{padding-right:14px}.embed-copy{position:static;margin-top:8px}}
.preview-host{padding:24px;background:var(--bg);min-height:100vh}
.preview-note{color:var(--muted);font-size:var(--fs-13)}
.danger{border-top:1px solid var(--line);margin-top:18px;padding-top:14px}

/* ---- P1: knowledge / AI config / playground ---- */
.form .col2 label{margin-top:12px}
.lead-opts{display:flex;flex-wrap:wrap;gap:14px;margin-top:4px}
.lead-opt{display:inline-flex;align-items:center;gap:6px;font-weight:500}
.lead-opt input{width:auto}
.guard-row{display:flex;flex-wrap:wrap;gap:8px}
.src-row{display:flex;justify-content:space-between;align-items:center;gap:10px;padding:8px 0;border-bottom:1px solid var(--line-2)}
.src-row:last-child{border-bottom:0}
.panel h3{font-size:var(--fs-15);margin:0 0 10px;display:flex;align-items:center;gap:8px}

/* ---- responsive ---- */
@media (max-width:960px){
  .app{grid-template-columns:1fr}
  .sidebar{position:fixed;left:-280px;top:0;width:264px;transition:left .22s ease;z-index:40;box-shadow:var(--sh-3)}
  .app.nav-open .sidebar{left:0}
  .app.nav-open .scrim{display:block;position:fixed;inset:0;background:rgba(15,23,42,.45);z-index:35}
  .nav-toggle{display:inline-flex;align-items:center;justify-content:center;width:40px;height:40px;background:#fff;color:var(--ink);border:1px solid var(--line);border-radius:9px;cursor:pointer}
  .topbar{padding:10px 14px}
  .content{padding:16px}
  .form.grid2{grid-template-columns:1fr}
  .form.grid2 .col2{grid-column:1}
  .user .who{display:none}
}
@media (max-width:640px){
  .filter-bar{flex-direction:column;align-items:stretch}
  .filter-bar .filter-actions{margin-left:0}
  .table-wrap{overflow-x:visible}
  .table.responsive,.table.responsive tbody,.table.responsive tr,.table.responsive td{display:block;width:auto;max-width:100%}
  .table.responsive thead{position:absolute;left:-9999px}
  .table.responsive tr{border:1px solid var(--line);border-radius:11px;margin:0 0 10px;padding:10px 12px;box-shadow:var(--sh-1)}
  .table.responsive td{border:0;padding:4px 0;text-align:left}
  .table.responsive td::before{content:attr(data-th) "";display:block;color:var(--muted);font-size:var(--fs-11);font-weight:600;text-transform:uppercase;letter-spacing:.03em;margin-bottom:1px}
  .table.responsive td.cell-main::before{display:none}
  .table.responsive td:empty{display:none}
  .conv-prev{max-width:100%;white-space:normal;overflow:visible;text-overflow:clip;overflow-wrap:anywhere;word-break:break-word}
  /* UI-POLISH-23 SSB — 100% made a long message a full-width card and erased the in/out sides on phones;
     88% keeps a readable column AND a constant visual gap that says which side is speaking. */
  .msg{max-width:88%}
  .page-head{flex-direction:column}
  .setup-row{flex-direction:column;align-items:stretch}
  .setup-row>div{min-width:0}
  .setup-row .btn{width:100%}
  .cards{grid-template-columns:1fr}
  .content{padding:14px}
  .panel{padding:16px}
  .channel-grid{grid-template-columns:1fr}
}
@media (prefers-reduced-motion:reduce){*{transition:none!important}}

/* P2 Operational Inbox */
.badge-stack{display:flex;flex-wrap:wrap;gap:6px;align-items:center}
.action-row{display:flex;flex-wrap:wrap;gap:10px;align-items:center;margin-top:8px}
.inline-form{display:inline-flex;flex-wrap:wrap;gap:6px;align-items:center;margin:0}
.reason-inp{min-width:180px;max-width:100%}
.check-inline{display:flex;align-items:flex-end}
.check-inline label{display:inline-flex;gap:6px;align-items:center;font-size:var(--fs-14)}
.src-list{margin:6px 0 0;padding-left:18px}
.src-list li{margin:2px 0}
/* P2.1 Omnichannel */
.badge.sky{background:var(--brand-050,#e0f2fe);color:#0369a1}
.badge.red{background:#fee2e2;color:#b91c1c}
.channel-switcher{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:12px}
/* UI04 §9/§40: bigger click target, smooth hover/active/press/focus transitions, brand-tinted icons. */
.chan-tab{display:inline-flex;align-items:center;gap:7px;padding:8px 13px;border:1px solid var(--line-2,#e5e7eb);border-radius:var(--r-pill,999px);color:var(--ink-2);text-decoration:none;font-size:var(--fs-14);font-weight:600;background:#fff;transition:background .16s ease,color .16s ease,border-color .16s ease,box-shadow .16s ease,transform .1s ease}
.chan-tab .ic{opacity:.85}
.chan-tab:hover{background:var(--brand-050);border-color:var(--brand-100);color:var(--brand-d)}
.chan-tab:active{transform:translateY(1px)}
.chan-tab:focus-visible{outline:2px solid var(--brand);outline-offset:2px}
.chan-tab[aria-current="page"]{background:var(--brand,#4f46e5);color:#fff;border-color:var(--brand,#4f46e5);box-shadow:0 1px 6px rgba(79,70,229,.28)}
.chan-tab[aria-current="page"] .ic{opacity:1}
/* §40 tablet: channel tabs scroll horizontally instead of wrapping into an ugly second row. */
@media (min-width:561px) and (max-width:1279px){.channel-switcher{flex-wrap:nowrap;overflow-x:auto;-webkit-overflow-scrolling:touch;scrollbar-width:thin;padding-bottom:2px}.chan-tab{flex:0 0 auto}}
/* UI04-CORR-02 §12-17 channel nav: compact pills with a soft circular brand-tinted icon badge, actionable count, whole
   pill as the click target, and a single deterministic row (discreet horizontal scroll — never wraps to 2 lines). */
.chan-nav{flex-wrap:nowrap;overflow-x:auto;-webkit-overflow-scrolling:touch;scrollbar-width:thin;padding-bottom:2px}
.chan-nav::-webkit-scrollbar{height:6px}
.chan-nav::-webkit-scrollbar-thumb{background:var(--line-2,#e5e7eb);border-radius:3px}
.chan-nav .chan-tab{flex:0 0 auto;gap:8px;padding:5px 13px 5px 5px}
.ct-ic{display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;border-radius:50%;background:var(--line-2,#eef0f3);color:var(--ink-2);flex:0 0 auto}
.ct-ic .ic{width:16px;height:16px;opacity:1}
.ct-label{white-space:nowrap}
.ct-count{margin-left:2px}
.chan-tab[data-ch="all"] .ct-ic{background:#eef2ff;color:#4f46e5}
.chan-tab[data-ch="website"] .ct-ic{background:#e0f2fe;color:#0369a1}
.chan-tab[data-ch="facebook"] .ct-ic{background:#e7f0ff;color:#1877f2}
.chan-tab[data-ch="zalo"] .ct-ic{background:#e6f2ff;color:#0068ff}
.chan-tab[data-ch="zalo_personal"] .ct-ic{background:#e6f2ff;color:#0068ff}
.chan-tab[data-ch="tiktok"] .ct-ic{background:#f1f1f2;color:#111}
.chan-tab[data-ch="instagram"] .ct-ic{background:#fce7f3;color:#c13584}
.chan-tab[aria-current="page"] .ct-ic{background:rgba(255,255,255,.22);color:#fff}
@media (min-width:1280px){.chan-nav{flex-wrap:nowrap}}
/* S2R6-CORR03 §A: STRUCTURAL channel visibility. No JS horizontal scroll is reliable on iOS Safari/PWA, so on mobile
   the SELECTED channel is reordered to the FRONT of the strip — right after "Tất cả kênh" — guaranteeing it is visible
   immediately after navigation, for all 7 channels, with zero JS. Desktop keeps the canonical order (mobile-only). */
@media (max-width:760px){
  .chan-nav .chan-tab[data-ch="all"]{order:-2}
  .chan-nav .chan-tab[aria-current="page"]{order:-1}
}
.omni-detail{display:grid;grid-template-columns:1fr 320px;gap:16px;align-items:start}
.omni-main{min-width:0}
.omni-aside{min-width:0}
.kv{display:flex;justify-content:space-between;gap:10px;padding:4px 0;border-bottom:1px solid var(--line-2,#eef2f7)}
.kv:last-child{border-bottom:0}
.kv .k{color:var(--muted);font-size:var(--fs-13)}
.btn.xs{padding:2px 8px;font-size:var(--fs-12);min-height:0}
/* P2.2A1 action-required counters + bell */
.count-badge{display:inline-flex;align-items:center;justify-content:center;min-width:18px;height:18px;padding:0 5px;margin-left:6px;border-radius:9px;background:#dc2626;color:#fff;font-size:11px;font-weight:700;line-height:1}
.nav-badge{margin-left:auto}
.bell-menu{position:relative}
.bell-btn{position:relative;display:inline-flex;align-items:center;justify-content:center;width:40px;height:40px;border-radius:10px;cursor:pointer;color:var(--muted)}
.bell-btn:hover{background:var(--brand-050);color:var(--brand-d)}
.bell-btn .count-badge{position:absolute;top:2px;right:2px;margin:0}
/* UI04-CORR-05 §17/§19: a comfortably-sized panel so the actionable counts are always readable (positioning is
   handled by cc.js placeMenu now that the topbar no longer creates a fixed-containing block). */
.bell-pop{right:0;min-width:260px;max-width:320px;padding:0}
/* CORR-01 §8: compact popover — header w/ total, tight channel rows, sound toggle footer. */
.bell-head{display:flex;align-items:center;justify-content:space-between;padding:9px 12px;font-weight:700;border-bottom:1px solid var(--line-2,#eef2f7)}
.bell-list{padding:2px 0;max-height:44vh;overflow:auto}
.bell-row{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:7px 12px;text-decoration:none;color:inherit}
.bell-row .bell-ch{display:inline-flex;align-items:center;gap:8px;min-width:0}
.bell-row .bell-ch>span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.bell-row .bell-ch .ic{flex:0 0 auto;color:var(--muted,#6b7280)}
.bell-row .count-badge{margin:0;flex:0 0 auto}
.bell-row:hover{background:var(--brand-050)}
.bell-empty{padding:12px 14px}
.bell-foot{border-top:1px solid var(--line-2,#eef2f7);padding:8px 12px}
.bell-foot .snd-toggle{width:100%;justify-content:space-between;border:0;padding:6px 4px}
.bell-empty{padding:14px}
/* Zalo Personal QR + notice */
/* ZALO-PERSONAL-UI-WIRING-01: the box now holds a REAL QR served by CHOTSALE, so it gets a plain white
   ground (a striped background behind a QR is a scanning hazard) and keeps the dashed placeholder only
   while the image is still being fetched. */
.qr-box{width:200px;height:200px;border:2px dashed var(--line-2,#cbd5e1);border-radius:12px;display:flex;align-items:center;justify-content:center;text-align:center;color:var(--muted);background:#fff;font-weight:700;padding:8px;flex:0 0 auto}
.qr-box .qr-img{width:100%;height:100%;object-fit:contain;image-rendering:pixelated;display:block}
.qr-box .qr-wait{display:flex;flex-direction:column;align-items:center;gap:8px;font-weight:600;font-size:13px}
/* IDENTITY-BIND-01 §8 — the same trap UI04-CORR-02 documented for the emoji popup: an author-level
   `display:` beats the user-agent `[hidden]{display:none}`, so the server-rendered `hidden` on the spinner
   and on the auto-submit finalize form did nothing and both were visible under the QR. Honour `[hidden]` at
   author specificity (no !important). */
.qr-box .qr-wait[hidden]{display:none}
.qr-box .qr-img[hidden]{display:none}
.action-row .inline-form[hidden],.inline-form[hidden]{display:none}
.qr-box .spinner{width:22px;height:22px;border:3px solid var(--line-2,#cbd5e1);border-top-color:var(--brand,#2563eb);border-radius:50%;animation:cc-spin .8s linear infinite}
@keyframes cc-spin{to{transform:rotate(360deg)}}
@media (prefers-reduced-motion:reduce){.qr-box .spinner{animation:none}}
.qr-wrap{display:flex;gap:18px;align-items:flex-start;flex-wrap:wrap;margin:12px 0}
[data-zp-error]{color:var(--danger,#b91c1c)}
.notice-list{margin:8px 0;padding-left:18px}
.notice-list li{margin:6px 0}
.notice-panel{border-left:3px solid var(--warn,#d97706)}
.check-line{display:flex;gap:8px;align-items:center;padding:4px 0;font-size:var(--fs-14)}
.scope-fs{border:1px solid var(--line-2,#e5e7eb);border-radius:10px;padding:10px 12px;margin:6px 0}
.scope-fs legend{padding:0 6px;font-size:var(--fs-13);color:var(--muted)}
@media (max-width:900px){.omni-detail{grid-template-columns:1fr}}

/* P2.2A2 — contextual interaction row / Zalo multi-account / Facebook comment workspace */
.interaction-switcher,.zalo-account-switcher{margin-top:-4px}
.conv-post{display:flex;align-items:center;gap:4px;margin:2px 0}
.post-thumb{display:inline-flex;align-items:center;justify-content:center;width:18px;height:18px;border-radius:4px;background:var(--line-2,#eef1f5)}
.reply-from{margin-bottom:6px}
.panel-head{display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap}
.post-context .post-context-row{display:flex;gap:14px;align-items:flex-start}
.post-context .post-thumb-lg{flex:0 0 auto;width:56px;height:56px;border-radius:10px;background:var(--line-2,#eef1f5);display:flex;align-items:center;justify-content:center}
.post-context .post-title{font-weight:600;margin:4px 0}
.post-context-body{min-width:0}
@media (max-width:480px){.post-context .post-context-row{flex-direction:column}.channel-switcher{overflow-x:auto;-webkit-overflow-scrolling:touch}}

/* P2.3A-UI01 — conversation workspace (3-zone messaging layout) */
.cw{display:flex;flex-direction:column;height:calc(100dvh - 108px);min-height:520px;background:#fff;border:1px solid var(--line-2,#e5e7eb);border-radius:12px;overflow:hidden}
.cw-head{flex:0 0 auto;display:flex;align-items:center;gap:10px;padding:10px 14px;border-bottom:1px solid var(--line-2,#e5e7eb);background:#fff}
.cw-back{flex:0 0 auto}
.cw-who{flex:1;min-width:0}
.cw-who h2{margin:0;font-size:16px;line-height:1.3;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.cw-sub{display:flex;gap:6px;align-items:center;flex-wrap:wrap;margin-top:2px}
.cw-head-badges{flex:0 0 auto;display:flex;gap:4px;align-items:center}
.cw-head-actions{flex:0 0 auto;display:flex;gap:6px;align-items:center}
.cw-body{flex:1;display:flex;min-height:0}
.cw-main{position:relative;flex:1;display:flex;flex-direction:column;min-width:0;min-height:0}
.cw-timeline{flex:1;overflow-y:auto;padding:14px 16px;background:#f6f8fa;scroll-behavior:smooth}
.cw-postctx{display:flex;gap:8px;align-items:center;background:#fff;border:1px solid var(--line-2,#e5e7eb);border-radius:10px;padding:8px 10px;margin-bottom:10px}
.cw-postctx .post-thumb{flex:0 0 auto}
.cw-newmsg{position:absolute;left:50%;transform:translateX(-50%);bottom:172px;z-index:6;background:var(--brand,#4f46e5);color:#fff;border:none;border-radius:20px;padding:6px 14px;font:600 13px system-ui;cursor:pointer;box-shadow:0 4px 12px rgba(0,0,0,.18)}
.cw-composer{flex:0 0 auto;border-top:1px solid var(--line-2,#e5e7eb);padding:10px 14px;background:#fff}
.cw-composer-hint{padding:14px}
.cw-draft{margin-bottom:8px}
/* UI04 §34: compact editor, auto-grows to a bounded height (JS caps at 160). */
.cw-input{width:100%;box-sizing:border-box;min-height:46px;max-height:160px;resize:none;border:1px solid #cfd6dd;border-radius:10px;padding:10px 12px;font:15px/1.5 system-ui,sans-serif}
.cw-input:focus{outline:2px solid var(--brand,#4f46e5);outline-offset:1px;border-color:var(--brand,#4f46e5)}
/* UI04 §33: ONE toolbar under the editor (tools left, actions right); emoji popup anchored to its button, opens above. */
.cw-toolbar{display:flex;align-items:center;gap:8px;margin-top:8px}
.cw-tools{display:flex;align-items:center;gap:4px}
.cw-emoji-wrap{position:relative;display:inline-flex}
.cw-subhint{display:flex;align-items:center;gap:10px;margin-top:6px;flex-wrap:wrap}
.cw-composer-bar{display:flex;align-items:center;gap:10px;margin-top:8px;flex-wrap:wrap}
.cw-hint{flex:1;min-width:120px}
.cw-actions-r{display:flex;gap:8px;align-items:center;margin-left:auto}
.cw-send{min-width:92px}
.cw-menu{position:relative}
.cw-menu .menu-pop{right:0;min-width:240px}
.cw-menu .menu-item{padding:6px 8px;border-bottom:1px solid var(--line-2,#eef1f5)}
.cw-menu .menu-item:last-child{border-bottom:none}
.cw-detail{flex:0 0 300px;border-left:1px solid var(--line-2,#e5e7eb);overflow-y:auto;padding:12px;background:#fff}
.cw-detail .panel{border:1px solid var(--line-2,#eef1f5);margin-bottom:10px}
.cw-detail-close{display:none}
.cw-detail-toggle{display:none}
.cw-testtool{border-left:3px solid var(--warn,#d97706)}
/* CHOTSALE-INBOX-PROD-06-P3C-S2 — mini-CRM customer panel (read-mode first, compact) */
.cw-crm .cw-crm-name{font-weight:650;font-size:15px;line-height:1.3;overflow-wrap:anywhere}
.cw-crm .cw-crm-v{overflow-wrap:anywhere;text-align:right}
.cw-crm .cw-crm-empty{margin:6px 0 8px}
.cw-crm-actions{display:flex;flex-direction:column;gap:6px;margin-top:8px}
.cw-crm-drawer{margin-top:6px}
.cw-crm-drawer>summary{display:inline-flex;align-items:center;gap:6px;cursor:pointer;list-style:none}
.cw-crm-drawer>summary::-webkit-details-marker{display:none}
.cw-crm-pop{margin-top:8px;padding:10px;border:1px solid var(--line-2,#eef1f5);border-radius:10px;background:#fbfcfe}
/* P3C-S2R1: ONE field per row (owner-approved) — full width, no horizontal clipping on desktop or mobile drawer. */
.cw-crm-grid{display:flex;flex-direction:column;gap:10px}
.cw-fld{display:flex;flex-direction:column;gap:4px;font-size:12px;color:var(--muted,#6b7280);min-width:0}
.cw-in{width:100%;box-sizing:border-box;padding:7px 8px;border:1px solid var(--line-2,#d7dde5);border-radius:8px;font:inherit;font-size:13px;color:#111}
.cw-in:focus{outline:2px solid var(--brand,#2563eb);outline-offset:-1px;border-color:transparent}
textarea.cw-in{resize:vertical;min-height:38px}
.cw-crm-search{display:flex;gap:6px;margin-bottom:8px}
.cw-crm-search .cw-in{flex:1}
.cw-crm-hits{display:flex;flex-direction:column;gap:6px}
.cw-crm-hit{display:flex;align-items:center;justify-content:space-between;gap:8px;padding:6px 8px;border:1px solid var(--line-2,#eef1f5);border-radius:8px}
.cw-crm-hit>div{min-width:0;overflow-wrap:anywhere}
@media (max-width:1100px){.cw-head-badges{display:none}}
@media (max-width:900px){
  .cw{height:calc(100dvh - 84px)}
  .cw-detail-toggle{display:inline-flex}
  /* CORR/S2R6B: the "+ Thông tin" panel is a TRUE fixed overlay — out of document flow entirely, so CLOSED it reserves
     ZERO width and can never be swipe-exposed (document scrollWidth stays <= viewport). OPEN it slides over the chat. */
  .cw-detail{position:fixed;top:0;right:0;bottom:0;width:min(340px,88vw);max-width:100vw;transform:translateX(100%);transition:transform .18s ease;z-index:60;box-shadow:-8px 0 24px rgba(0,0,0,.18);overscroll-behavior:contain}
  .cw[data-detail-open] .cw-detail{transform:translateX(0)}
  .cw-detail-close{display:block;margin-left:auto}
  .cw-scrim{position:fixed;inset:0;background:rgba(0,0,0,.4);z-index:55}
  .cw-scrim[hidden]{display:none;pointer-events:none}   /* S2R6-CORR03 §B: a CLOSED scrim can never cover the header */
  .cw-back-label{display:inline}
  .cw-newmsg{bottom:188px}
}
/* the back label ("Hội thoại") is mobile-only; desktop keeps the compact icon-only back control */
.cw-back-label{display:none;margin-left:4px}
/* S2R6-CLOSEOUT §B: compact mobile conversation header (≤760px) — 3 tidy lines, ellipsis, no multi-line explosion. */
@media (max-width:760px){
  /* CORR05 §K — wrap:wrap, not nowrap. With three real controls on the right, nowrap pushed the assignee pill
     past the viewport edge on 375/390 (measured in Chromium). The controls now drop to their own row. */
  .cw-head{padding:8px 10px;gap:8px;flex-wrap:wrap}
  /* S2R6-CORR03 §B: the native back anchor sits above the header content, with a full 44x44 touch target, and always
     receives the tap (no closed overlay can sit over it — see .cw-scrim[hidden]). */
  .cw-back{position:relative;z-index:3;pointer-events:auto;min-width:44px;min-height:44px;display:inline-flex;align-items:center;justify-content:center}
  .cw-who{flex:1;min-width:0}
  .cw-who h2{font-size:15px;line-height:1.25}
  .cw-sub{flex-wrap:nowrap;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0}
  .cw-sub .chan-tag{min-width:0;overflow:hidden;text-overflow:ellipsis}
  .cw-sub .chan-lbl{display:none}                 /* keep the channel ICON; drop the redundant "Facebook Messenger" text */
  .cw-head-actions{flex:0 0 auto}
}
/* S2R6-CLOSEOUT §A: the selected channel is clearly highlighted in the compact mobile selector (server-validated). */
.qc-chan-sum.btn{max-width:52vw;overflow:hidden}
.qc-chan-item.is-active{background:var(--brand-050,#eff6ff);color:var(--brand-d,#1d4ed8);font-weight:600}
.qc-chan-item.is-active .ct-ic{color:var(--brand,#2563eb)}
/* S2R6-CLOSEOUT §C: grouped, deferred "Thao tác" actions (compact popover desktop / bottom sheet mobile). */
/* CORR05 §A — the "Thao tác" sheet, its backdrop, its header, its deferred <details> rows and their mobile
   overrides are all deleted. They existed to hold one button. Leaving the styles behind would keep ~30 rules alive
   for markup nothing renders, which is how dead CSS survives long enough to look load-bearing. */
.cw-head-actions{position:relative}
@media (max-width:480px){
  .cw-composer{padding:8px 10px}
  .cw-send{min-width:76px}
  .msg{max-width:90%}
}

/* P2.3A-UI01 — overflow guards (no horizontal scroll on small screens) */
.cw{max-width:100%;overflow-x:hidden}
.cw-main{overflow-x:hidden}
.cw-head{flex-wrap:wrap}
/* UI-POLISH-23 SSB — this overflow guard used to force .msg{max-width:100%} at EVERY width; being later in
   the file it silently overrode the 76% bubble cap, which is exactly the Owner-reported "bubble phủ hết chiều
   ngang" on desktop. The guard keeps box-sizing (its real job); width belongs to the bubble rules above. */
.cw-msg{max-width:100%}
.cw-msg,.msg{box-sizing:border-box}
.msg-meta{flex-wrap:wrap;word-break:break-word}
.cw-composer-bar{max-width:100%}

/* P2.3A-UI01 — prevent any horizontal scroll on small screens (shell + workspace) */
@media (max-width:900px){ html,body{overflow-x:hidden} .main-wrap{overflow-x:hidden;max-width:100vw} }

/* P2.3A-UI01 — tighten composer + bubbles on narrow/compact widths (fits small phones cleanly) */
@media (max-width:560px){
  .cw-timeline{padding:12px 12px}
  .msg{max-width:88%}
  .cw-hint{display:none}
  .cw-composer{padding:8px 10px}
  .cw-actions-r{margin-left:auto}
  .cw-send{min-width:72px}
  .cw-head-actions .cw-detail-toggle span{display:none}
}

/* P2.3A-UI02 — Chotsale.vn product branding */
.brand{display:flex;align-items:center;gap:8px}
/* UI04-CORR-05 §11-13: the logo is a wide "Chotsale.vn" wordmark with large transparent vertical padding. `contain`
   at a small max-height rendered it tiny/unbalanced. Crop the padding with `cover` in a wordmark-proportioned box so
   the mark reads at a balanced size (~132px wide in the sidebar). Sizes are driven by a CSS var for easy tuning. */
.brand-logo{display:block;object-fit:cover;object-position:center;width:var(--brand-logo-w,132px);height:calc(var(--brand-logo-w,132px) / 3);max-width:100%}
.brand .brand-name{font-weight:700;font-size:15px;color:#fff;letter-spacing:.2px}
.brand.big{flex-direction:column;gap:10px;margin-bottom:12px}
.brand.big .brand-logo{--brand-logo-w:210px} /* §14 login: larger wordmark, same crop ratio */
.brand.big .brand-name{color:var(--ink,#111);font-size:20px}
.widget-poweredby{font:11px system-ui;color:#8a94a3;text-align:center;padding:4px 0}
.widget-poweredby a{color:#8a94a3;text-decoration:none}

/* P2.3A-UI02 — modern inbox filter toolbar */
.filter-bar-modern{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin:8px 0 4px}
.fb-search{flex:1;min-width:200px}
.fb-search input{width:100%;box-sizing:border-box;border:1px solid #cfd6dd;border-radius:10px;padding:9px 12px;font:14px system-ui}
.fb-quick{display:flex;gap:6px;flex-wrap:wrap}
.fb-chip{display:inline-flex;align-items:center;gap:6px;border:1px solid var(--line-2,#e5e7eb);border-radius:20px;padding:6px 12px;font-size:13px;cursor:pointer;background:#fff;user-select:none}
.fb-chip.on{background:var(--brand-050,#eef2ff);border-color:var(--brand,#4f46e5);color:var(--brand,#4f46e5);font-weight:600}
.fb-chip input{position:absolute;opacity:0;width:0;height:0}
.fb-advanced .menu-pop.fb-adv-pop{min-width:280px;max-width:320px;display:none;flex-direction:column;gap:8px;padding:12px}
.fb-advanced[open] .menu-pop.fb-adv-pop{display:flex}
.fb-adv-pop label{display:block;font-size:12px;color:var(--muted);margin-bottom:2px}
.fb-adv-pop select{width:100%;box-sizing:border-box}
.filter-actions{display:flex;gap:6px;align-items:center;margin-left:auto}
/* CORR-01 §5 compact level-2 source selector (per channel) — sits next to search, wraps cleanly on small screens */
.fb-source{display:inline-flex;align-items:center;gap:6px}
.fb-source-lbl{font-size:13px;color:var(--muted);white-space:nowrap;margin:0}
.fb-source select{max-width:220px;padding:8px 10px;border:1px solid #cfd6dd;border-radius:10px;font:inherit;background:#fff}
/* UI04-CORR-01 §4/§21 compact inbox time filter — a single select + inline custom dates; never breaks the toolbar row. */
.fb-time{display:inline-flex;align-items:center;gap:6px}
.fb-time>label,.fb-time-lbl{display:inline-flex;align-items:center;color:var(--muted);margin:0}
.fb-time select{padding:8px 10px;border:1px solid #cfd6dd;border-radius:10px;font:inherit;background:#fff;max-width:150px}
.fb-time-custom{display:inline-flex;align-items:center;gap:4px}
.fb-time-custom.is-hidden{display:none}
.fb-time-custom input[type=date]{padding:6px 8px;border:1px solid #cfd6dd;border-radius:10px;font:inherit;background:#fff;max-width:150px}
.fb-time-dash{color:var(--muted)}
/* CORR-02 §2/§18: desktop (≥1280px) toolbar is a DETERMINISTIC single row — nothing wraps below. Search flexes; the
   compact controls never wrap; "Xoá lọc" now lives inside the Bộ lọc popover so it can never create a second row. */
@media (min-width:1280px){
  .filter-bar-modern{flex-wrap:nowrap}
  .filter-bar-modern .fb-search{flex:1 1 auto;min-width:160px}
  .filter-bar-modern .fb-source,.filter-bar-modern .fb-time,.filter-bar-modern .fb-quick,.filter-bar-modern .fb-advanced{flex:0 0 auto}
  .filter-bar-modern .fb-quick{flex-wrap:nowrap}
}
.fb-adv-pop .fb-clear{align-self:flex-start}
/* CORR-02 §5 compact source cell */
.chan-tag .src-name{display:inline-block;max-width:22ch;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:bottom}
.src-surface{margin-left:6px;padding:1px 7px;border-radius:var(--r-pill);background:var(--line-2,#eef0f3);color:var(--muted);font-size:var(--fs-12)}
@media (max-width:560px){.fb-search{min-width:140px;flex-basis:100%}.filter-actions{margin-left:0}.fb-source{flex-basis:100%}.fb-source select{flex:1;max-width:none}.chan-tag .src-name{max-width:16ch}}
/* focus-visible: keyboard users always see where they are (a11y — not colour-only) */
.fb-chip:focus-within{outline:2px solid var(--brand,#4f46e5);outline-offset:1px}

/* ---- P2.3A-UI03 instant filters: loading state (small, no full-page flicker) ---- */
#inbox-live{position:relative}
#inbox-live.is-loading{opacity:.6;transition:opacity .12s ease}
#inbox-live.is-loading *{cursor:progress}
.fb-loading{width:14px;height:14px;border-radius:50%;border:2px solid var(--line-2,#e5e7eb);border-top-color:var(--brand,#4f46e5);display:none}
#inbox-live.is-loading .fb-loading{display:inline-block;animation:fb-spin .6s linear infinite}
@keyframes fb-spin{to{transform:rotate(360deg)}}
@media (prefers-reduced-motion:reduce){#inbox-live.is-loading .fb-loading{animation:none}}

/* ---- P2.3A-UI03 "Cần trả lời" (awaiting reply): distinct from unread; signalled by weight + accent, not colour alone ---- */
.conv-row.conv-needs{background:var(--warn-bg,#fffbeb)}
.conv-row.conv-needs td.cell-main{box-shadow:inset 3px 0 0 var(--warn,#d97706)}
.conv-row.conv-needs .conv-who{font-weight:700}
.conv-row.conv-needs .conv-prev{color:var(--ink)}

/* ---- P2.3A-UI03 label management (create + rename/recolor + safe delete) ---- */
.lbl-manage .menu-pop{min-width:300px;max-width:340px;display:flex;flex-direction:column;gap:8px;padding:12px}
.lbl-manage-row{display:flex;align-items:center;gap:6px;flex-wrap:wrap;padding-bottom:6px;border-bottom:1px solid var(--line-2,#eef0f3)}
.lbl-manage-row:last-child{border-bottom:0;padding-bottom:0}
.lbl-manage-row input[type="text"]{flex:1;min-width:90px;padding:5px 8px;border:1px solid #cbd5e1;border-radius:8px;font:inherit}
.lbl-manage-row select{padding:5px 6px;border:1px solid #cbd5e1;border-radius:8px}
.lbl-manage-row .inline-form{display:inline-flex;gap:5px;align-items:center;margin:0}

/* ---- P2.3A-UI03-CORR-02 composer attachment toolbar + emoji + local audio ---- */
.cw-attach{display:inline-flex;align-items:center;justify-content:center;width:34px;height:34px;border:1px solid var(--line-2,#e5e7eb);border-radius:9px;background:#fff;color:var(--ink);cursor:pointer}
.cw-attach:hover{background:var(--line-2,#f1f5f9)}
/* UI04 §35: capability-gated controls are dimmed but clearly interactive-looking (not "broken"): 0.55 + a subtle bg. */
.cw-attach.is-off,.cw-attach[disabled]{opacity:.55;cursor:not-allowed;background:var(--line-2,#f5f6f8)}
/* UI04 §32: popup anchored to the emoji button (cw-emoji-wrap), opens ABOVE it, high z-index; never overlays the caret. */
.cw-emoji-pop{position:absolute;bottom:calc(100% + 8px);left:0;z-index:1200;display:flex;flex-wrap:wrap;gap:2px;width:264px;max-width:80vw;padding:8px;background:#fff;border:1px solid var(--line);border-radius:12px;box-shadow:0 10px 30px rgba(15,23,42,.16)}
/* UI04-CORR-02 §21-22 emoji ROOT-CAUSE fix: the author `display:flex` above overrides the UA `[hidden]{display:none}`,
   so the palette rendered OPEN on composer load regardless of the (correct) `hidden` attribute + aria-expanded=false.
   Honour `[hidden]` at author specificity — the popup is closed until the toggle removes the attribute (no !important). */
.cw-emoji-pop[hidden]{display:none}
/* CORR-04 §30-32 composer attachment tray (staff review before send) */
.cw-tray{display:flex;flex-direction:column;gap:6px;margin:6px 0}
.cw-tray[hidden]{display:none}
.cw-tray-item{display:flex;align-items:center;gap:8px;padding:6px 10px;border:1px solid var(--line);border-radius:9px;background:#fafbfc;font-size:var(--fs-13)}
.cw-tray-item .ti-name{font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:180px}
.cw-tray-item .ti-status{margin-left:auto;font-size:var(--fs-12);color:var(--muted)}
.cw-tray-item.is-ready .ti-status{color:var(--ok,#16a34a)}
.cw-tray-item.is-uploading .ti-status{color:var(--brand-d)}
.cw-tray-item.is-error{border-color:#fca5a5;background:#fef2f2}
.cw-tray-item.is-error .ti-status{color:#dc2626}
.cw-tray-item .ti-remove{border:0;background:none;cursor:pointer;font-size:16px;line-height:1;color:var(--muted);padding:0 4px}
.cw-tray-item .ti-remove:hover{color:#dc2626}
/* CORR-04 §40-42 thread attachment media */
.msg-atts{display:flex;flex-direction:column;gap:4px;margin-top:4px}
.msg-att-img img{max-width:260px;max-height:260px;border-radius:10px;display:block;border:1px solid var(--line)}
.msg-att-video{max-width:320px;border-radius:10px}
.msg-att-audio{width:260px;max-width:100%}
.msg-att-file{display:inline-flex;align-items:center;gap:8px;padding:8px 10px;border:1px solid var(--line);border-radius:10px;background:#fff;text-decoration:none;color:var(--ink);max-width:280px}
.msg-att-file:hover{background:var(--brand-050)}
.msg-att-file .att-name{font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* CHOTSALE-INBOX-PROD-06-P3 — image lightbox + compact multi-image grid + graceful broken-media fallback */
.msg-att-img{cursor:zoom-in;display:inline-block}
.msg-atts-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:6px}
.msg-atts-grid .msg-att-img img{width:100%;height:120px;object-fit:cover;max-width:none;max-height:none}
.msg-att-img.att-broken{display:inline-flex;align-items:center;justify-content:center;min-width:140px;min-height:88px;border:1px dashed var(--line);border-radius:10px;background:var(--bg,#f6f8fa);cursor:default}
.msg-att-img.att-broken img{display:none}
.msg-att-img.att-broken::after{content:"Không tải được ảnh";color:var(--muted);font-size:12px}
.cw-lightbox{position:fixed;inset:0;z-index:200;background:rgba(0,0,0,.82);display:flex;align-items:center;justify-content:center;padding:24px}
.cw-lightbox img{max-width:96vw;max-height:92vh;border-radius:8px;box-shadow:0 8px 40px rgba(0,0,0,.5)}
.cw-lightbox-close{position:absolute;top:14px;right:18px;width:40px;height:40px;border:none;border-radius:50%;background:rgba(255,255,255,.14);color:#fff;font-size:24px;line-height:1;cursor:pointer}
.cw-lightbox-close:hover{background:rgba(255,255,255,.28)}
/* mobile: the sticky composer honors the iOS home-indicator safe area (no content hidden under it) */
@supports(padding:max(0px)){@media (max-width:900px){.cw-composer{padding-bottom:max(10px,env(safe-area-inset-bottom))}}}
/* CHOTSALE-INBOX-PROD-06-P3 Slice 2 — Facebook connection card + avatar + Page selector */
.fb-ava{display:inline-flex;align-items:center;justify-content:center;border-radius:50%;background:var(--brand-050);color:var(--brand-d);font-weight:700;position:relative;overflow:hidden;flex:0 0 auto;font-size:14px}
.fb-ava img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;border-radius:50%}
.fb-conn{max-width:720px}
.fb-conn-head,.fb-brand{display:flex;align-items:center;gap:8px;font-weight:700}
.fb-account{display:flex;align-items:center;gap:12px;padding:12px;border:1px solid var(--line);border-radius:12px;background:var(--brand-050,#f5f7ff);margin:0 0 14px}
.fb-account-body{display:flex;flex-direction:column;gap:2px;min-width:0;flex:1}
.fb-account-name{font-weight:700;font-size:var(--fs-15,15px);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.fb-account-sub{display:inline-flex;align-items:center;gap:6px;color:var(--muted);font-size:var(--fs-12)}
.fb-account-actions{display:flex;gap:6px;flex:0 0 auto}
.fb-dot{width:8px;height:8px;border-radius:50%;display:inline-block;background:var(--muted-2,#9aa4b2)}
.fb-dot.ok{background:var(--ok,#16a34a)}
.fb-dot.off{background:var(--warn,#d97706)}
.fb-pages-head{display:flex;align-items:baseline;justify-content:space-between;gap:8px;margin:6px 0 2px}
.fb-pages-head h3{margin:0;font-size:var(--fs-14)}
.fb-count{color:var(--muted);font-weight:600;font-size:var(--fs-13)}
.fb-pages{list-style:none;margin:6px 0 0;padding:0;display:flex;flex-direction:column;gap:4px}
.fb-page-row{display:flex;align-items:center;gap:10px;padding:8px 10px;border:1px solid var(--line-2,#eef1f5);border-radius:10px;background:#fff}
.fb-page-body{min-width:0;flex:1;display:flex;flex-direction:column;gap:1px}
.fb-page-name{font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.fb-page-status{display:inline-flex;align-items:center;gap:5px;font-size:var(--fs-12);color:var(--muted)}
.fb-page-status.ok{color:var(--ok,#16a34a)}
.fb-page-act{display:flex;gap:6px;flex:0 0 auto}
.fb-pick{display:flex;align-items:center;gap:10px;flex:1;min-width:0;cursor:pointer}
.fb-addpages{margin-top:14px;border-top:1px solid var(--line);padding-top:12px}
.fb-addpages-head{display:flex;align-items:center;justify-content:space-between;gap:8px;flex-wrap:wrap}
.fb-addpages-head h3{margin:0;font-size:var(--fs-14)}
.fb-addpages-tools{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.fb-pages-pick{max-height:min(46vh,340px);overflow:auto}
.fb-addpages-foot{margin-top:10px}
/* inbox Page selector popover (searchable, avatars) — reuses the .menu/.menu-pop popover + placeMenu positioning */
.src-pop{min-width:280px;max-width:min(92vw,360px);padding:6px;display:flex;flex-direction:column;gap:4px}
.src-search{width:100%;box-sizing:border-box;padding:7px 9px;border:1px solid #cfd6dd;border-radius:9px;font:inherit;margin-bottom:2px}
.src-list{max-height:min(52vh,320px);overflow:auto;display:flex;flex-direction:column;gap:1px}
.src-item{display:flex;align-items:center;gap:8px;padding:7px 8px;border-radius:9px;color:var(--ink-2);text-decoration:none}
.src-item:hover{background:var(--brand-050)}
.src-item.is-active{background:var(--brand-050);color:var(--brand-d);font-weight:650}
.src-item .fb-ava{width:22px;height:22px;font-size:11px}
.src-item .src-nm{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.src-item.is-hidden{display:none}
.src-empty{padding:8px;color:var(--muted);font-size:var(--fs-12)}
@media (max-width:560px){.fb-account-actions{display:none}.fb-page-act .btn:first-child{display:none}}
.cw-emoji{width:32px;height:32px;border:0;background:none;font-size:18px;line-height:1;cursor:pointer;border-radius:8px}
.cw-emoji:hover{background:var(--line-2,#f1f5f9)}
/* S3 AUDIO OUTBOUND — the inline voice recorder (record → timer → preview → attach). Compact + wraps on mobile; no modal. */
.cw-audio-pane{display:flex;align-items:center;flex-wrap:wrap;gap:8px;margin-top:8px;padding:8px 10px;border:1px solid var(--line-2,#e5e7eb);border-radius:10px;background:#fafbfc}
.cw-audio-pane[hidden]{display:none}
.cw-audio-pane audio,.cw-audio-pane .cw-rec-audio{height:34px;max-width:min(240px,60vw)}
.cw-rec-status{font-size:var(--fs-13);color:#dc2626}
.cw-rec-time{font-variant-numeric:tabular-nums;font-weight:600;font-size:var(--fs-13);color:var(--ink,#111);min-width:44px}
.cw-rec-dot{width:10px;height:10px;border-radius:50%;background:#dc2626;display:inline-block;animation:cwRecPulse 1s ease-in-out infinite}
@keyframes cwRecPulse{0%,100%{opacity:1}50%{opacity:.25}}
.cw-rec-err{flex-basis:100%;color:#dc2626}
.cw-mic-btn{color:var(--brand-d,#1d4ed8)}
@media (max-width:760px){.cw-audio-pane audio,.cw-audio-pane .cw-rec-audio{max-width:100%;flex:1 1 140px}}

/* ---- P2.3A-UI03-CORR-02 Facebook comment moderation actions (capability-gated foundation) ---- */
.cw-comment-actions{display:flex;gap:6px;margin-top:6px}
.cw-comment-act[data-comment-on]{background:var(--brand-050);border-color:var(--brand-100);color:var(--brand-d);font-weight:600}
.cw-comment-err{flex:1 1 100%;color:var(--no)}
.cw-comment-act{font-size:var(--fs-12);padding:2px 10px;border:1px solid var(--line-2,#e5e7eb);border-radius:var(--r-pill);background:#fff;color:var(--ink);cursor:pointer}
.cw-comment-act.is-off,.cw-comment-act[disabled]{opacity:.5;cursor:not-allowed}

/* ---- P2.3A-UI03-CORR-02 conversation label picker (attach/detach + search; CRUD lives in settings) ---- */
.lbl-pick-pop{min-width:260px;max-width:320px;display:flex;flex-direction:column;gap:8px;padding:10px}
.lbl-search{width:100%;box-sizing:border-box;padding:7px 9px;border:1px solid #cbd5e1;border-radius:8px;font:inherit}
.lbl-pick-list{display:flex;flex-direction:column;gap:5px;max-height:240px;overflow-y:auto}
.lbl-pick-row{display:flex;align-items:center;gap:6px;justify-content:space-between}
.lbl-pick-row .lbl-on{margin-left:auto}

/* P2.3A-UI02 — widget builder color field */
.color-field{display:flex;gap:8px;align-items:center}
.color-field input[type="color"]{width:44px;height:38px;padding:2px;border:1px solid #cfd6dd;border-radius:8px;cursor:pointer;background:#fff}
.color-field input[data-hex]{flex:1}
.embed-help{margin:8px 0}
.embed-help summary{cursor:pointer}
.panel-head{display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap}

/* ================= CHOTSALE-UI04 — light modern shell + collapsible sidebar ================= */
/* §5-6: light sidebar (Owner does not want the dark sidebar). White bg, dark ink, subtle border, restrained accent. */
.sidebar{background:#fff;color:var(--ink-2);border-right:1px solid var(--line);box-shadow:none}
.sidebar .brand{color:var(--ink);border-bottom:1px solid var(--line)}
.sidebar .brand .brand-name{color:var(--ink)}
.sidebar .brand span{color:var(--brand)}
.sidebar nav a{color:var(--ink-2);font-weight:500}
.sidebar nav a:hover{background:var(--brand-050);color:var(--brand-d)}
.sidebar nav a.active{background:var(--brand-050);color:var(--brand-d);box-shadow:none;font-weight:650}
.sidebar nav a.active .ic{color:var(--brand);opacity:1}
.sidebar nav a .ic{opacity:.75}
.nav-group{color:var(--muted-2)}
.side-foot{color:var(--muted-2);border-top:1px solid var(--line)}
/* §7 collapsible sidebar: header row with a collapse toggle; collapsed = icon-only + tooltips. */
.side-head{display:flex;align-items:center;justify-content:space-between;gap:6px}
.sidebar-collapse{display:inline-flex;align-items:center;justify-content:center;width:30px;height:30px;border:1px solid var(--line);border-radius:8px;background:#fff;color:var(--muted);cursor:pointer}
.sidebar-collapse:hover{background:var(--brand-050);color:var(--brand-d)}
@media (min-width:901px){
  .app.sidebar-collapsed{grid-template-columns:64px 1fr}
  .app.sidebar-collapsed .sidebar{padding:14px 8px;align-items:stretch}
  .app.sidebar-collapsed .sidebar .brand-name,
  .app.sidebar-collapsed .sidebar nav a span,
  .app.sidebar-collapsed .nav-group,
  .app.sidebar-collapsed .side-foot,
  .app.sidebar-collapsed .sidebar .count-badge,
  .app.sidebar-collapsed .tenant-switch{display:none}
  .app.sidebar-collapsed .sidebar nav a{justify-content:center;padding:10px 0}
  /* §13 collapsed rail (64px): stack a compact square logo MARK (left-crop of the wordmark) above the toggle so
     neither is squashed and they never overlap. */
  .app.sidebar-collapsed .side-head{justify-content:center;flex-direction:column;gap:8px}
  .app.sidebar-collapsed .sidebar .brand{justify-content:center;padding:2px 0 10px}
  .app.sidebar-collapsed .sidebar .brand-logo{width:44px;height:44px;object-position:left center;border-radius:8px}
}
@media (max-width:900px){ .sidebar-collapse{display:none} }

/* ---- UI04 dashboard: time filter, connection KPIs, no-data cards, by-channel chart ---- */
.dash-timefilter{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-left:auto}
.dash-timefilter select,.dash-timefilter input[type="date"]{padding:7px 9px;border:1px solid #cfd6dd;border-radius:9px;font:inherit;background:#fff}
.dash-h{margin:18px 0 8px;font-size:var(--fs-14);color:var(--muted);font-weight:700;letter-spacing:.04em;text-transform:uppercase}
.cards-compact{display:grid;grid-template-columns:repeat(auto-fill,minmax(150px,1fr));gap:12px}
.conn-card .card-v{font-size:var(--fs-22)}
.card-nodata{opacity:.85}
.card-nodata .card-v{color:var(--muted-2)}
.chart{display:flex;flex-direction:column;gap:8px}
.chart-row{display:flex;align-items:center;gap:10px}
.chart-lbl{display:inline-flex;align-items:center;gap:6px;min-width:150px;font-size:var(--fs-13);color:var(--ink-2)}
.chart-bar{flex:1;height:12px;background:var(--line-2,#eef2f7);border-radius:999px;overflow:hidden}
.chart-fill{display:block;height:100%;background:linear-gradient(90deg,var(--brand),#7c3aed);border-radius:999px}
.chart-val{min-width:36px;text-align:right;font-weight:700;font-size:var(--fs-13)}

/* ================= CHOTSALE-UI04 — persistent unified inbox workspace ================= */
/* §16-17: the inbox page runs full-width/height so the queue + thread + context fit as panes. */
.content-inbox{max-width:none;padding:0}
.inbox-ws{display:grid;grid-template-columns:340px minmax(0,1fr);gap:0;height:calc(100vh - 56px);min-height:480px}
.inbox-queue{border-right:1px solid var(--line);overflow:auto;background:#fff;padding:12px 12px 8px}
.inbox-thread{overflow:hidden;display:flex;flex-direction:column;min-width:0;background:var(--bg)}
.inbox-thread .cw{height:100%}
.inbox-thread-empty{margin:auto;text-align:center;color:var(--muted);padding:40px;display:flex;flex-direction:column;align-items:center;gap:10px}
.inbox-thread-empty .ic{width:40px;height:40px;opacity:.5}
/* §18-20 compact queue rows (~60px): avatar + name/time + preview + meta. Many visible without scrolling. */
.q-panel{padding:0;border:0;box-shadow:none;background:transparent}
.q-list{display:flex;flex-direction:column}
.q-row{display:flex;gap:10px;align-items:flex-start;padding:9px 10px;border-radius:10px;color:inherit;border:1px solid transparent;transition:background .12s ease,border-color .12s ease}
.q-row:hover{background:var(--brand-050);text-decoration:none}
.q-row.is-active{background:var(--brand-050);border-color:var(--brand-100)}
.q-row.conv-needs{box-shadow:inset 3px 0 0 var(--warn,#d97706)}
.q-avatar{flex:0 0 auto;width:34px;height:34px;border-radius:50%;background:var(--brand-050);color:var(--brand-d);display:flex;align-items:center;justify-content:center;font-weight:600;font-size:13px;text-transform:uppercase}
.q-body{min-width:0;flex:1;display:flex;flex-direction:column;gap:2px}
.q-line1{display:flex;align-items:baseline;gap:8px}
.q-name{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-weight:600;color:var(--ink)}
.q-row.conv-needs .q-name{font-weight:750}
.q-time{flex:0 0 auto;font-size:var(--fs-11)}
.q-prev{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:100%}
.q-meta{display:flex;align-items:center;gap:6px;flex-wrap:wrap;margin-top:2px}
.q-meta .chan-tag{font-size:var(--fs-12)}
.q-meta .src-name{max-width:14ch}
/* CORR-01 §2-4: minimal queue row — preview + channel icon on line 2; compact "● Cần trả lời" signal, no big badges. */
.q-line2{display:flex;align-items:center;gap:8px;justify-content:space-between;min-width:0}
.q-line2 .q-prev{flex:1;display:flex;align-items:center;gap:6px}
.q-chan{flex:0 0 auto;display:inline-flex;color:var(--muted,#6b7280)}
.q-chan .ic{width:14px;height:14px}
.q-sig{flex:0 0 auto;display:flex;align-items:center;gap:6px}
.q-sig .badge.red{padding:0 6px;font-size:var(--fs-11);min-width:16px;text-align:center}
.q-needs{display:inline-flex;align-items:center;gap:4px;font-size:var(--fs-11);color:var(--warn,#b45309);white-space:nowrap;font-weight:600}
.q-needs .q-dot{width:6px;height:6px;border-radius:50%;background:var(--warn,#d97706);flex:0 0 auto}
.q-labels{font-size:var(--fs-11)}
.q-assignee{display:inline-flex;color:var(--muted)}
.q-assignee .ic{width:14px;height:14px}
/* UI04-CORR-01 §7-12 infinite queue loading: the JS path hides the numeric pager and shows a small bottom spinner. */
.cc-js .inbox-queue .pager{display:none}
.q-more{display:flex;align-items:center;justify-content:center;gap:8px;padding:12px;color:var(--muted);font-size:var(--fs-12)}
.q-more[hidden]{display:none}
.q-more-spin{width:14px;height:14px;border:2px solid var(--line-2,#e5e7eb);border-top-color:var(--brand,#4f46e5);border-radius:50%;animation:q-spin .7s linear infinite}
@keyframes q-spin{to{transform:rotate(360deg)}}
.q-row.is-leaving{opacity:0;transform:translateX(8px);transition:opacity .18s ease,transform .18s ease}
/* §13-16 thread pane swap loading hint (does not blank the previous thread). */
.inbox-thread.is-loading{position:relative}
.inbox-thread.is-loading::after{content:"";position:absolute;inset:0;background:rgba(255,255,255,.35)}
@media (prefers-reduced-motion:reduce){.q-more-spin{animation:none}.q-row.is-leaving{transition:none}}
/* In the narrow queue the top filter bar stays usable; the channel tabs scroll horizontally. */
.inbox-queue .channel-switcher{flex-wrap:nowrap;overflow-x:auto}
.inbox-queue .filter-bar-modern{gap:6px}
/* UI04-CORR-03 §5-13 COMPACT queue controls (Workspace Mode). Vertical stack — NO horizontal overflow (§11). */
.qc-bar{display:flex;flex-direction:column;align-items:stretch;gap:8px;margin:0 0 10px}
.qc-search{width:100%}
.qc-search input{width:100%;box-sizing:border-box}
.qc-row{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.qc-row>.qc-chan{flex:1 1 auto;min-width:0}
.qc-row>.qc-adv{flex:0 0 auto}
.qc-chan-sum{width:100%;justify-content:flex-start;gap:7px;overflow:hidden}
.qc-chan-sum .ct-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1 1 auto;text-align:left}
.qc-chan-sum .ic:last-child{opacity:.6;flex:0 0 auto}
.qc-chan-pop{min-width:220px;padding:6px;display:flex;flex-direction:column;gap:2px}
.qc-chan-item{display:flex;align-items:center;gap:8px;padding:7px 9px;border-radius:9px;color:var(--ink-2);text-decoration:none}
.qc-chan-item:hover{background:var(--brand-050)}
.qc-chan-item.is-active{background:var(--brand-050);color:var(--brand-d);font-weight:650}
.qc-chan-item .ct-count{margin-left:auto}
/* the Bộ lọc popover stacks its selects/chips vertically (it is re-anchored fixed by cc.js placeMenu) */
.qc-adv-pop{min-width:250px;display:flex;flex-direction:column;gap:8px;padding:10px}
.qc-adv-pop>div{display:flex;flex-direction:column;gap:3px}
.qc-adv-pop label{font-size:var(--fs-12);color:var(--muted)}
.qc-adv-pop select,.qc-adv-pop input[type=date]{width:100%;padding:7px 9px;border:1px solid #cfd6dd;border-radius:9px;font:inherit;background:#fff}
.qc-adv-pop .fb-time,.qc-adv-pop .fb-source{flex-direction:row;flex-wrap:wrap;align-items:center}
.qc-adv-pop .fb-source select,.qc-adv-pop .fb-time select{max-width:none}
.qc-chips{flex-direction:row!important;flex-wrap:wrap;gap:6px}
.qc-summary{padding:0 2px}
@media (min-width:1280px){.qc-row{flex-wrap:nowrap}}
@media (max-width:1100px){
  /* tablet: queue + thread; the customer context becomes the cw detail drawer (already slide-in). */
  .inbox-ws{grid-template-columns:300px minmax(0,1fr)}
}
@media (max-width:760px){
  /* mobile: one pane at a time — show the thread if a conversation is selected, else the queue. */
  .inbox-ws{grid-template-columns:1fr;height:auto}
  .inbox-ws[data-has-thread] .inbox-queue{display:none}
  .inbox-queue{border-right:0}
  /* CHOTSALE-MOBILE-CHAT-UX-01 §B — ROOT-CAUSE FIX. The mobile workspace was `height:auto`, so `.inbox-thread .cw{height:100%}`
     resolved 100% against an auto-height ancestor and COLLAPSED `.cw` to content height → the timeline could not scroll
     internally and the WHOLE PAGE scrolled, burying the composer beneath a long history. Pin the open conversation as a
     viewport-sized chat surface so ONLY `.cw-timeline` scrolls and `.cw-composer` stays at the bottom. cc.js refines
     top/left/width/height from visualViewport (keyboard-aware); this rule is the no-JS fallback. Desktop (>760px) untouched. */
  .inbox-ws[data-has-thread]{min-height:0}
  .cw[data-cw]{position:fixed;left:0;right:0;top:0;width:100%;height:100dvh;max-height:100dvh;min-height:0;border:0;border-radius:0;z-index:30}
  .cw-body,.cw-main,.cw-timeline{min-height:0}
  /* §B8 responsive action bar — keep every control usable on a narrow screen: the attach row scrolls horizontally while the
     primary Send (and AI) stay pinned and always tappable. No control is shrunk to unreadable; nothing is removed. */
  .cw-composer{padding:8px 10px}
  .cw-toolbar{gap:6px}
  .cw-tools{flex:1 1 0;min-width:0;flex-wrap:nowrap;overflow-x:auto;-webkit-overflow-scrolling:touch;scrollbar-width:none}
  .cw-tools::-webkit-scrollbar{display:none}
  .cw-tools .cw-attach{flex:0 0 auto}
  .cw-actions-r{flex:0 0 auto;gap:6px;margin-left:6px}
}
/* CHOTSALE-MOBILE-CHAT-UX-01 §B: while a mobile conversation is pinned (fixed) the page behind must not scroll (cc.js sets
   the flag; removed on desktop / when returning to the list). */
html[data-cw-fixed]{overflow:hidden}
/* AI-FOUNDATION-01 §B: a read-only value display (business name / lead fields sourced from Knowledge). */
.ro-field{padding:9px 12px;border:1px dashed var(--line,#e5e7eb);border-radius:8px;background:var(--bg,#f6f8fa);color:var(--ink,#0f172a);min-height:20px}
/* AI Config header: compact status chip + compact one-line safety note (plain flow → bold never splits into columns). */
.ai-status{margin:2px 0 8px}
.ai-safety{margin:0 0 14px;padding:8px 12px;border:1px solid var(--brand-100,#e0e7ff);border-radius:8px;background:var(--brand-050,#eff6ff);color:var(--ink-2,#334155);font-size:13px;line-height:1.5}
.ai-safety strong{color:var(--ink,#0f172a)}
@media (max-width:420px){
  /* very narrow: collapse the AI button to its icon so the primary Send is never pushed off-screen (function preserved). */
  .cw-ai .cw-ai-label{display:none}
  .cw-ai{padding-left:9px;padding-right:9px}
}
/* UI04-CORR-02 §3-5 LIST MODE — full-width overview list (no thread/context panes until a conversation is selected). */
.inbox-list-mode{padding:14px 20px 8px}
.ov-panel{padding:0;border:0;box-shadow:none;background:transparent}
.ov-head{display:grid;grid-template-columns:minmax(0,2.4fr) 1.3fr 1.1fr 1.1fr 96px;gap:14px;padding:6px 12px;color:var(--muted);font-size:var(--fs-12);font-weight:600;border-bottom:1px solid var(--line)}
.ov-scroll{max-height:calc(100vh - 208px);overflow:auto}
.ov-list{display:flex;flex-direction:column}
.ov-row{display:grid;grid-template-columns:minmax(0,2.4fr) 1.3fr 1.1fr 1.1fr 96px;gap:14px;align-items:center;padding:9px 12px;border-bottom:1px solid var(--line);color:inherit;transition:background .12s ease}
.ov-row:hover{background:var(--brand-050);text-decoration:none}
.ov-row.is-active{background:var(--brand-050)}
.ov-row.conv-needs{box-shadow:inset 3px 0 0 var(--warn,#d97706)}
.ov-cust{display:flex;gap:10px;align-items:center;min-width:0}
.ov-avatar{flex:0 0 auto;width:34px;height:34px;border-radius:50%;background:var(--brand-050);color:var(--brand-d);display:flex;align-items:center;justify-content:center}
.ov-cust-body{min-width:0;display:flex;flex-direction:column;gap:2px}
.ov-line1{display:flex;align-items:center;gap:8px;min-width:0}
.ov-name{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-weight:600;color:var(--ink)}
.ov-row.conv-needs .ov-name{font-weight:750}
.ov-prev{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ov-source,.ov-assign,.ov-status{min-width:0;overflow:hidden}
.ov-source .chan-tag{font-size:var(--fs-12)}
.ov-source .src-name{max-width:18ch}
.ov-time{text-align:right;white-space:nowrap}
.inbox-return{display:inline-flex;align-items:center;gap:6px;margin:0 0 10px;padding:6px 11px;border:1px solid var(--line);border-radius:var(--r-pill,999px);background:#fff;color:var(--ink-2);text-decoration:none;font-size:var(--fs-13);font-weight:600}
.inbox-return:hover{background:var(--brand-050);border-color:var(--brand-100);color:var(--brand-d)}
.inbox-return .ic{width:15px;height:15px}
@media (max-width:1100px){
  .ov-head{grid-template-columns:minmax(0,2.4fr) 1.2fr 1fr 84px}
  .ov-row{grid-template-columns:minmax(0,2.4fr) 1.2fr 1fr 84px}
  .ov-head span:nth-child(3),.ov-assign{display:none}
}
@media (max-width:720px){
  .ov-head{display:none}
  .ov-row{grid-template-columns:minmax(0,1fr) auto;gap:8px;padding:10px 12px}
  .ov-source,.ov-status{display:none}
  .inbox-list-mode{padding:10px 12px}
}

/* STAFF-CHANNEL-ACL-01 — the business-facing "no permission" screen (rendered in the bare shell). Centered, responsive. */
.cc-denied{max-width:440px;margin:0 auto;text-align:center;padding:8px}
.cc-denied .brand.big{justify-content:center;margin-bottom:8px}
.cc-denied-ico{font-size:44px;line-height:1;margin:6px 0}
.cc-denied h1{font-size:20px;margin:6px 0}
.cc-denied-actions{display:flex;gap:10px;justify-content:center;flex-wrap:wrap;margin-top:16px}
.cc-denied-actions .btn{min-width:120px;justify-content:center}
@media (max-width:480px){.cc-denied-actions{flex-direction:column}.cc-denied-actions .btn{width:100%}}

/* STAFF-CHANNEL-ACL-01 — the channel-first staff permission editor (accordion of channel cards + account pickers). */
.acl-all{display:flex;align-items:center;gap:8px;padding:10px 12px;border:1px solid var(--line-2,#e5e7eb);border-radius:10px;background:#fafbfc;font-weight:600;margin-bottom:10px}
.acl-chan{border:1px solid var(--line-2,#e5e7eb);border-radius:10px;margin-bottom:8px;overflow:hidden}
.acl-chan-head{display:flex;align-items:center;gap:10px;padding:10px 12px;background:#fff}
.acl-chan-head .acl-chan-name{font-weight:600;flex:1 1 auto;min-width:0}
.acl-chan-head .acl-count{font-size:12px;color:var(--muted,#6b7280)}
.acl-chan-body{padding:6px 12px 12px;border-top:1px solid var(--line-2,#eef2f7);background:#fafbfc}
.acl-chan[data-acl-off] .acl-chan-body{display:none}
.acl-mode{display:flex;gap:14px;flex-wrap:wrap;margin:6px 0 8px}
.acl-mode label{display:inline-flex;align-items:center;gap:6px}
.acl-accounts{display:none;flex-direction:column;gap:2px;max-height:280px;overflow-y:auto}
.acl-chan[data-acl-mode="pick"] .acl-accounts{display:flex}
.acl-search{width:100%;box-sizing:border-box;margin:4px 0 8px;padding:8px 10px;border:1px solid var(--line-2,#e5e7eb);border-radius:8px}
.acl-acc{display:flex;align-items:center;gap:8px;padding:6px 8px;border-radius:8px}
.acl-acc:hover{background:var(--brand-050,#eff6ff)}
.acl-acc .acl-acc-name{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.acl-acc.is-off{opacity:.55}
.acl-acc-tools{display:flex;gap:8px;margin:4px 0}
.acl-acc-tools .btn.xs{font-size:12px}
.acl-selcount{font-size:12px;color:var(--brand-d,#1d4ed8);margin-left:auto}
@media (max-width:600px){.acl-accounts{max-height:220px}}
.acl-pick{display:none}
.acl-chan[data-acl-mode="pick"] .acl-pick{display:block}
.acl-channels[hidden]{display:none}

/* WIDGET-PRO-01 — appearance template picker cards (admin). Samples adopt the widget's primary color via --wc. */
.wtpl-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(140px,1fr));gap:10px;margin:6px 0}
.wtpl-card{position:relative;display:flex;flex-direction:column;gap:6px;align-items:center;padding:10px;border:2px solid var(--line-2,#e5e7eb);border-radius:12px;cursor:pointer;background:#fff;transition:border-color .12s,box-shadow .12s}
.wtpl-card:hover{border-color:var(--wc,#4f46e5)}
.wtpl-card.is-on{border-color:var(--wc,#4f46e5);box-shadow:0 0 0 3px color-mix(in srgb,var(--wc,#4f46e5) 20%,transparent)}
.wtpl-card input{position:absolute;opacity:0;pointer-events:none}
.wtpl-name{font-size:12px;font-weight:600;color:var(--ink-2,#374151)}
.wtpl-sample{display:flex;align-items:center;justify-content:center;width:100%;height:52px}
/* button samples */
.wtpl-btn{gap:6px;color:#fff;font:600 12px system-ui}
.wtpl-btn .wtpl-ic{width:16px;height:16px;border-radius:50%;background:currentColor;opacity:.9;flex:0 0 auto}
.wtpl-btn--round,.wtpl-btn--round_badge{background:var(--wc);border-radius:50%;width:40px;height:40px;color:#fff}
.wtpl-btn--round .wtpl-tx,.wtpl-btn--round_badge .wtpl-tx{display:none}
.wtpl-btn--round .wtpl-ic,.wtpl-btn--round_badge .wtpl-ic{background:#fff}
.wtpl-btn--round_badge::after{content:"3";position:absolute;top:14px;right:44px;background:#e11d48;color:#fff;font:700 9px/14px system-ui;min-width:14px;height:14px;border-radius:7px;text-align:center}
.wtpl-btn--pill{background:var(--wc);border-radius:16px;padding:8px 12px}
.wtpl-btn--pill .wtpl-ic{background:#fff}
.wtpl-btn--pill_light{background:#fff;border:1px solid #e5e7eb;border-radius:16px;padding:7px 12px;color:#111}
.wtpl-btn--pill_light .wtpl-ic{background:var(--wc)}
.wtpl-btn--assistant{background:#fff;border:2px solid var(--wc);border-radius:12px;padding:6px 12px;color:#111}
.wtpl-btn--assistant .wtpl-ic{background:var(--wc)}
.wtpl-btn--support{background:var(--wc);border-radius:12px;padding:8px 12px}
.wtpl-btn--support .wtpl-ic{background:#fff}
/* chat window samples */
.wtpl-chat{flex-direction:column;width:64px;height:52px;border:1px solid #e5e7eb;border-radius:8px;overflow:hidden;background:#f6f8fa}
.wtpl-chat-head{height:14px;background:var(--wc)}
.wtpl-chat-body{flex:1;padding:4px;display:flex;flex-direction:column;gap:3px}
.wtpl-b{height:6px;border-radius:4px}
.wtpl-b.a{width:70%;background:#fff;border:1px solid #e5e7eb}
.wtpl-b.u{width:55%;align-self:flex-end;background:var(--wc)}
.wtpl-chat--modern{border-radius:12px}
.wtpl-chat--modern .wtpl-b{border-radius:6px}
.wtpl-chat--compact{width:54px;height:46px}
.wtpl-chat--assistant .wtpl-chat-head{background:linear-gradient(135deg,var(--wc),rgba(0,0,0,.2))}
/* create-success callout on the widget list */
.wgt-created{border:1px solid var(--ok,#16a34a);background:#f0fdf4;border-radius:12px;padding:12px 14px;margin-bottom:12px;display:flex;flex-wrap:wrap;align-items:center;gap:10px}
.wgt-created strong{font-size:15px}
tr.is-created{background:#f0fdf4}
tr.is-created td:first-child{box-shadow:inset 3px 0 0 var(--ok,#16a34a)}

/* ==== CHOTSALE-AI-CORE-V2.4.1 — Knowledge dashboard counters (§G) + import review cards (§A) ==== */
.kv-counters{display:flex;flex-wrap:wrap;gap:8px;margin:0 0 10px}
.kv-counter{display:inline-flex;flex-direction:column;align-items:flex-start;min-width:96px;padding:8px 12px;border:1px solid var(--line,#e5e7eb);border-radius:10px;background:#fff;text-decoration:none;color:inherit;transition:border-color .12s,box-shadow .12s}
.kv-counter:hover{border-color:#c7cdd6}
.kv-counter.is-active{border-color:var(--brand,#2563eb);box-shadow:inset 0 -2px 0 var(--brand,#2563eb)}
.kv-counter .kv-c-n{font-size:20px;font-weight:700;line-height:1.1}
.kv-counter .kv-c-l{font-size:12px;color:#64748b}
.kv-counter.ok .kv-c-n{color:var(--ok,#16a34a)}
.kv-counter.warn .kv-c-n{color:var(--warn,#d97706)}
.kv-src{margin:-4px 0 10px}
.kv-allbar{margin-bottom:10px}
.kv-selcount{margin-left:6px}
.kv-group{padding:0;overflow:hidden}
.kv-group-head{display:flex;flex-wrap:wrap;align-items:center;gap:8px 14px;padding:12px 14px;border-bottom:1px solid var(--line,#e5e7eb);background:#f8fafc}
.kv-group-title{display:flex;align-items:center;gap:8px;font-size:15px}
.kv-group-meta{flex:1 1 auto}
.kv-group-actions{display:flex;gap:6px;flex-shrink:0}
.kv-cards{display:flex;flex-direction:column}
/* V2.4.2 — card = [pick label | destination override controls] */
.kv-card{display:grid;grid-template-columns:1fr minmax(210px,300px);align-items:start;gap:12px;padding:12px 14px;border-top:1px solid #f1f5f9}
.kv-card:first-child{border-top:0}
.kv-card:hover{background:#fafbfc}
.kv-card-pick{display:grid;grid-template-columns:28px 1fr;align-items:start;gap:10px;min-width:0;cursor:pointer}
.kv-card-check{padding-top:2px}
.kv-card-main{display:flex;flex-direction:column;gap:3px;min-width:0}
.kv-card-title{display:flex;flex-wrap:wrap;align-items:center;gap:6px}
.kv-card-excerpt{overflow:hidden;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}
.kv-card-src{word-break:break-all}
.kv-card-target{text-align:right;white-space:normal}
.kv-card-conflict{margin-top:4px}
/* V2.4.2 — Owner target-override controls */
.kv-card-dest{display:flex;flex-direction:column;gap:6px;min-width:0}
.kv-dest-field{display:flex;flex-direction:column;gap:2px;margin:0}
.kv-dest-lbl{font-size:11px;color:#64748b;font-weight:600}
.kv-card-dest select,.kv-card-dest input,.kv-group-bulk select,.kv-group-bulk input{width:100%;max-width:100%;font-size:13px;padding:5px 8px;box-sizing:border-box}
.kv-dest-ai{font-style:italic}
.is-hidden{display:none!important}
.kv-group-bulk{display:flex;flex-wrap:wrap;align-items:center;gap:8px;padding:8px 14px;border-bottom:1px solid var(--line,#e5e7eb);background:#fbfdff}
.kv-group-bulk select{width:auto;min-width:150px}
.kv-group-bulk input{width:auto;min-width:150px}
@media(max-width:640px){
  .kv-card{grid-template-columns:1fr;gap:10px}
  .kv-card-dest{border-top:1px dashed #e5e7eb;padding-top:8px}
  .kv-counter{min-width:78px;padding:6px 10px}
  .kv-counter .kv-c-n{font-size:17px}
  .kv-group-bulk select,.kv-group-bulk input{width:100%;min-width:0}
}

/* ==== CHOTSALE-PRODUCT-CATALOG-V1 — catalog form ==== */
.cat-sec{margin:18px 0 6px;font-size:14px;font-weight:700;border-top:1px solid var(--line,#e5e7eb);padding-top:12px}
.cat-radios{display:flex;gap:16px;margin-bottom:8px}
.cat-radio{display:inline-flex;align-items:center;gap:6px;font-weight:500}
.cat-2col{display:grid;grid-template-columns:1fr 1fr;gap:12px}
.cat-3col{display:grid;grid-template-columns:1fr 1fr 1fr;gap:12px}
.cat-row{display:grid;grid-template-columns:1fr 1fr 1fr 1fr auto;gap:8px;align-items:center;margin-bottom:8px}
.cat-row input{margin:0}
.cat-row .btn.xs{padding:4px 8px}
[data-cat-repeat="attr"] .cat-row{grid-template-columns:1fr 1fr auto}
@media(max-width:640px){ .cat-2col,.cat-3col,.cat-row{grid-template-columns:1fr} .cat-row .btn.xs{justify-self:start} }

/* ==== CHOTSALE-PRODUCT-CATALOG-V1-CORR-01 — category quick-management modal ==== */
.cat-modal{position:fixed;inset:0;z-index:60;display:flex;align-items:center;justify-content:center}
.cat-modal[hidden]{display:none}
.cat-modal-backdrop{position:absolute;inset:0;background:rgba(15,23,42,.42)}
.cat-modal-box{position:relative;background:#fff;border-radius:12px;padding:16px;width:min(440px,92vw);max-height:85vh;overflow:auto;box-shadow:0 12px 44px rgba(0,0,0,.22)}
.cat-modal-head{display:flex;justify-content:space-between;align-items:center;margin-bottom:10px}
/* stacked label → field with breathing room; rounded fields consistent with the rest of this ticket's inputs */
.cat-modal-box label{display:block;font-weight:600;font-size:13px;color:#334155;margin:12px 0 5px}
.cat-modal-box label:first-of-type{margin-top:2px}
[data-cat-modal="newcat"] input[type=text],[data-cat-modal="newcat"] select,.cat-create-row input,.cat-create-row select{box-sizing:border-box;padding:9px 11px;border:1px solid #d7dde5;border-radius:8px;font-size:14px;background:#fff}
[data-cat-modal="newcat"] input[type=text],[data-cat-modal="newcat"] select{width:100%;display:block}
.cat-create-row{display:flex;gap:8px;margin-bottom:6px}
.cat-create-row input{flex:1;min-width:0}
.cat-modal-msg{min-height:16px;margin:2px 0 4px}
.cat-mlist{list-style:none;margin:8px 0 0;padding:0}
.cat-mi{display:flex;align-items:center;gap:8px;padding:8px 0;border-top:1px solid #f1f5f9}
.cat-mi-name{flex:1;min-width:0;display:flex;gap:6px;align-items:center}
.cat-mi-name input{flex:1;min-width:0}
.cat-mi.is-inactive .cat-mi-name{color:#94a3b8;text-decoration:line-through}
.cat-mi.is-child{padding-left:22px;position:relative}
.cat-mi.is-child::before{content:"└";position:absolute;left:6px;color:#cbd5e1}
.cat-create-row select{max-width:44%;min-width:0}
.cat-mi-actions{display:flex;gap:6px;flex-shrink:0}
.cat-inline-add{margin-left:6px;vertical-align:middle;font-weight:500}
/* V1.1 — inline per-row status action (Đưa vào sử dụng / Ngừng sử dụng); CSP-safe POST form, no inline JS */
.cat-rowform{display:inline}
.cat-row-actions{white-space:nowrap}
.cat-row-actions .btn{margin-left:4px}
@media(max-width:640px){ .cat-modal-box{width:94vw;padding:12px} .cat-mi{flex-wrap:wrap} .cat-mi-actions{width:100%} }

/* ===== CHOTSALE-WEBSITE-VISITOR-INTELLIGENCE-V1 (R-P11) — "Theo dõi" live visitor intelligence ===== */
.trk{display:flex;flex-direction:column;gap:16px}
.trk-counters{display:flex;flex-wrap:wrap;gap:12px;padding:16px}
.trk-counter{flex:1 1 120px;min-width:110px;display:flex;flex-direction:column;align-items:flex-start;gap:2px;padding:12px 14px;background:var(--brand-050);border:1px solid var(--line);border-radius:var(--r-sm)}
.trk-c-num{font-size:var(--fs-28);font-weight:800;line-height:1;color:var(--ink)}
.trk-c-lbl{font-size:var(--fs-12);color:var(--muted);font-weight:600}
.trk-filter-panel{padding:14px 16px}
.trk-filters{display:flex;flex-wrap:wrap;gap:12px;align-items:flex-end}
.trk-fl{display:flex;flex-direction:column;gap:4px;font-size:var(--fs-11);color:var(--muted);font-weight:600}
.trk-fl select{font:var(--fs-13)/1.3 var(--f-sans);padding:7px 10px;border:1px solid var(--line);border-radius:var(--r-sm);background:var(--card);color:var(--ink);min-width:150px}
.trk-live{display:inline-flex;align-items:center;gap:6px;margin-left:auto;font-size:var(--fs-12);color:var(--ok);font-weight:600}
.trk-live-dot{width:8px;height:8px;border-radius:50%;background:var(--ok-dot);animation:trkpulse 1.6s ease-in-out infinite}
@keyframes trkpulse{0%,100%{opacity:1;transform:scale(1)}50%{opacity:.4;transform:scale(.7)}}
.trk-layout{display:grid;grid-template-columns:minmax(280px,380px) 1fr;gap:16px;align-items:start}
.trk-list{padding:8px;max-height:calc(100dvh - 260px);overflow-y:auto}
.trk-rows{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:4px}
.trk-row{width:100%;display:flex;gap:10px;align-items:flex-start;text-align:left;background:none;border:1px solid transparent;border-radius:var(--r-sm);padding:10px;cursor:pointer;font:inherit;color:var(--ink)}
.trk-row:hover{background:var(--brand-050)}
.trk-row.is-active{background:var(--brand-050);border-color:var(--brand-100)}
.trk-dot{width:9px;height:9px;border-radius:50%;flex:0 0 auto;margin-top:5px;background:var(--off-dot)}
.trk-dot.is-online{background:var(--ok-dot);box-shadow:0 0 0 3px var(--ok-bg)}
.trk-dot.is-off{background:var(--off-dot)}
.trk-row-main{display:flex;flex-direction:column;gap:2px;min-width:0;flex:1}
.trk-row-top{display:flex;flex-wrap:wrap;align-items:center;gap:6px}
.trk-row-cur{font-size:var(--fs-13);color:var(--ink-2);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:100%}
.trk-row-meta{font-size:var(--fs-12)}
.trk-chip{display:inline-block;font-size:var(--fs-11);font-weight:600;padding:2px 8px;border-radius:var(--r-pill);background:var(--brand-050);color:var(--brand-d);border:1px solid var(--brand-100)}
.trk-chip.is-chat{background:var(--ok-bg);color:var(--ok);border-color:transparent}
.trk-chip.is-muted{background:var(--off-bg);color:var(--off);border-color:transparent}
.trk-chip.is-cat{background:var(--warn-bg);color:var(--warn);border-color:transparent}
a.trk-chip{text-decoration:none}
.trk-detail{padding:18px;min-height:280px}
.trk-detail-empty{padding:48px 20px}
.trk-detail-head{display:flex;align-items:center;gap:10px;margin-bottom:14px;padding-bottom:12px;border-bottom:1px solid var(--line)}
.trk-back{display:none;background:none;border:1px solid var(--line);border-radius:var(--r-sm);padding:6px 10px;font:inherit;font-size:var(--fs-13);color:var(--ink-2);cursor:pointer}
.trk-dh-title{display:flex;flex-direction:column;gap:2px}
.trk-dh-title b{font-size:var(--fs-16)}
.trk-dh-status{font-size:var(--fs-12);color:var(--muted);display:inline-flex;align-items:center;gap:6px}
.trk-kvs{display:grid;grid-template-columns:1fr 1fr;gap:8px 16px;margin-bottom:14px}
.trk-kv{display:flex;flex-direction:column;gap:1px;min-width:0}
.trk-k{font-size:var(--fs-11);color:var(--muted);font-weight:600}
.trk-v{font-size:var(--fs-13);color:var(--ink);word-break:break-word}
.trk-sec{margin-top:14px}
.trk-sec h4{margin:0 0 8px;font-size:var(--fs-13);color:var(--ink-2)}
.trk-interest{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:4px;font-size:var(--fs-13)}
.trk-journey{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:0;position:relative}
.trk-jv{display:flex;gap:12px;padding:7px 0;border-left:2px solid var(--line);padding-left:14px;margin-left:6px;position:relative}
.trk-jv::before{content:"";position:absolute;left:-5px;top:12px;width:8px;height:8px;border-radius:50%;background:var(--brand);border:2px solid var(--card)}
.trk-jv.is-evt::before{background:var(--ok-dot)}
.trk-jt{font-size:var(--fs-12);color:var(--muted);flex:0 0 42px;font-variant-numeric:tabular-nums}
.trk-jl{font-size:var(--fs-13);color:var(--ink);min-width:0}
.trk-cur-note{margin-top:8px}
@media(max-width:900px){
  .trk-layout{grid-template-columns:1fr}
  .trk-list{max-height:none}
  .trk-detail{display:none}
  .trk.trk-show-detail .trk-list{display:none}
  .trk.trk-show-detail .trk-detail{display:block}
  .trk-back{display:inline-block}
  .trk-kvs{grid-template-columns:1fr}
  .trk-fl select{min-width:0;width:100%}
  .trk-fl{flex:1 1 140px}
  .trk-live{width:100%;margin-left:0;justify-content:flex-start}
}
@media(max-width:420px){ .trk-counter{flex:1 1 45%} .trk-c-num{font-size:var(--fs-22)} }

/* WIDGET-V2 §17 — compact website-context card in the Inbox conversation detail */
.cw-wc{margin:0 0 12px;padding:12px;border:1px solid var(--line);border-radius:var(--r-sm);background:var(--brand-050)}
.cw-wc h4{margin:0 0 8px;font-size:var(--fs-13);color:var(--ink-2)}
.cw-wc-row{display:flex;justify-content:space-between;gap:10px;font-size:var(--fs-12);padding:3px 0;align-items:baseline}
.cw-wc-row>span{color:var(--muted);flex:0 0 auto}
.cw-wc-row>b{text-align:right;min-width:0;word-break:break-word;font-weight:600;color:var(--ink)}
.cw-wc-link{margin-top:8px}

/* PROACTIVE-CHAT-V1 — staff proactive action in the Theo dõi visitor detail */
.trk-pro{margin:0 0 14px}
.trk-pro-view,.trk-pro-start{display:inline-flex;align-items:center;gap:6px}
.trk-pro-box{margin-top:10px;padding:12px;border:1px solid var(--line);border-radius:var(--r-sm);background:var(--brand-050)}
.trk-pro-box p{margin:0 0 8px}
.trk-pro-msg{width:100%;box-sizing:border-box;border:1px solid var(--line);border-radius:var(--r-sm);padding:8px 10px;font:var(--fs-13)/1.5 var(--f-sans);resize:vertical;min-height:60px;background:var(--card);color:var(--ink)}
.trk-pro-actions{display:flex;justify-content:flex-end;gap:8px;margin-top:8px}
.trk-pro-status{margin-top:8px;font-size:var(--fs-12);color:var(--ok);min-height:16px}
.trk-pro-blocked{display:inline-block}

/* VISITOR-LIVE-DASHBOARD-V1 — Tab 1 "Tổng quan trực tuyến" */
.trk-tabs{display:flex;gap:4px;margin:0 0 16px;border-bottom:1px solid var(--line)}
.trk-tab{appearance:none;background:none;border:none;border-bottom:2px solid transparent;padding:10px 14px;font:600 var(--fs-14)/1.2 var(--f-sans);color:var(--muted);cursor:pointer}
.trk-tab:hover{color:var(--ink)}
.trk-tab.is-active{color:var(--brand-d);border-bottom-color:var(--brand-d)}
.dash-counters{display:flex;flex-wrap:wrap;gap:12px;padding:16px;margin-bottom:16px}
.dash-counter{flex:1 1 110px;display:flex;flex-direction:column;gap:2px;position:relative}
.dash-c-num{font-size:var(--fs-26);font-weight:700;color:var(--ink);font-variant-numeric:tabular-nums}
.dash-c-lbl{font-size:var(--fs-12);color:var(--muted)}
.dash-c-big{font-size:var(--fs-18);font-weight:700;color:var(--ink)}
.dash-c-dot{position:absolute;top:6px;right:6px;width:8px;height:8px;border-radius:50%;background:var(--ok-dot);animation:trkpulse 1.6s ease-in-out infinite}
.dash-grid{display:grid;grid-template-columns:1fr 340px;gap:16px;align-items:start}
.dash-row{display:grid;grid-template-columns:1fr 1fr;gap:16px}
.dash-col-main{display:flex;flex-direction:column;gap:16px;min-width:0}
.dash-card{padding:16px;min-width:0}
.dash-card h3{margin:0 0 12px;font-size:var(--fs-14);color:var(--ink-2)}
.dash-card h4{margin:12px 0 6px}
.dash-empty{padding:14px 4px}
.dash-spark{width:100%;height:120px;display:block}
.dash-spark-area{fill:var(--brand-050)}
.dash-spark-line{stroke:var(--brand-d);stroke-width:2;vector-effect:non-scaling-stroke}
.dash-spark-meta{margin-top:6px}
.dash-bars{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:8px}
.dash-bars li{display:grid;grid-template-columns:96px 1fr auto;align-items:center;gap:10px}
.dash-bar-lbl{font-size:var(--fs-13);color:var(--ink);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.dash-bar-track{height:8px;background:var(--off-bg);border-radius:var(--r-pill);overflow:hidden}
.dash-bar-fill{display:block;height:100%;background:var(--brand-d);border-radius:var(--r-pill)}
.dash-bar-val{font-size:var(--fs-12);color:var(--ink);font-variant-numeric:tabular-nums;white-space:nowrap}
.dash-geo-vn .dash-bar-lbl{width:auto}
/* CORR-03R1: three separate, truthful geo groups */
.dash-geo-grp{margin-top:12px}
.dash-geo-grp:first-child{margin-top:0}
.dash-geo-grp+.dash-geo-grp{border-top:1px dashed var(--line);padding-top:10px}
.dash-geo-grp h4{margin:0 0 6px}
.dash-taglist{list-style:none;margin:0;padding:0;display:flex;flex-wrap:wrap;gap:6px}
.dash-taglist li{font-size:var(--fs-12);padding:3px 8px;border-radius:var(--r-pill);background:var(--brand-050);color:var(--brand-d)}
.dash-taglist li.is-unknown{background:var(--off-bg);color:var(--muted)}
.dash-taglist li.is-vn-unknown{background:#eef4ea;color:#3d6b3d}
.dash-geo-note{margin:6px 2px 0;line-height:1.45}
.dash-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:8px}
.dash-list li{display:flex;justify-content:space-between;gap:10px;align-items:baseline}
.dash-list-main{min-width:0;display:flex;flex-direction:column}
.dash-list-main b{font-size:var(--fs-13);color:var(--ink);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.dash-list-sub{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.dash-list-num{font-size:var(--fs-12);color:var(--ink);font-variant-numeric:tabular-nums;white-space:nowrap}
.dash-stream{max-height:640px;overflow:auto;position:sticky;top:16px}
.dash-stream-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:4px}
.dash-stream-row{width:100%;text-align:left;appearance:none;background:none;border:none;border-radius:var(--r-sm);padding:10px;display:flex;gap:10px;cursor:pointer}
.dash-stream-row:hover{background:var(--brand-050)}
.dash-stream-main{min-width:0;display:flex;flex-direction:column;gap:3px}
.dash-stream-top{display:flex;flex-wrap:wrap;align-items:baseline;gap:6px}
.dash-stream-cur,.dash-stream-meta{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.dash-stream-cur{font-size:var(--fs-13);color:var(--ink-2)}
@media(max-width:900px){
  .dash-grid{grid-template-columns:1fr}
  .dash-row{grid-template-columns:1fr}
  .dash-stream{position:static;max-height:none}
}
@media(max-width:420px){ .dash-counter{flex:1 1 45%} .dash-bars li{grid-template-columns:80px 1fr auto} }

/* VISITOR-LIVE-DASHBOARD-V1-CORR-01 — Vietnam realtime map + visual hierarchy (light-professional, realtime accent) */
/* realtime status pill */
.dash-status .trk-live-dot{background:var(--ok-dot)}
.dash-status.is-live{color:var(--ok)}
.dash-status.is-stale{color:var(--warn)}
.dash-status.is-stale .trk-live-dot{background:var(--warn);animation:none}
/* KPI hierarchy — the whole strip reads as one realtime board; "Đang online" leads */
.dash-counters{gap:10px;background:linear-gradient(180deg,var(--brand-050),var(--card));border:1px solid var(--line)}
.dash-counter{padding:6px 12px;border-radius:var(--r-sm);justify-content:center}
.dash-counter--live{background:var(--card);border:1px solid var(--brand-100);box-shadow:0 1px 0 var(--brand-100)}
.dash-counter--live .dash-c-num{color:var(--brand-d);font-size:var(--fs-28)}
.dash-counter--live .dash-c-lbl{color:var(--brand-d);font-weight:600}
/* the map card — large, tinted surface so it anchors the board */
.dash-map .dash-map-head{display:flex;align-items:baseline;justify-content:space-between;gap:10px;margin-bottom:10px}
.dash-map .dash-map-head h3{margin:0}
.dash-map-grid{display:grid;grid-template-columns:minmax(0,1fr) minmax(220px,300px);gap:18px;align-items:start}
.dash-map-visual{background:radial-gradient(130% 100% at 50% 4%,#f2f7ff,var(--card));border:1px solid var(--line);border-radius:var(--r-md,12px);padding:12px;min-height:380px;display:flex;align-items:center;justify-content:center}
.dash-map-wrap{width:100%;max-width:360px}
.dash-map-svg{width:100%;height:auto;display:block;max-height:600px;filter:drop-shadow(0 2px 4px rgba(37,74,139,.10))}
/* CORR-03R1: REAL province polygons (public-domain geoBoundaries), region-tinted, with active highlight + markers */
.dash-map-land{opacity:1}
.dash-prov-area{stroke:#ffffff;stroke-width:.6;stroke-linejoin:round;transition:fill .25s ease}
.dash-region-north{fill:#dbe6fa}
.dash-region-central{fill:#dfeaef}
.dash-region-south{fill:#dcefe4}
/* active province area highlight by absolute intensity (1 / 2–4 / 5+) */
.dash-prov-area.dash-prov-l1{fill:#a9c4f2}
.dash-prov-area.dash-prov-l2{fill:#6f92e8}
.dash-prov-area.dash-prov-l3{fill:var(--brand)}
.dash-prov.is-active .dash-prov-area,.dash-prov-area.is-active{stroke:var(--brand-d);stroke-width:1.4}
.dash-prov:hover .dash-prov-area,.dash-prov:focus .dash-prov-area{stroke:var(--brand-d);stroke-width:1.1}
.dash-map-island circle{fill:#9db8e6}
.dash-map-island-lbl{fill:#8aa0c4;font-size:9px;font-style:italic}
.dash-prov{cursor:pointer}
.dash-prov-marker{pointer-events:none}
.dash-prov-halo{fill:var(--brand-d);opacity:.12}
.dash-prov-dot{fill:var(--brand-d);stroke:#fff;stroke-width:1.5}
.dash-prov-num{fill:#fff;font-size:11px;font-weight:700;pointer-events:none}
.dash-prov-marker.dash-prov-l1 .dash-prov-dot{fill:#5f83dd}
.dash-prov-marker.dash-prov-l2 .dash-prov-dot{fill:var(--brand)}
.dash-prov-marker.dash-prov-l3 .dash-prov-dot{fill:var(--brand-d)}
.dash-prov-marker.dash-prov-l3 .dash-prov-halo{opacity:.18;animation:dashpulse 2.4s ease-in-out infinite}
.dash-prov:focus{outline:none}
@keyframes dashpulse{0%,100%{opacity:.10}50%{opacity:.24}}
.dash-map-side{min-width:0}
.dash-prov-list{max-height:300px;overflow:auto}
.dash-prov-row{width:100%;display:grid;grid-template-columns:96px 1fr auto;align-items:center;gap:10px;appearance:none;background:none;border:none;border-radius:var(--r-sm);padding:5px 6px;cursor:pointer;text-align:left}
.dash-prov-row:hover{background:var(--brand-050)}
.dash-prov-row.is-active{background:var(--brand-050);box-shadow:inset 2px 0 0 var(--brand-d)}
.dash-map-focus{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin:0 0 10px;padding:8px 10px;background:var(--brand-050);border:1px solid var(--brand-100);border-radius:var(--r-sm);font-size:var(--fs-13)}
.dash-map-clear{appearance:none;border:1px solid var(--brand-100);background:var(--card);color:var(--brand-d);border-radius:var(--r-pill);padding:2px 10px;font-size:var(--fs-12);cursor:pointer;font-weight:600}
.dash-map-clear:hover{background:var(--brand-050)}
.dash-map-attr{margin:10px 2px 0;padding-top:8px;border-top:1px solid var(--line);font-size:var(--fs-12);line-height:1.5}
.dash-map-attr a{color:var(--brand-d);text-decoration:none}
.dash-map-attr a:hover{text-decoration:underline}
.dash-map-wrap{display:flex;flex-direction:column;align-items:center;gap:8px}
.dash-map-empty{margin:0;text-align:center}
@media(max-width:900px){
  .dash-map-grid{grid-template-columns:1fr}
  .dash-map-visual{min-height:0}
  .dash-map-wrap{max-width:260px}
  .dash-prov-list{max-height:none}
}
@media(max-width:420px){
  .dash-counter--live{flex-basis:100%}
  .dash-map-wrap{max-width:220px}
  .dash-prov-row{grid-template-columns:80px 1fr auto}
}

/* CHOTSALE-CRM-LEAD-FOUNDATION-V1 — Leads module (reuses design tokens; light-professional, no dark divergence) */
.page-actions{display:flex;gap:8px;align-items:center}
.lead-counters{display:flex;flex-wrap:wrap;gap:8px;padding:12px}
.lead-counter{display:flex;flex-direction:column;gap:2px;padding:8px 14px;border:1px solid var(--line);border-radius:var(--r-sm);text-decoration:none;color:var(--ink);min-width:84px}
.lead-counter:hover{background:var(--brand-050)}
.lead-counter.is-active{border-color:var(--brand-d);background:var(--brand-050)}
.lead-c-num{font-size:var(--fs-22);font-weight:700;color:var(--ink);font-variant-numeric:tabular-nums}
.lead-c-lbl{font-size:var(--fs-12);color:var(--muted)}
.lead-filter-panel{padding:12px}
.lead-filters{display:flex;flex-wrap:wrap;gap:8px;align-items:center}
.lead-filters .lead-search{flex:1 1 220px;min-width:180px}
.lead-filters input,.lead-filters select{border:1px solid var(--line);border-radius:var(--r-sm);padding:7px 10px;font:var(--fs-13)/1.4 var(--f-sans);background:var(--card);color:var(--ink)}
.lead-list{padding:0}
.lead-table tbody tr{cursor:pointer}
.lead-table tbody tr:hover{background:var(--brand-050)}
.lead-chip{display:inline-block;font-size:var(--fs-11);font-weight:600;padding:2px 9px;border-radius:var(--r-pill);background:var(--off-bg);color:var(--ink-2)}
.lead-chip-ok,.lead-chip-won{background:var(--ok-bg);color:var(--ok)}
.lead-chip-new{background:var(--brand-050);color:var(--brand-d)}
.lead-chip-consulting{background:#dbeafe;color:#1e40af}
.lead-chip-considering{background:var(--warn-bg);color:var(--warn)}
.lead-chip-waiting{background:#fef9c3;color:#854d0e}
.lead-chip-lost{background:var(--off-bg);color:var(--muted)}
/* modal */
.lead-modal{position:fixed;inset:0;z-index:60;display:flex;align-items:flex-start;justify-content:center;padding:24px}
.lead-modal-scrim{position:absolute;inset:0;background:rgba(15,23,42,.45)}
.lead-modal-panel{position:relative;background:var(--card);border-radius:var(--r-md,12px);box-shadow:0 20px 60px rgba(2,6,23,.35);width:min(720px,100%);max-height:calc(100vh - 48px);overflow:auto}
.lead-modal-head{display:flex;align-items:center;justify-content:space-between;padding:16px 18px;border-bottom:1px solid var(--line);position:sticky;top:0;background:var(--card);z-index:1}
.lead-modal-head h3{margin:0}
.lead-modal-x{appearance:none;border:none;background:none;font-size:24px;line-height:1;color:var(--muted);cursor:pointer;padding:0 4px}
.lead-mode{display:flex;gap:4px;padding:12px 18px 0}
.lead-mode-tab{appearance:none;background:none;border:none;border-bottom:2px solid transparent;padding:8px 12px;font:600 var(--fs-14)/1.2 var(--f-sans);color:var(--muted);cursor:pointer}
.lead-mode-tab.is-active{color:var(--brand-d);border-bottom-color:var(--brand-d)}
.lead-ai{padding:12px 18px;border-bottom:1px dashed var(--line)}
.lead-ai-text{width:100%;box-sizing:border-box;border:1px solid var(--line);border-radius:var(--r-sm);padding:10px;font:var(--fs-13)/1.5 var(--f-sans);resize:vertical;min-height:70px;background:var(--card);color:var(--ink)}
.lead-ai-actions{display:flex;align-items:center;gap:8px;margin-top:8px;flex-wrap:wrap}
.lead-ai-status{font-size:var(--fs-12);color:var(--muted)}
.lead-voice-btn.is-rec{background:var(--no-bg,#fee2e2);color:var(--no,#b91c1c);border-color:transparent}
.lead-form{padding:14px 18px 18px}
.lead-identity{margin:0 0 12px;padding:10px 12px;border-radius:var(--r-sm);font-size:var(--fs-13);background:var(--warn-bg);color:var(--warn);border:1px solid transparent}
.lead-identity.is-conflict{background:var(--no-bg,#fee2e2);color:var(--no,#b91c1c)}
.lead-identity.is-existing{background:var(--brand-050);color:var(--brand-d)}
.lead-form-grid{display:grid;grid-template-columns:1fr 1fr;gap:12px}
.lead-fl{display:flex;flex-direction:column;gap:4px;font-size:var(--fs-13)}
.lead-fl>span{color:var(--muted);font-size:var(--fs-12)}
.lead-fl input,.lead-fl select,.lead-fl textarea{border:1px solid var(--line);border-radius:var(--r-sm);padding:8px 10px;font:var(--fs-13)/1.4 var(--f-sans);background:var(--card);color:var(--ink);box-sizing:border-box;width:100%}
.lead-col2{grid-column:1 / -1}
/* CRM-LEAD-ADDRESS-CANONICAL-CORR-01 — canonical address block (detailed line full-width, province+ward side-by-side). */
.lead-address-group{display:grid;grid-template-columns:1fr 1fr;gap:12px}
.lead-address-group .lead-addr-line{grid-column:1 / -1}
.lead-address-group .cw-fld{font-size:var(--fs-13)}
.lead-address-group .cw-fld>span{color:var(--muted);font-size:var(--fs-12)}
.lead-address-group .cw-in{border:1px solid var(--line);border-radius:var(--r-sm);padding:8px 10px;font:var(--fs-13)/1.4 var(--f-sans);background:var(--card);color:var(--ink);box-sizing:border-box;width:100%}
@media (max-width:560px){.lead-address-group{grid-template-columns:1fr}}
.lead-budget{display:flex;gap:8px}
.lead-interest-picker{position:relative}
.lead-interest-results{position:absolute;z-index:2;left:0;right:0;background:var(--card);border:1px solid var(--line);border-radius:var(--r-sm);box-shadow:var(--sh-2,0 4px 12px rgba(2,6,23,.12));max-height:200px;overflow:auto}
.lead-int-opt{display:block;width:100%;text-align:left;appearance:none;border:none;background:none;padding:8px 10px;font:var(--fs-13)/1.4 var(--f-sans);color:var(--ink);cursor:pointer}
.lead-int-opt:hover{background:var(--brand-050)}
.lead-interest-chips{display:flex;flex-wrap:wrap;gap:6px;margin-top:6px}
.lead-int-chip{display:inline-flex;align-items:center;gap:6px;font-size:var(--fs-12);padding:4px 10px;border-radius:var(--r-pill);background:var(--off-bg);color:var(--ink-2)}
.lead-int-chip.is-matched{background:var(--ok-bg);color:var(--ok)}
.lead-int-x{appearance:none;border:none;background:none;cursor:pointer;color:inherit;font-size:15px;line-height:1}
.lead-form-foot{display:flex;align-items:center;justify-content:space-between;gap:10px;margin-top:14px}
.lead-form-status{font-size:var(--fs-12);color:var(--muted)}
/* detail */
.lead-back{font-size:var(--fs-13);color:var(--brand-d);text-decoration:none}
.lead-detail-grid{display:grid;grid-template-columns:1fr 340px;gap:16px;align-items:start}
.lead-detail-main,.lead-detail-side{display:flex;flex-direction:column;gap:16px;min-width:0}
.lead-card{padding:16px}
.lead-card h3{margin:0 0 12px;font-size:var(--fs-14);color:var(--ink-2)}
.lead-kvs{display:grid;grid-template-columns:1fr;gap:6px}
.lead-kv{display:flex;justify-content:space-between;gap:12px;align-items:baseline;padding:3px 0}
.lead-k{color:var(--muted);font-size:var(--fs-12);flex:0 0 auto}
.lead-v{text-align:right;min-width:0;word-break:break-word;font-size:var(--fs-13);color:var(--ink)}
.lead-need{margin-top:10px;padding-top:10px;border-top:1px dashed var(--line);font-size:var(--fs-13)}
.lead-inline{display:inline-flex;gap:6px;align-items:center}
.lead-inline select{border:1px solid var(--line);border-radius:var(--r-sm);padding:4px 8px;font-size:var(--fs-12)}
.lead-interest-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:8px}
.lead-interest-list li{display:flex;flex-wrap:wrap;gap:8px;align-items:center;font-size:var(--fs-13)}
.lead-links{display:flex;flex-wrap:wrap;gap:8px}
.lead-note-form{display:flex;gap:8px;margin-bottom:10px}
.lead-note-form input{flex:1;border:1px solid var(--line);border-radius:var(--r-sm);padding:7px 10px;font-size:var(--fs-13)}
.lead-timeline{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:8px}
.lead-timeline li{display:flex;gap:10px;font-size:var(--fs-13)}
.lead-tl-t{color:var(--muted);font-size:var(--fs-12);flex:0 0 96px;font-variant-numeric:tabular-nums}
/* inbox card lead hook */
.cw-lead{margin-top:10px;padding-top:10px;border-top:1px dashed var(--line)}
.cw-lead .btn{width:100%}
@media(max-width:900px){
  .lead-detail-grid{grid-template-columns:1fr}
  .lead-form-grid{grid-template-columns:1fr}
  .lead-modal{padding:0}
  /* CORR-01R1 mobile absorption (production-proven iPhone/Safari Lead-modal fix): use the DYNAMIC viewport (100dvh, with
     the 100vh fallback kept first) so the panel never overshoots behind Safari's bottom toolbar, AND pin the primary
     action as a sticky footer bar above the mobile browser UI + safe-area so "Thêm Lead" stays reachable while scrolling. */
  .lead-modal-panel{width:100%;max-height:100vh;max-height:100dvh;border-radius:0}
  .lead-form-foot{position:sticky;bottom:0;background:var(--card);border-top:1px solid var(--line);margin:14px -18px -18px;padding:12px 18px;padding-bottom:calc(12px + env(safe-area-inset-bottom,0px));z-index:2}
}

/* fix: the [hidden] attribute must win over the explicit display on these lead components */
.lead-modal[hidden]{display:none}
.lead-ai[hidden]{display:none}
.lead-identity[hidden]{display:none}
.lead-interest-results[hidden]{display:none}

/* ============================================================
   CRM-LEADS-WORKSPACE-V1 — visual refresh (Leads surface only)
   Stronger hierarchy/contrast, Chotsale purple accents, real
   code-status palette. Scoped to lead components; no global reset.
   ============================================================ */

/* view switch: [ Danh sách ] [ Làm việc ] [ Kanban ] */
.lead-views{display:inline-flex;gap:2px;padding:3px;background:var(--line-2);border:1px solid var(--line);border-radius:var(--r-pill)}
.lead-view-tab{display:inline-flex;align-items:center;gap:6px;padding:7px 16px;border-radius:var(--r-pill);font-size:var(--fs-13);font-weight:600;color:var(--muted);white-space:nowrap;transition:background .12s,color .12s}
.lead-view-tab:hover{color:var(--ink-2)}
.lead-view-tab.is-active{background:var(--card);color:var(--brand-d);box-shadow:var(--sh-1)}

/* quick filters (§14) */
.lead-quick{display:flex;flex-wrap:wrap;gap:8px;padding:12px 14px;margin-bottom:12px}
.lead-qf{display:inline-flex;align-items:center;gap:7px;padding:7px 12px;border:1px solid var(--line);border-radius:var(--r-pill);background:var(--card);font-size:var(--fs-13);font-weight:600;color:var(--ink-2);transition:border-color .12s,background .12s,color .12s}
.lead-qf:hover{border-color:var(--brand-100);color:var(--brand-d)}
.lead-qf.is-active{background:var(--brand-050);border-color:var(--brand-100);color:var(--brand-d)}
.lead-qf-n{min-width:18px;height:18px;padding:0 5px;display:inline-flex;align-items:center;justify-content:center;border-radius:var(--r-pill);background:var(--line);color:var(--muted);font-size:var(--fs-11);font-weight:700}
.lead-qf.is-active .lead-qf-n{background:var(--brand);color:#fff}

/* avatar (hashed hue) */
.lead-ava{--ava-h:250;flex:0 0 auto;width:34px;height:34px;border-radius:var(--r-pill);display:inline-flex;align-items:center;justify-content:center;font-weight:700;font-size:var(--fs-13);color:hsl(var(--ava-h) 62% 34%);background:hsl(var(--ava-h) 72% 94%);border:1px solid hsl(var(--ava-h) 60% 88%)}

/* source badges (real channels only) */
.lead-src{display:inline-flex;align-items:center;padding:2px 9px;border-radius:var(--r-pill);font-size:var(--fs-11);font-weight:700;letter-spacing:.01em;background:var(--line-2);color:var(--ink-2);border:1px solid var(--line)}
.lead-src-website{background:#eff6ff;color:#1d4ed8;border-color:#dbeafe}
.lead-src-facebook{background:#eef2ff;color:#1e40af;border-color:#e0e7ff}
.lead-src-zalo{background:#e0f2fe;color:#0369a1;border-color:#bae6fd}
.lead-src-tiktok{background:#f1f5f9;color:#0f172a;border-color:#e2e8f0}
.lead-src-instagram{background:#fdf2f8;color:#be185d;border-color:#fce7f3}
.lead-src-phone{background:#ecfdf5;color:#047857;border-color:#d1fae5}
.lead-src-walk_in{background:#fefce8;color:#854d0e;border-color:#fef9c3}
.lead-src-referral{background:#f5f3ff;color:#6d28d9;border-color:#ede9fe}
.lead-src-manual,.lead-src-other{background:var(--line-2);color:var(--muted);border-color:var(--line)}

/* upgraded list table (§4) */
.lead-table{width:100%;border-collapse:separate;border-spacing:0;background:var(--card);border:1px solid var(--line);border-radius:var(--r);overflow:hidden}
.lead-table thead th{position:sticky;top:0;z-index:1;background:var(--line-2);text-align:left;font-size:var(--fs-11);font-weight:700;text-transform:uppercase;letter-spacing:.04em;color:var(--muted);padding:10px 14px;border-bottom:1px solid var(--line);white-space:nowrap}
.lead-table tbody td{padding:11px 14px;border-bottom:1px solid var(--line-2);vertical-align:middle;font-size:var(--fs-13)}
.lead-table tbody tr:last-child td{border-bottom:0}
.lead-table tbody tr:hover{background:var(--brand-050)}
.lead-th-chk,.lead-td-chk{width:36px;text-align:center;padding-left:10px;padding-right:0}
.lead-th-act,.lead-td-act{width:1%;white-space:nowrap;text-align:right}
.lead-td-main a.lead-open,.lead-td-main .lead-nm{display:flex;align-items:center;gap:10px;color:inherit}
/* §8.1 — the lead name stays on ONE line (nowrap + ellipsis + title tooltip); need line below it. */
.lead-nm{min-width:0;flex-direction:column;align-items:flex-start;gap:1px}
.lead-nm strong,.lead-nm b{display:block;font-weight:650;color:var(--ink);line-height:1.3;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:100%;min-width:0}
.lead-need{display:block;font-size:var(--fs-12);color:var(--muted);overflow:hidden;text-overflow:ellipsis;max-width:26ch;white-space:nowrap}
.lead-td-ct{color:var(--ink-2)}
.lead-td-ct span{display:block;font-size:var(--fs-12);color:var(--muted)}
.lead-plus{margin-left:6px;font-size:var(--fs-11);font-weight:700;color:var(--muted)}
.lead-int-chips{display:flex;align-items:center;gap:6px;flex-wrap:wrap}
.lead-int-chip{display:inline-flex;padding:2px 8px;border-radius:var(--r-pill);background:var(--brand-050);color:var(--brand-d);font-size:var(--fs-11);font-weight:600;max-width:16ch;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.lead-overdue{display:inline-flex;align-items:center;gap:4px;margin-left:6px;color:var(--warn);font-size:var(--fs-11);font-weight:700}
.lead-overdue svg{width:12px;height:12px}

/* row actions + overflow menu (§5) */
.lead-acts{display:inline-flex;align-items:center;gap:4px;justify-content:flex-end}
.lead-ico{width:30px;height:30px;display:inline-flex;align-items:center;justify-content:center;border:1px solid var(--line);border-radius:var(--r-sm);background:var(--card);color:var(--ink-2);transition:border-color .12s,color .12s,background .12s}
.lead-ico:hover{border-color:var(--brand-100);color:var(--brand-d);background:var(--brand-050)}
.lead-ico[aria-disabled="true"],.lead-ico:disabled{opacity:.4;pointer-events:none}
.lead-ico svg{width:15px;height:15px}
.lead-menu{position:relative;display:inline-flex}
/* CRM-UX-CONSOLIDATION-02 §3.1 — cc.js repositions this to position:fixed on open (escaping .lead-table/.tbl-wrap
   overflow clipping) with viewport-collision flip-up. z-index sits above the sticky bulk bar (15) / thead (1), not absurd. */
.lead-menu-list{position:absolute;right:0;top:calc(100% + 4px);z-index:60;min-width:180px;max-width:calc(100vw - 16px);padding:5px;background:var(--card);border:1px solid var(--line);border-radius:var(--r-sm);box-shadow:var(--sh-2);list-style:none;margin:0}
.lead-menu-list[hidden]{display:none}
/* §6 — professional vertical popover: each action is a full-width icon+label row (the markup uses bare <a>, so target
   both <a> and li>* so rows never render as concatenated inline text). */
.lead-menu-list a,.lead-menu-list li>*{display:flex;align-items:center;gap:9px;width:100%;padding:8px 10px;border-radius:6px;font-size:var(--fs-13);color:var(--ink-2);text-align:left;background:none;border:0;text-decoration:none;cursor:pointer}
.lead-menu-list a .ic,.lead-menu-list li>* .ic{flex:none;color:var(--muted)}
.lead-menu-list a:hover,.lead-menu-list a:focus,.lead-menu-list li>*:hover,.lead-menu-list li>*:focus{background:var(--brand-050);color:var(--brand-d);outline:none}
.lead-menu-list a:hover .ic,.lead-menu-list a:focus .ic{color:var(--brand-d)}
/* CORR02 §5 — the Zalo "Liên hệ qua Zalo" popover (fixed-positioned by cc.js; no discovery claim). */
.lead-zalo{position:relative;display:inline-block}
.lead-zalo-pop{position:fixed;z-index:1000;min-width:230px;max-width:calc(100vw - 16px);padding:12px;background:var(--card);border:1px solid var(--line);border-radius:var(--r-sm);box-shadow:var(--sh-3)}
.lead-zalo-pop[hidden]{display:none}
.lead-zalo-head{font-weight:650;font-size:var(--fs-13);color:var(--ink);margin-bottom:6px}
.lead-zalo-phone{font-size:var(--fs-16);font-weight:700;color:var(--brand-d);letter-spacing:.5px;margin-bottom:10px}
.lead-zalo-actions{display:flex;gap:8px;margin-bottom:8px;flex-wrap:wrap}

/* bulk action bar (§20 — only rendered when functional) */
.lead-bulk{position:sticky;bottom:12px;z-index:15;display:flex;align-items:center;gap:12px;margin-top:12px;padding:10px 14px;background:var(--ink);color:#fff;border-radius:var(--r);box-shadow:var(--sh-3)}
.lead-bulk[hidden]{display:none}
.lead-bulk .lead-bulk-n{font-weight:700}
.lead-bulk select,.lead-bulk button{font-size:var(--fs-13)}
.lead-bulk button[data-bulk-apply]{padding:6px 12px;border-radius:var(--r-sm);border:0;background:var(--brand);color:#fff;font-weight:600;cursor:pointer}
.lead-bulk button[data-bulk-apply]:hover{background:var(--brand-d)}
.lead-bulk [data-bulk-clear]{margin-left:auto;color:var(--muted-2);background:none;border:0;cursor:pointer}

/* ---------- 3-column workspace (§8) ---------- */
.lead-ws{display:grid;grid-template-columns:24% minmax(0,1fr) 25%;gap:14px;align-items:start;min-height:calc(100dvh - 160px)}
/* CORR01 Fix A — grid tracks use minmax(0,…) and children may shrink below their content min-size, so a long
   unbroken string (email/need) can never force the track wider than its share (the classic CSS-Grid 1fr blowout). */
.lead-ws>*{min-width:0}
.lead-ws-queue,.lead-ws-timeline{position:sticky;top:14px;max-height:calc(100dvh - 90px);overflow:auto}
.lead-ws-queue{display:flex;flex-direction:column;gap:10px}
.lead-wsq-filter{display:flex;gap:8px;flex-wrap:wrap}
.lead-ws-list{display:flex;flex-direction:column;gap:8px;list-style:none;margin:0;padding:0}
.lead-ws-center.is-loading{opacity:.5;pointer-events:none;transition:opacity .1s}

/* queue cards */
/* §3.2 — COMPACT queue row: 2 lines, ~56–68px. Tight padding + single-line ellipsis; no avatar/assignee foot. */
.lead-qcard{display:block;padding:8px 10px;border:1px solid var(--line);border-radius:var(--r-sm);background:var(--card);transition:border-color .12s,box-shadow .12s,background .12s;cursor:pointer}
.lead-qcard:hover{border-color:var(--brand-100);box-shadow:var(--sh-1)}
.lead-qcard.is-active{border-color:var(--brand);background:var(--brand-050);box-shadow:inset 3px 0 0 var(--brand)}
.lead-qcard-top{display:flex;align-items:center;gap:7px;min-width:0}
.lead-qcard-top b{font-size:var(--fs-13);font-weight:650;color:var(--ink);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1;min-width:0}
.lead-qcard-meta{display:flex;align-items:center;gap:6px;margin-top:4px;min-width:0;overflow:hidden;white-space:nowrap}
.lead-qcard-int{font-size:var(--fs-12);color:var(--muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;flex:1}
.lead-qcard-time{flex:none;margin-left:auto}

/* center: header + primary actions + tabs — §3.3 compact header (~90–110px incl. the action row) */
.lead-wc{background:var(--card);border:1px solid var(--line);border-radius:var(--r-lg);overflow:hidden}
/* CORR03R1 — the center Lead header is a VERTICAL hierarchy: identity row → meta row → action row. Actions no longer
   share the identity row (that compressed the name to "A..." and word-broke the meta). Each block gets full width. */
.lead-wc-head{display:flex;flex-direction:column;gap:10px;padding:12px 16px;border-bottom:1px solid var(--line)}
.lead-wc-head .lead-ava{width:40px;height:40px;font-size:var(--fs-14);flex:none}
.lead-wc-id{min-width:0;display:flex;align-items:center;gap:12px}
.lead-wc-id h3{font-size:var(--fs-18);font-weight:700;margin:0;line-height:1.25;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.lead-wc-sub{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-top:3px;font-size:var(--fs-12);color:var(--muted)}
.lead-wc-actions{display:flex;flex-wrap:wrap;gap:8px;padding:0}
.lead-wc-actions .btn{font-size:var(--fs-13)}
.lead-wc-actions .btn[disabled],.lead-wc-actions .btn[aria-disabled="true"]{opacity:.5;pointer-events:none}
.lead-wc-tabs{display:flex;gap:2px;padding:0 12px;border-bottom:1px solid var(--line);overflow-x:auto}
.lead-wc-tab{padding:12px 14px;font-size:var(--fs-13);font-weight:600;color:var(--muted);border-bottom:2px solid transparent;white-space:nowrap;background:none;border-top:0;border-left:0;border-right:0;cursor:pointer}
.lead-wc-tab:hover{color:var(--ink-2)}
.lead-wc-tab.is-active{color:var(--brand-d);border-bottom-color:var(--brand)}
.lead-wc-panel{padding:18px}
.lead-wc-panel:not(.is-active){display:none}

/* CORR03 §15/§20/§21 — clean header: name+status line, then Phụ trách / Nguồn meta */
.lead-wc-idmeta{min-width:0;flex:1}
.lead-wc-nameline{display:flex;align-items:center;gap:10px;min-width:0}
/* the name takes the room it needs and only ellipsizes when genuinely long; the status badge never shrinks it. */
.lead-wc-nameline h3{font-size:var(--fs-18);font-weight:700;margin:0;line-height:1.25;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}
.lead-wc-nameline .chip,.lead-wc-nameline .badge{flex:none}
/* each meta item (Phụ trách: … / Nguồn: …) is a whole nowrap unit; flex-wrap moves the WHOLE item to the next line,
   never word-by-word. An extreme value ellipsizes instead of overflowing. */
.lead-wc-meta{display:flex;gap:6px 22px;flex-wrap:wrap;margin-top:5px;font-size:var(--fs-13);color:var(--muted)}
.lead-wc-meta span{white-space:nowrap;max-width:100%;overflow:hidden;text-overflow:ellipsis}
.lead-wc-meta b{color:var(--ink-2);font-weight:600}
/* CORR03 §14/§16/§17 — VERTICAL full-width stacked cards + a compact 2-column key/value grid inside each card */
.lead-info-stack{display:flex;flex-direction:column;gap:14px}
.lead-info-stack .lead-card{width:auto}
.lead-kv-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:6px 24px}
.lead-kv-grid .kv{display:flex;align-items:baseline;gap:10px;min-width:0;padding:3px 0}
.lead-kv-grid .kv .k{flex:none;width:120px;font-size:var(--fs-12);color:var(--muted)}
.lead-kv-grid .kv .v{min-width:0;font-size:var(--fs-13);color:var(--ink);overflow-wrap:anywhere}
.lead-kv-block{margin-top:10px}
.lead-kv-block .k{display:block;font-size:var(--fs-12);color:var(--muted);margin-bottom:3px}
.lead-kv-block .v{font-size:var(--fs-13);color:var(--ink);line-height:1.5}
/* CORR03 §7/§8 — Lead email composer + no-email state */
.cw-email-to{display:flex;flex-direction:column;gap:1px;padding:8px 10px;background:var(--line-2);border-radius:var(--r-sm);margin-bottom:10px}
.cw-email-to b{font-size:var(--fs-13);color:var(--ink)}
.cw-email-to span{font-size:var(--fs-12);color:var(--muted)}
.cw-email-empty{text-align:center;padding:8px 0}
.cw-email-empty p{margin:0 0 10px;color:var(--ink-2)}
/* CORR03 §2 — email settings */
.email-cfg-wrap{display:flex;flex-direction:column;gap:14px;max-width:820px}
.cw-check{flex-direction:row;align-items:center;gap:8px}
.cw-check input{width:auto}
/* info grid + inline edit forms (§7/§9) */
.lead-info-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:14px 22px}
.lead-info-grid>div{min-width:0}
.lead-info-grid dt,.lead-kv .lead-c-lbl{font-size:var(--fs-11);font-weight:700;text-transform:uppercase;letter-spacing:.03em;color:var(--muted-2);margin-bottom:3px}
.lead-info-grid dd{margin:0;font-size:var(--fs-14);color:var(--ink)}
.lead-ef{display:flex;flex-direction:column;gap:12px}
.lead-ef-row{display:flex;flex-direction:column;gap:5px}
.lead-ef-fields{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px}
.lead-ef label{font-size:var(--fs-12);font-weight:600;color:var(--ink-2)}
.lead-ef input,.lead-ef select,.lead-ef textarea{width:100%}

/* ---------- right: sales timeline (§8 RIGHT / §4 model) ---------- */
.lead-ws-timeline .lead-tl{position:relative;list-style:none;margin:0;padding:4px 0 4px 6px}
.lead-tl-item{position:relative;padding:0 0 16px 26px}
.lead-tl-item::before{content:"";position:absolute;left:9px;top:20px;bottom:-2px;width:2px;background:var(--line)}
.lead-tl-item:last-child::before{display:none}
.lead-tl-dot{position:absolute;left:2px;top:2px;width:18px;height:18px;border-radius:var(--r-pill);background:var(--brand-050);color:var(--brand-d);display:inline-flex;align-items:center;justify-content:center;border:1px solid var(--brand-100)}
.lead-tl-dot svg{width:11px;height:11px}
.lead-tl-head{display:flex;align-items:baseline;justify-content:space-between;gap:8px}
.lead-tl-title{font-size:var(--fs-13);font-weight:600;color:var(--ink)}
.lead-tl-t{font-size:var(--fs-11);color:var(--muted-2);white-space:nowrap}
.lead-tl-detail{font-size:var(--fs-12);color:var(--muted);margin-top:2px}

/* ---------- Kanban (§17) ---------- */
.lead-kb-wrap{overflow-x:auto;overflow-y:hidden;padding-bottom:8px;-webkit-overflow-scrolling:touch}
.lead-kb-board{display:grid;grid-auto-flow:column;grid-auto-columns:300px;gap:12px;align-items:start;min-height:calc(100dvh - 200px)}
.lead-kb-col{display:flex;flex-direction:column;background:var(--line-2);border:1px solid var(--line);border-radius:var(--r);max-height:calc(100dvh - 170px)}
.lead-kb-head{position:sticky;top:0;display:flex;align-items:center;gap:8px;padding:11px 13px;border-bottom:1px solid var(--line);background:var(--line-2);border-radius:var(--r) var(--r) 0 0;z-index:1}
.lead-kb-head strong{font-size:var(--fs-13);font-weight:700}
.lead-kb-n{min-width:20px;height:20px;padding:0 6px;display:inline-flex;align-items:center;justify-content:center;border-radius:var(--r-pill);background:var(--card);color:var(--muted);font-size:var(--fs-11);font-weight:700;border:1px solid var(--line)}
.lead-kb-dot{width:8px;height:8px;border-radius:var(--r-pill);flex:0 0 auto}
.lead-kb-body{flex:1;overflow-y:auto;padding:10px;display:flex;flex-direction:column;gap:9px;min-height:60px}
.lead-kb-body.is-over,.lead-kb-drop.is-over{background:var(--brand-050);outline:2px dashed var(--brand-100);outline-offset:-4px;border-radius:var(--r-sm)}
.lead-kb-card{display:block;padding:11px 12px;background:var(--card);border:1px solid var(--line);border-radius:var(--r-sm);box-shadow:var(--sh-1);cursor:grab;transition:box-shadow .12s,transform .06s}
.lead-kanban.can-drag .lead-kb-card:hover{box-shadow:var(--sh-2)}
.lead-kb-card.is-dragging{opacity:.45;cursor:grabbing}
.lead-kb-card.is-pending{opacity:.6;pointer-events:none}
.lead-kb-name{font-size:var(--fs-13);font-weight:650;color:var(--ink);line-height:1.3}
.lead-kb-meta{display:flex;align-items:center;gap:7px;flex-wrap:wrap;margin-top:7px}
.lead-kb-int{font-size:var(--fs-12);color:var(--muted);margin-top:5px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.lead-kb-foot{display:flex;align-items:center;justify-content:space-between;margin-top:7px;font-size:var(--fs-11);color:var(--muted-2)}
.lead-kb-empty{padding:16px;text-align:center;font-size:var(--fs-12);color:var(--muted-2)}

/* status accent dots by canonical code (§15 palette) */
.lead-kb-dot.st-new{background:var(--brand)}
.lead-kb-dot.st-consulting{background:#3b82f6}
.lead-kb-dot.st-considering{background:var(--warn-dot)}
.lead-kb-dot.st-waiting{background:#eab308}
.lead-kb-dot.st-won{background:var(--ok-dot)}
.lead-kb-dot.st-lost{background:var(--muted-2)}

/* ---------- mobile (§26): list 390 / 3-col collapses / kanban horizontal ---------- */
@media (max-width:900px){
  .lead-ws{grid-template-columns:minmax(0,1fr);min-height:0}
  .lead-ws-queue,.lead-ws-timeline{position:static;max-height:none;overflow:visible}
  /* tap a lead → center becomes the focused view; queue+timeline stack below */
  .lead-ws.has-selected .lead-ws-center{order:-1}
}
@media (max-width:640px){
  .lead-views{width:100%;justify-content:stretch}
  .lead-view-tab{flex:1;justify-content:center;padding:8px 6px}
  .lead-quick{overflow-x:auto;flex-wrap:nowrap;-webkit-overflow-scrolling:touch}
  .lead-qf{flex:0 0 auto}
  /* list → card rows to avoid horizontal scroll at 390px */
  .lead-table,.lead-table thead,.lead-table tbody,.lead-table tr,.lead-table td{display:block;width:auto}
  .lead-table thead{position:absolute;left:-9999px}
  .lead-table tbody tr{margin:0 0 10px;border:1px solid var(--line);border-radius:var(--r);overflow:hidden;background:var(--card)}
  .lead-table tbody td{border-bottom:1px solid var(--line-2);padding:9px 12px}
  .lead-td-act{text-align:left}
  .lead-need{max-width:none;white-space:normal}
  /* CORR03R1 — on mobile the action buttons WRAP (identity first, meta stacked, actions below); no horizontal scroll/clip. */
  .lead-wc-actions{flex-wrap:wrap}
  .lead-wc-meta{gap:4px 16px}
  .lead-info-grid,.lead-ef-fields,.lead-kv-grid{grid-template-columns:1fr}
  .lead-kv-grid .kv .k{width:110px}
  .lead-kb-board{grid-auto-columns:82vw}
}

/* ============================================================
   CHOTSALE-CRM-ORDER-01 — Sales Order surfaces (list/create/detail).
   Reuses the Leads visual direction; server is the money authority.
   ============================================================ */
.page-head-actions{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.btn-brand{background:var(--brand);color:#fff;border-color:var(--brand)}
.btn-brand:hover{background:var(--brand-d);border-color:var(--brand-d)}
.btn-danger{background:#fee2e2;color:#b91c1c;border-color:#fecaca}
.btn-danger:hover{background:#fecaca}
.btn-block{display:block;width:100%;text-align:center;padding:11px 16px;font-weight:600}
.ta-right{text-align:right}.ta-center{text-align:center}
.tbl-wrap{overflow-x:auto;-webkit-overflow-scrolling:touch}

.ord-chip{display:inline-flex;align-items:center;padding:2px 10px;border-radius:var(--r-pill);font-size:var(--fs-11);font-weight:700}
.ord-st-draft{background:var(--line-2);color:var(--muted)}
.ord-st-confirmed{background:#dbeafe;color:#1e40af}
.ord-st-processing{background:var(--warn-bg);color:var(--warn)}
.ord-st-completed{background:var(--ok-bg);color:var(--ok)}
.ord-st-cancelled{background:#fee2e2;color:#b91c1c}

.ord-quick{display:flex;flex-wrap:wrap;gap:8px;padding:12px 14px;margin-bottom:12px}
.ord-qf{display:inline-flex;align-items:center;gap:7px;padding:7px 12px;border:1px solid var(--line);border-radius:var(--r-pill);background:var(--card);font-size:var(--fs-13);font-weight:600;color:var(--ink-2)}
.ord-qf:hover{border-color:var(--brand-100);color:var(--brand-d)}
.ord-qf.is-active{background:var(--brand-050);border-color:var(--brand-100);color:var(--brand-d)}
.ord-qf-n{min-width:18px;height:18px;padding:0 5px;display:inline-flex;align-items:center;justify-content:center;border-radius:var(--r-pill);background:var(--line);color:var(--muted);font-size:var(--fs-11);font-weight:700}
.ord-qf.is-active .ord-qf-n{background:var(--brand);color:#fff}
.ord-search{display:inline-flex;gap:6px}

.ord-table{width:100%;border-collapse:separate;border-spacing:0}
.ord-table thead th{background:var(--line-2);text-align:left;font-size:var(--fs-11);font-weight:700;text-transform:uppercase;letter-spacing:.04em;color:var(--muted);padding:10px 12px;border-bottom:1px solid var(--line);white-space:nowrap}
.ord-table tbody td{padding:11px 12px;border-bottom:1px solid var(--line-2);font-size:var(--fs-13);vertical-align:middle}
.ord-table tbody tr:hover{background:var(--brand-050)}
.ord-code{font-weight:700;color:var(--brand-d)}
.ord-total{font-weight:700;color:var(--ink);white-space:nowrap}

.ord-grid{display:grid;grid-template-columns:minmax(0,1fr) 320px;gap:16px;align-items:start}
.ord-grid-main{display:flex;flex-direction:column;gap:14px;min-width:0}
.ord-grid-side{position:sticky;top:14px;display:flex;flex-direction:column;gap:12px}
.ord-sec{padding:16px}
.ord-sec h3{margin:0 0 12px;font-size:var(--fs-15)}
.ord-sec .panel-head{margin-bottom:12px}

.ord-cust-search{display:flex;flex-direction:column;gap:8px;position:relative}
.ord-cust-results,.ord-prod-results{display:flex;flex-direction:column;border:1px solid var(--line);border-radius:var(--r-sm);overflow:hidden;background:var(--card);box-shadow:var(--sh-1)}
.ord-cust-results[hidden],.ord-prod-results[hidden]{display:none}
.ord-res{display:block;width:100%;text-align:left;padding:9px 12px;border:0;border-bottom:1px solid var(--line-2);background:none;cursor:pointer;font-size:var(--fs-13)}
.ord-res:last-child{border-bottom:0}
.ord-res:hover{background:var(--brand-050)}
.ord-res-empty{padding:10px 12px}
.ord-cust-selected{display:flex;align-items:center;justify-content:space-between;gap:10px}
.ord-cust-selected[hidden]{display:none}
.ord-cust-picked{font-weight:600;color:var(--ink)}
.ord-cust-quick{margin-top:12px;padding:12px;border:1px dashed var(--line);border-radius:var(--r-sm);background:var(--line-2)}
.ord-cust-quick[hidden]{display:none}
.ord-quick-grid{display:grid;grid-template-columns:1fr 1fr;gap:10px}
.ord-quick-grid label{display:flex;flex-direction:column;gap:4px;font-size:var(--fs-12);font-weight:600;color:var(--ink-2)}
.ord-quick-actions{display:flex;align-items:center;gap:10px;margin-top:10px}

.ord-prod-search{position:relative;margin-bottom:12px}
.ord-lines{display:flex;flex-direction:column;gap:8px}
.ord-line{display:grid;grid-template-columns:minmax(0,1fr) 72px 118px 96px auto 30px;gap:8px;align-items:center;padding:9px 10px;border:1px solid var(--line);border-radius:var(--r-sm);background:var(--card)}
.ord-line-main{min-width:0}
.ord-line-name{display:block;font-weight:600;font-size:var(--fs-13);color:var(--ink);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ord-line-code{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ord-line-f{display:flex;flex-direction:column;gap:2px;font-size:var(--fs-11);color:var(--muted);min-width:0}
.ord-line-f .inp{width:100%;min-width:0;padding:6px 8px;font-size:var(--fs-13);text-align:right}
.ord-line-amt{font-weight:700;font-size:var(--fs-13);white-space:nowrap;text-align:right}
.ord-line-x{width:26px;height:26px;border:1px solid var(--line);border-radius:var(--r-sm);background:var(--card);color:var(--muted);cursor:pointer;font-size:16px;line-height:1}
.ord-line-x:hover{border-color:#fecaca;color:#b91c1c;background:#fef2f2}
.ord-lines-empty{padding:14px;text-align:center}
.ord-lines-empty[hidden]{display:none}

.ord-summary{gap:10px}
.ord-sum-title{margin:0 0 2px;font-size:var(--fs-14);font-weight:650;color:var(--ink)}
.ord-sum-row{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:4px 0}
.ord-sum-row .inp{max-width:150px;text-align:right}
.ord-sum-total{border-top:1px solid var(--line);padding-top:10px;margin-top:4px}
.ord-sum-total span{font-weight:600}
.ord-sum-total b{font-size:var(--fs-18);color:var(--brand-d)}
.ord-meta-grid{display:grid;gap:12px}
.ord-meta-grid label{display:flex;flex-direction:column;gap:5px;font-size:var(--fs-12);font-weight:600;color:var(--ink-2)}
.ord-form-msg{margin-top:8px;font-size:var(--fs-13);color:var(--muted);text-align:center;min-height:18px}
.ord-form-msg.is-err{color:#b91c1c;font-weight:600}

.ord-detail{display:grid;grid-template-columns:minmax(0,1fr) 320px;gap:16px;align-items:start}
.ord-detail-main{display:flex;flex-direction:column;gap:14px;min-width:0}
.ord-detail-side{display:flex;flex-direction:column;gap:14px}
.ord-detail-head{display:flex;align-items:flex-start;justify-content:space-between;gap:14px;padding:16px;background:var(--card);border:1px solid var(--line);border-radius:var(--r-lg)}
.ord-detail-code{font-size:var(--fs-22);font-weight:800}
.ord-detail-sub{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-top:6px}
.ord-detail-total{text-align:right}
.ord-detail-total b{display:block;font-size:var(--fs-22);font-weight:800;color:var(--brand-d)}
.ord-detail-actions{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:10px;padding:12px 0 0}
.ord-act-primary{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.ord-next-cta{font-size:var(--fs-14);font-weight:650;padding:9px 18px}
.ord-next-hint{white-space:nowrap}
.ord-act-rest{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-left:auto}
/* FINAL-CORR01 §4 — order lifecycle stepper (canonical OrderStatus; presentation only) */
.ord-stepper{list-style:none;display:flex;align-items:center;gap:6px;margin:14px 0 0;padding:12px;background:var(--card);border:1px solid var(--line);border-radius:var(--r);overflow-x:auto}
.ord-step{display:flex;align-items:center;gap:7px;flex:1;min-width:0;color:var(--muted-2);font-size:var(--fs-12)}
.ord-step:not(:last-child)::after{content:"";flex:1;height:2px;background:var(--line);border-radius:2px}
.ord-step-dot{display:inline-flex;align-items:center;justify-content:center;width:22px;height:22px;border-radius:var(--r-pill);background:var(--line-2);color:var(--muted);font-size:var(--fs-12);font-weight:700;flex:none}
.ord-step-lbl{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.ord-step.is-done{color:var(--ok)}
.ord-step.is-done .ord-step-dot{background:var(--ok-bg);color:var(--ok)}
.ord-step.is-done:not(:last-child)::after{background:var(--ok-dot)}
.ord-step.is-current{color:var(--brand-d);font-weight:650}
.ord-step.is-current .ord-step-dot{background:var(--brand);color:#fff}
.ord-stepper.is-cancelled{padding:12px 14px}
.ord-step-cancel{display:flex;align-items:center;gap:7px;color:var(--no);font-weight:600;font-size:var(--fs-13)}
.ord-row-acts{display:inline-flex;gap:6px;justify-content:flex-end;white-space:nowrap}
.ord-cust-view b{font-size:var(--fs-15)}
/* FINAL-CORR01 §6 — printable Order document (A4). Screen: centered sheet; print: no chrome, A4 margins. */
.print-body{background:var(--bg);margin:0;padding:0}
.print-toolbar{display:flex;gap:8px;justify-content:center;padding:12px;background:var(--card);border-bottom:1px solid var(--line);position:sticky;top:0;z-index:5}
.print-doc{max-width:820px;margin:16px auto;background:#fff;color:#111;padding:28px 32px;box-shadow:var(--sh-2);font-size:13px;line-height:1.5}
.pd-head{display:flex;align-items:flex-start;justify-content:space-between;gap:20px;border-bottom:2px solid #111;padding-bottom:12px}
.pd-title h1{margin:0;font-size:24px;letter-spacing:1px}
.pd-code{font-size:15px;font-weight:700;color:#4338ca;margin-top:2px}
.pd-head-meta{display:grid;grid-template-columns:1fr 1fr;gap:2px 18px;font-size:12px;text-align:right}
.pd-head-meta>div{display:flex;gap:8px;justify-content:flex-end}
.pd-head-meta span{color:#666}
.pd-parties{display:grid;grid-template-columns:1fr 1fr;gap:24px;margin-top:18px}
.pd-party h2{font-size:12px;letter-spacing:.5px;color:#4338ca;margin:0 0 8px;border-bottom:1px solid #ddd;padding-bottom:4px}
.pd-kv{display:flex;gap:8px;margin-bottom:3px}
.pd-kv span{color:#666;min-width:120px}
.pd-items{width:100%;border-collapse:collapse;margin-top:20px;font-size:12px}
.pd-items th{background:#f1f2f6;text-align:left;padding:8px 8px;border-bottom:2px solid #ccc;font-size:11px;letter-spacing:.3px}
.pd-items td{padding:7px 8px;border-bottom:1px solid #eee;vertical-align:top}
.pd-variant{color:#666;font-weight:400}
.pd-code-sm{color:#888;font-size:11px;margin-top:2px}
.pd-summary{display:flex;justify-content:flex-end;margin-top:14px}
.pd-summary table{min-width:280px;border-collapse:collapse}
.pd-summary td{padding:5px 8px}
.pd-summary tr td:last-child{text-align:right;font-variant-numeric:tabular-nums}
.pd-total td{border-top:2px solid #111;font-size:16px;font-weight:800;color:#4338ca;padding-top:8px}
.pd-signs{display:grid;grid-template-columns:1fr 1fr;gap:40px;margin-top:40px;text-align:center}
.pd-sign span{display:block;font-weight:700}
.pd-sign i{color:#666;font-size:11px}
.pd-sign{border-top:1px dashed #bbb;padding-top:56px}
.pd-foot{margin-top:28px;text-align:center;color:#999;font-size:11px;border-top:1px solid #eee;padding-top:10px}
.ta-right{text-align:right}.ta-center{text-align:center}
@media print{
  @page{size:A4 portrait;margin:14mm}
  html.cc-js .print-body,.print-body{background:#fff}
  .no-print,.print-toolbar{display:none !important}
  .print-doc{max-width:none;margin:0;padding:0;box-shadow:none}
  .pd-items{page-break-inside:auto}
  .pd-items tr{page-break-inside:avoid}
  .pd-summary,.pd-signs,.pd-total{page-break-inside:avoid}
}
.ord-ship{margin-top:6px}
.ord-cust-actions{display:flex;gap:6px;margin-top:10px}
.ord-items-table{width:100%;border-collapse:collapse}
.ord-items-table th{text-align:left;font-size:var(--fs-11);font-weight:700;text-transform:uppercase;color:var(--muted);padding:8px 10px;border-bottom:1px solid var(--line)}
.ord-items-table td{padding:9px 10px;border-bottom:1px solid var(--line-2);font-size:var(--fs-13);vertical-align:top}
.ord-it-name{font-weight:600}
.ord-it-type{display:inline-block;margin-top:3px;font-size:var(--fs-11);color:var(--muted)}
.ord-items-table tfoot td{padding:8px 10px;font-size:var(--fs-13)}
.ord-items-total td{font-weight:800;font-size:var(--fs-15);border-top:2px solid var(--line)}
.ord-rel{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:8px}
.ord-rel li{display:flex;align-items:center;justify-content:space-between;gap:8px;font-size:var(--fs-13)}
.ord-acts{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:9px}
.ord-act{display:flex;flex-direction:column;gap:1px}
.ord-act-d{font-size:var(--fs-13);color:var(--ink)}

.ord-hist{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:6px}
.ord-hist-row{display:flex;align-items:center;gap:10px;flex-wrap:wrap;padding:9px 10px;border:1px solid var(--line);border-radius:var(--r-sm);color:inherit}
.ord-hist-row:hover{border-color:var(--brand-100);background:var(--brand-050)}
.ord-hist-code{font-weight:700;color:var(--brand-d)}
.ord-hist-total{margin-left:auto;font-weight:700}

@media (max-width:900px){
  .ord-grid,.ord-detail{grid-template-columns:1fr}
  .ord-grid-side,.ord-detail-side{position:static}
}
@media (max-width:640px){
  .ord-table,.ord-table thead,.ord-table tbody,.ord-table tr,.ord-table td{display:block;width:auto}
  .ord-table thead{position:absolute;left:-9999px}
  .ord-table tbody tr{margin:0 0 10px;border:1px solid var(--line);border-radius:var(--r);overflow:hidden;background:var(--card)}
  .ord-table tbody td{border-bottom:1px solid var(--line-2);padding:8px 12px}
  .ord-quick{overflow-x:auto;flex-wrap:nowrap;-webkit-overflow-scrolling:touch}
  .ord-qf{flex:0 0 auto}
  .ord-quick-grid{grid-template-columns:1fr}
  /* CORR01 Fix B — shrinkable tracks (minmax(0,1fr), not 1fr's min-content floor) so line fields never clip at 390/375 */
  .ord-line{grid-template-columns:minmax(0,1fr) minmax(0,1fr);grid-auto-rows:auto;gap:8px 10px}
  .ord-line>*{min-width:0}
  .ord-line-main{grid-column:1 / -1}
  .ord-line-amt{grid-column:1 / -1;text-align:left}
  .ord-detail-head{flex-direction:column}
  .ord-detail-total{text-align:left}
}

/* ============================================================
   CHOTSALE-CRM-INBOX-COMMERCE-01 — compact sales panel inside the
   conversation right drawer (.cw-detail). Reuses order visual tokens;
   shrinkable grids (minmax(0,1fr)) so nothing clips in the narrow drawer.
   ============================================================ */
.cw-commerce .cw-commerce-note{padding:10px 0;line-height:1.5}
.cw-commerce-search{position:relative;margin-bottom:10px}
.cw-commerce .ord-prod-results{position:relative;margin-top:6px}
.ic-lines{display:flex;flex-direction:column;gap:8px}
.ic-lines-empty{padding:10px 0}
.ic-lines-empty[hidden]{display:none}
.ic-line{border:1px solid var(--line);border-radius:var(--r-sm);background:var(--card);padding:8px;min-width:0}
.ic-line-head{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:6px}
.ic-line-name{font-weight:600;font-size:var(--fs-13);color:var(--ink);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}
.ic-line-x{flex:0 0 auto;width:24px;height:24px;border:1px solid var(--line);border-radius:var(--r-sm);background:var(--card);color:var(--muted);cursor:pointer;font-size:15px;line-height:1}
.ic-line-x:hover{border-color:#fecaca;color:#b91c1c;background:#fef2f2}
.ic-line-fields{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr) minmax(0,1fr);gap:6px;align-items:end}
.ic-line-fields>*{min-width:0}
.ic-line-fields label{display:flex;flex-direction:column;gap:2px;font-size:var(--fs-11);color:var(--muted)}
.ic-line-fields .cw-in{width:100%;min-width:0;padding:5px 6px;font-size:var(--fs-12);text-align:right}
.ic-line-amt{grid-column:1 / -1;text-align:right;font-weight:700;font-size:var(--fs-13);margin-top:2px}
.ic-sum{margin-top:10px;display:flex;flex-direction:column;gap:6px;border-top:1px solid var(--line);padding-top:10px}
.ic-sum-row{display:flex;align-items:center;justify-content:space-between;gap:8px;font-size:var(--fs-13)}
.ic-sum-row .ic-disc{max-width:120px;text-align:right;padding:5px 6px}
.ic-sum-total{border-top:1px dashed var(--line);padding-top:8px}
.ic-sum-total b{font-size:var(--fs-16);color:var(--brand-d)}
.ic-note{width:100%;min-width:0;margin-top:8px;resize:vertical}
.cw-commerce .btn-block{margin-top:10px}
.ic-msg{margin-top:8px;font-size:var(--fs-12);text-align:center;min-height:16px}
.ic-msg.is-err{color:#b91c1c;font-weight:600}
.ic-msg.is-ok{color:var(--ok);font-weight:600}
/* FINAL-CORR01 §3.2 — the draft-preserving contact gate inside the Sản phẩm tab (create/link without losing the draft). */
.ic-gate{margin-top:10px;padding:10px;border:1px solid var(--brand-100);border-radius:var(--r-sm);background:var(--brand-050)}
.ic-gate[hidden]{display:none}
.ic-gate-head{font-weight:650;font-size:var(--fs-13);margin-bottom:8px;color:var(--ink)}
.ic-gate-modes{display:flex;gap:6px;margin-bottom:8px}
.ic-gate-mode{flex:1;padding:6px 8px;border:1px solid var(--line);border-radius:var(--r-sm);background:var(--card);font-size:var(--fs-12);cursor:pointer;color:var(--ink-2)}
.ic-gate-mode.is-active{border-color:var(--brand);background:#fff;color:var(--brand-d);font-weight:600}
.ic-gate-panel{display:flex;flex-direction:column;gap:6px}
.ic-gate-panel[hidden]{display:none}
.ic-gate-results{max-height:180px;overflow:auto}
.ic-gate-actions{display:flex;gap:8px;justify-content:flex-end;margin-top:8px}
.ic-gate-actions .btn-brand{flex:1}
.ic-ord-hist{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:6px}
.ic-ord-row{display:flex;align-items:center;gap:8px;flex-wrap:wrap;padding:8px;border:1px solid var(--line);border-radius:var(--r-sm);color:inherit;min-width:0}
.ic-ord-row:hover{border-color:var(--brand-100);background:var(--brand-050)}
.ic-ord-code{font-weight:700;color:var(--brand-d)}
.ic-ord-total{margin-left:auto;font-weight:700;white-space:nowrap}
.ic-ord-date{flex-basis:100%}

/* ============================ CHOTSALE-AI-TRAINING-CENTER-04 — Training Center workspace ============================ */
.tc-wrap{max-width:100%;box-sizing:border-box}
.tc-head{margin:0 0 12px}
.tc-title{font-size:20px;font-weight:700;color:var(--ink);margin:0 0 4px}
.tc-sub{font-size:13px;color:var(--muted);margin:0;max-width:760px}
.tc-tabbar{margin:0 0 16px;flex-wrap:wrap}
.tc-body{min-width:0}
.tc-section{margin-top:20px}
.tc-h2{font-size:15px;font-weight:700;color:var(--ink);margin:0 0 10px}
.tc-h3{font-size:13px;font-weight:700;color:var(--ink-2);margin:14px 0 8px}
/* overview cards */
.tc-cards{display:grid;grid-template-columns:repeat(auto-fill,minmax(180px,1fr));gap:12px;margin:0 0 8px}
.tc-card{display:block;background:var(--card);border:1px solid var(--line);border-radius:10px;padding:14px 16px;text-decoration:none;transition:border-color .15s,box-shadow .15s}
.tc-card:hover{border-color:var(--brand);box-shadow:0 1px 4px rgba(15,23,42,.06)}
.tc-card-v{font-size:26px;font-weight:800;color:var(--ink);line-height:1.1}
.tc-card-t{font-size:12px;color:var(--muted);margin-top:4px}
/* filters */
.tc-filters{display:flex;flex-wrap:wrap;gap:10px;align-items:flex-end;margin:0 0 14px}
.tc-filter{display:flex;flex-direction:column;gap:3px;font-size:12px;color:var(--muted)}
.tc-filter select,.tc-field select,.tc-field textarea,.tc-field input{border:1px solid var(--line);border-radius:8px;padding:7px 9px;font-size:13px;color:var(--ink);background:#fff;max-width:100%;box-sizing:border-box}
/* tables */
.tc-tablewrap{width:100%;overflow-x:auto;border:1px solid var(--line);border-radius:10px;background:var(--card)}
.tc-table{width:100%;border-collapse:collapse;font-size:13px;min-width:640px}
.tc-table th{text-align:left;font-weight:600;color:var(--muted);font-size:11px;text-transform:uppercase;letter-spacing:.03em;padding:9px 12px;border-bottom:1px solid var(--line);white-space:nowrap}
.tc-table td{padding:9px 12px;border-bottom:1px solid var(--line-2);color:var(--ink-2);vertical-align:middle}
.tc-table tr:last-child td{border-bottom:0}
.tc-table tr:hover td{background:#fafbfd}
.tc-num{text-align:right;font-variant-numeric:tabular-nums}
.tc-strong{font-weight:700;color:var(--ink)}
.tc-dim{color:var(--muted-2);font-size:12px;white-space:nowrap}
.tc-link{color:var(--brand);text-decoration:none;font-weight:600}
.tc-link:hover{text-decoration:underline}
.tc-actions{white-space:nowrap;display:flex;gap:6px;align-items:center;justify-content:flex-end}
/* badges + buttons */
.badge-ok{background:var(--ok-bg);color:var(--ok)}
.badge-warn{background:var(--warn-bg);color:var(--warn)}
.badge-danger{background:var(--no-bg);color:var(--no)}
.btn-xs{font-size:12px;padding:4px 9px;border-radius:7px;line-height:1.2}
.tc-mini{font-size:12px;padding:4px 7px;border:1px solid var(--line);border-radius:7px;background:#fff}
/* empty / flash / note */
.tc-empty{padding:26px 16px;text-align:center;color:var(--muted);border:1px dashed var(--line);border-radius:10px;background:var(--card)}
.tc-flash{background:var(--ok-bg);color:var(--ok);border:1px solid var(--ok-dot);border-radius:8px;padding:9px 12px;font-size:13px;margin:0 0 12px}
.tc-note{font-size:12px;color:var(--muted);margin:8px 0 0;line-height:1.5}
/* turn review 2-column */
.tc-review{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,380px);gap:16px;align-items:start}
.tc-review-main{min-width:0}
.tc-review-side{min-width:0;display:flex;flex-direction:column;gap:14px}
.tc-turn{background:var(--card);border:1px solid var(--line);border-radius:10px;padding:12px 14px;margin-bottom:12px}
.tc-turn-ai{border-left:3px solid var(--brand)}
.tc-turn-role{font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.03em;color:var(--muted);margin-bottom:5px}
.tc-turn-body{font-size:14px;color:var(--ink);line-height:1.55;white-space:pre-wrap;word-break:break-word}
.tc-turn-meta{margin-top:6px}
.tc-panel{background:var(--card);border:1px solid var(--line);border-radius:10px;padding:12px 14px}
.tc-chips{display:flex;flex-wrap:wrap;gap:6px}
.tc-list{margin:0;padding:0;list-style:none;display:flex;flex-direction:column;gap:6px;font-size:13px;color:var(--ink-2)}
.tc-list li{line-height:1.5}
/* detail + kv */
.tc-detail{margin:0 0 16px;padding:16px}
.tc-detail-head{display:flex;justify-content:space-between;align-items:flex-start;gap:12px;margin-bottom:10px}
.tc-kv{display:grid;grid-template-columns:repeat(auto-fill,minmax(190px,1fr));gap:8px 18px;margin:0 0 12px}
.tc-kv-row{display:flex;justify-content:space-between;gap:10px;font-size:13px;border-bottom:1px dashed var(--line-2);padding-bottom:5px}
.tc-kv-k{color:var(--muted)}
.tc-kv-v{color:var(--ink);font-weight:600;text-align:right}
.tc-know{font-size:13px;margin:0 0 12px}
/* forms */
.tc-form{display:flex;flex-direction:column;gap:10px}
.tc-inline-form{flex-direction:row;flex-wrap:wrap;align-items:flex-end;background:#fafbfd;border:1px solid var(--line);border-radius:10px;padding:12px;margin:0 0 14px}
.tc-field{display:flex;flex-direction:column;gap:4px;font-size:12px;color:var(--muted)}
.tc-field textarea{resize:vertical;font-family:inherit}
.tc-status-form{display:inline-flex;gap:5px;align-items:center}
/* CHOTSALE-AI-TRAINING-CENTER-05 — feedback→gap ingest cell + create-draft workflow */
.tc-gapcell{min-width:150px}
.tc-ingest-form{display:inline-flex;gap:5px;align-items:center;flex-wrap:wrap}
.tc-draft-form{margin:0 0 16px;padding:16px;max-width:640px}
.tc-draft-form .tc-field span{font-weight:600;color:var(--ink-2)}
.btn-brand.btn-xs{color:#fff}
/* CHOTSALE-AI-TRAINING-CENTER-06 — evaluation / outcome section */
.tc-eval{margin-top:14px}
.tc-eval-outcome{font-size:13px;margin:0 0 8px}
.tc-eval-criteria li{display:flex;gap:6px;align-items:center}
/* CHOTSALE-TRAINING-CENTER-V1-FINAL-CORR02 (§4/§9/§26) — question-first Knowledge Gap UX.
   The customer question is the primary object; taxonomy/counters are secondary. Fluid widths only so the primary
   question and the "Bổ sung kiến thức" action stay obvious at 1440/1280/1024/390/375 with no body overflow. */
.tc-gaplist{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:10px}
.tc-gapcard{display:flex;gap:12px;align-items:flex-start;justify-content:space-between;flex-wrap:wrap;
  border:1px solid var(--line);border-radius:10px;padding:12px 14px;background:var(--card);max-width:100%}
.tc-gapcard-main{flex:1 1 320px;min-width:0}
.tc-gapcard-side{display:flex;flex-direction:column;gap:6px;align-items:flex-end;flex:0 0 auto}
.tc-gapq-label{margin:0 0 2px;font-size:11px;text-transform:uppercase;letter-spacing:.02em;color:var(--ink-2)}
.tc-gapq{display:block;font-size:15px;font-weight:600;line-height:1.35;color:var(--ink);text-decoration:none;overflow-wrap:anywhere}
.tc-gapq:hover{text-decoration:underline}
.tc-gapmiss{margin:6px 0 0;font-size:13px;color:var(--ink-2);overflow-wrap:anywhere}
.tc-gapmiss-label{font-weight:600}
.tc-gapmeta{margin:8px 0 0;display:flex;flex-wrap:wrap;gap:10px;font-size:12px;color:var(--ink-2)}
/* Gap Detail: the human task first, technical metadata collapsed underneath. */
.tc-ask,.tc-missing,.tc-todo,.tc-similar{margin:14px 0 0;max-width:100%}
.tc-askq{margin:4px 0 0;font-size:16px;font-weight:600;line-height:1.4;overflow-wrap:anywhere}
.tc-todo-list li,.tc-qlist li{overflow-wrap:anywhere}
.tc-qlist li{margin:2px 0}
.tc-tech{margin:16px 0 0;border:1px solid var(--line);border-radius:8px;background:var(--bg);max-width:100%}
.tc-tech>summary{cursor:pointer;padding:8px 12px;font-size:12px;font-weight:700;color:var(--ink-2);text-transform:uppercase;letter-spacing:.02em}
.tc-tech .tc-kv{padding:0 12px 12px}
@media(max-width:560px){
  .tc-gapcard{flex-direction:column}
  .tc-gapcard-side{align-items:stretch;width:100%}
  .tc-gapcard-side .btn{width:100%;text-align:center}
}
/* CHOTSALE-TRAINING-CENTER-V1-FINAL-HARDENING-01 (§26) — Guard overblock/underblock verdicts, set apart from the
   evidence criteria so the reviewer reads them as a distinct question. Fluid widths only: the block must not force a
   horizontal viewport at 1440/1280/1024/390/375. */
.tc-eval-guard{margin-top:12px;padding:10px 12px;border:1px solid var(--line);border-radius:8px;background:var(--bg);max-width:100%}
.tc-h4{font-size:12px;font-weight:700;color:var(--ink-2);margin:0 0 8px;text-transform:uppercase;letter-spacing:.02em}
.tc-eval-guard .tc-list{margin:0}
.tc-eval-guard li{overflow-wrap:anywhere}
.tc-eval-guard .tc-note,.tc-eval-guard .tc-dim{margin:8px 0 0}
/* responsive */
@media(max-width:920px){.tc-review{grid-template-columns:1fr}.tc-review-side{order:-1}}
@media(max-width:560px){.tc-cards{grid-template-columns:repeat(auto-fill,minmax(140px,1fr))}.tc-filters{gap:8px}.tc-kv{grid-template-columns:1fr}.tc-actions{flex-wrap:wrap;justify-content:flex-start}.tc-ingest-form{flex-direction:column;align-items:stretch}}

/* CHOTSALE-ZALO-OA-MULTIACCOUNT-01 — a workspace can run several Official Accounts, so the channel page is a
   list of connection cards. Each card owns its own actions; the layout stacks on narrow screens so ten OAs stay
   usable on a phone instead of turning into a horizontally scrolling admin table. */
.oa-list{display:flex;flex-direction:column;gap:12px}
.oa-card{display:flex;align-items:center;justify-content:space-between;gap:14px;flex-wrap:wrap;border:1px solid var(--line);border-radius:10px;padding:12px 14px;background:var(--surface)}
.oa-card>.conv-cell{min-width:0;flex:1 1 260px}
.oa-card-actions{margin-top:0;flex:0 0 auto}
/* CLOSEOUT-07: provider-entitlement notice on an OA card — informative, not an error state. */
.oa-note{margin-top:8px;padding:8px 10px;border-radius:8px;border:1px solid var(--line);background:var(--surface-2,var(--surface))}
.oa-note.warn{border-color:var(--warn,#b7791f)}
.oa-note>.btn{margin-top:6px}
/* PRODUCT-COMPLETION-13: the reason under a failed outbound message. */
.deliv-reason{margin-top:4px;line-height:1.35}
@media (max-width:640px){.oa-card{flex-direction:column;align-items:stretch}.oa-card-actions{width:100%}.oa-card-actions .btn{flex:1 1 auto}}

/* CORR22A §10/§17 — reaction chips. Compact by design: they sit under the bubble as metadata, never as a
   separate message, and they must not add a permanently visible control to every bubble. Mobile keeps the same
   size because a reaction is read, not tapped, on this surface. */
.msg-reacts { position: absolute; top: 100%; margin-top: -9px; right: 8px; z-index: 3;
  display: flex; flex-wrap: nowrap; gap: 3px; }
/* CORR02 SS-E - ZALO-LIKE PLACEMENT. The chips used to be a block INSIDE the bubble, so a reaction added a whole
   extra row to the message and pushed the rest of the conversation down. They are now an overlay pinned to the
   bubble's lower corner and overlapping its edge, which is where Zalo puts them and what "does not add a row"
   requires. Being out of flow the overlay costs zero height by itself; the only reservation is the 9px below on
   .msg.has-reacts, added ONLY to bubbles that actually carry a reaction. Anchoring is on .msg rather than on the
   body, so it lands identically on text, image, video and file cards. */
.msg.in .msg-reacts { right: auto; left: 8px; }
.msg.has-reacts { margin-bottom: 9px; }
.msg-react { display: inline-flex; align-items: center; gap: 3px; padding: 0 6px; border-radius: 999px;
    background: var(--card, #fff); border: 1px solid var(--line, #e3e6ea); box-shadow: 0 1px 3px rgba(0,0,0,.10);
    font-size: 11px; line-height: 17px; }
.msg-react.is-mine { background: var(--accent-soft, #e7f1ff); border-color: var(--accent, #9ec5fe); }
.msg-react .mr-emoji { font-size: 13px; }
.msg-react .mr-count { color: var(--muted, #6b7280); font-variant-numeric: tabular-nums; }

/* CORR22A-2 §3/§17 — the reaction affordance. Hidden until the message is hovered (desktop) or focused/tapped
   (touch): a conversation is read far more often than it is reacted to, so a permanent control on every bubble
   would cost more attention than the feature is worth. On touch there is no hover, so the trigger stays visible
   but small — a control you cannot reveal is a control you do not have. */
.cw-react-wrap { position: absolute; top: 2px; z-index: 5; display: inline-block; margin-top: 0; }
/* CORR02 SS-F - THE TRIGGER MUST NOT COST HEIGHT EITHER.
   Measured at 375x667 on the real transcript: a short text bubble was 57.3px while an INELIGIBLE one (no
   trigger rendered) was 34.3px. The affordance itself was in flow inside the bubble, so every reactable message
   paid ~23px for a control that is invisible until hover. Lifted out of flow and parked just outside the
   bubble's edge - the side the bubble is NOT anchored to, so it never overlaps the text and never leaves the
   thread column. The palette stays anchored to this wrapper, so opening it is unchanged. */
.msg.in .cw-react-wrap { right: -26px; }
.msg.out .cw-react-wrap { left: -26px; }
.cw-react-btn { opacity: 0; transition: opacity .12s ease; background: none; border: 0; padding: 2px 4px;
  cursor: pointer; color: var(--muted, #6b7280); border-radius: 6px; }
.msg:hover .cw-react-btn, .cw-react-btn:focus-visible, .cw-react-wrap.is-busy .cw-react-btn { opacity: 1; }
.cw-react-btn:hover { background: var(--surface-2, #f1f3f5); }
.cw-react-wrap.is-busy { opacity: .6; pointer-events: none; }
.cw-react-wrap.is-error .cw-react-btn { color: var(--danger, #dc2626); opacity: 1; }
.cw-react-pop { position: absolute; bottom: 100%; left: 0; z-index: 30; display: flex; gap: 2px; padding: 4px;
  width: max-content;
  margin-bottom: 4px; background: var(--surface, #fff); border: 1px solid var(--border, #e3e6ea);
  border-radius: 999px; box-shadow: 0 6px 18px rgba(0,0,0,.12); }
/* CORR01 §3 — THE SAME ROOT CAUSE ALREADY FIXED FOR .cw-emoji-pop ABOVE (UI04-CORR-02 §21-22).
   The author `display:flex` on the rule above outranks the UA stylesheet's `[hidden]{display:none}`, so the
   server-rendered `hidden` attribute did nothing: EVERY message rendered its palette permanently open — the
   "large floating emoji rows repeated across bubbles" the Owner reported. Honouring `[hidden]` at author
   specificity (no !important, matching every sibling rule in this file) is what makes CLOSED the default and
   leaves conversation height untouched; the palette is already position:absolute, so it overlays and never
   pushes bubbles apart. */
.cw-react-pop[hidden] { display: none; }
.cw-react-opt { background: none; border: 0; font-size: 18px; line-height: 1; padding: 4px 5px; cursor: pointer;
  border-radius: 999px; }
.cw-react-opt:hover, .cw-react-opt:focus-visible { background: var(--surface-2, #f1f3f5); }
.cw-react-opt.is-on { background: var(--accent-soft, #e7f1ff); }
.msg.out .cw-react-pop { left: auto; right: 0; }
@media (max-width: 640px) {
  /* Touch has no hover: keep the trigger reachable, and let the palette wrap rather than overflow the viewport. */
  .cw-react-btn { opacity: .65; }
  /* CORR02 SS-D/SS-E - WHY THE MOBILE PALETTE RENDERED AS A TALL VERTICAL RAIL.
     .cw-react-pop is absolutely positioned inside .cw-react-wrap, an inline-block that wraps only the small
     trigger button - about 24px wide. An absolutely positioned box shrink-to-fits against its CONTAINING BLOCK,
     so the available width WAS those 24px; max-width:78vw raises a ceiling but never the available width. On
     desktop nothing wrapped, so the row simply overflowed the box and happened to look right; on mobile the
     flex-wrap:wrap added here turned 24px into one emoji per line - the vertical column covering the
     conversation in the Owner's screenshot.
     width:max-content sizes the palette to its content instead of to the trigger, so it is horizontal first.
     Wrapping stays as the fallback, bounded so a narrow viewport wraps compactly instead of overflowing:
     7 tokens at ~29px is ~205px, a single row even at 375px. */
  .cw-react-pop { width: max-content; max-width: min(78vw, 320px); flex-wrap: wrap; border-radius: 12px; }
  /* keep the palette inside the viewport when the bubble sits at either edge */
  .msg.out .cw-react-pop { right: 0; left: auto; }
  .msg.in .cw-react-pop { left: 0; right: auto; }
}

/* AI-CHANNEL-CONTROL-01 §10/§15 — the unclaimed-composer hint. One row on desktop, wraps on mobile so the
   call to action never pushes itself off screen. */
.cw-claim-hint{display:flex;align-items:center;gap:10px;flex-wrap:wrap;justify-content:space-between}
.cw-claim-hint .btn{flex:0 0 auto}
/* The suggest button while a draft is in flight: the label changes and the control is inert, so a second
   click cannot queue a second provider call. */
.btn.cw-ai[aria-busy="true"]{opacity:.7;pointer-events:none}

/* AI-CHANNEL-CONTROL-01-UI §B/§D/§K — the AI state control.
   One pill that READS as the current state, and a menu that only opens on demand. The pill text truncates rather
   than pushing the header wide, because the header already carries the customer, the channel and the assignee. */
.ai-ctl{position:relative;display:inline-block}
.ai-pill{display:inline-flex;align-items:center;gap:5px;max-width:190px;white-space:nowrap}
.ai-pill .ai-pill-txt{overflow:hidden;text-overflow:ellipsis}
.ai-pill.is-gated{border-style:dashed;opacity:.85}
.ai-pill.is-handoff{border-color:var(--warn,#c47f17);color:var(--warn,#c47f17)}
.ai-menu{position:absolute;right:0;top:calc(100% + 6px);z-index:40;min-width:260px;max-width:min(320px,92vw);
  background:var(--surface,#fff);border:1px solid var(--line,#e3e6ea);border-radius:10px;
  box-shadow:0 8px 28px rgba(16,24,40,.14);padding:6px;display:flex;flex-direction:column;gap:2px}
.ai-menu[hidden]{display:none}
.ai-menu-h{padding:8px 10px 4px;font-weight:600}
.ai-menu-reason,.ai-menu-why{padding:0 10px 8px}
.ai-menu-act{padding:4px 6px}
.ai-menu-act .btn{width:100%}
.ai-opt{display:flex;gap:9px;align-items:flex-start;width:100%;text-align:left;background:none;border:0;
  padding:9px 10px;border-radius:8px;cursor:pointer;min-height:44px}
.ai-opt:hover,.ai-opt:focus-visible{background:var(--brand-050,#eef4ff)}
.ai-opt.is-on{background:var(--brand-050,#eef4ff)}
.ai-opt.is-on .ai-opt-txt strong::after{content:' ✓';color:var(--brand-d,#1c4ed8)}
.ai-opt-txt{display:flex;flex-direction:column;min-width:0}
.ai-opt-ico{flex:0 0 auto;line-height:1.4}

/* The settings list. One row per connected account, wrapping on narrow screens rather than scrolling sideways. */
.ai-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:8px}
.ai-row{border:1px solid var(--line,#e3e6ea);border-radius:10px;padding:10px 12px}
.ai-row-main{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.ai-row-id{display:flex;flex-direction:column;min-width:0;flex:1 1 180px}
.ai-row-sum{flex:1 1 200px;min-width:0}
.ai-row-ctl{flex:0 0 auto;margin-left:auto}
.ai-row-sched{margin-top:10px;padding-top:10px;border-top:1px dashed var(--line,#e3e6ea)}
.ai-sched{display:flex;flex-direction:column;gap:8px}
.ai-sched-row{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.ai-sched-row>span:first-child{flex:0 0 110px}
.ai-days{display:flex;gap:6px;flex-wrap:wrap}
.ai-day{display:inline-flex;align-items:center;justify-content:center;min-width:44px;min-height:36px;
  border:1px solid var(--line,#e3e6ea);border-radius:8px;cursor:pointer;padding:0 8px}
.ai-day input{position:absolute;opacity:0;width:0;height:0}
.ai-day.is-on{background:var(--brand-050,#eef4ff);border-color:var(--brand,#2563eb);font-weight:600}
.ai-times{display:inline-flex;align-items:center;gap:6px;flex-wrap:wrap}

/* §K mobile: the pill must not eat the header. It keeps its own line under the badges and the menu becomes a
   bottom sheet, so the options stay thumb-sized instead of shrinking to fit a dropdown. */
@media (max-width:640px){
  .ai-pill{max-width:150px}
  /* CORR05 §K — this pushed .ai-ctl to the END of .cw-head back when the caretaker had to get past the badge
     group. Both the caretaker AND the assignee carry .ai-ctl, so with a third control in the row it put Đóng
     FIRST on a phone (seen in Chromium at 375). Order is now stated explicitly, in §K's priority order. */
  .cw-ai-state .ai-menu{position:fixed;left:8px;right:8px;bottom:8px;top:auto;max-width:none;min-width:0;
    border-radius:14px;padding:8px;box-shadow:0 -6px 28px rgba(16,24,40,.22)}
  .ai-opt{min-height:52px}
  .ai-row-ctl{margin-left:0;width:100%}
  .ai-row-ctl .ai-ctl,.ai-row-ctl .ai-pill{width:100%;max-width:none;justify-content:space-between}
  .ai-sched-row>span:first-child{flex:1 1 100%}
}

/* CHOTSALE-AI-CHANNEL-CONTROL-UX-BULK-SCHEDULE-CORR01 — the AI chăm sóc workspace.
   Built to stay usable at 500 accounts: the list scrolls vertically, every row wraps, and nothing relies on a
   wide viewport. */
.ai-tabs{display:flex;gap:6px;flex-wrap:wrap;margin:10px 0 8px}
.ai-tab{border:1px solid var(--line,#e3e6ea);background:none;border-radius:999px;padding:7px 12px;
  cursor:pointer;min-height:38px;white-space:nowrap}
.ai-tab.is-on{background:var(--brand-050,#eef4ff);border-color:var(--brand,#2563eb);font-weight:600}
.ai-tab-n{opacity:.65;font-variant-numeric:tabular-nums}
.ai-sum{display:flex;align-items:center;gap:10px;flex-wrap:wrap;padding:8px 10px;margin-bottom:8px;
  border:1px dashed var(--line,#e3e6ea);border-radius:8px}
.ai-sum-bits{display:flex;gap:12px;flex-wrap:wrap}
.ai-toolbar{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin-bottom:8px}
.ai-search{flex:1 1 220px;min-width:0}
.ai-pick{display:inline-flex;align-items:center;gap:8px;cursor:pointer;min-height:44px;min-width:44px}
.ai-pick-all{flex:0 0 auto}
.ai-count{margin-left:auto;font-variant-numeric:tabular-nums}

/* The bulk bar earns its space: hidden until something is selected, sticky once it is, so the actions stay
   reachable however far down a 500-row list the Owner has scrolled. */
.ai-bulkbar{position:sticky;top:0;z-index:5;display:flex;align-items:center;gap:12px;flex-wrap:wrap;
  padding:10px 12px;margin-bottom:8px;border-radius:10px;background:var(--brand-050,#eef4ff);
  border:1px solid var(--brand,#2563eb)}
.ai-bulkbar[hidden]{display:none}
.ai-bulk-n{font-weight:600}
.ai-bulk-acts{display:flex;align-items:center;gap:6px;flex-wrap:wrap;margin-left:auto}
.ai-bulk-btn{white-space:nowrap}
.ai-list{max-height:none}
.ai-empty{padding:14px 4px}

/* The schedule dialog. Centred on desktop, a bottom sheet on a phone. */
.ai-modal{position:fixed;inset:0;z-index:60;background:rgba(16,24,40,.45);display:flex;align-items:center;
  justify-content:center;padding:16px}
.ai-modal[hidden]{display:none}
.ai-modal-box{background:var(--surface,#fff);border-radius:14px;padding:16px;width:min(520px,100%);
  max-height:90vh;overflow:auto;box-shadow:0 18px 50px rgba(16,24,40,.28)}
.ai-modal-box h3{margin:0 0 12px}
.ai-modal-sec{margin-bottom:14px}
.ai-radio{display:flex;align-items:center;gap:8px;min-height:44px;cursor:pointer}
.ai-presets{display:flex;gap:6px;flex-wrap:wrap;margin-top:8px}
.ai-modal .ai-times{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.ai-modal-prev{border:1px solid var(--line,#e3e6ea);border-radius:10px;padding:10px 12px;margin-bottom:14px;
  display:flex;flex-direction:column;gap:6px}
.ai-prev-row{display:flex;justify-content:space-between;gap:12px;flex-wrap:wrap}
.ai-modal-acts{display:flex;justify-content:flex-end;gap:8px}
.ai-err{color:var(--danger,#b42318);margin-top:6px}
.ai-err[hidden]{display:none}

@media (max-width:640px){
  /* Bottom sheet: the dialog meets the thumb rather than the middle of the screen. */
  .ai-modal{align-items:flex-end;padding:0}
  .ai-modal-box{width:100%;border-radius:16px 16px 0 0;max-height:92vh}
  .ai-bulkbar{flex-direction:column;align-items:stretch}
  .ai-bulk-acts{margin-left:0}
  .ai-bulk-btn{width:100%;justify-content:center}
  .ai-count{margin-left:0;width:100%}
  .ai-tab{flex:1 1 auto;text-align:center}
  .ai-modal-acts .btn{flex:1 1 auto;min-height:48px}
}

/* CHOTSALE-AI-INBOX-STATE-UX-CORR02 §J — the caretaker control must survive every breakpoint.
   .cw-head-badges is display:none below 1100px; the caretaker used to live inside it and disappeared with it,
   which is why production acceptance found no AI control on a phone. It now has its own container that is never
   hidden, and shrinks to an icon-and-caret pill on the narrowest screens rather than being removed. */
.cw-head-care{flex:0 0 auto;display:flex;align-items:center;margin-left:auto}
@media (max-width:1100px){.cw-head-care{display:flex}}
/* CORR05 §I — the 40px pill and the sr-only label that used to live here are SUPERSEDED, not shadowed: 40px
   failed the 44px touch minimum, and clipping the label left two indistinguishable icon buttons once §F removed
   the text line below them. Both now live in the CORR05 block, and this one no longer contradicts it. */

/* CHOTSALE-INBOX-HEADER-VISUAL-ACTION-POLISH-CORR05 §D/§E/§I/§J — the header controls.

   CORR04 made the header STRUCTURALLY right (three surfaces, one writer each) and left it looking wrong: three
   pale 1px pills that read as generic filter chips, so the one control that says whether a robot or a person is
   answering the customer carried the same visual weight as a dropdown for sorting a table. Nothing here changes
   what the controls DO. What changes is that they look like controls, they differ from each other, and the
   status beside them looks like text.

   The shared shape is .cw-pill. Caretaker and assignee then diverge deliberately (§E): the caretaker is tinted by
   STATE, the assignee is fronted by a FACE. Tints stay pale — a saturated fill on a control reporting a perfectly
   normal condition reads as an alarm, and after the third one nobody reads any of them. */
/* .btn.xs sets min-height:0 at (0,2,0); a bare .cw-pill (0,1,0) loses to it and the pills collapsed to 21px.
   Chromium found this — a string assertion against the stylesheet could not. Scoped to the container rather than
   to .btn, because the read-only assignee surface is a <span>, not a button, and it needs the same box. */
/* CORR05R1 §A — THE PILLS HAD NO HOVER, AND IT WAS A CASCADE DEFECT, NOT A MISSING RULE.
   `.cw-ai-state .cw-pill.is-ai` is THREE classes — specificity (0,3,0). `.cw-pill:hover` is one class plus a
   pseudo-class — (0,2,0). The state tint therefore won every paint property it declared, in every caretaker
   state, at every width: Chromium measured the hovered background and border as byte-identical to the resting
   ones (delta 0.0, 24/24 state×viewport combinations). `.as-pill.is-assigned` did the same to the assignee.

   Reordering the rules would fix today's file and leave the trap armed: the next variant class anyone adds
   silently outranks every interaction state again. So the fight is removed instead of won. STATE RULES NOW SET
   ONLY CUSTOM PROPERTIES; the base, hover and open rules are the only things that ever assign `background` or
   `border-color`. A custom property resolves at use time, so a variant can no longer beat an interaction —
   there is nothing for it to beat. The fix uses no forced declarations at all, and needed none.

   §B restraint: hover DEEPENS the state's own hue rather than replacing it with a neutral wash, so the
   AI/Human/Handoff identity survives being pointed at. */
.cw-head-care .cw-pill{min-height:36px;padding:0 10px;gap:7px;font-weight:600;
  border:1px solid var(--pill-bd,var(--line,#d7dbe0));
  border-radius:var(--r-pill,999px);background:var(--pill-bg,#fff);color:var(--ink,#111827);
  transition:background .12s,border-color .12s,box-shadow .12s}
.cw-pill-ico{flex:0 0 auto;font-size:15px;line-height:1}
/* The chevron is the affordance: it must survive the label being ellipsised, so it never shrinks. */
.cw-caret{flex:0 0 auto;color:var(--ink-3,#6b7280);font-size:11px;line-height:1}

/* §D caretaker — one palette per derived AiCaretakerState. Colours only; no paint properties, so nothing here
   can out-specify an interaction state ever again. */
.cw-ai-state .cw-pill.is-ai{--pill-bg:#f4f7ff;--pill-bd:#c7d7fb;--pill-bg-h:#e7eeff;--pill-bd-h:#a3bef7;color:#1c3fa8}
.cw-ai-state .cw-pill.is-human{--pill-bg:#f7f9fb;--pill-bd:#d3dae2;--pill-bg-h:#eef2f7;--pill-bd-h:#b2bdcb;color:#334155}
.cw-ai-state .cw-pill.is-handoff{--pill-bg:#fff8ee;--pill-bd:#f0c99a;--pill-bg-h:#fdeed6;--pill-bd-h:#e0a761;color:#9a5b06}
.cw-ai-state .cw-pill.is-handoff .cw-caret{color:#b8761a}

/* §E assignee — a person, not a state. The initial avatar does the differentiating work; the pill itself stays
   neutral so the two controls cannot be confused at a glance even in greyscale. */
.as-pill{max-width:210px;--pill-bg-h:#f4f7fa;--pill-bd-h:#b6bec8}
.as-pill.is-assigned{--pill-bg:#fbfcfe;--pill-bd:#cfd8e3;--pill-bg-h:#f0f4f9;--pill-bd-h:#aab8c8}
.as-pill .lead-ava{width:22px;height:22px;font-size:11px;border-radius:var(--r-pill,999px)}
.as-face-none{flex:0 0 auto;display:inline-flex;color:var(--ink-3,#8b95a1)}
/* The read-only surface is a <span>, not a control: it must NOT pick up the hover affordance. Stated at
   (0,4,0) so it outranks the shared interaction rule below rather than relying on where it sits in the file. */
.as-pill.is-static{opacity:.9;cursor:default}
.cw-head-care .as-pill.is-static:hover{--pill-bg-h:var(--pill-bg,#fff);--pill-bd-h:var(--pill-bd,var(--line,#d7dbe0));
  box-shadow:none}

/* §B Đóng — secondary by default, destructive only on hover/focus. A permanently red button in a header the
   staff look at all day is a standing invitation to misread the whole row as dangerous.

   These two measured as ALREADY WORKING at (0,2,0)-later-wins, but only by file order: any future
   `.cw-head-care .cw-close`-shaped rule added below would have silently killed them, which is exactly how the
   caretaker hover died. Scoped to the container so they win on specificity, not on luck. */
.cw-head-care .cw-close,.cw-head-care .cw-reopen{min-height:36px;padding:0 10px;gap:6px;border:1px solid var(--line,#d7dbe0);background:#fff;
  color:var(--ink-2,#4b5563);font-weight:600;transition:background .12s,border-color .12s,color .12s,box-shadow .12s}
.cw-head-care .cw-close:hover,.cw-head-care .cw-close:focus-visible{border-color:#e2a2a2;background:#fef2f2;
  color:var(--danger,#b91c1c);box-shadow:0 0 0 3px rgba(220,38,38,.10)}
.cw-head-care .cw-close:focus-visible{outline:2px solid var(--danger,#dc2626);outline-offset:2px}
.cw-head-care .cw-reopen:hover,.cw-head-care .cw-reopen:focus-visible{border-color:var(--brand,#2563eb);
  background:var(--brand-050,#eef4ff);color:var(--brand-d,#1d4ed8);box-shadow:0 0 0 3px rgba(37,99,235,.10)}
.cw-head-care .cw-reopen:focus-visible{outline:2px solid var(--brand,#2563eb);outline-offset:2px}
.cw-closef{margin:0;display:inline-flex}

/* ---- THE INTERACTION STATES. One place, after every palette, consuming only custom properties. -------------
   Order within this block is deliberate: hover, then OPEN, so a pill that is both reads as open (the stronger
   state). Focus is an outline, which composes with either. */
.cw-head-care .cw-pill:hover{background:var(--pill-bg-h,var(--surface-2,#f6f8fb));
  border-color:var(--pill-bd-h,var(--ink-3,#9aa3ad));box-shadow:0 1px 2px rgba(16,24,40,.06)}
.cw-head-care .cw-pill:hover .cw-caret{color:var(--ink,#111827)}
.cw-head-care .cw-pill:focus-visible{outline:2px solid var(--brand,#2563eb);outline-offset:2px}
.cw-head-care .cw-pill[aria-expanded="true"]{border-color:var(--brand,#2563eb);
  box-shadow:0 0 0 3px var(--brand-050,#eef4ff)}
.cw-head-care .cw-pill[aria-expanded="true"] .cw-caret{color:var(--brand-d,#1d4ed8)}

/* §G status — a LABEL. No border, no fill, no pointer: it must not read as a fourth control. */
.cw-statusline{margin-top:3px}
.cw-status{display:inline-flex;align-items:center;gap:6px;font-size:var(--fs-12,12px);font-weight:600;
  color:var(--ink-3,#6b7280)}
.cw-status-dot{width:7px;height:7px;border-radius:50%;background:currentColor;flex:0 0 auto}
.cw-status.is-ok{color:#12805c}
.cw-status.is-warn{color:#9a5b06}
.cw-status.is-off{color:var(--ink-3,#6b7280)}

/* §J the dropdowns — a staff picker, not a settings dialog. */
.as-menu{min-width:248px;max-width:min(300px,92vw)}
.ai-menu-sep{height:1px;background:var(--line,#e3e6ea);margin:6px 4px}
.ai-menu-h.as-sub{padding-top:8px}
.as-cur{display:flex;align-items:center;gap:9px;padding:8px 10px;border-radius:8px;
  background:var(--brand-050,#eef4ff);font-weight:600}
.as-cur .lead-ava{width:26px;height:26px;font-size:12px}
.as-check{color:var(--brand-d,#1c4ed8);font-weight:700;margin-left:auto}
.as-search{margin:4px 6px 6px;width:calc(100% - 12px)}
.as-list{max-height:260px;overflow-y:auto;display:flex;flex-direction:column;gap:2px}
.as-opt-f{margin:0}
.as-opt{display:flex;align-items:center;gap:9px;width:100%;text-align:left;background:none;border:0;
  padding:7px 10px;border-radius:8px;cursor:pointer;min-height:44px}
.as-opt .lead-ava{width:26px;height:26px;font-size:12px}
.as-opt:hover,.as-opt:focus-visible{background:var(--brand-050,#eef4ff)}
.as-opt.is-on{background:var(--brand-050,#eef4ff);font-weight:600}
.as-opt-n{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

/* §L — the header menus must clear the right customer panel rather than slide under it. */
.cw-head-care .ai-menu{z-index:70}
.cw-head-care{gap:8px}

/* §I/§K MOBILE — the visual pill may stay compact, but the TAP TARGET may not. CORR04 shipped 40px pills and a
   21px ellipsis; the ellipsis is gone and all three survivors are >=44px on touch. The row wraps to its own line
   rather than shrinking, so nothing has to be hidden to fit. */
@media (max-width:640px){
  .cw-head-care{flex-wrap:wrap;gap:8px;row-gap:8px;flex:1 1 100%;min-width:0;max-width:100%;margin-left:0}
  .cw-head-care .cw-pill,.cw-head-care .cw-close,.cw-head-care .cw-reopen{min-height:44px;padding:0 12px}
  /* §K priority order is caretaker, assignee, close — and the LABELS stay. CORR04 clipped .ai-pill-txt to a 1px
     sr-only box at this breakpoint, leaving two identical-looking icon buttons; §F then removed the text line that
     had been compensating for it. Both keep their words, ellipsised if they must. */
  .cw-head-care .ai-pill-txt{position:static;width:auto;height:auto;clip:auto;overflow:hidden;text-overflow:ellipsis}
  .cw-head-care .cw-pill{max-width:100%;flex:1 1 auto;min-width:0;justify-content:flex-start}
  .cw-head-care .ai-ctl{min-width:0;flex:1 1 auto;display:flex}
  /* §K priority: caretaker, assignee, close — asserted by measuring their x positions in a real browser. */
  .cw-head-care .cw-ai-state{order:1}
  .cw-head-care .as-ctl,.cw-head-care .as-pill.is-static{order:2}
  .cw-head-care .cw-closef{order:3;flex:0 0 auto}
  .as-pill{max-width:none}
  .as-menu{position:fixed;left:8px;right:8px;bottom:8px;top:auto;max-width:none;min-width:0;
    border-radius:14px;padding:8px;box-shadow:0 -6px 28px rgba(16,24,40,.22)}
  .as-list{max-height:46vh}
  .as-opt{min-height:48px}
  /* The AI suggest button becomes icon-only beside the send button; the accessible name is on the button. */
  .cw-ai .cw-ai-label{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
  .btn.cw-ai{min-width:44px;min-height:44px;justify-content:center}
}
/* §K 375/390 — Đóng collapses to its icon (aria-label + title stay the full sentence) so caretaker and assignee
   keep their labels on the narrowest phones. The hit target does NOT shrink with the label. */
@media (max-width:430px){
  .cw-close .cw-close-lbl,.cw-reopen .cw-close-lbl{position:absolute;width:1px;height:1px;overflow:hidden;
    clip:rect(0 0 0 0);white-space:nowrap}
  .cw-head-care .cw-close,.cw-head-care .cw-reopen{flex:0 0 auto;min-width:44px;padding:0;justify-content:center}
}

/* META-SOCIAL-UI-FOUNDATION-01 — content workspace. Grid-based so it reflows on narrow widths without any
   horizontal scroll: the month collapses from 7 columns to 4 rather than overflowing (§14, 390/375px). */
.cal-grid{display:grid;grid-template-columns:repeat(7,minmax(0,1fr));gap:6px;margin:12px 0}
.cal-cell{min-height:64px;border:1px solid var(--line,#e6e6ef);border-radius:8px;padding:6px;font-size:var(--fs-13,13px)}
.cal-cell.is-blank{border-style:dashed;opacity:.45}
.cal-day{color:var(--muted,#6b7280)}
.cw-tiles{display:grid;grid-template-columns:repeat(auto-fill,minmax(160px,1fr));gap:10px;margin-top:12px}
.cw-tile{border:1px solid var(--line,#e6e6ef);border-radius:10px;padding:12px;display:flex;flex-direction:column;gap:4px}
.cw-tile.is-disabled{opacity:.55}
.content-list{margin-top:12px}
@media (max-width:640px){
  .cal-grid{grid-template-columns:repeat(4,minmax(0,1fr))}
  .cal-cell{min-height:52px}
  .filters{flex-wrap:wrap}
  .filters select,.filters input{min-width:0;flex:1 1 46%}
}


/* ============================================================================================================
   DELTA-15 — SOCIAL PUBLISHING: the compose workspace and the posts list.
   ============================================================================================================
   THE OVERFLOW BUG THIS BLOCK EXISTS TO FIX, stated once so it is not reintroduced.

   The old composer was a `<dialog class="cw-modal">`. `.cw-modal` belongs to the CRM's div-based modal system and
   declares `position:fixed;inset:0;display:flex` — an author `display:flex` that beats the UA's
   `dialog:not([open]){display:none}` — so the composer was a permanently-mounted full-screen overlay fighting the
   browser's own dialog behaviour, wrapped around a stack of native `<fieldset>`s and `.sp-*`/`.cw-field` classes
   that had NO rules at all. It did not need narrower widths; it needed to stop being a modal.

   The two rules that actually prevent horizontal overflow here, and which every future edit must preserve:
     1. `min-width:0` on every grid/flex child. A grid item's default `min-width:auto` refuses to shrink below its
        content, so ONE long Page name or unbroken URL pushes the whole layout sideways. This is the fix; media
        queries are not.
     2. `overflow-wrap:anywhere` on anything holding user or provider text (Page names, post bodies, error
        reasons, permalinks). Tenants really do name Fanpages with 60 unbroken characters.
   ============================================================================================================ */

/* ---- compose workspace shell ---- */
.spc{display:block}
.spc-head{display:flex;align-items:center;justify-content:space-between;gap:16px;flex-wrap:wrap;
  padding:0 0 14px;border-bottom:1px solid var(--line-2);margin-bottom:16px}
.spc-head-t{min-width:0}
.spc-head h1{margin:2px 0 0;font-size:var(--fs-22);line-height:1.25}
.spc-back{display:inline-block;font-size:var(--fs-13);color:var(--muted);text-decoration:none}
.spc-back:hover{color:var(--brand)}
.spc-chans{display:flex;gap:8px;flex-wrap:wrap;min-width:0}
.spc-chan{display:inline-flex;align-items:center;gap:6px;padding:6px 12px;border:1px solid var(--line);
  border-radius:999px;font-size:var(--fs-13);background:var(--card);cursor:pointer}
.spc-chan.is-on{border-color:var(--brand);background:var(--brand-050);color:var(--brand-d);font-weight:600}
.spc-chan.is-off{opacity:.6;cursor:not-allowed}
.spc-chan-why{font-style:normal;font-size:var(--fs-11);color:var(--muted);
  background:var(--line-2);border-radius:999px;padding:1px 7px}

/* Two columns on the desktop, one below 1080px. `minmax(0,1fr)` is load-bearing — see rule 1 above. */
.spc-grid{display:grid;grid-template-columns:minmax(0,1fr) 340px;gap:16px;align-items:start}
.spc-main,.spc-side{display:flex;flex-direction:column;gap:16px;min-width:0}
.spc-side{position:sticky;top:12px}

.spc-card{padding:16px 18px;min-width:0}
.spc-card-head{display:flex;align-items:center;justify-content:space-between;gap:12px;margin:0 0 12px;min-width:0}
.spc-card-head h2{margin:0;font-size:var(--fs-15);font-weight:600;color:var(--ink)}

/* ---- editor ---- */
.spc-toolbar{display:flex;gap:4px;margin-bottom:8px;flex-wrap:wrap}
.spc-tool{border:1px solid var(--line);background:var(--card);border-radius:8px;width:34px;height:32px;
  cursor:pointer;font-size:15px;line-height:1;color:var(--ink-2)}
.spc-tool:hover{background:var(--line-2)}
.spc-tool:focus-visible{outline:2px solid var(--brand);outline-offset:1px}
/* `resize:vertical` + a bounded max-height: a long post grows the textarea, never the page layout. */
.spc-editor{width:100%;max-width:100%;box-sizing:border-box;min-height:180px;max-height:46vh;resize:vertical;
  border:1px solid var(--line);border-radius:10px;padding:12px 14px;font:inherit;font-size:var(--fs-14);
  line-height:1.55;color:var(--ink);background:var(--card)}
.spc-editor:focus{outline:none;border-color:var(--brand);box-shadow:0 0 0 3px var(--brand-050)}
.spc-count{font-size:var(--fs-12);color:var(--muted);font-variant-numeric:tabular-nums}
.spc-count.is-long{color:var(--warn)}

/* ---- AI panel ---- */
.spc-ai{margin-top:12px;border:1px solid var(--line-2);border-radius:10px;padding:12px;background:var(--bg)}
.spc-ai-head{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-bottom:8px;font-size:var(--fs-13)}
.spc-ai-head .ic{color:var(--brand)}
.spc-ai-tones{display:flex;gap:6px;flex-wrap:wrap;margin-bottom:8px}
.spc-ai-tones .btn.is-on{background:var(--brand);color:#fff;border-color:var(--brand)}
.spc-ai-row{display:flex;gap:8px;min-width:0}
.spc-ai-instr{flex:1 1 auto;min-width:0;border:1px solid var(--line);border-radius:8px;padding:7px 10px;
  font:inherit;font-size:var(--fs-13)}
.spc-ai-out{margin-top:10px;padding:10px 12px;border:1px solid var(--line);border-radius:8px;background:var(--card);
  font-size:var(--fs-13);line-height:1.55;white-space:pre-wrap;overflow-wrap:anywhere}
.spc-ai-out .btn{margin-top:8px;margin-right:6px}
.spc-ai-out.is-error{border-color:var(--no);color:var(--no);background:var(--no-bg)}
.spc-ai-off{margin:10px 0 0}

/* ---- media manager ---- */
.spc-modes{display:inline-flex;border:1px solid var(--line);border-radius:9px;overflow:hidden;margin-bottom:6px}
.spc-mode{appearance:none;border:0;background:var(--card);padding:7px 16px;font:inherit;font-size:var(--fs-13);
  color:var(--muted);cursor:pointer;border-right:1px solid var(--line)}
.spc-mode:last-child{border-right:0}
.spc-mode.is-on{background:var(--brand);color:#fff;font-weight:600}
.spc-modes-why{margin:0 0 12px}
/* DELTA-16 - Instagram's own rules, shown only while an Instagram destination is selected. It is a callout
   rather than more grey small print because it carries a REFUSAL a user is likely to meet (JPG only) and one
   that has no Facebook equivalent at all (no text-only post). min-width:0 and overflow-wrap keep it inside the
   grid column at every width, which is the rule the whole composer layout depends on. */
.spc-ig-rules{margin:0 0 12px;padding:10px 12px;border:1px solid var(--line);border-left:3px solid var(--brand);
  border-radius:9px;background:var(--bg);min-width:0;overflow-wrap:anywhere}
.spc-ig-rules[hidden]{display:none}
.spc-ig-rules strong{display:block;font-size:var(--fs-12);margin-bottom:5px;color:var(--ink)}
.spc-ig-rules ul{margin:0;padding-left:18px}
.spc-ig-rules li{font-size:var(--fs-12);color:var(--muted);line-height:1.55;margin-bottom:2px}
.spc-drop{border:1.5px dashed var(--line);border-radius:12px;padding:20px 16px;text-align:center;background:var(--bg)}
.spc-drop.is-over{border-color:var(--brand);background:var(--brand-050)}
.spc-drop[aria-disabled="true"]{opacity:.55}
.spc-drop-t{margin:0 0 8px;font-size:var(--fs-13);color:var(--muted)}
.spc-drop p:last-child{margin:8px 0 0}
.spc-pick{position:relative;overflow:hidden;display:inline-block}
.spc-pick input[type=file]{position:absolute;inset:0;opacity:0;width:100%;height:100%;cursor:pointer}
.spc-gallery{display:grid;grid-template-columns:repeat(auto-fill,minmax(110px,1fr));gap:10px;margin-top:12px}
.spc-gallery:empty{display:none}
.spc-item{position:relative;border:1px solid var(--line);border-radius:10px;overflow:hidden;background:var(--card);
  min-width:0}
.spc-item img,.spc-item video{display:block;width:100%;height:88px;object-fit:cover;background:var(--line-2)}
.spc-item-name{display:block;padding:5px 7px;font-size:var(--fs-11);color:var(--muted);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.spc-item-x{position:absolute;top:5px;right:5px;width:22px;height:22px;border:0;border-radius:50%;
  background:rgba(15,23,42,.72);color:#fff;font-size:15px;line-height:1;cursor:pointer}
.spc-item.is-busy{opacity:.55}
.spc-media-err{margin:10px 0 0;color:var(--no);font-size:var(--fs-13);overflow-wrap:anywhere}

/* ---- per-page variants ---- */
.spc-radio{display:flex;align-items:flex-start;gap:9px;padding:7px 0;font-size:var(--fs-14);cursor:pointer;
  min-width:0}
.spc-radio input{margin-top:3px;flex:0 0 auto}
.spc-radio span{min-width:0;overflow-wrap:anywhere}
.spc-var-bulk{display:flex;gap:8px;flex-wrap:wrap;margin:10px 0 4px}
.spc-vars{display:flex;flex-direction:column;gap:8px;margin-top:10px}
.spc-var{border:1px solid var(--line);border-radius:10px;padding:0;background:var(--card);min-width:0}
.spc-var>summary{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:10px 14px;
  cursor:pointer;font-size:var(--fs-13);min-width:0}
.spc-var>summary::-webkit-details-marker{display:none}
.spc-var-name{font-weight:600;color:var(--ink);min-width:0;overflow-wrap:anywhere}
.spc-var-state{flex:0 0 auto;font-size:var(--fs-11);color:var(--muted);background:var(--line-2);
  border-radius:999px;padding:2px 9px}
.spc-var.is-custom .spc-var-state{background:var(--brand-050);color:var(--brand-d)}
.spc-var-body{display:block;width:calc(100% - 28px);max-width:100%;box-sizing:border-box;margin:0 14px 10px;
  border:1px solid var(--line);border-radius:8px;padding:10px 12px;font:inherit;font-size:var(--fs-13);
  line-height:1.55;resize:vertical}
.spc-var-acts{display:flex;gap:6px;flex-wrap:wrap;padding:0 14px 12px}
.spc-var-err{margin:0 14px 12px;color:var(--no);font-size:var(--fs-12);overflow-wrap:anywhere}

/* ---- preview ---- */
.spc-prev-pick{max-width:200px;min-width:0;border:1px solid var(--line);border-radius:8px;padding:5px 8px;
  font:inherit;font-size:var(--fs-12)}
.spc-prev{border:1px solid var(--line);border-radius:10px;padding:14px;background:var(--card);min-width:0}
.spc-prev-head{display:flex;align-items:center;gap:10px;margin-bottom:10px;min-width:0}
.spc-prev-av{flex:0 0 auto;width:38px;height:38px;border-radius:50%;background:var(--brand-050)}
.spc-prev-head>div{min-width:0}
.spc-prev-head strong{display:block;font-size:var(--fs-13);overflow-wrap:anywhere}
.spc-prev-body{margin:0 0 10px;font-size:var(--fs-14);line-height:1.55;white-space:pre-wrap;
  overflow-wrap:anywhere;color:var(--ink)}
.spc-prev-media{display:grid;grid-template-columns:repeat(auto-fit,minmax(120px,1fr));gap:4px}
.spc-prev-media:empty{display:none}
.spc-prev-media img,.spc-prev-media video{width:100%;height:120px;object-fit:cover;border-radius:6px;
  background:var(--line-2)}
/* DELTA-16 - the preview frame follows the destination's provider.
   Instagram is MEDIA-FIRST and square; Facebook is TEXT-FIRST. The markup renders media before body and
   Facebook re-orders it back, so the DOM order is Instagram's and Facebook's is the deviation - the opposite
   arrangement would leave a media-less Instagram preview (which cannot be published anyway) looking correct.
   This remains an approximation and the caption under it says so; nothing here claims pixel accuracy. */
.spc-prev[data-preview-provider="facebook"] .spc-prev-media{order:2}
.spc-prev[data-preview-provider="facebook"] .spc-prev-body{order:1;margin:0 0 10px}
.spc-prev[data-preview-provider="facebook"]{display:flex;flex-direction:column}
.spc-prev[data-preview-provider="instagram"]{display:flex;flex-direction:column}
.spc-prev[data-preview-provider="instagram"] .spc-prev-media{order:1;margin-bottom:10px;
  grid-template-columns:repeat(auto-fit,minmax(140px,1fr))}
.spc-prev[data-preview-provider="instagram"] .spc-prev-media img,
.spc-prev[data-preview-provider="instagram"] .spc-prev-media video{aspect-ratio:1/1;height:auto}
.spc-prev[data-preview-provider="instagram"] .spc-prev-body{order:2;margin:0}
.spc-prev[data-preview-provider="instagram"] .spc-prev-av{border-radius:50%;
  background:linear-gradient(45deg,#f9ce34,#ee2a7b,#6228d7)}
.spc-prev-head{position:relative}
.spc-prev-chan{margin-left:auto;flex:0 0 auto;font-size:var(--fs-11);color:var(--muted);
  border:1px solid var(--line);border-radius:999px;padding:1px 8px;white-space:nowrap}

/* ---- page picker ---- */
.spc-sel{font-size:var(--fs-12);color:var(--brand-d);background:var(--brand-050);border-radius:999px;
  padding:2px 9px;white-space:nowrap}
.spc-search{width:100%;max-width:100%;box-sizing:border-box;border:1px solid var(--line);border-radius:8px;
  padding:7px 10px;font:inherit;font-size:var(--fs-13);margin-bottom:8px}
/* A bounded scroll region, and it must LOOK like one. Without the border a clipped final row reads as a broken
   layout rather than as "there is more below"; the list is the one place a user must be able to trust that they
   have seen every destination they are about to publish to. */
.spc-pages{display:flex;flex-direction:column;gap:2px;max-height:300px;overflow-y:auto;overflow-x:hidden;
  border:1px solid var(--line-2);border-radius:9px;padding:4px}
.spc-page{display:flex;align-items:center;gap:9px;padding:8px 8px;border-radius:9px;cursor:pointer;min-width:0}
.spc-page:hover{background:var(--line-2)}
.spc-page input{flex:0 0 auto}
.spc-page.is-off{opacity:.6;cursor:not-allowed}
.spc-page-av{flex:0 0 auto;width:28px;height:28px;border-radius:50%;background:var(--brand-050);color:var(--brand-d);
  display:flex;align-items:center;justify-content:center;font-size:var(--fs-12);font-weight:600}
/* DELTA-16 - the destination list mixes Facebook Pages and Instagram accounts, so the avatar carries the
   provider. It is a tint on the INITIAL, never a fetched image: an avatar this application does not hold is one
   it must not invent, and the Instagram profile picture URL Meta returns expires (DELTA-11). */
.spc-page-av-instagram{background:linear-gradient(45deg,#fdf0d5,#fde0ec,#e9e0fb);color:#8a2b6a}
.spc-page-body{min-width:0;flex:1 1 auto}
.spc-page-name{display:block;font-size:var(--fs-13);color:var(--ink);overflow-wrap:anywhere;line-height:1.35}
.spc-page-meta{display:block;font-size:var(--fs-11);color:var(--muted);overflow-wrap:anywhere}
.spc-ok{color:var(--ok)}
.spc-no{color:var(--warn)}
.spc-selall{margin-top:8px}
/* Many Pages become CHIPS, not a giant row: the list stays scrollable and the selection stays readable. */
.spc-chips{display:flex;flex-wrap:wrap;gap:5px;margin-top:10px}
.spc-chips:empty{display:none}
.spc-chip{display:inline-flex;align-items:center;gap:5px;max-width:100%;min-width:0;
  background:var(--brand-050);color:var(--brand-d);border-radius:999px;padding:3px 9px;font-size:var(--fs-11)}
.spc-chip span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:150px}
.spc-chip button{border:0;background:none;color:inherit;cursor:pointer;font-size:13px;line-height:1;padding:0}

/* ---- schedule + checks ---- */
.spc-at{width:100%;max-width:100%;box-sizing:border-box;border:1px solid var(--line);border-radius:8px;
  padding:7px 10px;font:inherit;font-size:var(--fs-13);margin:6px 0 8px}
.spc-checks{border-color:var(--warn-dot)}
.spc-check-list{margin:0;padding-left:18px;font-size:var(--fs-13);color:var(--warn);line-height:1.6}
.spc-check-list li{overflow-wrap:anywhere}

/* ---- sticky action bar ---- */
.spc-bar{position:sticky;bottom:0;z-index:5;display:flex;align-items:center;gap:10px;flex-wrap:wrap;
  margin-top:16px;padding:12px 0;background:var(--bg);border-top:1px solid var(--line)}
.spc-bar-sp{flex:1 1 auto}
.spc-bar .btn.primary{min-width:110px}

/* ---- posts list ---- */
.sp-filters{display:flex;gap:8px;flex-wrap:wrap;margin:12px 0}
.sp-filters select,.sp-filters input{min-width:0;border:1px solid var(--line);border-radius:8px;padding:6px 9px;
  font:inherit;font-size:var(--fs-13)}
.sp-list{display:flex;flex-direction:column;gap:10px}
.sp-row{display:flex;gap:14px;align-items:flex-start;border:1px solid var(--line);border-radius:12px;
  padding:14px 16px;background:var(--card);min-width:0}
.sp-row-main{flex:1 1 auto;min-width:0}
.sp-row-actions{flex:0 0 auto;display:flex;gap:6px;flex-wrap:wrap;justify-content:flex-end;max-width:220px}
.sp-body{font-size:var(--fs-14);line-height:1.55;color:var(--ink);overflow-wrap:anywhere;margin-bottom:8px}
.sp-meta{display:flex;gap:8px;flex-wrap:wrap;align-items:center;margin-bottom:8px;min-width:0}
.sp-tag{font-size:var(--fs-11);color:var(--muted);background:var(--line-2);border-radius:999px;padding:2px 8px;
  white-space:nowrap}
.sp-count{font-size:var(--fs-12);color:var(--ink-2);font-weight:600}
.sp-targets{display:flex;flex-direction:column;gap:6px}
.sp-target{display:flex;gap:8px;align-items:center;flex-wrap:wrap;font-size:var(--fs-13);min-width:0;
  padding:6px 10px;border-radius:8px;background:var(--bg)}
.sp-target-name{display:inline-flex;align-items:center;gap:6px;min-width:0;overflow-wrap:anywhere}
.sp-open{font-size:var(--fs-12)}
.sp-why{flex:1 1 100%;font-size:var(--fs-12);color:var(--warn);overflow-wrap:anywhere}

/* State pills. Each canonical state gets its OWN colour: `possibly_sent` must never look like either success or
   failure, because both readings prompt the wrong action. */
.pill.sp-draft{background:var(--off-bg);color:var(--off)}
.pill.sp-scheduled,.pill.sp-provider_scheduled{background:var(--brand-050);color:var(--brand-d)}
.pill.sp-publishing,.pill.sp-provider_processing{background:var(--warn-bg);color:var(--warn)}
.pill.sp-published{background:var(--ok-bg);color:var(--ok)}
.pill.sp-partial{background:var(--warn-bg);color:var(--warn)}
.pill.sp-possibly_sent{background:#ede9fe;color:#5b21b6}
.pill.sp-failed{background:var(--no-bg);color:var(--no)}
.pill.sp-cancelled{background:var(--off-bg);color:var(--off)}
.pill.sp-processing{background:var(--warn-bg);color:var(--warn)}
.pill.sp-locally_scheduled{background:var(--brand-050);color:var(--brand-d)}

/* ---- UX-18: campaign summary cards ---- */
.sp-camp .sp-body{font-weight:600}
.sp-counts{display:flex;gap:10px;flex-wrap:wrap;align-items:center}
.sp-cnt{font-size:var(--fs-13);color:var(--ink-2)}
.sp-cnt strong{font-weight:700}
.sp-cnt-ok strong{color:var(--ok)}
.sp-cnt-bad strong{color:var(--no)}
.sp-cnt-run strong{color:var(--warn)}
.sp-cnt-ask strong{color:#5b21b6}
.sp-cnt-plan strong{color:var(--brand-d)}
.sp-cnt-off strong,.sp-cnt-draftc strong{color:var(--off)}
.sp-detail{white-space:nowrap}

/* ---- UX-18: campaign detail page ---- */
.spd-back{margin:0 0 4px;font-size:var(--fs-13)}
.spd-head-meta{margin:10px 0 6px}
.spd-tabs{display:flex;gap:6px;flex-wrap:wrap;margin:12px 0 10px}
.spd-tab{display:inline-flex;align-items:center;gap:6px;padding:6px 12px;border:1px solid var(--line);
  border-radius:var(--r-pill,999px);background:#fff;color:var(--ink-2);text-decoration:none;
  font-size:var(--fs-13);font-weight:600}
.spd-tab.is-on{background:var(--brand-050);border-color:var(--brand-100);color:var(--brand-d)}
.spd-tab-n{font-weight:700;font-size:var(--fs-12);color:var(--muted)}
.spd-tab.is-on .spd-tab-n{color:var(--brand-d)}
.spd-search{display:flex;gap:8px;flex-wrap:wrap;margin:0 0 10px}
.spd-search input[type=search]{flex:1 1 220px;min-width:0;border:1px solid var(--line);border-radius:8px;
  padding:7px 10px;font-size:var(--fs-14)}
.spd-list{display:flex;flex-direction:column;border:1px solid var(--line);border-radius:12px;overflow:hidden}
.spd-row{display:flex;gap:10px;align-items:center;padding:9px 12px;border-bottom:1px solid var(--line-2);
  min-width:0}
.spd-row:last-child{border-bottom:0}
.spd-av{position:relative;flex:0 0 auto;width:34px;height:34px;border-radius:50%;display:inline-flex;
  align-items:center;justify-content:center;font-weight:700;font-size:var(--fs-13);color:#fff;
  background:var(--brand,#2563eb);overflow:hidden}
.spd-av-instagram{background:#c13584}
.spd-av img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}
.spd-main{flex:1 1 auto;min-width:0;display:flex;flex-direction:column;gap:1px}
.spd-name{font-weight:600;font-size:var(--fs-14);overflow-wrap:anywhere}
.spd-meta{font-size:var(--fs-12);color:var(--muted)}
.spd-why{font-size:var(--fs-12);color:var(--warn);overflow-wrap:anywhere}
.spd-pager{display:flex;gap:10px;align-items:center;justify-content:center;margin:12px 0 0}
.spd-none{padding:14px}

/* ---- UX-18: composer toolbar popovers + selector controls ---- */
.spc-toolbar{position:relative}
.spc-pop{position:absolute;top:100%;left:0;z-index:30;margin-top:6px;padding:8px;background:var(--card,#fff);
  border:1px solid var(--line);border-radius:10px;box-shadow:0 8px 24px rgba(15,23,42,.14);max-width:min(320px,90vw)}
.spc-pop-emoji{display:grid;grid-template-columns:repeat(6,1fr);gap:2px}
.spc-pop-emoji[hidden],.spc-pop-link[hidden]{display:none}
.spc-emo{border:0;background:none;font-size:20px;line-height:1;padding:6px;border-radius:8px;cursor:pointer}
.spc-emo:hover{background:var(--line-2)}
.spc-pop-link{display:flex;gap:6px;flex-wrap:wrap;align-items:center;min-width:min(300px,86vw)}
.spc-link-url{flex:1 1 180px;min-width:0;border:1px solid var(--line);border-radius:8px;padding:6px 9px;
  font-size:var(--fs-13)}
.spc-link-err{flex:1 1 100%;margin:0;color:var(--no)}
.spc-selrow{display:flex;gap:6px;flex-wrap:wrap;margin-top:8px}
[data-compose-selected-only].is-on{background:var(--brand-050);border-color:var(--brand-100);color:var(--brand-d)}

/* ---- calendar events ---- */
.cal-cell.has-events{background:var(--brand-050);border-color:var(--brand-100)}
.cal-event{display:block;margin-top:4px;padding:3px 6px;border-radius:6px;background:var(--card);
  font-size:var(--fs-11);text-decoration:none;color:var(--ink);border:1px solid var(--line);min-width:0}
.cal-event:hover{border-color:var(--brand)}
.cal-event-t{font-weight:600;margin-right:4px}
.cal-event-p{color:var(--muted);display:inline-block;max-width:100%;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap;vertical-align:bottom}

/* ---- responsive ----
   One column below 1080px, and the sticky side panel stops being sticky (a sticky element in a single-column
   flow pins itself over the content beneath it). */
@media (max-width:1080px){
  .spc-grid{grid-template-columns:minmax(0,1fr)}
  .spc-side{position:static}
  .spc-pages{max-height:none}
}
@media (max-width:640px){
  .spc-card{padding:14px}
  /* The card head is a two-item flex row; on a narrow screen its control must drop below the heading instead of
     squeezing it to two characters. */
  .spc-card-head{flex-wrap:wrap}
  .spc-card-head h2{flex:1 1 100%}
  .spc-head{gap:10px}
  .spc-head h1{font-size:var(--fs-18)}
  .spc-editor{min-height:150px;max-height:60vh}
  .spc-gallery{grid-template-columns:repeat(auto-fill,minmax(88px,1fr))}
  .spc-row,.sp-row{flex-direction:column}
  .sp-row-actions{max-width:none;justify-content:flex-start}
  .spc-bar{gap:8px}
  .spc-bar .btn{flex:1 1 auto;text-align:center}
  .spc-bar-sp{display:none}
  .spc-ai-row{flex-direction:column}
  .spc-prev-pick{max-width:none;width:100%}
}

/* ---- Instagram account selection (INSTAGRAM-UX-POLISH-01) ----
   The previous screen shipped .ig-cand markup with NO stylesheet behind it, so the browser fell back to raw
   label/radio defaults — technically working and unmistakably a debug page. */
.ig-select{max-width:560px;margin:0 auto;padding:20px 22px}
.ig-select-head{display:flex;gap:14px;align-items:flex-start;margin:0 0 18px}
.ig-select-ico{flex:0 0 auto;width:44px;height:44px;border-radius:13px;display:flex;align-items:center;justify-content:center;background:linear-gradient(135deg,#feda75 0%,#d62976 55%,#4f5bd5 100%);color:#fff}
.ig-select-ico .ic{width:24px;height:24px}
.ig-select h1{font-size:var(--fs-18);margin:0}
.ig-select .lead{font-size:var(--fs-13);color:var(--muted);margin:4px 0 0}
.ig-cands{display:flex;flex-direction:column;gap:10px;margin:0 0 14px}
.ig-cand{display:flex;align-items:center;gap:12px;min-width:0;padding:12px 14px;border:1px solid var(--line);border-radius:var(--r);background:var(--card);cursor:pointer;transition:.12s ease}
.ig-cand:hover{border-color:var(--brand-100);background:var(--brand-050)}
.ig-cand:focus-within{border-color:var(--brand);box-shadow:0 0 0 3px var(--brand-050)}
.ig-cand:has(input:checked){border-color:var(--brand);background:var(--brand-050)}
.ig-cand input[type=radio]{flex:0 0 auto;width:18px;height:18px;margin:0;accent-color:var(--brand)}
.ig-cand-av{flex:0 0 auto;width:38px;height:38px;border-radius:50%;display:flex;align-items:center;justify-content:center;background:linear-gradient(135deg,#feda75 0%,#d62976 55%,#4f5bd5 100%);color:#fff}
.ig-cand-av .ic{width:20px;height:20px}
.ig-cand-body{display:flex;flex-direction:column;gap:2px;min-width:0}
.ig-cand-name{font-weight:700;font-size:var(--fs-15);color:var(--ink);overflow-wrap:anywhere}
.ig-cand-meta{font-size:var(--fs-12);color:var(--muted);overflow-wrap:anywhere}
.ig-select-note{margin:0 0 16px;padding:10px 12px;border-radius:var(--r-sm);background:var(--line-2);color:var(--muted);font-size:var(--fs-12);line-height:1.5}
.ig-select-actions{display:flex;gap:10px;justify-content:flex-end;flex-wrap:wrap}
@media (max-width:420px){
  .ig-select{padding:16px}
  .ig-select-actions{flex-direction:column-reverse}
  .ig-select-actions .btn{width:100%}
}

/* ---- Instagram account management (MULTI-ACCOUNT-AND-DISCONNECT-01) ---- */
.ig-accs{display:flex;flex-direction:column;gap:10px;margin:0 0 16px}
.ig-acc{display:flex;align-items:flex-start;gap:12px;min-width:0;padding:12px 14px;border:1px solid var(--line);border-radius:var(--r);background:var(--card)}
.ig-acc-body{flex:1 1 auto;min-width:0;display:flex;flex-direction:column;gap:4px}
.ig-acc-head{display:flex;align-items:center;gap:8px;flex-wrap:wrap;min-width:0}
.ig-acc-actions{flex:0 0 auto;display:flex;gap:8px;align-items:center}
.ig-caps{display:flex;flex-wrap:wrap;gap:6px;margin-top:2px}
.ig-cap{display:inline-flex;align-items:baseline;gap:5px;padding:2px 8px;border-radius:var(--r-pill);background:var(--line-2);font-size:var(--fs-11);min-width:0}
.ig-cap-k{color:var(--ink-2);font-weight:600}
.ig-cap-v{color:var(--muted);overflow-wrap:anywhere}
@media (max-width:420px){
  .ig-acc{flex-wrap:wrap}
  .ig-acc-actions{width:100%}
  .ig-acc-actions .btn,.ig-acc-actions form{width:100%}
  .ig-acc-actions .btn{width:100%}
}

/* ---- COMMENT-WORKSPACE-28 — the Facebook/Instagram COMMENT workspace ----
   Deliberately at the END of the file. UI-POLISH-23 was broken by a late `.msg{max-width:100%}` guard silently
   overriding an earlier bubble cap; the same trap applies here, so every rule that has to win over the existing
   `.msg` widths (including the 560px/480px phone overrides above) lives after all of them, in ONE block, with
   its mobile section immediately after its desktop section so order never depends on where the reader looks. */

/* §1 NESTED THREAD. Root comment vs reply is a STRUCTURAL fact carried by `data-comment-role`; `.is-reply`
   only draws it. The indent is applied on the bubble's OWN side (a right-aligned outbound reply indents from
   the right), and the width cap shrinks by the same amount so an indented bubble never grows the column. */
.msg.is-reply{max-width:calc(76% - 34px)}
.msg.is-reply.in{margin-left:34px;border-left:2px solid var(--brand-100,#c7d2fe)}
.msg.is-reply.out{margin-right:34px;border-right:2px solid var(--brand-100,#c7d2fe)}
.msg.is-root{border-left:2px solid var(--line-2,#e5e7eb)}
.msg.is-root.out{border-left:1px solid var(--brand-100);border-right:2px solid var(--line-2,#e5e7eb)}
/* The role word is the NON-COLOUR marker: indentation and side are visual only, this is readable and copyable. */
.msg .msg-cmt-role{margin-right:auto;font-size:11px;letter-spacing:.01em}

/* §2 POST CONTEXT CARD. Every child is optional; the card is a flex row that simply has fewer children when
   the metadata is absent, so a degraded card is a short one line and never an empty box. */
.cw-postctx{align-items:flex-start;gap:10px;padding:10px 12px}
.cw-postctx .pc-thumb{flex:0 0 auto;width:56px;height:56px;border-radius:8px;object-fit:cover;border:1px solid var(--line-2,#e5e7eb);background:var(--line-2,#eef1f5)}
.cw-postctx .pc-main{flex:1 1 auto;min-width:0}
.cw-postctx .pc-id{display:flex;align-items:baseline;gap:8px;flex-wrap:wrap;min-width:0;font-size:var(--fs-13,13px);color:var(--ink)}
.cw-postctx .pc-id strong{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:100%}
/* The 3-line clamp the ticket asks for: a long post is summarised, never scrolled and never truncated mid-word
   by the server (the full text stays in `title`). */
.cw-postctx .pc-excerpt{margin:3px 0 0;font-size:var(--fs-13,13px);line-height:1.45;color:var(--ink);display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden;word-break:break-word}
.cw-postctx .pc-meta{display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin-top:4px}
.cw-postctx .pc-time{display:inline-flex;align-items:center;gap:4px}
.cw-postctx .pc-link{flex:0 0 auto;align-self:flex-start;white-space:nowrap}

/* §3 REPLY TARGET. Server-rendered above the input; it states the ONE comment the send path will publish under. */
.cw-reply-target{display:flex;align-items:baseline;gap:8px;min-width:0;margin:0 0 6px;padding:5px 10px;border-left:3px solid var(--brand,#4f46e5);border-radius:0 8px 8px 0;background:var(--brand-050,#eef2ff);font-size:var(--fs-12,12px);color:var(--ink)}
.cw-reply-target .rt-lbl{flex:0 0 auto}
.cw-reply-target .rt-quote{flex:1 1 auto;min-width:0;color:var(--muted,#6b7280);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.cw-reply-target.is-focus{outline:2px solid var(--brand,#4f46e5);outline-offset:1px}

/* §4 MOBILE (<=640px): the post card must not own the viewport, and the indent must not eat the bubble.
   The clamp tightens to 2 lines and the card is height-capped, so the timeline — the thing staff came for —
   still starts above the fold on a 375px phone. */
@media (max-width:640px){
  .msg.is-reply{max-width:calc(88% - 16px)}
  .msg.is-reply.in{margin-left:16px}
  .msg.is-reply.out{margin-right:16px}
  .cw-postctx{gap:8px;padding:8px 10px;max-height:96px;overflow:hidden}
  .cw-postctx .pc-thumb{width:40px;height:40px}
  .cw-postctx .pc-excerpt{-webkit-line-clamp:2;margin-top:2px}
  .cw-postctx .pc-chan{display:none}
  .cw-reply-target{flex-direction:column;align-items:flex-start;gap:1px}
  .cw-reply-target .rt-quote{max-width:100%;width:100%}
}

/* COMMENTS-WORKSPACE-28 ADDENDUM — the private-message dialog. Compact on desktop, a full-width sheet on a
   phone (where this action matters most), and the comment quote stays visible so the target is never
   ambiguous while typing. */
.cw-pm-dialog{border:1px solid var(--line);border-radius:12px;padding:0;max-width:460px;width:calc(100% - 32px)}
.cw-pm-dialog::backdrop{background:rgba(15,23,42,.45)}
.cw-pm-form{display:flex;flex-direction:column;gap:10px;padding:16px}
.cw-pm-h{margin:0;font-size:15px;line-height:1.35}
.cw-pm-src{margin:0}
.cw-pm-quote{display:block;margin-top:2px;padding-left:8px;border-left:3px solid var(--line);
  overflow:hidden;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}
.cw-pm-form textarea{width:100%;box-sizing:border-box;border:1px solid var(--line);border-radius:8px;padding:8px;
  font:inherit;resize:vertical}
.cw-pm-note{margin:0}
.cw-pm-err{margin:0;color:#b91c1c;font-size:13px}
.cw-pm-err[hidden]{display:none}
.cw-pm-actions{display:flex;justify-content:flex-end;gap:8px}
@media (max-width:640px){
  .cw-pm-dialog{width:100%;max-width:none;margin:auto auto 0;border-radius:14px 14px 0 0}
  .cw-pm-actions .btn{flex:1}
}

/* ZALO-PERSONAL-01D — the Danh bạ drawer. Right-side sheet on desktop, full-height sheet on mobile; it never
   covers the composer on a phone because it replaces the view rather than floating over part of it. */
.zp-open{display:inline-flex;align-items:center;gap:6px}
.ov-tools{display:flex;justify-content:flex-end;padding:0 0 8px}
.zp-drawer{position:fixed;inset:0;z-index:60;display:flex;justify-content:flex-end}
.zp-drawer[hidden]{display:none}
.zp-scrim{position:absolute;inset:0;background:rgba(15,23,42,.35)}
.zp-panel{position:relative;z-index:1;display:flex;flex-direction:column;width:min(420px,100%);max-width:100%;
  height:100%;background:var(--surface,#fff);border-left:1px solid var(--line,#e5e7eb);box-shadow:-8px 0 24px rgba(15,23,42,.12)}
.zp-head{padding:12px 14px;border-bottom:1px solid var(--line,#e5e7eb);display:flex;flex-direction:column;gap:8px}
.zp-head-row{display:flex;align-items:center;justify-content:space-between;gap:8px}
.zp-acc select{width:100%;padding:6px 8px;border:1px solid var(--line,#e5e7eb);border-radius:8px;background:#fff}
.zp-tabs{display:flex;gap:4px;padding:8px 10px;border-bottom:1px solid var(--line,#e5e7eb);overflow-x:auto}
.zp-tab{flex:0 0 auto;padding:6px 10px;border:1px solid transparent;border-radius:999px;background:transparent;
  font-size:13px;cursor:pointer}
.zp-tab[aria-selected="true"]{background:var(--accent-soft,#eef2ff);border-color:var(--accent,#6366f1);font-weight:600}
.zp-tools,.zp-find{display:flex;gap:6px;padding:8px 10px}
.zp-q{flex:1;min-width:0;padding:6px 8px;border:1px solid var(--line,#e5e7eb);border-radius:8px}
.zp-note{margin:0;padding:0 12px 6px}
.zp-note.is-err{color:var(--danger,#b91c1c)}
.zp-note.is-warn{color:var(--warn,#b45309)}
.zp-list{flex:1;overflow-y:auto;padding:4px 8px 8px}
.zp-row{display:flex;align-items:center;justify-content:space-between;gap:8px;padding:8px;border-radius:10px}
.zp-row+.zp-row{border-top:1px solid var(--line-soft,#f1f5f9)}
.zp-row-main{min-width:0;display:flex;flex-direction:column}
.zp-name{font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.zp-row-acts{display:flex;flex-wrap:wrap;gap:4px;justify-content:flex-end}
.zp-rel-badge{align-self:center;font-size:12px;padding:2px 8px;border-radius:999px;background:var(--chip,#f1f5f9)}
.zp-more{padding:0 10px 12px;text-align:center}
.zp-group .cw-card-h{display:flex;align-items:center;justify-content:space-between;gap:8px}
.zp-member{display:flex;align-items:center;justify-content:space-between;gap:8px;padding:4px 0}
@media (max-width:640px){
  .zp-panel{width:100%;border-left:0}
  .zp-row{flex-direction:column;align-items:flex-start}
  .zp-row-acts{justify-content:flex-start}
}

/* 01E — group authorship + provider state on a bubble. The avatar is 20px so a group thread does not turn into
   a list of faces; initials keep the same box, so a missing avatar cannot shift the layout. */
.msg-sender{display:inline-flex;align-items:center;gap:4px;margin-right:6px}
.msg-ava{width:20px;height:20px;border-radius:50%;object-fit:cover;flex:0 0 20px;background:var(--chip,#f1f5f9)}
.msg-ava-txt{display:inline-flex;align-items:center;justify-content:center;font-size:11px;font-weight:700;
  color:var(--muted,#64748b)}
.msg-recalled{font-style:italic}

/* 01F — a quoted message inside a bubble, and the typing line under the transcript. */
.msg-quote{display:flex;gap:6px;margin-bottom:4px;padding:4px 6px;border-radius:8px;background:rgba(15,23,42,.05)}
.msg-quote-bar{width:3px;border-radius:2px;background:var(--accent,#6366f1);flex:0 0 3px}
.msg-quote-text{font-size:12px;color:var(--muted,#64748b);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cw-typing{padding:2px 12px 6px;font-size:12px;color:var(--muted,#64748b)}
.cw-typing[hidden]{display:none}

/* 01G — outbound affordances: quote bar, mention suggestions, sticker picker, per-bubble actions. */
.zp-reply[hidden]{display:none}
.zp-reply{display:flex;align-items:center;gap:8px}
.zp-mention-pop{position:absolute;z-index:40;max-height:200px;overflow-y:auto;min-width:200px;background:var(--surface,#fff);
  border:1px solid var(--line,#e5e7eb);border-radius:10px;box-shadow:0 8px 20px rgba(15,23,42,.12)}
.zp-mention-pop[hidden]{display:none}
.zp-mention-item{display:block;width:100%;text-align:left;padding:6px 10px;background:none;border:0;cursor:pointer}
.zp-mention-item:hover,.zp-mention-item.is-active{background:var(--accent-soft,#eef2ff)}
.zp-stk-pop{width:260px;padding:8px}
.zp-stk-list{display:grid;grid-template-columns:repeat(4,1fr);gap:6px;max-height:180px;overflow-y:auto;margin-top:6px}
.zp-stk-list img{width:100%;height:auto;cursor:pointer;border-radius:6px}
.zp-react-pop{display:inline-flex;gap:2px;margin-left:4px}
.msg-act{padding:0 6px}

/* ---------------------------------------------------------------------------------------------------------
   CHOTSALE-INBOX-CHAT-DENSITY-01 §1 — a denser transcript, and controls that appear when they are wanted.

   Deliberately at the END of the file, for the reason UI-POLISH-23 documented the hard way: a late
   `.msg{max-width:100%}` guard silently undid an earlier rule, so anything that must win goes last.
--------------------------------------------------------------------------------------------------------- */

/* Lighter bubbles. The border and shadow were drawing a box around every line of a conversation; a chat reads
   better when the SHAPE carries the grouping and the chrome gets out of the way. */
.msg{border-color:transparent;box-shadow:none;padding:5px 10px}
.msg.in{background:var(--surface-2,#f1f5f9)}
.msg.out{background:var(--brand-soft,#e0edff)}

/* A CLUSTER is consecutive messages from one sender on one day (see data-clu). Only the spacing and the
   repeated name change — every bubble keeps its own id, actions, reactions and state. */
.msg.clu-mid,.msg.clu-last{margin-top:2px}
.msg.clu-mid,.msg.clu-first{border-bottom-right-radius:6px}
.msg.in.clu-mid,.msg.in.clu-first{border-bottom-right-radius:12px;border-bottom-left-radius:6px}
/* The name is said ONCE per run, at the top, which is where a reader looks for it. */
/* The class the renderer actually emits is `.msg-sender` (avatar + name, group threads only). */
.msg.clu-mid .msg-sender,.msg.clu-last .msg-sender{display:none}

/* The toolbar: absolutely positioned against the bubble, so revealing it never moves the conversation. */
.msg{--tools-gap:6px}
.msg-tools{position:absolute;top:-10px;display:flex;gap:2px;padding:2px;border-radius:999px;
  background:var(--surface,#fff);border:1px solid var(--line);box-shadow:var(--sh-2,0 2px 8px rgba(0,0,0,.12));
  opacity:0;visibility:hidden;transition:opacity .12s ease;z-index:3}
.msg.out .msg-tools{right:var(--tools-gap)}
.msg.in .msg-tools{left:var(--tools-gap)}
/* Hover OR keyboard focus OR an explicit tap (.tools-open, set by cc.js on touch). The hover area includes the
   toolbar itself because it overlaps the bubble's top edge — moving the pointer onto it must not dismiss it. */
.msg:hover>.msg-tools,.msg:focus-within>.msg-tools,.msg.tools-open>.msg-tools{opacity:1;visibility:visible}
.msg-tool{display:inline-flex;align-items:center;justify-content:center;width:26px;height:26px;padding:0;
  border:0;border-radius:999px;background:transparent;color:var(--muted);cursor:pointer}
.msg-tool:hover,.msg-tool:focus-visible{background:var(--surface-2,#f1f5f9);color:var(--fg)}
.msg-tool:focus-visible{outline:2px solid var(--brand,#2563eb);outline-offset:1px}
/* The first and last bubbles must not have their toolbar clipped by the scroller. */
.msg:first-child .msg-tools{top:2px}

.msg-more-wrap{position:relative;display:inline-flex}
.msg-more-pop{position:absolute;top:calc(100% + 4px);right:0;min-width:170px;padding:4px;border-radius:10px;
  background:var(--surface,#fff);border:1px solid var(--line);box-shadow:var(--sh-2,0 6px 18px rgba(0,0,0,.16));z-index:4}
/* Author specificity, so the server-rendered `hidden` wins over the display above — the same trap
   UI04-CORR-02 documented for the emoji popup and MEDIA-01 hit again on the QR spinner. */
.msg-more-pop[hidden]{display:none}
.msg-more-pop .msg-recall{display:block;width:100%;text-align:left;padding:7px 9px;border:0;border-radius:7px;
  background:transparent;color:var(--danger,#b91c1c);cursor:pointer;font:inherit}
.msg-more-pop .msg-recall:hover,.msg-more-pop .msg-recall:focus-visible{background:var(--danger-soft,#fef2f2)}

@media (pointer:coarse),(hover:none){
  /* CORR03 §2 — 44x44 CSS px of HIT AREA on touch, which is the smallest target a thumb reliably hits.
     
     The icon itself stays small: the button keeps its 26px visual box through a transparent border, so the
     toolbar looks the same and only the tappable area grows. Growing width/height instead would have made the
     row bulky and pushed the toolbar off the bubble.
     
     Border-box keeps the total at exactly 44, and `margin:0` on the row means two 44px targets sit edge to
     edge without overlapping — an overlap is worse than a small target, because the wrong action fires. */
  .msg-tool,.msg-tools .cw-react-btn{
    width:44px;height:44px;border:9px solid transparent;background-clip:padding-box;box-sizing:border-box}
  .msg-tools{top:-22px;gap:0;padding:0}
  /* A picker option is a separate row and gets the same floor. */
  .msg-tools .cw-react-opt{width:44px;height:44px;font-size:22px}
  .msg-more-pop .msg-recall{min-height:44px}
}
@media (prefers-reduced-motion:reduce){.msg-tools{transition:none}}

/* ---------------------------------------------------------------------------------------------------------
   CHOTSALE-INBOX-CHAT-UI-CORR02 — the reaction control belongs to the toolbar, and a picker is not a row of
   default buttons.

   The always-visible control the Owner photographed was `.cw-react-wrap` rendering OUTSIDE `.msg-tools`; that
   is fixed in the renderer. These rules make the two pickers (Zalo OA and Zalo personal) look like one thing
   now that they sit in the same place, and give the popup a surface so it can never read as unstyled chrome.
--------------------------------------------------------------------------------------------------------- */
.msg-tools .cw-react-wrap{position:relative;display:inline-flex}
/* Inside the toolbar the trigger is a toolbar button, whatever it was styled as on its own. */
.msg-tools .cw-react-btn{display:inline-flex;align-items:center;justify-content:center;width:26px;height:26px;
  padding:0;border:0;border-radius:999px;background:transparent;color:var(--muted);cursor:pointer}
.msg-tools .cw-react-btn:hover,.msg-tools .cw-react-btn:focus-visible{background:var(--surface-2,#f1f5f9);color:var(--fg)}
.msg-tools .cw-react-pop{position:absolute;bottom:calc(100% + 6px);left:50%;transform:translateX(-50%);
  display:flex;gap:2px;padding:4px;border-radius:999px;white-space:nowrap;
  background:var(--surface,#fff);border:1px solid var(--line);box-shadow:var(--sh-2,0 6px 18px rgba(0,0,0,.16));z-index:5}
/* Author specificity so the server-rendered `hidden` wins over the flex above — the same trap that has now
   bitten the emoji popup, the QR spinner and the message overflow menu. */
.msg-tools .cw-react-pop[hidden]{display:none}
/* A picker option is an emoji, not a button: no border, no background, no browser chrome. */
.msg-tools .cw-react-opt{display:inline-flex;align-items:center;justify-content:center;width:30px;height:30px;
  padding:0;border:0;border-radius:999px;background:transparent;font-size:17px;line-height:1;cursor:pointer}
.msg-tools .cw-react-opt:hover,.msg-tools .cw-react-opt:focus-visible{background:var(--surface-2,#f1f5f9);transform:scale(1.12)}
.msg-tools .cw-react-opt:focus-visible{outline:2px solid var(--brand,#2563eb);outline-offset:1px}
.msg-tools .cw-react-opt.is-on{background:var(--brand-soft,#e0edff)}
.msg-tools .cw-react-opt.is-remove{font-size:14px;color:var(--muted)}
/* CORR03 §2 — superseded by the 44x44 rule above, which covers both pickers and the overflow menu. */
@media (prefers-reduced-motion:reduce){.msg-tools .cw-react-opt:hover{transform:none}}

/* CHOTSALE-ZALO-CONNECTION-UI-01 — a workload is not a fault, and an account without a picture still has a
   name. The needs-reply count sat as a bare red number beside "Đã kết nối", where it read as an error; it is
   now a labelled link. Initials stand in for the owner's avatar, which the bridge returns empty. */
.zp-needs-reply{display:inline-flex;align-items:center;gap:4px;padding:1px 8px;border-radius:999px;
  font-size:12px;font-weight:600;text-decoration:none;
  background:var(--warn-soft,#fef3c7);color:var(--warn-fg,#92400e);border:1px solid var(--warn-line,#fde68a)}
.zp-needs-reply:hover,.zp-needs-reply:focus-visible{background:var(--warn-line,#fde68a)}
.conv-avatar.zp-initials{display:inline-flex;align-items:center;justify-content:center;
  font-size:12px;font-weight:700;letter-spacing:.02em;color:var(--muted);background:var(--surface-2,#f1f5f9)}
