/* ==========================================================================
   30-COMPONENTS.CSS — buttons, cards, header, footer, forms, alerts, nav.
   ==========================================================================
   Naming: c-<component>__<element>--<modifier>.
   No literal design values: every colour, space, radius and shadow is a token.
   ========================================================================== */

/* ============================ BUTTON SYSTEM ============================
   Five variants, three sizes, one arrow convention. Individual sections must
   not define their own button styles. */

.c-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-xs);
  min-height: var(--tap-target);
  /* --btn-pad-scale is set only by a Design tab preset and defaults to 1, so an
     untouched install computes calc(1.5rem * 1) = the designed 24px exactly.
     A multiplier rather than an absolute length: --sm/--md/--lg below each have
     their own padding, and one fixed value would collapse the three sizes into
     one. --btn-radius likewise falls back to the designed --radius-sm. */
  padding: var(--space-sm) calc(var(--space-lg) * var(--btn-pad-scale, 1));
  border: 1px solid transparent;
  /* --btn-radius is the Design tab preset hook; the designed default is the
     button system's own --radius-btn (6px). */
  border-radius: var(--btn-radius, var(--radius-btn));
  font-size: var(--text-ui);
  font-weight: var(--font-weight-semibold);
  letter-spacing: var(--tracking-ui);
  line-height: var(--leading-flat);
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  transition:
    background-color var(--transition-base),
    border-color var(--transition-base),
    color var(--transition-base),
    transform var(--transition-base);
}

/* The arrow nudges; the button does not grow. */
.c-btn__arrow {
  transition: transform var(--transition-base);
}

.c-btn:hover .c-btn__arrow {
  transform: translateX(var(--space-2xs));
}

.c-btn:active {
  transform: translateY(1px);
}

.c-btn[disabled],
.c-btn[aria-disabled="true"] {
  opacity: 0.55;
  cursor: not-allowed;
  transform: none;
}

/* 1. primary — gold fill, dark text. White on gold is forbidden (~1.9:1). */
.c-btn--primary {
  background-color: var(--color-accent);
  color: var(--color-accent-on);
}

.c-btn--primary:hover {
  background-color: var(--color-accent-hover);
  color: var(--color-accent-on);
}

/* 2. secondary-dark — solid navy on light bands. */
.c-btn--secondary-dark {
  background-color: var(--color-primary-600);
  color: var(--color-text-on-dark);
}

.c-btn--secondary-dark:hover {
  background-color: var(--color-primary-700);
  color: var(--color-text-on-dark);
}

/* 3. ghost-light — transparent with a light hairline, for dark bands only. */
.c-btn--ghost-light {
  background-color: transparent;
  border-color: var(--color-border-on-dark);
  color: var(--color-text-on-dark);
}

.c-btn--ghost-light:hover {
  background-color: rgba(255, 255, 255, 0.1);
  border-color: var(--color-text-on-dark);
  color: var(--color-text-on-dark);
}

/* 4. outline — navy hairline on light bands. */
.c-btn--outline {
  background-color: transparent;
  border-color: var(--color-primary-600);
  color: var(--color-primary-600);
}

.c-btn--outline:hover {
  background-color: var(--color-primary-600);
  color: var(--color-text-on-dark);
}

/* 5. text-link — no chrome. Retains the 44px target via padding. */
.c-btn--text-link {
  padding-inline: 0;
  background: none;
  color: var(--color-primary-500);
  letter-spacing: normal;
  text-transform: none;
}

.c-btn--text-link:hover {
  color: var(--color-primary-700);
  text-decoration: underline;
  text-underline-offset: 0.2em;
}

/* Sizes. sm keeps a 44px hit area via padding even though it looks smaller.
   Each carries --btn-pad-scale so a padding preset moves all three in step. */
.c-btn--sm {
  padding: var(--space-xs) calc(var(--space-md) * var(--btn-pad-scale, 1));
  font-size: var(--text-xs);
}

.c-btn--md {
  padding: var(--space-sm) calc(var(--space-lg) * var(--btn-pad-scale, 1));
}

.c-btn--lg {
  padding: var(--space-md) calc(var(--space-xl) * var(--btn-pad-scale, 1));
  font-size: var(--text-sm);
}

/* Full-width stacked CTAs on mobile, per the contract. */
@media (max-width: 767px) {
  .c-btn--block-mobile {
    width: 100%;
  }
}

/* ========================= SECTION HEADER ============================== */
.c-section-header--center {
  text-align: center;
  margin-inline: auto;
  max-width: 720px;
}

.c-section-header__eyebrow {
  margin-block-end: var(--space-xs);
  color: var(--color-primary-500);
  font-size: var(--text-ui);
  font-weight: var(--font-weight-semibold);
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase;
}

.l-band--dark .c-section-header__eyebrow {
  color: var(--color-accent);
}

.c-section-header__title {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
}

.c-section-header--center .c-section-header__title {
  justify-content: center;
}

/* The amber dash: one of the five sanctioned accent roles. */
.c-section-header__dash {
  flex: 0 0 auto;
  width: var(--space-xl);
  height: var(--space-3xs);
  border-radius: var(--radius-full);
  background-color: var(--color-accent);
}
/* Header, utility bar, navigation, cards, footer, forms and alerts continue in
   this file. Boundaries are marked so each component stays locatable. */

/* ========================== UTILITY BAR ================================
   Deep navy strip above the header. Removed entirely on mobile — its content
   is relocated to the drawer footer and the site footer. */
.c-utility {
  background-color: var(--color-header-navy);
  color: var(--color-text-on-dark-muted);
  font-size: var(--text-sm);
  /* Thin gold rule at the very top of the page: the frame the whole header
     sits inside. One of the header pass's restrained gold details. */
  border-block-start: 2px solid var(--color-accent);
}

.c-utility__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-xl);
  min-height: var(--utility-height);
}

.c-utility__list {
  display: flex;
  align-items: center;
  gap: var(--space-xl);
  margin: 0;
  padding: 0;
  list-style: none;
}

/* Non-interactive items (address, hours). They match the links' vertical
   rhythm but must not look clickable, so they get no hover and no underline.

   The gap is for the icon that now precedes the text; it matches
   .c-utility__link's so an item and a link sit on the same rhythm whether or not
   the one beside it is interactive. */
.c-utility__item {
  display: inline-flex;
  align-items: center;
  gap: var(--space-xs);
  min-height: var(--utility-height);
  color: var(--color-text-on-dark-muted);
}

/* ---- Utility-bar icons ----

   DECORATIVE, and sized in the stylesheet rather than only in the markup so the
   whole set can be adjusted in one place. flex-shrink:0 is the load-bearing
   declaration: without it a long address compresses the pin into an ellipse before
   the text wraps, which is the classic flex-icon failure.

   The colour is inherited from the item, so an icon brightens with its own label
   on hover instead of drifting out of step with it. */
.c-utility__icon {
  flex: 0 0 auto;
  /* Gold, per the header pass: the four information glyphs are the bar's
     accent, while the values they annotate stay white. */
  width: 15px;
  height: 15px;
  color: var(--color-accent);
}

.c-utility__link:hover .c-utility__icon {
  opacity: 1;
}

/* ---- Social links, at the right-hand end of the bar ----

   Tighter than the information list: these are adjacent marks that read as one
   group, and the --space-lg used between "address" and "hours" would scatter them
   across the bar. */
.c-utility__social {
  gap: var(--space-2xs);
}

/* ICON-ONLY LINKS STILL NEED A TARGET. The glyph is 16px, under WCAG 2.2's 24x24
   minimum, so the padding is what makes the link hittable rather than the icon
   being drawn larger — enlarging it would break the optical weight the rest of the
   bar is set at. Measured: 16 + 2x4px padding = 24px square, and the bar's own
   40px min-height covers the vertical axis. */
.c-utility__social-link {
  padding: var(--space-2xs);
  border-radius: var(--radius-sm);
}

.c-utility__social-link:hover {
  /* A tint rather than a border: a 1px outline appearing on hover shifts the
     adjacent icons by a pixel, which reads as the row twitching. */
  background-color: rgb(255 255 255 / 12%);
}

.c-utility__social-link:hover .c-utility__icon--social {
  color: var(--color-accent-strong);
}

/* The brand marks are drawn at 16 rather than the 14 the information icons use.
   They carry no text label beside them, so they are the only thing identifying the
   destination and have to survive being the smallest mark on the page. */
.c-utility__icon--social {
  width: 16px;
  height: 16px;
  /* The brand marks stay light rather than gold: six gold glyphs in one bar
     would spend the whole accent budget before the navigation is reached. */
  color: var(--color-text-on-dark-muted);
}

/* Hours are the least urgent item in the bar and the first to be dropped when the
   row starts to crowd. Unchanged from before this pass — but the threshold now has
   a second reason: the social icons occupy the right-hand end, so the row has less
   slack at 1024–1279 than it did. */
@media (max-width: 1279px) {
  .c-utility__item--hours {
    display: none;
  }
}

.c-utility__link {
  display: inline-flex;
  align-items: center;
  /* Fills the bar height so the hit area clears the WCAG 2.2 target-size
     minimum. The text alone is only ~19px tall. */
  min-height: var(--utility-height);
  gap: var(--space-xs);
  color: var(--color-text-on-dark-muted);
  text-decoration: none;
}

.c-utility__link:hover {
  color: var(--color-text-on-dark);
}

@media (max-width: 1023px) {
  .c-utility {
    display: none;
  }
}

/* ============================= HEADER ==================================
   Two rows: an identity masthead over a navigation bar, separated by a
   hairline. The whole header is sticky as one unit; on scroll the identity row
   collapses away and only the navigation bar remains, so the sticky footprint
   stays close to the old single-row height instead of eating the viewport. */
.c-header {
  position: sticky;
  top: 0;
  z-index: var(--z-header);
  background-color: var(--color-header-masthead);
  /* The one header shadow: under the navigation row, subtle by contract. */
  box-shadow: var(--shadow-header);
}

/* ---- identity row ---- */
.c-header__identity-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-lg);
  min-height: var(--header-identity-height);
  transition: min-height var(--transition-base);
}

/* Plain masthead surface: the client asked for the header background plain,
   so the identity row carries colour only — no watermark, no image, no rule. */
.c-header__identity {
  background-color: var(--color-header-masthead);
}

/* Compressed state, toggled by navigation.js on scroll. The identity row is
   hidden rather than shrunk: scaling a masthead down produces a cramped,
   illegible version of itself, while removing it leaves a clean nav bar. */
.c-header.is-compact .c-header__identity {
  display: none;
}

.c-header__brand {
  display: inline-flex;
  align-items: center;
  /* Polish pass: one step tighter than the row gap, so the crest and the
     institutional text read as one visually tight lockup. */
  gap: var(--space-md);
  min-width: 0;
  text-decoration: none;
  color: var(--color-text-primary);
}

.c-header__logo {
  width: auto;
  height: auto;
  max-height: var(--header-logo-height);
  flex: 0 0 auto;
}

.c-header__wordmark {
  display: flex;
  flex-direction: column;
  min-width: 0;
  line-height: var(--leading-heading);
}

/* The parent college: context, so it sits above the department and is quieter
   than it. Header pass: promoted from metadata to the masthead's first line —
   uppercase, navy, letter-spaced — because it is the institution the whole
   crest stands for. */
.c-header__parent {
  font-size: var(--text-body);
  font-weight: var(--font-weight-semibold);
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase;
  color: var(--color-primary-700);
}

/* The department is the subject of the site and carries the weight. Header
   pass: sized between h2 and h3 so the four lockup lines read as four distinct
   levels rather than two sizes. */
.c-header__title {
  font-size: var(--text-masthead-title);
  font-weight: var(--font-weight-bold);
  letter-spacing: var(--tracking-display);
  color: var(--color-primary-700);
}

/* Accreditation credential, below the department it belongs to. Sized with the
   location line, but weighted and darkened a step so the two short lines under
   the title are not read as one block. No accent colour: --color-accent on a
   white surface is ~1.8:1 and would fail contrast for a claim-bearing line. */
.c-header__accreditation {
  margin-block-start: var(--space-2xs);
  font-size: var(--text-body);
  font-weight: var(--font-weight-medium);
  letter-spacing: var(--tracking-ui);
  color: var(--color-text-secondary);
}

.c-header__location {
  margin-block-start: var(--space-3xs);
  font-size: var(--text-sm);
  color: var(--color-text-muted);
}

/* Small gold dash before the location line — the same amber-dash language the
   section headers use, so the masthead reads as part of the page's system
   rather than as a separate ornament. */
.c-header__location::before {
  content: "";
  display: inline-block;
  width: var(--space-xl);
  height: var(--space-3xs);
  margin-inline-end: var(--space-2xs);
  vertical-align: middle;
  border-radius: var(--radius-full);
  background-color: var(--color-accent);
}

/* ---- founder, identity row, wide desktop only ----
   Restrained by construction: a small portrait and two short lines, with a
   vertical hairline separating it from the wordmark so it reads as a distinct
   piece of institutional information rather than as part of the brand lockup. */
.c-header__founder {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  margin-inline-start: auto;
}

/* The divider stands at the founder block's own height — the portrait's height
   — rather than the row's, so it reads as framing the exhibit rather than
   slicing the band. */
.c-header__founder::before {
  content: "";
  flex: 0 0 auto;
  align-self: center;
  width: 1px;
  height: var(--header-founder-size);
  margin-inline-end: var(--space-lg);
  background-color: var(--color-border);
}

.c-header__founder-photo {
  width: var(--header-founder-size);
  height: var(--header-founder-size);
  flex: 0 0 auto;
  /* Thin gold ring: the founder block's one piece of gold, so the eye lands on
     the portrait as the masthead's right-hand exhibit. */
  border: 2px solid var(--color-accent);
  border-radius: var(--radius-full);
  object-fit: cover;
  /* Portraits are framed head-up, so the top of the crop is the face. */
  object-position: top center;
}

.c-header__founder-text {
  display: flex;
  flex-direction: column;
  line-height: var(--leading-heading);
}

.c-header__founder-name {
  font-size: var(--text-body);
  font-weight: var(--font-weight-semibold);
  color: var(--color-text-primary);
}

.c-header__founder-role {
  margin-block-start: var(--space-3xs);
  font-size: var(--text-ui);
  font-weight: var(--font-weight-medium);
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase;
  /* Institutional blue rather than gold: accent text on ivory is ~1.9:1 and
     fails contrast, so this block's gold stays in the portrait ring. */
  color: var(--color-primary-500);
}

/* ---- navigation row ----
   Deep navy field anchoring the header. The row's text colour is set here
   rather than per-link so the submenu toggle (which is a button, not a link)
   inherits it too. */
.c-header__bar {
  background-color: var(--color-header-navy);
  color: var(--color-text-on-dark-muted);
}

/* Stretched to the row's full height so the gold active block spans it. */
.c-header__nav {
  align-self: stretch;
}

.c-header__bar-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-lg);
  min-height: var(--header-nav-height);
}

.c-header__actions {
  display: flex;
  align-items: center;
  gap: var(--space-md);
}

/* The navigation row's CTA: the gold primary button already carries the right
   fill and ink; it is stepped up one size here so it holds its own beside the
   15px navigation labels. */
.c-header__actions .c-btn--primary {
  padding: var(--space-sm) var(--space-lg);
  font-size: var(--text-nav-link);
}

/* A restrained lift, not a zoom: one pixel, transform only. */
.c-header__actions .c-btn--primary:hover {
  transform: translateY(-1px);
}

/* The burger's own visibility is owned by .c-burger, which is hidden by default
   and revealed below the drawer breakpoint. This modifier exists only to place
   it in the identity row, not to toggle it — duplicating the toggle here would
   give two rules the same job. */
.c-header__burger {
  flex: 0 0 auto;
}

/* Below 1280 the founder block is the first thing to go: it is supporting
   information, and the wordmark plus navigation must not be crowded for it. */
@media (max-width: 1279px) {
  .c-header__founder {
    display: none;
  }
}

@media (max-width: 1023px) {
  .c-header__identity-inner {
    min-height: var(--header-height-mobile);
  }

  .c-header__parent {
    font-size: var(--text-xs);
    font-weight: var(--font-weight-medium);
    letter-spacing: var(--tracking-ui);
    color: var(--color-text-muted);
  }

  .c-header__title {
    font-size: var(--text-h3);
  }

  .c-header__accreditation {
    margin-block-start: var(--space-3xs);
    font-size: var(--text-xs);
  }

  .c-header__location {
    font-size: var(--text-xs);
  }

  .c-header__location::before {
    display: none;
  }

  /* Nav glyphs are a desktop-row device; below the drawer breakpoint the
     labels alone carry the destination, exactly as before the pass. */
  .c-nav__icon {
    display: none;
  }

  /* The navigation row becomes the drawer. The burger, already revealed by
     .c-burger at this breakpoint, is in the identity row so the header still
     has a control after the nav row is removed. */
  .c-header__bar {
    display: none;
  }

  /* Nothing is left to collapse on scroll once the identity row is the whole
     header, so the compact state must not hide it. */
  .c-header.is-compact .c-header__identity {
    display: block;
  }
}

@media (max-width: 767px) {
  .c-header__title {
    font-size: var(--text-body);
  }

  /* The location repeats in the footer and in the drawer; at this width the
     wordmark needs the room more than the page needs the third line. */
  .c-header__location {
    display: none;
  }
}

/* =========================== NAVIGATION ================================
   Drawer switches in at 1023px, NOT 767: the primary menu plus the CTA cannot
   fit on a tablet without crowding. */
.c-nav {
  display: flex;
}

.c-nav__list {
  display: flex;
  align-items: center;
  gap: var(--space-lg);
  margin: 0;
  padding: 0;
  list-style: none;
}

.c-nav__link {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2xs);
  min-height: var(--tap-target);
  padding-block: var(--space-xs);
  color: var(--color-text-primary);
  font-size: var(--text-ui);
  font-weight: var(--font-weight-medium);
  letter-spacing: var(--tracking-ui);
  text-decoration: none;
  text-transform: uppercase;
  position: relative;
}

/* Active/hover indicator: a gold underline. Sanctioned accent role. */
.c-nav__link::after {
  content: "";
  position: absolute;
  inset-inline: 0;
  bottom: 0;
  height: var(--space-3xs);
  background-color: var(--color-accent-strong);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--transition-base);
}

.c-nav__link:hover::after,
.c-nav .current-menu-item > .c-nav__link::after,
.c-nav .current_page_item > .c-nav__link::after {
  transform: scaleX(1);
}

/* ---- header navigation row: navy field, white labels, gold states ----
   Scoped to .c-header__nav so the drawer's copy of .c-nav__link keeps its
   light-surface styling untouched. */
.c-header__nav .c-nav__list {
  align-items: stretch;
}

.c-header__nav .c-nav__item {
  display: flex;
  align-items: stretch;
}

.c-header__nav .c-nav__link {
  color: var(--color-text-on-dark-muted);
  font-size: var(--text-nav-link);
  font-weight: var(--font-weight-semibold);
  padding-inline: var(--space-md);
  /* Polish pass: a touch more air between glyph and label, so the two read
     as one aligned unit on the row's centre line. */
  gap: var(--space-xs);
}

.c-header__nav .c-nav__link:hover {
  color: var(--color-accent-strong);
}

.c-header__nav .c-nav__icon {
  width: 20px;
  height: 20px;
}

/* Active item: a gold block spanning the row height — the navy text on gold
   keeps the contrast the accent-on rule demands. The underline indicator is
   switched off for it: two indicators on one item is noise. */
.c-header__nav .current-menu-item > .c-nav__link,
.c-header__nav .current_page_item > .c-nav__link {
  background-color: var(--color-accent);
  color: var(--color-primary-900);
}

.c-header__nav .current-menu-item > .c-nav__link::after,
.c-header__nav .current_page_item > .c-nav__link::after {
  transform: scaleX(0);
}

/* A gold field under a gold focus ring disappears; the active item borrows the
   light-surface ring instead. */
.c-header__nav .current-menu-item > .c-nav__link:focus-visible,
.c-header__nav .current_page_item > .c-nav__link:focus-visible {
  outline-color: var(--focus-color);
}

/* Dropdown. Hover-opens on pointer devices; the toggle button in the markup
   makes it operable by keyboard and touch. */
.c-nav__submenu {
  position: absolute;
  top: 100%;
  left: 0;
  z-index: var(--z-dropdown);
  min-width: 260px;
  margin: 0;
  padding: var(--space-xs);
  list-style: none;
  background-color: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-md);
}

.c-nav__item {
  position: relative;
}

.c-nav__item[aria-expanded="false"] > .c-nav__submenu,
.c-nav__submenu[hidden] {
  display: none;
}

