/* CloakiVPN website — one stylesheet, no inline styles anywhere (strict CSP: style-src 'self').
   Dark-first with a light-mode override via prefers-color-scheme. */

/* Palette is taken from the app icon (CloakiVPN.icon): shield purples #5f3a86 / #906dac, visor
   cyans #2ddcff / #00b3dd / #0089c6, hood #0c020c. Backgrounds are near-black with a faint purple
   cast so the shield reads as part of the page. Every text pairing below was measured against
   WCAG 2.x — re-measure when changing one, the light theme has failed AA here before. */
:root {
  --bg: #0f0b15;
  --bg-elev: #18131f;
  --bg-elev2: #211a2b;
  --border: #2f2740;
  --text: #ece9f2;            /* 16.2:1 on --bg */
  --text-dim: #a79fb6;        /* 7.7:1 on --bg, 7.2:1 on --bg-elev */
  --accent: #2ddcff;          /* icon cyan — links, focus rings, checkmarks: 11.9:1 on --bg */
  --accent-hover: #8ae8ff;
  /* Buttons use their own pair so the light-mode link colour (see below) doesn't dull them. */
  --accent-btn: #906dac;      /* icon shield purple, exact — --accent-ink on it is 4.83:1 */
  --accent-btn-hover: #a385bf;/* 6.5:1 */
  --accent-ink: #0c020c;      /* icon hood black */
  --danger: #f87171;
  --ok: #34d399;
  --warn: #fbbf24;
  --radius: 12px;
  --maxw: 1080px;
  --font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
}
@media (prefers-color-scheme: light) {
  :root {
    --bg: #f8f7fb; --bg-elev: #ffffff; --bg-elev2: #f0edf5; --border: #ddd7e6;
    --text: #1a1024; --text-dim: #5c5370;   /* 17.2:1 and 6.7:1 on --bg */
    /* The icon's cyans cannot carry text on a light background — #0089c6 measures 3.65:1, under
       the 4.5:1 AA floor, and links are the main place accent is used as text. The deep shield
       purple #5f3a86 measures 8.1:1 on --bg (7.5:1 on --bg-elev2), so light mode is all purple. */
    --accent: #5f3a86; --accent-hover: #4c2e6c;
    /* White ink on #5f3a86 is 8.6:1, on the hover shade 11.0:1. */
    --accent-btn: #5f3a86; --accent-btn-hover: #4c2e6c;
    --accent-ink: #ffffff;
    /* --danger/--ok/--warn are tuned for the dark background and were never overridden here, so
       in light mode they were being used as text at 2.77:1, 1.92:1 and 1.67:1 respectively —
       the "Remove" buttons and the account expiry badge among them. Same semantics, AA contrast
       (5.4:1, 5.0:1, 5.6:1 on --bg). */
    --danger: #c81e1e;
    --ok: #0f7a52;
    --warn: #8a5a00;
  }
}

* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
  margin: 0; background: var(--bg); color: var(--text);
  font-family: var(--font); line-height: 1.6; -webkit-font-smoothing: antialiased;
}
/* Underlined by default. Colour alone is not a sufficient signal (WCAG 1.4.1) and it fails for
   anyone who can't separate the accent from body text. Chrome that is positionally obvious — nav,
   buttons, footer, the brand — opts out individually below. */
a { color: var(--accent); text-decoration: underline; text-underline-offset: 2px; }
a:hover { text-decoration-thickness: 2px; }
h1, h2, h3 { line-height: 1.2; font-weight: 700; }
h1 { font-size: 2.4rem; margin: 0 0 .5rem; }
h2 { font-size: 1.6rem; margin: 2.5rem 0 1rem; }
h3 { font-size: 1.15rem; margin: 1.5rem 0 .5rem; }
p { color: var(--text-dim); }
code, pre { font-family: var(--mono); }

.container { max-width: var(--maxw); margin: 0 auto; padding: 0 1.25rem; }

/* Nav */
.nav { border-bottom: 1px solid var(--border); background: var(--bg-elev); position: sticky; top: 0; z-index: 10; }
.nav-inner { display: flex; align-items: center; gap: 1.25rem; height: 60px; }
.brand { font-weight: 800; font-size: 1.15rem; color: var(--text); display: flex; align-items: center; gap: .5rem; text-decoration: none; }
.brand:hover { text-decoration: none; }
.brand .logo { width: 26px; height: 30px; display: block; }
.nav-links { display: flex; gap: 1.1rem; margin-left: auto; align-items: center; flex-wrap: wrap; }
.nav-links a { color: var(--text-dim); font-size: .95rem; text-decoration: none; }
.nav-links a:hover { color: var(--text); text-decoration: none; }
/* `.nav-links a` outranks `.btn`, so without this the nav "Get started" button drew --text-dim on the
   button fill — about 1.9:1 in light mode. Restore the button's own ink. */
.nav-links a.btn, .nav-links a.btn:hover { color: var(--accent-ink); }

