/*
  Per-block styles. Tokens only, no literal colors or type sizes, so a reskin
  never has to open this file.
*/

/* ---------- Any block on photography ---------- */

/*
  Keyed off .has-bg, not .block--hero.

  On the parent page a background photo is not a hero feature: the impact
  stats sit on a forest, the partner quotes on a lobby, the closing CTA on a
  march. All of this used to be written as .block--hero and those sections
  rendered flat grey, which was the single biggest reason the rebuild did not
  look like the original.
*/
.edo-overlay .block.has-bg {
  color: var(--color-ink-invert);
  background-color: var(--color-surface-invert);
  background-image: var(--block-bg);
  background-size: cover;
  background-position: var(--block-bg-position, center);
  overflow: hidden;
}

/* Backgrounds below the fold are swapped in by JS once they approach the
   viewport. Without this a page of full-bleed photos costs several MB up front. */
.edo-overlay .block.has-bg[data-bg-load="lazy"]:not(.is-bg-ready) { background-image: none; }

.edo-overlay .block__scrim {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
}
.edo-overlay .block[data-scrim="dark"] .block__scrim { background: var(--scrim-dark); }
.edo-overlay .block[data-scrim="left"] .block__scrim { background: var(--scrim-left); }
.edo-overlay .block[data-scrim="none"] .block__scrim { background: var(--scrim-none); }

/*
  "shadow": no overlay at all, the type carries its own shadow instead.

  Jonah, 2026-08-27. A scrim protects text by flattening the photograph, which
  is the wrong trade when the picture is the subject. This keeps the image at
  full contrast and puts a tight black glow behind the words. Applied to the
  text rather than the box so it follows the letterforms.
*/
.edo-overlay .block[data-scrim="shadow"] .block__scrim { background: none; }
.edo-overlay .block[data-scrim="shadow"][data-text="light"] .block__inner {
  text-shadow: var(--text-shadow-strong);
}
/* Buttons are solid shapes; a glow behind their label just muddies it. */
.edo-overlay .block[data-scrim="shadow"] .btn { text-shadow: none; }

/*
  Pale artwork such as the world map carries navy type, not white. Declared
  rather than inherited so a theme rule on p or h2 cannot win.
*/
.edo-overlay .block[data-text="dark"],
.edo-overlay .block[data-text="dark"] .block__heading,
.edo-overlay .block[data-text="dark"] .block__subhead,
.edo-overlay .block[data-text="dark"] .block__body,
.edo-overlay .block[data-text="dark"] .block__attribution {
  color: var(--color-ink);
}

/* ---------- Hero ---------- */

.edo-overlay .block--hero .block__heading { font-size: var(--size-display); }

/*
  Jonah, 2026-08-27: the copy column was too narrow and the wordmark with it.

  Both come from this one number. The animation is sized `80vw` by the
  artwork's own stylesheet but also `max-width: 100%`, so it was being clamped
  to whatever this container allowed -- 780px, against 1152px on the live page.
  Widening the container fixes the copy measure and the wordmark together.
*/
.edo-overlay .block--hero.is-align-center .block__inner {
  max-width: var(--container);
  text-align: center;
}
.edo-overlay .block--hero.is-align-center .block__body {
  max-width: var(--measure-wide);
  margin-inline: auto;
}
.edo-overlay .block--hero.is-align-center .block__actions { justify-content: center; }

.edo-overlay .block--hero.is-align-left .block__inner { max-width: var(--container); }
.edo-overlay .block--hero.is-align-left .block__body,
.edo-overlay .block--hero.is-align-left .block__heading { max-width: 44ch; }

.edo-overlay .block__animation { margin-bottom: var(--space-md); }

/* ---------- Two column ---------- */

.edo-overlay .block--two-column:not(.has-bg) { background: var(--color-surface); }

.edo-overlay .block__inner--split {
  display: grid;
  gap: var(--space-xl);
  grid-template-columns: 1fr;
  align-items: center;
}

@media (min-width: 900px) {
  .edo-overlay .block__inner--split { grid-template-columns: 1fr 1fr; }
  .edo-overlay .block--two-column.is-reversed .block__col--content { order: 2; }
  .edo-overlay .block--two-column.is-reversed .block__col--widget { order: 1; }
}

.edo-overlay .block__col--widget { min-height: var(--widget-height, 60vh); }

.edo-overlay .widget-placeholder {
  display: grid;
  place-items: center;
  height: var(--widget-height, 60vh);
  border: var(--border-width) dashed var(--color-border);
  border-radius: var(--radius-md);
  color: var(--color-ink-muted);
  background: var(--color-surface-alt);
  font-size: var(--size-small);
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

/* ---------- Stats ---------- */

.edo-overlay .block--stats { text-align: center; }
/* Only the version with no photograph needs a surface of its own. */
.edo-overlay .block--stats:not(.has-bg) { background: var(--color-surface-alt); }

/* "OUR IMPACT" is a section heading, not a hero one: 48px, matching the 47px
   the live page renders it at. */
.edo-overlay .block--stats .block__heading {
  font-size: var(--size-h2);
  text-transform: uppercase;
  margin-bottom: var(--space-xl);
}

.edo-overlay .stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: var(--space-lg);
  margin: 0;
}

/*
  Outlined boxes, not bare numbers. Over a photograph a hairline box is what
  holds four unequal figures together as one set; without it they float and
  the section stops reading as a unit.
*/
.edo-overlay .stats__item {
  margin: 0;
  padding: var(--space-lg) var(--space-md);
  border: var(--border-width) solid currentColor;
}
/* Off a photograph the box would be a heavy navy rectangle, so it goes. */
.edo-overlay .block--stats:not(.has-bg) .stats__item { border: 0; padding: 0; }

/*
  The stat figures are the h3 tier on this slide: 38px at the top of the clamp,
  weight 800, one step down from the 900 the headings carry. They were running
  at 56px and outshouting "OUR IMPACT" above them.
*/
.edo-overlay .stats__value {
  font-family: var(--font-display);
  font-weight: var(--weight-h3);
  font-size: var(--size-stat);
  line-height: var(--leading-tight);
  color: inherit;
}
.edo-overlay .block--stats:not(.has-bg) .stats__value { color: var(--color-accent); }

.edo-overlay .stats__label {
  margin: var(--space-xs) 0 0;
  color: inherit;
  font-size: var(--size-body);
  font-weight: 700;
  text-transform: none;
  letter-spacing: 0;
  line-height: var(--leading-tight);
}
.edo-overlay .block--stats:not(.has-bg) .stats__label { color: var(--color-ink-muted); }

/* ---------- Carousel ---------- */

/*
  :not(.has-bg) on both, and it matters.

  These are `background` shorthands, so they reset background-image to none.
  .is-testimonials is three classes deep and sits later in the file than
  .block.has-bg, so it won that cascade and quietly wiped the partner-quotes
  photograph even though the lazy loader had done its job. A surface colour
  should only apply where there is no photograph to show.
*/
.edo-overlay .block--carousel:not(.has-bg) { background: var(--color-surface); }
.edo-overlay .block--carousel.is-testimonials:not(.has-bg) { background: var(--color-surface-alt); }

.edo-overlay .carousel { position: relative; margin-bottom: var(--space-lg); }

.edo-overlay .carousel__track {
  display: flex;
  gap: var(--space-md);
  margin: 0;
  padding: 0 0 var(--space-md);
  list-style: none;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  /* Jonah, 2026-08-26: no scrollbar on a carousel. Progress is the dots. */
  scrollbar-width: none;
  -ms-overflow-style: none;
  /* Vertical page snap must not fight horizontal track scrolling. */
  overscroll-behavior-x: contain;
}

.edo-overlay .carousel__item {
  flex: 0 0 auto;
  scroll-snap-align: start;
  width: min(320px, 78vw);
}

/*
  The item hugs its plate. It used to be a fixed 180px around a 132px plate,
  which left 48px of dead air inside every item on top of the track's gap, and
  the strip read as very loosely spaced.
*/
.edo-overlay .is-logos .carousel__item { width: auto; }
.edo-overlay .is-testimonials .carousel__item { width: min(420px, 84vw); }

.edo-overlay .carousel__track::-webkit-scrollbar { display: none; }

/* Arrow, dots, arrow. Centred under the track. */
.edo-overlay .carousel__controls {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-md);
  margin-top: var(--space-md);
}

.edo-overlay .carousel__dots {
  display: flex;
  align-items: center;
  gap: var(--space-xs);
}

.edo-overlay .carousel__dot {
  width: 10px;
  height: 10px;
  padding: 0;
  border: 1px solid var(--color-ink);
  border-radius: 999px;
  background: transparent;
  cursor: pointer;
  transition: background-color var(--motion-fast) var(--easing);
}

.edo-overlay .carousel__dot[aria-selected="true"] {
  background: var(--color-accent-alt);
  border-color: var(--color-accent-alt);
}

/* The dots are the smallest thing on the page, so give them a real hit area
   without making them look bigger. */
.edo-overlay .carousel__dot::before {
  content: "";
  position: absolute;
  inset: -10px;
}
.edo-overlay .carousel__dot { position: relative; }

.edo-overlay .carousel__btn {
  display: grid;
  place-items: center;
  width: 2.5rem;
  height: 2.5rem;
  padding: 0;
  border-radius: var(--radius-pill);
  border: var(--border-width) solid var(--color-ink);
  background: transparent;
  color: var(--color-ink);
  cursor: pointer;
  transition: background-color var(--motion-fast) var(--easing),
              color var(--motion-fast) var(--easing);
}
.edo-overlay .carousel__btn svg { width: 1.1rem; height: 1.1rem; }
.edo-overlay .carousel__btn:hover {
  background: var(--color-ink);
  color: var(--color-surface);
}
/*
  Below 900px the arrows drop out of the absolute positioning above and back
  into the control row, where the desktop rule that fills them navy no longer
  applies. Without this they render as a transparent button with a navy border
  on a dark slide, which reads as white. Jonah, 2026-08-28: keep them blue.
*/
@media (max-width: 899px) {
  .edo-overlay .carousel__btn {
    background: var(--color-ink);
    border-color: var(--color-ink);
    color: var(--color-surface);
  }
}

/* No disabled state any more: the track loops rather than dead-ending. */

/* ---------- Cards ---------- */

.edo-overlay .card { height: 100%; }

