/* ─────────────────────────────────────────────────────────────
 * sd-portal.css — SlabDraw account/admin portal design system.
 *
 * Layout + components ported from the THRED Realty portal, but the
 * PALETTE is NOT redefined here. Every color is a semantic alias over
 * SlabDraw's own design tokens (css/app/00-tokens-base.css) — the
 * single source of truth. The shell loads that token file first, so:
 *   • no hardcoded hex lives in this file,
 *   • the portal tracks the app's palette automatically, and
 *   • light/dark switching is inherited from the primitives (no
 *     per-theme override block needed here).
 *
 * Everything is scoped to `body.sd-portal`, so it can never reach the
 * canvas app, the share pages, or any other surface.
 * ───────────────────────────────────────────────────────────── */

:root {
  /* ── Color = ALIAS over SlabDraw primitives (no hex here) ──────── */
  --p-bg:             var(--bg);
  --p-surface:        var(--surface);
  --p-surface-alt:    var(--surface-alt);
  --p-surface-hover:  var(--raised);
  --p-text:           var(--text);
  --p-text-strong:    var(--text);
  --p-text-muted:     var(--muted);
  --p-text-on-accent: var(--on-accent, #fff);
  --p-border:         var(--border);
  --p-border-strong:  var(--border-md);
  --p-divider:        var(--border);
  --p-accent:         var(--accent);
  --p-accent-hover:   var(--accent2);
  --p-accent-soft:    var(--accent-bg-soft);
  --p-accent-ring:    var(--accent-focus-ring);
  --p-ok:     var(--success); --p-ok-soft:     var(--success-soft); --p-ok-border:     var(--success-border);
  --p-warn:   var(--warning); --p-warn-soft:   var(--warning-soft); --p-warn-border:   var(--warning-border);
  --p-danger: var(--error);   --p-danger-soft: var(--error-soft);   --p-danger-border: var(--error-border);

  /* ── Non-color scale (layout rhythm) — radii alias the app's ──── */
  --p-r-input: var(--radius);     /* 6px  */
  --p-r-card:  var(--radius-lg);  /* 10px */
  --p-r-pill:  var(--radius-pill);
  --p-font: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, system-ui, sans-serif;
  --p-fs-12:12px; --p-fs-13:13px; --p-fs-14:14px; --p-fs-16:16px;
  --p-fs-18:18px; --p-fs-22:22px; --p-fs-28:28px; --p-fs-36:36px; --p-fs-48:48px;
  --p-s-4:4px; --p-s-8:8px; --p-s-12:12px; --p-s-16:16px;
  --p-s-20:20px; --p-s-24:24px; --p-s-32:32px; --p-s-48:48px; --p-s-64:64px;
  --p-sidebar-w:248px; --p-topbar-h:56px; --p-content-max:1180px;
  --p-ease:cubic-bezier(.2,.7,.2,1); --p-dur-fast:100ms; --p-dur:150ms;
}

@media (min-width:1500px){ :root{ --p-content-max:1440px; } }

/* ── Base ────────────────────────────────────────────────────── */
body.sd-portal { box-sizing:border-box; }
body.sd-portal *, body.sd-portal *::before, body.sd-portal *::after { box-sizing:border-box; }
body.sd-portal {
  margin:0; font-family:var(--p-font); color:var(--p-text); background:var(--p-bg);
  font-size:var(--p-fs-14); line-height:1.5; -webkit-font-smoothing:antialiased; min-height:100vh;
}
body.sd-portal img, body.sd-portal svg { display:block; max-width:100%; }
/* Links are accent-colored — but an <a> styled as a button (the CRM uses anchor
   buttons like .db-new-btn / .crm-save-btn that set their own bg + on-accent
   text) must keep ITS color, else a{color:accent} paints the label blue on a
   blue button. :where() excludes button-class anchors at ZERO added specificity,
   so component rules like `.sd-portal .nav-item` (0,2,0) still win. text-decoration
   stays on every anchor so excluded buttons never underline; <button> is immune. */
body.sd-portal a { text-decoration:none; transition:color var(--p-dur) var(--p-ease); }
body.sd-portal a:where(:not([class*="btn"])) { color:var(--p-accent); }
body.sd-portal a:where(:not([class*="btn"])):hover { color:var(--p-accent-hover); }
body.sd-portal button { font-family:inherit; }
body.sd-portal input, body.sd-portal select, body.sd-portal textarea { font-family:inherit; font-size:var(--p-fs-14); }
body.sd-portal h1, body.sd-portal h2, body.sd-portal h3, body.sd-portal h4 {
  color:var(--p-text-strong); margin:0; font-weight:700; letter-spacing:-.015em;
}
body.sd-portal p { margin:0; }
body.sd-portal .muted { color:var(--p-text-muted); }
body.sd-portal .num { font-variant-numeric:tabular-nums; }

/* ── App layout (topbar + sidebar + content) ─────────────────── */
.sd-portal .app {
  display:grid;
  grid-template-columns:var(--p-sidebar-w) 1fr;
  grid-template-rows:var(--p-topbar-h) 1fr;
  height:100vh; overflow:hidden;
}

/* ── Topbar ──────────────────────────────────────────────────── */
/* Shared top header lives in css/topbar.css (one component, portal + canvas).
   The portal only owns PLACEMENT — slotting the bar into the .app grid's top row. */
.sd-portal .sd-topbar { grid-column:1 / -1; grid-row:1; }

/* ── Sidebar ─────────────────────────────────────────────────── */
.sd-portal .sidebar {
  grid-column:1; grid-row:2; background:var(--p-surface); border-right:1px solid var(--p-border);
  padding:var(--p-s-16) 0; overflow-y:auto; overscroll-behavior:contain;
}
.sd-portal .nav-back {
  display:flex; align-items:center; gap:var(--p-s-8);
  margin:0 var(--p-s-16) var(--p-s-8); padding:var(--p-s-8) var(--p-s-12);
  border:1px solid var(--p-border); border-radius:var(--p-r-input);
  color:var(--p-text); font-weight:600; font-size:var(--p-fs-13);
}
.sd-portal .nav-back:hover { background:var(--p-surface-alt); color:var(--p-text); }
.sd-portal .nav-section { padding:var(--p-s-8) 0 var(--p-s-16); }
.sd-portal .nav-section + .nav-section { border-top:1px solid var(--p-divider); padding-top:var(--p-s-16); }
.sd-portal .nav-section-label {
  padding:0 var(--p-s-24) var(--p-s-8);
  font-size:11px; font-weight:700; letter-spacing:.06em; text-transform:uppercase; color:var(--p-text-muted);
}
.sd-portal .nav-item {
  display:flex; align-items:center; gap:var(--p-s-12);
  padding:var(--p-s-8) var(--p-s-24); color:var(--p-text); font-size:var(--p-fs-14); position:relative;
  transition:background var(--p-dur-fast) var(--p-ease), color var(--p-dur-fast) var(--p-ease);
}
.sd-portal .nav-item:hover { background:var(--p-surface-alt); color:var(--p-text); }
.sd-portal .nav-item--active, .sd-portal .nav-item.is-active { background:var(--p-accent-soft); color:var(--p-accent); font-weight:600; }
.sd-portal .nav-item--active::before, .sd-portal .nav-item.is-active::before {
  content:''; position:absolute; left:0; top:4px; bottom:4px; width:3px;
  background:var(--p-accent); border-radius:0 2px 2px 0;
}
.sd-portal .nav-badge { margin-left:auto; background:var(--p-accent); color:var(--p-text-on-accent); font-size:11px; font-weight:700; padding:1px 7px; border-radius:var(--p-r-pill); min-width:18px; text-align:center; }

/* ── Content ─────────────────────────────────────────────────── */
.sd-portal .content { grid-column:2; grid-row:2; background:var(--p-bg); overflow-y:auto; overscroll-behavior:contain; }
/* Fixed-height content mode — for SPA surfaces (e.g. the CRM hub) whose own
   panels manage internal scroll. The content cell doesn't scroll; the child
   fills it. Set via sd_portal_begin(..., ['fixed'=>true]). */
.sd-portal .content--fixed { overflow:hidden; padding:0; display:flex; flex-direction:column; min-height:0; }
.sd-portal .content--fixed > * { flex:1 1 auto; min-height:0; }
/* CRM hub rides the portal shell but keeps `crm-body` on <body> so its 40+
   mobile rules (.crm-body .X in mobile.css) still apply. Neutralize crm-body's
   own body-level flex so the portal .app grid owns the chrome instead. */
.sd-portal.crm-body { display:block; height:auto; }
.sd-portal .content-inner { max-width:var(--p-content-max); padding:var(--p-s-32) var(--p-s-48); }
.sd-portal .page-head { display:flex; align-items:flex-end; justify-content:space-between; margin-bottom:var(--p-s-24); gap:var(--p-s-16); }
.sd-portal .page-head h1 { font-size:var(--p-fs-28); }
.sd-portal .page-head p { color:var(--p-text-muted); margin-top:var(--p-s-4); font-size:var(--p-fs-14); }
.sd-portal .page-actions { display:flex; gap:var(--p-s-8); }

/* ── Card ────────────────────────────────────────────────────── */
.sd-portal .card { background:var(--p-surface); border:1px solid var(--p-border); border-radius:var(--p-r-card); padding:var(--p-s-24); }
.sd-portal .card + .card { margin-top:var(--p-s-16); }
.sd-portal .card-head { display:flex; align-items:center; justify-content:space-between; margin-bottom:var(--p-s-16); gap:var(--p-s-16); }
.sd-portal .card-head h2 { font-size:var(--p-fs-18); font-weight:600; }
.sd-portal .card-foot { margin-top:var(--p-s-16); padding-top:var(--p-s-16); border-top:1px solid var(--p-divider); display:flex; justify-content:space-between; align-items:center; gap:var(--p-s-12); }
.sd-portal .card--warn   { border-color:var(--p-warn-border); }
.sd-portal .card--danger { border-color:var(--p-danger-border); }
.sd-portal .card-hint { color:var(--p-text-muted); font-size:var(--p-fs-13); line-height:1.55; margin-bottom:var(--p-s-16); max-width:64ch; }

/* ── Status pill ─────────────────────────────────────────────── */
.sd-portal .status { display:inline-flex; align-items:center; gap:6px; font-size:var(--p-fs-12); font-weight:600; padding:2px 10px; border-radius:var(--p-r-pill); background:var(--p-surface-alt); color:var(--p-text); }
.sd-portal .status::before { content:''; width:6px; height:6px; border-radius:50%; background:currentColor; }
.sd-portal .status--ok { background:var(--p-ok-soft); color:var(--p-ok); }
.sd-portal .status--warn { background:var(--p-warn-soft); color:var(--p-warn); }
.sd-portal .status--danger { background:var(--p-danger-soft); color:var(--p-danger); }

/* ── Buttons ─────────────────────────────────────────────────── */
.sd-portal .btn {
  display:inline-flex; align-items:center; justify-content:center; gap:var(--p-s-8);
  height:40px; padding:0 var(--p-s-16); border:1px solid var(--p-border); border-radius:var(--p-r-input);
  background:var(--p-surface); color:var(--p-text);
  font-family:inherit; font-size:var(--p-fs-14); font-weight:600; cursor:pointer; text-decoration:none;
  white-space:nowrap;   /* labels like "Sign out" must never wrap to two lines */
  transition:background var(--p-dur) var(--p-ease), border-color var(--p-dur) var(--p-ease), color var(--p-dur) var(--p-ease);
}
.sd-portal .btn:hover { background:var(--p-surface-alt); border-color:var(--p-border-strong); color:var(--p-text); }
.sd-portal .btn--sm { height:32px; padding:0 var(--p-s-12); font-size:var(--p-fs-13); }
.sd-portal .btn-primary { background:var(--p-accent); color:var(--p-text-on-accent); border-color:var(--p-accent); }
.sd-portal .btn-primary:hover { background:var(--p-accent-hover); border-color:var(--p-accent-hover); color:var(--p-text-on-accent); }
.sd-portal .btn-secondary { background:var(--p-surface); color:var(--p-text); border-color:var(--p-border); }
.sd-portal .btn-danger { background:var(--p-danger); color:#fff; border-color:var(--p-danger); }
.sd-portal .btn-danger:hover { filter:brightness(.95); color:#fff; }

/* ── Form fields ─────────────────────────────────────────────── */
.sd-portal .field { margin-bottom:var(--p-s-16); }
.sd-portal .field label { display:block; font-size:var(--p-fs-13); font-weight:500; color:var(--p-text); margin-bottom:var(--p-s-4); }
.sd-portal .field input[type="text"], .sd-portal .field input[type="email"], .sd-portal .field input[type="password"],
.sd-portal .field input[type="tel"], .sd-portal .field input[type="url"], .sd-portal .field input[type="number"],
.sd-portal .field select, .sd-portal .field textarea {
  width:100%; height:40px; padding:0 var(--p-s-12); background:var(--p-surface);
  border:1px solid var(--p-border); border-radius:var(--p-r-input); color:var(--p-text); font-size:var(--p-fs-14);
  transition:border-color var(--p-dur) var(--p-ease), box-shadow var(--p-dur) var(--p-ease);
}
.sd-portal .field textarea { height:auto; min-height:100px; padding:var(--p-s-12); resize:vertical; line-height:1.5; }
.sd-portal .field input:focus, .sd-portal .field select:focus, .sd-portal .field textarea:focus {
  outline:none; border-color:var(--p-accent); box-shadow:var(--p-accent-ring);
}
.sd-portal .field input[readonly] { background:var(--p-surface-alt); color:var(--p-text-muted); }
.sd-portal .field-row { display:grid; grid-template-columns:1fr 1fr; gap:var(--p-s-12); }
.sd-portal .field-help { font-size:var(--p-fs-12); color:var(--p-text-muted); margin-top:var(--p-s-4); }

/* ── Alert / message ─────────────────────────────────────────── */
.sd-portal .alert { display:flex; align-items:center; gap:var(--p-s-8); padding:var(--p-s-12) var(--p-s-16); border-radius:var(--p-r-input); font-size:var(--p-fs-13); border:1px solid transparent; margin-bottom:var(--p-s-16); }
.sd-portal .alert svg { flex:0 0 auto; }
.sd-portal .alert--ok     { background:var(--p-ok-soft);     color:var(--p-ok);     border-color:var(--p-ok-border); }
.sd-portal .alert--warn   { background:var(--p-warn-soft);   color:var(--p-warn);   border-color:var(--p-warn-border); }
.sd-portal .alert--danger { background:var(--p-danger-soft); color:var(--p-danger); border-color:var(--p-danger-border); }
.sd-portal .alert--info   { background:var(--p-accent-soft); color:var(--p-accent); border-color:var(--accent-border); }
.sd-portal .alert[hidden] { display:none; }   /* .alert sets display:flex, which would otherwise defeat the `hidden` attribute */

/* ── Avatar block (account header) ───────────────────────────── */
.sd-portal .avatar-row { display:flex; align-items:center; gap:var(--p-s-16); margin-bottom:var(--p-s-24); }
.sd-portal .avatar-lg { width:56px; height:56px; flex:0 0 56px; border-radius:var(--p-r-pill); background:var(--p-accent-soft); color:var(--p-accent); display:grid; place-items:center; font-weight:800; font-size:var(--p-fs-22); text-transform:uppercase; }
.sd-portal .avatar-info .name { font-weight:700; font-size:var(--p-fs-16); color:var(--p-text-strong); }
.sd-portal .avatar-info .role { color:var(--p-text-muted); font-size:var(--p-fs-13); }

/* ── Table ───────────────────────────────────────────────────── */
.sd-portal .table { width:100%; border-collapse:collapse; background:var(--p-surface); border:1px solid var(--p-border); border-radius:var(--p-r-card); overflow:hidden; }
.sd-portal .table th, .sd-portal .table td { padding:var(--p-s-12) var(--p-s-16); text-align:left; vertical-align:middle; }
.sd-portal .table th { background:var(--p-surface-alt); font-size:var(--p-fs-12); font-weight:600; color:var(--p-text-muted); text-transform:uppercase; letter-spacing:.04em; border-bottom:1px solid var(--p-border); }
.sd-portal .table td { border-bottom:1px solid var(--p-divider); font-size:var(--p-fs-14); }
.sd-portal .table tr:last-child td { border-bottom:0; }

/* ── List row (sessions etc.) ────────────────────────────────── */
.sd-portal .list-row { display:flex; align-items:center; justify-content:space-between; gap:var(--p-s-16); padding:var(--p-s-12) 0; border-bottom:1px solid var(--p-divider); }
.sd-portal .list-row:last-child { border-bottom:0; }
.sd-portal .list-row .meta { color:var(--p-text-muted); font-size:var(--p-fs-12); margin-top:2px; }
.sd-portal .list-row__main { display:flex; align-items:center; gap:var(--p-s-12); min-width:0; }
.sd-portal .list-row__actions { display:flex; gap:var(--p-s-8); align-items:center; flex-shrink:0; }
.sd-portal .av { width:36px; height:36px; flex:0 0 36px; border-radius:var(--p-r-pill); background:var(--p-accent-soft); color:var(--p-accent); display:grid; place-items:center; font-weight:700; font-size:var(--p-fs-14); text-transform:uppercase; }
.sd-portal .av--invite { background:var(--p-surface-alt); color:var(--p-text-muted); }
.sd-portal .av svg { width:15px; height:15px; }
.sd-portal .badge-soft { display:inline-block; font-size:11px; font-weight:600; padding:1px 8px; border-radius:var(--p-r-pill); background:var(--p-accent-soft); color:var(--p-accent); }

/* ── KPI stat cards (stat-grid > stat-card) ──────────────────── */
.sd-portal .stat-grid { display:grid; grid-template-columns:repeat(auto-fit, minmax(160px,1fr)); gap:var(--p-s-16); }
.sd-portal .stat-card { position:relative; overflow:hidden; background:var(--p-surface); border:1px solid var(--p-border); border-radius:var(--p-r-card); padding:var(--p-s-20) var(--p-s-24); }
.sd-portal .stat-card::before { content:''; position:absolute; top:0; left:0; width:100%; height:3px; background:var(--p-border); }
.sd-portal .stat-card--accent::before { background:var(--p-accent); }
.sd-portal .stat-card--ok::before     { background:var(--p-ok); }
.sd-portal .stat-card--warn::before   { background:var(--p-warn); }
.sd-portal .stat-card--danger::before { background:var(--p-danger); }
.sd-portal .stat-card__value { font-size:var(--p-fs-28); font-weight:800; line-height:1; letter-spacing:-.03em; color:var(--p-text-strong); font-variant-numeric:tabular-nums; }
.sd-portal .stat-card--accent .stat-card__value { color:var(--p-accent); }
.sd-portal .stat-card--ok     .stat-card__value { color:var(--p-ok); }
.sd-portal .stat-card--warn   .stat-card__value { color:var(--p-warn); }
.sd-portal .stat-card--danger .stat-card__value { color:var(--p-danger); }
.sd-portal .stat-card__label { font-size:11px; color:var(--p-text-muted); text-transform:uppercase; letter-spacing:.06em; margin-top:var(--p-s-8); font-weight:500; }

/* ── Toolbar + search input (icon via SVG mask) ──────────────── */
.sd-portal .toolbar { display:flex; gap:var(--p-s-12); align-items:center; margin-bottom:var(--p-s-16); flex-wrap:wrap; }
.sd-portal .toolbar__count { font-size:var(--p-fs-12); color:var(--p-text-muted); margin-left:auto; white-space:nowrap; }
.sd-portal .search { position:relative; flex:1; max-width:360px; min-width:180px; }
.sd-portal .search::before {
  content:''; position:absolute; left:12px; top:50%; transform:translateY(-50%);
  width:14px; height:14px; background:var(--p-text-muted); pointer-events:none;
  mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2.5'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cline x1='21' y1='21' x2='16.65' y2='16.65'/%3E%3C/svg%3E") center/contain no-repeat;
  -webkit-mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2.5'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cline x1='21' y1='21' x2='16.65' y2='16.65'/%3E%3C/svg%3E") center/contain no-repeat;
}
.sd-portal .search input { width:100%; height:40px; padding:0 var(--p-s-12) 0 36px; background:var(--p-surface); border:1px solid var(--p-border); border-radius:var(--p-r-input); color:var(--p-text); font-size:var(--p-fs-14); outline:none; transition:border-color var(--p-dur) var(--p-ease), box-shadow var(--p-dur) var(--p-ease); }
.sd-portal .search input:focus { border-color:var(--p-accent); box-shadow:var(--p-accent-ring); }

/* ── Card grid (responsive multi-column card layout) ─────────── */
.sd-portal .card-grid { display:grid; grid-template-columns:repeat(auto-fill, minmax(300px,1fr)); gap:var(--p-s-16); }

/* ── Empty state (icon + title + hint + CTA) ─────────────────── */
.sd-portal .empty-state { text-align:center; padding:var(--p-s-48) var(--p-s-24); max-width:440px; margin:0 auto; }
.sd-portal .empty-state__icon { width:56px; height:56px; margin:0 auto var(--p-s-16); border-radius:var(--p-r-pill); background:var(--p-accent-soft); color:var(--p-accent); display:grid; place-items:center; }
.sd-portal .empty-state__icon svg { width:26px; height:26px; }
.sd-portal .empty-state h3 { font-size:var(--p-fs-18); font-weight:700; }
.sd-portal .empty-state p { color:var(--p-text-muted); font-size:var(--p-fs-14); line-height:1.55; margin-top:var(--p-s-8); }
.sd-portal .empty-state .page-actions { margin-top:var(--p-s-20); justify-content:center; }

/* ── Table variants (zebra / compact / numeric columns) ──────── */
.sd-portal .table--zebra tbody tr:nth-child(even) td { background:var(--p-surface-alt); }
.sd-portal .table--compact th, .sd-portal .table--compact td { padding:var(--p-s-8) var(--p-s-12); }
.sd-portal .table th.num, .sd-portal .table td.num { text-align:right; font-variant-numeric:tabular-nums; }

/* ── Section heading (sub-sections within a page) ───────────── */
.sd-portal .section { margin-top:var(--p-s-32); }
.sd-portal .section-title { font-size:var(--p-fs-18); font-weight:700; color:var(--p-text-strong); }
.sd-portal .section-sub { color:var(--p-text-muted); font-size:var(--p-fs-13); margin:var(--p-s-4) 0 var(--p-s-16); }

/* ── Plan / pricing grid ───────────────────────────────────── */
.sd-portal .plan-grid { display:grid; grid-template-columns:repeat(auto-fit, minmax(240px,1fr)); gap:var(--p-s-16); }
.sd-portal .plan-card { position:relative; display:flex; flex-direction:column; gap:var(--p-s-10, 10px); background:var(--p-surface); border:1px solid var(--p-border); border-radius:var(--p-r-card); padding:var(--p-s-24); }
.sd-portal .plan-card--featured { border-color:var(--p-accent); box-shadow:0 0 0 1px var(--p-accent); }
.sd-portal .plan-card--soldout { opacity:.6; }
.sd-portal .plan-badge { position:absolute; top:-10px; left:var(--p-s-24); background:var(--p-accent); color:var(--p-text-on-accent); font-size:11px; font-weight:700; padding:2px 10px; border-radius:var(--p-r-pill); }
.sd-portal .plan-badge--soldout { background:var(--p-text-muted); }
.sd-portal .plan-name { font-size:var(--p-fs-18); font-weight:700; color:var(--p-text-strong); }
.sd-portal .plan-desc { color:var(--p-text-muted); font-size:var(--p-fs-13); line-height:1.5; margin-top:2px; }
.sd-portal .plan-seats { color:var(--p-text-muted); font-size:var(--p-fs-12); font-weight:500; margin-top:var(--p-s-4); }
.sd-portal .plan-price { margin-top:var(--p-s-4); }
.sd-portal .plan-price-eyebrow { font-size:var(--p-fs-12); color:var(--p-text-muted); margin-bottom:2px; }
.sd-portal .plan-price-eyebrow s { opacity:.7; }
.sd-portal .plan-price-amt { font-size:var(--p-fs-28); font-weight:800; letter-spacing:-.02em; color:var(--p-text-strong); }
.sd-portal .plan-price-unit { color:var(--p-text-muted); font-size:var(--p-fs-13); margin-left:4px; }
.sd-portal .plan-price-note { font-size:var(--p-fs-12); color:var(--p-text-muted); margin-top:2px; }
.sd-portal .plan-save { color:var(--p-ok); font-weight:700; }
.sd-portal .plan-slots { font-size:var(--p-fs-12); color:var(--p-text-muted); }
.sd-portal .plan-note { font-size:var(--p-fs-12); color:var(--p-ok); font-weight:600; }
.sd-portal .plan-cta { margin-top:auto; display:flex; flex-direction:column; gap:var(--p-s-8); padding-top:var(--p-s-12); }

/* ── Progress bar (installments) ───────────────────────────── */
.sd-portal .progress { height:8px; background:var(--p-surface-alt); border:1px solid var(--p-border); border-radius:var(--p-r-pill); overflow:hidden; }
.sd-portal .progress__fill { height:100%; background:var(--p-accent); border-radius:var(--p-r-pill); min-width:4px; }

/* ── Inline input + button row (promo code etc.) ───────────── */
.sd-portal .promo-row { display:flex; gap:var(--p-s-8); margin-top:var(--p-s-12); max-width:440px; }
.sd-portal .promo-input { flex:1; min-width:0; height:40px; padding:0 var(--p-s-12); background:var(--p-surface); border:1px solid var(--p-border); border-radius:var(--p-r-input); color:var(--p-text); font-size:var(--p-fs-14); }
.sd-portal .promo-input:focus { outline:none; border-color:var(--p-accent); box-shadow:var(--p-accent-ring); }
.sd-portal summary.disclosure { cursor:pointer; font-weight:600; color:var(--p-accent); list-style:none; }
.sd-portal summary.disclosure::-webkit-details-marker { display:none; }

/* ── Modal (portal-native; JS toggles `.open` on `.modal-bg`) ── */
.sd-portal .modal-bg { position:fixed; inset:0; z-index:1000; display:none; align-items:center; justify-content:center; background:rgba(0,0,0,.5); padding:var(--p-s-24); }
.sd-portal .modal-bg.open { display:flex; }
.sd-portal .modal { width:100%; max-width:440px; background:var(--p-surface); border:1px solid var(--p-border); border-radius:var(--p-r-card); padding:var(--p-s-24); box-shadow:0 24px 60px rgba(0,0,0,.35); }
.sd-portal .modal h3 { font-size:var(--p-fs-18); font-weight:700; margin-bottom:var(--p-s-16); }
.sd-portal .modal-username { color:var(--p-accent); }
.sd-portal .modal-actions { display:flex; justify-content:flex-end; gap:var(--p-s-8); margin-top:var(--p-s-20); }

/* ── Logo upload (company settings) ────────────────────────── */
.sd-portal .logo-row { display:flex; align-items:center; gap:var(--p-s-12); flex-wrap:wrap; }
.sd-portal .logo-preview { width:140px; height:52px; object-fit:contain; border:1px solid var(--p-border); border-radius:var(--p-r-input); background:var(--p-surface-alt); padding:4px; }

/* ── Quick-add services (reuses my-services.js markup → style natively) ── */
.sd-portal .mysvc-add-form { display:flex; gap:var(--p-s-8); flex-wrap:wrap; align-items:center; margin-top:var(--p-s-12); }
.sd-portal .mysvc-row { display:flex; gap:var(--p-s-8); align-items:center; flex-wrap:wrap; padding:var(--p-s-8) 0; border-bottom:1px solid var(--p-divider); }
.sd-portal .mysvc-row:last-of-type { border-bottom:0; }
.sd-portal .mysvc-inp { height:38px; padding:0 var(--p-s-12); background:var(--p-surface); border:1px solid var(--p-border); border-radius:var(--p-r-input); color:var(--p-text); font:inherit; font-size:var(--p-fs-14); }
.sd-portal .mysvc-inp:focus { outline:none; border-color:var(--p-accent); box-shadow:var(--p-accent-ring); }
.sd-portal .mysvc-name  { flex:1 1 140px; min-width:120px; }
.sd-portal .mysvc-desc  { flex:2 1 180px; min-width:140px; }
.sd-portal .mysvc-price { flex:0 1 110px; width:110px; }
.sd-portal .mysvc-unit  { flex:0 0 84px; }
.sd-portal .mysvc-move, .sd-portal .mysvc-del {
  height:34px; min-width:34px; padding:0 8px; border:1px solid var(--p-border);
  background:var(--p-surface); color:var(--p-text); border-radius:var(--p-r-input); cursor:pointer;
}
.sd-portal .mysvc-move:hover, .sd-portal .mysvc-del:hover { background:var(--p-surface-alt); }
.sd-portal .mysvc-move:disabled { opacity:.4; cursor:default; }
.sd-portal .svc-empty { color:var(--p-text-muted); font-size:var(--p-fs-13); padding:var(--p-s-8) 0; }

/* ── Mono code chips + QR + recovery grid (2FA flow; generic) ── */
.sd-portal .code { font-family:ui-monospace,SFMono-Regular,Menlo,monospace; font-size:var(--p-fs-13); background:var(--p-surface-alt); border:1px solid var(--p-border); border-radius:var(--p-r-input); padding:2px 6px; word-break:break-all; }
.sd-portal .code--block { display:block; padding:var(--p-s-8); margin-top:var(--p-s-4); }
.sd-portal .qr-box { display:inline-block; padding:12px; background:#fff; border:1px solid var(--p-border); border-radius:var(--p-r-input); margin:var(--p-s-8) 0; }
.sd-portal .code-grid { display:grid; grid-template-columns:repeat(2,1fr); gap:var(--p-s-8); list-style:none; padding:var(--p-s-12); margin:var(--p-s-12) 0; background:var(--p-surface-alt); border:1px solid var(--p-border); border-radius:var(--p-r-input); }
.sd-portal .code-grid li code { font-family:ui-monospace,SFMono-Regular,Menlo,monospace; font-size:var(--p-fs-14); letter-spacing:1px; }
/* 2FA flow step rhythm — container is #twofaFlow inside a portal card */
.sd-portal #twofaFlow h3 { font-size:var(--p-fs-16); font-weight:600; margin:var(--p-s-16) 0 var(--p-s-8); }
.sd-portal #twofaFlow h3:first-child { margin-top:0; }
.sd-portal #twofaFlow form { margin-top:var(--p-s-12); }

/* ── Auth pages (login / reset / forgot / verify / 2fa / deletion) ─────
   Centered card, no shell — the portal design system applied to the
   pre-login surface (replaces the legacy auth.css). Reuses .card / .field /
   .btn / .alert; only the layout + logo + pw-toggle are auth-specific. */
.sd-portal.sd-auth { display:flex; align-items:center; justify-content:center; min-height:100vh; padding:var(--p-s-24); }
.sd-portal .auth-card { width:100%; max-width:400px; background:var(--p-surface); border:1px solid var(--p-border); border-radius:var(--p-r-card); padding:var(--p-s-32); }
.sd-portal .auth-card--wide { max-width:480px; }
.sd-portal .auth-logo { text-align:center; margin-bottom:var(--p-s-24); }
.sd-portal .auth-logo h1 { font-size:var(--p-fs-22); font-weight:800; letter-spacing:-.02em; }
.sd-portal .auth-logo h1 .dot { color:var(--p-accent); }
.sd-portal .auth-logo p { color:var(--p-text-muted); font-size:var(--p-fs-13); margin-top:var(--p-s-4); line-height:1.5; }
.sd-portal .auth-footer { text-align:center; margin-top:var(--p-s-20); font-size:var(--p-fs-13); color:var(--p-text-muted); line-height:1.7; }
.sd-portal .btn--block { width:100%; }
.sd-portal .field--pw .pw-wrap { position:relative; }
.sd-portal .field--pw .pw-wrap input { padding-right:52px; }
.sd-portal .field--pw .pw-toggle { position:absolute; right:6px; top:50%; transform:translateY(-50%); background:none; border:0; color:var(--p-accent); font:inherit; font-size:var(--p-fs-12); font-weight:600; cursor:pointer; padding:6px 8px; }
/* Terms-accept checkbox row (signup) */
.sd-portal .field--terms { margin-top:var(--p-s-4); }
.sd-portal .auth-terms { display:flex; align-items:flex-start; gap:var(--p-s-8); font-size:var(--p-fs-13); color:var(--p-text-muted); line-height:1.5; cursor:pointer; }
.sd-portal .auth-terms input { margin-top:3px; flex-shrink:0; }

/* utility */
.sd-portal .hidden { display:none !important; }

/* ── Responsive: collapse sidebar to off-canvas drawer ───────── */
@media (max-width:900px) {
  /* The shared base (css/app/00-tokens-base.css) sets
     html,body{height:100%;overflow:hidden} for the full-screen CANVAS app.
     The portal loads that same base, which trapped scroll on EVERY portal
     page on a phone. Free the document here so all portal pages scroll. The
     CRM hub runs its own fixed-shell model (crm-mobile.css), so exclude it. */
  html { height:auto; overflow-y:auto; }
  body.sd-portal:not(.crm-body){
    height:auto;
    min-height:100dvh;
    overflow-y:auto;
    -webkit-overflow-scrolling:touch;
  }
  .sd-portal .app { display:block; height:auto; overflow:visible; }
  .sd-portal .content { overflow-y:visible; }
  .sd-portal .sidebar {
    position:fixed; top:var(--p-topbar-h); left:0; bottom:0; width:280px; max-width:84vw;
    transform:translateX(-100%); transition:transform .25s var(--p-ease); z-index:60;
    box-shadow:0 12px 40px -8px rgba(0,0,0,.18);
  }
  .sd-portal.nav-open .sidebar { transform:translateX(0); }
  .sd-portal.nav-open::after { content:''; position:fixed; inset:var(--p-topbar-h) 0 0 0; background:rgba(0,0,0,.35); z-index:50; }
  .sd-portal .nav-item { min-height:44px; }
  .sd-portal .content-inner { padding:var(--p-s-24); }
  .sd-portal .page-head { flex-direction:column; align-items:flex-start; gap:var(--p-s-12); }
}
@media (max-width:600px) {
  .sd-portal .field input, .sd-portal .field select, .sd-portal .field textarea { font-size:16px; height:44px; }
  .sd-portal .field-row { grid-template-columns:1fr; }
  .sd-portal .content-inner { padding:var(--p-s-16); }
  .sd-portal .card { padding:var(--p-s-16); }

  /* Pricing cards stack one-up on a phone (defensive — minmax already wraps,
     but lock it so a 2-up never squeezes long plan/price labels). */
  .sd-portal .plan-grid { grid-template-columns:1fr; }

  /* Quick-add service rows: the 7 inline controls (name/desc/price/unit/▲▼✕)
     wrap-spilled messily. Give name + desc their own full-width rows; let the
     price/unit/buttons share the last row. */
  .sd-portal .mysvc-row, .sd-portal .mysvc-add-form { gap:6px; }
  .sd-portal .mysvc-name, .sd-portal .mysvc-desc { flex:1 1 100%; min-width:0; }
  .sd-portal .mysvc-price { flex:1 1 90px; width:auto; }

  /* Button rows wrap + fill instead of cramming on one line. */
  .sd-portal .page-actions { flex-wrap:wrap; }
  .sd-portal .page-actions .btn { flex:1 1 auto; }
  .sd-portal .card-foot { flex-direction:column; align-items:stretch; gap:var(--p-s-12); }
  .sd-portal .card-foot .btn { width:100%; }

  /* ≥44px touch targets (the desktop 40/32px buttons are too small to tap). */
  .sd-portal .btn { min-height:44px; }
  .sd-portal .btn--sm { min-height:40px; }
}
