/* =============================================================================
   ECOSOUND · PUBLIC MARKETING SITE
   Layout for the landing, the pricing page and the booking page (nav header,
   landing sections, pricing page, scheduler, footer). Screen markup lives in
   js/screens.js (landing / pricingScreen / contactScreen).
   Colors/type/spacing resolve to css/tokens.css so a theme change flows through.
   ============================================================================= */

/* ---- Site shell: scrollable column, footer pinned below content -------- */
.ecs-site {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  background: var(--ecs-paper);
  overflow-y: auto;
}

/* ---- Nav header ---------------------------------------------------------
   A white bar, the height of the portal's top bar, so the landing's ink
   hero stands apart from the site's chrome above it. A hairline closes it
   off from the white pages (pricing, a call, the review policy). It scrolls
   away with the page; the tour's pinned slides keep the whole window. */
.ecs-site-nav {
  flex-shrink: 0;
  position: relative;
  z-index: 5;
  display: flex;
  align-items: center;
  justify-content: space-between;
  min-height: 64px;
  padding: 12px 64px;
  background: var(--ecs-surface);
  border-bottom: 1px solid var(--ecs-line);
}
.ecs-site-nav__brand { display: flex; align-items: center; gap: 11px; color: var(--ecs-ink); }
.ecs-site-nav__co {
  font-family: var(--ecs-font-mono);
  font-weight: var(--ecs-fw-medium);
  font-size: var(--ecs-fs-2xs);
  letter-spacing: var(--ecs-tracking-wide);
  color: var(--ecs-text-muted);
  margin-left: 6px;
  padding-top: 2px;
}
.ecs-site-nav__links { display: flex; align-items: center; gap: 30px; }
.ecs-site-nav__link {
  font-family: var(--ecs-font-body);
  font-weight: var(--ecs-fw-medium);
  font-size: var(--ecs-fs-sm);
  color: var(--ecs-text);
  cursor: pointer;
  padding-bottom: 3px;
  border-bottom: 2px solid transparent;
  transition: color var(--ecs-dur-fast) var(--ecs-ease),
              border-color var(--ecs-dur-fast) var(--ecs-ease);
}
.ecs-site-nav__link:hover { color: var(--ecs-ink); border-bottom-color: var(--ecs-line-strong); }
.ecs-site-nav__link.is-active { color: var(--ecs-ink); border-bottom-color: var(--ecs-green-500); }

/* =============================================================================
   LANDING (D) — full-width colour blocks on one content column. Each section
   is a band; `.ecs-land-inner` is the 1160px column every band shares, so the
   headings, the demo grid and the bundle all start on the same left edge.
   Sections carry no kicker: the colour block already says a new one began,
   and a label restating the heading under it was the page talking twice.
   ============================================================================= */
/* The page scrolls here, and the scrollbar's gutter is the one strip no band
   can paint: nothing a scroller holds reaches past its scrollport. So the
   gutter is kept on the right only, where the scrollbar is, and its track is
   toned as a track, so it reads as the scrollbar rather than a white gap
   beside the ink bar and the bands. (Both edges used to be reserved, to
   centre the column exactly; that left a strip at the left edge too.) */
.ecs-land {
  background: var(--ecs-surface);
  scrollbar-gutter: stable;
}
.ecs-site.ecs-scroll { scrollbar-color: var(--ecs-line-strong) var(--ecs-paper); }
.ecs-site ::selection { background: var(--ecs-green-300); color: var(--ecs-ink); }
.ecs-land-sec { padding: 96px 64px; }
.ecs-land-inner { max-width: 1160px; margin: 0 auto; }
/* The section headings are the one place the serif speaks: an italic, the
   way a survey report sets a species name, a size up from Roboto's because
   its x-height is smaller. Everything under them stays Roboto. */
.ecs-land-title {
  font: italic var(--ecs-fw-medium) var(--ecs-fs-section) / 1.06 var(--ecs-font-serif);
  font-optical-sizing: auto;
  letter-spacing: -0.012em;
  color: var(--ecs-ink);
  margin: 0 0 48px;
  text-wrap: balance;
}
/* The number is where the section falls in a batch's run (the tour, the
   download, the price), set in the band's own quiet tone so the words lead. */
.ecs-land-title__n { color: var(--ecs-text-muted); }
.ecs-land-how .ecs-land-title__n { color: var(--ecs-text-mint); }
.ecs-land-delivs .ecs-land-title__n { color: var(--ecs-text-meadow); }

/* Link-buttons keep their own label colour on hover; base.css greens every
   a:hover, which would turn a white label green on a green fill. */
.ecs-site a.ecs-btn--primary:hover { color: var(--ecs-on-dark); }
.ecs-site a.ecs-btn--ghost:hover { color: var(--ecs-ink); }
.ecs-site a.ecs-btn--bright:hover { color: var(--ecs-forest-900); }
.ecs-site a.ecs-btn--quiet:hover { color: var(--ecs-forest-600); }

/* ---- 1 · Hero (an ink slide, with the bat) ------------------------------- */
/* The first slide is a panel, not a band: ink, inset on the nav's own
   gutters with the white page around it. With the bar over it, it fills the
   first screen (.ecs-land-first, as tall as the scroller), so the tour's
   mint only comes up as the reader scrolls. The words sit on the left with
   room of their own; the photograph fills the panel's right side, flush
   with its top, edge and foot. The ink is the one the promise closes the
   page on. Two classes, so the bands' breakpoints leave the padding alone. */
.ecs-land-first {
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  min-height: 100%;
}
.ecs-land-sec.ecs-land-hero {
  flex: 1 0 auto;
  display: flex;
  flex-direction: column;
  padding: 32px 64px 64px;
  background: var(--ecs-surface);
}
.ecs-land-hero__stage {
  flex: 1 0 auto;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  width: 100%;
  max-width: 1760px;
  min-height: 480px;
  margin: 0 auto;
  background: var(--ecs-forest-900);
  color: var(--ecs-on-dark);
}
.ecs-land-hero__stage.has-photo { grid-template-columns: minmax(0, 1fr) 42%; }
/* Centred on the height, so the headline sits level with the bat's face. */
.ecs-land-hero__text {
  align-self: center;
  padding: 64px;
}
.ecs-land-hero__title {
  font: var(--ecs-fw-bold) var(--ecs-fs-landing) / 1.02 var(--ecs-font-display);
  font-size: clamp(40px, 4.1vw, 76px);
  letter-spacing: -0.025em;
  color: var(--ecs-on-dark);
  margin: 0 0 24px;
  text-wrap: balance;
}
.ecs-land-hero__sub {
  font: var(--ecs-fw-regular) var(--ecs-fs-lg) / 1.55 var(--ecs-font-body);
  /* A step up on wide screens, so it stays in scale with the headline. */
  font-size: clamp(var(--ecs-fs-lg), 1.05vw, 21px);
  color: var(--ecs-on-dark-2);
  max-width: 44ch;
  margin: 0 0 36px;
  text-wrap: pretty;
}
.ecs-land-hero__ctas { display: flex; flex-wrap: wrap; gap: 12px; }
/* The way on is the promise's own button: panel green on the ink, ink label.
   Beside it, the call is a white hairline, so there is one green moment. */
.ecs-land-hero__call {
  background: transparent;
  color: var(--ecs-on-dark);
  border: 1px solid rgba(255, 255, 255, 0.44);
}
.ecs-land-hero__call:hover { background: rgba(255, 255, 255, 0.08); border-color: var(--ecs-on-dark); }
.ecs-site a.ecs-land-hero__call:hover { color: var(--ecs-on-dark); }
.ecs-land-hero .ecs-btn:focus-visible { outline-color: var(--ecs-focus-on-dark); box-shadow: none; }

/* The print is flush with the panel: square, no frame, and its own dark
   (the cave's, a shade warmer than the ink) is what shows while it loads.
   Cropped from the top third, where the bat hangs from the flowstone. */
.ecs-land-hero__photo {
  position: relative;
  margin: 0;
  overflow: hidden;
  background: #0F0B0A;
}
.ecs-land-hero__photo img {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 35%;
  /* The one authored moment: the print lowers from the roof, the way the
     bat hangs from it. The finished picture is the resting state. */
  animation: ecs-land-hang 1.1s var(--ecs-ease-out) 120ms both;
}
@keyframes ecs-land-hang {
  from { clip-path: inset(0 0 100% 0); transform: scale(1.04); }
  to   { clip-path: inset(0); transform: none; }
}
/* The name sits on the cave's own dark at the print's foot. */
.ecs-land-hero__cap {
  position: absolute;
  left: 24px;
  bottom: 20px;
  font: var(--ecs-fw-regular) var(--ecs-fs-xs) / 1.4 var(--ecs-font-body);
  color: var(--ecs-on-dark-2);
}

/* The recording (recordingPass), as the tour's review window shows it: the
   spectrogram as the reviewer saw it, with the boxes, frequency lines and
   scale drawn over it by the page. The image is dark in itself, so what sits
   on it is light; the panel colour under it is the image's own floor, which
   is what shows while it loads. */
.ecs-land-rec__pass { min-width: 0; }
.ecs-land-rec__plot { position: relative; background: #172419; }
.ecs-land-rec__plot img { display: block; width: 100%; height: auto; }
.ecs-land-rec__over { position: absolute; inset: 0; }
/* The frequency lines run through the pass, and its labels and the 50 ms
   bar sit down its left edge, where the first call leaves room. */
.ecs-land-rec__khz {
  position: absolute;
  left: 0;
  right: 0;
  border-top: 1px dashed rgba(255, 255, 255, 0.14);
}
.ecs-land-rec__khz span {
  position: absolute;
  left: 10px;
  bottom: 3px;
  font: var(--ecs-fw-medium) var(--ecs-fs-2xs) / 1 var(--ecs-font-mono);
  letter-spacing: 0.04em;
  color: var(--ecs-on-dark-3);
}
.ecs-land-rec__call {
  position: absolute;
  box-sizing: border-box;
  border: 1.5px solid rgba(255, 255, 255, 0.78);
}
.ecs-land-rec__call.is-tagged { border-color: var(--ecs-on-dark); }
.ecs-land-rec__tag {
  position: absolute;
  left: -1.5px;
  bottom: 100%;
  padding: 3px 6px 2px;
  background: var(--ecs-on-dark);
  color: var(--ecs-ink);
  font: var(--ecs-fw-medium) var(--ecs-fs-3xs) / 1.2 var(--ecs-font-mono);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  white-space: nowrap;
}
.ecs-land-rec__time {
  position: absolute;
  top: 10px;
  right: 12px;
  font: var(--ecs-fw-medium) var(--ecs-fs-2xs) / 1 var(--ecs-font-mono);
  letter-spacing: 0.04em;
  color: var(--ecs-on-dark-2);
}
.ecs-land-rec__scale {
  position: absolute;
  left: 10px;
  bottom: 10px;
  padding-top: 5px;
  border-top: 1.5px solid rgba(255, 255, 255, 0.62);
  text-align: center;
  font: var(--ecs-fw-medium) var(--ecs-fs-2xs) / 1 var(--ecs-font-mono);
  color: var(--ecs-on-dark-3);
}
.ecs-land-rec__sp {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 4px 10px;
  margin: 10px 0 0;
  font: var(--ecs-fw-regular) var(--ecs-fs-sm) / 1.5 var(--ecs-font-body);
  color: var(--ecs-text-2);
}
.ecs-land-rec__code {
  padding: 1px 6px;
  border: 1px solid var(--ecs-line-strong);
  font: var(--ecs-fw-medium) var(--ecs-fs-3xs) / 1.4 var(--ecs-font-mono);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ecs-ink);
}
/* The boxes land call by call, the way a detector works through the file,
   each time the tour's review window comes up (see the tour's motion). */
@keyframes ecs-land-find {
  from { opacity: 0; transform: scale(1.14); }
  to   { opacity: 1; transform: none; }
}

/* Only where the intake grid is wider than its window: under ~1240px. */
.ecs-land-demo__scroll {
  display: none;
  font: var(--ecs-fw-medium) var(--ecs-fs-xs) / 1.5 var(--ecs-font-body);
  color: var(--ecs-green-600);
}

/* The demo grid is a picture of the product, not a control: a narrower row
   header so fourteen nights fit the column, and nothing that looks clickable. */
.ecs-matrix.is-demo .ecs-matrix__corner,
.ecs-matrix.is-demo .ecs-matrix__rowh { width: 176px; min-width: 176px; }
.ecs-matrix.is-demo .ecs-matrix__rowh { padding-top: 9px; padding-bottom: 9px; }
/* No tick in front of the name, so nothing for the recorder line to indent
   under. */
.ecs-matrix.is-demo .ecs-matrix__rowmeta { padding-left: 0; margin-top: 2px; }
/* Each count fills its row: a 34px chip in a 56px row left a white seam under
   every site. `height: 1px` on the cell is what lets 100% resolve to the row. */
