/* Softphone. One stylesheet, no framework, no build.
   Designed at 380px (the pop-out width), content capped at 420px when GHL gives more.
   State switching is driven by the attributes app.js already sets:
     body[data-phone]  -> connecting | ready | popout | error | offline | setup
     [hidden] on #callbox / #answer / #dispo / #target  -> read back with :has()
   so the stage needs no extra JS to stay mutually exclusive. */

/* ------------------------------------------------------------------ tokens */
/* iOS-style light and dark (2026-09-23, Petar: "modern, like iOS, white and
   black"). Mockup: claude.ai/artifact/MSFd1jf5WVMAdYdodejYPT. The theme is the
   rep's choice (Settings > Appearance): html[data-theme] is light or dark, and
   no attribute means Automatic, which follows the computer's setting. */
:root {
  --font: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Helvetica Neue", Inter, system-ui, "Segoe UI", sans-serif;
  --bg: #f2f2f7;        --surface: #ffffff;     --surface-2: #e9e9ee;
  --line: #e5e5ea;      --line-strong: #c7c7cc;
  --fg: #000000;        --fg-2: #3a3a3c;        --mut: #6c6c70;
  --primary: #0066d6;   --primary-hover: #0057b8; --primary-soft: #e6f0ff;
  --brand: #0066d6;     --brand-soft: #e6f0ff;
  --ok: #1b7a36;        --ok-hover: #166a2e;    --ok-soft: #e4f7e9;
  --call: #1e9e47;      --call-hover: #1a8a3e;
  --warn: #a14f06;      --warn-soft: #fff2dc;
  --bad: #d70015;       --bad-hover: #b80012;   --bad-soft: #ffebea;
  --end: #e5342a;
  --on-accent: #ffffff;
  --key: #e5e5ea;

  --radius: 14px; --radius-sm: 10px; --radius-pill: 999px;
  --shadow-1: 0 1px 2px rgba(0, 0, 0, .06);
  --ring: 0 0 0 3px rgba(0, 102, 214, .28);
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;
    --bg: #000000;      --surface: #1c1c1e;     --surface-2: #2c2c2e;
    --line: #38383a;    --line-strong: #48484a;
    --fg: #ffffff;      --fg-2: #d1d1d6;        --mut: #98989f;
    --primary: #0a84ff; --primary-hover: #409cff; --primary-soft: rgba(10, 132, 255, .18);
    --brand: #0a84ff;   --brand-soft: rgba(10, 132, 255, .18);
    --ok: #30d158;      --ok-hover: #5ae07d;    --ok-soft: rgba(48, 209, 88, .16);
    --warn: #ffb340;    --warn-soft: rgba(255, 159, 10, .18);
    --bad: #ff6961;     --bad-hover: #ff8a84;   --bad-soft: rgba(255, 69, 58, .16);
    --key: #333336;
    --shadow-1: none;
    --ring: 0 0 0 3px rgba(10, 132, 255, .4);
  }
}
:root[data-theme="dark"] {
  color-scheme: dark;
  --bg: #000000;        --surface: #1c1c1e;     --surface-2: #2c2c2e;
  --line: #38383a;      --line-strong: #48484a;
  --fg: #ffffff;        --fg-2: #d1d1d6;        --mut: #98989f;
  --primary: #0a84ff;   --primary-hover: #409cff; --primary-soft: rgba(10, 132, 255, .18);
  --brand: #0a84ff;     --brand-soft: rgba(10, 132, 255, .18);
  --ok: #30d158;        --ok-hover: #5ae07d;    --ok-soft: rgba(48, 209, 88, .16);
  --warn: #ffb340;      --warn-soft: rgba(255, 159, 10, .18);
  --bad: #ff6961;       --bad-hover: #ff8a84;   --bad-soft: rgba(255, 69, 58, .16);
  --key: #333336;
  --shadow-1: none;
  --ring: 0 0 0 3px rgba(10, 132, 255, .4);
}

/* -------------------------------------------------------------------- base */
* { box-sizing: border-box; }
[hidden] { display: none !important; }

html { -webkit-text-size-adjust: 100%; background: var(--bg); }
body {
  margin: 0 auto;
  padding: 0 16px 24px;
  max-width: 420px;
  min-height: 100vh;
  background: var(--bg);
  color: var(--fg);
  font: 400 14px/20px var(--font);
  -webkit-font-smoothing: antialiased;
}
h1, h2, h3, p, ul, figure { margin: 0; }
ul { list-style: none; padding: 0; }
svg { flex: none; }
.cap { font-size: 12px; line-height: 16px; color: var(--mut); }
.num { font-variant-numeric: tabular-nums; letter-spacing: .01em; }
.sr {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}

:where(button, input, select, a):focus-visible {
  outline: 2px solid transparent;
  box-shadow: var(--ring);
  border-radius: var(--radius-sm);
}

/* ------------------------------------------------------------------ top bar */
.topbar {
  position: sticky; top: 0; z-index: 5;
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  height: 56px; margin: 0 -16px; padding: 0 16px;
  background: var(--bg);
  border-bottom: 1px solid var(--line);
}
.status { display: flex; align-items: center; gap: 8px; min-width: 0; }
.dot {
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--line-strong); flex: none;
}
.pill { font-size: 14px; font-weight: 500; color: var(--fg-2); }
.status:has(#pill.ok) .dot   { background: var(--ok); }
.status:has(#pill.bad) .dot  { background: var(--bad); }
.status:has(#pill.info) .dot { background: var(--primary); }
.status:has(#pill.warn) .dot { background: var(--warn); animation: pulse 1.6s ease-in-out infinite; }

.topbar-actions { display: flex; align-items: center; gap: 4px; }
.icon-btn {
  display: grid; place-items: center;
  width: 44px; height: 44px; padding: 0;
  border: 0; border-radius: var(--radius-sm);
  background: transparent; color: var(--mut); cursor: pointer;
  transition: background .15s ease-out, color .15s ease-out;
}
.icon-btn:hover { background: var(--surface-2); color: var(--fg); }

/* -------------------------------------------------------------------- stage */
/* min-height = viewport minus the 56px sticky top bar, so a transient card
   (incoming ring, outcome, pop-out, off) can center in the leftover space.
   Only applied while one of those transient cards is showing — in idle/empty/
   recent the stage must not claim extra height, or the browse zone (Contacts/
   Recent switcher + lists) gets pushed to the bottom of the viewport instead
   of following the dialer with the normal gap. Dialer and the in-call layout
   stay top-aligned (default justify-content). */
#stage {
  padding-top: 16px;
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
}
/* Sprint 3 H: transient cards (ringing, outcome, pop-out, off) anchor at
   roughly a third of the stage height instead of dead center. */
#stage:has(#callbox:not([hidden]) #answer:not([hidden])),
#stage:has(#dispo:not([hidden])),
body[data-phone="popout"] #stage,
body[data-phone="error"] #stage,
body[data-phone="offline"] #stage,
body[data-phone="setup"] #stage {
  min-height: calc(100vh - 56px);
  justify-content: flex-start;
  padding-top: 12vh;
}
#stage > section { animation: rise .15s ease-out; }

.card {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--bg);
  box-shadow: var(--shadow-1);
  padding: 20px 16px;
}
.card-title { font: 600 15px/22px var(--font); color: var(--fg); }

/* Exactly one thing on the stage. A live call, the outcome card, the pop-out
   card and the off card each take over from the dialer. */
body[data-phone="popout"] #dialbox,
body[data-phone="error"] #dialbox,
body[data-phone="offline"] #dialbox,
body[data-phone="setup"] #dialbox,
#stage:has(#callbox:not([hidden])) #dialbox,
#stage:has(#dispo:not([hidden])) #dialbox { display: none; }

body[data-phone="popout"] #browse,
body[data-phone="error"] #browse,
body[data-phone="offline"] #browse,
body[data-phone="setup"] #browse,
#app:has(#callbox:not([hidden])) #browse,
#app:has(#dispo:not([hidden])) #browse { display: none; }

/* ------------------------------------------------------------------- dialer */
#dialbox { display: grid; gap: 16px; }

.from-row {
  display: flex; align-items: center; gap: 8px;
  padding: 8px 12px;
  border: 1px solid var(--line);
  border-radius: var(--radius-pill);
  background: var(--surface);
  font-size: 13px;
}
.from-row > .from-label { color: var(--mut); flex: none; }
#callerId {
  flex: 1 1 auto; min-width: 0;
  border: 0; padding: 0; margin: 0;
  background: transparent; color: var(--fg);
  font: 500 13px/20px var(--font);
  font-variant-numeric: tabular-nums;
  cursor: pointer;
}
/* One number is a fact, not a choice. */
#callerId[data-single] { appearance: none; pointer-events: none; cursor: default; }

#num {
  width: 100%; height: 56px; padding: 0 12px;
  border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--surface); color: var(--fg);
  font: 600 22px/28px var(--font);
  font-variant-numeric: tabular-nums;
  text-align: center; letter-spacing: .01em;
  transition: border-color .15s ease-out, box-shadow .15s ease-out;
}
#num::placeholder { font-weight: 400; color: var(--mut); font-size: 16px; }
#num:focus { border-color: var(--primary); outline: none; box-shadow: var(--ring); }

/* Grid items default to min-width:auto, so without this the row wrapping
   #num/#targetChip sizes to the long chip's max-content width and blows out
   the 380px page instead of letting the chip's own max-width/ellipsis work. */
#dialbox > div:has(#num) { min-width: 0; }

#targetChip {
  display: inline-flex; align-items: center; gap: 6px;
  max-width: 100%; padding: 4px 4px 4px 12px;
  border: 1px solid var(--primary);
  border-radius: var(--radius-pill);
  background: var(--primary-soft);
  color: var(--primary);
  font-size: 13px; line-height: 20px;
}
#targetChip:has(#target[hidden]) { display: none; }
#target { min-width: 0; flex: 1 1 auto; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
#targetClear {
  display: grid; place-items: center;
  width: 24px; height: 24px; padding: 0; flex: none;
  border: 0; border-radius: 50%;
  background: transparent; color: inherit; cursor: pointer;
}
#targetClear:hover { background: rgba(21, 94, 239, .14); }

/* ------------------------------------------------------------------- keypad */
/* Sprint 3 H: once a target chip is set, the keypad collapses to this 44px
   row so contacts/recents surface higher without scrolling; tapping it (or
   typing in #num) expands #pad again. */
.pad-row {
  display: flex; align-items: center; gap: 8px;
  width: 100%; height: 44px; padding: 0 12px;
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  background: var(--surface); color: var(--fg-2);
  font: 500 14px/20px var(--font); cursor: pointer;
  transition: background .15s ease-out;
}
.pad-row:hover { background: var(--surface-2); }
.pad-row .ico { color: var(--mut); }

.pad { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }
.pad button {
  display: grid; gap: 1px; place-items: center; align-content: center;
  height: 52px; padding: 0;
  border: 1px solid transparent; border-radius: var(--radius);
  background: var(--surface); color: var(--fg);
  font: inherit; cursor: pointer;
  transition: background .12s ease-out, transform .12s ease-out;
}
.pad button:hover { background: var(--surface-2); }
.pad button:active { background: var(--line); transform: scale(.97); }
.pad .k { font: 600 20px/24px var(--font); font-variant-numeric: tabular-nums; }
.pad button[data-k="*"] .k, .pad button[data-k="#"] .k { font-weight: 400; }
.pad small { font-size: 10px; line-height: 10px; letter-spacing: .08em; color: var(--mut); }

