/* KLUCZNIK — shared foundation (tokens, base, aura). Page CSS stays inline. */
/* ─── [02] :root tokens ─────────────────────────────────────────────────── */
:root {
  /* color: base (huashu palette, locked) */
  --bg:        #E8EDF2;   /* page bg, cool grey-blue */
  --deep:      #2C3947;   /* primary ink, nav, dark surfaces */
  --accent:    #547A95;   /* mid-blue, links / focus / progress */
  --gold:      #C2A56D;   /* the brass key — accents, badges, CTAs of trust */
  --gold-deep: #8A6B2A;   /* gold on light: text-readable variant */
  --gold-hover:#B5944A;   /* gold button :hover — was a magic hex on 5 pages */
  --text:      #1A252F;   /* body text */
  --muted:     #7A8FA0;   /* secondary, helper, captions */
  --surface:   #F4F7FA;   /* card bg, raised surfaces */
  --border:    #D1DCE5;   /* hairline, dividers, default form border */
  --danger:    #8B3A3A;   /* error, destructive */
  --success:   #2E6B4F;   /* success, online, claim */

  /* color: semantic foreground (fg1 > fg2 > fg3) */
  --fg1: var(--text);
  --fg2: var(--deep);
  --fg3: var(--muted);
  --fg-inverse: #FFFFFF;
  --fg-on-gold: var(--deep);
  --link: var(--accent);
  --link-hover: var(--deep);

  /* color: semantic surface */
  --bg-page: var(--bg);
  --bg-card: var(--surface);
  --bg-elevated: #FFFFFF;
  --bg-deep: var(--deep);
  --bg-codeblock: var(--deep);
  --bg-codeblock-fg: #D2E0EA;
  --bg-codeblock-hl: var(--gold);
  --bg-codeblock-comment: #7A95A8;

  /* tinted surfaces (color-mixed into bg) — wabi calm, not flashy */
  --tint-accent:  color-mix(in oklab, var(--accent) 8%, var(--surface));
  --tint-gold:    color-mix(in oklab, var(--gold) 8%, var(--surface));
  --tint-success: color-mix(in oklab, var(--success) 8%, var(--surface));
  --tint-danger:  color-mix(in oklab, var(--danger) 8%, var(--surface));

  /* radius */
  --radius-sm: 6px;
  --radius:    10px;
  --radius-lg: 14px;
  --radius-pill: 999px;
  --radius-imperfect: 8px 8px 6px 8px;

  /* shadow / elevation */
  --shadow-hairline: 0 1px 2px rgba(26,37,47,.04);
  --shadow-soft:     0 1px 2px rgba(26,37,47,.04), 0 8px 28px -16px rgba(26,37,47,.18);
  --shadow-card:     0 1px 2px rgba(26,37,47,.04), 0 8px 24px -12px rgba(26,37,47,.12);
  --shadow-sticky:   0 -4px 14px -10px rgba(44,57,71,.2);
  --shadow-focus:    0 0 0 3px color-mix(in oklab, var(--accent) 18%, transparent);
  --shadow-focus-gold: 0 0 0 2px color-mix(in oklab, var(--gold) 28%, transparent);

  /* spacing scale (4px base) */
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 20px;
  --space-6: 24px;
  --space-7: 28px;
  --space-8: 32px;
  --space-9: 36px;
  --space-10: 40px;
  --space-12: 48px;
  --space-16: 64px;
  --space-20: 80px;

  /* motion */
  --ease-out:   cubic-bezier(.2,.7,.2,1);
  --ease-press: cubic-bezier(.4,.0,.6,1);
  --dur-fast:   120ms;
  --dur-base:   180ms;
  --dur-trans:  240ms;
  --dur-enter:  320ms;
  --dur-slow:   600ms;

  /* type: families */
  --font-sans: 'Inter', system-ui, -apple-system, 'Segoe UI', sans-serif;
  --font-mono: 'JetBrains Mono', 'SF Mono', 'Fira Code', ui-monospace, monospace;

  /* type: feature settings */
  --font-features: 'ss01', 'cv11';

  /* ─── additive: converged spacing + type system ─────────────────────────
     Synthesizes neuropsych rhythm (predictable 4px cadence reduces cognitive
     load), dashboard density norms (clamp-fluid gaps that don't collapse on
     mobile), and a 6-tier type scale tuned so eyebrow→h1→body chain reads
     as a single hierarchical breath. Strictly additive — no overrides. */

  /* spacing primitives (continue 4px scale) */
  --space-24: 96px;
  --space-32: 128px;

  /* semantic spacing aliases */
  --gap-section-d: clamp(64px, 8vw, 128px);
  --gap-section-m: clamp(40px, 12vw, 72px);
  --pad-card:      clamp(20px, 2.4vw, 28px);
  --pad-hero:      clamp(28px, 3.6vw, 40px);
  --gap-card-stack: 16px;
  --gap-h1-body:    24px;
  --gap-h2-body:    16px;
  --gap-eyebrow-h1: 12px;
  --gap-cta:        32px;
  --gutter:         clamp(16px, 4vw, 32px);

  /* paragraph + stack rhythm (snap raw 18/14/10/9 drift onto grid by intent) */
  --gap-p:          clamp(16px, 0.5vw + 14px, 20px); /* body <p>/prose block rhythm — formalizes raw 18px onto grid */
  --gap-stack-tight: 8px;  /* dense vertical/inline stacks (alias --space-2) */
  --gap-row:        12px;  /* comfortable content rows/lists (alias --space-3) */
  --gap-field:      16px;  /* form fields + mobile grid gaps (alias --space-4) */
  --gap-chip:       8px;   /* inline chip/pill/button icon-text gap (alias --space-2) */

  /* 6-tier type scale (font-shorthand-ready) */
  --ts-eyebrow-font:  600 12px/1 var(--font-mono);
  --ts-eyebrow-track: .08em;
  --ts-eyebrow-case:  uppercase;

  --ts-h1-font:  700 clamp(40px, 5.2vw, 56px)/1.05 var(--font-sans);
  --ts-h1-track: -.02em;

  --ts-h2-font:  600 clamp(28px, 3.2vw, 36px)/1.15 var(--font-sans);
  --ts-h2-track: -.01em;

  --ts-body-lg-font: 400 18px/1.555 var(--font-sans);
  --ts-body-font:    400 16px/1.5 var(--font-sans);

  --ts-micro-font:  500 13px/1.385 var(--font-mono);
  --ts-micro-track: .01em;
}

