/*
 | Signup overlay stylesheet — extracted 2026-08-27.
 |
 | ⚠ THESE RULES WERE THREE INLINE <style> BLOCKS. They lived in
 | paper-gate-overlay.blade.php, -signup and -checkout, and were therefore
 | re-sent on every render and unusable by any page that is not the study-guide
 | overlay. Extracting them is what lets /signup, /user/login and
 | /signup/checkout share one stylesheet with the popup instead of each inlining
 | ~20 KB of a copy that would then drift.
 |
 | ⚠ ORDER IS THE ORIGINAL DOM ORDER, NOT SOURCE ORDER. signup's block was
 | emitted first (its partial is @included at paper-gate-overlay:59, above the
 | shell's own <style> at :68) and the checkout fragment arrives last, by fetch.
 | Measured before extracting: the three blocks share ZERO rule selectors — the
 | only common entries are two @media wrappers with disjoint bodies — so the
 | cascade cannot change. The order is preserved anyway, because "cannot change"
 | is a claim about today's rules and the order costs nothing to keep.
 |
 | ⚠ THE CHECKOUT BLOCK IS FOR A FETCHED FRAGMENT. SignupController:658 renders
 | partials/paper-gate-overlay-checkout as the overlay's step-2 body, injected by
 | fetch. Its CSS used to travel with the fragment; it now has to be on the page
 | already. That is safe because the fragment is overlay-only — it stashes
 | RENDERED_CHECKOUT_VARIANT='overlay' and is served nowhere else — so the shell
 | that links this file is always present before the fragment can arrive.
 |
 | ⚠ CLASS NAMES ARE UNCHANGED (pd-ovl-*, pd-su-*, pd-co-*). They were NOT
 | renamed to the design's .rail/.panel/.site-head/.site-foot/.modal. See the
 | build report: the design's 81 classes and our 89 share ZERO names, and the
 | design's rail is a different DOM from ours, so that is a rebuild of a live
 | converting flow rather than a rename — and it cannot satisfy "the overlay must
 | render identically". Decide it separately.
 */

/* ══════════ STEP 1 — signup panel  (was inline in paper-gate-overlay-signup) ══════════ */
/* #130 BUILD 3E Part C — social buttons.

   ⚠ THE PROVIDER FILLS BELOW ARE SCOPED LITERALS AND ARE **NOT** TOKENS.
   Google's white field and Meta's blue are mandated by those companies' brand
   guidelines. They describe Google and Meta, not PaperDue, so they must never
   be promoted into the --brand-* / --pd-ovl-* layer or reused for anything
   else. --brand-orange was misused in exactly that way; this heads it off.
   Apple's field is the one exception and is NOT a literal: Apple mandates
   black or white rather than a specific hex, so it reuses the overlay's
   existing ink token instead of inventing #111827.

   ⚠ META BLUE IS #0d6be6 HERE, NOT THE BRAND #1877F2, AND THAT IS DELIBERATE.
   White on #1877F2 measures 4.23:1 and fails AA at body size. #0d6be6 is the
   same hue and saturation darkened until white clears 4.5 — measured 4.93:1,
   the same headroom the #b85212 CTA below settled on. Hue moves 213.9deg ->
   214.0deg and saturation 89.3% -> 89.0%, so it still reads as Meta blue, but
   it is not the mandated hex. The alternative was an 18.66px bold label to
   qualify as large text at 3:1, which would have made these buttons louder
   than the primary CTA. */
.pd-ovl-social { display: flex; flex-direction: column; gap: 9px; margin: 0 0 4px; }

/* One shell for all three, so the stack is equal-height on a single radius.
   EVERY button carries a 1px border — the dark two set it to their own fill —
   because a border on Google alone would make that button 2px taller. */
.pd-ovl-soc { position: relative; display: flex; align-items: center; justify-content: center; gap: 10px; box-sizing: border-box; width: 100%; min-height: 46px; padding: 12px 16px; font-family: inherit; font-size: 14.5px; font-weight: 700; border: 1px solid transparent; border-radius: var(--pd-ovl-r); cursor: pointer; text-decoration: none; transition: border-color .14s, background .14s; }
/* ⚠ MARK AND LABEL ARE ONE CENTRED UNIT, MATCHING signup/form:91. This
   REPLACES a previous deliberate choice, so the reasoning it displaces is kept
   rather than deleted: the mark used to be absolutely pinned at left:14px with
   44px of symmetric padding, which centred the LABEL in the button and stopped
   it running under the mark. That reads correctly on its own but does not match
   /signup, where icon and text travel together — and the two surfaces offering
   the same three providers in two different alignments is the thing being
   fixed. The 44px reservation goes with it; a centred flex unit cannot collide
   with its own icon, so the padding drops to /signup's 16px.

   Equal-height across the stack is unaffected — that comes from the 1px border
   every button carries plus min-height, both untouched. */
.pd-ovl-soc svg { width: 18px; height: 18px; flex: none; }
/* ⚠ OUT-SPECIFIES `.pd-ovl a { text-decoration: underline }` FROM BUILD 3A,
   deliberately. That rule fixes link-in-text-block for "Sign in", which sits
   INSIDE a sentence and needs a non-colour cue. These are standalone bordered
   buttons with no surrounding prose, so the rule does not apply to them and the
   underline just makes a button look like a link. axe reports zero violations
   either way; verified with the overlay open on a real page. */