/* ------------------------------------------------------------------ buttons */
.btn {
  display: flex; align-items: center; justify-content: center; gap: 8px;
  width: 100%; height: 52px; padding: 0 16px;
  border: 1px solid transparent; border-radius: var(--radius);
  background: var(--surface-2); color: var(--fg);
  font: 600 16px/20px var(--font); cursor: pointer;
  transition: background .15s ease-out, border-color .15s ease-out;
}
.btn-ok { background: var(--ok); color: var(--on-accent); }
.btn-ok:hover { background: var(--ok-hover); }
.btn-bad { background: var(--bad); color: var(--on-accent); }
.btn-bad:hover { background: var(--bad-hover); }
.btn-primary { background: var(--primary); color: #fff; }
.btn-primary:hover { background: var(--primary-hover); }
.btn-quiet {
  height: 40px; background: transparent; color: var(--mut);
  font-size: 14px; font-weight: 500;
}
.btn-quiet:hover { color: var(--fg); background: var(--surface-2); }
.link {
  display: inline-block; color: var(--primary);
  font-size: 13px; font-weight: 500; text-decoration: none; padding: 4px 0;
}
.link:hover { text-decoration: underline; }

/* --------------------------------------------------------- call: shared head */
#callbox { display: grid; gap: 20px; justify-items: center; text-align: center; }
.avatar {
  display: grid; place-items: center;
  width: 64px; height: 64px; border-radius: 50%;
  background: var(--primary-soft); color: var(--primary);
  font: 600 22px/1 var(--font); letter-spacing: .02em;
}
.avatar:has(.initials:not(:empty)) .ico { display: none; }
/* Soft pulse ring while the call is ringing (answer button visible). */
#callbox:has(#answer:not([hidden])) .avatar {
  animation: avatar-pulse 2s ease-in-out infinite;
}
@keyframes avatar-pulse {
  0%, 100% { box-shadow: 0 0 0 0 var(--primary-soft); }
  50%      { box-shadow: 0 0 0 8px var(--primary-soft); }
}
#peer {
  font: 600 22px/28px var(--font);
  max-width: 100%; overflow-wrap: anywhere;
}
#peerNum { font-variant-numeric: tabular-nums; }
.ring-cap { display: flex; align-items: center; justify-content: center; gap: 6px; }
.ring-cap .dot { background: var(--ok); animation: pulse 1.4s ease-in-out infinite; }
#timer { font: 600 28px/32px var(--font); font-variant-numeric: tabular-nums; color: var(--fg-2); }
.peer-block { display: grid; gap: 4px; justify-items: center; }

/* Ringing (app.js unhides #answer) vs in-call. One markup, two layouts. */
#callbox:has(#answer:not([hidden])) #timer,
#callbox:has(#answer:not([hidden])) .ctl-row { display: none; }
#callbox:has(#answer[hidden]) .ring-cap { display: none; }

.end-row {
  display: flex; align-items: flex-start; justify-content: center; gap: 40px;
  width: 100%; padding-bottom: 22px;
}
.rbtn {
  position: relative;
  display: grid; place-items: center;
  width: 64px; height: 64px; padding: 0;
  border: 0; border-radius: 50%;
  color: var(--on-accent); cursor: pointer;
  transition: background .15s ease-out, transform .12s ease-out;
}
.rbtn:active { transform: scale(.96); }
.rbtn-ok { background: var(--ok); }
.rbtn-ok:hover { background: var(--ok-hover); }
.rbtn-bad { background: var(--bad); }
.rbtn-bad:hover { background: var(--bad-hover); }
.rbtn .lbl {
  position: absolute; top: calc(100% + 6px); left: 50%; transform: translateX(-50%);
  font: 500 12px/16px var(--font); color: var(--mut); white-space: nowrap;
}
/* In-call: the same #hangup becomes the full-width end-call button. */
#callbox:has(#answer[hidden]) .end-row { display: block; padding-bottom: 0; }
#callbox:has(#answer[hidden]) #hangup {
  width: 100%; height: 52px; border-radius: var(--radius);
  display: flex; align-items: center; justify-content: center; gap: 8px;
  font: 600 16px/20px var(--font);
}
#callbox:has(#answer[hidden]) #hangup .lbl {
  position: static; transform: none; color: var(--on-accent);
  font: 600 16px/20px var(--font);
}
#callbox:has(#answer[hidden]) .lbl-decline,
#callbox:has(#answer:not([hidden])) .lbl-hangup { display: none; }

/* In-call control row: mute / hold / keypad */
.ctl-row { display: flex; justify-content: center; gap: 24px; padding-bottom: 22px; }
.ctl {
  position: relative;
  display: grid; place-items: center;
  width: 56px; height: 56px; padding: 0;
  border: 1px solid var(--line); border-radius: 50%;
  background: transparent; color: var(--fg-2); cursor: pointer;
  transition: background .15s ease-out, color .15s ease-out, border-color .15s ease-out;
}
.ctl:hover { background: var(--surface-2); }
.ctl .lbl {
  position: absolute; top: calc(100% + 6px); left: 50%; transform: translateX(-50%);
  font: 500 12px/16px var(--font); color: var(--mut); white-space: nowrap;
}
.ctl[aria-pressed="true"] {
  background: var(--primary-soft); border-color: var(--primary); color: var(--primary);
}
.ctl[aria-pressed="true"] .lbl { color: var(--primary); }

/* DTMF: reuse the one real keypad, parked in the dialer, shown inside the call. */
body.dtmf #stage:has(#callbox:not([hidden])) #dialbox { display: block; margin-top: 16px; }
body.dtmf #dialbox > :not(#pad) { display: none; }

/* -------------------------------------------------------------- outcome card */
#dispo { position: relative; overflow: hidden; display: grid; gap: 16px; }
#dispoBar {
  position: absolute; top: 4px; left: 4px;
  height: 3px; border-radius: var(--radius-pill);
  background: var(--primary);
  animation: countdown 20s linear forwards;
}
.dispo-head { display: grid; gap: 2px; }
#dispoPeer { font: 600 15px/22px var(--font); }
.dispo-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
#dispoPeer { overflow-wrap: anywhere; }
.tile {
  display: grid; gap: 6px; justify-items: center; align-content: center;
  min-height: 72px; padding: 12px 8px;
  border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--surface); color: var(--fg-2);
  font: 500 13px/16px var(--font); text-align: center; cursor: pointer;
  transition: background .15s ease-out, border-color .15s ease-out, color .15s ease-out;
}
.tile:hover { background: var(--surface-2); }
.tile[aria-pressed="true"] {
  border-color: var(--primary); background: var(--primary-soft); color: var(--primary);
}
#dispoNote {
  width: 100%; height: 44px; padding: 0 12px;
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  background: var(--bg); color: var(--fg); font: 400 14px/20px var(--font);
}
#dispoNote::placeholder { color: var(--mut); }
#dispoNote:focus { border-color: var(--primary); outline: none; box-shadow: var(--ring); }
.dispo-actions { display: grid; gap: 4px; }

/* ------------------------------------------------- pop-out card / off card */
#popoutcard, #offcard { display: none; gap: 12px; justify-items: center; text-align: center; }
body[data-phone="popout"] #popoutcard { display: grid; }
body[data-phone="error"] #offcard,
body[data-phone="offline"] #offcard,
body[data-phone="setup"] #offcard { display: grid; }
.state-dot { width: 10px; height: 10px; border-radius: 50%; }
#popoutcard .state-dot { background: var(--primary); }
#offcard .state-dot { background: var(--bad); }
/* TASKS 4.8/4.5: not-set-up is not a fault -- same card shape, a neutral/amber
   marker instead of the red "something is broken" dot. */
body[data-phone="setup"] #offcard .state-dot { background: var(--warn); }
#popoutcard .btn, #offcard .btn { margin-top: 4px; }
body[data-phone="error"] .t-offline, body[data-phone="error"] .t-setup,
body[data-phone="offline"] .t-error, body[data-phone="offline"] .t-setup,
body[data-phone="setup"] .t-error, body[data-phone="setup"] .t-offline { display: none; }
#err { color: var(--fg-2); font-size: 14px; line-height: 20px; }

/* Off-state text doubles as the inline alert when the phone is otherwise fine
   (a call log that did not save must not blank the dialer). "setup" is
   excluded too: it gets the full dot+title card above, not this soft banner. */
body:not([data-phone="error"]):not([data-phone="offline"]):not([data-phone="setup"]) #offcard:has(#err:not([hidden])) {
  display: grid; grid-auto-flow: row; justify-items: start; text-align: left;
  gap: 8px; margin-top: 16px; padding: 12px;
  border-color: var(--bad); background: var(--bad-soft); box-shadow: none;
}
body:not([data-phone="error"]):not([data-phone="offline"]):not([data-phone="setup"]) #offcard .state-dot,
body:not([data-phone="error"]):not([data-phone="offline"]):not([data-phone="setup"]) #offcard .card-title { display: none; }
body:not([data-phone="error"]):not([data-phone="offline"]):not([data-phone="setup"]) #offcard #err { color: var(--bad); font-size: 13px; }
body:not([data-phone="error"]):not([data-phone="offline"]):not([data-phone="setup"]) #offcard .btn {
  width: auto; height: 36px; padding: 0 12px; font-size: 13px;
}

/* ------------------------------------------------------- browse: seg + lists */
#browse { margin-top: 24px; }
.seg {
  display: grid; grid-template-columns: 1fr 1fr; gap: 4px;
  padding: 4px; border-radius: var(--radius-sm); background: var(--surface-2);
}
.seg-btn {
  height: 40px; border: 0; border-radius: 6px;
  background: transparent; color: var(--mut);
  font: 500 14px/20px var(--font); cursor: pointer;
  transition: background .15s ease-out, color .15s ease-out;
}
.seg-btn[aria-selected="true"] {
  background: var(--bg); color: var(--fg); font-weight: 600; box-shadow: var(--shadow-1);
}
.panel { padding-top: 16px; }

.search { position: relative; margin-bottom: 8px; }
.search svg { position: absolute; left: 12px; top: 12px; color: var(--mut); pointer-events: none; }
#q {
  width: 100%; height: 44px; padding: 0 12px 0 40px;
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  background: var(--surface); color: var(--fg); font: 400 14px/20px var(--font);
}
#q::placeholder { color: var(--mut); }
#q:focus { border-color: var(--primary); outline: none; box-shadow: var(--ring); }
#q::-webkit-search-cancel-button { cursor: pointer; }

.list li { border-bottom: 1px solid var(--line); }
.list li:last-child { border-bottom: 0; }
.row {
  display: flex; align-items: center; gap: 12px;
  width: 100%; min-height: 56px; padding: 8px 4px;
  border: 0; background: transparent; color: inherit;
  font: inherit; text-align: left; cursor: pointer;
  border-radius: var(--radius-sm);
  transition: background .12s ease-out;
}
.row:hover { background: var(--surface); }
.row-body { flex: 1 1 auto; min-width: 0; display: grid; gap: 2px; }
.row-title {
  font: 500 14px/20px var(--font);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.row-cap { font-size: 12px; line-height: 16px; color: var(--mut); font-variant-numeric: tabular-nums; }
.ava {
  display: grid; place-items: center; flex: none;
  width: 32px; height: 32px; border-radius: 50%;
  background: var(--surface-2); color: var(--fg-2);
  font: 600 12px/1 var(--font);
}
.dir { display: grid; place-items: center; flex: none; width: 32px; height: 32px; color: var(--mut); }
.dir-missed { color: var(--bad); }
.chip {
  flex: none; padding: 2px 8px; border-radius: var(--radius-pill);
  font: 500 12px/16px var(--font);
  background: var(--surface-2); color: var(--fg-2);
}
.chip-ok { background: var(--ok-soft); color: var(--ok); }
.chip-bad { background: var(--bad-soft); color: var(--bad); }
.chip-warn { background: var(--warn-soft); color: var(--warn); }

.empty {
  display: grid; gap: 8px; justify-items: center;
  padding: 32px 16px; color: var(--mut); text-align: center; font-size: 14px;
}
.empty svg { color: var(--line-strong); }
.list:not(:empty) + .empty { display: none; }

#boot { padding: 32px 0; color: var(--mut); text-align: center; }

/* ------------------------------------------------------------------- motion */
@keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: .35; } }
@keyframes rise { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }
@keyframes countdown { from { width: calc(100% - 8px); } to { width: 0; } }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important; animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }
}

