/* ==========================================================================
   Whale Done Wash
   Tokens come straight off the trailer artwork in the Ocean Hideaways Figma
   file: Deep Blue #001B6A ground, Maho Blue #0040FF, and a Periwinkle #668CFF
   for secondary copy. Every raised surface is Maho at 40% over the ground,
   which is exactly #002AA6 — the same value the trailer's wave shapes composite
   to. Type is Syncopate for display, Afacad for everything else.
   ========================================================================== */

:root {
  --deep: #001b6a;
  --deep-deeper: #00114a;
  --wave: #002aa6;
  --wave-hi: #003ad6;
  --maho: #0040ff;
  --maho-hover: #2a60ff;
  --peri: #668cff;
  --peri-dim: #8fabff;
  --kelp: #00ff5e;
  --white: #fff;

  --hairline: rgb(102 140 255 / 24%);
  --hairline-soft: rgb(102 140 255 / 14%);

  --r-pill: 999px;
  --r-xl: 32px;
  --r-lg: 24px;
  --r-md: 18px;
  --r-sm: 12px;

  --container: 1180px;
  --gutter: 24px;
  --section-y: clamp(64px, 8vw, 120px);

  --shadow-card: 0 1px 2px rgb(0 8 40 / 30%), 0 14px 34px -14px rgb(0 8 40 / 55%);
  --shadow-lift: 0 2px 6px rgb(0 8 40 / 34%), 0 24px 50px -18px rgb(0 8 40 / 66%);
  --ease: cubic-bezier(0.22, 0.61, 0.36, 1);

  color-scheme: dark;
}

/* --------------------------------------------------------------- base ---- */

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: 104px;
  overflow-x: hidden;
  overflow-x: clip;
}

body {
  margin: 0;
  background: var(--deep);
  color: var(--white);
  font-family: "Afacad", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  font-size: 1.1875rem;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
  overflow-x: clip;
}

img,
svg {
  display: block;
  max-width: 100%;
}

a {
  color: var(--peri);
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
}

a:hover {
  color: var(--white);
}

/* Syncopate is drawn lowercase-forward and sets very wide, so display type is
   set in lowercase with the tracking the logo uses and tight leading. */
h1,
h2,
h3,
h4 {
  margin: 0;
  font-family: "Syncopate", "Afacad", sans-serif;
  font-weight: 700;
  letter-spacing: 0.03em;
  line-height: 1.18;
  text-transform: lowercase;
  text-wrap: balance;
}

h1 {
  font-size: clamp(1.8rem, 3.9vw, 3rem);
  line-height: 1.14;
}

h2 {
  font-size: clamp(1.5rem, 3vw, 2.35rem);
}

h3 {
  font-size: clamp(1.0625rem, 1.5vw, 1.25rem);
  line-height: 1.25;
}

/* Card and list headings read better in Afacad — Syncopate at small sizes eats
   too much width to hold a two-word phrase on one line. */
.card h3,
.step h3,
.audience h3,
.why__list h3,
.place h3,
.footer__brand h3 {
  font-family: "Afacad", sans-serif;
  font-weight: 700;
  letter-spacing: 0;
  text-transform: none;
}

p {
  margin: 0;
  text-wrap: pretty;
}

ul,
ol {
  margin: 0;
  padding: 0;
  list-style: none;
}

strong,
b {
  font-weight: 700;
}

:focus-visible {
  outline: 3px solid var(--peri);
  outline-offset: 3px;
  border-radius: 4px;
}

::selection {
  background: var(--maho);
  color: var(--white);
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
}

.skip-link {
  position: absolute;
  left: 50%;
  top: 12px;
  z-index: 100;
  padding: 10px 20px;
  transform: translate(-50%, -160%);
  background: var(--maho);
  border-radius: var(--r-pill);
  color: var(--white);
  font-weight: 700;
  text-decoration: none;
  transition: transform 0.2s var(--ease);
}

.skip-link:focus-visible {
  transform: translate(-50%, 0);
}

/* ---------------------------------------------------------- primitives ---- */

