@taprootio/espalier 2.3.1 → 2.5.0

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.
@@ -1,4 +1,4 @@
1
- var c=function(n,e,s,a){var r=arguments.length,t=r<3?e:a===null?a=Object.getOwnPropertyDescriptor(e,s):a,l;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")t=Reflect.decorate(n,e,s,a);else for(var i=n.length-1;i>=0;i--)(l=n[i])&&(t=(r<3?l(t):r>3?l(e,s,t):l(e,s))||t);return r>3&&t&&Object.defineProperty(e,s,t),t};import{css as h,html as m}from"lit";import{customElement as y,property as f,state as u}from"lit/decorators.js";import{classMap as g}from"lit/directives/class-map.js";import{createRef as S,ref as p}from"lit/directives/ref.js";import{EspalierElementBase as d}from"../shared/esp-element-base.js";import{SlottedIconController as v}from"../shared/slotted-icon-controller.js";let o=class extends d{constructor(){super(...arguments),this.iconSlot=new v(this),this.secondarySlot=S(),this.hasSecondary=!1,this.truncate=!1,this.handleSecondarySlotChange=()=>{this.hasSecondary=this.secondarySlot.value?.assignedNodes({flatten:!0}).some(e=>e.nodeType===Node.TEXT_NODE?(e.textContent??"").trim().length>0:!0)??!1}}firstUpdated(e){super.firstUpdated(e),this.iconSlot.handleSlotChange(),this.handleSecondarySlotChange()}render(){const e={cell:!0,"has-icon":this.iconSlot.hasAssignedSlotContent,"has-secondary":this.hasSecondary,truncate:this.truncate};return m`
1
+ var c=function(a,e,s,n){var r=arguments.length,t=r<3?e:n===null?n=Object.getOwnPropertyDescriptor(e,s):n,l;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")t=Reflect.decorate(a,e,s,n);else for(var i=a.length-1;i>=0;i--)(l=a[i])&&(t=(r<3?l(t):r>3?l(e,s,t):l(e,s))||t);return r>3&&t&&Object.defineProperty(e,s,t),t};import{css as h,html as m}from"lit";import{customElement as y,property as f,state as u}from"lit/decorators.js";import{classMap as g}from"lit/directives/class-map.js";import{createRef as S,ref as p}from"lit/directives/ref.js";import{EspalierElementBase as d}from"../shared/esp-element-base.js";import{SlottedIconController as v}from"../shared/slotted-icon-controller.js";import{slotHasContent as w}from"../shared/slot-content.js";let o=class extends d{constructor(){super(...arguments),this.iconSlot=new v(this),this.secondarySlot=S(),this.hasSecondary=!1,this.truncate=!1,this.handleSecondarySlotChange=()=>{this.hasSecondary=w(this.secondarySlot.value)}}firstUpdated(e){super.firstUpdated(e),this.iconSlot.handleSlotChange(),this.handleSecondarySlotChange()}render(){const e={cell:!0,"has-icon":this.iconSlot.hasAssignedSlotContent,"has-secondary":this.hasSecondary,truncate:this.truncate};return m`
2
2
  <span part="cell" class=${g(e)}>
3
3
  <span part="icon" class="icon">
4
4
  <slot
@@ -0,0 +1,40 @@
1
+ import { EspalierElementBase } from "../shared/esp-element-base.js";
2
+ /**
3
+ * A labelled group of related links inside [`<esp-footer>`](/components/footer/).
4
+ * Supply ordinary anchors in the default slot; the component provides the
5
+ * compact vertical rhythm and an accessible navigation landmark.
6
+ *
7
+ * ```html
8
+ * <esp-footer-link-group heading="Explore">
9
+ * <a href="/components">Components</a>
10
+ * <a href="/guides">Guides</a>
11
+ * <a href="/api">API</a>
12
+ * </esp-footer-link-group>
13
+ * ```
14
+ *
15
+ * @customElement esp-footer-link-group
16
+ * @slot - Links belonging to the group. Native anchors are preferred because
17
+ * footer links do not need application-menu disclosure or drawer behavior.
18
+ * @csspart nav - The group's navigation landmark.
19
+ * @csspart heading - The visible heading used to label the navigation landmark.
20
+ * @csspart links - The link-list container.
21
+ * @docPageTitle Footer Link Group
22
+ * @docUrl /components/footer/link-group
23
+ * @menuGroup Navigation
24
+ * @menuIcon list-details
25
+ */
26
+ export declare class EspalierFooterLinkGroup extends EspalierElementBase {
27
+ /**
28
+ * Visible heading for the link group. It also labels the navigation
29
+ * landmark. When omitted, the landmark receives the fallback label
30
+ * “Footer links” without rendering an empty heading.
31
+ */
32
+ heading: string;
33
+ protected render(): import("lit-html").TemplateResult<1>;
34
+ static styles: import("lit").CSSResult[];
35
+ }
36
+ declare global {
37
+ interface HTMLElementTagNameMap {
38
+ "esp-footer-link-group": EspalierFooterLinkGroup;
39
+ }
40
+ }
@@ -0,0 +1,57 @@
1
+ var d=function(t,o,r,n){var s=arguments.length,e=s<3?o:n===null?n=Object.getOwnPropertyDescriptor(o,r):n,l;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")e=Reflect.decorate(t,o,r,n);else for(var a=t.length-1;a>=0;a--)(l=t[a])&&(e=(s<3?l(e):s>3?l(o,r,e):l(o,r))||e);return s>3&&e&&Object.defineProperty(o,r,e),e};import{css as v,html as f,nothing as p}from"lit";import{customElement as g,property as u}from"lit/decorators.js";import{EspalierElementBase as c}from"../shared/esp-element-base.js";const h="esp-footer-link-group-heading";let i=class extends c{constructor(){super(...arguments),this.heading=""}render(){return f`
2
+ <nav
3
+ part="nav"
4
+ aria-labelledby=${this.heading?h:p}
5
+ aria-label=${this.heading?p:"Footer links"}
6
+ >
7
+ ${this.heading?f`<h2 part="heading" id=${h}>${this.heading}</h2>`:p}
8
+ <div part="links" class="links"><slot></slot></div>
9
+ </nav>
10
+ `}};i.styles=[...c.styles,v`
11
+ :host {
12
+ display: block;
13
+ min-inline-size: 0;
14
+ }
15
+
16
+ nav {
17
+ display: grid;
18
+ gap: var(--esp-footer-link-group-gap, var(--esp-size-small));
19
+ min-inline-size: 0;
20
+ color: var(--esp-footer-color, var(--esp-color-text));
21
+ }
22
+
23
+ h2 {
24
+ margin: 0;
25
+ color: var(--esp-footer-heading-color, var(--esp-color-headings));
26
+ font-family: var(--esp-font-headings);
27
+ font-size: var(--esp-type-normal);
28
+ font-weight: var(--esp-font-weight-headings);
29
+ line-height: 1.25;
30
+ }
31
+
32
+ .links {
33
+ display: grid;
34
+ gap: var(--esp-size-tiny);
35
+ min-inline-size: 0;
36
+ }
37
+
38
+ ::slotted(a) {
39
+ inline-size: fit-content;
40
+ max-inline-size: 100%;
41
+ color: var(--esp-footer-link-color, var(--esp-color-link));
42
+ overflow-wrap: anywhere;
43
+ text-decoration: none;
44
+ text-underline-offset: 0.18em;
45
+ }
46
+
47
+ ::slotted(a:hover) {
48
+ color: var(--esp-footer-link-hover-color, var(--esp-color-link-hover));
49
+ text-decoration: underline;
50
+ }
51
+
52
+ ::slotted(a:focus-visible) {
53
+ border-radius: var(--esp-size-border-radius);
54
+ outline: var(--esp-footer-focus-outline, 2px solid var(--esp-color-link));
55
+ outline-offset: 3px;
56
+ }
57
+ `],d([u({type:String})],i.prototype,"heading",void 0),i=d([g("esp-footer-link-group")],i);export{i as EspalierFooterLinkGroup};
@@ -0,0 +1,217 @@
1
+ import { type PropertyValues } from "lit";
2
+ import { EspalierElementBase } from "../shared/esp-element-base.js";
3
+ import "./esp-footer-link-group.js";
4
+ export type FooterColumns = "auto" | "1" | "2" | "3" | "4" | "5" | "6";
5
+ /**
6
+ * A responsive site footer with structured spaces for branding, feature
7
+ * artwork, link groups, supporting actions, and legal or utility content.
8
+ * Its background remains full-bleed while its content automatically aligns
9
+ * to the surface of a containing [`<esp-page>`](/components/page/).
10
+ *
11
+ * Use [`<esp-footer-link-group>`](/components/footer/link-group/) children for
12
+ * ordinary navigation columns. `columns` is a maximum: the grid always drops
13
+ * columns when they no longer fit.
14
+ *
15
+ * ```html
16
+ * <esp-footer
17
+ * light-brand-logo="/assets/logo-light.svg"
18
+ * dark-brand-logo="/assets/logo-dark.svg"
19
+ * brand-text="Espalier"
20
+ * brand-href="/"
21
+ * brand-alt="Espalier logo"
22
+ * light-brand-color="oklch(0.35 0.12 216)"
23
+ * dark-brand-color="oklch(0.9 0.08 216)"
24
+ * columns="3">
25
+ * <esp-footer-link-group heading="Explore">
26
+ * <a href="/components">Components</a>
27
+ * <a href="/api">API</a>
28
+ * </esp-footer-link-group>
29
+ * <esp-footer-link-group heading="Learn">
30
+ * <a href="/guides/getting-started">Getting started</a>
31
+ * <a href="/guides/styling">Styling</a>
32
+ * </esp-footer-link-group>
33
+ * <p slot="aside">Themeable web components built on web standards.</p>
34
+ * <div slot="bottom">Copyright 2026 Example Organization</div>
35
+ * </esp-footer>
36
+ * ```
37
+ *
38
+ * A slotted brand replaces configured branding, while the media slot accepts
39
+ * a responsive `picture`, native image, or `esp-image`. Media spans the
40
+ * surface-aligned content well; use the decorative background layer for
41
+ * edge-to-edge artwork:
42
+ *
43
+ * ```html
44
+ * <esp-footer columns="4">
45
+ * <picture slot="media">
46
+ * <source media="(prefers-color-scheme: dark)" srcset="/assets/canvas-bg-dark.jpg" />
47
+ * <img
48
+ * src="/assets/canvas-bg.jpg"
49
+ * alt="A colorful floral pattern"
50
+ * style="display: block; width: 100%; height: auto;" />
51
+ * </picture>
52
+ * <a slot="brand" href="/" aria-label="Espalier home">
53
+ * <img src="/assets/espalier-logo.svg" alt="Espalier" />
54
+ * </a>
55
+ * <esp-footer-link-group heading="Product">
56
+ * <a href="/components">Components</a>
57
+ * </esp-footer-link-group>
58
+ * </esp-footer>
59
+ * ```
60
+ *
61
+ * Decorative art uses an image layer independent of the base color. The same
62
+ * API supports a repeating landscape band or one large cover image:
63
+ *
64
+ * ```html
65
+ * <style>
66
+ * esp-footer.mountains {
67
+ * --esp-footer-background: oklch(0.48 0.12 145);
68
+ * --esp-footer-background-image-opacity: 0.55;
69
+ * --esp-footer-background-image:
70
+ * linear-gradient(to bottom, transparent 8rem, oklch(0.48 0.12 145)),
71
+ * url("/assets/espalier-geometric-texture.png");
72
+ * --esp-footer-background-repeat: no-repeat, repeat-x;
73
+ * --esp-footer-background-position: 0 0, top;
74
+ * --esp-footer-background-size: 100% 100%, auto 10rem;
75
+ * --esp-footer-padding-block: 6rem;
76
+ * }
77
+ *
78
+ * esp-footer.photo {
79
+ * --esp-footer-background: oklch(0.2 0.04 216);
80
+ * --esp-footer-heading-color: white;
81
+ * --esp-footer-background-image:
82
+ * linear-gradient(oklch(0.1 0 0 / 0.55), oklch(0.1 0 0 / 0.55)),
83
+ * url("/assets/canvas-bg.jpg");
84
+ * --esp-footer-background-repeat: no-repeat;
85
+ * --esp-footer-background-position: center;
86
+ * --esp-footer-background-size: cover;
87
+ * }
88
+ * </style>
89
+ * <esp-footer class="mountains" brand-text="Mountain Studio"></esp-footer>
90
+ * <esp-footer class="photo" brand-text="Photo Studio"></esp-footer>
91
+ * ```
92
+ *
93
+ * Surface alignment is automatic inside `esp-page`; opt out only when the
94
+ * footer's content should also span the entire bar:
95
+ *
96
+ * ```html
97
+ * <esp-page align="center" style="--esp-page-max-width: 36rem;">
98
+ * <main>Surface-aligned page content</main>
99
+ * <esp-footer slot="footer" brand-text="Aligned Studio" columns="3">
100
+ * <esp-footer-link-group heading="Explore">
101
+ * <a href="/work">Work</a>
102
+ * <a href="/about">About</a>
103
+ * </esp-footer-link-group>
104
+ * </esp-footer>
105
+ * </esp-page>
106
+ *
107
+ * <esp-footer full-bleed-content brand-text="Full-width Studio"></esp-footer>
108
+ * ```
109
+ *
110
+ * @customElement esp-footer
111
+ * @slot media - Meaningful artwork spanning the surface-aligned content well,
112
+ * preferably responsive `<picture>` markup or an `esp-image` with appropriate
113
+ * alternative text.
114
+ * @slot brand - Custom brand identity. Overrides configured brand properties.
115
+ * @slot - `esp-footer-link-group` navigation columns.
116
+ * @slot aside - Supporting content such as a newsletter, call to action,
117
+ * contact details, social links, or locale controls.
118
+ * @slot bottom - Copyright, legal/utility links, attribution, accessibility
119
+ * controls, site credit, or a final wordmark.
120
+ * @csspart footer - The native footer landmark and full-bleed base surface.
121
+ * @csspart background - The independent decorative image layer.
122
+ * @csspart content - The surface-aligned content wrapper.
123
+ * @csspart media - The media region spanning the aligned content well.
124
+ * @csspart primary - The grid containing brand, link groups, and aside content.
125
+ * @csspart brand - The brand region.
126
+ * @csspart groups - The link-group grid.
127
+ * @csspart aside - The supporting-content region.
128
+ * @csspart bottom - The final legal/utility region.
129
+ * @cssprop --esp-footer-background - Base footer color. Defaults to `var(--esp-color-layer-2)`.
130
+ * @cssprop --esp-footer-color - Body text color. Defaults to `var(--esp-color-text)`.
131
+ * @cssprop --esp-footer-heading-color - Heading and configured-brand color. Defaults to `var(--esp-color-headings)`.
132
+ * @cssprop --esp-footer-link-color - Link color. Defaults to `var(--esp-color-link)`.
133
+ * @cssprop --esp-footer-link-hover-color - Hovered link color. Defaults to `var(--esp-color-link-hover)`.
134
+ * @cssprop --esp-footer-focus-outline - Focus-visible outline. Defaults to `2px solid var(--esp-color-link)`.
135
+ * @cssprop --esp-footer-border - Block-start footer border. Defaults to `1px solid var(--esp-color-border)`.
136
+ * @cssprop --esp-footer-padding-block - Content block padding. Defaults to `var(--esp-size-padding-page)`.
137
+ * @cssprop --esp-footer-padding-inline - Content inline padding. Defaults to `var(--esp-size-padding-page)`.
138
+ * @cssprop --esp-footer-section-gap - Gap between media, primary, and bottom regions. Defaults to `var(--esp-size-big)`.
139
+ * @cssprop --esp-footer-column-gap - Gap between link-group columns and major primary regions. Defaults to `var(--esp-size-padding-page)`.
140
+ * @cssprop --esp-footer-row-gap - Compact-layout row gap. Defaults to `var(--esp-size-big)`.
141
+ * @cssprop --esp-footer-link-group-min-width - Intrinsic minimum link-group column width. Defaults to `10rem`.
142
+ * @cssprop --esp-footer-link-group-gap - Space between a link-group heading and its links. Defaults to `var(--esp-size-small)`.
143
+ * @cssprop --esp-footer-brand-logo-size - Configured logo block size. Defaults to `3rem`.
144
+ * @cssprop --esp-footer-brand-logo-max-width - Configured logo maximum inline size. Defaults to `12rem`.
145
+ * @cssprop --esp-footer-background-image - Decorative image or gradient layer. Defaults to `none`.
146
+ * @cssprop --esp-footer-background-image-opacity - Decorative layer opacity. Defaults to `1`.
147
+ * @cssprop --esp-footer-background-repeat - Decorative layer repeat behavior. Defaults to `repeat`.
148
+ * @cssprop --esp-footer-background-position - Decorative layer position. Defaults to `0 0`.
149
+ * @cssprop --esp-footer-background-size - Decorative layer size. Defaults to `auto`.
150
+ * @cssprop --esp-footer-background-blend-mode - Decorative layer blend mode. Defaults to `normal`.
151
+ * @cssprop --esp-footer-content-max-width - Surface-alignment cap published by `esp-page`. Defaults to `100%`.
152
+ * @cssprop --esp-footer-content-lead - Fraction of surplus placed before content (`0`, `0.5`, or `1`). Defaults to `0`.
153
+ * @docPageTitle Footer
154
+ * @docUrl /components/footer
155
+ * @menuGroup Structure
156
+ * @menuLabel Footer
157
+ * @menuIcon layout
158
+ */
159
+ export declare class EspalierFooter extends EspalierElementBase {
160
+ /** Configured brand text used when the `brand` slot is empty. */
161
+ brandText: string;
162
+ /** Configured brand logo URL used when the `brand` slot is empty. */
163
+ brandLogo: string;
164
+ /**
165
+ * Configured brand logo URL used in light scheme. A non-empty value
166
+ * overrides `brand-logo`; an empty value falls back to it.
167
+ */
168
+ lightBrandLogo: string;
169
+ /**
170
+ * Configured brand logo URL used in dark scheme. A non-empty value
171
+ * overrides `brand-logo`; an empty value falls back to it.
172
+ */
173
+ darkBrandLogo: string;
174
+ /** Optional configured-brand link target. */
175
+ brandHref: string;
176
+ /** Accessible text for a configured logo. */
177
+ brandAlt: string;
178
+ /**
179
+ * Optional configured brand color. Scheme-specific colors override it;
180
+ * when all configured colors are empty, `--esp-footer-heading-color`
181
+ * remains the fallback.
182
+ */
183
+ brandColor: string;
184
+ /**
185
+ * Configured brand color used in light scheme. A non-empty value
186
+ * overrides `brand-color`; an empty value falls back to it and then
187
+ * `--esp-footer-heading-color`.
188
+ */
189
+ lightBrandColor: string;
190
+ /**
191
+ * Configured brand color used in dark scheme. A non-empty value
192
+ * overrides `brand-color`; an empty value falls back to it and then
193
+ * `--esp-footer-heading-color`.
194
+ */
195
+ darkBrandColor: string;
196
+ /**
197
+ * Maximum number of link-group columns. Numeric values cap the wide layout;
198
+ * the intrinsic grid still renders fewer columns when space is limited.
199
+ */
200
+ columns: FooterColumns;
201
+ /**
202
+ * Opt out of the `esp-page` surface-alignment contract and allow footer
203
+ * content to use the full bar width. The background is always full-bleed.
204
+ */
205
+ fullBleedContent: boolean;
206
+ /** Optional accessible label for pages containing multiple footer landmarks. */
207
+ landmarkLabel: string;
208
+ protected willUpdate(changedProperties: PropertyValues): void;
209
+ protected firstUpdated(changedProperties: PropertyValues): void;
210
+ protected render(): import("lit-html").TemplateResult<1>;
211
+ static styles: import("lit").CSSResult[];
212
+ }
213
+ declare global {
214
+ interface HTMLElementTagNameMap {
215
+ "esp-footer": EspalierFooter;
216
+ }
217
+ }
@@ -0,0 +1,307 @@
1
+ var t=function(i,o,e,a){var s=arguments.length,d=s<3?o:a===null?a=Object.getOwnPropertyDescriptor(o,e):a,l;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")d=Reflect.decorate(i,o,e,a);else for(var p=i.length-1;p>=0;p--)(l=i[p])&&(d=(s<3?l(d):s>3?l(o,e,d):l(o,e))||d);return s>3&&d&&Object.defineProperty(o,e,d),d};import{css as f,html as v,nothing as y}from"lit";import{customElement as x,property as n,state as C}from"lit/decorators.js";import{classMap as k}from"lit/directives/class-map.js";import{styleMap as _}from"lit/directives/style-map.js";import{renderConfiguredBrand as z,resolveConfiguredBrand as B}from"../shared/configured-brand.js";import{EspalierElementBase as g}from"../shared/esp-element-base.js";import{slotHasContent as h}from"../shared/slot-content.js";import"./esp-footer-link-group.js";const m=new Set(["auto","1","2","3","4","5","6"]),c={media:!1,brand:!1,groups:!1,aside:!1,bottom:!1},S={fromAttribute(i){return i&&m.has(i)?i:"auto"},toAttribute(i){return m.has(i)?i:"auto"}};let r=class extends g{constructor(){super(...arguments),this.slotContent={...c},this.brandText="",this.brandLogo="",this.lightBrandLogo="",this.darkBrandLogo="",this.brandHref="",this.brandAlt="",this.brandColor="",this.lightBrandColor="",this.darkBrandColor="",this.columns="auto",this.fullBleedContent=!1,this.landmarkLabel="",this.handleSlotChange=o=>{if(!(o.target instanceof HTMLSlotElement))return;const e=this.slotRegion(o.target);if(!e)return;const a=h(o.target);this.slotContent[e]!==a&&(this.slotContent={...this.slotContent,[e]:a})}}willUpdate(o){super.willUpdate(o),o.has("columns")&&!m.has(this.columns)&&(this.columns="auto")}slotRegion(o){return o.name?["media","brand","aside","bottom"].includes(o.name)?o.name:null:"groups"}firstUpdated(o){super.firstUpdated(o);const e={...c};for(const a of this.shadowRoot?.querySelectorAll("slot")??[]){const s=this.slotRegion(a);s&&(e[s]=h(a))}Object.entries(e).some(([a,s])=>this.slotContent[a]!==s)&&(this.slotContent=e)}render(){const{media:o,brand:e,groups:a,aside:s,bottom:d}=this.slotContent,l=B({scheme:this.scheme,brandLogo:this.brandLogo,brandColor:this.brandColor,lightBrandLogo:this.lightBrandLogo,darkBrandLogo:this.darkBrandLogo,lightBrandColor:this.lightBrandColor,darkBrandColor:this.darkBrandColor}),p=e||!!(l.brandLogo||this.brandText),u=p||a||s,b={primary:!0,"has-brand":p,"has-groups":a,"has-aside":s};return v`
2
+ <footer
3
+ part="footer"
4
+ aria-label=${this.landmarkLabel||y}
5
+ style=${_({"--_esp-footer-brand-color":l.brandColor||null})}
6
+ >
7
+ <div part="background" class="background" aria-hidden="true"></div>
8
+ <div part="content" class="content-frame">
9
+ <div class="content">
10
+ <div part="media" class="media" ?hidden=${!o}>
11
+ <slot name="media" @slotchange=${this.handleSlotChange}></slot>
12
+ </div>
13
+
14
+ <div part="primary" class=${k(b)} ?hidden=${!u}>
15
+ <div part="brand" class="brand" ?hidden=${!p}>
16
+ <slot name="brand" @slotchange=${this.handleSlotChange}
17
+ >${z({brandLogo:l.brandLogo,brandText:this.brandText,brandHref:this.brandHref,brandAlt:this.brandAlt})}</slot
18
+ >
19
+ </div>
20
+
21
+ <div part="groups" class="groups" ?hidden=${!a}>
22
+ <slot @slotchange=${this.handleSlotChange}></slot>
23
+ </div>
24
+
25
+ <div part="aside" class="aside" ?hidden=${!s}>
26
+ <slot name="aside" @slotchange=${this.handleSlotChange}></slot>
27
+ </div>
28
+ </div>
29
+
30
+ <div part="bottom" class="bottom" ?hidden=${!d}>
31
+ <slot name="bottom" @slotchange=${this.handleSlotChange}></slot>
32
+ </div>
33
+ </div>
34
+ </div>
35
+ </footer>
36
+ `}};r.styles=[...g.styles,f`
37
+ :host {
38
+ display: block;
39
+ min-inline-size: 0;
40
+ }
41
+
42
+ [hidden] {
43
+ display: none !important;
44
+ }
45
+
46
+ footer {
47
+ position: relative;
48
+ isolation: isolate;
49
+ min-inline-size: 0;
50
+ overflow: hidden;
51
+ color: var(--esp-footer-color, var(--esp-color-text));
52
+ background: var(--esp-footer-background, var(--esp-color-layer-2));
53
+ border-block-start: var(--esp-footer-border, 1px solid var(--esp-color-border));
54
+ }
55
+
56
+ .background {
57
+ position: absolute;
58
+ z-index: -1;
59
+ inset: 0;
60
+ pointer-events: none;
61
+ background-image: var(--esp-footer-background-image, none);
62
+ background-repeat: var(--esp-footer-background-repeat, repeat);
63
+ background-position: var(--esp-footer-background-position, 0 0);
64
+ background-size: var(--esp-footer-background-size, auto);
65
+ opacity: var(--esp-footer-background-image-opacity, 1);
66
+ mix-blend-mode: var(--esp-footer-background-blend-mode, normal);
67
+ }
68
+
69
+ .content-frame {
70
+ --_esp-footer-content-surplus: max(
71
+ 0px,
72
+ calc(100% - var(--esp-footer-content-max-width, 100%))
73
+ );
74
+
75
+ box-sizing: border-box;
76
+ min-inline-size: 0;
77
+ padding-inline: calc(var(--_esp-footer-content-surplus) * var(--esp-footer-content-lead, 0))
78
+ calc(var(--_esp-footer-content-surplus) * (1 - var(--esp-footer-content-lead, 0)));
79
+ }
80
+
81
+ :host([full-bleed-content]) .content-frame {
82
+ padding-inline: 0;
83
+ }
84
+
85
+ .content {
86
+ display: grid;
87
+ container: esp-footer / inline-size;
88
+ gap: var(--esp-footer-section-gap, var(--esp-size-big));
89
+ min-inline-size: 0;
90
+ padding-block: var(--esp-footer-padding-block, var(--esp-size-padding-page))
91
+ calc(
92
+ var(--esp-footer-padding-block, var(--esp-size-padding-page)) +
93
+ env(safe-area-inset-bottom, 0px)
94
+ );
95
+ padding-inline: var(--esp-footer-padding-inline, var(--esp-size-padding-page));
96
+ }
97
+
98
+ .media,
99
+ .primary,
100
+ .brand,
101
+ .groups,
102
+ .aside,
103
+ .bottom {
104
+ min-inline-size: 0;
105
+ }
106
+
107
+ .media ::slotted(img),
108
+ .media ::slotted(picture),
109
+ .media ::slotted(esp-image) {
110
+ display: block;
111
+ inline-size: 100%;
112
+ max-inline-size: 100%;
113
+ }
114
+
115
+ .primary {
116
+ display: grid;
117
+ grid-template-columns: minmax(10rem, 1fr) minmax(0, 3fr) minmax(10rem, 1fr);
118
+ grid-template-areas: "brand groups aside";
119
+ gap: var(--esp-footer-row-gap, var(--esp-size-big))
120
+ var(--esp-footer-column-gap, var(--esp-size-padding-page));
121
+ align-items: start;
122
+ }
123
+
124
+ .primary.has-brand.has-groups:not(.has-aside),
125
+ .primary.has-groups.has-aside:not(.has-brand) {
126
+ grid-template-columns: minmax(10rem, 1fr) minmax(0, 3fr);
127
+ }
128
+
129
+ .primary.has-brand.has-groups:not(.has-aside) {
130
+ grid-template-areas: "brand groups";
131
+ }
132
+
133
+ .primary.has-groups.has-aside:not(.has-brand) {
134
+ grid-template-areas: "groups aside";
135
+ }
136
+
137
+ .primary.has-brand.has-aside:not(.has-groups) {
138
+ grid-template-columns: repeat(2, minmax(0, 1fr));
139
+ grid-template-areas: "brand aside";
140
+ }
141
+
142
+ .primary.has-brand:not(.has-groups):not(.has-aside) {
143
+ grid-template-columns: minmax(0, 1fr);
144
+ grid-template-areas: "brand";
145
+ }
146
+
147
+ .primary.has-groups:not(.has-brand):not(.has-aside) {
148
+ grid-template-columns: minmax(0, 1fr);
149
+ grid-template-areas: "groups";
150
+ }
151
+
152
+ .primary.has-aside:not(.has-brand):not(.has-groups) {
153
+ grid-template-columns: minmax(0, 1fr);
154
+ grid-template-areas: "aside";
155
+ }
156
+
157
+ .brand {
158
+ grid-area: brand;
159
+ }
160
+
161
+ .groups {
162
+ --_esp-footer-column-gap: var(--esp-footer-column-gap, var(--esp-size-padding-page));
163
+ --_esp-footer-column-min: var(--esp-footer-link-group-min-width, 10rem);
164
+ --_esp-footer-column-basis: var(--_esp-footer-column-min);
165
+
166
+ grid-area: groups;
167
+ display: grid;
168
+ grid-template-columns: repeat(
169
+ auto-fit,
170
+ minmax(min(100%, var(--_esp-footer-column-basis)), 1fr)
171
+ );
172
+ gap: var(--esp-footer-row-gap, var(--esp-size-big)) var(--_esp-footer-column-gap);
173
+ }
174
+
175
+ :host([columns="1"]) .groups {
176
+ --_esp-footer-column-basis: 100%;
177
+ }
178
+
179
+ :host([columns="2"]) .groups {
180
+ --_esp-footer-column-basis: max(
181
+ var(--_esp-footer-column-min),
182
+ calc(50% - var(--_esp-footer-column-gap))
183
+ );
184
+ }
185
+
186
+ :host([columns="3"]) .groups {
187
+ --_esp-footer-column-basis: max(
188
+ var(--_esp-footer-column-min),
189
+ calc(33.3333% - var(--_esp-footer-column-gap))
190
+ );
191
+ }
192
+
193
+ :host([columns="4"]) .groups {
194
+ --_esp-footer-column-basis: max(
195
+ var(--_esp-footer-column-min),
196
+ calc(25% - var(--_esp-footer-column-gap))
197
+ );
198
+ }
199
+
200
+ :host([columns="5"]) .groups {
201
+ --_esp-footer-column-basis: max(
202
+ var(--_esp-footer-column-min),
203
+ calc(20% - var(--_esp-footer-column-gap))
204
+ );
205
+ }
206
+
207
+ :host([columns="6"]) .groups {
208
+ --_esp-footer-column-basis: max(
209
+ var(--_esp-footer-column-min),
210
+ calc(16.6667% - var(--_esp-footer-column-gap))
211
+ );
212
+ }
213
+
214
+ .aside {
215
+ grid-area: aside;
216
+ }
217
+
218
+ .configured-brand {
219
+ display: inline-flex;
220
+ align-items: center;
221
+ gap: var(--esp-size-small);
222
+ max-inline-size: 100%;
223
+ color: var(
224
+ --_esp-footer-brand-color,
225
+ var(--esp-footer-heading-color, var(--esp-color-headings))
226
+ );
227
+ font-family: var(--esp-font-brand, var(--esp-font-headings));
228
+ font-size: var(--esp-type-medium);
229
+ font-weight: var(--esp-font-weight-brand, var(--esp-font-weight-headings));
230
+ line-height: 1.1;
231
+ overflow-wrap: anywhere;
232
+ text-decoration: none;
233
+ }
234
+
235
+ a.configured-brand:hover {
236
+ color: var(--esp-footer-link-hover-color, var(--esp-color-link-hover));
237
+ text-decoration: underline;
238
+ text-underline-offset: 0.18em;
239
+ }
240
+
241
+ a.configured-brand:focus-visible {
242
+ border-radius: var(--esp-size-border-radius);
243
+ outline: var(--esp-footer-focus-outline, 2px solid var(--esp-color-link));
244
+ outline-offset: 3px;
245
+ }
246
+
247
+ .brand-logo {
248
+ display: block;
249
+ inline-size: auto;
250
+ max-inline-size: min(var(--esp-footer-brand-logo-max-width, 12rem), 100%);
251
+ block-size: var(--esp-footer-brand-logo-size, 3rem);
252
+ object-fit: contain;
253
+ }
254
+
255
+ .brand-text {
256
+ min-inline-size: 0;
257
+ }
258
+
259
+ @container esp-footer (max-width: 48rem) {
260
+ .primary,
261
+ .primary.has-brand.has-groups:not(.has-aside),
262
+ .primary.has-groups.has-aside:not(.has-brand),
263
+ .primary.has-brand.has-aside:not(.has-groups),
264
+ .primary.has-brand:not(.has-groups):not(.has-aside),
265
+ .primary.has-groups:not(.has-brand):not(.has-aside),
266
+ .primary.has-aside:not(.has-brand):not(.has-groups) {
267
+ grid-template-columns: minmax(0, 1fr);
268
+ }
269
+
270
+ .primary.has-brand.has-groups.has-aside {
271
+ grid-template-areas:
272
+ "brand"
273
+ "groups"
274
+ "aside";
275
+ }
276
+
277
+ .primary.has-brand.has-groups:not(.has-aside) {
278
+ grid-template-areas:
279
+ "brand"
280
+ "groups";
281
+ }
282
+
283
+ .primary.has-groups.has-aside:not(.has-brand) {
284
+ grid-template-areas:
285
+ "groups"
286
+ "aside";
287
+ }
288
+
289
+ .primary.has-brand.has-aside:not(.has-groups) {
290
+ grid-template-areas:
291
+ "brand"
292
+ "aside";
293
+ }
294
+
295
+ .primary.has-brand:not(.has-groups):not(.has-aside) {
296
+ grid-template-areas: "brand";
297
+ }
298
+
299
+ .primary.has-groups:not(.has-brand):not(.has-aside) {
300
+ grid-template-areas: "groups";
301
+ }
302
+
303
+ .primary.has-aside:not(.has-brand):not(.has-groups) {
304
+ grid-template-areas: "aside";
305
+ }
306
+ }
307
+ `],t([C()],r.prototype,"slotContent",void 0),t([n({attribute:"brand-text",type:String})],r.prototype,"brandText",void 0),t([n({attribute:"brand-logo",type:String})],r.prototype,"brandLogo",void 0),t([n({attribute:"light-brand-logo",type:String})],r.prototype,"lightBrandLogo",void 0),t([n({attribute:"dark-brand-logo",type:String})],r.prototype,"darkBrandLogo",void 0),t([n({attribute:"brand-href",type:String})],r.prototype,"brandHref",void 0),t([n({attribute:"brand-alt",type:String})],r.prototype,"brandAlt",void 0),t([n({attribute:"brand-color",type:String})],r.prototype,"brandColor",void 0),t([n({attribute:"light-brand-color",type:String})],r.prototype,"lightBrandColor",void 0),t([n({attribute:"dark-brand-color",type:String})],r.prototype,"darkBrandColor",void 0),t([n({converter:S,reflect:!0})],r.prototype,"columns",void 0),t([n({attribute:"full-bleed-content",type:Boolean,reflect:!0})],r.prototype,"fullBleedContent",void 0),t([n({attribute:"landmark-label",type:String})],r.prototype,"landmarkLabel",void 0),r=t([x("esp-footer")],r);export{r as EspalierFooter};
@@ -0,0 +1,2 @@
1
+ export * from "./esp-footer-link-group.js";
2
+ export * from "./esp-footer.js";
@@ -0,0 +1 @@
1
+ export*from"./esp-footer-link-group.js";export*from"./esp-footer.js";