@designtools/codesurface 0.1.2 → 0.1.7

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.
Files changed (54) hide show
  1. package/dist/cli.js +239 -67
  2. package/dist/client/assets/index-1q-WwsbN.css +1 -0
  3. package/dist/client/assets/index-A_L26x1h.js +164 -0
  4. package/dist/client/assets/index-B6jN1q8m.js +221 -0
  5. package/dist/client/assets/index-B7jQZQIh.js +164 -0
  6. package/dist/client/assets/index-BSe1-ayg.js +221 -0
  7. package/dist/client/assets/index-BoqOSsiL.js +164 -0
  8. package/dist/client/assets/index-BrTweOBw.css +1 -0
  9. package/dist/client/assets/index-BvlvZBFo.js +164 -0
  10. package/dist/client/assets/index-C8zdCN9Y.css +1 -0
  11. package/dist/client/assets/index-CNoLX-EE.css +1 -0
  12. package/dist/client/assets/index-Caw3C8nD.js +164 -0
  13. package/dist/client/assets/index-CiJuTDXP.css +1 -0
  14. package/dist/client/assets/index-D4qADRtt.js +221 -0
  15. package/dist/client/assets/index-DOOYG-7t.js +221 -0
  16. package/dist/client/assets/index-DOo00IKO.js +164 -0
  17. package/dist/client/assets/index-Dd5ywdn8.css +1 -0
  18. package/dist/client/assets/index-lOuYsLDH.css +1 -0
  19. package/dist/client/assets/index-s0F6GbJf.js +164 -0
  20. package/dist/client/assets/index-xf9QDxu1.css +1 -0
  21. package/dist/client/index.html +2 -2
  22. package/package.json +3 -1
  23. package/dist/client/assets/index-B5g8qgFW.css +0 -1
  24. package/dist/client/assets/index-BB9cuIlF.js +0 -111
  25. package/dist/client/assets/index-BH-ji2K7.js +0 -150
  26. package/dist/client/assets/index-BH4MtIeE.js +0 -150
  27. package/dist/client/assets/index-BRJOTqhn.js +0 -130
  28. package/dist/client/assets/index-Bb8QmYLf.css +0 -1
  29. package/dist/client/assets/index-BdWkGSfZ.js +0 -130
  30. package/dist/client/assets/index-BnRqJ-Bb.js +0 -150
  31. package/dist/client/assets/index-BneJISnX.js +0 -150
  32. package/dist/client/assets/index-C9_QxP1g.css +0 -1
  33. package/dist/client/assets/index-CBjuhHfq.js +0 -150
  34. package/dist/client/assets/index-CEFmdeB7.css +0 -1
  35. package/dist/client/assets/index-CQpCDasO.js +0 -131
  36. package/dist/client/assets/index-CRUCeIYi.css +0 -1
  37. package/dist/client/assets/index-CUSGVUIj.js +0 -150
  38. package/dist/client/assets/index-CdshIoQY.css +0 -1
  39. package/dist/client/assets/index-Cne4pc0S.css +0 -1
  40. package/dist/client/assets/index-Cps9lJoI.css +0 -1
  41. package/dist/client/assets/index-Cs7mKzsY.css +0 -1
  42. package/dist/client/assets/index-D11nArXR.css +0 -1
  43. package/dist/client/assets/index-D2DhQd-K.js +0 -51
  44. package/dist/client/assets/index-DG2JRz0f.js +0 -150
  45. package/dist/client/assets/index-DO-UYUx0.js +0 -150
  46. package/dist/client/assets/index-DOb58Ii1.js +0 -111
  47. package/dist/client/assets/index-DVd7DS_W.css +0 -1
  48. package/dist/client/assets/index-DZNHUm4M.js +0 -130
  49. package/dist/client/assets/index-Di7zgczR.css +0 -1
  50. package/dist/client/assets/index-DlUCyHdA.css +0 -1
  51. package/dist/client/assets/index-FTflg87d.js +0 -130
  52. package/dist/client/assets/index-U5_kmGxX.js +0 -150
  53. package/dist/client/assets/index-_4EXPfyt.css +0 -1
  54. package/dist/client/assets/index-gow3pju2.css +0 -1
package/dist/cli.js CHANGED
@@ -1297,8 +1297,8 @@ function categorizeToken(name, value) {
1297
1297
  return "other";
1298
1298
  }
