* { box-sizing: border-box; margin: 0; padding: 0; }
body { background: #0f0d1a; font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", Arial, sans-serif; }
.page { background: #0f0d1a; min-height: 100vh; min-height: 100dvh; display: flex; flex-direction: column; align-items: center; }
/* Single-provider mode: the multi-provider services UI is irrelevant
   and would flash visibly before initSingleProviderMode injects its
   waiting screen. The pre-init script in <body> sets this class on
   the html element synchronously when the launch payload includes a
   service_id, so the multi-provider chrome is hidden from first paint.
   NOTE: do NOT hide .page wholesale — .profile-view lives inside it
   and is needed for the post-connect profile selector. We hide the
   specific multi-provider chrome elements only. */
html.single-provider-mode body { background: #000; }
/* Hide the multi-provider chrome by ID, not by class. The install-
   extension error screen built by showSingleProviderError() reuses
   the .ext-banner class on a freshly-created element (no ID) — if we
   hid by class here, that error screen would be invisible too. */
html.single-provider-mode .header,
html.single-provider-mode #extBanner,
html.single-provider-mode .service-list,
html.single-provider-mode .footer { display: none !important; }
html.single-provider-mode .page,
html.single-provider-mode .inner,
html.single-provider-mode .bottom-bar { background: #000; }
.inner { width: 100%; max-width: 480px; display: flex; flex-direction: column; min-height: 100vh; min-height: 100dvh; }

.header { background: #1a1430; padding: 16px 20px; display: flex; align-items: center; gap: 16px; border-bottom: 0.5px solid rgba(255,255,255,0.08); }
.back-btn {
  color: #c084fc;
  font-size: 32px;
  font-weight: 700;
  cursor: pointer;
  line-height: 1;
  padding: 4px 10px;
  border-radius: 8px;
  /* The ‹ glyph (U+2039) sits visually below its baseline center,
     so flex's align-items: center on the parent doesn't actually
     line it up with the title text. Pull it up to match — value
     dialed in by measuring the arrow's bounding-box center against
     the "S" glyph's bounding-box center in the rendered header,
     then bumping an additional 1px up for optical centering (the S
     glyph's lower bowl gives it a perceptual center slightly above
     its geometric center). */
  transform: translateY(-1.5px);
  transition: background 0.15s, color 0.15s, transform 0.15s;
}
.back-btn:hover { color: #d8b4fe; background: rgba(192,132,252,0.12); }
.header-title { color: #fff; font-size: 18px; font-weight: 500; flex: 1; text-align: center; margin-right: 24px; }

.section-label { color: rgba(255,255,255,0.35); font-size: 11px; font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase; padding: 18px 20px 8px; }

.service-row { display: flex; align-items: center; gap: 16px; padding: 14px 20px; border-bottom: 0.5px solid rgba(255,255,255,0.07); transition: background 0.15s; }
.service-row.connected { cursor: pointer; }
.service-row.connected:hover { background: rgba(255,255,255,0.04); }
.service-row.unconnected { opacity: 0.75; }

.service-icon { width: 56px; height: 56px; border-radius: 12px; flex-shrink: 0; overflow: hidden; background: #1a1a2e; display: flex; align-items: center; justify-content: center; position: relative; }
.service-icon img { width: 100%; height: 100%; object-fit: cover; display: block; position: absolute; top: 0; left: 0; border-radius: 12px; }
.icon-fallback { color: rgba(255,255,255,0.4); font-size: 18px; font-weight: 600; }

.service-info { flex: 1; min-width: 0; }
.service-name { color: #fff; font-size: 16px; font-weight: 400; margin-bottom: 3px; display: flex; align-items: center; gap: 8px; }
.service-email { color: rgba(255,255,255,0.5); font-size: 13px; margin-bottom: 3px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* Defensive: some mobile browsers still auto-linkify email text even with
   the format-detection meta tag above. Strip the link styling so the email
   reads as plain text and doesn't open a mail client on tap. */
.service-email a, .action-sheet-subtitle a { color: inherit; text-decoration: none; pointer-events: none; }
.service-profile { display: flex; align-items: center; gap: 6px; color: rgba(255,255,255,0.5); font-size: 13px; }
.profile-avatar { width: 16px; height: 16px; border-radius: 50%; background: rgba(255,255,255,0.2); flex-shrink: 0; display: flex; align-items: center; justify-content: center; }
.profile-avatar svg { width: 12px; height: 12px; }
.chevron { color: rgba(255,255,255,0.25); font-size: 14px; flex-shrink: 0; }

.broken-badge { display: inline-flex; align-items: center; justify-content: center; width: 18px; height: 18px; border-radius: 50%; background: #f59e0b; flex-shrink: 0; font-size: 11px; font-weight: 700; color: #000; }

.connect-btn { flex-shrink: 0; background: #7c3aed; color: #fff; border: none; border-radius: 20px; padding: 7px 16px; font-size: 13px; font-weight: 600; cursor: pointer; transition: background 0.15s; white-space: nowrap; }
.connect-btn:hover { background: #6d28d9; }
.connect-btn:disabled { background: #3b2a6e; color: rgba(255,255,255,0.4); cursor: default; }
.connect-btn.connecting { background: #4c1d95; }

.status { padding: 48px 20px; text-align: center; color: rgba(255,255,255,0.4); font-size: 14px; }

/* Top-anchored toast. `position: fixed` + `top` locks it to the top
   of the viewport so it stays visible while the user scrolls. Docked
   just below where the header typically ends so it reads as a banner
   rather than floating in mid-air. Slides down from the top when
   shown (via `translateY`) and fades in. */
/* z-index 101: one above the single-provider fullscreen overlays (100) so toasts
   (e.g. the install-watch "Extension installed — connecting…") stay visible there. */
.toast { position: fixed; top: 72px; left: 50%; transform: translate(-50%, -12px); background: #1e1b4b; border: 1px solid #4c1d95; color: #e9d5ff; padding: 10px 20px; border-radius: 24px; font-size: 13px; font-weight: 500; opacity: 0; transition: opacity 0.3s, transform 0.3s; pointer-events: none; z-index: 101; max-width: calc(100% - 32px); text-align: center; line-height: 1.4; }
.toast.show { opacity: 1; transform: translate(-50%, 0); }
.toast.success { background: #14532d; border-color: #166534; color: #bbf7d0; }
.toast.error { background: #7f1d1d; border-color: #991b1b; color: #fecaca; }
.toast.info { background: #1e3a5f; border-color: #1d4ed8; color: #bfdbfe; }
.toast.warning { background: #78350f; border-color: #92400e; color: #fde68a; }

.ext-banner {
  margin: 16px 20px;
  padding: 16px 18px;
  background: #1e1430;
  border: 1px solid #4c1d95;
  border-radius: 12px;
  color: #e4e4e7;
  font-size: 14px;
  line-height: 1.55;
  text-align: center;
  display: none;
  position: relative; /* anchors the corner .ext-close ✕ */
}
.ext-banner.show { display: block; }
/* Corner ✕ that dismisses the install/update prompt (banner + single-provider error). */
.ext-close { position: absolute; top: 8px; right: 10px; background: none; border: none; padding: 4px 6px; color: rgba(255,255,255,0.8); font-size: 13px; font-weight: 700; line-height: 1; cursor: pointer; }
.ext-banner strong { display: block; color: #fff; font-size: 15px; font-weight: 600; margin-bottom: 4px; }
.ext-banner p { margin: 0; color: rgba(255,255,255,0.7); }
.ext-banner a {
  display: inline-block;
  margin: 10px 4px 0;
  padding: 8px 14px;
  background: #6d28d9;
  color: #fff !important;
  border-radius: 6px;
  font-weight: 500;
  font-size: 13px;
  text-decoration: none;
}
.ext-banner a:hover { background: #7c3aed; }

.footer { background: #0a0814; border-top: 0.5px solid rgba(255,255,255,0.08); padding: 10px 12px 14px; font-size: 11px; color: rgba(255,255,255,0.38); text-align: center; line-height: 1.35; letter-spacing: 0.01em; }
.footer a { color: #6b63c9; text-decoration: none; }

/* ── Sticky chrome (BOTH views) ───────────────────────────────────────────────
   The whole page (document) scrolls, so the mouse wheel / trackpad / scrollbar
   work anywhere — over the header, the disclaimer, and the side gutters — not
   just over a middle list. The header + ext-banner pin together at the top
   (.top-bar); the profile Continue button + disclaimer pin together at the
   bottom (.bottom-bar). Wrapping each pinned region into ONE sticky element keeps
   Continue directly above the disclaimer with pure CSS — no measuring the
   disclaimer's variable height. margin-top:auto on the bottom bar holds it at the
   viewport bottom even when the content above is short (otherwise a short list
   would leave the disclaimer floating mid-viewport). Single-provider mode hides
   the chrome INSIDE these bars (its own fixed overlays take over); the empty bars
   stay harmless. .page/.inner keep their base min-height:100vh, which gives the
   document its scroll height. */
.top-bar    { position: sticky; top: var(--yc-banner-pad, 0px); z-index: 20; }
/* Opaque background so a long profile list scrolls UNDER the pinned bar, not
   visibly behind the Continue button. Matches the page background (the footer
   paints its own darker tone on top of this in its area). Single-provider mode
   overrides to its black page background below. */
.bottom-bar { position: sticky; bottom: 0; z-index: 20; background: #0f0d1a; }

/* The active middle view GROWS to fill the space between the bars, which keeps
   the bottom bar (disclaimer) pinned to the viewport bottom even when the content
   is short — and gives the loading/empty status message room to center in. Basis
   auto (not 0) so a long list still lays out at its content height and the page
   scrolls. (This replaces a margin-top:auto on the bottom bar, which would have
   starved the middle of the free space it needs to grow.) */
.service-list, .profile-view.active { flex: 1 0 auto; }

/* Services list: a flex column so a lone status message (loading / empty /
   error — i.e. no rows yet) can center vertically; once real rows exist, revert
   to top-alignment. */
.service-list { display: flex; flex-direction: column; }
.service-list:not(:has(.service-row)) { justify-content: center; }

/* Profile selector view — plain document flow (masthead, heading, list scroll
   with the page). Continue lives in .bottom-bar and shows only while active. */
.profile-view { display: none; flex-direction: column; }
.profile-view.active { display: flex; }
.profile-service-logo { width: 100%; overflow: hidden; }
.profile-service-logo img { width: 100%; height: auto; display: block; object-fit: cover; }
.profile-heading { text-align: center; color: #fff; font-size: 17px; font-weight: 500; padding: 22px 20px 20px; background: #000; }
/* Theme the internal scroll to match our palette (the default gray is ugly on
   the dark profile view). Purple accent (#7c3aed) thumb on a transparent track;
   Firefox gets the standardized scrollbar-color. */
/* Themed document scrollbar (both views now scroll the page). Purple accent
   (#7c3aed) thumb on a transparent track. scrollbar-gutter:stable ALWAYS reserves
   the scrollbar's space, so the page width (and the centered content) doesn't
   shift by ~10px between a view that scrolls (services list) and one that fits
   (a short profile picker). */
html { scrollbar-width: thin; scrollbar-color: rgba(124,58,237,0.55) transparent; scrollbar-gutter: stable; }
html::-webkit-scrollbar { width: 8px; }
html::-webkit-scrollbar-track { background: transparent; }
html::-webkit-scrollbar-thumb { background: rgba(124,58,237,0.55); border-radius: 4px; }
html::-webkit-scrollbar-thumb:hover { background: rgba(124,58,237,0.8); }
.profile-row { display: flex; align-items: center; gap: 0; padding: 0; border-bottom: 0.5px solid rgba(255,255,255,0.08); cursor: pointer; transition: background 0.15s; min-height: 80px; }
.profile-row:hover { background: rgba(255,255,255,0.04); }
.profile-row.selected { background: rgba(255,255,255,0.06); }
.profile-avatar-img { width: 80px; height: 80px; border-radius: 0; overflow: hidden; flex-shrink: 0; background: #2a2040; display: flex; align-items: center; justify-content: center; }
.profile-avatar-img img { width: 100%; height: 100%; object-fit: cover; }
.profile-name { color: #fff; font-size: 17px; font-weight: 400; flex: 1; padding-left: 18px; }
.profile-kids-badge { font-size: 11px; color: #7c3aed; margin-left: 6px; }
.profile-check { width: 48px; display: flex; align-items: center; justify-content: center; flex-shrink: 0; visibility: hidden; }
.profile-row.selected .profile-check { visibility: visible; }
/* Lock badge on PIN-protected profiles (mobile parity): sits BETWEEN the avatar
   and the name (mobile constrains the name's start to the lock's end). It takes
   the name's normal 18px left offset from the avatar; the name then tucks in
   right after it. */
.profile-lock { display: flex; align-items: center; justify-content: center; flex-shrink: 0; padding-left: 18px; }
.profile-lock + .profile-name { padding-left: 8px; }
.action-sheet-overlay { position: fixed; inset: 0; background: rgba(0,0,0,0.75); display: flex; align-items: center; justify-content: center; z-index: 200; padding: 24px; }
.action-sheet { background: #1a1a2e; border-radius: 20px; width: 100%; max-width: 340px; overflow: hidden; position: relative; }
.action-sheet-close { position: absolute; top: 10px; right: 10px; width: 32px; height: 32px; border-radius: 50%; background: transparent; border: none; color: rgba(255,255,255,0.45); font-size: 20px; line-height: 1; cursor: pointer; display: flex; align-items: center; justify-content: center; transition: background 0.15s, color 0.15s; padding: 0; }
.action-sheet-close:hover { background: rgba(255,255,255,0.08); color: rgba(255,255,255,0.85); }
.action-sheet-header { padding: 28px 24px 20px; text-align: center; }
.action-sheet-logo { width: 56px; height: 56px; border-radius: 12px; object-fit: contain; background: rgba(255,255,255,0.05); margin: 0 auto 14px; display: flex; align-items: center; justify-content: center; overflow: hidden; }
.action-sheet-logo img { width: 100%; height: 100%; object-fit: contain; }
.action-sheet-title { color: #fff; font-size: 18px; font-weight: 700; letter-spacing: 0.05em; margin-bottom: 4px; }
.action-sheet-profile { color: rgba(255,255,255,0.85); font-size: 15px; font-weight: 500; margin-bottom: 2px; }
.action-sheet-subtitle { color: rgba(255,255,255,0.35); font-size: 12px; }
.action-sheet-btn { display: block; width: 100%; padding: 15px 24px; background: rgba(255,255,255,0.06); border: none; border-top: 1px solid rgba(255,255,255,0.06); color: rgba(255,255,255,0.9); font-size: 14px; font-weight: 500; text-align: center; cursor: pointer; transition: background 0.15s; }
.action-sheet-btn:hover { background: rgba(255,255,255,0.1); }
.action-sheet-btn.destructive { color: #f87171; }
.action-sheet-btn.primary { color: #c4b5fd; font-weight: 600; }
.kids-modal-overlay { position: fixed; inset: 0; background: rgba(0,0,0,0.75); display: flex; align-items: center; justify-content: center; z-index: 200; padding: 24px; }
.kids-modal { background: #1a1430; border-radius: 16px; padding: 28px 24px; max-width: 340px; width: 100%; text-align: center; }
.kids-modal p { color: rgba(255,255,255,0.85); font-size: 14px; line-height: 1.6; margin-bottom: 20px; }
.kids-modal button { background: #7c3aed; color: #fff; border: none; border-radius: 20px; padding: 10px 28px; font-size: 14px; font-weight: 600; cursor: pointer; }
.kids-modal button:hover { background: #6d28d9; }
/* Full-page blocking loader for manage-dialog async actions (e.g. Change
   Profile's host-side getProfiles) so the page can't be interacted with while
   it loads. z-index above the action sheet / modals (200). */
.manage-loading-overlay { position: fixed; inset: 0; background: rgba(0,0,0,0.8); display: flex; flex-direction: column; align-items: center; justify-content: center; z-index: 300; padding: 24px; }
/* Debug ?ghostoverlay: translucent veil so the page behind stays visible. */
.manage-loading-overlay.ghost { background: rgba(0,0,0,0.35); }
.manage-loading-spinner { width: 48px; height: 48px; border-radius: 50%; border: 4px solid rgba(255,255,255,0.15); border-top-color: #7c3aed; animation: manage-spin 0.8s linear infinite; margin-bottom: 20px; }
.manage-loading-text { color: rgba(255,255,255,0.85); font-size: 15px; font-weight: 500; text-align: center; }
@keyframes manage-spin { to { transform: rotate(360deg); } }
/* PIN entry modal — reuses .kids-modal-overlay layout but has its own inner container for multi-button + digit-grid */
.pin-modal { background: #1a1430; border-radius: 16px; padding: 24px; max-width: 340px; width: 100%; text-align: center; }
.pin-modal-title { color: #fff; font-size: 16px; font-weight: 600; margin-bottom: 20px; }
.pin-modal-profile { color: rgba(255,255,255,0.7); font-size: 13px; margin-bottom: 6px; }
/* Wrapper (flex-centres the field, provides the bottom gap). Named "digits"
   historically for the fixed per-digit boxes; now holds one generic full-width
   PIN field (.pin-modal-input) since PIN length is a per-provider detail we
   don't yet model. The old `.pin-modal-digits input` box rules were removed —
   at (0,1,1) they out-specified `.pin-modal-input` (0,1,0) and forced the field
   to a single 44px digit box. */
.pin-modal-digits { display: flex; gap: 10px; justify-content: center; margin-bottom: 16px; }
.pin-modal-input { width: 100%; box-sizing: border-box; height: 56px; background: #2a2040; border: 1px solid rgba(255,255,255,0.15); border-radius: 10px; color: #fff; font-size: 24px; text-align: center; font-weight: 600; letter-spacing: 8px; outline: none; transition: border-color 0.15s; -webkit-text-security: disc; }
.pin-modal-input:focus { border-color: #7c3aed; }
.pin-modal-input.error { border-color: #f87171; }
/* Fixed-digit mode: one box per digit (channelOf().pinLength > 0). A distinct
   class from .pin-modal-input — NOT a `.pin-modal-digits input` descendant rule
   — so the two never fight on specificity (that collision is what shrank the
   generic field to a single 44px box). */
.pin-modal-box { width: 44px; height: 56px; flex-shrink: 0; background: #2a2040; border: 1px solid rgba(255,255,255,0.15); border-radius: 10px; color: #fff; font-size: 24px; text-align: center; font-weight: 600; outline: none; transition: border-color 0.15s; -webkit-text-security: disc; }
.pin-modal-box:focus { border-color: #7c3aed; }
.pin-modal-box.error { border-color: #f87171; }
/* Kill Edge's native password reveal ("eye") and clear ("×") buttons. On a
   type=password field Edge injects these inside the input on the right; they use
   their own light color scheme (ugly on our dark modal) and consume content
   width, which shoves the centered PIN off to the left as soon as you type.
   We already have -webkit-text-security masking, so the reveal is redundant. */
.pin-modal-input::-ms-reveal, .pin-modal-input::-ms-clear,
.pin-modal-box::-ms-reveal, .pin-modal-box::-ms-clear { display: none; width: 0; height: 0; }
.pin-modal-error { color: #f87171; font-size: 13px; min-height: 18px; margin-bottom: 16px; }
.pin-modal-buttons { display: flex; gap: 10px; justify-content: center; }
.pin-modal-buttons button { flex: 1; border: none; border-radius: 20px; padding: 10px 20px; font-size: 14px; font-weight: 600; cursor: pointer; transition: background 0.15s; }
.pin-modal-buttons .pin-cancel { background: rgba(255,255,255,0.08); color: rgba(255,255,255,0.85); }
.pin-modal-buttons .pin-cancel:hover { background: rgba(255,255,255,0.14); }
.pin-modal-buttons .pin-ok { background: #7c3aed; color: #fff; }
.pin-modal-buttons .pin-ok:hover { background: #6d28d9; }
.pin-modal-buttons .pin-ok:disabled { background: rgba(124, 58, 237, 0.35); cursor: not-allowed; }
/* Continue lives in the shared .bottom-bar; show it only while the picker is
   active (in the services list the bottom-bar is just the disclaimer). */
.profile-continue-wrap { display: none; padding: 20px 20px 20px; justify-content: center; }
.inner:has(.profile-view.active) .profile-continue-wrap { display: flex; }
.profile-continue-btn { width: 70%; max-width: 280px; padding: 16px; background: #4c6ef5; color: #fff; border: none; border-radius: 50px; font-size: 16px; font-weight: 600; cursor: pointer; transition: opacity 0.2s, background 0.2s; }
.profile-continue-btn:disabled { opacity: 0.4; cursor: default; }
.profile-continue-btn:not(:disabled):hover { background: #3b5bdb; }
