/* ==========================================================================
   La Distinction Academy — Drupal glue
   --------------------------------------------------------------------------
   css/main.css and css/tokens.css are the design prototype, ported verbatim,
   and stay that way: they are the visual source of truth and should be updated
   from the prototype, not edited here.

   This file holds only the small adjustments Drupal's markup needs that the
   static prototype never had to account for — text-format wrappers, field and
   block containers, contextual links, and admin toolbar interaction.
   ========================================================================== */

/* --------------------------------------------------------------------------
   Announcement bar
   Editors write the message in a text format, which wraps it in its own <p>.
   Flatten that so a lead-in and the message stay on one line at bar height.
   -------------------------------------------------------------------------- */

.announce__item {
  padding-block: 0.6rem;
  font-size: var(--fs-small);
  font-weight: 600;
  letter-spacing: 0.01em;
}
.announce__item p {
  display: inline;
  padding-block: 0;
  margin: 0;
}
.announce__lead {
  margin-right: 0.25rem;
}

/* --------------------------------------------------------------------------
   Navigation
   A menu parent set to <nolink> renders as a <button> so it stays keyboard
   operable. Strip the native button chrome so it matches its <a> siblings.
   -------------------------------------------------------------------------- */

button.nav__link {
  appearance: none;
  border: 0;
  background: none;
  font: inherit;
  /* `font: inherit` resets weight; re-assert the design's 600 so Parents
     matches its <a class="nav__link"> siblings. */
  font-weight: 600;
  cursor: pointer;
  text-align: left;
}

/* --------------------------------------------------------------------------
   Blocks
   Header and footer blocks carry the design's own layout class on their block
   wrapper (`.site-logo`, `.header__cta`, `.footer-col`…), so no extra element
   sits inside the prototype's flex and grid containers. That also makes the
   block wrapper the contextual region, giving each block an edit pencil.
   -------------------------------------------------------------------------- */

/* Contextual module already sets `.contextual-region { position: relative }`,
   so this file must not repeat it. Doing so re-declared the rule *after*
   main.css and so beat the design's own positioning: the Parent Resources
   panel lost `position: fixed`, dropped into the flow, and added ~950px of
   blank space below the footer for logged-in users only.

   The panel and its backdrop stay fixed even while acting as contextual
   regions; their contextual link still anchors correctly to the fixed box. */
.resources-panel.contextual-region,
.resources-backdrop.contextual-region {
  position: fixed;
}

/* --------------------------------------------------------------------------
   Two column layout
   The prototype only ever shows this section with the image on the left, but
   the paragraph exposes an image-placement setting, so the mirrored case needs
   defining. Column widths swap with the image so the text keeps the wider side.
   -------------------------------------------------------------------------- */

.welcome--image-right .welcome__grid {
  grid-template-columns: minmax(0, 1fr) minmax(0, 0.85fr);
}
.welcome--image-right .welcome__photo {
  order: 2;
}

/* --------------------------------------------------------------------------
   Media
   A media entity renders inside an <article> wrapper the static prototype never
   had. Where the design sizes an image against its container — the hero's
   organic crop, for instance — that wrapper has to pass the height through, or
   the image's `height: 100%` resolves against an auto-height parent and the
   container shows through underneath.
   -------------------------------------------------------------------------- */

/* The design sizes these figures itself — a fixed aspect, a stretched grid
   cell, a minimum height — and expects the <img> to fill them via
   `object-fit: cover`. A media entity puts an <article> (and sometimes a
   wrapping div) between figure and image, which breaks the `height: 100%`
   chain: the image then under-fills its box or overflows it at natural size.
   Passing the size through the wrappers restores the design's crop.

   `.about-mission__photo` is deliberately absent: there the image's own aspect
   sets the row height, handled separately below. */
.hero__media > *,
.welcome__photo > *,
/* Exclude the icon badge — it sits inside __media as a sibling of the
   photo wrapper, and must stay the design's 54px circle. */
.program-card__media > *:not(.program-card__icon),
.lbc__photo > *,
.founder__photo > *,
.cta-card__media > *,
.about-hero__photo > *,
.tabs__photo > *,
.about-founder__photo > *,
.prog-banner__photo > *,
.prog-finder__photo > *,
.admit-hero__photo > *,
.community-hero__photo > *,
.event-card figure > *,
.involve-card__media > * {
  display: block;
  width: 100%;
  height: 100%;
}

/* The programme card is the one place the image is a *direct* child of a box
   sized by `aspect-ratio`. The prototype's markup carries width/height
   attributes, so its image has an intrinsic ratio and `height: 100%` resolves
   cleanly; an image-style URL has no such attributes, so `height: 100%` against
   an auto-height parent becomes cyclic and the browser falls back to the file's
   natural height — making the card 15px too tall.

   Taking the image out of flow lets `aspect-ratio` govern the box again. The
   icon badge is already absolutely positioned by the design, so it is
   unaffected. */
.program-card__media > img,
.program-card__media > .media,
.program-card__media > article {
  position: absolute;
  inset: 0;
}

/* Reassert the design's crop on the image itself, since the intermediate
   wrappers mean the original selectors no longer match as direct children. */
.hero__media img,
.welcome__photo img,
.program-card__media img,
.lbc__photo img,
.founder__photo img,
.cta-card__media img,
.about-hero__photo img,
.tabs__photo img,
.about-founder__photo img,
.prog-banner__photo img,
.prog-finder__photo img,
.admit-hero__photo img,
.community-hero__photo img,
.event-card figure img,
.involve-card__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* The design's mission photo is a portrait that sets the row height. Drupal
   serves it through an image style whose aspect may differ, so pin the shape
   here — the section then matches whatever style the site is configured to
   use. */
.about-mission__photo img {
  width: 100%;
  height: auto;
  aspect-ratio: 4 / 5;
  object-fit: cover;
}

/* The collage positions each photo absolutely inside its figure. The media
   wrappers sit between the two and break that in two ways: the inner
   `figure.media` also matches `.collage figure`, so it becomes the positioning
   context, and it has no height of its own. Removing their boxes puts the image
   back in direct contact with the collage cell it is meant to fill. */
.collage__tall > .paragraph,
.collage__wide > .paragraph,
.collage__tall > .paragraph > .media,
.collage__wide > .paragraph > .media {
  display: contents;
}

/* --------------------------------------------------------------------------
   Events listing
   The design draws the category filter as a row of pills. Those were a static
   mock-up; the real filter is a Views exposed form, which gives a working
   select plus an accessible label and degrades without JavaScript. Rather than
   fake pills around a hidden select, the form is dressed in the same pill
   language — rounded, bordered, navy on white — so it reads as part of the
   design while behaving like a real control.
   -------------------------------------------------------------------------- */