/* mobile body floor */
@media (max-width: 480px) {
  :root { --ts-body-font: 400 15px/1.5 var(--font-sans); }
}

/* one-time global: balance long headings */
h1, h2 { text-wrap: balance; }

/* additive utility classes */
.nums-tabular { font-variant-numeric: tabular-nums; }
.text-balance { text-wrap: balance; }
.read-65      { max-inline-size: 65ch; }

/* ─── [03] base reset + body + paper noise ──────────────────────────────── */
* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
body {
  font-family: var(--font-sans);
  background: var(--bg);
  color: var(--text);
  font-size: 15px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  font-feature-settings: var(--font-features);
  min-height: 100vh;
}

/* paper texture, ABOVE aura so it grains the whole composition */
body::after {
  content: ""; position: fixed; inset: 0; pointer-events: none; z-index: 1;
  opacity: .035; mix-blend-mode: multiply;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='64' height='64'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='2' seed='7'/><feColorMatrix values='0 0 0 0 .1 0 0 0 0 .14 0 0 0 0 .18 0 0 0 .9 0'/></filter><rect width='64' height='64' filter='url(%23n)'/></svg>");
  background-size: 64px 64px;
}

/* all content lifts above aura + texture */
.page { position: relative; z-index: 2; }

/* ─── [04] fluid type scale ─────────────────────────────────────────────── */
/* tracking tightens as size grows.
   line-height stays generous so polish descenders (ą ę ł) breathe. */
.type-display { font: 600 clamp(2.4rem, 6vw + 1rem, 5.2rem)/1.04 var(--font-sans); letter-spacing: -0.035em; color: var(--fg2); }
.type-h1      { font: 600 clamp(1.9rem, 3.6vw + .6rem, 3.2rem)/1.10 var(--font-sans); letter-spacing: -0.025em; color: var(--fg2); }
.type-h2      { font: 600 clamp(1.4rem, 2vw + .5rem, 2.1rem)/1.18 var(--font-sans); letter-spacing: -0.015em; color: var(--fg2); }
.type-h3      { font: 600 1.125rem/1.3 var(--font-sans); letter-spacing: -0.005em; color: var(--fg2); }
.type-body    { font: 400 clamp(1rem, .4vw + .9rem, 1.125rem)/1.55 var(--font-sans); letter-spacing: -0.005em; color: var(--fg1); }
.type-lead    { font: 400 clamp(1.05rem, .5vw + .95rem, 1.25rem)/1.55 var(--font-sans); letter-spacing: -0.008em; color: var(--fg3); }
.type-small   { font: 400 13px/1.5 var(--font-sans); color: var(--fg1); }
.type-caption { font: 500 12px/1.45 var(--font-sans); color: var(--fg3); }
.type-meta    { font: 500 clamp(.72rem, .1vw + .7rem, .8rem)/1.4 var(--font-sans); letter-spacing: 0.06em; text-transform: uppercase; color: var(--fg3); }
.type-eyebrow { font: 500 11px/1.2 var(--font-sans); letter-spacing: 0.14em; text-transform: uppercase; color: var(--accent); }
.type-mono    { font: 400 clamp(.82rem, .2vw + .78rem, .94rem)/1.5 var(--font-mono); letter-spacing: 0; }
.type-key     { font: 600 14px/1.4 var(--font-mono); letter-spacing: 0.04em; color: var(--fg2); }
.type-tabnum  { font-variant-numeric: tabular-nums; }