.edo-overlay .card--blog {
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  overflow: hidden;
  padding-bottom: var(--space-md);
}
/* Fixed ratio box, so a card with no picture still occupies the same space. */
.edo-overlay .card__media {
  aspect-ratio: 16 / 9;
  width: 100%;
  background: var(--color-surface-alt);
  overflow: hidden;
}
.edo-overlay .card__image {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.edo-overlay .card__title {
  margin: var(--space-md) var(--space-md) 0;
  font-size: var(--size-h3);
  line-height: var(--leading-tight);
}
.edo-overlay .card__title a { text-decoration: none; }
.edo-overlay .card__title a:hover { text-decoration: underline; }
.edo-overlay .card__excerpt {
  margin: 0 var(--space-md);
  color: var(--color-ink-muted);
  font-size: var(--size-small);
}

/*
  Partner logos arrive in every shape and format: transparent PNGs, JPEGs with
  baked-in white boxes, the odd SVG, some square and some wide. A fixed box
  with `contain` is what makes a row of them read as one set.

  No grayscale filter. That was an invention on my part, nobody asked for it,
  and on the JPEGs with white backgrounds it just looked like a mistake.
*/
.edo-overlay .card--logo {
  display: grid;
  place-items: center;
  height: 100%;
  min-height: 110px;
  padding: var(--space-md);
  background: var(--color-surface);
  border-radius: var(--radius-md);
}
.edo-overlay .card--logo img {
  max-height: 72px;
  max-width: 100%;
  width: auto;
  object-fit: contain;
}

.edo-overlay .card--quote {
  margin: 0;
  padding: var(--space-lg);
  background: var(--color-surface-alt);
  border-radius: var(--radius-md);
}
.edo-overlay .card__quote {
  margin: 0 0 var(--space-md);
  font-size: var(--size-h3);
  line-height: var(--leading-body);
}
.edo-overlay .card__attribution { display: flex; flex-direction: column; }
.edo-overlay .card__name { font-weight: var(--weight-display); }
.edo-overlay .card__role { color: var(--color-ink-muted); font-size: var(--size-small); }

/* ---------- Accordion ---------- */

.edo-overlay .block--accordion:not(.has-bg) { background: var(--color-surface); }

.edo-overlay .accordion__item { border-bottom: 1px solid var(--color-border); }
.edo-overlay .accordion__q {
  padding: var(--space-md) 0;
  font-weight: var(--weight-display);
  font-size: var(--size-h3);
  cursor: pointer;
}
.edo-overlay .accordion__a { padding-bottom: var(--space-md); color: var(--color-ink-muted); }

/* ---------- CTA band ---------- */

.edo-overlay .block--cta-band {
  background: var(--color-surface-invert);
  color: var(--color-ink-invert);
  text-align: center;
}
.edo-overlay .block--cta-band .block__actions { justify-content: center; }

/* ---------- Dev only ---------- */

.edo-overlay .block--unknown {
  background: var(--color-surface-alt);
  border-block: var(--border-width) dashed var(--color-accent-alt);
}

/* ---------- Cards ---------- */

.edo-overlay .block--cards:not(.has-bg) { background: var(--color-surface); }

.edo-overlay .cards {
  display: grid;
  grid-template-columns: repeat(var(--card-columns, 3), 1fr);
  gap: var(--space-lg);
  margin: 0;
  padding: 0;
  list-style: none;
}

/*
  These never applied. Written as bare `.cards`, they lost to
  `.edo-overlay .cards` above on specificity at every width, so a four-column
  grid stayed four columns on a 375px phone: 143px tiles running off the right
  edge, clipped rather than scrolled. Found 2026-09-14 on the homepage, but
  every card grid on every overlay page had it -- Toolkits, Take Action and
  Quizzes included. Prefixed now, and placed after the rule they override.
*/
@media (max-width: 900px) {
  .edo-overlay .cards { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 600px) {
  .edo-overlay .cards { grid-template-columns: minmax(0, 1fr); }
}

.edo-overlay .cards__item { display: flex; }

.edo-overlay .card--panel {
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
  width: 100%;
  padding: var(--space-lg);
  background: var(--color-surface-alt);
  border-radius: var(--radius-md);
  /* Cards that name a category accent get it as a top rule. Cards that do not
     fall back to the border colour, so the shape stays consistent either way. */
  border-top: 4px solid var(--card-accent, var(--color-border));
  text-decoration: none;
  transition: transform var(--motion-fast) var(--easing);
}

a.card--panel:hover { transform: translateY(-4px); }

.edo-overlay .card--panel .card__image {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  border-radius: var(--radius-sm);
  margin-bottom: var(--space-xs);
}

.edo-overlay .card--panel .card__title {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--size-h3);
  line-height: var(--leading-tight);
  color: var(--card-accent, var(--color-ink));
}

.edo-overlay .card--panel .card__excerpt { margin: 0; color: var(--color-ink-muted); }

/* On a stacked card the wrapper is a pass-through: it exists for the sideways
   one, and must not introduce a second flow context here. */
.edo-overlay .card--panel .card__text {
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
  min-width: 0;
}

/* Widget iframes fill their column and take the height from the data. */
.edo-overlay .widget-frame {
  display: block;
  width: 100%;
  height: var(--widget-height, 60vh);
  border: 0;
  border-radius: var(--radius-md);
  background: var(--color-surface-alt);
}

/* ---------- Button context ---------- */

/*
  The outline button on photography.

  White-on-transparent only works if what is behind it is reliably dark, and a
  photograph is not: on the partner-quotes slide the lobby is bright and the
  button all but disappeared. Rather than hope, it gets the same navy fill
  every other non-Donate button has, with a white edge to hold it against a
  busy picture. Outline keeps its transparent treatment on flat surfaces, where
  the contrast is known.
*/
.edo-overlay .block.has-bg .btn--outline {
  background: var(--color-ink);
  border-color: #ffffff;
  color: #ffffff;
}

/* The cta-band's panel is a known solid navy, so outline stays an outline. */
.edo-overlay .block--cta-band .btn--outline {
  --btn-outline-ink: #ffffff;
  background: transparent;
  border-color: #ffffff;
  color: #ffffff;
}

/*
  Navy stays navy on photography.

  An earlier version inverted these to white on any dark slide. That reads
  better in isolation but it breaks Jonah's rule -- "everything that is not
  Donate is dark blue with white text" -- and it does not match the parent,
  where the Explore button on the globe slide is navy over the sky.

  What it does get is a white edge, so the shape still separates from a busy
  photograph without changing the fill.
*/
/*
  No white edge on the blue buttons. It was added to hold them against busy
  photography; Jonah's call on 2026-08-28 is that the fill alone is enough and
  the outline read as a second, competing shape.
*/

/* ---------- Header animation ---------- */

/*
  The morph component sizes itself against the viewport (80vw wide on desktop,
  a fixed 150px tall on mobile). Inside a full-height hero that is one element
  deciding the layout on its own, and it pushed the body copy and buttons off
  the bottom of the screen.

  These cap it against the hero's height instead. Written more specifically
  than the component's own rules so they win without !important.
*/
.edo-overlay .block__animation {
  width: 100%;
  margin-bottom: var(--space-lg);
}

.edo-overlay .block__animation .earthday-morph-pair .desktop-stage svg {
  width: min(80vw, 1200px);
  max-height: 26vh;
  height: auto;
  margin-inline: auto;
}

.edo-overlay .block__animation .earthday-morph-pair .mobile-stage svg {
  width: 100%;
  height: auto;
  max-height: 18vh;
}

/* Short landscape phones have almost no vertical room to give away. */
@media (max-height: 560px) {
  .edo-overlay .block__animation .earthday-morph-pair .desktop-stage svg,
  .edo-overlay .block__animation .earthday-morph-pair .mobile-stage svg {
    max-height: 22vh;
  }
}

/*
  The wordmark is white, so it needs a dark hero. On a pale background it would
  be invisible, and that is a content mistake worth making obvious rather than
  silently unreadable.
*/
.edo-overlay .block[data-text="dark"] .block__animation .morph-stage path {
  fill: var(--color-ink) !important;
}

/* The 2026 wordmark sizes itself the same way its 2027 sibling does. */
.edo-overlay .block__animation .edo-morph-2026 .stage svg {
  width: min(80vw, 1200px);
  max-height: 26vh;
  height: auto;
  margin-inline: auto;
}
.edo-overlay .block__animation .edo-morph-2026 .stage.mobile-stage svg {
  width: 100%;
  height: auto;
  max-height: 18vh;
}

/*
  Image in a two-column. Height is driven by the picture rather than a fixed
  widget height, so a collage keeps its own proportions.
*/
/*
  Both the element and any image inside it.

  WP Rocket's WebP rewriting wraps our <img> in a <picture> and carries the
  class up onto the wrapper, so a rule written only for .block__media stopped
  applying to the actual image. Styling both means it does not matter which one
  the optimiser hands us.
*/
.edo-overlay .block--two-column .block__media,
.edo-overlay .block--two-column .block__media img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: var(--radius-md);
}
.edo-overlay .block__col--widget:has(.block__media) { min-height: 0; }

/* ---------- Subhead and attribution ---------- */

/*
  The hero's second line ("Our Power, Our Planet"). Display face, roughly half
  the display size, and it tracks with the heading above rather than with the
  body copy below, because it belongs to the title.
*/
.edo-overlay .block__subhead {
  margin: 0 0 var(--space-md);
  font-family: var(--font-display);
  font-weight: var(--weight-display);
  /* Its own step: bigger than a section h2, smaller than the wordmark. */
  font-size: var(--size-h1);
  line-height: var(--leading-tight);
  letter-spacing: var(--tracking-display, 0.03em);
  text-transform: uppercase;
  color: inherit;
}
.edo-overlay .block--hero.is-align-center .block__subhead { text-align: center; }

/*
  Attribution under a pull quote. Not italic: <cite> defaults to italic and the
  brand face has no italic cut, so the browser would synthesise a slanted
  Montserrat, which looks like a rendering fault rather than a design choice.
*/
.edo-overlay .block__attribution {
  display: block;
  margin: 0 0 var(--space-lg);
  font-style: normal;
  font-weight: 700;
  font-size: var(--size-body);
  color: inherit;
  opacity: 0.92;
}
.edo-overlay .block--hero.is-align-center .block__attribution { text-align: center; }

/* ---------- Secondary button ---------- */

/*
  The navy button. Used where an orange one would sit next to the orange
  Donate and the pair would read as one shape, as on "Missed an event".
*/
.edo-overlay .btn--secondary {
  background: var(--color-ink);
  border-color: var(--color-ink);
  color: #ffffff;
}
.edo-overlay .btn--secondary:hover,
.edo-overlay .btn--secondary:focus-visible {
  background: var(--color-accent-alt);
  border-color: var(--color-accent-alt);
  color: #ffffff;
}

/* ---------- FAQ ---------- */

/*
  The parent sets FAQ at display size and hangs it on the left margin rather
  than treating it as a normal section heading. It is the only word on the
  slide, so at h2 size it read as an afterthought.
*/
.edo-overlay .block--accordion .block__heading {
  font-size: var(--size-display);
  margin-bottom: var(--space-lg);
}

