/*
 * Bridgus design system — core
 *
 * The only stylesheet in <head>. Each component ships its own chunk in
 * /static/css/c/*.css, emitted by the component the first time it renders
 * (and fetched only when that component appears on the page, including
 * fragments swapped in by htmx). Layer order is fixed here, so chunks can
 * load in any order without specificity fights.
 */
@layer reset, tokens, fonts, base, layout, components, utilities;

/* ------------------------------------------------------------------ tokens */
@layer tokens {
  :root {
    color-scheme: light dark;

    /* brand */
    --brand-h: 42;
    --accent: oklch(0.73 0.155 var(--brand-h));
    --accent-strong: oklch(0.66 0.17 var(--brand-h));
    --accent-soft: color-mix(in oklab, var(--accent) 16%, var(--surface));
    --accent-ink: oklch(0.99 0.01 var(--brand-h));
    /* solid accent surface that carries --accent-ink text (≥ 4.5:1) */
    --accent-fill: oklch(0.55 0.127 var(--brand-h));

    /* neutrals (warm greys) */
    --bg: light-dark(oklch(0.935 0.004 75), oklch(0.17 0.004 75));
    --surface: light-dark(oklch(0.962 0.003 75), oklch(0.215 0.004 75));
    --surface-2: light-dark(oklch(0.985 0.002 75), oklch(0.255 0.005 75));
    --surface-sunken: light-dark(oklch(0.91 0.005 75), oklch(0.19 0.004 75));
    --border: light-dark(oklch(1 0 0 / 0.75), oklch(1 0 0 / 0.06));
    --border-strong: light-dark(oklch(0.86 0.006 75), oklch(0.33 0.006 75));
    --ink: light-dark(oklch(0.2 0.005 75), oklch(0.96 0.003 75));
    --ink-2: light-dark(oklch(0.38 0.005 75), oklch(0.82 0.004 75));
    --muted: light-dark(oklch(0.5 0.006 75), oklch(0.66 0.006 75));
    --inverse: light-dark(oklch(0.18 0.004 75), oklch(0.97 0.003 75));
    --inverse-ink: light-dark(oklch(0.98 0 0), oklch(0.18 0.004 75));

    /* status palette: every tone has the same four roles, from one formula
     *   --{tone}       solid fill (bars, dots, solid badges)
     *   --{tone}-soft  tinted background
     *   --{tone}-text  readable text/icons on the soft background (≥ 4.5:1)
     *   --{tone}-line  border on the soft background
     *   --on-{tone}    text on the solid fill
     */
    --success: light-dark(oklch(0.62 0.15 152), oklch(0.74 0.135 152));
    --success-soft: light-dark(oklch(0.952 0.033 152), oklch(0.295 0.052 152));
    --success-text: light-dark(oklch(0.46 0.135 152), oklch(0.86 0.083 152));
    --success-line: light-dark(oklch(0.87 0.068 152), oklch(0.42 0.075 152));
    --on-success: oklch(0.99 0.005 152);
    --warning: light-dark(oklch(0.77 0.15 72), oklch(0.81 0.135 72));
    --warning-soft: light-dark(oklch(0.952 0.033 72), oklch(0.295 0.052 72));
    --warning-text: light-dark(oklch(0.46 0.135 72), oklch(0.86 0.083 72));
    --warning-line: light-dark(oklch(0.87 0.068 72), oklch(0.42 0.075 72));
    --on-warning: oklch(0.25 0.05 72);
    --danger: light-dark(oklch(0.6 0.19 25), oklch(0.74 0.171 25));
    --danger-soft: light-dark(oklch(0.952 0.042 25), oklch(0.295 0.066 25));
    --danger-text: light-dark(oklch(0.46 0.171 25), oklch(0.86 0.105 25));
    --danger-line: light-dark(oklch(0.87 0.086 25), oklch(0.42 0.095 25));
    --on-danger: oklch(0.99 0.005 25);
    --info: light-dark(oklch(0.58 0.18 258), oklch(0.74 0.162 258));
    --info-soft: light-dark(oklch(0.952 0.04 258), oklch(0.295 0.063 258));
    --info-text: light-dark(oklch(0.46 0.162 258), oklch(0.86 0.099 258));
    --info-line: light-dark(oklch(0.87 0.081 258), oklch(0.42 0.09 258));
    --on-info: oklch(0.99 0.005 258);
    --violet: light-dark(oklch(0.6 0.2 305), oklch(0.74 0.18 305));
    --violet-soft: light-dark(oklch(0.952 0.044 305), oklch(0.295 0.07 305));
    --violet-text: light-dark(oklch(0.46 0.18 305), oklch(0.86 0.11 305));
    --violet-line: light-dark(oklch(0.87 0.09 305), oklch(0.42 0.1 305));
    --on-violet: oklch(0.99 0.005 305);
    --teal: light-dark(oklch(0.62 0.11 190), oklch(0.74 0.099 190));
    --teal-soft: light-dark(oklch(0.952 0.024 190), oklch(0.295 0.038 190));
    --teal-text: light-dark(oklch(0.46 0.099 190), oklch(0.86 0.061 190));
    --teal-line: light-dark(oklch(0.87 0.05 190), oklch(0.42 0.055 190));
    --on-teal: oklch(0.99 0.005 190);
    --pink: light-dark(oklch(0.64 0.18 350), oklch(0.74 0.162 350));
    --pink-soft: light-dark(oklch(0.952 0.04 350), oklch(0.295 0.063 350));
    --pink-text: light-dark(oklch(0.46 0.162 350), oklch(0.86 0.099 350));
    --pink-line: light-dark(oklch(0.87 0.081 350), oklch(0.42 0.09 350));
    --on-pink: oklch(0.99 0.005 350);
    --accent-text: light-dark(oklch(0.5 0.15 var(--brand-h)), oklch(0.84 0.09 var(--brand-h)));
    --accent-line: light-dark(oklch(0.86 0.07 var(--brand-h)), oklch(0.44 0.08 var(--brand-h)));
    --neutral: var(--muted);
    --neutral-soft: var(--surface-sunken);
    --neutral-text: var(--ink-2);
    --neutral-line: var(--border-strong);
    --on-neutral: var(--surface-2);

    /* data viz */
    --chart-bar: light-dark(oklch(0.86 0.004 75), oklch(0.34 0.005 75));
    --chart-line: light-dark(oklch(0.9 0.004 75), oklch(0.29 0.005 75));
    --chart-grid: light-dark(oklch(0.84 0.004 75), oklch(0.32 0.005 75));
    --map: oklch(0.55 0.22 268);

    /* type */
    --font-sans: "Poppins", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
    --font-mono: "Geist Mono", ui-monospace, "SF Mono", "Cascadia Code", monospace;
    --font-display: "Bricolage Grotesque", var(--font-sans);
    --text-2xs: 0.6875rem;
    --text-xs: 0.75rem;
    --text-sm: 0.8125rem;
    --text-md: 0.9375rem;
    --text-lg: 1.125rem;
    --text-xl: 1.375rem;
    --text-2xl: clamp(1.5rem, 1.2rem + 1vw, 1.875rem);
    --text-3xl: clamp(1.75rem, 1.3rem + 1.6vw, 2.25rem);

    /* space — 8px grid: --space-N = N × 8px. Paddings, gaps and margins use
     * these tokens; --space-0-5 (4px) is reserved for micro spacing inside
     * small elements (badges, pills, icon-to-label gaps). */
    --space-0-5: 0.25rem; /*  4px */
    --space-1: 0.5rem;    /*  8px */
    --space-2: 1rem;      /* 16px */
    --space-3: 1.5rem;    /* 24px */
    --space-4: 2rem;      /* 32px */
    --space-5: 2.5rem;    /* 40px */
    --space-6: 3rem;      /* 48px */
    --space-8: 4rem;      /* 64px */
    --space-10: 5rem;     /* 80px */
    --space-12: 6rem;     /* 96px */

    /* sizes on the same grid */
    --control-sm: 2rem;   /* 32px */
    --control-md: 2.5rem; /* 40px */
    --control-lg: 3rem;   /* 48px */
    --card-pad: var(--space-3);

    /* shape */
    --radius-xs: 6px;
    --radius-sm: 10px;
    --radius-md: 14px;
    --radius-lg: 18px;
    --radius-xl: 26px;
    --radius-full: 999px;

    --shadow-xs: 0 1px 2px oklch(0.2 0.01 75 / 0.06);
    --shadow-sm: 0 1px 2px oklch(0.2 0.01 75 / 0.05), 0 2px 8px oklch(0.2 0.01 75 / 0.05);
    --shadow-md: 0 4px 12px oklch(0.2 0.01 75 / 0.08), 0 1px 3px oklch(0.2 0.01 75 / 0.06);
    --shadow-lg: 0 18px 40px oklch(0.2 0.01 75 / 0.16), 0 4px 12px oklch(0.2 0.01 75 / 0.08);
    --ring: 0 0 0 3px color-mix(in oklab, var(--accent) 35%, transparent);

    --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
    /* springs are reserved for overlays (dialogs, toasts, dropdowns);
     * everything else moves with --ease-out. cubic-bezier fallbacks are
     * replaced by linear() below where supported. */
    --ease-spring: cubic-bezier(0.34, 1.36, 0.64, 1);
    --ease-pop: cubic-bezier(0.34, 1.56, 0.64, 1);
    --dur-fast: 120ms;
    --dur: 200ms;
    --dur-slow: 320ms;
    --dur-spring: 650ms;

    --container: 1320px;

    /* weights match the embedded font files (Poppins 400/500/600, Geist Mono 400/500,
     * Bricolage Grotesque 200–800 variable); for Poppins --weight-bold falls back to the
     * nearest embedded face (600) in the browser. */
    --weight-regular: 400;
    --weight-medium: 500;
    --weight-semibold: 600;
    --weight-bold: 700;

    --leading-none: 1;
    --leading-display: 1.1;
    --leading-tight: 1.2;
    --leading-snug: 1.35;
    --leading-cozy: 1.45;
    --leading-normal: 1.5;
    --leading-relaxed: 1.65;

    --tracking-tightest: -0.04em;
    --tracking-tighter: -0.02em;
    --tracking-tight: -0.01em;
    --tracking-wide: 0.06em;
    --tracking-wider: 0.08em;
    --tracking-widest: 0.16em;

    /* stacking */
    --z-base: 0;
    --z-raised: 2;
    --z-dropdown: 10;
    --z-sticky: 20;
    --z-tooltip: 30;
    --z-overlay: 40;
    --z-dialog: 50;
    --z-toast: 100;

    /* icon boxes */
    --icon-xs: 1rem;      /* 16px */
    --icon-sm: 1.125rem;  /* 18px */
    --icon-md: 1.25rem;   /* 20px */
    --icon-lg: 1.5rem;    /* 24px */

    /* lines and focus */
    --border-width: 1px;
    --border-width-strong: 2px;
    --ring-width: 3px;
    --focus-offset: 2px;
    --hover-lift: 2px;
    --radius-focus: 4px;

    --blur-sm: 4px;
    --blur-md: 16px;
    --blur-lg: 20px;

    /* light and shadow colors */
    --scrim: oklch(0.15 0.01 75 / 0.4);

    /* motion */
    --dur-reduced: 0.01ms;
    --dur-exit: 240ms;
    --dur-long: 700ms;
    --dur-loop: 1.8s;
    --stagger-sm: 30ms;
    --stagger-md: 40ms;
    --stagger-lg: 50ms;

    --card-min-block: 9.5rem;
  }

  :root[data-theme="light"] { color-scheme: light; }
  :root[data-theme="dark"] { color-scheme: dark; }

  @supports (transition-timing-function: linear(0, 1)) {
    :root {
      /* gentle spring, ~2% overshoot */
      --ease-spring: linear(0, 0.006, 0.025 2.8%, 0.101 6.1%, 0.539 18.9%, 0.721 25.3%, 0.849 31.5%,
        0.937 38.1%, 0.968 41.8%, 0.991 45.7%, 1.006 50.1%, 1.015 55%, 1.017 63.9%, 1.001 85.9%, 1);
      /* bouncy spring for small "pop" elements */
      --ease-pop: linear(0, 0.009, 0.035 2.1%, 0.141, 0.281 6.7%, 0.723 12.9%, 0.938 16.7%, 1.017,
        1.077, 1.121, 1.149 24.3%, 1.159, 1.163, 1.161, 1.154 29.9%, 1.129 32.8%, 1.051 39.6%,
        1.017 43.1%, 0.991, 0.977 51%, 0.974 53.8%, 0.975 57.1%, 0.997 69.8%, 1.003 76.9%, 1);
    }
  }
}

