@hyperframes/studio 0.8.103 → 0.8.105

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 (200) hide show
  1. package/dist/assets/{hyperframes-player-DG795Hwu.js → hyperframes-player-tnfCiVdR.js} +1 -1
  2. package/dist/assets/{index-BiEtDkae.js → index-Ca6LZlVb.js} +1 -1
  3. package/dist/assets/index-Cre9X4RS.css +1 -0
  4. package/dist/assets/{index-BPJRf2X9.js → index-DEDhPmPD.js} +215 -215
  5. package/dist/assets/{index-DuCZ3pQw.js → index-zpe332hb.js} +1 -1
  6. package/dist/{chunk-62DDWOSH.js → chunk-EEXSYY5F.js} +19 -18
  7. package/dist/chunk-EEXSYY5F.js.map +1 -0
  8. package/dist/{chunk-6GAO75IU.js → chunk-NCUBAVGK.js} +10 -8
  9. package/dist/chunk-NCUBAVGK.js.map +1 -0
  10. package/dist/{chunk-HIGHVWYD.js → chunk-QADHJFDF.js} +2 -2
  11. package/dist/index.css +6 -1
  12. package/dist/index.css.map +1 -1
  13. package/dist/index.d.ts +181 -168
  14. package/dist/index.html +2 -2
  15. package/dist/index.js +1018 -919
  16. package/dist/index.js.map +1 -1
  17. package/dist/player.js +2 -2
  18. package/dist/styles/tailwind-preset.js.map +1 -1
  19. package/dist/styles.css +1 -1
  20. package/dist/ui.js +2 -2
  21. package/package.json +8 -8
  22. package/src/captions/components/CaptionAnimationPanel.tsx +2 -2
  23. package/src/captions/components/CaptionPropertyPanel.tsx +2 -2
  24. package/src/captions/components/CaptionTimeline.tsx +3 -3
  25. package/src/components/AskAgentModal.tsx +1 -1
  26. package/src/components/LintModal.tsx +35 -35
  27. package/src/components/StudioErrorBoundary.tsx +1 -1
  28. package/src/components/StudioHeader.dom.test.tsx +4 -4
  29. package/src/components/StudioHeader.tsx +2 -1
  30. package/src/components/StudioToast.tsx +7 -16
  31. package/src/components/TimelineToolPicker.tsx +1 -1
  32. package/src/components/TimelineToolbar.tsx +11 -11
  33. package/src/components/dock/Dock.tsx +1 -1
  34. package/src/components/dock/dock.css +9 -1
  35. package/src/components/editor/AnimationCard.tsx +5 -5
  36. package/src/components/editor/AnimationCardParts.tsx +1 -1
  37. package/src/components/editor/BlockParamsPanel.tsx +3 -3
  38. package/src/components/editor/BorderRadiusEditor.tsx +8 -15
  39. package/src/components/editor/CanvasContextMenu.tsx +1 -1
  40. package/src/components/editor/ComputedTweenNotice.tsx +1 -1
  41. package/src/components/editor/DomEditOverlay.tsx +5 -6
  42. package/src/components/editor/DomEditRotateHandle.tsx +1 -1
  43. package/src/components/editor/EaseCurveSection.tsx +14 -19
  44. package/src/components/editor/EaseModeControls.tsx +2 -2
  45. package/src/components/editor/EaseParamFields.tsx +8 -8
  46. package/src/components/editor/FileTree.tsx +1 -1
  47. package/src/components/editor/FileTreeIcons.tsx +47 -26
  48. package/src/components/editor/FileTreeNodes.tsx +11 -8
  49. package/src/components/editor/GestureRecordControl.tsx +3 -3
  50. package/src/components/editor/GsapAddAnimationControl.tsx +1 -1
  51. package/src/components/editor/GsapAnimationSection.tsx +2 -2
  52. package/src/components/editor/InlineTextToolbar.tsx +4 -4
  53. package/src/components/editor/InspectorHeaderActions.tsx +1 -1
  54. package/src/components/editor/KeyframeDiamond.tsx +6 -4
  55. package/src/components/editor/KeyframeNavigation.tsx +4 -4
  56. package/src/components/editor/LayersPanel.tsx +3 -3
  57. package/src/components/editor/PromotableControl.tsx +2 -2
  58. package/src/components/editor/PropertyPanel.tsx +3 -3
  59. package/src/components/editor/PropertyPanelEmptyState.tsx +4 -4
  60. package/src/components/editor/PropertyPanelFlatFooter.tsx +2 -2
  61. package/src/components/editor/PropertyPanelFlatHeader.test.tsx +1 -1
  62. package/src/components/editor/PropertyPanelFlatHeader.tsx +2 -2
  63. package/src/components/editor/SnapToolbar.tsx +5 -5
  64. package/src/components/editor/TimelineFxPopover.tsx +4 -4
  65. package/src/components/editor/Transform3DCube.tsx +1 -1
  66. package/src/components/editor/anchoredResizeCommitFeedsOffset.test.ts +46 -6
  67. package/src/components/editor/anchoredResizeReleaseShift.test.ts +0 -84
  68. package/src/components/editor/domEditOverlayGestures.ts +13 -19
  69. package/src/components/editor/domEditOverlayStartGesture.test.ts +170 -13
  70. package/src/components/editor/domEditOverlayStartGesture.ts +15 -25
  71. package/src/components/editor/easeCurveSvg.tsx +1 -1
  72. package/src/components/editor/manualEdits.test.ts +3 -9
  73. package/src/components/editor/manualEdits.ts +0 -1
  74. package/src/components/editor/manualEditsDom.ts +3 -13
  75. package/src/components/editor/manualEditsDomPatches.test.ts +3 -131
  76. package/src/components/editor/manualEditsDomPatches.ts +1 -53
  77. package/src/components/editor/manualEditsSnapshot.ts +3 -0
  78. package/src/components/editor/manualEditsTypes.ts +2 -0
  79. package/src/components/editor/manualOffsetDrag.test.ts +41 -0
  80. package/src/components/editor/manualOffsetDrag.ts +6 -27
  81. package/src/components/editor/persistSeam.integration.test.ts +0 -18
  82. package/src/components/editor/plainTranslate.ts +42 -6
  83. package/src/components/editor/propertyPanelColorCurveGraph.tsx +2 -2
  84. package/src/components/editor/propertyPanelColorGradingControls.tsx +1 -1
  85. package/src/components/editor/propertyPanelColorGradingSection.tsx +8 -8
  86. package/src/components/editor/propertyPanelColorGradingSlider.tsx +1 -1
  87. package/src/components/editor/propertyPanelColorSecondary.tsx +4 -4
  88. package/src/components/editor/propertyPanelFill.tsx +6 -6
  89. package/src/components/editor/propertyPanelFlatColorGradingAccessory.tsx +3 -3
  90. package/src/components/editor/propertyPanelFlatColorGradingSection.test.tsx +1 -1
  91. package/src/components/editor/propertyPanelFlatColorGradingSection.tsx +6 -9
  92. package/src/components/editor/propertyPanelFlatEffectsSection.tsx +4 -4
  93. package/src/components/editor/propertyPanelFlatMediaSection.tsx +2 -2
  94. package/src/components/editor/propertyPanelFlatMotionSection.tsx +2 -2
  95. package/src/components/editor/propertyPanelFlatOverlaysSection.tsx +2 -2
  96. package/src/components/editor/propertyPanelFlatPrimitives.test.tsx +4 -3
  97. package/src/components/editor/propertyPanelFlatPrimitives.tsx +1 -1
  98. package/src/components/editor/propertyPanelFlatSliderReadout.tsx +1 -1
  99. package/src/components/editor/propertyPanelFont.tsx +2 -2
  100. package/src/components/editor/propertyPanelFxCarveModule.tsx +1 -1
  101. package/src/components/editor/propertyPanelFxControls.tsx +2 -2
  102. package/src/components/editor/propertyPanelFxEqModule.tsx +2 -2
  103. package/src/components/editor/propertyPanelFxNodeRow.tsx +1 -1
  104. package/src/components/editor/propertyPanelFxPresetRun.tsx +1 -1
  105. package/src/components/editor/propertyPanelMediaSection.tsx +1 -1
  106. package/src/components/editor/propertyPanelPrimitives.tsx +1 -1
  107. package/src/components/editor/propertyPanelSections.tsx +2 -2
  108. package/src/components/editor/propertyPanelTransformCommit.test.ts +29 -0
  109. package/src/components/editor/propertyPanelTransformCommit.ts +8 -5
  110. package/src/components/editor/propertyPanelTypes.ts +1 -0
  111. package/src/components/editor/propertyPanelValueTier.test.ts +1 -1
  112. package/src/components/editor/propertyPanelValueTier.ts +1 -1
  113. package/src/components/editor/rotateInlineSave.test.ts +111 -0
  114. package/src/components/editor/rotationDraft.test.ts +111 -0
  115. package/src/components/editor/rotationDraft.ts +145 -0
  116. package/src/components/editor/useDomEditNudge.test.tsx +33 -0
  117. package/src/components/editor/useDomEditNudge.ts +6 -2
  118. package/src/components/editor/useDomEditOverlayGestures.ts +22 -24
  119. package/src/components/feedback/StudioFeedbackCard.tsx +11 -23
  120. package/src/components/nle/AssetPreviewOverlay.tsx +1 -1
  121. package/src/components/nle/AudioMeterStrip.tsx +2 -2
  122. package/src/components/nle/NLEPreview.test.ts +8 -4
  123. package/src/components/nle/PreviewOverlays.tsx +1 -1
  124. package/src/components/nle/PreviewPane.tsx +3 -3
  125. package/src/components/nle/PreviewPoster.tsx +29 -1
  126. package/src/components/nle/PreviewZoomOverlay.tsx +1 -1
  127. package/src/components/panels/SlideshowPanel.tsx +4 -4
  128. package/src/components/panels/SlideshowSubPanels.tsx +19 -21
  129. package/src/components/panels/VariablesBindElement.tsx +1 -1
  130. package/src/components/panels/VariablesDeclarationForm.tsx +1 -1
  131. package/src/components/panels/VariablesPanel.tsx +4 -6
  132. package/src/components/panels/VariablesRowAction.tsx +1 -1
  133. package/src/components/renders/FfmpegRequiredNotice.tsx +4 -4
  134. package/src/components/renders/RenderQueue.tsx +2 -2
  135. package/src/components/renders/RenderQueueItem.tsx +3 -3
  136. package/src/components/sidebar/AssetCard.tsx +3 -3
  137. package/src/components/sidebar/AssetContextMenu.tsx +7 -7
  138. package/src/components/sidebar/AssetsTab.tsx +6 -6
  139. package/src/components/sidebar/AudioRow.tsx +5 -3
  140. package/src/components/sidebar/BlocksTab.tsx +6 -6
  141. package/src/components/sidebar/CompositionsTab.drag.test.tsx +3 -69
  142. package/src/components/sidebar/CompositionsTab.rootBadge.test.tsx +4 -50
  143. package/src/components/sidebar/CompositionsTab.thumbnails.test.tsx +256 -0
  144. package/src/components/sidebar/CompositionsTab.tsx +65 -12
  145. package/src/components/sidebar/PromptPreviewModal.tsx +3 -3
  146. package/src/components/sidebar/SidebarLintButton.tsx +3 -3
  147. package/src/components/sidebar/compositionsTabTestUtils.tsx +39 -0
  148. package/src/components/timelineToolbarStyles.ts +3 -3
  149. package/src/components/ui/Button.tsx +4 -4
  150. package/src/components/ui/HyperframesLogo.tsx +19 -18
  151. package/src/components/ui/Input.tsx +1 -1
  152. package/src/components/ui/Menu.tsx +4 -2
  153. package/src/hooks/draggedGsapPosition.ts +28 -0
  154. package/src/hooks/elementOffsetStager.ts +34 -13
  155. package/src/hooks/gsapRuntimeBridge.ts +5 -3
  156. package/src/hooks/gsapRuntimeKeyframes.ts +36 -2
  157. package/src/hooks/plainRotation.test.ts +122 -0
  158. package/src/hooks/plainRotation.ts +42 -0
  159. package/src/hooks/useClipboard.source.test.ts +42 -4
  160. package/src/hooks/useClipboard.ts +13 -3
  161. package/src/hooks/useDomEditCommits.ts +0 -3
  162. package/src/hooks/useDomEditSession.ts +5 -5
  163. package/src/hooks/useDomGeometryCommit.test.tsx +79 -1
  164. package/src/hooks/useDomGeometryCommit.ts +16 -17
  165. package/src/hooks/useDomGeometryCommits.test.tsx +233 -33
  166. package/src/hooks/useDomGeometryCommits.ts +27 -80
  167. package/src/hooks/useGsapAwareEditing.test.tsx +194 -11
  168. package/src/hooks/useGsapAwareEditing.ts +43 -42
  169. package/src/hooks/useInlineTextEdit.test.tsx +33 -3
  170. package/src/hooks/useInlineTextEdit.ts +2 -2
  171. package/src/player/components/ClipContextMenu.tsx +1 -1
  172. package/src/player/components/CompositionThumbnail.tsx +23 -11
  173. package/src/player/components/EditModal.tsx +6 -6
  174. package/src/player/components/KeyframeDiamondContextMenu.tsx +2 -2
  175. package/src/player/components/PlayerControls.tsx +3 -3
  176. package/src/player/components/ShortcutsPanel.tsx +8 -20
  177. package/src/player/components/TimelineCanvas.tsx +1 -1
  178. package/src/player/components/TimelineClip.tsx +2 -2
  179. package/src/player/components/TimelineEmptyState.tsx +2 -2
  180. package/src/player/components/TimelineLanes.tsx +0 -1
  181. package/src/player/components/TrackClipCount.tsx +1 -1
  182. package/src/player/components/VolumeControl.tsx +1 -1
  183. package/src/player/components/timelineClipChildren.tsx +1 -1
  184. package/src/player/components/timelineMotionStyles.test.ts +6 -22
  185. package/src/player/components/trackHeaderLabelRows.tsx +16 -16
  186. package/src/player/lib/thumbnailScheduler.ts +4 -5
  187. package/src/player/lib/timelineViewportBudgets.test.ts +1 -1
  188. package/src/player/lib/timelineViewportBudgets.ts +1 -1
  189. package/src/styles/hex-baseline.json +7 -19
  190. package/src/styles/studio.css +0 -9
  191. package/src/styles/tailwind-preset.shared.js +2 -1
  192. package/src/styles/theme.css +204 -147
  193. package/src/styles/theme.test.ts +13 -9
  194. package/src/utils/blockCategories.ts +41 -9
  195. package/src/utils/clipboardPayload.ts +2 -0
  196. package/dist/assets/index-CQN3M56N.css +0 -1
  197. package/dist/chunk-62DDWOSH.js.map +0 -1
  198. package/dist/chunk-6GAO75IU.js.map +0 -1
  199. package/src/hooks/gsapTargetCache.ts +0 -62
  200. /package/dist/{chunk-HIGHVWYD.js.map → chunk-QADHJFDF.js.map} +0 -0