.ecs-matrix.is-demo .ecs-matrix__c { height: 1px; }
.ecs-matrix.is-demo .ecs-matrix__cell {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  height: 100%;
  min-height: 34px;
  line-height: 1.2;
  cursor: default;
}
.ecs-matrix.is-demo .ecs-matrix__cell:hover { outline: none; }
.ecs-matrix__name {
  font: var(--ecs-fw-medium) var(--ecs-fs-sm) / 1.4 var(--ecs-font-body);
  color: var(--ecs-ink);
}
/* The grid fills in night by night, left to right, the way the folder is
   read. It starts visible (0.2), so a paused or reduced-motion render is
   never a blank frame. */
.ecs-matrix.is-demo .ecs-matrix__cell {
  animation: ecs-land-read 0.5s var(--ecs-ease-out) both;
  animation-delay: calc(240ms + var(--c, 0) * 45ms);
}
@keyframes ecs-land-read {
  from { opacity: 0.2; }
  to   { opacity: 1; }
}

/* ---- 2 · How it works (mint): the tour ----------------------------------- */
/* Two layouts share one markup. Here, the unfolded one, for a phone or a
   window too short to pin: one column, the heading and its line, then every
   step with its icon and its picture under it, all of them finished (the
   media block after the pictures). Wide and tall enough, the slide is pinned
   whole: the heading and its line side by side over the route, and one step
   at a time beside the window (the block after that).
   Quiet text on the band is the mint's own grey (--ecs-text-mint), not a
   neutral one, so the words sit in the green rather than on it. */
.ecs-land-how { background: var(--ecs-green-200); }
.ecs-land-tour {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  align-items: start;
}
.ecs-land-how__head { margin-bottom: 48px; }
.ecs-land-how__title { margin: 0 0 16px; }
.ecs-land-route { display: none; }
.ecs-land-steps {
  list-style: none;
  margin: 0;
  padding: 0;
}
.ecs-land-step {
  position: relative;
  display: grid;
  grid-template-columns: 48px minmax(0, 1fr);
  align-content: start;
  column-gap: 24px;
}
.ecs-land-step__head { display: contents; }
.ecs-land-step__icon {
  grid-row: 1 / span 2;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  border: 1.5px solid var(--ecs-forest-500);
  border-radius: var(--ecs-radius-pill);
  color: var(--ecs-forest-500);
  background: var(--ecs-green-200);
  transition: background-color var(--ecs-dur-base) var(--ecs-ease-out),
              color var(--ecs-dur-base) var(--ecs-ease-out),
              box-shadow var(--ecs-dur-base) var(--ecs-ease-out);
}
/* The title is set like the hero, tight and heavy, so the four read as
   headlines; the body under it steps back to the mint's grey. The title's
   first line sits on the circle's centre line. */
.ecs-land-step > :not(.ecs-land-step__head) { grid-column: 2; }
.ecs-land-step__title {
  grid-column: 2;
  font: var(--ecs-fw-bold) var(--ecs-fs-h3) / 1.1 var(--ecs-font-display);
  letter-spacing: -0.025em;
  color: var(--ecs-ink);
  margin: 0 0 12px;
  padding-top: 8px;
  text-wrap: balance;
}
.ecs-land-step__body {
  font: var(--ecs-fw-regular) var(--ecs-fs-md) / 1.6 var(--ecs-font-body);
  color: var(--ecs-text-mint);
  margin: 0;
  max-width: 46ch;
  text-wrap: pretty;
}
/* Done: the circle fills mint. Active: it fills grove and wears the halo. */
.ecs-land-step.is-done .ecs-land-step__icon { background: var(--ecs-green-300); }
.ecs-land-step.is-active .ecs-land-step__icon {
  background: var(--ecs-forest-500);
  color: var(--ecs-on-dark);
  box-shadow: 0 0 0 6px var(--ecs-green-300);
}

/* Each step's way on. Step 1 first gives the spec of what uploads, as data
   (the extensions the drop zone accepts, in mono). */
.ecs-land-step__spec {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  margin: 20px 0 0;
}
.ecs-land-step__fmt {
  padding: 3px 8px;
  background: var(--ecs-surface);
  border: 1px solid var(--ecs-line-mint);
  font: var(--ecs-fw-medium) var(--ecs-fs-2xs) / 1.4 var(--ecs-font-mono);
  color: var(--ecs-ink);
}
.ecs-land-step__fmtnote {
  margin-left: 6px;
  font: var(--ecs-fw-medium) var(--ecs-fs-2xs) / 1.4 var(--ecs-font-mono);
  color: var(--ecs-text-mint);
}
/* The one button every step ends on, so as the tour moves on only its words
   change. At rest it is Sprout, the lightest green that still reads as a
   button on the mint, with an ink label. Under the pointer it steps to
   Meadow and the arrow steps on; pressed, it goes dark at once (Fir, with a
   white label). A step's note, where it has one, leads in. */
.ecs-land-step__cta { margin-top: 24px; }
.ecs-land-go {
  gap: 8px;
  min-height: 40px;
  padding: 0 16px 0 18px;
  background: var(--ecs-green-350);
  color: var(--ecs-forest-900);
  font-size: var(--ecs-fs-base);
}
.ecs-land-go:hover,
.ecs-land-go:focus-visible {
  background: var(--ecs-green-400);
  color: var(--ecs-forest-900);
}
.ecs-land-go:active {
  background: var(--ecs-forest-600);
  color: var(--ecs-on-dark);
  transition-duration: 0s;
}
.ecs-land-go svg { transition: transform var(--ecs-dur-fast) var(--ecs-ease-out); }
.ecs-land-go:hover svg,
.ecs-land-go:focus-visible svg { transform: translateX(3px); }
.ecs-land-step__note {
  margin: 0 0 10px;
  font: var(--ecs-fw-regular) var(--ecs-fs-xs) / 1.5 var(--ecs-font-body);
  color: var(--ecs-text-mint);
}
.ecs-land-step__note--below { margin: 10px 0 0; }

/* The window. Every picture sits in the same grid cell, so the window is as
   tall as the tallest and nothing jumps when they swap; the ones not being
   read are transparent, not hidden, so a screen reader still has all four.
   The swap is a crossfade in place: the window itself never moves. */
.ecs-land-stage {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
}
.ecs-land-view {
  grid-area: 1 / 1;
  display: flex;
  flex-direction: column;
  margin: 0;
  background: var(--ecs-surface);
  border: 1px solid rgba(var(--ecs-ink-rgb), 0.22);
  color: var(--ecs-text);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--ecs-dur-base) var(--ecs-ease-out);
}
.ecs-land-view.is-active { opacity: 1; pointer-events: auto; }
/* All four windows are the portal's light screen: white, an ink hairline,
   a Lab Paper title bar. The bar names the screen the way the portal would
   (the project, the quote, the review, the file), and the project sits on
   the right of every bar that is not already that name. */
.ecs-land-view__bar {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
  padding: 9px 20px;
  border-bottom: 1px solid var(--ecs-line);
  background: var(--ecs-paper);
  font: var(--ecs-fw-medium) var(--ecs-fs-3xs) / 1.4 var(--ecs-font-mono);
  letter-spacing: var(--ecs-tracking-wide);
  text-transform: uppercase;
  color: var(--ecs-ink);
}
.ecs-land-view__body {
  position: relative;
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 14px;
  padding: 18px 20px;
  min-width: 0;
}
.ecs-land-view__text {
  margin: 0;
  font: var(--ecs-fw-regular) var(--ecs-fs-sm) / 1.5 var(--ecs-font-body);
  color: var(--ecs-text-2);
}

/* 1 · the intake grid, narrowed to fit the window: fourteen nights in the
   column the stage has, not the page's. The totals are the page's business, not the picture's: the per-night
   counts, the footer and the nights column step out, and a night's head
   folds onto two lines. */
.ecs-land-view .ecs-matrix.is-demo .ecs-matrix__corner,
.ecs-land-view .ecs-matrix.is-demo .ecs-matrix__rowh { width: 116px; min-width: 116px; padding-top: 4px; padding-bottom: 4px; }
.ecs-land-view .ecs-matrix.is-demo .ecs-matrix__name { line-height: 1.25; }
.ecs-land-view .ecs-matrix.is-demo .ecs-matrix__rowmeta { margin-top: 0; line-height: 1.3; }
.ecs-land-view .ecs-matrix.is-demo .ecs-matrix__colh { min-width: 0; padding: 6px 2px 5px; }
.ecs-land-view .ecs-matrix.is-demo .ecs-matrix__colday { white-space: normal; }
.ecs-land-view .ecs-matrix.is-demo .ecs-matrix__cell { min-width: 0; min-height: 30px; padding-left: 2px; padding-right: 5px; }
.ecs-land-view .ecs-matrix.is-demo .ecs-matrix__coltot,
.ecs-land-view .ecs-matrix.is-demo tfoot,
.ecs-land-view .ecs-matrix.is-demo .ecs-matrix__toth:nth-last-child(2),
.ecs-land-view .ecs-matrix.is-demo .ecs-matrix__tot:nth-last-child(2) { display: none; }
.ecs-land-view .ecs-matrix__rowmeta { white-space: nowrap; }

/* 2 · the quote: the sample as 400 recordings, the flagged ones in grove,
   and the quote's own figures beside it. */
.ecs-land-quote {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  align-items: center;
  column-gap: 28px;
}
.ecs-land-quote__pic { display: grid; gap: 12px; max-width: 260px; }
.ecs-land-quote__sample {
  width: 100%;
  max-width: 260px;
  display: grid;
  grid-template-columns: repeat(20, minmax(0, 1fr));
  gap: 3px;
}
.ecs-land-quote__sample i {
  aspect-ratio: 1;
  background: var(--ecs-green-200);
}
.ecs-land-quote__sample i.is-bat { background: var(--ecs-forest-500); }
.ecs-land-quote__sum dl { margin: 0 0 20px; }
.ecs-land-quote__row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
  padding: 9px 0;
  border-top: 1px solid var(--ecs-line);
}
.ecs-land-quote__row:first-child { border-top: 0; }
.ecs-land-quote__row dt { font: var(--ecs-fw-regular) var(--ecs-fs-sm) / 1.4 var(--ecs-font-body); color: var(--ecs-text); }
.ecs-land-quote__row dd {
  margin: 0;
  font: var(--ecs-fw-medium) var(--ecs-fs-xs) / 1.4 var(--ecs-font-mono);
  font-variant-numeric: tabular-nums;
  color: var(--ecs-ink);
  white-space: nowrap;
}
.ecs-land-quote__row.is-total { border-top-color: var(--ecs-line-strong); padding-top: 14px; }
.ecs-land-quote__row.is-total dt { font-weight: var(--ecs-fw-medium); color: var(--ecs-ink); }
.ecs-land-quote__row.is-total dd {
  font: var(--ecs-fw-bold) var(--ecs-fs-h3) / 1 var(--ecs-font-display);
  letter-spacing: var(--ecs-tracking-tight);
  color: var(--ecs-forest-500);
}
/* A picture of the button, not the button: nothing here can be pressed. */
.ecs-land-quote__accept { width: 100%; justify-content: center; gap: 8px; cursor: default; pointer-events: none; }

/* 3 · the review: the pass, then who touches every call. */
.ecs-land-review .ecs-land-rec__sp { margin-top: 10px; }
.ecs-land-trail {
  list-style: none;
  margin: 0;
  padding: 14px 0 0;
  border-top: 1px solid var(--ecs-line);
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 16px;
}
.ecs-land-trail__step {
  display: grid;
  grid-template-columns: 24px minmax(0, 1fr);
  column-gap: 10px;
  align-items: start;
  font: var(--ecs-fw-regular) var(--ecs-fs-sm) / 1.4 var(--ecs-font-body);
  color: var(--ecs-text);
}
.ecs-land-trail__mark {
  grid-row: 1 / span 2;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  border-radius: var(--ecs-radius-pill);
  background: var(--ecs-green-200);
  color: var(--ecs-forest-500);
}
.ecs-land-trail__who { font-weight: var(--ecs-fw-medium); color: var(--ecs-ink); }

/* 4 · the map: a 1 km grid, one stream, the six sites. */
.ecs-land-map { display: block; width: 100%; height: auto; background: var(--ecs-green-100); }
.ecs-land-map__grid line { stroke: var(--ecs-line-mint); stroke-width: 1; stroke-dasharray: 3 4; }
.ecs-land-map__stream { fill: none; stroke: var(--ecs-info-line); stroke-width: 5; stroke-linecap: round; }
.ecs-land-map__area { fill: rgba(var(--ecs-accent-rgb), 0.14); stroke: var(--ecs-forest-500); stroke-width: 1.5; }
.ecs-land-map__dot { fill: var(--ecs-ink); }
.ecs-land-map__name { font: var(--ecs-fw-medium) var(--ecs-fs-sm) var(--ecs-font-body); fill: var(--ecs-ink); }
.ecs-land-map__n { font: var(--ecs-fw-medium) var(--ecs-fs-xs) var(--ecs-font-mono); fill: var(--ecs-text-muted); }
.ecs-land-map__scale path,
.ecs-land-map__north path { fill: none; stroke: var(--ecs-ink); stroke-width: 1.5; }
.ecs-land-map__north path { fill: var(--ecs-ink); stroke: none; }
.ecs-land-map__scale text,
.ecs-land-map__north text { font: var(--ecs-fw-medium) var(--ecs-fs-xs) var(--ecs-font-mono); fill: var(--ecs-ink); }
.ecs-land-map__north text { text-anchor: middle; }
.ecs-land-map__site { transform-box: fill-box; transform-origin: center; }