/* ------------------------------------------------------------------- fonts */
/*
 * Self-hosted, latin subset, SIL OFL (see /static/fonts/OFL-*.txt). The url()s
 * are relative to this stylesheet (/static/css/), so they resolve to
 * /static/fonts/* without a content hash; the files are versioned by name.
 */
@layer fonts {
  @font-face {
    font-family: "Poppins";
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url("../fonts/poppins-latin-400-normal.woff2") format("woff2");
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
  }
  @font-face {
    font-family: "Poppins";
    font-style: normal;
    font-weight: 500;
    font-display: swap;
    src: url("../fonts/poppins-latin-500-normal.woff2") format("woff2");
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
  }
  @font-face {
    font-family: "Poppins";
    font-style: normal;
    font-weight: 600;
    font-display: swap;
    src: url("../fonts/poppins-latin-600-normal.woff2") format("woff2");
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
  }
  @font-face {
    font-family: "Geist Mono";
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url("../fonts/geist-mono-latin-400-normal.woff2") format("woff2");
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
  }
  @font-face {
    font-family: "Geist Mono";
    font-style: normal;
    font-weight: 500;
    font-display: swap;
    src: url("../fonts/geist-mono-latin-500-normal.woff2") format("woff2");
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
  }
  @font-face {
    font-family: "Bricolage Grotesque";
    font-style: normal;
    font-weight: 200 800;
    font-display: swap;
    src: url("../fonts/bricolage-grotesque-latin-opsz-normal.woff2") format("woff2");
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
  }
}