.container {
  width: 100%;
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.section {
  position: relative;
  padding-block: var(--section-y);
}

.section--wave {
  background: var(--wave);
}

.lede {
  max-width: 60ch;
  color: var(--peri);
  font-size: clamp(1.125rem, 1.5vw, 1.3125rem);
}

.hl {
  color: var(--peri);
}

.eyebrow {
  display: block;
  margin-bottom: 18px;
  color: var(--peri);
  font-size: 0.9375rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  line-height: 1;
  text-transform: uppercase;
}

.cta .eyebrow {
  color: rgb(255 255 255 / 82%);
}

.section-head {
  max-width: 46ch;
  margin-bottom: clamp(40px, 5vw, 64px);
}

.section-head .lede {
  margin-top: 20px;
}

.section-head--center {
  max-width: 54ch;
  margin-inline: auto;
  text-align: center;
}

.section-head--center .lede {
  margin-inline: auto;
}

.badge {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 9px 18px;
  background: var(--wave);
  border: 1px solid var(--hairline);
  border-radius: var(--r-pill);
  color: var(--peri);
  font-size: 0.9375rem;
  font-weight: 700;
  letter-spacing: 0.02em;
  line-height: 1;
}

.badge .icon {
  font-size: 1rem;
  color: var(--maho);
}

/* No pill, no border — just the icon and label. Used where the badge sits
   directly on the page background instead of needing to be set off from it. */
.badge--bare {
  padding-left: 0;
  padding-right: 0;
  background: none;
  border-color: transparent;
}

.badge--bare .icon {
  color: var(--white);
}

/* The one place the kelp green off the trailer is allowed to appear. */
.badge--eco {
  border-color: rgb(0 255 94 / 34%);
  color: var(--kelp);
}

.badge--eco .icon {
  color: var(--kelp);
}

/* Announced by screen readers, invisible on screen. Used to tell people that a
   link leaves the site, which the visual design conveys only by convention. */
.u-visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* --------------------------------------------------------------- icons ---- */

.icon {
  display: inline-block;
  width: 1em;
  height: 1em;
  flex: none;
  background-color: currentColor;
  -webkit-mask: var(--icon) center / contain no-repeat;
  mask: var(--icon) center / contain no-repeat;
}

.icon-tile {
  display: grid;
  place-items: center;
  width: 52px;
  height: 52px;
  flex: none;
  background: var(--maho);
  border-radius: var(--r-sm);
  color: var(--white);
  font-size: 1.625rem;
}

.icon-tile--quiet {
  background: rgb(0 64 255 / 40%);
  color: var(--peri);
}

.icon-tile--white {
  background: var(--white);
  color: var(--maho);
}

/* ------------------------------------------------------------- buttons ---- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 14px 28px;
  border: 0;
  border-radius: var(--r-pill);
  font-family: inherit;
  font-size: 1.0625rem;
  font-weight: 700;
  letter-spacing: 0.01em;
  line-height: 1;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  transition: background-color 0.2s var(--ease), color 0.2s var(--ease),
    transform 0.2s var(--ease), box-shadow 0.2s var(--ease);
}

.btn:hover {
  transform: translateY(-1px);
}

.btn:active {
  transform: translateY(0);
}

.btn .icon {
  font-size: 1.125em;
}

.btn--primary {
  background: var(--maho);
  color: var(--white);
  box-shadow: 0 10px 26px -10px rgb(0 64 255 / 90%);
}

.btn--primary:hover {
  background: var(--maho-hover);
  color: var(--white);
  box-shadow: 0 14px 32px -10px rgb(0 64 255 / 100%);
}

.btn--outline {
  background: transparent;
  box-shadow: inset 0 0 0 1.5px var(--hairline);
  color: var(--white);
}

.btn--outline:hover {
  background: rgb(102 140 255 / 12%);
  box-shadow: inset 0 0 0 1.5px var(--peri);
  color: var(--white);
}

.btn--light {
  background: var(--white);
  color: var(--deep);
}

.btn--light:hover {
  background: var(--peri-dim);
  color: var(--deep);
}

.btn--ghost-light {
  background: transparent;
  box-shadow: inset 0 0 0 1.5px rgb(255 255 255 / 46%);
  color: var(--white);
}

.btn--ghost-light:hover {
  background: rgb(255 255 255 / 14%);
  box-shadow: inset 0 0 0 1.5px var(--white);
  color: var(--white);
}

.btn--sm {
  padding: 11px 20px;
  font-size: 1rem;
}

.btn--lg {
  padding: 17px 32px;
  font-size: 1.125rem;
}

/* The arrow leans into the hover, so the primary action feels like a hand-off. */
.btn .icon--arrow {
  transition: transform 0.2s var(--ease);
}

.btn:hover .icon--arrow {
  transform: translateX(3px);
}

.btn-row {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
}

.btn-row--center {
  justify-content: center;
}

/* -------------------------------------------------------------- header ---- */

.header {
  position: sticky;
  top: 0;
  z-index: 50;
  background: rgb(0 27 106 / 86%);
  backdrop-filter: saturate(160%) blur(16px);
  -webkit-backdrop-filter: saturate(160%) blur(16px);
  border-bottom: 1px solid transparent;
  transition: border-color 0.2s var(--ease);
}

.header[data-stuck="true"] {
  border-bottom-color: var(--hairline-soft);
}

.header__inner {
  display: flex;
  align-items: center;
  gap: 24px;
  min-height: 84px;
}

.header__logo {
  flex: none;
  line-height: 0;
}

.header__logo img {
  width: auto;
  height: 50px;
}

/* An <img> carries its height attribute as a presentational hint, so every
   rule that sets one dimension has to release the other. */
.cta__mark,
.footer__logo,
.hero__whale {
  height: auto;
}

.nav {
  display: flex;
  align-items: center;
  gap: 2px;
  margin-inline: auto;
}

.nav__link {
  padding: 9px 14px;
  border-radius: var(--r-pill);
  color: var(--white);
  font-size: 1.0625rem;
  font-weight: 700;
  text-decoration: none;
  transition: background-color 0.2s var(--ease), color 0.2s var(--ease);
}

.nav__link:hover {
  background: rgb(102 140 255 / 14%);
  color: var(--peri);
}

/* The nav carries its own call button for the collapsed mobile menu only. */
.nav > .btn {
  display: none;
}

.header__actions {
  display: flex;
  align-items: center;
  gap: 10px;
  flex: none;
}

.nav-toggle {
  display: none;
  width: 46px;
  height: 46px;
  padding: 0;
  background: var(--wave);
  border: 1px solid var(--hairline);
  border-radius: var(--r-pill);
  color: var(--white);
  font-size: 1.5rem;
  cursor: pointer;
}

.nav-toggle .icon--close {
  display: none;
}

.nav-toggle[aria-expanded="true"] .icon--menu {
  display: none;
}

.nav-toggle[aria-expanded="true"] .icon--close {
  display: inline-block;
}

@media (max-width: 1040px) {
  .header__inner {
    min-height: 72px;
  }

  .header__logo img {
    height: 38px;
  }

  .nav-toggle {
    display: grid;
    place-items: center;
    margin-left: auto;
  }

  /* Hide the container, not just the button inside it. Left as a flex item it
     is zero-width but still claims one 24px gap, which pushed the toggle to
     48px from the edge against the logo's 24px. */
  .header__actions {
    display: none;
  }

  .nav {
    position: absolute;
    left: var(--gutter);
    right: var(--gutter);
    top: calc(100% + 8px);
    display: none;
    flex-direction: column;
    align-items: stretch;
    gap: 2px;
    margin: 0;
    padding: 14px;
    background: var(--wave);
    border: 1px solid var(--hairline);
    border-radius: var(--r-lg);
    box-shadow: var(--shadow-lift);
  }

  .nav[data-open="true"] {
    display: flex;
  }

  .nav__link {
    padding: 13px 16px;
  }

  .nav > .btn {
    display: inline-flex;
    margin-top: 10px;
  }

  .nav > .btn + .btn {
    margin-top: 8px;
  }
}

/* ---------------------------------------------------------------- hero ---- */

.hero {
  position: relative;
  padding-top: clamp(40px, 5vw, 72px);
  padding-bottom: clamp(56px, 7vw, 104px);
  overflow: hidden;
}

.hero__inner {
  position: relative;
  z-index: 1;
  display: grid;
  gap: clamp(40px, 5vw, 64px);
  align-items: center;
  grid-template-columns: minmax(0, 1fr) minmax(0, 0.82fr);
}

.hero h1 {
  margin-top: 20px;
}

.hero .lede {
  margin-top: 22px;
}

.hero .btn-row {
  margin-top: 32px;
}

/* At phone widths, two --lg buttons don't fit on one line and wrap to a stack.
   Sized down (not swapped to .btn--sm, so this stays independent of that class)
   and given equal width, so the pair always sits side by side. */
@media (max-width: 480px) {
  .hero .btn-row {
    flex-wrap: nowrap;
    gap: 10px;
  }

  .hero .btn-row .btn {
    flex: 1;
    padding: 12px 16px;
    font-size: 0.9375rem;
  }
}

.hero__trust {
  display: flex;
  flex-wrap: wrap;
  gap: 10px 24px;
  margin-top: 32px;
}

.hero__trust li {
  display: flex;
  align-items: center;
  gap: 8px;
  color: var(--peri);
  font-size: 1.0625rem;
}

.hero__trust .icon {
  color: var(--maho);
  font-size: 1.25rem;
}

/* Two crests, pushed off to the right and far wider than the banner, so what
   shows is the rising left flank of each — the way the trailer's wave enters
   from a corner rather than arcing symmetrically in the middle. .hero's own
   overflow does the cropping, so no cut end is ever visible. */
.hero__sea {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 0;
  height: 82%;
  pointer-events: none;
}

/* Full ellipses rather than the dome mask. The mask's flat edge would drift
   into view at the top of the bob and read as a hard horizontal cut; an ellipse
   has no edge to expose. The 1.736 ratio is the dome's own geometry — the dome
   is a half-ellipse of 3.472:1, so doubling its height gives the whole shape,
   and the arc that shows here is identical to a dome's crest. Each ellipse is
   anchored by its apex with `top`, and runs far below the banner from there.

   The offsets look extreme because each ellipse is scaled about its own apex —
   roughly 1.75x wider than the banner needs — purely to flatten the arc across
   the visible span so it matches the dome's shallow crest. Widening a crest
   without moving its apex means holding the element's horizontal centre fixed,
   so `left` and `right` grow by the same amount in opposite directions. */
.hero__wave {
  position: absolute;
  aspect-ratio: 1.736;
  background: var(--maho);
  border-radius: 50%;
  animation: surf 8s var(--ease) infinite;
}

@keyframes surf {
  0%,
  100% {
    transform: translate3d(0, -2.2%, 0);
  }

  50% {
    transform: translate3d(0, 2.2%, 0);
  }
}

/* Each apex sits off-screen to the right, at differing amounts, so the two
   flanks cross the banner at different angles instead of nesting. They rise and
   fall on close cycles with only a small offset, so they move almost together
   like one swell rather than independently. */
.hero__wave--back {
  left: -3.5%;
  right: -99.5%;
  top: 30%;
  opacity: 0.22;
  animation-duration: 11s;
  animation-delay: -1.5s;
}

.hero__wave--front {
  left: -15.8%;
  right: -69.8%;
  top: 58%;
  opacity: 0.4;
  animation-duration: 9.5s;
}

/* The desktop offsets are a share of the banner width, so on a phone they push
   both apexes almost entirely off-screen and leave only a sliver. Narrow
   viewports pull the swell back on while keeping each apex right of centre. */
@media (max-width: 700px) {
  /* Stacked, the hero is ~930px tall, so a sea at 82% of it outgrows the
     ellipses and their bottom curves come back into view as ovals. Capping the
     layer keeps the swell a band at the foot of the banner, which the ellipses
     clear by hundreds of pixels at any hero height. */
  .hero__sea {
    height: 400px;
  }

  .hero__wave--back {
    left: -67.5%;
    right: -147.5%;
    top: 34%;
  }

  .hero__wave--front {
    left: -82.2%;
    right: -108.2%;
    top: 56%;
  }
}

.hero__art {
  position: relative;
  display: grid;
  place-items: center;
}

.hero__whale {
  width: 92%;
  filter: drop-shadow(0 24px 44px rgb(0 8 40 / 55%));
  animation: swim 7s var(--ease) infinite;
}

@keyframes swim {
  0%,
  100% {
    transform: translate3d(0, -2%, 0) rotate(-1.5deg);
  }

  50% {
    transform: translate3d(0, 3%, 0) rotate(1.5deg);
  }
}

@media (prefers-reduced-motion: reduce) {
  .hero__whale {
    animation: none;
  }

  .hero__wave {
    animation: none;
  }
}

@media (max-width: 900px) {
  .hero__inner {
    grid-template-columns: minmax(0, 1fr);
  }

  .hero__art {
    max-width: 460px;
    margin-inline: auto;
  }
}

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

.grid {
  display: grid;
  gap: 20px;
}

.grid--3 {
  grid-template-columns: repeat(3, minmax(0, 1fr));
}

@media (max-width: 940px) {
  .grid--3 {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 600px) {
  .grid--3 {
    grid-template-columns: minmax(0, 1fr);
  }
}

.card {
  display: flex;
  flex-direction: column;
  gap: 14px;
  padding: 28px;
  background: var(--wave);
  border: 1px solid var(--hairline-soft);
  border-radius: var(--r-lg);
  transition: box-shadow 0.25s var(--ease), transform 0.25s var(--ease),
    border-color 0.25s var(--ease), background-color 0.25s var(--ease);
}

.card:hover {
  transform: translateY(-3px);
  background: var(--wave-hi);
  border-color: var(--hairline);
  box-shadow: var(--shadow-lift);
}

.card p {
  color: var(--peri);
  font-size: 1.0625rem;
}

.card__tag {
  margin-top: auto;
  padding-top: 6px;
  color: var(--white);
  font-size: 0.9375rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.section--wave .card {
  background: rgb(0 64 255 / 26%);
}

.section--wave .card:hover {
  background: rgb(0 64 255 / 40%);
}

/* ------------------------------------------------------------ how-it-works */

.steps {
  display: grid;
  gap: 20px;
  grid-template-columns: repeat(4, minmax(0, 1fr));
}

@media (max-width: 940px) {
  .steps {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 560px) {
  .steps {
    grid-template-columns: minmax(0, 1fr);
  }
}

.step {
  position: relative;
  padding: 28px;
  background: rgb(0 64 255 / 26%);
  border: 1px solid var(--hairline-soft);
  border-radius: var(--r-lg);
}

.step__num {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 18px;
  color: var(--white);
  font-family: "Syncopate", sans-serif;
  font-size: 0.8125rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: lowercase;
}

.step__num .icon {
  color: var(--white);
  font-size: 1.5rem;
}

.step h3 {
  margin-bottom: 10px;
}

.step p {
  color: var(--peri);
  font-size: 1.0625rem;
}

/* Bin cleaning and pressure washing are booked so differently that they need
   two flows. Both are in the markup unconditionally: the tablist is display:none
   until site.js sets data-js on the wrapper, so with no JavaScript the two
   flows simply stack, each under its own heading, and nothing is unreachable. */
.tabs__list {
  display: none;
  flex-wrap: wrap;
  gap: 6px;
  justify-content: center;
  width: fit-content;
  max-width: 100%;
  margin: 0 auto 36px;
  padding: 6px;
  background: rgb(0 64 255 / 22%);
  border: 1px solid var(--hairline-soft);
  border-radius: var(--r-pill);
}

.tabs[data-js="true"] .tabs__list {
  display: flex;
}

.tabs__tab {
  display: inline-flex;
  gap: 10px;
  align-items: center;
  padding: 12px 26px;
  background: none;
  border: 0;
  border-radius: var(--r-pill);
  color: var(--peri);
  font-family: inherit;
  font-size: 1.0625rem;
  cursor: pointer;
  transition:
    background 0.2s var(--ease),
    color 0.2s var(--ease);
}

.tabs__tab .icon {
  font-size: 1.375rem;
}

.tabs__tab:hover {
  color: var(--white);
}

.tabs__tab[aria-selected="true"] {
  background: var(--maho);
  color: var(--white);
}

/* Left to wrap, the pills stack at different widths and the group reads as
   broken rather than as a control. Below the phone breakpoint they share the
   full width in equal columns instead, one per tab however many there are.
   Three won't fit beside their icons at phone width, so the icons drop out
   there and the labels are left to wrap onto two lines. This runs wider than
   the usual 560px phone breakpoint because three pills need about 590px of
   viewport to sit on one line; between the two they would wrap. */
@media (max-width: 640px) {
  .tabs__list {
    display: grid;
    width: 100%;
    grid-auto-columns: minmax(0, 1fr);
    grid-auto-flow: column;
  }

  .tabs[data-js="true"] .tabs__list {
    display: grid;
  }

  .tabs__tab {
    justify-content: center;
    gap: 8px;
    padding: 12px 10px;
    font-size: 0.9375rem;
  }

  .tabs__tab .icon {
    display: none;
  }

  .tabs__tab {
    line-height: 1.2;
    text-align: center;
  }
}

.tabs__panel[hidden] {
  display: none;
}

/* Stacked (no-JS) the two flows need air and a label of their own. Once the
   tabs are live the tab itself carries the label, so both go away. */
.tabs__panel + .tabs__panel {
  margin-top: 44px;
}

.tabs__panel-title {
  margin-bottom: 20px;
  color: var(--white);
  font-family: "Syncopate", sans-serif;
  font-size: 0.8125rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-align: center;
  text-transform: lowercase;
}

.tabs[data-js="true"] .tabs__panel + .tabs__panel {
  margin-top: 0;
}

.tabs[data-js="true"] .tabs__panel-title {
  display: none;
}

/* The pressure washing flow is three steps, not four. Declared after the
   .steps breakpoints above so it wins at desktop width, which means it has to
   restate them. */
.steps--3 {
  grid-template-columns: repeat(3, minmax(0, 1fr));
}

@media (max-width: 940px) {
  .steps--3 {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 560px) {
  .steps--3 {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* ---------------------------------------------------------- who we serve */

.split {
  display: grid;
  gap: clamp(32px, 4vw, 64px);
  align-items: center;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
}

@media (max-width: 900px) {
  .split {
    grid-template-columns: minmax(0, 1fr);
  }
}

.split .lede {
  margin-top: 20px;
}

.split .audience {
  margin-top: 32px;
}

.audience {
  display: grid;
  gap: 14px;
}

.audience li {
  display: flex;
  gap: 16px;
  padding: 20px 22px;
  background: var(--wave);
  border: 1px solid var(--hairline-soft);
  border-radius: var(--r-md);
}

.audience h3 {
  margin-bottom: 4px;
}

.audience p {
  color: var(--peri);
  font-size: 1.0625rem;
}

.audience .icon-tile {
  width: 46px;
  height: 46px;
  font-size: 1.375rem;
}

/* This panel was a stack of masked domes standing in for a photograph — now it
   holds the real one. The 4/5 box is deliberately unchanged so the split layout
   doesn't shift: a landscape photo cropped to a portrait box shows its full
   height and about the middle 45% of its width. No scrim over this one. */
.pod {
  position: relative;
  overflow: hidden;
  aspect-ratio: 4 / 5;
  background: var(--deep-deeper);
  border-radius: var(--r-xl);
}

.pod__photo {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
}

/* ------------------------------------------------------------- pricing ---- */

/* Same pill language as the how-it-works tabs, and the same contract: hidden
   until site.js sets data-js, so a no-JS visitor sees both rates listed on
   every card instead of a dead control. The saving lives in the switch rather
   than under each price — one statement of the offer, not four. */
.billing {
  display: none;
  justify-content: center;
  margin-bottom: 32px;
}

.billing[data-js="true"] {
  display: flex;
}

.billing__switch {
  display: inline-flex;
  flex-wrap: wrap;
  gap: 6px;
  justify-content: center;
  max-width: 100%;
  padding: 6px;
  background: rgb(0 64 255 / 22%);
  border: 1px solid var(--hairline-soft);
  border-radius: var(--r-pill);
}

.billing__opt {
  display: inline-flex;
  gap: 10px;
  align-items: center;
  padding: 12px 24px;
  background: none;
  border: 0;
  border-radius: var(--r-pill);
  color: var(--peri);
  font-family: inherit;
  font-size: 1.0625rem;
  cursor: pointer;
  transition:
    background 0.2s var(--ease),
    color 0.2s var(--ease);
}

.billing__opt:hover {
  color: var(--white);
}

.billing__opt[aria-checked="true"] {
  background: var(--maho);
  color: var(--white);
}

/* Maho reads well on the panel ground while the option is unselected; once the
   option itself turns Maho the badge has to lift off it instead. */
.billing__save {
  padding: 3px 10px;
  background: var(--maho);
  border-radius: var(--r-pill);
  color: var(--white);
  font-size: 0.8125rem;
  font-weight: 700;
  white-space: nowrap;
}

.billing__opt[aria-checked="true"] .billing__save {
  background: rgb(255 255 255 / 24%);
}

@media (max-width: 560px) {
  .billing__switch {
    width: 100%;
  }

  /* Side by side the badge pushes "Pay for the year" into a mid-phrase wrap,
     so on a phone the badge drops under its label instead. */
  .billing__opt {
    flex: 1;
    flex-direction: column;
    gap: 5px;
    justify-content: center;
    padding: 10px 8px;
    font-size: 0.9375rem;
    text-align: center;
  }

  .billing__save {
    padding: 2px 8px;
    font-size: 0.75rem;
  }
}

.plan__rate[hidden],
.plan__min[hidden],
.plan__flag[hidden] {
  display: none;
}


.plans {
  display: grid;
  gap: 16px;
  margin-top: 13px;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  align-items: stretch;
}

/* Paying a year up front has no one-time equivalent, so on desktop that card
   stays in the row but recedes instead of competing with the four plans that
   do have an annual price. It is still a live choice, so engaging with it
   brings it back to full strength rather than leaving it looking disabled. */
.plans[data-mode="year"] .plan--onetime {
  opacity: 0.5;
  transition: opacity 0.2s var(--ease);
}

.plans[data-mode="year"] .plan--onetime:hover,
.plans[data-mode="year"] .plan--onetime:focus-within {
  opacity: 1;
}

/* Five across needs ~170px of card interior to fit "$19.80 / cleaning" on one
   line; below roughly 1180px the cards drop under that, so the row regroups
   into two columns. Four plans then make a clean 2x2 — which only works if the
   one-time card leaves altogether, since a faded fifth would strand a
   half-relevant orphan on a row of its own. */
@media (max-width: 1180px) {
  .plans {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .plans[data-mode="year"] .plan--onetime {
    display: none;
  }
}

@media (max-width: 560px) {
  .plans {
    grid-template-columns: minmax(0, 1fr);
    max-width: 420px;
    margin-inline: auto;
  }
}

.plan {
  position: relative;
  display: flex;
  flex-direction: column;
  padding: 26px 22px;
  background: rgb(0 64 255 / 22%);
  border: 1px solid var(--hairline-soft);
  border-radius: var(--r-lg);
}

.plan--featured {
  background: var(--maho);
  border-color: var(--maho);
  box-shadow: 0 28px 56px -22px rgb(0 64 255 / 90%);
}

/* The row, not the chip, is what straddles the card's top edge. With JS only
   one chip is ever in it; with JS off the featured card carries both, and they
   sit side by side rather than stacked on the same coordinates. */
.plan__flags {
  position: absolute;
  top: -13px;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  gap: 6px;
}

.plan__flag {
  padding: 7px 14px;
  white-space: nowrap;
  background: var(--white);
  border-radius: var(--r-pill);
  color: var(--maho);
  font-size: 0.8125rem;
  font-weight: 700;
  letter-spacing: 0.05em;
  line-height: 1;
  text-transform: uppercase;
}

.plan__name {
  font-family: "Syncopate", sans-serif;
  font-size: 1.0625rem;
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: lowercase;
}

.plan__meta {
  margin-top: 6px;
  color: var(--peri);
  font-size: 1rem;
}

.plan--featured .plan__meta {
  color: rgb(255 255 255 / 84%);
}

.plan__price {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 2px 6px;
  margin-top: 20px;
}

.plan__price b {
  font-family: "Syncopate", sans-serif;
  font-size: 1.875rem;
  font-weight: 700;
  letter-spacing: 0;
  line-height: 1;
}

.plan__price > span {
  color: var(--peri);
  font-size: 0.9375rem;
}

.plan--featured .plan__price > span {
  color: rgb(255 255 255 / 84%);
}

/* The annual total, tucked under the per-cleaning headline in the same
   Syncopate at a smaller size, so the two prices read as one pair rather than
   as two competing figures. */
.plan__year {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 2px 6px;
  margin-top: 10px;
}

/* Raised cents: the dollars stay the figure you actually read, and a price
   like $1,029.60 keeps the visual weight of $1,029 without losing accuracy. */
.cents {
  font-size: 0.58em;
  font-weight: 700;
  vertical-align: 0.42em;
  letter-spacing: 0;
  line-height: 1;
}

.plan__year b {
  color: var(--peri);
  font-size: 1.25rem;
  font-weight: 700;
  line-height: 1;
}

.plan__year > span {
  color: var(--peri);
  font-size: 0.8125rem;
}

.plan--featured .plan__year b,
.plan--featured .plan__year > span {
  color: rgb(255 255 255 / 84%);
}

/* Raising the cents narrows the figure enough to come back up close to the
   per-cleaning view's 1.875rem. 1.625rem clears the tightest five-across card
   by 15px; full size clears it by 0, which is no margin at all. */
[data-rate="year"] .plan__price b {
  font-size: 1.625rem;
}

[data-rate="year"] .plan__price > span {
  font-size: 0.875rem;
}

.plan__billing {
  margin-top: 8px;
  padding-top: 14px;
  border-top: 1px solid var(--hairline);
  color: var(--peri);
  font-size: 0.9375rem;
}

.plan--featured .plan__billing {
  border-top-color: rgb(255 255 255 / 28%);
  color: rgb(255 255 255 / 84%);
}

/* Minimum terms sit under the billing cadence rather than in the inclusions
   panel, because they differ per plan — three months on the frequent plans,
   six on quarterly, none at all on a one-time. */
.plan__min {
  margin-top: 8px;
  color: var(--peri-dim);
  font-size: 0.875rem;
}

.plan--featured .plan__min {
  color: rgb(255 255 255 / 76%);
}

/* auto pushes the button to the foot of the card, and the cards stretch to a
   common height, so the buttons line up across the row even though the monthly
   card carries an extra line. The nth-last-child rule keeps a minimum gap above
   the button whichever element happens to precede it. */
.plan .btn {
  margin-top: auto;
  width: 100%;
  padding-inline: 14px;
}

.plan > :nth-last-child(2) {
  margin-bottom: 20px;
}

/* One shared inclusions panel, in place of five identical lists. */
.includes {
  margin-top: 24px;
  padding: 26px 28px;
  background: rgb(0 64 255 / 22%);
  border: 1px solid var(--hairline-soft);
  border-radius: var(--r-lg);
}

.includes__title {
  margin-bottom: 18px;
  font-family: "Syncopate", sans-serif;
  font-size: 0.8125rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: lowercase;
}

.includes__list {
  display: grid;
  gap: 12px 28px;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  font-size: 1.0625rem;
}

@media (max-width: 800px) {
  .includes__list {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 560px) {
  .includes__list {
    grid-template-columns: minmax(0, 1fr);
  }
}

.includes__list li {
  display: flex;
  gap: 10px;
  align-items: flex-start;
  color: var(--white);
}

.includes__list .icon {
  margin-top: 0.28em;
  color: var(--peri);
  font-size: 1.125rem;
}

/* The extra-bin add-on set off from the flat inclusions above it — it has a
   price attached, so it isn't a bare checkmark item. */
.includes__addon {
  margin-top: 20px;
  padding-top: 20px;
  border-top: 1px solid var(--hairline-soft);
  color: var(--white);
  font-size: 1rem;
}

/* Inverted against the rest of the panel: the lead-in question carries the
   Periwinkle and the offer itself stays white, so the eye lands on the price. */
.includes__addon strong {
  color: var(--peri);
}

/* Three cards side by side rather than notes stretched across the row — the
   set reads as "here are a few things you might want", not one long aside. */
/* No max-width of its own — it fills the container exactly like .plans and
   .includes above it, so all three rows land on the same edges. */
.pricing-notes {
  display: grid;
  gap: 20px;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  margin-top: 28px;
}

/* Straight from three to one, at the same point .grid--3 leaves three
   columns: a two-column step would strand the third note on a row alone. */
@media (max-width: 940px) {
  .pricing-notes {
    grid-template-columns: minmax(0, 1fr);
  }
}

.pricing-note {
  display: flex;
  gap: 16px;
  align-items: flex-start;
  padding: 20px 24px;
  background: var(--wave);
  border: 1px solid var(--hairline-soft);
  border-radius: var(--r-lg);
}

.pricing-note strong {
  color: var(--white);
}

.pricing-note .icon-tile {
  flex: none;
  width: 40px;
  height: 40px;
  font-size: 1.25rem;
}

.pricing-note__body {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 14px;
}

.pricing-note__body p {
  color: var(--peri);
  font-size: 1.0625rem;
}

/* --------------------------------------------------------- service area ---- */

/* Seven places will not divide into three equal columns, so this grid is
   declared in twelfths and every card claims a span: the three islands take a
   third each across the top, the four mainland towns take a quarter each
   underneath. Both rows come out flush. */
.places {
  display: grid;
  gap: 20px;
  grid-template-columns: repeat(12, minmax(0, 1fr));
}

.places > .place {
  grid-column: span 3;
}

.places > .place:nth-child(-n + 3) {
  grid-column: span 4;
}

/* Tablet regroups as 2 / 2 / 3 — sixths, with the trailing three narrower. */
@media (max-width: 940px) {
  .places {
    grid-template-columns: repeat(6, minmax(0, 1fr));
  }

  .places > .place,
  .places > .place:nth-child(-n + 3) {
    grid-column: span 3;
  }

  .places > .place:nth-child(n + 5) {
    grid-column: span 2;
  }
}

@media (max-width: 600px) {
  .places {
    grid-template-columns: minmax(0, 1fr);
  }

  /* The spans have to be cleared outright, not just narrowed: a leftover
     `span 3` against a single-column template would invent implicit columns. */
  .places > .place,
  .places > .place:nth-child(-n + 3),
  .places > .place:nth-child(n + 5) {
    grid-column: auto;
  }
}

.place {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  min-height: 380px;
  overflow: hidden;
  padding: 28px;
  background: var(--wave);
  border-radius: var(--r-xl);
  isolation: isolate;
}

.place img {
  position: absolute;
  inset: 0;
  z-index: -2;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Favour the lower two-thirds so shorelines and houses stay in frame. */
  object-position: center 68%;
  transition: transform 0.6s var(--ease);
}

/* The scrim is Deep Blue and Maho rather than a neutral black: it pulls the
   island photography into the palette instead of just darkening it, and keeps
   white type legible over a bright sky. */
.place::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background:
    linear-gradient(
      180deg,
      rgb(0 27 106 / 15%) 0%,
      rgb(0 27 106 / 55%) 48%,
      rgb(0 17 74 / 94%) 100%
    ),
    linear-gradient(0deg, rgb(0 64 255 / 26%), rgb(0 64 255 / 26%));
}

.place:hover img {
  transform: scale(1.05);
}

.place__icon {
  position: absolute;
  top: 26px;
  left: 28px;
}

.place__body {
  position: relative;
}

.place h3 {
  font-size: 1.375rem;
}

.place p {
  margin-top: 8px;
  color: rgb(255 255 255 / 88%);
  font-size: 1.0625rem;
}

/* Seven full-height cards is a punishing scroll on a phone for copy nobody is
   reading on the way past, so the blurb goes and each card collapses to a photo
   with the town name on it. */
@media (max-width: 600px) {
  .place {
    min-height: 190px;
    padding: 20px;
  }

  .place p {
    display: none;
  }

  .place__icon {
    top: 18px;
    left: 20px;
  }
}

.area-note {
  margin-top: 28px;
  color: var(--peri);
  font-size: 1.0625rem;
  text-align: center;
}

/* ---------------------------------------------------------------- why us ---- */

.why {
  position: relative;
  overflow: hidden;
  padding: clamp(48px, 6vw, 80px) clamp(28px, 5vw, 64px);
  background: var(--wave);
  border-radius: var(--r-xl);
}

.why__inner {
  position: relative;
  z-index: 1;
}

.why__list {
  display: grid;
  gap: 28px 32px;
  grid-template-columns: repeat(3, minmax(0, 1fr));
}

@media (max-width: 940px) {
  .why__list {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 600px) {
  .why__list {
    grid-template-columns: minmax(0, 1fr);
  }
}

.why__list h3 {
  margin: 16px 0 8px;
}

.why__list p {
  color: var(--peri);
  font-size: 1.0625rem;
}

/* ------------------------------------------------------------------ faq ---- */

.faq {
  max-width: 820px;
  margin-inline: auto;
}

.faq__item {
  border-bottom: 1px solid var(--hairline-soft);
}

.faq__item summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  padding: 22px 4px;
  font-size: 1.1875rem;
  font-weight: 700;
  cursor: pointer;
  list-style: none;
}

.faq__item summary::-webkit-details-marker {
  display: none;
}

.faq__item summary:hover {
  color: var(--peri);
}

.faq__item summary .icon {
  flex: none;
  color: var(--maho);
  font-size: 1.5rem;
  transition: transform 0.25s var(--ease);
}

.faq__item[open] summary .icon {
  transform: rotate(180deg);
  color: var(--peri);
}

.faq__answer {
  padding: 0 48px 24px 4px;
  color: var(--peri);
}

/* ---------------------------------------------------------------- modal ---- */

/* Visibility is carried by .jobber-hidden, not the hidden attribute, because
   Jobber's embed adds that exact class to .jobber-dialog-overlay when the form
   asks to close. Sharing the class means their control and ours agree. */
.jobber-hidden {
  display: none !important;
}

/* .modal__chooser is a grid and the two head buttons are inline-flex, and an
   author display rule beats the hidden attribute's UA default — so hiding has
   to be stated outright or these stay on screen when JS sets .hidden. */
.modal__chooser[hidden],
.modal__form[hidden],
.modal__back[hidden] {
  display: none;
}

.modal {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: flex;
  justify-content: center;
  align-items: safe center;
  padding: clamp(12px, 4vw, 48px);
  background: rgb(0 8 40 / 76%);
  overflow-y: auto;
  overscroll-behavior: contain;
}

body.has-modal {
  overflow: hidden;
}

.modal__panel {
  width: min(640px, 100%);
  background: var(--deep);
  border: 1px solid var(--hairline);
  border-radius: var(--r-xl);
  box-shadow: var(--shadow-lift);
}

.modal__head {
  display: flex;
  gap: 12px;
  align-items: center;
  padding: 18px 20px;
  border-bottom: 1px solid var(--hairline-soft);
}

.modal__title {
  flex: 1;
  font-size: 1.0625rem;
  letter-spacing: 0.05em;
}

.modal__back,
.modal__close {
  display: inline-flex;
  gap: 6px;
  align-items: center;
  flex: none;
  padding: 8px 14px;
  background: rgb(0 64 255 / 26%);
  border: 0;
  border-radius: var(--r-pill);
  color: var(--peri);
  font: inherit;
  font-size: 0.9375rem;
  cursor: pointer;
  transition: background 0.2s var(--ease), color 0.2s var(--ease);
}

.modal__back:hover,
.modal__close:hover {
  background: var(--maho);
  color: var(--white);
}

.modal__back .icon {
  transform: rotate(180deg);
}

.modal__close {
  padding: 8px;
  font-size: 1.125rem;
}

/* --- the service picker --- */

.modal__chooser {
  display: grid;
  gap: 10px;
  padding: 20px;
}

.modal__choice {
  display: grid;
  gap: 14px;
  align-items: center;
  grid-template-columns: auto minmax(0, 1fr) auto;
  padding: 16px;
  background: rgb(0 64 255 / 22%);
  border: 1px solid var(--hairline-soft);
  border-radius: var(--r-md);
  color: var(--peri);
  font: inherit;
  font-size: 1rem;
  text-align: left;
  cursor: pointer;
  transition: background 0.2s var(--ease), border-color 0.2s var(--ease),
    transform 0.2s var(--ease);
}

.modal__choice:hover {
  transform: translateY(-1px);
  background: rgb(0 64 255 / 38%);
  border-color: var(--hairline);
}

.modal__choice strong {
  display: block;
  margin-bottom: 2px;
  color: var(--white);
  font-size: 1.0625rem;
}

.modal__choice .icon-tile {
  width: 44px;
  height: 44px;
  font-size: 1.375rem;
}

.modal__choice-go {
  color: var(--peri);
  font-size: 1.25rem;
}

.modal__choice:hover .modal__choice-go {
  color: var(--white);
}

/* --- the embedded form ---
   Jobber serves the form cross-origin, so its white ground can't be restyled
   from here. Rather than fight it, the panel gives it a white card of its own
   with the corners already in the design language. */
.modal__form {
  position: relative;
  padding: 16px;
}

.modal__form .jobber-inline-work-request {
  overflow: hidden;
  background: var(--white);
  border-radius: var(--r-md);
}

/* While the form is fetching, Jobber adds .jobber-spinner to this same slot,
   which sets position:absolute; inset:0; width/height:100% at 0.6 opacity.
   Its offsetParent is .modal — the fixed full-viewport overlay — so it blows up
   into a 760px-wide, full-height pane, and our white card background turns that
   into a grey wash over the whole screen. Pinning it back into normal flow at
   the size of the card it is about to become makes loading read as the form
   arriving rather than a panel flashing over the page. */
.modal__form .jobber-inline-work-request.jobber-spinner {
  position: relative;
  width: auto;
  height: auto;
  min-height: 300px;
  opacity: 1;
}

.modal__form iframe {
  display: block;
  width: 100%;
  border: 0;
}

.modal__fallback {
  padding: 24px 8px;
  color: var(--peri);
  text-align: center;
}

@media (max-width: 560px) {
  .modal__panel {
    border-radius: var(--r-lg);
  }

  .modal__choice {
    gap: 12px;
    padding: 14px;
  }

  .modal__choice .icon-tile {
    width: 38px;
    height: 38px;
    font-size: 1.125rem;
  }
}

/* ------------------------------------------------------------------ cta ---- */

.cta {
  position: relative;
  overflow: hidden;
  padding: clamp(56px, 7vw, 96px) 40px 40px;
  background: var(--maho);
  border-radius: var(--r-xl);
  color: var(--white);
  text-align: center;
  isolation: isolate;
}

.cta__inner {
  position: relative;
  z-index: 1;
}

.cta__mark {
  width: 92px;
  margin: 0 auto 26px;
}

.cta h2 {
  max-width: 20ch;
  margin-inline: auto;
}

.cta p {
  max-width: 52ch;
  margin: 20px auto 0;
  color: rgb(255 255 255 / 86%);
}

.cta .btn-row {
  margin-top: 34px;
}

.cta__contact {
  display: block;
  margin-top: 22px;
  color: rgb(255 255 255 / 86%);
  font-size: 1rem;
}

.cta__contact a {
  color: var(--white);
}

/* SMS consent disclosure. Talkroute's 10DLC registration requires it beside the
   contact details and on any form that asks for a phone number. */
.sms-note {
  max-width: 62ch;
  margin: 18px auto 0;
  color: var(--peri);
  font-size: 12px;
  line-height: 1.25;
}

.sms-note a {
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 2px;
}

.sms-note a:hover {
  color: var(--white);
}

.cta .sms-note--on-dark {
  max-width: none;
  margin-top: 36px;
  color: rgb(255 255 255 / 78%);
}

/* --------------------------------------------------------------- footer ---- */

.footer {
  position: relative;
  padding-top: clamp(56px, 7vw, 88px);
  padding-bottom: 32px;
  background: var(--deep-deeper);
}

.footer__top {
  display: grid;
  gap: 40px;
  grid-template-columns: minmax(0, 1.4fr) repeat(2, minmax(0, 1fr));
}

@media (max-width: 760px) {
  .footer__top {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .footer__brand {
    grid-column: 1 / -1;
  }
}

@media (max-width: 520px) {
  .footer__top {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* Sized for the horizontal lockup's own aspect ratio (3.845:1) — the stacked
   mark this replaced was nearly square, so its 132px width doesn't carry over. */
.footer__logo {
  width: 176px;
  margin-bottom: 22px;
}

.footer__brand h3 {
  max-width: 22ch;
  margin-bottom: 16px;
  font-size: 1.0625rem;
}

.socials {
  display: flex;
  gap: 10px;
  margin-top: 22px;
}

.socials a {
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  background: rgb(0 64 255 / 34%);
  border-radius: var(--r-pill);
  color: var(--white);
  font-size: 1rem;
  transition: background-color 0.2s var(--ease), transform 0.2s var(--ease);
}

.socials a:hover {
  background: var(--maho);
  transform: translateY(-2px);
}

.footer__col h4 {
  margin-bottom: 16px;
  font-family: "Syncopate", sans-serif;
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: lowercase;
}

.footer__col li + li {
  margin-top: 10px;
}

.footer__col a {
  color: var(--peri);
  font-size: 1.0625rem;
  text-decoration: none;
}

.footer__col a:hover {
  color: var(--white);
}

.footer__contact {
  display: flex;
  align-items: center;
  gap: 10px;
  overflow-wrap: anywhere;
}

.footer__contact .icon {
  color: var(--maho);
  font-size: 1.125rem;
}

.footer__contact:hover .icon {
  color: var(--peri);
}

.footer__bottom {
  display: flex;
  flex-wrap: wrap;
  gap: 12px 28px;
  align-items: center;
  justify-content: space-between;
  margin-top: clamp(40px, 5vw, 64px);
  padding-top: 26px;
  border-top: 1px solid var(--hairline-soft);
  color: var(--peri);
  font-size: 0.9375rem;
}

.footer__legal {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 20px;
}

.footer__legal a {
  text-decoration: none;
}

/* ------------------------------------------------------------- legal ---- */
/* Shared prose styles for the privacy policy and terms of use pages —
   plain paragraphs and lists, kept inside a readable measure. */

.legal {
  max-width: 74ch;
}

.legal > * + * {
  margin-top: 16px;
}

.legal h2 {
  margin-top: 52px;
  font-size: clamp(1.25rem, 2vw, 1.5rem);
}

.legal > h2:first-child {
  margin-top: 0;
}

.legal h3 {
  margin-top: 8px;
  font-family: "Afacad", sans-serif;
  font-size: 1.0625rem;
  font-weight: 700;
  letter-spacing: 0;
  text-transform: none;
}

.legal p {
  color: var(--peri-dim);
}

.legal ul {
  padding-left: 0;
}

.legal li {
  position: relative;
  padding-left: 22px;
  color: var(--peri-dim);
}

.legal li + li {
  margin-top: 8px;
}

.legal li::before {
  content: "";
  position: absolute;
  left: 4px;
  top: 0.75em;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--peri);
}

.legal a {
  color: var(--peri);
  text-decoration: underline;
  text-underline-offset: 3px;
}

.legal a:hover {
  color: var(--white);
}

.legal strong {
  color: var(--white);
}

.legal__updated {
  margin-top: 12px;
  color: var(--peri);
  font-size: 0.9375rem;
}

