/* ══ storefront landing — the shared core ═══════════════════════════════════
   One stylesheet, four shops. Nothing below names a colour, a typeface or a
   radius: every one of those comes from the SKIN block above this one, which is
   the only part that differs between storefronts. That is what makes a fix here
   a fix in all four instead of a fix in one and a promise about the others.

   The class names are the ones public/quote.js, public/auth-modal.js and
   lib/coins-footer.js already write. Renaming one here silently unstyles the
   thing it belongs to — there is no error for a class nobody matches.

   Dark only. These shops ship one skin, nailed into the markup on <html>, so
   there is no light palette to keep in step and no switch to flash. ═════════ */
*,*::before,*::after{box-sizing:border-box}
html,body{margin:0;padding:0}
body{background:var(--paper);color:var(--ink);font-family:var(--body);
  font-size:16px;line-height:1.6;-webkit-font-smoothing:antialiased}
img{max-width:100%}
a{color:inherit}
.wrap{max-width:1180px;margin:0 auto;padding:0 34px}
.mono{font-family:var(--mono)}
.eyebrow{font-family:var(--mono);font-size:11px;letter-spacing:.22em;text-transform:uppercase;color:var(--dim)}
h1,h2,h3{font-family:var(--disp);font-weight:var(--disp-w);letter-spacing:var(--disp-ls);margin:0;line-height:1.05}

/* ── buttons ──
   One shape, three weights. The primary is the accent because on a dark page an
   accent-filled slab is the only thing that reads as "press this" without
   shouting; the ghost is a hairline, so a secondary action never competes. */
.btn{display:inline-block;border:0;cursor:pointer;font-family:var(--body);font-weight:700;
  font-size:15px;letter-spacing:.01em;padding:15px 26px;text-decoration:none;border-radius:var(--r);
  background:var(--ac);color:var(--on-ac);transition:transform .12s ease,box-shadow .18s ease,background .18s ease}
.btn:hover{transform:translateY(-1px);box-shadow:0 10px 26px var(--ac-glow)}
.btn.ghost{background:transparent;color:var(--ink);border:1px solid var(--line);box-shadow:none}
.btn.ghost:hover{border-color:var(--ac);box-shadow:none;transform:none}
.btn.sm{font-size:14px;padding:11px 18px}

/* ── header ── */
.nav{position:sticky;top:0;z-index:40;background:var(--paper-90);
  -webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);border-bottom:1px solid var(--line)}
.nav .in{display:flex;align-items:center;gap:32px;height:74px}
.lg{display:flex;align-items:center;gap:11px;text-decoration:none;flex:none}
.lg .mk{height:32px;width:auto;flex:none;border-radius:8px}
.lg b{font-family:var(--disp);font-weight:var(--disp-w);font-size:23px;letter-spacing:var(--disp-ls);
  line-height:1;color:var(--ink)}
.lg b em{font-style:normal;color:var(--ac)}
.nav .links{display:flex;gap:26px;font-size:15px}
.nav .links a{color:var(--dim);text-decoration:none}
.nav .links a:hover{color:var(--ink)}
.nav .right{margin-left:auto;display:flex;align-items:center;gap:12px}
.nav .enter{font-size:15px;font-weight:600;text-decoration:none}
.nav .enter:hover{color:var(--ac)}

/* ── hero ── */
.hero{padding:64px 0 0;display:grid;grid-template-columns:1.05fr .95fr;gap:52px;align-items:start}
.hero h1{font-size:clamp(38px,5.6vw,64px);margin:16px 0 0}
.hero h1 em{font-style:normal;color:var(--ac)}
.hero .sub{font-size:18px;line-height:1.6;color:var(--dim);max-width:54ch;margin:24px 0 0}
.hero .sub b{color:var(--ink);font-weight:600}
.hero .cta{display:flex;gap:14px;align-items:center;flex-wrap:wrap;margin-top:28px}
.hero .cta .fine{font-family:var(--mono);font-size:11.5px;color:var(--dim)}

/* the example card — shows the product before anyone signs up */
.hcard{border:1px solid var(--line);background:var(--card);border-radius:calc(var(--r) + 6px);
  padding:20px 22px;box-shadow:0 24px 60px rgba(0,0,0,.34)}
.hct{font-family:var(--mono);font-size:10px;letter-spacing:.18em;text-transform:uppercase;
  color:var(--dim);padding-bottom:13px;border-bottom:1px solid var(--line);display:flex;justify-content:space-between;gap:10px}
.hr{display:flex;align-items:center;gap:13px;padding:11px 0;border-bottom:1px solid var(--line)}
.hr:last-of-type{border-bottom:0}
/* The logo box is a FIXED width, so every carrier's name starts at the same
   place. Left to size itself, the artwork ranges from 20px (UPS) to 57px (DPD)
   at this height and drags the text after it — which reads as sloppy inside one
   card, and as a twitch when the card cycles to a corridor served by a
   differently-shaped mark. 58px is the widest of them, so nothing is scaled
   down to buy the alignment. Scoped to .hr: .cl is shared with the logo strip,
   which wants its own bigger box. */
