/* ═══════════════════════════════════════════════════════════════════════════
   Dombay VPN — design system
   Implements the Claude Design handoff ("Dombay Website — Responsive Reference").

   HOW THIS IS LOADED
   Every page links this file *last* in <head>, after its own inline <style>.
   That ordering is load-bearing: the pages carry large hand-written stylesheets
   and this layer must win ties without a forest of !important. Page rules with
   genuinely higher specificity still win, which is what you want for one-off
   page layouts.

       <link rel="stylesheet" href="/assets/fonts/fonts.css">
       <link rel="stylesheet" href="/assets/dombay-design.css">
     </head>

   It lives under /assets/ because that is the one directory served by
   express.static on EVERY host (apex, partners., beta., trial., migrate.) and
   by nginx from the website root. Root-level files need a bespoke Express route.

   THE THREE LEVERS, in order of how much they move
   1. Token redefinition. Every page already declares the same ~20 custom
      properties (--bg/--surface/--accent/--text/…). Re-pointing those names at
      the new palette re-skins the bulk of 33 pages without touching their rules.
      Note --accent flips blue → green: green is now the product/primary accent
      and blue demotes to the technical/node-hoster accent, exactly as designed.
   2. Shared legacy classes. The pages were copy-pasted from one another, so
      `.btn`, `.hero`, `.hero-badge`, `nav`, `.card`, `h1…h3` mean the same thing
      everywhere. Restyling them here lands the new look site-wide.
   3. New `dds-` components for what the old markup has no equivalent of.

   ACCENTS — one per page, never two competing in a section. Set on <body>:
       <body class="dds-accent-gold">    green (default) · blue · gold · purple
   green  = product / primary          blue   = node-hoster / technical
   gold   = paid upgrade (Private Pro, Premium Partner, Beta, bug bounty)
   purple = resellers / company / support
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── Tokens ───────────────────────────────────────────────────────────────── */
:root {
  /* Ground */
  --dds-bg:            #07080F;
  --dds-surface:       #101026;
  --dds-surface-raised:#161634;
  --dds-panel-deep:    #0A0A16;
  --dds-border:        rgba(255,255,255,.09);
  --dds-border-strong: rgba(255,255,255,.14);
  --dds-hairline:      rgba(255,255,255,.06);

  /* Accent families */
  --dds-green:         #35D8A0;
  --dds-green-tint:    #7DEBC2;
  --dds-on-green:      #06231B;
  --dds-blue:          #5B7FFF;
  --dds-blue-light:    #8FA6FF;
  --dds-gold:          #E8B84B;
  --dds-gold-grad:     linear-gradient(135deg,#F5D889,#E8B84B);
  --dds-on-gold:       #20160A;
  --dds-purple:        #7C3AED;
  --dds-purple-light:  #A78BFA;
  --dds-purple-pale:   #C4A6FA;

  /* Text */
  --dds-text:          #F6F3FF;
  --dds-text-bright:   #F8F5FF;
  --dds-body:          #C7CEE0;
  --dds-body-alt:      #E4E8F2;
  --dds-secondary:     #94A3B8;
  --dds-secondary-alt: #B6BDD0;
  --dds-muted:         #6B7A99;
  --dds-muted-alt:     #5B6480;

  /* Status */
  --dds-error:         #F87171;
  --dds-code-green:    #A8D8A8;
  --dds-canary-bg:     linear-gradient(160deg,#111E3D,#0E1830);
  --dds-canary-border: #26324F;

  /* Per-page accent — overridden by the .dds-accent-* body classes below. */
  --dds-accent:        var(--dds-green);
  --dds-accent-soft:   var(--dds-green-tint);
  /* TYPE-safe accent: 12px mono labels need 4.5:1, and raw purple #7C3AED sits
     at ~3.5:1 on the ground. Borders and fills keep --dds-accent; small TEXT
     takes this. Green/gold/blue are bright enough to pass as themselves. */
  --dds-accent-type:   var(--dds-accent);
  --dds-on-accent:     var(--dds-on-green);
  --dds-accent-rgb:    53,216,160;

  /* THE ACTION COLOUR IS ALWAYS GREEN, on every page.
     The accent varies by section (blue for node-hoster, gold for paid upgrades,
     purple for company/support) and drives kickers, borders and tints — but a
     CTA that changes colour page to page makes the reader re-learn what a
     button looks like, and it looked like drift rather than intent. These are
     deliberately NOT redeclared in the .dds-accent-* blocks below, so they stay
     green wherever they are used. */
  --dds-cta:           var(--dds-green);
  --dds-on-cta:        var(--dds-on-green);
  --dds-cta-rgb:       53,216,160;

  /* Type */
  --dds-font-display: 'Dombay Display', Archivo, 'Golos Text', system-ui,
                      -apple-system, 'Segoe UI', 'Noto Sans', 'PingFang SC',
                      'Hiragino Sans', 'Noto Sans CJK SC', 'Noto Sans Arabic',
                      'Noto Sans Hebrew', 'Noto Sans Devanagari', sans-serif;
  --dds-font-body:    'IBM Plex Sans', system-ui, -apple-system, 'Segoe UI',
                      'Noto Sans', 'PingFang SC', 'Hiragino Sans',
                      'Noto Sans CJK SC', 'Noto Sans Arabic', 'Noto Sans Hebrew',
                      'Noto Sans Devanagari', sans-serif;
  --dds-font-mono:    'IBM Plex Mono', ui-monospace, SFMono-Regular, Menlo,
                      Consolas, monospace;

  /* Shape + rhythm */
  --dds-r-card:   16px;
  --dds-r-card-lg:20px;
  --dds-r-btn:    10px;
  --dds-r-pill:   999px;
  --dds-max:      1264px;   /* marketing sections            */
  --dds-measure:  76ch;     /* long-form reading pages       */
  --dds-max-card: 420px;    /* auth / utility cards          */
  --dds-pad-x:    clamp(20px, 4vw, 88px);
  --dds-pad-y:    clamp(40px, 6vw, 80px);
  --dds-gap:      clamp(12px, 1.6vw, 20px);

  /* ── Legacy bridge ──────────────────────────────────────────────────────
     The names the 33 existing pages already use. Pages that still declare
     these in their own :root win (same specificity, later in the cascade), so
     the migration removes their colour declarations and inherits from here. */
  --bg:           var(--dds-bg);
  --surface:      var(--dds-surface);
  --surface2:     var(--dds-surface-raised);
  --card:         var(--dds-surface);
  --border:       var(--dds-border);
  --accent:       var(--dds-accent);
  --accent2:      var(--dds-accent-soft);
  --green:        var(--dds-green);
  --blue:         var(--dds-blue);
  --gold:         var(--dds-gold);
  --gold-dim:     #B08A2E;
  --purple:       var(--dds-purple);
  --purple-light: var(--dds-purple-light);
  --text:         var(--dds-text);
  --muted:        var(--dds-secondary);
  --dim:          var(--dds-muted);
  --red:          var(--dds-error);
  --good:         var(--dds-green);
  --orange:       var(--dds-gold);
  --radius:       var(--dds-r-card);
  /* Payment-rail brand colours stay literal — they are other companies' marks. */
  --stripe:       #635BFF;
  --tg:           #2AABEE;
  --usdt:         #26A17B;
  --tron:         #EF0027;
}

/* Per-page accent. One accent per page; secondary actions go outline-only. */
/* --dds-accent-type is re-declared in EVERY accent class, not only purple: the
   :root default `var(--dds-accent)` resolves ON :root where the accent is the
   green default, and custom properties inherit as COMPUTED values — so without
   these, every blue/gold page's kicker rendered frozen green. */
.dds-accent-green,
body:not([class*="dds-accent-"]) {
  --dds-accent: var(--dds-green); --dds-accent-soft: var(--dds-green-tint);
  --dds-on-accent: var(--dds-on-green); --dds-accent-rgb: 53,216,160;
  --dds-accent-type: var(--dds-green);
}
.dds-accent-blue {
  --dds-accent: var(--dds-blue); --dds-accent-soft: var(--dds-blue-light);
  --dds-on-accent: #050B22; --dds-accent-rgb: 91,127,255;
  --dds-accent-type: var(--dds-blue-light);   /* base blue is ~3:1 at 12px mono */
}
.dds-accent-gold {
  --dds-accent: var(--dds-gold); --dds-accent-soft: #F5D889;
  --dds-on-accent: var(--dds-on-gold); --dds-accent-rgb: 232,184,75;
  --dds-accent-type: var(--dds-gold);
}
.dds-accent-purple {
  --dds-accent: var(--dds-purple); --dds-accent-soft: var(--dds-purple-light);
  --dds-on-accent: #F6F3FF; --dds-accent-rgb: 124,58,237;
  --dds-accent-type: var(--dds-purple-pale);   /* small text needs ~9:1, raw purple is 3.5:1 */
}
/* The bridge aliases must be re-declared at the body scope too, or they keep
   resolving against :root's green while --dds-accent has already changed. */
[class*="dds-accent-"] { --accent: var(--dds-accent); --accent2: var(--dds-accent-soft); }

/* ── Ground + base type ───────────────────────────────────────────────────── */
html { -webkit-text-size-adjust: 100%; }

body {
  background: var(--dds-bg);
  color: var(--dds-body);
  font-family: var(--dds-font-body);
  font-size: 15px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/* Display face on everything structural. Tight tracking is part of the brand. */
h1, h2, h3, h4, h5, h6,
.dds-display {
  font-family: var(--dds-font-display);
  color: var(--dds-text);
  text-wrap: pretty;
}
h1 { font-weight: 800; font-size: clamp(25px, 4.2vw, 50px); line-height: 1.08; letter-spacing: -.04em; color: var(--dds-text-bright); }
h2 { font-weight: 800; font-size: clamp(20px, 2.4vw, 28px); line-height: 1.15; letter-spacing: -.03em; }
h3 { font-weight: 800; font-size: clamp(16px, 1.5vw, 19px); line-height: 1.25; letter-spacing: -.02em; }
h4 { font-weight: 700; font-size: clamp(14px, 1.2vw, 16px); letter-spacing: -.015em; }

/* The old hero rule painted H1 emphasis with a blue→purple gradient clip. The
   new system uses one solid accent instead — gradient text competes with the
   accent rule and renders as a smear at small sizes. */
h1 span,
.hero h1 span {
  background: none !important;
  -webkit-background-clip: initial !important;
  background-clip: initial !important;
  -webkit-text-fill-color: currentColor !important;
  color: var(--dds-accent);
}

a { color: var(--dds-accent-soft); text-decoration: none; }
a:hover { color: var(--dds-accent); }

code, kbd, pre, samp, .mono { font-family: var(--dds-font-mono); }

::selection { background: rgba(var(--dds-accent-rgb), .28); color: var(--dds-text-bright); }

:focus-visible {
  outline: 2px solid var(--dds-accent);
  outline-offset: 2px;
  border-radius: 4px;
}

/* ── The kicker ───────────────────────────────────────────────────────────────
   One recurring pattern above hero H1s, identical on every page: mono, uppercase,
   wide tracking, in the page accent, flanked by two 1px rules that fade
   accent→transparent. Never a pill or badge.

   `.hero-badge` is the legacy pill the old site used in the same slot, so it is
   converted in place — that lands the kicker on every existing hero for free. */
/* Block-level flex, not inline-flex: an inline-level box is positioned by its
   PARENT's `text-align`, so the six pages that centre the kicker on the element
   itself (`.page-label{text-align:center}`) dropped it to the left edge under a
   heading that was still centred — it read as though it had slipped sideways off
   the hero. As a block box with auto inline margins it centres on its own, and
   the pages that centre it from the parent are unaffected. */
.dds-kicker,
.hero-badge {
  display: flex !important;
  align-items: center;
  justify-content: center;
  width: max-content;
  max-width: 100%;
  margin-inline: auto;
  gap: clamp(10px, 1.2vw, 14px);
  margin-bottom: clamp(14px, 2vw, 22px);
  padding: 0 !important;
  border: 0 !important;
  border-radius: 0 !important;
  background: none !important;
  font-family: var(--dds-font-mono);
  font-size: clamp(10px, .9vw, 12px);
  font-weight: 500;
  letter-spacing: clamp(.24em, .5vw, .3em);
  text-transform: uppercase;
  color: var(--dds-accent-type, var(--dds-accent));
  line-height: 1.4;
}
/* Joined scripts: wide Latin tracking pulls Arabic/Hebrew letterforms apart and
   uppercase is meaningless — the kicker reads naturally there. */
[dir="rtl"] .dds-kicker, [dir="rtl"] .hero-badge { letter-spacing: .06em; text-transform: none; }
/* Opt-in start-aligned kicker (mock 3b/3c/3f run the Buy heading block flush
   left): kills the auto-centring margins and opens rule-less at the reading edge. */
.dds-kicker.dds-kicker-start { margin-inline: 0; justify-content: flex-start; }
.dds-kicker.dds-kicker-start::before { display: none; }
[dir="rtl"] .dds-kicker.dds-kicker-start::before { display: block; }
[dir="rtl"] .dds-kicker.dds-kicker-start::after { display: none; }
.dds-kicker::before, .dds-kicker::after,
.hero-badge::before, .hero-badge::after {
  content: "";
  width: clamp(26px, 4vw, 48px);
  height: 1px;
  flex-shrink: 0;
}
.dds-kicker::before, .hero-badge::before { background: linear-gradient(90deg, rgba(var(--dds-accent-rgb),0), rgba(var(--dds-accent-rgb),.55)); }
.dds-kicker::after,  .hero-badge::after  { background: linear-gradient(270deg, rgba(var(--dds-accent-rgb),0), rgba(var(--dds-accent-rgb),.55)); }

/* The kicker's flanking gradients mirror in RTL, or they point the wrong way. */
[dir="rtl"] .dds-kicker::before, [dir="rtl"] .hero-badge::before { background: linear-gradient(270deg, rgba(var(--dds-accent-rgb),0), rgba(var(--dds-accent-rgb),.55)); }
[dir="rtl"] .dds-kicker::after,  [dir="rtl"] .hero-badge::after  { background: linear-gradient(90deg,  rgba(var(--dds-accent-rgb),0), rgba(var(--dds-accent-rgb),.55)); }

/* An icon inside the kicker slot would break the rule-text-rule rhythm. */
.dds-kicker svg, .hero-badge svg { display: none; }
.dds-kicker .di, .hero-badge .di { display: none; }
/* The badge-conversion selectors need the same guard — migrate/trial shipped
   emoji in the badge string, icons.js swapped them to SVGs, and only the
   .dds-kicker half of this rule was hiding them. */
.hero > .badge svg, .hero > .pill svg, .hero-content > .badge svg,
.hero > .eyebrow svg, .hero-content > .eyebrow svg,
.hero > .badge .di, .hero > .pill .di, .hero-content > .badge .di,
.hero > .eyebrow .di, .hero-content > .eyebrow .di { display: none; }

/* Several pages put a filled PILL in the kicker slot — the one treatment the
   spec explicitly forbids ("never a pill/badge instead"). Convert any badge
   sitting directly inside a hero, so those pages get the kicker without
   per-page markup edits. */
.hero > .badge, .hero > .pill, .hero-content > .badge,
.hero > .hero-pill, .hero > .eyebrow, .hero-content > .eyebrow {
  display: flex !important;   /* block-level, so it centres itself — see above */
  align-items: center;
  justify-content: center;
  width: max-content;
  max-width: 100%;
  margin-inline: auto;
  gap: clamp(10px, 1.2vw, 14px);
  margin-bottom: clamp(14px, 2vw, 22px);
  padding: 0 !important;
  border: 0 !important;
  border-radius: 0 !important;
  background: none !important;
  font-family: var(--dds-font-mono);
  font-size: clamp(10px, .9vw, 12px);
  font-weight: 500;
  letter-spacing: clamp(.24em, .5vw, .3em);
  text-transform: uppercase;
  color: var(--dds-accent);
  line-height: 1.4;
}
.hero > .badge::before, .hero > .badge::after,
.hero > .pill::before, .hero > .pill::after,
.hero-content > .badge::before, .hero-content > .badge::after,
.hero > .eyebrow::before, .hero > .eyebrow::after,
.hero-content > .eyebrow::before, .hero-content > .eyebrow::after {
  content: "";
  width: clamp(26px, 4vw, 48px);
  height: 1px;
  flex-shrink: 0;
}
.hero > .badge::before, .hero > .pill::before,
.hero-content > .badge::before, .hero > .eyebrow::before, .hero-content > .eyebrow::before {
  background: linear-gradient(90deg, rgba(var(--dds-accent-rgb),0), rgba(var(--dds-accent-rgb),.55));
}
.hero > .badge::after, .hero > .pill::after,
.hero-content > .badge::after, .hero > .eyebrow::after, .hero-content > .eyebrow::after {
  background: linear-gradient(270deg, rgba(var(--dds-accent-rgb),0), rgba(var(--dds-accent-rgb),.55));
}

/* ── Numbered steps ───────────────────────────────────────────────────────────
   A numeral on an accent-filled disc inherited body grey, landing at 1.16:1 —
   the number was effectively invisible. Anything filled with the accent takes
   the on-accent colour. */
.step-num, .step-number, .s-num, .num-badge {
  color: var(--dds-on-accent);
}

/* ── Buttons ──────────────────────────────────────────────────────────────────
   The variant classes are listed here too, not just on the colour rule below:
   several pages mark up a button as `.btn-primary` alone, with no `.btn`, so a
   base rule keyed only on `.btn` never reached them and they kept the page's
   own font and size. */
.dds-btn, .btn,
.btn-primary, .btn-outline, .btn-secondary, .btn-gold, .btn-nav {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .5em;
  padding: 11px clamp(14px, 1.6vw, 22px);
  min-height: 44px;                     /* tap target floor */
  border: 1px solid transparent;
  border-radius: var(--dds-r-btn);
  font-family: var(--dds-font-display);
  font-weight: 700;
  font-size: clamp(12.5px, 1.1vw, 14px);
  letter-spacing: -.01em;
  line-height: 1.2;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  transition: filter .18s ease, border-color .18s ease, background-color .18s ease, transform .1s ease;
}
.dds-btn:hover, .btn:hover { filter: brightness(1.08); transform: translateY(-1px); opacity: 1; }
.dds-btn:active, .btn:active { transform: translateY(0); }

.dds-btn-primary, .btn-primary, .btn-nav, .nav-links a.btn-nav {
  background: var(--dds-cta);
  color: var(--dds-on-cta);
  border-color: transparent;
}
.dds-btn-primary:hover, .btn-primary:hover, .nav-links a.btn-nav:hover { color: var(--dds-on-cta); }

/* Secondary actions are outline-only — never a second filled colour. */
.dds-btn-outline, .btn-outline, .btn-secondary {
  background: transparent;
  color: var(--dds-text);
  /* Mock weight for outline-next-to-primary: rgba(255,255,255,.18). */
  border-color: rgba(255,255,255,.18);
}
.dds-btn-outline:hover, .btn-outline:hover, .btn-secondary:hover {
  border-color: rgba(var(--dds-cta-rgb), .55);
  color: var(--dds-text);
}

.dds-btn-gold, .btn-gold {
  /* FLAT gold: every mock frame with a gold CTA paints solid #E8B84B on
     #20160A (Beta 9a–9d, Private Pro, the migrate capsule) — the gradient was
     a system invention the pages each had to override. */
  background: var(--dds-gold);
  color: var(--dds-on-gold);
  border-color: transparent;
  box-shadow: none;
}
.dds-btn-gold:hover, .btn-gold:hover { box-shadow: 0 6px 22px rgba(232,184,75,.24); }

.btn-large, .dds-btn-lg { padding: 14px clamp(20px, 2.2vw, 30px); font-size: clamp(13.5px, 1.2vw, 15.5px); min-height: 50px; }

/* ── Cards ────────────────────────────────────────────────────────────────────
   One recipe: surface fill, hairline border, 12–20px radius. Emphasis is an
   accent border at ~30% alpha — never a different fill. */
.dds-card {
  background: var(--dds-surface);
  border: 1px solid var(--dds-border);
  border-radius: var(--dds-r-card);
  padding: clamp(18px, 2.2vw, 28px);
}
.dds-card-accent {
  border-width: 1.5px;
  border-color: rgba(var(--dds-accent-rgb), .3);
  background: linear-gradient(150deg, rgba(var(--dds-accent-rgb), .1), var(--dds-surface));
}
/* A card that hangs a badge over its edge must not clip it. */
.dds-card-badged { overflow: visible; }

.dds-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 270px), 1fr));
  gap: var(--dds-gap);
}
.dds-grid-tight { grid-template-columns: repeat(auto-fit, minmax(min(100%, 170px), 1fr)); }
.dds-grid-wide  { grid-template-columns: repeat(auto-fit, minmax(min(100%, 320px), 1fr)); }

