/* ==========================================================================
   Schoolopedia — components
   Sharp rectangles only. No border-radius, no gradients, and no box-shadow
   anywhere except the sticky navbar (--shadow-navbar) — see AGENTS.md §1.
   ========================================================================== */

/* --------------------------------------------------------------------------
   Eyebrow
   -------------------------------------------------------------------------- */

.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: var(--space-3);
  color: var(--color-ink-muted);
}

.eyebrow::before {
  content: "";
  display: block;
  width: 6px;
  height: 12px;
  flex-shrink: 0;
  background-color: var(--color-copper);
}

.eyebrow--invert {
  color: var(--color-ink-invert-muted);
}

.eyebrow--blink::before {
  animation: eyebrow-blink 1.5s ease-in-out infinite;
}

@keyframes eyebrow-blink {
  0%,
  100% {
    opacity: 1;
  }
  50% {
    opacity: 0.25;
  }
}

/* --------------------------------------------------------------------------
   Buttons
   -------------------------------------------------------------------------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-5);
  height: 48px;
  padding-inline: var(--space-3);
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: 14px;
  line-height: 20px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  background-color: var(--color-copper);
  color: var(--color-ink-invert);
  border: 1px solid var(--color-copper);
  transition: background-color var(--dur-fast) var(--ease-out),
    border-color var(--dur-fast) var(--ease-out);
}

.btn:hover {
  background-color: var(--color-copper-deep);
  border-color: var(--color-copper-deep);
}

.btn__icon {
  flex-shrink: 0;
  transition: transform var(--dur-fast) var(--ease-out);
}

.btn:hover .btn__icon {
  transform: translateX(3px);
}

.btn--ghost {
  background-color: transparent;
  color: var(--color-ink);
  border-color: var(--color-line-strong);
}

.btn--ghost:hover {
  background-color: var(--color-surface-sunk);
  border-color: var(--color-ink);
}

.btn--invert {
  background-color: var(--color-surface);
  color: var(--color-ink);
  border-color: var(--color-surface);
}

.btn--invert:hover {
  background-color: var(--color-surface-sunk);
  border-color: var(--color-surface-sunk);
}

.btn--sm {
  height: 36px;
  gap: var(--space-4);
}

.btn--block {
  width: 100%;
}

/* Text link with an arrow */
.link-arrow {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-family: var(--font-mono);
  font-size: 14px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--color-copper-text);
  border-bottom: 1px solid var(--color-line-strong);
  padding-bottom: 2px;
  transition: border-color var(--dur-fast) var(--ease-out),
    color var(--dur-fast) var(--ease-out);
}

.link-arrow:hover {
  color: var(--color-copper-deep);
  border-bottom-color: var(--color-copper);
}

.link-arrow svg {
  transition: transform var(--dur-fast) var(--ease-out);
}

.link-arrow:hover svg {
  transform: translateX(3px);
}

/* On dark surfaces the default blue-dark fails contrast — invert instead. */
.link-arrow--invert {
  color: var(--color-ink-invert);
  border-bottom-color: var(--color-ink-invert-muted);
}

.link-arrow--invert:hover {
  color: var(--color-ink-invert);
  border-bottom-color: var(--color-amber);
}

/* --------------------------------------------------------------------------
   Navbar
   -------------------------------------------------------------------------- */

.navbar {
  position: sticky;
  top: 0;
  z-index: 100;
  background-color: var(--color-surface);
  border-bottom: 1px solid var(--color-line-soft);
  /* Deliberate exception to the no-shadow rule — see tokens.css. */
  box-shadow: var(--shadow-navbar);
}

.navbar__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-6);
  height: var(--navbar-height);
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: var(--space-3);
  flex-shrink: 0;
}

/* Owl mark cropped from the master logo — the stacked wordmark is illegible
   at navbar height, so the mark pairs with type set in the site's own font. */
.brand__mark {
  width: auto;
  height: 90px;
  flex-shrink: 0;
}

/* Name over tagline, mirroring the stacked lockup of the master logo. */
.brand__text {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 2px;
}

.brand__name {
  font-family: var(--font-sans);
  font-weight: 600;
  font-size: 28px;
  line-height: 32px;
  letter-spacing: -0.02em;
  color: var(--color-ink);
}

/* The accent "O", matching the recoloured master logo's wordmark. Copper
   rather than amber: this is type, not a mark, and copper clears AA on
   paper at 6.7:1 while reading as the same brand hue as the amber owl. */
.brand__accent {
  color: var(--color-copper-text);
}

.brand__sub {
  font-family: var(--font-mono);
  font-size: 11px;
  line-height: 16px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--color-ink-muted);
}