/* The folder and the quote load before they show (has-load): the folders
   being read, one bar per recorder site, or the quote's three phases ticked
   off in turn, over the window's body, and then the screen itself. It lasts
   --lead, well under two seconds. landingTour.js marks the tour is-live
   (never under reduced motion) and a window is-played once it is up and on
   screen; until then it waits at the start, and with no script at all the
   loading never shows and the screen is simply there. */
.ecs-land-view.has-load { --lead: 1250ms; }
.ecs-land-load {
  position: absolute;
  inset: 0;
  display: none;
  align-items: center;
  justify-content: center;
  padding: 18px 20px;
  pointer-events: none;
}
.ecs-land-tour.is-live .ecs-land-view.has-load .ecs-land-load { display: flex; }
.ecs-land-tour.is-live .ecs-land-view.has-load:not(.is-played) .ecs-land-view__body > :not(.ecs-land-load) { opacity: 0; }
.ecs-land-load__panel { width: min(100%, 420px); }
.ecs-land-load__head {
  display: flex;
  justify-content: space-between;
  gap: 16px;
  margin: 0 0 6px;
  padding-bottom: 10px;
  border-bottom: 1px solid var(--ecs-line);
  font: var(--ecs-fw-medium) var(--ecs-fs-3xs) / 1.4 var(--ecs-font-mono);
  letter-spacing: var(--ecs-tracking-wide);
  text-transform: uppercase;
  color: var(--ecs-ink);
}
.ecs-land-load__head span + span { color: var(--ecs-text-muted); font-variant-numeric: tabular-nums; }
.ecs-land-load__sites,
.ecs-land-load__phases { list-style: none; margin: 0; padding: 0; }
/* The folders: as the upload screen's per-site rows (.ecs-upsite), a name,
   a 4px bar and the site's count, each bar filling a beat after the last. */
.ecs-land-load__sites li {
  display: grid;
  grid-template-columns: 6.5rem minmax(0, 1fr) 3.5rem;
  align-items: center;
  gap: 14px;
  min-height: 30px;
  border-bottom: 1px solid var(--ecs-line-4);
}
.ecs-land-load__sites li:last-child { border-bottom: 0; }
.ecs-land-load__name { font: var(--ecs-fw-medium) var(--ecs-fs-xs) / 1.3 var(--ecs-font-body); color: var(--ecs-ink); }
.ecs-land-load__bar { height: 4px; overflow: hidden; background: var(--ecs-line-4); }
.ecs-land-load__bar i {
  display: block;
  height: 100%;
  background: var(--ecs-forest-500);
  transform: scaleX(0);
  transform-origin: left;
}
.ecs-land-load__n {
  text-align: right;
  font: var(--ecs-fw-regular) var(--ecs-fs-2xs) / 1.3 var(--ecs-font-mono);
  font-variant-numeric: tabular-nums;
  color: var(--ecs-text-muted);
}
/* The quote's phases: a ring for the one still to come, grove for the one
   running, a grove disc with its tick once it is done. */
.ecs-land-load__phases li {
  display: grid;
  grid-template-columns: 20px minmax(0, 1fr);
  align-items: center;
  gap: 12px;
  min-height: 38px;
  font: var(--ecs-fw-regular) var(--ecs-fs-sm) / 1.35 var(--ecs-font-body);
  color: var(--ecs-text-muted);
}
.ecs-land-load__dot {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  border: 1.5px solid var(--ecs-line-strong);
  border-radius: var(--ecs-radius-pill);
  color: var(--ecs-on-dark);
}
.ecs-land-load__dot svg { opacity: 0; }

/* Played: each site's bar fills a beat after the one above it, or each phase
   runs and is ticked off, then the loading lifts and the screen comes up. */
.ecs-land-view.is-played .ecs-land-load { animation: ecs-land-lift 0.22s var(--ecs-ease-out) calc(var(--lead) - 100ms) both; }
.ecs-land-view.is-played .ecs-land-view__body > :not(.ecs-land-load) { animation: ecs-land-show 0.34s var(--ecs-ease-out) var(--lead) both; }
.ecs-land-view.is-played .ecs-land-load__bar i { animation: ecs-land-fill 0.55s var(--ecs-ease-out) calc(60ms + var(--k, 0) * 100ms) both; }
.ecs-land-view.is-played .ecs-land-load__n { animation: ecs-land-done 0.2s var(--ecs-ease-out) calc(560ms + var(--k, 0) * 100ms) both; }
.ecs-land-view.is-played .ecs-land-load__phases li { animation: ecs-land-done 0.2s var(--ecs-ease-out) calc(60ms + var(--k, 0) * 380ms) both; }
/* Running, then done: the second only takes over at its own time
   (forwards, not both), so until then the first holds the ring. */
.ecs-land-view.is-played .ecs-land-load__dot {
  animation: ecs-land-run 0.2s var(--ecs-ease-out) calc(60ms + var(--k, 0) * 380ms) both,
             ecs-land-tick 0.22s var(--ecs-ease-out) calc(60ms + (var(--k, 0) + 1) * 380ms) forwards;
}
.ecs-land-view.is-played .ecs-land-load__dot svg { animation: ecs-land-mark 0.22s var(--ecs-ease-out) calc(60ms + (var(--k, 0) + 1) * 380ms) both; }
@keyframes ecs-land-lift { from { opacity: 1; } to { opacity: 0; transform: translateY(-6px); } }
@keyframes ecs-land-show { from { opacity: 0; } to { opacity: 1; } }
@keyframes ecs-land-fill { from { transform: scaleX(0); } to { transform: scaleX(1); } }
@keyframes ecs-land-done { from { color: var(--ecs-text-muted); } to { color: var(--ecs-ink); } }
@keyframes ecs-land-run {
  from { border-color: var(--ecs-line-strong); }
  to   { border-color: var(--ecs-forest-500); box-shadow: 0 0 0 4px var(--ecs-green-200); }
}
@keyframes ecs-land-tick {
  from { border-color: var(--ecs-forest-500); background: transparent; box-shadow: 0 0 0 4px var(--ecs-green-200); }
  to   { border-color: var(--ecs-forest-500); background: var(--ecs-forest-500); box-shadow: 0 0 0 0 var(--ecs-green-200); }
}
@keyframes ecs-land-mark { from { opacity: 0; transform: scale(0.6); } to { opacity: 1; transform: none; } }

/* The window's one authored moment, replayed each time a picture comes up:
   what the step finds lands piece by piece — the grid's nights, the sample's
   bats, the pass's calls and then its reviewers, the map's sites. The two
   that load start once their loading has lifted (--lead). Outside the
   window, and under reduced motion, every picture is simply finished. */