.edo-overlay .accordion__q {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-md);
  font-weight: var(--weight-body);
  color: var(--color-accent);
  list-style: none;
}
.edo-overlay .accordion__q::-webkit-details-marker { display: none; }
.edo-overlay .accordion__q::marker { content: ""; }

/*
  The +/- affordance. A pseudo-element rather than an icon: it is one
  character, it inherits colour for free, and there is no second file to keep
  in step with the type.
*/
.edo-overlay .accordion__q::after {
  content: "+";
  flex: 0 0 auto;
  font-size: 1.6em;
  line-height: 1;
  font-weight: var(--weight-body);
  transition: transform var(--motion-fast) var(--easing);
}
.edo-overlay .accordion__item[open] .accordion__q::after { content: "\2212"; }
.edo-overlay .accordion__q:hover { color: var(--color-accent-alt); }

/* ---------- Carousel: arrows beside the track ---------- */

/*
  The parent puts the arrows either side of the track and leaves only the dots
  underneath. Ours had arrow-dots-arrow in one row below, which reads as a
  media player rather than a carousel.

  Below 900px they go back under the track: at phone width a 40px control on
  each side eats a third of the card.
*/
@media (min-width: 900px) {
  .edo-overlay .carousel { padding-inline: calc(2.5rem + var(--space-md)); }

  .edo-overlay .carousel__controls {
    display: contents;
  }

  .edo-overlay .carousel__btn {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    z-index: 1;
    border-color: transparent;
    background: var(--color-ink);
    color: var(--color-surface);
  }
  .edo-overlay .carousel__btn[data-dir="-1"] { left: 0; }
  .edo-overlay .carousel__btn[data-dir="1"] { right: 0; }
  .edo-overlay .carousel__btn:hover {
    background: var(--color-accent-alt);
    color: #ffffff;
  }

  /*
    display:contents on the control row removed the box the dots were centred
    in, so they need their own.
  */
  .edo-overlay .carousel__dots {
    justify-content: center;
    margin-top: var(--space-md);
  }
}

/* ---------- Blog cards ---------- */

/*
  No border and no rounding on the parent's story cards: the picture is the
  edge. The border was making a row of them look like a table.
*/
.edo-overlay .card--blog {
  border: 0;
  background: transparent;
  /*
    Jonah, 2026-08-27: the space under the photo should equal the space between
    the photos. The track's column gap is --space-md, so the card's own flex gap
    goes to zero and the title's top margin carries that exact value. With both
    a gap and a margin the real distance was the sum of the two.
  */
  gap: 0;
  padding-bottom: 0;
}
.edo-overlay .card--blog .card__title,
.edo-overlay .card--blog .card__excerpt { margin-inline: 0; }

.edo-overlay .card--blog .card__title {
  margin-top: var(--space-md);
  color: var(--color-ink);
  font-size: var(--size-card-title);
  font-weight: var(--weight-card-title);
}

.edo-overlay .card--blog .card__excerpt {
  margin-top: var(--space-xs);
  color: var(--color-ink);
  /*
    Five lines, then it stops. Excerpt length is whatever an editor typed, and
    without a cap one long article makes its card twice the height of the row.
    The old -webkit- box properties are still the only thing that works here;
    line-clamp on its own is not supported widely enough yet.
  */
  display: -webkit-box;
  -webkit-line-clamp: 5;
  line-clamp: 5;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.edo-overlay .block--carousel.is-blog .block__heading {
  font-size: var(--size-h2);
  text-align: center;
  margin-bottom: var(--space-xl);
}

/* ---------- Carousel label pill ---------- */

/*
  A manually authored tag in the top-left of a story photo, e.g. "Earth Day
  2026". Not a category: it is typed per item in the carousel, so it says
  whatever the editor needs it to say.
*/
.edo-overlay .card__media { position: relative; }

.edo-overlay .card__label {
  position: absolute;
  top: var(--space-sm);
  left: var(--space-sm);
  z-index: 1;
  margin: 0;
  padding: 0.35em 0.85em;
  /* 70% so the photograph reads through it. rgb()/alpha rather than the
     opacity property, which would fade the label text along with the plate. */
  background: rgb(32 71 142 / 0.7);
  color: var(--color-ink-invert);
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--size-small);
  line-height: 1.2;
  letter-spacing: 0.02em;
  border-radius: var(--radius-pill);
}

/* ---------- Partner logo band ---------- */

/*
  On the parent this is not a slide, it is a thin blue strip under the quote:
  "Our Partners" on the left, the logos running through the middle, and a link
  to the full list on the right. Ours was a full-height section with a heading
  above a row of logos, which is why the page had one more screen than the
  original.

  It runs with "snap": false in the data, so it rides along under the section
  above rather than claiming a viewport of its own.
*/
.edo-overlay .block--carousel.is-logos {
  min-height: 0;
  padding-block: var(--space-md);
  background: var(--color-ink);
  color: var(--color-ink-invert);
}

.edo-overlay .block--carousel.is-logos .block__inner {
  display: flex;
  align-items: center;
  gap: var(--space-lg);
  max-width: none;
}

.edo-overlay .block--carousel.is-logos .block__heading,
.edo-overlay .block--carousel.is-logos .block__actions {
  flex: 0 0 auto;
  margin: 0;
}
.edo-overlay .block--carousel.is-logos .block__heading {
  font-size: var(--size-h3);
  color: inherit;
}

.edo-overlay .block--carousel.is-logos .carousel {
  flex: 1 1 auto;
  min-width: 0;
  margin: 0;
  padding-inline: 0;
}
.edo-overlay .block--carousel.is-logos .carousel__track {
  padding-bottom: 0;
  gap: var(--space-sm);
}

/*
  White plate behind each mark: the set includes transparent PNGs that would
  vanish on the blue, and JPEGs that already carry their own white box.

  Every plate is the same fixed size and the mark is centred inside it with
  `contain`. Without the fixed box a tall stacked logo renders a third of the
  height of a wide one, which is what made the fourth mark look shrunken.
*/
.edo-overlay .block--carousel.is-logos .card--logo {
  --plate-w: 132px;
  --plate-h: 66px;
  --plate-pad: 8px;

  min-height: 0;
  width: var(--plate-w);
  height: var(--plate-h);
  padding: var(--plate-pad);
  background: var(--color-surface);
  overflow: hidden;
}

/*
  Pixel constraints, not percentages.

  Two earlier attempts failed for the same underlying reason. `max-height: 100%`
  and then `height: 100%` both need the containing block to have a definite
  height, and inside a grid item whose row is auto-sized that is a cyclic
  dependency: the row wants to size to its content, the content wants to size to
  the row, and the browser resolves the percentage to auto. The image then
  rendered at its intrinsic size and was sliced by the plate.

  WP Rocket also rewrites most of these into <picture><source webp><img>, so
  both elements are constrained. Styling only the <img> left it resolving
  against an auto-sized wrapper, which is the same failure one level down.

  Deriving the caps from the plate's own custom properties means the two cannot
  drift apart, and `width/height: auto` lets each mark keep its proportions and
  simply scale until it fits.
*/
.edo-overlay .block--carousel.is-logos .card--logo picture,
.edo-overlay .block--carousel.is-logos .card--logo img {
  display: block;
  width: auto;
  height: auto;
  max-width: calc(var(--plate-w) - var(--plate-pad) * 2);
  max-height: calc(var(--plate-h) - var(--plate-pad) * 2);
  object-fit: contain;
}

.edo-overlay .block--carousel.is-logos .carousel__controls { display: none; }

/* ---------- Partner strip: the marquee ---------- */

/*
  The strip runs itself. There are more partners than fit, and a row that has
  to be dragged is a row nobody reads to the end of.

  app.js clones the track's contents once and sets --marquee-width to the width
  of the original set. Translating by exactly that distance means the copy is
  sitting precisely where the original started when the animation restarts, so
  the loop has no seam. Duplicating in JS rather than PHP keeps each partner
  link in the markup once, which is what a crawler should see.
*/
/*
  The clip goes on the wrapper, not on the thing that moves.

  `overflow: hidden` clips an element's children, never the element itself, so
  putting it on the track and then translating the track slid the whole strip
  bodily to the left -- straight over the "Our Partners" heading beside it, and
  leaving a gap behind as it went. The wrapper is what defines the window; the
  track is what travels through it.
*/
.edo-overlay .block--carousel.is-logos .carousel {
  overflow: hidden;
  /*
    Faded edges rather than a hard cut, so logos enter and leave instead of
    being sliced off at the boundary. A mask fades the strip itself, which
    works over the blue band without needing a gradient overlay that would have
    to know the background colour.
  */
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 4%, #000 96%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 4%, #000 96%, transparent);
}

.edo-overlay .block--carousel.is-logos .carousel__track {
  overflow: visible;
  scroll-snap-type: none;
  /* Content-driven, so it is never squeezed to the wrapper's width. */
  width: max-content;
  flex-wrap: nowrap;
}

.edo-overlay .block--carousel.is-logos.is-marquee .carousel__track {
  animation: edo-marquee var(--marquee-duration, 60s) linear infinite;
  will-change: transform;
}

/* Stop it while someone is reading, or trying to click a partner. */
.edo-overlay .block--carousel.is-logos.is-marquee:hover .carousel__track,
.edo-overlay .block--carousel.is-logos.is-marquee:focus-within .carousel__track {
  animation-play-state: paused;
}

@keyframes edo-marquee {
  from { transform: translateX(0); }
  to   { transform: translateX(calc(-1 * var(--marquee-width, 50%))); }
}

/* Continuous motion is exactly what reduced-motion asks us not to do. */
@media (prefers-reduced-motion: reduce) {
  .edo-overlay .block--carousel.is-logos.is-marquee .carousel__track {
    animation: none;
  }
  /* No animation means it has to be reachable by hand, so give the window its
     scrollbar back rather than hiding the partners past the fold. */
  .edo-overlay .block--carousel.is-logos .carousel { overflow-x: auto; }
}

/*
  Mobile. The band stacked into a column and the track lost its width, so the
  logos collapsed to nothing. Heading and link sit on one row above, and the
  strip runs full width underneath at a slightly smaller plate.
*/
@media (max-width: 900px) {
  .edo-overlay .block--carousel.is-logos .block__inner {
    display: grid;
    grid-template-columns: auto auto;
    justify-content: space-between;
    align-items: center;
    gap: var(--space-sm);
    text-align: left;
  }
  .edo-overlay .block--carousel.is-logos .carousel {
    grid-column: 1 / -1;
    width: 100%;
  }
  .edo-overlay .block--carousel.is-logos .block__heading { font-size: var(--size-body); }
  .edo-overlay .block--carousel.is-logos .card--logo { --plate-w: 112px; --plate-h: 58px; }
}

/* ---------- Partner quotes over a photograph ---------- */