.events-listing .views-exposed-form {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: center;
  gap: 0.5rem;
  margin-bottom: 1.5rem;
}
.events-listing .views-exposed-form > * {
  display: contents;
}
.events-listing .form-item {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin: 0;
}
.events-listing .form-item__label {
  color: var(--lda-body);
  font: 600 var(--fs-xsmall) / 1.2 var(--font-sans);
  margin: 0;
}
.events-listing .form-select {
  appearance: auto;
  border: 1px solid var(--lda-border);
  background: #fff;
  color: var(--lda-navy);
  border-radius: var(--r-pill);
  padding: 0.55rem 1rem;
  font: 600 var(--fs-xsmall) / 1.2 var(--font-sans);
  cursor: pointer;
}
.events-listing .form-select:focus-visible {
  outline: 3px solid var(--lda-orange);
  outline-offset: 2px;
}
.events-listing .form-actions input[type="submit"],
.events-listing .form-actions button {
  appearance: none;
  border: 1px solid var(--lda-navy);
  background: var(--lda-navy);
  color: #fff;
  border-radius: var(--r-pill);
  padding: 0.55rem 1.25rem;
  font: 600 var(--fs-xsmall) / 1.2 var(--font-sans);
  cursor: pointer;
}
.events-listing .form-actions input[type="submit"]:hover,
.events-listing .form-actions button:hover {
  background: var(--lda-royal-blue);
  border-color: var(--lda-royal-blue);
}

/* The view's rows reuse the design's event grid. */
.events-listing .views-view .view-content,
.events-listing .view-content {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: clamp(1.25rem, 2.5vw, 1.75rem);
}

/* --------------------------------------------------------------------------
   Admin overlay
   The toolbar is fixed-position; keep the sticky header clear of it.
   -------------------------------------------------------------------------- */

body.toolbar-fixed .site-header {
  top: var(--drupal-displace-offset-top, 0);
}

/* Contextual links must not stretch the components they sit inside. */
.contextual-region > .contextual {
  position: absolute;
}

/* --------------------------------------------------------------------------
   Closing CTA (Schedule a Tour)
   The prototype card uses overflow:hidden for the photo corners, which also
   clips the white burst that should sit beside the button and bleed onto the
   navy band below. Keep the photo clipped; let the doodle escape.
   -------------------------------------------------------------------------- */

.cta-card {
  overflow: visible;
}
.cta-card__media {
  border-radius: var(--r-lg) 0 0 var(--r-lg);
  overflow: hidden;
}
.cta-card__burst {
  top: auto;
  bottom: -0.35rem;
  right: -2.35rem;
  width: 2.75rem;
  color: #fff;
}

/* --------------------------------------------------------------------------
   Simple landing-page prose (Hours of Operation, Parents hub, legal pages)
   basic_content paragraphs had no theme template, so handbook copy dumped
   raw into Layout Builder. Give it a cream card, readable measure, and a
   scannable holiday grid so it matches the rest of the site.
   -------------------------------------------------------------------------- */

/* Top padding matters where a prose card is the first thing after a hero: the
   hero closes on a wave, and with no space above it the card butts straight
   into the curve. */
.prose-page {
  padding-block: clamp(2rem, 1.2rem + 2vw, 3.5rem) 3.5rem;
}

/* The section paints the band; nothing inside it paints another full-width
   block. The card used to fill itself cream, which was fine when it was an
   inset 52rem card on a plain page — but once it filled the container and the
   section gained its own band, the result was cream on cream on the Privacy
   page and cream inside sky on the Private Area. Two tints of nearly the same
   colour, edge to edge, with a rounded corner where they met.

   The card is now a layout wrapper only. Colour comes from one place: the
   section's Background field. */
.prose-card {
  background: none;
  border-radius: 0;
  padding: 0;
}

/* The measure goes on the body as a whole, not on individual elements. Capping
   only the paragraphs and lists left the headings and their gold rules running
   the full container width while the text they introduced stopped two-thirds of
   the way across — the rule pointing at nothing. Everything now shares one
   column edge. */
.prose-card__body {
  max-width: 68ch;
}

.prose-card__title {
  margin: 0 0 1rem;
  font-size: clamp(1.35rem, 1.1rem + 0.8vw, 1.75rem);
}

.prose-card__body > *:first-child {
  margin-top: 0;
}

.prose-card__body > p:first-child {
  color: var(--lda-body-soft);
  font-size: var(--fs-small);
  margin-bottom: 1.5rem;
}

.prose-card__body h2 {
  margin: 1.75rem 0 0.65rem;
  font-size: clamp(1.15rem, 1rem + 0.45vw, 1.35rem);
  padding-bottom: 0.35rem;
  border-bottom: 2px solid var(--lda-gold);
}

.prose-card__body h2:first-child {
  margin-top: 0;
}

.prose-card__body p {
  margin: 0 0 0.65rem;
  max-width: 62ch;
  color: var(--lda-body);
  line-height: 1.6;
}

.prose-card__body ul {
  list-style: none;
  margin: 0.35rem 0 1rem;
  padding: 0;
  display: grid;
  gap: 0.45rem;
}

/* Holiday lists (and any longer list) read better as two columns. */
.prose-card__body ul:has(> li:nth-child(6)) {
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.4rem 1.25rem;
}

.prose-card__body li {
  position: relative;
  padding: 0.55rem 0.75rem 0.55rem 1.85rem;
  /* Solid white with a hairline, so a list item reads the same on the cream
     band, the sky band and the plain page. A translucent wash took on whatever
     was behind it and vanished into it. */
  background: var(--lda-white);
  border: 1px solid var(--lda-border);
  border-radius: var(--r-md);
  font-size: var(--fs-small);
  color: var(--lda-body);
  line-height: 1.45;
}

.prose-card__body li::before {
  content: "";
  position: absolute;
  left: 0.7rem;
  top: 0.9rem;
  width: 0.45rem;
  height: 0.45rem;
  border-radius: 50%;
  background: var(--lda-gold);
}

.prose-card__body em {
  color: var(--lda-body-soft);
  font-size: var(--fs-small);
}

.prose-card__body a {
  color: var(--lda-royal-blue);
  font-weight: 600;
  text-decoration: underline;
  text-underline-offset: 0.15em;
}

.prose-card__body a:hover {
  color: var(--lda-orange);
}

/* Final contact line — a soft callout. White with a gold edge rather than the
   sky tint it used to carry, which disappeared whenever the section itself was
   banded sky. */
.prose-card__body > p:last-child {
  margin: 1.5rem 0 0;
  padding: 0.9rem 1rem;
  max-width: none;
  border: 1px solid var(--lda-border);
  border-left: 4px solid var(--lda-gold);
  border-radius: var(--r-md);
  background: var(--lda-white);
  font-weight: 600;
}

/* A hero with no photograph should not keep the photo's column — but the
   container must still be the container. Capping the grid itself at 40rem was
   capping `.container`, so the whole hero (and everything measuring itself
   against it) shrank to 640px and floated in the middle of the page. The cap
   belongs on the copy. */
.admit-hero__grid:not(:has(.admit-hero__photo)),
.community-hero__grid:not(:has(.community-hero__photo)) {
  grid-template-columns: minmax(0, 1fr);
}
.admit-hero__grid:not(:has(.admit-hero__photo)) .admit-hero__copy,
.community-hero__grid:not(:has(.community-hero__photo)) .community-hero__copy {
  max-width: 46rem;
}

@media (max-width: 700px) {
  .prose-card__body ul:has(> li:nth-child(6)) {
    grid-template-columns: 1fr;
  }
}

/* --------------------------------------------------------------------------
   Private Area password gate (protected_pages login form)
   -------------------------------------------------------------------------- */

