srcdev-nuxt-components 9.3.0 → 9.3.2

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 (53) hide show
  1. package/.claude/hooks/check-component-update.sh +66 -0
  2. package/.claude/settings.json +1 -1
  3. package/.claude/skills/component-local-style-override.md +45 -0
  4. package/.claude/skills/components/accordian-core.md +26 -5
  5. package/.claude/skills/components/expanding-panel-classic.md +221 -0
  6. package/.claude/skills/components/expanding-panel.md +8 -8
  7. package/.claude/skills/components/navigation-items.md +51 -0
  8. package/.claude/skills/components/responsive-header.md +161 -0
  9. package/.claude/skills/components/site-header.md +98 -0
  10. package/.claude/skills/index.md +6 -1
  11. package/.claude/skills/page-transitions.md +116 -0
  12. package/.claude/skills/theming-form-geometry-tokens.md +12 -0
  13. package/.claude/skills/theming-override-default.md +14 -0
  14. package/.claude/skills/theming-partial-override.md +17 -0
  15. package/.vscode/srcdev-component-accordian-core.code-snippets +74 -0
  16. package/.vscode/srcdev-component-expanding-panel-classic.code-snippets +121 -0
  17. package/.vscode/srcdev-component-expanding-panel.code-snippets +1 -3
  18. package/.vscode/srcdev-component-responsive-header.code-snippets +46 -0
  19. package/.vscode/srcdev-component-site-header.code-snippets +74 -0
  20. package/app/components/02.molecules/expandable/accordian/AccordianCore.vue +19 -11
  21. package/app/components/02.molecules/expandable/accordian/CONSUMER-STYLING.md +93 -0
  22. package/app/components/02.molecules/expandable/accordian/stories/AccordianCore.stories.ts +31 -0
  23. package/app/components/02.molecules/expandable/accordian/tests/AccordianCore.spec.ts +31 -0
  24. package/app/components/02.molecules/expandable/accordian/tests/__snapshots__/AccordianCore.spec.ts.snap +7 -21
  25. package/app/components/02.molecules/expandable/expanding-panel/CONSUMER-STYLING.md +10 -10
  26. package/app/components/02.molecules/expandable/expanding-panel/ExpandingPanel.vue +35 -37
  27. package/app/components/02.molecules/expandable/expanding-panel/stories/ExpandingPanel.stories.ts +5 -6
  28. package/app/components/02.molecules/expandable/expanding-panel/tests/__snapshots__/ExpandingPanel.spec.ts.snap +5 -13
  29. package/app/components/02.molecules/expandable/expanding-panel-classic/CONSUMER-STYLING.md +103 -0
  30. package/app/components/02.molecules/expandable/expanding-panel-classic/ExpandingPanelClassic.vue +191 -0
  31. package/app/components/02.molecules/expandable/expanding-panel-classic/stories/ExpandingPanelClassic.stories.ts +293 -0
  32. package/app/components/02.molecules/expandable/expanding-panel-classic/tests/ExpandingPanelClassic.spec.ts +514 -0
  33. package/app/components/02.molecules/expandable/expanding-panel-classic/tests/__snapshots__/ExpandingPanelClassic.spec.ts.snap +59 -0
  34. package/app/components/03.organisms/responsive-header/CONSUMER-STYLING.md +66 -0
  35. package/app/components/{responsive-header → 03.organisms/responsive-header}/NavigationItems.vue +21 -28
  36. package/app/components/{responsive-header → 03.organisms/responsive-header}/ResponsiveHeader.vue +141 -43
  37. package/app/components/03.organisms/responsive-header/stories/NavigationItems.stories.ts +80 -0
  38. package/app/components/03.organisms/responsive-header/stories/ResponsiveHeader.stories.ts +122 -0
  39. package/app/components/03.organisms/responsive-header/tests/NavigationItems.spec.ts +155 -0
  40. package/app/components/03.organisms/responsive-header/tests/ResponsiveHeader.spec.ts +319 -0
  41. package/app/components/03.organisms/responsive-header/tests/__snapshots__/NavigationItems.spec.ts.snap +34 -0
  42. package/app/components/03.organisms/responsive-header/tests/__snapshots__/ResponsiveHeader.spec.ts.snap +72 -0
  43. package/app/components/03.organisms/site-header/CONSUMER-STYLING.md +60 -0
  44. package/app/components/03.organisms/site-header/SiteHeader.vue +96 -0
  45. package/app/components/03.organisms/site-header/stories/SiteHeader.stories.ts +135 -0
  46. package/app/components/03.organisms/site-header/tests/SiteHeader.spec.ts +103 -0
  47. package/app/components/03.organisms/site-header/tests/__snapshots__/SiteHeader.spec.ts.snap +15 -0
  48. package/app/components/05.forms/input-select/CONSUMER-STYLING.md +42 -0
  49. package/app/components/05.forms/input-select/InputSelectCore.vue +21 -9
  50. package/app/components/05.forms/input-text/CONSUMER-STYLING.md +60 -0
  51. package/app/components/05.forms/input-text/InputTextCore.vue +17 -8
  52. package/app/layouts/default.vue +64 -67
  53. package/package.json +4 -1