.nav-links {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

/* Ink, not ink-soft, and medium weight: the menu has to read at a glance
   against the paper. The padding gives the active tint room to sit in. */
.nav-link {
  font-family: var(--font-sans);
  font-size: 13px;
  font-weight: 500;
  line-height: 16px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  white-space: nowrap;
  color: var(--color-ink);
  padding: var(--space-2) var(--space-2);
  border-bottom: 2px solid transparent;
  transition: color var(--dur-fast) var(--ease-out),
    background-color var(--dur-fast) var(--ease-out),
    border-color var(--dur-fast) var(--ease-out);
}

.nav-link:hover {
  background-color: var(--color-surface-sunk);
  border-bottom-color: var(--color-line-strong);
}

/* The current page: a warm sand panel, copper type and a copper rule, so it
   reads as selected and not merely hovered. Copper-text is 6.7:1 on paper. */
.nav-link--active,
.nav-link--active:hover {
  font-weight: 600;
  color: var(--color-copper-text);
  background-color: var(--color-surface-tint);
  border-bottom-color: var(--color-copper);
}

/* Two buttons on a wide screen, the menu toggle on a narrow one — never both,
   so this gap only ever separates the pair of buttons. */
.navbar__right {
  display: flex;
  align-items: center;
  gap: var(--space-4);
}

.navbar__right .btn {
  white-space: nowrap;
}

.navbar__right .btn svg {
  flex-shrink: 0;
}

/* The phone icon is drawn for the contact list, at its size. In a small button
   it comes down to match the arrow beside it in the button next door. */
.navbar__call svg {
  width: 16px;
  height: 16px;
}

/* The nav links, the brand and two buttons stop fitting before the layout
   reaches its mobile breakpoint. The call is the one that gives way: it is the
   secondary action, and the menu below still carries it. */
@media (max-width: 1340px) {
  .navbar__call {
    display: none;
  }
}

@media (max-width: 1180px) {
  .navbar__inner {
    gap: var(--space-4);
  }

  .nav-links {
    gap: 0;
  }

  .nav-link {
    font-size: 12px;
    padding-inline: 7px;
  }

  .brand__mark {
    height: 72px;
  }

  .brand__name {
    font-size: 24px;
    line-height: 28px;
  }
}

/* Just above the collapse the brand keeps its name and drops the tagline. */
@media (max-width: 1080px) {
  .brand__sub {
    display: none;
  }
}

.nav-toggle {
  display: none;
  width: 40px;
  height: 40px;
  align-items: center;
  justify-content: center;
  flex-direction: column;
  gap: 5px;
}

.nav-toggle__bar {
  display: block;
  width: 22px;
  height: 2px;
  background-color: var(--color-ink);
  transition: transform var(--dur-fast) var(--ease-out),
    opacity var(--dur-fast) var(--ease-out);
}

.nav-toggle[aria-expanded="true"] .nav-toggle__bar:nth-child(1) {
  transform: translateY(7px) rotate(45deg);
}

.nav-toggle[aria-expanded="true"] .nav-toggle__bar:nth-child(2) {
  opacity: 0;
}

.nav-toggle[aria-expanded="true"] .nav-toggle__bar:nth-child(3) {
  transform: translateY(-7px) rotate(-45deg);
}

.mobile-nav {
  position: fixed;
  inset: var(--navbar-height) 0 0;
  z-index: 99;
  background-color: var(--color-surface);
  padding: var(--space-8) var(--gutter);
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  transform: translateX(100%);
  visibility: hidden;
  transition: transform var(--dur-mid) var(--ease-reveal),
    visibility var(--dur-mid);
}

.mobile-nav[data-open="true"] {
  transform: translateX(0);
  visibility: visible;
}

.mobile-nav__link {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding-block: var(--space-5);
  border-bottom: 1px solid var(--color-line-soft);
  font-family: var(--font-sans);
  font-weight: 500;
  font-size: 22px;
  color: var(--color-ink);
}

.mobile-nav__cta {
  margin-top: var(--space-6);
}

/* --------------------------------------------------------------------------
   Hero
   -------------------------------------------------------------------------- */

.hero {
  padding-block: var(--space-20) var(--space-15);
  background-color: var(--color-surface);
}

.hero__inner {
  display: grid;
  grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr);
  gap: var(--space-12);
  align-items: center;
}

.hero__copy {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-6);
}

.hero__title .accent {
  color: var(--color-copper);
}

.hero__tagline {
  font-family: var(--font-mono);
  font-size: 13px;
  letter-spacing: 0.04em;
  color: var(--color-ink-muted);
  padding-left: var(--space-4);
  border-left: 2px solid var(--color-amber);
}

.hero__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4);
  padding-top: var(--space-2);
}

.hero__media {
  position: relative;
}

.hero__image {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
}

/* The animation takes the height of the copy beside it, so its top and bottom
   line up with the eyebrow and the buttons. The loop is rendered at 10:9 with
   its content kept clear of the edges, so `cover` only ever trims background. */
.hero__media--motion {
  align-self: stretch;
  display: flex;
  flex-direction: column;
}

.hero__motion {
  position: relative;
  flex: 1;
  min-height: 320px;
}

.hero__video {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  background-color: var(--color-surface);
}

/* Pause and music sit on the frame's bottom-left corner. Hidden without
   JavaScript, because without it there is nothing for them to control. */
.hero__controls {
  position: absolute;
  left: var(--space-4);
  bottom: var(--space-4);
  display: none;
  gap: var(--space-2);
}

.js .hero__controls {
  display: flex;
}

.hero__control,
.showcase__control {
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--color-ink);
  background-color: var(--color-surface);
  border: 1px solid var(--color-line-strong);
  padding: var(--space-2) var(--space-3);
  cursor: pointer;
  transition: border-color 0.2s var(--ease-out), color 0.2s var(--ease-out);
}

.hero__control:hover,
.showcase__control:hover {
  border-color: var(--color-copper);
  color: var(--color-copper-text);
}

.hero__control:focus-visible,
.showcase__control:focus-visible {
  outline: 2px solid var(--color-copper);
  outline-offset: 2px;
}

.hero__control.is-on {
  border-color: var(--color-copper);
  color: var(--color-copper-text);
}

/* --------------------------------------------------------------------------
   Digital Learning showcase — three silent loops under the capability grid
   -------------------------------------------------------------------------- */

.showcase {
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
}

.showcase__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  padding-bottom: var(--space-3);
  border-bottom: 1px solid var(--color-line);
}

/* Nothing to pause without JavaScript: the posters stand still. */
.showcase__control {
  display: none;
}

.js .showcase__control {
  display: inline-block;
}