.private-gate,
form.private-gate {
  display: block;
  max-width: 28rem;
  margin: 3rem auto 4rem;
}

.private-gate .protected_pages_description,
.private-gate .protected_pages_description strong {
  display: block;
  font-weight: 500;
  color: var(--lda-body-soft);
  font-size: var(--fs-small);
  line-height: 1.55;
  margin-bottom: 1.25rem;
}

.private-gate .form-item {
  margin-bottom: 1rem;
}

.private-gate label {
  font-weight: 600;
  color: var(--lda-navy);
}

.private-gate input[type="password"] {
  width: 100%;
  padding: 0.7rem 0.85rem;
  border: 1px solid var(--lda-border);
  border-radius: var(--r-md);
  font: inherit;
  background: #fff;
}

.private-gate input[type="password"]:focus {
  outline: 2px solid var(--lda-gold);
  outline-offset: 1px;
}

.private-gate .btn,
.private-gate .button {
  margin-top: 0.35rem;
}

.private-gate legend {
  font-weight: 700;
  color: var(--lda-navy);
  font-size: 1.1rem;
  padding: 0;
}

.private-gate fieldset {
  border: 0;
  margin: 0;
  padding: 0;
  min-inline-size: 0;
}

/* ---- Downloadable gallery pack (cover + ZIP) ---------------------------- */

.gallery-pack {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1.25rem;
  max-width: 36rem;
  margin: 0 auto;
}

.gallery-pack__cover {
  margin: 0;
  width: 100%;
  border-radius: var(--r-md, 0.75rem);
  overflow: hidden;
}

.gallery-pack__cover img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 3 / 2;
  object-fit: cover;
}

.gallery-pack__download {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
}

/* --------------------------------------------------------------------------
   Event detail page
   The prototype has no event page, so this composes the design's existing
   pieces: the two-column rhythm of the programme finder, the card language of
   the event grid, and the site's button styles for Commerce's add-to-cart form.
   -------------------------------------------------------------------------- */

.event-detail__grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: clamp(1.5rem, 3.5vw, 3rem);
  align-items: start;
}

.event-detail__photo {
  margin: 0;
  border-radius: var(--r-xl);
  overflow: hidden;
  aspect-ratio: 4 / 5;
}
.event-detail__photo > *,
.event-detail__photo img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.event-detail__copy h1 {
  font-size: var(--fs-h2);
  margin-top: 0.6rem;
}
.event-detail__price {
  margin-top: 0.5rem;
  color: var(--lda-royal-blue);
  font-size: 1.25rem;
  font-weight: 700;
}
.event-detail .event-meta {
  margin-top: 1rem;
}
.event-detail .event-meta li {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}
.event-detail .event-meta svg {
  flex: none;
  color: var(--lda-gold);
}
.event-detail__body {
  margin-top: 1.1rem;
}
.event-detail__body p {
  margin-bottom: 0.75rem;
}
.event-detail__body ul {
  margin: 0.5rem 0 0.75rem;
  padding-left: 1.1rem;
  list-style: disc;
}

/* Commerce add-to-cart, dressed in the site's own controls. */
.event-detail__buy {
  margin-top: 1.5rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--lda-border);
}
/* Drop the field chrome the page already states above. The variation *title*
   is hidden here rather than removed from its display, because the cart lists
   items by rendering that same title — hiding it there blanked every cart row.
   The price stays: it sits inside the region Commerce refreshes over AJAX, so
   it is the visible confirmation that changing the ticket type did something. */
.event-detail__buy .field__label,
.event-detail__buy .field--name-title,
.event-detail__buy .product__title {
  display: none;
}
.event-detail__buy .field--name-price {
  order: -1;
  margin-bottom: 1rem;
  color: var(--lda-royal-blue);
  font: 700 1.5rem / 1.2 var(--font-sans);
}
.event-detail__buy {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
}
.event-detail__buy fieldset {
  border: 0;
  padding: 0;
  margin: 0 0 1.25rem;
}
.event-detail__buy legend {
  padding: 0;
  margin-bottom: 0.5rem;
}
.event-detail__buy .fieldset-legend {
  color: var(--lda-navy);
  font: 600 var(--fs-small) / 1.2 var(--font-sans);
}
.event-detail__buy .form-item {
  margin: 0 0 1rem;
}
.event-detail__buy label {
  display: block;
  margin-bottom: 0.4rem;
  color: var(--lda-navy);
  font: 600 var(--fs-small) / 1.2 var(--font-sans);
}
.event-detail__buy .form-select,
.event-detail__buy input[type="number"] {
  border: 1px solid var(--lda-border);
  border-radius: var(--r-md);
  background: #fff;
  color: var(--lda-navy);
  padding: 0.6rem 0.9rem;
  font: 500 var(--fs-small) / 1.2 var(--font-sans);
  min-width: 8rem;
}
.event-detail__buy .form-radios {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}
.event-detail__buy .form-type-radio {
  margin: 0;
}
.event-detail__buy .form-type-radio label {
  border: 1px solid var(--lda-border);
  border-radius: var(--r-pill);
  padding: 0.5rem 1rem;
  cursor: pointer;
  margin: 0;
}
.event-detail__buy input[type="radio"]:checked + label {
  background: var(--lda-navy);
  border-color: var(--lda-navy);
  color: #fff;
}
.event-detail__buy input[type="submit"],
.event-detail__buy button[type="submit"] {
  appearance: none;
  border: 0;
  border-radius: var(--r-pill);
  background: var(--lda-navy);
  color: #fff;
  padding: 0.85rem 1.75rem;
  font: 700 var(--fs-small) / 1.2 var(--font-sans);
  cursor: pointer;
}
.event-detail__buy input[type="submit"]:hover,
.event-detail__buy button[type="submit"]:hover {
  background: var(--lda-royal-blue);
}

.event-detail__buy .commerce-order-item-add-to-cart-form {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  width: 100%;
}
.event-detail__buy .form-actions {
  margin: 0;
}

@media (max-width: 860px) {
  .event-detail__grid { grid-template-columns: 1fr; }
}

/* Sold-out state and the forms that replace the ticket picker. */
.event-detail__soldout {
  color: var(--lda-navy);
  font: 700 1.125rem / 1.3 var(--font-sans);
  margin-bottom: 0.35rem;
}
.event-detail__places {
  display: inline-block;
  margin-bottom: 0.9rem;
  padding: 0.35rem 0.8rem;
  border-radius: var(--r-pill);
  background: var(--lda-cream);
  color: var(--lda-navy);
  font: 600 var(--fs-xsmall) / 1.2 var(--font-sans);
}
.event-detail__buy .webform-submission-form {
  margin-top: 1rem;
}
.event-detail__buy .webform-submission-form .form-item {
  margin-bottom: 0.9rem;
}
.event-detail__buy .webform-submission-form input[type="text"],
.event-detail__buy .webform-submission-form input[type="email"],
.event-detail__buy .webform-submission-form input[type="tel"],
.event-detail__buy .webform-submission-form input[type="number"],
.event-detail__buy .webform-submission-form textarea {
  width: 100%;
  border: 1px solid var(--lda-border);
  border-radius: var(--r-md);
  padding: 0.6rem 0.9rem;
  font: 500 var(--fs-small) / 1.4 var(--font-sans);
  color: var(--lda-navy);
  background: #fff;
}