.ecs-land-view .ecs-matrix.is-demo .ecs-matrix__cell,
.ecs-land-view .ecs-land-rec__call { animation: none; }
.ecs-land-view.is-played .ecs-matrix.is-demo .ecs-matrix__cell {
  animation: ecs-land-read 0.5s var(--ecs-ease-out) both;
  animation-delay: calc(var(--lead) + 120ms + var(--c, 0) * 40ms);
}
.ecs-land-view.is-played .ecs-land-quote__sample i.is-bat {
  animation: ecs-land-flag 0.5s var(--ecs-ease-out) both;
  animation-delay: calc(var(--lead) + 160ms + var(--k, 0) * 28ms);
}
.ecs-land-view.is-active .ecs-land-rec__call {
  animation: ecs-land-find 0.45s var(--ecs-ease-out) both;
  animation-delay: calc(160ms + var(--i, 0) * 110ms);
}
.ecs-land-view.is-active .ecs-land-trail__step {
  animation: ecs-land-rise 0.5s var(--ecs-ease-out) both;
  animation-delay: calc(700ms + var(--k, 0) * 160ms);
}
.ecs-land-view.is-active .ecs-land-map__site {
  animation: ecs-land-find 0.5s var(--ecs-ease-out) both;
  animation-delay: calc(160ms + var(--k, 0) * 90ms);
}
@keyframes ecs-land-flag {
  from { background: var(--ecs-green-200); }
  to   { background: var(--ecs-forest-500); }
}
@keyframes ecs-land-rise {
  from { opacity: 0.25; transform: translateY(6px); }
  to   { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .ecs-land-view,
  .ecs-land-step__icon { transition: none; }
  .ecs-land-tour.is-live .ecs-land-view.has-load .ecs-land-load { display: none; }
  .ecs-land-tour.is-live .ecs-land-view.has-load .ecs-land-view__body > :not(.ecs-land-load) { opacity: 1; animation: none; }
  .ecs-land-view.is-played .ecs-matrix.is-demo .ecs-matrix__cell,
  .ecs-land-view.is-played .ecs-land-quote__sample i.is-bat,
  .ecs-land-view.is-active .ecs-land-rec__call,
  .ecs-land-view.is-active .ecs-land-trail__step,
  .ecs-land-view.is-active .ecs-land-map__site { animation: none; }
}
/* Unfolded (a phone, or a window too short to pin): no window to hold still
   beside the steps, so each picture falls in under its own step, all of them
   finished. The list and the stage step aside (display: contents) so their
   children can interleave in one column. */
@media (max-width: 860px), (max-height: 559px) {
  .ecs-land-how__side,
  .ecs-land-steps,
  .ecs-land-stage-col,
  .ecs-land-stage { display: contents; }
  .ecs-land-step { margin-bottom: 24px; }
  .ecs-land-step[data-step="1"] { order: 2; }
  .ecs-land-step[data-step="2"] { order: 4; }
  .ecs-land-step[data-step="3"] { order: 6; }
  .ecs-land-view[data-view="0"] { order: 1; }
  .ecs-land-view[data-view="1"] { order: 3; }
  .ecs-land-view[data-view="2"] { order: 5; }
  .ecs-land-view[data-view="3"] { order: 7; }
  .ecs-land-view { grid-area: auto; opacity: 1; transform: none; pointer-events: auto; margin-bottom: 56px; }
  .ecs-land-where { order: 8; }
}

/* The pinned slide: the heading, the route, the step being read and its
   window hold still as one for the length of the track, and a stretch of
   scroll under them (--tour-step) moves the tour one station on. The track
   is three stretches, first station to last: the slide pins as the first
   step's station comes up and starts to leave as soon as the reader goes
   on from the last. js/landingTour.js steers the page over it a station a
   gesture; under reduced motion it scrolls freely. */
@media (min-width: 861px) and (min-height: 560px) {
  .ecs-land-how { padding-top: 0; --tour-step: 220vh; }
  .ecs-land-how__track {
    position: relative;
    height: calc(100vh + 3 * var(--tour-step));
  }
  /* The heading gets a band's own room over it (as much as the bands'
     96px on a 800px screen), more than the slide keeps under its last
     line. On a short screen the window gives up height to it (--fit),
     rather than the heading its room. */
  .ecs-land-how__pin {
    position: sticky;
    top: 0;
    height: 100vh;
    display: flex;
    flex-direction: column;
    justify-content: center;
    padding: clamp(48px, 12vh, 120px) 0 clamp(24px, 5vh, 48px);
  }
  .ecs-land-tour {
    grid-template-columns: minmax(0, 4fr) minmax(0, 8fr);
    column-gap: 64px;
  }

  /* The heading takes the steps' column. Under it, the route runs the full
     width: the steps' icons as stations, and a grove fill (--route, 0..1)
     along the mint track as the reader scrolls. Reached stations fill mint,
     the current one grove with the halo. */
  .ecs-land-how__head { display: contents; }
  .ecs-land-how__title {
    align-self: end;
    font-size: clamp(40px, 3.6vw, 52px);
    line-height: 1;
    margin: 0;
  }
  .ecs-land-route {
    grid-column: 1 / -1;
    display: block;
    margin: clamp(20px, 4.5vh, 44px) 0 clamp(24px, 5vh, 52px);
  }
  .ecs-land-route__line {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: space-between;
  }
  /* The track and its fill run centre to centre, first station to last, so
     a third of the fill lands exactly on the second station. */
  .ecs-land-route__line::before,
  .ecs-land-route__line::after {
    content: "";
    position: absolute;
    left: 24px;
    right: 24px;
    top: calc(50% - 0.75px);
    height: 1.5px;
    transform-origin: left;
  }
  .ecs-land-route__line::before { background: var(--ecs-line-mint); }
  .ecs-land-route__line::after {
    background: var(--ecs-forest-500);
    transform: scaleX(var(--route, 0));
  }
  .ecs-land-route__stop {
    position: relative;
    z-index: 1;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 48px;
    height: 48px;
    border: 1.5px solid var(--ecs-forest-500);
    border-radius: var(--ecs-radius-pill);
    color: var(--ecs-forest-500);
    background: var(--ecs-green-200);
    transition: background-color var(--ecs-dur-base) var(--ecs-ease-out),
                color var(--ecs-dur-base) var(--ecs-ease-out),
                box-shadow var(--ecs-dur-base) var(--ecs-ease-out);
  }
  .ecs-land-route__stop.is-reached { background: var(--ecs-green-300); }
  .ecs-land-route__stop.is-here {
    background: var(--ecs-forest-500);
    color: var(--ecs-on-dark);
    box-shadow: 0 0 0 6px var(--ecs-green-300);
  }
  /* One step at a time: all four share one cell, and only the one being
     read is up. The others are transparent, not hidden, so a screen reader
     still has all four, and they take no clicks; the keyboard brings one up
     (landingTour.js onFocus). Its icon is the route's station, so it steps
     out. The shared cell is as tall as the longest step, and each step's
     button drops to its foot, so the button sits on one line, just under
     the longest step's words, whichever step is up. */
  .ecs-land-steps { display: grid; }
  .ecs-land-step {
    grid-area: 1 / 1;
    display: flex;
    flex-direction: column;
    opacity: 0;
    pointer-events: none;
    transform: translateY(12px);
    transition: opacity var(--ecs-dur-base) var(--ecs-ease-out),
                transform var(--ecs-dur-slow) var(--ecs-ease-out);
  }
  .ecs-land-step.is-active { opacity: 1; pointer-events: auto; transform: none; }
  .ecs-land-step__icon { display: none; }
  .ecs-land-step__title {
    font-size: clamp(30px, 2.7vw, 38px);
    line-height: 1.06;
    margin: 0 0 18px;
    padding-top: 0;
  }
  .ecs-land-step__body {
    font-size: var(--ecs-fs-lg);
    line-height: 1.6;
    max-width: 34ch;
  }
  /* The archive note hangs under Book a call without lifting that button.
     Every step keeps the same space under its button, so the four buttons
     stay on one line. */
  .ecs-land-step__cta { margin-top: auto; padding-top: 24px; position: relative; padding-bottom: 30px; }
  .ecs-land-step__note--below {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    margin: 0;
  }

  /* The review's pass, set wide so the window stays short: the spectrogram
     is drawn squatter, boxes and gridlines with it (they are placed in
     percent of the frame). */
  .ecs-land-review .ecs-land-rec__plot { aspect-ratio: 5 / 2; }
  .ecs-land-review .ecs-land-rec__plot img { height: 100%; object-fit: fill; }

  /* On a short window the pictures shrink to fit under the route rather
     than push it off the top: the tour sets --fit and the height it takes
     back (--fit-trim) from the window's natural size. */
  .ecs-land-stage {
    transform: scale(var(--fit, 1));
    transform-origin: top right;
    margin-bottom: calc(-1 * var(--fit-trim, 0px));
  }
}
@media (prefers-reduced-motion: reduce) {
  .ecs-land-step,
  .ecs-land-route__stop,
  .ecs-land-go svg { transition: none; }
  .ecs-land-step { transform: none; }
}
.ecs-land-where {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 56px 0 0;
  /* The window scales from its top right, so its drawn left edge sits in by
     (1 - --fit) of the column. The note follows that edge. */
  margin-left: calc((1 - var(--fit, 1)) * 100%);
  padding-top: 20px;
  border-top: 1px solid var(--ecs-line-mint);
  font: var(--ecs-fw-medium) var(--ecs-fs-sm) / 1.5 var(--ecs-font-body);
  color: var(--ecs-green-600);
}
.ecs-land-where svg { flex-shrink: 0; }
/* Pinned, the note sits just under the window. The base gap is for the
   unfolded column, where the note follows the last step. */
@media (min-width: 861px) and (min-height: 560px) {
  .ecs-land-where {
    margin-top: 16px;
    padding-top: 12px;
  }
}

/* ---- 3 · What you receive (panel green, ink text): the zip, opened ------
   The tour's slide mirrored, so the page runs in a zigzag: the window takes
   the side the tour's steps had, at the tour window's width, and the
   heading and its files stand where the tour's window stood. The batch's
   name is the right side of the window's bar. With the heading beside the
   window rather than over it, the band keeps the others' padding and still
   lands on one screen at 1280×800. Narrow, it is one column: the heading,
   then its files as tabs on the window's top edge. */
.ecs-land-delivs { background: var(--ecs-green-400); }
.ecs-land-res { display: flex; flex-direction: column; }
.ecs-land-deliv__fmt {
  display: inline-block;
  margin-left: 10px;
  padding: 2px 6px;
  vertical-align: 2px;
  background: var(--ecs-forest-900);
  color: var(--ecs-green-400);
  font: var(--ecs-fw-medium) var(--ecs-fs-3xs) / 1.3 var(--ecs-font-mono);
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

/* The files, as tabs: square, on the band, and the one that is open is the
   window's paper. Here, narrow, they are the window's own file tabs, and the
   open one joins the bar under it; wide, they are a list down the window's
   side (the block after). One tab stop; the arrows move along them
   (js/landingResults.js). */
.ecs-land-res__tabs {
  position: relative;
  z-index: 1;
  display: flex;
  min-width: 0;
  margin-bottom: -1px;
  overflow-x: auto;
  scrollbar-width: none;
}
.ecs-land-res__tabs::-webkit-scrollbar { display: none; }
.ecs-land-res__tab {
  appearance: none;
  flex: none;
  min-height: 38px;
  margin: 0;
  padding: 0 20px;
  border: 1px solid transparent;
  border-bottom: 0;
  border-radius: 0;
  background: transparent;
  font: var(--ecs-fw-medium) var(--ecs-fs-sm) / 1 var(--ecs-font-body);
  color: var(--ecs-ink);
  white-space: nowrap;
  cursor: pointer;
  transition: background-color var(--ecs-dur-fast) var(--ecs-ease-out);
}
.ecs-land-res__tab:hover { background: rgba(255, 255, 255, 0.34); }
.ecs-land-res__tab.is-active {
  background: var(--ecs-paper);
  border-color: rgba(var(--ecs-ink-rgb), 0.22);
  cursor: default;
}
/* Inset, because the strip scrolls and would clip a ring drawn outside. */
.ecs-land-res__tab:focus-visible { outline-offset: -5px; box-shadow: none; }
/* Each file's count, measured, so mono: the label is its unit. Quiet in the
   band's own green-ink, ink once its file is open. */
.ecs-land-res__count {
  margin-left: 4px;
  font: var(--ecs-fw-medium) var(--ecs-fs-2xs) / 1 var(--ecs-font-mono);
  font-variant-numeric: tabular-nums;
  color: var(--ecs-text-meadow);
}
.ecs-land-res__tab.is-active .ecs-land-res__count { color: var(--ecs-ink); }
/* The batch's name, on the right of the file it belongs to. On a phone the
   bar wraps and the name stays at the right. */
.ecs-land-res .ecs-land-view__bar { flex-wrap: wrap; }
.ecs-land-res .ecs-land-view__bar > span:last-child { margin-left: auto; text-align: right; }

/* Wide: the window on the left at the tour window's share (8 of 12, the
   same 64px gap), and down the right, the heading and its files as an
   index: each file a row on the band's hairline, its name at the tour's
   step-title weight and its count at the right edge, and the rows share
   the height so the last hairline lands level with the window's foot, as
   the pricing sum ends level with its sheet. The open one is the window's
   paper, as its tab is. */
@media (min-width: 861px) {
  .ecs-land-res {
    display: grid;
    grid-template-columns: minmax(0, 8fr) minmax(0, 4fr);
    grid-template-rows: auto auto 1fr;
    column-gap: 64px;
  }
  /* Same width as the tour's window, which shrinks by --fit on a short
     screen (landingTour.js shares it as --tour-fit). */
  .ecs-land-res__window {
    grid-column: 1;
    grid-row: 1 / -1;
    align-self: start;
    width: calc(var(--tour-fit, 1) * 100%);
  }
  .ecs-land-res__title,
  .ecs-land-res__tabs { grid-column: 2; }
  /* The tour heading's own size, so the two read as a pair. */
  .ecs-land-res__title {
    font-size: clamp(40px, 3.6vw, 52px);
    line-height: 1;
    margin: 0 0 40px;
  }
  .ecs-land-res__tabs {
    grid-row: 2 / -1;
    align-self: stretch;
    flex-direction: column;
    margin: 0;
    overflow: visible;
    border-top: 1px solid rgba(var(--ecs-ink-rgb), 0.22);
  }
  /* One line per row, name and count on a shared baseline, the pair
     centred in the row's height. */
  .ecs-land-res__tab {
    flex: 1 0 auto;
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    align-content: center;
    align-items: baseline;
    column-gap: 16px;
    min-height: 56px;
    padding: 0 20px;
    border: 0;
    border-bottom: 1px solid rgba(var(--ecs-ink-rgb), 0.22);
    text-align: left;
  }
  .ecs-land-res__name {
    font: var(--ecs-fw-bold) clamp(22px, 1.9vw, 28px) / 1.1 var(--ecs-font-display);
    letter-spacing: -0.025em;
  }
  .ecs-land-res__count {
    margin: 0;
    font-size: var(--ecs-fs-md);
  }
}

/* The window: the open file, and provenance.json as its status bar under
   every tab. Every pane shares one cell, so the window is as tall as the
   tallest and nothing jumps as the tabs change; the ones not open are
   hidden from view and from a screen reader, which reaches each through
   its tab. */
.ecs-land-res__window {
  container: res-window / inline-size;
  display: flex;
  flex-direction: column;
  background: var(--ecs-surface);
  border: 1px solid rgba(var(--ecs-ink-rgb), 0.22);
}
.ecs-land-res__stage { display: grid; grid-template-columns: minmax(0, 1fr); min-width: 0; }
.ecs-land-res__pane {
  grid-area: 1 / 1;
  display: flex;
  flex-direction: column;
  min-width: 0;
  visibility: hidden;
  opacity: 0;
  transition: opacity var(--ecs-dur-fast) var(--ecs-ease-out), visibility 0s linear var(--ecs-dur-fast);
}
.ecs-land-res__pane.is-active {
  visibility: visible;
  opacity: 1;
  transition: opacity var(--ecs-dur-base) var(--ecs-ease-out), visibility 0s;
}
.ecs-land-res__pane:focus-visible { outline-offset: -4px; box-shadow: none; }
.ecs-land-res__body { flex: 1; min-width: 0; padding: 14px 20px 16px; }
.ecs-land-res__body .ecs-chart__head { margin-bottom: 8px; }
.ecs-land-res__chart + .ecs-land-res__chart { margin-top: 14px; }
.ecs-land-res__text {
  margin: 8px 0 0;
  font: var(--ecs-fw-regular) var(--ecs-fs-sm) / 1.4 var(--ecs-font-body);
  color: var(--ecs-text-2);
}
/* Sites pane fills the window so the offset note can sit in its bottom-right corner. */
.ecs-land-res__body--sites {
  display: flex;
  flex-direction: column;
}
.ecs-land-res__footnote {
  margin: auto 0 0;
  padding-top: 10px;
  text-align: right;
  font: var(--ecs-fw-regular) var(--ecs-fs-2xs) / 1.35 var(--ecs-font-body);
  color: var(--ecs-text-muted);
  letter-spacing: 0.01em;
}
/* The mark sits on the pill's top-right corner. Inside the pill, flex
   centering dropped it onto the word's midline. */
.ecs-land-res__tier {
  display: inline-flex;
  align-items: flex-start;
  margin-left: 10px;
  vertical-align: 1px;
}
.ecs-land-res__tier .ecs-pill { margin-left: 0; }
.ecs-land-res__tier .ecs-land-res__fn-mark {
  margin: 0 0 0 2px;
  font: 600 10px/1 var(--ecs-font-body);
  letter-spacing: 0;
  color: var(--ecs-text-muted);
}
.ecs-land-res .ecs-table thead th { padding-bottom: 6px; }
.ecs-land-res .ecs-table tbody :is(td, th) { padding-top: 5px; padding-bottom: 5px; }

/* The ranked bars get the window's width: the names keep what they need
   and the bars take the rest. */
.ecs-land-res .ecs-rank__row {
  grid-template-columns: minmax(180px, 3fr) minmax(0, 7fr) auto;
  gap: 12px;
  padding-top: 3px;
  padding-bottom: 3px;
}
.ecs-land-res .ecs-rank__label em { line-height: 1.25; }
/* Every track ends on one line, whatever the count's digits. */
.ecs-land-res .ecs-rank__value { min-width: 5ch; text-align: right; }
/* The night and hour charts, drawn for the window and for a phone. */
.ecs-land-res__plot.is-narrow { display: none; }
/* A numeric column's head is a label like the others (the cell rule's
   !important would set it at the cells' size). */
.ecs-land-res .ecs-table thead th.ecs-td-num { font: var(--ecs-th-font) !important; text-transform: uppercase; }

/* Sites: the ranked bars, each site with its tier and one line of what it
   heard (plain, not the Latin names' italic). */
.ecs-land-res__sites .ecs-pill { margin-left: 10px; vertical-align: 1px; }
.ecs-land-res__sites .ecs-rank__label em { font-style: normal; }
/* A site's line is a sentence, not a name: at the tour window's width the
   names take half the row, and a line wraps rather than cut off its taxon. */
.ecs-land-res__sites .ecs-rank__row { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) auto; }
.ecs-land-res__sites .ecs-rank__label em { white-space: normal; }

/* Files: the zip and what is inside it, drawn as the tree it is. */
.ecs-bundle { margin: 0; }
.ecs-bundle code { font-family: var(--ecs-font-mono); }
.ecs-bundle__zip {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 0;
  padding: 0 0 8px;
  color: var(--ecs-forest-500);
}
.ecs-bundle__ziptitle { font: var(--ecs-fw-medium) var(--ecs-fs-sm) / 1.3 var(--ecs-font-body); color: var(--ecs-ink); }
/* One guide down the left of the zip's contents, one tick into each file. */
.ecs-bundle__list,
.ecs-bundle__extras {
  list-style: none;
  margin: 0 0 0 7px;
  padding: 0;
  border-left: 1px solid var(--ecs-line-mint);
}
.ecs-bundle__row,
.ecs-bundle__extra {
  position: relative;
  display: grid;
  /* As wide as the longest name (provenance.json), so the words beside
     them wrap as little as the window allows. */
  grid-template-columns: 144px minmax(0, 1fr);
  column-gap: 20px;
  padding-left: 22px;
}
.ecs-bundle__row::before,
.ecs-bundle__extra::before {
  content: "";
  position: absolute;
  left: 0;
  width: 12px;
  border-top: 1px solid var(--ecs-line-mint);
}
.ecs-bundle__row { padding-top: 8px; padding-bottom: 8px; border-top: 1px solid var(--ecs-line-3); }
.ecs-bundle__row::before { top: 18px; }
.ecs-bundle__extras { border-top: 1px solid var(--ecs-line-3); padding: 6px 0 0; }
.ecs-bundle__extra { padding-top: 3px; padding-bottom: 3px; }
.ecs-bundle__extra::before { top: 12px; }
.ecs-bundle__file {
  font-size: var(--ecs-fs-xs);
  font-weight: var(--ecs-fw-medium);
  line-height: 1.5;
  color: var(--ecs-ink);
  overflow-wrap: anywhere;
}
.ecs-bundle__row .ecs-bundle__file { padding-top: 2px; }
.ecs-bundle__extra .ecs-bundle__file { font-weight: var(--ecs-fw-regular); color: var(--ecs-text); }
.ecs-bundle__title {
  margin: 0 0 2px;
  font: var(--ecs-fw-bold) var(--ecs-fs-md) / 1.3 var(--ecs-font-display);
  color: var(--ecs-ink);
}
.ecs-bundle__body {
  margin: 0;
  font: var(--ecs-fw-regular) var(--ecs-fs-sm) / 1.4 var(--ecs-font-body);
  color: var(--ecs-text);
}
.ecs-bundle__detail {
  font: var(--ecs-fw-regular) var(--ecs-fs-xs) / 1.5 var(--ecs-font-body);
  color: var(--ecs-text-muted);
}

/* provenance.json, the status bar: who reviewed it, then the run's facts,
   on the same paper as the bar over the file. */
.ecs-land-res__prov {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 10px 32px;
  padding: 10px 20px;
  border-top: 1px solid var(--ecs-line);
  background: var(--ecs-paper);
}
.ecs-land-res__provtitle {
  display: flex;
  align-items: center;
  gap: 9px;
  margin: 0;
  font: var(--ecs-fw-bold) var(--ecs-fs-sm) / 1.3 var(--ecs-font-display);
  color: var(--ecs-ink);
}
.ecs-land-res__provtitle svg { flex: none; align-self: center; color: var(--ecs-forest-500); }
.ecs-land-res__provfile {
  margin-left: 6px;
  font: var(--ecs-fw-medium) var(--ecs-fs-3xs) / 1.3 var(--ecs-font-mono);
  letter-spacing: var(--ecs-tracking-wide);
  text-transform: uppercase;
  color: var(--ecs-text-muted);
}
.ecs-land-res__facts { display: flex; flex-wrap: wrap; gap: 6px 26px; margin: 0; }
.ecs-land-res__facts > div { display: flex; align-items: baseline; gap: 8px; }
.ecs-land-res__facts dt { font: var(--ecs-fw-regular) var(--ecs-fs-2xs) / 1.4 var(--ecs-font-body); color: var(--ecs-text-muted); }
.ecs-land-res__facts dd {
  margin: 0;
  font: var(--ecs-fw-medium) var(--ecs-fs-2xs) / 1.4 var(--ecs-font-mono);
  font-variant-numeric: tabular-nums;
  color: var(--ecs-ink);
}

/* The window's one authored moment, each time a tab opens: its bars grow
   from their baseline and its table rows fade in turn. landingResults.js
   marks the window is-live (never under reduced motion), and is-seen once it
   is mostly on screen, so the first tab plays where somebody can see it.
   With no script, or reduced motion, every figure is simply there. */
.ecs-land-res .ecs-rank__bar { transform-origin: left center; }
.ecs-land-res .ecs-chart-bar { transform-box: fill-box; transform-origin: 50% 100%; }
.ecs-land-res.is-live:not(.is-seen) .ecs-rank__bar { transform: scaleX(0); }
.ecs-land-res.is-live:not(.is-seen) .ecs-chart-bar { transform: scaleY(0); }
.ecs-land-res.is-seen .ecs-land-res__pane.is-active .ecs-rank__bar {
  animation: ecs-land-grow-x 0.7s var(--ecs-ease-out) both;
  animation-delay: calc(100ms + var(--k, 0) * 55ms);
}
.ecs-land-res.is-seen .ecs-land-res__pane.is-active .ecs-chart-bar {
  animation: ecs-land-grow-y 0.65s var(--ecs-ease-out) both;
  animation-delay: 100ms;
}
/* Opacity only. ecs-land-rise also translates the row, and a transform on
   tbody tr makes the table size to its content until the animation ends,
   then snap back to the pane. */
.ecs-land-res.is-seen .ecs-land-res__pane.is-active tbody tr {
  animation: ecs-land-row 0.45s var(--ecs-ease-out) both;
  animation-delay: calc(60ms + var(--k, 0) * 45ms);
}
.ecs-land-res :is(.ecs-rank__row, tbody tr):nth-child(2) { --k: 1; }
.ecs-land-res :is(.ecs-rank__row, tbody tr):nth-child(3) { --k: 2; }
.ecs-land-res :is(.ecs-rank__row, tbody tr):nth-child(4) { --k: 3; }
.ecs-land-res :is(.ecs-rank__row, tbody tr):nth-child(5) { --k: 4; }
.ecs-land-res :is(.ecs-rank__row, tbody tr):nth-child(6) { --k: 5; }
.ecs-land-res :is(.ecs-rank__row, tbody tr):nth-child(7) { --k: 6; }
.ecs-land-res :is(.ecs-rank__row, tbody tr):nth-child(8) { --k: 7; }
@keyframes ecs-land-grow-x { from { transform: scaleX(0); } to { transform: none; } }
@keyframes ecs-land-grow-y { from { transform: scaleY(0); } to { transform: none; } }
@keyframes ecs-land-row { from { opacity: 0.25; } to { opacity: 1; } }
@media (prefers-reduced-motion: reduce) {
  .ecs-land-res__pane,
  .ecs-land-res__pane.is-active,
  .ecs-land-res__tab { transition: none; }
  .ecs-land-res .ecs-rank__bar,
  .ecs-land-res .ecs-chart-bar,
  .ecs-land-res tbody tr { animation: none !important; transform: none !important; }
}

/* ---- 4 · How we price (white) ------------------------------------------- */
/* The zigzag's third turn: the words on the left at the tour's 4 of 12, the
   two ways to pay on the right at its 8, the same 64px gap. The words run the
   sheet's height, so the button under the sum lands level with the sheet's
   foot.
   Narrow, it is one column: the words, then the sheet. */
.ecs-land-price {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  row-gap: 48px;
}
.ecs-land-price__words { display: flex; flex-direction: column; min-width: 0; }
.ecs-land-price .ecs-land-title { margin-bottom: 20px; }
.ecs-land-price__lede {
  margin: 0;
  max-width: 32ch;
  font: var(--ecs-fw-regular) var(--ecs-fs-lg) / 1.55 var(--ecs-font-body);
  color: var(--ecs-text-2);
  text-wrap: balance;
}
/* What the section is here to say, on a line of its own in ink. */
.ecs-land-price__free { display: block; font-weight: var(--ecs-fw-medium); color: var(--ecs-ink); }
/* The sum, and under its total the way to the rates: the tour's own button,
   so the band adds a quote up first and then says where the figures are. */
.ecs-land-price__quote { display: flex; flex-direction: column; margin-top: 36px; }
.ecs-land-price__go { align-self: flex-start; margin-top: 32px; }

/* The quote as a sum, set the way a ledger sets one: the operators in a
   column of their own, a term to a line with what it means under it, and the
   total under a rule of ink. */
.ecs-land-sum { margin: 0; }
.ecs-land-sum__row {
  position: relative;
  padding: 13px 0 13px 34px;
  border-top: 1px solid var(--ecs-line);
}
.ecs-land-sum__row:first-child { border-top: 0; padding-top: 0; }
.ecs-land-sum__op {
  position: absolute;
  left: 0;
  top: 11px;
  width: 20px;
  text-align: center;
  font: var(--ecs-fw-medium) var(--ecs-fs-title) / 1 var(--ecs-font-mono);
  color: var(--ecs-text-muted);
}
.ecs-land-sum__row:first-child .ecs-land-sum__op { top: -2px; }
.ecs-land-sum dt {
  font: var(--ecs-fw-medium) var(--ecs-fs-md) / 1.4 var(--ecs-font-body);
  color: var(--ecs-ink);
}
.ecs-land-sum dd {
  margin: 2px 0 0;
  font: var(--ecs-fw-regular) var(--ecs-fs-sm) / 1.5 var(--ecs-font-body);
  color: var(--ecs-text-muted);
  text-wrap: pretty;
}
.ecs-land-sum__row.is-total { border-top: 2px solid var(--ecs-ink); padding-bottom: 0; }
.ecs-land-sum__row.is-total dt { font-weight: var(--ecs-fw-bold); }
.ecs-land-sum__row.is-total .ecs-land-sum__op { color: var(--ecs-ink); }

/* Two ways to pay, one sheet: square, on the windows' 22% ink hairline. Its
   rows are shared across both columns (subgrid), so a longer price on one
   side keeps payment level with payment and the two buttons on one line.
   Beside the words it is as tall as they are, and the buttons' row takes
   the difference, so they sit at its foot. What the two share runs under
   both, on the paper the results window's status bar uses. */
.ecs-land-ways {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  grid-template-rows: auto auto auto 1fr auto;
  background: var(--ecs-surface);
  border: 1px solid rgba(var(--ecs-ink-rgb), 0.22);
}
.ecs-land-way {
  display: grid;
  grid-row: span 4;
  grid-template-rows: subgrid;
  row-gap: 0;
  min-width: 0;
  padding: 32px;
}
.ecs-land-way + .ecs-land-way { border-left: 1px solid rgba(var(--ecs-ink-rgb), 0.22); }
.ecs-land-way__name {
  margin: 0 0 20px;
  font: var(--ecs-fw-bold) var(--ecs-fs-title) / 1.25 var(--ecs-font-display);
  letter-spacing: -0.01em;
  color: var(--ecs-ink);
}
.ecs-land-way__fact {
  margin: 0;
  padding: 16px 0;
  border-top: 1px solid var(--ecs-line);
  font: var(--ecs-fw-regular) var(--ecs-fs-md) / 1.5 var(--ecs-font-body);
  color: var(--ecs-ink);
  text-wrap: pretty;
}
.ecs-land-way__label {
  display: block;
  margin-bottom: 6px;
  font: var(--ecs-fw-medium) var(--ecs-fs-3xs) / 1.2 var(--ecs-font-mono);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ecs-text-muted);
}
.ecs-land-way__go {
  display: flex;
  align-items: flex-end;
  padding-top: 20px;
  border-top: 1px solid var(--ecs-line);
}
.ecs-land-way__cta { padding: 12px 20px; white-space: nowrap; }
/* One height for both, so the two buttons share a line: the ghost's hairline,
   matched on the fill in the fill's own colour. */