.showcase__item {
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.showcase__frame {
  position: relative;
  aspect-ratio: 4 / 3;
  background-color: var(--color-surface);
  border: 1px solid var(--color-line-soft);
  border-top: 2px solid var(--color-copper);
}

.showcase__video {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.showcase__caption {
  font-size: 15px;
  line-height: 22px;
  color: var(--color-ink);
}

/* The same tonal ladder as the capability panels above. */
.showcase__item:nth-child(3n + 1) .showcase__frame {
  border-top-color: var(--color-amber);
}

.showcase__item:nth-child(3n + 3) .showcase__frame {
  border-top-color: var(--color-stone);
}

/* Three loops stay a row of three down to tablet width — two plus an orphan
   would break the set — and stack on a phone. */
@media (max-width: 1024px) {
  .showcase .grid--3 {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: var(--space-4);
  }
}

@media (max-width: 640px) {
  .showcase .grid--3 {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* Brand gradient rule under the hero photo. */
.hero__stripe {
  height: 6px;
  background: var(--gradient-brand);
}

/* --------------------------------------------------------------------------
   Marquee
   -------------------------------------------------------------------------- */

.marquee {
  border-block: 1px solid var(--color-line-soft);
  padding-block: var(--space-6);
  overflow: hidden;
}

.marquee__label {
  text-align: center;
  color: var(--color-ink);
  letter-spacing: 0.12em;
  margin-bottom: var(--space-5);
}

.marquee__viewport {
  overflow: hidden;
  -webkit-mask-image: linear-gradient(
    90deg,
    transparent,
    var(--color-ink) 12%,
    var(--color-ink) 88%,
    transparent
  );
  mask-image: linear-gradient(
    90deg,
    transparent,
    var(--color-ink) 12%,
    var(--color-ink) 88%,
    transparent
  );
}

.marquee__track {
  display: flex;
  align-items: center;
  gap: var(--space-15);
  width: max-content;
  animation: marquee-scroll 38s linear infinite;
}

.marquee:hover .marquee__track {
  animation-play-state: paused;
}

.marquee__item {
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: 15px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--color-ink-muted);
  white-space: nowrap;
}

/* --------------------------------------------------------------------------
   About the owner — portrait beside quote and story
   -------------------------------------------------------------------------- */

.owner__grid {
  display: grid;
  grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
  gap: var(--space-15);
  align-items: start;
}

/* On the about page the story runs long, so the portrait keeps pace with it. */
.owner__media {
  position: sticky;
  top: calc(var(--navbar-height) + var(--space-6));
}

.owner__photo {
  display: block;
  width: 100%;
  aspect-ratio: 3 / 4;
  object-fit: cover;
}

/* The same brand rule that sits under the hero. */
.owner__stripe {
  height: 6px;
  background: var(--gradient-brand);
}

.owner__copy {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-5);
}

.owner__role {
  color: var(--color-copper-text);
  margin-top: calc(var(--space-3) * -1);
}

.owner__quote {
  margin: var(--space-2) 0;
  padding-left: var(--space-6);
  border-left: 3px solid var(--color-copper);
}

.owner__intro,
.owner__body {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  font-size: 17px;
  line-height: 28px;
  color: var(--color-ink-soft);
}

.owner__intro strong,
.owner__body strong {
  font-weight: 600;
  color: var(--color-ink);
}

/* The client set this line in bold italic; here it closes the story as the
   one copper statement, ruled off from the paragraphs above it. */
.owner__philosophy {
  align-self: stretch;
  padding-top: var(--space-5);
  border-top: 1px solid var(--color-line);
  font-size: 18px;
  line-height: 28px;
  font-weight: 500;
  font-style: italic;
  color: var(--color-copper-text);
}

@media (max-width: 900px) {
  .owner__grid {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-10);
  }

  .owner__media {
    position: static;
    max-width: 420px;
  }
}

/* --------------------------------------------------------------------------
   Client logos — the same band as the capability marquee, with logos
   -------------------------------------------------------------------------- */

.logo-band {
  border-block: 1px solid var(--color-line-soft);
  padding-block: var(--space-8);
  overflow: hidden;
}

.logo-band__label {
  text-align: center;
  color: var(--color-ink);
  letter-spacing: 0.12em;
  margin-bottom: var(--space-6);
}

.logo-band__body {
  text-align: center;
  font-size: 15px;
  line-height: 22px;
  color: var(--color-ink-muted);
  margin-top: calc(var(--space-4) * -1);
  margin-bottom: var(--space-6);
}

.logo-band__viewport {
  overflow: hidden;
  -webkit-mask-image: linear-gradient(
    90deg,
    transparent,
    var(--color-ink) 12%,
    var(--color-ink) 88%,
    transparent
  );
  mask-image: linear-gradient(
    90deg,
    transparent,
    var(--color-ink) 12%,
    var(--color-ink) 88%,
    transparent
  );
}

.logo-band__track {
  display: flex;
  align-items: center;
  gap: var(--space-15);
  width: max-content;
  margin: 0;
  padding: 0;
  list-style: none;
  animation: marquee-scroll 40s linear infinite;
}

.logo-band:hover .logo-band__track {
  animation-play-state: paused;
}

.logo-band__item {
  display: flex;
  align-items: center;
  height: 64px;
}

/* Muted like the capability names, so a row of logos in a dozen house
   colours reads as one band; each one comes up to full colour on hover. */
.logo-band__logo {
  width: auto;
  height: 100%;
  max-width: 200px;
  object-fit: contain;
  filter: grayscale(1);
  opacity: 0.7;
  transition: filter var(--dur-fast) var(--ease-out),
    opacity var(--dur-fast) var(--ease-out);
}

.logo-band__item:hover .logo-band__logo {
  filter: none;
  opacity: 1;
}

@media (max-width: 640px) {
  .logo-band__track {
    gap: var(--space-10);
  }

  .logo-band__item {
    height: 48px;
  }
}

@keyframes marquee-scroll {
  from {
    transform: translateX(0);
  }
  to {
    transform: translateX(-50%);
  }
}

/* --------------------------------------------------------------------------
   Cards
   -------------------------------------------------------------------------- */

.card {
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
  min-height: 192px;
  padding: var(--space-8) var(--space-10) var(--space-8) var(--space-6);
  background-color: var(--color-surface-sunk);
  border-top: 3px solid var(--color-copper);
  transition: background-color var(--dur-fast) var(--ease-out),
    transform var(--dur-fast) var(--ease-out);
}

.card:hover {
  background-color: var(--color-surface-tint);
  transform: translateY(-3px);
}

/* Tonal ladder across a row of cards — amber stepping down through copper
   into stone and ink. Positional, so the markup carries no colour. */
.grid--4 > .card:nth-child(4n + 1) {
  border-top-color: var(--color-amber);
}
.grid--4 > .card:nth-child(4n + 2) {
  border-top-color: var(--color-copper);
}
.grid--4 > .card:nth-child(4n + 3) {
  border-top-color: var(--color-stone);
}
.grid--4 > .card:nth-child(4n + 4) {
  border-top-color: var(--color-ink);
}

.card__index {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.1em;
  color: var(--color-ink-muted);
}

.card__title {
  font-family: var(--font-sans);
  font-weight: 500;
  font-size: 20px;
  line-height: 28px;
  color: var(--color-ink);
}

.card__body {
  color: var(--color-ink-muted);
  margin-top: auto;
}

/* --------------------------------------------------------------------------
   Numbered steps
   -------------------------------------------------------------------------- */

.steps {
  display: flex;
  flex-direction: column;
}

.step {
  display: grid;
  grid-template-columns: 56px minmax(0, 1fr);
  gap: var(--space-5);
  padding-block: var(--space-6);
  border-top: 1px solid var(--color-line);
}

.step:last-child {
  border-bottom: 1px solid var(--color-line);
}

.step__number {
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: 14px;
  letter-spacing: 0.06em;
  color: var(--color-ink-muted);
  padding-top: 3px;
}

.step__title {
  font-family: var(--font-sans);
  font-weight: 500;
  font-size: 18px;
  line-height: 26px;
  color: var(--color-ink);
  margin-bottom: var(--space-2);
}

.step__body {
  color: var(--color-ink-muted);
}

/* --------------------------------------------------------------------------
   Accordion
   -------------------------------------------------------------------------- */

.accordion {
  border-top: 1px solid var(--color-line);
}

.accordion__item {
  border-bottom: 1px solid var(--color-line);
}

.accordion__trigger {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-6);
  padding-block: var(--space-6);
  text-align: left;
  font-family: var(--font-sans);
  font-weight: 500;
  font-size: 18px;
  line-height: 26px;
  color: var(--color-ink);
  transition: color var(--dur-fast) var(--ease-out);
}