/* semantic shortcuts (matches dom defaults so plain h1/p look right) */
h1.k-display, .k-h1 { font: 600 clamp(1.9rem, 3.6vw + .6rem, 3.2rem)/1.10 var(--font-sans); letter-spacing: -0.025em; color: var(--fg2); }
h2.k-h2, .k-h2     { font: 600 clamp(1.4rem, 2vw + .5rem, 2.1rem)/1.18 var(--font-sans); letter-spacing: -0.015em; color: var(--fg2); }
.k-body            { font: 400 16px/1.55 var(--font-sans); color: var(--fg1); }
.k-code            { font: 400 13px/1.65 var(--font-mono); color: var(--fg2); }

/* ─── [05] aura (atmosphere) ────────────────────────────────────────────── */
/* blobs drift on their own keyframes; the .pull wrapper offsets the whole
   set by a fraction of the cursor position so the atmosphere "looks at" you. */
.aura {
  position: fixed; inset: 0;
  z-index: 0; pointer-events: none;
  overflow: hidden;
}
.aura .pull {
  position: absolute; inset: 0;
  transform: translate(
    calc((var(--cx, 50) - 50) * 0.18px),
    calc((var(--cy, 50) - 50) * 0.16px)
  );
  transition: transform 1.4s var(--ease-out);
  will-change: transform;
}
.aura .blob {
  position: absolute;
  border-radius: 50%;
  filter: blur(70px);
  mix-blend-mode: multiply;
  will-change: transform, opacity;
  opacity: .55;
}
.aura .b1 {
  width: 56vmax; height: 56vmax;
  top: -22vmax; left: -16vmax;
  background: radial-gradient(closest-side, color-mix(in oklab, var(--gold) 55%, transparent), transparent 70%);
  animation: aura-drift-1 28s ease-in-out infinite alternate;
}
.aura .b2 {
  width: 48vmax; height: 48vmax;
  bottom: -18vmax; right: -14vmax;
  background: radial-gradient(closest-side, color-mix(in oklab, var(--accent) 50%, transparent), transparent 70%);
  animation: aura-drift-2 36s ease-in-out infinite alternate;
}
.aura .b3 {
  width: 38vmax; height: 38vmax;
  top: 32%; left: 38%;
  background: radial-gradient(closest-side, color-mix(in oklab, var(--deep) 14%, transparent), transparent 65%);
  animation: aura-drift-3 44s ease-in-out infinite alternate;
  opacity: .35;
}
.aura .b4 {
  width: 28vmax; height: 28vmax;
  top: 58%; left: 8%;
  background: radial-gradient(closest-side, color-mix(in oklab, var(--gold) 38%, transparent), transparent 70%);
  animation: aura-drift-4 32s ease-in-out infinite alternate;
  opacity: .45;
}
/* an extra small "reactive" blob — pulses at the cursor position */
.aura .b-cursor {
  position: absolute;
  width: 22vmax; height: 22vmax;
  border-radius: 50%;
  filter: blur(56px);
  mix-blend-mode: multiply;
  background: radial-gradient(closest-side, color-mix(in oklab, var(--accent) 38%, transparent), transparent 65%);
  pointer-events: none;
  left: calc(var(--cx, 50) * 1vw);
  top:  calc(var(--cy, 50) * 1vh);
  transform: translate(-50%, -50%);
  transition: left .8s var(--ease-out), top .8s var(--ease-out), opacity .8s var(--ease-out);
  opacity: .22;
}

@keyframes aura-drift-1 {
  0%   { transform: translate(0, 0)        scale(1);    opacity: .55; }
  50%  { transform: translate(12vw, 6vh)   scale(1.18); opacity: .42; }
  100% { transform: translate(-6vw, 10vh)  scale(.86);  opacity: .60; }
}
@keyframes aura-drift-2 {
  0%   { transform: translate(0, 0)         scale(1);    opacity: .50; }
  50%  { transform: translate(-10vw, -8vh)  scale(.78);  opacity: .60; }
  100% { transform: translate(6vw, -14vh)   scale(1.22); opacity: .40; }
}
@keyframes aura-drift-3 {
  0%   { transform: translate(0, 0)        scale(1);   opacity: .35; }
  50%  { transform: translate(8vw, -5vh)   scale(1.3); opacity: .25; }
  100% { transform: translate(-10vw, 10vh) scale(.7);  opacity: .42; }
}
@keyframes aura-drift-4 {
  0%   { transform: translate(0, 0)         scale(1);    opacity: .45; }
  50%  { transform: translate(10vw, -12vh)  scale(.7);   opacity: .55; }
  100% { transform: translate(-8vw, 8vh)    scale(1.25); opacity: .35; }
}

