/* Mobile-first. 16px base, 48px touch targets. Pair colour with shape/text. */
*, *::before, *::after { box-sizing: border-box; }

:root {
  --bg: #f4f6f8;
  --card: #ffffff;
  --ink: #11141a;
  --ink-soft: #555c66;
  --line: #d8dde3;
  --accent: #006aac; /* CRM theme — rgb(0,106,172) */
  --accent-ink: #ffffff;
  --warn: #b54708;
  --good: #117a3a;
  --pill: #eef2f6;
  --pill-ink: #2c3340;
  --shadow: 0 1px 3px rgba(17, 20, 26, .08), 0 4px 12px rgba(17, 20, 26, .04);
  --radius: 12px;
}

html, body { margin: 0; padding: 0; }
body {
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, system-ui, sans-serif;
  font-size: 16px;
  line-height: 1.45;
  color: var(--ink);
  background: var(--bg);
  -webkit-text-size-adjust: 100%;
}

.wrap {
  max-width: 720px;
  margin: 0 auto;
  padding: 16px;
  padding-bottom: 120px; /* room for sticky search button */
}

header.app {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 8px 0 16px;
}
header.app h1 {
  font-size: 20px;
  margin: 0;
  font-weight: 700;
  letter-spacing: -0.01em;
}
header.app .who {
  font-size: 13px;
  color: var(--ink-soft);
}

/* Quick-nav pills (My Dashboard / My Portal) — small, under the header. */
.pill-row {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 0 0 14px;
}
.nav-pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 7px 14px;
  min-height: 36px;
  border: 1.5px solid var(--accent);
  border-radius: 999px;
  background: var(--card);
  color: var(--accent);
  font-size: 14px;
  font-weight: 600;
  text-decoration: none;
}
.nav-pill:active { background: var(--accent); color: var(--accent-ink); }

/* Floating "↑ Top" — appears on long lists. Sits clear of the sticky
   search bar on mobile; high-contrast so it reads regardless of colour. */
.back-to-top {
  position: fixed;
  right: 16px;
  bottom: calc(84px + env(safe-area-inset-bottom));
  z-index: 20;
  min-height: 44px;
  padding: 10px 16px;
  border-radius: 999px;
  border: 2.5px solid var(--ink);
  background: var(--card);
  color: var(--ink);
  font-size: 15px;
  font-weight: 700;
  cursor: pointer;
  box-shadow: var(--shadow);
}
.back-to-top:active { background: var(--ink); color: #fff; }
@media (min-width: 720px) {
  .back-to-top { bottom: 24px; }
}

/* ── Forms ────────────────────────────────────────────────────────── */
.field {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-bottom: 12px;
}
.field label {
  font-size: 14px;
  font-weight: 600;
  color: var(--ink-soft);
}
.field input {
  width: 100%;
  min-height: 48px;
  padding: 12px 14px;
  border: 1.5px solid var(--line);
  border-radius: var(--radius);
  background: var(--card);
  font-size: 17px;
  font-family: inherit;
  color: var(--ink);
  -webkit-appearance: none;
  appearance: none;
}
.field input:focus {
  outline: 3px solid color-mix(in srgb, var(--accent) 30%, transparent);
  border-color: var(--accent);
}

/* Buttons — 48px minimum, full-width on mobile. */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: 52px;
  padding: 12px 18px;
  border-radius: var(--radius);
  border: 1.5px solid var(--line);
  background: var(--card);
  color: var(--ink);
  font-size: 17px;
  font-weight: 600;
  cursor: pointer;
  font-family: inherit;
}
.btn:active { transform: translateY(1px); }
.btn-primary {
  background: var(--accent);
  color: var(--accent-ink);
  border-color: var(--accent);
}
/* Very subtle alternating row bands on the secondary action buttons.
   Decorative rhythm only — no meaning is carried by colour. Differs by
   lightness as well as hue so the alternation still reads if the faint
   blue is imperceptible. New Enquiry (.btn-primary) is exempt. */
.btn.band-a { background: #f5f6f8; border-color: #dfe3e9; }
.btn.band-b { background: #e9edf3; border-color: #cfd6e0; }
.btn-block { width: 100%; }
.btn-row {
  display: grid;
  grid-template-columns: 1fr;
  gap: 10px;
  margin-top: 8px;
}
@media (min-width: 600px) {
  .btn-row.cols-2 { grid-template-columns: 1fr 1fr; }
}
/* Force a button to span the full row inside a 2-col grid (e.g. New Enquiry). */
.btn-row .span-2 { grid-column: 1 / -1; }
/* Subtle group sub-header inside the button grid (e.g. "Update status").
   A thin rule above + quiet uppercase label does the separating, no box. */
.btn-row .group-head {
  margin: 4px 0 0;
  padding-top: 14px;
  border-top: 1px solid var(--line);
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink-soft);
}

/* Search button — inline above results on every viewport. */
.sticky-search {
  margin-top: 12px;
}

/* ── Cards ────────────────────────────────────────────────────────── */
.cards { display: flex; flex-direction: column; gap: 12px; margin-top: 16px; }

.card {
  background: var(--card);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 16px;
  border: 1.5px solid transparent;
  cursor: pointer;
  position: relative;        /* anchor for the absolute pin-toggle */
  /* When scrollIntoView lands on a card, leave room above it for the
     nav pills + "Contact Search" h1 — so the user keeps that context
     instead of the card slamming flush to the iframe top. 128px clears
     the pill row (~39px) + its margin + h1 + h1's padding with a small
     gap at the very top. */
  scroll-margin-top: 128px;
}
.card:focus-within, .card.is-selected { border-color: var(--accent); }

/* Sticky top block — when a card is open, keep the name / address / Last
   quote+job / "Go To Full Contact" pinned while the action sections scroll
   underneath. Only on an open card (collapsed list rows are untouched). The
   negative margin lets the block span the card's 16px padding so its
   background fully covers scrolling content + the rounded top corners. */
/* Pin the top block — name, address, contact details, Last quote+job (and on
   desktop the Go To Full Contact button) — while the action sections scroll
   underneath. The block's parent is the whole card, so it stays stuck for the
   full scroll (a sticky element only holds while its parent is on screen). */
.card.is-selected .card-sticky {
  position: sticky;
  top: 0;
  z-index: 6;
  background: var(--card);
  margin: -16px -16px 0;
  padding: 16px 16px 8px;
  border-radius: var(--radius) var(--radius) 0 0;
  box-shadow: 0 6px 8px -7px rgba(0, 0, 0, 0.3);
}
.card.is-selected .card-sticky .go-to-contact { margin-top: 10px; margin-bottom: 0; }
/* In focus mode the PINNED badge sits just above this block — don't let the
   negative top margin pull the block up and overlap it. */
body.is-pinned .card.is-selected .card-sticky { margin-top: 0; }
/* Mobile/tablet: hide the Go To Full Contact button (rarely opened from a
   phone). The rest of the header + Last quote/job still pin. */
@media (max-width: 1023px) {
  .card.is-selected .card-sticky .go-to-contact { display: none; }
}
/* Landscape PHONES only (short viewport — excludes desktop monitors, which are
   tall and keep the full sticky header). Vertical space is tight in landscape,
   so pin ONLY the identity lines (name + assignee + address) and let the
   contact details / custom fields / buttons scroll underneath. We un-stick the
   whole .card-sticky block and move the stickiness to the inner .card-pinhead. */
@media (orientation: landscape) and (max-height: 600px) {
  .card.is-selected .card-sticky {
    position: static;
    box-shadow: none;
  }
  .card.is-selected .card-pinhead {
    position: sticky;
    top: 0;
    z-index: 6;
    background: var(--card);
    /* span the card's 16px side padding so scrolling content can't peek past
       the pinned identity block at the edges */
    margin: 0 -16px;
    padding: 4px 16px 6px;
    box-shadow: 0 6px 8px -7px rgba(0, 0, 0, 0.3);
  }
}

/* Pin tickbox / badge sit above the sticky background. */
.card .pin-toggle, .card .pin-badge { z-index: 7; }

/* ── Pin tickbox ──────────────────────────────────────────────────────
   Top-right of an EXPANDED card only — hidden when the card is collapsed
   in the search results, otherwise it'd clutter every row. Tick = focus
   mode (body.is-pinned hides search form + other cards). */
.card .pin-toggle {
  position: absolute;
  top: 12px;
  right: 12px;
  display: none;             /* shown when card is expanded — see below */
  align-items: center;
  gap: 8px;
  padding: 6px 10px;
  border-radius: 8px;
  background: rgba(255,255,255,0.85);
  cursor: pointer;
  user-select: none;
  z-index: 2;
}
.card.is-selected .pin-toggle { display: inline-flex; }
.card .pin-toggle .pin-label {
  font-size: 13px;
  font-weight: 700;
  color: var(--ink);          /* full ink — admin contrast rule applies here too */
  white-space: nowrap;
}
/* Custom square checkbox — same recipe as the admin form's tag checkbox
   so the visual language is consistent. Bypasses native rectangular
   rendering on Chrome/Windows. */
.card .pin-toggle input[type="checkbox"] {
  -webkit-appearance: none;
  appearance: none;
  width: 20px;
  height: 20px;
  min-width: 20px;
  min-height: 20px;
  flex-shrink: 0;
  margin: 0;
  padding: 0;
  /* Darker border + subtle shadow — at-rest visibility for Allan's
     dyslexia + colourblind needs. The default --line (#d8dde3) was almost
     invisible against the white card. #7a828c reads clearly at rest. */
  border: 1.5px solid #7a828c;
  border-radius: 4px;
  background: #fff;
  cursor: pointer;
  position: relative;
  box-sizing: border-box;
  box-shadow: 0 1px 2px rgba(10, 20, 40, 0.12);
  transition: background 0.12s ease, border-color 0.12s ease, box-shadow 0.12s ease;
}
.card .pin-toggle input[type="checkbox"]:hover {
  border-color: var(--ink-soft);
  box-shadow: 0 1px 3px rgba(10, 20, 40, 0.18);
}
.card .pin-toggle input[type="checkbox"]:checked {
  background: var(--accent);
  border-color: var(--accent);
}
.card .pin-toggle input[type="checkbox"]:checked::after {
  content: '';
  position: absolute;
  left: 5px;
  top: 1px;
  width: 6px;
  height: 11px;
  border: solid #fff;
  border-width: 0 2.5px 2.5px 0;
  transform: rotate(45deg);
}
.card .pin-toggle input[type="checkbox"]:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* "Pinned" badge — small accent chip that sits in its OWN row above the
   card header when pinned, so it never collides with the contact name.
   In-flow (not absolute) so the card-head reflows down to make room
   when the badge appears, then back up when it leaves. */
.card .pin-badge {
  display: none;
  width: fit-content;
  padding: 4px 10px;
  margin-bottom: 10px;
  background: var(--accent);
  color: var(--accent-ink);
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  border-radius: 999px;
  box-shadow: 0 1px 2px rgba(10, 20, 40, 0.18);
}
body.is-pinned .card.is-selected .pin-badge { display: inline-flex; }

/* "← Back to search" pill — sits in the existing nav-pill row alongside
   My Dashboard / My Portal. Only shown when pinned, so the row stays
   tidy in normal search mode. Native button styled to match the nav-pill. */
.nav-pill--back {
  display: none;
  cursor: pointer;
  font-family: inherit;
}
body.is-pinned .nav-pill--back { display: inline-flex; }

/* Focus mode — when body.is-pinned, fade out + hide the search form and
   any card that isn't the selected/pinned one. Uses transition-behavior:
   allow-discrete so display:none can be transitioned (modern Chromium /
   Safari 17.4+). Falls back to instant hide on older browsers. */
#searchForm,
#results .card {
  transition: opacity 220ms ease, display 220ms ease allow-discrete;
}
/* Scoped to mobile/tablet: at >=1024px the two-pane layout already isolates
   the selected client in the right pane, so we must NOT hide the form or the
   other cards (they live in the left rail and stay useful). */
