/* ef/fonts.css */
/* ============================================================
   Evolution Framework UI — Webfonts
   ------------------------------------------------------------
   ONE family does everything: Plus Jakarta Sans. Weight 800 for
   headings, 400–500 for body. This single-family system is the
   brand's typographic signature — clean and minimal.

   SELF-HOSTED. Four variable woff2 files live in assets/fonts/
   (latin + latin-ext, upright + italic), each covering the whole
   200–800 weight axis, and they ship inside the npm package. No
   third-party request, no CSP entry for fonts.googleapis.com, no
   flash of fallback text. See assets/fonts/README.md to re-fetch
   or update them.
   ============================================================ */

/* latin-ext — accented European characters */
@font-face {
  font-family: 'Plus Jakarta Sans';
  font-style: normal;
  font-weight: 200 800;
  font-display: swap;
  src: url('/fonts/plus-jakarta-sans-latin-ext-wght-normal.woff2') format('woff2-variations');
  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: 'Plus Jakarta Sans';
  font-style: italic;
  font-weight: 200 800;
  font-display: swap;
  src: url('/fonts/plus-jakarta-sans-latin-ext-wght-italic.woff2') format('woff2-variations');
  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;
}

/* latin */
@font-face {
  font-family: 'Plus Jakarta Sans';
  font-style: normal;
  font-weight: 200 800;
  font-display: swap;
  src: url('/fonts/plus-jakarta-sans-latin-wght-normal.woff2') format('woff2-variations');
  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: 'Plus Jakarta Sans';
  font-style: italic;
  font-weight: 200 800;
  font-display: swap;
  src: url('/fonts/plus-jakarta-sans-latin-wght-italic.woff2') format('woff2-variations');
  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;
}

/* ef/colors.css */
/* ============================================================
   Evolution Framework UI — Color tokens
   ------------------------------------------------------------
   Warm indigo primary + amber accent + teal success on a warm
   GRAY neutral ramp (Tailwind "gray", not slate). This is the
   default palette. Fully swappable: override the SEMANTIC tokens
   (--brand*, --surface-*, --text-*) in your own scope to reskin.

   Public, brief-aligned names live in the SEMANTIC ALIASES
   block (--primary, --accent, --success, --error, --bg, --text…).
   ============================================================ */

:root {
  /* color-scheme tells the BROWSER which palette to paint before any CSS of ours applies:
     the canvas, form controls and scrollbars. Without it a dark page paints white first. */
  color-scheme: light;

  /* ---- Brand: Indigo ---------------------------------- */
  --indigo-50:  #eef2ff;   /* primary-light: hover bg, tinted cards */
  --indigo-100: #e0e7ff;
  --indigo-200: #c7d2fe;   /* primary-mid: borders on tinted elements */
  --indigo-300: #a5b4fc;
  --indigo-400: #818cf8;
  --indigo-500: #6366f1;
  --indigo-600: #4f46e5;   /* PRIMARY brand */
  --indigo-700: #4338ca;
  --indigo-800: #3730a3;   /* primary-dark: hover, article hero bg */
  --indigo-900: #312e81;
  --indigo-950: #1e1b4b;

  /* ---- Accent: Amber ---------------------------------- */
  --amber-50:   #fffbeb;   /* accent-light */
  --amber-100:  #fef3c7;
  --amber-200:  #fde68a;   /* accent-mid: callout borders */
  --amber-300:  #fcd34d;
  --amber-400:  #fbbf24;
  --amber-500:  #f59e0b;   /* ACCENT */
  --amber-600:  #d97706;
  --amber-700:  #b45309;
  --amber-900:  #78350f;

  /* ---- Success: Teal ---------------------------------- */
  --teal-50:    #f0fdfa;   /* success-light */
  --teal-100:   #ccfbf1;
  --teal-200:   #99f6e4;   /* success-mid: callout borders */
  --teal-300:   #5eead4;
  --teal-400:   #2dd4bf;
  --teal-500:   #14b8a6;   /* SUCCESS */
  --teal-600:   #0d9488;
  --teal-700:   #0f766e;

  /* ---- Error: Orange ---------------------------------- */
  --orange-50:  #fff7ed;   /* error-light */
  --orange-100: #ffedd5;
  --orange-200: #fed7aa;   /* error border */
  --orange-300: #fdba74;
  --orange-400: #fb923c;
  --orange-500: #f97316;   /* ERROR */
  --orange-600: #ea580c;
  --orange-700: #c2410c;

  /* Deep red — hard "fail" only (scenario "bad" column) */
  --red-50:     #fef2f2;
  --red-100:    #fee2e2;
  --red-200:    #fecaca;
  --red-500:    #ef4444;
  --red-600:    #dc2626;
  --red-700:    #b91c1c;

  /* ---- Neutral: GRAY (warm, Tailwind gray) ------------ */
  --white:      #ffffff;
  --gray-50:    #f9fafb;   /* PAGE background */
  --gray-100:   #f3f4f6;   /* sidebar / secondary panel bg */
  --gray-200:   #e5e7eb;   /* borders, dividers */
  --gray-300:   #d1d5db;
  --gray-400:   #9ca3af;   /* placeholder, meta, timestamps */
  --gray-500:   #6b7280;   /* secondary text */
  --gray-600:   #4b5563;
  --gray-700:   #374151;
  --gray-800:   #1f2937;
  --gray-900:   #111827;   /* primary text, headings */
  --gray-950:   #030712;   /* dark: disabled field   */
  --black:      #000000;

  /* ============================================================
     SEMANTIC ALIASES — the public, brief-aligned API.
     Reach for these in product code and decks.
     ============================================================ */

  /* Core neutrals (brief names) */
  --bg:               var(--gray-50);
  --text:             var(--gray-900);
  --text-2:           var(--gray-500);
  --text-3:           var(--gray-400);
  --border:           var(--gray-200);
  --sidebar-bg:       var(--gray-100);

  /* ---- Extended aliases (used by components/kits) ----- */
  --brand:            var(--indigo-600);
  --brand-hi:            var(--indigo-500);
  /* Brand as raw channels for alpha compositing (shadows, glows, tints):
     rgb(var(--brand-rgb) / <a>). Keep in sync with --brand; a brand override
     scope (e.g. a red brand) must set this too so brand shadows follow. */
  --brand-rgb:        79 70 229;   /* = --indigo-600 (#4f46e5) */
  --brand-hover:      var(--indigo-700);
  --brand-active:     var(--indigo-800);
  --brand-ink:        var(--indigo-900);
  --brand-subtle:     var(--indigo-50);
  --brand-subtle-2:   var(--indigo-100);
  --brand-border:     var(--indigo-200);
  --on-brand:         var(--white);

  /* Text */
  --text-strong:      var(--gray-900);   /* headings        */
  --text-body:        var(--gray-700);   /* paragraph copy  */
  --text-muted:       var(--gray-500);   /* secondary       */
  --text-faint:       var(--gray-400);   /* meta, captions  */
  --text-on-dark:     var(--gray-50);
  --text-inverse:     var(--white);
  --text-link:        var(--indigo-600);

  /* Surfaces */
  --surface-page:     var(--gray-50);    /* warm page bg    */
  --surface-subtle:   var(--gray-100);   /* alt section bg / row hover */
  --surface-header:   var(--gray-50);    /* table & list header bands — a light tint, lighter than the row hover so the two stay distinct */
  --surface-card:     var(--white);
  --surface-sunken:   var(--gray-100);   /* inputs, wells   */
  --surface-ink:      var(--gray-900);   /* dark sections   */
  --surface-ink-2:    var(--indigo-800); /* dark indigo     */

  /* Borders / dividers */
  --border-strong:    var(--gray-300);
  --border-faint:     var(--gray-100);
  --ring:             var(--indigo-500);

  /* Form controls — the filled field rhythm shared by every input-shaped
     control (Input, Textarea, Select, MultiSelect, the pickers…). A resting
     field is a soft fill plus a HAIRLINE border: the fill carries the rhythm
     so a column of fields still reads as quiet blocks, and the hairline is
     what keeps the field legible off a white card — the fill alone can't,
     since it is only one step off the surfaces fields sit on. Hover
     strengthens the border and focus lifts the fill to the card surface.

     LIGHT uses --surface-page (gray-50), not --surface-sunken (gray-100):
     sunken read heavy against a white card, and the hairline now carries the
     edge so the fill doesn't have to. DARK keeps --surface-sunken — there the
     field must read as a well cut INTO the card, and --field-bg-disabled is
     already --surface-page, so pointing the resting fill there too would
     collapse disabled into resting.

     Focus LIFTS, disabled SINKS — a disabled field must never end up lighter
     than a live one, or it reads as the active field. Redeclare this group in
     any theme scope that redefines the surfaces it points at. */
  --field-bg:            var(--surface-page);
  --field-bg-focus:      var(--surface-card);
  --field-bg-disabled:   var(--gray-200);
  --field-border:        var(--border);
  --field-border-hover:  var(--border-strong);
  --field-border-focus:  var(--brand);
  --field-shadow:        none;

  /* Status (semantic, brief-aligned) */
  --success-bg:       var(--teal-50);
  --warning:          var(--amber-500);
  --warning-ink:         var(--amber-700);
  --warning-bg:       var(--amber-50);
  --on-warning:       var(--amber-900);
  --danger:           var(--orange-500);
  --destructive:       var(--red-600);
  --destructive-hi:      var(--red-500);
  --destructive-ink:     var(--red-700);
  --danger-ink:          var(--orange-700);
  --danger-bg:        var(--orange-50);


  /* ============================================================
     Brief-name COLOR aliases — LIGHT-MODE shortcuts.
     Point at palette PRIMITIVES, matching the light values of
     their semantic twins (--primary ≡ light --brand, etc). They
     are deliberately NOT var(--brand)/var(--warning): those
     semantic tokens are redefined in later-loaded theme scopes
     ([data-theme] in theme-dark.css), and an :root alias whose
     target is conditionally redefined in a later sheet collapses
     to the invalid (empty) value in the CSS engine — which blanks
     anything colored var(--primary). Because they are primitives
     they do NOT follow dark theme or a brand reskin: for anything
     that must re-theme, use the semantic names (--brand*, --warning,
     --danger). Reskinning a brand? Override --primary*
     alongside --brand* in your scope.
     ============================================================ */

  /* Primary action / brand (brief names) */
  --primary:          var(--indigo-600);
  --primary-light:    var(--indigo-50);
  --primary-mid:      var(--indigo-200);
  --primary-dark:     var(--indigo-800);

  /* Accent (brief names) */
  --accent:           var(--amber-500);
  --accent-light:     var(--amber-50);
  --accent-mid:       var(--amber-200);

  /* Success / Error (brief names) */
  --success:          var(--teal-500);
  --success-ink:         var(--teal-700);
  --success-light:    var(--teal-50);
  --success-mid:      var(--teal-200);
  --positive:         #16a34a;
  --error:            var(--orange-500);
  --error-light:      var(--orange-50);

  /* ---- Categorical chart series -----------------------------------------
     Eight slots for "which series is this", assigned IN ORDER and never
     cycled. Slot 1 is --brand, so a single-series chart keeps the hue it has
     always had and gaining a second series never repaints the first.

     These are NOT the status colours, and must never be swapped for them:
     --warning/--success/--danger are amber/teal/orange and MEAN something, so
     a teal series would read as "good". That reservation is why slots 2-8 are
     their own hues rather than a reshuffle of the four ramps above.

     Validated as a set against the light chart surface (--surface-card,
     #ffffff): every slot inside the lightness band and over the chroma floor,
     worst adjacent CVD ΔE 9.1, worst adjacent normal-vision ΔE 19.6. Three
     slots (3, 4, 5) sit under 3:1 contrast on white, which obliges a visible
     label or a table view alongside — charts here keep value labels on by
     default for that reason.

     Re-validate with the dataviz skill's validate_palette.js before changing
     ANY value: the order is load-bearing (dropping slot 7 puts green next to
     red and drops the worst adjacent pair to 7.2). A ninth series is not a
     ninth hue — fold it into "Other" or facet the chart. */
  --chart-1:  var(--brand);
  --chart-2:  #eb6834;
  --chart-3:  #1baf7a;
  --chart-4:  #eda100;
  --chart-5:  #e87ba4;
  --chart-6:  #008300;
  --chart-7:  #4a3aa7;
  --chart-8:  #e34948;

  /* ---- Sequential chart series (ORDERED data only) -----------------------
     ONE hue, stepped, starting AT the brand and getting lighter. Slot 1 is
     --brand itself, so the first series of an ordered set looks exactly like the
     single-series default and each later step recedes from it.

     Use it when the series have an inherent ORDER — Q1→Q4, 2024→2026, age
     buckets — because a ramp encodes that order and distinct hues destroy it:
     nothing says orange follows indigo. For unordered identities (You / Team /
     Competitor) keep --chart-*; a ramp there invents a ranking not in the data.

     FOUR slots, and four is the ceiling in this direction. Running lighter from
     the brand means every step moves toward the surface, so the ramp runs out of
     contrast rather than out of hue: validated in ordinal mode against #ffffff
     with monotone lightness, all gaps >= 0.06, light end 2.35:1 (2:1 floor) and
     1 degree of hue spread — but a fifth step lands at 1.81:1 and fails.

     Slot 4 is a tint BETWEEN indigo-400 and indigo-300 rather than a ramp step,
     because indigo-300 itself measures 1.99:1 on white — one hundredth under the
     floor. Re-run the validator in ordinal mode before changing any value.

     Slots 2-4 are primitives/tints and do NOT follow a --brand override; a
     reskin that changes the brand hue must redeclare this group. */
  --chart-seq-1:  var(--brand);
  --chart-seq-2:  var(--indigo-500);
  --chart-seq-3:  var(--indigo-400);
  --chart-seq-4:  #9aa2fa;
}

/* ef/theme-dark.css */
/* ============================================================
   Evolution Framework UI — Dark theme
   ------------------------------------------------------------
   A GLOBAL theme (unlike `.ef-on-ink`, which is a local dark
   island inside a light page). It re-assigns the SAME semantic
   token names the light theme defines in :root — so every
   component that reads tokens flips automatically.

   How themes work here (the theming contract):
   • Palette primitives (--gray-*, --indigo-*, …) are constant.
   • The SEMANTIC tokens (--brand, --text-*, --surface-*, …) are
     the theming API. A "theme" is just a scope that sets them.
       – Light  = :root                (tokens/colors.css)
       – Dark   = [data-theme="dark"]   (this file)
   • A different BRAND (e.g. red instead of indigo) is another
     scope overriding the accent tokens (--brand*, --ring,
     --text-link). It composes with light/dark.

   Activation:
   • Light (default):  nothing on :root; force with <html data-theme="light">
     (explicit light scope resets tokens even inside a dark/auto ancestor)
   • Dark (explicit):  <html data-theme="dark">  (or on any subtree)
   • Auto (follow OS): <html data-theme="auto">  → dark when the
     OS is in dark mode, light otherwise.
   ============================================================ */

/* Explicit force-light — resets the semantic tokens to their :root (light)
   values, so `data-theme="light"` re-themes to light even inside a dark or
   auto ancestor (or a dark-OS environment). Mirrors tokens/colors.css :root. */
[data-theme="light"] {
  color-scheme: light;
  --bg:               var(--gray-50);
  --text:             var(--gray-900);
  --text-2:           var(--gray-500);
  --text-3:           var(--gray-400);
  --border:           var(--gray-200);
  --sidebar-bg:       var(--gray-100);

  --brand:            var(--indigo-600);
  --brand-hover:      var(--indigo-700);
  --brand-active:     var(--indigo-800);
  --brand-ink:        var(--indigo-900);
  --brand-subtle:     var(--indigo-50);
  --brand-subtle-2:   var(--indigo-100);
  --brand-border:     var(--indigo-200);
  --on-brand:         var(--white);

  --text-strong:      var(--gray-900);
  --text-body:        var(--gray-700);
  --text-muted:       var(--gray-500);
  --text-faint:       var(--gray-400);
  --text-on-dark:     var(--gray-50);
  --text-inverse:     var(--white);
  --text-link:        var(--indigo-600);

  --surface-page:     var(--gray-50);
  --surface-subtle:   var(--gray-100);
  --surface-header:   var(--gray-50);
  --surface-card:     var(--white);
  --surface-sunken:   var(--gray-100);
  --surface-ink:      var(--gray-900);
  --surface-ink-2:    var(--indigo-800);

  --border-strong:    var(--gray-300);
  --border-faint:     var(--gray-100);
  --ring:             var(--indigo-500);

  --field-bg:            var(--surface-page);
  --field-bg-focus:      var(--surface-card);
  --field-bg-disabled:   var(--gray-200);
  --field-border:        var(--border);
  --field-border-hover:  var(--border-strong);
  --field-border-focus:  var(--brand);
  --field-shadow:        none;

  --success-bg:       var(--teal-50);
  --warning:          var(--amber-500);
  --warning-bg:       var(--amber-50);
  --danger:           var(--orange-500);
  --danger-bg:        var(--orange-50);


  --shadow-sm:        0 1px 4px rgba(79, 70, 229, 0.06), 0 1px 2px rgba(17, 24, 39, 0.05);
  --shadow:           0 2px 16px rgba(79, 70, 229, 0.08), 0 1px 4px rgba(0, 0, 0, 0.05);
  --shadow-md:        0 2px 16px rgba(79, 70, 229, 0.08), 0 1px 4px rgba(0, 0, 0, 0.05);
  --shadow-lg:        0 8px 40px rgba(79, 70, 229, 0.13), 0 2px 8px rgba(0, 0, 0, 0.07);
  --shadow-xl:        0 16px 56px rgba(79, 70, 229, 0.16), 0 4px 12px rgba(0, 0, 0, 0.08);
}

/* Explicit opt-in — works on :root or any subtree (so a single
   region can be dark, and demos can scope it). */