.c-nav__submenu .c-nav__link {
  width: 100%;
  padding: var(--space-sm) var(--space-md);
  text-transform: none;
  letter-spacing: normal;
  border-radius: var(--radius-sm);
  /* The dropdown is a light surface hanging off a navy row: reset the navy-row
     treatment so its entries read as list items again. */
  color: var(--color-text-primary);
  font-size: var(--text-sm);
  font-weight: var(--font-weight-medium);
}

.c-nav__submenu .c-nav__link::after {
  display: none;
}

.c-nav__submenu .c-nav__link:hover {
  background-color: var(--color-surface-alt);
}

/* Toggle button that owns aria-expanded for the submenu. */
.c-nav__toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: var(--tap-target);
  min-height: var(--tap-target);
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  cursor: pointer;
}

.c-nav__toggle svg {
  transition: transform var(--transition-base);
}

.c-nav__toggle[aria-expanded="true"] svg {
  transform: rotate(180deg);
}


/* ======================= MOBILE DRAWER + BURGER ========================= */
.c-burger {
  display: none;
  align-items: center;
  justify-content: center;
  min-width: var(--tap-target);
  min-height: var(--tap-target);
  padding: 0;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background-color: var(--color-surface);
  color: var(--color-primary-900);
  cursor: pointer;
}

.c-drawer {
  position: fixed;
  inset: 0 0 0 auto;
  /* Sits one layer above its own overlay. */
  z-index: calc(var(--z-overlay) + 1);
  width: min(88vw, 380px);
  padding: var(--space-lg);
  overflow-y: auto;
  background-color: var(--color-surface);
  box-shadow: var(--shadow-lg);
  transform: translateX(100%);
  transition: transform var(--duration-slow) var(--ease-out);
}

.c-drawer.is-open {
  transform: translateX(0);
}

.c-drawer__overlay {
  position: fixed;
  inset: 0;
  z-index: var(--z-overlay);
  background-color: rgba(3, 25, 50, 0.55);
  opacity: 0;
  visibility: hidden;
  transition:
    opacity var(--transition-base),
    visibility var(--transition-base);
}

.c-drawer__overlay.is-open {
  opacity: 1;
  visibility: visible;
}

.c-drawer__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-md);
  margin-block-end: var(--space-lg);
}

/* The drawer reuses the header's title styling, but the drawer is narrow and
   the masthead size (text-h3) wraps to three lines in it. Stepped down here
   rather than in .c-header__title, which must stay large in the masthead. */
.c-drawer__title {
  font-size: var(--text-body);
}

/* Relocated utility lines need separating from each other, not just from the
   nav above them. */
.c-drawer__utility > * + * {
  margin-block-start: var(--space-xs);
}

.c-drawer__nav .c-nav__list {
  flex-direction: column;
  align-items: stretch;
  gap: var(--space-2xs);
}

.c-drawer__nav .c-nav__link {
  justify-content: space-between;
  padding: var(--space-sm) 0;
  border-block-end: 1px solid var(--color-border-subtle);
}

.c-drawer__nav .c-nav__submenu {
  position: static;
  min-width: 0;
  border: 0;
  box-shadow: none;
  padding-inline-start: var(--space-md);
}

/* Relocated utility information, mobile only. */
.c-drawer__utility {
  margin-block-start: var(--space-lg);
  padding-block-start: var(--space-lg);
  border-block-start: 1px solid var(--color-border);
  font-size: var(--text-sm);
  color: var(--color-text-muted);
}

/* The relocated utility lines each carry a leading icon now, so the line has to be
   a flex row rather than a text paragraph — otherwise the glyph sits on the text
   baseline and a wrapped address indents under the icon instead of aligning with
   the first word. */
.c-drawer__utility p,
.c-drawer__utility a {
  display: flex;
  align-items: center;
  gap: var(--space-xs);
}

.c-drawer__utility p {
  margin: 0;
}

/* Same flex-shrink reasoning as .c-utility__icon: a long address must wrap rather
   than squash the pin. Drawn a step larger than the desktop bar's because the
   drawer's body text is --text-sm rather than --text-xs. */
.c-drawer__icon {
  flex: 0 0 auto;
  width: 16px;
  height: 16px;
  color: var(--color-primary-600);
}

/* ---- Social links in the drawer ----

   The utility bar is display:none below 1024px, so without this the mobile visitor
   loses every social link the desktop visitor has. A horizontal row of 44px
   targets, not the 24px minimum the desktop bar uses: this is a touch surface, and
   --tap-target is the project's locked value for one. */
.c-drawer__social {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-xs);
  margin: var(--space-md) 0 0;
  padding: 0;
  list-style: none;
}

.c-drawer__social-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: var(--tap-target);
  min-height: var(--tap-target);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  color: var(--color-primary-700);
  text-decoration: none;
}

.c-drawer__social-link:hover {
  border-color: var(--color-primary-600);
  color: var(--color-primary-600);
}

.c-drawer__social-icon {
  flex: 0 0 auto;
}

@media (max-width: 1023px) {
  .c-burger {
    display: inline-flex;
  }

  /* Desktop nav is hidden, not merely narrowed. */
  .c-header__nav {
    display: none;
  }
}

@media (min-width: 1024px) {
  .c-drawer,
  .c-drawer__overlay {
    display: none;
  }
}

/* ============================== HERO =================================== */
.c-hero {
  position: relative;
  background-color: var(--color-primary-800);
  color: var(--color-text-on-dark);
  isolation: isolate;
}

.c-hero__slides {
  position: relative;
}

.c-hero__slide {
  position: relative;
  display: grid;
  align-items: center;
  min-height: 520px;
}

/* Only the active slide is visible. Without JS the first slide remains
   displayed and every slide stays in the DOM, so content never disappears. */
.c-hero__slide[hidden] {
  display: none;
}

/* ---- The crossfade (the reference site's banner behaviour) ----

   Once carousel.js confirms it is running, the slides STACK in a single grid
   cell (grid-area, so the container keeps the tallest slide's height) and the
   active one fades in OVER the outgoing one: a true crossfade, the way the
   reference site's banner moves between photographs. Only the incoming slide
   animates — the outgoing one keeps .is-leaving at opacity 1 underneath,
   which is what stops the band's navy background from bleeding through at
   the midpoint (two simultaneous fades would dip the whole hero to dark for
   a frame). z-index puts the incoming slide on top; opacity only, so nothing
   animates a layout property; and visibility (not display) is what removes a
   finished slide, so it leaves the tab order and the accessibility tree the
   moment it is fully covered.

   calc(var(--duration-slow) * 1.5) = 600ms: one and a half steps of the
   token scale, because a banner crossfade reads as hurried at 400ms and
   sleepy at a full second. */
.c-hero.is-enhanced .c-hero__slides {
  display: grid;
}

.c-hero.is-enhanced .c-hero__slide {
  grid-area: 1 / 1;
  opacity: 0;
  visibility: hidden;
}

.c-hero.is-enhanced .c-hero__slide.is-active {
  opacity: 1;
  visibility: visible;
  z-index: 1;
  transition: opacity calc(var(--duration-slow) * 1.5) var(--ease-out);
}

/* The outgoing slide, for the duration of the incoming one's fade: still
   fully opaque, still painted (underneath), no transition of its own. */
.c-hero.is-enhanced .c-hero__slide.is-leaving {
  opacity: 1;
  visibility: visible;
}

/* The user's motion preference outranks the ambience: slides still change,
   they just cut instead of dissolving. */
@media (prefers-reduced-motion: reduce) {
  .c-hero.is-enhanced .c-hero__slide.is-active {
    transition: none;
  }
}

.c-hero__media {
  position: absolute;
  inset: 0;
  z-index: -1;
}

.c-hero__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Scrim: guarantees text contrast over any photograph — but only where the
   text actually is. Polish pass, per the client's direction: the LEFT edge
   stays dark navy for headline contrast but at 0.76 (down from 0.92) —
   enough that architectural detail remains visible through it; the CENTRE
   is a medium transparent navy; and the gradient still reaches FULL
   TRANSPARENCY at 72% of the width, so the right-hand quarter of every
   photograph — the heritage building, palms and sky — shows through clean
   and bright. There is no uniform dark overlay anywhere on the image. */
.c-hero__media::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(
    90deg,
    rgba(1, 33, 70, 0.76) 0%,
    rgba(1, 33, 70, 0.38) 48%,
    rgba(1, 33, 70, 0) 72%
  );
}

.c-hero__content {
  max-width: var(--measure-lead);
  /* Polish pass: the block sits a touch above the optical centre — the trust
     strip covers the hero's lower 64px, which pulls the eye down — while
     staying clear of both the top and bottom edges. */
  padding-block: var(--space-2xl) calc(var(--space-3xl) + var(--space-xl));
}

/* Polish pass, desktop only: the text column is capped at 40% of the
   container, so the campus photograph visually dominates the right ~60%.
   Below 1024 the ch-based measure above keeps the previous behaviour
   untouched — no responsive change. */
@media (min-width: 1024px) {
  .c-hero__content {
    max-width: 40%;
  }
}

.c-hero__title {
  /* Polish pass: the hero's own size/leading tokens — ~15% smaller and a
     notch tighter than the page display scale, so the wording stays strong
     without consuming the banner. */
  font-size: var(--text-hero-display);
  line-height: var(--leading-hero);
  letter-spacing: var(--tracking-display);
  color: var(--color-text-on-dark);
}

/* Eyebrow above the headline. Gold, uppercase, never a heading element. */
.c-hero__eyebrow {
  margin-block-end: var(--space-sm);
  color: var(--color-accent);
  font-size: var(--text-ui);
  font-weight: var(--font-weight-semibold);
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase;
}

/* The closing line of the headline, in gold. Its own block so it always sits
   on a line of its own regardless of the heading's wrap point. */
.c-hero__title-accent {
  display: block;
  color: var(--color-accent);
}

.c-hero__lead {
  margin-block-start: var(--space-md);
  font-size: var(--text-body-lg);
  color: var(--color-text-on-dark-muted);
}

.c-hero__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-md);
  margin-block-start: var(--space-xl);
}

/* Carousel controls. Hidden until carousel.js confirms it is running, so they
   can never be dead chrome. Arrows sit on the hero's vertical centre line at
   each edge; dots sit at the bottom centre — matching the approved reference. */
.c-hero__controls {
  display: none;
}

.c-hero.is-enhanced .c-hero__controls {
  display: block;
  position: static;
}

.c-hero.is-enhanced .c-hero__arrow {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  z-index: var(--z-base);
}

.c-hero.is-enhanced [data-tdc-slide-prev] {
  left: var(--container-gutter);
}

.c-hero.is-enhanced [data-tdc-slide-next] {
  right: var(--container-gutter);
}

.c-hero__arrow {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: var(--tap-target);
  min-height: var(--tap-target);
  border: 1px solid var(--color-border-on-dark);
  border-radius: var(--radius-full);
  /* Polish pass: a whisper of fill, so the arrows stay elegant and never
     compete with the hero content; the hover still gives clear affordance. */
  background-color: rgba(3, 25, 50, 0.32);
  color: var(--color-text-on-dark);
  cursor: pointer;
  transition: background-color var(--transition-base);
}

.c-hero__arrow:hover {
  background-color: rgba(3, 25, 50, 0.6);
}

.c-hero__dots {
  display: flex;
  justify-content: center;
  gap: var(--space-xs);
  margin: 0;
  padding: 0;
  list-style: none;
}

.c-hero.is-enhanced .c-hero__dots {
  position: absolute;
  inset-inline: 0;
  bottom: var(--space-lg);
  z-index: var(--z-base);
}

.c-hero__dot {
  width: var(--space-xs);
  height: var(--space-xs);
  padding: 0;
  border: 0;
  border-radius: var(--radius-full);
  background-color: rgba(255, 255, 255, 0.45);
  cursor: pointer;
  transition: background-color var(--transition-base), width var(--transition-base);
}

.c-hero__dot[aria-current="true"] {
  width: var(--space-lg);
  background-color: var(--color-accent);
}

@media (max-width: 767px) {
  .c-hero__slide {
    min-height: 0;
  }

  .c-hero__content {
    padding-block: var(--space-2xl);
  }

  .c-hero__actions .c-btn {
    width: 100%;
  }
}


/* ========================== TRUST STRIP ================================
   SIGNATURE MOVE (contract-mandated): the card straddles the hero boundary,
   pulled up by --trust-overlap so it overlaps the hero's lower edge. Desktop
   and tablet only — the token goes to 0 on mobile, where the overlap would read
   as a rendering error.

   TREATMENT. One unified institutional panel, never a row of floating cards.
   The items share a single deep navy surface, a single shadow and a single
   radius; they are separated only by translucent hairlines. Anything that gave
   an item its own background, border or elevation would break the "one
   institutional strip" reading. The navy is --color-primary-900, one step
   deeper than the hero's --color-primary-800: the panel straddles the hero for
   --trust-overlap of its height and must still read as a panel there, which a
   shared tone would erase. The only border is a translucent hairline
   (--color-border-on-dark), which keeps the edge visible where the panel
   crosses the hero without the heavy box the brief rules out.

   The gold accent is a hairline top edge on the whole strip, drawn as a
   ::before rather than a border so it can sit inside the rounded corners
   without a second radius calculation. Its thickness is --space-3xs, the same
   token as .c-section-header__dash: those are the page's only two thin gold
   indicators and they should not disagree. A literal px height here would also
   breach the tokens rule against literal space values.

   Gold appears exactly twice on the band — the top edge and the icon glyphs —
   and nowhere else: it is wayfinding, not decoration. */
.c-trust {
  position: relative;
  z-index: var(--z-base);
  overflow: hidden; /* clips the gold accent to the radius */
  margin-block-start: calc(var(--trust-overlap) * -1);
  padding-block: var(--space-sm);
  padding-inline: var(--space-sm);
  background-color: var(--color-primary-900);
  border: 1px solid var(--color-border-on-dark);
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow-lg);
}

/* Thin gold top edge across the full width of the strip. Decorative: it carries
   no information a screen reader needs, and being a pseudo-element it is not in
   the accessibility tree at all. */
.c-trust::before {
  content: "";
  position: absolute;
  inset-block-start: 0;
  inset-inline: 0;
  height: var(--space-3xs);
  background-color: var(--color-accent);
}

.c-trust__item {
  display: flex;
  flex-direction: column;
  align-items: center;
  /* Polish pass: centred on the vertical axis too, so every icon/label/value
     pair sits optically centred in its cell. The strip keeps its single
     surface, radius, shadow and its approved height (no block padding
     added — the strip's own padding already carries the rhythm). */
  justify-content: center;
  gap: var(--space-2xs);
  padding-inline: var(--space-lg);
  text-align: center;
}

/* Divider between items, not around them: the + selector can never match the
   first item, so a single-item strip carries no divider at all. Translucent
   white (--color-border-on-dark), low-contrast against the navy on purpose —
   the divider groups, it does not fence. */
.c-trust__item + .c-trust__item {
  border-inline-start: 1px solid var(--color-border-on-dark);
}

/* Two per row from 1023 down (see the grid change at the same breakpoint in
   20-layout.css): the first item of each row must lose its leading divider, or
   the rule would float at the row's left edge. Rows after the first gain a
   horizontal rule instead. An odd item count stretches its last item across
   the full row (20-layout.css), and that item is an odd child, so it correctly
   loses the leading divider too. The breakpoint here MUST match the grid's. */
@media (max-width: 1023px) {
  .c-trust__item:nth-child(odd) {
    border-inline-start: 0;
  }

  .c-trust__item:nth-child(n + 3) {
    border-block-start: 1px solid var(--color-border-on-dark);
    margin-block-start: var(--space-md);
    padding-block-start: var(--space-md);
  }
}

/* The icon sits above the label in its own disc, which gives every glyph the
   same optical size regardless of how wide its own drawing is. The tile is
   --space-2xl, matching .c-programme__icon: those are the two icon tiles on the
   page and they should agree. Circular here rather than rounded-square, because
   the programme tile carries a category colour and this one must not be mistaken
   for one.

   Gold glyph on --color-primary-700: the badge is one step lighter than the
   panel's --color-primary-900, so it reads as a seat for the icon without
   introducing a colour the palette does not already hold, and its gold is the
   band's second and last gold. Every item wears the identical treatment. */
.c-trust__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: var(--space-2xl);
  height: var(--space-2xl);
  color: var(--color-accent);
  background-color: var(--color-primary-700);
  border-radius: var(--radius-full);
}

/* Eyebrow, not a title: small, uppercase, tracked, and visually secondary to
   the value below it. White like the value — on navy a muted label would slip
   below the institutional legibility the band needs; the size, weight and
   tracking carry the hierarchy instead.

   --leading-flat rather than the inherited --leading-body. The label is always
   one uppercased line, so 1.6 leading was adding 7px of empty box under a 12px
   glyph — enough on its own to push the desktop strip to 122px, past the 120px
   ceiling. Flat leading is what the theme already uses for other single-line UI
   text (.c-btn, .c-faculty__placeholder, .c-notice__date), and uppercase has no
   descenders to clip. It also tightens the label to the value it introduces, so
   the pair reads as one unit instead of two stacked lines. */
.c-trust__label {
  display: block;
  font-size: var(--text-xs);
  font-weight: var(--font-weight-semibold);
  letter-spacing: var(--tracking-eyebrow);
  line-height: var(--leading-flat);
  text-transform: uppercase;
  color: var(--color-text-on-dark);
}

/* The value carries the emphasis — it is the thing being said. */
.c-trust__value {
  display: block;
  font-size: var(--text-body-lg);
  font-weight: var(--font-weight-semibold);
  line-height: var(--leading-heading);
  color: var(--color-text-on-dark);
  text-wrap: balance;
}

/* "Since" in "Since 1964": grammar, so it recedes and lets the date dominate.
   --color-text-on-dark-muted, the on-dark hierarchy step. */
.c-trust__value-lead {
  font-size: var(--text-sm);
  font-weight: var(--font-weight-regular);
  color: var(--color-text-on-dark-muted);
}

/* Separator between programme names. Not gold even on navy, where it would
   clear contrast easily: gold on this band is wayfinding (the top edge, the
   icons), and a bullet is punctuation. --color-text-on-dark-muted keeps it a
   quiet part of the value it parses. The template already emits a literal space
   each side for screen readers, so the optical margin here is small. */
.c-trust__sep {
  margin-inline: 0.1em;
  color: var(--color-text-on-dark-muted);
}

@media (max-width: 1023px) {
  .c-trust__value {
    font-size: var(--text-body);
  }
}

@media (max-width: 767px) {
  /* Overlap is removed by the token; the card also loses its lift so it does
     not float over a band it no longer overlaps. */
  .c-trust {
    padding-block: var(--space-md);
    padding-inline: var(--space-xs);
    box-shadow: var(--shadow-sm);
  }

  .c-trust__item {
    padding-inline: var(--space-sm);
  }

  /* The icon tile stays at --space-2xl on mobile. Stepping it down to
     --space-xl (32px) left only 3px of clearance around the 26px glyph, so the
     disc read as a ring drawn on the icon rather than as a tile behind it. The
     next token down is not usable, and inventing a 40px value would breach the
     tokens rule, so the tile does not change size here. */
}

/* Narrow mobile keeps the 2x2 grid, so each cell is only ~160px wide. The item
   padding is cut back and the value steps down one size, which is what lets
   "B.Ed. • M.Ed. • Ph.D." hold a single line instead of breaking after a
   separator. --text-sm is the floor here: the 16px body minimum applies to
   running prose, not to this label pair, and 14px is still above the 12px
   metadata floor. */
@media (max-width: 479px) {
  .c-trust__item {
    padding-inline: var(--space-2xs);
  }

  .c-trust__value {
    font-size: var(--text-sm);
  }
}

/* The single-column case is gone — the grid stays 2x2 to the narrowest
   supported width — so no extra divider rule is needed below 480. The 1023px
   two-per-row rules above are correct for every layout the strip now has. */

/* ========================== PROGRAMME CARD =============================
   White card on a white band; the border is the only thing separating it from
   the page, so it is functional and must not be lightened. */
.c-programme {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
  height: 100%;
  padding: var(--space-lg);
  background-color: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  transition:
    border-color var(--transition-base),
    box-shadow var(--transition-base),
    transform var(--transition-base);
}

.c-programme:hover {
  border-color: var(--color-primary-500);
  box-shadow: var(--shadow-sm);
  transform: translateY(-2px);
}

/* Icon tile: pale tint + saturated glyph. Category tokens are set by a data
   attribute so an unmapped term falls back to navy, never a random hue. */
