@energycap/internal-ui 0.1.3 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -9,6 +9,39 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
9
9
  > collected under `### Changed` / `### Removed`. Review those sections before
10
10
  > bumping across a minor (pre-1.0) or major version.
11
11
 
12
+ ## [0.1.5] - 2026-07-07
13
+
14
+ ### Added
15
+
16
+ - Modal / dialog component: `.modal` panel with `.modal-header` + `.modal-title` +
17
+ `.modal-close`, `.modal-body`, and `.modal-footer`. Recommended usage is `.modal`
18
+ on a native `<dialog>` opened with `.showModal()` (styled `::backdrop` scrim, plus
19
+ a UA-chrome reset) — the browser handles the focus trap, Esc-to-close, and page
20
+ `inert`. A `.modal-overlay` scrim is also provided as a CSS-only, no-JS fallback
21
+ (toggle with the `hidden` attribute — `.modal-overlay[hidden]` is styled out — a
22
+ server render, or a `:target` anchor); it does not trap focus. Library ships no
23
+ JavaScript.
24
+ - `--overlay` (slate-900 @ 50%) backdrop-scrim token and `--shadow-overlay`
25
+ elevation token for the modal panel.
26
+
27
+ ## [0.1.4] - 2026-07-01
28
+
29
+ ### Added
30
+
31
+ - `--hover` (indigo-200) and `--selected` (indigo-100) tokens for interactive
32
+ hover / selected fills.
33
+ - `.row-selected` table-row class — soft `--selected` fill plus a primary-colored
34
+ bar on the row's left edge (mirrors the active sidebar nav item).
35
+
36
+ ### Changed
37
+
38
+ - Table row hover is now the stronger `--hover` (indigo-200) instead of the
39
+ near-white canvas, and only applies to `.row-clickable` rows so static rows no
40
+ longer imply interactivity.
41
+ - `install-skills` now installs to `.claude/skills` (was `.agents/skills`) so Claude
42
+ Code discovers the skill; GitHub Copilot reads that directory too. Pass `--dest` to
43
+ override. If you previously installed to `.agents/skills`, you can delete the old copy.
44
+
12
45
  ## [0.1.3] - 2026-06-30
13
46
 
14
47
  ### Added
package/README.md CHANGED
@@ -38,6 +38,7 @@ color tokens are also exposed as Tailwind utilities.
38
38
  | `--primary` / `--primary-hover` | `bg-primary` / `bg-primary-hover`, `text-primary` | indigo 600 / 700 |
39
39
  | `--primary-light` | `bg-primary-light`, `border-l-primary-light` | indigo-400 (accent on dark surfaces) |
40
40
  | `--primary-soft` | — | indigo-300 (focus ring / soft fill) |
41
+ | `--hover` / `--selected` | — | indigo-200 / indigo-100 (interactive row/surface hover + selected fills) |
41
42
  | `--canvas` | `bg-canvas` | slate-50 (page background) |
42
43
  | `--surface` / `--surface-alt` | `bg-surface` / `bg-surface-alt` | white / slate-100 |
43
44
  | `--border` / `--border-strong` | `border-border` / `border-border-strong` | slate-200 / slate-400 |
@@ -48,8 +49,10 @@ color tokens are also exposed as Tailwind utilities.
48
49
  | `--success` / `--warning` / `--danger` / `--info` | `text-*` / `bg-*` | green-600 / amber-600 / red-600 / blue-500 |
49
50
  | `--danger-hover` | `bg-danger-hover` | red-700 (solid danger button hover) |
50
51
  | `--{success,warning,danger,info}-bg` / `-text` | — | soft fill + readable text for alerts/badges |
52
+ | `--overlay` | — | slate-900 @ 50% (modal backdrop scrim) |
51
53
  | `--radius-sm/md/lg` | `rounded-sm/md/lg` | 4 / 6 / 8 px (match Tailwind defaults) |
52
54
  | `--shadow-card` | — | card / panel elevation |
55
+ | `--shadow-overlay` | — | modal / dialog elevation |
53
56
  | `--font-sans` / `--font-mono` | `font-sans` / `font-mono` | Inter / Cascadia Code |
54
57
 
55
58
  ## Component classes
@@ -59,10 +62,11 @@ color tokens are also exposed as Tailwind utilities.
59
62
  | Buttons | `.btn` + `.btn-primary` / `.btn-outline` / `.btn-danger`, `.btn-sm`, `.btn-icon-only`, `.btn-group` |
60
63
  | Forms | `.form-group` (`> label`), `.form-control` (input/select/textarea), `.form-hint`, `.form-actions` |
61
64
  | Cards | `.card`, `.card-heading` |
62
- | Tables | `.table-container` (+ `.table-sticky`) wrapping a `<table>`; `.table-empty`; `.row-clickable` + `.row-anchor` |
65
+ | Tables | `.table-container` (+ `.table-sticky`) wrapping a `<table>`; `.table-empty`; `.row-clickable` + `.row-anchor`; `.row-selected` |
63
66
  | Badges | `.badge` + `.badge-success/warning/danger/info/muted` |
64
67
  | Alerts | `.alert` + `.alert-success/warning/error/info` (`.alert-danger` alias) |
65
68
  | Layout | `.app-shell`, `.sidebar` (`.sidebar-brand/-nav/-footer`, `a.active`, `.nav-section`), `.main-content`, `.content-header`, `.subtitle`, `.toolbar`, `.pagination` |
69
+ | Modal | `.modal` (panel) — on a native `<dialog>` (`::backdrop` scrim, recommended) or inside a `.modal-overlay` scrim (no-JS fallback); `.modal-header` + `.modal-title` + `.modal-close`; `.modal-body`; `.modal-footer` |
66
70
 
67
71
  See the kitchen-sink docs site (`apps/docs`) for live examples of every token
68
72
  and component.
@@ -70,7 +74,7 @@ and component.
70
74
  ## Agent skills
71
75
 
72
76
  ```bash
73
- npx @energycap/internal-ui install-skills # -> ./.agents/skills
77
+ npx @energycap/internal-ui install-skills # -> ./.claude/skills
74
78
  ```
75
79
 
76
80
  ## Build