@@ -17,17 +17,15 @@
17
17
  </slot>
18
18
  </div>
19
19
  </summary>
20
- </details>
21
- <div
22
- :id="`id-${name}-content`"
23
- class="expanding-panel-content"
24
- :aria-labelledby="`id-${name}-trigger`"
25
- role="region"
26
- >
27
- <div class="inner">
20
+ <div
21
+ :id="`id-${name}-content`"
22
+ class="expanding-panel-content"
23
+ :aria-labelledby="`id-${name}-trigger`"
24
+ role="region"
25
+ >
28
26
  <slot name="content"></slot>
29
27
  </div>
30
- </div>
28
+ </details>
31
29
  </div>
32
30
  </template>
33
31
 
@@ -58,10 +56,6 @@ const open = computed(() => props.forceOpened || isPanelOpen.value);
58
56
 
59
57
  const { elementClasses } = useStyleClassPassthrough(props.styleClassPassthrough);
60
58
 
61
- // contentIsOnTop panels behave like a dropdown/overlay (e.g. ContentDocs' mobile nav) rather
62
- // than an inline accordion — clicking outside is the expected way to dismiss those, matching
63
- // native <select>/menu behaviour. Not wanted for ordinary accordions (forceOpened is always
64
- // false here too — a forceOpened panel isn't meant to be dismissible by any interaction).
65
59
  const rootEl = ref<HTMLElement | null>(null);
