/*
 * Tokens, reset and element defaults. Loaded by every page, before the
 * stylesheet for whichever surface is rendering (app.css or landing.css).
 *
 * Hand-written, no build step: what is in this file is what the browser gets.
 * Two ideas keep it that way without turning into a specificity fight.
 *
 * 1. Cascade layers. The order below is the whole cascade, declared once and
 *    obeyed everywhere - a `components` rule always beats `base`, whatever the
 *    selectors involved. Later files add to these layers; none of them may
 *    reorder them.
 *
 * 2. One token vocabulary, two skins. The names here (--ink, --line, --surface)
 *    describe a role, not a colour. The app uses the values set below; the
 *    marketing page re-points the same names at its own palette in landing.css.
 *    A component written against --ink works on both without knowing which.
 */

@layer reset, tokens, base, components, utilities;

@layer tokens {
  :root {
    /* ── Type ─────────────────────────────────────────────────────────── */
    --font-sans:
      ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto,
      "Helvetica Neue", Arial, "Noto Sans", sans-serif;
    --font-mono:
      ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas,
      "Liberation Mono", "Courier New", monospace;

    --text-xs: 0.75rem;
    --text-sm: 0.875rem;
    --text-base: 1rem;
    --text-lg: 1.125rem;
    --text-xl: 1.25rem;

    /* ── Colour ───────────────────────────────────────────────────────── */
    /* Roles, not shades. Darkest ink to lightest. */
    --ink: #0f172a;
    --ink-soft: #334155;
    --ink-muted: #64748b;
    --ink-faint: #94a3b8;

    --surface: #fff;
    --surface-sunken: #f8fafc;
    --surface-raised: #fff;

    /* Borders, strongest to faintest. */
    --line-strong: #cbd5e1;
    --line: #e2e8f0;
    --line-soft: #f1f5f9;

    /* Tone sets. Each is a background, a border, text and a dot, so a banner
       and a badge of the same tone agree without either restating the colours. */
    --ok-bg: #ecfdf5;
    --ok-line: #a7f3d0;
    --ok-text: #065f46;
    --ok-dot: #10b981;

    --warn-bg: #fffbeb;
    --warn-line: #fde68a;
    --warn-text: #92400e;
    --warn-dot: #f59e0b;

    --danger-bg: #fef2f2;
    --danger-line: #fecaca;
    --danger-text: #991b1b;
    --danger-dot: #ef4444;
    --danger-solid: #dc2626;
    --danger-solid-hover: #b91c1c;

    --neutral-bg: #f1f5f9;
    --neutral-line: #cbd5e1;
    --neutral-text: #334155;
    --neutral-dot: #94a3b8;

    /* ── Shape and depth ──────────────────────────────────────────────── */
    --radius-sm: 0.25rem;
    --radius: 0.375rem;
    --radius-lg: 0.5rem;
    --radius-xl: 1rem;
    --radius-pill: 999px;

    --shadow-sm: 0 1px 2px 0 rgb(15 23 42 / 0.05);
    --shadow-lg: 0 10px 15px -3px rgb(15 23 42 / 0.1), 0 4px 6px -4px rgb(15 23 42 / 0.1);

    /* Focus ring, defined once so every control agrees. */
    --focus-ring: 0 0 0 1px var(--ink);

    /* ── Rhythm ───────────────────────────────────────────────────────── */
    --gutter: clamp(1rem, 4vw, 1.5rem);
    --shell: 72rem;
  }
}

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

  /* :where() keeps every reset at zero specificity, so a single class in
     `components` always wins without needing !important or a longer selector. */
  :where(body, h1, h2, h3, h4, p, figure, blockquote, dl, dd, pre) {
    margin: 0;
  }

  :where(ul, ol) {
    margin: 0;
    padding: 0;
    list-style: none;
  }

  :where(html) {
    -webkit-text-size-adjust: 100%;
    tab-size: 4;
  }

  :where(body) {
    min-block-size: 100%;
    -webkit-font-smoothing: antialiased;
  }

  :where(img, svg, video, canvas) {
    display: block;
    max-inline-size: 100%;
    block-size: auto;
  }

  :where(input, button, textarea, select) {
    font: inherit;
    color: inherit;
  }

  :where(button) {
    background: none;
    border: 0;
    padding: 0;
    cursor: pointer;
  }

  /* A fieldset is the right element for a group of radios, but its default
     border and inset legend belong to 1997. */
  :where(fieldset) {
    margin: 0;
    padding: 0;
    border: 0;
    min-inline-size: 0;
  }

  :where(legend) {
    padding: 0;
  }

  :where(table) {
    border-collapse: collapse;
    inline-size: 100%;
  }

  :where(th) {
    text-align: start;
    font-weight: 500;
  }

  :where(a) {
    color: inherit;
    text-decoration: none;
  }

  :where(h1, h2, h3, h4) {
    font-size: inherit;
    font-weight: inherit;
    text-wrap: balance;
  }

  :where(p) {
    text-wrap: pretty;
  }

  /* Nobody has asked for motion; those who have asked for less get none. */
  @media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
      animation-duration: 0.01ms !important;
      animation-iteration-count: 1 !important;
      transition-duration: 0.01ms !important;
      scroll-behavior: auto !important;
    }
  }
}

@layer base {
  html,
  body {
    block-size: 100%;
  }

  body {
    font-family: var(--font-sans);
    font-size: var(--text-base);
    line-height: 1.5;
    color: var(--ink);
    background: var(--surface);
  }

  /* One focus treatment for everything focusable, visible only for keyboard
     and other non-pointer input. */
  :focus-visible {
    outline: 2px solid var(--ink);
    outline-offset: 2px;
  }

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

  strong {
    font-weight: 600;
  }

  ::selection {
    background: var(--ink);
    color: #fff;
  }
}

@layer components {
  /* ── Third-party hooks ──────────────────────────────────────────────── */

  /* Alpine strips this once it has booted; until then the element stays
     hidden, so a closed menu or modal never flashes open on first paint. */
  [x-cloak] {
    display: none !important;
  }

  /* htmx sets aria-busy on an element while its request is in flight. */
  [aria-busy="true"] {
    opacity: 0.6;
    transition: opacity 150ms;
  }

  /* Shown only while an htmx request from this element is running. */
  .htmx-indicator {
    visibility: hidden;
    opacity: 0;
    transition: opacity 150ms;
  }

  :is(.htmx-request .htmx-indicator, .htmx-request.htmx-indicator) {
    visibility: visible;
    opacity: 1;
  }

  /* The counterpart: hidden *while* the request is running, so a control can
     trade its resting label for the indicator above. */
  :is(.htmx-request .htmx-idle, .htmx-request.htmx-idle) {
    visibility: hidden;
  }
}

@layer utilities {
  .visually-hidden {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
  }
}