.ecs-land-way__cta.ecs-btn--primary { border: 1px solid var(--ecs-forest-500); }
.ecs-land-way__cta.ecs-btn--primary:hover { border-color: var(--ecs-forest-600); }
.ecs-land-way__cta svg { flex: none; }
.ecs-land-way__cta.ecs-btn--ghost svg { color: var(--ecs-forest-500); }
.ecs-land-ways__both {
  grid-column: 1 / -1;
  display: flex;
  align-items: flex-start;
  gap: 10px;
  margin: 0;
  padding: 14px 32px;
  border-top: 1px solid var(--ecs-line);
  background: var(--ecs-paper);
  font: var(--ecs-fw-regular) var(--ecs-fs-sm) / 1.5 var(--ecs-font-body);
  color: var(--ecs-text);
  text-wrap: balance;
}
.ecs-land-ways__both svg { flex: none; margin-top: 1px; color: var(--ecs-forest-500); }

@media (min-width: 861px) {
  .ecs-land-price {
    grid-template-columns: minmax(0, 4fr) minmax(0, 8fr);
    column-gap: 64px;
  }
  /* The tour heading's own size, so the three read as a set. */
  .ecs-land-price .ecs-land-title {
    font-size: clamp(40px, 3.6vw, 52px);
    line-height: 1;
    margin-bottom: 24px;
  }
  .ecs-land-price__quote { margin-top: auto; padding-top: 40px; }
}
/* Too narrow for the sheet beside the words (a way's column would be under
   its button): the words go on top, heading and lede beside the sum, and the
   sheet takes the column's whole width under them. */
