@import 'tailwindcss';

/* Marketing design-system skins. Imported UNLAYERED (no `layer(...)`) and
 * AFTER `@import 'tailwindcss'`, so its `html[data-skin='X'][data-chrome=
 * 'marketing']` scoped rules outrank Tailwind's layered utilities without
 * `!important`. All @imports must sit at the top of the file (Tailwind 4 /
 * Lightning CSS requirement). Each skin file scopes everything to its own
 * data-skin + marketing chrome, so this is a no-op for the default skin and
 * for every app/editor/admin surface. */
@import './skins/geometry.css';

/* Fonts come from Google Fonts via a <link> rendered by app.blade.php
 * based on the active theme's font_sans / font_display knobs. The :root
 * fallback below covers the install wizard + any pre-theme-loaded view. */

@source '../../vendor/laravel/framework/src/Illuminate/Pagination/resources/views/*.blade.php';
@source '../../storage/framework/views/*.php';
@source '../**/*.blade.php';
@source '../js/**/*.{ts,tsx}';

@theme {
    --font-sans: 'Inter', system-ui, -apple-system, 'Segoe UI', sans-serif;
    --font-display: 'Inter', system-ui, -apple-system, 'Segoe UI', sans-serif;
    --font-mono: 'JetBrains Mono', ui-monospace, 'SFMono-Regular', Menlo, monospace;

    --color-background: #faf8f5;
    --color-foreground: #1c1917;
    --color-muted: #f2efe9;
    --color-muted-foreground: #6b6358;
    --color-border: #e6e1d8;
    --color-card: #ffffff;
    --color-ring: #0052ff;

    --color-accent: #0052ff;
    --color-accent-secondary: #4d7cff;
    --color-accent-foreground: #ffffff;

    --color-destructive: #dc2626;
    --color-destructive-foreground: #ffffff;

    /* Accent-tinted shadows. color-mix re-resolves whenever `--color-accent`
       changes (admin's Appearance knob) so accent-aware hovers stay in sync
       with the rest of the theme. Exposed as Tailwind utilities `shadow-accent`
       and `shadow-accent-lg` since they're named `--shadow-*`. */
    --shadow-accent: 0 4px 14px color-mix(in srgb, var(--color-accent) 25%, transparent);
    --shadow-accent-lg: 0 8px 24px color-mix(in srgb, var(--color-accent) 35%, transparent);

    /* --- 11-step scales (Sprint 1) --- */
    --color-accent-50:  oklch(0.97 0.082 264);
    --color-accent-100: oklch(0.93 0.118 264);
    --color-accent-200: oklch(0.86 0.165 264);
    --color-accent-300: oklch(0.77 0.2   264);
    --color-accent-400: oklch(0.65 0.223 264);
    --color-accent-500: oklch(0.484 0.235 264);
    --color-accent-600: oklch(0.42 0.223 264);
    --color-accent-700: oklch(0.34 0.2   264);
    --color-accent-800: oklch(0.26 0.165 264);
    --color-accent-900: oklch(0.18 0.129 264);
    --color-accent-950: oklch(0.12 0.094 264);

    --color-neutral-50:  oklch(0.97 0.003 75);
    --color-neutral-100: oklch(0.93 0.004 75);
    --color-neutral-200: oklch(0.86 0.006 75);
    --color-neutral-300: oklch(0.77 0.007 75);
    --color-neutral-400: oklch(0.65 0.008 75);
    --color-neutral-500: oklch(0.5 0.008 75);
    --color-neutral-600: oklch(0.42 0.008 75);
    --color-neutral-700: oklch(0.34 0.007 75);
    --color-neutral-800: oklch(0.26 0.006 75);
    --color-neutral-900: oklch(0.18 0.004 75);
    --color-neutral-950: oklch(0.12 0.003 75);

    --color-success: oklch(0.65 0.16 145);
    --color-success-foreground: oklch(1 0 0);
    --color-warning: oklch(0.78 0.18 75);
    --color-warning-foreground: oklch(0.2 0 0);
    --color-danger:  oklch(0.62 0.21 25);
    --color-danger-foreground: oklch(1 0 0);
    --color-info:    oklch(0.65 0.15 240);
    --color-info-foreground: oklch(1 0 0);
    /* `test` is the badge color for sandbox-mode subscriptions / invoices.
       Distinct from `info` so admins can spot test rows at a glance even
       when an info-toned notice is rendered next to them. Purple chosen
       because it doesn't overlap any other semantic status tone. */
    --color-test:    oklch(0.6 0.2 295);
    --color-test-foreground: oklch(1 0 0);

    --radius-base: 0.5rem;
    --radius-sm: calc(var(--radius-base) * 0.5);
    --radius-md: var(--radius-base);
    --radius-lg: calc(var(--radius-base) * 1.5);
    --radius-xl: calc(var(--radius-base) * 2);
    --radius-full: 9999px;

    --space-unit: 1rem;
    --text-scale: 1;

    /* Map Tailwind 4's spacing base to the Density knob. Default Tailwind
       spacing is 0.25rem (so `p-4` = 1rem); we redefine it as
       `--space-unit / 4` so at the default knob value (`--space-unit: 1rem`)
       Tailwind's scale is unchanged, while compact (0.875rem) and
       comfortable (1.125rem) settings tighten/loosen every `p-*`, `m-*`,
       `gap-*`, `space-y-*` etc. proportionally across the whole app. */
    --spacing: calc(var(--space-unit) / 4);

    --shadow-sm: 0 1px 2px rgb(0 0 0 / 0.06);
    --shadow-md: 0 4px 8px rgb(0 0 0 / 0.08);
    --shadow-lg: 0 8px 16px rgb(0 0 0 / 0.10);
    --shadow-xl: 0 16px 32px rgb(0 0 0 / 0.12);

    --button-radius: var(--radius-md);

    /* Motion — small entrance animations shared across app chrome.
     * Durations stay under 300ms and easings are ease-out / spring-ish so
     * the UI feels responsive, never decorated. A global
     * prefers-reduced-motion override at the bottom of this file disables
     * all of it for users who ask. */
    --animate-fade-in: fade-in 0.15s ease-out both;
    --animate-fade-in-up: fade-in-up 0.3s cubic-bezier(0.16, 1, 0.3, 1) both;
    --animate-pop-in: pop-in 0.2s cubic-bezier(0.16, 1, 0.3, 1) both;
    --animate-glyph-in: glyph-in 0.15s ease-out both;

    @keyframes fade-in {
        from {
            opacity: 0;
        }
    }
    @keyframes fade-in-up {
        from {
            opacity: 0;
            transform: translateY(8px);
        }
    }
    @keyframes pop-in {
        from {
            opacity: 0;
            transform: scale(0.97) translateY(8px);
        }
    }
    /* Checkbox / Radio glyph overlays — display flips none→block on check,
     * which restarts the animation, so the tick pops every time. */
    @keyframes glyph-in {
        from {
            opacity: 0;
            transform: scale(0.4);
        }
    }
}

