/* =========================================================
   base.css — reset, design tokens, typography
   Direction: Linear-inspired. Near-black canvas, restrained
   violet accent used only for state (selection, links, focus,
   progress) — never as decoration. Tight, confident type scale.
   Edit color/type tokens here; everything else references them.
   ========================================================= */

:root{
  /* --- surface --- */
  --canvas:      #08090A;   /* page background */
  --surface:     #0D0E10;   /* cards, inputs */
  --surface-2:   #17181B;   /* hover / raised */
  --border:      rgba(255,255,255,.09);
  --border-strong: rgba(255,255,255,.16);

  /* --- text --- */
  --ink:         #F3F4F6;
  --ink-soft:    #8B8F98;
  --ink-faint:   #5C5F66;

  /* legacy aliases kept for older markup */
  --paper:       var(--canvas);
  --paper-dim:   var(--surface-2);
  --line:        var(--border);
  --line-strong: var(--border-strong);

  /* --- accent: violet, used for interactive state only --- */
  --violet:      #6E76F0;
  --violet-dim:  rgba(110,118,240,.14);
  --violet-text: var(--violet); /* violet-on-canvas text (links, .eyebrow) — see [data-theme="light"] override below for why this needs its own value */
  --blue:        var(--violet);
  --blue-dim:    var(--violet-dim);

  --green:       #4FC38A;
  --green-dim:   rgba(79,195,138,.14);
  --amber:       #E8A33D;
  --amber-dim:   rgba(232,163,61,.14);
  --red:         #EF6461;
  --red-dim:     rgba(239,100,97,.14);

  /* --- background grid (see body::before below) --- */
  --grid-line:        rgba(255,255,255,.028);
  --grid-line-strong: rgba(255,255,255,.055);

  /* --- isometric figure faces (login/dashboard FIG illustrations) ---
     Dark theme: unchanged from the original implementation (reuses
     --surface/--surface-2 + opacity for the 3-face shading). Light
     theme overrides these with dedicated solid colors instead --
     see the [data-theme="light"] block for why. */
  --iso-top:           var(--surface-2);
  --iso-left:          var(--surface);
  --iso-right:         var(--surface-2);
  --iso-left-opacity:  .8;
  --iso-right-opacity: .9;

  /* --- type --- */
  --font-display: 'Inter Tight', 'Inter', -apple-system, sans-serif;
  --font-body:    'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
  --font-mono:    'JetBrains Mono', 'SFMono-Regular', Menlo, monospace;

  /* --- layout --- */
  --wrap: 780px;
  --radius: 10px;
  --radius-sm: 7px;
  /* Proportional scale, same idea as shadcn/ui's --radius-* tokens
     (each size derived from one base value via calc(), not picked
     independently) — added for future components that need a size
     between --radius-sm and --radius, or larger than --radius.
     --radius-sm above is kept as its existing 7px rather than
     recalculated, so nothing already using it shifts. */
  --radius-md:  calc(var(--radius) * 0.8);
  --radius-lg:  var(--radius);
  --radius-xl:  calc(var(--radius) * 1.4);
  --radius-2xl: calc(var(--radius) * 1.8);

  /* --- motion: purposeful, not decorative --- */
  --dur-micro:  120ms;  /* hovers, clicks, focus rings */
  --dur-small:  220ms;  /* dropdowns, accordion panels, toggles */
  --dur-medium: 320ms;  /* modals, result reveals */
  --ease-out:    cubic-bezier(0.16, 1, 0.3, 1);      /* decelerate — entering */
  --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);      /* moving between states */
  --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);  /* slight overshoot — playful, used sparingly */
}

