lombokcss 0.1.0

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/src/lombok.js ADDED
@@ -0,0 +1,155 @@
1
+ /* LombokCSS — lombok.js (optional, ~1.5KB). Zero dependencies.
2
+ Enhances: dropdowns, tabs, modals, toasts, table sort, navbar toggle.
3
+ Everything degrades gracefully if JS is off (details/dialog are native). */
4
+ (function () {
5
+ "use strict";
6
+ var d = document;
7
+
8
+ /* Dropdowns: toggle [data-dropdown] -> nearest .dropdown gets .is-open */
9
+ d.addEventListener("click", function (e) {
10
+ var t = e.target.closest("[data-dropdown-toggle]");
11
+ var open = d.querySelector(".dropdown.is-open");
12
+ if (open && (!t || !open.contains(t))) open.classList.remove("is-open");
13
+ if (t) {
14
+ e.preventDefault();
15
+ var dd = t.closest(".dropdown");
16
+ if (dd) { dd.classList.toggle("is-open");
17
+ t.setAttribute("aria-expanded", dd.classList.contains("is-open")); }
18
+ }
19
+ });
20
+ d.addEventListener("keydown", function (e) {
21
+ if (e.key === "Escape") { var o = d.querySelector(".dropdown.is-open"); if (o) o.classList.remove("is-open"); }
22
+ });
23
+
24
+ /* Tabs: [role=tablist] with buttons whose aria-controls -> panel id */
25
+ d.querySelectorAll('[role="tablist"]').forEach(function (list) {
26
+ var tabs = list.querySelectorAll('[role="tab"]');
27
+ tabs.forEach(function (tab) {
28
+ tab.addEventListener("click", function () {
29
+ tabs.forEach(function (x) {
30
+ x.setAttribute("aria-selected", "false");
31
+ var p = d.getElementById(x.getAttribute("aria-controls"));
32
+ if (p) p.hidden = true;
33
+ });
34
+ tab.setAttribute("aria-selected", "true");
35
+ var panel = d.getElementById(tab.getAttribute("aria-controls"));
36
+ if (panel) panel.hidden = false;
37
+ });
38
+ });
39
+ });
40
+
41
+ /* Modal: [data-modal-open="id"] / [data-modal-close]; uses native <dialog> */
42
+ d.addEventListener("click", function (e) {
43
+ var op = e.target.closest("[data-modal-open]");
44
+ if (op) { var m = d.getElementById(op.getAttribute("data-modal-open")); if (m && m.showModal) m.showModal(); }
45
+ var cl = e.target.closest("[data-modal-close]");
46
+ if (cl) { var dlg = cl.closest("dialog"); if (dlg) dlg.close(); }
47
+ });
48
+ /* click on backdrop closes */
49
+ d.querySelectorAll("dialog.modal").forEach(function (dlg) {
50
+ dlg.addEventListener("click", function (e) { if (e.target === dlg) dlg.close(); });
51
+ });
52
+
53
+ /* Navbar toggle (.navbar-toggle button toggles .is-open on .navbar) */
54
+ d.addEventListener("click", function (e) {
55
+ var b = e.target.closest(".navbar-toggle");
56
+ if (b) { var nav = b.closest(".navbar"); if (nav) nav.classList.toggle("is-open"); }
57
+ });
58
+
59
+ /* Drawer / Offcanvas: [data-drawer-open="id"] / [data-drawer-close] */
60
+ function closeDrawer(dr) {
61
+ dr.classList.remove("is-open");
62
+ var ov = d.getElementById(dr.id + "-overlay") || dr.nextElementSibling;
63
+ if (ov && ov.classList.contains("drawer-overlay")) ov.classList.remove("is-open");
64
+ }
65
+ d.addEventListener("click", function (e) {
66
+ var op = e.target.closest("[data-drawer-open]");
67
+ if (op) {
68
+ var dr = d.getElementById(op.getAttribute("data-drawer-open"));
69
+ if (dr) { dr.classList.add("is-open");
70
+ var ov = d.getElementById(dr.id + "-overlay") || dr.nextElementSibling;
71
+ if (ov && ov.classList.contains("drawer-overlay")) ov.classList.add("is-open"); }
72
+ }
73
+ var cl = e.target.closest("[data-drawer-close], .drawer-overlay");
74
+ if (cl) { var open = d.querySelector(".drawer.is-open"); if (open) closeDrawer(open); }
75
+ });
76
+
77
+ /* Popover: [data-popover-toggle] -> nearest .popover gets .is-open */
78
+ d.addEventListener("click", function (e) {
79
+ var t = e.target.closest("[data-popover-toggle]");
80
+ var open = d.querySelector(".popover.is-open");
81
+ if (open && (!t || !open.contains(t))) {
82
+ open.classList.remove("is-open");
83
+ var b = open.querySelector("[data-popover-toggle]"); if (b) b.setAttribute("aria-expanded", "false");
84
+ }
85
+ if (t) {
86
+ e.preventDefault();
87
+ var pop = t.closest(".popover");
88
+ if (pop) { pop.classList.toggle("is-open");
89
+ t.setAttribute("aria-expanded", pop.classList.contains("is-open")); }
90
+ }
91
+ });
92
+ d.addEventListener("keydown", function (e) {
93
+ if (e.key === "Escape") {
94
+ var dr = d.querySelector(".drawer.is-open"); if (dr) closeDrawer(dr);
95
+ var po = d.querySelector(".popover.is-open"); if (po) po.classList.remove("is-open");
96
+ }
97
+ });
98
+
99
+ /* Toast API: Lombok.toast("msg", {variant:"success", timeout:3000}) */
100
+ window.Lombok = window.Lombok || {};
101
+ window.Lombok.toast = function (msg, opts) {
102
+ opts = opts || {};
103
+ var region = d.querySelector(".toast-region");
104
+ if (!region) { region = d.createElement("div"); region.className = "toast-region"; region.setAttribute("aria-live", "polite"); d.body.appendChild(region); }
105
+ var el = d.createElement("div");
106
+ el.className = "toast" + (opts.variant ? " alert-" + opts.variant : "");
107
+ el.setAttribute("role", "status");
108
+ el.textContent = msg;
109
+ region.appendChild(el);
110
+ setTimeout(function () { el.remove(); }, opts.timeout || 3500);
111
+ return el;
112
+ };
113
+
114
+ /* Carousel: prev/next buttons + dots; scroll by one slide width */
115
+ d.querySelectorAll(".carousel").forEach(function (c) {
116
+ var track = c.querySelector(".carousel-track");
117
+ if (!track) return;
118
+ function step() {
119
+ var slide = track.querySelector(".carousel-slide");
120
+ var gap = parseFloat(getComputedStyle(track).columnGap || getComputedStyle(track).gap || 16) || 16;
121
+ return slide ? slide.getBoundingClientRect().width + gap : track.clientWidth;
122
+ }
123
+ var dir = (d.documentElement.getAttribute("dir") === "rtl") ? -1 : 1;
124
+ var prev = c.querySelector(".carousel-prev"), next = c.querySelector(".carousel-next");
125
+ if (prev) prev.addEventListener("click", function () { track.scrollBy({ left: -step() * dir, behavior: "smooth" }); });
126
+ if (next) next.addEventListener("click", function () { track.scrollBy({ left: step() * dir, behavior: "smooth" }); });
127
+ var dots = c.querySelectorAll(".carousel-dots > *");
128
+ dots.forEach(function (dot, i) {
129
+ dot.addEventListener("click", function () { track.scrollTo({ left: step() * i * dir, behavior: "smooth" }); });
130
+ });
131
+ if (dots.length) track.addEventListener("scroll", function () {
132
+ var idx = Math.round(Math.abs(track.scrollLeft) / step());
133
+ dots.forEach(function (x, i) { x.classList.toggle("is-active", i === idx); });
134
+ }, { passive: true });
135
+ });
136
+
137
+ /* Table sort: <th aria-sort> click sorts its column (string/number aware) */
138
+ d.querySelectorAll("table.table thead th[aria-sort]").forEach(function (th) {
139
+ th.addEventListener("click", function () {
140
+ var table = th.closest("table"), tbody = table.tBodies[0];
141
+ var idx = Array.prototype.indexOf.call(th.parentNode.children, th);
142
+ var asc = th.getAttribute("aria-sort") !== "ascending";
143
+ th.parentNode.querySelectorAll("th[aria-sort]").forEach(function (o) { o.setAttribute("aria-sort", "none"); });
144
+ th.setAttribute("aria-sort", asc ? "ascending" : "descending");
145
+ var rows = Array.prototype.slice.call(tbody.rows);
146
+ rows.sort(function (a, b) {
147
+ var x = a.cells[idx].textContent.trim(), y = b.cells[idx].textContent.trim();
148
+ var nx = parseFloat(x), ny = parseFloat(y);
149
+ var r = (!isNaN(nx) && !isNaN(ny)) ? nx - ny : x.localeCompare(y);
150
+ return asc ? r : -r;
151
+ });
152
+ rows.forEach(function (r) { tbody.appendChild(r); });
153
+ });
154
+ });
155
+ })();
package/src/themes.css ADDED
@@ -0,0 +1,158 @@
1
+ /* ==========================================================================
2
+ LombokCSS — themes.css
3
+ Design-trend presets. Switch with data-style="..." on <html> or <body>.
4
+ Each preset ONLY re-maps tokens; component structure never changes.
5
+ Works alongside data-theme="dark|light".
6
+ ========================================================================== */
7
+
8
+ /* --------------------------------------------------------------------------
9
+ 1) modern-corporate-flat (also the :root default)
10
+ Clean, flat, neutral + one brand color, medium radius, soft shadow.
11
+ Colors are inherited from :root / dark overlay, so we only confirm look.
12
+ -------------------------------------------------------------------------- */
13
+ [data-style="modern-corporate-flat"] {
14
+ --lc-accent:#3b82f6; --lc-accent-hover:#2f6fe0; --lc-accent-active:#2861c9;
15
+ --lc-radius-sm:6px; --lc-radius:10px; --lc-radius-lg:16px;
16
+ --lc-border-width:1px;
17
+ --lc-shadow-sm:0 1px 2px rgba(16,24,40,.06);
18
+ --lc-shadow:0 4px 12px rgba(16,24,40,.08);
19
+ --lc-shadow-lg:0 12px 32px rgba(16,24,40,.12);
20
+ --lc-shadow-hard:none; --lc-blur:none;
21
+ }
22
+
23
+ /* --------------------------------------------------------------------------
24
+ 2) resonant-stark (Linear-style) — intrinsically dark, high contrast.
25
+ -------------------------------------------------------------------------- */
26
+ [data-style="resonant-stark"] {
27
+ --lc-bg:#08090c;
28
+ --lc-surface:#101218;
29
+ --lc-surface-2:#171a22;
30
+ --lc-text:#f3f5f8;
31
+ --lc-text-muted:#a3acba;
32
+ --lc-text-faint:#6c7585;
33
+ --lc-border:#23262f;
34
+ --lc-border-strong:#333845;
35
+ --lc-accent:#7c6cff; --lc-accent-hover:#8d7fff; --lc-accent-active:#6b5af0;
36
+ --lc-accent-text:#ffffff; --lc-accent-soft:#1b1830; --lc-accent-soft-text:#bcb2ff;
37
+ --lc-ring:rgba(124,108,255,.5);
38
+ /* dark-appropriate status colors (soft backgrounds + readable text) */
39
+ --lc-success-soft:#11271b; --lc-success-text:#6ee7a0;
40
+ --lc-warning-soft:#2a1f0d; --lc-warning-text:#fbbf24;
41
+ --lc-danger-soft:#2a1414; --lc-danger-text:#fca5a5;
42
+ --lc-info-soft:#0c2530; --lc-info-text:#67d3f7;
43
+ --lc-radius-sm:5px; --lc-radius:7px; --lc-radius-lg:11px;
44
+ --lc-border-width:1px;
45
+ --lc-shadow-sm:0 1px 2px rgba(0,0,0,.5);
46
+ --lc-shadow:0 2px 10px rgba(0,0,0,.55);
47
+ --lc-shadow-lg:0 10px 36px rgba(0,0,0,.65);
48
+ --lc-shadow-hard:none; --lc-blur:none;
49
+ --lc-tracking:-.01em;
50
+ --lc-font-display:var(--lc-font-sans);
51
+ --lc-weight-semibold:600;
52
+ }
53
+
54
+ /* --------------------------------------------------------------------------
55
+ 3) neo-brutalism — thick black borders, hard offset shadow, bold blocks.
56
+ -------------------------------------------------------------------------- */
57
+ [data-style="neo-brutalism"] {
58
+ --lc-bg:#fdf6e3;
59
+ --lc-surface:#ffffff;
60
+ --lc-surface-2:#fff3c4;
61
+ --lc-text:#0a0a0a;
62
+ --lc-text-muted:#33312b;
63
+ --lc-text-faint:#6b6760;
64
+ --lc-border:#0a0a0a;
65
+ --lc-border-strong:#0a0a0a;
66
+ --lc-accent:#ff4f00; --lc-accent-hover:#e84700; --lc-accent-active:#cc3f00;
67
+ --lc-accent-text:#ffffff; --lc-accent-soft:#ffe1cc; --lc-accent-soft-text:#0a0a0a;
68
+ --lc-ring:rgba(10,10,10,.9);
69
+ --lc-success:#1f9e4d; --lc-warning:#e0a400; --lc-danger:#e3342f; --lc-info:#2563eb;
70
+ --lc-success-soft:#d9f5e2; --lc-warning-soft:#fff0c4; --lc-danger-soft:#ffd9d7; --lc-info-soft:#d7e3ff;
71
+ --lc-radius-sm:0px; --lc-radius:0px; --lc-radius-lg:0px;
72
+ --lc-border-width:2.5px;
73
+ --lc-shadow-sm:3px 3px 0 #0a0a0a;
74
+ --lc-shadow:5px 5px 0 #0a0a0a;
75
+ --lc-shadow-lg:8px 8px 0 #0a0a0a;
76
+ --lc-shadow-hard:5px 5px 0 #0a0a0a;
77
+ --lc-blur:none;
78
+ --lc-weight-medium:700; --lc-weight-semibold:800; --lc-weight-bold:900;
79
+ }
80
+ [data-style="neo-brutalism"][data-theme="dark"] {
81
+ --lc-bg:#16140f; --lc-surface:#1f1c14; --lc-surface-2:#2a2517;
82
+ --lc-text:#fdf6e3; --lc-text-muted:#cfc7ad; --lc-text-faint:#8f8a72;
83
+ --lc-border:#fdf6e3; --lc-border-strong:#fdf6e3;
84
+ --lc-shadow-sm:3px 3px 0 #fdf6e3; --lc-shadow:5px 5px 0 #fdf6e3; --lc-shadow-lg:8px 8px 0 #fdf6e3;
85
+ --lc-shadow-hard:5px 5px 0 #fdf6e3; --lc-accent-soft:#3a2a1c;
86
+ }
87
+
88
+ /* --------------------------------------------------------------------------
89
+ 4) semantic-minimalist — minimal, neutral, generous spacing, readable.
90
+ -------------------------------------------------------------------------- */
91
+ [data-style="semantic-minimalist"] {
92
+ --lc-bg:#fbfbfa;
93
+ --lc-surface:#ffffff;
94
+ --lc-surface-2:#f4f4f2;
95
+ --lc-text:#23211e;
96
+ --lc-text-muted:#6a665f;
97
+ --lc-text-faint:#9a958c;
98
+ --lc-border:#e8e6e1;
99
+ --lc-border-strong:#d4d1c9;
100
+ --lc-accent:#1f6f5c; --lc-accent-hover:#1a5e4e; --lc-accent-active:#164f42;
101
+ --lc-accent-text:#ffffff; --lc-accent-soft:#e4f0ec; --lc-accent-soft-text:#155446;
102
+ --lc-ring:rgba(31,111,92,.4);
103
+ --lc-radius-sm:4px; --lc-radius:6px; --lc-radius-lg:8px;
104
+ --lc-border-width:1px;
105
+ --lc-shadow-sm:none; --lc-shadow:0 1px 3px rgba(0,0,0,.05); --lc-shadow-lg:0 6px 18px rgba(0,0,0,.07);
106
+ --lc-shadow-hard:none; --lc-blur:none;
107
+ --lc-leading-normal:1.7; --lc-leading-relaxed:1.85;
108
+ --lc-font-display:Georgia,"Times New Roman",serif; /* characterful display, restrained */
109
+ }
110
+ [data-style="semantic-minimalist"][data-theme="dark"] {
111
+ --lc-bg:#16150f; --lc-surface:#1d1c15; --lc-surface-2:#26241b;
112
+ --lc-text:#ece9df; --lc-text-muted:#a7a394; --lc-text-faint:#777262;
113
+ --lc-border:#2c2a20; --lc-border-strong:#3a3729; --lc-accent-soft:#163029;
114
+ }
115
+
116
+ /* --------------------------------------------------------------------------
117
+ 5) glassmorphism — frosted glass; semi-transparent surfaces + backdrop blur.
118
+ Page sits on a gradient so the blur reads. Fallback below for no support.
119
+ -------------------------------------------------------------------------- */
120
+ [data-style="glassmorphism"] {
121
+ --lc-bg:#0b1020;
122
+ --lc-bg-gradient:radial-gradient(1200px 600px at 12% -10%, #6d28d9 0%, transparent 55%),
123
+ radial-gradient(900px 500px at 100% 0%, #0ea5e9 0%, transparent 50%),
124
+ radial-gradient(800px 600px at 50% 120%, #db2777 0%, transparent 55%);
125
+ --lc-surface:rgba(255,255,255,.10);
126
+ --lc-surface-2:rgba(255,255,255,.16);
127
+ --lc-text:#f4f6ff;
128
+ --lc-text-muted:#c4cbe6;
129
+ --lc-text-faint:#9aa2c4;
130
+ --lc-border:rgba(255,255,255,.22);
131
+ --lc-border-strong:rgba(255,255,255,.35);
132
+ --lc-accent:#a78bfa; --lc-accent-hover:#b9a4fb; --lc-accent-active:#9170f7;
133
+ --lc-accent-text:#13102a; --lc-accent-soft:rgba(167,139,250,.22); --lc-accent-soft-text:#e3dbff;
134
+ --lc-ring:rgba(167,139,250,.5);
135
+ --lc-success-soft:rgba(34,197,94,.2); --lc-warning-soft:rgba(217,119,6,.22);
136
+ --lc-danger-soft:rgba(220,38,38,.22); --lc-info-soft:rgba(14,165,233,.22);
137
+ --lc-radius-sm:10px; --lc-radius:16px; --lc-radius-lg:22px;
138
+ --lc-border-width:1px;
139
+ --lc-shadow-sm:0 2px 8px rgba(0,0,0,.25);
140
+ --lc-shadow:0 8px 32px rgba(0,0,0,.32);
141
+ --lc-shadow-lg:0 20px 60px rgba(0,0,0,.4);
142
+ --lc-shadow-hard:none;
143
+ --lc-blur:blur(14px) saturate(140%);
144
+ --lc-glass-tint:rgba(255,255,255,.10);
145
+ --lc-glass-border:rgba(255,255,255,.28);
146
+ }
147
+ [data-style="glassmorphism"] body { background-image: var(--lc-bg-gradient); background-attachment: fixed; }
148
+
149
+ /* Fallback: if backdrop-filter is unsupported, make glass surfaces opaque
150
+ so content stays legible (no see-through mud). */
151
+ @supports not (backdrop-filter: blur(1px)) {
152
+ [data-style="glassmorphism"] {
153
+ --lc-surface:#1b2138;
154
+ --lc-surface-2:#232a44;
155
+ --lc-border:rgba(255,255,255,.18);
156
+ --lc-blur:none;
157
+ }
158
+ }
@@ -0,0 +1,255 @@
1
+ /* ==========================================================================
2
+ LombokCSS — utilities.css
3
+ Atomic helpers. RTL-safe via logical properties. Responsive: sm/md/lg/xl.
4
+ ========================================================================== */
5
+
6
+ /* ---- Display ---- */
7
+ .block{display:block}.inline-block{display:inline-block}.inline{display:inline}.hidden{display:none}
8
+ .flex{display:flex}.inline-flex{display:inline-flex}.grid{display:grid}.inline-grid{display:inline-grid}
9
+
10
+ /* ---- Flexbox ---- */
11
+ .flex-row{flex-direction:row}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}
12
+ .flex-1{flex:1 1 0%}.flex-auto{flex:1 1 auto}.flex-none{flex:none}
13
+ .items-start{align-items:flex-start}.items-center{align-items:center}.items-end{align-items:flex-end}.items-stretch{align-items:stretch}.items-baseline{align-items:baseline}
14
+ .justify-start{justify-content:flex-start}.justify-center{justify-content:center}.justify-end{justify-content:flex-end}
15
+ .justify-between{justify-content:space-between}.justify-around{justify-content:space-around}.justify-evenly{justify-content:space-evenly}
16
+ .self-start{align-self:flex-start}.self-center{align-self:center}.self-end{align-self:flex-end}
17
+
18
+ /* ---- Grid ---- */
19
+ .grid-cols-1{grid-template-columns:repeat(1,1fr)}.grid-cols-2{grid-template-columns:repeat(2,1fr)}
20
+ .grid-cols-3{grid-template-columns:repeat(3,1fr)}.grid-cols-4{grid-template-columns:repeat(4,1fr)}
21
+ .grid-cols-5{grid-template-columns:repeat(5,1fr)}.grid-cols-6{grid-template-columns:repeat(6,1fr)}
22
+ .grid-cols-12{grid-template-columns:repeat(12,1fr)}
23
+ .col-span-2{grid-column:span 2}.col-span-3{grid-column:span 3}.col-span-4{grid-column:span 4}
24
+ .col-span-6{grid-column:span 6}.col-span-full{grid-column:1 / -1}
25
+
26
+ /* ---- Gap (uses spacing scale) ---- */
27
+ .gap-0{gap:0}.gap-1{gap:var(--lc-space-1)}.gap-2{gap:var(--lc-space-2)}.gap-3{gap:var(--lc-space-3)}
28
+ .gap-4{gap:var(--lc-space-4)}.gap-6{gap:var(--lc-space-6)}.gap-8{gap:var(--lc-space-8)}
29
+
30
+ /* ---- Spacing: padding (logical) ---- */
31
+ .p-0{padding:0}.p-1{padding:var(--lc-space-1)}.p-2{padding:var(--lc-space-2)}.p-3{padding:var(--lc-space-3)}
32
+ .p-4{padding:var(--lc-space-4)}.p-6{padding:var(--lc-space-6)}.p-8{padding:var(--lc-space-8)}
33
+ .px-2{padding-inline:var(--lc-space-2)}.px-3{padding-inline:var(--lc-space-3)}.px-4{padding-inline:var(--lc-space-4)}.px-6{padding-inline:var(--lc-space-6)}
34
+ .py-1{padding-block:var(--lc-space-1)}.py-2{padding-block:var(--lc-space-2)}.py-3{padding-block:var(--lc-space-3)}.py-4{padding-block:var(--lc-space-4)}.py-6{padding-block:var(--lc-space-6)}
35
+ .pt-4{padding-block-start:var(--lc-space-4)}.pb-4{padding-block-end:var(--lc-space-4)}
36
+
37
+ /* ---- Spacing: margin (logical) ---- */
38
+ .m-0{margin:0}.m-auto{margin:auto}
39
+ .m-1{margin:var(--lc-space-1)}.m-2{margin:var(--lc-space-2)}.m-4{margin:var(--lc-space-4)}
40
+ .mx-auto{margin-inline:auto}.my-2{margin-block:var(--lc-space-2)}.my-4{margin-block:var(--lc-space-4)}.my-6{margin-block:var(--lc-space-6)}
41
+ .mt-2{margin-block-start:var(--lc-space-2)}.mt-4{margin-block-start:var(--lc-space-4)}.mt-6{margin-block-start:var(--lc-space-6)}
42
+ .mb-0{margin-block-end:0}.mb-2{margin-block-end:var(--lc-space-2)}.mb-4{margin-block-end:var(--lc-space-4)}.mb-6{margin-block-end:var(--lc-space-6)}
43
+ .ms-auto{margin-inline-start:auto}.me-auto{margin-inline-end:auto}
44
+
45
+ /* ---- Sizing ---- */
46
+ .w-full{inline-size:100%}.w-auto{inline-size:auto}.w-screen{inline-size:100vw}.w-fit{inline-size:fit-content}
47
+ .h-full{block-size:100%}.h-screen{block-size:100vh}.min-h-screen{min-block-size:100vh}
48
+ .max-w-xs{max-inline-size:20rem}.max-w-sm{max-inline-size:24rem}.max-w-md{max-inline-size:28rem}
49
+ .max-w-lg{max-inline-size:32rem}.max-w-xl{max-inline-size:36rem}.max-w-2xl{max-inline-size:42rem}.max-w-7xl{max-inline-size:80rem}
50
+
51
+ /* ---- Typography ---- */
52
+ .text-xs{font-size:var(--lc-text-xs)}.text-sm{font-size:var(--lc-text-sm)}.text-base{font-size:var(--lc-text-base)}
53
+ .text-lg{font-size:var(--lc-text-lg)}.text-xl{font-size:var(--lc-text-xl)}.text-2xl{font-size:var(--lc-text-2xl)}.text-3xl{font-size:var(--lc-text-3xl)}
54
+ .font-light{font-weight:300}.font-normal{font-weight:var(--lc-weight-normal)}.font-medium{font-weight:var(--lc-weight-medium)}
55
+ .font-semibold{font-weight:var(--lc-weight-semibold)}.font-bold{font-weight:var(--lc-weight-bold)}
56
+ .text-start{text-align:start}.text-center{text-align:center}.text-end{text-align:end}.text-justify{text-align:justify}
57
+ .leading-tight{line-height:var(--lc-leading-tight)}.leading-normal{line-height:var(--lc-leading-normal)}.leading-relaxed{line-height:var(--lc-leading-relaxed)}
58
+ .tracking-tight{letter-spacing:-.02em}.tracking-wide{letter-spacing:.04em}
59
+ .uppercase{text-transform:uppercase}.capitalize{text-transform:capitalize}
60
+ .truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
61
+ .font-mono{font-family:var(--lc-font-mono)}
62
+
63
+ /* ---- Colors ---- */
64
+ .text-primary{color:var(--lc-accent)}.text-muted{color:var(--lc-text-muted)}.text-faint{color:var(--lc-text-faint)}
65
+ .text-success{color:var(--lc-success-text)}.text-danger{color:var(--lc-danger-text)}.text-warning{color:var(--lc-warning-text)}
66
+ .bg-bg{background:var(--lc-bg)}.bg-surface{background:var(--lc-surface)}.bg-surface-2{background:var(--lc-surface-2)}
67
+ .bg-primary{background:var(--lc-accent);color:var(--lc-accent-text)}.bg-soft{background:var(--lc-accent-soft);color:var(--lc-accent-soft-text)}
68
+ .border{border:var(--lc-border-width) solid var(--lc-border)}.border-strong{border-color:var(--lc-border-strong)}
69
+ .border-0{border:0}.border-t{border-block-start:var(--lc-border-width) solid var(--lc-border)}.border-b{border-block-end:var(--lc-border-width) solid var(--lc-border)}
70
+
71
+ /* ---- Radius ---- */
72
+ .rounded-none{border-radius:0}.rounded-sm{border-radius:var(--lc-radius-sm)}.rounded{border-radius:var(--lc-radius)}
73
+ .rounded-lg{border-radius:var(--lc-radius-lg)}.rounded-full{border-radius:var(--lc-radius-full)}
74
+
75
+ /* ---- Effects ---- */
76
+ .shadow-none{box-shadow:none}.shadow-sm{box-shadow:var(--lc-shadow-sm)}.shadow{box-shadow:var(--lc-shadow)}.shadow-lg{box-shadow:var(--lc-shadow-lg)}
77
+ .backdrop-blur{-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px)}
78
+ .opacity-50{opacity:.5}.opacity-75{opacity:.75}
79
+
80
+ /* ---- Position ---- */
81
+ .relative{position:relative}.absolute{position:absolute}.fixed{position:fixed}.sticky{position:sticky}
82
+ .inset-0{inset:0}.top-0{inset-block-start:0}.bottom-0{inset-block-end:0}.start-0{inset-inline-start:0}.end-0{inset-inline-end:0}
83
+ .z-10{z-index:10}.z-20{z-index:20}.z-30{z-index:30}.z-50{z-index:50}
84
+
85
+ /* ---- Misc ---- */
86
+ .overflow-hidden{overflow:hidden}.overflow-auto{overflow:auto}.overflow-x-auto{overflow-x:auto}
87
+ .cursor-pointer{cursor:pointer}.cursor-default{cursor:default}.select-none{user-select:none}
88
+ .transition{transition:all var(--lc-transition)}
89
+ .sr-only{position:absolute;inline-size:1px;block-size:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}
90
+ .aspect-square{aspect-ratio:1}.aspect-video{aspect-ratio:16/9}
91
+
92
+ /* ---- Status colors (solid / soft / text / border) ---- */
93
+ .text-info{color:var(--lc-info-text)}
94
+ .bg-success{background:var(--lc-success);color:#fff}.bg-warning{background:var(--lc-warning);color:#fff}
95
+ .bg-danger{background:var(--lc-danger);color:#fff}.bg-info{background:var(--lc-info);color:#fff}
96
+ .bg-success-soft{background:var(--lc-success-soft);color:var(--lc-success-text)}
97
+ .bg-warning-soft{background:var(--lc-warning-soft);color:var(--lc-warning-text)}
98
+ .bg-danger-soft{background:var(--lc-danger-soft);color:var(--lc-danger-text)}
99
+ .bg-info-soft{background:var(--lc-info-soft);color:var(--lc-info-text)}
100
+ .border-success{border-color:var(--lc-success)}.border-warning{border-color:var(--lc-warning)}
101
+ .border-danger{border-color:var(--lc-danger)}.border-info{border-color:var(--lc-info)}.border-primary{border-color:var(--lc-accent)}
102
+
103
+ /* ---- Full gap scale + directional gaps ---- */
104
+ .gap-5{gap:var(--lc-space-5)}.gap-10{gap:var(--lc-space-10)}.gap-12{gap:var(--lc-space-12)}
105
+ .gap-x-2{column-gap:var(--lc-space-2)}.gap-x-4{column-gap:var(--lc-space-4)}.gap-x-6{column-gap:var(--lc-space-6)}
106
+ .gap-y-2{row-gap:var(--lc-space-2)}.gap-y-4{row-gap:var(--lc-space-4)}.gap-y-6{row-gap:var(--lc-space-6)}
107
+ /* ---- Full col-span scale ---- */
108
+ .col-span-1{grid-column:span 1}.col-span-5{grid-column:span 5}
109
+ .col-span-7{grid-column:span 7}.col-span-8{grid-column:span 8}
110
+ .col-span-9{grid-column:span 9}.col-span-10{grid-column:span 10}
111
+ .col-span-11{grid-column:span 11}.col-span-12{grid-column:span 12}
112
+
113
+ /* ==========================================================================
114
+ Responsive prefixes (mobile-first), full scale: sm 640 / md 768 / lg 1024 / xl 1280
115
+ ========================================================================== */
116
+ @media (min-width:640px){
117
+ .sm\:block{display:block}
118
+ .sm\:inline-block{display:inline-block}
119
+ .sm\:flex{display:flex}
120
+ .sm\:inline-flex{display:inline-flex}
121
+ .sm\:grid{display:grid}
122
+ .sm\:inline-grid{display:inline-grid}
123
+ .sm\:hidden{display:none}
124
+ .sm\:flex-row{flex-direction:row}.sm\:flex-col{flex-direction:column}.sm\:flex-wrap{flex-wrap:wrap}
125
+ .sm\:items-start{align-items:flex-start}.sm\:items-center{align-items:center}.sm\:items-end{align-items:flex-end}
126
+ .sm\:justify-start{justify-content:flex-start}.sm\:justify-center{justify-content:center}.sm\:justify-end{justify-content:flex-end}.sm\:justify-between{justify-content:space-between}
127
+ .sm\:grid-cols-1{grid-template-columns:repeat(1,1fr)}
128
+ .sm\:grid-cols-2{grid-template-columns:repeat(2,1fr)}
129
+ .sm\:grid-cols-3{grid-template-columns:repeat(3,1fr)}
130
+ .sm\:grid-cols-4{grid-template-columns:repeat(4,1fr)}
131
+ .sm\:grid-cols-5{grid-template-columns:repeat(5,1fr)}
132
+ .sm\:grid-cols-6{grid-template-columns:repeat(6,1fr)}
133
+ .sm\:grid-cols-12{grid-template-columns:repeat(12,1fr)}
134
+ .sm\:col-span-1{grid-column:span 1}
135
+ .sm\:col-span-2{grid-column:span 2}
136
+ .sm\:col-span-3{grid-column:span 3}
137
+ .sm\:col-span-4{grid-column:span 4}
138
+ .sm\:col-span-5{grid-column:span 5}
139
+ .sm\:col-span-6{grid-column:span 6}
140
+ .sm\:col-span-full{grid-column:1 / -1}
141
+ .sm\:gap-0{gap:0}
142
+ .sm\:gap-1{gap:var(--lc-space-1)}
143
+ .sm\:gap-2{gap:var(--lc-space-2)}
144
+ .sm\:gap-3{gap:var(--lc-space-3)}
145
+ .sm\:gap-4{gap:var(--lc-space-4)}
146
+ .sm\:gap-5{gap:var(--lc-space-5)}
147
+ .sm\:gap-6{gap:var(--lc-space-6)}
148
+ .sm\:gap-8{gap:var(--lc-space-8)}
149
+ .sm\:text-start{text-align:start}.sm\:text-center{text-align:center}.sm\:text-end{text-align:end}
150
+ }
151
+ @media (min-width:768px){
152
+ .md\:block{display:block}
153
+ .md\:inline-block{display:inline-block}
154
+ .md\:flex{display:flex}
155
+ .md\:inline-flex{display:inline-flex}
156
+ .md\:grid{display:grid}
157
+ .md\:inline-grid{display:inline-grid}
158
+ .md\:hidden{display:none}
159
+ .md\:flex-row{flex-direction:row}.md\:flex-col{flex-direction:column}.md\:flex-wrap{flex-wrap:wrap}
160
+ .md\:items-start{align-items:flex-start}.md\:items-center{align-items:center}.md\:items-end{align-items:flex-end}
161
+ .md\:justify-start{justify-content:flex-start}.md\:justify-center{justify-content:center}.md\:justify-end{justify-content:flex-end}.md\:justify-between{justify-content:space-between}
162
+ .md\:grid-cols-1{grid-template-columns:repeat(1,1fr)}
163
+ .md\:grid-cols-2{grid-template-columns:repeat(2,1fr)}
164
+ .md\:grid-cols-3{grid-template-columns:repeat(3,1fr)}
165
+ .md\:grid-cols-4{grid-template-columns:repeat(4,1fr)}
166
+ .md\:grid-cols-5{grid-template-columns:repeat(5,1fr)}
167
+ .md\:grid-cols-6{grid-template-columns:repeat(6,1fr)}
168
+ .md\:grid-cols-12{grid-template-columns:repeat(12,1fr)}
169
+ .md\:col-span-1{grid-column:span 1}
170
+ .md\:col-span-2{grid-column:span 2}
171
+ .md\:col-span-3{grid-column:span 3}
172
+ .md\:col-span-4{grid-column:span 4}
173
+ .md\:col-span-5{grid-column:span 5}
174
+ .md\:col-span-6{grid-column:span 6}
175
+ .md\:col-span-full{grid-column:1 / -1}
176
+ .md\:gap-0{gap:0}
177
+ .md\:gap-1{gap:var(--lc-space-1)}
178
+ .md\:gap-2{gap:var(--lc-space-2)}
179
+ .md\:gap-3{gap:var(--lc-space-3)}
180
+ .md\:gap-4{gap:var(--lc-space-4)}
181
+ .md\:gap-5{gap:var(--lc-space-5)}
182
+ .md\:gap-6{gap:var(--lc-space-6)}
183
+ .md\:gap-8{gap:var(--lc-space-8)}
184
+ .md\:text-start{text-align:start}.md\:text-center{text-align:center}.md\:text-end{text-align:end}
185
+ }
186
+ @media (min-width:1024px){
187
+ .lg\:block{display:block}
188
+ .lg\:inline-block{display:inline-block}
189
+ .lg\:flex{display:flex}
190
+ .lg\:inline-flex{display:inline-flex}
191
+ .lg\:grid{display:grid}
192
+ .lg\:inline-grid{display:inline-grid}
193
+ .lg\:hidden{display:none}
194
+ .lg\:flex-row{flex-direction:row}.lg\:flex-col{flex-direction:column}.lg\:flex-wrap{flex-wrap:wrap}
195
+ .lg\:items-start{align-items:flex-start}.lg\:items-center{align-items:center}.lg\:items-end{align-items:flex-end}
196
+ .lg\:justify-start{justify-content:flex-start}.lg\:justify-center{justify-content:center}.lg\:justify-end{justify-content:flex-end}.lg\:justify-between{justify-content:space-between}
197
+ .lg\:grid-cols-1{grid-template-columns:repeat(1,1fr)}
198
+ .lg\:grid-cols-2{grid-template-columns:repeat(2,1fr)}
199
+ .lg\:grid-cols-3{grid-template-columns:repeat(3,1fr)}
200
+ .lg\:grid-cols-4{grid-template-columns:repeat(4,1fr)}
201
+ .lg\:grid-cols-5{grid-template-columns:repeat(5,1fr)}
202
+ .lg\:grid-cols-6{grid-template-columns:repeat(6,1fr)}
203
+ .lg\:grid-cols-12{grid-template-columns:repeat(12,1fr)}
204
+ .lg\:col-span-1{grid-column:span 1}
205
+ .lg\:col-span-2{grid-column:span 2}
206
+ .lg\:col-span-3{grid-column:span 3}
207
+ .lg\:col-span-4{grid-column:span 4}
208
+ .lg\:col-span-5{grid-column:span 5}
209
+ .lg\:col-span-6{grid-column:span 6}
210
+ .lg\:col-span-full{grid-column:1 / -1}
211
+ .lg\:gap-0{gap:0}
212
+ .lg\:gap-1{gap:var(--lc-space-1)}
213
+ .lg\:gap-2{gap:var(--lc-space-2)}
214
+ .lg\:gap-3{gap:var(--lc-space-3)}
215
+ .lg\:gap-4{gap:var(--lc-space-4)}
216
+ .lg\:gap-5{gap:var(--lc-space-5)}
217
+ .lg\:gap-6{gap:var(--lc-space-6)}
218
+ .lg\:gap-8{gap:var(--lc-space-8)}
219
+ .lg\:text-start{text-align:start}.lg\:text-center{text-align:center}.lg\:text-end{text-align:end}
220
+ }
221
+ @media (min-width:1280px){
222
+ .xl\:block{display:block}
223
+ .xl\:inline-block{display:inline-block}
224
+ .xl\:flex{display:flex}
225
+ .xl\:inline-flex{display:inline-flex}
226
+ .xl\:grid{display:grid}
227
+ .xl\:inline-grid{display:inline-grid}
228
+ .xl\:hidden{display:none}
229
+ .xl\:flex-row{flex-direction:row}.xl\:flex-col{flex-direction:column}.xl\:flex-wrap{flex-wrap:wrap}
230
+ .xl\:items-start{align-items:flex-start}.xl\:items-center{align-items:center}.xl\:items-end{align-items:flex-end}
231
+ .xl\:justify-start{justify-content:flex-start}.xl\:justify-center{justify-content:center}.xl\:justify-end{justify-content:flex-end}.xl\:justify-between{justify-content:space-between}
232
+ .xl\:grid-cols-1{grid-template-columns:repeat(1,1fr)}
233
+ .xl\:grid-cols-2{grid-template-columns:repeat(2,1fr)}
234
+ .xl\:grid-cols-3{grid-template-columns:repeat(3,1fr)}
235
+ .xl\:grid-cols-4{grid-template-columns:repeat(4,1fr)}
236
+ .xl\:grid-cols-5{grid-template-columns:repeat(5,1fr)}
237
+ .xl\:grid-cols-6{grid-template-columns:repeat(6,1fr)}
238
+ .xl\:grid-cols-12{grid-template-columns:repeat(12,1fr)}
239
+ .xl\:col-span-1{grid-column:span 1}
240
+ .xl\:col-span-2{grid-column:span 2}
241
+ .xl\:col-span-3{grid-column:span 3}
242
+ .xl\:col-span-4{grid-column:span 4}
243
+ .xl\:col-span-5{grid-column:span 5}
244
+ .xl\:col-span-6{grid-column:span 6}
245
+ .xl\:col-span-full{grid-column:1 / -1}
246
+ .xl\:gap-0{gap:0}
247
+ .xl\:gap-1{gap:var(--lc-space-1)}
248
+ .xl\:gap-2{gap:var(--lc-space-2)}
249
+ .xl\:gap-3{gap:var(--lc-space-3)}
250
+ .xl\:gap-4{gap:var(--lc-space-4)}
251
+ .xl\:gap-5{gap:var(--lc-space-5)}
252
+ .xl\:gap-6{gap:var(--lc-space-6)}
253
+ .xl\:gap-8{gap:var(--lc-space-8)}
254
+ .xl\:text-start{text-align:start}.xl\:text-center{text-align:center}.xl\:text-end{text-align:end}
255
+ }