@@ -42,7 +42,6 @@ const VMIN = -HR / S; // bottom of visible view (undershoot headroom)
42
42
  // of snapping to the view edge; the handle DOT is still clampView'd into view.
43
43
  const DRAG_VMAX = 2;
44
44
  const DRAG_VMIN = -1;
45
- const ACCENT = "#3CE6AC";
46
45
 
47
46
  // Figma-style ease-type dropdown: the current ease (glyph + name) as a button
48
47
  // that opens the preset grid in a popover. This is where a preset is selected —
@@ -130,7 +129,7 @@ function EaseTypeDropdown({
130
129
  aria-expanded={open}
131
130
  aria-controls={open ? menuId : undefined}
132
131
  onClick={() => setOpen((prev) => !prev)}
133
- className="flex w-full items-center gap-2 rounded-md border border-white/10 bg-black/20 px-2 py-1.5 text-left transition-colors hover:border-white/20"
132
+ className="flex w-full items-center gap-2 rounded-md border border-border bg-input px-2 py-1.5 text-left transition-colors hover:border-border-strong"
134
133
  >
135
134
  <MiniCurveSvg ease={ease} active size={16} />
136
135
  <span className="text-[11px] text-neutral-200">{label}</span>
@@ -151,7 +150,7 @@ function EaseTypeDropdown({
151
150
  role="menu"
152
151
  aria-label={`${MODE_LABELS[kind]} ease presets`}
153
152
  onKeyDown={handleMenuKeyDown}
154
- className="absolute inset-x-0 top-full z-20 mt-1 rounded-md border border-white/10 bg-neutral-900 p-2 shadow-xl"
153
+ className="absolute inset-x-0 top-full z-20 mt-1 rounded-md border border-border bg-raised p-2 shadow-xl"
155
154
  >
156
155
  <EasePresetGrid
157
156
  kind={kind}
@@ -407,7 +406,7 @@ export function EaseCurveSection({
407
406
  {showGraph ? (
408
407
  <>
409
408
  <div
410
- className="mx-auto overflow-hidden rounded-md border border-white/5 bg-black/20"
409
+ className="mx-auto overflow-hidden rounded-md border border-border bg-input"
411
410
  style={{ aspectRatio: `${SVGW} / ${SVGH}`, width: "100%", maxWidth: 230 }}
412
411
  >
413
412
  <svg
@@ -429,7 +428,7 @@ export function EaseCurveSection({
429
428
  y1={top}
430
429
  x2={xToSvg(q)}
431
430
  y2={bottom}
432
- stroke="white"
431
+ className="stroke-text-0"
433
432
  strokeOpacity="0.05"
434
433
  strokeWidth="1"
435
434
  />
@@ -441,7 +440,7 @@ export function EaseCurveSection({
441
440
  y1={yToSvg(q)}
442
441
  x2={right}
443
442
  y2={yToSvg(q)}
444
- stroke="white"
443
+ className="stroke-text-0"
445
444
  strokeOpacity="0.05"
446
445
  strokeWidth="1"
447
446
  />
@@ -453,7 +452,7 @@ export function EaseCurveSection({
453
452
  width={S}
454
453
  height={bottom - top}
455
454
  fill="none"
456
- stroke="white"
455
+ className="stroke-text-0"
457
456
  strokeOpacity="0.1"
458
457
  strokeWidth="1"
459
458
  />
@@ -463,7 +462,7 @@ export function EaseCurveSection({
463
462
  y1={a0.y}
464
463
  x2={a1.x}
465
464
  y2={a1.y}
466
- stroke="white"
465
+ className="stroke-text-0"
467
466
  strokeOpacity="0.08"
468
467
  strokeWidth="1"
469
468
  strokeDasharray="3 4"
@@ -476,8 +475,7 @@ export function EaseCurveSection({
476
475
  y1={a0.y}
477
476
  x2={p1.x}
478
477
  y2={p1.y}
479
- stroke={ACCENT}
480
- strokeOpacity="0.5"
478
+ className="stroke-accent-ink"
481
479
  strokeWidth="1.5"
482
480
  />
483
481
  <line
@@ -485,8 +483,7 @@ export function EaseCurveSection({
485
483
  y1={a1.y}
486
484
  x2={p2.x}
487
485
  y2={p2.y}
488
- stroke={ACCENT}
489
- strokeOpacity="0.5"
486
+ className="stroke-accent-ink"
490
487
  strokeWidth="1.5"
491
488
  />
492
489
  </>
@@ -495,13 +492,13 @@ export function EaseCurveSection({
495
492
  <path
496
493
  d={curvePath}
497
494
  fill="none"
498
- stroke={ACCENT}
495
+ className="stroke-accent-ink"
499
496
  strokeWidth="2.5"
500
497
  strokeLinecap="round"
501
498
  />
502
499
  {/* Anchors at (0,0) and (1,1) */}
503
- <circle cx={a0.x} cy={a0.y} r="3" fill={ACCENT} />
504
- <circle cx={a1.x} cy={a1.y} r="3" fill={ACCENT} />
500
+ <circle cx={a0.x} cy={a0.y} r="3" className="fill-accent-ink" />
501
+ <circle cx={a1.x} cy={a1.y} r="3" className="fill-accent-ink" />
505
502
  {/* Draggable control handles (large transparent hit area + visible dot) */}
506
503
  {showHandles &&
507
504
  [["p1", p1] as const, ["p2", p2] as const].map(([key, pt]) => (
@@ -518,7 +515,7 @@ export function EaseCurveSection({
518
515
  aria-valuemax={1}
519
516
  aria-valuenow={key === "p1" ? x1 : x2}
520
517
  aria-valuetext={`x ${key === "p1" ? x1 : x2}, y ${key === "p1" ? y1 : y2}`}
521
- className="cursor-grab stroke-transparent outline-hidden active:cursor-grabbing focus-visible:stroke-white focus-visible:stroke-[2px]"
518
+ className="cursor-grab stroke-transparent outline-hidden active:cursor-grabbing focus-visible:stroke-text-0 focus-visible:stroke-[2px]"
522
519
  onPointerDown={(e) => handlePointerDown(key, e)}
523
520
  onKeyDown={(event) => handleKeyDown(key, event)}
524
521
  onPointerEnter={() => setHover(key)}
@@ -528,10 +525,8 @@ export function EaseCurveSection({
528
525
  cx={pt.x}
529
526
  cy={pt.y}
530
527
  r={hover === key || draggingRef.current === key ? 7 : 5.5}
531
- fill="#0a0a1a"
532
- stroke={ACCENT}
533
528
  strokeWidth="2.5"
534
- className="pointer-events-none transition-[r]"
529
+ className="pointer-events-none fill-input stroke-accent-ink transition-[r]"
535
530
  />
536
531
  </g>
537
532
  ))}
@@ -59,7 +59,7 @@ export const EasePresetGrid = function EasePresetGrid({
59
59
  <MiniCurveSvg ease={preset.ease} active={isActive} />
60
60
  <span
61
61
  className={`text-center text-[8px] leading-none ${
62
- isActive ? "text-panel-accent" : "text-neutral-500"
62
+ isActive ? "text-accent-ink" : "text-neutral-500"
63
63
  }`}
64
64
  >
65
65
  {preset.label}
@@ -80,7 +80,7 @@ export function EaseModeToggle({
80
80
  }) {
81
81
  return (
82
82
  <div
83
- className="mb-2 grid grid-cols-3 rounded-md bg-black/20 p-0.5"
83
+ className="mb-2 grid grid-cols-3 rounded-md bg-press p-0.5"
84
84
  role="radiogroup"
85
85
  aria-label="Ease editor mode"
86
86
  >
@@ -93,17 +93,17 @@ export function EaseBezierField({
93
93
  }
94
94
  }}
95
95
  onBlur={(event) => commit(event.currentTarget.value)}
96
- className={`w-full rounded border bg-black/20 px-1.5 py-1 font-mono text-[10px] text-neutral-300 outline-hidden ${
96
+ className={`w-full rounded border bg-input px-1.5 py-1 font-mono text-[10px] text-neutral-300 outline-hidden ${
97
97
  error
98
- ? "border-red-500/70 focus:border-red-400"
99
- : "border-white/10 focus:border-panel-accent/50"
98
+ ? "border-danger-ink/70 focus:border-danger-ink"
99
+ : "border-border focus:border-panel-accent/50"
100
100
  }`}
101
101
  />
102
102
  </div>
103
103
  <p
104
104
  id={errorId}
105
105
  aria-live="polite"
106
- className={`mt-1 text-[9px] text-red-400 ${error ? "" : "sr-only"}`}
106
+ className={`mt-1 text-[9px] text-danger-ink ${error ? "" : "sr-only"}`}
107
107
  >
108
108
  {error ?? "Valid bezier values"}
109
109
  </p>
@@ -183,7 +183,7 @@ export function SpringBounceField({
183
183
  const bounce = parseSpringBounce(`spring(${value})`);
184
184
  if (bounce !== null) onCommit(`spring(${round2(bounce)})`);
185
185
  }}
186
- className="w-16 rounded-sm border border-white/10 bg-black/20 px-1.5 py-1 font-mono text-[10px] text-neutral-300 outline-hidden focus:border-panel-accent/50"
186
+ className="w-16 rounded-sm border border-border bg-input px-1.5 py-1 font-mono text-[10px] text-neutral-300 outline-hidden focus:border-panel-accent/50"
187
187
  />
188
188
  </div>
189
189
  );
@@ -207,7 +207,7 @@ export function WiggleField({
207
207
  min={1}
208
208
  step={1}
209
209
  onCommit={(value) => commitWiggle(onCommit, value, config.type, amplitude)}
210
- className="w-14 rounded-sm border border-white/10 bg-black/20 px-1.5 py-1 font-mono text-[10px] text-neutral-300 outline-hidden focus:border-panel-accent/50"
210
+ className="w-14 rounded-sm border border-border bg-input px-1.5 py-1 font-mono text-[10px] text-neutral-300 outline-hidden focus:border-panel-accent/50"
211
211
  />
212
212
  </div>
213
213
  <div className="flex items-center gap-1">
@@ -220,7 +220,7 @@ export function WiggleField({
220
220
  commitWiggle(onCommit, config.wiggles, event.currentTarget.value, amplitude);
221
221
  }
222
222
  }}
223
- className="rounded-sm border border-white/10 bg-black/20 px-1.5 py-1 text-[10px] text-neutral-300 outline-hidden focus:border-panel-accent/50"
223
+ className="rounded-sm border border-border bg-input px-1.5 py-1 text-[10px] text-neutral-300 outline-hidden focus:border-panel-accent/50"
224
224
  >
225
225
  {WIGGLE_TYPES.map((type) => (
226
226
  <option key={type} value={type}>
@@ -238,7 +238,7 @@ export function WiggleField({
238
238
  max={1}
239
239
  step={0.01}
240
240
  onCommit={(value) => commitWiggle(onCommit, config.wiggles, config.type, value)}
241
- className="w-16 rounded-sm border border-white/10 bg-black/20 px-1.5 py-1 font-mono text-[10px] text-neutral-300 outline-hidden focus:border-panel-accent/50"
241
+ className="w-16 rounded-sm border border-border bg-input px-1.5 py-1 font-mono text-[10px] text-neutral-300 outline-hidden focus:border-panel-accent/50"
242
242
  />
243
243
  </div>
244
244
  </div>
@@ -263,7 +263,7 @@ export const FileTree = memo(function FileTree({
263
263
  <div
264
264
  className={`flex-1 overflow-y-auto py-1 transition-colors ${
265
265
  dragOverFolder === ""
266
- ? "bg-[#3CE6AC]/5 outline-solid outline-1 outline-[#3CE6AC]/30 -outline-offset-1"
266
+ ? "bg-accent/5 outline-solid outline-1 outline-accent-ink -outline-offset-1"
267
267
  : ""
268
268
  }`}
269
269
  onContextMenu={handleRootContextMenu}
@@ -21,34 +21,55 @@ import {
21
21
  const SZ = 14;
22
22
  const W = "duotone" as const;
23
23
 
24
+ type Icon = typeof File;
25
+ // Brand hues; each light half is darkened to hold 3:1 on a hovered or selected row.
26
+ const RED = "text-[light-dark(oklch(0.59_0.194_35),oklch(0.71_0.194_35))]";
27
+ const BLUE = "text-[light-dark(oklch(0.56_0.14_253),oklch(0.69_0.14_253))]";
28
+ const GREEN = "text-[light-dark(oklch(0.53_0.192_150),#22C55E)]";
29
+ const GRAY = "text-[light-dark(oklch(0.56_0.019_261),#9CA3AF)]";
30
+ export const DIM = "text-[light-dark(oklch(0.55_0.023_264),oklch(0.69_0.023_264))]";
31
+ const ICONS = new Map<string, [Icon, string]>([
32
+ ["html", [FileHtml, RED]],
33
+ ["css", [FileCss, "text-[light-dark(oklch(0.5_0.2_266),oklch(0.71_0.2_266))]"]],
34
+ ["js", [FileJs, "text-[light-dark(oklch(0.56_0.156_101),#F0DB4F)]"]],
35
+ ["jsx", [FileJsx, "text-[light-dark(oklch(0.55_0.117_219),#61DAFB)]"]],
36
+ ["ts", [FileTs, BLUE]],
37
+ ["tsx", [FileTsx, BLUE]],
38
+ ["json", [FileCode, "text-[light-dark(oklch(0.54_0.182_152),#4ADE80)]"]],
39
+ ["svg", [FileSvg, "text-[light-dark(oklch(0.58_0.187_48),#F97316)]"]],
40
+ ["md", [FileMd, GRAY]],
41
+ ["txt", [FileTxt, GRAY]],
42
+ ["png", [FilePng, GREEN]],
43
+ ["jpg", [FileJpg, GREEN]],
44
+ ["webp", [PhImage, GREEN]],
45
+ ["mp4", [FileVideo, "text-[light-dark(oklch(0.59_0.2_304),oklch(0.71_0.2_304))]"]],
46
+ ["mp3", [Waveform, "text-[light-dark(oklch(0.53_0.159_165),#3CE6AC)]"]],
47
+ ["woff", [TextAa, DIM]],
48
+ ]);
49
+ const ALIAS = new Map(
50
+ Object.entries({
51
+ mjs: "js",
52
+ cjs: "js",
53
+ mts: "ts",
54
+ mdx: "md",
55
+ jpeg: "jpg",
56
+ gif: "webp",
57
+ ico: "webp",
58
+ webm: "mp4",
59
+ mov: "mp4",
60
+ wav: "mp3",
61
+ ogg: "mp3",
62
+ m4a: "mp3",
63
+ woff2: "woff",
64
+ ttf: "woff",
65
+ otf: "woff",
66
+ }),
67
+ );
68
+
24
69
  export function FileIcon({ path }: { path: string }) {
25
70
  const ext = path.split(".").pop()?.toLowerCase() ?? "";
26
- const c = "shrink-0";
27
- if (ext === "html") return <FileHtml size={SZ} weight={W} color="#E44D26" className={c} />;
28
- if (ext === "css") return <FileCss size={SZ} weight={W} color="#264DE4" className={c} />;
29
- if (ext === "js" || ext === "mjs" || ext === "cjs")
30
- return <FileJs size={SZ} weight={W} color="#F0DB4F" className={c} />;
31
- if (ext === "jsx") return <FileJsx size={SZ} weight={W} color="#61DAFB" className={c} />;
32
- if (ext === "ts" || ext === "mts")
33
- return <FileTs size={SZ} weight={W} color="#3178C6" className={c} />;
34
- if (ext === "tsx") return <FileTsx size={SZ} weight={W} color="#3178C6" className={c} />;
35
- if (ext === "json") return <FileCode size={SZ} weight={W} color="#4ADE80" className={c} />;
36
- if (ext === "svg") return <FileSvg size={SZ} weight={W} color="#F97316" className={c} />;
37
- if (ext === "md" || ext === "mdx")
38
- return <FileMd size={SZ} weight={W} color="#9CA3AF" className={c} />;
39
- if (ext === "txt") return <FileTxt size={SZ} weight={W} color="#9CA3AF" className={c} />;
40
- if (ext === "png") return <FilePng size={SZ} weight={W} color="#22C55E" className={c} />;
41
- if (ext === "jpg" || ext === "jpeg")
42
- return <FileJpg size={SZ} weight={W} color="#22C55E" className={c} />;
43
- if (ext === "webp" || ext === "gif" || ext === "ico")
44
- return <PhImage size={SZ} weight={W} color="#22C55E" className={c} />;
45
- if (ext === "mp4" || ext === "webm" || ext === "mov")
46
- return <FileVideo size={SZ} weight={W} color="#A855F7" className={c} />;
47
- if (ext === "mp3" || ext === "wav" || ext === "ogg" || ext === "m4a")
48
- return <Waveform size={SZ} weight={W} color="#3CE6AC" className={c} />;
49
- if (ext === "woff" || ext === "woff2" || ext === "ttf" || ext === "otf")
50
- return <TextAa size={SZ} weight={W} color="#6B7280" className={c} />;
51
- return <File size={SZ} weight={W} color="#6B7280" className={c} />;
71
+ const [Glyph, color] = ICONS.get(ALIAS.get(ext) ?? ext) ?? [File, DIM];
72
+ return <Glyph size={SZ} weight={W} className={`shrink-0 ${color}`} />;
52
73
  }
53
74
 
54
75
  // ── Tree Types ──
@@ -16,6 +16,7 @@ import {
16
16
  type TreeNode,
17
17
  type ContextMenuState,
18
18
  type InlineInputState,
19
+ DIM,
19
20
  } from "./FileTreeIcons";
20
21
 
21
22
  export type { ContextMenuState, InlineInputState };
@@ -173,7 +174,7 @@ export function ContextMenu({
173
174
  <div className="border-t border-neutral-700 my-1" />
174
175
  <button
175
176
  role="menuitem"
176
- className="w-full flex items-center gap-2 px-3 py-1.5 text-xs text-red-400 hover:bg-red-900/30 focus-visible:bg-red-900/30 active:bg-red-900/50 outline-hidden cursor-pointer text-left"
177
+ className="w-full flex items-center gap-2 px-3 py-1.5 text-xs text-danger-ink hover:bg-danger/25 focus-visible:bg-danger/25 active:bg-danger/25 outline-hidden cursor-pointer text-left"
177
178
  onClick={() => {
178
179
  onDelete(state.targetPath);
179
180
  onClose();
@@ -263,7 +264,7 @@ export function InlineInput({
263
264
  style={{ paddingLeft: `${8 + depth * 12 + (isFolder ? 0 : 14)}px` }}
264
265
  >
265
266
  {isFolder ? (
266
- <FolderSimple size={SZ_ICON} weight="duotone" color="#6B7280" className="shrink-0" />
267
+ <FolderSimple size={SZ_ICON} weight="duotone" className={`shrink-0 ${DIM}`} />
267
268
  ) : (
268
269
  <FileIcon path={value} />
269
270
  )}
@@ -279,12 +280,12 @@ export function InlineInput({
279
280
  onBlur={handleBlur}
280
281
  aria-invalid={error ? true : undefined}
281
282
  className={`w-full min-w-0 bg-neutral-800 text-neutral-200 text-xs px-1.5 py-0.5 rounded border outline-hidden ${
282
- error ? "border-red-500/70" : "border-neutral-600 focus:border-[#3CE6AC]"
283
+ error ? "border-danger-ink" : "border-neutral-600 focus:border-accent-ink"
283
284
  }`}
284
285
  spellCheck={false}
285
286
  />
286
287
  {error && (
287
- <div className="mt-0.5 text-[10px] text-red-400" role="alert">
288
+ <div className="mt-0.5 text-[10px] text-danger-ink" role="alert">
288
289
  {error}
289
290
  </div>
290
291
  )}
@@ -344,13 +345,13 @@ export function DeleteConfirm({
344
345
  <div className="flex gap-1.5">
345
346
  <button
346
347
  onClick={onCancel}
347
- className="flex-1 px-2 py-1 rounded-sm bg-neutral-700 text-neutral-300 hover:bg-neutral-600 transition-colors"
348
+ className="flex-1 px-2 py-1 rounded-sm bg-hover text-neutral-300 hover:bg-press transition-colors"
348
349
  >
349
350
  Cancel
350
351
  </button>
351
352
  <button
352
353
  onClick={onConfirm}
353
- className="flex-1 px-2 py-1 rounded-sm bg-red-900/60 text-red-300 hover:bg-red-800/60 transition-colors"
354
+ className="flex-1 px-2 py-1 rounded-sm bg-danger/15 text-danger-ink hover:bg-danger/25 transition-colors"
354
355
  >
355
356
  Delete
356
357
  </button>
@@ -419,7 +420,7 @@ export const TreeFile = memo(function TreeFile({
419
420
  <span className="truncate flex-1">{node.name}</span>
420
421
  {lintInfo && lintInfo.count > 0 && (
421
422
  <span
422
- className="shrink-0 min-w-[16px] rounded-full bg-amber-500/20 px-1 text-[8px] font-bold text-amber-400 text-center mr-1"
423
+ className="shrink-0 min-w-[16px] rounded-full bg-amber-500/20 px-1 text-[8px] font-bold text-warning-ink text-center mr-1"
423
424
  title={lintInfo.messages.join("\n")}
424
425
  >
425
426
  {lintInfo.count}
@@ -505,7 +506,9 @@ export const TreeFolder = memo(function TreeFolder({
505
506
  }}
506
507
  onDragLeave={onDragLeave}
507
508
  className={`w-full flex items-center gap-1.5 px-2.5 py-1 min-h-7 text-left text-xs text-neutral-400 hover:bg-neutral-800/30 hover:text-neutral-300 transition-colors ${
508
- isDragOver ? "bg-[#3CE6AC]/10 outline-solid outline-1 outline-[#3CE6AC]/40" : ""
509
+ isDragOver
510
+ ? "bg-accent/10 outline-solid outline-1 outline-accent-ink -outline-offset-1"
511
+ : ""
509
512
  }`}
510
513
  style={{ paddingLeft: `${8 + depth * 12}px` }}
511
514
  >
@@ -43,7 +43,7 @@ export function GestureRecordPanelButton({
43
43
  }}
44
44
  className={`w-full flex items-center justify-center gap-2 rounded-lg py-2 text-[11px] font-medium transition-colors ${
45
45
  recording
46
- ? "bg-red-500/15 text-red-400 border border-red-500/30 animate-pulse"
46
+ ? "bg-red-500/15 text-danger-ink border border-red-500/30 animate-pulse"
47
47
  : "bg-panel-input text-panel-text-2 hover:bg-panel-hover border border-panel-border"
48
48
  }`}
49
49
  >
@@ -77,8 +77,8 @@ export function GestureRecordBadge({
77
77
  title={label}
78
78
  className={`pointer-events-auto absolute z-20 flex h-7 w-7 items-center justify-center rounded-full border shadow-lg transition-colors ${
79
79
  recording
80
- ? "border-red-400/60 bg-red-500 text-white animate-pulse"
81
- : "border-studio-accent/60 bg-neutral-950 text-studio-accent hover:bg-neutral-900"
80
+ ? "border-danger/60 bg-danger text-on-danger animate-pulse"
81
+ : "border-studio-accent/60 bg-neutral-950 text-accent-ink hover:bg-neutral-900"
82
82
  }`}
83
83
  style={{
84
84
  left: Math.max(0, rect.left + rect.width + 8),
@@ -3,7 +3,7 @@ import { ADD_METHODS, ADD_METHOD_LABELS, METHOD_TOOLTIPS } from "./gsapAnimation
3
3
  const STYLES = {
4
4
  classic: {
5
5
  method:
6
- "rounded-lg border border-neutral-700 bg-neutral-900 px-2.5 py-1.5 text-[11px] font-medium text-neutral-300 transition-colors hover:border-neutral-600 hover:text-white",
6
+ "rounded-lg border border-neutral-700 bg-neutral-900 px-2.5 py-1.5 text-[11px] font-medium text-neutral-300 transition-colors hover:border-neutral-600 hover:text-text-0",
7
7
  cancel: "px-1.5 text-[11px] text-neutral-500 hover:text-neutral-300",
8
8
  trigger: "text-[11px] font-medium text-neutral-400 transition-colors hover:text-neutral-200",
9
9
  },
@@ -24,13 +24,13 @@ export const GsapAnimationSection = memo(function GsapAnimationSection({
24
24
  return (
25
25
  <Section title="Animation" icon={<Film size={15} />}>
26
26
  {multipleTimelines && (
27
- <p className="mb-2 rounded-lg bg-amber-500/10 px-3 py-2 text-[11px] leading-relaxed text-amber-400">
27
+ <p className="mb-2 rounded-lg bg-amber-500/10 px-3 py-2 text-[11px] leading-relaxed text-warning-ink">
28
28
  This file has multiple GSAP timelines. Animation editing is disabled to prevent data loss
29
29
  — consolidate into a single timeline to enable editing.
30
30
  </p>
31
31
  )}
32
32
  {unsupportedTimelinePattern && (
33
- <p className="mb-2 rounded-lg bg-amber-500/10 px-3 py-2 text-[11px] leading-relaxed text-amber-400">
33
+ <p className="mb-2 rounded-lg bg-amber-500/10 px-3 py-2 text-[11px] leading-relaxed text-warning-ink">
34
34
  This timeline uses a computed key (window.__timelines[variable]) the editor can&apos;t
35
35
  resolve statically. Use a string-literal key (window.__timelines[&quot;id&quot;]) or a
36
36
  variable declaration (const tl = gsap.timeline()) to enable editing.
@@ -77,7 +77,7 @@ export function InlineTextToolbar({
77
77
  data-inline-text-toolbar="true"
78
78
  role="toolbar"
79
79
  aria-label="Text formatting"
80
- className="pointer-events-auto fixed z-200 flex items-center gap-1 rounded-lg border border-white/10 bg-[#15171c] p-1 shadow-[0_8px_24px_rgba(0,0,0,0.55)]"
80
+ className="pointer-events-auto fixed z-200 flex items-center gap-1 rounded-lg border border-border bg-raised p-1 shadow-[0_8px_24px_rgba(0,0,0,0.55)]"
81
81
  style={{
82
82
  left: placement.left,
83
83
  top: placement.top,
@@ -98,12 +98,12 @@ export function InlineTextToolbar({
98
98
  onClick={(event) => event.stopPropagation()}
99
99
  >
100
100
  <label
101
- className="group relative flex h-6 w-6 cursor-pointer items-center justify-center rounded-md hover:bg-white/10"
101
+ className="group relative flex h-6 w-6 cursor-pointer items-center justify-center rounded-md hover:bg-hover"
102
102
  title="Text colour"
103
103
  >
104
104
  <span
105
105
  aria-hidden="true"
106
- className="h-4 w-4 rounded-full border-2 border-white/25 transition-transform duration-150 group-hover:scale-110 group-active:scale-95"
106
+ className="h-4 w-4 rounded-full border-2 border-border-strong transition-transform duration-150 group-hover:scale-110 group-active:scale-95"
107
107
  // `background` maps a gradient to the PADDING box and then repeats it
108
108
  // to fill the border box, so the 1px border shows the strip either
109
109
  // side of the tile: the end colour on the left, the start colour on
@@ -202,7 +202,7 @@ function ToolbarToggle({
202
202
  aria-label={label}
203
203
  aria-pressed={on}
204
204
  className={`flex h-6 w-6 items-center justify-center rounded-md text-xs ${
205
- on ? "bg-studio-accent/20 text-studio-accent" : "text-white/70 hover:bg-white/10"
205
+ on ? "bg-studio-accent/20 text-accent-ink" : "text-text-2 hover:bg-hover"
206
206
  }`}
207
207
  style={{
208
208
  fontWeight: bold ? 700 : 400,
@@ -67,7 +67,7 @@ export function InspectorHeaderActions({
67
67
  }}
68
68
  className={`flex h-6 w-6 items-center justify-center rounded transition-colors ${
69
69
  copied
70
- ? "text-studio-accent"
70
+ ? "text-accent-ink"
71
71
  : "text-neutral-500 hover:bg-neutral-800 hover:text-neutral-300"
72
72
  }`}
73
73
  title={copied ? "Copied!" : "Copy element info to clipboard"}
@@ -19,8 +19,11 @@ export const KeyframeDiamond = memo(function KeyframeDiamond({
19
19
  isHold = false,
20
20
  }: KeyframeDiamondProps) {
21
21
  const isFilled = state === "active";
22
- const opacity = state === "ghost" ? 0.25 : state === "inactive" ? 0.6 : 1;
23
- const color = state === "active" ? "#3CE6AC" : "#a3a3a3";
22
+ const color = {
23
+ active: "text-accent",
24
+ inactive: "text-text-2 hover:text-text-0",
25
+ ghost: "text-text-off hover:text-text-0",
26
+ }[state];
24
27
 
25
28
  return (
26
29
  <button
@@ -29,8 +32,7 @@ export const KeyframeDiamond = memo(function KeyframeDiamond({
29
32
  e.stopPropagation();
30
33
  onClick();
31
34
  }}
32
- className="relative shrink-0 p-0.5 transition-opacity hover:opacity-100 before:absolute before:-inset-1.5 before:content-['']"
33
- style={{ color, opacity }}
35
+ className={`relative shrink-0 p-0.5 transition-colors before:absolute before:-inset-1.5 before:content-[''] ${color}`}
34
36
  title={title}
35
37
  aria-label={title}
36
38
  aria-pressed={state === "active"}
@@ -82,11 +82,11 @@ function ArrowLeft({ disabled }: { disabled: boolean }) {
82
82
  height="10"
83
83
  viewBox="0 0 6 10"
84
84
  fill="none"
85
- style={{ opacity: disabled ? 0.25 : 1 }}
85
+ className={disabled ? "text-text-off" : "text-text-2"}
86
86
  >
87
87
  <path
88
88
  d="M5 1L1 5L5 9"
89
- stroke="#a3a3a3"
89
+ stroke="currentColor"
90
90
  strokeWidth="1.4"
91
91
  strokeLinecap="round"
92
92
  strokeLinejoin="round"
@@ -102,11 +102,11 @@ function ArrowRight({ disabled }: { disabled: boolean }) {
102
102
  height="10"
103
103
  viewBox="0 0 6 10"
104
104
  fill="none"
105
- style={{ opacity: disabled ? 0.25 : 1 }}
105
+ className={disabled ? "text-text-off" : "text-text-2"}
106
106
  >
107
107
  <path
108
108
  d="M1 1L5 5L1 9"
109
- stroke="#a3a3a3"
109
+ stroke="currentColor"
110
110
  strokeWidth="1.4"
111
111
  strokeLinecap="round"
112
112
  strokeLinejoin="round"
@@ -458,7 +458,7 @@ export const LayersPanel = memo(function LayersPanel() {
458
458
  isDragged
459
459
  ? "opacity-40"
460
460
  : selected
461
- ? "bg-panel-accent/14 text-panel-accent"
461
+ ? "bg-panel-accent/14 text-accent-ink"
462
462
  : "text-panel-text-2 hover:bg-panel-hover/40 hover:text-panel-text-1"
463
463
  } ${dragKey ? "cursor-grabbing" : "cursor-pointer"}`}
464
464
  style={{ paddingLeft: 8 + layer.depth * 16 }}
@@ -494,9 +494,9 @@ export const LayersPanel = memo(function LayersPanel() {
494
494
  <span
495
495
  className={`flex h-5 w-5 shrink-0 items-center justify-center rounded text-[8px] font-bold uppercase ${
496
496
  selected
497
- ? "bg-panel-accent/18 text-panel-accent"
497
+ ? "bg-panel-accent/18 text-accent-ink"
498
498
  : isCompHost
499
- ? "bg-panel-accent/40 text-panel-accent"
499
+ ? "bg-on text-accent-ink"
500
500
  : "bg-panel-hover text-panel-text-4"
501
501
  }`}
502
502
  >
@@ -83,7 +83,7 @@ export function PromotableControl({
83
83
  <span
84
84
  // Sits above the row (not on top of top-0) so it clears a value that
85
85
  // renders flush to the row's right edge, e.g. flat Font/Color rows.
86
- className="pointer-events-none absolute -top-2 right-1.5 z-10 inline-flex max-w-[60%] items-center gap-1 truncate rounded-sm bg-studio-accent/20 px-1 py-px font-mono text-[8px] font-medium text-studio-accent"
86
+ className="pointer-events-none absolute -top-2 right-1.5 z-10 inline-flex max-w-[60%] items-center gap-1 truncate rounded-sm bg-studio-accent/20 px-1 py-px font-mono text-[8px] font-medium text-accent-ink"
87
87
  title={`Bound to variable "${promote.boundId}"`}
88
88
  >
89
89
  ◆ {promote.boundId}
@@ -97,7 +97,7 @@ export function PromotableControl({
97
97
  e.stopPropagation();
98
98
  promote.promote();
99
99
  }}
100
- className="absolute -top-2 right-1.5 z-10 inline-flex items-center gap-1 rounded-sm bg-neutral-800/80 px-1 py-px font-mono text-[8px] font-medium text-neutral-400 opacity-70 transition-colors hover:bg-studio-accent/20 hover:text-studio-accent hover:opacity-100"
100
+ className="absolute -top-2 right-1.5 z-10 inline-flex items-center gap-1 rounded-sm bg-raised/80 px-1 py-px font-mono text-[8px] font-medium text-neutral-400 opacity-70 transition-colors hover:bg-studio-accent/20 hover:text-accent-ink hover:opacity-100"
101
101
  >
102
102
  ◇ var
103
103
  </button>
@@ -3,8 +3,8 @@ import { memo, useMemo, useRef, useState } from "react";
3
3
  import { Move } from "../../icons/SystemIcons";
4
4
  import { InspectorHeaderActions } from "./InspectorHeaderActions";
5
5
  import { useStudioShellContext } from "../../contexts/StudioContext";
6
- import { readStudioBoxSize, readStudioRotation } from "./manualEdits";
7
- import { readMoveOffset } from "./plainTranslate";
6
+ import { readStudioBoxSize } from "./manualEdits";
7
+ import { readMoveOffset, readShownRotation } from "./plainTranslate";
8
8
  import {
9
9
  buildElementInfoText,
10
10
  EMPTY_STYLES,
@@ -210,7 +210,7 @@ export const PropertyPanel = memo(function PropertyPanel(props: PropertyPanelPro
210
210
  manualSize.height > 0
211
211
  ? manualSize.height
212
212
  : (parsePxMetricValue(styles.height ?? "") ?? element.boundingBox.height);
213
- const manualRotation = readStudioRotation(element.element);
213
+ const manualRotation = readShownRotation(element.element);
214
214
 
215
215
  const elStart = Number.parseFloat(element?.dataAttributes?.start ?? "0") || 0;
216
216
  const elDuration = Number.parseFloat(element?.dataAttributes?.duration ?? "1") || 0;
@@ -24,7 +24,7 @@ function FlatEmptyState() {
24
24
  <div className="mt-2 flex w-full flex-col gap-1.5">
25
25
  <span className="flex items-center justify-between rounded-lg border border-panel-border bg-panel-bg px-3 py-2">
26
26
  <span className="flex items-center gap-2 text-[11px] text-panel-text-2">
27
- <span className="text-panel-danger">●</span>
27
+ <span className="text-danger-ink">●</span>
28
28
  Record a gesture
29
29
  </span>
30
30
  <span className="rounded-sm border border-panel-border-input px-[5px] py-px font-mono text-[9px] text-panel-text-5">
@@ -33,7 +33,7 @@ function FlatEmptyState() {
33
33
  </span>
34
34
  <span className="flex items-center justify-between rounded-lg border border-panel-border bg-panel-bg px-3 py-2">
35
35
  <span className="flex items-center gap-2 text-[11px] text-panel-text-2">
36
- <span className="text-panel-accent">✦</span>
36
+ <span className="text-accent-ink">✦</span>
37
37
  Describe a change to the agent
38
38
  </span>
39
39
  <span className="rounded-sm border border-panel-border-input px-[5px] py-px font-mono text-[9px] text-panel-text-5">
@@ -50,7 +50,7 @@ function elementKindGlyph(element: DomEditSelection): { glyph: string; className
50
50
  return { glyph: "◆", className: "bg-panel-media/10 text-panel-media" };
51
51
  }
52
52
  if (element.textFields?.length > 0) {
53
- return { glyph: "T", className: "bg-panel-accent/10 text-panel-accent" };
53
+ return { glyph: "T", className: "bg-panel-accent/10 text-accent-ink" };
54
54
  }
55
55
  return { glyph: "▦", className: "bg-panel-container/10 text-panel-container" };
56
56
  }
@@ -74,7 +74,7 @@ function FlatMultiSelectState({
74
74
  return (
75
75
  <div className="flex flex-col gap-3 px-4 py-3">
76
76
  <div className="flex items-center gap-3 rounded-xl border border-panel-border bg-panel-surface p-3">
77
- <span className="flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-panel-accent/10 text-panel-accent">
77
+ <span className="flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-panel-accent/10 text-accent-ink">
78
78
  <Layers size={16} />
79
79
  </span>
80
80
  <div className="min-w-0 flex-1">
@@ -40,7 +40,7 @@ export function PropertyPanelFlatFooter({
40
40
  height="13"
41
41
  viewBox="0 0 16 16"
42
42
  fill="currentColor"
43
- className="text-panel-accent"
43
+ className="text-accent-ink"
44
44
  >
45
45
  <path d="M8 1l1.4 4.6L14 7l-4.6 1.4L8 13l-1.4-4.6L2 7l4.6-1.4z" />
46
46
  </svg>
@@ -57,7 +57,7 @@ export function PropertyPanelFlatFooter({
57
57
  track("button", "Gesture recording");
58
58
  onToggleRecording();
59
59
  }}
60
- className={recording ? "text-panel-danger animate-pulse" : "text-panel-danger"}
60
+ className={recording ? "text-danger-ink animate-pulse" : "text-danger-ink"}
61
61
  >
62
62
  <svg width="14" height="14" viewBox="0 0 14 14" fill="currentColor">
63
63
  {recording ? (