66
60
  onClickOutside(rootEl, () => {
67
61
  if (props.contentIsOnTop && !props.forceOpened && isPanelOpen.value) {
@@ -94,9 +88,6 @@ const handleToggle = (event: Event) => {
94
88
  };
95
89
 
96
90
  const onDetailsToggle = (event: Event) => {
97
- // forceOpened drives the native `open` attribute directly, which fires its own
98
- // 'toggle' event — ignore it here or it leaks into isPanelOpen and gets stuck
99
- // once forceOpened later reverts to false.
100
91
  if (props.forceOpened) return;
101
92
  isPanelOpen.value = (event.target as HTMLDetailsElement).open;
102
93
  };
@@ -129,16 +120,20 @@ const onDetailsToggle = (event: Event) => {
129
120
  .label-wrapper {
130
121
  display: inline-block;
131
122
  }
123
+ /* inline-size is reserved explicitly — the grid's align-items:center
124
+ doesn't stretch this item to row height, so with only aspect-ratio:1
125
+ and no content yet (icon SVG not loaded), the wrapper has nothing to
126
+ size itself against and collapses to 0 until the icon arrives, then
127
+ pops in and shifts the "auto" grid column's width. */
132
128
  .icon-wrapper {
133
129
  display: flex;
134
130
  align-items: center;
135
131
  justify-content: space-between;
136
132
 
133
+ inline-size: var(--expanding-panel-icon-size, 1.2rem);
137
134
  aspect-ratio: 1;
138
135
  overflow: hidden;
139
136
 
140
- /* Space is always reserved (not v-if'd away) so a forceOpened panel's summary
141
- row stays the same height as a toggleable sibling's — only the glyph hides. */
142
137
  &.icon-wrapper--hidden {
143
138
  visibility: hidden;
144
139
  }
@@ -161,32 +156,35 @@ const onDetailsToggle = (event: Event) => {
161
156
  }
162
157
  }
163
158
  }
164
- + .expanding-panel-content {
165
- grid-template-rows: 1fr;
166
- }
167
159
  }
168
- }
169
160
 
170
- .expanding-panel-content {
171
- display: grid;
172
- grid-template-rows: 0fr;
173
- transition: grid-template-rows v-bind(animationDurationStr) ease-in-out;
174
- will-change: grid-template-rows;
161
+ &::details-content {
162
+ overflow: clip;
163
+ height: 0;
164
+ transition:
165
+ height v-bind(animationDurationStr) ease-in-out,
166
+ content-visibility v-bind(animationDurationStr) ease-in-out allow-discrete;
167
+ }
175
168
 
176
- .inner {
177
- overflow: hidden;
178
- margin-top: 0;
169
+ @supports (interpolate-size: allow-keywords) {
170
+ interpolate-size: allow-keywords;
171
+
172
+ &[open]::details-content {
173
+ height: auto;
174
+ }
179
175
  }
180
176
  }
181
177
 
182
178
  &.content-is-on-top {
183
- position: relative;
184
-
185
- .expanding-panel-content {
186
- position: absolute;
187
- top: calc(100% + var(--expanding-panel-content-gap, 0px));
188
- inset-inline: 0;
189
- z-index: var(--expanding-panel-content-z-index, 10);
179
+ .expanding-panel-details {
180
+ position: relative;
181
+
182
+ &::details-content {
183
+ position: absolute;
184
+ top: calc(100% + var(--expanding-panel-content-gap, 0px));
185
+ inset-inline: 0;
186
+ z-index: var(--expanding-panel-content-z-index, 10);
187
+ }
190
188
  }
191
189
  }
192
190
  }
@@ -242,12 +242,11 @@ export const ContentIsOnTop: Story = {
242
242
  </template>
243
243
  <template #content>
244
244
  <!--
245
- The background/border/shadow live on this wrapper never on .inner
246
- itself. .inner has no explicit height when collapsed (grid-template-rows: 0fr)
247
- and relies on overflow:hidden to clip its children to 0px; but padding/border/
248
- background set directly on .inner are part of ITS OWN box, not overflow content,
249
- so they'd still render as a visible gap under the summary while closed. Styling
250
- a wrapper *inside* the slot keeps it clipped correctly by .inner's overflow:hidden.
245
+ Background/border/shadow can go directly on .expanding-panel-content (or, as
246
+ here, a wrapper inside the slot either works). ::details-content (the native
247
+ anonymous box wrapping this content) is what clips to 0 height when collapsed,
248
+ via overflow:clip on the parent so this element's own box, including padding
249
+ and background, is clipped correctly regardless of where the styling lives.
251
250
  -->
252
251
  <div style="color: #808080; background-color:#fff;border:1px solid #ddd;border-radius:0.4rem;padding:1rem;box-shadow:0 4px 12px rgb(0 0 0 / 15%)">
253
252
  <p style="margin:0">
@@ -7,10 +7,8 @@ exports[`ExpandingPanel > renders correct HTML structure with all props set 1`]
7
7
  <div class="label-wrapper"></div>
8
8
  <div class="icon-wrapper icon-wrapper--hidden"><span class="iconify i-bi:caret-down-fill icon mi-12" aria-hidden="true"></span></div>
9
9
  </summary>
10
+ <div id="id-snap-all-content" class="expanding-panel-content" aria-labelledby="id-snap-all-trigger" role="region"></div>
10
11
  </details>
11
- <div id="id-snap-all-content" class="expanding-panel-content" aria-labelledby="id-snap-all-trigger" role="region">
12
- <div class="inner"></div>
13
- </div>
14
12
  </div>"
15
13
  `;
16
14
 
@@ -21,10 +19,8 @@ exports[`ExpandingPanel > renders correct HTML structure with contentIsOnTop tru
21
19
  <div class="label-wrapper"></div>
22
20
  <div class="icon-wrapper"><span class="iconify i-bi:caret-down-fill icon mi-12" aria-hidden="true"></span></div>
23
21
  </summary>
22
+ <div id="id-snap-content-on-top-content" class="expanding-panel-content" aria-labelledby="id-snap-content-on-top-trigger" role="region"></div>
24
23
  </details>
25
- <div id="id-snap-content-on-top-content" class="expanding-panel-content" aria-labelledby="id-snap-content-on-top-trigger" role="region">
26
- <div class="inner"></div>
27
- </div>
28
24
  </div>"
29
25
  `;
30
26
 
@@ -35,10 +31,8 @@ exports[`ExpandingPanel > renders correct HTML structure with default props 1`]
35
31
  <div class="label-wrapper"></div>
36
32
  <div class="icon-wrapper"><span class="iconify i-bi:caret-down-fill icon mi-12" aria-hidden="true"></span></div>
37
33
  </summary>
34
+ <div id="id-snap-default-content" class="expanding-panel-content" aria-labelledby="id-snap-default-trigger" role="region"></div>
38
35
  </details>
39
- <div id="id-snap-default-content" class="expanding-panel-content" aria-labelledby="id-snap-default-trigger" role="region">
40
- <div class="inner"></div>
41
- </div>
42
36
  </div>"
43
37
  `;
44
38
 
@@ -49,11 +43,9 @@ exports[`ExpandingPanel > renders correct HTML structure with populated slots 1`
49
43
  <div class="label-wrapper"><span>Summary text</span></div>
50
44
  <div class="icon-wrapper"><span>▸</span></div>
51
45
  </summary>
52
- </details>
53
- <div id="id-snap-slots-content" class="expanding-panel-content" aria-labelledby="id-snap-slots-trigger" role="region">
54
- <div class="inner">
46
+ <div id="id-snap-slots-content" class="expanding-panel-content" aria-labelledby="id-snap-slots-trigger" role="region">
55
47
  <p>Content text</p>
56
48
  </div>
57
- </div>
49
+ </details>
58
50
  </div>"
59
51
  `;
@@ -0,0 +1,103 @@
1
+ # ExpandingPanelClassic — Consumer Styling Guide
2
+
3
+ ## Public token API
4
+
5
+ All `--expanding-panel-classic-*` tokens are the stable override surface. Set them at any scope
6
+ (global, page, or instance) without touching the component itself.
7
+
8
+ | Token | Default | Controls |
9
+ |---|---|---|
10
+ | `--expanding-panel-classic-summary-gap` | `1rem` | Gap between the summary label and the toggle icon |
11
+ | `--expanding-panel-classic-summary-padding-block` | `0.5rem` | Vertical padding on the clickable summary row |
12
+ | `--expanding-panel-classic-icon-size` | `1.2rem` | Toggle icon `font-size` |
13
+ | `--expanding-panel-classic-content-z-index` | `10` | Stacking order of the content region when `contentIsOnTop` is `true` |
14
+ | `--expanding-panel-classic-content-gap` | `0px` | Space between the summary and the content region when `contentIsOnTop` is `true` |
15
+
16
+ Note: `background-color`, `padding`, and shadow are **not** tokenised, and must never be applied
17
+ to `.inner` itself — see [expanding-panel-classic.md](../../../../.claude/skills/components/expanding-panel-classic.md#styling-the-content-when-contentisontop)
18
+ for why, and style a wrapper *inside* the `#content` slot instead.
19
+
20
+ ---
21
+
22
+ ## Global theming — recommended approach
23
+
24
+ Create `assets/styles/setup/07.components/expanding-panel-classic.css` in the consuming app and set
25
+ tokens on `:root`. This applies to every `ExpandingPanelClassic` across the site.
26
+
27
+ ```css
28
+ /* assets/styles/setup/07.components/expanding-panel-classic.css */
29
+ :root {
30
+ --expanding-panel-classic-summary-gap: 1.6rem;
31
+ --expanding-panel-classic-summary-padding-block: 1.2rem;
32
+ --expanding-panel-classic-icon-size: 1.4rem;
33
+ }
34
+ ```
35
+
36
+ ---
37
+
38
+ ## Page-scoped overrides
39
+
40
+ Override tokens for a specific section by scoping them under the page or layout wrapper.
41
+ No `:deep()` is required (component styles are unscoped).
42
+
43
+ ```css
44
+ /* In the consuming page's unscoped <style> block */
45
+ .faq-section {
46
+ .expanding-panel-classic {
47
+ --expanding-panel-classic-summary-padding-block: 1.6rem;
48
+ }
49
+ }
50
+ ```
51
+
52
+ ---
53
+
54
+ ## Per-instance overrides via styleClassPassthrough
55
+
56
+ Use sparingly — prefer global or page-scoped CSS. When a single instance needs a distinct
57
+ visual style, pass a modifier class:
58
+
59
+ ```vue
60
+ <ExpandingPanelClassic
61
+ name="promo"
62
+ :content-is-on-top="true"
63
+ :style-class-passthrough="['promo-panel']"
64
+ >
65
+ <template #summary>...</template>
66
+ <template #content>
67
+ <!-- Wrapper INSIDE the slot carries the visual styling — never .inner itself -->
68
+ <div class="promo-panel-body">...</div>
69
+ </template>
70
+ </ExpandingPanelClassic>
71
+ ```
72
+
73
+ ```css
74
+ .expanding-panel-classic.promo-panel {
75
+ --expanding-panel-classic-content-gap: 0.4rem;
76
+ --expanding-panel-classic-content-z-index: 20;
77
+ }
78
+
79
+ .promo-panel-body {
80
+ background-color: white;
81
+ padding: 1rem;
82
+ box-shadow: 0 4px 12px rgb(0 0 0 / 15%);
83
+ }
84
+ ```
85
+
86
+ ---
87
+
88
+ ## Notes
89
+
90
+ - `--expanding-panel-classic-content-gap` and `--expanding-panel-classic-content-z-index` only take effect when
91
+ `contentIsOnTop` is `true` — they're no-ops for the default (in-flow) layout.
92
+ - Never set `background-color`, `padding`, `border`, or a shadow directly on `.inner`. `.inner`
93
+ has no explicit height when collapsed (`grid-template-rows: 0fr`) and relies on
94
+ `overflow: hidden` to clip its *children* to 0px — but padding/border/background on `.inner`'s
95
+ own box are not "overflow content", so they'd still render as a visible gap under the summary
96
+ while closed. Always style a wrapper element placed *inside* the `#content` slot instead; that
97
+ wrapper is a child of `.inner` and gets clipped correctly.
98
+ - Don't stack multiple `contentIsOnTop` panels as direct siblings (linked via a shared `name` or
99
+ not). The overlay is absolutely positioned so it doesn't push the next element down — which
100
+ means a sibling `ExpandingPanelClassic` placed right after it sits exactly where the overlay renders,
101
+ and gets visually covered when the first panel opens. `contentIsOnTop` is for a single panel
102
+ overlaying unrelated trailing page content, not for grouped/stacked accordion panels — use the
103
+ default in-flow layout for those.
@@ -0,0 +1,191 @@
1
+ <template>
2
+ <div ref="rootEl" class="expanding-panel-classic" :class="[elementClasses, { 'content-is-on-top': contentIsOnTop }]">
3
+ <details class="expanding-panel-classic-details" :name :open @toggle="onDetailsToggle">
4
+ <summary
5
+ :id="`id-${name}-trigger`"
6
+ class="expanding-panel-classic-summary"
7
+ :aria-controls="`id-${name}-content`"
8
+ :aria-expanded="open"
9
+ @click.prevent.stop="handleToggle"
10
+ >
11
+ <div class="label-wrapper">
12
+ <slot name="summary"></slot>
13
+ </div>
14
+ <div class="icon-wrapper" :class="{ 'icon-wrapper--hidden': forceOpened }">
15
+ <slot name="icon">
16
+ <Icon name="bi:caret-down-fill" class="icon mi-12" />
17
+ </slot>
18
+ </div>
19
+ </summary>
20
+ </details>
21
+ <div
22
+ :id="`id-${name}-content`"
23
+ class="expanding-panel-classic-content"
24
+ :aria-labelledby="`id-${name}-trigger`"
25
+ role="region"
26
+ >
27
+ <div class="inner">
28
+ <slot name="content"></slot>
29
+ </div>
30
+ </div>
31
+ </div>
32
+ </template>
33
+
34
+ <script setup lang="ts">
35
+ import { onClickOutside } from "@vueuse/core";
36
+
37
+ interface Props {
38
+ name?: string;
39
+ animationDuration?: number;
40
+ forceOpened?: boolean;
41
+ contentIsOnTop?: boolean;
42
+ styleClassPassthrough?: string | string[];
43
+ }
44
+
45
+ const props = withDefaults(defineProps<Props>(), {
46
+ name: undefined,
47
+ animationDuration: 400,
48
+ forceOpened: false,
49
+ contentIsOnTop: false,
50
+ styleClassPassthrough: () => [],
51
+ });
52
+
53
+ const fallbackName = useId();
54
+ const name = computed(() => props.name || fallbackName);
55
+ const isPanelOpen = defineModel<boolean>({ default: false });
56
+ const animationDurationStr = computed(() => `${props.animationDuration}ms`);
57
+ const open = computed(() => props.forceOpened || isPanelOpen.value);
58
+
59
+ const { elementClasses } = useStyleClassPassthrough(props.styleClassPassthrough);
60
+
61
+ const rootEl = ref<HTMLElement | null>(null);
62
+ onClickOutside(rootEl, () => {
63
+ if (props.contentIsOnTop && !props.forceOpened && isPanelOpen.value) {
64
+ isPanelOpen.value = false;
65
+ }
66
+ });
67
+
68
+ if (import.meta.dev) {
69
+ watch(
70
+ () => props.contentIsOnTop,
71
+ (value) => {
72
+ if (!value) return;
73
+ console.warn(
74
+ `ExpandingPanelClassic${props.name ? ` "${props.name}"` : ""}: contentIsOnTop is enabled. ` +
75
+ "The content overlay is absolutely positioned and does not reserve space, so a sibling " +
76
+ "element (e.g. another ExpandingPanelClassic) placed directly after this one will be visually " +
77
+ "covered when this panel opens. Intended for a single panel overlaying unrelated trailing " +
78
+ "page content — avoid stacking multiple contentIsOnTop panels as direct siblings."
79
+ );
80
+ },
81
+ { immediate: true }
82
+ );
83
+ }
84
+
85
+ const handleToggle = (event: Event) => {
86
+ if (props.forceOpened) {
87
+ event.preventDefault();
88
+ }
89
+ isPanelOpen.value = !isPanelOpen.value;
90
+ };
91
+
92
+ const onDetailsToggle = (event: Event) => {
93
+ if (props.forceOpened) return;
94
+ isPanelOpen.value = (event.target as HTMLDetailsElement).open;
95
+ };
96
+ </script>
97
+
98
+ <style lang="css">
99
+ @layer components {
100
+ .expanding-panel-classic {
101
+ .expanding-panel-classic-details {
102
+ &:hover {
103
+ cursor: pointer;
104
+ }
105
+ .expanding-panel-classic-summary {
106
+ display: grid;
107
+ align-items: center;
108
+ grid-template-columns: 1fr auto;
109
+ gap: var(--expanding-panel-classic-summary-gap, 1rem);
110
+ list-style: none;
111
+ user-select: none;
112
+
113
+ padding-block: var(--expanding-panel-classic-summary-padding-block, 0.5rem);
114
+
115
+ &::-webkit-details-marker,
116
+ &::marker {
117
+ display: none;
118
+ }
119
+
120
+ overflow: hidden;
121
+
122
+ .label-wrapper {
123
+ display: inline-block;
124
+ }
125
+ /* inline-size is reserved explicitly — the grid's align-items:center
126
+ doesn't stretch this item to row height, so with only aspect-ratio:1
127
+ and no content yet (icon SVG not loaded), the wrapper has nothing to
128
+ size itself against and collapses to 0 until the icon arrives, then
129
+ pops in and shifts the "auto" grid column's width. */
130
+ .icon-wrapper {
131
+ display: flex;
132
+ align-items: center;
133
+ justify-content: space-between;
134
+
135
+ inline-size: var(--expanding-panel-classic-icon-size, 1.2rem);
136
+ aspect-ratio: 1;
137
+ overflow: hidden;
138
+
139
+ &.icon-wrapper--hidden {
140
+ visibility: hidden;
141
+ }
142
+
143
+ .icon {
144
+ display: block;
145
+ transform: scaleY(1);
146
+ transition: transform v-bind(animationDurationStr) ease-in-out;
147
+ font-size: var(--expanding-panel-classic-icon-size, 1.2rem);
148
+ will-change: transform;
149
+ }
150
+ }
151
+ }
152
+
153
+ &[open] {
154
+ .expanding-panel-classic-summary {
155
+ .icon-wrapper {
156
+ .icon {
157
+ transform: scaleY(-1);
158
+ }
159
+ }
160
+ }
161
+ + .expanding-panel-classic-content {
162
+ grid-template-rows: 1fr;
163
+ }
164
+ }
165
+ }
166
+
167
+ .expanding-panel-classic-content {
168
+ display: grid;
169
+ grid-template-rows: 0fr;
170
+ transition: grid-template-rows v-bind(animationDurationStr) ease-in-out;
171
+ will-change: grid-template-rows;
172
+
173
+ .inner {
174
+ overflow: hidden;
175
+ margin-top: 0;
176
+ }
177
+ }
178
+
179
+ &.content-is-on-top {
180
+ position: relative;
181
+
182
+ .expanding-panel-classic-content {
183
+ position: absolute;
184
+ top: calc(100% + var(--expanding-panel-classic-content-gap, 0px));
185
+ inset-inline: 0;
186
+ z-index: var(--expanding-panel-classic-content-z-index, 10);
187
+ }
188
+ }
189
+ }
190
+ }
191
+ </style>