/* Sidebar plan card — compact "Credit" surface (Figma Credit/Free). */
.sb-plan{
  --plan-accent:#98a2b3;
  --plan-soft:#f9fafb;
  --plan-border:rgba(159,159,159,.16);
  --plan-fill:#ff6357;
  --plan-track:rgba(255,99,87,.24);
  --plan-text:#101010;
  --plan-muted:#4b5563;
  --plan-strong:#101010;
  --plan-cta:#101010;
  --plan-manage-bg:#fff;
  --plan-manage-border:rgba(159,159,159,.24);
  --plan-manage-fg:#101010;
  box-sizing:border-box;
  position:relative;
  display:flex;
  flex-direction:column;
  align-items:stretch;
  /* 6px between the rows the card is made of. The card is always expanded, so the
     account head, notice, meters and CTA are siblings and this gap spaces them. */
  gap:6px;
  width:100%;
  min-width:0;
  margin:0 0 6px;
  padding:12px;
  background:var(--surface);
  border:1px solid var(--plan-border);
  border-radius:16px;
  box-shadow:var(--e-2);
  overflow:visible;
  overflow-wrap:anywhere;
}
.sb-plan[hidden]{display:none}
/* Spec 007 — the plan card owns a private --plan-* palette (Figma "Credit"
   surface), so the dark theme swaps those very variables instead of patching
   each rule. Ink values are the measured AA pairs from research.md §4. */
