/* ═══════════════════════════════════════════════════════════════════════
   DataBandar — shared design tokens + base layer
   ───────────────────────────────────────────────────────────────────────
   Loaded by every template BEFORE its own inline <style>, so page CSS
   always wins on component rules. This file owns only:
     1. design tokens (previously duplicated in all 10 templates)
     2. a small accessibility/motion base layer

   Two surfaces, deliberately different — do not flatten them:
     SITE  (default)      landing, datasets, browse, login, profile
                          softer bg, rounder radii — marketing/gallery
     APP   (.surface-app) index, landcover3d, raster3d, terrain3d, points
                          cooler bg, tighter radii — dense tool chrome

   Every value here is byte-identical to what the templates used before
   the extraction, so centralising changed no pixels on its own.
   ═══════════════════════════════════════════════════════════════════════ */

:root {
  /* ── brand ─────────────────────────────────────────────────────────── */
  --brand: #FF7A1A;
  --brand-dark: #e86a0a;
  --brand2: #1f9d8b;

  /* ── accents (editor palettes, chart series, status) ───────────────── */
  --blue: #4a8fe7;
  --purple: #8b6cf0;
  --mint: #22b8a0;
  --coral: #f0656b;
  --yellow: #f5b342;
  --accent: #7c6cf8;
  --danger: #e05555;

  /* ── neutrals shared by both surfaces ──────────────────────────────── */
  --card: #f2f4f8;
  /* --soft was #8b929e, which failed WCAG AA on every surface it is used on
     (3.13:1 on white, 2.97 on the site bg, 2.77 on the app bg). It carries
     hint text, section labels and helper copy, so that was a real
     readability bug, not a nicety. #5f6672 clears 4.5:1 everywhere
     (5.78 / 5.49 / 5.11) while staying a soft grey rather than going black. */
  --soft: #5f6672;

  /* Brand-coloured TEXT on light backgrounds. --brand #FF7A1A is only
     2.61:1 on white — fine as a fill, unreadable as body text. Use
     --brand-ink for brand-tinted labels/links (4.72:1 worst case). */
  --brand-ink: #b34b06;

  /* ── type ──────────────────────────────────────────────────────────── */
  --font-ui: 'Plus Jakarta Sans', system-ui, sans-serif;
  --font-display: 'Outfit', sans-serif;
  --font-map: var(--font-display);   /* APP pages' alias for the same face */

  /* ── spacing scale ─────────────────────────────────────────────────── */
  /* Dense/dashboard ramp (8→32 core) — this app is a tool, not a brochure.
     Use these instead of ad-hoc px so density stays consistent. */
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 24px;
  --space-6: 32px;
  --space-7: 48px;
  --space-8: 64px;

  /* ── elevation ─────────────────────────────────────────────────────── */
  /* Two-layer shadows: a tight contact shadow for the edge + a wide diffuse
     one for the lift. Single-layer shadows (the previous set) read flat and
     slightly muddy at larger sizes — the contact layer is what makes a card
     look like it is sitting on the page rather than pasted onto it. */
  --shadow-xs: 0 1px 2px rgba(15, 20, 27, .05);
  --shadow-sm: 0 1px 2px rgba(15, 20, 27, .04), 0 3px 10px rgba(15, 20, 27, .05);
  --shadow-md: 0 2px 4px rgba(15, 20, 27, .03), 0 10px 28px rgba(15, 20, 27, .08);
  --shadow-lg: 0 4px 10px rgba(15, 20, 27, .04), 0 22px 52px rgba(15, 20, 27, .11);
  --shadow-xl: 0 8px 18px rgba(15, 20, 27, .05), 0 36px 80px rgba(15, 20, 27, .14);

  /* ── motion ────────────────────────────────────────────────────────── */
  /* 120–280ms: fast enough to feel instant, slow enough to read as motion */
  --dur-fast: 120ms;
  --dur: 180ms;
  --dur-slow: 280ms;
  --ease: cubic-bezier(.2, .6, .3, 1);

  /* ── focus ─────────────────────────────────────────────────────────── */
  --focus-ring: 3px solid rgba(255, 122, 26, .45);
  --focus-offset: 2px;

  /* ═══ SITE surface (default) ═══════════════════════════════════════ */
  --bg: #f8f9fb;
  --panel: #fff;
  --border: #e8ecf2;
  --text: #0f141b;
  --muted: #5b6472;
  --brandglow: rgba(255, 122, 26, .12);
  /* Radii nudged up ~15%: softer corners are the cheapest, most legible
     "this was refreshed" signal, and it applies to every card and panel
     on the marketing surface at once. */
  --radius-sm: 0.7rem;
  --radius: 1.05rem;
  --radius-lg: 1.6rem;
  --radius-xl: 2.2rem;
  /* Small-control radius. Lives in :root (not just .surface-app) so it
     resolves on every page — a var() that resolves nowhere silently
     computes to 0 and square-corners the control. */
  --r-sm: 8px;
}

/* ═══ APP surface — dense tool chrome ════════════════════════════════ */
body.surface-app {
  --bg: #eef1f6;
  --panel: #ffffff;
  --border: #d8dce6;
  --text: #0d1117;
  --muted: #606878;
  --brandglow: rgba(255, 122, 26, .16);
  /* Tool chrome stays tighter than the marketing surface, but 10px -> 12px
     is visible on every panel, card and control in the editor and 3D pages. */
  --radius: 12px;
  --r-sm: 8px;
  /* APP-only surfaces: the map stage and its paper-ish canvas */
  --stage: #e2e6ed;
  --map: #faf8f3;
  --card2: #e8ebf1;
}

/* ═══════════════════════════════════════════════════════════════════════
   Accessibility base layer
   ═══════════════════════════════════════════════════════════════════════ */

/* Visible keyboard focus on every interactive element.
   !important is deliberate and load-bearing here: the APP templates set
   `outline:none` on inputs/selects with higher specificity than any
   selector this file could use (it loads first), and their buttons have
   no focus style at all. Without the override, keyboard users get no
   focus indicator anywhere in the editor or the 3D pages.
   :focus-visible (not :focus) keeps the ring off mouse clicks. */
a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
summary:focus-visible,
[tabindex]:focus-visible,
[role="button"]:focus-visible {
  outline: var(--focus-ring) !important;
  outline-offset: var(--focus-offset) !important;
  border-radius: inherit;
}

/* Skip link — opt-in, only renders if a template includes one. */
.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 9999;
  padding: 10px 16px;
  background: var(--brand);
  color: #fff;
  font-family: var(--font-ui);
  font-weight: 700;
  font-size: 13px;
  border-radius: 0 0 var(--radius-sm, 8px) 0;
  text-decoration: none;
}
.skip-link:focus {
  left: 0;
}

/* Brand-tinted selection instead of the default blue. */
::selection {
  background: var(--brandglow);
  color: var(--text);
}

/* ═══════════════════════════════════════════════════════════════════════
   Reduced motion — respected app-wide.
   Several templates already scope this to one animation; this covers the
   rest (points, login, profile had none at all). Not `animation:none` —
   that would freeze the loading-sprite mid-frame and read as a hang.
   ═══════════════════════════════════════════════════════════════════════ */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
}
