@progressive-development/pd-page 1.0.4 → 1.0.5

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 (65) hide show
  1. package/dist/index.d.ts +1 -1
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/pd-footer/PdFooter.d.ts +48 -22
  4. package/dist/pd-footer/PdFooter.d.ts.map +1 -1
  5. package/dist/pd-footer/PdFooter.js +473 -71
  6. package/dist/pd-icon-brand/dist/brand-icon-map.js +88 -0
  7. package/dist/pd-icon-brand/dist/icons/apple-music.js +9 -0
  8. package/dist/pd-icon-brand/dist/icons/bandcamp.js +9 -0
  9. package/dist/pd-icon-brand/dist/icons/beatport.js +9 -0
  10. package/dist/pd-icon-brand/dist/icons/behance.js +9 -0
  11. package/dist/pd-icon-brand/dist/icons/bluesky.js +9 -0
  12. package/dist/pd-icon-brand/dist/icons/deezer.js +9 -0
  13. package/dist/pd-icon-brand/dist/icons/default-brand.js +9 -0
  14. package/dist/pd-icon-brand/dist/icons/discogs.js +9 -0
  15. package/dist/pd-icon-brand/dist/icons/discord.js +9 -0
  16. package/dist/pd-icon-brand/dist/icons/dribbble.js +9 -0
  17. package/dist/pd-icon-brand/dist/icons/facebook.js +9 -0
  18. package/dist/pd-icon-brand/dist/icons/github.js +9 -0
  19. package/dist/pd-icon-brand/dist/icons/instagram.js +9 -0
  20. package/dist/pd-icon-brand/dist/icons/linkedin.js +9 -0
  21. package/dist/pd-icon-brand/dist/icons/mastodon.js +9 -0
  22. package/dist/pd-icon-brand/dist/icons/medium.js +9 -0
  23. package/dist/pd-icon-brand/dist/icons/mixcloud.js +9 -0
  24. package/dist/pd-icon-brand/dist/icons/patreon.js +9 -0
  25. package/dist/pd-icon-brand/dist/icons/pinterest.js +9 -0
  26. package/dist/pd-icon-brand/dist/icons/reddit.js +9 -0
  27. package/dist/pd-icon-brand/dist/icons/snapchat.js +9 -0
  28. package/dist/pd-icon-brand/dist/icons/soundcloud.js +9 -0
  29. package/dist/pd-icon-brand/dist/icons/spotify.js +9 -0
  30. package/dist/pd-icon-brand/dist/icons/stackoverflow.js +9 -0
  31. package/dist/pd-icon-brand/dist/icons/telegram.js +9 -0
  32. package/dist/pd-icon-brand/dist/icons/threads.js +9 -0
  33. package/dist/pd-icon-brand/dist/icons/tiktok.js +9 -0
  34. package/dist/pd-icon-brand/dist/icons/twitch.js +9 -0
  35. package/dist/pd-icon-brand/dist/icons/vimeo.js +9 -0
  36. package/dist/pd-icon-brand/dist/icons/whatsapp.js +9 -0
  37. package/dist/pd-icon-brand/dist/icons/x-twitter.js +9 -0
  38. package/dist/pd-icon-brand/dist/icons/xing.js +9 -0
  39. package/dist/pd-icon-brand/dist/icons/youtube.js +9 -0
  40. package/dist/pd-menu/PdMenu.d.ts +7 -1
  41. package/dist/pd-menu/PdMenu.d.ts.map +1 -1
  42. package/dist/pd-menu/PdMenu.js +40 -3
  43. package/dist/pd-socialmedia/PdSocialmedia.d.ts +1 -0
  44. package/dist/pd-socialmedia/PdSocialmedia.d.ts.map +1 -1
  45. package/dist/pd-socialmedia/PdSocialmedia.js +24 -4
  46. package/dist/pd-socialmedia/pd-socialmedia-model.d.ts +1 -1
  47. package/dist/pd-socialmedia/pd-socialmedia-model.d.ts.map +1 -1
  48. package/dist/pd-socialmedia/pd-socialmedia-model.js +224 -0
  49. package/dist/types.d.ts +8 -0
  50. package/dist/types.d.ts.map +1 -1
  51. package/package.json +4 -4
  52. package/dist/pd-contact-us/pd-contact-us.stories.d.ts +0 -37
  53. package/dist/pd-contact-us/pd-contact-us.stories.d.ts.map +0 -1
  54. package/dist/pd-footer/pd-footer.stories.d.ts +0 -48
  55. package/dist/pd-footer/pd-footer.stories.d.ts.map +0 -1
  56. package/dist/pd-login/pd-login.stories.d.ts +0 -55
  57. package/dist/pd-login/pd-login.stories.d.ts.map +0 -1
  58. package/dist/pd-menu/pd-menu.stories.d.ts +0 -62
  59. package/dist/pd-menu/pd-menu.stories.d.ts.map +0 -1
  60. package/dist/pd-socialmedia/pd-socialmedia.stories.d.ts +0 -53
  61. package/dist/pd-socialmedia/pd-socialmedia.stories.d.ts.map +0 -1
  62. package/dist/pd-toast/pd-toast.stories.d.ts +0 -47
  63. package/dist/pd-toast/pd-toast.stories.d.ts.map +0 -1
  64. package/dist/stories/01_index.stories.d.ts +0 -37
  65. package/dist/stories/01_index.stories.d.ts.map +0 -1
