/* Vasavan theme as plain CSS, for sites without Tailwind. Generated from vasavan.css; edit that. */
/*
  Vasavan theme for vasavan.org tools. Source: apps/ui/src/styles/vasavan.css, served at cdn.vasavan.org/theme/.
  The Vasavan GraphicalUI theme (gui/themes/vasavan.md) mapped onto shadcn/ui + Tailwind v4.

  Install:   npx shadcn add https://cdn.vasavan.org/r/theme.json
  Then put   @import "./styles/vasavan.css";   at the top of the app's CSS entry (in place of
  @import "tailwindcss"). Fonts load from https://cdn.vasavan.org/fonts/, the one source.

  Layers
    1. Fonts: Geist (interface), Geist Mono (data, code), Geist Pixel (display).
    2. Vasavan tokens, literal values, light (:root) and dark (.dark).
    3. shadcn semantic roles, defined from the Vasavan tokens (never literals).
    4. Tailwind theme: type scale, radii, shadows, motion and weights wired to the tokens.
    5. Character: density (airy/compact) and intensity (quiet/bold) blended, plus motion.
    6. Base styles and shared finishes (focus ring, popup motion, press).
*/


/* 1. Fonts ------------------------------------------------------------------------------------ */
/* Geist, Geist Mono and Geist Pixel (Vercel, SIL OFL 1.1). vasavan.org never uses Labil Grotesk:
   that face belongs to ravivasavan.com. */