.accordion__trigger:hover {
  color: var(--color-copper-text);
}

.accordion__icon {
  position: relative;
  width: 14px;
  height: 14px;
  flex-shrink: 0;
}

.accordion__icon::before,
.accordion__icon::after {
  content: "";
  position: absolute;
  background-color: var(--color-copper);
  transition: transform var(--dur-fast) var(--ease-out),
    opacity var(--dur-fast) var(--ease-out);
}

.accordion__icon::before {
  inset: 6px 0 6px 0;
  height: 2px;
}

.accordion__icon::after {
  inset: 0 6px 0 6px;
  width: 2px;
}

.accordion__trigger[aria-expanded="true"] .accordion__icon::after {
  opacity: 0;
  transform: rotate(90deg);
}

/*
   An accordion is a way of folding content away, and folding needs something
   to unfold it. This collapsed unconditionally, so with scripting switched off
   all thirteen answers on the home page were clipped to nothing and the
   trigger that would have opened them did nothing — the content was simply
   gone. Behind `.js`, exactly like the reveal animations: closed once there is
   something there to open it, open otherwise.
*/
.accordion__panel {
  display: grid;
  grid-template-rows: 1fr;
}

.js .accordion__panel {
  grid-template-rows: 0fr;
  transition: grid-template-rows var(--dur-mid) var(--ease-reveal);
}

.js .accordion__panel[data-open="true"] {
  grid-template-rows: 1fr;
}

.accordion__panel-inner {
  overflow: hidden;
}

/*
   Clipped to zero height is invisible to the eye and perfectly audible to a
   screen reader, which would read all thirteen answers straight through the
   questions. `visibility` takes a collapsed answer out of the accessibility
   tree and out of the tab order, and it is switched at the far end of the
   open animation so it never clips the movement.
*/
.js .accordion__panel-inner {
  visibility: hidden;
  transition: visibility 0s linear var(--dur-mid);
}

.js .accordion__panel[data-open="true"] .accordion__panel-inner {
  visibility: visible;
  transition-delay: 0s;
}

.accordion__answer {
  padding-bottom: var(--space-6);
  padding-right: var(--space-10);
  color: var(--color-ink-muted);
}

/* --------------------------------------------------------------------------
   CTA panel
   -------------------------------------------------------------------------- */

.cta-panel {
  background-color: var(--color-surface-dark);
  background-image: var(--dots-invert), var(--gradient-dark);
  background-repeat: no-repeat;
  background-size: cover;
  padding: var(--space-15) var(--space-12);
  display: grid;
  grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr);
  gap: var(--space-10);
  align-items: center;
}

.cta-panel__title {
  color: var(--color-ink-invert);
}

.cta-panel__body {
  color: var(--color-ink-invert-muted);
}

/* Right half of the panel — actions sit flush against its right edge. */
.cta-panel__actions {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  align-items: flex-end;
}

/* --------------------------------------------------------------------------
   Form fields
   -------------------------------------------------------------------------- */

.field {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  width: 100%;
}

.field__label {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--color-ink-muted);
}

.field__input {
  border: 0;
  border-bottom: 1px solid var(--color-line-strong);
  background-color: transparent;
  padding-block: var(--space-2);
  font-family: var(--font-sans);
  font-weight: 500;
  font-size: 20px;
  line-height: 30px;
  color: var(--color-ink);
  transition: border-color var(--dur-fast) var(--ease-out);
}

.field__input::placeholder {
  color: var(--color-line-strong);
  font-weight: 400;
}

/*
   The enquiry form's fields used to answer focus with `outline: none` and a
   one-pixel change of border colour. That is not a focus indicator anybody can
   find: a keyboard visitor filling this form could not see which field they
   were in, and it was the only place on the site that opted out of the 2px
   copper ring in base.css.

   So the ring stays — the outline declaration is simply gone from here — and
   the border still deepens, which is the bit of the original that was doing
   useful work.
*/
.field__input:focus {
  border-bottom-color: var(--color-copper);
}