@@ -1,6 +1,10 @@
1
- import { css, LitElement, nothing, html } from 'lit';
2
- import { property } from 'lit/decorators.js';
1
+ import { css, LitElement, html, nothing } from 'lit';
2
+ import { property, state } from 'lit/decorators.js';
3
+ import { classMap } from 'lit/directives/class-map.js';
3
4
  import { localized, msg } from '@lit/localize';
5
+ import { SOCIAL_PROVIDERS } from '../pd-socialmedia/pd-socialmedia-model.js';
6
+ import { pdIcons } from '@progressive-development/pd-icon';
7
+ import '@progressive-development/pd-icon/pd-icon';
4
8
 
5
9
  var __defProp = Object.defineProperty;
6
10
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -15,39 +19,187 @@ var __decorateClass = (decorators, target, key, kind) => {
15
19
  let PdFooter = class extends LitElement {
16
20
  constructor() {
17
21
  super(...arguments);
22
+ this.sections = [];
23
+ this.socialLinks = [];
24
+ this.legalLinks = [];
18
25
  this.copyright = "";
19
26
  this.version = "";
20
- this.footerLinks = [];
27
+ this.showVersion = false;
28
+ this._isMobile = false;
29
+ this._openSections = /* @__PURE__ */ new Set();
30
+ this._boundMediaQueryHandler = this._handleMediaQuery.bind(this);
31
+ }
32
+ connectedCallback() {
33
+ super.connectedCallback();
34
+ this._mediaQueryList = window.matchMedia("(max-width: 767px)");
35
+ this._mediaQueryList.addEventListener(
36
+ "change",
37
+ this._boundMediaQueryHandler
38
+ );
39
+ this._isMobile = this._mediaQueryList.matches;
40
+ }
41
+ disconnectedCallback() {
42
+ super.disconnectedCallback();
43
+ this._mediaQueryList?.removeEventListener(
44
+ "change",
45
+ this._boundMediaQueryHandler
46
+ );
21
47
  }
22
48
  render() {
49
+ const hasBrand = this.querySelector("[slot=logo]") || this.querySelector("[slot=extra]");
50
+ return html`
51
+ <footer>
52
+ <div class="footer-main ${classMap({ "no-brand": !hasBrand })}">
53
+ <div class="footer-brand">
54
+ <slot name="logo"></slot>
55
+ <slot name="extra"></slot>
56
+ </div>
57
+
58
+ ${this._renderSections()} ${this._renderSocialLinks()}
59
+ </div>
60
+
61
+ <hr class="footer-divider" aria-hidden="true" />
62
+
63
+ ${this._renderBottomBar()}
64
+ </footer>
65
+ `;
66
+ }
67
+ /* ── Section rendering ── */
68
+ _renderSections() {
69
+ if (this.sections.length === 0) return nothing;
23
70
  return html`
24
71
  <nav
25
- class="footer-links"
72
+ class="footer-sections ${classMap({ mobile: this._isMobile })}"
26
73
  aria-label="${msg("Footer Navigation", { id: "pd.footer.nav.aria" })}"
27
74
  >
28
- <ul role="list">
29
- ${this.footerLinks?.map(
30
- (link) => html`
31
- <li
32
- role="button"
33
- tabindex="0"
34
- data-link="${link.key}"
35
- @click="${this._footerLinkClicked}"
36
- @keydown="${this._handleLinkKeydown}"
37
- >
38
- ${link.name}
39
- </li>
40
- `
75
+ ${this._isMobile ? this.sections.map((section, i) => this._renderAccordion(section, i)) : this.sections.map(
76
+ (section) => html`
77
+ <div class="footer-section">
78
+ <h3 class="section-heading">${section.heading}</h3>
79
+ <ul class="section-links" role="list">
80
+ ${section.links.map(
81
+ (link) => html`
82
+ <li
83
+ role="button"
84
+ tabindex="0"
85
+ data-link="${link.key}"
86
+ @click="${this._footerLinkClicked}"
87
+ @keydown="${this._handleLinkKeydown}"
88
+ >
89
+ ${link.name}
90
+ </li>
91
+ `
92
+ )}
93
+ </ul>
94
+ </div>
95
+ `
41
96
  )}
42
- </ul>
43
97
  </nav>
44
-
45
- <div class="bottom-line">
46
- <div>
47
- ${this.copyright ? html`<span class="copyright">© ${this.copyright}, </span>` : nothing}
48
- ${this.version ? html`<span class="version">${this.version}</span>` : nothing}
98
+ `;
99
+ }
100
+ _renderAccordion(section, index) {
101
+ const isOpen = this._openSections.has(index);
102
+ return html`
103
+ <div class="footer-section-mobile">
104
+ <div
105
+ class="section-trigger"
106
+ role="button"
107
+ tabindex="0"
108
+ aria-expanded="${isOpen}"
109
+ @click="${() => this._toggleSection(index)}"
110
+ @keydown="${(e) => this._handleSectionKeydown(e, index)}"
111
+ >
112
+ <span class="section-heading">${section.heading}</span>
113
+ <pd-icon
114
+ icon="${pdIcons.ICON_TOGGLE_COLLAPSE}"
115
+ ?activeIcon="${isOpen}"
116
+ aria-hidden="true"
117
+ ></pd-icon>
118
+ </div>
119
+ <div class="section-content ${classMap({ open: isOpen })}">
120
+ <div class="section-content-inner">
121
+ <ul class="section-links" role="list">
122
+ ${section.links.map(
123
+ (link) => html`
124
+ <li
125
+ role="button"
126
+ tabindex="${isOpen ? "0" : "-1"}"
127
+ data-link="${link.key}"
128
+ @click="${this._footerLinkClicked}"
129
+ @keydown="${this._handleLinkKeydown}"
130
+ >
131
+ ${link.name}
132
+ </li>
133
+ `
134
+ )}
135
+ </ul>
136
+ </div>
137
+ </div>
138
+ </div>
139
+ `;
140
+ }
141
+ /* ── Social links ── */
142
+ _renderSocialLinks() {
143
+ if (this.socialLinks.length === 0) return nothing;
144
+ return html`
145
+ <div
146
+ class="footer-social"
147
+ role="list"
148
+ aria-label="${msg("Social Media", { id: "pd.footer.social.aria" })}"
149
+ >
150
+ ${this.socialLinks.map((entry) => {
151
+ const provider = this._findProvider(entry.providerId);
152
+ const url = this._toSocialUrl(provider, entry.value);
153
+ const label = entry.label || provider?.label || entry.providerId;
154
+ return html`
155
+ <a
156
+ role="listitem"
157
+ href="${url || "#"}"
158
+ target="_blank"
159
+ rel="noopener noreferrer"
160
+ aria-label="${label}"
161
+ class="social-link"
162
+ title="${label}"
163
+ >${provider?.icon ?? "🔗"}</a
164
+ >
165
+ `;
166
+ })}
167
+ </div>
168
+ `;
169
+ }
170
+ /* ── Bottom bar ── */
171
+ _renderBottomBar() {
172
+ return html`
173
+ <div class="bottom-bar">
174
+ <div class="bottom-bar-left">
175
+ ${this.copyright ? html`<span class="copyright">&copy; ${this.copyright}</span>` : nothing}
176
+ ${this.showVersion && this.version ? html`<span class="version">${this.version}</span>` : nothing}
49
177
  </div>
50
178
 
179
+ ${this.legalLinks.length > 0 ? html`
180
+ <nav
181
+ class="bottom-bar-links"
182
+ aria-label="${msg("Legal Navigation", {
183
+ id: "pd.footer.legal.aria"
184
+ })}"
185
+ >
186
+ <ul role="list">
187
+ ${this.legalLinks.map(
188
+ (link) => html`
189
+ <li
190
+ role="button"
191
+ tabindex="0"
192
+ data-link="${link.key}"
193
+ @click="${this._footerLinkClicked}"
194
+ @keydown="${this._handleLinkKeydown}"
195
+ >
196
+ ${link.name}
197
+ </li>
198
+ `
199
+ )}
200
+ </ul>
201
+ </nav>
202
+ ` : nothing}
51
203
  ${this.madeBy ? html`<span