@font-face {
  font-family: "Geist";
  src: url("https://cdn.vasavan.org/fonts/Geist-Variable.woff2") format("woff2-variations"), url("https://cdn.vasavan.org/fonts/Geist-Variable.woff2") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Geist Mono";
  src: url("https://cdn.vasavan.org/fonts/GeistMono-Variable.woff2") format("woff2-variations"), url("https://cdn.vasavan.org/fonts/GeistMono-Variable.woff2") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Geist Pixel";
  src: url("https://cdn.vasavan.org/fonts/GeistPixel-Square.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@property --fade-top { syntax: "<length>"; inherits: false; initial-value: 0px; }
@property --fade-bottom { syntax: "<length>"; inherits: false; initial-value: 0px; }

/* 2. Vasavan tokens --------------------------------------------------------------------------- */
:root {
  /* Type: Geist for interface and reading, Geist Mono for data and code, Geist Pixel for display. */
  --font-ui: "Geist", -apple-system, BlinkMacSystemFont, sans-serif;
  --font-brand: var(--font-ui);
  --font-display: "Geist Pixel", var(--font-code);
  --font-editorial: var(--font-ui);
  --font-data: var(--font-ui);
  --font-code: "Geist Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
  --weight-ui-regular: 400;

  --letter-spacing-xxs: 0.02em;
  --letter-spacing-xs: 0.01em;
  --letter-spacing-s: 0.01em;
  --letter-spacing-m: 0em;
  --letter-spacing-l: -0.01em;
  --letter-spacing-xl: -0.01em;
  --letter-spacing-xxl: -0.02em;
  --tracking-xs: -0.02em; --tracking-s: -0.01em; --tracking-m: 0em; --tracking-l: 0.01em; --tracking-xl: 0.02em;

  --space-zero: 0px; --space-xxs: 4px; --space-xs: 8px; --space-s: 12px;
  --space-m: 16px; --space-l: 24px; --space-xl: 32px; --space-xxl: 48px;

  --radius-zero: 0px; --radius-xs: 4px; --radius-xl: 30px; --radius-full: 9999px;
  /* --size-*, --line-*, --radius-s/m/l and --spacing are set by Character (section 5). */

  --border-none: 0px; --border-s: 0px; --border-m: 0px; --border-l: 0px;

  --motion-duration: 200ms;
  --motion-easing: cubic-bezier(0.16, 1, 0.3, 1);
  --motion-large-duration: 360ms;
  --motion-large-easing: cubic-bezier(0.22, 1, 0.36, 1);
  --motion-popup-scale: 0.96;
  --motion-press-distance: 1px;

  --color-1: #abff5a; --color-1-transparent: #abff5a33;
  --color-2: #085e55; --color-2-transparent: #085e5533;
  --color-3: #ffc0ff; --color-3-transparent: #ffc0ff33;
  --color-4: #80d8e8; --color-4-transparent: #80d8e833;
  --success: #00906c; --success-transparent: #00906c33;
  --warning: #ffea00; --warning-transparent: #ffea0033;
  --error: #fc032d;   --error-transparent: #fc032d33;

  --neutral-1: #ffffff;  --neutral-1-transparent: #ffffff33;
  --neutral-2: #fbfbfb;  --neutral-2-transparent: #fbfbfb33;
  --neutral-3: #f4f4f4;  --neutral-3-transparent: #f4f4f433;
  --neutral-4: #e7e7e7;  --neutral-4-transparent: #e7e7e733;
  --neutral-5: #cdcdcd;  --neutral-5-transparent: #cdcdcd33;
  --neutral-6: #a1a1a1;  --neutral-6-transparent: #a1a1a133;
  --neutral-7: #7d7d7d;  --neutral-7-transparent: #7d7d7d33;
  --neutral-8: #555555;  --neutral-8-transparent: #55555533;
  --neutral-9: #333333;  --neutral-9-transparent: #33333333;
  --neutral-10: #000000; --neutral-10-transparent: #00000033;

  --shadow-none: none;
  --shadow-s: 0px 2px 4px 0px #00000000;
  --shadow-m: 0px 2px 6px 0px #0000000d, 0px 8px 24px 0px #00000013;
  --shadow-l: 0px 16px 48px 0px #00000000;

  --option-badge-background: #abff5a;
  --option-badge-foreground: #333333;
  --primary-on-color-1: var(--neutral-9);   /* theme primaryForeground, light: neutral-9 */

  /* Surfaces (same roles as the vanilla v1 design system) */
  --surface-canvas: var(--neutral-1);
  --surface-card: var(--neutral-3);
  --surface-raised: var(--neutral-1);       /* popover, toast, menu */
  --surface-field: var(--neutral-3);        /* input, textarea, select */
  --surface-field-on-card: var(--neutral-1);
  /* A well inside a raised surface (panel, popover): one clear step off it in either mode. */
  --surface-well: color-mix(in oklab, var(--neutral-3) 40%, var(--neutral-4));
  --surface-media: #000000;                 /* video letterbox: always black */
  --text: var(--neutral-10);
  --text-muted: var(--neutral-8);           /* theme describes with neutral-7; 8 keeps AA on neutral-3 in light */
  --text-disabled: var(--neutral-6);
  --divider: var(--neutral-4);
  --focus-color: color-mix(in oklab, var(--color-1) 72%, var(--color-2));
  --focus-halo: var(--neutral-10);
}

.dark {
  --focus-color: var(--color-1);
  /* On a black canvas, black media would vanish: lift it one step so the frame still reads. */
  --surface-media: var(--neutral-2);
  --neutral-1: #000000;  --neutral-1-transparent: #00000033;
  --neutral-2: #202020;  --neutral-2-transparent: #20202033;
  --neutral-3: #2b2b2b;  --neutral-3-transparent: #2b2b2b33;
  --neutral-4: #3d3d3d;  --neutral-4-transparent: #3d3d3d33;
  --neutral-5: #565656;  --neutral-5-transparent: #56565633;
  --neutral-6: #838383;  --neutral-6-transparent: #83838333;
  --neutral-7: #ababab;  --neutral-7-transparent: #ababab33;
  --neutral-8: #cfcfcf;  --neutral-8-transparent: #cfcfcf33;
  --neutral-9: #f4f4f4;  --neutral-9-transparent: #f4f4f433;
  --neutral-10: #ffffff; --neutral-10-transparent: #ffffff33;

  --primary-on-color-1: var(--neutral-2);   /* theme primaryForeground, dark: neutral-2 */

  --surface-card: var(--neutral-2);
  --surface-raised: var(--neutral-2);
  --surface-field-on-card: var(--neutral-3);
  --text-muted: var(--neutral-7);
}

/* 3. shadcn semantic roles -------------------------------------------------------------------- */
:root,
.dark {
  --background: var(--surface-canvas);
  --foreground: var(--text);
  --card: var(--surface-card);
  --card-foreground: var(--text);
  --popover: var(--surface-raised);
  --popover-foreground: var(--text);
  --secondary: var(--neutral-3);
  --secondary-foreground: var(--neutral-10);
  --muted: var(--neutral-3);
  --accent: var(--neutral-3);
  --accent-foreground: var(--neutral-10);
  --destructive: var(--error);
  --input: var(--surface-field);
  --ring: var(--focus-color);
  --radius: var(--radius-s);
  --field: var(--surface-field);
  --field-on-card: var(--surface-field-on-card);
  --media: var(--surface-media);
  --well: var(--surface-well);
  --backdrop: var(--neutral-10-transparent);
}
.dark { --backdrop: var(--neutral-1-transparent); }
:root { color-scheme: light; }
.dark { color-scheme: dark; }

/* 4. Tailwind theme --------------------------------------------------------------------------- */


/* 5. Character -------------------------------------------------------------------------------- */
/* Every surface decides its character on two axes plus a motion. Set it on <html> or on any
   element that should differ from its parent:

     <div data-character style="--density: -0.4; --intensity: 0.3" data-motion="smooth">

   --density   -1 airy  ...  0 theme  ...  1 compact   (space, type steps, radii)
   --intensity -1 quiet ...  0 theme  ...  1 bold      (accent, edges, display steps)
   data-motion  snappy | smooth (theme) | gentle | still

   Space, type, radii and edges blend, so any point on the pad is valid. The accent is the one
   switch: from halfway quiet it turns neutral. */
:root {
  --density: 0;
  --intensity: 0;
}

:root, [data-character] {
  --airy: max(0, calc(var(--density) * -1));
  --compact: max(0, var(--density));
  --quiet: max(0, calc(var(--intensity) * -1));
  --bold: max(0, var(--intensity));
  /* Hue doesn't blend well (lime through grey is olive), so the accent switches at halfway quiet. */
  --quiet-step: clamp(0, calc((var(--quiet) - 0.49) * 1000), 1);

  /* Density: space, text steps and radii. Airy and compact ends match the old feels. */
  --spacing: calc(0.25rem + 0.05rem * var(--airy) - 0.05rem * var(--compact));
  --size-xxs: calc(10px + 1px * var(--airy));
  --line-xxs: calc(14px + 2px * var(--airy) - 1px * var(--compact));
  --size-xs: calc(12px + 1px * var(--airy) - 1px * var(--compact));
  --line-xs: calc(16px + 4px * var(--airy) - 2px * var(--compact));
  --size-s: calc(14px + 1px * var(--airy) - 1px * var(--compact));
  --line-s: calc(20px + 4px * var(--airy) - 2px * var(--compact));
  --size-m: calc(16px + 2px * var(--airy) - 2px * var(--compact));
  --line-m: calc(24px + 6px * var(--airy) - 4px * var(--compact));
  /* Display steps also grow with intensity. */
  --size-l: calc(24px + 2px * var(--airy) - 4px * var(--compact) + 4px * var(--bold));
  --line-l: calc(32px + 4px * var(--airy) - 6px * var(--compact) + 2px * var(--bold));
  --size-xl: calc(36px + 4px * var(--airy) - 8px * var(--compact) + 12px * var(--bold));
  --line-xl: calc(40px + 8px * var(--airy) - 6px * var(--compact) + 12px * var(--bold));
  --size-xxl: calc(48px + 8px * var(--airy) - 12px * var(--compact) + 24px * var(--bold));
  --line-xxl: calc(52px + 12px * var(--airy) - 10px * var(--compact) + 20px * var(--bold));
  --letter-spacing-xl: calc(-0.01em - 0.01em * var(--bold));
  --letter-spacing-xxl: calc(-0.02em - 0.01em * var(--bold));
  --radius-s: calc(9px - 2px * var(--compact));
  --radius-m: calc(13px - 3px * var(--compact));
  --radius-l: calc(19px - 5px * var(--compact));

  /* Intensity: quiet trades lime for greys, bold hardens edges and contrast. */
  --primary: color-mix(in oklab, var(--neutral-9) calc(100% * var(--quiet-step)), var(--color-1));
  --primary-foreground: color-mix(
    in oklab,
    var(--neutral-1) calc(100% * var(--quiet-step)),
    color-mix(in oklab, #000000 calc(100% * var(--bold)), var(--primary-on-color-1))
  );
  --mark: color-mix(in oklab, var(--neutral-4) calc(100% * var(--quiet-step)), var(--option-badge-background));
  --mark-foreground: color-mix(
    in oklab,
    var(--neutral-9) calc(100% * var(--quiet-step)),
    color-mix(in oklab, #000000 calc(100% * var(--bold)), var(--option-badge-foreground))
  );
  --border: color-mix(
    in oklab,
    var(--neutral-10) calc(100% * var(--bold)),
    color-mix(in oklab, var(--neutral-3) calc(100% * var(--quiet)), var(--divider))
  );
  --muted-foreground: color-mix(in oklab, var(--neutral-9) calc(100% * var(--bold)), var(--text-muted));
}

/* Motion. smooth is the theme's own curve. */
[data-motion="snappy"] {
  --motion-duration: 140ms;
  --motion-easing: cubic-bezier(0.2, 0, 0, 1);
  --motion-large-duration: 240ms;
  --motion-large-easing: cubic-bezier(0.2, 0, 0, 1);
}
[data-motion="smooth"] {
  --motion-duration: 200ms;
  --motion-easing: cubic-bezier(0.16, 1, 0.3, 1);
  --motion-large-duration: 360ms;
  --motion-large-easing: cubic-bezier(0.22, 1, 0.36, 1);
}
[data-motion="gentle"] {
  --motion-duration: 320ms;
  --motion-easing: cubic-bezier(0.33, 1, 0.68, 1);
  --motion-large-duration: 560ms;
  --motion-large-easing: cubic-bezier(0.33, 1, 0.68, 1);
}
[data-motion="still"] {
  --motion-duration: 0ms;
  --motion-large-duration: 0ms;
  --motion-press-distance: 0px;
  --motion-popup-scale: 1;
}

/* A character scope paints its own canvas and type, so a nested surface previews correctly. */
[data-character] {
  background-color: var(--background);
  color: var(--foreground);
  font-size: var(--size-s);
  line-height: var(--line-s);
  letter-spacing: var(--letter-spacing-s);
}


/* Layout grid ----------------------------------------------------------------------------------- */
/* One grid for every page: 1440px max, 12 columns (4 below 768px), fixed 16px gutters. The page
   column is .page; .grid-12 lays children on the columns; .w-span-N sizes a block to N columns of
   its container (so use it in blocks that span the page column). */
:root {
  --page-max: 1440px;
  --page-pad: 1rem;
  --gutter: 16px;
  --cols: 4;
  --content: calc(min(100vw, var(--page-max)) - 2 * var(--page-pad));
  --col: calc((var(--content) - (var(--cols) - 1) * var(--gutter)) / var(--cols));
  /* Distance from the viewport edge to the page column, for full-bleed rows and fixed panels. */
  --page-inset: max(var(--page-pad), calc((100vw - var(--page-max)) / 2 + var(--page-pad)));
}
@media (min-width: 640px) { :root { --page-pad: 1.5rem; } }
@media (min-width: 768px) { :root { --cols: 12; } }
@media (min-width: 1280px) { :root { --page-pad: 2rem; } }

@layer utilities {
  .page { width: 100%; max-width: var(--page-max); margin-inline: auto; padding-inline: var(--page-pad); }
  .grid-12 { display: grid; grid-template-columns: repeat(var(--cols), minmax(0, 1fr)); column-gap: var(--gutter); }
  .w-span-1 { width: min(100%, calc((100% - (var(--cols) - 1) * var(--gutter)) / var(--cols) * 1 + var(--gutter) * 0)); }
  .w-span-2 { width: min(100%, calc((100% - (var(--cols) - 1) * var(--gutter)) / var(--cols) * 2 + var(--gutter) * 1)); }
  .w-span-3 { width: min(100%, calc((100% - (var(--cols) - 1) * var(--gutter)) / var(--cols) * 3 + var(--gutter) * 2)); }
  .w-span-4 { width: min(100%, calc((100% - (var(--cols) - 1) * var(--gutter)) / var(--cols) * 4 + var(--gutter) * 3)); }
  .w-span-5 { width: min(100%, calc((100% - (var(--cols) - 1) * var(--gutter)) / var(--cols) * 5 + var(--gutter) * 4)); }
  .w-span-6 { width: min(100%, calc((100% - (var(--cols) - 1) * var(--gutter)) / var(--cols) * 6 + var(--gutter) * 5)); }
  .w-span-7 { width: min(100%, calc((100% - (var(--cols) - 1) * var(--gutter)) / var(--cols) * 7 + var(--gutter) * 6)); }
  .w-span-8 { width: min(100%, calc((100% - (var(--cols) - 1) * var(--gutter)) / var(--cols) * 8 + var(--gutter) * 7)); }
  .w-span-9 { width: min(100%, calc((100% - (var(--cols) - 1) * var(--gutter)) / var(--cols) * 9 + var(--gutter) * 8)); }
  .w-span-10 { width: min(100%, calc((100% - (var(--cols) - 1) * var(--gutter)) / var(--cols) * 10 + var(--gutter) * 9)); }
  .w-span-11 { width: min(100%, calc((100% - (var(--cols) - 1) * var(--gutter)) / var(--cols) * 11 + var(--gutter) * 10)); }
  .w-span-12 { width: min(100%, calc((100% - (var(--cols) - 1) * var(--gutter)) / var(--cols) * 12 + var(--gutter) * 11)); }
}

/* 6. Base and shared finishes ----------------------------------------------------------------- */
@layer base {
  *, *::before, *::after {
    border-width: 0;
    border-color: var(--border);
  }
  html {
    font-family: var(--font-ui);
    font-weight: var(--weight-ui-regular);
    font-synthesis: none;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    text-size-adjust: 100%;
    background: var(--background);
    color: var(--foreground);
  }
  body {
    min-height: 100dvh;
    background: var(--background);
    color: var(--foreground);
    font-size: var(--size-s);
    line-height: var(--line-s);
    letter-spacing: var(--letter-spacing-s);
    text-wrap: pretty;
  }
  /* Headings and controls take their weight from the class, never from browser defaults. */
  h1, h2, h3, h4, h5, h6, th, kbd, button, input, select, textarea, optgroup {
    font-weight: inherit;
  }
  ::selection { background: var(--color-1-transparent); }
  :focus-visible { outline: none; }
}

@layer utilities {
  /* Focus: one soft ring that hugs the shape with air between, never a line pressed onto it.
     Outlines follow border-radius, so the ring keeps the element's corners. */
  .focus-ring:focus-visible,
  .focus-ring-within:focus-within {
    outline: 2px solid var(--focus-color);
    outline-offset: 3px;
  }
  /* Selected item (card, row): the same two-colour ring, drawn inside. */
  .ring-selected {
    box-shadow: inset 0 0 0 1px var(--focus-halo), inset 0 0 0 3px var(--focus-color);
  }
  /* Popups (select, menu, tooltip, dialog): theme popup scale + small curve on Base UI lifecycle. */
  .popup-motion {
    transform-origin: var(--transform-origin, center);
    transition-property: opacity, scale;
    transition-duration: var(--motion-duration);
    transition-timing-function: var(--motion-easing);
  }
  .popup-motion[data-starting-style],
  .popup-motion[data-ending-style] {
    opacity: 0;
    scale: var(--motion-popup-scale);
  }
  .backdrop-motion {
    transition: opacity var(--motion-large-duration) var(--motion-large-easing);
  }
  .backdrop-motion[data-starting-style],
  .backdrop-motion[data-ending-style] { opacity: 0; }
  .press {
    transition-property: color, background-color, box-shadow, translate, opacity;
    transition-duration: var(--motion-duration);
    transition-timing-function: var(--motion-easing);
  }
  .press:active:not(:disabled):not([aria-disabled="true"]):not([data-disabled]) {
    translate: 0 var(--motion-press-distance);
  }
  .tabular { font-variant-numeric: tabular-nums; }
  /* Eyebrow: the small label above a title or group (never a value label). Uppercase mono, tracked. */
  .eyebrow {
    font-family: var(--font-code);
    font-size: var(--size-xxs);
    line-height: var(--line-xxs);
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--muted-foreground);
  }
  /* The mark as a loader: its three dots dim and return one by one (see components/vasavan/mark). */
  .mark-loading { animation: mark-dot 1.1s ease-in-out infinite; }
  /* Hidden scrollbar; edges fade where there is more to scroll (see components/vasavan/scroll-fade). */
  .scroll-fade {
    scrollbar-width: none;
    --fade-top: 0px;
    --fade-bottom: 0px;
    mask-image: linear-gradient(to bottom, transparent, #000 var(--fade-top), #000 calc(100% - var(--fade-bottom)), transparent);
    transition: --fade-top var(--motion-duration) var(--motion-easing), --fade-bottom var(--motion-duration) var(--motion-easing);
  }
  .scroll-fade::-webkit-scrollbar { display: none; }
}

/* Sonner toasts: the theme's Toast popover assignment (radius m, padding m, shadow m, no edge). */
[data-sonner-toaster] {
  --normal-bg: var(--popover);
  --normal-text: var(--popover-foreground);
  --normal-border: transparent;
  --border-radius: var(--radius-m);
  font-family: var(--font-ui);
}
[data-sonner-toaster] [data-sonner-toast] {
  padding: var(--space-m);
  gap: var(--space-xs);
  border-width: 0;
  box-shadow: var(--shadow-m);
  font-size: var(--size-s);
  line-height: var(--line-s);
  letter-spacing: var(--letter-spacing-s);
}
[data-sonner-toaster] [data-sonner-toast] [data-title] { font-weight: 400; }
[data-sonner-toaster] [data-sonner-toast] [data-description] { color: var(--text-muted); }
[data-sonner-toaster] [data-sonner-toast][data-type="success"] [data-icon] { color: var(--success); }
[data-sonner-toaster] [data-sonner-toast][data-type="error"] [data-icon] { color: var(--error); }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    transition-duration: 0ms !important;
    animation-duration: 0ms !important;
    animation-iteration-count: 1 !important;
  }
}

@keyframes mark-dot {
  0%, 60%, 100% { opacity: 1; }
  30% { opacity: 0.2; }
}