[data-theme="dark"] {
  color-scheme: dark;
  /* Core neutrals (brief names) */
  --bg:               var(--gray-950);
  --text:             var(--gray-50);
  --text-2:           var(--gray-400);
  --text-3:           var(--gray-500);
  --border:           rgba(255, 255, 255, 0.12);
  --sidebar-bg:       var(--gray-900);

  /* Brand — keep fills saturated for white-text contrast; links/tints lighten */
  --brand:            var(--indigo-500);
  --brand-hover:      var(--indigo-400);
  --brand-active:     var(--indigo-300);
  --brand-ink:        var(--indigo-100);
  --brand-subtle:     rgba(129, 140, 248, 0.18);
  --brand-subtle-2:   rgba(129, 140, 248, 0.26);
  --brand-border:     rgba(129, 140, 248, 0.35);
  --on-brand:         var(--white);

  /* Text */
  --text-strong:      var(--white);
  --text-body:        var(--gray-200);
  --text-muted:       var(--gray-400);
  --text-faint:       var(--gray-500);
  --text-on-dark:     var(--gray-50);
  --text-inverse:     var(--gray-900);
  --text-link:        var(--indigo-300);

  /* Surfaces — page darkest, canvas above it, cards raised lighter, fields inset */
  --surface-page:     var(--gray-900);
  --surface-subtle:   var(--gray-900);
  --surface-header:   var(--gray-700);
  --surface-card:     var(--gray-800);
  --surface-sunken:   var(--gray-900);
  --surface-ink:      var(--black);
  --surface-ink-2:    var(--indigo-900);

  /* Borders / dividers / focus */
  --border-strong:    rgba(255, 255, 255, 0.24);
  --border-faint:     rgba(255, 255, 255, 0.07);
  --ring:             var(--indigo-400);

  --field-bg:            var(--surface-sunken);
  --field-bg-focus:      var(--surface-card);
  --field-bg-disabled:   var(--gray-950);   /* sinks below the resting fill, which is now the page grey */
  --field-border:        var(--border);
  --field-border-hover:  var(--border-strong);
  --field-border-focus:  var(--brand);
  --field-shadow:        none;

  /* Status — hues stay saturated; backgrounds go translucent */
  --success-bg:       rgba(45, 212, 191, 0.16);
  --warning:          var(--amber-500);
  --warning-bg:       rgba(245, 158, 11, 0.16);
  --danger:           var(--orange-500);
  --danger-bg:        rgba(249, 115, 22, 0.16);


  /* Elevation — on dark, shadows read as deeper black, not indigo tint */
  --shadow-sm:        0 1px 2px rgba(0, 0, 0, 0.4);
  --shadow:           0 2px 8px rgba(0, 0, 0, 0.45);
  --shadow-md:        0 2px 12px rgba(0, 0, 0, 0.5);
  --shadow-lg:        0 12px 32px rgba(0, 0, 0, 0.55);
  --shadow-xl:        0 24px 64px rgba(0, 0, 0, 0.6);

  /* Glass — smoked dark frost instead of translucent white */
  --glass-bg:         rgba(30, 34, 48, 0.55);
  --glass-bg-strong:  rgba(30, 34, 48, 0.75);
  --glass-bg-bar:     rgba(20, 24, 36, 0.6);
  --glass-border:     var(--border-hairline) solid rgba(255, 255, 255, 0.12);
  --glass-highlight:  inset 0 1px 0 rgba(255, 255, 255, 0.10); /* @kind shadow */
  --glass-shadow:     var(--glass-highlight), 0 10px 30px rgba(0, 0, 0, 0.5), 0 2px 6px rgba(0, 0, 0, 0.4);

  /* ---- Categorical chart series (dark steps) ------------------------------
     The same eight hues re-stepped for the dark chart surface (--surface-card,
     gray-800) — a selected set, never an automatic flip of the light values.
     Slot 1 stays --brand, which is indigo-500 here.
     Validated against #1f2937: all eight inside the dark lightness band, worst
     adjacent CVD ΔE 8.4, worst adjacent normal-vision ΔE 19.3. See the note in
     tokens/colors.css before touching any value or the order. */
  --chart-1:  var(--brand);
  --chart-2:  #d95926;
  --chart-3:  #199e70;
  --chart-4:  #c98500;
  --chart-5:  #d55181;
  --chart-6:  #008300;
  --chart-7:  #9085e9;
  --chart-8:  #e66767;

  /* ---- Sequential chart series (dark) ------------------------------------
     The ramp REVERSES on a dark surface: prominence belongs to the
     lightest step there, so slot 1 is the palest rather than the deepest.
     Validated in ordinal mode against #1f2937 — monotone, all gaps >= 0.06,
     end step 2.33:1 on the surface, hue spread 3 degrees. Five slots, as light. */
  --chart-seq-1:  var(--brand);
  --chart-seq-2:  var(--indigo-400);
  --chart-seq-3:  var(--indigo-300);
  --chart-seq-4:  var(--indigo-200);
}

/* Auto — follow the OS. Opt in with data-theme="auto". */
@media (prefers-color-scheme: dark) {
  [data-theme="auto"] {
    color-scheme: dark;
    --bg:               var(--gray-950);
    --text:             var(--gray-50);
    --text-2:           var(--gray-400);
    --text-3:           var(--gray-500);
    --border:           rgba(255, 255, 255, 0.12);
    --sidebar-bg:       var(--gray-900);

    --brand:            var(--indigo-500);
    --brand-hover:      var(--indigo-400);
    --brand-active:     var(--indigo-300);
    --brand-ink:        var(--indigo-100);
    --brand-subtle:     rgba(129, 140, 248, 0.18);
    --brand-subtle-2:   rgba(129, 140, 248, 0.26);
    --brand-border:     rgba(129, 140, 248, 0.35);
    --on-brand:         var(--white);

    --text-strong:      var(--white);
    --text-body:        var(--gray-200);
    --text-muted:       var(--gray-400);
    --text-faint:       var(--gray-500);
    --text-on-dark:     var(--gray-50);
    --text-inverse:     var(--gray-900);
    --text-link:        var(--indigo-300);

    --surface-page:     var(--gray-900);
    --surface-subtle:   var(--gray-900);
    --surface-header:   var(--gray-700);
    --surface-card:     var(--gray-800);
    --surface-sunken:   var(--gray-900);
    --surface-ink:      var(--black);
    --surface-ink-2:    var(--indigo-900);

    --border-strong:    rgba(255, 255, 255, 0.24);
    --border-faint:     rgba(255, 255, 255, 0.07);
    --ring:             var(--indigo-400);

    --field-bg:            var(--surface-sunken);
    --field-bg-focus:      var(--surface-card);
    --field-bg-disabled:   var(--gray-950);   /* sinks below the resting fill, which is now the page grey */
    --field-border:        var(--border);
    --field-border-hover:  var(--border-strong);
    --field-border-focus:  var(--brand);
    --field-shadow:        none;

    --success-bg:       rgba(45, 212, 191, 0.16);
    --warning:          var(--amber-500);
    --warning-bg:       rgba(245, 158, 11, 0.16);
    --danger:           var(--orange-500);
    --danger-bg:        rgba(249, 115, 22, 0.16);


    --shadow-sm:        0 1px 2px rgba(0, 0, 0, 0.4);
    --shadow:           0 2px 8px rgba(0, 0, 0, 0.45);
    --shadow-md:        0 2px 12px rgba(0, 0, 0, 0.5);
    --shadow-lg:        0 12px 32px rgba(0, 0, 0, 0.55);
    --shadow-xl:        0 24px 64px rgba(0, 0, 0, 0.6);

    --glass-bg:         rgba(30, 34, 48, 0.55);
    --glass-bg-strong:  rgba(30, 34, 48, 0.75);
    --glass-bg-bar:     rgba(20, 24, 36, 0.6);
    --glass-border:     var(--border-hairline) solid rgba(255, 255, 255, 0.12);
    --glass-highlight:  inset 0 1px 0 rgba(255, 255, 255, 0.10); /* @kind shadow */
    --glass-shadow:     var(--glass-highlight), 0 10px 30px rgba(0, 0, 0, 0.5), 0 2px 6px rgba(0, 0, 0, 0.4);

    /* ---- Categorical chart series (dark steps) ------------------------------
       The same eight hues re-stepped for the dark chart surface (--surface-card,
       gray-800) — a selected set, never an automatic flip of the light values.
       Slot 1 stays --brand, which is indigo-500 here.
       Validated against #1f2937: all eight inside the dark lightness band, worst
       adjacent CVD ΔE 8.4, worst adjacent normal-vision ΔE 19.3. See the note in
       tokens/colors.css before touching any value or the order. */
    --chart-1:  var(--brand);
    --chart-2:  #d95926;
    --chart-3:  #199e70;
    --chart-4:  #c98500;
    --chart-5:  #d55181;
    --chart-6:  #008300;
    --chart-7:  #9085e9;
    --chart-8:  #e66767;

    /* ---- Sequential chart series (dark) ------------------------------------
       The ramp REVERSES on a dark surface: prominence belongs to the
       lightest step there, so slot 1 is the palest rather than the deepest.
       Validated in ordinal mode against #1f2937 — monotone, all gaps >= 0.06,
       end step 2.33:1 on the surface, hue spread 3 degrees. Five slots, as light. */
    --chart-seq-1:  var(--brand);
    --chart-seq-2:  var(--indigo-400);
    --chart-seq-3:  var(--indigo-300);
    --chart-seq-4:  var(--indigo-200);
  }
}

/* ef/typography.css */
/* ============================================================
   Evolution Framework UI — Typography tokens
   ------------------------------------------------------------
   SINGLE family: Plus Jakarta Sans does everything — display,
   UI, body. Headings always weight 800 with negative tracking;
   body 400–500. Generous line-heights for the airy,
   negative-space aesthetic. No monospace — this is a
   one-family system by design.
   ============================================================ */

/* ---- Root font size ------------------------------------
   The ENTIRE system is rem-anchored to this one value — the
   type scale below, plus spacing, radii and component sizing
   are all rem, so this is the single lever that scales the
   whole UI proportionally (type and whitespace together).
   Set as a % so it scales from — and respects — the user's
   browser default rather than a fixed px, keeping zoom and
   accessibility intact. 106.25% of the 16px browser default =
   a 17px base. A consuming app can override this default by
   setting its own `html` / `:root { font-size }` after
   importing styles.css. */
html {
  font-size: 106.25%; /* 16px browser default → 17px base */
}

/* ---- Base content reset -------------------------------------------------
   Raw markup in a page — a <p>, an <h2>, a <ul>, a link — should already look
   like this design system, so pages carry content without a wrapper class or a
   hand-rolled type rule for every block. Components are NOT affected: each one
   classes the elements it renders and sets its own size/margin, and a class
   selector (0,1,0) always beats an element selector (0,0,1). Every one of the
   38 bare elements the library renders was checked against this.

   Anything needing a different size still reaches for a --text-* token; this is
   only the sensible default so the common case needs no CSS at all. */
body {
  margin: 0;
  font-family: var(--font-sans);
  font-size: var(--text-base);
  line-height: var(--leading-normal);
  color: var(--text-body);
  -webkit-font-smoothing: antialiased;
}

/* Block rhythm — margin-block so adjacent blocks collapse predictably, and the
   first/last child never pushes its container open. */
p, ul, ol, blockquote, figure, pre {
  margin: 0 0 var(--space-4);
}

h1, h2, h3, h4, h5, h6 {
  margin: 0 0 var(--space-3);
  font-weight: var(--fw-extra);
  letter-spacing: var(--tracking-tight);
  line-height: var(--leading-snug);
  color: var(--text-strong);
  text-wrap: balance;
}

h1 { font-size: var(--text-4xl); }
h2 { font-size: var(--text-3xl); }
h3 { font-size: var(--text-2xl); }
h4 { font-size: var(--text-xl); }
h5 { font-size: var(--text-lg); }
h6 { font-size: var(--text-base); }

/* A heading that follows body copy needs air above it; the first one in a
   container does not. */
* + h1, * + h2, * + h3, * + h4, * + h5, * + h6 {
  margin-top: var(--space-8);
}

ul, ol {
  padding-left: var(--space-6);
}

li {
  margin-bottom: var(--space-2);
}

li:last-child {
  margin-bottom: 0;
}

/* Markers recede so the item text carries the list — weight and whitespace do
   the hierarchy, not colour. Opt a single list up to brand markers with
   `.ef-markers-brand` (tokens/utilities.css); nested lists stay faint there too. */
li::marker {
  color: var(--text-faint);
}

/* Nested lists sit tight to their parent item. */
li > ul, li > ol {
  margin: var(--space-2) 0 0;
}

a {
  color: var(--text-link);
  text-decoration: underline;
  text-underline-offset: 0.15em;
  text-decoration-thickness: 0.06em;
}

a:hover {
  text-decoration-thickness: 0.12em;
}

a:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
  border-radius: var(--radius-xs);
}

/* Small print — a tagline, a footnote, the line under a wordmark. Prose, not the
   inline UI scrap the .ef-* utilities are for, so it gets an element rather than a
   pair of classes. The browser default is 0.8em of the parent and inherits colour,
   which compounds when nested and ignores the scale; this pins it to both. */
small {
  font-size: var(--text-sm);
  color: var(--text-muted);
}

/* The last block in a container shouldn't add trailing space — containers own
   their own padding. */
p:last-child, ul:last-child, ol:last-child,
h1:last-child, h2:last-child, h3:last-child,
h4:last-child, h5:last-child, h6:last-child {
  margin-bottom: 0;
}

:root {
  /* ---- Family (one family, system fallback) ---------- */
  --font: 'Plus Jakarta Sans', system-ui, -apple-system, 'Segoe UI',
          Roboto, Helvetica, Arial, sans-serif;
  --font-sans: var(--font);
  --font-display: var(--font);

  /* ---- Weights --------------------------------------- */
  --fw-regular:  400; /* @kind other */
  --fw-medium:   500; /* @kind other */
  --fw-semibold: 600; /* @kind other */
  --fw-bold:     700; /* @kind other */
  --fw-extra:    800; /* @kind other */

  /* ---- Type scale (rem). px comments are at the 16px
         browser baseline; the shipped root (html 106.25%)
         renders them ×1.0625 larger — e.g. base = 17px. ---- */
  --text-2xs:  0.6875rem;  /* 11px — micro labels        */
  --text-xs:   0.75rem;    /* 12px — meta, eyebrow        */
  --text-sm:   0.875rem;   /* 14px — secondary UI         */
  --text-base: 1rem;       /* 16px — body                 */
  --text-lg:   1.125rem;   /* 18px — lead body            */
  --text-xl:   1.25rem;    /* 20px — small headings       */
  --text-2xl:  1.5rem;     /* 24px                        */
  --text-3xl:  1.875rem;   /* 30px                        */
  --text-4xl:  2.25rem;    /* 36px                        */
  --text-5xl:  3rem;       /* 48px                        */
  --text-6xl:  3.75rem;    /* 60px — hero display         */
  --text-7xl:  4.5rem;     /* 72px — XL hero              */

  /* ---- Line heights ---------------------------------- */
  --leading-none:    1;       /* @kind other */
  --leading-tight:   1.1;     /* @kind other */
  --leading-snug:    1.25;    /* @kind other */
  --leading-normal:  1.5;     /* @kind other */
  --leading-relaxed: 1.65;    /* @kind other */

  /* ---- Letter spacing -------------------------------- */
  --tracking-tighter: -0.03em;  /* @kind other */
  --tracking-tight:   -0.015em; /* @kind other */
  --tracking-normal:  0;        /* @kind other */
  --tracking-wide:    0.02em;   /* @kind other */
  --tracking-eyebrow: 0.12em;   /* @kind other */
}

/* ef/spacing.css */
/* ============================================================
   Evolution Framework UI — Spacing & layout tokens
   ------------------------------------------------------------
   4px base grid. Generous section rhythm for the airy,
   negative-space marketing aesthetic.
   ============================================================ */

:root {
  /* ---- Space scale (4px base) ------------------------ */
  --space-0:   0;
  --space-1:   0.25rem;   /* 4px  */
  --space-2:   0.5rem;    /* 8px  */
  --space-3:   0.75rem;   /* 12px */
  --space-4:   1rem;      /* 16px */
  --space-5:   1.25rem;   /* 20px */
  --space-6:   1.5rem;    /* 24px */
  --space-8:   2rem;      /* 32px */
  --space-10:  2.5rem;    /* 40px */
  --space-12:  3rem;      /* 48px */
  --space-16:  4rem;      /* 64px */
  --space-20:  5rem;      /* 80px */
  --space-24:  6rem;      /* 96px */
  --space-32:  8rem;      /* 128px */

  /* ---- Section rhythm -------------------------------- */
  --section-y:       var(--space-24);  /* vertical padding per marketing section */
  --section-y-tight: var(--space-16);

  /* ---- Container widths ------------------------------ */
  --container-sm:  640px;
  --container-md:  768px;
  --container-lg:  1024px;
  --container-xl:  1200px;   /* primary marketing max-width */
  --container-2xl: 1320px;
  --gutter:        var(--space-6);
}

/* ef/elevation.css */
/* ============================================================
   Evolution Framework UI — Elevation: radii, borders, shadows
   ------------------------------------------------------------
   The shadow system is INDIGO-TINTED — a key brand detail. Card
   shadows subtly reinforce the primary color rather than using
   neutral gray. Radius scale in practice: controls (buttons,
   inputs, pickers, rows) sit at 6–8px (xs/sm); panels take
   --radius-panel (12px by default); hero CTAs at 24px (xl).
   ============================================================ */