.hr .cl{width:58px;flex:none;display:flex;align-items:center;justify-content:center}
.hr .cl img{max-width:58px}
.hr .t{flex:1;min-width:0}
.hr b{display:block;font-size:15.5px;font-weight:700}
.hr span{display:block;font-family:var(--mono);font-size:11px;color:var(--dim);margin-top:3px}
.hr i{font-style:normal;font-family:var(--disp);font-weight:var(--disp-w);font-size:21px}
.hr.pick{background:var(--ac-soft);border-radius:var(--r);padding:11px 14px;margin:0 -14px;border-bottom:0}
.hr.pick i{color:var(--ac)}
.hcf{font-family:var(--mono);font-size:10.5px;color:var(--dim);
  margin-top:14px;padding-top:13px;border-top:1px solid var(--line)}

/* ── the card cycles through four corridors ────────────────────────────────
   The slides are STACKED in one grid cell rather than laid out in a row, for
   two reasons. The card is then as tall as its tallest slide and NOTHING on the
   page moves when one replaces another — a rotator that resizes every three
   seconds drags the whole hero up and down under the reader. And the ones not
   showing go `visibility:hidden`, which takes them out of the accessibility
   tree as well: four stacked copies of a price list, read aloud back to back,
   would be worse than no card at all.

   CSS and not a script, for two reasons that would each be enough: this origin
   serves `script-src 'self'` with no inline scripts, and the page has to work
   with JavaScript off. Where animations do not run — or reduced motion is asked
   for — the FIRST slide is what shows, because that is the base state and the
   animation only ever adds to it. */
.hstack{display:grid}
.hslide{grid-area:1/1;align-self:start;opacity:0;visibility:hidden;animation:hcyc 12s linear infinite}
.hslide:first-child{opacity:1;visibility:visible}
/* Three seconds each. The cross-fade is 3% of the cycle (~0.36s): long enough
   not to read as a blink, short enough that the card is fully legible for
   essentially the whole slot. */
@keyframes hcyc{
  0%{opacity:0;visibility:visible}
  3%{opacity:1}
  25%{opacity:1;visibility:visible}
  28%{opacity:0;visibility:hidden}
  100%{opacity:0;visibility:hidden}
}
/* Three corridors instead of four — a shop whose cache is only warm on three
   routes still gets a card that cycles correctly. Thirds instead of quarters,
   and a second set of keyframes rather than a variable: the percentages inside
   a @keyframes cannot come from a custom property, so faking it with one would
   leave the card blank for a quarter of every cycle. Put `h3` on .hstack. */
.hstack.h3 .hslide{animation-name:hcyc3;animation-duration:9s}
.hstack.h3 + .hdots i{animation-name:hdot3;animation-duration:9s}
.hstack.h3 .hslide:nth-child(2),.hstack.h3 + .hdots i:nth-child(2){animation-delay:3s}
.hstack.h3 .hslide:nth-child(3),.hstack.h3 + .hdots i:nth-child(3){animation-delay:6s}
@keyframes hcyc3{
  0%{opacity:0;visibility:visible}
  4%{opacity:1}
  33%{opacity:1;visibility:visible}
  37%{opacity:0;visibility:hidden}
  100%{opacity:0;visibility:hidden}
}
@keyframes hdot3{0%,33%{background:var(--ac)}37%,100%{background:var(--line)}}
.hdots{display:flex;gap:7px;margin-top:16px}
.hdots i{width:6px;height:6px;border-radius:50%;background:var(--line);animation:hdot 12s linear infinite}
@keyframes hdot{0%,25%{background:var(--ac)}28%,100%{background:var(--line)}}
.hslide:nth-child(2),.hdots i:nth-child(2){animation-delay:3s}
.hslide:nth-child(3),.hdots i:nth-child(3){animation-delay:6s}
.hslide:nth-child(4),.hdots i:nth-child(4){animation-delay:9s}
/* Asked for no motion: no rotation at all, and the dots stop describing one —
   the lit dot has to be the slide actually on screen, which is the first. */
@media (prefers-reduced-motion:reduce){
  .hslide,.hdots i{animation:none}
  .hdots i:first-child{background:var(--ac)}
}

/* ── the price check ──────────────────────────────────────────────────────
   A real form, and a real answer, for somebody who has no account. It reads a
   cache the supplier keeps per corridor and weight bucket, refreshed at most
   weekly, priced through THIS shop's markup — so the figure a visitor reads is
   the figure they would be charged. Nothing is quoted live per visitor: that
   would fan out to a dozen carriers over the same egress the label purchases
   use, for a stranger. */
.quote{display:block;margin:48px 0 0;border:1px solid var(--line);background:var(--card);
  border-radius:calc(var(--r) + 6px);padding:24px 26px;color:inherit}
.quote .qt{font-family:var(--mono);font-size:10px;letter-spacing:.2em;
  text-transform:uppercase;color:var(--dim);margin-bottom:14px}
/* Twelve columns and every field says how many it takes, keyed to CLASSES and
   never to :nth-child — so the next field added here cannot silently shift
   everything after it. */