/* ------------------------------------------------------------------- reset */
@layer reset {
  *, *::before, *::after { box-sizing: border-box; }
  * { margin: 0; }
  html { -webkit-text-size-adjust: none; text-size-adjust: none; interpolate-size: allow-keywords; }
  body { min-height: 100svh; line-height: var(--leading-normal); -webkit-font-smoothing: antialiased; }
  img, picture, video, canvas, svg { display: block; max-inline-size: 100%; }
  input, button, textarea, select { font: inherit; color: inherit; }
  button { cursor: pointer; background: none; border: 0; padding: 0; }
  a { color: inherit; text-decoration: none; }
  ul[role="list"], ol[role="list"] { list-style: none; padding: 0; }
  p, h1, h2, h3, h4 { overflow-wrap: break-word; }
  h1, h2, h3, h4 { text-wrap: balance; line-height: var(--leading-tight); }
  p { text-wrap: pretty; }
  table { border-collapse: collapse; }
  [hidden] { display: none !important; }
  [x-cloak] { display: none !important; }
}

/* -------------------------------------------------------------------- base */
@layer base {
  body {
    font-family: var(--font-sans);
    font-size: var(--text-md);
    color: var(--ink);
    background: var(--bg);
    transition: background-color var(--dur) var(--ease-out), color var(--dur) var(--ease-out);
  }

  :focus-visible { outline: var(--border-width-strong) solid var(--accent); outline-offset: var(--focus-offset); border-radius: var(--radius-focus); }
  ::selection { background: color-mix(in oklab, var(--accent) 30%, transparent); }

  h1, h2, h3 { font-family: var(--font-display); font-optical-sizing: auto; }
  h1 { font-size: var(--text-2xl); font-weight: var(--weight-semibold); letter-spacing: var(--tracking-tighter); }
  h2 { font-size: var(--text-xl); font-weight: var(--weight-semibold); letter-spacing: var(--tracking-tighter); }
  h3 { font-size: var(--text-lg); font-weight: var(--weight-semibold); letter-spacing: var(--tracking-tight); }
  h4 { font-size: var(--text-md); font-weight: var(--weight-medium); }
  small { font-size: var(--text-xs); }
  code, kbd { font-family: var(--font-mono); font-size: 0.875em; }
  code {
    padding: 0.1em 0.4em;
    border-radius: var(--radius-xs);
    background: var(--surface-sunken);
  }

  .icon { flex-shrink: 0; inline-size: 1.25em; block-size: 1.25em; overflow: visible; }

  /* [data-motion-essential] marks animations that carry information (timers) */
  @media (prefers-reduced-motion: reduce) {
    :not([data-motion-essential]), :not([data-motion-essential])::before, :not([data-motion-essential])::after {
      animation-duration: var(--dur-reduced) !important;
      transition-duration: var(--dur-reduced) !important;
    }
  }
}