.field__note {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.04em;
  min-height: 16px;
}

.field__note--error {
  color: var(--color-error);
}

.field__note--success {
  color: var(--color-success);
}

/* A submit button inside a stretch-aligned .field must not span the column. */
.field .btn {
  align-self: flex-start;
}

/* --------------------------------------------------------------------------
   Select

   Two controls, for two worlds.

   Without JavaScript the native <select> is the control, and it gets what CSS
   can give a native select: the platform arrow suppressed and a chevron drawn
   in its place. The open list stays the operating system's, because there has
   never been a way to style it.

   With JavaScript, main.js draws a listbox in front of it and hides it. That
   control is a <button> and a <ul>, so every part of it — including the open
   list, the highlight and the chosen row — is ours.

   Both are underlines rather than boxes, because the five fields beside them
   are. A select that turned into a bordered box to look modern would only look
   like it came from a different form.
   -------------------------------------------------------------------------- */

select.field__input {
  appearance: none;
  cursor: pointer;

  /* Room for the chevron, and an ellipsis rather than text sliding under it
     when a long subject meets a narrow column. */
  padding-right: var(--space-8);
  text-overflow: ellipsis;

  /* The open list is drawn by the operating system. This much it does honour:
     a light popup on paper rather than a stark white box, whatever the visitor
     has their system set to. */
  color-scheme: light;

  /* Two 6px tiles, one stroke each, overlapping by a pixel so the arms meet at
     the point. Gradients rather than an SVG: a data URI would put a colour
     outside tokens.css, which is the one place colour is allowed to live. */
  background-repeat: no-repeat;
  background-size: 6px 6px, 6px 6px;
  background-position: right 9px center, right 4px center;
  background-image:
    linear-gradient(
      45deg,
      transparent calc(50% - 1px),
      var(--color-ink-muted) calc(50% - 1px),
      var(--color-ink-muted) calc(50% + 1px),
      transparent calc(50% + 1px)
    ),
    linear-gradient(
      135deg,
      transparent calc(50% - 1px),
      var(--color-ink-muted) calc(50% - 1px),
      var(--color-ink-muted) calc(50% + 1px),
      transparent calc(50% + 1px)
    );
}

/* The prompt is not an answer. Until a subject is chosen the select is
   `:invalid` — it is required and the prompt option has no value — so it reads
   muted, the way the sibling inputs read their placeholders.

   Stone, though, not the placeholder token those inputs use. A placeholder is
   a hint sitting beside an empty field; this text IS the control's current
   value, and at 1.7:1 on sand nobody could read what the form was about to
   send. Stone is 5.5:1 and still plainly not the chosen state. */
select.field__input:invalid {
  color: var(--color-ink-muted);
}

select.field__input:hover {
  border-bottom-color: var(--color-ink-muted);
}

select.field__input:hover,
select.field__input:focus {
  background-image:
    linear-gradient(
      45deg,
      transparent calc(50% - 1px),
      var(--color-copper-text) calc(50% - 1px),
      var(--color-copper-text) calc(50% + 1px),
      transparent calc(50% + 1px)
    ),
    linear-gradient(
      135deg,
      transparent calc(50% - 1px),
      var(--color-copper-text) calc(50% - 1px),
      var(--color-copper-text) calc(50% + 1px),
      transparent calc(50% + 1px)
    );
}

/* Focus flips it: the two gradients trade places and the chevron points up. */
select.field__input:focus {
  background-image:
    linear-gradient(
      135deg,
      transparent calc(50% - 1px),
      var(--color-copper-text) calc(50% - 1px),
      var(--color-copper-text) calc(50% + 1px),
      transparent calc(50% + 1px)
    ),
    linear-gradient(
      45deg,
      transparent calc(50% - 1px),
      var(--color-copper-text) calc(50% - 1px),
      var(--color-copper-text) calc(50% + 1px),
      transparent calc(50% + 1px)
    );
}

/* The list itself. Only the colours are ours to set — the box, its border and
   its motion belong to the platform — but that is enough to stop a warm-paper
   form opening a cold white menu at somebody. */
select.field__input option {
  background-color: var(--color-surface);
  color: var(--color-ink);
  font-weight: 400;
}

select.field__input option:disabled {
  color: var(--color-ink-muted);
}

/* ------------------------------------------------------- the drawn control */

.select {
  position: relative;
  width: 100%;
}

/* It already carries .field__input, so the underline, the type and the colour
   come from there. This is only what a <button> does not inherit from an
   <input>. */
.select__control {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  width: 100%;
  text-align: left;
  cursor: pointer;
  background-color: transparent;
}

