/* =============================================================================
   R3 Component Library — master stylesheet
   =============================================================================
   This is the ONLY file a page needs to link:

       <link rel="stylesheet" href="/components/styles.css">

   It defines the design tokens, the base/reset layer, the utility classes, and
   it @imports every component stylesheet. Linking it gives you .btn, .input,
   .panel, .modal, .table and .nav.

   ---------------------------------------------------------------------------
   THE CASCADE LAYERS — why this file starts with @layer
   ---------------------------------------------------------------------------
   Existing R3 pages already define class names that collide with this library:
   `.nav-item` (shell/settings.html), `.modal-btn` (shell/dashboard.html),
   `.dropdown-item`, and a bare `button {}` element rule (editor/editor.html:24).

   Every rule in this library lives inside a @layer. Per the CSS cascade,
   UNLAYERED styles beat ALL layered styles regardless of specificity. A page's
   own <style> block is unlayered, so its rules keep winning.

   The practical consequence, and it is the whole migration strategy:

       Adding this stylesheet to a page CANNOT change how that page currently
       looks. Legacy rules keep winning until you delete them.

   So you can link the library on day one and refactor a component at a time.
   See INTEGRATION.md.

   Layer order (later beats earlier):
     tokens      design tokens (--r3-*)
     base        opt-in element normalization, focus ring
     components  .btn .input .panel .modal .table .nav
     theme       theme-switch transitions + toggle control
     utilities   .flex .gap-2 .text-sm ... (beat components on purpose)
   ---------------------------------------------------------------------------
   All tokens are prefixed --r3-* so they never collide with the app's existing
   --space-color (set per-space at runtime) or --col-tracks (pricechange).
   ============================================================================= */

@layer tokens, base, components, theme, utilities;

@import url('./button.css')     layer(components);
@import url('./form.css')       layer(components);
@import url('./panel.css')      layer(components);
@import url('./modal.css')      layer(components);
@import url('./table.css')      layer(components);
@import url('./quick-table.css') layer(components);
@import url('./navigation.css') layer(components);
@import url('./theme.css')      layer(theme);

/* =============================================================================
   TOKENS
   ============================================================================= */

