/* ================================================================
   FPFX — CHECKOUT

   Replaces the 210-line <style> block that lived inside checkout.php,
   which the rebrand pass never reached: it still carried 74 raw violet
   and magenta values and set the page in Manrope. Everything here is
   the agreed design from _design/checkout-preview.html.

   Layout: configuration left, live order summary right. One account
   per order and no add-to-cart step — every selection lands in the
   summary as it is made.
   ================================================================ */
/* ================================================================
   FPFX CHECKOUT v4 — built to the Noctorial reference

   The shape that reference gets right, and the inherited build does not:

     · One account per order, and NO add-to-cart step. Every selection
       lands in the summary the moment it is made, so the price on the
       right is always the price of what is currently chosen.
     · Two steps, tabbed on the right: 1. Configuration, 2. Payment.
       Customer details and payment belong to step 2, so step 1 is
       nothing but choosing.
     · Email is asked FIRST, on its own, to speed the rest up.
     · Sizes a model does not sell stay visible with a ✕ rather than
       disappearing, so the range is legible.

   Everything here is FPFX's own palette, type and marks.
   ================================================================ */
:root{
  --bg:#0A0806;--bg-2:#100C08;--ink:#0D0B08;--surface:#171109;--surface-2:#211810;
  --gold:#EEB762;--gold-hi:#F3DBB2;--gold-dim:#8A6B3A;
  --text:#F8F8F8;--muted:#C4BCB1;--muted-2:#AEA8A1;
  --line:rgba(238,183,98,.15);--line-2:rgba(238,183,98,.42);
  --green:#22C55E;--red:#EF4444;
  /* Named for its job, not a hue. The extraction shipped this as --blue with a
     gold value; a token called --blue in a warm-only system is an invitation to
     put a real blue in it. Aurora permits no blue, violet or teal. */
  --accent-2:#EEB762;
  --ease:cubic-bezier(.22,.61,.36,1);--ease-out:cubic-bezier(.16,1,.3,1);
  --mono:"JetBrains Mono",ui-monospace,Menlo,monospace;
  --sans:var(--au-body,"DM Sans"),system-ui,-apple-system,"Segoe UI",sans-serif;
  --display:var(--au-display,"Outfit"),var(--sans);
}
*{box-sizing:border-box}
body{margin:0;background:var(--bg);color:var(--text);font-family:var(--sans);line-height:1.6;
  -webkit-font-smoothing:antialiased;min-height:100vh;display:flex;flex-direction:column;overflow-x:hidden}
h1,h2,h3,h4{margin:0;line-height:1.08;letter-spacing:-.03em;font-family:var(--display)}
p{margin:0}
a{color:var(--gold);text-decoration:none}
button,input,select{font-family:inherit}
:focus-visible{outline:2px solid var(--gold);outline-offset:3px;border-radius:6px}
/* Alpine cloaking. This lived in the inline <style> that this sheet replaces and
   is NOT optional: without it every x-show/x-if branch paints once before Alpine
   boots, so the page flashes all five programme size grids and both step panes
   before settling. */
[x-cloak]{display:none!important}

/* ---------- masthead ---------- */
.top{border-bottom:1px solid var(--line);background:rgba(9,8,6,.7)}
.top-in{max-width:1240px;margin:0 auto;padding:16px 24px;display:flex;align-items:center;gap:16px}
.lk{display:flex;align-items:center;gap:10px;margin-right:auto}
.lk b{font-size:.98rem;font-weight:800;letter-spacing:-.035em;color:var(--text)}
.lk b em{font-style:normal;background:linear-gradient(100deg,var(--gold-hi),var(--gold) 46%,var(--gold-dim));
  -webkit-background-clip:text;background-clip:text;color:transparent}
.top .stat{display:flex;align-items:center;gap:7px;font-family:var(--mono);font-size:10px;
  letter-spacing:.12em;text-transform:uppercase;color:var(--muted-2)}
.pip{width:6px;height:6px;border-radius:50%;background:var(--green)}
.top .ghost{padding:8px 13px;border-radius:9px;border:1px solid var(--line);color:var(--muted);
  font-family:var(--mono);font-size:9.5px;letter-spacing:.12em;text-transform:uppercase;transition:.25s var(--ease)}
.top .ghost:hover{color:var(--text);border-color:var(--line-2)}
@media(max-width:820px){.hide-sm{display:none}}

.hero{max-width:1240px;margin:0 auto;padding:38px 24px 0}
.hero h1{font-size:clamp(30px,4.6vw,46px);font-weight:800}
.hero h1 em{font-style:italic;font-weight:400;
  background:linear-gradient(100deg,var(--gold-hi),var(--gold) 50%,var(--gold-dim));
  -webkit-background-clip:text;background-clip:text;color:transparent}
.hero p{margin-top:12px;color:var(--muted);font-size:1rem;max-width:52ch}
.hero hr{margin:26px 0 0;border:0;border-top:1px solid var(--line)}

/* ---------- layout ---------- */
main{flex:1;width:100%;max-width:1240px;margin:0 auto;padding:24px 24px 40px;
  display:grid;grid-template-columns:minmax(0,1fr) 396px;gap:26px;align-items:start}
@media(max-width:1040px){main{grid-template-columns:1fr;padding-bottom:100px}}

.card{border:1px solid var(--line);border-radius:18px;
  background:linear-gradient(168deg,rgba(23,19,13,.8),rgba(13,11,8,.8))}
.card-b{padding:24px}
@media(max-width:520px){.card-b{padding:18px}}

.eyebrow{display:block;font-family:var(--mono);font-size:9.5px;letter-spacing:.15em;
  text-transform:uppercase;color:var(--muted-2);margin-bottom:9px}
h2.sec{font-size:1.15rem;font-weight:800;margin:0 0 4px}
.sec-sub{color:var(--muted-2);font-size:.8rem;margin-bottom:16px}
.divide{border:0;border-top:1px solid var(--line);margin:22px 0}
.grp{margin-bottom:20px}
.grp>h3{font-size:.95rem;font-weight:700;color:var(--text);margin-bottom:11px}

/* choice buttons: model, size, platform */
.picks{display:grid;gap:8px}
.picks.m3{grid-template-columns:repeat(3,1fr)}
.picks.m4{grid-template-columns:repeat(4,1fr)}
@media(max-width:620px){.picks.m3,.picks.m4{grid-template-columns:repeat(2,1fr)}}
.pick{position:relative;padding:14px 10px;border-radius:12px;border:1px solid var(--line);
  background:var(--ink);color:var(--muted);cursor:pointer;font-size:.88rem;font-weight:700;
  text-align:center;transition:color .2s var(--ease),border-color .2s var(--ease),background .2s var(--ease)}