/* Twelve columns, and every field says how many it takes — because how many
   FIELDS there are changes with the session. A visitor sees six controls, a
   signed-in customer eight: the two postcodes appear, and they are what turns a
   cached country-pair estimate into a real, buyable quote.

   Spans keyed to CLASSES, not to :nth-child, so the next field added here
   cannot silently shift everything after it. Both states add up to 12 per row:

     signed out   6 + 6            /  2 + 2 + 5 + 3
     signed in    3 + 3 + 3 + 3    /  2 + 2 + 5 + 3                            */
.qf{display:grid;grid-template-columns:repeat(12,1fr);gap:14px;align-items:end}
.qf .qf-country{grid-column:span 6}
.qf .qf-postal{grid-column:span 3}
.qf .qf-units{grid-column:span 2}
.qf .qf-weight{grid-column:span 2}
.qf .qf-size{grid-column:span 5}
.qf .btn{grid-column:span 3}
/* Signed in: each country shares its half with its own postcode, which is also
   why they sit next to each other in the markup — tabbing goes origin → its
   code → destination → its code instead of jumping across the row. */
html[data-signed-in] .qf .qf-country{grid-column:span 3}
.qf .f span{display:block;font-family:var(--mono);font-size:10px;letter-spacing:.16em;
  text-transform:uppercase;color:var(--dim);margin-bottom:7px}
.quote .f{display:block}
.quote .in{width:100%;box-sizing:border-box;font:inherit;font-size:15px;color:var(--ink);
  background:var(--inset);border:1px solid var(--line);border-radius:var(--r);padding:14px 15px;
  -webkit-appearance:none;appearance:none}
.quote select.in{
  /* The native arrow goes with -webkit-appearance:none, so draw one. A CSS
     gradient and not an SVG: Tor's Safest profile refuses inline SVG and the
     control would look like it had nothing to open. */
  padding-right:34px;
  background-image:linear-gradient(45deg,transparent 50%,var(--dim) 50%),
                   linear-gradient(135deg,var(--dim) 50%,transparent 50%);
  background-position:calc(100% - 19px) calc(50% + 1px),calc(100% - 14px) calc(50% + 1px);
  background-size:5px 5px,5px 5px;background-repeat:no-repeat}
.quote .in:focus{outline:0;border-color:var(--ac);box-shadow:0 0 0 3px var(--ac-glow)}
.dim3{display:flex;align-items:center;gap:6px}
.dim3 .in{flex:1;min-width:0;text-align:center;padding-left:6px;padding-right:6px}
/* No steppers on these three. Three number inputs sharing one column already run
   to ~79px each, and Chromium's spinner eats a fifth of that before a digit is
   drawn — on a field nobody nudges one centimetre at a time. Weight keeps its
   own: 0.1 kg steps are exactly what that arrow is for. */
.dim3 .in::-webkit-outer-spin-button,
.dim3 .in::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}
.dim3 .in{-moz-appearance:textfield;appearance:textfield}
.dim3 em{font-style:normal;color:var(--dim);font-size:13px;flex:none}
.quote button.btn{border:0;cursor:pointer}
.quote button.btn[disabled]{opacity:.6;cursor:progress}
.quote .fine{font-family:var(--mono);font-size:11px;color:var(--dim);margin-top:14px}

/* ── the postcode finder ──
   The postcode boxes take a CITY as well as a code — "madri" finds 28001 Madrid
   — because that is how somebody who is not a postal clerk knows where they are
   sending from. This is the list that drops out of them.

   ⚠ Every property is written out on purpose. `.qf .f span` styles EVERY span
   inside a field — 10px uppercase mono in --dim with a bottom margin — and it is
   two classes deep, so anything left unsaid here inherits it and the list reads
   as a column of tiny grey captions instead of a menu. */
.quote .f{position:relative}
.qf .f .sugg{position:absolute;left:0;right:0;top:100%;z-index:60;display:block;margin:5px 0 0;
  max-height:262px;overflow-y:auto;background:var(--card);border:1px solid var(--line);border-radius:var(--r);box-shadow:0 20px 44px rgba(0,0,0,.38);
  font-family:inherit;font-size:14px;letter-spacing:normal;text-transform:none;color:var(--ink)}