/* ── Layout shells ────────────────────────────────────────────────────────── */
.dds-section  { padding: var(--dds-pad-y) var(--dds-pad-x); }
.dds-wrap     { max-width: var(--dds-max); margin-inline: auto; }
.dds-longform { max-width: var(--dds-measure); margin-inline: auto; padding: clamp(32px,4vw,56px) clamp(20px,4vw,40px); }
.dds-cardwrap { max-width: var(--dds-max-card); margin-inline: auto; }

/* Long-form measure: one column at every width; only padding and cap change. */
.dds-longform p,
.dds-longform li { font-size: clamp(13px, 1.15vw, 14.5px); line-height: 1.75; color: var(--dds-secondary); }
.dds-longform h2 { margin: 32px 0 12px; }
.dds-longform h3 { font-weight: 700; font-size: clamp(15px, 1.5vw, 18px); margin: 24px 0 12px; padding-bottom: 8px; border-bottom: 1px solid rgba(255,255,255,.1); }

/* Tables inside reading pages scroll rather than shrink below legibility. */
.dds-scroll-x { overflow-x: auto; border: 1px solid var(--dds-border); border-radius: 12px; -webkit-overflow-scrolling: touch; }
.dds-scroll-x > table { min-width: 440px; margin: 0; border: 0; }

