@opendata-ai/openchart-vanilla 8.2.3 → 8.3.1

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.
@@ -236,7 +236,7 @@ interface MountOptions extends ChartEventHandlers {
236
236
  onDataPointClick?: (data: Record<string, unknown>) => void;
237
237
  /** Enable responsive resizing. Defaults to true. */
238
238
  responsive?: boolean;
239
- /** Show the tryOpenData.ai watermark. Defaults to true. */
239
+ /** Show the OpenData watermark. Defaults to true. */
240
240
  watermark?: boolean;
241
241
  /** Initial selected element. */
242
242
  selectedElement?: ElementRef;
@@ -18,7 +18,7 @@
18
18
  return cached;
19
19
  }
20
20
  target = mod != null ? __create(__getProtoOf(mod)) : {};
21
- const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
21
+ const to = isNodeMode || !mod || !mod.__esModule || !__hasOwnProp.call(mod, "default") ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
22
22
  if (mod && typeof mod === "object" || typeof mod === "function") {
23
23
  for (let key of __getOwnPropNames(mod))
24
24
  if (!__hasOwnProp.call(to, key))
@@ -77,7 +77,7 @@
77
77
  function add(tree, x, y, d) {
78
78
  if (isNaN(x) || isNaN(y))
79
79
  return tree;
80
- var parent, node = tree._root, leaf = { data: d }, x0 = tree._x0, y0 = tree._y0, x1 = tree._x1, y1 = tree._y1, xm, ym, xp, yp, right, bottom, i, j;
80
+ var parent, node = tree._root, leaf = { data: d }, { _x0: x0, _y0: y0, _x1: x1, _y1: y1 } = tree, xm, ym, xp, yp, right, bottom, i, j;
81
81
  if (!node)
82
82
  return tree._root = leaf, tree;
83
83
  while (node.length) {
@@ -455,17 +455,17 @@
455
455
  var { data, r: rj } = quad, r = ri + rj;
456
456
  if (data) {
457
457
  if (data.index > node.index) {
458
- var x2 = xi - data.x - data.vx, y2 = yi - data.y - data.vy, l = x2 * x2 + y2 * y2;
458
+ var x = xi - data.x - data.vx, y = yi - data.y - data.vy, l = x * x + y * y;
459
459
  if (l < r * r) {
460
- if (x2 === 0)
461
- x2 = jiggle_default(random), l += x2 * x2;
462
- if (y2 === 0)
463
- y2 = jiggle_default(random), l += y2 * y2;
460
+ if (x === 0)
461
+ x = jiggle_default(random), l += x * x;
462
+ if (y === 0)
463
+ y = jiggle_default(random), l += y * y;
464
464
  l = (r - (l = Math.sqrt(l))) / l * strength;
465
- node.vx += (x2 *= l) * (r = (rj *= rj) / (ri2 + rj));
466
- node.vy += (y2 *= l) * r;
467
- data.vx -= x2 * (r = 1 - r);
468
- data.vy -= y2 * r;
465
+ node.vx += (x *= l) * (r = (rj *= rj) / (ri2 + rj));
466
+ node.vy += (y *= l) * r;
467
+ data.vx -= x * (r = 1 - r);
468
+ data.vy -= y * r;
469
469
  }
470
470
  }
471
471
  return;
@@ -525,24 +525,24 @@
525
525
  }
526
526
  function force(alpha) {
527
527
  for (var k = 0, n = links.length;k < iterations; ++k) {
528
- for (var i = 0, link, source, target, x2, y2, l, b;i < n; ++i) {
528
+ for (var i = 0, link, source, target, x, y, l, b;i < n; ++i) {
529
529
  link = links[i], source = link.source, target = link.target;
530
- x2 = target.x + target.vx - source.x - source.vx || jiggle_default(random);
531
- y2 = target.y + target.vy - source.y - source.vy || jiggle_default(random);
532
- l = Math.sqrt(x2 * x2 + y2 * y2);
530
+ x = target.x + target.vx - source.x - source.vx || jiggle_default(random);
531
+ y = target.y + target.vy - source.y - source.vy || jiggle_default(random);
532
+ l = Math.sqrt(x * x + y * y);
533
533
  l = (l - distances[i]) / l * alpha * strengths[i];
534
- x2 *= l, y2 *= l;
535
- target.vx -= x2 * (b = bias[i]);
536
- target.vy -= y2 * b;
537
- source.vx += x2 * (b = 1 - b);
538
- source.vy += y2 * b;
534
+ x *= l, y *= l;
535
+ target.vx -= x * (b = bias[i]);
536
+ target.vy -= y * b;
537
+ source.vx += x * (b = 1 - b);
538
+ source.vy += y * b;
539
539
  }
540
540
  }
541
541
  }
542
542
  function initialize() {
543
543
  if (!nodes)
544
544
  return;
545
- var i, n = nodes.length, m = links.length, nodeById = new Map(nodes.map((d, i2) => [id(d, i2, nodes), d])), link;
545
+ var i, n = nodes.length, m = links.length, nodeById = new Map(nodes.map((d, i) => [id(d, i, nodes), d])), link;
546
546
  for (i = 0, count = new Array(n);i < m; ++i) {
547
547
  link = links[i], link.index = i;
548
548
  if (typeof link.source !== "object")
@@ -755,9 +755,9 @@
755
755
  }
756
756
  }
757
757
  function poke() {
758
- var now2 = clock.now(), delay = now2 - clockLast;
758
+ var now = clock.now(), delay = now - clockLast;
759
759
  if (delay > pokeDelay)
760
- clockSkew -= delay, clockLast = now2;
760
+ clockSkew -= delay, clockLast = now;
761
761
  }
762
762
  function nap() {
763
763
  var t0, t1 = taskHead, t2, time = Infinity;
@@ -899,7 +899,7 @@
899
899
  force: function(name, _) {
900
900
  return arguments.length > 1 ? (_ == null ? forces.delete(name) : forces.set(name, initializeForce(_)), simulation) : forces.get(name);
901
901
  },
902
- find: function(x3, y3, radius) {
902
+ find: function(x, y, radius) {
903
903
  var i = 0, n = nodes.length, dx, dy, d2, node, closest;
904
904
  if (radius == null)
905
905
  radius = Infinity;
@@ -907,8 +907,8 @@
907
907
  radius *= radius;
908
908
  for (i = 0;i < n; ++i) {
909
909
  node = nodes[i];
910
- dx = x3 - node.x;
911
- dy = y3 - node.y;
910
+ dx = x - node.x;
911
+ dy = y - node.y;
912
912
  d2 = dx * dx + dy * dy;
913
913
  if (d2 < radius)
914
914
  closest = node, radius = d2;
@@ -932,62 +932,62 @@
932
932
  function initialize() {
933
933
  if (!nodes)
934
934
  return;
935
- var i, n = nodes.length, node2;
935
+ var i, n = nodes.length, node;
936
936
  strengths = new Array(n);
937
937
  for (i = 0;i < n; ++i)
938
- node2 = nodes[i], strengths[node2.index] = +strength(node2, i, nodes);
938
+ node = nodes[i], strengths[node.index] = +strength(node, i, nodes);
939
939
  }
940
940
  function accumulate(quad) {
941
- var strength2 = 0, q, c2, weight = 0, x3, y3, i;
941
+ var strength = 0, q, c, weight = 0, x, y, i;
942
942
  if (quad.length) {
943
- for (x3 = y3 = i = 0;i < 4; ++i) {
944
- if ((q = quad[i]) && (c2 = Math.abs(q.value))) {
945
- strength2 += q.value, weight += c2, x3 += c2 * q.x, y3 += c2 * q.y;
943
+ for (x = y = i = 0;i < 4; ++i) {
944
+ if ((q = quad[i]) && (c = Math.abs(q.value))) {
945
+ strength += q.value, weight += c, x += c * q.x, y += c * q.y;
946
946
  }
947
947
  }
948
- quad.x = x3 / weight;
949
- quad.y = y3 / weight;
948
+ quad.x = x / weight;
949
+ quad.y = y / weight;
950
950
  } else {
951
951
  q = quad;
952
952
  q.x = q.data.x;
953
953
  q.y = q.data.y;
954
954
  do
955
- strength2 += strengths[q.data.index];
955
+ strength += strengths[q.data.index];
956
956
  while (q = q.next);
957
957
  }
958
- quad.value = strength2;
958
+ quad.value = strength;
959
959
  }
960
- function apply(quad, x1, _, x22) {
960
+ function apply(quad, x1, _, x2) {
961
961
  if (!quad.value)
962
962
  return true;
963
- var x3 = quad.x - node.x, y3 = quad.y - node.y, w = x22 - x1, l = x3 * x3 + y3 * y3;
963
+ var x = quad.x - node.x, y = quad.y - node.y, w = x2 - x1, l = x * x + y * y;
964
964
  if (w * w / theta2 < l) {
965
965
  if (l < distanceMax2) {
966
- if (x3 === 0)
967
- x3 = jiggle_default(random), l += x3 * x3;
968
- if (y3 === 0)
969
- y3 = jiggle_default(random), l += y3 * y3;
966
+ if (x === 0)
967
+ x = jiggle_default(random), l += x * x;
968
+ if (y === 0)
969
+ y = jiggle_default(random), l += y * y;
970
970
  if (l < distanceMin2)
971
971
  l = Math.sqrt(distanceMin2 * l);
972
- node.vx += x3 * quad.value * alpha / l;
973
- node.vy += y3 * quad.value * alpha / l;
972
+ node.vx += x * quad.value * alpha / l;
973
+ node.vy += y * quad.value * alpha / l;
974
974
  }
975
975
  return true;
976
976
  } else if (quad.length || l >= distanceMax2)
977
977
  return;
978
978
  if (quad.data !== node || quad.next) {
979
- if (x3 === 0)
980
- x3 = jiggle_default(random), l += x3 * x3;
981
- if (y3 === 0)
982
- y3 = jiggle_default(random), l += y3 * y3;
979
+ if (x === 0)
980
+ x = jiggle_default(random), l += x * x;
981
+ if (y === 0)
982
+ y = jiggle_default(random), l += y * y;
983
983
  if (l < distanceMin2)
984
984
  l = Math.sqrt(distanceMin2 * l);
985
985
  }
986
986
  do
987
987
  if (quad.data !== node) {
988
988
  w = strengths[quad.data.index] * alpha / l;
989
- node.vx += x3 * w;
990
- node.vy += y3 * w;
989
+ node.vx += x * w;
990
+ node.vy += y * w;
991
991
  }
992
992
  while (quad = quad.next);
993
993
  }
@@ -1011,10 +1011,10 @@
1011
1011
  return force;
1012
1012
  }
1013
1013
  // ../../node_modules/.bun/d3-force@3.0.0/node_modules/d3-force/src/x.js
1014
- function x_default2(x3) {
1014
+ function x_default2(x) {
1015
1015
  var strength = constant_default(0.1), nodes, strengths, xz;
1016
- if (typeof x3 !== "function")
1017
- x3 = constant_default(x3 == null ? 0 : +x3);
1016
+ if (typeof x !== "function")
1017
+ x = constant_default(x == null ? 0 : +x);
1018
1018
  function force(alpha) {
1019
1019
  for (var i = 0, n = nodes.length, node;i < n; ++i) {
1020
1020
  node = nodes[i], node.vx += (xz[i] - node.x) * strengths[i] * alpha;
@@ -1027,7 +1027,7 @@
1027
1027
  strengths = new Array(n);
1028
1028
  xz = new Array(n);
1029
1029
  for (i = 0;i < n; ++i) {
1030
- strengths[i] = isNaN(xz[i] = +x3(nodes[i], i, nodes)) ? 0 : +strength(nodes[i], i, nodes);
1030
+ strengths[i] = isNaN(xz[i] = +x(nodes[i], i, nodes)) ? 0 : +strength(nodes[i], i, nodes);
1031
1031
  }
1032
1032
  }
1033
1033
  force.initialize = function(_) {
@@ -1038,15 +1038,15 @@
1038
1038
  return arguments.length ? (strength = typeof _ === "function" ? _ : constant_default(+_), initialize(), force) : strength;
1039
1039
  };
1040
1040
  force.x = function(_) {
1041
- return arguments.length ? (x3 = typeof _ === "function" ? _ : constant_default(+_), initialize(), force) : x3;
1041
+ return arguments.length ? (x = typeof _ === "function" ? _ : constant_default(+_), initialize(), force) : x;
1042
1042
  };
1043
1043
  return force;
1044
1044
  }
1045
1045
  // ../../node_modules/.bun/d3-force@3.0.0/node_modules/d3-force/src/y.js
1046
- function y_default2(y3) {
1046
+ function y_default2(y) {
1047
1047
  var strength = constant_default(0.1), nodes, strengths, yz;
1048
- if (typeof y3 !== "function")
1049
- y3 = constant_default(y3 == null ? 0 : +y3);
1048
+ if (typeof y !== "function")
1049
+ y = constant_default(y == null ? 0 : +y);
1050
1050
  function force(alpha) {
1051
1051
  for (var i = 0, n = nodes.length, node;i < n; ++i) {
1052
1052
  node = nodes[i], node.vy += (yz[i] - node.y) * strengths[i] * alpha;
@@ -1059,7 +1059,7 @@
1059
1059
  strengths = new Array(n);
1060
1060
  yz = new Array(n);
1061
1061
  for (i = 0;i < n; ++i) {
1062
- strengths[i] = isNaN(yz[i] = +y3(nodes[i], i, nodes)) ? 0 : +strength(nodes[i], i, nodes);
1062
+ strengths[i] = isNaN(yz[i] = +y(nodes[i], i, nodes)) ? 0 : +strength(nodes[i], i, nodes);
1063
1063
  }
1064
1064
  }
1065
1065
  force.initialize = function(_) {
@@ -1070,7 +1070,7 @@
1070
1070
  return arguments.length ? (strength = typeof _ === "function" ? _ : constant_default(+_), initialize(), force) : strength;
1071
1071
  };
1072
1072
  force.y = function(_) {
1073
- return arguments.length ? (y3 = typeof _ === "function" ? _ : constant_default(+_), initialize(), force) : y3;
1073
+ return arguments.length ? (y = typeof _ === "function" ? _ : constant_default(+_), initialize(), force) : y;
1074
1074
  };
1075
1075
  return force;
1076
1076
  }
@@ -1083,14 +1083,14 @@
1083
1083
  for (const node of nodes) {
1084
1084
  if (!node.community)
1085
1085
  continue;
1086
- const c2 = node.community;
1087
- cx.set(c2, (cx.get(c2) ?? 0) + (node.x ?? 0));
1088
- cy.set(c2, (cy.get(c2) ?? 0) + (node.y ?? 0));
1089
- count.set(c2, (count.get(c2) ?? 0) + 1);
1086
+ const c = node.community;
1087
+ cx.set(c, (cx.get(c) ?? 0) + (node.x ?? 0));
1088
+ cy.set(c, (cy.get(c) ?? 0) + (node.y ?? 0));
1089
+ count.set(c, (count.get(c) ?? 0) + 1);
1090
1090
  }
1091
- for (const [c2, n] of count) {
1092
- cx.set(c2, cx.get(c2) / n);
1093
- cy.set(c2, cy.get(c2) / n);
1091
+ for (const [c, n] of count) {
1092
+ cx.set(c, cx.get(c) / n);
1093
+ cy.set(c, cy.get(c) / n);
1094
1094
  }
1095
1095
  const k = strength * alpha;
1096
1096
  for (const node of nodes) {
package/dist/static.js CHANGED
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  renderTileMapSVG
3
- } from "./chunk-ZKASH7AX.js";
3
+ } from "./chunk-ERRV4WFS.js";
4
4
  import {
5
5
  renderChartSVG,
6
6
  resetSvgIdCounter
7
- } from "./chunk-2CEKMIJH.js";
7
+ } from "./chunk-W76C53MC.js";
8
8
  import {
9
9
  SVG_NS,
10
10
  buildThemeStyleBlock
@@ -1,5 +1,5 @@
1
- import { h as CameraTarget, M as MountOptions } from '../mount-Djb1VvKO.js';
2
- export { C as Camera, F as FULL_VIEW, V as ViewBoxSize, i as cameraTransform, j as camerasClose, k as damp, l as dampCamera, m as fitTarget, n as interpolateCamera, s as scrubCamera } from '../mount-Djb1VvKO.js';
1
+ import { h as CameraTarget, M as MountOptions } from '../mount-Bs8nFSf1.js';
2
+ export { C as Camera, F as FULL_VIEW, V as ViewBoxSize, i as cameraTransform, j as camerasClose, k as damp, l as dampCamera, m as fitTarget, n as interpolateCamera, s as scrubCamera } from '../mount-Bs8nFSf1.js';
3
3
  import { DataRow, ChartSpec, LayerSpec, GraphSpec, GeoMapSpec, ChartLayout } from '@opendata-ai/openchart-core';
4
4
  import '../export-gif.js';
5
5
 
@@ -17,9 +17,9 @@ import {
17
17
  lerp,
18
18
  scrubCamera,
19
19
  storyMotion
20
- } from "../chunk-WG6NOQVC.js";
20
+ } from "../chunk-GRA2NIRZ.js";
21
21
  import "../chunk-T32UHMZA.js";
22
- import "../chunk-2CEKMIJH.js";
22
+ import "../chunk-W76C53MC.js";
23
23
  import "../chunk-RM5XS6NR.js";
24
24
 
25
25
  // src/story/create-chart-story.ts
@@ -1 +1 @@
1
- {"version":3,"mappings":"AAWA,iBCEE,62DGFA,4lBJAF,eQNE,mIAeA,6BAQA,qEAUA,yDAOA,uCAIA,qCAWA,8IAgBA,qGAcA,4EAQA,yFRvFF,qBWNE,6CAIA,2KAQA,wIAOA,+GAMA,+HAQA,wFAOA,oDAYA,8CAIA,wHAQA,4HAQA,2EAMA,6EAMA,4EAWA,8EAgBA,sDAIA,sEAMA,4EAIA,wEAaA,sFAUA,sFASA,gCAMA,mFGhKA,ogBAsBE,4FAOA,iFAOA,gMAWA,iGAMA,0EAKA,mHAQA,yJAUA,oKAUA,uMAkBF,qFAOA,4FDlHA,2EAKA,gCAIA,2CEJA,kJAaA,iHASA,wDAIA,sRAeA,6RAoBA,uFAKA,iGAKA,gDAMA,qEAMA,oIAWA,0DAKA,2RAiBA,yKAWA,0GAMA,wCAIA,mFbtIA,kDAKA,+CAKA,qGASA,wHAUA,yGAWA,qFAKA,0MAYA,oRAeA,6DAOA,mXAoBA,0DAIA,yFAKA,yDIpHA,iGAKE,qFAMA,yDAIA,4DAKA,gGAAA,gGAOA,oJASA,gFAOA,mDAIA,sEAKA,iFAKA,2CAKF,sNAOA,kPAOA,2IAKA,gJAKA,iCASE,0FAAA,0FAaF,oLAYE,mLAAA,kLAaA,yFAKA,qFAKA,4CAAA,2CAOA,+FAKA,6DAMA,4FAKA,+DAaF,iPAaA,wFAAA,8EAAA,yFAAA,+EAMA,+IAOA,+BAGE,wCASF,oJAQE,6OAaE,oEAKA,2GAKA,+FAOJ,4DAIA,+CASA,gCAIA,iHAUA,gDASA,+DAKE,kEAOF,iFAOA,mGAWA,2DAIE,qCAKF,8CAQA,+BASE,qDAAA,qDAMA,qCAUA,6CAIA,kEASF,2EASA,oHGjYA,qIASA,kEAOA,2CAIA,4GASE,8bAkBA,2RAaF,qPAcA,qLAiBA,6DAIE,kEAIA,+FAOF,4CAIA,iCAIA,0HAOA,+EAQA,sEAMA,oDAKE,0OAUE,2GAQJ,qEAYA,iKNrKA,oEHCF,oBKJI,4JAMA,4JAOA,8NAOA,yOAOA,wRAAA,yRAcA,4RAaA,uRAYA,4RAAA,+RAaA,uKAAA,2KE/EF,8GAgBA,kHAgBA,iHAeA,4FAgBA,8IAaA,iGAaA,yDAUA,sGAaA,uFAWA,yFAUA,sGGpIE,yLAAA,wLAOA,qFAAA,oFASA,oRAYA,8MAOA,8MASA,kNAUA,qOAAA,sOAQA,+JAAA,+JAWA,8NAOA,8NAOA,8NAOA,iMAWA,sKAOA,wJAQA,gLASA,8JAKA,+EAKA,2KAQA,mQAYA,0NAQA,8PAYA,uLAMA,6KAeF,wJVrMF,yBYDE,uCACE,6LAAA,+LAAA,qMAAA","sources":["../src/styles/index.css","../src/styles/tokens.css","../src/styles/you-draw-it.css","../src/styles/sparkline.css","../src/styles/dark.css","../src/styles/table-animation.css","../src/styles/table.css","../src/styles/keyframes.css","../src/styles/base.css","../src/styles/graph.css","../src/styles/animation.css","../src/styles/chrome.css","../src/styles/reduced-motion.css","../src/styles/legend.css","../src/styles/tooltip.css","../src/styles/series-search.css"],"sourcesContent":["/**\n * @opendata-ai/openchart-core styles\n *\n * CSS with oc- prefix for all class names.\n * CSS custom properties for theme overrides.\n * Dark mode via .oc-dark class on the container.\n * Cascade layers: oc.tokens, oc.base, oc.components, oc.animation, oc.reduced-motion.\n */\n\n/* For optimal typography, load Inter: https://fonts.google.com/specimen/Inter */\n\n@layer oc.tokens, oc.base, oc.components, oc.animation, oc.reduced-motion;\n\n@import \"./tokens.css\";\n@import \"./dark.css\";\n@import \"./base.css\";\n@import \"./chrome.css\";\n@import \"./tooltip.css\";\n@import \"./legend.css\";\n@import \"./series-search.css\";\n@import \"./you-draw-it.css\";\n@import \"./table.css\";\n@import \"./table-animation.css\";\n@import \"./graph.css\";\n@import \"./sparkline.css\";\n@import \"./keyframes.css\";\n@import \"./animation.css\";\n@import \"./reduced-motion.css\";\n","/* GENERATED FILE — do not edit. Source: packages/core/src/styles/token-definitions.ts. Regenerate: bun run generate:tokens */\n\n@layer oc.tokens {\n /* ---------------------------------------------------------------------------\n * Custom properties (light mode defaults)\n *\n * These are FALLBACK defaults. At runtime, the JS theme engine stamps the\n * resolved theme as inline --oc-* custom properties on each .oc-root\n * container (see packages/vanilla/src/theme-tokens.ts). These CSS values\n * serve as fallbacks for contexts where JS hasn't mounted yet (SSR, static\n * HTML examples).\n * --------------------------------------------------------------------------- */\n\n .oc-root,\n .oc-chart-root,\n .oc-table-wrapper,\n .oc-table-root,\n .oc-graph-wrapper,\n .oc-graph-root,\n .oc-sankey-root,\n .oc-tilemap-root,\n .oc-barlist-root,\n .oc-map-root {\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n\n /* Opt out of iOS text auto-inflation so measured widths match rendered text. */\n -webkit-text-size-adjust: 100%;\n text-size-adjust: 100%;\n\n --oc-font-family:\n \"Inter Variable\", Inter, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n --oc-font-mono: \"JetBrains Mono\", \"Fira Code\", \"Cascadia Code\", monospace;\n\n /* Animation easing presets via CSS linear() */\n --oc-ease-smooth: linear(\n 0,\n 0.157,\n 0.438,\n 0.64,\n 0.766,\n 0.85,\n 0.906,\n 0.941,\n 0.964,\n 0.978,\n 0.988,\n 0.994,\n 0.998,\n 1\n );\n --oc-ease-snappy: linear(\n 0,\n 0.012,\n 0.048,\n 0.108,\n 0.194,\n 0.302,\n 0.426,\n 0.559,\n 0.69,\n 0.808,\n 0.905,\n 0.973,\n 1.013,\n 1.028,\n 1.023,\n 1.006,\n 0.984,\n 0.966,\n 0.957,\n 0.957,\n 0.964,\n 0.975,\n 0.986,\n 0.995,\n 1,\n 1.003,\n 1.002,\n 1,\n 0.998,\n 0.998,\n 0.999,\n 1\n );\n\n /* Animation timing defaults */\n --oc-animation-duration: 500ms;\n --oc-animation-stagger: 80ms;\n --oc-annotation-delay: 200ms;\n\n /* Typography scale (editorial design system) */\n --oc-title-size: 26px;\n --oc-title-weight: 590;\n --oc-title-tracking: -0.022em;\n --oc-subtitle-size: 14px;\n --oc-subtitle-weight: 450;\n --oc-source-size: 11px;\n --oc-source-weight: 450;\n --oc-body-size: 13px;\n --oc-eyebrow-size: 11px;\n --oc-eyebrow-weight: 550;\n --oc-eyebrow-tracking: 0.08em;\n\n /* Surfaces (light mode defaults) */\n --oc-bg: #ffffff;\n --oc-card: #ffffff;\n --oc-secondary: #f4f4f5; /* zinc-100, raised surface */\n\n /*\n * Text levels. Names invert across modes: in light mode \"muted\" sits at\n * a lighter zinc step than \"subtle\" because both are picked relative to\n * the active background, not from a fixed lightness ladder. The intent\n * is \"muted = first step away from primary text\"; \"subtle = next step\n * down\"; etc.\n *\n * Light mode: text=zinc-950, secondary=zinc-700, muted=zinc-500,\n * subtle=zinc-400, faint=zinc-300\n * Dark mode (dark.css): inverts the surface tokens but keeps the same\n * muted -> subtle -> faint progression away from primary.\n */\n --oc-text: #09090b;\n --oc-text-secondary: #3f3f46;\n --oc-text-muted: #71717a;\n --oc-text-faint: #d4d4d8;\n\n /* Lines */\n --oc-gridline: rgba(0, 0, 0, 0.1);\n --oc-axis: rgba(0, 0, 0, 0.1);\n --oc-border: rgba(0, 0, 0, 0.08);\n --oc-border-radius: 2px;\n\n /* Brand and semantic */\n --oc-accent: #06b6d4;\n --oc-accent-strong: #0891b2; /* darker cyan for line strokes on light bg */\n --oc-positive: #10b981;\n --oc-negative: #e11d48;\n --oc-focus: #3b82f6;\n /* static, intentionally NOT derived from --oc-focus and NOT flipped in dark mode */\n --oc-focus-ring: rgba(59, 130, 246, 0.1);\n --oc-focus-ring-strong: rgba(59, 130, 246, 0.25);\n --oc-editable-hover: rgba(79, 70, 229, 0.35); /* edit-mode hover outline, indigo one-off */\n\n /* Spacing scale (4px base) — only --oc-space-2/4 are consumed (JS-stamped) */\n --oc-space-2: 8px;\n --oc-space-4: 16px;\n\n /* Interactive states */\n --oc-hover-bg: rgba(0, 0, 0, 0.025);\n --oc-tooltip-bg: rgba(255, 255, 255, 0.88);\n --oc-tooltip-border: rgba(0, 0, 0, 0.08);\n --oc-tooltip-shadow: 0 2px 8px rgba(0, 0, 0, 0.08), 0 0 1px rgba(0, 0, 0, 0.12);\n --oc-tooltip-text: #09090b;\n --oc-legend-text: #3f3f46;\n }\n}\n","@layer oc.components {\n /* ---------------------------------------------------------------------------\n * You draw it (youDrawIt)\n *\n * NYT-style draw-then-reveal. SVG-space elements (hatched region, guess path,\n * reveal clip) render inside the chart SVG; the prompt + skip-to-reveal button\n * are an absolutely-positioned HTML overlay the vanilla adapter sizes over the\n * drawing region (inline left/top/width/height). All colors come from --oc-*\n * tokens so they flip in .oc-dark.\n * --------------------------------------------------------------------------- */\n\n /* Hatched \"draw here\" region. Fill comes from an SVG <pattern> (line color =\n * the target series color); this only governs overall opacity + fade-out. */\n .oc-ydi-region {\n opacity: 0.35;\n transition: opacity 0.4s ease;\n }\n\n .oc-ydi-region[data-ydi-hidden=\"true\"] {\n opacity: 0;\n }\n\n /* The vertical rule at `from` where drawing begins. */\n .oc-ydi-boundary {\n stroke: var(--oc-text-muted);\n stroke-width: 1;\n stroke-dasharray: 3 3;\n stroke-opacity: 0.6;\n }\n\n /* Reader's guess: a distinct pen-like stroke that reads as \"yours\" against the\n * solid real line. Dashed + focus-blue so it stays legible in both modes. */\n .oc-ydi-guess {\n stroke: var(--oc-focus);\n stroke-width: 2.5;\n stroke-linecap: round;\n stroke-linejoin: round;\n stroke-dasharray: 1 6;\n }\n\n /* Host-supplied comparison line (\"what everyone else guessed\"). Muted so it\n * sits behind the reader's guess and the real line. */\n .oc-ydi-comparison {\n stroke: var(--oc-text-muted);\n stroke-width: 1.5;\n stroke-opacity: 0.5;\n stroke-dasharray: 4 4;\n }\n\n /* Reveal clip rect: the width animates from the `from` boundary to the full\n * area on reveal, wiping the real line in left-to-right. The vanilla adapter\n * adds .oc-ydi-clip-animate right before setting the final width; reduced\n * motion skips the class so the width snaps. */\n .oc-ydi-clip-rect.oc-ydi-clip-animate {\n transition: width 0.7s cubic-bezier(0.22, 1, 0.36, 1);\n }\n\n /* HTML controls overlay: prompt (top) + reveal button (bottom-right). */\n .oc-ydi-controls {\n display: flex;\n flex-direction: column;\n justify-content: space-between;\n align-items: flex-end;\n pointer-events: none;\n font-family: var(--oc-font-family);\n padding: 8px;\n box-sizing: border-box;\n z-index: 10;\n }\n\n .oc-ydi-prompt {\n align-self: center;\n max-width: 100%;\n padding: 6px 12px;\n border-radius: 6px;\n background: var(--oc-card);\n border: 1px solid var(--oc-border);\n color: var(--oc-text-secondary);\n font-size: 13px;\n font-weight: 500;\n line-height: 16px;\n text-align: center;\n box-shadow: var(--oc-tooltip-shadow);\n }\n\n .oc-ydi-controls.oc-ydi-revealed .oc-ydi-prompt {\n display: none;\n }\n\n /* Skip-to-reveal button. pointer-events re-enabled (the overlay disables it)\n * so it stays clickable and keyboard-reachable. Min height enforced inline by\n * the adapter (>= 24px effective touch target). */\n .oc-ydi-reveal-button {\n pointer-events: auto;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n padding: 6px 14px;\n border: 1px solid var(--oc-border);\n border-radius: 6px;\n background: var(--oc-bg);\n color: var(--oc-text);\n font-family: inherit;\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n box-shadow: var(--oc-tooltip-shadow);\n transition:\n background-color 0.15s,\n border-color 0.15s;\n }\n\n .oc-ydi-reveal-button:hover {\n background: var(--oc-hover-bg);\n }\n\n .oc-ydi-reveal-button:focus-visible {\n outline: 2px solid var(--oc-focus);\n outline-offset: 2px;\n }\n\n .oc-ydi-reveal-button:disabled {\n opacity: 0.5;\n cursor: default;\n }\n}\n","@layer oc.components {\n /**\n * Sparkline display mode.\n *\n * Stamped on the SVG root as data-display=\"sparkline\" by the renderer when\n * the spec sets display: 'sparkline'. Strips any inherited padding/margin\n * so the mark renders truly edge-to-edge in tight container layouts (KPI\n * cards, table cells, dashboard tiles).\n */\n\n .oc-chart[data-display=\"sparkline\"] {\n display: block;\n margin: 0;\n padding: 0;\n }\n}\n","/* GENERATED FILE — do not edit. Source: packages/core/src/styles/token-definitions.ts. Regenerate: bun run generate:tokens */\n\n@layer oc.tokens {\n /* ---------------------------------------------------------------------------\n * Dark mode overrides (fallback defaults)\n *\n * At runtime, the JS theme engine stamps dark-adapted --oc-* custom\n * properties on each .oc-root container. These CSS values serve as\n * fallbacks for contexts where JS hasn't mounted yet.\n * --------------------------------------------------------------------------- */\n\n .oc-dark {\n /* Surfaces (zinc-based achromatic ramp) */\n --oc-bg: #09090b;\n --oc-card: #111113;\n --oc-secondary: #27272a;\n\n /* Text levels — see tokens.css for the cross-mode naming rationale */\n --oc-text: #f7f8f8;\n --oc-text-secondary: #d0d6e0;\n --oc-text-muted: #a1a1aa;\n --oc-text-faint: #52525b;\n\n /* Lines */\n --oc-gridline: rgba(255, 255, 255, 0.05);\n --oc-axis: rgba(255, 255, 255, 0.1);\n --oc-border: rgba(255, 255, 255, 0.1);\n\n /* Brand and semantic — accent stays cyan (no darkening on dark bg) */\n --oc-accent: #06b6d4;\n --oc-accent-strong: #06b6d4;\n --oc-positive: #34d399;\n --oc-negative: #fb7185;\n --oc-focus: #60a5fa;\n\n /* Interactive states */\n --oc-hover-bg: rgba(255, 255, 255, 0.05);\n --oc-tooltip-bg: rgba(17, 17, 19, 0.92);\n --oc-tooltip-border: rgba(255, 255, 255, 0.08);\n --oc-tooltip-shadow: 0 2px 8px rgba(0, 0, 0, 0.3), 0 0 1px rgba(0, 0, 0, 0.4);\n --oc-tooltip-text: #f7f8f8;\n --oc-legend-text: #d0d6e0;\n }\n}\n","@layer oc.animation {\n /* ---------------------------------------------------------------------------\n * Table entrance animations (.oc-table-wrapper.oc-animate)\n * --------------------------------------------------------------------------- */\n\n .oc-table-wrapper.oc-animate {\n /* Chrome (title/subtitle): fade + slide up */\n & > .oc-chrome {\n animation: oc-enter-fade calc(var(--oc-animation-duration) * 0.6)\n var(--oc-animation-ease, var(--oc-ease-smooth)) both;\n }\n\n /* Table header: quick fade before rows start */\n & thead {\n animation: oc-enter-fade-only calc(var(--oc-animation-duration) * 0.4)\n var(--oc-animation-ease, var(--oc-ease-smooth)) both;\n }\n\n /* Row entrance: slide up only, no opacity (cells handle their own fading\n to avoid opacity compounding between row and cell animations) */\n & tbody tr {\n animation: oc-table-enter-row var(--oc-animation-duration)\n var(--oc-animation-ease, var(--oc-ease-smooth)) both;\n animation-delay: calc(var(--oc-animation-stagger) * var(--oc-row-index, 0));\n }\n\n /* Cell text: fade in synced with row slide */\n & tbody td {\n animation: oc-enter-fade-only calc(var(--oc-animation-duration) * 0.5)\n var(--oc-animation-ease, var(--oc-ease-smooth)) both;\n animation-delay: calc(var(--oc-animation-stagger) * var(--oc-row-index, 0));\n }\n\n /* Heatmap/category cell backgrounds: longer fade, delayed after row appears */\n & td.oc-table-heatmap,\n & td.oc-table-category {\n animation: oc-enter-fade-only calc(var(--oc-animation-duration) * 0.7)\n var(--oc-animation-ease, var(--oc-ease-smooth)) both;\n animation-delay: calc(\n var(--oc-animation-stagger) *\n var(--oc-row-index, 0) +\n var(--oc-animation-duration) *\n 0.3\n );\n }\n\n /* Bar fill: clip-path grow only (no opacity change to preserve resting\n opacity: 0.15 from table.css) */\n & .oc-table-bar-fill {\n animation: oc-table-enter-bar-fill calc(var(--oc-animation-duration) * 0.8)\n var(--oc-animation-ease, var(--oc-ease-smooth)) both;\n animation-delay: calc(\n var(--oc-animation-stagger) *\n var(--oc-row-index, 0) +\n var(--oc-animation-duration) *\n 0.3\n );\n }\n\n /* Sparkline SVG: clip-path reveal left-to-right. Targets the SVG directly\n (not the wrapper) to avoid clipping absolutely-positioned dots and labels. */\n & .oc-table-sparkline > svg {\n animation: oc-enter-line calc(var(--oc-animation-duration) * 0.8)\n var(--oc-animation-ease, var(--oc-ease-smooth)) both;\n animation-delay: calc(\n var(--oc-animation-stagger) *\n var(--oc-row-index, 0) +\n var(--oc-animation-duration) *\n 0.4\n );\n }\n\n /* Sparkline dots and labels: fade in after the line draws through */\n & .oc-table-sparkline-dot,\n & .oc-table-sparkline-labels {\n animation: oc-enter-fade-only calc(var(--oc-animation-duration) * 0.3)\n var(--oc-animation-ease, var(--oc-ease-smooth)) both;\n animation-delay: calc(\n var(--oc-animation-stagger) *\n var(--oc-row-index, 0) +\n var(--oc-animation-duration) *\n 0.8\n );\n }\n\n /* Search and pagination: quick fade on mount */\n & .oc-table-search,\n & .oc-table-pagination {\n animation: oc-enter-fade-only calc(var(--oc-animation-duration) * 0.5)\n var(--oc-animation-ease, var(--oc-ease-smooth)) both;\n }\n }\n}\n","@layer oc.components {\n /* ---------------------------------------------------------------------------\n * Table base\n * --------------------------------------------------------------------------- */\n\n .oc-table-wrapper {\n font-family: var(--oc-font-family);\n color: var(--oc-text);\n background: var(--oc-bg);\n\n & > .oc-chrome {\n margin-bottom: 16px;\n padding-left: 16px;\n padding-right: 16px;\n }\n\n & > .oc-chrome:first-child {\n padding-top: 4px;\n }\n\n & table {\n width: 100%;\n border-collapse: collapse;\n }\n\n & th,\n & td {\n padding: 10px 16px;\n text-align: left;\n border-bottom: 1px solid var(--oc-border);\n }\n\n & th {\n font-weight: 600;\n font-size: 12px;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n color: var(--oc-text-secondary);\n white-space: nowrap;\n }\n\n & thead {\n position: sticky;\n top: 0;\n z-index: 2;\n background: var(--oc-bg);\n }\n\n & thead th {\n border-bottom-width: 2px;\n }\n\n & td {\n font-size: 14px;\n font-variant-numeric: tabular-nums;\n }\n\n & th:focus {\n outline: 2px solid var(--oc-focus);\n outline-offset: -2px;\n }\n\n & tbody:focus {\n outline: none;\n }\n }\n\n .oc-table-title {\n margin-bottom: 4px;\n font-size: var(--oc-title-computed-size, var(--oc-title-size));\n font-weight: var(--oc-title-computed-weight, var(--oc-title-weight));\n color: var(--oc-title-computed-color, var(--oc-text));\n }\n\n .oc-table-subtitle {\n margin-bottom: 8px;\n font-size: var(--oc-subtitle-computed-size, var(--oc-subtitle-size));\n font-weight: var(--oc-subtitle-computed-weight, var(--oc-subtitle-weight));\n color: var(--oc-subtitle-computed-color, var(--oc-text-secondary));\n }\n\n .oc-table-source {\n font-size: var(--oc-source-computed-size, var(--oc-source-size));\n color: var(--oc-source-computed-color, var(--oc-text-muted));\n }\n\n .oc-table-footer-text {\n font-size: var(--oc-footer-computed-size, var(--oc-source-size));\n color: var(--oc-footer-computed-color, var(--oc-text-muted));\n }\n\n .oc-table-scroll {\n overflow-x: auto;\n }\n\n /* ---------------------------------------------------------------------------\n * Sticky first column\n * --------------------------------------------------------------------------- */\n\n .oc-table--sticky {\n & th:first-child,\n & td:first-child {\n position: sticky;\n left: 0;\n z-index: 1;\n background: var(--oc-bg);\n }\n }\n\n /* ---------------------------------------------------------------------------\n * Sort controls\n * --------------------------------------------------------------------------- */\n\n .oc-table-sort-btn {\n background: none;\n border: none;\n cursor: pointer;\n padding: 2px;\n margin-left: 6px;\n display: inline-flex;\n flex-direction: column;\n align-items: center;\n vertical-align: middle;\n gap: 2px;\n\n &::before,\n &::after {\n content: \"\";\n display: block;\n width: 0;\n height: 0;\n border-left: 5px solid transparent;\n border-right: 5px solid transparent;\n transition:\n opacity 0.15s,\n border-color 0.15s;\n }\n\n &::before {\n border-bottom: 4.5px solid var(--oc-text-secondary);\n opacity: 0.45;\n }\n\n &::after {\n border-top: 4.5px solid var(--oc-text-secondary);\n opacity: 0.45;\n }\n\n &:hover::before,\n &:hover::after {\n opacity: 0.75;\n }\n }\n\n th[aria-sort=\"ascending\"] .oc-table-sort-btn {\n &::before {\n opacity: 1;\n border-bottom-color: var(--oc-text);\n }\n\n &::after {\n opacity: 0.15;\n }\n }\n\n th[aria-sort=\"descending\"] .oc-table-sort-btn {\n &::after {\n opacity: 1;\n border-top-color: var(--oc-text);\n }\n\n &::before {\n opacity: 0.15;\n }\n }\n\n /* ---------------------------------------------------------------------------\n * Search\n * --------------------------------------------------------------------------- */\n\n /* Shared search-input skin (table + series-search).\n Padding excluded: it diverges (table: 8px 12px; series: 0 10px 0 28px)\n and series-search.css is imported before table.css — a padding declaration\n here would beat the series-search override by source order. */\n .oc-table-search input,\n .oc-series-search-input {\n width: 100%;\n border: 1px solid var(--oc-border);\n border-radius: 6px;\n font-size: 13px;\n font-family: inherit;\n background: var(--oc-bg);\n color: var(--oc-text);\n box-sizing: border-box;\n transition: border-color 0.15s;\n }\n\n .oc-table-search input::placeholder,\n .oc-series-search-input::placeholder {\n color: var(--oc-text-muted);\n font-size: 13px;\n }\n\n .oc-table-search input:focus,\n .oc-series-search-input:focus {\n outline: none;\n border-color: var(--oc-focus);\n box-shadow: 0 0 0 3px var(--oc-focus-ring);\n }\n\n .oc-table-search {\n padding: 8px 0;\n\n & input {\n padding: 8px 12px;\n }\n }\n\n /* ---------------------------------------------------------------------------\n * Pagination\n * --------------------------------------------------------------------------- */\n\n .oc-table-pagination {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 12px 0 4px;\n font-size: 13px;\n color: var(--oc-text-secondary);\n\n & button {\n padding: 6px 14px;\n border: 1px solid var(--oc-border);\n border-radius: 6px;\n background: var(--oc-bg);\n color: var(--oc-text);\n cursor: pointer;\n font-size: 13px;\n font-family: inherit;\n transition:\n background 0.15s,\n border-color 0.15s;\n\n &:disabled {\n opacity: 0.35;\n cursor: not-allowed;\n }\n\n &:hover:not(:disabled) {\n background: var(--oc-hover-bg);\n border-color: var(--oc-axis);\n }\n\n &:focus-visible {\n outline: 2px solid var(--oc-focus);\n outline-offset: 1px;\n }\n }\n }\n\n .oc-table-pagination-info {\n font-variant-numeric: tabular-nums;\n }\n\n .oc-table-pagination-btns {\n display: flex;\n gap: 8px;\n }\n\n /* ---------------------------------------------------------------------------\n * Bar cells\n * --------------------------------------------------------------------------- */\n\n .oc-table-bar {\n position: relative;\n }\n\n .oc-table-bar-fill {\n position: absolute;\n top: 6px;\n left: 0;\n bottom: 6px;\n border-radius: 2px;\n opacity: 0.15;\n pointer-events: none;\n }\n\n .oc-table-bar-value {\n position: relative;\n z-index: 1;\n }\n\n /* ---------------------------------------------------------------------------\n * Sparkline cells\n * --------------------------------------------------------------------------- */\n\n .oc-table-sparkline {\n display: block;\n width: 100%;\n position: relative;\n\n & svg {\n display: block;\n width: 100%;\n overflow: visible;\n }\n }\n\n .oc-table-sparkline-dot {\n position: absolute;\n border-radius: 50%;\n width: 5px;\n height: 5px;\n }\n\n .oc-table-sparkline-labels {\n display: flex;\n justify-content: space-between;\n font-size: 11px;\n line-height: 1;\n }\n\n /* ---------------------------------------------------------------------------\n * Image cells\n * --------------------------------------------------------------------------- */\n\n .oc-table-image {\n display: inline-block;\n vertical-align: middle;\n\n & img {\n object-fit: cover;\n }\n }\n\n .oc-table-image-rounded img {\n border-radius: 50%;\n }\n\n /* ---------------------------------------------------------------------------\n * Flag cells\n * --------------------------------------------------------------------------- */\n\n .oc-table-flag {\n font-size: 1.2em;\n }\n\n /* ---------------------------------------------------------------------------\n * Compact mode\n * --------------------------------------------------------------------------- */\n\n .oc-table--compact {\n & th,\n & td {\n padding: 4px 8px;\n font-size: 13px;\n }\n\n & th {\n font-size: 11px;\n }\n }\n\n /* ---------------------------------------------------------------------------\n * Row hover (when onRowClick is set)\n * --------------------------------------------------------------------------- */\n\n .oc-table--clickable tbody {\n & tr {\n cursor: pointer;\n }\n\n & tr:hover {\n background: var(--oc-hover-bg);\n }\n }\n\n /* ---------------------------------------------------------------------------\n * Keyboard cell focus indicator\n * --------------------------------------------------------------------------- */\n\n .oc-table-cell-focus {\n outline: 2px solid var(--oc-focus);\n outline-offset: -2px;\n }\n\n /* ---------------------------------------------------------------------------\n * Empty state\n * --------------------------------------------------------------------------- */\n\n .oc-table-empty {\n padding: 32px 16px;\n text-align: center;\n color: var(--oc-text-secondary);\n font-size: 14px;\n font-style: italic;\n }\n}\n","@layer oc.animation {\n /* ---------------------------------------------------------------------------\n * Animation keyframes\n * --------------------------------------------------------------------------- */\n\n /* Bar entrance: clip-path reveal bottom-to-top + fade in (vertical columns).\n Bars grow upward from baseline with a soft opacity fade. */\n @keyframes oc-enter-bar {\n from {\n clip-path: inset(100% 0 0 0);\n opacity: 0;\n }\n 75% {\n opacity: 1;\n }\n to {\n clip-path: inset(0 0 0 0);\n opacity: 1;\n }\n }\n\n /* Bar entrance: clip-path reveal left-to-right + fade in (horizontal bars).\n Bars grow rightward from axis with a soft opacity fade. */\n @keyframes oc-enter-bar-h {\n from {\n clip-path: inset(0 100% 0 0);\n opacity: 0;\n }\n 75% {\n opacity: 1;\n }\n to {\n clip-path: inset(0 0 0 0);\n opacity: 1;\n }\n }\n\n /* Line/area entrance: clip-path reveal left-to-right + fade in.\n Lines draw in following reading direction with a soft lead-in. */\n @keyframes oc-enter-line {\n from {\n clip-path: inset(0 100% 0 0);\n opacity: 0;\n }\n 15% {\n opacity: 1;\n }\n to {\n clip-path: inset(0 0 0 0);\n opacity: 1;\n }\n }\n\n /* Point/arc entrance: scale up + fade in from center */\n @keyframes oc-enter-point {\n from {\n opacity: 0;\n transform: scale(0.3);\n }\n to {\n opacity: 1;\n transform: scale(1);\n }\n }\n\n /* Map feature entrance: fade in while transitioning fill from a neutral base\n to the data-driven color stored in --oc-feature-fill. The target opacity is\n --oc-feature-target-opacity (default 1) so features under a focus dim\n animate straight to their dimmed rest opacity instead of hitting 1 and then\n snapping down when the dim is applied post-animation. */\n @keyframes oc-enter-map-fill {\n from {\n fill: var(--oc-secondary);\n opacity: 0;\n }\n to {\n fill: var(--oc-feature-fill);\n opacity: var(--oc-feature-target-opacity, 1);\n }\n }\n\n /* Map point pop-in: gentle scale from 0.75 + fade. Uses transform-origin to\n scale from the circle's own center (cx/cy) rather than the SVG origin. */\n @keyframes oc-enter-map-point {\n from {\n opacity: 0;\n transform: scale(0.75);\n }\n to {\n opacity: 1;\n transform: scale(1);\n }\n }\n\n /* Pure opacity fade (no transform). Safe for elements with existing transforms\n like arc groups that use translate() for positioning. */\n @keyframes oc-enter-fade-only {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n }\n\n /* Fade + subtle slide up for text, rule, tick, annotations */\n @keyframes oc-enter-fade {\n from {\n opacity: 0;\n transform: translateY(4px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n }\n\n /* Table row entrance: slide up only, no opacity (cells fade independently\n to avoid opacity compounding between row and cell animations) */\n @keyframes oc-table-enter-row {\n from {\n transform: translateY(6px);\n }\n to {\n transform: translateY(0);\n }\n }\n\n /* Table bar fill entrance: clip-path grow only, no opacity\n (preserves resting opacity: 0.15 from table.css) */\n @keyframes oc-table-enter-bar-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\n /* Tooltip entrance */\n @keyframes oc-tooltip-in {\n from {\n opacity: 0;\n transform: translateY(2px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n }\n}\n","@layer oc.base {\n /* ---------------------------------------------------------------------------\n * Wrapper roots\n * --------------------------------------------------------------------------- */\n\n .oc-chart-root {\n width: 100%;\n height: 100%;\n }\n\n .oc-table-root,\n .oc-graph-root,\n .oc-sankey-root,\n .oc-barlist-root,\n .oc-tilemap-root,\n .oc-map-root {\n width: 100%;\n height: 100%;\n }\n\n .oc-table-root {\n overflow: auto;\n }\n\n /* ---------------------------------------------------------------------------\n * Chart container\n * --------------------------------------------------------------------------- */\n\n .oc-chart {\n font-family: var(--oc-font-family);\n display: block;\n width: 100%;\n }\n\n /* ---------------------------------------------------------------------------\n * BarList SVG container\n * --------------------------------------------------------------------------- */\n\n .oc-tilemap,\n .oc-map {\n display: block;\n width: 100%;\n height: auto;\n }\n\n .oc-map-feature {\n transition: opacity 400ms ease;\n }\n\n .oc-barlist {\n display: block;\n width: 100%;\n }\n\n /* ---------------------------------------------------------------------------\n * Screen reader only utility\n * --------------------------------------------------------------------------- */\n\n /* `overflow: clip`, not `hidden` — see applySrOnlyStyles in\n packages/vanilla/src/dom-helpers.ts for why. Keep the two in sync. */\n .oc-sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: clip;\n clip-path: inset(50%);\n white-space: nowrap;\n border-width: 0;\n }\n\n /* ---------------------------------------------------------------------------\n * Editable hover feedback\n * --------------------------------------------------------------------------- */\n\n .oc-editable-hover {\n outline: 1.5px solid var(--oc-editable-hover);\n outline-offset: 2px;\n border-radius: 2px;\n }\n\n /* ---------------------------------------------------------------------------\n * Keyboard focus indicators\n *\n * --oc-focus carries a light value in tokens.css and a dark value in\n * dark.css, so both rings stay visible in either mode.\n * --------------------------------------------------------------------------- */\n\n /* Container ring when the chart itself receives keyboard focus. */\n .oc-root:focus-visible {\n outline: 2px solid var(--oc-focus);\n outline-offset: 2px;\n }\n\n /* Mark ring during arrow-key navigation (see wireKeyboardNav). Outline on\n * SVG elements draws around the mark's bounding box, same technique as\n * .oc-editable-hover above. */\n .oc-mark-focused {\n outline: 2px solid var(--oc-focus);\n outline-offset: 1px;\n border-radius: 2px;\n }\n}\n","@layer oc.components {\n /* ---------------------------------------------------------------------------\n * Graph\n * --------------------------------------------------------------------------- */\n\n .oc-graph-wrapper {\n position: relative;\n overflow: hidden;\n background: var(--oc-bg);\n font-family: var(--oc-font-family);\n width: 100%;\n height: 100%;\n }\n\n .oc-graph-canvas {\n display: block;\n width: 100%;\n height: 100%;\n cursor: grab;\n }\n\n .oc-graph-canvas--dragging {\n cursor: grabbing;\n }\n\n .oc-graph-chrome {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n z-index: 2;\n padding: 16px 16px 8px;\n pointer-events: none;\n\n & .oc-title {\n font-size: var(--oc-title-size);\n font-weight: var(--oc-title-weight);\n letter-spacing: var(--oc-title-tracking);\n color: var(--oc-text);\n margin: 0 0 4px;\n --_stroke: color-mix(in srgb, var(--oc-bg) 80%, transparent);\n text-shadow:\n -2px -2px 0 var(--_stroke),\n 2px -2px 0 var(--_stroke),\n -2px 2px 0 var(--_stroke),\n 2px 2px 0 var(--_stroke),\n 0 -2px 0 var(--_stroke),\n 0 2px 0 var(--_stroke),\n -2px 0 0 var(--_stroke),\n 2px 0 0 var(--_stroke);\n }\n\n & .oc-subtitle {\n font-size: var(--oc-subtitle-size);\n color: var(--oc-text-secondary);\n margin: 0;\n --_stroke: color-mix(in srgb, var(--oc-bg) 80%, transparent);\n text-shadow:\n -1px -1px 0 var(--_stroke),\n 1px -1px 0 var(--_stroke),\n -1px 1px 0 var(--_stroke),\n 1px 1px 0 var(--_stroke);\n }\n }\n\n .oc-graph-legend {\n position: absolute;\n top: 8px;\n right: 8px;\n background: var(--oc-bg);\n border: 1px solid var(--oc-border);\n border-radius: var(--oc-border-radius);\n padding: 8px 12px;\n font-size: 12px;\n color: var(--oc-text-secondary);\n max-height: 200px;\n overflow-y: auto;\n }\n\n .oc-graph-legend-item {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 2px 0;\n /* Button reset for interactive rows (rendered as <button>). */\n width: 100%;\n margin: 0;\n background: none;\n border: none;\n font: inherit;\n color: inherit;\n text-align: left;\n cursor: default;\n }\n\n /* Interactive legend rows are buttons; give them affordance + a focus ring. */\n button.oc-graph-legend-item {\n cursor: pointer;\n border-radius: 4px;\n\n &:hover {\n background: var(--oc-focus-ring);\n }\n\n &:focus-visible {\n outline: 2px solid var(--oc-focus);\n outline-offset: 1px;\n }\n }\n\n /* De-emphasized (toggled-off) category. */\n .oc-graph-legend-item--inactive {\n opacity: 0.45;\n }\n\n .oc-graph-legend-label {\n flex: 1 1 auto;\n }\n\n .oc-graph-legend-count {\n color: var(--oc-text-secondary);\n font-variant-numeric: tabular-nums;\n margin-left: auto;\n padding-left: 8px;\n }\n\n .oc-graph-legend-swatch {\n width: 10px;\n height: 10px;\n border-radius: 50%;\n flex-shrink: 0;\n }\n\n /* Edge-legend swatches render as a short line, not a dot. */\n .oc-graph-legend-swatch--line {\n width: 12px;\n height: 3px;\n border-radius: 1px;\n }\n\n .oc-graph-search {\n position: absolute;\n top: 8px;\n left: 8px;\n\n & input {\n font-family: var(--oc-font-family);\n font-size: var(--oc-body-size);\n padding: 6px 10px;\n border: 1px solid var(--oc-border);\n border-radius: var(--oc-border-radius);\n background: var(--oc-bg);\n color: var(--oc-text);\n outline: none;\n\n &:focus {\n border-color: var(--oc-focus);\n box-shadow: 0 0 0 2px var(--oc-focus-ring-strong);\n }\n }\n }\n\n /* Dark mode graph overrides (darker bg for canvas-based rendering) */\n .oc-dark .oc-graph-wrapper,\n .oc-graph-wrapper.oc-dark {\n /* GitHub-dark canvas background, intentionally not a token */\n --oc-bg: #0d1117;\n }\n\n /*\n * graph-mount.ts stamps .oc-dark on both .oc-graph-wrapper and\n * .oc-graph-container simultaneously, so the self-variant\n * (.oc-dark.oc-graph-wrapper) and descendant variant\n * (.oc-dark .oc-graph-legend) resolve identically.\n */\n .oc-dark .oc-graph-legend,\n .oc-dark.oc-graph-wrapper .oc-graph-legend,\n .oc-dark .oc-graph-search input {\n background: rgba(13, 17, 23, 0.85);\n border-color: var(--oc-border);\n }\n}\n","@layer oc.animation {\n /* ---------------------------------------------------------------------------\n * Animation scoped rules (.oc-animate enables animation on the chart root)\n * --------------------------------------------------------------------------- */\n\n .oc-animate {\n /* Vertical bars (default): smooth ease-out, no overshoot.\n oc-mark-bar is reserved for future mark type aliases. */\n & .oc-mark-rect rect,\n & .oc-mark-bar rect {\n animation: oc-enter-bar var(--oc-animation-duration) var(--oc-ease-smooth) both;\n animation-delay: calc(var(--oc-animation-stagger) * var(--oc-mark-index, 0));\n }\n\n /* Horizontal bars (data-orient is on the mark group, not the SVG root) */\n & .oc-mark-rect[data-orient=\"horizontal\"] rect,\n & .oc-mark-bar[data-orient=\"horizontal\"] rect {\n animation-name: oc-enter-bar-h;\n }\n\n /* Stacked bar/column segments: chain sequentially so each segment starts\n right when the previous one finishes, creating one fluid reveal.\n Uses linear easing so handoffs between segments are seamless (no\n deceleration/acceleration stutter at segment boundaries). */\n & .oc-mark-rect[data-stack-pos] rect {\n animation-duration: var(--oc-stack-segment-duration, 150ms);\n animation-timing-function: linear;\n animation-delay: calc(\n var(--oc-animation-stagger) *\n var(--oc-mark-index, 0) +\n var(--oc-stack-pos, 0) *\n var(--oc-stack-segment-duration, 150ms)\n );\n }\n\n /* Line marks: entire group clips left-to-right (no WAAPI needed) */\n & .oc-mark-line {\n animation: oc-enter-line var(--oc-animation-duration)\n var(--oc-animation-ease, var(--oc-ease-smooth)) both;\n animation-delay: calc(var(--oc-animation-stagger) * var(--oc-mark-index, 0));\n }\n\n /* Area marks: entire group clips left-to-right + fades in */\n & .oc-mark-area {\n animation: oc-enter-line var(--oc-animation-duration)\n var(--oc-animation-ease, var(--oc-ease-smooth)) both;\n animation-delay: calc(var(--oc-animation-stagger) * var(--oc-mark-index, 0));\n }\n\n /* Arc marks (pie/donut slices): simple fade in.\n Scale transforms break arc positioning because arcs use translate()\n on parent groups. A clean fade is more elegant for pie/donut anyway. */\n & .oc-mark-arc {\n animation: oc-enter-fade-only var(--oc-animation-duration)\n var(--oc-animation-ease, var(--oc-ease-smooth)) both;\n animation-delay: calc(var(--oc-animation-stagger) * var(--oc-mark-index, 0));\n }\n\n /* Point marks (scatter, dot).\n Points render as bare <circle> elements with class oc-mark-point directly,\n not wrapped in a group, so we target circle.oc-mark-point (not descendant).\n Duration is 40% of the configured duration (quick pop-in relative to other marks). */\n & circle.oc-mark-point,\n & circle.oc-mark-circle {\n animation: oc-enter-fade-only calc(var(--oc-animation-duration) * 0.4)\n var(--oc-animation-ease, var(--oc-ease-smooth)) both;\n animation-delay: calc(var(--oc-animation-stagger) * var(--oc-mark-index, 0));\n }\n\n /* Points on line/area charts: delay so they pop in as the line draws through. */\n & .oc-mark-line ~ circle.oc-mark-point,\n & .oc-mark-area ~ circle.oc-mark-point {\n animation-delay: calc(\n var(--oc-animation-duration) *\n 0.35 +\n var(--oc-animation-stagger) *\n var(--oc-mark-index, 0)\n );\n }\n\n /* Text marks: fade + slight slide up */\n & .oc-mark-text text {\n animation: oc-enter-fade calc(var(--oc-animation-duration) * 0.6)\n var(--oc-animation-ease, var(--oc-ease-smooth)) both;\n animation-delay: calc(var(--oc-animation-stagger) * var(--oc-mark-index, 0));\n }\n\n /* Rule marks: fade in */\n & .oc-mark-rule line {\n animation: oc-enter-fade calc(var(--oc-animation-duration) * 0.5)\n var(--oc-animation-ease, var(--oc-ease-smooth)) both;\n animation-delay: calc(var(--oc-animation-stagger) * var(--oc-mark-index, 0));\n }\n\n /* Tick marks: fade in */\n & .oc-mark-tick line {\n animation: oc-enter-fade calc(var(--oc-animation-duration) * 0.5)\n var(--oc-animation-ease, var(--oc-ease-smooth)) both;\n animation-delay: calc(var(--oc-animation-stagger) * var(--oc-mark-index, 0));\n }\n\n /* Data labels: fade after their parent mark */\n & .oc-mark-label {\n animation: oc-enter-fade 300ms var(--oc-ease-smooth) both;\n animation-delay: calc(\n var(--oc-animation-stagger) *\n var(--oc-mark-index, 0) +\n var(--oc-animation-duration) *\n 0.7\n );\n }\n\n /* Annotations: fade in after marks finish */\n & .oc-annotation {\n animation: oc-enter-fade 400ms var(--oc-ease-smooth) both;\n animation-delay: calc(var(--oc-animation-duration) + var(--oc-annotation-delay, 200ms));\n }\n\n /* Tilemap tiles: fade in with jittered stagger for organic feel.\n Per-tile delay is computed in the renderer with pseudo-random variation. */\n & .oc-tilemap-tile {\n animation: oc-enter-fade-only calc(var(--oc-animation-duration) * 0.35) ease-in both;\n animation-delay: var(--oc-tile-delay, 0ms);\n }\n\n /* Map features: fill color reveal with shuffled stagger.\n Per-feature --oc-map-delay is computed in the renderer via a seeded\n Fisher-Yates shuffle so features pop in organically. */\n & .oc-map-feature {\n animation: oc-enter-map-fill var(--oc-animation-duration)\n var(--oc-animation-ease, var(--oc-ease-smooth)) both;\n animation-delay: var(--oc-map-delay, 0ms);\n }\n\n /* Bulk mode: high feature counts (counties, ~3k+) get a single group\n fade instead of per-feature fill animations. opacity is GPU-compositable\n so this stays smooth regardless of child count. */\n & .oc-map-features[data-bulk-animate] {\n animation: oc-enter-fade-only var(--oc-animation-duration)\n var(--oc-animation-ease, var(--oc-ease-smooth)) both;\n }\n\n & .oc-map-features[data-bulk-animate] .oc-map-feature {\n animation: none;\n }\n\n /* Map borders: fade in near the end of the feature sweep */\n & .oc-map-borders path {\n animation: oc-enter-fade-only calc(var(--oc-animation-duration) * 0.4) ease-in both;\n animation-delay: calc(var(--oc-animation-duration) * 0.7);\n }\n\n /* Map points: gentle scale (0.75->1) + fade pop-in after borders.\n transform-origin set per-circle in the renderer so scale happens\n around each circle's own center, not the SVG origin. */\n & .oc-map-point {\n animation: oc-enter-map-point calc(var(--oc-animation-duration) * 0.4)\n var(--oc-animation-ease, var(--oc-ease-smooth)) both;\n animation-delay: calc(\n var(--oc-animation-duration) *\n 0.8 +\n var(--oc-mark-index, 0) *\n var(--oc-point-stagger, 60ms)\n );\n }\n\n /* Sankey nodes: fade in with stagger by column depth (left-to-right) */\n & .oc-sankey-node rect {\n animation: oc-enter-fade-only var(--oc-animation-duration)\n var(--oc-animation-ease, var(--oc-ease-smooth)) both;\n animation-delay: calc(var(--oc-animation-stagger) * var(--oc-mark-index, 0));\n }\n\n /* Sankey links: fade in after nodes, with stagger.\n Links delay by 30% of duration so nodes appear first, then links flow in. */\n & .oc-sankey-link path {\n animation: oc-enter-fade-only var(--oc-animation-duration)\n var(--oc-animation-ease, var(--oc-ease-smooth)) both;\n animation-delay: calc(\n var(--oc-animation-duration) *\n 0.3 +\n var(--oc-animation-stagger) *\n var(--oc-mark-index, 0)\n );\n }\n\n /* Barlist rows: fade + slide up per row, bars grow left-to-right */\n & .oc-barlist-row {\n animation: oc-enter-fade calc(var(--oc-animation-duration) * 0.6)\n var(--oc-animation-ease, var(--oc-ease-smooth)) both;\n animation-delay: var(--oc-row-delay, 0ms);\n }\n\n & .oc-barlist-bar {\n animation: oc-enter-bar-h var(--oc-animation-duration)\n var(--oc-animation-ease, var(--oc-ease-smooth)) both;\n animation-delay: var(--oc-row-delay, 0ms);\n }\n }\n\n /* ---------------------------------------------------------------------------\n * Sparkline mode: pair the line/area reveal with a stronger ease-out so it\n * doesn't read as a uniform left-to-right swipe. cubic-bezier(0.16, 1, 0.3, 1)\n * is \"expo-out\" — fast initial draw that decelerates noticeably at the end,\n * giving the trend a hand-drawn feel. Duration is bumped via the engine\n * (compile.ts) so the cleanup timer stays in sync.\n * --------------------------------------------------------------------------- */\n\n .oc-animate[data-display=\"sparkline\"] .oc-mark-line,\n .oc-animate[data-display=\"sparkline\"] .oc-mark-area {\n animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1);\n }\n}\n","@layer oc.components {\n /* ---------------------------------------------------------------------------\n * Chrome (eyebrow, title, subtitle, source, byline, footer, brand)\n * --------------------------------------------------------------------------- */\n\n .oc-chrome {\n font-family: var(--oc-font-family);\n }\n\n .oc-eyebrow {\n font-size: var(--oc-eyebrow-size);\n font-weight: var(--oc-eyebrow-weight);\n letter-spacing: var(--oc-eyebrow-tracking);\n text-transform: uppercase;\n fill: var(--oc-accent);\n }\n\n .oc-title {\n font-size: var(--oc-title-size);\n font-weight: var(--oc-title-weight);\n letter-spacing: var(--oc-title-tracking);\n fill: var(--oc-text);\n }\n\n .oc-subtitle {\n font-size: var(--oc-subtitle-size);\n font-weight: var(--oc-subtitle-weight);\n fill: var(--oc-text-muted);\n }\n\n .oc-source,\n .oc-byline,\n .oc-footer {\n font-size: var(--oc-source-size);\n font-weight: var(--oc-source-weight);\n fill: var(--oc-text-muted);\n }\n\n .oc-brand {\n font-size: 11px;\n font-weight: 510;\n letter-spacing: 0.02em;\n fill: var(--oc-text-faint);\n }\n\n .oc-brand-dot {\n fill: var(--oc-accent);\n }\n\n .oc-eyebrow-dot {\n fill: var(--oc-accent);\n }\n\n /* ---------------------------------------------------------------------------\n * Metric bar (.oc-metrics) — optional row of label/value cells above chart\n * --------------------------------------------------------------------------- */\n\n .oc-metrics {\n font-family: var(--oc-font-family);\n }\n\n .oc-metric-label {\n font-size: 10px;\n font-weight: 510;\n letter-spacing: 0.08em;\n text-transform: uppercase;\n fill: var(--oc-text-muted);\n }\n\n .oc-metric-value {\n font-size: 22px;\n font-weight: 510;\n letter-spacing: -0.01em;\n fill: var(--oc-text);\n font-variant-numeric: tabular-nums;\n }\n\n .oc-metric-delta-up {\n fill: var(--oc-positive);\n font-size: 12px;\n font-weight: 510;\n }\n\n .oc-metric-delta-down {\n fill: var(--oc-negative);\n font-size: 12px;\n font-weight: 510;\n }\n\n .oc-metric-secondary {\n fill: var(--oc-positive);\n font-size: 12px;\n font-weight: 400;\n }\n\n /* ---------------------------------------------------------------------------\n * Axis tick labels — inline variant sits above each gridline at the\n * chart-area left edge (no left gutter). Used by line/area y-axes.\n * --------------------------------------------------------------------------- */\n\n .oc-axis-tick-inline {\n font-size: 11px;\n font-weight: 400;\n fill: var(--oc-text-muted);\n }\n\n /* ---------------------------------------------------------------------------\n * Endpoint labels (right-side per-series column for line/area charts)\n *\n * Swatch idiom: a thicker colored stroke segment with an optional thinner\n * lighter strip below. Mirrors the refreshed traditional legend swatch so a\n * single chart never shows two swatch idioms (mock-2 alignment). Per-series\n * color is stamped inline by the renderer; CSS tokens here cover the muted\n * value text and the leader line so theme overrides flow through naturally.\n * --------------------------------------------------------------------------- */\n\n .oc-endpoint-labels {\n font-family: var(--oc-font-family);\n }\n\n .oc-endpoint-label {\n /* Color set inline per series; this fallback only kicks in if the renderer\n ever omits the inline fill. */\n fill: var(--oc-endpoint-label-color, var(--oc-text));\n }\n\n .oc-endpoint-value {\n fill: var(--oc-endpoint-value-color, var(--oc-text-muted));\n }\n\n .oc-endpoint-leader {\n stroke: var(--oc-endpoint-leader-color, currentColor);\n }\n\n /* .oc-endpoint-marker — fill/stroke set inline (open-ring style: bg fill, series stroke). */\n /* .oc-endpoint-swatch — color set inline per series. */\n\n /* ---------------------------------------------------------------------------\n * Annotation dot + subtitle (text-annotation extensions)\n * --------------------------------------------------------------------------- */\n\n /* .oc-annotation-dot — fill/stroke resolved by the engine (open-ring default = bg fill, series stroke). */\n\n .oc-annotation-subtitle {\n fill: var(--oc-annotation-subtitle-color, var(--oc-text-muted));\n }\n\n /* ---------------------------------------------------------------------------\n * Table footer chrome\n * --------------------------------------------------------------------------- */\n\n /* Footer row: source/footer text on the left, brand watermark on the right,\n * sharing a single baseline. gap keeps them apart if the row gets narrow. */\n .oc-table-footer-row {\n display: flex;\n align-items: baseline;\n gap: 16px;\n padding: 16px 16px 4px;\n }\n\n /* Chrome block sits inside the flex row now, so it no longer owns the\n * footer's top padding or horizontal inset (the row provides both). */\n .oc-chrome-footer {\n padding-top: 0;\n }\n\n /* Brand watermark: pushed to the right edge (margin-left:auto holds it there\n * even when the source text is absent), never shrinks below its own text. */\n .oc-table-footer-row .oc-table-ref {\n margin-left: auto;\n flex-shrink: 0;\n text-align: right;\n }\n}\n","/* ---------------------------------------------------------------------------\n * Reduced motion\n *\n * Catch-all: last-declared layer beats every earlier layer regardless of\n * specificity. No !important, no hand-maintained selector mirror.\n *\n * Selector list matches CSS_TOKEN_ROOT_SELECTORS in token-definitions.ts.\n * --------------------------------------------------------------------------- */\n\n@layer oc.reduced-motion {\n @media (prefers-reduced-motion: reduce) {\n :is(\n .oc-root,\n .oc-chart-root,\n .oc-table-wrapper,\n .oc-table-root,\n .oc-graph-wrapper,\n .oc-graph-root,\n .oc-sankey-root,\n .oc-tilemap-root,\n .oc-barlist-root,\n .oc-map-root\n ),\n :is(\n .oc-root,\n .oc-chart-root,\n .oc-table-wrapper,\n .oc-table-root,\n .oc-graph-wrapper,\n .oc-graph-root,\n .oc-sankey-root,\n .oc-tilemap-root,\n .oc-barlist-root,\n .oc-map-root\n )\n *,\n :is(\n .oc-root,\n .oc-chart-root,\n .oc-table-wrapper,\n .oc-table-root,\n .oc-graph-wrapper,\n .oc-graph-root,\n .oc-sankey-root,\n .oc-tilemap-root,\n .oc-barlist-root,\n .oc-map-root\n )\n *::before,\n :is(\n .oc-root,\n .oc-chart-root,\n .oc-table-wrapper,\n .oc-table-root,\n .oc-graph-wrapper,\n .oc-graph-root,\n .oc-sankey-root,\n .oc-tilemap-root,\n .oc-barlist-root,\n .oc-map-root\n )\n *::after {\n animation: none;\n transition: none;\n }\n }\n}\n","@layer oc.components {\n /* ---------------------------------------------------------------------------\n * Legend\n * --------------------------------------------------------------------------- */\n\n .oc-legend {\n font-family: var(--oc-font-family);\n font-size: var(--oc-body-size);\n }\n\n .oc-legend-entry {\n cursor: default;\n }\n\n .oc-legend text {\n fill: var(--oc-legend-text);\n }\n}\n","@layer oc.components {\n /* ---------------------------------------------------------------------------\n * Tooltip\n * Editorial card matching the new design system: zinc surface, cyan accent,\n * Inter Variable, mono numerics. Sized for a slice tooltip that lists every\n * series at the snapped x.\n * --------------------------------------------------------------------------- */\n\n .oc-tooltip {\n position: absolute;\n display: none;\n pointer-events: none;\n z-index: 1000;\n background: var(--oc-tooltip-bg);\n backdrop-filter: blur(14px);\n border: 1px solid var(--oc-tooltip-border);\n border-radius: var(--oc-border-radius, 2px);\n box-shadow: var(--oc-tooltip-shadow);\n color: var(--oc-tooltip-text);\n font-family: var(--oc-font-family);\n font-size: 12px;\n padding: 0;\n max-width: 280px;\n min-width: 160px;\n line-height: 1.4;\n animation: oc-tooltip-in 120ms ease-out;\n transition:\n left 100ms ease-in-out,\n top 100ms ease-in-out;\n\n & .oc-tooltip-header {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 12px 6px;\n }\n\n & .oc-tooltip-dot {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n flex-shrink: 0;\n }\n\n & .oc-tooltip-title {\n font-weight: 590;\n font-size: 11px;\n letter-spacing: 0.04em;\n text-transform: uppercase;\n color: var(--oc-text-muted);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n & .oc-tooltip-body {\n padding: 6px 12px 10px;\n border-top: 1px solid var(--oc-tooltip-border);\n }\n\n /* No separator when body is the only child */\n & .oc-tooltip-body:first-child {\n border-top: none;\n padding-top: 10px;\n }\n\n & .oc-tooltip-row {\n display: flex;\n align-items: baseline;\n justify-content: space-between;\n gap: 16px;\n padding: 2px 0;\n }\n\n & .oc-tooltip-row-swatch {\n display: inline-block;\n width: 8px;\n height: 8px;\n border-radius: 50%;\n margin-right: 6px;\n flex-shrink: 0;\n transform: translateY(-1px);\n }\n\n & .oc-tooltip-label {\n color: var(--oc-text-secondary);\n font-size: 12px;\n font-weight: 400;\n white-space: nowrap;\n flex-shrink: 0;\n display: inline-flex;\n align-items: center;\n }\n\n & .oc-tooltip-value {\n font-weight: 510;\n font-size: 12px;\n font-variant-numeric: tabular-nums;\n color: var(--oc-tooltip-text);\n text-align: right;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n }\n\n /* ---------------------------------------------------------------------------\n * Crosshair guideline + per-series snap dots (line/area charts)\n * Animate the snap between adjacent points so the indicator slides instead\n * of jumping. ~50ms ease-in-out keeps the motion crisp without lagging.\n * --------------------------------------------------------------------------- */\n\n .oc-crosshair {\n pointer-events: none;\n transition:\n x1 50ms ease-in-out,\n x2 50ms ease-in-out;\n }\n\n .oc-snap-dots circle {\n pointer-events: none;\n transition:\n cx 50ms ease-in-out,\n cy 50ms ease-in-out;\n }\n}\n","@layer oc.components {\n /* ---------------------------------------------------------------------------\n * Series search (seriesSearch)\n *\n * DOM combobox overlaid on the SVG band the engine reserves below chrome.\n * The wrapper is absolutely positioned by the vanilla adapter (inline\n * left/top/width/height), so everything here is visual only. All colors come\n * from --oc-* tokens, which flip in .oc-dark.\n * --------------------------------------------------------------------------- */\n\n .oc-series-search {\n position: absolute;\n display: flex;\n align-items: center;\n justify-content: flex-end;\n gap: 8px;\n font-family: var(--oc-font-family);\n z-index: 10;\n }\n\n /* Chips: removable filter tokens for the current selection. They flow to the\n * left of the input and scroll horizontally rather than wrapping over the\n * chart when a reader picks many series. */\n .oc-series-search-chips {\n display: flex;\n align-items: center;\n gap: 6px;\n min-width: 0;\n overflow-x: auto;\n scrollbar-width: none;\n }\n\n .oc-series-search-chips::-webkit-scrollbar {\n display: none;\n }\n\n .oc-series-search-chip {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 3px 4px 3px 10px;\n border: 1px solid var(--oc-border);\n border-radius: 999px;\n background: var(--oc-secondary);\n color: var(--oc-text-secondary);\n font-size: 12px;\n font-weight: 500;\n line-height: 16px;\n white-space: nowrap;\n }\n\n .oc-series-search-chip-remove {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n /* 16px glyph, but a >=24px hit area (WCAG 2.5.5 target size) via padding\n pulled back with negative margin so the chip layout stays tight. */\n width: 16px;\n height: 16px;\n padding: 4px;\n margin: -4px -2px -4px -4px;\n border: none;\n border-radius: 50%;\n background: transparent;\n color: var(--oc-text-muted);\n cursor: pointer;\n transition:\n color 0.15s,\n background-color 0.15s;\n }\n\n .oc-series-search-chip-remove:hover {\n color: var(--oc-text);\n background: var(--oc-hover-bg);\n }\n\n .oc-series-search-chip-remove:focus-visible {\n outline: 2px solid var(--oc-focus);\n outline-offset: 1px;\n }\n\n .oc-series-search-chip-remove svg {\n display: block;\n }\n\n /* Combobox: input + popup listbox. Styling matches the table search input\n * (border, radius, focus ring) so the two search surfaces read as one system. */\n .oc-series-search-box {\n position: relative;\n flex: 0 1 220px;\n min-width: 120px;\n }\n\n .oc-series-search-icon {\n position: absolute;\n left: 9px;\n top: 50%;\n transform: translateY(-50%);\n color: var(--oc-text-muted);\n pointer-events: none;\n }\n\n /* Shared skin provided by the grouped rule in table.css.\n Only divergent props live here. */\n .oc-series-search-input {\n height: 32px;\n padding: 0 10px 0 28px;\n }\n\n .oc-series-search-listbox {\n position: absolute;\n top: calc(100% + 4px);\n right: 0;\n min-width: 100%;\n max-height: 240px;\n overflow-y: auto;\n margin: 0;\n padding: 4px;\n list-style: none;\n border: 1px solid var(--oc-border);\n border-radius: 8px;\n background: var(--oc-card);\n box-shadow: var(--oc-tooltip-shadow);\n z-index: 20;\n }\n\n .oc-series-search-option {\n padding: 6px 10px;\n border-radius: 4px;\n font-size: 13px;\n color: var(--oc-text);\n cursor: pointer;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n .oc-series-search-option[aria-selected=\"true\"],\n .oc-series-search-option:hover {\n background: var(--oc-hover-bg);\n }\n\n /* The typed substring within each suggestion. */\n .oc-series-search-match {\n font-weight: 600;\n }\n\n .oc-series-search-empty {\n padding: 6px 10px;\n font-size: 12px;\n color: var(--oc-text-muted);\n }\n}\n"],"names":[]}
1
+ {"version":3,"mappings":"AAWA,iBCEE,62DIFA,4lBLAF,eSNE,mIAeA,6BAQA,qEAUA,yDAOA,uCAIA,qCAWA,8IAgBA,qGAcA,4EAQA,yFTvFF,qBGNE,6CAIA,2KAQA,wIAOA,+GAMA,+HAQA,wFAOA,oDAYA,8CAIA,wHAQA,4HAQA,2EAMA,6EAMA,4EAWA,8EAgBA,sDAIA,sEAMA,4EAIA,wEAaA,sFAUA,sFASA,gCAMA,mFIhKA,ogBAsBE,4FAOA,iFAOA,gMAWA,iGAMA,0EAKA,mHAQA,yJAUA,oKAUA,uMAkBF,qFAOA,4FIlHA,2EAKA,gCAIA,2CIJA,kJAaA,iHASA,wDAIA,sRAeA,6RAoBA,uFAKA,iGAKA,gDAMA,qEAMA,oIAWA,0DAKA,2RAiBA,yKAWA,0GAMA,wCAIA,mFbtIA,kDAKA,+CAKA,qGASA,wHAUA,yGAWA,qFAKA,0MAYA,oRAeA,6DAOA,mXAoBA,0DAIA,yFAKA,yDIpHA,iGAKE,qFAMA,yDAIA,4DAKA,gGAAA,gGAOA,oJASA,gFAOA,mDAIA,sEAKA,iFAKA,2CAKF,sNAOA,kPAOA,2IAKA,gJAKA,iCASE,0FAAA,0FAaF,oLAYE,mLAAA,kLAaA,yFAKA,qFAKA,4CAAA,2CAOA,+FAKA,6DAMA,4FAKA,+DAaF,iPAaA,wFAAA,8EAAA,yFAAA,+EAMA,+IAOA,+BAGE,wCASF,oJAQE,6OAaE,oEAKA,2GAKA,+FAOJ,4DAIA,+CASA,gCAIA,iHAUA,gDASA,+DAKE,kEAOF,iFAOA,mGAWA,2DAIE,qCAKF,8CAQA,+BASE,qDAAA,qDAMA,qCAUA,6CAIA,kEASF,2EASA,oHQjYA,qIASA,kEAOA,2CAIA,4GASE,8bAkBA,2RAaF,qPAcA,qLAiBA,6DAIE,kEAIA,+FAOF,4CAIA,iCAIA,0HAOA,+EAQA,sEAMA,oDAKE,0OAUE,2GAQJ,qEAYA,iKVrKA,oEJCF,oBUJI,4JAMA,4JAOA,8NAOA,yOAOA,wRAAA,yRAcA,4RAaA,uRAYA,4RAAA,+RAaA,uKAAA,2KF/EF,8GAgBA,kHAgBA,iHAeA,4FAgBA,8IAaA,iGAaA,yDAUA,sGAaA,uFAWA,yFAUA,sGIpIE,yLAAA,wLAOA,qFAAA,oFASA,oRAYA,8MAOA,8MASA,kNAUA,qOAAA,sOAQA,+JAAA,+JAWA,8NAOA,8NAOA,8NAOA,iMAWA,sKAOA,wJAQA,gLASA,8JAKA,+EAKA,2KAQA,mQAYA,0NAQA,8PAYA,uLAMA,6KAeF,wJZrMF,yBaDE,uCACE,6LAAA,+LAAA,qMAAA","sources":["../src/styles/index.css","../src/styles/tokens.css","../src/styles/you-draw-it.css","../src/styles/chrome.css","../src/styles/sparkline.css","../src/styles/dark.css","../src/styles/table.css","../src/styles/tooltip.css","../src/styles/keyframes.css","../src/styles/base.css","../src/styles/table-animation.css","../src/styles/legend.css","../src/styles/graph.css","../src/styles/animation.css","../src/styles/series-search.css","../src/styles/reduced-motion.css"],"sourcesContent":["/**\n * @opendata-ai/openchart-core styles\n *\n * CSS with oc- prefix for all class names.\n * CSS custom properties for theme overrides.\n * Dark mode via .oc-dark class on the container.\n * Cascade layers: oc.tokens, oc.base, oc.components, oc.animation, oc.reduced-motion.\n */\n\n/* For optimal typography, load Inter: https://fonts.google.com/specimen/Inter */\n\n@layer oc.tokens, oc.base, oc.components, oc.animation, oc.reduced-motion;\n\n@import \"./tokens.css\";\n@import \"./dark.css\";\n@import \"./base.css\";\n@import \"./chrome.css\";\n@import \"./tooltip.css\";\n@import \"./legend.css\";\n@import \"./series-search.css\";\n@import \"./you-draw-it.css\";\n@import \"./table.css\";\n@import \"./table-animation.css\";\n@import \"./graph.css\";\n@import \"./sparkline.css\";\n@import \"./keyframes.css\";\n@import \"./animation.css\";\n@import \"./reduced-motion.css\";\n","/* GENERATED FILE — do not edit. Source: packages/core/src/styles/token-definitions.ts. Regenerate: bun run generate:tokens */\n\n@layer oc.tokens {\n /* ---------------------------------------------------------------------------\n * Custom properties (light mode defaults)\n *\n * These are FALLBACK defaults. At runtime, the JS theme engine stamps the\n * resolved theme as inline --oc-* custom properties on each .oc-root\n * container (see packages/vanilla/src/theme-tokens.ts). These CSS values\n * serve as fallbacks for contexts where JS hasn't mounted yet (SSR, static\n * HTML examples).\n * --------------------------------------------------------------------------- */\n\n .oc-root,\n .oc-chart-root,\n .oc-table-wrapper,\n .oc-table-root,\n .oc-graph-wrapper,\n .oc-graph-root,\n .oc-sankey-root,\n .oc-tilemap-root,\n .oc-barlist-root,\n .oc-map-root {\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n\n /* Opt out of iOS text auto-inflation so measured widths match rendered text. */\n -webkit-text-size-adjust: 100%;\n text-size-adjust: 100%;\n\n --oc-font-family:\n \"Inter Variable\", Inter, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n --oc-font-mono: \"JetBrains Mono\", \"Fira Code\", \"Cascadia Code\", monospace;\n\n /* Animation easing presets via CSS linear() */\n --oc-ease-smooth: linear(\n 0,\n 0.157,\n 0.438,\n 0.64,\n 0.766,\n 0.85,\n 0.906,\n 0.941,\n 0.964,\n 0.978,\n 0.988,\n 0.994,\n 0.998,\n 1\n );\n --oc-ease-snappy: linear(\n 0,\n 0.012,\n 0.048,\n 0.108,\n 0.194,\n 0.302,\n 0.426,\n 0.559,\n 0.69,\n 0.808,\n 0.905,\n 0.973,\n 1.013,\n 1.028,\n 1.023,\n 1.006,\n 0.984,\n 0.966,\n 0.957,\n 0.957,\n 0.964,\n 0.975,\n 0.986,\n 0.995,\n 1,\n 1.003,\n 1.002,\n 1,\n 0.998,\n 0.998,\n 0.999,\n 1\n );\n\n /* Animation timing defaults */\n --oc-animation-duration: 500ms;\n --oc-animation-stagger: 80ms;\n --oc-annotation-delay: 200ms;\n\n /* Typography scale (editorial design system) */\n --oc-title-size: 26px;\n --oc-title-weight: 590;\n --oc-title-tracking: -0.022em;\n --oc-subtitle-size: 14px;\n --oc-subtitle-weight: 450;\n --oc-source-size: 11px;\n --oc-source-weight: 450;\n --oc-body-size: 13px;\n --oc-eyebrow-size: 11px;\n --oc-eyebrow-weight: 550;\n --oc-eyebrow-tracking: 0.08em;\n\n /* Surfaces (light mode defaults) */\n --oc-bg: #ffffff;\n --oc-card: #ffffff;\n --oc-secondary: #f4f4f5; /* zinc-100, raised surface */\n\n /*\n * Text levels. Names invert across modes: in light mode \"muted\" sits at\n * a lighter zinc step than \"subtle\" because both are picked relative to\n * the active background, not from a fixed lightness ladder. The intent\n * is \"muted = first step away from primary text\"; \"subtle = next step\n * down\"; etc.\n *\n * Light mode: text=zinc-950, secondary=zinc-700, muted=zinc-500,\n * subtle=zinc-400, faint=zinc-300\n * Dark mode (dark.css): inverts the surface tokens but keeps the same\n * muted -> subtle -> faint progression away from primary.\n */\n --oc-text: #09090b;\n --oc-text-secondary: #3f3f46;\n --oc-text-muted: #71717a;\n --oc-text-faint: #d4d4d8;\n\n /* Lines */\n --oc-gridline: rgba(0, 0, 0, 0.1);\n --oc-axis: rgba(0, 0, 0, 0.1);\n --oc-border: rgba(0, 0, 0, 0.08);\n --oc-border-radius: 2px;\n\n /* Brand and semantic */\n --oc-accent: #06b6d4;\n --oc-accent-strong: #0891b2; /* darker cyan for line strokes on light bg */\n --oc-positive: #10b981;\n --oc-negative: #e11d48;\n --oc-focus: #3b82f6;\n /* static, intentionally NOT derived from --oc-focus and NOT flipped in dark mode */\n --oc-focus-ring: rgba(59, 130, 246, 0.1);\n --oc-focus-ring-strong: rgba(59, 130, 246, 0.25);\n --oc-editable-hover: rgba(79, 70, 229, 0.35); /* edit-mode hover outline, indigo one-off */\n\n /* Spacing scale (4px base) — only --oc-space-2/4 are consumed (JS-stamped) */\n --oc-space-2: 8px;\n --oc-space-4: 16px;\n\n /* Interactive states */\n --oc-hover-bg: rgba(0, 0, 0, 0.025);\n --oc-tooltip-bg: rgba(255, 255, 255, 0.88);\n --oc-tooltip-border: rgba(0, 0, 0, 0.08);\n --oc-tooltip-shadow: 0 2px 8px rgba(0, 0, 0, 0.08), 0 0 1px rgba(0, 0, 0, 0.12);\n --oc-tooltip-text: #09090b;\n --oc-legend-text: #3f3f46;\n }\n}\n","@layer oc.components {\n /* ---------------------------------------------------------------------------\n * You draw it (youDrawIt)\n *\n * NYT-style draw-then-reveal. SVG-space elements (hatched region, guess path,\n * reveal clip) render inside the chart SVG; the prompt + skip-to-reveal button\n * are an absolutely-positioned HTML overlay the vanilla adapter sizes over the\n * drawing region (inline left/top/width/height). All colors come from --oc-*\n * tokens so they flip in .oc-dark.\n * --------------------------------------------------------------------------- */\n\n /* Hatched \"draw here\" region. Fill comes from an SVG <pattern> (line color =\n * the target series color); this only governs overall opacity + fade-out. */\n .oc-ydi-region {\n opacity: 0.35;\n transition: opacity 0.4s ease;\n }\n\n .oc-ydi-region[data-ydi-hidden=\"true\"] {\n opacity: 0;\n }\n\n /* The vertical rule at `from` where drawing begins. */\n .oc-ydi-boundary {\n stroke: var(--oc-text-muted);\n stroke-width: 1;\n stroke-dasharray: 3 3;\n stroke-opacity: 0.6;\n }\n\n /* Reader's guess: a distinct pen-like stroke that reads as \"yours\" against the\n * solid real line. Dashed + focus-blue so it stays legible in both modes. */\n .oc-ydi-guess {\n stroke: var(--oc-focus);\n stroke-width: 2.5;\n stroke-linecap: round;\n stroke-linejoin: round;\n stroke-dasharray: 1 6;\n }\n\n /* Host-supplied comparison line (\"what everyone else guessed\"). Muted so it\n * sits behind the reader's guess and the real line. */\n .oc-ydi-comparison {\n stroke: var(--oc-text-muted);\n stroke-width: 1.5;\n stroke-opacity: 0.5;\n stroke-dasharray: 4 4;\n }\n\n /* Reveal clip rect: the width animates from the `from` boundary to the full\n * area on reveal, wiping the real line in left-to-right. The vanilla adapter\n * adds .oc-ydi-clip-animate right before setting the final width; reduced\n * motion skips the class so the width snaps. */\n .oc-ydi-clip-rect.oc-ydi-clip-animate {\n transition: width 0.7s cubic-bezier(0.22, 1, 0.36, 1);\n }\n\n /* HTML controls overlay: prompt (top) + reveal button (bottom-right). */\n .oc-ydi-controls {\n display: flex;\n flex-direction: column;\n justify-content: space-between;\n align-items: flex-end;\n pointer-events: none;\n font-family: var(--oc-font-family);\n padding: 8px;\n box-sizing: border-box;\n z-index: 10;\n }\n\n .oc-ydi-prompt {\n align-self: center;\n max-width: 100%;\n padding: 6px 12px;\n border-radius: 6px;\n background: var(--oc-card);\n border: 1px solid var(--oc-border);\n color: var(--oc-text-secondary);\n font-size: 13px;\n font-weight: 500;\n line-height: 16px;\n text-align: center;\n box-shadow: var(--oc-tooltip-shadow);\n }\n\n .oc-ydi-controls.oc-ydi-revealed .oc-ydi-prompt {\n display: none;\n }\n\n /* Skip-to-reveal button. pointer-events re-enabled (the overlay disables it)\n * so it stays clickable and keyboard-reachable. Min height enforced inline by\n * the adapter (>= 24px effective touch target). */\n .oc-ydi-reveal-button {\n pointer-events: auto;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n padding: 6px 14px;\n border: 1px solid var(--oc-border);\n border-radius: 6px;\n background: var(--oc-bg);\n color: var(--oc-text);\n font-family: inherit;\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n box-shadow: var(--oc-tooltip-shadow);\n transition:\n background-color 0.15s,\n border-color 0.15s;\n }\n\n .oc-ydi-reveal-button:hover {\n background: var(--oc-hover-bg);\n }\n\n .oc-ydi-reveal-button:focus-visible {\n outline: 2px solid var(--oc-focus);\n outline-offset: 2px;\n }\n\n .oc-ydi-reveal-button:disabled {\n opacity: 0.5;\n cursor: default;\n }\n}\n","@layer oc.components {\n /* ---------------------------------------------------------------------------\n * Chrome (eyebrow, title, subtitle, source, byline, footer, brand)\n * --------------------------------------------------------------------------- */\n\n .oc-chrome {\n font-family: var(--oc-font-family);\n }\n\n .oc-eyebrow {\n font-size: var(--oc-eyebrow-size);\n font-weight: var(--oc-eyebrow-weight);\n letter-spacing: var(--oc-eyebrow-tracking);\n text-transform: uppercase;\n fill: var(--oc-accent);\n }\n\n .oc-title {\n font-size: var(--oc-title-size);\n font-weight: var(--oc-title-weight);\n letter-spacing: var(--oc-title-tracking);\n fill: var(--oc-text);\n }\n\n .oc-subtitle {\n font-size: var(--oc-subtitle-size);\n font-weight: var(--oc-subtitle-weight);\n fill: var(--oc-text-muted);\n }\n\n .oc-source,\n .oc-byline,\n .oc-footer {\n font-size: var(--oc-source-size);\n font-weight: var(--oc-source-weight);\n fill: var(--oc-text-muted);\n }\n\n .oc-brand {\n font-size: 11px;\n font-weight: 510;\n letter-spacing: 0.02em;\n fill: var(--oc-text-faint);\n }\n\n .oc-brand-dot {\n fill: var(--oc-accent);\n }\n\n .oc-eyebrow-dot {\n fill: var(--oc-accent);\n }\n\n /* ---------------------------------------------------------------------------\n * Metric bar (.oc-metrics) — optional row of label/value cells above chart\n * --------------------------------------------------------------------------- */\n\n .oc-metrics {\n font-family: var(--oc-font-family);\n }\n\n .oc-metric-label {\n font-size: 10px;\n font-weight: 510;\n letter-spacing: 0.08em;\n text-transform: uppercase;\n fill: var(--oc-text-muted);\n }\n\n .oc-metric-value {\n font-size: 22px;\n font-weight: 510;\n letter-spacing: -0.01em;\n fill: var(--oc-text);\n font-variant-numeric: tabular-nums;\n }\n\n .oc-metric-delta-up {\n fill: var(--oc-positive);\n font-size: 12px;\n font-weight: 510;\n }\n\n .oc-metric-delta-down {\n fill: var(--oc-negative);\n font-size: 12px;\n font-weight: 510;\n }\n\n .oc-metric-secondary {\n fill: var(--oc-positive);\n font-size: 12px;\n font-weight: 400;\n }\n\n /* ---------------------------------------------------------------------------\n * Axis tick labels — inline variant sits above each gridline at the\n * chart-area left edge (no left gutter). Used by line/area y-axes.\n * --------------------------------------------------------------------------- */\n\n .oc-axis-tick-inline {\n font-size: 11px;\n font-weight: 400;\n fill: var(--oc-text-muted);\n }\n\n /* ---------------------------------------------------------------------------\n * Endpoint labels (right-side per-series column for line/area charts)\n *\n * Swatch idiom: a thicker colored stroke segment with an optional thinner\n * lighter strip below. Mirrors the refreshed traditional legend swatch so a\n * single chart never shows two swatch idioms (mock-2 alignment). Per-series\n * color is stamped inline by the renderer; CSS tokens here cover the muted\n * value text and the leader line so theme overrides flow through naturally.\n * --------------------------------------------------------------------------- */\n\n .oc-endpoint-labels {\n font-family: var(--oc-font-family);\n }\n\n .oc-endpoint-label {\n /* Color set inline per series; this fallback only kicks in if the renderer\n ever omits the inline fill. */\n fill: var(--oc-endpoint-label-color, var(--oc-text));\n }\n\n .oc-endpoint-value {\n fill: var(--oc-endpoint-value-color, var(--oc-text-muted));\n }\n\n .oc-endpoint-leader {\n stroke: var(--oc-endpoint-leader-color, currentColor);\n }\n\n /* .oc-endpoint-marker — fill/stroke set inline (open-ring style: bg fill, series stroke). */\n /* .oc-endpoint-swatch — color set inline per series. */\n\n /* ---------------------------------------------------------------------------\n * Annotation dot + subtitle (text-annotation extensions)\n * --------------------------------------------------------------------------- */\n\n /* .oc-annotation-dot — fill/stroke resolved by the engine (open-ring default = bg fill, series stroke). */\n\n .oc-annotation-subtitle {\n fill: var(--oc-annotation-subtitle-color, var(--oc-text-muted));\n }\n\n /* ---------------------------------------------------------------------------\n * Table footer chrome\n * --------------------------------------------------------------------------- */\n\n /* Footer row: source/footer text on the left, brand watermark on the right,\n * sharing a single baseline. gap keeps them apart if the row gets narrow. */\n .oc-table-footer-row {\n display: flex;\n align-items: baseline;\n gap: 16px;\n padding: 16px 16px 4px;\n }\n\n /* Chrome block sits inside the flex row now, so it no longer owns the\n * footer's top padding or horizontal inset (the row provides both). */\n .oc-chrome-footer {\n padding-top: 0;\n }\n\n /* Brand watermark: pushed to the right edge (margin-left:auto holds it there\n * even when the source text is absent), never shrinks below its own text. */\n .oc-table-footer-row .oc-table-ref {\n margin-left: auto;\n flex-shrink: 0;\n text-align: right;\n }\n}\n","@layer oc.components {\n /**\n * Sparkline display mode.\n *\n * Stamped on the SVG root as data-display=\"sparkline\" by the renderer when\n * the spec sets display: 'sparkline'. Strips any inherited padding/margin\n * so the mark renders truly edge-to-edge in tight container layouts (KPI\n * cards, table cells, dashboard tiles).\n */\n\n .oc-chart[data-display=\"sparkline\"] {\n display: block;\n margin: 0;\n padding: 0;\n }\n}\n","/* GENERATED FILE — do not edit. Source: packages/core/src/styles/token-definitions.ts. Regenerate: bun run generate:tokens */\n\n@layer oc.tokens {\n /* ---------------------------------------------------------------------------\n * Dark mode overrides (fallback defaults)\n *\n * At runtime, the JS theme engine stamps dark-adapted --oc-* custom\n * properties on each .oc-root container. These CSS values serve as\n * fallbacks for contexts where JS hasn't mounted yet.\n * --------------------------------------------------------------------------- */\n\n .oc-dark {\n /* Surfaces (zinc-based achromatic ramp) */\n --oc-bg: #09090b;\n --oc-card: #111113;\n --oc-secondary: #27272a;\n\n /* Text levels — see tokens.css for the cross-mode naming rationale */\n --oc-text: #f7f8f8;\n --oc-text-secondary: #d0d6e0;\n --oc-text-muted: #a1a1aa;\n --oc-text-faint: #52525b;\n\n /* Lines */\n --oc-gridline: rgba(255, 255, 255, 0.05);\n --oc-axis: rgba(255, 255, 255, 0.1);\n --oc-border: rgba(255, 255, 255, 0.1);\n\n /* Brand and semantic — accent stays cyan (no darkening on dark bg) */\n --oc-accent: #06b6d4;\n --oc-accent-strong: #06b6d4;\n --oc-positive: #34d399;\n --oc-negative: #fb7185;\n --oc-focus: #60a5fa;\n\n /* Interactive states */\n --oc-hover-bg: rgba(255, 255, 255, 0.05);\n --oc-tooltip-bg: rgba(17, 17, 19, 0.92);\n --oc-tooltip-border: rgba(255, 255, 255, 0.08);\n --oc-tooltip-shadow: 0 2px 8px rgba(0, 0, 0, 0.3), 0 0 1px rgba(0, 0, 0, 0.4);\n --oc-tooltip-text: #f7f8f8;\n --oc-legend-text: #d0d6e0;\n }\n}\n","@layer oc.components {\n /* ---------------------------------------------------------------------------\n * Table base\n * --------------------------------------------------------------------------- */\n\n .oc-table-wrapper {\n font-family: var(--oc-font-family);\n color: var(--oc-text);\n background: var(--oc-bg);\n\n & > .oc-chrome {\n margin-bottom: 16px;\n padding-left: 16px;\n padding-right: 16px;\n }\n\n & > .oc-chrome:first-child {\n padding-top: 4px;\n }\n\n & table {\n width: 100%;\n border-collapse: collapse;\n }\n\n & th,\n & td {\n padding: 10px 16px;\n text-align: left;\n border-bottom: 1px solid var(--oc-border);\n }\n\n & th {\n font-weight: 600;\n font-size: 12px;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n color: var(--oc-text-secondary);\n white-space: nowrap;\n }\n\n & thead {\n position: sticky;\n top: 0;\n z-index: 2;\n background: var(--oc-bg);\n }\n\n & thead th {\n border-bottom-width: 2px;\n }\n\n & td {\n font-size: 14px;\n font-variant-numeric: tabular-nums;\n }\n\n & th:focus {\n outline: 2px solid var(--oc-focus);\n outline-offset: -2px;\n }\n\n & tbody:focus {\n outline: none;\n }\n }\n\n .oc-table-title {\n margin-bottom: 4px;\n font-size: var(--oc-title-computed-size, var(--oc-title-size));\n font-weight: var(--oc-title-computed-weight, var(--oc-title-weight));\n color: var(--oc-title-computed-color, var(--oc-text));\n }\n\n .oc-table-subtitle {\n margin-bottom: 8px;\n font-size: var(--oc-subtitle-computed-size, var(--oc-subtitle-size));\n font-weight: var(--oc-subtitle-computed-weight, var(--oc-subtitle-weight));\n color: var(--oc-subtitle-computed-color, var(--oc-text-secondary));\n }\n\n .oc-table-source {\n font-size: var(--oc-source-computed-size, var(--oc-source-size));\n color: var(--oc-source-computed-color, var(--oc-text-muted));\n }\n\n .oc-table-footer-text {\n font-size: var(--oc-footer-computed-size, var(--oc-source-size));\n color: var(--oc-footer-computed-color, var(--oc-text-muted));\n }\n\n .oc-table-scroll {\n overflow-x: auto;\n }\n\n /* ---------------------------------------------------------------------------\n * Sticky first column\n * --------------------------------------------------------------------------- */\n\n .oc-table--sticky {\n & th:first-child,\n & td:first-child {\n position: sticky;\n left: 0;\n z-index: 1;\n background: var(--oc-bg);\n }\n }\n\n /* ---------------------------------------------------------------------------\n * Sort controls\n * --------------------------------------------------------------------------- */\n\n .oc-table-sort-btn {\n background: none;\n border: none;\n cursor: pointer;\n padding: 2px;\n margin-left: 6px;\n display: inline-flex;\n flex-direction: column;\n align-items: center;\n vertical-align: middle;\n gap: 2px;\n\n &::before,\n &::after {\n content: \"\";\n display: block;\n width: 0;\n height: 0;\n border-left: 5px solid transparent;\n border-right: 5px solid transparent;\n transition:\n opacity 0.15s,\n border-color 0.15s;\n }\n\n &::before {\n border-bottom: 4.5px solid var(--oc-text-secondary);\n opacity: 0.45;\n }\n\n &::after {\n border-top: 4.5px solid var(--oc-text-secondary);\n opacity: 0.45;\n }\n\n &:hover::before,\n &:hover::after {\n opacity: 0.75;\n }\n }\n\n th[aria-sort=\"ascending\"] .oc-table-sort-btn {\n &::before {\n opacity: 1;\n border-bottom-color: var(--oc-text);\n }\n\n &::after {\n opacity: 0.15;\n }\n }\n\n th[aria-sort=\"descending\"] .oc-table-sort-btn {\n &::after {\n opacity: 1;\n border-top-color: var(--oc-text);\n }\n\n &::before {\n opacity: 0.15;\n }\n }\n\n /* ---------------------------------------------------------------------------\n * Search\n * --------------------------------------------------------------------------- */\n\n /* Shared search-input skin (table + series-search).\n Padding excluded: it diverges (table: 8px 12px; series: 0 10px 0 28px)\n and series-search.css is imported before table.css — a padding declaration\n here would beat the series-search override by source order. */\n .oc-table-search input,\n .oc-series-search-input {\n width: 100%;\n border: 1px solid var(--oc-border);\n border-radius: 6px;\n font-size: 13px;\n font-family: inherit;\n background: var(--oc-bg);\n color: var(--oc-text);\n box-sizing: border-box;\n transition: border-color 0.15s;\n }\n\n .oc-table-search input::placeholder,\n .oc-series-search-input::placeholder {\n color: var(--oc-text-muted);\n font-size: 13px;\n }\n\n .oc-table-search input:focus,\n .oc-series-search-input:focus {\n outline: none;\n border-color: var(--oc-focus);\n box-shadow: 0 0 0 3px var(--oc-focus-ring);\n }\n\n .oc-table-search {\n padding: 8px 0;\n\n & input {\n padding: 8px 12px;\n }\n }\n\n /* ---------------------------------------------------------------------------\n * Pagination\n * --------------------------------------------------------------------------- */\n\n .oc-table-pagination {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 12px 0 4px;\n font-size: 13px;\n color: var(--oc-text-secondary);\n\n & button {\n padding: 6px 14px;\n border: 1px solid var(--oc-border);\n border-radius: 6px;\n background: var(--oc-bg);\n color: var(--oc-text);\n cursor: pointer;\n font-size: 13px;\n font-family: inherit;\n transition:\n background 0.15s,\n border-color 0.15s;\n\n &:disabled {\n opacity: 0.35;\n cursor: not-allowed;\n }\n\n &:hover:not(:disabled) {\n background: var(--oc-hover-bg);\n border-color: var(--oc-axis);\n }\n\n &:focus-visible {\n outline: 2px solid var(--oc-focus);\n outline-offset: 1px;\n }\n }\n }\n\n .oc-table-pagination-info {\n font-variant-numeric: tabular-nums;\n }\n\n .oc-table-pagination-btns {\n display: flex;\n gap: 8px;\n }\n\n /* ---------------------------------------------------------------------------\n * Bar cells\n * --------------------------------------------------------------------------- */\n\n .oc-table-bar {\n position: relative;\n }\n\n .oc-table-bar-fill {\n position: absolute;\n top: 6px;\n left: 0;\n bottom: 6px;\n border-radius: 2px;\n opacity: 0.15;\n pointer-events: none;\n }\n\n .oc-table-bar-value {\n position: relative;\n z-index: 1;\n }\n\n /* ---------------------------------------------------------------------------\n * Sparkline cells\n * --------------------------------------------------------------------------- */\n\n .oc-table-sparkline {\n display: block;\n width: 100%;\n position: relative;\n\n & svg {\n display: block;\n width: 100%;\n overflow: visible;\n }\n }\n\n .oc-table-sparkline-dot {\n position: absolute;\n border-radius: 50%;\n width: 5px;\n height: 5px;\n }\n\n .oc-table-sparkline-labels {\n display: flex;\n justify-content: space-between;\n font-size: 11px;\n line-height: 1;\n }\n\n /* ---------------------------------------------------------------------------\n * Image cells\n * --------------------------------------------------------------------------- */\n\n .oc-table-image {\n display: inline-block;\n vertical-align: middle;\n\n & img {\n object-fit: cover;\n }\n }\n\n .oc-table-image-rounded img {\n border-radius: 50%;\n }\n\n /* ---------------------------------------------------------------------------\n * Flag cells\n * --------------------------------------------------------------------------- */\n\n .oc-table-flag {\n font-size: 1.2em;\n }\n\n /* ---------------------------------------------------------------------------\n * Compact mode\n * --------------------------------------------------------------------------- */\n\n .oc-table--compact {\n & th,\n & td {\n padding: 4px 8px;\n font-size: 13px;\n }\n\n & th {\n font-size: 11px;\n }\n }\n\n /* ---------------------------------------------------------------------------\n * Row hover (when onRowClick is set)\n * --------------------------------------------------------------------------- */\n\n .oc-table--clickable tbody {\n & tr {\n cursor: pointer;\n }\n\n & tr:hover {\n background: var(--oc-hover-bg);\n }\n }\n\n /* ---------------------------------------------------------------------------\n * Keyboard cell focus indicator\n * --------------------------------------------------------------------------- */\n\n .oc-table-cell-focus {\n outline: 2px solid var(--oc-focus);\n outline-offset: -2px;\n }\n\n /* ---------------------------------------------------------------------------\n * Empty state\n * --------------------------------------------------------------------------- */\n\n .oc-table-empty {\n padding: 32px 16px;\n text-align: center;\n color: var(--oc-text-secondary);\n font-size: 14px;\n font-style: italic;\n }\n}\n","@layer oc.components {\n /* ---------------------------------------------------------------------------\n * Tooltip\n * Editorial card matching the new design system: zinc surface, cyan accent,\n * Inter Variable, mono numerics. Sized for a slice tooltip that lists every\n * series at the snapped x.\n * --------------------------------------------------------------------------- */\n\n .oc-tooltip {\n position: absolute;\n display: none;\n pointer-events: none;\n z-index: 1000;\n background: var(--oc-tooltip-bg);\n backdrop-filter: blur(14px);\n border: 1px solid var(--oc-tooltip-border);\n border-radius: var(--oc-border-radius, 2px);\n box-shadow: var(--oc-tooltip-shadow);\n color: var(--oc-tooltip-text);\n font-family: var(--oc-font-family);\n font-size: 12px;\n padding: 0;\n max-width: 280px;\n min-width: 160px;\n line-height: 1.4;\n animation: oc-tooltip-in 120ms ease-out;\n transition:\n left 100ms ease-in-out,\n top 100ms ease-in-out;\n\n & .oc-tooltip-header {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 12px 6px;\n }\n\n & .oc-tooltip-dot {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n flex-shrink: 0;\n }\n\n & .oc-tooltip-title {\n font-weight: 590;\n font-size: 11px;\n letter-spacing: 0.04em;\n text-transform: uppercase;\n color: var(--oc-text-muted);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n & .oc-tooltip-body {\n padding: 6px 12px 10px;\n border-top: 1px solid var(--oc-tooltip-border);\n }\n\n /* No separator when body is the only child */\n & .oc-tooltip-body:first-child {\n border-top: none;\n padding-top: 10px;\n }\n\n & .oc-tooltip-row {\n display: flex;\n align-items: baseline;\n justify-content: space-between;\n gap: 16px;\n padding: 2px 0;\n }\n\n & .oc-tooltip-row-swatch {\n display: inline-block;\n width: 8px;\n height: 8px;\n border-radius: 50%;\n margin-right: 6px;\n flex-shrink: 0;\n transform: translateY(-1px);\n }\n\n & .oc-tooltip-label {\n color: var(--oc-text-secondary);\n font-size: 12px;\n font-weight: 400;\n white-space: nowrap;\n flex-shrink: 0;\n display: inline-flex;\n align-items: center;\n }\n\n & .oc-tooltip-value {\n font-weight: 510;\n font-size: 12px;\n font-variant-numeric: tabular-nums;\n color: var(--oc-tooltip-text);\n text-align: right;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n }\n\n /* ---------------------------------------------------------------------------\n * Crosshair guideline + per-series snap dots (line/area charts)\n * Animate the snap between adjacent points so the indicator slides instead\n * of jumping. ~50ms ease-in-out keeps the motion crisp without lagging.\n * --------------------------------------------------------------------------- */\n\n .oc-crosshair {\n pointer-events: none;\n transition:\n x1 50ms ease-in-out,\n x2 50ms ease-in-out;\n }\n\n .oc-snap-dots circle {\n pointer-events: none;\n transition:\n cx 50ms ease-in-out,\n cy 50ms ease-in-out;\n }\n}\n","@layer oc.animation {\n /* ---------------------------------------------------------------------------\n * Animation keyframes\n * --------------------------------------------------------------------------- */\n\n /* Bar entrance: clip-path reveal bottom-to-top + fade in (vertical columns).\n Bars grow upward from baseline with a soft opacity fade. */\n @keyframes oc-enter-bar {\n from {\n clip-path: inset(100% 0 0 0);\n opacity: 0;\n }\n 75% {\n opacity: 1;\n }\n to {\n clip-path: inset(0 0 0 0);\n opacity: 1;\n }\n }\n\n /* Bar entrance: clip-path reveal left-to-right + fade in (horizontal bars).\n Bars grow rightward from axis with a soft opacity fade. */\n @keyframes oc-enter-bar-h {\n from {\n clip-path: inset(0 100% 0 0);\n opacity: 0;\n }\n 75% {\n opacity: 1;\n }\n to {\n clip-path: inset(0 0 0 0);\n opacity: 1;\n }\n }\n\n /* Line/area entrance: clip-path reveal left-to-right + fade in.\n Lines draw in following reading direction with a soft lead-in. */\n @keyframes oc-enter-line {\n from {\n clip-path: inset(0 100% 0 0);\n opacity: 0;\n }\n 15% {\n opacity: 1;\n }\n to {\n clip-path: inset(0 0 0 0);\n opacity: 1;\n }\n }\n\n /* Point/arc entrance: scale up + fade in from center */\n @keyframes oc-enter-point {\n from {\n opacity: 0;\n transform: scale(0.3);\n }\n to {\n opacity: 1;\n transform: scale(1);\n }\n }\n\n /* Map feature entrance: fade in while transitioning fill from a neutral base\n to the data-driven color stored in --oc-feature-fill. The target opacity is\n --oc-feature-target-opacity (default 1) so features under a focus dim\n animate straight to their dimmed rest opacity instead of hitting 1 and then\n snapping down when the dim is applied post-animation. */\n @keyframes oc-enter-map-fill {\n from {\n fill: var(--oc-secondary);\n opacity: 0;\n }\n to {\n fill: var(--oc-feature-fill);\n opacity: var(--oc-feature-target-opacity, 1);\n }\n }\n\n /* Map point pop-in: gentle scale from 0.75 + fade. Uses transform-origin to\n scale from the circle's own center (cx/cy) rather than the SVG origin. */\n @keyframes oc-enter-map-point {\n from {\n opacity: 0;\n transform: scale(0.75);\n }\n to {\n opacity: 1;\n transform: scale(1);\n }\n }\n\n /* Pure opacity fade (no transform). Safe for elements with existing transforms\n like arc groups that use translate() for positioning. */\n @keyframes oc-enter-fade-only {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n }\n\n /* Fade + subtle slide up for text, rule, tick, annotations */\n @keyframes oc-enter-fade {\n from {\n opacity: 0;\n transform: translateY(4px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n }\n\n /* Table row entrance: slide up only, no opacity (cells fade independently\n to avoid opacity compounding between row and cell animations) */\n @keyframes oc-table-enter-row {\n from {\n transform: translateY(6px);\n }\n to {\n transform: translateY(0);\n }\n }\n\n /* Table bar fill entrance: clip-path grow only, no opacity\n (preserves resting opacity: 0.15 from table.css) */\n @keyframes oc-table-enter-bar-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\n /* Tooltip entrance */\n @keyframes oc-tooltip-in {\n from {\n opacity: 0;\n transform: translateY(2px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n }\n}\n","@layer oc.base {\n /* ---------------------------------------------------------------------------\n * Wrapper roots\n * --------------------------------------------------------------------------- */\n\n .oc-chart-root {\n width: 100%;\n height: 100%;\n }\n\n .oc-table-root,\n .oc-graph-root,\n .oc-sankey-root,\n .oc-barlist-root,\n .oc-tilemap-root,\n .oc-map-root {\n width: 100%;\n height: 100%;\n }\n\n .oc-table-root {\n overflow: auto;\n }\n\n /* ---------------------------------------------------------------------------\n * Chart container\n * --------------------------------------------------------------------------- */\n\n .oc-chart {\n font-family: var(--oc-font-family);\n display: block;\n width: 100%;\n }\n\n /* ---------------------------------------------------------------------------\n * BarList SVG container\n * --------------------------------------------------------------------------- */\n\n .oc-tilemap,\n .oc-map {\n display: block;\n width: 100%;\n height: auto;\n }\n\n .oc-map-feature {\n transition: opacity 400ms ease;\n }\n\n .oc-barlist {\n display: block;\n width: 100%;\n }\n\n /* ---------------------------------------------------------------------------\n * Screen reader only utility\n * --------------------------------------------------------------------------- */\n\n /* `overflow: clip`, not `hidden` — see applySrOnlyStyles in\n packages/vanilla/src/dom-helpers.ts for why. Keep the two in sync. */\n .oc-sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: clip;\n clip-path: inset(50%);\n white-space: nowrap;\n border-width: 0;\n }\n\n /* ---------------------------------------------------------------------------\n * Editable hover feedback\n * --------------------------------------------------------------------------- */\n\n .oc-editable-hover {\n outline: 1.5px solid var(--oc-editable-hover);\n outline-offset: 2px;\n border-radius: 2px;\n }\n\n /* ---------------------------------------------------------------------------\n * Keyboard focus indicators\n *\n * --oc-focus carries a light value in tokens.css and a dark value in\n * dark.css, so both rings stay visible in either mode.\n * --------------------------------------------------------------------------- */\n\n /* Container ring when the chart itself receives keyboard focus. */\n .oc-root:focus-visible {\n outline: 2px solid var(--oc-focus);\n outline-offset: 2px;\n }\n\n /* Mark ring during arrow-key navigation (see wireKeyboardNav). Outline on\n * SVG elements draws around the mark's bounding box, same technique as\n * .oc-editable-hover above. */\n .oc-mark-focused {\n outline: 2px solid var(--oc-focus);\n outline-offset: 1px;\n border-radius: 2px;\n }\n}\n","@layer oc.animation {\n /* ---------------------------------------------------------------------------\n * Table entrance animations (.oc-table-wrapper.oc-animate)\n * --------------------------------------------------------------------------- */\n\n .oc-table-wrapper.oc-animate {\n /* Chrome (title/subtitle): fade + slide up */\n & > .oc-chrome {\n animation: oc-enter-fade calc(var(--oc-animation-duration) * 0.6)\n var(--oc-animation-ease, var(--oc-ease-smooth)) both;\n }\n\n /* Table header: quick fade before rows start */\n & thead {\n animation: oc-enter-fade-only calc(var(--oc-animation-duration) * 0.4)\n var(--oc-animation-ease, var(--oc-ease-smooth)) both;\n }\n\n /* Row entrance: slide up only, no opacity (cells handle their own fading\n to avoid opacity compounding between row and cell animations) */\n & tbody tr {\n animation: oc-table-enter-row var(--oc-animation-duration)\n var(--oc-animation-ease, var(--oc-ease-smooth)) both;\n animation-delay: calc(var(--oc-animation-stagger) * var(--oc-row-index, 0));\n }\n\n /* Cell text: fade in synced with row slide */\n & tbody td {\n animation: oc-enter-fade-only calc(var(--oc-animation-duration) * 0.5)\n var(--oc-animation-ease, var(--oc-ease-smooth)) both;\n animation-delay: calc(var(--oc-animation-stagger) * var(--oc-row-index, 0));\n }\n\n /* Heatmap/category cell backgrounds: longer fade, delayed after row appears */\n & td.oc-table-heatmap,\n & td.oc-table-category {\n animation: oc-enter-fade-only calc(var(--oc-animation-duration) * 0.7)\n var(--oc-animation-ease, var(--oc-ease-smooth)) both;\n animation-delay: calc(\n var(--oc-animation-stagger) *\n var(--oc-row-index, 0) +\n var(--oc-animation-duration) *\n 0.3\n );\n }\n\n /* Bar fill: clip-path grow only (no opacity change to preserve resting\n opacity: 0.15 from table.css) */\n & .oc-table-bar-fill {\n animation: oc-table-enter-bar-fill calc(var(--oc-animation-duration) * 0.8)\n var(--oc-animation-ease, var(--oc-ease-smooth)) both;\n animation-delay: calc(\n var(--oc-animation-stagger) *\n var(--oc-row-index, 0) +\n var(--oc-animation-duration) *\n 0.3\n );\n }\n\n /* Sparkline SVG: clip-path reveal left-to-right. Targets the SVG directly\n (not the wrapper) to avoid clipping absolutely-positioned dots and labels. */\n & .oc-table-sparkline > svg {\n animation: oc-enter-line calc(var(--oc-animation-duration) * 0.8)\n var(--oc-animation-ease, var(--oc-ease-smooth)) both;\n animation-delay: calc(\n var(--oc-animation-stagger) *\n var(--oc-row-index, 0) +\n var(--oc-animation-duration) *\n 0.4\n );\n }\n\n /* Sparkline dots and labels: fade in after the line draws through */\n & .oc-table-sparkline-dot,\n & .oc-table-sparkline-labels {\n animation: oc-enter-fade-only calc(var(--oc-animation-duration) * 0.3)\n var(--oc-animation-ease, var(--oc-ease-smooth)) both;\n animation-delay: calc(\n var(--oc-animation-stagger) *\n var(--oc-row-index, 0) +\n var(--oc-animation-duration) *\n 0.8\n );\n }\n\n /* Search and pagination: quick fade on mount */\n & .oc-table-search,\n & .oc-table-pagination {\n animation: oc-enter-fade-only calc(var(--oc-animation-duration) * 0.5)\n var(--oc-animation-ease, var(--oc-ease-smooth)) both;\n }\n }\n}\n","@layer oc.components {\n /* ---------------------------------------------------------------------------\n * Legend\n * --------------------------------------------------------------------------- */\n\n .oc-legend {\n font-family: var(--oc-font-family);\n font-size: var(--oc-body-size);\n }\n\n .oc-legend-entry {\n cursor: default;\n }\n\n .oc-legend text {\n fill: var(--oc-legend-text);\n }\n}\n","@layer oc.components {\n /* ---------------------------------------------------------------------------\n * Graph\n * --------------------------------------------------------------------------- */\n\n .oc-graph-wrapper {\n position: relative;\n overflow: hidden;\n background: var(--oc-bg);\n font-family: var(--oc-font-family);\n width: 100%;\n height: 100%;\n }\n\n .oc-graph-canvas {\n display: block;\n width: 100%;\n height: 100%;\n cursor: grab;\n }\n\n .oc-graph-canvas--dragging {\n cursor: grabbing;\n }\n\n .oc-graph-chrome {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n z-index: 2;\n padding: 16px 16px 8px;\n pointer-events: none;\n\n & .oc-title {\n font-size: var(--oc-title-size);\n font-weight: var(--oc-title-weight);\n letter-spacing: var(--oc-title-tracking);\n color: var(--oc-text);\n margin: 0 0 4px;\n --_stroke: color-mix(in srgb, var(--oc-bg) 80%, transparent);\n text-shadow:\n -2px -2px 0 var(--_stroke),\n 2px -2px 0 var(--_stroke),\n -2px 2px 0 var(--_stroke),\n 2px 2px 0 var(--_stroke),\n 0 -2px 0 var(--_stroke),\n 0 2px 0 var(--_stroke),\n -2px 0 0 var(--_stroke),\n 2px 0 0 var(--_stroke);\n }\n\n & .oc-subtitle {\n font-size: var(--oc-subtitle-size);\n color: var(--oc-text-secondary);\n margin: 0;\n --_stroke: color-mix(in srgb, var(--oc-bg) 80%, transparent);\n text-shadow:\n -1px -1px 0 var(--_stroke),\n 1px -1px 0 var(--_stroke),\n -1px 1px 0 var(--_stroke),\n 1px 1px 0 var(--_stroke);\n }\n }\n\n .oc-graph-legend {\n position: absolute;\n top: 8px;\n right: 8px;\n background: var(--oc-bg);\n border: 1px solid var(--oc-border);\n border-radius: var(--oc-border-radius);\n padding: 8px 12px;\n font-size: 12px;\n color: var(--oc-text-secondary);\n max-height: 200px;\n overflow-y: auto;\n }\n\n .oc-graph-legend-item {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 2px 0;\n /* Button reset for interactive rows (rendered as <button>). */\n width: 100%;\n margin: 0;\n background: none;\n border: none;\n font: inherit;\n color: inherit;\n text-align: left;\n cursor: default;\n }\n\n /* Interactive legend rows are buttons; give them affordance + a focus ring. */\n button.oc-graph-legend-item {\n cursor: pointer;\n border-radius: 4px;\n\n &:hover {\n background: var(--oc-focus-ring);\n }\n\n &:focus-visible {\n outline: 2px solid var(--oc-focus);\n outline-offset: 1px;\n }\n }\n\n /* De-emphasized (toggled-off) category. */\n .oc-graph-legend-item--inactive {\n opacity: 0.45;\n }\n\n .oc-graph-legend-label {\n flex: 1 1 auto;\n }\n\n .oc-graph-legend-count {\n color: var(--oc-text-secondary);\n font-variant-numeric: tabular-nums;\n margin-left: auto;\n padding-left: 8px;\n }\n\n .oc-graph-legend-swatch {\n width: 10px;\n height: 10px;\n border-radius: 50%;\n flex-shrink: 0;\n }\n\n /* Edge-legend swatches render as a short line, not a dot. */\n .oc-graph-legend-swatch--line {\n width: 12px;\n height: 3px;\n border-radius: 1px;\n }\n\n .oc-graph-search {\n position: absolute;\n top: 8px;\n left: 8px;\n\n & input {\n font-family: var(--oc-font-family);\n font-size: var(--oc-body-size);\n padding: 6px 10px;\n border: 1px solid var(--oc-border);\n border-radius: var(--oc-border-radius);\n background: var(--oc-bg);\n color: var(--oc-text);\n outline: none;\n\n &:focus {\n border-color: var(--oc-focus);\n box-shadow: 0 0 0 2px var(--oc-focus-ring-strong);\n }\n }\n }\n\n /* Dark mode graph overrides (darker bg for canvas-based rendering) */\n .oc-dark .oc-graph-wrapper,\n .oc-graph-wrapper.oc-dark {\n /* GitHub-dark canvas background, intentionally not a token */\n --oc-bg: #0d1117;\n }\n\n /*\n * graph-mount.ts stamps .oc-dark on both .oc-graph-wrapper and\n * .oc-graph-container simultaneously, so the self-variant\n * (.oc-dark.oc-graph-wrapper) and descendant variant\n * (.oc-dark .oc-graph-legend) resolve identically.\n */\n .oc-dark .oc-graph-legend,\n .oc-dark.oc-graph-wrapper .oc-graph-legend,\n .oc-dark .oc-graph-search input {\n background: rgba(13, 17, 23, 0.85);\n border-color: var(--oc-border);\n }\n}\n","@layer oc.animation {\n /* ---------------------------------------------------------------------------\n * Animation scoped rules (.oc-animate enables animation on the chart root)\n * --------------------------------------------------------------------------- */\n\n .oc-animate {\n /* Vertical bars (default): smooth ease-out, no overshoot.\n oc-mark-bar is reserved for future mark type aliases. */\n & .oc-mark-rect rect,\n & .oc-mark-bar rect {\n animation: oc-enter-bar var(--oc-animation-duration) var(--oc-ease-smooth) both;\n animation-delay: calc(var(--oc-animation-stagger) * var(--oc-mark-index, 0));\n }\n\n /* Horizontal bars (data-orient is on the mark group, not the SVG root) */\n & .oc-mark-rect[data-orient=\"horizontal\"] rect,\n & .oc-mark-bar[data-orient=\"horizontal\"] rect {\n animation-name: oc-enter-bar-h;\n }\n\n /* Stacked bar/column segments: chain sequentially so each segment starts\n right when the previous one finishes, creating one fluid reveal.\n Uses linear easing so handoffs between segments are seamless (no\n deceleration/acceleration stutter at segment boundaries). */\n & .oc-mark-rect[data-stack-pos] rect {\n animation-duration: var(--oc-stack-segment-duration, 150ms);\n animation-timing-function: linear;\n animation-delay: calc(\n var(--oc-animation-stagger) *\n var(--oc-mark-index, 0) +\n var(--oc-stack-pos, 0) *\n var(--oc-stack-segment-duration, 150ms)\n );\n }\n\n /* Line marks: entire group clips left-to-right (no WAAPI needed) */\n & .oc-mark-line {\n animation: oc-enter-line var(--oc-animation-duration)\n var(--oc-animation-ease, var(--oc-ease-smooth)) both;\n animation-delay: calc(var(--oc-animation-stagger) * var(--oc-mark-index, 0));\n }\n\n /* Area marks: entire group clips left-to-right + fades in */\n & .oc-mark-area {\n animation: oc-enter-line var(--oc-animation-duration)\n var(--oc-animation-ease, var(--oc-ease-smooth)) both;\n animation-delay: calc(var(--oc-animation-stagger) * var(--oc-mark-index, 0));\n }\n\n /* Arc marks (pie/donut slices): simple fade in.\n Scale transforms break arc positioning because arcs use translate()\n on parent groups. A clean fade is more elegant for pie/donut anyway. */\n & .oc-mark-arc {\n animation: oc-enter-fade-only var(--oc-animation-duration)\n var(--oc-animation-ease, var(--oc-ease-smooth)) both;\n animation-delay: calc(var(--oc-animation-stagger) * var(--oc-mark-index, 0));\n }\n\n /* Point marks (scatter, dot).\n Points render as bare <circle> elements with class oc-mark-point directly,\n not wrapped in a group, so we target circle.oc-mark-point (not descendant).\n Duration is 40% of the configured duration (quick pop-in relative to other marks). */\n & circle.oc-mark-point,\n & circle.oc-mark-circle {\n animation: oc-enter-fade-only calc(var(--oc-animation-duration) * 0.4)\n var(--oc-animation-ease, var(--oc-ease-smooth)) both;\n animation-delay: calc(var(--oc-animation-stagger) * var(--oc-mark-index, 0));\n }\n\n /* Points on line/area charts: delay so they pop in as the line draws through. */\n & .oc-mark-line ~ circle.oc-mark-point,\n & .oc-mark-area ~ circle.oc-mark-point {\n animation-delay: calc(\n var(--oc-animation-duration) *\n 0.35 +\n var(--oc-animation-stagger) *\n var(--oc-mark-index, 0)\n );\n }\n\n /* Text marks: fade + slight slide up */\n & .oc-mark-text text {\n animation: oc-enter-fade calc(var(--oc-animation-duration) * 0.6)\n var(--oc-animation-ease, var(--oc-ease-smooth)) both;\n animation-delay: calc(var(--oc-animation-stagger) * var(--oc-mark-index, 0));\n }\n\n /* Rule marks: fade in */\n & .oc-mark-rule line {\n animation: oc-enter-fade calc(var(--oc-animation-duration) * 0.5)\n var(--oc-animation-ease, var(--oc-ease-smooth)) both;\n animation-delay: calc(var(--oc-animation-stagger) * var(--oc-mark-index, 0));\n }\n\n /* Tick marks: fade in */\n & .oc-mark-tick line {\n animation: oc-enter-fade calc(var(--oc-animation-duration) * 0.5)\n var(--oc-animation-ease, var(--oc-ease-smooth)) both;\n animation-delay: calc(var(--oc-animation-stagger) * var(--oc-mark-index, 0));\n }\n\n /* Data labels: fade after their parent mark */\n & .oc-mark-label {\n animation: oc-enter-fade 300ms var(--oc-ease-smooth) both;\n animation-delay: calc(\n var(--oc-animation-stagger) *\n var(--oc-mark-index, 0) +\n var(--oc-animation-duration) *\n 0.7\n );\n }\n\n /* Annotations: fade in after marks finish */\n & .oc-annotation {\n animation: oc-enter-fade 400ms var(--oc-ease-smooth) both;\n animation-delay: calc(var(--oc-animation-duration) + var(--oc-annotation-delay, 200ms));\n }\n\n /* Tilemap tiles: fade in with jittered stagger for organic feel.\n Per-tile delay is computed in the renderer with pseudo-random variation. */\n & .oc-tilemap-tile {\n animation: oc-enter-fade-only calc(var(--oc-animation-duration) * 0.35) ease-in both;\n animation-delay: var(--oc-tile-delay, 0ms);\n }\n\n /* Map features: fill color reveal with shuffled stagger.\n Per-feature --oc-map-delay is computed in the renderer via a seeded\n Fisher-Yates shuffle so features pop in organically. */\n & .oc-map-feature {\n animation: oc-enter-map-fill var(--oc-animation-duration)\n var(--oc-animation-ease, var(--oc-ease-smooth)) both;\n animation-delay: var(--oc-map-delay, 0ms);\n }\n\n /* Bulk mode: high feature counts (counties, ~3k+) get a single group\n fade instead of per-feature fill animations. opacity is GPU-compositable\n so this stays smooth regardless of child count. */\n & .oc-map-features[data-bulk-animate] {\n animation: oc-enter-fade-only var(--oc-animation-duration)\n var(--oc-animation-ease, var(--oc-ease-smooth)) both;\n }\n\n & .oc-map-features[data-bulk-animate] .oc-map-feature {\n animation: none;\n }\n\n /* Map borders: fade in near the end of the feature sweep */\n & .oc-map-borders path {\n animation: oc-enter-fade-only calc(var(--oc-animation-duration) * 0.4) ease-in both;\n animation-delay: calc(var(--oc-animation-duration) * 0.7);\n }\n\n /* Map points: gentle scale (0.75->1) + fade pop-in after borders.\n transform-origin set per-circle in the renderer so scale happens\n around each circle's own center, not the SVG origin. */\n & .oc-map-point {\n animation: oc-enter-map-point calc(var(--oc-animation-duration) * 0.4)\n var(--oc-animation-ease, var(--oc-ease-smooth)) both;\n animation-delay: calc(\n var(--oc-animation-duration) *\n 0.8 +\n var(--oc-mark-index, 0) *\n var(--oc-point-stagger, 60ms)\n );\n }\n\n /* Sankey nodes: fade in with stagger by column depth (left-to-right) */\n & .oc-sankey-node rect {\n animation: oc-enter-fade-only var(--oc-animation-duration)\n var(--oc-animation-ease, var(--oc-ease-smooth)) both;\n animation-delay: calc(var(--oc-animation-stagger) * var(--oc-mark-index, 0));\n }\n\n /* Sankey links: fade in after nodes, with stagger.\n Links delay by 30% of duration so nodes appear first, then links flow in. */\n & .oc-sankey-link path {\n animation: oc-enter-fade-only var(--oc-animation-duration)\n var(--oc-animation-ease, var(--oc-ease-smooth)) both;\n animation-delay: calc(\n var(--oc-animation-duration) *\n 0.3 +\n var(--oc-animation-stagger) *\n var(--oc-mark-index, 0)\n );\n }\n\n /* Barlist rows: fade + slide up per row, bars grow left-to-right */\n & .oc-barlist-row {\n animation: oc-enter-fade calc(var(--oc-animation-duration) * 0.6)\n var(--oc-animation-ease, var(--oc-ease-smooth)) both;\n animation-delay: var(--oc-row-delay, 0ms);\n }\n\n & .oc-barlist-bar {\n animation: oc-enter-bar-h var(--oc-animation-duration)\n var(--oc-animation-ease, var(--oc-ease-smooth)) both;\n animation-delay: var(--oc-row-delay, 0ms);\n }\n }\n\n /* ---------------------------------------------------------------------------\n * Sparkline mode: pair the line/area reveal with a stronger ease-out so it\n * doesn't read as a uniform left-to-right swipe. cubic-bezier(0.16, 1, 0.3, 1)\n * is \"expo-out\" — fast initial draw that decelerates noticeably at the end,\n * giving the trend a hand-drawn feel. Duration is bumped via the engine\n * (compile.ts) so the cleanup timer stays in sync.\n * --------------------------------------------------------------------------- */\n\n .oc-animate[data-display=\"sparkline\"] .oc-mark-line,\n .oc-animate[data-display=\"sparkline\"] .oc-mark-area {\n animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1);\n }\n}\n","@layer oc.components {\n /* ---------------------------------------------------------------------------\n * Series search (seriesSearch)\n *\n * DOM combobox overlaid on the SVG band the engine reserves below chrome.\n * The wrapper is absolutely positioned by the vanilla adapter (inline\n * left/top/width/height), so everything here is visual only. All colors come\n * from --oc-* tokens, which flip in .oc-dark.\n * --------------------------------------------------------------------------- */\n\n .oc-series-search {\n position: absolute;\n display: flex;\n align-items: center;\n justify-content: flex-end;\n gap: 8px;\n font-family: var(--oc-font-family);\n z-index: 10;\n }\n\n /* Chips: removable filter tokens for the current selection. They flow to the\n * left of the input and scroll horizontally rather than wrapping over the\n * chart when a reader picks many series. */\n .oc-series-search-chips {\n display: flex;\n align-items: center;\n gap: 6px;\n min-width: 0;\n overflow-x: auto;\n scrollbar-width: none;\n }\n\n .oc-series-search-chips::-webkit-scrollbar {\n display: none;\n }\n\n .oc-series-search-chip {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 3px 4px 3px 10px;\n border: 1px solid var(--oc-border);\n border-radius: 999px;\n background: var(--oc-secondary);\n color: var(--oc-text-secondary);\n font-size: 12px;\n font-weight: 500;\n line-height: 16px;\n white-space: nowrap;\n }\n\n .oc-series-search-chip-remove {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n /* 16px glyph, but a >=24px hit area (WCAG 2.5.5 target size) via padding\n pulled back with negative margin so the chip layout stays tight. */\n width: 16px;\n height: 16px;\n padding: 4px;\n margin: -4px -2px -4px -4px;\n border: none;\n border-radius: 50%;\n background: transparent;\n color: var(--oc-text-muted);\n cursor: pointer;\n transition:\n color 0.15s,\n background-color 0.15s;\n }\n\n .oc-series-search-chip-remove:hover {\n color: var(--oc-text);\n background: var(--oc-hover-bg);\n }\n\n .oc-series-search-chip-remove:focus-visible {\n outline: 2px solid var(--oc-focus);\n outline-offset: 1px;\n }\n\n .oc-series-search-chip-remove svg {\n display: block;\n }\n\n /* Combobox: input + popup listbox. Styling matches the table search input\n * (border, radius, focus ring) so the two search surfaces read as one system. */\n .oc-series-search-box {\n position: relative;\n flex: 0 1 220px;\n min-width: 120px;\n }\n\n .oc-series-search-icon {\n position: absolute;\n left: 9px;\n top: 50%;\n transform: translateY(-50%);\n color: var(--oc-text-muted);\n pointer-events: none;\n }\n\n /* Shared skin provided by the grouped rule in table.css.\n Only divergent props live here. */\n .oc-series-search-input {\n height: 32px;\n padding: 0 10px 0 28px;\n }\n\n .oc-series-search-listbox {\n position: absolute;\n top: calc(100% + 4px);\n right: 0;\n min-width: 100%;\n max-height: 240px;\n overflow-y: auto;\n margin: 0;\n padding: 4px;\n list-style: none;\n border: 1px solid var(--oc-border);\n border-radius: 8px;\n background: var(--oc-card);\n box-shadow: var(--oc-tooltip-shadow);\n z-index: 20;\n }\n\n .oc-series-search-option {\n padding: 6px 10px;\n border-radius: 4px;\n font-size: 13px;\n color: var(--oc-text);\n cursor: pointer;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n .oc-series-search-option[aria-selected=\"true\"],\n .oc-series-search-option:hover {\n background: var(--oc-hover-bg);\n }\n\n /* The typed substring within each suggestion. */\n .oc-series-search-match {\n font-weight: 600;\n }\n\n .oc-series-search-empty {\n padding: 6px 10px;\n font-size: 12px;\n color: var(--oc-text-muted);\n }\n}\n","/* ---------------------------------------------------------------------------\n * Reduced motion\n *\n * Catch-all: last-declared layer beats every earlier layer regardless of\n * specificity. No !important, no hand-maintained selector mirror.\n *\n * Selector list matches CSS_TOKEN_ROOT_SELECTORS in token-definitions.ts.\n * --------------------------------------------------------------------------- */\n\n@layer oc.reduced-motion {\n @media (prefers-reduced-motion: reduce) {\n :is(\n .oc-root,\n .oc-chart-root,\n .oc-table-wrapper,\n .oc-table-root,\n .oc-graph-wrapper,\n .oc-graph-root,\n .oc-sankey-root,\n .oc-tilemap-root,\n .oc-barlist-root,\n .oc-map-root\n ),\n :is(\n .oc-root,\n .oc-chart-root,\n .oc-table-wrapper,\n .oc-table-root,\n .oc-graph-wrapper,\n .oc-graph-root,\n .oc-sankey-root,\n .oc-tilemap-root,\n .oc-barlist-root,\n .oc-map-root\n )\n *,\n :is(\n .oc-root,\n .oc-chart-root,\n .oc-table-wrapper,\n .oc-table-root,\n .oc-graph-wrapper,\n .oc-graph-root,\n .oc-sankey-root,\n .oc-tilemap-root,\n .oc-barlist-root,\n .oc-map-root\n )\n *::before,\n :is(\n .oc-root,\n .oc-chart-root,\n .oc-table-wrapper,\n .oc-table-root,\n .oc-graph-wrapper,\n .oc-graph-root,\n .oc-sankey-root,\n .oc-tilemap-root,\n .oc-barlist-root,\n .oc-map-root\n )\n *::after {\n animation: none;\n transition: none;\n }\n }\n}\n"],"names":[]}