/*
  One card, centred, white on the photo. The parent shows a single quote at a
  time rather than a row of them, and the arrows sit outside the card.
*/
/*
  One quote at a time, filling the track.

  It was 880px inside a ~1080px track, so the next card leaned in from the
  right edge, which reads as a layout accident rather than a carousel. The
  parent shows one card, centred, with the arrows outside it.
*/
.edo-overlay .block--carousel.is-testimonials .carousel__item {
  width: 100%;
}

/*
  The card has to lift off the photograph.

  A white panel on a bright picture -- and the Abu Dhabi lobby is very bright
  -- has almost no edge, so the two planes merge. The shadow is what separates
  them. Warm-neutral and offset downwards rather than a flat black glow,
  because this is an object sitting above the image, not text on top of it.
*/
.edo-overlay .block--carousel.is-testimonials .card--quote {
  position: relative;
  padding: var(--space-xl);
  background: var(--color-surface);
  color: var(--color-ink);
  box-shadow: 0 18px 44px rgb(0 0 0 / 0.34);
}

/*
  ...but only over a photograph.

  That shadow is sized to lift a white card off a bright picture. On the
  homepage's donor quotes there is no picture -- the card sits on the pale
  tint -- and a 44px black blur with nothing to separate from just reads as a
  smudge under the box. Steve, 2026-09-16: "this shadow looks like shit".
  Without artwork behind it the card needs an edge, not a lift.
*/
.edo-overlay .block--carousel.is-testimonials:not(.has-bg) .card--quote {
  box-shadow: none;
  border: var(--border-width) solid var(--color-border);
}
.edo-overlay .block--carousel.is-testimonials .card__quote {
  font-size: var(--size-body);
  color: var(--color-ink);
}
.edo-overlay .block--carousel.is-testimonials .card__name,
.edo-overlay .block--carousel.is-testimonials .card__role { color: var(--color-ink); }

/* The oversized quote marks the parent hangs off the card corners. */
.edo-overlay .block--carousel.is-testimonials .card--quote::before,
.edo-overlay .block--carousel.is-testimonials .card--quote::after {
  position: absolute;
  font-family: var(--font-display);
  font-weight: var(--weight-display);
  font-size: 4rem;
  line-height: 1;
  color: var(--color-ink);
  pointer-events: none;
}
.edo-overlay .block--carousel.is-testimonials .card--quote::before {
  content: "\201C";
  top: var(--space-sm);
  left: var(--space-md);
}
.edo-overlay .block--carousel.is-testimonials .card--quote::after {
  content: "\201D";
  right: var(--space-md);
  bottom: 0;
}

.edo-overlay .block--carousel.is-testimonials .block__actions {
  justify-content: center;
  margin-top: var(--space-lg);
}

/* ---------- Closing CTA ---------- */

/*
  The parent's closing slide is a photograph with a solid blue panel of stacked
  links over it, not a row of pill buttons. The data is still buttons, because
  that is what they are; only the presentation changes here.
*/
/* background-color, never the shorthand: the shorthand would reset the photo. */
.edo-overlay .block--cta-band {
  background-color: var(--color-surface-invert);
  text-align: center;
}

.edo-overlay .block--cta-band .block__inner {
  max-width: var(--container-narrow);
}

.edo-overlay .block--cta-band .block__heading {
  font-size: var(--size-display);
}

/*
  The panel now wraps the links AND the social row, so the blue is on the
  wrapper. It used to be on .block__actions, which meant anything added below
  the links fell outside the blue and floated on the photograph.
*/
.edo-overlay .block--cta-band .block__panel {
  padding: var(--space-md) var(--space-lg) var(--space-lg);
  background: var(--color-ink);
  text-align: left;
}

.edo-overlay .block--cta-band .block__actions {
  flex-direction: column;
  gap: 0;
}

/*
  The globe. Sized here rather than in the asset so the same slot works for an
  uploaded image or a drawn partial. The parent's file is 148px square and it
  is used at close to full size, not as a small icon.
*/
.edo-overlay .block__icon {
  display: block;
  width: clamp(4rem, 2.5rem + 4vw, 5.5rem);
  height: auto;
  margin: 0 auto var(--space-md);
  color: inherit;
}

/* ---------- Social row ---------- */

.edo-overlay .block__social-label {
  margin: 0;
  padding: var(--space-sm) 0;
  font-family: var(--font-display);
  font-weight: var(--weight-display);
  font-size: var(--size-small);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--color-ink-invert);
  border-bottom: 1px solid rgb(255 255 255 / 0.35);
}

.edo-overlay .social {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: var(--space-md);
  margin: var(--space-md) 0 0;
  padding: 0;
  list-style: none;
}

.edo-overlay .social__item { display: flex; }

/*
  A 24px glyph is well under the 44px minimum for a touch target, so the link
  is padded out to a real one and the icon just sits inside it.
*/
.edo-overlay .social__link {
  display: grid;
  place-items: center;
  width: 2.75rem;
  height: 2.75rem;
  color: var(--color-ink-invert);
  text-decoration: none;
  transition: color var(--motion-fast) var(--easing);
}
.edo-overlay .social__link:hover,
.edo-overlay .social__link:focus-visible { color: var(--color-accent-3); }

.edo-overlay .social__icon {
  width: 1.5rem;
  height: 1.5rem;
}

.edo-overlay .block--cta-band .block__actions .btn {
  padding: var(--space-sm) 0;
  border: 0;
  border-bottom: 1px solid rgb(255 255 255 / 0.35);
  background: none;
  color: var(--color-ink-invert);
  text-align: left;
}
/* Only drop the rule on the final link when nothing follows the list. */
.edo-overlay .block--cta-band .block__actions:last-child .btn:last-child { border-bottom: 0; }
.edo-overlay .block--cta-band .block__actions .btn:hover,
.edo-overlay .block--cta-band .block__actions .btn:focus-visible {
  background: none;
  color: var(--color-accent-3);
}

/* ---------- Two column: the copy side ---------- */

/*
  The parent's split sections are navy copy on white with a picture beside
  them. Content column takes the narrow measure so the paragraph does not run
  the full half-width at desktop.
*/
.edo-overlay .block--two-column .block__col--content .block__body,
.edo-overlay .block--two-column .block__col--content .block__heading { max-width: 32ch; }
.edo-overlay .block--two-column .block__heading { font-size: var(--size-h2); }

/* ---------- Carousel controls on a photograph ---------- */

/*
  The dots and arrows are drawn in --color-ink, which is navy, and on the
  partner-quotes photograph that is navy on a dark lobby floor: present in the
  DOM, invisible to a reader. On any light-text block they invert.
*/
.edo-overlay .block.has-bg[data-text="light"] .carousel__dot {
  border-color: var(--color-ink-invert);
}
.edo-overlay .block.has-bg[data-text="light"] .carousel__dot[aria-selected="true"] {
  background: var(--color-accent-alt);
  border-color: var(--color-accent-alt);
}
.edo-overlay .block.has-bg[data-text="light"] .carousel__btn {
  background: var(--color-ink-invert);
  color: var(--color-ink);
}
.edo-overlay .block.has-bg[data-text="light"] .carousel__btn:hover {
  background: var(--color-accent-alt);
  color: #ffffff;
}

/* ---------- Eyebrow ---------- */

/*
  The label above a heading ("Toolkits", "Quizzes"). Set small, in the display
  face, and in the accent so it reads as a tag rather than as a small heading.
  A paragraph, not a heading: the section already has one.
*/
.edo-overlay .block__eyebrow {
  margin: 0 0 var(--space-xs);
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--size-small);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--color-accent-alt);
}

/* ---------- Section nav ---------- */

/*
  A row of jump links. Wraps rather than scrolls: there are only ever a handful
  and a second line on a phone is easier to use than a hidden overflow.
*/
.edo-overlay .block--section-nav { min-height: 0; }
.edo-overlay .block--section-nav:not(.has-bg) { background: var(--color-surface); }
.edo-overlay .block--section-nav .block__inner { text-align: center; }

.edo-overlay .section-nav__list {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--space-sm) var(--space-md);
  margin: 0;
  padding: 0;
  list-style: none;
}

.edo-overlay .section-nav__link {
  display: inline-block;
  padding: 0.7rem 1.6rem;
  border: var(--border-width) solid var(--color-ink);
  border-radius: var(--radius-pill);
  color: var(--color-ink);
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--size-small);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  text-decoration: none;
  transition: transform var(--motion-fast) var(--easing);
}

/* Same rule as the buttons: grow, never recolour. */
@media (hover: hover) {
  .edo-overlay .section-nav__link:hover { transform: scale(1.06); }
}
.edo-overlay .section-nav__link:focus-visible { transform: scale(1.06); }

@media (prefers-reduced-motion: reduce) {
  .edo-overlay .section-nav__link:hover,
  .edo-overlay .section-nav__link:focus-visible { transform: none; }
}

/* On a photograph the chips invert, like the outline button does. */
.edo-overlay .block--section-nav.has-bg[data-text="light"] .section-nav__link {
  border-color: #ffffff;
  color: #ffffff;
}

/* ---------- Hub card rows ---------- */

/*
  The hub's cards are a picture with a title under it and nothing else: the
  whole card is the link. No panel, no top rule, no tinted background -- those
  belong to the 2027 "focus areas" cards, which carry body copy.
*/
.edo-overlay .block--cards .card--panel {
  padding: 0;
  background: transparent;
  border-top: 0;
}
.edo-overlay .block--cards .card--panel .card__image {
  aspect-ratio: 16 / 9;
  border-radius: 0;
  margin-bottom: var(--space-sm);
}
.edo-overlay .block--cards .card--panel .card__title {
  font-size: var(--size-card-title);
  font-weight: var(--weight-card-title);
  color: var(--color-ink);
}
/*
  Card tiles, not billboards.

  On a deck slide the grid can fill the container, because the slide has a
  whole screen to fill. On a flow page it must not: two cards stretched across
  a 1200px container gave 590px-wide tiles with 330px of photograph, which is
  most of the reason a card row here was twice the height of the parent's.
  Measured on prod 2026-09-06, its tiles are 280x160. Capping the track rather
  than the card keeps the gap even; the single-column phone layout below 600px
  is left alone, where a capped track would look stranded.
*/
/* From 901px: below that the two-column tablet rule near the top of the file
   has to be free to apply, and this one outranks it. */
@media (min-width: 901px) {
  .edo-page.is-flow .block--cards .cards {
    grid-template-columns: repeat(var(--card-columns, 3), minmax(0, 340px));
    justify-content: start;
  }
}