/* ── Site chrome: header ──────────────────────────────────────────────────── */
nav, .dds-nav {
  background: rgba(7,8,15,.86);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border-bottom: 1px solid var(--dds-border);
}
nav .logo, .dds-logo {
  font-family: var(--dds-font-display);
  font-weight: 800;
  font-size: clamp(15px, 1.4vw, 19px);
  letter-spacing: -.02em;
  color: var(--dds-text);
}
nav .logo span, .dds-logo span { color: var(--dds-green); }
/* The brand mark: a tinted rounded tile holding the mountain stroke. One shape
   at every size, and it never renders below 26px. Always green — the per-page
   accent colours the UI, never the brand. */
.dds-mark {
  width: 30px; height: 30px; min-width: 26px;
  border-radius: 9px;
  background: linear-gradient(145deg, rgba(53,216,160,.24), rgba(53,216,160,.07));
  box-shadow: inset 0 0 0 1px rgba(53,216,160,.34);
  display: inline-flex; align-items: center; justify-content: center;
  flex-shrink: 0;
}
/* The mark is FILLED, not stroked: it is the app icon's two-peak ridge with the
   horizon band cut through it (client/lib/vista/ridge_mark.dart, same geometry as
   client/tool/render_app_icon.py). The web mark used to be a generic stroked
   mountain with no snowline at all, so the site did not carry the brand the apps
   ship. The slot is a mask rather than a painted stripe, which is what lets the
   tile's gradient show through it.

   OPTICAL SIZING — the one place the web mark DELIBERATELY diverges from
   ridge_mark.dart, so do not "restore" it. The app draws the snowline as two
   bands: solid over y104–117, then half-strength over y117–123. The web mark is
   only ever drawn in this tile — 30px, min 26px, no override anywhere on the
   site — and the glyph is 62% of it, so 200 viewBox units map to ~18.6px. That
   makes the solid band 1.2px and the half-strength band 0.56px: the first
   antialiases to a dim row and the second cannot exist at all. The peaks and the
   base fused into a single blob and the snowline read as absent, which is exactly
   how it was reported.
   So the web mark collapses the SAME zone (y104–123) into one solid slot. The
   ridge path is byte-identical to the app's — the peaks are the brand — and the
   snowline occupies the identical band; only the soft lower edge, which no
   web-sized rendering could ever show, is dropped. Verified by rendering at 26 /
   30 / 40px at 1x and comparing actual pixels, not computed styles.
   Locked by website/tests/brand-mark-snowline.test.js. */