/* ------------------------------------------------------------------ motion */
/*
 * html.motion is set by js/theme.js in <head>, so content is hidden from
 * the first paint only when JS (and therefore Alpine) will reveal it.
 *   x-reveal           the element pops in when it enters the viewport
 *   x-reveal.children  its children pop in one after another
 * Only nodes with data-swap-animate get .swap-in (see app.js); navigation swaps instantly.
 */
@layer base {
  @keyframes rise-in {
    from { opacity: 0; translate: 0 var(--space-1); }
  }
  @keyframes fade-in { from { opacity: 0; } }

  .motion {
    --dur-reveal: 450ms;
    --dur-swap: 300ms;
    [x-reveal]:not(.is-in),
    [x-reveal\.children]:not(.is-in) > * { opacity: 0; }

    [x-reveal].is-in,
    [x-reveal\.children].is-in > *,
    .swap-in :is(.list > li, tbody > tr, .grid > *) {
      animation:
        rise-in var(--dur-reveal) var(--ease-out) backwards;
      animation-delay: calc(var(--i, 0) * var(--stagger-md));
    }

    .swap-in { animation: fade-in var(--dur-swap) ease-out backwards; }

  }

  /* theme switch: circular reveal driven by the View Transitions API */
  ::view-transition-old(root),
  ::view-transition-new(root) { animation: none; mix-blend-mode: normal; }
  .theme-switching *,
  .theme-switching *::before,
  .theme-switching *::after,
  .theme-switching body { transition: none !important; }
}