@media (max-width: 1023px) {
  body.is-pinned #searchForm,
  body.is-pinned #results .card:not(.is-selected) {
    opacity: 0;
    display: none;
  }
}
/* Also hide the floating "back to top" arrow while pinned — nothing to
   scroll back to, would just look like noise. */
body.is-pinned .back-to-top { display: none !important; }

/* Focus ("fixed") mode must size the card identically at EVERY width. Inside
   the GHL iframe a scrollbar can dip the width just under 1024px; if the focus
   layout were gated only on @media(min-width:1024) (as it is further down) the
   card would collapse to a narrow column the instant that happens. So also
   drive the focus layout off the focused card actually living in the detail
   pane — that condition is width-independent, so the card stays put. The
   mobile case (card never relocated, so #detailPane is empty) is unaffected. */
/* Driven by a JS-set class (syncFocusPane) rather than :has() — :has() didn't
   re-evaluate reliably on DOM changes, so focus width drifted (860 ↔ narrow).
   cf-focus-pane is set whenever the focused card is living in the detail pane,
   at any width, so the card holds a stable 860px. */
body.cf-focus-pane .cf-left { display: none; }
body.cf-focus-pane .cf-grid { grid-template-columns: 1fr; }
/* width:100% is essential: in a grid track, `margin: 0 auto` cancels the
   default stretch, so the pane would otherwise shrink to its content width
   (narrow when sections are closed, wide only when long tag names are shown).
   width:100% makes it fill the column, capped at max-width and centred. */
body.cf-focus-pane #detailPane { width: 100%; max-width: 860px; margin: 0 auto; }
body.cf-focus-pane #detailPane .card { width: 100%; }

.card .card-head { margin-bottom: 4px; }
.card .name {
  font-size: 20px;
  font-weight: 700;
  letter-spacing: -0.01em;
  margin: 0 0 6px;
  word-break: break-word;
}
.card .assignee {
  font-size: 14px;
  font-weight: 600;
  color: var(--ink-soft);
  margin: 0 0 8px;
  display: flex;
  align-items: center;
  gap: 6px;
}
.card .assignee .assignee-dot { color: var(--good); font-size: 10px; }

.card .address {
  font-size: 17.5px;
  color: var(--ink);
  margin: 0 0 8px;
  line-height: 1.4;
  word-break: break-word;
}
.card .address.empty { color: var(--ink-soft); font-style: italic; font-size: 15px; }

/* Phone + email on ONE line. */
.card .contact-row {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 8px;
  margin-top: 2px;
}
.card .contact-link {
  font-size: 15px;
  color: var(--ink-soft);
  text-decoration: none;
  word-break: break-all;
}
.card .contact-link:active { color: var(--accent); }
.card .contact-sep { color: var(--line); font-weight: 700; }

/* "Go To Contact…" — sits below the dates line. Heavy, high-contrast border
   (not faint colour) so it reads clearly for colour-blind eyes; arrow gives a
   shape cue too. */
.card .go-to-contact {
  margin: 4px 0 14px;
  text-decoration: none;
  border: 3px solid var(--ink);
  font-weight: 700;
  color: var(--ink);
}
.card .go-to-contact::after { content: " \2197"; font-weight: 700; }
.card .go-to-contact:active { background: var(--ink); color: #fff; }
.card .meta {
  font-size: 15px;
  color: var(--ink-soft);
  margin: 2px 0;
  word-break: break-word;
}
.card a.meta-link { color: var(--ink-soft); text-decoration: none; }
.card a.meta-link:active { color: var(--accent); }

/* Dates + total: one line, sitting close under the header. */
.card .activity {
  margin-top: 6px;
  padding-top: 8px;
  border-top: 1px solid var(--line);
  font-size: 15px;
}
.card .activity-line {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 6px 18px;
}
.card .activity-line .ai { white-space: nowrap; }
.card .activity-line .ai-lbl { color: var(--ink-soft); font-weight: 600; }
.card .activity-line .ai-val { color: var(--ink); font-weight: 600; }
.card .activity-line .ai-val.empty { color: var(--ink-soft); font-style: italic; font-weight: 400; }
/* legacy stacked rows (loading / fallback) */
.card .activity .row { display: flex; gap: 6px; align-items: baseline; }
.card .activity .row .val.empty { color: var(--ink-soft); font-style: italic; }

.tags-block { margin-top: 14px; }
.tags-head {
  margin: 0 0 6px;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--ink-soft);
}
.tags { display: flex; flex-wrap: wrap; gap: 6px; }
.tag {
  display: inline-block;
  font-size: 12px;
  font-weight: 600;
  padding: 4px 10px;
  border-radius: 999px;
  background: var(--pill);
  color: var(--pill-ink);
}
.tag.dnd { background: #fce8e3; color: #9a2a14; }

/* Expanded / selected card actions. */
.actions { margin-top: 14px; }
.actions h3 {
  margin: 4px 0 10px;
  font-size: 14px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink-soft);
}

.empty, .loading, .error {
  text-align: center;
  padding: 32px 16px;
  color: var(--ink-soft);
  font-size: 15px;
}
.error { color: var(--warn); }

/* ── PIN screen ───────────────────────────────────────────────────── */
.pin-wrap {
  min-height: 100dvh;
  display: flex; align-items: center; justify-content: center;
  padding: 24px;
}
.pin-card {
  width: 100%; max-width: 360px;
  background: var(--card);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 24px;
}
.pin-card h1 { margin: 0 0 4px; font-size: 22px; }
.pin-card p { color: var(--ink-soft); margin: 0 0 20px; font-size: 15px; }
.pin-input {
  width: 100%;
  font-size: 28px;
  letter-spacing: 14px;
  text-align: center;
  padding: 16px;
  min-height: 64px;
  border: 1.5px solid var(--line);
  border-radius: var(--radius);
  font-family: inherit;
  font-weight: 700;
}
.pin-msg { margin-top: 12px; font-size: 14px; min-height: 20px; }
.pin-msg.ok { color: var(--good); }
.pin-msg.err { color: var(--warn); }

/* ── Action group accordions (What next? / Update status / Useful Tools / Quotes & Jobs) ── */
.action-group {
  margin-top: 12px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--card);
  overflow: hidden;
}
.action-group.is-open {
  border-color: var(--accent);
  box-shadow: 0 1px 3px rgba(0, 106, 172, 0.10);
}
.group-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  padding: 14px 16px;
  background: var(--pill);
  border: 0;
  border-bottom: 1px solid var(--line);
  font: inherit;
  font-size: 16px;
  font-weight: 700;
  color: var(--ink);
  text-align: left;
  cursor: pointer;
  min-height: 52px;
}
.action-group:not(.is-open) .group-header { border-bottom-color: transparent; }
.action-group.is-open .group-header {
  background: rgba(0, 106, 172, 0.10);
  border-bottom-color: var(--accent);
}
.group-title { letter-spacing: -0.01em; }
.group-caret {
  font-size: 22px;
  line-height: 1;
  color: var(--accent);
  font-weight: 700;
  margin-left: 12px;
}
.group-body { padding: 12px; }
.group-body[hidden] { display: none; }

/* ── Billing rows (native Estimates / Invoices list) ─────────────────────── */
.billing-slot { display: flex; flex-direction: column; gap: 8px; margin-top: 8px; }
.billing-slot:empty { display: none; }

.billing-panel .notes-panel-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}
.billing-refresh {
  background: #fff;
  border: 1px solid var(--line);
  color: var(--ink);
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  padding: 5px 10px;
  border-radius: 6px;
  cursor: pointer;
  min-height: 32px;
}
.billing-refresh:hover { background: var(--pill); border-color: var(--accent); color: var(--accent); }
.billing-refresh:disabled { opacity: 0.6; cursor: default; }