.dds-mark svg {
  width: 62%; height: 62%;
  fill: var(--dds-green); stroke: none;
  overflow: visible;
}
nav .logo img, .dds-logo img { width: 30px; height: 30px; min-width: 26px; border-radius: 9px; }

/* ── Nav GEOMETRY — one layout everywhere, the home page is the reference ─────
   Every page carried its own nav metrics (16px/32px padding vs 0/52px, gap 16
   vs 36, heights 62–77px), so the header visibly re-arranged itself on every
   navigation. One rule now owns the geometry: logo · links (pushed left) ·
   lang · CTA, sticky, 76px on desktop. Gaps are fluid because the RU labels
   are long: fixed 36px gaps overflowed the row at ~1230px and wrapped
   "Сообщить о баге" onto a second line inside the fixed-height bar.
   :not(.toc) spares in-page semantic navs (nerds.html's table of contents);
   the partner-dashboard app shell opts back out with a higher-specificity
   re-assert in its own sheet. */
nav:not(.toc), .dds-nav {
  display: flex;
  align-items: center;
  /* 6.5vw ramps the gutter to the 88px content line by ~1360px — at the 52px
     cap the bar never aligned with the sections below it on laptop widths
     (logo x=45–52 vs content x=88), and the RU label row still fits at 1120
     with 68px of slack (measured). */
  padding: 0 clamp(20px, 6.5vw, 88px);
  gap: clamp(14px, 2.2vw, 36px);
  min-height: 64px;
  position: sticky;
  top: 0;
  z-index: 100;
  flex-wrap: nowrap;
}
@media (min-width: 701px) { nav:not(.toc), .dds-nav { height: 76px; } }
.nav-links {
  display: flex;
  align-items: center;
  gap: clamp(12px, 1.6vw, 26px);
  /* BOTH margins set: pages carry their own physical `margin-left: auto`
     (push-right), and one auto margin per side would centre the links in the
     leftover space. Logical + later in the cascade, this pins them to the
     logo's side like the home page. */
  margin-inline: 0 auto;
  flex-wrap: nowrap;
  min-width: 0;
}
/* Element ORDER, one composition everywhere (home page): logo · links · … ·
   lang pill · CTA last before the edge. Pages authored these in every DOM
   order; flex order normalizes without touching thirty files. Desktop only —
   the ≤1119px drawer keeps its own arrangement. */
@media (min-width: 1120px) {
  nav:not(.toc) .nav-links { order: 1; }
  /* `nav > .lang-btn` catches pages whose pill has no .lang-wrap container. */
  nav:not(.toc) .lang-wrap, nav:not(.toc) > .lang-btn { order: 6; }
  nav:not(.toc) > a.btn-nav, nav:not(.toc) .nav-links a.btn-nav { order: 7; }
}
/* The drawer band (≤1119): links are hidden, so the bar is logo · ☰ · lang ·
   CTA — the home page's own arrangement, with the burger's auto margin opening
   the gap. Without this the right-group clustered LEFT beside the logo at
   tablet widths (~400px of dead bar on every page at 834). */