/*
  A card with no picture.

  The toolkits page is a list of documents, not a gallery: the parent gives
  each one a title and a VIEW NOW button. Without an image our card collapsed
  to a bare line of text with nothing saying it was a link, so an imageless
  card gets the affordance back as a rule and an arrow rather than by inventing
  a per-item button field. :not(:has()) means the data decides -- add a picture
  later and the card becomes a picture card with no edit here.
*/
.edo-overlay .block--cards a.card--panel:not(:has(.card__image)) {
  padding: var(--space-md) 0;
  border-top: var(--border-width) solid var(--color-border);
}
.edo-overlay .block--cards a.card--panel:not(:has(.card__image)) .card__title::after {
  content: " →";
  color: var(--color-accent-alt);
}
@media (hover: hover) {
  .edo-overlay .block--cards a.card--panel:not(:has(.card__image)):hover { transform: none; }
  .edo-overlay .block--cards a.card--panel:not(:has(.card__image)):hover .card__title {
    text-decoration: underline;
  }
}

.edo-overlay .block--cards .block__heading { font-size: var(--size-h3); }
.edo-overlay .block--cards .block__actions { margin-top: var(--space-lg); }

/* ---------- Page header: title band, then breadcrumb and share ---------- */

/*
  The sub-pages all open the same way on the parent: a deep navy band carrying
  a small label and a big title, then a thin light strip with the breadcrumb on
  one side and the share links on the other. Measured 2026-09-06, the band is
  flush to the header above it with no gap, which is why it cancels the flow
  page's top padding rather than adding to it.
*/
.edo-overlay .block--page-header {
  background: var(--color-surface-invert);
  color: var(--color-ink-invert);
}
.edo-overlay .block--page-header .block__heading,
.edo-overlay .block--page-header .block__body { color: var(--color-ink-invert); }
.edo-overlay .block--page-header .block__eyebrow { color: var(--color-ink-invert); }
.edo-overlay .block--page-header .block__heading {
  font-size: var(--size-h1);
  text-transform: uppercase;
  margin-bottom: 0;
}
/*
  The tagline under the title, not a second title.

  .block__subhead is sized as a heading because in a hero it IS the h1. Here
  the heading above it already is, so inheriting that gave the pillar pages
  "HEALTHY PEOPLE / FOOD SHOULD NOURISH US, NOT HARM US." in one 42px block of
  caps, reading as a single run-on title. Jonah's design sets it in sentence
  case, bold, about half the size.
*/
.edo-overlay .block--page-header .block__subhead {
  font-size: var(--size-h3);
  font-weight: 700;
  text-transform: none;
  line-height: 1.3;
  color: var(--color-ink-invert);
  margin: var(--space-sm) 0 0;
  max-width: var(--container-narrow);
}
.edo-overlay .block--page-header .block__body {
  max-width: var(--container-narrow);
  margin-top: var(--space-md);
}

/* The strip is not a .block: it is the underline of the band above it. */
.edo-overlay .page-strip {
  background: var(--color-surface);
  border-bottom: var(--border-width) solid var(--color-border);
  padding-inline: var(--gutter);
}
.edo-overlay .page-strip__inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-sm) var(--space-lg);
  width: 100%;
  max-width: var(--container);
  margin-inline: auto;
  padding-block: var(--space-sm);
}

.edo-overlay .crumbs__list {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-xs);
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: var(--size-small);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
/* The separator is drawn, not typed, so it never lands in a copied selection
   or gets read out as a word. */
.edo-overlay .crumbs__item + .crumbs__item::before {
  content: "";
  display: inline-block;
  width: 0.5em;
  height: 0.5em;
  margin-right: var(--space-xs);
  border-top: 1.5px solid var(--color-border);
  border-right: 1.5px solid var(--color-border);
  transform: rotate(45deg) translateY(-0.1em);
}
.edo-overlay .crumbs__link { color: var(--color-ink-muted); text-decoration: none; }
.edo-overlay .crumbs__link:hover { text-decoration: underline; }
.edo-overlay .crumbs__current { color: var(--color-ink); font-weight: 700; }

.edo-overlay .share {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
}
.edo-overlay .share__label {
  margin: 0;
  font-size: var(--size-small);
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--color-ink-muted);
}
/*
  The compact row is a different animal from the one in the page footer.

  The base .social is built for the closing CTA band, where the icons sit in a
  column UNDER their label and want a margin above them. Reused in the strip
  they inherited that margin, which dropped the icons 10px below the word SHARE
  and made the whole strip 20px taller than it should be. Measured 2026-09-06:
  label centre 443.2, icon centre 453.2. Everything else on that line -- the
  breadcrumb, the label -- already shared one centreline; only this did not.

  Three icons on one line also never wrap, so the wrapping the base rule allows
  is only a way for them to break onto a second row at an awkward width.
*/
.edo-overlay .social--compact {
  gap: var(--space-xs);
  margin: 0;
  flex-wrap: nowrap;
  justify-content: flex-start;
}
.edo-overlay .social--compact .social__link {
  width: 30px;
  height: 30px;
  border: var(--border-width) solid var(--color-border);
  border-radius: 50%;
  color: var(--color-ink);
}
.edo-overlay .social--compact .social__icon { width: 14px; height: 14px; }

/* ---------- Pull quote ---------- */

/*
  A blockquote, not a heading. The quotation marks are drawn by the block so
  the text in the data stays clean and an editor cannot end up with two sets.
*/
.edo-overlay .block--quote { background: var(--color-surface-alt); }
.edo-overlay .pullquote {
  max-width: var(--container-narrow);
  margin: 0 auto;
  text-align: center;
}
.edo-overlay .pullquote__text {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--size-h3);
  line-height: var(--leading-tight);
  color: var(--color-accent-alt);
  text-wrap: balance;
}
.edo-overlay .pullquote__text p { margin: 0; }
.edo-overlay .pullquote__text p::before { content: "\201C"; }
.edo-overlay .pullquote__text p::after { content: "\201D"; }
.edo-overlay .pullquote__cite {
  margin-top: var(--space-md);
  font-size: var(--size-small);
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--color-ink-muted);
}

/* ---------- Icon cards ---------- */

/*
  For a row of documents rather than a gallery.

  The parent renders each toolkit as a 1110x210 navy capsule, one per row --
  eight of them is a very long page and every one looks the same. Steve, 2026-
  09-06: two per row, with a mark drawn for each. The mark carries the card's
  accent so the grid has a rhythm the parent's does not, and the accent is data
  (`accent` on the item) rather than an nth-child rule, so reordering the list
  in WordPress cannot shuffle the colours out from under it.
*/
.edo-overlay .block--cards .card__tile {
  display: grid;
  place-items: center;
  flex: none;
  width: 88px;
  height: 88px;
  background: var(--card-accent, var(--color-accent));
  color: var(--color-ink-invert);
  border-radius: var(--radius-md);
}
.edo-overlay .block--cards .card__tile .tile__icon { width: 44px; height: 44px; }

/*
  The icon preset lays the card out sideways: mark on the left, title and its
  affordance on the right. It reads as a row you can act on rather than as a
  poster, which is what a link to a document should look like.
*/
.edo-overlay .block--cards.is-icon a.card--panel,
.edo-overlay .block--cards.is-icon .card--panel {
  flex-direction: row;
  align-items: center;
  gap: var(--space-md);
  padding: var(--space-md);
  background: var(--color-surface-alt);
  border-top: 0;
  border-left: 4px solid var(--card-accent, var(--color-accent));
}

/* The copy stacks beside the tile: title, then what tapping it does. */
.edo-overlay .block--cards.is-icon .card__text {
  display: flex;
  flex-direction: column;
  gap: var(--space-2xs);
  min-width: 0;
}
.edo-overlay .block--cards.is-icon .card--panel .card__title {
  font-size: var(--size-body);
  font-weight: 700;
  line-height: var(--leading-tight);
  color: var(--color-ink);
}
/* The arrow rule for imageless cards is for a bare list; these have a tile. */
.edo-overlay .block--cards.is-icon a.card--panel .card__title::after { content: none; }
.edo-overlay .block--cards.is-icon .card__actions {
  margin-top: var(--space-2xs);
  font-size: var(--size-small);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-accent-alt);
}
@media (hover: hover) {
  .edo-overlay .block--cards.is-icon a.card--panel:hover { transform: translateY(-2px); }
  .edo-overlay .block--cards.is-icon a.card--panel:hover .card__title { text-decoration: underline; }
}

/* Two up is the point of the preset, so it does not read the column count. */
@media (min-width: 701px) {
  .edo-page.is-flow .block--cards.is-icon .cards {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    justify-content: stretch;
  }
}

/*
  The call to action sits on the floor of the card.

  Titles run to one line or three depending on the quiz, and a cta that follows
  the title straight down leaves a row of them at four different heights. This
  is why the text side is a flex column: the last thing in it can be pushed to
  the bottom and the row reads as a row.
*/
.edo-overlay .block--cards:not(.is-icon) .cards__item { align-items: stretch; }
.edo-overlay .block--cards:not(.is-icon) .card--panel .card__text { flex: 1 1 auto; }
.edo-overlay .block--cards:not(.is-icon) .card--panel .card__actions { margin-top: auto; }
.edo-overlay .card__actions {
  font-size: var(--size-small);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-accent-alt);
}

/* ---------- Icon blocks ---------- */

/*
  The parent's own pattern, from /earth-day-tips/: a grid of solid colour
  tiles, each a line mark over a short centred title, colours rotating across
  the grid. Jonah pointed at that page for the toolkits, and reusing a pattern
  the site already has is worth more here than a new idea -- consistency is the
  brief. Same data as the icon rows; only the preset changes.
*/
.edo-overlay .block--cards.is-icon-block a.card--panel,
.edo-overlay .block--cards.is-icon-block .card--panel {
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-md);
  min-height: 210px;
  padding: var(--space-lg) var(--space-md);
  background: var(--card-accent, var(--color-accent));
  color: var(--card-ink, var(--color-ink-invert));
  border-top: 0;
  text-align: center;
}
/* On a solid tile the mark is the tile's own colour inverted, not a chip. */
.edo-overlay .block--cards.is-icon-block .card__tile {
  width: auto;
  height: auto;
  background: none;
  border-radius: 0;
}
.edo-overlay .block--cards.is-icon-block .card__tile .tile__icon { width: 40px; height: 40px; }
.edo-overlay .block--cards.is-icon-block .card__text { align-items: center; gap: var(--space-xs); }
.edo-overlay .block--cards.is-icon-block .card--panel .card__title {
  font-size: var(--size-body);
  font-weight: 700;
  line-height: var(--leading-tight);
  color: var(--card-ink, var(--color-ink-invert));
  text-wrap: balance;
}
.edo-overlay .block--cards.is-icon-block a.card--panel .card__title::after { content: none; }
.edo-overlay .block--cards.is-icon-block .card__actions {
  margin-top: 0;
  color: var(--card-ink, var(--color-ink-invert));
  opacity: 0.85;
}
@media (hover: hover) {
  .edo-overlay .block--cards.is-icon-block a.card--panel:hover { transform: translateY(-3px); }
}

