@alphacifer/slidev-addon-theme 0.0.9 → 0.0.11

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 (220) hide show
  1. package/README.md +133 -75
  2. package/components/card/chevron-card/ChevronCard.vue +44 -32
  3. package/components/card/chevron-card/ChevronCardBadge.vue +14 -8
  4. package/components/card/chevron-card/ChevronCardContent.vue +15 -13
  5. package/components/card/chevron-card/style.css +12 -0
  6. package/components/card/{horiz-card/HorizCard.vue → horizontal-card/HorizontalCard.vue} +78 -85
  7. package/components/card/{horiz-card/HorizCardBadge.vue → horizontal-card/HorizontalCardBadge.vue} +15 -10
  8. package/components/card/{horiz-card/HorizCardContent.vue → horizontal-card/HorizontalCardContent.vue} +11 -11
  9. package/components/card/{horiz-card/HorizCardIcon.vue → horizontal-card/HorizontalCardIcon.vue} +24 -38
  10. package/components/card/horizontal-card/style.css +17 -0
  11. package/components/card/{vert-card/VertCard.vue → vertical-card/VerticalCard.vue} +80 -103
  12. package/components/card/{vert-card/VertCardBadge.vue → vertical-card/VerticalCardBadge.vue} +15 -10
  13. package/components/card/{vert-card/VertCardContent.vue → vertical-card/VerticalCardContent.vue} +13 -12
  14. package/components/card/{vert-card/VertCardIcon.vue → vertical-card/VerticalCardIcon.vue} +15 -33
  15. package/components/card/vertical-card/style.css +19 -0
  16. package/components/comparisons/arc-comparison/ArcComparison.vue +376 -80
  17. package/components/comparisons/arc-comparison/ArcComparisonBadge.vue +9 -4
  18. package/components/comparisons/arc-comparison/ArcComparisonContent.vue +9 -4
  19. package/components/comparisons/arc-comparison/ArcComparisonHeading.vue +9 -4
  20. package/components/comparisons/arc-comparison/ArcComparisonLeft.vue +39 -63
  21. package/components/comparisons/arc-comparison/ArcComparisonOrbit.vue +9 -8
  22. package/components/comparisons/arc-comparison/ArcComparisonRight.vue +39 -63
  23. package/components/comparisons/arc-comparison/style.css +27 -0
  24. package/components/comparisons/table-comparison/TableComparison.vue +17 -97
  25. package/components/comparisons/table-comparison/TableComparisonCell.vue +22 -20
  26. package/components/comparisons/table-comparison/{TableComparisonCol.vue → TableComparisonColumn.vue} +16 -14
  27. package/components/comparisons/table-comparison/{TableComparisonCols.vue → TableComparisonColumns.vue} +5 -8
  28. package/components/comparisons/table-comparison/TableComparisonRow.vue +10 -14
  29. package/components/comparisons/table-comparison/TableComparisonRows.vue +1 -4
  30. package/components/comparisons/table-comparison/style.css +15 -0
  31. package/components/core/Date.vue +2 -5
  32. package/components/core/QnA.vue +1 -1
  33. package/components/core/Quote.vue +3 -6
  34. package/components/core/ReflectedTitle.vue +2 -6
  35. package/components/core/Speaker.vue +5 -10
  36. package/components/core/TransitionHeading.vue +2 -5
  37. package/components/core/arc-orbit/ArcOrbit.vue +65 -84
  38. package/components/core/arc-orbit/ArcOrbitBadge.vue +9 -11
  39. package/components/core/arc-orbit/ArcOrbitCallout.vue +30 -32
  40. package/components/core/arc-orbit/ArcOrbitContent.vue +6 -12
  41. package/components/core/arc-orbit/ArcOrbitHeading.vue +13 -11
  42. package/components/core/arc-orbit/style.css +20 -0
  43. package/components/core/style.css +9 -0
  44. package/components/core/thanks/{ThanksContent.vue → SquareThanks.vue} +36 -31
  45. package/components/core/thanks/SquareThanksContent.vue +89 -0
  46. package/components/core/thanks/ThanksOutlineSquare.vue +2 -5
  47. package/components/core/thanks/ThanksSquare.vue +2 -5
  48. package/components/core/thanks/style.css +30 -0
  49. package/components/defense-in-depth/arc-defense-in-depth/ArcDefenseInDepth.vue +802 -0
  50. package/components/defense-in-depth/arc-defense-in-depth/ArcDefenseInDepthLayer.vue +240 -0
  51. package/components/defense-in-depth/arc-defense-in-depth/ArcDefenseInDepthLayerHeading.vue +96 -0
  52. package/components/defense-in-depth/arc-defense-in-depth/ArcDefenseInDepthLayerPart.vue +501 -0
  53. package/components/defense-in-depth/arc-defense-in-depth/ArcDefenseInDepthLayerSector.vue +162 -0
  54. package/components/defense-in-depth/arc-defense-in-depth/style.css +38 -0
  55. package/components/facets/tetrad/{rect-orbit-tetrad/RectOrbitTetrad.vue → rectangle-orbit-tetrad/RectangleOrbitTetrad.vue} +66 -63
  56. package/components/facets/tetrad/{rect-orbit-tetrad/RectOrbitTetradCallout.vue → rectangle-orbit-tetrad/RectangleOrbitTetradCallout.vue} +62 -48
  57. package/components/facets/tetrad/rectangle-orbit-tetrad/RectangleOrbitTetradCenter.vue +54 -0
  58. package/components/facets/tetrad/rectangle-orbit-tetrad/RectangleOrbitTetradContent.vue +44 -0
  59. package/components/facets/tetrad/rectangle-orbit-tetrad/RectangleOrbitTetradHeading.vue +27 -0
  60. package/components/facets/tetrad/{rect-orbit-tetrad/RectOrbitTetradIcon.vue → rectangle-orbit-tetrad/RectangleOrbitTetradIcon.vue} +23 -13
  61. package/components/facets/tetrad/rectangle-orbit-tetrad/style.css +22 -0
  62. package/components/facets/triad/arrow-triad/ArrowTriad.vue +99 -109
  63. package/components/facets/triad/arrow-triad/ArrowTriadCallout.vue +31 -59
  64. package/components/facets/triad/arrow-triad/ArrowTriadContent.vue +18 -13
  65. package/components/facets/triad/arrow-triad/ArrowTriadHeading.vue +20 -13
  66. package/components/facets/triad/arrow-triad/ArrowTriadIcon.vue +14 -9
  67. package/components/facets/triad/arrow-triad/style.css +15 -0
  68. package/components/facets/triad/gear-triad/GearTriad.vue +73 -64
  69. package/components/facets/triad/gear-triad/GearTriadCallout.vue +58 -53
  70. package/components/facets/triad/gear-triad/GearTriadCenter.vue +9 -4
  71. package/components/facets/triad/gear-triad/GearTriadContent.vue +21 -36
  72. package/components/facets/triad/gear-triad/GearTriadDetail.vue +92 -0
  73. package/components/facets/triad/gear-triad/GearTriadDetails.vue +169 -0
  74. package/components/facets/triad/gear-triad/GearTriadDetailsContent.vue +18 -0
  75. package/components/facets/triad/gear-triad/GearTriadDetailsHeading.vue +60 -0
  76. package/components/facets/triad/gear-triad/GearTriadHeading.vue +19 -13
  77. package/components/facets/triad/gear-triad/GearTriadIcon.vue +22 -9
  78. package/components/facets/triad/gear-triad/style.css +26 -0
  79. package/components/facets/triad/{hex-triad/HexTriad.vue → hexagon-triad/HexagonTriad.vue} +81 -63
  80. package/components/facets/triad/{hex-triad/HexTriadBadge.vue → hexagon-triad/HexagonTriadBadge.vue} +38 -12
  81. package/components/facets/triad/{hex-triad/HexTriadCallout.vue → hexagon-triad/HexagonTriadCallout.vue} +35 -31
  82. package/components/facets/triad/hexagon-triad/HexagonTriadCenterBadge.vue +74 -0
  83. package/components/facets/triad/hexagon-triad/HexagonTriadContent.vue +34 -0
  84. package/components/facets/triad/hexagon-triad/HexagonTriadHeading.vue +44 -0
  85. package/components/facets/triad/{hex-triad/HexTriadLayer.vue → hexagon-triad/HexagonTriadLayer.vue} +12 -4
  86. package/components/facets/triad/hexagon-triad/style.css +22 -0
  87. package/components/process/arc-arrow-process/ArcArrowProcess.vue +13 -35
  88. package/components/process/arc-arrow-process/ArcArrowProcessArrow.vue +20 -21
  89. package/components/process/arc-arrow-process/ArcArrowProcessCallout.vue +30 -71
  90. package/components/process/arc-arrow-process/ArcArrowProcessContent.vue +18 -13
  91. package/components/process/arc-arrow-process/ArcArrowProcessHeading.vue +18 -18
  92. package/components/process/arc-arrow-process/ArcArrowProcessIcon.vue +23 -11
  93. package/components/process/arc-arrow-process/style.css +20 -0
  94. package/components/pyramid/circular-pyramid/CircularPyramid.vue +276 -190
  95. package/components/pyramid/circular-pyramid/CircularPyramidStack.vue +83 -98
  96. package/components/pyramid/circular-pyramid/CircularPyramidStackContent.vue +136 -29
  97. package/components/pyramid/circular-pyramid/CircularPyramidStackHeading.vue +212 -0
  98. package/components/pyramid/circular-pyramid/style.css +26 -0
  99. package/components/pyramid/square-pyramid/SquarePyramid.vue +199 -83
  100. package/components/pyramid/square-pyramid/SquarePyramidStack.vue +87 -95
  101. package/components/pyramid/square-pyramid/SquarePyramidStackContent.vue +138 -27
  102. package/components/pyramid/square-pyramid/SquarePyramidStackHeading.vue +212 -0
  103. package/components/pyramid/square-pyramid/style.css +48 -0
  104. package/components/style.css +35 -0
  105. package/layouts/core/arc-toc.vue +40 -45
  106. package/layouts/core/bg-center.vue +7 -6
  107. package/layouts/core/style.css +17 -0
  108. package/layouts/shifting-heading/shifting-intro.vue +4 -13
  109. package/layouts/thanks/thanks.vue +5 -5
  110. package/package.json +8 -6
  111. package/style.css +17 -0
  112. package/uno.config.ts +1 -0
  113. package/utils/activateOnKeyboard.ts +14 -0
  114. package/utils/{chevronCard → card/chevron-card}/context.ts +1 -1
  115. package/utils/card/chevron-card/index.ts +1 -0
  116. package/utils/card/horizontal-card/context.ts +12 -0
  117. package/utils/{horizCard/createHorizCardGeometry.ts → card/horizontal-card/createHorizontalCardGeometry.ts} +10 -45
  118. package/utils/card/horizontal-card/index.ts +2 -0
  119. package/utils/card/vertical-card/context.ts +19 -0
  120. package/utils/{vertCard/createVertCardGeometry.ts → card/vertical-card/createVerticalCardGeometry.ts} +9 -130
  121. package/utils/card/vertical-card/index.ts +2 -0
  122. package/utils/colors.ts +93 -0
  123. package/utils/{arcComparison → comparisons/arc-comparison}/context.ts +0 -11
  124. package/utils/{arcComparison → comparisons/arc-comparison}/createArcComparisonGeometry.ts +1 -1
  125. package/utils/comparisons/arc-comparison/resolveArcComparisonItems.ts +33 -0
  126. package/utils/comparisons/table-comparison/constants.ts +47 -0
  127. package/utils/{tableComparison → comparisons/table-comparison}/context.ts +2 -2
  128. package/utils/{arcOrbit → core/arc-orbit}/resolveArcOrbitItems.ts +11 -15
  129. package/utils/defense-in-depth/arc-defense-in-depth/context.ts +113 -0
  130. package/utils/defense-in-depth/arc-defense-in-depth/createArcDefenseInDepthGeometry.ts +600 -0
  131. package/utils/defense-in-depth/arc-defense-in-depth/types.ts +144 -0
  132. package/utils/defense-in-depth/shared/colors.ts +51 -0
  133. package/utils/defense-in-depth/shared/constants.ts +22 -0
  134. package/utils/defense-in-depth/shared/types.ts +7 -0
  135. package/utils/facets/tetrad/rectangle-orbit-tetrad/context.ts +31 -0
  136. package/utils/{rectOrbitTetrad/createRectOrbitTetradGeometry.ts → facets/tetrad/rectangle-orbit-tetrad/createRectangleOrbitTetradGeometry.ts} +5 -104
  137. package/utils/facets/tetrad/rectangle-orbit-tetrad/index.ts +3 -0
  138. package/utils/{rectOrbitTetrad/resolveRectOrbitTetradItems.ts → facets/tetrad/rectangle-orbit-tetrad/resolveRectangleOrbitTetradItems.ts} +41 -49
  139. package/utils/{arrowTriad → facets/triad/arrow-triad}/resolveArrowTriadItems.ts +27 -28
  140. package/utils/{gearTriad → facets/triad/gear-triad}/context.ts +5 -5
  141. package/utils/{gearTriad → facets/triad/gear-triad}/createGearTriadGeometry.ts +2 -0
  142. package/utils/{gearTriad → facets/triad/gear-triad}/resolveGearTriadItems.ts +23 -24
  143. package/utils/facets/triad/hexagon-triad/context.ts +25 -0
  144. package/utils/{hexTriad/createHexTriadGeometry.ts → facets/triad/hexagon-triad/createHexagonTriadGeometry.ts} +11 -27
  145. package/utils/facets/triad/hexagon-triad/index.ts +3 -0
  146. package/utils/facets/triad/hexagon-triad/resolveHexagonTriadItems.ts +60 -0
  147. package/utils/{shiftingHeading → layouts/shifting-heading}/collectShiftingIntroNodes.ts +1 -0
  148. package/utils/layouts/table-of-contents/calculateTocCenterAlignmentOffset.ts +17 -0
  149. package/utils/{tableOfContents → layouts/table-of-contents}/calculateTocMarkerPositions.ts +0 -12
  150. package/utils/{tableOfContents → layouts/table-of-contents}/createTocConnectorPath.ts +11 -5
  151. package/utils/{mergeUno → merge-uno}/classifyVisual.ts +1 -1
  152. package/utils/{mergeUno → merge-uno}/collectClassNames.ts +9 -3
  153. package/utils/process/arc-arrow-process/resolveArcArrowProcessItems.ts +180 -0
  154. package/utils/pyramid/circular-pyramid/context.ts +1 -4
  155. package/utils/pyramid/circular-pyramid/createCircularPyramidGeometry.ts +6 -10
  156. package/utils/pyramid/shared/colors.ts +33 -83
  157. package/utils/pyramid/shared/constants.ts +3 -2
  158. package/utils/pyramid/shared/types.ts +0 -5
  159. package/utils/pyramid/square-pyramid/context.ts +1 -4
  160. package/utils/pyramid/square-pyramid/createSquarePyramidGeometry.ts +6 -10
  161. package/utils/useDiagramAutoScale.ts +64 -16
  162. package/utils/useMergedUnoAttrs.ts +9 -5
  163. package/components/card/chevron-card/ChevronCardHeading.vue +0 -39
  164. package/components/card/horiz-card/HorizCardHeading.vue +0 -47
  165. package/components/card/vert-card/VertCardHeading.vue +0 -68
  166. package/components/card/vert-card/VertCardTitle.vue +0 -76
  167. package/components/comparisons/arc-comparison/ArcComparisonContents.vue +0 -17
  168. package/components/comparisons/arc-comparison/ArcComparisonTitle.vue +0 -29
  169. package/components/core/arc-orbit/ArcOrbitContents.vue +0 -18
  170. package/components/core/arc-orbit/ArcOrbitTitle.vue +0 -50
  171. package/components/facets/tetrad/rect-orbit-tetrad/RectOrbitTetradCenter.vue +0 -53
  172. package/components/facets/tetrad/rect-orbit-tetrad/RectOrbitTetradContent.vue +0 -39
  173. package/components/facets/tetrad/rect-orbit-tetrad/RectOrbitTetradHeading.vue +0 -44
  174. package/components/facets/triad/gear-triad/GearTriadContents.vue +0 -111
  175. package/components/facets/triad/gear-triad/GearTriadDescription.vue +0 -38
  176. package/components/facets/triad/hex-triad/HexTriadCenterBadge.vue +0 -51
  177. package/components/facets/triad/hex-triad/HexTriadContent.vue +0 -20
  178. package/components/facets/triad/hex-triad/HexTriadHeading.vue +0 -28
  179. package/components/pyramid/circular-pyramid/CircularPyramidStackTitle.vue +0 -138
  180. package/components/pyramid/square-pyramid/SquarePyramidStackTitle.vue +0 -134
  181. package/layouts/core/table-of-contents.vue +0 -30
  182. package/utils/arcArrowProcess/resolveArcArrowProcessItems.ts +0 -189
  183. package/utils/arcComparison/resolveArcComparisonItems.ts +0 -102
  184. package/utils/chevronCard/createChevronCardGeometry.ts +0 -48
  185. package/utils/chevronCard/index.ts +0 -2
  186. package/utils/hexTriad/context.ts +0 -25
  187. package/utils/hexTriad/index.ts +0 -3
  188. package/utils/hexTriad/resolveHexTriadItems.ts +0 -63
  189. package/utils/horizCard/context.ts +0 -13
  190. package/utils/horizCard/index.ts +0 -2
  191. package/utils/pyramid/index.ts +0 -3
  192. package/utils/rectOrbitTetrad/context.ts +0 -31
  193. package/utils/rectOrbitTetrad/index.ts +0 -3
  194. package/utils/tableComparison/constants.ts +0 -72
  195. package/utils/tableOfContents/calculateTocCenterAlignmentOffset.ts +0 -11
  196. package/utils/vertCard/context.ts +0 -18
  197. package/utils/vertCard/index.ts +0 -2
  198. package/utils/{arcComparison → comparisons/arc-comparison}/index.ts +0 -0
  199. package/utils/{tableComparison → comparisons/table-comparison}/index.ts +0 -0
  200. package/utils/{arcOrbit → core/arc-orbit}/context.ts +0 -0
  201. package/utils/{arcOrbit → core/arc-orbit}/createArcOrbitGeometry.ts +0 -0
  202. package/utils/{arcOrbit → core/arc-orbit}/index.ts +0 -0
  203. package/utils/{arrowTriad → facets/triad/arrow-triad}/context.ts +0 -0
  204. package/utils/{arrowTriad → facets/triad/arrow-triad}/createArrowTriadGeometry.ts +0 -0
  205. package/utils/{arrowTriad → facets/triad/arrow-triad}/index.ts +0 -0
  206. package/utils/{gearTriad → facets/triad/gear-triad}/index.ts +0 -0
  207. package/utils/{tableOfContents → layouts/table-of-contents}/calculateUniformTocArticleWidth.ts +0 -0
  208. package/utils/{tableOfContents → layouts/table-of-contents}/createTocArcPath.ts +0 -0
  209. package/utils/{tableOfContents → layouts/table-of-contents}/index.ts +0 -0
  210. package/utils/{mergeUno → merge-uno}/classifyLayout.ts +0 -0
  211. package/utils/{mergeUno → merge-uno}/classifySimple.ts +0 -0
  212. package/utils/{mergeUno → merge-uno}/classifyTypography.ts +0 -0
  213. package/utils/{mergeUno → merge-uno}/classifyUtility.ts +0 -0
  214. package/utils/{mergeUno → merge-uno}/index.ts +0 -0
  215. package/utils/{mergeUno → merge-uno}/mergeClassValues.ts +0 -0
  216. package/utils/{mergeUno → merge-uno}/splitVariantScope.ts +1 -1
  217. package/utils/{mergeUno → merge-uno}/types.ts +0 -0
  218. package/utils/{arcArrowProcess → process/arc-arrow-process}/context.ts +1 -1
  219. /package/utils/{arcArrowProcess → process/arc-arrow-process}/createArcArrowProcessGeometry.ts +0 -0
  220. /package/utils/{arcArrowProcess → process/arc-arrow-process}/index.ts +0 -0