@media (max-width: 1119px) {
  nav:not(.toc) .nav-hamburger { order: 5; margin-inline-start: auto; }
  nav:not(.toc) .lang-wrap, nav:not(.toc) > .lang-btn { order: 6; }
  nav:not(.toc) > a.btn-nav { order: 7; }
}
/* Canonical hamburger base — pages that never styled their own got the browser's
   default white button rendering IN THE DESKTOP BAR. Hidden above the drawer
   breakpoint; the ≤1119px block below re-shows it (later in file, wins the tie). */
.nav-hamburger {
  display: none;
  background: none;
  border: 0;
  color: var(--dds-text);
  font-size: 1.4rem;
  line-height: 1;
  cursor: pointer;
  padding: .25rem .5rem;
}
/* The header CTA: one pill geometry (home page reference), not per-page sizes. */
nav a.btn-nav, .nav-links a.btn-nav {
  padding: 9px 20px;
  border-radius: 10px;
  font-family: var(--dds-font-display);
  font-size: 14px;
  font-weight: 700;
  min-height: 0;
  line-height: normal;
  flex-shrink: 0;
}
.nav-links a { color: var(--dds-secondary); font-size: clamp(13px, 1.05vw, 14.5px); white-space: nowrap; }
.nav-links a:hover, .nav-links a.active:not(.btn-nav) { color: var(--dds-text); }
/* :not(.btn-nav) is load-bearing. On the page that IS the CTA's destination the
   header button carries BOTH classes, and recolouring its text to the accent
   painted accent-on-accent — a blank green pill at 1.00:1, on buy.html of all
   pages. The filled CTA already signals "here" by being filled. */
.nav-links a.active:not(.btn-nav) { color: var(--dds-cta); font-weight: 600; }

/* One switcher pill everywhere: the home page's 34px mono pill (globe · label ·
   caret). Pages had grown 29px and 44px variants of it. Coarse pointers get the
   full 44px tap floor. */
.lang-btn, .dds-langpill {
  font-family: var(--dds-font-mono);
  font-size: 12px;
  color: var(--dds-secondary);
  background: none;
  border: 1px solid var(--dds-border-strong);
  border-radius: 8px;
  padding: 6px 10px;
  display: inline-flex;
  align-items: center;
  gap: .3rem;
  min-height: 34px;
  white-space: nowrap;
  cursor: pointer;
  flex-shrink: 0;
}
@media (pointer: coarse) { .lang-btn, .dds-langpill { min-height: 44px; } }
.lang-btn:hover { border-color: rgba(var(--dds-accent-rgb), .5); color: var(--dds-text); }
.lang-drop { background: var(--dds-surface-raised); border: 1px solid var(--dds-border); border-radius: 10px; }
.lang-drop button { color: var(--dds-secondary); font-family: var(--dds-font-body); }
.lang-drop button:hover { background: rgba(var(--dds-accent-rgb), .1); color: var(--dds-text); }
.lang-drop button.active { color: var(--dds-accent); font-weight: 700; }

/* ── Hero ─────────────────────────────────────────────────────────────────── */
.hero, .dds-hero {
  position: relative;
  overflow: hidden;
  padding: var(--dds-pad-y) var(--dds-pad-x) clamp(32px, 4vw, 60px);
  text-align: center;
  /* No `background: none` here: it tied with — and erased — every page's own
     hero glow (legal's radials never rendered). Pages own their backdrop; the
     photo furniture below only mounts when the page actually ships a photo. */
}
/* Opt-in flat-photo treatment (mock 2a/2b): photo at .32 under one simple
   top-to-bottom scrim that lands on solid ground at the bottom edge. */
.hero.dds-hero-scrim .hero-bg, .dds-hero.dds-hero-scrim .dds-hero-bg { opacity: .32; }
/* :has + the variant class out-specifies the photo-furniture base below, so the
   simple scrim replaces the vignette instead of losing the tie to it. */
.hero.dds-hero-scrim:has(.hero-bg)::after, .dds-hero.dds-hero-scrim:has(.dds-hero-bg)::after {
  background: linear-gradient(180deg, rgba(7,8,15,.55) 0%, rgba(7,8,15,.72) 62%, var(--dds-bg) 100%);
}
/* And the aurora stays off in the scrim treatment — mock 2a/2b are calm. */
.hero.dds-hero-scrim:has(.hero-bg)::before, .dds-hero.dds-hero-scrim:has(.dds-hero-bg)::before { content: none; }
/* The backdrop photo and the scrim over it are ONE decision — tuning either
   alone is how the ridge disappeared twice.
   A FLAT scrim forces a bad trade: dark enough for the headline means the photo
   dies everywhere, because the text only occupies the middle third. A VIGNETTE
   puts the darkness where the text actually is and lets the ridge and the
   sunset read at the edges, so the photo can sit at .85 instead of .38.
   Measured on the rendered pixels with the text hidden, worst case across the
   headline and sub-headline bands: 8.73:1 and 8.05:1 — both above AAA (7:1),
   where the previous, far dimmer treatment scored 14.07 and 9.54. Visibility
   here cost no legibility at all. */
.hero-bg, .dds-hero-bg { opacity: .85; z-index: 0; }
.hero:has(.hero-bg)::after, .dds-hero:has(.dds-hero-bg)::after {
  content: "";
  position: absolute; inset: 0; z-index: 0;
  background:
    radial-gradient(ellipse 58% 66% at 50% 44%,
      rgba(7,8,15,.84) 0%, rgba(7,8,15,.48) 58%, rgba(7,8,15,.16) 80%),
    linear-gradient(180deg, rgba(7,8,15,0) 0%, rgba(7,8,15,.38) 74%, var(--dds-bg) 100%);
  pointer-events: none;
}
.hero > *:not(.hero-bg), .dds-hero > *:not(.dds-hero-bg) { position: relative; z-index: 2; }
.hero-sub, .dds-lede {
  font-size: clamp(13.5px, 1.3vw, 16.5px);
  line-height: 1.6;
  color: var(--dds-secondary-alt);
  max-width: 60ch;
  margin-inline: auto;
  text-wrap: pretty;
}

/* ── Stat strip ───────────────────────────────────────────────────────────── */
.dds-stat {
  background: var(--dds-surface);
  border: 1px solid var(--dds-border);
  border-radius: var(--dds-r-card);
  padding: clamp(16px, 2vw, 24px);
  text-align: center;
}
.dds-stat-value { font-family: var(--dds-font-display); font-weight: 800; font-size: clamp(22px, 2.6vw, 32px); color: var(--dds-accent); line-height: 1.1; }
.dds-stat-label { font-size: clamp(11.5px, 1vw, 13px); color: var(--dds-secondary); margin-top: 8px; }