/* --------------------------------------------------------------------------
   Shop
   The prototype has no shop, so the catalogue borrows the design's card
   language — cream body, gold rim on hover, navy type — rather than inventing
   a new one.
   -------------------------------------------------------------------------- */

.view-shop .view-content {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: clamp(1.25rem, 2.5vw, 1.75rem);
}

.shop-card {
  border: 1px solid var(--lda-border);
  border-radius: var(--r-lg);
  overflow: hidden;
  background: #fff;
  transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
.shop-card:hover {
  border-color: var(--lda-gold);
  box-shadow: var(--shadow-lift);
}
.shop-card__link {
  display: block;
  color: inherit;
}
.shop-card__media {
  position: relative;
  aspect-ratio: 1 / 1;
  background: var(--lda-page);
}
.shop-card__media > *,
.shop-card__media img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.shop-card__placeholder {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  color: var(--lda-gold-soft);
}
.shop-card__placeholder svg {
  width: 40px;
  height: 40px;
}
.shop-card__body {
  padding: 0.9rem 1rem 1.1rem;
  background: var(--lda-cream-deep);
}
.shop-card__body h3 {
  font-size: 1rem;
  line-height: 1.3;
}
.shop-card__price {
  margin-top: 0.35rem;
  color: var(--lda-royal-blue);
  font: 700 var(--fs-small) / 1.2 var(--font-sans);
}

/* Product page: reuse the event detail rhythm. */
.commerce-product-full .field--name-field-image {
  border-radius: var(--r-xl);
  overflow: hidden;
}

/* Cards in a shop row stretch to the tallest, so titles of different lengths
   still line their prices up. */
.view-shop .view-content > * { display: flex; }
.shop-card { display: flex; flex-direction: column; width: 100%; }
.shop-card__link { display: flex; flex-direction: column; flex: 1; }
.shop-card__body { flex: 1; }

/* Header cart: a round control matching the Parent Resources button, with the
   item count as a badge. Hidden entirely when empty — see
   commerce-cart-block.html.twig. */
.header__cart {
  position: relative;
  text-decoration: none;
}
.header__cart-count {
  position: absolute;
  top: -4px;
  right: -4px;
  min-width: 20px;
  height: 20px;
  padding: 0 5px;
  display: grid;
  place-items: center;
  border-radius: var(--r-pill);
  background: var(--lda-orange);
  color: #fff;
  font: 700 0.6875rem / 1 var(--font-sans);
}

/* --------------------------------------------------------------------------
   Product page and cart
   Commerce ships admin-flavoured markup for both. These bring them into the
   site's language: the product page mirrors the event page's two columns, and
   the cart becomes a readable table with the site's buttons.
   -------------------------------------------------------------------------- */

.product-detail__grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: clamp(1.5rem, 3.5vw, 3rem);
  align-items: start;
}
.product-detail__photo {
  position: relative;
  margin: 0;
  border-radius: var(--r-xl);
  overflow: hidden;
  aspect-ratio: 1 / 1;
  background: var(--lda-page);
}
.product-detail__photo > *,
.product-detail__photo img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.product-detail__placeholder {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  color: var(--lda-gold-soft);
}
.product-detail__placeholder svg { width: 64px; height: 64px; }

.product-detail__copy h1 { font-size: var(--fs-h2); }
.product-detail__body { margin-top: 1rem; }
.product-detail__body p { margin-bottom: 0.75rem; }

.product-detail__buy {
  margin-top: 1.5rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--lda-border);
  display: flex;
  flex-direction: column;
  align-items: flex-start;
}
.product-detail__buy .field__label,
.product-detail__buy .field--name-title,
/* Commerce injects the variation's fields with generated class names; the
   title among them repeats the H1 beside the photo. */
.product-detail__buy [class*="variation_title"],
.event-detail__buy [class*="variation_title"] {
  display: none;
}
.product-detail__buy .field--name-price {
  order: -1;
  margin-bottom: 1rem;
  color: var(--lda-royal-blue);
  font: 700 1.5rem / 1.2 var(--font-sans);
}
.product-detail__buy .field--name-list-price {
  order: -1;
  margin-bottom: 0.2rem;
  color: var(--lda-body-soft);
  text-decoration: line-through;
}
.product-detail__buy label {
  display: block;
  margin-bottom: 0.4rem;
  color: var(--lda-navy);
  font: 600 var(--fs-small) / 1.2 var(--font-sans);
}
.product-detail__buy .form-select,
.product-detail__buy input[type="number"] {
  border: 1px solid var(--lda-border);
  border-radius: var(--r-md);
  background: #fff;
  color: var(--lda-navy);
  padding: 0.6rem 0.9rem;
  font: 500 var(--fs-small) / 1.2 var(--font-sans);
  min-width: 12rem;
}
.product-detail__buy .form-item { margin: 0 0 1rem; }
.product-detail__buy input[type="submit"] {
  appearance: none;
  border: 0;
  border-radius: var(--r-pill);
  background: var(--lda-navy);
  color: #fff;
  padding: 0.85rem 1.75rem;
  font: 700 var(--fs-small) / 1.2 var(--font-sans);
  cursor: pointer;
}
.product-detail__buy input[type="submit"]:hover { background: var(--lda-royal-blue); }

/* Cart ---------------------------------------------------------------- */
.view-commerce-cart-form { margin-block: 1.5rem; }
.view-commerce-cart-form table {
  width: 100%;
  border-collapse: collapse;
}
.view-commerce-cart-form th {
  text-align: left;
  padding: 0.75rem 0.9rem;
  border-bottom: 2px solid var(--lda-border);
  color: var(--lda-navy);
  font: 700 var(--fs-small) / 1.2 var(--font-sans);
}
.view-commerce-cart-form td {
  padding: 0.9rem;
  border-bottom: 1px solid var(--lda-border);
  vertical-align: middle;
}
.view-commerce-cart-form .views-field-edit-quantity input {
  width: 5rem;
  border: 1px solid var(--lda-border);
  border-radius: var(--r-md);
  padding: 0.45rem 0.6rem;
}
.view-commerce-cart-form .views-field-remove-button input,
.cart-block--offcanvas-contents__links a {
  appearance: none;
  border: 1px solid var(--lda-border);
  border-radius: var(--r-pill);
  background: #fff;
  color: var(--lda-navy);
  padding: 0.45rem 1rem;
  font: 600 var(--fs-xsmall) / 1.2 var(--font-sans);
  cursor: pointer;
}
.commerce-order--edit-form .form-actions,
.view-commerce-cart-form .form-actions {
  display: flex;
  gap: 0.75rem;
  justify-content: flex-end;
  margin-top: 1.25rem;
}
.view-commerce-cart-form .form-actions input[type="submit"] {
  appearance: none;
  border: 1px solid var(--lda-navy);
  border-radius: var(--r-pill);
  background: #fff;
  color: var(--lda-navy);
  padding: 0.75rem 1.5rem;
  font: 700 var(--fs-small) / 1.2 var(--font-sans);
  cursor: pointer;
}
/* Checkout is the primary action. */
.view-commerce-cart-form .form-actions input[value="Checkout"],
.view-commerce-cart-form .form-actions #edit-checkout {
  background: var(--lda-navy);
  color: #fff;
}
.order-total-line {
  display: flex;
  justify-content: flex-end;
  gap: 1.5rem;
  padding: 0.35rem 0.9rem;
  color: var(--lda-navy);
}
.order-total-line--total {
  font: 700 1.125rem / 1.2 var(--font-sans);
  border-top: 2px solid var(--lda-border);
  padding-top: 0.75rem;
  margin-top: 0.35rem;
}