@layer tokens {

  /* ---------------------------------------------------------------------------
     Non-color tokens. Identical in both themes — declared once on :root.
     Use these instead of magic numbers. If you need a value that isn't here,
     add it here rather than hardcoding it at the call site.
     --------------------------------------------------------------------------- */
  :root {

    /* -- Typography ---------------------------------------------------------
       The app is overwhelmingly monospace (180 `font-family: monospace` decls
       vs 18 `system-ui`), so --r3-font-ui defaults to mono to match the editor,
       shell and pricechange surfaces. The viewer/canvas surfaces are sans; to
       flip a page, override one token on <body>:

           body { --r3-font-ui: var(--r3-font-sans); }
    */
    --r3-font-mono: ui-monospace, 'SF Mono', 'Fira Code', 'JetBrains Mono', Menlo, Consolas, monospace;
    --r3-font-sans: system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
    --r3-font-ui: var(--r3-font-mono);

    --r3-text-xs:   0.72rem;
    --r3-text-sm:   0.8rem;
    --r3-text-base: 0.875rem;
    --r3-text-lg:   1rem;
    --r3-text-xl:   1.25rem;
    --r3-text-2xl:  1.5rem;

    --r3-weight-normal:   400;
    --r3-weight-medium:   500;
    --r3-weight-semibold: 600;

    --r3-leading-tight:  1.25;
    --r3-leading-normal: 1.5;

    /* -- Spacing scale (4px base) ------------------------------------------ */
    --r3-space-0: 0;
    --r3-space-1: 0.25rem;  /*  4px */
    --r3-space-2: 0.5rem;   /*  8px */
    --r3-space-3: 0.75rem;  /* 12px */
    --r3-space-4: 1rem;     /* 16px */
    --r3-space-5: 1.5rem;   /* 24px */
    --r3-space-6: 2rem;     /* 32px */
    --r3-space-7: 3rem;     /* 48px */

    /* -- Radius ------------------------------------------------------------- */
    --r3-radius-sm:   3px;
    --r3-radius-md:   4px;   /* the app's dominant radius */
    --r3-radius-lg:   6px;   /* modals, cards */
    --r3-radius-xl:   10px;
    --r3-radius-full: 999px;

    /* -- Borders ------------------------------------------------------------ */
    --r3-border-width: 1px;

    /* -- Motion -------------------------------------------------------------
       --r3-theme-transition is the 0.2s light/dark fade. */
    --r3-transition-fast: 120ms;
    --r3-transition:      150ms;
    --r3-transition-slow: 240ms;
    --r3-theme-transition: 200ms;
    --r3-ease: cubic-bezier(0.4, 0, 0.2, 1);

    /* -- Elevation (z-index scale — never invent a z-index) ------------------ */
    --r3-z-base:     0;
    --r3-z-sticky:   50;
    --r3-z-dropdown: 100;
    --r3-z-modal:    1000;
    --r3-z-toast:    2000;

    /* -- Focus ring ---------------------------------------------------------- */
    --r3-focus-width:  2px;
    --r3-focus-offset: 2px;

    /* -- Control sizes -------------------------------------------------------- */
    --r3-control-sm: 1.625rem; /* 26px */
    --r3-control-md: 2rem;     /* 32px */
    --r3-control-lg: 2.5rem;   /* 40px */

    /* -- Component sizes ------------------------------------------------------
       Widths that would otherwise be magic numbers scattered across the
       component files. */
    --r3-modal-sm: 340px;
    --r3-modal-md: 440px;   /* the default .modal */
    --r3-modal-lg: 640px;
    --r3-modal-xl: 900px;

    --r3-menu-min:  180px;  /* .nav-menu dropdown */
    --r3-card-min:  240px;  /* .panel-grid column floor, before it reflows */

    /* -- Breakpoint -----------------------------------------------------------
       THE breakpoint. Below this, modals become bottom sheets, .table-stack
       stacks, .panel-grid drops to one column, and .nav-bar scrolls.

       It is a literal `640px` in each @media rule rather than a var(): a media
       query CANNOT read a custom property (`@media (max-width: var(--x))` is
       invalid CSS — the at-rule is evaluated before custom properties resolve).
       This token is the single documented source; if you change it, change the
       four @media rules in modal/table/panel/navigation.css with it. */
    --r3-bp-mobile: 640px;
  }

  /* ---------------------------------------------------------------------------
     LIGHT THEME
     Default. Applies at :root so the library is styled even before theme.js
     runs (no flash of unstyled color), and on .light-mode for the explicit
     opt-in that theme.js writes to <body>.

     Every color is a semantic ROLE, not a hue. The four-part contract for each
     accent colour:

       --r3-x        the colour itself — fills, borders, indicators
       --r3-x-fg     text placed ON a --r3-x fill        (>= 4.5:1 vs --r3-x)
       --r3-x-ink    --r3-x used AS text on the page bg  (>= 4.5:1 vs --r3-bg)
       --r3-x-soft   translucent tint for subtle backgrounds

     -ink exists because the app's signature blue #4a9eff scores only 2.7:1 on
     white — it is unreadable as light-mode text. -ink is the darkened variant
     that passes. Never use --r3-accent directly as a text colour.

     All pairs are verified WCAG AA — see components/contrast-check.mjs.
     --------------------------------------------------------------------------- */
  :root,
  .light-mode {
    color-scheme: light;

    --r3-bg:             #ffffff;
    --r3-bg-sunken:      #f2f3f5;
    --r3-surface:        #ffffff;
    --r3-surface-raised: #ffffff;
    --r3-surface-hover:  #f0f1f3;
    --r3-surface-active: #e6e8eb;

    /* --r3-border is a DIVIDER (panel rules, table rules). Dividers are
       decorative and exempt from WCAG 1.4.11, so it can stay soft.
       --r3-border-strong is a CONTROL BOUNDARY (the outline of a secondary
       button). That is NOT exempt — it must clear 3:1 against the surface
       behind it, which is why it is darker than the #b9bec4-ish grey the eye
       initially reaches for. */
    --r3-border:         #e3e5e8;
    --r3-border-strong:  #8f959c;  /* 3.09:1 on --r3-surface */

    --r3-text:           #16181d;  /* 17.8:1 on --r3-bg */
    --r3-text-muted:     #5b6169;  /*  6.3:1 on --r3-bg */
    --r3-text-subtle:    #6f757d;  /*  4.7:1 on --r3-bg — placeholders, empty states */
    --r3-text-inverse:   #ffffff;

    --r3-accent:         #1668dc;
    --r3-accent-hover:   #0f56bd;
    --r3-accent-fg:      #ffffff;  /*  5.2:1 on --r3-accent */
    --r3-accent-ink:     #0f5ec4;  /*  6.1:1 on --r3-bg */
    --r3-accent-soft:    rgba(22, 104, 220, 0.10);

    --r3-success:        #157f4c;
    --r3-success-fg:     #ffffff;
    --r3-success-ink:    #127344;
    --r3-success-soft:   rgba(21, 127, 76, 0.10);

    --r3-danger:         #c62b31;
    --r3-danger-fg:      #ffffff;
    --r3-danger-ink:     #b8262c;
    --r3-danger-soft:    rgba(198, 43, 49, 0.10);

    --r3-warning:        #955700;
    --r3-warning-fg:     #ffffff;
    --r3-warning-ink:    #8a5200;
    --r3-warning-soft:   rgba(149, 87, 0, 0.10);

    --r3-focus:          #1668dc;
    --r3-scrim:          rgba(15, 17, 20, 0.45);

    --r3-shadow-sm: 0 1px 2px rgba(15, 17, 20, 0.06);
    --r3-shadow-md: 0 4px 12px rgba(15, 17, 20, 0.08);
    --r3-shadow-lg: 0 16px 48px rgba(15, 17, 20, 0.18);
  }

  /* ---------------------------------------------------------------------------
     DARK THEME
     Values are taken from the palette the app already ships — #111 body,
     #1a1a1a panel, #2e2e2e border, #4a9eff accent — with the text greys nudged
     to clear WCAG AA. (The app's ubiquitous #888 muted text is 4.2:1 on #1a1a1a
     and fails AA; --r3-text-muted is #a3a3a3 = 6.6:1.)
     --------------------------------------------------------------------------- */
  .dark-mode {
    color-scheme: dark;

    --r3-bg:             #111111;
    --r3-bg-sunken:      #0d0d0d;
    --r3-surface:        #1a1a1a;
    --r3-surface-raised: #222222;
    --r3-surface-hover:  #2a2a2a;
    --r3-surface-active: #333333;

    /* Same split as light mode: --r3-border is a decorative divider and keeps
       the app's existing #2e2e2e. --r3-border-strong is a control boundary and
       must clear 3:1 on --r3-surface — the app's current #555 button borders
       score 2.4:1 and fail. This is the one place the library deliberately
       looks lighter than today's UI; it's the cost of an outline you can
       actually see. */
    --r3-border:         #2e2e2e;
    --r3-border-strong:  #6b6b6b;  /* 3.05:1 on --r3-surface */

    --r3-text:           #ededed;  /* 16.1:1 on --r3-bg */
    --r3-text-muted:     #a3a3a3;  /*  7.5:1 on --r3-bg */
    --r3-text-subtle:    #8a8a8a;  /*  5.1:1 on --r3-bg — placeholders, empty states */
    --r3-text-inverse:   #111111;

    --r3-accent:         #4a9eff;  /* the app's signature blue, unchanged */
    --r3-accent-hover:   #6fb2ff;
    --r3-accent-fg:      #06121f;  /*  6.9:1 on --r3-accent */
    --r3-accent-ink:     #4a9eff;  /*  6.9:1 on --r3-bg — readable as-is on dark */
    --r3-accent-soft:    rgba(74, 158, 255, 0.14);

    --r3-success:        #29a866;
    --r3-success-fg:     #04140b;
    --r3-success-ink:    #4ed693;
    --r3-success-soft:   rgba(41, 168, 102, 0.14);

    --r3-danger:         #ff6b6b;  /* the app's existing danger */
    --r3-danger-fg:      #240505;
    --r3-danger-ink:     #ff8080;
    --r3-danger-soft:    rgba(255, 107, 107, 0.14);

    --r3-warning:        #e0a02a;
    --r3-warning-fg:     #1a1200;
    --r3-warning-ink:    #e8b355;
    --r3-warning-soft:   rgba(224, 160, 42, 0.14);

    --r3-focus:          #6fb2ff;
    --r3-scrim:          rgba(0, 0, 0, 0.65);

    --r3-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.4);
    --r3-shadow-md: 0 4px 12px rgba(0, 0, 0, 0.45);
    --r3-shadow-lg: 0 16px 48px rgba(0, 0, 0, 0.55);
  }
}

