import animate from 'tailwindcss-animate';

/**
 * Hand-written, never CLI-generated. `shadcn add` rewrites this file and
 * strips every comment in it, so if you run the CLI, diff this file
 * afterwards and put the comments back.
 *
 * The palette is PIG's, inlined as literals rather than injected at runtime:
 * this site has no user-chosen accent, so a runtime theme layer would be a
 * moving part that buys nothing. Every value here is `hsl(var(--token))` —
 * the triples themselves, with their measured contrast ratios, live in
 * src/index.css. Nothing in this file is a raw colour.
 */
/** @type {import('tailwindcss').Config} */
export default {
  darkMode: ['class', '[data-theme="dark"]'],
  content: ['./index.html', './src/**/*.{ts,tsx}'],
  theme: {
    extend: {
      colors: {
        bg: 'hsl(var(--bg))',
        background: 'hsl(var(--bg))',
        surface: 'hsl(var(--surface))',
        'surface-2': 'hsl(var(--surface-2))',
        'surface-3': 'hsl(var(--surface-3))',
        border: 'hsl(var(--border))',
        // The only boundary token that clears 3:1 as a non-text signal. Inputs,
        // selects, outline chips and icons at rest use it; `border` is decorative.
        'border-strong': 'hsl(var(--border-strong))',
        input: 'hsl(var(--border))',
        ring: 'hsl(var(--ring))',
        fg: 'hsl(var(--fg))',
        foreground: 'hsl(var(--fg))',
        'fg-2': 'hsl(var(--fg-2))',
        muted: 'hsl(var(--muted))',
        'muted-foreground': 'hsl(var(--muted))',
        // shadcn's `accent` is its SUBTLE hover surface, not the brand. Mapping
        // it to the brand paints a full-strength block on every hover state.
        accent: 'hsl(var(--accent-subtle))',
        'accent-foreground': 'hsl(var(--accent-fg))',
        brand: 'hsl(var(--accent))',
        'accent-fg': 'hsl(var(--accent-fg))',
        'accent-on': 'hsl(var(--accent-on))',
        'accent-edge': 'hsl(var(--accent-edge))',
        'accent-subtle': 'hsl(var(--accent-subtle))',
        // The tab bar's 2px state bar: accent in dark, accent-fg in light, so
        // the trigger needs one class and no theme variant.
        'tab-underline': 'hsl(var(--tab-underline))',
        primary: { DEFAULT: 'hsl(var(--accent))', foreground: 'hsl(var(--accent-on))' },
        secondary: { DEFAULT: 'hsl(var(--surface-2))', foreground: 'hsl(var(--fg))' },
        card: { DEFAULT: 'hsl(var(--surface))', foreground: 'hsl(var(--fg))' },
        popover: { DEFAULT: 'hsl(var(--surface))', foreground: 'hsl(var(--fg))' },
        // `danger-on`, not white: white on the dark theme's red is 3.63:1.
        destructive: { DEFAULT: 'hsl(var(--danger))', foreground: 'hsl(var(--danger-on))' },
        positive: 'hsl(var(--positive))',
        warning: 'hsl(var(--warning))',
        'warning-on': 'hsl(var(--warning-on))',
        'warning-subtle': 'hsl(var(--warning-subtle))',
        danger: 'hsl(var(--danger))',
        'danger-on': 'hsl(var(--danger-on))',
        'danger-subtle': 'hsl(var(--danger-subtle))',
        info: 'hsl(var(--info))',
        // The board's three tile states. Named by MEANING, not by colour, so
        // the high-contrast palette can swap the values without renaming.
        tile: {
          exact: 'hsl(var(--tile-exact))',
          'exact-fg': 'hsl(var(--tile-exact-fg))',
          present: 'hsl(var(--tile-present))',
          'present-fg': 'hsl(var(--tile-present-fg))',
          absent: 'hsl(var(--tile-absent))',
          'absent-fg': 'hsl(var(--tile-absent-fg))',
          // An unplayed tile's edge (`border-tile-empty`).
          empty: 'hsl(var(--tile-empty-border))',
        },
      },
      fontFamily: {
        sans: ['Geist Variable', 'Inter', 'ui-sans-serif', 'system-ui', 'sans-serif'],
        mono: ['Geist Mono Variable', 'ui-monospace', 'SFMono-Regular', 'Menlo', 'monospace'],
      },
      /*
       * The type scale (spec §3). Sans unless the name says mono; the face is
       * still applied by `font-mono` on the element, these only fix size,
       * leading, weight and tracking. Responsive steps are the `-lg` / `-xl`
       * siblings (`text-display lg:text-display-lg xl:text-display-xl`).
       * Weight ceiling is 600 everywhere.
       */
      fontSize: {
        display: ['2.25rem', { lineHeight: '1.05', fontWeight: '600', letterSpacing: '-0.02em' }],
        'display-lg': ['3rem', { lineHeight: '1.05', fontWeight: '600', letterSpacing: '-0.02em' }],
        'display-xl': ['3.5rem', { lineHeight: '1.05', fontWeight: '600', letterSpacing: '-0.02em' }],
        h1: ['1.75rem', { lineHeight: '1.15', fontWeight: '600', letterSpacing: '-0.015em' }],
        'h1-lg': ['2rem', { lineHeight: '1.15', fontWeight: '600', letterSpacing: '-0.015em' }],
        h2: ['1.5rem', { lineHeight: '1.15', fontWeight: '600', letterSpacing: '-0.015em' }],
        'h2-lg': ['1.875rem', { lineHeight: '1.15', fontWeight: '600', letterSpacing: '-0.015em' }],
        h3: ['1.125rem', { lineHeight: '1.3', fontWeight: '600', letterSpacing: '-0.01em' }],
        lede: ['1.125rem', { lineHeight: '1.5', fontWeight: '400' }],
        'lede-lg': ['1.25rem', { lineHeight: '1.5', fontWeight: '400' }],
        // The tab claim: never mono, never uppercase, never shortened.
        claim: ['1.125rem', { lineHeight: '1.35', fontWeight: '500' }],
        'claim-lg': ['1.25rem', { lineHeight: '1.35', fontWeight: '500' }],
        // The education floor. Nothing that explains is ever smaller.
        prose: ['1rem', { lineHeight: '1.6', fontWeight: '400' }],
        ui: ['0.875rem', { lineHeight: '1.4' }],
        small: ['0.8125rem', { lineHeight: '1.45', fontWeight: '400' }],
        caption: ['0.75rem', { lineHeight: '1.4' }],
        // mono, uppercase — pair with `font-mono uppercase`.
        label: ['0.6875rem', { lineHeight: '1.2', fontWeight: '500', letterSpacing: '0.04em' }],
        'mono-data': ['0.8125rem', { lineHeight: '1.4', fontWeight: '400' }],
        stat: ['0.8125rem', { lineHeight: '1.4', fontWeight: '600' }],
        metric: ['2rem', { lineHeight: '1.1', fontWeight: '600', letterSpacing: '-0.01em' }],
        // The landing's 0% → ~60% figure.
        figure: ['2.5rem', { lineHeight: '1', fontWeight: '500', letterSpacing: '-0.02em' }],
        'figure-lg': ['3.5rem', { lineHeight: '1', fontWeight: '500', letterSpacing: '-0.02em' }],
        code: ['0.8125rem', { lineHeight: '1.6' }],
      },
      letterSpacing: { label: '0.04em' },
      // A real four-step scale. 4px tiles/cells, 6px controls, 8px inner blocks,
      // 12px surfaces. Named aliases resolve to the same CSS variables index.css
      // declares, so a component can say what it means (`rounded-control`).
      borderRadius: {
        sm: '0.25rem',
        md: '0.375rem',
        lg: '0.5rem',
        xl: '0.75rem',
        tile: 'var(--radius-tile)',
        control: 'var(--radius-control)',
        surface: 'var(--radius-surface)',
      },
      // Overlays only. Flat components carry no shadow; borders do the work.
      boxShadow: { overlay: 'var(--shadow-overlay)' },
      maxWidth: { canvas: '80rem', measure: 'var(--measure)', 'measure-wide': 'var(--measure-wide)' },
      transitionDuration: { 1: 'var(--dur-1)', 2: 'var(--dur-2)', 3: 'var(--dur-3)' },
      transitionTimingFunction: { enter: 'var(--ease-out)', exit: 'var(--ease-in)' },
    },
  },
  plugins: [animate],
};