/* Commerce and Views pages have no paragraph to supply the design's container,
   so they would run edge to edge. Constrain them to the same measure. */
.view-commerce-cart-form,
.commerce-checkout-flow,
.checkout-pane,
.commerce-order-receipt,
.view-shop > .view-header,
.page-shop-empty {
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: var(--container-pad);
}

/* Cart line item: photo beside a linked name. */
.cart-item {
  display: flex;
  align-items: center;
  gap: 0.9rem;
}
.cart-item__media {
  flex: none;
  width: 64px;
  height: 64px;
  border-radius: var(--r-md);
  overflow: hidden;
  background: var(--lda-page);
}
.cart-item__media img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.cart-item__name a {
  color: var(--lda-navy);
  font-weight: 600;
}
.cart-item__name a:hover { color: var(--lda-orange); }

/* Ticket cards in the shop are tagged so they read differently from goods. */
.shop-card__tag {
  display: inline-block;
  margin-bottom: 0.35rem;
  padding: 0.15rem 0.55rem;
  border-radius: var(--r-pill);
  background: var(--lda-navy);
  color: #fff;
  font: 700 0.625rem / 1.4 var(--font-sans);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.product-detail__price {
  margin-top: 0.5rem;
  color: var(--lda-royal-blue);
  font: 700 1.5rem / 1.2 var(--font-sans);
}

/* --------------------------------------------------------------------------
   Empty cart
   Commerce prints a bare sentence with no container. Give it the site's
   breathing room and a way onward, so it is not a dead end.
   -------------------------------------------------------------------------- */

.cart-empty {
  padding-block: clamp(2.5rem, 5vw, 4.5rem);
}
.cart-empty__inner {
  max-width: 40rem;
  text-align: center;
}
.cart-empty__icon {
  display: inline-grid;
  place-items: center;
  width: 72px;
  height: 72px;
  margin-bottom: 1.1rem;
  border-radius: 50%;
  border: 1px solid var(--lda-border);
  background: var(--lda-cream);
  color: var(--lda-gold);
}
.cart-empty__icon svg { width: 32px; height: 32px; }
.cart-empty h2 { font-size: var(--fs-h3); }
.cart-empty p {
  margin-top: 0.6rem;
  color: var(--lda-body);
}
.cart-empty__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  justify-content: center;
  margin-top: 1.5rem;
}

/* --------------------------------------------------------------------------
   Testimonials
   Past three, the quotes become a slider paging three at a time. The design's
   grid is three across, so a fourth card would otherwise sit alone on a second
   row and read as a mistake.
   -------------------------------------------------------------------------- */

.quote-slider .slider__track {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: calc((100% - 2 * var(--gap)) / 3);
  gap: var(--gap);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  scrollbar-width: none;
  padding-block: 0.25rem;
}
.quote-slider .slider__track::-webkit-scrollbar { display: none; }
.quote-slide {
  scroll-snap-align: start;
  display: flex;
}
.quote-slide > * { width: 100%; }

@media (max-width: 900px) {
  .quote-slider .slider__track { grid-auto-columns: calc((100% - var(--gap)) / 2); }
}
@media (max-width: 620px) {
  .quote-slider .slider__track { grid-auto-columns: 100%; }
}

/* Quote card details ---------------------------------------------------- */
.quote-card blockquote p { margin: 0; }
.quote-card blockquote p + p { margin-top: 0.6rem; }

.quote-card__by {
  display: flex;
  align-items: center;
  gap: 0.65rem;
  margin-top: auto;
  padding-top: 1rem;
}
.quote-card__avatar {
  flex: none;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  overflow: hidden;
  background: var(--lda-cream);
}
.quote-card__avatar img,
.quote-card__avatar > * {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.quote-card__who {
  display: flex;
  flex-direction: column;
  line-height: 1.3;
}
.quote-card__source {
  color: var(--lda-body-soft);
  font-size: var(--fs-xsmall);
  font-style: normal;
}

/* --------------------------------------------------------------------------
   Inner page heroes
   The home hero's photo is a large organic crop with a navy wash over it. The
   inner pages shipped as plain rounded rectangles, so they read as a different
   site. These give them the same treatment at a smaller scale: a softened
   organic corner, a tint, and a cap on height so the photo supports the copy
   rather than dominating it.
   -------------------------------------------------------------------------- */

.admit-hero__photo,
.community-hero__photo,
.about-hero__photo {
  position: relative;
  max-height: 420px;
  /* Organic shape: one deep corner, echoing the home hero's crop. */
  border-radius: var(--r-xl) var(--r-xl) 88px var(--r-xl);
  overflow: hidden;
}

.about-hero__photo {
  max-height: 340px;
}

/* The wash keeps white copy legible where it overlaps and ties the photo to
   the navy band below. `pointer-events: none` so it never blocks a link. */
.admit-hero__photo::after,
.community-hero__photo::after,
.about-hero__photo::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(
    115deg,
    rgba(21, 57, 95, 0.26) 0%,
    rgba(21, 57, 95, 0.10) 45%,
    rgba(12, 28, 48, 0.34) 100%
  );
}

/* A gold hairline picks up the crest colour, as the home hero's wave does. */
.admit-hero__photo,
.community-hero__photo {
  box-shadow: 0 0 0 1px var(--lda-gold-soft), var(--shadow-lift);
}

@media (max-width: 860px) {
  .admit-hero__photo,
  .community-hero__photo,
  .about-hero__photo {
    max-height: 280px;
    border-radius: var(--r-lg) var(--r-lg) 56px var(--r-lg);
  }
}

/* Back link above the heading on event and product pages, replacing the
   breadcrumb that was removed. */
.event-detail__back,
.product-detail__back {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  margin-bottom: 0.75rem;
  font-size: var(--fs-small);
}
.event-detail__back svg,
.product-detail__back svg {
  width: 16px;
  height: 16px;
}

/* ==========================================================================
   System messages
   Olivero's messages are inherited otherwise: edge to edge, in their own
   palette. These sit inside the page container and use the brand's colours.
   ========================================================================== */