/* =============================================================================
   BASE
   Deliberately minimal. This library is being adopted incrementally into pages
   that already style their own elements, so base does NOT restyle body, h1-h6,
   p or button. It only sets box-sizing on the library's own components and
   provides the shared focus ring.

   Opt a page in to full base styling with <body class="r3">.
   ============================================================================= */

@layer base {

  /* Scoped box-sizing — never touches elements the library doesn't own. */
  .btn, .btn::before, .btn::after,
  .panel, .panel *,
  .modal, .modal *,
  .table, .table *,
  .nav, .nav * {
    box-sizing: border-box;
  }

  /* The one shared focus ring. Every interactive component uses it, so keyboard
     focus is consistent and visible in both themes. :focus-visible means mouse
     users don't see it, keyboard users always do. */
  .btn:focus-visible,
  .nav-link:focus-visible,
  .nav-item:focus-visible,
  .table a:focus-visible,
  .modal-close:focus-visible,
  .theme-toggle:focus-visible {
    outline: var(--r3-focus-width) solid var(--r3-focus);
    outline-offset: var(--r3-focus-offset);
    border-radius: var(--r3-radius-sm);
  }

  /* Opt-in page base. */
  body.r3 {
    margin: 0;
    background: var(--r3-bg);
    color: var(--r3-text);
    font-family: var(--r3-font-ui);
    font-size: var(--r3-text-base);
    line-height: var(--r3-leading-normal);
    -webkit-font-smoothing: antialiased;
  }

  body.r3 ::placeholder { color: var(--r3-text-subtle); }

  /* Custom scrollbar, matching the editor's existing .dark-scroll treatment but
     theme-aware. */
  body.r3 * {
    scrollbar-width: thin;
    scrollbar-color: var(--r3-border-strong) transparent;
  }

  /* Respect the user's OS-level motion preference. */
  @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;
    }
  }

  /* Screen-reader-only text. Use on icon buttons when you'd rather not use
     aria-label, and for table captions. */
  .sr-only {
    position: absolute;
    width: 1px; height: 1px;
    padding: 0; margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
  }
}

