/* VPN.free Premium. The look is described at PREMIUMLOOK-1 below the fonts. */

/* PREMIUMSTYLE-1 (2026-10-04): Roboto is SELF-HOSTED, copied byte-for-byte with its
 * @font-face rules from vpn.free (public/fonts, FONTS-1). This line used to be a
 * fonts.googleapis.com @import, which sent every buyer's IP address to Google on a
 * page that promises "nothing in our database that could point back at you", and
 * which vpn.free itself removed on 2026-09-26 for exactly that reason. */
@font-face {
  font-family: "Roboto";
  font-style: normal;
  font-weight: 300;
  font-stretch: 100%;
  font-display: swap;
  src: url("/fonts/roboto-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Roboto";
  font-style: normal;
  font-weight: 300;
  font-stretch: 100%;
  font-display: swap;
  src: url("/fonts/roboto-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Roboto";
  font-style: normal;
  font-weight: 400;
  font-stretch: 100%;
  font-display: swap;
  src: url("/fonts/roboto-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Roboto";
  font-style: normal;
  font-weight: 400;
  font-stretch: 100%;
  font-display: swap;
  src: url("/fonts/roboto-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Roboto";
  font-style: normal;
  font-weight: 500;
  font-stretch: 100%;
  font-display: swap;
  src: url("/fonts/roboto-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Roboto";
  font-style: normal;
  font-weight: 500;
  font-stretch: 100%;
  font-display: swap;
  src: url("/fonts/roboto-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* PREMIUMSTYLE-1 review: 700 declared on the same variable files. Without it every
 * heading and button (700) fell back to the 500 face and was synthesised bold. */
@font-face {
  font-family: "Roboto";
  font-style: normal;
  font-weight: 700;
  font-stretch: 100%;
  font-display: swap;
  src: url("/fonts/roboto-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Roboto";
  font-style: normal;
  font-weight: 700;
  font-stretch: 100%;
  font-display: swap;
  src: url("/fonts/roboto-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Roboto";
  font-style: italic;
  font-weight: 300;
  font-stretch: 100%;
  font-display: swap;
  src: url("/fonts/roboto-latin-ext-italic.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Roboto";
  font-style: italic;
  font-weight: 300;
  font-stretch: 100%;
  font-display: swap;
  src: url("/fonts/roboto-latin-italic.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Roboto";
  font-style: italic;
  font-weight: 400;
  font-stretch: 100%;
  font-display: swap;
  src: url("/fonts/roboto-latin-ext-italic.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Roboto";
  font-style: italic;
  font-weight: 400;
  font-stretch: 100%;
  font-display: swap;
  src: url("/fonts/roboto-latin-italic.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* ── PREMIUMLOOK-1 (2026-10-16) ──────────────────────────────────────────
 *
 * Owner on the previous look: "so cheap". Measured against the page, the cheap
 * read came from three habits, not from the palette:
 *
 *   Boxes inside boxes. Every step sat in a big rounded panel, which held
 *   rounded cards, which held rounded rows: four nested borders around a price.
 *   The page itself is the surface now; a box appears only where one thing has
 *   to be read as one thing (a plan, the free month, a code).
 *
 *   Soft everything. 14 to 22px radii on every element, gradient buttons, an
 *   orange pill for "Back". Access here is a certificate, so the shapes follow
 *   a document: 6px controls, 10px surfaces, hairlines, and a dashed rule where
 *   something is meant to be kept.
 *
 *   Shouting small print. Hints and labels were uppercase with letter spacing.
 *   They are sentence case now and the hierarchy is carried by size and weight.
 *
 * The palette is still vpn.free's (navy, #1e88e5, amber), so a visitor arriving
 * from the free site lands somewhere that is visibly the same product. Every
 * text colour below was computed against its real background, not eyeballed
 * (the numbers are next to the tokens).
 *
 * Dark only. The shell has no light mode: a prefers-color-scheme:light block
 * was removed from it because honouring it flashed a white page inside a dark
 * frame. Inputs stay at 16px, the size under which iOS zooms on focus.
 */

:root {
  --bg: #0a101d;
  --surface: #0f1829;        /* one level up: plans, the free month, panels */
  --surface-2: #142036;      /* hover, and the step you are on */
  --line: rgba(255, 255, 255, .09);
  --line-strong: rgba(255, 255, 255, .17);

  --text: #e8eef5;           /* 16.3:1 on --bg */
  --muted: #a3b1c2;          /*  8.7:1 on --bg, 7.5:1 on --surface-2 */
  --faint: #8494a8;          /*  6.1:1 on --bg, 5.3:1 on --surface-2 */

  --blue: #1e88e5;
  --blue-text: #82c1f7;      /*  9.9:1 on --bg */
  --amber: #ffb02e;          /* the one "do this" colour; ink on it 10.1:1 */
  --amber-ink: #1d1200;
  --amber-text: #ffc561;     /* 12.1:1 on --bg */
  --orange: #ff8f00;

  --good: #45c7a6;
  --good-text: #8fe0c8;
  --bad: #f19189;
  --warn: #ffc046;

  /* Kept so anything still reading the old names gets a sane value. */
  --border: var(--line-strong);
  --white-30: var(--faint);
  --white-10: var(--line);

  --r-sm: 6px;               /* controls, chips, inputs */
  --r-md: 10px;              /* surfaces */
  --r-lg: 10px;
  --r-pill: 999px;           /* kept for anything outside this sheet that still asks for it */

  --mono: ui-monospace, "SFMono-Regular", Menlo, Consolas, "Roboto Mono", monospace;
  --ease-out: cubic-bezier(.22, .8, .36, 1);
}

* { box-sizing: border-box; }

html {
  color-scheme: dark;
  -webkit-tap-highlight-color: rgba(30, 136, 229, .22);
  -webkit-text-size-adjust: 100%;
}

/* One global reduced-motion reset, so no component has to remember. 0.001ms
 * rather than 0: animationend still fires, so nothing that waits on it hangs. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
}

body {
  margin: 0;
  min-height: 100vh;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  font-family: "Roboto", Arial, Helvetica, sans-serif;
  font-size: 16px;
  line-height: 1.55;
  color: var(--text);
  background: var(--bg);
  padding:
    0
    max(16px, env(safe-area-inset-right))
    max(24px, env(safe-area-inset-bottom))
    max(16px, env(safe-area-inset-left));
  -webkit-font-smoothing: antialiased;
}

.fx { display: none; }

.skip {
  position: absolute; left: -9999px;
  background: var(--blue); color: #061426; padding: 10px 14px; border-radius: var(--r-sm);
}
.skip:focus { left: 16px; top: 16px; z-index: 10; }

a { color: var(--blue-text); text-underline-offset: 3px; text-decoration-thickness: 1px; }
a:hover { color: #b6dbfb; }

/* ── the header ───────────────────────────────────────────────────────── */

/* A hairline under the brand, full width, like the top of a letterhead. The
 * header is not sticky: the funnel is short and every step moves focus to its
 * own heading, so a pinned bar would only take a phone's height away. */
.head {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  width: min(100%, 640px); margin: 0 auto;
  padding: max(14px, env(safe-area-inset-top)) 0 14px;
  border-bottom: 1px solid var(--line);
}
.brand {
  display: flex; align-items: center; gap: 10px; min-height: 44px;
  font-size: 17px; font-weight: 700; letter-spacing: -.02em; line-height: 1;
  text-decoration: none; color: var(--text);
}
.brand:focus-visible { outline: 2px solid var(--blue); outline-offset: 4px; border-radius: var(--r-sm); }
/* The tile keeps vpn.free's two-colour mark, because it is the logo. The stops
 * hold blue for most of the tile so it never competes with the amber action. */
.mark-tile {
  flex: none; display: grid; place-items: center;
  width: 32px; height: 32px; border-radius: 8px;
  background: linear-gradient(135deg, var(--blue) 0%, #2b7fd4 48%, var(--orange) 100%);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .2);
}
/* A percentage, never a pixel size: one rule keeps the glyph right at every
 * tile size, and a fixed child in a fluid box is how a white gap gets shipped. */
.mark-tile .mark { width: 72%; height: 72%; display: block; }
/* A hard two-tone stop at the dot: the soft sweep passes through grey-brown. */
.wordmark {
  background: linear-gradient(90deg, var(--blue) 0 46%, var(--orange) 54% 100%);
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent; color: transparent;
}
/* "Premium" set as a word beside the name, separated by a rule, rather than a
 * badge: a lockup reads as the product's name, a badge reads as a sticker. */
.tier {
  font-size: 15px; font-weight: 400; letter-spacing: 0;
  color: var(--amber-text);
  padding-left: 10px; border-left: 1px solid var(--line-strong);
}
.sandbox-flag {
  margin: 0 0 0 auto;
  font-size: 12.5px; font-weight: 500;
  color: var(--amber-text);
  border: 1px dashed rgba(255, 176, 46, .5); border-radius: var(--r-sm); padding: 4px 9px;
}

/* ── layout ───────────────────────────────────────────────────────────── */

main { flex: 1; width: 100%; display: flex; }
.step { width: 100%; display: flex; }
.step[hidden] { display: none; }

/* No panel around the step any more: the page is the surface. */
.col {
  width: min(100%, 640px); margin: 0 auto; align-self: flex-start;
  padding: clamp(28px, 6vw, 48px) 0 8px;
  display: grid; grid-template-columns: minmax(0, 1fr); gap: 20px;
  align-content: start;
}
/* 🪤 A wrapper inside a step (the signed-in / signed-out halves of #login) is
 * ONE grid item of .col, so .col's gap never reaches its children. Every such
 * wrapper is a .stack. */
.stack { display: grid; grid-template-columns: minmax(0, 1fr); gap: 16px; }
.stack[hidden] { display: none; }

/* Steps move focus to their heading for screen readers; the heading is not a
 * control the user tabbed to, so it is focusable and silent. */
[tabindex="-1"]:focus { outline: none; }

h1 {
  font-size: clamp(30px, 8vw, 48px); font-weight: 700; line-height: 1.06;
  letter-spacing: -.035em; margin: 0; text-wrap: balance;
}
h2 {
  font-size: clamp(24px, 6.2vw, 32px); font-weight: 700; line-height: 1.12;
  letter-spacing: -.03em; margin: 0; text-wrap: balance;
}
p { margin: 0; }
.lede { color: var(--muted); font-size: 17px; line-height: 1.6; text-wrap: pretty; }
.hint { font-size: 13.5px; color: var(--faint); text-align: center; }
.label { font-size: 13px; font-weight: 500; color: var(--muted); }
.meta { font-size: 13px; color: var(--faint); font-family: var(--mono); font-variant-numeric: tabular-nums; }
.status { font-size: 14px; color: var(--muted); min-height: 1.4em; }
.status:empty { min-height: 0; }
.status.bad { color: var(--bad); }
.status.good { color: var(--good-text); }
.fine { font-size: 13.5px; color: var(--faint); line-height: 1.55; }
.loading { color: var(--faint); font-size: 14px; }
hr { border: 0; border-top: 1px solid var(--line); margin: 4px 0; width: 100%; }
.row { display: flex; gap: 10px; flex-wrap: wrap; }
.row > * { flex: 1 1 140px; }

/* ── controls ─────────────────────────────────────────────────────────── */

.btn {
  display: flex; align-items: center; justify-content: center; gap: 8px;
  width: 100%; min-height: 52px; padding: 14px 18px;
  border: 1px solid transparent; border-radius: var(--r-sm);
  font: inherit; font-size: 16px; font-weight: 700; letter-spacing: -.005em;
  text-decoration: none; cursor: pointer;
  touch-action: manipulation;
  /* An explicit property list, never `transition: all`. */
  transition: background-color .18s var(--ease-out), border-color .18s var(--ease-out),
              color .18s var(--ease-out), transform .12s var(--ease-out);
}
/* Solid colours, no gradients and no glows. The amber is the page's single
 * "yes, this" and it is loud enough flat. */
.btn.primary { background: var(--amber); color: var(--amber-ink); }
.btn.primary:hover:not(:disabled) { background: #ffbd4f; color: var(--amber-ink); }
.btn.blue { background: var(--blue); color: #061426; }
.btn.blue:hover:not(:disabled) { background: #3d98ea; color: #061426; }
/* Discord's own blurple and mark: a join button people recognise from every
 * other site gets clicked; our blue would read as one more of ours. */
.btn.discord { background: #5865F2; color: #fff; gap: 10px; }
.btn.discord:hover:not(:disabled) { background: #4752C4; color: #fff; }
.btn.discord .discord-logo { width: 22px; height: 22px; flex: none; }
.btn.ghost { background: transparent; color: var(--text); border-color: var(--line-strong); font-weight: 500; }
.btn.ghost:hover:not(:disabled) { background: rgba(255, 255, 255, .05); border-color: rgba(255, 255, 255, .3); color: var(--text); }
/* A bare .btn (Link it, Claim it) is a secondary action on a form. */
.btn:not(.primary):not(.blue):not(.ghost):not(.discord):not(.danger):not(.is-off) {
  background: var(--surface-2); color: var(--text); border-color: var(--line-strong);
}
.btn:active:not(:disabled) { transform: scale(.985); }
/* Disabled reads inert rather than faded: a dimmed amber still says "press". */
.btn:disabled,
.btn.primary:disabled, .btn.blue:disabled {
  background: transparent; color: var(--faint);
  border: 1px dashed var(--line-strong); cursor: not-allowed; transform: none;
}
.btn:focus-visible { outline: 2px solid var(--blue-text); outline-offset: 3px; }

/* "Back" is navigation, not an action, so it is a quiet text control with a
 * chevron. It used to be an orange pill, the loudest thing on every step. */
.back {
  justify-self: start; display: inline-flex; align-items: center; gap: 6px;
  min-height: 44px; margin: -8px 0 -4px -6px; padding: 0 8px;
  background: none; border: 0; border-radius: var(--r-sm);
  color: var(--muted); font: inherit; font-size: 15px; font-weight: 500;
  text-decoration: none; cursor: pointer;
  transition: color .15s var(--ease-out), background-color .15s var(--ease-out);
}
.back:hover { color: var(--text); background: rgba(255, 255, 255, .04); }
/* "Cancel this order" shares the .back markup but is DESTRUCTIVE, so it sits
 * quiet and turns red on hover; Pay stays the loudest thing on the receipt. */
.back.cancel {
  margin: 0; color: var(--faint);
  text-decoration: underline; text-underline-offset: 3px; font-weight: 400; font-size: 14px;
}
.back.cancel:hover { color: var(--bad); background: none; }
.back:focus-visible { outline: 2px solid var(--blue-text); outline-offset: 2px; }

.linklike {
  background: none; border: 0; padding: 0; font: inherit; font-size: inherit;
  color: var(--blue-text); cursor: pointer; text-decoration: underline; text-underline-offset: 3px;
}
.linklike:focus-visible { outline: 2px solid var(--blue-text); outline-offset: 2px; border-radius: 3px; }

.field {
  width: 100%; min-height: 52px;
  background: var(--bg);
  border: 1px solid var(--line-strong); border-radius: var(--r-sm);
  padding: 13px 14px;
  font: inherit; font-size: 16px;   /* the iOS zoom floor */
  color: var(--text);
  transition: border-color .15s var(--ease-out), box-shadow .15s var(--ease-out);
}
.field::placeholder { color: var(--faint); opacity: .85; }
.field:hover { border-color: rgba(255, 255, 255, .28); }
.field:focus { outline: none; border-color: var(--blue); box-shadow: 0 0 0 3px rgba(30, 136, 229, .22); }
.label + .field { margin-top: -8px; }

/* ── surfaces and chips ───────────────────────────────────────────────── */

.card {
  background: var(--surface);
  border: 1px solid var(--line); border-radius: var(--r-md); padding: 18px;
  display: grid; grid-template-columns: minmax(0, 1fr); gap: 12px;
  color: var(--muted); font-size: 15px; line-height: 1.6;
}
.card b { color: var(--text); font-weight: 600; }
/* A flat card is a side note: no surface, a rule on the left. */
.card.flat {
  background: none; border: 0; border-left: 2px solid var(--line-strong);
  border-radius: 0; padding: 2px 0 2px 16px;
  font-size: 14.5px; color: var(--muted);
}

/* Status chips are plain coloured text with a rule mark: the content is the
 * word, not a sticker around it. */
.chip {
  justify-self: start; display: inline-flex; align-items: center; gap: 8px;
  font-size: 14px; font-weight: 600; letter-spacing: 0;
  color: var(--muted);
}
.chip::before { content: ""; width: 18px; height: 2px; border-radius: 1px; background: currentColor; }
.chip.good { color: var(--good-text); }
.chip.warn { color: var(--amber-text); }
.chip.bad  { color: var(--bad); }

/* ── choices: plans, payment methods, devices ─────────────────────────── */

.plans, .methods, .devices { display: grid; grid-template-columns: minmax(0, 1fr); gap: 10px; }

/* A drawn radio at the left, so a choice reads as a choice before it is
 * read as a price. The ring is a pseudo-element on the existing button: no
 * markup change, and the script's aria-checked keeps driving it. */
.choice {
  position: relative;
  display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 4px 12px; align-items: baseline;
  width: 100%; text-align: left; min-height: 64px;
  background: var(--surface);
  border: 1px solid var(--line-strong); border-radius: var(--r-md);
  padding: 16px 18px 16px 50px;
  font: inherit; color: var(--text); cursor: pointer;
  transition: border-color .18s var(--ease-out), background-color .18s var(--ease-out);
}
.choice::before {
  content: ""; position: absolute; left: 18px; top: 19px;
  width: 18px; height: 18px; border-radius: 50%;
  border: 1.5px solid var(--faint); background: var(--bg);
  transition: border-color .18s var(--ease-out), box-shadow .18s var(--ease-out);
}
.choice:hover { background: var(--surface-2); border-color: rgba(255, 255, 255, .28); }
.choice[aria-checked="true"], .choice.sel { border-color: var(--blue); background: rgba(30, 136, 229, .08); }
.choice[aria-checked="true"]::before, .choice.sel::before {
  border-color: var(--blue); background: var(--blue); box-shadow: inset 0 0 0 4px var(--bg);
}
.choice:focus-visible { outline: 2px solid var(--blue-text); outline-offset: 2px; }
.choice .t { font-weight: 700; font-size: 16px; }
.choice .price {
  font-weight: 700; font-size: 18px; letter-spacing: -.01em;
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
.choice .d { grid-column: 1 / -1; font-size: 14px; color: var(--muted); }
.choice .badge {
  justify-self: end; align-self: center;
  font-size: 12.5px; font-weight: 600; white-space: nowrap;
  padding: 2px 0 2px 10px; border-left: 2px solid currentColor; border-radius: 0;
}
.badge.anonymous    { color: var(--good-text); }
.badge.pseudonymous { color: var(--blue-text); }
.badge.identified   { color: var(--amber-text); }
.badge.soon         { color: var(--amber-text); }
.badge.steps        { color: var(--muted); }
.choice:disabled { cursor: default; opacity: .6; }
.choice:disabled:hover { background: var(--surface); border-color: var(--line-strong); }

/* ── the secret ───────────────────────────────────────────────────────── */

/* A code is the thing the buyer keeps, so it is set like a printed serial:
 * mono, spaced, inside a dashed tear line. */
.secret {
  display: block;
  font-family: var(--mono);
  font-size: 15px; line-height: 1.75; letter-spacing: .04em;
  word-break: break-all; color: #fff;
  background: var(--surface);
  border: 1px dashed rgba(130, 193, 247, .5); border-radius: var(--r-sm);
  padding: 16px 18px;
}
.secret.mono-sm { font-size: 14px; }

.check {
  display: grid; grid-template-columns: 22px 1fr; gap: 12px; align-items: start;
  font-size: 15px; color: var(--muted); cursor: pointer; line-height: 1.5;
}
.check input { width: 22px; height: 22px; margin: 0; accent-color: var(--blue); }
.check input:focus-visible { outline: 2px solid var(--blue-text); outline-offset: 2px; }
.check input:checked + span { color: var(--text); }

/* ── steppers ─────────────────────────────────────────────────────────── */

.steps { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: minmax(0, 1fr); gap: 12px; }
.s { display: grid; grid-template-columns: 18px 1fr; gap: 12px; align-items: center; font-size: 15px; color: var(--faint); }
.s em {
  width: 18px; height: 18px; border-radius: 50%;
  border: 1.5px solid var(--line-strong);
  display: grid; place-items: center; font-style: normal; font-size: 10px; line-height: 1;
}
.s.done { color: var(--muted); }
.s.done em { background: var(--blue); border-color: var(--blue); color: #061426; }
.s.done em::before { content: "\2713"; font-weight: 700; }
.s.now { color: var(--text); }
.s.now em { border-color: var(--amber); border-right-color: transparent; animation: spin .8s linear infinite; }
.s.failed em { border-color: var(--bad); background: var(--bad); color: #2c1613; }
.s.failed em::before { content: "\00d7"; font-weight: 700; }
@keyframes spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .s.now em { animation: none; border-right-color: var(--amber); }
}

.bar { height: 2px; border-radius: 1px; background: var(--line); overflow: hidden; }
.bar i { display: block; height: 100%; background: var(--blue); transition: width .5s var(--ease-out); }

/* The certificate fields: label left, value right, a rule between rows. */
.kv { display: grid; grid-template-columns: auto 1fr; gap: 0 16px; margin: 0; font-size: 15px; }
.kv dt, .kv dd { padding: 10px 0; border-top: 1px solid var(--line); }
.kv dt:first-of-type, .kv dd:first-of-type { border-top: 0; padding-top: 0; }
.kv dt { color: var(--faint); }
.kv dd { margin: 0; text-align: right; color: var(--text); font-variant-numeric: tabular-nums; overflow-wrap: anywhere; }

/* ── disclosure ───────────────────────────────────────────────────────── */

.fold { border-top: 1px solid var(--line); }
.fold summary {
  cursor: pointer; list-style: none;
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  min-height: 56px; padding: 8px 0;
  font-size: 16px; font-weight: 500; color: var(--text);
}
.fold summary::-webkit-details-marker { display: none; }
/* A drawn plus that turns into a minus, instead of a "+" glyph after the text. */
.fold summary::after {
  content: ""; flex: none; width: 14px; height: 14px;
  background:
    linear-gradient(currentColor, currentColor) center / 14px 1.5px no-repeat,
    linear-gradient(currentColor, currentColor) center / 1.5px 14px no-repeat;
  color: var(--muted);
  transition: transform .2s var(--ease-out);
}
.fold[open] summary::after { transform: rotate(45deg); }
.fold summary:hover { color: #fff; }
.fold summary:focus-visible { outline: 2px solid var(--blue-text); outline-offset: 2px; border-radius: 4px; }
.fold-body { display: grid; gap: 12px; padding: 0 0 18px; font-size: 15px; color: var(--muted); max-width: 64ch; }

/* ── footer ───────────────────────────────────────────────────────────── */

.foot {
  width: min(100%, 640px); margin: 48px auto 0; padding-top: 16px;
  border-top: 1px solid var(--line);
  display: grid; gap: 10px; font-size: 14px; color: var(--faint);
}
.foot p:first-child { display: flex; flex-wrap: wrap; align-items: center; column-gap: 2px; margin-left: -8px; }
/* Every footer link is a 44px target: they are the only way to the terms and
 * the code recovery on a phone, and thumbs miss 14px text. */
.foot a, .foot .linklike {
  display: inline-flex; align-items: center; min-height: 44px; padding: 0 8px;
  color: var(--muted); text-decoration: none; border-radius: var(--r-sm);
}
.foot a:hover, .foot .linklike:hover { color: var(--text); text-decoration: underline; }
.foot .fine { font-size: 13px; }

@media (min-width: 700px) {
  .col, .head, .foot { width: min(100%, 680px); }
}

/* ── standalone pages: install guide, terms, privacy, contact ─────────── */

/* Documents rather than steps, so wider, in a 68ch measure: what matters for
 * prose is characters per line, and a pixel width drifts away from it. */
.page {
  width: min(100%, 760px); margin: 0 auto; align-self: flex-start;
  padding: clamp(28px, 6vw, 48px) 0 8px;
  display: grid; grid-template-columns: minmax(0, 1fr); gap: 16px;
  align-content: start;
  color: var(--muted);
}
.page h1 { color: var(--text); font-size: clamp(30px, 7vw, 42px); }
.page .lede { margin-bottom: 8px; }
.page .back, .page .back:hover { justify-self: start; text-decoration: none; }
.page h2 {
  font-size: clamp(19px, 4.6vw, 22px); letter-spacing: -.02em; color: var(--text);
  margin-top: 20px; padding-top: 24px; border-top: 1px solid var(--line);
}
.page p, .page li { max-width: 68ch; }
.page strong, .page b { color: var(--text); font-weight: 600; }
.page a { color: var(--blue-text); }
.page a:hover { color: #b6dbfb; }
.page ul { margin: 0; padding-left: 20px; display: grid; gap: 8px; }
.page li::marker { color: var(--faint); }
.page code, .card code {
  font-family: var(--mono);
  font-size: .9em; background: rgba(255, 255, 255, .06);
  border: 1px solid var(--line); border-radius: 4px; padding: 1px 5px;
  overflow-wrap: anywhere;
}

.legal { gap: 12px; }
.legal p + p { margin-top: 2px; }

/* An imprint is left-aligned prose that wraps; the funnel's .kv right-aligns. */
.kv.wide { grid-template-columns: minmax(0, 11.5rem) minmax(0, 1fr); }
.kv.wide dd { text-align: left; font-variant-numeric: normal; }
@media (max-width: 520px) {
  .kv.wide { grid-template-columns: minmax(0, 1fr); }
  .kv.wide dt { padding-bottom: 0; }
  .kv.wide dd { border-top: 0; padding-top: 2px; }
  .kv.wide dt:first-of-type { padding-top: 0; }
}

/* ── the install guide ────────────────────────────────────────────────── */

.ig-host { display: grid; gap: 16px; }
.ig { display: grid; gap: 14px; }
.ig-detected { font-size: 14px; color: var(--faint); min-height: 1.4em; }

/* Buttons rather than a <select>: the alternatives have to be VISIBLE, or a
 * buyer on Brave never learns Brave is an option and the guess stands. */
.ig-switch { display: grid; gap: 8px; }
.ig-picks { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 4px; }
.ig-pick {
  min-height: 44px; padding: 8px 14px;
  background: transparent; color: var(--muted);
  border: 1px solid var(--line-strong); border-radius: var(--r-sm);
  font: inherit; font-size: 14px; cursor: pointer;
  transition: border-color .15s var(--ease-out), background-color .15s var(--ease-out), color .15s var(--ease-out);
}
.ig-pick:hover { background: rgba(255, 255, 255, .05); color: var(--text); }
.ig-pick.sel { background: rgba(30, 136, 229, .12); border-color: var(--blue); color: #fff; font-weight: 600; }
.ig-pick:focus-visible { outline: 2px solid var(--blue-text); outline-offset: 2px; }

.ig-where { font-size: 15px; color: var(--muted); }
.ig-steps { margin: 0; padding-left: 24px; display: grid; gap: 12px; font-size: 15px; color: var(--text); }
.ig-steps li { line-height: 1.55; padding-left: 4px; }
.ig-steps li::marker { color: var(--blue-text); font-weight: 700; font-variant-numeric: tabular-nums; }
.ig-note { display: block; margin-top: 4px; font-size: 13.5px; color: var(--faint); }

.ig-alt {
  display: grid; gap: 8px; padding: 14px;
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-md);
  font-size: 14px;
}
/* The one element allowed to scroll sideways, so a long command never widens
 * the page on a phone. */
.ig-alt pre { margin: 0; overflow-x: auto; padding: 10px 12px; background: var(--bg); border-radius: var(--r-sm); }
.ig-alt pre code { background: none; border: 0; padding: 0; font-size: 13px; white-space: pre; }

.ig-pw-line { font-size: 14.5px; color: var(--muted); }
.ig-pw { color: #fff; background: rgba(30, 136, 229, .14); border-color: rgba(30, 136, 229, .4); }

/* The step everyone skips, so it is set apart with a rule rather than left as
 * a final paragraph that reads as a sign-off. */
.ig-next {
  display: grid; gap: 6px; padding: 4px 0 4px 16px;
  border-left: 2px solid var(--blue);
  font-size: 14.5px; color: var(--muted);
}
.ig-next-t { font-weight: 700; color: var(--text); }

.ig-trouble { display: grid; gap: 0; margin-top: 4px; }
.ig-trouble-t { font-size: 15px; font-weight: 600; color: var(--text); margin-bottom: 4px; }
.ig-t { border-top: 1px solid var(--line); padding: 4px 0; }
.ig-t summary {
  cursor: pointer; font-size: 15px; color: var(--text); min-height: 44px;
  list-style: none; display: flex; gap: 10px; align-items: center;
}
.ig-t summary::-webkit-details-marker { display: none; }
.ig-t summary::before { content: "+"; color: var(--blue-text); font-weight: 700; flex: none; width: 12px; }
.ig-t[open] summary::before { content: "\2212"; }
.ig-t summary:focus-visible { outline: 2px solid var(--blue-text); outline-offset: 2px; border-radius: 4px; }
.ig-t p { margin: 4px 0 10px 22px; font-size: 14px; color: var(--muted); }

.ig-phone { font-size: 15px; color: var(--muted); }
.ig-h2 { font-size: clamp(19px, 4.6vw, 22px); margin-top: 20px; padding-top: 24px; border-top: 1px solid var(--line); }

/* The documents' chrome widens with them, or brand and footer sit visibly
 * inset from the article they belong to. */
.doc .head, .doc .foot { width: min(100%, 760px); }

/* ── the optional account ─────────────────────────────────────────────── */

h3.sub {
  margin: 28px 0 0; padding-top: 28px; border-top: 1px solid var(--line);
  font-size: 19px; font-weight: 700; letter-spacing: -.015em;
  color: var(--text);
}

.devices { list-style: none; margin: 4px 0; padding: 0; display: grid; gap: 0; }

/* Device rows are rows in the card, divided by rules, not boxes in a box.
 * Remove is a real target and coloured from --bad, never amber, which is the
 * page's "yes, buy it" signal. */
.device {
  display: flex; align-items: center; gap: 10px 14px; flex-wrap: wrap;
  padding: 12px 0; border-top: 1px solid var(--line);
}
.device:last-child { border-bottom: 1px solid var(--line); }
/* min-width:0 so a long platform name wraps instead of pushing the button off
 * the row; the shell shipped that exact overflow once at 390px. */
.device .dev-what { flex: 1 1 auto; min-width: 0; font-size: 15px; color: var(--text); }
.device .dev-what code {
  font-family: var(--mono); font-size: 13px; padding: 1px 6px; border-radius: 4px;
  background: rgba(255, 255, 255, .06); color: var(--muted); border: 0;
}
.device .dev-when { flex: 0 0 auto; font-size: 13.5px; color: var(--faint); }

.btn.small {
  width: auto; min-height: 44px; padding: 8px 16px;
  font-size: 14px; font-weight: 600;
}
.btn.danger { background: transparent; color: var(--bad); border: 1px solid rgba(241, 145, 137, .45); }
.btn.danger:hover:not(:disabled) { background: rgba(241, 145, 137, .1); color: var(--bad); }

/* An account page on a deployment with no identity provider: the button stays
 * visible and says so, because both mobile apps link straight here. */
.btn.is-off { background: transparent; color: var(--faint); border: 1px dashed var(--line-strong); cursor: not-allowed; }

@media (max-width: 420px) {
  .device .dev-when { order: 3; }
  .device .btn.small { order: 4; width: 100%; }
}

/* The device you are holding (2026-10-16). */
.dev-this {
  display: inline-block; margin-left: 8px; padding: 0 0 0 8px;
  font-size: 13px; font-weight: 600; line-height: 1.4;
  color: var(--good-text); border-left: 2px solid var(--good);
}

/* ── the old onboarding checklist (kept for any page still rendering it) ── */

.checklist { list-style: none; margin: 14px 0; padding: 0; display: grid; gap: 0; counter-reset: ob; }
.checklist li {
  counter-increment: ob;
  display: grid; grid-template-columns: 26px 1fr; gap: 12px; align-items: start;
  padding: 12px 0; border-top: 1px solid var(--line);
}
.checklist li::before {
  content: counter(ob);
  display: grid; place-items: center;
  width: 24px; height: 24px; border-radius: 50%;
  border: 1px solid var(--line-strong);
  font-size: 12px; font-weight: 700; color: var(--faint);
}
.checklist li.done::before { content: "\2713"; border-color: var(--good); color: var(--good-text); }
.checklist li.done .ob-title { color: var(--good-text); }
.ob-title { font-weight: 600; font-size: 15px; }
.ob-detail { font-size: 14px; color: var(--muted); margin-top: 2px; }
#onboard-actions { display: flex; flex-wrap: wrap; gap: 10px; }
/* 🪤 THE DISPLAY RULE ABOVE BEATS THE `hidden` ATTRIBUTE. This sheet has no
 * global `[hidden]{display:none}`: it handles the attribute per element
 * (`.step[hidden]`), so setting `el.hidden` on a flex container does nothing
 * at all. Measured on beta: the funnel read "all three done" with its action
 * buttons still sitting underneath. Same shape as the premium offer's
 * `[hidden]` bug already recorded in CLAUDE.md. */
#onboard-actions[hidden] { display: none; }
#go-intro[hidden], #check-intro[hidden] { display: none; }
#onboard-actions .btn { width: auto; flex: 1 1 200px; }
@media (max-width: 420px) { #onboard-actions .btn { flex: 1 1 100%; } }
.ob-done-banner {
  margin-top: 12px; padding: 12px 16px; border-left: 2px solid var(--good);
  color: var(--good-text); font-size: 15px; font-weight: 600;
}

/* ── the intake form ──────────────────────────────────────────────────── */

.q { border-top: 1px solid var(--line); padding-top: 18px; margin-top: 18px; }
.q:first-child { border-top: 0; padding-top: 0; margin-top: 0; }
.q-t { font-size: 16px; font-weight: 600; color: var(--text); margin: 0 0 4px; }
.q-n { font-size: 14px; color: var(--faint); margin: 0 0 10px; }
.q-opts { display: grid; gap: 10px; margin-top: 10px; }
.q-opts .check input:disabled + span { color: var(--faint); }
.q-sites { display: grid; gap: 10px; margin-top: 8px; }
.q-site-row { display: grid; gap: 6px; }
.q-site-row select, .q select {
  width: 100%; min-height: 52px; padding: 12px 14px;
  background: var(--bg); color: var(--text);
  border: 1px solid var(--line-strong); border-radius: var(--r-sm);
  font: inherit; font-size: 16px;
}
.q select:focus { outline: none; border-color: var(--blue); box-shadow: 0 0 0 3px rgba(30, 136, 229, .22); }
@media (min-width: 560px) {
  .q-site-row { grid-template-columns: minmax(0, 1fr) minmax(0, 200px); align-items: center; }
  .q-detail { grid-column: 1 / -1; }
}

/* 🪤 These three hide with a CLASS and an explicit display rule, never with the
   `hidden` attribute. premium.css has no global [hidden] { display: none }, so
   any display rule beats the attribute: that trap has now bitten this project
   twice, on the premium offer and on the onboarding action row. */
.q-detail { display: none; }
.q-detail.on { display: block; }
.q-other { display: none; margin-top: 8px; }
.q-other.on { display: block; }
.q-conditional { display: none; }
.q-conditional.on { display: block; }

#intake-privacy { margin-bottom: 8px; }

/* 🪤 The action row is `display:flex`, and premium.css has no global
   [hidden] { display: none }, so the attribute alone does nothing to a child of
   it. That trap has now bitten this project three times: the premium offer, the
   onboarding action row, and it would have bitten these two buttons next. A
   test walks every id toggled with `.hidden` and fails without a rule here. */
#go-discord[hidden], #link-discord[hidden] { display: none; }
/* And three more found once the test read classes as well as ids (`.btn` and
 * `.card` set the display). `#do-enroll` is the one that hurt: it stayed up after
 * the certificate was made, and a second press spent the used code into a
 * "That code has already been used" error. */
#error-retry[hidden], #do-enroll[hidden], #onboard-card[hidden] { display: none; }

/* ── the iPhone and iPad notice ───────────────────────────────────────── */

/* A native <dialog>: Esc, the focus trap and the inert page behind it come
 * from the browser. Centred on a wide screen, a bottom sheet on a phone. */
dialog.sheet {
  width: min(440px, calc(100vw - 32px)); max-width: none;
  padding: 28px 24px 24px; color: var(--text);
  background: var(--surface);
  border: 1px solid var(--line-strong); border-radius: 12px;
  box-shadow: 0 30px 80px rgba(0, 0, 0, .6);
}
dialog.sheet[open] { animation: sheet-in .24s var(--ease-out); }
dialog.sheet::backdrop { background: rgba(4, 8, 16, .74); }
dialog.sheet form { display: grid; gap: 14px; justify-items: start; }
dialog.sheet h2 { margin: 0; font-size: 24px; line-height: 1.2; }
dialog.sheet .lede { margin: 0; font-size: 16px; }
.sheet-icon {
  width: 44px; height: 44px; display: grid; place-items: center;
  color: var(--amber-text);
}
.sheet-icon svg { width: 36px; height: 36px; }
.sheet-fine { margin: 0; font-size: 14.5px; line-height: 1.55; color: var(--faint); }
.sheet-actions { display: grid; gap: 10px; width: 100%; margin-top: 8px; }
@keyframes sheet-in { from { opacity: 0; transform: translateY(12px); } to { opacity: 1; transform: none; } }
@media (max-width: 520px) {
  dialog.sheet {
    width: 100%; margin: auto 0 0; border-radius: 14px 14px 0 0;
    border-bottom: 0; padding-bottom: calc(24px + env(safe-area-inset-bottom));
  }
  /* The grab bar says "this slides" the way the system sheets do. */
  dialog.sheet form::before {
    content: ""; justify-self: center; width: 36px; height: 4px; margin: -14px 0 6px;
    border-radius: 2px; background: var(--line-strong);
  }
  @keyframes sheet-in { from { transform: translateY(100%); } to { transform: none; } }
}

/* ── the offer: two ways in, the free one first ───────────────────────── */

.sr-only {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap;
}

.col-wide { width: min(100%, 1040px); gap: 28px; }
/* The header follows the offer's wider column while the offer is showing, or
 * the logo sits inset from the content beneath it. */
body:has(.step[data-step="offer"]:not([hidden])) .head,
body:has(.step[data-step="offer"]:not([hidden])) .foot { width: min(100%, 1040px); }

.offer-head { display: grid; gap: 16px; max-width: 760px; padding-top: clamp(4px, 2vw, 24px); }
.offer-head h1 { font-size: clamp(34px, 9vw, 64px); line-height: 1.02; letter-spacing: -.04em; }
.offer-head .lede { max-width: 54ch; font-size: clamp(17px, 2.4vw, 19px); }

.paths { display: grid; grid-template-columns: minmax(0, 1fr); gap: 16px; }
@media (min-width: 820px) {
  .paths { grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr); gap: 20px; align-items: stretch; }
}
.path {
  display: grid; align-content: start; gap: 18px;
  padding: 24px; border-radius: var(--r-md);
  border: 1px solid var(--line-strong); background: transparent;
}
.path-title { font-size: 18px; font-weight: 700; letter-spacing: -.015em; color: var(--text); }

/* The free month is set like the certificate it earns you: a surface with a
 * single amber rule along the top and the term in big figures. The whole
 * thing is the link, because a card that looks pressable and only answers on
 * its button is the commonest dead tap on a phone. */
.path-free {
  position: relative; overflow: hidden;
  color: var(--text); text-decoration: none;
  grid-template-rows: auto auto 1fr auto;
  background: var(--surface);
  border-color: rgba(255, 176, 46, .34);
  border-top: 3px solid var(--amber);
  transition: border-color .2s var(--ease-out), background-color .2s var(--ease-out), transform .2s var(--ease-out);
}
.path-free:hover { color: var(--text); border-color: rgba(255, 176, 46, .7); border-top-color: var(--amber); background: var(--surface-2); }
.path-free:active { transform: scale(.995); }
.path-free:focus-visible { outline: 2px solid var(--amber-text); outline-offset: 3px; }
.path-days {
  font-size: 17px; font-weight: 500; color: var(--amber-text);
  display: flex; align-items: baseline; gap: 10px;
}
.path-days b {
  font-size: clamp(64px, 18vw, 88px); line-height: .82; font-weight: 700; letter-spacing: -.055em;
  color: var(--amber); font-variant-numeric: tabular-nums;
}
/* The steps read as a numbered list set in figures, not as four badges. */
.path-steps { list-style: none; margin: 0; padding: 0; display: grid; gap: 0; counter-reset: ps; }
.path-steps li {
  counter-increment: ps;
  display: grid; grid-template-columns: 28px 1fr; gap: 8px; align-items: baseline;
  padding: 10px 0; border-top: 1px solid var(--line);
  font-size: 16px; color: var(--text);
}
.path-steps li:last-child { border-bottom: 1px solid var(--line); }
.path-steps li::before {
  content: counter(ps, decimal-leading-zero);
  font-family: var(--mono); font-size: 13px; color: var(--amber-text);
  font-variant-numeric: tabular-nums;
}
.path-steps li.done { color: var(--muted); }
.path-steps li.done::before { content: "\2713"; color: var(--good-text); font-family: inherit; }
.path-cta { pointer-events: none; }
.path-cta svg { transition: transform .2s var(--ease-out); }
.path-free:hover .path-cta svg { transform: translateX(3px); }

.path-pay { align-content: start; }
.path-pay .hint { margin-top: -6px; }
@media (min-width: 820px) { .path-pay .hint { text-align: left; } }

/* ── the #free step ── */

.free-head { display: grid; gap: 14px; }
.free-days {
  font-size: 17px; font-weight: 500; color: var(--amber-text);
  display: flex; align-items: baseline; gap: 10px;
}
.free-days b {
  font-size: clamp(56px, 15vw, 72px); line-height: .82; font-weight: 700; letter-spacing: -.055em;
  color: var(--amber); font-variant-numeric: tabular-nums;
}
.free-progress { font-size: 14px; font-weight: 500; color: var(--muted); margin: 0 0 14px; }

/* One rail down the left, a mark on it per step, the instructions inside the
 * step they belong to. Only the step you are on gets a surface; the others are
 * rows on the rail, so the page shows one thing to do instead of four boxes.
 * The rail is drawn per row, so it can never disagree with the row count. */
.journey { list-style: none; margin: 0; padding: 0; display: grid; gap: 4px; position: relative; }
.journey li {
  position: relative;
  display: grid; grid-template-columns: 32px minmax(0, 1fr); gap: 16px; align-items: start;
  padding: 16px 16px 16px 12px;
  border: 1px solid transparent; border-radius: var(--r-md);
  transition: border-color .2s var(--ease-out), background-color .2s var(--ease-out);
}
.journey li + li::before {
  content: ""; position: absolute; left: 27px; top: -8px; width: 2px; height: 26px;
  background: var(--line-strong);
}
.j-mark {
  position: relative; z-index: 1;
  width: 32px; height: 32px; border-radius: 50%; display: grid; place-items: center;
  font-size: 14px; font-weight: 700; color: var(--muted); font-variant-numeric: tabular-nums;
  background: var(--bg); border: 1.5px solid var(--line-strong);
}
.j-body { display: grid; gap: 4px; min-width: 0; padding-top: 4px; }
.journey .ob-title { font-size: 17px; font-weight: 700; letter-spacing: -.01em; }
.journey .ob-detail { font-size: 15px; color: var(--muted); }

.journey li.current { border-color: rgba(30, 136, 229, .55); background: var(--surface); }
.journey li.current .j-mark { color: #061426; background: var(--blue); border-color: var(--blue); }
.journey li.done .j-mark { color: var(--good-text); background: var(--bg); border-color: var(--good); }
.journey li.done .ob-title { color: var(--muted); }
.journey li.done .ob-detail { display: none; }
.journey li.locked .ob-title, .journey li.locked .ob-detail { color: var(--faint); }
.journey li.locked .j-mark { color: var(--faint); border-style: dashed; }
/* One loud step at a time. Every step still to do keeps its buttons, so
 * nobody is forced into an order, but only the CURRENT one is in colour:
 * three coloured buttons stacked down a phone read as three equal demands. */
.journey li:not(.current) .j-actions .btn {
  background: transparent; color: var(--text);
  border: 1px solid var(--line-strong); font-weight: 600;
}
.journey li:not(.current) .j-actions .btn:hover { background: rgba(255, 255, 255, .05); }

.j-actions { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 12px; }
.j-actions .btn { width: auto; flex: 1 1 210px; min-height: 48px; padding: 12px 16px; font-size: 15px; }
.j-note { flex: 1 1 100%; font-size: 14px; color: var(--faint); margin: 0; }
.j-locked { margin-top: 4px; }
@media (max-width: 420px) { .j-actions .btn { flex: 1 1 100%; } }

.form-panel {
  display: grid; gap: 14px; padding: 22px 20px;
  border: 1px solid var(--line-strong); border-radius: var(--r-md);
  background: var(--surface); scroll-margin-top: 16px;
  color: var(--muted);
}
.form-panel > p:first-child { color: var(--text); }
.form-panel .legal { font-size: 14.5px; line-height: 1.6; padding-left: 14px; border-left: 2px solid var(--amber); }

.ob-done {
  display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 14px 16px; align-items: center;
  padding: 20px; border-radius: var(--r-md);
  background: var(--surface); border: 1px solid rgba(69, 199, 166, .45); color: var(--good-text);
}
.ob-done .btn { grid-column: 1 / -1; }
.ob-done-title { font-size: 18px; font-weight: 700; color: var(--text); }
.ob-done-sub { font-size: 15px; color: var(--muted); }

/* The account page's one-line link to the funnel. */
.free-link {
  display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: 12px;
  position: relative; overflow: hidden;
  color: var(--text); text-decoration: none;
  border-color: rgba(255, 176, 46, .34);
  transition: border-color .2s var(--ease-out), background-color .2s var(--ease-out);
}
.free-link::before { content: ""; position: absolute; inset: 0 auto 0 0; width: 3px; background: var(--amber); }
.free-link:hover { color: var(--text); border-color: rgba(255, 176, 46, .7); background: var(--surface-2); }
.free-link b { display: block; font-size: 16px; }
.free-link-sub { display: block; font-size: 14px; color: var(--muted); margin-top: 2px; }
.free-link svg { color: var(--amber-text); }

#free-path[hidden], #pay-title[hidden], #acct-free-link[hidden], #ob-done[hidden],
#survey-block[hidden], #go-discord[hidden], #open-form[hidden], .j-park[hidden],
#free-off[hidden], #onboard-card[hidden] { display: none; }

/* ── one entrance ─────────────────────────────────────────────────────── */

/* A step that appears settles in once, opacity and a few pixels only, so the
 * text is readable from the first frame. The reduced-motion reset at the top
 * of the file turns it off. */
.step:not([hidden]) > .col, .page { animation: step-in .32s var(--ease-out) both; }
@keyframes step-in { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }

/* The way back to vpn.free, top right on every page (2026-10-16, owner: "that
 * is where the user wants to go always"). A link with an outward arrow rather
 * than a button, so it never competes with the step's one amber action. */
.head-app {
  margin-left: auto; display: inline-flex; align-items: center; gap: 6px;
  min-height: 44px; padding: 0 12px; margin-right: -12px;
  color: var(--blue-text); font-size: 15px; font-weight: 500; text-decoration: none;
  border-radius: var(--r-sm);
}
.sandbox-flag:not([hidden]) + .head-app { margin-left: 12px; }
.head-app:hover { color: #b6dbfb; background: rgba(255, 255, 255, .04); }
.head-app:focus-visible { outline: 2px solid var(--blue-text); outline-offset: 2px; }
#account-lede b { color: var(--text); font-weight: 600; overflow-wrap: anywhere; }
/* On a 360px phone the brand lockup and the full link do not fit one row. The
 * verb goes (it stays in the accessible name: clipped, not removed) and the
 * lockup tightens, so the way back never drops onto a line of its own. */
@media (max-width: 400px) {
  .head { gap: 8px; }
  .brand { gap: 8px; font-size: 16px; }
  .mark-tile { width: 28px; height: 28px; }
  .tier { padding-left: 8px; font-size: 14px; }
  .head-app { padding: 0 8px; margin-right: -8px; gap: 4px; }
  .head-app-verb {
    position: absolute; width: 1px; height: 1px; overflow: hidden;
    clip: rect(0 0 0 0); white-space: nowrap;
  }
}