52
204
  class="made-by"
53
205
  role="button"
@@ -59,24 +211,44 @@ let PdFooter = class extends LitElement {
59
211
  </div>
60
212
  `;
61
213
  }
62
- /**
63
- * Handles keyboard events on footer links.
64
- * Activates on Enter or Space key.
65
- */
214
+ /* ── Event handlers ── */
215
+ _footerLinkClicked(e) {
216
+ const target = e.currentTarget;
217
+ const linkKey = target.dataset.link;
218
+ const allLinks = [
219
+ ...this.sections.flatMap((s) => s.links),
220
+ ...this.legalLinks
221
+ ];
222
+ const linkObj = allLinks.find((fl) => fl.key === linkKey);
223
+ if (linkObj) {
224
+ this.dispatchEvent(
225
+ new CustomEvent("footer-link", {
226
+ detail: { linkObj },
227
+ bubbles: true,
228
+ composed: true
229
+ })
230
+ );
231
+ }
232
+ }
66
233
  _handleLinkKeydown(e) {
67
234
  if (e.key === "Enter" || e.key === " ") {
68
235
  e.preventDefault();
69
236
  this._footerLinkClicked(e);
70
237
  }
71
238
  }
72
- /**
73
- * Handles keyboard events on madeBy element.
74
- * Activates on Enter or Space key.
75
- */
76
- _handleMadeByKeydown(e) {
239
+ _toggleSection(index) {
240
+ const next = new Set(this._openSections);
241
+ if (next.has(index)) {
242
+ next.delete(index);
243
+ } else {
244
+ next.add(index);
245
+ }
246
+ this._openSections = next;
247
+ }
248
+ _handleSectionKeydown(e, index) {
77
249
  if (e.key === "Enter" || e.key === " ") {
78
250
  e.preventDefault();
79
- this._clickMadeBy();
251
+ this._toggleSection(index);
80
252
  }
81
253
  }
82
254
  _clickMadeBy() {
@@ -89,76 +261,229 @@ let PdFooter = class extends LitElement {
89
261
  }
90
262
  }
91
263
  }
92
- _footerLinkClicked(e) {
93
- const target = e.currentTarget;
94
- const linkKey = target.dataset.link;
95
- const linkObj = this.footerLinks?.find((fl) => fl.key === linkKey);
96
- if (linkObj) {
97
- this.dispatchEvent(
98
- new CustomEvent("footer-link", {
99
- detail: { linkObj },
100
- bubbles: true,
101
- composed: true
102
- })
103
- );
264
+ _handleMadeByKeydown(e) {
265
+ if (e.key === "Enter" || e.key === " ") {
266
+ e.preventDefault();
267
+ this._clickMadeBy();
104
268
  }
105
269
  }
270
+ /* ── Helpers ── */
271
+ _handleMediaQuery(e) {
272
+ this._isMobile = e.matches;
273
+ }
274
+ _findProvider(id) {
275
+ return SOCIAL_PROVIDERS.find((p) => p.id === id);
276
+ }
277
+ _toSocialUrl(provider, raw) {
278
+ const v = raw?.trim();
279
+ if (!v) return null;
280
+ if (provider?.toUrl) return provider.toUrl(v);
281
+ if (/^https?:\/\//i.test(v)) return v;
282
+ return null;
283
+ }
106
284
  };
107
285
  PdFooter.styles = [
108
286
  css`
109
287
  :host {
110
288
  display: flex;
111
- flex-flow: column;
112
- justify-content: end;
289
+ flex-direction: column;
113
290
  background-color: var(--pd-footer-bg-col, var(--pd-default-col));
114
- width: 100%;
115
- white-space: nowrap;
116
- }
117
-
118
- .footer-links {
119
- display: flex;
120
- align-items: center;
121
- justify-content: right;
122
- height: 100%;
123
291
  color: var(--pd-footer-font-col, var(--pd-on-primary-col));
124
292
  font-family: var(
125
293
  --pd-footer-font-family,
126
294
  var(--pd-default-font-link-family)
127
295
  );
128
- font-size: var(--pd-footer-font-size, 1.1em);
296
+ font-size: var(--pd-footer-font-size, 1em);
297
+ width: 100%;
129
298
  }
130
299
 
131
- .footer-links ul {
300
+ /* ── Main content area ── */
301
+
302
+ .footer-main {
303
+ display: grid;
304
+ grid-template-areas:
305
+ "brand sections"
306
+ "social social";
307
+ grid-template-columns: auto 1fr;
308
+ row-gap: var(--pd-spacing-sm);
309
+ column-gap: var(--pd-footer-section-gap, var(--pd-spacing-lg));
310
+ max-width: var(
311
+ --pd-footer-max-width,
312
+ var(--pd-content-max-width, 1170px)
313
+ );
314
+ width: 100%;
315
+ margin: 0 auto;
316
+ padding: var(--pd-spacing-lg) var(--pd-spacing-md) var(--pd-spacing-sm);
317
+ box-sizing: border-box;
318
+ }
319
+
320
+ .footer-main.no-brand {
321
+ grid-template-areas:
322
+ "sections"
323
+ "social";
324
+ grid-template-columns: 1fr;
325
+ }
326
+
327
+ .footer-brand {
328
+ grid-area: brand;
132
329
  display: flex;
133
- flex-wrap: wrap;
330
+ flex-direction: column;
331
+ gap: var(--pd-spacing-md);
332
+ }
333
+
334
+ /* ── Sections (desktop grid) ── */
335
+
336
+ .footer-sections {
337
+ grid-area: sections;
338
+ display: grid;
339
+ grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
340
+ gap: var(--pd-footer-section-gap, var(--pd-spacing-lg));
341
+ }
342
+
343
+ .section-heading {
344
+ font-size: var(--pd-footer-heading-font-size, 1.1em);
345
+ font-weight: var(--pd-footer-heading-font-weight, bold);
346
+ margin: 0 0 var(--pd-spacing-sm) 0;
347
+ color: var(
348
+ --pd-footer-heading-font-col,
349
+ var(--pd-footer-font-col, var(--pd-on-primary-col))
350
+ );
351
+ }
352
+
353
+ .section-links {
134
354
  list-style: none;
135
- gap: var(--pd-spacing-lg);
136
355
  margin: 0;
137
- padding: var(--pd-spacing-lg);
356
+ padding: 0;
357
+ display: flex;
358
+ flex-direction: column;
359
+ gap: var(--pd-spacing-xs);
138
360
  }
139
361
 
140
- .footer-links li {
362
+ .section-links li {
141
363
  cursor: pointer;
364
+ font-size: var(--pd-footer-link-font-size, 0.95em);
365
+ padding: var(--pd-spacing-xs) 0;
366
+ opacity: 0.85;
367
+ transition:
368
+ opacity 0.15s ease,
369
+ color 0.15s ease;
370
+ }
371
+
372
+ .section-links li:hover {
373
+ color: var(--pd-footer-link-hover-col, var(--pd-default-hover-col));
374
+ opacity: 1;
375
+ }
376
+
377
+ .section-links li:focus-visible {
378
+ outline: 2px solid var(--pd-focus-ring-col, var(--pd-default-col));
379
+ outline-offset: 2px;
380
+ border-radius: var(--pd-radius-sm);
142
381
  }
143
382
 
144
- .footer-links li:hover {
145
- color: var(--pd-default-hover-col);
383
+ /* ── Mobile accordion ── */
384
+
385
+ .footer-sections.mobile {
386
+ display: flex;
387
+ flex-direction: column;
388
+ gap: 0;
146
389
  }
147
390
 
148
- .footer-links li:focus-visible {
391
+ .section-trigger {
392
+ display: flex;
393
+ justify-content: space-between;
394
+ align-items: center;
395
+ padding: var(--pd-spacing-sm) 0;
396
+ cursor: pointer;
397
+ border-bottom: 1px solid
398
+ var(--pd-footer-divider-col, rgba(255, 255, 255, 0.15));
399
+ user-select: none;
400
+ }
401
+
402
+ .section-trigger:focus-visible {
149
403
  outline: 2px solid var(--pd-focus-ring-col, var(--pd-default-col));
150
404
  outline-offset: 2px;
151
405
  border-radius: var(--pd-radius-sm);
152
406
  }
153
407
 
154
- .bottom-line {
408
+ .section-trigger pd-icon {
409
+ --pd-icon-size: 1.2rem;
410
+ --pd-icon-col: var(--pd-footer-font-col, var(--pd-on-primary-col));
411
+ transition: transform 0.25s ease;
412
+ }
413
+
414
+ .section-content {
415
+ display: grid;
416
+ grid-template-rows: 0fr;
417
+ transition: grid-template-rows 0.25s ease;
418
+ }
419
+
420
+ .section-content.open {
421
+ grid-template-rows: 1fr;
422
+ }
423
+
424
+ .section-content-inner {
425
+ overflow: hidden;
426
+ }
427
+
428
+ .section-content.open .section-content-inner {
429
+ padding-bottom: var(--pd-spacing-sm);
430
+ }
431
+
432
+ /* ── Social icons ── */
433
+
434
+ .footer-social {
435
+ grid-area: social;
436
+ display: flex;
437
+ flex-wrap: wrap;
438
+ gap: var(--pd-footer-social-gap, var(--pd-spacing-sm));
439
+ align-items: center;
440
+ }
441
+
442
+ .social-link {
443
+ display: inline-flex;
444
+ align-items: center;
445
+ justify-content: center;
446
+ width: var(--pd-footer-social-icon-size, 2.5rem);
447
+ height: var(--pd-footer-social-icon-size, 2.5rem);
448
+ font-size: calc(var(--pd-footer-social-icon-size, 2.5rem) * 0.65);
449
+ text-decoration: none;
450
+ border-radius: var(--pd-radius-md);
451
+ transition:
452
+ transform 0.2s ease,
453
+ opacity 0.2s ease;
454
+ min-width: 44px;
455
+ min-height: 44px;
456
+ }
457
+
458
+ .social-link:hover {
459
+ transform: scale(1.15);
460
+ opacity: 0.8;
461
+ }
462
+
463
+ .social-link:focus-visible {
464
+ outline: 2px solid var(--pd-focus-ring-col, var(--pd-default-col));
465
+ outline-offset: 2px;
466
+ }
467
+
468
+ /* ── Divider ── */
469
+
470
+ .footer-divider {
471
+ border: none;
472
+ border-top: 1px solid
473
+ var(--pd-footer-divider-col, rgba(255, 255, 255, 0.15));
474
+ margin: 0;
475
+ }
476
+
477
+ /* ── Bottom bar ── */
478
+
479
+ .bottom-bar {
155
480
  background-color: var(
156
481
  --pd-footer-bottom-col,
157
482
  var(--pd-default-light-col)
158
483
  );
159
484
  font-size: var(--pd-footer-bottom-font-size, 0.9em);
160
485
  color: var(--pd-footer-bottom-font-col, var(--pd-default-dark-col));
161
- padding: var(--pd-spacing-sm);
486
+ padding: var(--pd-spacing-sm) var(--pd-spacing-md);
162
487
  display: flex;
163
488
  gap: var(--pd-spacing-md);
164
489
  flex-wrap: wrap;
@@ -166,22 +491,56 @@ PdFooter.styles = [
166
491
  align-items: center;
167
492
  }
168
493
 
494
+ .bottom-bar-left {
495
+ display: flex;
496
+ gap: var(--pd-spacing-sm);
497
+ align-items: center;
498
+ flex-wrap: wrap;
499
+ }
500
+
169
501
  .copyright {
170
502
  font-weight: bold;
171
503
  }
172
504
 
173
505
  .version {
174
506
  font-weight: normal;
507
+ opacity: 0.7;
508
+ }
509
+
510
+ .bottom-bar-links ul {
511
+ display: flex;
512
+ list-style: none;
513
+ gap: var(--pd-spacing-md);
514
+ margin: 0;
515
+ padding: 0;
516
+ flex-wrap: wrap;
517
+ }
518
+
519
+ .bottom-bar-links li {
520
+ cursor: pointer;
521
+ opacity: 0.85;
522
+ }
523
+
524
+ .bottom-bar-links li:hover {
525
+ opacity: 1;
526
+ text-decoration: underline;
527
+ }
528
+
529
+ .bottom-bar-links li:focus-visible {
530
+ outline: 2px solid var(--pd-focus-ring-col, var(--pd-default-col));
531
+ outline-offset: 2px;
532
+ border-radius: var(--pd-radius-sm);
175
533
  }
176
534
 
177
535
  .made-by {
178
536
  cursor: pointer;
179
537
  font-style: italic;
180
- white-space: normal;
538
+ font-size: 0.85em;
539
+ opacity: 0.7;
181
540
  }
182
541
 
183
542
  .made-by:hover {
184
- color: var(--pd-default-col);
543
+ opacity: 1;
185
544
  }
186
545
 
187
546
  .made-by:focus-visible {
@@ -189,20 +548,63 @@ PdFooter.styles = [
189
548
  outline-offset: 2px;
190
549
  border-radius: var(--pd-radius-sm);
191
550
  }
551
+
552
+ /* ── Mobile adjustments ── */
553
+
554
+ @media (max-width: 767px) {
555
+ .footer-main {
556
+ grid-template-areas:
557
+ "brand"
558
+ "sections"
559
+ "social";
560
+ grid-template-columns: 1fr;
561
+ padding: var(--pd-spacing-md) var(--pd-spacing-sm);
562
+ }
563
+
564
+ .bottom-bar {
565
+ flex-direction: column;
566
+ align-items: flex-start;
567
+ gap: var(--pd-spacing-xs);
568
+ }
569
+ }
570
+
571
+ @media (prefers-reduced-motion: reduce) {
572
+ .section-content {
573
+ transition: none;
574
+ }
575
+ .social-link {
576
+ transition: none;
577
+ }
578
+ }
192
579
  `
193
580
  ];
581
+ __decorateClass([
582
+ property({ type: Array })
583
+ ], PdFooter.prototype, "sections", 2);
584
+ __decorateClass([
585
+ property({ type: Array })
586
+ ], PdFooter.prototype, "socialLinks", 2);
587
+ __decorateClass([
588
+ property({ type: Array })
589
+ ], PdFooter.prototype, "legalLinks", 2);
194
590
  __decorateClass([
195
591
  property({ type: String })
196
592
  ], PdFooter.prototype, "copyright", 2);
197
593
  __decorateClass([
198
594
  property({ type: String })
199
595
  ], PdFooter.prototype, "version", 2);
596
+ __decorateClass([
597
+ property({ type: Boolean, attribute: "show-version" })
598
+ ], PdFooter.prototype, "showVersion", 2);
200
599
  __decorateClass([
201
600
  property({ type: Object })
202
601
  ], PdFooter.prototype, "madeBy", 2);
203
602
  __decorateClass([
204
- property({ type: Array })
205
- ], PdFooter.prototype, "footerLinks", 2);
603
+ state()
604
+ ], PdFooter.prototype, "_isMobile", 2);
605
+ __decorateClass([
606
+ state()
607
+ ], PdFooter.prototype, "_openSections", 2);
206
608
  PdFooter = __decorateClass([
207
609
  localized()
208
610
  ], PdFooter);