/* =============================================================================
   UTILITIES
   Tailwind-like, but only the ones this codebase actually reaches for. They sit
   in the last layer so a utility always beats a component rule — that's the
   point of a utility.

   Utilities are for LAYOUT (flex, gap, spacing) and small text tweaks. If you
   find yourself stacking six utilities to rebuild a component, the component is
   missing — add it to the library instead.
   ============================================================================= */

@layer utilities {

  /* -- Display ------------------------------------------------------------- */
  .block        { display: block; }
  .inline-block { display: inline-block; }
  .inline       { display: inline; }
  .flex         { display: flex; }
  .inline-flex  { display: inline-flex; }
  .grid         { display: grid; }
  .hidden       { display: none; }

  /* -- Flex / grid --------------------------------------------------------- */
  .flex-row     { flex-direction: row; }
  .flex-col     { flex-direction: column; }
  .flex-wrap    { flex-wrap: wrap; }
  .flex-1       { flex: 1 1 0%; }
  .flex-none    { flex: none; }
  .grow         { flex-grow: 1; }
  .shrink-0     { flex-shrink: 0; }

  .items-start   { align-items: flex-start; }
  .items-center  { align-items: center; }
  .items-end     { align-items: flex-end; }
  .items-stretch { align-items: stretch; }

  .justify-start   { justify-content: flex-start; }
  .justify-center  { justify-content: center; }
  .justify-end     { justify-content: flex-end; }
  .justify-between { justify-content: space-between; }

  /* -- Gap (spacing scale) -------------------------------------------------- */
  .gap-0 { gap: var(--r3-space-0); }
  .gap-1 { gap: var(--r3-space-1); }
  .gap-2 { gap: var(--r3-space-2); }
  .gap-3 { gap: var(--r3-space-3); }
  .gap-4 { gap: var(--r3-space-4); }
  .gap-5 { gap: var(--r3-space-5); }
  .gap-6 { gap: var(--r3-space-6); }

  /* -- Margin / padding ------------------------------------------------------ */
  .m-0 { margin: var(--r3-space-0); }
  .m-1 { margin: var(--r3-space-1); }
  .m-2 { margin: var(--r3-space-2); }
  .m-3 { margin: var(--r3-space-3); }
  .m-4 { margin: var(--r3-space-4); }

  .mt-0 { margin-top: var(--r3-space-0); }
  .mt-1 { margin-top: var(--r3-space-1); }
  .mt-2 { margin-top: var(--r3-space-2); }
  .mt-3 { margin-top: var(--r3-space-3); }
  .mt-4 { margin-top: var(--r3-space-4); }
  .mt-5 { margin-top: var(--r3-space-5); }
  .mb-0 { margin-bottom: var(--r3-space-0); }
  .mb-1 { margin-bottom: var(--r3-space-1); }
  .mb-2 { margin-bottom: var(--r3-space-2); }
  .mb-3 { margin-bottom: var(--r3-space-3); }
  .mb-4 { margin-bottom: var(--r3-space-4); }
  .mb-5 { margin-bottom: var(--r3-space-5); }
  .ml-auto { margin-left: auto; }
  .mr-auto { margin-right: auto; }

  .p-0 { padding: var(--r3-space-0); }
  .p-1 { padding: var(--r3-space-1); }
  .p-2 { padding: var(--r3-space-2); }
  .p-3 { padding: var(--r3-space-3); }
  .p-4 { padding: var(--r3-space-4); }
  .p-5 { padding: var(--r3-space-5); }

  .px-2 { padding-left: var(--r3-space-2); padding-right: var(--r3-space-2); }
  .px-3 { padding-left: var(--r3-space-3); padding-right: var(--r3-space-3); }
  .px-4 { padding-left: var(--r3-space-4); padding-right: var(--r3-space-4); }
  .py-1 { padding-top: var(--r3-space-1); padding-bottom: var(--r3-space-1); }
  .py-2 { padding-top: var(--r3-space-2); padding-bottom: var(--r3-space-2); }
  .py-3 { padding-top: var(--r3-space-3); padding-bottom: var(--r3-space-3); }
  .py-4 { padding-top: var(--r3-space-4); padding-bottom: var(--r3-space-4); }

  /* -- Typography ----------------------------------------------------------- */
  .text-xs   { font-size: var(--r3-text-xs); }
  .text-sm   { font-size: var(--r3-text-sm); }
  .text-base { font-size: var(--r3-text-base); }
  .text-lg   { font-size: var(--r3-text-lg); }
  .text-xl   { font-size: var(--r3-text-xl); }
  .text-2xl  { font-size: var(--r3-text-2xl); }

  .font-normal   { font-weight: var(--r3-weight-normal); }
  .font-medium   { font-weight: var(--r3-weight-medium); }
  .font-semibold { font-weight: var(--r3-weight-semibold); }

  .font-mono { font-family: var(--r3-font-mono); }
  .font-sans { font-family: var(--r3-font-sans); }

  .text-left   { text-align: left; }
  .text-center { text-align: center; }
  .text-right  { text-align: right; }

  .uppercase  { text-transform: uppercase; letter-spacing: 0.06em; }
  .truncate   { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .whitespace-nowrap { white-space: nowrap; }

  /* Text colour — semantic roles only. There is deliberately no `.text-blue`:
     a colour utility that isn't theme-aware would break dark mode. */
  .text-default { color: var(--r3-text); }
  .text-muted   { color: var(--r3-text-muted); }
  .text-subtle  { color: var(--r3-text-subtle); }
  .text-accent  { color: var(--r3-accent-ink); }
  .text-success { color: var(--r3-success-ink); }
  .text-danger  { color: var(--r3-danger-ink); }
  .text-warning { color: var(--r3-warning-ink); }

  /* -- Surfaces ------------------------------------------------------------- */
  .bg-default { background: var(--r3-bg); }
  .bg-surface { background: var(--r3-surface); }
  .bg-sunken  { background: var(--r3-bg-sunken); }

  .border     { border: var(--r3-border-width) solid var(--r3-border); }
  .border-top { border-top: var(--r3-border-width) solid var(--r3-border); }
  .border-bottom { border-bottom: var(--r3-border-width) solid var(--r3-border); }
  .rounded-sm { border-radius: var(--r3-radius-sm); }
  .rounded    { border-radius: var(--r3-radius-md); }
  .rounded-lg { border-radius: var(--r3-radius-lg); }
  .rounded-full { border-radius: var(--r3-radius-full); }

  .shadow-sm { box-shadow: var(--r3-shadow-sm); }
  .shadow-md { box-shadow: var(--r3-shadow-md); }
  .shadow-lg { box-shadow: var(--r3-shadow-lg); }

  /* -- Sizing / overflow ----------------------------------------------------- */
  .w-full  { width: 100%; }
  .h-full  { height: 100%; }
  .max-w-full { max-width: 100%; }
  .overflow-auto   { overflow: auto; }
  .overflow-hidden { overflow: hidden; }
  .overflow-y-auto { overflow-y: auto; }

  /* -- Position -------------------------------------------------------------- */
  .relative { position: relative; }
  .absolute { position: absolute; }
  .fixed    { position: fixed; }
  .sticky   { position: sticky; }
  .inset-0  { inset: 0; }

  /* -- Interaction ----------------------------------------------------------- */
  .cursor-pointer { cursor: pointer; }
  .select-none    { user-select: none; }
  .pointer-events-none { pointer-events: none; }
}