/*
  The admin bar, belt and braces.

  The render hooks are removed in the template, which is the real fix. This is
  here because that removal is a matter of hook timing and the bar is only ever
  visible to a logged-in editor -- exactly the person who would be looking at
  the page to approve it, and exactly the case a deploy is hardest to test. If
  it ever prints again it will not land on top of the page.
*/
.edo-overlay #wpadminbar { display: none !important; }
.edo-overlay html { margin-top: 0 !important; }

/* ---------- Card images: the <picture> rewrite ---------- */

/*
  Imagify and WP Rocket rewrite every `<img class="card__image">` into
  `<picture class="card__image"><img class=""></picture>` -- the class goes to
  the WRAPPER and the real image is left bare. So every rule that mattered
  (`aspect-ratio`, `object-fit: cover`) was landing on a box whose content
  ignored it, and each card simply rendered its source at its own ratio.

  Measured on the hub 2026-09-09: the cleanup photo is 1999x1333 (3:2) and came
  out 340x227; the toolkit cover is 2048x1152 (16:9) and came out 340x191. Two
  cards in one row, 36px apart at the bottom. That is the "wonky tile".

  The fix is to style both halves, and it has to work whether or not the
  rewrite happened -- locally it does not, on staging it does. `:where()` keeps
  this at zero specificity so the per-preset rules further up still win on the
  wrapper, and the inner img just fills whatever box it is given.
*/
/*
  `height: auto` is the load-bearing line here, not the positioning.

  `.edo-overlay .card__image` sets `height: 100%` for the older fixed-height
  media box. On a <picture> that resolves against a flex column of auto height,
  so it collapses to the image's own height and silently beats the
  `aspect-ratio` set further up. The other card rows only looked correct
  because their photographs happen to be 16:9 already -- they were right by
  luck, not by rule, and the first non-16:9 image in any of them would have
  broken the same way the cleanup photo did.
*/
.edo-overlay picture.card__image {
  display: block;
  position: relative;
  height: auto;
  overflow: hidden;
}

/*
  The inner image is taken out of flow deliberately.

  `height: 100%` on a child whose parent sizes itself from `aspect-ratio` is
  circular: the parent's height is auto until its content is measured, the
  child's 100% has nothing to resolve against, and both fall back to the
  image's intrinsic height -- which is the whole bug restated. Measured after
  the first attempt: still 218px against 191px. Absolute positioning gives the
  child a containing block with a settled height, so the ratio on the wrapper
  is the only thing deciding how tall the card's picture is.
*/
.edo-overlay picture.card__image > img {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  aspect-ratio: auto;
}

/* ---------- Tones ---------- */

/*
  The band a section sits on: white (the default, no class), a pale tint, or
  deep navy. Set with `tone` on any layout; see ed_page_classes().

  These come last and carry :not(.has-bg) on purpose. Several blocks set their
  own default background (`.block--cards:not(.has-bg)`, `.block--stats...`),
  and a tone has to beat those without an !important -- and a photograph has
  to beat the tone, because a picture is a stronger decision than a colour.
*/
.edo-overlay .block.is-tone-tint:not(.has-bg) {
  background-color: var(--color-surface-alt);
}

.edo-overlay .block.is-tone-navy:not(.has-bg) {
  --btn-outline-ink: var(--color-ink-invert);
  background-color: var(--color-surface-invert);
  color: var(--color-ink-invert);
}

/*
  Everything that names --color-ink directly has to be told. Listed rather than
  inherited because each of these declares its own colour further up, which is
  what stops a stray theme rule on h2 or p from winning on a light page.
*/
.edo-overlay .block.is-tone-navy:not(.has-bg) :is(
  .block__heading, .block__subhead, .block__body, .block__attribution,
  .card__title, .card__title a, .card__excerpt,
  .stats__value, .stats__label,
  .signup__label, .signup__consent, .signup__status
) {
  color: var(--color-ink-invert);
}

/* A navy button on a navy band is a hole. The filled button turns white. */
.edo-overlay .block.is-tone-navy:not(.has-bg) :is(.btn--primary, .btn--secondary) {
  background: var(--color-ink-invert);
  border-color: var(--color-ink-invert);
  color: var(--color-ink);
}

/* Same inversion the photograph blocks already get for their carousel controls. */
.edo-overlay .block.is-tone-navy:not(.has-bg) .carousel__dot { border-color: var(--color-ink-invert); }
.edo-overlay .block.is-tone-navy:not(.has-bg) .carousel__dot[aria-selected="true"] {
  background: var(--color-accent-alt);
  border-color: var(--color-accent-alt);
}
.edo-overlay .block.is-tone-navy:not(.has-bg) .carousel__btn {
  background: var(--color-ink-invert);
  color: var(--color-ink);
}
.edo-overlay .block.is-tone-navy:not(.has-bg) .carousel__btn:hover {
  background: var(--color-accent-alt);
  color: #ffffff;
}

/* ---------- Photo strip ---------- */

/*
  "Earth Day through the years": a run of photographs from past Earth Days.
  One ratio for every frame, whatever the source was shot at -- the originals
  on this strip are 3:2, 4:3 and 16:9, and a strip of mixed heights reads as
  an unsorted folder rather than as a record.
*/
.edo-overlay .is-photos .carousel__item { width: min(300px, 72vw); }

.edo-overlay .card--photo {
  margin: 0;
  overflow: hidden;
  border-radius: var(--radius-md);
}
/* A photo credit, where the picture came with one. Quiet by design: it is
   attribution under the image, not a heading competing with it. */
.edo-overlay .card--photo .card__caption {
  margin: calc(var(--space-2xs) + 2px) 0 0;
  font-size: var(--size-small);
  line-height: 1.4;
  color: var(--color-ink-muted);
}
.edo-overlay .card--photo .card__image {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 3 / 2;
  object-fit: cover;
  margin: 0;
}
/* The <picture> rewrite on staging: the ratio lives on the wrapper there. */
.edo-overlay .card--photo picture.card__image { position: relative; height: auto; }
.edo-overlay .card--photo picture.card__image > img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* ---------- Signup ---------- */

.edo-overlay .block--signup .block__inner { max-width: var(--container-narrow); }
.edo-overlay .block--signup { text-align: center; }
.edo-overlay .block--signup .block__body { margin-inline: auto; }

.edo-overlay .signup {
  display: grid;
  gap: var(--space-md);
  margin: 0;
  text-align: left;
}

/* Email, postcode and the button on one line when there is room for them. */
.edo-overlay .signup__row {
  display: grid;
  grid-template-columns: 2fr 1fr auto;
  align-items: end;
  gap: var(--space-sm);
}
@media (max-width: 700px) {
  .edo-overlay .signup__row { grid-template-columns: 1fr; }
}

.edo-overlay .signup__field { display: grid; gap: var(--space-2xs); }

/*
  Visible labels, not placeholders. A placeholder vanishes the moment someone
  starts typing, which is precisely when they need to check which box is the
  postcode.
*/
.edo-overlay .signup__label {
  font-size: var(--size-small);
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--color-ink);
}

.edo-overlay .signup__input {
  width: 100%;
  min-height: 3rem;
  padding: 0 var(--space-md);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-surface);
  color: var(--color-ink);
  font: inherit;
}
.edo-overlay .signup__input:focus-visible {
  outline: 3px solid var(--color-accent-alt);
  outline-offset: 2px;
  border-color: var(--color-ink);
}

.edo-overlay .signup__submit { min-height: 3rem; }

.edo-overlay .signup__consent {
  display: flex;
  align-items: flex-start;
  gap: var(--space-xs);
  font-size: var(--size-small);
  color: var(--color-ink);
}
.edo-overlay .signup__consent input {
  width: 1.15rem;
  height: 1.15rem;
  margin: 0.1rem 0 0;
  accent-color: var(--color-accent-alt);
  flex: none;
}

.edo-overlay .signup__status {
  margin: 0;
  font-weight: 700;
  color: var(--color-ink);
}
.edo-overlay .signup__status.is-error { color: var(--color-accent-alt); }

/* Once it has gone through, the fields are done with. The message stays. */
.edo-overlay .signup.is-sent :is(.signup__row, .signup__consent) { display: none; }
.edo-overlay .signup[aria-busy="true"] .signup__submit { opacity: 0.6; }

/*
  A coloured tile keeps its own ink on a navy band.

  The navy tone turns every title and excerpt white, which is right for text
  sitting on the band and wrong for text sitting on a tile: the Quizzes tile on
  the homepage is chrome yellow, and white on yellow is about 1.7:1. The tile
  already knows its ink (--card-ink, set per item from the accent), so it wins
  here by one class of specificity rather than by !important.
*/
.edo-overlay .block.block--cards.is-icon-block .card--panel :is(.card__title, .card__excerpt, .card__actions) {
  color: var(--card-ink, var(--color-ink-invert));
}
.edo-overlay .block--cards.is-icon-block .card--panel .card__excerpt {
  font-size: var(--size-small);
  line-height: 1.5;
  opacity: 0.92;
}

/*
  The <picture> fix, corrected -- 2026-09-14.

  `height: auto` on picture.card__image was right for the tile cards, where the
  wrapper takes its height from `aspect-ratio`, and wrong everywhere else. In a
  blog card the picture sits in .card__media, a box of fixed height with no
  ratio at all; with the image absolutely positioned inside it the picture had
  no in-flow content and collapsed to 0px. The news cards on the homepage, the
  stories carousel on 2026-dev and News and Stories all rendered as empty grey
  boxes with fully loaded images inside them. Here the wrapper fills its box.
*/
.edo-overlay .card__media picture.card__image {
  display: block;
  position: relative;
  width: 100%;
  height: 100%;
}

/* The news carousels centre their heading; the label above it has to follow. */
.edo-overlay .block--carousel.is-blog .block__eyebrow { text-align: center; }

/* ---------- Partner band on a flow page ---------- */

/*
  On 2026-dev the partner strip is a full-bleed band tucked under a slide, and
  `max-width: none` is right there. On a flow page it is just another section,
  and full-bleed made it the one band on the homepage whose edges did not line
  up with the 1200px container above and below it -- heading at 48px from the
  left while every other heading sat at 265px.

  Two buttons also do not fit in the same row as the heading and the logos: at
  1200px they left the marquee 368px. So on a flow page the band stacks --
  heading and buttons on one line, logos across the full width under them --
  which centres it and gives the marks room. 2026-dev is untouched.
*/
.edo-page.is-flow .block--carousel.is-logos .block__inner {
  max-width: var(--container);
  flex-wrap: wrap;
  row-gap: var(--space-md);
}
.edo-page.is-flow .block--carousel.is-logos .block__heading { order: 1; }
.edo-page.is-flow .block--carousel.is-logos .block__actions { order: 2; margin-left: auto; }
.edo-page.is-flow .block--carousel.is-logos .carousel { order: 3; flex-basis: 100%; }
.edo-page.is-flow .block--carousel.is-logos { padding-block: var(--space-lg); }