@media (max-width: 1180px) {
  .ecs-land-price { grid-template-columns: minmax(0, 1fr); row-gap: 48px; }
  .ecs-land-price__words {
    display: grid;
    grid-template-columns: minmax(0, 5fr) minmax(0, 6fr);
    grid-template-rows: auto auto 1fr;
    column-gap: 64px;
  }
  /* The sum keeps its button under it, beside the heading and lede. */
  .ecs-land-price__quote { grid-column: 2; grid-row: 1 / -1; margin: 0; padding-top: 0; }
}
@media (max-width: 760px) {
  .ecs-land-price__words { display: flex; }
  .ecs-land-price__quote { margin-top: 36px; }
  .ecs-land-ways { grid-template-columns: minmax(0, 1fr); grid-template-rows: none; }
  .ecs-land-way { display: block; grid-row: auto; }
  .ecs-land-way + .ecs-land-way { border-left: 0; border-top: 1px solid rgba(var(--ecs-ink-rgb), 0.22); }
}

/* =============================================================================
   PRICING PAGE (/pricing) — the rate, on the recordings it is charged for;
   one batch added up; how a quote is made; the two ways to pay. The
   landing's bands in the landing's order (white, Mint, Meadow, white, then
   the grey footer), and its window grammar: white, square, a 22% ink
   hairline and a Lab Paper bar. Every price and count is Plex Mono.
   ============================================================================= */
.ecs-rate .ecs-land-title { margin-bottom: 40px; }
@media (min-width: 861px) {
  /* The tour heading's own size, so the site's section titles read as a set. */
  .ecs-rate .ecs-land-title { font-size: clamp(40px, 3.6vw, 52px); line-height: 1; }
}

/* A figure while the rates load: a block of paper about its width, so the
   line hardly moves when the number lands. Then the number comes up in its
   place. Neither is announced: the region is aria-busy until it is filled. */
.ecs-rate-sk {
  display: inline-block;
  width: calc(var(--ch, 4) * 0.6em);
  height: 0.74em;
  vertical-align: -0.04em;
  background: var(--ecs-surface-3);
  animation: ecs-rate-wait 1.1s var(--ecs-ease) infinite alternate;
}
.ecs-rate-fig { animation: ecs-rate-in 0.32s var(--ecs-ease-out) both; }
@keyframes ecs-rate-wait { from { opacity: 1; } to { opacity: 0.45; } }
@keyframes ecs-rate-in { from { opacity: 0; } to { opacity: 1; } }

/* ---- 1 · The rate (white) --------------------------------------------------
   The words on the left at 5 of 12, the two recordings on the right at 7,
   the landing's 64px gap. The headline is the rate in two lines, the second
   quieter because it is the smaller price. */
.ecs-land-sec.ecs-rate-top { background: var(--ecs-surface); padding-top: 72px; padding-bottom: 96px; }
.ecs-rate-top__grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  row-gap: 48px;
  align-items: center;
}
/* Each rate is one line, sized to its column (a container query, not the
   window, so a wider screen never breaks "bat recording" in two). The second
   is the smaller price, so it is set smaller and quieter. */
.ecs-rate-top__words { container-type: inline-size; min-width: 0; }
.ecs-rate-title {
  margin: 0 0 24px;
  font: var(--ecs-fw-bold) var(--ecs-fs-landing) / 1.02 var(--ecs-font-display);
  font-size: clamp(34px, 8.6cqi, 64px);
  letter-spacing: -0.025em;
  color: var(--ecs-ink);
  text-wrap: balance;
}
.ecs-rate-title__line { display: block; }
.ecs-rate-title__line + .ecs-rate-title__line { margin-top: 0.14em; font-size: 0.72em; color: var(--ecs-text-muted); }
.ecs-rate-title__unit { white-space: nowrap; }
/* Below 1000px the words take the whole column, so the column is no longer
   the headline's measure: held to the size it has beside the recordings on
   a desktop, so it never grows as the window shrinks. */
@media (max-width: 999px) {
  .ecs-rate-title { font-size: clamp(34px, 8.6cqi, 37px); }
}
.ecs-rate-title .ecs-rate-sk { background: var(--ecs-surface-3); }
.ecs-rate-lede {
  margin: 0 0 36px;
  max-width: 40ch;
  font: var(--ecs-fw-regular) var(--ecs-fs-lg) / 1.55 var(--ecs-font-body);
  color: var(--ecs-text-2);
  text-wrap: pretty;
}
.ecs-rate-ctas { display: inline-flex; flex-direction: column; gap: 12px; }
/* The primary's words are long ("Register and upload for a free quote"), so
   the two do not fit side by side in the half column; they stack at one
   width, the primary's, rather than wrap to two ragged lengths. */
.ecs-rate-ctas .ecs-btn { justify-content: center; }
/* One height for both: the primary carries a hairline in its own fill. */
.ecs-rate-ctas .ecs-btn--primary { border: 1px solid var(--ecs-forest-500); }
.ecs-rate-ctas .ecs-btn--primary:hover { border-color: var(--ecs-forest-600); }
.ecs-rate-ctas .ecs-btn--ghost svg { color: var(--ecs-forest-500); }

/* The two recordings, on one frequency scale, one over the other: the
   headline's two lines, as sound. Each is a window with its price in the
   caption, level with its name. */
.ecs-rate-recs { display: grid; gap: 16px; min-width: 0; }
.ecs-rate-rec {
  margin: 0;
  background: var(--ecs-surface);
  border: 1px solid rgba(var(--ecs-ink-rgb), 0.22);
}
.ecs-rate-rec .ecs-land-rec__plot { aspect-ratio: 1280 / 500; }
.ecs-rate-rec .ecs-land-rec__plot img { height: 100%; object-fit: cover; }
.ecs-rate-rec__cap {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 12px 18px 13px;
}
.ecs-rate-rec__what {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 4px 10px;
  min-width: 0;
}
.ecs-rate-rec__what .ecs-land-rec__code { align-self: center; }
.ecs-rate-rec__name { font: var(--ecs-fw-medium) var(--ecs-fs-md) / 1.3 var(--ecs-font-body); color: var(--ecs-ink); }
.ecs-rate-rec__detail { font: var(--ecs-fw-regular) var(--ecs-fs-sm) / 1.4 var(--ecs-font-body); color: var(--ecs-text-muted); }
.ecs-rate-rec__price {
  flex: none;
  font: var(--ecs-fw-medium) var(--ecs-fs-title) / 1 var(--ecs-font-mono);
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.02em;
  color: var(--ecs-ink);
}
.ecs-rate-recs__src {
  margin: 0;
  font: var(--ecs-fw-regular) var(--ecs-fs-xs) / 1.5 var(--ecs-font-body);
  color: var(--ecs-text-muted);
}
/* The frequency labels sit on a plate of the image's own floor, so "20"
   reads over the insect pulses it shares a band with. */
.ecs-rate-rec .ecs-land-rec__khz span {
  bottom: 2px;
  padding: 2px 4px 1px;
  background: rgba(23, 36, 25, 0.82);
  color: var(--ecs-on-dark-2);
}
/* The 50 ms bar goes to the right-hand corner: this scale runs down to
   8 kHz, so its 20 kHz line sits where the bar sits on the hero's. */
.ecs-rate-rec .ecs-land-rec__scale { left: auto; right: 12px; }
/* The bat's calls are found one by one, the way the detector works along
   the file, once, as the page opens. */
.ecs-rate-rec .ecs-land-rec__call {
  animation: ecs-land-find 0.45s var(--ecs-ease-out) calc(280ms + var(--i, 0) * 140ms) both;
}

/* Under the words but with room for two: the recordings side by side. */
@media (min-width: 640px) and (max-width: 999px) {
  .ecs-rate-recs { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .ecs-rate-recs__src { grid-column: 1 / -1; }
  .ecs-rate-rec { display: flex; flex-direction: column; }
  .ecs-rate-rec__cap { flex: 1; align-items: flex-end; }
}


@media (min-width: 1000px) {
  .ecs-rate-top__grid { grid-template-columns: minmax(0, 6fr) minmax(0, 6fr); column-gap: 64px; }
}

/* ---- 2 · A batch, added up (Mint) ------------------------------------------
   The zigzag's turn: the ledger's window on the left at 7 of 12, the words
   on the right. The ledger is the landing band's sum with its figures in:
   operators in their own column, one term to a line with what it means
   under it, the money right-aligned in mono, a rule of ink over the review
   and a heavier one over the quote. */
.ecs-rate-eg { background: var(--ecs-green-200); }
.ecs-rate-eg__grid { display: grid; grid-template-columns: minmax(0, 1fr); row-gap: 40px; }
.ecs-rate-eg__lede {
  margin: 0;
  max-width: 36ch;
  font: var(--ecs-fw-regular) var(--ecs-fs-lg) / 1.55 var(--ecs-font-body);
  color: var(--ecs-text-mint);
  text-wrap: pretty;
}
.ecs-rate-eg__window {
  margin: 0;
  min-width: 0;
  background: var(--ecs-surface);
  border: 1px solid rgba(var(--ecs-ink-rgb), 0.22);
}
.ecs-ledger { margin: 0; padding: 10px 28px 26px; }
.ecs-ledger__row {
  display: grid;
  grid-template-columns: 28px minmax(0, 1fr) auto minmax(7ch, auto);
  column-gap: 16px;
  align-items: first baseline;
  padding: 15px 0;
  border-top: 1px solid var(--ecs-line);
}
.ecs-ledger__row:first-child { border-top: 0; }
.ecs-ledger dt {
  grid-column: 1 / 4;
  display: grid;
  grid-template-columns: subgrid;
  align-items: first baseline;
}
.ecs-ledger__op {
  grid-column: 1;
  text-align: center;
  font: var(--ecs-fw-medium) var(--ecs-fs-title) / 1 var(--ecs-font-mono);
  color: var(--ecs-text-muted);
}
.ecs-ledger__term {
  grid-column: 2;
  font: var(--ecs-fw-medium) var(--ecs-fs-md) / 1.4 var(--ecs-font-body);
  color: var(--ecs-ink);
}
.ecs-ledger__n {
  display: inline-block;
  min-width: 6ch;
  margin-right: 2px;
  font: var(--ecs-fw-medium) var(--ecs-fs-md) / 1.4 var(--ecs-font-mono);
  font-variant-numeric: tabular-nums;
  text-align: right;
}
.ecs-ledger__rate {
  grid-column: 3;
  font: var(--ecs-fw-medium) var(--ecs-fs-sm) / 1.4 var(--ecs-font-mono);
  font-variant-numeric: tabular-nums;
  color: var(--ecs-text-muted);
  text-align: right;
  white-space: nowrap;
}
.ecs-ledger__note {
  grid-column: 2 / 4;
  margin-top: 2px;
  font: var(--ecs-fw-regular) var(--ecs-fs-sm) / 1.5 var(--ecs-font-body);
  color: var(--ecs-text-muted);
  text-wrap: pretty;
}
.ecs-ledger__amt {
  grid-column: 4;
  margin: 0;
  text-align: right;
  font: var(--ecs-fw-medium) var(--ecs-fs-lg) / 1.3 var(--ecs-font-mono);
  font-variant-numeric: tabular-nums;
  color: var(--ecs-ink);
  white-space: nowrap;
}
.ecs-ledger__row.is-sub { border-top: 1px solid var(--ecs-ink); }
.ecs-ledger__row.is-total { border-top: 2px solid var(--ecs-ink); padding-bottom: 0; }
.ecs-ledger__row.is-total .ecs-ledger__term { font-weight: var(--ecs-fw-bold); }
.ecs-ledger__row:is(.is-sub, .is-total) .ecs-ledger__op { color: var(--ecs-ink); }
.ecs-ledger__row.is-total .ecs-ledger__amt { font-size: var(--ecs-fs-h4); letter-spacing: -0.02em; }
/* The lines come in top to bottom once the window is on screen
   (js/pricingPage.js), the way a quote is read. */
.ecs-ledger__row:nth-child(2) { --k: 1; }
.ecs-ledger__row:nth-child(3) { --k: 2; }
.ecs-ledger__row:nth-child(4) { --k: 3; }
.ecs-ledger__row:nth-child(5) { --k: 4; }
.ecs-ledger__row:nth-child(6) { --k: 5; }
.ecs-rate-eg__window.is-live:not(.is-seen) .ecs-ledger__row { opacity: 0; }
.ecs-rate-eg__window.is-seen .ecs-ledger__row {
  animation: ecs-rate-line 0.5s var(--ecs-ease-out) calc(var(--k, 0) * 110ms) both;
}
@keyframes ecs-rate-line {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: none; }
}

@media (min-width: 1000px) {
  .ecs-rate-eg__grid { grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); column-gap: 64px; align-items: center; }
  .ecs-rate-eg__window { grid-column: 1; grid-row: 1; }
  .ecs-rate-eg__words { grid-column: 2; grid-row: 1; }
}