.c-programme__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--space-2xl);
  height: var(--space-2xl);
  border-radius: var(--radius-lg);
  background-color: var(--color-cat-default-bg);
  color: var(--color-cat-default-fg);
}

.c-programme[data-category="1"] .c-programme__icon {
  background-color: var(--color-cat-1-bg);
  color: var(--color-cat-1-fg);
}

.c-programme[data-category="2"] .c-programme__icon {
  background-color: var(--color-cat-2-bg);
  color: var(--color-cat-2-fg);
}

.c-programme[data-category="3"] .c-programme__icon {
  background-color: var(--color-cat-3-bg);
  color: var(--color-cat-3-fg);
}

.c-programme[data-category="4"] .c-programme__icon {
  background-color: var(--color-cat-4-bg);
  color: var(--color-cat-4-fg);
}

.c-programme__body {
  /* Flex so the footer's auto top-margin can push it to the card's bottom edge.
     Without this the grid's equal-height rows leave ragged whitespace under the
     shorter cards. */
  display: flex;
  flex: 1;
  flex-direction: column;
  gap: var(--space-2xs);
  min-width: 0;
}

/* Unlinked card: a listing, not a control. It keeps the card's surface and
   spacing so the row stays visually regular, but loses every affordance that
   promises a destination — the lift, the border change and the shadow. */
.c-programme--static {
  cursor: default;
}

.c-programme--static:hover {
  border-color: var(--color-border);
  box-shadow: none;
  transform: none;
}

.c-programme__title {
  font-size: var(--text-h3);
}

.c-programme__title a {
  color: inherit;
  text-decoration: none;
}

/* Whole-card affordance without a clickable div: the real anchor is stretched
   over the card, so the accessible name and keyboard behaviour stay correct. */
.c-programme__title a::after {
  content: "";
  position: absolute;
  inset: 0;
}

.c-programme__subtitle {
  font-size: var(--text-sm);
  color: var(--color-text-muted);
}

/* Meta sits directly under the copy; the "view details" cue is pushed to the
   card's bottom edge so cards of differing text length share a baseline. */
.c-programme__meta {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-sm);
  padding-block-start: var(--space-sm);
  border-block-start: 1px solid var(--color-border-subtle);
  font-size: var(--text-xs);
  color: var(--color-text-muted);
}

/* THE THING THAT KEEPS THE FOUR CTAs ON ONE LINE.
   The footer holds the divider, the duration and the CTA as one block and is
   pushed to the bottom of the card by margin-block-start: auto, so its own
   height is what aligns — not the height of the copy above it.

   Pushing .c-programme__more on its own was not enough: B.Ed. (UPRTOU)'s
   subtitle runs to three lines where B.Ed.'s runs to one, so the divider and the
   duration line landed at different heights on each card even when the CTA
   itself did not. Grouping them means all three rows align together.

   margin-block-start: auto is removed from .c-programme__more for the same
   reason — two competing auto margins in one flex column split the free space
   between them instead of collecting it above the footer. */
.c-programme__footer {
  margin-block-start: auto;
  /* A floor for the gap above the divider. The auto margin resolves to 0 on the
     tallest card in the row, and without this its divider would sit 4px under
     the subtitle while every other card's had room. */
  padding-block-start: var(--space-xs);
}

.c-programme__more {
  padding-block-start: var(--space-sm);
  font-size: var(--text-ui);
  font-weight: var(--font-weight-semibold);
  color: var(--color-primary-500);
}

/* MANDATORY MOBILE TRANSFORMATION: compact horizontal rows, not shrunken
   cards. Icon left, text right, meta inline. */
@media (max-width: 767px) {
  .c-programme {
    flex-direction: row;
    align-items: center;
    gap: var(--space-md);
    padding: var(--space-md);
  }

  .c-programme__icon {
    width: var(--space-xl);
    height: var(--space-xl);
  }

  .c-programme__body {
    min-width: 0;
  }

  /* The footer stops being a footer here. In a compact row there is no card
     height to fill, so the auto margin has nothing to distribute and the
     divider would draw a rule across a two-line row. */
  .c-programme__footer {
    margin-block-start: var(--space-2xs);
    padding-block-start: 0;
  }

  .c-programme__meta {
    margin-block-start: 0;
    padding-block-start: 0;
    border-block-start: 0;
  }

  .c-programme__more {
    padding-block-start: var(--space-2xs);
  }
}


/* =========================== FACULTY CARD ==============================
   ONE CARD, TWO CONTEXTS. This component renders both the homepage showcase
   (three across, inside the people band's wide column) and the /faculty/ archive
   (four across). There is no second "lead" component: two components meant the
   same person was presented two different ways depending on which page you
   arrived from.

   The Head of Department is distinguished by .c-faculty--hod — a gold frame, a
   gold rule under the photograph and a badge — never by a different card.

   THE CARD IS A VERTICAL TOWER: PHOTOGRAPH, THEN NAME, THEN RECORD.
   This is the approved reference's arrangement and it is restored deliberately.
   An intermediate pass made the card a horizontal row — plate left, text right —
   to buy height back. It bought it at the cost of the photograph: a fixed 96px
   plate column made every face a thumbnail, which is the one thing the reference
   is emphatic about.

   Height is instead controlled by what the reference actually got wrong for this
   data: it spent three filled tiles and a full-size button on four short values.
   Those are now compact label/value rows and a small button. The photograph keeps
   the full width of the card.

   THE PLATE IS 1:1, AND THAT RATIO IS MEASURED, NOT CHOSEN.
   probe-portrait-vertical.php walked all twelve source files and found, per file,
   the widest frame that still contains the head and the top of the shoulders once
   object-fit: cover has filled it:

     Dr. Seemant kumar Ray   1.05:1   <- the binding constraint
     Prof. Sudhanshu Sinha   1.16:1
     Prof. Shraddha Singh    1.17:1
     Dr. Pashant kumar P.    1.18:1
     Dr. Arvind Singh        1.20:1
     Dr. Vaibhav Singh       1.30:1
     Prof. Reeta Singh       1.35:1
     Mr. Ray Sahab Yadav     1.36:1
     Dr. Geeta Singh         2.22:1
     Dr. Sulekha Singh       2.41:1
     the two landscape files  no constraint (no detectable background)

   1:1 clears the 1.05:1 floor on every file. 5:4 (1.25) does not — it would cut
   the shoulders off five of the twelve. Re-run that probe before replacing a
   photograph, and do not widen this frame on taste.

   THE APPROVED REFERENCE CORROBORATES THIS INDEPENDENTLY. Measured off
   design-reference/homepage-approved-reference.png.png (a 1024px composite, x1.40625
   to the 1280 container), the reference's own faculty card photograph is 113x101
   reference px = 159x142 at 1440, a ratio of 1.119:1. The frame in the approved
   design is therefore roughly square and very slightly landscape — not the 4:5
   portrait an earlier pass used. 1:1 sits between the reference's 1.119 and the
   sources' 1.05 ceiling.

   Two further facts from that measurement, recorded so they are not rediscovered:

     - The reference card box is 113x200 reference px = 159x281 at 1440, which is
       proportionally shorter than this card. It carries a name, a designation and
       a row of social icons; it does NOT carry the brief's four record rows. The
       extra height here is those four rows, and it is not recoverable without
       dropping fields the brief names.
     - The reference runs FOUR cards across the faculty column at 113px each. This
       theme runs three at 255px, which is the deviation recorded in
       sections/faculty.php: four tracks in the 814px column give 185px cards, and
       the omitted records are reached through "View all faculty" rather than hidden.

   Equal heights across a row come from .l-grid stretching its items plus
   height: 100% here; the button's auto top margin spends whatever slack a
   stretched card has, so no card ends with a gap above its own bottom edge. */
.c-faculty {
  position: relative;
  display: flex;
  flex-direction: column;
  height: 100%;
  overflow: hidden;
  background-color: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  transition: box-shadow var(--transition-base);
}

.c-faculty:hover {
  box-shadow: var(--shadow-sm);
}

/* The Head of Department card. A gold hairline frame and a 2px gold top edge —
   the accent's thin-indicator role at card scale, the same role as
   .c-section-header__dash. Not a fill: a gold field is forbidden, and one filled
   card in a row of twelve would read as a selected state rather than as a rank.

   The badge inside carries the meaning; this is the supporting cue, so the
   distinction is never colour alone. */
.c-faculty--hod {
  border-color: var(--color-border-accent);
  border-block-start: var(--space-3xs) solid var(--color-accent);
  box-shadow: var(--shadow-sm);
}

.c-faculty--hod:hover {
  box-shadow: var(--shadow-md);
}

/* ---- The portrait plate ----
   Full width of the card, no column of its own. Three of the twelve portraits are
   background-removed PNGs with a genuinely transparent field (verified
   per-pixel), so the surface behind them IS the visible backdrop of the
   photograph rather than decoration. That surface is on the FRAME below, not
   here.

   flex: 0 0 auto so a stretched card never stretches the photograph with it: the
   frame holds its measured ratio and the body absorbs the extra height. */
.c-faculty__plate {
  position: relative;
  flex: 0 0 auto;
  /* Separates the photograph from the name beneath it. On the HOD card this
     hairline becomes the reference's gold rule (below). */
  border-block-end: 1px solid var(--color-border);
}

.c-faculty--hod .c-faculty__plate {
  border-block-end: var(--space-3xs) solid var(--color-accent);
}

/* The frame carries the measured 1:1 ratio (see the note above the component).
   Square corners: the plate meets the card's own rounded corners, and a second
   radius inside them reads as a sticker sitting on the card. */
.c-faculty__plate .c-media {
  aspect-ratio: var(--ratio-faculty-card);
  border-radius: 0;
  background-color: var(--color-photo-plate);
}


/* cover, with the crop measured rather than assumed.

   contain is wrong here: the twelve sources run 0.688 to 1.749 wide-over-tall, so
   in a 1:1 frame the widest letterboxes and its photograph ends well above the
   others. A row of plates with photographs finishing at different heights is
   exactly the ragged result this grid must not have.

   WHAT cover COSTS, and why it is safe. probe-portrait-extent.php scanned the head
   band of all twelve sources for the horizontal extent of the subject against the
   background. The subject's centre sits between 44.8% and 53.1% of file width on
   all twelve, and every portrait needs at most 61.6% of its own width to hold the
   subject symmetrically. A 1:1 frame is WIDER than eleven of the twelve sources,
   so for those it keeps 100% of the file's width and crops the bottom instead —
   which is why the ratio was chosen from the shoulder line rather than from the
   horizontal extent. The two landscape files (#4 at 1.749, and #12 which is a
   full-bleed photograph with no detectable background) are cropped at the sides,
   and both have their subject at 49.9% so the crop stays symmetric.

   object-position: center top keeps the vertical overflow leaving from the bottom,
   never off the top of a head; measured headroom above the subject is 0%–10.2%, so
   top is the only safe vertical anchor.

   Re-run that probe before changing a source photograph. */
.c-faculty__photo {
  object-fit: cover;
  object-position: center top;
}

/* ---- The Head of Department badge ----
   Absolutely positioned over the plate's top-left corner. Navy plate, gold crest,
   white label: white on navy is 14.1:1 and the gold glyph is 8.1:1 (both
   measured), so the badge survives a user stylesheet dropping the fill.

   The plate is now the card's full width — 255px in the showcase, 290px on the
   archive — so the FULL PHRASE fits and is the visible label, as in the reference.
   The initialism was a concession to the 96px plate of the horizontal pass and is
   gone; there is no longer a visible/accessible name split to keep in sync.

   Measured against the subject extents: the leftmost subject edge across the
   twelve sources is 20.5% of file width, so a badge inset --space-xs from the
   plate's top-left stays clear of every head. */
.c-faculty__flag {
  position: absolute;
  inset-block-start: var(--space-xs);
  inset-inline-start: var(--space-xs);
  z-index: var(--z-base);
  display: flex;
  align-items: center;
  gap: var(--space-2xs);
  max-width: calc(100% - var(--space-lg));
  padding: var(--space-3xs) var(--space-xs);
  border-radius: var(--radius-sm);
  background-color: var(--color-primary-700);
  color: var(--color-text-on-dark);
  /* 11px is BELOW the --text-xs metadata floor and is the one deliberate exception
     on this card. It is not read as metadata: it is a rank marker in a badge, bold
     uppercase at 14.1:1 on navy. Not to be reused elsewhere. */
  font-size: 0.6875rem;
  font-weight: var(--font-weight-bold);
  letter-spacing: var(--tracking-ui);
  line-height: var(--leading-heading);
  text-transform: uppercase;
}

.c-faculty__flag-icon {
  display: inline-flex;
  flex: 0 0 auto;
  color: var(--color-accent);
}

/* ---- Body ----
   CENTRED, not ranged left. The reference centres the name, the ornament and the
   chip row under the photograph, and the four record rows are label/value pairs
   which read as a block under them. flex: 1 1 auto so the body — never the
   photograph — absorbs the height a stretched grid track adds.

   The gap is --space-xs, not --space-sm: with four record rows plus a name, an
   ornament, a chip row and a button, every 4px of gap is 28px of card height. */
.c-faculty__body {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  align-items: center;
  gap: var(--space-xs);
  min-width: 0;
  padding: var(--space-sm) var(--space-sm) var(--space-md);
  text-align: center;
}

/* ---- Name ----
   --text-body, not --text-h3. At --text-h3 (19–22px) over the showcase's ~231px
   content width the longest of the twelve names ("Dr. Pashant kumar Pandey", 24
   characters) is three wrapped lines; at --text-body it is two at 1440 and the
   card is 40px shorter for it.

   balance evens the wrap rather than leaving a one-word last line. Engines without
   it fall back to the default wrap, so nothing is lost. */
.c-faculty__name {
  color: var(--color-primary-700);
  font-size: var(--text-body);
  font-weight: var(--font-weight-bold);
  line-height: var(--leading-heading);
  letter-spacing: var(--tracking-display);
  text-wrap: balance;
}

.c-faculty__name a {
  color: inherit;
  text-decoration: none;
}

.c-faculty__name a:hover {
  color: var(--color-primary-500);
  text-decoration: underline;
  text-underline-offset: 0.15em;
}

/* ---- Gold ornament under the name ----
   Two thin rules with a rotated square between them: the same thin-indicator
   accent role as .c-section-header__dash, and centred under the name exactly as
   the reference has it.

   The rules are the wrapper's pseudo-elements so the gem can rotate without them.
   Fixed widths, not flex: 1 — this is a punctuation mark, and a rule growing to
   the card's full width would read as a divider cutting the card in half. */
.c-faculty__ornament {
  display: flex;
  align-items: center;
  gap: var(--space-3xs);
}

.c-faculty__ornament::before,
.c-faculty__ornament::after {
  content: "";
  width: var(--space-md);
  height: var(--space-3xs);
  border-radius: var(--radius-full);
  background-color: var(--color-accent);
}

.c-faculty__gem {
  width: var(--space-2xs);
  height: var(--space-2xs);
  background-color: var(--color-accent);
  transform: rotate(45deg);
}

/* ---- Credential chips ----
   The qualification string, segmented on its commas into one chip per credential.
   The mortarboard ring leads the row. Seven records have three tokens, five have
   four (measured), and no token exceeds 5 characters.

   justify-content: center so the row sits under the centred name and ornament.

   The ul is display: contents, so the ring and every chip are siblings in ONE
   wrapping flex row. With the ul as its own flex box the chips laid out inside the
   space left of the ring instead, which put a wrapped chip out of line with the
   row above it.

   List semantics are unaffected: display: contents removes the ul from the layout
   tree only, not from the accessibility tree. list-style must then be set on the
   ITEM — with no ul box, the ul's list-style does not apply and markers appear.

   OUTLINED, NOT FILLED. --color-border-accent is --color-accent held back to
   border weight: four saturated gold pills on a white card would be a colour
   field, which the accent rules forbid, and text on them would fail contrast.
   Navy on the pale warm fill is 13.1:1 (measured). */
.c-faculty__credentials {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: var(--space-3xs);
}

/* A ring, not a filled disc: it belongs to the chip row it introduces, so it
   carries the chips' outline weight rather than the navy fill the metadata icons
   use. That contrast is what separates "credentials" from "service record" without
   a second border or a rule between them. */
.c-faculty__credentials-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: var(--space-md);
  height: var(--space-md);
  border: 1px solid var(--color-border-accent);
  border-radius: var(--radius-full);
  color: var(--color-primary-700);
}

.c-faculty__quals {
  /* No box of its own, so the ring and the chips share one wrapping row.
     margin/padding are still zeroed for engines that ignore display: contents and
     fall back to a block ul. */
  display: contents;
  margin: 0;
  padding: 0;
}

.c-faculty__qual-chip {
  list-style: none;
  padding: 1px var(--space-2xs);
  border: 1px solid var(--color-border-accent);
  border-radius: var(--radius-sm);
  background-color: var(--color-surface-accent);
  color: var(--color-primary-700);
  font-size: var(--text-xs);
  font-weight: var(--font-weight-medium);
  line-height: 1.4;
  white-space: nowrap;
}

/* ---- Service record ----
   The four rows in the brief: Designation, Research Interests, Joining Date and
   Grade Pay. A LIST OF ROWS, not the filled tiles of the single-card reference:
   three warm-filled tiles on a 231px card are three boxes inside a box costing
   --space-sm of padding each, which is 72px of card height spent on chrome. The
   gold-underlined label plus value is kept; the fill is dropped, and the navy icon
   disc carries the tile's weight instead.

   ALL FOUR ROWS ALWAYS RENDER, even though designation and grade pay are empty on
   all twelve records today (measured — see the template header). An omitted row
   would make the cards differ in shape from one another and would hide which
   fields the institution still owes; a labelled em dash does neither. */
.c-faculty__record {
  display: flex;
  flex-direction: column;
  gap: var(--space-2xs);
  width: 100%;
  margin: 0;
  padding: 0;
  list-style: none;
  /* The rows are label/value pairs and read left-to-right, so they range left
     inside the otherwise centred body. */
  text-align: start;
}

/* Row: icon disc, then the label and its value on one line.
   align-items: start, not center — the research row's value drops below its label
   and runs to two clamped lines, and a centred disc would float halfway down it. */
.c-faculty__meta {
  display: flex;
  align-items: start;
  gap: var(--space-xs);
  min-width: 0;
}


/* Navy fill with a gold glyph: 8.1:1 measured. The counterpart to the credential
   ring above — filled means "record", outlined means "credential".

   --space-md (16px), down from --space-lg (24px): four discs at 24px are 96px of
   card height on their own, and the glyph inside is 12px either way. */
.c-faculty__meta-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: var(--space-md);
  height: var(--space-md);
  /* Aligns the disc's optical centre with the label's cap height rather than with
     the top of the label's line box. */
  margin-block-start: var(--space-3xs);
  border-radius: var(--radius-full);
  background-color: var(--color-primary-700);
  color: var(--color-accent);
}

/* ONE LINE PER ROW WHERE THE VALUE FITS: "Joining Date: 1 Jul 2005", not the
   label stacked over its value. That is the approved reference's row, and on
   three of the four rows it halves the row: a 15px label line plus a 17px value
   line becomes one ~17px line.

   A WRAPPING FLEX ROW, NOT A TWO-COLUMN GRID. Both items are intrinsically
   sized, so the line breaks only when the value genuinely cannot sit beside its
   label. Measured against the narrowest case that matters — the showcase card at
   1440 gives 207px of row after the icon disc and its gap — "JOINING DATE:",
   "DESIGNATION:" and "GRADE PAY:" all fit beside their values, while
   "RESEARCH INTERESTS:" leaves ~87px against stored values of 22-58 characters,
   so that value alone drops to the next line and clamps there (below).

   "On the same line wherever possible" is therefore a consequence of the layout,
   not a per-row exception in the template: no row is special-cased, and a
   designation or grade pay figure entered later will sit inline if it fits and
   wrap if it does not.

   align-items: baseline, not stretch or center. The label is 10px and the value
   12px; aligning their boxes rather than their baselines leaves the label riding
   high against the value's x-height.

   row-gap stays at flexbox's 0: when the value does wrap, it belongs tight under
   its own label, and any gap there would read as a new row. */
.c-faculty__meta-body {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  column-gap: var(--space-2xs);
  min-width: 0;
}

/* The label is a 10px eyebrow — the second and last sub-floor size on this card,
   for the same reason as the badge: a tracked uppercase marker introducing the
   value beside it, not body metadata. --color-text-muted on white is 6.34:1
   (measured), comfortably past AA at this weight. */