:root[data-theme="dark"] .sb-plan{
  --plan-soft:#1a1c21;
  --plan-border:rgba(255,255,255,.12);
  --plan-text:#f2f3f5; --plan-muted:#a9b1bd;
  --plan-strong:#f2f3f5;
  /* --plan-cta is a FILL (the upgrade button paints white labels on it), not an
     ink: dark keeps it dark-raised so #fff stays at 12.8:1. */
  --plan-cta:#23262d;
  --plan-manage-bg:var(--surface-hover);
  --plan-manage-border:rgba(255,255,255,.16);
  --plan-manage-fg:#f2f3f5;
}
:root[data-theme="dark"] .sb-plan[data-plan="guest"],
:root[data-theme="dark"] .sb-plan[data-plan="free"]{ --tag-fg:#c3c9d2; }
:root[data-theme="dark"] .sb-plan[data-plan="starter"]{ --tag-fg:#6ee7a0; }
:root[data-theme="dark"] .sb-plan[data-plan="creator"]{ --tag-fg:#8ab4ff; }
:root[data-theme="dark"] .sb-plan[data-plan="pro"]{ --tag-fg:#fcd34d; }
:root[data-theme="dark"] .sb-plan[data-plan="business"]{ --tag-fg:#c4a6ff; }
.sb-plan[data-plan="guest"],.sb-plan[data-plan="free"]{--plan-accent:#98a2b3;--tag-bg:rgba(159,159,159,.16);--tag-fg:#101010}
.sb-plan[data-plan="starter"]{--plan-accent:#31cc5b;--tag-bg:rgba(49,204,91,.24);--tag-fg:#31cc5b}
.sb-plan[data-plan="creator"]{--plan-accent:#4285f4;--tag-bg:rgba(66,133,244,.24);--tag-fg:#4285f4}
.sb-plan[data-plan="pro"]{--plan-accent:#fbbc05;--tag-bg:rgba(251,188,5,.24);--tag-fg:#fbbc05}
.sb-plan[data-plan="business"]{--plan-accent:#7c3aed;--tag-bg:rgba(124,58,237,.16);--tag-fg:#7c3aed}

.sb-plan-account{display:flex;align-items:center;gap:1px;min-width:0;padding:4px 0}
.sb-plan-avatar{flex:none;width:32px;height:32px;border-radius:16px;overflow:hidden;background:var(--canvas);display:grid;place-items:center}
.sb-plan-avatar img{width:100%;height:100%;object-fit:cover;display:block;border-radius:inherit}
.sb-plan-avatar-fallback{font-size:13px;font-weight:700;line-height:1;color:var(--text-3);text-transform:uppercase}
.sb-plan-who{display:flex;flex-direction:column;flex:1;min-width:0;gap:1.5px;padding:0 4px}
/* Account head mirrors the developers console card: the identity stacks — account
   name on line 1, plan badge on line 2, both left-aligned — instead of sitting on
   one row. The name keeps its ellipsis so a long name clips at the container edge
   rather than pushing the badge out; the badge keeps its inline-block pill (a
   centred flex pill clips at BOTH ends: "reator (legac"). */
.sb-plan-identity{display:flex;flex-direction:column;align-items:flex-start;gap:6px;min-width:0;width:100%}
.sb-plan-name{flex:0 0 auto;max-width:100%;min-width:0;font-size:14px;line-height:18px;font-weight:700;color:var(--plan-text);letter-spacing:-.01em;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.sb-plan-status{box-sizing:border-box;flex:0 200 auto;min-width:46px;max-width:88px;height:16px;padding:1px 6px;border:0;border-radius:16px;background:var(--tag-bg,rgba(159,159,159,.16));color:var(--tag-fg,#101010);font-size:12px;line-height:14px;font-weight:500;display:inline-block;text-align:center;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.sb-plan-status.active{background:var(--tag-bg,rgba(159,159,159,.16));color:var(--tag-fg,#101010)}
.usage-refresh{flex:none;width:24px;height:24px;margin-left:auto;display:grid;place-items:center;border:0;border-radius:8px;background:transparent;color:var(--plan-muted);cursor:pointer;touch-action:manipulation;transition:background .15s ease,color .15s ease}
.usage-refresh svg{width:14px;height:14px}
.usage-refresh:hover{background:var(--canvas);color:var(--plan-text)}
.usage-refresh:disabled{cursor:wait;opacity:.55}
.usage-refresh.is-loading svg{animation:usage-spin .8s linear infinite}
/* Collapse toggle for the plan card. Hides the notice, meters and CTA; the
   account row (avatar, name, badge, refresh) stays. The preference persists in
   localStorage (ov-sidebar-collapsed — historical key name, kept stable). */
.sb-collapse-btn{flex:none;width:24px;height:24px;padding:0;display:grid;place-items:center;border:0;border-radius:8px;background:transparent;color:var(--text-2);cursor:pointer;touch-action:manipulation;transition:background .15s ease,color .15s ease}
.sb-collapse-btn:hover{background:var(--surface-hover);color:#16161a}
.sb-collapse-btn svg{transition:transform .25s ease}
.sb-collapse-btn .sb-chevron-collapsed{transform:rotate(-180deg)}
#usageBar[data-collapsed] .sb-plan-notice,
#usageBar[data-collapsed] .sb-plan-credit,
#usageBar[data-collapsed] .sb-plan-upgrade{display:none}
/* No margin: .sb-plan's 6px gap spaces the rows, always-expanded card. */
.sb-plan-notice{margin:0;color:var(--plan-muted);font-size:12px;line-height:14px}
.sb-plan-notice:empty{display:none}

/* Near-limit paywall. No separate warning panel — a stacked red box in a 256px
   column wrapped to four lines and read as an error. The state is carried by the
   rows the card already has: the meter captions ("Còn 4.141/50.000 ký tự") take the
   warn tone and the card border is tinted, while the CTA opens the pricing view.
   Text always states the numbers, never colour alone. */
/* Only the metric that is actually nearly spent, plus the daily row when that is
   what will refuse the next run. Everything else stays muted, so red means "this is
   what is about to block you". */
.sb-plan-caption b[data-alert="true"],
.sb-plan-subrow[data-alert="true"]{color:var(--ov-action-dark);font-weight:600}
.sb-plan[data-quota-state="low"],
.sb-plan[data-quota-state="exhausted"]{border-color:var(--ov-brand-line)}

.sb-plan-credit{display:flex;flex-direction:column;gap:12px;min-width:0;padding:10px;background:var(--surface);border:1.2px solid var(--plan-border);border-radius:12px}
.sb-plan-metric{display:flex;flex-direction:column;gap:3px;min-width:0}
.sb-plan-label{position:relative;display:flex;align-items:center;gap:2px;min-width:0}
.sb-plan-label > span[data-usage-i18n]:not(.sb-plan-tip){min-width:0;font-size:13px;line-height:18px;font-weight:400;color:var(--plan-text);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.sb-plan-info{flex:none;width:12px;height:12px;padding:0;border:0;border-radius:999px;background:transparent;color:var(--plan-muted);display:grid;place-items:center;cursor:help}
.sb-plan-info:hover,.sb-plan-info:focus-visible{color:var(--plan-text)}
.sb-plan-info svg{width:12px;height:12px;display:block}
.sb-plan-tip{position:absolute;left:-8px;top:calc(100% + 4px);z-index:20;width:max-content;max-width:min(207px,calc(100% + 48px));padding:7px 8px;background:#282828;border:1.2px solid rgba(159,159,159,.12);border-radius:8px;box-shadow:var(--e-2);color:#fff;font-size:12px;line-height:15px;font-weight:400;opacity:0;visibility:hidden;transform:translateY(-3px);transition:opacity .12s ease,transform .12s ease,visibility .12s;pointer-events:none}
.sb-plan-info:hover + .sb-plan-tip,.sb-plan-info:focus-visible + .sb-plan-tip{opacity:1;visibility:visible;transform:translateY(0)}

.usage-track{width:100%;height:6px;background:var(--plan-track);border-radius:16px;overflow:hidden;flex:none;margin:0}
.usage-track.is-unavailable{background:repeating-linear-gradient(135deg,#f2f4f7,#f2f4f7 5px,#e4e7ec 5px,#e4e7ec 10px)}
.usage-fill{height:100%;width:0;background:var(--plan-fill);border-radius:16px;transition:width .3s ease}
.usage-fill.warn{background:#f79009}
.usage-fill.over{background:#d92d20}
.sb-plan-caption{display:flex;justify-content:flex-end;min-width:0}
.sb-plan-caption b{min-width:0;font-size:12px;line-height:15px;font-weight:400;color:var(--plan-muted);font-variant-numeric:tabular-nums;text-align:right;overflow-wrap:anywhere}
.sb-plan-subrow{margin:-9px 0 0;color:var(--plan-muted);font-size:12px;line-height:13px;font-variant-numeric:tabular-nums;text-align:right}
.sb-plan-subrow[hidden]{display:none}
/* Extra (non-expiring) credit: headroom behind the plan limit, so it stays
   quieter than the meters and never competes with a real warning. */
.sb-plan-credit-row{opacity:.85}
.sb-plan-period{margin:0;color:var(--plan-muted);font-size:12px;line-height:13px;opacity:1}
.sb-plan-period:empty{display:none}

/* Renewal strip (last 7 days of a bank-paid plan). Sits inside the credit block
   so it reads as part of the plan, not as a banner: one line of text explaining
   when it ends, one 44px button that opens the same QR at the same price.
   The accent is the plan's own colour, so it never competes with the paywall's
   coral CTA below it. */
.sb-plan-renew{display:flex;align-items:center;gap:8px;margin:2px 0 0;padding:8px 10px;border:1px solid var(--plan-track);background:var(--plan-soft);border-radius:12px;min-width:0}
.sb-plan-renew[hidden]{display:none}
.sb-plan-renew-text{margin:0;flex:1 1 auto;min-width:0;font-size:12px;line-height:15px;font-weight:500;color:var(--plan-text);overflow-wrap:anywhere}
.sb-plan-renew-btn{flex:none;min-height:32px;padding:6px 12px;border:0;border-radius:999px;background:var(--plan-fill);color:#fff;font-family:inherit;font-size:12px;font-weight:700;line-height:16px;cursor:pointer;touch-action:manipulation;white-space:nowrap}
.sb-plan-renew-btn:hover{filter:brightness(.95)}
.sb-plan-renew-btn:focus-visible{outline:2px solid var(--plan-text);outline-offset:2px}
@media (max-width:680px){
  /* On a phone the card is narrower than the sidebar: stack the button under the
     sentence instead of squeezing the date into two broken lines. */
  .sb-plan-renew{flex-direction:column;align-items:stretch;gap:6px}
  .sb-plan-renew-btn{min-height:44px;font-size:13px}
}

.sb-plan-upgrade{box-sizing:border-box;width:100%;min-height:36px;display:flex;align-items:center;justify-content:center;gap:6px;padding:7px 12px;border:1px solid rgba(0,0,0,.08);border-radius:8px;text-decoration:none;font-size:13px;line-height:18px;font-weight:500;letter-spacing:0;text-align:center;touch-action:manipulation;transition:background .15s ease,border-color .15s ease,color .15s ease,filter .15s ease}
.sb-plan-upgrade[data-cta="upgrade"]{background:var(--plan-cta);color:#fff}
.sb-plan-upgrade[data-cta="upgrade"]:hover{background:#262626}
.sb-plan-upgrade[data-cta="manage"]{border-color:var(--plan-manage-border);background:var(--plan-manage-bg);color:var(--plan-manage-fg)}
.sb-plan-upgrade[data-cta="manage"]:hover{background:var(--canvas);border-color:var(--plan-text)}
.sb-plan-upgrade svg{flex:none}
.sb-plan[data-state="loading"]{opacity:.72}
.usage-refresh:focus-visible,.sb-collapse-btn:focus-visible,.sb-plan-info:focus-visible,.sb-plan-upgrade:focus-visible{outline:2px solid var(--plan-accent);outline-offset:2px}
.sidebar.collapsed .sb-bottom{padding-left:12px;padding-right:12px}
.sidebar.collapsed .sb-plan{display:none}
.gen-cost-hint,.dub-cost-hint{font-size:12px;color:#61616a;white-space:nowrap}
.gen-cost-hint.over,.dub-cost-hint.over{color:#8a4705;font-weight:700}
.ov-plan-quota-overlay{position:fixed;inset:0;background:rgba(20,20,25,.52);display:grid;place-items:center;z-index:99999;padding:20px}
/* A touch of blur instead of more darkness: the work stays visible behind the wall,
   so the wall reads as an offer in front of the page rather than a blackout. */
@supports (backdrop-filter:blur(2px)){
  .ov-plan-quota-overlay{backdrop-filter:blur(2px) saturate(1.02);-webkit-backdrop-filter:blur(2px) saturate(1.02)}
}
.ov-plan-quota-modal{background:var(--surface);border-radius:16px;max-width:420px;width:100%;padding:24px;box-shadow:var(--e-3);position:relative;overflow-wrap:anywhere}
.ov-plan-quota-close{position:absolute;top:8px;right:8px;width:44px;height:44px;border:0;background:transparent;font-size:20px;line-height:1;color:#50505a;cursor:pointer;border-radius:8px;touch-action:manipulation}
.ov-plan-quota-close:hover{background:var(--canvas)}.ov-plan-quota-close:focus-visible,.ov-plan-quota-actions a:focus-visible,.ov-plan-quota-actions button:focus-visible{outline:3px solid #185abc;outline-offset:2px}
.ov-plan-quota-modal h2{margin:0 44px 8px 0;font-size:20px}.ov-plan-quota-msg{margin:0 0 8px;color:#42424b;font-size:14px}.ov-plan-quota-suggest{margin:0 0 16px;color:#8f2018;font-weight:800;font-size:13px}
.ov-plan-quota-actions{display:flex;flex-direction:column;gap:8px}.ov-plan-quota-actions a,.ov-plan-quota-actions button{min-height:44px;display:flex;align-items:center;justify-content:center;text-align:center;text-decoration:none;border-radius:999px;padding:11px 14px;font-weight:800;font-size:13px;cursor:pointer;touch-action:manipulation}
.ov-plan-quota-primary{background:var(--ov-action);color:#fff}.ov-plan-quota-primary:hover{background:var(--ov-action-dark)}.ov-plan-quota-later{background:transparent;border:0;color:var(--ov-ink-3)}
@keyframes usage-spin{to{transform:rotate(360deg)}}
@media (max-width:820px){.sidebar.collapsed .sb-plan{display:block}}
@media (prefers-reduced-motion:reduce){.usage-fill,.usage-refresh svg{transition:none!important;animation:none!important}}

/* Quota exceeded -> inline SePay upgrade. Keeps checkout in the studio so the
   user can pay and resume the skipped generation without losing their text. */
.ov-plan-quota-modal.ov-upgrade-payment{max-width:780px;max-height:92vh;overflow:auto;padding:22px 24px 24px}
.ov-upgrade-payment h2{margin:0 44px 4px 0;font-size:20px}
.ov-upgrade-subtitle{margin:0 0 12px;color:var(--text-2);font-size:13px;line-height:1.5}
.ov-upgrade-countdown{display:inline-flex;align-items:center;gap:7px;margin-bottom:14px;padding:6px 10px;border:1px solid var(--ov-brand-line);border-radius:999px;background:var(--ov-brand-soft);color:#b93a35;font-size:12px;font-weight:800;font-variant-numeric:tabular-nums}
.ov-upgrade-dot{width:6px;height:6px;border-radius:999px;background:#fe655d;box-shadow:0 0 0 4px rgba(254,101,93,.12)}
.ov-upgrade-grid{display:grid;grid-template-columns:240px minmax(0,1fr);gap:20px;align-items:start}
.ov-upgrade-qr-card{border:1px solid #ece7e7;border-radius:16px;background:var(--surface);padding:11px;text-align:center;box-shadow:var(--e-2)}
.ov-upgrade-qr-card img{display:block;width:100%;height:auto;border-radius:8px}
.ov-upgrade-qr-download{margin-top:10px;width:100%;min-height:38px;border:1px solid var(--ov-brand-line);border-radius:12px;background:var(--surface);color:#b93a35;font-size:12px;font-weight:800;display:inline-flex;align-items:center;justify-content:center;gap:7px;cursor:pointer;touch-action:manipulation}
.ov-upgrade-qr-download:hover{background:var(--ov-brand-soft)}
.ov-upgrade-info-row{display:flex;align-items:flex-start;justify-content:space-between;gap:14px;padding:7px 0;font-size:13px;line-height:1.4}
.ov-upgrade-label{color:var(--text-2);flex:0 0 auto}
.ov-upgrade-value{color:var(--text);font-weight:700;text-align:right;word-break:break-word}
.ov-upgrade-value.copy{display:inline-flex;align-items:center;justify-content:flex-end;gap:6px}
.ov-upgrade-copy{width:28px;height:28px;border:0;border-radius:8px;background:transparent;color:var(--text-2);display:grid;place-items:center;cursor:pointer;flex:0 0 auto;font-size:15px}
.ov-upgrade-copy:hover{background:var(--ov-brand-soft);color:#b93a35}
.ov-upgrade-divider{border:0;border-top:1px solid #ece7e7;margin:9px 0}
.ov-upgrade-warning{margin-top:12px;padding:11px 12px;border:1px solid #f4daa7;border-radius:12px;background:var(--warn-tint);color:#704400;font-size:12px;line-height:1.5}
.ov-upgrade-status{margin:14px 0 0;font-size:13px;font-weight:700;color:var(--text-2);min-height:18px}
.ov-upgrade-status.ok{color:#047857}.ov-upgrade-status.error{color:#be123c}
.ov-upgrade-actions{flex-direction:row;margin-top:16px}
.ov-upgrade-actions .ov-plan-quota-primary{flex:2}
.ov-upgrade-actions .ov-plan-quota-later{flex:1}
.ov-plan-quota-modal.ov-upgrade-payment .ov-plan-quota-close{top:10px;right:10px}
@media(max-width:680px){
  .ov-plan-quota-modal.ov-upgrade-payment{padding:18px 16px}
  .ov-upgrade-grid{grid-template-columns:1fr;gap:16px}
  .ov-upgrade-qr-card{max-width:260px;margin:0 auto}
  .ov-upgrade-actions{flex-direction:column-reverse}
  .ov-upgrade-actions .ov-plan-quota-primary,.ov-upgrade-actions .ov-plan-quota-later{flex:none}
}

/* Inline post-quota notice: keeps the editor text intact and offers the two
   shortest paths forward (upgrade or shorten) without a dead end. */
.ov-quota-notice{display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin:0 0 10px;padding:9px 10px 9px 12px;border:1px solid var(--ov-brand-line);border-radius:12px;background:var(--ov-brand-soft);color:var(--ov-ink);font-size:12px;line-height:1.4}
.ov-quota-notice-text{min-width:0;flex:1 1 260px;font-weight:650}
.ov-quota-notice-actions{display:flex;align-items:center;gap:7px;flex:none}
.ov-quota-notice-primary,.ov-quota-notice-secondary{min-height:32px;border-radius:8px;padding:0 11px;font-size:12px;font-weight:800;cursor:pointer;touch-action:manipulation;white-space:nowrap}
.ov-quota-notice-primary{border:1px solid var(--ov-action);background:var(--ov-action);color:#fff}
.ov-quota-notice-primary:hover{background:var(--ov-action-dark)}
.ov-quota-notice-secondary{border:1px solid var(--ov-brand-line);background:var(--surface);color:var(--ov-action-dark)}
.ov-quota-notice-secondary:hover{background:var(--ov-brand-tint)}
.ov-quota-notice-close{width:32px;height:32px;border:0;border-radius:8px;background:transparent;color:var(--ov-action-dark);font-size:20px;line-height:1;cursor:pointer;touch-action:manipulation}
.ov-quota-notice-close:hover{background:var(--ov-brand-tint)}
@media(max-width:760px){.ov-quota-notice{align-items:flex-start}.ov-quota-notice-text{flex-basis:100%}.ov-quota-notice-actions{width:100%;justify-content:flex-end}}

/* KB1 — in-editor paywall for the PER-REQUEST limit (max_chars_request).
   The monthly-quota notice above only appears once the period budget is nearly
   gone; this one warns while typing, before Generate, because 86% of paywall
   modals fire on the 3,000-chars-per-run limit of the free plan. Same palette
   and shape as .ov-quota-notice so the two read as one system. */
.ov-paywall-banner{display:flex;align-items:center;gap:10px;flex-wrap:wrap;
  margin:0 0 10px;padding:9px 10px 9px 12px;border:1px solid var(--ov-brand-line);border-radius:12px;
  background:var(--ov-brand-soft);color:var(--ov-ink);font-size:12px;line-height:1.4}
.ov-paywall-banner[hidden]{display:none}
.ov-paywall-text{min-width:0;font-weight:650}
.ov-paywall-offer{min-width:0;color:var(--ov-action-dark)}
.ov-paywall-actions{display:flex;align-items:center;gap:7px;margin-left:auto;flex:none}
.ov-paywall-primary,.ov-paywall-secondary{min-height:32px;border-radius:8px;padding:0 11px;font-size:12px;font-weight:800;cursor:pointer;touch-action:manipulation;white-space:nowrap}
.ov-paywall-primary{border:1px solid var(--ov-action);background:var(--ov-action);color:#fff}
.ov-paywall-primary:hover{background:var(--ov-action-dark)}
.ov-paywall-secondary{border:1px solid var(--ov-brand-line);background:var(--surface);color:var(--ov-action-dark)}
.ov-paywall-secondary:hover{background:var(--ov-brand-tint)}
@media(max-width:760px){.ov-paywall-banner{align-items:flex-start}.ov-paywall-text,.ov-paywall-offer{flex-basis:100%}.ov-paywall-actions{width:100%;margin-left:0;justify-content:flex-end}}

/* KB3 — plan ladder inside the quota modal. The old step named a single plan,
   so anyone who needed a bigger one had to guess or leave. Rows are led by the
   limit that actually triggered the modal (chars per run). */
.ov-plan-compare-title{margin:0 0 8px;font-size:12px;font-weight:800;letter-spacing:.06em;text-transform:uppercase;color:var(--text-2)}
.ov-plan-compare{list-style:none;margin:0 0 12px;padding:0;display:flex;flex-direction:column;gap:8px}
.ov-plan-row{display:flex;align-items:center;gap:12px;flex-wrap:wrap;border:1px solid #e6e6ea;border-radius:12px;padding:10px 12px;background:var(--surface)}
.ov-plan-row.is-rec{border-color:var(--ov-action);background:var(--ov-brand-soft)}
.ov-plan-row-main{min-width:0;flex:1 1 220px}
.ov-plan-row-head{display:flex;align-items:center;gap:8px;font-size:13px;color:#1c1c22}
.ov-plan-badge{font-size:12px;font-weight:800;letter-spacing:.03em;text-transform:uppercase;color:#fff;background:var(--ov-action);border-radius:999px;padding:2px 8px;white-space:nowrap}
.ov-plan-row-meta{font-size:12px;color:var(--ov-ink-3);margin-top:3px;line-height:1.35}
.ov-plan-row-yearly{font-size:12px;color:#6b6b74;margin-top:2px}
/* KB: phần tăng thêm so với gói đang dùng — chỉ hiện với khách đã trả tiền */
.ov-plan-row-delta{font-size:12px;font-weight:700;color:#1f7a45;margin-top:3px}
.ov-plan-row-cta{display:flex;align-items:center;gap:10px;margin-left:auto;flex:none}
.ov-plan-row-price{font-size:13px;font-weight:800;color:#1c1c22;white-space:nowrap}
.ov-plan-row-btn{min-height:32px;border:1px solid #d8d8de;background:var(--surface);color:#1c1c22;border-radius:8px;padding:0 11px;font-size:12px;font-weight:800;cursor:pointer;touch-action:manipulation;white-space:nowrap}
.ov-plan-row-btn:hover{background:var(--surface-hover)}
.ov-plan-row .ov-plan-quota-primary{min-height:32px;padding:0 12px;border-radius:8px;font-size:12px}
.ov-plan-quota-secondary{min-height:32px;border:1px solid #d8d8de;background:var(--surface);color:var(--ov-ink-3);border-radius:8px;padding:0 11px;font-size:12px;font-weight:700;cursor:pointer;touch-action:manipulation;white-space:nowrap}
.ov-plan-quota-secondary:hover{background:var(--surface-hover)}
@media(max-width:680px){.ov-plan-row-cta{margin-left:0;width:100%;justify-content:space-between}.ov-plan-compare{margin-bottom:10px}}

/* --- dialogs that own the screen ------------------------------------------
   A dialog that covers the viewport must own the scroll: before this the page
   behind it kept scrolling on touch devices, so a swipe on the plan ladder
   scrolled the editor underneath and the customer lost their place. */
html.ov-modal-open,
html.ov-modal-open body{overflow:hidden}
/* Locking the page steals the scrollbar, and everything underneath jumps 15px to the
   right at the exact moment the dialog appears. Reserving the gutter keeps the page
   still, which is most of why a modal feels "settled" instead of slapped on. */
html{scrollbar-gutter:stable}

/* Never taller than the viewport, always scrollable inside. Only the payment step
   had a max-height, so a three-plan ladder in 360px could push the actions (and
   the "not now" exit) below the visible area with no way to reach them. */
.ov-plan-quota-modal{
  /* width:100% + padding is content-box by default, which made the dialog 32px
     wider than the phone that opened it and pushed the close button off-screen. */
  box-sizing:border-box;
  max-height:calc(100dvh - 32px);
  overflow:auto;
  overscroll-behavior:contain;
  -webkit-overflow-scrolling:touch;
}
/* The recommended plan is chosen for the customer and pinned to the bottom, so
   on a phone the main action is reachable without scrolling the ladder. */
.ov-plan-quota-actions.is-sticky{
  position:sticky;bottom:-1px;z-index:2;
  margin-top:12px;padding:10px 0 calc(2px + env(safe-area-inset-bottom,0px));
  background:var(--surface);
  box-shadow:var(--e-2);
}
.ov-plan-row-selected{
  display:inline-grid;place-items:center;flex:none;
  width:28px;height:28px;border-radius:999px;
  background:var(--ov-action);color:#fff;font-size:14px;font-weight:800;
}
.ov-inline-offer{scroll-margin-top:12px}

/* Phones: the quota/payment dialog becomes a bottom sheet, the whole width of the
   screen, with the safe-area inset respected so the primary button clears the
   iOS home indicator. Tap targets grow to ~44px (the platform minimum). */
@media (max-width:680px){
  .ov-plan-quota-overlay{padding:0;place-items:end stretch}
  .ov-plan-quota-modal{
    width:100%;max-width:100%;
    max-height:94dvh;
    border-radius:16px 16px 0 0;
    padding:18px 16px calc(12px + env(safe-area-inset-bottom,0px));
  }
  .ov-plan-quota-modal h2{font-size:16px;margin-right:40px}
  .ov-plan-quota-close{top:6px;right:6px}
  .ov-plan-quota-msg{font-size:13px;margin-bottom:6px}
  /* Keep the ladder visible above the pinned action: three stacked buttons
     (primary + split + not-now) ate ~160px of a 640px screen and hid the last
     plan behind the bar. Primary keeps the full width; the two exits share a row.
     When there is no split button, "not now" takes the whole row instead. */
  .ov-plan-quota-actions.is-sticky{display:grid;grid-template-columns:1fr 1fr;gap:8px}
  .ov-plan-quota-actions.is-sticky > *{grid-column:1/-1}
  .ov-plan-quota-actions.is-sticky > .ov-plan-quota-later{grid-column:1/-1}
  .ov-plan-quota-actions.is-sticky.is-sticky-split > .ov-plan-quota-secondary,
  .ov-plan-quota-actions.is-sticky.is-sticky-split > .ov-plan-quota-later{grid-column:auto}
  .ov-plan-quota-actions a,.ov-plan-quota-actions button{min-height:46px}
  .ov-plan-quota-actions.is-sticky > .ov-plan-quota-secondary,
  .ov-plan-quota-actions.is-sticky > .ov-plan-quota-later{min-height:40px}
  .ov-plan-row-btn,.ov-plan-quota-secondary{min-height:40px;padding:0 14px;font-size:13px}
  .ov-plan-row-cta{width:100%;justify-content:space-between}
  .ov-plan-row-price{font-size:12px}
  /* Tighter ladder on a phone: four lines of copy per plan plus the pinned bar
     has to fit 640px without hiding the last plan. */
  .ov-plan-compare{gap:6px;margin-bottom:8px}
  .ov-plan-row{padding:9px 10px}
  .ov-plan-row-head{font-size:13px}
  .ov-plan-row-meta{font-size:12px;line-height:1.3;margin-top:2px}
  .ov-plan-row-yearly{font-size:12px;margin-top:1px}
  .ov-plan-compare-title{margin-bottom:6px}
  .ov-paywall-actions{width:100%;margin-left:0}
  .ov-paywall-primary,.ov-paywall-secondary,.ov-quota-notice-primary,.ov-quota-notice-secondary{min-height:40px}
  .ov-plan-quota-modal.ov-upgrade-payment{max-height:94dvh}
  .ov-upgrade-qr-card{max-width:min(260px,72vw)}
}

/* ==========================================================================
   Paywall — proposal C
   Brand ramp for identity/graphics, a darker action step for text-bearing
   buttons (4.84:1 with white), ink for copy, one action colour, and a
   two-step dialog (offer → optional compare → payment → done).
   ========================================================================== */
:root{
  --ov-brand:#FE655D;
  --ov-brand-strong:#FC3E57;
  --ov-brand-soft:#FFF4F2;
  --ov-brand-tint:#FFE7E4;
  --ov-brand-line:#FFD6D2;
  --ov-action:#CC3F39;
  --ov-action-dark:#B93631;
  --ov-ink:#111111;
  --ov-ink-2:#4B5563;
  --ov-ink-3:#6B7280;
  --ov-line:#E5E7EB;
  --ov-line-soft:#F1F1F4;
  --ov-success:#1F7A45;
  --ov-warn:#B45309;
  --ov-font:'Plus Jakarta Sans','Inter',-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Helvetica,Arial,sans-serif;
}

.ov-plan-quota-overlay{background:rgba(10,10,10,.45);padding:20px}
.ov-plan-quota-modal{
  box-sizing:border-box;
  width:100%;max-width:460px;
  max-height:calc(100dvh - 32px);
  overflow:auto;overscroll-behavior:contain;-webkit-overflow-scrolling:touch;
  padding:22px 22px 14px;
  border-radius:16px;
  box-shadow:var(--e-3);
  font-family:var(--ov-font);
  color:var(--ov-ink);
  word-spacing:.07em;
}
.ov-plan-quota-modal h2:focus{outline:none}
.ov-plan-quota-modal h2{margin:0 38px 6px 0;color:var(--ov-ink);font-size:20px;line-height:1.3;font-weight:800;letter-spacing:-.02em;text-wrap:balance}
.ov-plan-quota-modal .ov-sub{margin:0 0 14px;color:var(--ov-ink-2);font-size:14px;line-height:1.55}
.ov-plan-quota-close{top:6px;right:6px;width:44px;height:44px;color:var(--ov-ink-3)}
.ov-plan-quota-close:hover{background:var(--ov-line-soft);color:var(--ov-ink)}

/* gap meter: what the current plan covers vs what is missing */
.ov-gap{margin:0 0 16px}
.ov-gap-bar{display:flex;height:10px;border-radius:999px;overflow:hidden;background:var(--ov-line-soft)}
.ov-gap-bar .have{background:#D1D5DB;box-shadow:inset 0 0 0 1px #6B7280}
.ov-gap-bar .need{background:var(--ov-action)}
.ov-gap-legend{display:flex;gap:14px;flex-wrap:wrap;margin-top:7px;font-size:12px;color:var(--ov-ink-3)}
.ov-gap-legend span{display:inline-flex;align-items:center;gap:6px}
.ov-gap-legend i{width:7px;height:7px;border-radius:8px;display:inline-block}
.ov-gap-legend .have{background:#D1D5DB;border:1px solid #6B7280}
.ov-gap-legend .need{background:var(--ov-action)}

/* one recommended plan */
.ov-offer{border:1px solid var(--ov-brand-line);background:linear-gradient(180deg,var(--ov-brand-soft),#fff 64%);border-radius:16px;padding:14px 15px;margin:0 0 14px;box-shadow:var(--e-2)}
.ov-offer-top{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.ov-offer-top b{font-size:16px;letter-spacing:-.01em;color:var(--ov-ink)}
.ov-badge{font-size:12px;font-weight:800;letter-spacing:.02em;text-transform:uppercase;color:var(--ov-action-dark);background:var(--ov-brand-tint);border-radius:999px;padding:3px 8px}
.ov-offer-price{margin-left:auto;text-align:right;line-height:1.15;white-space:nowrap;font-variant-numeric:tabular-nums}
.ov-offer-price strong{font-size:20px;letter-spacing:-.01em;color:var(--ov-ink)}
.ov-offer-price span{font-size:12px;color:var(--ov-ink-3)}
.ov-offer-meta{margin:8px 0 0;font-size:12px;line-height:1.45;color:var(--ov-ink-2)}

/* Billing-cycle switch. Two 44px targets inside the offer card; the yearly one
   carries its own discount, computed from the catalogue (never hard-coded), so a
   price change cannot leave a stale "-66%" badge on screen. */
.ov-cycles{display:flex;align-items:center;gap:6px;flex-wrap:wrap;margin:0 0 13px;padding:4px;border:1px solid var(--ov-line);border-radius:999px;background:var(--ov-line-soft)}
.ov-cycle{flex:1 1 0;min-width:0;min-height:38px;padding:7px 10px;border:0;border-radius:999px;background:transparent;color:var(--ov-ink-2);font-family:var(--ov-font);font-size:12px;font-weight:700;line-height:16px;cursor:pointer;touch-action:manipulation;white-space:nowrap}
.ov-cycle.is-on{background:var(--surface);color:var(--ov-ink);box-shadow:var(--e-1)}
.ov-cycle:focus-visible{outline:2px solid var(--ov-action);outline-offset:2px}
.ov-cycle-save{flex:none;margin:0 6px 0 2px;font-size:12px;font-weight:800;letter-spacing:.01em;color:var(--ov-action-dark);background:var(--ov-brand-tint);border-radius:999px;padding:4px 9px;white-space:nowrap}
.ov-pick-year{display:block;margin-top:2px;font-size:12px;font-weight:400;color:var(--ov-ink-2)}
@media (max-width:680px){.ov-cycle{min-height:44px;font-size:13px}}

/* trust + free path + exits */
.ov-trust{list-style:none;margin:0 0 14px;padding:0;display:flex;flex-direction:column;gap:7px}
.ov-trust li{position:relative;padding-left:22px;font-size:13px;line-height:1.5;color:var(--ov-ink-2)}
.ov-trust li::before{content:"✓";position:absolute;left:0;top:0;color:var(--ov-success);font-weight:800}
.ov-free{display:flex;align-items:center;justify-content:center;width:100%;min-height:44px;margin:0 0 4px;border:1px solid var(--ov-line);border-radius:12px;background:var(--surface);color:var(--ov-ink);font-family:var(--ov-font);font-size:13px;font-weight:600;cursor:pointer;touch-action:manipulation}
.ov-free:hover{background:var(--ov-line-soft);border-color:#d7dae0}
.ov-foot{display:flex;align-items:center;justify-content:space-between;gap:10px;margin-top:10px;margin-bottom:2px}
.ov-link{background:none;border:0;border-radius:8px;padding:4px;color:var(--ov-action-dark);font-family:var(--ov-font);font-size:12px;font-weight:600;cursor:pointer}
.ov-link:hover{background:var(--ov-brand-soft)}
.ov-quiet{background:none;border:0;border-radius:8px;padding:4px;color:var(--ov-ink-3);font-family:var(--ov-font);font-size:12px;cursor:pointer}
.ov-quiet:hover{color:var(--ov-ink);background:var(--ov-line-soft)}

/* actions pinned to the bottom of the dialog */
.ov-actions.is-sticky{position:sticky;bottom:-1px;z-index:2;display:flex;flex-direction:column;gap:8px;margin-top:14px;padding:10px 0 calc(2px + env(safe-area-inset-bottom,0px));background:var(--surface);border-top:1px solid var(--ov-line-soft)}
.ov-primary{display:flex;align-items:center;justify-content:center;width:100%;min-height:50px;border:0;border-radius:12px;background:var(--ov-action);color:#fff;font-family:var(--ov-font);font-size:14px;font-weight:700;letter-spacing:-.01em;text-align:center;text-decoration:none;cursor:pointer;box-shadow:var(--e-2);transition:filter .12s ease,box-shadow .12s ease,transform .12s ease}
.ov-primary:hover{background:var(--ov-action-dark);box-shadow:var(--e-2)}
.ov-primary:active{transform:translateY(1px)}
.ov-secondary{display:flex;align-items:center;justify-content:center;width:100%;min-height:44px;border:1px solid var(--ov-line);border-radius:12px;background:var(--surface);color:var(--ov-ink);font-family:var(--ov-font);font-size:13px;font-weight:600;cursor:pointer}
.ov-secondary:hover{background:var(--ov-line-soft)}
.ov-micro{margin:8px 0 0;text-align:center;color:var(--ov-ink-3);font-size:12px;line-height:1.5}

/* compare step: radio rows, one CTA */
.ov-back{display:inline-flex;align-items:center;gap:5px;border:0;background:none;color:var(--ov-ink-3);font-family:var(--ov-font);font-size:12px;cursor:pointer;padding:2px 0;margin:0 0 8px}
.ov-back:hover{color:var(--ov-ink)}
.ov-picks{display:flex;flex-direction:column;gap:8px;margin:0 0 12px}
.ov-pick{position:relative;display:flex;align-items:center;gap:11px;border:1px solid var(--ov-line);border-radius:12px;padding:11px 12px;background:var(--surface);cursor:pointer}
.ov-pick.is-on{border-color:var(--ov-brand-line);background:linear-gradient(180deg,var(--ov-brand-soft),#fff 70%);box-shadow:var(--e-2)}
.ov-pick input{position:absolute;opacity:0;pointer-events:none}
.ov-pick:focus-within{outline:2px solid var(--ov-action);outline-offset:2px}
.ov-radio{flex:none;width:20px;height:20px;border-radius:999px;border:1.5px solid #6B7280;background:var(--surface);display:grid;place-items:center}
.ov-pick.is-on .ov-radio{border-color:var(--ov-action);background:var(--ov-action)}
.ov-radio::after{content:"";width:7px;height:7px;border-radius:999px;background:var(--surface);opacity:0}
.ov-pick.is-on .ov-radio::after{opacity:1}
.ov-pick-main{min-width:0;flex:1}
.ov-pick-name{display:flex;align-items:center;gap:7px;font-size:14px;font-weight:700;color:var(--ov-ink)}
.ov-pick-meta{display:block;margin-top:2px;font-size:12px;line-height:1.4;color:var(--ov-ink-3)}
.ov-pick.is-on .ov-pick-meta,.ov-pick.is-on .ov-pick-price span{color:var(--ov-ink-2)}
.ov-pick-price{font-size:13px;font-weight:800;white-space:nowrap;font-variant-numeric:tabular-nums;color:var(--ov-ink)}
.ov-pick-price span{font-size:12px;font-weight:400;color:var(--ov-ink-3)}

/* payment */
.ov-steps{margin:0 0 10px;color:var(--ov-ink-3);font-size:12px;font-weight:700;letter-spacing:.02em;text-transform:uppercase}
.ov-amount{display:flex;align-items:flex-end;justify-content:space-between;gap:12px;margin:2px 0 10px;padding:0 0 12px;border-bottom:1px solid var(--ov-line-soft)}
.ov-amount-plan{font-size:12px;line-height:1.4;color:var(--ov-ink-3)}
.ov-amount-plan b{display:block;color:var(--ov-ink);font-size:13px}
.ov-amount strong{font-size:24px;letter-spacing:-.02em;font-variant-numeric:tabular-nums;white-space:nowrap}
.ov-qr{width:min(210px,70%);aspect-ratio:1;border:1px solid #ECE7E7;border-radius:12px;margin:0 auto 10px;display:flex;align-items:center;justify-content:center;overflow:hidden;background:var(--surface)}
.ov-qr img{width:100%;height:100%;object-fit:contain;display:block}
.ov-qr-dl{display:block;margin:0 auto 12px;min-height:36px;padding:0 12px;border:1px solid var(--ov-brand-line);border-radius:8px;background:var(--surface);color:var(--ov-action-dark);font-family:var(--ov-font);font-size:12px;font-weight:700;cursor:pointer}
.ov-rows{display:flex;flex-direction:column;margin:0 0 10px}
.ov-row{display:flex;justify-content:space-between;gap:12px;padding:8px 0;border-bottom:1px solid var(--ov-line-soft);font-size:12px;line-height:1.45}
.ov-row:last-child{border-bottom:0}
.ov-row span{flex:none;color:var(--ov-ink-3)}
.ov-row b{text-align:right;word-break:break-word;font-weight:700;font-variant-numeric:tabular-nums}
.ov-copy{width:28px;height:28px;margin-left:4px;border:0;border-radius:8px;background:transparent;color:var(--ov-ink-3);cursor:pointer}
.ov-copy:hover{background:var(--ov-brand-soft);color:var(--ov-action-dark)}
.ov-countdown{display:inline-flex;align-items:center;gap:6px;margin:0 0 10px;padding:5px 10px;border:1px solid var(--ov-brand-line);border-radius:999px;background:var(--ov-brand-soft);color:var(--ov-action-dark);font-size:12px;font-weight:800;font-variant-numeric:tabular-nums}
.ov-countdown::before{content:"";width:6px;height:6px;border-radius:999px;background:var(--ov-brand-strong)}
.ov-status{margin:0 0 12px;color:var(--ov-ink-3);font-size:12px;line-height:1.5}
.ov-status.error{color:#B42318}
.ov-status.ok{color:var(--ov-success)}
.ov-support{margin:10px 0 0;text-align:center;color:var(--ov-ink-3);font-size:12px;line-height:1.5}
.ov-fine{margin:6px 0 0;text-align:center;color:var(--ov-ink-3);font-size:12px;line-height:1.5}

/* done */
.ov-done-tick{width:44px;height:44px;margin:0 0 12px;border-radius:999px;background:var(--ov-brand-tint);color:var(--ov-action-dark);display:grid;place-items:center;font-size:20px;font-weight:800}
.ov-progress{height:5px;margin:0 0 12px;border-radius:999px;background:var(--ov-line-soft);overflow:hidden}
.ov-progress span{display:block;height:100%;width:62%;border-radius:999px;background:var(--ov-action)}

/* focus */
.ov-primary:focus-visible,.ov-secondary:focus-visible,.ov-free:focus-visible,.ov-link:focus-visible,.ov-quiet:focus-visible,.ov-back:focus-visible,.ov-plan-quota-close:focus-visible,.ov-qr-dl:focus-visible,.ov-copy:focus-visible{outline:2px solid var(--ov-action);outline-offset:2px}

/* inline surfaces adopt the same palette */
.ov-paywall-banner,.ov-quota-notice{border-color:var(--ov-brand-line);background:var(--ov-brand-soft);color:var(--ov-ink)}
.ov-paywall-offer{color:var(--ov-action-dark)}
.ov-paywall-primary,.ov-quota-notice-primary{border:1px solid transparent;background:var(--ov-action);color:#fff}
.ov-paywall-primary:hover,.ov-quota-notice-primary:hover{background:var(--ov-action-dark)}
.ov-paywall-secondary,.ov-quota-notice-secondary{border:1px solid var(--ov-brand-line);background:var(--surface);color:var(--ov-action-dark)}
.ov-paywall-secondary:hover,.ov-quota-notice-secondary:hover{background:var(--ov-brand-tint)}
.ov-quota-notice-close{color:var(--ov-action-dark)}
.ov-quota-notice-close:hover{background:var(--ov-brand-tint)}

@media (max-width:680px){
  .ov-plan-quota-overlay{padding:0;place-items:end stretch}
  .ov-plan-quota-modal{width:100%;max-width:100%;max-height:94dvh;border-radius:16px 16px 0 0;padding:18px 16px calc(12px + env(safe-area-inset-bottom,0px))}
  .ov-plan-quota-modal h2{font-size:20px}
  .ov-primary{min-height:46px}
  .ov-free,.ov-secondary{min-height:40px}
  .ov-pick{padding:10px}
  .ov-pick-price{font-size:13px}
  .ov-amount strong{font-size:24px}
  .ov-qr{width:min(190px,66%)}
}

/* Discount code in the in-place checkout. The code only ever reaches SePay as a
   smaller amount, so the field lives with the amount it changes. */
.ov-amount-list{display:block;margin-top:2px;font-size:12px;font-weight:600;letter-spacing:0;color:var(--ov-ink-3);text-decoration:line-through}
.ov-discount{margin:0 0 12px}
.ov-discount-label{display:block;margin-bottom:5px;font-family:var(--ov-font);font-size:12px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:var(--ov-ink-3)}
.ov-discount-row{display:flex;align-items:stretch;gap:8px}
.ov-discount-input{flex:1 1 auto;min-width:0;min-height:42px;padding:9px 13px;border:1px solid var(--ov-line);border-radius:12px;background:var(--surface);font-family:var(--ov-font);font-size:13px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:var(--ov-ink)}
.ov-discount-input::placeholder{font-weight:500;letter-spacing:0;text-transform:none;color:var(--ov-ink-3)}
.ov-discount-apply{width:auto;flex:0 0 auto;min-height:42px;padding:0 18px}
.ov-discount-on{display:flex;align-items:center;justify-content:space-between;gap:10px;flex-wrap:wrap;font-family:var(--ov-font);font-size:13px;font-weight:700;color:var(--ov-success)}
.ov-discount-msg{margin:7px 0 0;font-family:var(--ov-font);font-size:12px;color:var(--ov-ink-3)}
.ov-discount-msg.ok{color:var(--ov-success);font-weight:700}
.ov-discount-msg.error{color:var(--ov-action);font-weight:700}
.ov-discount-msg[hidden]{display:none}
@media(max-width:480px){.ov-discount-apply{padding:0 14px}}

.sb-plan .sb-plan-status{color:var(--info-ink);background:var(--info-soft);}

/* ===========================================================================
   Offer dialog v2 (redesign 2026-11-07) — the "quota paywall" the customer
   sees from every wall. Layout follows the reference design: promo strip,
   two columns (hero art | plan panel), plan tabs, credits headline, feature
   list, monthly/yearly price cards and one pill CTA.

   Everything is scoped under `.ovp-v2`, the modifier `renderOfferStep()` puts
   on `.ov-plan-quota-modal`. The old offer/payment/compare/done steps keep
   their own styles, so this block cannot leak into them.
   ========================================================================= */
.ovp-v2{
  --ovp-accent:#F97316;
  --ovp-accent-ink:#C2410C;
  --ovp-ink:#16110D;
  --ovp-ink-2:#4C4139;
  --ovp-ink-3:#6F665E;
  --ovp-line:#EDE6DF;
  --ovp-soft:#FBF7F3;
  --ovp-cta:#111111;
  width:100%;
  /* 2026-11-08: the panel read cramped — 14px feature lines stacked 4px apart inside a
     840px dialog. The canvas grows to 920 and every rhythm below is loosened, which is
     how a dense list starts to breathe without dropping a single line of content. */
  max-width:920px;
  padding:0;
  border:0;
  border-radius:36px;
  background:#fff;
  box-shadow:var(--e-3);
  overflow:hidden;
  display:flex;
  flex-direction:column;
  max-height:calc(100dvh - 24px);
  color:var(--ovp-ink);
  font-family:var(--ov-font);
}
.ovp-v2.ov-plan-quota-modal{max-width:920px;overflow:hidden}
/* Promo strip. Was a solid rust band (#A93404 → #C8470B) with white type: it read as
   a warning bar and competed with the CTA. 2026-11-08: "sửa lại màu nền cho nhạt hơn,
   dùng luôn màu nền của ảnh" — these stops are sampled from the hero photograph itself
   (upgrade-dialog/audio-space.png: canvas #FDF6F4, mid #FBE4D8, peach #FADAC6), so the
   strip flows into the photo's top edge instead of sitting on it. The wash is symmetric
   (both ends at the photo's canvas colour, the peach halo sitting under the sentence) so
   the band does not look heavier on the side above the white panel. White type cannot
   hold 4.5:1 on these tints; #8A3A10 measured 6.99:1 on the rendered band. */
.ovp-promo{
  flex:none;
  padding:8px 18px 22px;
  border-radius:32px 32px 0 0;
  background:linear-gradient(94deg,#FDF6F4 0%,#FBE4D8 38%,#FADAC6 50%,#FBE4D8 62%,#FDF6F4 100%);
  color:#8A3A10;
  text-align:center;
  font-size:12.5px;
  font-weight:650;
  line-height:17px;
  letter-spacing:.01em;
}
.ovp-body{
  flex:1;
  min-height:0;
  display:flex;
  gap:0;
  margin-top:-17px;
  padding:10px;
  border-radius:36px;
  background:#fff;
  height:520px;
}
/* ---- left: hero ---------------------------------------------------------- */
.ovp-hero{
  position:relative;
  flex:1.02 1 0;
  min-width:0;
  display:flex;
  flex-direction:column;
  justify-content:space-between;
  gap:22px;
  padding:26px;
  border-radius:28px;
  overflow:hidden;
  background:#FFF1E6;
}
/* Reference hero: one photographic background, cropped like object-cover. */
.ovp-hero-photo{position:absolute;inset:0;z-index:0;width:100%;height:100%;object-fit:cover;object-position:50% 55%}
/* The wordmark is knocked out to white, so the top-left corner needs a darker
   wash: without it the last letters sit on near-white peach and vanish. */
.ovp-hero::before{content:"";position:absolute;inset:0;z-index:1;pointer-events:none;
  /* The photo is light; a small warm scrim under the wordmark keeps the white logo
     legible, and a soft wash at the bottom keeps the title readable. */
  background:
    radial-gradient(115% 62% at 0% 0%,rgba(104,38,8,.30) 0%,rgba(104,38,8,0) 56%),
    linear-gradient(180deg,rgba(255,249,244,0) 52%,rgba(255,249,244,.62) 100%)}
.ovp-hero-logo{position:relative;z-index:2;display:inline-flex;align-items:center;gap:6px;color:#fff;font-family:var(--ov-font);font-size:15px;line-height:20px;font-weight:750;letter-spacing:-.02em;text-shadow:0 1px 3px rgba(104,38,8,.45)}
.ovp-hero-mark{width:18px;height:18px;filter:brightness(0) invert(1);opacity:.98;flex:none}
.ovp-hero-copy{position:relative;z-index:2;display:flex;flex-direction:column;gap:12px;max-width:400px}
.ovp-hero-copy h3{margin:0;color:#26170F;font-size:27px;line-height:35px;font-weight:700;letter-spacing:-.02em;text-wrap:balance}
.ovp-hero-copy p{margin:0;color:#5C473B;font-size:14.5px;line-height:22px;font-weight:500}
.ovp-hero-note{margin:1px 0 0;color:#7A6152;font-size:11.5px;line-height:16px;font-weight:500}
/* ---- right: plan panel --------------------------------------------------- */
.ovp-offer{
  flex:1.08 1 0;
  min-width:0;
  display:flex;
  flex-direction:column;
  gap:15px;
  padding:18px 20px 8px;
  margin:0;
  border:0;
  background:transparent;
  box-shadow:none;
}
.ovp-head{display:flex;align-items:center;justify-content:space-between;gap:8px;min-height:36px}
.ovp-tabs{
  display:inline-flex;
  align-items:center;
  gap:3px;
  padding:3px;
  border-radius:999px;
  background:#F4F0EC;
  box-shadow:inset 0 0 0 .5px #E8E1DA;
}
.ovp-tab{
  position:relative;
  display:inline-flex;
  align-items:center;
  justify-content:center;
  gap:6px;
  height:34px;
  min-width:38px;
  padding:0 14px;
  border:0;
  border-radius:999px;
  background:transparent;
  color:#5F564F;
  font-family:var(--ov-font);
  font-size:13px;
  font-weight:600;
  line-height:20px;
  white-space:nowrap;
  cursor:pointer;
  transition:background-color .1s ease,color .1s ease;
}
.ovp-tab:hover{color:var(--ovp-ink)}
.ovp-tab[aria-checked="true"]{background:#fff;color:var(--ovp-ink);box-shadow:0 1px 3px rgba(17,17,17,.12)}
.ovp-tab .ovp-rec{font-size:8.5px;padding:2px 5px}
.ovp-tab:focus-visible{outline:2px solid var(--ovp-accent);outline-offset:2px}
.ovp-rec{
  font-size:9px;
  font-weight:800;
  letter-spacing:.05em;
  text-transform:uppercase;
  color:#A93A04;
  background:#FFE7D5;
  border-radius:999px;
  padding:2px 6px;
  line-height:1;
}
.ovp-v2 .ov-plan-quota-close.ovp-close{
  position:static;
  flex:none;
  width:36px;
  height:36px;
  display:grid;
  place-items:center;
  border-radius:999px;
  color:#8A8078;
  font-size:22px;
  line-height:1;
  background:transparent;
}
.ovp-v2 .ov-plan-quota-close.ovp-close:hover{background:#F4F0EC;color:var(--ovp-ink)}
/* credits block */
.ovp-credits{display:flex;align-items:flex-start;gap:8px;min-width:0}
.ovp-star{flex:none;width:22px;height:28px;display:grid;place-items:center;color:var(--ovp-ink)}
.ovp-credits-main{min-width:0;flex:1}
.ovp-credits h4{margin:0;display:flex;align-items:center;gap:9px;flex-wrap:wrap;color:var(--ovp-ink);font-size:19px;line-height:28px;font-weight:500;letter-spacing:.005em}
.ovp-credits p{margin:4px 0 0;color:var(--ovp-ink-3);font-size:12.5px;line-height:18px;font-weight:400}
/* feature list — the only scroll container on desktop */
.ovp-features{
  min-height:0;
  /* Height is a whole number of rows (24px each) so the list never cuts a row in
     half; the mask tells the eye there is more below (the scrollbar is overlay
     style on most desktop platforms and stays invisible until scrolled). */
  max-height:250px;
  overflow-y:auto;
  overscroll-behavior:contain;
  padding-right:2px;
  display:flex;
  flex-direction:column;
  gap:9px;
  scrollbar-width:thin;
}
.ovp-feat{display:flex;align-items:flex-start;gap:10px;min-width:0;font-size:14px;line-height:22px;font-weight:400;color:var(--ovp-ink-2)}
.ovp-feat svg{flex:none;width:20px;height:22px;color:var(--ovp-accent)}
.ovp-feat b{font-weight:650;color:var(--ovp-accent-ink)}
.ovp-inherit{display:inline-flex;align-items:center;gap:8px;align-self:flex-start;border:0;background:none;padding:0;font-family:var(--ov-font);font-size:14px;line-height:20px;color:var(--ovp-ink-2);cursor:pointer}
.ovp-inherit svg{flex:none;width:20px;height:20px;color:var(--ovp-accent)}
.ovp-inherit:hover{opacity:.8}
.ovp-inherit[hidden],.ovp-inherit-list[hidden]{display:none}
.ovp-inherit-list{margin:0;padding:0 0 0 28px;list-style:none;display:flex;flex-direction:column;gap:2px;font-size:12.5px;line-height:18px;color:var(--ovp-ink-3)}
/* price cards */
/* Two cards must read as a pair: same width, same top edge, same bottom edge.
   `align-items:end` used to bottom-align them, so a card with one extra line of
   copy (the yearly one) grew upwards and left its caption floating higher; the
   uneven .92fr/1.08fr columns made the pair look lopsided too. */
.ovp-prices{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));align-items:stretch;gap:12px;flex:none}
.ovp-price-wrap{display:flex;flex-direction:column;gap:4px;min-width:0;height:100%}
.ovp-refund{margin:0;padding:0 2px;color:var(--ovp-ink-3);font-size:11.5px;line-height:16px;font-weight:500;text-align:center;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-height:16px}
.ovp-price-wrap:first-child .ovp-refund{color:var(--ovp-ink-3)}
.ovp-price{
  display:flex;
  align-items:flex-start;
  gap:9px;
  width:100%;
  min-width:0;
  flex:1 1 auto; /* fill the stretched column so both cards are the same height */
  padding:12px 14px;
  border:1px solid var(--ovp-line);
  border-radius:16px;
  background:#fff;
  text-align:left;
  font-family:var(--ov-font);
  cursor:pointer;
  transition:border-color .1s ease,box-shadow .1s ease;
}
.ovp-price:hover{border-color:#D9CFC6}
.ovp-price[aria-checked="true"]{border-color:var(--ovp-accent);box-shadow:0 0 0 1px var(--ovp-accent)}
.ovp-price:focus-visible{outline:2px solid var(--ovp-accent);outline-offset:2px}
.ovp-radio{flex:none;width:20px;height:20px;display:grid;place-items:center;border:1px solid #CFC7BF;border-radius:999px;background:#fff}
.ovp-price[aria-checked="true"] .ovp-radio{border-color:var(--ovp-accent);background:var(--ovp-accent)}
.ovp-price[aria-checked="true"] .ovp-radio::after{content:"";width:8px;height:8px;border-radius:999px;background:#fff}
.ovp-price-body{display:flex;min-width:0;flex:1;flex-direction:column;gap:1px}
/* Price: the head number carries the hierarchy, the trailing ".000" is small
   (reference design), and the currency mark stays a whisper before it.
   Size/weight are a psychology lever, not decoration: perceived magnitude tracks
   font size (Coulter & Coulter 2005, "size does matter") and perceived weight, and
   the leading digits anchor the whole number (left-digit effect, Thomas & Morwitz
   2005). At 26px/750 with -0.03em the number read as a billboard — "to lớn và đắt"
   (feedback 2026-11-08). Measured five size/weight pairs on the same card before
   choosing (reports/paywall-audit-20261107/shots/_price-tiers.png): 22px/600 keeps
   the number the first thing the eye lands on inside the card while shrinking the
   felt magnitude; normal tracking stops the digits clumping into one heavy block.
   Going below 21px stopped reading as a price next to the 12.5px meta line, which
   costs more trust than the "cheap feeling" gains. */
.ovp-price-amount{display:flex;align-items:baseline;gap:1px;flex-wrap:nowrap;white-space:nowrap;color:var(--ovp-ink)}
.ovp-cur{color:var(--ovp-ink-3);font-size:10.5px;line-height:14px;font-weight:500;margin-right:2px}
.ovp-major{font-size:22px;line-height:25px;font-weight:600;letter-spacing:-.005em}
.ovp-minor{font-size:12.5px;line-height:24px;font-weight:600;letter-spacing:0}
.ovp-per{color:var(--ovp-ink-3);font-size:12px;line-height:16px;font-weight:400;margin-left:3px}
.ovp-price-meta{display:flex;align-items:baseline;gap:3px;flex-wrap:wrap;color:var(--ovp-ink-3);font-size:12px;line-height:16px;font-weight:400}
.ovp-total{color:var(--ovp-ink-2);font-weight:600}
/* trust + actions */
.ovp-trust{margin:0;display:flex;align-items:center;justify-content:center;gap:6px 14px;flex-wrap:wrap;color:var(--ovp-ink-3);font-size:11.5px;line-height:16px;font-weight:500}
.ovp-trust span{display:inline-flex;align-items:center;gap:5px}
.ovp-trust svg{width:13px;height:13px;color:#1F7A45}
.ovp-v2 .ov-actions.is-sticky{
  position:sticky;
  bottom:0;
  z-index:2;
  margin-top:auto;
  padding:6px 0 0;
  border-top:0;
  background:transparent;
  gap:8px;
}
.ovp-v2 .ov-primary{
  min-height:50px;
  border-radius:999px;
  background:var(--ovp-cta);
  color:#fff;
  font-size:15px;
  font-weight:600;
  letter-spacing:0;
  box-shadow:0 1px 2px rgba(17,17,17,.18);
}
.ovp-v2 .ov-primary:hover{background:#1C1C1C;filter:none}
.ovp-v2 .ov-free{
  min-height:44px;
  border:1px solid var(--ovp-line);
  border-radius:999px;
  background:#fff;
  color:var(--ovp-ink);
  font-size:13px;
  font-weight:600;
}
.ovp-v2 .ov-free:hover{background:var(--ovp-soft);border-color:#D9CFC6}
.ovp-links{display:flex;align-items:center;justify-content:center;gap:4px 14px;flex-wrap:wrap;margin:0;padding:0}
.ovp-link{border:0;background:none;padding:7px 2px;border-radius:8px;color:#8A5A3C;font-family:var(--ov-font);font-size:12px;line-height:16px;font-weight:600;cursor:pointer}
.ovp-link:hover{color:var(--ovp-accent-ink);text-decoration:underline}
.ovp-link.ovp-muted{color:var(--ovp-ink-3);font-weight:500}
/* the top-plan case: nothing to sell, one human path */
.ovp-empty{display:flex;flex-direction:column;gap:10px;margin-top:4px}
.ovp-empty p{margin:0;color:var(--ovp-ink-2);font-size:14px;line-height:21px}

/* ---------------------------------------------------------------------------
   Entrance motion. One direction, one curve, no bounce.

   A paywall is an interruption; the animation's job is to make the interruption
   read as "this slid in" instead of "the screen was replaced". So: a 180ms dim on
   the backdrop, and the dialog itself travels 6px (18px as a phone sheet) while it
   fades — nothing scales up past 1, nothing overshoots, nothing waits. Overshoot
   and long entrances are what make an upsell feel eager; a short decelerating move
   is read as competence.

   Exit is intentionally instant: the dialog must be gone the moment the customer
   dismisses it. A lingering wall is more annoying than an abrupt one, and the
   caller (closeModal) needs the element gone synchronously for focus restore.

   `prefers-reduced-motion: reduce` removes the movement entirely and keeps only a
   fade, which is also what a vestibular-sensitive customer expects.
   --------------------------------------------------------------------------- */
@keyframes ovp-overlay-in{from{opacity:0}to{opacity:1}}
@keyframes ovp-dialog-in{from{opacity:0;transform:translateY(6px) scale(.99)}to{opacity:1;transform:none}}
@keyframes ovp-sheet-in{from{opacity:0;transform:translateY(18px)}to{opacity:1;transform:none}}
.ov-plan-quota-overlay{animation:ovp-overlay-in 180ms cubic-bezier(.2,0,0,1) both}
.ov-plan-quota-modal{animation:ovp-dialog-in 220ms cubic-bezier(.2,0,0,1) both}
/* the hero photograph decodes a beat after the shell paints: fade it in so the
   dialog never shows a half-painted image, and never "pops" */
.ovp-hero-photo{opacity:0;transition:opacity .35s var(--ovp-ease-out,cubic-bezier(.2,0,0,1))}
.ovp-hero-photo.is-ready{opacity:1}
@media (max-width:680px){
  .ov-plan-quota-modal{animation-name:ovp-sheet-in;animation-duration:240ms}
}
@media (prefers-reduced-motion:reduce){
  .ov-plan-quota-overlay{animation:none}
  .ov-plan-quota-modal{animation:none}
  .ovp-hero-photo{transition:none;opacity:1}
}

/* ---------------------------------------------------------------------------
   Pay skin — the single-column steps of the same dialog (QR transfer, done,
   cancel, payment error). Before this the offer looked like the new design and
   the very next screen switched back to the 420px red-accent card, so the same
   customer saw two products in two clicks (feedback 2026-11-08: "deploy thay cho
   toàn bộ modal"). The markup is deliberately untouched — same ids, same data-
   attributes — so the intent/polling/discount logic and every existing test keep
   working; only the tokens and the type scale change.
   --------------------------------------------------------------------------- */
.ovp-v2.ovp-pay{
  max-width:560px;
  padding:26px 26px 22px;
  border-radius:28px;
  gap:0;
  overflow-y:auto;
  overscroll-behavior:contain;
  /* the legacy step markup reads its colours from the --ov-* tokens; point them at
     the v2 palette here so the two steps cannot drift apart again. */
  --ov-action:#111111;
  --ov-action-dark:#000000;
  --ov-brand-line:#EDE6DF;
  --ov-brand-soft:#FDF6F4;
  --ov-brand-tint:#FBEDE6;
  --ov-brand-strong:#F97316;
  --ov-line:#EDE6DF;
  --ov-line-soft:#F2ECE6;
  --ov-ink:#16110D;
  --ov-ink-2:#4C4139;
  --ov-ink-3:#6F665E;
}
/* The dialog is a flex column with a max-height; without this, every child shrinks
   to fit and the QR (height derived from aspect-ratio) collapsed to a 33px stamp
   instead of scrolling. Content keeps its size, the modal scrolls. */
.ovp-v2.ovp-pay > *{flex:0 0 auto}
.ovp-v2.ovp-pay .ov-steps{margin:0 0 8px;font-size:11px;line-height:15px;font-weight:600;letter-spacing:.09em;color:var(--ovp-ink-3)}
.ovp-v2.ovp-pay h2{margin:0 38px 6px 0;font-size:20px;line-height:27px;font-weight:600;letter-spacing:-.01em;color:var(--ovp-ink)}
.ovp-v2.ovp-pay .ov-sub{margin:0 0 14px;font-size:13px;line-height:19px;font-weight:400;color:var(--ovp-ink-3)}
/* amount: same "head number, small units" treatment as the price cards */
.ovp-v2.ovp-pay .ov-amount{
  display:flex;align-items:center;justify-content:space-between;gap:14px;
  margin:0 0 12px;padding:11px 14px;
  border:1px solid var(--ovp-line);border-radius:16px;background:var(--ovp-soft);
}
.ovp-v2.ovp-pay .ov-amount-plan{font-size:12px;line-height:17px;font-weight:400;color:var(--ovp-ink-3)}
.ovp-v2.ovp-pay .ov-amount-plan b{display:block;font-size:13px;line-height:19px;font-weight:600;color:var(--ovp-ink)}
.ovp-v2.ovp-pay .ov-amount strong{font-size:22px;line-height:26px;font-weight:600;letter-spacing:-.005em;font-variant-numeric:tabular-nums;white-space:nowrap;color:var(--ovp-ink)}
.ovp-v2.ovp-pay .ov-amount-list{display:block;margin-top:2px;font-size:11.5px;line-height:15px;font-weight:500;color:var(--ovp-ink-3);text-decoration:line-through}
.ovp-v2.ovp-pay .ov-back{margin:0 0 10px;padding:2px 0;border:0;background:none;color:var(--ovp-ink-3);font-family:var(--ov-font);font-size:12px;line-height:16px;font-weight:500;cursor:pointer}
.ovp-v2.ovp-pay .ov-back:hover{color:var(--ovp-ink)}
.ovp-v2.ovp-pay .ov-discount{margin:0 0 12px}
.ovp-v2.ovp-pay .ov-discount-label{margin:0 0 5px;font-size:11px;line-height:15px;font-weight:600;letter-spacing:.09em;color:var(--ovp-ink-3)}
.ovp-v2.ovp-pay .ov-discount-input{min-height:40px;padding:8px 13px;border:1px solid var(--ovp-line);border-radius:12px;background:#fff;font-family:var(--ov-font);font-size:13px;font-weight:500;color:var(--ovp-ink)}
.ovp-v2.ovp-pay .ov-secondary{min-height:40px;border:1px solid var(--ovp-line);border-radius:999px;background:#fff;color:var(--ovp-ink);font-size:12.5px;font-weight:600}
.ovp-v2.ovp-pay .ov-secondary:hover{background:var(--ovp-soft)}
.ovp-v2.ovp-pay .ov-discount-on{font-size:12.5px;font-weight:600;color:#1F7A45}
.ovp-v2.ovp-pay .ov-discount-msg{margin:7px 0 0;font-size:11.5px;line-height:16px}
.ovp-v2.ovp-pay .ov-qr{width:min(196px,62%);margin:2px auto 10px;padding:8px;border:1px solid var(--ovp-line);border-radius:18px;background:#fff;box-shadow:0 1px 2px rgba(22,17,13,.04)}
.ovp-v2.ovp-pay .ov-qr img{border-radius:11px}
.ovp-v2.ovp-pay .ov-qr-dl{margin:0 auto 12px;min-height:34px;padding:0 14px;border:1px solid var(--ovp-line);border-radius:999px;background:#fff;color:var(--ovp-ink-2);font-family:var(--ov-font);font-size:12px;font-weight:600;cursor:pointer}
.ovp-v2.ovp-pay .ov-qr-dl:hover{background:var(--ovp-soft);border-color:#D9CFC6}
.ovp-v2.ovp-pay .ov-rows{margin:0 0 12px;padding-top:2px;border-top:1px solid var(--ovp-line)}
.ovp-v2.ovp-pay .ov-row{padding:9px 0;border-bottom:1px solid var(--ovp-line-soft);font-size:12px;line-height:17px}
.ovp-v2.ovp-pay .ov-row span{color:var(--ovp-ink-3);font-weight:400}
.ovp-v2.ovp-pay .ov-row b{color:var(--ovp-ink);font-size:12.5px;font-weight:600;font-variant-numeric:tabular-nums}
.ovp-v2.ovp-pay .ov-copy{width:26px;height:26px;margin-left:5px;border-radius:8px;color:var(--ovp-ink-3)}
.ovp-v2.ovp-pay .ov-copy:hover{background:var(--ovp-soft);color:var(--ovp-accent-ink)}
.ovp-v2.ovp-pay .ov-countdown{align-self:flex-start;margin:0 0 8px;padding:5px 10px;border:1px solid #F6DCCB;border-radius:999px;background:#FDF1EA;color:#B4501B;font-size:12px;font-weight:600;font-variant-numeric:tabular-nums}
.ovp-v2.ovp-pay .ov-countdown::before{background:var(--ovp-accent)}
.ovp-v2.ovp-pay .ov-status{margin:0 0 12px;font-size:12px;line-height:17px;font-weight:400;color:var(--ovp-ink-3)}
/* The waiting line and the confirm button travel together as one sticky footer. The
   QR and the bank rows are taller than a phone screen, so the button has to be
   reachable without scrolling; putting the status INSIDE the bar is what stops the
   bar from covering the sentence that explains what to do next. The support links and
   the disclaimer stay after it in flow, so they are visible at the end of the scroll. */
.ovp-v2.ovp-pay .ov-pay-foot{
  position:sticky;bottom:0;z-index:2;margin-top:10px;padding:8px 0 2px;
  /* Opaque on purpose: the waiting line lives INSIDE the bar, so a translucent
     wash made the bar's own text collide with the bank rows scrolling behind it. */
  background:#fff;
  box-shadow:0 -1px 0 var(--ovp-line), 0 -12px 18px -14px rgba(22,17,13,.35);
}
.ovp-v2.ovp-pay .ov-actions.is-sticky{position:static;padding-top:0;background:transparent}
.ovp-v2.ovp-pay .ov-pay-foot .ov-status{margin:0 0 8px}
.ovp-v2.ovp-pay .ov-quiet{min-height:36px;border:0;background:none;color:var(--ovp-ink-3);font-family:var(--ov-font);font-size:12.5px;font-weight:500;cursor:pointer}
.ovp-v2.ovp-pay .ov-quiet:hover{color:var(--ovp-ink)}
.ovp-v2.ovp-pay .ov-support,.ovp-v2.ovp-pay .ov-fine{margin:8px 0 0;font-size:11.5px;line-height:16px;color:var(--ovp-ink-3)}
.ovp-v2.ovp-pay .ov-link{border:0;background:none;color:var(--ovp-ink-2);font-family:var(--ov-font);font-size:11.5px;font-weight:600;cursor:pointer;text-decoration:underline;text-underline-offset:2px}
.ovp-v2.ovp-pay .ov-done-tick{width:46px;height:46px;margin:0 0 12px;border-radius:999px;background:#FDF1EA;color:var(--ovp-accent-ink);font-size:20px;font-weight:700}
.ovp-v2.ovp-pay .ov-progress{height:4px;background:var(--ovp-line);border-radius:999px}
.ovp-v2.ovp-pay .ov-progress span{background:var(--ovp-accent)}
/* post-download sheet */
.ovp-v2.ovp-pay .ovp-sheet-title{margin:0 38px 6px 0;font-size:20px;line-height:27px;font-weight:600;letter-spacing:-.01em}
.ovp-v2.ovp-pay .ovp-sheet-body{margin:0 0 16px;font-size:13px;line-height:19px;color:var(--ovp-ink-3)}
.ovp-v2.ovp-pay .ovp-sheet-plan{
  display:grid;gap:2px;margin:0 0 16px;padding:14px 16px;
  border:1px solid var(--ovp-line);border-radius:18px;background:var(--ovp-soft);
}
.ovp-v2.ovp-pay .ovp-sheet-name{font-size:12px;line-height:17px;font-weight:500;color:var(--ovp-ink-3)}
.ovp-v2.ovp-pay .ovp-sheet-price{display:flex;align-items:baseline;gap:1px;color:var(--ovp-ink);white-space:nowrap}
.ovp-v2.ovp-pay .ovp-sheet-meta{font-size:12px;line-height:17px;color:var(--ovp-ink-3)}
@media(max-width:680px){
  .ovp-v2.ovp-pay{max-width:100%;padding:18px 16px calc(14px + env(safe-area-inset-bottom,0px));border-radius:22px 22px 0 0;max-height:94dvh}
  .ovp-v2.ovp-pay .ov-amount strong{font-size:20px;line-height:24px}
  .ovp-v2.ovp-pay .ov-qr{width:min(160px,54%)}
  .ovp-v2.ovp-pay .ov-actions.is-sticky{flex-direction:column-reverse}
  /* Phone order: what the customer must SEE to pay comes first — plan/amount, the
     QR, the transfer details, then the sticky confirm bar. The discount field and
     the "change plan" link move below it: they are secondary on a 640px screen and
     were pushing the QR under the bar. */
  .ovp-v2.ovp-pay .ov-steps{order:1}
  .ovp-v2.ovp-pay h2{order:2}
  .ovp-v2.ovp-pay .ov-sub{order:3}
  .ovp-v2.ovp-pay .ov-amount{order:4}
  .ovp-v2.ovp-pay .ov-qr{order:5;margin-top:2px}
  .ovp-v2.ovp-pay .ov-qr-dl{order:6}
  .ovp-v2.ovp-pay .ov-rows{order:7;margin-bottom:6px}
  .ovp-v2.ovp-pay .ov-countdown{order:8;margin:0 0 4px}
  .ovp-v2.ovp-pay .ov-pay-foot{order:9;margin-top:4px}
  .ovp-v2.ovp-pay .ov-discount{order:10;margin-top:6px}
  .ovp-v2.ovp-pay .ov-back{order:11}
  .ovp-v2.ovp-pay .ov-support{order:12}
  .ovp-v2.ovp-pay .ov-fine{order:13}
}

@media(max-width:919px){
  /* phone: the hero is decorative and goes away; the panel becomes the sheet */
  .ov-plan-quota-modal.ovp-v2{max-width:100%;max-height:94dvh;border-radius:22px 22px 0 0;overflow-y:auto;overscroll-behavior:contain}
  .ovp-promo{padding:8px 14px 22px;border-radius:22px 22px 0 0;font-size:12px;line-height:16px}
  .ovp-body{margin-top:-14px;height:auto;flex:0 0 auto;flex-direction:column;padding:6px;border-radius:22px 22px 0 0}
  .ovp-hero{display:none}
  /* The desktop rhythm is deliberately loose; on a phone the same looseness pushes
     the CTA under the fold, so the sheet keeps its own (still calm) scale. */
  .ovp-offer{flex:0 0 auto;padding:8px 8px 2px;gap:9px}
  .ovp-v2 .ovp-offer .ovp-mobile-reason{display:block}
  .ovp-tab{height:34px;font-size:13px}
  .ovp-credits h4{font-size:17px;line-height:24px}
  .ovp-feat{line-height:20px;gap:8px}
  .ovp-feat svg{height:20px}
  /* Phones show the whole promise: seven short lines beat a 4-line scroll box
     that cuts a bullet mid-word. The sheet itself scrolls if the screen is tiny. */
  .ovp-features{max-height:none;overflow:visible;gap:6px}
  .ovp-prices{grid-template-columns:1fr;gap:6px}
  .ovp-refund{text-align:left;padding:0}
  .ovp-v2 .ov-plan-quota-close.ovp-close{width:44px;height:44px;font-size:24px}
  .ovp-v2 .ov-actions.is-sticky{padding-top:4px;padding-bottom:calc(2px + env(safe-area-inset-bottom,0px));background:#fff}
  .ovp-v2 .ov-primary{min-height:50px;font-size:15px}
}
@media(max-width:400px){
  /* 360x640 is the tightest phone we support: one notch tighter so the whole
     promise plus the CTA fit without an inner scroll. */
  .ovp-offer{gap:8px}
  /* 360x640: the reason replaces the two card captions so the CTA stays in view */
  .ovp-refund{display:none}
  .ovp-tab{padding:0 9px;font-size:12.5px}
  .ovp-credits h4{font-size:17px;line-height:24px}
  .ovp-price{padding:10px}
}
@media (prefers-reduced-motion:reduce){
  .ovp-tab,.ovp-price{transition:none}
}

/* v2 offer dialog — small structural fixes */
.ovp-v2 .ovp-offer{border-radius:0;overflow:hidden}
.ovp-feat>span{min-width:0;flex:1 1 auto}
.ovp-v2 [data-ovp-title]{outline:none}
.ovp-v2 #ovQuotaTitle:focus{outline:none}
/* no promo strip (nothing to sell, no reset date): the card keeps the rounded top */
.ovp-v2.ovp-flat .ovp-body{margin-top:0;border-radius:32px}
.ovp-v2.ovp-flat .ovp-promo{display:none}
.ovp-features.is-scroll{
  -webkit-mask-image:linear-gradient(180deg,#000 calc(100% - 20px),transparent 100%);
          mask-image:linear-gradient(180deg,#000 calc(100% - 20px),transparent 100%);
}
.ovp-features::-webkit-scrollbar{width:6px}
.ovp-features::-webkit-scrollbar-thumb{background:#E3D9CF;border-radius:999px}
.ovp-features::-webkit-scrollbar-track{background:transparent}
.ovp-v2 .ovp-credits h4:focus{outline:none}

/* ---------------------------------------------------------------------------
   Offer dialog — review variants (A/B/C) and the shared quiet actions.
   A = reference layout with fewer rows, B = one plan + cycle pills,
   C = number-led with price rows. Same skeleton, less copy in each.
   ------------------------------------------------------------------------- */
/* the free split path reads as a quiet link but keeps a 40px tap target */
.ovp-v2 .ov-free{
  width:auto;min-height:40px;padding:0 7px;border:0;border-radius:8px;background:none;
  color:#8A5A3C;font-family:var(--ov-font);font-size:12px;line-height:16px;font-weight:600;
  display:inline-flex;align-items:center;gap:5px;
}
.ovp-v2 .ov-free:hover{background:none;border:0;color:var(--ovp-accent-ink);text-decoration:underline}
.ovp-mini{margin:0;color:var(--ovp-ink-3);font-size:11.5px;line-height:16px;font-weight:500}
.ovp-mobile-reason{display:none;margin:0 0 2px;color:var(--ovp-ink);font-size:14px;line-height:19px;font-weight:600;letter-spacing:-.01em}
.ovp-mini-center{text-align:center}
@media(max-width:919px){
}