/*
  The band is --color-ink, which is exactly the navy the primary button and the
  outline border are drawn in: one button was a white label floating in space,
  the other was invisible. Inverted here, the same way a navy tone does.
*/
/*
  Set on the BUTTON, not the section. `.btn--outline` declares
  --btn-outline-ink on itself, so a value set on an ancestor never reaches it
  -- the first attempt here did exactly that and changed nothing. The navy tone
  had the same latent bug, so it is fixed in the same rule.
*/
.edo-overlay .block--carousel.is-logos .btn--outline,
.edo-overlay .block.is-tone-navy:not(.has-bg) .btn--outline {
  --btn-outline-ink: var(--color-ink-invert);
}
.edo-overlay .block--carousel.is-logos :is(.btn--primary, .btn--secondary) {
  background: var(--color-ink-invert);
  border-color: var(--color-ink-invert);
  color: var(--color-ink);
}

@media (max-width: 700px) {
  .edo-page.is-flow .block--carousel.is-logos .block__actions { margin-left: 0; order: 4; }
}

/* ---------- Colour tiles fill their row ---------- */

/*
  The 340px track cap on flow pages is for photo cards, where a 590px-wide
  photograph is too much. A colour tile has no photograph to stretch, and
  capped it left three tiles pinned left with 116px of empty band on the right
  -- the Get Inspired row read as off-centre because it was. Tiles take the
  whole row instead, which is also what the four-tile Toolkits grid already did.
*/
@media (min-width: 901px) {
  .edo-page.is-flow .block--cards.is-icon-block .cards {
    grid-template-columns: repeat(var(--card-columns, 3), minmax(0, 1fr));
  }
}

/* ---------- Hero spotlight ---------- */

/*
  Headline and button on the left, a floating card on the right, both over a
  full-bleed photograph. Below 900px the two stack and the card sits under the
  headline at full width -- on a phone a card floating over a photo is just a
  card with a worse background.
*/
/*
  The flow rule sets `min-height: 0` on every block with more weight than a
  single class selector, so the hero has to say so on the page scope too --
  otherwise it collapses to the height of its own text (measured: 507px where
  it should be ~700) and stops reading as a hero at all.
*/
.edo-overlay .block--hero-spotlight,
.edo-page.is-flow .block--hero-spotlight,
.edo-page.is-flow .block--hero-spotlight.is-snap,
.edo-page.is-flow .block--hero-spotlight.is-freescroll {
  min-height: clamp(520px, 78svh, 780px);
  align-items: center;
  color: var(--color-ink-invert);
}
.edo-overlay .block__inner--spotlight {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 400px);
  align-items: center;
  gap: var(--space-2xl);
}
@media (max-width: 900px) {
  .edo-overlay .block__inner--spotlight {
    grid-template-columns: 1fr;
    gap: var(--space-xl);
  }
}

.edo-overlay .block--hero-spotlight .block__heading {
  font-size: var(--size-h1);
  text-transform: uppercase;
  margin-bottom: var(--space-lg);
}
.edo-overlay .block--hero-spotlight .block__body { max-width: 34ch; }

.edo-overlay .spotlight__cards { list-style: none; margin: 0; padding: 0; }
/* Before JS runs, only the first card shows. After it runs JS owns this. */
.edo-overlay .spotlight__slide[data-rest] { display: none; }

.edo-overlay .promo {
  display: block;
  padding: var(--space-lg);
  background: var(--color-surface);
  color: var(--color-ink);
  border-radius: var(--radius-md);
  box-shadow: 0 18px 50px rgb(0 0 0 / 0.28);
  text-decoration: none;
}
.edo-overlay .promo__label {
  margin: 0 0 var(--space-xs);
  font-size: var(--size-small);
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--color-accent-alt);
}
.edo-overlay .promo__title {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--size-card-title);
  line-height: var(--leading-tight);
  color: var(--color-ink);
}
.edo-overlay .promo__excerpt {
  margin: var(--space-xs) 0 0;
  color: var(--color-ink-muted);
  font-size: var(--size-small);
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.edo-overlay .promo__cta {
  display: inline-block;
  margin-top: var(--space-sm);
  font-size: var(--size-small);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-accent-alt);
}
.edo-overlay .promo__cta::after { content: " \2192"; }
.edo-overlay .promo__image {
  display: block;
  width: 100%;
  margin-top: var(--space-md);
  aspect-ratio: 16 / 9;
  object-fit: cover;
}
.edo-overlay picture.promo__image { position: relative; height: auto; }
.edo-overlay picture.promo__image > img {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
}
@media (hover: hover) {
  .edo-overlay a.promo:hover { transform: translateY(-3px); }
  .edo-overlay a.promo:hover .promo__title { text-decoration: underline; }
}
.edo-overlay a.promo { transition: transform var(--motion-fast) var(--easing); }

.edo-overlay .spotlight__dots {
  display: flex;
  justify-content: flex-end;
  gap: var(--space-xs);
  margin-top: var(--space-sm);
}
.edo-overlay .spotlight__dot {
  width: 11px;
  height: 11px;
  padding: 0;
  border: 2px solid var(--color-ink-invert);
  border-radius: 50%;
  background: none;
  cursor: pointer;
}
.edo-overlay .spotlight__dot[aria-current="true"] {
  background: var(--color-accent-alt);
  border-color: var(--color-accent-alt);
}

/* ---------- Carousel head row ---------- */

/*
  Heading left, "see all" right, on one line. Only on flow pages: the deck's
  carousels were signed off with their button under the track and this must not
  reach back and move them.
*/
.edo-page.is-flow .block__head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--space-md) var(--space-lg);
  margin-bottom: var(--space-lg);
}
.edo-page.is-flow .block__head-text { flex: 1 1 24rem; min-width: 0; }
.edo-page.is-flow .block__head-text > :last-child { margin-bottom: 0; }
.edo-page.is-flow .block__head .block__actions { margin: 0; flex: 0 0 auto; }

/* ---------- Feature cards ---------- */

/*
  The "Our featured work" cards. The plain tile -- picture, title, one line --
  was too thin for a campaign that wants explaining, so this is a proper panel:
  the photograph runs full bleed across the top, the copy sits on a white card
  under it with the campaign's accent as a rule, and the whole thing lifts on
  hover. The picture is clipped by the card, so it can grow without pushing the
  layout around.
*/
.edo-page.is-flow .block--cards.is-feature .cards {
  grid-template-columns: repeat(var(--card-columns, 2), minmax(0, 1fr));
}
.edo-overlay .block--cards.is-feature .card--panel {
  padding: 0;
  overflow: hidden;
  background: var(--color-surface);
  border-top: 4px solid var(--card-accent, var(--color-accent));
  box-shadow: 0 2px 0 rgb(0 0 0 / 0.06), 0 12px 32px rgb(0 0 0 / 0.08);
  transition: transform var(--motion-fast) var(--easing),
              box-shadow var(--motion-fast) var(--easing);
}
.edo-overlay .block--cards.is-feature .card--panel .card__image {
  margin: 0;
  aspect-ratio: 16 / 9;
  transition: transform 300ms var(--easing);
}
.edo-overlay .block--cards.is-feature .card__text {
  gap: var(--space-xs);
  padding: var(--space-lg);
}
.edo-overlay .block--cards.is-feature .card--panel .card__title {
  font-size: var(--size-h3);
  color: var(--color-ink);
}
.edo-overlay .block--cards.is-feature .card__excerpt { color: var(--color-ink-muted); }
.edo-overlay .block--cards.is-feature .card__actions { margin-top: var(--space-sm); }

@media (hover: hover) {
  .edo-overlay .block--cards.is-feature a.card--panel:hover {
    transform: translateY(-4px);
    box-shadow: 0 2px 0 rgb(0 0 0 / 0.06), 0 20px 44px rgb(0 0 0 / 0.16);
  }
  .edo-overlay .block--cards.is-feature a.card--panel:hover .card__image { transform: scale(1.04); }
  .edo-overlay .block--cards.is-feature a.card--panel:hover .card__title { text-decoration: none; }
}
@media (prefers-reduced-motion: reduce) {
  .edo-overlay .block--cards.is-feature a.card--panel:hover,
  .edo-overlay .block--cards.is-feature a.card--panel:hover .card__image { transform: none; }
}

/* ---------- Blog tile is one link ---------- */

.edo-overlay a.card--blog { text-decoration: none; display: flex; }
@media (hover: hover) {
  .edo-overlay a.card--blog:hover .card__title { text-decoration: underline; }
  .edo-overlay a.card--blog:hover .card__image { transform: scale(1.03); }
}
.edo-overlay a.card--blog .card__media { overflow: hidden; }
.edo-overlay a.card--blog .card__image { transition: transform 300ms var(--easing); }

/* ---------- Carousel head rows read left ---------- */

/*
  `.block--carousel.is-blog .block__heading` is centred for the 2026 deck,
  where the stories carousel is a centred slide. On a flow page the heading now
  shares a line with a "see all" button pinned right, and a centred heading in
  a left-right row reads as a mistake -- Steve, 2026-09-17, pointing at
  "Press / EARTHDAY.ORG in the News". Anything inside a head row is left.
*/
.edo-page.is-flow .block__head-text :is(.block__heading, .block__eyebrow, .block__body) {
  text-align: left;
}

/* ---------- Hero fills the screen ---------- */

/*
  One full viewport, like nationalparks.org: the photograph is the first thing
  and nothing else competes with it. svh rather than vh so mobile browser
  chrome hiding does not resize the hero mid-scroll.
*/
.edo-overlay .block--hero-spotlight,
.edo-page.is-flow .block--hero-spotlight,
.edo-page.is-flow .block--hero-spotlight.is-snap,
.edo-page.is-flow .block--hero-spotlight.is-freescroll {
  min-height: 100svh;
}