.select__value {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.select[data-empty="true"] .select__value {
  color: var(--color-ink-muted);
}

.select[data-invalid="true"] .select__control {
  border-bottom-color: var(--color-error);
}

.select[data-open="true"] .select__control {
  border-bottom-color: var(--color-copper);
}

/* Two borders on a square, turned 45°. Cheaper than an icon and, unlike a
   background-image, it can rotate — so opening the list turns the chevron over
   rather than swapping one picture for another. */
.select__chevron {
  width: 8px;
  height: 8px;
  flex-shrink: 0;
  margin-right: 3px;
  border-right: 2px solid var(--color-ink-muted);
  border-bottom: 2px solid var(--color-ink-muted);
  transform: translateY(-2px) rotate(45deg);
  transition: transform var(--dur-fast) var(--ease-out),
    border-color var(--dur-fast) var(--ease-out);
}

.select__control:hover .select__chevron,
.select__control:focus .select__chevron,
.select[data-open="true"] .select__chevron {
  border-color: var(--color-copper-text);
}

.select__control[aria-expanded="true"] .select__chevron {
  transform: translateY(2px) rotate(-135deg);
}

/* ---------------------------------------------------------------- the list */

/*
   Hidden by visibility rather than by display, for two reasons: it can be
   measured while closed, which is what decides whether it opens up or down,
   and it can be transitioned. Same as the mobile navigation.

   No shadow — there are none on this site but the navbar's — so the separation
   from the page comes from a real border and the copper cap, which is the same
   edge the form panel itself carries.
*/
.select__list {
  --select-shift: -4px;

  position: absolute;
  left: 0;
  right: 0;
  z-index: 30;
  /* A design cap, not a fit: main.js narrows this to whole rows when the space
     on the side it opened towards is tighter than that. */
  max-height: 360px;
  overflow-y: auto;
  overscroll-behavior: contain;
  background-color: var(--color-surface-raised);
  border: 1px solid var(--color-line);
  border-top: 2px solid var(--color-copper);
  opacity: 0;
  visibility: hidden;
  transform: translateY(var(--select-shift));
  transition: opacity var(--dur-fast) var(--ease-out),
    transform var(--dur-fast) var(--ease-out),
    visibility var(--dur-fast);
}

/* Hard against the control, because its own underline is already the line
   between the two. */
.select[data-drop="down"] .select__list {
  top: calc(100% + 1px);
}

/* Opening upwards there is no underline up there to separate them, so the list
   keeps its distance — and the copper edge travels with it, because it marks
   where the list meets the control rather than the top of a box. */
.select[data-drop="up"] .select__list {
  --select-shift: 4px;

  bottom: calc(100% + var(--space-2));
  border-top: 1px solid var(--color-line);
  border-bottom: 2px solid var(--color-copper);
}

.select__list[data-open="true"] {
  opacity: 1;
  visibility: visible;
  transform: none;
}

.select__option {
  /* The border is always there and always two pixels, transparent until the
     row is the chosen one, so nothing shifts sideways when it is. */
  border-left: 2px solid transparent;
  padding: var(--space-3) var(--space-5);
  padding-left: calc(var(--space-5) - 2px);
  font-family: var(--font-sans);
  font-size: 16px;
  line-height: 24px;
  color: var(--color-ink-soft);
  cursor: pointer;
  transition: background-color var(--dur-fast) var(--ease-out),
    color var(--dur-fast) var(--ease-out);
}

/* One highlight, whether it was reached by pointer or by arrow key. The script
   sets this class from both, so hovering and arrowing never light up two
   different rows. */
.select__option--active {
  background-color: var(--color-surface-sunk);
  color: var(--color-ink);
}

.select__option[aria-selected="true"] {
  border-left-color: var(--color-copper);
  color: var(--color-copper-text);
  font-weight: 500;
}

/* --------------------------------------------------------------------------
   Floating actions

   Square tiles, not round bubbles.

   The green circle every site puts in this corner is WhatsApp's, not ours, and
   this design system has no round corners and no shadows anywhere but the
   navbar — so the usual widget would sit on the page as an obviously foreign
   object, which is exactly how a visitor learns to ignore something. The
   glyphs are the part people recognise; the tiles are the site's own.

   The two are filled differently on purpose. Two identical copper squares
   stacked read as one thing drawn twice; ink and copper read immediately as
   two different ways to get in touch. Both are colours the site already uses
   for exactly this — copper is every call to action on it, and ink is the
   closing panel.

   The stack sits below the mobile navigation, which covers the whole viewport
   when open — so the menu hides it without either of them knowing about the
   other.
   -------------------------------------------------------------------------- */

.floating {
  position: fixed;
  right: var(--space-8);
  bottom: var(--space-8);
  z-index: 90;

  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.floating__action {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 56px;
  height: 56px;

  transition: background-color var(--dur-fast) var(--ease-out),
    transform var(--dur-fast) var(--ease-out);
}

.floating__action:hover {
  /* Up, not out. Growing a fixed element pushes it towards the corner it is
     pinned to; lifting it reads as a press without moving the target. */
  transform: translateY(-2px);
}

/* Held down: back where it started, so the tile answers the finger. */
.floating__action:active {
  transform: none;
}

.floating__action--whatsapp {
  background-color: var(--color-copper);
  color: var(--color-ink-invert);
}

.floating__action--whatsapp:hover {
  background-color: var(--color-copper-deep);
}

/*
   The call, and only where the navbar cannot offer it.

   Above 1340px the navbar has room for "Talk to our team" and this would be
   the same action twice on one screen. Below it the navbar has dropped that
   button, and this takes over — which is why the breakpoint here is the same
   number as the one that hides .navbar__call, and has to stay that way.
*/
.floating__action--call {
  display: none;
  background-color: var(--color-surface-dark);
  color: var(--color-ink-invert);
}

.floating__action--call:hover {
  background-color: var(--color-ink-soft);
}

/* The phone is a stroked glyph beside a filled one, so at an equal box it
   reads lighter. A few pixels larger evens the two tiles out. */
.floating__action--call svg {
  width: 25px;
  height: 25px;
}

@media (max-width: 1340px) {
  .floating__action--call {
    display: flex;
  }
}

@media (max-width: 900px) {
  .floating {
    right: var(--space-5);
    bottom: var(--space-5);
  }

  .floating__action {
    width: 52px;
    height: 52px;
  }
}

/* --------------------------------------------------------------------------
   Footer
   -------------------------------------------------------------------------- */

/* Two-tier footer. The separation from whatever sits above comes from the
   four-colour rule, not from a background wash — so the body can stay white
   and let the master logo keep its own colours with no plate behind it. */
.footer {
  background-color: var(--color-surface);
}

.footer__rule {
  height: 4px;
  width: 100%;
  background: var(--gradient-brand);
}

.footer__body {
  padding-block: var(--space-15);
}

.brand-logo {
  display: block;
  width: 176px;
  height: auto;
}

/* Hairline dividers between columns give the block structure without adding
   another colour. */
.footer__grid {
  display: grid;
  grid-template-columns: minmax(0, 1.5fr) repeat(3, minmax(0, 1fr));
  gap: 0;
}

.footer__col {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  align-items: flex-start;
  padding-left: var(--space-10);
  border-left: 1px solid var(--color-line-soft);
}

.footer__col:first-child {
  padding-left: 0;
  padding-right: var(--space-10);
  border-left: 0;
}

.footer__title {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--color-ink);
  padding-bottom: var(--space-4);
  margin-bottom: var(--space-1);
  border-bottom: 1px solid var(--color-line-soft);
  width: 100%;
}

.footer__link {
  color: var(--color-ink-muted);
  font-size: 14px;
  line-height: 22px;
  transition: color var(--dur-fast) var(--ease-out);
}

.footer__link:hover {
  color: var(--color-copper-text);
}

/* Second tier: a full-bleed strip, visually quieter than the body above it. */
.footer__legal-bar {
  background-color: var(--color-surface-sunk);
  border-top: 1px solid var(--color-line);
}

.footer__legal {
  padding-block: var(--space-5);
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: center;
  gap: var(--space-4);
}

.footer__legal-links {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-5);
}