1299
1299
  function getTokenGroup(name) {
1300
- const n3 = name.replace(/^--/, "");
1301
- const scaleMatch = n3.match(/^([\w]+)-\d+$/);
1300
+ const n4 = name.replace(/^--/, "");
1301
+ const scaleMatch = n4.match(/^([\w]+)-\d+$/);
1302
1302
  if (scaleMatch) return scaleMatch[1];
1303
1303
  const semanticPrefixes = [
1304
1304
  "primary",
@@ -1309,19 +1309,19 @@ function getTokenGroup(name) {
1309
1309
  "warning"
1310
1310
  ];
1311
1311
  for (const prefix of semanticPrefixes) {
1312
- if (n3 === prefix || n3.startsWith(`${prefix}-`)) return prefix;
1312
+ if (n4 === prefix || n4.startsWith(`${prefix}-`)) return prefix;
1313
1313
  }
1314
- if (["background", "foreground", "card", "card-foreground", "popover", "popover-foreground"].includes(n3)) {
1314
+ if (["background", "foreground", "card", "card-foreground", "popover", "popover-foreground"].includes(n4)) {
1315
1315
  return "surface";
1316
1316
  }
1317
- if (["border", "input", "ring", "muted", "muted-foreground", "accent", "accent-foreground"].includes(n3)) {
1317
+ if (["border", "input", "ring", "muted", "muted-foreground", "accent", "accent-foreground"].includes(n4)) {
1318
1318
  return "utility";
1319
1319
  }
1320
- if (n3.startsWith("chart")) return "chart";
1321
- if (n3.startsWith("sidebar")) return "sidebar";
1322
- if (n3.startsWith("radius")) return "radius";
1323
- if (n3.startsWith("shadow")) return "shadow";
1324
- if (n3.startsWith("border-width")) return "border";
1320
+ if (n4.startsWith("chart")) return "chart";
1321
+ if (n4.startsWith("sidebar")) return "sidebar";
1322
+ if (n4.startsWith("radius")) return "radius";
1323
+ if (n4.startsWith("shadow")) return "shadow";
1324
+ if (n4.startsWith("border-width")) return "border";
1325
1325
  return "other";
1326
1326
  }
1327
1327
  function detectColorFormat(value) {
@@ -1335,6 +1335,8 @@ function detectColorFormat(value) {
1335
1335
  // src/server/lib/scan-components.ts
1336
1336
  import fs5 from "fs/promises";
1337
1337
  import path5 from "path";
1338
+ import recast2 from "recast";
1339
+ import { namedTypes as n3 } from "ast-types";
1338
1340
  async function scanComponents(projectRoot) {
1339
1341
  const componentDirs = [
1340
1342
  "components/ui",
@@ -1355,86 +1357,253 @@ async function scanComponents(projectRoot) {
1355
1357
  const fullDir = path5.join(projectRoot, componentDir);
1356
1358
  const files = await fs5.readdir(fullDir);
1357
1359
  const tsxFiles = files.filter((f) => f.endsWith(".tsx"));
1360
+ const parser = await getParser();
1358
1361
  const components = [];
1359
1362
  for (const file of tsxFiles) {
1360
1363
  const filePath = path5.join(componentDir, file);
1361
1364
  const source = await fs5.readFile(path5.join(projectRoot, filePath), "utf-8");
1362
- const entry = parseComponent(source, filePath);
1363
- if (entry) {
1364
- components.push(entry);
1365
- }
1365
+ const entries = parseComponentAST(source, filePath, parser);
1366
+ components.push(...entries);
1366
1367
  }
1367
1368
  return { components };
1368
1369
  }
1369
- function parseComponent(source, filePath) {
1370
- const cvaMatch = source.match(
1371
- /const\s+(\w+)\s*=\s*cva\(\s*(["'`])([\s\S]*?)\2\s*,\s*\{/
1372
- );
1373
- const slotMatch = source.match(/data-slot=["'](\w+)["']/);
1374
- if (!slotMatch) return null;
1375
- const dataSlot = slotMatch[1];
1376
- const name = dataSlot.charAt(0).toUpperCase() + dataSlot.slice(1);
1377
- if (!cvaMatch) {
1378
- return {
1370
+ function parseComponentAST(source, filePath, parser) {
1371
+ let ast;
1372
+ try {
1373
+ ast = recast2.parse(source, { parser });
1374
+ } catch {
1375
+ return [];
1376
+ }
1377
+ const cvaMap = /* @__PURE__ */ new Map();
1378
+ const slotToComponent = /* @__PURE__ */ new Map();
1379
+ const exportedNames = /* @__PURE__ */ new Set();
1380
+ const acceptsChildrenSet = /* @__PURE__ */ new Set();
1381
+ let currentComponentName = null;
1382
+ recast2.visit(ast, {
1383
+ // Find cva() calls: const fooVariants = cva("base classes", { variants: {...}, defaultVariants: {...} })
1384
+ visitVariableDeclaration(path17) {
1385
+ for (const decl of path17.node.declarations) {
1386
+ if (n3.VariableDeclarator.check(decl) && n3.Identifier.check(decl.id) && n3.CallExpression.check(decl.init) && isIdentifierNamed(decl.init.callee, "cva")) {
1387
+ const varName = decl.id.name;
1388
+ const args = decl.init.arguments;
1389
+ const baseClasses = extractStringValue(args[0]) || "";
1390
+ const configArg = args[1];
1391
+ const variants = configArg && n3.ObjectExpression.check(configArg) ? extractVariantsFromConfig(configArg) : [];
1392
+ cvaMap.set(varName, { baseClasses, variants });
1393
+ }
1394
+ }
1395
+ this.traverse(path17);
1396
+ },
1397
+ // Find forwardRef and function components to track data-slot and currentComponentName
1398
+ visitCallExpression(path17) {
1399
+ const node = path17.node;
1400
+ if (isForwardRefCall(node)) {
1401
+ const parent = path17.parent?.node;
1402
+ if (n3.VariableDeclarator.check(parent) && n3.Identifier.check(parent.id)) {
1403
+ currentComponentName = parent.id.name;
1404
+ }
1405
+ }
1406
+ this.traverse(path17);
1407
+ },
1408
+ // Find data-slot JSX attributes
1409
+ visitJSXAttribute(path17) {
1410
+ const attr = path17.node;
1411
+ if (n3.JSXIdentifier.check(attr.name) && attr.name.name === "data-slot" && n3.StringLiteral.check(attr.value)) {
1412
+ const slotValue = attr.value.value;
1413
+ const compName = findEnclosingComponentName(path17) || currentComponentName;
1414
+ if (compName) {
1415
+ slotToComponent.set(slotValue, compName);
1416
+ }
1417
+ }
1418
+ this.traverse(path17);
1419
+ },
1420
+ // Detect {...props} spread in JSX — indicates component accepts children
1421
+ visitJSXSpreadAttribute(path17) {
1422
+ const expr = path17.node.argument;
1423
+ if (n3.Identifier.check(expr) && expr.name === "props") {
1424
+ const compName = findEnclosingComponentName(path17) || currentComponentName;
1425
+ if (compName) {
1426
+ acceptsChildrenSet.add(compName);
1427
+ }
1428
+ }
1429
+ this.traverse(path17);
1430
+ },
1431
+ // Collect named exports: export { Button, Card, ... }
1432
+ visitExportNamedDeclaration(path17) {
1433
+ const node = path17.node;
1434
+ if (node.specifiers) {
1435
+ for (const spec of node.specifiers) {
1436
+ if (n3.ExportSpecifier.check(spec) && n3.Identifier.check(spec.exported)) {
1437
+ exportedNames.add(spec.exported.name);
1438
+ }
1439
+ }
1440
+ }
1441
+ if (node.declaration) {
1442
+ if (n3.VariableDeclaration.check(node.declaration)) {
1443
+ for (const decl of node.declaration.declarations) {
1444
+ if (n3.VariableDeclarator.check(decl) && n3.Identifier.check(decl.id)) {
1445
+ exportedNames.add(decl.id.name);
1446
+ }
1447
+ }
1448
+ } else if (n3.FunctionDeclaration.check(node.declaration) && node.declaration.id) {
1449
+ exportedNames.add(node.declaration.id.name);
1450
+ }
1451
+ }
1452
+ this.traverse(path17);
1453
+ },
1454
+ // export default function Foo
1455
+ visitExportDefaultDeclaration(path17) {
1456
+ const decl = path17.node.declaration;
1457
+ if (n3.FunctionDeclaration.check(decl) && decl.id) {
1458
+ exportedNames.add(decl.id.name);
1459
+ }
1460
+ this.traverse(path17);
1461
+ }
1462
+ });
1463
+ recast2.visit(ast, {
1464
+ visitFunctionDeclaration(path17) {
1465
+ const name = path17.node.id ? String(path17.node.id.name) : null;
1466
+ if (name) {
1467
+ currentComponentName = name;
1468
+ this.traverse(path17);
1469
+ currentComponentName = null;
1470
+ } else {
1471
+ this.traverse(path17);
1472
+ }
1473
+ },
1474
+ visitJSXAttribute(path17) {
1475
+ const attr = path17.node;
1476
+ if (n3.JSXIdentifier.check(attr.name) && attr.name.name === "data-slot" && n3.StringLiteral.check(attr.value)) {
1477
+ const slotValue = attr.value.value;
1478
+ if (!slotToComponent.has(slotValue) && currentComponentName) {
1479
+ slotToComponent.set(slotValue, currentComponentName);
1480
+ }
1481
+ }
1482
+ this.traverse(path17);
1483
+ }
1484
+ });
1485
+ const tokenRefs = extractTokenReferences(source);
1486
+ const entries = [];
1487
+ for (const [dataSlot, componentName] of slotToComponent) {
1488
+ const exportName = exportedNames.has(componentName) ? componentName : null;
1489
+ if (!exportName) continue;
1490
+ const cvaVarName = findCvaForComponent(componentName, cvaMap);
1491
+ const cvaData = cvaVarName ? cvaMap.get(cvaVarName) : null;
1492
+ const name = dataSlot.split("-").map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join("");
1493
+ entries.push({
1379
1494
  name,
1380
1495
  filePath,
1381
1496
  dataSlot,
1382
- baseClasses: "",
1383
- variants: [],
1384
- tokenReferences: extractTokenReferences(source)
1385
- };
1497
+ exportName,
1498
+ baseClasses: cvaData?.baseClasses || "",
1499
+ variants: cvaData?.variants || [],
1500
+ tokenReferences: tokenRefs,
1501
+ acceptsChildren: acceptsChildrenSet.has(componentName)
1502
+ });
1386
1503
  }
1387
- const baseClasses = cvaMatch[3].trim();
1388
- const variants = parseVariants(source);
1389
- const tokenReferences = extractTokenReferences(source);
1390
- return {
1391
- name,
1392
- filePath,
1393
- dataSlot,
1394
- baseClasses,
1395
- variants,
1396
- tokenReferences
1397
- };
1504
+ return entries;
1398
1505
  }
1399
- function parseVariants(source) {
1506
+ function isIdentifierNamed(node, name) {
1507
+ return n3.Identifier.check(node) && node.name === name;
1508
+ }
1509
+ function isObjectProperty(node) {
1510
+ return n3.Property.check(node) || n3.ObjectProperty.check(node);
1511
+ }
1512
+ function isForwardRefCall(node) {
1513
+ if (!n3.CallExpression.check(node)) return false;
1514
+ if (isIdentifierNamed(node.callee, "forwardRef")) return true;
1515
+ if (n3.MemberExpression.check(node.callee) && isIdentifierNamed(node.callee.object, "React") && isIdentifierNamed(node.callee.property, "forwardRef")) {
1516
+ return true;
1517
+ }
1518
+ return false;
1519
+ }
1520
+ function extractStringValue(node) {
1521
+ if (!node) return null;
1522
+ if (n3.StringLiteral.check(node) || n3.Literal.check(node) && typeof node.value === "string") {
1523
+ return String(node.value);
1524
+ }
1525
+ if (n3.TemplateLiteral.check(node) && node.expressions.length === 0 && node.quasis.length === 1) {
1526
+ return node.quasis[0].value.cooked || node.quasis[0].value.raw;
1527
+ }
1528
+ return null;
1529
+ }
1530
+ function extractVariantsFromConfig(configObj) {
1400
1531
  const dimensions = [];
1401
- const variantsBlock = source.match(/variants\s*:\s*\{([\s\S]*?)\}\s*,?\s*defaultVariants/);
1402
- if (!variantsBlock) return dimensions;
1403
- const block = variantsBlock[1];
1404
- const dimRegex = /(\w+)\s*:\s*\{([^}]+)\}/g;
1405
- let dimMatch;
1406
- while ((dimMatch = dimRegex.exec(block)) !== null) {
1407
- const dimName = dimMatch[1];
1408
- const dimBody = dimMatch[2];
1532
+ const variantsProp = findObjProperty(configObj, "variants");
1533
+ if (!variantsProp || !n3.ObjectExpression.check(variantsProp.value)) return dimensions;
1534
+ const defaultVariantsProp = findObjProperty(configObj, "defaultVariants");
1535
+ const defaults = {};
1536
+ if (defaultVariantsProp && n3.ObjectExpression.check(defaultVariantsProp.value)) {
1537
+ for (const prop of defaultVariantsProp.value.properties) {
1538
+ if (isObjectProperty(prop)) {
1539
+ const key = getPropertyKeyName(prop);
1540
+ const val = extractStringValue(prop.value);
1541
+ if (key && val) defaults[key] = val;
1542
+ }
1543
+ }
1544
+ }
1545
+ for (const dimProp of variantsProp.value.properties) {
1546
+ if (!isObjectProperty(dimProp)) continue;
1547
+ const dimName = getPropertyKeyName(dimProp);
1548
+ if (!dimName || !n3.ObjectExpression.check(dimProp.value)) continue;
1409
1549
  const options = [];
1410
1550
  const classes = {};
1411
- const optRegex = /["']?([\w-]+)["']?\s*:\s*\n?\s*["'`]([^"'`]*)["'`]/g;
1412
- let optMatch;
1413
- while ((optMatch = optRegex.exec(dimBody)) !== null) {
1414
- options.push(optMatch[1]);
1415
- classes[optMatch[1]] = optMatch[2].trim();
1416
- }
1417
- const defaultVariantsSection = source.match(
1418
- /defaultVariants\s*:\s*\{([^}]+)\}/
1419
- );
1420
- let defaultVal = options[0] || "";
1421
- if (defaultVariantsSection) {
1422
- const defMatch = defaultVariantsSection[1].match(
1423
- new RegExp(`${dimName}\\s*:\\s*["'](\\w+)["']`)
1424
- );
1425
- if (defMatch) defaultVal = defMatch[1];
1551
+ for (const optProp of dimProp.value.properties) {
1552
+ if (!isObjectProperty(optProp)) continue;
1553
+ const optName = getPropertyKeyName(optProp);
1554
+ const optValue = extractStringValue(optProp.value);
1555
+ if (optName) {
1556
+ options.push(optName);
1557
+ classes[optName] = optValue || "";
1558
+ }
1426
1559
  }
1427
1560
  if (options.length > 0) {
1428
1561
  dimensions.push({
1429
1562
  name: dimName,
1430
1563
  options,
1431
- default: defaultVal,
1564
+ default: defaults[dimName] || options[0],
1432
1565
  classes
1433
1566
  });
1434
1567
  }
1435
1568
  }
1436
1569
  return dimensions;
1437
1570
  }
1571
+ function findObjProperty(obj, name) {
1572
+ for (const prop of obj.properties) {
1573
+ if (isObjectProperty(prop) && getPropertyKeyName(prop) === name) {
1574
+ return prop;
1575
+ }
1576
+ }
1577
+ return null;
1578
+ }
1579
+ function getPropertyKeyName(prop) {
1580
+ if (n3.Identifier.check(prop.key)) return prop.key.name;
1581
+ if (n3.StringLiteral.check(prop.key) || n3.Literal.check(prop.key) && typeof prop.key.value === "string") {
1582
+ return prop.key.value;
1583
+ }
1584
+ return null;
1585
+ }
1586
+ function findEnclosingComponentName(astPath) {
1587
+ let current = astPath.parent;
1588
+ while (current) {
1589
+ const node = current.node;
1590
+ if (n3.VariableDeclarator.check(node) && n3.Identifier.check(node.id)) {
1591
+ return node.id.name;
1592
+ }
1593
+ if (n3.FunctionDeclaration.check(node) && node.id) {
1594
+ return node.id.name;
1595
+ }
1596
+ current = current.parent;
1597
+ }
1598
+ return null;
1599
+ }
1600
+ function findCvaForComponent(componentName, cvaMap) {
1601
+ const lower = componentName.charAt(0).toLowerCase() + componentName.slice(1);
1602
+ const expected = `${lower}Variants`;
1603
+ if (cvaMap.has(expected)) return expected;
1604
+ if (cvaMap.size === 1) return cvaMap.keys().next().value;
1605
+ return null;
1606
+ }
1438
1607
  function extractTokenReferences(source) {
1439
1608
  const tokens = /* @__PURE__ */ new Set();
1440
1609
  const classStrings = source.match(/["'`][^"'`]*["'`]/g) || [];
@@ -1443,8 +1612,7 @@ function extractTokenReferences(source) {
1443
1612
  let match;
1444
1613
  while ((match = tokenPattern.exec(str)) !== null) {
1445
1614
  const val = match[1];
1446
- if (!val.match(/^\d/) && // not a number
1447
- !["xs", "sm", "md", "lg", "xl", "2xl", "3xl", "full", "none"].includes(val) && !val.startsWith("[")) {
1615
+ if (!val.match(/^\d/) && !["xs", "sm", "md", "lg", "xl", "2xl", "3xl", "full", "none"].includes(val) && !val.startsWith("[")) {
1448
1616
  tokens.add(val.split("/")[0]);
1449
1617
  }
1450
1618
  }
@@ -2569,7 +2737,11 @@ function replaceTokenInBlock(css, selector, token, newValue) {
2569
2737
  "g"
2570
2738
  );
2571
2739
  if (!tokenRegex.test(block)) {
2572
- throw new Error(`Token "${token}" not found in "${selector}" block`);
2740
+ const indent = block.match(/\n(\s+)--/)?.[1] ?? " ";
2741
+ block = block.trimEnd() + `
2742
+ ${indent}${token}: ${newValue};
2743
+ `;
2744
+ return css.slice(0, openBrace + 1) + block + css.slice(blockEnd - 1);
2573
2745
  }
2574
2746
  block = block.replace(tokenRegex, `$1${newValue}$3`);
2575
2747
  return css.slice(0, openBrace + 1) + block + css.slice(blockEnd - 1);
@@ -0,0 +1 @@
1
+ /*! tailwindcss v4.1.18 | MIT License | https://tailwindcss.com */@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-outline-style:solid;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-ease:initial}}}@layer theme{:root,:host{--font-sans:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--font-mono:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--spacing:.25rem;--text-sm:.875rem;--text-sm--line-height:calc(1.25/.875);--text-base:1rem;--text-base--line-height: 1.5 ;--text-lg:1.125rem;--text-lg--line-height:calc(1.75/1.125);--text-2xl:1.5rem;--text-2xl--line-height:calc(2/1.5);--font-weight-normal:400;--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--tracking-wide:.025em;--tracking-wider:.05em;--leading-snug:1.375;--leading-relaxed:1.625;--radius-sm:.25rem;--radius-md:.375rem;--radius-lg:.5rem;--ease-in-out:cubic-bezier(.4,0,.2,1);--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4,0,.2,1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;-moz-tab-size:4;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab,red,red)){::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){-webkit-appearance:button;-moz-appearance:button;appearance:button}::file-selector-button{-webkit-appearance:button;-moz-appearance:button;appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}*{box-sizing:border-box;margin:0;padding:0}}@layer components;@layer utilities{.visible{visibility:visible}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.static{position:static}.sticky{position:sticky}.inset-0{inset:calc(var(--spacing)*0)}.top-0{top:calc(var(--spacing)*0)}.top-1\/2{top:50%}.right-0{right:calc(var(--spacing)*0)}.container{width:100%}@media(min-width:40rem){.container{max-width:40rem}}@media(min-width:48rem){.container{max-width:48rem}}@media(min-width:64rem){.container{max-width:64rem}}@media(min-width:80rem){.container{max-width:80rem}}@media(min-width:96rem){.container{max-width:96rem}}.mt-1{margin-top:calc(var(--spacing)*1)}.mt-1\.5{margin-top:calc(var(--spacing)*1.5)}.mt-2{margin-top:calc(var(--spacing)*2)}.mt-auto{margin-top:auto}.mb-0\.5{margin-bottom:calc(var(--spacing)*.5)}.mb-1{margin-bottom:calc(var(--spacing)*1)}.mb-1\.5{margin-bottom:calc(var(--spacing)*1.5)}.mb-2{margin-bottom:calc(var(--spacing)*2)}.mb-3{margin-bottom:calc(var(--spacing)*3)}.ml-1{margin-left:calc(var(--spacing)*1)}.ml-auto{margin-left:auto}.block{display:block}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline{display:inline}.inline-block{display:inline-block}.inline-flex{display:inline-flex}.inline-grid{display:inline-grid}.table{display:table}.h-4{height:calc(var(--spacing)*4)}.h-5{height:calc(var(--spacing)*5)}.h-8{height:calc(var(--spacing)*8)}.h-11{height:calc(var(--spacing)*11)}.h-20{height:calc(var(--spacing)*20)}.h-full{height:100%}.h-screen{height:100vh}.w-1{width:calc(var(--spacing)*1)}.w-1\.5{width:calc(var(--spacing)*1.5)}.w-5{width:calc(var(--spacing)*5)}.w-20{width:calc(var(--spacing)*20)}.w-full{width:100%}.min-w-0{min-width:calc(var(--spacing)*0)}.flex-1{flex:1}.shrink-0{flex-shrink:0}.-translate-y-1\/2{--tw-translate-y: -50% ;translate:var(--tw-translate-x)var(--tw-translate-y)}.transform{transform:var(--tw-rotate-x,)var(--tw-rotate-y,)var(--tw-rotate-z,)var(--tw-skew-x,)var(--tw-skew-y,)}.cursor-ew-resize{cursor:ew-resize}.cursor-pointer{cursor:pointer}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.items-start{align-items:flex-start}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.gap-0\.5{gap:calc(var(--spacing)*.5)}.gap-1{gap:calc(var(--spacing)*1)}.gap-1\.5{gap:calc(var(--spacing)*1.5)}.gap-2{gap:calc(var(--spacing)*2)}.gap-3{gap:calc(var(--spacing)*3)}.gap-4{gap:calc(var(--spacing)*4)}.gap-x-2{column-gap:calc(var(--spacing)*2)}.gap-y-1\.5{row-gap:calc(var(--spacing)*1.5)}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-x-hidden{overflow-x:hidden}.overflow-y-auto{overflow-y:auto}.rounded{border-radius:.25rem}.rounded-full{border-radius:3.40282e38px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-md{border-radius:var(--radius-md)}.rounded-sm{border-radius:var(--radius-sm)}.rounded-tl{border-top-left-radius:.25rem}.rounded-tr{border-top-right-radius:.25rem}.rounded-br{border-bottom-right-radius:.25rem}.rounded-bl{border-bottom-left-radius:.25rem}.border{border-style:var(--tw-border-style);border-width:1px}.border-0{border-style:var(--tw-border-style);border-width:0}.border-1{border-style:var(--tw-border-style);border-width:1px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-r{border-right-style:var(--tw-border-style);border-right-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-l{border-left-style:var(--tw-border-style);border-left-width:1px}.bg-\[var\(--name\)\]{background-color:var(--name)}.bg-\[image\:var\(--name\)\]{background-image:var(--name)}.bg-none{background-image:none}.p-0{padding:calc(var(--spacing)*0)}.p-2\.5{padding:calc(var(--spacing)*2.5)}.p-3{padding:calc(var(--spacing)*3)}.p-4{padding:calc(var(--spacing)*4)}.p-6{padding:calc(var(--spacing)*6)}.px-1{padding-inline:calc(var(--spacing)*1)}.px-1\.5{padding-inline:calc(var(--spacing)*1.5)}.px-3{padding-inline:calc(var(--spacing)*3)}.px-4{padding-inline:calc(var(--spacing)*4)}.px-6{padding-inline:calc(var(--spacing)*6)}.py-0\.5{padding-block:calc(var(--spacing)*.5)}.py-1{padding-block:calc(var(--spacing)*1)}.py-1\.5{padding-block:calc(var(--spacing)*1.5)}.py-2{padding-block:calc(var(--spacing)*2)}.py-2\.5{padding-block:calc(var(--spacing)*2.5)}.py-3{padding-block:calc(var(--spacing)*3)}.py-4{padding-block:calc(var(--spacing)*4)}.py-6{padding-block:calc(var(--spacing)*6)}.py-8{padding-block:calc(var(--spacing)*8)}.pt-0\.5{padding-top:calc(var(--spacing)*.5)}.pt-3{padding-top:calc(var(--spacing)*3)}.pr-2\.5{padding-right:calc(var(--spacing)*2.5)}.pb-1{padding-bottom:calc(var(--spacing)*1)}.pb-2{padding-bottom:calc(var(--spacing)*2)}.pb-2\.5{padding-bottom:calc(var(--spacing)*2.5)}.pb-3{padding-bottom:calc(var(--spacing)*3)}.pb-4{padding-bottom:calc(var(--spacing)*4)}.pl-1{padding-left:calc(var(--spacing)*1)}.pl-2{padding-left:calc(var(--spacing)*2)}.text-center{text-align:center}.text-left{text-align:left}.font-mono{font-family:var(--font-mono)}.text-2xl{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}.text-base{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}.text-lg{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-\[8px\]{font-size:8px}.text-\[9px\]{font-size:9px}.text-\[10px\]{font-size:10px}.text-\[11px\]{font-size:11px}.text-\[12px\]{font-size:12px}.text-\[13px\]{font-size:13px}.leading-relaxed{--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed)}.leading-snug{--tw-leading:var(--leading-snug);line-height:var(--leading-snug)}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-normal{--tw-font-weight:var(--font-weight-normal);font-weight:var(--font-weight-normal)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-wide{--tw-tracking:var(--tracking-wide);letter-spacing:var(--tracking-wide)}.tracking-wider{--tw-tracking:var(--tracking-wider);letter-spacing:var(--tracking-wider)}.capitalize{text-transform:capitalize}.lowercase{text-transform:lowercase}.uppercase{text-transform:uppercase}.italic{font-style:italic}.line-through{text-decoration-line:line-through}.overline{text-decoration-line:overline}.underline{text-decoration-line:underline}.antialiased{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.shadow{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a),0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-\[var\(--name\)\]{--tw-shadow:var(--name);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-none{--tw-shadow:0 0 #0000;box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow\/gradient{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a),0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.outline{outline-style:var(--tw-outline-style);outline-width:1px}.blur{--tw-blur:blur(8px);filter:var(--tw-blur,)var(--tw-brightness,)var(--tw-contrast,)var(--tw-grayscale,)var(--tw-hue-rotate,)var(--tw-invert,)var(--tw-saturate,)var(--tw-sepia,)var(--tw-drop-shadow,)}.filter{filter:var(--tw-blur,)var(--tw-brightness,)var(--tw-contrast,)var(--tw-grayscale,)var(--tw-hue-rotate,)var(--tw-invert,)var(--tw-saturate,)var(--tw-sepia,)var(--tw-drop-shadow,)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.ease-in-out{--tw-ease:var(--ease-in-out);transition-timing-function:var(--ease-in-out)}.select-none{-webkit-user-select:none;user-select:none}}:root{--studio-bg:#0a0a0c;--studio-surface:#1a1a1e;--studio-surface-hover:#242428;--studio-surface-active:#2e2e34;--studio-border:#3c3c44;--studio-border-subtle:#2e2e36;--studio-text:#f4f4f8;--studio-text-muted:#b0b0c0;--studio-text-dimmed:#808094;--studio-input-bg:#121216;--studio-accent:#60a5fa;--studio-accent-hover:#3b82f6;--studio-accent-muted:#60a5fa29;--studio-success:#22c55e;--studio-warning:#f59e0b;--studio-danger:#ef4444}body{background:var(--studio-bg);color:var(--studio-text);-webkit-font-smoothing:antialiased;height:100vh;font-family:-apple-system,BlinkMacSystemFont,Inter,Segoe UI,system-ui,sans-serif;font-size:12px;overflow:hidden}#root{height:100vh}.studio-scrollbar::-webkit-scrollbar{width:5px}.studio-scrollbar::-webkit-scrollbar-track{background:0 0}.studio-scrollbar::-webkit-scrollbar-thumb{background:var(--studio-border);border-radius:3px}.studio-scrollbar::-webkit-scrollbar-thumb:hover{background:var(--studio-text-muted)}.studio-icon-btn{width:28px;height:28px;color:var(--studio-text-muted);cursor:pointer;background:0 0;border:none;border-radius:6px;flex-shrink:0;justify-content:center;align-items:center;transition:background .1s,color .1s;display:inline-flex}.studio-icon-btn:hover{background:var(--studio-surface-hover);color:var(--studio-text)}.studio-icon-btn.active{background:var(--studio-accent);color:#fff}.studio-segmented{background:var(--studio-input-bg);border-radius:6px;gap:1px;padding:2px;display:inline-flex}.studio-segmented button{color:var(--studio-text-dimmed);cursor:pointer;white-space:nowrap;background:0 0;border:none;border-radius:4px;justify-content:center;align-items:center;gap:4px;padding:4px 10px;font-size:11px;font-weight:500;transition:background .1s,color .1s;display:inline-flex;position:relative}.studio-segmented button:hover{color:var(--studio-text);background:#ffffff0a}.studio-segmented button[title]:hover:after{content:attr(title);background:var(--studio-surface,#1e1e1e);color:var(--studio-text,#ccc);text-transform:none;letter-spacing:0;border:1px solid var(--studio-border-subtle,#333);white-space:nowrap;z-index:100;pointer-events:none;border-radius:4px;padding:4px 8px;font-size:10px;font-weight:400;position:absolute;bottom:calc(100% + 6px);left:50%;transform:translate(-50%);box-shadow:0 2px 8px #0000004d}.studio-segmented button.active{background:var(--studio-surface-hover);color:var(--studio-text);box-shadow:0 1px 2px #0003}.studio-segmented.wrap{flex-wrap:wrap}.studio-tab-explainer{color:var(--studio-text-dimmed);background:var(--studio-input-bg);border:1px solid var(--studio-border-subtle);border-radius:6px;align-items:flex-start;gap:8px;padding:10px 14px;font-size:11px;line-height:1.45;display:flex}.studio-tab-explainer svg{width:13px;height:13px;color:var(--studio-text-dimmed);opacity:.6;flex-shrink:0;margin-top:1px}.studio-tab-explainer .studio-explainer-file{color:var(--studio-text-dimmed);opacity:.7;margin-top:3px;font-family:SF Mono,Fira Code,Cascadia Code,monospace;font-size:10px}.studio-section-hdr{text-transform:uppercase;letter-spacing:.05em;color:var(--studio-text-muted);cursor:pointer;-webkit-user-select:none;user-select:none;background:0 0;border:none;align-items:center;gap:5px;width:100%;padding:12px 16px;font-size:9px;font-weight:600;display:flex}.studio-section-hdr:hover{color:var(--studio-text)}.studio-section-hdr .count{color:var(--studio-text-dimmed);margin-left:auto;font-size:9px;font-weight:400}.studio-section-hdr svg{flex-shrink:0;width:10px;height:10px;transition:transform .15s}.studio-tree{border-left:1px solid var(--studio-border-subtle);margin-top:-6px;margin-bottom:6px;margin-left:20px;position:relative}.studio-tree-node{position:relative}.studio-tree-node:before{content:"";background:var(--studio-border-subtle);width:10px;height:1px;position:absolute;top:12px;left:0}.studio-tree-node:last-child:after{content:"";background:var(--studio-surface);width:1px;position:absolute;top:14px;bottom:0;left:-1px}.studio-tree-node>button{padding-left:14px}.studio-tree-node .studio-section-hdr{padding:5px 16px 5px 14px}.studio-tree-content{padding:5px 16px 8px 20px}.studio-prop-row{align-items:center;gap:8px;min-height:26px;padding:2px 16px;display:flex}.studio-prop-label{color:var(--studio-text-dimmed);letter-spacing:.03em;flex-shrink:0;min-width:42px;font-size:10px;font-weight:500}.studio-input{background:var(--studio-input-bg);border:1px solid var(--studio-border-subtle);color:var(--studio-text);border-radius:4px;outline:none;min-width:0;min-height:32px;padding:6px 8px;font-family:SF Mono,Fira Code,Cascadia Code,monospace;font-size:11px;transition:border-color .15s}.studio-input-sm{background:var(--studio-input-bg);border:1px solid var(--studio-border-subtle);color:var(--studio-text);border-radius:4px;outline:none;min-width:0;min-height:28px;padding:4px 8px;font-family:SF Mono,Fira Code,Cascadia Code,monospace;font-size:11px;transition:border-color .15s}.studio-input-sm:focus{border-color:var(--studio-accent)}.studio-input-sm::placeholder{color:var(--studio-text-dimmed)}.studio-input:focus{border-color:var(--studio-accent)}.studio-input::placeholder{color:var(--studio-text-dimmed)}.studio-select{background:var(--studio-input-bg);border:1px solid var(--studio-border-subtle);color:var(--studio-text);cursor:pointer;border-radius:4px;outline:none;align-items:center;gap:4px;min-width:0;min-height:32px;padding:6px 8px;font-family:SF Mono,Fira Code,Cascadia Code,monospace;font-size:11px;transition:border-color .15s;display:flex}.studio-select:focus,.studio-select[data-state=open]{border-color:var(--studio-accent)}.studio-select:hover{border-color:var(--studio-border)}.studio-select .studio-prop-select-value{text-overflow:ellipsis;white-space:nowrap;text-align:left;flex:1;min-width:0;overflow:hidden}.studio-prop-select-trigger{background:var(--studio-input-bg);border:1px solid var(--studio-border-subtle);cursor:pointer;min-width:0;height:26px;color:var(--studio-text);border-radius:5px;outline:none;flex:1;align-items:center;gap:4px;padding:0 6px 0 8px;font-family:SF Mono,Fira Code,Cascadia Code,monospace;font-size:10px;transition:border-color .15s;display:flex}.studio-prop-select-trigger:hover{border-color:var(--studio-border);background:var(--studio-surface-hover)}.studio-prop-select-trigger[data-state=open]{border-color:var(--studio-accent)}.studio-prop-select-value{text-overflow:ellipsis;white-space:nowrap;text-align:left;flex:1;min-width:0;overflow:hidden}.studio-prop-select-content{min-width:var(--radix-select-trigger-width);z-index:10000;background:#1c1c1c;border:1px solid #333;border-radius:7px;padding:4px;box-shadow:0 8px 24px #00000073,0 2px 8px #00000040}.studio-prop-select-group-label{color:var(--studio-text-dimmed);-webkit-user-select:none;user-select:none;padding:4px 8px 2px;font-family:SF Mono,Fira Code,Cascadia Code,monospace;font-size:9px}.studio-prop-select-item{color:var(--studio-text);cursor:pointer;-webkit-user-select:none;user-select:none;border-radius:4px;outline:none;justify-content:space-between;align-items:center;gap:8px;padding:5px 8px;font-family:SF Mono,Fira Code,Cascadia Code,monospace;font-size:10px;display:flex}.studio-prop-select-item[data-highlighted]{background:var(--studio-accent-muted);color:var(--studio-accent)}.studio-prop-select-item[data-state=checked]{color:var(--studio-accent)}.studio-prop-select-check{color:var(--studio-accent);flex-shrink:0;align-items:center;display:flex}.studio-prop-select-separator{background:var(--studio-border-subtle);height:1px;margin:3px 0}.studio-two-col{grid-template-columns:1fr 1fr;gap:4px 8px;display:grid}.studio-swatch{cursor:pointer;background-image:linear-gradient(var(--swatch-color,transparent),var(--swatch-color,transparent)),linear-gradient(45deg,#1a1a24 25%,transparent 25%),linear-gradient(-45deg,#1a1a24 25%,transparent 25%),linear-gradient(45deg,transparent 75%,#1a1a24 75%),linear-gradient(-45deg,transparent 75%,#1a1a24 75%);background-position:0 0,0 0,0 3px,3px -3px,-3px 0;background-size:cover,6px 6px,6px 6px,6px 6px,6px 6px;border:1px inset #ffffff26;border-radius:3px;flex-shrink:0;width:18px;height:18px;transition:box-shadow .1s}.studio-swatch:hover{box-shadow:0 0 0 1px var(--studio-accent)}.studio-address-bar{border:1px solid var(--studio-border-subtle);background:var(--studio-input-bg);border-radius:6px;align-items:center;min-width:300px;max-width:480px;height:28px;transition:border-color .1s;display:flex;overflow:hidden}.studio-toolbar-group{border:1px solid var(--studio-border-subtle);background:var(--studio-input-bg);border-radius:6px;align-items:center;height:28px;display:flex;overflow:hidden}.studio-toolbar-btn{width:28px;height:100%;color:var(--studio-text-muted);cursor:pointer;background:0 0;border:none;flex-shrink:0;justify-content:center;align-items:center;transition:background .1s,color .1s;display:inline-flex}.studio-toolbar-btn:hover{background:var(--studio-surface-hover);color:var(--studio-text)}.studio-toolbar-btn.active{background:var(--studio-accent);color:#fff}.studio-address-bar:focus-within{border-color:var(--studio-accent)}.studio-address-icon{color:var(--studio-text-dimmed);flex-shrink:0;align-items:center;padding:0 6px;display:flex}.studio-address-input{min-width:0;height:100%;color:var(--studio-text);background:0 0;border:none;outline:none;flex:1;padding:0;font-size:11px}.studio-address-input::placeholder{color:var(--studio-text-dimmed)}.studio-address-sep{background:var(--studio-border);flex-shrink:0;width:1px;height:16px;margin:0 8px}.studio-bp-trigger{height:100%;color:var(--studio-text-muted);cursor:pointer;background:0 0;border:none;flex-shrink:0;align-items:center;gap:10px;padding:0 10px 0 4px;font-size:11px;font-weight:500;transition:color .1s;display:flex}.studio-bp-trigger:hover{color:var(--studio-text)}.studio-bp-dropdown{z-index:9999;background:#1c1c1c;border:1px solid #333;border-radius:6px;min-width:110px;padding:4px;animation:.1s studio-dropdown-in;box-shadow:0 8px 24px #00000080}@keyframes studio-dropdown-in{0%{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:translateY(0)}}.studio-bp-option{color:#b0b0b0;cursor:pointer;text-align:left;background:0 0;border:none;border-radius:4px;align-items:center;width:100%;padding:5px 8px;font-size:11px;font-weight:500;transition:background 80ms,color 80ms;display:flex}.studio-bp-option:hover{color:#fff;background:#ffffff14}.studio-bp-option.active{color:#fff}.studio-bp-option-check{color:#fff;flex-shrink:0;width:14px;margin-right:4px;display:inline-flex}.studio-bp-btn{border:1px solid var(--studio-border-subtle);background:var(--studio-input-bg);height:28px;color:var(--studio-text-muted);cursor:pointer;border-radius:4px;justify-content:center;align-items:center;padding:3px 8px;font-family:SF Mono,Fira Code,Cascadia Code,monospace;font-size:11px;font-weight:500;transition:background .1s,color .1s,border-color .1s;display:inline-flex}.studio-bp-btn:hover{background:var(--studio-surface-hover);border-color:var(--studio-border);color:var(--studio-text)}.studio-bp-btn.active{background:var(--studio-accent-muted);border-color:var(--studio-accent);color:var(--studio-accent)}input[type=range]{-webkit-appearance:none;-moz-appearance:none;appearance:none;background:var(--studio-border);border-radius:2px;outline:none;height:3px}input[type=range]::-webkit-slider-thumb{-webkit-appearance:none;-moz-appearance:none;appearance:none;background:var(--studio-accent);cursor:pointer;border:2px solid var(--studio-bg);border-radius:50%;width:12px;height:12px}input[type=range]::-webkit-slider-thumb:hover{background:var(--studio-accent-hover)}.studio-color-trigger{background:var(--studio-input-bg);border:1px solid var(--studio-border-subtle);cursor:pointer;width:100%;color:var(--studio-text);text-align:left;border-radius:4px;align-items:center;gap:8px;padding:4px 6px;font-family:SF Mono,Fira Code,Cascadia Code,monospace;font-size:11px;transition:border-color .15s;display:flex}.studio-color-trigger:hover{border-color:var(--studio-border)}.studio-color-trigger:focus{border-color:var(--studio-accent);outline:none}.studio-color-trigger svg{width:10px;height:10px;color:var(--studio-text-dimmed);flex-shrink:0;margin-left:auto}.studio-color-picker .react-colorful{gap:8px!important;width:100%!important;height:150px!important}.studio-color-picker .react-colorful__saturation{border-radius:6px!important}.studio-color-picker .react-colorful__hue,.studio-color-picker .react-colorful__alpha{border-radius:6px!important;height:12px!important}.studio-color-picker .react-colorful__pointer{border-width:2px!important;width:16px!important;height:16px!important}.studio-tooltip{background:var(--studio-surface-raised,#2a2a2e);color:var(--studio-text-secondary,#b0b0b8);border:1px solid var(--studio-border-subtle,#3a3a40);z-index:99999;pointer-events:none;border-radius:4px;max-width:200px;padding:4px 8px;font-size:11px;line-height:1.3;animation:.12s ease-out studio-tooltip-in;box-shadow:0 2px 8px #0006}.studio-tooltip-arrow{fill:var(--studio-surface-raised,#2a2a2e)}@keyframes studio-tooltip-in{0%{opacity:0;transform:scale(.96)}to{opacity:1;transform:scale(1)}}.studio-popover{z-index:10000;background:var(--studio-surface);border:1px solid var(--studio-border);border-radius:8px;flex-direction:column;width:240px;max-height:400px;padding:6px;display:flex;box-shadow:0 8px 24px #00000080,0 2px 8px #0000004d}.studio-popover-swatch{border:1px solid var(--studio-border);background-image:linear-gradient(var(--swatch-color,transparent),var(--swatch-color,transparent)),linear-gradient(45deg,#1a1a24 25%,transparent 25%),linear-gradient(-45deg,#1a1a24 25%,transparent 25%),linear-gradient(45deg,transparent 75%,#1a1a24 75%),linear-gradient(-45deg,transparent 75%,#1a1a24 75%);background-position:0 0,0 0,0 4px,4px -4px,-4px 0;background-size:cover,8px 8px,8px 8px,8px 8px,8px 8px;border-radius:6px;flex-shrink:0;width:100%;height:48px;margin-bottom:6px}.studio-popover-list{flex-direction:column;gap:1px;max-height:280px;display:flex;overflow-y:auto}.studio-popover-list::-webkit-scrollbar{width:4px}.studio-popover-list::-webkit-scrollbar-thumb{background:var(--studio-border);border-radius:2px}.studio-popover-item{cursor:pointer;text-align:left;color:var(--studio-text);background:0 0;border:none;border-radius:4px;align-items:center;gap:8px;width:100%;padding:5px 8px;font-family:SF Mono,Fira Code,Cascadia Code,monospace;font-size:11px;transition:background .1s;display:flex}.studio-popover-item:hover{background:var(--studio-surface-hover)}.studio-popover-item.active{background:var(--studio-accent-muted);color:var(--studio-accent)}.studio-popover-item .studio-swatch{border-radius:3px;width:16px;height:16px}.studio-scrub-input{background:var(--studio-input-bg);border:1px solid var(--studio-border-subtle);border-radius:4px;align-items:center;width:100%;min-height:32px;transition:border-color .15s;display:flex;overflow:hidden}.studio-scrub-input:focus-within{border-color:var(--studio-accent)}.studio-scrub-icon{cursor:ew-resize;width:30px;min-width:30px;height:32px;color:var(--studio-text-dimmed);flex-shrink:0;justify-content:center;align-items:center;display:flex}.studio-scrub-icon:hover{color:var(--studio-text);background:var(--studio-surface-hover)}.studio-scrub-icon.no-scrub{cursor:default}.studio-scrub-icon.no-scrub:hover{background:0 0}.studio-scrub-label{cursor:ew-resize;width:26px;min-width:26px;height:32px;color:var(--studio-text-dimmed);text-transform:uppercase;flex-shrink:0;justify-content:center;align-items:center;font-size:9px;font-weight:600;display:flex}.studio-scrub-label:hover{color:var(--studio-text);background:var(--studio-surface-hover)}.studio-scrub-label.no-scrub{cursor:default}.studio-scrub-label.no-scrub:hover{background:0 0}.studio-scrub-value{min-width:0;color:var(--studio-text);background:0 0;border:none;outline:none;flex:1;padding:6px 8px;font-family:SF Mono,Fira Code,Cascadia Code,monospace;font-size:11px}.studio-scrub-value::placeholder{color:var(--studio-text-dimmed)}.studio-scale-icon{width:30px;min-width:30px;height:32px;color:var(--studio-text-dimmed);flex-shrink:0;justify-content:center;align-items:center;display:flex}.studio-scale-label{width:26px;min-width:26px;height:32px;color:var(--studio-text-dimmed);text-transform:uppercase;flex-shrink:0;justify-content:center;align-items:center;font-size:9px;font-weight:600;display:flex}.studio-scale-input{background:var(--studio-input-bg);border:1px solid var(--studio-border-subtle);border-radius:4px;align-items:center;width:100%;min-height:32px;transition:border-color .15s;display:flex;overflow:hidden}.studio-scale-input:focus-within{border-color:var(--studio-accent)}.studio-scale-input select{min-width:0;color:var(--studio-text);cursor:pointer;-webkit-appearance:none;-moz-appearance:none;appearance:none;background:0 0;border:none;outline:none;flex:1;padding:6px 8px;font-family:SF Mono,Fira Code,Cascadia Code,monospace;font-size:11px}.studio-scale-input .studio-select,.studio-scrub-input .studio-select{min-width:0;min-height:unset;background:0 0;border:none;border-radius:0;flex:1;height:100%;padding:6px 8px;font-size:11px}.studio-scale-input .studio-select:hover,.studio-scrub-input .studio-select:hover{background:0 0;border:none}.studio-scale-input .studio-select[data-state=open],.studio-scrub-input .studio-select[data-state=open]{border:none}.studio-scale-input input{min-width:0;color:var(--studio-text);background:0 0;border:none;outline:none;flex:1;padding:6px 8px;font-family:SF Mono,Fira Code,Cascadia Code,monospace;font-size:11px}.studio-scale-input input::placeholder{color:var(--studio-text-dimmed)}.studio-scale-toggle{cursor:pointer;width:auto;min-width:26px;height:32px;color:var(--studio-text-dimmed);background:0 0;border:none;flex-shrink:0;justify-content:center;align-items:center;padding:0 4px;transition:color .1s,background .1s;display:flex}.studio-scale-toggle:hover{color:var(--studio-text);background:var(--studio-surface-hover)}.studio-scale-toggle.active{color:var(--studio-accent)}.studio-addable-row{cursor:pointer;background:#ffffff05;border-radius:4px;justify-content:space-between;align-items:center;padding:4px 8px;transition:background .1s;display:flex}.studio-addable-row:hover{background:var(--studio-surface-hover)}.studio-addable-row .label{color:var(--studio-text-dimmed);font-size:11px}.studio-addable-row .plus{width:18px;height:18px;color:var(--studio-text-dimmed);opacity:.4;border-radius:3px;justify-content:center;align-items:center;transition:opacity .1s,background .1s;display:flex}.studio-addable-row:hover .plus{opacity:1;background:var(--studio-surface-active)}.studio-radius-preview{border:2px solid var(--studio-text-dimmed);background:0 0;flex-shrink:0;width:22px;height:22px}.studio-gradient-grid{grid-template-columns:repeat(4,1fr);gap:6px;display:grid}.studio-gradient-swatch{border:1px solid var(--studio-border-subtle);cursor:pointer;border-radius:6px;align-items:flex-end;height:40px;padding:3px 5px;transition:box-shadow .15s,transform .1s;display:flex;position:relative;overflow:hidden}.studio-gradient-swatch:hover{box-shadow:0 0 0 1px var(--studio-accent);transform:scale(1.04)}.studio-gradient-label{color:#fff;text-shadow:0 1px 3px #00000080;align-items:center;gap:3px;font-size:8px;font-weight:600;display:flex}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-outline-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}@property --tw-ease{syntax:"*";inherits:false}