/* ==========================================================================
   20-LAYOUT.CSS — container, bands, section rhythm, responsive grids.
   ==========================================================================
   The homepage is a vertical stack of full-bleed bands, each containing one
   centred 1280px container. Bands own their background; containers own their
   width. Nothing else sets page-level horizontal padding.
   ========================================================================== */

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

/* A narrower column for long-form prose inside a full-width band. */
.l-container--narrow {
  max-width: 880px;
}

/* --------------------------------------------------------------- bands --- */
.l-band {
  position: relative;
  padding-block: var(--space-section);
}

.l-band--light {
  background-color: var(--color-background);
}

.l-band--alt {
  background-color: var(--color-surface-alt);
}

/* Cool institutional tint. One step bluer than --alt, so the principal's
   message reads as its own elevated surface rather than as a third greige.
   The reference alternates white -> tint down the page; --alt is the warmer
   neutral used by the founder and people bands. */
.l-band--tint {
  background-color: var(--color-surface-tint);
}

.l-band--dark {
  background-color: var(--color-primary-700);
  color: var(--color-text-on-dark-muted);
}

.l-band--dark h1,
.l-band--dark h2,
.l-band--dark h3 {
  color: var(--color-text-on-dark);
}

/* Tight band: used where a band abuts a card that overlaps it. */
.l-band--flush-top {
  padding-block-start: 0;
}

.l-band--flush-bottom {
  padding-block-end: 0;
}

/* Per-section spacing overrides, set from the Homepage editor's Appearance
   fieldset. These are the ONLY spacing values a section may be given, and each
   is expressed in the existing space scale rather than a free length, so a
   band's rhythm can never fall outside the design system. They stay relative to
   --space-section, which the Design tab's rhythm preset steps down per
   breakpoint, so a compact band on mobile is compact against the mobile rhythm
   rather than against the desktop one. */
.l-band--space-sm {
  padding-block: calc(var(--space-section) * 0.6);
}

.l-band--space-lg {
  padding-block: calc(var(--space-section) * 1.35);
}

.l-band--space-flush {
  padding-block: 0;
}

/* ------------------------------------------------------------- stacks --- */
.l-stack > * + * {
  margin-block-start: var(--space-md);
}

.l-stack--lg > * + * {
  margin-block-start: var(--space-xl);
}

/* Space between a section header and the content it introduces. */
.l-section-body {
  margin-block-start: var(--space-xl);
}

/* -------------------------------------------------------------- grids ---
   Auto-fit grids so a section with fewer items than columns still reads as
   intentional rather than leaving a ragged hole. Column counts below are the
   contract maximums; the minmax floor prevents sub-legible cards. */
.l-grid {
  display: grid;
  gap: var(--space-lg);
}

/* Programmes: up to 4 across on desktop, 2 on tablet, compact rows on mobile
   (the mobile transformation is in 30-components.css).

   auto-fit, NOT a fixed four tracks, and this grid is shared with the
   /programme/ archive which renders three published records — a fixed four
   tracks leaves a visible hole there. auto-fit collapses empty tracks, so the
   homepage's four cards resolve to four equal columns and the archive's three
   resolve to three, with no rule needed per context.

   The equal-height requirement is satisfied by the grid itself — grid items
   stretch to the tallest in the row — plus height:100% on the card. What aligns
   the CTAs inside those equal cards is .c-programme__footer's auto margin. */
.l-grid--programmes {
  grid-template-columns: repeat(auto-fit, minmax(min(200px, 100%), 1fr));
}

/* Faculty ARCHIVE grid: 4 across on desktop, 2 across on tablet AND mobile —
   the contract keeps 2 columns on mobile rather than collapsing to 1. */
.l-grid--faculty {
  grid-template-columns: repeat(4, minmax(0, 1fr));
}

/* Faculty SHOWCASE grid: the homepage row of three, inside the people band's
   wide column. A separate class from .l-grid--faculty on purpose — the two live
   in different containers and want different counts:

     archive    12 records in the full 1232px container -> 4 tracks
     showcase    3 records in an ~832px column          -> 3 tracks

   Sharing one class forced a compromise that was wrong in both places: at 4
   tracks the showcase cards were ~190px wide, which is what made the portraits
   read as cropped thumbnails.

   MEASURED, not estimated. The people band is 2.2fr : 1fr of the 1232px
   container with a 32px gap, so the faculty column is 825px, and:

     3 tracks -> 254px cards
     4 tracks -> 182px cards, below the 200px floor .l-grid--programmes uses

   The section renders tdc_faculty_count records, whose registry default is 3
   (max 6). Three records over four tracks would leave a visible hole in the row;
   six over four would leave an orphan pair on a second row. Three tracks is
   right at both ends of the declared range, which is what settles this.

   Three tracks are held all the way down to 768 rather than stepped to 2,
   because 3 records over 2 tracks leaves a single orphan on a second row. What
   keeps the row from crushing at 1024 is the notices column narrowing (below),
   not the card count. */