/* -----------------------------------------------------------
   Light theme — same bones as the dark theme above (identical
   type scale, spacing, radii, and the same --violet accent hue
   for fills/buttons so brand identity carries across both), not
   an inverted clone of it. Two things specifically don't just
   flip 1:1 from dark:

   1. Elevation direction reverses. In the dark theme, cards read
      as "raised" by being LIGHTER than the canvas (surface is a
      step up from canvas). Near white, that same trick reads as
      *dirty gray* rather than *elevated* — so here, --surface is
      pure white (lighter, not darker, than canvas) and elevation
      instead comes from --shadow-card, which the dark theme has
      no equivalent for (dark surfaces already read as raised from
      lightness alone, a shadow would barely be visible against a
      near-black canvas anyway).

   2. --violet-text exists because the *same* #6E76F0 that works
      fine as white-on-violet button fill, or as violet-on-black
      body text, fails WCAG AA (3.8:1, need 4.5:1) as violet text
      directly on a white/near-white canvas — links and .eyebrow
      labels specifically. Rather than re-tune --violet itself
      (and risk the button fill / dark-mode text looking off), only
      the text-on-canvas usage gets a deepened, same-hue variant
      (#4B44D6, ~6.8:1 on white) via this separate token. --violet
      itself is identical in both themes — the brand accent doesn't
      change, only where contrast math requires it to.
   ----------------------------------------------------------- */
[data-theme="light"]{
  --canvas:      #EAE9F5;
  --surface:     #FFFFFF;
  --surface-2:   #DFDCEF;
  --border:      rgba(20,18,40,.1);
  --border-strong: rgba(20,18,40,.18);

  --ink:         #16161C;
  --ink-soft:    #5B5E6B;
  --ink-faint:   #9A9CA8;

  --violet-text: #4B44D6;

  --green:       #1F8F5F;
  --green-dim:   rgba(31,143,95,.12);
  --amber:       #A8670A;
  --amber-dim:   rgba(168,103,10,.12);
  --red:         #C93E37;
  --red-dim:     rgba(201,62,55,.12);

  --grid-line:        rgba(20,18,40,.04);
  --grid-line-strong: rgba(20,18,40,.08);

  /* Measured, not guessed: canvas/surface/surface-2 sat around
     1.07-1.16:1 contrast against each other before this change --
     under ~1.15:1 is essentially imperceptible without a border
     doing all the work, confirmed by computing real WCAG relative-
     luminance contrast ratios, not just looking at it. Isometric
     figure faces specifically (which reused --surface/--surface-2)
     sat at 1.07-1.08:1 against the canvas -- "mixing into the
     background" was a literal, measurable description, not just a
     feeling. These dedicated colors (not reused from
     canvas/surface/surface-2) give the figures a real light-to-
     dark gradient across their three faces -- 1.22:1 / 1.55:1 /
     1.99:1 against canvas respectively -- both fixing the contrast
     problem and reading as more three-dimensional (a lit top face,
     progressively shadowed sides) than the flat opacity-blend the
     dark theme uses. Also gives the light theme actual violet hue
     in it rather than being pure neutral gray, addressing "no
     other color, totally white" directly. */
  --iso-top:           #D6D2EE;
  --iso-left:          #C0B9E2;
  --iso-right:         #AAA1D6;
  --iso-left-opacity:  1;
  --iso-right-opacity: 1;

  --shadow-card: 0 1px 2px rgba(20,18,40,.04), 0 6px 20px rgba(20,18,40,.06);
}

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

/* Smooth, deliberate theme switch — only the properties that
   actually change between themes, not a blanket `all` transition
   (which would also animate hovers/layout shifts that have nothing
   to do with theme). Respects prefers-reduced-motion via the
   shared rule further down. */
*{ transition: background-color var(--dur-small) var(--ease-in-out), color var(--dur-small) var(--ease-in-out), border-color var(--dur-small) var(--ease-in-out), box-shadow var(--dur-small) var(--ease-in-out); }

[hidden]{ display: none !important; }

html{ scroll-behavior: smooth; }

body{
  margin: 0;
  background: var(--canvas);
  background-image:
    radial-gradient(680px 420px at 12% -8%, rgba(110,118,240,.10), transparent 60%),
    radial-gradient(520px 360px at 100% 0%, rgba(110,118,240,.05), transparent 55%);
  background-repeat: no-repeat;
  color: var(--ink);
  font-family: var(--font-body);
  font-size: 16px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}