/* Buttons */
.btn {
  display: inline-block; border: 1px solid transparent; border-radius: 10px;
  padding: .65rem 1.15rem; font-size: .95rem; font-weight: 600; cursor: pointer;
  background: var(--accent-btn); color: var(--accent-ink); font-family: var(--font);
  text-decoration: none;
}
.btn:hover { background: var(--accent-btn-hover); text-decoration: none; }
.btn.ghost { background: transparent; color: var(--text); border-color: var(--border); }
.btn.ghost:hover { background: var(--bg-elev2); }
.btn.danger { background: transparent; color: var(--danger); border-color: var(--border); }
.btn.danger:hover { background: rgba(248,113,113,.1); }
.btn.sm { padding: .4rem .75rem; font-size: .85rem; }
.btn:disabled { opacity: .5; cursor: not-allowed; }

/* Hero */
.hero { padding: 5rem 0 3.5rem; text-align: center; }
.hero-logo { display: block; width: 104px; height: 120px; margin: 0 auto 1.5rem; }
.hero h1 { font-size: 3rem; max-width: 16ch; margin: 0 auto 1rem; }
.hero p.lede { font-size: 1.2rem; max-width: 60ch; margin: 0 auto 2rem; color: var(--text-dim); }
.hero .cta { display: flex; gap: .75rem; justify-content: center; flex-wrap: wrap; }

/* Feature grid */
.grid { display: grid; gap: 1rem; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); margin: 2rem 0; }
/* Fixed three across (the homepage's six cards → two even rows), stepping down on narrow screens. */
.grid.cols-3 { grid-template-columns: repeat(3, 1fr); }
@media (max-width: 860px) { .grid.cols-3 { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 560px) { .grid.cols-3 { grid-template-columns: 1fr; } }
.card {
  background: var(--bg-elev); border: 1px solid var(--border); border-radius: var(--radius);
  padding: 1.4rem;
}
.card h3 { margin-top: 0; }
.card p { margin-bottom: 0; }

/* Pricing */
.tiers { display: grid; gap: 1.25rem; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); margin: 2rem 0; }
.tier { background: var(--bg-elev); border: 1px solid var(--border); border-radius: var(--radius); padding: 1.75rem; text-align: center; }
.tier.featured { border-color: var(--accent-btn); }
.tier .price { font-size: 2.4rem; font-weight: 800; color: var(--text); margin: .5rem 0; }
.tier .price small { font-size: 1rem; color: var(--text-dim); font-weight: 500; }
.tier .per { color: var(--text-dim); font-size: .9rem; }
.tier ul { list-style: none; padding: 0; margin: 1.25rem 0; text-align: left; }
.tier li { padding: .35rem 0; color: var(--text-dim); }
.tier li::before { content: "✓"; color: var(--accent); font-weight: 700; margin-right: .5rem; }

/* Forms */
.panel { background: var(--bg-elev); border: 1px solid var(--border); border-radius: var(--radius); padding: 2rem; max-width: 460px; margin: 2rem auto; }
.panel.wide { max-width: 760px; }
label { display: block; font-size: .9rem; font-weight: 600; margin: 1rem 0 .35rem; }
input[type=text], input[type=password], select {
  width: 100%; padding: .7rem .8rem; border-radius: 10px; border: 1px solid var(--border);
  background: var(--bg); color: var(--text); font-family: var(--mono); font-size: 1rem;
}
input:focus, select:focus { outline: 2px solid var(--accent); border-color: var(--accent); }

/* Keyboard focus for EVERYTHING interactive, not just form fields. Previously only inputs and
   selects were styled, so the whole keyboard path through signup, login, checkout and device
   management relied on whatever the browser drew over a saturated button fill — often nothing
   legible (WCAG 2.4.7). :focus-visible so it appears for keyboard users without ringing on mouse
   clicks. The offset + contrasting outline keeps it readable on top of the accent fill. */
a:focus-visible,
button:focus-visible,
.btn:focus-visible,
summary:focus-visible,
[tabindex]:focus-visible {
  outline: 3px solid var(--accent);
  outline-offset: 2px;
  border-radius: 6px;
}
/* On an accent-filled button the accent outline would vanish into it, so invert there. */
.btn:not(.ghost):not(.danger):focus-visible { outline-color: var(--text); }

/* Respect a reduced-motion preference — the only motion here is the smooth-scroll on html. */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
}

/* ── Private-beta banner ────────────────────────────────────────────────────
   Static markup on every page (check_website.py enforces it). Not sticky — the nav already is, and
   two stuck bars eat too much of a phone screen. --accent-ink on --accent-btn: 4.83:1 dark, 8.6:1
   light. Remove the markup and this block together at public launch. */
.beta-banner { background: var(--accent-btn); color: var(--accent-ink); font-size: .9rem; text-align: center; padding: .5rem 0; }

/* ── Skip link (L6) ─────────────────────────────────────────────────────────
   Offscreen until focused, so keyboard users can jump the sticky nav on every page. */