.pick:hover{color:var(--text);border-color:var(--line-2)}
.pick.on{background:linear-gradient(100deg,var(--gold),var(--gold-hi));color:#120E06;border-color:transparent}
.pick small{display:block;font-family:var(--mono);font-size:9px;letter-spacing:.1em;
  text-transform:uppercase;font-weight:500;opacity:.7;margin-top:2px}
.pick.off{opacity:.34;cursor:not-allowed;border-style:dashed}
.pick.off:hover{color:var(--muted);border-color:var(--line)}
.pick .x{margin-left:5px;opacity:.7}
.pick .fee{display:block;font-family:var(--mono);font-size:.72rem;font-weight:600;margin-top:3px;color:var(--gold)}
.pick.on .fee{color:#120E06}
.pick .was{display:block;font-family:var(--mono);font-size:.62rem;font-weight:400;
  color:var(--muted-2);text-decoration:line-through}
.pick.on .was{color:rgba(18,14,6,.55)}
.pick .tag{position:absolute;top:-7px;left:50%;transform:translateX(-50%);padding:2px 7px;border-radius:999px;
  /* Was var(--gold-dim) behind #120E06 at 7px: 3.89:1 and two-thirds the size
     of the contrast floors size band. Gold carries the same meaning and reads. */
  background:var(--gold);color:#120E06;font-family:var(--mono);font-size:9px;font-weight:700;
  letter-spacing:.08em;text-transform:uppercase;white-space:nowrap}
.pick.on .tag{background:#120E06;color:var(--gold-hi)}

/* ---------- email gate: signed in / known email / new email ---------- */
.idbox{margin-top:11px;border-radius:12px;border:1px solid var(--line);background:var(--ink);overflow:hidden}
.idbox[hidden]{display:none}
.idbox.known{border-color:rgba(238,183,98,.42);background:linear-gradient(155deg,rgba(238,183,98,.08),var(--ink))}
.idbox.you{border-color:rgba(34,197,94,.34);background:rgba(34,197,94,.06)}
.idbox-h{display:flex;align-items:center;gap:10px;padding:12px 14px}
.idbox-h svg{flex:none}
.idbox.known .idbox-h svg{color:var(--gold)}
.idbox.you .idbox-h svg{color:var(--green)}
.idbox-h b{font-size:.85rem;font-weight:700}
.idbox-h small{display:block;color:var(--muted);font-size:.74rem;line-height:1.45;margin-top:2px}
.idbox-h .alt{margin-left:auto;flex:none;border:0;background:transparent;cursor:pointer;color:var(--muted-2);
  font-family:var(--mono);font-size:9px;letter-spacing:.11em;text-transform:uppercase;padding:4px}
.idbox-h .alt:hover{color:var(--gold)}
.idbox-h .alt:focus-visible{outline:2px solid var(--gold);outline-offset:2px;border-radius:6px;color:var(--gold)}
/* wrap, not nowrap: at 360px an input and an 18px-padded button on one row push
   the card past the viewport, and this panel appears mid-checkout on a phone. */
.idbox-b{padding:0 14px 14px;display:flex;flex-wrap:wrap;gap:8px;align-items:flex-start}
.idbox-b .f{flex:1 1 190px;min-width:0;margin:0}
.idbox-b .signin{flex:none;padding:12px 18px;border-radius:11px;border:0;cursor:pointer;
  font-size:.85rem;font-weight:700;background:linear-gradient(100deg,var(--gold),var(--gold-hi));color:#120E06;
  /* the field has a label above it; without this the button floats halfway up */
  align-self:flex-end}
.idbox-b .signin:disabled{opacity:.6;cursor:default}
.idbox-b .signin:focus-visible{outline:2px solid var(--gold-hi);outline-offset:2px}
.idbox-foot{padding:0 14px 13px;font-size:.73rem;color:var(--muted-2)}
.idbox-foot a{color:var(--gold);text-decoration:none;border-bottom:1px solid var(--line-2)}
.idbox-foot a:hover{color:var(--gold-hi)}

/* THE ROW IS RESERVED AND NEVER REMOVED — two problems, one rule.

   LAYOUT. As `display:none`/`hidden`, the panel below jumped down by the height
   of this line the instant the lookup started and back up when it finished,
   under the pointer, on the field the customer had just left. It now keeps its
   box at all times and only the spinner's ink disappears.

   ANNOUNCEMENT. A live region that is display:none OR visibility:hidden is out
   of the accessibility tree, so toggling the CONTAINER would have meant the
   "Checking" state was announced to nobody — the region would arrive already
   populated instead of changing while being observed. So the container is
   permanently present and it is the TEXT INSIDE it that empties, which is the
   change screen readers are listening for. */
.checking{display:flex;align-items:center;gap:8px;margin-top:9px;min-height:14px;
  font-family:var(--mono);font-size:9px;
  letter-spacing:.12em;text-transform:uppercase;color:var(--muted-2)}
.checking[hidden]{visibility:hidden}
.checking i{width:10px;height:10px;border-radius:50%;border:1.5px solid var(--line-2);
  border-top-color:var(--gold);animation:spin .7s linear infinite}
.checking i.off{visibility:hidden;animation:none}
@media (prefers-reduced-motion: reduce){.checking i{animation-duration:2.4s}}
@keyframes spin{to{transform:rotate(360deg)}}

/* preview-only state switcher */

/* contract strip */
.contract{display:grid;grid-template-columns:repeat(auto-fit,minmax(98px,1fr));gap:1px;
  background:var(--line);border:1px solid var(--line);border-radius:13px;overflow:hidden;margin-top:4px}
.contract div{padding:12px 14px;background:var(--ink)}
.contract small{display:block;font-family:var(--mono);font-size:9px;letter-spacing:.13em;
  text-transform:uppercase;color:var(--muted-2)}
.contract b{display:block;margin-top:4px;font-family:var(--mono);font-size:.9rem;font-weight:600;color:var(--text)}
.contract div.hi b{color:var(--gold)}

/* ---------- add-ons ---------- */
.addon{border-bottom:1px solid var(--line)}
.addon:last-of-type{border-bottom:0}
.addon-r{display:flex;align-items:center;gap:12px;padding:13px 2px;cursor:pointer}
/* checkbox, not a radio — add-ons are independent of one another */
.addon-tick{flex:none;width:19px;height:19px;border-radius:6px;border:1px solid rgba(238,183,98,.35);
  display:grid;place-items:center;background:var(--ink);transition:.2s var(--ease)}
.addon-tick::after{content:"";width:4.5px;height:9px;margin-top:-2px;
  border:2px solid #120E06;border-top:0;border-left:0;transform:rotate(42deg);
  opacity:0;transition:opacity .18s}
.addon-r:hover .addon-tick{border-color:var(--line-2)}
.addon.on .addon-tick{background:linear-gradient(100deg,var(--gold),var(--gold-hi));border-color:transparent}
.addon.on .addon-tick::after{opacity:1}
.addon-n{font-size:.88rem;font-weight:600;color:var(--text)}
.addon-pct{padding:3px 8px;border-radius:999px;background:rgba(238,183,98,.12);
  border:1px solid rgba(238,183,98,.3);color:var(--gold);
  font-family:var(--mono);font-size:9px;font-weight:600;white-space:nowrap}
.addon-badge{padding:3px 7px;border-radius:999px;background:var(--gold);color:#120E06;
  font-family:var(--mono);font-size:9px;font-weight:700;letter-spacing:.08em;text-transform:uppercase}
.addon-more{margin-left:auto;display:flex;align-items:center;gap:6px;border:0;background:transparent;
  color:var(--muted-2);font-family:var(--mono);font-size:9px;letter-spacing:.1em;text-transform:uppercase;
  cursor:pointer;padding:5px 2px;transition:color .2s}
.addon-more:hover{color:var(--gold)}
.addon-more i{width:15px;height:15px;border-radius:50%;border:1px solid currentColor;display:grid;
  place-items:center;font-style:normal;font-size:9px}
.addon-info{display:none;padding:0 2px 15px 31px}
.addon-info.open{display:block}
.addon-info p{font-size:.79rem;color:var(--muted);line-height:1.6}
.addon-info ul{margin:8px 0 0;padding-left:16px;font-size:.76rem;color:var(--muted-2);line-height:1.7}
.addon-info code{font-family:var(--mono);font-size:.7rem;color:var(--gold-dim)}

/* ---------- forms ---------- */
.pair{display:grid;grid-template-columns:1fr 1fr;gap:12px}
@media(max-width:480px){.pair{grid-template-columns:1fr;gap:0}}
.f{margin-bottom:13px}
.f>label{display:block;font-family:var(--mono);font-size:9px;letter-spacing:.14em;
  text-transform:uppercase;color:var(--muted-2);margin-bottom:7px}
.f>label .req{color:var(--gold-dim)}
.in{width:100%;padding:12px 14px;border-radius:11px;font-size:.9rem;border:1px solid var(--line);
  background:var(--ink);color:var(--text);transition:border-color .25s ease,background .25s ease}
.in:focus{outline:none;border-color:var(--line-2);background:var(--surface)}
.in::placeholder{color:#4B473F}
select.in{appearance:none;cursor:pointer;padding-right:36px;
  background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'><path d='M1 1l5 5 5-5' fill='none' stroke='%238E8A82' stroke-width='1.6' stroke-linecap='round'/></svg>");
  background-repeat:no-repeat;background-position:right 13px center}
.hint{font-size:.72rem;color:var(--muted-2);margin-top:6px;line-height:1.5}
.hint code{font-family:var(--mono);font-size:.68rem;color:var(--gold-dim)}
.inp{position:relative;display:block}
.inp .in{padding-right:60px}
.rev{position:absolute;right:7px;top:50%;transform:translateY(-50%);border:1px solid transparent;
  background:transparent;cursor:pointer;padding:7px 8px;border-radius:8px;font-family:var(--mono);
  font-size:9px;letter-spacing:.12em;color:var(--muted-2);transition:.25s var(--ease)}
.rev:hover{color:var(--gold);background:rgba(238,183,98,.08);border-color:var(--line)}
.err{display:none;align-items:center;gap:6px;margin-top:7px;font-size:.74rem;color:#ff9b9b}
.err.on{display:flex}
.err::before{content:"!";flex:none;width:13px;height:13px;border-radius:50%;display:grid;place-items:center;
  background:var(--red);color:#fff;font-size:9px;font-weight:700}
.f.bad .in{border-color:var(--red);background:rgba(239,68,68,.05)}
.iti{display:block;width:100%}
.iti .in{padding-left:96px}
.iti__selected-country{border-radius:11px 0 0 11px;background:rgba(238,183,98,.05)!important}
.iti__dropdown-content,.iti__country-list{background:#0D0B08!important;color:var(--text)!important;
  border:1px solid var(--line)!important;box-shadow:0 22px 60px rgba(0,0,0,.6)!important}
.iti__country{background:#0D0B08!important;color:var(--text)!important}
.iti__country.iti__highlight,.iti__country:hover{background:var(--surface-3,#2E2116)!important}
.iti__dial-code{color:var(--muted-2)!important}
.iti__search-input{background:var(--bg,#0A0806)!important;color:var(--text)!important;
  border:1px solid var(--line)!important;border-radius:9px!important;padding:9px 11px!important}

/* ---------- payment ---------- */
.gws{display:grid;gap:8px}
.gw{display:flex;align-items:center;gap:12px;padding:13px 14px;border-radius:12px;border:1px solid var(--line);
  background:var(--ink);cursor:pointer;transition:border-color .25s var(--ease),background .25s var(--ease)}
.gw:hover{border-color:var(--line-2)}
.gw.on{border-color:var(--gold);background:linear-gradient(155deg,rgba(238,183,98,.1),rgba(13,11,8,.9))}
/* The radio is HIDDEN, NOT REMOVED. display:none takes an input out of the tab
   order and out of the arrow-key roving a radiogroup depends on, so a keyboard
   buyer could see two payment methods and reach neither. Clipped instead: the
   control keeps its focus, its name/value pairing and its native group
   semantics, and the label draws the visible state. :focus-within is what puts
   the ring on the tile the hidden input is inside. */
.gw input{position:absolute;width:1px;height:1px;margin:-1px;padding:0;border:0;
  clip:rect(0 0 0 0);clip-path:inset(50%);overflow:hidden;white-space:nowrap}
.gw:focus-within{border-color:var(--gold);outline:2px solid rgba(238,183,98,.5);outline-offset:2px}
.gw-mark{flex:none;width:40px;height:40px;display:grid;place-items:center;border-radius:11px;
  border:1px solid var(--line);background:var(--bg-2);color:var(--gold)}
.gw.on .gw-mark{background:linear-gradient(100deg,var(--gold),var(--gold-hi));color:#120E06;border-color:transparent}
.gw-c{min-width:0;flex:1}
.gw-c b{display:block;font-size:.86rem;font-weight:700}
.gw-c small{display:block;color:var(--muted-2);font-size:.71rem;line-height:1.45;margin-top:1px}
.gw-tag{flex:none;font-family:var(--mono);font-size:9px;letter-spacing:.1em;
  text-transform:uppercase;color:var(--muted-2)}
.cardbox{margin-top:12px;border:1px solid var(--line);border-radius:13px;overflow:hidden;background:var(--bg-2)}
.cardbox[hidden]{display:none}
.cardbox-h{display:flex;align-items:center;gap:9px;padding:12px 15px;border-bottom:1px solid var(--line);
  font-family:var(--mono);font-size:9px;letter-spacing:.13em;text-transform:uppercase;color:var(--muted-2)}
.cardbox-h b{color:var(--text);font-weight:600;margin-right:auto}
.brands{display:flex;gap:5px}
.brands span{padding:2px 6px;border-radius:4px;border:1px solid var(--line);
  font-family:var(--mono);font-size:9px;color:var(--muted-2);transition:.25s ease}
.brands.narrowed span{opacity:.25}
.brands.narrowed span.hit{opacity:1;border-color:var(--gold);color:var(--gold)}
.cardbox-b{padding:15px}
.cnum{font-family:var(--mono);letter-spacing:.08em}
/* `.cbrand` — an absolutely-positioned slot for a vendor logo inside the number
   field — is DELIBERATELY GONE, along with the `.inp .cnum` right padding that
   reserved room for it. The preview's brand artwork hard-codes #1F72CD, #1A1F71,
   #EB001B, #F79E1B and font-family:Inter: a blue, a navy, a legacy type stack,
   and a fourth brand (Discover) that the gateway's paymentBrand field cannot
   even be told about. The detected brand is shown by lighting the matching pill
   in `.brands` instead — same information, this page's own palette, and it is
   announced to assistive tech by the live region beside it. */
.cvchelp{position:absolute;right:10px;top:50%;transform:translateY(-50%);width:19px;height:19px;
  border-radius:50%;border:1px solid var(--line);background:transparent;color:var(--muted-2);
  font-family:var(--mono);font-size:9px;cursor:pointer;padding:0;line-height:1;
  transition:color .2s var(--ease),border-color .2s var(--ease)}
.cvchelp:hover{color:var(--gold);border-color:var(--line-2)}
.lockline{display:flex;align-items:center;gap:7px;margin-top:13px;font-size:.71rem;color:var(--muted-2)}
.lockline svg{flex:none;color:var(--green)}
.redir{display:flex;gap:10px;align-items:flex-start;margin-top:12px;padding:13px 14px;border-radius:11px;
  border:1px solid rgba(238,183,98,.24);background:rgba(238,183,98,.06)}
.redir[hidden]{display:none}
.redir svg{flex:none;margin-top:2px;color:var(--accent-2)}
.redir b{display:block;font-size:.79rem}
.redir small{display:block;color:var(--muted);font-size:.72rem;line-height:1.55;margin-top:3px}

/* ================================================================
   RIGHT: STEPS + CART
   ================================================================ */
/* main sets align-items:start so the two columns top-align. That shrinks the
   aside to its content, and a sticky child can only travel inside its own
   parent's box — with the parent exactly as tall as the panel there is
   nowhere to travel, so it scrolls away and looks like sticky is ignored.
   Stretching only the aside gives the panel the full grid row to move in;
   the left column keeps its top alignment. */
main > aside{align-self:stretch}
.side{position:sticky;top:20px;display:flex;flex-direction:column;gap:14px}
.steps{display:grid;grid-template-columns:1fr 1fr;gap:8px}
.step{padding:12px;border-radius:11px;border:1px solid var(--line);background:var(--ink);
  color:var(--muted-2);font-size:.83rem;font-weight:600;cursor:pointer;text-align:center;
  transition:.25s var(--ease)}
.step.on{background:linear-gradient(100deg,var(--gold),var(--gold-hi));color:#120E06;border-color:transparent}
.step:disabled{opacity:.4;cursor:not-allowed}

.cart{border:1px solid var(--line);border-radius:18px;overflow:hidden;
  background:linear-gradient(168deg,rgba(23,19,13,.94),rgba(13,11,8,.94));
  box-shadow:0 40px 90px -50px rgba(0,0,0,.95)}
.cart-h{display:flex;align-items:baseline;gap:10px;padding:17px 19px 13px}
.cart-h h2{font-size:1rem;font-weight:800}
.cart-h span{margin-left:auto;font-family:var(--mono);font-size:9px;letter-spacing:.13em;
  text-transform:uppercase;color:var(--muted-2)}
.cart-list{padding:0 19px}

/* the live selection. Contrast matters here: --muted-2 on near-black is
   about 2.9:1, which fails at these sizes, so the meta line uses --muted
   (~5.7:1) and every add-on name uses full --text. */
.li{padding:14px 0;border-bottom:1px solid var(--line)}
.li:last-child{border-bottom:0}
.li-t{display:flex;align-items:baseline;gap:9px}
.li-t b{font-size:1rem;font-weight:800;letter-spacing:-.02em}
.li-t .pr{margin-left:auto;font-family:var(--mono);font-size:.92rem;font-weight:600;color:var(--gold)}
.li-m{margin-top:5px;font-family:var(--mono);font-size:.76rem;letter-spacing:.04em;color:var(--muted)}
.li-a{margin-top:11px;display:grid;gap:7px}
.li-ar{display:flex;align-items:baseline;gap:8px;font-size:.83rem;color:var(--text)}
.li-ar .v{margin-left:auto;font-family:var(--mono);font-size:.79rem;color:var(--muted)}
.li-ar::before{content:"+";flex:none;font-family:var(--mono);font-size:.72rem;color:var(--gold-dim)}

.cart-sum{margin:15px 19px 0;padding-top:14px;border-top:1px solid var(--line)}
.sr{display:flex;align-items:baseline;gap:10px;padding:4px 0;font-size:.82rem;color:var(--muted)}
.sr .v{margin-left:auto;font-family:var(--mono);color:var(--text)}
.sr.off .v,.sr.off span:first-child{color:var(--green)}
.sr.tot{margin-top:9px;padding-top:12px;border-top:1px solid var(--line);color:var(--text);font-weight:700}
.sr.tot .v{font-family:var(--mono);font-size:1.5rem;font-weight:700;color:var(--gold);letter-spacing:-.03em}

.acc{margin:14px 19px 0}
.acc-h{display:flex;align-items:center;width:100%;padding:12px 13px;border-radius:11px;
  border:1px solid var(--line);background:var(--ink);color:var(--muted);cursor:pointer;font-size:.82rem}
.acc-h:hover{border-color:var(--line-2);color:var(--text)}
.acc-h i{margin-left:auto;font-style:normal;font-size:.7rem;transition:transform .25s var(--ease)}
.acc.open .acc-h i{transform:rotate(180deg)}
.acc-b{display:none;margin-top:8px;gap:7px}
.acc.open .acc-b{display:flex}
.acc-b .in{padding:10px 12px;text-transform:uppercase;font-family:var(--mono);font-size:.75rem;letter-spacing:.08em}
.acc-b button{flex:none;padding:0 15px;border-radius:11px;border:1px solid var(--line);background:transparent;
  color:var(--muted);font-family:var(--mono);font-size:9px;letter-spacing:.12em;text-transform:uppercase;cursor:pointer}
.acc-b button:hover{color:var(--text);border-color:var(--line-2)}
.coupon-on{display:flex;align-items:center;gap:9px;margin:14px 19px 0;padding:10px 12px;border-radius:11px;
  border:1px dashed rgba(34,197,94,.4);background:rgba(34,197,94,.06);font-size:.76rem}
.coupon-on b{font-family:var(--mono);color:var(--green)}
.coupon-on button{margin-left:auto;border:0;background:transparent;color:var(--muted-2);cursor:pointer;
  font-family:var(--mono);font-size:9px;letter-spacing:.11em;text-transform:uppercase}
.coupon-on button:hover{color:var(--red)}

.cart-b{padding:15px 19px 19px}
.chk{display:flex;align-items:flex-start;gap:9px;margin-bottom:13px;font-size:.75rem;line-height:1.5;
  color:var(--muted);cursor:pointer}
.chk input{appearance:none;flex:none;width:16px;height:16px;margin:2px 0 0;display:grid;place-items:center;
  border-radius:5px;border:1px solid rgba(238,183,98,.3);background:var(--ink);cursor:pointer}
.chk input:checked{background:linear-gradient(100deg,var(--gold),var(--gold-hi));border-color:transparent}
.chk input:checked::after{content:"";width:4px;height:8px;margin-top:-2px;
  border:2px solid #120E06;border-top:0;border-left:0;transform:rotate(42deg)}
.go{display:block;width:100%;padding:15px;border-radius:12px;border:0;cursor:pointer;
  font-size:.92rem;font-weight:700;background:linear-gradient(100deg,var(--gold),var(--gold-hi));color:#120E06;
  box-shadow:0 14px 34px -14px rgba(238,183,98,.7);transition:transform .24s var(--ease-out),box-shadow .3s ease}
.go:hover{transform:translateY(-2px);box-shadow:0 22px 46px -16px rgba(238,183,98,.85)}
.go:disabled{opacity:.4;cursor:not-allowed;transform:none;box-shadow:none}
.ent{display:flex;gap:9px;align-items:flex-start;margin-top:13px;padding-top:13px;border-top:1px solid var(--line)}
.ent svg{flex:none;margin-top:2px;color:var(--gold-dim)}
.ent small{color:var(--muted-2);font-size:.66rem;line-height:1.55}

/* step panes */
.pane{display:none}
.pane.on{display:block}

/* mobile bar */
.bar{display:none}
@media(max-width:1040px){
  .side{position:static}
  .cart-b .go{display:none}
  .bar{display:flex;position:fixed;left:0;right:0;bottom:0;z-index:30;align-items:center;gap:14px;
    padding:11px 18px calc(11px + env(safe-area-inset-bottom));border-top:1px solid var(--line);
    background:rgba(9,8,6,.95);backdrop-filter:blur(16px)}
  .bar small{display:block;font-family:var(--mono);font-size:9px;letter-spacing:.14em;
    text-transform:uppercase;color:var(--muted-2)}
  .bar b{display:block;font-family:var(--mono);font-size:1.12rem;font-weight:700;color:var(--gold);line-height:1.2}
  .bar .go{width:auto;margin-left:auto;padding:13px 22px;white-space:nowrap}
}
/* The preview's own one-line <footer> is NOT ported. The built page ends in the
   shared .plinth from public-footer.php, which brings its own stylesheet. A bare
   `footer{...}` rule here would centre-align and shrink the whole plinth on this
   one surface, so the rule is deliberately absent rather than merely unused. */

/* ================================================================
   BUILT-PAGE BRIDGE
   ----------------------------------------------------------------
   Everything above is the extraction from _design/checkout-preview.html.
   Everything below is what the LIVE page needs and the preview never had:
   the real masthead links, the validation panel, the affiliate banner, the
   quote-loading state and the offset for the shared .plinth under the mobile
   pay bar. Kept in one block at the end so the extraction stays readable as
   an extraction.
   ================================================================ */

/* ---------- masthead: real links in the preview's shell ---------- */
.top-in .lk img{display:block;height:26px;width:auto}
.top .ghost{display:inline-flex;align-items:center;gap:6px;white-space:nowrap;cursor:pointer}
.top .ghost svg{width:14px;height:14px;flex:none}
/* [hidden] HAS TO BE RESTATED AT THIS SPECIFICITY, exactly as .hide-sm does
   twenty lines below and for the same reason: `.top .ghost` sets display at
   (0,2,0) and the UA's `[hidden]{display:none}` cannot reach it. Without this
   the masthead would go on offering "Sign in" to a customer who has just signed
   in from the panel below — the most permanent chrome on the page contradicting
   the thing they just did. */
.top .ghost[hidden],.top .who[hidden]{display:none}
.top .who{font-family:var(--mono);font-size:9.5px;letter-spacing:.1em;text-transform:uppercase;
  color:var(--muted-2);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:30ch}
/* .hide-sm HAS TO BE RESTATED HERE, and at this specificity, or it does not work.
   The extraction declares `.hide-sm{display:none}` at (0,1,0) but `.top .stat` and
   `.top .ghost` at (0,2,0), so the secure-checkout pip and the sign-in link stayed
   on screen at every width and pushed the Help link off the right edge at 360px —
   measured: the link sat at left 361 in a 360px viewport, clipped by body's
   overflow-x:hidden, so the only support route on a payment page was unreachable
   and there was not even a scrollbar to hint at it. */
@media(max-width:820px){
  .top .hide-sm{display:none}
}
@media(max-width:560px){
  .top-in{gap:9px;padding:13px 16px}
  .top .ghost{padding:7px 10px}
  .top-in .lk img{height:22px}
}

/* ---------- hero ---------- */
.hero h1 em{font-family:var(--display)}
@media(max-width:520px){.hero{padding:26px 16px 0}}

/* ---------- page shell ---------- */
/* fpfx.css sets body{overflow-x:clip} to stop the marketing background from
   pushing the page sideways. On a page with a sticky element that is fatal:
   clipping one axis forces the other to `auto`, body becomes the scroll
   container, and the summary then sticks to BODY rather than to the viewport
   — which looks exactly like sticky doing nothing. Checkout carries none of
   those bleeding background layers, so it does not need the clip. */
body.checkout-page{overflow-x:visible;overflow-y:visible}
body.checkout-page{background-attachment:scroll}
.checkout-page .pick,.checkout-page .addon-r,.checkout-page .step,
.checkout-page .go,.checkout-page .gw{touch-action:manipulation}
/* The right column dims while a fresh quote is in flight. Opacity only: the
   figures stay on screen and stay readable, so nothing jumps. */
.checkout-page .quote-updating{opacity:.72;transition:opacity .15s linear}
/* observeCheckoutCards() adds .is-in-view. The card's DEFAULT state is its
   finished state — full border, full opacity — so a hidden tab, a throttled
   rAF or no IntersectionObserver at all still paints a correct first frame.
   .is-in-view only warms the edge. */
.checkout-page .card{transition:border-color .45s var(--ease-out)}
.checkout-page .card.is-in-view{border-color:rgba(238,183,98,.26)}

/* ---------- validation summary ---------- */
.validation-panel{margin:0 0 16px;padding:16px 17px;border-radius:15px;
  border:1px solid rgba(239,68,68,.5);background:linear-gradient(160deg,rgba(239,68,68,.09),rgba(13,11,8,.9))}
.validation-head{display:flex;align-items:flex-start;gap:11px;margin-bottom:12px}
.validation-icon{flex:none;width:34px;height:34px;border-radius:11px;display:grid;place-items:center;
  background:rgba(239,68,68,.16);color:#ff9b9b}
.validation-head b{display:block;font-size:.88rem;font-weight:700;color:var(--text)}
.validation-head p{margin:3px 0 0;color:var(--muted);font-size:.78rem;line-height:1.45}
.validation-list{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px}
.validation-item{display:flex;align-items:center;gap:10px;min-width:0;padding:9px 11px;border-radius:11px;
  border:1px solid var(--line);background:var(--ink);color:var(--text);text-align:left;cursor:pointer;
  font:inherit;transition:border-color .18s var(--ease),transform .18s var(--ease)}
.validation-item:hover{border-color:var(--line-2);transform:translateY(-1px)}
.validation-item i{flex:none;width:24px;height:24px;display:grid;place-items:center;border-radius:8px;
  background:rgba(239,68,68,.16);color:#ff9b9b;font-style:normal;font-family:var(--mono);
  font-size:11px;font-weight:700}
.validation-item span{min-width:0}
.validation-item b{display:block;font-size:.78rem;font-weight:600}
.validation-item small{display:block;margin-top:1px;color:var(--muted);font-size:.68rem;line-height:1.35}
@media(max-width:620px){.validation-list{grid-template-columns:1fr}}

/* ---------- affiliate attribution banner ---------- */
.affiliate-purchase-banner{display:flex;align-items:center;gap:12px;margin:0 0 16px;padding:14px 15px;
  border-radius:15px;border:1px solid rgba(238,183,98,.28);
  background:linear-gradient(160deg,rgba(238,183,98,.09),rgba(13,11,8,.9))}
.affiliate-purchase-banner .affiliate-mark{flex:none;width:40px;height:40px;border-radius:12px;display:grid;
  place-items:center;background:linear-gradient(100deg,var(--gold),var(--gold-hi));color:#120E06;
  font-family:var(--mono);font-weight:700}
/* The tile holds the supplied mono crest, not a letter. The master is a flat
   white silhouette, which is what makes it legible on the gold ground. */
.affiliate-purchase-banner .affiliate-mark img{display:block;width:22px;height:22px;object-fit:contain}
.affiliate-purchase-banner>div{min-width:0}
.affiliate-purchase-banner small{display:block;font-family:var(--mono);font-size:9px;letter-spacing:.13em;
  text-transform:uppercase;color:var(--muted-2)}
.affiliate-purchase-banner b{display:block;margin-top:2px;font-size:.84rem;color:var(--text);font-weight:600}
.affiliate-purchase-banner em{display:block;margin-top:3px;font-style:normal;font-size:.74rem;color:var(--muted)}
.affiliate-purchase-banner strong{color:var(--gold)}

/* ---------- add-on row, live data ---------- */
.addon-r{flex-wrap:wrap}
.addon-n{flex:1 1 auto;min-width:0}
.addon-more{flex:none}
.addon.is-locked .addon-r{cursor:default}
.addon.is-locked .addon-tick{opacity:.55}
@media(max-width:520px){
  .addon-more .t{display:none}
  .addon-info{padding-left:2px}
}

/* ---------- summary rows ---------- */
/* Colour is never the only signal that a row is a saving: the value already
   carries a leading minus sign, and the label says what the saving is. */
.sr.off .v::before{content:"";}
.sr .v{white-space:nowrap}
.cart-h span{white-space:nowrap}

/* ---------- steps ---------- */
.step{font-family:var(--display)}
.step[aria-current="true"]{position:relative}

/* ---------- keep the plinth clear of the fixed pay bar ---------- */
@media(max-width:1040px){
  .checkout-page .plinth{padding-bottom:84px}
}

/* ---------- overflow safety ---------- */
/* Long programme names and long money strings must wrap or ellipsis rather than
   widen the page. Verified at 360px. */
.pick{overflow-wrap:anywhere}
.li-t b{min-width:0;overflow-wrap:anywhere}
.contract b{overflow-wrap:anywhere}
.gw-c b,.gw-c small{overflow-wrap:anywhere}

/* ---------- motion ---------- */
@media(prefers-reduced-motion:reduce){
  *,*::before,*::after{animation-duration:.001ms!important;animation-iteration-count:1!important;
    transition-duration:.001ms!important;scroll-behavior:auto!important}
  .go:hover{transform:none}
  .validation-item:hover{transform:none}
}

/* ---------- visually hidden, still in the accessibility tree ---------- */
/* The add-on tick and the coupon label are real form controls. Hiding them with
   display:none would take them out of the tab order and out of the screen-reader
   tree; this keeps both and lets .addon-tick be the thing that is painted. */
.fx-vh{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;
  clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;border:0}
.addon-r input.fx-vh:focus-visible+.addon-tick{outline:2px solid var(--gold);outline-offset:2px}
.addon-r input.fx-vh:disabled+.addon-tick{opacity:.5}

/* ---------- keyboard focus on the text inputs ---------- */
/* The extraction sets `.in:focus{outline:none}` at (0,2,0), which beats the page's
   `:focus-visible` rule at (0,1,0) — so a keyboard user tabbing through the customer
   form got NO ring, only a border tint from rgba(238,183,98,.15) to .42. That is a
   colour-only signal on a payment form. Restated here, later in the file and at
   matching specificity, so the ring comes back for keyboard focus while a mouse
   click still gets the quiet border change. */
.in:focus-visible{outline:2px solid var(--gold);outline-offset:2px}
.acc-b button:focus-visible,.acc-h:focus-visible,.step:focus-visible,
.go:focus-visible,.pick:focus-visible,.top .ghost:focus-visible{outline:2px solid var(--gold);outline-offset:3px}

/* ================================================================
   INLINE CARD FORM
   ----------------------------------------------------------------
   The panel itself (.cardbox, .cardbox-h, .cardbox-b, .brands, .cnum,
   .cvchelp, .pair, .f, .err, .lockline) is already in the extraction
   above, unchanged. What is added here is only what the LIVE inline
   path needs and the preview never had: the busy state while an
   authorisation is in flight, the 3-D Secure interstitial, and the
   notice panel for an answer we could not read.

   No new colour token is introduced. Everything below draws on
   --gold, --gold-hi, --gold-dim, --line, --ink, --bg, --muted and
   --red, which are the page's existing warm set.
   ================================================================ */

/* ---------- brand pills ---------- */
/* The pill row is the brand indicator. `.brands.narrowed span.hit` is already
   declared above; these two only make the row legible on a narrow phone, where
   three pills and the panel title share one line. */
.cardbox-h{flex-wrap:wrap;row-gap:6px}
.brands span{white-space:nowrap}

/* ---------- one card field per row on a phone ---------- */
/* .pair already collapses to one column below 480px, but it also drops its row
   gap there (gap:0), which is right for two stacked text inputs sharing a
   margin and wrong for expiry-above-CVV, where the CVV's own .f has no top
   margin. Restore a row gap for the card pair only. */
@media(max-width:480px){
  .cardbox-b .pair{gap:0 12px}
}

/* ---------- fields in flight ---------- */
/* Disabled rather than merely styled: the values must not change underneath a
   request that has already been sent. */
.cardbox-b .in:disabled{opacity:.55;cursor:not-allowed}
.cardbox[aria-busy="true"]{border-color:var(--line-2)}
.cardbox[aria-busy="true"] .cardbox-h b::after{content:"";display:inline-block;vertical-align:middle;
  width:10px;height:10px;margin-left:8px;border-radius:50%;
  border:2px solid rgba(238,183,98,.28);border-top-color:var(--gold);animation:fx-card-spin .7s linear infinite}
@keyframes fx-card-spin{to{transform:rotate(360deg)}}

/* ---------- the pay button while an authorisation is open ---------- */
/* The button is ALREADY disabled through :disabled="busy"; this is the visible
   half of that, so a slow acquirer does not read as a dead button and invite a
   second click. A gold rule travels the width of the control — motion, not a
   colour change, because the control is gold to begin with. */
.go[aria-busy="true"]{position:relative;overflow:hidden}
.go[aria-busy="true"]::after{content:"";position:absolute;left:0;bottom:0;height:2px;width:38%;
  background:linear-gradient(90deg,transparent,#120E06,transparent);animation:fx-go-sweep 1.15s var(--ease) infinite}
@keyframes fx-go-sweep{from{transform:translateX(-110%)}to{transform:translateX(360%)}}

/* ---------- 3-D Secure interstitial ---------- */
/* Shown for the moment between "your bank needs to verify this" and the ACS page
   taking over the tab. Without it a slow issuer page looks like a hang on a
   screen the customer has just entered a card into, which is exactly when they
   reach for the back button. Full-screen and top-level: the ACS sets its own
   framing policy and portal pages send X-Frame-Options: SAMEORIGIN, so this is a
   real navigation, never an iframe. */
.fx-3ds{position:fixed;inset:0;z-index:80;display:grid;place-items:center;padding:24px;
  background:rgba(5,5,5,.93);backdrop-filter:blur(9px)}
.fx-3ds[hidden]{display:none}
.fx-3ds-in{max-width:380px;text-align:center}
.fx-3ds-ring{width:46px;height:46px;margin:0 auto 18px;border-radius:50%;
  border:2px solid rgba(238,183,98,.2);border-top-color:var(--gold);animation:fx-card-spin .9s linear infinite}
.fx-3ds b{display:block;font-family:var(--display);font-size:1.12rem;font-weight:700;letter-spacing:-.02em}
.fx-3ds p{margin-top:9px;color:var(--muted);font-size:.82rem;line-height:1.6}
.fx-3ds small{display:block;margin-top:14px;font-family:var(--mono);font-size:9px;letter-spacing:.13em;
  text-transform:uppercase;color:var(--muted-2)}

/* ---------- "we could not read the answer" notice ---------- */
/* Amber-warm, NOT red. This panel appears when the browser could not complete
   the request, and the one thing it must not do is look like a decline — a
   customer who reads "failed" pays again, and a payment that actually went
   through is then paid for twice. */
.cardnote{display:flex;gap:11px;align-items:flex-start;margin-top:12px;padding:13px 14px;border-radius:12px;
  border:1px solid rgba(238,183,98,.34);background:rgba(238,183,98,.07)}
.cardnote[hidden]{display:none}
.cardnote svg{flex:none;margin-top:2px;color:var(--gold)}
.cardnote b{display:block;font-size:.8rem}
.cardnote p{margin-top:4px;color:var(--muted);font-size:.74rem;line-height:1.55}
.cardnote a{display:inline-block;margin-top:7px;font-family:var(--mono);font-size:9px;letter-spacing:.12em;
  text-transform:uppercase;border-bottom:1px solid var(--line-2);padding-bottom:2px}

/* ---------- retry mode ---------- */
/* /checkout?retry=<order_number> reopens an order that is already awaiting
   payment. The configuration step is locked because the order — and the amount
   the gateway will be asked for — is already written; letting the buyer change
   the programme here would show one price and charge another. */
.retrylock{display:flex;gap:11px;align-items:flex-start;margin:0 0 16px;padding:14px 15px;border-radius:15px;
  border:1px solid rgba(238,183,98,.28);background:linear-gradient(160deg,rgba(238,183,98,.09),rgba(13,11,8,.9))}
.retrylock svg{flex:none;margin-top:2px;color:var(--gold)}
.retrylock b{display:block;font-size:.85rem}
.retrylock p{margin-top:3px;color:var(--muted);font-size:.75rem;line-height:1.55}
.retrylock code{font-family:var(--mono);font-size:.72rem;color:var(--gold)}
.pane.is-locked{opacity:.55;pointer-events:none;filter:saturate(.65)}

/* ================================================================
   THE CARD VISUAL  (.fxcv-*)
   ----------------------------------------------------------------
   The rendered card beside the four inputs. It fills in as they are
   typed and turns to its back when the security code takes focus.

   IT IS A PICTURE. It contains no input, no form and no field: the
   number, the name and the expiry are DOM TEXT, and the security
   code is never in the DOM at all — the back shows one bullet per
   digit and nothing else. See assets/js/fpfx-card-visual.js.

   WHY A CONTAINER QUERY AND NOT A MEDIA QUERY
   -------------------------------------------
   The width available to this panel is NOT monotonic in the
   viewport. `main` becomes two columns at 1041px and squeezes the
   left one to 580px, so the space inside .cardbox-b measures:

       360px viewport -> 242px      758px viewport -> 628px
      1050px viewport -> 498px     1270px viewport -> 688px

   A 1050px desktop therefore has LESS room than a 768px tablet. Any
   `min-width` media query that put the card beside the fields on a
   "desktop" would squash it flat across the 1041-1111px band. The
   panel's own width is the only honest input, so that is what is
   measured.
   ================================================================ */

/* The query container. `inline-size` only, so height is untouched. Named, so
   nothing else in the sheet can accidentally answer these queries. */
.cardbox-b{container:fxcvbox / inline-size}

/* ---------- the two-up shell ---------- */
.fxcv-split{display:block}

/* ---------- the card ---------- */
/* Hidden until assets/js/fpfx-card-visual.js mounts and adds .is-live. If that
   script 404s or throws, NO CARD APPEARS and the form is exactly what shipped
   before it existed. The visual is an enhancement and never a dependency. */
.fxcv{display:none}
.fxcv.is-live{display:block}
.fxcv{
  perspective:1400px;
  container:fxcvcard / inline-size;
  /* Aurora's curve. NOT var(--ease) — this sheet's global --ease is
     cubic-bezier(.22,.61,.36,1), and retuning it would move every existing
     transition on the page. Declared locally instead. */
  --fxcv-ease:cubic-bezier(.2,.8,.3,1);
  --fxcv-glow:var(--gold);
  margin:0 auto 18px;
  max-width:340px;
}

.fxcv-card{
  position:relative;
  width:100%;
  aspect-ratio:1.586;              /* ISO/IEC 7810 ID-1, the real card ratio */
  transform-style:preserve-3d;
  transition:transform .62s var(--fxcv-ease);
  will-change:transform;
}
.fxcv.is-flipped .fxcv-card{transform:rotateY(180deg)}

.fxcv-face{
  position:absolute;inset:0;
  border-radius:16px;
  overflow:hidden;
  backface-visibility:hidden;
  -webkit-backface-visibility:hidden;
  border:1px solid var(--line);
  /* Depth, not a drop shadow: a warm rim light above, a deep ground below. */
  box-shadow:0 18px 40px -18px rgba(0,0,0,.9),0 2px 0 rgba(238,183,98,.06) inset;
}

/* Front. The brand treatments below override the field; this is the neutral. */
.fxcv-front{background:linear-gradient(152deg,var(--surface-2),var(--surface) 62%,var(--ink))}
.fxcv-back{
  transform:rotateY(180deg);
  background:linear-gradient(152deg,var(--surface),var(--ink) 70%);
}

/* ---------- the bull ---------- */
/* The approved render, assets/images/bull-candlestick.webp. It carries a SOLID
   BLACK GROUND, so it is screened rather than masked — screen drops black to
   nothing and leaves only the lit part of the animal on the card.
   Brand art on this project is a rendered image and never a drawn path. */
.fxcv-bull{
  position:absolute;right:-6%;bottom:-8%;
  width:62%;height:auto;
  
  opacity:.5;
  pointer-events:none;user-select:none;
}

/* ---------- the specular sheen ---------- */
.fxcv-sheen{
  position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(114deg,transparent 32%,rgba(243,219,178,.11) 46%,rgba(243,219,178,.02) 54%,transparent 68%);
  animation:fxcv-sheen 7.5s var(--fxcv-ease) infinite;
}
@keyframes fxcv-sheen{
  0%,62%{transform:translateX(-58%)}
  100%{transform:translateX(58%)}
}

/* ---------- furniture ---------- */
.fxcv-mark{
  position:absolute;left:6.2%;top:8%;
  font-family:var(--display);font-weight:700;
  font-size:clamp(11px,4.6cqw,16px);letter-spacing:.06em;
  color:var(--gold-hi);
}
.fxcv-chip{
  position:absolute;left:6.2%;top:32%;
  width:13.4%;aspect-ratio:1.34;
  border-radius:4px;
  background:linear-gradient(145deg,var(--gold-hi),var(--gold) 42%,var(--gold-dim));
  display:flex;flex-direction:column;justify-content:center;gap:11%;padding:0 14%;
  box-shadow:0 1px 2px rgba(0,0,0,.5);
}
.fxcv-chip i{display:block;height:1px;background:rgba(13,11,8,.55);border-radius:1px}
.fxcv-brand{
  position:absolute;right:6.2%;top:8%;
  font-family:var(--mono);font-weight:600;
  font-size:clamp(8px,3.1cqw,11px);letter-spacing:.14em;
  color:var(--fxcv-glow);
  text-transform:uppercase;
  transition:opacity .3s var(--fxcv-ease),color .3s var(--fxcv-ease);
}

/* ---------- the number ---------- */
/* ONE TEXT NODE, MONO, TABULAR, NOWRAP. Every glyph the face can show — digit,
   bullet and space alike — has the same advance in JetBrains Mono and in the
   monospace fallbacks, so a digit landing on a bullet moves nothing. The card
   NEVER reflows as it fills, which is the whole trick.
   6.1cqw of the CARD's width fits the longest template this page accepts — a
   19-digit Visa, 23 characters — at the narrowest container that still shows
   the card. Amex is 17 characters and simply ends sooner. */
.fxcv-num{
  position:absolute;left:6.2%;right:6.2%;top:56%;
  font-family:var(--mono);
  font-variant-numeric:tabular-nums;
  font-size:clamp(12px,6.1cqw,20px);
  letter-spacing:0;
  white-space:nowrap;
  color:var(--text);
  text-shadow:0 1px 2px rgba(0,0,0,.65);
}

/* ---------- holder and expiry ---------- */
.fxcv-holder-l,.fxcv-exp-l,.fxcv-cvv-l{
  position:absolute;
  font-family:var(--mono);font-size:clamp(6px,2.3cqw,8px);
  letter-spacing:.15em;text-transform:uppercase;color:var(--muted-2);
}
.fxcv-holder-l{left:6.2%;bottom:20%}
.fxcv-exp-l{right:6.2%;bottom:20%;text-align:right}

.fxcv-holder,.fxcv-exp{
  position:absolute;bottom:8%;
  font-size:clamp(9px,3.5cqw,12px);
  color:var(--text);
  white-space:nowrap;overflow:hidden;
}
/* The name TRUNCATES, it does not overflow: a long legal name on a card is
   normal, and a card face that grows to fit one is not a card face. */
.fxcv-holder{
  left:6.2%;max-width:60%;
  font-family:var(--sans);font-weight:500;
  text-transform:uppercase;letter-spacing:.03em;
  text-overflow:ellipsis;
}
.fxcv-exp{
  right:6.2%;
  font-family:var(--mono);font-variant-numeric:tabular-nums;
}
/* Placeholder state — present, legible, plainly not yet filled. */
.fxcv-holder.is-ph,.fxcv-exp.is-ph{color:var(--muted-2);opacity:.7}

/* ---------- the back ---------- */
.fxcv-stripe{
  position:absolute;left:0;right:0;top:13%;height:19%;
  background:linear-gradient(180deg,#0B0906,#1A1410 40%,#0B0906);
  box-shadow:0 1px 0 rgba(238,183,98,.07),0 -1px 0 rgba(238,183,98,.07);
}
.fxcv-sig{
  position:absolute;left:6.2%;right:6.2%;top:44%;height:20%;
  border-radius:4px;
  background:#E8E2D6;                 /* a signature panel is a printed strip */
  display:flex;align-items:center;justify-content:flex-end;
  padding:0 4%;overflow:hidden;
}
.fxcv-sig-hatch{
  position:absolute;inset:0;
  background:repeating-linear-gradient(115deg,rgba(238,183,98,.22) 0 6px,transparent 6px 12px);
}
/* THE SECURITY CODE, MASKED. One bullet per digit and nothing else — the digits
   never enter this document. There is no reveal control and one must not be
   added; the owner asked for it hidden. */
.fxcv-cvv{
  position:relative;
  font-family:var(--mono);font-size:clamp(9px,3.4cqw,12px);
  letter-spacing:.22em;color:#1A1410;
  min-height:1em;
}
.fxcv-cvv-l{right:6.2%;top:67%}

/* ---------- per-brand treatment ---------- */
/* WARM THROUGHOUT. No vendor colour appears here — no #1A1F71, no #1F72CD, no
   #EB001B. That is the same decision already recorded above, where the .cbrand
   vendor-artwork slot was removed for hard-coding exactly those hues. The brand
   changes the FIELD and the GLOW, never the palette. */
.fxcv[data-fxcv-brand="VISA"] .fxcv-front{
  background:linear-gradient(152deg,#2E2116,var(--surface) 62%,var(--ink));
}
.fxcv[data-fxcv-brand="VISA"]{--fxcv-glow:var(--gold-hi)}

/* Mastercard's FORM — two overlapping discs — drawn in our gold and amber. The
   shape is the recognisable part; the colours are ours. */
.fxcv[data-fxcv-brand="MC"] .fxcv-front{
  background:
    radial-gradient(circle at 84% 84%,rgba(238,183,98,.42) 0 11%,transparent 11.5%),
    radial-gradient(circle at 72% 84%,rgba(243,219,178,.42) 0 11%,transparent 11.5%),
    linear-gradient(152deg,#33240F,var(--surface) 60%,var(--ink));
}
.fxcv[data-fxcv-brand="MC"]{--fxcv-glow:var(--gold)}

.fxcv[data-fxcv-brand="AMEX"] .fxcv-front{
  background:linear-gradient(152deg,#3A2A18,#241A10 58%,var(--ink));
}
.fxcv[data-fxcv-brand="AMEX"]{--fxcv-glow:var(--gold-dim)}

/* ---------- responsive ---------- */
/* Side by side once the panel is genuinely wide enough. 628px at a 768 tablet
   and 688px at 1280 both clear this; the 498px of the 1041-1111px band does
   not, and stacks — correctly, because it really does have less room. */
/* THE GRID IS CONDITIONAL ON A CARD ACTUALLY BEING THERE — `:has(.fxcv.is-live)`
   and not a bare `.fxcv-split`. Measured: with the visual absent the two-column
   rule still allocated its first track, so the fields collapsed to 300px inside
   a 688px panel and 388px sat empty. The card column must only exist when the
   card does. If a browser lacks :has() the whole rule drops and the layout falls
   back to the stacked one below, which is the correct failure direction. */
@container fxcvbox (min-width:600px){
  .fxcv-split:has(.fxcv.is-live){
    display:grid;
    grid-template-columns:minmax(260px,300px) minmax(280px,1fr);
    gap:26px;align-items:start;
  }
  .fxcv-split:has(.fxcv.is-live) .fxcv{margin:0;max-width:300px;position:sticky;top:20px}
}

/* Below that the card sits ABOVE the fields at its own comfortable width. At a
   360px phone the panel is 242px wide, which renders the card at 242x153 with
   the number at about 15px of mono — legible, so it is KEPT, not dropped. */
@container fxcvbox (max-width:599px){
  .fxcv{max-width:340px;margin:0 auto 18px}
}

/* Narrower than this there is no honest way to draw a card. A squashed card is
   worse than no card, so it goes entirely and the fields take the room.

   THE THRESHOLD IS 179px AND NOT 300px, WHICH IS A MEASURED CORRECTION.
   A 360px phone leaves this panel 242px — the viewport loses 30px to the
   panel's own padding and the rest to the page gutters and the card's border.
   A 300px cut-off therefore DROPPED THE CARD ON EVERY PHONE, which is the one
   place the owner is most likely to look at it. Measured at 242px the card
   renders 242x153 with the number at 14.8px of mono, which is comfortably
   legible, so it stays. 179px is roughly a 300px viewport — narrower than any
   real handset — so this rule is now a genuine safety net rather than the
   default path. */
@container fxcvbox (max-width:179px){
  .fxcv.is-live{display:none}
}

/* ---------- motion ---------- */
@media(prefers-reduced-motion:reduce){
  .cardbox[aria-busy="true"] .cardbox-h b::after,
  .fx-3ds-ring,.go[aria-busy="true"]::after{animation:none}
  .go[aria-busy="true"]::after{width:100%;opacity:.35}

  /* THE FLIP STILL HAPPENS — it simply arrives instantly. The rotation is kept,
     only its tween is dropped, so the back face and the masked security code
     stay reachable. The back is NEVER display:none: a reduced-motion user who
     could not see the CVV panel would be stranded, which is a worse outcome
     than the animation they asked not to have. */
  .fxcv-card{transition:none}
  .fxcv-sheen{animation:none}
}
