kuinetic 0.1.2 → 0.1.3

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.
@@ -61,7 +61,7 @@ var kuinetic = (() => {
61
61
 
62
62
  // src/core/element-config.ts
63
63
  var ACTIVATIONS = /* @__PURE__ */ new Set(["load", "enter", "hover", "focus", "click", "manual"]);
64
- var TIMELINES = /* @__PURE__ */ new Set(["time", "view", "scroll", "pointer"]);
64
+ var TIMELINES = /* @__PURE__ */ new Set(["time", "view", "scroll", "pointer", "pin"]);
65
65
  function readAttributes(el) {
66
66
  return {
67
67
  source: el.getAttribute(ATTR.source) ?? "",
@@ -243,7 +243,7 @@ var kuinetic = (() => {
243
243
  var HEX_COLOR = /^#[0-9a-f]{3,8}$/i;
244
244
  var COLOR_FUNCTIONS = /^(?:rgba?|hsla?|okl(?:ch|ab)|l(?:ch|ab)|color)\([^()]*\)$/i;
245
245
  var COLOR_KEYWORD = /^[a-z]+$/i;
246
- var EASING_KEYWORD = /^(?:linear|ease|step-start|step-end|spring|[a-z]+-(?:in|out|in-out))$/i;
246
+ var EASING_KEYWORD = /^(?:linear|ease|step-start|step-end|spring|bounce|[a-z]+-(?:in|out|in-out))$/i;
247
247
  var EASING_FUNCTION = /^(?:cubic-bezier|steps|linear)\([^()]*\)$/i;
248
248
  var CALC_TYPES = /* @__PURE__ */ new Set(["length", "percentage", "number"]);
249
249
  var CALC_CHARACTER = /^[\d.\s+\-*/%a-z,]$/i;
@@ -530,7 +530,7 @@ var kuinetic = (() => {
530
530
  plan.vars,
531
531
  resolveParams(entry.spec.params, primitive.parameters, (m) => warnings.push(m))
532
532
  );
533
- if (primitive.renderer === "css-keyframes") pushTrack(tracks, entry);
533
+ if (primitive.renderer === "css-keyframes") pushTrack(tracks, entry, timeline);
534
534
  else plan.jsEffects.push(entry);
535
535
  }
536
536
  Object.assign(plan.declarations, declarationsFor(tracks));
@@ -546,12 +546,13 @@ var kuinetic = (() => {
546
546
  function iterationCountProperty(presetName) {
547
547
  return `--kui-fx-${presetName}-iterations`;
548
548
  }
549
- function pushTrack(tracks, entry) {
549
+ function pushTrack(tracks, entry, timeline) {
550
550
  const { spec, resolved } = entry;
551
551
  const id = resolved.primitive.id;
552
552
  tracks.names.push(resolved.preset.keyframes ?? `kui-${resolved.preset.name}`);
553
- tracks.durations.push(spec.duration ?? `var(${timingProperty(id, "duration")}, 600ms)`);
554
- tracks.delays.push(staggerDelay(spec.delay, id));
553
+ const duration = spec.duration ?? `var(${timingProperty(id, "duration")}, 600ms)`;
554
+ tracks.durations.push(duration);
555
+ tracks.delays.push(staggerDelay(spec.delay, id, timeline, duration));
555
556
  tracks.easings.push(easingValue(spec.easing, id));
556
557
  tracks.iterationCounts.push(`var(${iterationCountProperty(resolved.preset.name)}, 1)`);
557
558
  }
@@ -575,9 +576,12 @@ var kuinetic = (() => {
575
576
  `"${name}" does not support timeline "${timeline}" (supports: ${supported.join(", ")})`
576
577
  );
577
578
  }
578
- function staggerDelay(delay, primitiveId) {
579
+ function staggerDelay(delay, primitiveId, timeline, duration) {
579
580
  const base = delay ?? `var(${timingProperty(primitiveId, "delay")}, 0ms)`;
580
- return `calc(${base} + var(--kui-i, 0) * var(--kui-stagger, 0ms))`;
581
+ const staggered = `${base} + var(--kui-i, 0) * var(--kui-stagger, 0ms)`;
582
+ if (timeline !== "pin") return `calc(${staggered})`;
583
+ const span = `${duration} + (var(--kui-stagger-count, 1) - 1) * var(--kui-stagger, 0ms)`;
584
+ return `calc(${staggered} - var(--kui-progress, 0) * (${span}))`;
581
585
  }
582
586
  function easingValue(easing, primitiveId) {
583
587
  if (!easing) return `var(${timingProperty(primitiveId, "ease")}, ease-out)`;
@@ -860,7 +864,8 @@ var kuinetic = (() => {
860
864
  "back-in-out",
861
865
  "quart-out",
862
866
  "circ-out",
863
- "spring"
867
+ "spring",
868
+ "bounce"
864
869
  ]);
865
870
  function splitTopLevel(input, delimiter, warnings = []) {
866
871
  const parts = [];
@@ -1095,7 +1100,22 @@ var kuinetic = (() => {
1095
1100
  viewportLeft: 0
1096
1101
  }),
1097
1102
  onScroll: (handler) => listen(win, "scroll", handler),
1098
- onResize: (handler) => listen(win, "resize", handler)
1103
+ /*
1104
+ * The document's own height counts as a resize, not just the window's.
1105
+ *
1106
+ * `elementScrollRoot` has observed its element's size since it was written, for the reason
1107
+ * stated three doc comments down: "images loading, fonts swapping, a container changing size,
1108
+ * or content being inserted". Every one of those applies at least as strongly to the page
1109
+ * itself, and the page root was the one that only listened for `window.resize` — so on any
1110
+ * document with lazy-loaded media below the fold, every cached content offset silently drifted
1111
+ * by however much the page grew after it was measured, with no epoch bump to correct it.
1112
+ *
1113
+ * Measured on `demo/scroll.html` (32,000px of lazy screenshots): the horizontal track's stage
1114
+ * moved ~840px between page load and reaching it, which is a third of that effect's whole
1115
+ * scroll range. Nothing was wrong with the maths; the number it was doing the maths on was
1116
+ * taken before forty images existed.
1117
+ */
1118
+ onResize: (handler) => observeSize(win.document.documentElement, win, handler)
1099
1119
  };
1100
1120
  }
1101
1121
  function elementScrollRoot(el, win) {
@@ -1322,7 +1342,7 @@ var kuinetic = (() => {
1322
1342
  flushComputedAnimationName(el);
1323
1343
  ledger.set("animation-name", name);
1324
1344
  }
1325
- function createCssInstance(el, ledger, animationNames) {
1345
+ function createCssInstance(el, ledger, animationNames, scrubbed = false) {
1326
1346
  const ownedNames = new Set(animationNames);
1327
1347
  let settle2;
1328
1348
  let finished = new Promise((resolve) => {
@@ -1341,6 +1361,10 @@ var kuinetic = (() => {
1341
1361
  finished = new Promise((resolve) => {
1342
1362
  settle2 = resolve;
1343
1363
  });
1364
+ if (scrubbed) {
1365
+ settle2?.();
1366
+ return;
1367
+ }
1344
1368
  let animations = ownedAnimationsOf(el, ownedNames);
1345
1369
  if (!activatedBefore) {
1346
1370
  restartCssAnimation(el, ledger);
@@ -1373,6 +1397,9 @@ var kuinetic = (() => {
1373
1397
  }
1374
1398
  };
1375
1399
  }
1400
+ function continuousSetup(cleanup) {
1401
+ return { cleanup, continuous: true };
1402
+ }
1376
1403
  function cleanupOf(result) {
1377
1404
  if (result === void 0) return void 0;
1378
1405
  return typeof result === "function" ? result : result.cleanup;
@@ -1389,7 +1416,7 @@ var kuinetic = (() => {
1389
1416
  return createJsInstance({
1390
1417
  activate() {
1391
1418
  running = setup();
1392
- if (typeof running === "function") return;
1419
+ if (typeof running === "function" || "continuous" in running) return;
1393
1420
  const work = running.finished;
1394
1421
  finished = new Promise((resolve) => {
1395
1422
  settle2 = resolve;
@@ -1398,11 +1425,14 @@ var kuinetic = (() => {
1398
1425
  },
1399
1426
  cancel: teardown,
1400
1427
  finish() {
1401
- if (typeof running === "object") running.finish?.();
1428
+ if (typeof running === "object" && "finish" in running) running.finish?.();
1402
1429
  settle2?.();
1403
1430
  },
1404
1431
  destroy: teardown,
1405
- finished: () => finished
1432
+ finished: () => finished,
1433
+ // Only an explicit marker counts. A bare `Cleanup` deliberately does not — see
1434
+ // `ContinuousSetup` above for why the two cannot be told apart by shape.
1435
+ continuous: () => typeof running === "object" && "continuous" in running
1406
1436
  });
1407
1437
  }
1408
1438
  function deferPrepare(setup) {
@@ -1426,6 +1456,9 @@ var kuinetic = (() => {
1426
1456
  get finished() {
1427
1457
  return hooks.finished?.() ?? Promise.resolve();
1428
1458
  },
1459
+ get continuous() {
1460
+ return hooks.continuous?.() ?? false;
1461
+ },
1429
1462
  destroy() {
1430
1463
  active = false;
1431
1464
  hooks.destroy();
@@ -1437,6 +1470,7 @@ var kuinetic = (() => {
1437
1470
  function createStyleLedger(el) {
1438
1471
  const style = el.style;
1439
1472
  const previous = /* @__PURE__ */ new Map();
1473
+ const authoredStyleAttribute = el.hasAttribute("style");
1440
1474
  function remember(property) {
1441
1475
  if (previous.has(property)) return;
1442
1476
  const existing = style.getPropertyValue(property);
@@ -1454,6 +1488,8 @@ var kuinetic = (() => {
1454
1488
  else style.setProperty(property, value);
1455
1489
  }
1456
1490
  previous.clear();
1491
+ if (!authoredStyleAttribute && style.length === 0 && !el.getAttribute("style"))
1492
+ el.removeAttribute("style");
1457
1493
  },
1458
1494
  owned: () => [...previous.keys()]
1459
1495
  };
@@ -1487,6 +1523,8 @@ var kuinetic = (() => {
1487
1523
  index++;
1488
1524
  }
1489
1525
  }
1526
+ ;
1527
+ group.style.setProperty("--kui-stagger-count", String(Math.max(index, 1)));
1490
1528
  }
1491
1529
  function applyStagger(root) {
1492
1530
  const selector = `[${ATTR.stagger}]`;
@@ -1498,12 +1536,14 @@ var kuinetic = (() => {
1498
1536
  function planStyles(input) {
1499
1537
  const { plan, config, capabilities, respectReducedMotion } = input;
1500
1538
  const reduce = respectReducedMotion && capabilities.reducedMotion;
1501
- const useNativeTimeline = supportsTimeline(config.timeline, capabilities) && plan.supportedTimelines.includes(config.timeline);
1539
+ const scrubbed = config.timeline === "pin" && plan.supportedTimelines.includes("pin");
1540
+ const useNativeTimeline = !scrubbed && supportsTimeline(config.timeline, capabilities) && plan.supportedTimelines.includes(config.timeline);
1502
1541
  const properties = { ...plan.vars, ...plan.declarations };
1503
1542
  Object.assign(properties, timelineProperties(config, capabilities, useNativeTimeline));
1504
1543
  const hasCssAnimation = Object.keys(plan.declarations).length > 0;
1505
1544
  const gate = resolveGate({
1506
1545
  useNativeTimeline,
1546
+ scrubbed: scrubbed && hasCssAnimation,
1507
1547
  reduce,
1508
1548
  activation: config.activation,
1509
1549
  // JS effects are gated too. They emit no `animation` declaration, so only the play-state
@@ -1518,7 +1558,7 @@ var kuinetic = (() => {
1518
1558
  // already applied under reduced motion.
1519
1559
  unsupportedTransform: needsIndividualTransforms(plan.channels, capabilities)
1520
1560
  });
1521
- if (gate === "deferred") properties["animation-play-state"] = "paused";
1561
+ if (gate === "deferred" || gate === "scrubbed") properties["animation-play-state"] = "paused";
1522
1562
  return {
1523
1563
  properties,
1524
1564
  attributes: {
@@ -1542,6 +1582,7 @@ var kuinetic = (() => {
1542
1582
  }
1543
1583
  function resolveGate(input) {
1544
1584
  if (input.useNativeTimeline) return "native-timeline";
1585
+ if (input.scrubbed) return "scrubbed";
1545
1586
  if (!input.hasWork) return "immediate";
1546
1587
  if (input.reduce || input.activation === "load" || input.unsupportedTransform) return "immediate";
1547
1588
  return "deferred";
@@ -1722,7 +1763,9 @@ var kuinetic = (() => {
1722
1763
  this.liveElements.add(el);
1723
1764
  if (Object.keys(stylePlan.properties).some((property) => property.startsWith("animation-"))) {
1724
1765
  const animationNames = (plan.declarations["animation-name"] ?? "").split(",").map((name) => name.trim()).filter(Boolean);
1725
- state.instances.push(createCssInstance(el, ledger, animationNames));
1766
+ state.instances.push(
1767
+ createCssInstance(el, ledger, animationNames, stylePlan.gate === "scrubbed")
1768
+ );
1726
1769
  }
1727
1770
  state.instances.push(
1728
1771
  ...this.jsEffectPreparer.prepare({ el, plan, signal: controller.signal, ledger })
@@ -1783,7 +1826,9 @@ var kuinetic = (() => {
1783
1826
  state.attributes.set(ATTR.state, "failed");
1784
1827
  return;
1785
1828
  }
1786
- void Promise.all(started.map((instance) => instance.finished)).then(() => {
1829
+ const timed = started.filter((instance) => !instance.continuous);
1830
+ if (timed.length === 0 && started.length > 0) return;
1831
+ void Promise.all(timed.map((instance) => instance.finished)).then(() => {
1787
1832
  if (this.states.get(el) !== state || state.status !== "running") return;
1788
1833
  state.status = "finished";
1789
1834
  state.attributes.set(ATTR.state, "finished");
@@ -1972,7 +2017,18 @@ var kuinetic = (() => {
1972
2017
  background: "background",
1973
2018
  color: "color",
1974
2019
  stroke: "stroke",
1975
- text: "text"
2020
+ text: "text",
2021
+ /**
2022
+ * Skew is the one transform CSS never gave an independent property to — there is no `skew:`
2023
+ * beside `translate:`/`rotate:`/`scale:`, so it can only be written through the `transform`
2024
+ * shorthand. That makes it its own channel: anything writing `transform` clobbers the whole
2025
+ * shorthand, so every primitive that does is on this channel, whatever the transform is for.
2026
+ * `scroll-skew` is one member; `flip-face` (`effects/three-d`) and `flip-3d`
2027
+ * (`effects/catalog/core`, the `flip-in-*`/`flip-out-*` family) are the other two — both need
2028
+ * the `perspective()` transform *function* for an element to have depth on itself, which
2029
+ * likewise only exists inside `transform`.
2030
+ */
2031
+ skew: "skew"
1976
2032
  };
1977
2033
  function inertInstance(destroy = () => {
1978
2034
  }) {
@@ -2026,6 +2082,13 @@ var kuinetic = (() => {
2026
2082
  ease: { type: "easing", default: "ease-in-out", cssProperty: "--kui-ease" },
2027
2083
  distance: { type: "length", default: "14px", cssProperty: "--kui-distance" }
2028
2084
  };
2085
+ var orbit = {
2086
+ duration: { type: "time", default: "3.5s", cssProperty: "--kui-duration" },
2087
+ // `linear` by default, unlike every other ambient primitive: a continuous rotation that eases
2088
+ // visibly stutters once per revolution, because the ease restarts at each iteration boundary.
2089
+ ease: { type: "easing", default: "linear", cssProperty: "--kui-ease" },
2090
+ angle: { type: "angle", default: "360deg", cssProperty: "--kui-to-angle" }
2091
+ };
2029
2092
  var pulse = {
2030
2093
  duration: { type: "time", default: "2.2s", cssProperty: "--kui-duration" },
2031
2094
  ease: { type: "easing", default: "ease-in-out", cssProperty: "--kui-ease" },
@@ -2044,6 +2107,12 @@ var kuinetic = (() => {
2044
2107
  reducedMotion: "disable",
2045
2108
  perfClass: "continuous"
2046
2109
  }),
2110
+ cssPrimitive("ambient-orbit", [CHANNEL.rotate], {
2111
+ parameters: orbit,
2112
+ defaultActivation: "load",
2113
+ reducedMotion: "disable",
2114
+ perfClass: "continuous"
2115
+ }),
2047
2116
  cssPrimitive("ambient-pulse", [CHANNEL.scale, CHANNEL.opacity], {
2048
2117
  parameters: pulse,
2049
2118
  defaultActivation: "load",
@@ -2115,6 +2184,7 @@ var kuinetic = (() => {
2115
2184
  keyframes: "kui-floating-shapes",
2116
2185
  params: { duration: "6s", distance: "10px" }
2117
2186
  },
2187
+ { name: "orbit", primitive: "ambient-orbit", keyframes: "kui-orbit" },
2118
2188
  { name: "glow-pulse", primitive: "ambient-pulse", keyframes: "kui-glow-pulse" }
2119
2189
  ];
2120
2190
  function registerAmbient(registry) {
@@ -2431,6 +2501,9 @@ var kuinetic = (() => {
2431
2501
  var liftParams = {
2432
2502
  distance: { type: "length", default: "6px", cssProperty: "--kui-lift-distance" }
2433
2503
  };
2504
+ var popParams = {
2505
+ scale: { type: "number", default: "1.06", cssProperty: "--kui-pop-scale", finite: true, minimum: 0 }
2506
+ };
2434
2507
  function hoverPrimitive(id, channels, extraParams = {}) {
2435
2508
  return {
2436
2509
  id,
@@ -2452,6 +2525,7 @@ var kuinetic = (() => {
2452
2525
  }
2453
2526
  var HOVER_PRIMITIVES = [
2454
2527
  hoverPrimitive("lift", ["translate"], liftParams),
2528
+ hoverPrimitive("pop", ["scale"], popParams),
2455
2529
  hoverPrimitive("lift-shadow", ["translate", "shadow"], liftParams),
2456
2530
  hoverPrimitive("shine-sweep", ["sweep"]),
2457
2531
  hoverPrimitive("split-flap", ["rotate"]),
@@ -2762,12 +2836,173 @@ var kuinetic = (() => {
2762
2836
  return registry.registerPrimitives(INTERACTION_PRIMITIVES).registerPresets(INTERACTION_PRESETS);
2763
2837
  }
2764
2838
 
2839
+ // src/effects/catalog/media-shared.ts
2840
+ var AXIS_DEGREES = { vertical: 0, horizontal: 90 };
2841
+ var UNIT_DEGREES = { deg: 1, grad: 0.9, rad: 180 / Math.PI, turn: 360 };
2842
+ var BAND_OVERLAP_PX = 1;
2843
+ var STAGE_CLASS = "kui-slat-stage";
2844
+ var SLAT_CLASS = "kui-slat-item";
2845
+ var GOLDEN_RATIO_CONJUGATE = 0.6180339887498949;
2846
+ function slatOrder(index, count, from) {
2847
+ if (count <= 1) return 0;
2848
+ switch (from) {
2849
+ case "start":
2850
+ return index;
2851
+ case "end":
2852
+ return count - 1 - index;
2853
+ case "edges":
2854
+ return Math.min(index, count - 1 - index);
2855
+ case "random-ish":
2856
+ return Math.floor(index * GOLDEN_RATIO_CONJUGATE % 1 * count);
2857
+ case "alternate":
2858
+ default:
2859
+ return zigzagRank(index, count);
2860
+ }
2861
+ }
2862
+ function zigzagRank(index, count) {
2863
+ const fromStart = index;
2864
+ const fromEnd = count - 1 - index;
2865
+ const pair = Math.min(fromStart, fromEnd);
2866
+ return fromStart <= fromEnd ? pair * 2 : pair * 2 + 1;
2867
+ }
2868
+ function slatAngleDegrees(authored, axis) {
2869
+ const trimmed = authored.trim();
2870
+ if (!trimmed) return AXIS_DEGREES[axis];
2871
+ const match = /^(-?(?:\d+(?:\.\d+)?|\.\d+))(deg|rad|grad|turn)?$/.exec(trimmed);
2872
+ if (!match) return AXIS_DEGREES[axis];
2873
+ const value = Number(match[1]);
2874
+ if (!Number.isFinite(value)) return AXIS_DEGREES[axis];
2875
+ const unit = match[2] ?? "deg";
2876
+ const degrees = value * UNIT_DEGREES[unit];
2877
+ return (degrees % 180 + 180) % 180;
2878
+ }
2879
+ function slatTravelVector(angleDegrees) {
2880
+ const theta = angleDegrees * Math.PI / 180;
2881
+ return { x: -Math.sin(theta), y: Math.cos(theta) };
2882
+ }
2883
+ function slatBandClip(index, count, angleDegrees, box) {
2884
+ const { width, height } = box;
2885
+ const theta = angleDegrees * Math.PI / 180;
2886
+ const nx = Math.cos(theta);
2887
+ const ny = Math.sin(theta);
2888
+ const { x: dx, y: dy } = slatTravelVector(angleDegrees);
2889
+ const span = Math.abs(nx) * width + Math.abs(ny) * height;
2890
+ const centreX = width / 2;
2891
+ const centreY = height / 2;
2892
+ const step = span / count;
2893
+ const near = index * step - span / 2 - BAND_OVERLAP_PX;
2894
+ const far = (index + 1) * step - span / 2 + BAND_OVERLAP_PX;
2895
+ const reach = width + height;
2896
+ const corner = (along, across) => `${(centreX + along * nx + across * dx).toFixed(2)}px ${(centreY + along * ny + across * dy).toFixed(2)}px`;
2897
+ return `polygon(${corner(near, reach)}, ${corner(near, -reach)}, ${corner(far, -reach)}, ${corner(far, reach)})`;
2898
+ }
2899
+ function axisLabel(angleDegrees) {
2900
+ if (angleDegrees === 0) return "vertical";
2901
+ if (angleDegrees === 90) return "horizontal";
2902
+ return "diagonal";
2903
+ }
2904
+ function syncStageToImage(stage, img, bands) {
2905
+ const { slats, angleDegrees } = bands;
2906
+ const width = img.offsetWidth;
2907
+ const height = img.offsetHeight;
2908
+ stage.style.top = `${img.offsetTop}px`;
2909
+ stage.style.left = `${img.offsetLeft}px`;
2910
+ stage.style.width = `${width}px`;
2911
+ stage.style.height = `${height}px`;
2912
+ slats.forEach((slat, index) => {
2913
+ slat.style.clipPath = slatBandClip(index, slats.length, angleDegrees, { width, height });
2914
+ });
2915
+ }
2916
+ function watchImageBox(stage, img, win, bands) {
2917
+ const handler = () => syncStageToImage(stage, img, bands);
2918
+ win.addEventListener("resize", handler, { passive: true });
2919
+ const stopWindow = () => win.removeEventListener("resize", handler);
2920
+ const ResizeObserverCtor = win.ResizeObserver;
2921
+ if (!ResizeObserverCtor) return stopWindow;
2922
+ const observer = new ResizeObserverCtor(handler);
2923
+ observer.observe(img);
2924
+ return () => {
2925
+ stopWindow();
2926
+ observer.disconnect();
2927
+ };
2928
+ }
2929
+ function imagePaintStyle(img, win) {
2930
+ const computed = win.getComputedStyle(img);
2931
+ const position = computed.objectPosition || "50% 50%";
2932
+ const fit = computed.objectFit;
2933
+ if (fit === "cover") return { size: "cover", position };
2934
+ if (fit === "contain" || fit === "scale-down") return { size: "contain", position };
2935
+ if (fit === "none") return { size: "auto", position };
2936
+ return { size: "100% 100%", position };
2937
+ }
2938
+ function installSlatStage(el, doc, win, options) {
2939
+ const img = el.querySelector("img");
2940
+ if (!img) return null;
2941
+ const url = img.currentSrc || img.getAttribute("src") || "";
2942
+ if (!url) return null;
2943
+ const { count, angleDegrees, from, fold } = options;
2944
+ const travel = slatTravelVector(angleDegrees);
2945
+ const stage = doc.createElement("div");
2946
+ stage.className = STAGE_CLASS;
2947
+ stage.setAttribute("aria-hidden", "true");
2948
+ stage.dataset.kuiSlatAxis = axisLabel(angleDegrees);
2949
+ stage.dataset.kuiSlatAngle = String(angleDegrees);
2950
+ stage.dataset.kuiSlatFold = String(fold);
2951
+ stage.style.setProperty("--kui-slat-count", String(count));
2952
+ stage.style.setProperty("--kui-slat-dx", travel.x.toFixed(4));
2953
+ stage.style.setProperty("--kui-slat-dy", travel.y.toFixed(4));
2954
+ const paint = imagePaintStyle(img, win);
2955
+ const slats = [];
2956
+ for (let index = 0; index < count; index++) {
2957
+ const slat = doc.createElement("div");
2958
+ slat.className = SLAT_CLASS;
2959
+ slat.style.setProperty("--kui-slat-index", String(index));
2960
+ slat.style.setProperty("--kui-i", String(slatOrder(index, count, from)));
2961
+ slat.style.backgroundImage = `url("${url}")`;
2962
+ slat.style.backgroundSize = paint.size;
2963
+ slat.style.backgroundPosition = paint.position;
2964
+ stage.append(slat);
2965
+ slats.push(slat);
2966
+ }
2967
+ el.append(stage);
2968
+ const bands = { slats, angleDegrees };
2969
+ syncStageToImage(stage, img, bands);
2970
+ const stopWatching = watchImageBox(stage, img, win, bands);
2971
+ const imageStyles = createStyleLedger(img);
2972
+ imageStyles.set("visibility", "hidden");
2973
+ return {
2974
+ stage,
2975
+ slats,
2976
+ restore: () => {
2977
+ stopWatching();
2978
+ imageStyles.restore();
2979
+ stage.remove();
2980
+ }
2981
+ };
2982
+ }
2983
+ function applySlatTimingVars(stage, params) {
2984
+ const { durationMs, delayMs, easing } = params.timing;
2985
+ const duration = durationMs === void 0 ? params.text("duration", "500ms") : `${durationMs}ms`;
2986
+ const delay = delayMs === void 0 ? params.text("delay", "0ms") : `${delayMs}ms`;
2987
+ stage.style.setProperty("--kui-duration", duration);
2988
+ stage.style.setProperty("--kui-delay", delay);
2989
+ stage.style.setProperty("--kui-ease", easing ?? params.text("ease", "ease-out"));
2990
+ stage.style.setProperty("--kui-stagger", params.text("stagger", "60ms"));
2991
+ }
2992
+ function slatAssembleFinishMs(params, count) {
2993
+ if (count === 0) return 0;
2994
+ const durationMs = params.timing.durationMs ?? params.ms("duration", 500);
2995
+ const delayMs = params.timing.delayMs ?? params.ms("delay", 0);
2996
+ const staggerMs = params.ms("stagger", 60);
2997
+ return delayMs + (count - 1) * staggerMs + durationMs;
2998
+ }
2999
+
2765
3000
  // src/effects/catalog/media.ts
2766
3001
  var geometry = {
2767
3002
  distance: { type: "length", default: "24px", cssProperty: "--kui-distance" },
2768
3003
  scale: { type: "number", default: "1.12", cssProperty: "--kui-to-scale" }
2769
3004
  };
2770
- var MEDIA_PRIMITIVES = [
3005
+ var MEDIA_CSS_PRIMITIVES = [
2771
3006
  cssPrimitive("media-wipe", [CHANNEL.clip]),
2772
3007
  cssPrimitive("media-mask", ["mask"], { perfClass: "paint" }),
2773
3008
  // Not `reducedMotion: 'disable'` — that policy means "no finite duration would make sense,
@@ -2788,33 +3023,66 @@ var kuinetic = (() => {
2788
3023
  defaultActivation: "hover",
2789
3024
  perfClass: "paint"
2790
3025
  }),
3026
+ // `geometry.distance` only, not `...geometry`: `kui-blur-up` (media.css) reads `--kui-distance`
3027
+ // and `--kui-blur` but never `--kui-to-scale` — this primitive doesn't even declare
3028
+ // `CHANNEL.scale`. Spreading the whole shared object used to expose `scale:` as an
3029
+ // apparently-valid, silently-inert parameter, the same shape `flip-3d`'s dead `perspective`
3030
+ // parameter was (`entrance.css`'s comment on `kui-flip-in-x`).
2791
3031
  cssPrimitive("media-blur-up", [CHANNEL.translate, CHANNEL.filter], {
2792
- parameters: { ...geometry, blur: { type: "length", default: "16px", cssProperty: "--kui-blur" } },
3032
+ parameters: {
3033
+ distance: geometry.distance,
3034
+ blur: { type: "length", default: "16px", cssProperty: "--kui-blur" }
3035
+ },
2793
3036
  perfClass: "paint"
2794
3037
  }),
3038
+ // No `defaultActivation` — same convention `core.ts`'s `parallax`/`parallax-scale`/
3039
+ // `parallax-rotate`/`scroll-fade`/`desaturate`/`skew`/`progress`/`progress-stroke` already use
3040
+ // for every other `timelines: ['view', 'scroll', ...]` primitive. `resolveActivation`
3041
+ // (`animator.ts`) only consults `defaultActivation` when the author named no activation, and
3042
+ // falls through to `element-config.ts`'s hardcoded `'enter'` when a primitive declares none.
3043
+ // Setting it to `'manual'` here (matching `activations: ['manual']`) looked like the obviously
3044
+ // correct pairing, but it is what actually broke the effect: `effectiveActivation`
3045
+ // (`style-plan.ts`) only converts a stuck `'manual'` into `'enter'` when `config.timeline !==
3046
+ // 'time'` — i.e. only once the author has actually written `timeline:view`/`timeline:scroll`.
3047
+ // Authored bare (no `timeline:`, the sweep's own probe and the likely first thing anyone
3048
+ // tries), `config.timeline` stays the default `'time'`, that conversion never fires, and the
3049
+ // element sits at `data-kui-state="ready"` forever — which is also the state
3050
+ // `entrance.css`'s `[data-kui-state='ready'] { --kui-distance: 0px !important; }` targets, so
3051
+ // every sample read the same permanently-zeroed `--kui-distance`: not a paused animation, a
3052
+ // zeroed one. `timeline:view`/`timeline:scroll` usage is unaffected either way, since a native
3053
+ // timeline resolves to the `'native-timeline'` gate before activation is even consulted.
3054
+ // `geometry.distance` only: `kui-image-parallax-frame` never reads `--kui-to-scale` and this
3055
+ // primitive doesn't declare `CHANNEL.scale` — same dead-parameter shape as `media-blur-up` above.
2795
3056
  cssPrimitive("media-parallax-frame", [CHANNEL.translate], {
2796
- parameters: geometry,
3057
+ parameters: { distance: geometry.distance },
2797
3058
  timelines: ["view", "scroll"],
2798
3059
  activations: ["manual"],
2799
- defaultActivation: "manual",
2800
3060
  reducedMotion: "disable"
2801
3061
  }),
3062
+ // Its own `scale` parameter, not `geometry`: `kui-lightbox-open` opens from a fixed 0.92, never
3063
+ // reading `--kui-to-scale` (or any `distance`, since this primitive doesn't animate position at
3064
+ // all) — the whole shared object was dead weight here. Unlike `media-blur-up`/
3065
+ // `media-parallax-frame`, this primitive *does* declare `CHANNEL.scale`, so the fix is to wire
3066
+ // the keyframe up to a real parameter rather than remove the promise: `--kui-from-scale`, the
3067
+ // same name and "starts at this scale, animates to 1" meaning `scale`/`scale-move`
3068
+ // (`catalog/core.ts`) already use, so `lightbox-open scale:0.8` now does what it looks like it
3069
+ // should. See `kui-lightbox-open` in `media.css`.
2802
3070
  cssPrimitive("media-lightbox", [CHANNEL.opacity, CHANNEL.scale], {
2803
- parameters: geometry
3071
+ parameters: { scale: { type: "number", default: "0.92", cssProperty: "--kui-from-scale" } }
2804
3072
  })
2805
3073
  ];
2806
- var MEDIA_PRESETS = [
2807
- { name: "wipe-up", primitive: "media-wipe", keyframes: "kui-wipe-up" },
2808
- { name: "wipe-down", primitive: "media-wipe", keyframes: "kui-wipe-down" },
2809
- { name: "wipe-left", primitive: "media-wipe", keyframes: "kui-wipe-left" },
2810
- { name: "wipe-right", primitive: "media-wipe", keyframes: "kui-wipe-right" },
2811
- { name: "wipe-circle", primitive: "media-wipe", keyframes: "kui-wipe-circle" },
2812
- { name: "wipe-diagonal", primitive: "media-wipe", keyframes: "kui-wipe-diagonal" },
2813
- { name: "mask-reveal", primitive: "media-mask", keyframes: "kui-mask-reveal" },
2814
- { name: "curtain-reveal", primitive: "media-wipe", keyframes: "kui-curtain-reveal" },
3074
+ var MEDIA_CSS_PRESETS = [
3075
+ { name: "wipe-up", primitive: "media-wipe", keyframes: "kui-wipe-up", cloak: true },
3076
+ { name: "wipe-down", primitive: "media-wipe", keyframes: "kui-wipe-down", cloak: true },
3077
+ { name: "wipe-left", primitive: "media-wipe", keyframes: "kui-wipe-left", cloak: true },
3078
+ { name: "wipe-right", primitive: "media-wipe", keyframes: "kui-wipe-right", cloak: true },
3079
+ { name: "wipe-circle", primitive: "media-wipe", keyframes: "kui-wipe-circle", cloak: true },
3080
+ { name: "wipe-diagonal", primitive: "media-wipe", keyframes: "kui-wipe-diagonal", cloak: true },
3081
+ { name: "mask-reveal", primitive: "media-mask", keyframes: "kui-mask-reveal", cloak: true },
3082
+ { name: "curtain-reveal", primitive: "media-wipe", keyframes: "kui-curtain-reveal", cloak: true },
2815
3083
  { name: "ken-burns", primitive: "media-ken-burns", keyframes: "kui-ken-burns" },
2816
3084
  { name: "ken-burns-out", primitive: "media-ken-burns", keyframes: "kui-ken-burns-out" },
2817
- { name: "blur-up", primitive: "media-blur-up", keyframes: "kui-blur-up" },
3085
+ { name: "blur-up", primitive: "media-blur-up", keyframes: "kui-blur-up", cloak: true },
2818
3086
  { name: "duotone-hover", primitive: "media-filter", keyframes: "kui-duotone-hover" },
2819
3087
  { name: "grayscale-hover", primitive: "media-filter", keyframes: "kui-grayscale-hover" },
2820
3088
  { name: "saturate-hover", primitive: "media-filter", keyframes: "kui-saturate-hover" },
@@ -2826,14 +3094,131 @@ var kuinetic = (() => {
2826
3094
  { name: "before-after-wipe", primitive: "media-wipe", keyframes: "kui-before-after-wipe" },
2827
3095
  { name: "lightbox-open", primitive: "media-lightbox", keyframes: "kui-lightbox-open" }
2828
3096
  ];
3097
+ var slatParams = {
3098
+ slats: {
3099
+ type: "number",
3100
+ default: "8",
3101
+ cssProperty: "--kui-slats",
3102
+ minimum: 2,
3103
+ maximum: 24,
3104
+ integer: true
3105
+ },
3106
+ axis: {
3107
+ type: "keyword",
3108
+ default: "vertical",
3109
+ cssProperty: "--kui-axis",
3110
+ values: ["vertical", "horizontal"]
3111
+ },
3112
+ /*
3113
+ * The general form of `axis:`, in degrees: `0deg` is `axis:vertical`, `90deg` is
3114
+ * `axis:horizontal`, and anything between cuts the picture into diagonal bands. An authored
3115
+ * angle wins; leaving it off reads `axis:`, so every existing attribute keeps its meaning.
3116
+ *
3117
+ * `text`, not `angle`, for one reason: `readParams` pre-fills every declared parameter with its
3118
+ * schema default, so a typed default is indistinguishable from an authored value and there would
3119
+ * be no way to tell `angle:0deg` from "no angle, use the axis". An empty default is only possible
3120
+ * on a type that is never written to a stylesheet, which is exactly what `text` is for — and this
3121
+ * value never reaches CSS anyway. `slatAngleDegrees` does the parsing and the range clamp.
3122
+ */
3123
+ angle: { type: "text", default: "", cssProperty: "--kui-slat-angle" },
3124
+ from: {
3125
+ type: "keyword",
3126
+ default: "alternate",
3127
+ cssProperty: "--kui-from",
3128
+ values: ["alternate", "start", "end", "edges", "random-ish"]
3129
+ },
3130
+ fold: { type: "keyword", default: "false", cssProperty: "--kui-fold", values: ["true", "false"] },
3131
+ duration: { type: "time", default: "500ms", cssProperty: "--kui-duration" },
3132
+ delay: { type: "time", default: "0ms", cssProperty: "--kui-delay" },
3133
+ ease: { type: "easing", default: "ease-out", cssProperty: "--kui-ease" },
3134
+ stagger: { type: "time", default: "60ms", cssProperty: "--kui-stagger" }
3135
+ };
3136
+ function prepareSlatAssemble(el, params, ctx) {
3137
+ const doc = el.ownerDocument;
3138
+ const count = Math.min(24, Math.max(2, Math.round(params.num("slats", 8))));
3139
+ const axis = params.text("axis", "vertical");
3140
+ const angleDegrees = slatAngleDegrees(params.text("angle", ""), axis);
3141
+ const from = params.text("from", "alternate");
3142
+ const fold = params.is("fold");
3143
+ const node = el;
3144
+ if (ctx.win.getComputedStyle(node).position === "static") ctx.style.set("position", "relative");
3145
+ const built = installSlatStage(el, doc, ctx.win, { count, angleDegrees, from, fold });
3146
+ if (!built) return () => {
3147
+ };
3148
+ const { stage } = built;
3149
+ applySlatTimingVars(stage, params);
3150
+ stage.classList.add("kui-slat-animating");
3151
+ let settle2;
3152
+ const finished = new Promise((resolve) => {
3153
+ settle2 = resolve;
3154
+ });
3155
+ let landed = false;
3156
+ const land = () => {
3157
+ if (landed) return;
3158
+ landed = true;
3159
+ stage.classList.remove("kui-slat-animating");
3160
+ built.restore();
3161
+ settle2();
3162
+ };
3163
+ const timer = ctx.win.setTimeout(land, slatAssembleFinishMs(params, count));
3164
+ return {
3165
+ cleanup: () => {
3166
+ ctx.win.clearTimeout(timer);
3167
+ if (landed) return;
3168
+ landed = true;
3169
+ built.restore();
3170
+ },
3171
+ finished,
3172
+ finish: () => {
3173
+ ctx.win.clearTimeout(timer);
3174
+ land();
3175
+ }
3176
+ };
3177
+ }
3178
+ var MEDIA_JS_PRIMITIVES = [
3179
+ {
3180
+ id: "slat-assemble",
3181
+ renderer: "javascript",
3182
+ channels: [CHANNEL.opacity, CHANNEL.translate, CHANNEL.rotate],
3183
+ parameters: slatParams,
3184
+ supportedTimelines: ["time"],
3185
+ supportedActivations: ["load", "enter", "hover", "focus", "click", "manual"],
3186
+ defaultActivation: "enter",
3187
+ perfClass: "dom-transform",
3188
+ // Same reasoning as every JS-rendered primitive in `text.ts`: nothing here declares a CSS
3189
+ // `animation-duration` the reduced-motion policy layer could shorten, and `disable` is what
3190
+ // stops `installSlatStage`'s DOM surgery from ever running at all under reduced motion — the
3191
+ // animator never calls `activate()`, so the wrapped `<img>` is simply left exactly as authored.
3192
+ reducedMotion: "disable",
3193
+ // Land()ing hands the picture back to the real `<img>` and tears down every slat — see
3194
+ // `prepareSlatAssemble`'s `land()`. Declared, not assumed: see `restoresOnFinish`'s own comment
3195
+ // in `core/types.ts` for why the catalog's default is the opposite of this.
3196
+ restoresOnFinish: true,
3197
+ prepare: deferPrepare(prepareSlatAssemble)
3198
+ }
3199
+ ];
3200
+ var MEDIA_JS_PRESETS = [
3201
+ { name: "slat-assemble", primitive: "slat-assemble", cloak: true }
3202
+ ];
3203
+ var MEDIA_PRIMITIVES = [...MEDIA_CSS_PRIMITIVES, ...MEDIA_JS_PRIMITIVES];
3204
+ var MEDIA_PRESETS = [...MEDIA_CSS_PRESETS, ...MEDIA_JS_PRESETS];
2829
3205
  function registerMedia(registry) {
2830
3206
  return registry.registerPrimitives(MEDIA_PRIMITIVES).registerPresets(MEDIA_PRESETS);
2831
3207
  }
2832
3208
 
3209
+ // src/effects/catalog/subtree-capture.ts
3210
+ function captureChildren(el) {
3211
+ const authored = Array.from(el.childNodes);
3212
+ return () => {
3213
+ el.replaceChildren(...authored);
3214
+ };
3215
+ }
3216
+
2833
3217
  // src/effects/catalog/numbers-shared.ts
2834
3218
  var SR_ONLY_CLASS = "kui-sr-only";
2835
3219
  var DECORATIVE_CLASS = "kui-count-decorative";
2836
3220
  function installCountLayers(el, doc) {
3221
+ const restoreChildren = captureChildren(el);
2837
3222
  const decorative = doc.createElement("span");
2838
3223
  decorative.setAttribute("aria-hidden", "true");
2839
3224
  decorative.className = DECORATIVE_CLASS;
@@ -2845,9 +3230,7 @@ var kuinetic = (() => {
2845
3230
  return {
2846
3231
  decorative,
2847
3232
  srOnly,
2848
- restore: () => {
2849
- el.textContent = srOnly.textContent;
2850
- }
3233
+ restore: restoreChildren
2851
3234
  };
2852
3235
  }
2853
3236
  function easeOutCubic(t) {
@@ -3157,7 +3540,12 @@ var kuinetic = (() => {
3157
3540
  ];
3158
3541
  var METER_PRIMITIVES = [
3159
3542
  cssPrimitive("stroke-sweep", [CHANNEL.stroke]),
3160
- cssPrimitive("meter-bar", [CHANNEL.scale]),
3543
+ // `from` gives `progress-bar` a real knob on its start scale — it had none before. `--kui-bar-from`
3544
+ // is also what the `[data-kui-fx~='progress-bar'][data-kui-state='ready']` gate in numbers.css
3545
+ // neutralizes; see that rule's comment for the on:enter fix this parameter doubles as.
3546
+ cssPrimitive("meter-bar", [CHANNEL.scale], {
3547
+ parameters: { from: { type: "number", default: "0", cssProperty: "--kui-bar-from" } }
3548
+ }),
3161
3549
  cssPrimitive("meter-segments", [CHANNEL.opacity]),
3162
3550
  cssPrimitive("meter-stars", [CHANNEL.clip])
3163
3551
  ];
@@ -3166,7 +3554,13 @@ var kuinetic = (() => {
3166
3554
  { name: "gauge-sweep", primitive: "stroke-sweep", keyframes: "kui-gauge-sweep" },
3167
3555
  { name: "donut-sweep", primitive: "stroke-sweep", keyframes: "kui-donut-sweep" },
3168
3556
  { name: "sparkline-draw", primitive: "stroke-sweep", keyframes: "kui-sparkline-draw" },
3169
- { name: "progress-bar", primitive: "meter-bar", keyframes: "kui-progress-bar" },
3557
+ // `cloak: true`: `kui-progress-bar`'s `from { scale: 0 1 }` (numbers.css) is a zero-width box
3558
+ // while paused, not just an invisible one — so while it waits it occupies no space in layout at
3559
+ // all. Not, despite the tidier story, because an observer refuses to fire on it: Chromium was
3560
+ // measured resolving a zero-area target's `intersectionRatio` to `1`. See numbers.css's
3561
+ // `[data-kui-fx~='progress-bar'][data-kui-state='ready']` rule for the geometry half of the fix;
3562
+ // `cloak` keeps the pre-JS and post-JS "waiting" look the same (invisible) either side of it.
3563
+ { name: "progress-bar", primitive: "meter-bar", keyframes: "kui-progress-bar", cloak: true },
3170
3564
  { name: "progress-segments", primitive: "meter-segments", keyframes: "kui-progress-segments" },
3171
3565
  { name: "star-rating-fill", primitive: "meter-stars", keyframes: "kui-star-rating-fill" }
3172
3566
  ];
@@ -3181,6 +3575,7 @@ var kuinetic = (() => {
3181
3575
  var DECORATIVE_CLASS2 = "kui-split-decorative";
3182
3576
  function installSplitLayers(el, doc) {
3183
3577
  const originalText = el.textContent.trim();
3578
+ const restoreChildren = captureChildren(el);
3184
3579
  const decorative = doc.createElement("span");
3185
3580
  decorative.setAttribute("aria-hidden", "true");
3186
3581
  decorative.className = DECORATIVE_CLASS2;
@@ -3192,9 +3587,7 @@ var kuinetic = (() => {
3192
3587
  return {
3193
3588
  decorative,
3194
3589
  originalText,
3195
- restore: () => {
3196
- el.textContent = originalText;
3197
- }
3590
+ restore: restoreChildren
3198
3591
  };
3199
3592
  }
3200
3593
  function segmentGraphemes(text) {
@@ -3362,14 +3755,43 @@ var kuinetic = (() => {
3362
3755
  distance: { type: "length", default: "32px", cssProperty: "--kui-distance" }
3363
3756
  };
3364
3757
  var TEXT_CSS_PRIMITIVES = [
3365
- cssPrimitive("text-shimmer", [CHANNEL.background], { reducedMotion: "disable" }),
3758
+ // `color`, alongside `background`: both presets' unconditional rule sets `-webkit-text-fill-color:
3759
+ // transparent` so the `background-image` gradient shows through the glyphs (the standard
3760
+ // gradient-text technique). That is a real claim on the glyph fill, the same physical property
3761
+ // `text-outline-fill` animates on its own `color` channel below — without this, the two looked
3762
+ // disjoint to the compiler (`background` vs `stroke`+`color`) and composing them would let
3763
+ // whichever applied last silently win the glyph fill instead of being flagged as a conflict.
3764
+ cssPrimitive("text-shimmer", [CHANNEL.background, CHANNEL.color], { reducedMotion: "disable" }),
3765
+ // `gradient-sweep` is the only one of the three `text-sweep`-family presets whose keyframe
3766
+ // touches `-webkit-text-fill-color` (see text.css) — `highlight-sweep` and `underline-draw` only
3767
+ // paint a `background-image`. Claiming `color` for all three made the compiler reject compositions
3768
+ // like `underline-draw, text-outline-fill` as a glyph-fill conflict even though they touch disjoint
3769
+ // properties. Split so only the preset that actually claims the fill declares the channel.
3770
+ cssPrimitive("text-gradient-sweep", [CHANNEL.background, CHANNEL.color], { parameters: textSweepParams }),
3366
3771
  cssPrimitive("text-sweep", [CHANNEL.background], { parameters: textSweepParams }),
3367
3772
  cssPrimitive("text-outline-fill", [CHANNEL.stroke, CHANNEL.color]),
3368
3773
  cssPrimitive("var-weight", ["font"], { parameters: fontWeightParams }),
3369
3774
  cssPrimitive("var-width", ["font"], { parameters: fontWidthParams }),
3370
3775
  cssPrimitive("var-slant", ["font"], { parameters: fontSlantParams }),
3776
+ /*
3777
+ * `defaultActivation: 'load'` for the same reason every ambient primitive declares it, and it
3778
+ * was missing here: a marquee is continuous motion, so `reducedMotion: 'disable'` is only half
3779
+ * the rule `ambient.ts` spells out — the other half is starting on `load` rather than waiting on
3780
+ * a scroll-triggered `enter`.
3781
+ *
3782
+ * Without it, a bare `data-kui="marquee 42s"` resolved to `enter`, which `style-plan.ts`'s
3783
+ * `resolveGate` sends down the `deferred` path and stamps `animation-play-state: paused`. It
3784
+ * compiled correctly, reported `data-kui-state="ready"`, and never ran — measured on a marquee
3785
+ * fully in view, so this was not an observer that had simply not fired yet. Every page carrying
3786
+ * one had to know to write `on:load`, which is exactly the kind of thing an author cannot be
3787
+ * expected to guess.
3788
+ *
3789
+ * `marquee-scroll-linked` is unaffected: its position comes from `animation-timeline: scroll()`,
3790
+ * not from an activation.
3791
+ */
3371
3792
  cssPrimitive("text-marquee", [CHANNEL.translate], {
3372
3793
  timelines: ["time", "scroll"],
3794
+ defaultActivation: "load",
3373
3795
  reducedMotion: "disable"
3374
3796
  }),
3375
3797
  cssPrimitive("redaction-reveal", [CHANNEL.clip]),
@@ -3377,7 +3799,7 @@ var kuinetic = (() => {
3377
3799
  ];
3378
3800
  var TEXT_CSS_PRESETS = [
3379
3801
  { name: "gradient-shimmer", primitive: "text-shimmer", keyframes: "kui-gradient-shimmer" },
3380
- { name: "gradient-sweep", primitive: "text-sweep", keyframes: "kui-gradient-sweep" },
3802
+ { name: "gradient-sweep", primitive: "text-gradient-sweep", keyframes: "kui-gradient-sweep" },
3381
3803
  {
3382
3804
  name: "highlight-sweep",
3383
3805
  primitive: "text-sweep",
@@ -3540,9 +3962,10 @@ var kuinetic = (() => {
3540
3962
  layers.decorative.textContent = scrambledFrame(graphemes, resolved, charset, Math.random);
3541
3963
  };
3542
3964
  render();
3965
+ const totalTicks = Math.max(1, graphemes.length * revealEvery);
3543
3966
  const run = createStepRunner(ctx.win, {
3544
3967
  delayMs: params.timing.delayMs ?? 0,
3545
- stepMs: stepMsFor(params, graphemes.length * revealEvery, 40),
3968
+ stepMs: stepMsFor(params, totalTicks, Math.max(1, 700 / totalTicks)),
3546
3969
  tick: () => {
3547
3970
  ticks++;
3548
3971
  if (ticks % revealEvery === 0) resolved++;
@@ -3567,7 +3990,7 @@ var kuinetic = (() => {
3567
3990
  const words = params.text("words", "").split("|").map((word) => word.trim()).filter(Boolean);
3568
3991
  if (words.length === 0) return () => {
3569
3992
  };
3570
- const original = el.textContent;
3993
+ const restoreChildren = captureChildren(el);
3571
3994
  const swapMs = 150;
3572
3995
  let index = 0;
3573
3996
  el.textContent = words[0];
@@ -3588,7 +4011,7 @@ var kuinetic = (() => {
3588
4011
  cleanup: () => {
3589
4012
  run.stop();
3590
4013
  el.classList.remove("kui-word-cycler-swap");
3591
- el.textContent = original;
4014
+ restoreChildren();
3592
4015
  },
3593
4016
  finished: run.finished,
3594
4017
  finish: () => run.stop()
@@ -3624,9 +4047,9 @@ var kuinetic = (() => {
3624
4047
  { name: "split-chars", primitive: "split-text", params: { unit: "chars", direction: "fade" } },
3625
4048
  { name: "split-words", primitive: "split-text", params: { unit: "words", direction: "fade" } },
3626
4049
  { name: "split-lines", primitive: "split-text", params: { unit: "lines", direction: "fade" } },
3627
- { name: "text-reveal-up", primitive: "split-text", params: { unit: "words", direction: "up" } },
3628
- { name: "text-reveal-down", primitive: "split-text", params: { unit: "words", direction: "down" } },
3629
- { name: "text-reveal-mask", primitive: "split-text", params: { unit: "lines", direction: "mask" } },
4050
+ { name: "text-reveal-up", primitive: "split-text", params: { unit: "words", direction: "up" }, cloak: true },
4051
+ { name: "text-reveal-down", primitive: "split-text", params: { unit: "words", direction: "down" }, cloak: true },
4052
+ { name: "text-reveal-mask", primitive: "split-text", params: { unit: "lines", direction: "mask" }, cloak: true },
3630
4053
  { name: "text-wave", primitive: "split-text-motion", params: { motion: "wave" } },
3631
4054
  { name: "text-jitter", primitive: "split-text-motion", params: { motion: "jitter" } },
3632
4055
  { name: "typewriter", primitive: "typewriter", params: { loop: "false" } },
@@ -3658,66 +4081,130 @@ var kuinetic = (() => {
3658
4081
  distance: { type: "length", default: "24px", cssProperty: "--kui-distance" },
3659
4082
  opacity: { type: "number", default: "0", cssProperty: "--kui-from-opacity" }
3660
4083
  };
4084
+ var ENTRANCE_TIMELINES = ["time", "view", "scroll", "pin"];
3661
4085
  var PRIMITIVES = [
3662
4086
  // --- entrance / exit -------------------------------------------------------------------
3663
- cssPrimitive("reveal", [CHANNEL.opacity, CHANNEL.translate], { parameters: distance2 }),
4087
+ cssPrimitive("reveal", [CHANNEL.opacity, CHANNEL.translate], { timelines: ENTRANCE_TIMELINES, parameters: distance2 }),
3664
4088
  cssPrimitive("scale", [CHANNEL.scale], {
4089
+ timelines: ENTRANCE_TIMELINES,
3665
4090
  parameters: { scale: { type: "number", default: "0.92", cssProperty: "--kui-from-scale" } }
3666
4091
  }),
3667
4092
  // Separate from `scale` because it claims translate as well and so composes differently.
4093
+ // `distance.distance` only, not `...distance`: `kui-zoom-in-up`/`-down` (entrance.css) read
4094
+ // `--kui-distance` and `--kui-from-scale` but never `--kui-from-opacity` — this primitive
4095
+ // doesn't declare `CHANNEL.opacity`. Spreading the whole shared `distance` object used to expose
4096
+ // `opacity:` as an apparently-valid, silently-inert parameter (same dead-parameter shape as
4097
+ // `flip-3d`'s old `perspective`, fixed above).
3668
4098
  cssPrimitive("scale-move", [CHANNEL.scale, CHANNEL.translate], {
4099
+ timelines: ENTRANCE_TIMELINES,
3669
4100
  parameters: {
3670
- ...distance2,
4101
+ distance: distance2.distance,
3671
4102
  scale: { type: "number", default: "0.92", cssProperty: "--kui-from-scale" }
3672
4103
  }
3673
4104
  }),
3674
4105
  cssPrimitive("rotate", [CHANNEL.rotate], {
4106
+ timelines: ENTRANCE_TIMELINES,
3675
4107
  parameters: { angle: { type: "angle", default: "-8deg", cssProperty: "--kui-from-angle" } }
3676
4108
  }),
4109
+ // `distance.distance` only, not `...distance`: `kui-roll-in`/`-out` (entrance.css) write
4110
+ // `rotate`/`translate`, never `opacity` — this primitive doesn't declare `CHANNEL.opacity`. Same
4111
+ // dead-parameter shape as `scale-move` above.
3677
4112
  cssPrimitive("roll", [CHANNEL.rotate, CHANNEL.translate], {
4113
+ timelines: ENTRANCE_TIMELINES,
3678
4114
  parameters: {
3679
- ...distance2,
4115
+ distance: distance2.distance,
3680
4116
  angle: { type: "angle", default: "-120deg", cssProperty: "--kui-from-angle" }
3681
4117
  }
3682
4118
  }),
3683
- cssPrimitive("flip-3d", [CHANNEL.rotate], {
4119
+ // `skew`, not `rotate`: entrance.css's keyframes write `transform: perspective(...)
4120
+ // rotateX/Y(...)`, not the individual `rotate:` property — the `perspective` parameter below
4121
+ // used to compile cleanly and do nothing, because nothing read it. See entrance.css's own
4122
+ // comment on `kui-flip-in-x` for the fix; `CHANNEL.skew` is this catalog's name for "claims the
4123
+ // whole `transform` shorthand" (`core/types.ts`), shared with `scroll-skew` and `flip-face`.
4124
+ cssPrimitive("flip-3d", [CHANNEL.skew], {
4125
+ timelines: ENTRANCE_TIMELINES,
3684
4126
  parameters: {
3685
4127
  angle: { type: "angle", default: "90deg", cssProperty: "--kui-from-angle" },
3686
4128
  perspective: { type: "length", default: "1200px", cssProperty: "--kui-perspective" }
3687
4129
  }
3688
4130
  }),
3689
4131
  cssPrimitive("blur", [CHANNEL.filter], {
4132
+ timelines: ENTRANCE_TIMELINES,
3690
4133
  parameters: { blur: { type: "length", default: "12px", cssProperty: "--kui-blur" } }
3691
4134
  }),
3692
4135
  // Purpose-built combination: one keyframe, so opacity is written once instead of twice.
3693
4136
  cssPrimitive("reveal-blur", [CHANNEL.opacity, CHANNEL.translate, CHANNEL.filter], {
4137
+ timelines: ENTRANCE_TIMELINES,
3694
4138
  parameters: { ...distance2, blur: { type: "length", default: "12px", cssProperty: "--kui-blur" } }
3695
4139
  }),
3696
4140
  // --- scroll-linked ---------------------------------------------------------------------
3697
4141
  // These are progress-linked, not time-triggered: they reverse as the user scrolls back.
3698
4142
  // That is by design and is why `timeline:` is a different axis from `on:`.
4143
+ // `distance.distance` only, not the whole `distance` object: `kui-parallax-y`/`-x` (scroll.css)
4144
+ // write only `translate` — this primitive doesn't declare `CHANNEL.opacity`. Same dead-parameter
4145
+ // shape as `scale-move`/`roll` above; `parallax-y`/`parallax-x`/`depth-layer` never read
4146
+ // `--kui-from-opacity`.
3699
4147
  cssPrimitive("parallax", [CHANNEL.translate], {
3700
- parameters: distance2,
3701
- timelines: ["view", "scroll"],
4148
+ parameters: { distance: distance2.distance },
4149
+ timelines: ["view", "scroll", "pin"],
3702
4150
  activations: ["manual"],
3703
4151
  reducedMotion: "disable",
3704
4152
  perfClass: "compositor"
3705
4153
  }),
4154
+ // `from` exists because the resting end was hardcoded (scale 1 / rotate 0deg), which fixed
4155
+ // these to "grow slightly" and "tilt slightly" — a scroll-driven element that should sweep in
4156
+ // from a quarter-size or from half a turn away had no way to say so. Same `--kui-from-*`
4157
+ // properties the entrance primitives already use, so the two stay spellable the same way.
3706
4158
  cssPrimitive("parallax-scale", [CHANNEL.scale], {
3707
- parameters: { scale: { type: "number", default: "1.2", cssProperty: "--kui-to-scale" } },
3708
- timelines: ["view", "scroll"],
4159
+ parameters: {
4160
+ scale: { type: "number", default: "1.2", cssProperty: "--kui-to-scale" },
4161
+ from: { type: "number", default: "1", cssProperty: "--kui-from-scale" }
4162
+ },
4163
+ timelines: ["view", "scroll", "pin"],
3709
4164
  activations: ["manual"],
3710
4165
  reducedMotion: "disable"
3711
4166
  }),
3712
4167
  cssPrimitive("parallax-rotate", [CHANNEL.rotate], {
3713
- parameters: { angle: { type: "angle", default: "12deg", cssProperty: "--kui-to-angle" } },
3714
- timelines: ["view", "scroll"],
4168
+ parameters: {
4169
+ angle: { type: "angle", default: "12deg", cssProperty: "--kui-to-angle" },
4170
+ from: { type: "angle", default: "0deg", cssProperty: "--kui-from-angle" }
4171
+ },
4172
+ timelines: ["view", "scroll", "pin"],
3715
4173
  activations: ["manual"],
3716
4174
  reducedMotion: "disable"
3717
4175
  }),
3718
4176
  cssPrimitive("scroll-fade", [CHANNEL.opacity], {
3719
4177
  parameters: { opacity: { type: "number", default: "0", cssProperty: "--kui-from-opacity" } },
3720
- timelines: ["view", "scroll"],
4178
+ timelines: ["view", "scroll", "pin"],
4179
+ activations: ["manual"],
4180
+ reducedMotion: "disable"
4181
+ }),
4182
+ // `filter`, not `opacity` — it collides with `blur`, and declaring the real channel is what
4183
+ // makes `channels.ts` say so instead of letting the two silently overwrite each other's
4184
+ // `filter` declaration.
4185
+ cssPrimitive("desaturate", [CHANNEL.filter], {
4186
+ parameters: {
4187
+ from: { type: "percentage", default: "100%", cssProperty: "--kui-from-grayscale" },
4188
+ to: { type: "percentage", default: "0%", cssProperty: "--kui-to-grayscale" }
4189
+ },
4190
+ timelines: ["view", "scroll", "pin"],
4191
+ activations: ["manual"],
4192
+ reducedMotion: "disable",
4193
+ perfClass: "paint"
4194
+ }),
4195
+ /*
4196
+ * `transform`, not one of the independent transform properties, because CSS never shipped a
4197
+ * standalone `skew:`. That is also why `skew` is its own channel rather than folded in with
4198
+ * `rotate`: writing `transform` replaces the entire shorthand, so a skew composed with anything
4199
+ * else that wrote `transform` would silently win. Nothing else in the catalog does — every other
4200
+ * transform in the library goes through `translate`/`rotate`/`scale` — so the shorthand is free.
4201
+ */
4202
+ cssPrimitive("skew", [CHANNEL.skew], {
4203
+ parameters: {
4204
+ from: { type: "angle", default: "8deg", cssProperty: "--kui-from-skew" },
4205
+ to: { type: "angle", default: "0deg", cssProperty: "--kui-to-skew" }
4206
+ },
4207
+ timelines: ["view", "scroll", "pin"],
3721
4208
  activations: ["manual"],
3722
4209
  reducedMotion: "disable"
3723
4210
  }),
@@ -3737,13 +4224,14 @@ var kuinetic = (() => {
3737
4224
  })
3738
4225
  ];
3739
4226
  var p = (name, primitive, keyframes, params) => ({ name, primitive, keyframes, ...params ? { params } : {} });
4227
+ var pIn = (name, primitive, keyframes, params) => ({ ...p(name, primitive, keyframes, params), cloak: true });
3740
4228
  var FADE = [
3741
- p("fade-in", "reveal", "kui-in"),
4229
+ pIn("fade-in", "reveal", "kui-in"),
3742
4230
  p("fade-out", "reveal", "kui-out"),
3743
- p("fade-up", "reveal", "kui-in-up"),
3744
- p("fade-down", "reveal", "kui-in-down"),
3745
- p("fade-left", "reveal", "kui-in-left"),
3746
- p("fade-right", "reveal", "kui-in-right"),
4231
+ pIn("fade-up", "reveal", "kui-in-up"),
4232
+ pIn("fade-down", "reveal", "kui-in-down"),
4233
+ pIn("fade-left", "reveal", "kui-in-left"),
4234
+ pIn("fade-right", "reveal", "kui-in-right"),
3747
4235
  p("fade-out-up", "reveal", "kui-out-up"),
3748
4236
  p("fade-out-down", "reveal", "kui-out-down"),
3749
4237
  p("fade-out-left", "reveal", "kui-out-left"),
@@ -3751,56 +4239,56 @@ var kuinetic = (() => {
3751
4239
  ];
3752
4240
  var SLIDE_PARAMS = { distance: "100px", opacity: "1" };
3753
4241
  var SLIDE = [
3754
- p("slide-up", "reveal", "kui-in-up", SLIDE_PARAMS),
3755
- p("slide-down", "reveal", "kui-in-down", SLIDE_PARAMS),
3756
- p("slide-left", "reveal", "kui-in-left", SLIDE_PARAMS),
3757
- p("slide-right", "reveal", "kui-in-right", SLIDE_PARAMS),
4242
+ pIn("slide-up", "reveal", "kui-in-up", SLIDE_PARAMS),
4243
+ pIn("slide-down", "reveal", "kui-in-down", SLIDE_PARAMS),
4244
+ pIn("slide-left", "reveal", "kui-in-left", SLIDE_PARAMS),
4245
+ pIn("slide-right", "reveal", "kui-in-right", SLIDE_PARAMS),
3758
4246
  p("slide-out-up", "reveal", "kui-out-up", SLIDE_PARAMS),
3759
4247
  p("slide-out-down", "reveal", "kui-out-down", SLIDE_PARAMS),
3760
4248
  p("slide-out-left", "reveal", "kui-out-left", SLIDE_PARAMS),
3761
4249
  p("slide-out-right", "reveal", "kui-out-right", SLIDE_PARAMS)
3762
4250
  ];
3763
4251
  var LOGICAL = [
3764
- p("slide-inline-start", "reveal", "kui-in-inline-start", SLIDE_PARAMS),
3765
- p("slide-inline-end", "reveal", "kui-in-inline-end", SLIDE_PARAMS),
3766
- p("slide-block-start", "reveal", "kui-in-up", SLIDE_PARAMS),
3767
- p("slide-block-end", "reveal", "kui-in-down", SLIDE_PARAMS)
4252
+ pIn("slide-inline-start", "reveal", "kui-in-inline-start", SLIDE_PARAMS),
4253
+ pIn("slide-inline-end", "reveal", "kui-in-inline-end", SLIDE_PARAMS),
4254
+ pIn("slide-block-start", "reveal", "kui-in-up", SLIDE_PARAMS),
4255
+ pIn("slide-block-end", "reveal", "kui-in-down", SLIDE_PARAMS)
3768
4256
  ];
3769
4257
  var ZOOM = [
3770
- p("zoom-in", "scale", "kui-zoom-in"),
4258
+ pIn("zoom-in", "scale", "kui-zoom-in"),
3771
4259
  p("zoom-out", "scale", "kui-zoom-out"),
3772
- p("pop-in", "scale", "kui-zoom-in", { scale: "0.6", ease: "back-out" }),
4260
+ pIn("pop-in", "scale", "kui-zoom-in", { scale: "0.6", ease: "back-out" }),
3773
4261
  p("pop-out", "scale", "kui-zoom-out", { scale: "0.6", ease: "back-in" }),
3774
- p("zoom-in-up", "scale-move", "kui-zoom-in-up"),
3775
- p("zoom-in-down", "scale-move", "kui-zoom-in-down")
4262
+ pIn("zoom-in-up", "scale-move", "kui-zoom-in-up"),
4263
+ pIn("zoom-in-down", "scale-move", "kui-zoom-in-down")
3776
4264
  ];
3777
4265
  var FLIP = [
3778
- p("flip-in-x", "flip-3d", "kui-flip-in-x"),
3779
- p("flip-in-y", "flip-3d", "kui-flip-in-y"),
4266
+ pIn("flip-in-x", "flip-3d", "kui-flip-in-x"),
4267
+ pIn("flip-in-y", "flip-3d", "kui-flip-in-y"),
3780
4268
  p("flip-out-x", "flip-3d", "kui-flip-out-x"),
3781
4269
  p("flip-out-y", "flip-3d", "kui-flip-out-y")
3782
4270
  ];
3783
4271
  var ROTATE = [
3784
- p("rotate-in", "rotate", "kui-rotate-in"),
4272
+ pIn("rotate-in", "rotate", "kui-rotate-in"),
3785
4273
  p("rotate-out", "rotate", "kui-rotate-out"),
3786
- p("rotate-in-left", "rotate", "kui-rotate-in", { angle: "-45deg" }),
3787
- p("rotate-in-right", "rotate", "kui-rotate-in", { angle: "45deg" }),
3788
- p("roll-in", "roll", "kui-roll-in"),
4274
+ pIn("rotate-in-left", "rotate", "kui-rotate-in", { angle: "-45deg" }),
4275
+ pIn("rotate-in-right", "rotate", "kui-rotate-in", { angle: "45deg" }),
4276
+ pIn("roll-in", "roll", "kui-roll-in"),
3789
4277
  p("roll-out", "roll", "kui-roll-out"),
3790
- p("swing-in", "rotate", "kui-swing-in", { angle: "-15deg", ease: "back-out" })
4278
+ pIn("swing-in", "rotate", "kui-swing-in", { angle: "-15deg", ease: "back-out" })
3791
4279
  ];
3792
4280
  var BLUR = [
3793
- p("blur-in", "blur", "kui-blur-in"),
4281
+ pIn("blur-in", "blur", "kui-blur-in"),
3794
4282
  p("blur-out", "blur", "kui-blur-out"),
3795
- p("fade-blur-up", "reveal-blur", "kui-fade-blur-up"),
3796
- p("fade-blur-in", "reveal-blur", "kui-fade-blur-in")
4283
+ pIn("fade-blur-up", "reveal-blur", "kui-fade-blur-up"),
4284
+ pIn("fade-blur-in", "reveal-blur", "kui-fade-blur-in")
3797
4285
  ];
3798
4286
  var CHARACTER = [
3799
- p("bounce-in", "scale", "kui-zoom-in", { scale: "0.3", ease: "back-out" }),
3800
- p("bounce-in-up", "reveal", "kui-in-up", { distance: "60px", ease: "back-out" }),
3801
- p("bounce-in-down", "reveal", "kui-in-down", { distance: "60px", ease: "back-out" }),
3802
- p("back-in-up", "reveal", "kui-in-up", { distance: "120px", ease: "expo-out" }),
3803
- p("back-in-down", "reveal", "kui-in-down", { distance: "120px", ease: "expo-out" })
4287
+ pIn("bounce-in", "scale", "kui-zoom-in", { scale: "0.3", ease: "bounce" }),
4288
+ pIn("bounce-in-up", "reveal", "kui-in-up", { distance: "60px", ease: "back-out" }),
4289
+ pIn("bounce-in-down", "reveal", "kui-in-down", { distance: "60px", ease: "back-out" }),
4290
+ pIn("back-in-up", "reveal", "kui-in-up", { distance: "120px", ease: "expo-out" }),
4291
+ pIn("back-in-down", "reveal", "kui-in-down", { distance: "120px", ease: "expo-out" })
3804
4292
  ];
3805
4293
  var SCROLL = [
3806
4294
  p("parallax-y", "parallax", "kui-parallax-y"),
@@ -3809,11 +4297,14 @@ var kuinetic = (() => {
3809
4297
  p("parallax-rotate", "parallax-rotate", "kui-parallax-rotate"),
3810
4298
  p("depth-layer", "parallax", "kui-parallax-y", { distance: "200px" }),
3811
4299
  p("scroll-fade", "scroll-fade", "kui-scroll-fade"),
4300
+ p("scroll-desaturate", "desaturate", "kui-desaturate"),
4301
+ p("scroll-skew", "skew", "kui-scroll-skew"),
3812
4302
  p("scroll-progress-bar", "progress", "kui-progress-x"),
4303
+ p("scroll-progress-bar-y", "progress", "kui-progress-y"),
3813
4304
  p("scroll-progress-ring", "progress-stroke", "kui-progress-ring"),
3814
4305
  // `reveal-repeat` was removed: it was byte-identical to `reveal-once`, and the activation
3815
4306
  // binder unobserves after first entry, so a repeating reveal is not implementable yet.
3816
- p("reveal-once", "reveal", "kui-in-up")
4307
+ pIn("reveal-once", "reveal", "kui-in-up")
3817
4308
  ];
3818
4309
  var PRESETS = [
3819
4310
  ...FADE,
@@ -3836,6 +4327,59 @@ var kuinetic = (() => {
3836
4327
  return registry;
3837
4328
  }
3838
4329
 
4330
+ // src/effects/step-marking.ts
4331
+ var STEP_STATE_ATTR = "data-kui-step-state";
4332
+ function selectorBreadth(selector, doc) {
4333
+ try {
4334
+ if (doc.documentElement.matches(selector)) return "document-wide";
4335
+ if (doc.body?.matches(selector)) return "document-wide";
4336
+ return "ok";
4337
+ } catch {
4338
+ return "invalid";
4339
+ }
4340
+ }
4341
+ function resolveTarget(selector, ctx, effect) {
4342
+ if (!selector) return selector;
4343
+ const breadth = selectorBreadth(selector, ctx.doc);
4344
+ if (breadth === "invalid") {
4345
+ ctx.warn(`${effect} target "${selector}" is not a valid selector and will be ignored`);
4346
+ return "";
4347
+ }
4348
+ if (breadth === "document-wide") {
4349
+ ctx.warn(`${effect} target "${selector}" matches the whole document and will be ignored`);
4350
+ return "";
4351
+ }
4352
+ return selector;
4353
+ }
4354
+ function createStepMarker(resolve) {
4355
+ const ledgers = /* @__PURE__ */ new Map();
4356
+ return {
4357
+ mark(index) {
4358
+ const seen = /* @__PURE__ */ new Map();
4359
+ for (const node of resolve()) {
4360
+ const parent = node.parentElement;
4361
+ const position = seen.get(parent) ?? 0;
4362
+ seen.set(parent, position + 1);
4363
+ let ledger = ledgers.get(node);
4364
+ if (!ledger) {
4365
+ ledger = createAttributeLedger(node);
4366
+ ledgers.set(node, ledger);
4367
+ }
4368
+ ledger.set(STEP_STATE_ATTR, stepStateFor(position, index));
4369
+ }
4370
+ },
4371
+ restore() {
4372
+ for (const ledger of ledgers.values()) ledger.restore();
4373
+ ledgers.clear();
4374
+ }
4375
+ };
4376
+ }
4377
+ function stepStateFor(position, index) {
4378
+ if (position < index) return "before";
4379
+ if (position === index) return "active";
4380
+ return "after";
4381
+ }
4382
+
3839
4383
  // src/effects/forms/primitives.ts
3840
4384
  var timing = {
3841
4385
  duration: { type: "time", default: "400ms", cssProperty: "--kui-duration" },
@@ -3954,10 +4498,18 @@ var kuinetic = (() => {
3954
4498
  function nextStep(step, total) {
3955
4499
  return total > 0 ? (step + 1) % total : 0;
3956
4500
  }
3957
- function prepareStepProgress(el, params) {
4501
+ function prepareStepProgress(el, params, ctx) {
3958
4502
  const total = Math.max(1, Math.round(params.num("steps", 4)));
4503
+ const selector = resolveTarget(params.text("target"), ctx, "step-progress");
4504
+ const marker = createStepMarker(
4505
+ () => selector ? ctx.doc.querySelectorAll(selector) : el.children
4506
+ );
4507
+ const self = createAttributeLedger(el);
3959
4508
  let step = 0;
3960
- const render = () => el.setAttribute("data-kui-step", String(step));
4509
+ const render = () => {
4510
+ self.set("data-kui-step", String(step));
4511
+ marker.mark(step);
4512
+ };
3961
4513
  const advance = () => {
3962
4514
  step = nextStep(step, total);
3963
4515
  render();
@@ -3966,13 +4518,17 @@ var kuinetic = (() => {
3966
4518
  render();
3967
4519
  return () => {
3968
4520
  el.removeEventListener("click", advance);
3969
- el.removeAttribute("data-kui-step");
4521
+ self.restore();
4522
+ marker.restore();
3970
4523
  };
3971
4524
  }
3972
4525
  var STEP_PROGRESS_PRIMITIVE = jsInputPrimitive(
3973
4526
  "step-progress",
3974
4527
  ["state"],
3975
- { steps: { type: "number", default: "4", cssProperty: "--kui-steps", minimum: 1, maximum: 20, integer: true } },
4528
+ {
4529
+ steps: { type: "number", default: "4", cssProperty: "--kui-steps", minimum: 1, maximum: 20, integer: true },
4530
+ target: { type: "text", default: "", cssProperty: "--kui-target" }
4531
+ },
3976
4532
  deferPrepare(prepareStepProgress)
3977
4533
  );
3978
4534
  function nextSubmitStage(stage) {
@@ -4229,6 +4785,7 @@ var kuinetic = (() => {
4229
4785
  const resistance = params.num("resistance", 0.55);
4230
4786
  const momentum = params.num("momentum", 0.2);
4231
4787
  const offset = { x: 0, y: 0 };
4788
+ const pickup = { x: 0, y: 0 };
4232
4789
  const deps = springDeps(ctx);
4233
4790
  const runners = {
4234
4791
  x: createSpringRunner(config, (value) => write({ ...offset, x: value }), deps),
@@ -4245,10 +4802,15 @@ var kuinetic = (() => {
4245
4802
  onStart() {
4246
4803
  runners.x.stop();
4247
4804
  runners.y.stop();
4805
+ pickup.x = offset.x;
4806
+ pickup.y = offset.y;
4248
4807
  el.setAttribute("data-kui-dragging", "true");
4249
4808
  },
4250
4809
  onMove(vector) {
4251
- write({ x: resist(vector.dx, bounds, resistance), y: resist(vector.dy, bounds, resistance) });
4810
+ write({
4811
+ x: resist(pickup.x + vector.dx, bounds, resistance),
4812
+ y: resist(pickup.y + vector.dy, bounds, resistance)
4813
+ });
4252
4814
  },
4253
4815
  onEnd(vector) {
4254
4816
  el.setAttribute("data-kui-dragging", "false");
@@ -4276,8 +4838,9 @@ var kuinetic = (() => {
4276
4838
  runners.y.to(0);
4277
4839
  return;
4278
4840
  }
4279
- runners.x.to(offset.x + vector.vx * mode.momentum);
4280
- runners.y.to(offset.y + vector.vy * mode.momentum);
4841
+ const carry = mode.inertia ? mode.momentum : 0;
4842
+ runners.x.to(offset.x + vector.vx * carry);
4843
+ runners.y.to(offset.y + vector.vy * carry);
4281
4844
  }
4282
4845
  function prepareSwipeable(el, params) {
4283
4846
  const stop = recognise(
@@ -4561,9 +5124,12 @@ var kuinetic = (() => {
4561
5124
  ctx.style.claim("height");
4562
5125
  const duration = effectDurationMs(params, 400);
4563
5126
  let animation = null;
5127
+ let previous = node.getBoundingClientRect().height;
4564
5128
  const observer = watchAttribute(node, params.text("attribute"), () => {
4565
5129
  animation?.cancel();
4566
- animation = animateHeight(node, duration, params.text("ease"));
5130
+ const endpoints = heightEndpoints(node, previous);
5131
+ previous = endpoints.to;
5132
+ animation = animateHeight(node, endpoints, duration, params.text("ease"));
4567
5133
  });
4568
5134
  ctx.invalidate();
4569
5135
  return () => {
@@ -4571,13 +5137,19 @@ var kuinetic = (() => {
4571
5137
  animation?.cancel();
4572
5138
  };
4573
5139
  }
4574
- function animateHeight(node, duration, easing) {
4575
- const from = `${node.getBoundingClientRect().height}px`;
5140
+ function heightEndpoints(node, previous) {
4576
5141
  node.style.removeProperty("height");
4577
- const to = `${node.scrollHeight}px`;
5142
+ const to = node.getBoundingClientRect().height;
5143
+ return { from: previous, to };
5144
+ }
5145
+ function animateHeight(node, endpoints, duration, easing) {
4578
5146
  const animate = node.animate;
4579
5147
  if (typeof animate !== "function") return null;
4580
- return animate.call(node, [{ height: from }, { height: to }], { duration, easing, fill: "none" });
5148
+ return animate.call(
5149
+ node,
5150
+ [{ height: `${endpoints.from}px` }, { height: `${endpoints.to}px` }],
5151
+ { duration, easing, fill: "none" }
5152
+ );
4581
5153
  }
4582
5154
  function prepareIndicator(el, params, ctx) {
4583
5155
  const node = el;
@@ -4707,27 +5279,42 @@ var kuinetic = (() => {
4707
5279
  }
4708
5280
  function prepareHeaderShrink(el, params, ctx) {
4709
5281
  const offset = params.num("offset", 120);
4710
- return subscribeScrollTop(el, ctx, (top) => {
5282
+ const state = createAttributeLedger(el);
5283
+ const unsubscribe = subscribeScrollTop(el, ctx, (top) => {
4711
5284
  const progress = offset > 0 ? Math.min(1, Math.max(0, top / offset)) : 1;
4712
5285
  ctx.style.set("--kui-shrink", progress.toFixed(4));
4713
- el.setAttribute("data-kui-shrunk", String(progress >= 1));
5286
+ state.set("data-kui-shrunk", String(progress >= 1));
4714
5287
  });
5288
+ return () => {
5289
+ unsubscribe();
5290
+ state.restore();
5291
+ };
4715
5292
  }
4716
5293
  function prepareHeaderHide(el, params, ctx) {
4717
5294
  const minDelta = params.num("offset", 8);
4718
5295
  let last = 0;
4719
- return subscribeScrollTop(el, ctx, (top) => {
5296
+ const state = createAttributeLedger(el);
5297
+ const unsubscribe = subscribeScrollTop(el, ctx, (top) => {
4720
5298
  const delta = top - last;
4721
5299
  if (Math.abs(delta) < minDelta) return;
4722
- el.setAttribute("data-kui-hidden", String(delta > 0 && top > minDelta));
5300
+ state.set("data-kui-hidden", String(delta > 0 && top > minDelta));
4723
5301
  last = top;
4724
5302
  });
5303
+ return () => {
5304
+ unsubscribe();
5305
+ state.restore();
5306
+ };
4725
5307
  }
4726
5308
  function prepareBackToTop(el, params, ctx) {
4727
5309
  const offset = params.num("offset", 400);
4728
- return subscribeScrollTop(el, ctx, (top) => {
4729
- el.setAttribute("data-kui-visible", String(top > offset));
5310
+ const state = createAttributeLedger(el);
5311
+ const unsubscribe = subscribeScrollTop(el, ctx, (top) => {
5312
+ state.set("data-kui-visible", String(top > offset));
4730
5313
  });
5314
+ return () => {
5315
+ unsubscribe();
5316
+ state.restore();
5317
+ };
4731
5318
  }
4732
5319
  var NAV_JS_PRIMITIVES = [
4733
5320
  navPrimitive(
@@ -4765,13 +5352,38 @@ var kuinetic = (() => {
4765
5352
  const rect = el.getBoundingClientRect();
4766
5353
  return { top: rect.top, height: rect.height };
4767
5354
  };
5355
+ var domPosition = (el) => {
5356
+ const view = el.ownerDocument?.defaultView;
5357
+ return view ? view.getComputedStyle(el).position : "static";
5358
+ };
5359
+ var domOffsetTop = (el) => {
5360
+ const view = el.ownerDocument?.defaultView;
5361
+ if (!view) return 0;
5362
+ const parsed = Number.parseFloat(view.getComputedStyle(el).top);
5363
+ return Number.isFinite(parsed) ? parsed : 0;
5364
+ };
5365
+ function geometrySource(el, positionOf) {
5366
+ let outermostSticky = null;
5367
+ for (let node = el; node; node = node.parentElement) {
5368
+ if (positionOf(node) === "sticky") outermostSticky = node;
5369
+ }
5370
+ return outermostSticky?.parentElement ?? el;
5371
+ }
5372
+ function sourceTop(el, box, measure, positionOf) {
5373
+ const source = geometrySource(el, positionOf);
5374
+ return source === el ? box.top : measure(source).top;
5375
+ }
4768
5376
  function trackProgress(el, ctx, options, onProgress) {
4769
5377
  const measure = options.measure ?? domGeometry;
5378
+ const positionOf = options.positionOf ?? domPosition;
5379
+ const offsetOf = options.offsetOf ?? domOffsetTop;
4770
5380
  let scrollTop = 0;
4771
5381
  let scrollportTop = 0;
4772
5382
  const geometry2 = createMeasureCache(() => {
4773
5383
  const box = measure(el);
4774
- return { contentTop: box.top - scrollportTop + scrollTop, height: box.height };
5384
+ const top = options.contentAnchor ? measure(options.contentAnchor).top - box.height : sourceTop(el, box, measure, positionOf);
5385
+ const stickyOffset = options.stickyEl ? offsetOf(options.stickyEl) : 0;
5386
+ return { contentTop: top - stickyOffset - scrollportTop + scrollTop, height: box.height };
4775
5387
  });
4776
5388
  return ctx.scheduler.subscribe(ctx.rootFor(el), (frame) => {
4777
5389
  scrollTop = frame.metrics.scrollTop;
@@ -4797,11 +5409,167 @@ var kuinetic = (() => {
4797
5409
  return clamp01(-top / span);
4798
5410
  }
4799
5411
 
5412
+ // src/effects/scroll-mechanics/scroll-spy.ts
5413
+ function prepareScrollSpy(el, params, ctx) {
5414
+ const sectionsAuthored = params.text("sections");
5415
+ if (sectionsAuthored) {
5416
+ const sectionsSelector = resolveTarget(sectionsAuthored, ctx, "scroll-spy sections");
5417
+ return prepareScrollSpyContainer(el, params, ctx, sectionsSelector);
5418
+ }
5419
+ return prepareScrollSpySingle(el, params, ctx);
5420
+ }
5421
+ function prepareScrollSpySingle(el, params, ctx) {
5422
+ if (params.text("offset-top", "0px") !== "0px") {
5423
+ ctx.warn('scroll-spy "offset-top" has no effect without sections: and is ignored here');
5424
+ }
5425
+ const selector = resolveTarget(params.text("target"), ctx, "scroll-spy");
5426
+ const links = /* @__PURE__ */ new Map();
5427
+ const self = createAttributeLedger(el);
5428
+ let last;
5429
+ const untrack = trackProgress(el, ctx, { distance: params.text("distance") }, (progress) => {
5430
+ const active = progress > 0 && progress < 1;
5431
+ if (active === last) return;
5432
+ last = active;
5433
+ self.set("data-kui-active", String(active));
5434
+ if (selector) markLinks(ctx.doc, selector, active, links);
5435
+ });
5436
+ return continuousSetup(() => {
5437
+ untrack();
5438
+ self.restore();
5439
+ for (const ledger of links.values()) ledger.restore();
5440
+ });
5441
+ }
5442
+ function markLinks(doc, selector, active, links) {
5443
+ for (const link of doc.querySelectorAll(selector)) {
5444
+ let ledger = links.get(link);
5445
+ if (!ledger) {
5446
+ ledger = createAttributeLedger(link);
5447
+ links.set(link, ledger);
5448
+ }
5449
+ ledger.set("data-kui-active", String(active));
5450
+ }
5451
+ }
5452
+ function hrefHash(link) {
5453
+ const href = link.getAttribute("href") ?? "";
5454
+ const at = href.indexOf("#");
5455
+ return at === -1 ? "" : href.slice(at);
5456
+ }
5457
+ function pairSectionsWithLinks(sections, links, ctx, sectionsSelector) {
5458
+ const linksByHash = /* @__PURE__ */ new Map();
5459
+ for (const link of links) {
5460
+ const hash = hrefHash(link);
5461
+ if (hash) linksByHash.set(hash, link);
5462
+ }
5463
+ const claimed = /* @__PURE__ */ new Set();
5464
+ const pairs = sections.map((section) => {
5465
+ if (!section.id) {
5466
+ ctx.warn(
5467
+ `scroll-spy: a section matched by sections:"${sectionsSelector}" has no id and cannot be paired with a link`
5468
+ );
5469
+ return { section, link: null };
5470
+ }
5471
+ const hash = `#${section.id}`;
5472
+ const link = linksByHash.get(hash) ?? null;
5473
+ if (link) claimed.add(hash);
5474
+ return { section, link };
5475
+ });
5476
+ for (const [hash, link] of linksByHash) {
5477
+ if (!claimed.has(hash)) {
5478
+ ctx.warn(`scroll-spy: link "${link.getAttribute("href")}" matches no section id in sections:"${sectionsSelector}"`);
5479
+ }
5480
+ }
5481
+ return pairs;
5482
+ }
5483
+ function offsetTopPixels(authored, frame) {
5484
+ return toPixels(
5485
+ authored,
5486
+ {
5487
+ viewportWidth: frame.metrics.viewportWidth,
5488
+ viewportHeight: frame.metrics.viewportHeight,
5489
+ percentBasis: 0,
5490
+ fontSize: 16,
5491
+ rootFontSize: 16
5492
+ },
5493
+ 0
5494
+ );
5495
+ }
5496
+ function highestReachedIndex(tops, scrollTop, line) {
5497
+ let index = -1;
5498
+ for (let i = 0; i < tops.length; i++) {
5499
+ if (tops[i] - scrollTop - line <= 0) index = i;
5500
+ }
5501
+ return index;
5502
+ }
5503
+ function prepareScrollSpyContainer(el, params, ctx, sectionsSelector) {
5504
+ if (params.text("distance", "100vh") !== "100vh") {
5505
+ ctx.warn('scroll-spy "distance" has no effect with sections: \u2014 each section measures its own height');
5506
+ }
5507
+ const linksSelector = resolveTarget(params.text("target"), ctx, "scroll-spy target");
5508
+ const sections = sectionsSelector ? [...el.querySelectorAll(sectionsSelector)] : [];
5509
+ if (sectionsSelector && sections.length === 0) {
5510
+ ctx.warn(`scroll-spy sections:"${sectionsSelector}" matched nothing inside this element`);
5511
+ }
5512
+ const links = linksSelector ? [...el.querySelectorAll(linksSelector)] : [];
5513
+ const pairs = pairSectionsWithLinks(sections, links, ctx, sectionsSelector);
5514
+ const sectionLedgers = pairs.map((pair) => createAttributeLedger(pair.section));
5515
+ const linkLedgers = /* @__PURE__ */ new Map();
5516
+ for (const { link } of pairs) {
5517
+ if (link && !linkLedgers.has(link)) linkLedgers.set(link, createAttributeLedger(link));
5518
+ }
5519
+ const offsetAuthored = params.text("offset-top", "0px");
5520
+ let scrollTop = 0;
5521
+ let scrollportTop = 0;
5522
+ const contentTops = createMeasureCache(
5523
+ () => pairs.map(({ section }) => domGeometry(section).top - scrollportTop + scrollTop)
5524
+ );
5525
+ let active = -1;
5526
+ function setActive(index, value) {
5527
+ const pair = pairs[index];
5528
+ sectionLedgers[index].set("data-kui-active", String(value));
5529
+ if (pair.link) linkLedgers.get(pair.link).set("data-kui-active", String(value));
5530
+ }
5531
+ const untrack = ctx.scheduler.subscribe(ctx.rootFor(el), (frame) => {
5532
+ scrollTop = frame.metrics.scrollTop;
5533
+ scrollportTop = frame.metrics.viewportTop;
5534
+ const tops = contentTops.read(frame.epoch);
5535
+ const line = offsetTopPixels(offsetAuthored, frame);
5536
+ const next = highestReachedIndex(tops, scrollTop, line);
5537
+ if (next === active) return;
5538
+ if (active !== -1) setActive(active, false);
5539
+ if (next !== -1) setActive(next, true);
5540
+ active = next;
5541
+ });
5542
+ return continuousSetup(() => {
5543
+ untrack();
5544
+ for (const ledger of sectionLedgers) ledger.restore();
5545
+ for (const ledger of linkLedgers.values()) ledger.restore();
5546
+ });
5547
+ }
5548
+
4800
5549
  // src/effects/scroll-mechanics/primitives.ts
4801
5550
  var PROGRESS_VAR = "--kui-progress";
4802
5551
  var distanceParam = {
4803
5552
  distance: { type: "length", default: "100vh", cssProperty: "--kui-distance" }
4804
5553
  };
5554
+ var stickyParams = {
5555
+ "offset-top": {
5556
+ type: "length",
5557
+ default: "var(--kui-pin-offset, 0px)",
5558
+ cssProperty: "--kui-offset-top"
5559
+ },
5560
+ spacer: {
5561
+ type: "keyword",
5562
+ default: "false",
5563
+ cssProperty: "--kui-spacer",
5564
+ values: ["true", "false"]
5565
+ }
5566
+ };
5567
+ function installSticky(node, params, ctx) {
5568
+ ctx.style.set("position", "sticky");
5569
+ ctx.style.set("top", params.text("offset-top", "var(--kui-pin-offset, 0px)"));
5570
+ const inserted = params.is("spacer") ? insertSpacer(node, params.text("distance"), ctx) : null;
5571
+ return { spacer: inserted?.spacer ?? null, dispose: () => inserted?.remove() };
5572
+ }
4805
5573
  function scrollPrimitive(spec) {
4806
5574
  const { id, channels, parameters, prepare, perfClass = "compositor" } = spec;
4807
5575
  return {
@@ -4809,7 +5577,12 @@ var kuinetic = (() => {
4809
5577
  renderer: "javascript",
4810
5578
  channels,
4811
5579
  parameters,
4812
- supportedTimelines: ["time", "view", "scroll"],
5580
+ // `'pin'` is accepted but ignored: these primitives read scroll position themselves and are
5581
+ // never driven by an `animation-timeline`. It is listed so that composing the driver with the
5582
+ // effects it drives — `data-kui="pin-section distance:200vh, parallax-rotate ... "` plus
5583
+ // `timeline:pin` — survives `compile.ts`'s `intersect`. Without it the intersection empties,
5584
+ // `style-plan.ts` refuses the timeline, and the scrub silently degrades to a one-shot.
5585
+ supportedTimelines: ["time", "view", "scroll", "pin"],
4813
5586
  supportedActivations: ["manual", "load", "enter"],
4814
5587
  defaultActivation: "load",
4815
5588
  perfClass,
@@ -4822,19 +5595,17 @@ var kuinetic = (() => {
4822
5595
  }
4823
5596
  function preparePin(el, params, ctx) {
4824
5597
  const node = el;
4825
- ctx.style.set("position", "sticky");
4826
- ctx.style.set("top", params.text("offset", "0px"));
4827
- const removeSpacer = params.is("spacer") ? insertSpacer(node, params.text("distance"), ctx) : null;
5598
+ const { dispose: unstick } = installSticky(node, params, ctx);
4828
5599
  const tracked = node.parentElement ?? el;
4829
- const untrack = trackProgress(tracked, ctx, { distance: params.text("distance") }, (progress) => {
5600
+ const untrack = trackProgress(tracked, ctx, { distance: params.text("distance"), stickyEl: node }, (progress) => {
4830
5601
  writeProgress(ctx, progress);
4831
5602
  el.setAttribute("data-kui-pinned", progress > 0 && progress < 1 ? "true" : "false");
4832
5603
  });
4833
- return () => {
5604
+ return continuousSetup(() => {
4834
5605
  untrack();
4835
- removeSpacer?.();
5606
+ unstick();
4836
5607
  el.removeAttribute("data-kui-pinned");
4837
- };
5608
+ });
4838
5609
  }
4839
5610
  function insertSpacer(node, distance3, ctx) {
4840
5611
  const spacer = ctx.doc.createElement("div");
@@ -4844,34 +5615,81 @@ var kuinetic = (() => {
4844
5615
  spacer.style.pointerEvents = "none";
4845
5616
  node.after(spacer);
4846
5617
  ctx.invalidate();
4847
- return () => {
4848
- spacer.remove();
4849
- ctx.invalidate();
5618
+ return {
5619
+ spacer,
5620
+ remove: () => {
5621
+ spacer.remove();
5622
+ ctx.invalidate();
5623
+ }
4850
5624
  };
4851
5625
  }
4852
5626
  function prepareProgress(el, params, ctx) {
4853
5627
  const steps = Math.max(0, Math.round(params.num("steps", 0)));
5628
+ const selector = resolveTarget(params.text("target"), ctx, "scrollytelling-step");
5629
+ const marker = createStepMarker(() => ctx.doc.querySelectorAll(selector));
5630
+ const self = createAttributeLedger(el);
5631
+ let lastIndex;
4854
5632
  const untrack = trackProgress(el, ctx, { distance: params.text("distance") }, (progress) => {
4855
5633
  writeProgress(ctx, progress);
4856
- if (steps > 0) {
4857
- const index = Math.min(steps - 1, Math.floor(progress * steps));
4858
- el.setAttribute("data-kui-step", String(index));
4859
- }
5634
+ if (steps === 0) return;
5635
+ const index = Math.min(steps - 1, Math.floor(progress * steps));
5636
+ if (index === lastIndex) return;
5637
+ lastIndex = index;
5638
+ self.set("data-kui-step", String(index));
5639
+ ctx.style.set("--kui-step", String(index));
5640
+ if (selector) marker.mark(index);
4860
5641
  });
4861
- return () => {
5642
+ return continuousSetup(() => {
4862
5643
  untrack();
4863
- el.removeAttribute("data-kui-step");
4864
- };
5644
+ self.restore();
5645
+ marker.restore();
5646
+ });
4865
5647
  }
4866
5648
  function prepareHorizontal(el, params, ctx) {
4867
- const node = el;
5649
+ const selector = resolveTarget(params.text("target"), ctx, "horizontal-scroll");
5650
+ if (!selector) return prepareBareTrack(el, params, ctx);
5651
+ const track = el.querySelector(selector);
5652
+ if (!track) {
5653
+ ctx.warn(`horizontal-scroll target "${selector}" matched nothing inside this element`);
5654
+ return () => {
5655
+ };
5656
+ }
5657
+ return prepareManagedTrack(el, track, params, ctx);
5658
+ }
5659
+ function prepareBareTrack(node, params, ctx) {
4868
5660
  const authored = params.text("travel", "auto");
4869
5661
  const travel = createMeasureCache(() => trackTravel(node, authored, node.ownerDocument));
4870
- const untrack = trackProgress(el, ctx, { distance: params.text("distance") }, (progress, frame) => {
4871
- ctx.style.set("translate", `${-progress * travel.read(frame.epoch)}px 0`);
5662
+ return continuousSetup(
5663
+ trackProgress(node, ctx, { distance: params.text("distance") }, (progress, frame) => {
5664
+ ctx.style.set("translate", `${-progress * travel.read(frame.epoch)}px 0`);
5665
+ writeProgress(ctx, progress);
5666
+ })
5667
+ );
5668
+ }
5669
+ function prepareManagedTrack(host, track, params, ctx) {
5670
+ const offsetTop = params.text("offset-top", "var(--kui-pin-offset, 0px)");
5671
+ ctx.style.set("position", "sticky");
5672
+ ctx.style.set("top", offsetTop);
5673
+ ctx.style.set("height", `calc(100vh - ${offsetTop})`);
5674
+ ctx.style.set("overflow", "hidden");
5675
+ ctx.style.set("display", "grid");
5676
+ ctx.style.set("align-content", "center");
5677
+ const { remove: removeSpacer } = insertSpacer(host, params.text("distance"), ctx);
5678
+ const rail = createStyleLedger(track);
5679
+ rail.set("display", "flex");
5680
+ rail.set("width", "max-content");
5681
+ const authored = params.text("travel", "auto");
5682
+ const travel = createMeasureCache(() => trackTravel(track, authored, track.ownerDocument));
5683
+ const tracked = host.parentElement ?? host;
5684
+ const untrack = trackProgress(tracked, ctx, { distance: params.text("distance"), stickyEl: host }, (progress, frame) => {
5685
+ rail.set("translate", `${-progress * travel.read(frame.epoch)}px 0`);
4872
5686
  writeProgress(ctx, progress);
4873
5687
  });
4874
- return untrack;
5688
+ return continuousSetup(() => {
5689
+ untrack();
5690
+ rail.restore();
5691
+ removeSpacer();
5692
+ });
4875
5693
  }
4876
5694
  function trackTravel(node, authored, doc) {
4877
5695
  if (authored && authored !== "auto") return toPixels(authored, ABSOLUTE_BASIS, 0);
@@ -4881,11 +5699,41 @@ var kuinetic = (() => {
4881
5699
  return Math.max(0, node.scrollWidth - viewportWidth);
4882
5700
  }
4883
5701
  function prepareMediaScrub(el, params, ctx) {
5702
+ const managed = params.is("spacer") ? installSticky(el, params, ctx) : null;
5703
+ const contentAnchor = managed?.spacer ?? void 0;
5704
+ const stickyEl = managed ? el : void 0;
5705
+ const selector = resolveTarget(params.text("target"), ctx, "media-scrub");
5706
+ const scrub = selector ? prepareTargetScrub(el, params, ctx, { selector, contentAnchor, stickyEl }) : prepareSrcScrub(el, params, ctx, { contentAnchor, stickyEl });
5707
+ return continuousSetup(() => {
5708
+ scrub();
5709
+ managed?.dispose();
5710
+ });
5711
+ }
5712
+ function prepareTargetScrub(el, params, ctx, authored) {
5713
+ const { selector, contentAnchor, stickyEl } = authored;
5714
+ const marker = createStepMarker(() => ctx.doc.querySelectorAll(selector));
5715
+ const frames = Math.max(1, ctx.doc.querySelectorAll(selector).length);
5716
+ let lastIndex;
5717
+ const untrack = trackProgress(el, ctx, { distance: params.text("distance"), contentAnchor, stickyEl }, (progress) => {
5718
+ writeProgress(ctx, progress);
5719
+ const index = Math.min(frames - 1, Math.floor(progress * frames));
5720
+ if (index === lastIndex) return;
5721
+ lastIndex = index;
5722
+ marker.mark(index);
5723
+ });
5724
+ marker.mark(0);
5725
+ return () => {
5726
+ untrack();
5727
+ marker.restore();
5728
+ };
5729
+ }
5730
+ function prepareSrcScrub(el, params, ctx, anchors) {
5731
+ const { contentAnchor, stickyEl } = anchors;
4884
5732
  const frames = Math.max(1, Math.round(params.num("frames", 1)));
4885
5733
  const pattern = mediaSrcPattern(params.text("src"), ctx);
4886
5734
  const media = el;
4887
5735
  let lastIndex = -1;
4888
- const untrack = trackProgress(el, ctx, { distance: params.text("distance") }, (progress) => {
5736
+ const untrack = trackProgress(el, ctx, { distance: params.text("distance"), contentAnchor, stickyEl }, (progress) => {
4889
5737
  writeProgress(ctx, progress);
4890
5738
  const index = Math.min(frames - 1, Math.floor(progress * frames));
4891
5739
  if (index === lastIndex) return;
@@ -4909,80 +5757,37 @@ var kuinetic = (() => {
4909
5757
  if (media.tagName !== "IMG") return;
4910
5758
  if (pattern) media.src = pattern.replace("{i}", String(index).padStart(String(frames).length, "0"));
4911
5759
  }
4912
- function prepareScrollSpy(el, params, ctx) {
4913
- const selector = spyTarget(params.text("target"), ctx);
4914
- const links = /* @__PURE__ */ new Map();
4915
- const self = createAttributeLedger(el);
4916
- let last;
4917
- const untrack = trackProgress(el, ctx, { distance: params.text("distance") }, (progress) => {
4918
- const active = progress > 0 && progress < 1;
4919
- if (active === last) return;
4920
- last = active;
4921
- self.set("data-kui-active", String(active));
4922
- if (selector) markLinks(ctx.doc, selector, active, links);
4923
- });
5760
+ function prepareSmoothScroll(el, params, ctx) {
5761
+ ctx.style.set("scroll-behavior", params.text("behavior", "smooth"));
4924
5762
  return () => {
4925
- untrack();
4926
- self.restore();
4927
- for (const ledger of links.values()) ledger.restore();
4928
5763
  };
4929
5764
  }
4930
- function spyTarget(selector, ctx) {
4931
- if (!selector) return selector;
4932
- const breadth = selectorBreadth(selector, ctx.doc);
4933
- if (breadth === "invalid") {
4934
- ctx.warn(`scroll-spy target "${selector}" is not a valid selector and will be ignored`);
4935
- return "";
4936
- }
4937
- if (breadth === "document-wide") {
4938
- ctx.warn(`scroll-spy target "${selector}" matches the whole document and will be ignored`);
4939
- return "";
4940
- }
4941
- return selector;
4942
- }
4943
- function selectorBreadth(selector, doc) {
4944
- try {
4945
- if (doc.documentElement.matches(selector)) return "document-wide";
4946
- if (doc.body?.matches(selector)) return "document-wide";
4947
- return "ok";
4948
- } catch {
4949
- return "invalid";
4950
- }
4951
- }
4952
- function markLinks(doc, selector, active, links) {
4953
- for (const link of doc.querySelectorAll(selector)) {
4954
- let ledger = links.get(link);
4955
- if (!ledger) {
4956
- ledger = createAttributeLedger(link);
4957
- links.set(link, ledger);
4958
- }
4959
- ledger.set("data-kui-active", String(active));
4960
- }
4961
- }
4962
5765
  function prepareSnap(el, params, ctx) {
4963
- ctx.style.set(
4964
- "scroll-snap-type",
4965
- `${params.is("axis", "x") ? "x" : "y"} ${params.text("strictness", "mandatory")}`
4966
- );
4967
- const childLedgers = [...el.children].map((child) => createStyleLedger(child));
5766
+ const axis = params.is("axis", "x") ? "x" : "y";
5767
+ ctx.style.set("scroll-snap-type", `${axis} ${params.text("strictness", "mandatory")}`);
5768
+ const selector = resolveTarget(params.text("target"), ctx, "scroll-snap");
5769
+ const items = selector ? [...el.querySelectorAll(selector)] : [...el.children];
5770
+ if (selector && items.length === 0) {
5771
+ ctx.warn(`scroll-snap target "${selector}" matched nothing inside this element`);
5772
+ }
5773
+ if (selector) installSnapContainer(axis, ctx);
5774
+ const childLedgers = items.map((child) => createStyleLedger(child));
4968
5775
  for (const ledger of childLedgers) ledger.set("scroll-snap-align", params.text("align", "start"));
4969
5776
  return () => {
4970
5777
  for (const ledger of childLedgers) ledger.restore();
4971
5778
  };
4972
5779
  }
5780
+ function installSnapContainer(axis, ctx) {
5781
+ ctx.style.set(axis === "x" ? "overflow-x" : "overflow-y", "auto");
5782
+ if (axis === "x") ctx.style.set("display", "flex");
5783
+ }
4973
5784
  var SCROLL_PRIMITIVES = [
4974
5785
  scrollPrimitive({
4975
5786
  id: "pin",
4976
5787
  channels: ["layout", "progress"],
4977
5788
  parameters: {
4978
5789
  ...distanceParam,
4979
- offset: { type: "length", default: "0px", cssProperty: "--kui-offset" },
4980
- spacer: {
4981
- type: "keyword",
4982
- default: "false",
4983
- cssProperty: "--kui-spacer",
4984
- values: ["true", "false"]
4985
- }
5790
+ ...stickyParams
4986
5791
  },
4987
5792
  prepare: deferPrepare(preparePin),
4988
5793
  perfClass: "layout"
@@ -4992,7 +5797,10 @@ var kuinetic = (() => {
4992
5797
  channels: ["progress"],
4993
5798
  parameters: {
4994
5799
  ...distanceParam,
4995
- steps: { type: "number", default: "0", cssProperty: "--kui-steps" }
5800
+ steps: { type: "number", default: "0", cssProperty: "--kui-steps" },
5801
+ // Same name, same shape and the same validation as scroll-spy's: one `target:` convention
5802
+ // across the library rather than a second word for "the elements this effect marks".
5803
+ target: { type: "text", default: "", cssProperty: "--kui-target" }
4996
5804
  },
4997
5805
  prepare: deferPrepare(prepareProgress)
4998
5806
  }),
@@ -5001,7 +5809,16 @@ var kuinetic = (() => {
5001
5809
  channels: ["translate", "progress"],
5002
5810
  parameters: {
5003
5811
  ...distanceParam,
5004
- travel: { type: "text", default: "auto", cssProperty: "--kui-travel" }
5812
+ travel: { type: "text", default: "auto", cssProperty: "--kui-travel" },
5813
+ // Same name, same shape and the same validation as scroll-spy's and media-scrub's: one
5814
+ // `target:` convention across the library. Naming the row that moves is also what opts this
5815
+ // primitive into owning the stage, the sticky window and the row's layout itself.
5816
+ target: { type: "text", default: "", cssProperty: "--kui-target" },
5817
+ "offset-top": {
5818
+ type: "length",
5819
+ default: "var(--kui-pin-offset, 0px)",
5820
+ cssProperty: "--kui-offset-top"
5821
+ }
5005
5822
  },
5006
5823
  prepare: deferPrepare(prepareHorizontal)
5007
5824
  }),
@@ -5010,8 +5827,13 @@ var kuinetic = (() => {
5010
5827
  channels: ["media", "progress"],
5011
5828
  parameters: {
5012
5829
  ...distanceParam,
5830
+ // A scrub is a hold, so it needs the same two knobs a pin does. Declaring them here is what
5831
+ // lets `sequence-scrub` become one attribute with no wrapper at all.
5832
+ ...stickyParams,
5013
5833
  frames: { type: "number", default: "1", cssProperty: "--kui-frames" },
5014
- src: { type: "text", default: "", cssProperty: "--kui-src" }
5834
+ src: { type: "text", default: "", cssProperty: "--kui-src" },
5835
+ // The preferred form. `frames:`/`src:` remain for sequences too long to author as tags.
5836
+ target: { type: "text", default: "", cssProperty: "--kui-target" }
5015
5837
  },
5016
5838
  prepare: deferPrepare(prepareMediaScrub),
5017
5839
  perfClass: "paint"
@@ -5020,11 +5842,30 @@ var kuinetic = (() => {
5020
5842
  id: "scroll-spy",
5021
5843
  channels: ["state"],
5022
5844
  parameters: {
5845
+ // `distance`: the per-section form only. `offset-top`: the container form only. Each is a
5846
+ // no-op — warned, not silent — in the other; see `prepareScrollSpySingle` and
5847
+ // `prepareScrollSpyContainer`.
5023
5848
  ...distanceParam,
5024
- target: { type: "text", default: "", cssProperty: "--kui-target" }
5849
+ // Same name and meaning in both forms: the link(s) this instance marks. Per-section, the
5850
+ // one link this section names; with `sections:`, every link `target:` matches, each paired
5851
+ // to its own section by `href`. See `prepareScrollSpyContainer`.
5852
+ target: { type: "text", default: "", cssProperty: "--kui-target" },
5853
+ // Presence, not value, selects the container form: authoring this at all switches
5854
+ // `prepareScrollSpy` from one-section-per-instance to one-instance-on-the-shared-ancestor.
5855
+ sections: { type: "text", default: "", cssProperty: "--kui-sections" },
5856
+ "offset-top": { type: "length", default: "0px", cssProperty: "--kui-offset-top" }
5025
5857
  },
5026
5858
  prepare: deferPrepare(prepareScrollSpy)
5027
5859
  }),
5860
+ scrollPrimitive({
5861
+ id: "smooth-scroll",
5862
+ channels: ["layout"],
5863
+ parameters: {
5864
+ behavior: { type: "keyword", default: "smooth", cssProperty: "--kui-scroll-behavior", values: ["smooth", "auto"] }
5865
+ },
5866
+ prepare: deferPrepare(prepareSmoothScroll),
5867
+ perfClass: "layout"
5868
+ }),
5028
5869
  scrollPrimitive({
5029
5870
  id: "scroll-snap",
5030
5871
  channels: ["layout"],
@@ -5041,7 +5882,11 @@ var kuinetic = (() => {
5041
5882
  default: "start",
5042
5883
  cssProperty: "--kui-snap-align",
5043
5884
  values: ["start", "center", "end"]
5044
- }
5885
+ },
5886
+ // Names the snap items. Also what opts this primitive into owning the scroll container
5887
+ // itself — see `installSnapContainer`. Without it, the direct children are the items and
5888
+ // the page keeps its own `overflow`, exactly as before.
5889
+ target: { type: "text", default: "", cssProperty: "--kui-target" }
5045
5890
  },
5046
5891
  prepare: deferPrepare(prepareSnap),
5047
5892
  perfClass: "layout"
@@ -5064,11 +5909,28 @@ var kuinetic = (() => {
5064
5909
  // --- travel ------------------------------------------------------------------------------
5065
5910
  { name: "horizontal-scroll", primitive: "horizontal-track" },
5066
5911
  // --- media -------------------------------------------------------------------------------
5067
- { name: "sequence-scrub", primitive: "media-scrub" },
5912
+ /*
5913
+ * `spacer:true` is what deletes the `.scrub-stage` wrapper a page used to hand-write.
5914
+ *
5915
+ * It could not be switched on until the tracker stopped measuring against the parent. A scrub
5916
+ * makes itself sticky, and `geometrySource` escapes a sticky subtree by taking its parent — so
5917
+ * with the wrapper gone the scrub was measured against whatever section contained it. Measured
5918
+ * on `demo/scroll.html`: the parent started 926px above the scrub against a 1817px distance, so
5919
+ * progress reached 51% before the element had even stuck and half the sequence played off
5920
+ * screen. The wrapper was not ceremony; it was the tight box that made the parent honest.
5921
+ *
5922
+ * `trackProgress`'s `contentAnchor` is the fix. Progress is read from the spacer, which the
5923
+ * library inserts, is exactly `distance` tall, is never sticky, and moves with the content — so
5924
+ * there is no wrapper to write and nothing to disagree with.
5925
+ *
5926
+ * `video-scrub` stays off: a video positioned by the page is not asking the library for a box.
5927
+ */
5928
+ { name: "sequence-scrub", primitive: "media-scrub", params: { spacer: "true" } },
5068
5929
  { name: "video-scrub", primitive: "media-scrub" },
5069
5930
  // --- navigation --------------------------------------------------------------------------
5070
5931
  { name: "scroll-spy", primitive: "scroll-spy" },
5071
5932
  // --- native CSS passthroughs ---------------------------------------------------------------
5933
+ { name: "smooth-scroll-to", primitive: "smooth-scroll" },
5072
5934
  { name: "scroll-snap-x", primitive: "scroll-snap", params: { axis: "x" } },
5073
5935
  { name: "scroll-snap-y", primitive: "scroll-snap", params: { axis: "y" } }
5074
5936
  ];
@@ -5083,11 +5945,16 @@ var kuinetic = (() => {
5083
5945
  var UNSUPPORTED = /[AaSsQqTt]/;
5084
5946
  function parsePath(d) {
5085
5947
  if (UNSUPPORTED.test(d)) {
5086
- return { segments: [], reason: "arc and shorthand commands (A S Q T) are not supported" };
5948
+ return {
5949
+ segments: [],
5950
+ subpaths: [],
5951
+ reason: "arc and shorthand commands (A S Q T) are not supported"
5952
+ };
5087
5953
  }
5088
5954
  const tokens = [...d.matchAll(COMMAND)].map((m) => m[1] ?? m[2]);
5089
5955
  const state = {
5090
- segments: [],
5956
+ subpaths: [],
5957
+ open: void 0,
5091
5958
  current: { x: 0, y: 0 },
5092
5959
  start: { x: 0, y: 0 },
5093
5960
  command: ""
@@ -5101,18 +5968,33 @@ var kuinetic = (() => {
5101
5968
  index++;
5102
5969
  continue;
5103
5970
  }
5104
- if (!state.command) return { segments: [], reason: "path must start with a command letter" };
5971
+ if (!state.command) {
5972
+ return { segments: [], subpaths: [], reason: "path must start with a command letter" };
5973
+ }
5105
5974
  index = consume(tokens, index, state);
5106
5975
  }
5107
- if (state.segments.length === 0) return { segments: [], reason: "no drawable segments" };
5108
- return { segments: state.segments };
5976
+ if (state.subpaths.length === 0) {
5977
+ return { segments: [], subpaths: [], reason: "no drawable segments" };
5978
+ }
5979
+ return { segments: state.subpaths.flatMap((sub) => sub.segments), subpaths: state.subpaths };
5980
+ }
5981
+ function pushSegment(state, segment) {
5982
+ if (!state.open) {
5983
+ state.open = { segments: [], closed: false };
5984
+ state.subpaths.push(state.open);
5985
+ }
5986
+ state.open.segments.push(segment);
5109
5987
  }
5110
5988
  var ARITY = { m: 2, l: 2, h: 1, v: 1, c: 6, z: 0 };
5111
5989
  function closeSubpath(state) {
5112
- const { current, start } = state;
5113
- if (Math.abs(current.x - start.x) < 1e-6 && Math.abs(current.y - start.y) < 1e-6) return;
5114
- state.segments.push(lineToCubic(current, start));
5990
+ const { current, start, open } = state;
5991
+ if (!open) return;
5992
+ if (Math.abs(current.x - start.x) >= 1e-6 || Math.abs(current.y - start.y) >= 1e-6) {
5993
+ open.segments.push(lineToCubic(current, start));
5994
+ }
5995
+ open.closed = true;
5115
5996
  state.current = { ...start };
5997
+ state.open = void 0;
5116
5998
  }
5117
5999
  function consume(tokens, index, state) {
5118
6000
  const key = state.command.toLowerCase();
@@ -5124,10 +6006,11 @@ var kuinetic = (() => {
5124
6006
  if (key === "m") {
5125
6007
  state.current = next;
5126
6008
  state.start = next;
6009
+ state.open = void 0;
5127
6010
  state.command = relative ? "l" : "L";
5128
6011
  return index + arity;
5129
6012
  }
5130
- state.segments.push(straightOrCubic({ key, args, from: state.current, relative }, next));
6013
+ pushSegment(state, straightOrCubic({ key, args, from: state.current, relative }, next));
5131
6014
  state.current = next;
5132
6015
  return index + arity;
5133
6016
  }
@@ -5190,34 +6073,78 @@ var kuinetic = (() => {
5190
6073
  function chordLength(segment) {
5191
6074
  return Math.hypot(segment.to.x - segment.from.x, segment.to.y - segment.from.y);
5192
6075
  }
5193
- function toPathData(segments) {
5194
- if (segments.length === 0) return "";
5195
- const head = segments[0];
5196
- const parts = [`M${round(head.from.x)},${round(head.from.y)}`];
5197
- for (const s of segments) {
5198
- parts.push(
5199
- `C${round(s.c1.x)},${round(s.c1.y)} ${round(s.c2.x)},${round(s.c2.y)} ${round(s.to.x)},${round(s.to.y)}`
5200
- );
6076
+ function round(value) {
6077
+ return Math.round(value * 100) / 100;
6078
+ }
6079
+ function subpathsToPathData(subpaths) {
6080
+ const parts = [];
6081
+ for (const sub of subpaths) {
6082
+ const head = sub.segments[0];
6083
+ parts.push(`M${round(head.from.x)},${round(head.from.y)}`);
6084
+ for (const s of sub.segments) {
6085
+ parts.push(
6086
+ `C${round(s.c1.x)},${round(s.c1.y)} ${round(s.c2.x)},${round(s.c2.y)} ${round(s.to.x)},${round(s.to.y)}`
6087
+ );
6088
+ }
6089
+ if (sub.closed) parts.push("Z");
5201
6090
  }
5202
6091
  return parts.join(" ");
5203
6092
  }
5204
- function round(value) {
5205
- return Math.round(value * 100) / 100;
6093
+ function centroidOf(subpath) {
6094
+ let x = 0;
6095
+ let y = 0;
6096
+ for (const s of subpath.segments) {
6097
+ x += s.from.x;
6098
+ y += s.from.y;
6099
+ }
6100
+ return { x: x / subpath.segments.length, y: y / subpath.segments.length };
6101
+ }
6102
+ function collapsedLike(partner) {
6103
+ const at = centroidOf(partner);
6104
+ return {
6105
+ segments: partner.segments.map(() => ({
6106
+ from: { ...at },
6107
+ c1: { ...at },
6108
+ c2: { ...at },
6109
+ to: { ...at }
6110
+ })),
6111
+ closed: partner.closed
6112
+ };
6113
+ }
6114
+ function normaliseSubpaths(a, b) {
6115
+ const count = Math.max(a.length, b.length);
6116
+ const from = [];
6117
+ const to = [];
6118
+ for (let i = 0; i < count; i++) {
6119
+ const left = a[i] ?? collapsedLike(b[i]);
6120
+ const right = b[i] ?? collapsedLike(a[i]);
6121
+ const target = Math.max(left.segments.length, right.segments.length);
6122
+ const closed = left.closed && right.closed;
6123
+ from.push({ segments: normaliseCount(left.segments, target), closed });
6124
+ to.push({ segments: normaliseCount(right.segments, target), closed });
6125
+ }
6126
+ return { from, to };
5206
6127
  }
5207
6128
  function createMorph(fromPath, toPath) {
5208
6129
  const a = parsePath(fromPath);
5209
6130
  const b = parsePath(toPath);
5210
6131
  if (a.reason) return { reason: `start path: ${a.reason}` };
5211
6132
  if (b.reason) return { reason: `end path: ${b.reason}` };
5212
- const count = Math.max(a.segments.length, b.segments.length);
5213
- const from = normaliseCount(a.segments, count);
5214
- const to = normaliseCount(b.segments, count);
6133
+ const { from, to } = normaliseSubpaths(a.subpaths, b.subpaths);
6134
+ const count = from.reduce((total, sub) => total + sub.segments.length, 0);
5215
6135
  return {
5216
6136
  morph: {
5217
6137
  segmentCount: count,
5218
6138
  at(t) {
5219
6139
  const clamped = Math.min(1, Math.max(0, t));
5220
- return toPathData(from.map((segment, i) => lerpCubic(segment, to[i], clamped)));
6140
+ return subpathsToPathData(
6141
+ from.map((sub, i) => ({
6142
+ segments: sub.segments.map(
6143
+ (segment, j) => lerpCubic(segment, to[i].segments[j], clamped)
6144
+ ),
6145
+ closed: sub.closed
6146
+ }))
6147
+ );
5221
6148
  }
5222
6149
  }
5223
6150
  };
@@ -5274,6 +6201,35 @@ var kuinetic = (() => {
5274
6201
  path.setAttribute("d", startPath);
5275
6202
  };
5276
6203
  }
6204
+ var PATH_DRAW_PRIMITIVE = cssPrimitive("path-draw", [CHANNEL.stroke], {
6205
+ parameters: {
6206
+ length: { type: "number", default: "100", cssProperty: "--kui-path-length", finite: true }
6207
+ }
6208
+ });
6209
+ var SHAPE_FILL_PRIMITIVE = cssPrimitive("shape-fill", [CHANNEL.clip]);
6210
+ var BAR_GROW_PRIMITIVE = cssPrimitive("bar-grow", [CHANNEL.scale], {
6211
+ parameters: { from: { type: "number", default: "0", cssProperty: "--kui-bar-from" } }
6212
+ });
6213
+ var LOGO_BUILD_PRIMITIVE = cssPrimitive("logo-assemble", [
6214
+ CHANNEL.opacity,
6215
+ CHANNEL.scale,
6216
+ CHANNEL.rotate
6217
+ ]);
6218
+ var ICON_TOGGLE_PRIMITIVE = {
6219
+ id: "icon-toggle",
6220
+ renderer: "javascript",
6221
+ channels: [CHANNEL.translate, CHANNEL.rotate, CHANNEL.scale, CHANNEL.opacity, CHANNEL.clip],
6222
+ parameters: {
6223
+ duration: { type: "time", default: "260ms", cssProperty: "--kui-duration" },
6224
+ ease: { type: "easing", default: "ease-out", cssProperty: "--kui-ease" }
6225
+ },
6226
+ supportedTimelines: ["time"],
6227
+ supportedActivations: ["load"],
6228
+ defaultActivation: "load",
6229
+ perfClass: "compositor",
6230
+ reducedMotion: "disable",
6231
+ prepare: () => inertInstance()
6232
+ };
5277
6233
  var SVG_PRIMITIVES = [
5278
6234
  {
5279
6235
  id: "path-morph",
@@ -5293,19 +6249,77 @@ var kuinetic = (() => {
5293
6249
  perfClass: "paint",
5294
6250
  reducedMotion: "disable",
5295
6251
  prepare: deferPrepare(prepareMorph)
5296
- }
6252
+ },
6253
+ PATH_DRAW_PRIMITIVE,
6254
+ SHAPE_FILL_PRIMITIVE,
6255
+ BAR_GROW_PRIMITIVE,
6256
+ LOGO_BUILD_PRIMITIVE,
6257
+ ICON_TOGGLE_PRIMITIVE
5297
6258
  ];
5298
6259
  var SVG_PRESETS = [
5299
6260
  { name: "icon-morph", primitive: "path-morph" },
5300
- { name: "blob-morph", primitive: "path-morph", params: { duration: "800ms" } }
6261
+ { name: "blob-morph", primitive: "path-morph", params: { duration: "800ms" } },
6262
+ // Stroke draws. One keyframe block each rather than one shared block, matching the
6263
+ // progress-ring/gauge-sweep/donut-sweep/sparkline-draw group in numbers.ts: identical bodies
6264
+ // today, but each name is free to diverge and a consumer can restyle one without the others.
6265
+ { name: "draw-stroke", primitive: "path-draw", keyframes: "kui-draw-stroke", params: { duration: "800ms", ease: "ease-in-out" } },
6266
+ { name: "draw-signature", primitive: "path-draw", keyframes: "kui-draw-signature", params: { duration: "1600ms", ease: "ease-in-out" } },
6267
+ { name: "draw-underline", primitive: "path-draw", keyframes: "kui-draw-underline", params: { duration: "420ms" } },
6268
+ { name: "checkmark-draw", primitive: "path-draw", keyframes: "kui-checkmark-draw", params: { duration: "320ms" } },
6269
+ { name: "cross-draw", primitive: "path-draw", keyframes: "kui-cross-draw", params: { duration: "260ms" } },
6270
+ { name: "chart-line-draw", primitive: "path-draw", keyframes: "kui-chart-line-draw", params: { duration: "1200ms", ease: "ease-in-out" } },
6271
+ { name: "gradient-stroke", primitive: "path-draw", keyframes: "kui-gradient-stroke", params: { duration: "2400ms", ease: "ease-in-out" } },
6272
+ // Fills.
6273
+ { name: "heart-fill", primitive: "shape-fill", keyframes: "kui-heart-fill", params: { duration: "420ms" } },
6274
+ { name: "bookmark-fill", primitive: "shape-fill", keyframes: "kui-bookmark-fill", params: { duration: "360ms" } },
6275
+ { name: "chart-area-fill", primitive: "shape-fill", keyframes: "kui-chart-area-fill", params: { duration: "900ms" } },
6276
+ // `cloak: true`: `kui-chart-bar-grow`'s `from { scale: 1 0 }` (svg.css) is a zero-height box
6277
+ // while paused, not just an invisible one — so it occupies no space in layout for the whole
6278
+ // wait. Same defect `fold-panel` has, and the same fix shape: see svg.css's
6279
+ // `[data-kui-fx~='chart-bar-grow'][data-kui-state='ready']` rule.
6280
+ {
6281
+ name: "chart-bar-grow",
6282
+ primitive: "bar-grow",
6283
+ keyframes: "kui-chart-bar-grow",
6284
+ params: { duration: "700ms", ease: "back-out" },
6285
+ cloak: true
6286
+ },
6287
+ { name: "logo-build", primitive: "logo-assemble", keyframes: "kui-logo-build", params: { duration: "520ms", ease: "back-out" } },
6288
+ // Icon toggles — no `keyframes`, because their motion is a CSS transition in svg.css keyed off
6289
+ // aria state, not a compiled animation. Same shape as forms.ts's native-state presets.
6290
+ { name: "hamburger-to-x", primitive: "icon-toggle" },
6291
+ { name: "play-to-pause", primitive: "icon-toggle" },
6292
+ { name: "plus-to-minus", primitive: "icon-toggle" }
5301
6293
  ];
5302
6294
  function registerSvg(registry) {
5303
6295
  return registry.registerPrimitives(SVG_PRIMITIVES).registerPresets(SVG_PRESETS);
5304
6296
  }
5305
6297
 
5306
6298
  // src/effects/three-d/index.ts
6299
+ var CARD_TOGGLE_PRIMITIVE = {
6300
+ id: "card-toggle",
6301
+ renderer: "javascript",
6302
+ channels: [CHANNEL.rotate],
6303
+ parameters: {
6304
+ duration: { type: "time", default: "700ms", cssProperty: "--kui-duration" },
6305
+ ease: { type: "easing", default: "ease-in-out", cssProperty: "--kui-ease" },
6306
+ perspective: { type: "length", default: "1600px", cssProperty: "--kui-perspective" }
6307
+ },
6308
+ supportedTimelines: ["time"],
6309
+ supportedActivations: ["load"],
6310
+ defaultActivation: "load",
6311
+ perfClass: "compositor",
6312
+ reducedMotion: "disable",
6313
+ prepare: () => inertInstance()
6314
+ };
5307
6315
  var THREE_D_PRIMITIVES = [
5308
- cssPrimitive("flip-face", [CHANNEL.rotate], {
6316
+ // `skew`, not `rotate`: the keyframes in three-d.css write `transform: perspective(...)
6317
+ // rotateX/Y(...)`, not the individual `rotate:` property — `perspective` only creates depth for
6318
+ // an element's *children*, so giving one of these effects its own depth means reaching for the
6319
+ // `perspective()` transform *function*, which only exists inside the `transform` shorthand.
6320
+ // `CHANNEL.skew` is this catalog's name for "claims the whole `transform` shorthand"; see the
6321
+ // comment on it in `core/types.ts`.
6322
+ cssPrimitive("flip-face", [CHANNEL.skew], {
5309
6323
  parameters: {
5310
6324
  angle: { type: "angle", default: "180deg", cssProperty: "--kui-from-angle" },
5311
6325
  perspective: { type: "length", default: "1200px", cssProperty: "--kui-perspective" }
@@ -5315,12 +6329,19 @@ var kuinetic = (() => {
5315
6329
  parameters: { distance: { type: "length", default: "40px", cssProperty: "--kui-distance" } }
5316
6330
  }),
5317
6331
  cssPrimitive("wipe", [CHANNEL.clip]),
5318
- cssPrimitive("bar", [CHANNEL.scale])
6332
+ // `from` gives `loading-bar` a real knob on its start scale — it had none before, unlike
6333
+ // `flip-face`'s `angle:` two rows up. `--kui-bar-from` is also what the fold-panel-style
6334
+ // `[data-kui-fx~='loading-bar'][data-kui-state='ready']` gate neutralizes in three-d.css; see
6335
+ // that rule's comment for the on:enter fix this parameter doubles as.
6336
+ cssPrimitive("bar", [CHANNEL.scale], {
6337
+ parameters: { from: { type: "number", default: "0", cssProperty: "--kui-bar-from" } }
6338
+ }),
6339
+ CARD_TOGGLE_PRIMITIVE
5319
6340
  ];
5320
6341
  var THREE_D_PRESETS = [
5321
6342
  // --- 3D & perspective ---
5322
- { name: "card-flip-y", primitive: "flip-face", keyframes: "kui-card-flip-y" },
5323
- { name: "card-flip-x", primitive: "flip-face", keyframes: "kui-card-flip-x" },
6343
+ { name: "card-flip-y", primitive: "flip-face", keyframes: "kui-card-flip-y", cloak: true },
6344
+ { name: "card-flip-x", primitive: "flip-face", keyframes: "kui-card-flip-x", cloak: true },
5324
6345
  { name: "cube-rotate", primitive: "flip-face", keyframes: "kui-cube-rotate", params: { angle: "90deg" } },
5325
6346
  {
5326
6347
  name: "book-page-turn",
@@ -5328,17 +6349,32 @@ var kuinetic = (() => {
5328
6349
  keyframes: "kui-book-page-turn",
5329
6350
  params: { angle: "-160deg", duration: "900ms" }
5330
6351
  },
6352
+ // `cloak: true`, unlike its `flip-face` siblings above: those are `to`-only keyframes, so their
6353
+ // paused/waiting box is the ordinary, untransformed rest state. `fold-panel` is `from`-only —
6354
+ // its `rotateX(-90deg)` (three-d.css) *is* the paused box, edge-on and zero-height, so it holds
6355
+ // no space in layout for the whole wait; see the
6356
+ // `[data-kui-fx~='fold-panel'][data-kui-state='ready']` rule in three-d.css for the other half
6357
+ // of that fix. `cloak` only ever hid the pre-JS flash, not this, but adding it here keeps the
6358
+ // pre-JS and post-JS "ready" appearances the same (invisible) instead of trading one flash for
6359
+ // the other.
5331
6360
  {
5332
6361
  name: "fold-panel",
5333
6362
  primitive: "flip-face",
5334
6363
  keyframes: "kui-fold-panel",
5335
- params: { angle: "-90deg" }
6364
+ params: { angle: "-90deg" },
6365
+ cloak: true
5336
6366
  },
5337
6367
  // --- page transitions ---
5338
6368
  { name: "page-fade", primitive: "page-reveal", keyframes: "kui-page-fade" },
5339
6369
  { name: "page-slide", primitive: "page-reveal", keyframes: "kui-page-slide" },
5340
6370
  { name: "curtain-wipe", primitive: "wipe", keyframes: "kui-curtain-wipe", params: { duration: "800ms" } },
5341
- { name: "loading-bar", primitive: "bar", keyframes: "kui-loading-bar" }
6371
+ // `cloak: true` for the same reason as `fold-panel`: `kui-loading-bar`'s `from { scale: 0 1 }`
6372
+ // (three-d.css) is a zero-width box, not just an invisible one — see that file's
6373
+ // `[data-kui-fx~='loading-bar'][data-kui-state='ready']` rule.
6374
+ { name: "loading-bar", primitive: "bar", keyframes: "kui-loading-bar", cloak: true },
6375
+ // No `keyframes`: its motion is a CSS transition in three-d.css keyed off the control's
6376
+ // aria-pressed, not a compiled animation. Same shape as the icon toggles in svg.ts.
6377
+ { name: "flip-card", primitive: "card-toggle" }
5342
6378
  ];
5343
6379
  function registerThreeD(registry) {
5344
6380
  return registry.registerPrimitives(THREE_D_PRIMITIVES).registerPresets(THREE_D_PRESETS);
@@ -5371,7 +6407,7 @@ var kuinetic = (() => {
5371
6407
  if (!document.getElementById('kuinetic-styles')) {
5372
6408
  var style = document.createElement('style')
5373
6409
  style.id = 'kuinetic-styles'
5374
- style.textContent = "/* src/css/base.css */\n@layer kui.tokens, kui.presets, kui.effects, kui.policy;\n@layer kui.tokens {\n :root {\n --kui-ease-expo-in: cubic-bezier(0.7, 0, 0.84, 0);\n --kui-ease-expo-out: cubic-bezier(0.16, 1, 0.3, 1);\n --kui-ease-expo-in-out: cubic-bezier(0.87, 0, 0.13, 1);\n --kui-ease-back-in: cubic-bezier(0.36, 0, 0.66, -0.56);\n --kui-ease-back-out: cubic-bezier(0.34, 1.56, 0.64, 1);\n --kui-ease-back-in-out: cubic-bezier(0.68, -0.6, 0.32, 1.6);\n --kui-ease-quart-out: cubic-bezier(0.25, 1, 0.5, 1);\n --kui-ease-circ-out: cubic-bezier(0, 0.55, 0.45, 1);\n --kui-ease-spring: linear(0, 0.4 12%, 0.9 25%, 1.06 38%, 1.01 62%, 1);\n }\n [data-kui-fx] {\n --kui-dir: 1;\n }\n :dir(rtl) [data-kui-fx] {\n --kui-dir: -1;\n }\n}\n@layer kui.policy {\n html[data-kui-cloak] [data-kui][data-kui-reveal]:not([data-kui-state]) {\n opacity: 0 !important;\n }\n @media (prefers-reduced-motion: reduce) {\n [data-kui-rm],\n [data-kui-rm]::before,\n [data-kui-rm]::after,\n [data-kui-rm] .kui-odometer-strip,\n [data-kui-rm][data-kui-fx~=label-float] ~ label,\n [data-kui-rm][data-kui-fx~=input-underline-grow] ~ .kui-underline,\n [data-kui-rm][data-kui-fx~=toggle-morph] ~ .kui-track,\n [data-kui-rm][data-kui-fx~=toggle-morph] ~ .kui-track .kui-thumb,\n [data-kui-rm][data-kui-fx~=checkbox-draw] ~ svg path,\n [data-kui-rm][data-kui-fx~=radio-fill] ~ .kui-dot,\n [data-kui-rm][data-kui-fx~=strength-meter] ~ .kui-meter > * {\n transition-duration: 1ms !important;\n transition-delay: 0ms !important;\n }\n [data-kui-rm=shorten],\n [data-kui-rm=shorten]::before,\n [data-kui-rm=shorten]::after {\n animation-duration: 1ms !important;\n animation-delay: 0ms !important;\n }\n [data-kui-rm=crossfade] {\n animation-name: kui-in !important;\n animation-duration: 200ms !important;\n }\n [data-kui-rm=disable] {\n animation: none !important;\n opacity: 1 !important;\n translate: none !important;\n scale: none !important;\n rotate: none !important;\n filter: none !important;\n }\n }\n @media print {\n [data-kui-fx],\n [data-kui-reveal] {\n animation: none !important;\n opacity: 1 !important;\n translate: none !important;\n scale: none !important;\n rotate: none !important;\n filter: none !important;\n }\n }\n}\n\n/* src/css/presets.generated.css */\n@layer kui.presets {\n [data-kui-fx~=back-in-down] {\n --kui-distance: 120px;\n --kui-reveal-ease: expo-out;\n }\n [data-kui-fx~=back-in-up] {\n --kui-distance: 120px;\n --kui-reveal-ease: expo-out;\n }\n [data-kui-fx~=blob-morph] {\n --kui-path-morph-duration: 800ms;\n }\n [data-kui-fx~=bob] {\n --kui-ambient-float-duration: 2s;\n --kui-distance: 8px;\n }\n [data-kui-fx~=book-page-turn] {\n --kui-from-angle: -160deg;\n --kui-flip-face-duration: 900ms;\n }\n [data-kui-fx~=bounce-in] {\n --kui-from-scale: 0.3;\n --kui-scale-ease: back-out;\n }\n [data-kui-fx~=bounce-in-down] {\n --kui-distance: 60px;\n --kui-reveal-ease: back-out;\n }\n [data-kui-fx~=bounce-in-up] {\n --kui-distance: 60px;\n --kui-reveal-ease: back-out;\n }\n [data-kui-fx~=confetti-burst] {\n --kui-feedback-burst-duration: 900ms;\n --kui-pop-scale: 1.15;\n }\n [data-kui-fx~=count-bump] {\n --kui-feedback-pop-duration: 280ms;\n --kui-pop-scale: 1.3;\n }\n [data-kui-fx~=count-compact] {\n --kui-from: 0;\n --kui-to: 128400;\n --kui-format: compact;\n }\n [data-kui-fx~=count-currency] {\n --kui-from: 0;\n --kui-to: 4820;\n --kui-format: currency;\n --kui-decimals: 0;\n }\n [data-kui-fx~=count-down] {\n --kui-from: 100;\n --kui-to: 0;\n }\n [data-kui-fx~=count-percent] {\n --kui-from: 0;\n --kui-to: 0.82;\n --kui-format: percent;\n --kui-decimals: 0;\n }\n [data-kui-fx~=count-up] {\n --kui-from: 0;\n --kui-to: 100;\n }\n [data-kui-fx~=cube-rotate] {\n --kui-from-angle: 90deg;\n }\n [data-kui-fx~=cursor-follow] {\n --kui-stiffness: 300;\n --kui-damping: 30;\n }\n [data-kui-fx~=cursor-invert] {\n --kui-stiffness: 260;\n --kui-damping: 26;\n }\n [data-kui-fx~=cursor-label] {\n --kui-stiffness: 260;\n --kui-damping: 26;\n }\n [data-kui-fx~=cursor-lag] {\n --kui-stiffness: 80;\n --kui-damping: 14;\n }\n [data-kui-fx~=curtain-wipe] {\n --kui-wipe-duration: 800ms;\n }\n [data-kui-fx~=decode] {\n --kui-charset: binary;\n }\n [data-kui-fx~=depth-layer] {\n --kui-distance: 200px;\n }\n [data-kui-fx~=dot-grid-drift] {\n --kui-ambient-gradient-duration: 16s;\n --kui-ambient-gradient-ease: linear;\n }\n [data-kui-fx~=drag-inertia] {\n --kui-inertia: true;\n }\n [data-kui-fx~=drag-x] {\n --kui-axis: x;\n }\n [data-kui-fx~=drag-y] {\n --kui-axis: y;\n }\n [data-kui-fx~=elastic-pull] {\n --kui-return: true;\n --kui-bounds: 80;\n }\n [data-kui-fx~=expand-to-modal] {\n --kui-flip-scale: true;\n --kui-flip-container-duration: 500ms;\n }\n [data-kui-fx~=floating-shapes] {\n --kui-ambient-float-duration: 6s;\n --kui-distance: 10px;\n }\n [data-kui-fx~=fold-panel] {\n --kui-from-angle: -90deg;\n }\n [data-kui-fx~=glitch] {\n --kui-charset: symbols;\n }\n [data-kui-fx~=gradient-rotate-border] {\n --kui-ambient-gradient-duration: 6s;\n --kui-ambient-gradient-ease: linear;\n }\n [data-kui-fx~=grid-to-list] {\n --kui-flip-scale: true;\n }\n [data-kui-fx~=heart-burst] {\n --kui-feedback-burst-duration: 700ms;\n --kui-pop-scale: 1.4;\n }\n [data-kui-fx~=highlight-sweep] {\n --kui-sweep-color: gold;\n }\n [data-kui-fx~=line-grid-drift] {\n --kui-ambient-gradient-duration: 16s;\n --kui-ambient-gradient-ease: linear;\n }\n [data-kui-fx~=magnetic-snap] {\n --kui-strength: 0.6;\n --kui-radius: 160;\n }\n [data-kui-fx~=mega-menu-drop] {\n --kui-panel-reveal-duration: 550ms;\n }\n [data-kui-fx~=noise-overlay] {\n --kui-ambient-gradient-duration: 650ms;\n --kui-ambient-gradient-ease: steps(6);\n }\n [data-kui-fx~=odometer-roll] {\n --kui-from: 0;\n --kui-to: 4820;\n }\n [data-kui-fx~=pin-section] {\n --kui-distance: 100vh;\n --kui-spacer: true;\n }\n [data-kui-fx~=pin-spacer] {\n --kui-spacer: true;\n }\n [data-kui-fx~=pin-until] {\n --kui-spacer: false;\n }\n [data-kui-fx~=pop-in] {\n --kui-from-scale: 0.6;\n --kui-scale-ease: back-out;\n }\n [data-kui-fx~=pop-out] {\n --kui-from-scale: 0.6;\n --kui-scale-ease: back-in;\n }\n [data-kui-fx~=pull-to-refresh] {\n --kui-feedback-pull-duration: 900ms;\n --kui-feedback-pull-ease: ease-out;\n }\n [data-kui-fx~=rotate-in-left] {\n --kui-from-angle: -45deg;\n }\n [data-kui-fx~=rotate-in-right] {\n --kui-from-angle: 45deg;\n }\n [data-kui-fx~=rubber-band] {\n --kui-return: true;\n --kui-bounds: 120;\n }\n [data-kui-fx~=scanline] {\n --kui-ambient-gradient-duration: 3.5s;\n --kui-ambient-gradient-ease: linear;\n }\n [data-kui-fx~=scramble] {\n --kui-charset: upper;\n }\n [data-kui-fx~=scroll-snap-x] {\n --kui-axis: x;\n }\n [data-kui-fx~=scroll-snap-y] {\n --kui-axis: y;\n }\n [data-kui-fx~=scrollytelling-step] {\n --kui-steps: 4;\n }\n [data-kui-fx~=slide-block-end] {\n --kui-distance: 100px;\n --kui-from-opacity: 1;\n }\n [data-kui-fx~=slide-block-start] {\n --kui-distance: 100px;\n --kui-from-opacity: 1;\n }\n [data-kui-fx~=slide-down] {\n --kui-distance: 100px;\n --kui-from-opacity: 1;\n }\n [data-kui-fx~=slide-inline-end] {\n --kui-distance: 100px;\n --kui-from-opacity: 1;\n }\n [data-kui-fx~=slide-inline-start] {\n --kui-distance: 100px;\n --kui-from-opacity: 1;\n }\n [data-kui-fx~=slide-left] {\n --kui-distance: 100px;\n --kui-from-opacity: 1;\n }\n [data-kui-fx~=slide-out-down] {\n --kui-distance: 100px;\n --kui-from-opacity: 1;\n }\n [data-kui-fx~=slide-out-left] {\n --kui-distance: 100px;\n --kui-from-opacity: 1;\n }\n [data-kui-fx~=slide-out-right] {\n --kui-distance: 100px;\n --kui-from-opacity: 1;\n }\n [data-kui-fx~=slide-out-up] {\n --kui-distance: 100px;\n --kui-from-opacity: 1;\n }\n [data-kui-fx~=slide-right] {\n --kui-distance: 100px;\n --kui-from-opacity: 1;\n }\n [data-kui-fx~=slide-up] {\n --kui-distance: 100px;\n --kui-from-opacity: 1;\n }\n [data-kui-fx~=snap-back] {\n --kui-return: true;\n --kui-stiffness: 260;\n }\n [data-kui-fx~=split-chars] {\n --kui-unit: chars;\n --kui-direction: fade;\n }\n [data-kui-fx~=split-lines] {\n --kui-unit: lines;\n --kui-direction: fade;\n }\n [data-kui-fx~=split-words] {\n --kui-unit: words;\n --kui-direction: fade;\n }\n [data-kui-fx~=spotlight-follow] {\n --kui-ambient-gradient-duration: 9s;\n }\n [data-kui-fx~=stacking-cards] {\n --kui-spacer: false;\n }\n [data-kui-fx~=starfield] {\n --kui-ambient-gradient-duration: 40s;\n --kui-ambient-gradient-ease: linear;\n }\n [data-kui-fx~=swing-in] {\n --kui-from-angle: -15deg;\n --kui-rotate-ease: back-out;\n }\n [data-kui-fx~=swipe-x] {\n --kui-axis: x;\n }\n [data-kui-fx~=tab-indicator-slide] {\n --kui-flip-indicator-duration: 300ms;\n }\n [data-kui-fx~=text-jitter] {\n --kui-motion: jitter;\n }\n [data-kui-fx~=text-reveal-down] {\n --kui-unit: words;\n --kui-direction: down;\n }\n [data-kui-fx~=text-reveal-mask] {\n --kui-unit: lines;\n --kui-direction: mask;\n }\n [data-kui-fx~=text-reveal-up] {\n --kui-unit: words;\n --kui-direction: up;\n }\n [data-kui-fx~=text-wave] {\n --kui-motion: wave;\n }\n [data-kui-fx~=throwable] {\n --kui-inertia: true;\n --kui-damping: 18;\n }\n [data-kui-fx~=toast-slide-out] {\n --kui-feedback-toast-ease: ease-in;\n }\n [data-kui-fx~=typewriter] {\n --kui-loop: false;\n }\n [data-kui-fx~=typewriter-loop] {\n --kui-loop: true;\n }\n [data-kui-fx~=wave-blob] {\n --kui-ambient-gradient-duration: 12s;\n }\n [data-kui-fx~=wobble] {\n --kui-feedback-wobble-duration: 600ms;\n --kui-feedback-wobble-ease: ease-in-out;\n }\n}\n\n/* src/css/entrance.css */\n@layer kui.effects {\n @keyframes kui-in {\n from {\n opacity: var(--kui-from-opacity, 0);\n }\n }\n @keyframes kui-out {\n to {\n opacity: 0;\n }\n }\n @keyframes kui-in-up {\n from {\n opacity: var(--kui-from-opacity, 0);\n translate: 0 var(--kui-distance, 24px);\n }\n }\n @keyframes kui-in-down {\n from {\n opacity: var(--kui-from-opacity, 0);\n translate: 0 calc(var(--kui-distance, 24px) * -1);\n }\n }\n @keyframes kui-in-left {\n from {\n opacity: var(--kui-from-opacity, 0);\n translate: var(--kui-distance, 24px) 0;\n }\n }\n @keyframes kui-in-right {\n from {\n opacity: var(--kui-from-opacity, 0);\n translate: calc(var(--kui-distance, 24px) * -1) 0;\n }\n }\n @keyframes kui-out-up {\n to {\n opacity: 0;\n translate: 0 calc(var(--kui-distance, 24px) * -1);\n }\n }\n @keyframes kui-out-down {\n to {\n opacity: 0;\n translate: 0 var(--kui-distance, 24px);\n }\n }\n @keyframes kui-out-left {\n to {\n opacity: 0;\n translate: calc(var(--kui-distance, 24px) * -1) 0;\n }\n }\n @keyframes kui-out-right {\n to {\n opacity: 0;\n translate: var(--kui-distance, 24px) 0;\n }\n }\n @keyframes kui-in-inline-start {\n from {\n opacity: var(--kui-from-opacity, 0);\n translate: calc(var(--kui-distance, 24px) * var(--kui-dir, 1) * -1) 0;\n }\n }\n @keyframes kui-in-inline-end {\n from {\n opacity: var(--kui-from-opacity, 0);\n translate: calc(var(--kui-distance, 24px) * var(--kui-dir, 1)) 0;\n }\n }\n @keyframes kui-zoom-in {\n from {\n scale: var(--kui-from-scale, 0.92);\n }\n }\n @keyframes kui-zoom-out {\n to {\n scale: var(--kui-from-scale, 0.92);\n }\n }\n @keyframes kui-zoom-in-up {\n from {\n scale: var(--kui-from-scale, 0.92);\n translate: 0 var(--kui-distance, 24px);\n }\n }\n @keyframes kui-zoom-in-down {\n from {\n scale: var(--kui-from-scale, 0.92);\n translate: 0 calc(var(--kui-distance, 24px) * -1);\n }\n }\n @keyframes kui-flip-in-x {\n from {\n rotate: x var(--kui-from-angle, 90deg);\n }\n }\n @keyframes kui-flip-in-y {\n from {\n rotate: y var(--kui-from-angle, 90deg);\n }\n }\n @keyframes kui-flip-out-x {\n to {\n rotate: x var(--kui-from-angle, 90deg);\n }\n }\n @keyframes kui-flip-out-y {\n to {\n rotate: y var(--kui-from-angle, 90deg);\n }\n }\n @keyframes kui-rotate-in {\n from {\n rotate: var(--kui-from-angle, -8deg);\n }\n }\n @keyframes kui-rotate-out {\n to {\n rotate: var(--kui-from-angle, -8deg);\n }\n }\n @keyframes kui-swing-in {\n from {\n rotate: var(--kui-from-angle, -15deg);\n }\n }\n @keyframes kui-roll-in {\n from {\n rotate: var(--kui-from-angle, -120deg);\n translate: calc(var(--kui-distance, 24px) * -1) 0;\n }\n }\n @keyframes kui-roll-out {\n to {\n rotate: var(--kui-from-angle, -120deg);\n translate: var(--kui-distance, 24px) 0;\n }\n }\n @keyframes kui-blur-in {\n from {\n filter: blur(var(--kui-blur, 12px));\n }\n }\n @keyframes kui-blur-out {\n to {\n filter: blur(var(--kui-blur, 12px));\n }\n }\n @keyframes kui-fade-blur-up {\n from {\n opacity: var(--kui-from-opacity, 0);\n translate: 0 var(--kui-distance, 24px);\n filter: blur(var(--kui-blur, 12px));\n }\n }\n @keyframes kui-fade-blur-in {\n from {\n opacity: var(--kui-from-opacity, 0);\n filter: blur(var(--kui-blur, 12px));\n }\n }\n [data-kui-fx*=flip-] {\n transform-style: preserve-3d;\n }\n}\n\n/* src/css/scroll.css */\n@layer kui.effects {\n @keyframes kui-parallax-y {\n from {\n translate: 0 calc(var(--kui-distance, 100px) * -1);\n }\n to {\n translate: 0 var(--kui-distance, 100px);\n }\n }\n @keyframes kui-parallax-x {\n from {\n translate: calc(var(--kui-distance, 100px) * -1) 0;\n }\n to {\n translate: var(--kui-distance, 100px) 0;\n }\n }\n @keyframes kui-parallax-scale {\n from {\n scale: 1;\n }\n to {\n scale: var(--kui-to-scale, 1.2);\n }\n }\n @keyframes kui-parallax-rotate {\n from {\n rotate: 0deg;\n }\n to {\n rotate: var(--kui-to-angle, 12deg);\n }\n }\n @keyframes kui-scroll-fade {\n from {\n opacity: var(--kui-from-opacity, 0);\n }\n to {\n opacity: 1;\n }\n }\n @keyframes kui-progress-x {\n from {\n scale: 0 1;\n }\n to {\n scale: 1 1;\n }\n }\n @keyframes kui-progress-ring {\n from {\n stroke-dashoffset: var(--kui-path-length, 100);\n }\n to {\n stroke-dashoffset: 0;\n }\n }\n [data-kui-fx~=scroll-progress-bar] {\n transform-origin: left center;\n }\n [data-kui-fx~=scroll-progress-ring] {\n stroke-dasharray: var(--kui-path-length, 100);\n }\n @supports (animation-timeline: view()) {\n [data-kui-timeline] {\n animation-range: var(--kui-range, entry 0% cover 60%);\n }\n }\n}\n\n/* src/css/three-d.css */\n@layer kui.effects {\n @keyframes kui-card-flip-y {\n to {\n rotate: y var(--kui-from-angle, 180deg);\n }\n }\n @keyframes kui-card-flip-x {\n to {\n rotate: x var(--kui-from-angle, 180deg);\n }\n }\n @keyframes kui-cube-rotate {\n to {\n rotate: y var(--kui-from-angle, 90deg);\n }\n }\n @keyframes kui-book-page-turn {\n to {\n rotate: y var(--kui-from-angle, -160deg);\n }\n }\n @keyframes kui-fold-panel {\n from {\n rotate: x var(--kui-from-angle, -90deg);\n }\n }\n [data-kui-fx~=card-flip-x],\n [data-kui-fx~=card-flip-y],\n [data-kui-fx~=cube-rotate],\n [data-kui-fx~=book-page-turn],\n [data-kui-fx~=fold-panel] {\n transform-style: preserve-3d;\n perspective: var(--kui-perspective, 1200px);\n }\n [data-kui-fx~=book-page-turn] {\n transform-origin: left center;\n }\n [data-kui-fx~=fold-panel] {\n transform-origin: top center;\n }\n @keyframes kui-page-fade {\n from {\n opacity: 0;\n }\n }\n @keyframes kui-page-slide {\n from {\n opacity: 0;\n translate: 0 var(--kui-distance, 40px);\n }\n }\n @keyframes kui-curtain-wipe {\n from {\n clip-path: inset(0 0 100% 0);\n }\n }\n @keyframes kui-loading-bar {\n from {\n scale: 0 1;\n }\n }\n [data-kui-fx~=loading-bar] {\n transform-origin: left center;\n }\n}\n\n/* src/css/media.css */\n@layer kui.effects {\n @keyframes kui-wipe-up {\n from {\n clip-path: inset(100% 0 0);\n }\n }\n @keyframes kui-wipe-down {\n from {\n clip-path: inset(0 0 100%);\n }\n }\n @keyframes kui-wipe-left {\n from {\n clip-path: inset(0 100% 0 0);\n }\n }\n @keyframes kui-wipe-right {\n from {\n clip-path: inset(0 0 0 100%);\n }\n }\n @keyframes kui-wipe-circle {\n from {\n clip-path: circle(0 at 50% 50%);\n }\n }\n @keyframes kui-wipe-diagonal {\n from {\n clip-path: polygon(0 0, 0 0, 0 0);\n }\n to {\n clip-path: polygon(0 0, 200% 0, 0 200%);\n }\n }\n @keyframes kui-curtain-reveal {\n from {\n clip-path: inset(0 50%);\n }\n }\n @keyframes kui-before-after-wipe {\n from {\n clip-path: inset(0 100% 0 0);\n }\n }\n @keyframes kui-mask-reveal {\n from {\n mask-position: 100% 0;\n }\n to {\n mask-position: 0 0;\n }\n }\n [data-kui-fx~=mask-reveal] {\n mask-image:\n linear-gradient(\n 90deg,\n #000 0 45%,\n transparent 55% 100%);\n mask-size: 220% 100%;\n }\n @keyframes kui-ken-burns {\n from {\n scale: 1;\n translate: 0 0;\n }\n to {\n scale: var(--kui-to-scale, 1.12);\n translate: var(--kui-distance, 24px) calc(var(--kui-distance, 24px) * -0.5);\n }\n }\n @keyframes kui-ken-burns-out {\n from {\n scale: var(--kui-to-scale, 1.12);\n translate: calc(var(--kui-distance, 24px) * -1) 0;\n }\n to {\n scale: 1;\n translate: 0 0;\n }\n }\n @keyframes kui-blur-up {\n from {\n translate: 0 var(--kui-distance, 24px);\n filter: blur(var(--kui-blur, 16px));\n }\n to {\n translate: 0 0;\n filter: blur(0);\n }\n }\n @keyframes kui-duotone-hover {\n from {\n filter: grayscale(1) sepia(0.7) hue-rotate(330deg) saturate(2);\n }\n to {\n filter: none;\n }\n }\n @keyframes kui-grayscale-hover {\n from {\n filter: grayscale(1);\n }\n to {\n filter: grayscale(0);\n }\n }\n @keyframes kui-saturate-hover {\n from {\n filter: saturate(0.45);\n }\n to {\n filter: saturate(1.35);\n }\n }\n @keyframes kui-image-parallax-frame {\n from {\n translate: 0 calc(var(--kui-distance, 24px) * -1);\n }\n to {\n translate: 0 var(--kui-distance, 24px);\n }\n }\n @keyframes kui-lightbox-open {\n from {\n opacity: 0;\n scale: 0.92;\n }\n to {\n opacity: 1;\n scale: 1;\n }\n }\n @media (pointer: coarse) {\n [data-kui-fx~=duotone-hover]:active,\n [data-kui-fx~=grayscale-hover]:active,\n [data-kui-fx~=saturate-hover]:active {\n filter: none;\n }\n }\n}\n\n/* src/css/text.css */\n@layer kui.effects {\n .kui-sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip-path: inset(50%);\n white-space: nowrap;\n border: 0;\n }\n .kui-split-decorative {\n display: inline;\n }\n .kui-split-item {\n display: inline-block;\n animation-duration: var(--kui-duration, 500ms);\n animation-delay: calc(var(--kui-delay, 0ms) + var(--kui-i, 0) * var(--kui-stagger, 30ms));\n animation-timing-function: var(--kui-ease, ease-out);\n animation-fill-mode: both;\n }\n .kui-split-line {\n display: block;\n }\n [data-kui-split-fx=fade] .kui-split-item {\n animation-name: kui-split-reveal-fade;\n }\n [data-kui-split-fx=up] .kui-split-item {\n animation-name: kui-split-reveal-up;\n }\n [data-kui-split-fx=down] .kui-split-item {\n animation-name: kui-split-reveal-down;\n }\n [data-kui-split-fx=mask] .kui-split-item {\n animation-name: kui-split-reveal-mask;\n }\n @keyframes kui-split-reveal-fade {\n from {\n opacity: 0;\n }\n }\n @keyframes kui-split-reveal-up {\n from {\n opacity: 0;\n translate: 0 0.6em;\n }\n }\n @keyframes kui-split-reveal-down {\n from {\n opacity: 0;\n translate: 0 -0.6em;\n }\n }\n @keyframes kui-split-reveal-mask {\n from {\n opacity: 0;\n clip-path: inset(0 0 100% 0);\n }\n }\n [data-kui-split-fx=wave] .kui-split-item {\n animation-name: kui-split-wave;\n animation-duration: 1400ms;\n animation-iteration-count: infinite;\n animation-timing-function: ease-in-out;\n }\n [data-kui-split-fx=jitter] .kui-split-item {\n animation-name: kui-split-jitter;\n animation-duration: 220ms;\n animation-iteration-count: infinite;\n animation-timing-function: ease-in-out;\n animation-direction: alternate;\n }\n @keyframes kui-split-wave {\n 0%, 100% {\n translate: 0 0;\n }\n 50% {\n translate: 0 -0.35em;\n }\n }\n @keyframes kui-split-jitter {\n from {\n translate: 0 0;\n rotate: 0deg;\n }\n to {\n translate: 0 0.08em;\n rotate: 3deg;\n }\n }\n .kui-typewriter::after {\n content: \"\";\n display: inline-block;\n width: 0.08em;\n margin-inline-start: 0.05em;\n height: 1em;\n vertical-align: -0.15em;\n background: currentColor;\n animation: kui-caret-blink 1s steps(1) infinite;\n }\n @keyframes kui-caret-blink {\n 50% {\n opacity: 0;\n }\n }\n .kui-scramble {\n font-variant-numeric: tabular-nums;\n }\n [data-kui-fx~=word-cycler] {\n display: inline-block;\n transition: opacity 150ms ease-out;\n }\n [data-kui-fx~=word-cycler].kui-word-cycler-swap {\n opacity: 0;\n }\n [data-kui-fx~=gradient-shimmer] {\n background-image:\n linear-gradient(\n 100deg,\n currentColor 40%,\n color-mix(in srgb, currentColor 35%, transparent) 50%,\n currentColor 60%);\n background-size: 220% 100%;\n -webkit-background-clip: text;\n background-clip: text;\n -webkit-text-fill-color: transparent;\n --kui-fx-gradient-shimmer-iterations: infinite;\n }\n @keyframes kui-gradient-shimmer {\n from {\n background-position: 200% 0;\n }\n to {\n background-position: -200% 0;\n }\n }\n [data-kui-fx~=gradient-sweep] {\n background-image:\n linear-gradient(\n 100deg,\n transparent 30%,\n color-mix(in srgb, var(--kui-sweep-color, currentColor) 70%, transparent) 50%,\n transparent 70%);\n background-size: 260% 100%;\n -webkit-background-clip: text;\n background-clip: text;\n -webkit-text-fill-color: transparent;\n }\n @keyframes kui-gradient-sweep {\n from {\n background-position: 220% 0;\n }\n to {\n background-position: -60% 0;\n }\n }\n [data-kui-fx~=highlight-sweep] {\n background-image: linear-gradient(90deg, color-mix(in srgb, var(--kui-sweep-color, currentColor) 55%, transparent) 0 100%);\n background-repeat: no-repeat;\n background-size: 0% 100%;\n padding: 0 0.05em;\n }\n @keyframes kui-highlight-sweep {\n to {\n background-size: 100% 100%;\n }\n }\n [data-kui-fx~=underline-draw] {\n background-image: linear-gradient(var(--kui-sweep-color, currentColor), var(--kui-sweep-color, currentColor));\n background-repeat: no-repeat;\n background-position: 0 100%;\n background-size: 0% 2px;\n padding-bottom: 0.15em;\n }\n @keyframes kui-underline-draw {\n to {\n background-size: 100% 2px;\n }\n }\n [data-kui-fx~=text-outline-fill] {\n -webkit-text-stroke: 1px currentColor;\n color: transparent;\n }\n @keyframes kui-text-outline-fill {\n to {\n color: currentColor;\n }\n }\n @keyframes kui-var-weight {\n from {\n font-weight: var(--kui-from-weight, 100);\n }\n to {\n font-weight: var(--kui-to-weight, 800);\n }\n }\n @keyframes kui-var-width {\n from {\n font-stretch: var(--kui-from-width, 75%);\n }\n to {\n font-stretch: var(--kui-to-width, 125%);\n }\n }\n @keyframes kui-var-slant {\n from {\n font-style: oblique var(--kui-from-slant, 0deg);\n }\n to {\n font-style: oblique var(--kui-to-slant, 10deg);\n }\n }\n [data-kui-fx~=marquee],\n [data-kui-fx~=marquee-scroll-linked] {\n display: flex;\n width: max-content;\n will-change: translate;\n }\n [data-kui-fx~=marquee] {\n --kui-fx-marquee-iterations: infinite;\n }\n @keyframes kui-marquee {\n to {\n translate: -50% 0;\n }\n }\n @property --kui-redaction-x { syntax: \"<percentage>\"; inherits: true; initial-value: 0%; }\n [data-kui-fx~=redaction-reveal] {\n position: relative;\n display: inline-block;\n }\n [data-kui-fx~=redaction-reveal]::before {\n content: \"\";\n position: absolute;\n inset: 0;\n background: var(--kui-bar-color, #111);\n clip-path: inset(0 0 0 var(--kui-redaction-x));\n }\n @keyframes kui-redaction-reveal {\n to {\n --kui-redaction-x: 100%;\n }\n }\n [data-kui-fx~=text-3d-extrude] {\n display: inline-block;\n text-shadow:\n 1px 1px 0 color-mix(in srgb, currentColor 70%, transparent),\n 2px 2px 0 color-mix(in srgb, currentColor 60%, transparent),\n 3px 3px 0 color-mix(in srgb, currentColor 50%, transparent),\n 4px 4px 0 color-mix(in srgb, currentColor 40%, transparent),\n 5px 5px 0 color-mix(in srgb, currentColor 30%, transparent),\n 6px 6px 8px rgb(0 0 0 / 0.35);\n }\n @keyframes kui-text-3d-extrude {\n from {\n rotate: var(--kui-from-angle, -20deg);\n translate: 0 var(--kui-distance, 32px);\n }\n to {\n rotate: 0deg;\n translate: 0 0;\n }\n }\n}\n\n/* src/css/navigation.css */\n@layer kui.effects {\n @keyframes kui-nav-reveal {\n from {\n opacity: 0;\n translate: 0 var(--kui-distance, 16px);\n }\n }\n @keyframes kui-menu-fullscreen {\n from {\n opacity: 0;\n clip-path: circle(0% at var(--kui-origin, 100% 0%));\n }\n to {\n opacity: 1;\n clip-path: circle(150% at var(--kui-origin, 100% 0%));\n }\n }\n @keyframes kui-panel-reveal {\n from {\n opacity: 0;\n translate: 0 calc(var(--kui-distance, 10px) * -1);\n }\n }\n @keyframes kui-drawer-slide-right {\n from {\n translate: 100% 0;\n }\n }\n [data-kui-fx~=header-shrink] {\n --kui-shrink: 0;\n padding-block: calc(1.4rem - 0.7rem * var(--kui-shrink, 0));\n font-size: calc(1rem - 0.15rem * var(--kui-shrink, 0));\n transition:\n padding-block 200ms ease-out,\n font-size 200ms ease-out,\n box-shadow 200ms ease-out;\n }\n [data-kui-fx~=header-shrink][data-kui-shrunk=true] {\n box-shadow: 0 2px 10px rgb(0 0 0 / 0.12);\n }\n [data-kui-fx~=header-hide-on-scroll] {\n transition: translate 220ms ease-out;\n }\n [data-kui-fx~=header-hide-on-scroll][data-kui-hidden=true] {\n translate: 0 -100%;\n }\n [data-kui-fx~=back-to-top-fade] {\n opacity: 0;\n translate: 0 12px;\n pointer-events: none;\n transition: opacity 200ms ease-out, translate 200ms ease-out;\n }\n [data-kui-fx~=back-to-top-fade][data-kui-visible=true] {\n opacity: 1;\n translate: 0 0;\n pointer-events: auto;\n }\n}\n\n/* src/css/forms.css */\n@layer kui.effects {\n [data-kui-fx~=label-float] ~ label {\n transition: translate 180ms ease-out, scale 180ms ease-out;\n transform-origin: left center;\n }\n [data-kui-fx~=label-float]:focus ~ label,\n [data-kui-fx~=label-float]:not(:placeholder-shown) ~ label {\n translate: 0 -1.35rem;\n scale: 0.82;\n }\n [data-kui-fx~=input-underline-grow] ~ .kui-underline {\n display: block;\n height: 2px;\n background: currentColor;\n scale: 0 1;\n transform-origin: left center;\n transition: scale 220ms ease-out;\n }\n [data-kui-fx~=input-underline-grow]:focus ~ .kui-underline {\n scale: 1 1;\n }\n @keyframes kui-focus-ring-grow {\n from {\n box-shadow: 0 0 0 0 var(--kui-ring-color, rgb(210 105 30 / 0.55));\n }\n to {\n box-shadow: 0 0 0 5px var(--kui-ring-color, rgb(210 105 30 / 0.55));\n }\n }\n @keyframes kui-validate-shake {\n 10%, 90% {\n translate: -1px 0;\n }\n 20%, 80% {\n translate: 2px 0;\n }\n 30%, 50%, 70% {\n translate: -4px 0;\n }\n 40%, 60% {\n translate: 4px 0;\n }\n }\n [data-kui-fx~=validate-check] {\n stroke-dasharray: 24;\n stroke-dashoffset: 24;\n }\n @keyframes kui-validate-check {\n to {\n stroke-dashoffset: 0;\n }\n }\n [data-kui-fx~=strength-meter] ~ .kui-meter > * {\n background: var(--kui-meter-off, currentColor);\n opacity: 0.2;\n transition: opacity 200ms ease-out, background-color 200ms ease-out;\n }\n [data-kui-fx~=strength-meter][data-kui-strength-level=\"1\"] ~ .kui-meter > *:nth-child(-n+1),\n [data-kui-fx~=strength-meter][data-kui-strength-level=\"2\"] ~ .kui-meter > *:nth-child(-n+2),\n [data-kui-fx~=strength-meter][data-kui-strength-level=\"3\"] ~ .kui-meter > *:nth-child(-n+3),\n [data-kui-fx~=strength-meter][data-kui-strength-level=\"4\"] ~ .kui-meter > *:nth-child(-n+4),\n [data-kui-fx~=strength-meter][data-kui-strength-level=\"5\"] ~ .kui-meter > *:nth-child(-n+5),\n [data-kui-fx~=strength-meter][data-kui-strength-level=\"6\"] ~ .kui-meter > *:nth-child(-n+6),\n [data-kui-fx~=strength-meter][data-kui-strength-level=\"7\"] ~ .kui-meter > *:nth-child(-n+7),\n [data-kui-fx~=strength-meter][data-kui-strength-level=\"8\"] ~ .kui-meter > *:nth-child(-n+8),\n [data-kui-fx~=strength-meter][data-kui-strength-level=\"9\"] ~ .kui-meter > *:nth-child(-n+9),\n [data-kui-fx~=strength-meter][data-kui-strength-level=\"10\"] ~ .kui-meter > *:nth-child(-n+10),\n [data-kui-fx~=strength-meter][data-kui-strength-level=\"11\"] ~ .kui-meter > *:nth-child(-n+11),\n [data-kui-fx~=strength-meter][data-kui-strength-level=\"12\"] ~ .kui-meter > *:nth-child(-n+12),\n [data-kui-fx~=strength-meter][data-kui-strength-level=\"13\"] ~ .kui-meter > *:nth-child(-n+13),\n [data-kui-fx~=strength-meter][data-kui-strength-level=\"14\"] ~ .kui-meter > *:nth-child(-n+14),\n [data-kui-fx~=strength-meter][data-kui-strength-level=\"15\"] ~ .kui-meter > *:nth-child(-n+15),\n [data-kui-fx~=strength-meter][data-kui-strength-level=\"16\"] ~ .kui-meter > *:nth-child(-n+16),\n [data-kui-fx~=strength-meter][data-kui-strength-level=\"17\"] ~ .kui-meter > *:nth-child(-n+17),\n [data-kui-fx~=strength-meter][data-kui-strength-level=\"18\"] ~ .kui-meter > *:nth-child(-n+18),\n [data-kui-fx~=strength-meter][data-kui-strength-level=\"19\"] ~ .kui-meter > *:nth-child(-n+19),\n [data-kui-fx~=strength-meter][data-kui-strength-level=\"20\"] ~ .kui-meter > *:nth-child(-n+20) {\n opacity: 1;\n background: var(--kui-meter-on, #2e9e5b);\n }\n [data-kui-fx~=toggle-morph] ~ .kui-track {\n display: inline-block;\n width: calc(40px * var(--kui-toggle-scale, 1));\n height: calc(22px * var(--kui-toggle-scale, 1));\n border-radius: 999px;\n background: var(--dim, #9a8d80);\n transition: background-color 200ms ease-out;\n position: relative;\n }\n [data-kui-fx~=toggle-morph] ~ .kui-track .kui-thumb {\n position: absolute;\n top: calc(2px * var(--kui-toggle-scale, 1));\n left: calc(2px * var(--kui-toggle-scale, 1));\n width: calc(18px * var(--kui-toggle-scale, 1));\n height: calc(18px * var(--kui-toggle-scale, 1));\n border-radius: 50%;\n background: var(--kui-thumb-color, #fff);\n translate: 0 0;\n transition: translate 200ms ease-out;\n }\n [data-kui-fx~=toggle-morph]:checked ~ .kui-track {\n background: var(--accent, #d2691e);\n }\n [data-kui-fx~=toggle-morph]:checked ~ .kui-track .kui-thumb {\n translate: calc(18px * var(--kui-toggle-scale, 1)) 0;\n }\n [data-kui-fx~=checkbox-draw] ~ svg path {\n stroke-dasharray: 24;\n stroke-dashoffset: 24;\n transition: stroke-dashoffset 220ms ease-out;\n }\n [data-kui-fx~=checkbox-draw]:checked ~ svg path {\n stroke-dashoffset: 0;\n }\n [data-kui-fx~=radio-fill] ~ .kui-dot {\n display: inline-block;\n width: calc(10px * var(--kui-radio-scale, 1));\n height: calc(10px * var(--kui-radio-scale, 1));\n border-radius: 50%;\n background: var(--accent, #d2691e);\n scale: 0;\n transition: scale 180ms ease-out;\n }\n [data-kui-fx~=radio-fill]:checked ~ .kui-dot {\n scale: 1;\n }\n [data-kui-fx~=range-fill] {\n --kui-fill: 0%;\n accent-color: var(--accent, #d2691e);\n background:\n linear-gradient(\n to right,\n var(--accent, #d2691e) var(--kui-fill, 0%),\n var(--line, #2a2422) var(--kui-fill, 0%));\n height: 4px;\n border-radius: 999px;\n appearance: none;\n outline: none;\n }\n [data-kui-fx~=submit-to-spinner-to-check] .kui-stage-idle,\n [data-kui-fx~=submit-to-spinner-to-check] .kui-stage-loading,\n [data-kui-fx~=submit-to-spinner-to-check] .kui-stage-done {\n display: none;\n }\n [data-kui-fx~=submit-to-spinner-to-check][data-kui-stage=idle] .kui-stage-idle,\n [data-kui-fx~=submit-to-spinner-to-check][data-kui-stage=loading] .kui-stage-loading,\n [data-kui-fx~=submit-to-spinner-to-check][data-kui-stage=done] .kui-stage-done {\n display: inline-flex;\n }\n [data-kui-fx~=submit-to-spinner-to-check] .kui-spinner {\n width: 1em;\n height: 1em;\n border-radius: 50%;\n border: 2px solid currentColor;\n border-top-color: transparent;\n animation: kui-spin 700ms linear infinite;\n }\n @keyframes kui-spin {\n to {\n rotate: 360deg;\n }\n }\n [data-kui-fx~=step-progress] {\n cursor: pointer;\n }\n [data-kui-fx~=step-progress] > * {\n background: var(--dim, #9a8d80);\n opacity: 0.35;\n transition: opacity 200ms ease-out, background-color 200ms ease-out;\n }\n [data-kui-fx~=step-progress][data-kui-step=\"0\"] > *:nth-child(-n+1),\n [data-kui-fx~=step-progress][data-kui-step=\"1\"] > *:nth-child(-n+2),\n [data-kui-fx~=step-progress][data-kui-step=\"2\"] > *:nth-child(-n+3),\n [data-kui-fx~=step-progress][data-kui-step=\"3\"] > *:nth-child(-n+4),\n [data-kui-fx~=step-progress][data-kui-step=\"4\"] > *:nth-child(-n+5),\n [data-kui-fx~=step-progress][data-kui-step=\"5\"] > *:nth-child(-n+6),\n [data-kui-fx~=step-progress][data-kui-step=\"6\"] > *:nth-child(-n+7),\n [data-kui-fx~=step-progress][data-kui-step=\"7\"] > *:nth-child(-n+8),\n [data-kui-fx~=step-progress][data-kui-step=\"8\"] > *:nth-child(-n+9),\n [data-kui-fx~=step-progress][data-kui-step=\"9\"] > *:nth-child(-n+10),\n [data-kui-fx~=step-progress][data-kui-step=\"10\"] > *:nth-child(-n+11),\n [data-kui-fx~=step-progress][data-kui-step=\"11\"] > *:nth-child(-n+12),\n [data-kui-fx~=step-progress][data-kui-step=\"12\"] > *:nth-child(-n+13),\n [data-kui-fx~=step-progress][data-kui-step=\"13\"] > *:nth-child(-n+14),\n [data-kui-fx~=step-progress][data-kui-step=\"14\"] > *:nth-child(-n+15),\n [data-kui-fx~=step-progress][data-kui-step=\"15\"] > *:nth-child(-n+16),\n [data-kui-fx~=step-progress][data-kui-step=\"16\"] > *:nth-child(-n+17),\n [data-kui-fx~=step-progress][data-kui-step=\"17\"] > *:nth-child(-n+18),\n [data-kui-fx~=step-progress][data-kui-step=\"18\"] > *:nth-child(-n+19),\n [data-kui-fx~=step-progress][data-kui-step=\"19\"] > *:nth-child(-n+20) {\n opacity: 1;\n background: var(--accent, #d2691e);\n }\n}\n\n/* src/css/ambient.css */\n@layer kui.effects {\n [data-kui-fx~=gradient-mesh] {\n background-image:\n radial-gradient(\n at 15% 20%,\n color-mix(in srgb, var(--kui-c1, #7c3aed) 55%, transparent),\n transparent 55%),\n radial-gradient(\n at 85% 15%,\n color-mix(in srgb, var(--kui-c2, #06b6d4) 50%, transparent),\n transparent 55%),\n radial-gradient(\n at 50% 85%,\n color-mix(in srgb, var(--kui-c3, #f97316) 45%, transparent),\n transparent 55%);\n background-size: 200% 200%;\n --kui-fx-gradient-mesh-iterations: infinite;\n }\n @keyframes kui-gradient-mesh {\n 0%, 100% {\n background-position:\n 0% 0%,\n 100% 0%,\n 50% 100%;\n }\n 50% {\n background-position:\n 25% 35%,\n 75% 30%,\n 35% 70%;\n }\n }\n [data-kui-fx~=aurora] {\n background-image:\n linear-gradient(\n 120deg,\n color-mix(in srgb, var(--kui-c1, #34d399) 45%, transparent),\n transparent 45%),\n linear-gradient(\n 240deg,\n color-mix(in srgb, var(--kui-c2, #60a5fa) 45%, transparent),\n transparent 45%),\n linear-gradient(\n 0deg,\n color-mix(in srgb, var(--kui-c3, #c084fc) 40%, transparent),\n transparent 50%);\n background-size: 260% 260%;\n --kui-fx-aurora-iterations: infinite;\n }\n @keyframes kui-aurora {\n 0%, 100% {\n background-position:\n 0% 50%,\n 100% 50%,\n 50% 0%;\n }\n 50% {\n background-position:\n 60% 30%,\n 40% 70%,\n 55% 60%;\n }\n }\n [data-kui-fx~=wave-blob] {\n background-image:\n radial-gradient(\n circle,\n color-mix(in srgb, var(--kui-c1, #22d3ee) 50%, transparent),\n transparent 60%);\n background-size: 140% 140%;\n background-repeat: no-repeat;\n --kui-fx-wave-blob-iterations: infinite;\n }\n @keyframes kui-wave-blob {\n 0%, 100% {\n background-position: 20% 30%;\n background-size: 140% 140%;\n }\n 33% {\n background-position: 70% 20%;\n background-size: 160% 160%;\n }\n 66% {\n background-position: 50% 75%;\n background-size: 120% 120%;\n }\n }\n [data-kui-fx~=spotlight-follow] {\n background-image:\n radial-gradient(\n circle,\n color-mix(in srgb, var(--kui-c1, #fde68a) 65%, transparent),\n transparent 65%);\n background-size: 55% 55%;\n background-repeat: no-repeat;\n --kui-fx-spotlight-follow-iterations: infinite;\n }\n @keyframes kui-spotlight-follow {\n 0%, 100% {\n background-position: 10% 15%;\n }\n 25% {\n background-position: 85% 20%;\n }\n 50% {\n background-position: 80% 80%;\n }\n 75% {\n background-position: 15% 75%;\n }\n }\n [data-kui-fx~=gradient-rotate-border] {\n position: relative;\n background-image:\n linear-gradient(\n 90deg,\n var(--kui-c1, #f472b6),\n var(--kui-c2, #60a5fa),\n var(--kui-c3, #34d399),\n var(--kui-c4, #fbbf24),\n var(--kui-c1, #f472b6));\n background-size: 300% 100%;\n padding: 3px;\n mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);\n mask-composite: exclude;\n -webkit-mask-composite: xor;\n --kui-fx-gradient-rotate-border-iterations: infinite;\n }\n @keyframes kui-gradient-rotate-border {\n from {\n background-position: 0% 50%;\n }\n to {\n background-position: 300% 50%;\n }\n }\n [data-kui-fx~=noise-overlay] {\n background-image:\n repeating-radial-gradient(\n circle at 0 0,\n color-mix(in srgb, var(--kui-c1, currentColor) 30%, transparent) 0,\n transparent 1.4px,\n transparent 3px);\n background-size: 5px 5px;\n --kui-fx-noise-overlay-iterations: infinite;\n }\n @keyframes kui-noise-overlay {\n 0% {\n background-position: 0 0;\n }\n 20% {\n background-position: -3px 1px;\n }\n 40% {\n background-position: 2px -2px;\n }\n 60% {\n background-position: -1px 3px;\n }\n 80% {\n background-position: 3px 2px;\n }\n 100% {\n background-position: 0 0;\n }\n }\n [data-kui-fx~=scanline] {\n background-image:\n linear-gradient(\n to bottom,\n transparent,\n color-mix(in srgb, var(--kui-c1, currentColor) 35%, transparent) 50%,\n transparent);\n background-size: 100% 220%;\n background-repeat: no-repeat;\n --kui-fx-scanline-iterations: infinite;\n }\n @keyframes kui-scanline {\n from {\n background-position: 0 -120%;\n }\n to {\n background-position: 0 120%;\n }\n }\n [data-kui-fx~=dot-grid-drift] {\n background-image:\n radial-gradient(\n circle,\n color-mix(in srgb, var(--kui-c1, currentColor) 45%, transparent) 1.5px,\n transparent 1.5px);\n background-size: 22px 22px;\n --kui-fx-dot-grid-drift-iterations: infinite;\n }\n @keyframes kui-dot-grid-drift {\n from {\n background-position: 0 0;\n }\n to {\n background-position: 22px 22px;\n }\n }\n [data-kui-fx~=line-grid-drift] {\n background-image:\n repeating-linear-gradient(\n 0deg,\n color-mix(in srgb, var(--kui-c1, currentColor) 30%, transparent) 0 1px,\n transparent 1px 26px),\n repeating-linear-gradient(\n 90deg,\n color-mix(in srgb, var(--kui-c1, currentColor) 30%, transparent) 0 1px,\n transparent 1px 26px);\n --kui-fx-line-grid-drift-iterations: infinite;\n }\n @keyframes kui-line-grid-drift {\n from {\n background-position: 0 0, 0 0;\n }\n to {\n background-position: 0 26px, 26px 0;\n }\n }\n [data-kui-fx~=starfield] {\n background-image:\n radial-gradient(\n 1px 1px at 10% 20%,\n color-mix(in srgb, var(--kui-c1, #ffffff) 90%, transparent),\n transparent),\n radial-gradient(\n 1px 1px at 70% 60%,\n color-mix(in srgb, var(--kui-c1, #ffffff) 70%, transparent),\n transparent),\n radial-gradient(\n 1.5px 1.5px at 40% 80%,\n color-mix(in srgb, var(--kui-c1, #ffffff) 85%, transparent),\n transparent),\n radial-gradient(\n 1px 1px at 90% 30%,\n color-mix(in srgb, var(--kui-c1, #ffffff) 60%, transparent),\n transparent),\n radial-gradient(\n 1.5px 1.5px at 25% 55%,\n color-mix(in srgb, var(--kui-c1, #ffffff) 80%, transparent),\n transparent);\n background-size: 220px 220px;\n background-repeat: repeat;\n --kui-fx-starfield-iterations: infinite;\n }\n @keyframes kui-starfield {\n from {\n background-position:\n 0 0,\n 0 0,\n 0 0,\n 0 0,\n 0 0;\n }\n to {\n background-position:\n 220px 90px,\n -160px 220px,\n 90px -140px,\n -220px -90px,\n 140px 160px;\n }\n }\n [data-kui-fx~=float] {\n --kui-fx-float-iterations: infinite;\n }\n @keyframes kui-float {\n 0%, 100% {\n translate: 0 0;\n }\n 50% {\n translate: 0 calc(var(--kui-distance, 14px) * -1);\n }\n }\n [data-kui-fx~=bob] {\n --kui-fx-bob-iterations: infinite;\n }\n @keyframes kui-bob {\n 0%, 100% {\n translate: 0 0;\n }\n 50% {\n translate: 0 calc(var(--kui-distance, 8px) * -1);\n }\n }\n [data-kui-fx~=floating-shapes] {\n --kui-fx-floating-shapes-iterations: infinite;\n }\n @keyframes kui-floating-shapes {\n 0%, 100% {\n translate: 0 0;\n }\n 33% {\n translate: calc(var(--kui-distance, 10px) * 0.6) calc(var(--kui-distance, 10px) * -1);\n }\n 66% {\n translate: calc(var(--kui-distance, 10px) * -0.6) calc(var(--kui-distance, 10px) * -0.4);\n }\n }\n [data-kui-fx~=glow-pulse] {\n --kui-fx-glow-pulse-iterations: infinite;\n }\n @keyframes kui-glow-pulse {\n 0%, 100% {\n scale: 1;\n opacity: 0.6;\n }\n 50% {\n scale: var(--kui-pulse-scale, 1.15);\n opacity: 1;\n }\n }\n}\n\n/* src/css/feedback.css */\n@layer kui.effects {\n [data-kui-fx~=skeleton-shimmer] {\n background-color: var(--kui-skeleton-base, #2a2422);\n background-image:\n linear-gradient(\n 100deg,\n transparent 30%,\n color-mix(in srgb, var(--kui-skeleton-highlight, #ffffff) 18%, transparent) 50%,\n transparent 70%);\n background-size: 200% 100%;\n --kui-fx-skeleton-shimmer-iterations: infinite;\n }\n @keyframes kui-skeleton-shimmer {\n from {\n background-position: 150% 0;\n }\n to {\n background-position: -50% 0;\n }\n }\n @keyframes kui-skeleton-to-content {\n from {\n opacity: 0;\n }\n }\n [data-kui-fx~=spinner] {\n display: inline-block;\n width: var(--kui-spinner-size, 28px);\n height: var(--kui-spinner-size, 28px);\n border-radius: 50%;\n border: 3px solid color-mix(in srgb, currentColor 20%, transparent);\n border-top-color: currentColor;\n --kui-fx-spinner-iterations: infinite;\n }\n @keyframes kui-spinner-spin {\n to {\n rotate: 360deg;\n }\n }\n [data-kui-fx~=spinner-ring] {\n display: inline-block;\n width: var(--kui-spinner-size, 28px);\n height: var(--kui-spinner-size, 28px);\n border-radius: 50%;\n border: 3px dashed color-mix(in srgb, currentColor 55%, transparent);\n --kui-fx-spinner-ring-iterations: infinite;\n }\n @keyframes kui-spinner-ring-spin {\n to {\n rotate: 360deg;\n }\n }\n [data-kui-fx~=spinner-dots] {\n display: inline-block;\n width: var(--kui-dot-size, 8px);\n height: var(--kui-dot-size, 8px);\n border-radius: 50%;\n background: currentColor;\n box-shadow: calc(var(--kui-dot-size, 8px) * -2) 0 currentColor, calc(var(--kui-dot-size, 8px) * 2) 0 currentColor;\n --kui-fx-spinner-dots-iterations: infinite;\n }\n @keyframes kui-spinner-dots {\n 0%, 80%, 100% {\n scale: 0.7;\n opacity: 0.5;\n }\n 40% {\n scale: 1.15;\n opacity: 1;\n }\n }\n [data-kui-fx~=progress-indeterminate] {\n transform-origin: 0% 50%;\n background: currentColor;\n border-radius: inherit;\n --kui-fx-progress-indeterminate-iterations: infinite;\n }\n @keyframes kui-progress-indeterminate {\n 0% {\n translate: -100% 0;\n scale: 0.4 1;\n }\n 50% {\n scale: 1 1;\n }\n 100% {\n translate: 100% 0;\n scale: 0.4 1;\n }\n }\n @keyframes kui-toast-slide-in {\n from {\n opacity: 0;\n translate: 0 var(--kui-distance, 24px);\n }\n to {\n opacity: 1;\n translate: 0 0;\n }\n }\n @keyframes kui-toast-slide-out {\n from {\n opacity: 1;\n translate: 0 0;\n }\n to {\n opacity: 0;\n translate: 0 var(--kui-distance, 24px);\n }\n }\n @keyframes kui-shake-error {\n 10%, 90% {\n translate: -1px 0;\n }\n 20%, 80% {\n translate: 2px 0;\n }\n 30%, 50%, 70% {\n translate: -4px 0;\n }\n 40%, 60% {\n translate: 4px 0;\n }\n }\n @keyframes kui-wobble {\n 0% {\n translate: 0 0;\n rotate: 0deg;\n }\n 15% {\n translate: -6px 0;\n rotate: -6deg;\n }\n 30% {\n translate: 4px 0;\n rotate: 4deg;\n }\n 45% {\n translate: -3px 0;\n rotate: -3deg;\n }\n 60% {\n translate: 2px 0;\n rotate: 2deg;\n }\n 75% {\n translate: -1px 0;\n rotate: -1deg;\n }\n 100% {\n translate: 0 0;\n rotate: 0deg;\n }\n }\n [data-kui-fx~=ripple] {\n border-radius: 50%;\n background: currentColor;\n transform-origin: center;\n }\n @keyframes kui-ripple {\n from {\n scale: 0.2;\n opacity: 0.6;\n }\n to {\n scale: var(--kui-ripple-scale, 4);\n opacity: 0;\n }\n }\n @keyframes kui-badge-pop {\n 0% {\n scale: 0.4;\n }\n 60% {\n scale: var(--kui-pop-scale, 1.18);\n }\n 100% {\n scale: 1;\n }\n }\n @keyframes kui-count-bump {\n 0%, 100% {\n scale: 1;\n }\n 50% {\n scale: var(--kui-pop-scale, 1.18);\n }\n }\n [data-kui-fx~=heart-burst] {\n color: var(--kui-heart-color, #f43f5e);\n }\n @keyframes kui-heart-burst {\n 0% {\n scale: 1;\n }\n 30% {\n scale: var(--kui-pop-scale, 1.18);\n }\n 55% {\n scale: 0.9;\n }\n 100% {\n scale: 1;\n }\n }\n [data-kui-fx~=confetti-burst] {\n background-image:\n radial-gradient(\n circle at 20% 20%,\n var(--kui-c1, #f43f5e) 0 3px,\n transparent 3px),\n radial-gradient(\n circle at 75% 15%,\n var(--kui-c2, #fbbf24) 0 3px,\n transparent 3px),\n radial-gradient(\n circle at 50% 75%,\n var(--kui-c3, #34d399) 0 3px,\n transparent 3px),\n radial-gradient(\n circle at 85% 65%,\n var(--kui-c4, #60a5fa) 0 3px,\n transparent 3px),\n radial-gradient(\n circle at 15% 65%,\n var(--kui-c5, #c084fc) 0 3px,\n transparent 3px);\n background-repeat: no-repeat;\n }\n @keyframes kui-confetti-burst {\n 0% {\n scale: 0.6;\n opacity: 0;\n }\n 40% {\n scale: var(--kui-pop-scale, 1.18);\n opacity: 1;\n }\n 100% {\n scale: 1;\n opacity: 1;\n }\n }\n @keyframes kui-copy-confirm {\n 0% {\n opacity: 0;\n }\n 15% {\n opacity: 1;\n }\n 85% {\n opacity: 1;\n }\n 100% {\n opacity: 0;\n }\n }\n @keyframes kui-pull-to-refresh {\n 0% {\n translate: 0 0;\n }\n 45% {\n translate: 0 var(--kui-pull-distance, 36px);\n }\n 100% {\n translate: 0 0;\n }\n }\n}\n\n/* src/css/numbers.css */\n@layer kui.effects {\n @keyframes kui-progress-ring {\n from {\n stroke-dashoffset: var(--kui-path-length, 100);\n }\n to {\n stroke-dashoffset: 0;\n }\n }\n @keyframes kui-gauge-sweep {\n from {\n stroke-dashoffset: var(--kui-path-length, 100);\n }\n to {\n stroke-dashoffset: 0;\n }\n }\n @keyframes kui-donut-sweep {\n from {\n stroke-dashoffset: var(--kui-path-length, 100);\n }\n to {\n stroke-dashoffset: 0;\n }\n }\n @keyframes kui-sparkline-draw {\n from {\n stroke-dashoffset: var(--kui-path-length, 1000);\n }\n to {\n stroke-dashoffset: 0;\n }\n }\n [data-kui-fx~=progress-ring],\n [data-kui-fx~=gauge-sweep],\n [data-kui-fx~=donut-sweep],\n [data-kui-fx~=sparkline-draw] {\n stroke-dasharray: var(--kui-path-length, 100);\n fill: none;\n }\n @keyframes kui-progress-bar {\n from {\n scale: 0 1;\n }\n to {\n scale: 1 1;\n }\n }\n [data-kui-fx~=progress-bar] {\n transform-origin: left center;\n }\n @keyframes kui-progress-segments {\n from {\n opacity: 0.18;\n }\n to {\n opacity: 1;\n }\n }\n @keyframes kui-star-rating-fill {\n from {\n clip-path: inset(0 100% 0 0);\n }\n to {\n clip-path: inset(0 calc(100% - var(--kui-fill, 100%)) 0 0);\n }\n }\n .kui-count-decorative {\n display: inline-flex;\n align-items: baseline;\n }\n .kui-odometer-col {\n display: inline-block;\n overflow: hidden;\n height: 1em;\n line-height: 1;\n vertical-align: baseline;\n }\n .kui-odometer-strip {\n display: flex;\n flex-direction: column;\n translate: 0 calc(var(--kui-o, 0) * -1em);\n transition: translate 220ms ease-out;\n }\n .kui-odometer-strip > span {\n height: 1em;\n line-height: 1;\n }\n}\n\n/* src/css/interaction.css */\n@layer kui.effects {\n @property --kui-border-angle { syntax: \"<angle>\"; inherits: false; initial-value: 0deg; }\n @property --kui-border-pct { syntax: \"<percentage>\"; inherits: false; initial-value: 0%; }\n [data-kui-fx~=lift] {\n transition: translate var(--kui-lift-duration, 220ms) var(--kui-lift-ease, ease-out);\n }\n [data-kui-fx~=lift]:focus-visible {\n translate: 0 calc(var(--kui-lift-distance, 6px) * -1);\n }\n [data-kui-fx~=lift-shadow] {\n transition: translate var(--kui-lift-shadow-duration, 220ms) var(--kui-lift-shadow-ease, ease-out), box-shadow var(--kui-lift-shadow-duration, 220ms) var(--kui-lift-shadow-ease, ease-out);\n }\n [data-kui-fx~=lift-shadow]:focus-visible {\n translate: 0 calc(var(--kui-lift-distance, 6px) * -1);\n box-shadow: 0 14px 28px -12px rgb(0 0 0 / 0.45);\n }\n [data-kui-fx~=shine-sweep] {\n position: relative;\n overflow: hidden;\n }\n [data-kui-fx~=shine-sweep]::after {\n content: \"\";\n position: absolute;\n inset: 0;\n background:\n linear-gradient(\n 115deg,\n transparent 40%,\n var(--kui-c1, rgb(255 255 255 / 0.35)) 50%,\n transparent 60%);\n background-size: 220% 100%;\n background-position: 120% 0;\n pointer-events: none;\n }\n [data-kui-fx~=shine-sweep]:focus-visible::after {\n animation: kui-shine-sweep var(--kui-shine-sweep-duration, 700ms) var(--kui-shine-sweep-ease, ease-out);\n }\n @keyframes kui-shine-sweep {\n from {\n background-position: 120% 0;\n }\n to {\n background-position: -20% 0;\n }\n }\n [data-kui-fx~=split-flap] {\n display: inline-block;\n perspective: 600px;\n backface-visibility: hidden;\n }\n [data-kui-fx~=split-flap]:focus-visible {\n animation: kui-split-flap var(--kui-split-flap-duration, 600ms) var(--kui-split-flap-ease, ease-in-out);\n }\n @keyframes kui-split-flap {\n from {\n rotate: x 0deg;\n }\n to {\n rotate: x 360deg;\n }\n }\n [data-kui-fx~=border-draw] {\n border: 2px solid transparent;\n border-image-slice: 1;\n border-image-source:\n conic-gradient(\n from -90deg,\n var(--kui-border-draw-color, var(--accent, #d2691e)) 0 var(--kui-border-pct, 0%),\n transparent 0);\n transition: --kui-border-pct var(--kui-border-draw-duration, 500ms) var(--kui-border-draw-ease, ease-out);\n }\n [data-kui-fx~=border-draw]:focus-visible {\n --kui-border-pct: 100%;\n }\n [data-kui-fx~=border-glow] {\n transition: box-shadow var(--kui-border-glow-duration, 260ms) var(--kui-border-glow-ease, ease-out);\n }\n [data-kui-fx~=border-glow]:focus-visible {\n box-shadow: 0 0 0 3px var(--kui-border-glow-color, var(--accent, #d2691e));\n }\n [data-kui-fx~=beam-border],\n [data-kui-fx~=beam-border-auto] {\n position: relative;\n }\n [data-kui-fx~=beam-border]::before,\n [data-kui-fx~=beam-border-auto]::before {\n content: \"\";\n position: absolute;\n inset: 0;\n border-radius: inherit;\n padding: var(--kui-beam-border-width, 3px);\n background:\n conic-gradient(\n from var(--kui-border-angle, 0deg),\n transparent 0deg,\n transparent 260deg,\n var(--kui-beam-border-c1, #ff5f6d) 282deg,\n var(--kui-beam-border-c2, #ffc371) 306deg,\n var(--kui-beam-border-c3, #4facfe) 330deg,\n var(--kui-beam-border-c4, #a855f7) 354deg,\n transparent 360deg);\n -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);\n -webkit-mask-composite: xor;\n mask-composite: exclude;\n opacity: 0;\n pointer-events: none;\n transition: opacity var(--kui-beam-border-fade-duration, 200ms) ease-out;\n }\n [data-kui-fx~=beam-border]:focus-visible::before {\n opacity: 1;\n animation: kui-beam-rotate var(--kui-beam-border-duration, 4260ms) linear infinite;\n }\n [data-kui-fx~=beam-border-auto]::before {\n opacity: 1;\n animation: kui-beam-rotate var(--kui-beam-border-duration, 4260ms) linear infinite;\n }\n @keyframes kui-beam-rotate {\n to {\n --kui-border-angle: 360deg;\n }\n }\n @media (prefers-reduced-motion: reduce) {\n [data-kui-fx~=beam-border]:focus-visible::before,\n [data-kui-fx~=beam-border-auto]::before {\n animation: none;\n --kui-border-angle: 45deg;\n }\n }\n [data-kui-fx~=underline-slide] {\n position: relative;\n text-decoration: none;\n }\n [data-kui-fx~=underline-slide]::after {\n content: \"\";\n position: absolute;\n left: 0;\n right: 0;\n bottom: -0.15em;\n height: 0.08em;\n background: currentcolor;\n scale: 0 1;\n transform-origin: left center;\n transition: scale var(--kui-underline-slide-duration, 260ms) var(--kui-underline-slide-ease, ease-out);\n }\n [data-kui-fx~=underline-slide]:focus-visible::after {\n scale: 1 1;\n }\n [data-kui-fx~=underline-center] {\n position: relative;\n text-decoration: none;\n }\n [data-kui-fx~=underline-center]::after {\n content: \"\";\n position: absolute;\n left: 0;\n right: 0;\n bottom: -0.15em;\n height: 0.08em;\n background: currentcolor;\n scale: 0 1;\n transform-origin: center;\n transition: scale var(--kui-underline-center-duration, 260ms) var(--kui-underline-center-ease, ease-out);\n }\n [data-kui-fx~=underline-center]:focus-visible::after {\n scale: 1 1;\n }\n [data-kui-fx~=icon-wiggle]:focus-visible {\n animation: kui-icon-wiggle var(--kui-icon-wiggle-duration, 500ms) var(--kui-icon-wiggle-ease, ease-in-out);\n }\n @keyframes kui-icon-wiggle {\n 0%, 100% {\n rotate: 0deg;\n }\n 20% {\n rotate: -12deg;\n }\n 40% {\n rotate: 10deg;\n }\n 60% {\n rotate: -6deg;\n }\n 80% {\n rotate: 4deg;\n }\n }\n [data-kui-fx~=icon-spin]:focus-visible {\n animation: kui-icon-spin var(--kui-icon-spin-duration, 700ms) linear;\n }\n @keyframes kui-icon-spin {\n from {\n rotate: 0deg;\n }\n to {\n rotate: 360deg;\n }\n }\n [data-kui-fx~=icon-bounce]:focus-visible {\n animation: kui-icon-bounce var(--kui-icon-bounce-duration, 500ms) var(--kui-icon-bounce-ease, ease-out);\n }\n @keyframes kui-icon-bounce {\n 0%, 100% {\n translate: 0 0;\n }\n 30% {\n translate: 0 -7px;\n }\n 55% {\n translate: 0 1px;\n }\n 75% {\n translate: 0 -3px;\n }\n }\n @media (hover: hover) and (pointer: fine) {\n [data-kui-fx~=lift]:hover {\n translate: 0 calc(var(--kui-lift-distance, 6px) * -1);\n }\n [data-kui-fx~=lift-shadow]:hover {\n translate: 0 calc(var(--kui-lift-distance, 6px) * -1);\n box-shadow: 0 14px 28px -12px rgb(0 0 0 / 0.45);\n }\n [data-kui-fx~=shine-sweep]:hover::after {\n animation: kui-shine-sweep var(--kui-shine-sweep-duration, 700ms) var(--kui-shine-sweep-ease, ease-out);\n }\n [data-kui-fx~=split-flap]:hover {\n animation: kui-split-flap var(--kui-split-flap-duration, 600ms) var(--kui-split-flap-ease, ease-in-out);\n }\n [data-kui-fx~=border-draw]:hover {\n --kui-border-pct: 100%;\n }\n [data-kui-fx~=border-glow]:hover {\n box-shadow: 0 0 0 3px var(--kui-border-glow-color, var(--accent, #d2691e));\n }\n [data-kui-fx~=beam-border]:hover::before {\n opacity: 1;\n animation: kui-beam-rotate var(--kui-beam-border-duration, 4260ms) linear infinite;\n }\n [data-kui-fx~=underline-slide]:hover::after {\n scale: 1 1;\n }\n [data-kui-fx~=underline-center]:hover::after {\n scale: 1 1;\n }\n [data-kui-fx~=icon-wiggle]:hover {\n animation: kui-icon-wiggle var(--kui-icon-wiggle-duration, 500ms) var(--kui-icon-wiggle-ease, ease-in-out);\n }\n [data-kui-fx~=icon-spin]:hover {\n animation: kui-icon-spin var(--kui-icon-spin-duration, 700ms) linear;\n }\n [data-kui-fx~=icon-bounce]:hover {\n animation: kui-icon-bounce var(--kui-icon-bounce-duration, 500ms) var(--kui-icon-bounce-ease, ease-out);\n }\n }\n [data-kui-fx~=tilt-3d],\n [data-kui-fx~=tilt-parallax] {\n transform-style: preserve-3d;\n }\n [data-kui-fx~=cursor-spotlight]::before {\n content: \"\";\n position: absolute;\n inset: 0;\n border-radius: inherit;\n pointer-events: none;\n opacity: var(--kui-spotlight-opacity, 0);\n transition: opacity 200ms ease-out;\n background:\n radial-gradient(\n circle 160px at var(--kui-x, 50%) var(--kui-y, 50%),\n color-mix(in srgb, var(--accent, #d2691e) 30%, transparent),\n transparent 70%);\n }\n .kui-cursor-dot {\n position: fixed;\n top: 0;\n left: 0;\n z-index: 9999;\n display: grid;\n place-items: center;\n pointer-events: none;\n opacity: 0;\n transition: opacity 160ms ease-out;\n }\n .kui-cursor-dot-active {\n opacity: 1;\n }\n .kui-cursor-dot-follow,\n .kui-cursor-dot-lag,\n .kui-cursor-dot-invert {\n width: 14px;\n height: 14px;\n margin: -7px 0 0 -7px;\n border-radius: 50%;\n background: var(--accent, #d2691e);\n }\n .kui-cursor-dot-invert {\n background: var(--kui-invert-color, #fff);\n mix-blend-mode: difference;\n }\n .kui-cursor-dot-label {\n margin: -1.4em 0 0 -1.4em;\n padding: 0.4em 0.8em;\n border-radius: 999px;\n background: var(--accent, #d2691e);\n color: var(--kui-label-color, #fff);\n font-size: 0.75rem;\n font-family:\n ui-monospace,\n Menlo,\n monospace;\n white-space: nowrap;\n }\n @media (pointer: coarse) {\n .kui-cursor-dot {\n display: none;\n }\n }\n}\n\n/* src/css/index.css */\n"
6410
+ style.textContent = "/* src/css/base.css */\n@layer kui.tokens, kui.presets, kui.effects, kui.policy, kui.cloak;\n@layer kui.tokens {\n :root {\n --kui-ease-expo-in: cubic-bezier(0.7, 0, 0.84, 0);\n --kui-ease-expo-out: cubic-bezier(0.16, 1, 0.3, 1);\n --kui-ease-expo-in-out: cubic-bezier(0.87, 0, 0.13, 1);\n --kui-ease-back-in: cubic-bezier(0.36, 0, 0.66, -0.56);\n --kui-ease-back-out: cubic-bezier(0.34, 1.56, 0.64, 1);\n --kui-ease-back-in-out: cubic-bezier(0.68, -0.6, 0.32, 1.6);\n --kui-ease-quart-out: cubic-bezier(0.25, 1, 0.5, 1);\n --kui-ease-circ-out: cubic-bezier(0, 0.55, 0.45, 1);\n --kui-ease-spring: linear(0, 0.4 12%, 0.9 25%, 1.06 38%, 1.01 62%, 1);\n --kui-ease-bounce: linear(0, 0.5 10%, 1.2 30%, 0.9 50%, 1.08 68%, 0.97 82%, 1.02 92%, 1);\n }\n [data-kui-fx] {\n --kui-dir: 1;\n --kui-i: 0;\n }\n :dir(rtl) [data-kui-fx] {\n --kui-dir: -1;\n }\n}\n@layer kui.policy {\n html[data-kui-cloak] [data-kui][data-kui-reveal]:not([data-kui-state]) {\n opacity: 0 !important;\n }\n @media (prefers-reduced-motion: reduce) {\n [data-kui-rm],\n [data-kui-rm]::before,\n [data-kui-rm]::after,\n [data-kui-rm] .kui-odometer-strip,\n [data-kui-rm][data-kui-fx~=label-float] ~ label,\n [data-kui-rm][data-kui-fx~=input-underline-grow] ~ .kui-underline,\n [data-kui-rm][data-kui-fx~=toggle-morph] ~ .kui-track,\n [data-kui-rm][data-kui-fx~=toggle-morph] ~ .kui-track .kui-thumb,\n [data-kui-rm][data-kui-fx~=checkbox-draw] ~ svg path,\n [data-kui-rm][data-kui-fx~=radio-fill] ~ .kui-dot,\n [data-kui-rm][data-kui-fx~=strength-meter] ~ .kui-meter > *,\n [data-kui-rm][data-kui-fx~=hamburger-to-x] .kui-bar,\n [data-kui-rm][data-kui-fx~=play-to-pause] .kui-bar,\n [data-kui-rm][data-kui-fx~=plus-to-minus] .kui-bar,\n [data-kui-rm][data-kui-fx~=flip-card] > .kui-face-front,\n [data-kui-rm][data-kui-fx~=flip-card] > .kui-face-back {\n transition-duration: 1ms !important;\n transition-delay: 0ms !important;\n }\n [data-kui-rm=shorten],\n [data-kui-rm=shorten]::before,\n [data-kui-rm=shorten]::after {\n animation-duration: 1ms !important;\n animation-delay: 0ms !important;\n }\n [data-kui-rm=crossfade] {\n animation-name: kui-in !important;\n animation-duration: 200ms !important;\n }\n [data-kui-rm=disable] {\n animation: none !important;\n opacity: 1 !important;\n translate: none !important;\n scale: none !important;\n rotate: none !important;\n filter: none !important;\n }\n }\n @media print {\n [data-kui-fx],\n [data-kui-reveal] {\n animation: none !important;\n opacity: 1 !important;\n translate: none !important;\n scale: none !important;\n rotate: none !important;\n filter: none !important;\n }\n }\n}\n\n/* src/css/presets.generated.css */\n@layer kui.presets {\n [data-kui-fx~=accordion-height] {\n --kui-auto-height-duration: 400ms;\n --kui-auto-height-ease: ease-out;\n }\n [data-kui-fx~=aurora] {\n --kui-ambient-gradient-duration: 10s;\n --kui-ambient-gradient-delay: 0ms;\n --kui-ambient-gradient-ease: ease-in-out;\n }\n [data-kui-fx~=back-in-down] {\n --kui-distance: 120px;\n --kui-reveal-ease: var(--kui-ease-expo-out, ease-out);\n --kui-reveal-duration: 600ms;\n --kui-reveal-delay: 0ms;\n }\n [data-kui-fx~=back-in-up] {\n --kui-distance: 120px;\n --kui-reveal-ease: var(--kui-ease-expo-out, ease-out);\n --kui-reveal-duration: 600ms;\n --kui-reveal-delay: 0ms;\n }\n [data-kui-fx~=badge-pop] {\n --kui-feedback-pop-duration: 420ms;\n --kui-feedback-pop-delay: 0ms;\n --kui-feedback-pop-ease: var(--kui-ease-back-out, ease-out);\n }\n [data-kui-fx~=beam-border] {\n --kui-beam-border-duration: 220ms;\n --kui-beam-border-ease: ease-out;\n }\n [data-kui-fx~=beam-border-auto] {\n --kui-beam-border-auto-duration: 220ms;\n --kui-beam-border-auto-ease: ease-out;\n }\n [data-kui-fx~=before-after-wipe] {\n --kui-media-wipe-duration: 600ms;\n --kui-media-wipe-delay: 0ms;\n --kui-media-wipe-ease: ease-out;\n }\n [data-kui-fx~=blob-morph] {\n --kui-path-morph-duration: 800ms;\n }\n [data-kui-fx~=blur-in] {\n --kui-blur-duration: 600ms;\n --kui-blur-delay: 0ms;\n --kui-blur-ease: ease-out;\n }\n [data-kui-fx~=blur-out] {\n --kui-blur-duration: 600ms;\n --kui-blur-delay: 0ms;\n --kui-blur-ease: ease-out;\n }\n [data-kui-fx~=blur-up] {\n --kui-media-blur-up-duration: 600ms;\n --kui-media-blur-up-delay: 0ms;\n --kui-media-blur-up-ease: ease-out;\n }\n [data-kui-fx~=bob] {\n --kui-ambient-float-duration: 2s;\n --kui-distance: 8px;\n --kui-ambient-float-delay: 0ms;\n --kui-ambient-float-ease: ease-in-out;\n }\n [data-kui-fx~=book-page-turn] {\n --kui-from-angle: -160deg;\n --kui-flip-face-duration: 900ms;\n --kui-flip-face-delay: 0ms;\n --kui-flip-face-ease: ease-out;\n }\n [data-kui-fx~=bookmark-fill] {\n --kui-shape-fill-duration: 360ms;\n --kui-shape-fill-delay: 0ms;\n --kui-shape-fill-ease: ease-out;\n }\n [data-kui-fx~=border-draw] {\n --kui-border-draw-duration: 220ms;\n --kui-border-draw-ease: ease-out;\n }\n [data-kui-fx~=border-glow] {\n --kui-border-glow-duration: 220ms;\n --kui-border-glow-ease: ease-out;\n }\n [data-kui-fx~=bounce-in] {\n --kui-from-scale: 0.3;\n --kui-scale-ease: var(--kui-ease-bounce, ease-out);\n --kui-scale-duration: 600ms;\n --kui-scale-delay: 0ms;\n }\n [data-kui-fx~=bounce-in-down] {\n --kui-distance: 60px;\n --kui-reveal-ease: var(--kui-ease-back-out, ease-out);\n --kui-reveal-duration: 600ms;\n --kui-reveal-delay: 0ms;\n }\n [data-kui-fx~=bounce-in-up] {\n --kui-distance: 60px;\n --kui-reveal-ease: var(--kui-ease-back-out, ease-out);\n --kui-reveal-duration: 600ms;\n --kui-reveal-delay: 0ms;\n }\n [data-kui-fx~=card-flip-x] {\n --kui-flip-face-duration: 600ms;\n --kui-flip-face-delay: 0ms;\n --kui-flip-face-ease: ease-out;\n }\n [data-kui-fx~=card-flip-y] {\n --kui-flip-face-duration: 600ms;\n --kui-flip-face-delay: 0ms;\n --kui-flip-face-ease: ease-out;\n }\n [data-kui-fx~=chart-area-fill] {\n --kui-shape-fill-duration: 900ms;\n --kui-shape-fill-delay: 0ms;\n --kui-shape-fill-ease: ease-out;\n }\n [data-kui-fx~=chart-bar-grow] {\n --kui-bar-grow-duration: 700ms;\n --kui-bar-grow-ease: var(--kui-ease-back-out, ease-out);\n --kui-bar-grow-delay: 0ms;\n }\n [data-kui-fx~=chart-line-draw] {\n --kui-path-draw-duration: 1200ms;\n --kui-path-draw-ease: ease-in-out;\n --kui-path-draw-delay: 0ms;\n }\n [data-kui-fx~=checkmark-draw] {\n --kui-path-draw-duration: 320ms;\n --kui-path-draw-delay: 0ms;\n --kui-path-draw-ease: ease-out;\n }\n [data-kui-fx~=confetti-burst] {\n --kui-feedback-burst-duration: 900ms;\n --kui-pop-scale: 1.15;\n --kui-feedback-burst-delay: 0ms;\n --kui-feedback-burst-ease: var(--kui-ease-back-out, ease-out);\n }\n [data-kui-fx~=copy-confirm] {\n --kui-feedback-confirm-duration: 1400ms;\n --kui-feedback-confirm-delay: 0ms;\n --kui-feedback-confirm-ease: linear;\n }\n [data-kui-fx~=count-bump] {\n --kui-feedback-pop-duration: 280ms;\n --kui-pop-scale: 1.3;\n --kui-feedback-pop-delay: 0ms;\n --kui-feedback-pop-ease: var(--kui-ease-back-out, ease-out);\n }\n [data-kui-fx~=count-compact] {\n --kui-from: 0;\n --kui-to: 128400;\n --kui-format: compact;\n --kui-count-duration: 1600ms;\n }\n [data-kui-fx~=count-currency] {\n --kui-from: 0;\n --kui-to: 4820;\n --kui-format: currency;\n --kui-decimals: 0;\n --kui-count-duration: 1600ms;\n }\n [data-kui-fx~=count-down] {\n --kui-from: 100;\n --kui-to: 0;\n --kui-count-duration: 1600ms;\n }\n [data-kui-fx~=count-percent] {\n --kui-from: 0;\n --kui-to: 0.82;\n --kui-format: percent;\n --kui-decimals: 0;\n --kui-count-duration: 1600ms;\n }\n [data-kui-fx~=count-up] {\n --kui-from: 0;\n --kui-to: 100;\n --kui-count-duration: 1600ms;\n }\n [data-kui-fx~=cross-draw] {\n --kui-path-draw-duration: 260ms;\n --kui-path-draw-delay: 0ms;\n --kui-path-draw-ease: ease-out;\n }\n [data-kui-fx~=cube-rotate] {\n --kui-from-angle: 90deg;\n --kui-flip-face-duration: 600ms;\n --kui-flip-face-delay: 0ms;\n --kui-flip-face-ease: ease-out;\n }\n [data-kui-fx~=cursor-follow] {\n --kui-stiffness: 300;\n --kui-damping: 30;\n }\n [data-kui-fx~=cursor-invert] {\n --kui-stiffness: 260;\n --kui-damping: 26;\n }\n [data-kui-fx~=cursor-label] {\n --kui-stiffness: 260;\n --kui-damping: 26;\n }\n [data-kui-fx~=cursor-lag] {\n --kui-stiffness: 80;\n --kui-damping: 14;\n }\n [data-kui-fx~=curtain-reveal] {\n --kui-media-wipe-duration: 600ms;\n --kui-media-wipe-delay: 0ms;\n --kui-media-wipe-ease: ease-out;\n }\n [data-kui-fx~=curtain-wipe] {\n --kui-wipe-duration: 800ms;\n --kui-wipe-delay: 0ms;\n --kui-wipe-ease: ease-out;\n }\n [data-kui-fx~=decode] {\n --kui-charset: binary;\n }\n [data-kui-fx~=depth-layer] {\n --kui-distance: 200px;\n --kui-parallax-duration: 600ms;\n --kui-parallax-delay: 0ms;\n --kui-parallax-ease: ease-out;\n }\n [data-kui-fx~=donut-sweep] {\n --kui-stroke-sweep-duration: 600ms;\n --kui-stroke-sweep-delay: 0ms;\n --kui-stroke-sweep-ease: ease-out;\n }\n [data-kui-fx~=dot-grid-drift] {\n --kui-ambient-gradient-duration: 16s;\n --kui-ambient-gradient-ease: linear;\n --kui-ambient-gradient-delay: 0ms;\n }\n [data-kui-fx~=drag-inertia] {\n --kui-inertia: true;\n }\n [data-kui-fx~=drag-x] {\n --kui-axis: x;\n }\n [data-kui-fx~=drag-y] {\n --kui-axis: y;\n }\n [data-kui-fx~=draw-signature] {\n --kui-path-draw-duration: 1600ms;\n --kui-path-draw-ease: ease-in-out;\n --kui-path-draw-delay: 0ms;\n }\n [data-kui-fx~=draw-stroke] {\n --kui-path-draw-duration: 800ms;\n --kui-path-draw-ease: ease-in-out;\n --kui-path-draw-delay: 0ms;\n }\n [data-kui-fx~=draw-underline] {\n --kui-path-draw-duration: 420ms;\n --kui-path-draw-delay: 0ms;\n --kui-path-draw-ease: ease-out;\n }\n [data-kui-fx~=drawer-slide] {\n --kui-drawer-slide-duration: 600ms;\n --kui-drawer-slide-delay: 0ms;\n --kui-drawer-slide-ease: ease-out;\n }\n [data-kui-fx~=dropdown-open] {\n --kui-panel-reveal-duration: 600ms;\n --kui-panel-reveal-delay: 0ms;\n --kui-panel-reveal-ease: ease-out;\n }\n [data-kui-fx~=duotone-hover] {\n --kui-media-filter-duration: 600ms;\n --kui-media-filter-delay: 0ms;\n --kui-media-filter-ease: ease-out;\n }\n [data-kui-fx~=elastic-pull] {\n --kui-return: true;\n --kui-bounds: 80;\n }\n [data-kui-fx~=expand-to-modal] {\n --kui-flip-scale: true;\n --kui-flip-container-duration: 500ms;\n --kui-flip-container-ease: ease-out;\n }\n [data-kui-fx~=fade-blur-in] {\n --kui-reveal-blur-duration: 600ms;\n --kui-reveal-blur-delay: 0ms;\n --kui-reveal-blur-ease: ease-out;\n }\n [data-kui-fx~=fade-blur-up] {\n --kui-reveal-blur-duration: 600ms;\n --kui-reveal-blur-delay: 0ms;\n --kui-reveal-blur-ease: ease-out;\n }\n [data-kui-fx~=fade-down] {\n --kui-reveal-duration: 600ms;\n --kui-reveal-delay: 0ms;\n --kui-reveal-ease: ease-out;\n }\n [data-kui-fx~=fade-in] {\n --kui-reveal-duration: 600ms;\n --kui-reveal-delay: 0ms;\n --kui-reveal-ease: ease-out;\n }\n [data-kui-fx~=fade-left] {\n --kui-reveal-duration: 600ms;\n --kui-reveal-delay: 0ms;\n --kui-reveal-ease: ease-out;\n }\n [data-kui-fx~=fade-out] {\n --kui-reveal-duration: 600ms;\n --kui-reveal-delay: 0ms;\n --kui-reveal-ease: ease-out;\n }\n [data-kui-fx~=fade-out-down] {\n --kui-reveal-duration: 600ms;\n --kui-reveal-delay: 0ms;\n --kui-reveal-ease: ease-out;\n }\n [data-kui-fx~=fade-out-left] {\n --kui-reveal-duration: 600ms;\n --kui-reveal-delay: 0ms;\n --kui-reveal-ease: ease-out;\n }\n [data-kui-fx~=fade-out-right] {\n --kui-reveal-duration: 600ms;\n --kui-reveal-delay: 0ms;\n --kui-reveal-ease: ease-out;\n }\n [data-kui-fx~=fade-out-up] {\n --kui-reveal-duration: 600ms;\n --kui-reveal-delay: 0ms;\n --kui-reveal-ease: ease-out;\n }\n [data-kui-fx~=fade-right] {\n --kui-reveal-duration: 600ms;\n --kui-reveal-delay: 0ms;\n --kui-reveal-ease: ease-out;\n }\n [data-kui-fx~=fade-up] {\n --kui-reveal-duration: 600ms;\n --kui-reveal-delay: 0ms;\n --kui-reveal-ease: ease-out;\n }\n [data-kui-fx~=flip-card] {\n --kui-card-toggle-duration: 700ms;\n --kui-card-toggle-ease: ease-in-out;\n }\n [data-kui-fx~=flip-filter] {\n --kui-flip-container-duration: 400ms;\n --kui-flip-container-ease: ease-out;\n }\n [data-kui-fx~=flip-in-x] {\n --kui-flip-3d-duration: 600ms;\n --kui-flip-3d-delay: 0ms;\n --kui-flip-3d-ease: ease-out;\n }\n [data-kui-fx~=flip-in-y] {\n --kui-flip-3d-duration: 600ms;\n --kui-flip-3d-delay: 0ms;\n --kui-flip-3d-ease: ease-out;\n }\n [data-kui-fx~=flip-out-x] {\n --kui-flip-3d-duration: 600ms;\n --kui-flip-3d-delay: 0ms;\n --kui-flip-3d-ease: ease-out;\n }\n [data-kui-fx~=flip-out-y] {\n --kui-flip-3d-duration: 600ms;\n --kui-flip-3d-delay: 0ms;\n --kui-flip-3d-ease: ease-out;\n }\n [data-kui-fx~=flip-reorder] {\n --kui-flip-container-duration: 400ms;\n --kui-flip-container-ease: ease-out;\n }\n [data-kui-fx~=flip-shuffle] {\n --kui-flip-container-duration: 400ms;\n --kui-flip-container-ease: ease-out;\n }\n [data-kui-fx~=flip-sort] {\n --kui-flip-container-duration: 400ms;\n --kui-flip-container-ease: ease-out;\n }\n [data-kui-fx~=float] {\n --kui-ambient-float-duration: 4s;\n --kui-ambient-float-delay: 0ms;\n --kui-ambient-float-ease: ease-in-out;\n }\n [data-kui-fx~=floating-shapes] {\n --kui-ambient-float-duration: 6s;\n --kui-distance: 10px;\n --kui-ambient-float-delay: 0ms;\n --kui-ambient-float-ease: ease-in-out;\n }\n [data-kui-fx~=focus-ring-grow] {\n --kui-focus-ring-duration: 600ms;\n --kui-focus-ring-delay: 0ms;\n --kui-focus-ring-ease: ease-out;\n }\n [data-kui-fx~=fold-panel] {\n --kui-from-angle: -90deg;\n --kui-flip-face-duration: 600ms;\n --kui-flip-face-delay: 0ms;\n --kui-flip-face-ease: ease-out;\n }\n [data-kui-fx~=gauge-sweep] {\n --kui-stroke-sweep-duration: 600ms;\n --kui-stroke-sweep-delay: 0ms;\n --kui-stroke-sweep-ease: ease-out;\n }\n [data-kui-fx~=glitch] {\n --kui-charset: symbols;\n }\n [data-kui-fx~=glow-pulse] {\n --kui-ambient-pulse-duration: 2.2s;\n --kui-ambient-pulse-delay: 0ms;\n --kui-ambient-pulse-ease: ease-in-out;\n }\n [data-kui-fx~=gradient-mesh] {\n --kui-ambient-gradient-duration: 10s;\n --kui-ambient-gradient-delay: 0ms;\n --kui-ambient-gradient-ease: ease-in-out;\n }\n [data-kui-fx~=gradient-rotate-border] {\n --kui-ambient-gradient-duration: 6s;\n --kui-ambient-gradient-ease: linear;\n --kui-ambient-gradient-delay: 0ms;\n }\n [data-kui-fx~=gradient-shimmer] {\n --kui-text-shimmer-duration: 600ms;\n --kui-text-shimmer-delay: 0ms;\n --kui-text-shimmer-ease: ease-out;\n }\n [data-kui-fx~=gradient-stroke] {\n --kui-path-draw-duration: 2400ms;\n --kui-path-draw-ease: ease-in-out;\n --kui-path-draw-delay: 0ms;\n }\n [data-kui-fx~=gradient-sweep] {\n --kui-text-gradient-sweep-duration: 600ms;\n --kui-text-gradient-sweep-delay: 0ms;\n --kui-text-gradient-sweep-ease: ease-out;\n }\n [data-kui-fx~=grayscale-hover] {\n --kui-media-filter-duration: 600ms;\n --kui-media-filter-delay: 0ms;\n --kui-media-filter-ease: ease-out;\n }\n [data-kui-fx~=grid-to-list] {\n --kui-flip-scale: true;\n --kui-flip-container-duration: 400ms;\n --kui-flip-container-ease: ease-out;\n }\n [data-kui-fx~=hamburger-to-x] {\n --kui-icon-toggle-duration: 260ms;\n --kui-icon-toggle-ease: ease-out;\n }\n [data-kui-fx~=heart-burst] {\n --kui-feedback-burst-duration: 700ms;\n --kui-pop-scale: 1.4;\n --kui-feedback-burst-delay: 0ms;\n --kui-feedback-burst-ease: var(--kui-ease-back-out, ease-out);\n }\n [data-kui-fx~=heart-fill] {\n --kui-shape-fill-duration: 420ms;\n --kui-shape-fill-delay: 0ms;\n --kui-shape-fill-ease: ease-out;\n }\n [data-kui-fx~=highlight-sweep] {\n --kui-sweep-color: gold;\n --kui-text-sweep-duration: 600ms;\n --kui-text-sweep-delay: 0ms;\n --kui-text-sweep-ease: ease-out;\n }\n [data-kui-fx~=icon-bounce] {\n --kui-icon-bounce-duration: 220ms;\n --kui-icon-bounce-ease: ease-out;\n }\n [data-kui-fx~=icon-morph] {\n --kui-path-morph-duration: 300ms;\n }\n [data-kui-fx~=icon-spin] {\n --kui-icon-spin-duration: 220ms;\n --kui-icon-spin-ease: ease-out;\n }\n [data-kui-fx~=icon-wiggle] {\n --kui-icon-wiggle-duration: 220ms;\n --kui-icon-wiggle-ease: ease-out;\n }\n [data-kui-fx~=image-parallax-frame] {\n --kui-media-parallax-frame-duration: 600ms;\n --kui-media-parallax-frame-delay: 0ms;\n --kui-media-parallax-frame-ease: ease-out;\n }\n [data-kui-fx~=ken-burns] {\n --kui-media-ken-burns-duration: 600ms;\n --kui-media-ken-burns-delay: 0ms;\n --kui-media-ken-burns-ease: ease-out;\n }\n [data-kui-fx~=ken-burns-out] {\n --kui-media-ken-burns-duration: 600ms;\n --kui-media-ken-burns-delay: 0ms;\n --kui-media-ken-burns-ease: ease-out;\n }\n [data-kui-fx~=lift] {\n --kui-lift-duration: 220ms;\n --kui-lift-ease: ease-out;\n }\n [data-kui-fx~=lift-shadow] {\n --kui-lift-shadow-duration: 220ms;\n --kui-lift-shadow-ease: ease-out;\n }\n [data-kui-fx~=lightbox-open] {\n --kui-media-lightbox-duration: 600ms;\n --kui-media-lightbox-delay: 0ms;\n --kui-media-lightbox-ease: ease-out;\n }\n [data-kui-fx~=line-grid-drift] {\n --kui-ambient-gradient-duration: 16s;\n --kui-ambient-gradient-ease: linear;\n --kui-ambient-gradient-delay: 0ms;\n }\n [data-kui-fx~=loading-bar] {\n --kui-bar-duration: 600ms;\n --kui-bar-delay: 0ms;\n --kui-bar-ease: ease-out;\n }\n [data-kui-fx~=logo-build] {\n --kui-logo-assemble-duration: 520ms;\n --kui-logo-assemble-ease: var(--kui-ease-back-out, ease-out);\n --kui-logo-assemble-delay: 0ms;\n }\n [data-kui-fx~=long-press] {\n --kui-pressable-duration: 500ms;\n }\n [data-kui-fx~=magnetic-snap] {\n --kui-strength: 0.6;\n --kui-radius: 160;\n }\n [data-kui-fx~=marquee] {\n --kui-text-marquee-duration: 600ms;\n --kui-text-marquee-delay: 0ms;\n --kui-text-marquee-ease: ease-out;\n }\n [data-kui-fx~=marquee-scroll-linked] {\n --kui-text-marquee-duration: 600ms;\n --kui-text-marquee-delay: 0ms;\n --kui-text-marquee-ease: ease-out;\n }\n [data-kui-fx~=mask-reveal] {\n --kui-media-mask-duration: 600ms;\n --kui-media-mask-delay: 0ms;\n --kui-media-mask-ease: ease-out;\n }\n [data-kui-fx~=masonry-reflow] {\n --kui-flip-container-duration: 400ms;\n --kui-flip-container-ease: ease-out;\n }\n [data-kui-fx~=mega-menu-drop] {\n --kui-panel-reveal-duration: 550ms;\n --kui-panel-reveal-delay: 0ms;\n --kui-panel-reveal-ease: ease-out;\n }\n [data-kui-fx~=menu-fullscreen] {\n --kui-menu-fullscreen-duration: 600ms;\n --kui-menu-fullscreen-delay: 0ms;\n --kui-menu-fullscreen-ease: ease-out;\n }\n [data-kui-fx~=menu-stagger-open] {\n --kui-nav-reveal-duration: 600ms;\n --kui-nav-reveal-delay: 0ms;\n --kui-nav-reveal-ease: ease-out;\n }\n [data-kui-fx~=noise-overlay] {\n --kui-ambient-gradient-duration: 650ms;\n --kui-ambient-gradient-ease: steps(6);\n --kui-ambient-gradient-delay: 0ms;\n }\n [data-kui-fx~=odometer-roll] {\n --kui-from: 0;\n --kui-to: 4820;\n --kui-count-odometer-duration: 1600ms;\n }\n [data-kui-fx~=orbit] {\n --kui-ambient-orbit-duration: 3.5s;\n --kui-ambient-orbit-delay: 0ms;\n --kui-ambient-orbit-ease: linear;\n }\n [data-kui-fx~=page-fade] {\n --kui-page-reveal-duration: 600ms;\n --kui-page-reveal-delay: 0ms;\n --kui-page-reveal-ease: ease-out;\n }\n [data-kui-fx~=page-slide] {\n --kui-page-reveal-duration: 600ms;\n --kui-page-reveal-delay: 0ms;\n --kui-page-reveal-ease: ease-out;\n }\n [data-kui-fx~=parallax-rotate] {\n --kui-parallax-rotate-duration: 600ms;\n --kui-parallax-rotate-delay: 0ms;\n --kui-parallax-rotate-ease: ease-out;\n }\n [data-kui-fx~=parallax-scale] {\n --kui-parallax-scale-duration: 600ms;\n --kui-parallax-scale-delay: 0ms;\n --kui-parallax-scale-ease: ease-out;\n }\n [data-kui-fx~=parallax-x] {\n --kui-parallax-duration: 600ms;\n --kui-parallax-delay: 0ms;\n --kui-parallax-ease: ease-out;\n }\n [data-kui-fx~=parallax-y] {\n --kui-parallax-duration: 600ms;\n --kui-parallax-delay: 0ms;\n --kui-parallax-ease: ease-out;\n }\n [data-kui-fx~=pin-section] {\n --kui-distance: 100vh;\n --kui-spacer: true;\n }\n [data-kui-fx~=pin-spacer] {\n --kui-spacer: true;\n }\n [data-kui-fx~=pin-until] {\n --kui-spacer: false;\n }\n [data-kui-fx~=play-to-pause] {\n --kui-icon-toggle-duration: 260ms;\n --kui-icon-toggle-ease: ease-out;\n }\n [data-kui-fx~=plus-to-minus] {\n --kui-icon-toggle-duration: 260ms;\n --kui-icon-toggle-ease: ease-out;\n }\n [data-kui-fx~=pop] {\n --kui-pop-duration: 220ms;\n --kui-pop-ease: ease-out;\n }\n [data-kui-fx~=pop-in] {\n --kui-from-scale: 0.6;\n --kui-scale-ease: var(--kui-ease-back-out, ease-out);\n --kui-scale-duration: 600ms;\n --kui-scale-delay: 0ms;\n }\n [data-kui-fx~=pop-out] {\n --kui-from-scale: 0.6;\n --kui-scale-ease: var(--kui-ease-back-in, ease-out);\n --kui-scale-duration: 600ms;\n --kui-scale-delay: 0ms;\n }\n [data-kui-fx~=progress-bar] {\n --kui-meter-bar-duration: 600ms;\n --kui-meter-bar-delay: 0ms;\n --kui-meter-bar-ease: ease-out;\n }\n [data-kui-fx~=progress-indeterminate] {\n --kui-feedback-progress-track-duration: 1.4s;\n --kui-feedback-progress-track-delay: 0ms;\n --kui-feedback-progress-track-ease: ease-in-out;\n }\n [data-kui-fx~=progress-ring] {\n --kui-stroke-sweep-duration: 600ms;\n --kui-stroke-sweep-delay: 0ms;\n --kui-stroke-sweep-ease: ease-out;\n }\n [data-kui-fx~=progress-segments] {\n --kui-meter-segments-duration: 600ms;\n --kui-meter-segments-delay: 0ms;\n --kui-meter-segments-ease: ease-out;\n }\n [data-kui-fx~=pull-to-refresh] {\n --kui-feedback-pull-duration: 900ms;\n --kui-feedback-pull-ease: ease-out;\n --kui-feedback-pull-delay: 0ms;\n }\n [data-kui-fx~=range-fill] {\n --kui-range-fill-duration: 400ms;\n --kui-range-fill-delay: 0ms;\n --kui-range-fill-ease: ease-out;\n }\n [data-kui-fx~=redaction-reveal] {\n --kui-redaction-reveal-duration: 600ms;\n --kui-redaction-reveal-delay: 0ms;\n --kui-redaction-reveal-ease: ease-out;\n }\n [data-kui-fx~=reveal-once] {\n --kui-reveal-duration: 600ms;\n --kui-reveal-delay: 0ms;\n --kui-reveal-ease: ease-out;\n }\n [data-kui-fx~=ripple] {\n --kui-feedback-ripple-duration: 600ms;\n --kui-feedback-ripple-delay: 0ms;\n --kui-feedback-ripple-ease: ease-out;\n }\n [data-kui-fx~=roll-in] {\n --kui-roll-duration: 600ms;\n --kui-roll-delay: 0ms;\n --kui-roll-ease: ease-out;\n }\n [data-kui-fx~=roll-out] {\n --kui-roll-duration: 600ms;\n --kui-roll-delay: 0ms;\n --kui-roll-ease: ease-out;\n }\n [data-kui-fx~=rotate-in] {\n --kui-rotate-duration: 600ms;\n --kui-rotate-delay: 0ms;\n --kui-rotate-ease: ease-out;\n }\n [data-kui-fx~=rotate-in-left] {\n --kui-from-angle: -45deg;\n --kui-rotate-duration: 600ms;\n --kui-rotate-delay: 0ms;\n --kui-rotate-ease: ease-out;\n }\n [data-kui-fx~=rotate-in-right] {\n --kui-from-angle: 45deg;\n --kui-rotate-duration: 600ms;\n --kui-rotate-delay: 0ms;\n --kui-rotate-ease: ease-out;\n }\n [data-kui-fx~=rotate-out] {\n --kui-rotate-duration: 600ms;\n --kui-rotate-delay: 0ms;\n --kui-rotate-ease: ease-out;\n }\n [data-kui-fx~=rubber-band] {\n --kui-return: true;\n --kui-bounds: 120;\n }\n [data-kui-fx~=saturate-hover] {\n --kui-media-filter-duration: 600ms;\n --kui-media-filter-delay: 0ms;\n --kui-media-filter-ease: ease-out;\n }\n [data-kui-fx~=scanline] {\n --kui-ambient-gradient-duration: 3.5s;\n --kui-ambient-gradient-ease: linear;\n --kui-ambient-gradient-delay: 0ms;\n }\n [data-kui-fx~=scramble] {\n --kui-charset: upper;\n }\n [data-kui-fx~=scroll-desaturate] {\n --kui-desaturate-duration: 600ms;\n --kui-desaturate-delay: 0ms;\n --kui-desaturate-ease: ease-out;\n }\n [data-kui-fx~=scroll-fade] {\n --kui-scroll-fade-duration: 600ms;\n --kui-scroll-fade-delay: 0ms;\n --kui-scroll-fade-ease: ease-out;\n }\n [data-kui-fx~=scroll-progress-bar] {\n --kui-progress-duration: 600ms;\n --kui-progress-delay: 0ms;\n --kui-progress-ease: ease-out;\n }\n [data-kui-fx~=scroll-progress-bar-y] {\n --kui-progress-duration: 600ms;\n --kui-progress-delay: 0ms;\n --kui-progress-ease: ease-out;\n }\n [data-kui-fx~=scroll-progress-ring] {\n --kui-progress-stroke-duration: 600ms;\n --kui-progress-stroke-delay: 0ms;\n --kui-progress-stroke-ease: ease-out;\n }\n [data-kui-fx~=scroll-skew] {\n --kui-skew-duration: 600ms;\n --kui-skew-delay: 0ms;\n --kui-skew-ease: ease-out;\n }\n [data-kui-fx~=scroll-snap-x] {\n --kui-axis: x;\n }\n [data-kui-fx~=scroll-snap-y] {\n --kui-axis: y;\n }\n [data-kui-fx~=scrollytelling-step] {\n --kui-steps: 4;\n }\n [data-kui-fx~=sequence-scrub] {\n --kui-spacer: true;\n }\n [data-kui-fx~=shake-error] {\n --kui-feedback-shake-duration: 500ms;\n --kui-feedback-shake-delay: 0ms;\n --kui-feedback-shake-ease: linear;\n }\n [data-kui-fx~=shine-sweep] {\n --kui-shine-sweep-duration: 220ms;\n --kui-shine-sweep-ease: ease-out;\n }\n [data-kui-fx~=skeleton-shimmer] {\n --kui-feedback-shimmer-duration: 1.6s;\n --kui-feedback-shimmer-delay: 0ms;\n --kui-feedback-shimmer-ease: linear;\n }\n [data-kui-fx~=skeleton-to-content] {\n --kui-feedback-fade-duration: 600ms;\n --kui-feedback-fade-delay: 0ms;\n --kui-feedback-fade-ease: ease-out;\n }\n [data-kui-fx~=slat-assemble] {\n --kui-slat-assemble-duration: 500ms;\n --kui-slat-assemble-delay: 0ms;\n --kui-slat-assemble-ease: ease-out;\n }\n [data-kui-fx~=slide-block-end] {\n --kui-distance: 100px;\n --kui-from-opacity: 1;\n --kui-reveal-duration: 600ms;\n --kui-reveal-delay: 0ms;\n --kui-reveal-ease: ease-out;\n }\n [data-kui-fx~=slide-block-start] {\n --kui-distance: 100px;\n --kui-from-opacity: 1;\n --kui-reveal-duration: 600ms;\n --kui-reveal-delay: 0ms;\n --kui-reveal-ease: ease-out;\n }\n [data-kui-fx~=slide-down] {\n --kui-distance: 100px;\n --kui-from-opacity: 1;\n --kui-reveal-duration: 600ms;\n --kui-reveal-delay: 0ms;\n --kui-reveal-ease: ease-out;\n }\n [data-kui-fx~=slide-inline-end] {\n --kui-distance: 100px;\n --kui-from-opacity: 1;\n --kui-reveal-duration: 600ms;\n --kui-reveal-delay: 0ms;\n --kui-reveal-ease: ease-out;\n }\n [data-kui-fx~=slide-inline-start] {\n --kui-distance: 100px;\n --kui-from-opacity: 1;\n --kui-reveal-duration: 600ms;\n --kui-reveal-delay: 0ms;\n --kui-reveal-ease: ease-out;\n }\n [data-kui-fx~=slide-left] {\n --kui-distance: 100px;\n --kui-from-opacity: 1;\n --kui-reveal-duration: 600ms;\n --kui-reveal-delay: 0ms;\n --kui-reveal-ease: ease-out;\n }\n [data-kui-fx~=slide-out-down] {\n --kui-distance: 100px;\n --kui-from-opacity: 1;\n --kui-reveal-duration: 600ms;\n --kui-reveal-delay: 0ms;\n --kui-reveal-ease: ease-out;\n }\n [data-kui-fx~=slide-out-left] {\n --kui-distance: 100px;\n --kui-from-opacity: 1;\n --kui-reveal-duration: 600ms;\n --kui-reveal-delay: 0ms;\n --kui-reveal-ease: ease-out;\n }\n [data-kui-fx~=slide-out-right] {\n --kui-distance: 100px;\n --kui-from-opacity: 1;\n --kui-reveal-duration: 600ms;\n --kui-reveal-delay: 0ms;\n --kui-reveal-ease: ease-out;\n }\n [data-kui-fx~=slide-out-up] {\n --kui-distance: 100px;\n --kui-from-opacity: 1;\n --kui-reveal-duration: 600ms;\n --kui-reveal-delay: 0ms;\n --kui-reveal-ease: ease-out;\n }\n [data-kui-fx~=slide-right] {\n --kui-distance: 100px;\n --kui-from-opacity: 1;\n --kui-reveal-duration: 600ms;\n --kui-reveal-delay: 0ms;\n --kui-reveal-ease: ease-out;\n }\n [data-kui-fx~=slide-up] {\n --kui-distance: 100px;\n --kui-from-opacity: 1;\n --kui-reveal-duration: 600ms;\n --kui-reveal-delay: 0ms;\n --kui-reveal-ease: ease-out;\n }\n [data-kui-fx~=snap-back] {\n --kui-return: true;\n --kui-stiffness: 260;\n }\n [data-kui-fx~=sparkline-draw] {\n --kui-stroke-sweep-duration: 600ms;\n --kui-stroke-sweep-delay: 0ms;\n --kui-stroke-sweep-ease: ease-out;\n }\n [data-kui-fx~=spinner] {\n --kui-feedback-spin-duration: 900ms;\n --kui-feedback-spin-delay: 0ms;\n --kui-feedback-spin-ease: linear;\n }\n [data-kui-fx~=spinner-dots] {\n --kui-feedback-dot-pulse-duration: 1.2s;\n --kui-feedback-dot-pulse-delay: 0ms;\n --kui-feedback-dot-pulse-ease: ease-in-out;\n }\n [data-kui-fx~=spinner-ring] {\n --kui-feedback-spin-duration: 900ms;\n --kui-feedback-spin-delay: 0ms;\n --kui-feedback-spin-ease: linear;\n }\n [data-kui-fx~=split-chars] {\n --kui-unit: chars;\n --kui-direction: fade;\n --kui-split-text-duration: 500ms;\n --kui-split-text-delay: 0ms;\n --kui-split-text-ease: ease-out;\n }\n [data-kui-fx~=split-flap] {\n --kui-split-flap-duration: 220ms;\n --kui-split-flap-ease: ease-out;\n }\n [data-kui-fx~=split-lines] {\n --kui-unit: lines;\n --kui-direction: fade;\n --kui-split-text-duration: 500ms;\n --kui-split-text-delay: 0ms;\n --kui-split-text-ease: ease-out;\n }\n [data-kui-fx~=split-words] {\n --kui-unit: words;\n --kui-direction: fade;\n --kui-split-text-duration: 500ms;\n --kui-split-text-delay: 0ms;\n --kui-split-text-ease: ease-out;\n }\n [data-kui-fx~=spotlight-follow] {\n --kui-ambient-gradient-duration: 9s;\n --kui-ambient-gradient-delay: 0ms;\n --kui-ambient-gradient-ease: ease-in-out;\n }\n [data-kui-fx~=stacking-cards] {\n --kui-spacer: false;\n }\n [data-kui-fx~=star-rating-fill] {\n --kui-meter-stars-duration: 600ms;\n --kui-meter-stars-delay: 0ms;\n --kui-meter-stars-ease: ease-out;\n }\n [data-kui-fx~=starfield] {\n --kui-ambient-gradient-duration: 40s;\n --kui-ambient-gradient-ease: linear;\n --kui-ambient-gradient-delay: 0ms;\n }\n [data-kui-fx~=step-progress] {\n --kui-step-progress-duration: 400ms;\n --kui-step-progress-delay: 0ms;\n --kui-step-progress-ease: ease-out;\n }\n [data-kui-fx~=strength-meter] {\n --kui-strength-meter-duration: 400ms;\n --kui-strength-meter-delay: 0ms;\n --kui-strength-meter-ease: ease-out;\n }\n [data-kui-fx~=submit-to-spinner-to-check] {\n --kui-submit-flow-duration: 400ms;\n --kui-submit-flow-delay: 0ms;\n --kui-submit-flow-ease: ease-out;\n }\n [data-kui-fx~=swing-in] {\n --kui-from-angle: -15deg;\n --kui-rotate-ease: var(--kui-ease-back-out, ease-out);\n --kui-rotate-duration: 600ms;\n --kui-rotate-delay: 0ms;\n }\n [data-kui-fx~=swipe-x] {\n --kui-axis: x;\n }\n [data-kui-fx~=tab-indicator-slide] {\n --kui-flip-indicator-duration: 300ms;\n --kui-flip-indicator-ease: ease-out;\n }\n [data-kui-fx~=text-3d-extrude] {\n --kui-text-3d-extrude-duration: 600ms;\n --kui-text-3d-extrude-delay: 0ms;\n --kui-text-3d-extrude-ease: ease-out;\n }\n [data-kui-fx~=text-jitter] {\n --kui-motion: jitter;\n }\n [data-kui-fx~=text-outline-fill] {\n --kui-text-outline-fill-duration: 600ms;\n --kui-text-outline-fill-delay: 0ms;\n --kui-text-outline-fill-ease: ease-out;\n }\n [data-kui-fx~=text-reveal-down] {\n --kui-unit: words;\n --kui-direction: down;\n --kui-split-text-duration: 500ms;\n --kui-split-text-delay: 0ms;\n --kui-split-text-ease: ease-out;\n }\n [data-kui-fx~=text-reveal-mask] {\n --kui-unit: lines;\n --kui-direction: mask;\n --kui-split-text-duration: 500ms;\n --kui-split-text-delay: 0ms;\n --kui-split-text-ease: ease-out;\n }\n [data-kui-fx~=text-reveal-up] {\n --kui-unit: words;\n --kui-direction: up;\n --kui-split-text-duration: 500ms;\n --kui-split-text-delay: 0ms;\n --kui-split-text-ease: ease-out;\n }\n [data-kui-fx~=text-wave] {\n --kui-motion: wave;\n }\n [data-kui-fx~=throwable] {\n --kui-inertia: true;\n --kui-damping: 18;\n }\n [data-kui-fx~=toast-slide-in] {\n --kui-feedback-toast-duration: 420ms;\n --kui-feedback-toast-delay: 0ms;\n --kui-feedback-toast-ease: var(--kui-ease-back-out, ease-out);\n }\n [data-kui-fx~=toast-slide-out] {\n --kui-feedback-toast-ease: ease-in;\n --kui-feedback-toast-duration: 420ms;\n --kui-feedback-toast-delay: 0ms;\n }\n [data-kui-fx~=typewriter] {\n --kui-loop: false;\n }\n [data-kui-fx~=typewriter-loop] {\n --kui-loop: true;\n }\n [data-kui-fx~=underline-center] {\n --kui-underline-center-duration: 220ms;\n --kui-underline-center-ease: ease-out;\n }\n [data-kui-fx~=underline-draw] {\n --kui-text-sweep-duration: 600ms;\n --kui-text-sweep-delay: 0ms;\n --kui-text-sweep-ease: ease-out;\n }\n [data-kui-fx~=underline-slide] {\n --kui-underline-slide-duration: 220ms;\n --kui-underline-slide-ease: ease-out;\n }\n [data-kui-fx~=validate-check] {\n --kui-validate-check-duration: 600ms;\n --kui-validate-check-delay: 0ms;\n --kui-validate-check-ease: ease-out;\n }\n [data-kui-fx~=validate-shake] {\n --kui-validate-shake-duration: 600ms;\n --kui-validate-shake-delay: 0ms;\n --kui-validate-shake-ease: ease-out;\n }\n [data-kui-fx~=var-slant] {\n --kui-var-slant-duration: 600ms;\n --kui-var-slant-delay: 0ms;\n --kui-var-slant-ease: ease-out;\n }\n [data-kui-fx~=var-weight] {\n --kui-var-weight-duration: 600ms;\n --kui-var-weight-delay: 0ms;\n --kui-var-weight-ease: ease-out;\n }\n [data-kui-fx~=var-width] {\n --kui-var-width-duration: 600ms;\n --kui-var-width-delay: 0ms;\n --kui-var-width-ease: ease-out;\n }\n [data-kui-fx~=wave-blob] {\n --kui-ambient-gradient-duration: 12s;\n --kui-ambient-gradient-delay: 0ms;\n --kui-ambient-gradient-ease: ease-in-out;\n }\n [data-kui-fx~=wipe-circle] {\n --kui-media-wipe-duration: 600ms;\n --kui-media-wipe-delay: 0ms;\n --kui-media-wipe-ease: ease-out;\n }\n [data-kui-fx~=wipe-diagonal] {\n --kui-media-wipe-duration: 600ms;\n --kui-media-wipe-delay: 0ms;\n --kui-media-wipe-ease: ease-out;\n }\n [data-kui-fx~=wipe-down] {\n --kui-media-wipe-duration: 600ms;\n --kui-media-wipe-delay: 0ms;\n --kui-media-wipe-ease: ease-out;\n }\n [data-kui-fx~=wipe-left] {\n --kui-media-wipe-duration: 600ms;\n --kui-media-wipe-delay: 0ms;\n --kui-media-wipe-ease: ease-out;\n }\n [data-kui-fx~=wipe-right] {\n --kui-media-wipe-duration: 600ms;\n --kui-media-wipe-delay: 0ms;\n --kui-media-wipe-ease: ease-out;\n }\n [data-kui-fx~=wipe-up] {\n --kui-media-wipe-duration: 600ms;\n --kui-media-wipe-delay: 0ms;\n --kui-media-wipe-ease: ease-out;\n }\n [data-kui-fx~=wobble] {\n --kui-feedback-wobble-duration: 600ms;\n --kui-feedback-wobble-ease: ease-in-out;\n --kui-feedback-wobble-delay: 0ms;\n }\n [data-kui-fx~=zoom-in] {\n --kui-scale-duration: 600ms;\n --kui-scale-delay: 0ms;\n --kui-scale-ease: ease-out;\n }\n [data-kui-fx~=zoom-in-down] {\n --kui-scale-move-duration: 600ms;\n --kui-scale-move-delay: 0ms;\n --kui-scale-move-ease: ease-out;\n }\n [data-kui-fx~=zoom-in-up] {\n --kui-scale-move-duration: 600ms;\n --kui-scale-move-delay: 0ms;\n --kui-scale-move-ease: ease-out;\n }\n [data-kui-fx~=zoom-out] {\n --kui-scale-duration: 600ms;\n --kui-scale-delay: 0ms;\n --kui-scale-ease: ease-out;\n }\n}\n@layer kui.cloak {\n html[data-kui-cloak] [data-kui~=back-in-down]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=back-in-up]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=blur-in]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=blur-up]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=bounce-in]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=bounce-in-down]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=bounce-in-up]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=card-flip-x]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=card-flip-y]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=chart-bar-grow]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=curtain-reveal]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=fade-blur-in]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=fade-blur-up]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=fade-down]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=fade-in]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=fade-left]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=fade-right]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=fade-up]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=flip-in-x]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=flip-in-y]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=fold-panel]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=loading-bar]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=mask-reveal]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=pop-in]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=progress-bar]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=reveal-once]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=roll-in]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=rotate-in]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=rotate-in-left]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=rotate-in-right]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=slat-assemble]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=slide-block-end]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=slide-block-start]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=slide-down]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=slide-inline-end]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=slide-inline-start]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=slide-left]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=slide-right]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=slide-up]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=swing-in]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=text-reveal-down]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=text-reveal-mask]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=text-reveal-up]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=wipe-circle]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=wipe-diagonal]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=wipe-down]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=wipe-left]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=wipe-right]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=wipe-up]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=zoom-in]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=zoom-in-down]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=zoom-in-up]:not([data-kui-state]) {\n opacity: 0;\n animation: kui-cloak-release 1ms linear 2s forwards;\n }\n @keyframes kui-cloak-release {\n to {\n opacity: 1;\n }\n }\n @media (prefers-reduced-motion: reduce) {\n html[data-kui-cloak] [data-kui~=back-in-down]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=back-in-up]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=blur-in]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=blur-up]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=bounce-in]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=bounce-in-down]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=bounce-in-up]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=card-flip-x]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=card-flip-y]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=chart-bar-grow]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=curtain-reveal]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=fade-blur-in]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=fade-blur-up]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=fade-down]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=fade-in]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=fade-left]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=fade-right]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=fade-up]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=flip-in-x]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=flip-in-y]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=fold-panel]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=loading-bar]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=mask-reveal]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=pop-in]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=progress-bar]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=reveal-once]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=roll-in]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=rotate-in]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=rotate-in-left]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=rotate-in-right]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=slat-assemble]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=slide-block-end]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=slide-block-start]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=slide-down]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=slide-inline-end]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=slide-inline-start]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=slide-left]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=slide-right]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=slide-up]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=swing-in]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=text-reveal-down]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=text-reveal-mask]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=text-reveal-up]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=wipe-circle]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=wipe-diagonal]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=wipe-down]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=wipe-left]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=wipe-right]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=wipe-up]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=zoom-in]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=zoom-in-down]:not([data-kui-state]),\n html[data-kui-cloak] [data-kui~=zoom-in-up]:not([data-kui-state]) {\n opacity: 1;\n animation: none;\n }\n }\n}\n\n/* src/css/entrance.css */\n@layer kui.effects {\n @keyframes kui-in {\n from {\n opacity: var(--kui-from-opacity, 0);\n }\n }\n @keyframes kui-out {\n to {\n opacity: 0;\n }\n }\n @keyframes kui-in-up {\n from {\n opacity: var(--kui-from-opacity, 0);\n translate: 0 var(--kui-distance, 24px);\n }\n }\n @keyframes kui-in-down {\n from {\n opacity: var(--kui-from-opacity, 0);\n translate: 0 calc(var(--kui-distance, 24px) * -1);\n }\n }\n @keyframes kui-in-left {\n from {\n opacity: var(--kui-from-opacity, 0);\n translate: var(--kui-distance, 24px) 0;\n }\n }\n @keyframes kui-in-right {\n from {\n opacity: var(--kui-from-opacity, 0);\n translate: calc(var(--kui-distance, 24px) * -1) 0;\n }\n }\n @keyframes kui-out-up {\n to {\n opacity: 0;\n translate: 0 calc(var(--kui-distance, 24px) * -1);\n }\n }\n @keyframes kui-out-down {\n to {\n opacity: 0;\n translate: 0 var(--kui-distance, 24px);\n }\n }\n @keyframes kui-out-left {\n to {\n opacity: 0;\n translate: calc(var(--kui-distance, 24px) * -1) 0;\n }\n }\n @keyframes kui-out-right {\n to {\n opacity: 0;\n translate: var(--kui-distance, 24px) 0;\n }\n }\n @keyframes kui-in-inline-start {\n from {\n opacity: var(--kui-from-opacity, 0);\n translate: calc(var(--kui-distance, 24px) * var(--kui-dir, 1)) 0;\n }\n }\n @keyframes kui-in-inline-end {\n from {\n opacity: var(--kui-from-opacity, 0);\n translate: calc(var(--kui-distance, 24px) * var(--kui-dir, 1) * -1) 0;\n }\n }\n [data-kui-state=ready] {\n --kui-distance: 0px !important;\n }\n @keyframes kui-zoom-in {\n from {\n scale: var(--kui-from-scale, 0.92);\n }\n }\n @keyframes kui-zoom-out {\n to {\n scale: var(--kui-from-scale, 0.92);\n }\n }\n @keyframes kui-zoom-in-up {\n from {\n scale: var(--kui-from-scale, 0.92);\n translate: 0 var(--kui-distance, 24px);\n }\n }\n @keyframes kui-zoom-in-down {\n from {\n scale: var(--kui-from-scale, 0.92);\n translate: 0 calc(var(--kui-distance, 24px) * -1);\n }\n }\n @keyframes kui-flip-in-x {\n from {\n transform: perspective(var(--kui-perspective, 1200px)) rotateX(var(--kui-from-angle, 90deg));\n }\n }\n @keyframes kui-flip-in-y {\n from {\n transform: perspective(var(--kui-perspective, 1200px)) rotateY(var(--kui-from-angle, 90deg));\n }\n }\n @keyframes kui-flip-out-x {\n to {\n transform: perspective(var(--kui-perspective, 1200px)) rotateX(var(--kui-from-angle, 90deg));\n }\n }\n @keyframes kui-flip-out-y {\n to {\n transform: perspective(var(--kui-perspective, 1200px)) rotateY(var(--kui-from-angle, 90deg));\n }\n }\n @keyframes kui-rotate-in {\n from {\n rotate: var(--kui-from-angle, -8deg);\n }\n }\n @keyframes kui-rotate-out {\n to {\n rotate: var(--kui-from-angle, -8deg);\n }\n }\n @keyframes kui-swing-in {\n from {\n rotate: var(--kui-from-angle, -15deg);\n }\n }\n @keyframes kui-roll-in {\n from {\n rotate: var(--kui-from-angle, -120deg);\n translate: calc(var(--kui-distance, 24px) * -1) 0;\n }\n }\n @keyframes kui-roll-out {\n to {\n rotate: var(--kui-from-angle, -120deg);\n translate: var(--kui-distance, 24px) 0;\n }\n }\n @keyframes kui-blur-in {\n from {\n filter: blur(var(--kui-blur, 12px));\n }\n }\n @keyframes kui-blur-out {\n to {\n filter: blur(var(--kui-blur, 12px));\n }\n }\n @keyframes kui-fade-blur-up {\n from {\n opacity: var(--kui-from-opacity, 0);\n translate: 0 var(--kui-distance, 24px);\n filter: blur(var(--kui-blur, 12px));\n }\n }\n @keyframes kui-fade-blur-in {\n from {\n opacity: var(--kui-from-opacity, 0);\n filter: blur(var(--kui-blur, 12px));\n }\n }\n [data-kui-fx*=flip-] {\n transform-style: preserve-3d;\n }\n [data-kui-fx~=flip-in-x],\n [data-kui-fx~=flip-in-y],\n [data-kui-fx~=flip-out-x],\n [data-kui-fx~=flip-out-y] {\n perspective: var(--kui-perspective, 1200px);\n }\n [data-kui-fx~=flip-in-x][data-kui-state=ready],\n [data-kui-fx~=flip-in-y][data-kui-state=ready] {\n --kui-from-angle: 0deg !important;\n opacity: 0 !important;\n }\n}\n\n/* src/css/scroll.css */\n@layer kui.effects {\n @keyframes kui-parallax-y {\n from {\n translate: 0 calc(var(--kui-distance, 100px) * -1);\n }\n to {\n translate: 0 var(--kui-distance, 100px);\n }\n }\n @keyframes kui-parallax-x {\n from {\n translate: calc(var(--kui-distance, 100px) * -1) 0;\n }\n to {\n translate: var(--kui-distance, 100px) 0;\n }\n }\n @keyframes kui-parallax-scale {\n from {\n scale: var(--kui-from-scale, 1);\n }\n to {\n scale: var(--kui-to-scale, 1.2);\n }\n }\n @keyframes kui-parallax-rotate {\n from {\n rotate: var(--kui-from-angle, 0deg);\n }\n to {\n rotate: var(--kui-to-angle, 12deg);\n }\n }\n @keyframes kui-scroll-fade {\n from {\n opacity: var(--kui-from-opacity, 0);\n }\n to {\n opacity: 1;\n }\n }\n @keyframes kui-desaturate {\n from {\n filter: grayscale(var(--kui-from-grayscale, 100%));\n }\n to {\n filter: grayscale(var(--kui-to-grayscale, 0%));\n }\n }\n @keyframes kui-scroll-skew {\n from {\n transform: skewY(var(--kui-from-skew, 8deg));\n }\n to {\n transform: skewY(var(--kui-to-skew, 0deg));\n }\n }\n @keyframes kui-progress-x {\n from {\n scale: 0 1;\n }\n to {\n scale: 1 1;\n }\n }\n @keyframes kui-progress-y {\n from {\n scale: 1 0;\n }\n to {\n scale: 1 1;\n }\n }\n @keyframes kui-progress-ring {\n from {\n stroke-dashoffset: var(--kui-path-length, 100);\n }\n to {\n stroke-dashoffset: 0;\n }\n }\n [data-kui-fx~=scroll-progress-bar] {\n transform-origin: left center;\n }\n [data-kui-fx~=scroll-progress-ring] {\n stroke-dasharray: var(--kui-path-length, 100);\n }\n [data-kui-fx~=sequence-scrub]:has(> [data-kui-step-state]),\n [data-kui-fx~=video-scrub]:has(> [data-kui-step-state]),\n .kui-frame-stack {\n position: relative;\n }\n [data-kui-fx~=sequence-scrub] > [data-kui-step-state],\n [data-kui-fx~=video-scrub] > [data-kui-step-state],\n .kui-frame-stack > [data-kui-step-state] {\n position: absolute;\n inset: 0;\n width: 100%;\n height: 100%;\n object-fit: cover;\n opacity: 0;\n }\n [data-kui-fx~=sequence-scrub] > [data-kui-step-state=active],\n [data-kui-fx~=video-scrub] > [data-kui-step-state=active],\n .kui-frame-stack > [data-kui-step-state=active] {\n opacity: 1;\n }\n @supports (animation-timeline: view()) {\n [data-kui-timeline] {\n animation-range: var(--kui-range, entry 0% cover 60%);\n }\n }\n}\n\n/* src/css/three-d.css */\n@layer kui.effects {\n @keyframes kui-card-flip-y {\n to {\n transform: perspective(var(--kui-perspective, 1200px)) rotateY(var(--kui-from-angle, 180deg));\n }\n }\n @keyframes kui-card-flip-x {\n to {\n transform: perspective(var(--kui-perspective, 1200px)) rotateX(var(--kui-from-angle, 180deg));\n }\n }\n @keyframes kui-cube-rotate {\n to {\n transform: perspective(var(--kui-perspective, 1200px)) rotateY(var(--kui-from-angle, 90deg));\n }\n }\n @keyframes kui-book-page-turn {\n to {\n transform: perspective(var(--kui-perspective, 1200px)) rotateY(var(--kui-from-angle, -160deg));\n }\n }\n @keyframes kui-fold-panel {\n from {\n transform: perspective(var(--kui-perspective, 1200px)) rotateX(var(--kui-from-angle, -90deg));\n }\n }\n [data-kui-fx~=card-flip-x],\n [data-kui-fx~=card-flip-y],\n [data-kui-fx~=cube-rotate],\n [data-kui-fx~=book-page-turn],\n [data-kui-fx~=fold-panel] {\n transform-style: preserve-3d;\n perspective: var(--kui-perspective, 1200px);\n }\n [data-kui-fx~=card-flip-x]:not(:has(> :nth-child(2))),\n [data-kui-fx~=card-flip-y]:not(:has(> :nth-child(2))) {\n --kui-from-angle: 360deg;\n }\n [data-kui-fx~=card-flip-x]:has(> :nth-child(2)),\n [data-kui-fx~=card-flip-y]:has(> :nth-child(2)) {\n display: grid;\n }\n [data-kui-fx~=card-flip-x]:has(> :nth-child(2)) > :first-child,\n [data-kui-fx~=card-flip-x]:has(> :nth-child(2)) > :nth-child(2),\n [data-kui-fx~=card-flip-y]:has(> :nth-child(2)) > :first-child,\n [data-kui-fx~=card-flip-y]:has(> :nth-child(2)) > :nth-child(2) {\n grid-area: 1 / 1;\n backface-visibility: hidden;\n }\n [data-kui-fx~=card-flip-x]:has(> :nth-child(2)) > :nth-child(2) {\n rotate: x 180deg;\n }\n [data-kui-fx~=card-flip-y]:has(> :nth-child(2)) > :nth-child(2) {\n rotate: y 180deg;\n }\n [data-kui-fx~=book-page-turn] {\n transform-origin: left center;\n }\n [data-kui-fx~=fold-panel] {\n transform-origin: top center;\n }\n [data-kui-fx~=fold-panel][data-kui-state=ready] {\n --kui-from-angle: 0deg !important;\n opacity: 0 !important;\n }\n @keyframes kui-page-fade {\n from {\n opacity: 0;\n }\n }\n @keyframes kui-page-slide {\n from {\n opacity: 0;\n translate: 0 var(--kui-distance, 40px);\n }\n }\n @keyframes kui-curtain-wipe {\n from {\n clip-path: inset(0 0 100% 0);\n }\n to {\n clip-path: inset(0 0 0 0);\n }\n }\n @keyframes kui-loading-bar {\n from {\n scale: var(--kui-bar-from, 0) 1;\n }\n }\n [data-kui-fx~=loading-bar] {\n transform-origin: left center;\n }\n [data-kui-fx~=loading-bar][data-kui-state=ready] {\n --kui-bar-from: 1 !important;\n opacity: 0 !important;\n }\n [data-kui-fx~=flip-card] {\n display: grid;\n perspective: var(--kui-perspective, 1600px);\n }\n [data-kui-fx~=flip-card] > .kui-face-front,\n [data-kui-fx~=flip-card] > .kui-face-back {\n grid-area: 1 / 1;\n backface-visibility: hidden;\n transition: rotate var(--kui-card-toggle-duration, 700ms) var(--kui-card-toggle-ease, ease-in-out);\n }\n [data-kui-fx~=flip-card] > .kui-face-front {\n rotate: y 0deg;\n }\n [data-kui-fx~=flip-card] > .kui-face-back {\n rotate: y 180deg;\n }\n [data-kui-fx~=flip-card]:has(> .kui-flip-control[aria-pressed=true]) > .kui-face-front {\n rotate: y -180deg;\n }\n [data-kui-fx~=flip-card]:has(> .kui-flip-control[aria-pressed=true]) > .kui-face-back {\n rotate: y 0deg;\n }\n [data-kui~=flip-card] {\n display: grid;\n perspective: var(--kui-perspective, 1600px);\n }\n [data-kui~=flip-card] > .kui-face-front,\n [data-kui~=flip-card] > .kui-face-back {\n grid-area: 1 / 1;\n backface-visibility: hidden;\n }\n [data-kui~=flip-card] > .kui-face-front {\n rotate: y 0deg;\n }\n [data-kui~=flip-card] > .kui-face-back {\n rotate: y 180deg;\n }\n}\n\n/* src/css/media.css */\n@layer kui.effects {\n @keyframes kui-wipe-up {\n from {\n clip-path: inset(100% 0 0);\n }\n to {\n clip-path: inset(0 0 0);\n }\n }\n @keyframes kui-wipe-down {\n from {\n clip-path: inset(0 0 100%);\n }\n to {\n clip-path: inset(0 0 0);\n }\n }\n @keyframes kui-wipe-left {\n from {\n clip-path: inset(0 100% 0 0);\n }\n to {\n clip-path: inset(0 0 0 0);\n }\n }\n @keyframes kui-wipe-right {\n from {\n clip-path: inset(0 0 0 100%);\n }\n to {\n clip-path: inset(0 0 0 0);\n }\n }\n @keyframes kui-wipe-circle {\n from {\n clip-path: circle(0 at 50% 50%);\n }\n to {\n clip-path: circle(75% at 50% 50%);\n }\n }\n @keyframes kui-wipe-diagonal {\n from {\n clip-path: polygon(0 0, 0 0, 0 0);\n }\n to {\n clip-path: polygon(0 0, 200% 0, 0 200%);\n }\n }\n @keyframes kui-curtain-reveal {\n from {\n clip-path: inset(0 50%);\n }\n to {\n clip-path: inset(0 0);\n }\n }\n @keyframes kui-before-after-wipe {\n from {\n clip-path: inset(0 100% 0 0);\n }\n to {\n clip-path: inset(0 0 0 0);\n }\n }\n @keyframes kui-mask-reveal {\n from {\n mask-position: 100% 0;\n }\n to {\n mask-position: 0 0;\n }\n }\n [data-kui-fx~=mask-reveal] {\n mask-image:\n linear-gradient(\n 90deg,\n #000 0 45%,\n transparent 55% 100%);\n mask-size: 220% 100%;\n }\n @keyframes kui-ken-burns {\n from {\n scale: 1;\n translate: 0 0;\n }\n to {\n scale: var(--kui-to-scale, 1.12);\n translate: var(--kui-distance, 24px) calc(var(--kui-distance, 24px) * -0.5);\n }\n }\n @keyframes kui-ken-burns-out {\n from {\n scale: var(--kui-to-scale, 1.12);\n translate: calc(var(--kui-distance, 24px) * -1) 0;\n }\n to {\n scale: 1;\n translate: 0 0;\n }\n }\n @keyframes kui-blur-up {\n from {\n translate: 0 var(--kui-distance, 24px);\n filter: blur(var(--kui-blur, 16px));\n }\n to {\n translate: 0 0;\n filter: blur(0);\n }\n }\n @keyframes kui-duotone-hover {\n from {\n filter: grayscale(1) sepia(0.7) hue-rotate(330deg) saturate(2);\n }\n to {\n filter: none;\n }\n }\n @keyframes kui-grayscale-hover {\n from {\n filter: grayscale(1);\n }\n to {\n filter: grayscale(0);\n }\n }\n @keyframes kui-saturate-hover {\n from {\n filter: saturate(0.45);\n }\n to {\n filter: saturate(1.35);\n }\n }\n @keyframes kui-image-parallax-frame {\n from {\n translate: 0 calc(var(--kui-distance, 24px) * -1);\n }\n to {\n translate: 0 var(--kui-distance, 24px);\n }\n }\n @keyframes kui-lightbox-open {\n from {\n opacity: 0;\n scale: var(--kui-from-scale, 0.92);\n }\n to {\n opacity: 1;\n scale: 1;\n }\n }\n @media (pointer: coarse) {\n [data-kui-fx~=duotone-hover]:active,\n [data-kui-fx~=grayscale-hover]:active,\n [data-kui-fx~=saturate-hover]:active {\n filter: none;\n }\n }\n .kui-slat-stage {\n position: absolute;\n overflow: clip;\n }\n .kui-slat-item {\n position: absolute;\n inset: 0;\n background-repeat: no-repeat;\n background-size: 100% 100%;\n animation-duration: var(--kui-duration, 500ms);\n animation-delay: calc(var(--kui-delay, 0ms) + var(--kui-i, 0) * var(--kui-stagger, 60ms));\n animation-timing-function: var(--kui-ease, ease-out);\n animation-fill-mode: both;\n }\n .kui-slat-stage.kui-slat-animating .kui-slat-item {\n will-change: transform;\n }\n .kui-slat-item:nth-child(odd) {\n --kui-slat-sign: -1;\n }\n .kui-slat-item:nth-child(even) {\n --kui-slat-sign: 1;\n }\n .kui-slat-stage[data-kui-slat-fold=true] {\n perspective: 1200px;\n }\n .kui-slat-stage:not([data-kui-slat-fold=true]) .kui-slat-item {\n animation-name: kui-slat-assemble;\n }\n .kui-slat-stage[data-kui-slat-fold=true] .kui-slat-item {\n animation-name: kui-slat-assemble-fold;\n }\n @keyframes kui-slat-assemble {\n from {\n opacity: 0;\n translate: calc(var(--kui-slat-sign, 1) * var(--kui-slat-dx, 0) * 38%) calc(var(--kui-slat-sign, 1) * var(--kui-slat-dy, 1) * 38%);\n }\n 12% {\n opacity: 1;\n }\n to {\n opacity: 1;\n translate: 0 0;\n }\n }\n @keyframes kui-slat-assemble-fold {\n from {\n opacity: 0;\n translate: calc(var(--kui-slat-sign, 1) * var(--kui-slat-dx, 0) * 38%) calc(var(--kui-slat-sign, 1) * var(--kui-slat-dy, 1) * 38%);\n rotate: var(--kui-slat-dx, 0) var(--kui-slat-dy, 1) 0 calc(var(--kui-slat-sign, 1) * 38deg);\n }\n 12% {\n opacity: 1;\n }\n to {\n opacity: 1;\n translate: 0 0;\n rotate: var(--kui-slat-dx, 0) var(--kui-slat-dy, 1) 0 0deg;\n }\n }\n}\n\n/* src/css/text.css */\n@layer kui.effects {\n .kui-sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip-path: inset(50%);\n white-space: nowrap;\n border: 0;\n }\n .kui-split-decorative {\n display: inline;\n }\n .kui-split-item {\n display: inline-block;\n animation-duration: var(--kui-duration, 500ms);\n animation-delay: calc(var(--kui-delay, 0ms) + var(--kui-i, 0) * var(--kui-stagger, 30ms));\n animation-timing-function: var(--kui-ease, ease-out);\n animation-fill-mode: both;\n }\n .kui-split-line {\n display: block;\n }\n [data-kui-split-fx=fade] .kui-split-item {\n animation-name: kui-split-reveal-fade;\n }\n [data-kui-split-fx=up] .kui-split-item {\n animation-name: kui-split-reveal-up;\n }\n [data-kui-split-fx=down] .kui-split-item {\n animation-name: kui-split-reveal-down;\n }\n [data-kui-split-fx=mask] .kui-split-item {\n animation-name: kui-split-reveal-mask;\n }\n @keyframes kui-split-reveal-fade {\n from {\n opacity: 0;\n }\n }\n @keyframes kui-split-reveal-up {\n from {\n opacity: 0;\n translate: 0 0.6em;\n }\n }\n @keyframes kui-split-reveal-down {\n from {\n opacity: 0;\n translate: 0 -0.6em;\n }\n }\n @keyframes kui-split-reveal-mask {\n from {\n opacity: 0;\n clip-path: inset(0 0 100% 0);\n }\n to {\n clip-path: inset(0 0 0 0);\n }\n }\n [data-kui-split-fx=wave] .kui-split-item {\n animation-name: kui-split-wave;\n animation-duration: 1400ms;\n animation-iteration-count: infinite;\n animation-timing-function: ease-in-out;\n }\n [data-kui-split-fx=jitter] .kui-split-item {\n animation-name: kui-split-jitter;\n animation-duration: 220ms;\n animation-iteration-count: infinite;\n animation-timing-function: ease-in-out;\n animation-direction: alternate;\n }\n @keyframes kui-split-wave {\n 0%, 100% {\n translate: 0 0;\n }\n 50% {\n translate: 0 -0.35em;\n }\n }\n @keyframes kui-split-jitter {\n from {\n translate: 0 0;\n rotate: 0deg;\n }\n to {\n translate: 0 0.08em;\n rotate: 3deg;\n }\n }\n .kui-typewriter::after {\n content: \"\";\n display: inline-block;\n width: 0.08em;\n margin-inline-start: 0.05em;\n height: 1em;\n vertical-align: -0.15em;\n background: currentColor;\n animation: kui-caret-blink 1s steps(1) infinite;\n }\n @keyframes kui-caret-blink {\n 50% {\n opacity: 0;\n }\n }\n .kui-scramble {\n font-variant-numeric: tabular-nums;\n }\n [data-kui-fx~=word-cycler] {\n display: inline-block;\n transition: opacity 150ms ease-out;\n }\n [data-kui-fx~=word-cycler].kui-word-cycler-swap {\n opacity: 0;\n }\n [data-kui-fx~=gradient-shimmer] {\n background-image:\n linear-gradient(\n 100deg,\n currentColor 40%,\n color-mix(in srgb, currentColor 35%, transparent) 50%,\n currentColor 60%);\n background-size: 220% 100%;\n -webkit-background-clip: text;\n background-clip: text;\n -webkit-text-fill-color: transparent;\n --kui-fx-gradient-shimmer-iterations: infinite;\n }\n @keyframes kui-gradient-shimmer {\n from {\n background-position: 200% 0;\n }\n to {\n background-position: -200% 0;\n }\n }\n [data-kui-fx~=gradient-sweep] {\n background-image:\n linear-gradient(\n 100deg,\n transparent 30%,\n color-mix(in srgb, var(--kui-sweep-color, currentColor) 70%, transparent) 50%,\n transparent 70%);\n background-size: 260% 100%;\n -webkit-background-clip: text;\n background-clip: text;\n -webkit-text-fill-color: transparent;\n }\n @keyframes kui-gradient-sweep {\n from {\n background-position: 220% 0;\n }\n to {\n background-position: -60% 0;\n }\n }\n [data-kui-fx~=highlight-sweep] {\n background-image: linear-gradient(90deg, color-mix(in srgb, var(--kui-sweep-color, currentColor) 55%, transparent) 0 100%);\n background-repeat: no-repeat;\n background-size: 0% 100%;\n padding: 0 0.05em;\n }\n @keyframes kui-highlight-sweep {\n to {\n background-size: 100% 100%;\n }\n }\n [data-kui-fx~=underline-draw] {\n background-image: linear-gradient(var(--kui-sweep-color, currentColor), var(--kui-sweep-color, currentColor));\n background-repeat: no-repeat;\n background-position: 0 100%;\n background-size: 0% 2px;\n padding-bottom: 0.15em;\n }\n @keyframes kui-underline-draw {\n to {\n background-size: 100% 2px;\n }\n }\n [data-kui-fx~=text-outline-fill] {\n -webkit-text-stroke: 1px currentColor;\n -webkit-text-fill-color: transparent;\n }\n @keyframes kui-text-outline-fill {\n to {\n -webkit-text-fill-color: currentColor;\n }\n }\n @keyframes kui-var-weight {\n from {\n font-weight: var(--kui-from-weight, 100);\n }\n to {\n font-weight: var(--kui-to-weight, 800);\n }\n }\n @keyframes kui-var-width {\n from {\n font-stretch: var(--kui-from-width, 75%);\n }\n to {\n font-stretch: var(--kui-to-width, 125%);\n }\n }\n @keyframes kui-var-slant {\n from {\n font-style: oblique var(--kui-from-slant, 0deg);\n }\n to {\n font-style: oblique var(--kui-to-slant, 10deg);\n }\n }\n [data-kui-fx~=marquee],\n [data-kui-fx~=marquee-scroll-linked] {\n display: flex;\n width: max-content;\n will-change: translate;\n }\n [data-kui-fx~=marquee] {\n --kui-fx-marquee-iterations: infinite;\n }\n @keyframes kui-marquee {\n to {\n translate: -50% 0;\n }\n }\n @property --kui-redaction-x { syntax: \"<percentage>\"; inherits: true; initial-value: 0%; }\n [data-kui-fx~=redaction-reveal] {\n position: relative;\n display: inline-block;\n }\n [data-kui-fx~=redaction-reveal]::before {\n content: \"\";\n position: absolute;\n inset: 0;\n background: var(--kui-bar-color, #111);\n clip-path: inset(0 0 0 var(--kui-redaction-x));\n }\n @keyframes kui-redaction-reveal {\n to {\n --kui-redaction-x: 100%;\n }\n }\n [data-kui-fx~=text-3d-extrude] {\n display: inline-block;\n text-shadow:\n 1px 1px 0 color-mix(in srgb, currentColor 70%, transparent),\n 2px 2px 0 color-mix(in srgb, currentColor 60%, transparent),\n 3px 3px 0 color-mix(in srgb, currentColor 50%, transparent),\n 4px 4px 0 color-mix(in srgb, currentColor 40%, transparent),\n 5px 5px 0 color-mix(in srgb, currentColor 30%, transparent),\n 6px 6px 8px rgb(0 0 0 / 0.35);\n }\n @keyframes kui-text-3d-extrude {\n from {\n rotate: var(--kui-from-angle, -20deg);\n translate: 0 var(--kui-distance, 32px);\n }\n to {\n rotate: 0deg;\n translate: 0 0;\n }\n }\n}\n\n/* src/css/navigation.css */\n@layer kui.effects {\n @keyframes kui-nav-reveal {\n from {\n opacity: 0;\n translate: 0 var(--kui-distance, 16px);\n }\n }\n @keyframes kui-menu-fullscreen {\n from {\n opacity: 0;\n clip-path: circle(0% at var(--kui-origin, 100% 0%));\n }\n to {\n opacity: 1;\n clip-path: circle(150% at var(--kui-origin, 100% 0%));\n }\n }\n @keyframes kui-panel-reveal {\n from {\n opacity: 0;\n translate: 0 calc(var(--kui-distance, 10px) * -1);\n }\n }\n @keyframes kui-drawer-slide-right {\n from {\n translate: 100% 0;\n }\n }\n [data-kui-fx~=header-shrink] {\n --kui-shrink: 0;\n padding-block: calc(1.4rem - 0.7rem * var(--kui-shrink, 0));\n font-size: calc(1rem - 0.15rem * var(--kui-shrink, 0));\n transition:\n padding-block 200ms ease-out,\n font-size 200ms ease-out,\n box-shadow 200ms ease-out;\n }\n [data-kui-fx~=header-shrink][data-kui-shrunk=true] {\n box-shadow: 0 2px 10px rgb(0 0 0 / 0.12);\n }\n [data-kui-fx~=header-hide-on-scroll] {\n transition: translate 220ms ease-out;\n }\n [data-kui-fx~=header-hide-on-scroll][data-kui-hidden=true] {\n translate: 0 -100%;\n }\n [data-kui-fx~=back-to-top-fade] {\n opacity: 0;\n translate: 0 12px;\n pointer-events: none;\n transition: opacity 200ms ease-out, translate 200ms ease-out;\n }\n [data-kui-fx~=back-to-top-fade][data-kui-visible=true] {\n opacity: 1;\n translate: 0 0;\n pointer-events: auto;\n }\n}\n\n/* src/css/forms.css */\n@layer kui.effects {\n [data-kui-fx~=label-float] ~ label {\n transition: translate 180ms ease-out, scale 180ms ease-out;\n transform-origin: left center;\n }\n [data-kui-fx~=label-float]:focus ~ label,\n [data-kui-fx~=label-float]:not(:placeholder-shown) ~ label {\n translate: 0 -1.35rem;\n scale: 0.82;\n }\n [data-kui-fx~=input-underline-grow] ~ .kui-underline {\n display: block;\n height: 2px;\n background: currentColor;\n scale: 0 1;\n transform-origin: left center;\n transition: scale 220ms ease-out;\n }\n [data-kui-fx~=input-underline-grow]:focus ~ .kui-underline {\n scale: 1 1;\n }\n @keyframes kui-focus-ring-grow {\n from {\n box-shadow: 0 0 0 0 var(--kui-ring-color, rgb(210 105 30 / 0.55));\n }\n to {\n box-shadow: 0 0 0 5px var(--kui-ring-color, rgb(210 105 30 / 0.55));\n }\n }\n @keyframes kui-validate-shake {\n 10%, 90% {\n translate: -1px 0;\n }\n 20%, 80% {\n translate: 2px 0;\n }\n 30%, 50%, 70% {\n translate: -4px 0;\n }\n 40%, 60% {\n translate: 4px 0;\n }\n }\n [data-kui-fx~=validate-check] {\n stroke-dasharray: 24;\n stroke-dashoffset: 24;\n }\n @keyframes kui-validate-check {\n to {\n stroke-dashoffset: 0;\n }\n }\n [data-kui-fx~=strength-meter] ~ .kui-meter > * {\n background: var(--kui-meter-off, currentColor);\n opacity: 0.2;\n transition: opacity 200ms ease-out, background-color 200ms ease-out;\n }\n [data-kui-fx~=strength-meter][data-kui-strength-level=\"1\"] ~ .kui-meter > *:nth-child(-n+1),\n [data-kui-fx~=strength-meter][data-kui-strength-level=\"2\"] ~ .kui-meter > *:nth-child(-n+2),\n [data-kui-fx~=strength-meter][data-kui-strength-level=\"3\"] ~ .kui-meter > *:nth-child(-n+3),\n [data-kui-fx~=strength-meter][data-kui-strength-level=\"4\"] ~ .kui-meter > *:nth-child(-n+4),\n [data-kui-fx~=strength-meter][data-kui-strength-level=\"5\"] ~ .kui-meter > *:nth-child(-n+5),\n [data-kui-fx~=strength-meter][data-kui-strength-level=\"6\"] ~ .kui-meter > *:nth-child(-n+6),\n [data-kui-fx~=strength-meter][data-kui-strength-level=\"7\"] ~ .kui-meter > *:nth-child(-n+7),\n [data-kui-fx~=strength-meter][data-kui-strength-level=\"8\"] ~ .kui-meter > *:nth-child(-n+8),\n [data-kui-fx~=strength-meter][data-kui-strength-level=\"9\"] ~ .kui-meter > *:nth-child(-n+9),\n [data-kui-fx~=strength-meter][data-kui-strength-level=\"10\"] ~ .kui-meter > *:nth-child(-n+10),\n [data-kui-fx~=strength-meter][data-kui-strength-level=\"11\"] ~ .kui-meter > *:nth-child(-n+11),\n [data-kui-fx~=strength-meter][data-kui-strength-level=\"12\"] ~ .kui-meter > *:nth-child(-n+12),\n [data-kui-fx~=strength-meter][data-kui-strength-level=\"13\"] ~ .kui-meter > *:nth-child(-n+13),\n [data-kui-fx~=strength-meter][data-kui-strength-level=\"14\"] ~ .kui-meter > *:nth-child(-n+14),\n [data-kui-fx~=strength-meter][data-kui-strength-level=\"15\"] ~ .kui-meter > *:nth-child(-n+15),\n [data-kui-fx~=strength-meter][data-kui-strength-level=\"16\"] ~ .kui-meter > *:nth-child(-n+16),\n [data-kui-fx~=strength-meter][data-kui-strength-level=\"17\"] ~ .kui-meter > *:nth-child(-n+17),\n [data-kui-fx~=strength-meter][data-kui-strength-level=\"18\"] ~ .kui-meter > *:nth-child(-n+18),\n [data-kui-fx~=strength-meter][data-kui-strength-level=\"19\"] ~ .kui-meter > *:nth-child(-n+19),\n [data-kui-fx~=strength-meter][data-kui-strength-level=\"20\"] ~ .kui-meter > *:nth-child(-n+20) {\n opacity: 1;\n background: var(--kui-meter-on, #2e9e5b);\n }\n [data-kui-fx~=toggle-morph] ~ .kui-track {\n display: inline-block;\n width: calc(40px * var(--kui-toggle-scale, 1));\n height: calc(22px * var(--kui-toggle-scale, 1));\n border-radius: 999px;\n background: var(--muted, #9a8d80);\n transition: background-color 200ms ease-out;\n position: relative;\n }\n [data-kui-fx~=toggle-morph] ~ .kui-track .kui-thumb {\n position: absolute;\n top: calc(2px * var(--kui-toggle-scale, 1));\n left: calc(2px * var(--kui-toggle-scale, 1));\n width: calc(18px * var(--kui-toggle-scale, 1));\n height: calc(18px * var(--kui-toggle-scale, 1));\n border-radius: 50%;\n background: var(--kui-thumb-color, #fff);\n translate: 0 0;\n transition: translate 200ms ease-out;\n }\n [data-kui-fx~=toggle-morph]:checked ~ .kui-track {\n background: var(--accent, #d2691e);\n }\n [data-kui-fx~=toggle-morph]:checked ~ .kui-track .kui-thumb {\n translate: calc(18px * var(--kui-toggle-scale, 1)) 0;\n }\n [data-kui-fx~=checkbox-draw] ~ svg path {\n stroke-dasharray: 24;\n stroke-dashoffset: 24;\n transition: stroke-dashoffset 220ms ease-out;\n }\n [data-kui-fx~=checkbox-draw]:checked ~ svg path {\n stroke-dashoffset: 0;\n }\n [data-kui-fx~=radio-fill] ~ .kui-dot {\n display: inline-block;\n width: calc(10px * var(--kui-radio-scale, 1));\n height: calc(10px * var(--kui-radio-scale, 1));\n border-radius: 50%;\n background: var(--accent, #d2691e);\n scale: 0;\n transition: scale 180ms ease-out;\n }\n [data-kui-fx~=radio-fill]:checked ~ .kui-dot {\n scale: 1;\n }\n [data-kui-fx~=range-fill] {\n --kui-fill: 0%;\n accent-color: var(--accent, #d2691e);\n background:\n linear-gradient(\n to right,\n var(--accent, #d2691e) var(--kui-fill, 0%),\n var(--border, #2a2422) var(--kui-fill, 0%));\n height: 4px;\n border-radius: 999px;\n appearance: none;\n outline: none;\n }\n [data-kui-fx~=submit-to-spinner-to-check] .kui-stage-idle,\n [data-kui-fx~=submit-to-spinner-to-check] .kui-stage-loading,\n [data-kui-fx~=submit-to-spinner-to-check] .kui-stage-done {\n display: none;\n }\n [data-kui-fx~=submit-to-spinner-to-check][data-kui-stage=idle] .kui-stage-idle,\n [data-kui-fx~=submit-to-spinner-to-check][data-kui-stage=loading] .kui-stage-loading,\n [data-kui-fx~=submit-to-spinner-to-check][data-kui-stage=done] .kui-stage-done {\n display: inline-flex;\n }\n [data-kui-fx~=submit-to-spinner-to-check] .kui-spinner {\n width: 1em;\n height: 1em;\n border-radius: 50%;\n border: 2px solid currentColor;\n border-top-color: transparent;\n animation: kui-spin 700ms linear infinite;\n }\n @keyframes kui-spin {\n to {\n rotate: 360deg;\n }\n }\n [data-kui-fx~=step-progress] {\n cursor: pointer;\n }\n [data-kui-fx~=step-progress] > [data-kui-step-state],\n .kui-step-track > [data-kui-step-state] {\n background: var(--muted, #9a8d80);\n opacity: 0.35;\n transition: opacity 200ms ease-out, background-color 200ms ease-out;\n }\n [data-kui-fx~=step-progress] > [data-kui-step-state=before],\n [data-kui-fx~=step-progress] > [data-kui-step-state=active],\n .kui-step-track > [data-kui-step-state=before],\n .kui-step-track > [data-kui-step-state=active] {\n opacity: 1;\n background: var(--accent, #d2691e);\n }\n}\n\n/* src/css/ambient.css */\n@layer kui.effects {\n [data-kui-fx~=gradient-mesh] {\n background-image:\n radial-gradient(\n at 15% 20%,\n color-mix(in srgb, var(--kui-c1, #7c3aed) 55%, transparent),\n transparent 55%),\n radial-gradient(\n at 85% 15%,\n color-mix(in srgb, var(--kui-c2, #06b6d4) 50%, transparent),\n transparent 55%),\n radial-gradient(\n at 50% 85%,\n color-mix(in srgb, var(--kui-c3, #f97316) 45%, transparent),\n transparent 55%);\n background-size: 200% 200%;\n --kui-fx-gradient-mesh-iterations: infinite;\n }\n @keyframes kui-gradient-mesh {\n 0%, 100% {\n background-position:\n 0% 0%,\n 100% 0%,\n 50% 100%;\n }\n 50% {\n background-position:\n 25% 35%,\n 75% 30%,\n 35% 70%;\n }\n }\n [data-kui-fx~=aurora] {\n background-image:\n linear-gradient(\n 120deg,\n color-mix(in srgb, var(--kui-c1, #34d399) 45%, transparent),\n transparent 45%),\n linear-gradient(\n 240deg,\n color-mix(in srgb, var(--kui-c2, #60a5fa) 45%, transparent),\n transparent 45%),\n linear-gradient(\n 0deg,\n color-mix(in srgb, var(--kui-c3, #c084fc) 40%, transparent),\n transparent 50%);\n background-size: 260% 260%;\n --kui-fx-aurora-iterations: infinite;\n }\n @keyframes kui-aurora {\n 0%, 100% {\n background-position:\n 0% 50%,\n 100% 50%,\n 50% 0%;\n }\n 50% {\n background-position:\n 60% 30%,\n 40% 70%,\n 55% 60%;\n }\n }\n [data-kui-fx~=wave-blob] {\n background-image:\n radial-gradient(\n circle,\n color-mix(in srgb, var(--kui-c1, #22d3ee) 50%, transparent),\n transparent 60%);\n background-size: 140% 140%;\n background-repeat: no-repeat;\n --kui-fx-wave-blob-iterations: infinite;\n }\n @keyframes kui-wave-blob {\n 0%, 100% {\n background-position: 20% 30%;\n background-size: 140% 140%;\n }\n 33% {\n background-position: 70% 20%;\n background-size: 160% 160%;\n }\n 66% {\n background-position: 50% 75%;\n background-size: 120% 120%;\n }\n }\n [data-kui-fx~=spotlight-follow] {\n background-image:\n radial-gradient(\n circle,\n color-mix(in srgb, var(--kui-c1, #fde68a) 65%, transparent),\n transparent 65%);\n background-size: 55% 55%;\n background-repeat: no-repeat;\n --kui-fx-spotlight-follow-iterations: infinite;\n }\n @keyframes kui-spotlight-follow {\n 0%, 100% {\n background-position: 10% 15%;\n }\n 25% {\n background-position: 85% 20%;\n }\n 50% {\n background-position: 80% 80%;\n }\n 75% {\n background-position: 15% 75%;\n }\n }\n [data-kui-fx~=gradient-rotate-border] {\n position: relative;\n background-image:\n linear-gradient(\n 90deg,\n var(--kui-c1, #f472b6),\n var(--kui-c2, #60a5fa),\n var(--kui-c3, #34d399),\n var(--kui-c4, #fbbf24),\n var(--kui-c1, #f472b6));\n background-size: 300% 100%;\n padding: 3px;\n mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);\n mask-composite: exclude;\n -webkit-mask-composite: xor;\n --kui-fx-gradient-rotate-border-iterations: infinite;\n }\n @keyframes kui-gradient-rotate-border {\n from {\n background-position: 0% 50%;\n }\n to {\n background-position: 300% 50%;\n }\n }\n [data-kui-fx~=noise-overlay] {\n background-image:\n repeating-radial-gradient(\n circle at 0 0,\n color-mix(in srgb, var(--kui-c1, currentColor) 30%, transparent) 0,\n transparent 1.4px,\n transparent 3px);\n background-size: 5px 5px;\n --kui-fx-noise-overlay-iterations: infinite;\n }\n @keyframes kui-noise-overlay {\n 0% {\n background-position: 0 0;\n }\n 20% {\n background-position: -3px 1px;\n }\n 40% {\n background-position: 2px -2px;\n }\n 60% {\n background-position: -1px 3px;\n }\n 80% {\n background-position: 3px 2px;\n }\n 100% {\n background-position: 0 0;\n }\n }\n [data-kui-fx~=scanline] {\n background-image:\n linear-gradient(\n to bottom,\n transparent,\n color-mix(in srgb, var(--kui-c1, currentColor) 35%, transparent) 50%,\n transparent);\n background-size: 100% 220%;\n background-repeat: no-repeat;\n --kui-fx-scanline-iterations: infinite;\n }\n @keyframes kui-scanline {\n from {\n background-position: 0 -120%;\n }\n to {\n background-position: 0 120%;\n }\n }\n [data-kui-fx~=dot-grid-drift] {\n background-image:\n radial-gradient(\n circle,\n color-mix(in srgb, var(--kui-c1, currentColor) 45%, transparent) 1.5px,\n transparent 1.5px);\n background-size: 22px 22px;\n --kui-fx-dot-grid-drift-iterations: infinite;\n }\n @keyframes kui-dot-grid-drift {\n from {\n background-position: 0 0;\n }\n to {\n background-position: 22px 22px;\n }\n }\n [data-kui-fx~=line-grid-drift] {\n background-image:\n repeating-linear-gradient(\n 0deg,\n color-mix(in srgb, var(--kui-c1, currentColor) 30%, transparent) 0 1px,\n transparent 1px 26px),\n repeating-linear-gradient(\n 90deg,\n color-mix(in srgb, var(--kui-c1, currentColor) 30%, transparent) 0 1px,\n transparent 1px 26px);\n --kui-fx-line-grid-drift-iterations: infinite;\n }\n @keyframes kui-line-grid-drift {\n from {\n background-position: 0 0, 0 0;\n }\n to {\n background-position: 0 26px, 26px 0;\n }\n }\n [data-kui-fx~=starfield] {\n background-image:\n radial-gradient(\n 1px 1px at 10% 20%,\n color-mix(in srgb, var(--kui-c1, #ffffff) 90%, transparent),\n transparent),\n radial-gradient(\n 1px 1px at 70% 60%,\n color-mix(in srgb, var(--kui-c1, #ffffff) 70%, transparent),\n transparent),\n radial-gradient(\n 1.5px 1.5px at 40% 80%,\n color-mix(in srgb, var(--kui-c1, #ffffff) 85%, transparent),\n transparent),\n radial-gradient(\n 1px 1px at 90% 30%,\n color-mix(in srgb, var(--kui-c1, #ffffff) 60%, transparent),\n transparent),\n radial-gradient(\n 1.5px 1.5px at 25% 55%,\n color-mix(in srgb, var(--kui-c1, #ffffff) 80%, transparent),\n transparent);\n background-size: 220px 220px;\n background-repeat: repeat;\n --kui-fx-starfield-iterations: infinite;\n }\n @keyframes kui-starfield {\n from {\n background-position:\n 0 0,\n 0 0,\n 0 0,\n 0 0,\n 0 0;\n }\n to {\n background-position:\n 220px 90px,\n -160px 220px,\n 90px -140px,\n -220px -90px,\n 140px 160px;\n }\n }\n [data-kui-fx~=orbit] {\n --kui-fx-orbit-iterations: infinite;\n }\n @keyframes kui-orbit {\n to {\n rotate: var(--kui-to-angle, 360deg);\n }\n }\n [data-kui-fx~=float] {\n --kui-fx-float-iterations: infinite;\n }\n @keyframes kui-float {\n 0%, 100% {\n translate: 0 0;\n }\n 50% {\n translate: 0 calc(var(--kui-distance, 14px) * -1);\n }\n }\n [data-kui-fx~=bob] {\n --kui-fx-bob-iterations: infinite;\n }\n @keyframes kui-bob {\n 0%, 100% {\n translate: 0 0;\n }\n 50% {\n translate: 0 calc(var(--kui-distance, 8px) * -1);\n }\n }\n [data-kui-fx~=floating-shapes] {\n --kui-fx-floating-shapes-iterations: infinite;\n }\n @keyframes kui-floating-shapes {\n 0%, 100% {\n translate: 0 0;\n }\n 33% {\n translate: calc(var(--kui-distance, 10px) * 0.6) calc(var(--kui-distance, 10px) * -1);\n }\n 66% {\n translate: calc(var(--kui-distance, 10px) * -0.6) calc(var(--kui-distance, 10px) * -0.4);\n }\n }\n [data-kui-fx~=glow-pulse] {\n --kui-fx-glow-pulse-iterations: infinite;\n }\n @keyframes kui-glow-pulse {\n 0%, 100% {\n scale: 1;\n opacity: 0.6;\n }\n 50% {\n scale: var(--kui-pulse-scale, 1.15);\n opacity: 1;\n }\n }\n}\n\n/* src/css/feedback.css */\n@layer kui.effects {\n [data-kui-fx~=skeleton-shimmer] {\n background-color: var(--kui-skeleton-base, #2a2422);\n background-image:\n linear-gradient(\n 100deg,\n transparent 30%,\n color-mix(in srgb, var(--kui-skeleton-highlight, #ffffff) 18%, transparent) 50%,\n transparent 70%);\n background-size: 200% 100%;\n --kui-fx-skeleton-shimmer-iterations: infinite;\n }\n @keyframes kui-skeleton-shimmer {\n from {\n background-position: 150% 0;\n }\n to {\n background-position: -50% 0;\n }\n }\n @keyframes kui-skeleton-to-content {\n from {\n opacity: 0;\n }\n }\n [data-kui-fx~=spinner] {\n display: inline-block;\n width: var(--kui-spinner-size, 28px);\n height: var(--kui-spinner-size, 28px);\n border-radius: 50%;\n border: 3px solid color-mix(in srgb, currentColor 20%, transparent);\n border-top-color: currentColor;\n --kui-fx-spinner-iterations: infinite;\n }\n @keyframes kui-spinner-spin {\n to {\n rotate: 360deg;\n }\n }\n [data-kui-fx~=spinner-ring] {\n display: inline-block;\n width: var(--kui-spinner-size, 28px);\n height: var(--kui-spinner-size, 28px);\n border-radius: 50%;\n border: 3px dashed color-mix(in srgb, currentColor 55%, transparent);\n --kui-fx-spinner-ring-iterations: infinite;\n }\n @keyframes kui-spinner-ring-spin {\n to {\n rotate: 360deg;\n }\n }\n [data-kui-fx~=spinner-dots] {\n display: inline-block;\n width: var(--kui-dot-size, 8px);\n height: var(--kui-dot-size, 8px);\n border-radius: 50%;\n background: currentColor;\n box-shadow: calc(var(--kui-dot-size, 8px) * -2) 0 currentColor, calc(var(--kui-dot-size, 8px) * 2) 0 currentColor;\n --kui-fx-spinner-dots-iterations: infinite;\n }\n @keyframes kui-spinner-dots {\n 0%, 80%, 100% {\n scale: 0.7;\n opacity: 0.5;\n }\n 40% {\n scale: 1.15;\n opacity: 1;\n }\n }\n [data-kui-fx~=progress-indeterminate] {\n transform-origin: 0% 50%;\n background: currentColor;\n border-radius: inherit;\n --kui-fx-progress-indeterminate-iterations: infinite;\n }\n @keyframes kui-progress-indeterminate {\n 0% {\n translate: -100% 0;\n scale: 0.4 1;\n }\n 50% {\n scale: 1 1;\n }\n 100% {\n translate: 100% 0;\n scale: 0.4 1;\n }\n }\n @keyframes kui-toast-slide-in {\n from {\n opacity: 0;\n translate: 0 var(--kui-distance, 24px);\n }\n to {\n opacity: 1;\n translate: 0 0;\n }\n }\n @keyframes kui-toast-slide-out {\n from {\n opacity: 1;\n translate: 0 0;\n }\n to {\n opacity: 0;\n translate: 0 var(--kui-distance, 24px);\n }\n }\n @keyframes kui-shake-error {\n 10%, 90% {\n translate: -1px 0;\n }\n 20%, 80% {\n translate: 2px 0;\n }\n 30%, 50%, 70% {\n translate: -4px 0;\n }\n 40%, 60% {\n translate: 4px 0;\n }\n }\n @keyframes kui-wobble {\n 0% {\n translate: 0 0;\n rotate: 0deg;\n }\n 15% {\n translate: -6px 0;\n rotate: -6deg;\n }\n 30% {\n translate: 4px 0;\n rotate: 4deg;\n }\n 45% {\n translate: -3px 0;\n rotate: -3deg;\n }\n 60% {\n translate: 2px 0;\n rotate: 2deg;\n }\n 75% {\n translate: -1px 0;\n rotate: -1deg;\n }\n 100% {\n translate: 0 0;\n rotate: 0deg;\n }\n }\n [data-kui-fx~=ripple] {\n border-radius: 50%;\n background: currentColor;\n transform-origin: center;\n }\n @keyframes kui-ripple {\n from {\n scale: 0.2;\n opacity: 0.6;\n }\n to {\n scale: var(--kui-ripple-scale, 4);\n opacity: 0;\n }\n }\n @keyframes kui-badge-pop {\n 0% {\n scale: 0.4;\n }\n 60% {\n scale: var(--kui-pop-scale, 1.18);\n }\n 100% {\n scale: 1;\n }\n }\n @keyframes kui-count-bump {\n 0%, 100% {\n scale: 1;\n }\n 50% {\n scale: var(--kui-pop-scale, 1.18);\n }\n }\n [data-kui-fx~=heart-burst] {\n color: var(--kui-heart-color, #f43f5e);\n }\n @keyframes kui-heart-burst {\n 0% {\n scale: 1;\n }\n 30% {\n scale: var(--kui-pop-scale, 1.18);\n }\n 55% {\n scale: 0.9;\n }\n 100% {\n scale: 1;\n }\n }\n [data-kui-fx~=confetti-burst] {\n background-image:\n radial-gradient(\n circle at 20% 20%,\n var(--kui-c1, #f43f5e) 0 3px,\n transparent 3px),\n radial-gradient(\n circle at 75% 15%,\n var(--kui-c2, #fbbf24) 0 3px,\n transparent 3px),\n radial-gradient(\n circle at 50% 75%,\n var(--kui-c3, #34d399) 0 3px,\n transparent 3px),\n radial-gradient(\n circle at 85% 65%,\n var(--kui-c4, #60a5fa) 0 3px,\n transparent 3px),\n radial-gradient(\n circle at 15% 65%,\n var(--kui-c5, #c084fc) 0 3px,\n transparent 3px);\n background-repeat: no-repeat;\n }\n @keyframes kui-confetti-burst {\n 0% {\n scale: 0.6;\n opacity: 0;\n }\n 40% {\n scale: var(--kui-pop-scale, 1.18);\n opacity: 1;\n }\n 100% {\n scale: 1;\n opacity: 1;\n }\n }\n @keyframes kui-copy-confirm {\n 0% {\n opacity: 0;\n }\n 15% {\n opacity: 1;\n }\n 85% {\n opacity: 1;\n }\n 100% {\n opacity: 0;\n }\n }\n @keyframes kui-pull-to-refresh {\n 0% {\n translate: 0 0;\n }\n 45% {\n translate: 0 var(--kui-pull-distance, 36px);\n }\n 100% {\n translate: 0 0;\n }\n }\n}\n\n/* src/css/numbers.css */\n@layer kui.effects {\n @keyframes kui-progress-ring {\n from {\n stroke-dashoffset: var(--kui-path-length, 100);\n }\n to {\n stroke-dashoffset: 0;\n }\n }\n @keyframes kui-gauge-sweep {\n from {\n stroke-dashoffset: var(--kui-path-length, 100);\n }\n to {\n stroke-dashoffset: 0;\n }\n }\n @keyframes kui-donut-sweep {\n from {\n stroke-dashoffset: var(--kui-path-length, 100);\n }\n to {\n stroke-dashoffset: 0;\n }\n }\n @keyframes kui-sparkline-draw {\n from {\n stroke-dashoffset: var(--kui-path-length, 1000);\n }\n to {\n stroke-dashoffset: 0;\n }\n }\n [data-kui-fx~=progress-ring],\n [data-kui-fx~=gauge-sweep],\n [data-kui-fx~=donut-sweep],\n [data-kui-fx~=sparkline-draw] {\n stroke-dasharray: var(--kui-path-length, 100);\n fill: none;\n }\n @keyframes kui-progress-bar {\n from {\n scale: var(--kui-bar-from, 0) 1;\n }\n to {\n scale: 1 1;\n }\n }\n [data-kui-fx~=progress-bar] {\n transform-origin: left center;\n }\n [data-kui-fx~=progress-bar][data-kui-state=ready] {\n --kui-bar-from: 1 !important;\n opacity: 0 !important;\n }\n @keyframes kui-progress-segments {\n from {\n opacity: 0.18;\n }\n to {\n opacity: 1;\n }\n }\n @keyframes kui-star-rating-fill {\n from {\n clip-path: inset(0 100% 0 0);\n }\n to {\n clip-path: inset(0 calc(100% - var(--kui-fill, 100%)) 0 0);\n }\n }\n .kui-count-decorative {\n display: inline-flex;\n align-items: baseline;\n }\n .kui-odometer-col {\n display: inline-block;\n overflow: hidden;\n height: 1em;\n line-height: 1;\n vertical-align: baseline;\n }\n .kui-odometer-strip {\n display: flex;\n flex-direction: column;\n translate: 0 calc(var(--kui-o, 0) * -1em);\n transition: translate 220ms ease-out;\n }\n .kui-odometer-strip > span {\n height: 1em;\n line-height: 1;\n }\n}\n\n/* src/css/interaction.css */\n@layer kui.effects {\n @property --kui-border-angle { syntax: \"<angle>\"; inherits: false; initial-value: 0deg; }\n @property --kui-border-pct { syntax: \"<percentage>\"; inherits: false; initial-value: 0%; }\n [data-kui-fx~=lift] {\n transition: translate var(--kui-lift-duration, 220ms) var(--kui-lift-ease, ease-out);\n }\n [data-kui-fx~=lift]:focus-visible {\n translate: 0 calc(var(--kui-lift-distance, 6px) * -1);\n }\n [data-kui-fx~=pop] {\n transition: scale var(--kui-pop-duration, 220ms) var(--kui-pop-ease, ease-out);\n }\n [data-kui-fx~=pop]:focus-visible {\n scale: var(--kui-pop-scale, 1.06);\n }\n [data-kui-fx~=lift-shadow] {\n transition: translate var(--kui-lift-shadow-duration, 220ms) var(--kui-lift-shadow-ease, ease-out), box-shadow var(--kui-lift-shadow-duration, 220ms) var(--kui-lift-shadow-ease, ease-out);\n }\n [data-kui-fx~=lift-shadow]:focus-visible {\n translate: 0 calc(var(--kui-lift-distance, 6px) * -1);\n box-shadow: 0 14px 28px -12px rgb(0 0 0 / 0.45);\n }\n [data-kui-fx~=shine-sweep] {\n position: relative;\n overflow: hidden;\n }\n [data-kui-fx~=shine-sweep]::after {\n content: \"\";\n position: absolute;\n inset: 0;\n background:\n linear-gradient(\n 115deg,\n transparent 40%,\n var(--kui-c1, rgb(255 255 255 / 0.35)) 50%,\n transparent 60%);\n background-size: 220% 100%;\n background-position: 120% 0;\n pointer-events: none;\n }\n [data-kui-fx~=shine-sweep]:focus-visible::after {\n animation: kui-shine-sweep var(--kui-shine-sweep-duration, 700ms) var(--kui-shine-sweep-ease, ease-out);\n }\n @keyframes kui-shine-sweep {\n from {\n background-position: 120% 0;\n }\n to {\n background-position: -20% 0;\n }\n }\n [data-kui-fx~=split-flap] {\n display: inline-block;\n perspective: 600px;\n backface-visibility: hidden;\n }\n [data-kui-fx~=split-flap]:focus-visible {\n animation: kui-split-flap var(--kui-split-flap-duration, 600ms) var(--kui-split-flap-ease, ease-in-out);\n }\n @keyframes kui-split-flap {\n from {\n rotate: x 0deg;\n }\n to {\n rotate: x 360deg;\n }\n }\n [data-kui-fx~=border-draw] {\n border: 2px solid transparent;\n border-image-slice: 1;\n border-image-source:\n conic-gradient(\n from -90deg,\n var(--kui-border-draw-color, var(--accent, #d2691e)) 0 var(--kui-border-pct, 0%),\n transparent 0);\n transition: --kui-border-pct var(--kui-border-draw-duration, 500ms) var(--kui-border-draw-ease, ease-out);\n }\n [data-kui-fx~=border-draw]:focus-visible {\n --kui-border-pct: 100%;\n }\n [data-kui-fx~=border-glow] {\n transition: box-shadow var(--kui-border-glow-duration, 260ms) var(--kui-border-glow-ease, ease-out);\n }\n [data-kui-fx~=border-glow]:focus-visible {\n box-shadow: 0 0 0 3px var(--kui-border-glow-color, var(--accent, #d2691e));\n }\n [data-kui-fx~=beam-border],\n [data-kui-fx~=beam-border-auto] {\n position: relative;\n }\n [data-kui-fx~=beam-border]::before,\n [data-kui-fx~=beam-border-auto]::before {\n content: \"\";\n position: absolute;\n inset: 0;\n border-radius: inherit;\n padding: var(--kui-beam-border-width, 3px);\n background:\n conic-gradient(\n from var(--kui-border-angle, 0deg),\n transparent 0deg,\n transparent 260deg,\n var(--kui-beam-border-c1, #ff5f6d) 282deg,\n var(--kui-beam-border-c2, #ffc371) 306deg,\n var(--kui-beam-border-c3, #4facfe) 330deg,\n var(--kui-beam-border-c4, #a855f7) 354deg,\n transparent 360deg);\n -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);\n -webkit-mask-composite: xor;\n mask-composite: exclude;\n opacity: 0;\n pointer-events: none;\n transition: opacity var(--kui-beam-border-fade-duration, 200ms) ease-out;\n }\n [data-kui-fx~=beam-border]:focus-visible::before {\n opacity: 1;\n animation: kui-beam-rotate var(--kui-beam-border-duration, 4260ms) linear infinite;\n }\n [data-kui-fx~=beam-border-auto]::before {\n opacity: 1;\n animation: kui-beam-rotate var(--kui-beam-border-duration, 4260ms) linear infinite;\n }\n @keyframes kui-beam-rotate {\n to {\n --kui-border-angle: 360deg;\n }\n }\n @media (prefers-reduced-motion: reduce) {\n [data-kui-fx~=beam-border]:focus-visible::before,\n [data-kui-fx~=beam-border-auto]::before {\n animation: none;\n --kui-border-angle: 45deg;\n }\n }\n [data-kui-fx~=underline-slide] {\n position: relative;\n text-decoration: none;\n }\n [data-kui-fx~=underline-slide]::after {\n content: \"\";\n position: absolute;\n left: 0;\n right: 0;\n bottom: -0.15em;\n height: 0.08em;\n background: currentcolor;\n scale: 0 1;\n transform-origin: left center;\n transition: scale var(--kui-underline-slide-duration, 260ms) var(--kui-underline-slide-ease, ease-out);\n }\n [data-kui-fx~=underline-slide]:focus-visible::after {\n scale: 1 1;\n }\n [data-kui-fx~=underline-center] {\n position: relative;\n text-decoration: none;\n }\n [data-kui-fx~=underline-center]::after {\n content: \"\";\n position: absolute;\n left: 0;\n right: 0;\n bottom: -0.15em;\n height: 0.08em;\n background: currentcolor;\n scale: 0 1;\n transform-origin: center;\n transition: scale var(--kui-underline-center-duration, 260ms) var(--kui-underline-center-ease, ease-out);\n }\n [data-kui-fx~=underline-center]:focus-visible::after {\n scale: 1 1;\n }\n [data-kui-fx~=icon-wiggle]:focus-visible {\n animation: kui-icon-wiggle var(--kui-icon-wiggle-duration, 500ms) var(--kui-icon-wiggle-ease, ease-in-out);\n }\n @keyframes kui-icon-wiggle {\n 0%, 100% {\n rotate: 0deg;\n }\n 20% {\n rotate: -12deg;\n }\n 40% {\n rotate: 10deg;\n }\n 60% {\n rotate: -6deg;\n }\n 80% {\n rotate: 4deg;\n }\n }\n [data-kui-fx~=icon-spin]:focus-visible {\n animation: kui-icon-spin var(--kui-icon-spin-duration, 700ms) linear;\n }\n @keyframes kui-icon-spin {\n from {\n rotate: 0deg;\n }\n to {\n rotate: 360deg;\n }\n }\n [data-kui-fx~=icon-bounce]:focus-visible {\n animation: kui-icon-bounce var(--kui-icon-bounce-duration, 500ms) var(--kui-icon-bounce-ease, ease-out);\n }\n @keyframes kui-icon-bounce {\n 0%, 100% {\n translate: 0 0;\n }\n 30% {\n translate: 0 -7px;\n }\n 55% {\n translate: 0 1px;\n }\n 75% {\n translate: 0 -3px;\n }\n }\n @media (hover: hover) and (pointer: fine) {\n [data-kui-fx~=lift]:hover {\n translate: 0 calc(var(--kui-lift-distance, 6px) * -1);\n }\n [data-kui-fx~=pop]:hover {\n scale: var(--kui-pop-scale, 1.06);\n }\n [data-kui-fx~=lift-shadow]:hover {\n translate: 0 calc(var(--kui-lift-distance, 6px) * -1);\n box-shadow: 0 14px 28px -12px rgb(0 0 0 / 0.45);\n }\n [data-kui-fx~=shine-sweep]:hover::after {\n animation: kui-shine-sweep var(--kui-shine-sweep-duration, 700ms) var(--kui-shine-sweep-ease, ease-out);\n }\n [data-kui-fx~=split-flap]:hover {\n animation: kui-split-flap var(--kui-split-flap-duration, 600ms) var(--kui-split-flap-ease, ease-in-out);\n }\n [data-kui-fx~=border-draw]:hover {\n --kui-border-pct: 100%;\n }\n [data-kui-fx~=border-glow]:hover {\n box-shadow: 0 0 0 3px var(--kui-border-glow-color, var(--accent, #d2691e));\n }\n [data-kui-fx~=beam-border]:hover::before {\n opacity: 1;\n animation: kui-beam-rotate var(--kui-beam-border-duration, 4260ms) linear infinite;\n }\n [data-kui-fx~=underline-slide]:hover::after {\n scale: 1 1;\n }\n [data-kui-fx~=underline-center]:hover::after {\n scale: 1 1;\n }\n [data-kui-fx~=icon-wiggle]:hover {\n animation: kui-icon-wiggle var(--kui-icon-wiggle-duration, 500ms) var(--kui-icon-wiggle-ease, ease-in-out);\n }\n [data-kui-fx~=icon-spin]:hover {\n animation: kui-icon-spin var(--kui-icon-spin-duration, 700ms) linear;\n }\n [data-kui-fx~=icon-bounce]:hover {\n animation: kui-icon-bounce var(--kui-icon-bounce-duration, 500ms) var(--kui-icon-bounce-ease, ease-out);\n }\n }\n [data-kui-fx~=tilt-3d],\n [data-kui-fx~=tilt-parallax] {\n transform-style: preserve-3d;\n }\n [data-kui-fx~=cursor-spotlight]::before {\n content: \"\";\n position: absolute;\n inset: 0;\n border-radius: inherit;\n pointer-events: none;\n opacity: var(--kui-spotlight-opacity, 0);\n transition: opacity 200ms ease-out;\n background:\n radial-gradient(\n circle 160px at var(--kui-x, 50%) var(--kui-y, 50%),\n color-mix(in srgb, var(--accent, #d2691e) 30%, transparent),\n transparent 70%);\n }\n .kui-cursor-dot {\n position: fixed;\n top: 0;\n left: 0;\n z-index: 9999;\n display: grid;\n place-items: center;\n pointer-events: none;\n opacity: 0;\n transition: opacity 160ms ease-out;\n }\n .kui-cursor-dot-active {\n opacity: 1;\n }\n .kui-cursor-dot-follow,\n .kui-cursor-dot-lag,\n .kui-cursor-dot-invert {\n width: 14px;\n height: 14px;\n margin: -7px 0 0 -7px;\n border-radius: 50%;\n background: var(--accent, #d2691e);\n }\n .kui-cursor-dot-invert {\n background: var(--kui-invert-color, #fff);\n mix-blend-mode: difference;\n }\n .kui-cursor-dot-label {\n margin: -1.4em 0 0 -1.4em;\n padding: 0.4em 0.8em;\n border-radius: 999px;\n background: var(--accent, #d2691e);\n color: var(--kui-label-color, #fff);\n font-size: 0.75rem;\n font-family:\n ui-monospace,\n Menlo,\n monospace;\n white-space: nowrap;\n }\n @media (pointer: coarse) {\n .kui-cursor-dot {\n display: none;\n }\n }\n}\n\n/* src/css/layout.css */\n@layer kui.effects {\n [data-kui-fx~=accordion-height] {\n overflow: hidden;\n }\n [data-kui-fx~=accordion-height]:not([data-open]) {\n height: 0;\n }\n}\n\n/* src/css/svg.css */\n@layer kui.effects {\n @keyframes kui-draw-stroke {\n from {\n stroke-dashoffset: var(--kui-path-length, 100);\n }\n to {\n stroke-dashoffset: 0;\n }\n }\n @keyframes kui-draw-signature {\n from {\n stroke-dashoffset: var(--kui-path-length, 100);\n }\n to {\n stroke-dashoffset: 0;\n }\n }\n @keyframes kui-draw-underline {\n from {\n stroke-dashoffset: var(--kui-path-length, 100);\n }\n to {\n stroke-dashoffset: 0;\n }\n }\n @keyframes kui-checkmark-draw {\n from {\n stroke-dashoffset: var(--kui-path-length, 100);\n }\n to {\n stroke-dashoffset: 0;\n }\n }\n @keyframes kui-cross-draw {\n from {\n stroke-dashoffset: var(--kui-path-length, 100);\n }\n to {\n stroke-dashoffset: 0;\n }\n }\n @keyframes kui-chart-line-draw {\n from {\n stroke-dashoffset: var(--kui-path-length, 100);\n }\n to {\n stroke-dashoffset: 0;\n }\n }\n [data-kui-fx~=draw-stroke],\n [data-kui-fx~=draw-signature],\n [data-kui-fx~=draw-underline],\n [data-kui-fx~=checkmark-draw],\n [data-kui-fx~=cross-draw],\n [data-kui-fx~=chart-line-draw] {\n stroke-dasharray: var(--kui-path-length, 100);\n fill: none;\n }\n @keyframes kui-gradient-stroke {\n from {\n stroke: var(--kui-stroke-from, currentColor);\n }\n 50% {\n stroke: var(--kui-stroke-via, currentColor);\n }\n to {\n stroke: var(--kui-stroke-to, currentColor);\n }\n }\n [data-kui-fx~=gradient-stroke] {\n --kui-fx-gradient-stroke-iterations: infinite;\n }\n @keyframes kui-heart-fill {\n from {\n clip-path: inset(100% 0 0 0);\n }\n to {\n clip-path: inset(0 0 0 0);\n }\n }\n @keyframes kui-bookmark-fill {\n from {\n clip-path: inset(100% 0 0 0);\n }\n to {\n clip-path: inset(0 0 0 0);\n }\n }\n @keyframes kui-chart-area-fill {\n from {\n clip-path: inset(0 100% 0 0);\n }\n to {\n clip-path: inset(0 0 0 0);\n }\n }\n @keyframes kui-chart-bar-grow {\n from {\n scale: 1 var(--kui-bar-from, 0);\n }\n to {\n scale: 1 1;\n }\n }\n [data-kui-fx~=chart-bar-grow] {\n transform-origin: bottom center;\n }\n [data-kui-fx~=chart-bar-grow][data-kui-state=ready] {\n --kui-bar-from: 1 !important;\n opacity: 0 !important;\n }\n @keyframes kui-logo-build {\n from {\n opacity: 0;\n scale: 0.62;\n rotate: -8deg;\n }\n to {\n opacity: 1;\n scale: 1;\n rotate: 0deg;\n }\n }\n [data-kui-fx~=hamburger-to-x] .kui-bar {\n transition:\n translate var(--kui-icon-toggle-duration, 260ms) var(--kui-icon-toggle-ease, ease-out),\n rotate var(--kui-icon-toggle-duration, 260ms) var(--kui-icon-toggle-ease, ease-out),\n opacity var(--kui-icon-toggle-duration, 260ms) var(--kui-icon-toggle-ease, ease-out);\n }\n [data-kui-fx~=hamburger-to-x][aria-expanded=true] .kui-bar:nth-child(1) {\n translate: 0 var(--kui-bar-gap, 6px);\n rotate: 45deg;\n }\n [data-kui-fx~=hamburger-to-x][aria-expanded=true] .kui-bar:nth-child(2) {\n opacity: 0;\n }\n [data-kui-fx~=hamburger-to-x][aria-expanded=true] .kui-bar:nth-child(3) {\n translate: 0 calc(var(--kui-bar-gap, 6px) * -1);\n rotate: -45deg;\n }\n [data-kui-fx~=play-to-pause] .kui-bar {\n transition: translate var(--kui-icon-toggle-duration, 260ms) var(--kui-icon-toggle-ease, ease-out), clip-path var(--kui-icon-toggle-duration, 260ms) var(--kui-icon-toggle-ease, ease-out);\n }\n [data-kui-fx~=play-to-pause]:not([aria-pressed=true]) .kui-bar:nth-child(1) {\n translate: var(--kui-bar-gap, 4px) 0;\n clip-path: polygon(0 0, 100% 25%, 100% 75%, 0 100%);\n }\n [data-kui-fx~=play-to-pause]:not([aria-pressed=true]) .kui-bar:nth-child(2) {\n translate: calc(var(--kui-bar-gap, 4px) * -1) 0;\n clip-path: polygon(0 25%, 100% 50%, 100% 50%, 0 75%);\n }\n [data-kui-fx~=plus-to-minus] {\n transition: rotate var(--kui-icon-toggle-duration, 260ms) var(--kui-icon-toggle-ease, ease-out);\n }\n [data-kui-fx~=plus-to-minus] .kui-bar {\n transition: scale var(--kui-icon-toggle-duration, 260ms) var(--kui-icon-toggle-ease, ease-out);\n }\n [data-kui-fx~=plus-to-minus] .kui-bar:nth-child(2) {\n rotate: 90deg;\n }\n [data-kui-fx~=plus-to-minus][aria-expanded=true] {\n rotate: 90deg;\n }\n [data-kui-fx~=plus-to-minus][aria-expanded=true] .kui-bar:nth-child(1) {\n scale: 0;\n }\n}\n\n/* src/css/index.css */\n"
5375
6411
  document.head.appendChild(style)
5376
6412
  }
5377
6413
  window.__kuinetic = kuinetic.kuinetic({ observe: true }).start()