.c-faculty__meta-label {
  color: var(--color-text-muted);
  font-size: 0.625rem;
  font-weight: var(--font-weight-semibold);
  letter-spacing: var(--tracking-ui);
  line-height: 1.5;
  text-transform: uppercase;
  /* 10-base.css sets overflow-wrap: break-word globally, which broke "JOINING
     DATE" mid-word as "JOININ / G DATE" once the content column narrowed to 72px
     at 1024. A two-word label must break between its words or not at all. */
  overflow-wrap: normal;
}

/* The colon that makes "Designation: Assistant Professor" read as one phrase.
   It is punctuation between two elements that are already separate nodes, so it
   is generated here rather than baked into the translatable string — a
   translator should not have to carry English punctuation to get the layout, and
   the same label is reused by the profile page without a colon. */
.c-faculty__meta-label::after {
  content: ":";
}

.c-faculty__meta-value {
  color: var(--color-text-primary);
  font-size: var(--text-xs);
  font-weight: var(--font-weight-medium);
  line-height: 1.4;
}

/* The "not published" state. Muted and lighter than a real value, so a scan of the
   card separates published facts from pending ones without reading the labels. The
   em dash is aria-hidden and the row carries a visually hidden phrase instead (see
   the template) — a screen reader hears "Grade pay, not published", never "dash". */
.c-faculty__empty {
  color: var(--color-text-muted);
  font-weight: var(--font-weight-regular);
}

/* Research interests are the one prose field on the card and the only one that can
   run long: the nine stored values are 22–58 characters (measured across all
   twelve records; three are empty). Clamped to two lines rather than truncated in
   PHP, so the full text stays in the markup for search engines and assistive
   technology while the card keeps a predictable height.

   flex-basis: 100% puts this ONE value on its own line under its label, and is
   what makes the clamp meaningful. Left to intrinsic sizing a flex item is laid
   out at max-content — a 58-character sentence measured as a single unbroken line
   — so it would either overflow the card or wrap unpredictably depending on the
   stored string. Declaring the full-width basis is what turns "too long to sit
   beside its label" from an emergent accident into the defined behaviour, and it
   is the reason the other three rows stay inline: they do not carry this class.

   The modifier is built in the template from the row's own key
   (`c-faculty__meta--<key>`), so a search for this literal selector will not find it
   in the PHP. Renaming the 'research' key renames this class.

   -webkit-line-clamp is the only widely supported mechanism for this and is
   implemented in every current engine including Firefox. Without support the text
   simply shows in full and the card grows — legible, just taller.

   The :not() excludes the em-dash state. A dash is one character; giving it its
   own full-width line under the label would make the three empty research rows
   taller than the nine filled ones are wide, for no gain. Unpublished research
   therefore reads "RESEARCH INTERESTS: —" on one line. */
.c-faculty__meta--research .c-faculty__meta-value:not(.c-faculty__empty) {
  flex: 0 0 100%;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  overflow: hidden;
}

/* ---- View Profile button ----
   .c-btn--secondary-dark at --sm, given the navy fill and gold label. Everything
   else — hover, focus ring, disabled, the arrow animation — still comes from
   .c-btn, so this cannot drift from the page's button system.

   Gold label on --color-primary-700 is 8.1:1, 11.1:1 on hover (both measured).
   That is the one sanctioned direction for this pair: gold FILL with white text is
   forbidden at 1.9:1, and this is its inverse.

   min-height is reduced from the 44px comfort target to --space-xl (32px), which
   is above the WCAG 2.2 target-size minimum (--tap-target-min, 24px). The brief
   asks for a small button and there are twelve of them; at 44px the button was the
   tallest single element in the card. Scoped to this card only.

   margin-block-start: auto pins it to the card's foot, so a row of cards has its
   buttons on one baseline however long the names above them run — and it is what
   absorbs the slack a stretched grid track adds, rather than leaving a gap. */
.c-faculty__profile {
  min-height: var(--space-xl);
  margin-block-start: auto;
  padding: var(--space-2xs) var(--space-sm);
  background-color: var(--color-primary-700);
  color: var(--color-accent);
  font-size: var(--text-xs);
  letter-spacing: normal;
}

.c-faculty__profile:hover {
  background-color: var(--color-primary-800);
  color: var(--color-accent-strong);
}

/* Shown only when no photograph is on record. Decorative monogram, hidden from
   assistive technology; the name below it carries the meaning. Matches the plate's
   own ratio, so a record without a photograph keeps the grid's rhythm. */
.c-faculty__placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
  aspect-ratio: var(--ratio-faculty-card);
  background-color: var(--color-primary-100);
  color: var(--color-primary-700);
  font-size: var(--text-display);
  font-weight: var(--font-weight-bold);
  line-height: var(--leading-flat);
}

/* ======================== FACULTY SHOWCASE =============================
   The homepage faculty column: header, the row of three cards, then the archive
   link. A flex column so the link's position is controlled explicitly rather
   than by whatever height the column happens to be stretched to. */
.c-faculty-showcase {
  display: flex;
  flex-direction: column;
}

/* The archive link sits directly under the cards.

   This is the fix for the band's worst piece of dead space. The notices column
   ran 226px taller than the faculty column, and the link previously carried
   .u-text-center .u-mt-lg — centred under a column whose leftover height opened
   as a gap between the cards and the link. It is now left aligned with the cards
   and the section heading, one space-lg below the grid, and the residual slack is
   left at the foot of the column where it reads as band padding. */
.c-faculty-showcase__more {
  margin-block-start: var(--space-lg);
}

/* ---- Narrow cards ----
   THE TWO GRIDS REACH A NARROW CARD AT DIFFERENT VIEWPORTS, so each is scoped
   separately. Measured card widths:

                        1440   1280   1024    768    390
     showcase (3 up)     255    255    200    227    358
     archive  (4 up)     290    290    226    352    171   (2 up below 1024)

   They move in opposite directions between 1024 and 768: the archive drops to two
   tracks and GROWS to 352px while the showcase holds three and sits at 227px. One
   media query applied to both would have to shrink the 352px archive card in order
   to serve the 227px showcase one, which is the defect the first attempt at this
   had.

   A container query is the natural expression of "this card is narrow" and was
   tried first. It does not work here: a container query cannot restyle the element
   it queries against, so with container-type on .c-faculty the descendant rules
   applied while the card-level ones were silently dropped. Introducing a wrapper
   element purely to hold the containment was not worth it for a component whose
   two contexts are both known and measurable.

   The compact declarations below are therefore duplicated across two blocks. That
   duplication is deliberate and is the price of scoping each grid to the viewport
   range where ITS cards are narrow.

   The PHOTOGRAPH is never touched by these blocks. It is the card's subject and it
   scales with the card's own width; what gives way is padding, the name's size and
   the button's inline padding.

   .c-faculty__record's gap is NOT in these blocks. It used to be tightened to
   --space-2xs here, from a base of --space-xs; the base is now --space-2xs at every
   width, because the single-line rows made 8px between them read as four separate
   items rather than one list. A narrow-card override to the value the base already
   carries is dead weight, so it is gone from all three blocks. */

/* Both grids are narrow at 1024–1279: showcase 200px, archive 226px. */
@media (min-width: 1024px) and (max-width: 1279px) {
  .l-grid--faculty-featured .c-faculty__body,
  .l-grid--faculty .c-faculty__body {
    gap: var(--space-2xs);
    padding: var(--space-xs) var(--space-xs) var(--space-sm);
  }

  /* Two lines of --text-sm is shorter and easier to scan than three of
     --text-body, which is what a ~176px card produced for the longest name. */
  .l-grid--faculty-featured .c-faculty__name,
  .l-grid--faculty .c-faculty__name {
    font-size: var(--text-sm);
  }

  /* "View Profile" plus its arrow measures ~90px at --text-xs; the padding and the
     gap give way rather than the label. The 32px tap height is untouched. */
  .l-grid--faculty-featured .c-faculty__profile,
  .l-grid--faculty .c-faculty__profile {
    gap: var(--space-3xs);
    padding-inline: var(--space-2xs);
  }
}

/* At 768–1023 only the SHOWCASE is narrow (227px). The archive is two across here,
   so its cards are 352px — wider than at any desktop width — and stay roomy. */
@media (min-width: 768px) and (max-width: 1023px) {
  .l-grid--faculty-featured .c-faculty__body {
    gap: var(--space-2xs);
    padding: var(--space-xs) var(--space-xs) var(--space-sm);
  }

  .l-grid--faculty-featured .c-faculty__name {
    font-size: var(--text-sm);
  }

  .l-grid--faculty-featured .c-faculty__profile {
    gap: var(--space-3xs);
    padding-inline: var(--space-2xs);
  }
}

/* Below 768 the ARCHIVE holds two cards per row by contract, so its cards are
   171px at 390. The vertical card survives that width where the horizontal one did
   not — the photograph is the card's full width rather than a fixed 72px column —
   but the record rows have only ~139px of value column, so their padding and gaps
   are tightened and the badge loses its inline padding.

   The showcase is exempt: it collapses to ONE column on mobile, so its cards are
   358px, wider than at any desktop width. */
@media (max-width: 767px) {
  .l-grid--faculty .c-faculty__body {
    gap: var(--space-2xs);
    padding: var(--space-xs) var(--space-2xs) var(--space-sm);
  }

  .l-grid--faculty .c-faculty__name {
    font-size: var(--text-sm);
  }

  .l-grid--faculty .c-faculty__meta {
    gap: var(--space-2xs);
  }

  .l-grid--faculty .c-faculty__profile {
    gap: var(--space-3xs);
    padding-inline: var(--space-2xs);
  }

  /* "Head of Department" is 17 characters; on a 171px plate it wraps to two lines,
     which is acceptable over the top of a photograph but not with the desktop
     badge's inline padding as well. */
  .l-grid--faculty .c-faculty__flag {
    inset-block-start: var(--space-2xs);
    inset-inline-start: var(--space-2xs);
    gap: var(--space-3xs);
    padding: var(--space-3xs) var(--space-2xs);
  }
}

/* ============================ NOTICE CARD ==============================
   Date plate left, content right. "New" is a badge with a text label — never
   colour alone. */
.c-notice {
  position: relative;
  display: flex;
  gap: var(--space-md);
  padding: var(--space-lg);
  background-color: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
}

/* Navy plate with a large day over a small month, as in the reference. The
   reference measures a 32px plate on a 1024px-wide composite = 45px at the 1280
   container; --space-3xl (64px) was too wide for the 32rem homepage column, so
   the plate is sized by its content plus padding with a floor, not by a fixed
   width. */
.c-notice__date {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  min-width: var(--space-2xl);
  padding: var(--space-xs);
  border-radius: var(--radius-sm);
  background-color: var(--color-primary-700);
  color: var(--color-text-on-dark);
  line-height: var(--leading-flat);
}

.c-notice__day {
  font-size: var(--text-h3);
  font-weight: var(--font-weight-bold);
}

.c-notice__month {
  margin-block-start: var(--space-3xs);
  font-size: var(--text-xs);
  letter-spacing: var(--tracking-ui);
  text-transform: uppercase;
}

.c-notice__title {
  font-size: var(--text-body);
  font-weight: var(--font-weight-semibold);
}

.c-notice__title a {
  color: inherit;
  text-decoration: none;
}

.c-notice__title a::after {
  content: "";
  position: absolute;
  inset: 0;
}

.c-notice__summary {
  margin-block-start: var(--space-2xs);
  font-size: var(--text-sm);
  color: var(--color-text-muted);
}

/* Category + New sit above the title so the badge never breaks the heading. */
.c-notice__flags {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-xs);
  margin-block-end: var(--space-2xs);
}

.c-notice__category {
  font-size: var(--text-xs);
  font-weight: var(--font-weight-semibold);
  letter-spacing: var(--tracking-ui);
  text-transform: uppercase;
  color: var(--color-primary-500);
}

.c-notice__attachment {
  display: flex;
  align-items: center;
  gap: var(--space-2xs);
  margin-block-start: var(--space-xs);
  font-size: var(--text-xs);
  font-weight: var(--font-weight-semibold);
  color: var(--color-primary-600);
}

.c-notice__badge {
  display: inline-flex;
  align-items: center;
  gap: var(--space-3xs);
  padding: var(--space-3xs) var(--space-xs);
  border-radius: var(--radius-sm);
  background-color: var(--color-error);
  color: var(--color-text-on-dark);
  font-size: var(--text-xs);
  font-weight: var(--font-weight-semibold);
  letter-spacing: var(--tracking-ui);
  text-transform: uppercase;
}

/* =========================== GALLERY CARD ==============================
   The homepage's closing photograph band: four equal tiles in one row on
   desktop, two on tablet, a scroll-snap filmstrip on mobile (below). The
   grid stays auto-fit with a 240px floor rather than a fixed four tracks,
   so whatever count the editor sets still fills the row or wraps cleanly —
   four published tiles at desktop width resolve to exactly four columns.

   PRESENTATION PASS (client-directed). The tiles were bare 3:2 frames with
   no caption and no unifying treatment; they now read as ONE component:
   one navy scrim, one gold indicator, one circular control — each declared
   once, here, so every record renders the same by construction. Titles and
   album terms come from the records; nothing is invented, and no photograph
   is replaced, re-cropped or re-linked. */
.c-gallery {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(240px, 100%), 1fr));
  gap: var(--space-lg);
}

/* Heading left, "view gallery" right. The pair is vertically centred against
   the two-line header block (eyebrow + title): a true shared baseline is
   unreachable here, because the section header's first line is the eyebrow,
   so baseline alignment would hang the button off the eyebrow instead. */
.c-gallery__head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-md);
}

/* The band's own heading in institutional navy — the same dark ink the
   founder and principal statements carry, one step deeper than body text. */
.c-gallery__head .c-section-header__title {
  color: var(--color-primary-900);
}

/* One tile language: 12px corner, soft elevation, no visible border, one
   shared 3:2 frame. Equal widths come from the grid; equal heights from the
   enforced ratio — so four tiles are four of the same object, not four
   neighbouring sizes. */
.c-gallery__link {
  position: relative;
  display: block;
  overflow: hidden;
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-md);
  transition: box-shadow var(--transition-base);
}

.c-gallery__link .c-media {
  border-radius: var(--radius-lg);
  /* Navy behind the photograph, so a slow or failed load shows the band's
     own colour rather than the neutral placeholder grey. */
  background-color: var(--color-primary-900);
}

.c-gallery__link img {
  transition: transform var(--duration-slow) var(--ease-out);
}

.c-gallery__link:hover,
.c-gallery__link:focus-visible {
  box-shadow: var(--shadow-lg);
}

.c-gallery__link:hover img {
  transform: scale(1.04);
}

/* ONE scrim on every tile: the site navy deepening toward the foot and
   fading to nothing over the upper half, so the photograph stays clearly
   visible while the caption sits on calm ground. Declared once, never per
   record — identical colour and strength on all tiles by construction. */
.c-gallery__overlay {
  position: absolute;
  inset: 0;
  z-index: var(--z-base);
  background-image: linear-gradient(
    to top,
    rgba(3, 25, 50, 0.78),
    rgba(3, 25, 50, 0.42) 30%,
    rgba(3, 25, 50, 0) 60%
  );
}

/* Caption: the record's own title and album term, set low on the scrim.
   Spans, not headings — the tile sits under the band's h2 and must not
   grow an outline of its own. */
.c-gallery__caption {
  position: absolute;
  inset-block-end: 0;
  inset-inline: 0;
  z-index: var(--z-base);
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  padding: var(--space-lg);
}

/* The same thin gold indicator the section header carries: one accent
   language from band to tile, on every tile alike. */
.c-gallery__dash {
  width: var(--space-xl);
  height: var(--space-3xs);
  margin-block-end: var(--space-2xs);
  border-radius: var(--radius-full);
  background-color: var(--color-accent);
}

.c-gallery__title {
  color: var(--color-text-on-dark);
  font-size: var(--text-body);
  font-weight: var(--font-weight-semibold);
  line-height: var(--leading-heading);
}

.c-gallery__meta {
  margin-block-start: var(--space-3xs);
  color: var(--color-text-on-dark-muted);
  font-size: var(--text-sm);
  line-height: var(--leading-heading);
}

/* The one control every tile shares: the hero arrow's own language —
   circular, navy-translucent fill, light hairline, white arrow — at tile
   scale. Decorative: the whole tile is the affordance. */
.c-gallery__go {
  position: absolute;
  inset-block-start: var(--space-md);
  inset-inline-end: var(--space-md);
  z-index: var(--z-base);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: calc(var(--space-md) * 2.5);
  height: calc(var(--space-md) * 2.5);
  border: 1px solid var(--color-border-on-dark);
  border-radius: var(--radius-full);
  background-color: rgba(3, 25, 50, 0.32);
  color: var(--color-text-on-dark);
  font-size: var(--text-body);
  line-height: var(--leading-flat);
  transition: background-color var(--transition-base);
}

.c-gallery__link:hover .c-gallery__go {
  background-color: rgba(3, 25, 50, 0.6);
}

/* MANDATORY MOBILE TRANSFORMATION: scroll-snap filmstrip, not a stacked
   column. Peeking next tile signals scrollability without an added control. */
@media (max-width: 767px) {
  .c-gallery {
    display: flex;
    gap: var(--space-sm);
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    /* Bleed to the viewport edges so the strip reads as continuous. */
    margin-inline: calc(var(--container-gutter) * -1);
    padding-inline: var(--container-gutter);
    scroll-padding-inline-start: var(--container-gutter);
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
  }

  .c-gallery::-webkit-scrollbar {
    display: none;
  }

  .c-gallery__item {
    flex: 0 0 78%;
    scroll-snap-align: start;
  }

  /* Tighter caption inset on the narrow tiles, same scrim and accent. */
  .c-gallery__caption {
    padding: var(--space-md);
  }
}

/* ======================== PRINCIPAL MESSAGE ============================
   One wide editorial panel on the tinted band, photograph left and the message
   right. It is deliberately NOT the dark navy card it used to be: that card was
   a narrow aside beside the programme grid, and a dark surface next to a row of
   white cards read as a widget. On its own band with navy type it reads as a
   statement from the head of the institution.

   PRESENTATION PASS (client-directed; CSS only — no markup, no content). The
   band used to be ONE flat white box with a bare rounded photograph floating
   inside it, which read as a form with a picture attached, not a statement.
   It now speaks the founder band's exhibit-row language, so the page's two
   people-bands read as one system:

   THE PHOTOGRAPH IS A PLATE. The same treatment as .c-founder__frame — white
   surface, hairline border, the gold top inlay, the solid mount shadow — so
   the principal's portrait hangs on the band the way the founder's does.

   THE MESSAGE IS A DOCUMENT CARD. The same treatment as .c-founder__body —
   white surface, --radius-lg, --shadow-sm, its own gold top inlay — with one
   addition this band owns alone: the oversized accent quotation mark above
   the message, the classic principal's-message composition on college sites,
   which is what marks the text as a signed statement rather than body copy.

   NOT CHANGED: not one element of markup (every qa-frontend contract on this
   band is structural and survives untouched), not a word of content, and the
   photograph still renders at its own 0.929:1 proportions through
   .c-media--natural, still requested at 'large' — the 724px source is wider
   than anything this track can show, so it is never upscaled. */
.c-principal {
  display: grid;
  /* 0.45fr, up from 0.42fr: the photograph is now a mounted plate rather than
     a bare image, and the plate's padding and frame need the extra width to
     keep the portrait itself no smaller than it was. It computes to ~383px of
     plate (~355px of image) at the 1280 container, and the 16rem minimum
     takes over at tablet rather than collapsing the portrait. */
  grid-template-columns: minmax(min(16rem, 100%), 0.45fr) minmax(0, 1fr);
  align-items: start;
  gap: var(--space-3xl);
  margin: 0;
}

/* Grid items must be allowed to shrink with the band. This is especially
   important on narrow mobile viewports, where a descendant's min-content width
   must never widen the figure past the container. */
.c-principal {
  width: 100%;
  min-width: 0;
}

.c-principal > * {
  width: 100%;
  min-width: 0;
  max-width: 100%;
}

.c-principal__body,
.c-principal__quote {
  min-width: 0;
  max-width: 100%;
  overflow-wrap: break-word;
}


/* Without a photograph the message runs alone rather than leaving an empty
   first track. */
.c-principal--textonly {
  grid-template-columns: minmax(0, 1fr);
}

/* ---- The plate ----

   A white surface on the band's tinted background, which is the whole reason
   the portrait now reads as framed rather than dropped in. --shadow-sm, not md
   or lg: this is a picture on a wall, not a floating UI card. The mount first,
   then the elevation: the solid tint peeks past the plate's lower corner while
   --shadow-sm keeps the plate's own edge soft — the identical recipe to
   .c-founder__frame, so the two portrait plates on the page are literally the
   same object. */