@@ -0,0 +1,802 @@
1
+ <script setup lang="ts">
2
+ import { activateOnKeyboard } from '../../../utils/activateOnKeyboard';
3
+ import {
4
+ type ComputedRef,
5
+ computed,
6
+ Fragment,
7
+ inject,
8
+ provide,
9
+ ref,
10
+ useSlots,
11
+ type VNode,
12
+ watch,
13
+ } from 'vue';
14
+
15
+ import {
16
+ ARC_DID_ROOT_KEY,
17
+ type IArcDefenseInDepthRegisteredLayerData,
18
+ type IArcDefenseInDepthRootContext,
19
+ } from '../../../utils/defense-in-depth/arc-defense-in-depth/context';
20
+ import { createArcDefenseInDepthGeometry } from '../../../utils/defense-in-depth/arc-defense-in-depth/createArcDefenseInDepthGeometry';
21
+ import type {
22
+ IArcDefenseInDepthLayerItem,
23
+ IArcDefenseInDepthPartGeometry,
24
+ TArcDefenseInDepthOrder,
25
+ } from '../../../utils/defense-in-depth/arc-defense-in-depth/types';
26
+ import { lightenColor } from '../../../utils/colors';
27
+ import { resolveArcDefenseInDepthPalette } from '../../../utils/defense-in-depth/shared/colors';
28
+ import { DEFAULT_DID_COLOR } from '../../../utils/defense-in-depth/shared/constants';
29
+ import { useDiagramAutoScale } from '../../../utils/useDiagramAutoScale';
30
+ import { useMergedUnoAttrs } from '../../../utils/useMergedUnoAttrs';
31
+
32
+ defineOptions({
33
+ name: 'ArcDefenseInDepth',
34
+ inheritAttrs: false,
35
+ });
36
+
37
+ export interface IArcDefenseInDepthProps {
38
+ readonly order?: TArcDefenseInDepthOrder;
39
+ readonly count?: number;
40
+ readonly activeIndex?: number;
41
+ readonly color?: string;
42
+ readonly colors?: readonly string[] | string[];
43
+ readonly width?: number | string;
44
+ readonly height?: number | string;
45
+ readonly scale?: number;
46
+ readonly autoScale?: boolean;
47
+ readonly maxScale?: number;
48
+ readonly animation?: boolean;
49
+ readonly startDelay?: number;
50
+ readonly interactive?: boolean;
51
+ readonly viewBoxWidth?: number;
52
+ readonly viewBoxHeight?: number;
53
+ readonly innerRadius?: number;
54
+ readonly outerRadius?: number;
55
+ readonly gap?: number;
56
+ readonly showDecorativeArcs?: boolean;
57
+ readonly titleAngleSpan?: number;
58
+ readonly showPartBoundaries?: boolean;
59
+ readonly activePart?: string | number;
60
+ }
61
+
62
+ const props = withDefaults(defineProps<IArcDefenseInDepthProps>(), {
63
+ order: 'outer-to-inner',
64
+ count: undefined,
65
+ activeIndex: -1,
66
+ activePart: undefined,
67
+ color: DEFAULT_DID_COLOR,
68
+ colors: undefined,
69
+ width: 720,
70
+ height: undefined,
71
+ scale: undefined,
72
+ autoScale: true,
73
+ maxScale: undefined,
74
+ animation: true,
75
+ startDelay: undefined,
76
+ interactive: true,
77
+ viewBoxWidth: 900,
78
+ viewBoxHeight: 460,
79
+ innerRadius: 90,
80
+ outerRadius: 445,
81
+ gap: 0,
82
+ showDecorativeArcs: false,
83
+ titleAngleSpan: undefined,
84
+ showPartBoundaries: true,
85
+ });
86
+
87
+ const emit = defineEmits<{
88
+ (e: 'update:activeIndex', index: number): void;
89
+ (e: 'update:activePart', part: string | number | undefined): void;
90
+ (e: 'select', index: number): void;
91
+ (e: 'part-click', part: IArcDefenseInDepthPartGeometry): void;
92
+ (e: 'click', event: MouseEvent): void;
93
+ }>();
94
+
95
+ const slots = useSlots();
96
+ const rootRef = ref<HTMLElement | null>(null);
97
+
98
+ const shiftingIntro = inject<
99
+ | {
100
+ active: ComputedRef<boolean>;
101
+ isShifting?: ComputedRef<boolean>;
102
+ }
103
+ | undefined
104
+ >('SLIDEV_LAYOUT_SHIFTING_INTRO', undefined);
105
+
106
+ const isAnimated = computed(() => {
107
+ if (!props.animation) {
108
+ return false;
109
+ }
110
+
111
+ if (shiftingIntro) {
112
+ return shiftingIntro.active.value;
113
+ }
114
+
115
+ return true;
116
+ });
117
+
118
+ const resolvedStartDelay = computed(() => {
119
+ if (props.startDelay !== undefined) {
120
+ return props.startDelay;
121
+ }
122
+
123
+ if (shiftingIntro?.isShifting?.value) {
124
+ return 500;
125
+ }
126
+
127
+ return 0;
128
+ });
129
+
130
+ interface INamedComponent {
131
+ readonly type?: {
132
+ readonly name?: string;
133
+ readonly displayName?: string;
134
+ readonly __name?: string;
135
+ };
136
+ }
137
+
138
+ function hasComponentName(type: unknown, targetName: string): boolean {
139
+ if (typeof type === 'object' && type !== null) {
140
+ const comp = type as INamedComponent['type'];
141
+ return (
142
+ comp?.name === targetName ||
143
+ comp?.displayName === targetName ||
144
+ comp?.__name === targetName
145
+ );
146
+ }
147
+
148
+ return false;
149
+ }
150
+
151
+ function countSlottedLayers(slotNodes?: VNode[]): number {
152
+ if (!slotNodes) {
153
+ return 0;
154
+ }
155
+
156
+ let count = 0;
157
+ for (const node of slotNodes) {
158
+ if (hasComponentName(node.type, 'ArcDefenseInDepthLayer')) {
159
+ count++;
160
+ continue;
161
+ }
162
+ if (node.type === Fragment && Array.isArray(node.children)) {
163
+ count += countSlottedLayers(node.children as VNode[]);
164
+ }
165
+ }
166
+
167
+ return count;
168
+ }
169
+
170
+ const slottedLayerCount = computed(() => {
171
+ const defaultSlotNodes = slots.default?.();
172
+ return countSlottedLayers(defaultSlotNodes);
173
+ });
174
+
175
+ const registeredLayerTokens = ref<symbol[]>([]);
176
+ const registeredLayerData = ref<
177
+ Map<symbol, IArcDefenseInDepthRegisteredLayerData>
178
+ >(new Map());
179
+
180
+ function registerLayer(
181
+ token?: symbol,
182
+ dataRef?: ComputedRef<IArcDefenseInDepthRegisteredLayerData | undefined>,
183
+ ) {
184
+ const lToken = token ?? Symbol();
185
+ if (!registeredLayerTokens.value.includes(lToken)) {
186
+ registeredLayerTokens.value = [...registeredLayerTokens.value, lToken];
187
+ }
188
+
189
+ let stopWatch: (() => void) | undefined;
190
+ if (dataRef) {
191
+ stopWatch = watch(
192
+ dataRef,
193
+ (val) => {
194
+ const nextMap = new Map(registeredLayerData.value);
195
+ if (val) {
196
+ nextMap.set(lToken, val);
197
+ } else {
198
+ nextMap.delete(lToken);
199
+ }
200
+ registeredLayerData.value = nextMap;
201
+ },
202
+ { immediate: true },
203
+ );
204
+ }
205
+
206
+ const index = computed(() => registeredLayerTokens.value.indexOf(lToken));
207
+
208
+ return {
209
+ index,
210
+ unregister: () => {
211
+ stopWatch?.();
212
+ registeredLayerTokens.value = registeredLayerTokens.value.filter(
213
+ (t) => t !== lToken,
214
+ );
215
+ const nextMap = new Map(registeredLayerData.value);
216
+ nextMap.delete(lToken);
217
+ registeredLayerData.value = nextMap;
218
+ },
219
+ };
220
+ }
221
+
222
+ const resolvedCount = computed<number>(() => {
223
+ if (props.count !== undefined && props.count > 0) {
224
+ return Math.max(1, Math.min(props.count, 6));
225
+ }
226
+
227
+ if (slottedLayerCount.value > 0) {
228
+ return Math.max(1, Math.min(slottedLayerCount.value, 6));
229
+ }
230
+
231
+ if (registeredLayerTokens.value.length > 0) {
232
+ return Math.max(1, Math.min(registeredLayerTokens.value.length, 6));
233
+ }
234
+
235
+ return 0;
236
+ });
237
+
238
+ const resolvedLayers = computed<IArcDefenseInDepthLayerItem[]>(() => {
239
+ const indexed: (IArcDefenseInDepthLayerItem | undefined)[] = [];
240
+ const unindexed: IArcDefenseInDepthLayerItem[] = [];
241
+
242
+ for (let i = 0; i < registeredLayerTokens.value.length; i++) {
243
+ const token = registeredLayerTokens.value[i];
244
+ if (!token) {
245
+ continue;
246
+ }
247
+
248
+ const data = registeredLayerData.value.get(token);
249
+ const item: IArcDefenseInDepthLayerItem = {
250
+ title: data?.title ?? '',
251
+ color: data?.color,
252
+ parts: data?.parts ?? [],
253
+ sectors: data?.sectors ?? [],
254
+ titleAngleSpan: data?.titleAngleSpan,
255
+ titleWidth: data?.titleWidth,
256
+ };
257
+ if (data?.index !== undefined && data.index >= 0) {
258
+ indexed[data.index] = item;
259
+ } else {
260
+ unindexed.push(item);
261
+ }
262
+ }
263
+
264
+ let unindexedIdx = 0;
265
+ const result: IArcDefenseInDepthLayerItem[] = [];
266
+ const total = Math.max(indexed.length, registeredLayerTokens.value.length);
267
+ for (let i = 0; i < total; i++) {
268
+ const item = indexed[i];
269
+ if (item) {
270
+ result.push(item);
271
+ } else {
272
+ const fallback = unindexed[unindexedIdx++];
273
+ if (fallback) {
274
+ result.push(fallback);
275
+ }
276
+ }
277
+ }
278
+
279
+ return result;
280
+ });
281
+
282
+ const palette = computed(() =>
283
+ resolveArcDefenseInDepthPalette(props.color, resolvedCount.value),
284
+ );
285
+
286
+ function getLayerColor(index: number): string {
287
+ if (index >= 0 && index < registeredLayerTokens.value.length) {
288
+ const token = registeredLayerTokens.value[index];
289
+ if (token) {
290
+ const custom = registeredLayerData.value.get(token)?.color;
291
+ if (custom) {
292
+ return custom;
293
+ }
294
+ }
295
+ }
296
+
297
+ const customColor = props.colors?.[index];
298
+ if (customColor) {
299
+ return customColor;
300
+ }
301
+
302
+ const defaultLayers = palette.value.layerColors;
303
+ return defaultLayers[index % defaultLayers.length] ?? DEFAULT_DID_COLOR;
304
+ }
305
+
306
+ const internalActiveIndex = ref<number>(props.activeIndex);
307
+
308
+ watch(
309
+ () => props.activeIndex,
310
+ (val) => {
311
+ internalActiveIndex.value = val;
312
+ },
313
+ );
314
+
315
+ function setActiveIndex(index: number): void {
316
+ internalActiveIndex.value = index;
317
+ emit('update:activeIndex', index);
318
+ emit('select', index);
319
+ }
320
+
321
+ const internalActivePart = ref<string | number | undefined>(props.activePart);
322
+ watch(
323
+ () => props.activePart,
324
+ (val) => {
325
+ internalActivePart.value = val;
326
+ },
327
+ );
328
+
329
+ function setActivePart(part: string | number | undefined): void {
330
+ internalActivePart.value = part;
331
+ emit('update:activePart', part);
332
+ }
333
+
334
+ function isPartActive(part: IArcDefenseInDepthPartGeometry): boolean {
335
+ if (part.active) {
336
+ return true;
337
+ }
338
+
339
+ if (internalActivePart.value !== undefined) {
340
+ return (
341
+ internalActivePart.value === part.label ||
342
+ internalActivePart.value === part.index
343
+ );
344
+ }
345
+
346
+ return false;
347
+ }
348
+
349
+ const geo = computed(() => {
350
+ return createArcDefenseInDepthGeometry({
351
+ viewBoxWidth: props.viewBoxWidth,
352
+ viewBoxHeight: props.viewBoxHeight,
353
+ innerRadius: props.innerRadius,
354
+ outerRadius: props.outerRadius,
355
+ count: resolvedCount.value,
356
+ gap: props.gap,
357
+ order: props.order,
358
+ titleAngleSpan: props.titleAngleSpan,
359
+ layers: resolvedLayers.value,
360
+ });
361
+ });
362
+
363
+ const hasAnyActivePart = computed<boolean>(() => {
364
+ if (internalActivePart.value !== undefined) {
365
+ return true;
366
+ }
367
+
368
+ for (const layer of geo.value.layers) {
369
+ for (const part of layer.parts) {
370
+ if (part.active) {
371
+ return true;
372
+ }
373
+ }
374
+ }
375
+
376
+ return false;
377
+ });
378
+
379
+ function getActivePartFill(
380
+ customColor?: string,
381
+ fallbackBaseColor?: string,
382
+ ): string {
383
+ const base = customColor || fallbackBaseColor || DEFAULT_DID_COLOR;
384
+ return lightenColor({ hex: base, ratio: 0.5 });
385
+ }
386
+
387
+ function getPartOpacity(layerIndex: number, isActive: boolean): number {
388
+ if (hasAnyActivePart.value) {
389
+ return isActive ? 1 : 0.28;
390
+ }
391
+
392
+ if (
393
+ internalActiveIndex.value === -1 ||
394
+ internalActiveIndex.value === layerIndex
395
+ ) {
396
+ return 1;
397
+ }
398
+
399
+ return 0.45;
400
+ }
401
+
402
+ function handlePartClick(
403
+ part: IArcDefenseInDepthPartGeometry,
404
+ layerIndex: number,
405
+ ): void {
406
+ if (!props.interactive) {
407
+ return;
408
+ }
409
+
410
+ emit('part-click', part);
411
+ if (isPartActive(part)) {
412
+ setActivePart(undefined);
413
+ } else {
414
+ setActivePart(part.label);
415
+ if (
416
+ internalActiveIndex.value !== -1 &&
417
+ internalActiveIndex.value !== layerIndex
418
+ ) {
419
+ setActiveIndex(layerIndex);
420
+ }
421
+ }
422
+ }
423
+
424
+ const rootContext: IArcDefenseInDepthRootContext = {
425
+ geo,
426
+ count: resolvedCount,
427
+ activeIndex: internalActiveIndex,
428
+ setActiveIndex,
429
+ activePart: internalActivePart,
430
+ setActivePart,
431
+ hasAnyActivePart,
432
+ isPartActive: (label, index, activeProp) => {
433
+ if (activeProp) {
434
+ return true;
435
+ }
436
+
437
+ if (internalActivePart.value !== undefined) {
438
+ return (
439
+ internalActivePart.value === label || internalActivePart.value === index
440
+ );
441
+ }
442
+ return false;
443
+ },
444
+ color: computed(() => props.color),
445
+ colors: computed(() => props.colors),
446
+ order: computed(() => props.order),
447
+ animation: isAnimated,
448
+ interactive: computed(() => props.interactive),
449
+ startDelay: resolvedStartDelay,
450
+ getLayerColor,
451
+ registerLayer,
452
+ };
453
+
454
+ provide(ARC_DID_ROOT_KEY, rootContext);
455
+
456
+ const { resolvedScale, containerHeight } = useDiagramAutoScale({
457
+ rootRef,
458
+ baseWidth: props.viewBoxWidth,
459
+ baseHeight: props.viewBoxHeight,
460
+ scale: () => props.scale,
461
+ autoScale: () => props.autoScale,
462
+ maxScale: () => props.maxScale,
463
+ width: () => props.width,
464
+ height: () => props.height,
465
+ });
466
+
467
+ const stageTransform = computed(() => {
468
+ if (resolvedScale.value !== 1) {
469
+ return `scale(${resolvedScale.value})`;
470
+ }
471
+
472
+ return undefined;
473
+ });
474
+
475
+ const resolvedWidthStyle = computed(() => {
476
+ if (props.width !== undefined) {
477
+ return typeof props.width === 'number' ? `${props.width}px` : props.width;
478
+ }
479
+
480
+ return '100%';
481
+ });
482
+
483
+ const resolvedHeightStyle = computed(() => {
484
+ if (props.height !== undefined) {
485
+ return typeof props.height === 'number'
486
+ ? `${props.height}px`
487
+ : props.height;
488
+ }
489
+
490
+ if (containerHeight.value > 0) {
491
+ return `${containerHeight.value}px`;
492
+ }
493
+
494
+ return `${props.viewBoxHeight}px`;
495
+ });
496
+
497
+ function handleLayerClick(index: number): void {
498
+ if (props.interactive) {
499
+ if (internalActiveIndex.value === index) {
500
+ setActiveIndex(-1);
501
+ } else {
502
+ setActiveIndex(index);
503
+ }
504
+ }
505
+ }
506
+
507
+ function handleContainerClick(event: MouseEvent): void {
508
+ emit('click', event);
509
+ }
510
+
511
+ const { className, forwardedAttrs } = useMergedUnoAttrs(
512
+ 'alpha-arc-defense-in-depth w-full flex items-center justify-center select-none relative border-0 p-0 m-0 min-w-0 bg-transparent',
513
+ );
514
+ </script>
515
+
516
+ <template>
517
+ <fieldset
518
+ ref="rootRef"
519
+ aria-label="Defense in depth diagram"
520
+ v-bind="forwardedAttrs()"
521
+ :class="className()"
522
+ :data-count="resolvedCount"
523
+ :data-active-index="internalActiveIndex"
524
+ :data-order="props.order"
525
+ :style="{
526
+ width: resolvedWidthStyle,
527
+ height: resolvedHeightStyle,
528
+ '--alpha-arc-defense-in-depth-start-delay': `${resolvedStartDelay}ms`,
529
+ }"
530
+ @click="handleContainerClick"
531
+ @keydown="activateOnKeyboard"
532
+ >
533
+ <!-- Stage Container with diagram auto-scale -->
534
+ <div
535
+ class="alpha-arc-defense-in-depth__stage relative flex items-center justify-center overflow-visible shrink-0"
536
+ :style="{
537
+ width: `${props.viewBoxWidth}px`,
538
+ height: `${props.viewBoxHeight}px`,
539
+ transform: stageTransform,
540
+ transformOrigin: 'center center',
541
+ }"
542
+ >
543
+ <!-- Base SVG Layer: Concentric Arcs and Decorative Flairs -->
544
+ <svg
545
+ class="alpha-arc-defense-in-depth__svg absolute inset-0 w-full h-full overflow-visible pointer-events-none"
546
+ :viewBox="`0 0 ${props.viewBoxWidth} ${props.viewBoxHeight}`"
547
+ xmlns="http://www.w3.org/2000/svg"
548
+ >
549
+ <title>Defense in depth diagram</title>
550
+ <defs>
551
+ <filter
552
+ id="alpha-arc-defense-in-depth-glow"
553
+ x="-20%"
554
+ y="-20%"
555
+ width="140%"
556
+ height="140%"
557
+ >
558
+ <feGaussianBlur stdDeviation="3" result="blur" />
559
+ <feComposite in="SourceGraphic" in2="blur" operator="over" />
560
+ </filter>
561
+ </defs>
562
+
563
+ <!-- Concentric Arc Bands (Seamless with zero spacing) -->
564
+ <g class="alpha-arc-defense-in-depth__layers">
565
+ <g
566
+ v-for="layer in geo.layers"
567
+ :key="layer.index"
568
+ class="alpha-arc-defense-in-depth__layer-group"
569
+ >
570
+ <!-- Full base band -->
571
+ <path
572
+ :d="layer.path"
573
+ :fill="getLayerColor(layer.index)"
574
+ :stroke="props.showPartBoundaries ? palette.strokeColor : 'none'"
575
+ :stroke-width="props.showPartBoundaries ? 1.5 : 0"
576
+ stroke-linejoin="round"
577
+ class="alpha-arc-defense-in-depth__band transition-all duration-300 ease-out pointer-events-none"
578
+ :class="[
579
+ { 'alpha-arc-defense-in-depth__band--animated': isAnimated },
580
+ ]"
581
+ :style="{
582
+ opacity: hasAnyActivePart
583
+ ? (internalActiveIndex === layer.index ? 0.45 : 0.25)
584
+ : (internalActiveIndex === -1 || internalActiveIndex === layer.index ? 1 : 0.45),
585
+ filter:
586
+ internalActiveIndex === layer.index && !hasAnyActivePart
587
+ ? 'var(--alpha-arc-defense-in-depth-layer-glow)'
588
+ : undefined,
589
+ '--layer-anim-delay': `${resolvedStartDelay + layer.index * 100}ms`,
590
+ }"
591
+ />
592
+
593
+ <!-- Title Sector Boundary/Area (when layer has parts) -->
594
+ <path
595
+ v-if="props.showPartBoundaries && layer.titlePath && layer.parts.length > 0"
596
+ :d="layer.titlePath"
597
+ :fill="getLayerColor(layer.index)"
598
+ :stroke="palette.strokeColor"
599
+ stroke-width="1.5"
600
+ stroke-linejoin="round"
601
+ class="alpha-arc-defense-in-depth__band alpha-arc-defense-in-depth__sector alpha-arc-defense-in-depth__sector--title transition-all duration-300 ease-out hover:brightness-105 pointer-events-none"
602
+ :class="[
603
+ { 'alpha-arc-defense-in-depth__band--animated': isAnimated },
604
+ ]"
605
+ :style="{
606
+ opacity: hasAnyActivePart
607
+ ? (internalActiveIndex === layer.index ? 0.45 : 0.25)
608
+ : (internalActiveIndex === -1 || internalActiveIndex === layer.index ? 1 : 0.45),
609
+ '--layer-anim-delay': `${resolvedStartDelay + layer.index * 100}ms`,
610
+ }"
611
+ />
612
+
613
+ <!-- Interactive Part Sector Areas on top with visible boundaries -->
614
+ <template v-if="layer.sectors.length > 0">
615
+ <template v-for="sector in layer.sectors" :key="sector.index">
616
+ <!-- If sector has split: true, render individual track sub-bands -->
617
+ <template v-if="sector.split">
618
+ <path
619
+ v-for="part in sector.parts"
620
+ :key="part.index"
621
+ :d="part.path"
622
+ :fill="isPartActive(part) ? getActivePartFill(part.color || sector.color, getLayerColor(layer.index)) : (part.color || sector.color || getLayerColor(layer.index))"
623
+ :stroke="isPartActive(part) ? 'var(--alpha-arc-defense-in-depth-active-stroke)' : (props.showPartBoundaries ? palette.strokeColor : 'none')"
624
+ :stroke-width="isPartActive(part) ? 3.5 : (props.showPartBoundaries ? 1.5 : 0)"
625
+ stroke-linejoin="round"
626
+ class="alpha-arc-defense-in-depth__band alpha-arc-defense-in-depth__sector alpha-arc-defense-in-depth__sector--part transition-all duration-300 ease-out hover:brightness-110 pointer-events-none"
627
+ :class="[
628
+ { 'alpha-arc-defense-in-depth__band--animated': isAnimated },
629
+ { 'alpha-arc-defense-in-depth__sector--active': isPartActive(part) },
630
+ ]"
631
+ :style="{
632
+ opacity: getPartOpacity(layer.index, isPartActive(part)),
633
+ filter: isPartActive(part)
634
+ ? 'var(--alpha-arc-defense-in-depth-active-glow)'
635
+ : undefined,
636
+ '--layer-anim-delay': `${resolvedStartDelay + layer.index * 100}ms`,
637
+ }"
638
+ />
639
+ </template>
640
+ <!-- If sector is NOT split: render the entire sector band -->
641
+ <template v-else>
642
+ <path
643
+ :d="sector.path"
644
+ :fill="sector.parts[0] && isPartActive(sector.parts[0]) ? getActivePartFill(sector.color, getLayerColor(layer.index)) : (sector.color || getLayerColor(layer.index))"
645
+ :stroke="sector.parts[0] && isPartActive(sector.parts[0]) ? 'var(--alpha-arc-defense-in-depth-active-stroke)' : (props.showPartBoundaries ? palette.strokeColor : 'none')"
646
+ :stroke-width="sector.parts[0] && isPartActive(sector.parts[0]) ? 3.5 : (props.showPartBoundaries ? 1.5 : 0)"
647
+ stroke-linejoin="round"
648
+ class="alpha-arc-defense-in-depth__band alpha-arc-defense-in-depth__sector alpha-arc-defense-in-depth__sector--part transition-all duration-300 ease-out hover:brightness-110 pointer-events-none"
649
+ :class="[
650
+ { 'alpha-arc-defense-in-depth__band--animated': isAnimated },
651
+ { 'alpha-arc-defense-in-depth__sector--active': sector.parts[0] && isPartActive(sector.parts[0]) },
652
+ ]"
653
+ :style="{
654
+ opacity: getPartOpacity(layer.index, !!(sector.parts[0] && isPartActive(sector.parts[0]))),
655
+ filter: sector.parts[0] && isPartActive(sector.parts[0])
656
+ ? 'var(--alpha-arc-defense-in-depth-active-glow)'
657
+ : undefined,
658
+ '--layer-anim-delay': `${resolvedStartDelay + layer.index * 100}ms`,
659
+ }"
660
+ />
661
+ </template>
662
+
663
+ <!-- Divider concentric lines when sector is split -->
664
+ <template
665
+ v-if="props.showPartBoundaries && sector.split && sector.dividerPaths.length > 0"
666
+ >
667
+ <path
668
+ v-for="(dPath, dIdx) in sector.dividerPaths"
669
+ :key="dIdx"
670
+ :d="dPath"
671
+ fill="none"
672
+ :stroke="palette.strokeColor"
673
+ stroke-width="1.5"
674
+ stroke-linecap="round"
675
+ class="pointer-events-none"
676
+ />
677
+ </template>
678
+ </template>
679
+ </template>
680
+ </g>
681
+ </g>
682
+
683
+ <!-- Active Sector Highlight Overlay (rendered on top of all layers and dividers so stroke & glow are never clipped) -->
684
+ <g
685
+ v-if="hasAnyActivePart"
686
+ class="alpha-arc-defense-in-depth__active-sectors pointer-events-none"
687
+ >
688
+ <template v-for="layer in geo.layers" :key="layer.index">
689
+ <template v-for="sector in layer.sectors" :key="sector.index">
690
+ <template v-if="sector.split">
691
+ <template v-for="part in sector.parts" :key="part.index">
692
+ <path
693
+ v-if="isPartActive(part) && part.path"
694
+ :d="part.path"
695
+ :fill="getActivePartFill(part.color || sector.color, getLayerColor(layer.index))"
696
+ stroke="var(--alpha-arc-defense-in-depth-active-stroke)"
697
+ stroke-width="3.5"
698
+ stroke-linejoin="round"
699
+ class="alpha-arc-defense-in-depth__band alpha-arc-defense-in-depth__sector alpha-arc-defense-in-depth__sector--active pointer-events-none"
700
+ :style="{
701
+ filter: 'var(--alpha-arc-defense-in-depth-active-glow)',
702
+ }"
703
+ />
704
+ </template>
705
+ </template>
706
+ <template v-else>
707
+ <path
708
+ v-if="sector.parts[0] && isPartActive(sector.parts[0]) && sector.path"
709
+ :d="sector.path"
710
+ :fill="getActivePartFill(sector.color, getLayerColor(layer.index))"
711
+ stroke="var(--alpha-arc-defense-in-depth-active-stroke)"
712
+ stroke-width="3.5"
713
+ stroke-linejoin="round"
714
+ class="alpha-arc-defense-in-depth__band alpha-arc-defense-in-depth__sector alpha-arc-defense-in-depth__sector--active pointer-events-none"
715
+ :style="{
716
+ filter: 'var(--alpha-arc-defense-in-depth-active-glow)',
717
+ }"
718
+ />
719
+ </template>
720
+ </template>
721
+ </template>
722
+ </g>
723
+
724
+ <!-- Center Cutout Hole (Solid White Semicircle) -->
725
+ <path
726
+ v-if="geo.innerCutoutPath"
727
+ :d="geo.innerCutoutPath"
728
+ fill="var(--alpha-arc-defense-in-depth-center-fill)"
729
+ stroke="none"
730
+ class="pointer-events-none"
731
+ />
732
+ </svg>
733
+
734
+ <template v-if="props.interactive">
735
+ <template v-for="layer in geo.layers" :key="`layer-${layer.index}`">
736
+ <button
737
+ type="button"
738
+ class="alpha-interaction-control"
739
+ :aria-label="`Select layer ${layer.index + 1}`"
740
+ :style="{ clipPath: `path('${layer.path}')` }"
741
+ @click="handleLayerClick(layer.index)"
742
+ />
743
+ <button
744
+ v-if="props.showPartBoundaries && layer.titlePath && layer.parts.length > 0"
745
+ type="button"
746
+ class="alpha-interaction-control"
747
+ :aria-label="`Select layer ${layer.index + 1}`"
748
+ :style="{ clipPath: `path('${layer.titlePath}')` }"
749
+ @click="handleLayerClick(layer.index)"
750
+ />
751
+ <template v-for="sector in layer.sectors" :key="sector.index">
752
+ <template v-if="sector.split">
753
+ <button
754
+ v-for="part in sector.parts"
755
+ :key="part.index"
756
+ type="button"
757
+ class="alpha-interaction-control"
758
+ :aria-label="`Select part ${part.index + 1}`"
759
+ :style="{ clipPath: `path('${part.path}')` }"
760
+ @click.stop="handlePartClick(part, layer.index)"
761
+ />
762
+ </template>
763
+ <button
764
+ v-else
765
+ type="button"
766
+ class="alpha-interaction-control"
767
+ :aria-label="`Select sector ${sector.index + 1}`"
768
+ :style="{ clipPath: `path('${sector.path}')` }"
769
+ @click.stop="sector.parts[0] ? handlePartClick(sector.parts[0], layer.index) : handleLayerClick(layer.index)"
770
+ />
771
+ </template>
772
+ </template>
773
+ </template>
774
+
775
+ <!-- Stage Overlays: Slotted Layers -->
776
+ <div
777
+ class="alpha-arc-defense-in-depth__stage-overlay absolute inset-0 w-full h-full pointer-events-none"
778
+ >
779
+ <slot />
780
+ </div>
781
+ </div>
782
+ </fieldset>
783
+ </template>
784
+
785
+ <style scoped>
786
+ .alpha-arc-defense-in-depth__band--animated {
787
+ animation: arc-defense-in-depth-band-in 600ms cubic-bezier(0.16, 1, 0.3, 1)
788
+ var(--layer-anim-delay, 0ms) both;
789
+ transform-origin: 50% 90%;
790
+ }
791
+
792
+ @keyframes arc-defense-in-depth-band-in {
793
+ 0% {
794
+ opacity: 0;
795
+ transform: scale(0.92);
796
+ }
797
+ 100% {
798
+ opacity: 1;
799
+ transform: scale(1);
800
+ }
801
+ }
802
+ </style>