/* ------------------------------------------------------- admin settings */
/* The settings view replaces the stage: the phone keeps running underneath,
   an active call is never interrupted. body.settings is the only switch;
   body.oncall adds the "Call in progress" banner and disables number changes. */
.settings-bar { display: flex; align-items: center; gap: 4px; min-width: 0; }
.settings-title { font: 600 15px/22px var(--font); color: var(--fg); }
body.settings .status,
body.settings .topbar-actions { display: none; }
body.settings #stage,
body.settings #browse { display: none; }

.banner {
  margin: 12px 0 0; padding: 10px 12px;
  border-radius: var(--radius-sm);
  background: var(--warn-soft); color: var(--fg-2);
  font-size: 13px; line-height: 18px;
}

#settings { padding-bottom: 24px; }
.set-card { margin-top: 12px; padding: 16px; }
.set-card > .cap { margin-top: 2px; }
.set-card > .card-title + .cap { margin-bottom: 4px; }
.set-card .btn-quiet { width: 100%; margin-top: 8px; }

.setlist { display: block; margin-top: 4px; }
.set-row {
  position: relative;
  display: flex; align-items: center; gap: 12px;
  min-height: 44px; padding: 4px 0;
  border-top: 1px solid var(--line);
}
.setlist > .set-row:first-child,
.setlist > li:first-child { border-top: 0; }
.set-label { flex: 1 1 auto; min-width: 0; font-size: 14px; color: var(--fg-2); }
.set-help {
  padding: 4px 0 8px;
  font-size: 12px; line-height: 16px; color: var(--mut);
}
.set-input {
  flex: 0 1 160px; min-width: 0; height: 36px; padding: 0 10px;
  border: 1px solid var(--line-strong); border-radius: var(--radius-sm);
  background: var(--bg); color: var(--fg); font: 400 14px/20px var(--font);
  text-align: right;
}
.set-input:disabled { color: var(--mut); background: var(--surface-2); }
/* A row whose value is a sentence, not a number. .set-input's `0 1 160px` basis
   is a width cap built for a one-line value; a 300-character message needs the
   whole width, so the field drops to its own line. The tick goes absolute
   (.set-row is already positioned) so it stays beside the label instead of
   wrapping onto a third line of its own. */
.set-row.set-stack { flex-wrap: wrap; }
.set-stack > .set-input { flex: 1 1 100%; margin-bottom: 4px; text-align: left; }
.set-stack > .saved { position: absolute; top: 10px; right: 0; }
.set-select {
  flex: 0 1 auto; min-width: 140px; max-width: 100%; height: 36px; padding: 0 8px;
  border: 1px solid var(--line-strong); border-radius: var(--radius-sm);
  background: var(--bg); color: var(--fg); font: 400 13px/20px var(--font);
}
.link-btn {
  padding: 4px; border: 0; background: none; cursor: pointer;
  color: var(--primary); font: 500 13px/20px var(--font);
}

/* A real switch: role="switch" + aria-checked, not a styled checkbox. */
.switch {
  flex: none; position: relative;
  width: 44px; height: 26px; padding: 0;
  border: 0; border-radius: var(--radius-pill);
  background: var(--line-strong); cursor: pointer;
  transition: background .15s ease-out;
}
.switch .knob {
  position: absolute; top: 3px; left: 3px;
  width: 20px; height: 20px; border-radius: 50%;
  background: #fff; box-shadow: var(--shadow-1);
  transition: transform .15s ease-out;
}
.switch[aria-checked="true"] { background: var(--ok); }
.switch[aria-checked="true"] .knob { transform: translateX(18px); }
.switch:disabled { opacity: .5; cursor: not-allowed; }

/* Health badges */
.badges { margin-top: 8px; }
.badge-row {
  display: block;
  min-height: 44px; padding: 6px 0;
  border-top: 1px solid var(--line);
}
.badges > .badge-row:first-child { border-top: 0; }
.badge-line { display: flex; align-items: center; gap: 8px; min-height: 20px; }
.badge-label { flex: 1 1 auto; min-width: 0; font-size: 14px; color: var(--fg-2); }
/* Detail always sits on its own line under the label; the dot stays up top. */
.badge-detail {
  margin: 2px 0 0 16px;
  font-size: 12px; line-height: 16px; color: var(--mut);
}
.state-dot { width: 8px; height: 8px; border-radius: 50%; flex: none; background: var(--line-strong); }
.dot-ok { background: var(--ok); }
.dot-warn { background: var(--warn); }
.dot-bad { background: var(--bad); }

