/* ======================================================================
   wizard.css — the public monitor-creation wizard (`/new`).

   Split out of app-user.css (2026-08-21). These rules were authored for the
   marketing `site` layout but lived in the *user-area* stylesheet, which the
   `site` layout never loads — so `/new` rendered with no styling at all (all
   four steps stacked and visible). Keeping them in their own file makes the
   dependency explicit: the wizard view asks the layout for this sheet.

   Self-contained on purpose — it only leans on site.css tokens (--purple,
   --line, --muted, --purple-soft) and the shared .btn, each with a literal
   fallback so a token rename can never blank the page again.
   ====================================================================== */

.wz{max-width:660px;margin:0 auto;padding:44px 18px 90px}

/* ---- progress rail ---- */
.wz-steps{display:flex;gap:8px;list-style:none;padding:0;margin:0 0 30px}
.wz-steps li{flex:1;height:4px;border-radius:999px;background:var(--line,#ece9f5);position:relative;
  transition:background .3s ease}
.wz-steps li.is-on{background:var(--purple,#7c5cff)}
.wz-steps li span{position:absolute;left:0;top:10px;font-size:11px;font-weight:700;
  color:var(--muted,#8b8696);text-transform:uppercase;letter-spacing:.05em;white-space:nowrap}
@media (max-width:600px){.wz-steps li span{display:none}}

/* ---- steps ---- */
.wz-step{display:none}
.wz-step.is-on{display:block;animation:wz-in .3s cubic-bezier(.2,.8,.3,1) backwards}
@keyframes wz-in{from{opacity:0;transform:translateY(10px)}}
.wz-h1{font-size:27px;font-weight:800;letter-spacing:-.02em;margin:0 0 7px}
.wz-sub{color:var(--muted,#8b8696);margin:0 0 22px;font-size:15px}

/* ---- step 1: the URL bar ---- */
.wz-urlbar{display:flex;gap:10px;flex-wrap:wrap}
.wz-urlbar input{flex:1;min-width:220px;padding:15px 17px;border-radius:14px;
  border:1.5px solid var(--line,#ece9f5);font:inherit;font-size:15px;background:#fff;color:inherit}
.wz-urlbar input:focus{outline:none;border-color:var(--purple,#7c5cff);
  box-shadow:0 0 0 4px rgba(124,92,255,.13)}
.wz-err{color:#e11d48;font-size:13.5px;font-weight:600;margin:11px 0 0}

/* Honest live-check block (§D): ONE status line (spinner + text), tips underneath as
   secondary ambience — never a faked multi-step bar. */
.wz-checking{margin-top:18px}
.wz-status{display:flex;align-items:center;gap:11px;margin:0;color:var(--ink,#1d1b2e);
  font-size:14.5px;font-weight:600}
.wz-tips{margin:11px 0 0;color:var(--muted,#8b8696);font-size:13.5px;min-height:1.35em}
.wz-spin{width:16px;height:16px;border-radius:50%;border:2px solid var(--line,#ece9f5);
  border-top-color:var(--purple,#7c5cff);animation:wz-spin .7s linear infinite;flex:0 0 auto}
@keyframes wz-spin{to{transform:rotate(360deg)}}

/* ---- step 2: interval picker ---- */
.wz-opts{display:grid;gap:11px;grid-template-columns:1fr}
@media (min-width:560px){.wz-opts{grid-template-columns:repeat(2,1fr)}}
.wz-opt{display:flex;flex-direction:column;gap:3px;align-items:flex-start;text-align:left;
  padding:15px 17px;border-radius:15px;border:1.5px solid var(--line,#ece9f5);background:#fff;
  cursor:pointer;font:inherit;transition:border-color .16s ease,transform .16s ease,box-shadow .16s ease}
.wz-opt:hover{transform:translateY(-1px);box-shadow:0 8px 24px rgba(80,60,160,.09)}
.wz-opt.is-on{border-color:var(--purple,#7c5cff);background:var(--purple-soft,#f3effe)}
.wz-opt-label{font-weight:700;font-size:15px}
.wz-opt-plan{font-size:12.5px;color:var(--muted,#8b8696)}
/* Locked-for-plan presets (signed-in only; the API says so). Logged-out paid presets stay
   fully interactive — they get the inline note below instead of this disabled look. */
.wz-opt.is-locked{opacity:.55;cursor:not-allowed}
.wz-opt.is-locked:hover{transform:none;box-shadow:none}
.wz-note{margin:14px 0 0;font-size:13.5px;color:var(--muted,#8b8696)}
.wz-upsell{font-weight:700;margin-left:6px}

/* ---- step 3: channels (multi-select + in-wizard connect, §B) ---- */
.wz-chans{display:flex;flex-direction:column;gap:12px;margin-top:6px}
.wz-chan{border:1.5px solid var(--line,#ece9f5);border-radius:15px;background:#fff;overflow:hidden}
.wz-chan.is-on{border-color:var(--purple,#7c5cff)}
.wz-chan-row{display:flex;align-items:center;gap:12px;width:100%;padding:14px 16px;
  background:none;border:0;cursor:pointer;font:inherit;text-align:left;color:inherit}
.wz-chan-ico{font-size:20px;flex:0 0 auto;line-height:1}
.wz-chan-main{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}
.wz-chan-name{font-weight:700;font-size:15px}
.wz-chan-hint{font-size:12.5px;color:var(--muted,#8b8696);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.wz-chan-check{flex:0 0 auto;width:22px;height:22px;border-radius:7px;position:relative;
  border:2px solid var(--line,#ece9f5);transition:background .15s ease,border-color .15s ease}
.wz-chan.is-on .wz-chan-check{background:var(--purple,#7c5cff);border-color:var(--purple,#7c5cff)}
.wz-chan.is-on .wz-chan-check::after{content:"";position:absolute;left:6px;top:2px;width:6px;height:11px;
  border:solid #fff;border-width:0 2px 2px 0;transform:rotate(45deg)}
/* The channel body is a collapsible section (founder 2026-08-21): animate it
   instead of snapping. `hidden` stays the single source of truth the JS toggles —
   the grid `1fr -> 0fr` trick animates to the content's REAL height (no magic
   max-height that would race a QR panel taller than the cap), the padding lives on
   the inner wrapper so a collapsed body leaves no sliver, and `visibility` keeps it
   out of the a11y tree + tab order — flipped only AFTER the collapse finishes, so
   the exit animation is still visible. */
.wz-connect{display:grid;grid-template-rows:1fr;border-top:1px solid var(--line,#ece9f5);
  opacity:1;visibility:visible;
  transition:grid-template-rows .3s cubic-bezier(.2,.8,.3,1),opacity .22s ease .05s,
             border-top-color .3s ease,visibility 0s}
.wz-connect[hidden]{display:grid;grid-template-rows:0fr;opacity:0;visibility:hidden;
  border-top-color:transparent;
  transition:grid-template-rows .3s cubic-bezier(.2,.8,.3,1),opacity .16s ease,
             border-top-color .3s ease,visibility 0s linear .3s}
.wz-connect-in{overflow:hidden;padding:2px 16px 16px}
.wz-connect-in>*{margin-top:12px}
/* Nested reveals INSIDE an open body (connect panel, add-address, code entry, the
   quota upsell). They toggle `hidden`, so this fires exactly once, on display. */
.wz .wz-connect:not([hidden]) [data-tg-panel]:not([hidden]),
.wz .wz-connect:not([hidden]) [data-email-add]:not([hidden]),
.wz .wz-connect:not([hidden]) [data-email-code]:not([hidden]),
.wz .wz-connect:not([hidden]) [data-email-upsell]:not([hidden]){
  animation:wz-reveal .28s cubic-bezier(.2,.8,.3,1) backwards}
@keyframes wz-reveal{from{opacity:0;transform:translateY(-6px)}}
.wz-poll{color:var(--muted,#8b8696);font-size:12.5px;margin:8px 0 0}
.wz-linkbtn{background:none;border:0;color:var(--purple,#7c5cff);font:inherit;font-size:13px;
  font-weight:700;cursor:pointer;padding:6px 0;text-decoration:underline}
.wz-email-pick{display:flex;flex-wrap:wrap;gap:8px}
.wz-email-chip{padding:8px 12px;border-radius:10px;border:1.5px solid var(--line,#ece9f5);
  background:#fff;cursor:pointer;font:inherit;font-size:13.5px;color:inherit}
.wz-email-chip.is-on{border-color:var(--purple,#7c5cff);background:var(--purple-soft,#f3effe)}
.wz-email-add{display:flex;flex-direction:column;gap:10px}
.wz-email-code{display:flex;flex-direction:column;gap:10px}
.wz-code-sent{font-size:13.5px;color:var(--muted,#8b8696);margin:0}
.wz-code-row{display:flex;gap:8px}
.wz-code-row input{flex:1;min-width:0;padding:12px 14px;border-radius:12px;
  border:1.5px solid var(--line,#ece9f5);font:inherit;font-size:16px;letter-spacing:.18em;background:#fff}
.wz-code-row input:focus,.wz-email input:focus{outline:none;border-color:var(--purple,#7c5cff);
  box-shadow:0 0 0 4px rgba(124,92,255,.13)}

.wz-email{display:flex;flex-direction:column;gap:6px}
.wz-email span{font-size:12px;font-weight:700;text-transform:uppercase;letter-spacing:.05em;
  color:var(--muted,#8b8696)}
.wz-email input{padding:13px 15px;border-radius:13px;border:1.5px solid var(--line,#ece9f5);
  font:inherit;font-size:15px;background:#fff}

.wz-nav{display:flex;gap:10px;justify-content:space-between;margin-top:26px}
.btn.is-busy{opacity:.65;pointer-events:none}

/* ---- step 4: done ---- */
.wz-done{text-align:center;padding:26px 0}
.wz-done-art{width:66px;height:66px;margin:0 auto 18px;border-radius:50%;display:grid;
  place-items:center;font-size:30px;color:#fff;
  background:linear-gradient(135deg,#22c55e,#16a34a);animation:wz-pop .45s cubic-bezier(.2,1.5,.4,1) backwards}
@keyframes wz-pop{from{transform:scale(.4);opacity:0}}
/* The QR panel is a self-contained centred unit in BOTH hosts. It used to inherit
   `text-align` from its step: centred under step 4's `.wz-done`, but LEFT-ragged
   inside step 3's channel body — centred QR + centred spinner over a left-aligned
   caption, button and poll line. Centre it here so it reads the same in both. */
.wz-qr{margin:22px auto 0;max-width:280px;text-align:center}
.wz-qr-box{width:190px;margin:0 auto 14px;background:#fff;padding:9px;border-radius:12px;
  box-shadow:0 8px 30px rgba(80,60,160,.1)}
.wz-qr-box svg{width:100%;height:auto;display:block}
/* loading animation shown UNDER the QR while polling for Start (founder 2026-08-21) */
.wz-tgload{display:flex;justify-content:center;margin:12px 0 2px}
.wz-tgload[hidden]{display:none}
/* ---- step 4: terminal outcome panel (bridge -07) ----
   The anon-Telegram poll resolves into a distinct, self-contained state: a badge, a heading,
   body copy and actions. It REPLACES the optimistic waiting chrome (the ✓ art, the "you're all
   set" heading and the QR) via `.wz-done.is-final`, so the final screen reads honestly for every
   outcome. Success is a green win; the error tones are calm amber/orange — clearly actionable,
   never alarming red. */
.wz-done.is-final .wz-done-art,
.wz-done.is-final [data-done-title],
.wz-done.is-final [data-done-body],
.wz-done.is-final [data-done-qr]{display:none}
.wz-outcome{text-align:center;padding:6px 0 4px;animation:wz-pop .4s cubic-bezier(.2,1.5,.4,1) backwards}
.wz-outcome[hidden]{display:none}
.wz-outcome-badge{width:66px;height:66px;margin:0 auto 18px;border-radius:50%;display:grid;
  place-items:center;font-size:30px;line-height:1;color:#fff}
.wz-outcome-title{font-size:23px;font-weight:800;letter-spacing:-.01em;margin:0 0 8px;
  color:var(--wz-ink,#1d1b2e)}
.wz-outcome-body{color:var(--wz-muted,#5c5870);font-size:14.5px;line-height:1.5;
  margin:0 auto 22px;max-width:40ch}
.wz-outcome-actions{display:flex;flex-direction:column;align-items:center;gap:10px}
.wz-outcome-actions .btn{min-width:210px}
/* tones: success (green win) vs calm attention (amber/orange, deliberately not red) */
.wz-outcome.is-ok .wz-outcome-badge{background:linear-gradient(135deg,#22c55e,#16a34a)}
.wz-outcome.is-warn .wz-outcome-badge{background:linear-gradient(135deg,#fbbf24,#f59e0b);color:#3f2d05}
.wz-outcome.is-error .wz-outcome-badge{background:linear-gradient(135deg,#fb923c,#f97316)}

/* ---- in-account modal host (§A) ---- */
/* Rendered on /u/monitors (which also has a dark theme). The card is a deliberately LIGHT
   dialog with explicit ink/surface, so it reads the same over the light site and the dark
   user area — the wizard's own #fff inputs stay legible. */
.wz-modal{position:fixed;inset:0;z-index:1000;display:flex;align-items:flex-start;
  justify-content:center;padding:24px 16px;overflow:auto}
.wz-modal[hidden]{display:none}
.wz-modal-scrim{position:fixed;inset:0;background:rgba(20,14,40,.55)}
.wz-modal-card{position:relative;z-index:1;width:100%;max-width:560px;margin:auto;
  background:#fff;color:#1d1b2e;border-radius:20px;max-height:calc(100vh - 48px);overflow:auto;
  box-shadow:0 30px 80px rgba(30,20,70,.4);animation:wz-modal-in .25s cubic-bezier(.2,.8,.3,1) backwards}
.wz-modal-x{position:absolute;top:12px;right:14px;z-index:2;width:36px;height:36px;border-radius:10px;
  background:none;border:0;font-size:26px;line-height:1;color:var(--muted,#8b8696);cursor:pointer}
.wz-modal-x:hover{background:var(--purple-soft,#f3effe)}
@keyframes wz-modal-in{from{opacity:0;transform:translateY(14px)}}
.wz.is-modal{max-width:none;margin:0;padding:30px 22px 26px}
body.wz-modal-open{overflow:hidden}

/* ---- hand-off link preview (bridge -09-02-03) ----
   Only rendered for a wizard entered from a /sources/<host> "track this search" box; the
   markup ships `hidden` everywhere else, so these rules are inert on every other entry.
   Messenger-style row: host monogram (we hold no favicons and fetch nothing), the search
   read back in words, the raw URL, and the live-check status mirrored out of step 1.
   Colours are pinned to the wizard's own tokens for the same dark-mode reason as below. */
.wz-preview{display:flex;gap:12px;align-items:flex-start;margin:0 0 24px;padding:13px 14px;
  border:1.5px solid var(--line,#ece9f5);border-radius:15px;background:#fff;
  box-shadow:0 8px 24px rgba(80,60,160,.07)}
.wz-preview[hidden]{display:none}
.wz-preview-ico{flex:0 0 auto;width:38px;height:38px;border-radius:11px;display:grid;
  place-items:center;font-weight:800;font-size:17px;color:#fff;line-height:1;
  background:linear-gradient(135deg,var(--purple,#7c5cff),var(--purple-2,#9b6bff))}
.wz-preview-main{flex:1 1 auto;min-width:0;display:flex;flex-direction:column;gap:2px}
.wz-preview-title,.wz-preview-url{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.wz-preview-title{font-weight:700;font-size:14.5px;line-height:1.35;color:var(--wz-ink,#1d1b2e)}
.wz-preview-title:empty{display:none}
.wz-preview-url{font-size:12.5px;color:var(--wz-muted,#5c5870);opacity:.85}
.wz-preview-status{margin-top:5px;font-size:12.5px;font-weight:600;color:var(--purple,#7c5cff)}
.wz-preview-status:empty{display:none}
.wz-preview-change{flex:0 0 auto;align-self:center;white-space:nowrap;padding:0}
@media (max-width:480px){
  .wz-preview{flex-wrap:wrap}
  .wz-preview-change{align-self:flex-start;margin-left:50px}
}

/* ---- theme-safe scoping (bridge -11, 2026-08-21) --------------------------
   The wizard is a deliberately LIGHT surface (white card, dark ink) rendered in
   TWO hosts: the light marketing layout (/new) and the user-area modal, whose
   layout sets `color-scheme: light dark` and carries dark-mode tokens. In OS
   dark mode that made any form control WITHOUT an explicit color fall back to
   the UA's light `fieldtext` → light text on the wizard's forced #fff →
   invisible (the email input + the 6-digit-code input), while messages that
   leaned on an ambient token risked the dark palette. Pin the component's own
   text tokens and force a light color-scheme so inputs, code entry and every
   status / error / confirmation line stay legible in BOTH hosts and BOTH modes.
   Placed last so it wins on source order for the equal-specificity input rules. */
.wz{color-scheme:light;--wz-ink:#1d1b2e;--wz-muted:#5c5870}
.wz,.wz .wz-h1{color:var(--wz-ink)}
.wz input,.wz textarea,.wz select{color:var(--wz-ink);background:#fff}
.wz input::placeholder{color:#9a95ab;opacity:1}
/* the "we sent a code" / "waiting for Start" / plan-upsell lines — darker than the
   ambient muted so they read as a real message on the white card, not a ghost. */
.wz-code-sent,.wz-poll,.wz-note{color:var(--wz-muted)}

@media (prefers-reduced-motion: reduce){
  .wz-step.is-on,.wz-done-art,.wz-modal-card,.wz-outcome{animation:none}
  .wz-opt:hover{transform:none}
  .wz-connect,.wz-connect[hidden]{transition:none}
  .wz .wz-connect:not([hidden]) [data-tg-panel]:not([hidden]),
  .wz .wz-connect:not([hidden]) [data-email-add]:not([hidden]),
  .wz .wz-connect:not([hidden]) [data-email-code]:not([hidden]),
  .wz .wz-connect:not([hidden]) [data-email-upsell]:not([hidden]){animation:none}
}
