/* ============================================================
   THE APP SHELL  —  /account once you're signed in.
   ============================================================
   Signed out, /account is a marketing page with a sign-in card on it.
   Signed in, it stops being a page and becomes an application: a fixed
   sidebar, a working area, and objects you operate.

   That split is deliberate. The old dashboard was the homepage's
   components (.card, .stat-num, .green-card) arranged down a 1080px
   column — which reads as a receipt, because a receipt is what a
   centred column of cards IS. Nothing on it could be acted on.

   The tokens are the store's own (--bg, --panel, --line, --green =
   electric cyan, Inter, 16px radii) so this is recognisably the same
   product as /twitch — only the composition changes. There is no new
   palette and no new typeface here on purpose.
   ============================================================ */

/* ── shell ───────────────────────────────────────────────────────
   Sidebar is fixed and the main column is pushed, rather than a
   two-column grid: the working area scrolls on its own and the nav
   never leaves, which is the single thing that makes a page feel
   like an app rather than a document.
   ──────────────────────────────────────────────────────────────── */
.app{--side:252px;--top:64px;--z:1}
/* site.css does `@media(min-width:1057px){body{zoom:1.1}}`. Under zoom, a vh
   is NOT divided by the zoom factor — 100vh resolves to the full viewport and
   is THEN scaled, so it renders 10% taller than the screen and forces ~90px
   of scroll on a page that should exactly fit. Mirror the same breakpoint and
   divide it back out. Keep this in step with site.css:653. */
@media(min-width:1057px){ .app{--z:1.1} }
body.in-app{background:var(--bg)}
/* the marketing backdrop belongs to the signed-out page only — a fixed
   aura + grid behind an app chrome just muddies every panel edge */
body.in-app::before,body.in-app::after{display:none}
/* marketing chrome is for the gate. Once you're in, the sidebar IS the nav. */
body.in-app > header.nav,body.in-app > footer,body.in-app > main.page{display:none}
.app{display:none}
body.in-app .app{display:block}

.app-side{position:fixed;top:0;left:0;bottom:0;width:var(--side);z-index:40;
  background:var(--panel);border-right:1px solid var(--line);
  display:flex;flex-direction:column;overflow-y:auto;overscroll-behavior:contain}
.app-main{margin-left:var(--side);min-height:calc(100vh / var(--z));display:flex;flex-direction:column}

/* ── sidebar: brand ─────────────────────────────────────────── */
.app-brand{display:flex;align-items:center;gap:9px;height:var(--top);flex:none;
  padding:0 18px;border-bottom:1px solid var(--line);text-decoration:none}
.app-brand img.logo-word{height:17px;width:auto;display:block}
.app-brand .logo-mark{width:22px;height:22px;display:block}