/* Number rows */
.num-row, .user-row, .pick-row {
  position: relative;
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px;
  min-height: 44px; padding: 10px 0;
  border-top: 1px solid var(--line);
}
.setlist > li:first-child { border-top: 0; }
.num-head { flex: 1 1 100%; display: flex; align-items: center; gap: 8px; min-width: 0; }
.num-label {
  flex: 1 1 auto; min-width: 0; height: 32px; padding: 0 8px;
  border: 1px solid transparent; border-radius: var(--radius-sm);
  background: transparent; color: var(--fg);
  font: 600 15px/22px var(--font);
}
.num-label:hover { border-color: var(--line); }
.num-label:focus { border-color: var(--line-strong); background: var(--bg); }
.num-sub { flex: 1 1 100%; display: flex; align-items: center; gap: 8px; min-width: 0; }
.num-e164 { font-size: 14px; color: var(--fg-2); }
.caps { display: flex; gap: 4px; }
.num-ctl { flex: 1 1 100%; display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.radio { display: flex; align-items: center; gap: 6px; font-size: 13px; color: var(--fg-2); cursor: pointer; }
.radio input { width: 18px; height: 18px; accent-color: var(--primary); }
.switch-wrap { display: flex; align-items: center; gap: 6px; }
.switch-caption { font-size: 12px; color: var(--mut); }

.picker { margin-top: 8px; border-top: 1px dashed var(--line); }
.picker-empty { padding: 12px 0; font-size: 13px; color: var(--mut); }
.pick-btn {
  flex: 1 1 auto; display: flex; align-items: center; justify-content: space-between; gap: 8px;
  min-height: 44px; padding: 0 10px;
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  background: var(--surface); color: var(--fg); cursor: pointer;
  font: 500 14px/20px var(--font);
}
.pick-btn:hover { background: var(--surface-2); }
.pick-btn:disabled { opacity: .5; cursor: default; }

/* User rows. The avatar and name/email block are grouped in .user-main so
   they never split across lines. The select wraps under that group on
   narrow widths (flexbox handles this naturally: it only wraps once the
   row runs out of room) and right-aligns itself on its own line via the
   auto margin. */
.user-row { flex-wrap: wrap; }
.user-main { display: flex; gap: 12px; align-items: center; flex: 1 1 180px; min-width: 0; }
.user-body { flex: 1 1 auto; min-width: 0; display: flex; flex-wrap: wrap; align-items: center; gap: 4px 6px; }
.user-name {
  flex: 1 1 auto; min-width: 0;
  font-size: 14px; font-weight: 500; color: var(--fg);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.user-body .cap { flex: 1 1 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.user-row .set-select { flex: 0 0 auto; min-width: 110px; margin-left: auto; }

/* Per-row save feedback */
.saved {
  display: inline-flex; align-items: center; gap: 4px; flex: none;
  color: var(--ok); font-size: 12px; font-weight: 500;
}
.row-err {
  flex: 1 1 100%;
  margin-top: 2px;
  color: var(--bad); font-size: 12px; line-height: 16px;
}

.set-foot { margin-top: 16px; text-align: center; }
.set-foot-line { margin-top: 2px; font-size: 11px; line-height: 16px; color: var(--mut); }
.set-foot-line:first-child { margin-top: 0; }

/* Skeletons: grey bars per card, never a full-screen spinner. */
.skel {
  display: block; height: 14px; margin-top: 12px;
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  animation: skel 1.4s ease-in-out infinite;
}
.skel-title { height: 20px; width: 55%; margin-top: 0; }
@keyframes skel { 0%, 100% { opacity: 1; } 50% { opacity: .5; } }

/* Confirm sheet: slides up 150 ms from the bottom of the panel. */
.sheet {
  position: fixed; inset: 0; z-index: 20;
  display: flex; align-items: flex-end; justify-content: center;
  background: rgba(16, 24, 40, .45);
}
.sheet-card {
  width: 100%; max-width: 420px; padding: 20px 16px calc(16px + env(safe-area-inset-bottom));
  border-radius: var(--radius) var(--radius) 0 0;
  background: var(--bg); box-shadow: var(--shadow-1);
  transform: translateY(100%);
  transition: transform .15s ease-out;
}
.sheet.open .sheet-card { transform: translateY(0); }
#sheetText { font-size: 15px; line-height: 22px; color: var(--fg); }
.sheet-actions { display: flex; gap: 8px; margin-top: 16px; }
.sheet-actions .btn { flex: 1 1 0; }

/* ===================================================================== */
/* Sprint 1 C: "Text-enable your existing number" (web/settings-hosted.js) */
/* ===================================================================== */

.hosted-body { margin-top: 8px; }

/* Requests already in flight, above the rail. */
.hosted-order { padding: 8px 0; border-top: 1px solid var(--line); }
.hosted-order-head { display: flex; align-items: center; gap: 8px; }
.hosted-order-head .num { font-size: 15px; font-weight: 600; color: var(--fg); }
.hosted-order .cap { display: block; margin-top: 2px; }

/* The rail. One hairline runs behind the nodes; the last step stops it. */
.hosted-steps {
  position: relative;
  margin: 12px 0 0; padding: 0;
  list-style: none;
}
.hosted-step {
  position: relative;
  display: flex; gap: 12px;
  padding: 0 0 16px 0;
}
.hosted-step:last-child { padding-bottom: 0; }
.hosted-step::before {
  content: ""; position: absolute; left: 12px; top: 24px; bottom: 0;
  width: 1px; background: var(--line);
}
.hosted-step:last-child::before { display: none; }
.hosted-step.is-done::before { background: var(--ok); opacity: .45; }

.hosted-node {
  flex: none; z-index: 1;
  display: inline-flex; align-items: center; justify-content: center;
  width: 25px; height: 25px; border-radius: 50%;
  border: 1px solid var(--line-strong); background: var(--bg);
  color: var(--mut); font: 600 12px/1 var(--font);
  transition: background .15s ease-out, border-color .15s ease-out, color .15s ease-out;
}
.is-done .hosted-node { border-color: var(--ok); background: var(--ok); color: #fff; }
.is-now .hosted-node {
  border-color: var(--primary); background: var(--primary-soft); color: var(--primary);
  box-shadow: 0 0 0 3px var(--primary-soft);
}

.hosted-step-main { flex: 1 1 auto; min-width: 0; padding-top: 3px; }
.hosted-step-label {
  display: block;
  font: 600 14px/20px var(--font); color: var(--fg-2);
}
.is-todo .hosted-step-label { color: var(--mut); font-weight: 500; }
.is-now .hosted-step-label { color: var(--fg); }
.hosted-step-main > .cap { display: block; margin-top: 1px; }

/* Only the current step opens a pane, so one thing is ever being asked for. */
.hosted-pane { margin-top: 8px; }
.hosted-pane > .cap { display: block; }
.hosted-pane .btn { width: 100%; margin-top: 8px; }
.hosted-pane .set-help { padding-bottom: 0; }
.hosted-pane .link-btn { display: inline-block; margin-top: 6px; padding-left: 0; }

/* Input plus its button share a line and wrap cleanly at 380 px. */
.hosted-row { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 8px; }
.hosted-input { flex: 1 1 140px; text-align: left; }
/* At 380 px the field always takes the row, so the button sits under it at
   full width like every other button in the system. */
.hosted-row .btn { flex: 1 1 100%; margin-top: 0; }
.set-card .hosted-row .btn-quiet { width: 100%; margin-top: 0; }

.hosted-verdict { display: block; margin-top: 8px; }
.hosted-verdict.is-ok { color: var(--ok); }
.hosted-verdict.is-bad { color: var(--bad); }

/* File pickers: the native control, given the same 44 px rhythm as a row. */
.hosted-file {
  display: flex; flex-wrap: wrap; align-items: center; gap: 4px 8px;
  min-height: 44px; padding: 8px 0;
  border-top: 1px solid var(--line);
}
.hosted-file-label { flex: 1 1 100%; font-size: 14px; color: var(--fg-2); }
.hosted-file input[type="file"] {
  flex: 1 1 auto; min-width: 0;
  font: 400 12px/16px var(--font); color: var(--mut);
}
.hosted-file input[type="file"]::file-selector-button {
  margin-right: 8px; padding: 6px 10px;
  border: 1px solid var(--line-strong); border-radius: var(--radius-sm);
  background: var(--surface); color: var(--fg-2);
  font: 500 12px/16px var(--font); cursor: pointer;
}
.hosted-file-name { flex: 1 1 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.hosted-details { margin-top: 8px; }
.hosted-details > summary {
  cursor: pointer; color: var(--primary);
  font: 500 13px/20px var(--font); list-style: none;
}
.hosted-details > summary::-webkit-details-marker { display: none; }
.hosted-details > summary::before { content: "+ "; }
.hosted-details[open] > summary::before { content: "\2212 "; }
.hosted-fields { margin: 6px 0 0; padding-left: 18px; list-style: disc; }
.hosted-fields li { font-size: 12px; line-height: 18px; color: var(--mut); }

/* Text-vs-call choice ahead of "Send me the code": two 44 px radio targets. */
.hosted-method { margin-top: 8px; }
.hosted-method-opt { flex: 1 1 auto; min-height: 44px; }

/* Cancel sits under a request still in flight, set off from its status line. */
.hosted-cancel { margin-top: 8px; }
.hosted-cancel .btn { width: auto; }

@media (prefers-reduced-motion: reduce) {
  .hosted-node { transition: none; }
}

/* Sprint 2 F: "Get a number in another country" (web/settings-international.js).
   380 px first: the search reads as three stacked fields and a full-width
   button, and a result row puts the number and its price on one line because
   in this card the price IS the decision. */
.intl-body { margin-top: 8px; }

.intl-orders { margin: 0; }
.intl-order { padding: 8px 0; border-top: 1px solid var(--line); }
.intl-order-head { display: flex; align-items: center; gap: 8px; }
.intl-order-head .num { font-size: 15px; font-weight: 600; color: var(--fg); }
.intl-flag { font-size: 18px; line-height: 1; }
.intl-order .cap { display: block; margin-top: 2px; }

.intl-search { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 8px; }
.intl-field { display: flex; flex-direction: column; gap: 4px; flex: 1 1 100%; min-width: 0; }
.intl-field-label { font: 500 12px/16px var(--font); color: var(--mut); }
/* .set-input's `flex: 0 1 160px` sizes it for a row-direction .set-row, where the
   160px basis is a width cap. Inside .intl-field/.intl-req (column-direction
   flex containers) that same basis lands on the main axis instead, i.e. it
   becomes the input's HEIGHT -- a ~160px input. Reset the basis here so height
   falls back to .set-input's own `height: 36px`, same as every other field. */
.intl-input { width: 100%; min-width: 0; text-align: left; flex: 1 1 auto; }
.intl-go { width: 100%; margin-top: 2px; }

.intl-docs-note {
  margin: 10px 0 0; padding: 8px 10px;
  border-radius: var(--radius-sm);
  background: var(--warn-soft); color: var(--fg-2);
  font: 400 12px/18px var(--font);
}

.intl-list { margin-top: 4px; }
.intl-row { padding: 10px 0; border-top: 1px solid var(--line); }
.intl-row-head {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 12px;
}
.intl-num { flex: 0 0 auto; font-size: 16px; font-weight: 600; color: var(--fg); }
.intl-price {
  flex: 1 1 auto; min-width: 0; text-align: right;
  font: 600 13px/18px var(--font); color: var(--fg-2);
  font-variant-numeric: tabular-nums;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.intl-row-meta { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; margin-top: 4px; }
.intl-buy { width: 100%; margin-top: 10px; }

.intl-reqs {
  margin-top: 10px; padding: 10px;
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  background: var(--surface);
}
.intl-req { display: flex; flex-direction: column; gap: 6px; padding: 8px 0; }
.intl-req + .intl-req { border-top: 1px solid var(--line); }
.intl-req .cap { margin: 0; }
.intl-req .cap.is-mut { color: var(--mut); font-style: italic; }
.intl-reqs .cap.is-ok { color: var(--ok); }
.intl-req input[type="file"] {
  font: 400 12px/16px var(--font); color: var(--mut);
}
.intl-req input[type="file"]::file-selector-button {
  margin-right: 8px; padding: 6px 10px;
  border: 1px solid var(--line-strong); border-radius: var(--radius-sm);
  background: var(--bg); color: var(--fg-2);
  font: 500 12px/16px var(--font); cursor: pointer;
}

.intl-foot { margin-top: 10px; }
.intl-foot .link-btn { font-size: 12px; }

/* ------------------------------------------ settings IA (sprint 3, section G)
   The settings screen is six panels under a sticky tab row, plus full-stage
   detail views for the three long flows. Everything below is placement and
   target size: no card's internals are restyled here. */

/* Sticky under the 56 px top bar, full-bleed like the top bar itself. */
.set-head {
  position: sticky; top: 56px; z-index: 4;
  display: flex; flex-wrap: wrap; align-items: center; gap: 4px;
  margin: 0 -16px; padding: 0 16px;
  background: var(--bg);
  border-bottom: 1px solid var(--line);
}
.set-tabs {
  display: grid; grid-template-columns: repeat(3, 1fr);
  width: 100%; min-width: 0;
}
/* Six tabs in two rows so labels remain readable in the widget. */
.set-tab {
  min-width: 0; height: 44px; padding: 0 2px;
  border: 0; border-bottom: 2px solid transparent;
  background: none; color: var(--mut); cursor: pointer;
  font: 500 13px/44px var(--font);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  transition: color .15s ease-out, border-color .15s ease-out;
}
.set-tab:hover { color: var(--fg-2); }
.set-tab[aria-selected="true"] { color: var(--primary); border-bottom-color: var(--primary); font-weight: 600; }
.set-head-detail { gap: 8px; height: 52px; }
.set-head-detail .settings-title {
  flex: 1 1 auto; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.set-panel { display: block; }
.set-panel > .set-card:first-child { margin-top: 12px; }

/* Settings search: stacked above the tab row (`.set-head` wraps), so it
   never competes with the tabs for width down to 380 px. */
.set-search { flex: 1 1 100%; order: -1; padding: 10px 0; }
.set-search-input {
  width: 100%; height: 44px; padding: 0 12px;
  border: 1px solid var(--line-strong); border-radius: var(--radius-sm);
  background: var(--surface); color: var(--fg);
  font: 400 14px/44px var(--font);
}
.set-search-input::placeholder { color: var(--mut); }
.set-search-input:focus-visible { outline: 2px solid var(--primary); outline-offset: 1px; }
.set-search-results {
  margin: 6px 0 4px; padding: 4px;
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  background: var(--bg);
  max-height: 60vh; overflow-y: auto;
}
.set-search-opt {
  /* Content is a fixed 20px label + 2px gap + 16px subtitle = 38px; 5px of
     padding top and bottom brings the row to 48px, comfortably above the
     44px minimum, without touching either font size. */
  display: block; box-sizing: border-box; min-height: 44px; padding: 5px 10px;
  border-radius: var(--radius-sm);
  cursor: pointer;
}
.set-search-opt:hover, .set-search-opt.is-active { background: var(--primary-soft); }
.set-search-label { display: block; font: 500 14px/20px var(--font); color: var(--fg); }
.set-search-label .set-search-hit { background: none; color: var(--primary); font-weight: 700; }
.set-search-sub { display: block; margin-top: 2px; font: 400 12px/16px var(--font); color: var(--mut); }
.set-search-empty { margin: 6px 0 4px; padding: 8px 2px; font: 400 13px/18px var(--font); color: var(--mut); }

/* A chosen result briefly draws the eye to the card or row it opened on. */
.set-search-flash { animation: setSearchFlash 1200ms ease-out; border-radius: var(--radius-sm); }
@keyframes setSearchFlash {
  0%, 35% { background: var(--primary-soft); }
  100% { background: transparent; }
}
@media (prefers-reduced-motion: reduce) {
  .set-search-flash { animation: none; outline: 2px solid var(--primary); outline-offset: 2px; }
}

/* Needs attention: the only block that keeps its helper sentences open. */
.attention-card { border-color: var(--line-strong); }
.attention-row { padding: 8px 0; }
.attention-text { font-weight: 500; color: var(--fg); white-space: normal; }
.attention-row .badge-line { align-items: flex-start; }
.attention-row .state-dot { margin-top: 7px; }
.attention-link { display: block; margin-left: 16px; padding: 10px 0; text-align: left; }

/* Overview summary rows */
.set-value { flex: none; font-size: 14px; color: var(--fg); }
.jump-link { flex: none; margin-left: 8px; }

/* "Get started" checklist (TASKS 4.8/4.5): a step per badge-row, same shape
   as a Phone-health row, plus a tick/circle/amber-dot instead of a status
   dot. Row padding is deliberately tight (not the font) so six open steps
   still read as a short list, and a finished step is a single line. */
.onboarding-progress { margin-top: 2px; }
.onboarding-steps { margin-top: 4px; }
.onboarding-step { padding: 7px 0; }
.onboarding-step-done { padding: 6px 0; }
.onboarding-step .badge-detail { margin-left: 24px; margin-top: 2px; }
.onboarding-clickpath { margin: 3px 0 0 24px; font-style: italic; }
.onboarding-step-done .badge-label { color: var(--mut); text-decoration: line-through; text-decoration-color: var(--line-strong); }
.onboarding-icon {
  display: flex; align-items: center; justify-content: center; flex: none;
  width: 16px; height: 16px; border-radius: 50%;
  border: 2px solid var(--line-strong); color: transparent;
}
.onboarding-icon-done { border-color: var(--ok); background: var(--ok); color: #fff; }
/* Started but not finished (e.g. registration submitted, in review): a
   filled amber dot, so it never reads as "nobody has touched this yet". Not
   counted as done -- see onboardingSteps()/onboardingComplete() in
   web/settings-onboarding.js. */
.onboarding-icon-pending { border-color: var(--warn); background: var(--warn); }
/* Nothing else works until Telnyx is connected: the one step that gets its
   own emphasis while it is still open. */
.onboarding-step-primary { border-radius: var(--radius-sm); background: var(--primary-soft); padding: 8px 10px; margin: 0 -10px; }
/* The real primary-button style (same as the Telnyx-account card's own
   "Connect Telnyx" button), full width under the step it belongs to. */
.onboarding-action-primary { margin: 6px 0 0 24px; width: calc(100% - 24px); height: 44px; }
.onboarding-action {
  display: block; min-height: 44px; margin: 2px 0 0 24px; padding: 10px 0;
  text-align: left; text-decoration: none;
}
/* Quiet and small on purpose: it must always read as secondary to whatever
   primary action sits above it, never louder. */
.onboarding-secondary {
  display: block; min-height: 44px; margin: 0 0 0 24px; padding: 8px 0;
  text-align: left; text-decoration: none;
  color: var(--mut); font-size: 12px; font-weight: 400;
}
.onboarding-911 { margin-top: 8px; padding-top: 8px; border-top: 1px solid var(--line); color: var(--mut); }

/* Task cards: Current status, Waiting on, Next, Last checked, Refresh. */
.task-card .task-lines { margin-top: 4px; }
.task-status { margin-left: 16px; }
.task-line { gap: 8px; }
.task-value { flex: none; font-size: 14px; color: var(--fg); }
.task-card .task-next { width: auto; min-width: 140px; margin: 0; }
.task-foot { justify-content: space-between; }
.task-stamp { flex: 1 1 auto; min-width: 0; }
.task-refresh { flex: none; }
.task-open { display: block; width: 100%; margin-top: 4px; text-align: left; }

/* "Add a number": collapsed by default, two rows that open a detail view. */
.disclosure {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  width: 100%; min-height: 44px; padding: 0;
  border: 0; background: none; color: var(--fg); cursor: pointer; text-align: left;
}
.disclosure-mark { flex: none; color: var(--mut); font-size: 16px; line-height: 1; }
.row-open {
  flex: 1 1 auto; min-width: 0; min-height: 44px; padding: 0;
  border: 0; background: none; cursor: pointer; text-align: left;
  color: var(--primary); font: 500 14px/20px var(--font);
}

/* Helper copy longer than a line hides behind "Details". */
.details-link { display: block; padding: 10px 0; text-align: left; }
.set-details-row { display: block; }

/* 44 px targets everywhere on this screen, chips-as-buttons included. */
#settings button:not(.switch):not(.set-tab):not(.disclosure),
#settings select,
#settings input:not([type="radio"]):not([type="checkbox"]) { min-height: 44px; }
#settings .radio { min-height: 44px; }
#settings .link-btn { padding-block: 10px; }
/* The switch keeps its 26 px look and gets a 44 px hit area around it. */
#settings .switch::after {
  content: ''; position: absolute; left: -6px; right: -6px;
  top: 50%; height: 44px; transform: translateY(-50%);
}

/* ------------------------------------------------------------ dial list */
/* One line of status and at most two buttons: the list is the rep's queue, not
   a second screen. Primary is the next thing they would press. */
.dial-bar { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; padding: 12px 14px; }
.dial-text { flex: 1 1 160px; min-width: 0; margin: 0; font-size: 14px; line-height: 20px; color: var(--fg); }
.dial-actions { display: flex; gap: 8px; flex: 0 0 auto; }
.dial-actions .btn { width: auto; height: 36px; padding: 0 14px; font-size: 14px; }

/* Alerts stay dismissible without hiding phone connection status. */
#offcard { position: relative; }
#offcard:has(#err:not([hidden])) { padding-right: 38px; }
#dismissError { position:absolute; right:8px; top:8px; width:28px; height:28px; border:0; border-radius:6px; background:transparent; color:var(--fg); cursor:pointer; font-size:22px; }
#dismissError:hover { background:var(--surface); }
.dir-missed { color:var(--bad); }

/* Use the phone palette for native scrollbars on both surfaces. */
* { scrollbar-color: var(--line-strong) var(--bg); scrollbar-width: auto; }
*::-webkit-scrollbar-track { background: var(--bg); }
*::-webkit-scrollbar-corner { background: var(--bg); }
*::-webkit-scrollbar-thumb { background: var(--line-strong); border-radius: 8px; }
#dialBar { position: sticky; top: 56px; z-index: 15; background: var(--bg); border: 1px solid var(--line); }
#setSequenceGap { width: 86px; appearance: textfield; -moz-appearance: textfield; }
#setSequenceGap::-webkit-inner-spin-button,
#setSequenceGap::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }

body.settings #dialBar { position: static; }

/* Available / Away. A small text button in the top bar: the pill beside the dot
   already says the state ("Phone on" or "Away"), this only changes it. */
.presence-btn {
  height: 32px; padding: 0 12px; border: 1px solid var(--line-strong); border-radius: var(--radius-pill);
  background: transparent; color: var(--fg-2); font: 500 13px/1 var(--font); cursor: pointer; white-space: nowrap;
}
.presence-btn:hover { background: var(--surface-2); color: var(--fg); }
.presence-btn:focus-visible { outline: none; box-shadow: var(--ring); }

/* Call outcomes card (Settings > Calls) and their tiles on the post-call card. */
.outcome-line { display: flex; gap: 6px; width: 100%; align-items: center; }
.outcome-line .set-input { flex: 1 1 0; min-width: 0; text-align: left; }
.outcome-line .set-select { flex: 0 0 auto; min-width: 0; width: 118px; }
.set-card .outcome-del { width: auto; margin-top: 0; padding: 0 6px; flex: 0 0 auto; }
.tile-custom { min-height: 48px; }

/* Caller card (TASKS 1.2): under the caller's name while it rings and during the call. */
.caller-card { display: grid; gap: 6px; justify-items: center; margin-top: 6px; max-width: 100%; }
.caller-tags { display: flex; flex-wrap: wrap; gap: 4px; justify-content: center; }
.caller-note {
  max-width: 100%; margin: 0; padding: 6px 10px; border-radius: var(--radius-sm);
  background: var(--surface-2); color: var(--fg-2); font-size: 12px; line-height: 16px;
  text-align: left; overflow-wrap: anywhere;
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden;
}

/* Incoming calls card (Settings > Calls): business hours. */
.hours-box { gap: 8px; }
.hours-box > .set-select { flex: 1 1 100%; }
.hours-line { display: flex; gap: 8px; align-items: center; width: 100%; }
.hours-line .hours-time { flex: 1 1 0; text-align: left; }
.hours-days { display: flex; gap: 4px; width: 100%; }
.day-chip {
  flex: 1 1 0; min-width: 0; height: 32px; padding: 0;
  border: 1px solid var(--line-strong); border-radius: var(--radius-sm);
  background: var(--bg); color: var(--fg-2); font: 500 12px/16px var(--font); cursor: pointer;
}
.day-chip[aria-pressed="true"] { border-color: var(--primary); background: var(--primary-soft); color: var(--primary); }

/* ------------------------------------------------ dashboard (Phone page) */
/* The widget and narrow windows stay the 420px phone. A wide Phone page puts
   the phone on the left and the dashboard beside it. */
@media (max-width: 999px) { #dash { display: none !important; } }
@media (min-width: 1000px) {
  body.dash {
    max-width: 1440px; padding: 0 32px 32px;
    display: grid; grid-template-columns: 380px minmax(0, 1fr); column-gap: 32px; align-items: start;
  }
  body.dash > #app { grid-column: 1; grid-row: 1; position: sticky; top: 0; }
  body.dash > #dash { grid-column: 2; grid-row: 1; padding-top: 16px; }
}
.dash-head { display: flex; align-items: center; justify-content: space-between; gap: 16px; margin-bottom: 16px; }
.dash-title { font: 600 22px/28px var(--font); }
.dseg { display: inline-flex; padding: 3px; gap: 2px; border-radius: var(--radius-sm); background: var(--surface-2); }
.dseg-btn {
  border: 0; background: none; color: var(--fg-2); cursor: pointer;
  padding: 6px 12px; border-radius: 6px; font: 500 13px/18px var(--font);
}
.dseg-btn[aria-pressed="true"] { background: var(--bg); color: var(--fg); box-shadow: var(--shadow-1); }
.dseg-small .dseg-btn { padding: 4px 10px; font-size: 12px; }
.dash-stats { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 12px; margin-bottom: 16px; }
.dash-stat { display: grid; gap: 2px; text-align: left; padding: 14px 16px; cursor: pointer; color: var(--fg); font: inherit; }
.dash-stat:disabled { cursor: default; }
.dash-stat[aria-pressed="true"] { border-color: var(--primary); }
.dash-stat-value { font: 600 24px/30px var(--font); font-variant-numeric: tabular-nums; }
.dash-cols { display: grid; grid-template-columns: minmax(0, 1fr) 300px; gap: 16px; align-items: start; }
@media (max-width: 1280px) { .dash-cols { grid-template-columns: minmax(0, 1fr); } }
.dash-log { padding: 16px 0 4px; }
.dash-log-head { display: flex; align-items: center; gap: 12px; padding: 0 16px 12px; flex-wrap: wrap; }
.dash-log-head .card-title { margin-right: auto; }
.dash-rep { min-width: 140px; }
.dash-rows > li + li { border-top: 1px solid var(--line); }
.dash-row { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; padding: 0 12px 0 0; }
.dash-row-main {
  display: grid; grid-template-columns: 64px minmax(0, 1fr) auto; align-items: center; gap: 12px;
  padding: 10px 12px 10px 16px; border: 0; background: none; color: inherit; text-align: left; cursor: pointer; font: inherit;
}
.dash-row-main:hover { background: var(--surface-2); }
.dash-dir { font: 500 12px/16px var(--font); color: var(--mut); }
.dash-dir.bad { color: var(--bad); }
.dash-who { display: grid; min-width: 0; }
.dash-name { font-weight: 500; color: var(--fg); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dash-who .cap { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dash-meta { display: flex; align-items: center; gap: 6px; }
.dash-dur { min-width: 40px; text-align: right; font-variant-numeric: tabular-nums; color: var(--fg-2); }
.dash-call { width: auto; flex: none; height: 32px; padding: 0 12px; white-space: nowrap; }
.dash-detail { grid-column: 1 / -1; display: grid; gap: 8px; padding: 4px 16px 16px 92px; }
.dash-detail audio { width: 100%; max-width: 480px; height: 36px; }
.dash-sub { font: 600 13px/18px var(--font); color: var(--fg); }
.dash-summary { white-space: pre-line; color: var(--fg-2); }
.dash-transcript summary { cursor: pointer; color: var(--primary); }
.dash-transcript p { margin-top: 6px; color: var(--fg-2); white-space: pre-line; max-height: 240px; overflow: auto; }
.dash-empty { padding: 24px 16px; text-align: center; }
.dash-side { display: grid; gap: 16px; }
.dash-card { padding: 16px; }
.dash-mini { display: grid; gap: 10px; margin-top: 10px; }
.dash-mini-row { display: flex; align-items: center; justify-content: space-between; gap: 8px; min-width: 0; }
.dash-state-available { background: var(--ok-soft); color: var(--ok); }
.dash-state-away { background: var(--warn-soft); color: var(--warn); }

.dash-export { width: auto; height: 32px; padding: 0 12px; margin: 0; }
.dash-tag { display: flex; gap: 8px; margin-top: 10px; }
.dash-tag .set-input { flex: 1 1 auto; text-align: left; }
.dash-tag .btn { width: auto; flex: none; height: 36px; padding: 0 14px; }
.dash-reps { width: 100%; margin-top: 10px; border-collapse: collapse; font-size: 13px; }
.dash-reps th { text-align: right; font-weight: 500; color: var(--mut); padding: 0 0 6px 6px; font-size: 12px; }
.dash-reps td { text-align: right; padding: 6px 0 6px 6px; border-top: 1px solid var(--line); font-variant-numeric: tabular-nums; }
.dash-reps th:first-child, .dash-reps td:first-child { text-align: left; padding-left: 0; }
.dash-reps td.bad { color: var(--bad); }
.dash-reps td.dash-name { max-width: 110px; }


/* =================================================================== look: iOS
   Flat grouped surfaces, round keys, green call and red end, blue tint for
   everything interactive. Colours come only from the tokens above, so light,
   dark and Automatic all follow from html[data-theme]. */
.card { border-radius: 16px; background: var(--surface); border-color: transparent; box-shadow: none; }
.topbar { border-bottom-color: transparent; }
.status { padding: 4px 12px 4px 10px; border-radius: var(--radius-pill); background: var(--surface); }
.status:has(#pill.ok) { background: var(--ok-soft); }
.status:has(#pill.ok) .pill { color: var(--ok); font-weight: 600; }
.presence-btn { border-color: var(--line-strong); }

.pad { grid-template-columns: repeat(3, 72px); justify-content: space-evenly; row-gap: 12px; }
.pad button { width: 72px; height: 72px; border-radius: 50%; background: var(--key); border-color: transparent; }
.pad button:hover { background: var(--line-strong); }
.pad .k { font: 400 30px/34px var(--font); }
.pad small { color: var(--fg); font-weight: 700; letter-spacing: .14em; }
#num { background: transparent; border-color: transparent; font-size: 32px; font-weight: 400; }
#num:focus { background: var(--surface); }

.btn-ok, .rbtn-ok { background: var(--call); color: #ffffff; }
.btn-ok:hover, .rbtn-ok:hover { background: var(--call-hover); }
.btn-bad, .rbtn-bad { background: var(--end); color: #ffffff; }
.btn-bad:hover, .rbtn-bad:hover { background: var(--bad-hover); }
.btn-primary { background: var(--primary); color: #ffffff; }
.btn-primary:hover { background: var(--primary-hover); }
#callbox:has(#answer[hidden]) #hangup .lbl { color: #ffffff; }

.seg { background: var(--surface-2); border: 0; padding: 2px; }
.seg-btn { height: 34px; color: var(--fg); }
.seg-btn[aria-selected="true"] { background: var(--surface); color: var(--fg); box-shadow: 0 1px 3px rgba(0, 0, 0, .14); }

.ava, .avatar { background: var(--brand-soft); color: var(--brand); }
.hue-0 { background: #e9e1ff; color: #5b3cc4; }
.hue-1 { background: #dcf5e4; color: #1b7a36; }
.hue-2 { background: #ffe9d6; color: #a14f06; }
.hue-3 { background: #ffe1ee; color: #a3245c; }
.hue-4 { background: #dcefff; color: #0a5ba8; }
.hue-5 { background: #fff3c4; color: #7a5a00; }
:root[data-theme="dark"] .hue-0 { background: #3a2d5c; color: #c9b8ff; }
:root[data-theme="dark"] .hue-1 { background: #173d2a; color: #7ee2a0; }
:root[data-theme="dark"] .hue-2 { background: #4a2a12; color: #ffb26b; }
:root[data-theme="dark"] .hue-3 { background: #4a1f33; color: #ff9cc4; }
:root[data-theme="dark"] .hue-4 { background: #123348; color: #7cc8ff; }
:root[data-theme="dark"] .hue-5 { background: #3d3410; color: #ffe066; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme]) .hue-0 { background: #3a2d5c; color: #c9b8ff; }
  :root:not([data-theme]) .hue-1 { background: #173d2a; color: #7ee2a0; }
  :root:not([data-theme]) .hue-2 { background: #4a2a12; color: #ffb26b; }
  :root:not([data-theme]) .hue-3 { background: #4a1f33; color: #ff9cc4; }
  :root:not([data-theme]) .hue-4 { background: #123348; color: #7cc8ff; }
  :root:not([data-theme]) .hue-5 { background: #3d3410; color: #ffe066; }
}
.dir-in { color: var(--brand); }
.dir-out { color: var(--ok); }
.list { background: var(--surface); border-radius: 12px; overflow: hidden; }
.list li { border-bottom-color: var(--line); }
.row { border-radius: 0; padding: 8px 12px; }
.row:hover { background: var(--surface-2); }
#q { background: var(--surface-2); border-color: transparent; border-radius: var(--radius-sm); }

.tile { border-radius: 14px; background: var(--surface); border: 2px solid var(--surface); }
.tile[aria-pressed="true"] { border-color: var(--primary); background: var(--primary-soft); color: var(--fg); }
#dispo { background: var(--bg); }
#dispoNote { background: var(--surface); border-color: transparent; }

.set-card { background: var(--surface); }
.switch[aria-checked="true"] { background: #34c759; }

.dash-title { font-size: 34px; line-height: 41px; font-weight: 700; letter-spacing: -.01em; }
.dash-stat { grid-template-columns: 40px minmax(0, 1fr); column-gap: 12px; align-items: center; padding: 16px; }
.dash-stat .dash-stat-ico { grid-row: span 2; display: grid; place-items: center; width: 40px; height: 40px; border-radius: 12px; }
.dash-stat[aria-pressed="true"] { box-shadow: 0 0 0 2px var(--primary); }
.tone-brand .dash-stat-ico { background: var(--brand-soft); color: var(--brand); }
.tone-ok .dash-stat-ico { background: var(--ok-soft); color: var(--ok); }
.tone-bad .dash-stat-ico { background: var(--bad-soft); color: var(--bad); }
.tone-warn .dash-stat-ico { background: var(--warn-soft); color: var(--warn); }
.dash-row-main { grid-template-columns: 36px minmax(0, 1fr) auto; }
.dash-ava { display: grid; place-items: center; width: 36px; height: 36px; border-radius: 50%; font: 600 13px/1 var(--font); position: relative; }
.dash-ava .dash-dir-ico {
  position: absolute; right: -3px; bottom: -3px; display: grid; place-items: center;
  width: 16px; height: 16px; border-radius: 50%; background: var(--surface); border: 1px solid var(--line);
}
.dash-dir-ico.in { color: var(--brand); } .dash-dir-ico.out { color: var(--ok); } .dash-dir-ico.missed { color: var(--bad); }
.dash-detail { padding-left: 64px; }
.dseg { background: var(--surface-2); border: 0; }
.dseg-btn { color: var(--fg); }
.dseg-btn[aria-pressed="true"] { background: var(--surface); color: var(--fg); box-shadow: 0 1px 3px rgba(0, 0, 0, .14); }
.dash-team-dot { width: 8px; height: 8px; border-radius: 50%; display: inline-block; margin-right: 8px; background: var(--line-strong); }
.dash-team-dot.available { background: #34c759; }
.dash-team-dot.away { background: #ff9f0a; }
.dash-row .dash-call { color: var(--primary); }

/* Appearance picker (Settings, every rep). */
#appearance { margin-top: 12px; }
.theme-pick { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; margin: 12px 0 8px; }
.theme-pick button {
  display: grid; justify-items: center; gap: 6px; padding: 8px 4px; border: 0; border-radius: 12px;
  background: transparent; color: var(--fg); font: 500 13px/16px var(--font); cursor: pointer;
}
.theme-pick button[aria-checked="true"] { background: var(--primary-soft); color: var(--primary); }
.theme-thumb { width: 56px; height: 72px; border-radius: 10px; border: 1px solid var(--line-strong); }
.theme-thumb.light { background: #ffffff; }
.theme-thumb.dark { background: #1c1c1e; }
.theme-thumb.auto { background: linear-gradient(90deg, #ffffff 50%, #1c1c1e 50%); }

/* Recent: All / Missed. */
.recent-filter { margin-bottom: 10px; }
.recent-filter .seg-btn[aria-pressed="true"] { background: var(--surface); box-shadow: 0 1px 3px rgba(0, 0, 0, .14); font-weight: 600; }
#activity[data-missed-only] > li:not([data-missed]) { display: none; }

/* ------------------------------------------------ bottom tab bar (iOS mockup) */
.tabbar {
  position: fixed; bottom: 0; left: 0; right: 0; z-index: 5;
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
  max-width: 420px; margin: 0 auto; padding: 6px 0 10px;
  background: var(--surface); border-top: 1px solid var(--line);
}
.tabbar button {
  display: grid; justify-items: center; gap: 2px; padding: 4px 0; border: 0; background: none;
  color: var(--mut); font: 500 10px/12px var(--font); cursor: pointer;
}
.tabbar button[aria-current="page"] { color: var(--primary); font-weight: 600; }
.tab-ico { position: relative; display: flex; }
.tab-badge {
  position: absolute; top: -4px; right: -12px; min-width: 18px; height: 18px; padding: 0 5px; box-sizing: border-box;
  border-radius: 9px; background: #ff3b30; color: #fff; font: 700 11px/18px var(--font); text-align: center;
}
/* Which part shows on which tab. A call and the outcome card force Keypad (app.js). */
body:not(.wide)[data-tab="keypad"] #browse,
body:not(.wide)[data-tab="lists"] #browse,
body:not(.wide)[data-tab="recents"] #dialbox,
body:not(.wide)[data-tab="contacts"] #dialbox,
body:not(.wide)[data-tab="lists"] #dialbox { display: none; }
body:not(.wide)[data-tab="recents"] #browse, body:not(.wide)[data-tab="contacts"] #browse { margin-top: 8px; }
body:not(.wide) #browse > .seg[role="tablist"] { display: none; }
body.settings .tabbar, body.settings #panelLists,
#app:has(#callbox:not([hidden])) .tabbar,
#app:has(#dispo:not([hidden])) .tabbar,
body[data-phone="error"] .tabbar, body[data-phone="offline"] .tabbar,
body[data-phone="setup"] .tabbar { display: none; }
.lists-panel { margin-top: 16px; display: grid; gap: 10px; }
.tag-form { display: flex; gap: 8px; }
.tag-form .set-input { flex: 1 1 auto; text-align: left; height: 44px; }
.tag-form .btn { width: auto; height: 44px; padding: 0 18px; }
/* The wide Phone page (app.js sets .wide) has room for everything: no tabs. */
body.wide .tabbar, body.wide #panelLists { display: none; }
body:not(.wide):not(.settings) { padding-bottom: 72px; }
/* Keypad sized to fit the widget above the tab bar. */
body:not(.wide) .pad { grid-template-columns: repeat(3, 64px); row-gap: 10px; }
body:not(.wide) .pad button { width: 64px; height: 64px; }
body:not(.wide) .pad .k { font-size: 28px; line-height: 30px; }
body:not(.wide) #dialbox { gap: 12px; }

/* In-call controls: six round buttons in two rows (iOS mockup), plus the note and text panels. */
.ctl-row { display: grid; grid-template-columns: repeat(3, 56px); justify-content: center; column-gap: 32px; row-gap: 34px; }
.ctl:disabled { opacity: .4; cursor: default; }
#callbox:has(#answer[hidden]) #peerLink { display: none; }
.call-panel { width: 100%; display: grid; gap: 8px; text-align: left; }
.call-panel textarea {
  width: 100%; box-sizing: border-box; resize: none; padding: 10px 12px; border: 0; border-radius: var(--radius-sm);
  background: var(--surface-2); color: var(--fg); font: 400 15px/20px var(--font);
}
.call-panel textarea:focus, .call-panel select:focus, .call-panel input:focus { outline: none; box-shadow: var(--ring); }
.call-panel select, .call-panel input {
  width: 100%; box-sizing: border-box; height: 36px; padding: 0 12px; border: 0; border-radius: var(--radius-sm);
  background: var(--surface-2); color: var(--fg); font: 400 15px/20px var(--font);
}
.call-panel-row input { flex: 1 1 auto; min-width: 0; }
#transferStatus:empty { display: none; }
/* Transfer makes seven controls: four across keeps them to two rows, so the widget height fixes below still hold. */
.ctl-row:has(#transferToggle:not([hidden])) { grid-template-columns: repeat(4, 56px); column-gap: 18px; }
.call-panel-row { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.call-panel-row .btn { width: auto; height: 36px; padding: 0 16px; }
/* With a note or text box open, the caller details step aside so Hang up stays in view. */
#callbox:has(.call-panel:not([hidden])) #callerCard,
#callbox:has(.call-panel:not([hidden])) #peerContext,
#callbox:has(.call-panel:not([hidden])) .avatar { display: none; }
#callbox:has(.call-panel:not([hidden])) { gap: 14px; }

/* Ringing screen: Text back / Open contact above Decline and Answer. */
.ring-actions { display: none; }
#callbox:has(#answer:not([hidden])) .ring-actions { display: flex; justify-content: center; gap: 48px; }
.ring-act {
  display: grid; justify-items: center; gap: 6px; padding: 0; border: 0; background: none;
  color: var(--fg); font: 500 12px/16px var(--font); cursor: pointer;
}
.ring-act:disabled { opacity: .4; cursor: default; }
.ring-ico { display: grid; place-items: center; width: 52px; height: 52px; border-radius: 50%; background: var(--surface-2); }
.ring-act:hover:not(:disabled) .ring-ico { background: var(--line-strong); }
/* The call screen's Contact / Open contact buttons replace the "Open in GHL" link,
   and a ringing call starts near the top so Decline and Answer stay in the widget. */
#callbox #peerLink { display: none; }
#stage:has(#callbox:not([hidden]) #answer:not([hidden])) { padding-top: 8px; }
#callbox:has(#answer:not([hidden])) { gap: 14px; }
#callbox:has(#answer:not([hidden])) .end-row { padding-bottom: 26px; }

/* PhoneClover palettes: explicit choices, independent of browser appearance. */
:root[data-theme] {
  color-scheme: dark;
  --bg:#2d3748; --surface:#374356; --surface-2:#4b5563; --fg:#fff; --fg-2:#edf2f7; --mut:#d0d8e2;
  --line:#566174; --line-strong:#718096; --primary:#5bbf8a; --primary-hover:#72cfa0;
  --primary-soft:#244d3e; --brand:#5bbf8a; --brand-soft:#244d3e; --ok:#5bbf8a;
  --call:#fff; --call-hover:#e8f5ed; --end:#ff7868; --key:transparent;
  --clover-head:#fff; --clover-ink:#2d3748; --clover-chip:#2d3748; --clover-chip-ink:#fff;
  --clover-call-ink:#2d3748; --clover-digits:#fff;
}
:root[data-theme="light-mint"] {
  --bg:#558973; --surface:#477660; --surface-2:#39644f; --line:#78a791; --line-strong:#aed0bf;
  --clover-ink:#477660; --clover-chip:#558973; --clover-call-ink:#477660;
}
:root[data-theme="dark-mint"] {
  --bg:#303034; --surface:#3d3d42; --surface-2:#49494f; --line:#57575f; --line-strong:#777780;
  --clover-head:#55af87; --clover-ink:#202b28; --clover-chip:#303034; --clover-chip-ink:#83dbb2;
  --clover-digits:#71d1a4; --call:#55af87; --clover-call-ink:#172e24;
}
:root[data-theme="black"] {
  --bg:#050909; --surface:#202424; --surface-2:#303434; --line:#454949; --line-strong:#777;
  --clover-head:#303034; --clover-ink:#d4d8d5; --clover-chip:#050909; --clover-chip-ink:#d4d8d5;
  --clover-digits:#c1c7c3; --call:#b8c2bb; --clover-call-ink:#050909; --primary:#b8c2bb;
}
.phoneclover-brand { display:flex; align-items:center; gap:5px; grid-column:1 / 3; }
.phoneclover-brand img { object-fit:contain; }
:root[data-theme="black"] .phoneclover-brand { filter:grayscale(1) brightness(3); }
.topbar { display:grid; grid-template-columns:auto 1fr auto; height:88px; gap:6px; padding:10px 16px; background:var(--clover-head); color:var(--clover-ink); }
.topbar-actions { display:contents; }
#gear { grid-column:3; grid-row:1; justify-self:end; color:var(--clover-ink); }
.status { grid-column:1; grid-row:2; }
#presence { grid-column:2; grid-row:2; justify-self:start; }
.status, .status:has(#pill.ok), #presence { background:var(--clover-chip); color:var(--clover-chip-ink); border:0; padding:3px 8px; min-height:24px; font-size:11px; }
.status .pill, .status:has(#pill.ok) .pill { color:var(--clover-chip-ink); font-size:11px; }
body.settings .phoneclover-brand { display:none; }
body.settings .topbar { display:flex; height:56px; }
#dialbox { position:relative; }
.topbar .from-row { grid-column:3; grid-row:2; max-width:145px; height:24px; margin:0; padding:2px 7px; background:var(--clover-chip); color:var(--clover-chip-ink); border:0; }
.topbar .from-label { display:none; }
#callerId { color:var(--clover-chip-ink); font-size:10px; padding:0; min-width:0; }
#stage { padding-top:0; }
#dialbox > div:has(#num) { margin:0 -16px; padding:16px; background:var(--clover-head); color:var(--clover-ink); }
#num { color:var(--clover-ink); height:52px; font-size:24px; }
#num::placeholder { color:var(--clover-ink); opacity:1; font-size:18px; }
#num:focus { background:transparent; }
.pad button, body:not(.wide) .pad button { background:transparent; border:0; color:var(--clover-digits); border-radius:12px; }
.pad small { color:var(--clover-digits); font-size:9px; font-weight:400; }
#call { width:auto; min-width:108px; height:40px; padding:0 18px; justify-self:center; color:var(--clover-call-ink); border-radius:24px; }
.tabbar { background:var(--bg); border:0; }
.tabbar button { color:var(--clover-digits); opacity:.72; }
.tabbar button[aria-current="page"] { color:var(--clover-digits); opacity:1; text-decoration:underline; text-underline-offset:4px; }
.theme-pick { grid-template-columns:repeat(4,minmax(0,1fr)); }
.theme-thumb.default { background:linear-gradient(#fff 30%,#2d3748 30%); }
.theme-thumb.light-mint { background:linear-gradient(#fff 30%,#558973 30%); }
.theme-thumb.dark-mint { background:linear-gradient(#55af87 30%,#303034 30%); }
.theme-thumb.black { background:linear-gradient(#303034 30%,#050909 30%); }
/* Fit the initial keypad and Call action in shorter widget viewports. */
@media (max-height:650px) {
  body:not(.wide):not(.settings) .pad { row-gap:2px; }
  body:not(.wide):not(.settings) .pad button { height:clamp(32px,8.8vh,56px); width:64px; }
  body:not(.wide):not(.settings) #dialbox { gap:6px; }
  body:not(.wide):not(.settings) #dialbox > div:has(#num) { padding-top:8px; padding-bottom:8px; }
  body:not(.wide):not(.settings) #num { height:40px; }
  body:not(.wide):not(.settings) .tabbar { padding:4px 0; }
}

body.settings .topbar .from-row { display:none; }
@media (max-height:460px) {
  body:not(.wide):not(.settings) .topbar { height:76px; padding-top:4px; padding-bottom:4px; }
  body:not(.wide):not(.settings) .pad button { height:30px; }
  body:not(.wide):not(.settings) .pad .k { font-size:23px; line-height:24px; }
  body:not(.wide):not(.settings) .pad small { font-size:7px; line-height:8px; }
  body:not(.wide):not(.settings) #num { height:32px; }
  body:not(.wide):not(.settings) #call { height:34px; }
  body:not(.wide):not(.settings) .tabbar svg { width:20px; height:20px; }
}

/* ----------------------------------------------------------- Clover theme */
/* "Clover": the Phone Clover brand theme, the phoneclover.com look (design system: relianceai/phoneclover.com
   docs/website/design.md). Added next to the other themes; it only applies when
   html[data-theme="clover"], so Default, Light mint, Dark mint and Black are unchanged.
   Mint means act or good; no red or orange: decline/hang up are neutral dark. */
:root[data-theme="clover"] {
  --font: "Hanken Grotesk", Inter, system-ui, -apple-system, "Segoe UI", sans-serif;
  --bg:#1f1f1f; --surface:#282828; --surface-2:#303030; --line:#3a3a3a; --line-strong:#4a4a4a;
  --fg:#f4f4f2; --fg-2:#d8d9d8; --mut:#aaabaa;
  --primary:#5bbf8a; --primary-hover:#76ce9f; --primary-soft:#243a2e;
  --brand:#5bbf8a; --brand-soft:#243a2e;
  --ok:#5bbf8a; --ok-hover:#76ce9f; --ok-soft:#243a2e;
  --warn:#d8d9d8; --warn-soft:#303030; --bad:#d8d9d8; --bad-hover:#f4f4f2; --bad-soft:#303030;
  --call:#5bbf8a; --call-hover:#76ce9f; --end:#3a3a3a; --on-accent:#1f1f1f; --key:transparent;
  --clover-head:#1f1f1f; --clover-ink:#f4f4f2; --clover-chip:#282828; --clover-chip-ink:#d8d9d8;
  --clover-call-ink:#1f1f1f; --clover-digits:#f4f4f2;
  --radius:12px; --radius-sm:8px;
  --ring:0 0 0 3px rgba(91,191,138,.35);
}
.phoneclover-brand img.on-dark { display:none; }
:root[data-theme="clover"] .phoneclover-brand img:not(.on-dark) { display:none; }
:root[data-theme="clover"] .phoneclover-brand img.on-dark { display:block; }
:root[data-theme="clover"] .topbar { border-bottom:1px solid var(--line); }
:root[data-theme="clover"] .status,
:root[data-theme="clover"] #presence,
:root[data-theme="clover"] .topbar .from-row { border:1px solid var(--line); }
:root[data-theme="clover"] #dialbox > div:has(#num) { border-bottom:0; }
:root[data-theme="clover"] #num { font-weight:700; font-variant-numeric:tabular-nums; letter-spacing:-.01em; }
:root[data-theme="clover"] #targetChip { background:var(--surface); border-color:var(--primary); color:var(--primary); }
:root[data-theme="clover"] .pad small { color:var(--mut); }
:root[data-theme="clover"] .pad button:hover { background:var(--surface); }
:root[data-theme="clover"] #call { font-weight:700; }
:root[data-theme="clover"] .tabbar { border-top:1px solid var(--line); }
:root[data-theme="clover"] .tabbar button { color:var(--mut); opacity:1; }
:root[data-theme="clover"] .tabbar button[aria-current="page"] { color:var(--primary); text-decoration:none; }
:root[data-theme="clover"] .card { background:var(--surface); box-shadow:none; }
:root[data-theme="clover"] .card-title { font-weight:700; }
/* call screen: Answer is the one mint action; Decline and Hang up are neutral dark */
:root[data-theme="clover"] .rbtn-bad { background:#3a3a3a; color:var(--fg); box-shadow:inset 0 0 0 1px #4a4a4a; }
:root[data-theme="clover"] .rbtn-bad:hover { background:#474747; }
:root[data-theme="clover"] #callbox:has(#answer[hidden]) #hangup .lbl { color:var(--fg); }
:root[data-theme="clover"] .ring-act .ring-ico { background:var(--surface-2); }
:root[data-theme="clover"] .ctl { background:var(--surface-2); border-color:var(--line); }
:root[data-theme="clover"] .ctl[aria-pressed="true"] { background:transparent; border:2px solid var(--primary); color:var(--primary); }
/* outcome: selected tile = mint border and icon, label stays white */
:root[data-theme="clover"] .tile[aria-pressed="true"] { background:var(--surface); border:2px solid var(--primary); color:var(--fg); }
:root[data-theme="clover"] .tile[aria-pressed="true"] svg { color:var(--primary); }
:root[data-theme="clover"] #dispoNote { background:var(--surface); }
:root[data-theme="clover"] .switch[aria-checked="true"],
:root[data-theme="clover"] .dash-team-dot.available { background:var(--primary); }
:root[data-theme="clover"] .timer, :root[data-theme="clover"] #timer { font-variant-numeric:tabular-nums; }
:root[data-theme="clover"] .pad button { border-radius:8px; }
:root[data-theme="clover"] .seg-btn[aria-selected="true"] { background:var(--surface-2); box-shadow:inset 0 0 0 1px var(--line); }
:root[data-theme="clover"] .dseg { background:var(--surface); box-shadow:inset 0 0 0 1px var(--line); }
:root[data-theme="clover"] .dseg-btn[aria-pressed="true"] { background:var(--surface-2); box-shadow:inset 0 0 0 1px var(--line); }
:root[data-theme="clover"] .dash-title { font-weight:800; letter-spacing:-.02em; }
:root[data-theme="clover"] .dash-stats { gap:16px; }
/* Wide Phone page: the phone column is docked, divided from the dashboard by a rule,
   and the dialled number sits on a quiet reserved line. */
@media (min-width: 1000px) {
  :root[data-theme="clover"] body.dash > #app { min-height:100vh; padding-right:28px; border-right:1px solid var(--line); }
  :root[data-theme="clover"] body.dash .topbar { margin-right:-28px; padding-right:44px; }
  :root[data-theme="clover"] body.dash { column-gap:36px; }
  :root[data-theme="clover"] body.dash #dialbox > div:has(#num) { margin:0 0 4px; padding:10px 0 14px; border-bottom:1px solid var(--line); }
}
.theme-pick { grid-template-columns:repeat(5,minmax(0,1fr)); gap:4px; }
.theme-pick button { min-width:0; padding:8px 2px; }
.theme-thumb { width:100%; max-width:56px; height:auto; aspect-ratio:56 / 72; }
.theme-thumb.clover { background:linear-gradient(#1f1f1f 30%,#5bbf8a 30%,#5bbf8a 36%,#282828 36%); }

/* ------------------------------------------------ widget call screens fit */
/* The widget is 443-640px tall on real screens, and every call screen used to scroll there
   (Milos, 2026-09-24). Space scales with the widget height (vh = the iframe), and the main
   action (Decline/Answer, Hang up, Save/Skip) is sticky so it stays on screen even if the
   caller details still overflow. Checked by scripts/diagnostics/audit-widget-viewports.mjs. */
body:not(.wide):has(#callbox:not([hidden])),
body:not(.wide):has(#dispo:not([hidden])) { padding-bottom: 8px; }
body:not(.wide) #stage:has(#callbox:not([hidden])),
body:not(.wide) #stage:has(#callbox:not([hidden]) #answer:not([hidden])),
body:not(.wide) #stage:has(#dispo:not([hidden])) { min-height: 0; padding-top: 8px; }
body:not(.wide) #callbox { gap: clamp(8px, 2vh, 20px); padding-top: clamp(10px, 2.4vh, 20px); padding-bottom: clamp(10px, 2.4vh, 20px); }
body:not(.wide) #callbox .avatar { width: clamp(40px, 8vh, 64px); height: clamp(40px, 8vh, 64px); font-size: clamp(16px, 3.4vh, 22px); }
body:not(.wide) #callbox .peer-block { gap: 2px; }
body:not(.wide) .caller-card { gap: 4px; margin-top: 2px; }
body:not(.wide) #timer { font-size: clamp(22px, 4.4vh, 28px); line-height: 1.15; }
body:not(.wide) .ctl-row { row-gap: clamp(24px, 4.6vh, 34px); }
body:not(.wide) .ctl { width: clamp(44px, 8.4vh, 56px); height: clamp(44px, 8.4vh, 56px); }
body:not(.wide) .ring-ico { width: clamp(42px, 8vh, 52px); height: clamp(42px, 8vh, 52px); }
body:not(.wide) #callbox:has(#answer:not([hidden])) .rbtn { width: clamp(52px, 10vh, 64px); height: clamp(52px, 10vh, 64px); }
body:not(.wide) #callbox:has(#answer[hidden]) #hangup { height: clamp(44px, 8.4vh, 52px); }
body:not(.wide) #callbox .end-row,
body:not(.wide) .dispo-actions { position: sticky; bottom: 0; z-index: 1; background: inherit; }
body:not(.wide) #callbox:has(#answer[hidden]) .end-row { padding-bottom: 2px; }
body:not(.wide) #callbox:has(#answer:not([hidden])) .end-row { padding-bottom: 24px; }
body:not(.wide) #dispo { overflow: clip; gap: clamp(8px, 2.2vh, 16px); padding-top: clamp(12px, 2.8vh, 20px); padding-bottom: clamp(10px, 2.4vh, 20px); }
body:not(.wide) .dispo-grid .tile { min-height: clamp(44px, 9.5vh, 72px); padding-top: 6px; padding-bottom: 6px; }
body:not(.wide) #dispoNote { height: clamp(36px, 7vh, 44px); }
body:not(.wide) .dispo-actions .btn { height: clamp(36px, 7vh, 44px); }
/* In-call keypad: the digits matter more than the caller card and Note/Contact/Text,
   so those step aside while it is open, and the keys shrink to the room left. */
body.dtmf:not(.wide) #callbox .avatar,
body.dtmf:not(.wide) #callerCard,
body.dtmf:not(.wide) #peerContext,
body.dtmf:not(.wide) #peerNum,
body.dtmf:not(.wide) .ctl-row > :nth-child(n+4) { display: none; }
body.dtmf:not(.wide) #stage:has(#callbox:not([hidden])) #dialbox { margin-top: 8px; }
body.dtmf:not(.wide) .pad { row-gap: 2px; }
body.dtmf:not(.wide) .pad button { height: clamp(28px, 7vh, 56px); }
/* Very short widgets (a zoomed or bookmarks-bar laptop): drop the avatar and the outcome icons
   so the pinned action does not sit on top of the controls above it. */
@media (max-height: 500px) {
  body:not(.wide) #callbox .avatar,
  body:not(.wide) .dispo-grid .tile svg { display: none; }
  body:not(.wide) .dispo-grid .tile { min-height: 40px; }
}
/* Answer uses the Call button's ink: on Default's white --call a white icon was invisible. */
:root[data-theme] .rbtn-ok { color: var(--clover-call-ink); }

/* Shared theme polish: layout changes do not alter call ownership or mirroring. */
.topbar .settings-title, .topbar #settingsBack { color:var(--clover-ink); }
#gear:hover, #gear:focus-visible { background:var(--surface-2); color:var(--fg); }
.pad button:hover, body:not(.wide) .pad button:hover { background:var(--hover-bg,var(--surface-2)); }
:root[data-theme="clover"] .topbar { border-bottom:0; }
:root[data-theme="clover"] #dialbox > div:has(#num) { border-bottom:1px solid var(--line); }
@media (min-width:1000px) {
  :root[data-theme="clover"] body.dash #dialbox > div:has(#num) { margin:0 -16px; padding:16px; }
  :root[data-theme="clover"] body.dash .topbar { margin-right:-16px; padding-right:16px; }
}
body:not(.embedded):not(.settings) .topbar { border-radius:16px 16px 0 0; }
body:not(.embedded):not(.settings) #dialbox > div:has(#num) { border-radius:0 0 16px 16px; }
/* Without the number-entry panel, the header is a complete card. */
body:not(.embedded):not(.settings):has(#callbox:not([hidden])) .topbar,
body:not(.embedded):not(.settings):has(#dispo:not([hidden])) .topbar { border-radius:16px; }
.topbar .status, .topbar #presence, .topbar .from-row {
  height:36px; min-height:36px; box-sizing:border-box; align-self:center;
  display:flex; align-items:center; padding:0 8px; line-height:20px;
}
#callerId { height:22px; line-height:20px; }
#callerId:not([data-single]) { appearance:auto; }
.phoneclover-brand img.on-mint { display:none; }
:root[data-theme="dark-mint"] .phoneclover-brand img:not(.on-mint) { display:none; }
:root[data-theme="dark-mint"] .phoneclover-brand img.on-mint { display:block; }
:root[data-theme="clover"] .phoneclover-brand img.on-mint { display:none; }

/* Header actions use the theme's light ink against their dark hover surface. */
:root { --header-hover-ink:var(--fg); }
:root[data-theme="dark-mint"] { --header-hover-ink:var(--clover-head); --hover-bg:#5b5b63; --header-hover-bg:var(--bg); }
#gear:hover, #gear:focus-visible,
.topbar #settingsBack:hover, .topbar #settingsBack:focus-visible {
  background:var(--header-hover-bg,var(--hover-bg,var(--surface-2))); color:var(--header-hover-ink);
}
/* Equal flexible space above/below the keypad + Call group at every widget height. */
  body.embedded:not(.settings)[data-tab="keypad"] #stage:not(:has(#callbox:not([hidden]), #dispo:not([hidden]))) #dialbox:has(#pad:not([hidden])) {
    min-height:calc(100dvh - var(--phone-header-height,88px) - var(--phone-tabs-height,60px)); grid-template-rows:auto 1fr auto auto 1fr;
  }
  body.embedded:not(.settings)[data-tab="keypad"] #stage:not(:has(#callbox:not([hidden]), #dispo:not([hidden]))) #dialbox:has(#pad:not([hidden]))::before,
  body.embedded:not(.settings)[data-tab="keypad"] #stage:not(:has(#callbox:not([hidden]), #dispo:not([hidden]))) #dialbox:has(#pad:not([hidden]))::after { content:""; }
  body.embedded:not(.settings)[data-tab="keypad"] #dialbox::before { grid-row:2; }
  body.embedded:not(.settings)[data-tab="keypad"] #dialbox::after { grid-row:5; }
  body.embedded:not(.settings)[data-tab="keypad"] #dialbox > div:has(#num) { grid-row:1; }
  body.embedded:not(.settings)[data-tab="keypad"] #dialbox #pad { grid-row:3; }
  body.embedded:not(.settings)[data-tab="keypad"] #dialbox #call { grid-row:4; }
/* Transparent native tracks reveal the same header/body boundary as the page. */
html { background:linear-gradient(to bottom,var(--clover-head) 0 var(--header-edge,0px),var(--bg) var(--header-edge,0px) 100%) fixed; scrollbar-color:var(--line-strong) transparent; }
html::-webkit-scrollbar-track { background:transparent; }
/* Chromium paints transparent native tracks over the host canvas, not the
   document background. Style its root track explicitly, at normal width. */
@supports selector(::-webkit-scrollbar) {
  html { scrollbar-color:auto; }
  html::-webkit-scrollbar { width:13px; height:16px; background:linear-gradient(to bottom,var(--clover-head) 0 var(--header-edge,0px),var(--bg) var(--header-edge,0px) 100%); }
  html::-webkit-scrollbar-button { display:none; }
  html::-webkit-scrollbar-track { background:transparent; }
  html::-webkit-scrollbar-track:vertical { margin-top:8px; margin-bottom:8px; }
  html::-webkit-scrollbar-thumb { background:var(--line-strong); border-radius:8px; border:3px solid transparent; background-clip:padding-box; }
  html::-webkit-scrollbar-thumb:vertical { border-left:0; }
}

body.embedded:not(.settings):not(.oncall)[data-tab="keypad"]:not(:has(#dispo:not([hidden]))) { padding-bottom:var(--phone-tabs-height,60px); }
@media (max-height:380px) {
  body.embedded:not(.settings):not(.oncall) .topbar { height:72px; }
  body.embedded:not(.settings):not(.oncall) #dialbox { gap:4px; }
  body.embedded:not(.settings):not(.oncall) #dialbox > div:has(#num) { padding-top:4px; padding-bottom:4px; }
  body.embedded:not(.settings):not(.oncall) #num { height:28px; }
  body.embedded:not(.settings):not(.oncall) .pad button { height:28px; }
  body.embedded:not(.settings):not(.oncall) #call { height:32px; }
}
/* Very short panels still leave room for in-call editing and DTMF. */
@media (max-height:460px) {
  body.embedded.oncall:not(.settings) .topbar { display:flex; height:48px; padding-top:4px; padding-bottom:4px; }
  body.embedded.oncall:not(.settings) .phoneclover-brand,
  body.embedded.oncall:not(.settings) .topbar .from-row { display:none; }
  body.embedded.oncall:not(.settings) #callbox { gap:6px; }
  body.embedded.oncall:not(.settings) #callbox:has(.call-panel:not([hidden])) .peer-block { display:none; }
}
@media (max-height:460px) {
  body.embedded.dtmf #peer { font-size:18px; line-height:22px; }
  body.embedded.dtmf #callbox { padding-top:6px; padding-bottom:6px; }
}

/* Roomier shared header controls; leave breathing room on tabs without number entry. */
.topbar .status, .topbar .status .pill, .topbar #presence { font-size:13px; }
.topbar #callerId { font-size:12px; }
body:not(.settings):not(.oncall) .topbar { height:96px; padding-bottom:14px; }
@media (max-height:380px) {
 body.embedded:not(.settings):not(.oncall) .topbar { height:88px; }
}

body.embedded:not(.settings):not(.oncall) .pad button { height:clamp(28px,calc(16vh - 28px),56px); }

body:not(.settings):not(.oncall):is([data-tab="recents"], [data-tab="contacts"], [data-tab="lists"]) .topbar { height:108px; padding-bottom:24px; }
