@barocss/browser 0.6.0 → 0.8.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.
@@ -178,8 +178,12 @@ function clearContextCaches(ctx) {
178
178
  }
179
179
  const utilityRegistry = [];
180
180
  function registerUtility(util, ctx) {
181
- utilityRegistry.push(util);
182
- {
181
+ const state = ctx && getContextState(ctx);
182
+ if (ctx && !state) throw new Error("Utility registration requires a context from createContext");
183
+ (state?.utilities || utilityRegistry).push(util);
184
+ if (ctx) {
185
+ clearContextCaches(ctx);
186
+ } else {
183
187
  parseResultCache.clear();
184
188
  utilityCache.clear();
185
189
  }
@@ -190,6 +194,7 @@ function getUtility(ctx) {
190
194
  const modifierRegistry = [];
191
195
  function staticModifier(name, selectors, options = {}, ctx) {
192
196
  registerModifier({
197
+ name,
193
198
  match: (mod) => mod === name,
194
199
  modifySelector: ({ ..._rest }) => {
195
200
  return selectors.map((sel) => ({
@@ -273,7 +278,7 @@ function staticUtility(name, decls, opts, ctx) {
273
278
  description: opts?.description,
274
279
  category: opts?.category,
275
280
  priority: opts?.priority
276
- });
281
+ }, ctx);
277
282
  }
278
283
  function spacingKeyValue(ctx, key, negative) {
279
284
  if (key === "px" || !/^[a-zA-Z][\w-]*$/.test(key) || ctx.theme("spacing", key) == null) return null;
@@ -374,7 +379,7 @@ function functionalUtility(opts, ctx) {
374
379
  description: opts.description,
375
380
  category: opts.category,
376
381
  priority: opts.priority
377
- });
382
+ }, ctx);
378
383
  }
379
384
  const MATH_FNS = /* @__PURE__ */ new Set(["calc", "min", "max", "clamp"]);
380
385
  function expandThemeFunctions(value) {
@@ -493,14 +498,23 @@ function parseClassName(className, ctx) {
493
498
  if (cache.has(className)) {
494
499
  return cache.get(className);
495
500
  }
496
- let important = false;
497
501
  let realClassName = className;
498
- if (className.startsWith("!")) {
502
+ const classPrefix = ctx ? configuredClassPrefix(ctx) : "";
503
+ if (classPrefix) {
504
+ if (!className.startsWith(classPrefix + ":")) {
505
+ const none = { modifiers: [], utility: null };
506
+ cache.set(className, none);
507
+ return none;
508
+ }
509
+ realClassName = className.slice(classPrefix.length + 1);
510
+ }
511
+ let important = false;
512
+ if (realClassName.startsWith("!")) {
499
513
  important = true;
500
- realClassName = className.slice(1);
501
- } else if (className.length > 1 && className.endsWith("!")) {
514
+ realClassName = realClassName.slice(1);
515
+ } else if (realClassName.length > 1 && realClassName.endsWith("!")) {
502
516
  important = true;
503
- realClassName = className.slice(0, -1);
517
+ realClassName = realClassName.slice(0, -1);
504
518
  }
505
519
  const tokens = tokenize(realClassName);
506
520
  const result = parseTokens(tokens, ctx);
@@ -510,6 +524,10 @@ function parseClassName(className, ctx) {
510
524
  cache.set(className, result);
511
525
  return result;
512
526
  }
527
+ function configuredClassPrefix(ctx) {
528
+ const configured = ctx.config("prefix");
529
+ return typeof configured === "string" && /^[a-z]+$/.test(configured) ? configured : "";
530
+ }
513
531
  function parseTokens(tokens, ctx) {
514
532
  const modifiers = [];
515
533
  let utility = null;
@@ -1029,24 +1047,41 @@ function animationToCssVars(animations2) {
1029
1047
  }
1030
1048
  return result;
1031
1049
  }
1032
- function keyframesToCss(keyframes2) {
1033
- if (!keyframes2) return "";
1034
- let css = "";
1035
- for (const name in keyframes2) {
1036
- const frames = keyframes2[name];
1037
- css += `@keyframes ${name} {
1050
+ const COMMENT_OR_BLOCK = /\/\*|\*\/|[{};]/;
1051
+ function keyframesBlock(name, frames) {
1052
+ if (!name || COMMENT_OR_BLOCK.test(name) || /\s/.test(name) || !frames || typeof frames !== "object") return "";
1053
+ let body = "";
1054
+ for (const [step, props] of Object.entries(frames)) {
1055
+ if (COMMENT_OR_BLOCK.test(step) || !props || typeof props !== "object") return "";
1056
+ let decls = "";
1057
+ for (const [prop, value] of Object.entries(props)) {
1058
+ const v2 = String(value);
1059
+ if (COMMENT_OR_BLOCK.test(prop) || COMMENT_OR_BLOCK.test(v2)) return "";
1060
+ decls += ` ${prop}: ${v2};
1038
1061
  `;
1039
- for (const step in frames) {
1040
- css += ` ${step} {`;
1041
- const props = frames[step];
1042
- for (const prop in props) {
1043
- css += ` ${prop}: ${props[prop]};`;
1044
- }
1045
- css += " }\n";
1046
1062
  }
1047
- css += "}\n";
1063
+ body += ` ${step} {
1064
+ ${decls} }
1065
+ `;
1048
1066
  }
1049
- return css;
1067
+ return `@keyframes ${name} {
1068
+ ${body}}`;
1069
+ }
1070
+ function referencedKeyframes(css, ctx) {
1071
+ if (!css.includes("animation")) return [];
1072
+ const all = ctx.theme("keyframes");
1073
+ if (!all || typeof all !== "object") return [];
1074
+ const names = /* @__PURE__ */ new Set();
1075
+ for (const m of css.matchAll(/(?:^|[\s;{])animation(?:-name)?\s*:\s*([^;}]+)/g)) {
1076
+ const value = m[1].replace(/var\(--animate-([\w-]+)\)/g, (whole, key) => {
1077
+ const v2 = ctx.theme("animations", key) ?? ctx.theme("animation", key);
1078
+ return typeof v2 === "string" ? v2 : whole;
1079
+ });
1080
+ for (const word of value.split(/[\s,()]+/)) {
1081
+ if (word && Object.prototype.hasOwnProperty.call(all, word)) names.add(word);
1082
+ }
1083
+ }
1084
+ return [...names].map((n) => keyframesBlock(n, all[n])).filter(Boolean);
1050
1085
  }
1051
1086
  function transitionTimingFunctionToCssVars(transition) {
1052
1087
  const result = {};
@@ -1114,11 +1149,13 @@ function themeToCssVarsAll(theme) {
1114
1149
  ...borderRadiusToCssVars(theme.borderRadius),
1115
1150
  ...zIndexToCssVars(theme.zIndex),
1116
1151
  ...opacityToCssVars(theme.opacity),
1117
- ...animationToCssVars(theme.animations),
1152
+ ...animationToCssVars({ ...theme.animations, ...theme.animation }),
1118
1153
  ...transitionTimingFunctionToCssVars(theme.transitionTimingFunction),
1119
1154
  ...transitionDurationToCssVars(theme.transitionDuration),
1120
1155
  ...transitionDelayToCssVars(theme.transitionDelay),
1121
1156
  ...blurToCssVars(theme.blur),
1157
+ ...Object.fromEntries(Object.entries(theme.textShadow ?? {}).map(([k, v2]) => [`--text-shadow-${escapeKey(k)}`, v2])),
1158
+ ...Object.fromEntries(Object.entries(theme.dropShadow ?? {}).map(([k, v2]) => [`--drop-shadow-${escapeKey(k)}`, v2])),
1122
1159
  ...Object.fromEntries(Object.entries(theme.aspect ?? {}).map(([k, v2]) => [`--aspect-${escapeKey(k)}`, v2]))
1123
1160
  // keyframes handled separately
1124
1161
  };
@@ -1480,6 +1517,7 @@ function generateCssRules(classList, ctx, opts) {
1480
1517
  const css = rootToCss([node]);
1481
1518
  rootCssList.push(css);
1482
1519
  }
1520
+ rootCssList.push(...referencedKeyframes(cssList.join("\n"), ctx));
1483
1521
  return {
1484
1522
  cls,
1485
1523
  ast: allCleanAst,
@@ -1803,7 +1841,7 @@ const colors = {
1803
1841
  "950": "oklch(13% 0.028 261.692)"
1804
1842
  },
1805
1843
  zinc: {
1806
- "50": "oklch(98.5% 0 0)",
1844
+ "50": "oklch(98.5% 0 none)",
1807
1845
  "100": "oklch(96.7% 0.001 286.375)",
1808
1846
  "200": "oklch(92% 0.004 286.32)",
1809
1847
  "300": "oklch(87.1% 0.006 286.286)",
@@ -1816,17 +1854,17 @@ const colors = {
1816
1854
  "950": "oklch(14.1% 0.005 285.823)"
1817
1855
  },
1818
1856
  neutral: {
1819
- "50": "oklch(98.5% 0 0)",
1820
- "100": "oklch(97% 0 0)",
1821
- "200": "oklch(92.2% 0 0)",
1822
- "300": "oklch(87% 0 0)",
1823
- "400": "oklch(70.8% 0 0)",
1824
- "500": "oklch(55.6% 0 0)",
1825
- "600": "oklch(43.9% 0 0)",
1826
- "700": "oklch(37.1% 0 0)",
1827
- "800": "oklch(26.9% 0 0)",
1828
- "900": "oklch(20.5% 0 0)",
1829
- "950": "oklch(14.5% 0 0)"
1857
+ "50": "oklch(98.5% 0 none)",
1858
+ "100": "oklch(97% 0 none)",
1859
+ "200": "oklch(92.2% 0 none)",
1860
+ "300": "oklch(87% 0 none)",
1861
+ "400": "oklch(70.8% 0 none)",
1862
+ "500": "oklch(55.6% 0 none)",
1863
+ "600": "oklch(43.9% 0 none)",
1864
+ "700": "oklch(37.1% 0 none)",
1865
+ "800": "oklch(26.9% 0 none)",
1866
+ "900": "oklch(20.5% 0 none)",
1867
+ "950": "oklch(14.5% 0 none)"
1830
1868
  },
1831
1869
  stone: {
1832
1870
  "50": "oklch(98.5% 0.001 106.423)",
@@ -2061,6 +2099,58 @@ const colors = {
2061
2099
  "800": "oklch(45.5% 0.188 13.697)",
2062
2100
  "900": "oklch(41% 0.159 10.272)",
2063
2101
  "950": "oklch(27.1% 0.105 12.094)"
2102
+ },
2103
+ mauve: {
2104
+ "50": "oklch(98.5% 0 none)",
2105
+ "100": "oklch(96% 0.003 325.6)",
2106
+ "200": "oklch(92.2% 0.005 325.62)",
2107
+ "300": "oklch(86.5% 0.012 325.68)",
2108
+ "400": "oklch(71.1% 0.019 323.02)",
2109
+ "500": "oklch(54.2% 0.034 322.5)",
2110
+ "600": "oklch(43.5% 0.029 321.78)",
2111
+ "700": "oklch(36.4% 0.029 323.89)",
2112
+ "800": "oklch(26.3% 0.024 320.12)",
2113
+ "900": "oklch(21.2% 0.019 322.12)",
2114
+ "950": "oklch(14.5% 0.008 326)"
2115
+ },
2116
+ olive: {
2117
+ "50": "oklch(98.8% 0.003 106.5)",
2118
+ "100": "oklch(96.6% 0.005 106.5)",
2119
+ "200": "oklch(93% 0.007 106.5)",
2120
+ "300": "oklch(88% 0.011 106.6)",
2121
+ "400": "oklch(73.7% 0.021 106.9)",
2122
+ "500": "oklch(58% 0.031 107.3)",
2123
+ "600": "oklch(46.6% 0.025 107.3)",
2124
+ "700": "oklch(39.4% 0.023 107.4)",
2125
+ "800": "oklch(28.6% 0.016 107.4)",
2126
+ "900": "oklch(22.8% 0.013 107.4)",
2127
+ "950": "oklch(15.3% 0.006 107.1)"
2128
+ },
2129
+ mist: {
2130
+ "50": "oklch(98.7% 0.002 197.1)",
2131
+ "100": "oklch(96.3% 0.002 197.1)",
2132
+ "200": "oklch(92.5% 0.005 214.3)",
2133
+ "300": "oklch(87.2% 0.007 219.6)",
2134
+ "400": "oklch(72.3% 0.014 214.4)",
2135
+ "500": "oklch(56% 0.021 213.5)",
2136
+ "600": "oklch(45% 0.017 213.2)",
2137
+ "700": "oklch(37.8% 0.015 216)",
2138
+ "800": "oklch(27.5% 0.011 216.9)",
2139
+ "900": "oklch(21.8% 0.008 223.9)",
2140
+ "950": "oklch(14.8% 0.004 228.8)"
2141
+ },
2142
+ taupe: {
2143
+ "50": "oklch(98.6% 0.002 67.8)",
2144
+ "100": "oklch(96% 0.002 17.2)",
2145
+ "200": "oklch(92.2% 0.005 34.3)",
2146
+ "300": "oklch(86.8% 0.007 39.5)",
2147
+ "400": "oklch(71.4% 0.014 41.2)",
2148
+ "500": "oklch(54.7% 0.021 43.1)",
2149
+ "600": "oklch(43.8% 0.017 39.3)",
2150
+ "700": "oklch(36.7% 0.016 35.7)",
2151
+ "800": "oklch(26.8% 0.011 36.5)",
2152
+ "900": "oklch(21.4% 0.009 43.1)",
2153
+ "950": "oklch(14.7% 0.004 49.3)"
2064
2154
  }
2065
2155
  };
2066
2156
  const spacing = {
@@ -2132,8 +2222,13 @@ const fontSize = {
2132
2222
  };
2133
2223
  const fontFamily = {
2134
2224
  sans: [
2135
- "ui-sans-serif",
2136
- "system-ui",
2225
+ "-apple-system",
2226
+ "BlinkMacSystemFont",
2227
+ "Segoe UI",
2228
+ "Roboto",
2229
+ "Helvetica Neue",
2230
+ "Noto Sans",
2231
+ "Arial",
2137
2232
  "sans-serif",
2138
2233
  "Apple Color Emoji",
2139
2234
  "Segoe UI Emoji",
@@ -2276,11 +2371,7 @@ const keyframes = {
2276
2371
  }
2277
2372
  },
2278
2373
  ping: {
2279
- "75%": {
2280
- transform: "scale(2)",
2281
- opacity: "0"
2282
- },
2283
- "100%": {
2374
+ "75%, 100%": {
2284
2375
  transform: "scale(2)",
2285
2376
  opacity: "0"
2286
2377
  }
@@ -2290,14 +2381,15 @@ const keyframes = {
2290
2381
  opacity: "0.5"
2291
2382
  }
2292
2383
  },
2384
+ // #274: Tailwind 4.1.13's frames (0%/100% share the up position; 50% is the floor).
2293
2385
  bounce: {
2294
- "0%": {
2386
+ "0%, 100%": {
2295
2387
  transform: "translateY(-25%)",
2296
- "animation-timing-function": "cubic-bezier(0.8,0,1,1)"
2388
+ "animation-timing-function": "cubic-bezier(0.8, 0, 1, 1)"
2297
2389
  },
2298
- "100%": {
2390
+ "50%": {
2299
2391
  transform: "none",
2300
- "animation-timing-function": "cubic-bezier(0,0,0.2,1)"
2392
+ "animation-timing-function": "cubic-bezier(0, 0, 0.2, 1)"
2301
2393
  }
2302
2394
  }
2303
2395
  };
@@ -2347,6 +2439,21 @@ const blur = {
2347
2439
  "2xl": "40px",
2348
2440
  "3xl": "64px"
2349
2441
  };
2442
+ const textShadow = {
2443
+ "2xs": "0px 1px 0px rgb(0 0 0 / 0.15)",
2444
+ xs: "0px 1px 1px rgb(0 0 0 / 0.2)",
2445
+ sm: "0px 1px 0px rgb(0 0 0 / 0.075), 0px 1px 1px rgb(0 0 0 / 0.075), 0px 2px 2px rgb(0 0 0 / 0.075)",
2446
+ md: "0px 1px 1px rgb(0 0 0 / 0.1), 0px 1px 2px rgb(0 0 0 / 0.1), 0px 2px 4px rgb(0 0 0 / 0.1)",
2447
+ lg: "0px 1px 2px rgb(0 0 0 / 0.1), 0px 3px 2px rgb(0 0 0 / 0.1), 0px 4px 8px rgb(0 0 0 / 0.1)"
2448
+ };
2449
+ const dropShadow = {
2450
+ xs: "0 1px 1px rgb(0 0 0 / 0.05)",
2451
+ sm: "0 1px 2px rgb(0 0 0 / 0.15)",
2452
+ md: "0 3px 3px rgb(0 0 0 / 0.12)",
2453
+ lg: "0 4px 4px rgb(0 0 0 / 0.15)",
2454
+ xl: "0 9px 7px rgb(0 0 0 / 0.1)",
2455
+ "2xl": "0 25px 25px rgb(0 0 0 / 0.15)"
2456
+ };
2350
2457
  const defaultTheme = {
2351
2458
  colors,
2352
2459
  spacing,
@@ -2369,9 +2476,53 @@ const defaultTheme = {
2369
2476
  keyframes,
2370
2477
  animationVars,
2371
2478
  blur,
2479
+ textShadow,
2480
+ dropShadow,
2372
2481
  // Tailwind 4.1.13 --aspect-* (aspect-video → var(--aspect-video))
2373
2482
  aspect: { video: "16 / 9" }
2374
2483
  };
2484
+ const customUtilityName = /^[A-Za-z_][A-Za-z0-9_-]*$/;
2485
+ const customUtilityProp = /^(--[A-Za-z0-9_-]+|-?[A-Za-z][A-Za-z0-9-]*)$/;
2486
+ function validateCustomUtility(name, decls) {
2487
+ if (typeof name !== "string" || !customUtilityName.test(name)) return null;
2488
+ if (!decls || typeof decls !== "object" || Array.isArray(decls)) return null;
2489
+ const out = [];
2490
+ for (const [prop, raw] of Object.entries(decls)) {
2491
+ if (typeof raw !== "string" && typeof raw !== "number") return null;
2492
+ const value = String(raw).trim();
2493
+ if (!customUtilityProp.test(prop) || !value || !isStructureSafeValue(value) || hasCommentDelimiter(value)) return null;
2494
+ out.push([prop, value]);
2495
+ }
2496
+ return out.length ? out : null;
2497
+ }
2498
+ function registerCustomUtilities(ctx, utilities) {
2499
+ if (!utilities || typeof utilities !== "object" || Array.isArray(utilities)) return;
2500
+ const list = getUtility(ctx);
2501
+ const builtins = [...list];
2502
+ const before = list.length;
2503
+ for (const [name, decls] of Object.entries(utilities)) {
2504
+ const safe = validateCustomUtility(name, decls);
2505
+ if (!safe) {
2506
+ debugWarn(`[BAROCSS] Ignoring invalid custom utility "${name}"`);
2507
+ continue;
2508
+ }
2509
+ const shadowed = builtins.filter((u) => u.match(name));
2510
+ registerUtility({
2511
+ name,
2512
+ category: "custom",
2513
+ match: (className) => className === name,
2514
+ handler: (value, c, token) => {
2515
+ let base = [];
2516
+ for (const reg of shadowed) {
2517
+ base = reg.handler(value, c, token, reg) || [];
2518
+ if (base.length > 0) break;
2519
+ }
2520
+ return [...base, ...safe.map(([prop, v]) => decl(prop, v))];
2521
+ }
2522
+ }, ctx);
2523
+ }
2524
+ if (list.length > before) list.unshift(...list.splice(before));
2525
+ }
2375
2526
  const preflightMinimalCSS = `
2376
2527
  /* BaroCSS Preflight - Minimal Reset */
2377
2528
  /* ================================= */
@@ -2503,7 +2654,7 @@ html {
2503
2654
  line-height: 1.15;
2504
2655
  -webkit-text-size-adjust: 100%;
2505
2656
  /* Tailwind 4.1.13 root font (app --default-font-family / --font-sans win) */
2506
- font-family: var(--default-font-family, var(--font-sans, ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'));
2657
+ font-family: var(--default-font-family, var(--font-sans, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', 'Noto Sans', Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'));
2507
2658
  font-feature-settings: var(--default-font-feature-settings, normal);
2508
2659
  font-variation-settings: var(--default-font-variation-settings, normal);
2509
2660
  }
@@ -2806,7 +2957,7 @@ html {
2806
2957
  -webkit-text-size-adjust: 100%;
2807
2958
  -ms-text-size-adjust: 100%;
2808
2959
  /* Tailwind 4.1.13 root font (app --default-font-family / --font-sans win) */
2809
- font-family: var(--default-font-family, var(--font-sans, ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'));
2960
+ font-family: var(--default-font-family, var(--font-sans, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', 'Noto Sans', Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'));
2810
2961
  font-feature-settings: var(--default-font-feature-settings, normal);
2811
2962
  font-variation-settings: var(--default-font-variation-settings, normal);
2812
2963
  }
@@ -3254,9 +3405,7 @@ function resolveTheme(config) {
3254
3405
  }
3255
3406
  function themeToCssVars(theme) {
3256
3407
  const vars = themeToCssVarsAll(theme);
3257
- const result = toCssVarsBlock(vars, `
3258
- ${keyframesToCss(theme.keyframes || {})}
3259
- `);
3408
+ const result = toCssVarsBlock(vars);
3260
3409
  return result;
3261
3410
  }
3262
3411
  function createContext(configObj) {
@@ -3310,6 +3459,7 @@ function createContext(configObj) {
3310
3459
  }
3311
3460
  };
3312
3461
  initializeContextState(ctx, getUtility(), getModifier());
3462
+ registerCustomUtilities(ctx, configObj.utilities);
3313
3463
  return ctx;
3314
3464
  }
3315
3465
  function parseFraction(input) {
@@ -3708,6 +3858,9 @@ staticUtility("snap-both", [["scroll-snap-type", "both var(--baro-scroll-snap-st
3708
3858
  staticUtility("snap-mandatory", [["--baro-scroll-snap-strictness", "mandatory"]], { category: "interactivity" });
3709
3859
  staticUtility("snap-proximity", [["--baro-scroll-snap-strictness", "proximity"]], { category: "interactivity" });
3710
3860
  [
3861
+ ["mbs", "scroll-margin-block-start"],
3862
+ // #311 (Tailwind 4.3), before `mb`
3863
+ ["mbe", "scroll-margin-block-end"],
3711
3864
  ["mt", "scroll-margin-top"],
3712
3865
  ["mr", "scroll-margin-right"],
3713
3866
  ["mb", "scroll-margin-bottom"],
@@ -3718,6 +3871,8 @@ staticUtility("snap-proximity", [["--baro-scroll-snap-strictness", "proximity"]]
3718
3871
  ["me", "scroll-margin-inline-end"],
3719
3872
  ["m", "scroll-margin"]
3720
3873
  ].forEach(([name, prop]) => {
3874
+ staticUtility(`scroll-${name}-px`, [[prop, "1px"]], { category: "interactivity" });
3875
+ staticUtility(`-scroll-${name}-px`, [[prop, "-1px"]], { category: "interactivity" });
3721
3876
  functionalUtility({
3722
3877
  name: `scroll-${name}`,
3723
3878
  spacingKeys: true,
@@ -3736,6 +3891,9 @@ staticUtility("snap-proximity", [["--baro-scroll-snap-strictness", "proximity"]]
3736
3891
  });
3737
3892
  });
3738
3893
  [
3894
+ ["pbs", "scroll-padding-block-start"],
3895
+ // #311 (Tailwind 4.3), before `pb`
3896
+ ["pbe", "scroll-padding-block-end"],
3739
3897
  ["pt", "scroll-padding-top"],
3740
3898
  ["pr", "scroll-padding-right"],
3741
3899
  ["pb", "scroll-padding-bottom"],
@@ -3752,13 +3910,15 @@ staticUtility("snap-proximity", [["--baro-scroll-snap-strictness", "proximity"]]
3752
3910
  prop,
3753
3911
  supportsArbitrary: true,
3754
3912
  supportsCustomProperty: true,
3913
+ handleBareValue: ({ value }) => value === "px" ? "1px" : /^(\d|\.\d)/.test(value) ? value : null,
3755
3914
  handle: (value, _ctx, token, _extra) => {
3756
- if (parseNumber(value) || token.negative) {
3915
+ if (token.negative) return [];
3916
+ if (parseNumber(value)) {
3757
3917
  return [decl(prop, `calc(var(--spacing) * ${value})`)];
3758
3918
  }
3759
3919
  return [decl(prop, value)];
3760
3920
  },
3761
- handleCustomProperty: (value) => [decl(prop, `var(${value})`)],
3921
+ handleCustomProperty: (value, _ctx, token) => token.negative ? [] : [decl(prop, `var(${value})`)],
3762
3922
  description: `scroll-${name} utility (static, arbitrary, custom property supported)`,
3763
3923
  category: "interactivity"
3764
3924
  });
@@ -3789,6 +3949,40 @@ functionalUtility({
3789
3949
  description: "will-change utility (static, arbitrary, custom property supported)",
3790
3950
  category: "interactivity"
3791
3951
  });
3952
+ staticUtility("scrollbar-auto", [["scrollbar-width", "auto"]], { category: "interactivity" });
3953
+ staticUtility("scrollbar-thin", [["scrollbar-width", "thin"]], { category: "interactivity" });
3954
+ staticUtility("scrollbar-none", [["scrollbar-width", "none"]], { category: "interactivity" });
3955
+ staticUtility("scrollbar-gutter-auto", [["scrollbar-gutter", "auto"]], { category: "interactivity" });
3956
+ staticUtility("scrollbar-gutter-stable", [["scrollbar-gutter", "stable"]], { category: "interactivity" });
3957
+ staticUtility("scrollbar-gutter-both", [["scrollbar-gutter", "stable both-edges"]], { category: "interactivity" });
3958
+ const SCROLLBAR_COLOR = "var(--baro-scrollbar-thumb) var(--baro-scrollbar-track)";
3959
+ const scrollbarProperties = () => atRoot([
3960
+ property("--baro-scrollbar-thumb", "#0000", "<color>"),
3961
+ property("--baro-scrollbar-track", "#0000", "<color>")
3962
+ ]);
3963
+ const stripColorHint = (v) => v.replace(/^color:/, "");
3964
+ for (const part of ["thumb", "track"]) {
3965
+ const key = `--baro-scrollbar-${part}`;
3966
+ const compose = (inner) => [scrollbarProperties(), ...inner, decl("scrollbar-color", SCROLLBAR_COLOR)];
3967
+ const withOpacity = (color, opacity2) => opacity2 ? [decl(key, `color-mix(in oklab, ${color} ${opacity2.replace(/^\[(.*)\]$/, "$1").replace(/%$/, "")}%, transparent)`)] : [decl(key, color)];
3968
+ functionalUtility({
3969
+ name: `scrollbar-${part}`,
3970
+ themeKeys: ["colors"],
3971
+ supportsOpacity: true,
3972
+ supportsArbitrary: true,
3973
+ supportsCustomProperty: true,
3974
+ handle: (value, _ctx, token, extra) => {
3975
+ if (extra?.realThemeValue) return compose(withOpacity(`var(--color-${extra.realThemeValue})`, extra.opacity));
3976
+ if (token.arbitrary) return compose(withOpacity(stripColorHint(value), extra?.opacity));
3977
+ if (value === "inherit" || value === "transparent") return compose([decl(key, value)]);
3978
+ if (value === "current") return compose(withOpacity("currentcolor", extra?.opacity));
3979
+ return null;
3980
+ },
3981
+ handleCustomProperty: (value, _ctx, _token, extra) => compose(withOpacity(`var(${stripColorHint(value)})`, extra?.opacity)),
3982
+ description: `scrollbar-color ${part} utility (theme, arbitrary, custom property, opacity)`,
3983
+ category: "interactivity"
3984
+ });
3985
+ }
3792
3986
  const defaultTiming = "var(--default-transition-timing-function)";
3793
3987
  const defaultDuration = "var(--default-transition-duration)";
3794
3988
  staticUtility("transition", [
@@ -3907,10 +4101,12 @@ staticUtility("animate-bounce", [["animation", "var(--animate-bounce)"]], { cate
3907
4101
  staticUtility("animate-none", [["animation", "none"]], { category: "transitions" });
3908
4102
  functionalUtility({
3909
4103
  name: "animate",
3910
- prop: "animation",
4104
+ // #274: theme.animations (and Tailwind's theme.animation) names, e.g. theme.extend.animation.wiggle.
4105
+ themeKeys: ["animations", "animation"],
3911
4106
  supportsArbitrary: true,
3912
4107
  supportsCustomProperty: true,
3913
- handle: (value, ctx, token) => {
4108
+ handle: (value, ctx, token, extra) => {
4109
+ if (extra?.realThemeValue) return [decl("animation", `var(--animate-${extra.realThemeValue})`)];
3914
4110
  if (token.customProperty) {
3915
4111
  return [decl("animation", `var(${value})`)];
3916
4112
  }
@@ -3924,53 +4120,99 @@ staticUtility("border-collapse", [["border-collapse", "collapse"]], { category:
3924
4120
  staticUtility("border-separate", [["border-collapse", "separate"]], { category: "table" });
3925
4121
  staticUtility("table-auto", [["table-layout", "auto"]], { category: "table" });
3926
4122
  staticUtility("table-fixed", [["table-layout", "fixed"]], { category: "table" });
3927
- functionalUtility({
3928
- name: "border-spacing-x",
3929
- prop: "border-spacing",
3930
- supportsArbitrary: true,
3931
- supportsCustomProperty: true,
3932
- handle: (value, _ctx, _token) => {
3933
- if (parseNumber(value)) {
3934
- return [decl("border-spacing", `calc(var(--spacing) * ${value}) var(--baro-border-spacing-y)`)];
3935
- }
3936
- return [decl("border-spacing", `${value} var(--baro-border-spacing-y)`)];
3937
- },
3938
- handleCustomProperty: (value) => [decl("border-spacing", `var(${value}) var(--baro-border-spacing-y)`)],
3939
- description: "border-spacing-x utility (static, number, arbitrary, custom property supported)",
3940
- category: "table"
3941
- });
3942
- functionalUtility({
3943
- name: "border-spacing-y",
3944
- prop: "border-spacing",
3945
- supportsArbitrary: true,
3946
- supportsCustomProperty: true,
3947
- handle: (value, _ctx, _token) => {
3948
- if (parseNumber(value)) {
3949
- return [decl("border-spacing", `var(--baro-border-spacing-x) calc(var(--spacing) * ${value})`)];
3950
- }
3951
- return [decl("border-spacing", `var(--baro-border-spacing-x) ${value}`)];
3952
- },
3953
- handleCustomProperty: (value) => [decl("border-spacing", `var(--baro-border-spacing-x) var(${value})`)],
3954
- description: "border-spacing-y utility (static, number, arbitrary, custom property supported)",
3955
- category: "table"
3956
- });
3957
- functionalUtility({
3958
- name: "border-spacing",
3959
- prop: "border-spacing",
3960
- supportsArbitrary: true,
3961
- supportsCustomProperty: true,
3962
- handle: (value, _ctx, _token) => {
3963
- if (parseNumber(value)) {
3964
- return [decl("border-spacing", `calc(var(--spacing) * ${value})`)];
3965
- }
3966
- return [decl("border-spacing", value)];
3967
- },
3968
- handleCustomProperty: (value) => [decl("border-spacing", `var(${value})`)],
3969
- description: "border-spacing utility (static, number, arbitrary, custom property supported)",
3970
- category: "table"
4123
+ const borderSpacingProperties = () => atRoot([
4124
+ property("--baro-border-spacing-x", "0", "<length>"),
4125
+ property("--baro-border-spacing-y", "0", "<length>")
4126
+ ]);
4127
+ const BORDER_SPACING = "var(--baro-border-spacing-x) var(--baro-border-spacing-y)";
4128
+ const borderSpacing = (axes, v) => [
4129
+ borderSpacingProperties(),
4130
+ ...axes.map((a) => decl(`--baro-border-spacing-${a}`, v)),
4131
+ decl("border-spacing", BORDER_SPACING)
4132
+ ];
4133
+ [
4134
+ ["border-spacing-x", ["x"]],
4135
+ ["border-spacing-y", ["y"]],
4136
+ ["border-spacing", ["x", "y"]]
4137
+ ].forEach(([name, axes]) => {
4138
+ staticUtility(`${name}-px`, [
4139
+ borderSpacingProperties,
4140
+ ...axes.map((a) => [`--baro-border-spacing-${a}`, "1px"]),
4141
+ ["border-spacing", BORDER_SPACING]
4142
+ ], { category: "table" });
4143
+ functionalUtility({
4144
+ name,
4145
+ prop: "border-spacing",
4146
+ supportsArbitrary: true,
4147
+ supportsCustomProperty: true,
4148
+ handle: (value) => borderSpacing(axes, parseNumber(value) ? `calc(var(--spacing) * ${value})` : value),
4149
+ handleCustomProperty: (value) => borderSpacing(axes, `var(${value})`),
4150
+ description: `${name} utility (number, px, arbitrary, custom property supported)`,
4151
+ category: "table"
4152
+ });
3971
4153
  });
3972
4154
  staticUtility("caption-top", [["caption-side", "top"]], { category: "table" });
3973
4155
  staticUtility("caption-bottom", [["caption-side", "bottom"]], { category: "table" });
4156
+ function parseAlpha(op) {
4157
+ if (!op) return null;
4158
+ if (/^\d+(\.\d+)?$/.test(op)) return { alpha: `${op}%`, isVar: false };
4159
+ const pct = /^\[(\d+(?:\.\d+)?)%\]$/.exec(op);
4160
+ if (pct) return { alpha: `${pct[1]}%`, isVar: false };
4161
+ const cp = /^\((--[\w-]+)\)$/.exec(op);
4162
+ if (cp) return { alpha: `var(${cp[1]})`, isVar: true };
4163
+ return null;
4164
+ }
4165
+ function splitTop(value, sep) {
4166
+ const out = [];
4167
+ let depth = 0;
4168
+ let cur = "";
4169
+ for (const ch of value) {
4170
+ if (ch === "(") depth++;
4171
+ else if (ch === ")") depth--;
4172
+ if (depth === 0 && (sep === " " ? /\s/.test(ch) : ch === sep)) {
4173
+ if (cur.trim()) out.push(cur.trim());
4174
+ cur = "";
4175
+ } else cur += ch;
4176
+ }
4177
+ if (cur.trim()) out.push(cur.trim());
4178
+ return out;
4179
+ }
4180
+ const LENGTH = /^-?(\d*\.)?\d+([a-z]+|%)?$/i;
4181
+ function shadowLayers(value, layer, alpha) {
4182
+ return splitTop(value, ",").map((l) => {
4183
+ const parts = splitTop(l, " ");
4184
+ const i = parts.findIndex((p) => p !== "inset" && !LENGTH.test(p));
4185
+ const c = i < 0 ? "currentcolor" : parts[i];
4186
+ parts[i < 0 ? parts.length : i] = `var(--baro-${layer}-color, ${alpha ? `oklab(from ${c} l a b / ${alpha})` : c})`;
4187
+ return parts.join(" ");
4188
+ });
4189
+ }
4190
+ function shadowValueDecls(layer, prop, value, opacity2, render = (l) => l.join(", ")) {
4191
+ const a = parseAlpha(opacity2);
4192
+ if (opacity2 && !a) return null;
4193
+ if (!a) return [decl(prop, render(shadowLayers(value, layer)))];
4194
+ const alphaDecl = decl(`--baro-${layer}-alpha`, a.alpha);
4195
+ if (!a.isVar) return [alphaDecl, decl(prop, render(shadowLayers(value, layer, a.alpha)))];
4196
+ return [
4197
+ alphaDecl,
4198
+ decl(prop, render(shadowLayers(value, layer))),
4199
+ atRule("supports", "(color: lab(from red l a b))", [decl(prop, render(shadowLayers(value, layer, a.alpha)))])
4200
+ ];
4201
+ }
4202
+ function shadowColorDecls(layer, color, opacity2, ref = color) {
4203
+ const key = `--baro-${layer}-color`;
4204
+ if (color === "inherit") return [decl(key, "inherit")];
4205
+ const a = parseAlpha(opacity2);
4206
+ if (opacity2 && !a) return null;
4207
+ const inner = a ? `color-mix(in oklab, ${ref} ${a.alpha}, transparent)` : ref;
4208
+ const fallback = a ? `color-mix(in srgb, ${color} ${a.alpha}, transparent)` : color;
4209
+ return [
4210
+ decl(key, fallback),
4211
+ atRule("supports", "(color: color-mix(in lab, red, red))", [
4212
+ decl(key, `color-mix(in oklab, ${inner} var(--baro-${layer}-alpha), transparent)`)
4213
+ ])
4214
+ ];
4215
+ }
3974
4216
  staticUtility("filter-none", [["filter", "none"]], { category: "effects" });
3975
4217
  functionalUtility({
3976
4218
  name: "filter",
@@ -4055,57 +4297,68 @@ functionalUtility({
4055
4297
  description: "contrast filter utility (static, number, arbitrary, custom property supported)",
4056
4298
  category: "effects"
4057
4299
  });
4058
- [
4059
- ["drop-shadow-xs", "xs", "0 1px 1px var(--baro-drop-shadow-color, #0000001a)"],
4060
- ["drop-shadow-sm", "sm", "0 1px 2px var(--baro-drop-shadow-color, #0000001a)"],
4061
- ["drop-shadow-md", "md", "0 3px 3px var(--baro-drop-shadow-color, #0000001a)"],
4062
- ["drop-shadow-lg", "lg", "0 4px 4px var(--baro-drop-shadow-color, #0000001a)"],
4063
- ["drop-shadow-xl", "xl", "0 9px 7px var(--baro-drop-shadow-color, #0000001a)"],
4064
- ["drop-shadow-2xl", "2xl", "0 25px 25px var(--baro-drop-shadow-color, #0000001a)"]
4065
- ].forEach(([name, size, sizeValue]) => {
4066
- staticUtility(name, [
4067
- decl("--baro-drop-shadow-size", `drop-shadow(${sizeValue})`),
4068
- decl("--baro-drop-shadow", `var(--drop-shadow-${size})`),
4069
- filters$1()
4070
- ]);
4071
- });
4072
- staticUtility("drop-shadow-none", [decl("--baro-drop-shadow", "drop-shadow(0 0 #0000)"), filters$1()]);
4073
- ["inherit", "current", "transparent"].forEach((name) => {
4074
- staticUtility(`drop-shadow-${name}`, [
4075
- decl("--baro-drop-shadow-color", name === "current" ? "currentColor" : name)
4076
- ]);
4077
- });
4078
- ["black", "white"].forEach((name) => {
4079
- staticUtility(`drop-shadow-${name}`, [
4080
- decl("--baro-drop-shadow-color", `var(--color-${name})`)
4081
- ]);
4300
+ const dropShadowProperties = () => atRoot([
4301
+ property("--baro-drop-shadow"),
4302
+ property("--baro-drop-shadow-color"),
4303
+ property("--baro-drop-shadow-alpha", "100%", "<percentage>"),
4304
+ property("--baro-drop-shadow-size")
4305
+ ]);
4306
+ const wrapDropShadow = (layers) => layers.map((l) => `drop-shadow(${l})`).join(" ");
4307
+ const DROP_SHADOW_DEFAULT = "0 1px 2px rgb(0 0 0 / 0.1), 0 1px 1px rgb(0 0 0 / 0.06)";
4308
+ const namedDropShadow = (ctx, name) => {
4309
+ const v = ctx.theme("dropShadow", name);
4310
+ return typeof v === "string" && /^[\w.-]+$/.test(name) ? v : null;
4311
+ };
4312
+ function dropShadowValue(value, opacity2, named, keepNamed = false) {
4313
+ const decls = shadowValueDecls("drop-shadow", "--baro-drop-shadow-size", value, opacity2, wrapDropShadow);
4314
+ if (!decls) return null;
4315
+ const composed = named !== void 0 && (!opacity2 || keepNamed) ? named : "var(--baro-drop-shadow-size)";
4316
+ return [dropShadowProperties(), ...decls, decl("--baro-drop-shadow", composed), filters$1()];
4317
+ }
4318
+ staticUtility("drop-shadow-none", [decl("--baro-drop-shadow", " "), filters$1()]);
4319
+ registerUtility({
4320
+ name: "drop-shadow",
4321
+ match: (className) => /^drop-shadow(\/.+)?$/.test(className),
4322
+ handler: (value, _ctx, token) => {
4323
+ const full = value ? `${token.prefix}-${value}` : token.prefix;
4324
+ const cut = full.indexOf("/");
4325
+ const opacity2 = cut < 0 ? void 0 : full.slice(cut + 1);
4326
+ const literal = "drop-shadow(0 1px 2px rgb(0 0 0 / 0.1)) drop-shadow( 0 1px 1px rgb(0 0 0 / 0.06))";
4327
+ return dropShadowValue(DROP_SHADOW_DEFAULT, opacity2, literal, true) ?? [];
4328
+ },
4329
+ category: "effects"
4082
4330
  });
4331
+ const dropShadowColor = (color, opacity2, ref) => {
4332
+ const decls = shadowColorDecls("drop-shadow", color, opacity2, ref);
4333
+ return decls && [dropShadowProperties(), ...decls, decl("--baro-drop-shadow", "var(--baro-drop-shadow-size)")];
4334
+ };
4083
4335
  functionalUtility({
4084
4336
  name: "drop-shadow",
4085
4337
  themeKeys: ["colors"],
4086
4338
  supportsArbitrary: true,
4087
4339
  supportsCustomProperty: true,
4088
- handle: (value, _ctx, _token, extra) => {
4089
- if (extra?.realThemeValue) {
4090
- return [decl("--baro-drop-shadow-color", `var(--color-${extra.realThemeValue})`)];
4091
- }
4092
- if (parseColor(value)) {
4093
- return [decl("--baro-drop-shadow-color", value)];
4340
+ supportsOpacity: true,
4341
+ handleBareValue: ({ value, ctx }) => namedDropShadow(ctx, value) ? value : null,
4342
+ handle: (value, ctx, token, extra) => {
4343
+ const opacity2 = extra?.opacity;
4344
+ const keyword = token.arbitrary ? void 0 : { inherit: "inherit", current: "currentcolor", transparent: "transparent" }[extra?.realThemeValue ?? value];
4345
+ if (keyword) return dropShadowColor(keyword, opacity2);
4346
+ if (extra?.realThemeValue) return dropShadowColor(value, opacity2, `var(--color-${extra.realThemeValue})`);
4347
+ if (token.arbitrary) {
4348
+ if (parseColor(value)) return dropShadowColor(value, opacity2);
4349
+ return dropShadowValue(value, opacity2);
4094
4350
  }
4095
- return [
4096
- decl("--baro-drop-shadow-size", `drop-shadow(${value})`),
4097
- decl("--baro-drop-shadow", `var(--baro-drop-shadow-size)`)
4098
- ];
4351
+ const named = namedDropShadow(ctx, value);
4352
+ if (named) return dropShadowValue(named, opacity2, `drop-shadow(var(--drop-shadow-${value}))`);
4353
+ return null;
4099
4354
  },
4100
4355
  handleCustomProperty: (value) => {
4101
- if (value.startsWith("color:")) {
4102
- return [
4103
- decl("--baro-drop-shadow-color", `var(${value.replace("color:", "")})`)
4104
- ];
4105
- }
4356
+ if (value.startsWith("color:")) return dropShadowColor(`var(${value.slice(6)})`, void 0) ?? [];
4106
4357
  return [
4358
+ dropShadowProperties(),
4107
4359
  decl("--baro-drop-shadow-size", `drop-shadow(var(${value}))`),
4108
- decl("--baro-drop-shadow", `var(--baro-drop-shadow-size)`)
4360
+ decl("--baro-drop-shadow", `var(--baro-drop-shadow-size)`),
4361
+ filters$1()
4109
4362
  ];
4110
4363
  },
4111
4364
  description: "drop-shadow filter utility (static, arbitrary, custom property supported)",
@@ -4475,166 +4728,119 @@ const ringShadowProperties = () => atRoot([
4475
4728
  property("--baro-ring-offset-width", "0px", "<length>"),
4476
4729
  property("--baro-ring-offset-color", "#fff")
4477
4730
  ]);
4478
- const shadowLayer = (value) => [
4479
- ringShadowProperties(),
4480
- decl("--baro-shadow", value),
4481
- decl("box-shadow", SHADOW_COMPOSITE)
4482
- ];
4483
- [
4484
- ["shadow-2xs", "var(--shadow-2xs)"],
4485
- ["shadow-xs", "var(--shadow-xs)"],
4486
- ["shadow-sm", "var(--shadow-sm)"],
4487
- ["shadow", "0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)"],
4488
- ["shadow-md", "var(--shadow-md)"],
4489
- ["shadow-lg", "var(--shadow-lg)"],
4490
- ["shadow-xl", "var(--shadow-xl)"],
4491
- ["shadow-2xl", "var(--shadow-2xl)"],
4492
- ["shadow-none", "0 0 #0000"]
4493
- ].forEach(([name, value]) => {
4494
- staticUtility(name, [
4495
- ringShadowProperties,
4496
- ["--baro-shadow", value],
4497
- ["box-shadow", SHADOW_COMPOSITE]
4498
- ], { category: "effects" });
4499
- });
4500
- [
4501
- ["inset-shadow-2xs", "inset 0 1px var(--baro-inset-shadow-color, rgb(0 0 0 / 0.05))"],
4502
- ["inset-shadow-xs", "inset 0 1px 1px var(--baro-inset-shadow-color, rgb(0 0 0 / 0.05))"],
4503
- ["inset-shadow-sm", "inset 0 2px 4px var(--baro-inset-shadow-color, rgb(0 0 0 / 0.05))"],
4504
- ["inset-shadow-md", "inset 0 4px 6px -1px var(--baro-inset-shadow-color, rgb(0 0 0 / 0.05))"],
4505
- ["inset-shadow-lg", "inset 0 10px 15px -3px var(--baro-inset-shadow-color, rgb(0 0 0 / 0.05))"],
4506
- ["inset-shadow-xl", "inset 0 20px 25px -5px var(--baro-inset-shadow-color, rgb(0 0 0 / 0.05))"],
4507
- ["inset-shadow-2xl", "inset 0 25px 50px -12px var(--baro-inset-shadow-color, rgb(0 0 0 / 0.05))"],
4508
- ["inset-shadow-none", "0 0 #0000"]
4509
- ].forEach(([name, value]) => {
4510
- staticUtility(name, [
4511
- ringShadowProperties,
4512
- ["--baro-inset-shadow", value],
4513
- ["box-shadow", SHADOW_COMPOSITE]
4514
- ], { category: "effects" });
4515
- });
4516
- function createShadowThemeColor(key, main, opacity2, realThemeValue) {
4517
- let fallbackColor = main;
4518
- const colorVar = `var(--color-${realThemeValue})`;
4519
- let colorValue = colorVar;
4520
- if (opacity2) {
4521
- colorValue = `color-mix(in oklab, color-mix(in oklab, ${colorVar} ${opacity2}%, transparent) var(--baro-shadow-alpha),transparent)`;
4522
- if (parseColor(main)) {
4523
- if (main.startsWith("#")) {
4524
- const opacityValue = Math.round(Number(opacity2) / 100 * 255);
4525
- fallbackColor = `${main}${opacityValue.toString(16).padStart(2, "0")}`;
4526
- } else {
4527
- fallbackColor = `color-mix(in oklab, ${main} ${opacity2}%, transparent)`;
4528
- }
4529
- }
4530
- }
4531
- return [
4532
- atRule("supports", "(color:color-mix(in lab, red, red))", [
4533
- decl(key, colorValue)
4534
- ]),
4535
- decl(key, fallbackColor)
4536
- ];
4731
+ const shadowColorProperties = (layer) => atRoot([
4732
+ property(`--baro-${layer}-color`),
4733
+ property(`--baro-${layer}-alpha`, "100%", "<percentage>")
4734
+ ]);
4735
+ const NAMED_SHADOWS = {
4736
+ "": "0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)",
4737
+ "2xs": "0 1px rgb(0 0 0 / 0.05)",
4738
+ xs: "0 1px 2px 0 rgb(0 0 0 / 0.05)",
4739
+ sm: "0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)",
4740
+ md: "0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1)",
4741
+ lg: "0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1)",
4742
+ xl: "0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1)",
4743
+ "2xl": "0 25px 50px -12px rgb(0 0 0 / 0.25)",
4744
+ inner: "inset 0 2px 4px 0 rgb(0 0 0 / 0.05)"
4745
+ };
4746
+ const NAMED_INSET_SHADOWS = {
4747
+ "2xs": "inset 0 1px rgb(0 0 0 / 0.05)",
4748
+ xs: "inset 0 1px 1px rgb(0 0 0 / 0.05)",
4749
+ sm: "inset 0 2px 4px rgb(0 0 0 / 0.05)"
4750
+ };
4751
+ const INSET_EXTENSIONS = {
4752
+ md: "inset 0 4px 6px -1px rgb(0 0 0 / 0.05)",
4753
+ lg: "inset 0 10px 15px -3px rgb(0 0 0 / 0.05)",
4754
+ xl: "inset 0 20px 25px -5px rgb(0 0 0 / 0.05)",
4755
+ "2xl": "inset 0 25px 50px -12px rgb(0 0 0 / 0.05)"
4756
+ };
4757
+ const insetEach = (value) => value.split(/,(?![^(]*\))/).map((l) => `inset ${l.trim()}`).join(", ");
4758
+ const own = (table, key) => Object.prototype.hasOwnProperty.call(table, key);
4759
+ function boxShadowLayer(layer, value, opacity2) {
4760
+ const decls = shadowValueDecls(layer, `--baro-${layer}`, value, opacity2);
4761
+ if (!decls) return null;
4762
+ return [ringShadowProperties(), shadowColorProperties(layer), ...decls, decl("box-shadow", SHADOW_COMPOSITE)];
4763
+ }
4764
+ function namedBoxShadow(layer, name, opacity2) {
4765
+ if (layer === "shadow") return own(NAMED_SHADOWS, name) ? boxShadowLayer(layer, NAMED_SHADOWS[name], opacity2) : null;
4766
+ if (own(NAMED_INSET_SHADOWS, name)) return boxShadowLayer(layer, NAMED_INSET_SHADOWS[name], opacity2);
4767
+ if (!opacity2 && own(INSET_EXTENSIONS, name)) return boxShadowLayer(layer, INSET_EXTENSIONS[name], void 0);
4768
+ return null;
4537
4769
  }
4538
- functionalUtility({
4770
+ staticUtility("shadow-none", [ringShadowProperties, ["--baro-shadow", "0 0 #0000"], ["box-shadow", SHADOW_COMPOSITE]], { category: "effects" });
4771
+ staticUtility("inset-shadow-none", [ringShadowProperties, ["--baro-inset-shadow", "inset 0 0 #0000"], ["box-shadow", SHADOW_COMPOSITE]], { category: "effects" });
4772
+ registerUtility({
4539
4773
  name: "shadow",
4540
- supportsArbitrary: true,
4541
- supportsCustomProperty: true,
4542
- supportsOpacity: true,
4543
- themeKeys: ["colors", "shadows"],
4544
- handle: (value, ctx, token, extra) => {
4545
- const main = value;
4546
- const opacity2 = extra?.opacity;
4547
- const realThemeValue = extra?.realThemeValue;
4548
- if (realThemeValue) {
4549
- return createShadowThemeColor(
4550
- "--baro-shadow-color",
4551
- main,
4552
- opacity2,
4553
- realThemeValue
4554
- );
4555
- }
4556
- if (main.startsWith("color:")) {
4557
- const cp = main.replace("color:", "");
4558
- if (opacity2) {
4559
- return [
4560
- decl(
4561
- "--baro-shadow-color",
4562
- `color-mix(in oklab, var(${cp}) ${opacity2}%, transparent)`
4563
- )
4564
- ];
4565
- }
4566
- return [decl("--baro-shadow-color", `var(${cp})`)];
4567
- }
4568
- if (token.arbitrary) {
4569
- if (parseColor(main)) {
4570
- if (opacity2) {
4571
- return [
4572
- decl(
4573
- "--baro-shadow-color",
4574
- `color-mix(in oklab, ${main} ${opacity2}%, transparent)`
4575
- )
4576
- ];
4577
- }
4578
- return [decl("--baro-shadow-color", main)];
4579
- }
4580
- return shadowLayer(main);
4581
- }
4582
- if (main === "inherit" || main === "current" || main === "transparent") {
4583
- return [
4584
- decl("--baro-shadow-color", main === "current" ? "currentColor" : main)
4585
- ];
4586
- }
4587
- return null;
4774
+ match: (className) => /^shadow(\/.+)?$/.test(className),
4775
+ handler: (value, _ctx, token) => {
4776
+ const full = value ? `${token.prefix}-${value}` : token.prefix;
4777
+ const cut = full.indexOf("/");
4778
+ return namedBoxShadow("shadow", "", cut < 0 ? void 0 : full.slice(cut + 1)) ?? [];
4588
4779
  },
4589
- handleCustomProperty: (value) => shadowLayer(`var(${value})`)
4780
+ category: "effects"
4590
4781
  });
4782
+ const KEYWORD_COLORS = { inherit: "inherit", current: "currentcolor", transparent: "transparent" };
4783
+ function layerColor(layer, main, opacity2, token, realThemeValue) {
4784
+ const keyword = token.arbitrary ? void 0 : KEYWORD_COLORS[realThemeValue ?? main];
4785
+ if (keyword) return shadowColorDecls(layer, keyword, opacity2);
4786
+ if (realThemeValue) return shadowColorDecls(layer, main, opacity2, `var(--color-${realThemeValue})`);
4787
+ if (main.startsWith("color:")) return shadowColorDecls(layer, `var(${main.slice(6)})`, opacity2);
4788
+ if (token.arbitrary && parseColor(main)) return shadowColorDecls(layer, main, opacity2);
4789
+ return void 0;
4790
+ }
4791
+ for (const layer of ["shadow", "inset-shadow"]) {
4792
+ functionalUtility({
4793
+ name: layer,
4794
+ supportsArbitrary: true,
4795
+ supportsCustomProperty: true,
4796
+ supportsOpacity: true,
4797
+ themeKeys: ["colors"],
4798
+ handleBareValue: ({ value, extra }) => namedBoxShadow(layer, value, extra?.opacity) ? value : null,
4799
+ handle: (value, _ctx, token, extra) => {
4800
+ const opacity2 = extra?.opacity;
4801
+ const named = !extra?.realThemeValue && !token.arbitrary ? namedBoxShadow(layer, value, opacity2) : null;
4802
+ if (named) return named;
4803
+ const color = layerColor(layer, value, opacity2, token, extra?.realThemeValue);
4804
+ if (color !== void 0) return color;
4805
+ if (token.arbitrary) return boxShadowLayer(layer, layer === "inset-shadow" ? insetEach(value) : value, opacity2);
4806
+ return null;
4807
+ },
4808
+ handleCustomProperty: (value) => value.startsWith("color:") ? shadowColorDecls(layer, `var(${value.slice(6)})`, void 0) ?? [] : [ringShadowProperties(), decl(`--baro-${layer}`, layer === "inset-shadow" ? `inset var(${value})` : `var(${value})`), decl("box-shadow", SHADOW_COMPOSITE)]
4809
+ });
4810
+ }
4811
+ const textShadowProperties = () => atRoot([
4812
+ property("--baro-text-shadow-color"),
4813
+ property("--baro-text-shadow-alpha", "100%", "<percentage>")
4814
+ ]);
4815
+ const namedTextShadow = (ctx, name) => {
4816
+ const v = ctx.theme("textShadow", name);
4817
+ return typeof v === "string" && /^[\w.-]+$/.test(name) ? v : null;
4818
+ };
4819
+ const textShadowValue = (value, opacity2) => {
4820
+ const decls = shadowValueDecls("text-shadow", "text-shadow", value, opacity2);
4821
+ return decls ? [textShadowProperties(), ...decls] : null;
4822
+ };
4823
+ staticUtility("text-shadow-none", [textShadowProperties, ["text-shadow", "none"]], { category: "effects" });
4591
4824
  functionalUtility({
4592
- name: "inset-shadow",
4825
+ name: "text-shadow",
4593
4826
  supportsArbitrary: true,
4594
4827
  supportsCustomProperty: true,
4595
4828
  supportsOpacity: true,
4596
- themeKeys: ["colors", "shadows"],
4829
+ themeKeys: ["colors"],
4830
+ handleBareValue: ({ value, ctx }) => namedTextShadow(ctx, value) ? value : null,
4597
4831
  handle: (value, ctx, token, extra) => {
4598
- const main = value;
4599
4832
  const opacity2 = extra?.opacity;
4600
- const realThemeValue = extra?.realThemeValue;
4601
- if (realThemeValue) {
4602
- return createShadowThemeColor(
4603
- "--baro-inset-shadow-color",
4604
- main,
4605
- opacity2,
4606
- realThemeValue
4607
- );
4608
- }
4609
- if (main.startsWith("color:")) {
4610
- const cp = main.replace("color:", "");
4611
- let colorValue = `var(${cp})`;
4612
- if (opacity2) {
4613
- colorValue = `color-mix(in oklab, var(${cp}) ${opacity2}%, transparent)`;
4614
- }
4615
- return [decl("--baro-inset-shadow-color", colorValue)];
4616
- }
4617
- if (token.arbitrary) {
4618
- if (parseColor(main)) {
4619
- let colorValue = main;
4620
- if (opacity2) {
4621
- colorValue = `color-mix(in oklab, ${main} ${opacity2}%, transparent)`;
4622
- }
4623
- return [decl("--baro-inset-shadow-color", colorValue)];
4624
- }
4625
- return [decl("box-shadow", `inset ${main}`)];
4626
- }
4627
- if (main === "inherit" || main === "current" || main === "transparent") {
4628
- return [
4629
- decl(
4630
- "--baro-inset-shadow-color",
4631
- main === "current" ? "currentColor" : main
4632
- )
4633
- ];
4833
+ if (!extra?.realThemeValue && !token.arbitrary) {
4834
+ const named = namedTextShadow(ctx, value);
4835
+ if (named) return textShadowValue(named, opacity2);
4634
4836
  }
4837
+ const color = layerColor("text-shadow", value, opacity2, token, extra?.realThemeValue);
4838
+ if (color !== void 0) return color && [textShadowProperties(), ...color];
4839
+ if (token.arbitrary) return textShadowValue(value, opacity2);
4635
4840
  return null;
4636
4841
  },
4637
- handleCustomProperty: (value) => [decl("box-shadow", `var(${value})`)]
4842
+ handleCustomProperty: (value) => value.startsWith("color:") ? [textShadowProperties(), ...shadowColorDecls("text-shadow", `var(${value.slice(6)})`, void 0) ?? []] : [textShadowProperties(), decl("text-shadow", `var(${value})`)],
4843
+ category: "effects"
4638
4844
  });
4639
4845
  [
4640
4846
  ["ring", "1px"],
@@ -5177,12 +5383,15 @@ staticUtility("not-sr-only", [
5177
5383
  ], { category: "layout" });
5178
5384
  staticUtility("@container", [["container-type", "inline-size"]], { category: "layout" });
5179
5385
  staticUtility("@container-normal", [["container-type", "normal"]], { category: "layout" });
5386
+ staticUtility("@container-size", [["container-type", "size"]], { category: "layout" });
5387
+ const NAMED_CONTAINER = /^@container(-normal|-size)?\/([a-zA-Z0-9_-]+)$/;
5388
+ const CONTAINER_TYPE = { "": "inline-size", "-normal": "normal", "-size": "size" };
5180
5389
  registerUtility({
5181
5390
  name: "@container",
5182
- match: (className) => /^@container\/[a-zA-Z0-9_-]+$/.test(className),
5391
+ match: (className) => NAMED_CONTAINER.test(className),
5183
5392
  handler: (_value, _ctx, token) => {
5184
- const name = /^@container\/([a-zA-Z0-9_-]+)$/.exec(`${token.prefix}${token.value ? `-${token.value}` : ""}`)?.[1];
5185
- return name ? [decl("container-type", "inline-size"), decl("container-name", name)] : null;
5393
+ const m = NAMED_CONTAINER.exec(`${token.prefix}${token.value ? `-${token.value}` : ""}`);
5394
+ return m ? [decl("container-type", CONTAINER_TYPE[m[1] ?? ""]), decl("container-name", m[2])] : null;
5186
5395
  },
5187
5396
  category: "layout"
5188
5397
  });
@@ -5267,6 +5476,11 @@ staticUtility("sticky", [["position", "sticky"]], { category: "layout" });
5267
5476
  [
5268
5477
  ["inset-x", "inset-inline"],
5269
5478
  ["inset-y", "inset-block"],
5479
+ // Tailwind 4.3 logical sides; registered before `inset` so their handler runs first for `inset-s-*` etc.
5480
+ ["inset-s", "inset-inline-start"],
5481
+ ["inset-e", "inset-inline-end"],
5482
+ ["inset-bs", "inset-block-start"],
5483
+ ["inset-be", "inset-block-end"],
5270
5484
  ["inset", "inset"],
5271
5485
  ["start", "inset-inline-start"],
5272
5486
  ["end", "inset-inline-end"],
@@ -5362,6 +5576,15 @@ functionalUtility({
5362
5576
  description: "gap utility (number, arbitrary, custom property supported)",
5363
5577
  category: "layout"
5364
5578
  });
5579
+ functionalUtility({
5580
+ name: "zoom",
5581
+ prop: "zoom",
5582
+ supportsArbitrary: true,
5583
+ supportsCustomProperty: true,
5584
+ handleBareValue: ({ value }) => /^\d+$/.test(value) ? `${value}%` : null,
5585
+ description: "zoom utility (integer percent, arbitrary, custom property)",
5586
+ category: "layout"
5587
+ });
5365
5588
  staticUtility("basis-full", [["flex-basis", "100%"]], { category: "flex-grid" });
5366
5589
  staticUtility("basis-auto", [["flex-basis", "auto"]], { category: "flex-grid" });
5367
5590
  staticUtility("basis-3xs", [["flex-basis", "var(--container-3xs)"]], { category: "flex-grid" });
@@ -5636,6 +5859,8 @@ functionalUtility({
5636
5859
  // auto-cols-[minmax(0,2fr)]
5637
5860
  supportsCustomProperty: true,
5638
5861
  // auto-cols-(--my-auto-cols)
5862
+ handleBareValue: ({ value }) => parseNumber(value) ? `calc(var(--spacing) * ${value})` : null,
5863
+ // #310: auto-cols-4
5639
5864
  handle: (value) => {
5640
5865
  if (typeof value === "string") return [decl("grid-auto-columns", value)];
5641
5866
  return null;
@@ -5655,6 +5880,8 @@ functionalUtility({
5655
5880
  // auto-rows-[minmax(0,2fr)]
5656
5881
  supportsCustomProperty: true,
5657
5882
  // auto-rows-(--my-auto-rows)
5883
+ handleBareValue: ({ value }) => parseNumber(value) ? `calc(var(--spacing) * ${value})` : null,
5884
+ // #310: auto-rows-12
5658
5885
  handle: (value) => {
5659
5886
  if (typeof value === "string") return [decl("grid-auto-rows", value)];
5660
5887
  return null;
@@ -5857,6 +6084,8 @@ functionalUtility({
5857
6084
  ["py", "padding-block"],
5858
6085
  ["ps", "padding-inline-start"],
5859
6086
  ["pe", "padding-inline-end"],
6087
+ ["pbs", "padding-block-start"],
6088
+ ["pbe", "padding-block-end"],
5860
6089
  ["pt", "padding-top"],
5861
6090
  ["pr", "padding-right"],
5862
6091
  ["pb", "padding-bottom"],
@@ -5880,6 +6109,8 @@ functionalUtility({
5880
6109
  ["my", "margin-block"],
5881
6110
  ["ms", "margin-inline-start"],
5882
6111
  ["me", "margin-inline-end"],
6112
+ ["mbs", "margin-block-start"],
6113
+ ["mbe", "margin-block-end"],
5883
6114
  ["mt", "margin-top"],
5884
6115
  ["mr", "margin-right"],
5885
6116
  ["mb", "margin-bottom"],
@@ -6205,6 +6436,41 @@ functionalUtility({
6205
6436
  description: "max-width utility (spacing, fraction, arbitrary, custom property, static supported)",
6206
6437
  category: "sizing"
6207
6438
  });
6439
+ {
6440
+ const containers = ["3xs", "2xs", "xs", "sm", "md", "lg", "xl", "2xl", "3xl", "4xl", "5xl", "6xl", "7xl"].map(
6441
+ (k) => [k, `var(--container-${k})`]
6442
+ );
6443
+ const common = [["0", "0px"], ["px", "1px"], ["full", "100%"], ["min", "min-content"], ["max", "max-content"], ["fit", "fit-content"]];
6444
+ const inlineVp = [["screen", "100vw"], ["dvw", "100dvw"], ["lvw", "100lvw"], ["svw", "100svw"]];
6445
+ const blockVp = [["screen", "100vh"], ["dvh", "100dvh"], ["lvh", "100lvh"], ["svh", "100svh"], ["lh", "1lh"]];
6446
+ const families = [
6447
+ ["inline", "inline-size", [...common, ["auto", "auto"], ...inlineVp, ...containers]],
6448
+ ["min-inline", "min-inline-size", [...common, ["auto", "auto"], ...inlineVp, ...containers]],
6449
+ ["max-inline", "max-inline-size", [...common, ["none", "none"], ...inlineVp, ...containers]],
6450
+ ["block", "block-size", [...common, ["auto", "auto"], ...blockVp]],
6451
+ ["min-block", "min-block-size", [...common, ["auto", "auto"], ...blockVp]],
6452
+ ["max-block", "max-block-size", [...common, ["none", "none"], ...blockVp]]
6453
+ ];
6454
+ for (const [name, prop, statics] of families) {
6455
+ for (const [key, value] of statics) staticUtility(`${name}-${key}`, [[prop, value]], { category: "sizing" });
6456
+ functionalUtility({
6457
+ spacingKeys: true,
6458
+ name,
6459
+ prop,
6460
+ supportsArbitrary: true,
6461
+ supportsCustomProperty: true,
6462
+ supportsFraction: true,
6463
+ handleBareValue: ({ value, token }) => {
6464
+ if (token.negative) return null;
6465
+ if (parseNumber(value)) return `calc(var(--spacing) * ${value})`;
6466
+ if (parseFractionOrNumber(value)) return `calc(${value} * 100%)`;
6467
+ return null;
6468
+ },
6469
+ description: `${prop} utility (spacing, fraction, arbitrary, custom property, keywords)`,
6470
+ category: "sizing"
6471
+ });
6472
+ }
6473
+ }
6208
6474
  const leadingProperty = () => atRoot([property("--baro-leading")]);
6209
6475
  staticUtility("font-sans", [["font-family", "var(--font-sans)"]], { category: "typography" });
6210
6476
  staticUtility("font-serif", [["font-family", "var(--font-serif)"]], { category: "typography" });
@@ -6235,13 +6501,15 @@ functionalUtility({
6235
6501
  name: "font",
6236
6502
  supportsArbitrary: true,
6237
6503
  supportsCustomProperty: true,
6238
- handle: (value) => {
6504
+ handle: (value, _ctx, token) => {
6505
+ if (token.prefix !== "font") return null;
6239
6506
  if (parseNumber(value)) {
6240
6507
  return [decl("font-weight", value)];
6241
6508
  }
6242
6509
  return [decl("font-family", value)];
6243
6510
  },
6244
- handleCustomProperty: (value) => {
6511
+ handleCustomProperty: (value, _ctx, token) => {
6512
+ if (token.prefix !== "font") return null;
6245
6513
  if (value.startsWith("font-name:")) {
6246
6514
  return [decl("font-family", `var(${value.replace("font-name:", "")})`)];
6247
6515
  }
@@ -6540,6 +6808,42 @@ functionalUtility({
6540
6808
  description: "content utility (arbitrary, custom property supported)",
6541
6809
  category: "typography"
6542
6810
  });
6811
+ const placeholderColor = (value) => [rule("&::placeholder", [decl("color", value)])];
6812
+ staticUtility("placeholder-inherit", placeholderColor("inherit"), { category: "typography" });
6813
+ staticUtility("placeholder-current", placeholderColor("currentcolor"), { category: "typography" });
6814
+ staticUtility("placeholder-transparent", placeholderColor("transparent"), { category: "typography" });
6815
+ functionalUtility({
6816
+ name: "placeholder",
6817
+ themeKeys: ["colors"],
6818
+ supportsArbitrary: true,
6819
+ supportsCustomProperty: true,
6820
+ supportsOpacity: true,
6821
+ handle: (value, _ctx, _token, extra) => {
6822
+ if (extra?.realThemeValue) return [rule("&::placeholder", themeColorDecls("color", value, extra))];
6823
+ if (parseColor(value)) return placeholderColor(value);
6824
+ return null;
6825
+ },
6826
+ handleCustomProperty: (value) => placeholderColor(`var(${value})`),
6827
+ description: "placeholder color utility (theme, alpha, arbitrary, custom property)"
6828
+ });
6829
+ functionalUtility({
6830
+ name: "font-features",
6831
+ supportsArbitrary: true,
6832
+ supportsCustomProperty: true,
6833
+ handle: (value, _ctx, token) => token.arbitrary ? [decl("font-feature-settings", value)] : null,
6834
+ handleCustomProperty: (value) => [decl("font-feature-settings", `var(${value.replace(/^[a-z-]+:(?=--)/, "")})`)],
6835
+ description: "font-feature-settings utility (arbitrary, custom property)",
6836
+ category: "typography"
6837
+ });
6838
+ functionalUtility({
6839
+ name: "tab",
6840
+ prop: "tab-size",
6841
+ supportsArbitrary: true,
6842
+ supportsCustomProperty: true,
6843
+ handleBareValue: ({ value }) => /^\d+$/.test(value) ? value : null,
6844
+ description: "tab-size utility (integer, arbitrary, custom property)",
6845
+ category: "typography"
6846
+ });
6543
6847
  const gradientStopProperties = () => {
6544
6848
  return atRoot([
6545
6849
  property("--baro-gradient-position"),
@@ -6871,6 +7175,11 @@ const withBorderStyle = (props, width) => [
6871
7175
  [
6872
7176
  ["border-x", ["border-left-width", "border-right-width"]],
6873
7177
  ["border-y", ["border-top-width", "border-bottom-width"]],
7178
+ ["border-bs", ["border-block-start-width"]],
7179
+ ["border-be", ["border-block-end-width"]],
7180
+ ["border-s", ["border-inline-start-width"]],
7181
+ // #311 (Tailwind 4.3)
7182
+ ["border-e", ["border-inline-end-width"]],
6874
7183
  ["border-t", ["border-top-width"]],
6875
7184
  ["border-r", ["border-right-width"]],
6876
7185
  ["border-b", ["border-bottom-width"]],
@@ -6890,6 +7199,7 @@ const withBorderStyle = (props, width) => [
6890
7199
  functionalUtility({
6891
7200
  name,
6892
7201
  themeKeys: ["borderWidth", "colors"],
7202
+ supportsOpacity: true,
6893
7203
  supportsArbitrary: true,
6894
7204
  supportsCustomProperty: true,
6895
7205
  handleBareValue: ({ value }) => {
@@ -7870,9 +8180,10 @@ staticModifier("starting", ["&"], {
7870
8180
  wrap: () => [atRule("starting-style", "", [], "starting")],
7871
8181
  source: "starting"
7872
8182
  });
7873
- function createContainerParams(type, value, name) {
8183
+ function createContainerParams(type, value, name, negate = false) {
7874
8184
  const condition = type === "min" ? "width >=" : "width <";
7875
- return name ? `${name} (${condition} ${value})` : `(${condition} ${value})`;
8185
+ const query = `${negate ? "not " : ""}(${condition} ${value})`;
8186
+ return name ? `${name} ${query}` : query;
7876
8187
  }
7877
8188
  function createContainerRule(params, ast) {
7878
8189
  return {
@@ -8041,17 +8352,17 @@ functionalModifier(
8041
8352
  return result;
8042
8353
  }
8043
8354
  );
8044
- const SIZE_VARIANT = /^@(?:(min|max)-)?(\[[^\]]+\]|[a-zA-Z0-9.]+)(?:\/([a-zA-Z0-9_-]+))?$/;
8355
+ const SIZE_VARIANT = /^(not-)?@(?:(min|max)-)?(\[[^\]]+\]|[a-zA-Z0-9.]+)(?:\/([a-zA-Z0-9_-]+))?$/;
8045
8356
  functionalModifier(
8046
- (mod) => SIZE_VARIANT.test(mod) && !/^@container(?:\/|$)/.test(mod),
8357
+ (mod) => SIZE_VARIANT.test(mod) && !/^(?:not-)?@container(?:\/|$)/.test(mod),
8047
8358
  void 0,
8048
8359
  (mod, context) => {
8049
8360
  const m = SIZE_VARIANT.exec(mod.type);
8050
8361
  if (!m) return [];
8051
- const [, type, size, name] = m;
8362
+ const [, not, type, size, name] = m;
8052
8363
  const value = size.startsWith("[") ? size.slice(1, -1).replace(/_/g, " ") : context.theme("container." + size);
8053
8364
  if (!value) return [];
8054
- return [createContainerRule(createContainerParams(type === "max" ? "max" : "min", value, name), [])];
8365
+ return [createContainerRule(createContainerParams(type === "max" ? "max" : "min", value, name, !!not), [])];
8055
8366
  }
8056
8367
  );
8057
8368
  const startsAtRule = (bracket) => /^[\s_]*@/.test(bracket);
@@ -8191,7 +8502,7 @@ functionalModifier(
8191
8502
  }
8192
8503
  );
8193
8504
  functionalModifier(
8194
- (mod) => /^not-/.test(mod),
8505
+ (mod) => /^not-/.test(mod) && !mod.startsWith("not-@"),
8195
8506
  ({ selector, mod }) => {
8196
8507
  const m = /^not-(.+)$/.exec(mod.type);
8197
8508
  return {
@@ -8258,7 +8569,8 @@ functionalModifier(
8258
8569
  void 0
8259
8570
  );
8260
8571
  functionalModifier(
8261
- (mod) => mod.startsWith("not-"),
8572
+ (mod) => mod.startsWith("not-") && !mod.startsWith("not-@"),
8573
+ // not-@… is container negation (#311)
8262
8574
  ({ selector, mod }) => {
8263
8575
  const pseudo = mod.type.replace("not-", "");
8264
8576
  if (pseudo.startsWith("[")) {
@@ -9114,7 +9426,7 @@ class ChangeDetector {
9114
9426
  function unescapeCssIdent(s) {
9115
9427
  return s.replace(/\\([0-9a-fA-F]{1,6})\s?|\\(.)/g, (_m, hex, ch) => hex ? String.fromCodePoint(parseInt(hex, 16)) : ch);
9116
9428
  }
9117
- const LEADING_CLASS = /^\s*\.((?:\\[0-9a-fA-F]{1,6}\s?|\\.|[\w-]|[^\x00-\x7F])+)/;
9429
+ const LEADING_CLASS = /^\s*(?::(?:where|is)\(\s*)?\.((?:\\[0-9a-fA-F]{1,6}\s?|\\.|[\w-]|[^\x00-\x7F])+)/;
9118
9430
  function splitTopLevel(sel) {
9119
9431
  const parts = [];
9120
9432
  let depth = 0, start = 0;
@@ -9131,6 +9443,17 @@ function splitTopLevel(sel) {
9131
9443
  parts.push(sel.slice(start));
9132
9444
  return parts;
9133
9445
  }
9446
+ function collectKeyframeNames(rules, out = /* @__PURE__ */ new Set()) {
9447
+ for (const rule2 of Array.from(rules)) {
9448
+ if (rule2.type === 7 && typeof rule2.name === "string") {
9449
+ out.add(rule2.name);
9450
+ continue;
9451
+ }
9452
+ const inner = rule2.cssRules;
9453
+ if (inner && inner.length) collectKeyframeNames(inner, out);
9454
+ }
9455
+ return out;
9456
+ }
9134
9457
  function collectLeadingClasses(rules, out = /* @__PURE__ */ new Set()) {
9135
9458
  for (const rule2 of Array.from(rules)) {
9136
9459
  const selectorText = rule2.selectorText;
@@ -9254,6 +9577,7 @@ class ClassGc {
9254
9577
  return { trackedClasses: this.counts.size, candidates: this.candidates.size };
9255
9578
  }
9256
9579
  }
9580
+ const SSR_STYLE_SELECTOR = "style[data-barocss-ssr]";
9257
9581
  const LAYER_ORDER = "@layer theme, base, components, utilities;";
9258
9582
  class BrowserRuntime {
9259
9583
  constructor(options = {}) {
@@ -9261,10 +9585,14 @@ class BrowserRuntime {
9261
9585
  this.rootCache = /* @__PURE__ */ new Set();
9262
9586
  this.isDestroyed = false;
9263
9587
  this.existing = null;
9588
+ this.existingKeyframes = /* @__PURE__ */ new Set();
9264
9589
  this.existingSheetCount = -1;
9265
9590
  this.pinned = /* @__PURE__ */ new Set();
9266
9591
  this.gc = null;
9267
9592
  this.reclaimedCount = 0;
9593
+ this.ssrRules = [];
9594
+ this.ssrClasses = /* @__PURE__ */ new Set();
9595
+ this.observedOnce = false;
9268
9596
  this.getCategory = (cls) => parseClassName(cls, this.context).utility?.category;
9269
9597
  const defaultConfig = {};
9270
9598
  this.options = {
@@ -9303,6 +9631,44 @@ class BrowserRuntime {
9303
9631
  console.log("[BrowserRuntime] init");
9304
9632
  this.injectPreflightCSS();
9305
9633
  this.ensureCssVars();
9634
+ this.adoptSsrSheets();
9635
+ }
9636
+ /**
9637
+ * #268: adopt the class rules of server-rendered `<style data-barocss-ssr>` sheets in <head>, at startup
9638
+ * (constructor and the first observe()). Each rule moves
9639
+ * (same task, so no paint in between) into the partition its class would get if generated here, at
9640
+ * its #254 sorted position, so a later client `sm:` rule lands before a server `lg:` rule. Its classes
9641
+ * are never regenerated and never reclaimed. `:root`, `@property` and `@keyframes` stay in the sheet.
9642
+ */
9643
+ adoptSsrSheets() {
9644
+ if (typeof document === "undefined") return;
9645
+ const adopted = [];
9646
+ if (!document.head) return;
9647
+ for (const el of Array.from(document.head.querySelectorAll(`${SSR_STYLE_SELECTOR}:not([data-barocss-adopted])`))) {
9648
+ const sheet = el.sheet;
9649
+ if (!sheet) continue;
9650
+ el.setAttribute("data-barocss-adopted", "");
9651
+ const moved = [];
9652
+ for (let i = sheet.cssRules.length - 1; i >= 0; i--) {
9653
+ const rule2 = sheet.cssRules[i];
9654
+ const classes = collectLeadingClasses([rule2]);
9655
+ if (classes.size === 0) continue;
9656
+ classes.forEach((cls) => this.ssrClasses.add(cls));
9657
+ moved.unshift({ css: rule2.cssText, cls: classes.values().next().value });
9658
+ sheet.deleteRule(i);
9659
+ }
9660
+ adopted.push(...moved);
9661
+ }
9662
+ if (adopted.length === 0) return;
9663
+ this.ssrRules.push(...adopted);
9664
+ this.insertSsrRules(adopted);
9665
+ }
9666
+ insertSsrRules(rules) {
9667
+ for (const { css, cls } of rules) {
9668
+ const category = this.getCategory(cls);
9669
+ if (category) this.stylePartitionManager.addCategoryRule(css, category);
9670
+ else this.stylePartitionManager.addRule(css);
9671
+ }
9306
9672
  }
9307
9673
  injectPreflightCSS() {
9308
9674
  const level = this.options.config.preflight ?? true;
@@ -9370,6 +9736,7 @@ ${preflightCSS}
9370
9736
  results = [...existingResults, ...results];
9371
9737
  results.forEach((result) => this.incrementalParser.markProcessed(result.cls));
9372
9738
  }
9739
+ if (this.ssrClasses.size > 0) results = results.filter((result) => !this.ssrClasses.has(result.cls));
9373
9740
  if (this.options.skipExisting && results.length > 0 && typeof document !== "undefined") {
9374
9741
  const existing = this.getExistingClasses();
9375
9742
  results = results.filter((result) => !existing.has(result.cls));
@@ -9377,6 +9744,7 @@ ${preflightCSS}
9377
9744
  if (results.length === 0) return;
9378
9745
  const cssRules = [];
9379
9746
  const rootCssRules = [];
9747
+ const pageKeyframes = this.options.skipExisting && typeof document !== "undefined" ? (this.getExistingClasses(), this.existingKeyframes) : null;
9380
9748
  for (const result of results) {
9381
9749
  if (result.css && Array.isArray(result.cssList)) {
9382
9750
  cssRules.push(result);
@@ -9384,6 +9752,10 @@ ${preflightCSS}
9384
9752
  }
9385
9753
  if (result.rootCss && Array.isArray(result.rootCssList)) {
9386
9754
  for (const rootCss of result.rootCssList) {
9755
+ if (pageKeyframes?.size) {
9756
+ const kf = /^\s*@keyframes\s+([^\s{]+)/.exec(rootCss)?.[1];
9757
+ if (kf && pageKeyframes.has(kf)) continue;
9758
+ }
9387
9759
  if (!this.rootCache.has(rootCss)) {
9388
9760
  this.rootCache.add(rootCss);
9389
9761
  rootCssRules.push(rootCss);
@@ -9404,12 +9776,12 @@ ${preflightCSS}
9404
9776
  }
9405
9777
  /** #269: a class that must never be reclaimed. */
9406
9778
  isPermanent(cls) {
9407
- if (this.pinned.has(cls)) return true;
9779
+ if (this.pinned.has(cls) || this.ssrClasses.has(cls)) return true;
9408
9780
  if (typeof document === "undefined") return true;
9409
9781
  return this.getExistingClasses().has(cls);
9410
9782
  }
9411
9783
  /**
9412
- * #269: delete the generated rules of classes no live element uses. Root/@property rules stay
9784
+ * #269: delete the generated rules of classes no live element uses. Root/@property/@keyframes rules stay
9413
9785
  * (they are shared and harmless); a rule text another cached class still emits is kept.
9414
9786
  */
9415
9787
  reclaim(classes) {
@@ -9433,14 +9805,15 @@ ${preflightCSS}
9433
9805
  }
9434
9806
  /** Class names defined by the page's own stylesheets (BaroCSS's sheets and cross-origin sheets excluded). */
9435
9807
  getExistingClasses() {
9436
- const own = new Set(Array.from(document.querySelectorAll("style[data-barocss]"), (s) => s.sheet));
9808
+ const own2 = new Set(Array.from(document.querySelectorAll("style[data-barocss]"), (s) => s.sheet));
9437
9809
  const sheets = Array.from(document.styleSheets).filter((sheet) => {
9438
- if (own.has(sheet)) return false;
9810
+ if (own2.has(sheet)) return false;
9439
9811
  const owner = sheet.ownerNode;
9440
9812
  return !(owner && typeof owner.hasAttribute === "function" && (owner.hasAttribute("data-barocss") || (owner.id || "").startsWith(this.options.styleId)));
9441
9813
  });
9442
9814
  if (this.existing && sheets.length === this.existingSheetCount) return this.existing;
9443
9815
  const out = /* @__PURE__ */ new Set();
9816
+ const keyframes2 = /* @__PURE__ */ new Set();
9444
9817
  for (const sheet of sheets) {
9445
9818
  let rules;
9446
9819
  try {
@@ -9449,7 +9822,9 @@ ${preflightCSS}
9449
9822
  continue;
9450
9823
  }
9451
9824
  collectLeadingClasses(rules, out);
9825
+ collectKeyframeNames(rules, keyframes2);
9452
9826
  }
9827
+ this.existingKeyframes = keyframes2;
9453
9828
  this.existing = out;
9454
9829
  this.existingSheetCount = sheets.length;
9455
9830
  return out;
@@ -9458,6 +9833,10 @@ ${preflightCSS}
9458
9833
  * MutationObserver instance method to automatically call addClass when class attributes change in DOM
9459
9834
  */
9460
9835
  observe(root = document.body, options) {
9836
+ if (!this.observedOnce) {
9837
+ this.observedOnce = true;
9838
+ this.adoptSsrSheets();
9839
+ }
9461
9840
  return this.changeDetector.observe(root, options);
9462
9841
  }
9463
9842
  normalizeClasses(classes) {
@@ -9509,6 +9888,7 @@ ${preflightCSS}
9509
9888
  this.stylePartitionManager = new StylePartitionManager(this.getInsertionPoint(), this.options.maxRulesPerPartition, `${this.options.styleId}-partition`, this.getCategory);
9510
9889
  this.injectPreflightCSS();
9511
9890
  this.ensureCssVars();
9891
+ this.insertSsrRules(this.ssrRules);
9512
9892
  }
9513
9893
  reset() {
9514
9894
  if (this.isDestroyed) return;
@@ -9519,6 +9899,7 @@ ${preflightCSS}
9519
9899
  this.stylePartitionManager = new StylePartitionManager(this.getInsertionPoint(), this.options.maxRulesPerPartition, `${this.options.styleId}-partition`, this.getCategory);
9520
9900
  this.injectPreflightCSS();
9521
9901
  this.ensureCssVars();
9902
+ this.insertSsrRules(this.ssrRules);
9522
9903
  }
9523
9904
  updateConfig(newConfig) {
9524
9905
  if (this.isDestroyed) return;
@@ -9661,6 +10042,7 @@ export {
9661
10042
  BrowserRuntime,
9662
10043
  ChangeDetector,
9663
10044
  LAYER_ORDER,
10045
+ SSR_STYLE_SELECTOR,
9664
10046
  StylePartitionManager,
9665
10047
  baroBoot,
9666
10048
  baroStart,