.lda-messages {
  margin: 1.5rem 0;
}
.lda-messages__inner {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.lda-message {
  --msg-accent: var(--lda-royal-blue);
  --msg-tint: var(--lda-sky);
  border: 1px solid var(--lda-border);
  border-left: 4px solid var(--msg-accent);
  border-radius: var(--r-md);
  background: var(--msg-tint);
  box-shadow: var(--shadow-card);
}
.lda-message__container {
  display: flex;
  align-items: flex-start;
  gap: 0.85rem;
  padding: 1rem 1.15rem;
}

.lda-message__icon {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 26px;
  height: 26px;
  border-radius: var(--r-pill);
  background: var(--msg-accent);
  color: var(--lda-white);
}
.lda-message__icon svg {
  width: 17px;
  height: 17px;
}

.lda-message__content {
  min-width: 0;
  color: var(--lda-navy);
  font-size: var(--fs-small);
  line-height: var(--lh-snug);
}
.lda-message__content a {
  color: var(--msg-accent);
  font-weight: 600;
}
.lda-message__content p {
  margin: 0 0 0.4rem;
}
.lda-message__content p:last-child {
  margin-bottom: 0;
}
.lda-message__list {
  margin: 0;
  padding-left: 1.1rem;
}
.lda-message__list li + li {
  margin-top: 0.3rem;
}

/* One accent colour per type. Success is green because no brand colour reads
   as "that worked"; the other three are the design's own. */
.lda-message--status {
  --msg-accent: #1E7F52;
  --msg-tint: #EFF9F3;
}
.lda-message--error {
  --msg-accent: #C0392B;
  --msg-tint: #FDF1EF;
}
.lda-message--warning {
  --msg-accent: var(--lda-orange);
  --msg-tint: var(--lda-cream);
}
.lda-message--info {
  --msg-accent: var(--lda-royal-blue);
  --msg-tint: var(--lda-sky);
}

/* Inline form errors, which Drupal prints inside the form rather than here. */
.form-item--error-message {
  margin-top: 0.35rem;
  color: #C0392B;
  font-size: var(--fs-xsmall);
  font-weight: 600;
}
.form-item input.error,
.form-item select.error,
.form-item textarea.error,
input.error,
select.error,
textarea.error {
  border-color: #C0392B !important;
  box-shadow: 0 0 0 3px rgba(192, 57, 43, 0.12);
}

/* ==========================================================================
   Embedded webforms (the Form paragraph)
   The prototype has no forms, so this is new work in the design's language:
   a cream panel with the same radius, borders and focus ring as the cards.
   ========================================================================== */

.form-panel {
  padding: clamp(1.5rem, 1rem + 2vw, 2.5rem);
  border: 1px solid var(--lda-border);
  border-radius: var(--r-xl);
  background: var(--lda-white);
  box-shadow: var(--shadow-card);
}
.form-panel__head {
  margin-bottom: 1.5rem;
  text-align: center;
}
.form-panel__head h2 {
  margin: 0 0 0.5rem;
}
.form-panel__head p:last-child {
  margin-bottom: 0;
}

.form-panel .form-item {
  margin: 0 0 1.15rem;
}
.form-panel label {
  display: block;
  margin-bottom: 0.35rem;
  color: var(--lda-navy);
  font-weight: 600;
  font-size: var(--fs-small);
}
.form-panel .description,
.form-panel .form-item__description,
.form-panel .webform-element-description {
  margin-top: 0.3rem;
  color: var(--lda-body-soft);
  font-size: var(--fs-xsmall);
  line-height: var(--lh-snug);
}

.form-panel input[type="text"],
.form-panel input[type="email"],
.form-panel input[type="tel"],
.form-panel input[type="number"],
.form-panel input[type="date"],
.form-panel input[type="time"],
.form-panel select,
.form-panel textarea {
  width: 100%;
  padding: 0.7rem 0.9rem;
  border: 1px solid var(--lda-border);
  border-radius: var(--r-sm);
  background: var(--lda-white);
  color: var(--lda-navy);
  font: inherit;
  font-size: var(--fs-body);
}
.form-panel input:focus-visible,
.form-panel select:focus-visible,
.form-panel textarea:focus-visible {
  outline: none;
  border-color: var(--lda-royal-blue);
  box-shadow: 0 0 0 3px rgba(7, 62, 152, 0.14);
}
.form-panel textarea {
  min-height: 8rem;
  resize: vertical;
}

/* The tour fields, which appear and disappear with the reason select. */
.form-panel fieldset {
  margin: 0 0 1.15rem;
  padding: 1.15rem;
  border: 1px solid var(--lda-border);
  border-radius: var(--r-md);
  background: var(--lda-cream);
}
.form-panel legend {
  padding: 0 0.4rem;
  color: var(--lda-navy);
  font-weight: 700;
  font-size: var(--fs-body);
}
.form-panel fieldset .form-item:last-child {
  margin-bottom: 0;
}

.form-panel .form-actions {
  margin-top: 1.5rem;
  text-align: center;
}
.form-panel .form-actions input[type="submit"],
.form-panel .form-actions button {
  padding: 0.8rem 2rem;
  border: 0;
  border-radius: var(--r-pill);
  background: var(--lda-orange);
  color: var(--lda-white);
  font: inherit;
  font-weight: 700;
  cursor: pointer;
  transition: background 0.2s ease, transform 0.2s ease;
}
.form-panel .form-actions input[type="submit"]:hover,
.form-panel .form-actions button:hover {
  background: var(--lda-royal-blue);
  transform: translateY(-1px);
}

/* Webform prints its confirmation in place of the form. */
.form-panel .webform-confirmation {
  text-align: center;
}

/* The About hero's panel is a three-column grid — children, copy, photo — and
   both the children and the photo are now optional. Drop the columns that have
   nothing in them, or the copy is squeezed against an empty 10.5rem gutter. */
.about-hero__panel--no-art {
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr);
}
.about-hero__panel--no-photo {
  grid-template-columns: 10.5rem minmax(0, 1fr);
}
.about-hero__panel--no-art.about-hero__panel--no-photo {
  grid-template-columns: minmax(0, 1fr);
  max-width: 42rem;
}

/* ==========================================================================
   Time picker (jquery.timepicker, used by the tour form's Preferred time)
   The plugin appends its list to <body>, outside .form-panel, so these cannot
   be nested under the panel.
   ========================================================================== */

.ui-timepicker-wrapper {
  z-index: 1200;
  max-height: 15rem;
  border: 1px solid var(--lda-border);
  border-radius: var(--r-md);
  background: var(--lda-white);
  box-shadow: var(--shadow-lift);
  outline: none;
  overflow-x: hidden;
  overflow-y: auto;
}

.ui-timepicker-list {
  margin: 0;
  padding: 0.35rem;
  list-style: none;
}

.ui-timepicker-list li {
  padding: 0.5rem 0.75rem;
  border-radius: var(--r-sm);
  color: var(--lda-navy);
  font-size: var(--fs-small);
  font-weight: 600;
  line-height: 1.2;
  white-space: nowrap;
  cursor: pointer;
}

.ui-timepicker-list li:hover,
.ui-timepicker-list li.ui-timepicker-selected,
.ui-timepicker-list .ui-timepicker-selected:hover {
  background: var(--lda-sky);
  color: var(--lda-royal-blue);
}

/* Slots the notice period has already ruled out. The plugin keeps them in the
   list rather than removing them, which is worth preserving — it shows that
   the school does open then, just not soon enough. */
.ui-timepicker-list li.ui-timepicker-disabled,
.ui-timepicker-list li.ui-timepicker-disabled:hover,
.ui-timepicker-list li.ui-timepicker-disabled.ui-timepicker-selected {
  background: transparent;
  color: var(--lda-body-soft);
  opacity: 0.45;
  cursor: not-allowed;
}