.l-grid--faculty-featured {
  grid-template-columns: repeat(3, minmax(0, 1fr));
}

/* Notices: 2 across on desktop, 1 below. */
.l-grid--notices {
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

/* Trust strip: one row of up to six items, straddling the hero boundary. The
   column count comes from the item count (--trust-count, set inline by the
   template) so the row is always exactly full — a fixed six-track grid would
   leave gaps, and auto-fit would wrap the last item onto a lonely second row. */
.l-grid--trust {
  grid-template-columns: repeat(var(--trust-count, 4), minmax(0, 1fr));
  gap: 0;
  margin: 0;
  list-style: none;
}

/* Split layouts. Two remain: About (text + photograph) and People (faculty grid
   + notices list). The Principal's message is no longer one of them — it owns a
   band and lays itself out in 30-components.css, because the latest approved
   reference separates it from the programme grid it used to sit beside. */
.l-split {
  display: grid;
  gap: var(--space-2xl);
  align-items: center;
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

/* About band. Proportions, gutter and alignment are all taken from the approved
   reference, which places the photograph in the WIDER column:

     text   x  76 -> 440  = 365px
     gap    x 440 -> 471  =  32px
     photo  x 471 -> 954  = 484px

   That is text : photo = 1 : 1.33, and it is the opposite of the 1.15fr 1fr
   this band used to carry. Only horizontal figures are quoted: the reference is
   a vertically compressed composite, so nothing about height or padding can be
   derived from it — see the measurement caveat in 00-tokens.css.

   align-items: start, not the inherited center. Centring left the photograph
   floating with equal dead bands above and below it — 88px each at 1440 and
   143px each at 1024 — which reads as a stray element rather than as a column.
   Starting both columns on one line is what the reference does, and the wider
   track spends the slack on the photograph instead of on nothing: at 1440 the
   image renders 678x443 rather than 551x359.

   The residual ragging under the photograph is the verified copy being three
   paragraphs where the reference's placeholder was three sentences. It is not
   closed by cropping the image or by cutting client prose. */
.l-split--about {
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.33fr);
  gap: var(--space-xl);
  align-items: start;
}

/* People band: faculty grid left, notices list right, separated by a hairline
   rather than by a gap alone.

   PROPORTIONS. The reference is 1024px wide and its container measures 912ref,
   so reference px x 1.40625 gives implementation px (the same factor the 1280
   container was derived from — see 00-tokens.css). Measured across the band's
   scanlines:

     faculty column   x  72 -> 606  = 534ref = 751px
     divider          x 631          (hairline, ink in >60% of scanlines)
     notices column   x 656 -> 953  = 298ref = 419px

   which is faculty : notices = 64 : 36 of the 1232px content width. The brief
   for this pass specifies a wider faculty showcase than that — ~68-70% against
   ~30-32% — so the tracks are declared as a RATIO rather than as a fixed notices
   width: 2.2fr : 1fr = 68.75% : 31.25% of the track space, which stays inside the
   contracted window at every desktop width instead of drifting as the container
   narrows. A fixed 23rem notices track was tried first and measured 68.9% at
   1440 but only 65.6% at 1024, outside the brief.

   At 1440 that resolves to faculty 814px, notices 370px — within 1px of the
   reference's own notices column (372px scaled), so the ratio widens the faculty
   side by taking space the gutter used to hold, not by shrinking the notices.

   The deviation from the reference is deliberate and one-directional: it spends
   the difference on the portrait cards, which is what makes three 1:1 plates at
   ~253px possible in the left column. Only horizontal figures are quoted — the
   reference is a vertically compressed composite, so nothing about height or
   padding can be derived from it.

   align-items: stretch. The band must read as one even block: the two columns
   share both a top and a bottom, and the hairline divider runs the full band
   height instead of stopping where the shorter column's content ends. The
   notices column's scrolling window fills whatever height the faculty side
   leaves below the notices head (see 40-interactive.css), so the notices run
   to the band's bottom with no dead space below them — and the "View all"
   link lives in the head, so nothing is stranded at the bottom of the
   column. */
.l-split--people {
  grid-template-columns: minmax(0, 2.2fr) minmax(0, 1fr);
  align-items: stretch;
  gap: var(--space-2xl);
}

.l-split--people > * + * {
  padding-inline-start: var(--space-2xl);
  border-inline-start: 1px solid var(--color-border);
  /* The faculty column opens with an eyebrow above its H2; the notices column
     opens with its heading directly. Left alone, the two headings sit ~29px
     apart and the band reads as two blocks that start at different heights — the
     reference has them level. This offset is the eyebrow's own line box plus its
     bottom margin, written from the same tokens the eyebrow uses rather than as a
     measured constant, so it stays correct if the eyebrow's size or spacing
     changes. The divider is unaffected: a border spans the padding box, so it
     still runs from the top of the column. */
  padding-block-start: calc(var(--text-ui) * var(--leading-body) + var(--space-xs));
}

/* Footer: 4 columns, brand column wider. The gutter is one step tighter than
   the section grids — the footer's rows are short and self-spaced by the
   44px tap-target rhythm, so a wide gutter only dilutes the columns. */
.l-grid--footer {
  grid-template-columns: minmax(0, 1.6fr) repeat(3, minmax(0, 1fr));
  gap: var(--space-lg);
}

/* ================= NARROW DESKTOP 1024–1279 =================
   The gutter and the divider padding step down one token here, which is what
   holds the 68/31 track ratio at a usable card width: at 1024 the two 48px
   inset gutters cost 96px of the 976px content box, and the three portrait cards
   land at 187px. Cutting both to 32px returns 32px to the cards. The ratio itself
   does not change — it is the same declaration at every desktop width. */
@media (max-width: 1279px) {
  .l-split--people {
    gap: var(--space-xl);
  }

  .l-split--people > * + * {
    padding-inline-start: var(--space-xl);
  }
}

/* ================= TABLET 768–1023 ================= */
/* Component rules still key off 1279 in 30-components.css. The 1024–1279 block
   above is this file's only narrow-desktop block: every other layout grid is
   identical across the fluid desktop band. */
@media (max-width: 1023px) {
  /* Two per row from here (the item count still caps the tracks, so a single
     item keeps the whole row to itself). At this width each column is
     ~230-330px, which fits "Experienced Faculty" on two lines without
     crushing, and two across is what makes the strip read as one band. */
  .l-grid--trust {
    grid-template-columns: repeat(min(var(--trust-count, 4), 2), minmax(0, 1fr));
  }

  /* An odd item count would leave the last item alone in the left half of a
     two-track grid — the ragged orphan the strip must never show. The selector
     is pure position logic: a last child is an odd child only when the count
     is odd, so a 3- or 5-item strip stretches its final item across the full
     row (its content stays centred), while even counts are untouched at every
     width. Scoped to the two-track layouts, so the count-driven desktop grid
     above is never affected. */
  .l-grid--trust > :last-child:nth-child(odd) {
    grid-column: 1 / -1;
  }

  .l-grid--programmes,
  .l-grid--faculty {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

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

  .l-split,
  .l-split--about,
  .l-split--people {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-xl);
  }

  /* The hairline between the paired columns becomes a horizontal rule once they
     are stacked, otherwise it would sit alongside nothing. */
  .l-split--people > * + * {
    padding-inline-start: 0;
    padding-block-start: var(--space-xl);
    border-inline-start: 0;
    border-block-start: 1px solid var(--color-border);
  }

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

/* ================= MOBILE ≤767 ================= */
@media (max-width: 767px) {
  /* The same two-track layout as tablet, still capped by the item count so a
     lone item is not stranded in the left half of an empty second track. */
  .l-grid--trust {
    grid-template-columns: repeat(min(var(--trust-count, 4), 2), minmax(0, 1fr));
  }

  /* Faculty deliberately stays at 2 columns. Do not collapse to 1. */
  .l-grid--faculty {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-md);
  }

  /* The showcase does the opposite and collapses to ONE column, because it holds
     exactly three records. Two tracks would leave a single orphan card on a
     second row, and three tracks at 375px gives 109px cards — a face at that
     size is not a portrait. One column per row is not a shrunken card here: the
     card turns into a compact horizontal row (see 30-components.css), the same
     mandatory mobile transformation the programme cards use. */
  .l-grid--faculty-featured {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-sm);
  }

  /* Programme cards become full-width compact rows. */
  .l-grid--programmes {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-sm);
  }

  /* MANDATORY TRANSFORMATION: the About image leads on mobile. Source order
     in the template is text-then-image for a sensible reading order; the grid
     reorders it visually. */
  .l-split--about .l-split__media {
    order: -1;
  }

  .l-grid--footer {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-lg);
  }
}

/* ================= SMALL MOBILE <480 ================= */
@media (max-width: 479px) {
  /* The trust strip deliberately stays two-per-row here rather than collapsing
     to a single column. One column stacked the four items into a ~500px tower —
     the "excessive height" the strip is meant to avoid — and pushed About below
     the fold. At 375px each cell is ~160px wide, which holds the longest value
     ("Experienced Faculty") on two lines. The count cap and the odd-count orphan
     rule from the 1023px block still apply, so any item count lays out evenly.
     Do not collapse to 1. */
  .l-grid--trust {
    grid-template-columns: repeat(min(var(--trust-count, 4), 2), minmax(0, 1fr));
  }
}