/* ------------------------------------------------------------------ layout */
@layer layout {
  .container {
    inline-size: min(100% - 2 * var(--space-2), var(--container));
    margin-inline: auto;
  }

  .stack { display: flex; flex-direction: column; gap: var(--gap, var(--space-2)); }
  .cluster { display: flex; flex-wrap: wrap; align-items: center; gap: var(--gap, var(--space-2)); }
  .spread { display: flex; align-items: center; justify-content: space-between; gap: var(--gap, var(--space-2)); }

  /* auto-fit grid: columns never narrower than --min */
  .grid {
    --grid-min: 15rem;
    display: grid;
    gap: var(--gap, var(--space-2));
    grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--min, var(--grid-min))), 1fr));
  }

  /* dashboard row: main + aside, collapses on narrow screens */
  .split {
    display: grid;
    gap: var(--gap, var(--space-2));
    grid-template-columns: minmax(0, var(--main, 2fr)) minmax(0, var(--aside, 1fr));

    @media (width < 960px) { grid-template-columns: minmax(0, 1fr); }
  }
}

/* --------------------------------------------------------------- utilities */
@layer base {
  /* htmx indicator styles live here because htmx.config.includeIndicatorStyles is off (CSP) */
  .htmx-indicator { opacity: 0; }
  .htmx-request .htmx-indicator,
  .htmx-request.htmx-indicator { opacity: 1; transition: opacity var(--dur) ease-in; }
}

@layer utilities {
  .muted { color: var(--muted); }
  .ink-2 { color: var(--ink-2); }
  .text-xs { font-size: var(--text-xs); }
  .text-sm { font-size: var(--text-sm); }
  .text-lg { font-size: var(--text-lg); }
  .num { font-variant-numeric: tabular-nums; }
  .semibold { font-weight: var(--weight-semibold); }
  .grow { flex: 1; }
  .w-full { inline-size: 100%; }
  .sr-only {
    position: absolute; inline-size: var(--border-width); block-size: var(--border-width); padding: 0; margin: calc(var(--border-width) * -1);
    overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0;
  }
}