/* ── sidebar: nav ───────────────────────────────────────────── */
.app-nav{flex:1;padding:16px 12px 8px}
.app-grp{display:block;margin:16px 0 7px;padding:0 10px;font-size:10px;font-weight:700;
  letter-spacing:.13em;text-transform:uppercase;color:#5e5e68}
.app-nav > .app-grp:first-child{margin-top:0}
.app-link{display:flex;align-items:center;gap:11px;position:relative;
  padding:9px 10px;margin-bottom:2px;border-radius:10px;
  font-size:14px;font-weight:600;color:var(--muted-2);text-decoration:none;
  border:0;background:none;font-family:inherit;width:100%;text-align:left;cursor:pointer;
  transition:background .15s ease,color .15s ease}
.app-link svg{width:17px;height:17px;flex:none;color:#65656f;transition:color .15s ease}
.app-link:hover{background:var(--panel-2);color:var(--text)}
.app-link:hover svg{color:var(--muted-2)}
.app-link.on{background:color-mix(in srgb,var(--green) 13%,transparent);color:var(--text)}
.app-link.on svg{color:var(--green)}
/* the active marker reads as "you are here" without needing a colour change
   the eye has to decode — it is the only cyan bar in the sidebar */
.app-link.on:before{content:"";position:absolute;left:-12px;top:50%;transform:translateY(-50%);
  width:3px;height:19px;border-radius:0 3px 3px 0;background:var(--green)}
.app-link .tag{margin-left:auto;font-size:10.5px;font-weight:700;padding:2px 7px;border-radius:100px;
  background:var(--panel-2);color:var(--muted);font-variant-numeric:tabular-nums}
.app-link.on .tag{background:color-mix(in srgb,var(--green) 22%,transparent);color:var(--green)}

/* ── sidebar: foot ──────────────────────────────────────────── */
.app-foot{flex:none;padding:12px;border-top:1px solid var(--line)}
.app-me{display:flex;align-items:center;gap:10px;padding:8px 10px;border-radius:11px;background:var(--panel-2)}
.app-av{width:31px;height:31px;flex:none;border-radius:9px;display:grid;place-items:center;
  background:linear-gradient(135deg,var(--green),var(--green-2));color:var(--ink);
  font-size:12px;font-weight:800;letter-spacing:.02em}
.app-me .mail{flex:1;min-width:0;font-size:12px;font-weight:600;color:var(--muted-2);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.app-out{flex:none;display:grid;place-items:center;width:27px;height:27px;border-radius:8px;
  border:0;background:none;color:var(--muted);cursor:pointer;transition:background .15s,color .15s}
.app-out svg{width:15px;height:15px}
.app-out:hover{background:#2a2a2f;color:var(--text)}

/* ── topbar ──────────────────────────────────────────────────── */
.app-top{position:sticky;top:0;z-index:30;height:var(--top);flex:none;
  display:flex;align-items:center;gap:14px;padding:0 28px;
  background:color-mix(in srgb,var(--bg) 86%,transparent);
  -webkit-backdrop-filter:saturate(1.6) blur(12px);backdrop-filter:saturate(1.6) blur(12px);
  border-bottom:1px solid var(--line)}
.app-top h1{margin:0;min-width:0;font-size:17px;font-weight:700;letter-spacing:-.01em;color:var(--text);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.app-top .sp{flex:1}
/* Above the sidebar breakpoint the page header carries the title, so the
   topbar's copy of it is redundant — two titles, one 17px and one 31px, four
   rows apart. Below it the sidebar is a drawer and the topbar is the only
   thing that says where you are, so it stays. */
@media(min-width:901px){
  .app-top #appTitle{display:none}
  /* With the title and the buy button both moved onto the page, the topbar has
     exactly two remaining jobs — the you-are-live strip and the leave-the-frame
     link — and neither is usually present. Rather than leave 64px of empty
     chrome above every view, it collapses when it is holding nothing. */
  .app-top:not(:has(#appLive > *)):not(:has(#appBuy > *)){
    height:0;min-height:0;padding:0;border-bottom:0;overflow:hidden
  }
}
.app-burger{display:none;width:34px;height:34px;flex:none;border:1px solid var(--line);border-radius:9px;
  background:var(--panel);color:var(--text);cursor:pointer;place-items:center}
.app-burger svg{width:17px;height:17px}

/* buttons — .btn is the app's own, deliberately squarer and quieter than the
   storefront's .pill, which is a marketing CTA and shouts in here */
.btn{display:inline-flex;align-items:center;gap:7px;height:36px;padding:0 14px;border-radius:10px;
  font:inherit;font-size:13.5px;font-weight:650;cursor:pointer;text-decoration:none;white-space:nowrap;
  border:1px solid var(--line);background:var(--panel);color:var(--text);
  transition:transform .16s cubic-bezier(.23,1,.32,1),background .15s,border-color .15s}
.btn svg{width:15px;height:15px}
.btn:hover{background:var(--panel-2);border-color:#33333a}
.btn:active{transform:scale(.97)}
.btn.pri{background:var(--green);border-color:var(--green);color:var(--ink);font-weight:700}
.btn.pri:hover{background:var(--green-2);border-color:var(--green-2)}
.btn.sm{height:31px;padding:0 11px;font-size:12.5px;border-radius:9px}
.btn.gho{background:none;border-color:transparent;color:var(--muted-2)}
.btn.gho:hover{background:var(--panel);color:var(--text)}
.btn[disabled]{opacity:.5;pointer-events:none}

/* ── working area ───────────────────────────────────────────── */
.app-body{flex:1;padding:40px 36px 80px;max-width:1180px;width:100%}

/* ── page header ──────────────────────────────────────────────────
   Every view opens the same way: what this page is, one line on why you
   would be here, and the actions that belong to it on the same line as the
   title. The topbar used to carry a 17px title and nothing else, which told
   you where you were but never what the page was for — and it put the page's
   main action in the chrome rather than on the page.
   ──────────────────────────────────────────────────────────────── */
.pg-head{display:flex;align-items:flex-start;gap:20px;flex-wrap:wrap;margin:0 0 30px}
.pg-head .tx{flex:1 1 320px;min-width:0}
.pg-t{margin:0;font-size:31px;font-weight:800;letter-spacing:-.03em;line-height:1.1;color:var(--text)}
.pg-d{margin:7px 0 0;font-size:14.5px;line-height:1.55;color:var(--muted);max-width:64ch}
.pg-act{display:flex;align-items:center;gap:9px;flex-wrap:wrap;flex:none;padding-top:4px}

/* ── stat tiles ───────────────────────────────────────────────────
   A row of three. Icon chip, the number, then what the number counts. They
   are not decoration: each one is a link to the view that explains it, so a
   count you did not expect is one click from the thing behind it.
   ──────────────────────────────────────────────────────────────── */
.kpis{display:grid;grid-template-columns:repeat(3,1fr);gap:13px;margin:0 0 26px}
.kpi{display:flex;align-items:center;gap:14px;padding:17px 18px;border-radius:var(--r);
  border:1px solid var(--line);background:var(--panel);text-align:left;width:100%;
  font:inherit;color:inherit;cursor:pointer;
  transition:border-color .16s ease,background .16s ease,transform .16s ease}
.kpi:hover{border-color:#33333a;background:var(--panel-2)}
.kpi:active{transform:scale(.995)}
.kpi:focus-visible{outline:2px solid var(--green);outline-offset:2px}
.kpi-ic{width:38px;height:38px;flex:none;border-radius:11px;display:grid;place-items:center;
  background:color-mix(in srgb,var(--green) 14%,transparent);color:var(--green)}
.kpi-ic svg{width:19px;height:19px}
/* The muted variant is for a count of zero. A tile that reads "0" in full
   accent colour claims importance it has not earned. */
.kpi.z .kpi-ic{background:var(--panel-2);color:#55555e}
.kpi b{display:block;font-size:25px;font-weight:800;letter-spacing:-.03em;line-height:1;
  color:var(--text);font-variant-numeric:tabular-nums}
.kpi.z b{color:var(--muted-2)}
.kpi span{display:block;margin-top:5px;font-size:11px;font-weight:700;letter-spacing:.09em;
  text-transform:uppercase;color:var(--muted)}
@media(max-width:760px){ .kpis{grid-template-columns:1fr;gap:10px} }

/* ── buy-page FAQ ─────────────────────────────────────────────────
   Under the packages, not beside them. Everything here is answered on the
   public pages too — this is the same answer where the decision is actually
   being made, so nobody has to leave the dashboard to check a policy before
   paying. Rows, not cards: an accordion of bordered boxes reads as seven
   things to do rather than seven things to read.
   ──────────────────────────────────────────────────────────────── */
.faq{margin:44px 0 0}
/* Two columns once there is room for both. Capped at 820px and stacked, the
   accordion left the right half of the working area empty on every buy page;
   the heading and a way to ask something that is NOT on the list are worth
   more there than nothing. Below this the rail stacks back on top. */
@media(min-width:1240px){
  .faq{display:grid;grid-template-columns:minmax(240px,300px) minmax(0,1fr);
    column-gap:56px;align-items:start}
  .faq-side{position:sticky;top:22px}
}
.faq-list{max-width:760px}
.faq-h{margin:0 0 4px;font-size:19px;font-weight:700;letter-spacing:-.02em;color:var(--text)}
.faq-s{margin:0 0 18px;font-size:13.5px;color:var(--muted)}

/* ── the ask card ──
   An FAQ can only answer what someone thought to put on it. This is the way
   out for everything else, and it sits beside the questions rather than after
   them so it is visible without reading to the bottom first. */
.faq-ask{border:1px solid var(--line);border-radius:var(--r);background:var(--panel);
  padding:16px 17px;margin:0 0 22px}
.faq-ask b{display:block;font-size:14px;font-weight:700;color:var(--text)}
.faq-ask p{margin:5px 0 0;font-size:13px;line-height:1.6;color:var(--muted)}
.faq-ask-b{display:flex;flex-wrap:wrap;gap:8px;margin-top:13px}
@media(min-width:1240px){ .faq-ask{margin:22px 0 0} }
.faq-i{border-bottom:1px solid var(--line)}
.faq-i:first-of-type{border-top:1px solid var(--line)}
.faq-i > summary{list-style:none;cursor:pointer;display:flex;align-items:center;gap:16px;
  padding:16px 2px;font-size:14.5px;font-weight:650;color:var(--text)}
.faq-i > summary::-webkit-details-marker{display:none}
.faq-i > summary:hover{color:var(--green)}
.faq-i > summary:focus-visible{outline:2px solid var(--green);outline-offset:-2px;border-radius:6px}
/* the marker is a pseudo-element so it never lands in the accessible name —
   a screen reader reads the question, not "question plus" */
.faq-i > summary::after{content:"";flex:none;margin-left:auto;width:9px;height:9px;
  border-right:2px solid var(--muted);border-bottom:2px solid var(--muted);
  transform:rotate(45deg) translate(-2px,-2px);transition:transform .2s ease}
.faq-i[open] > summary::after{transform:rotate(-135deg) translate(-3px,-3px)}
.faq-a{padding:0 2px 18px;margin:0;font-size:13.5px;line-height:1.65;color:var(--muted-2);max-width:68ch}
.faq-a a{color:var(--green);font-weight:600}
@media(prefers-reduced-motion:reduce){ .faq-i > summary::after{transition:none} }

/* ── the fine print ───────────────────────────────────────────────
   Closes the buy pages. Quieter than everything above it on purpose — this is
   not a sell, it is the set of facts somebody wants confirmed at the moment
   they are about to pay, so it reads as reassurance rather than another
   panel competing with the prices.
   ──────────────────────────────────────────────────────────────── */
/* The last accordion row drops its own rule: with .fine's border-top 30px
   below it, the block ended on two hairlines a thumb apart. One divider
   between the questions and the small print, not two. */
.faq-list .faq-i:last-of-type{border-bottom:0}
.fine{margin:14px 0 0;padding:20px 0 0;border-top:1px solid var(--line)}
.fine-l{list-style:none;display:grid;gap:10px;margin:0}
.fine-l li{display:flex;align-items:flex-start;gap:10px;
  font-size:12.5px;line-height:1.55;color:var(--muted-2)}
.fine-l svg{width:15px;height:15px;flex:none;margin-top:1px;color:var(--muted)}
.fine-t{margin:16px 0 0;font-size:12px;line-height:1.6;color:var(--muted)}
.fine-t a{color:var(--muted-2);text-decoration:underline;text-underline-offset:2px;
  text-decoration-color:#3a3a42;transition:color .15s ease,text-decoration-color .15s ease}
.fine-t a:hover{color:var(--green);text-decoration-color:var(--green)}
@media(min-width:560px){ .fine-l{grid-template-columns:1fr 1fr} .fine-l li:first-child{grid-column:1 / -1} }

/* ── notices ──────────────────────────────────────────────────────
   One sentence with an icon, full width. Used where a page needs to explain
   itself or flag a limit before you hit it.
   ──────────────────────────────────────────────────────────────── */
.note{display:flex;align-items:flex-start;gap:13px;padding:15px 17px;margin:0 0 22px;
  border-radius:var(--r);border:1px solid var(--line);background:var(--panel)}
.note-ic{width:32px;height:32px;flex:none;border-radius:10px;display:grid;place-items:center;
  background:color-mix(in srgb,var(--green) 14%,transparent);color:var(--green)}
.note-ic svg{width:17px;height:17px}
.note p{margin:0;font-size:13.5px;line-height:1.6;color:var(--muted-2);padding-top:6px}
.note p b{color:var(--text);font-weight:700}
.note a{color:var(--green);font-weight:600}
/* Warnings keep the same shape and change only the chip — the palette here is
   one accent by choice, so amber is reserved for the case that actually needs
   to stop someone, and never used for emphasis. */
.note.warn{border-color:color-mix(in srgb,#f0a83a 30%,var(--line))}
.note.warn .note-ic{background:color-mix(in srgb,#f0a83a 15%,transparent);color:#f0a83a}
.app-view{display:none}
.app-view.on{display:block}
.sec-h{display:flex;align-items:center;gap:12px;margin:30px 0 13px}
.sec-h:first-child{margin-top:0}
.sec-h h2{margin:0;font-size:13px;font-weight:700;letter-spacing:.02em;color:var(--text)}
.sec-h .sp{flex:1}

/* entrance — one orchestrated load, staggered by index, not scattered
   per-component effects. Skipped entirely for reduced-motion. */
.rise{opacity:0;transform:translateY(9px);animation:appRise .42s cubic-bezier(.23,1,.32,1) forwards}
@keyframes appRise{to{opacity:1;transform:none}}
@media(prefers-reduced-motion:reduce){
  .rise{animation:none;opacity:1;transform:none}
  .btn:active{transform:none}
}

/* ── get started ─────────────────────────────────────────────
   Only rendered while something on it is still undone. A permanent
   checklist of ticks is clutter — the moment it's all green it has
   nothing left to say, so it removes itself.
   ──────────────────────────────────────────────────────────── */
.gs{border:1px solid var(--line);border-radius:var(--r);background:var(--panel);overflow:hidden;margin-bottom:26px}
.gs-h{display:flex;align-items:center;gap:13px;padding:17px 18px}
.gs-ic{width:36px;height:36px;flex:none;border-radius:10px;display:grid;place-items:center;
  background:color-mix(in srgb,var(--green) 15%,transparent);color:var(--green)}
.gs-ic svg{width:18px;height:18px}
.gs-h b{display:block;font-size:14.5px;font-weight:700;color:var(--text)}
.gs-h span{display:block;font-size:12.5px;color:var(--muted);margin-top:1px}
.gs-steps{padding:0 10px 10px;display:flex;flex-direction:column;gap:5px}
.gs-step{display:flex;align-items:center;gap:12px;padding:12px 12px;border-radius:11px;background:var(--panel-2)}
.gs-step.done{background:color-mix(in srgb,#3ddc84 8%,transparent)}
.gs-n{width:23px;height:23px;flex:none;border-radius:50%;display:grid;place-items:center;
  font-size:11.5px;font-weight:700;background:#2a2a30;color:var(--muted-2)}
.gs-step.done .gs-n{background:color-mix(in srgb,#3ddc84 20%,transparent);color:#3ddc84}
.gs-n svg{width:12px;height:12px}
.gs-tx{flex:1;min-width:0}
.gs-tx b{display:block;font-size:13.5px;font-weight:650;color:var(--text)}
.gs-tx span{display:block;font-size:12.5px;color:var(--muted);margin-top:1px}
.gs-step.done .gs-tx b{color:var(--muted-2)}

/* ── state tabs ───────────────────────────────────────────────
   A tab row is always a control for the thing directly beneath it — the
   duration picker above the package grid, the state filter above the order
   list. It carried no bottom margin, so in every one of those views the tabs
   sat flush on the content they filter, with the heading 13px above them
   floating closer to the tabs than the tabs were to their own grid. 16px is
   enough to separate them while still reading as one group. */
.tabs{display:flex;gap:6px;flex-wrap:wrap;margin-bottom:16px}
.tab{display:inline-flex;align-items:center;gap:7px;height:34px;padding:0 13px;border-radius:10px;
  border:1px solid transparent;background:var(--panel);color:var(--muted-2);
  font:inherit;font-size:13.5px;font-weight:650;cursor:pointer;
  transition:background .15s,color .15s,border-color .15s}
.tab:hover{background:var(--panel-2);color:var(--text)}
.tab .c{font-size:11px;font-weight:700;padding:1.5px 6px;border-radius:100px;
  background:#2a2a30;color:var(--muted);font-variant-numeric:tabular-nums}
.tab.on{background:color-mix(in srgb,var(--green) 14%,transparent);border-color:color-mix(in srgb,var(--green) 34%,transparent);color:var(--text)}
.tab.on .c{background:var(--green);color:var(--ink)}

/* ── channel chips (dashboard strip) ────────────────────────── */
.chan-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(238px,1fr));gap:12px}
.chan{display:flex;align-items:center;gap:11px;padding:13px;border-radius:13px;
  border:1px solid var(--line);background:var(--panel);min-width:0;
  transition:border-color .15s ease}
.chan:hover{border-color:#33333a}
.chan.live{border-color:color-mix(in srgb,#ff4747 40%,transparent);
  background:linear-gradient(180deg,color-mix(in srgb,#ff4747 7%,transparent),transparent)}
.chan-av{width:38px;height:38px;flex:none;border-radius:11px;object-fit:cover;background:#1f1f24;
  display:grid;place-items:center;font-size:14px;font-weight:800;color:var(--muted)}
.chan-tx{flex:1;min-width:0}
.chan-nm{display:block;font-size:13.5px;font-weight:700;color:var(--text);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.chan-st{display:inline-flex;align-items:center;gap:5px;margin-top:2px;font-size:11.5px;font-weight:600;color:var(--muted)}
.chan-st .d{width:6px;height:6px;border-radius:50%;background:#4d4d56}
.chan.live .chan-st{color:#ff8080}
.chan.live .chan-st .d{background:#ff4747;box-shadow:0 0 7px #ff4747;animation:appPulse 1.5s infinite}
@keyframes appPulse{0%,100%{opacity:1}50%{opacity:.35}}
.chan-x{flex:none;width:26px;height:26px;border-radius:8px;border:0;background:none;color:#55555e;
  cursor:pointer;display:grid;place-items:center;transition:background .15s,color .15s}
.chan-x svg{width:13px;height:13px}
.chan-x:hover{background:#2a2a30;color:#ff8080}

/* ── the session card — an order you can act on ──────────────
   Grid, not a stacked column: what you bought reads left, the state
   reads right, actions sit on their own rail. The old .ord card put
   a 4-segment progress bar across the full width, which is why the
   thing looked like parcel tracking.
   ──────────────────────────────────────────────────────────── */
.ses-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(340px,1fr));gap:14px}
.ses{display:flex;flex-direction:column;border:1px solid var(--line);border-radius:var(--r);
  background:var(--panel);overflow:hidden;transition:border-color .15s ease}
.ses:hover{border-color:#33333a}
.ses.is-run{border-color:color-mix(in srgb,var(--green) 32%,transparent)}
.ses.is-rdy{border-color:color-mix(in srgb,#ffb340 30%,transparent)}

.ses-top{display:flex;align-items:center;gap:10px;padding:13px 15px;border-bottom:1px solid var(--line)}
.ses-no{font-size:11px;font-weight:700;letter-spacing:.07em;text-transform:uppercase;color:#5e5e68;
  font-variant-numeric:tabular-nums}
.ses-top .sp{flex:1}
.pill-st{display:inline-flex;align-items:center;gap:6px;font-size:10px;font-weight:800;
  letter-spacing:.07em;text-transform:uppercase;padding:4px 9px;border-radius:100px;
  background:#2a2a30;color:var(--muted-2);white-space:nowrap}
.pill-st .d{width:5px;height:5px;border-radius:50%;background:currentColor}
.pill-st.run{background:color-mix(in srgb,var(--green) 17%,transparent);color:var(--green)}
.pill-st.run .d{animation:appPulse 1.5s infinite}
.pill-st.rdy{background:color-mix(in srgb,#ffb340 16%,transparent);color:#ffb340}
.pill-st.done{background:color-mix(in srgb,#3ddc84 14%,transparent);color:#3ddc84}
.pill-st.bad{background:color-mix(in srgb,#ff5f57 16%,transparent);color:#ff8080}

/* Cards in a row are equal height (grid), so a short one gets stretched. Left
   alone that opens a hole between the facts and the action bar. Pinning the
   fact row to the bottom instead means every card reads the same way whatever
   its height: what you bought at the top, where it's got to at the bottom. */
.ses-mid{padding:15px;flex:1;display:flex;flex-direction:column}
.ses-what{display:flex;align-items:baseline;gap:8px;flex-wrap:wrap;margin-bottom:3px}
.ses-what b{font-size:21px;font-weight:800;letter-spacing:-.02em;color:var(--text);
  font-variant-numeric:tabular-nums;line-height:1}
.ses-what span{font-size:13.5px;font-weight:600;color:var(--muted-2)}
.ses-sub{font-size:12.5px;color:var(--muted)}
.ses-extra{margin-top:9px;display:flex;flex-direction:column;gap:4px}
.ses-extra i{font-style:normal;font-size:12.5px;color:var(--muted)}

/* the two-slot fact row — CHANNEL and the state fact beside it, the
   shape ViewBotter uses for CHANNEL / EXPIRES / AUTOSTART */
.ses-facts{display:grid;grid-template-columns:1fr 1fr;gap:9px;margin-top:auto;padding-top:14px}
.fact{padding:10px 11px;border-radius:11px;background:var(--panel-2);min-width:0}
.fact .k{display:block;font-size:9.5px;font-weight:700;letter-spacing:.09em;text-transform:uppercase;color:#5e5e68}
.fact .v{display:block;margin-top:3px;font-size:13px;font-weight:650;color:var(--text);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.fact .v.dim{color:var(--muted);font-weight:600}
.fact.wide{grid-column:1/-1}

/* live progress — a single filled bar, because "how much of my session is
   left" is one number. Four labelled segments answered a question about
   parcels that nobody buying a stream session was asking. */
.ses-bar{margin-top:13px;flex:none}
.ses-bar .track{height:5px;border-radius:100px;background:#2a2a30;overflow:hidden}
.ses-bar .fill{height:100%;border-radius:100px;background:linear-gradient(90deg,var(--green-2),var(--green));
  transition:width .5s cubic-bezier(.23,1,.32,1)}
.ses-bar .lab{display:flex;justify-content:space-between;gap:8px;margin-top:7px;font-size:11.5px;color:var(--muted)}
.ses-bar .lab b{color:var(--green);font-weight:700}

.ses-act{display:flex;align-items:center;gap:8px;padding:12px 15px;border-top:1px solid var(--line);
  background:color-mix(in srgb,var(--panel-2) 55%,transparent)}
.ses-act .sp{flex:1}

/* ── empty states ────────────────────────────────────────────
   Every empty view says what will appear here and gives the one
   action that fills it. A bare "nothing yet" is a dead end.
   ──────────────────────────────────────────────────────────── */
.empty{border:1px dashed #2e2e34;border-radius:var(--r);background:color-mix(in srgb,var(--panel) 55%,transparent);
  padding:42px 24px;text-align:center}
.empty .ic{width:44px;height:44px;margin:0 auto 13px;border-radius:13px;display:grid;place-items:center;
  background:var(--panel-2);color:#55555e}
.empty .ic svg{width:21px;height:21px}
.empty b{display:block;font-size:15px;font-weight:700;color:var(--text)}
.empty p{margin:5px auto 0;max-width:360px;font-size:13.5px;line-height:1.55;color:var(--muted)}
.empty .btn{margin-top:16px}

/* ── add-channel form ───────────────────────────────────────── */
.addch{border:1px solid var(--line);border-radius:var(--r);background:var(--panel);padding:17px;max-width:720px}
.addch-row{display:flex;gap:9px;flex-wrap:wrap}
.addch .sel{display:flex;gap:4px;padding:4px;border-radius:11px;background:var(--panel-2);border:1px solid var(--line)}
.addch .sel button{border:0;background:none;font:inherit;font-size:13px;font-weight:650;color:var(--muted-2);
  padding:0 13px;height:32px;border-radius:8px;cursor:pointer;transition:background .15s,color .15s}
.addch .sel button.on{background:var(--green);color:var(--ink);font-weight:700}
.addch .inp{flex:1;min-width:190px;display:flex;align-items:center;height:42px;padding:0 13px;
  border-radius:11px;background:var(--panel-2);border:1px solid var(--line);
  transition:border-color .16s,box-shadow .16s}
.addch .inp:focus-within{border-color:var(--green);box-shadow:0 0 0 3px color-mix(in srgb,var(--green) 20%,transparent)}
.addch .inp .pre{font-size:13.5px;color:var(--muted);font-weight:500;flex:none}
.addch .inp input{flex:1;min-width:0;background:none;border:0;outline:none;color:var(--text);
  font:inherit;font-size:14.5px;font-weight:600;padding:0 0 0 2px}
.addch .inp input::placeholder{color:#55555e;font-weight:500}
.addch .btn{height:42px;padding:0 18px}
.addch .msg{margin-top:10px;font-size:12.5px;color:#ff8080;display:none}
.addch .msg.show{display:block}

/* ── responsive ──────────────────────────────────────────────
   Under 900 the sidebar becomes a slide-over. It keeps its own
   scroll and the scrim closes it; the burger only exists here.
   ──────────────────────────────────────────────────────────── */
@media(max-width:900px){
  .app-main{margin-left:0}
  .app-burger{display:grid}
  .app-side{transform:translateX(-100%);transition:transform .3s cubic-bezier(.32,.72,0,1);width:262px}
  body.side-open .app-side{transform:none}
  .app-scrim{position:fixed;inset:0;z-index:39;background:rgba(4,4,6,.62);
    opacity:0;pointer-events:none;transition:opacity .3s ease}
  body.side-open .app-scrim{opacity:1;pointer-events:auto}
  .app-body{padding:20px 16px 64px}
  .app-top{padding:0 16px}
  .ses-grid,.chan-grid{grid-template-columns:1fr}
}
@media(prefers-reduced-motion:reduce){
  .app-side,.app-scrim{transition:none}
}
@media(max-width:344px){
  .ses-facts{grid-template-columns:1fr}
  .addch-row{flex-direction:column}
  .addch .inp{min-width:0}
}

/* ════════════════════════════════════════════════════════════════
   ROUND 2 — the parts that make it operable rather than readable.
   ════════════════════════════════════════════════════════════════ */

/* ── topbar live strip ───────────────────────────────────────────
   The one fact worth the topbar's space: you are live RIGHT NOW, and
   that is exactly when buying viewers makes sense. Only rendered when
   a channel actually resolves live — never as a placeholder.
   ──────────────────────────────────────────────────────────────── */
.app-live{display:inline-flex;align-items:center;gap:9px;height:34px;padding:0 6px 0 12px;
  border-radius:100px;background:color-mix(in srgb,#ff4747 12%,transparent);
  border:1px solid color-mix(in srgb,#ff4747 30%,transparent);min-width:0}
.app-live .d{width:6px;height:6px;flex:none;border-radius:50%;background:#ff4747;
  box-shadow:0 0 7px #ff4747;animation:appPulse 1.5s infinite}
.app-live .tx{font-size:13px;font-weight:650;color:#ffb3b3;white-space:nowrap;
  overflow:hidden;text-overflow:ellipsis;min-width:0}
.app-live .tx b{color:#fff;font-weight:700}
.app-live .btn{height:26px;padding:0 10px;font-size:12px;border-radius:100px}
@media(max-width:640px){
  .app-live .tx{display:none}
  .app-live{padding-left:10px}
  /* Two buy CTAs cannot both fit next to the burger and the title at 390 —
     the row overflowed and Chrome widened the layout viewport to 455, which
     then made every fixed overlay (scrim, drawer) 455 wide too. When a
     channel is live the strip's own CTA is the better of the two, because it
     is the one with a reason attached, so the static button stands down.

     This selector used to be `.app-top > .btn.pri` and therefore matched
     nothing: the button is wrapped in <span id="appBuy">, so it is a
     grandchild of the topbar, not a child. The rule read as if the problem
     were handled while the row went on overflowing — at 320 the burger, the
     live strip and the buy button came to 380px of fixed width, which
     crushed the title to 0px and pushed the button 44px off-screen. Target
     the wrapper that is actually there. */
  body.has-live .app-top > #appBuy{display:none}
}

/* ── clickable channel cards ─────────────────────────────────── */
.chan.tap{cursor:pointer;text-align:left;font:inherit;width:100%;
  transition:border-color .15s ease,transform .16s cubic-bezier(.23,1,.32,1)}
.chan.tap:hover{border-color:#3b3b43}
.chan.tap:active{transform:scale(.99)}
.chan .go{flex:none;color:#4a4a53;display:grid;place-items:center;width:20px;height:20px}
.chan .go svg{width:15px;height:15px}

/* ── channel detail ──────────────────────────────────────────── */
.ch-hero{display:flex;align-items:center;gap:16px;padding:19px;border-radius:var(--r);
  border:1px solid var(--line);background:var(--panel);flex-wrap:wrap}
.ch-hero.live{border-color:color-mix(in srgb,#ff4747 38%,transparent);
  background:linear-gradient(180deg,color-mix(in srgb,#ff4747 8%,transparent),transparent)}
.ch-hero .av{width:60px;height:60px;flex:none;border-radius:16px;object-fit:cover;background:#1f1f24;
  display:grid;place-items:center;font-size:22px;font-weight:800;color:var(--muted)}
.ch-hero .who{flex:1;min-width:170px}
.ch-hero .nm{font-size:22px;font-weight:800;letter-spacing:-.02em;color:var(--text);line-height:1.15;
  word-break:break-word}
.ch-hero .url{display:block;margin-top:2px;font-size:12.5px;color:var(--muted)}
.ch-hero .st{display:inline-flex;align-items:center;gap:6px;margin-top:8px;font-size:12.5px;
  font-weight:650;color:var(--muted);padding:4px 10px;border-radius:100px;background:var(--panel-2)}
.ch-hero .st .d{width:6px;height:6px;border-radius:50%;background:#4d4d56}
.ch-hero.live .st{background:color-mix(in srgb,#ff4747 15%,transparent);color:#ff9c9c}
.ch-hero.live .st .d{background:#ff4747;box-shadow:0 0 7px #ff4747;animation:appPulse 1.5s infinite}
.ch-hero .acts{display:flex;gap:8px;flex-wrap:wrap}
.ch-stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(132px,1fr));gap:12px;margin-top:14px}
.ch-stat{padding:14px 15px;border-radius:13px;border:1px solid var(--line);background:var(--panel)}
.ch-stat b{display:block;font-size:23px;font-weight:800;letter-spacing:-.025em;color:var(--text);
  line-height:1;font-variant-numeric:tabular-nums}
.ch-stat span{display:block;margin-top:5px;font-size:11px;font-weight:650;letter-spacing:.06em;
  text-transform:uppercase;color:#5e5e68}
.back{display:inline-flex;align-items:center;gap:6px;margin-bottom:14px;padding:0;border:0;background:none;
  font:inherit;font-size:13px;font-weight:650;color:var(--muted);cursor:pointer;transition:color .15s}
.back svg{width:15px;height:15px}
.back:hover{color:var(--text)}

/* ── the order drawer ────────────────────────────────────────────
   A card in a grid cannot hold a full breakdown without wrecking the
   grid, and a modal in the middle of the screen loses the list behind
   it. A right-hand drawer keeps the list in place and slides the
   detail in over it — iOS's own curve, because it is the one that
   feels attached to the gesture rather than timed.
   ──────────────────────────────────────────────────────────────── */
.dr-scrim{position:fixed;inset:0;z-index:60;background:rgba(4,4,6,.66);
  opacity:0;pointer-events:none;transition:opacity .3s ease}
body.dr-open .dr-scrim{opacity:1;pointer-events:auto}
.dr{position:fixed;top:0;right:0;bottom:0;z-index:61;width:min(440px,100%);
  background:var(--panel);border-left:1px solid var(--line);
  display:flex;flex-direction:column;
  transform:translateX(100%);transition:transform .34s cubic-bezier(.32,.72,0,1)}
/* Same trap as .mo-wrap: display:flex would beat [hidden]{display:none}, so a
   closed drawer stayed rendered (off-screen, but still laid out). */
.dr[hidden]{display:none}
body.dr-open .dr{transform:none}
.dr-top{display:flex;align-items:center;gap:11px;flex:none;height:var(--top);padding:0 16px;
  border-bottom:1px solid var(--line)}
.dr-top b{font-size:15px;font-weight:700;color:var(--text)}
.dr-top .sp{flex:1}
.dr-x{width:32px;height:32px;flex:none;border-radius:9px;border:0;background:var(--panel-2);
  color:var(--muted-2);cursor:pointer;display:grid;place-items:center;transition:background .15s,color .15s}
.dr-x svg{width:15px;height:15px}
.dr-x:hover{background:#2f2f36;color:var(--text)}
.dr-body{flex:1;overflow-y:auto;overscroll-behavior:contain;padding:18px 16px 26px}
.dr-h{display:flex;align-items:baseline;gap:9px;flex-wrap:wrap;margin-bottom:4px}
.dr-h b{font-size:25px;font-weight:800;letter-spacing:-.025em;color:var(--text);font-variant-numeric:tabular-nums}
.dr-h span{font-size:14px;font-weight:600;color:var(--muted-2)}
.dr-sec{margin-top:20px}
.dr-sec > h4{margin:0 0 9px;font-size:10px;font-weight:700;letter-spacing:.11em;
  text-transform:uppercase;color:#5e5e68}
.dr-line{display:flex;align-items:flex-start;gap:12px;padding:11px 0;border-bottom:1px solid var(--line)}
.dr-line:last-child{border-bottom:0}
.dr-line .k{flex:none;width:104px;font-size:12.5px;color:var(--muted)}
.dr-line .v{flex:1;min-width:0;font-size:13.5px;font-weight:600;color:var(--text);
  word-break:break-word;text-align:right}
.dr-line .v.mono{font-variant-numeric:tabular-nums}
.dr-item{display:flex;align-items:center;gap:11px;padding:11px 12px;border-radius:11px;
  background:var(--panel-2);margin-bottom:7px}
.dr-item .q{flex:none;min-width:44px;font-size:15px;font-weight:800;color:var(--text);
  font-variant-numeric:tabular-nums;letter-spacing:-.02em}
.dr-item .n{flex:1;min-width:0;font-size:13px;font-weight:600;color:var(--muted-2);line-height:1.4}
.dr-item .s{flex:none;font-size:9.5px;font-weight:800;letter-spacing:.06em;text-transform:uppercase;
  padding:3px 8px;border-radius:100px;background:#2c2c33;color:var(--muted)}
.dr-item .s.ok{background:color-mix(in srgb,#3ddc84 14%,transparent);color:#3ddc84}
.dr-item .s.go{background:color-mix(in srgb,var(--green) 16%,transparent);color:var(--green)}
.dr-foot{flex:none;display:flex;gap:8px;padding:13px 16px;border-top:1px solid var(--line);
  background:color-mix(in srgb,var(--panel-2) 55%,transparent)}
.dr-foot .btn{flex:1;justify-content:center}
@media(prefers-reduced-motion:reduce){ .dr,.dr-scrim{transition:none} }

/* ── settings ────────────────────────────────────────────────── */
.set{max-width:660px}
.set-card{border:1px solid var(--line);border-radius:var(--r);background:var(--panel);
  overflow:hidden;margin-bottom:16px}
.set-row{display:flex;align-items:center;gap:14px;padding:16px 17px;border-bottom:1px solid var(--line);
  flex-wrap:wrap}
.set-row:last-child{border-bottom:0}
.set-tx{flex:1;min-width:180px}
.set-tx b{display:block;font-size:13.5px;font-weight:650;color:var(--text)}
.set-tx span{display:block;margin-top:2px;font-size:12.5px;line-height:1.5;color:var(--muted)}
.set-val{font-size:13.5px;font-weight:650;color:var(--muted-2);word-break:break-all}
.seg{display:flex;gap:4px;padding:4px;border-radius:11px;background:var(--panel-2);border:1px solid var(--line)}
.seg button{border:0;background:none;font:inherit;font-size:13px;font-weight:650;color:var(--muted-2);
  padding:0 14px;height:30px;border-radius:8px;cursor:pointer;
  transition:background .15s ease,color .15s ease}
.seg button:hover{color:var(--text)}
.seg button.on{background:var(--green);color:var(--ink);font-weight:700}

/* ── section subhead used above split lists ──────────────────── */
.sec-h .n{font-size:11px;font-weight:700;padding:2px 8px;border-radius:100px;
  background:var(--panel-2);color:var(--muted);font-variant-numeric:tabular-nums}

@media(max-width:900px){
  .dr{width:100%}
  .ch-hero .acts{width:100%}
  .ch-hero .acts .btn{flex:1;justify-content:center}
}

/* ── starting a held order ───────────────────────────────────────
   Only ever rendered for status 'ready'. The channel is asked again
   here because a held order may have been bought days before the
   customer decided which channel to stream on — and this is the last
   moment the answer can still change anything.
   ──────────────────────────────────────────────────────────────── */
.dr-start{margin-top:20px;padding:15px;border-radius:14px;
  border:1px solid color-mix(in srgb,#ffb340 32%,transparent);
  background:color-mix(in srgb,#ffb340 7%,transparent)}
.dr-start h4{margin:0 0 9px;font-size:10px;font-weight:700;letter-spacing:.11em;
  text-transform:uppercase;color:#ffb340}
.dr-start .inp{display:flex;align-items:center;height:46px;padding:0 13px;border-radius:12px;
  background:var(--panel-2);border:1px solid var(--line);
  transition:border-color .16s ease,box-shadow .16s ease}
.dr-start .inp:focus-within{border-color:#ffb340;box-shadow:0 0 0 3px color-mix(in srgb,#ffb340 22%,transparent)}
.dr-start .inp .pre{flex:none;font-size:13.5px;color:var(--muted);font-weight:500}
.dr-start .inp input{flex:1;min-width:0;background:none;border:0;outline:none;color:var(--text);
  font:inherit;font-size:15px;font-weight:600;padding:0 0 0 2px}
.dr-start .inp input::placeholder{color:#55555e;font-weight:500}
.dr-start p{margin:10px 0 0;font-size:12.5px;line-height:1.55;color:var(--muted)}
.dr-start .err{margin-top:9px;font-size:12.5px;color:#ff8080;display:none}
.dr-start .err.show{display:block}
.btn.warn{background:#ffb340;border-color:#ffb340;color:#231603;font-weight:700}
.btn.warn:hover{background:#ffc266;border-color:#ffc266}

/* ── framed pages ────────────────────────────────────────────────
   Store, guides, support and legal open INSIDE the shell instead of
   navigating away. Each one is the real page in a same-origin iframe,
   not a copy of its markup, which matters for three reasons:

     · those pages are indexed and rank — they keep their own URLs,
       their own <head> and their own SEO, untouched;
     · the PDP wizards, the cart and the channel lookups are inline
       scripts and heavy CSS. Injecting that markup into this document
       would mean re-running the scripts by hand and refereeing a
       collision between their stylesheet and this one;
     · the frame is a hard boundary — a page can be redesigned without
       any chance of it reaching in and breaking the dashboard.

   The iframe FILLS the content area and scrolls internally rather than
   auto-sizing to its content. Auto-height would make every position:fixed
   element inside it (the cart drawer, the order modal) position against a
   3000px-tall viewport and fly off-screen.
   ──────────────────────────────────────────────────────────────── */
.pg-wrap{position:relative;height:calc(100vh / var(--z) - var(--top));background:var(--bg)}
.pg-wrap iframe{display:block;width:100%;height:100%;border:0;background:var(--bg)}
/* the framed page owns the full width — .app-body's padding and reading
   width belong to the app's own views */
body.pg-view .app-body{padding:0;max-width:none}

.pg-load{position:absolute;inset:0;display:grid;place-items:center;gap:12px;
  background:var(--bg);transition:opacity .25s ease}
.pg-load.gone{opacity:0;pointer-events:none}
.pg-load .sp{width:26px;height:26px;border-radius:50%;border:2.5px solid rgba(255,255,255,.12);
  border-top-color:var(--green);animation:pgspin .7s linear infinite}
@keyframes pgspin{to{transform:rotate(360deg)}}
.pg-load span{font-size:13px;color:var(--muted)}
@media(prefers-reduced-motion:reduce){ .pg-load .sp{animation-duration:2s} }

/* Shown only if the frame cannot load — never instead of trying. */
.pg-fail{position:absolute;inset:0;display:grid;place-items:center;padding:24px;text-align:center}
.pg-fail b{display:block;font-size:15px;font-weight:700;color:var(--text)}
.pg-fail p{margin:6px auto 14px;max-width:340px;font-size:13.5px;line-height:1.55;color:var(--muted)}

/* an "open the real page" escape hatch in the topbar while framing */
.pg-out{display:inline-flex;align-items:center;gap:6px}
@media(max-width:640px){ .pg-out span{display:none} }

/* ── packages ────────────────────────────────────────────────────
   The monthly plans. These already existed on the hub — four tiers
   with live Stripe prices — and nothing on the site sold them:
   assets/plans.js was written and then never linked from any page.
   This is the surface that makes them buyable.

   A plan here is one thing and the card says only that thing: N live
   viewers held on one channel for a month. There are no chat bots,
   no follower allowance and no VOD views in a BuyLiveViewers plan, so
   there are no rows for them.
   ──────────────────────────────────────────────────────────────── */
/* Exactly four tiers, so pick column counts that DIVIDE evenly rather than
   whatever auto-fit lands on. At 1160px minus gaps each column came to 253px
   against a 252px minimum — auto-fit took the safer 3 and left Pro alone on a
   row of its own, which reads as an afterthought rather than the top tier. */
.pk-grid{display:grid;grid-template-columns:1fr;gap:14px}
@media(min-width:620px){ .pk-grid{grid-template-columns:repeat(2,1fr)} }
@media(min-width:1120px){ .pk-grid{grid-template-columns:repeat(4,1fr)} }
.pk{display:flex;flex-direction:column;border:1px solid var(--line);border-radius:var(--r);
  background:var(--panel);overflow:hidden;transition:border-color .16s ease,transform .16s cubic-bezier(.23,1,.32,1)}
.pk:hover{border-color:#33333a}
.pk.on{border-color:color-mix(in srgb,var(--green) 45%,transparent)}

.pk-head{padding:18px 18px 16px;background:var(--panel-2);border-bottom:1px solid var(--line)}
.pk-name{font-size:14.5px;font-weight:700;letter-spacing:-.01em;color:var(--text)}
.pk-price{display:flex;align-items:baseline;gap:5px;margin-top:7px}
.pk-price b{font-size:29px;font-weight:800;letter-spacing:-.03em;color:var(--text);
  line-height:1;font-variant-numeric:tabular-nums}
.pk-price span{font-size:13px;font-weight:600;color:var(--muted)}
.pk-blurb{margin-top:8px;font-size:12.5px;line-height:1.5;color:var(--muted)}

.pk-body{flex:1;padding:16px 18px}
.pk-row{display:flex;align-items:center;gap:11px;margin-bottom:11px}
.pk-ic{width:29px;height:29px;flex:none;border-radius:9px;display:grid;place-items:center}
.pk-ic svg{width:15px;height:15px}
.pk-ic.a{background:color-mix(in srgb,var(--green) 15%,transparent);color:var(--green)}
.pk-ic.b{background:color-mix(in srgb,var(--purple) 20%,transparent);color:#a894ff}
.pk-ic.c{background:color-mix(in srgb,#ff9f45 15%,transparent);color:#ff9f45}
.pk-row .t{font-size:13.5px;color:var(--muted-2);line-height:1.35}
.pk-row .t b{color:var(--text);font-weight:700}

.pk-checks{margin-top:14px;padding-top:13px;border-top:1px solid var(--line);
  display:flex;flex-direction:column;gap:7px}
.pk-check{display:flex;align-items:flex-start;gap:8px;font-size:12.5px;color:var(--muted)}
.pk-check svg{width:13px;height:13px;flex:none;margin-top:2px;color:#3ddc84}

.pk-foot{padding:0 18px 18px}
.pk-foot .btn{width:100%;justify-content:center;height:40px}
.pk-sub{margin-top:8px;text-align:center;font-size:11.5px;color:var(--muted)}
.pk-or{margin-top:13px;padding-top:13px;border-top:1px solid var(--line);text-align:center}
.pk-or a{font-size:12.5px;font-weight:600;color:var(--green);text-decoration:none}
.pk-or a:hover{text-decoration:underline}

/* the channel this plan will run on — asked once, above the tiers, because
   the hub refuses a plan without one and refuses a second plan on a channel
   that already has one */
.pk-setup{border:1px solid var(--line);border-radius:var(--r);background:var(--panel);
  padding:17px;margin-bottom:18px;max-width:720px}
.pk-setup .k{display:block;margin-bottom:9px;font-size:10px;font-weight:700;letter-spacing:.11em;
  text-transform:uppercase;color:#5e5e68}
.pk-setup .row{display:flex;gap:9px;flex-wrap:wrap;align-items:center}
.pk-chips{display:flex;gap:6px;flex-wrap:wrap;margin-top:10px}
.pk-chip{border:1px solid var(--line);background:var(--panel-2);color:var(--muted-2);
  font:inherit;font-size:12.5px;font-weight:600;padding:5px 11px;border-radius:100px;cursor:pointer;
  transition:border-color .15s,color .15s}
.pk-chip:hover{border-color:#3a3a41;color:var(--text)}
.pk-msg{margin-top:11px;font-size:12.5px;line-height:1.5;color:#ff8080;display:none}
.pk-msg.show{display:block}
.pk-msg.ok{color:var(--muted-2)}


/* ── modal ───────────────────────────────────────────────────────
   A short, blocking decision taken after a choice has been made —
   "which channel is this for", once you have picked a package.

   Deliberately NOT the order drawer. A drawer is for reading a thing
   that already exists beside the list it came from; this interrupts,
   wants one answer, and hands it straight to checkout. It is also
   built generically (openModal) because the same shape is wanted for
   every other product surface, not just packages.

   Scales from .96 rather than 0 — nothing in the real world appears
   out of nothing — and keeps transform-origin at centre, because
   unlike a popover it is not anchored to the thing that opened it.
   ──────────────────────────────────────────────────────────────── */
.mo-scrim{position:fixed;inset:0;z-index:70;background:rgba(4,4,6,.7);
  -webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);
  opacity:0;pointer-events:none;transition:opacity .2s ease}
body.mo-open .mo-scrim{opacity:1;pointer-events:auto}
.mo-wrap{position:fixed;inset:0;z-index:71;display:grid;place-items:center;padding:20px;
  pointer-events:none}
/* display:grid above beats the UA's [hidden]{display:none}, so a CLOSED modal
   stayed laid out over the page. The wrapper is pointer-events:none, but .mo
   below re-enables them — so the invisible panel sat centred in the viewport
   and swallowed clicks on whatever was under it (on /account: the email
   field, which is centred too, hence "can't type in the box"). */
.mo-wrap[hidden]{display:none}
/* Belt and braces: a modal that isn't open can never take a click, even if
   the hidden attribute is missed. */
body:not(.mo-open) .mo{pointer-events:none}
.mo{width:min(460px,100%);max-height:calc(100vh / var(--z) - 40px);
  display:flex;flex-direction:column;
  background:var(--panel);border:1px solid var(--line);border-radius:var(--r);
  box-shadow:0 24px 64px rgba(0,0,0,.5);
  opacity:0;transform:scale(.96);transform-origin:center;pointer-events:auto;
  transition:opacity .2s ease,transform .2s cubic-bezier(.23,1,.32,1)}
body.mo-open .mo{opacity:1;transform:none}

.mo-head{display:flex;align-items:flex-start;gap:12px;padding:17px 18px 15px;border-bottom:1px solid var(--line)}
.mo-head .tx{flex:1;min-width:0}
.mo-head b{display:block;font-size:15.5px;font-weight:700;letter-spacing:-.01em;color:var(--text)}
.mo-head span{display:block;margin-top:3px;font-size:12.5px;line-height:1.5;color:var(--muted)}
.mo-x{flex:none;width:30px;height:30px;border-radius:9px;border:0;background:var(--panel-2);
  color:var(--muted-2);cursor:pointer;display:grid;place-items:center;transition:background .15s,color .15s}
.mo-x svg{width:14px;height:14px}
.mo-x:hover{background:#2f2f36;color:var(--text)}

.mo-body{padding:17px 18px;overflow-y:auto;overscroll-behavior:contain}
.mo-foot{flex:none;display:flex;gap:9px;padding:14px 18px;border-top:1px solid var(--line);
  background:color-mix(in srgb,var(--panel-2) 55%,transparent)}
.mo-foot .btn{flex:1;justify-content:center;height:40px}

/* what you picked, restated so the decision is never made blind */
.mo-pick{display:flex;align-items:center;gap:12px;padding:12px 13px;border-radius:12px;
  background:var(--panel-2);border:1px solid var(--line);margin-bottom:16px}
.mo-pick .n{flex:1;min-width:0}
.mo-pick .n b{display:block;font-size:14px;font-weight:700;color:var(--text)}
.mo-pick .n span{display:block;margin-top:2px;font-size:12.5px;color:var(--muted)}
.mo-pick .p{flex:none;text-align:right}
.mo-pick .p b{display:block;font-size:16px;font-weight:800;letter-spacing:-.02em;color:var(--text);
  font-variant-numeric:tabular-nums}
.mo-pick .p span{display:block;font-size:11px;color:var(--muted)}

/* ── the chat-bot add-on ─────────────────────────────────────────
   Same row as .mo-pick so the modal reads as one stack: what you
   picked, who it is for, and what you can add to it. Collapsed to a
   single line until it is switched on, because most orders do not
   want it and an open panel of message options reads as a required
   step rather than an extra.
   ──────────────────────────────────────────────────────────────── */
.mo-addon{border:1px solid var(--line);border-radius:12px;background:var(--panel-2);
  margin-top:14px;overflow:hidden;transition:border-color .16s}
.mo-addon.on{border-color:rgba(74,214,255,.42)}
.mo-addon-hd{display:flex;align-items:center;gap:11px;width:100%;padding:12px 13px;
  background:none;border:0;text-align:left;cursor:pointer;color:inherit;font:inherit}
.mo-box{flex:none;width:18px;height:18px;border-radius:6px;border:1.6px solid var(--line);
  position:relative;transition:background .16s,border-color .16s}
.mo-addon.on .mo-box{background:var(--green,#4ad6ff);border-color:transparent}
.mo-addon.on .mo-box::after{content:"";position:absolute;left:5px;top:1.5px;width:5px;height:10px;
  border:solid #08080a;border-width:0 2px 2px 0;transform:rotate(45deg)}
.mo-addon-tx{flex:1;min-width:0}
.mo-addon-tx b{display:block;font-size:14px;font-weight:700;color:var(--text)}
.mo-addon-tx span{display:block;margin-top:2px;font-size:12.5px;color:var(--muted)}
.mo-addon-pr{flex:none;font-size:14px;font-weight:800;letter-spacing:-.02em;color:var(--text);
  font-variant-numeric:tabular-nums}

.mo-addon-opts{padding:0 13px 13px}
.mo-chips{display:flex;flex-wrap:wrap;gap:8px}
.mo-chip{appearance:none;border:1px solid var(--line);background:transparent;color:var(--muted);
  border-radius:999px;padding:7px 13px;font:inherit;font-size:12.5px;font-weight:600;cursor:pointer;
  transition:border-color .16s,color .16s,background .16s}
.mo-chip:hover{color:var(--text);border-color:rgba(255,255,255,.24)}
.mo-chip.on{background:var(--green,#4ad6ff);border-color:transparent;color:#08080a}
.mo-comments{display:block;width:100%;box-sizing:border-box;margin-top:10px;min-height:88px;
  padding:10px 12px;border-radius:10px;border:1px solid var(--line);background:var(--panel);
  color:var(--text);font:inherit;font-size:13px;line-height:1.5;resize:vertical}
.mo-comments:focus{outline:2px solid var(--green,#4ad6ff);outline-offset:1px;border-color:transparent}

@media(prefers-reduced-motion:reduce){ .mo,.mo-scrim{transition:none}
  .mo-addon,.mo-box,.mo-chip{transition:none} }
@media(max-width:520px){
  .mo-wrap{padding:0;place-items:end stretch}
  .mo{width:100%;max-height:88vh;border-radius:18px 18px 0 0;border-bottom:0;
    transform:translateY(16px) scale(1)}
  body.mo-open .mo{transform:none}
}

/* ── one-off packages ────────────────────────────────────────────
   Same card as the monthly tiers on purpose: a customer choosing
   between "500 viewers for 3 hours" and "the Regular package" is
   making one decision, and two different card designs would make it
   look like two different shops.
   ──────────────────────────────────────────────────────────────── */
.qp-grid{display:grid;grid-template-columns:1fr;gap:12px}
@media(min-width:560px){ .qp-grid{grid-template-columns:repeat(2,1fr)} }
@media(min-width:900px){ .qp-grid{grid-template-columns:repeat(3,1fr)} }
@media(min-width:1240px){ .qp-grid{grid-template-columns:repeat(3,1fr)} }

.qp{display:flex;align-items:center;gap:14px;padding:15px 16px;border-radius:var(--r);
  border:1px solid var(--line);background:var(--panel);width:100%;text-align:left;font:inherit;
  cursor:pointer;transition:border-color .15s ease,background .15s ease,transform .16s cubic-bezier(.23,1,.32,1)}
.qp:hover{border-color:color-mix(in srgb,var(--green) 38%,transparent);background:var(--panel-2)}
.qp:active{transform:scale(.99)}
.qp .n{flex:1;min-width:0}
.qp .n b{display:block;font-size:21px;font-weight:800;letter-spacing:-.025em;color:var(--text);
  line-height:1;font-variant-numeric:tabular-nums}
.qp .n span{display:block;margin-top:5px;font-size:12.5px;color:var(--muted)}
.qp .p{flex:none;text-align:right}
.qp .p b{display:block;font-size:17px;font-weight:800;letter-spacing:-.02em;color:var(--green);
  font-variant-numeric:tabular-nums}
.qp .p span{display:block;margin-top:3px;font-size:10.5px;color:#5e5e68;text-transform:uppercase;letter-spacing:.07em}

/* duration tabs reuse .tabs from the order lists */
.qp-note{margin:14px 0 0;font-size:12.5px;line-height:1.6;color:var(--muted);max-width:640px}