.billing-row-head {
  /* Tighter 2-column layout — date on left, name + meta on right */
  grid-template-columns: auto 1fr auto;
}
.billing-row-main {
  display: flex;
  flex-direction: column;
  gap: 2px;
  overflow: hidden;
}
.billing-row-name {
  font-weight: 600;
  font-size: 15px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.billing-row-meta {
  font-size: 13px;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.billing-row-body { font-size: 14px; }
.billing-row-body > div { padding: 2px 0; }

.billing-status {
  display: inline-block;
  padding: 1px 8px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 700;
  border: 1px solid currentColor;
  text-transform: uppercase;
  letter-spacing: 0.02em;
}
/* Status colours — ALWAYS paired with text label so colourblind users
   (per user_allan-colourblind memory) never rely on hue alone. */
.status-sent      { color: #b54708; background: #fff5e6; }   /* amber */
.status-pending   { color: #b54708; background: #fff5e6; }
.status-draft     { color: #555c66; background: #eef2f6; }   /* grey */
.status-accepted  { color: #117a3a; background: #e6f7ec; }   /* green */
.status-paid      { color: #117a3a; background: #e6f7ec; }
.status-declined  { color: #9b1c1c; background: #fdecec; }   /* red */
.status-void      { color: #9b1c1c; background: #fdecec; }
.status-overdue   { color: #9b1c1c; background: #fdecec; }
.status-unknown   { color: #555c66; background: #eef2f6; }

.billing-items { margin: 6px 0; }
.billing-items-toggle {
  background: none;
  border: 0;
  font: inherit;
  font-size: 14px;
  color: var(--ink);
  cursor: pointer;
  padding: 6px 0;
  text-align: left;
  min-height: 36px;
}
.billing-items-caret {
  color: var(--accent);
  font-size: 16px;
  font-weight: 700;
  margin-left: 4px;
}
.billing-items-list {
  margin-top: 4px;
  padding: 8px 10px;
  background: var(--pill);
  border-radius: 8px;
  border: 1px solid var(--line);
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.billing-item {
  padding: 6px 0;
  border-bottom: 1px dashed var(--line);
}
.billing-item:last-child { border-bottom: 0; }
.billing-item-head {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  font-size: 14px;
  font-weight: 600;
}
.billing-item-name { color: var(--ink); }
.billing-item-total { font-variant-numeric: tabular-nums; }
.billing-item-meta {
  font-size: 13px;
  color: var(--ink);
  margin-top: 2px;
}
.billing-items-empty { font-size: 13px; color: var(--ink); padding: 4px 0; }

.billing-row-inline-actions {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  flex-wrap: wrap;
  margin-top: 6px;
}
.billing-open-link, .billing-preview-link {
  text-decoration: none;
  font-weight: 700;
  font-size: 14px;
  padding: 8px 14px;
  border-radius: 8px;
  min-height: 36px;
  display: inline-flex;
  align-items: center;
}
.billing-open-link {
  background: var(--accent);
  color: var(--accent-ink);
}
.billing-preview-link {
  background: #fff;
  color: var(--accent);
  border: 1.5px solid var(--accent);
}
.billing-open-link:hover, .billing-preview-link:hover { filter: brightness(1.05); }

.billing-load-more {
  display: flex;
  justify-content: center;
  padding: 6px 0 2px;
}

/* ── Standalone "this contact's estimates" page (estimates.html) ─────────── */
.est-head { margin: 12px 0 16px; }
.est-title { font-size: 22px; font-weight: 800; margin: 0 0 4px; color: var(--ink); }
.est-sub { margin: 0; font-size: 14px; color: var(--ink-soft, #555c66); }
.est-list { display: flex; flex-direction: column; gap: 10px; }
.est-row {
  border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--card); padding: 12px; display: flex; flex-direction: column; gap: 8px;
}
.est-row--done { opacity: 0.85; }
.est-row-head { display: flex; flex-direction: column; gap: 2px; }
.est-items-label { font-size: 13px; color: var(--ink-soft, #555c66); margin-bottom: 4px; }
/* On this page the line items are always visible (no toggle). */
.est-row .billing-items-list { display: block; }
.est-actions { justify-content: flex-start; }
.est-actions .btn { min-height: 44px; }
.est-row-result {
  font-size: 14px; font-weight: 600; padding: 8px 10px; border-radius: 8px;
}
.est-row-result--ok  { background: #e6f7ec; color: #117a3a; }
.est-row-result--err { background: #fdecec; color: #8a1f1f; }
.est-result-link { font-weight: 700; margin-left: 6px; }
.est-view-invoice { margin-left: 6px; background: none; border: 0; padding: 0; color: #0f7a3a; font: inherit; font-weight: 800; text-decoration: underline; cursor: pointer; }

/* Accept-then-invoice full-screen flow: customer preview (with its Accept button)
   on top, a Create Invoice action below. */
.est-accept { position: fixed; inset: 0; z-index: 10000; display: flex; flex-direction: column; background: #0f172a; }
.est-accept__head { padding: 10px 12px; color: #fff; }
.est-accept__title { font-weight: 800; font-size: 16px; }
.est-accept__step { font-size: 12px; color: #cbd5e1; margin-top: 2px; }
.est-accept__frame { flex: 1 1 auto; width: 100%; border: 0; background: #fff; min-height: 0; }
.est-accept__hint { padding: 6px 12px; font-size: 12px; color: #cbd5e1; }
.est-accept__hint a { color: #93c5fd; }
.est-accept__msg { padding: 8px 12px; font-size: 13px; }
.est-accept__msg--err { background: #fdecec; color: #8a1f1f; }
.est-accept__foot {
  display: flex; gap: 8px; justify-content: flex-end;
  padding: 10px calc(10px + env(safe-area-inset-right)) calc(10px + env(safe-area-inset-bottom)) 10px;
  background: #0f172a;
}
.est-load-more { display: flex; justify-content: center; padding: 8px 0; }

/* In-app confirm modal for the convert action. */
.est-modal { position: fixed; inset: 0; z-index: 9999; display: flex; align-items: center; justify-content: center; }
.est-modal__backdrop { position: absolute; inset: 0; background: rgba(0,0,0,0.45); }
.est-modal__dialog {
  position: relative; background: var(--card, #fff); width: min(100%, 420px);
  margin: 16px; border-radius: 14px; padding: 18px; box-shadow: 0 10px 40px rgba(0,0,0,0.25);
}
.est-modal__title { font-size: 18px; font-weight: 800; margin: 0 0 8px; color: var(--ink); }
.est-modal__body { font-size: 15px; color: var(--ink); margin-bottom: 14px; }
.est-modal__body p { margin: 0; }
.est-modal__body .est-warn { margin-top: 10px; padding: 8px 10px; border-radius: 8px; background: #fff5e6; color: #7a4a00; font-size: 13px; }
.est-modal__actions { display: flex; justify-content: flex-end; gap: 8px; }

/* ── Quotes & Jobs notes (per-card slot below the action buttons) ──────── */
.notes-slot { display: flex; flex-direction: column; gap: 8px; margin-top: 8px; }
.notes-slot:empty { display: none; }

.notes-panel {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--card);
  overflow: hidden;
}
.notes-panel-head {
  padding: 8px 12px;
  font-weight: 700;
  font-size: 14px;
  color: var(--ink);
  background: var(--pill);
  border-bottom: 1px solid var(--line);
}
.notes-panel-body { padding: 4px 0; }
.notes-loading, .notes-empty, .notes-error {
  padding: 12px;
  font-size: 14px;
  color: var(--ink);
}
.notes-error { color: var(--warn); }
.notes-retry {
  margin-left: 8px;
  background: none;
  border: 1px solid var(--warn);
  color: var(--warn);
  padding: 2px 8px;
  border-radius: 6px;
  font-size: 13px;
  cursor: pointer;
}

.notes-panel-body { padding: 8px; display: flex; flex-direction: column; gap: 6px; }
.notes-row {
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--card);
  overflow: hidden;
}
.notes-row.band-a { background: var(--card); }
.notes-row.band-b { background: #f7fafc; }
.notes-row.is-open {
  border-color: var(--accent);
  box-shadow: 0 1px 4px rgba(0, 106, 172, 0.12);
}
.notes-row-head {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: 12px;
  width: 100%;
  padding: 12px 14px;
  background: var(--pill);
  border: 0;
  border-bottom: 1px solid var(--line);
  font: inherit;
  color: var(--ink);
  text-align: left;
  cursor: pointer;
  min-height: 48px;
}
.notes-row.is-open .notes-row-head {
  background: rgba(0, 106, 172, 0.10);
  border-bottom-color: var(--accent);
}
.notes-row-date {
  font-variant-numeric: tabular-nums;
  font-size: 13px;
  font-weight: 700;
  color: var(--ink);
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 3px 8px;
}
.notes-row-preview {
  font-size: 15px;
  font-weight: 500;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.notes-row-caret {
  font-size: 22px;
  line-height: 1;
  color: var(--accent);
  width: 24px;
  text-align: center;
  font-weight: 700;
}
.notes-row.is-open .notes-row-caret { color: var(--accent); }
.notes-row-body {
  border-top: 1px dashed var(--line);
  padding: 8px 12px 10px;
}
.notes-row-text {
  margin: 0 0 6px;
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, system-ui, sans-serif;
  font-size: 14px;
  white-space: pre-wrap;
  word-break: break-word;
  color: var(--ink);
}
.notes-row-inline-actions {
  display: flex;
  justify-content: flex-end;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 8px;
}

.notes-row-edit, .notes-row-tojob, .notes-row-delete {
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  padding: 6px 12px;
  border-radius: 6px;
  cursor: pointer;
  min-height: 36px;
  background: #fff;
}
.notes-row-edit { border: 1px solid var(--line, #d8dde4); color: var(--ink, #11141a); }
.notes-row-tojob { border: 1px solid var(--accent, #006AAC); color: var(--accent, #006AAC); }
.notes-row-tojob:hover { background: var(--accent, #006AAC); color: #fff; }
.notes-row-delete { border: 1px solid var(--warn); color: var(--warn); }
.notes-row-delete:hover { background: var(--warn); color: #fff; }
.notes-row-delete:disabled { opacity: 0.6; cursor: default; }

/* Inline note editor */
.note-edit { margin-bottom: 8px; display: grid; gap: 8px; }
.note-edit-text {
  width: 100%;
  font: inherit;
  font-size: 15px;
  padding: 9px 10px;
  border: 1.5px solid var(--line, #d8dde4);
  border-radius: 6px;
  min-height: 120px;
  background: var(--card, #fff);
  color: var(--ink, #11141a);
}
.note-edit-actions { display: flex; gap: 8px; }
.note-edit-save { background: var(--accent, #006AAC); color: #fff; border: 1.5px solid var(--accent, #006AAC); }
.note-edit-cancel { background: var(--card, #fff); border: 1.5px solid var(--ink, #11141a); color: var(--ink, #11141a); }
.note-edit-msg { font-size: 13px; min-height: 1em; }
.photos-upload-msg { font-size: 13px; line-height: 1.4; margin: 6px 0; min-height: 1em; }

.notes-collapse-bar {
  display: flex;
  justify-content: flex-end;
  padding: 4px 0;
}
.btn-link {
  background: none;
  border: 0;
  color: var(--accent);
  font: inherit;
  font-weight: 600;
  text-decoration: underline;
  cursor: pointer;
  padding: 8px 12px;
  min-height: 44px;
}

/* Add-note inline form */
.note-add {
  border: 1.5px solid var(--accent);
  border-radius: var(--radius);
  background: var(--card);
  padding: 12px;
}
.note-add-head {
  font-weight: 700;
  font-size: 14px;
  margin-bottom: 8px;
}
.note-add-preview {
  font-size: 13px;
  color: var(--ink);
  background: var(--pill);
  border-radius: 8px;
  padding: 8px 10px;
  margin-bottom: 8px;
  line-height: 1.4;
}
.note-add-preview-line { font-variant-numeric: tabular-nums; }
.note-add-text {
  width: 100%;
  min-height: 7rem;
  resize: vertical;
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 10px;
  font: inherit;
  color: var(--ink);
  background: #fff;
}
.note-add-text:focus { outline: 2px solid var(--accent); outline-offset: 1px; }
/* Date picker row on the add-note panel — label + native date input, plus the
   "Visit?" tick box pushed to the end of the line. */
.note-add-daterow { display: flex; align-items: center; gap: 10px; margin: 8px 0 2px; }
.note-add-datefield { display: inline-flex; align-items: center; gap: 10px; }
.note-add-datelabel { font-size: 13px; font-weight: 600; color: var(--ink, #11141a); }
/* "Visit?" sits at the end of the date row; ticking reveals Time + Arrival. */
.note-visit { display: inline-flex; align-items: center; gap: 6px; margin-left: auto; font-size: 13px; font-weight: 600; color: var(--ink, #11141a); cursor: pointer; }
.note-visit input { width: 18px; height: 18px; flex: 0 0 auto; cursor: pointer; }
.note-add-date {
  font: inherit;
  font-size: 16px;            /* 16px+ stops iOS zooming in on focus */
  padding: 7px 10px;
  border: 1px solid var(--line, #d7dbe2);
  border-radius: 8px;
  background: #fff;
  color: var(--ink, #11141a);
}
.note-add-date:focus { outline: 2px solid var(--accent); outline-offset: 1px; }
/* Job time row + arrival Fixed/Flexible toggle on the add-note panel. */
.note-add-timerow, .note-add-arrivalrow { display: flex; align-items: center; gap: 10px; margin: 8px 0 2px; flex-wrap: wrap; }
.note-add-to { color: var(--ink-soft, #5a6472); font-size: 13px; }
/* Time = Hour + Minute selects (the minute list is only 00/15/30/45, so iOS
   physically can't land on an off-step minute — unlike <input type=time>,
   which ignores `step` on the native wheel). */
.note-time { display: inline-flex; align-items: center; gap: 2px; min-width: 0; }
.note-time-colon { color: var(--ink, #11141a); font-weight: 700; }
.note-time select {
  font: inherit; font-size: 16px; /* 16px stops iOS zoom-on-focus */
  padding: 7px 8px; border: 1px solid var(--line, #d7dbe2); border-radius: 8px;
  background: #fff; color: var(--ink, #11141a);
  min-width: 0;
  /* Drop the native dropdown chevron — it eats ~18px per box, and the wheel
     that opens on tap makes the affordance obvious. Lets all four fit one row. */
  -webkit-appearance: none; -moz-appearance: none; appearance: none;
  text-align: center; text-align-last: center;
}
.note-time select:focus { outline: 2px solid var(--accent); outline-offset: 1px; }
/* Keep the whole start–end range on ONE line on phones: no wrap + tight gaps. */
.note-add-timerow { flex-wrap: nowrap; gap: 6px; }
.note-add-timerow .note-add-datelabel { flex: 0 0 auto; }
.note-add-timerow .note-add-to { flex: 0 0 auto; }
.note-arr-toggle { display: inline-flex; border: 1px solid var(--line, #d7dbe2); border-radius: 8px; overflow: hidden; }
.note-arr-btn {
  font: inherit; font-size: 14px; font-weight: 600; padding: 7px 18px;
  background: #fff; color: var(--ink-soft, #5a6472); border: 0; border-left: 1px solid var(--line, #d7dbe2); cursor: pointer;
}
.note-arr-btn:first-child { border-left: 0; }
.note-arr-btn.is-active { background: var(--accent, #006AAC); color: #fff; }
/* When "Visit?" is unticked, grey out + lock the Time + Arrival rows. The inputs
   also carry `disabled` (set in JS), which keeps them out of tab order. */
.note-add.no-visit .note-add-timerow,
.note-add.no-visit .note-add-arrivalrow,
.note-edit.no-visit .note-add-timerow,
.note-edit.no-visit .note-add-arrivalrow { opacity: .45; pointer-events: none; }
.note-add-actions {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  margin-top: 8px;
}
.note-add-msg { font-size: 13px; min-height: 18px; margin-top: 6px; }

/* "Open" state on the View / Add buttons — subtle ring so user sees what's open */
.btn[data-act^="notes-"].is-open {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
}

/* ── Embedded funnel form modal ─────────────────────────────────────────── */
.form-embed-modal {
  position: fixed;
  inset: 0;
  z-index: 9999;
  display: flex;
  align-items: center;
  justify-content: center;
}
.form-embed-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(17, 20, 26, 0.55);
}
.form-embed-dialog {
  position: relative;
  z-index: 1;
  width: min(100%, 720px);
  height: min(100%, 92vh);
  margin: 16px;
  background: var(--card);
  border-radius: var(--radius);
  box-shadow: 0 10px 40px rgba(0, 0, 0, 0.3);
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

/* Wide popups (e.g. the GHL email editor — options left, live preview right).
   Only on big screens, so it never overrides the phone full-screen rule below. */
@media (min-width: 1024px) {
  .form-embed-dialog.is-wide {
    width: min(96vw, 1320px);
    height: min(100%, 94vh);
  }
}
.form-embed-head {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 14px;
  background: var(--pill);
  border-bottom: 1px solid var(--line);
}
.form-embed-title {
  flex: 1;
  font-weight: 700;
  font-size: 15px;
  color: var(--ink);
}
.form-embed-popout {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  font-size: 18px;
  font-weight: 700;
  color: var(--accent);
  text-decoration: none;
  border-radius: 6px;
}
.form-embed-popout:hover { background: rgba(0, 106, 172, 0.10); }
.form-embed-close {
  background: none;
  border: 0;
  font: inherit;
  font-size: 20px;
  color: var(--ink);
  cursor: pointer;
  width: 36px;
  height: 36px;
  border-radius: 6px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.form-embed-close:hover { background: rgba(255, 0, 0, 0.06); color: var(--warn); }
.form-embed-submitted-strip {
  background: #117a3a;
  color: #fff;
  font-weight: 700;
  font-size: 14px;
  padding: 8px 14px;
  text-align: center;
  border-bottom: 1px solid rgba(0, 0, 0, 0.1);
}
.form-embed-iframe {
  flex: 1;
  width: 100%;
  border: 0;
  display: block;
  background: #fff;
}
@media (max-width: 480px) {
  .form-embed-dialog { margin: 0; height: 100vh; width: 100vw; border-radius: 0; }
}

/* ── Mobile-only popup notice ─────────────────────────────────────────────
   Reuses .form-embed-modal for the fixed-position centred overlay (it
   handles backdrop + flex centring). The dialog itself is a smaller, more
   alert-styled box than the full embed dialog. */
.mobile-notice-overlay .mobile-notice-dialog {
  position: relative;
  z-index: 1;
  width: min(100%, 440px);
  margin: 16px;
  background: var(--card, #fff);
  border-radius: var(--radius, 8px);
  box-shadow: 0 10px 40px rgba(0, 0, 0, 0.3);
  padding: 22px 24px 20px;
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.mobile-notice-title {
  font-size: 18px;
  font-weight: 700;
  margin: 0;
  color: var(--ink, #11141a);
}
.mobile-notice-body {
  font-size: 15px;
  line-height: 1.5;
  color: var(--ink, #11141a);
  margin: 0;
}
.mobile-notice-actions {
  display: flex;
  gap: 10px;
  justify-content: flex-end;
  margin-top: 4px;
}
.mobile-notice-actions .btn {
  padding: 10px 18px;
  font-size: 15px;
  font-weight: 600;
  min-height: 44px;
}
.mobile-notice-ok {
  background: var(--card, #fff);
  border: 1.5px solid var(--ink, #11141a);
  color: var(--ink, #11141a);
}
.mobile-notice-open {
  background: var(--ink, #11141a);
  color: #fff;
  border: 1.5px solid var(--ink, #11141a);
}

/* ── Loud action-failure popup ────────────────────────────────────────────
   Same scaffolding as the mobile notice, but unmissable: a warn-coloured
   accent bar + title so a misconfigured button can never silently "flash and
   do nothing" again. Help text is full --ink (smaller, not lighter) so it
   stays readable. */
.action-error-overlay .mobile-notice-dialog {
  border-top: 5px solid var(--warn, #c0392b);
}
.action-error-title { color: var(--warn, #c0392b); }
.action-error-help {
  font-size: 13px;
  line-height: 1.45;
  color: var(--ink, #11141a);
  margin: 0;
}
.action-error-ok {
  background: var(--ink, #11141a);
  color: #fff;
  border: 1.5px solid var(--ink, #11141a);
}

/* ── Teased (locked) features + upgrade modal ──────────────────────────────
   A locked button stays visible but dimmed with a 🔒; tapping it opens the
   upgrade modal instead of running its real action. */
/* Teased ELEMENT buttons go clearly lighter/grey so they read as "not on your
   plan". The section header you tap to GET to them is deliberately excluded
   (:not(.group-header)) — it stays normal so people click in and explore. */
.btn.is-locked:not(.group-header),
button.is-locked:not(.group-header) {
  opacity: 0.45;
  filter: grayscale(100%);
  cursor: pointer;           /* still tappable — it opens the upsell */
}
.is-locked .lock-ico { font-weight: 700; }
.upgrade-overlay .mobile-notice-dialog { border-top: 5px solid var(--accent, #006AAC); }
.upgrade-title { color: var(--accent, #006AAC); }
.upgrade-help {
  font-size: 13px;
  line-height: 1.45;
  color: var(--ink, #11141a);
  margin: 0;
}
.upgrade-book {
  background: var(--accent, #006AAC);
  color: #fff;
  border: 1.5px solid var(--accent, #006AAC);
  text-decoration: none;
  /* Stack: calendar icon on top, label centred below it, with breathing room. */
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 14px 16px;
  text-align: center;
  line-height: 1.35;
}
.upgrade-book .ub-ico { flex: 0 0 auto; font-size: 22px; line-height: 1; }
.upgrade-book .ub-txt { text-align: center; }
/* "Try it free" — the primary call to action in the upgrade modal. */
.upgrade-trial {
  background: var(--good, #1a7f4b);
  color: #fff;
  border: none;
  font-weight: 800;
}
.upgrade-trial:hover { filter: brightness(1.05); }
.upgrade-trial:disabled { opacity: .7; }

/* Delete Contact — low-emphasis red outline, set apart at the very bottom of the
   card so it's deliberate, never sitting next to the everyday buttons. */
.delete-contact {
  margin-top: 18px;
  background: #fff;
  color: var(--warn, #c0392b);
  border: 1.5px solid var(--warn, #c0392b);
  font-weight: 600;
}
.delete-contact:hover { background: #fdecea; }
.delete-contact:disabled { opacity: .6; }
.upgrade-close {
  background: var(--card, #fff);
  border: 1.5px solid var(--ink, #11141a);
  color: var(--ink, #11141a);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  text-align: center;
}

/* ── Read-only (lapsed subscription) banner ─────────────────────────────── */
.readonly-banner {
  position: sticky;
  top: 0;
  z-index: 60;
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  padding: 10px 14px;
  background: #8a1c1c;            /* deep red — clearly "attention", not error-spam */
  color: #fff;
  font-weight: 600;
  line-height: 1.35;
  box-shadow: 0 2px 6px rgba(0,0,0,.18);
}
.readonly-banner__msg { flex: 1 1 240px; }
.readonly-banner__btn {
  flex: 0 0 auto;
  background: #fff;
  color: #8a1c1c;
  border: none;
  font-weight: 800;
  padding: 8px 18px;
  text-decoration: none;
}
.readonly-banner__btn:hover { background: #ffe9e9; }

/* ── Trial countdown chip ───────────────────────────────────────────────── */
.trial-chip {
  position: fixed;
  right: 12px;
  bottom: 12px;
  z-index: 55;
  background: var(--accent, #006AAC);
  color: #fff;
  font-weight: 700;
  font-size: 13px;
  padding: 7px 13px;
  border-radius: 999px;
  box-shadow: 0 2px 8px rgba(0,0,0,.2);
}
.trial-chip--soon { background: #b5651d; }  /* amber/brown when ≤7 days */
/* Inline demo video in the upgrade popup (16:9, responsive). */
.upgrade-video {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9;
  border-radius: 8px;
  overflow: hidden;
  background: #000;
}
.upgrade-video iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }
.upgrade-watch {
  display: inline-block;
  font-weight: 700;
  color: var(--accent, #006AAC);
  text-decoration: none;
  padding: 4px 0;
}

/* ── Card "all details" block (Basic tier = app is the only interface) ─────── */
.cd-toggle {
  margin-top: 8px;
  background: none;
  border: 0;
  padding: 4px 0;
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  color: var(--accent, #006AAC);
  cursor: pointer;
}
.contact-details {
  margin-top: 8px;
  border-top: 1px solid var(--line, #e6e9ee);
  padding-top: 8px;
  display: grid;
  gap: 10px;
}
/* Rows live in a nested wrapper (so "Show all fields" can swap them) — keep the
   same row spacing as the grid would have given them directly. */
.contact-details [data-cd-rows] { display: grid; gap: 10px; }
/* "Show all fields" one-off reveal — subtler than the main details toggle. */
.cd-allfields {
  margin-top: 4px;
  background: none;
  border: 0;
  padding: 4px 0;
  font: inherit;
  font-size: 12.5px;
  color: var(--ink-soft, #5a6472);
  text-decoration: underline;
  cursor: pointer;
}
/* The [hidden] attribute must beat `display: grid` for the toggle to work. */
.contact-details[hidden] { display: none; }
/* Stack: field name on top, value on its own line below, right-aligned —
   long values no longer get crushed against a right-aligned column. */
.cd-row {
  display: block;
  font-size: 13px;
  line-height: 1.4;
}
.cd-label { display: block; color: var(--ink-soft, #5a6472); font-weight: 600; }
.cd-val { display: block; color: var(--ink, #11141a); text-align: left; word-break: break-word; }
/* Unreliable values (e.g. Total Spend — we can't total what we don't capture). */
.cd-row--muted .cd-label,
.cd-row--muted .cd-val { color: var(--ink-soft, #9aa3af); opacity: 0.65; }
/* Bold the postcode in the header address (key field for sat-nav). */
.address strong, .addr-postcode { font-weight: 700; }
/* Coaching hint above the note box (set Last Quote/Job date from line 1). */
.note-add-hint { font-size: 12px; color: var(--ink-soft, #5a6472); margin: 6px 0; line-height: 1.4; }
.note-add-hint strong { color: var(--ink, #11141a); }

/* ── Inline contact edit (Basic tier writes back to GHL) ──────────────────── */
.edit-contact {
  margin-top: 8px;
  background: none;
  border: 0;
  padding: 4px 0;
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  color: var(--accent, #006AAC);
  cursor: pointer;
}
.edit-form {
  margin-top: 10px;
  border-top: 1px solid var(--line, #e6e9ee);
  padding-top: 10px;
  display: grid;
  gap: 8px;
}
.ef-field { display: grid; gap: 3px; font-size: 12px; }
.ef-field > span { font-weight: 600; color: var(--ink-soft, #5a6472); }
.ef-field input {
  font: inherit;
  font-size: 15px;            /* 16px-ish avoids iOS zoom-on-focus */
  padding: 9px 10px;
  border: 1.5px solid var(--line, #d8dde4);
  border-radius: 6px;
  background: var(--card, #fff);
  color: var(--ink, #11141a);
  min-height: 44px;
}
.ef-actions { display: flex; gap: 8px; margin-top: 2px; }
.ef-save {
  background: var(--accent, #006AAC);
  color: #fff;
  border: 1.5px solid var(--accent, #006AAC);
}
.ef-cancel {
  background: var(--card, #fff);
  border: 1.5px solid var(--ink, #11141a);
  color: var(--ink, #11141a);
}
.ef-msg { font-size: 13px; min-height: 1em; }

/* ── Demo toggle (snapshot/agency only — flip Starter ↔ Full for prospects) ──
   Small, in-flow at the very top so it scrolls away and never covers the card. */
.demo-toggle {
  display: flex;
  width: fit-content;
  align-items: center;
  gap: 6px;
  margin: 0 auto 8px;
  padding: 3px 4px 3px 10px;
  background: var(--ink, #11141a);
  color: #fff;
  border-radius: 999px;
}
.demo-toggle__lbl {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  opacity: 0.8;
}
.demo-toggle__btn {
  font: inherit;
  font-size: 11px;
  font-weight: 700;
  border: 0;
  border-radius: 999px;
  padding: 4px 11px;
  min-height: 26px;
  cursor: pointer;
  background: #fff;
  color: var(--ink, #11141a);
}
.demo-toggle.is-basic .demo-toggle__btn { background: var(--accent, #006AAC); color: #fff; }

/* ── Appointments panel (in Quotes + Jobs sections) ─────────────────────
   Reuses the .notes-panel shell; adds row-level visuals tuned for the
   appointments rhythm — date pill + title + status badge. */
.appointments-panel .appt-section + .appt-section { margin-top: 10px; }
.appointments-panel .appt-section-head {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink-soft, #555c66);
  padding: 6px 4px;
}
.appt-row {
  border: 1px solid var(--border, #d8dde4);
  border-radius: 6px;
  padding: 10px 12px;
  margin: 6px 0;
  background: #fff;
  cursor: pointer;
}
.appt-row:hover { border-color: #b6bdc7; }
.appt-row.is-expanded { background: #fafbfd; }
.appt-row-head {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}
.appt-pill {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 12.5px;
  background: #eef2f7;
  padding: 3px 8px;
  border-radius: 4px;
  white-space: nowrap;
}
.appt-title {
  font-weight: 600;
  font-size: 14px;
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.appt-status {
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  padding: 3px 8px;
  border-radius: 999px;
  background: #eef2f7;
  color: var(--ink-soft, #555c66);
  white-space: nowrap;
}
.appt-status-confirmed { background: #e8f6ee; color: #146c2e; }
.appt-status-showed    { background: #e8f6ee; color: #146c2e; }
.appt-status-cancelled { background: #fdecec; color: #8a1f1f; }
.appt-status-noshow    { background: #fdecec; color: #8a1f1f; }
.appt-status-invalid   { background: #fdecec; color: #8a1f1f; }
.appt-row-sub {
  margin-top: 6px;
  font-size: 13px;
  color: var(--ink-soft, #555c66);
}
/* Diary "extras" chips on the card's appointment rows — mirrors the mobile
   Appointments page. Colourblind-safe: every chip pairs an icon/text with its
   colour, never colour alone. */
.appt-row-chips { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
.appt-row-chips > span {
  padding: 2px 8px; border-radius: 999px; font-size: 11px; font-weight: 700;
  line-height: 1.7; white-space: nowrap;
}
.appt-row__jobstatus { background: #eef2f7; color: #334155; }
.appt-row__jobstatus--provisional { background: #fef9c3; color: #854d0e; }
.appt-row__jobstatus--booked      { background: #dbeafe; color: #1e40af; }
.appt-row__jobstatus--in-progress { background: #ede9fe; color: #5b21b6; }
.appt-row__jobstatus--completed   { background: #dcfce7; color: #166534; }
.appt-row__jobstatus--invoiced    { background: #cffafe; color: #155e75; }
.appt-row__style  { background: #f1f5f9; color: #334155; }
.appt-row__marker { background: #f8fafc; color: #334155; border-radius: 4px; }
.appt-row__cal    { font-weight: 600; }
.appt-details {
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px solid var(--border, #d8dde4);
  font-size: 13.5px;
}
.appt-dl-row {
  display: grid;
  grid-template-columns: 110px 1fr;
  gap: 10px;
  padding: 4px 0;
}
.appt-dl-k { font-weight: 600; color: var(--ink-soft, #555c66); }
.appt-dl-v { word-break: break-word; }
.appt-actions { margin-top: 10px; display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
/* Primary action on an appointment — jump to it on the GBU Scheduler diary. */
.appt-goto-diary {
  display: inline-block;
  font-size: 13px;
  font-weight: 600;
  padding: 6px 12px;
  border: 1.5px solid #006aac;
  border-radius: 4px;
  background: #006aac;
  color: #fff;
  cursor: pointer;
}
.appt-goto-diary:hover { background: #005a92; border-color: #005a92; }
.appt-open-ghl {
  display: inline-block;
  font-size: 13px;
  font-weight: 600;
  padding: 6px 12px;
  border: 1.5px solid var(--ink, #11141a);
  border-radius: 4px;
  color: var(--ink, #11141a);
  text-decoration: none;
}
.appt-open-ghl:hover { background: #f5f5f5; }
.appt-refresh {
  font-size: 13px;
  padding: 4px 10px;
  border-radius: 4px;
  border: 1px solid var(--border, #d8dde4);
  background: #fff;
  cursor: pointer;
}
.appt-retry {
  font-size: 13px;
  padding: 4px 10px;
  border-radius: 4px;
  border: 1px solid var(--border, #d8dde4);
  background: #fff;
  cursor: pointer;
  margin-left: 4px;
}

/* ── Tasks panel (Useful Tools section) ─────────────────────────────────
   Reuses .notes-panel scaffolding. Full inline CRUD: list, click-to-edit,
   delete, quick complete-toggle via the checkbox. */
.tasks-panel { padding-top: 4px; }
.tasks-panel .notes-panel-head {
  gap: 12px;
  align-items: center;
  padding: 6px 4px 10px;
  flex-wrap: wrap;
}
.tasks-panel .notes-panel-head > :first-child { margin-right: auto; } /* push buttons to the right */
.task-add-btn {
  font-size: 13px;
  padding: 4px 12px;
  border-radius: 4px;
  border: 1.5px solid var(--ink, #11141a);
  background: var(--ink, #11141a);
  color: #fff;
  cursor: pointer;
  font-weight: 600;
}
.task-add-btn:hover { opacity: 0.9; }
.task-add-slot { padding: 10px 4px 4px; }

.task-row {
  border: 1px solid var(--border, #d8dde4);
  border-radius: 8px;
  padding: 12px 14px;
  margin: 10px 0;
  background: #fff;
}
.task-row.is-complete { background: #f8f9fb; }
.task-row.is-complete .task-title { text-decoration: line-through; color: var(--ink-soft, #555c66); }
.task-row.is-expanded { background: #fafbfd; }
.task-row-head {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  cursor: pointer;
  padding: 2px 0;
}
.task-check-wrap {
  display: inline-flex;
  align-items: center;
  cursor: pointer;
}
.task-check {
  width: 20px;
  height: 20px;
  cursor: pointer;
}
.task-title {
  font-weight: 600;
  font-size: 14px;
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.task-due {
  font-size: 12px;
  font-weight: 600;
  padding: 3px 8px;
  border-radius: 4px;
  background: #eef2f7;
  color: var(--ink-soft, #555c66);
  white-space: nowrap;
}
.task-due.is-overdue { background: #fdecec; color: #8a1f1f; }
.task-assignee {
  font-size: 12.5px;
  color: var(--ink-soft, #555c66);
  white-space: nowrap;
}

.task-details {
  margin-top: 14px;
  padding-top: 14px;
  border-top: 1px solid var(--border, #d8dde4);
}
.task-form { display: flex; flex-direction: column; gap: 14px; }
.task-field { display: flex; flex-direction: column; gap: 6px; font-size: 13px; }
.task-field > span { font-weight: 600; color: var(--ink-soft, #555c66); font-size: 12.5px; }
.task-input {
  font-size: 14px;
  padding: 8px 10px;
  border: 1.5px solid var(--border, #d8dde4);
  border-radius: 5px;
  box-sizing: border-box;
  font-family: inherit;
  background: #fff;
}
.task-input:focus { border-color: var(--ink, #11141a); outline: none; }
.task-row-fields { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
@media (max-width: 600px) {
  .task-row-fields { grid-template-columns: 1fr; }
}
.task-form-actions {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
  align-items: center;
  margin-top: 8px;
  padding-top: 4px;
}
.task-form-actions .btn { padding: 8px 16px; font-size: 14px; min-height: 40px; }
.task-save-btn { background: var(--ink, #11141a); color: #fff; border-color: var(--ink, #11141a); }
.task-cancel-btn { background: #fff; }
.task-delete-btn { background: #fff; border-color: #a44; color: #a44; }
.task-open-ghl {
  font-size: 13px;
  font-weight: 600;
  padding: 6px 12px;
  border: 1.5px solid var(--ink, #11141a);
  border-radius: 4px;
  color: var(--ink, #11141a);
  text-decoration: none;
}
.task-form-msg { font-size: 13px; margin-left: auto; color: var(--ink-soft, #555c66); }
.task-form-msg.err { color: #8a1f1f; font-weight: 600; }
.task-retry {
  font-size: 13px; padding: 4px 10px; border-radius: 4px;
  border: 1px solid var(--border, #d8dde4); background: #fff; cursor: pointer; margin-left: 4px;
}

/* ── Opportunities section ──────────────────────────────────────────────
   Dedicated accordion. Auto-loads on first open. List of opps, each row
   click-to-expand into ETAS-style action cards (Move to Stage, Close).
   Pipelines are loaded once and used for the cascading dropdown. */
.opp-count-header { font-weight: 600; color: var(--ink-soft, #555c66); font-size: 14px; margin-left: 4px; }
.opp-section-actions {
  display: flex;
  gap: 8px;
  margin-bottom: 10px;
}
.opp-section-actions .opp-add-btn { flex: 1; }
.opp-refresh-btn {
  font-size: 13px;
  padding: 6px 12px;
  border-radius: 4px;
  border: 1px solid var(--border, #d8dde4);
  background: #fff;
  cursor: pointer;
}
.opp-add-slot { padding: 6px 0 10px; }

.opp-row {
  border: 1px solid var(--border, #d8dde4);
  border-radius: 6px;
  padding: 10px 12px;
  margin: 6px 0;
  background: #fff;
  cursor: pointer;
}
.opp-row:hover { border-color: #b6bdc7; }
.opp-row.is-expanded { background: #fafbfd; }
.opp-row-head {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}
.opp-status {
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  padding: 3px 8px;
  border-radius: 999px;
  background: #eef2f7;
  color: var(--ink-soft, #555c66);
  white-space: nowrap;
}
.opp-status-open      { background: #e6eff9; color: #1b4a85; }
.opp-status-won       { background: #e8f6ee; color: #146c2e; }
.opp-status-lost      { background: #fdecec; color: #8a1f1f; }
.opp-status-abandoned { background: #f0eef2; color: #555c66; }
.opp-name {
  font-weight: 600;
  font-size: 14px;
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.opp-money {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 13px;
  font-weight: 600;
  white-space: nowrap;
}
.opp-caret { color: var(--ink-soft, #555c66); font-size: 14px; }
.opp-row-sub {
  margin-top: 6px;
  font-size: 13px;
  color: var(--ink-soft, #555c66);
}

.opp-actions {
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px solid var(--border, #d8dde4);
}

/* ETAS-style action cards inside an expanded opp row. Each card is a
   header + collapsible body — Move to Stage, Close (won/lost/abandoned). */
.opp-action-card {
  border: 1px solid var(--border, #d8dde4);
  border-radius: 6px;
  margin: 6px 0;
  background: #eef4fc;
  overflow: hidden;
}
.opp-action-card[data-card="close"] { background: #f8f4ee; }
.opp-action-head {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  cursor: pointer;
  user-select: none;
}
.opp-action-head:hover { filter: brightness(0.97); }
.opp-action-icon { font-size: 16px; }
.opp-action-title { font-weight: 600; font-size: 14px; flex: 1; }
.opp-action-caret { color: var(--ink-soft, #555c66); font-size: 14px; }
.opp-action-body {
  padding: 10px 12px 12px;
  background: #fff;
  border-top: 1px solid var(--border, #d8dde4);
}
.opp-action-footer {
  margin-top: 10px;
  text-align: right;
}
.opp-open-ghl {
  display: inline-block;
  font-size: 13px;
  font-weight: 600;
  padding: 6px 12px;
  border: 1.5px solid var(--ink, #11141a);
  border-radius: 4px;
  color: var(--ink, #11141a);
  text-decoration: none;
}
.opp-open-ghl:hover { background: #f5f5f5; }

.opp-form { display: flex; flex-direction: column; gap: 10px; }
.opp-status-radios {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}
.opp-status-radio {
  flex: 1;
  min-width: 110px;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 10px 12px;
  border: 1.5px solid var(--border, #d8dde4);
  border-radius: 5px;
  background: #fff;
  cursor: pointer;
  font-size: 14px;
  font-weight: 600;
}
.opp-status-radio input { cursor: pointer; }
.opp-status-radio:has(input:checked) {
  border-color: var(--ink, #11141a);
  background: #f5f7fa;
}

.opp-retry {
  font-size: 13px; padding: 4px 10px; border-radius: 4px;
  border: 1px solid var(--border, #d8dde4); background: #fff; cursor: pointer; margin-left: 4px;
}

/* ── New Enquiry / New Contact CTA ──────────────────────────────────────
   Renders inside the no-match empty state ("Want to add as a new client?").
   Search-first UX: the button only appears after a search returns no
   results, so it's invitation not clutter. */
.new-enquiry-cta {
  font-size: 16px;
  padding: 14px 18px;
  min-height: 52px;
  letter-spacing: 0.01em;
}

/* Skeleton search-result cards — painted instantly on search submit so the
   page never feels frozen while the GHL roundtrip is in flight. Real cards
   replace them when the response arrives. */
.card-skel { pointer-events: none; }
.card-skel .skel-line {
  height: 14px;
  border-radius: 6px;
  margin: 8px 0;
  background: linear-gradient(90deg, #e8eaf0 0%, #f3f5f9 50%, #e8eaf0 100%);
  background-size: 200% 100%;
  animation: skel-shimmer 1.2s ease-in-out infinite;
}
.card-skel .skel-line-name { width: 55%; height: 20px; margin-top: 0; }
.card-skel .skel-line-sub  { width: 35%; height: 12px; }
.card-skel .skel-line-addr { width: 80%; height: 14px; }
@keyframes skel-shimmer {
  0%   { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}

/* A11y — respect reduced motion. */
@media (prefers-reduced-motion: reduce) {
  .btn:active { transform: none; }
  .card-skel .skel-line { animation: none; background: #e8eaf0; }
  body.is-pinned #detailPane .card { animation: none; }
}

/* ── Workflows panel (contact card inline) ─────────────────────── */
.workflows-slot:empty { display: none; }
/* Override the base .notes-panel overflow:hidden — it clips the
   absolutely-positioned typeahead dropdown so only 1-2 rows show. We need
   the dropdown to be able to extend below the panel box. */
.workflows-panel { margin-top: 6px; overflow: visible; }
.workflows-head { font-weight: 700; color: var(--ink); }
.workflows-disclaimer {
  padding: 6px 12px; font-size: 12px; color: var(--ink-soft);
  background: #fff8e6; border-bottom: 1px solid var(--line);
}
.workflows-picker { padding: 10px 12px; position: relative; }
.workflows-picker-label {
  display: block; font-size: 12px; font-weight: 700; color: var(--ink);
  text-transform: uppercase; letter-spacing: 0.04em; margin-bottom: 6px;
}
.workflows-search-wrap {
  position: relative; cursor: text;
}
.workflows-search {
  width: 100%; padding: 12px 36px 12px 14px;
  border: 2px solid var(--accent, #1773b0); border-radius: 10px;
  font: inherit; font-size: 15px; background: #fff;
  box-sizing: border-box;
}
.workflows-search:focus {
  outline: none; box-shadow: 0 0 0 3px rgba(23,115,176,0.15);
}
.workflows-search-chevron {
  position: absolute; right: 12px; top: 50%; transform: translateY(-50%);
  color: var(--accent, #1773b0); font-size: 18px; pointer-events: none;
}
.workflows-options {
  position: absolute; left: 12px; right: 12px; top: calc(100% - 4px);
  /* Show 6+ rows at default row height (~42px each = ~260px). Capped
     to 60vh so very long lists don't run off a small phone. */
  max-height: min(60vh, 360px); overflow-y: auto;
  background: #fff; border: 2px solid var(--accent, #1773b0); border-top: 0;
  border-radius: 0 0 10px 10px;
  box-shadow: 0 8px 20px rgba(0,0,0,0.12); z-index: 50;
  display: flex; flex-direction: column;
}
.workflows-option { padding: 10px 14px; font-size: 14px; }
.workflows-option {
  text-align: left; padding: 8px 12px; background: #fff;
  border: 0; border-bottom: 1px solid var(--line);
  font: inherit; cursor: pointer;
}
.workflows-option:last-child { border-bottom: 0; }
.workflows-option:hover { background: #f4f6f8; }
.workflows-option--empty { color: var(--ink-soft); cursor: default; }
.workflows-log {
  display: flex; flex-direction: column; gap: 4px;
  padding: 4px 12px 12px;
}
.workflow-row {
  display: flex; align-items: center; gap: 8px;
  padding: 8px 10px;
  background: #f4f6f8; border-radius: 6px;
}
.workflow-row__main { flex: 1 1 auto; min-width: 0; }
.workflow-row__name { font-weight: 600; color: var(--ink); }
.workflow-row__meta { font-size: 12px; color: var(--ink-soft); margin-top: 1px; }
.workflow-row__remove {
  flex: 0 0 auto;
  background: transparent; border: 0; color: var(--ink-soft);
  font-size: 20px; line-height: 1; cursor: pointer; padding: 4px 8px;
  border-radius: 4px;
}
.workflow-row__remove:hover { background: #fee2e2; color: #991b1b; }

/* ── Tags picker (Add Tag / Remove Tag — mirrors the workflows picker) ── */
.tags-slot:empty { display: none; }
.tags-panel { margin-top: 6px; overflow: visible; }
/* .action-group has overflow:hidden (to clip its rounded corners), which crops
   the absolutely-positioned picker dropdown when the panel is short — the tags
   panel has no log below it to give the box height, so the list gets cut off.
   Let the dropdown escape the box while it's open (covers workflows too). */
.action-group:has(.tags-options:not([hidden])),
.action-group:has(.workflows-options:not([hidden])) {
  overflow: visible;
}
.tags-picker { padding: 10px 12px 18px; position: relative; }
.tags-picker-label {
  display: block; font-size: 12px; font-weight: 700; color: var(--ink);
  text-transform: uppercase; letter-spacing: 0.04em; margin-bottom: 6px;
}
.tags-search-wrap { position: relative; cursor: text; }
.tags-search {
  width: 100%; padding: 12px 36px 12px 14px;
  border: 2px solid var(--accent, #1773b0); border-radius: 10px;
  font: inherit; font-size: 15px; background: #fff;
  box-sizing: border-box;
}
.tags-search:focus {
  outline: none; box-shadow: 0 0 0 3px rgba(23,115,176,0.15);
}
.tags-search-chevron {
  position: absolute; right: 12px; top: 50%; transform: translateY(-50%);
  color: var(--accent, #1773b0); font-size: 18px; pointer-events: none;
}
.tags-options {
  position: absolute; left: 12px; right: 12px; top: calc(100% - 4px);
  max-height: min(60vh, 360px); overflow-y: auto;
  background: #fff; border: 2px solid var(--accent, #1773b0); border-top: 0;
  border-radius: 0 0 10px 10px;
  box-shadow: 0 8px 20px rgba(0,0,0,0.12); z-index: 50;
  display: flex; flex-direction: column;
}
.tags-option {
  text-align: left; padding: 8px 12px; background: #fff;
  border: 0; border-bottom: 1px solid var(--line);
  font: inherit; font-size: 14px; cursor: pointer;
}
.tags-option:last-child { border-bottom: 0; }
.tags-option:hover { background: #f4f6f8; }
.tags-option--empty { color: var(--ink-soft); cursor: default; }
.tags-status { padding: 4px 12px 10px; }
.tags-done { font-size: 14px; color: var(--good, #117a3a); font-weight: 600; }

/* Photos panel — uploaded images from contact.website_uploaded_images.
   Reuses .notes-panel shell; adds the thumbnail grid + lightbox styles. */
.photos-panel .notes-panel-head { /* same head treatment as appointments */ }
/* ── Simple SMS compose (inline panel in the Messages section) ──────────── */
.sms-compose {
  margin-top: 8px; padding: 10px;
  border: 1px solid var(--line, #e6e9ee); border-radius: 8px;
  background: var(--card, #fff);
  display: flex; flex-direction: column; gap: 8px;
}
.sms-to { font-size: 13px; color: var(--ink-soft, #5a6472); }
.sms-to--warn { color: var(--warn, #b42318); font-weight: 600; }
.sms-text {
  width: 100%; font: inherit; padding: 10px;
  border: 1.5px solid var(--line, #e6e9ee); border-radius: 8px;
  resize: vertical; box-sizing: border-box;
}
.sms-preview {
  font-size: 14px; line-height: 1.45; white-space: pre-wrap;
  background: rgba(0,0,0,0.04); border-radius: 6px; padding: 8px 10px;
  color: var(--ink, #11141a);
}
.sms-meta { font-size: 12px; color: var(--ink-soft, #5a6472); text-align: right; }
.sms-actions { display: flex; }
.sms-actions .sms-send { width: 100%; }
.sms-msg { font-size: 13px; min-height: 1em; }
.sms-sent { font-size: 15px; color: var(--good, #117a3a); font-weight: 600; padding: 6px 2px; }

.images-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(110px, 1fr));
  gap: 8px;
  padding: 8px;
}
.images-cell {
  position: relative;
  padding: 0; border: 0; background: transparent;
  border-radius: 6px; overflow: hidden; aspect-ratio: 1;
  box-shadow: 0 0 0 1px rgba(0,0,0,0.08);
}
.images-cell:hover { box-shadow: 0 0 0 2px var(--accent, #2563eb); }
.images-cell img {
  width: 100%; height: 100%; object-fit: cover; display: block; cursor: zoom-in;
}

/* Delete affordance overlaid on each photo (and at the end of each file row).
   Always visible on touch — there's no hover on a phone, and this app is
   mobile-first. Big enough for a thumb (32px) without dominating the thumbnail. */
.img-del {
  position: absolute; top: 4px; right: 4px;
  width: 32px; height: 32px; padding: 0;
  border: 0; border-radius: 50%;
  background: rgba(0,0,0,0.55); color: #fff;
  font-size: 15px; line-height: 1; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  box-shadow: 0 1px 3px rgba(0,0,0,0.4);
}
.img-del:hover { background: rgba(220,38,38,0.92); }
.img-del:disabled { opacity: 0.6; cursor: default; }
.img-del.file-del { position: static; flex: 0 0 auto; }

/* Lightbox overlay — fixed full-viewport, dim backdrop, image + arrows. */
.images-lightbox {
  position: fixed; inset: 0; z-index: 9999;
  background: rgba(0,0,0,0.88);
  display: flex; align-items: center; justify-content: center;
  padding: 24px;
}
.images-lightbox[hidden] { display: none; }
.images-lightbox .lb-img {
  max-width: 95%; max-height: 90%; object-fit: contain;
  border-radius: 4px; background: #111;
}
.images-lightbox .lb-close,
.images-lightbox .lb-prev,
.images-lightbox .lb-next {
  position: absolute; background: rgba(255,255,255,0.12); color: #fff;
  border: 0; cursor: pointer; font-size: 28px; line-height: 1;
  width: 44px; height: 44px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
}
.images-lightbox .lb-close:hover,
.images-lightbox .lb-prev:hover,
.images-lightbox .lb-next:hover { background: rgba(255,255,255,0.25); }
.images-lightbox .lb-close { top: 16px; right: 16px; }
.images-lightbox .lb-prev  { left: 16px; top: 50%; transform: translateY(-50%); }
.images-lightbox .lb-next  { right: 16px; top: 50%; transform: translateY(-50%); }
.images-lightbox .lb-caption {
  position: absolute; bottom: 16px; left: 50%; transform: translateX(-50%);
  color: #fff; font-size: 14px; background: rgba(0,0,0,0.5);
  padding: 6px 12px; border-radius: 4px;
}
.images-lightbox .lb-del {
  position: absolute; bottom: 14px; right: 16px;
  background: rgba(0,0,0,0.55); color: #fff; border: 0;
  font-size: 14px; line-height: 1; cursor: pointer;
  padding: 10px 14px; border-radius: 6px;
}
.images-lightbox .lb-del:hover { background: rgba(220,38,38,0.92); }
.images-lightbox .lb-del:disabled { opacity: 0.6; cursor: default; }
.images-lightbox .lb-del[hidden] { display: none; }

/* Non-image attachments inside the Photos & Files panel. */
.files-head {
  font-size: 13px; color: var(--ink-soft, #6b7280);
  margin: 12px 8px 4px; padding-top: 8px;
  border-top: 1px solid rgba(0,0,0,0.08);
}
.files-list { display: flex; flex-direction: column; gap: 4px; padding: 0 8px 8px; }
/* Row is a flex wrapper: the open button takes the space, delete sits at the end. */
.files-row {
  display: flex; align-items: center; gap: 6px;
  border-radius: 6px; background: rgba(0,0,0,0.03);
}
.files-row:hover { background: rgba(0,0,0,0.07); }
.files-open-btn {
  flex: 1 1 auto; display: flex; align-items: center; gap: 10px;
  padding: 8px 10px; border: 0; background: transparent;
  cursor: pointer; font: inherit; text-align: left; color: inherit;
}
.files-icon { font-size: 20px; flex: 0 0 auto; }
.files-name { flex: 1 1 auto; word-break: break-word; font-size: 14px; }
.files-open { font-size: 12px; color: var(--accent, #2563eb); flex: 0 0 auto; }

/* File viewer overlay — same dim backdrop as image lightbox, but with
   a toolbar at top and a full-height iframe for the file. */
.file-viewer { padding: 0; flex-direction: column; }
.file-viewer .fv-toolbar {
  width: 100%; display: flex; align-items: center; gap: 12px;
  padding: 10px 16px; background: rgba(0,0,0,0.55); color: #fff;
  box-sizing: border-box;
}
.file-viewer .fv-name {
  flex: 1 1 auto; font-size: 14px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.file-viewer .fv-download {
  color: #fff; text-decoration: none;
  background: rgba(255,255,255,0.15); padding: 6px 12px;
  border-radius: 4px; font-size: 13px;
}
.file-viewer .fv-download:hover { background: rgba(255,255,255,0.28); }
.file-viewer .fv-close {
  background: rgba(255,255,255,0.15); border: 0; color: #fff;
  width: 32px; height: 32px; border-radius: 50%; font-size: 20px;
  line-height: 1; cursor: pointer;
}
.file-viewer .fv-close:hover { background: rgba(255,255,255,0.28); }
.file-viewer .fv-frame {
  flex: 1 1 auto; width: 100%; border: 0; background: #fff;
}

/* ════════════════════════════════════════════════════════════════════
   Two-pane desktop/tablet layout (>=1024px)
   --------------------------------------------------------------------
   Mobile/tablet (<1024px) is UNCHANGED: .cf-grid is a plain block, the
   detail pane is hidden, and everything flows single-column exactly as
   before. At >=1024px the .cf-grid becomes a two-column CRM: the search
   form + results list sit in the left rail, and app.js relocates the
   selected client's card (with its full inline detail/actions) into
   #detailPane on the right.
   ════════════════════════════════════════════════════════════════════ */

/* Base (all widths): no layout change on mobile, detail pane hidden. */
.cf-grid { display: block; }
.detail-pane { display: none; }

/* Desktop-only Focus button (shown at >=1024px on the selected card). */
.focus-btn { display: none; }
.focus-btn .focus-off { display: none; }
/* Desktop-only Print button (shown at >=1024px on the selected card). */
.print-btn { display: none; }
/* Desktop-only keyboard hint line. */
.kbd-hints { display: none; }

/* Recently-viewed strip — hidden by default (all widths); shown only at
   >=1024px AND only when it has content (:not([hidden])), so an empty strip
   never displays. */
.recent-actions { display: none; }

/* Results count / "Searching…" hint — desktop-only, same [hidden] idiom. */
.results-count { display: none; }

@keyframes cf-focus-in {
  from { opacity: 0.4; transform: translateY(4px); }
  to   { opacity: 1; transform: none; }
}

@media (min-width: 1024px) {
  /* Give the two panes room to breathe. */
  .wrap { max-width: 1180px; }

  .cf-grid {
    display: grid;
    grid-template-columns: minmax(320px, 380px) 1fr;
    gap: 24px;
    align-items: start;
  }

  /* Left rail holds the search form + results list. */
  .cf-left { min-width: 0; }

  /* Right pane shows the selected client's full detail/actions. */
  .detail-pane {
    display: block;
    min-width: 0;
  }
  /* Empty state — shown only while nothing is selected (no whitespace
     inside the <aside>, so :empty matches until a card is moved in). */
  #detailPane:empty::before {
    content: "Select a client to see their details and actions here.";
    display: flex;
    align-items: center;
    justify-content: center;
    text-align: center;
    min-height: 220px;
    padding: 24px;
    color: var(--ink-soft);
    background: var(--card);
    border: 1.5px dashed var(--line);
    border-radius: var(--radius, 12px);
    font-size: 15px;
  }
  /* The relocated card fills the right pane comfortably. */
  #detailPane .card { width: 100%; }

  /* Gently scale the mobile-tuned (touch) typography down for pointer use.
     Kept INSIDE this media query so mobile sizes are byte-identical. */
  .field input, .btn { font-size: clamp(14px, 1.1vw, 16px); }
  .card .name { font-size: clamp(16px, 1.4vw, 19px); }
  .card .address { font-size: clamp(14px, 1.1vw, 16px); }

  /* Pin/focus mode is unnecessary at this width (the layout already
     isolates the selected client), so hide the per-card pin toggle. */
  .card .pin-toggle { display: none; }

  /* "⤢ Focus" button — visible only on the selected (detail-pane) card.
     It is the desktop trigger for focus mode (proxies the hidden pin box). */
  .card.is-selected .focus-btn {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    margin-top: 10px;
    padding: 8px 14px;
    border: 1.5px solid var(--accent);
    border-radius: 999px;
    background: var(--card);
    color: var(--accent);
    font: inherit;
    font-weight: 700;
    cursor: pointer;
  }
  .card.is-selected .focus-btn:hover { background: #f0f6fb; }
  /* Print button — secondary (muted) so Focus stays the primary action. */
  .card.is-selected .print-btn {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    margin-top: 10px;
    margin-left: 8px;
    padding: 8px 14px;
    border: 1.5px solid var(--line);
    border-radius: 999px;
    background: var(--card);
    color: var(--ink-soft);
    font: inherit;
    font-weight: 700;
    cursor: pointer;
  }
  .card.is-selected .print-btn:hover { border-color: var(--accent); color: var(--accent); }
  /* Label swaps to "✕ Exit focus" while focused. */
  body.is-pinned .focus-btn .focus-on { display: none; }
  body.is-pinned .focus-btn .focus-off { display: inline; }

  /* Focus mode — hide the search rail, single column, centre the client. */
  body.is-pinned .cf-left { display: none; }
  body.is-pinned .cf-grid { grid-template-columns: 1fr; }
  body.is-pinned #detailPane { max-width: 860px; margin: 0 auto; }
  body.is-pinned #detailPane .card { animation: cf-focus-in 180ms ease both; }

  /* ── Recent lists (under the search box): Latest Added / Recently Opened ── */
  .recent-actions:not([hidden]) {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    margin: 0 0 14px;
  }
  .recent-action {
    font: inherit;
    font-weight: 600;
    font-size: 13px;
    padding: 7px 14px;
    border: 1.5px solid var(--line);
    border-radius: 8px;
    background: var(--card);
    color: var(--ink);
    cursor: pointer;
  }
  .recent-action:hover { border-color: var(--accent); color: var(--accent); }
  /* Active = the list currently shown. Colour + fill (not colour alone). */
  .recent-action.is-active {
    background: var(--accent);
    border-color: var(--accent);
    color: #fff;
  }

  /* ── Keyboard highlight on a result card (outline = colour, ▸ = shape, so
        it reads for colourblind users too) ── */
  .card.is-kbd { outline: 2px solid var(--accent); outline-offset: 2px; }
  .card.is-kbd .name::before { content: "▸ "; color: var(--accent); font-weight: 700; }

  /* ── Sticky client identity header on the OPEN card ── */
  .card.is-selected .card-head {
    position: sticky;
    top: 0;
    z-index: 5;
    background: var(--card);
    padding-top: 8px;
    border-bottom: 1px solid var(--line);
  }

  /* ── Results count line ── */
  .results-count:not([hidden]) {
    display: block;
    font-size: 13px;
    font-weight: 700;
    color: var(--ink-soft);
    margin: 0 0 8px;
  }

  /* ── Denser, hover-aware result rows (UNSELECTED list cards only). The
        relocated detail card lives in #detailPane so it's naturally excluded;
        the :not(.is-selected) guard also covers the brief pre-relocate frame. ── */
  #results .card:not(.is-selected) { padding: 12px 14px; }
  #results .card:not(.is-selected) .name { font-size: clamp(15px, 1.2vw, 17px); margin-bottom: 2px; }
  #results .card:not(.is-selected) .address { font-size: 13.5px; margin-bottom: 4px; }
  #results .card:not(.is-selected) .assignee { margin-bottom: 4px; }
  #results .card:not(.is-selected):hover {
    border-color: var(--accent);
    background: #f0f6fb;
  }

  /* ── Keyboard hint line + key-caps (GHL-native, muted) ── */
  .kbd-hints {
    display: block;
    font-size: 12px;
    color: var(--ink-soft);
    line-height: 1.9;
    margin: 8px 0 12px;
  }
  .kbd-hints kbd,
  .kbd-cheatsheet kbd {
    font: inherit;
    font-size: 11px;
    padding: 1px 6px;
    margin: 0 1px;
    border: 1px solid var(--line);
    border-bottom-width: 2px;
    border-radius: 5px;
    background: #f4f6f9;
    color: var(--ink);
  }
}

/* Keyboard shortcuts cheatsheet (opened with "?"). Centred modal; only ever
   triggered on desktop (the "?" handler is gated on IS_WIDE_QUERY). */
.kbd-cheatsheet-overlay {
  position: fixed; inset: 0; z-index: 1000;
  display: flex; align-items: center; justify-content: center;
}
.kbd-cheatsheet-backdrop { position: absolute; inset: 0; background: rgba(0, 0, 0, 0.35); }
.kbd-cheatsheet {
  position: relative; z-index: 1;
  width: min(92vw, 420px);
  background: var(--card);
  border-radius: var(--radius, 12px);
  box-shadow: 0 10px 40px rgba(0, 0, 0, 0.3);
  padding: 16px 18px;
}
.kbd-cheatsheet-head {
  display: flex; align-items: center; justify-content: space-between;
  font-weight: 700; font-size: 16px; margin-bottom: 12px;
}
.kbd-cheatsheet-close {
  border: 0; background: transparent; font-size: 18px;
  cursor: pointer; color: var(--ink-soft); line-height: 1;
}
.kbd-cheatsheet-list {
  display: grid; grid-template-columns: auto 1fr; gap: 8px 14px;
  margin: 0; align-items: center;
}
.kbd-cheatsheet-list dt { text-align: right; margin: 0; white-space: nowrap; }
.kbd-cheatsheet-list dd { margin: 0; color: var(--ink); font-size: 14px; }
.kbd-cheatsheet-list kbd {
  font: inherit; font-size: 12px; padding: 2px 7px; margin: 0 1px;
  border: 1px solid var(--line); border-bottom-width: 2px; border-radius: 5px;
  background: #f4f6f9; color: var(--ink);
}

/* ════════════════════════════════════════════════════════════════════
   Print — clean single-client sheet (🖨 Print button on the open card).
   Blanks everything except the selected client's card, lifts it to the page
   origin, hides interactive chrome, and force-expands collapsed details.
   Width-agnostic: `.card.is-selected` is the open card in two-pane, focus,
   and mobile alike.
   ════════════════════════════════════════════════════════════════════ */
@media print {
  body * { visibility: hidden !important; }
  .card.is-selected, .card.is-selected * { visibility: visible !important; }
  .card.is-selected {
    position: absolute;
    left: 0;
    top: 0;
    width: 100%;
    margin: 0;
    box-shadow: none;
    border: none;
  }
  /* Identity header must not float when printed. */
  .card.is-selected .card-head { position: static; border-bottom: 1px solid #ccc; }
  /* Expand any collapsed "Show all details" so nothing is clipped. */
  .card.is-selected .contact-details[hidden] { display: block !important; }
  /* Hide interactive-only controls inside the printed card. */
  .card.is-selected .actions,
  .card.is-selected .print-btn,
  .card.is-selected .focus-btn,
  .card.is-selected .edit-contact,
  .card.is-selected .pin-toggle,
  .card.is-selected .pin-badge,
  .card.is-selected .cd-toggle,
  .card.is-selected .cd-allfields { display: none !important; }
  @page { margin: 12mm; }
}