@layer base {
    /* Fallback font stacks used by the install wizard + any pre-theme
     * surface where the runtime `<style nonce>` block from app.blade.php
     * hasn't loaded yet. Wrapped in @layer base so the runtime block
     * (which is unlayered = highest cascade priority) always overrides.
     *
     * Previously these lived outside any @layer; in prod the runtime
     * <style> tag rendered AFTER the static @vite <link> so it won
     * by source order, but in dev mode Vite injects CSS dynamically
     * via JS modules AFTER head-parse — which put this unlayered :root
     * after the runtime block in cascade order, clobbering the theme's
     * chosen font. Layering this rule fixes both modes. */
    :root {
        --font-sans: 'Inter', system-ui, -apple-system, 'Segoe UI', sans-serif;
        --font-display: 'Inter', system-ui, -apple-system, 'Segoe UI', sans-serif;
        --font-mono: 'JetBrains Mono', ui-monospace, 'SFMono-Regular', Menlo, monospace;
    }

    /* Scale the root font-size by the Density knob's `--text-scale`. Every
       rem-based size in the app scales proportionally (Tailwind text-* /
       p-* / w-* utilities all use rem). 16px is the browser default; we
       multiply rather than override so users with a custom browser font-
       size baseline still get a relative bump. */
    html {
        font-size: calc(16px * var(--text-scale, 1));
    }

    body {
        font-family: var(--font-sans);
        font-weight: var(--font-weight-body);
        font-size: var(--text-body);
        line-height: var(--text-body-line);
    }
    h1 {
        font-weight: var(--font-weight-display);
        font-size: var(--text-h1);
        line-height: var(--text-h1-line);
        letter-spacing: var(--text-h1-tracking);
    }
    h2 {
        font-weight: var(--font-weight-heading);
        font-size: var(--text-h2);
        line-height: var(--text-h2-line);
        letter-spacing: var(--text-h2-tracking);
    }
    h3 {
        font-weight: var(--font-weight-subheading);
        font-size: var(--text-h3);
        line-height: var(--text-h3-line);
        letter-spacing: var(--text-h3-tracking);
    }
    /* Heading font-family is scoped to marketing chrome only — admin /
       editor / auth surfaces inherit the body's `--font-sans` (Inter) so the
       Appearance display-font knob (Lora / Playfair / etc.) doesn't bleed
       italic-serif into transactional chrome. `data-chrome` is set
       server-side in `app.blade.php` via `ChromeMode::forComponent()` and
       kept in sync on Inertia visits by the `useForceLightTheme` /
       `useThemeFromPreference` hooks. */
    [data-chrome="marketing"] h1,
    [data-chrome="marketing"] h2 {
        font-family: var(--font-display);
    }
    [data-chrome="marketing"] h3 {
        font-family: var(--font-subheading, var(--font-display));
    }

    [data-theme='dark'] {
        --color-background: #1a1917;
        --color-foreground: #ebe8e2;
        --color-muted: #262422;
        --color-muted-foreground: #a8a29d;
        --color-border: #36322e;
        --color-card: #22201d;
        --color-ring: #4d7cff;

        --color-accent: #4d7cff;
        --color-accent-secondary: #80a3ff;
        --color-accent-foreground: #0a0a09;

        --color-success: oklch(0.7 0.14 145);
        --color-success-foreground: oklch(0.15 0 0);
        --color-warning: oklch(0.82 0.16 75);
        --color-warning-foreground: oklch(0.18 0 0);
        --color-danger:  oklch(0.68 0.19 25);
        --color-danger-foreground: oklch(1 0 0);
        --color-info:    oklch(0.7 0.13 240);
        --color-info-foreground: oklch(0.15 0 0);
        --color-test:    oklch(0.7 0.17 295);
        --color-test-foreground: oklch(0.15 0 0);
    }

    html {
        color-scheme: light;
    }
    html[data-theme='dark'] {
        color-scheme: dark;
    }
}

