/* ============================================================================
   tenant.css — the SHOP (owner/staff) "Commerce OS" theme layer.

   Loaded by layout.php ONLY in tenant mode (<body class="tenant">), on TOP of
   admin.css. Platform admin never gets this file, so it stays byte-unchanged.

   admin.css is fully variable-driven, so re-pointing its variables here
   re-themes every existing .card/.badge/.btn/.nav-item without touching the
   pages. Since MUI foundation G1 they all point at the MUI 3 tokens (the --md-*
   sets further down): purple is the single tenant accent (owner decision M-D1),
   the sidebar section titles are neutral, and the page, sidebar, cards, borders
   and text follow the light / dark / high-contrast token sets. We also swap the
   type to Sora/DM Sans and add the reusable Commerce-OS primitives
   (.summary-card, .stat-card-*, .crm-*, .ord-chip, .lifecycle, …) that the
   module pages build on.
   ============================================================================ */

/* ---------- Brand re-point: MUI 3 purple, the single tenant accent (M-D1) ----------
   Every value is a var() onto the --md-* tokens. All four token sets (light · dark ·
   high-contrast · high-contrast dark) re-declare those tokens on this same <body>, so one
   mapping resolves to the right colour in each set.
   --brand-700 (strong brand text: links, active nav / badge labels) is --md-p and
   --brand-soft is a primary tint on the surface — deliberately NOT --md-opc on --md-pc:
   in the high-contrast sets --md-opc is white (every var(--brand-700) link would vanish on
   a white card) and --md-p on --md-pc drops to 1.4:1. tests/md3_tokens_test.php (TOK-3)
   measures these pairs in all four sets. */
body.tenant {
  --brand:        var(--md-p);
  --brand-600:    color-mix(in srgb, var(--md-p) 92%, var(--md-op));    /* hover: the M3 8% on-primary state layer */
  --brand-700:    var(--md-p);
  --brand-soft:   color-mix(in srgb, var(--md-p) 10%, var(--md-surf));  /* selected / soft fill: the M3 10% focus-pressed layer */
  --brand-soft-2: color-mix(in srgb, var(--md-p) 8%, var(--md-surf));   /* hover fill: the M3 8% hover layer */
  --info:         var(--md-p);
  --info-soft:    color-mix(in srgb, var(--md-p) 10%, var(--md-surf));
  --radius-lg:    16px;
  --focus-ring:   0 0 0 2px var(--md-c0), 0 0 0 4px var(--md-p);

  /* sidebar section accents — neutral: purple is the only tenant accent (M-D1) */
  --acc-orange:  var(--md-onsv); --acc-orange-soft:  var(--md-c3);
  --acc-indigo:  var(--md-onsv); --acc-indigo-soft:  var(--md-c3);
  --acc-slate:   var(--md-onsv); --acc-slate-soft:   var(--md-c3);
  --acc-amber:   var(--md-onsv); --acc-amber-soft:   var(--md-c3);
  --acc-emerald: var(--md-onsv); --acc-emerald-soft: var(--md-c3);
  --acc-neutral: var(--md-onsv); --acc-neutral-soft: var(--md-c3);

  /* shell surfaces on the MUI tokens (G1-c). admin.css paints the page with --bg and the
     sidebar, header and cards with --surface / --border; the tenant header then restyles
     itself onto --md-c1 (the M3 top app bar, further down). M3 has two text emphases, so
     the lighter admin grey (--text-3) is on-surface-variant as well. */
  --bg:            var(--md-surf);
  --surface:       var(--md-surf);
  --surface-2:     var(--md-c1);
  --muted:         var(--md-c3);
  --border:        var(--md-outlinev);
  --border-strong: var(--md-outline);
  --text:          var(--md-onsurf);
  --text-2:        var(--md-onsv);
  --text-3:        var(--md-onsv);

  /* UI-2 · --primary compatibility alias (TEMPORARY) — see the :root block above.
     Repeated here because a custom property resolves in the scope that declares it. */
  --primary: var(--brand);

  font-family: 'DM Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
}

/* ---------- Brand re-point (dark) ----------
   The same MUI mapping as the light scope: the dark token sets re-declare --md-* on this
   same element, so these resolve to the dark (and high-contrast dark) values. */
html[data-theme="dark"] body.tenant {
  --brand:        var(--md-p);
  --brand-600:    color-mix(in srgb, var(--md-p) 92%, var(--md-op));
  --brand-700:    var(--md-p);
  --brand-soft:   color-mix(in srgb, var(--md-p) 10%, var(--md-surf));
  --brand-soft-2: color-mix(in srgb, var(--md-p) 8%, var(--md-surf));
  --info:         var(--md-p);
  --info-soft:    color-mix(in srgb, var(--md-p) 10%, var(--md-surf));
  --acc-slate-soft:   var(--md-c3);
  --acc-neutral-soft: var(--md-c3);

  /* UI-2 · --primary compatibility alias (TEMPORARY) — see the :root block above.
     Repeated here because a custom property resolves in the scope that declares it. */
  --primary: var(--brand);
}

body.tenant h1, body.tenant h2, body.tenant h3,
body.tenant h4, body.tenant h5, body.tenant h6,
body.tenant .brand-text, body.tenant .page-head h1 {
  font-family: 'Sora', sans-serif;
}

/* The shop brand mark is a solid MUI primary (M3 is flat); on-primary keeps the initial
   readable in every token set */
body.tenant .brand-logo {
  background: var(--md-p);
  color: var(--md-op);
}

/* ---------- Sidebar: section titles (neutral since G1 — every --acc-* is --md-onsv) ---------- */
body.tenant .nav-section[data-accent] { --sec: var(--acc-neutral); --sec-soft: var(--acc-neutral-soft); }
body.tenant .nav-section[data-accent="orange"]  { --sec: var(--acc-orange);  --sec-soft: var(--acc-orange-soft); }
body.tenant .nav-section[data-accent="indigo"]  { --sec: var(--acc-indigo);  --sec-soft: var(--acc-indigo-soft); }
body.tenant .nav-section[data-accent="slate"]    { --sec: var(--acc-slate);   --sec-soft: var(--acc-slate-soft); }
body.tenant .nav-section[data-accent="amber"]    { --sec: var(--acc-amber);   --sec-soft: var(--acc-amber-soft); }
body.tenant .nav-section[data-accent="emerald"]  { --sec: var(--acc-emerald); --sec-soft: var(--acc-emerald-soft); }
body.tenant .nav-section[data-accent="neutral"]  { --sec: var(--acc-neutral); --sec-soft: var(--acc-neutral-soft); }

body.tenant .nav-section[data-accent] .nav-section-title {
  display: flex; align-items: center; gap: 8px;
  color: var(--sec);
  font-family: 'Sora', sans-serif; font-weight: 700; letter-spacing: 0.01em;
}
body.tenant .nav-section[data-accent] .nav-section-title::before {
  content: ''; width: 7px; height: 7px; border-radius: 3px;
  background: var(--sec); flex-shrink: 0; box-shadow: 0 0 0 3px var(--sec-soft);
}
/* The active item's look is ONE indicator now — see "MUI foundation G3 · shell" at the end of this
   file. (The inset bar that sat here stacked a second bar beside admin.css's ::before bar and, being a
   box-shadow that out-ranked :focus-visible, hid the keyboard focus ring on the active item.) */

/* "coming soon" stub item */
body.tenant .nav-soon {
  display: flex; align-items: center; gap: 12px;
  padding: 10px 12px; border-radius: var(--radius);
  color: var(--text-3); opacity: .6; cursor: default; font-size: 13.5px;
}
body.tenant .nav-soon .soon-tag {
  margin-left: auto; font-size: 9px; font-weight: 700; letter-spacing: .04em;
  text-transform: uppercase; padding: 1px 7px; border-radius: 999px;
  background: var(--muted); color: var(--text-3);
}

/* ---------- Cards a touch softer (vendor-shop = 16px radius) ---------- */
body.tenant .card { border-radius: var(--radius-lg); }

/* ---------- KPI / summary cards ---------- */
body.tenant .summary-card {
  display: flex; align-items: center; gap: 14px;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius-lg); padding: 16px 18px; box-shadow: var(--shadow-xs);
}
body.tenant .summary-card .sc-icon {
  width: 42px; height: 42px; border-radius: 12px; flex-shrink: 0;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--brand-soft); color: var(--brand-700);
}
body.tenant .summary-card .sc-label { font-size: 12px; color: var(--text-3); }
body.tenant .summary-card .sc-value {
  font-family: 'Sora', sans-serif; font-size: 22px; font-weight: 800;
  color: var(--text); font-variant-numeric: tabular-nums; line-height: 1.1;
}