@media (prefers-reduced-motion: reduce) {
  .aura .blob,
  .aura .b-cursor,
  .footer-blob,
  .saved-hero-bg,
  .aura .blob,
  .aura .b-cursor {
    animation: none !important;
    transition: none !important;
  }
}

/* ─── [06] mobile foundation ────────────────────────────────────────────────
   Appended by MOBILE FOUNDATION pass. Do not move tokens above this line.
   All rules here are additive — nothing above is overridden.              */

/* ── saldo color-state thresholds ──────────────────────────────────────────
   Used by mobile-fx.js saldoColorState() and any page that color-codes the
   balance display. Progression: gold → desaturated gold → amber → graphite.
   NEVER use red — balance depletion is calm, not alarming.
     healthy  ≥30 % remaining
     low      10–30 %
     warn      5–10 %
     empty     <5 %                                                         */
:root {
  --saldo-healthy: var(--gold);
  --saldo-low:     #B89060;
  --saldo-warn:    #C9923A;
  --saldo-empty:   var(--muted);
}

/* ── view-transition-name convention ────────────────────────────────────────
   Pages that animate the saldo number across a navigation should set:
     view-transition-name: saldo
   on the element holding the balance figure BEFORE calling
   document.startViewTransition(). For list items keyed by ID use:
     view-transition-name: key-${id}
   where ${id} is the item's unique identifier (set inline via JS).
   mobile-fx.js viewTransition() wraps startViewTransition with a graceful
   fallback so pages never need to branch manually.
   CSS for the ::view-transition-* pseudo-elements lives per-page or in
   mobile-fx.css — not here — so pages can customise timing independently.  */

/* ── mobile viewport ────────────────────────────────────────────────────── */
@media (max-width: 640px) {
  /* Dynamic/large/small viewport height vars — polyfill via JS for engines
     that do not yet expose dvh/lvh/svh. JS reads these to size full-height
     panels without the iOS toolbar bounce problem.                         */
  :root {
    --vh-s: 1svh;   /* small viewport height  — excludes all UA chrome      */
    --vh-l: 1lvh;   /* large viewport height  — excludes only permanent bars */
    --vh-d: 1dvh;   /* dynamic viewport height — tracks toolbar show/hide   */
  }

  /* Safe area inset utilities. Use .safe-top / .safe-bot on sticky headers
     and bottom nav so they clear notch + home indicator on all iOS devices. */
  .safe-top  { padding-top:    env(safe-area-inset-top,    0px); }
  .safe-bot  { padding-bottom: env(safe-area-inset-bottom, 0px); }
  .safe-left { padding-left:   env(safe-area-inset-left,   0px); }
  .safe-right{ padding-right:  env(safe-area-inset-right,  0px); }

  /* Kill the grey flash on tap — coarse-pointer devices only get it when
     -webkit-tap-highlight-color is unset. Transparent preserves focus ring. */
  * { -webkit-tap-highlight-color: transparent; }

  /* Prevent accidental text-select and double-tap zoom on interactive nodes.
     manipulation = pan-x + pan-y + pinch-zoom; preserves all scroll.      */
  button, a, [role="button"], label, summary {
    touch-action: manipulation;
  }

  /* iOS Safari auto-zooms inputs smaller than 16px. Force 16px to stop it.
     The !important overrides any .type-* class that sets font-size smaller. */
  input, textarea, select {
    font-size: 16px !important;
  }

  /* Prevent pull-to-refresh on the body — pages that want it can opt out by
     setting overscroll-behavior-y: auto on their scroll container.         */
  body {
    overscroll-behavior-y: contain;
  }

  /* ── @media (hover:hover) guidance ───────────────────────────────────────
     Authors: gate hover-only enhancements behind this query so they never
     fire on touchscreens that emulate hover on long-press:

       @media (hover:hover) and (pointer:fine) {
         .card:hover { transform: translateY(-2px); }
       }

     KluczFX already checks window.KluczFX.fine before applying magnetic /
     tilt3d — no extra guard needed for those. For raw CSS, always use the
     media query above.                                                      */
}