.pd-ovl a.pd-ovl-soc, .pd-ovl a.pd-ovl-soc:hover { text-decoration: none; }

/* Google — white field, grey boundary, dark label, multicolour G.
   This border IS the button's only boundary (a white field on a white dialog),
   so 1.4.11's 3:1 applies to it. It uses the shared --pd-ovl-border-2, which
   is now #858fa3 (3.25:1). When Part C shipped, that token was #c3cddb and
   measured 1.61:1 despite a comment claiming 3.0:1, so this rule carried the
   value as a scoped literal instead; the token was corrected immediately
   after and the literal is no longer needed. */
.pd-ovl-soc-google { color: var(--pd-ovl-ink); background: #fff; border-color: var(--pd-ovl-border-2); }
.pd-ovl-soc-google:hover { background: var(--pd-ovl-bg-soft); border-color: #7d8798; color: var(--pd-ovl-ink); }

/* Apple — near-black field, white label and mark, on the existing ink token. */
.pd-ovl-soc-apple { color: #fff; background: var(--pd-ovl-ink); border-color: var(--pd-ovl-ink); }
.pd-ovl-soc-apple:hover { background: #1e293b; border-color: #1e293b; color: #fff; }

/* Meta — white label and white f on the darkened blue. See the hex note above. */
.pd-ovl-soc-facebook { color: #fff; background: #0d6be6; border-color: #0d6be6; }
.pd-ovl-soc-facebook:hover { background: #0b5cc9; border-color: #0b5cc9; color: #fff; }

/* Focus. The dark two take an inset WHITE ring in addition to the outer dark
   one: the outer ring lands on the dialog's white ground, and against a
   near-black or blue field it is not itself a cue. White measures 17.85:1 on
   Apple's field and 4.93:1 on Meta's, both clearing the 3:1 that 1.4.11 asks
   of a focus indicator against the control it marks. */
.pd-ovl-soc:focus-visible { outline: 3px solid var(--pd-ovl-ink); outline-offset: 2px; }
.pd-ovl-soc-apple:focus-visible, .pd-ovl-soc-facebook:focus-visible { box-shadow: inset 0 0 0 2px #fff; }
.pd-ovl-soc-busy { opacity: .6; pointer-events: none; }
.pd-ovl-or { display: flex; align-items: center; gap: 12px; margin: 16px 0 14px; font-family: var(--pd-ovl-mono); font-size: 9.5px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase; color: var(--pd-ovl-muted); }
.pd-ovl-or::before, .pd-ovl-or::after { content: ""; flex: 1; height: 1px; background: var(--pd-ovl-border); }
@media (prefers-reduced-motion: reduce) { .pd-ovl-soc { transition: none; } }
.pd-ovl-sub { margin: 0 0 14px; font-size: 14px; color: #5b667d; line-height: 1.5; }
.pd-ovl-banner { margin: 0 0 12px; padding: 10px 12px; border-radius: 8px; background: #fdecea; color: #8c1d18; font-size: 13.5px; line-height: 1.5; }
.pd-ovl-field { margin: 0 0 12px; }
.pd-ovl-label { display: block; margin: 0 0 5px; font-size: 13px; font-weight: 600; color: #1a1a2e; }
.pd-ovl-input { width: 100%; box-sizing: border-box; padding: 11px 12px; font: inherit; font-size: 15px; color: #1a1a2e; background: #fff; border: 1.5px solid #d5dae3; border-radius: 8px; }
.pd-ovl-input:focus { outline: none; border-color: #2a4fa8; box-shadow: 0 0 0 3px rgba(42,79,168,.14); }
.pd-ovl-input.pd-ovl-input-bad { border-color: #c0392b; }
.pd-ovl-err { margin: 5px 0 0; font-size: 12.5px; color: #c0392b; }

/* ── PASSWORD CONTROLS — geometry ported from signup/form.blade.php:105-116 ──
   Same 28px hit area, same 4px gap, same right offset, so the two surfaces
   agree. Colours are the overlay's existing literals (#5b667d is the label /
   sub grey already used above; #b85212 is the CTA orange this file already
   carries at .pd-ovl-submit) — no token and no scale is introduced here.

   ⚠ padding-right RESERVES THE GUTTER. Without it a long password runs under
   both buttons. 76px = 2 × 28px buttons + 4px gap + 10px offset + breathing
   room, the same figure /signup uses. */
.pd-ovl-input-wrap { position: relative; }
.pd-ovl-input.pd-ovl-input-icons { padding-right: 76px; }
.pd-ovl-input-icons-wrap { position: absolute; right: 10px; top: 50%; transform: translateY(-50%); display: flex; gap: 4px; }
.pd-ovl-icon-btn { width: 28px; height: 28px; padding: 0; background: transparent; border: none; color: #5b667d; cursor: pointer; border-radius: 6px; display: flex; align-items: center; justify-content: center; transition: background .12s, color .12s; }
.pd-ovl-icon-btn:hover { background: #eef2fa; color: #1a1a2e; }
.pd-ovl-icon-btn.pd-ovl-icon-sparkle:hover { background: #fdf0e6; color: #b85212; }
.pd-ovl-icon-btn:focus-visible { outline: 2px solid #2a4fa8; outline-offset: 2px; }
.pd-ovl-icon-btn svg { width: 15px; height: 15px; }
.pd-ovl-hint { margin: 6px 0 0; font-size: 11.5px; color: #5b667d; }
@media (prefers-reduced-motion: reduce) { .pd-ovl-icon-btn { transition: none; } }
/*
  ⚠ #b85212, NOT THE BRAND #e8732a, AND THAT IS DELIBERATE.

  White text on the brand orange measures 3.04:1. WCAG AA requires 4.5:1 for
  body-size text, so the overlay's primary CTA failed — axe-core flagged
  #pd-ovl-submit-text as a SERIOUS violation the first time it was scanned with
  step 1 actually visible (Phase 3). Earlier scans missed it because the button
  was absent in 2A's empty shell and hidden behind step 2 in the 2B scan.

  #b85212 is the same hue darkened to 4.94:1. Contrast for the non-text uses of
  the brand orange (plan-card border, radio fill) is unchanged and already clears
  the 3:1 that applies to UI components.

  ⚠ THE BRAND ORANGE FAILS THE SAME WAY WHEREVER WHITE TEXT SITS ON IT — including
  checkout/v4's .btn-pay, which is out of scope here. Recorded in the handoff.
*/
.pd-ovl-submit { width: 100%; margin: 4px 0 12px; padding: 12px 16px; font: inherit; font-size: 15px; font-weight: 700; color: #fff; background: #b85212; border: 0; border-radius: 9px; cursor: pointer; }
.pd-ovl-submit:hover { background: #a4490f; }
.pd-ovl-submit:focus-visible { outline: 2px solid #2a4fa8; outline-offset: 2px; }
.pd-ovl-submit[disabled] { opacity: .6; cursor: not-allowed; }
.pd-ovl-switch { margin: 10px 0 0; font-size: 13px; color: #5b667d; }
.pd-ovl-body .signup-disclosure { margin: 0; font-size: 12px; line-height: 1.5; color: #475569; }


/* ══════════ SHELL — dialog, backdrop, rail  (was inline in paper-gate-overlay) ══════════ */
/*
  ── TOKENS ──────────────────────────────────────────────────────────────────
  From the standalone popup design's :root block, namespaced --pd-ovl-* so they
  cannot leak into or be overridden by the study-guide page's own custom
  properties. Ratios are the design's own contrast audit, carried over verbatim
  because they are the reason each value is what it is.

  ⚠ --pd-ovl-orange IS DECORATION ONLY: borders, bullet dots, gradients. White
  on #e8732a is 3.04:1 and FAILS WCAG AA. Every filled surface that carries
  white text uses --pd-ovl-orange-ink (#b85212, 4.94:1). The design states this
  outright — "brand orange #e8732a cannot carry white text anywhere" — and it is
  the same failure fixed in Phase 3 and again in BUILD 2. Do not "restore the
  brand colour" on a button.
*/
.pd-ovl {
  --pd-ovl-navy:#1a2744;            /* with white: 14.8:1 (measured) */
  --pd-ovl-ink:#0f172a;             /* on white: 17.9:1 (measured) */
  --pd-ovl-slate:#475569;           /* on white: 7.6:1 (measured) */
  --pd-ovl-muted:#5c6a7d;           /* on white: 5.5:1 (measured) — AA body */
  --pd-ovl-orange:#e8732a;          /* decoration only — see above */
  --pd-ovl-orange-ink:#b85212;      /* white on it: 4.94:1 — buttons, badges */
  --pd-ovl-orange-ink-hov:#9c4410;
  /* ⚠ UNUSED SINCE BUILD 3E removed the doc-card note strip, which was their
     only consumer. Kept because they are part of the design's token set and
     the next rail element that needs a soft-orange field or an orange link
     should reach for these rather than inventing a literal. Delete only
     alongside a decision that the rail will never carry one. */
  --pd-ovl-orange-soft:#fff2e8;
  --pd-ovl-rail:#eef2fa;
  --pd-ovl-border:#e2e8f0;
  /* ⚠ WAS #c3cddb, WHOSE COMMENT CLAIMED 3.0:1 WHILE THE VALUE MEASURED
     1.61:1 — the comment asserted a ratio the colour did not have, and every
     boundary drawn with it was failing 1.4.11 while the token said otherwise.
     #858fa3 measures 3.25:1 on white and 3.11:1 on --bg-soft, so all four
     BOUNDARY uses clear 3:1: the plan card, the radio, the Stripe frame and
     the consent checkbox — each a white control on a white or near-white
     field, where this border is the only thing identifying it.

     ⚠ THE DECORATIVE USES WERE SPLIT OFF RATHER THAN DARKENED WITH IT. The
     spinner's track and the billing separator are not boundaries and carry no
     3:1 duty; at this weight they would read as rules competing with the legal
     copy. They now point at --pd-ovl-line, which already existed for exactly
     that job, so the split cost no new token. */
  --pd-ovl-border-2:#858fa3;        /* UI boundary on white: 3.25:1 (measured) */
  --pd-ovl-line:#dde5f2;
  --pd-ovl-bg-soft:#f8fafc;
  --pd-ovl-link:#a8420c;            /* on --bg-soft: 5.8:1 (measured); currently unused */
  --pd-ovl-r:10px;
  --pd-ovl-ui:'Plus Jakarta Sans',system-ui,-apple-system,sans-serif;
  --pd-ovl-mono:'JetBrains Mono',ui-monospace,SFMono-Regular,monospace;
}

/*
  ⚠ THE DIALOG IS NOW TWO-COLUMN, AND THAT SUPERSEDES THE 580px DERIVATION —
  it does not repeal the reasoning behind it. Restating, because the constraint
  is still live and the next person to touch a width needs it.

  partials/payment-element-init.blade.php:121-122 picks the Payment Element's
  layout ONCE at mount, from the MOUNT CONTAINER's measured width:

      const containerWidth = mountEl ? mountEl.offsetWidth : window.innerWidth;
      const layoutType = containerWidth < 500 ? 'accordion' : 'tabs';

  Fixed for the life of that mount. Under 500 every desktop visitor gets the
  MOBILE ACCORDION — which is exactly what happened at the original 460px
  (460 - 44 = 416), and why the single-column dialog was widened to 580.

  The old arithmetic measured the whole dialog minus body padding, because the
  dialog WAS the panel. It no longer is: the mount container now sits inside
  .pd-ovl-panel, which is the second grid track, so the rail's fixed 340px comes
  off the top before any padding.

      dialog max-width          1040
      - rail track               340
      ------------------------------
      panel track                700
      - .pd-ovl-body padding      44   (22 each side)
      - panel scrollbar        ~= 17   (Chrome/Windows; 0 with overlay scrollbars)
      ------------------------------
      measured, worst case       639   -> 639 >= 500, tabs. 139px of margin.

  So the threshold is cleared with room to spare, and by a different route than
  before. The number that must not drop below ~901 is now the DIALOG width
  (340 + 500 + 44 + 17), not 561.

  Below 860px the grid collapses to one column (see the media query) and the
  panel spans the full dialog — on a phone that measures well under 500 and the
  accordion is correct there, unchanged from before.
*/
.pd-ovl { position: fixed; inset: 0; z-index: 9000; display: flex; align-items: center; justify-content: center; padding: 20px; font-family: var(--pd-ovl-ui); }
.pd-ovl[hidden] { display: none; }
.pd-ovl-backdrop { position: absolute; inset: 0; background: rgba(15, 23, 42, .62); }
/* ⚠ grid-template-rows IS WHAT MAKES .pd-ovl-panel SCROLL, AND WITHOUT IT THE
   CONSENT CHECKBOX IS UNREACHABLE. The row was implicit and therefore `auto`,
   so it sized to CONTENT: the panel grew to 1042px inside a 736px dialog
   (scrollHeight === clientHeight — it never became a scroll container at all),
   the overflow landed here, and `overflow: hidden` below clipped it. Measured
   at 1280x800 the consent block ended at 942px and the pay button at 1012px
   against an 800px viewport, with NO user-scrollable element anywhere in the
   dialog. A visitor could not reach the box, so could not consent and could not
   subscribe.

   minmax(0, 1fr) lets the row shrink below its content, which is the condition
   .pd-ovl-panel's existing `min-height: 0; overflow-y: auto` (:218) was always
   written for. Nothing else changes: same scroll model, same markup order, same
   counsel-approved copy.

   ⚠ RESET TO `none` IN THE ≤860px BLOCK BELOW. There the grid is ONE column and
   TWO rows (rail, then panel), and a single explicit row would pin the RAIL to
   1fr and leave the panel implicit — squashing the wrong element. Mobile
   already scrolls correctly via the dialog's own overflow-y: auto and is
   deliberately left exactly as it was. */
.pd-ovl-dialog { position: relative; width: 100%; max-width: 1040px; max-height: min(92vh, 900px); display: grid; grid-template-columns: 340px minmax(0, 1fr); grid-template-rows: minmax(0, 1fr); background: #fff; border-radius: 14px; box-shadow: 0 40px 80px -24px rgba(15, 23, 42, .5); overflow: hidden; color: var(--pd-ovl-ink); }
.pd-ovl-dialog:focus { outline: none; }

.pd-ovl-close { position: absolute; top: 14px; right: 14px; z-index: 5; width: 34px; height: 34px; border: none; border-radius: 50%; background: rgba(15, 23, 42, .07); color: var(--pd-ovl-slate); display: flex; align-items: center; justify-content: center; cursor: pointer; }
.pd-ovl-close:hover { background: rgba(15, 23, 42, .15); color: var(--pd-ovl-ink); }
.pd-ovl-close:focus-visible { outline: 3px solid var(--pd-ovl-ink); outline-offset: 2px; }
.pd-ovl-close svg { width: 14px; height: 14px; }

/* ── rail ── */
.pd-ovl-rail { background: var(--pd-ovl-rail); border-right: 1px solid var(--pd-ovl-border); padding: 24px; display: flex; flex-direction: column; overflow-y: auto; min-height: 0; }
.pd-ovl-back { display: flex; align-items: center; gap: 7px; background: none; border: none; padding: 0; margin-bottom: 14px; font-family: inherit; font-size: 12.5px; font-weight: 700; color: var(--pd-ovl-slate); cursor: pointer; }
.pd-ovl-back:hover:not(:disabled) { color: var(--pd-ovl-ink); }
.pd-ovl-back:disabled { opacity: .45; cursor: default; }
/* ⚠ display:flex above BEATS the UA [hidden]{display:none}, so without this the
   inert Back button renders anyway — it did, and the 1200px screenshot caught
   it. A visible control that does nothing is worse than no control. */
.pd-ovl-back[hidden] { display: none; }
.pd-ovl-back svg { width: 13px; height: 13px; }

.pd-ovl-doc { flex-shrink: 0; border: 1px solid var(--pd-ovl-border); border-radius: 14px; background: #fff; overflow: hidden; box-shadow: 0 2px 10px rgba(15, 23, 42, .05); margin-bottom: 20px; }
.pd-ovl-doc-head { padding: 10px 15px; border-bottom: 1px solid var(--pd-ovl-border); background: var(--pd-ovl-bg-soft); font-size: 9.5px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase; color: var(--pd-ovl-muted); }
.pd-ovl-doc-body { padding: 15px; display: flex; gap: 13px; }
.pd-ovl-doc-body svg { flex: none; width: 40px; height: 52px; }
.pd-ovl-doc-title { font-size: 13.5px; font-weight: 700; line-height: 1.35; margin-bottom: 5px; text-wrap: pretty; }
.pd-ovl-doc-meta { font-size: 10px; color: var(--pd-ovl-muted); }

.pd-ovl-incl { font-size: 17px; font-weight: 800; letter-spacing: -.5px; margin: 0 0 10px; }
.pd-ovl-grp { flex-shrink: 0; border-top: 1px solid var(--pd-ovl-line); padding: 10px 0; }
.pd-ovl-grp-name { display: flex; align-items: center; gap: 9px; font-size: 14px; font-weight: 700; color: var(--pd-ovl-navy); }
.pd-ovl-ico { width: 22px; height: 22px; flex: none; border-radius: 6px; background: var(--pd-ovl-navy); color: #fff; display: flex; align-items: center; justify-content: center; }
.pd-ovl-ico svg { width: 12px; height: 12px; }
.pd-ovl-grp ul { list-style: none; display: flex; flex-direction: column; gap: 4px; margin: 6px 0 1px 31px; padding: 0; }
.pd-ovl-grp li { display: flex; gap: 9px; font-size: 12.5px; color: var(--pd-ovl-slate); line-height: 1.5; }
.pd-ovl-grp li::before { content: ""; flex: none; width: 5px; height: 5px; border-radius: 50%; background: var(--pd-ovl-orange); margin-top: 6px; }
.pd-ovl-mono { font-family: var(--pd-ovl-mono); }

/*
  ⚠ LINKS INSIDE THE OVERLAY MUST BE UNDERLINED, and this is a real fix rather
  than a style preference. The site's global anchor rule sets
  text-decoration:none, so "Already have an account? Sign in" rendered as
  #b45113 text inside #5b667d text — 1.13:1 against its surroundings, where
  WCAG needs 3:1 OR a non-colour distinguisher. axe reports it as
  link-in-text-block, serious.

  ⚠ IT WAS INVISIBLE TO EVERY EARLIER SCAN. Those ran against a fixture built
  with setContent, where the site stylesheet never loads, so the anchor kept the
  browser default — blue AND underlined — and passed. It only appears when the
  overlay is opened on a real study guide. Same blind spot that hid the cookie
  dialogue in Phase 3: fixtures cannot see what the page does to you.

  The design's own :root block says a{text-decoration:underline}; this is that.
*/
.pd-ovl a { text-decoration: underline; }
.pd-ovl a:hover { text-decoration: underline; }
.pd-ovl button { text-decoration: none; }

/* ── panel ── */
.pd-ovl-panel { min-height: 0; overflow-y: auto; display: flex; flex-direction: column; }
.pd-ovl-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; padding: 30px 32px 0; }
.pd-ovl-title { margin: 0; font-size: 26px; font-weight: 800; letter-spacing: -.8px; color: var(--pd-ovl-ink); }
.pd-ovl-body { padding: 16px 32px 30px; }

/* ── rail collapses below 860px, per the design's sole media query ── */
@media (max-width: 860px) {
  .pd-ovl { padding: 0; align-items: flex-end; }
  .pd-ovl-dialog { max-width: none; border-radius: 14px 14px 0 0; max-height: 92vh; grid-template-columns: 1fr; grid-template-rows: none; overflow-y: auto; }
  .pd-ovl-rail { border-right: none; border-bottom: 1px solid var(--pd-ovl-border); padding: 20px; overflow: visible; }
  /* keep the doc card, drop the long feature list */
  .pd-ovl-rail .pd-ovl-grp, .pd-ovl-rail .pd-ovl-incl { display: none; }
  .pd-ovl-doc { margin-bottom: 0; }
  .pd-ovl-panel { overflow: visible; }
  .pd-ovl-head { padding: 24px 20px 0; }
  .pd-ovl-title { font-size: 21px; }
  .pd-ovl-body { padding: 14px 20px 24px; }
}
@media (prefers-reduced-motion: no-preference) {
  .pd-ovl-dialog { animation: pd-ovl-in .16s ease-out; }
  @keyframes pd-ovl-in { from { transform: translateY(8px); opacity: .6; } to { transform: none; opacity: 1; } }
}


/* ══════════ STEP 2 — plans/payment fragment (was inline in paper-gate-overlay-checkout) ══════════ */
/*
  Panel styles — design lines 484-613, mapped onto BUILD 3A's --pd-ovl-* tokens.
  ⚠ Every filled surface here uses --pd-ovl-orange-ink (#b85212, white on it
  4.94:1). --pd-ovl-orange appears ONLY as a translucent border or divider tint,
  which is what the design's own audit permits: "brand orange is borders, dots
  and gradients only".
*/
.pd-ovl-sec { display: flex; align-items: center; gap: 10px; font-size: 11.5px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase; color: var(--pd-ovl-slate); margin: 0 0 14px; }
.pd-ovl-sec::after { content: ""; flex: 1; height: 1px; background: var(--pd-ovl-border); }
.pd-ovl-step { color: var(--pd-ovl-orange-ink); }

.pd-ovl-plans { display: flex; flex-direction: column; gap: 10px; }
.pd-ovl-plan { position: relative; display: flex; align-items: center; gap: 14px; border: 1.5px solid var(--pd-ovl-border-2); border-radius: var(--pd-ovl-r); padding: 16px 18px; background: #fff; color: var(--pd-ovl-ink); cursor: pointer; text-align: left; width: 100%; font-family: inherit; transition: border-color .14s, box-shadow .14s, background .14s; }
/* Darker than the resting --pd-ovl-border-2 (#858fa3, 3.25:1), not lighter.
   #9fb0c6 measured 2.21:1 and was fine against the old #c3cddb; once the
   token was raised it would have made hover the WEAKER state. #7d8798 is
   3.63:1 on white. */
.pd-ovl-plan:hover { border-color: #7d8798; }
.pd-ovl-plan:focus-visible { outline: 3px solid rgba(184,82,18,.45); outline-offset: 2px; }
.pd-ovl-plan-featured { border-color: rgba(232,115,42,.55); background: linear-gradient(180deg,#fff7f1 0,#fff 66%); }
.pd-ovl-plan-badged { padding-top: 26px; }
.pd-ovl-plan-on { border: 2px solid var(--pd-ovl-orange-ink); background: #fffdfb; padding: 15px 17px; }
.pd-ovl-plan-on.pd-ovl-plan-badged { padding-top: 25px; }
.pd-ovl-plan-featured.pd-ovl-plan-on { box-shadow: 0 5px 20px rgba(184,82,18,.16); }
.pd-ovl-radio { flex: none; width: 20px; height: 20px; border-radius: 50%; border: 2px solid var(--pd-ovl-border-2); display: flex; align-items: center; justify-content: center; transition: border-color .13s; }
.pd-ovl-plan-on .pd-ovl-radio { border-color: var(--pd-ovl-orange-ink); }
.pd-ovl-radio i { width: 10px; height: 10px; border-radius: 50%; background: transparent; display: block; }
.pd-ovl-plan-on .pd-ovl-radio i { background: var(--pd-ovl-orange-ink); }
.pd-ovl-plan-id { display: flex; align-items: center; gap: 13px; width: 168px; flex-shrink: 0; }
.pd-ovl-plan-name { font-size: 16px; font-weight: 700; letter-spacing: -.2px; }
.pd-ovl-plan-featured .pd-ovl-plan-name { font-size: 17px; }
.pd-ovl-plan-div { width: 1px; align-self: stretch; margin-right: 20px; background: var(--pd-ovl-border); }
.pd-ovl-plan-on .pd-ovl-plan-div, .pd-ovl-plan-featured .pd-ovl-plan-div { background: rgba(232,115,42,.3); }
.pd-ovl-plan-main { flex: 1; min-width: 0; }
.pd-ovl-plan-price { display: flex; align-items: baseline; gap: 6px; flex-wrap: wrap; }
.pd-ovl-plan-price b { font-size: 22px; font-weight: 800; letter-spacing: -.8px; line-height: 1.05; }
.pd-ovl-plan-featured .pd-ovl-plan-price b { font-size: 27px; }
.pd-ovl-plan-price span { font-size: 13.5px; font-weight: 600; color: var(--pd-ovl-muted); }
.pd-ovl-plan-note { display: block; font-size: 12.5px; color: var(--pd-ovl-muted); margin-top: 5px; }
.pd-ovl-badge { position: absolute; top: 0; right: 0; border-radius: 0 8px 0 10px; padding: 6px 13px; font-size: 10px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; white-space: nowrap; color: #fff; background: #0f7a3d; }
.pd-ovl-badge-orange { background: var(--pd-ovl-orange-ink); }

.pd-ovl-assure { display: flex; align-items: center; justify-content: center; gap: 20px; flex-wrap: wrap; background: var(--pd-ovl-bg-soft); border: 1px solid var(--pd-ovl-border); border-radius: var(--pd-ovl-r); padding: 12px; margin-top: 12px; margin-bottom: 22px; font-size: 13px; color: var(--pd-ovl-slate); }
.pd-ovl-assure span { display: inline-flex; align-items: center; gap: 7px; }
.pd-ovl-assure svg { width: 14px; height: 14px; flex: none; }

/* Both error states share the design's one pattern. */
/* ⚠ SCOPED BY ID, NOT BY .pd-ovl-err. That class is also step 1's inline field
   error (paper-gate-overlay-signup:70), and `.pd-ovl-err:not(:empty)` would
   out-specify its plain rule and wrap every "Enter a valid email" in a full
   error box. Only the payment error gets the box. */
.pd-ovl-err-box, #pd-ovl-payment-err:not(:empty) { display: flex; gap: 9px; align-items: flex-start; margin-top: 12px; padding: 11px 13px; border: 1px solid #f0c7c3; border-left: 3px solid #b3261e; border-radius: 8px; background: #fdf2f1; color: #b3261e; font-size: 13px; line-height: 1.5; }
.pd-ovl-err-box[hidden] { display: none; }
#pd-ovl-payment-err:empty { display: none; }
.pd-ovl-err-box svg { flex: none; width: 15px; height: 15px; margin-top: 1px; }
.pd-ovl-plans.pd-ovl-is-error .pd-ovl-plan { border-color: #e3b4af; }

/* ── RAIL PICKER (ported from checkout/v4:122-124, retokenised) ──────────── */
/* v4's rule is scoped #pd-v4 .pmt-tab; this is a different surface with its own
   token layer, so the shape is copied and the colours come from --pd-ovl-*.
   Nothing here is shared with v4 — no selector in either file can match the
   other's markup. */
.pd-ovl-rails { display: flex; gap: 8px; margin-bottom: 14px; }
.pd-ovl-rail-tab { flex: 1; display: flex; align-items: center; justify-content: center; gap: 7px; padding: 11px; border: 2px solid var(--pd-ovl-border); border-radius: var(--pd-ovl-r); background: #fff; font: inherit; font-size: 13.5px; font-weight: 700; color: var(--pd-ovl-slate); cursor: pointer; }
.pd-ovl-rail-tab:hover:not(:disabled) { border-color: var(--pd-ovl-border-2); }
.pd-ovl-rail-tab-on { border-color: var(--pd-ovl-orange-ink); background: #fffdfb; color: var(--pd-ovl-ink); }
.pd-ovl-rail-tab:focus-visible { outline: 3px solid rgba(184,82,18,.45); outline-offset: 2px; }
/* Disabled only for the brief window before the Stripe Element has mounted. */
.pd-ovl-rail-tab:disabled { opacity: .55; cursor: default; }
/* Sized in em against the tab's own label, so the mark tracks the type if the
   font-size ever moves. 1.35em ≈ 18px here — large enough that the two tones
   stay separable at the 390px viewport, where 1.15em muddied them. Vertical
   centring comes from the tab's existing align-items:center; the 7px gap is the
   tab's own and is unchanged. */
.pd-ovl-rail-mark { width: 1.35em; height: 1.35em; flex: none; }

.pd-ovl-paypal-note { display: flex; align-items: flex-start; gap: 9px; padding: 14px 15px; border: 1.5px solid var(--pd-ovl-border); border-radius: var(--pd-ovl-r); background: var(--pd-ovl-bg-soft); font-size: 13px; line-height: 1.55; color: var(--pd-ovl-slate); }
.pd-ovl-paypal-note svg { flex: none; width: 15px; height: 15px; margin-top: 2px; }

/* ⚠ DIMMED, NOT CLICK-BLOCKED. pointer-events:none over PayPal's iframe would
   swallow the click and give the visitor NO feedback at all. The real gate is
   createSubscription throwing on !overlayConsentOk (paper-gate-overlay-payment),
   which also writes the reason into #pd-ovl-paypal-error. This only makes the
   locked state legible. */
.pd-ovl-paypal-container { transition: opacity .13s; }
.pd-ovl-paypal-locked .pd-ovl-paypal-container { opacity: .5; }

/* ── OUR frame; Stripe's element inside (design :558, :579-590) ── */
/* min-width documents Stripe's 500px tab threshold without ever overflowing a
   narrower panel — under 500px Stripe self-switches to the accordion. */
.pd-ovl-frame { position: relative; border: 1.5px solid var(--pd-ovl-border-2); border-radius: 12px; background: #fff; padding: 16px; min-width: min(500px, 100%); }
.pd-ovl-is-loading { min-height: 250px; }
.pd-ovl-payment-element { min-height: 40px; }

/*
  ⚠ THE SKELETON COVERS THE ELEMENT — IT MUST NEVER REPLACE IT.
  The first version of this used `.pd-ovl-is-loading .pd-ovl-payment-element
  { display: none }`, and the mount container then measured 0px. That is not
  cosmetic: payment-element-init:121-122 reads mountEl.offsetWidth ONCE, at
  mount, and picks `containerWidth < 500 ? 'accordion' : 'tabs'` from it, fixed
  for the life of the mount. A hidden container measures 0, takes the < 500
  branch, and PINS THE MOBILE ACCORDION ON EVERY DESKTOP — the exact defect
  paper-gate-overlay.blade.php:66-92 exists to prevent, reintroduced by a
  loading state.
  So the element stays in normal flow at full width and the skeleton is painted
  over it. Caught by the test asserting the measured width, not by looking.
*/
.pd-ovl-sk-wrap { display: none; position: absolute; inset: 16px; background: #fff; z-index: 1; }
.pd-ovl-is-loading .pd-ovl-sk-wrap { display: block; }
.pd-ovl-sk { border-radius: 8px; background: linear-gradient(90deg,#eef1f6 25%,#f7f9fc 37%,#eef1f6 63%); background-size: 400% 100%; animation: pd-ovl-sh 1.4s ease infinite; }
@keyframes pd-ovl-sh { 0% { background-position: 100% 0; } 100% { background-position: -100% 0; } }
.pd-ovl-sk-tabs { display: grid; grid-template-columns: repeat(3,1fr); gap: 10px; margin-bottom: 16px; }
.pd-ovl-sk-tab { height: 62px; }
.pd-ovl-sk-line { height: 44px; margin-bottom: 12px; }
.pd-ovl-sk-half { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.pd-ovl-sk-half .pd-ovl-sk-line { margin-bottom: 0; }
.pd-ovl-sk-cap { display: flex; align-items: center; gap: 9px; margin-top: 12px; font-size: 12.5px; color: var(--pd-ovl-muted); }
.pd-ovl-spin { width: 14px; height: 14px; flex: none; border: 2px solid var(--pd-ovl-line); border-top-color: var(--pd-ovl-orange-ink); border-radius: 50%; animation: pd-ovl-sp .7s linear infinite; }
@keyframes pd-ovl-sp { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .pd-ovl-sk, .pd-ovl-spin { animation: none; }
}

.pd-ovl-consent { display: flex; align-items: flex-start; gap: 12px; margin: 22px 0 14px; padding: 14px 15px; border: 1.5px solid var(--pd-ovl-border); border-radius: var(--pd-ovl-r); background: var(--pd-ovl-bg-soft); cursor: pointer; }
.pd-ovl-consent:hover { border-color: var(--pd-ovl-border-2); }
.pd-ovl-consent input { position: absolute; opacity: 0; width: 0; height: 0; }
.pd-ovl-consent-box { width: 21px; height: 21px; flex: none; margin-top: 1px; border-radius: 4px; border: 1.5px solid var(--pd-ovl-border-2); background: #fff; color: transparent; display: flex; align-items: center; justify-content: center; transition: all .13s; }
.pd-ovl-consent input:checked + .pd-ovl-consent-box { background: var(--pd-ovl-orange-ink); border-color: var(--pd-ovl-orange-ink); color: #fff; }
.pd-ovl-consent input:focus-visible + .pd-ovl-consent-box { outline: 3px solid rgba(184,82,18,.45); outline-offset: 2px; }
.pd-ovl-consent-box svg { width: 13px; height: 13px; }
.pd-ovl-consent-text { font-size: 13px; line-height: 1.6; color: var(--pd-ovl-slate); }
/* legal copy is fixed — do not reword */
.pd-ovl-consent-text #pd-ovl-billing { display: block; margin-top: 7px; padding-top: 7px; border-top: 1px dashed var(--pd-ovl-line); color: var(--pd-ovl-ink); }
.pd-ovl-is-error-consent .pd-ovl-consent { border-color: #e3b4af; background: #fdf2f1; }

.pd-ovl-pay { width: 100%; font-family: inherit; font-size: 17px; font-weight: 700; color: #fff; background: var(--pd-ovl-orange-ink); border: none; border-radius: var(--pd-ovl-r); padding: 17px; display: flex; align-items: center; justify-content: center; gap: 9px; box-shadow: 0 3px 12px rgba(184,82,18,.28); cursor: pointer; transition: background .14s; }
.pd-ovl-pay:hover:not(:disabled) { background: var(--pd-ovl-orange-ink-hov); }
.pd-ovl-pay:focus-visible { outline: 3px solid var(--pd-ovl-ink); outline-offset: 2px; }
/* ⚠ #5f6c7e, not the design's #6a7789. The design's own audit flags that pair
   as "at the AA line; if the token moves, darken to #5f6c7e" — so this takes
   the darker value it names rather than sitting on the boundary. */
.pd-ovl-pay:disabled { background: #e8ecf2; color: #5f6c7e; box-shadow: none; cursor: not-allowed; }
.pd-ovl-pay-ico { width: 17px; height: 17px; flex: none; }
.pd-ovl-pay:disabled .pd-ovl-pay-ico { opacity: .6; }
.pd-ovl-pay-foot { display: flex; align-items: center; justify-content: center; gap: 8px; margin-top: 12px; font-size: 12px; color: var(--pd-ovl-muted); }
.pd-ovl-pay-foot svg { width: 13px; height: 13px; flex: none; }

@media (max-width: 860px) {
  .pd-ovl-plan-id { width: auto; }
  .pd-ovl-plan-div { display: none; }
  .pd-ovl-plan { flex-wrap: wrap; }
}
