/* ===========================================================
   Evy Diepenbroek — Shared design tokens + cross-page components

   Loaded on EVERY page, before that page's own stylesheet. This is
   the one place to change a font, a spacing/max-width value, or a
   colour and have it apply site-wide — new pages should reach for
   these tokens/components rather than redeclaring their own.

   Contains:
     - PP Mori @font-face (site-wide, was previously duplicated
       between style.css and test-navigation.css)
     - :root design tokens (colours, radius, content max-width)
     - .eod-page base layout (padding, box-sizing, font)
     - .eod-btn button component (More about me / Contact me / etc.)
     - [data-eod-reveal] fade+rise scroll-reveal system
     - .eod-awards component
     - .eod-cta "I am a [ ] Design" component
     - .eod-footer* component
   =========================================================== */

/* PP Mori — self-hosted. These 3 files (fonts/PPMori-*.woff2) need to
   be uploaded to your host and the url() paths below updated to
   wherever they end up living — a relative "fonts/…" path only
   resolves for local testing. */
@font-face {
  font-family: "PP Mori";
  src: url("fonts/PPMori-Extralight.woff2") format("woff2");
  font-weight: 300;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "PP Mori";
  src: url("fonts/PPMori-Regular.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "PP Mori";
  src: url("fonts/PPMori-Semibold.woff2") format("woff2");
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}

:root {
  --eod-black: #0a0a0a;
  --eod-white: #fafafa;
  --eod-radius: 1em;
  --eod-accent: #212aff; /* matches the Navigation component's link/hover colour */
  --eod-ink: #1a1a1a;
  --eod-muted: #6b6b6b;
  --eod-cta-bg: #f2f2f2;
  --eod-border: rgba(0, 0, 0, 0.1);
  --eod-icon-border: #414651; /* matches the reference site's own button icon border */
  /* Caps how wide any section's actual CONTENT (text, cards, the
     footer logo) gets on an ultra-wide monitor — the sections'
     own full-bleed backgrounds (hero black, CTA grey, footer's
     accent blue) are untouched, only what sits inside them is
     capped+centered. Applied per-element rather than to the
     sections themselves, since those backgrounds are meant to run
     edge to edge (the footer's own rounded top corners only make
     sense against a full-bleed background). */
  --eod-content-max: 2100px;
}

/* ---- Page-wide type + layout ---- */
.eod-page {
  font-family: "PP Mori", "Helvetica Neue", Arial, sans-serif;
  font-weight: 400;
  color: var(--eod-ink);
  overflow-x: clip; /* the home hero's tornado cards intentionally bleed past the viewport */
}
.eod-page * { box-sizing: border-box; }
.eod-page section,
.eod-page footer {
  padding-left: 2.5em;
  padding-right: 2.5em;
}
@media (max-width: 767px) {
  .eod-page section,
  .eod-page footer {
    padding-left: 1.25em;
    padding-right: 1.25em;
  }
}

/* script.js toggles this on <body> while a scroll is actively in
   progress, so a stationary cursor that a moving/sticky button
   happens to scroll past can't trigger its hover (see the button
   hover comment in script.js for why that was causing a jitter). */
body.eod-is-scrolling .eod-btn {
  pointer-events: none;
}

/* Standard sr-only utility — visually hidden but still in normal
   layout flow (so screen readers, search engines, and "find on page"
   all still see it), for content whose VISUAL rendering happens some
   other way (e.g. the About hero's canvas-rendered text, about.js). */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* Three parts, two of them fixed in place: an accent-blue circle at
   the very left and a white-outlined circle at the very right never
   move — only the black label between them slides. At rest, the
   label sits flush left, exactly covering the blue circle (which is
   directly underneath it), and stops right before the white circle,
   so what's actually visible is "black label + white circle". On
   hover, the label slides right by exactly one circle's width — now
   covering the white circle instead — which uncovers the blue
   circle on the left by that exact same amount. Nothing rotates or
   swaps sides; each circle already has its own fixed icon (↗ white,
   → blue) and simply becomes visible or hidden as the label passes
   over it. --eod-btn-circle sets that shared width once (both the
   circles' own size and the label's slide distance/reserved space
   read from it) so they can never drift out of sync. */
.eod-btn {
  --eod-btn-circle: 3.2em;
  position: relative;
  display: inline-block;
  isolation: isolate;
  font-size: 0.95em;
  text-decoration: none;
  /* Reserves room for the white circle beyond the label's own
     content width — without this, the container's auto-width would
     just be the label's width and the right:0 circle below would
     have nowhere of its own to sit. */
  padding-right: var(--eod-btn-circle);
}
.eod-btn__circle {
  position: absolute;
  top: 0;
  z-index: 1;
  width: var(--eod-btn-circle);
  height: var(--eod-btn-circle);
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
}
.eod-btn__circle svg {
  width: 45%;
  height: 45%;
  stroke: currentColor;
}
.eod-btn__circle--accent {
  left: 0;
  background: var(--eod-accent);
  color: var(--eod-white);
}
/* Fixed diagonal→horizontal split: the white circle's arrow points
   ↗ (this site's own icon, unrotated), the blue one underneath it
   points → (the same icon rotated 45°, permanently — nothing
   animates the rotation itself, only which circle is visible). */
.eod-btn__circle--accent svg {
  transform: rotate(45deg);
}
.eod-btn__circle--white {
  right: 0;
  background: var(--eod-white);
  border: 1px solid var(--eod-icon-border);
  color: var(--eod-ink);
}
.eod-btn__label {
  position: relative;
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: center;
  height: var(--eod-btn-circle);
  padding: 0 1.4em;
  border-radius: 999px;
  font-weight: 500;
  white-space: nowrap;
  transition: transform 0.45s cubic-bezier(0.65, 0, 0.35, 1);
}
.eod-btn--dark .eod-btn__label {
  background: var(--eod-ink);
  color: var(--eod-white);
}
.eod-btn--dark:hover .eod-btn__label {
  transform: translateX(var(--eod-btn-circle));
}

/* ---- Scroll-reveal-in: fade + rise (default), applied to any
   element carrying data-eod-reveal. script.js observes each one and
   adds .is-inview the first time it enters the viewport (load-time
   for anything already on screen, e.g. the hero heading). Stagger
   within a group via data-eod-reveal-delay="1" / "2" / … — script.js
   turns that into a transition-delay. The attribute's VALUE picks
   the entrance direction — data-eod-reveal="left"/"right" slide in
   from that outer side instead of rising from below. */
[data-eod-reveal] {
  opacity: 0;
  transform: translateY(2.2em);
  transition: opacity 0.9s cubic-bezier(0.16, 1, 0.3, 1), transform 0.9s cubic-bezier(0.16, 1, 0.3, 1);
}
[data-eod-reveal="left"] {
  transform: translateX(-3em);
}
[data-eod-reveal="right"] {
  transform: translateX(3em);
}
[data-eod-reveal].is-inview {
  opacity: 1;
  transform: translate(0);
}

/* ===========================================================
   Awards / CTA / Footer — identical on every page that has them
   (Home, About, …). Edit here once, it applies everywhere.
   =========================================================== */

/* ---- Awards ---- */
/* min-height + flex-centering follows the same pattern as .eod-cta
   below (min-height:70svh, column + justify-center) so a short award
   list never reads as a cramped little strip between two much taller
   sections — padding alone can't guarantee a floor height the way
   min-height does when the list itself is short. */
.eod-awards {
  background: var(--eod-white);
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding-top: 10em;
  padding-bottom: 10em;
}
@media (max-width: 767px) {
  .eod-awards {
    padding-top: 5em;
    padding-bottom: 5em;
  }
}
.eod-awards__row {
  display: flex;
  align-items: flex-start;
  gap: 3em;
  /* width: 100% (not bare max-width/margin): auto cross-axis margins
     on a flex item actually opt OUT of stretch per spec, which would
     collapse this to its own content width at every size, not just
     ultra-wide ones — see .eod-hero__heading's own version of this
     same fix for the full explanation. max-width only kicks in once
     that 100% would exceed the cap; margin: auto centers the
     difference so the title/list gap doesn't stretch out absurdly on
     an ultra-wide monitor. No-op below the cap. */
  width: 100%;
  max-width: var(--eod-content-max);
  margin: 0 auto;
}
.eod-awards__title {
  flex: 0 0 auto;
  font-size: clamp(2em, 4vw, 2.75em);
  font-weight: 400;
  letter-spacing: -0.02em;
  margin: 0;
}
.eod-awards__list {
  flex: 1 1 auto;
  max-width: 50em;
  margin-left: auto;
  list-style: none;
  margin-top: 0;
  margin-bottom: 0;
  padding: 0;
  border-top: 1px solid var(--eod-border);
}
@media (max-width: 767px) {
  .eod-awards__row {
    flex-direction: column;
    gap: 1.5em;
  }
  .eod-awards__list {
    margin-left: 0;
    width: 100%;
  }
  .eod-awards__item-title {
    font-size: 1.1em;
  }
  .eod-awards__item-body p {
    font-size: 1em;
  }
}
.eod-awards__item {
  border-bottom: 1px solid var(--eod-border);
}
.eod-awards__item-header {
  width: 100%;
  display: flex;
  align-items: center;
  gap: 1.5em;
  padding: 1.4em 0;
  background: none;
  border: none;
  font: inherit;
  color: inherit;
  text-align: left;
  cursor: pointer;
}
.eod-awards__item-title {
  flex: 1 1 auto;
  font-size: 1em;
}
.eod-awards__item-year {
  flex: none;
  color: var(--eod-muted);
  font-size: 0.9em;
}
.eod-awards__item-chevron {
  flex: none;
  display: inline-flex;
  transition: transform 0.25s ease;
}
.eod-awards__item-header[aria-expanded="true"] .eod-awards__item-chevron {
  transform: rotate(180deg);
}
.eod-awards__item-body {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.3s ease;
}
.eod-awards__item-body p {
  margin: 0 0 1.4em;
  max-width: 40em;
  color: var(--eod-muted);
  font-size: 0.9em;
  line-height: 1.5;
}

/* ---- CTA: "I am a [ ] Motion Design" ---- */
/* .eod-page .eod-cta (not just .eod-cta): needs to out-specificity
   .eod-page section's generic 2.5em padding rule above, which — as
   a class+element selector — otherwise beats a plain single-class
   .eod-cta rule regardless of which comes later in the file. */
.eod-page .eod-cta {
  background: var(--eod-cta-bg);
  /* svh, not vh: .eod-cta is position:sticky, and on mobile 100vh
     recalculates continuously as the browser chrome (address bar)
     animates in/out WHILE you scroll — combined with sticky, that
     reads as the whole section trembling/jittering as you scroll
     through it. 100svh is pinned to the smallest possible viewport,
     so it can't fluctuate mid-scroll (same fix as .eod-hero — see
     script.js's stableViewportHeight comment for the same root
     cause on the tornado's own scroll math). */
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  /* Centers .eod-cta__group (below) as a shrink-wrapped block within
     the section — without this, align-items defaults to stretch and
     the group (a plain block div) just fills the section's full
     available width, leaving whatever's left over after its own
     (much narrower) content as empty space stuck on ONE side only. */
  align-items: center;
  padding-top: 6em;
  padding-bottom: 6em;
  /* 180px at the reference 1280px-wide desktop (14vw ≈ 180px there),
     but scales DOWN below that instead of staying rigidly fixed —
     at in-between viewport widths (tablet-ish), holding a flat 180px
     left almost no room for .eod-cta__title's content (the cycling
     word + "Design", which must never clip — see .eod-cta__word
     below) and would force the whole two-line block to overflow.
     Prioritising the word staying fully readable over the frame
     keeping an exact 180px margin at every width. Promoted to a
     custom property (not just a literal value here) so
     .eod-cta__lede/__title's own font-size formula, below, can read
     it back — see --eod-cta-indent's own comment for why that
     matters. */
  --eod-cta-side-padding: clamp(1.25em, 14vw, 11.25rem);
  padding-left: var(--eod-cta-side-padding);
  padding-right: var(--eod-cta-side-padding);
  /* Shared indent for .eod-cta__title and .eod-cta__row (below) —
     same formula as .eod-cta__title's own font-size (clamp(2.8em,
     9vw, 8em)) × the 3.5em margin it used to carry directly, just
     expressed in rem/vw instead of em so it doesn't depend on which
     element's own (very different) font-size is doing the
     multiplying. Without this, .eod-cta__row — much smaller text —
     computed a 3.5em margin against ITS OWN size and landed nowhere
     near .eod-cta__title's actual indent. */
  --eod-cta-indent: clamp(9.8rem, 31.5vw, 28rem);
  /* Sticks in place while the footer (its very next sibling) scrolls
     up and over it — that's what makes the footer look like it's
     coming out from underneath this section instead of just being
     the next block in line. See .eod-footer-wrap below for the
     other half. Full-viewport height so there's real room for that
     reveal (and the footer's own parallax) to play out. */
  position: sticky;
  top: 0;
  z-index: 1;
}
@media (max-width: 767px) {
  .eod-page .eod-cta {
    padding-top: 3em;
    padding-bottom: 3em;
    padding-left: 1.25em;
    padding-right: 1.25em;
  }
}
/* "I am a [badge]" as a small lede line, then "Motion Design" as the
   big display line right under it, indented to start roughly under
   the badge. Each line enters from its own outer side (see
   [data-eod-reveal="left"/"right"] above) instead of a plain
   fade+rise. Font: Mori Regular throughout this section.

   Plain inline text flow (not flex) — "I am a" is one real sentence
   with the badge sitting inline inside it like an image in a
   paragraph, so on a narrow screen it wraps naturally word-by-word
   (confirmed against the live reference: at mobile widths it really
   does break across 3 lines, it isn't a deliberately-stacked
   layout). .eod-cta__title stays nowrap (see below) — that one's a
   single headline, not a sentence. */
/* Wraps lede + title + row as one unit so .eod-page .eod-cta's
   align-items: center (above) can centre the WHOLE composition as a
   block, rather than each line independently stretching to the
   section's full width and just leaving its own unused space on the
   right. width: var(--eod-cta-group-width, fit-content) — script.js
   pins this to the group's own natural width AT THE WIDEST possible
   cycling word (not whichever one is currently active) once up
   front (and again on resize), specifically so a plain word swap —
   which can change .eod-cta__word's own width, see below — never
   also reflows this group's centred position and drags
   .eod-cta__lede/the body+button row sideways with it. Only
   "Design" is meant to visibly move on a swap. fit-content is just
   the fallback before that JS runs. */
.eod-cta__group {
  width: var(--eod-cta-group-width, fit-content);
  /* Already self-limiting in practice (fit-content, or the widest-
     word-pinned var above) — min(...) adds the same ultra-wide cap as
     every other section purely as a defensive floor, in case future
     copy ever makes this genuinely wider than --eod-content-max. */
  max-width: min(100%, var(--eod-content-max));
}
/* font-size is derived, not a flat vw guess: the old clamp(2.8em,
   9vw, 8em) let the cycling word + "Design" genuinely run past the
   viewport edge and get clipped by .eod-page's overflow-x: clip —
   confirmed at 768px, 1024px AND even a full 1440px desktop (the
   widest word, "Graphic", overflowed by 56–74px at every one of
   those). Measuring the real rendered word+"Design" combo showed its
   width tracks very close to 6.86× the font-size at any size — the
   calc() below works backwards from that: whatever space is actually
   left after --eod-cta-side-padding and --eod-cta-indent are taken
   out of the viewport, divided by that ratio (7.5, not 6.86 — a
   ~7-9% safety margin so it never sits flush against the edge)
   IS the largest font-size that's still guaranteed to fit, at any
   viewport width, by construction — no more re-discovering an
   overflow at some untested in-between width. The 8em ceiling still
   applies once the viewport is wide enough (~1500px+, once padding/
   indent have maxed out their own clamps) that a flat 8em provably
   fits again. */
.eod-cta__lede {
  margin: 0;
  font-size: clamp(2.8em, calc((100vw - var(--eod-cta-side-padding) - var(--eod-cta-indent)) / 7.5), 8em);
  font-weight: 400;
  line-height: 1.05;
}
.eod-cta__accent {
  color: var(--eod-accent);
}
/* Badge: swaps its image in lockstep with the word cycler below (both
   share data-eod-cycle="cta-role" — script.js's initCyclers() steps
   every element carrying the same value together, on one interval,
   so they can never drift out of sync). Same grid-stack + is-active/
   is-exit pattern as .eod-cta__word-item.

   Sized directly off the surrounding text (font-size: inherit, from
   .eod-cta__lede) at EVERY width, not just on mobile — an earlier
   version gave it its own independent, viewport-based clamp() for
   desktop specifically to mimic the reference site's own (much
   larger, non-text-relative) sizing there, but that meant the badge
   and the text it sits inline with could end up wildly mismatched
   in between the tuned breakpoints. Matching the actual text height
   it's next to, everywhere, is simpler and can't drift. */
.eod-cta__badge {
  display: inline-grid;
  position: relative;
  font-size: inherit;
  width: auto;
  /* 0.65em, not a full 1em: an em box includes ascender/descender
     space the letters themselves don't actually use (real cap-height
     is usually ~70-75% of font-size, and even that read as still a
     bit tall against the actual glyphs here) — sized to the full em,
     the badge visibly hung lower than the text's own glyphs, far
     enough to collide with .eod-cta__title's line right below it
     (that title's own -0.2em margin-top is a deliberate slight
     overlap with THIS line, see below — not with the badge
     specifically). */
  height: 0.65em;
  aspect-ratio: 200 / 156;
  margin: 0 0.15em;
  border-radius: 0.3em;
  overflow: hidden;
  vertical-align: middle;
  background: var(--eod-ink);
}
.eod-cta__badge-item {
  grid-area: 1 / 1;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  transform: translateY(100%);
  transition: opacity 0.5s cubic-bezier(0.65, 0, 0.35, 1), transform 0.5s cubic-bezier(0.65, 0, 0.35, 1);
}
.eod-cta__badge-item.is-active {
  opacity: 1;
  transform: translateY(0);
}
.eod-cta__badge-item.is-exit {
  opacity: 0;
  transform: translateY(-100%);
}
.eod-cta__title {
  display: flex;
  /* Never wraps — the cycling word and "Design" always stay on one
     line, at any viewport width (the clamp() below shrinks the font
     to fit rather than letting it break into two lines). */
  flex-wrap: nowrap;
  align-items: center;
  gap: 0.2em;
  /* Negative top margin: pulls it up into .eod-cta__lede just above,
     so the two lines slightly overlap instead of sitting with a
     clean gap between them. */
  margin: -0.2em 0 1em var(--eod-cta-indent);
  /* Same derived formula as .eod-cta__lede above (see its comment) —
     shared so the two lines stay the same size, per the earlier
     requirement, and because this is really the element the formula
     was derived FOR (the widest word + "Design" living here is what
     was overflowing). */
  font-size: clamp(2.8em, calc((100vw - var(--eod-cta-side-padding) - var(--eod-cta-indent)) / 7.5), 8em);
  font-weight: 400;
  letter-spacing: -0.02em;
  line-height: 1;
}
@media (max-width: 767px) {
  /* The shared clamp above floors at 2.8em (44.8px) and never shrinks
     below that no matter how narrow the phone gets — on a 375px-wide
     screen that floor genuinely doesn't leave enough room for the
     cycling word's widest candidate ("Graphic") + "Design" side by
     side (both protected from flex-shrinking so they never squeeze/
     clip instead — see .eod-cta__word and .eod-cta__suffix below), so
     the line quietly overflowed the viewport and got cut by
     .eod-page's own overflow-x: clip. A lower mobile-only floor (2em)
     lets it keep shrinking all the way down to the smallest common
     phone width instead of hitting a hard wall. Placed AFTER the base
     rule above (not just inside a later media query) — same
     specificity, so source order is what makes this one win. */
  .eod-cta__lede,
  .eod-cta__title {
    font-size: clamp(2em, 10.5vw, 8em);
  }
}
/* Word cycler: every candidate word occupies the SAME grid cell (so
   the crossfade between e.g. "Motion" and "Graphic" can play out with
   both briefly overlapping), but the BOX itself now tracks the width
   of whichever one is actually active — script.js's initCyclers()
   measures each candidate's natural width once up front and pushes
   the active one to --eod-cta-word-width on every swap (falling back
   to max-content before that JS runs). Left-aligned (below) so the
   word always starts at the exact same x — matching .eod-cta__row's
   own margin-left: var(--eod-cta-indent) right below it — and
   "Design" right after is what visibly shifts as the word's width
   changes, not the other way around.
   flex: none: without it, being a flex item inside .eod-cta__title
   (nowrap) let the flex algorithm shrink this below its own natural
   width at in-between viewport widths — clipping the word mid-word
   instead of ever wrapping or overflowing. The word must always
   render at its full natural width; see .eod-page .eod-cta's padding
   above for the other half of making room for that. */
.eod-cta__word {
  display: inline-grid;
  flex: none;
  width: var(--eod-cta-word-width, max-content);
  transition: width 0.4s cubic-bezier(0.16, 1, 0.3, 1);
  vertical-align: bottom;
  overflow: hidden;
}
.eod-cta__word-item {
  grid-area: 1 / 1;
  text-align: left;
  opacity: 0;
  transform: translateY(100%);
  transition: opacity 0.5s cubic-bezier(0.65, 0, 0.35, 1), transform 0.5s cubic-bezier(0.65, 0, 0.35, 1);
  white-space: nowrap;
}
.eod-cta__word-item.is-active {
  opacity: 1;
  transform: translateY(0);
}
.eod-cta__word-item.is-exit {
  opacity: 0;
  transform: translateY(-100%);
}
/* Same flex-shrink protection as .eod-cta__word above, for the same
   reason: as a plain (default flex-shrink:1) flex item, "Design"
   could get squeezed narrower than its own text when the row runs
   short on space — text can't actually compress, so it would just
   overflow its own shrunk box instead, past the viewport edge. */
.eod-cta__suffix {
  flex: none;
}
/* Same left indent as .eod-cta__title, and the same right-side
   reveal direction (data-eod-reveal="right" in the HTML) — grouped
   with the title rather than fading in on its own separate line.

   Width: script.js's syncCtaRowWidth() sets --eod-cta-row-width to
   .eod-cta__title's own actual rendered width (re-measured whenever
   the word cycler swaps, since "Motion" vs "Graphic" etc. aren't
   the same width) — without it, this row would stretch to the
   section's full remaining width via flex's default stretch, and
   the button would end up far further right than where the title
   above it actually ends. */
.eod-cta__row {
  display: flex;
  align-items: center;
  /* flex-start, not space-between: space-between pushed the button
     all the way to this row's far edge — which, synced to match the
     title's own (often much wider) rendered width above, could land
     the button far past the body text with a lot of dead space
     between them. flex-start keeps the button right next to the
     text; the row still doesn't exceed the title's width above, that
     extra width (if any) just goes unused past the button instead of
     being spent pushing it away. */
  justify-content: flex-start;
  flex-wrap: wrap;
  gap: 1.5em;
  margin-left: var(--eod-cta-indent);
  width: var(--eod-cta-row-width, auto);
  max-width: 100%;
  transition: width 0.4s cubic-bezier(0.16, 1, 0.3, 1);
}
@media (max-width: 767px) {
  .eod-cta__title,
  .eod-cta__row {
    margin-left: 1.25em;
  }
  /* .eod-cta__lede's data-eod-reveal="left" (base rule, applies at
     every width) slides it in from the left on entry — on mobile
     it should come from the right instead, same direction as
     .eod-cta__title/__row right below it. A class+attribute
     selector (specificity 0,2,0) beats the generic
     [data-eod-reveal="left"] (0,1,0) regardless of source order, so
     this doesn't need to touch that shared rule — which
     .eod-hero__heading's own "Have a look" span also depends on,
     unaffected here since it isn't .eod-cta__lede. */
  .eod-cta__lede[data-eod-reveal="left"] {
    transform: translateX(3em);
  }
}
.eod-cta__body {
  max-width: 30em;
  margin: 0;
  font-size: 0.95em;
  font-weight: 400;
  line-height: 1.5;
  color: var(--eod-muted);
}

/* ---- Footer ----
   Three-layer structure (matches the GSAP ScrollTrigger parallax
   recipe in script.js's initFooterParallax()):
     .eod-footer-wrap        — outer block, normal document flow.
                                Next sibling right after .eod-cta, so
                                it's what actually scrolls up over the
                                sticky CTA (the "reveal"); also the
                                ScrollTrigger trigger element.
     .eod-footer             — the real content, parallax-lifted
                                (yPercent) as the wrap scrolls into
                                view — settles at 0 once fully in view.
     .eod-footer-wrap__dark  — a dark overlay above it, fading out
                                over the same scroll range, so the
                                footer reads as emerging from shadow. */
.eod-footer-wrap {
  position: relative;
  z-index: 2;
  background: var(--eod-accent);
  border-radius: 1.5em 1.5em 0 0;
  /* Clips the parallax-lifted content below so it can't spill past
     the rounded top corners while it's still catching up on scroll. */
  overflow: hidden;
}
.eod-footer-wrap__dark {
  position: absolute;
  inset: 0;
  z-index: 1;
  background: #000;
  opacity: 0;
  pointer-events: none;
  will-change: opacity;
}
.eod-footer {
  position: relative;
  color: var(--eod-white);
  padding-top: 3em;
  padding-bottom: 2em;
  will-change: transform;
}
.eod-footer__top {
  display: flex;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 2em;
  padding-bottom: 6em;
  /* Capped on an ultra-wide monitor so the contact/social columns
     don't end up spread absurdly far apart; margin: 0 auto is a
     no-op below the cap. */
  max-width: var(--eod-content-max);
  margin-left: auto;
  margin-right: auto;
}
.eod-footer__col {
  display: flex;
  flex-direction: column;
  gap: 0.6em;
  font-size: 0.9em;
}
.eod-footer__col--right {
  text-align: right;
  align-items: flex-end;
}
.eod-footer__label {
  opacity: 0.6;
  letter-spacing: 0.05em;
  font-size: 0.8em;
}
.eod-footer__link {
  color: inherit;
  text-decoration: none;
}
.eod-footer__link:hover {
  text-decoration: underline;
}
/* Full-width version of the same logo mark used top-left in the nav
   (see Navigation embad.html) — fill: currentColor, so it picks up
   .eod-footer's white. Capped on an ultra-wide monitor — "full width"
   of a 3000px+ viewport reads as an absurdly huge wordmark; margin:
   0 auto is a no-op below the cap. */
.eod-footer__logo {
  display: block;
  width: 100%;
  height: auto;
  max-width: var(--eod-content-max);
  margin-left: auto;
  margin-right: auto;
}
@media (max-width: 767px) {
  .eod-footer__top {
    padding-bottom: 3em;
  }
  .eod-footer__col {
    font-size: 1.1em;
  }
  .eod-footer__label {
    font-size: 0.9em;
  }
}