/* ── Badges / pills ───────────────────────────────────────────────────────── */
.dds-badge {
  display: inline-flex; align-items: center; gap: 6px;
  font-family: var(--dds-font-mono);
  font-size: 10.5px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase;
  padding: 3px 9px; border-radius: var(--dds-r-pill);
  background: rgba(var(--dds-accent-rgb), .12); color: var(--dds-accent-soft);
}
.dds-badge-online { background: rgba(53,216,160,.12); color: var(--dds-green-tint); }
.dds-badge-gold   { background: rgba(232,184,75,.14); color: var(--dds-gold); }
.dds-badge-error  { background: rgba(248,113,113,.12); color: var(--dds-error); }

/* ── Forms ────────────────────────────────────────────────────────────────── */
input, select, textarea, .dds-input {
  font-family: var(--dds-font-body);
  font-size: 14px;
  color: var(--dds-text);
  background: rgba(7,8,15,.6);
  border: 1px solid var(--dds-border-strong);
  border-radius: 8px;
  padding: 11px 13px;
  min-height: 44px;
}
input::placeholder, textarea::placeholder { color: var(--dds-muted-alt); }
input:focus, select:focus, textarea:focus, .dds-input:focus {
  border-color: rgba(var(--dds-accent-rgb), .55);
  outline: none;
  box-shadow: 0 0 0 3px rgba(var(--dds-accent-rgb), .12);
}
label, .dds-label { font-size: 11.5px; font-weight: 600; color: var(--dds-secondary); }

/* ── Tables ───────────────────────────────────────────────────────────────── */
.dds-table { width: 100%; border-collapse: collapse; }
.dds-table thead th {
  text-align: start;
  padding: 11px 16px;
  font-family: var(--dds-font-mono);
  font-size: 10.5px; font-weight: 600; letter-spacing: .06em; text-transform: uppercase;
  color: var(--dds-muted);
  background: var(--dds-surface);
}
.dds-table td { padding: 11px 16px; font-size: 13.5px; color: var(--dds-body-alt); border-top: 1px solid var(--dds-hairline); }