/* --------------------------------------------------------------------------
   Scroll reveal
   Progressive enhancement: the `js` class is set by main.js, so with
   JavaScript disabled every element stays fully visible.
   -------------------------------------------------------------------------- */

.js [data-reveal] {
  opacity: 0;
  transform: translateY(20px);
  transition: opacity var(--dur-slow) var(--ease-reveal),
    transform var(--dur-slow) var(--ease-reveal);
  transition-delay: var(--reveal-delay, 0ms);
}

.js [data-reveal].is-revealed {
  opacity: 1;
  transform: none;
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }

  .js [data-reveal] {
    opacity: 1;
    transform: none;
  }
}

/* --------------------------------------------------------------------------
   Responsive
   -------------------------------------------------------------------------- */

@media (max-width: 1024px) {
  .hero__inner {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-10);
  }

  /* Stacked, there is no copy beside it to match: use the loop's own shape. */
  .hero__motion {
    flex: none;
    min-height: 0;
    aspect-ratio: 10 / 9;
  }

  .footer__grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 900px) {
  .nav-links,
  .navbar__right .btn {
    display: none;
  }

  .nav-toggle {
    display: flex;
  }

  .brand__mark {
    height: 52px;
  }

  .cta-panel {
    grid-template-columns: minmax(0, 1fr);
    padding: var(--space-10) var(--space-6);
  }

  /* One column — nothing to align against on the right any more. */
  .cta-panel__actions {
    align-items: flex-start;
  }
}

@media (max-width: 640px) {
  .footer__grid {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-8);
  }

  /* The legal row has no columns left to align against on a phone, so it
     centres rather than hanging off the left edge. */
  .footer__legal {
    flex-direction: column;
    justify-content: center;
    text-align: center;
    gap: var(--space-5);
  }

  .footer__legal-links {
    justify-content: center;
    gap: var(--space-4) var(--space-5);
  }

  .card {
    padding: var(--space-6);
  }

}

/* Once the grid wraps, the columns need a row gap — and the divider on the
   column that starts a new row has to go. */
@media (max-width: 1024px) {
  .footer__grid {
    row-gap: var(--space-12);
  }

  .footer__col:nth-child(3) {
    padding-left: 0;
    border-left: 0;
  }
}

@media (max-width: 640px) {
  .footer__grid {
    row-gap: var(--space-10);
  }

  .footer__col {
    padding-left: 0;
    padding-right: 0;
    border-left: 0;
  }

  .footer__col:first-child {
    padding-right: 0;
  }
}

/* --------------------------------------------------------------------------
   Tally
   The "one platform for ERP, another for admissions…" list. The running
   count down the right edge is the point of the block: it makes the number
   of systems a school is juggling countable rather than rhetorical.
   -------------------------------------------------------------------------- */

.tally {
  width: 100%;
  border-top: 1px solid var(--color-line);
}

.tally__row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-4);
  padding-block: var(--space-3);
  border-bottom: 1px solid var(--color-line);
}

.tally__label {
  font-family: var(--font-sans);
  font-size: 16px;
  line-height: 24px;
  color: var(--color-ink-soft);
}

.tally__row:first-child .tally__label {
  font-weight: 500;
  color: var(--color-ink);
}

.tally__count {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.1em;
  color: var(--color-ink-muted);
  flex-shrink: 0;
}

/* On the dark panel the hairlines and type invert. */
.tally--invert {
  border-top-color: var(--overlay-hairline-invert);
}

.tally--invert .tally__row {
  border-bottom-color: var(--overlay-hairline-invert);
}

.tally--invert .tally__label {
  color: var(--color-ink-invert-muted);
}

.tally--invert .tally__row:first-child .tally__label {
  color: var(--color-ink-invert);
}

/* --------------------------------------------------------------------------
   Feature group
   One capability area of the ecosystem: a mono heading over a bulleted list.
   -------------------------------------------------------------------------- */

.feature-group {
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
  padding: var(--space-8) var(--space-6);
  background-color: var(--color-surface-sunk);
  border-top: 3px solid var(--color-copper);
}

.feature-group__title {
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: 11px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--color-ink);
  padding-bottom: var(--space-4);
  border-bottom: 1px solid var(--color-line);
}

/* Tonal ladder across the grid — amber through copper into stone and ink.
   Positional, so the markup carries no colour. */
.grid--3 > .feature-group:nth-child(3n + 1) {
  border-top-color: var(--color-amber);
}
.grid--3 > .feature-group:nth-child(3n + 2) {
  border-top-color: var(--color-copper);
}
.grid--3 > .feature-group:nth-child(3n + 3) {
  border-top-color: var(--color-stone);
}

.feature-list {
  display: flex;
  flex-direction: column;
}

.feature-list__item {
  display: grid;
  grid-template-columns: 6px minmax(0, 1fr);
  gap: var(--space-3);
  align-items: start;
  padding-block: var(--space-2);
  font-size: 15px;
  line-height: 22px;
  color: var(--color-ink-soft);
}

