/* styles.css — shared design tokens, matching loggia.work and the internal
   Loggia portal so the whole product family feels like one thing. */

/* iOS design language on desktop: SF typography, grouped-gray canvas, rounded
   cards, translucent chrome, softer depth. The classical ink+gold brand is
   kept (primary buttons stay ink navy, gold as the editorial accent); iOS
   supplies the structure. All class names are unchanged so nothing in the
   markup or JS has to move. */
:root{
  --bg-canvas:#F2F2F7; --bg-surface:#FFFFFF; --bg-muted:#EDECF0; --border:#DFDEE4;
  --sep:rgba(60,60,67,.16);
  --text-primary:#111114; --text-secondary:rgba(60,60,67,.62); --text-tertiary:rgba(60,60,67,.38);
  /* ── The orange ramp (2026-08-03 palette change) ──────────────────────────
     ONE hue, FOUR steps, and which one you use is decided by what sits on top
     of it — not by taste. #F66A22 is the brand orange and it is 3.0:1 on white:
     that passes AA for graphics and for text ≥24px, and FAILS for body text and
     for white-on-orange. The old --accent-deep #D14E0A was 4.4:1, so it was
     safe everywhere and the distinction never had to exist. It does now.

       --accent-bright  #F66A22  GRAPHICAL ONLY. Progress fills, toggle tracks,
                                 accent-color, borders, 24px+ display numerals.
                                 Never behind text, never as text under 24px.
       --accent-deep    #C65310  Fills that CARRY WHITE TEXT. 4.52:1 with #FFF.
                                 The handoff said #C75411 and called it 4.5:1.
                                 Measured, that is 4.4637 — under the bar it was
                                 picked to clear. This is one hex step darker,
                                 indistinguishable on screen, and actually
                                 passes. Corrected rather than shipped: the
                                 entire point of splitting the ramp is that the
                                 text-bearing step is safe.
                                 .btn.primary, count badges, .pill.admin, avatars.
       --accent-text    #BF4708  Orange TEXT on white/paper. 5.09:1.
       --accent-text-soft #B24405 Orange text on --accent-soft. 4.84:1 on #FBEBDD.

     --accent-deep keeps its name and its meaning ("the fill white text sits
     on") so the ~70 existing uses stay correct by default; the sweep moves the
     GRAPHICAL ones out to --accent-bright, which is the direction that cannot
     break contrast. --accent (#C96F2E) predates this ramp and is unrelated to
     it — it is the muted brand tone, left alone deliberately. */
  --accent:#C96F2E; --accent-soft:#FBEBDD;
  --accent-bright:#F66A22; --accent-deep:#C65310;
  --accent-text:#BF4708; --accent-text-soft:#B24405;
  --heat-red:#E5301C; --heat-orange:#F4590D; --heat-amber:#FF8A3D; --heat-yellow:#FFC53D;
  --ios-blue:#0A84FF;
  /* Holographic blue — the scarce tier for "machine acting right now" or "a
     decision blocking the machine" (dashboard rebuild plan §3.1). A different
     hex from --ios-blue on purpose: #0A84FF fails AA 4.5:1 for text on white.
     The 5.02:1 figure that stood here described the OLD #0A6BDF and survived
     the palette change as a false reassurance — #2E86DC is 3.78:1 on
     --bg-surface, which passes for graphics and fails for text. That gap is
     exactly why --holo-text exists; use it for anything readable.
     --holo-grad never carries or backs text: strokes ≤2px, dots ≤10px, live
     canvas edges only. */
  --holo:#2E86DC; --holo-soft:rgba(46,134,220,.12);
  /* --holo-grad's MIDDLE stop, promoted to a token of its own so a non-SVG
     surface can name it. dashboard.css is hex-scanned, so the border beam
     (§2.12) could not otherwise say "the cyan in the holo sweep" without
     re-spelling a hex there. --holo-grad itself is deliberately NOT rewritten
     to reference this: a test parses that declaration for three LITERAL hexes
     and a var() would break it. Inherits --holo-grad's restriction verbatim —
     it never carries or backs text (2.38:1 on white); strokes and dots only. */
  --holo-cyan:#22B8CF;
  /* The focus ring, which was a raw rgba sitting in the middle of the token
     file and therefore theme-frozen: .18 alpha is swallowed by the dark
     surface, so the ring was close to invisible in dark mode. */
  --focus-ring:rgba(10,132,255,.18);
  /* Alice blue's text step, same split as the orange ramp above: #2E86DC is
     3.5:1 on white — fine for the mic glyph, dots, ripples and progress, not
     for the timer or "Opening the line…". #276DA8 is 4.75:1. */
  --holo-text:#276DA8; --holo-tint:#E7F1FD;
  --holo-grad:linear-gradient(135deg,#2E86DC 0%,#22B8CF 45%,#7A5AF8 100%);
  /* Text/glyph colour ON a filled accent surface. White in BOTH themes on
     purpose — the .btn.primary / .pill.admin idiom below is white-on-orange in
     dark mode too — so this is a token for "the fill owns the contrast", not a
     theme variable. It exists so token-only stylesheets (dashboard.css is
     hex-scanned) can express white-on-accent without a hex literal. */
  --on-accent:#FFFFFF;
  --success:#248A3D; --success-soft:#E4F4E8;
  --danger:#D7382E; --danger-soft:#FBE7E5;
  /* ── Status: the line and the text step (2026-08-28, Alert component) ─────
     --success and --danger above are FILL colours: the toast writes one as a
     background under hardcoded white text, and every .pill pair uses them as
     a glyph colour on their own -soft tint. They therefore must NOT flip in
     dark mode — lighten --danger and white-on-danger drops to ~2.6:1.

     So the flip happens in a second step instead, exactly as the mobile layer
     already does it (--m-danger-text, mobile.css:90, and the note beside it).
     -text is what you put ON a -soft tint; -line is the border of that tint.
     Both are needed because dashboard.css is hex-scanned and cannot spell an
     alpha border itself.

     WARNING IS NET-NEW. The portal had no warning colour at all: the one
     warning surface (.notice-inline) invented rgba(255,214,10,.12) inline —
     theme-frozen, no token, and a yellow nothing else on the page uses.
     #A16207 is 4.92:1 on white, so it carries small text, which the iOS amber
     (#FF9F0A, 2.1:1) cannot.

     THERE IS DELIBERATELY NO --info. The component this came from ships an
     `info` variant in violet, and the obvious blue here is already taken:
     --holo is a RESERVED scarcity tier meaning "the machine is acting right
     now", with per-view budgets asserted by exact list in
     test/dashboard-foundation.js. Every surface in this app that plays the
     info role today (.fv-activity, .of-insights, .of-strip) is already built
     on --accent-soft or the neutral --bg-muted, so `info` maps onto the
     existing primary and mono variants rather than adding a third hue to a
     deliberately small palette. */
  --success-line:rgba(36,138,61,.3); --success-text:#1B6E30;
  --danger-line:rgba(215,56,46,.3); --danger-text:#C3352B;
  --warning:#A16207; --warning-soft:#FCF1DE;
  --warning-line:rgba(161,98,7,.28); --warning-text:#8A5406;
  /* The accent's border step. .btn.outline and .chip.on already use the solid
     --accent-bright as a border; this is the tinted one an alert needs. */
  --accent-line:rgba(246,106,34,.3);
  /* ── File families (2026-08-28, FileCard component) ───────────────────────
     The ported component hardcoded ~20 Tailwind hues (bg-blue-500,
     bg-emerald-600, bg-purple-500 …). Importing that palette would have meant
     twenty new tokens in a design system that keeps a deliberately small one,
     so the map collapses to the SIX families a person actually scans a file
     list for. Every one is a fill carrying --on-accent, so each is dark enough
     for white text (all ≥5.3:1) and is restated rather than flipped in dark
     mode — same contract as --accent-deep. */
  --ft-doc:#1D5FA8; --ft-sheet:#1E7A4D; --ft-image:#A83672;
  --ft-video:#0F6E72; --ft-archive:#6D46B8; --ft-code:#455163;
  /* Referenced six times by the meeting-notes block in dashboard.css and never
     declared anywhere — those rules have been resolving to nothing. Same value
     as --text-tertiary, which is what the block was reaching for. */
  --text-muted:rgba(60,60,67,.38);
  --radius:10px; --radius-lg:16px; --radius-pill:980px;
  /* ── Glass surfaces (2026-08-28, Settings account card) ───────────────────
     Eight tokens, and they exist for ONE structural reason: dashboard.css is
     hex-scanned AND is not allowed a single `body.dark` override
     (test/dashboard-foundation.js enforces both), so a translucent surface —
     which needs an alpha channel and a different base colour per theme —
     cannot be spelled there at all. It is spelled here, once, the same way
     the rest of dark mode is: a token-level flip.
     NO NEW HUE. --glass-wash-a is --accent-bright at low alpha (Loggia's
     orange, the same accent every other surface uses) and --glass-wash-b is
     the neutral --sep family. Deliberately NOT the holo blue: Settings is a
     zero-holo view by design (appendix-visual-language §4) and holo means
     "the machine is acting right now", which a decorative gradient is not. */
  --glass-card:rgba(255,255,255,.62);   /* the big outer card */
  --glass-panel:rgba(255,255,255,.42);  /* a sub-panel, one step off the card */
  --glass-sheet:rgba(255,255,255,.9);   /* a .sheet: frosted, but forms stay readable */
  --glass-line:rgba(223,222,228,.6);    /* --border at 60% — the design's hairline */
  --glass-tint:rgba(255,255,255,.5);    /* the faint fill under pills + outline buttons */
  --glass-wash-a:rgba(246,106,34,.1); --glass-wash-b:rgba(60,60,67,.05);
  /* The filled button's long soft lift. Warm rather than neutral because the
     fill under it is --accent-deep; a white-label repaint moves the fill and
     leaves this, which is why it is kept low-alpha enough to read as depth
     rather than as a second brand colour. */
  --glass-lift:rgba(198,83,16,.45);
  --nav-blur:rgba(249,249,251,.8);
  --shadow-card:0 1px 2px rgba(17,17,20,.04),0 6px 16px -12px rgba(17,17,20,.18);
  --font-serif:'Source Serif 4', Georgia, serif;
  --font-sans:-apple-system,BlinkMacSystemFont,'SF Pro Text','Inter','Segoe UI',Roboto,Helvetica,Arial,sans-serif;
}
/* dark mode — token-level flip, toggled by #themeToggle via theme.js and
   persisted in localStorage('loggiaTheme'). Components read tokens, so this
   block is most of the work. */
/* Dark mode retuned toward a Whop-minimal palette: a flat near-black canvas,
   panels a hair lighter, low-contrast hairline borders doing the structural
   work instead of heavy shadows. Loggia's orange stays as the accent so the
   product keeps its identity — the STRUCTURE is minimal, the brand is intact. */
body.dark{
  --bg-canvas:#111113; --bg-surface:#191A1D; --bg-muted:#212226; --border:#2A2B30;
  --sep:rgba(235,235,245,.14);
  --text-primary:#EDEDEF; --text-secondary:rgba(235,235,245,.58); --text-tertiary:rgba(235,235,245,.34);
  --accent-soft:rgba(201,111,46,.16);
  /* The ramp inverts in dark mode: on #191A1D the DARK steps are the ones that
     fail, because the contrast now has to run the other way. --accent-bright
     stays put (it is graphical, and 5.9:1 on the dark surface anyway) and the
     two text steps lighten. --accent-deep keeps carrying white text, so it
     keeps a mid value rather than following them up. */
  --accent-deep:#C65310; --accent-text:#F0873F; --accent-text-soft:#F0873F;
  --holo:#3BA8FF; --holo-soft:rgba(59,168,255,.16);
  --holo-cyan:#53E0F2;
  --focus-ring:rgba(10,132,255,.28);
  --holo-text:#6FB4F0; --holo-tint:rgba(59,168,255,.14);
  --holo-grad:linear-gradient(135deg,#3BA8FF 0%,#53E0F2 45%,#A78BFA 100%);
  /* Restated, not flipped: orange fills keep white text in dark mode. */
  --on-accent:#FFFFFF;
  --success-soft:rgba(36,138,61,.2); --danger-soft:rgba(215,56,46,.2);
  /* The -text steps lighten; --success and --danger themselves deliberately do
     NOT (see the note beside them). #C3352B on #191A1D is 3.2:1 — the exact
     failure mobile.css documents at line 87; #FF6F63 is 6.1:1. The lines
     strengthen, because a 30% tint that reads on white disappears on
     near-black — the same inversion the accent ramp and the glass set make. */
  --success-line:rgba(60,190,126,.34); --success-text:#4FBE7E;
  --danger-line:rgba(255,111,99,.36); --danger-text:#FF6F63;
  --warning-soft:rgba(161,98,7,.22); --warning-line:rgba(240,175,70,.34);
  --warning-text:#F0AF46;
  --accent-line:rgba(246,106,34,.42);
  /* Restated, not flipped: these are fills that keep --on-accent. */
  --ft-doc:#1D5FA8; --ft-sheet:#1E7A4D; --ft-image:#A83672;
  --ft-video:#0F6E72; --ft-archive:#6D46B8; --ft-code:#455163;
  --text-muted:rgba(235,235,245,.34);
  /* The glass set, flipped. --glass-line does NOT follow the light value's
     recipe: --border (#2A2B30) at 60% over the #111113 canvas is very nearly
     invisible, so the hairline takes the --sep white instead. Same ROLE (a
     60%-strength structural line), contrast running the other way — the same
     inversion the accent ramp above documents. The two washes lift slightly:
     a 10% tint that reads on white disappears on near-black. */
  --glass-card:rgba(25,26,29,.62);
  --glass-panel:rgba(255,255,255,.05);
  --glass-sheet:rgba(25,26,29,.92);
  --glass-line:rgba(235,235,245,.14);
  --glass-tint:rgba(255,255,255,.06);
  --glass-wash-a:rgba(246,106,34,.14); --glass-wash-b:rgba(235,235,245,.04);
  --glass-lift:rgba(0,0,0,.5);
  --nav-blur:rgba(17,17,19,.82);
  --shadow-card:0 1px 2px rgba(0,0,0,.35);
}
body.dark .btn{background:rgba(120,120,128,.22);}
body.dark .seg button.on{box-shadow:0 1px 3px rgba(0,0,0,.55);}

*{box-sizing:border-box;margin:0;padding:0;-webkit-font-smoothing:antialiased;}
body{font-family:var(--font-sans);color:var(--text-primary);background:var(--bg-canvas);line-height:1.47;letter-spacing:-.01em;}
a{color:var(--accent-text);text-decoration:none;}
h1,h2,h3,h4{font-family:var(--font-sans);font-weight:600;letter-spacing:-.022em;}
button{font-family:var(--font-sans);cursor:pointer;}
input,textarea,select{font-family:var(--font-sans);}

.btn{display:inline-flex;align-items:center;justify-content:center;gap:6px;padding:9px 17px;border-radius:var(--radius);font-size:14px;font-weight:600;letter-spacing:-.01em;border:1px solid transparent;background:rgba(120,120,128,.10);color:var(--text-primary);transition:transform .08s,background .15s,filter .15s;}
.btn:active{transform:scale(.97);}
.btn.primary{background:var(--accent-deep);color:#fff;}
.btn.primary:hover{filter:brightness(1.12);}
.btn.outline{background:transparent;border-color:var(--accent-bright);color:var(--accent-text);}
/* The hover tint moves the label onto --accent-soft, where --accent-text is
   4.38:1 -- under the bar. The soft step is the same role one notch darker
   and clears it at 4.84:1, so the label steps with the background. */
.btn.outline:hover{background:var(--accent-soft);color:var(--accent-text-soft);}
.btn.danger{color:var(--danger);background:rgba(215,56,46,.10);}
.btn.danger:hover{background:rgba(215,56,46,.16);}
.btn.small{padding:6px 13px;font-size:13px;border-radius:8px;}
.btn:disabled{opacity:.4;cursor:not-allowed;transform:none;}

/* The field box. Two bugs were fixed here on 2026-08-28, both of them live:
     - THE LIST WAS FIVE TYPES SHORT. app.html carries type=number x8, date x4,
       time x2, url and search, and none of them matched this selector — they
       fell back to UA chrome, which does not read a single token and so
       ignored dark mode outright.
     - 15px IS ONE PIXEL UNDER THE iOS ZOOM THRESHOLD. Mobile Safari zooms the
       page on focus for any field below 16px, so every input in the product
       zoomed on an iPhone unless the page happened to override it (mobile.css
       does for its own shell; nothing else did). 16px is the fix and it is the
       same reason the embeds and the command palette were raised to it. */
input[type=text],input[type=email],input[type=password],input[type=tel],
input[type=number],input[type=search],input[type=url],input[type=date],
input[type=time],input[type=datetime-local],input[type=month],textarea,select{
  width:100%;padding:11px 13px;border:1px solid var(--border);border-radius:var(--radius);font-size:16px;
  background:var(--bg-surface);color:var(--text-primary);transition:border-color .15s,box-shadow .15s;
}
input:focus,textarea:focus,select:focus{outline:none;border-color:var(--ios-blue);box-shadow:0 0 0 3.5px var(--focus-ring);}
label{font-size:13px;text-transform:none;letter-spacing:-.01em;color:var(--text-secondary);font-weight:500;display:block;margin-bottom:6px;}

.eyebrow{font-size:12px;text-transform:uppercase;letter-spacing:.06em;color:var(--accent);font-weight:600;}

.pill{display:inline-flex;align-items:center;font-size:12px;font-weight:600;padding:3px 10px;border-radius:var(--radius-pill);text-transform:none;letter-spacing:-.01em;}
.pill.admin{background:var(--accent-deep);color:#fff;}
.pill.member{background:rgba(120,120,128,.14);color:var(--text-secondary);}
.pill.searchable{background:var(--success-soft);color:var(--success);}
.pill.unsearchable{background:rgba(120,120,128,.14);color:var(--text-secondary);}

/* ── The auth pages' alert — a compatibility alias, on purpose ──────────────────────
   login.html, reset.html and complete-signup.html load styles.css and
   NOTHING else, so the .alert component in dashboard.css cannot reach them.
   Rather than pull a whole stylesheet onto the login page for one box, this
   rule IS .alert.destructive.light.md, spelled out in the one file those
   three pages do load: same tint, same hairline, same padding, same radius,
   same 13px. The class name and the .open switch are untouched, because
   login.js / reset.js / complete-signup.js all drive it by classList and
   write the message straight onto the element with textContent.
   Two things changed. The border literal rgba(215,56,46,.3) was already
   --danger-line to the digit, so it says so now; and the text moves from
   --danger to --danger-text, which is the step that flips — --danger on
   --danger-soft is 3.2:1 on the dark canvas, and these three pages honour
   the theme toggle like every other. ───────────── */
.error-banner{background:var(--danger-soft);color:var(--danger-text);border:1px solid var(--danger-line);border-radius:var(--radius);padding:12px 14px;font-size:13px;line-height:1.5;margin-bottom:14px;display:none;}
.error-banner.open{display:block;}

/* Its neutral sibling, and the reason it is here: login.html and reset.html
   each carried a private, byte-identical copy of this rule. One copy now, in
   the one file both pages load, sharing .error-banner's geometry above so the
   two banners read as one object in two moods rather than as two shapes.
   NO display switch, deliberately: reset.html's #doneMessage carries no inline
   display of its own and is revealed by its PARENT panel, so a display:none
   here would permanently hide the "password updated" confirmation. Both pages
   drive visibility through el.style.display, exactly as before. */
.success-banner{background:var(--bg-muted);color:var(--text-primary);border:1px solid var(--border);border-radius:var(--radius);padding:12px 14px;font-size:13px;line-height:1.5;margin-bottom:14px;}

/* The third member of the same family: the standing note that explains a gate
   BEFORE it fires, rather than a banner that reports one after. Used by the
   "create an organization" form on login.html and complete-signup.html, which
   is invitation-only server-side (middleware/auth.js resolveSignupCode) and
   used to look optional. Declared here, once, so the two pages do not start a
   fresh copy-paste pair the moment the last one was folded away. */
.gate{background:var(--bg-muted);border:1px solid var(--border);border-radius:var(--radius);padding:11px 13px;font-size:12.5px;line-height:1.5;color:var(--text-secondary);margin-bottom:16px;}
.gate strong{color:var(--text-primary);font-weight:600;}
.req{font-size:10.5px;font-weight:600;text-transform:uppercase;letter-spacing:.05em;color:var(--accent-text);margin-left:6px;}

/* The toast is NOT an .alert and deliberately did not merge into one: it is
   fixed-position, pill-shaped, auto-dismissing and opaque in both themes.
   They share a palette, not a component.
   What did change is where its colour comes from. app.js and alice.js both
   wrote `el.style.background = isError ? var(--danger) : var(--accent-deep)`
   on every single call, which (a) is an inline style write, and the house
   rule is that colour stays in CSS, and (b) meant the rgba(28,27,25,.92)
   that used to stand here never once painted — the inline style won every
   time. So the two states are classes now and the values below are the ones
   that were REALLY on screen, not the dead one they were hiding.
   app.js toggles .error; alice.js still writes the inline style and is
   unaffected either way, since an inline style outranks both rules. */
.toast{position:fixed;bottom:22px;left:50%;transform:translateX(-50%) translateY(10px);background:var(--accent-deep);backdrop-filter:blur(20px);-webkit-backdrop-filter:blur(20px);color:#fff;padding:13px 22px;border-radius:var(--radius-pill);font-size:14px;font-weight:500;box-shadow:0 12px 40px rgba(0,0,0,.3);z-index:100;opacity:0;transition:opacity .22s,transform .22s;pointer-events:none;}
.toast.error{background:var(--danger);}
.toast.show{opacity:1;transform:translateX(-50%) translateY(0);}

::-webkit-scrollbar{width:8px;height:8px;}
::-webkit-scrollbar-thumb{background:rgba(60,60,67,.26);border-radius:5px;}
::-webkit-scrollbar-track{background:transparent;}

.modal-backdrop{position:fixed;inset:0;background:rgba(0,0,0,.32);backdrop-filter:blur(2px);-webkit-backdrop-filter:blur(2px);display:none;align-items:center;justify-content:center;z-index:50;}
.modal-backdrop.open{display:flex;}
.modal{background:var(--bg-surface);border:none;border-radius:var(--radius-lg);padding:26px;width:440px;max-width:92vw;max-height:86vh;overflow-y:auto;box-shadow:0 30px 80px -20px rgba(0,0,0,.4);}
.modal h3{font-size:20px;font-weight:600;margin-bottom:16px;letter-spacing:-.02em;}
.modal .field{margin-bottom:14px;}
.modal .actions{display:flex;justify-content:flex-end;gap:10px;margin-top:20px;}

/* iOS grouped-table treatment for the shared .data-table (CRM contacts,
   pipeline, forms, tasks, workflows, sequences, booking, Ads, agency clients).
   Styling it once lifts every screen that uses it. */
.data-table{width:100%;border-collapse:separate;border-spacing:0;background:var(--bg-surface);border-radius:var(--radius-lg);overflow:hidden;box-shadow:var(--shadow-card);font-size:14px;}
.data-table thead th{background:transparent;text-align:left;padding:12px 16px;font-size:12px;font-weight:600;letter-spacing:-.005em;color:var(--text-secondary);border-bottom:.5px solid var(--sep);}
.data-table tbody td{padding:13px 16px;border-bottom:.5px solid var(--sep);color:var(--text-primary);vertical-align:middle;}
.data-table tbody tr:last-child td{border-bottom:none;}
.data-table tbody tr{transition:background .12s;}
.data-table tbody tr:hover{background:rgba(120,120,128,.05);}
.data-table td .empty-note,.data-table .empty-note{color:var(--text-tertiary);}

/* Shared iOS surfaces used across CRM and Settings. */
.invite-box{display:flex;align-items:center;gap:10px;background:var(--bg-surface);border:none;border-radius:var(--radius);padding:13px 15px;box-shadow:var(--shadow-card);font-size:14px;}
.member-row{display:flex;justify-content:space-between;align-items:center;background:var(--bg-surface);border:none;border-radius:var(--radius);padding:11px 14px;font-size:14px;gap:10px;box-shadow:var(--shadow-card);margin-bottom:8px;}
.usage-box{border:none;border-radius:var(--radius-lg);padding:16px 18px;background:var(--bg-surface);box-shadow:var(--shadow-card);max-width:560px;}
.dropzone{border:1.5px dashed var(--border);border-radius:var(--radius-lg);}
.code-box{background:var(--bg-muted);border:none;border-radius:var(--radius);}

/* Avatar/initials circle — used for contacts and people rows, iOS style. */
.avatar-ios{width:38px;height:38px;border-radius:50%;background:var(--accent-deep);color:#fff;display:inline-flex;align-items:center;justify-content:center;font-size:14px;font-weight:600;flex:none;}

/* Segmented control (iOS) — for tab-like switches inside views. */
.seg-ios{display:inline-flex;background:rgba(120,120,128,.12);border-radius:9px;padding:2px;gap:2px;}
.seg-ios button{border:none;background:transparent;padding:6px 14px;border-radius:7px;font-size:13px;font-weight:600;color:var(--text-primary);}
.seg-ios button.on{background:var(--bg-surface);box-shadow:0 1px 3px rgba(0,0,0,.12);}

/* ===================================================================
   Contacts database — smart lists, bulk actions, CSV import.
   Design patterns borrowed from 21st.dev (filter pills, sticky bulk
   bar, drop-zone) and rebuilt in vanilla CSS so the portal keeps its
   no-build-step, strict-CSP architecture. Tokens only, no new colors.
   =================================================================== */

.cdb-bar{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-bottom:10px;}
.cdb-spacer{flex:1;}
.cdb-views{display:flex;gap:6px;flex-wrap:wrap;align-items:center;}

.cdb-view{display:inline-flex;align-items:center;gap:6px;padding:5px 11px;border-radius:var(--radius-pill);
  border:1px solid var(--border);background:var(--bg-surface);font-size:12.5px;font-weight:500;
  color:var(--text-secondary);cursor:pointer;transition:border-color .12s,color .12s,background .12s;}
.cdb-view:hover{border-color:var(--accent-bright);color:var(--text-primary);}
.cdb-view.on{background:var(--accent-soft);border-color:var(--accent-bright);color:var(--accent-text-soft);font-weight:600;}
.cdb-view .x{opacity:.45;font-size:14px;line-height:1;}
.cdb-view .x:hover{opacity:1;color:var(--danger);}

.cdb-filters{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin-bottom:12px;}
.cdb-select{padding:6px 10px;border:1px solid var(--border);border-radius:8px;background:var(--bg-surface);
  font-size:12.5px;color:var(--text-primary);font-family:inherit;}
.cdb-tags{display:flex;gap:5px;flex-wrap:wrap;}
.cdb-tag{padding:3px 9px;border-radius:var(--radius-pill);border:1px solid var(--border);
  background:var(--bg-surface);font-size:11.5px;color:var(--text-secondary);cursor:pointer;}
.cdb-tag:hover{border-color:var(--accent-bright);}
.cdb-tag.on{background:var(--accent-deep);border-color:var(--accent-deep);color:#fff;font-weight:600;}
.cdb-tag .n{opacity:.6;margin-left:4px;}
.cdb-count{font-size:12px;color:var(--text-tertiary);margin-left:auto;}

/* Row selection */
.cdb-row{display:flex;align-items:center;gap:10px;}
.cdb-check{width:16px;height:16px;accent-color:var(--accent-bright);flex:none;cursor:pointer;}
.cdb-selected{background:var(--accent-soft) !important;}

/* Sticky bulk bar — appears only with a selection.
   The fill used to be var(--text-primary), which is near-BLACK in light mode
   and near-WHITE in dark, while every label on it is hardcoded white: in dark
   mode the whole bar read white-on-white and the controls vanished (the
   dark-parity checklist's §6.7). It is --accent-deep now, which is the same
   colour in both themes and says the right thing besides — a selection you
   made and are about to act on is a USER act, and orange is what the user's
   own actions look like everywhere else in this product. */
.cdb-bulk{position:sticky;bottom:12px;z-index:20;display:flex;align-items:center;gap:8px;flex-wrap:wrap;
  padding:10px 14px;margin:12px 0;border-radius:var(--radius-lg);
  background:var(--accent-deep);box-shadow:0 8px 28px -8px rgba(17,17,20,.45);
  animation:cdbRise .16s ease-out;}
@keyframes cdbRise{from{opacity:0;transform:translateY(8px);}to{opacity:1;transform:none;}}
.cdb-bulk-n{color:var(--on-accent);font-size:12.5px;font-weight:600;margin-right:4px;}
.cdb-bulk-input{padding:5px 9px;border-radius:7px;border:1px solid rgba(255,255,255,.22);
  background:rgba(255,255,255,.1);color:var(--on-accent);font-size:12.5px;width:110px;font-family:inherit;}
.cdb-bulk-input::placeholder{color:rgba(255,255,255,.45);}
.cdb-bulk .cdb-select{background:rgba(255,255,255,.1);border-color:rgba(255,255,255,.22);color:var(--on-accent);}
.cdb-bulk .cdb-select option{color:var(--text-primary);}
.btn.danger{background:var(--danger);border-color:var(--danger);color:#fff;}
.btn.danger:hover{filter:brightness(1.08);}

/* Import drawer */
.cdb-import{border:1px solid var(--border);border-radius:var(--radius-lg);padding:16px;
  margin-bottom:14px;background:var(--bg-surface);box-shadow:var(--shadow-card);}
.cdb-import-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:12px;}
.cdb-drop{border:1.5px dashed var(--border);border-radius:var(--radius);padding:26px 16px;text-align:center;
  cursor:pointer;transition:border-color .14s,background .14s;color:var(--text-secondary);font-size:13px;}
.cdb-drop:hover,.cdb-drop:focus-visible,.cdb-drop.over{border-color:var(--accent-bright);background:var(--accent-soft);outline:none;}
.cdb-drop-i{font-size:22px;color:var(--accent-text-soft);margin-bottom:6px;}
.cdb-drop-sub{font-size:11.5px;color:var(--text-tertiary);margin-top:5px;}

.cdb-map-head{font-size:12px;font-weight:600;color:var(--text-secondary);margin:14px 0 8px;
  text-transform:uppercase;letter-spacing:.08em;}
.cdb-map{display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:8px;}
.cdb-map-row{display:flex;align-items:center;gap:8px;font-size:12.5px;}
.cdb-map-row label{flex:none;width:76px;color:var(--text-secondary);}
.cdb-map-row select{flex:1;min-width:0;}

.cdb-stats{display:flex;gap:8px;flex-wrap:wrap;margin:14px 0 0;}
.cdb-stat{padding:9px 13px;border-radius:var(--radius);border:1px solid var(--border);min-width:82px;}
.cdb-stat b{display:block;font-size:19px;font-weight:700;line-height:1.15;}
.cdb-stat span{font-size:11px;color:var(--text-secondary);}
.cdb-stat.ok b{color:var(--success);}
.cdb-stat.dup b{color:var(--heat-amber);}
.cdb-stat.err b{color:var(--danger);}

.cdb-issues{margin-top:10px;max-height:150px;overflow:auto;font-size:12px;}
.cdb-issue{padding:5px 9px;border-radius:7px;margin-bottom:4px;background:var(--bg-muted);color:var(--text-secondary);}
.cdb-issue b{color:var(--text-primary);font-weight:600;}
.cdb-import-actions{display:flex;align-items:center;gap:8px;margin-top:14px;}
.cdb-note{font-size:12px;color:var(--text-secondary);}
.cdb-empty{padding:26px;text-align:center;color:var(--text-tertiary);font-size:13px;}

/* ===================================================================
   Document pages — terms.html, privacy.html, sms-terms.html,
   sms-opt-in.html, plus the two lead-facing standalone pages
   (book.html, unsubscribe.html) that borrow the same masthead.

   This block was copy-pasted VERBATIM into four legal pages' inline
   <style> elements. All four already load this file and nothing else,
   so this is its honest home: one copy, one place to fix. No selector
   was renamed and no page's markup moved.

   Three things changed on the way in:

     * .doc a was var(--accent-deep). That token means "a FILL that
       carries white text"; used AS text on the dark canvas it is
       4.21:1 — a real failure now that these pages load /theme.js and
       can actually go dark. --accent-text is the step that exists for
       orange text (5.09:1 light, #F0873F dark) and it is what the
       global `a` rule near the top of this file already uses.
     * The white on --accent-deep fills (sms-terms' numbered steps,
       sms-opt-in's mock CTA) became --on-accent, the token for exactly
       that, which is white in BOTH themes by design.
     * body{padding:0;} was dropped: the `*` reset at the top of this
       file already zeroes it, so all four copies were dead weight.

   .logo here is the 18px document wordmark. login.html, reset.html and
   complete-signup.html declare their own 22px .logo inside their inline
   <style>, which the browser reads AFTER this sheet and which restates
   every property below, so those three pages are unaffected.
   =================================================================== */
.topbar{border-bottom:1px solid var(--border);background:var(--bg-surface);padding:16px 24px;display:flex;align-items:center;justify-content:space-between;}
.logo{font-family:var(--font-serif);font-size:18px;font-weight:700;color:var(--accent-deep);display:flex;align-items:center;gap:8px;}
.logo .mark{width:24px;height:24px;border:1.5px solid var(--accent-deep);border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:12px;}
.doc{max-width:760px;margin:0 auto;padding:48px 24px 80px;}
.doc .eyebrow{display:block;margin-bottom:10px;}
.doc h1{font-size:32px;margin-bottom:8px;}
.updated{color:var(--text-secondary);font-size:13px;margin-bottom:8px;}
.notice{background:var(--accent-soft);border:1px solid var(--accent);border-radius:6px;padding:14px 16px;font-size:13px;color:var(--text-primary);margin:20px 0 32px;}
.doc h2{font-size:19px;margin:32px 0 10px;}
.doc p,.doc li{font-size:14px;color:var(--text-primary);margin-bottom:12px;}
.doc ul{padding-left:20px;margin-bottom:12px;}
.doc a{color:var(--accent-text);text-decoration:underline;}