/* ---- 3 · How your quote is made (Meadow) -----------------------------------
   The tour's route, laid flat: the four steps as stations on one line, in
   the order a batch meets them. On the Meadow band the stations are white
   discs on an ink hairline, with ink icons. */
.ecs-rate-how { background: var(--ecs-green-400); }
.ecs-rate-how .ecs-land-title { margin-bottom: 48px; }
.ecs-rate-steps {
  position: relative;
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  column-gap: 32px;
  margin: 0;
  padding: 0;
  list-style: none;
}
.ecs-rate-steps::before {
  content: '';
  position: absolute;
  top: 23px;
  left: 24px;
  right: calc((100% - 96px) / 4 - 24px);
  border-top: 1.5px solid rgba(var(--ecs-ink-rgb), 0.3);
}
.ecs-rate-step { position: relative; min-width: 0; }
.ecs-rate-step__stop {
  display: grid;
  place-items: center;
  width: 48px;
  height: 48px;
  margin-bottom: 20px;
  border: 1.5px solid rgba(var(--ecs-ink-rgb), 0.3);
  border-radius: 999px;
  background: var(--ecs-surface);
  color: var(--ecs-ink);
}
.ecs-rate-step__title {
  margin: 0 0 10px;
  font: var(--ecs-fw-bold) var(--ecs-fs-title) / 1.2 var(--ecs-font-display);
  letter-spacing: -0.015em;
  color: var(--ecs-ink);
}
.ecs-rate-step__body {
  margin: 0;
  max-width: 30ch;
  font: var(--ecs-fw-regular) var(--ecs-fs-md) / 1.55 var(--ecs-font-body);
  color: var(--ecs-text-meadow);
  text-wrap: pretty;
}
.ecs-rate-step__body .ecs-rate-fig { font-weight: var(--ecs-fw-medium); color: var(--ecs-ink); }
.ecs-rate-step__body .ecs-rate-sk { background: rgba(255, 255, 255, 0.45); }

/* ---- 4 · Two ways to pay (white) ------------------------------------------
   The landing's sheet, whole width. The shared line leads to the policy. */
.ecs-rate-ways { background: var(--ecs-surface); }
.ecs-rate-ways .ecs-land-ways__both .ecs-authlink { white-space: nowrap; }

@media (max-width: 860px) {
  .ecs-land-sec.ecs-rate-top { padding-top: 48px; padding-bottom: 72px; }
  .ecs-rate-steps { grid-template-columns: minmax(0, 1fr); row-gap: 28px; }
  /* The route runs down the stations' side instead of across. */
  .ecs-rate-steps::before { top: 24px; bottom: 24px; left: 23px; right: auto; border-top: 0; border-left: 1.5px solid rgba(var(--ecs-ink-rgb), 0.3); }
  .ecs-rate-step { display: grid; grid-template-columns: 48px minmax(0, 1fr); column-gap: 20px; }
  .ecs-rate-step__stop { grid-row: 1 / span 2; margin-bottom: 0; }
  .ecs-rate-step__title { padding-top: 11px; }
  .ecs-rate-step__body { max-width: 44ch; }
}
@media (max-width: 560px) {
  .ecs-land-sec.ecs-rate-top { padding-top: 32px; padding-bottom: 56px; }
  .ecs-rate-title { font-size: 36px; }
  .ecs-rate-lede { font-size: var(--ecs-fs-md); margin-bottom: 28px; }
  .ecs-rate-ctas { display: flex; }
  .ecs-rate-rec__cap { padding: 10px 14px 11px; }
  .ecs-rate-rec__price { font-size: var(--ecs-fs-lg); }
  /* The ledger takes the column's whole width: the rate drops under the
     term, and the money keeps its own column. */
  .ecs-ledger { padding: 4px 16px 20px; }
  .ecs-ledger__row { grid-template-columns: 20px minmax(0, 1fr) auto; column-gap: 12px; }
  .ecs-ledger dt { grid-column: 1 / 3; }
  .ecs-ledger__rate { grid-column: 2; grid-row: 2; text-align: left; margin-top: 2px; }
  .ecs-ledger__note { grid-column: 2; }
  .ecs-ledger__amt { grid-column: 3; font-size: var(--ecs-fs-md); }
  .ecs-ledger__row.is-total .ecs-ledger__amt { font-size: var(--ecs-fs-title); }
  .ecs-ledger__op { font-size: var(--ecs-fs-lg); }
  .ecs-ledger__n { min-width: 0; }
  .ecs-rate-step__title { font-size: var(--ecs-fs-lg); }
}

@media (prefers-reduced-motion: reduce) {
  .ecs-rate-sk,
  .ecs-rate-fig,
  .ecs-rate-rec .ecs-land-rec__call,
  .ecs-rate-eg__window.is-seen .ecs-ledger__row { animation: none; }
  .ecs-rate-eg__window.is-live:not(.is-seen) .ecs-ledger__row { opacity: 1; }
}

/* ---- 5 · The promise (the ink the page opened on) ------------------------ */
.ecs-land-promise { background: var(--ecs-forest-900); color: var(--ecs-on-dark); }
.ecs-land-promise__grid {
  display: grid;
  grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
  column-gap: 64px;
  align-items: end;
}
.ecs-land-promise__statement {
  font: var(--ecs-fw-regular) var(--ecs-fs-h2) / 1.3 var(--ecs-font-display);
  letter-spacing: var(--ecs-tracking-tight);
  max-width: 32ch;
  margin: 0;
  text-wrap: balance;
}
.ecs-land-promise__why {
  font: var(--ecs-fw-regular) var(--ecs-fs-md) / 1.6 var(--ecs-font-body);
  color: var(--ecs-on-dark-2);
  max-width: 44ch;
  margin: 0 0 28px;
}
/* Landing controls take the global ring (base.css). On the ink panel the mint
   halo would be a light slab on the one dark surface, so there the ring is
   the panel green on its own. */
.ecs-land-promise .ecs-btn:focus-visible { outline-color: var(--ecs-focus-on-dark); box-shadow: none; }

@media (prefers-reduced-motion: reduce) {
  .ecs-matrix.is-demo .ecs-matrix__cell,
  .ecs-land-hero__photo img { animation: none; }
}

/* ---- Book a call (the enterprise front door, P4) ------------------------ */
/* Two bands in the site's order. White: the title, why to book and the one
   action on the left; beside it, on the pricing page's route stood upright,
   what the action sets off, so the scheduler's guest screen is no surprise.
   Mint: what the call will want to know. The route is in ink, so the button
   stays the page's one green moment. */
.ecs-book-page .ecs-land-title { margin-bottom: 40px; }
@media (min-width: 861px) {
  .ecs-book-page .ecs-land-title { font-size: clamp(40px, 3.6vw, 52px); line-height: 1; }
}
.ecs-land-sec.ecs-book { flex: 1 0 auto; background: var(--ecs-surface); padding-top: 72px; padding-bottom: 96px; }
.ecs-book__grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  row-gap: 48px;
  align-items: start;
}
.ecs-book__words { min-width: 0; }
.ecs-book__title {
  margin: 0 0 24px;
  font: var(--ecs-fw-bold) clamp(36px, 3.9vw, 56px) / 1.04 var(--ecs-font-display);
  letter-spacing: -0.025em;
  color: var(--ecs-ink);
  text-wrap: balance;
}
.ecs-book__lede {
  margin: 0 0 36px;
  max-width: 36ch;
  font: var(--ecs-fw-regular) var(--ecs-fs-lg) / 1.55 var(--ecs-font-body);
  color: var(--ecs-text-2);
  text-wrap: pretty;
}
.ecs-book__cta svg { flex: none; }
.ecs-book__alt {
  margin: 20px 0 0;
  font: var(--ecs-fw-regular) var(--ecs-fs-sm) / 1.5 var(--ecs-font-body);
  color: var(--ecs-text-muted);
}
/* With the scheduler in the page, it is the action: the words only say
   where the call happens. */
.ecs-book__note {
  margin: 0;
  max-width: 40ch;
  font: var(--ecs-fw-regular) var(--ecs-fs-md) / 1.55 var(--ecs-font-body);
  color: var(--ecs-text);
}

/* The route, upright: a station per step on an ink hairline that runs centre
   to centre, the title level with the station's middle. */
.ecs-book__steps {
  --gap: 32px;
  display: grid;
  row-gap: var(--gap);
  margin: 0;
  padding: 0;
  list-style: none;
}
/* Each leg runs from a station to the next, so the line ends on the last
   station however long that step's words run. */
.ecs-book__step:not(:last-child)::before {
  content: '';
  position: absolute;
  top: 48px;
  bottom: calc(-1 * var(--gap));
  left: 23.25px;
  border-left: 1.5px solid rgba(var(--ecs-ink-rgb), 0.22);
}
.ecs-book__step {
  position: relative;
  display: grid;
  grid-template-columns: 48px minmax(0, 1fr);
  column-gap: 20px;
  min-width: 0;
}
.ecs-book__stop {
  grid-row: 1 / span 2;
  display: grid;
  place-items: center;
  width: 48px;
  height: 48px;
  border: 1.5px solid rgba(var(--ecs-ink-rgb), 0.3);
  border-radius: 999px;
  background: var(--ecs-surface);
  color: var(--ecs-ink);
}
.ecs-book__steptitle {
  margin: 0 0 6px;
  padding-top: 11px;
  font: var(--ecs-fw-bold) var(--ecs-fs-title) / 1.2 var(--ecs-font-display);
  letter-spacing: -0.015em;
  color: var(--ecs-ink);
}
.ecs-book__stepbody {
  margin: 0;
  max-width: 40ch;
  font: var(--ecs-fw-regular) var(--ecs-fs-md) / 1.55 var(--ecs-font-body);
  color: var(--ecs-text-2);
  text-wrap: pretty;
}

/* A scheduler that may be framed takes the route's place. The Bookings page
   paints its own floor (#F4F4F4) around a 420px white column, and nothing on
   our side can restyle it, so the band steps to Lab Paper to meet it: the
   floor disappears into the band and the column reads as a white card on our
   page. The frame is that column's width and its whole form's height (about
   2010px, at every width from 343 to 460), so the page scrolls, never the
   frame; any spare height is more of the same floor. Its loading card sits
   under it in the same grid cell, where the column will paint, and is covered
   the moment it does. The column starts 25px down its page, so the frame
   rises by as much to bring the card's top level with the title's. */
.ecs-land-sec.ecs-book.is-embed { background: var(--ecs-paper); }
.ecs-book__cal {
  --book-frame-h: 2040px;
  display: grid;
  width: 100%;
  max-width: 420px;
  min-width: 0;
  margin-top: -25px;
}
.ecs-book__cal > * { grid-area: 1 / 1; }
.ecs-book__loading {
  margin: 25px 0 0;
  padding-top: 160px;
  background: var(--ecs-surface);
  text-align: center;
  font: var(--ecs-fw-medium) var(--ecs-fs-2xs) / 1.4 var(--ecs-font-mono);
  letter-spacing: 0.04em;
  color: var(--ecs-text-muted);
}
.ecs-book__iframe {
  display: block;
  width: 100%;
  height: var(--book-frame-h);
  border: 0;
  background: transparent;
}
.ecs-book__newtab { display: inline-flex; align-items: center; gap: 5px; }

@media (min-width: 1000px) {
  .ecs-book__grid { grid-template-columns: minmax(0, 6fr) minmax(0, 6fr); column-gap: 64px; }
  .ecs-book.is-embed .ecs-book__grid { grid-template-columns: minmax(0, 1fr) 420px; }
  /* The words hold still while the calendar reads down beside them, as the
     review policy's intro does. */
  .ecs-book.is-embed .ecs-book__words { position: sticky; top: 32px; }
}

/* What to have to hand (Mint): the sheet's facts, a mono label over the
   words on a hairline, one to a column. */
.ecs-book-prep { background: var(--ecs-green-200); }
.ecs-book-prep__facts {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  column-gap: 32px;
  margin: 0;
}
.ecs-book-prep__fact {
  min-width: 0;
  padding-top: 16px;
  border-top: 1px solid rgba(var(--ecs-ink-rgb), 0.22);
}
.ecs-book-prep__fact dt {
  margin: 0 0 8px;
  font: var(--ecs-fw-medium) var(--ecs-fs-3xs) / 1.2 var(--ecs-font-mono);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ecs-text-mint);
}
.ecs-book-prep__fact dd {
  margin: 0;
  max-width: 28ch;
  font: var(--ecs-fw-regular) var(--ecs-fs-lg) / 1.5 var(--ecs-font-body);
  color: var(--ecs-ink);
  text-wrap: pretty;
}

/* ---- Review policy (/review-policy) ------------------------------------- */
/* The booking page's columns: the intro holds still on the left while the
   policy reads down the right, one hairline-ruled section per question. */