.feature-list__item::before {
  content: "";
  display: block;
  width: 6px;
  height: 6px;
  margin-top: 8px;
  background-color: var(--color-copper);
}

/* --------------------------------------------------------------------------
   Emphasis list
   The PDF's recurring three-line refrains — "Faster attendance. Better
   records. Less manual work." Display-weight lines, not body copy.
   -------------------------------------------------------------------------- */

.emphasis-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}

.emphasis-list > li {
  font-family: var(--font-sans);
  font-weight: 500;
  font-size: clamp(18px, 2vw, 20px);
  line-height: 1.5;
  color: var(--color-ink);
}

.emphasis-list--accent > li {
  color: var(--color-copper-text);
}

.emphasis-list--invert > li {
  color: var(--color-ink-invert);
}

/* --------------------------------------------------------------------------
   Flow
   Enquiry → Application → Documents → Verification → Admission.
   The arrows are decorative; the steps read as a plain list to a screen
   reader, which is why the separators are aria-hidden in the markup.
   -------------------------------------------------------------------------- */

.flow {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
}

.flow__step {
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: 12px;
  line-height: 16px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-ink);
  padding: var(--space-2) var(--space-3);
  background-color: var(--color-surface-tint);
  border-bottom: 2px solid var(--color-copper);
}

.flow__arrow {
  color: var(--color-copper);
  flex-shrink: 0;
}

/* --------------------------------------------------------------------------
   Comparison
   Traditional ERP against Schoolopedia. The brand column is the dark panel
   so the contrast is carried by tone, not by a second accent colour.
   -------------------------------------------------------------------------- */

.compare {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-6);
}

.compare__col {
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
  padding: var(--space-10) var(--space-8);
  background-color: var(--color-surface-sunk);
  border-top: 3px solid var(--color-line-strong);
}

.compare__col--brand {
  background-color: var(--color-surface-dark);
  background-image: var(--dots-invert), var(--gradient-dark);
  background-repeat: no-repeat;
  background-size: cover;
  border-top-color: var(--color-amber);
}

.compare__label {
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: 10px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--color-ink-muted);
}

.compare__statement {
  font-family: var(--font-sans);
  font-weight: 500;
  font-size: clamp(20px, 2.2vw, 24px);
  line-height: 1.35;
  color: var(--color-ink);
}

.compare__list {
  display: flex;
  flex-direction: column;
  border-top: 1px solid var(--color-line);
}

.compare__list > li {
  padding-block: var(--space-3);
  border-bottom: 1px solid var(--color-line);
  font-size: 15px;
  line-height: 22px;
  color: var(--color-ink-soft);
}

.compare__col--brand .compare__label {
  color: var(--color-ink-invert-muted);
}

.compare__col--brand .compare__statement {
  color: var(--color-ink-invert);
}

.compare__col--brand .compare__list {
  border-top-color: var(--overlay-hairline-invert);
}

.compare__col--brand .compare__list > li {
  border-bottom-color: var(--overlay-hairline-invert);
  color: var(--color-ink-invert-muted);
}

/* --------------------------------------------------------------------------
   Callout
   A short, weighty aside set off from the body column.
   -------------------------------------------------------------------------- */

.callout {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  align-items: flex-start;
  width: 100%;
  padding: var(--space-8);
  background-color: var(--color-surface-sunk);
  border-left: 3px solid var(--color-copper);
}

.callout--dark {
  background-color: var(--color-surface-dark);
  background-image: var(--dots-invert), var(--gradient-dark);
  background-repeat: no-repeat;
  background-size: cover;
  border-left-color: var(--color-amber);
}

/* --------------------------------------------------------------------------
   Media
   Every photo slot in the site is this one shape. The sources are cropped to
   3:2 on disk, so object-fit only has to absorb rounding.
   -------------------------------------------------------------------------- */

.media {
  display: block;
  width: 100%;
  aspect-ratio: 3 / 2;
  object-fit: cover;
}

/* --------------------------------------------------------------------------
   Module
   The rhythm of the ecosystem page: hairline-separated rows, copy on the
   left, supporting list or flow on the right.
   -------------------------------------------------------------------------- */

.module {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: var(--space-12);
  align-items: start;
  padding-block: var(--space-12);
  border-top: 1px solid var(--color-line);
}

.module__copy,
.module__aside {
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
  align-items: flex-start;
}

/* Full-bleed transition band between two sections. This was a dune-halftone
   photograph; as a picture in the middle of the page it read as an unrelated
   image rather than a divider, so it is now a gradient that resolves to the
   exact background of the section on each side. Decorative only, no text. */
.band-fade {
  width: 100%;
  height: clamp(90px, 11vw, 150px);
  background-image: var(--gradient-band);
}

@media (max-width: 900px) {
  .compare,
  .module {
    grid-template-columns: minmax(0, 1fr);
  }

  .compare__col {
    padding: var(--space-8) var(--space-6);
  }

  .module {
    gap: var(--space-8);
    padding-block: var(--space-10);
  }

  .callout {
    padding: var(--space-6);
  }
}

/* An <address> inherits the browser's italic default. The footer address is a
   postal address, not an aside, and the rest of the footer is upright. */
address.footer__link {
  font-style: normal;
}

/* Single-column variant, for a topic list sitting in a narrow column. */
.topic-list--single {
  grid-template-columns: minmax(0, 1fr);
}

/* An FAQ answer is client-editable rich text, so it cannot carry design
   classes — HTML Purifier strips every class but .accent from it. The styling
   that .accordion__answer.text-body gave the hand-written markup is applied to
   the container's paragraphs instead, which renders identically and leaves the
   client nothing to get wrong. */
.accordion__panel-inner p {
  padding-bottom: var(--space-6);
  padding-right: var(--space-10);
  color: var(--color-ink-muted);
  font-family: var(--font-sans);
  font-weight: 400;
  font-size: 16px;
  line-height: 24px;
}