.c-principal__media {
  position: relative;
  padding: var(--space-sm);
  background-color: var(--color-surface);
  border: 1px solid var(--color-border-subtle);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-mount), var(--shadow-sm);
}

/* The gold rule along the top edge: the same inlay, inset and accent token as
   .c-founder__frame::before and .c-founder__body::before, so the plate and the
   document card carry one indicator language and read as a single exhibit row.
   It sits inside the plate's padding, clear of the photograph below it.
   Decorative. */
.c-principal__media::before {
  content: "";
  position: absolute;
  inset-block-start: 0;
  inset-inline: var(--space-md);
  height: var(--space-3xs);
  border-end-start-radius: var(--radius-full);
  border-end-end-radius: var(--radius-full);
  background-color: var(--color-accent);
}

/* The photograph fills its plate — there is no dead space beside it — and keeps
   its own 0.929:1 proportions because .c-media--natural imposes no ratio.
   Prominent is a column-width decision, not a crop decision. The old 22rem cap
   is gone because the grid track is now the cap, and it was always the wider
   guard anyway. */
.c-principal__media .c-media {
  border-radius: var(--radius-sm);
}

/* The mat line: a hairline just inside the plate, the way a mounted print is
   held by a cut mat rather than touching the frame — the same finish as
   .c-founder__image. box-sizing is border-box globally, so the hairline eats
   into the image's box and the no-upscale arithmetic in the track above holds
   exactly. */
.c-principal__media .c-media__img {
  border: 1px solid var(--color-border-subtle);
  border-radius: var(--radius-sm);
}

/* ---- The document card ----

   The message column as a signed statement on a sheet: white surface,
   hairline border, --radius-lg, --shadow-sm — the identical recipe to
   .c-founder__body, so the founder's archival sheet and the principal's
   statement sheet are the same object at different widths. position, so the
   gold top inlay below can be an inset pseudo-element rather than a border
   that would round with the card's corners. */
.c-principal__body {
  position: relative;
  min-width: 0;
  padding: var(--space-lg);
  background-color: var(--color-surface);
  border: 1px solid var(--color-border-subtle);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
}

.c-principal__body::before {
  content: "";
  position: absolute;
  inset-block-start: 0;
  inset-inline: var(--space-md);
  height: var(--space-3xs);
  border-end-start-radius: var(--radius-full);
  border-end-end-radius: var(--radius-full);
  background-color: var(--color-accent);
}

@media (min-width: 768px) {
  .c-principal__body {
    padding: var(--space-2xl);
  }
}

/* Eyebrow, matching every other section eyebrow on the page. It carries the
   aria-labelledby id, so it names the section without adding a second h2 to the
   outline beside "Courses Offered". */
.c-principal__eyebrow {
  color: var(--color-primary-500);
  font-size: var(--text-ui);
  font-weight: var(--font-weight-semibold);
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase;
}

/* The gold dash, same token and same dimensions as the section header's, so the
   page has one gold indicator and not two that disagree. */
.c-principal__dash {
  display: block;
  width: var(--space-xl);
  height: var(--space-3xs);
  margin-block: var(--space-sm) var(--space-lg);
  border-radius: var(--radius-full);
  background-color: var(--color-accent);
}

.c-principal__quote {
  margin: 0;
  max-width: var(--measure-body);
  color: var(--color-text-primary);
  font-size: var(--text-body-lg);
}

/* The oversized opening quotation mark — the one element of the college-site
   principal's-message composition this band owns. A pseudo-element, so the
   markup, the DOM text and the accessibility order are untouched: the message
   already says what it says, the mark only frames it. --text-h1 rather than a
   watermark scale, because it must read as punctuation belonging to the first
   line, not as a heading; accent gold, the band's existing indicator colour.
   The small negative margin tucks the first paragraph into the space below
   the glyph's ink — a quotation mark's em square is mostly empty at the
   bottom — so the mark and the text read as one opening gesture rather than
   two stacked blocks. */
.c-principal__quote::before {
  content: "\201C";
  display: block;
  margin-block-end: calc(var(--space-xs) * -1);
  color: var(--color-accent);
  font-size: var(--text-h1);
  font-weight: var(--font-weight-bold);
  line-height: var(--leading-flat);
}

.c-principal__quote > * + * {
  margin-block-start: var(--space-md);
}

/* Attribution. Only rendered when a name exists — see the template. A rule
   above it separates the byline from the message without a second card edge;
   inside the document card it reads as the signature line of a letter. */
.c-principal__attribution {
  display: flex;
  flex-direction: column;
  gap: var(--space-3xs);
  margin-block-start: var(--space-lg);
  padding-block-start: var(--space-lg);
  border-block-start: 1px solid var(--color-border);
  font-style: normal;
}

/* --text-h3, up from --text-body-lg: the name is the signature of the
   statement and was previously the same size as the message text, which made
   the byline read as a fourth line of the quote. The token is the scale's
   existing step — the same size the notices heading sits at. */
.c-principal__name {
  color: var(--color-primary-700);
  font-size: var(--text-h3);
  line-height: var(--leading-heading);
  font-weight: var(--font-weight-bold);
}

.c-principal__role {
  color: var(--color-text-secondary);
  font-size: var(--text-sm);
  font-weight: var(--font-weight-medium);
  letter-spacing: var(--tracking-ui);
  text-transform: uppercase;
}

/* The two institutional lines, read from the same options as the masthead. */
.c-principal__org {
  color: var(--color-text-muted);
  font-size: var(--text-sm);
}

.c-principal__action {
  margin-block-start: var(--space-lg);
}

/* Plate above the message once the columns would become too narrow to read.
   The plate keeps a cap and stays left-aligned, so it does not become a
   full-width banner; centring it would read as a profile avatar rather than a
   hung picture. 16rem of plate (~230px of image) sits clearly above a faculty
   thumbnail while fitting the ~343px mobile container with room to breathe. */
@media (max-width: 767px) {
  .c-principal {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-xl);
  }

  .c-principal__media {
    max-width: 16rem;
  }

  .c-principal__body {
    padding: var(--space-lg);
  }
}

/* ============================== FOUNDER ================================
   Institutional heritage, as an exhibit row: a framed portrait plate on the
   left, the name and running prose in a document card on the right, and the
   founding year ghosted into the card's corner.

   WHAT CHANGED IN THE PRESENTATION PASS, AND WHY.

   The block used to be a bare 13rem image with a gold underline beside body
   text. At the band's width that read as a thumbnail next to a paragraph — the
   founder of the institution presented more modestly than a faculty member, who
   at least gets a card. The portrait is now a plate: white surface, hairline
   border, a gold rule along its top edge, and the stored facts beneath it.

   REDESIGN PASS (client-directed; still no markup and no content change).
   The refinement pass had kept the body bare on the tinted band — an
   editorial spread — but at the container's width the measure-capped prose
   left a wide dead margin on the right of the text column, and the band read
   as unfinished rather than airy. Two changes fix that:

   THE BODY IS A DOCUMENT CARD. The prose column is now an "archival sheet":
   a white surface with a hairline border, --radius-lg, --shadow-sm and the
   same gold top inlay the plate wears — so the plate and the sheet read as
   one exhibit row, a hung picture beside the page of history it captions,
   and the sheet's edge now carries to the container's right margin instead
   of stopping at the prose measure. The band's tinted background shows only
   around the two surfaces, which is what gives the composition its depth.

   THE HERITAGE YEAR. The card's top-right corner — the space the lead's
   shorter measure leaves empty — carries a ghost "1914": the founding year
   from the institution's own stored caption ("Founded the school that
   became the college, 1914"), repeated as a watermark rather than invented.
   It is a pseudo-element, so the markup, the DOM text and the accessibility
   order are untouched. It renders only from 1200px, where the card is wide
   enough to hold it clear of the text.

   WHAT DID NOT CHANGE. Not a word of content, not one element of markup,
   and none of the measured contracts: the portrait's 225px no-upscale cap
   and its arithmetic, the reading measures, the type hierarchy, and the
   single-column portrait-first layout below 768px. The image itself is
   untouched: same attachment, same intrinsic 225x316 proportions, still
   never upscaled. */
.c-founder__inner {
  display: grid;
  /* 35fr / 65fr — the founder redesign's exhibit proportions: the portrait
     column is a fixed SHARE of the composition rather than a capped track, so
     the plate and the document card scale together as one exhibit row. The
     18rem floor exists for the narrow desktop widths (768-1023), where 35% of
     the container would shrink a square portrait below the 260px anchoring
     height flow-founder-viewport.mjs asserts; from 1024px up the share alone
     governs, and the no-upscale contract still holds by arithmetic: the
     container caps at 1280px, so the widest this track ever becomes is
     ~417px, and the plate serves the 1232px full-size file — the portrait can
     never be upscaled. */
  grid-template-columns: minmax(min(18rem, 100%), 35fr) minmax(0, 65fr);
  align-items: start;
  gap: var(--space-3xl);
  /* Below the petal layer (z-index 2), so a falling petal paints over the
     two white surfaces and everything on them - the paint order that makes
     the gold fall visible against the white cards - while the petals stay
     sparse, small and translucent enough that the founder's face and every
     line of prose read clearly beneath the passing leaves. The z-index still
     lifts the grid above the band's tinted ground and keeps the card's own
     stacking context (and the ghost year inside it) painting in order. */
  position: relative;
  z-index: 1;
}

/* Without a portrait the prose column stands alone rather than leaving an
   empty first track. */
.c-founder__inner--textonly {
  grid-template-columns: minmax(0, 1fr);
}

/* ---- The document card ----

   The prose column as an archival sheet. position, so the gold top inlay
   below can be an absolutely positioned pseudo-element rather than a border
   that would round with the card's corners; isolation, so the ghost year
   further down can sit BEHIND the card's text while still painting on top of
   the card's own white surface — a stacking context is the only way a
   negative z-index child lands between those two layers.

   The padding is --space-lg at the base and grows to --space-2xl on the
   two-column widths, where the card is wide enough for a sheet's margin. */
.c-founder__body {
  position: relative;
  isolation: isolate;
  padding: var(--space-lg);
  background-color: var(--color-surface);
  border: 1px solid var(--color-border-subtle);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
}

/* The gold rule along the card's top edge: the same inlay, inset and accent
   token as .c-founder__frame::before, so the plate and the sheet carry one
   indicator language and read as a single exhibit row. Decorative. */
.c-founder__body::before {
  content: "";
  position: absolute;
  inset-block-start: 0;
  inset-inline: var(--space-md);
  height: var(--space-3xs);
  border-end-start-radius: var(--radius-full);
  border-end-end-radius: var(--radius-full);
  background-color: var(--color-accent);
}

@media (min-width: 768px) {
  .c-founder__body {
    padding: var(--space-2xl);
  }
}

/* ---- The heritage year ----

   "1914" is not invented copy: it is the founding year in the institution's
   own stored caption, repeated as a watermark in the corner the lead's
   shorter measure leaves empty — the space that used to read as a dead
   right margin. A pseudo-element, so no markup, no DOM text and no tab stop;
   z-index -1 so it can never sit on top of a word even if a longer name one
   day reaches it.

   Only from 1200px. Below that the card's interior is too narrow for the
   numeral to clear the lead's 46ch measure, and a watermark that collides
   with text is not decoration but damage. */
@media (min-width: 1200px) {
  .c-founder__body::after {
    content: "1914";
    position: absolute;
    z-index: -1;
    inset-block-start: var(--space-md);
    inset-inline-end: var(--space-xl);
    font-size: var(--text-heritage-year);
    line-height: var(--leading-flat);
    font-weight: var(--font-weight-bold);
    letter-spacing: var(--tracking-display);
    color: var(--color-primary-100);
  }
}

/* THE PLATE IS SIZED BY ITS TRACK. The original cap (20rem, derived from a
   225px recovered photograph that has since been replaced) is gone: the
   portrait column is now 35fr of the composition, and the plate fills it.
   The no-upscale contract moves to the arithmetic in .c-founder__inner — the
   track never exceeds ~417px against a 1024px served file — and
   flow-founder-viewport.mjs still measures the rendered image against the
   served file at every width, so an accidental upscale is caught. */
.c-founder__portrait {
  margin: 0;
  max-width: 100%;
  /* position, so the gold top rule below can be an inset pseudo-element rather
     than a border that would round with the plate's corners. */
  position: relative;
}

/* ---- The plate ----

   A white surface on the band's tinted background, which is the whole reason the
   portrait now reads as framed rather than dropped in. --shadow-sm, not md or
   lg: this is a picture on a wall, not a floating UI card, and the heavier
   shadows in the token set belong to the elements that genuinely overlap
   something. */
.c-founder__frame {
  position: relative;
  padding: var(--space-sm);
  background-color: var(--color-surface);
  border: 1px solid var(--color-border-subtle);
  border-radius: var(--radius-md);
  /* The mount first, then the elevation: the solid tint peeks past the
     plate's lower corner while --shadow-sm keeps the plate's own edge soft.
     A shadow never paints over the element it belongs to, so the mount can
     only ever show outside the plate — no z-index games required. */
  box-shadow: var(--shadow-mount), var(--shadow-sm);
}

/* The gold rule along the top edge. A pseudo-element inset to the plate's own
   radius, so it reads as an inlay rather than as a border that has to fight the
   rounded corner. Decorative, and 3px is the same thin-indicator weight as
   .c-section-header__dash. */
.c-founder__frame::before {
  content: "";
  position: absolute;
  inset-block-start: 0;
  inset-inline: var(--space-md);
  height: var(--space-3xs);
  border-end-start-radius: var(--radius-full);
  border-end-end-radius: var(--radius-full);
  background-color: var(--color-accent);
}

/* THE GOLD RING. The image carries a 2px --color-accent frame — the same
   treatment the faculty profile's masthead portrait wears — so the founder's
   likeness sits in a gold mount inside the white plate, and the two portrait
   presentations on the site speak one ring language. box-sizing is border-box
   globally, so the image's outer width is unchanged and the plate's
   no-upscale arithmetic above still holds exactly. */
.c-founder__image {
  display: block;
  width: 100%;
  height: auto;
  border: 2px solid var(--color-accent);
  border-radius: var(--radius-sm);
}

/* ---- The fact badges ----

   Still the portrait's <figcaption>, so "Born 1872" remains the caption of the
   picture it describes. But each fact now wears a badge — a warm gold-tinted
   pill rather than the bare stacked ledger line — because the caption sits
   directly under the band's most decorative object, the framed plate, and a
   plain hairline rule there read as unfinished rather than modest. The gold
   accent family is the one the band already speaks: the plate's top inlay,
   the dash under the name, the ghost year in the corner. The badge says
   "heritage marker", which is what these facts are.

   The ledger rule is gone: a badge is a self-contained object and does not
   need a separator above it. And the badges are FULL-WIDTH and centred, per
   the client's direction: each pill stretches to the plate's width exactly,
   so the picture and its caption read as one column, and the icon-and-text
   group sits in the middle of it. */
.c-founder__facts {
  display: flex;
  flex-direction: column;
  /* stretch (the default), not start: a badge as wide as the plate above it
     is the design — a start-aligned shrink-to-fit pill beside a 320px frame
     would look like it was avoiding something. */
  align-items: stretch;
  gap: var(--space-xs);
  margin-block-start: var(--space-md);
  color: var(--color-text-primary);
  font-size: var(--text-sm);
}

/* Each fact one badge. --color-surface-accent behind a --color-border-accent
   hairline: both tokens exist for exactly this warm-accent-on-light role, so
   the badge agrees with the page's accent language rather than introducing a
   sixth gold. --radius-full because a badge is the token's own shape.
   max-width: 100% so a long fact wraps inside its pill instead of overflowing
   the portrait column. justify-content: center and text-align: center put the
   glyph, and any wrapped line of the text, in the middle of the pill.

   align-items: start, not center: the second fact wraps to two lines at this
   column width, and a centred icon would float to the middle of the badge
   instead of sitting on the first line where the eye starts. */
.c-founder__fact {
  display: inline-flex;
  align-items: start;
  justify-content: center;
  gap: var(--space-2xs);
  max-width: 100%;
  padding: var(--space-2xs) var(--space-sm);
  border: 1px solid var(--color-border-accent);
  border-radius: var(--radius-full);
  background-color: var(--color-surface-accent);
  font-weight: var(--font-weight-medium);
  text-align: center;
}

/* The glyph sits in a WHITE circular disc — --color-surface behind a
   --color-primary-600 glyph — rather than the old primary-100 chip, so the
   saturated navy glyph pops against the gold-tinted pill the same way the
   programme category tiles pair a saturated glyph with a pale ground. The
   chip is the 15px glyph plus --space-2xs of padding all round; flex-shrink: 0
   so a wrapping fact cannot squash it. */
.c-founder__fact-icon {
  flex: 0 0 auto;
  padding: var(--space-2xs);
  color: var(--color-primary-600);
  background-color: var(--color-surface);
  border-radius: var(--radius-full);
}

/* padding-block balances the 23px icon disc, so a one-line fact's pill is
   evenly padded top and bottom. min-width: 0 so the text can shrink and
   wrap inside the badge. */
.c-founder__fact-text {
  min-width: 0;
  padding-block: var(--space-2xs);
}

/* No portrait: the facts move into the text column and run inline there, where
   there is width for them and no picture for them to caption. */
.c-founder__facts--inline {
  flex-direction: row;
  flex-wrap: wrap;
  gap: var(--space-xs) var(--space-lg);
  margin-block-start: var(--space-lg);
}

.c-founder__eyebrow {
  margin-block-end: var(--space-xs);
  color: var(--color-primary-500);
  font-size: var(--text-ui);
  font-weight: var(--font-weight-semibold);
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase;
}

/* --text-h1, up from --text-h2. The founder's name is the subject of the band,
   and at --text-h2 it was the same size as every other section heading on the
   page — which made the origin of the institution rank equal with "Courses
   Offered". The token is the existing scale's next step, not a new value. */
.c-founder__name {
  font-size: var(--text-h1);
  line-height: var(--leading-heading);
  letter-spacing: var(--tracking-display);
  color: var(--color-primary-700);
  text-wrap: balance;
}

/* The gold dash under the name. Same 32x3 dimensions and the same accent token as
   .c-section-header__dash and .c-principal__dash — one indicator language across
   the page, not three. */
.c-founder__dash {
  display: block;
  width: var(--space-xl);
  height: var(--space-3xs);
  margin-block: var(--space-md) var(--space-md);
  border-radius: var(--radius-full);
  background-color: var(--color-accent);
}

.c-founder__role {
  color: var(--color-text-secondary);
  font-size: var(--text-sm);
  font-weight: var(--font-weight-medium);
  letter-spacing: var(--tracking-ui);
  text-transform: uppercase;
}

/* ---- The opening paragraph ----

   --text-body-lg (17px) against the 16px body below it, at --measure-lead rather
   than --measure-body: a shorter line for the larger type, which is what keeps an
   editorial lead readable instead of merely bigger. Both tokens already exist;
   neither is introduced here.

   The colour is --color-text-primary while the body below stays
   --color-text-secondary, so the opening carries slightly more weight without a
   font-weight change that would make it look like a heading. */
.c-founder__lead {
  max-width: var(--measure-lead);
  margin-block-start: var(--space-lg);
  color: var(--color-text-primary);
  font-size: var(--text-body-lg);
  line-height: var(--leading-body);
  text-wrap: pretty;
}

.c-founder__prose {
  margin-block-start: var(--space-lg);
  color: var(--color-text-secondary);
}

/* The paragraph rhythm inside the biography. .u-prose's own 16px step is the
   site-wide default for prose; at this length — three paragraphs of institutional
   history — 24px is what stops it reading as one dense block, which is the
   readability problem this pass was asked to fix. Nothing is reworded. */
.c-founder__prose > * + * {
  margin-block-start: var(--space-lg);
}

/* Portrait above the prose once the columns would become too narrow to read.

   The plate keeps a cap and stays left-aligned: centring it would read as a
   profile avatar rather than a hung picture. 15rem rather than the old 12rem —
   the client asked for a taller portrait, and the replacement photograph is
   high-resolution, so 15rem (240px plate, 214px image) keeps the portrait
   clearly larger than a faculty thumbnail while still fitting the ~343px
   mobile container with room to breathe. */
@media (max-width: 767px) {
  .c-founder__inner {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-xl);
  }

  .c-founder__portrait {
    max-width: 15rem;
  }

  /* The lead loses its narrower measure on one column: --measure-lead inside a
     ~343px viewport would cap nothing, and keeping the rule would only make the
     declaration misleading. */
  .c-founder__lead {
    max-width: none;
  }
}