/* Shown when the notice period has used up everything left of today. */
.form-panel__slot-note {
  margin: 0.4rem 0 0;
  color: var(--lda-orange);
  font-size: var(--fs-xsmall);
  font-weight: 600;
}

/* ==========================================================================
   Contact page
   Contact cards, the map and the FAQ list. None of these appear in the
   prototype, so they are built from the design's tokens rather than ported.
   ========================================================================== */

.contact-cards__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  gap: var(--gap);
}

.contact-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.4rem;
  padding: 1.75rem 1.25rem;
  border: 1px solid var(--lda-border);
  border-radius: var(--r-lg);
  background: var(--lda-white);
  box-shadow: var(--shadow-card);
  text-align: center;
  transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.contact-card:hover {
  transform: translateY(-2px);
  box-shadow: var(--shadow-lift);
}

.contact-card__icon {
  display: grid;
  place-items: center;
  width: 3rem;
  height: 3rem;
  margin-bottom: 0.35rem;
  border-radius: var(--r-pill);
  background: var(--lda-sky);
  color: var(--lda-royal-blue);
}
.contact-card__icon svg {
  width: 24px;
  height: 24px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
}

.contact-card__label {
  margin: 0;
  color: var(--lda-body-soft);
  font-size: var(--fs-eyebrow);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.contact-card__value {
  color: var(--lda-navy);
  font-size: var(--fs-h3);
  font-weight: 700;
  line-height: var(--lh-snug);
  text-decoration: none;
}
.contact-card__value:hover {
  color: var(--lda-royal-blue);
  text-decoration: underline;
}

.contact-card p {
  margin: 0;
  color: var(--lda-body-soft);
  font-size: var(--fs-small);
}

/* The map. A fixed aspect keeps the frame from collapsing before it loads. */
.map-section__frame {
  aspect-ratio: 16 / 7;
  border: 1px solid var(--lda-border);
  border-radius: var(--r-xl);
  background: var(--lda-sky);
  overflow: hidden;
}
.map-section__frame iframe {
  display: block;
  width: 100%;
  height: 100%;
  border: 0;
}

.map-section__address {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.5rem 1rem;
  margin: 1rem 0 0;
  color: var(--lda-navy);
  font-weight: 600;
}
.map-section__pin {
  width: 20px;
  height: 20px;
  flex: none;
  fill: none;
  stroke: var(--lda-orange);
  stroke-width: 1.8;
}
.map-section__address .link-arrow {
  margin-left: auto;
}

@media (max-width: 640px) {
  .map-section__frame {
    aspect-ratio: 4 / 3;
  }
  .map-section__address .link-arrow {
    margin-left: 0;
  }
}

/* Directions from nearby towns, below the map. */
.routes {
  margin-top: 2.25rem;
}
.routes__title {
  margin: 0 0 1.25rem;
  text-align: center;
}
.routes__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  gap: var(--gap);
}

.route-card {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  padding: 1.25rem;
  border: 1px solid var(--lda-border);
  border-radius: var(--r-lg);
  background: var(--lda-cream);
}

.route-card__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 0.35rem 0.75rem;
}
.route-card__from {
  margin: 0;
  color: var(--lda-navy);
  font-size: var(--fs-body);
  font-weight: 700;
}
.route-card__time {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  margin: 0;
  color: var(--lda-body-soft);
  font-size: var(--fs-xsmall);
  font-weight: 600;
}
.route-card__time svg {
  width: 15px;
  height: 15px;
  flex: none;
  fill: none;
  stroke: var(--lda-orange);
  stroke-width: 1.8;
}

.route-card p {
  margin: 0;
  color: var(--lda-body);
  font-size: var(--fs-small);
  line-height: var(--lh-snug);
}

/* Pushed to the bottom so the links line up across cards of unequal copy. */
.route-card__link {
  margin-top: auto;
  padding-top: 0.35rem;
  font-size: var(--fs-small);
}

/* ==========================================================================
   Product photo gallery
   ========================================================================== */

.product-gallery__stage {
  position: relative;
  aspect-ratio: 1 / 1;
  border-radius: var(--r-xl);
  background: var(--lda-cream);
  overflow: hidden;
}
.product-gallery__slide {
  position: absolute;
  inset: 0;
  margin: 0;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.25s ease;
}
.product-gallery__slide.is-active {
  opacity: 1;
  visibility: visible;
}
.product-gallery__slide > *,
.product-gallery__slide img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Thumbnails scroll rather than wrap, so a product with eight photos does not
   push the price down the page. */
.product-gallery__thumbs {
  display: flex;
  gap: 0.6rem;
  margin-top: 0.75rem;
  padding-bottom: 0.25rem;
  overflow-x: auto;
  scroll-snap-type: x proximity;
  scrollbar-width: thin;
}
.product-gallery__thumb {
  flex: 0 0 4.5rem;
  width: 4.5rem;
  height: 4.5rem;
  padding: 0;
  border: 2px solid transparent;
  border-radius: var(--r-md);
  background: var(--lda-cream);
  scroll-snap-align: start;
  cursor: pointer;
  overflow: hidden;
  transition: border-color 0.2s ease, transform 0.2s ease;
}
.product-gallery__thumb:hover {
  transform: translateY(-2px);
}
.product-gallery__thumb.is-active {
  border-color: var(--lda-royal-blue);
}
.product-gallery__thumb:focus-visible {
  outline: none;
  border-color: var(--lda-orange);
  box-shadow: 0 0 0 3px rgba(237, 133, 0, 0.2);
}
.product-gallery__thumb > *,
.product-gallery__thumb img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* ==========================================================================
   Purchased downloads, on the thank-you page
   The same markup goes out in the receipt email, where none of this is
   available — so the template stays legible without it.
   ========================================================================== */

.lda-downloads {
  margin: 1.25rem 0;
  padding: 1.25rem;
  border: 1px solid var(--lda-border);
  border-radius: var(--r-lg);
  background: var(--lda-cream);
}
.lda-downloads__title {
  margin: 0 0 0.85rem;
  font-size: var(--fs-h3);
}
.lda-downloads__list {
  margin: 0;
  padding: 0;
  list-style: none;
}
.lda-downloads__item + .lda-downloads__item {
  margin-top: 1rem;
  padding-top: 1rem;
  border-top: 1px solid var(--lda-border);
}

.lda-downloads__link {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.7rem 1.25rem;
  border-radius: var(--r-pill);
  background: var(--lda-orange);
  color: var(--lda-white);
  font-weight: 700;
  text-decoration: none;
  transition: background 0.2s ease, transform 0.2s ease;
}
.lda-downloads__link:hover {
  background: var(--lda-royal-blue);
  color: var(--lda-white);
  transform: translateY(-1px);
}
.lda-downloads__icon {
  width: 18px;
  height: 18px;
  flex: none;
}

.lda-downloads__note {
  margin-top: 0.6rem;
  color: var(--lda-body);
  font-size: var(--fs-small);
}
.lda-downloads__note p {
  margin: 0;
}
.lda-downloads__keep {
  margin: 0.9rem 0 0;
  color: var(--lda-body-soft);
  font-size: var(--fs-xsmall);
}