:root {
  /* ---- Radii (controls 6–8 · panels via --radius-panel · hero CTA 24 · pill) */
  --radius-xs:   6px;     /* buttons, inputs, pickers, rows   */
  --radius-sm:   8px;     /* small controls, chips, grips     */
  --radius-md:   12px;    /* mid-step (sparingly used)        */
  --radius-lg:   16px;    /* the roomier step — opt in per case */
  --radius-xl:   24px;    /* hero CTAs, inline CTA blocks      */
  --radius-2xl:  28px;    /* hero panels                      */
  --radius-full: 100px;   /* pills, tags, badges, avatars     */

  /* The radius of a bordered PANEL surface — Card, Table, List, Stat, Modal,
     Popover, the picker popovers, the dropdown surfaces (Menu, SelectMenu,
     MultiSelect, Autocomplete, DropdownButton), Accordion, MediaCard, Quote,
     PageHeading, Alert, Toast, the Code block and the ActivityFeed card all
     point here rather than at a step of the scale.
     That makes panel rounding ONE lever: override this in your own scope to
     re-round every surface at once, without collapsing --radius-md into
     --radius-lg or editing a dozen components. */
  --radius-panel: var(--radius-md);

  /* brief-named aliases */
  --radius:      var(--radius-md);

  /* ---- Border widths --------------------------------- */
  --border-hairline: 0.5px;   /* iOS-crisp hairline — glass edges, dividers */
  --border-1: 1px;
  --border-2: 2px;

  /* ---- Shadows (INDIGO-TINTED — the brand signature) -- */
  --shadow-xs:  0 1px 2px rgba(17, 24, 39, 0.05);
  --shadow-sm:  0 1px 4px rgb(var(--brand-rgb) / 0.06), 0 1px 2px rgba(17, 24, 39, 0.05);
  --shadow:     0 2px 16px rgb(var(--brand-rgb) / 0.08), 0 1px 4px rgba(0, 0, 0, 0.05);
  --shadow-md:  0 2px 16px rgb(var(--brand-rgb) / 0.08), 0 1px 4px rgba(0, 0, 0, 0.05);
  --shadow-lg:  0 8px 40px rgb(var(--brand-rgb) / 0.13), 0 2px 8px rgba(0, 0, 0, 0.07);
  --shadow-xl:  0 16px 56px rgb(var(--brand-rgb) / 0.16), 0 4px 12px rgba(0, 0, 0, 0.08);

  /* Warm (amber) glow — accent button hover */
  --shadow-warm:  0 4px 24px rgba(245, 158, 11, 0.18), 0 1px 4px rgba(0, 0, 0, 0.05);

  /* Brand glow — primary CTAs */
  --shadow-brand:    0 12px 28px rgb(var(--brand-rgb) / 0.32);
  --shadow-brand-sm: 0 6px 16px rgb(var(--brand-rgb) / 0.24);

  /* Soft, wide brand glow — selected cards / haloed emphasis. Wide blur so it fans
     out gently; low alpha + barely any spread so it stays a whisper, not a halo. */
  --shadow-brand-glow:    0 12px 44px 1px rgb(var(--brand-rgb) / 0.14);
  --shadow-brand-glow-lg: 0 18px 56px 2px rgb(var(--brand-rgb) / 0.20);

  /* Soft brand panel shadow — an accent surface (form panels, emphasised cards):
     a wide low-alpha indigo glow lifted off a subtle neutral drop shadow. */
  --shadow-brand-soft: 0 8px 40px rgb(var(--brand-rgb) / 0.10), 0 2px 8px rgba(0, 0, 0, 0.05);

  /* Focus ring */
  --ring-width: 3px;
  --ring-color: rgba(99, 102, 241, 0.40);
  --focus-ring: 0 0 0 var(--ring-width) var(--ring-color);

  /* ============================================================
     iOS / GLASS — frosted-glass surface system
     ------------------------------------------------------------
     A frosted-glass surface system: a
     translucent white pane over an ambient mesh, blurred and
     saturated, edged with a hairline and an inset top highlight.
     Apply --glass-blur via backdrop-filter (it is the value, not
     the property) alongside --glass-bg / --glass-border / --glass-shadow.
     ============================================================ */
  --glass-bg:          rgba(255, 255, 255, 0.62);
  --glass-bg-strong:   rgba(255, 255, 255, 0.80);  /* tiles, icon wells */
  --glass-bg-bar:      rgba(255, 255, 255, 0.50);  /* nav / tab bars     */
  --glass-blur:        blur(22px) saturate(180%); /* @kind other */
  --glass-blur-bar:    blur(30px) saturate(200%); /* @kind other */  /* floating bars */
  --glass-border:      var(--border-hairline) solid rgba(255, 255, 255, 0.80);
  --glass-highlight:   inset 0 1px 0 rgba(255, 255, 255, 0.85); /* @kind shadow */  /* top sheen */
  --glass-shadow:      var(--glass-highlight), 0 10px 30px rgb(var(--brand-rgb) / 0.08), 0 2px 6px rgba(17, 24, 39, 0.04);

  /* ---- Gradient CTA — elevated primary button -------- */
  --gradient-brand:     linear-gradient(180deg, #6366F1, #4F46E5); /* @kind color */
  --shadow-brand-cta:   0 10px 22px rgb(var(--brand-rgb) / 0.38);

  /* ---- Ambient mesh — app/page background ------------ */
  --bg-mesh:
    radial-gradient(50% 36% at 92% 4%, rgba(245, 158, 11, 0.09), transparent 60%),
    radial-gradient(60% 50% at 50% 100%, rgba(20, 184, 166, 0.07), transparent 65%),
    var(--gray-100);

  /* ---- Layering ----------------------------------------------------------
     One scale for everything that floats, because the alternative is what this
     replaced: a literal per component, and a DateRangePicker that sat at 40 while
     its six siblings sat at 900 — under the sticky Navbar's 50, so the top bar
     painted straight over an open calendar. A named step makes that drift visible
     in review instead of at runtime.

     Order matters and is the whole point: a field's panel must clear the app
     chrome; a Drawer/Modal must clear both; a Toast must clear the Drawer that
     raised it; and the skip link must clear everything, since it is the one thing
     a keyboard user needs before anything else. */
  --z-nav:      50;    /* @kind other */  /* sticky Navbar               */
  --z-popover:  900;   /* @kind other */  /* field panels, Menu          */
  --z-overlay:  1000;  /* @kind other */  /* Drawer, Modal, Popover      */
  --z-toast:    1100;  /* @kind other */  /* above an open overlay       */
  --z-tooltip:  1200;  /* @kind other */  /* transient, beats the toast  */
  --z-skip:     2000;  /* @kind other */  /* the skip link beats all      */
}

/* site.css */
/* ============================================================
   DotSafe website
   ------------------------------------------------------------
   The Evolution Framework tokens in css/ef/ come first in the
   bundle. They give Light (:root), Dark ([data-theme="dark"])
   and Auto ([data-theme="auto"], which follows the device).
   This file adds Terminal and Pink with the same token names,
   with the values of the app (ios/Preferences.swift).
   All components below read tokens only.
   ============================================================ */

/* ---- Site tokens, Light ------------------------------------ */
:root {
  --page-bg:
    radial-gradient(1100px 620px at 8% -8%, rgb(199 210 254 / 0.55), transparent 70%),
    radial-gradient(900px 560px at 100% 4%, rgb(251 207 232 / 0.45), transparent 70%),
    var(--surface-page);
  --glass: rgb(255 255 255 / 0.72);
  --glass-border: rgb(255 255 255 / 0.9);
  --nav-bg: rgb(249 250 251 / 0.78);
  --bezel: #111827;
  --halo: 0.2;
  --code-bg: var(--surface-subtle);
}

/* ---- Dark --------------------------------------------------- */
[data-theme="dark"] {
  --page-bg:
    radial-gradient(1100px 620px at 8% -8%, rgb(79 70 229 / 0.22), transparent 70%),
    radial-gradient(900px 560px at 100% 4%, rgb(124 58 237 / 0.14), transparent 70%),
    var(--gray-950);
  --glass: rgb(31 41 55 / 0.72);
  --glass-border: rgb(255 255 255 / 0.08);
  --nav-bg: rgb(3 7 18 / 0.72);
  --bezel: #000;
  --halo: 0.28;
  --code-bg: rgb(255 255 255 / 0.06);
}
@media (prefers-color-scheme: dark) {
  [data-theme="auto"] {
    --page-bg:
      radial-gradient(1100px 620px at 8% -8%, rgb(79 70 229 / 0.22), transparent 70%),
      radial-gradient(900px 560px at 100% 4%, rgb(124 58 237 / 0.14), transparent 70%),
      var(--gray-950);
    --glass: rgb(31 41 55 / 0.72);
    --glass-border: rgb(255 255 255 / 0.08);
    --nav-bg: rgb(3 7 18 / 0.72);
    --bezel: #000;
    --halo: 0.28;
    --code-bg: rgb(255 255 255 / 0.06);
  }
}

/* ---- Terminal: bright green on near-black, monospaced ------- */
[data-theme="terminal"] {
  color-scheme: dark;
  --font: ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
  --brand: #39ff88;
  --brand-hi: #6affa6;
  --brand-rgb: 57 255 136;
  --brand-hover: #6affa6;
  --brand-active: #97f2b4;
  --brand-ink: #c4ffd6;
  --brand-subtle: rgb(57 255 136 / 0.1);
  --brand-subtle-2: rgb(57 255 136 / 0.16);
  --brand-border: #2d5e3f;
  --on-brand: #002a12;
  --text-strong: #c4ffd6;
  --text-body: #97f2b4;
  --text-muted: #62c98a;
  --text-faint: #41905f;
  --text-link: #39ff88;
  --text-on-dark: #c4ffd6;
  --surface-page: #050805;
  --surface-card: #0a110c;
  --surface-subtle: #0f1a12;
  --surface-sunken: #0f1a12;
  --surface-header: #0a110c;
  --surface-ink: #000;
  --border: #1c3826;
  --border-faint: #13281a;
  --border-strong: #2d5e3f;
  --ring: #39ff88;
  --shadow-sm: none;
  --shadow: none;
  --shadow-md: none;
  --shadow-lg: 0 0 0 1px #1c3826;
  --shadow-xl: 0 0 0 1px #1c3826;
  --shadow-brand: 0 0 24px rgb(57 255 136 / 0.25);
  --shadow-brand-sm: 0 0 12px rgb(57 255 136 / 0.2);
  --tracking-tight: 0;
  --tracking-tighter: -0.01em;
  --page-bg: #050805;
  --glass: #0a110c;
  --glass-border: #1c3826;
  --nav-bg: rgb(5 8 5 / 0.9);
  --bezel: #000;
  --halo: 0.25;
  --code-bg: #0f1a12;
}

/* ---- Pink: soft pinks, rounded type -------------------------- */
[data-theme="pink"] {
  color-scheme: light;
  --font: ui-rounded, "SF Pro Rounded", "Nunito", "Varela Round", system-ui, -apple-system, sans-serif;
  --brand: #d63384;
  --brand-hi: #e8559b;
  --brand-rgb: 214 51 132;
  --brand-hover: #b0246b;
  --brand-active: #8a1d55;
  --brand-ink: #5a1840;
  --brand-subtle: #ffe1ee;
  --brand-subtle-2: #ffd3e6;
  --brand-border: #f3aacb;
  --on-brand: #fff;
  --text-strong: #5a1840;
  --text-body: #7a2c58;
  --text-muted: #a1517f;
  --text-faint: #c27a9f;
  --text-link: #d63384;
  --surface-page: #fff5f9;
  --surface-card: #fff;
  --surface-subtle: #ffe8f1;
  --surface-sunken: #ffe8f1;
  --surface-header: #fff5f9;
  --surface-ink: #5a1840;
  --border: #ffd3e6;
  --border-faint: #ffe6f0;
  --border-strong: #f3aacb;
  --ring: #e8559b;
  --page-bg:
    radial-gradient(1000px 600px at 0% 0%, rgb(255 211 230 / 0.9), transparent 70%),
    radial-gradient(900px 600px at 100% 10%, rgb(245 208 254 / 0.6), transparent 70%),
    linear-gradient(180deg, #fff5f9, #ffe8f1);
  --glass: rgb(255 255 255 / 0.7);
  --glass-border: rgb(255 255 255 / 0.95);
  --nav-bg: rgb(255 245 249 / 0.8);
  --bezel: #5a1840;
  --halo: 0.2;
  --code-bg: #ffe8f1;
}

/* ---- Base ---------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }

html { scroll-behavior: smooth; -webkit-text-size-adjust: 100%; }
html[data-theme="terminal"] { font-size: 100%; }

body {
  min-height: 100vh;
  background: var(--page-bg);
  background-attachment: fixed;
  color: var(--text-body);
  overflow-x: hidden;
}

img { max-width: 100%; height: auto; }

a { color: var(--text-link); text-underline-offset: 0.18em; text-decoration-thickness: 1px; }
a:hover { color: var(--brand-hover); }

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

.skip {
  position: absolute; left: -9999px; top: 0;
  background: var(--surface-card); color: var(--text-strong); padding: var(--space-2) var(--space-4); z-index: 100;
}
.skip:focus { left: var(--space-4); top: var(--space-4); }

.container { width: 100%; max-width: 1120px; margin: 0 auto; padding: 0 var(--space-5); }
.container-narrow { max-width: 760px; }

h1 { font-size: clamp(2.25rem, 5vw + 0.5rem, 3.75rem); line-height: var(--leading-tight); letter-spacing: var(--tracking-tighter); }
h2 { font-size: clamp(1.75rem, 2.5vw + 0.75rem, 2.5rem); line-height: var(--leading-tight); }
h3 { font-size: var(--text-xl); }

.eyebrow {
  display: inline-block;
  margin-bottom: var(--space-3);
  font-size: var(--text-xs); font-weight: var(--fw-bold);
  letter-spacing: var(--tracking-eyebrow); text-transform: uppercase;
  color: var(--brand);
}
.lead { font-size: var(--text-lg); line-height: var(--leading-relaxed); color: var(--text-muted); max-width: 40em; }
.muted { color: var(--text-muted); }
.small { font-size: var(--text-sm); }

/* ---- Wordmark ------------------------------------------------
   "dotsafe": "d" and "t" in the brand colour, a brand dot with a
   halo for the "o", and "safe" in ink (Brand.swift). The dot has
   the width of an "o" and sits on the baseline. */
.wordmark {
  display: inline-flex; align-items: baseline;
  font-family: var(--font); font-weight: var(--fw-extra);
  font-size: 1.5rem; letter-spacing: 0; line-height: 1;
  color: var(--text-strong); text-decoration: none;
  isolation: isolate;
}
.wordmark .wm-brand { color: var(--brand); }
.wordmark .wm-dot {
  position: relative; display: inline-block;
  /* 0.65em is the advance of an "o" in Plus Jakarta Sans ExtraBold. The dot drops below the
     baseline by 3% of its width, as a round letter does. */
  width: 0.65em; height: 0.65em; margin-bottom: -0.02em;
  border-radius: 50%; background: var(--brand);
}
.wordmark .wm-dot::before {
  content: ""; position: absolute; inset: -25%; z-index: -1;
  border-radius: 50%; background: var(--brand); opacity: var(--halo);
}
.wordmark .wm-t { margin-left: -0.05em; }
[data-theme="terminal"] .wordmark .wm-dot { width: 0.6em; height: 0.6em; }

/* ---- Buttons ------------------------------------------------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--space-2);
  min-height: 48px; padding: 0 var(--space-6);
  border: 1px solid transparent; border-radius: var(--radius-full);
  font: inherit; font-weight: var(--fw-bold); font-size: var(--text-base);
  text-decoration: none; cursor: pointer; white-space: nowrap;
  transition: background-color 0.15s, color 0.15s, border-color 0.15s, transform 0.15s;
}
.btn:active { transform: translateY(1px); }
.btn-primary { background: var(--brand); color: var(--on-brand); box-shadow: var(--shadow-brand-sm); }
.btn-primary:hover { background: var(--brand-hover); color: var(--on-brand); }
.btn-secondary { background: var(--glass); color: var(--text-strong); border-color: var(--border); }
.btn-secondary:hover { border-color: var(--border-strong); color: var(--text-strong); }
.btn-sm { min-height: 38px; padding: 0 var(--space-4); font-size: var(--text-sm); }
.btn svg { width: 1.15em; height: 1.15em; flex: none; }
.cta-row { display: flex; flex-wrap: wrap; gap: var(--space-3); align-items: center; }
.cta-note { margin-top: var(--space-4); font-size: var(--text-sm); color: var(--text-muted); }

/* ---- Nav ----------------------------------------------------- */
.nav {
  position: sticky; top: 0; z-index: 50;
  background: var(--nav-bg);
  -webkit-backdrop-filter: saturate(1.6) blur(14px); backdrop-filter: saturate(1.6) blur(14px);
  border-bottom: 1px solid var(--border-faint);
}
.nav-row { display: flex; align-items: center; gap: var(--space-6); height: 64px; }
.nav-brand { display: inline-flex; text-decoration: none; }
.nav-links { display: flex; gap: var(--space-5); margin-left: auto; }
.nav-links a { color: var(--text-body); text-decoration: none; font-weight: var(--fw-medium); font-size: var(--text-sm); }
.nav-links a:hover, .nav-links a[aria-current="page"] { color: var(--brand); }
@media (max-width: 720px) {
  .nav-row { gap: var(--space-3); }
  .nav-links { display: none; }
  .nav-cta { margin-left: auto; }
}

/* ---- Sections ------------------------------------------------ */
.section { padding: var(--space-20) 0; }
.section-tight { padding: var(--space-12) 0; }
.section-head { max-width: 680px; margin-bottom: var(--space-10); }
.section-head.center { margin-left: auto; margin-right: auto; text-align: center; }
.section-head.center .lead { margin-left: auto; margin-right: auto; text-wrap: balance; }
@media (max-width: 720px) { .section { padding: var(--space-16) 0; } }

/* ---- Hero ----------------------------------------------------
   Large type beside a stage: the pattern demo, with the things
   a vault keeps around it. */
.hero { padding: var(--space-20) 0 var(--space-12); }
.hero h1 { margin-bottom: var(--space-5); }
.hero .lead { margin-bottom: var(--space-8); }
.hero-copy { text-align: center; position: relative; }
.hero-copy h1 {
  font-size: clamp(2.75rem, 6vw + 0.5rem, 5.75rem); line-height: 1.02;
  letter-spacing: -0.035em; color: var(--text-strong); text-wrap: balance;
}
.hero-copy .lead { text-wrap: balance; margin-left: auto; margin-right: auto; font-size: clamp(1.0625rem, 0.5vw + 1rem, 1.3125rem); max-width: 34em; }
.hero-copy .cta-row { justify-content: center; }
[data-theme="terminal"] .hero-copy h1 { letter-spacing: -0.02em; }
.hero-demo { position: relative; isolation: isolate; overflow: hidden; padding: var(--space-16) 0 var(--space-12); }
.hero-stage { margin-top: var(--space-6); }

/* Three soft colour fields that move slowly behind the hero. */
.aurora { position: absolute; inset: 0; z-index: -1; pointer-events: none; }
.aurora i {
  position: absolute; width: 46vw; aspect-ratio: 1; border-radius: 50%;
  background: radial-gradient(closest-side, rgb(var(--brand-rgb, 99 102 241) / 0.28), transparent);
  animation: aurora 18s ease-in-out infinite alternate;
}
.aurora i:nth-child(1) { left: -12vw; top: -10%; }
.aurora i:nth-child(2) { right: -14vw; top: 10%; background: radial-gradient(closest-side, rgb(236 72 153 / 0.2), transparent); animation-delay: -6s; }
.aurora i:nth-child(3) { left: 30vw; top: 48%; animation-delay: -12s; }
@keyframes aurora { from { translate: 0 0; scale: 1; } to { translate: 6vw 4vh; scale: 1.2; } }
[data-theme="terminal"] .aurora i:nth-child(2) { background: radial-gradient(closest-side, rgb(57 255 136 / 0.12), transparent); }

/* ---- The tour in the hero phone ------------------------------
   Real screens stacked in the phone. site.js shows one at a time,
   moves a finger over them, zooms the photo and copies a password. */
.tour { position: relative; }
.tour .scr { position: absolute; inset: 0; display: block; opacity: 0; transform: translateY(2%); transition: opacity 0.4s ease, transform 0.45s cubic-bezier(0.2, 0.7, 0.2, 1); }
.tour .scr-media { position: relative; opacity: 1; transform: none; }
.tour .scr.on { opacity: 1; transform: none; }
.tour .scr-photo { transform: scale(0.35); transform-origin: var(--from, 84% 42%); }
.tour .scr-photo.on { transform: none; }
.tour .scr-sheet { opacity: 1; transform: translateY(100%); transition: transform 0.5s cubic-bezier(0.2, 0.7, 0.2, 1); }
.tour .scr-bar { transform: none; }

/* A sheet screen in two layers (sheet() in build-site.ts). The sheet starts 6.6% down the
   screenshot, under the status bar. */
.scr-bar img { clip-path: inset(0 0 93.4% 0); }
.scr-sheet img { clip-path: inset(6.6% 0 0 0); }
.zoom { position: absolute; left: 0; right: 0; top: var(--zoom-top, 21.7%); height: var(--zoom-height, 56.6%); overflow: hidden; }
.zoom img { display: block; width: 100%; height: 100%; object-fit: cover; border-radius: 0; transform-origin: 50% 32%; transition: transform 1.3s cubic-bezier(0.3, 0.7, 0.2, 1); }
.zoom.zooming img { transform: scale(2.1); }
/* In the tour the zoomed photo grows past its frame and fills the screen, as a pinch does on
   the device. The phone frame clips it. */
.tour .zoom { overflow: visible; }
.tour .zoom img { transform-origin: 50% 38%; }
.finger {
  position: absolute; z-index: 5; width: 34px; height: 34px; margin: -17px 0 0 -17px; border-radius: 50%;
  background: rgb(255 255 255 / 0.55); border: 2px solid rgb(17 24 39 / 0.25); box-shadow: 0 4px 14px rgb(0 0 0 / 0.25);
  opacity: 0; transition: left 0.55s cubic-bezier(0.3, 0.7, 0.2, 1), top 0.55s cubic-bezier(0.3, 0.7, 0.2, 1), opacity 0.25s, scale 0.15s;
}
.finger.show { opacity: 1; }
.finger.press { scale: 0.75; background: rgb(var(--brand-rgb, 99 102 241) / 0.5); }

/* The field beside the phone where the password is pasted. */
.paste {
  position: absolute; z-index: 4; left: calc(100% + 28px); top: 52%; width: 230px;
  display: flex; flex-direction: column; gap: 6px; padding: var(--space-4);
  border-radius: 20px; background: var(--surface-card); border: 1px solid var(--border-faint); box-shadow: var(--shadow-xl);
  opacity: 0; translate: -12px 0; transition: opacity 0.35s, translate 0.35s;
}
.paste.show { opacity: 1; translate: 0 0; }
.paste small { color: var(--text-muted); font-size: var(--text-xs); }
.paste-label { color: var(--text-strong); font-size: var(--text-sm); font-weight: var(--fw-bold); }
.paste-field {
  display: flex; align-items: center; height: 40px; padding: 0 12px; border-radius: 10px;
  border: 2px solid var(--brand); background: var(--surface-page); color: var(--text-strong); letter-spacing: 0.15em;
}
.paste-field i { width: 2px; height: 20px; background: var(--brand); animation: caret 1s steps(1) infinite; }
@keyframes caret { 50% { opacity: 0; } }
.paste-menu {
  position: absolute; left: 24px; top: 36px; padding: 6px 12px; border-radius: 8px;
  background: rgb(17 24 39 / 0.92); color: #fff; font-size: 12px; font-weight: var(--fw-bold);
  opacity: 0; transition: opacity 0.2s;
}
.paste.menu .paste-menu { opacity: 1; }
@media (max-width: 1100px) { .paste { left: 50%; top: auto; bottom: -6%; translate: -50% 12px; } .paste.show { translate: -50% 0; } }

/* The rows in the hero mix photos, records and documents. */
.drift-mixed .drift-track { align-items: center; }
.drift-mixed .drift-track img { width: 200px; height: 200px; border-radius: 26px; }
.drift .fchip, .drift .rchip { position: static; flex: none; animation: none; }
.drift-phone .demo { width: 280px; }
.drift-phone .demo .phone { width: 100%; }
@media (max-width: 720px) {
  .drift-mixed .drift-track img { width: 128px; height: 128px; border-radius: 18px; }
  .drift-phone .demo { width: 236px; }
}

/* ---- The pattern demo in the hero ----------------------------
   A lock screen over the media screenshot. Draw 4 or more dots
   and it opens. site.js draws a pattern by itself until someone
   touches it. */
.demo { position: relative; z-index: 2; width: 264px; }
.demo .phone { width: 100%; }
.demo-lock {
  position: absolute; inset: 7px; border-radius: 31px; z-index: 2;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: var(--space-8);
  background: var(--page-bg); overflow: hidden;
  touch-action: none; user-select: none; -webkit-user-select: none;
  transition: opacity 0.5s ease, transform 0.6s cubic-bezier(0.2, 0.7, 0.2, 1);
}
.demo-lock .wordmark { font-size: 1.75rem; margin-top: -8%; }
.demo-grid { width: 82%; overflow: visible; cursor: crosshair; }
.demo-dots circle { fill: var(--text-faint); opacity: 0.6; transform-box: fill-box; transform-origin: center; transition: transform 0.2s cubic-bezier(0.3, 1.6, 0.5, 1), fill 0.15s; }
.demo-dots circle.on { fill: var(--brand); opacity: 1; transform: scale(1.6); filter: drop-shadow(0 0 6px rgb(var(--brand-rgb, 99 102 241) / 0.6)); }
.demo-line { fill: none; stroke: var(--brand); stroke-width: 6; stroke-linecap: round; stroke-linejoin: round; opacity: 0.9; }
.demo-hint { margin: 0; min-height: 1.5em; font-size: var(--text-sm); font-weight: var(--fw-semibold); color: var(--text-muted); }
.demo.open .demo-lock { opacity: 0; transform: scale(1.12); pointer-events: none; }
.demo.shake .demo-grid { animation: shake 0.4s; }
@keyframes shake { 20%, 60% { translate: -6px 0; } 40%, 80% { translate: 6px 0; } }
.demo-relock {
  position: absolute; z-index: 3; left: 50%; bottom: 13%; translate: -50% 0;
  padding: 8px 20px; border: 0; border-radius: var(--radius-full); cursor: pointer;
  background: var(--brand); color: var(--on-brand); font: inherit; font-size: var(--text-sm); font-weight: var(--fw-bold);
  box-shadow: var(--shadow-lg);
}
@media (max-width: 720px) { .demo { width: 240px; } .demo-lock { gap: var(--space-6); } }

.btn-lg { min-height: 56px; padding: 0 var(--space-8); font-size: var(--text-lg); }
@media (max-width: 420px) { .btn-lg { width: 100%; padding: 0 var(--space-4); font-size: var(--text-base); } }

/* Apple's badge, at its own proportions. Apple asks for clear space of a quarter of its height. */
.store-badge { display: inline-block; line-height: 0; margin: 4px 0; transition: transform 0.15s, opacity 0.15s; }
.store-badge:hover { opacity: 0.85; }
.store-badge:active { transform: translateY(1px); }
.store-badge img { height: 56px; width: auto; }
.cta-band .store-badge img { height: 52px; }
.store-badge .badge-white { display: none; }
[data-theme="dark"] .store-badge .badge-black, [data-theme="terminal"] .store-badge .badge-black { display: none; }
[data-theme="dark"] .store-badge .badge-white, [data-theme="terminal"] .store-badge .badge-white { display: block; }
@media (prefers-color-scheme: dark) {
  [data-theme="auto"] .store-badge .badge-black { display: none; }
  [data-theme="auto"] .store-badge .badge-white { display: block; }
}
.btn-ghost { background: transparent; color: var(--text-link); }
.btn-ghost:hover { color: var(--brand-hover); }

@keyframes float { 0%, 100% { translate: 0 0; } 50% { translate: 0 -10px; } }

/* A full-width tinted band, to set a section apart from the one before it. */
.section-tint { background: var(--surface-subtle); border-top: 1px solid var(--border-faint); border-bottom: 1px solid var(--border-faint); }
[data-theme="dark"] .section-tint { background: rgb(255 255 255 / 0.03); }
@media (prefers-color-scheme: dark) { [data-theme="auto"] .section-tint { background: rgb(255 255 255 / 0.03); } }
[data-theme="pink"] .section-tint { background: rgb(255 255 255 / 0.55); }

/* ---- Privacy: what the app connects to ------------------------- */
.net { position: relative; max-width: 900px; aspect-ratio: 900 / 380; margin: 0 auto var(--space-12); }
.net-lines { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
.net-lines path { fill: none; stroke-width: 2.5; }
.net-lines .ok { stroke: var(--brand); stroke-dasharray: 2 8; stroke-linecap: round; opacity: 0.7; animation: net-flow 1.2s linear infinite; }
.net-lines .no { stroke: var(--border-strong); stroke-dasharray: 6 8; opacity: 0.6; }
.net-lines .pkt { fill: var(--brand); filter: drop-shadow(0 0 6px rgb(var(--brand-rgb, 99 102 241) / 0.8)); }
@keyframes net-flow { to { stroke-dashoffset: -20; } }
.net-node {
  position: absolute; translate: -50% -50%; display: flex; flex-direction: column; align-items: center; text-align: center;
  padding: 12px 18px; border-radius: 18px; background: var(--surface-card); border: 1px solid var(--border-faint); box-shadow: var(--shadow-lg);
  min-width: 150px;
}
.net-node b { color: var(--text-strong); font-size: var(--text-sm); }
.net-node small { color: var(--text-muted); font-size: var(--text-xs); }
.net-device { left: 50%; top: 50%; padding: 18px 26px; border: 2px solid var(--brand); box-shadow: var(--shadow-xl), 0 0 0 8px var(--brand-subtle); }
.net-device b { font-size: var(--text-lg); }
.net-ic { display: grid; place-items: center; width: 44px; height: 44px; margin-bottom: 6px; border-radius: 14px; background: var(--brand); color: var(--on-brand); }
.net-ic svg { width: 22px; height: 22px; }
.net-a { left: 18.9%; top: 21%; } .net-b { left: 18.9%; top: 79%; }
.net-c { left: 81.1%; top: 15.8%; } .net-d { left: 81.1%; top: 50%; } .net-e { left: 81.1%; top: 84.2%; }
/* What the app never connects to: a dashed box with a centred cross, and a stop bar on its line. */
.net-x {
  flex-direction: row; align-items: center; gap: var(--space-3); text-align: left;
  background: var(--surface-card); border: 1.5px dashed var(--border-strong); box-shadow: none;
}
.net-x { min-width: 200px; }
.net-x span { display: flex; flex-direction: column; white-space: nowrap; }
.net-x b { color: var(--text-body); }
.no-ic { position: relative; flex: none; width: 30px; height: 30px; border-radius: 50%; background: rgb(229 72 77 / 0.14); }
.no-ic::before, .no-ic::after {
  content: ""; position: absolute; left: 50%; top: 50%; width: 13px; height: 2.5px; border-radius: 2px;
  background: #e5484d; translate: -50% -50%; rotate: 45deg;
}
.no-ic::after { rotate: -45deg; }
/* The four promises sit in one dark panel, so they stand out from the light page. */
.privacy-tiles {
  position: relative; overflow: hidden; display: grid; grid-template-columns: repeat(4, 1fr);
  border-radius: 32px; background: var(--surface-ink); box-shadow: var(--shadow-xl);
}
.privacy-tiles::before {
  content: ""; position: absolute; inset: -40% -10% auto; height: 120%; pointer-events: none;
  background: radial-gradient(closest-side, rgb(var(--brand-rgb, 99 102 241) / 0.35), transparent); animation: aurora 18s ease-in-out infinite alternate;
}
.privacy-tiles > div { position: relative; padding: var(--space-10) var(--space-8); }
.privacy-tiles > div + div { border-left: 1px solid rgb(255 255 255 / 0.1); }
.privacy-tiles .icon {
  width: 56px; height: 56px; border-radius: 18px; margin-bottom: var(--space-6);
  background: var(--brand); color: var(--on-brand); box-shadow: 0 0 0 8px rgb(var(--brand-rgb, 99 102 241) / 0.2), 0 0 32px rgb(var(--brand-rgb, 99 102 241) / 0.6);
}
.privacy-tiles .icon svg { width: 26px; height: 26px; }
.privacy-tiles h3 { font-size: var(--text-xl); color: #fff; margin-bottom: var(--space-2); }
.privacy-tiles p { color: rgb(255 255 255 / 0.68); font-size: var(--text-sm); margin: 0; }
[data-theme="dark"] .privacy-tiles { background: #000; border: 1px solid rgb(255 255 255 / 0.08); }
[data-theme="pink"] .privacy-tiles { background: var(--brand-ink); }
[data-theme="terminal"] .privacy-tiles { background: #000; border: 1px solid var(--border); }
[data-theme="terminal"] .privacy-tiles h3 { color: var(--text-strong); }
[data-theme="terminal"] .privacy-tiles p { color: var(--text-body); }
@media (max-width: 900px) { .privacy-tiles { grid-template-columns: repeat(2, 1fr); } .privacy-tiles > div:nth-child(3) { border-left: 0; } .privacy-tiles > div:nth-child(n+3) { border-top: 1px solid rgb(255 255 255 / 0.1); } }
@media (max-width: 720px) {
  .net { aspect-ratio: auto; display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-3); }
  .net-lines { display: none; }
  .net-node { position: relative; left: auto; top: auto; translate: none; min-width: 0; }
  .net-x { grid-column: 1 / -1; min-width: 0; }
  .net-device { grid-column: 1 / -1; }
  .privacy-tiles { grid-template-columns: 1fr; }
  .privacy-tiles > div + div { border-left: 0; border-top: 1px solid rgb(255 255 255 / 0.1); }
}

/* ---- Big section type ---------------------------------------- */
.section-xl { padding: var(--space-24) 0; }
@media (max-width: 720px) { .section-xl { padding: var(--space-16) 0; } }
.display {
  font-size: clamp(2rem, 3vw + 0.75rem, 3.25rem); line-height: 1.1; text-wrap: balance;
  letter-spacing: -0.035em; color: var(--text-strong); margin-bottom: var(--space-5);
}
[data-theme="terminal"] .display { letter-spacing: -0.01em; }
.section-head .display + .lead, .feature-copy .lead { font-size: clamp(1.0625rem, 0.4vw + 1rem, 1.25rem); }
.center { justify-content: center; text-align: center; }
.center-link { text-align: center; margin-top: var(--space-8); }

/* Show each block as it scrolls into view. boot.js adds "js", and site.js adds "in". */
.js .reveal { opacity: 0; transform: translateY(28px); transition: opacity 0.8s ease, transform 0.8s cubic-bezier(0.2, 0.7, 0.2, 1); }
.js .reveal.in { opacity: 1; transform: none; }

.badges { display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-5); margin-top: var(--space-8); padding: 0; list-style: none; }
.badges li { display: inline-flex; align-items: center; gap: var(--space-2); font-size: var(--text-sm); font-weight: var(--fw-semibold); color: var(--text-muted); margin: 0; }
.badges li::before { content: ""; width: 7px; height: 7px; border-radius: 50%; background: var(--brand); box-shadow: 0 0 0 4px var(--brand-subtle); }

.pills { display: flex; flex-wrap: wrap; justify-content: center; gap: var(--space-2); margin: var(--space-10) 0 0; padding: 0; list-style: none; }
.pills li { margin: 0; padding: 8px 16px; border-radius: var(--radius-full); background: var(--glass); border: 1px solid var(--border); font-size: var(--text-sm); font-weight: var(--fw-semibold); color: var(--text-body); }

/* ---- Photos drift behind the vault ---------------------------
   Two rows of photos move in opposite directions behind a large
   phone. Each track holds its photos twice, so a move of half its
   width loops without a jump. */
.drift-stage { position: relative; display: grid; place-items: center; margin-top: var(--space-6); }
.drift {
  position: absolute; inset: 50% 0 auto; translate: 0 -50%;
  left: 50%; width: 100vw; margin-left: -50vw;
  display: grid; gap: var(--space-4);
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
}
.drift-row { overflow: hidden; }
.drift-track { display: flex; gap: var(--space-4); width: max-content; animation: drift 90s linear infinite; }
.drift-back .drift-track { animation-direction: reverse; animation-duration: 110s; }
.drift-track img { width: 260px; height: 260px; flex: none; object-fit: cover; border-radius: 28px; }
@keyframes drift { from { translate: 0 0; } to { translate: calc(-50% - var(--space-2)) 0; } }
.drift-phone { position: relative; z-index: 1; padding: var(--space-6) 0; }
.drift-phone .phone {
  width: 300px;
  box-shadow: 0 0 0 10px rgb(255 255 255 / 0.55), 0 40px 80px -20px rgb(17 24 39 / 0.45), 0 0 120px rgb(var(--brand-rgb, 99 102 241) / 0.35);
}
[data-theme="dark"] .drift-phone .phone, [data-theme="terminal"] .drift-phone .phone { box-shadow: 0 0 0 10px rgb(255 255 255 / 0.06), 0 40px 80px -20px #000, 0 0 120px rgb(var(--brand-rgb, 99 102 241) / 0.3); }
@media (prefers-color-scheme: dark) { [data-theme="auto"] .drift-phone .phone { box-shadow: 0 0 0 10px rgb(255 255 255 / 0.06), 0 40px 80px -20px #000, 0 0 120px rgb(99 102 241 / 0.3); } }
[data-theme="terminal"] .drift-track img { filter: grayscale(1) sepia(1) hue-rotate(70deg) saturate(2.2) brightness(0.75); }
@media (max-width: 720px) {
  .drift { gap: var(--space-3); }
  .drift-track { gap: var(--space-3); }
  .drift-track img { width: 150px; height: 150px; border-radius: 18px; }
  .drift-phone .phone { width: 220px; }
}

/* ---- Feature grid: two columns of cards with moving pictures --- */
.bento { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--space-5); }
.bento-card {
  position: relative; display: flex; flex-direction: column; overflow: hidden; height: 640px;
  border-radius: 32px; background: var(--glass); border: 1px solid var(--glass-border); box-shadow: var(--shadow-sm);
}
.bento-copy { position: relative; z-index: 2; padding: var(--space-10) var(--space-10) var(--space-6); }
.bento-copy h3 { font-size: clamp(1.5rem, 1.2vw + 1rem, 2rem); line-height: 1.15; letter-spacing: -0.02em; color: var(--text-strong); margin-bottom: var(--space-3); text-wrap: balance; }
.bento-copy p { color: var(--text-muted); margin: 0; max-width: 32em; }
/* The pictures fill what the text leaves, so a long moving column cannot make a card taller. */
.bento-art { position: relative; flex: 1; min-height: 0; overflow: hidden; }
@media (max-width: 900px) {
  .bento { grid-template-columns: 1fr; }
  .bento-card { height: 600px; }
  .bento-copy { padding: var(--space-8) var(--space-6) var(--space-5); }
}

/* The Documents card opens a real PDF on a loop: tap, open, read, close. */
.doc-stack { position: relative; }
.doc-stack .scr { display: block; }
.doc-stack .scr-file { position: absolute; inset: 0; animation: doc-open 9s cubic-bezier(0.2, 0.7, 0.2, 1) infinite; }
.doc-stack .scr-bar { animation-name: doc-dim; }
@keyframes doc-open { 0%, 30% { translate: 0 100%; } 38%, 82% { translate: 0 0; } 90%, 100% { translate: 0 100%; } }
@keyframes doc-dim { 0%, 30% { opacity: 0; } 38%, 82% { opacity: 1; } 90%, 100% { opacity: 0; } }
.doc-stack .finger { left: 50%; top: 76.5%; animation: doc-tap 9s ease infinite; }
@keyframes doc-tap { 0%, 12% { opacity: 0; scale: 1; } 16% { opacity: 1; scale: 1; } 24% { opacity: 1; scale: 0.75; } 28% { opacity: 1; scale: 1; } 32%, 100% { opacity: 0; } }

/* The IDs card: tap the eye and the number shows, tap copy and the app says that the copy
   clears in 60 seconds. The clipboard beside it counts down and empties. One loop is 12s. */
.card-stack { position: relative; }
.card-stack .scr { display: block; }
.card-stack .scr-card-shown, .card-stack .scr-card-copied { position: absolute; inset: 0; opacity: 0; }
.card-stack .scr-card-shown { animation: card-shown 12s steps(1) infinite; }
.card-stack .scr-card-copied { animation: card-copied 12s ease infinite; }
@keyframes card-shown { 0% { opacity: 0; } 16% { opacity: 1; } 92% { opacity: 0; } }
@keyframes card-copied { 0%, 33% { opacity: 0; } 35%, 60% { opacity: 1; } 66%, 100% { opacity: 0; } }
.card-stack .finger { animation: card-finger 12s ease infinite; }
@keyframes card-finger {
  0%, 6% { opacity: 0; left: 78.2%; top: 37%; scale: 1; }
  9% { opacity: 1; left: 78.2%; top: 37%; scale: 1; } 13% { scale: 0.75; } 16% { scale: 1; }
  24% { left: 88.2%; top: 37%; scale: 1; } 30% { scale: 0.75; } 33% { opacity: 1; scale: 1; }
  38%, 100% { opacity: 0; left: 88.2%; top: 37%; }
}
.clip {
  position: absolute; z-index: 3; right: 6%; top: 64%;
  display: flex; align-items: center; gap: var(--space-3); padding: 12px 16px 12px 12px;
  border-radius: 18px; background: var(--surface-card); border: 1px solid var(--border-faint); box-shadow: var(--shadow-xl);
  opacity: 0; animation: clip-show 12s ease infinite;
}
@keyframes clip-show { 0%, 34% { opacity: 0; translate: 0 8px; } 38%, 90% { opacity: 1; translate: 0 0; } 96%, 100% { opacity: 0; } }
/* The countdown ring. site.js sets the arc and the seconds from one clock, so they agree. */
.clip-ring { position: relative; display: grid; place-items: center; width: 46px; height: 46px; flex: none; }
.clip-ring svg { position: absolute; inset: 0; width: 100%; height: 100%; rotate: -90deg; }
.clip-track { fill: none; stroke: var(--brand-subtle); stroke-width: 4; }
.clip-arc { fill: none; stroke: var(--brand); stroke-width: 4; stroke-linecap: round; stroke-dasharray: 100; stroke-dashoffset: 0; }
.clip-sec { position: relative; font-size: 12px; font-weight: var(--fw-extra); color: var(--text-strong); font-variant-numeric: tabular-nums; }
.clip-sec::after { content: "s"; }
.clip.is-empty .clip-ring { opacity: 0.35; }
.clip.is-empty .clip-sec { visibility: hidden; }
.clip-text { display: grid; }
.clip-text small { color: var(--text-muted); font-size: var(--text-xs); }
.clip-empty { visibility: hidden; }
.clip.is-empty .clip-full { visibility: hidden; }
.clip.is-empty .clip-empty { visibility: visible; }
.clip-text b { grid-area: 2 / 1; color: var(--text-strong); font-size: var(--text-sm); font-family: ui-monospace, "SF Mono", Menlo, monospace; white-space: nowrap; }
@media (max-width: 720px) { .clip { right: 4%; top: 66%; } }

/* Two shorter cards: no list of vaults, and the duress pattern. */
.bento-short { margin-top: var(--space-12); }
.bento-short .bento-card { height: 560px; }

.pool-q { padding: 8px 16px; border-radius: var(--radius-full); background: var(--surface-card); border: 1px solid var(--border); font-size: var(--text-sm); font-weight: var(--fw-bold); color: var(--text-strong); box-shadow: var(--shadow-md); }

/* What the device stores: files with random names, all one size, scrolling past. */
.art-files { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: var(--space-5); padding: 0 var(--space-8) var(--space-8); }
.store { width: 100%; max-width: 400px; border-radius: 16px; overflow: hidden; background: var(--surface-card); border: 1px solid var(--border); box-shadow: var(--shadow-md); }
.store-head { display: flex; justify-content: space-between; padding: 10px 16px; background: var(--surface-subtle); border-bottom: 1px solid var(--border); font-size: var(--text-xs); font-weight: var(--fw-bold); color: var(--text-muted); }
.store-body { height: 168px; overflow: hidden; -webkit-mask-image: linear-gradient(transparent, #000 15%, #000 85%, transparent); mask-image: linear-gradient(transparent, #000 15%, #000 85%, transparent); }
.store-list { margin: 0; padding: 0; list-style: none; animation: rise 22s linear infinite; }
.store-list li { display: flex; justify-content: space-between; gap: var(--space-4); margin: 0; padding: 8px 16px; border-bottom: 1px solid var(--border-faint); font-family: ui-monospace, "SF Mono", Menlo, monospace; font-size: 12.5px; color: var(--text-body); }
.store-list small { color: var(--text-muted); }

/* The duress pattern draws, the photos vanish one by one, and the empty vault shows. Loops every 10s. */
.art-duress { display: flex; align-items: center; justify-content: center; gap: var(--space-8); padding: 0 var(--space-8) var(--space-8); }
.duress-grid { width: 150px; flex: none; }
.duress-grid .p-dot { fill: var(--text-faint); opacity: 0.55; }
.d-line { fill: none; stroke: var(--danger, #dc2626); stroke-width: 6; stroke-linecap: round; stroke-dasharray: 1; stroke-dashoffset: 1; animation: d-line 10s ease-in-out infinite; }
.d-on circle { fill: var(--danger, #dc2626); transform-box: fill-box; transform-origin: center; scale: 0; animation: d-dot 10s ease-out infinite; animation-delay: calc(var(--n) * 0.18s); }
@keyframes d-line { 0%, 4% { stroke-dashoffset: 1; } 14%, 70% { stroke-dashoffset: 0; } 78%, 100% { stroke-dashoffset: 1; } }
@keyframes d-dot { 0%, 4% { scale: 0; } 7%, 70% { scale: 1; } 78%, 100% { scale: 0; } }
.duress-vault { position: relative; width: 190px; aspect-ratio: 1; flex: none; }
.duress-photos { display: grid; grid-template-columns: repeat(3, 1fr); gap: 5px; }
.duress-photos img { width: 100%; aspect-ratio: 1; object-fit: cover; border-radius: 10px; animation: d-photo 10s ease-in infinite; animation-delay: calc(var(--n) * 0.12s); }
@keyframes d-photo { 0%, 22% { opacity: 1; scale: 1; filter: none; } 30%, 88% { opacity: 0; scale: 0.6; filter: blur(4px); } 96%, 100% { opacity: 1; scale: 1; filter: none; } }
.duress-empty {
  position: absolute; inset: 0; display: grid; place-items: center; border-radius: 16px;
  border: 2px dashed var(--border-strong); color: var(--text-muted); font-size: var(--text-sm); font-weight: var(--fw-semibold);
  opacity: 0; animation: d-empty 10s ease infinite;
}
@keyframes d-empty { 0%, 32% { opacity: 0; } 40%, 86% { opacity: 1; } 92%, 100% { opacity: 0; } }
[data-theme="terminal"] .duress-photos img { filter: grayscale(1) sepia(1) hue-rotate(70deg) saturate(2.2) brightness(0.75); }
@media (max-width: 720px) {
  .bento-short .bento-card { height: 540px; }
  .art-duress { gap: var(--space-4); padding: 0 var(--space-5) var(--space-6); }
  .duress-grid { width: 110px; } .duress-vault { width: 160px; }
}

/* Columns that scroll up and down without end. */
.art-columns {
  display: flex; gap: var(--space-3); padding: 0 var(--space-6); overflow: hidden;
  -webkit-mask-image: linear-gradient(transparent, #000 18%, #000 82%, transparent);
  mask-image: linear-gradient(transparent, #000 18%, #000 82%, transparent);
}
.vcol { flex: 1; min-width: 0; }
.vtrack { display: flex; flex-direction: column; gap: var(--space-3); animation: rise 40s linear infinite; }
.vcol:nth-child(2) .vtrack { animation-direction: reverse; animation-duration: 48s; }
.vcol:nth-child(3) .vtrack { animation-duration: 36s; }
.vtrack img { width: 100%; aspect-ratio: 1; object-fit: cover; border-radius: 18px; }
@keyframes rise { from { translate: 0 0; } to { translate: 0 calc(-50% - var(--space-3) / 2); } }
.art-records .rchip { width: 100%; padding: 12px 16px 12px 12px; }
.art-records .rchip b { white-space: normal; }
.art-records .vcol:nth-child(2) { margin-top: 48px; }
[data-theme="terminal"] .vtrack img { filter: grayscale(1) sepia(1) hue-rotate(70deg) saturate(2.2) brightness(0.75); }

/* A phone that rises from the bottom of a card. */
.art-phone { display: flex; justify-content: center; align-items: flex-start; padding-top: var(--space-4); }
.art-phone .phone { width: 280px; }
.art-phone .reveal-phone, .art-phone .files-stage { margin-bottom: -40%; }
@media (max-width: 720px) {
  .art-phone .phone { width: 240px; }
  .art-phone .fchip-1 { left: -18%; } .art-phone .fchip-2 { right: -18%; } .art-phone .fchip-3 { left: -14%; }
  .art-phone .fchip { padding: 6px 12px 6px 6px; gap: var(--space-2); border-radius: 14px; }
  .art-phone .fchip i { width: 26px; height: 30px; font-size: 9px; }
  .art-phone .fchip b { font-size: 12px; } .art-phone .fchip small { font-size: 11px; }
}

/* ---- Feature rows: text beside page art ---------------------- */
.feature { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-16); align-items: center; }
.feature-flip .feature-copy { order: 2; }
.feature-art { position: relative; display: flex; justify-content: center; align-items: center; min-height: 380px; }
@media (max-width: 900px) {
  .feature { grid-template-columns: 1fr; gap: var(--space-10); }
  .feature-flip .feature-copy { order: 0; }
  .feature-art { min-height: 320px; }
}

/* One large phone, on a soft glow in the brand colour. */
.feature-art::before {
  content: ""; position: absolute; z-index: 0; width: 120%; aspect-ratio: 1; max-width: 560px;
  background: radial-gradient(closest-side, rgb(var(--brand-rgb, 99 102 241) / 0.22), transparent);
}
.feature-art .phone { position: relative; z-index: 1; width: 300px; }
@media (max-width: 720px) { .feature-art .phone { width: 250px; } }

/* ---- Band: one full-width section in ink --------------------- */
.band { padding: var(--space-24) 0; background: var(--surface-ink); color: rgb(255 255 255 / 0.72); }
.band .display, .band b { color: #fff; }
.band .lead { color: rgb(255 255 255 / 0.7); }
.band .eyebrow { color: var(--brand-hi, var(--brand)); }
.band-grid { display: grid; grid-template-columns: 1.1fr 0.9fr; gap: var(--space-16); align-items: center; }
.band-steps { margin: var(--space-8) 0 0; padding: 0; list-style: none; counter-reset: step; }
.band-steps li { counter-increment: step; position: relative; padding: var(--space-4) 0 var(--space-4) var(--space-12); border-top: 1px solid rgb(255 255 255 / 0.12); margin: 0; }
.band-steps li::before {
  content: counter(step); position: absolute; left: 0; top: var(--space-4);
  display: grid; place-items: center; width: 30px; height: 30px; border-radius: 50%;
  background: var(--brand); color: var(--on-brand); font-weight: var(--fw-extra); font-size: var(--text-sm);
}
.band .pattern { max-width: 300px; }
.band .pattern .p-dot { fill: rgb(255 255 255 / 0.35); opacity: 1; }
@media (max-width: 900px) { .band-grid { grid-template-columns: 1fr; } .band { padding: var(--space-16) 0; } }
[data-theme="dark"] .band { background: #000; }
[data-theme="terminal"] .band { background: #000; border-top: 1px solid var(--border); border-bottom: 1px solid var(--border); }
[data-theme="terminal"] .band .display, [data-theme="terminal"] .band b { color: var(--text-strong); }
[data-theme="pink"] .band { background: var(--brand-ink); }

/* The pattern draws itself when it, or a block around it, comes into view. --base
   delays the start, so patterns side by side draw one after another. */
.pattern.draw .p-line { stroke-dasharray: 1; stroke-dashoffset: 1; }
.pattern.draw .p-on circle { transform-box: fill-box; transform-origin: center; transform: scale(0); }
:is(.in .pattern.draw:not(.kdf-grid), .pattern.draw.in) .p-line { transition: stroke-dashoffset 1.6s ease-in-out calc(var(--base, 0s) + 0.3s); stroke-dashoffset: 0; }
:is(.in .pattern.draw:not(.kdf-grid), .pattern.draw.in) .p-on circle { transition: transform 0.35s cubic-bezier(0.3, 1.6, 0.5, 1); transition-delay: calc(var(--base, 0s) + 0.3s + var(--i, 0) * 0.23s); transform: scale(1); }
.pattern .p-on circle:nth-child(2) { --i: 1; } .pattern .p-on circle:nth-child(3) { --i: 2; }
.pattern .p-on circle:nth-child(4) { --i: 3; } .pattern .p-on circle:nth-child(5) { --i: 4; }
.pattern .p-on circle:nth-child(6) { --i: 5; } .pattern .p-on circle:nth-child(7) { --i: 6; }
html:not(.js) .pattern.draw .p-line { stroke-dashoffset: 0; }
html:not(.js) .pattern.draw .p-on circle { transform: none; }

/* ---- Record rows that drift behind the records phone --------- */
.drift-chips .drift-track { gap: var(--space-4); }
.rchip {
  display: inline-flex; align-items: center; gap: var(--space-3); flex: none;
  padding: 14px 22px 14px 14px; border-radius: 22px;
  background: var(--surface-card); border: 1px solid var(--border-faint); box-shadow: var(--shadow-md);
}
.rchip i { display: grid; place-items: center; width: 44px; height: 44px; border-radius: 13px; background: var(--brand-subtle); color: var(--brand); }
.rchip i svg { width: 22px; height: 22px; }
.rchip b { display: block; color: var(--text-strong); font-size: var(--text-base); white-space: nowrap; }
.rchip small { color: var(--text-muted); font-size: var(--text-sm); }
.drift-chips { gap: var(--space-10); }
@media (max-width: 720px) {
  .rchip { padding: 10px 16px 10px 10px; border-radius: 16px; }
  .rchip i { width: 34px; height: 34px; border-radius: 10px; }
  .rchip b { font-size: var(--text-sm); }
  .drift-chips { gap: var(--space-6); }
}

/* ---- Files: document names that float out of the phone -------- */
.files-stage { position: relative; z-index: 1; }
.fchips { position: absolute; inset: 0; z-index: 2; pointer-events: none; }
.fchip {
  position: absolute; display: inline-flex; align-items: center; gap: var(--space-3); white-space: nowrap;
  padding: 10px 18px 10px 10px; border-radius: 18px;
  background: var(--surface-card); border: 1px solid var(--border-faint); box-shadow: var(--shadow-xl);
  animation: float 7s ease-in-out infinite;
}
.fchip i {
  display: grid; place-items: center; width: 38px; height: 44px; border-radius: 8px;
  background: var(--brand-subtle); color: var(--brand); font-style: normal; font-size: 11px; font-weight: var(--fw-extra);
}
.fchip b { display: block; color: var(--text-strong); font-size: var(--text-sm); }
.fchip small { color: var(--text-muted); font-size: var(--text-xs); }
.fchip-1 { left: -38%; top: 16%; }
.fchip-2 { right: -42%; top: 42%; animation-delay: -2.4s; }
.fchip-3 { left: -30%; top: 70%; animation-delay: -4.8s; }
@media (max-width: 720px) {
  .fchip-1 { left: -14%; } .fchip-2 { right: -14%; } .fchip-3 { left: -10%; }
  .fchip { padding: 8px 14px 8px 8px; } .fchip i { width: 30px; height: 36px; }
}

/* ---- Pattern to key ------------------------------------------- */
/* Low in the band, so the key lines up with the last step beside it. */
.kdf { display: flex; flex-direction: column; align-items: center; gap: var(--space-6); align-self: end; }
.kdf .pattern { transition: opacity 0.8s; }
.kdf.done .pattern .p-line, .kdf.done .pattern .p-on { opacity: 0.12; transition: opacity 1s; }
.kdf-out { display: flex; flex-direction: column; align-items: center; gap: var(--space-2); width: 100%; max-width: 380px; text-align: center; }
.kdf-label { font-size: var(--text-xs); font-weight: var(--fw-bold); letter-spacing: var(--tracking-eyebrow); text-transform: uppercase; color: rgb(255 255 255 / 0.5); }
.kdf-key {
  display: block; width: 100%; padding: var(--space-3) var(--space-4); border-radius: var(--radius-md);
  background: rgb(255 255 255 / 0.06); border: 1px solid rgb(255 255 255 / 0.12);
  font-family: ui-monospace, "SF Mono", Menlo, monospace; font-size: 13px; line-height: 1.5; letter-spacing: 0.06em;
  color: rgb(255 255 255 / 0.35); word-break: break-all; transition: color 0.4s;
}
.kdf.done .kdf-key { color: var(--brand-hi, var(--brand)); }
.kdf-done { opacity: 0; transition: opacity 0.6s; color: var(--brand-hi, var(--brand)); }
.kdf.done .kdf-done { opacity: 1; }
[data-theme="terminal"] .kdf-label { color: var(--text-faint); }

/* ---- Three patterns, three vaults ------------------------------ */
.vaults { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--space-8); margin-bottom: var(--space-12); text-align: center; }
.vault-col .pattern { max-width: 170px; }
.vault-col:nth-child(2) .pattern { --base: 1.4s; }
.vault-col:nth-child(3) .pattern { --base: 2.8s; }
.vault-arrow { display: block; width: 2px; height: 36px; margin: var(--space-4) auto; background: linear-gradient(var(--brand-border), var(--brand)); position: relative; }
.vault-arrow::after { content: ""; position: absolute; left: 50%; bottom: -2px; width: 10px; height: 10px; border: solid var(--brand); border-width: 0 2px 2px 0; transform: translateX(-50%) rotate(45deg); }
.vault-col h3 { color: var(--text-strong); margin-bottom: var(--space-1); }
.vault-col p { color: var(--text-muted); margin: 0 auto; max-width: 16em; }
.tiles.tiles-2 { grid-template-columns: repeat(2, 1fr); max-width: 860px; margin: 0 auto; }
@media (max-width: 720px) {
  .vaults { grid-template-columns: 1fr; gap: var(--space-10); }
  .vault-col .pattern { max-width: 150px; }
  .vault-col:nth-child(n) .pattern { --base: 0s; }
  .tiles.tiles-2 { grid-template-columns: 1fr; }
}

/* ---- Storage blocks: same size, random, flickering ------------- */
.blocks { margin: 0 auto var(--space-12); max-width: 860px; }
.blocks-grid { display: grid; grid-template-columns: repeat(16, 1fr); gap: 6px; }
.blocks-grid i {
  aspect-ratio: 1; border-radius: 6px; background: var(--brand); opacity: var(--o);
  animation: flicker 6s ease-in-out var(--d) infinite;
}
@keyframes flicker { 0%, 100% { opacity: var(--o); } 30% { opacity: 0.08; } 60% { opacity: calc(var(--o) * 0.6); } }
.blocks figcaption { margin-top: var(--space-4); text-align: center; font-size: var(--text-sm); color: var(--text-muted); }
@media (max-width: 720px) {
  .blocks-grid { grid-template-columns: repeat(12, 1fr); gap: 4px; }
  .blocks-grid i { border-radius: 4px; }
  .blocks-grid i:nth-child(n+73) { display: none; }
}

/* ---- Prices ---------------------------------------------------- */
.price-chips { display: flex; flex-wrap: wrap; justify-content: center; gap: var(--space-4); margin: 0 0 var(--space-8); padding: 0; list-style: none; }
.price-chips li {
  display: flex; flex-direction: column; align-items: center; min-width: 132px; margin: 0;
  padding: var(--space-5) var(--space-6); border-radius: 24px;
  background: var(--glass); border: 1px solid var(--border); box-shadow: var(--shadow-sm);
}
.price-chips b { font-size: var(--text-2xl); color: var(--text-strong); letter-spacing: -0.02em; }
.price-chips small { color: var(--text-muted); font-size: var(--text-sm); }
.price-chips .hot { border: 2px solid var(--brand); box-shadow: 0 0 0 6px var(--brand-subtle); }
@media (max-width: 720px) { .price-chips li { min-width: 0; flex: 1 1 40%; } }

/* ---- Tiles and big numbers ----------------------------------- */
.tiles { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--space-5); }
.tile-card { padding: var(--space-8); border-radius: 28px; background: var(--glass); border: 1px solid var(--glass-border); box-shadow: var(--shadow-sm); }
.tile-card h3 { color: var(--text-strong); margin-bottom: var(--space-2); }
.tile-card p { color: var(--text-muted); margin: 0; }
@media (max-width: 900px) { .tiles { grid-template-columns: 1fr; } }

.stats { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--space-8); margin: 0 0 var(--space-12); text-align: center; }
.stats dt {
  font-size: clamp(2.25rem, 2.6vw + 1rem, 3.5rem); font-weight: var(--fw-extra); letter-spacing: -0.04em; line-height: 1.05; white-space: nowrap;
  background: linear-gradient(135deg, var(--brand), var(--brand-hi, var(--brand))); -webkit-background-clip: text; background-clip: text; color: transparent;
  margin-bottom: var(--space-2);
}
.stats dd { margin: 0 auto; max-width: 18em; color: var(--text-muted); }
@media (max-width: 900px) { .stats { grid-template-columns: repeat(2, 1fr); gap: var(--space-8) var(--space-5); } }

/* ---- Phone screenshots, one image for each theme ------------- */
.phone {
  display: block; position: relative;
  border: 7px solid var(--bezel); border-radius: 38px; overflow: hidden;
  background: var(--bezel); box-shadow: var(--shadow-xl);
}
/* The width and height attributes keep the space while an image loads. */
.phone img { display: none; width: 100%; height: auto; border-radius: 31px; }
[data-theme="light"] .phone .t-light,
[data-theme="dark"] .phone .t-dark,
[data-theme="terminal"] .phone .t-terminal,
[data-theme="pink"] .phone .t-pink,
[data-theme="auto"] .phone .t-light { display: block; }
@media (prefers-color-scheme: dark) {
  [data-theme="auto"] .phone .t-light { display: none; }
  [data-theme="auto"] .phone .t-dark { display: block; }
}
[data-theme="terminal"] .phone { border-color: #1c3826; box-shadow: 0 0 40px rgb(57 255 136 / 0.12); }

/* ---- Cards and grids ----------------------------------------- */
.card {
  background: var(--glass); border: 1px solid var(--glass-border);
  border-radius: var(--radius-xl); padding: var(--space-6);
  box-shadow: var(--shadow-sm);
  -webkit-backdrop-filter: blur(12px); backdrop-filter: blur(12px);
}
.card h3 { margin-bottom: var(--space-2); }
.card p:last-child { margin-bottom: 0; }
.grid-2, .grid-3, .grid-4 { display: grid; gap: var(--space-5); }
.grid-2 { grid-template-columns: repeat(2, 1fr); }
.grid-3 { grid-template-columns: repeat(3, 1fr); }
.grid-4 { grid-template-columns: repeat(4, 1fr); }
@media (max-width: 900px) { .grid-3, .grid-4 { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 620px) { .grid-2, .grid-3, .grid-4 { grid-template-columns: 1fr; } }

.icon {
  display: inline-grid; place-items: center; width: 44px; height: 44px; margin-bottom: var(--space-4);
  border-radius: var(--radius-md); background: var(--brand-subtle); color: var(--brand);
}
.icon svg { width: 22px; height: 22px; }

.step-num {
  display: inline-grid; place-items: center; width: 34px; height: 34px; margin-bottom: var(--space-3);
  border-radius: 50%; background: var(--brand); color: var(--on-brand);
  font-weight: var(--fw-extra); font-size: var(--text-sm);
}

/* Text beside a set of screenshots. */
.split { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-12); align-items: center; }
.split-shots { display: flex; gap: var(--space-4); justify-content: center; }
.split-shots .phone { width: 200px; }
.split-shots .phone:nth-child(2) { margin-top: var(--space-12); }
@media (max-width: 900px) {
  .split { grid-template-columns: 1fr; }
  .split-shots .phone { width: 44%; max-width: 200px; }
}

.checks { padding: 0; list-style: none; }
.checks li { position: relative; padding-left: var(--space-8); margin-bottom: var(--space-3); }
.checks li::before {
  content: ""; position: absolute; left: 0; top: 0.3em; width: 18px; height: 18px; border-radius: 50%;
  background: var(--brand-subtle);
  box-shadow: inset 0 0 0 1px var(--brand-border);
}
/* The tick: two sides of a small box, turned 45 degrees. */
.checks li::after {
  content: ""; position: absolute; left: 6.5px; top: calc(0.3em + 4px); width: 5px; height: 8px;
  border: solid var(--brand); border-width: 0 2px 2px 0; transform: rotate(45deg);
}
.checks li strong { color: var(--text-strong); }

/* ---- Pattern grid illustration ------------------------------- */
.pattern { width: 100%; max-width: 300px; aspect-ratio: 1; margin: 0 auto; }
.pattern .p-dot { fill: var(--text-faint); opacity: 0.55; }
.pattern .p-on { fill: var(--brand); }
.pattern .p-halo { fill: var(--brand); opacity: var(--halo); }
.pattern .p-line { stroke: var(--brand); stroke-width: 4; fill: none; stroke-linecap: round; stroke-linejoin: round; }

/* ---- Theme showcase -------------------------------------------
   Three phones change theme together every 3 seconds. Each theme
   wipes across from the left, the glow behind takes its colour,
   and the label names it. One loop is 12 seconds. */
.theme-stage { position: relative; display: flex; flex-direction: column; align-items: center; padding: var(--space-8) 0 0; }
.theme-stage::before {
  content: ""; position: absolute; z-index: 0; top: 0; left: 50%; width: min(900px, 120%); aspect-ratio: 1.6; translate: -50% -4%;
  background: radial-gradient(closest-side, var(--glow), transparent); animation: theme-glow 12s linear infinite;
}
@property --glow { syntax: "<color>"; inherits: false; initial-value: rgb(99 102 241 / 0.28); }
@keyframes theme-glow {
  0%, 22% { --glow: rgb(99 102 241 / 0.28); } 25%, 47% { --glow: rgb(17 24 39 / 0.45); }
  50%, 72% { --glow: rgb(57 255 136 / 0.3); } 75%, 97% { --glow: rgb(232 85 155 / 0.35); } 100% { --glow: rgb(99 102 241 / 0.28); }
}
.theme-bg { position: absolute; z-index: 0; inset: -8% -30% -4%; pointer-events: none; }
.theme-bg::before {
  content: ""; position: absolute; inset: 0;
  background-image: radial-gradient(var(--text-faint) 1.6px, transparent 1.8px); background-size: 30px 30px;
  -webkit-mask-image: radial-gradient(closest-side, #000 30%, transparent); mask-image: radial-gradient(closest-side, #000 30%, transparent);
  opacity: 0.5; animation: dots-drift 40s linear infinite;
}
@keyframes dots-drift { to { background-position: 30px 300px; } }
.theme-bg i {
  position: absolute; left: 50%; top: 50%; width: 220px; height: 220px; margin: -110px 0 0 -110px; border-radius: 50%;
  filter: blur(60px); opacity: 0.5; animation: orbit 24s linear infinite;
}
.theme-bg i:nth-child(1) { background: #6366f1; }
.theme-bg i:nth-child(2) { background: #1f2937; animation-delay: -6s; }
.theme-bg i:nth-child(3) { background: #39ff88; animation-delay: -12s; opacity: 0.35; }
.theme-bg i:nth-child(4) { background: #e8559b; animation-delay: -18s; }
@keyframes orbit { from { transform: rotate(0deg) translateX(min(30vw, 300px)) rotate(0deg); } to { transform: rotate(360deg) translateX(min(30vw, 300px)) rotate(-360deg); } }
.theme-phones { position: relative; z-index: 1; display: flex; align-items: center; justify-content: center; gap: var(--space-6); }
.tp-main .phone { width: 290px; }
.tp-side .phone { width: 230px; }
.tp-side:first-child { transform: rotate(-6deg) translateY(30px); }
.tp-side:last-child { transform: rotate(6deg) translateY(30px); }
.cycle { position: relative; }
.cycle img { display: block; }
.cycle img + img { position: absolute; inset: 0; clip-path: inset(0 100% 0 0); }
.cycle .c-dark { animation: wipe-dark 12s cubic-bezier(0.6, 0, 0.2, 1) infinite; }
.cycle .c-terminal { animation: wipe-terminal 12s cubic-bezier(0.6, 0, 0.2, 1) infinite; }
.cycle .c-pink { animation: wipe-pink 12s cubic-bezier(0.6, 0, 0.2, 1) infinite; }
@keyframes wipe-dark { 0%, 22% { clip-path: inset(0 100% 0 0); } 27%, 96% { clip-path: inset(0 0 0 0); } 100% { clip-path: inset(0 0 0 100%); } }
@keyframes wipe-terminal { 0%, 47% { clip-path: inset(0 100% 0 0); } 52%, 96% { clip-path: inset(0 0 0 0); } 100% { clip-path: inset(0 0 0 100%); } }
@keyframes wipe-pink { 0%, 72% { clip-path: inset(0 100% 0 0); } 77%, 96% { clip-path: inset(0 0 0 0); } 100% { clip-path: inset(0 0 0 100%); } }
.tp-side .cycle img + img { animation-delay: 0.12s; }
.theme-pills { display: flex; flex-wrap: wrap; justify-content: center; gap: var(--space-3); margin-top: var(--space-10); }
.theme-pills button {
  display: inline-flex; align-items: center; gap: var(--space-2); padding: 10px 18px; border-radius: var(--radius-full); cursor: pointer;
  background: var(--glass); border: 1px solid var(--border); font: inherit; font-size: var(--text-sm); font-weight: var(--fw-bold); color: var(--text-strong);
  transition: border-color 0.15s, transform 0.15s;
}
.theme-pills button:hover { transform: translateY(-2px); border-color: var(--border-strong); }
.theme-pills button[aria-pressed="true"] { border-color: var(--brand); box-shadow: 0 0 0 4px var(--brand-subtle); }
/* Each button fills in turn while its theme is on the phones, in step with the 12s cycle. */
.theme-pills button { position: relative; overflow: hidden; isolation: isolate; }
.theme-pills button::after {
  content: ""; position: absolute; z-index: -1; left: 0; top: 0; bottom: 0; width: 0;
  background: var(--fill); opacity: 0.22; animation: pill-fill 12s linear infinite;
}
.theme-pills button:nth-child(1) { --fill: #6366f1; }
.theme-pills button:nth-child(2) { --fill: #111827; } .theme-pills button:nth-child(2)::after { animation-delay: 3s; }
.theme-pills button:nth-child(3) { --fill: #39ff88; } .theme-pills button:nth-child(3)::after { animation-delay: 6s; }
.theme-pills button:nth-child(4) { --fill: #e8559b; } .theme-pills button:nth-child(4)::after { animation-delay: 9s; }
[data-theme="dark"] .theme-pills button:nth-child(2), [data-theme="terminal"] .theme-pills button:nth-child(2) { --fill: #9ca3af; }
@keyframes pill-fill { 0% { width: 0; opacity: 0.3; } 24.9% { width: 100%; opacity: 0.3; } 25%, 100% { width: 0; opacity: 0; } }
.theme-pills i { width: 16px; height: 16px; border-radius: 50%; border: 1px solid rgb(0 0 0 / 0.1); }
.sw-l { background: linear-gradient(135deg, #f5f3ff, #6366f1); } .sw-d { background: linear-gradient(135deg, #111827, #6366f1); }
.sw-t { background: linear-gradient(135deg, #050805, #39ff88); } .sw-p { background: linear-gradient(135deg, #fff5f9, #e8559b); }
@media (max-width: 720px) {
  .theme-phones { gap: 0; }
  .tp-main .phone { width: 200px; }
  .tp-side .phone { width: 150px; }
  .tp-side:first-child { margin-right: -60px; } .tp-side:last-child { margin-left: -60px; }
  .tp-main { position: relative; z-index: 1; }
  /* The side phones reach past a narrow screen. */
  .theme-stage { overflow: hidden; margin: 0 calc(var(--space-5) * -1); padding-bottom: var(--space-4); }
}

/* ---- Facts (a definition list) ------------------------------- */
.facts { display: grid; grid-template-columns: repeat(2, 1fr); gap: 0 var(--space-8); margin: 0; }
.facts div { padding: var(--space-4) 0; border-top: 1px solid var(--border); }
.facts dt { font-weight: var(--fw-bold); color: var(--text-strong); margin-bottom: var(--space-1); }
.facts dd { margin: 0; color: var(--text-muted); }
@media (max-width: 720px) { .facts { grid-template-columns: 1fr; } }

/* The honest panel: what DotSafe cannot do. */
.limits { border-left: 4px solid var(--warning); }
[data-theme="terminal"] .limits { border-left-color: var(--brand); }

/* ---- Page header for the inner pages -------------------------- */
.page-hero { position: relative; isolation: isolate; overflow: hidden; padding: var(--space-20) 0 var(--space-12); }
.page-hero h1 { margin-bottom: var(--space-5); }
.page-hero .hero-copy h1 { font-size: clamp(2.5rem, 4.5vw + 0.5rem, 4.5rem); }
.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }

/* ---- Pricing ---------------------------------------------------- */
.plans { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--space-5); align-items: stretch; }
.plan {
  position: relative; display: flex; flex-direction: column; padding: var(--space-8);
  border-radius: 28px; background: var(--glass); border: 1px solid var(--glass-border); box-shadow: var(--shadow-sm);
}
.plan h2 { font-size: var(--text-xl); color: var(--text-strong); margin: 0; }
.plan-price { font-size: clamp(2.5rem, 2vw + 1.5rem, 3.25rem); font-weight: var(--fw-extra); color: var(--text-strong); letter-spacing: -0.03em; line-height: 1.1; margin: var(--space-3) 0 var(--space-1); }
.plan-price small { font-size: var(--text-base); font-weight: var(--fw-medium); color: var(--text-muted); letter-spacing: 0; }
.plan-note { color: var(--text-muted); font-size: var(--text-sm); text-wrap: balance; }
.plan .checks li { text-wrap: pretty; }
.plan .checks { margin: var(--space-5) 0 var(--space-6); flex: 1; }
.plan-tag {
  position: absolute; top: -12px; left: var(--space-8); padding: 3px 12px; border-radius: var(--radius-full);
  background: var(--brand); color: var(--on-brand); font-size: var(--text-xs); font-weight: var(--fw-bold);
}
.plan-tag-quiet { background: var(--surface-card); color: var(--text-strong); border: 1px solid var(--border); }
/* The featured plan has a slowly turning gradient border. */
@property --turn { syntax: "<angle>"; inherits: false; initial-value: 0deg; }
.plan.featured {
  border: 2px solid transparent;
  background: linear-gradient(var(--surface-card), var(--surface-card)) padding-box,
              conic-gradient(from var(--turn), var(--brand), #ec4899, var(--brand-hi, var(--brand)), var(--brand)) border-box;
  box-shadow: var(--shadow-xl), 0 0 60px rgb(var(--brand-rgb, 99 102 241) / 0.2);
  animation: turn 6s linear infinite;
}
@keyframes turn { to { --turn: 360deg; } }
/* Lifetime, the best value, is a dark card with a glowing price. */
.plan.lifetime {
  background: radial-gradient(120% 80% at 100% 0%, rgb(236 72 153 / 0.35), transparent 60%), radial-gradient(120% 80% at 0% 100%, rgb(var(--brand-rgb, 99 102 241) / 0.45), transparent 60%), #0b0f1e;
  border: 1px solid rgb(255 255 255 / 0.12); color: rgb(255 255 255 / 0.75);
  box-shadow: var(--shadow-xl), 0 20px 60px -10px rgb(236 72 153 / 0.35);
  transform: translateY(-8px);
}
.plan.lifetime h2 { color: #fff; }
.plan.lifetime .plan-price { background: linear-gradient(90deg, #fff, #f9a8d4); -webkit-background-clip: text; background-clip: text; color: transparent; }
.plan.lifetime .plan-price small { color: rgb(255 255 255 / 0.7); -webkit-text-fill-color: rgb(255 255 255 / 0.7); }
.plan.lifetime .plan-note { color: rgb(255 255 255 / 0.7); }
.plan.lifetime .checks li { color: rgb(255 255 255 / 0.85); }
.plan.lifetime .checks li::before { background: rgb(255 255 255 / 0.12); box-shadow: inset 0 0 0 1px rgb(255 255 255 / 0.25); }
.plan.lifetime .checks li::after { border-color: #f9a8d4; }
.plan.lifetime .btn { background: #fff; color: #0b0f1e; border-color: #fff; }
.plan.lifetime .btn:hover { background: #f9a8d4; border-color: #f9a8d4; color: #0b0f1e; }
.plan-tag-hot { background: linear-gradient(90deg, #ec4899, #f59e0b); color: #fff; box-shadow: 0 0 20px rgb(236 72 153 / 0.6); }
/* Stacked, the plans need room for the tags that sit on their top edges. */
@media (max-width: 900px) { .plans { grid-template-columns: 1fr; max-width: 460px; margin: 0 auto; row-gap: var(--space-10); } .plan.lifetime { transform: none; } }

/* Three cards in a row. */
.bento-three { grid-template-columns: repeat(3, 1fr); }
.bento-three .bento-card { height: 520px; }
.bento-three .bento-copy { padding: var(--space-8) var(--space-8) var(--space-5); }
.bento-three .bento-copy h3 { font-size: var(--text-xl); }
@media (max-width: 900px) { .bento-three { grid-template-columns: 1fr; } .bento-three .bento-card { height: 480px; } .bento-three .bento-card:has(.art-sync), .bento-three .bento-card:has(.art-share) { height: 540px; } }

/* Sync: the vault on an iPad and an iPhone, with encrypted packets through iCloud. */
.art-sync { display: block; }
.sync-stage { position: absolute; left: 50%; bottom: -30px; width: 320px; height: 300px; translate: -50% 0; }
.sync-lines { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
.sync-line { fill: none; stroke: var(--brand); stroke-width: 2.5; stroke-dasharray: 2 8; stroke-linecap: round; opacity: 0.7; animation: net-flow 1.2s linear infinite; }
.art-sync .pkt { fill: var(--brand); filter: drop-shadow(0 0 6px rgb(var(--brand-rgb, 99 102 241) / 0.8)); }
.sync-cloud {
  position: absolute; z-index: 2; left: 50%; top: 0; translate: -50% 0; display: flex; align-items: center; gap: 8px;
  padding: 10px 16px; border-radius: var(--radius-full); background: var(--brand); color: var(--on-brand);
  box-shadow: var(--shadow-lg), 0 0 0 8px var(--brand-subtle);
}
.sync-cloud svg { width: 18px; height: 18px; }
.sync-cloud small { color: rgb(255 255 255 / 0.85); font-size: var(--text-xs); font-weight: var(--fw-semibold); }
.sync-pad { position: absolute; left: 26px; bottom: 6px; width: 160px; rotate: -4deg; }
.sync-phone { position: absolute; right: 32px; bottom: -14px; width: 100px; rotate: 5deg; z-index: 1; }
.phone.tablet { border-width: 6px; border-radius: 22px; }
.phone.tablet img { border-radius: 16px; }
.sync-phone .phone { border-width: 4px; border-radius: 20px; }
.sync-phone .phone img { border-radius: 16px; }

/* Sharing: the members of one vault, each with View or Edit. Jo moves from View to Edit,
   and the app's toast says so. Loops every 8s. */
.art-share { display: flex; flex-direction: column; align-items: center; gap: var(--space-3); padding: 0 var(--space-5) var(--space-6); }
.share-head {
  display: inline-flex; align-items: center; gap: 8px; padding: 8px 14px; border-radius: var(--radius-full);
  background: var(--brand); color: var(--on-brand); box-shadow: var(--shadow-lg), 0 0 0 6px var(--brand-subtle); font-size: var(--text-sm);
}
.share-head svg { width: 16px; height: 16px; }
.share-head small { color: rgb(255 255 255 / 0.8); font-size: var(--text-xs); font-weight: var(--fw-semibold); }
.share-rows { display: grid; gap: 8px; width: 100%; max-width: 300px; margin-top: var(--space-2); }
.mrow {
  display: flex; align-items: center; gap: 10px; padding: 8px 10px 8px 8px; border-radius: var(--radius-full);
  background: var(--surface-card); border: 1px solid var(--border-faint); box-shadow: var(--shadow-lg);
  opacity: 0; animation: mrow-in 8s ease infinite;
}
.mr-1 { translate: 10px 0; } .mr-2 { translate: -6px 0; animation-delay: 0.25s; } .mr-3 { translate: 14px 0; animation-delay: 0.5s; }
@keyframes mrow-in { 0%, 4% { opacity: 0; scale: 0.96; } 12%, 90% { opacity: 1; scale: 1; } 97%, 100% { opacity: 0; } }
.mrow img { width: 38px; height: 38px; border-radius: 50%; object-fit: cover; flex: none; }
.mwho { display: flex; flex-direction: column; line-height: 1.15; flex: 1; min-width: 0; }
.mwho b { color: var(--text-strong); font-size: var(--text-sm); }
.mwho small { color: var(--text-muted); font-size: var(--text-xs); }
.mbadge { padding: 5px 12px; border-radius: var(--radius-full); background: var(--brand-subtle); color: var(--brand); font-size: 12px; font-weight: var(--fw-bold); }
/* A two-part switch. The white thumb sits under the chosen part. */
.seg { position: relative; display: grid; grid-template-columns: 1fr 1fr; padding: 3px; border-radius: var(--radius-full); background: var(--surface-subtle); border: 1px solid var(--border-faint); }
.seg span { position: relative; z-index: 1; padding: 4px 10px; font-size: 12px; font-weight: var(--fw-bold); color: var(--text-muted); text-align: center; }
.seg i { position: absolute; z-index: 0; top: 3px; bottom: 3px; left: 3px; width: calc(50% - 3px); border-radius: var(--radius-full); background: var(--surface-card); box-shadow: var(--shadow-sm); }
.seg span:first-of-type { color: var(--text-strong); }
.seg-flip i { animation: seg-move 8s cubic-bezier(0.5, 0, 0.2, 1) infinite; }
.seg-flip span:first-of-type { animation: seg-off 8s steps(1) infinite; }
.seg-flip span:last-of-type { animation: seg-on 8s steps(1) infinite; }
@keyframes seg-move { 0%, 34% { translate: 0 0; } 40%, 100% { translate: 100% 0; } }
@keyframes seg-off { 0% { color: var(--text-strong); } 38% { color: var(--text-muted); } }
@keyframes seg-on { 0% { color: var(--text-muted); } 38% { color: var(--text-strong); } }
.share-toast {
  display: inline-flex; align-items: center; gap: 8px; margin-top: var(--space-2); padding: 6px 14px 6px 6px; border-radius: var(--radius-full);
  background: #111827; color: #fff; font-size: var(--text-sm); font-weight: var(--fw-bold); box-shadow: var(--shadow-xl);
  opacity: 0; animation: share-toast 8s ease infinite;
}
.share-toast img { width: 26px; height: 26px; border-radius: 50%; object-fit: cover; }
@keyframes share-toast { 0%, 42% { opacity: 0; translate: 0 8px; } 48%, 84% { opacity: 1; translate: 0 0; } 92%, 100% { opacity: 0; } }
[data-theme="dark"] .share-toast, [data-theme="terminal"] .share-toast { background: #000; border: 1px solid rgb(255 255 255 / 0.15); }

/* Comparison table: the Pro column is tinted, ticks sit in circles, and every cell is centred. */
.compare { position: relative; border-radius: 28px; overflow: hidden; background: var(--surface-card); border: 1px solid var(--border); box-shadow: var(--shadow-lg); }
.compare table { font-size: var(--text-base); border-collapse: separate; border-spacing: 0; }
.compare th, .compare td { padding: var(--space-4) var(--space-6); vertical-align: middle; border-bottom: 1px solid var(--border-faint); }
.compare tbody tr:last-child th, .compare tbody tr:last-child td { border-bottom: 0; }
.compare tbody th { font-weight: var(--fw-semibold); color: var(--text-strong); }
.compare td { text-align: center; width: 22%; color: var(--text-body); }
.compare thead th { background: transparent; font-size: var(--text-sm); font-weight: var(--fw-extra); text-transform: uppercase; letter-spacing: var(--tracking-eyebrow); color: var(--text-muted); text-align: center; padding-top: var(--space-6); }
.compare th:nth-child(3), .compare td:nth-child(3) { background: var(--brand-subtle); }
.compare thead th:nth-child(3) { color: var(--brand); }
.compare tbody tr:hover th, .compare tbody tr:hover td:nth-child(2) { background: var(--surface-subtle); }
.compare td.tick, .compare td.dash { font-size: 0; }
.compare td.tick::before {
  content: ""; display: inline-block; vertical-align: middle; width: 26px; height: 26px; border-radius: 50%;
  background: var(--brand) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 12.5 4 4 8-9'/%3E%3C/svg%3E") center / 15px no-repeat;
}
.compare td.dash::before { content: ""; display: inline-block; vertical-align: middle; width: 14px; height: 2px; border-radius: 2px; background: var(--text-faint); }
.compare td.yes { color: var(--brand); font-weight: var(--fw-extra); }
.compare tbody th small { display: block; margin-top: 2px; font-size: var(--text-xs); font-weight: var(--fw-medium); color: var(--text-muted); }
.compare td.spec { font-family: ui-monospace, "SF Mono", Menlo, monospace; font-size: var(--text-sm); font-weight: var(--fw-regular, 400); color: var(--text-body); white-space: nowrap; }
@media (max-width: 620px) {
  .compare th, .compare td { padding: var(--space-3) var(--space-2); font-size: var(--text-sm); }
  .compare tbody th { padding-left: var(--space-4); }
  .compare td.spec { white-space: normal; font-size: 11px; word-break: break-word; }
  .compare td { width: 28%; }
}

/* ---- Security page ------------------------------------------------ */
.intro p { font-size: clamp(1.125rem, 0.6vw + 1rem, 1.375rem); line-height: 1.6; color: var(--text-body); }
.intro p:first-child { color: var(--text-strong); }
.threats { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--space-5); }
.threats article {
  padding: var(--space-8); border-radius: 28px; background: var(--glass); border: 1px solid var(--glass-border); box-shadow: var(--shadow-sm);
  transition: transform 0.2s, box-shadow 0.2s;
}
.threats article:hover { transform: translateY(-4px); box-shadow: var(--shadow-lg); }
.threats h3 { font-size: var(--text-lg); color: var(--text-strong); margin-bottom: var(--space-2); }
.threats p { color: var(--text-muted); margin: 0; }
@media (max-width: 900px) { .threats { grid-template-columns: 1fr 1fr; } }
@media (max-width: 620px) { .threats { grid-template-columns: 1fr; } }

/* Threat cards: six pictures. */
.threats-grid .bento-card { height: 560px; }
@media (max-width: 900px) { .threats-grid .bento-card { height: 460px; } .threats-grid .bento-card:has(.art-clip2) { height: 540px; } .threats-grid .bento-card:has(.art-peek) { height: 600px; } .art-clip2 .clip { bottom: 6%; } }
.threats-grid .bento-copy h3 { font-size: var(--text-lg); }
.threats-grid .bento-copy p { font-size: var(--text-sm); }

/* A pattern draws, then an ordinary decoy vault opens. Loops every 8s. */
.art-decoy { display: flex; align-items: center; justify-content: center; gap: var(--space-5); padding: 0 var(--space-6) var(--space-6); }
.decoy-grid { width: 120px; flex: none; }
.decoy-grid .p-dot { fill: var(--text-faint); opacity: 0.55; }
.dl-brand { stroke: var(--brand); animation-duration: 8s; }
.do-brand circle { fill: var(--brand); animation-duration: 8s; }
.decoy-vault { width: 150px; padding: 8px; border-radius: 16px; background: var(--surface-card); border: 1px solid var(--border-faint); box-shadow: var(--shadow-lg); opacity: 0; animation: decoy-open 8s ease infinite; }
.decoy-vault small { display: block; margin: 0 0 6px 2px; font-size: 11px; font-weight: var(--fw-bold); color: var(--text-muted); }
.decoy-photos { display: grid; grid-template-columns: repeat(3, 1fr); gap: 4px; }
.decoy-photos img { width: 100%; aspect-ratio: 1; object-fit: cover; border-radius: 6px; }
@keyframes decoy-open { 0%, 18% { opacity: 0; translate: 0 10px; scale: 0.95; } 26%, 80% { opacity: 1; translate: 0 0; scale: 1; } 90%, 100% { opacity: 0; } }

/* Guess after guess flashes on the grid while one slow bar fills. */
.art-guess { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: var(--space-5); padding: 0 var(--space-6) var(--space-6); }
.guess-grid { width: 150px; }
.guess-grid .p-dot { fill: var(--text-faint); opacity: 0.55; }
/* Each guess lights its own dots and line in red, like a drawn pattern, then goes. */
.g-try { opacity: 0; animation: guess 3.6s steps(1) infinite; animation-delay: calc(var(--n) * 0.6s); }
.g-try polyline { fill: none; stroke: #e5484d; stroke-width: 5; stroke-linecap: round; stroke-linejoin: round; opacity: 0.85; }
.g-try circle { fill: #e5484d; }
@keyframes guess { 0% { opacity: 1; } 16.6%, 100% { opacity: 0; } }
.guess-bar { width: 220px; text-align: center; }
.guess-bar small { display: block; margin-bottom: 6px; font-size: var(--text-xs); font-weight: var(--fw-bold); color: var(--text-muted); }
.guess-bar span { display: block; height: 8px; border-radius: 4px; background: var(--brand-subtle); overflow: hidden; }
.guess-bar i { display: block; height: 100%; width: 0; background: var(--brand); animation: slow-fill 3.6s linear infinite; }
@keyframes slow-fill { from { width: 0; } to { width: 12%; } }

/* iCloud holds only encrypted blocks. */
.art-cloud { display: grid; place-items: center; padding: 0 var(--space-6) var(--space-6); }
.cloud-box { width: 240px; padding: var(--space-4); border-radius: 22px; text-align: center; background: var(--surface-card); border: 1px solid var(--border-faint); box-shadow: var(--shadow-lg); }
.cloud-box b { display: block; color: var(--text-strong); margin-bottom: var(--space-3); }
.cloud-box small { display: block; margin-top: var(--space-3); color: var(--text-muted); font-size: var(--text-xs); }
.cloud-blocks { display: grid; grid-template-columns: repeat(6, 1fr); gap: 5px; }
.cloud-blocks i { aspect-ratio: 1; border-radius: 5px; background: var(--brand); opacity: var(--o); animation: flicker 5s ease-in-out var(--d) infinite; }

/* The vault screen, then the privacy cover over it. */
.cover-stack { position: relative; }
.cover-stack .phone { width: 240px; }
.cover {
  position: absolute; inset: 7px; border-radius: 31px; display: grid; place-items: center;
  background: rgb(255 255 255 / 0.6); -webkit-backdrop-filter: blur(16px); backdrop-filter: blur(16px);
  animation: cover 6s ease-in-out infinite;
}
/* Small and quiet, near the top of the visible part of the phone. */
.cover { place-items: start center; padding-top: 38%; }
.cover .wordmark { font-size: 1.05rem; opacity: 0.55; }
[data-theme="dark"] .cover, [data-theme="terminal"] .cover { background: rgb(0 0 0 / 0.55); }
@keyframes cover { 0%, 30% { opacity: 0; } 40%, 85% { opacity: 1; } 95%, 100% { opacity: 0; } }

/* The clipboard countdown on its own. */
.art-clip { display: grid; place-items: center; }
.clip.clip-static { position: static; opacity: 1; animation: none; }

/* Threat cards, richer pictures. */
.art-decoy2 { position: relative; justify-content: flex-start; padding-left: 10%; }
.decoy-card {
  position: absolute; z-index: 2; right: 3%; top: 36%; width: 156px; padding: 10px; border-radius: 18px;
  background: var(--surface-card); border: 1px solid var(--border-faint); box-shadow: var(--shadow-xl);
  animation: decoy-open 8s ease infinite;
}
.decoy-card small { display: block; margin: 0 0 8px 2px; font-size: 12px; font-weight: var(--fw-bold); color: var(--text-strong); }
.decoy-card .decoy-photos { display: grid; grid-template-columns: repeat(3, 1fr); gap: 4px; }
.decoy-card img { width: 100%; aspect-ratio: 1; object-fit: cover; border-radius: 7px; }

.art-store { display: grid; place-items: center; padding: 0 var(--space-6) var(--space-6); }
.store-field { position: absolute; inset: 0 var(--space-6) var(--space-6); display: grid; grid-template-columns: repeat(10, 1fr); gap: 6px; align-content: center; opacity: 0.7;
  -webkit-mask-image: radial-gradient(closest-side, #000 40%, transparent); mask-image: radial-gradient(closest-side, #000 40%, transparent); }
.store-field i { aspect-ratio: 1; border-radius: 6px; background: var(--brand); opacity: var(--o); animation: flicker 6s ease-in-out var(--d) infinite; }
.art-store .store { position: relative; z-index: 1; box-shadow: var(--shadow-xl); }

.art-guess .guess-grid { width: 210px; }
@property --guesses { syntax: "<integer>"; inherits: false; initial-value: 0; }
.guess-meter { display: flex; align-items: center; gap: var(--space-2); line-height: 1; padding: 12px 20px; border-radius: var(--radius-full); background: var(--surface-card); border: 1px solid var(--border); box-shadow: var(--shadow-md); }
.guess-count { counter-reset: g var(--guesses); animation: guess-count 21.6s steps(36) infinite; font-weight: var(--fw-extra); font-size: var(--text-lg); color: var(--text-strong); font-variant-numeric: tabular-nums; }
.guess-count::before { content: counter(g); }
@keyframes guess-count { from { --guesses: 0; } to { --guesses: 36; } }
.guess-meter small { color: var(--text-muted); font-size: var(--text-sm); line-height: 1; white-space: nowrap; }
.guess-count { line-height: 1; min-width: 2ch; text-align: right; }

.art-cloud2 { position: relative; }
.art-cloud2 .cloud-box { position: absolute; z-index: 2; left: 50%; top: 0; translate: -50% 0; width: 200px; padding: var(--space-3); }
.rise { position: absolute; z-index: 1; left: 50%; top: 150px; width: 60px; height: 50px; translate: -50% 0; }
.rise i { position: absolute; left: 50%; bottom: 0; width: 10px; height: 10px; margin-left: -5px; border-radius: 3px; background: var(--brand); box-shadow: 0 0 10px rgb(var(--brand-rgb, 99 102 241) / 0.7); animation: rise-up 2.4s linear infinite; }
.rise i:nth-child(2) { animation-delay: 0.6s; margin-left: -18px; } .rise i:nth-child(3) { animation-delay: 1.2s; margin-left: 8px; } .rise i:nth-child(4) { animation-delay: 1.8s; }
@keyframes rise-up { from { translate: 0 0; opacity: 0; } 20% { opacity: 1; } to { translate: 0 -45px; opacity: 0; } }
.art-cloud2 .phone { margin-top: 200px; }

.art-cover .cover-stack .phone { width: 280px; }
.art-clip2 { position: relative; }
/* Below the login details, where the screen is empty. The ring and the seconds share one
   8s countdown: 60 to 0 over the first 75%, then the clipboard shows Empty. */
.art-clip2 .clip { position: absolute; z-index: 2; left: 50%; top: auto; bottom: 8%; width: max-content; translate: -50% 0; box-shadow: var(--shadow-xl); min-width: 0; padding: 8px 14px 8px 8px; gap: var(--space-2); }
.art-clip2 .clip-ring { width: 36px; height: 36px; }
.art-clip2 .clip-sec { font-size: 10px; }
.art-clip2 .clip-text small { font-size: 10px; }
.art-clip2 .clip-text b { font-size: 12px; }
.clip-text b { font-family: inherit; }
@media (max-width: 720px) {
  .art-cover .cover-stack .phone { width: 240px; }
  .decoy-card { right: 3%; top: 27%; width: 132px; padding: 8px; }
}

/* A copy of the storage: block names in a grid, a lens that moves from one to the next,
   and three things that the copy cannot show. The lens loop is 8s, 2s on each tile. */
.art-peek { display: flex; flex-direction: column; align-items: center; gap: var(--space-4); padding: 0 var(--space-6) var(--space-6); }
.peek { position: relative; width: 100%; max-width: 300px; }
.peek-grid {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px;
  -webkit-mask-image: linear-gradient(#000 60%, transparent); mask-image: linear-gradient(#000 60%, transparent);
}
.peek-grid i {
  display: grid; place-items: center; height: 38px; border-radius: 10px; font-style: normal;
  background: var(--surface-card); border: 1px solid var(--border-faint); box-shadow: var(--shadow-sm);
  font-family: ui-monospace, "SF Mono", Menlo, monospace; font-size: 12px; font-weight: var(--fw-bold); color: var(--text-faint);
}
.lens { position: absolute; z-index: 2; width: 84px; height: 84px; translate: -50% -50%; animation: lens-move 8s cubic-bezier(0.6, 0, 0.3, 1) infinite; }
.lens-glass {
  position: absolute; inset: 0; display: grid; place-items: center; border-radius: 50%; overflow: hidden;
  background: radial-gradient(circle at 35% 30%, #8b8cf8, var(--brand) 60%, #3730a3);
  border: 4px solid rgb(255 255 255 / 0.85); box-shadow: var(--shadow-xl), 0 0 0 6px rgb(var(--brand-rgb, 99 102 241) / 0.25);
}
.lens-glass b {
  grid-area: 1 / 1; font-family: ui-monospace, "SF Mono", Menlo, monospace; font-size: 22px; font-weight: var(--fw-extra); color: #fff;
  opacity: 0; animation: lens-code 8s steps(1) infinite; animation-delay: calc(var(--n) * 2s);
}
.lens-handle { position: absolute; right: -22px; bottom: -22px; width: 40px; height: 12px; border-radius: 6px; background: #312e81; rotate: 45deg; box-shadow: var(--shadow-md); }
/* Tile centres: column c at 12.5% + 25% x c, row r at 10% + 20% x r of a five-row grid. */
@keyframes lens-move {
  0%, 18% { left: 37.5%; top: 50%; }
  25%, 43% { left: 62.5%; top: 30%; }
  50%, 68% { left: 87.5%; top: 70%; }
  75%, 93% { left: 12.5%; top: 70%; }
  100% { left: 37.5%; top: 50%; }
}
@keyframes lens-code { 0% { opacity: 1; } 22%, 100% { opacity: 0; } }
.unknowns { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; width: 100%; max-width: 320px; }
.unknown {
  position: relative; display: flex; flex-direction: column; align-items: center; gap: 2px; text-align: center;
  padding: 12px 6px 10px; border-radius: 14px; background: var(--brand); color: var(--on-brand); box-shadow: var(--shadow-lg);
}
.unknown:nth-child(1) { rotate: -3deg; } .unknown:nth-child(3) { rotate: 3deg; }
.unknown::after {
  content: "?"; position: absolute; top: -7px; right: -7px; display: grid; place-items: center; width: 20px; height: 20px; border-radius: 50%;
  background: var(--surface-card); color: var(--brand); font-size: 12px; font-weight: var(--fw-extra); line-height: 1; box-shadow: var(--shadow-sm);
}
.u-ic { display: grid; place-items: center; width: 32px; height: 32px; margin-bottom: 4px; border-radius: 9px; background: rgb(255 255 255 / 0.16); }
.u-ic svg { width: 18px; height: 18px; }
.unknown small { font-size: 9px; font-weight: var(--fw-extra); letter-spacing: 0.12em; text-transform: uppercase; color: rgb(255 255 255 / 0.85); }
.unknown b { font-size: 12px; line-height: 1.2; }
[data-theme="terminal"] .lens-glass { background: radial-gradient(circle at 35% 30%, #6affa6, #1f7a45 70%); }
[data-theme="terminal"] .lens-glass b { color: #002a12; }
[data-theme="terminal"] .lens-handle { background: #1c3826; }

/* The limits, on the dark band, each with a cross. */
.band-limits .lead { margin-bottom: var(--space-8); }
.limits-list { margin: 0; padding: 0; list-style: none; display: grid; gap: var(--space-3); }
.limits-list li {
  position: relative; margin: 0; padding: var(--space-5) var(--space-6) var(--space-5) var(--space-16);
  border-radius: 20px; background: rgb(255 255 255 / 0.05); border: 1px solid rgb(255 255 255 / 0.1); color: rgb(255 255 255 / 0.72);
}
/* A cross drawn from two bars (a plus turned 45 degrees), so it is exactly centred. */
.limits-list li::before {
  content: ""; position: absolute; left: var(--space-5); top: var(--space-5);
  width: 26px; height: 26px; border-radius: 50%; rotate: 45deg;
  background:
    linear-gradient(#fff, #fff) center / 12px 2px no-repeat,
    linear-gradient(#fff, #fff) center / 2px 12px no-repeat,
    rgb(229 72 77 / 0.55);
}
.limits-list b { color: #fff; }
[data-theme="terminal"] .limits-list li { color: var(--text-body); border-color: var(--border); }
[data-theme="terminal"] .limits-list b { color: var(--text-strong); }

/* Four steps with a line that flows from one to the next. */
.pipeline { position: relative; display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--space-6); margin: 0; padding: 0; list-style: none; counter-reset: pipe; }
.pipeline::before {
  content: ""; position: absolute; left: 12%; right: 12%; top: 32px; height: 3px; border-radius: 3px;
  background: repeating-linear-gradient(90deg, var(--brand) 0 10px, transparent 10px 20px); opacity: 0.5;
  animation: pipe-flow 1s linear infinite;
}
@keyframes pipe-flow { to { background-position: 20px 0; } }
.pipeline li { position: relative; margin: 0; text-align: center; counter-increment: pipe; }
.pipe-ic {
  position: relative; display: grid; place-items: center; width: 64px; height: 64px; margin: 0 auto var(--space-5);
  border-radius: 20px; background: var(--brand); color: var(--on-brand); box-shadow: var(--shadow-lg), 0 0 0 8px var(--brand-subtle);
}
.pipe-ic svg { width: 28px; height: 28px; }
.pipeline h3 { font-size: var(--text-lg); color: var(--text-strong); margin-bottom: var(--space-2); }
.pipeline h3::before { content: counter(pipe) ". "; color: var(--brand); }
.pipeline p { color: var(--text-muted); font-size: var(--text-sm); margin: 0; }
@media (max-width: 900px) {
  .pipeline { grid-template-columns: 1fr; gap: var(--space-10); }
  .pipeline::before { left: 50%; right: auto; top: 32px; bottom: 32px; width: 3px; height: auto;
    background: repeating-linear-gradient(180deg, var(--brand) 0 10px, transparent 10px 20px); }
  /* Each step is a card on a phone, so the text has room and the line runs between cards. */
  .pipeline li { padding: var(--space-6) var(--space-5); border-radius: 24px; background: var(--surface-card); border: 1px solid var(--border-faint); box-shadow: var(--shadow-sm); }
  .pipe-ic { margin-bottom: var(--space-4); }
}
.callout.report { max-width: 860px; margin: var(--space-8) auto 0; }

/* ---- Tables -------------------------------------------------- */
.table-wrap { overflow-x: auto; border: 1px solid var(--border); border-radius: var(--radius-lg); background: var(--glass); }
table { width: 100%; border-collapse: collapse; font-size: var(--text-sm); }
th, td { padding: var(--space-3) var(--space-4); text-align: left; vertical-align: top; border-bottom: 1px solid var(--border-faint); }
thead th { background: var(--surface-header); color: var(--text-strong); font-weight: var(--fw-bold); border-bottom-color: var(--border); }
tbody tr:last-child td, tbody tr:last-child th { border-bottom: 0; }
tbody th { color: var(--text-strong); font-weight: var(--fw-semibold); }
td.yes { color: var(--success-ink, var(--brand)); font-weight: var(--fw-bold); }
[data-theme="dark"] td.yes, [data-theme="terminal"] td.yes { color: var(--brand); }

/* ---- FAQ ----------------------------------------------------- */
.faq { display: grid; gap: var(--space-3); }
.faq details { background: var(--glass); border: 1px solid var(--border); border-radius: var(--radius-lg); padding: 0 var(--space-5); }
.faq summary {
  display: flex; justify-content: space-between; gap: var(--space-4);
  padding: var(--space-4) 0; cursor: pointer; list-style: none;
  font-weight: var(--fw-bold); color: var(--text-strong);
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary { align-items: center; }
/* A plus drawn from two bars, so it is exactly centred. Open, the upright bar goes and a minus stays. */
.faq summary::after {
  content: ""; flex: none; width: 28px; height: 28px; border-radius: 50%;
  background:
    linear-gradient(var(--brand), var(--brand)) center / 12px 2px no-repeat,
    linear-gradient(var(--brand), var(--brand)) center / 2px 12px no-repeat,
    var(--brand-subtle);
  transition: transform 0.2s;
}
.faq details[open] summary::after {
  background: linear-gradient(var(--brand), var(--brand)) center / 12px 2px no-repeat, var(--brand-subtle);
  transform: rotate(180deg);
}
.faq details > div { padding-bottom: var(--space-4); }

/* ---- Article ------------------------------------------------------ */
.article-hero { position: relative; isolation: isolate; overflow: hidden; padding: var(--space-16) 0 var(--space-10); margin-bottom: var(--space-4); border-bottom: 1px solid var(--border-faint); }
.article-hero .aurora i { opacity: 0.7; }
.article-hero h1 { font-size: clamp(2.25rem, 3.5vw + 1rem, 3.5rem); line-height: 1.08; letter-spacing: -0.03em; color: var(--text-strong); margin-bottom: var(--space-4); text-wrap: balance; }
[data-theme="terminal"] .article-hero h1 { letter-spacing: -0.01em; }
.breadcrumb { font-size: var(--text-sm); color: var(--text-muted); margin-bottom: var(--space-5); }
.breadcrumb a { color: var(--text-muted); text-decoration: none; }
.breadcrumb a:hover { color: var(--brand); }
.meta { font-size: var(--text-sm); color: var(--text-faint); }

/* A thin bar under the nav that fills as you read. */
.read-progress { position: fixed; z-index: 60; left: 0; top: 64px; height: 3px; width: 100%; transform-origin: 0 50%; transform: scaleX(var(--read, 0)); background: linear-gradient(90deg, var(--brand), var(--brand-hi, var(--brand))); }
.ds-app .read-progress { top: 0; }

.prose { font-size: 1.125rem; line-height: 1.75; padding-top: var(--space-6); }
.prose > .lead:first-child { font-size: 1.3125rem; line-height: 1.6; color: var(--text-strong); max-width: none; margin-bottom: var(--space-8); }
.prose h2 { font-size: clamp(1.5rem, 1vw + 1.1rem, 1.875rem); letter-spacing: -0.02em; color: var(--text-strong); margin-top: var(--space-16); margin-bottom: var(--space-4); }
.prose h3 { font-size: var(--text-xl); color: var(--text-strong); margin-top: var(--space-10); }
.prose li { margin-bottom: var(--space-2); }
.prose ul { padding-left: 0; list-style: none; }
.prose ul > li { position: relative; padding-left: var(--space-6); }
.prose ul > li::before { content: ""; position: absolute; left: 4px; top: 0.7em; width: 7px; height: 7px; border-radius: 50%; background: var(--brand); }
.prose strong { color: var(--text-strong); }
.prose .table-wrap { margin: var(--space-8) 0; border-radius: 20px; }
.prose code { font-family: ui-monospace, "SF Mono", Menlo, monospace; font-size: 0.88em; background: var(--code-bg); padding: 0.12em 0.4em; border-radius: 6px; }
.prose ol.steps { counter-reset: step; list-style: none; padding: 0; }
.prose ol.steps > li { counter-increment: step; position: relative; padding-left: var(--space-12); margin-bottom: var(--space-5); }
.prose ol.steps > li::before {
  content: counter(step); position: absolute; left: 0; top: 0.05em;
  display: grid; place-items: center; width: 32px; height: 32px; border-radius: 50%;
  background: var(--brand); color: var(--on-brand); font-weight: var(--fw-extra); font-size: var(--text-sm);
}
.callout {
  margin: var(--space-8) 0; padding: var(--space-5) var(--space-6);
  border-radius: 20px; background: var(--brand-subtle); border: 1px solid var(--brand-border); color: var(--text-body);
}
.callout p:last-child { margin-bottom: 0; }
.callout.warn { background: var(--warning-bg); border-color: var(--accent-mid, var(--warning)); }
[data-theme="dark"] .callout.warn, [data-theme="terminal"] .callout.warn { background: var(--brand-subtle); border-color: var(--brand-border); }
@media (prefers-color-scheme: dark) { [data-theme="auto"] .callout.warn { background: var(--brand-subtle); border-color: var(--brand-border); } }

.article-end { margin-top: var(--space-20); padding: var(--space-16) 0; background: var(--surface-subtle); border-top: 1px solid var(--border-faint); }
.article-end .eyebrow { display: block; margin-bottom: var(--space-5); }
[data-theme="dark"] .article-end { background: rgb(255 255 255 / 0.03); }
.article-list { display: grid; gap: var(--space-5); }
.article-link {
  position: relative; display: flex; flex-direction: column; padding: var(--space-8); border-radius: 26px;
  text-decoration: none; color: inherit; background: var(--glass); border: 1px solid var(--glass-border); box-shadow: var(--shadow-sm);
  transition: transform 0.2s, box-shadow 0.2s, border-color 0.2s;
}
.article-link:hover { transform: translateY(-4px); box-shadow: var(--shadow-lg); border-color: var(--brand-border); color: inherit; }
.article-link h3 { color: var(--text-strong); font-size: var(--text-xl); line-height: 1.25; letter-spacing: -0.01em; margin-bottom: var(--space-3); text-wrap: balance; }
.article-link p { color: var(--text-muted); margin-bottom: var(--space-5); flex: 1; }
.article-foot { display: flex; align-items: center; justify-content: space-between; }
.article-go {
  display: grid; place-items: center; width: 36px; height: 36px; border-radius: 50%;
  background: var(--brand-subtle); color: var(--brand); font-weight: var(--fw-bold); transition: background 0.2s, color 0.2s, translate 0.2s;
}
.article-link:hover .article-go { background: var(--brand); color: var(--on-brand); translate: 4px 0; }

/* Contact, at the end of help. */
.contact { padding: var(--space-8); border-radius: 26px; background: var(--glass); border: 1px solid var(--glass-border); box-shadow: var(--shadow-sm); }
.contact h2 { font-size: var(--text-2xl); color: var(--text-strong); margin-bottom: var(--space-3); }

/* ---- Call-to-action band, at the end of every page ------------------
   A rounded panel in the brand colours: the text and badge on the left, a
   photo on the right that fades into the panel, with the unlock screen in front. */
.cta-band { padding: var(--space-16) var(--space-5); }
.cta-panel {
  position: relative; isolation: isolate; overflow: hidden; max-width: 1120px; padding: 0;
  display: grid; grid-template-columns: 1.05fr 0.95fr; align-items: stretch; min-height: 460px;
  border-radius: 36px; background: linear-gradient(135deg, var(--brand), #9333ea 55%, #ec4899); color: rgb(255 255 255 / 0.85);
  box-shadow: var(--shadow-xl);
}
.cta-panel::before {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background-image: radial-gradient(rgb(255 255 255 / 0.3) 1.6px, transparent 1.8px); background-size: 28px 28px;
  -webkit-mask-image: linear-gradient(90deg, #000, transparent 60%); mask-image: linear-gradient(90deg, #000, transparent 60%);
  animation: dots-drift 40s linear infinite;
}
.cta-copy { display: flex; flex-direction: column; justify-content: center; padding: var(--space-16) var(--space-12); }
.cta-band h2 { color: #fff; font-size: clamp(2rem, 3vw + 1rem, 3.5rem); line-height: 1.05; letter-spacing: -0.03em; margin-bottom: var(--space-4); }
.cta-band .lead { color: rgb(255 255 255 / 0.85); margin: 0 0 var(--space-8); max-width: 26em; text-wrap: balance; }
.cta-band .store-badge .badge-black { display: block; }
.cta-band .store-badge .badge-white { display: none !important; }
.cta-art { position: relative; min-height: 400px; }
/* The photo sits in its own frame, with its own colours. The phones overlap only its
   left edge, so they never cover her face. */
.cta-photo {
  position: absolute; top: 28px; right: 28px; bottom: 28px; left: 96px; width: calc(100% - 124px); height: calc(100% - 56px);
  object-fit: cover; object-position: 55% 22%; border-radius: 26px;
  box-shadow: 0 30px 60px -20px rgb(0 0 0 / 0.45), 0 0 0 1px rgb(255 255 255 / 0.18);
}
.cta-phone { position: absolute; z-index: 1; left: -30px; bottom: -12%; width: 130px; rotate: -8deg; animation: float 7s ease-in-out infinite; }
/* Corners scale with the phone, at about the proportions of an iPhone. */
.cta-phone .phone { width: 100%; border-width: 5px; border-radius: 15% / 7%; box-shadow: 0 30px 60px -10px rgb(0 0 0 / 0.5); }
.cta-phone .phone img { border-radius: 12% / 5.5%; }
.cta-phone2 { position: absolute; z-index: 2; left: 90px; bottom: -8%; width: 118px; rotate: 6deg; animation: float 8s ease-in-out infinite; animation-delay: -3s; }
.cta-phone2 .phone { width: 100%; border-width: 5px; border-radius: 15% / 7%; box-shadow: 0 30px 60px -10px rgb(0 0 0 / 0.5); }
.lightbox .scr { display: block; position: relative; }
.lightbox img { border-radius: 12% / 5.5%; }
/* `.phone img` hides each image that is not the theme's screenshot. A photo laid over the
   viewer screen must show in all themes: the closing panel and the hero tour. */
.phone .zoom img { display: block; border-radius: 0; }
.cta-chip {
  position: absolute; z-index: 3; right: 44px; top: 44px; display: inline-flex; align-items: center; gap: var(--space-2);
  padding: 8px 14px; border-radius: var(--radius-full); background: rgb(255 255 255 / 0.92); color: #111827;
  font-size: var(--text-xs); font-weight: var(--fw-bold); box-shadow: var(--shadow-lg); white-space: nowrap;
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px); animation: float 6s ease-in-out infinite; animation-delay: -2s;
}
.cta-chip svg { width: 16px; height: 16px; color: #4f46e5; }
[data-theme="terminal"] .cta-panel { background: linear-gradient(135deg, #0a110c, #0f2a18); border: 1px solid var(--brand-border); color: var(--text-body); }
[data-theme="terminal"] .cta-band h2 { color: var(--text-strong); }
[data-theme="terminal"] .cta-band .lead { color: var(--text-body); }
[data-theme="terminal"] .cta-photo { filter: grayscale(1) sepia(1) hue-rotate(70deg) saturate(1.6) brightness(0.8); }
[data-theme="pink"] .cta-panel { background: linear-gradient(135deg, #d63384, #e8559b 55%, #c084fc); }
@media (max-width: 900px) {
  .cta-panel { grid-template-columns: 1fr; text-align: center; }
  .cta-copy { padding: var(--space-12) var(--space-6) var(--space-6); }
  .cta-band .lead { margin-left: auto; margin-right: auto; }
  .cta-band .cta-row { justify-content: center; }
  .cta-art { min-height: 380px; }
  .cta-photo { top: 0; left: 20px; right: 20px; bottom: 24px; width: calc(100% - 40px); height: calc(100% - 24px); object-position: 62% 20%; }
  .cta-phone .phone, .cta-phone2 .phone { border-width: 3px; }
  .cta-phone { width: 80px; left: -14px; bottom: -6%; }
  .cta-phone2 { width: 76px; left: 52px; bottom: -3%; }
  .cta-chip { right: 32px; top: 14px; bottom: auto; font-size: var(--text-xs); }
}

/* 404 */
.not-found { text-align: center; }
.nf-pattern { width: 160px; margin: 0 auto var(--space-6); }

/* ---- Footer -------------------------------------------------- */
.footer { margin-top: var(--space-16); padding: var(--space-12) 0 var(--space-8); border-top: 1px solid var(--border); background: var(--glass); }
.footer-grid { display: grid; grid-template-columns: 1.6fr 1fr 1fr 1fr; gap: var(--space-8); }
.footer h2 { font-size: var(--text-xs); letter-spacing: var(--tracking-eyebrow); text-transform: uppercase; color: var(--text-faint); margin-bottom: var(--space-3); }
.footer nav a { display: block; color: var(--text-body); text-decoration: none; font-size: var(--text-sm); padding: 4px 0; }
.footer nav a:hover { color: var(--brand); }
.footer-brand p { margin: var(--space-3) 0 var(--space-5); color: var(--text-muted); font-size: var(--text-sm); }
.footer-base { margin-top: var(--space-10); font-size: var(--text-xs); color: var(--text-faint); }
.theme-picker { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); }
.theme-picker-label { font-size: var(--text-xs); color: var(--text-faint); margin-right: var(--space-1); }
.theme-picker button {
  font: inherit; font-size: var(--text-xs); font-weight: var(--fw-semibold);
  padding: 4px 10px; border-radius: var(--radius-full); cursor: pointer;
  background: transparent; color: var(--text-muted); border: 1px solid var(--border);
}
.theme-picker button[aria-pressed="true"] { background: var(--brand); color: var(--on-brand); border-color: var(--brand); }
@media (max-width: 760px) { .footer-grid { grid-template-columns: 1fr 1fr; } .footer-brand { grid-column: 1 / -1; } }


/* ---- Opened from the app's help viewer (?app=1) --------------
   The app draws its own title bar and close button. Show the
   article only: no nav, no footer and no App Store links. */
.ds-app .nav,
.ds-app .footer,
.ds-app .cta-band,
.ds-app .breadcrumb,
.ds-app [data-app-store],
.ds-app .app-hidden { display: none !important; }
.ds-app .article-head { padding-top: var(--space-6); }
.ds-app .footer { margin: 0; }

/* site.js marks a section that is off screen. Its animations wait until it comes back. */
[data-off], [data-off] *, [data-off] *::before, [data-off] *::after { animation-play-state: paused !important; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  * { transition: none !important; animation: none !important; }
  .js .reveal { opacity: 1; transform: none; }
}