/* Re-bind Tailwind 4's `shadow-{sm,md,lg,xl}` utilities to runtime CSS
   vars. Tailwind 4 reads `--shadow-*` declarations from @theme AT BUILD
   TIME and inlines the literal value into each utility (e.g. `.shadow-md`
   becomes `box-shadow: 0 4px 8px rgb(0 0 0 / 0.08)`), so when admin's
   Appearance "Elevation" knob writes new --shadow-md to root at runtime,
   the utility never reads it. These overrides force the utility to use
   `var(--shadow-*)` so the knob's runtime override actually takes effect.
   `@layer utilities` puts these at the same specificity as Tailwind's
   built-ins but later in the cascade, so they win. */
/* Native <select> chevron clearance. Browsers render the dropdown
   arrow at the very right edge of the element regardless of the CSS
   padding-right we set in utility classes — `px-3` (12px) leaves the
   chevron hugging the border. Every admin <select> sets `bg-background`
   (the common admin form pattern) so target only those + give them
   2rem of right padding so the native chevron sits in clean space.
   Non-admin <select> (browser default chrome) stays untouched. */
@layer base {
    /* Tailwind 4 dropped the preflight `button { cursor: pointer }` rule
       and now matches the browser UA default (`cursor: default`). Restore
       the pointer cursor on every interactive button/role=button so the
       app feels native — disabled buttons keep the default arrow so the
       inert state is obvious. */
    button:not(:disabled),
    [role="button"]:not([aria-disabled="true"]) {
        cursor: pointer;
    }
}

@layer base {
    select.bg-background,
    select[class~="bg-background"] {
        padding-right: 2rem;
        background-image: linear-gradient(45deg, transparent 50%, var(--color-foreground) 50%),
            linear-gradient(135deg, var(--color-foreground) 50%, transparent 50%);
        background-position: calc(100% - 17px) 50%, calc(100% - 12px) 50%;
        background-size: 5px 5px, 5px 5px;
        background-repeat: no-repeat;
        -webkit-appearance: none;
        -moz-appearance: none;
        appearance: none;
    }
}