.ecs-policy {
  flex: 1;
  width: 100%;
  max-width: calc(1160px + 128px);
  margin: 0 auto;
  padding: 56px 64px 112px;
  display: grid;
  grid-template-columns: minmax(0, 4fr) minmax(0, 7fr);
  column-gap: 64px;
  align-items: start;
}
.ecs-policy__intro { position: sticky; top: 32px; }
.ecs-policy__title {
  font: var(--ecs-fw-bold) var(--ecs-fs-h1) / 1.1 var(--ecs-font-display);
  letter-spacing: -0.025em;
  color: var(--ecs-ink);
  margin: 8px 0 16px;
  text-wrap: balance;
}
.ecs-policy__sub {
  font: var(--ecs-fw-regular) var(--ecs-fs-md) / 1.6 var(--ecs-font-body);
  color: var(--ecs-text-2);
  max-width: 40ch;
  margin: 0 0 32px;
  text-wrap: pretty;
}
.ecs-policy__ask {
  margin: 20px 0 0;
  font: var(--ecs-fw-regular) var(--ecs-fs-sm) / 1.5 var(--ecs-font-body);
  color: var(--ecs-text-muted);
}
.ecs-policy__secs { border-top: 1px solid var(--ecs-line); }
.ecs-policy__sec {
  display: grid;
  grid-template-columns: minmax(0, 2fr) minmax(0, 3fr);
  column-gap: 40px;
  padding: 28px 0 30px;
  border-bottom: 1px solid var(--ecs-line);
}
.ecs-policy__h {
  margin: 0;
  font: var(--ecs-fw-bold) var(--ecs-fs-title) / 1.25 var(--ecs-font-display);
  letter-spacing: -0.01em;
  color: var(--ecs-ink);
  text-wrap: balance;
}
.ecs-policy__body p {
  margin: 0;
  max-width: 62ch;
  font: var(--ecs-fw-regular) var(--ecs-fs-md) / 1.65 var(--ecs-font-body);
  color: var(--ecs-text);
  text-wrap: pretty;
}
.ecs-policy__body p + p { margin-top: 12px; }

/* ---- Footer -------------------------------------------------------------
   The grey band, in the landing's content column and on its 4 / 4 / 4
   grid, so its edges fall where every section's do. The first column says
   whose service ECOSOUND is and leads to the company's own site, the one
   link here that stays underlined. The other two are the site's pages and
   how to reach us, each under the sheet's mono label. Then a hairline and
   the copyright in the nav's mono, the bar's right end kept for Privacy. */
.ecs-site-foot {
  flex-shrink: 0;
  background: var(--ecs-paper-alt);
  border-top: 1px solid var(--ecs-line-2);
  padding: 64px 64px 32px;
}
.ecs-site-foot__inner {
  max-width: 1160px;
  margin: 0 auto;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  column-gap: 64px;
  row-gap: 56px;
  align-items: start;
}
.ecs-site-foot__brand { display: flex; flex-direction: column; align-items: flex-start; }
.ecs-site-foot__mark { display: inline-flex; color: var(--ecs-ink); }
.ecs-site-foot__about {
  margin: 20px 0 10px;
  max-width: 32ch;
  font: var(--ecs-fw-regular) var(--ecs-fs-base) / 1.5 var(--ecs-font-body);
  color: var(--ecs-text-2);
  text-wrap: balance;
}
.ecs-site-foot__parent {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font: var(--ecs-fw-medium) var(--ecs-fs-md) / 1.4 var(--ecs-font-body);
  color: var(--ecs-green-600);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-decoration-color: rgba(49, 103, 42, 0.4);
  text-underline-offset: 4px;
  transition: text-decoration-color var(--ecs-dur-base) var(--ecs-ease-out);
}
.ecs-site-foot__go { display: inline-flex; transition: transform var(--ecs-dur-base) var(--ecs-ease-out); }
.ecs-site-foot__parent:hover { text-decoration-color: currentColor; }
.ecs-site-foot__parent:hover .ecs-site-foot__go,
.ecs-site-foot__parent:focus-visible .ecs-site-foot__go { transform: translate(2px, -2px); }
.ecs-site-foot__title {
  margin: 0 0 16px;
  font: var(--ecs-fw-medium) var(--ecs-fs-3xs) / 1.2 var(--ecs-font-mono);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ecs-text-muted);
}
.ecs-site-foot__list {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 12px;
  margin: 0;
  padding: 0;
  list-style: none;
  font: var(--ecs-fw-regular) var(--ecs-fs-base) / 1.4 var(--ecs-font-body);
  font-style: normal;
}
.ecs-site-foot__link { font-weight: var(--ecs-fw-medium); color: var(--ecs-ink); text-decoration: none; }
.ecs-site-foot__mail { color: var(--ecs-green-600); text-decoration: none; }
.ecs-site-foot__place { color: var(--ecs-text-muted); }
.ecs-site-foot__link:hover,
.ecs-site-foot__mail:hover { color: var(--ecs-green-600); text-decoration: underline; text-underline-offset: 4px; }
.ecs-site-foot__bar {
  grid-column: 1 / -1;
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 12px 32px;
  padding-top: 20px;
  border-top: 1px solid rgba(var(--ecs-ink-rgb), 0.14);
}
.ecs-site-foot__legal {
  margin: 0;
  font: var(--ecs-fw-medium) var(--ecs-fs-2xs) / 1.5 var(--ecs-font-mono);
  letter-spacing: 0.04em;
  color: var(--ecs-text-muted);
}
@media (prefers-reduced-motion: reduce) {
  .ecs-site-foot__parent,
  .ecs-site-foot__go { transition: none; }
}
/* Under the landing's 860px step the brand takes the width, and the pages
   and the contact sit side by side under it. */
@media (max-width: 860px) {
  .ecs-site-foot { padding: 56px 32px 28px; }
  .ecs-site-foot__inner { grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: 32px; row-gap: 40px; }
  .ecs-site-foot__brand { grid-column: 1 / -1; }
}

/* =============================================================================
   RESPONSIVE — desktop-first, relax padding / stack windows on small screens.
   ============================================================================= */
@media (max-width: 1100px) {
  .ecs-site-nav,
  .ecs-site-foot { padding-left: 32px; padding-right: 32px; }
  .ecs-land-sec { padding-left: 32px; padding-right: 32px; }
  .ecs-policy { padding: 48px 32px 96px; column-gap: 40px; }
  .ecs-policy__sec { grid-template-columns: minmax(0, 1fr); row-gap: 10px; }
  /* The panel keeps the nav's narrower gutter. */
  .ecs-land-sec.ecs-land-hero { padding: 24px 32px 56px; }
  .ecs-land-hero__text { padding: 48px; }
}

@media (max-width: 1240px) {
  .ecs-land-demo__scroll { display: inline; }
}

@media (max-width: 860px) {
  .ecs-land-sec { padding-top: 72px; padding-bottom: 72px; }
  /* One column: the bat comes first, the panel's full width, and the words
     follow it, so a phone's first screen holds both. */
  .ecs-land-hero__stage,
  .ecs-land-hero__stage.has-photo { grid-template-columns: minmax(0, 1fr); min-height: 0; }
  /* The print keeps its shape; the words take what the screen has left. */
  .ecs-land-hero__stage.has-photo { grid-template-rows: auto minmax(0, 1fr); }
  .ecs-land-hero__photo { order: -1; aspect-ratio: 4 / 3; max-height: 52svh; }
  .ecs-land-hero__text { padding: 40px 40px 48px; }
  .ecs-land-hero__title { font-size: var(--ecs-fs-hero); }
  .ecs-land-title { font-size: var(--ecs-fs-h1); margin-bottom: 36px; }
  /* The tour's unfolded layout is set with the tour; only its type steps
     down here. */
  .ecs-land-step__title { font-size: var(--ecs-fs-h3); }
  .ecs-land-promise__grid { grid-template-columns: minmax(0, 1fr); row-gap: 24px; }
  .ecs-land-sec.ecs-book { padding-top: 48px; padding-bottom: 72px; }
  .ecs-book-prep__facts { grid-template-columns: minmax(0, 1fr); row-gap: 20px; }
  .ecs-policy { grid-template-columns: minmax(0, 1fr); row-gap: 40px; }
  .ecs-policy__intro { position: static; }
  .ecs-site-foot__inner { grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: 32px; }
  .ecs-site-foot__brand { grid-column: 1 / -1; }
}

/* Where the chart drawn for the window would shrink its labels out of
   reading, the narrow one is drawn instead. The window's width decides, not
   the screen's: wide, it is the tour window's share of the column. */
@container res-window (max-width: 480px) {
  .ecs-land-res__plot { display: none; }
  .ecs-land-res__plot.is-narrow { display: block; }
}
/* Where the table is wider than the window, it keeps a row to a line and
   scrolls inside its pane, with the tabs' fade to say there is more of it. */
@container res-window (max-width: 600px) {
  .ecs-land-res .ecs-table :is(th, td) { white-space: nowrap; }
  .ecs-land-res .ecs-table-scroll {
    -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 28px), transparent);
    mask-image: linear-gradient(to right, #000 calc(100% - 28px), transparent);
  }
}

@media (max-width: 560px) {
  /* Brand on its own line and the links under it: four targets beside the
     wordmark at 390px wrapped "Book a call" onto three lines. */
  .ecs-site-nav { flex-wrap: wrap; row-gap: 12px; padding: 16px; }
  .ecs-site-nav__co { display: none; }
  .ecs-site-nav__links { width: 100%; gap: 20px; }
  .ecs-site-nav__link { white-space: nowrap; }
  .ecs-site-nav__links .ecs-btn--nav { margin-left: auto; padding: 8px 16px; white-space: nowrap; }
  .ecs-matrix.is-demo .ecs-matrix__corner,
  .ecs-matrix.is-demo .ecs-matrix__rowh { width: 132px; min-width: 132px; }
  .ecs-land-sec { padding: 56px 16px; }
  .ecs-land-sec.ecs-land-hero { padding: 16px 16px 40px; }
  .ecs-land-hero__text { padding: 28px 20px 28px; }
  .ecs-land-hero__title { font-size: 32px; margin-bottom: 16px; }
  .ecs-land-hero__sub { font-size: var(--ecs-fs-md); margin-bottom: 28px; }
  .ecs-land-hero__ctas .ecs-btn { width: 100%; }
  .ecs-land-hero__cap { left: 16px; bottom: 14px; }
  .ecs-land-title { font-size: var(--ecs-fs-h2); margin-bottom: 28px; }
  .ecs-land-step { column-gap: 16px; }
  .ecs-land-step__title { font-size: var(--ecs-fs-title); padding-top: 11px; }
  .ecs-land-step__body { font-size: var(--ecs-fs-base); }
  .ecs-land-how__head { margin-bottom: 36px; }
  .ecs-land-view__body { padding: 16px; }
  .ecs-land-quote { grid-template-columns: minmax(0, 1fr); row-gap: 20px; }
  .ecs-land-trail { grid-template-columns: minmax(0, 1fr); gap: 10px; }
  .ecs-land-trail__step { align-items: center; }
  .ecs-land-where { margin-top: 40px; align-items: flex-start; }
  .ecs-land-where svg { margin-top: 3px; }
  /* Five tabs do not fit a phone, so the strip scrolls; the fade says there
     is more of it. Charts and the table scroll inside their own panes. */
  .ecs-land-res__tabs {
    -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 28px), transparent);
    mask-image: linear-gradient(to right, #000 calc(100% - 28px), transparent);
  }
  .ecs-land-res__tab { padding: 0 15px; }
  .ecs-land-res__body { padding: 18px 16px 20px; }
  /* A name over its bar, so neither is cut short. */
  .ecs-land-res .ecs-rank__row { grid-template-columns: minmax(0, 1fr) auto; row-gap: 6px; }
  .ecs-land-res .ecs-rank__label { grid-column: 1 / -1; white-space: normal; }
  .ecs-land-res .ecs-rank__label em { white-space: normal; }
  .ecs-land-res__prov { padding: 14px 16px; }
  .ecs-land-res__facts { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); width: 100%; }
  .ecs-land-res__facts > div { flex-direction: column; gap: 0; }
  /* The tree keeps its guide, but each file's name sits over its words. */
  .ecs-bundle__row,
  .ecs-bundle__extra { grid-template-columns: minmax(0, 1fr); row-gap: 4px; padding-left: 18px; }
  .ecs-bundle__extra { row-gap: 0; }
  /* The two ways are stacked by now (760px); on a phone each button takes
     its way's whole width. */
  .ecs-land-way { padding: 24px 20px; }
  .ecs-land-way__cta { width: 100%; }
  .ecs-land-ways__both { padding: 14px 20px; }
  .ecs-land-promise__statement { font-size: var(--ecs-fs-title); }
  .ecs-land-sec.ecs-book { padding-top: 32px; padding-bottom: 56px; }
  .ecs-book__lede { font-size: var(--ecs-fs-md); margin-bottom: 28px; }
  .ecs-book__cta { width: 100%; }
  .ecs-book__steps { --gap: 24px; }
  .ecs-book__steptitle { font-size: var(--ecs-fs-lg); padding-top: 13px; }
  .ecs-book-prep__fact dd { font-size: var(--ecs-fs-md); }
  .ecs-policy { padding: 32px 16px 64px; }
  .ecs-policy__title { font-size: var(--ecs-fs-h3); }
  .ecs-policy__intro .ecs-btn { width: 100%; }
  .ecs-site-foot { padding: 48px 16px 24px; }
  /* The address needs more of the width than the page names do. */
  .ecs-site-foot__inner { grid-template-columns: minmax(0, 2fr) minmax(0, 3fr); column-gap: 20px; row-gap: 36px; }
}