/* -----------------------------------------------------------
   Site-wide background — a static technical grid, replacing an
   earlier soft ambient "aurora" glow (blurred, animated,
   color-blob gradients). Direct feedback on that version: it read
   as generic "AI-generated SaaS" — soft glowing gradient blobs are
   a very overused trope at this point, regardless of how carefully
   tuned. A precise, static, blueprint-style grid is the opposite
   instinct: still restrained (very low opacity, no new brand
   color introduced), but reads as engineered rather than dreamy —
   matching the "FIG"-style isometric illustrations used elsewhere
   (see login.html) rather than fighting them.

   Two-tier grid, like real graph paper: fine 24px lines plus a
   bolder line every 4th cell (96px) for a sense of scale/structure
   rather than a flat, undifferentiated mesh. No blur, no
   animation, no noise layer -- hard-edged 1px lines don't suffer
   the gradient color-banding problem that motivated the noise
   dither on the old aurora version, so that whole extra layer is
   gone too. Fixed + negative z-index so it sits behind all page
   content; one rule on body means every page picks it up via
   base.css with no per-page markup.
   ----------------------------------------------------------- */
body::before{
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background-image:
    linear-gradient(var(--grid-line) 1px, transparent 1px),
    linear-gradient(90deg, var(--grid-line) 1px, transparent 1px),
    linear-gradient(var(--grid-line-strong) 1px, transparent 1px),
    linear-gradient(90deg, var(--grid-line-strong) 1px, transparent 1px);
  background-size: 24px 24px, 24px 24px, 96px 96px, 96px 96px;
}

/* Shared "this just appeared" entrance — a result, a saved
   confirmation, anything that should read as a direct consequence
   of the action the person just took. Transform + opacity only
   (no layout-triggering properties), one-shot, not looping. */
@keyframes reveal-in{
  from{ opacity: 0; transform: translateY(8px); }
  to{ opacity: 1; transform: translateY(0); }
}
.reveal-in{ animation: reveal-in var(--dur-medium) var(--ease-out); }

h1, h2, h3{
  font-family: var(--font-display);
  color: var(--ink);
  margin: 0 0 .4em;
  line-height: 1.12;
  font-weight: 700;
  letter-spacing: -.015em;
}

h1{ font-size: clamp(1.7rem, 1.3rem + 1.6vw, 2.4rem); }
h2{ font-size: clamp(1.3rem, 1.08rem + 1vw, 1.7rem); }

p{ margin: 0 0 1em; color: var(--ink-soft); }

.eyebrow{
  display: inline-block;
  font-family: var(--font-mono);
  font-size: .72rem;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--violet-text);
  margin-bottom: .6em;
}

.lede{
  font-size: 1.02rem;
  max-width: 52ch;
}

code{
  font-family: var(--font-mono);
  background: var(--surface-2);
  color: var(--ink);
  padding: .1em .4em;
  border-radius: 4px;
  font-size: .85em;
}

a{ color: var(--violet-text); text-decoration: none; }
a:hover{ text-decoration: underline; }

button{ font-family: inherit; }

::selection{ background: var(--violet-dim); color: var(--ink); }

/* Keyboard focus — a soft, semi-transparent ring plus a border-color
   shift, not a hard solid outline. This is shadcn/ui's actual
   focus-visible pattern (ring + ring-color at reduced opacity,
   border picks up the accent color too) ported to our token system.
   Deliberately uses `outline`, not `box-shadow`, for the ring itself
   -- box-shadow is a real collision risk here: any component with
   its own box-shadow (buttons already have one, for their glow
   effect) sits at the same CSS specificity as this rule and can
   silently override it depending on stylesheet load order, which is
   exactly what happened when this was first tried with box-shadow
   (verified: .btn-primary's own shadow completely hid the focus
   ring). `outline` is a separate property from `box-shadow` and
   can't collide with it, so the ring is guaranteed to show
   regardless of what any component declares for its own shadow. */
:focus-visible{
  outline: 3px solid rgba(110,118,240,.45);
  outline-offset: 1px;
  border-color: var(--violet);
}

@media (prefers-reduced-motion: reduce){
  *, *::before, *::after{ animation-duration: .001ms !important; transition-duration: .001ms !important; }
}