@layer utilities {
    .shadow-sm {
        box-shadow: var(--shadow-sm);
    }
    .shadow-md {
        box-shadow: var(--shadow-md);
    }
    .shadow-lg {
        box-shadow: var(--shadow-lg);
    }
    .shadow-xl {
        box-shadow: var(--shadow-xl);
    }

    /* Sleek scroll — narrow, themed via Appearance border token, no track
       background. Used by modals + any internal scroll container that
       should feel quiet, not OS-default-noisy. Cross-browser:
       Firefox via the scrollbar-* properties, WebKit via pseudo-classes. */
    .sleek-scroll {
        scrollbar-width: thin;
        scrollbar-color: var(--color-border) transparent;
    }
    .sleek-scroll::-webkit-scrollbar {
        width: 6px;
        height: 6px;
    }
    .sleek-scroll::-webkit-scrollbar-track {
        background: transparent;
    }
    .sleek-scroll::-webkit-scrollbar-thumb {
        background-color: var(--color-border);
        border-radius: 9999px;
    }
    .sleek-scroll::-webkit-scrollbar-thumb:hover {
        background-color: var(--color-muted-foreground);
    }
}

/* Server-rendered SEO body fallback (app.blade.php → \App\Support\
 * MarketingSeoServer). Hidden from real browsers so there is no flash of
 * unstyled content before React mounts (app.tsx then removes the node).
 * Non-JS crawlers / AI fetchers don't apply this external sheet, so they
 * still read the text — unlike <noscript>, which HTML→text converters
 * strip. Unlayered so it always beats Tailwind's layered utilities. */
.seo-ssr-body {
    display: none !important;
}

/* Motion: every error / success / flash banner gets a small slide-down
 * entrance for free — they already carry role="alert" or role="status"
 * for a11y, so no per-callsite wiring. Toasts opt out: Toast.tsx runs its
 * own enter/leave transitions and the two would fight. */
@keyframes alert-in {
    from {
        opacity: 0;
        transform: translateY(-4px);
    }
}
[role='alert'],
[role='status'] {
    animation: alert-in 0.25s ease-out both;
}
[data-testid^='toast-'] {
    animation: none;
}

/* Motion: admin list tables — visible rows cascade in. Opacity-only;
 * transforms on <tr> are unreliable across engines. Delays are capped at
 * 180ms (rows 11+ share the cap) so deep tables don't crawl. Replays on
 * page mount; filter re-fetches only animate genuinely new rows since
 * React reuses keyed DOM nodes. */
.stagger-rows tbody tr {
    animation: fade-in 0.25s ease-out both;
    animation-delay: 180ms;
}
.stagger-rows tbody tr:nth-child(1) {
    animation-delay: 0ms;
}
.stagger-rows tbody tr:nth-child(2) {
    animation-delay: 20ms;
}
.stagger-rows tbody tr:nth-child(3) {
    animation-delay: 40ms;
}
.stagger-rows tbody tr:nth-child(4) {
    animation-delay: 60ms;
}
.stagger-rows tbody tr:nth-child(5) {
    animation-delay: 80ms;
}
.stagger-rows tbody tr:nth-child(6) {
    animation-delay: 100ms;
}
.stagger-rows tbody tr:nth-child(7) {
    animation-delay: 120ms;
}
.stagger-rows tbody tr:nth-child(8) {
    animation-delay: 140ms;
}
.stagger-rows tbody tr:nth-child(9) {
    animation-delay: 160ms;
}

/* Accessibility kill-switch — collapses every animation/transition to a
 * single imperceptible frame for users with reduced motion enabled. */
@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;
    }
}

/* SPIKE — inline rich-text editor (TipTap over Konva). Zero the contenteditable
   chrome so the overlay sits exactly on the rendered glyphs. */
.rich-inline-editor .ProseMirror {
    margin: 0;
    padding: 0;
    outline: none;
    white-space: pre-wrap;
    word-break: break-word;
}
.rich-inline-editor .ProseMirror p {
    margin: 0;
}