.skip-link {
  position: absolute; left: -9999px; top: 0;
  background: var(--bg-elev); color: var(--text);
  padding: .7rem 1.1rem; border: 1px solid var(--border); border-radius: 0 0 8px 0;
  z-index: 100; text-decoration: none;
}
.skip-link:focus {
  left: 0;
  outline: 3px solid var(--accent); outline-offset: 2px;
}
.hint { font-size: .85rem; color: var(--text-dim); margin-top: .35rem; }
.form-actions { margin-top: 1.5rem; display: flex; gap: .75rem; align-items: center; }

/* Alerts */
.alert { border-radius: 10px; padding: .85rem 1rem; margin: 1rem 0; font-size: .95rem; border: 1px solid var(--border); }
.alert.err { color: var(--danger); border-color: rgba(248,113,113,.4); background: rgba(248,113,113,.08); }
.alert.ok { color: var(--ok); border-color: rgba(52,211,153,.4); background: rgba(52,211,153,.08); }
.alert.warn { color: var(--warn); border-color: rgba(251,191,36,.35); background: rgba(251,191,36,.08); }
.hidden { display: none !important; }

/* Code / config blocks */
pre.code {
  background: var(--bg); border: 1px solid var(--border); border-radius: 10px;
  padding: 1rem; overflow-x: auto; font-size: .85rem; color: var(--text); white-space: pre;
}
.mono { font-family: var(--mono); }
.account-number { font-family: var(--mono); font-size: 1.5rem; letter-spacing: .1em; color: var(--text); word-break: break-all; }

/* Device list */
.device { display: flex; align-items: center; gap: 1rem; padding: 1rem; border: 1px solid var(--border); border-radius: 10px; background: var(--bg-elev); margin-bottom: .75rem; flex-wrap: wrap; }
.device .meta { flex: 1; min-width: 160px; }
.device .meta .name { font-weight: 600; }
.device .meta .addr { font-family: var(--mono); font-size: .8rem; color: var(--text-dim); }
.device .actions { display: flex; gap: .5rem; }

/* QR */
#qr canvas, .qr canvas { background: #fff; padding: 10px; border-radius: 10px; display: block; }

/* Status */
.status-country { margin: 1.5rem 0; }
.status-country h3 { display: flex; align-items: center; gap: .5rem; margin-bottom: .5rem; }
.status-city { margin: .5rem 0 1rem; }
.status-city .city-name { font-size: .85rem; text-transform: uppercase; letter-spacing: .05em; color: var(--text-dim); margin-bottom: .4rem; }
.relay-row { display: flex; align-items: center; gap: .75rem; padding: .55rem .9rem; border: 1px solid var(--border); border-radius: 8px; background: var(--bg-elev); margin-bottom: .4rem; }
.relay-row .rname { font-family: var(--mono); font-size: .9rem; flex: 1; }
.badge { font-size: .78rem; padding: .12rem .55rem; border-radius: 999px; font-weight: 600; }
.badge.up { color: var(--ok); background: rgba(52,211,153,.12); }
.badge.down { color: var(--danger); background: rgba(248,113,113,.12); }
.badge.load-low { color: var(--ok); background: rgba(52,211,153,.1); }
.badge.load-medium { color: var(--warn); background: rgba(251,191,36,.1); }
.badge.load-high { color: var(--danger); background: rgba(248,113,113,.1); }

/* Content pages */
.prose { max-width: 72ch; margin: 2rem auto; }
.prose h2 { margin-top: 2rem; }
.prose ul { color: var(--text-dim); }
.steps { counter-reset: step; list-style: none; padding: 0; }
.steps li { counter-increment: step; position: relative; padding: .5rem 0 .5rem 2.5rem; color: var(--text-dim); }
.steps li::before { content: counter(step); position: absolute; left: 0; top: .4rem; width: 1.7rem; height: 1.7rem; background: var(--accent); color: var(--accent-ink); border-radius: 50%; display: grid; place-items: center; font-weight: 700; font-size: .9rem; }

/* Footer */
footer { border-top: 1px solid var(--border); margin-top: 4rem; padding: 2.5rem 0; color: var(--text-dim); font-size: .9rem; }
.foot-inner { display: flex; gap: 2rem; flex-wrap: wrap; justify-content: space-between; }
.foot-links { display: flex; gap: 1.25rem; flex-wrap: wrap; }
.foot-links a { color: var(--text-dim); text-decoration: none; }
.foot-links a:hover { text-decoration: underline; }

@media (max-width: 640px) {
  h1 { font-size: 2rem; } .hero h1 { font-size: 2.3rem; } .hero { padding: 3rem 0 2rem; }
  .nav-links { gap: .8rem; } .nav-links a { font-size: .88rem; }
}

/* Headings that lead a panel/section shouldn't carry the large default top margin. */
.panel h1:first-child, .panel h2:first-child, .panel h3:first-child { margin-top: 0; }
section > h2:first-child { margin-top: 1.5rem; }

/* ── Pay page (pay.cloakivpn.net only) ─────────────────────────────────────────
   The fields themselves are Stripe iframes styled through the Appearance API in pay.js, from the
   same tokens as above; these rules only space the mount points. */
.pay-panel { max-width: 520px; }
.pay-element { margin: 1rem 0; }
