/* Steid's theme.
   Started from Topcoat's `neutral` theme and retuned; see plans/ui.md.

   The theme is a small set of design tokens. Components refer to tokens only,
   never to raw colors, so the whole product restyles by editing `:root` and
   `.dark` below. A component that hardcodes a color is a bug — it will not
   follow a palette change and it will not adapt to the color scheme.

     --background              the page background
     --surface                 raised panels: cards, menus, flash messages
     --foreground              text and iconography on the background
     --muted-foreground        secondary text: captions, descriptions, placeholders
     --primary                 the emphasis color: primary actions, selection, links
     --primary-foreground      text on a primary-filled surface
     --success                 confirmations, and git additions
     --success-foreground      text on a success-filled surface
     --warning                 caution, and git modifications
     --warning-foreground      text on a warning-filled surface
     --destructive             destructive actions, errors, and git deletions
     --destructive-foreground  text on a destructive-filled surface
     --border                  hairline borders and dividers
     --ring                    the focus ring
     --shadow-xs               a subtle shadow for controls: buttons, inputs
     --shadow-sm               a shadow for raised surfaces: cards, menus

   Syntax highlighting adds a --syntax-* family, derived from the same palette and
   mapped onto the highlighter's classes at the bottom of this file.

   Interactive states (hover, press) have no tokens of their own: components
   derive them by applying the fill or foreground color at reduced opacity,
   which adapts to both color schemes automatically.

   Steid is dark-first — the layout sets `class="dark"` on <html>. Light mode
   is supported and secondary. */

@import "tailwindcss";

/* Scan the project's Rust sources for the Tailwind classes they use. This
   file is installed at the project root, so `./src` is the crate's source. */
@source "./src/**/*.rs";

/* Dark mode is opted into by putting the `dark` class on an ancestor,
   typically <html>. */
@custom-variant dark (&:is(.dark *));

/* Expose the tokens as Tailwind utilities (`bg-background`, `text-primary`,
   `border-border`, ...). The indirection through plain variables on `:root`
   and `.dark` is what lets the values swap when the color scheme changes. */
@theme inline {
  --font-sans: "Geist", ui-sans-serif, system-ui, sans-serif;
  /* Paths, commit hashes, branch names, and code. */
  --font-mono: "IBM Plex Mono", ui-monospace, "SF Mono", monospace;
  --color-background: var(--background);
  --color-surface: var(--surface);
  --color-foreground: var(--foreground);
  --color-muted-foreground: var(--muted-foreground);
  --color-primary: var(--primary);
  --color-primary-foreground: var(--primary-foreground);
  --color-success: var(--success);
  --color-success-foreground: var(--success-foreground);
  --color-warning: var(--warning);
  --color-warning-foreground: var(--warning-foreground);
  --color-destructive: var(--destructive);
  --color-destructive-foreground: var(--destructive-foreground);
  --color-border: var(--border);
  --color-ring: var(--ring);
  --shadow-xs: var(--shadow-xs);
  --shadow-sm: var(--shadow-sm);
}

/* Light mode. Secondary, but it should not look like an afterthought. */
:root {
  --background: oklch(0.99 0.003 260);
  --surface: oklch(1 0 0);
  --foreground: oklch(0.24 0.012 260);
  --muted-foreground: oklch(0.51 0.014 260);
  --primary: oklch(0.5 0.18 250);
  --primary-foreground: oklch(0.99 0.003 260);
  --success: oklch(0.52 0.15 145);
  --success-foreground: oklch(0.99 0.01 145);
  --warning: oklch(0.62 0.14 85);
  --warning-foreground: oklch(0.99 0.01 85);
  --destructive: oklch(0.55 0.2 27);
  --destructive-foreground: oklch(0.99 0.012 27);
  --border: oklch(0.9 0.008 260);
  --ring: oklch(0.5 0.18 250);
  --shadow-xs: 0 1px 2px oklch(0.24 0.02 260 / 12%);
  --shadow-sm:
    0 1px 2px oklch(0.24 0.02 260 / 10%),
    0 2px 8px -2px oklch(0.24 0.02 260 / 9%);

  --syntax-comment: oklch(0.55 0.015 260);
  --syntax-punctuation: oklch(0.46 0.015 260);
  --syntax-variable: oklch(0.3 0.014 260);
  --syntax-type: oklch(0.45 0.09 195);
  --syntax-function: oklch(0.48 0.15 250);
  --syntax-constant: oklch(0.5 0.12 62);
  --syntax-string: oklch(0.45 0.12 150);
  --syntax-keyword: oklch(0.45 0.17 300);
  --syntax-heading: oklch(0.42 0.16 250);
}

/* Dark mode. The primary surface for this product. */
.dark {
  --background: oklch(0.16 0.02 260);
  --surface: oklch(0.2 0.02 260);
  --foreground: oklch(0.9 0.01 260);
  --muted-foreground: oklch(0.66 0.014 260);
  --primary: oklch(0.65 0.15 250);
  --primary-foreground: oklch(0.16 0.02 260);
  --success: oklch(0.7 0.17 145);
  --success-foreground: oklch(0.16 0.02 145);
  --warning: oklch(0.8 0.15 85);
  --warning-foreground: oklch(0.16 0.02 85);
  --destructive: oklch(0.65 0.2 25);
  --destructive-foreground: oklch(0.14 0.02 25);
  --border: oklch(0.3 0.012 260);
  --ring: oklch(0.65 0.15 250);
  /* Light-mode shadows disappear on a dark background, so these are deeper. */
  --shadow-xs: 0 1px 2px oklch(0 0 0 / 35%);
  --shadow-sm: 0 1px 2px oklch(0 0 0 / 35%), 0 2px 8px -2px oklch(0 0 0 / 30%);

  --syntax-comment: oklch(0.6 0.014 260);
  --syntax-punctuation: oklch(0.72 0.014 260);
  --syntax-variable: oklch(0.86 0.02 260);
  --syntax-type: oklch(0.82 0.08 195);
  --syntax-function: oklch(0.78 0.11 240);
  --syntax-constant: oklch(0.82 0.11 70);
  --syntax-string: oklch(0.78 0.12 150);
  --syntax-keyword: oklch(0.75 0.12 300);
  --syntax-heading: oklch(0.75 0.13 250);
}