/* ── Console shell (logged-in) ────────────────────────────────────────────── */
.dds-console { display: flex; min-height: 100vh; }
.dds-sidebar {
  width: 248px; flex-shrink: 0;
  display: flex; flex-direction: column;
  padding: 24px 18px;
  border-inline-end: 1px solid var(--dds-border);
  background: var(--dds-panel-deep);
}
.dds-sidebar a, .dds-navitem {
  display: flex; align-items: center; gap: 11px;
  padding: 10px 12px; border-radius: 9px;
  color: var(--dds-secondary); font-size: 14px;
}
.dds-sidebar a.active, .dds-navitem.active {
  background: rgba(var(--dds-cta-rgb), .12);
  color: var(--dds-cta);
  font-weight: 600;
}
/* Sidebar/list icons inherit the active colour instead of hard-coding it. */
.dds-sidebar a svg, .dds-navitem svg { width: 16px; height: 16px; flex-shrink: 0; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.dds-console-main { flex: 1; display: flex; flex-direction: column; min-width: 0; }
.dds-topbar {
  min-height: 72px;
  display: flex; align-items: center; flex-wrap: wrap; gap: 12px;
  padding: 14px clamp(18px, 3vw, 36px);
  border-bottom: 1px solid var(--dds-border);
}
.dds-console-body { flex: 1; padding: clamp(18px,2.4vw,28px) clamp(18px,3vw,36px); }
/* Dense console UI floors at 11.5px, not the 13px marketing floor. */
.dds-console-body { font-size: 13px; }

/* ── Footer ───────────────────────────────────────────────────────────────── */
footer, .dds-footer { border-top: 1px solid var(--dds-border); background: none; }
footer h4, .dds-footer h4 {
  font-family: var(--dds-font-mono);
  font-size: 11px; font-weight: 600; letter-spacing: .14em; text-transform: uppercase;
  color: var(--dds-accent);
}
footer a, .dds-footer a { color: var(--dds-body-alt); opacity: .8; font-size: 14px; }
footer a:hover, .dds-footer a:hover { opacity: 1; color: var(--dds-accent-soft); }

/* ── Icons ────────────────────────────────────────────────────────────────────
   One set: custom inline SVG, stroke-only, currentColor, round caps/joins.
   `.di-ic` is what dombay-icons.js emits when it swaps an emoji out. */
.di-ic, .dds-icon {
  fill: none;
  stroke: currentColor;
  stroke-linecap: round;
  stroke-linejoin: round;
  vertical-align: -.14em;
}
.di-ic { stroke-width: 2; width: 1em; height: 1em; }
.dds-icon-lg { width: 26px; height: 26px; stroke-width: 1.8; }

/* Card icons carry the accent. In the mockups almost every icon is drawn in an
   accent tone (#7DEBC2 dominates); these inherited body grey instead, because
   the swapped SVG uses currentColor and the holder had no colour of its own.
   Listed by the real holder classes rather than a blanket rule, so inline icons
   sitting inside a sentence keep inheriting that sentence's colour. */
.feature-icon, .f-icon, .fi-icon, .mc-icon, .dl-icon, .card-icon, .a-icon,
.platform-icon, .pillar-icon, .result-icon, .req-icon, .redeem-icon, .step-icon {
  color: var(--dds-accent-soft);
}

/* ── Third-party embeds ───────────────────────────────────────────────────────
   The Google Sign-In button is rendered by Google's script at a fixed pixel
   width. login.html now measures its slot and asks for a fitting width, but the
   button also appears inside the partner console shell, so cap the slot itself
   as a safety net: no third-party embed may be the thing that makes the page
   scroll sideways. */
#g_signin, .g_id_signin, [id*="g_signin"] { max-width: 100%; overflow: hidden; }
#g_signin > div, .g_id_signin > div { max-width: 100% !important; }

/* ── Legibility floor ─────────────────────────────────────────────────────────
   The handoff floors body text at 13px on marketing pages and 11.5px in dense
   console UI. A handful of legacy badge/pill rules sat just under it (10.9–11.2px
   from .7rem-style sizing), which is exactly the size that reads as broken on a
   phone. Raise those to the floor rather than chase each rule — bounded on both
   ends, so they never drop under 11.5px and never inflate to the parent's size
   either (these are pills, not body copy).
   The hero kicker is deliberately NOT in this list: the design specifies it at
   10–12px mono with wide tracking, and raising it would break that. */
.save-badge, .badge, .langbtn, .pill, .tag, .chip,
.pp-save, .mc-badge { font-size: clamp(11.5px, .78rem, 13px); }

/* ── Utilities ────────────────────────────────────────────────────────────── */
.dds-mono   { font-family: var(--dds-font-mono); }
.dds-hr     { height: 1px; background: rgba(255,255,255,.1); border: 0; margin: 0; }
.dds-muted  { color: var(--dds-muted); }
.dds-truncate { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Long unbreakable strings (referral links, USDT addresses, node IPs) must not
   force the page to scroll sideways. */
.dds-break  { overflow-wrap: anywhere; word-break: break-word; }

/* ═══════════════════════════════════════════════════════════════════════════
   Responsive — media queries only for what inline/fluid CSS cannot express:
   nav↔hamburger, sidebar↔drawer, table↔stacked-card, full-width CTAs.
   Everything else is clamp() / auto-fit and needs no breakpoint.
   ═══════════════════════════════════════════════════════════════════════════ */

/* 1119px — nav collapses to the hamburger, console sidebar becomes a drawer. */
@media (max-width: 1119px) {
  /* The legacy pages each collapse their own nav at 700px (some at 599), which
     left the entire tablet band showing a full desktop link row that wrapped
     into two and three stacked rows — a 168px-tall header at 834px. The design
     puts this switch at 1119px, so the shared layer moves it there for every
     page at once. Mirrors the pages' own drawer markup: `.nav-links` hidden,
     `.nav-hamburger` shown, `nav.menu-open .nav-links` as the open panel. */
  nav .nav-links { display: none; }
  nav .nav-hamburger, .nav-hamburger { display: inline-flex; }
  nav:not(.toc) { position: relative; flex-wrap: nowrap; gap: 10px; }
  nav.menu-open .nav-links {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 14px;
    position: absolute;
    inset-inline: 0;
    top: 100%;
    background: var(--dds-surface);
    border-top: 1px solid var(--dds-border);
    border-bottom: 1px solid var(--dds-border);
    padding: 18px clamp(20px, 4vw, 40px);
    z-index: 200;
    box-shadow: 0 18px 40px rgba(0,0,0,.45);
  }
  nav.menu-open .nav-links a { width: 100%; font-size: 15px; }

  .dds-sidebar {
    position: fixed; inset-block: 0; inset-inline-start: 0; z-index: 300;
    transform: translateX(-100%);
    transition: transform .22s ease;
    box-shadow: 0 0 40px rgba(0,0,0,.5);
  }
  [dir="rtl"] .dds-sidebar { transform: translateX(100%); }
  .dds-sidebar.open { transform: translateX(0); }
  .dds-drawerbtn { display: inline-flex; }
  .dds-welcome { display: none; }
}
@media (min-width: 1120px) {
  .dds-drawerbtn { display: none; }
}

/* 599px — rows stack, data tables become labelled cards, CTAs go full width. */
@media (max-width: 599px) {
  .dds-row { display: block !important; }
  .dds-row > * { width: 100% !important; text-align: start !important; }
  .dds-cta, .btn-large { display: block; width: 100%; text-align: center; }
  .dds-table thead { display: none; }
  .dds-table tr { display: block; padding: 14px 16px; border-top: 1px solid var(--dds-hairline); }
  .dds-table td { display: block; padding: 2px 0; border: 0; text-align: start; }
  .dds-table td::before {
    content: attr(data-label) " ";
    color: var(--dds-muted);
    font-size: 11px;
    margin-inline-end: 6px;
  }
  .dds-longform { padding-inline: 20px; }
}

/* Base-width header. The design calls for 20–22px page padding below 600px; the
   legacy nav hard-codes 2rem, which is what pushed the row past 320px. */
@media (max-width: 599px) {
  nav:not(.toc), .dds-nav { padding-inline: 20px; gap: 10px; }
  /* Phone bar budget: logo + burger + lang + CTA. The desktop CTA padding ran
     the row 2px past a 390px viewport on the pages that keep all four. */
  nav a.btn-nav, .nav-links a.btn-nav { padding: 8px 14px; }
}
/* On phones the filled pill blows the bar's budget (+35px at 320, and an
   8–9px RTL overflow at 390) — compact text CTA below 600px, the same
   treatment the partner chrome uses. */
@media (max-width: 599px) {
  nav:not(.toc) > a.btn-nav {
    background: none;
    color: var(--dds-cta);
    padding: 6px 6px;
  }
}

/* 379px — nothing in the header row can shrink further, so items leave the row
   rather than be squeezed. The design drops the CTA and the language pill here
   "both stay reachable from the drawer" — but on this codebase only the CTA is
   actually duplicated inside the drawer (.nav-links holds a .btn-nav Buy);
   .lang-wrap is a SIBLING of the drawer, so hiding it would strand every
   non-English visitor on a 320px phone with no way to change language.
   So: the duplicate header CTA goes, and the language control is compacted
   instead of dropped. */
@media (max-width: 429px) {   /* 429 not 379: Arabic labels ran the 390 bar 11px over */
  .nav-buy-mobile, .dds-headcta { display: none !important; }
  /* Four items + a 137px logo: the row needs every pixel, so the gaps and the
     burger's side padding give up theirs before any control leaves the bar. */
  nav:not(.toc) { gap: 6px; }
  .nav-hamburger { padding: .25rem; }
  nav .lang-btn, .dds-langpill { padding: 6px 8px; font-size: 11px; gap: 2px; }
  /* Drop the globe glyph, keep the locale code — the label is the affordance. */
  nav .lang-btn .di, nav .lang-btn > svg { display: none; }
}


/* ── Band kicker ──────────────────────────────────────────────────────────────
   The SECTION opener (mock 4a/4b): start-aligned mono label with one rule
   fading accent→transparent across the rest of the column — the hero kicker's
   one-sided sibling. Opt-in class, RTL mirrors via the logical layout. */
.dds-band-kicker {
  display: flex;
  align-items: center;
  gap: clamp(10px, 1.2vw, 14px);
  font-family: var(--dds-font-mono);
  font-size: clamp(10px, .9vw, 12px);
  font-weight: 500;
  letter-spacing: clamp(.24em, .5vw, .3em);
  text-transform: uppercase;
  color: var(--dds-accent-type, var(--dds-accent));
  line-height: 1.4;
}
.dds-band-kicker::after {
  content: "";
  flex: 1;
  height: 1px;
  background: linear-gradient(90deg, rgba(var(--dds-accent-rgb),.55), rgba(var(--dds-accent-rgb),0));
}
[dir="rtl"] .dds-band-kicker::after {
  background: linear-gradient(270deg, rgba(var(--dds-accent-rgb),.55), rgba(var(--dds-accent-rgb),0));
}
[dir="rtl"] .dds-band-kicker { letter-spacing: .06em; text-transform: none; }

/* Step numerals: the colour rule below always assumed an accent-filled disc —
   fill it here so pages stop re-painting the disc in stray purples. */
.step-num, .step-number, .s-num, .num-badge { background: var(--dds-accent); }

/* Code containers that are DIVs — `pre/code` styling cannot reach
   <div class="code-block">, which rendered config listings in the body face. */
.code-block, .dds-code {
  font-family: var(--dds-font-mono);
  font-size: .8125rem;
  line-height: 1.6;
  white-space: pre;
  overflow-x: auto;
  text-align: left;
  direction: ltr;
}

/* Wide-table guard: wrap any console/data table in this and columns scroll
   inside the card instead of silently clipping below 700px. */
.dds-table-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }


/* ── Price pair (rouble-primary + dollar reference) ───────────────────────────
   Russian-language surfaces show the admin-set rouble price first with the USD
   list price as a faded reference: 1 190 ₽  $12.99. dir=ltr pins the glyph
   order inside any bidi context. The reference takes the muted token (4.4:1
   here), never an opacity hack. Rendering is conditional on lang==ru — pages
   that fail to fetch a rouble price render today's USD-only display. */
.price-pair { display: inline-flex; align-items: baseline; gap: .45em; direction: ltr; unicode-bidi: isolate; }
.price-rub { font: inherit; color: inherit; font-variant-numeric: tabular-nums; }
.price-usd-ref { color: var(--dds-muted); font-size: .58em; font-weight: 600; font-variant-numeric: tabular-nums; }


/* Per-page hero photo level: pages declare their mock's value in one line
   (`.hero { --dds-hero-photo: .28 }`) instead of a specificity war; untouched
   pages keep .85 (the home hero's tuned level). */
.hero-bg, .dds-hero-bg { opacity: var(--dds-hero-photo, .85); }

/* Danger variant — the shared button base erased page-declared danger borders
   (equal specificity, later load) and nowrapped sentence-length labels. */
.btn-danger, .dds-btn-danger {
  background: transparent;
  color: var(--dds-error);
  border: 1px solid rgba(248, 113, 113, .4);
  white-space: normal;
  line-height: 1.3;
}
.btn-danger:hover, .dds-btn-danger:hover { border-color: rgba(248, 113, 113, .75); }

/* ASCII/box-drawing figures: the self-hosted IBM Plex Mono subset has no
   box-drawing glyphs, so mixed-face advance widths stagger every border
   (measured 1.7px line spread). These system monos cover U+2500-257F in one
   face; spread 0.000px. */
.dds-figure, .diagram {
  font-family: Menlo, Consolas, "DejaVu Sans Mono", "Liberation Mono", monospace;
}

/* ── RTL ──────────────────────────────────────────────────────────────────── */
[dir="rtl"] { text-align: right; }
/* Numerals and code stay LTR even in mirrored layouts. */
[dir="rtl"] code, [dir="rtl"] pre, [dir="rtl"] .dds-mono, [dir="rtl"] .dds-num {
  direction: ltr;
  unicode-bidi: embed;
  text-align: left;
}

/* ═══════════════════════════════════════════════════════════════════════════
   Motion
   The mocks carry a whole motion layer the build never picked up — twelve
   keyframes across ~100 elements in the Home frame alone — so the shipped site
   was completely static where the design drifts, pulses and sweeps. These are
   the mock's own keyframes, values unchanged, plus the classes to attach them.

   Everything here is decorative: it must add life without competing with the
   text, and all of it is switched off under prefers-reduced-motion below.
   ═══════════════════════════════════════════════════════════════════════════ */
@keyframes dds-aurora  { 0%{transform:translateX(-14%)} 50%{transform:translateX(14%)} 100%{transform:translateX(-14%)} }
@keyframes dds-float   { 0%,100%{transform:translateY(0)} 50%{transform:translateY(-8px)} }
@keyframes dds-pulse   { 0%,100%{box-shadow:0 0 0 0 rgba(var(--dds-accent-rgb),.5)} 70%{box-shadow:0 0 0 14px rgba(var(--dds-accent-rgb),0)} }
@keyframes dds-shimmer { 0%{transform:translateX(-140%)} 60%,100%{transform:translateX(260%)} }
@keyframes dds-rise    { 0%{transform:translateY(24px) scale(.6); opacity:0} 30%{opacity:.9} 100%{transform:translateY(-70px) scale(1); opacity:0} }
@keyframes dds-blink   { 0%,100%{opacity:.3} 50%{opacity:1} }
@keyframes dds-march   { to { background-position:26px 0 } }
@keyframes dds-ring    { 0%{transform:scale(.35); opacity:.8} 75%{opacity:.1} 100%{transform:scale(1.7); opacity:0} }

/* The hero aurora: a soft accent-tinted glow drifting across the hero.
   z-index 1 is load-bearing. At 0 it shares a stacking level with the photo and
   the scrim, and since a generated ::before paints BEFORE the element's real
   children, an .85-opacity photo covered it completely — measured at a 2-level
   pixel delta over three seconds, i.e. nothing. It now sits above the photo and
   scrim but below the content (z-index 2), so it reads as moving light on the
   ridge without touching the headline's contrast. */
/* :has(.hero-bg): the aurora and the vignette are PHOTO furniture. On a hero
   without a photo they are pure damage — a hard-edged glowing rectangle in
   narrow columns, a wash over flat mock grounds (Beta 9a–9d). */
.hero:has(.hero-bg)::before, .dds-hero:has(.dds-hero-bg)::before {
  content: "";
  position: absolute;
  inset: -25% -20% auto -20%;
  height: 95%;
  z-index: 1;
  background:
    radial-gradient(ellipse 42% 55% at 32% 45%, rgba(var(--dds-cta-rgb), .30), transparent 68%),
    radial-gradient(ellipse 38% 48% at 72% 38%, rgba(var(--dds-accent-rgb), .22), transparent 70%);
  filter: blur(46px);
  mix-blend-mode: screen;
  animation: dds-aurora 12s ease-in-out infinite;
  pointer-events: none;
}

/* A live status dot — the pulse ring the mock puts beside "no logs" claims. */
.dds-pulse, .status-dot, .live-dot {
  position: relative;
  border-radius: 50%;
  animation: dds-pulse 3.4s ease-out infinite;
}
.dds-blink { animation: dds-blink 2.2s ease-in-out infinite; }

/* A slow sweep across a filled CTA. The element needs position + overflow, so
   it is opt-in rather than applied to every button. */
.dds-shimmer { position: relative; overflow: hidden; }
.dds-shimmer::after {
  content: "";
  position: absolute; inset: 0;
  background: linear-gradient(100deg, transparent 20%, rgba(255,255,255,.28) 50%, transparent 80%);
  transform: translateX(-140%);
  animation: dds-shimmer 5s ease-in-out infinite;
  pointer-events: none;
}

.dds-float { animation: dds-float 6s ease-in-out infinite; }
/* Stagger a row of floating elements so they do not bob in lockstep. */
.dds-float:nth-child(2) { animation-delay: -1.6s; }
.dds-float:nth-child(3) { animation-delay: -3.2s; }
.dds-float:nth-child(4) { animation-delay: -4.8s; }

/* Marching dashes along a connection line — the mock's "traffic is flowing". */
.dds-march {
  background-image: linear-gradient(90deg, rgba(var(--dds-accent-rgb),.55) 0 12px, transparent 12px 26px);
  background-size: 26px 100%;
  animation: dds-march 2s linear infinite;
}

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