/* ---- The petal layer -------------------------------------------------

   A very slow fall of eight petals across the founder band, CSS-only: no
   library, no canvas, no JavaScript, and nothing for a screen reader to read
   (the markup layer is aria-hidden, and each petal is an empty span).

   THE FOUR SAFETY PROPERTIES, all of which are asserted by
   probe-founder-redesign.mjs:

   1. CLIPPED TO THE BAND. .c-founder has overflow: hidden, so a petal can
      never wander into a neighbouring section, and the effect belongs to the
      founder band alone — the header's founder portrait, drawn from the same
      options, is a different component and stays perfectly static.

   2. ABOVE THE CARDS. The layer is z-index 2 and .c-founder__inner is
      z-index 1, so a falling petal paints over the portrait plate, the
      document card and the band's tinted ground alike — the paint order that
      makes the gold fall actually visible against the white surfaces (behind
      the inner, every petal was covered by the cards' own white). The petals
      stay sparse, small and translucent, so a leaf passing over the founder's
      face or a line of prose reads as a drifting leaf, never as occlusion.

   3. UNTOUCHABLE. pointer-events: none on the layer — a petal can never
      intercept a click, a hover or a keyboard focus target.

   4. OPTIONAL. prefers-reduced-motion: remove removes the layer entirely
      (and 10-base.css's global animation-neutralising rule is the second,
      independent belt around this). Below 768px the count halves, per the
      brief's "petal density reduced" allowance for small screens.

   The movement: each petal drifts down the band (top, in container
   percentages, so the fall spans the band whatever its height) while
   rotating through roughly a third of a turn and drifting sideways a few
   rem. `top` is animated rather than a transform percentage because a
   translate percentage would resolve against the petal's own 12px, not the
   band; eight slow absolutely-positioned elements is well inside the
   compositor's budget. Opacity fades in and out at the edges of the fall so
   petals appear and dissolve rather than pop. */

/* The band clips its petals. Nothing else about the band's box changes. */
.c-founder {
  overflow: hidden;
}

.c-founder__petals {
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
}

.c-founder__petals span {
  position: absolute;
  display: block;
  /* A petal: an asymmetric leaf roundness, a soft gold wash. The two alphas
     are the palette's own gold (#FBBA1A) — kept at 0.9 → 0.55 because a
     leaf's ink is shared between this fill and the animation's peak opacity
     (--petal-o, 0.3–0.5 per petal), and at that combined weight the fall
     reads clearly against the white card surfaces while a leaf passing over
     the founder's face or a line of prose still leaves the subject readable
     beneath it. A translucent decorative tint is still not a token the
     system has, so the rgba is written inline for eight shapes assistive
     tech never sees. */
  width: 14px;
  height: 11px;
  border-radius: 62% 38% 55% 45% / 48% 62% 38% 52%;
  background: linear-gradient(150deg, rgba(251, 186, 26, 0.9), rgba(251, 186, 26, 0.55));
  opacity: 0;
  animation: tdc-founder-petal linear infinite;
  animation-duration: 30s;
  will-change: top, transform, opacity;
}

/* The one fall, parameterised per petal through custom properties: where it
   starts across the band (--petal-x), how far it drifts sideways
   (--petal-drift), how it turns (--petal-turn), and how visible it is at its
   most visible (--petal-o). The negative animation delays spread the eight
   petals across the cycle immediately, so the band is never waiting for its
   first leaf. */
@keyframes tdc-founder-petal {
  0% {
    top: -8%;
    transform: translateX(0) rotate(-20deg);
    opacity: 0;
  }

  10% {
    opacity: var(--petal-o, 0.4);
  }

  90% {
    opacity: var(--petal-o, 0.4);
  }

  100% {
    top: 108%;
    transform: translateX(var(--petal-drift, 2.5rem)) rotate(var(--petal-turn, 160deg));
    opacity: 0;
  }
}

/* The eight petals: staggered positions, sizes, speeds, drifts and opacities,
   so no two fall alike. Deliberately sparse — the brief caps the effect at
   "5-10 petals maximum visible" and subtlety is the whole point. Each petal's
   --petal-o is its peak opacity (the keyframe holds 10%→90% of the fall);
   values sit between .35 and .5 so a petal is a clearly visible gold leaf on
   the white surfaces while a leaf over the face or prose never occludes it. */
.c-founder__petals span:nth-child(1) {
  left: 5%;
  width: 19px;
  height: 14px;
  animation-duration: 34s;
  animation-delay: -4s;
  --petal-drift: 3rem;
  --petal-turn: 150deg;
  --petal-o: 0.5;
}

.c-founder__petals span:nth-child(2) {
  left: 16%;
  width: 14px;
  height: 11px;
  animation-duration: 27s;
  animation-delay: -19s;
  --petal-drift: -2rem;
  --petal-turn: -130deg;
  --petal-o: 0.4;
}

.c-founder__petals span:nth-child(3) {
  left: 28%;
  width: 16px;
  height: 12px;
  animation-duration: 31s;
  animation-delay: -11s;
  --petal-drift: 2.5rem;
  --petal-turn: 170deg;
  --petal-o: 0.45;
}

.c-founder__petals span:nth-child(4) {
  left: 41%;
  width: 13px;
  height: 10px;
  animation-duration: 24s;
  animation-delay: -8s;
  --petal-drift: -1.5rem;
  --petal-turn: -160deg;
  --petal-o: 0.4;
}

.c-founder__petals span:nth-child(5) {
  left: 54%;
  width: 18px;
  height: 13px;
  animation-duration: 36s;
  animation-delay: -25s;
  --petal-drift: 3.5rem;
  --petal-turn: 140deg;
  --petal-o: 0.5;
}

.c-founder__petals span:nth-child(6) {
  left: 67%;
  width: 14px;
  height: 10px;
  animation-duration: 29s;
  animation-delay: -2s;
  --petal-drift: -2.5rem;
  --petal-turn: -150deg;
  --petal-o: 0.45;
}

.c-founder__petals span:nth-child(7) {
  left: 79%;
  width: 16px;
  height: 12px;
  animation-duration: 33s;
  animation-delay: -16s;
  --petal-drift: 2rem;
  --petal-turn: 165deg;
  --petal-o: 0.45;
}

.c-founder__petals span:nth-child(8) {
  left: 91%;
  width: 17px;
  height: 12px;
  animation-duration: 26s;
  animation-delay: -9s;
  --petal-drift: -3rem;
  --petal-turn: -145deg;
  --petal-o: 0.4;
}

/* Half the petals on small screens: the band is narrower and shorter, and the
   same count would read as weather rather than memory. */
@media (max-width: 767px) {
  .c-founder__petals span:nth-child(even) {
    display: none;
  }
}

/* Reduced motion: the layer is removed outright. The global rule in
   10-base.css would already neutralise the animation's duration; this makes
   the intent explicit and keeps the petals from sitting frozen mid-fall on
   the band. */
@media (prefers-reduced-motion: reduce) {
  .c-founder__petals {
    display: none;
  }
}

/* ============================== NOTICES LIST ===========================
   The homepage list beside the faculty grid. Everything here is the
   NO-SCRIPT presentation: the full list at its natural height, never
   clipped and never moving. The bottom-to-top scroll is added by
   notice-ticker.js through the .is-enhanced gate in 40-interactive.css,
   so every fallback (script failure, prefers-reduced-motion, a list
   short enough to fit) lands on this same readable static layout. */
.c-notices {
  /* A column so the viewport can soak up whatever height the stretched
     band leaves below the head (the fill is completed in
     40-interactive.css, which also takes the track out of flow so the
     moving list cannot grow the column it is measured against). */
  display: flex;
  flex-direction: column;

  /* The moving window's height on the STACKED layout (below 1024, where
     the columns collapse and there is no faculty column for the window
     to size against). On the desktop split the window is not capped at
     all: it fills the height the faculty column leaves beside it, so the
     notices run to the band's bottom with no dead space below. About
     two notice cards here: enough context to read, short enough that the
     default four-notice list always has somewhere to scroll to. */
  --tdc-notices-max: 17.5rem;
}

.c-notices__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-md);
  padding-block-end: var(--space-sm);
  border-block-end: 1px solid var(--color-border);
}

.c-notices__title {
  font-size: var(--text-h3);
}

/* The moving window. Statically it is a plain passthrough — no height
   cap, no clipping — so the no-JS list is exactly the list the markup
   describes. flex: 1 lets the box grow to fill the column once enhanced
   (min-height: 0 arrives with .is-enhanced in 40-interactive.css); left
   at its default it simply grows with the static content. */
.c-notices__viewport {
  flex: 1 1 auto;
  overflow: visible;
}

.c-notices__track {
  display: block;
}

.c-notices__list {
  margin: 0;
  padding: 0;
  list-style: none;
}

.c-notices__list > li + li {
  border-block-start: 1px solid var(--color-border-subtle);
}

/* Inside the list the notice card loses its own chrome — the list supplies the
   separators, so a card border would double them. */
.c-notices__list .c-notice {
  padding-inline: 0;
  background: none;
  border: 0;
  border-radius: 0;
}

/* =========================== ICON FEATURE ============================== */
.c-icon-feature {
  display: flex;
  gap: var(--space-md);
}

.c-icon-feature__icon {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--space-xl);
  height: var(--space-xl);
  border-radius: var(--radius-lg);
  background-color: var(--color-primary-100);
  color: var(--color-primary-600);
}

.c-icon-feature__title {
  font-size: var(--text-body);
  font-weight: var(--font-weight-semibold);
}

.c-icon-feature__text {
  font-size: var(--text-sm);
  color: var(--color-text-muted);
}


/* ========================= FACULTY PROFILE =============================
   The individual member page, rendered by template-parts/faculty/profile.php for
   every faculty record. One stylesheet block, one template: there is no per-person
   styling anywhere here, and adding a member needs no CSS.

   STRUCTURE. A navy masthead carrying the portrait and identity, then a white band
   split into a wide main column (research, publications) and a narrow aside (service
   record, contact, academic profiles). Two columns rather than one long scroll
   because the two kinds of content are read differently: the main column is prose to
   read, the aside is facts to look up.

   Every section self-omits when its data is absent, so this must degrade to a page
   with only a masthead and still look deliberate — which is why the masthead carries
   the visual weight and the body carries none of its own.

   .c-profile (the <article> root) and .c-profile__section carry no rules of their
   own: the root is the block's namespace and a scoping hook, and the section wrapper
   is spaced through `.c-profile__main > * + *` rather than directly. Both stay in the
   markup because removing them would leave the page's sections unnamed. */
.c-profile__masthead {
  /* The band's own vertical rhythm is reduced: the identity block already has
     generous internal spacing, and a full --space-section on top of it pushed the
     name below the fold at 768. */
  padding-block: var(--space-2xl);
}

/* Breadcrumbs sit on navy here rather than on white as everywhere else, so their own
   colours have to be lifted. Scoped to the masthead — the archive's breadcrumbs are
   unaffected. */
.c-profile__masthead .c-breadcrumbs {
  margin-block-end: var(--space-xl);
  color: var(--color-text-on-dark-muted);
}

.c-profile__masthead .c-breadcrumbs a {
  color: var(--color-text-on-dark-muted);
}

.c-profile__masthead .c-breadcrumbs a:hover {
  color: var(--color-accent);
}

.c-profile__masthead .c-breadcrumbs [aria-current="page"] {
  color: var(--color-text-on-dark);
}

/* Portrait left, identity right. The portrait column is a fixed rem width so it does
   not track the container: the identity text should take the extra width at larger
   viewports, not the photograph. */
.c-profile__identity {
  display: grid;
  grid-template-columns: 15rem minmax(0, 1fr);
  align-items: center;
  gap: var(--space-2xl);
}

/* The portrait's frame. --radius-xl is the institutional panel corner; the 2px gold
   border is the masthead's one strong accent — on navy a full gold frame reads as a
   frame, not a fill, and it is what the redesign's hero portrait asked for. */
.c-profile__portrait .c-media,
.c-profile__placeholder {
  overflow: hidden;
  border: var(--space-3xs) solid var(--color-accent);
  border-radius: var(--radius-xl);
  background-color: var(--color-photo-plate);
}

/* cover with the crop measured, exactly as on the card: object-position: center top
   keeps vertical overflow leaving from the bottom, never off the top of a head.
   Measured headroom above the subject across the twelve sources is 0%–10.2%, and
   subject centres fall between 44.8% and 53.1% of file width — see
   probe-portrait-extent.php. At 240px wide this frame is larger than the card's, so
   it crops strictly less. */
.c-profile__photo {
  object-fit: cover;
  object-position: center top;
}

.c-profile__placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
  aspect-ratio: var(--ratio-faculty-portrait);
  color: var(--color-primary-700);
  font-size: var(--text-display);
  font-weight: var(--font-weight-bold);
  line-height: var(--leading-flat);
}

/* ---- Identity ---- */
.c-profile__intro {
  min-width: 0;
}

/* The HOD badge. Gold outline on navy rather than the card's navy fill: the
   masthead IS navy, so a navy plate would disappear into it. Gold text on navy is
   8.1:1 (measured). */
.c-profile__flag {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2xs);
  margin-block-end: var(--space-sm);
  padding: var(--space-2xs) var(--space-sm);
  border: 1px solid var(--color-accent);
  border-radius: var(--radius-full);
  color: var(--color-accent);
  font-size: var(--text-ui);
  font-weight: var(--font-weight-semibold);
  letter-spacing: var(--tracking-ui);
  line-height: var(--leading-flat);
  text-transform: uppercase;
}

.c-profile__flag-icon {
  display: inline-flex;
  flex: 0 0 auto;
}

/* The page's h1: --text-profile-name, sized above every other page title because the
   masthead is the page's hero and the name is its headline. balance evens a two-line
   wrap rather than leaving one word alone on the second line. */
.c-profile__name {
  color: var(--color-text-on-dark);
  font-size: var(--text-profile-name);
  font-weight: var(--font-weight-bold);
  letter-spacing: var(--tracking-display);
  line-height: var(--leading-heading);
  text-wrap: balance;
}

/* The same gold ornament as the card, ranged left with the name. */
.c-profile__ornament {
  display: flex;
  align-items: center;
  gap: var(--space-2xs);
  margin-block: var(--space-sm);
}

.c-profile__ornament::before,
.c-profile__ornament::after {
  content: "";
  width: var(--space-xl);
  height: var(--space-3xs);
  border-radius: var(--radius-full);
  background-color: var(--color-accent);
}

.c-profile__gem {
  width: var(--space-xs);
  height: var(--space-xs);
  background-color: var(--color-accent);
  transform: rotate(45deg);
}

.c-profile__role {
  color: var(--color-text-on-dark);
  font-size: var(--text-body-lg);
  font-weight: var(--font-weight-semibold);
}

.c-profile__dept {
  color: var(--color-text-on-dark-muted);
  font-size: var(--text-body);
}

/* Credential chips on navy: a light hairline and a transparent fill, where the card
   uses a gold hairline on a warm fill. The card's warm fill is a near-white and would
   be a bright block here; the outline carries the same "discrete credential" reading
   without introducing a light field into the masthead. White on navy is 14.1:1. */
.c-profile__quals {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2xs);
  margin-block-start: var(--space-md);
  padding: 0;
  list-style: none;
}

.c-profile__qual-chip {
  padding: var(--space-2xs) var(--space-sm);
  border: 1px solid var(--color-border-on-dark);
  border-radius: var(--radius-md);
  color: var(--color-text-on-dark);
  font-size: var(--text-sm);
  font-weight: var(--font-weight-medium);
  white-space: nowrap;
}

/* ---- Body band ----
   The white band under the masthead. The page's other bands carry a section's
   worth of furniture — headers, grids of cards — but this one holds a biography
   card and two content columns, and a full --space-section (96px) of air above
   and below them read as emptiness rather than rhythm. Stepped to ~82px on
   desktop, still relative to --space-section so the tablet/mobile rhythm
   presets carry it down with the rest of the page (64 -> ~54, 48 -> ~41). */
.c-profile__body {
  padding-block: calc(var(--space-section) * 0.85);
}

/* The container now stacks three things — the biography card, the content grid
   and the back link — so its own rhythm is the page's: 48px between them on
   desktop, carried down by nothing because each child either self-omits or
   sits in the flow. Sections whose data is absent simply never appear, which
   is what keeps the band from developing blank gaps. */
.c-profile__body > .l-container > * + * {
  margin-block-start: var(--space-2xl);
}

/* ---- The shared card ----
   ONE FORMULA for every card on the page: white surface (the aside's panels sit
   on --color-surface-tint, the palest blue in the scale, so the facts column
   reads a half-step warmer than the prose column), --radius-xl's 16px corner,
   the hairline border, --shadow-sm's falloff. Navy owns the masthead and the
   headings; gold is the accent; white owns the content. No card is dark navy,
   nothing is a gradient. */
.c-profile__card,
.c-profile__panel {
  padding: var(--space-xl);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-xl);
  background-color: var(--color-surface);
  box-shadow: var(--shadow-sm);
}

.c-profile__panel {
  background-color: var(--color-surface-tint);
}

/* Every card heading: the pale-blue circle with its glyph, beside a navy title.
   The heading's own gold rule (below) is carried on the title, so the pair
   reads as one unit — icon, title, rule. */
.c-profile__card-head {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  margin-block-end: var(--space-md);
}

.c-profile__card-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: var(--space-2xl);
  height: var(--space-2xl);
  border-radius: var(--radius-full);
  background-color: var(--color-primary-100);
  color: var(--color-primary-600);
}

/* Inside the head the titles carry no margin of their own — the head owns the
   offset below it — and the panel title joins the section heading's gold rule
   so all six cards share one heading treatment. */
.c-profile__card-head .c-profile__heading,
.c-profile__card-head .c-profile__panel-title {
  margin-block-end: 0;
}

/* ---- Body: main column + aside ----
   2fr : 1fr — the editorial split the redesign asks for: the main column is
   read (research, publications), the aside is looked up (facts, contact,
   profiles), and the main column earns the wider track. The gap is --space-xl
   (32px), inside the 28-36px window the layout specifies.

   align-items: start so both columns begin on the same top baseline, and the
   aside's cards stay at the top rather than stretching to whatever height the
   publications list reaches. */
.c-profile__layout {
  display: grid;
  grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
  align-items: start;
  gap: var(--space-xl);
}

.c-profile__main > * + * {
  margin-block-start: var(--space-xl);
}

/* Only the aside renders — no research interests and no publications on record. One
   column, and the aside lays its panels out across it rather than sitting in a 300px
   strip beside a blank half-page (see the note in profile.php).

   minmax with a MAX, not 1fr: at 1440 a single panel stretched to 1fr would be 1232px
   wide with a label on the far left and a date on the far right, which is unreadable.
   Capped at 22rem the panel keeps the same measure it has in the two-column layout,
   and auto-fit collapses the tracks it does not need — so one panel is one 352px
   column packed to the left, and three panels are three. */
.c-profile__layout--single {
  grid-template-columns: minmax(0, 1fr);
}

.c-profile__layout--single .c-profile__aside {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(18rem, 22rem));
  align-items: start;
  justify-content: start;
  gap: var(--space-lg);
}

.c-profile__layout--single .c-profile__aside > * + * {
  margin-block-start: 0;
}

.c-profile__heading {
  margin-block-end: var(--space-md);
  color: var(--color-primary-700);
  font-size: var(--text-h3);
  font-weight: var(--font-weight-bold);
}

/* A short gold rule under each card heading — the accent's thin-indicator role,
   the same one .c-section-header__dash plays at band level. Both title classes
   carry it so every card on the page, main column or aside, shares one
   heading treatment. */
.c-profile__heading::after,
.c-profile__panel-title::after {
  content: "";
  display: block;
  width: var(--space-2xl);
  height: var(--space-3xs);
  margin-block-start: var(--space-xs);
  border-radius: var(--radius-full);
  background-color: var(--color-accent);
}

/* ---- Biography ----
   The record's own body text: 17px at a relaxed 1.75 leading, secondary ink.
   The card's own interior is the measure — the biography card is a full-width
   child of the container, and a ch-capped column inside it (u-prose's 62ch,
   formerly this rule's 46ch) left half the card blank beside the text. The
   card's padding is the comfortable inset, the container's 1280px cap is the
   readable bound, and the text wraps to whatever interior width remains at
   each breakpoint. Paragraph spacing is wpautop's <p> rhythm; the card
   supplies the frame. */
.c-profile .c-profile__bio {
  color: var(--color-text-secondary);
  font-size: var(--text-body-lg);
  line-height: var(--leading-prose-relaxed);
  max-width: none;
}