@layer base {
  body {
    @apply bg-background font-sans text-foreground;
  }
}

/* Syntax highlighting.
   `infrastructure/highlight.rs` emits classes, never inline colors, so the theme
   lives here with everything else and follows the color scheme. Tailwind never sees
   these class names — the markup is generated, not written in `src/` — so this is
   plain CSS against the tokens above, as ui.md requires.

   The classes are the *atoms* of a TextMate scope, flattened and prefixed: the scope
   `storage.type.function.rust` becomes `class="hl-storage hl-type hl-function hl-rust"`.
   Atoms are therefore not positional — `hl-function` is on `meta.function`, which
   wraps a whole function body, as well as on the name itself — so a single-atom
   selector is only safe for an atom that leads its scope. The rest are spelled out as
   the compound they really are.

   Order is load-bearing. Spans nest, so an inner span with two matching rules of equal
   specificity takes the later one; `punctuation.definition.string` carries both
   `hl-punctuation` and `hl-string`, and a quote should read as its string. Weakest
   first, strongest last. */

.hl-punctuation,
.hl-keyword.hl-operator {
  color: var(--syntax-punctuation);
}

.hl-variable,
.hl-entity.hl-other.hl-attribute-name {
  color: var(--syntax-variable);
}

.hl-entity.hl-name,
.hl-support.hl-function {
  color: var(--syntax-function);
}

.hl-entity.hl-name.hl-type,
.hl-entity.hl-name.hl-class,
.hl-entity.hl-name.hl-struct,
.hl-entity.hl-name.hl-enum,
.hl-entity.hl-name.hl-trait,
.hl-entity.hl-name.hl-namespace,
.hl-support.hl-type,
.hl-support.hl-class {
  color: var(--syntax-type);
}

.hl-constant,
.hl-support.hl-constant {
  color: var(--syntax-constant);
}

.hl-storage,
.hl-keyword,
.hl-entity.hl-name.hl-tag {
  color: var(--syntax-keyword);
}

.hl-string {
  color: var(--syntax-string);
}

/* Markdown and other markup: the source is read as prose, so structure carries the
   color and the body stays at foreground. */
.hl-markup.hl-heading {
  color: var(--syntax-heading);
  font-weight: 600;
}

.hl-markup.hl-raw {
  color: var(--syntax-string);
}

.hl-markup.hl-underline.hl-link {
  color: var(--syntax-function);
}

.hl-markup.hl-bold {
  font-weight: 600;
}

.hl-markup.hl-italic {
  font-style: italic;
}

/* Last, so a comment is a comment whatever it contains. */
.hl-comment {
  color: var(--syntax-comment);
}

.hl-invalid {
  color: var(--destructive);
}

/* Unified diff rows.

   Plain CSS rather than Tailwind utilities because these are theme tokens at
   low alpha, and `color-mix` against a custom property is not something a
   utility class can express. The alpha is the point: a tint has to sit under
   text that stays readable in both color schemes, which a solid `--success`
   or `--destructive` would not.

   Never a raw color here — every value is a token mixed with transparency, so
   the diff follows a palette change like everything else. The gutters take a
   stronger mix than the line so the numbers stay legible against it. */
.diff-line-add {
  background-color: color-mix(in oklab, var(--success) 12%, transparent);
}

.diff-line-del {
  background-color: color-mix(in oklab, var(--destructive) 12%, transparent);
}

.diff-gutter-add {
  background-color: color-mix(in oklab, var(--success) 20%, transparent);
}

.diff-gutter-del {
  background-color: color-mix(in oklab, var(--destructive) 20%, transparent);
}

/* A hunk header separates two parts of a file, so it reads as a rule rather
   than as a change: no tint, a hairline above it, and muted text. */
.diff-line-hunk td {
  border-top: 1px solid var(--border);
  padding-top: 0.25rem;
  padding-bottom: 0.25rem;
}

.diff-line-hunk:first-child td {
  border-top: 0;
}

/* Blame's age tint.

   A hairline down the left of each run of lines, its opacity scaled by how
   recently that commit touched the file relative to the file's own oldest and
   newest. Five steps, deliberately faint: it should read as texture telling you
   which end of a file is moving, not as a heat map with values to read off it.

   Plain CSS rather than Tailwind because the colour is the primary token at a
   fraction of an alpha, which is not a utility — and `color-mix` keeps it a
   token, so it follows a palette change and both colour schemes. */
.blame-age {
  border-left: 2px solid transparent;
}
.blame-age-0 {
  border-left-color: color-mix(in oklab, var(--primary) 5%, transparent);
}
.blame-age-1 {
  border-left-color: color-mix(in oklab, var(--primary) 9%, transparent);
}
.blame-age-2 {
  border-left-color: color-mix(in oklab, var(--primary) 14%, transparent);
}
.blame-age-3 {
  border-left-color: color-mix(in oklab, var(--primary) 21%, transparent);
}
.blame-age-4 {
  border-left-color: color-mix(in oklab, var(--primary) 30%, transparent);
}