.qf .f .sugg[hidden]{display:none}
.qf .f .sugg .so{display:block;margin:0;padding:10px 13px;cursor:pointer;color:var(--ink);
  font-family:inherit;font-size:14px;letter-spacing:normal;text-transform:none;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.qf .f .sugg .so b{font-family:var(--mono);font-size:12.5px;color:inherit}
.qf .f .sugg .so:hover{background:var(--ac-soft)}
.qf .f .sugg .so.on{background:var(--ac);color:var(--on-ac)}
.qf .f .sugg .none{display:block;margin:0;padding:12px 13px;color:var(--dim);
  font-family:inherit;font-size:13px;letter-spacing:normal;text-transform:none}
/* What was picked, echoed under the box. The field itself keeps the POSTCODE,
   because that is what gets submitted; this line names the locality it stands
   for, so nobody has to trust that 28001 was the Madrid they meant. */
.qf .f .pick{display:block;margin:6px 0 0;font-family:var(--mono);font-size:10.5px;
  letter-spacing:.04em;text-transform:none;color:var(--dim);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.qf .f .pick:empty{display:none}


/* ── the answer ──
   Rows, not a table: on a phone a table of four columns either scrolls sideways
   or shrinks the price to nothing. Same shape as the rate list inside the app,
   so the page has already shown you what buying looks like. */
.qres{margin-top:18px}
.qres:empty{display:none}
.qr-h{display:flex;align-items:baseline;justify-content:space-between;gap:14px;flex-wrap:wrap;
  padding-bottom:10px;border-bottom:1px solid var(--line);margin-bottom:12px}
.qr-h b{font-family:var(--disp);font-weight:var(--disp-w);letter-spacing:var(--disp-ls);font-size:19px}
.qr-h span{font-family:var(--mono);font-size:10px;letter-spacing:.16em;text-transform:uppercase;color:var(--dim)}
.qr-row{display:grid;grid-template-columns:52px minmax(0,1fr) auto;align-items:center;gap:14px;
  padding:12px 16px;border:1px solid var(--line);border-radius:var(--r);background:var(--card);margin-bottom:8px}
/* Decoration, and only decoration: the carrier is written out right next to it.
   It used to be one OR the other — artwork when we held some, the bare name when
   we did not — so reading the answer meant recognising a logo, and every row
   started at a different x because /img/carriers/*.png are different shapes and
   some carry their own white box. Now the artwork sits centred in a column of
   its own and the text begins at the same place on every row.

   A background and never an <img>: this origin serves `script-src-attr 'none'`,
   so the onerror fallback the rest of the fork relies on is dead code here and a
   missing PNG would leave a broken-image icon inside a price row. Nothing is
   lost when there is no artwork — the column simply stays empty. */
.qr-row .clg{width:52px;height:30px;background-repeat:no-repeat;
  background-position:center;background-size:contain}
.qr-row .cinfo{min-width:0}
.qr-row .cname{display:flex;align-items:center;gap:9px;flex-wrap:wrap;font-weight:700;font-size:15px}
.qr-row .svc{display:block;font-family:var(--mono);font-size:11.5px;color:var(--dim);margin-top:4px;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.qr-row .pill{font-family:var(--mono);font-size:9.5px;letter-spacing:.12em;text-transform:uppercase;
  color:var(--dim);border:1px solid var(--line);border-radius:100px;padding:4px 9px;flex:none}
.qr-row .amt{font-family:var(--disp);font-weight:var(--disp-w);font-size:21px;flex:none}
.qr-note{font-family:var(--mono);font-size:11px;color:var(--dim);line-height:1.65;margin-top:12px}
.qr-msg{border:1px solid var(--line);background:var(--card);border-radius:var(--r);
  padding:22px;text-align:center;color:var(--dim);font-size:14.5px;line-height:1.6}

/* ── the search window ──
   A live search polls every carrier and legitimately takes half a minute. The
   same floating card the app shows for the same wait, in this store's skin —
   without it the button just sat there disabled and the skeleton rows, below the
   fold on most screens, were the only sign anything was happening.

   Hidden by visibility and not by [hidden], so it can fade; inert either way,
   which is what a visitor with no scripts gets — and correctly so, because that
   path is a plain page POST with the browser's own progress bar. */
.search-loader{position:fixed;inset:0;z-index:70;display:flex;align-items:center;justify-content:center;
  padding:24px;opacity:0;visibility:hidden;pointer-events:none;
  transition:opacity .28s ease,visibility .28s ease}
.search-loader.open{opacity:1;visibility:visible;pointer-events:auto}
.sl-bg{position:absolute;inset:0;background:rgba(3,4,7,.72);
  -webkit-backdrop-filter:blur(3px);backdrop-filter:blur(3px)}
.sl-card{position:relative;width:min(100%,380px);padding:30px 28px 24px;text-align:center;
  background:var(--card);border:1px solid var(--line);border-radius:calc(var(--r) + 6px);box-shadow:0 30px 80px rgba(0,0,0,.5);
  transform:translateY(8px) scale(.985);transition:transform .28s cubic-bezier(.2,.8,.2,1)}
.search-loader.open .sl-card{transform:none}
.sl-icon{position:relative;width:56px;height:56px;margin:0 auto 16px;
  display:flex;align-items:center;justify-content:center}
.sl-logo{width:34px;height:34px;object-fit:contain;display:block;animation:sl-bob 1.6s ease-in-out infinite}
.sl-ring{position:absolute;inset:0;border-radius:50%;border:2px solid var(--line);
  border-top-color:var(--ac);animation:sl-spin .9s linear infinite}
.sl-title{font-family:var(--disp);font-weight:var(--disp-w);letter-spacing:var(--disp-ls);font-size:21px;margin-bottom:6px}
/* min-height, because the lines rotate and they are not all one line long: without
   it the card grows and shrinks under the reader every two seconds. */
.sl-msg{font-family:var(--mono);font-size:12.5px;line-height:1.5;color:var(--dim);
  min-height:2.6em;margin-bottom:18px;transition:opacity .22s ease}
.sl-track{height:6px;border-radius:100px;overflow:hidden;background:var(--inset);margin-bottom:9px}
.sl-bar{height:100%;width:0;border-radius:100px;background:var(--ac);transition:width .18s ease-out}
.sl-pct{font-family:var(--mono);font-size:11px;letter-spacing:.05em;color:var(--dim)}
@keyframes sl-bob{0%,100%{transform:translateY(0)}50%{transform:translateY(-4px)}}
@keyframes sl-spin{to{transform:rotate(360deg)}}
@media (prefers-reduced-motion:reduce){
  .sl-logo,.sl-ring{animation:none}
  .sl-card,.sl-bar,.search-loader{transition:none}
  .sl-card{transform:none}
}
/* Six skeleton rows in the shape of the answer that is coming, instead of a
   line of text over an empty panel: it says how long the list will be, and the
   results land into space already held for them rather than shoving the page
   down. CSS-driven, so a fetch that throws cannot leave it running for ever. */
.qsk-row{display:grid;grid-template-columns:52px minmax(0,1fr) auto;align-items:center;gap:14px;padding:13px 16px;border:1px solid var(--line);
  border-radius:var(--r);background:var(--card);margin-bottom:8px}
.qsk-b{border-radius:4px;background:linear-gradient(90deg,var(--line) 0%,var(--card) 40%,var(--line) 80%);
  background-size:300% 100%;animation:qsk 1.25s linear infinite}
@keyframes qsk{0%{background-position:120% 0}100%{background-position:-120% 0}}
.qsk-logo{width:52px;height:26px}
.qsk-txt{display:block;min-width:0}
.qsk-pill{display:block;width:96px;height:14px;margin-bottom:7px}
.qsk-svc{display:block;width:min(230px,72%);height:12px}
.qsk-amt{justify-self:end;width:74px;height:23px}
@media (prefers-reduced-motion:reduce){.qsk-b{animation:none}}

/* ── carriers ── */
.carriers{margin-top:56px;border-top:1px solid var(--line);border-bottom:1px solid var(--line);padding:26px 0}
.carriers .t{display:block;font-family:var(--mono);font-size:10px;
  letter-spacing:.2em;text-transform:uppercase;color:var(--dim);margin-bottom:20px}
/* TWO deliberate rows of six, not a ragged wrap. Eleven logos on one line forced
   every mark down to 25px tall, and a near-square one pays that worst — at a
   fixed height, width is all it gets. The grid keeps the split at 6+5 instead of
   wherever flex-wrap happens to break. */
.clrow{display:grid;grid-template-columns:repeat(6,minmax(0,1fr));gap:26px;align-items:center;justify-items:center}
/* Artwork from scripts/build-landing-logos.js: the official marks, trimmed of
   empty canvas so one uniform box gives them all the same visual weight. On a
   dark page only the WHITE variant is ever shown; the -c files ride along
   unused so a shop that ever ships a light skin has them. */
.cl{display:block}
.cl img{height:24px;width:auto;max-width:96px;object-fit:contain;display:block}
.clrow .cl img{height:40px;max-width:150px}
.cl .lt{display:none}

/* ── promises ── */
.promises{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));border-bottom:1px solid var(--line)}
.promises div{padding:26px 26px 26px 0;border-right:1px solid var(--line)}
.promises div:last-child{border-right:0;padding-right:0}
.promises b{display:block;font-family:var(--disp);font-weight:var(--disp-w);font-size:19px;
  letter-spacing:var(--disp-ls);margin-bottom:7px}
.promises p{margin:0;font-size:14.5px;color:var(--dim);line-height:1.55}

/* ── sections ── */
section{padding:58px 0}
.shd{display:flex;align-items:baseline;gap:18px;margin-bottom:34px}
.shd h2{font-size:clamp(26px,3.4vw,38px)}
.shd .n{font-family:var(--mono);font-size:11px;letter-spacing:.22em;color:var(--ac)}

.prices{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:22px}
.pc{border:1px solid var(--line);background:var(--card);border-radius:calc(var(--r) + 4px);padding:24px}
.pc.hot{border-color:var(--ac);box-shadow:0 0 0 1px var(--ac-glow),0 18px 44px var(--ac-glow)}
.pc .r{font-family:var(--mono);font-size:11px;letter-spacing:.14em;text-transform:uppercase;color:var(--dim)}
.pc .w{font-size:15px;color:var(--dim);margin-top:4px}
.pc .p{font-family:var(--disp);font-weight:var(--disp-w);letter-spacing:var(--disp-ls);
  font-size:42px;line-height:1;margin-top:16px}
.pc .p em{font-style:normal;color:var(--ac)}
.pc .k{font-family:var(--mono);font-size:11px;color:var(--dim);margin-top:10px}
.prices-note{font-family:var(--mono);font-size:11.5px;color:var(--dim);margin-top:20px}

.steps{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:34px}
.st .num{font-family:var(--disp);font-weight:var(--disp-w);font-size:54px;line-height:.9;color:var(--ac)}
.st b{display:block;font-family:var(--disp);font-weight:var(--disp-w);font-size:20px;
  letter-spacing:var(--disp-ls);margin:16px 0 8px;padding-top:16px;border-top:1px solid var(--line)}
.st p{margin:0;color:var(--dim);font-size:15px;line-height:1.6}

.why{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:22px}
.wc{border:1px solid var(--line);background:var(--card);border-radius:calc(var(--r) + 4px);
  padding:26px;position:relative;overflow:hidden}
.wc::before{content:'';position:absolute;left:0;top:0;width:44px;height:3px;background:var(--ac)}
.wc b{display:block;font-family:var(--disp);font-weight:var(--disp-w);font-size:19px;
  letter-spacing:var(--disp-ls);margin:8px 0 9px}
.wc p{margin:0;color:var(--dim);font-size:15px;line-height:1.6}

.faq{display:grid;grid-template-columns:1fr 1fr;gap:0 44px}
.fq{padding:20px 0;border-top:1px solid var(--line)}
.fq b{display:block;font-size:16.5px;font-weight:700;margin-bottom:6px}
.fq p{margin:0;color:var(--dim);font-size:15px;line-height:1.6}

.end{border-top:1px solid var(--line);padding:70px 0;background:var(--shade)}
.end h2{font-size:clamp(28px,4.2vw,46px);max-width:20ch}
.end h2 em{font-style:normal;color:var(--ac)}
.end .row{display:flex;align-items:center;gap:18px;margin-top:28px;flex-wrap:wrap}
.end .fine{font-family:var(--mono);font-size:11.5px;color:var(--dim)}

.foot{border-top:1px solid var(--line);padding:34px 0 44px}
.foot .in{display:flex;gap:34px;flex-wrap:wrap;align-items:flex-start}
.foot .lg b{font-size:20px}
.foot .cols{margin-left:auto;display:flex;gap:54px;flex-wrap:wrap}
.foot .col b{display:block;font-family:var(--mono);font-size:10px;letter-spacing:.2em;
  text-transform:uppercase;color:var(--dim);margin-bottom:10px;font-weight:400}
.foot .col a{display:block;text-decoration:none;font-size:14.5px;margin-bottom:6px;color:var(--dim)}
.foot .col a:hover{color:var(--ac)}
/* Which coins we take. A wrapping grid, not a flex row: the list is served from
   the operator's live toggles, so it can be six chips or ten and the column must
   not decide the layout. The superscript is how many networks a stablecoin runs
   on — sending USDT on the wrong chain is money that never lands, so the number
   earns its place even at this size. */
.foot .col.pay{max-width:230px}
.foot .coins{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:9px}
.foot .coin{font-family:var(--mono);font-size:11.5px;letter-spacing:.06em;
  padding:4px 8px;border:1px solid var(--line);border-radius:100px;color:var(--dim);white-space:nowrap}
.foot .coin i{font-style:normal;font-size:8.5px;vertical-align:super;margin-left:3px;opacity:.75}
.foot .coins-note{display:block;font-size:11.5px;line-height:1.5;color:var(--dim)}
.foot .legal{width:100%;margin-top:26px;padding-top:18px;border-top:1px solid var(--line);
  font-family:var(--mono);font-size:11px;color:var(--dim);display:flex;gap:22px;flex-wrap:wrap}
.foot .legal .r{margin-left:auto}

/* ── log out ──
   Always beside "my account", on every page, so leaving never needs a hunt
   through a settings screen. The door is drawn in CSS: NOT an SVG (Tor's
   "Safest" refuses inline SVG and the icon would vanish with no error and no
   gap) and not an emoji, which is a different picture on every platform. */
.exitbtn{background:transparent;border:1px solid var(--line);border-radius:var(--r);cursor:pointer;
  padding:11px 12px;line-height:0;color:var(--dim)}
.exitbtn:hover{border-color:var(--ac);color:var(--ink)}
.exitbtn i{display:inline-block;position:relative;width:15px;height:16px;
  border:2px solid currentColor;border-right:0}
.exitbtn i::before{content:"";position:absolute;top:50%;right:-9px;width:9px;height:2px;
  background:currentColor;transform:translateY(-1px)}
.exitbtn i::after{content:"";position:absolute;top:50%;right:-9px;width:6px;height:6px;
  border:2px solid currentColor;border-left:0;border-bottom:0;transform:translateY(-4px) rotate(45deg)}

/* ── the sign-in window ───────────────────────────────────────────────────
   Signing in happens ON this page. The customer read the price, decided, and
   sending them to a different URL to type two words is a page load and a change
   of scene in the middle of the one moment they had made up their mind.

   Everything here is scoped under .authov, so it cannot reach the page behind. */
.authov{position:fixed;inset:0;z-index:60;display:flex;align-items:center;justify-content:center;padding:24px}
.authov[hidden]{display:none}
.authov-bg{position:absolute;inset:0;background:rgba(3,4,7,.72);
  -webkit-backdrop-filter:blur(3px);backdrop-filter:blur(3px)}
.authov-win{position:relative;width:min(100%,430px);max-height:calc(100dvh - 48px);
  overflow-y:auto;background:var(--card);border:1px solid var(--line);border-radius:calc(var(--r) + 6px);
  box-shadow:0 30px 80px rgba(0,0,0,.5);padding:30px 28px 26px}
.authov-win h2{font-size:26px;margin:6px 0 20px;color:var(--ink)}
/* The close control is a corner, not a button: it must be findable and must not
   compete with the thing the window is asking for. */
.authov-x{position:absolute;top:8px;right:10px;background:none;border:0;cursor:pointer;
  color:var(--dim);font-size:26px;line-height:1;padding:6px 9px;font-family:inherit}
.authov-x:hover{color:var(--ink)}
.authov-seg{display:flex;border:1px solid var(--line);border-radius:var(--r);overflow:hidden;margin-bottom:18px}
.authov-seg button{flex:1;background:transparent;border:0;cursor:pointer;font-family:var(--body);
  font-weight:700;font-size:14px;color:var(--dim);padding:12px 8px}
.authov-seg button + button{border-left:1px solid var(--line)}
.authov-seg button.on{background:var(--ac);color:var(--on-ac)}
.authov label{display:block;font-family:var(--mono);font-size:10px;letter-spacing:.18em;
  text-transform:uppercase;color:var(--dim);margin:14px 0 6px}
.authov input{width:100%;box-sizing:border-box;background:var(--inset);color:var(--ink);
  border:1px solid var(--line);border-radius:var(--r);padding:13px 14px;font:inherit;font-size:15px}
.authov input:focus{outline:0;border-color:var(--ac);box-shadow:0 0 0 3px var(--ac-glow)}
.authov-caprow{display:flex;align-items:center;gap:10px;margin-bottom:8px}
.authov-caprow img{height:48px;background:var(--inset);border:1px solid var(--line);border-radius:8px}
.authov-refresh{background:transparent;border:1px solid var(--line);border-radius:var(--r);cursor:pointer;
  color:var(--dim);font-size:17px;line-height:1;padding:13px 15px;font-family:inherit}
.authov-refresh:hover{border-color:var(--ac);color:var(--ink)}
.authov-go{width:100%;margin-top:20px;text-align:center}
.authov-m{margin:12px 0 0;font-size:13.5px;line-height:1.5;min-height:0}
.authov-m.err{color:#fca5a5}
.authov-m.ok{color:#6ee7a8}
.authov-fine{margin:14px 0 0;font-size:11.5px;color:var(--dim);text-align:center}
/* Only the sign-up tab is free to sign up. */
.authov[data-mode="login"] .authov-fine{display:none}
/* The account rules, stated BEFORE anyone types. Sign-up only — on the sign-in
   tab they describe a password the customer already has, which is clutter over
   the field they need. CSS picks the tab, so nothing here needs a script. */
.authov-hint{margin:5px 0 0;font-family:var(--mono);font-size:10.5px;letter-spacing:.04em;
  color:var(--dim);line-height:1.5}
.authov[data-mode="login"] .authov-hint{display:none}
/* The page behind must not scroll while the window is open — on a phone the
   window is nearly the whole screen and a stray swipe scrolls the landing
   underneath it instead of the form. */
html.authov-open,html.authov-open body{overflow:hidden}

/* ── short windows ──
   Measured on Agora, not guessed: sign-up is 639px of content (sign-in is 463),
   so on a browser window under ~700px tall the sign-up tab scrolled INSIDE the
   window. A form you have to scroll to find the button of is a form people
   abandon. Compressed by HEIGHT rather than trimmed everywhere: nothing is
   removed, only the air between the fields closes up. */
@media (max-height:719px){
  .authov-win h2{font-size:22px;margin:4px 0 13px}
  .authov-seg{margin-bottom:12px}
  .authov-seg button{padding:9px 8px}
  .authov label{margin:10px 0 5px}
  .authov input{padding:10px 13px;font-size:14.5px}
  .authov-caprow{margin-bottom:6px}
  .authov-caprow img{height:40px}
  .authov-refresh{padding:10px 14px}
  .authov-go{margin-top:14px;padding:13px 24px}
  .authov-m{margin-top:9px}
  .authov-fine{margin-top:10px}
}
@media (min-width:560px) and (max-height:719px){
  .authov{padding:14px}
  .authov-win{padding:20px 26px 18px;max-height:calc(100dvh - 28px)}
}
@media (max-width:559px){
  .authov{padding:0;align-items:stretch}
  .authov-win{width:100%;max-height:100dvh;border:0;border-radius:0;box-shadow:none;padding:26px 22px 30px}
}

/* ── the gap between the phone and the desktop ─────────────────────────────
   Between 761px and ~1059px this page used to run off the right edge on Agora:
   243px of overflow at 768, 191 at 820, 111 at 900. Two grids could not shrink,
   and neither of them because of the grid — `.prices` floored at its content's
   min-content (a price is one unbreakable word), and `.clrow` floored at the
   widest logo's max-width. Fewer columns, and artwork allowed to give way. */
@media (min-width:761px) and (max-width:1059px){
  .prices{grid-template-columns:repeat(2,minmax(0,1fr))}
  .pc .p{font-size:36px}
  .clrow{grid-template-columns:repeat(4,minmax(0,1fr))}
  .clrow .cl img{max-width:100%}
}

/* ── mobile ── */
@media (max-width:760px){
  .wrap{padding:0 20px}
  .nav .in{height:62px;gap:14px}
  .nav .links,.nav .enter{display:none}
  .lg .mk{height:26px}
  .lg b{font-size:20px}
  .btn{font-size:14px;padding:13px 20px}
  .hero{padding:36px 0 0;grid-template-columns:1fr;gap:30px}
  .hero h1{font-size:36px}
  .hero .sub{font-size:16.5px;margin-top:18px}
  .hcard{padding:16px 18px}
  .hr.pick{padding:11px 12px;margin:0 -12px}
  /* The logo box shrinks with the artwork it holds (20px tall here, so the
     widest mark is 48 and not 58). Carrying the desktop width down to a 375px
     screen takes ten pixels off the service name, which is the column that can
     least afford them — it is already the one that wraps. */
  .hr .cl{width:48px}
  .hr .cl img{max-width:48px}
  .hr{gap:11px}
  .quote{padding:18px;margin-top:32px}
  .qf{grid-template-columns:1fr;gap:12px}
  /* One column: the spans above are cancelled one by one (same specificity and
     further down the sheet). */
  /* One column: the spans above are cancelled one by one (same specificity
     and further down the sheet). The signed-in rule needs its own line
     because it weighs more. */
  .qf .qf-country,.qf .qf-postal,.qf .qf-units,.qf .qf-weight,.qf .qf-size,.qf .btn{grid-column:auto}
  html[data-signed-in] .qf .qf-country{grid-column:auto}
  .carriers{margin-top:38px;padding:20px 0}
  /* Three 96px-capped logos plus two gaps need 320px, and a 320px phone only
     offers 280 — which is where horizontal scroll on this page comes from.
     minmax(0,1fr) lets the track narrow and max-width:100% lets the artwork
     follow it; object-fit already keeps it from distorting. */
  .clrow{grid-template-columns:repeat(3,minmax(0,1fr));gap:20px 16px}
  .clrow .cl img{height:30px;max-width:100%}
  .cl img{height:20px;max-width:62px}
  .promises{grid-template-columns:1fr}
  .promises div{padding:18px 0;border-right:0;border-bottom:1px solid var(--line)}
  .promises div:last-child{border-bottom:0}
  section{padding:48px 0}
  .shd{margin-bottom:24px;flex-wrap:wrap;gap:8px}
  .prices,.steps,.why{grid-template-columns:1fr;gap:16px}
  .steps{gap:26px}
  .pc .p{font-size:36px}
  .faq{grid-template-columns:1fr;gap:0}
  .end{padding:44px 0}
  .foot .cols{margin-left:0;gap:34px}
  .foot .legal .r{margin-left:0}
  .qr-row{grid-template-columns:40px minmax(0,1fr) auto;gap:11px;padding:11px 12px}
  .qr-row .clg{width:40px;height:26px}
  .sl-card{padding:26px 22px 22px}
  .qr-row .amt{font-size:19px}
}

/* ── signed-in vs signed-out calls to action ──────────────────────────────
   Both states are in the markup and this picks one, so the right nav is on the
   first frame. Default is SIGNED OUT, which is also what a visitor with no
   JavaScript gets: the honest fallback, since "log in" works for everybody
   while "my account" would be a lie for most.

   ⚠ The selectors are spelled out per container ON PURPOSE. `.sg-in{display:none}`
   alone loses to `.foot .col a{display:block}` — equal specificity, and the
   footer rule comes later — so the footer quietly shows BOTH versions at once.
   Measured on Agora, not guessed. Keep this block LAST in the sheet. */
.sg-in,
.nav .right a.sg-in,
.foot .col a.sg-in,
.end .btn.sg-in{display:none}

html[data-signed-in] .sg-out,
html[data-signed-in] .nav .right a.sg-out,
html[data-signed-in] .foot .col a.sg-out,
html[data-signed-in] .end .btn.sg-out,
html[data-signed-in] .end .fine.sg-out{display:none}

html[data-signed-in] .nav .right a.sg-in,
html[data-signed-in] .end .btn.sg-in{display:inline-block}
html[data-signed-in] .foot .col a.sg-in{display:block}
/* The log-out door is a <button>, and every rule above that brings an element
   back is written for an <a>. Without this line `.sg-in{display:none}` is the
   ONLY thing that ever matches it and the door is invisible in both states —
   which looks exactly like the feature simply not being there. */
html[data-signed-in] .nav .right button.sg-in{display:inline-flex}

/* The line under the form says something different to somebody who is signed
   in: a stranger is told to sign in for an exact price, a customer is told what
   their two postcodes buy them. Both states are in the markup, same as the nav.
   Only the "show" rule is needed — `html[data-signed-in] .sg-out` above already
   hides the other half, and nothing else in the sheet matches these spans. */
html[data-signed-in] .quote .fine .sg-in{display:inline}


/* The postal-code fields exist for everyone in the markup and are SHOWN only to
   a signed-in customer - they are what turns this form from a cached estimate
   into a real, buyable quote. Hidden by default so a stranger is never asked for
   something their answer does not use.

   ⚠ Written as `html:not(...)` and not as a bare `.authonly{display:none}`: the
   `.quote .f` rule that lays those fields out has the SAME specificity and comes
   later in the sheet, so it would win and the postcodes would be shown to
   everybody. Measured on Agora, not guessed. */
html:not([data-signed-in]) .authonly{display:none}