package/bin/cli.mjs CHANGED
@@ -1,7 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  /* @energycap/internal-ui CLI — currently just installs the bundled agent skills
3
- (shipped under the package's src/skills) into a consuming repo's agent-agnostic
4
- .agents/skills directory. */
3
+ (shipped under the package's src/skills) into a consuming repo's .claude/skills
4
+ directory. .claude/skills is read by both Claude Code and GitHub Copilot, so it's
5
+ the cross-agent target; pass --dest to install somewhere else. */
5
6
  import { cp, mkdir, readdir } from 'node:fs/promises';
6
7
  import { existsSync } from 'node:fs';
7
8
  import { dirname, join, resolve } from 'node:path';
@@ -26,7 +27,7 @@ function parseFlags(args) {
26
27
  async function installSkills(args) {
27
28
  const flags = parseFlags(args);
28
29
  const src = join(PKG_ROOT, 'src', 'skills');
29
- const dest = resolve(process.cwd(), flags.dest || '.agents/skills');
30
+ const dest = resolve(process.cwd(), flags.dest || '.claude/skills');
30
31
 
31
32
  if (!existsSync(src)) {
32
33
  console.error(`[internal-ui] no skills bundled in this package (looked in ${src}).`);
@@ -59,7 +60,8 @@ Usage:
59
60
  npx @energycap/internal-ui install-skills [--dest=<dir>] [--force]
60
61
 
61
62
  Commands:
62
- install-skills Copy the bundled agent skills into <dir> (default: .agents/skills)
63
+ install-skills Copy the bundled agent skills into <dir> (default: .claude/skills,
64
+ which both Claude Code and GitHub Copilot read)
63
65
  `);
64
66
  }
65
67
 
@@ -1,2 +1,2 @@
1
1
  /*! tailwindcss v4.3.2 | MIT License | https://tailwindcss.com */
2
- @layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-outline-style:solid}}}@layer theme{:root,:host{--font-sans:"Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;--font-mono:"Cascadia Code", "Fira Code", "Consolas", monospace;--color-red-100:oklch(93.6% .032 17.717);--color-red-600:oklch(57.7% .245 27.325);--color-red-700:oklch(50.5% .213 27.518);--color-amber-600:oklch(66.6% .179 58.318);--color-yellow-100:oklch(97.3% .071 103.193);--color-yellow-700:oklch(55.4% .135 66.442);--color-green-100:oklch(96.2% .044 156.743);--color-green-600:oklch(62.7% .194 149.214);--color-green-700:oklch(52.7% .154 150.069);--color-blue-100:oklch(93.2% .032 255.585);--color-blue-500:oklch(62.3% .214 259.815);--color-blue-600:oklch(54.6% .245 262.881);--color-indigo-300:oklch(78.5% .115 274.713);--color-indigo-400:oklch(67.3% .182 276.935);--color-indigo-600:oklch(51.1% .262 276.966);--color-indigo-700:oklch(45.7% .24 277.023);--color-slate-50:oklch(98.4% .003 247.858);--color-slate-100:oklch(96.8% .007 247.896);--color-slate-200:oklch(92.9% .013 255.508);--color-slate-300:oklch(86.9% .022 252.894);--color-slate-400:oklch(70.4% .04 256.788);--color-slate-500:oklch(55.4% .046 257.417);--color-slate-600:oklch(44.6% .043 257.281);--color-slate-800:oklch(27.9% .041 260.031);--color-slate-900:oklch(20.8% .042 265.755);--color-white:#fff;--spacing:.25rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-xl:1.25rem;--text-xl--line-height:calc(1.75 / 1.25);--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--tracking-wide:.025em;--tracking-wider:.05em;--leading-snug:1.375;--leading-normal:1.5;--leading-relaxed:1.625;--radius-md:.375rem;--radius-lg:.5rem;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}body{font-family:var(--font-sans,"Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif);color:var(--ink);background:var(--canvas);-webkit-font-smoothing:antialiased;line-height:1.5}ol{padding-left:1.5em;list-style:decimal}ul{padding-left:1.5em;list-style:outside}:focus:not(:focus-visible){outline:none}:focus-visible{outline:2px solid var(--primary);outline-offset:2px;border-radius:3px}}@layer components{.btn{cursor:pointer;justify-content:center;align-items:center;gap:calc(var(--spacing) * 1.5);border-radius:var(--radius-md);border-style:var(--tw-border-style);padding-inline:calc(var(--spacing) * 3.5);padding-block:calc(var(--spacing) * 1.5);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-leading:var(--leading-normal);line-height:var(--leading-normal);--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);color:var(--color-white);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));border-width:1px;border-color:#0000;text-decoration-line:none;display:inline-flex}.btn:hover{color:var(--color-white);text-decoration-line:none}.btn:disabled{cursor:not-allowed;opacity:.6}.btn:focus-visible{--tw-outline-style:none;box-shadow:0 0 0 3px var(--primary-soft);outline-style:none}.btn-primary{background-color:var(--primary)}.btn-primary:hover{background-color:var(--primary-hover)}.btn-danger{background-color:var(--danger)}.btn-danger:hover{background-color:var(--danger-hover)}.btn-primary:focus-visible,.btn-danger:focus-visible{border-color:var(--color-white)}.btn-outline{border-style:var(--tw-border-style);border-width:1px;border-color:var(--border);background-color:var(--surface);color:var(--ink)}.btn-outline:hover{border-color:var(--border-strong);background-color:var(--canvas);color:var(--ink)}.btn-outline:focus-visible{border-color:var(--primary)}.btn-sm{padding-inline:calc(var(--spacing) * 2.5);padding-block:var(--spacing);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.btn-icon-only{height:calc(var(--spacing) * 8);width:calc(var(--spacing) * 8);padding:0}.btn-group{align-items:center;gap:calc(var(--spacing) * 1.5);display:inline-flex}.form-group{margin-bottom:calc(var(--spacing) * 5)}.form-group>label{margin-bottom:calc(var(--spacing) * 1.5);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);color:var(--ink);display:block}.form-control{border-radius:var(--radius-md);border-style:var(--tw-border-style);border-width:1px;border-color:var(--border);background-color:var(--surface);width:100%;padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 2);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));color:var(--ink);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));font-family:inherit}.form-control::placeholder{color:var(--border-strong)}.form-control:focus{border-color:var(--primary);--tw-outline-style:none;box-shadow:0 0 0 3px var(--primary-soft);outline-style:none}textarea.form-control{min-height:calc(var(--spacing) * 30);resize:vertical;font-family:var(--font-mono);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed)}select.form-control{cursor:pointer;appearance:none;padding-right:calc(var(--spacing) * 9);--tw-leading:var(--leading-snug);line-height:var(--leading-snug);background-image:linear-gradient(45deg, transparent 50%, var(--border-strong) 50%), linear-gradient(135deg, var(--border-strong) 50%, transparent 50%);background-position:right 16px center,right 11px center;background-repeat:no-repeat;background-size:5px 5px,5px 5px}.form-hint{margin-top:var(--spacing);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));color:var(--muted)}.form-actions{margin-top:calc(var(--spacing) * 6);gap:calc(var(--spacing) * 2.5);border-top-style:var(--tw-border-style);border-top-width:1px;border-color:var(--border);padding-top:calc(var(--spacing) * 4);display:flex}.card{border-radius:var(--radius-lg);border-style:var(--tw-border-style);border-width:1px;border-color:var(--border);background-color:var(--surface);padding-inline:calc(var(--spacing) * 6);padding-block:calc(var(--spacing) * 5);box-shadow:var(--shadow-card)}.card-heading{margin-bottom:calc(var(--spacing) * 4);align-items:center;gap:calc(var(--spacing) * 2);border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:var(--border);padding-bottom:calc(var(--spacing) * 2.5);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);color:var(--ink-soft);display:flex}.card-heading i{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));color:var(--muted)}.table-container{border-radius:var(--radius-lg);border-style:var(--tw-border-style);border-width:1px;border-color:var(--border);background-color:var(--surface);max-width:100%;box-shadow:var(--shadow-card);overflow:auto}.table-container table{border-collapse:collapse;width:100%}.table-container thead th{border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:var(--border);background-color:var(--surface-alt);padding-inline:calc(var(--spacing) * 4);padding-block:calc(var(--spacing) * 2.5);text-align:left;font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);--tw-tracking:var(--tracking-wide);letter-spacing:var(--tracking-wide);color:var(--muted);text-transform:uppercase}.table-container tbody td{border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:var(--border);padding-inline:calc(var(--spacing) * 4);padding-block:calc(var(--spacing) * 2.5);vertical-align:middle;font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.table-container tbody tr:last-child td{border-bottom-style:var(--tw-border-style);border-bottom-width:0}.table-container tbody tr:hover{background-color:var(--canvas)}.table-container tfoot td{border-top-style:var(--tw-border-style);border-top-width:2px;border-color:var(--border);background-color:var(--canvas);padding-inline:calc(var(--spacing) * 4);padding-block:calc(var(--spacing) * 2.5);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);color:var(--ink-soft)}.table-empty{padding-inline:calc(var(--spacing) * 4);padding-block:calc(var(--spacing) * 10);text-align:center;color:var(--muted)}.table-sticky thead th{z-index:2;background-color:var(--surface-alt);box-shadow:inset 0 -1px 0 var(--border);position:sticky;top:0}.row-clickable{cursor:pointer;position:relative}.row-clickable:focus-within{background-color:var(--canvas)}.row-anchor{z-index:1;text-indent:-9999px;color:inherit;position:absolute;inset:0;overflow:hidden}.row-anchor:focus-visible{outline-style:var(--tw-outline-style);outline-width:2px;outline-color:var(--primary);outline-offset:-2px;border-radius:2px}.badge{align-items:center;gap:var(--spacing);padding-inline:calc(var(--spacing) * 2);padding-block:calc(var(--spacing) * .5);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);white-space:nowrap;border-radius:3.40282e38px;display:inline-flex}.badge-success{background:var(--success-bg);color:var(--success-text)}.badge-warning{background:var(--warning-bg);color:var(--warning-text)}.badge-danger{background:var(--danger-bg);color:var(--danger-text)}.badge-info{background:var(--info-bg);color:var(--info-text)}.badge-muted{background-color:var(--surface-alt);color:var(--muted-strong)}.alert{margin-bottom:calc(var(--spacing) * 4);align-items:center;gap:calc(var(--spacing) * 2);border-radius:var(--radius-md);padding-inline:calc(var(--spacing) * 3.5);padding-block:calc(var(--spacing) * 2.5);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);display:flex}.alert-success{border-style:var(--tw-border-style);border-width:1px;border-color:var(--success);background:var(--success-bg);color:var(--success-text)}.alert-warning{border-style:var(--tw-border-style);border-width:1px;border-color:var(--warning);background:var(--warning-bg);color:var(--warning-text)}.alert-error,.alert-danger{border-style:var(--tw-border-style);border-width:1px;border-color:var(--danger);background:var(--danger-bg);color:var(--danger-text)}.alert-info{border-style:var(--tw-border-style);border-width:1px;border-color:var(--info);background:var(--info-bg);color:var(--info-text)}.app-shell{height:100dvh;display:flex;overflow:hidden}.sidebar{width:calc(var(--spacing) * 55);background-color:var(--ink);flex-direction:column;flex-shrink:0;display:flex}.sidebar-brand{align-items:center;gap:calc(var(--spacing) * 2.5);border-bottom-style:var(--tw-border-style);border-color:#ffffff1a;border-bottom-width:1px;display:flex}@supports (color:color-mix(in lab, red, red)){.sidebar-brand{border-color:color-mix(in oklab, var(--color-white) 10%, transparent)}}.sidebar-brand{padding-inline:calc(var(--spacing) * 4.5);padding-block:calc(var(--spacing) * 4);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold);--tw-tracking:var(--tracking-wide);letter-spacing:var(--tracking-wide);color:var(--on-dark)}.sidebar>nav{flex-direction:column;flex:1;min-height:0;display:flex}.sidebar-nav{padding-inline:0;padding-block:calc(var(--spacing) * 2);flex:1;margin:0;list-style-type:none;overflow-y:auto}.sidebar-nav .nav-section{padding-inline:calc(var(--spacing) * 4.5);padding-top:calc(var(--spacing) * 4);padding-bottom:calc(var(--spacing) * 1.5);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);--tw-tracking:var(--tracking-wider);letter-spacing:var(--tracking-wider);color:var(--on-dark-muted);text-transform:uppercase}.sidebar-nav a{align-items:center;gap:calc(var(--spacing) * 2.5);border-left-style:var(--tw-border-style);padding-inline:calc(var(--spacing) * 4.5);padding-block:calc(var(--spacing) * 2);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);color:var(--on-dark-soft);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));border-color:#0000;border-left-width:3px;text-decoration-line:none;display:flex}.sidebar-nav a:hover{background-color:#ffffff0f}@supports (color:color-mix(in lab, red, red)){.sidebar-nav a:hover{background-color:color-mix(in oklab, var(--color-white) 6%, transparent)}}.sidebar-nav a:hover{color:var(--on-dark)}.sidebar-nav a.active{background-color:#ffffff0f}@supports (color:color-mix(in lab, red, red)){.sidebar-nav a.active{background-color:color-mix(in oklab, var(--color-white) 6%, transparent)}}.sidebar-nav a.active{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);color:var(--on-dark);border-left-color:var(--primary-light)}.sidebar-nav .nav-icon{width:calc(var(--spacing) * 4.5);opacity:.6;flex-shrink:0}.sidebar-footer{border-top-style:var(--tw-border-style);border-color:#ffffff1a;border-top-width:1px}@supports (color:color-mix(in lab, red, red)){.sidebar-footer{border-color:color-mix(in oklab, var(--color-white) 10%, transparent)}}.sidebar-footer{padding-inline:calc(var(--spacing) * 4.5);padding-block:calc(var(--spacing) * 3);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));color:var(--on-dark-muted)}.sidebar-footer a{color:var(--on-dark-muted-strong);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));text-decoration-line:none}.sidebar-footer a:hover{color:var(--on-dark)}.main-content{background-color:var(--canvas);min-width:0;padding-inline:calc(var(--spacing) * 8);padding-block:calc(var(--spacing) * 6);flex:1;overflow-y:auto}.content-header{margin-bottom:calc(var(--spacing) * 6)}.content-header h1{font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height));--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);color:var(--ink)}.subtitle{margin-top:calc(var(--spacing) * .5);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));color:var(--muted)}.toolbar{margin-bottom:calc(var(--spacing) * 4);justify-content:space-between;align-items:center;gap:calc(var(--spacing) * 3);display:flex}.toolbar-spacer{flex:1}.pagination{margin-top:calc(var(--spacing) * 4);justify-content:space-between;align-items:center;gap:calc(var(--spacing) * 3);flex-wrap:wrap;display:flex}.pagination-summary{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));color:var(--muted)}.pagination-summary strong{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);color:var(--ink)}.pagination-controls{align-items:center;gap:calc(var(--spacing) * 1.5);flex-wrap:wrap;display:flex}.pagination-disabled{cursor:not-allowed;opacity:.4}}@layer utilities;:root{--primary:var(--color-indigo-600);--primary-hover:var(--color-indigo-700);--primary-light:var(--color-indigo-400);--primary-soft:var(--color-indigo-300);--canvas:var(--color-slate-50);--surface:var(--color-white);--surface-alt:var(--color-slate-100);--border:var(--color-slate-200);--border-strong:var(--color-slate-400);--ink:var(--color-slate-900);--ink-soft:var(--color-slate-800);--muted:var(--color-slate-500);--muted-strong:var(--color-slate-600);--on-dark:var(--color-slate-100);--on-dark-soft:var(--color-slate-300);--on-dark-muted-strong:var(--color-slate-400);--on-dark-muted:var(--color-slate-500);--success:var(--color-green-600);--warning:var(--color-amber-600);--danger:var(--color-red-600);--danger-hover:var(--color-red-700);--info:var(--color-blue-500);--success-bg:var(--color-green-100);--success-text:var(--color-green-700);--warning-bg:var(--color-yellow-100);--warning-text:var(--color-yellow-700);--danger-bg:var(--color-red-100);--danger-text:var(--color-red-700);--info-bg:var(--color-blue-100);--info-text:var(--color-blue-600);--radius-sm:4px;--radius-md:6px;--radius-lg:8px;--shadow-card:0 1px 3px #0f172a0f, 0 0 0 1px #0f172a08}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-outline-style{syntax:"*";inherits:false;initial-value:solid}
2
+ @layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-outline-style:solid}}}@layer theme{:root,:host{--font-sans:"Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;--font-mono:"Cascadia Code", "Fira Code", "Consolas", monospace;--color-red-100:oklch(93.6% .032 17.717);--color-red-600:oklch(57.7% .245 27.325);--color-red-700:oklch(50.5% .213 27.518);--color-amber-600:oklch(66.6% .179 58.318);--color-yellow-100:oklch(97.3% .071 103.193);--color-yellow-700:oklch(55.4% .135 66.442);--color-green-100:oklch(96.2% .044 156.743);--color-green-600:oklch(62.7% .194 149.214);--color-green-700:oklch(52.7% .154 150.069);--color-blue-100:oklch(93.2% .032 255.585);--color-blue-500:oklch(62.3% .214 259.815);--color-blue-600:oklch(54.6% .245 262.881);--color-indigo-100:oklch(93% .034 272.788);--color-indigo-200:oklch(87% .065 274.039);--color-indigo-300:oklch(78.5% .115 274.713);--color-indigo-400:oklch(67.3% .182 276.935);--color-indigo-600:oklch(51.1% .262 276.966);--color-indigo-700:oklch(45.7% .24 277.023);--color-slate-50:oklch(98.4% .003 247.858);--color-slate-100:oklch(96.8% .007 247.896);--color-slate-200:oklch(92.9% .013 255.508);--color-slate-300:oklch(86.9% .022 252.894);--color-slate-400:oklch(70.4% .04 256.788);--color-slate-500:oklch(55.4% .046 257.417);--color-slate-600:oklch(44.6% .043 257.281);--color-slate-800:oklch(27.9% .041 260.031);--color-slate-900:oklch(20.8% .042 265.755);--color-white:#fff;--spacing:.25rem;--container-lg:32rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-base:1rem;--text-base--line-height:calc(1.5 / 1);--text-xl:1.25rem;--text-xl--line-height:calc(1.75 / 1.25);--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--tracking-wide:.025em;--tracking-wider:.05em;--leading-snug:1.375;--leading-normal:1.5;--leading-relaxed:1.625;--radius-md:.375rem;--radius-lg:.5rem;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}body{font-family:var(--font-sans,"Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif);color:var(--ink);background:var(--canvas);-webkit-font-smoothing:antialiased;line-height:1.5}ol{padding-left:1.5em;list-style:decimal}ul{padding-left:1.5em;list-style:outside}:focus:not(:focus-visible){outline:none}:focus-visible{outline:2px solid var(--primary);outline-offset:2px;border-radius:3px}}@layer components{.btn{cursor:pointer;justify-content:center;align-items:center;gap:calc(var(--spacing) * 1.5);border-radius:var(--radius-md);border-style:var(--tw-border-style);padding-inline:calc(var(--spacing) * 3.5);padding-block:calc(var(--spacing) * 1.5);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-leading:var(--leading-normal);line-height:var(--leading-normal);--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);color:var(--color-white);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));border-width:1px;border-color:#0000;text-decoration-line:none;display:inline-flex}.btn:hover{color:var(--color-white);text-decoration-line:none}.btn:disabled{cursor:not-allowed;opacity:.6}.btn:focus-visible{--tw-outline-style:none;box-shadow:0 0 0 3px var(--primary-soft);outline-style:none}.btn-primary{background-color:var(--primary)}.btn-primary:hover{background-color:var(--primary-hover)}.btn-danger{background-color:var(--danger)}.btn-danger:hover{background-color:var(--danger-hover)}.btn-primary:focus-visible,.btn-danger:focus-visible{border-color:var(--color-white)}.btn-outline{border-style:var(--tw-border-style);border-width:1px;border-color:var(--border);background-color:var(--surface);color:var(--ink)}.btn-outline:hover{border-color:var(--border-strong);background-color:var(--canvas);color:var(--ink)}.btn-outline:focus-visible{border-color:var(--primary)}.btn-sm{padding-inline:calc(var(--spacing) * 2.5);padding-block:var(--spacing);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.btn-icon-only{height:calc(var(--spacing) * 8);width:calc(var(--spacing) * 8);padding:0}.btn-group{align-items:center;gap:calc(var(--spacing) * 1.5);display:inline-flex}.form-group{margin-bottom:calc(var(--spacing) * 5)}.form-group>label{margin-bottom:calc(var(--spacing) * 1.5);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);color:var(--ink);display:block}.form-control{border-radius:var(--radius-md);border-style:var(--tw-border-style);border-width:1px;border-color:var(--border);background-color:var(--surface);width:100%;padding-inline:calc(var(--spacing) * 3);padding-block:calc(var(--spacing) * 2);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));color:var(--ink);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));font-family:inherit}.form-control::placeholder{color:var(--border-strong)}.form-control:focus{border-color:var(--primary);--tw-outline-style:none;box-shadow:0 0 0 3px var(--primary-soft);outline-style:none}textarea.form-control{min-height:calc(var(--spacing) * 30);resize:vertical;font-family:var(--font-mono);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed)}select.form-control{cursor:pointer;appearance:none;padding-right:calc(var(--spacing) * 9);--tw-leading:var(--leading-snug);line-height:var(--leading-snug);background-image:linear-gradient(45deg, transparent 50%, var(--border-strong) 50%), linear-gradient(135deg, var(--border-strong) 50%, transparent 50%);background-position:right 16px center,right 11px center;background-repeat:no-repeat;background-size:5px 5px,5px 5px}.form-hint{margin-top:var(--spacing);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));color:var(--muted)}.form-actions{margin-top:calc(var(--spacing) * 6);gap:calc(var(--spacing) * 2.5);border-top-style:var(--tw-border-style);border-top-width:1px;border-color:var(--border);padding-top:calc(var(--spacing) * 4);display:flex}.card{border-radius:var(--radius-lg);border-style:var(--tw-border-style);border-width:1px;border-color:var(--border);background-color:var(--surface);padding-inline:calc(var(--spacing) * 6);padding-block:calc(var(--spacing) * 5);box-shadow:var(--shadow-card)}.card-heading{margin-bottom:calc(var(--spacing) * 4);align-items:center;gap:calc(var(--spacing) * 2);border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:var(--border);padding-bottom:calc(var(--spacing) * 2.5);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);color:var(--ink-soft);display:flex}.card-heading i{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));color:var(--muted)}.table-container{border-radius:var(--radius-lg);border-style:var(--tw-border-style);border-width:1px;border-color:var(--border);background-color:var(--surface);max-width:100%;box-shadow:var(--shadow-card);overflow:auto}.table-container table{border-collapse:collapse;width:100%}.table-container thead th{border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:var(--border);background-color:var(--surface-alt);padding-inline:calc(var(--spacing) * 4);padding-block:calc(var(--spacing) * 2.5);text-align:left;font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);--tw-tracking:var(--tracking-wide);letter-spacing:var(--tracking-wide);color:var(--muted);text-transform:uppercase}.table-container tbody td{border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:var(--border);padding-inline:calc(var(--spacing) * 4);padding-block:calc(var(--spacing) * 2.5);vertical-align:middle;font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.table-container tbody tr:last-child td{border-bottom-style:var(--tw-border-style);border-bottom-width:0}.table-container tbody tr.row-selected{background:var(--selected)}.table-container tbody tr.row-selected td:first-child{box-shadow:inset 3px 0 0 var(--primary)}.table-container tbody tr.row-clickable:hover{background:var(--hover)}.table-container tfoot td{border-top-style:var(--tw-border-style);border-top-width:2px;border-color:var(--border);background-color:var(--canvas);padding-inline:calc(var(--spacing) * 4);padding-block:calc(var(--spacing) * 2.5);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);color:var(--ink-soft)}.table-empty{padding-inline:calc(var(--spacing) * 4);padding-block:calc(var(--spacing) * 10);text-align:center;color:var(--muted)}.table-sticky thead th{z-index:2;background-color:var(--surface-alt);box-shadow:inset 0 -1px 0 var(--border);position:sticky;top:0}.row-clickable{cursor:pointer;position:relative}.row-clickable:focus-within{background-color:var(--canvas)}.row-anchor{z-index:1;text-indent:-9999px;color:inherit;position:absolute;inset:0;overflow:hidden}.row-anchor:focus-visible{outline-style:var(--tw-outline-style);outline-width:2px;outline-color:var(--primary);outline-offset:-2px;border-radius:2px}.badge{align-items:center;gap:var(--spacing);padding-inline:calc(var(--spacing) * 2);padding-block:calc(var(--spacing) * .5);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);white-space:nowrap;border-radius:3.40282e38px;display:inline-flex}.badge-success{background:var(--success-bg);color:var(--success-text)}.badge-warning{background:var(--warning-bg);color:var(--warning-text)}.badge-danger{background:var(--danger-bg);color:var(--danger-text)}.badge-info{background:var(--info-bg);color:var(--info-text)}.badge-muted{background-color:var(--surface-alt);color:var(--muted-strong)}.alert{margin-bottom:calc(var(--spacing) * 4);align-items:center;gap:calc(var(--spacing) * 2);border-radius:var(--radius-md);padding-inline:calc(var(--spacing) * 3.5);padding-block:calc(var(--spacing) * 2.5);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);display:flex}.alert-success{border-style:var(--tw-border-style);border-width:1px;border-color:var(--success);background:var(--success-bg);color:var(--success-text)}.alert-warning{border-style:var(--tw-border-style);border-width:1px;border-color:var(--warning);background:var(--warning-bg);color:var(--warning-text)}.alert-error,.alert-danger{border-style:var(--tw-border-style);border-width:1px;border-color:var(--danger);background:var(--danger-bg);color:var(--danger-text)}.alert-info{border-style:var(--tw-border-style);border-width:1px;border-color:var(--info);background:var(--info-bg);color:var(--info-text)}.app-shell{height:100dvh;display:flex;overflow:hidden}.sidebar{width:calc(var(--spacing) * 55);background-color:var(--ink);flex-direction:column;flex-shrink:0;display:flex}.sidebar-brand{align-items:center;gap:calc(var(--spacing) * 2.5);border-bottom-style:var(--tw-border-style);border-color:#ffffff1a;border-bottom-width:1px;display:flex}@supports (color:color-mix(in lab, red, red)){.sidebar-brand{border-color:color-mix(in oklab, var(--color-white) 10%, transparent)}}.sidebar-brand{padding-inline:calc(var(--spacing) * 4.5);padding-block:calc(var(--spacing) * 4);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold);--tw-tracking:var(--tracking-wide);letter-spacing:var(--tracking-wide);color:var(--on-dark)}.sidebar>nav{flex-direction:column;flex:1;min-height:0;display:flex}.sidebar-nav{padding-inline:0;padding-block:calc(var(--spacing) * 2);flex:1;margin:0;list-style-type:none;overflow-y:auto}.sidebar-nav .nav-section{padding-inline:calc(var(--spacing) * 4.5);padding-top:calc(var(--spacing) * 4);padding-bottom:calc(var(--spacing) * 1.5);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);--tw-tracking:var(--tracking-wider);letter-spacing:var(--tracking-wider);color:var(--on-dark-muted);text-transform:uppercase}.sidebar-nav a{align-items:center;gap:calc(var(--spacing) * 2.5);border-left-style:var(--tw-border-style);padding-inline:calc(var(--spacing) * 4.5);padding-block:calc(var(--spacing) * 2);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);color:var(--on-dark-soft);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));border-color:#0000;border-left-width:3px;text-decoration-line:none;display:flex}.sidebar-nav a:hover{background-color:#ffffff0f}@supports (color:color-mix(in lab, red, red)){.sidebar-nav a:hover{background-color:color-mix(in oklab, var(--color-white) 6%, transparent)}}.sidebar-nav a:hover{color:var(--on-dark)}.sidebar-nav a.active{background-color:#ffffff0f}@supports (color:color-mix(in lab, red, red)){.sidebar-nav a.active{background-color:color-mix(in oklab, var(--color-white) 6%, transparent)}}.sidebar-nav a.active{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);color:var(--on-dark);border-left-color:var(--primary-light)}.sidebar-nav .nav-icon{width:calc(var(--spacing) * 4.5);opacity:.6;flex-shrink:0}.sidebar-footer{border-top-style:var(--tw-border-style);border-color:#ffffff1a;border-top-width:1px}@supports (color:color-mix(in lab, red, red)){.sidebar-footer{border-color:color-mix(in oklab, var(--color-white) 10%, transparent)}}.sidebar-footer{padding-inline:calc(var(--spacing) * 4.5);padding-block:calc(var(--spacing) * 3);font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height));color:var(--on-dark-muted)}.sidebar-footer a{color:var(--on-dark-muted-strong);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));text-decoration-line:none}.sidebar-footer a:hover{color:var(--on-dark)}.main-content{background-color:var(--canvas);min-width:0;padding-inline:calc(var(--spacing) * 8);padding-block:calc(var(--spacing) * 6);flex:1;overflow-y:auto}.content-header{margin-bottom:calc(var(--spacing) * 6)}.content-header h1{font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height));--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);color:var(--ink)}.subtitle{margin-top:calc(var(--spacing) * .5);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));color:var(--muted)}.toolbar{margin-bottom:calc(var(--spacing) * 4);justify-content:space-between;align-items:center;gap:calc(var(--spacing) * 3);display:flex}.toolbar-spacer{flex:1}.pagination{margin-top:calc(var(--spacing) * 4);justify-content:space-between;align-items:center;gap:calc(var(--spacing) * 3);flex-wrap:wrap;display:flex}.pagination-summary{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));color:var(--muted)}.pagination-summary strong{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);color:var(--ink)}.pagination-controls{align-items:center;gap:calc(var(--spacing) * 1.5);flex-wrap:wrap;display:flex}.pagination-disabled{cursor:not-allowed;opacity:.4}.modal-overlay{z-index:50;padding:calc(var(--spacing) * 4);background:var(--overlay);justify-content:center;align-items:center;display:flex;position:fixed;inset:0}.modal-overlay[hidden]{display:none}.modal{width:100%;max-height:calc(100dvh - 2rem);max-width:var(--container-lg);border-radius:var(--radius-lg);border-style:var(--tw-border-style);border-width:1px;border-color:var(--border);background-color:var(--surface);box-shadow:var(--shadow-overlay);flex-direction:column;display:flex;overflow:hidden}dialog.modal{max-width:min(var(--container-lg), calc(100vw - 2rem));margin:auto;padding:0}dialog.modal:not([open]){display:none}dialog.modal::backdrop{background:var(--overlay)}.modal-header{justify-content:space-between;align-items:center;gap:calc(var(--spacing) * 4);border-bottom-style:var(--tw-border-style);border-bottom-width:1px;border-color:var(--border);padding-inline:calc(var(--spacing) * 6);padding-block:calc(var(--spacing) * 4);display:flex}.modal-title{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height));--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold);color:var(--ink)}.modal-close{height:calc(var(--spacing) * 8);width:calc(var(--spacing) * 8);cursor:pointer;border-radius:var(--radius-md);border-style:var(--tw-border-style);font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height));--tw-leading:1;color:var(--muted);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration));background-color:#0000;border-width:0;justify-content:center;align-items:center;line-height:1;text-decoration-line:none;display:flex}.modal-close:hover{background-color:var(--canvas);color:var(--ink);text-decoration-line:none}.modal-close:focus-visible{color:var(--ink);--tw-outline-style:none;box-shadow:0 0 0 3px var(--primary-soft);outline-style:none}.modal-body{padding-inline:calc(var(--spacing) * 6);padding-block:calc(var(--spacing) * 5);font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height));color:var(--ink-soft);overflow-y:auto}.modal-footer{justify-content:flex-end;align-items:center;gap:calc(var(--spacing) * 2.5);border-top-style:var(--tw-border-style);border-top-width:1px;border-color:var(--border);padding-inline:calc(var(--spacing) * 6);padding-block:calc(var(--spacing) * 4);display:flex}}@layer utilities;:root{--primary:var(--color-indigo-600);--primary-hover:var(--color-indigo-700);--primary-light:var(--color-indigo-400);--primary-soft:var(--color-indigo-300);--hover:var(--color-indigo-200);--selected:var(--color-indigo-100);--canvas:var(--color-slate-50);--surface:var(--color-white);--surface-alt:var(--color-slate-100);--border:var(--color-slate-200);--border-strong:var(--color-slate-400);--ink:var(--color-slate-900);--ink-soft:var(--color-slate-800);--muted:var(--color-slate-500);--muted-strong:var(--color-slate-600);--on-dark:var(--color-slate-100);--on-dark-soft:var(--color-slate-300);--on-dark-muted-strong:var(--color-slate-400);--on-dark-muted:var(--color-slate-500);--success:var(--color-green-600);--warning:var(--color-amber-600);--danger:var(--color-red-600);--danger-hover:var(--color-red-700);--info:var(--color-blue-500);--success-bg:var(--color-green-100);--success-text:var(--color-green-700);--warning-bg:var(--color-yellow-100);--warning-text:var(--color-yellow-700);--danger-bg:var(--color-red-100);--danger-text:var(--color-red-700);--info-bg:var(--color-blue-100);--info-text:var(--color-blue-600);--overlay:#0f172a80;--radius-sm:4px;--radius-md:6px;--radius-lg:8px;--shadow-card:0 1px 3px #0f172a0f, 0 0 0 1px #0f172a08;--shadow-overlay:0 20px 25px -5px #0f172a26, 0 8px 10px -6px #0f172a1f}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-outline-style{syntax:"*";inherits:false;initial-value:solid}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@energycap/internal-ui",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "EnergyCAP internal UI — shared Tailwind v4 theme + component classes for internal tools. Framework-agnostic.",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",
@@ -0,0 +1,61 @@
1
+ @layer components {
2
+ /* Full-screen scrim that centers the panel. Ships visible when in the DOM —
3
+ the consumer controls open/close (server render, the `hidden` attribute, or a
4
+ `:target` anchor). The explicit `[hidden]` rule is needed because the base
5
+ `display: flex` would otherwise beat the UA `[hidden] { display: none }`. */
6
+ .modal-overlay {
7
+ @apply fixed inset-0 z-50 flex items-center justify-center p-4;
8
+ background: var(--overlay);
9
+ }
10
+ .modal-overlay[hidden] { @apply hidden; }
11
+
12
+ /* The centered panel — reuses the card recipe with a deeper elevation. Caps its
13
+ height and lets the body scroll instead of growing past the viewport. Works
14
+ both inside `.modal-overlay` (the no-JS scrim) and applied directly to a
15
+ native `<dialog>` opened with `.showModal()` (see below). */
16
+ .modal {
17
+ @apply flex flex-col w-full max-w-lg max-h-[calc(100dvh-2rem)] overflow-hidden
18
+ bg-surface border border-border rounded-lg;
19
+ box-shadow: var(--shadow-overlay);
20
+ }
21
+
22
+ /* Native <dialog> support — the recommended "real" modal: open it with
23
+ `.showModal()` and the browser traps focus, adds Esc-to-close, and inerts the
24
+ rest of the page. No `.modal-overlay` needed (the UA centers the dialog and
25
+ paints the scrim as `::backdrop`); here we reset the UA chrome that fights the
26
+ panel styles and keep a viewport gutter on small screens. */
27
+ dialog.modal {
28
+ /* `m-auto` restores the centering the UA gives modal dialogs — Tailwind's
29
+ Preflight resets `margin: 0` on every element, which would otherwise pin the
30
+ dialog to the top-left. `p-0` drops the UA `padding: 1em`. */
31
+ @apply p-0 m-auto;
32
+ max-width: min(var(--container-lg), calc(100vw - 2rem));
33
+ }
34
+ /* Author `.modal { display: flex }` outranks the UA `dialog:not([open])` rule,
35
+ so a closed dialog would otherwise stay visible — hide it explicitly. */
36
+ dialog.modal:not([open]) { @apply hidden; }
37
+ dialog.modal::backdrop { background: var(--overlay); }
38
+
39
+ .modal-header {
40
+ @apply flex items-center justify-between gap-4 px-6 py-4 border-b border-border;
41
+ }
42
+ .modal-title { @apply text-base font-semibold text-ink; }
43
+
44
+ /* Icon button for the × glyph. Works on <button> or <a>. */
45
+ .modal-close {
46
+ @apply flex items-center justify-center w-8 h-8 rounded-md
47
+ bg-transparent border-0 text-muted text-xl leading-none
48
+ no-underline cursor-pointer transition-colors;
49
+ }
50
+ .modal-close:hover { @apply bg-canvas text-ink no-underline; }
51
+ .modal-close:focus-visible {
52
+ @apply outline-none text-ink;
53
+ box-shadow: 0 0 0 3px var(--primary-soft);
54
+ }
55
+
56
+ .modal-body { @apply px-6 py-5 overflow-y-auto text-sm text-ink-soft; }
57
+
58
+ .modal-footer {
59
+ @apply flex items-center justify-end gap-2.5 px-6 py-4 border-t border-border;
60
+ }
61
+ }
@@ -18,7 +18,19 @@
18
18
  @apply px-4 py-2.5 text-sm align-middle border-b border-border;
19
19
  }
20
20
  .table-container tbody tr:last-child td { @apply border-b-0; }
21
- .table-container tbody tr:hover { @apply bg-canvas; }
21
+
22
+ /* Selected/active row — soft indigo fill plus a primary bar on the left edge
23
+ (mirrors .sidebar-nav a.active). box-shadow inset, not border-left: collapsed
24
+ table borders drop, same reason the sticky header uses a shadow. */
25
+ .table-container tbody tr.row-selected { background: var(--selected); }
26
+ .table-container tbody tr.row-selected td:first-child {
27
+ box-shadow: inset 3px 0 0 var(--primary);
28
+ }
29
+
30
+ /* Only clickable rows react to hover — static rows shouldn't imply interactivity.
31
+ Hovering a selected+clickable row darkens to --hover; the left bar persists
32
+ via td:first-child. */
33
+ .table-container tbody tr.row-clickable:hover { background: var(--hover); }
22
34
 
23
35
  .table-container tfoot td {
24
36
  @apply px-4 py-2.5 text-sm font-semibold text-ink-soft bg-canvas border-t-2 border-border;
package/src/index.css CHANGED
@@ -17,3 +17,4 @@
17
17
  @import "./components/badges.css";
18
18
  @import "./components/alerts.css";
19
19
  @import "./components/layout.css";
20
+ @import "./components/modal.css";
@@ -91,6 +91,71 @@ hidden).
91
91
 
92
92
  `.alert-danger` is an alias for `.alert-error`.
93
93
 
94
+ ## Modal / dialog
95
+
96
+ **Use a native `<dialog>` (recommended).** Put `.modal` on the `<dialog>`; the
97
+ `::backdrop` is the scrim (styled for you). Open it with `.showModal()` and the
98
+ browser traps focus, adds Esc-to-close, and inerts the rest of the page — the
99
+ things a modal must do that CSS alone can't. This works fine in server-rendered
100
+ apps: the server emits the markup, and a few lines of vanilla JS wire open/close.
101
+ No `aria-modal` needed — `.showModal()` conveys modality to assistive tech.
102
+
103
+ ```html
104
+ <button class="btn btn-primary" type="button" data-open-dialog="new-vendor">
105
+ New Master Vendor
106
+ </button>
107
+
108
+ <dialog id="new-vendor" class="modal" aria-labelledby="new-vendor-title">
109
+ <div class="modal-header">
110
+ <h2 id="new-vendor-title" class="modal-title">Add New Master Vendor</h2>
111
+ <button class="modal-close" type="button" data-close-dialog aria-label="Close">&times;</button>
112
+ </div>
113
+ <div class="modal-body">
114
+ <!-- form-group / content -->
115
+ </div>
116
+ <div class="modal-footer">
117
+ <button class="btn btn-outline" type="button" data-close-dialog>Cancel</button>
118
+ <button class="btn btn-primary" type="button">Create vendor</button>
119
+ </div>
120
+ </dialog>
121
+ ```
122
+
123
+ ```html
124
+ <!-- The whole script. Delegates, so it covers every dialog on the page. -->
125
+ <script>
126
+ document.querySelectorAll('[data-open-dialog]').forEach((b) =>
127
+ b.addEventListener('click', () => document.getElementById(b.dataset.openDialog)?.showModal()));
128
+ document.querySelectorAll('[data-close-dialog]').forEach((b) =>
129
+ b.addEventListener('click', () => b.closest('dialog')?.close()));
130
+ </script>
131
+ ```
132
+
133
+ **No-JS fallback.** If you truly can't run any JS, put the same `.modal` panel
134
+ inside a `.modal-overlay` scrim and toggle the overlay: the `hidden` attribute
135
+ (`.modal-overlay[hidden]` is styled out for you), a conditional server render, or a
136
+ `:target` anchor. This does **not** trap focus, so use `role="dialog"` +
137
+ `aria-labelledby` but **omit** `aria-modal` (claiming it would mislead assistive
138
+ tech). For a middle ground, mark the background content `inert` while it's open —
139
+ that removes it from the tab order and a11y tree without a full focus-trap script.
140
+
141
+ ```html
142
+ <div class="modal-overlay" hidden>
143
+ <div class="modal" role="dialog" aria-labelledby="mv-title">
144
+ <div class="modal-header">
145
+ <h2 id="mv-title" class="modal-title">Add New Master Vendor</h2>
146
+ <button class="modal-close" type="button" aria-label="Close">&times;</button>
147
+ </div>
148
+ <div class="modal-body"><!-- content --></div>
149
+ <div class="modal-footer">
150
+ <button class="btn btn-outline" type="button">Cancel</button>
151
+ <button class="btn btn-primary" type="button">Create vendor</button>
152
+ </div>
153
+ </div>
154
+ </div>
155
+ ```
156
+
157
+ `.modal-close` works on a `<button>` or an `<a>`.
158
+
94
159
  ## Forms
95
160
 
96
161
  ```html
package/src/theme.css CHANGED
@@ -23,6 +23,10 @@
23
23
  --primary-light: var(--color-indigo-400); /* accent on dark surfaces (active nav) */
24
24
  --primary-soft: var(--color-indigo-300); /* focus ring / soft fill */
25
25
 
26
+ /* Interactive fills — hover / selected states (reusable beyond table rows) */
27
+ --hover: var(--color-indigo-200);
28
+ --selected: var(--color-indigo-100);
29
+
26
30
  /* Surfaces */
27
31
  --canvas: var(--color-slate-50); /* app background */
28
32
  --surface: var(--color-white); /* cards, inputs, panels */
@@ -58,13 +62,18 @@
58
62
  --danger-bg: var(--color-red-100); --danger-text: var(--color-red-700);
59
63
  --info-bg: var(--color-blue-100); --info-text: var(--color-blue-600);
60
64
 
65
+ /* Overlay scrim behind modals/dialogs (slate-900 @ 50%, matching the
66
+ rgb(15 23 42 / …) convention below; no 1:1 palette match, so literal) */
67
+ --overlay: rgb(15 23 42 / 0.5);
68
+
61
69
  /* Radius (matches Tailwind v4 defaults; redeclared so component CSS resolves) */
62
70
  --radius-sm: 4px;
63
71
  --radius-md: 6px;
64
72
  --radius-lg: 8px;
65
73
 
66
- /* Elevation (custom name so Tailwind's own shadow-sm/md stay untouched) */
74
+ /* Elevation (custom names so Tailwind's own shadow-sm/md stay untouched) */
67
75
  --shadow-card: 0 1px 3px rgb(15 23 42 / 0.06), 0 0 0 1px rgb(15 23 42 / 0.03);
76
+ --shadow-overlay: 0 20px 25px -5px rgb(15 23 42 / 0.15), 0 8px 10px -6px rgb(15 23 42 / 0.12);
68
77
  }
69
78
 
70
79
  /* Typography — override Tailwind's default font stacks. */