/*
  On a phone the card breaks out of the hero and overlaps the section below,
  which is the trick that makes it read as floating ON the photograph rather
  than as a panel inside it. The negative margin pulls the next section up
  under it; position and z-index keep the card on top of what it lands on.
*/
@media (max-width: 900px) {
  /*
    Same four selectors as the full-height rule above, or it loses: that rule
    qualifies on .is-snap/.is-freescroll and so carries one more class than a
    plain .block--hero-spotlight. Measured: the hero kept 100svh and 72px of
    bottom padding, and the card had nothing to hang over.
  */
  .edo-page.is-flow .block--hero-spotlight,
  .edo-page.is-flow .block--hero-spotlight.is-snap,
  .edo-page.is-flow .block--hero-spotlight.is-freescroll {
    min-height: 88svh;
    padding-bottom: 0;
  }
  /*
    A transform, not a negative margin. The hero is sized by min-height, so it
    is taller than its content and a negative margin on the last item changes
    nothing -- measured: the card's bottom edge sat exactly on the hero's.
    Translating moves the card without touching layout, so it genuinely hangs
    over the section below, which starts with 72px of padding for it to land in.
  */
  .edo-overlay .spotlight__aside {
    position: relative;
    z-index: 2;
    transform: translateY(var(--space-2xl));
  }
  .edo-overlay .spotlight__dots {
    justify-content: center;
    /* The dots ride on the section below now, where white would vanish. */
    --dot-ink: var(--color-ink);
  }
  .edo-overlay .spotlight__dot { border-color: var(--dot-ink, var(--color-ink-invert)); }
}

/* ---------- Prose ---------- */

/*
  The article body, for the 250 informational pages in the audit that are text
  rather than layout. One readable measure, one vertical rhythm, and the same
  tokens as everything else -- so a converted page looks like it belongs here
  rather than like a page that was imported.
*/
.edo-overlay .block--prose.is-narrow .block__inner { max-width: var(--container-narrow); }

.edo-overlay .prose { color: var(--color-ink); font-size: var(--size-body); }
.edo-overlay .prose > :first-child { margin-top: 0; }
.edo-overlay .prose > :last-child { margin-bottom: 0; }

.edo-overlay .prose p,
.edo-overlay .prose ul,
.edo-overlay .prose ol { margin: 0 0 var(--space-md); line-height: 1.6; }

.edo-overlay .prose :is(h2, h3, h4) {
  font-family: var(--font-display);
  font-weight: var(--weight-display);
  line-height: var(--leading-tight);
  color: var(--color-ink);
  margin: var(--space-xl) 0 var(--space-sm);
  text-wrap: balance;
}
.edo-overlay .prose h2 { font-size: var(--size-h3); }
.edo-overlay .prose h3 { font-size: var(--size-card-title); }
.edo-overlay .prose h4 { font-size: var(--size-body); text-transform: uppercase; letter-spacing: 0.04em; }

.edo-overlay .prose :is(ul, ol) { padding-left: 1.25em; }
.edo-overlay .prose li { margin-bottom: var(--space-xs); }

/* Links in running text are underlined: colour alone is not a signal. */
.edo-overlay .prose a {
  color: var(--color-accent);
  text-decoration: underline;
  text-underline-offset: 0.15em;
}
.edo-overlay .prose a:hover { color: var(--color-accent-alt); }

.edo-overlay .prose img {
  display: block;
  max-width: 100%;
  height: auto;
  margin: var(--space-lg) 0;
}
.edo-overlay .prose figure { margin: var(--space-lg) 0; }
.edo-overlay .prose figcaption {
  margin-top: var(--space-xs);
  font-size: var(--size-small);
  color: var(--color-ink-muted);
}

.edo-overlay .prose blockquote {
  margin: var(--space-lg) 0;
  padding-left: var(--space-lg);
  border-left: 4px solid var(--color-accent-alt);
  font-family: var(--font-display);
  font-size: var(--size-card-title);
  line-height: var(--leading-tight);
  color: var(--color-ink);
}
.edo-overlay .prose blockquote p:last-child { margin-bottom: 0; }

.edo-overlay .prose table {
  width: 100%;
  border-collapse: collapse;
  margin: var(--space-lg) 0;
  font-size: var(--size-small);
}
.edo-overlay .prose :is(th, td) {
  padding: var(--space-sm);
  border-bottom: 1px solid var(--color-border);
  text-align: left;
}

/* Wide tables scroll inside the block rather than widening the page. */
.edo-overlay .prose { overflow-wrap: break-word; }

/* ---------- Embeds ---------- */

.edo-overlay .embed { min-height: var(--embed-min-height, 0); }
.edo-overlay .embed :is(iframe, video) { display: block; width: 100%; border: 0; }
.edo-overlay .embed__caption {
  margin: var(--space-sm) 0 0;
  font-size: var(--size-small);
  color: var(--color-ink-muted);
}

/* ---------- Photo grid ---------- */

/*
  A converted gallery is a GRID, not a carousel.

  Steve, 2026-09-20, on the social toolkit: the pledge cards are three to a row
  on the old page and came back as a carousel that cropped them, and the social
  icons came back as enormous sliding logos. Almost every gallery on the old
  site is a grid, so that is the default for converted pages; the carousel
  stays for sets that are genuinely a reel.
*/
.edo-overlay .block--carousel.is-photos.is-grid .carousel__track {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
  gap: var(--space-md);
  overflow: visible;
  scroll-snap-type: none;
  padding-bottom: 0;
}
.edo-overlay .block--carousel.is-photos.is-grid .carousel__item { width: auto; }
.edo-overlay .block--carousel.is-photos.is-grid .carousel__controls { display: none; }
/* Logos and icons should not be blown up to fill a card. */
.edo-overlay .block--carousel.is-photos.is-grid .card--photo .card__image {
  aspect-ratio: auto;
  height: auto;
  object-fit: contain;
}
/*
  ...but a <picture> needs its image back in flow first.

  Imagify rewrites every <img> on staging into a <picture>, and the reel
  variant above positions that inner <img> absolutely inside a box whose
  height comes from aspect-ratio. Take the aspect-ratio away, as the grid does
  here, and there is nothing left to give the box height: the picture collapses
  to 0 and the gallery renders as a column of captions with no photographs.
  All 38 images on /womenclimate-photos/ were invisible this way, and it
  passed verification every time because the <img> tags were all present --
  the check counts tags, not pixels.
*/
.edo-overlay .block--carousel.is-photos.is-grid .card--photo picture.card__image > img {
  position: static;
  width: 100%;
  height: auto;
  object-fit: contain;
}


/* ---------- Stat citation ---------- */

/*
  Under the label, quiet. A source line that competes with the figure defeats
  the point of the figure, and one that is invisible defeats the point of
  citing it.
*/
.edo-overlay .stats__source {
  margin: var(--space-2xs) 0 0;
  font-size: var(--size-small);
  line-height: 1.4;
  color: var(--color-ink-muted);
}
.edo-overlay .block[data-text="light"] .stats__source { color: inherit; opacity: 0.82; }
.edo-overlay .stats__source a { color: inherit; text-decoration: underline; }

/* ---------- Rich copy in a split column ---------- */

/*
  The list beside a picture: "What shapes a healthy plate" on the pillar pages.
  Ruled rows rather than bullets, because the items are the topics the page
  covers rather than a sequence, and a marker in the campaign accent keeps the
  list from reading as body copy.
*/
.edo-overlay .block__richtext { margin-top: var(--space-md); }
.edo-overlay .block__richtext > :last-child { margin-bottom: 0; }
.edo-overlay .block__richtext ul {
  list-style: none;
  margin: 0;
  padding: 0;
}
.edo-overlay .block__richtext ul > li {
  position: relative;
  padding: var(--space-sm) 0 var(--space-sm) var(--space-md);
  border-top: 1px solid color-mix(in srgb, currentColor 18%, transparent);
  font-weight: 600;
}
.edo-overlay .block__richtext ul > li:last-child {
  border-bottom: 1px solid color-mix(in srgb, currentColor 18%, transparent);
}
.edo-overlay .block__richtext ul > li::before {
  content: "";
  position: absolute;
  left: 0;
  top: calc(var(--space-sm) + 0.55em);
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--color-accent-alt);
}


/* ---------- Topic list in two columns ---------- */

/*
  The same ruled rows as a split column's list, run in two columns under one
  header cluster, over a photograph. `break-inside: avoid` because a row that
  splits across the column gutter loses its rule and its marker and stops
  looking like a row at all.
*/
.edo-overlay .prose.is-cols-2 ul {
  list-style: none;
  margin: 0;
  padding: 0;
  columns: 2;
  column-gap: var(--space-2xl);
}
.edo-overlay .prose.is-cols-2 ul > li {
  position: relative;
  break-inside: avoid;
  -webkit-column-break-inside: avoid;
  padding: var(--space-sm) 0 var(--space-sm) var(--space-md);
  border-top: 1px solid color-mix(in srgb, currentColor 22%, transparent);
  font-weight: 600;
}
.edo-overlay .prose.is-cols-2 ul > li::before {
  content: "";
  position: absolute;
  left: 0;
  top: calc(var(--space-sm) + 0.55em);
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--color-accent-alt);
}
/* Over a photograph the copy is light, and the header cluster goes with it. */
.edo-overlay .block--prose.has-bg .block__heading,
.edo-overlay .block--prose.has-bg .block__subhead,
.edo-overlay .block--prose.has-bg .prose { color: var(--color-ink-invert); }
.edo-overlay .block--prose.has-bg .block__subhead { max-width: var(--container-narrow); }

@media (max-width: 40rem) {
  .edo-overlay .prose.is-cols-2 ul { columns: 1; }
}

/*
  A sub-head under a real heading is a standfirst, not a title.

  .block__subhead is sized as a heading because in a hero it IS the page's h1.
  Anywhere the block already prints a heading above it, inheriting that gives
  two titles -- on the pillar pages the sub-head came out in caps LARGER than
  the headline it was meant to sit under. Scoped to the blocks that print a
  heading first, so the hero keeps its own treatment.
*/
.edo-overlay .block--prose .block__subhead,
.edo-overlay .block--two-column .block__subhead,
.edo-overlay .block--cards .block__subhead,
.edo-overlay .block--carousel .block__subhead {
  font-size: var(--size-h3);
  font-weight: 700;
  text-transform: none;
  line-height: 1.35;
  margin: var(--space-sm) 0 0;
  max-width: var(--container-narrow);
}


/* ---------- Title band over a photograph ---------- */

/*
  Keep the copy inside the fade.

  With a left fade the gradient is clear by 55% of the width, but the body copy
  is capped at a 780px measure -- on a 994px band that ran 270px past the
  protection and the sentence crossed the bright half of the photograph. The
  measure now yields to the gradient whenever the band has a picture behind it.
*/
.edo-overlay .block--page-header.has-bg .block__body,
.edo-overlay .block--page-header.has-bg .block__subhead {
  max-width: min(var(--container-narrow), 52%);
}

@media (max-width: 60rem) {
  /*
    No room for a fade on a phone: the copy is the full width, so a vertical
    wash protects it and the left gradient would not.
  */
  .edo-overlay .block--page-header.has-bg .block__body,
  .edo-overlay .block--page-header.has-bg .block__subhead {
    max-width: var(--container-narrow);
  }
  .edo-overlay .block--page-header[data-scrim="left"] .block__scrim {
    background: var(--scrim-dark-strong);
  }
}