.c-profile .c-profile__bio p + p {
  margin-block-start: var(--space-md);
}

/* ---- Research interest tags ----
   The stored string, segmented verbatim: one tag per interest. Gold outline on
   the palest blue surface, navy ink — the same three colours as every other
   card, with gold as the outline because the tag is the accent moment of the
   research card. */
.c-profile__tags {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-xs);
  margin: 0;
  padding: 0;
  list-style: none;
}

.c-profile__tag {
  padding: var(--space-2xs) var(--space-sm);
  border: 1px solid var(--color-accent);
  border-radius: var(--radius-md);
  background-color: var(--color-surface-tint);
  color: var(--color-primary-700);
  font-size: var(--text-sm);
  font-weight: var(--font-weight-medium);
  line-height: var(--leading-flat);
}

/* ---- Publications ---- */
.c-profile__papers {
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
  margin: 0;
  padding: 0;
  list-style: none;
}

/* Icon, citation, download — the download pushed to the right by the 1fr middle
   column, so a row of them lines up however long the titles are. */
.c-paper {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--space-md);
  padding: var(--space-md);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background-color: var(--color-surface);
  transition: box-shadow var(--transition-base), border-color var(--transition-base);
}

.c-paper:hover {
  border-color: var(--color-border-accent);
  box-shadow: var(--shadow-sm);
}

.c-paper__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: var(--space-2xl);
  height: var(--space-2xl);
  border-radius: var(--radius-md);
  background-color: var(--color-primary-100);
  color: var(--color-primary-600);
}

.c-paper__body {
  display: flex;
  flex-direction: column;
  gap: var(--space-3xs);
  min-width: 0;
}

.c-paper__title {
  color: var(--color-text-primary);
  font-size: var(--text-body);
  font-weight: var(--font-weight-medium);
  line-height: var(--leading-heading);
}

.c-paper__note {
  color: var(--color-text-muted);
  font-size: var(--text-xs);
}

.c-paper__download {
  flex: 0 0 auto;
  white-space: nowrap;
}

/* ---- Aside panels ---- */
.c-profile__aside > * + * {
  margin-block-start: var(--space-lg);
}

/* The panel title: the aside's own voice — the uppercase letter-spaced eyebrow —
   now carrying the same gold rule as the main column's headings so the two
   columns read as one page. Spacing is owned by the card head above. */
.c-profile__panel-title {
  color: var(--color-primary-700);
  font-size: var(--text-ui);
  font-weight: var(--font-weight-bold);
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase;
}

/* Definition list, one label/value pair per row, separated by hairlines rather than
   by gap alone — the pairs are a table of facts and the rule is what stops a long
   value running visually into the next label. */
.c-profile__facts {
  margin: 0;
}

.c-profile__fact {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-xs);
  padding-block: var(--space-xs);
}

.c-profile__fact + .c-profile__fact {
  border-block-start: 1px solid var(--color-border);
}

.c-profile__fact dt {
  color: var(--color-text-muted);
  font-size: var(--text-xs);
  font-weight: var(--font-weight-semibold);
  letter-spacing: var(--tracking-ui);
  text-transform: uppercase;
  /* 10-base.css sets overflow-wrap: break-word globally, which breaks a two-word
     label mid-word once the aside narrows. A label breaks between its words or not
     at all. */
  overflow-wrap: normal;
}

.c-profile__fact dd {
  margin: 0;
  color: var(--color-text-primary);
  font-size: var(--text-sm);
  font-weight: var(--font-weight-medium);
  text-align: end;
}

/* ---- Contact ---- */
.c-profile__contact {
  display: flex;
  align-items: center;
  gap: var(--space-xs);
  min-width: 0;
}

/* An email address is one unbroken token and will overflow a 300px panel. It wraps
   at any character here — there is no word boundary to break at and an overflowing
   address is worse than a wrapped one. */
.c-profile__contact a {
  font-size: var(--text-sm);
  font-weight: var(--font-weight-medium);
  overflow-wrap: anywhere;
}

/* ---- Academic profiles ----
   One row per service: glyph | service name | link. The hairline between rows is
   what makes the list read as a table of profiles rather than a stack of
   captions, the same role it plays in the service record above. */
.c-profile__ids {
  margin: 0;
  padding: 0;
  list-style: none;
}

.c-profile__id {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--space-sm);
  padding-block: var(--space-sm);
}

.c-profile__id + .c-profile__id {
  border-block-start: 1px solid var(--color-border);
}

/* The small pale-blue circle, half the card head's: the row is a look-up line,
   not a heading, and its glyph should not compete with the one above it. */
.c-profile__id-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: var(--space-xl);
  height: var(--space-xl);
  border-radius: var(--radius-full);
  background-color: var(--color-primary-100);
  color: var(--color-primary-600);
}

.c-profile__id-label {
  color: var(--color-text-primary);
  font-size: var(--text-sm);
  font-weight: var(--font-weight-semibold);
  overflow-wrap: normal;
}

/* The link is ranged right: the row's eye path is name -> value, and the value
   is where the action is. The gold arrow is the accent's wayfinding role,
   attached to the project-blue link text. An ORCID iD is 19 characters; it
   wraps rather than overflows, for the same reason as the email above. */
.c-profile__id-link {
  display: inline-flex;
  align-items: center;
  justify-content: end;
  gap: var(--space-2xs);
  font-size: var(--text-sm);
  text-align: end;
}

.c-profile__id-link .c-profile__id-value {
  overflow-wrap: anywhere;
}

.c-profile__id-value {
  font-size: var(--text-sm);
}

.c-profile__id-arrow {
  color: var(--color-accent-hover);
  font-weight: var(--font-weight-bold);
  line-height: var(--leading-flat);
}

/* The unlinked fallback, for a value that failed validation: the same text
   treatment as the link, without the arrow, so a row's shape does not change
   with its linkability. */
.c-profile__id > .c-profile__id-value {
  justify-self: end;
  overflow-wrap: anywhere;
}

/* ---- Back to Faculty ----
   The archive link now closes the PAGE rather than the aside, so its offset is
   the container's own 48px rhythm above (`.c-profile__body > .l-container >
   * + *`) and needs no rule of its own here. What it does need is its look: a
   quiet navy link with the gold arrow, comfortable to tap, never a button —
   the page's last line, not its loudest. */
.c-profile__back-link {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2xs);
  color: var(--color-primary-600);
  font-size: var(--text-sm);
  font-weight: var(--font-weight-semibold);
}

.c-profile__back-arrow {
  color: var(--color-accent-hover);
  font-weight: var(--font-weight-bold);
  line-height: var(--leading-flat);
}

/* ---- Profile responsive ----
   Two steps, both driven by measured content rather than by device classes.

   1023 and below: the two body columns stack. At 1024 the aside is 290px and its
   fact rows put a label and a value on one line; below that the ratio would take it
   under 260px, where "Joining Date" and a date no longer fit side by side.

   767 and below: the masthead stacks too, and the portrait narrows. A 240px portrait
   beside identity text at 375 leaves ~100px for a name at --text-h1. */
@media (max-width: 1023px) {
  .c-profile__layout {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-xl);
  }

  /* Stacked, the aside is full width, so its panels sit side by side instead of in a
     column — three full-width tinted panels stacked would be a tower of boxes below
     the content. Capped at 22rem for the same reason as the single-column rule above:
     a stretched fact panel puts its label and value at opposite ends of the viewport.
     auto-fit collapses to one track when only one panel renders, which is the current
     state of every record. */
  .c-profile__aside {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(18rem, 22rem));
    align-items: start;
    justify-content: start;
    gap: var(--space-lg);
  }

  /* The stack margin belongs to the column layout; the grid's gap replaces it. */
  .c-profile__aside > * + * {
    margin-block-start: 0;
  }
}

@media (max-width: 767px) {
  .c-profile__masthead {
    padding-block: var(--space-xl);
  }

  /* The cards keep their corner and hairline but give back interior at phone
     width: 32px of inset beside a 16px gutter is more frame than fact. */
  .c-profile__card,
  .c-profile__panel {
    padding: var(--space-lg);
  }

  .c-profile__identity {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-lg);
  }

  /* The portrait is capped rather than full width: at 358px a 4:5 frame is 448px
     tall, which pushes the name off a 667px-tall viewport entirely. 12rem keeps the
     face legible and the name above the fold. */
  .c-profile__portrait {
    max-width: 12rem;
  }

  /* Icon, citation and download stack: at 358px the three-column row left ~120px for
     a title, and the download button's label wrapped. The button then spans the row,
     which also gives it a full-width tap target. */
  .c-paper {
    grid-template-columns: auto minmax(0, 1fr);
    padding: var(--space-sm);
  }

  .c-paper__download {
    grid-column: 1 / -1;
    justify-content: center;
    width: 100%;
  }
}

/* ========================= PROGRAMME DETAIL =============================
   The individual programme page, rendered by template-parts/programme/detail.php
   for every programme record — B.Ed., M.Ed., B.Ed. (UPRTOU) and anything
   published later. One stylesheet block, one template: nothing here knows a
   programme's name, a syllabus or a semester count.

   STRUCTURE. A tinted hero carrying the identity (eyebrow, title, subtitle,
   duration chips, and — only when those fields exist — an at-a-glance panel),
   then a white band split into a wide main column (section headings, semester
   cards, prose) and a narrow aside (the Programme Overview panel and the
   syllabus link). The same two-column logic as the faculty profile: the main
   column is read, the aside is looked up.

   Every section self-omits when its data is absent, so the page must look
   deliberate with only a hero too — which is why the hero carries the visual
   weight and the body carries none of its own. */

/* ---- Hero ----
   A reduced band rhythm, like the faculty masthead: the hero has no full
   --space-section of air around it, or the content starts below the fold. */
.c-programme-page__hero {
  padding-block: var(--space-lg) var(--space-2xl);
  border-block-end: 1px solid var(--color-border-subtle);
}

.c-programme-page__hero-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(16rem, 20rem);
  align-items: start;
  gap: var(--space-xl);
}

.c-programme-page__hero-grid--single {
  grid-template-columns: minmax(0, 1fr);
}

.c-programme-page__eyebrow {
  margin-block-end: var(--space-2xs);
  color: var(--color-primary-500);
  font-size: var(--text-ui);
  font-weight: var(--font-weight-semibold);
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase;
}

.c-programme-page__title {
  margin: 0;
}

/* The one gold accent in the hero: a short rule between the title and the
   subtitle, the same thin-indicator role .c-section-header__dash plays. Gold is
   deliberately NOT the title colour — accent stays wayfinding, never a field. */
.c-programme-page__rule {
  width: var(--space-2xl);
  height: var(--space-3xs);
  margin-block: var(--space-sm) var(--space-md);
  border-radius: var(--radius-full);
  background-color: var(--color-accent);
}

.c-programme-page__subtitle {
  margin: 0;
  color: var(--color-text-secondary);
  font-size: var(--text-body-lg);
}

/* ---- Duration chips ---- */
.c-programme-page__chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-sm);
  margin: var(--space-lg) 0 0;
  padding: 0;
  list-style: none;
}

.c-programme-page__chip {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2xs);
  padding: var(--space-2xs) var(--space-md);
  border: 1px solid var(--color-primary-100);
  border-radius: var(--radius-full);
  background-color: var(--color-primary-100);
  color: var(--color-primary-700);
  font-size: var(--text-sm);
  font-weight: var(--font-weight-semibold);
}

/* A small gold dot inside each chip — the accent's wayfinding role again, on a
   surface dark enough for gold to read. */
.c-programme-page__chip::before {
  content: "";
  flex: 0 0 auto;
  width: calc(var(--space-xs) * 0.75);
  height: calc(var(--space-xs) * 0.75);
  border-radius: var(--radius-full);
  background-color: var(--color-accent);
}

/* ---- Hero at-a-glance panel: a white card on the tinted hero, the one
   elevated surface there. ---- */
.c-programme-page__glance {
  padding: var(--space-lg);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  background-color: var(--color-surface);
  box-shadow: var(--shadow-sm);
}

/* ---- Body layout ---- */
.c-programme-page__layout {
  display: grid;
  grid-template-columns: minmax(0, 2.2fr) minmax(0, 1fr);
  align-items: start;
  gap: var(--space-2xl);
}

.c-programme-page__layout--single {
  grid-template-columns: minmax(0, 1fr);
}

.c-programme-page__main > * + * {
  margin-block-start: var(--space-xl);
}

/* ---- Section headings (h2) and the gold rule under each — the faculty
   profile's own heading treatment, so both detail pages speak the same
   typographic language. ---- */
.c-programme-page__section-title {
  margin-block-end: var(--space-md);
  color: var(--color-primary-700);
  font-size: var(--text-h2);
  font-weight: var(--font-weight-bold);
}

.c-programme-page__section-title::after {
  content: "";
  display: block;
  width: var(--space-2xl);
  height: var(--space-3xs);
  margin-block-start: var(--space-xs);
  border-radius: var(--radius-full);
  background-color: var(--color-accent);
}

/* ---- Semester cards ----
   White cards, hairline border, soft shadow: restrained, institutional. The
   heading is navy text (not a navy band) — four navy bands down the page would
   be a wall; the gold is reserved for the numbering and the card's hairline
   header rule. */
.c-programme-page__semester {
  padding: var(--space-lg);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  background-color: var(--color-surface);
  box-shadow: var(--shadow-sm);
}

.c-programme-page__semester-title {
  margin-block-end: var(--space-sm);
  padding-block-end: var(--space-sm);
  border-block-end: 1px solid var(--color-border);
  color: var(--color-primary-700);
  font-size: var(--text-ui);
  font-weight: var(--font-weight-bold);
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase;
}

/* ---- Course rows ----
   An <ol> whose numbering is a CSS counter, so rows are numbered continuously
   across a labelled group without the group label consuming a number. The
   number itself prints into .c-programme-page__num. */
.c-programme-page__courses {
  margin: 0;
  padding: 0;
  list-style: none;
  counter-reset: tdc-course;
}

.c-programme-page__courses > li + li,
.c-programme-page__courses--nested > li + li {
  border-block-start: 1px solid var(--color-border-subtle);
}

.c-programme-page__course {
  display: flex;
  gap: var(--space-md);
  padding-block: var(--space-sm);
  counter-increment: tdc-course;
}

/* The row number in the eyebrow blue, not the accent gold: #fbba1a on white is
   under 2:1 and the number is read as text, not decoration. Gold stays in its
   wayfinding roles elsewhere on the page. */
.c-programme-page__num {
  flex: 0 0 auto;
  min-width: var(--space-xl);
  padding-block-start: var(--space-3xs);
  color: var(--color-primary-500);
  font-size: var(--text-sm);
  font-weight: var(--font-weight-bold);
  font-variant-numeric: tabular-nums;
}

.c-programme-page__num::before {
  content: counter(tdc-course, decimal-leading-zero);
}

.c-programme-page__course-body {
  display: flex;
  flex: 1 1 auto;
  flex-wrap: wrap;
  align-items: baseline;
  column-gap: var(--space-md);
  row-gap: var(--space-3xs);
  min-width: 0;
}

.c-programme-page__course-code {
  flex: 0 0 auto;
  color: var(--color-primary-600);
  font-size: var(--text-sm);
  font-weight: var(--font-weight-semibold);
}

.c-programme-page__course-title {
  flex: 1 1 12rem;
  color: var(--color-text-primary);
  font-size: var(--text-body);
  line-height: var(--leading-body);
}

.c-programme-page__course-meta {
  flex: 0 0 auto;
  margin-inline-start: auto;
  color: var(--color-text-muted);
  font-size: var(--text-xs);
}

/* ---- Labelled groups inside a semester (UPRTOU's "Theory, compulsory:",
   the B.Ed. optional-paper list) ---- */
.c-programme-page__group-label {
  margin-block-end: var(--space-2xs);
  color: var(--color-text-muted);
  font-size: var(--text-xs);
  font-weight: var(--font-weight-semibold);
  letter-spacing: var(--tracking-ui);
  text-transform: uppercase;
}

.c-programme-page__courses--nested {
  margin: 0;
  padding: 0;
  list-style: none;
}

/* ---- Prose ----
   u-prose already sets the measure; this adds the page's body voice. */
.c-programme-page__prose {
  color: var(--color-text-secondary);
}

.c-programme-page__prose p {
  margin: 0;
}

.c-programme-page__prose > * + * {
  margin-block-start: var(--space-sm);
}

/* ---- Raw (editor-authored HTML) content ----
   The parser never touches marked-up content; it renders through the_content()
   into this block, so authored tables need actual table styling here — navy
   header, gold top edge, hairline rows, internal scroll only. A table is
   display:block on this scope alone so it can scroll horizontally on phones
   without the page scrolling with it. */
.c-programme-page__raw table {
  display: block;
  max-width: 100%;
  overflow-x: auto;
  border-collapse: collapse;
  border-block-start: 3px solid var(--color-accent);
  border-radius: var(--radius-sm);
}

.c-programme-page__raw th {
  padding: var(--space-sm) var(--space-md);
  background-color: var(--color-primary-700);
  color: var(--color-text-on-dark);
  font-size: var(--text-sm);
  font-weight: var(--font-weight-semibold);
  text-align: start;
  white-space: nowrap;
}

.c-programme-page__raw td {
  padding: var(--space-sm) var(--space-md);
  border: 1px solid var(--color-border);
  font-size: var(--text-sm);
}

.c-programme-page__raw tr:nth-child(even) td {
  background-color: var(--color-surface-alt);
}

/* ---- Aside ---- */
.c-programme-page__aside > * + * {
  margin-block-start: var(--space-lg);
}

/* Tinted panel, the faculty aside's own surface, for the same reason: the body
   band is white, so a white panel with a border would read as an empty box. */
.c-programme-page__panel {
  padding: var(--space-lg);
  border-radius: var(--radius-lg);
  background-color: var(--color-surface-alt);
}

.c-programme-page__panel-title {
  margin-block-end: var(--space-md);
  color: var(--color-primary-700);
  font-size: var(--text-ui);
  font-weight: var(--font-weight-bold);
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase;
}

/* Definition list, one label/value pair per row with hairline separators — the
   faculty facts pattern. A long value (eligibility wording) wraps under its
   label rather than pushing it off the panel. */
.c-programme-page__facts {
  margin: 0;
}

.c-programme-page__fact {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-xs);
  padding-block: var(--space-xs);
}

.c-programme-page__fact + .c-programme-page__fact {
  border-block-start: 1px solid var(--color-border);
}

.c-programme-page__fact dt {
  color: var(--color-text-muted);
  font-size: var(--text-xs);
  font-weight: var(--font-weight-semibold);
  letter-spacing: var(--tracking-ui);
  text-transform: uppercase;
  overflow-wrap: normal;
}

.c-programme-page__fact dd {
  margin: 0;
  color: var(--color-text-primary);
  font-size: var(--text-sm);
  font-weight: var(--font-weight-medium);
  text-align: end;
}

/* The syllabus link's own block: the class is the probe contract (see
   detail.php), the spacing is the only thing owned here. */
.c-programme-page__panel .c-programme-syllabus {
  margin-block-start: var(--space-md);
}

.c-programme-page__aside-link {
  padding-inline: var(--space-2xs);
}

/* ---- Closing CTA ----
   The banner's look is the homepage CTA component's own (.c-cta__banner);
   this owns only its separation from the content above. */
.c-programme-page__cta-band {
  margin-block-start: var(--space-2xl);
}

/* ---- Programme detail responsive ----
   1023 and below: both grids stack, for the measured-content reason the faculty
   layout stacks — the aside's fact rows put a label and a value on one line,
   and below 1024 the ratio would take that column under 260px. Stacked, the
   aside lays its panel across the full width capped at the measure it keeps in
   the two-column layout, rather than one stretched box. */
@media (max-width: 1023px) {
  .c-programme-page__hero-grid,
  .c-programme-page__hero-grid--single {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-xl);
  }

  .c-programme-page__layout,
  .c-programme-page__layout--single {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-xl);
  }

  .c-programme-page__aside {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(18rem, 22rem));
    align-items: start;
    justify-content: start;
    gap: var(--space-lg);
  }

  .c-programme-page__aside > * + * {
    margin-block-start: 0;
  }

  .c-programme-page__aside-link {
    grid-column: 1 / -1;
  }
}

/* 767 and below: the hero tightens, the semester card sheds a step of padding,
   and the course row keeps its number but lets the meta drop under the title —
   a phone row is one column of text beside its index, not a squeezed grid. */