/* Gradient stat cards (white text on a colored field) */
body.tenant .stat-card {
  position: relative; overflow: hidden; border-radius: var(--radius-lg);
  padding: 18px; color: #fff; box-shadow: 0 8px 24px -10px rgba(15, 23, 42, .28);
}
body.tenant .stat-card::before { content: ''; position: absolute; right: -30px; top: -30px; width: 120px; height: 120px; border-radius: 50%; background: rgba(255, 255, 255, .10); }
body.tenant .stat-card .sc-num { font-family: 'Sora', sans-serif; font-size: 26px; font-weight: 800; font-variant-numeric: tabular-nums; position: relative; }
body.tenant .stat-card .sc-cap { font-size: 12px; opacity: .9; position: relative; }
body.tenant .stat-card-1 { background: linear-gradient(135deg, #047151 0%, #0eb07c 100%); }
body.tenant .stat-card-2 { background: linear-gradient(135deg, #1d4ed8 0%, #3b82f6 100%); }
body.tenant .stat-card-3 { background: linear-gradient(135deg, #9333ea 0%, #c084fc 100%); }
body.tenant .stat-card-4 { background: linear-gradient(135deg, #b45309 0%, #f59e0b 100%); }
body.tenant .stat-card-5 { background: linear-gradient(135deg, #be123c 0%, #f43f5e 100%); }
body.tenant .stat-card-6 { background: linear-gradient(135deg, #0e7490 0%, #22d3ee 100%); }
body.tenant .trend-chip {
  display: inline-block; font-size: 10px; padding: 3px 9px; border-radius: 999px;
  font-weight: 700; background: rgba(255, 255, 255, .22); backdrop-filter: blur(4px);
}

/* ---------- crm-* toolbar / filter primitives ---------- */
body.tenant .crm-toolbar { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; }
body.tenant .crm-pill {
  padding: 6px 13px; font-size: 12px; font-weight: 700; border-radius: 999px;
  color: var(--text-2); background: var(--surface); border: 1px solid var(--border);
  cursor: pointer; transition: all var(--t-fast); display: inline-flex; align-items: center; gap: 6px;
}
body.tenant .crm-pill:hover { color: var(--text); border-color: var(--border-strong); }
body.tenant .crm-pill.active {
  background: var(--brand); color: #fff; border-color: var(--brand);
  box-shadow: 0 4px 12px -4px color-mix(in srgb, var(--brand) 50%, transparent);
}
body.tenant .crm-pill .count, body.tenant .ord-chip .count {
  font-size: 10px; padding: 1px 6px; border-radius: 999px;
  background: rgba(148, 163, 184, .18); font-weight: 800;
}
body.tenant .crm-pill.active .count { background: rgba(255, 255, 255, .25); color: #fff; }
body.tenant .ord-chip { /* alias of crm-pill for orders */
  padding: 6px 12px; font-size: 11px; font-weight: 700; border-radius: 999px;
  color: var(--text-2); background: var(--surface); border: 1px solid var(--border);
  cursor: pointer; transition: all var(--t-fast); display: inline-flex; align-items: center; gap: 6px;
}
body.tenant .ord-chip.active { background: var(--brand-700); color: #fff; border-color: var(--brand-700); }

body.tenant .crm-search { position: relative; }
body.tenant .crm-search input {
  padding: 9px 12px 9px 34px; font-size: 13px; border-radius: 12px;
  border: 1px solid var(--border); background: var(--surface-2); color: var(--text); min-width: 220px;
}
body.tenant .crm-search input:focus { border-color: var(--brand); background: var(--surface); box-shadow: var(--focus-ring); outline: none; }
body.tenant .crm-icon-btn {
  width: 36px; height: 36px; border-radius: 10px; display: inline-flex; align-items: center;
  justify-content: center; background: var(--surface); border: 1px solid var(--border); color: var(--text-2);
}
body.tenant .crm-icon-btn:hover { background: var(--muted); color: var(--text); }
body.tenant .crm-result-count {
  font-size: 11px; font-weight: 700; color: var(--text-3);
  padding: 4px 10px; border-radius: 999px; background: var(--muted);
}

/* staggered hover-glow rows for crm tables */
body.tenant .crm-row { transition: background var(--t-fast), box-shadow var(--t-fast); }
body.tenant .crm-row:hover { background: var(--brand-soft-2); box-shadow: inset 3px 0 0 var(--brand); }

/* detail-modal stat block */
body.tenant .crm-detail-stat {
  padding: 12px 14px; border-radius: 12px; background: var(--surface-2); border: 1px solid var(--border);
}
body.tenant .crm-detail-stat .v { font-family: 'Sora', sans-serif; font-size: 18px; font-weight: 800; color: var(--text); }
body.tenant .crm-detail-stat .k { font-size: 11px; color: var(--text-3); }

/* empty-state glow icon */
body.tenant .crm-empty-icon {
  width: 80px; height: 80px; border-radius: 22px; margin: 0 auto;
  background: linear-gradient(135deg, var(--brand-soft-2) 0%, var(--brand-soft) 100%);
  color: var(--brand-700); display: inline-flex; align-items: center; justify-content: center;
  box-shadow: 0 12px 32px -10px color-mix(in srgb, var(--brand) 35%, transparent);
}
body.tenant .crm-empty-shell { text-align: center; padding: 56px 20px; }
body.tenant .crm-empty-shell h2 { font-family: 'Sora', sans-serif; font-size: 20px; font-weight: 800; margin: 14px 0 4px; }
body.tenant .crm-empty-shell p { color: var(--text-3); font-size: 13.5px; max-width: 440px; margin: 0 auto; }

/* ---------- eyebrow / live pulse ---------- */
body.tenant .eyebrow {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 10px; font-weight: 700; letter-spacing: .18em; text-transform: uppercase; color: var(--text-3);
}
@keyframes tenantLivePulse { 0%, 100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--brand) 55%, transparent); } 50% { box-shadow: 0 0 0 6px transparent; } }
body.tenant .live-pulse { width: 8px; height: 8px; border-radius: 50%; background: var(--brand); animation: tenantLivePulse 2s infinite; display: inline-block; }

/* ---------- avatar palette ---------- */
body.tenant .av { width: 34px; height: 34px; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center; color: #fff; font-weight: 800; font-size: 12px; }
body.tenant .av-1 { background: linear-gradient(135deg, #6366f1, #8b5cf6); }
body.tenant .av-2 { background: linear-gradient(135deg, #0eb07c, #06b6d4); }
body.tenant .av-3 { background: linear-gradient(135deg, #f59e0b, #f43f5e); }
body.tenant .av-4 { background: linear-gradient(135deg, #3b82f6, #0ea5e9); }
body.tenant .av-5 { background: linear-gradient(135deg, #ec4899, #f43f5e); }

/* ---------- order lifecycle steppers ---------- */
body.tenant .lifecycle { display: inline-flex; align-items: center; gap: 3px; }
body.tenant .lifecycle .step { width: 18px; height: 6px; background: var(--border); border-radius: 3px; transition: all var(--t); }
body.tenant .lifecycle .step.done { background: var(--brand); }
body.tenant .lifecycle .step.current { background: linear-gradient(90deg, var(--brand), color-mix(in srgb, var(--brand) 70%, var(--md-surf))); box-shadow: 0 0 10px color-mix(in srgb, var(--brand) 50%, transparent); }
body.tenant .lifecycle .step.cancelled { background: #fda4af; }

body.tenant .lifecycle-lg { display: flex; align-items: center; width: 100%; }
body.tenant .lifecycle-lg .step-lg { flex: 1; display: flex; flex-direction: column; align-items: center; gap: 6px; }
body.tenant .lifecycle-lg .dot { width: 30px; height: 30px; border-radius: 50%; background: var(--muted); border: 2px solid var(--border); display: flex; align-items: center; justify-content: center; color: var(--text-3); z-index: 2; }
body.tenant .lifecycle-lg .step-lg.done .dot { background: var(--brand); border-color: var(--brand); color: #fff; }
body.tenant .lifecycle-lg .step-lg.current .dot { background: var(--surface); border-color: var(--brand); color: var(--brand-700); box-shadow: 0 0 0 4px color-mix(in srgb, var(--brand) 18%, transparent); }
body.tenant .lifecycle-lg .step-lg .step-label { font-size: 10px; font-weight: 700; color: var(--text-3); text-transform: uppercase; letter-spacing: .05em; }
body.tenant .lifecycle-lg .step-lg.done .step-label, body.tenant .lifecycle-lg .step-lg.current .step-label { color: var(--brand-700); }
body.tenant .lifecycle-lg .connector { flex: 1; height: 2px; background: var(--border); margin: 0 -10px; position: relative; top: -12px; z-index: 1; }
body.tenant .lifecycle-lg .connector.done { background: var(--brand); }

/* ---------- linked pills ---------- */
body.tenant .linked-pill { display: inline-flex; align-items: center; gap: 4px; font-size: 10px; font-weight: 700; padding: 2px 7px; border-radius: 999px; cursor: pointer; }
body.tenant .linked-pill-return  { background: #fff7ed; color: #c2410c; }
body.tenant .linked-pill-refund  { background: #eff6ff; color: #1d4ed8; }
body.tenant .linked-pill-dispute { background: #fef2f2; color: #b91c1c; }

/* ledger debit/credit */
body.tenant .ledger-cr { color: #16a34a; font-weight: 700; }
body.tenant .ledger-dr { color: #dc2626; font-weight: 700; }

/* responsive column hide — admin.css only scopes .hide-mobile under .user-chip, so give the
   tenant tables a real one (Customers/CRM city + last-order columns collapse on narrow screens) */
@media (max-width: 640px) { body.tenant .hide-mobile { display: none !important; } }

/* sparkline + skeleton */
body.tenant .sparkline { display: inline-flex; align-items: flex-end; gap: 2px; height: 22px; }
body.tenant .sparkline span { width: 3px; background: var(--brand); border-radius: 2px; opacity: .8; }
@keyframes tenantShimmer { 0% { background-position: -200px 0; } 100% { background-position: 200px 0; } }
body.tenant .skeleton-bar { height: 12px; border-radius: 6px; background: linear-gradient(90deg, var(--muted) 25%, var(--surface-2) 37%, var(--muted) 63%); background-size: 400px 100%; animation: tenantShimmer 1.4s infinite; }

/* ============================================================================
   MATERIAL 3 LAYER (.md3) — pure MUI 3 baseline (purple seed).
   The --md-* TOKENS sit on body.tenant and, since G1, also drive the brand
   family and the shell variables of every tenant page (top of this file). The
   COMPONENT classes below stay opt-in, scoped under .md3 (or a module prefix).
   Four token sets: light · dark · high-contrast light · HC dark. The
   high-contrast sets respond to <html data-contrast="high"> (toggle in the
   sidebar theme controls, persisted to localStorage 'admin.contrast').
   ============================================================================ */
body.tenant, body.md3-auth{
  --md-p:#6750A4; --md-op:#fff; --md-pc:#EADDFF; --md-opc:#21005D;
  --md-s:#625B71; --md-sc:#E8DEF8; --md-osc:#1D192B;
  --md-t:#7D5260; --md-tc:#FFD8E4; --md-otc:#31111D;
  --md-err:#B3261E; --md-oerr:#fff; --md-errc:#F9DEDC; --md-oerrc:#410E0B;
  --md-warn:#7A5900; --md-owarn:#fff; --md-warnc:#FFDF9B; --md-owarnc:#251A00;
  --md-ok:#3B6939; --md-ook:#fff; --md-okc:#BCF0B4; --md-ookc:#072100;
  --md-onsurf:#1D1B20; --md-onsv:#49454F; --md-outline:#79747E; --md-outlinev:#CAC4D0;
  --md-c0:#fff; --md-c1:#F7F2FA; --md-c2:#F3EDF7; --md-c3:#ECE6F0; --md-c4:#E6E0E9;
  /* surface aliases, declared ONCE: every set re-declares c0 / c2 on this same element, so
     they resolve per set. --md-sv is the compatibility spelling the Team CSS uses. */
  --md-surf:var(--md-c0); --md-surfv:var(--md-c2); --md-sv:var(--md-surfv);
  --md-rx:8px; --md-rs:12px; --md-rm:16px; --md-rl:20px; --md-rxl:28px; --md-rf:999px; --md-bw:1px;
}
body.tenant .md3{ color:var(--md-onsurf); }
html[data-theme="dark"] body.tenant, html[data-theme="dark"] body.md3-auth{
  --md-p:#D0BCFF; --md-op:#381E72; --md-pc:#4F378B; --md-opc:#EADDFF;
  --md-s:#CCC2DC; --md-sc:#4A4458; --md-osc:#E8DEF8;
  --md-t:#EFB8C8; --md-tc:#633B48; --md-otc:#FFD8E4;
  --md-err:#F2B8B5; --md-oerr:#601410; --md-errc:#8C1D18; --md-oerrc:#F9DEDC;
  --md-warn:#F8BD49; --md-owarn:#402D00; --md-warnc:#5C4300; --md-owarnc:#FFDF9B;
  --md-ok:#A1D39A; --md-ook:#0A390F; --md-okc:#235024; --md-ookc:#BCF0B4;
  --md-onsurf:#E6E0E9; --md-onsv:#CAC4D0; --md-outline:#938F99; --md-outlinev:#49454F;
  --md-c0:#0F0D13; --md-c1:#1D1B20; --md-c2:#211F26; --md-c3:#2B2930; --md-c4:#36343B;
}
html[data-contrast="high"] body.tenant, html[data-contrast="high"] body.md3-auth{
  --md-p:#33106B; --md-op:#fff; --md-pc:#4B2D8C; --md-opc:#fff;
  --md-s:#241E33; --md-sc:#473F57; --md-osc:#fff;
  --md-t:#3D0E22; --md-tc:#5E303F; --md-otc:#fff;
  --md-err:#600004; --md-oerr:#fff; --md-errc:#98000A; --md-oerrc:#fff;
  --md-warn:#3D2D00; --md-owarn:#fff; --md-warnc:#5E4500; --md-owarnc:#fff;
  --md-ok:#0A2D06; --md-ook:#fff; --md-okc:#1F5121; --md-ookc:#fff;
  --md-onsurf:#000; --md-onsv:#1B1B20; --md-outline:#2B2930; --md-outlinev:#45424B; --md-bw:2px;
}
html[data-contrast="high"][data-theme="dark"] body.tenant, html[data-contrast="high"][data-theme="dark"] body.md3-auth{
  --md-p:#F6EDFF; --md-op:#000; --md-pc:#D5C4FB; --md-opc:#000;
  --md-s:#F6EDFF; --md-sc:#CBC1DB; --md-osc:#000;
  --md-t:#FFEBF0; --md-tc:#FFADC6; --md-otc:#000;
  --md-err:#FFECE9; --md-oerr:#000; --md-errc:#FFAEA4; --md-oerrc:#000;
  --md-warn:#FFEFD0; --md-owarn:#000; --md-warnc:#F2BE40; --md-owarnc:#000;
  --md-ok:#EAFFE2; --md-ook:#000; --md-okc:#A5D69E; --md-ookc:#000;
  --md-onsurf:#fff; --md-onsv:#F0EDF5; --md-outline:#F9F4FF; --md-outlinev:#D0CAD6; --md-bw:2px;
}

/* type + base */
body.tenant .md3, body.tenant .md3 .md-num{ font-family:'DM Sans','Roboto',sans-serif; }
body.tenant .md3 .md-disp{ font-family:'Sora','Roboto Flex',sans-serif; font-weight:700; letter-spacing:-.01em; }
body.tenant .md3 .md-eyebrow{ font-size:12px; letter-spacing:.04em; text-transform:uppercase; color:var(--md-onsv); font-weight:600; display:flex; align-items:center; gap:7px; }
body.tenant .md3 .md-eyebrow.plain{ text-transform:none; letter-spacing:0; }
body.tenant .md3 .md-dot{ width:8px; height:8px; border-radius:50%; background:#1f9d55; box-shadow:0 0 0 4px rgba(31,157,85,.16); }

/* hero */
body.tenant .md3 .md-hero{ background:var(--md-c1); border-radius:var(--md-rxl); padding:24px 28px; margin:6px 0 16px; display:flex; justify-content:space-between; gap:24px; flex-wrap:wrap; border:var(--md-bw) solid transparent; }
html[data-contrast="high"] body.tenant .md3 .md-hero{ border-color:var(--md-outlinev); }
body.tenant .md3 .md-greet{ font-family:'Sora',sans-serif; font-size:28px; font-weight:700; letter-spacing:-.02em; margin:6px 0 5px; }
body.tenant .md3 .md-greet b{ color:var(--md-p); }
body.tenant .md3 .md-health{ font-size:14.5px; color:var(--md-onsv); max-width:580px; line-height:1.55; }
body.tenant .md3 .md-health b{ color:var(--md-onsurf); font-weight:600; }
body.tenant .md3 .md-chips{ display:flex; gap:10px; flex-wrap:wrap; margin-top:18px; }
body.tenant .md3 .md-chip{ display:inline-flex; align-items:center; gap:8px; height:36px; padding:0 14px 0 9px; border-radius:var(--md-rx); font-size:13px; font-weight:500; border:var(--md-bw) solid var(--md-outlinev); background:transparent; color:var(--md-onsurf); cursor:pointer; text-decoration:none; transition:background .15s; }
body.tenant .md3 .md-chip:hover{ background:var(--md-c3); }
body.tenant .md3 .md-chip .num{ display:inline-flex; align-items:center; justify-content:center; min-width:22px; height:22px; padding:0 6px; border-radius:var(--md-rf); font-size:12px; font-weight:700; }
body.tenant .md3 .md-chip.attn{ background:var(--md-errc); border-color:transparent; color:var(--md-oerrc); } body.tenant .md3 .md-chip.attn .num{ background:var(--md-err); color:var(--md-oerr); }
body.tenant .md3 .md-chip.warn{ background:var(--md-warnc); border-color:transparent; color:var(--md-owarnc); } body.tenant .md3 .md-chip.warn .num{ background:var(--md-warn); color:var(--md-owarn); }
body.tenant .md3 .md-chip.ok{ background:var(--md-okc); border-color:transparent; color:var(--md-ookc); } body.tenant .md3 .md-chip.ok .num{ background:var(--md-ok); color:var(--md-ook); }
body.tenant .md3 .md-cta{ display:flex; flex-direction:column; gap:10px; min-width:210px; }
body.tenant .md3 .md-btn{ display:inline-flex; align-items:center; justify-content:center; gap:9px; height:44px; padding:0 22px; border-radius:var(--md-rf); font-size:14px; font-weight:600; border:none; cursor:pointer; text-decoration:none; transition:filter .15s,background .15s; }
body.tenant .md3 .md-btn.filled{ background:var(--md-p); color:var(--md-op); } body.tenant .md3 .md-btn.filled:hover{ filter:brightness(1.08); }
body.tenant .md3 .md-btn.tonal{ background:var(--md-sc); color:var(--md-osc); }
body.tenant .md3 .md-btn.out{ background:transparent; color:var(--md-p); border:var(--md-bw) solid var(--md-outline); }

/* compact greeting bar — greeting left, attention chips right, no action column */
body.tenant .md3 .md-hero.compact{ padding:15px 22px; margin:4px 0 14px; align-items:center; gap:18px; }
body.tenant .md3 .md-greet-wrap{ min-width:260px; flex:1; }
body.tenant .md3 .md-hero.compact .md-greet{ font-size:22px; margin:0 0 3px; }
body.tenant .md3 .md-hero.compact .md-health{ font-size:13.5px; }
body.tenant .md3 .md-hero.compact .md-chips{ margin-top:0; justify-content:flex-end; flex-shrink:0; }
@media (max-width:760px){
  body.tenant .md3 .md-hero.compact{ align-items:flex-start; }
  body.tenant .md3 .md-hero.compact .md-chips{ justify-content:flex-start; margin-top:8px; }
}

/* kpi stat cards */
body.tenant .md3 .md-grid-kpi{ display:grid; grid-template-columns:repeat(auto-fit,minmax(200px,1fr)); gap:12px; margin-bottom:16px; }
/* The ONE stat card (UI polish P2): a quiet outlined surface; the k-* tone colours ONLY the icon tile.
   Grid areas put the icon + label on the first row, the value full-width below (so a long PKR amount gets
   the whole card width), then the optional chip and sub line. DOM order stays ico · t · v · l (pinned).
   No grid gap: an EMPTY track keeps its gutters, so a card without an icon, chip or sub line would carry a
   phantom 10px indent or 6-12px of extra bottom space. The spacing lives on the items that are present. */
body.tenant .md3 .md-kpi{ position:relative; display:grid; grid-template-columns:auto minmax(0,1fr); grid-template-areas:"ico l" "v v" "t t" "s s"; align-items:center; align-content:start; gap:0; padding:14px 16px; border-radius:var(--md-rl); border:var(--md-bw) solid var(--md-outlinev); container-type:inline-size; }
body.tenant .md3 .md-kpi .ico{ grid-area:ico; width:30px; height:30px; margin-right:10px; border-radius:var(--md-rx); display:flex; align-items:center; justify-content:center; }
body.tenant .md3 .md-kpi .ico svg{ width:17px; height:17px; }
body.tenant .md3 .md-kpi .l{ grid-area:l; margin:0; font-size:12.5px; font-weight:600; line-height:1.3; color:var(--md-onsv); overflow-wrap:anywhere; }
body.tenant .md3 .md-kpi .v{ grid-area:v; margin:8px 0 0; font-family:'Sora',sans-serif; font-weight:700; font-size:21px; font-size:clamp(16px,8cqi,22px); line-height:1.2; letter-spacing:-.01em; white-space:nowrap; font-variant-numeric:tabular-nums; }
body.tenant .md3 .md-kpi .t{ grid-area:t; justify-self:start; margin-top:6px; font-size:11px; font-weight:600; padding:2px 8px; border-radius:var(--md-rf); white-space:nowrap; }
body.tenant .md3 .md-kpi.k-p, body.tenant .md3 .md-kpi.k-s, body.tenant .md3 .md-kpi.k-t, body.tenant .md3 .md-kpi.k-w, body.tenant .md3 .md-kpi.k-o{ background:var(--md-c0); color:var(--md-onsurf); }
body.tenant .md3 .md-kpi.k-p .t, body.tenant .md3 .md-kpi.k-s .t, body.tenant .md3 .md-kpi.k-t .t, body.tenant .md3 .md-kpi.k-w .t, body.tenant .md3 .md-kpi.k-o .t{ background:var(--md-c2); color:var(--md-onsv); }
body.tenant .md3 .md-kpi.k-p .ico{ background:var(--md-pc); color:var(--md-opc); }
body.tenant .md3 .md-kpi.k-s .ico{ background:var(--md-sc); color:var(--md-osc); }
body.tenant .md3 .md-kpi.k-t .ico{ background:var(--md-tc); color:var(--md-otc); }
body.tenant .md3 .md-kpi.k-w .ico{ background:var(--md-warnc); color:var(--md-owarnc); }
body.tenant .md3 .md-kpi.k-o .ico{ background:var(--md-c3); color:var(--md-onsv); }
body.tenant .md3 .md-kpi.k-o .l{ color:var(--md-onsv); }

/* generic cards + layout rows */
body.tenant .md3 .md-card{ background:var(--md-c0); border:var(--md-bw) solid var(--md-outlinev); border-radius:var(--md-rl); overflow:hidden; }
body.tenant .md3 .md-card.fill{ background:var(--md-c1); border-color:transparent; }
html[data-contrast="high"] body.tenant .md3 .md-card.fill{ border-color:var(--md-outlinev); }
body.tenant .md3 .md-card-h{ display:flex; justify-content:space-between; align-items:flex-start; padding:17px 19px 0; }
body.tenant .md3 .md-card-t{ font-family:'Sora',sans-serif; font-size:15.5px; font-weight:700; margin-top:3px; }
body.tenant .md3 .md-pad{ padding:16px 19px 18px; }
body.tenant .md3 .md-row3{ display:grid; grid-template-columns:repeat(auto-fit,minmax(230px,1fr)); gap:14px; margin-bottom:16px; }
body.tenant .md3 .md-cols{ display:grid; grid-template-columns:1.5fr 1fr; gap:15px; margin-bottom:16px; }
body.tenant .md3 .md-cols2{ display:grid; grid-template-columns:repeat(auto-fit,minmax(280px,1fr)); gap:15px; }
/* tablet: stack the chart+activity split (chart needs width) */
@media (max-width:980px){ body.tenant .md3 .md-cols{ grid-template-columns:1fr; } }
/* KPI slider on mobile — one card at a time, auto-loops every 10s (JS-driven). Each dot is a 24px tap target (WCAG 2.5.8, as
   G2's carousel dots) around the drawn 7px dot (Task 9 sweep: the bare 7px buttons were the whole target). */
body.tenant .md3 .kpi-dots{ display:none; justify-content:center; gap:0; margin:-4px 0 16px; }
body.tenant .md3 .kpi-dots button{ display:inline-flex; align-items:center; justify-content:center; width:24px; height:24px; padding:0; border:none; border-radius:var(--md-rf); background:transparent; cursor:pointer; }
body.tenant .md3 .kpi-dots button::before{ content:''; display:block; width:7px; height:7px; border-radius:50%; background:var(--md-outlinev); transition:.2s; }
body.tenant .md3 .kpi-dots button.on::before{ background:var(--md-p); width:20px; border-radius:4px; }
body.tenant .md3 .kpi-dots button:focus-visible{ outline:none; box-shadow:var(--focus-ring); }
@media (max-width:640px){
  body.tenant .md3 .md-grid-kpi{ display:flex; grid-template-columns:none; overflow-x:auto; scroll-snap-type:x mandatory; -webkit-overflow-scrolling:touch; scrollbar-width:none; -ms-overflow-style:none; gap:12px; margin-bottom:10px; }
  body.tenant .md3 .md-grid-kpi::-webkit-scrollbar{ display:none; }
  body.tenant .md3 .md-grid-kpi > .md-kpi{ flex:0 0 100%; scroll-snap-align:start; }
  body.tenant .md3 .kpi-dots{ display:flex; }
}
/* phones: single column everywhere + tighter spacing */
@media (max-width:560px){
  body.tenant .md3 .md-row3{ grid-template-columns:1fr; }
  /* extra-compact greeting bar on mobile */
  body.tenant .md3 .md-hero.compact{ padding:12px 14px; margin:2px 0 12px; gap:10px; }
  body.tenant .md3 .md-greet-wrap{ min-width:0; }
  body.tenant .md3 .md-hero.compact .md-greet{ font-size:17px; margin:0 0 2px; }
  body.tenant .md3 .md-hero.compact .md-health{ font-size:12.5px; line-height:1.4; }
  body.tenant .md3 .md-hero.compact .md-chips{ margin-top:9px; gap:8px; }
  body.tenant .md3 .md-hero.compact .md-chip{ height:36px; font-size:12px; padding:0 11px 0 7px; }
  body.tenant .md3 .md-hero.compact .md-chip .num{ min-width:18px; height:18px; font-size:11px; }
  body.tenant .md3 .md-hero.compact .md-greet{ font-size:20px; }
  body.tenant .md3 .md-card-h{ padding:14px 15px 0; }
  body.tenant .md3 .md-pad{ padding:14px 15px 15px; }
  body.tenant .md3 .md-li,
  body.tenant .md3 .md-ls,
  body.tenant .md3 .md-legend{ padding-left:15px; padding-right:15px; }
  body.tenant .md3 .md-amt{ min-width:74px; font-size:13px; }
  body.tenant .md3 .md-trend-big{ font-size:26px; }
}

/* ============================================================================
   MATERIAL 3 TOP APP BAR — tenant header restyle (uses the hoisted --md-* tokens).
   Platform admin never gets body.tenant, so its header stays byte-unchanged.
   ============================================================================ */
body.tenant .header{ background:var(--md-c1); border-bottom:1px solid var(--md-outlinev); gap:8px; }

/* search → M3 filled pill */
body.tenant .header .search{ max-width:560px; }
body.tenant .header .search input{ height:46px; border:none; background:var(--md-c3); border-radius:var(--md-rf); padding:0 18px 0 46px; color:var(--md-onsurf); transition:background .15s, box-shadow .15s; }
body.tenant .header .search input::placeholder{ color:var(--md-onsv); }
body.tenant .header .search input:hover{ background:var(--md-c4); }
body.tenant .header .search input:focus{ background:var(--md-c4); box-shadow:0 0 0 2px var(--md-p); }
body.tenant .header .search .search-icon{ left:17px; color:var(--md-onsv); }

/* icon buttons → M3 round + state-layer hover */
body.tenant .header .icon-btn{ width:44px; height:44px; border-radius:50%; color:var(--md-onsv); }
body.tenant .header .icon-btn:hover{ background:color-mix(in srgb, var(--md-onsurf) 8%, transparent); color:var(--md-onsurf); }
body.tenant .header .icon-btn .dot{ background:var(--md-err); border-color:var(--md-c1); }

/* user chip + avatar → M3 tonal */
body.tenant .header .user-chip{ border-radius:var(--md-rf); padding:5px 14px 5px 5px; }
body.tenant .header .user-chip:hover{ background:color-mix(in srgb, var(--md-onsurf) 8%, transparent); }
body.tenant .header .avatar{ background:var(--md-pc); color:var(--md-opc); font-weight:700; }
body.tenant .header .user-chip-name{ color:var(--md-onsurf); }
body.tenant .header .user-chip-role{ color:var(--md-onsv); }

/* dropdown menus (notifications + user) → M3 surface */
body.tenant .header .dropdown-menu{ background:var(--md-c2); border:1px solid var(--md-outlinev); border-radius:16px; box-shadow:0 8px 28px rgba(0,0,0,.16); overflow:hidden; }
body.tenant .header .dropdown-item{ color:var(--md-onsurf); border-radius:10px; }
body.tenant .header .dropdown-item:hover{ background:color-mix(in srgb, var(--md-p) 12%, transparent); }
body.tenant .header .dropdown-item.danger{ color:var(--md-err); }
body.tenant .header .dropdown-divider{ background:var(--md-outlinev); }
body.tenant .header .notif-head, body.tenant .header .notif-foot{ background:var(--md-c1); border-color:var(--md-outlinev); }
body.tenant .header .notif-body .dropdown-item:hover{ background:color-mix(in srgb, var(--md-p) 12%, transparent); }
body.tenant .header .activity-time{ color:var(--md-onsv); }

@media (max-width:560px){
  body.tenant .header{ padding:0 12px; gap:4px; }
  body.tenant .header .search input{ height:42px; }
}

/* trend / payment mix / top products */
/* the 7-day figure scales with its card (a .md-cq size container) — 30px down to 20px — so its one-line amount never wraps */
body.tenant .md3 .md-trend-big{ font-family:'Sora',sans-serif; font-size:30px; font-size:clamp(20px,9cqi,30px); font-weight:700; margin-top:6px; }
body.tenant .md3 .md-delta{ display:inline-flex; align-items:center; gap:4px; font-size:12.5px; font-weight:600; padding:3px 9px; border-radius:var(--md-rf); background:var(--md-okc); color:var(--md-ookc); }
body.tenant .md3 .md-delta.down{ background:var(--md-errc); color:var(--md-oerrc); }
body.tenant .md3 .md-minibars{ display:flex; align-items:flex-end; gap:6px; height:46px; margin-top:14px; }
body.tenant .md3 .md-minibars span{ flex:1; border-radius:4px 4px 0 0; background:var(--md-p); opacity:.85; min-height:3px; }
body.tenant .md3 .md-payrow{ display:flex; align-items:center; gap:10px; font-size:13px; margin-top:11px; }
body.tenant .md3 .md-payrow .nm{ width:56px; color:var(--md-onsv); } body.tenant .md3 .md-payrow .bar{ flex:1; height:9px; border-radius:var(--md-rf); background:var(--md-c3); overflow:hidden; }
body.tenant .md3 .md-payrow .bar i{ display:block; height:100%; border-radius:var(--md-rf); }
body.tenant .md3 .md-payrow .vv{ flex:none; min-width:70px; text-align:right; font-weight:600; font-variant-numeric:tabular-nums; }
body.tenant .md3 .md-tp{ display:flex; align-items:center; gap:11px; padding:9px 0; border-top:var(--md-bw) solid var(--md-outlinev); }
body.tenant .md3 .md-tp:first-of-type{ border-top:none; }
body.tenant .md3 .md-tp .rank{ width:26px; height:26px; border-radius:8px; background:var(--md-pc); color:var(--md-opc); display:flex; align-items:center; justify-content:center; font-size:12px; font-weight:700; }
body.tenant .md3 .md-tp .nm{ flex:1; font-size:13px; font-weight:500; }
body.tenant .md3 .md-tp .q{ font-size:11.5px; color:var(--md-onsv); }

/* chart + activity list */
body.tenant .md3 .md-seg{ display:inline-flex; border:var(--md-bw) solid var(--md-outline); border-radius:var(--md-rf); overflow:hidden; height:38px; }
body.tenant .md3 .md-seg button{ border:none; background:transparent; font-family:inherit; font-size:12.5px; font-weight:600; padding:0 14px; color:var(--md-onsv); cursor:pointer; }
body.tenant .md3 .md-seg button.on{ background:var(--md-sc); color:var(--md-osc); }
body.tenant .md3 .md-legend{ display:flex; gap:18px; padding:0 19px 17px; font-size:12px; color:var(--md-onsv); flex-wrap:wrap; }
body.tenant .md3 .md-legend i{ width:10px; height:10px; border-radius:3px; display:inline-block; margin-right:7px; vertical-align:-1px; }
body.tenant .md3 .md-li{ display:flex; align-items:center; gap:12px; padding:11px 19px; border-top:var(--md-bw) solid var(--md-outlinev); }
body.tenant .md3 .md-li:first-of-type{ border-top:none; }
body.tenant .md3 .md-av{ width:38px; height:38px; border-radius:50%; display:flex; align-items:center; justify-content:center; flex-shrink:0; }
body.tenant .md3 .md-av.p{ background:var(--md-pc); color:var(--md-p); } body.tenant .md3 .md-av.t{ background:var(--md-tc); color:var(--md-t); } body.tenant .md3 .md-av.w{ background:var(--md-warnc); color:var(--md-warn); }
body.tenant .md3 .md-li .nm{ font-size:13.5px; font-weight:500; } body.tenant .md3 .md-li .sub{ font-size:11.5px; color:var(--md-onsv); }
body.tenant .md3 .md-tag{ font-size:11px; font-weight:600; padding:3px 10px; border-radius:var(--md-rf); background:var(--md-c3); color:var(--md-onsv); }
body.tenant .md3 .md-tag.r{ background:var(--md-pc); color:var(--md-opc); } body.tenant .md3 .md-tag.o{ background:var(--md-tc); color:var(--md-otc); } body.tenant .md3 .md-tag.e{ background:var(--md-warnc); color:var(--md-owarnc); }

/* md-tag: success + error tones. Mirrors md-chip.ok / md-chip.attn (L316-318) so a status
   badge in a table reads the same as the equivalent chip in a toolbar. Existing tokens only. */
body.tenant .md3 .md-tag.ok{ background:var(--md-okc); color:var(--md-ookc); }
body.tenant .md3 .md-tag.attn{ background:var(--md-errc); color:var(--md-oerrc); }

/* ============================================================================
   md-table — the first table primitive in the .md3 layer.
   Every MD3 page reskinned before this one was card/list based and needed no
   table. The Sales hub is a 9-column financial register: currency has to align
   on the decimal down the column, which flex rows cannot do.
   ------------------------------------------------------------------------- */
body.tenant .md3 .md-table{ overflow-x:auto; }
body.tenant .md3 .md-table table{ width:100%; border-collapse:collapse; min-width:640px; }
body.tenant .md3 .md-table th{
  text-align:left; font-size:11px; font-weight:700; text-transform:uppercase;
  letter-spacing:.05em; color:var(--md-onsv); padding:11px 18px;
  border-bottom:var(--md-bw) solid var(--md-outlinev); white-space:nowrap;
}
body.tenant .md3 .md-table td{
  padding:12px 18px; border-top:var(--md-bw) solid var(--md-outlinev); vertical-align:middle;
}
body.tenant .md3 .md-table tbody tr:hover{ background:var(--md-c2); }
/* numeric cells: right-aligned, tabular figures so decimals line up down the column */
body.tenant .md3 .md-table .num{ text-align:right; font-variant-numeric:tabular-nums; white-space:nowrap; }
/* a wider floor for tables with many columns — see the 9-column All Sales list */
body.tenant .md3 .md-table.wide table{ min-width:900px; }
/* md-table.stack — mobile card layout for narrow multi-column tables. thead is dropped and
   each row becomes a card: the first cell is the title, every cell carrying data-label renders
   as a label/value pair. CSS-only over the same DOM. Opt-in via the stack class.
   The All Sales list does NOT use this — nine fields as label/value rows is still too heavy;
   it renders md-slist instead (see below). */
@media (max-width:760px){
  body.tenant .md3 .md-table.stack{ overflow-x:visible; padding:12px; }
  body.tenant .md3 .md-table.stack table{ min-width:0; display:block; }
  body.tenant .md3 .md-table.stack thead{ display:none; }
  body.tenant .md3 .md-table.stack tbody{ display:block; }
  body.tenant .md3 .md-table.stack tbody tr{
    display:block; padding:14px 16px; margin-bottom:10px;
    background:var(--md-c1); border:var(--md-bw) solid var(--md-outlinev);
    border-radius:var(--md-rm);
  }
  body.tenant .md3 .md-table.stack tbody tr:last-child{ margin-bottom:0; }
  body.tenant .md3 .md-table.stack tbody tr:hover{ background:var(--md-c1); }
  body.tenant .md3 .md-table.stack td{ display:block; border:0; padding:0; }
  body.tenant .md3 .md-table.stack td:first-child:not([data-label]){
    font-size:14.5px; font-weight:600; margin-bottom:8px;
  }
  body.tenant .md3 .md-table.stack td[data-label]{
    display:flex; align-items:center; justify-content:space-between;
    gap:12px; padding:5px 0; text-align:left;
  }
  body.tenant .md3 .md-table.stack td[data-label]::before{
    content:attr(data-label); flex:none;
    font-size:11px; font-weight:700; text-transform:uppercase;
    letter-spacing:.05em; color:var(--md-onsv);
  }
}

/* md-slist — the compact mobile sales row. Desktop keeps the full table (md-table.deskonly);
   below 760px that is swapped for this list. Deliberately dense: one scannable line carrying
   the document ref and the amount, one small metadata line, one tag line. Reuses the md-li
   grammar from dashboard.php — .md-av leading icon, .nm/.sub type scale, .md-amt, .md-tag.
   The whole row is an <a> so it is a real tap target with native link behaviour. */
body.tenant .md3 .md-slist{ display:none; }
@media (max-width:760px){
  body.tenant .md3 .md-table.deskonly{ display:none; }
  body.tenant .md3 .md-slist{ display:block; }
}
body.tenant .md3 .md-srow{
  display:flex; align-items:center; gap:11px; padding:10px 15px;
  border-top:var(--md-bw) solid var(--md-outlinev);
  color:inherit; text-decoration:none;
}
body.tenant .md3 .md-srow:first-child{ border-top:none; }
body.tenant .md3 .md-srow:active{ background:var(--md-c2); }
body.tenant .md3 .md-srow .md-av{ width:32px; height:32px; }
body.tenant .md3 .md-srow .b{ flex:1; min-width:0; }
body.tenant .md3 .md-srow .l1{ display:flex; align-items:baseline; justify-content:space-between; gap:10px; }
/* the document number is a code (Ruling 13): whole, breaking only at its own separators beside the amount — never cut to
   "INV-202609-00…"; an unbroken one longer than the row scrolls in its own box */
body.tenant .md3 .md-srow .nm{ font-size:14px; font-weight:600; min-width:0; overflow-x:auto; overflow-wrap:normal; word-break:normal; }
body.tenant .md3 .md-srow .md-amt{ min-width:0; flex:none; font-size:14px; }
body.tenant .md3 .md-srow .sub{ margin-top:1px; font-size:11.5px; color:var(--md-onsv); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
body.tenant .md3 .md-srow .l3{ display:flex; align-items:center; flex-wrap:wrap; gap:6px; margin-top:6px; }
body.tenant .md3 .md-srow .l3 .it{ font-size:11.5px; color:var(--md-onsv); }
body.tenant .md3 .md-srow .chev{ flex:none; color:var(--md-onsv); }

/* md-filterbar — filter chips + result count. Desktop is unchanged (chips wrap, count right).
   Below 760px the chips become a single swipeable strip and the count drops to its own small
   line: horizontal scroll is acceptable for controls, never for sale data. The strip shows that
   it scrolls — the lane's thin scroll cue (UIP block, A6), 4px under the chips — because with its
   scrollbar hidden a chip past the edge looked missing (visual review V3: Customers "Lead", PO
   "Received", Bills "Void"). */
body.tenant .md3 .md-filterbar{ display:flex; align-items:center; gap:12px; }
body.tenant .md3 .md-filterbar .md-chips{ flex:1; min-width:0; margin-bottom:0; }
body.tenant .md3 .md-filterbar .md-count{ flex:none; color:var(--md-onsv); font-size:12px; }
@media (max-width:760px){
  body.tenant .md3 .md-filterbar{ display:block; }
  body.tenant .md3 .md-filterbar .md-chips{ flex-wrap:nowrap; overflow-x:auto; padding-bottom:4px; }
  body.tenant .md3 .md-filterbar .md-chips > *{ flex:none; }
  body.tenant .md3 .md-filterbar .md-count{ display:block; margin-top:6px; font-size:11.5px; }
}

body.tenant .md3 .md-amt{ font-family:'Sora',sans-serif; font-size:14px; font-weight:700; min-width:88px; text-align:right; font-variant-numeric:tabular-nums; }
body.tenant .md3 .md-amt.dr{ color:var(--md-err); }

/* low-stock + ledger snapshot */
body.tenant .md3 .md-ls{ display:flex; align-items:center; gap:11px; padding:11px 19px; border-top:var(--md-bw) solid var(--md-outlinev); }
body.tenant .md3 .md-ls:first-of-type{ border-top:none; }
body.tenant .md3 .md-ls .pill{ font-size:11px; font-weight:700; padding:3px 9px; border-radius:var(--md-rf); background:var(--md-errc); color:var(--md-oerrc); white-space:nowrap; }
body.tenant .md3 .md-ls .pill.low{ background:var(--md-warnc); color:var(--md-owarnc); }
body.tenant .md3 .md-led{ display:flex; justify-content:space-between; gap:12px; padding:10px 0; border-top:var(--md-bw) solid var(--md-outlinev); font-size:13.5px; }
body.tenant .md3 .md-led:first-of-type{ border-top:none; }
body.tenant .md3 .md-led .k{ color:var(--md-onsv); } body.tenant .md3 .md-led .v{ font-weight:700; font-variant-numeric:tabular-nums; }

/* empty state — friendly tonal illustration + title + text */
body.tenant .md3 .md-empty{ padding:30px 19px; text-align:center; color:var(--md-onsv); display:flex; flex-direction:column; align-items:center; }
body.tenant .md3 .md-empty-ill{ width:62px; height:62px; border-radius:50%; display:inline-flex; align-items:center; justify-content:center; margin-bottom:13px; }
body.tenant .md3 .md-empty-title{ font-family:'Sora',sans-serif; font-weight:700; font-size:14.5px; color:var(--md-onsurf); margin-bottom:3px; }
body.tenant .md3 .md-empty-text{ font-size:12.5px; color:var(--md-onsv); max-width:300px; margin:0 auto; line-height:1.5; }

/* extended FAB */
body.tenant .md3-fab{ position:fixed; right:30px; bottom:26px; z-index:40; height:56px; padding:0 22px; border-radius:16px; background:var(--md-pc,#EADDFF); color:var(--md-opc,#21005D); border:1px solid transparent; display:inline-flex; align-items:center; gap:10px; font-family:'DM Sans',sans-serif; font-size:15px; font-weight:600; text-decoration:none; cursor:pointer; box-shadow:0 6px 18px rgba(0,0,0,.18); }
html[data-contrast="high"] body.tenant .md3-fab{ border-color:var(--md-outline,#2B2930); }
@media (max-width:640px){ body.tenant .md3-fab span{ display:none; } body.tenant .md3-fab{ padding:0 16px; } }

/* ── Team module ──────────────────────────────────────────────────────────── */
/* Section nav */
.team-snav-btn { display:flex; align-items:center; gap:6px; padding:7px 15px; border:none; border-radius:10px; font-size:12.5px; font-weight:600; cursor:pointer; font-family:inherit; color:var(--md-onsv); background:transparent; transition:background .12s,color .12s; }
.team-snav-active { background:var(--md-c0) !important; color:var(--md-p) !important; box-shadow:0 1px 4px rgba(0,0,0,.1); }
/* KPI strip */
.team-kpi { display:flex; align-items:center; gap:7px; padding:7px 14px; background:var(--md-sv); border-radius:var(--md-rm); }
.team-kpi-val { font-size:16px; font-weight:700; font-family:'Sora',sans-serif; }
.team-kpi-lbl { font-size:11px; color:var(--md-onsv); }
/* Branch card header */
.team-branch-hd { display:flex; align-items:stretch; background:var(--md-sv); }
.team-branch-stripe { width:4px; flex-shrink:0; }
.team-branch-count { font-size:10px; font-weight:700; padding:1px 7px; border-radius:999px; color:#fff; }
.team-add-btn { display:flex; align-items:center; gap:4px; padding:4px 12px; color:#fff; border:none; border-radius:20px; font-size:11.5px; cursor:pointer; font-family:inherit; transition:opacity .1s; }
.team-add-btn:hover { opacity:.85; }
/* Position group header */
.team-pos-group { display:flex; align-items:center; gap:7px; font-size:10.5px; text-transform:uppercase; letter-spacing:.08em; color:var(--md-onsv); padding:8px 14px 2px; }
.team-pos-group + .team-pos-group { border-top:1px solid var(--md-outlinev); }
.team-pos-count { font-size:10px; font-weight:700; padding:1px 6px; border-radius:999px; background:var(--md-outlinev); color:var(--md-onsv); }
/* Team rows */
.team-row { display:flex; align-items:center; gap:10px; padding:10px 14px; border-top:1px solid var(--md-outlinev); transition:background .1s; }
.team-pos-group + .team-row { border-top:none; }
.team-row:hover { background:var(--md-sv); }
.team-row--dim { opacity:.5; }
.team-badge-pos { font-size:10px; padding:2px 8px; border-radius:10px; background:rgba(103,80,164,.12); color:var(--md-p); font-weight:600; }
.team-wage-chip { font-size:11px; padding:3px 9px; border-radius:999px; background:var(--md-sv); color:var(--md-onsv); font-weight:600; white-space:nowrap; flex-shrink:0; }
.team-status-chip { font-size:10px; padding:2px 8px; border-radius:999px; font-weight:600; white-space:nowrap; flex-shrink:0; }
.team-status-active { background:#dcfce7; color:#166534; }
.team-status-off { background:#fef2f2; color:#991b1b; }
.team-edit-btn { flex-shrink:0; border:1px solid var(--md-outlinev); background:transparent; border-radius:6px; padding:4px 10px; font-size:11px; cursor:pointer; text-decoration:none; color:var(--md-onsurf); }
.team-edit-btn:hover { background:var(--md-sv); }

/* ── M3 org-tree (Team › Tree section) ────────────────────────────────────── */
/* Row wrapper draws the connector lines; .tm-tr-ch adds indent */
.tm-tree-wrap { padding:4px 0; }
.tm-tr-ch { padding-left:24px; }
/* Each item draws its own vertical + horizontal connector segment */
.tm-tr-item { position:relative; }
.tm-tr-item>.tm-tr-rw { position:relative; }
.tm-tr-item:not(:last-child)>.tm-tr-rw::before { content:''; position:absolute; left:-12px; top:0; bottom:0; width:1px; background:var(--md-outlinev); }
.tm-tr-item:last-child>.tm-tr-rw::before     { content:''; position:absolute; left:-12px; top:0; bottom:50%; width:1px; background:var(--md-outlinev); }
.tm-tr-item>.tm-tr-rw::after { content:''; position:absolute; left:-12px; top:50%; width:12px; height:1px; background:var(--md-outlinev); }
/* The actual row */
.tm-tr { display:flex; align-items:center; gap:8px; padding:7px 10px; border-radius:var(--md-rx); cursor:pointer; transition:background .12s; user-select:none; }
.tm-tr:hover { background:var(--md-c2); }
.tm-tr.leaf { cursor:default; }
.tm-tr.leaf:hover { background:transparent; }
/* Toggle chevron */
.tm-tr-toggle { width:20px; height:20px; display:flex; align-items:center; justify-content:center; flex-shrink:0; color:var(--md-onsv); }
/* Node icon circle */
.tm-tr-ic { width:30px; height:30px; border-radius:50%; display:flex; align-items:center; justify-content:center; font-size:12px; font-weight:700; flex-shrink:0; }
.tm-tr-ic.shop    { background:var(--md-p);  color:var(--md-op);  }
.tm-tr-ic.branch  { background:var(--md-pc); color:var(--md-opc); }
.tm-tr-ic.counter { background:var(--md-sc); color:var(--md-osc); }
/* Label block */
.tm-tr-label { flex:1; min-width:0; }
.tm-tr-name  { font-size:13px; font-weight:600; color:var(--md-onsurf); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.tm-tr-meta  { font-size:11px; color:var(--md-onsv); margin-top:1px; }
/* Right side */
.tm-tr-right { display:flex; align-items:center; gap:6px; flex-shrink:0; }
.tm-tr-count { min-width:20px; height:20px; padding:0 5px; border-radius:10px; background:var(--md-c4); color:var(--md-onsv); font-size:11px; font-weight:700; display:inline-flex; align-items:center; justify-content:center; }
/* Type chips */
.tm-chip         { font-size:10px; font-weight:600; padding:2px 8px; border-radius:999px; white-space:nowrap; letter-spacing:.02em; }
.tm-chip-shop    { background:var(--md-p);  color:var(--md-op);  }
.tm-chip-branch  { background:var(--md-pc); color:var(--md-opc); }
.tm-chip-counter { background:var(--md-sc); color:var(--md-osc); }
.tm-chip-cashier { background:var(--md-tc); color:var(--md-otc); }
.tm-chip-pos     { background:rgba(103,80,164,.10); color:var(--md-p); }
.tm-chip-staff   { border:1px solid var(--md-outlinev); color:var(--md-onsv); }
.tm-chip-owner   { background:var(--md-p); color:var(--md-op); font-size:9px; }
/* Status dots */
.tm-dot      { width:7px; height:7px; border-radius:50%; flex-shrink:0; }
.tm-dot-on   { background:#22c55e; }
.tm-dot-off  { background:var(--md-err); }
/* Vacant chip */
.tm-s-vac { background:var(--md-warnc); color:var(--md-owarnc); font-size:10px; padding:2px 7px; border-radius:999px; font-weight:600; }

/* ── Team Module ── */
.tm-group { padding: 4px 0; }
.tm-group-header {
  padding: 8px 14px;
  font-size: 12px;
  font-weight: 700;
  font-family: 'Sora', sans-serif;
  color: var(--md-onsv);
  text-transform: uppercase;
  letter-spacing: .04em;
  display: flex;
  align-items: center;
  gap: 6px;
}
.tm-group-count {
  font-weight: 500;
  color: var(--md-onsv);
  opacity: .65;
  font-size: 11px;
}
.tm-member {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 14px;
  cursor: pointer;
  text-decoration: none;
  color: var(--md-onsurf);
  border-radius: var(--md-rs);
  transition: background .1s;
}
.tm-member:hover { background: var(--md-c1); }
.tm-member.selected { background: var(--md-c2); }
.tm-member-info { display: flex; flex-direction: column; min-width: 0; flex: 1; }
.tm-member-name { font-size: 13.5px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.tm-member-role { font-size: 11.5px; color: var(--md-onsv); }
.tm-status-dot {
  width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0;
}
.tm-status-dot.active { background: var(--md-ok); }
.tm-status-dot.inactive { background: var(--md-err); }

/* Module tab bar */
.md-module-tabs {
  display: flex;
  gap: 0;
  border-bottom: 2px solid var(--md-outlinev);
  margin-bottom: 20px;
}
.md-module-tab {
  padding: 12px 20px;
  font-size: 13.5px;
  font-weight: 600;
  font-family: 'Sora', sans-serif;
  text-decoration: none;
  color: var(--md-onsv);
  border-bottom: 2px solid transparent;
  margin-bottom: -2px;
  transition: color .15s, border-color .15s;
}
.md-module-tab:hover { color: var(--md-onsurf); }
.md-module-tab.active { color: var(--brand); border-bottom-color: var(--brand); }

/* Compensation card rows */
.comp-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 10px 16px;
  border-bottom: var(--md-bw) solid var(--md-outlinev);
  font-size: 13.5px;
}
.comp-row:last-child { border-bottom: none; }
.comp-tag {
  font-size: 10px;
  background: var(--md-c3);
  padding: 2px 7px;
  border-radius: 4px;
  color: var(--md-onsv);
  font-weight: 600;
  margin-left: 6px;
}
.comp-meta { font-size: 12px; color: var(--md-onsv); }

/* Master-detail layout */
.tm-master-detail {
  display: grid;
  grid-template-columns: 320px 1fr;
  min-height: 500px;
  border: var(--md-bw) solid var(--md-outlinev);
  border-radius: var(--md-rm);
  overflow: hidden;
  background: var(--md-c0);
}
.tm-tree-panel {
  border-right: var(--md-bw) solid var(--md-outlinev);
  overflow-y: auto;
  max-height: 70vh;
}
/* Role filter chips — dynamic per shop's positions, business-agnostic */
.tm-chip {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 4px 10px; border-radius: 999px;
  border: 1px solid var(--md-outlinev);
  background: var(--md-c0);
  font-size: 11.5px; font-weight: 600;
  color: var(--md-onsv); text-decoration: none;
  transition: background .15s, color .15s, border-color .15s;
}
.tm-chip:hover { background: var(--md-c1); color: var(--md-onsurf); }
.tm-chip.active {
  background: var(--brand); color: #fff; border-color: var(--brand);
}
.tm-chip-count {
  font-size: 10px; font-weight: 700;
  background: rgba(0,0,0,.08); padding: 1px 6px; border-radius: 999px;
}
.tm-chip.active .tm-chip-count { background: rgba(255,255,255,.25); }
.tm-detail-panel {
  padding: 20px;
  overflow-y: auto;
}

/* Detail sub-tabs */
.tm-detail-tabs {
  display: flex;
  gap: 0;
  border-bottom: 1.5px solid var(--md-outlinev);
  margin-bottom: 16px;
}
.tm-detail-tab {
  padding: 10px 16px;
  font-size: 12.5px;
  font-weight: 600;
  cursor: pointer;
  color: var(--md-onsv);
  border-bottom: 2px solid transparent;
  margin-bottom: -1.5px;
  transition: color .15s, border-color .15s;
  background: none;
  border-top: none;
  border-left: none;
  border-right: none;
  font-family: 'Sora', sans-serif;
}
.tm-detail-tab:hover { color: var(--md-onsurf); }
.tm-detail-tab.active { color: var(--brand); border-bottom-color: var(--brand); }

/* Current cost card */
.tm-cost-card {
  background: var(--md-c1);
  border-radius: var(--md-rm);
  padding: 16px 20px;
  margin-bottom: 16px;
}
.tm-cost-row {
  display: flex;
  justify-content: space-between;
  padding: 4px 0;
  font-size: 13.5px;
}
.tm-cost-total {
  border-top: 1.5px solid var(--md-outlinev);
  margin-top: 6px;
  padding-top: 8px;
  font-weight: 700;
}

@media (max-width: 768px) {
  .tm-master-detail { grid-template-columns: 1fr; }
  .tm-tree-panel { border-right: none; border-bottom: var(--md-bw) solid var(--md-outlinev); max-height: 40vh; }
  .md-module-tab { padding: 10px 12px; font-size: 12px; }
}

/* POS sale detail: Items (wide) beside Tenders (fixed rail) on desktop, stacked on mobile.
   minmax(0,1fr) not 1fr — a bare 1fr has min-width:auto, so the items table cannot shrink and
   its text gets clipped instead of the column narrowing. Declared here rather than inline
   because an inline grid-template-columns outranks the media query below and the stack could
   never take effect. Items is first in DOM order, so it stacks on top. */
body.tenant .md3 .pos-detail-grid{ display:grid; grid-template-columns:minmax(0,1fr) 280px; gap:16px; align-items:start; }
@media (max-width:760px){
  body.tenant .md3 .pos-detail-grid{ grid-template-columns:1fr; }
}

/* Compact hero with action chips on a phone: give the title block the whole row so the chips
   wrap beneath it instead of squeezing it. .md-chips is flex-shrink:0 and the 640px rule drops
   .md-greet-wrap's 260px floor to min-width:0, so without this the text absorbs every pixel the
   chips take — three chips crush the subtitle to a ~55px column, one word per line.
   Scoped to .compact heroes that actually contain chips; team/ and counters/ have none. */
@media (max-width:640px){
  body.tenant .md3 .md-hero.compact .md-greet-wrap{ flex-basis:100%; }
}

/* ── MD3 components (G2) ── */
/* The shared component layer the page batches (B1/B2) adopt: PHP helpers in partials/md3.php,
   behaviour in the opt-in MD3 section of assets/js/admin.js. Everything below is scoped under
   body.tenant and painted only with --md-* role pairs (a fill and its own on-colour), which
   tests/md3_components_test.php measures in all four token sets. In-page components live inside a
   page's .md3 wrapper like the rest of the layer; the dialog skin, the snackbar and the tabs also
   work outside it (dialogs are teleported to <body>). New breakpoints: 480 / 760 / 900 / 1100
   only (owner decision M-D5). */

/* ── carried from the R-G1 review ── */
/* (a) admin.css gives .btn-primary (and every .btn-*:hover) its own box-shadow AFTER the global
   :focus-visible rule, at equal specificity, so a keyboard-focused primary button showed no ring. */
body.tenant .btn:focus-visible,
body.tenant .btn-primary:focus-visible{ outline:none; box-shadow:var(--focus-ring); }
/* (b) a role colour on its own container is ~1.4:1 in high contrast (#33106B on #4B2D8C). The KPI
   icon tiles and the tonal avatars now take the MUI on-container colour (TOK-3 measures them). */
body.tenant .md3 .md-kpi.k-p .ico{ color:var(--md-opc); }
body.tenant .md3 .md-kpi.k-s .ico{ color:var(--md-osc); }
body.tenant .md3 .md-kpi.k-t .ico{ color:var(--md-otc); }
body.tenant .md3 .md-kpi.k-w .ico{ color:var(--md-owarnc); }
body.tenant .md3 .md-av.p{ color:var(--md-opc); }
body.tenant .md3 .md-av.t{ color:var(--md-otc); }
body.tenant .md3 .md-av.w{ color:var(--md-owarnc); }

/* ── buttons: .text · .danger · .icon · .sm / .lg, next to the existing filled / tonal / out.
   .danger combines with .text / .out / .tonal; .icon alone is the M3 standard (transparent) icon
   button and combines with .filled / .tonal / .out / .danger. ── */
body.tenant .md3 .md-btn.text{ background:transparent; color:var(--md-p); padding:0 14px; }
body.tenant .md3 .md-btn.text:hover,
body.tenant .md3 .md-btn.out:hover{ background:color-mix(in srgb, var(--md-p) 8%, transparent); }
body.tenant .md3 .md-btn.tonal:hover{ background:color-mix(in srgb, var(--md-osc) 8%, var(--md-sc)); }
body.tenant .md3 .md-btn.danger{ background:var(--md-err); color:var(--md-oerr); }
body.tenant .md3 .md-btn.danger:hover{ filter:brightness(1.08); }
body.tenant .md3 .md-btn.danger.text,
body.tenant .md3 .md-btn.danger.out{ background:transparent; color:var(--md-err); }
body.tenant .md3 .md-btn.danger.out{ border:var(--md-bw) solid var(--md-err); }
body.tenant .md3 .md-btn.danger.tonal{ background:var(--md-errc); color:var(--md-oerrc); }
body.tenant .md3 .md-btn.danger.text:hover,
body.tenant .md3 .md-btn.danger.out:hover{ background:color-mix(in srgb, var(--md-err) 8%, transparent); filter:none; }
body.tenant .md3 .md-btn.sm{ height:36px; padding:0 16px; font-size:13px; gap:7px; }
body.tenant .md3 .md-btn.lg{ height:56px; padding:0 28px; font-size:15.5px; }
body.tenant .md3 .md-btn.text.sm{ padding:0 12px; }
body.tenant .md3 .md-btn.icon{ width:46px; padding:0; gap:0; flex:none; background:transparent; color:var(--md-onsv); }
body.tenant .md3 .md-btn.icon:hover{ background:color-mix(in srgb, var(--md-onsurf) 8%, transparent); color:var(--md-onsurf); }
body.tenant .md3 .md-btn.icon.filled{ background:var(--md-p); color:var(--md-op); }
body.tenant .md3 .md-btn.icon.tonal{ background:var(--md-sc); color:var(--md-osc); }
body.tenant .md3 .md-btn.icon.out{ background:transparent; color:var(--md-onsv); border:var(--md-bw) solid var(--md-outline); }
body.tenant .md3 .md-btn.icon.out:hover{ background:color-mix(in srgb, var(--md-onsurf) 8%, transparent); }
body.tenant .md3 .md-btn.icon.danger{ background:var(--md-err); color:var(--md-oerr); }
body.tenant .md3 .md-btn.icon.sm{ width:36px; padding:0; }
body.tenant .md3 .md-btn.icon.lg{ width:56px; padding:0; }
body.tenant .md3 .md-btn svg{ flex:none; }
body.tenant .md3 .md-btn:disabled,
body.tenant .md3 .md-btn[aria-disabled="true"]{ opacity:.38; cursor:not-allowed; pointer-events:none; filter:none; }
body.tenant .md3 .md-btn:focus-visible{ outline:none; box-shadow:var(--focus-ring); }

/* ── selected chip (filter / choice): .selected, or aria-pressed / aria-current on the chip.
   The M3 filter-chip selected state is the secondary container, as in .md-seg. ── */
body.tenant .md3 .md-chip.selected,
body.tenant .md3 .md-chip[aria-pressed="true"],
body.tenant .md3 .md-chip[aria-current="page"],
body.tenant .md3 .md-chip[aria-current="true"]{ background:var(--md-sc); border-color:transparent; color:var(--md-osc); font-weight:600; }
body.tenant .md3 .md-chip.selected:hover,
body.tenant .md3 .md-chip[aria-pressed="true"]:hover,
body.tenant .md3 .md-chip[aria-current="page"]:hover,
body.tenant .md3 .md-chip[aria-current="true"]:hover{ background:color-mix(in srgb, var(--md-osc) 8%, var(--md-sc)); }
body.tenant .md3 .md-chip:focus-visible{ outline:none; box-shadow:var(--focus-ring); }

/* ── fields: md_field() — label above, M3 outlined control, error / help linked by aria ── */
body.tenant .md3 .md-field{ display:flex; flex-direction:column; gap:6px; min-width:0; margin:0 0 16px; }
body.tenant .md3 .md-field-label{ font-size:12.5px; font-weight:600; color:var(--md-onsv); }
body.tenant .md3 .md-field-req{ color:var(--md-err); }
body.tenant .md3 .md-field-input{ box-sizing:border-box; width:100%; min-height:44px; padding:10px 14px; border:var(--md-bw) solid var(--md-outline); border-radius:var(--md-rx); background:var(--md-surf); color:var(--md-onsurf); font:inherit; font-size:14px; line-height:1.4; transition:border-color .15s, box-shadow .15s; }
body.tenant .md3 textarea.md-field-input{ min-height:96px; resize:vertical; }
body.tenant .md3 .md-field-input::placeholder{ color:var(--md-onsv); }
body.tenant .md3 .md-field-input:hover{ border-color:var(--md-onsurf); }
body.tenant .md3 .md-field-input:focus{ outline:none; border-color:var(--md-p); box-shadow:inset 0 0 0 1px var(--md-p); }
body.tenant .md3 .md-field-input[aria-invalid="true"]{ border-color:var(--md-err); }
body.tenant .md3 .md-field-input[aria-invalid="true"]:focus{ box-shadow:inset 0 0 0 1px var(--md-err); }
body.tenant .md3 .md-field-input:disabled{ opacity:.38; cursor:not-allowed; }
body.tenant .md3 .md-field-help{ font-size:12px; line-height:1.45; color:var(--md-onsv); }
body.tenant .md3 .md-field-err{ font-size:12px; line-height:1.45; font-weight:600; color:var(--md-err); }

/* ── switch / checkbox: md_switch() / md_checkbox() — a real checkbox underneath (keyboard,
   forms and assistive tech work natively); the switch draws the M3 track over a hidden input ── */
body.tenant .md3 .md-toggle-field{ display:flex; flex-direction:column; gap:4px; margin:0 0 12px; }
body.tenant .md3 .md-switch,
body.tenant .md3 .md-check{ position:relative; display:inline-flex; align-items:center; gap:12px; min-height:40px; cursor:pointer; font-size:14px; color:var(--md-onsurf); }
body.tenant .md3 .md-switch-input{ position:absolute; width:1px; height:1px; margin:-1px; padding:0; border:0; overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; }
body.tenant .md3 .md-switch-track{ position:relative; flex:none; box-sizing:border-box; width:52px; height:32px; border:2px solid var(--md-outline); border-radius:var(--md-rf); background:var(--md-c4); transition:background .15s, border-color .15s; }
body.tenant .md3 .md-switch-handle{ position:absolute; top:50%; left:6px; width:16px; height:16px; border-radius:50%; background:var(--md-outline); transform:translateY(-50%); transition:left .15s, width .15s, height .15s, background .15s; }
body.tenant .md3 .md-switch-input:checked + .md-switch-track{ background:var(--md-p); border-color:var(--md-p); }
body.tenant .md3 .md-switch-input:checked + .md-switch-track .md-switch-handle{ left:22px; width:24px; height:24px; background:var(--md-op); }
body.tenant .md3 .md-switch-input:focus-visible + .md-switch-track{ box-shadow:var(--focus-ring); }
body.tenant .md3 .md-switch-input:disabled + .md-switch-track{ opacity:.38; }
body.tenant .md3 .md-check-input{ flex:none; width:18px; height:18px; margin:0; accent-color:var(--md-p); cursor:pointer; }
body.tenant .md3 .md-check-input:focus-visible{ outline:none; box-shadow:var(--focus-ring); border-radius:2px; }

/* ── tabs: ONE definition for .md-pill-tab(s) — used by team/_tab_bar.php, never defined until
   now — and the older .md-module-tab(s), whose legacy rules above are out-ranked here. It is the
   Team & Payroll bar's own look, made reusable: 34px outlined pills and a SOLID PRIMARY active tab,
   whose fill stands ≥ 3:1 against the hero and the page in every token set (WCAG 1.4.11 — the state
   is never carried by weight alone). The bar WRAPS at every width, so on a phone the active tab is
   never pushed off-screen. ── */
body.tenant .md-pill-tabs,
body.tenant .md-module-tabs{ display:flex; align-items:center; flex-wrap:wrap; gap:6px; min-width:0; max-width:100%; margin:0; padding:0; border:0; }
body.tenant .md-pill-tab,
body.tenant .md-module-tab{ display:inline-flex; align-items:center; gap:6px; flex:none; box-sizing:border-box; height:34px; margin:0; padding:0 14px; border:var(--md-bw) solid var(--md-outlinev); border-radius:var(--md-rf); background:transparent; color:var(--md-onsv); font-family:inherit; font-size:13px; font-weight:500; line-height:1; white-space:nowrap; text-decoration:none; cursor:pointer; transition:background .15s, color .15s, border-color .15s, box-shadow .15s; }
body.tenant .md-pill-tab:hover,
body.tenant .md-module-tab:hover{ color:var(--md-onsurf); box-shadow:inset 0 0 0 999px color-mix(in srgb, currentColor 8%, transparent); }
body.tenant .md-pill-tab.active,
body.tenant .md-pill-tab[aria-current="page"],
body.tenant .md-pill-tab[aria-selected="true"],
body.tenant .md-module-tab.active,
body.tenant .md-module-tab[aria-current="page"],
body.tenant .md-module-tab[aria-selected="true"]{ background:var(--md-p); border-color:var(--md-p); color:var(--md-op); font-weight:600; }
body.tenant .md-pill-tab:focus-visible,
body.tenant .md-module-tab:focus-visible{ outline:none; box-shadow:var(--focus-ring); }
body.tenant .md-pill-tab svg,
body.tenant .md-module-tab svg{ flex:none; }
/* Inline-style bridge. team/_tab_bar.php (not edited in G2) paints every tab INLINE — with exactly
   the geometry and colours above, so nothing visible needs forcing. The one exception is the outline
   width: --md-bw, 2px in high contrast like every other MD3 outline, and an inline style out-ranks
   any stylesheet rule without !important. Remove this once that partial drops its inline styles. */
body.tenant .md-pill-tab[style]{ border-width:var(--md-bw) !important; }

/* ── dialog: a SKIN on the existing .modal-overlay / .modal pair. admin.js ("Dialog
   accessibility") still owns role, aria-modal, aria-labelledby (.modal-title), first focus, the
   focus trap and Escape; admin.css still owns positioning. Markup:
     <div class="modal-overlay md-scrim" @click.self="…"><div class="modal md-dialog md3">
       <h2 class="modal-title">…</h2><div class="md-dialog-body">…</div>
       <div class="md-dialog-actions"><button type="button" class="md-btn text">Cancel</button>…</div>
     </div></div>
   (.md3 on the dialog itself: dialogs are teleported to <body>, outside the page wrapper.) ── */
body.tenant .modal-overlay.md-scrim{ background:rgba(0, 0, 0, .32); -webkit-backdrop-filter:none; backdrop-filter:none; }
body.tenant .modal.md-dialog{ box-sizing:border-box; width:100%; max-width:560px; padding:24px; border:var(--md-bw) solid transparent; border-radius:var(--md-rxl); background:var(--md-c3); color:var(--md-onsurf); box-shadow:0 8px 28px rgba(0, 0, 0, .18), 0 2px 6px rgba(0, 0, 0, .10); }
html[data-contrast="high"] body.tenant .modal.md-dialog{ border-color:var(--md-outlinev); }
body.tenant .modal.md-dialog.wide{ max-width:760px; }
body.tenant .md-dialog .modal-title{ margin:0 0 12px; font-family:'Sora', sans-serif; font-size:22px; font-weight:700; line-height:1.3; color:var(--md-onsurf); }
body.tenant .md-dialog .md-dialog-body{ font-size:14px; line-height:1.55; color:var(--md-onsv); }
body.tenant .md-dialog .md-dialog-actions{ display:flex; flex-wrap:wrap; justify-content:flex-end; gap:8px; margin-top:24px; }
@media (max-width:480px){
  body.tenant .modal.md-dialog{ padding:20px; border-radius:var(--md-rl); }
  body.tenant .md-dialog .modal-title{ font-size:19px; }
}

/* ── banner: md_banner() — inline status; an error banner is role="alert" ── */
body.tenant .md3 .md-banner{ display:flex; align-items:flex-start; gap:12px; margin:0 0 16px; padding:12px 16px; border:var(--md-bw) solid transparent; border-radius:var(--md-rm); background:var(--md-sc); color:var(--md-osc); font-size:13.5px; line-height:1.5; }
body.tenant .md3 .md-banner.success{ background:var(--md-okc); color:var(--md-ookc); }
body.tenant .md3 .md-banner.warning{ background:var(--md-warnc); color:var(--md-owarnc); }
body.tenant .md3 .md-banner.error{ background:var(--md-errc); color:var(--md-oerrc); }
html[data-contrast="high"] body.tenant .md3 .md-banner{ border-color:currentColor; }
body.tenant .md3 .md-banner-ico{ flex:none; display:inline-flex; margin-top:1px; }
body.tenant .md3 .md-banner-body{ flex:1; min-width:0; }
body.tenant .md3 .md-banner-title{ font-weight:700; }
body.tenant .md3 .md-banner-action{ flex:none; align-self:center; padding:6px 10px; border-radius:var(--md-rf); color:inherit; font-weight:700; text-decoration:underline; text-underline-offset:2px; }
body.tenant .md3 .md-banner-action:hover{ background:color-mix(in srgb, currentColor 10%, transparent); }
body.tenant .md3 .md-banner-action:focus-visible{ outline:none; box-shadow:var(--focus-ring); }

/* ── snackbar: md_snackbar() / MdSnackbar.show() — admin.js shows one at a time; M3 inverse
   surface (on-surface fill, surface text). Scoped to body.tenant only: script-made snackbars
   are appended to <body>, outside any .md3 wrapper. ── */
body.tenant .md-snackbar{ position:fixed; left:50%; bottom:24px; z-index:1200; transform:translateX(-50%); box-sizing:border-box; display:flex; align-items:center; gap:4px; width:max-content; max-width:min(560px, calc(100vw - 32px)); min-height:48px; padding:4px 4px 4px 16px; border-radius:var(--md-rx); background:var(--md-onsurf); color:var(--md-surf); box-shadow:0 6px 18px rgba(0, 0, 0, .28); font-size:14px; line-height:1.4; transition:opacity .2s ease, transform .2s ease; }
body.tenant .md-snackbar[hidden]{ display:none; }
body.tenant .md-snackbar.is-entering{ opacity:0; transform:translate(-50%, 12px); }
body.tenant .md-snackbar-text{ flex:1; min-width:0; padding:10px 8px 10px 0; }
body.tenant .md-snackbar-action,
body.tenant .md-snackbar-close{ flex:none; display:inline-flex; align-items:center; justify-content:center; height:40px; border:0; border-radius:var(--md-rf); background:transparent; color:inherit; font:inherit; font-weight:700; text-decoration:none; cursor:pointer; }
body.tenant .md-snackbar-action{ padding:0 12px; }
body.tenant .md-snackbar-close{ width:40px; padding:0; }
body.tenant .md-snackbar-action:hover,
body.tenant .md-snackbar-close:hover{ background:color-mix(in srgb, var(--md-surf) 12%, transparent); }
body.tenant .md-snackbar-action:focus-visible,
body.tenant .md-snackbar-close:focus-visible{ outline:none; box-shadow:0 0 0 2px var(--md-surf); }
@media (max-width:760px){
  body.tenant .md-snackbar{ left:16px; right:16px; bottom:16px; width:auto; max-width:none; transform:none; }
  body.tenant .md-snackbar.is-entering{ transform:translateY(12px); }
}
@media (prefers-reduced-motion: reduce){
  body.tenant .md-snackbar{ transition:none; }
}

/* ── page header: md_page_header() — the <h1> text is exactly the title ── */
body.tenant .md3 .md-page-head{ display:flex; align-items:flex-end; justify-content:space-between; flex-wrap:wrap; gap:12px 16px; margin:4px 0 20px; }
body.tenant .md3 .md-page-head-text{ flex:1 1 320px; min-width:0; }
body.tenant .md3 .md-page-title{ margin:4px 0 0; font-family:'Sora', sans-serif; font-size:26px; font-weight:700; line-height:1.2; letter-spacing:-.015em; color:var(--md-onsurf); }
body.tenant .md3 .md-page-sub{ margin:6px 0 0; max-width:640px; font-size:14px; line-height:1.5; color:var(--md-onsv); }
body.tenant .md3 .md-page-actions{ display:flex; flex-wrap:wrap; gap:8px; }
@media (max-width:760px){
  body.tenant .md3 .md-page-title{ font-size:22px; }
  body.tenant .md3 .md-page-actions{ width:100%; }
}

/* ── empty state: md_empty() — the illustration badge in the MUI on-container pairs ── */
body.tenant .md3 .md-empty-ill.p{ background:var(--md-pc); color:var(--md-opc); }
body.tenant .md3 .md-empty-ill.t{ background:var(--md-tc); color:var(--md-otc); }
body.tenant .md3 .md-empty-ill.s{ background:var(--md-sc); color:var(--md-osc); }
body.tenant .md3 .md-empty-ill.ok{ background:var(--md-okc); color:var(--md-ookc); }
body.tenant .md3 .md-empty-ill.w{ background:var(--md-warnc); color:var(--md-owarnc); }

/* ── KPI carousel: [data-md-carousel] (opt-in, admin.js). The strip keeps the .md-grid-kpi layout
   above; these are the dots admin.js builds — 24px targets (WCAG 2.5.8) around the drawn dot.
   Reduced motion: no autoplay (admin.js reads --md3-carousel-autoplay) and no smooth scroll. ── */
body.tenant .md3 [data-md-carousel-dots]{ gap:0; }
body.tenant .md3 [data-md-carousel-dots] button{ display:inline-flex; align-items:center; justify-content:center; width:24px; height:24px; padding:0; border:0; border-radius:var(--md-rf); background:transparent; cursor:pointer; }
body.tenant .md3 [data-md-carousel-dots] button.on,
body.tenant .md3 [data-md-carousel-dots] button[aria-current="true"]{ width:24px; border-radius:var(--md-rf); background:transparent; }
body.tenant .md3 [data-md-carousel-dots] button::before{ content:''; display:block; width:7px; height:7px; border-radius:var(--md-rf); background:var(--md-outline); transition:width .2s, background .2s; }
body.tenant .md3 [data-md-carousel-dots] button.on::before,
body.tenant .md3 [data-md-carousel-dots] button[aria-current="true"]::before{ width:18px; background:var(--md-p); }
body.tenant .md3 [data-md-carousel-dots] button:focus-visible{ outline:none; box-shadow:var(--focus-ring); }
@media (prefers-reduced-motion: reduce){
  body.tenant [data-md-carousel]{ --md3-carousel-autoplay:off; scroll-behavior:auto; }
}
/* ── end MD3 components (G2) ── */

/* ── MUI foundation G3 · shell ── */
/* The tenant sidebar, header and forced first-password screen (partials/layout.php, nav_tenant.php).
   Scoped to body.tenant like everything above; new breakpoints 480 / 760 / 900 / 1100 only (M-D5). */

/* Brand: the shop's own name with the product in small type under it. Both lines sit INSIDE
   .brand-text, so admin.css's collapsed-rail rules (display:none on .brand-text) still hide them
   together. */
body.tenant .sidebar .brand-text{ min-width:0; }
body.tenant .sidebar .brand-name{ display:block; max-width:176px; overflow:hidden; text-overflow:ellipsis; font-size:15px; line-height:1.2; color:var(--md-onsurf); }
body.tenant .sidebar .brand-sub{ display:block; margin-top:2px; font-family:'DM Sans', sans-serif; font-size:11px; font-weight:500; line-height:1.2; letter-spacing:.01em; color:var(--md-onsv); }
/* ≤900px the sidebar is the off-canvas drawer with every label shown — so is the shop's name, which
   admin.css's phone rule (.brand-text hidden ≤520px, made for the old one-word brand) would drop. */
@media (max-width:900px){
  body.tenant .sidebar .brand-text{ display:inline-block; }
}

/* ONE active nav item: the Material 3 navigation-drawer indicator (a full-rounded pill), filled with the
   primary like the G2 active tab, so the state stands well over 3:1 against the sidebar (WCAG 1.4.11)
   instead of resting on weight alone. It replaces admin.css's left ::before bar, switched off here, and
   it paints no box-shadow — so the keyboard focus ring below is always the one that shows. */
body.tenant .sidebar .nav-item{ border-radius:var(--md-rf); }
body.tenant .sidebar .nav-item.active{ background:var(--md-p); color:var(--md-op); font-weight:600; }
body.tenant .sidebar .nav-item.active:hover{ background:color-mix(in srgb, var(--md-op) 8%, var(--md-p)); color:var(--md-op); }
body.tenant .sidebar .nav-item.active::before{ content:none; }
body.tenant .sidebar .nav-item:focus-visible,
body.tenant .sidebar .nav-item.active:focus-visible{ outline:none; box-shadow:var(--focus-ring); }

/* The icon rail admin.css collapses the sidebar into between 901 and 1100px hides the section titles;
   the section-accent rule near the top of this file re-displayed them there, as clipped text in a 76px
   rail. Hide them in the rail again; the ≤900px drawer shows every label, titles included. */
@media (max-width:1100px){
  body.tenant .app:not(.collapsed) .nav-section[data-accent] .nav-section-title{ display:none; }
}
@media (max-width:900px){
  body.tenant .app:not(.collapsed) .nav-section[data-accent] .nav-section-title{ display:flex; }
}

/* A header without the product search (the user may not open Products): the spacer keeps the account
   menu at the far end, where the search would otherwise have pushed it. */
body.tenant .header .header-spacer{ flex:1 1 auto; min-width:0; }

/* The forced first-password screen: brand · Sign out · the page. layout.php draws it with inline
   geometry shared with the platform panel (which loads no tenant.css); these are the tenant finishes. */
body.tenant .forced-header .forced-brand-mark,
body.tenant .forced-header .forced-brand-name{ font-family:'Sora', sans-serif; }
body.tenant .forced-main .content{ padding-top:32px; }
@media (max-width:480px){
  body.tenant .forced-header .forced-brand-sub{ display:none; }
  body.tenant .forced-main .content{ padding-top:20px; }
}
/* ── end MUI foundation G3 · shell ── */

/* ── MUI foundation G3 · sign-in ── */
/* The four sign-in pages (signin, forgot-password, reset-password, verify-2fa) are <body class="md3-auth">
   and load this file after admin.css. The four --md-* token sets above list body.md3-auth next to
   body.tenant, so ONE palette serves both — and it follows the device's stored light / dark /
   high-contrast choice here, as those pages always did (ruling M-R3: only the tenant PANEL is locked
   light). Painted only with MUI role pairs (a fill and its own on-colour), all measured by
   tests/md3_tokens_test.php in every set. Nothing here matches body.tenant. */
body.md3-auth{
  --focus-ring: 0 0 0 2px var(--md-c0), 0 0 0 4px var(--md-p);
  background:var(--md-surf); color:var(--md-onsurf);
}
body.md3-auth a{ color:var(--md-p); }
body.md3-auth a:hover{ color:var(--md-p); text-decoration:underline; text-underline-offset:2px; }

/* the brand side: a flat primary-container panel (M3 has no gradients) */
body.md3-auth .auth-aside{ background:var(--md-pc); color:var(--md-opc); }
body.md3-auth .auth-aside::before{ content:none; }
body.md3-auth .md3-auth-mark{ background:var(--md-p); color:var(--md-op); }
/* the same mark over the form, for the widths where the brand side is hidden */
body.md3-auth .md3-auth-brand{ display:none; align-items:center; gap:10px; margin:0 0 28px; font-weight:700; font-size:16px; color:var(--md-onsurf); }

/* the form side */
body.md3-auth .auth-form-wrap,
body.md3-auth .auth-main{ background:var(--md-surf); }
body.md3-auth .auth-card .auth-form{ background:var(--md-c1); color:var(--md-onsurf); border:var(--md-bw) solid var(--md-outlinev); border-radius:var(--md-rl); box-shadow:none; }
body.md3-auth .text-muted,
body.md3-auth .auth-sub{ color:var(--md-onsv); }
body.md3-auth .label{ color:var(--md-onsurf); }
body.md3-auth .input{ height:48px; background:var(--md-surf); color:var(--md-onsurf); border:var(--md-bw) solid var(--md-outline); border-radius:var(--md-rx); }
body.md3-auth .input::placeholder{ color:var(--md-onsv); }
body.md3-auth .input:hover{ border-color:var(--md-onsurf); }
body.md3-auth .input:focus{ border-color:var(--md-p); box-shadow:inset 0 0 0 1px var(--md-p); }
body.md3-auth .input-group{ background:var(--md-surf); border:var(--md-bw) solid var(--md-outline); border-radius:var(--md-rx); }
body.md3-auth .input-group:hover{ border-color:var(--md-onsurf); }
body.md3-auth .input-group:focus-within{ border-color:var(--md-p); box-shadow:inset 0 0 0 1px var(--md-p); }
body.md3-auth .input-group .input{ height:46px; border:0; box-shadow:none; background:transparent; }
body.md3-auth .input-group-addon{ background:transparent; color:var(--md-onsv); }
body.md3-auth .checkbox{ accent-color:var(--md-p); }
body.md3-auth .btn-primary{ background:var(--md-p); color:var(--md-op); border-radius:var(--md-rf); box-shadow:none; }
body.md3-auth .btn-primary:hover:not(:disabled){ background:color-mix(in srgb, var(--md-op) 8%, var(--md-p)); box-shadow:none; }
body.md3-auth .btn-secondary{ background:transparent; color:var(--md-p); border:var(--md-bw) solid var(--md-outline); border-radius:var(--md-rf); }
body.md3-auth .btn-secondary:hover:not(:disabled){ background:color-mix(in srgb, var(--md-p) 8%, var(--md-surf)); }
/* admin.css gives .btn-primary its own box-shadow after :focus-visible — the ring must win here too */
body.md3-auth .btn:focus-visible,
body.md3-auth .btn-primary:focus-visible{ outline:none; box-shadow:var(--focus-ring); }
body.md3-auth .alert.danger,
body.md3-auth .alert.error{ background:var(--md-errc); color:var(--md-oerrc); border-color:transparent; }
body.md3-auth .alert.success{ background:var(--md-okc); color:var(--md-ookc); border-color:transparent; }
html[data-contrast="high"] body.md3-auth .alert{ border-color:currentColor; }

/* ≤900px: one column, brand mark over the form. (verify-2fa's own inline styles set a two-column grid
   at every width; this out-ranks them, as admin.css's own ≤900px rule was meant to.) */
@media (max-width:900px){
  body.md3-auth .auth-shell{ grid-template-columns:1fr; }
  body.md3-auth .auth-aside{ display:none; }
  body.md3-auth .md3-auth-brand{ display:flex; }
}
@media (max-width:480px){
  body.md3-auth .auth-form-wrap,
  body.md3-auth .auth-main{ padding:24px 16px; }
  body.md3-auth .auth-card .auth-form{ padding:24px 20px; }
}
/* ── end MUI foundation G3 · sign-in ── */

/* ── MD3 pages (B1) ── */
/* Layout patterns the B1 tenant pages share (Vendor Bills, Payments, Profile, …), plus one neutral hover
   for row links, drawn with the declared --md-c2 that md-table rows already hover with. No other colour
   and no new token here; any breakpoint added to this block uses 480 / 760 / 900 / 1100 only. */
/* The centred row of next-step links under an md_empty() state; two or more links (Inventory's
   no-stock state) are spaced and wrap on a phone. */
body.tenant .md3 .md-empty-actions{ display:flex; flex-wrap:wrap; justify-content:center; gap:8px; margin-top:-12px; padding:0 19px 24px; }
/* A card title set as an <h2>: the .md-card-t metrics, without the browser's h2 margins. */
body.tenant .md3 h2.md-card-t{ margin:3px 0 0; }
/* A whole md-li row that is a link (the Categories tree and brand rows): the md-table row hover. */
body.tenant .md3 a.md-li:hover{ background:var(--md-c2); }
/* Categories & Brands (CAT-A): the list card lets a row menu open past its edge; tree rows indent one step per
   level (22px, 10px on a phone, where the level icons go and the status / count tags become sub-line text, so a
   5-level name keeps its room; display lives here, not inline, so the phone rule can win); the row menu is
   a small surface anchored to its button, never wider than the screen. */
body.tenant .md3 .md-card.cat-card{ overflow:visible; }
body.tenant .md3 .cat-row.cat-d2{ padding-left:41px; }
body.tenant .md3 .cat-row.cat-d3{ padding-left:63px; }
body.tenant .md3 .cat-row.cat-d4{ padding-left:85px; }
body.tenant .md3 .cat-row.cat-d5{ padding-left:107px; }
body.tenant .md3 .cat-row .cat-ico,
body.tenant .md3 .cat-row .cat-sub{ display:inline-flex; }
body.tenant .md3 .cat-row .cat-meta-m{ display:none; }
body.tenant .md3 .cat-menu-wrap{ position:relative; flex:none; }
body.tenant .md3 .cat-menu{ position:absolute; right:0; top:calc(100% + 4px); z-index:50; min-width:200px; max-width:calc(100vw - 32px); padding:4px 0; background:var(--md-c0); border:var(--md-bw) solid var(--md-outlinev); border-radius:var(--md-rm); box-shadow:0 8px 24px color-mix(in srgb, var(--md-onsurf) 16%, transparent); }
body.tenant .md3 .cat-menu form{ margin:0; }
body.tenant .md3 .cat-menu-item{ display:flex; align-items:center; gap:10px; width:100%; padding:9px 14px; border:0; background:transparent; color:var(--md-onsurf); font:inherit; font-size:13.5px; text-align:left; text-decoration:none; white-space:nowrap; cursor:pointer; }
body.tenant .md3 .cat-menu-item:hover{ background:var(--md-c2); }
body.tenant .md3 .cat-menu-item:focus-visible{ background:var(--md-c2); outline:2px solid var(--md-p); outline-offset:-2px; }
body.tenant .md3 .cat-menu-item.danger{ color:var(--md-err); }
@media (max-width:760px){
  body.tenant .md3 .cat-row.cat-d2{ padding-left:29px; }
  body.tenant .md3 .cat-row.cat-d3{ padding-left:39px; }
  body.tenant .md3 .cat-row.cat-d4{ padding-left:49px; }
  body.tenant .md3 .cat-row.cat-d5{ padding-left:59px; }
  body.tenant .md3 .cat-row .cat-ico,
  body.tenant .md3 .cat-row .cat-sub,
  body.tenant .md3 .cat-row .cat-tag,
  body.tenant .md3 .md-li .md-av.cat-ico{ display:none; }
  body.tenant .md3 .cat-row .cat-meta-m{ display:inline; }
}
/* ── end MD3 pages (B1) ── */

/* ── MD3 pages (B2) ── */
/* Layout patterns the B2 tenant pages share (Team, Positions, Attendance, the Sales-hub A/R views), drawn only with
   declared --md-* tokens; any breakpoint added to this block uses 480 / 760 / 900 / 1100 only. */
/* The attendance roster (team/attendance.php): each row is its own attendance.mark <form> — who (avatar, name,
   branch, the current mark) · the status picker · note + Save. The grid lives here and not inline, because an
   inline grid-template-columns would out-rank the phone rule and the row could never stack. ≤760px: one column,
   the picker's four buttons share its width and the note field takes what Save leaves. */
body.tenant .md3 .md-att-row{ display:grid; grid-template-columns:minmax(0,1fr) auto auto; align-items:center; gap:12px; margin:0; padding:12px 16px; }
body.tenant .md3 .md-att-row + .md-att-row{ border-top:var(--md-bw) solid var(--md-outlinev); }
@media (max-width:760px){
  body.tenant .md3 .md-att-row{ grid-template-columns:minmax(0,1fr); gap:10px; }
  body.tenant .md3 .md-att-pick > button{ flex:1 1 0; }
  body.tenant .md3 .md-att-row .md-field-input{ flex:1 1 auto; }
}
/* The master-detail split (team/positions.php; team/index.php reuses it): a 260-320px list beside the detail,
   ONE column ≤900px, where a fixed list column would squeeze the detail. The detail track is the plan's 1fr with a
   zero minimum: a bare 1fr keeps min-width:auto, so one long value could widen the page instead of wrapping (the
   .pos-detail-grid note above). */
body.tenant .md3 .md-split{ display:grid; grid-template-columns:minmax(260px,320px) minmax(0,1fr); gap:12px; align-items:start; }
/* Two equal columns of fields — a dialog's field pair (Positions' rank · commission; the Team dialogs and the Team
   Profile edit form reuse it) — ONE column ≤480px. No row gap: each md_field() carries its own bottom margin. */
body.tenant .md3 .md-form-grid2{ display:grid; grid-template-columns:minmax(0,1fr) minmax(0,1fr); gap:0 12px; }
/* A label · value grid (team's Profile details, Positions' Details): each fact one .md-kv row — the label left, the
   value right and wrapping, never cut to an ellipsis — with a divider above it. As many columns of at least 240px as
   the card fits (auto-fit): two in a wide card, ONE below ~508px — on a phone, and in the 901-1200px split, where two
   fixed columns squeezed each value into ~56-118px. Baselines, in the grid and in each row: the facts side by side
   share their first baseline, and a label sits beside the FIRST line of a value that wraps. (A row that centred its
   label would move its own baseline down beside a tall value, and the grid would then drop the row's neighbour — and
   its divider — by as much as 29px to meet it.) */
body.tenant .md3 .md-kv-grid{ display:grid; grid-template-columns:repeat(auto-fit, minmax(min(100%, 240px), 1fr)); align-items:baseline; column-gap:28px; }
body.tenant .md3 .md-kv{ display:flex; justify-content:space-between; align-items:baseline; gap:10px; min-width:0; padding:10px 0; border-top:var(--md-bw) solid var(--md-outlinev); }
body.tenant .md3 .md-kv-k{ flex-shrink:0; font-size:12px; font-weight:500; color:var(--md-onsv); }
body.tenant .md3 .md-kv-v{ min-width:0; font-size:13px; font-weight:600; color:var(--md-onsurf); text-align:right; overflow-wrap:anywhere; }
/* Team's role-filter chips (team/index.php: .md-chips.md-role-chips, 28px chips): a chip is never wider than its row,
   which wraps, and a long position name stays on ONE line inside its chip, cut to an ellipsis — the label's title
   carries the full name — instead of wrapping out of the chip onto the chip rows above and below it. */
body.tenant .md3 .md-role-chips .md-chip{ max-width:100%; min-width:0; }
body.tenant .md3 .md-role-chips .md-chip-label{ min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
body.tenant .md3 .md-role-chips .md-chip .num{ flex-shrink:0; }
/* The ONE B2 dialog layout (Positions' three dialogs, Team's thirteen), on the G2 dialog skin. The box keeps exactly
   class="modal md-dialog md3" and is laid out inline as a flex column with no padding of its own, so these three
   regions carry the skin's padding instead: the title row and the actions never scroll away, and only the fields
   scroll, between two dividers. The regions pair with the skin's .md-dialog-body / .md-dialog-actions (this block
   comes later, so its margin:0 wins over the skin's actions margin). ≤480px: the skin's 20px phone padding. */
body.tenant .md3 .md-dlg-head{ display:flex; align-items:flex-start; gap:16px; flex-shrink:0; padding:24px 24px 16px; }
body.tenant .md3 .md-dlg-body{ flex:1 1 auto; min-height:0; overflow-y:auto; padding:20px 24px 4px; border-top:var(--md-bw) solid var(--md-outlinev); border-bottom:var(--md-bw) solid var(--md-outlinev); }
body.tenant .md3 .md-dlg-foot{ flex-shrink:0; margin:0; padding:16px 24px 24px; }
/* A wrapper between the title row and a dialog's form (team's wage_revision: the x-show="compTab…" section): a flex
   column that shrinks to the box and hands its height on to the form, so on a short screen only .md-dlg-body scrolls
   and the actions stay in view. A class, because x-show owns the wrapper's inline display. */
body.tenant .md3 .md-dlg-section{ display:flex; flex-direction:column; flex:1 1 auto; min-height:0; }
/* The Sales-hub A/R tables (orders/_ar.php): an amount or a row action never breaks inside its cell — "Rs" stays with
   its figure and "+ Invoice" on one line, while the customer name takes the squeeze and wraps. ≤760px, where
   md-table stack turns each row into a card of label · value lines, a long contact (an e-mail has no break point) may
   wrap anywhere instead of running out of the card; wider, the table keeps it whole. */
body.tenant .md3 .md-ar-table td.num{ white-space:nowrap; }
@media (max-width:760px){
  body.tenant .md3 .md-ar-table td[data-label]{ overflow-wrap:anywhere; }
}
@media (max-width:900px){
  body.tenant .md3 .md-split{ grid-template-columns:minmax(0,1fr); }
}
@media (max-width:480px){
  body.tenant .md3 .md-form-grid2{ grid-template-columns:minmax(0,1fr); }
  body.tenant .md3 .md-dlg-head{ padding:20px 20px 16px; }
  body.tenant .md3 .md-dlg-body{ padding:20px 20px 4px; }
  body.tenant .md3 .md-dlg-foot{ padding:16px 20px 20px; }
}
/* ── end MD3 pages (B2) ── */

/* ── UI polish (UIP) ── */
/* The UI/UX polish lane's primitives (docs/superpowers/specs/2026-09-26-ui-polish-design.md). B1/B2 discipline:
   breakpoints 480 / 760 / 900 / 1100 only, no !important, declared --md-* tokens only, body.tenant .md3 scope. */

/* P3 money: md_money() — never wraps, tabular figures; a negative amount is the error colour AND has a sign */
body.tenant .md3 .md-money{ white-space:nowrap; font-variant-numeric:tabular-nums; }
body.tenant .md3 .md-money.neg{ color:var(--md-err); }

/* P2 stat card extras: the negative value, the sub line, the two semantic tones */
body.tenant .md3 .md-kpi .v.neg{ color:var(--md-err); }
body.tenant .md3 .md-kpi .s{ grid-area:s; margin-top:6px; font-size:12px; line-height:1.35; color:var(--md-onsv); }
/* A page that still writes its sub line as a SECOND .l (purchasing's $summary tiles) gets it on the sub-line row;
   otherwise both .l elements share the label's grid area and print over each other. */
body.tenant .md3 .md-kpi .l ~ .l{ grid-area:s; }
body.tenant .md3 .md-kpi.k-ok, body.tenant .md3 .md-kpi.k-err{ background:var(--md-c0); color:var(--md-onsurf); }
body.tenant .md3 .md-kpi.k-ok .ico{ background:var(--md-okc); color:var(--md-ookc); }
body.tenant .md3 .md-kpi.k-err .ico{ background:var(--md-errc); color:var(--md-oerrc); }
body.tenant .md3 .md-kpi.k-ok .t, body.tenant .md3 .md-kpi.k-err .t{ background:var(--md-c2); color:var(--md-onsv); }

/* P2 grid: a strip of 4 or 5 cards never strands one card on a row of its own. auto-fit at the 200px minimum does
   (4 cards → 3 + 1, 5 cards → 4 + 1, at common widths from 1280 down to 768), so those two counts use the same
   200px / 12px geometry but skip the stranding count: 4 cards sit four in a row while each keeps 200px (a strip of
   4 × 200 + 3 × 12 = 836px), else 2 × 2; 5 cards sit five in a row from 5 × 200 + 4 × 12 = 1048px, else 3 + 2.
   clamp() picks the track: (threshold − 100%) × 999 is ≤ 0 on a wide strip (→ the N-up width) and huge on a
   narrow one (→ the fallback width); each width is 1px short of an exact fit so rounding never drops a column.
   ≤640px the strip is the swipe carousel (display:flex) and ignores these tracks; a page's inline
   grid-template-columns still wins. */
body.tenant .md3 .md-grid-kpi:has(> .md-kpi:nth-child(4):last-child){ grid-template-columns:repeat(auto-fit,minmax(clamp((100% - 37px) / 4, (836px - 100%) * 999, (100% - 13px) / 2),1fr)); }
body.tenant .md3 .md-grid-kpi:has(> .md-kpi:nth-child(5):last-child){ grid-template-columns:repeat(auto-fit,minmax(clamp((100% - 49px) / 5, (1048px - 100%) * 999, (100% - 25px) / 3),1fr)); }

/* P4 table: the action column */
body.tenant .md3 .md-table .act{ text-align:right; white-space:nowrap; }

/* P5 field filters: labelled controls in one row, the buttons aligned to the 44px controls. The wide search field is
   an md_field() inside a <div class="md-filters-grow"> (md_field() prints its own wrapper, which takes no class). */
body.tenant .md3 .md-filters{ display:flex; flex-wrap:wrap; align-items:flex-end; column-gap:12px; margin-bottom:6px; }
body.tenant .md3 .md-filters > .md-field{ flex:0 1 200px; min-width:0; }
body.tenant .md3 .md-filters > .md-filters-grow{ flex:1 1 240px; max-width:320px; min-width:0; }
body.tenant .md3 .md-filters > .md-filters-act{ flex:none; display:flex; align-items:center; gap:4px; margin-bottom:16px; }

/* P10 sections: a key / value overview grid (<dl class="md-kv">), a section title, a form actions row.
   The grid is dl.md-kv on purpose: the frozen B2 block already owns .md-kv as the Team / Positions label · value
   ROW (<div class="md-kv">, a flex row), and a bare .md-kv here (later, same specificity) would re-lay every one of
   those rows as this grid. B2's row rule still matches the <dl>, so its padding, top rule and alignment are reset. */
body.tenant .md3 dl.md-kv{ display:grid; grid-template-columns:repeat(auto-fill,minmax(180px,1fr)); align-items:start; gap:14px 20px; margin:0; padding:0; border:0; }
body.tenant .md3 dl.md-kv > div{ min-width:0; }
body.tenant .md3 dl.md-kv dt{ font-size:12px; font-weight:600; color:var(--md-onsv); margin:0 0 3px; }
body.tenant .md3 dl.md-kv dd{ margin:0; font-size:14px; color:var(--md-onsurf); overflow-wrap:anywhere; }
body.tenant .md3 .md-section-t{ font-family:'Sora',sans-serif; font-size:15.5px; font-weight:700; margin:0; }
body.tenant .md3 .md-actions{ display:flex; flex-wrap:wrap; align-items:center; gap:8px 12px; margin-top:4px; }

/* P1 page header carrying user data (the Products detail: the product name as the title, its SKU in the sub line): a
   long unbroken name or code wraps inside the header instead of running past the page edge, as the old detail title
   did. The frozen G2 block owns the rest of these two rules. */
body.tenant .md3 .md-page-title, body.tenant .md3 .md-page-sub{ overflow-wrap:anywhere; }

/* A card header with a one-line note beside its title (the Products "Variants & pricing" card): the note is small muted
   text that wraps under the title on a narrow card. */
body.tenant .md3 .md-card-h.md-card-h-note{ flex-wrap:wrap; align-items:baseline; gap:4px 12px; padding-bottom:14px; }
body.tenant .md3 .md-card-note{ font-size:12.5px; line-height:1.4; color:var(--md-onsv); }

/* P4 dense tables (the Products list and variants tables; page rule 6): 8px cell sides — measured in the 901-1100px band
   (Task 9, B1): a table-mode register's narrowest card is 783px (a 901px viewport beside the 72px rail), and at 10px the
   payments register, the vendor ledger, the PO list and the products list ran 14-55px past it with ordinary data. */
body.tenant .md3 .md-table.md-dense th, body.tenant .md3 .md-table.md-dense td{ padding-left:8px; padding-right:8px; }
/* A code — .md-code, the lane's generic code primitive (a SKU; page rule 5 as amended by Ruling 13): 12px and always
   WHOLE. It breaks only at its own separators (hyphen, slash, space), never inside a segment, and it is never truncated
   or left to a hover title. An unbroken code widens its column; the table then scrolls inside its card. */
body.tenant .md3 .md-table td.md-code{ font-size:12px; color:var(--md-onsv); overflow-wrap:normal; word-break:normal; }
/* The same code as an overview fact: it wraps at its separators; an unbroken code longer than its column scrolls in its
   own box instead of running over the next fact. */
body.tenant .md3 dl.md-kv dd.md-code{ overflow-wrap:normal; word-break:normal; overflow-x:auto; }
/* Tags stacked in one cell (the Products list: the status, then "Not on POS"). */
body.tenant .md3 .md-tags{ display:flex; flex-direction:column; align-items:flex-start; gap:4px; }
/* The variants table's edit row: the variant.update form of the row above, opened by that row's Edit button. */
body.tenant .md3 .md-table tr.md-vedit > td{ background:var(--md-c1); }
body.tenant .md3 .md-vedit-form{ display:flex; flex-wrap:wrap; align-items:flex-end; gap:10px 12px; margin:0; }
body.tenant .md3 .md-vedit-f{ display:flex; flex-direction:column; gap:4px; min-width:0; font-size:12px; font-weight:600; color:var(--md-onsv); }
body.tenant .md3 .md-vedit-f > .md-field-input{ font-weight:400; }
/* P4 a pinned action column (.md-stick-act — Inventory's Adjust): a separator-free code may widen its column past the card
   (Ruling 13) and the table then scrolls inside its card; the row action stays in view at the card's right edge instead of
   scrolling away with the rest. The pinned cell keeps its own surface over the cells scrolling beneath it, and a left
   divider marks where they pass under it (the row dividers are the table's own collapsed borders, drawn across it) — ONLY
   while the table actually scrolls (Task 9, A7): the divider is a scroll-driven animation on the table's own scroll
   timeline, and a timeline with nothing to scroll is inactive, so a table that fits its card shows no divider. A browser
   without scroll timelines ignores animation-timeline and runs the 1ms animation on the document timeline, where fill-mode
   "both" keeps its keyframe: there the divider is ALWAYS shown (the look before A7). animation-timeline follows the
   shorthand, which would reset it.
   Where the table is a stack of cards the cell is an ordinary card line again (the resets in the 760 / 900 blocks below). */
body.tenant .md3 .md-table.md-stick-act th.act,
body.tenant .md3 .md-table.md-stick-act td.act{ position:sticky; right:0; z-index:1; background:var(--md-c0); animation:md-uip-stick-edge 1ms linear both; animation-timeline:scroll(nearest inline); }
@keyframes md-uip-stick-edge{ from, to{ box-shadow:inset var(--md-bw) 0 0 var(--md-outlinev); } }
body.tenant .md3 .md-table.md-stick-act tbody tr:hover > td.act{ background:var(--md-c2); }
/* A visually hidden label (the "Actions" header of an action column): read by assistive tech, never drawn. Its header
   cell is its containing block: an absolute box escapes the card's clip unless something inside the table's scroller is
   positioned, so in a table scrolling inside its card it would otherwise widen the PAGE from past the card's edge. */
body.tenant .md3 .md-sr{ position:absolute; width:1px; height:1px; overflow:hidden; clip-path:inset(50%); white-space:nowrap; }
body.tenant .md3 .md-table th.act{ position:relative; }
/* A code on a line of its own (a PO line's "SKU · colour size" under its name; a free-text PO number as a card title): it
   wraps at spaces and at the code's own separators, never inside a segment (Ruling 13). An unbroken code widens its column
   and the table then scrolls in its card; in a card, which cannot widen, it scrolls in its own box (the 760 / 900 blocks
   below). */
body.tenant .md3 .md-table .md-code-line{ overflow-wrap:normal; word-break:normal; }
/* Ruling 16: in TABLE mode a GENERATED code keeps its one line. Breaking at its hyphens is allowed (Ruling 13), so the
   automatic table layout would squeeze its column to the narrowest segment ("PO-" / "202609-" / "01459") whenever a
   wider column wants the space; a min-width sized for the code in its own font prevents that. Measured with the codes'
   widest digit (0): "PO-202609-00000" 13.6ch at Sora 700 13.5px, "BILL-202609-00000" 14.9ch at DM Sans 12px. A genuinely
   longer code still wraps at its separators; the card blocks below release the min-width (a card line scrolls instead). */
body.tenant .md3 .md-table .md-code-line.md-code-po{ min-width:14ch; }
body.tenant .md3 .md-table td.md-code.md-code-bill > span{ display:inline-block; min-width:15ch; }
/* A table's total row (tr.md-total: the PO lines, the supplier ledger, the bill lines): a heavier rule above it, on the
   header tint. In a stack of cards it is one "Total · amount" line (the 760 / 900 blocks below). */
body.tenant .md3 .md-table tr.md-total > td{ border-top:2px solid var(--md-outlinev); background:var(--md-c1); }
/* A table that always fits its card (the two-column statements on Financial Reports: the label wraps, the amount stays on its
   one line) — every other .md-table keeps the 640px floor and scrolls inside its card below it. */
body.tenant .md3 .md-table.md-fit table{ min-width:0; }
/* P7 a status tag in a table cell keeps its pill whole (Posting Gaps' "tracked — retry from the open queue" broke across two
   lines at 768-901); on a card line (the 760 / 900 blocks below) it may wrap again, as one rounded block. */
body.tenant .md3 .md-table td > .md-tag{ white-space:nowrap; }
/* The frozen All Sales list (orders/_list.php — the only div.md-table.wide.deskonly; its markup cannot change): nine columns,
   so the whole-money and whole-tag rules above pushed its Issues column behind the table's own scroll (in-card overflow at
   1280 / 1100 43 → 145px, 900 155 → 257, 768 287 → 389; final review I-1). Its cells take the dense 8px sides and its Payment /
   Status tags may wrap, as one rounded block ("needs reconciliation", "partially returned"); money stays on its one line.
   Measured on the same DOM: 0 / 0 / 30 / 162px, the Issues column in view from 1100px. */
body.tenant .md3 .md-table.wide.deskonly th,
body.tenant .md3 .md-table.wide.deskonly td{ padding-left:8px; padding-right:8px; }
body.tenant .md3 .md-table.wide.deskonly td > .md-tag{ display:inline-block; white-space:normal; }
/* A disclosure list (Ledger & Books' recent journal entries): each row is a <details> whose <summary> is the entry's line — a
   chevron, the title with its date under it, the amount at the right — and whose body holds the entry's own lines. */
body.tenant .md3 .md-dlist > details{ border-top:var(--md-bw) solid var(--md-outlinev); }
body.tenant .md3 .md-dlist > details > summary{ display:flex; align-items:center; gap:12px; padding:12px 19px; cursor:pointer; list-style:none; }
body.tenant .md3 .md-dlist > details > summary::-webkit-details-marker{ display:none; }
body.tenant .md3 .md-dlist > details > summary:hover{ background:var(--md-c2); }
body.tenant .md3 .md-dlist > details > summary:focus-visible{ outline:none; box-shadow:inset 0 0 0 2px var(--md-p); }
body.tenant .md3 .md-dlist > details[open] > summary{ background:var(--md-c1); }
body.tenant .md3 .md-dlist > details > summary > svg{ flex:none; color:var(--md-onsv); transition:transform .15s; }
body.tenant .md3 .md-dlist > details[open] > summary > svg{ transform:rotate(90deg); }
body.tenant .md3 .md-dlist-main{ flex:1; min-width:0; }
body.tenant .md3 .md-dlist-t{ display:block; font-size:13.5px; }
body.tenant .md3 .md-dlist-s{ display:block; margin-top:2px; font-size:12px; color:var(--md-onsv); }
/* L5-A: Ledger & Books' disabled Close stand-in (data-period-close, before the period has ended) keeps its hover explanation —
   the G2 disabled md-btn turns pointer events off, which would hide its title; a disabled button still cannot be pressed. */
body.tenant .md3 .md-btn[data-period-close]{ pointer-events:auto; }
/* A muted second line inside a table cell (a voucher's journal entry, a void's reversal, an expense note, an asset tag). */
body.tenant .md3 .md-cell-sub{ display:block; margin-top:2px; font-size:11.5px; font-weight:400; line-height:1.35; color:var(--md-onsv); }
/* Fields side by side while each keeps 220px, else one per line (the voucher composer's date · memo, an asset's amount · date):
   flex-wrap, because the same card is 360px beside a list and full width under it. */
body.tenant .md3 .md-field-row{ display:flex; flex-wrap:wrap; column-gap:12px; }
body.tenant .md3 .md-field-row > .md-field{ flex:1 1 220px; }
/* Voucher Entries: the register beside the 360px composer while the register keeps 564px, else the composer below it. It wraps
   instead of switching at a breakpoint because the content width also depends on the sidebar (248px from 1101px, 72px at
   901-1100px), which no viewport breakpoint sees; 999 : 1 hands the spare width to the register. */
body.tenant .md3 .md-vgrid{ display:flex; flex-wrap:wrap; align-items:flex-start; gap:16px; }
body.tenant .md3 .md-vgrid-main{ flex:999 1 564px; min-width:0; }
body.tenant .md3 .md-vgrid-side{ flex:1 1 360px; min-width:0; }
/* In that ~590px column the status select starts at 160px, so search · status · Apply · Clear keep one row. */
body.tenant .md3 .md-vgrid-main .md-filters > .md-field{ flex-basis:160px; }
/* Ruling 16: a generated voucher number (MV-#####, more digits past 99999) keeps its one line in table mode. */
body.tenant .md3 .md-table td.md-code.md-code-mv > span{ display:inline-block; min-width:9ch; }
/* A composer line: the account picker whole on its own; Debit · Credit · remove beside it while it keeps 220px next to their
   260px (a full-width composer), else wrapped under it (the 360px column). The header row wraps the same way. */
body.tenant .md3 .md-vline{ display:flex; flex-wrap:wrap; align-items:center; gap:8px; margin-bottom:10px; }
body.tenant .md3 .md-vline-acct{ flex:3 1 220px; min-width:0; }
body.tenant .md3 .md-vline-amts{ flex:2 1 260px; min-width:0; display:flex; align-items:center; gap:8px; }
body.tenant .md3 .md-vline-amts > .md-field-input{ flex:1 1 0; min-width:0; text-align:right; font-variant-numeric:tabular-nums; }
body.tenant .md3 .md-vline-head{ margin-bottom:6px; font-size:11px; font-weight:700; text-transform:uppercase; letter-spacing:.05em; color:var(--md-onsv); }
body.tenant .md3 .md-vline-head .md-vline-amts > span{ flex:1 1 0; min-width:0; text-align:right; }
body.tenant .md3 .md-vline-head .md-vline-amts > span:last-child{ flex:none; width:36px; }
/* The composer's running balance: the totals in the text colour; the difference ok / err only once it means something. */
body.tenant .md3 dl.md-vbal{ margin:8px 0 16px; padding:12px 14px; border:var(--md-bw) solid var(--md-outlinev); border-radius:var(--md-rm); background:var(--md-c1); font-size:13px; }
body.tenant .md3 dl.md-vbal > div{ display:flex; justify-content:space-between; align-items:baseline; gap:12px; padding:2px 0; }
body.tenant .md3 dl.md-vbal dt{ color:var(--md-onsv); }
body.tenant .md3 dl.md-vbal dd{ margin:0; font-weight:600; font-variant-numeric:tabular-nums; white-space:nowrap; color:var(--md-onsurf); }
body.tenant .md3 dl.md-vbal > .md-vbal-diff{ margin-top:6px; padding-top:8px; border-top:var(--md-bw) solid var(--md-outlinev); }
body.tenant .md3 dl.md-vbal > .md-vbal-diff dt{ font-weight:700; color:var(--md-onsurf); }
body.tenant .md3 dl.md-vbal > .md-vbal-diff dd{ font-weight:700; }
body.tenant .md3 dl.md-vbal dd.ok{ color:var(--md-ok); }
body.tenant .md3 dl.md-vbal dd.err{ color:var(--md-err); }

@media (max-width:760px){
  body.tenant .md3 .md-filters{ display:block; }
  body.tenant .md3 .md-filters > .md-filters-grow{ max-width:none; }
  body.tenant .md3 .md-filters > .md-filters-act{ margin-bottom:12px; }
  /* .stack cards: a code line keeps the WHOLE code — wrapped at its separators, flush right with the other values; an
     unbroken code longer than the card scrolls in its own box (a card cannot widen the way a column does). */
  body.tenant .md3 .md-table.stack td.md-code > span{ min-width:0; overflow-x:auto; text-align:right; }
  /* an action line keeps its buttons together at the right (Edit · Archive), not spread out by space-between */
  body.tenant .md3 .md-table.stack td.act[data-label]{ gap:8px; }
  body.tenant .md3 .md-table.stack td.act[data-label]::before{ margin-right:auto; }
  /* the variants cards: the gap sits ABOVE each card (tr + tr), so a hidden edit row after the last card adds no
     bottom gap; an open edit card follows the card above it by 6px (it overlapped it by 4px at -4px — Task 9, C3) and
     keeps its own surface on hover; its cell is a form, not a card title */
  body.tenant .md3 .md-table.stack.md-vlist tbody tr{ margin-bottom:0; }
  body.tenant .md3 .md-table.stack.md-vlist tbody tr + tr{ margin-top:10px; }
  body.tenant .md3 .md-table.stack.md-vlist tbody tr + tr.md-vedit{ margin-top:6px; }
  body.tenant .md3 .md-table.stack.md-vlist tbody tr.md-vedit,
  body.tenant .md3 .md-table.stack.md-vlist tbody tr.md-vedit:hover{ background:var(--md-c0); }
  body.tenant .md3 .md-table.stack tr.md-vedit > td:first-child{ margin:0; font-size:14px; font-weight:400; background:transparent; }
  /* a pinned action cell inside a .stack card is an ordinary card line */
  body.tenant .md3 .md-table.stack.md-stick-act th.act,
  body.tenant .md3 .md-table.stack.md-stick-act td.act,
  body.tenant .md3 .md-table.stack.md-stick-act tbody tr:hover > td.act{ position:static; background:transparent; box-shadow:none; animation:none; }
  /* a code line under a card's title keeps the whole code: longer than the card, it scrolls in its own box */
  body.tenant .md3 .md-table.stack .md-code-line{ overflow-x:auto; }
  /* Ruling 16's table-mode minimum does not apply to a card line */
  body.tenant .md3 .md-table.stack .md-code-line.md-code-po,
  body.tenant .md3 .md-table.stack td.md-code.md-code-bill > span{ min-width:0; }
  body.tenant .md3 .md-table.stack td.md-code.md-code-mv > span{ min-width:0; }
  /* a card line's value that carries a second line (.md-cell-val: a memo and its journal reference, a description and its
     note) sits flush right like every other value, both of its lines */
  body.tenant .md3 .md-table.stack td[data-label] > .md-cell-val{ min-width:0; text-align:right; }
  /* a total row is one "Total · amount" card line under the cards (a <tfoot> row gets the card surface too) */
  body.tenant .md3 .md-table.stack tfoot{ display:block; }
  body.tenant .md3 .md-table.stack tr.md-total{ display:flex; align-items:baseline; justify-content:space-between; gap:12px; padding:14px 16px; background:var(--md-c1); border:var(--md-bw) solid var(--md-outlinev); border-radius:var(--md-rm); }
  body.tenant .md3 .md-table.stack tfoot tr.md-total{ margin-top:10px; }
  body.tenant .md3 .md-table.stack tr.md-total > td{ border:0; background:transparent; }
  body.tenant .md3 .md-table.stack tr.md-total > td:first-child{ margin:0; font-size:14px; font-weight:700; }
  body.tenant .md3 .md-table.stack tr.md-total > td:empty{ display:none; }
  /* a tag on a card line may wrap (a narrow phone), as one rounded block */
  body.tenant .md3 .md-table.stack td > .md-tag{ white-space:normal; display:inline-block; text-align:right; }
  /* a total row with two labelled amounts (the Ledger trial balance's Debit and Credit): each is a card line of its own */
  body.tenant .md3 .md-table.stack tr.md-total:has(> td[data-label]){ flex-wrap:wrap; row-gap:0; }
  body.tenant .md3 .md-table.stack tr.md-total > td[data-label]{ flex:1 1 100%; }
  /* .md-stick-first (the Financial Reports trial balance, whose indented group rows cannot become cards): the table scrolls
     inside its card while its account column stays in view, a divider marking where the amounts pass under it. The column
     keeps a readable 160px (the names wrap), and each row's own background — opaque, so nothing shows through — is the
     sticky cell's too, the tinted group rows and the total row included. */
  body.tenant .md3 .md-table.md-stick-first table{ width:auto; min-width:100%; }
  body.tenant .md3 .md-table.md-stick-first thead tr,
  body.tenant .md3 .md-table.md-stick-first tbody tr{ background-color:var(--md-c0); }
  body.tenant .md3 .md-table.md-stick-first tbody tr:hover{ background-color:var(--md-c2); }
  body.tenant .md3 .md-table.md-stick-first th:first-child,
  body.tenant .md3 .md-table.md-stick-first td:first-child{ position:sticky; left:0; z-index:1; width:160px; background-color:inherit; box-shadow:inset calc(-1 * var(--md-bw)) 0 0 var(--md-outlinev); }
  body.tenant .md3 .md-table.md-stick-first tr.md-total > td:first-child{ background-color:var(--md-c1); }
  /* a cell spanning several columns (an opening / closing balance line, an empty note) scrolls with the row */
  body.tenant .md3 .md-table.md-stick-first td[colspan]:first-child{ position:static; width:auto; box-shadow:none; }
}
/* ≤900px: a .md-table.stack that also carries .stack-900 (the Products list: nine columns cannot fit a 768 card)
   becomes cards from 900px, not 760px — the shared .stack declarations repeated one breakpoint up, so a tablet held
   upright never shows that table cut off mid-cell. */
@media (max-width:900px){
  body.tenant .md3 .md-table.stack-900{ overflow-x:visible; padding:12px; }
  body.tenant .md3 .md-table.stack-900 table{ min-width:0; display:block; }
  body.tenant .md3 .md-table.stack-900 thead{ display:none; }
  body.tenant .md3 .md-table.stack-900 tbody{ display:block; }
  body.tenant .md3 .md-table.stack-900 tbody tr{ display:block; padding:14px 16px; margin-bottom:10px; background:var(--md-c1); border:var(--md-bw) solid var(--md-outlinev); border-radius:var(--md-rm); }
  body.tenant .md3 .md-table.stack-900 tbody tr:last-child{ margin-bottom:0; }
  body.tenant .md3 .md-table.stack-900 tbody tr:hover{ background:var(--md-c1); }
  body.tenant .md3 .md-table.stack-900 td{ display:block; border:0; padding:0; }
  body.tenant .md3 .md-table.stack-900 td:first-child:not([data-label]){ font-size:14.5px; font-weight:600; margin-bottom:8px; }
  body.tenant .md3 .md-table.stack-900 td[data-label]{ display:flex; align-items:center; justify-content:space-between; gap:12px; padding:5px 0; text-align:left; }
  body.tenant .md3 .md-table.stack-900 td[data-label]::before{ content:attr(data-label); flex:none; font-size:11px; font-weight:700; text-transform:uppercase; letter-spacing:.05em; color:var(--md-onsv); }
  /* the ≤760 card finishes above, one breakpoint up */
  body.tenant .md3 .md-table.stack-900 td.md-code > span{ min-width:0; overflow-x:auto; text-align:right; }
  body.tenant .md3 .md-table.stack-900 td.act[data-label]{ gap:8px; }
  body.tenant .md3 .md-table.stack-900 td.act[data-label]::before{ margin-right:auto; }
  body.tenant .md3 .md-table.stack-900 td > .md-tag{ white-space:normal; display:inline-block; text-align:right; }
  body.tenant .md3 .md-table.stack-900 td[data-label] > .md-cell-val{ min-width:0; text-align:right; }
  body.tenant .md3 .md-table.stack-900.md-stick-act th.act,
  body.tenant .md3 .md-table.stack-900.md-stick-act td.act,
  body.tenant .md3 .md-table.stack-900.md-stick-act tbody tr:hover > td.act{ position:static; background:transparent; box-shadow:none; animation:none; }
  /* a .stack-900 row list with edit rows (Inventory, .md-vlist): the ≤760 variants-card spacing one breakpoint up — the gap
     sits above each card, so a hidden edit row after the last card adds no bottom gap; an open edit card follows its row
     card by 6px on its own surface; its one cell is a form, not a card title */
  body.tenant .md3 .md-table.stack-900.md-vlist tbody tr{ margin-bottom:0; }
  body.tenant .md3 .md-table.stack-900.md-vlist tbody tr + tr{ margin-top:10px; }
  body.tenant .md3 .md-table.stack-900.md-vlist tbody tr + tr.md-vedit{ margin-top:6px; }
  body.tenant .md3 .md-table.stack-900.md-vlist tbody tr.md-vedit,
  body.tenant .md3 .md-table.stack-900.md-vlist tbody tr.md-vedit:hover{ background:var(--md-c0); }
  body.tenant .md3 .md-table.stack-900 tr.md-vedit > td:first-child{ margin:0; font-size:14px; font-weight:400; background:transparent; }
  /* the ≤760 code line (Ruling 16's minimum released) and total row, one breakpoint up */
  body.tenant .md3 .md-table.stack-900 .md-code-line{ overflow-x:auto; }
  body.tenant .md3 .md-table.stack-900 .md-code-line.md-code-po,
  body.tenant .md3 .md-table.stack-900 td.md-code.md-code-bill > span{ min-width:0; }
  body.tenant .md3 .md-table.stack-900 tfoot{ display:block; }
  body.tenant .md3 .md-table.stack-900 tr.md-total{ display:flex; align-items:baseline; justify-content:space-between; gap:12px; padding:14px 16px; background:var(--md-c1); border:var(--md-bw) solid var(--md-outlinev); border-radius:var(--md-rm); }
  body.tenant .md3 .md-table.stack-900 tfoot tr.md-total{ margin-top:10px; }
  body.tenant .md3 .md-table.stack-900 tr.md-total > td{ border:0; background:transparent; }
  body.tenant .md3 .md-table.stack-900 tr.md-total > td:first-child{ margin:0; font-size:14px; font-weight:700; }
  body.tenant .md3 .md-table.stack-900 tr.md-total > td:empty{ display:none; }
}

/* People & payroll (Staff & HR, Positions, Compensation, Attendance, Payroll, Salary structures, Statutory rules). */
/* The shared Team & payroll tab bar (team/_tab_bar.php, its markup frozen) under the page header, spaced like a module-tab row; its
   eight pills keep one row in the 984px content column at 1280 (and at 1100 beside the rail): 12px sides instead of 14px, so
   "Payroll" is no longer left alone on a second row. */
body.tenant .md3 .md-team-tabs{ margin-bottom:16px; }
body.tenant .md3 .md-team-tabs .md-pill-tab{ padding:0 12px; }
/* Compensation's card grids — the 2 × 2 pay components and the three organisation cards, ONE column ≤760px (at 375 the cards were
   squeezed to ~150px); each card keeps its own height. */
body.tenant .md3 .md-comp-grid{ display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:16px; align-items:start; }
body.tenant .md3 .md-comp-grid.md-comp-grid3{ grid-template-columns:repeat(3,minmax(0,1fr)); }
/* A card title set as an <h3> (the organisation cards under Compensation's "Organization & templates" heading): the .md-card-t
   metrics without the browser's h3 margins, as the B1 block does for h2.md-card-t. */
body.tenant .md3 h3.md-card-t{ margin:3px 0 0; }
/* A list row inside a card (Compensation; Salary structures and Statutory rules reuse it): the name wraps in full, the actions stay
   together at the right and drop under the name — still at the right — when the card is narrow. */
body.tenant .md3 .md-crow{ display:flex; flex-wrap:wrap; align-items:center; gap:8px 12px; padding:12px 16px; border-top:var(--md-bw) solid var(--md-outlinev); }
body.tenant .md3 .md-crow-main{ flex:1 1 160px; min-width:0; }
body.tenant .md3 .md-crow-t{ font-size:13.5px; font-weight:600; line-height:1.35; color:var(--md-onsurf); overflow-wrap:anywhere; }
body.tenant .md3 .md-crow-s{ display:flex; flex-wrap:wrap; align-items:center; gap:6px; margin-top:4px; font-size:12px; color:var(--md-onsv); }
body.tenant .md3 .md-crow-act{ display:flex; flex-wrap:wrap; align-items:center; gap:6px; margin:0 0 0 auto; }
body.tenant .md3 .md-crow.is-archived .md-crow-main{ opacity:.7; }
/* A dialog's form between the B2 regions (.md-dlg-head / .md-dlg-body / .md-dlg-foot): a flex column that shrinks to the box, so
   only the fields scroll and the actions stay in view — what Positions writes inline, as one class. */
body.tenant .md3 .md-dlg-form{ display:flex; flex-direction:column; flex:1 1 auto; min-height:0; margin:0; }
/* A compact select inside a list row (a deduction category's settlement account): it shares its line with Save while it keeps 160px. */
body.tenant .md3 .md-crow .md-field-input.md-inline-select{ flex:1 1 160px; width:auto; min-width:0; max-width:100%; min-height:36px; padding:6px 10px; font-size:13px; }
@media (max-width:760px){
  body.tenant .md3 .md-comp-grid,
  body.tenant .md3 .md-comp-grid.md-comp-grid3{ grid-template-columns:minmax(0,1fr); }
}
/* A card that hosts a popover (Payroll's "Pay…" — the runs list and a run's detail): the panel is not clipped by the card, whose
   header strip keeps the card's corners. */
body.tenant .md3 .md-pop-host{ overflow:visible; }
body.tenant .md3 .md-pop-host > .md-pop-top{ border-radius:var(--md-rl) var(--md-rl) 0 0; }
body.tenant .md3 .md-pay{ position:relative; }
body.tenant .md3 .md-pay > summary{ list-style:none; }
body.tenant .md3 .md-pay > summary::-webkit-details-marker{ display:none; }
body.tenant .md3 .md-pay-panel{ position:absolute; right:0; top:calc(100% + 6px); z-index:20; box-sizing:border-box; width:280px; max-width:calc(100vw - 32px); padding:14px 16px; background:var(--md-c0); border:var(--md-bw) solid var(--md-outlinev); border-radius:var(--md-rm); box-shadow:0 8px 24px rgba(0, 0, 0, .14); text-align:left; }
/* A form's fields and its submit in one row that wraps, the button on the fields' line (Salary structures' Apply row); ≤760px one
   field per line and a full-width button, so the button never runs off its card on a phone. */
body.tenant .md3 .md-form-inline{ display:flex; flex-wrap:wrap; align-items:flex-end; column-gap:12px; }
body.tenant .md3 .md-form-inline > .md-field{ flex:1 1 180px; min-width:0; }
body.tenant .md3 .md-form-inline > .md-btn{ flex:none; margin-bottom:16px; }
/* Payroll's run list: status tile · period, status and journal links · net / gross · the action. */
body.tenant .md3 .md-run{ display:grid; grid-template-columns:auto minmax(0,1fr) auto auto; align-items:center; gap:10px 14px; padding:12px 16px; }
body.tenant .md3 .md-run + .md-run{ border-top:var(--md-bw) solid var(--md-outlinev); }
body.tenant .md3 .md-run.is-current{ background:var(--md-pc); }
body.tenant .md3 .md-run:last-child{ border-radius:0 0 var(--md-rl) var(--md-rl); }
body.tenant .md3 .md-run-amt{ text-align:right; }
@media (max-width:760px){
  body.tenant .md3 .md-form-inline{ flex-direction:column; align-items:stretch; }
  body.tenant .md3 .md-form-inline > .md-field{ flex:0 0 auto; }
  body.tenant .md3 .md-form-inline > .md-btn{ align-self:stretch; }
  /* a run: tile · period on the first line, the amounts under the period, the action on a line of its own at the right. Beside
     the amounts (their 1fr column shrinking below its text) "Approve" was drawn over the net and gross lines at 375 (visual review
     V1); at the right the Pay… popover still opens leftwards inside the card. */
  body.tenant .md3 .md-run{ grid-template-columns:auto minmax(0,1fr); grid-template-areas:"ico main" "ico amt" "ico act"; }
  body.tenant .md3 .md-run-ico{ grid-area:ico; align-self:start; }
  body.tenant .md3 .md-run-main{ grid-area:main; }
  body.tenant .md3 .md-run-amt{ grid-area:amt; text-align:left; }
  body.tenant .md3 .md-run-act{ grid-area:act; justify-self:end; }
}
/* A member's name in the Staff & HR tree wraps in full (page rule 5): the legacy .tm-member-name rule cut it to one line. */
body.tenant .md3 .tm-member-name{ white-space:normal; overflow:visible; text-overflow:clip; overflow-wrap:anywhere; }

/* Dashboard. The chart card's header wraps, so on a phone the Combined / Online / Retail switch drops under "Sales performance"
   instead of being cut off by the card (it read "Combined | Online | Re" at 375). */
body.tenant .md3 .md-card-h.md-card-h-wrap{ flex-wrap:wrap; gap:10px 12px; }
/* A size container (the dashboard's 7-day card): a figure inside scales with the card's own width (cqi units). */
body.tenant .md3 .md-cq{ container-type:inline-size; }
/* The dashboard's activity feed (Task 9, E6): a label wraps in full and keeps at least 150px; when the amount (and on the narrowest
   phones the tag too) cannot sit beside it, it wraps onto a line of its own at the right (measured at 375: the label had ~60px and
   broke mid-word). On a wide card the label's flex-grow takes the free space, so the auto margin is 0 and the row is one line. */
body.tenant .md3 .md-li.md-feed{ flex-wrap:wrap; row-gap:4px; }
body.tenant .md3 .md-feed > .md-feed-t{ flex:1 1 150px; min-width:0; }
body.tenant .md3 .md-feed > .md-amt{ margin-left:auto; }

/* Settings: a section's fields in two columns, ONE column ≤760px (at 375 two fixed columns squeezed every field to ~150px and
   cut the branch name). The two pinned raw checkboxes ("Tax registered", the exchange-difference toggle — their markup is read
   byte for byte) sit in a <label class="md-check"> and are painted like md_checkbox()'s input. */
body.tenant .md3 .md-form-grid{ display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); column-gap:16px; }
/* A toggle that sits on a field row in the two-column grid (Settings' "Tax registered", beside GST number): aligned to the row's
   bottom with the fields' spacing — only while there are two columns; ≤760px it is a plain toggle again (Task 9, E7). */
body.tenant .md3 .md-form-grid > .md-form-end{ align-self:end; margin-bottom:18px; }
/* Only the raw, byte-pinned checkboxes: md_checkbox()'s own input (.md-check-input) keeps G2's rule (Task 9, E8). */
body.tenant .md3 .md-check > input[type="checkbox"]:not(.md-check-input){ flex:none; width:18px; height:18px; margin:0; accent-color:var(--md-p); cursor:pointer; }
body.tenant .md3 .md-check > input[type="checkbox"]:not(.md-check-input):focus-visible{ outline:none; box-shadow:var(--focus-ring); border-radius:2px; }
body.tenant .md3 .md-check > input[type="checkbox"]:not(.md-check-input):disabled{ cursor:not-allowed; }
@media (max-width:760px){
  body.tenant .md3 .md-form-grid{ grid-template-columns:minmax(0,1fr); }
  body.tenant .md3 .md-form-grid > .md-form-end{ align-self:auto; margin-bottom:12px; }
}

/* Production pages (Materials · BOM recipes, Job Board, Measurements, Production Output). */
/* A tonal icon tile — the one small colour on a card head, a kanban column or a timeline step: an MUI container pair; no
   tone class is neutral. .round for a timeline step. */
body.tenant .md3 .md-tile{ flex:none; display:inline-flex; align-items:center; justify-content:center; width:28px; height:28px; border-radius:var(--md-rx); background:var(--md-c3); color:var(--md-onsv); font-size:11px; font-weight:700; }
body.tenant .md3 .md-tile.round{ border-radius:50%; }
body.tenant .md3 .md-tile.p{ background:var(--md-pc); color:var(--md-opc); }
body.tenant .md3 .md-tile.s{ background:var(--md-sc); color:var(--md-osc); }
body.tenant .md3 .md-tile.t{ background:var(--md-tc); color:var(--md-otc); }
body.tenant .md3 .md-tile.w{ background:var(--md-warnc); color:var(--md-owarnc); }
body.tenant .md3 .md-tile.ok{ background:var(--md-okc); color:var(--md-ookc); }
body.tenant .md3 .md-tile.err{ background:var(--md-errc); color:var(--md-oerrc); }
/* A grid of cards (the recipe cards, a profile's body regions): as many 280px columns as fit. */
body.tenant .md3 .md-cardgrid{ display:grid; grid-template-columns:repeat(auto-fill,minmax(min(100%,280px),1fr)); gap:14px; }
/* A whole card that is a link (a recipe): a column whose last part (.md-card-foot) sits at the bottom when the grid stretches
   the card to its row; its outline darkens on hover; the focus ring on the keyboard. */
body.tenant .md3 a.md-card-link{ display:flex; flex-direction:column; color:inherit; text-decoration:none; transition:border-color .15s; }
body.tenant .md3 a.md-card-link > .md-card-foot{ margin-top:auto; }
body.tenant .md3 a.md-card-link:hover{ border-color:var(--md-outline); }
body.tenant .md3 a.md-card-link:focus-visible{ outline:none; box-shadow:var(--focus-ring); }
/* The Job Board kanban: one column per stage, the board scrolling sideways inside the page (never the page); a job is a link
   card whose title, customer and garment wrap in full (page rule 5) and whose job number is a whole code. */
body.tenant .md3 .md-kanban{ display:grid; grid-auto-flow:column; grid-auto-columns:minmax(248px,1fr); gap:14px; overflow-x:auto; padding-bottom:6px; }
body.tenant .md3 .md-kcol{ display:flex; flex-direction:column; min-width:0; min-height:120px; border:var(--md-bw) solid var(--md-outlinev); border-radius:var(--md-rl); background:var(--md-c1); }
body.tenant .md3 .md-kcol-h{ display:flex; align-items:center; gap:9px; padding:12px 14px; border-bottom:var(--md-bw) solid var(--md-outlinev); }
body.tenant .md3 .md-kcol-t{ margin:0; font-family:'Sora',sans-serif; font-size:13.5px; font-weight:700; color:var(--md-onsurf); }
body.tenant .md3 .md-kcol-h > .md-tag{ margin-left:auto; }
body.tenant .md3 .md-kcol-b{ display:flex; flex-direction:column; gap:10px; flex:1; padding:10px; }
body.tenant .md3 .md-kcol-empty{ margin:0; padding:22px 8px; text-align:center; font-size:12.5px; color:var(--md-onsv); }
body.tenant .md3 .md-kcard{ display:block; overflow:hidden; border:var(--md-bw) solid var(--md-outlinev); border-radius:var(--md-rm); background:var(--md-c0); color:var(--md-onsurf); text-decoration:none; transition:border-color .15s; }
body.tenant .md3 .md-kcard:hover{ border-color:var(--md-outline); }
body.tenant .md3 .md-kcard:focus-visible{ outline:none; box-shadow:var(--focus-ring); }
body.tenant .md3 .md-kcard-b{ padding:12px 13px; }
body.tenant .md3 .md-kcard-top{ display:flex; align-items:center; gap:9px; }
body.tenant .md3 .md-kcard-top > div{ flex:1; min-width:0; }
body.tenant .md3 .md-kcard-no{ font-family:'Sora',sans-serif; font-size:12px; font-weight:700; }
body.tenant .md3 .md-kcard-sub{ font-size:11.5px; color:var(--md-onsv); overflow-wrap:anywhere; }
body.tenant .md3 .md-kcard-t{ margin-top:9px; font-size:13px; font-weight:700; line-height:1.35; overflow-wrap:anywhere; }
body.tenant .md3 .md-kcard-meta{ display:flex; flex-direction:column; gap:5px; margin-top:8px; font-size:12px; color:var(--md-onsv); }
body.tenant .md3 .md-kcard-meta > div{ display:flex; align-items:center; gap:7px; min-width:0; overflow-wrap:anywhere; }
body.tenant .md3 .md-kcard-meta svg{ flex:none; }
body.tenant .md3 .md-kcard-f{ padding:9px 13px; border-top:var(--md-bw) solid var(--md-outlinev); background:var(--md-c1); font-size:12px; font-weight:700; color:var(--md-p); }
body.tenant .md3 .md-kcard-f.done{ font-weight:600; color:var(--md-onsv); }
/* A vertical timeline (a job's stage history, a profile's versions): a tile per step and a rule joining the steps. */
body.tenant .md3 .md-tl{ margin:0; padding:0; list-style:none; }
body.tenant .md3 .md-tl-i{ position:relative; display:flex; gap:13px; padding-bottom:16px; }
body.tenant .md3 .md-tl-i:last-child{ padding-bottom:0; }
body.tenant .md3 .md-tl-i:not(:last-child)::before{ content:""; position:absolute; left:13px; top:32px; bottom:4px; width:2px; border-radius:1px; background:var(--md-outlinev); }
body.tenant .md3 .md-tl-b{ flex:1; min-width:0; }
body.tenant .md3 .md-tl-t{ font-size:13.5px; font-weight:700; line-height:1.35; color:var(--md-onsurf); overflow-wrap:anywhere; }
body.tenant .md3 .md-tl-s{ margin-top:2px; font-size:12px; color:var(--md-onsv); }
body.tenant .md3 .md-tl-n{ margin-top:4px; font-size:12.5px; font-style:italic; color:var(--md-onsv); overflow-wrap:anywhere; }
/* A main column beside a side card (Production Output's records and its per-employee totals): side by side while the main column
   keeps 640px (its table's floor) next to the card's 280px, else the card wraps under it. It wraps on the CONTENT width, not at a
   breakpoint — the sidebar (248px from 1101px, 72px at 901-1100px) changes that width where no viewport breakpoint sees it
   (measured: at 1101-1280 a fixed two-column grid left the records 489-668px and scrolled their Void action out of view);
   999 : 1 hands the spare width to the main column. In it the filter fields start at 150px, so search · employee · status ·
   Apply keep one row. */
body.tenant .md3 .md-side-grid{ display:flex; flex-wrap:wrap; align-items:flex-start; gap:16px; }
body.tenant .md3 .md-side-grid-main{ flex:999 1 640px; min-width:0; }
body.tenant .md3 .md-side-grid-side{ flex:1 1 280px; min-width:0; }
body.tenant .md3 .md-side-grid-main .md-filters > .md-field{ flex-basis:150px; }
/* Ruling 16: a generated job number (JOB-YYYYMM-NNNNN) and a measurement profile number (MS-NNNNN) keep their one line in table
   mode; a card releases the minimum (below). The profile number is 9ch, like the voucher box: its bold link wrapped a zero-heavy
   MS-00000 at 8ch (Task 9, A5 — DM Sans digits are proportional, 0 the widest). */
body.tenant .md3 .md-table td.md-code.md-code-job > span{ display:inline-block; min-width:14ch; }
body.tenant .md3 .md-table td.md-code.md-code-ms > span{ display:inline-block; min-width:9ch; }
@media (max-width:760px){
  body.tenant .md3 .md-table.stack td.md-code.md-code-job > span,
  body.tenant .md3 .md-table.stack td.md-code.md-code-ms > span{ min-width:0; }
}

/* Task 9 — the responsive + accessibility sweep. */
/* A4: a default icon button is square — 44 × 44, like the 44px base height (G2 says 46px wide); .sm / .lg keep their own. */
body.tenant .md3 .md-btn.icon{ width:44px; }
/* A6: a scroll cue without a gradient. Every box that can scroll sideways — a table in its card, the Job Board kanban, a phone's
   filter-chip strip (V3), a code's own box (a card line, an overview fact, a header sub line, a Sales phone row's document number)
   — draws a thin 6px scrollbar with a visible rail, so it shows it scrolls even where the system hides scrollbars until you scroll
   (macOS, phones).
   ::-webkit-scrollbar only: setting scrollbar-width / scrollbar-color would switch Chromium back to its own (overlay) bar. A box
   with nothing to scroll draws no bar at all. */
body.tenant .md3 .md-table::-webkit-scrollbar,
body.tenant .md3 .md-kanban::-webkit-scrollbar,
body.tenant .md3 .md-table td.md-code > span::-webkit-scrollbar,
body.tenant .md3 .md-table .md-code-line::-webkit-scrollbar,
body.tenant .md3 dl.md-kv dd.md-code::-webkit-scrollbar,
body.tenant .md3 .md-page-sub .md-code-sub::-webkit-scrollbar,
body.tenant .md3 .md-srow .nm::-webkit-scrollbar,
body.tenant .md3 .md-filterbar .md-chips::-webkit-scrollbar{ height:6px; width:6px; }
body.tenant .md3 .md-table::-webkit-scrollbar-thumb,
body.tenant .md3 .md-kanban::-webkit-scrollbar-thumb,
body.tenant .md3 .md-table td.md-code > span::-webkit-scrollbar-thumb,
body.tenant .md3 .md-table .md-code-line::-webkit-scrollbar-thumb,
body.tenant .md3 dl.md-kv dd.md-code::-webkit-scrollbar-thumb,
body.tenant .md3 .md-page-sub .md-code-sub::-webkit-scrollbar-thumb,
body.tenant .md3 .md-srow .nm::-webkit-scrollbar-thumb,
body.tenant .md3 .md-filterbar .md-chips::-webkit-scrollbar-thumb{ background:var(--md-outline); border-radius:var(--md-rf); }
body.tenant .md3 .md-table::-webkit-scrollbar-track,
body.tenant .md3 .md-kanban::-webkit-scrollbar-track,
body.tenant .md3 .md-table td.md-code > span::-webkit-scrollbar-track,
body.tenant .md3 .md-table .md-code-line::-webkit-scrollbar-track,
body.tenant .md3 dl.md-kv dd.md-code::-webkit-scrollbar-track,
body.tenant .md3 .md-page-sub .md-code-sub::-webkit-scrollbar-track,
body.tenant .md3 .md-srow .nm::-webkit-scrollbar-track,
body.tenant .md3 .md-filterbar .md-chips::-webkit-scrollbar-track{ background:var(--md-c2); border-radius:var(--md-rf); }
/* A code box that scrolls is a keyboard stop (md_code_scroll() marks it data-md-scroll): it shows the focus ring. */
body.tenant .md3 [data-md-scroll]:focus-visible{ outline:none; box-shadow:var(--focus-ring); }
/* A8: a code in a header sub line (md_page_header() 'sub_parts' — a product's SKU, a job or profile number, the storefront path)
   stays whole: it wraps only at its own separators and, unbroken and longer than the line, scrolls in its own box. The sub
   line's own overflow-wrap:anywhere (for text) never reaches inside it. */
body.tenant .md3 .md-page-sub .md-code-sub{ display:inline-block; max-width:100%; overflow-x:auto; vertical-align:top; overflow-wrap:normal; word-break:normal; }

/* The final fix wave — the visual review's phone findings (V1 is the .md-run block above). */
/* V2: a banner's action (md_banner()'s link) drops under the message, at the right, whenever the message would be left narrower
   than 320px beside it — or than its whole line beside the icon (20px + the 12px gap) in a narrower banner. At 375 the Vendor Bills
   PO-goods note read in a 144px column, 13 lines tall (249px, 7 lines at 480). It wraps on the banner's own width, so a banner in a
   narrow box (the Pay… panel, a dialog) is covered too; a wide banner is unchanged — the message's flex-grow takes the free space,
   so the auto margin is 0. The message width counts on that 20px icon, so it binds only a message right after .md-banner-ico
   (md_banner() and the raw banners written in its markup): a banner with another icon — Staff & HR's Owner note, a 40px star —
   keeps the MD3 flex:1 and its text beside the icon (R-1). A raw banner whose own control wraps (the Staff & HR drift notice's Sync
   form) sets its own row gap inline; the 4px here is for md_banner()'s link. */
body.tenant .md3 .md-banner{ flex-wrap:wrap; row-gap:4px; }
body.tenant .md3 .md-banner-ico + .md-banner-body{ flex:1 1 min(320px, 100% - 32px); }
body.tenant .md3 .md-banner-action{ margin-left:auto; }
/* ── end UI polish (UIP) ── */

/* ── UI-1 · the Entire logo · the sticky phone header · the phone bottom bar ──
   Scoped to body.tenant (the tenant panel) and body.md3-auth (the four sign-in pages); the platform panel
   loads no tenant.css and is untouched (owner decision, UI-1). Breakpoints 760 / 900 only (M-D5). */

/* UI-1A · the shared logo (partials/entire_logo.php): the modular mark on the MUI primary (#6750A4). */
:is(body.tenant, body.md3-auth) .entire-logo{ display:inline-flex; align-items:center; gap:10px; min-width:0; max-width:100%; vertical-align:middle; }
:is(body.tenant, body.md3-auth) .entire-logo__symbol{ display:block; flex:none; max-width:none; overflow:visible; }
:is(body.tenant, body.md3-auth) .entire-logo__block{ fill:var(--md-p); }
:is(body.tenant, body.md3-auth) .entire-logo__text{ display:flex; flex-direction:column; min-width:0; }
:is(body.tenant, body.md3-auth) .entire-logo__word{ font-family:'Sora', sans-serif; font-weight:700; line-height:1.2; }
:is(body.tenant, body.md3-auth) .entire-logo__tagline{ margin-top:3px; font-family:'DM Sans', sans-serif; font-size:13px; font-weight:500; line-height:1.35; color:var(--md-onsv); }

/* the logo's motion presets live in the LOGO-MOTION block below */

/* sign-in: the brand side (with the slogan on the sign-in page) and the same logo over the form ≤900px */
body.md3-auth .auth-aside .entire-logo{ gap:12px; color:inherit; }
body.md3-auth .auth-aside .entire-logo__word{ font-size:21px; }
body.md3-auth .auth-aside .entire-logo__tagline{ font-size:14px; color:inherit; opacity:.85; }
body.md3-auth .md3-auth-brand .entire-logo__word{ font-size:17px; }

/* the tenant sidebar: the shop's name stays primary; Entire is the small line under it */
body.tenant .sidebar .brand-sub .entire-logo{ gap:5px; }
body.tenant .sidebar .brand-sub .entire-logo__word{ font-family:'DM Sans', sans-serif; font-size:11px; font-weight:600; }

/* the phone header: the shop's name leads, with the small Entire mark (the sidebar is a drawer ≤900px) */
body.tenant .header .header-brand{ display:none; }
@media (max-width:900px){
  body.tenant .header .header-brand{ display:flex; align-items:center; gap:8px; flex:0 1 auto; min-width:0; margin-right:auto; padding:6px 8px 6px 4px; border-radius:var(--md-rf); color:var(--md-onsurf); text-decoration:none; }
  body.tenant .header .header-brand:hover{ color:var(--md-onsurf); background:color-mix(in srgb, var(--md-onsurf) 8%, transparent); }
  body.tenant .header .header-brand:focus-visible{ outline:none; box-shadow:var(--focus-ring); }
  body.tenant .header .header-brand-name{ min-width:0; overflow:hidden; white-space:nowrap; text-overflow:ellipsis; font-family:'Sora', sans-serif; font-size:16px; font-weight:700; line-height:1.2; }
}

/* UI-1B · the phone header stays at the top. admin.css makes it position:sticky ≤900px, but its
   `html, body { overflow-x:hidden }` turns <body> into a scroll container that never scrolls, so the
   header had nothing to stick to and scrolled away. `clip` hides the same overflow WITHOUT making a
   scroll container, so sticky works against the page. (A browser without `clip` keeps today's behaviour.)
   The notch: with viewport-fit=cover the header grows by the top safe area, and the phone search
   overlay opens below it. */
@media (max-width:900px){
  body.tenant{ overflow-x:clip; }
  body.tenant .header{ top:0; padding-top:env(safe-area-inset-top, 0px); height:calc(var(--header-h) + env(safe-area-inset-top, 0px)); }
  body.tenant .header > .search{ top:calc(var(--header-h) + env(safe-area-inset-top, 0px)); }
}

/* UI-1C · the phone bottom bar (layout.php .bnav, items from nav_tenant.php). ≤760px only; the hamburger
   goes there because More opens the same drawer. Layers: above the page (45) and the FAB, under the POS
   dialogs (50), the drawer and its scrim (55 / 60), the modals (100) and the snackbar (1200). The spacer
   after .main keeps the last content — the POS Charge button — clear of it. */
body.tenant{ --bnav-h:64px; }
body.tenant .bnav,
body.tenant .bnav-spacer{ display:none; }
@media (max-width:760px){
  body.tenant .header .nav-toggle{ display:none; }
  body.tenant .bnav-spacer{ display:block; height:calc(var(--bnav-h) + env(safe-area-inset-bottom, 0px)); }
  body.tenant .bnav{ position:fixed; left:0; right:0; bottom:0; z-index:45; display:flex; align-items:stretch; box-sizing:border-box;
    padding:0 env(safe-area-inset-right, 0px) env(safe-area-inset-bottom, 0px) env(safe-area-inset-left, 0px);
    background:var(--md-c2); border-top:var(--md-bw) solid var(--md-outlinev); box-shadow:0 -2px 12px rgba(0, 0, 0, .06); }
  body.tenant .bnav .bnav-item{ flex:1 1 0; min-width:0; height:var(--bnav-h); margin:0; padding:0 2px; display:flex; flex-direction:column; align-items:center; justify-content:center; gap:4px;
    border:0; border-radius:0; background:transparent; color:var(--md-onsv); font-family:'DM Sans', sans-serif; font-size:12px; font-weight:600; line-height:1.2;
    text-decoration:none; cursor:pointer; -webkit-tap-highlight-color:transparent; }
  body.tenant .bnav .bnav-ind{ display:flex; align-items:center; justify-content:center; width:56px; max-width:100%; height:30px; border-radius:var(--md-rf); transition:background-color .15s ease; }
  body.tenant .bnav .bnav-ico{ display:block; flex:none; width:22px; height:22px; }
  body.tenant .bnav .bnav-label{ display:block; max-width:100%; overflow:hidden; white-space:nowrap; text-overflow:ellipsis; }
  body.tenant .bnav .bnav-item:hover{ color:var(--md-onsurf); }
  body.tenant .bnav .bnav-item:hover .bnav-ind{ background:color-mix(in srgb, var(--md-onsurf) 8%, transparent); }
  body.tenant .bnav .bnav-item.active{ color:var(--md-onsurf); font-weight:700; }
  body.tenant .bnav .bnav-item.active .bnav-ind{ background:var(--md-pc); color:var(--md-opc); }
  body.tenant .bnav .bnav-item:focus-visible{ outline:none; }
  body.tenant .bnav .bnav-item:focus-visible .bnav-ind{ box-shadow:var(--focus-ring); }
  /* the snackbar and the FAB sit above the bar */
  body.tenant:has(.bnav) .md-snackbar,
  body.tenant:has(.bnav) .md3-fab{ bottom:calc(var(--bnav-h) + env(safe-area-inset-bottom, 0px) + 16px); }
  /* The bar stays while a field has focus: the POS keeps the keyboard in its scan box and the owner rule
     is that the bar stays on POS; mobile browsers keep a fixed bar behind the on-screen keyboard. */
}
@media (prefers-reduced-motion:reduce){
  body.tenant .bnav .bnav-ind{ transition:none; }
}
@media print{
  body.tenant .bnav,
  body.tenant .bnav-spacer{ display:none; }
}
/* ── end UI-1 ── */

/* ── LOGO-MOTION · one-shot motion presets for the shared Entire logo (partials/entire_logo.php) ──
   A preset is the logo's data-motion attribute: the partial renders it (the sign-in build-in), or admin.js
   (EntireLogo) sets it on the tenant shell's logos for the page's preset. Owner rules (2026-09-30): transform
   + opacity only — never fill, path data or size, so the colour stays --md-p (#6750A4) and the geometry is the
   partial's own; one-shot, never infinite; every keyframe run ENDS at rest (transform:none, opacity:1) and
   uses fill-mode backwards (never forwards / both), so once it ends each block is back at its exact resting
   geometry. Reduced motion and print: fully static. Block units are the 100-unit viewBox (6 units = 6 %). */
:is(body.tenant, body.md3-auth) .entire-logo[data-motion] .entire-logo__block{ transform-box:fill-box; transform-origin:center; }
:is(body.tenant, body.md3-auth) .entire-logo[data-motion] .entire-logo__symbol{ transform-origin:50% 50%; }
/* per block: --lm-dx/--lm-dy its direction from the centre, --lm-sx its shift, --lm-a / --lm-w its assemble / wave delay */
:is(body.tenant, body.md3-auth) .entire-logo__block--1{ --lm-dx:-1; --lm-dy:-1; --lm-sx:-6px; --lm-a:.10s; --lm-w:.14s; }
:is(body.tenant, body.md3-auth) .entire-logo__block--2{ --lm-dx:1;  --lm-dy:-1; --lm-sx:6px;  --lm-a:.40s; --lm-w:.14s; }
:is(body.tenant, body.md3-auth) .entire-logo__block--3{ --lm-dx:0;  --lm-dy:0;  --lm-sx:-4px; --lm-a:.30s; --lm-w:0s; }
:is(body.tenant, body.md3-auth) .entire-logo__block--4{ --lm-dx:-1; --lm-dy:1;  --lm-sx:6px;  --lm-a:.20s; --lm-w:.28s; }
:is(body.tenant, body.md3-auth) .entire-logo__block--5{ --lm-dx:1;  --lm-dy:1;  --lm-sx:-6px; --lm-a:.50s; --lm-w:.28s; }

/* assemble · 1.1s · the blocks build in, then the word (the sign-in build-in, unchanged) */
:is(body.tenant, body.md3-auth) .entire-logo[data-motion="assemble"] .entire-logo__block{ animation:entire-logo-block-in .32s cubic-bezier(.2,.7,.25,1) var(--lm-a) backwards; }
:is(body.tenant, body.md3-auth) .entire-logo[data-motion="assemble"] .entire-logo__text{ animation:entire-logo-word-in .30s cubic-bezier(.2,.7,.25,1) .80s backwards; }
/* snap · 0.35s · the outer blocks ease out, then snap back onto the centre block */
:is(body.tenant, body.md3-auth) .entire-logo[data-motion="snap"] .entire-logo__block{ animation:entire-logo-snap .35s cubic-bezier(.3,.6,.3,1) backwards; }
/* pulse · 0.5s · the whole mark breathes once */
:is(body.tenant, body.md3-auth) .entire-logo[data-motion="pulse"] .entire-logo__symbol{ animation:entire-logo-pulse .5s ease-in-out backwards; }
/* wave · 0.6s · centre block first, then the top pair, then the bottom pair */
:is(body.tenant, body.md3-auth) .entire-logo[data-motion="wave"] .entire-logo__block{ animation:entire-logo-wave .32s ease-in-out var(--lm-w) backwards; }
/* shift · 0.45s · the blocks slide sideways and line up again */
:is(body.tenant, body.md3-auth) .entire-logo[data-motion="shift"] .entire-logo__block{ animation:entire-logo-shift .45s cubic-bezier(.3,.6,.3,1) backwards; }
/* success · 0.7s · snap, then pulse */
:is(body.tenant, body.md3-auth) .entire-logo[data-motion="success"] .entire-logo__block{ animation:entire-logo-snap .35s cubic-bezier(.3,.6,.3,1) backwards; }
:is(body.tenant, body.md3-auth) .entire-logo[data-motion="success"] .entire-logo__symbol{ animation:entire-logo-pulse .35s ease-in-out .35s backwards; }
/* error · 0.4s · a small sideways shake — no colour change */
:is(body.tenant, body.md3-auth) .entire-logo[data-motion="error"] .entire-logo__symbol{ animation:entire-logo-error .4s ease-in-out backwards; }

@keyframes entire-logo-block-in{ from{ opacity:0; transform:translate(-3px,2px); } to{ opacity:1; transform:none; } }
@keyframes entire-logo-word-in{ from{ opacity:0; transform:translateX(-3px); } to{ opacity:1; transform:none; } }
@keyframes entire-logo-snap{ 0%{ transform:none; } 40%{ transform:translate(calc(var(--lm-dx) * 5px), calc(var(--lm-dy) * 5px)); } 75%{ transform:translate(calc(var(--lm-dx) * -1.5px), calc(var(--lm-dy) * -1.5px)); } 100%{ transform:none; } }
@keyframes entire-logo-pulse{ 0%{ transform:none; } 45%{ transform:scale(1.08); } 100%{ transform:none; } }
@keyframes entire-logo-wave{ 0%{ transform:none; } 50%{ transform:scale(1.12); } 100%{ transform:none; } }
@keyframes entire-logo-shift{ 0%{ transform:none; } 40%{ transform:translateX(var(--lm-sx)); } 100%{ transform:none; } }
@keyframes entire-logo-error{ 0%{ transform:none; } 20%{ transform:translateX(-3px); } 40%{ transform:translateX(3px); } 60%{ transform:translateX(-2px); } 80%{ transform:translateX(2px); } 100%{ transform:none; } }

/* reduced motion and print: the logo at rest, nothing moves */
@media (prefers-reduced-motion:reduce){
  :is(body.tenant, body.md3-auth) .entire-logo[data-motion] .entire-logo__symbol,
  :is(body.tenant, body.md3-auth) .entire-logo[data-motion] .entire-logo__block,
  :is(body.tenant, body.md3-auth) .entire-logo[data-motion] .entire-logo__text{ animation:none; opacity:1; transform:none; }
}
@media print{
  :is(body.tenant, body.md3-auth) .entire-logo[data-motion] .entire-logo__symbol,
  :is(body.tenant, body.md3-auth) .entire-logo[data-motion] .entire-logo__block,
  :is(body.tenant, body.md3-auth) .entire-logo[data-motion] .entire-logo__text{ animation:none; opacity:1; transform:none; }
}
/* ── end LOGO-MOTION ── */

/* SALES-FILTER · the All Sales search + From / To + Apply row (orders/_list.php form.sales-filter). Scoped to
   that one form: the shared .md-chips / .md-chip rules are untouched. Desktop (>760px): one row — search takes
   the rest, the two dates share one fixed width, everything 40px tall. Phone (≤760px, the bottom-bar breakpoint):
   search, then From | To at 50 / 50, then Apply, then clear — each full width and at least 44px tall. Each date
   is one bordered box with its word inside; the input stays a native type="date" (its picker and calendar icon). */
body.tenant .md3 .sales-filter{ --sf-h:40px; display:flex; align-items:stretch; gap:10px; margin:0 0 12px; min-width:0; }
body.tenant .md3 .sales-filter__search{ position:relative; flex:1 1 220px; min-width:0; }
body.tenant .md3 .sales-filter__search svg{ position:absolute; left:12px; top:50%; transform:translateY(-50%); color:var(--md-onsv); pointer-events:none; }
body.tenant .md3 .sales-filter__search input{ box-sizing:border-box; width:100%; height:var(--sf-h); margin:0; padding:0 12px 0 36px;
  border:var(--md-bw) solid var(--md-outlinev); border-radius:var(--md-rx); background:var(--md-c0); color:var(--md-onsurf); font:inherit; font-size:14px; }
body.tenant .md3 .sales-filter__date{ box-sizing:border-box; flex:0 0 196px; min-width:0; height:var(--sf-h); margin:0; display:flex; align-items:center; gap:8px;
  padding:0 8px 0 12px; border:var(--md-bw) solid var(--md-outlinev); border-radius:var(--md-rx); background:var(--md-c0); cursor:text; }
body.tenant .md3 .sales-filter__date > span{ flex:none; font-size:12px; font-weight:600; color:var(--md-onsv); }
body.tenant .md3 .sales-filter__date input{ flex:1 1 auto; min-width:0; width:100%; height:100%; margin:0; padding:0; border:0; background:transparent;
  color:var(--md-onsurf); font:inherit; font-size:14px; }
body.tenant .md3 .sales-filter__date input:focus{ outline:none; }
body.tenant .md3 .sales-filter__search input:focus-visible,
body.tenant .md3 .sales-filter__date:focus-within{ outline:none; border-color:var(--md-p); box-shadow:0 0 0 1px var(--md-p); }
body.tenant .md3 .sales-filter__apply,
body.tenant .md3 .sales-filter__clear{ box-sizing:border-box; flex:none; height:var(--sf-h); margin:0; padding:0 18px; display:inline-flex; align-items:center; justify-content:center;
  border-radius:var(--md-rx); font:inherit; font-size:14px; font-weight:600; text-decoration:none; cursor:pointer; }
body.tenant .md3 .sales-filter__apply{ border:0; background:var(--md-okc); color:var(--md-ookc); }
body.tenant .md3 .sales-filter__clear{ border:var(--md-bw) solid var(--md-outlinev); background:transparent; color:var(--md-onsv); }
body.tenant .md3 .sales-filter__apply:hover,
body.tenant .md3 .sales-filter__clear:hover{ filter:brightness(.97); }
body.tenant .md3 .sales-filter__apply:focus-visible,
body.tenant .md3 .sales-filter__clear:focus-visible{ outline:none; box-shadow:var(--focus-ring); }
@media (max-width:760px){
  body.tenant .md3 .sales-filter{ --sf-h:44px; display:grid; grid-template-columns:minmax(0, 1fr) minmax(0, 1fr); gap:10px; }
  body.tenant .md3 .sales-filter__search,
  body.tenant .md3 .sales-filter__apply,
  body.tenant .md3 .sales-filter__clear{ grid-column:1 / -1; width:100%; }
  body.tenant .md3 .sales-filter__date{ width:100%; padding:0 6px 0 10px; }
}
/* ≤480px: a half-width box is too narrow for the word AND the native date beside it (the date was clipped at
   320 / 360), so the small word sits above the date inside the same 44px box and the date gets its full width. */
@media (max-width:480px){
  body.tenant .md3 .sales-filter__date{ flex-direction:column; align-items:stretch; justify-content:center; gap:1px; padding:3px 4px 3px 8px; }
  body.tenant .md3 .sales-filter__date > span{ font-size:10px; line-height:1.2; }
  body.tenant .md3 .sales-filter__date input{ flex:none; height:auto; font-size:13px; line-height:1.3; }
}
/* ── end SALES-FILTER ── */