/* Says what a digital product is before it is bought, so nobody waits by the
   letterbox for a PDF. */
.product-detail__badge {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  margin: 0 0 0.9rem;
  padding: 0.35rem 0.8rem;
  border-radius: var(--r-pill);
  background: var(--lda-sky);
  color: var(--lda-royal-blue);
  font-size: var(--fs-xsmall);
  font-weight: 700;
}
.product-detail__badge svg {
  width: 15px;
  height: 15px;
  flex: none;
}

/* ==========================================================================
   Footer layout
   A deliberate departure from the prototype, at the client's request: the
   prototype's brand-left / links-right split reads to them as a stock
   template. The brand now sits centred across the top, with the link columns
   spread beneath it.

   This is the one place where the site and the prototype differ by intent.
   Re-porting main.css will not undo it — these rules override it — but the
   prototype should be updated to match if it is ever revisited.
   ========================================================================== */

.site-footer__inner {
  display: block;
  padding-block: 2.75rem 2rem;
}

.site-footer__masthead {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.85rem;
  padding-bottom: 2rem;
  text-align: center;
}
.site-footer__masthead .site-footer__brand {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.85rem;
}
.site-footer__masthead .logo {
  transform: scale(1.08);
  transform-origin: center;
}
.site-footer__masthead .footer-tagline {
  max-width: 32rem;
  margin: 0;
}
.site-footer__masthead .footer-tagline p {
  margin: 0;
}

/* A gold rule between the brand and the links, echoing the section heads. */
.site-footer__columns {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
  gap: clamp(1.5rem, 4vw, 3rem);
  padding-top: 2rem;
  border-top: 1px solid rgba(255, 255, 255, 0.14);
}
/* Sits exactly on the divider, so it reads as a rule between the two halves
   rather than as an underline for the social icons above it. */
.site-footer__columns::before {
  content: "";
  position: absolute;
  top: -2px;
  left: 50%;
  width: 84px;
  height: 3px;
  transform: translateX(-50%);
  border-radius: var(--r-pill);
  background: var(--lda-gold);
}
.site-footer__columns {
  position: relative;
}

/* The dividers between columns were drawn for a 4-column split. */
.site-footer__columns .footer-col + .footer-col::before {
  display: none;
}

@media (max-width: 640px) {
  .site-footer__columns {
    grid-template-columns: 1fr;
    text-align: center;
  }
}

/* Copyright bar: the credit link has to read as a link on navy. */
.site-footer__legal a {
  color: var(--lda-white);
  text-decoration: underline;
  text-underline-offset: 2px;
}
.site-footer__legal a:hover {
  color: var(--lda-gold);
}

/* The CTA bar's buttons, now in their own grid cell so the artwork keeps its
   column however many links an editor adds. */
.about-cta__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem;
}

@media (max-width: 860px) {
  .about-cta__actions {
    width: 100%;
  }
  .about-cta__actions .btn {
    flex: 1 1 auto;
    text-align: center;
  }
}

/* The form panel now fills its container, so the fields have to use that width
   rather than stretch across it — a 1100px-wide text input is unusable. Grid
   rather than inline-block: half-width items plus a gutter overflow the row and
   wrap, which left every field alone on its own line in the left half. */
@media (min-width: 800px) {
  .form-panel form {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    column-gap: 1.5rem;
    align-items: start;
  }

  /* Anything that needs room takes the whole row: the grouped visit fields,
     the message, and the submit button. */
  .form-panel form > fieldset,
  .form-panel form > .form-actions,
  .form-panel form > .form-item:has(textarea),
  .form-panel form > .form-item:has(.form-textarea) {
    grid-column: 1 / -1;
  }

  /* Inside the visit fieldset the same rule applies: day and time pair up. */
  .form-panel .fieldset-wrapper {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    column-gap: 1.5rem;
    align-items: start;
  }
  .form-panel .fieldset-wrapper > .form-item-visitors,
  .form-panel .fieldset-wrapper > .description {
    grid-column: 1 / -1;
  }
}

/* ==========================================================================
   Gallery lightbox triggers
   Photos are buttons so they are reachable by keyboard, but they must not look
   like buttons — the photo is the control.
   ========================================================================== */

.gallery-trigger {
  display: block;
  width: 100%;
  height: 100%;
  padding: 0;
  border: 0;
  background: none;
  cursor: zoom-in;
}
.gallery-trigger img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.3s ease;
}
.facility-gallery .gallery-trigger:hover img,
.inside-grid .gallery-trigger:hover img {
  transform: scale(1.03);
}
.gallery-trigger:focus-visible {
  outline: 3px solid var(--lda-orange);
  outline-offset: 3px;
}

/* The pack's cover carries a count, so it is obvious there is more behind it
   than the one photograph on show. */
.gallery-pack__cover {
  position: relative;
  margin: 0;
  border-radius: var(--r-lg);
  overflow: hidden;
}
.gallery-pack__badge {
  position: absolute;
  right: 0.75rem;
  bottom: 0.75rem;
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.35rem 0.7rem;
  border-radius: var(--r-pill);
  background: rgba(15, 42, 70, 0.82);
  color: var(--lda-white);
  font-size: var(--fs-xsmall);
  font-weight: 700;
  pointer-events: none;
}
.gallery-pack__badge svg {
  width: 15px;
  height: 15px;
}

/* The rest of the set rides along for the viewer to page through. */
.gallery-pack__hidden {
  display: none;
}

/* ==========================================================================
   Section bands and the rhythm between them
   ========================================================================== */

.section--white {
  background: var(--lda-white);
}

/* Every banded section gets the same vertical rhythm, so a run of them reads
   as evenly spaced bands rather than blocks of differing height. */
.section--white,
.section--sky.prose-page,
.section--cream.prose-page {
  padding-block: clamp(2.25rem, 1.5rem + 2.5vw, 3.5rem);
}

/* The quick-action rows ship with almost no vertical padding — 0 top, 4px
   bottom — because on Admissions they tuck directly under the hero. Between
   two bands that leaves the icons crushed against the colour above and below.
   Scoped to the banded case so Admissions keeps the design's spacing. */
.section--white + .admit-actions,
.section--sky + .admit-actions,
.section--cream + .admit-actions {
  padding-top: clamp(2rem, 1.25rem + 2vw, 3rem);
}
.admit-actions:has(+ .section--white),
.admit-actions:has(+ .section--sky),
.admit-actions:has(+ .section--cream) {
  padding-bottom: clamp(2rem, 1.25rem + 2vw, 3rem);
}

/* The quick-action bar is cream by design, which works on Admissions where it
   is the only warm block on the page. Between two bands it is a third warm
   tone competing with them, so where it sits between banded sections it takes
   the neutral card treatment instead. Admissions is untouched — it has no
   banded siblings. */
.section--white + .admit-actions .admit-actions__bar,
.section--sky + .admit-actions .admit-actions__bar,
.admit-actions:has(+ .section--white) .admit-actions__bar,
.admit-actions:has(+ .section--sky) .admit-actions__bar {
  background: var(--lda-white);
  border: 1px solid var(--lda-border);
}