@media (max-width: 767px) {
  .c-programme-page__hero {
    padding-block: var(--space-md) var(--space-xl);
  }

  .c-programme-page__semester {
    padding: var(--space-md);
  }

  .c-programme-page__course {
    gap: var(--space-sm);
  }

  .c-programme-page__course-title {
    flex-basis: 100%;
  }

  .c-programme-page__course-meta {
    margin-inline-start: var(--space-xl);
  }

  .c-programme-page__glance {
    box-shadow: none;
  }
}

/* ============================= CTA BAND ================================ */

/*
 * FOOTER PASS. The CTA is no longer a tall full-bleed navy slab: the section
 * now carries the page's own surface and the message sits on a compact
 * rounded banner — deep navy under a gold edge, the department as a gold
 * eyebrow, and the two existing actions at their compact size.
 *
 * The band's vertical padding is set here rather than inherited from .l-band
 * so the section is compact by default. The Homepage editor's spacing choices
 * must still win, so each override is restated at .c-cta specificity after
 * the base rule: source order in this file beats 20-layout.css, and the
 * compound selectors beat the base one.
 */
.c-cta {
  padding-block: var(--space-md);
  color: var(--color-text-on-dark-muted);
}

.c-cta.l-band--space-sm {
  padding-block: calc(var(--space-section) * 0.6);
}

.c-cta.l-band--space-lg {
  padding-block: calc(var(--space-section) * 1.35);
}

.c-cta.l-band--space-flush {
  padding-block: 0;
}

/* The banner: deep institutional navy under a gold top edge, rounded like the
   site's cards, one hairline border lifting it off the page surface. The
   gradient is the hero's origin-to-primary pair, so the banner reads as the
   same navy family rather than a new colour. Vertical padding is one step
   below the horizontal: a banner, not a slab. */
.c-cta__banner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-xl);
  padding: var(--space-md) var(--space-xl);
  border: 1px solid rgb(255 255 255 / 12%);
  border-block-start: 3px solid var(--color-accent);
  border-radius: var(--radius-lg);
  background-image: linear-gradient(115deg, var(--color-primary-800), var(--color-primary-700));
  box-shadow: var(--shadow-md);
}

/* The copy column may shrink; the actions never force the banner wider than
   the container. */
.c-cta__content {
  min-width: 0;
}

/* The department, in the eyebrow voice the section headers use. Gold, per
   the reference: the one accent on the banner besides the edge. */
.c-cta__eyebrow {
  margin-block-end: var(--space-2xs);
  color: var(--color-accent);
  font-size: var(--text-ui);
  font-weight: var(--font-weight-semibold);
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase;
}

.c-cta__title {
  margin-block-end: var(--space-2xs);
  color: var(--color-text-on-dark);
}

.c-cta__subline {
  margin: 0;
}

.c-cta__actions {
  display: flex;
  flex: 0 0 auto;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: var(--space-md);
}

/* Tablet keeps the banner horizontal: at 768px the copy column and the two
   md buttons still fit beside each other, and the contract only stacks CTAs
   at phone width. */
@media (max-width: 767px) {
  .c-cta__banner {
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-md);
    padding: var(--space-md);
  }

  .c-cta__actions {
    width: 100%;
    flex-direction: column;
  }

  .c-cta__actions .c-btn {
    width: 100%;
  }
}

/* ============================== FOOTER ================================= */

/*
 * FOOTER PASS. The footer is compact and information-rich: a brand column
 * that mirrors the header masthead (crest, department, parent college), ruled
 * column headings, icon-led contact rows, and a one-line copyright strip.
 * Content determines the height — no min-height, tight band padding.
 */
.c-footer {
  background-color: var(--color-primary-900);
  color: var(--color-text-on-dark-muted);
  font-size: var(--text-sm);
  line-height: var(--leading-body);
}

/* Tight band: the columns' own rhythm carries the footer's height, so the
   main area no longer pads the content out into a tall navy slab. */
.c-footer__main {
  padding-block: var(--space-xl);
}

/* Column headings: eyebrow type sitting on a hairline, so each column opens
   with a ruled label instead of text floating in the navy. */
.c-footer__heading {
  margin-block-end: var(--space-sm);
  padding-block-end: var(--space-sm);
  border-block-end: 1px solid var(--color-border-on-dark);
  color: var(--color-text-on-dark);
  font-size: var(--text-ui);
  font-weight: var(--font-weight-semibold);
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase;
}

/* ---- Brand column ----
   The masthead's own crest and wordmark, restated small: the same custom
   logo, department name and parent college the header reads, so the two
   cannot drift apart. The crest is decorative exactly as it is up there. */
.c-footer__brand-head {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
}

.c-footer__logo {
  flex: 0 0 auto;
  width: auto;
  height: 40px;
}

.c-footer__brand-name {
  margin: 0;
  color: var(--color-text-on-dark);
  font-size: var(--text-body);
  font-weight: var(--font-weight-bold);
  line-height: 1.3;
}

.c-footer__brand-college {
  margin: 0;
  font-size: var(--text-sm);
}

.c-footer__brand-desc {
  margin-block: var(--space-md) 0;
  max-width: 34ch;
}

/* ---- Column lists ---- */
.c-footer__list {
  margin: 0;
  padding: 0;
  list-style: none;
}

/* The contact address is marked up as <address>, which browsers italicise by
   default. Reset it so it matches the surrounding footer text. */
.c-footer__address {
  font-style: normal;
}

/* One tight rhythm for every column row: the 44px locked tap target already
   spaces the rows, so the inter-row margin stays a hair. */
.c-footer__list li + li {
  margin-block-start: var(--space-2xs);
}

.c-footer__link {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap-target);
  color: var(--color-text-on-dark-muted);
  text-decoration: none;
}

.c-footer__link:hover {
  color: var(--color-text-on-dark);
  text-decoration: underline;
  text-underline-offset: 0.2em;
}

/* ---- Social row in the footer ----

   A horizontal row of icon buttons, not the stacked text links this list carries
   for the quick-links menu. The footer's own li + li margin would put each icon on
   its own line, so it is overridden here rather than the list class being replaced:
   .c-footer__list still supplies the reset. */
.c-footer__social {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-xs);
  margin-block-start: var(--space-md);
}

.c-footer__social li + li {
  margin-block-start: 0;
}

/* 44px, the project's locked touch target. The footer is the one place these links
   are likely to be tapped on a phone, and there is room for it here in a way there
   is not in a 40px utility bar. radius-md, not sm: at 44px the button is a tile,
   and the site's icon tiles round at the card radius. */
.c-footer__social-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: var(--tap-target);
  min-height: var(--tap-target);
  border: 1px solid rgb(255 255 255 / 18%);
  border-radius: var(--radius-md);
  transition: border-color 150ms ease, background-color 150ms ease, color 150ms ease;
}

/* The hover state is gold: border, glyph and a whisper of fill — the footer's
   one accent, matching the CTA edge. NOT an underline: the inherited
   .c-footer__link:hover underline would draw a line under an icon, which
   looks like a rendering fault. */
.c-footer__social-link:hover {
  border-color: var(--color-accent);
  background-color: rgb(251 186 26 / 10%);
  color: var(--color-accent);
  text-decoration: none;
}

.c-footer__social-icon {
  flex: 0 0 auto;
}

/* ---- Contact column ----
   Icon-led rows: the same four glyphs the contact page tiles use, at footer
   scale. Rows share the link columns' 44px rhythm so the tallest columns end
   level, and the icon sits in its own track so multi-line values hang
   cleanly beside it. */
.c-footer__contact {
  margin: 0;
  padding: 0;
  list-style: none;
}

.c-footer__contact-item {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  min-height: var(--tap-target);
}

.c-footer__contact-item + .c-footer__contact-item {
  margin-block-start: var(--space-2xs);
}

.c-footer__contact-icon {
  flex: 0 0 auto;
  color: var(--color-text-on-dark-muted);
}

.c-footer__contact-value {
  min-width: 0;
  /* The email address is one unbreakable token; it must wrap rather than
     push the column past the grid track. */
  overflow-wrap: anywhere;
}

/*
 * Menu anchors receive .c-nav__link from the nav_menu_link_attributes filter,
 * and that class sets a dark text colour for the header. Inside the footer that
 * renders navy on navy, so the colour is re-declared here. The underline
 * indicator is also suppressed: it belongs to the header's current-page state.
 */
.c-footer .c-nav__link {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap-target);
  color: var(--color-text-on-dark-muted);
  font-size: var(--text-sm);
  font-weight: var(--font-weight-regular);
  letter-spacing: normal;
  text-transform: none;
  text-decoration: none;
}

.c-footer .c-nav__link:hover {
  color: var(--color-text-on-dark);
  text-decoration: underline;
  text-underline-offset: 0.2em;
}

.c-footer .c-nav__link::after {
  display: none;
}

/*
 * COPYRIGHT STRIP. A compact closing band, deliberately the shortest on the
 * page: darker navy than the footer above it, separated by a hairline that
 * carries the gold accent at low saturation, and the line itself centred —
 * horizontally against the full viewport (the container is margin-inline:
 * auto, so a centred flex row inside it stays mathematically centred) and
 * vertically by the flex alignment inside the fixed 68px rail. The text is
 * data-driven (year + blogname) and wraps to centred lines on narrow
 * viewports; min-height, not height, so wrapping grows the band, never
 * clips it. No links are invented here — the legal nav renders only if a
 * menu is assigned to the location, and centres with the line when it is.
 */
.c-footer__bottom {
  background-color: #021225; /* primary-900 (#031932) stepped darker, same hue */
  border-block-start: 1px solid rgba(240, 214, 154, 0.38); /* --color-border-accent @ 38% */
}

.c-footer__bottom-inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: var(--space-md);
  min-height: 68px;
  padding-inline: var(--space-md);
  text-align: center;
}

.c-footer__bottom-inner p {
  margin: 0;
  color: var(--color-text-on-dark-muted);
  font-size: var(--text-ui); /* 13px */
  font-weight: var(--font-weight-regular);
  letter-spacing: 0.02em;
}

/* ---- Login links, in the bottom bar ----

   COMPACT UTILITY LINKS, not CTAs: no border, no fill, no button sizing — the
   same typographic weight as the copyright line they share the bar with. The
   bar is centered and wraps, so on a narrow phone the pair simply wraps under
   the copyright rather than overflowing. */

.c-footer__logins {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: var(--space-lg);
  margin: 0;
  padding: 0;
  list-style: none;
}

.c-footer__login-link {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2xs);
  /* Text alone is ~19px tall; this reaches the WCAG 2.2 minimum target size
     the same way the breadcrumb links do, without growing the bar. */
  min-height: var(--tap-target-min);
  color: var(--color-text-on-dark-muted);
  font-size: var(--text-ui);
  letter-spacing: 0.02em;
  text-decoration: none;
}

/* White on hover, and the glyph brightens to the stronger gold — the same
   muted-to-bright pair the utility bar's links use. The keyboard focus ring
   is not declared here: .c-footer :focus-visible in 10-base.css already turns
   the global outline gold on this dark band. */
.c-footer__login-link:hover {
  color: var(--color-text-on-dark);
}

.c-footer__login-link:hover .c-footer__login-icon {
  color: var(--color-accent-strong);
}

.c-footer__login-icon {
  flex: 0 0 auto;
  width: 14px;
  height: 14px;
  /* The restrained gold accent on dark: the glyph is the accent, the label
     stays white, exactly as the utility bar treats its information icons. */
  color: var(--color-accent);
}

/* =========================== BREADCRUMBS =============================== */
.c-breadcrumbs {
  padding-block: var(--space-md);
  font-size: var(--text-xs);
  color: var(--color-text-muted);
}

.c-breadcrumbs__list {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-xs);
  margin: 0;
  padding: 0;
  list-style: none;
}

.c-breadcrumbs__sep {
  color: var(--color-border);
}

/* Breadcrumb text is deliberately small, but the link's hit area must not be.
   The 24px floor meets WCAG 2.2 target size (minimum) without changing the
   visual weight of the trail. */
.c-breadcrumbs__list a {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap-target-min);
}

/* =========================== PAGINATION ================================ */
.c-pagination {
  margin-block-start: var(--space-2xl);
}

.c-pagination .page-numbers {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: var(--tap-target);
  min-height: var(--tap-target);
  padding-inline: var(--space-xs);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  color: var(--color-text-primary);
  font-size: var(--text-sm);
  text-decoration: none;
}

.c-pagination .page-numbers:hover {
  border-color: var(--color-primary-500);
}

.c-pagination .page-numbers.current {
  background-color: var(--color-primary-600);
  border-color: var(--color-primary-600);
  color: var(--color-text-on-dark);
}


/* ========================== FORM CONTROLS ============================== */
.c-field {
  display: flex;
  flex-direction: column;
  gap: var(--space-2xs);
}

.c-field__label {
  font-size: var(--text-sm);
  font-weight: var(--font-weight-medium);
  color: var(--color-text-primary);
}

/* Required marker pairs the symbol with a screen-reader text cue in markup. */
.c-field__required {
  color: var(--color-error);
}

.c-field__control {
  width: 100%;
  min-height: var(--tap-target);
  padding: var(--space-sm) var(--space-md);
  background-color: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  color: var(--color-text-primary);
  font-size: var(--text-body);
  transition:
    border-color var(--transition-base),
    box-shadow var(--transition-base);
}

.c-field__control:hover {
  border-color: var(--color-text-muted);
}

.c-field__control:focus-visible {
  border-color: var(--color-primary-600);
  outline: var(--focus-width) solid var(--focus-color);
  outline-offset: var(--focus-offset);
}

textarea.c-field__control {
  min-height: calc(var(--space-4xl) + var(--space-lg));
  resize: vertical;
}

/* Error state pairs colour with an icon and a text message — never colour
   alone (STEP 2C accessibility rule). */
.c-field__control[aria-invalid="true"] {
  border-color: var(--color-error);
}

.c-field__error {
  display: flex;
  align-items: center;
  gap: var(--space-2xs);
  font-size: var(--text-xs);
  color: var(--color-error);
}

.c-field__hint {
  font-size: var(--text-xs);
  color: var(--color-text-muted);
}

/* ============================== ALERT ================================== */
.c-alert {
  display: flex;
  align-items: flex-start;
  gap: var(--space-sm);
  padding: var(--space-md);
  border: 1px solid var(--color-border);
  border-inline-start-width: var(--space-2xs);
  border-radius: var(--radius-sm);
  background-color: var(--color-surface-alt);
  font-size: var(--text-sm);
}

.c-alert__icon {
  flex: 0 0 auto;
}

.c-alert--success {
  border-inline-start-color: var(--color-success);
}

.c-alert--warning {
  border-inline-start-color: var(--color-warning);
}

.c-alert--error {
  border-inline-start-color: var(--color-error);
}

.c-alert--info {
  border-inline-start-color: var(--color-primary-500);
}

/* ========================== CONTACT PAGE ================================
   The contact page's two-column institutional layout. Contact information
   holds the left ~40% of the container, the enquiry card the right ~60%, and
   both begin at the same height because the grid is start-aligned. It replaces
   the page's former breadcrumb → page-title → form stack, so the page opens
   directly with its content at the compact band rhythm and carries no
   generic title band of its own. */

.l-contact {
  display: grid;
  grid-template-columns: minmax(0, 2fr) minmax(0, 3fr);
  gap: var(--space-2xl);
  align-items: start;
}

/* The page's H1 lives inside the left column, so it is held to the section
   header scale rather than the page-title scale: it must read as a column
   heading beside the card's own "Send an enquiry" heading, and both columns
   must start at the same visual height. */
.l-contact .c-section-header__title {
  font-size: var(--text-h2);
}

.l-contact__info > * + * {
  margin-block-start: var(--space-lg);
}

/* Short measure for the intro sentence; the information list sets its own
   rhythm below it. */
.l-contact__intro {
  max-width: 36ch;
  color: var(--color-text-muted);
}

/* ------------------------------------------------------ contact list ---
   Icon, label, value — one institutional block per populated dashboard
   option. Navy glyph on the light primary tint; gold stays in its sanctioned
   accent roles and does not appear here. */
.c-contact-list {
  display: grid;
  gap: var(--space-lg);
  margin: 0;
  padding: 0;
  list-style: none;
}

.c-contact-list__item {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: var(--space-md);
  align-items: start;
}

.c-contact-list__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--space-2xl);
  height: var(--space-2xl);
  border-radius: var(--radius-md);
  background-color: var(--color-primary-100);
  color: var(--color-primary-600);
}

.c-contact-list__label {
  display: block;
  margin-block-end: var(--space-3xs);
  font-size: var(--text-xs);
  font-weight: var(--font-weight-semibold);
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase;
  color: var(--color-text-muted);
}

.c-contact-list__value {
  font-size: var(--text-body);
  color: var(--color-text-primary);
  /* The address is stored with newlines; they are typeset, not collapsed. */
  white-space: pre-line;
}

a.c-contact-list__value {
  color: var(--color-primary-600);
  text-decoration: none;
}

a.c-contact-list__value:hover {
  color: var(--color-primary-700);
  text-decoration: underline;
  text-underline-offset: 0.2em;
}

/* Location. The dashboard's map link resolves into a live keyless Google Maps
   embed of the SAME destination (see tdc_map_embed() in inc/helpers.php), so
   the college's position is on the page rather than a click away. The frame
   gets the institutional panel treatment: the trust strip's --radius-xl corner
   and the subtle hairline, and no shadow — a shadowed map would compete with
   the enquiry card, which is this page's one elevated surface. The light tint
   is the placeholder the lazy iframe loads against; the uploaded map image,
   when one is set, keeps precedence in the template and never meets these
   rules. */
.c-contact-map {
  display: grid;
  gap: var(--space-md);
}

.c-contact-map__embed {
  height: 280px;
  margin: 0;
  overflow: hidden;
  border: 1px solid var(--color-border-subtle);
  border-radius: var(--radius-xl);
  background-color: var(--color-surface-alt);
}

.c-contact-map__embed iframe {
  display: block;
  width: 100%;
  height: 100%;
  border: 0;
}

/* The link stays under the frame as its caption and its accessible fallback:
   the same destination, one click away, exactly as before the embed. */
.c-contact-map__link {
  font-size: var(--text-sm);
  font-weight: var(--font-weight-medium);
}

/* ----------------------------------------------------- enquiry card ---
   The form card: the page's one bordered, elevated surface, matching the card
   treatment used by the homepage's bands. */
.c-enquiry-card {
  padding: var(--space-2xl);
  background-color: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-sm);
}

.c-enquiry-form {
  display: grid;
  gap: var(--space-lg);
  margin-block-start: var(--space-xl);
}

.c-enquiry-card__alert {
  margin-block-start: var(--space-lg);
}

/* Short fields pair up; the message spans both tracks. Field heights,
   borders, focus rings and required marks are inherited unchanged from the
   shared .c-field rules above. */
.c-enquiry-fields {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-lg) var(--space-md);
}

.c-field--full {
  grid-column: 1 / -1;
}

.c-enquiry-card__submit {
  margin: 0;
}

/* -------------------------------------------- contact page responsive */
@media (max-width: 1023px) {
  /* One column: information first, form below — the template's source order
     already reads that way, so no reordering is needed. */
  .l-contact {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-2xl);
  }
}

@media (max-width: 767px) {
  /* Paired fields collapse to one track: at 375px two tracks would give
     ~140px inputs, too narrow for labels like "Email address". */
  .c-enquiry-fields {
    grid-template-columns: minmax(0, 1fr);
  }

  .c-enquiry-card {
    padding: var(--space-lg);
  }

  .c-contact-list {
    gap: var(--space-md);
  }

  /* The map keeps its corner and hairline but gives back height: at 375px the
     column is ~330px wide and 280px of map under the address list would push
     the enquiry form well past the fold. 220px still reads as a place. */
  .c-contact-map__embed {
    height: 220px;
  }
}

/* ===================== DEVELOPMENT PLACEHOLDER =========================
   Used only to prove layout while dashboard entities are unresolved. The
   hatched surface and explicit label make it impossible to mistake for real
   content, and nothing in this theme prints institutional text into it. */
.c-dev-placeholder {
  padding: var(--space-lg);
  border: 1px dashed var(--color-warning);
  border-radius: var(--radius-md);
  background-image: repeating-linear-gradient(
    45deg,
    var(--color-surface-alt),
    var(--color-surface-alt) 10px,
    var(--color-surface) 10px,
    var(--color-surface) 20px
  );
  color: var(--color-warning);
  font-size: var(--text-sm);
  font-weight: var(--font-weight-semibold);
}

.c-dev-placeholder__label {
  display: inline-block;
  margin-block-end: var(--space-2xs);
  font-size: var(--text-xs);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
}

