/* ============================================================================
   CHAO COLLEGE — LAYOUT & COMPONENTS
   ----------------------------------------------------------------------------
   No colors or font names live in this file. Everything references a token
   from brand/tokens.css. If you need a new color, add a token there first.
   ========================================================================= */

/* --- Reset ------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
body {
  margin: 0;
  font-family: var(--font-body);
  font-size: 1rem;
  line-height: 1.65;
  color: var(--color-text);
  background: var(--color-page-bg);
  -webkit-font-smoothing: antialiased;
}
img, svg, video { max-width: 100%; height: auto; display: block; }
h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-weight: var(--display-weight);
  letter-spacing: var(--display-tracking);
  color: var(--color-heading);
  line-height: 1.2;
  margin: 0 0 var(--space-4);
  /* WCAG 1.4.10. At 320px a single long word in a banner heading
     ("Representatives", "Communication") is wider than the column and pushes
     the whole page sideways. Break only words that cannot otherwise fit. */
  overflow-wrap: break-word;
}
h1 { font-size: clamp(2rem, 4.5vw, 3rem); }
h2 { font-size: clamp(1.6rem, 3vw, 2.25rem); }
h3 { font-size: 1.25rem; }
p, ul, ol { margin: 0 0 var(--space-4); }
a { color: var(--color-link); text-decoration-thickness: 1px; text-underline-offset: 2px; }
a:hover { color: var(--color-link-hover); }
:focus-visible {
  outline: 3px solid var(--color-focus);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}

/* --- Utility ----------------------------------------------------------- */
.wrap { width: 100%; max-width: var(--page-max); margin-inline: auto; padding-inline: var(--space-5); }
.wrap--narrow { max-width: 820px; }
.prose { max-width: var(--measure); }
.section { padding-block: var(--space-8); }
.section--tint { background: var(--color-page-alt-bg); }
/* For a section that ends where the next one's padding begins, so the
   two do not stack into an empty band. */
.section--flush { padding-bottom: 0; }
.section__lead { color: var(--color-text-muted); font-size: 1.075rem; max-width: var(--measure); }
.eyebrow {
  font-family: var(--font-ui);
  font-size: .8rem; font-weight: 700;
  letter-spacing: .12em; text-transform: uppercase;
  color: var(--color-text-muted);
  margin: 0 0 var(--space-2);
}
.skip-link {
  position: absolute; left: var(--space-4); top: -100px; z-index: 200;
  background: var(--color-btn-bg); color: var(--color-btn-text);
  padding: var(--space-3) var(--space-4); border-radius: var(--radius-md);
  font-family: var(--font-ui); font-weight: 700; text-decoration: none;
}
.skip-link:focus { top: var(--space-3); }
.visually-hidden {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}

/* --- Buttons ----------------------------------------------------------- */
.btn {
  display: inline-flex; align-items: center; gap: var(--space-2);
  font-family: var(--font-ui); font-weight: 600; font-size: .95rem;
  padding: var(--space-3) var(--space-5);
  border: 1px solid transparent; border-radius: var(--radius-pill);
  background: var(--color-btn-bg); color: var(--color-btn-text);
  text-decoration: none; cursor: pointer;
  transition: background var(--duration) var(--ease), color var(--duration) var(--ease),
              transform var(--duration) var(--ease);
}
.btn:hover { background: var(--color-btn-bg-hover); color: var(--color-btn-text-hover); transform: translateY(-1px); }
.btn--ghost {
  background: var(--color-ghost-bg);
  color: var(--color-text-invert);
  border-color: var(--color-ghost-border);
  backdrop-filter: blur(6px);
}
.btn--ghost:hover { background: var(--color-ghost-bg-hover); color: var(--color-text-invert); }
.btn--outline {
  background: transparent; color: var(--color-link);
  border-color: currentColor;
}
.btn--outline:hover { background: var(--brand-primary); color: var(--color-text-invert); border-color: transparent; }

/* --- Placeholder artwork ----------------------------------------------- *
   Any figure with .ph paints itself from the brand tokens. When a real photo
   arrives, put an <img> inside the same element and it covers the pattern.   */
.ph {
  position: relative; overflow: hidden;
  /* An opaque colour as well as the gradient. A gradient is a background
     IMAGE, so background-color stayed transparent and anything measuring the
     contrast of text over one of these walked up to the white page instead,
     concluding white-on-white. */
  background-color: var(--placeholder-a);
  background-image:
    linear-gradient(135deg, var(--placeholder-a) 0%, var(--placeholder-b) 55%, var(--placeholder-a) 100%);
  isolation: isolate;
}
.ph::before {
  content: ""; position: absolute; inset: 0; z-index: 0;
  background:
    repeating-linear-gradient(115deg,
      transparent 0 44px,
      rgba(255,255,255,.045) 44px 88px),
    radial-gradient(120% 90% at 15% 10%, var(--placeholder-c) 0%, transparent 55%);
  opacity: .9;
}
.ph > img { position: absolute; inset: 0; z-index: 1; width: 100%; height: 100%; object-fit: cover; }
.ph__label {
  position: absolute; z-index: 2; inset-inline: 0; bottom: 0;
  padding: var(--space-7) var(--space-4) var(--space-4);
  font-family: var(--font-ui); font-size: .85rem; line-height: 1.35;
  color: var(--color-text-invert);
  background: linear-gradient(to top, rgba(0,0,0,.78) 0%, rgba(0,0,0,.45) 55%, transparent 100%);
}
.ph__label b { display: block; font-size: .95rem; }

/* --- Site header / nav -------------------------------------------------- */
.site-header {
  position: sticky; top: 0; z-index: 100;
  background: var(--color-nav-bg);
  box-shadow: var(--shadow-sm);
}
.nav {
  display: flex; align-items: center; gap: var(--space-5);
  min-height: var(--nav-height);
}
.nav__brand {
  display: flex; align-items: center; gap: var(--space-3);
  color: var(--color-nav-text); text-decoration: none;
  font-family: var(--font-display); font-size: 1.15rem;
  letter-spacing: var(--display-tracking);
  margin-right: auto; white-space: nowrap;
}
.nav__brand:hover { color: var(--color-nav-text-hover); }

/* The Chao crest. Set `crestImage` in data/site.js to use the artwork; if it is
   null the .crest--letter fallback below is drawn instead. The crest is wider
   than it is tall, so it is sized by HEIGHT and keeps its own aspect ratio. */
.crest {
  flex: none; display: block;
  height: 40px; width: auto;
}
.crest--lg { height: clamp(72px, 9vw, 116px); }

/* Fallback mark used only when no crest image is set. */
.crest--letter {
  display: grid; place-items: center;
  width: 34px; height: 34px; border-radius: 50%;
  background: var(--brand-accent); color: var(--brand-primary-dark);
  font-family: var(--font-display); font-weight: 700; font-size: .95rem;
  line-height: 1; letter-spacing: 0;
  border: 2px solid var(--color-ghost-border);
}
.crest--letter.crest--lg { width: 84px; height: 84px; font-size: 2rem; border-width: 3px; }

.nav__menu { display: flex; align-items: center; gap: var(--space-1); list-style: none; margin: 0; padding: 0; }
.nav__item { position: relative; }
.nav__parent { display: inline-flex; align-items: center; }
.nav__link, .nav__toggle {
  display: inline-flex; align-items: center; gap: var(--space-2);
  font-family: var(--font-ui);
  font-weight: var(--nav-weight);
  letter-spacing: var(--nav-tracking);
  text-transform: var(--nav-transform);
  font-size: .93rem;
  color: var(--color-nav-text); text-decoration: none;
  background: none; border: 0; cursor: pointer;
  padding: var(--space-3) var(--space-3);
  border-radius: var(--radius-sm);
  transition: color var(--duration) var(--ease);
}
/* The caret sits tight against its label rather than reading as its own item. */
.nav__parent .nav__link { padding-right: var(--space-1); }
.nav__parent .nav__toggle { padding-left: var(--space-1); }
.nav__link:hover, .nav__toggle:hover,
.nav__parent:hover .nav__link,
.nav__link[aria-current="page"] { color: var(--color-nav-text-hover); }
.nav__link[aria-current="page"] { text-decoration: underline; text-underline-offset: 6px; }
.nav__caret { width: 8px; height: 8px; border-right: 2px solid currentColor; border-bottom: 2px solid currentColor;
  transform: rotate(45deg) translate(-2px, -2px); transition: transform var(--duration) var(--ease); }
.nav__toggle[aria-expanded="true"] .nav__caret { transform: rotate(-135deg) translate(-2px, -2px); }

.nav__submenu {
  position: absolute; top: calc(100% - 4px); left: 0; min-width: 230px;
  list-style: none; margin: 0; padding: var(--space-2);
  background: var(--color-nav-menu-bg);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-lg);
  display: none;
}
.nav__item--open .nav__submenu { display: block; }
.nav__submenu a {
  display: block; padding: var(--space-2) var(--space-3);
  font-family: var(--font-ui); font-size: .9rem; text-decoration: none;
  color: var(--color-nav-menu-text); border-radius: var(--radius-sm);
}
.nav__submenu a:hover { background: var(--color-page-alt-bg); }

.nav__cta { margin-left: var(--space-3); }
.nav__hamburger { display: none; }

@media (max-width: 900px) {
  .nav__hamburger {
    display: inline-flex; flex-direction: column; justify-content: center; gap: 5px;
    width: 42px; height: 42px; padding: 0 9px;
    background: none; border: 0; cursor: pointer;
  }
  .nav__hamburger span { display: block; height: 2px; background: var(--color-nav-text); border-radius: 2px; }
  .nav__menu {
    display: none; position: absolute; top: var(--nav-height); left: 0; right: 0;
    flex-direction: column; align-items: stretch; gap: 0;
    background: var(--color-nav-bg);
    padding: var(--space-3) var(--space-5) var(--space-6);
    box-shadow: var(--shadow-lg);
    max-height: calc(100vh - var(--nav-height)); overflow-y: auto;
  }
  .site-header--open .nav__menu { display: flex; }
  .nav__item { width: 100%; }
  /* The row rule goes on whichever element is the row: a plain link, or the
     label-plus-caret wrapper. */
  .nav__item > .nav__link,
  .nav__parent { width: 100%; border-bottom: 1px solid var(--color-ghost-border); }
  .nav__parent { justify-content: space-between; }
  .nav__link, .nav__toggle { padding-block: var(--space-4); border-radius: 0; }
  .nav__parent .nav__link { flex: 1; border-bottom: 0; }
  /* A comfortable tap target for the caret, separate from the label's.
     min-height keeps it at the 44px commonly recommended for touch. */
  .nav__parent .nav__toggle { padding-inline: var(--space-4); min-height: 44px; }
  .nav__submenu { position: static; display: none; box-shadow: none; background: transparent;
    padding: var(--space-2) 0 var(--space-3) var(--space-4); }
  .nav__item--open .nav__submenu { display: block; }
  .nav__submenu a { color: var(--color-nav-text); opacity: .9; }
  .nav__submenu a:hover { background: var(--color-ghost-bg); }
  .nav__cta { margin: var(--space-4) 0 0; justify-content: center; }
}

/* --- Hero (home) -------------------------------------------------------- */
.hero {
  position: relative;
  min-height: min(78vh, 640px);
  display: grid; place-items: center;
  text-align: center;
  color: var(--color-text-invert);
}
.hero::after {
  content: ""; position: absolute; inset: 0; z-index: 1;
  background: linear-gradient(to bottom, rgba(0,0,0,.62), rgba(0,0,0,.88));
}
.hero__inner { position: relative; z-index: 2; padding: var(--space-9) var(--space-5); }
.hero__wordmark {
  display: flex; align-items: center; justify-content: center;
  flex-wrap: wrap; gap: var(--space-4);
  font-family: var(--font-display);
  font-weight: var(--display-weight);
  letter-spacing: var(--display-tracking);
  text-transform: var(--display-transform);
  font-size: clamp(2.4rem, 7vw, 4.5rem);
  line-height: 1.05;
  color: var(--color-text-invert);
  margin: 0 0 var(--space-3);
  text-shadow: 0 2px 24px rgba(0,0,0,.35);
}
.hero__tagline {
  font-family: var(--font-ui); font-size: 1.05rem;
  color: var(--color-text-invert); margin: 0 0 var(--space-6);
}
.hero__links { display: flex; flex-wrap: wrap; gap: var(--space-3); justify-content: center; }

/* --- Page banner (interior pages) --------------------------------------- */
.banner {
  position: relative; color: var(--color-text-invert);
  /* The ground (.banner__bg) and the scrim both paint over this, so it changes
     nothing visually. It matters twice: a contrast checker walking up from the
     breadcrumb finds a real colour instead of the white page, and if the
     renderer never injects .banner__bg the white text still has something dark
     behind it. The real ground is the gradient under a 42% black scrim, which
     is darker than this, so measuring against navy understates the margin. */
  background-color: var(--brand-primary);
  /* Was a flat 6rem top and bottom, which put 192px of padding around about
     90px of content. Scales with the viewport now instead. */
  padding-block: clamp(2rem, 4.5vw, 3.25rem);
}
.banner::after { content: ""; position: absolute; inset: 0; z-index: 1; background: rgba(0,0,0,.42); }
.banner__inner { position: relative; z-index: 2; }
/* Interior page titles carry the banner on their own — no subtitle beneath —
   so they are set larger than a normal h1. */
.banner h1 {
  color: var(--color-text-invert);
  font-size: clamp(2.5rem, 6.5vw, 4.25rem);
  line-height: 1.05;
  margin: 0;
}
.banner p { color: rgba(255,255,255,.9); margin: var(--space-3) 0 0; max-width: var(--measure); font-family: var(--font-ui); }
/* `.banner p` also matches this element and is more specific, so it was
   winning and flattening the gap to zero. Scoped to beat it. */
.banner .breadcrumb {
  font-family: var(--font-ui); font-size: .85rem;
  color: rgba(255,255,255,.75); margin: 0 0 var(--space-2);
}
.breadcrumb a { color: inherit; }

/* --- Cards & grids ------------------------------------------------------ */
.grid { display: grid; gap: var(--space-5); }
.grid--2 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 420px), 1fr)); }
.grid--3 { grid-template-columns: repeat(auto-fill, minmax(min(100%, 280px), 1fr)); }
.grid--4 { grid-template-columns: repeat(auto-fill, minmax(min(100%, 210px), 1fr)); }

.card {
  background: var(--color-page-bg);
  border: 1px solid var(--color-rule);
  border-radius: var(--radius-lg);
  padding: var(--space-5);
  display: flex; flex-direction: column; gap: var(--space-2);
}
.card h3 { margin: 0; }
.card p { margin: 0; color: var(--color-text-muted); font-size: .95rem; }
.card__foot { margin-top: auto; padding-top: var(--space-3); }
a.card { text-decoration: none; transition: border-color var(--duration) var(--ease), box-shadow var(--duration) var(--ease), transform var(--duration) var(--ease); }
a.card:hover { border-color: var(--brand-accent); box-shadow: var(--shadow-md); transform: translateY(-2px); }


/* Announcement list */
.announce { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-4); }
.announce li {
  display: grid; grid-template-columns: 92px 1fr; gap: var(--space-4);
  padding-bottom: var(--space-4); border-bottom: 1px solid var(--color-rule);
}
.announce time {
  font-family: var(--font-ui); font-size: .8rem; font-weight: 700;
  letter-spacing: .08em; text-transform: uppercase; color: var(--color-text-muted);
  padding-top: .2rem;
}
.announce h3 { font-size: 1.05rem; margin: 0 0 var(--space-1); }
.announce p { margin: 0; font-size: .95rem; color: var(--color-text-muted); }
@media (max-width: 560px) { .announce li { grid-template-columns: 1fr; gap: var(--space-1); } }

/* Definition-style info rows */
.info-list { display: grid; gap: var(--space-4); margin: 0; }
.info-list > div { display: grid; grid-template-columns: 200px 1fr; gap: var(--space-4);
  padding-bottom: var(--space-4); border-bottom: 1px solid var(--color-rule); }
.info-list dt { font-family: var(--font-ui); font-weight: 700; color: var(--color-heading); }
.info-list dd { margin: 0; color: var(--color-text-muted); }
@media (max-width: 640px) { .info-list > div { grid-template-columns: 1fr; gap: var(--space-1); } }

/* --- Find us band ------------------------------------------------------- */
.locate { display: grid; grid-template-columns: 1fr 1fr; align-items: stretch; }
.locate__text { padding: var(--space-8) var(--space-6); background: var(--color-page-alt-bg); display: grid; align-content: center; }
.locate__map { min-height: 320px; }
.locate__map iframe { width: 100%; height: 100%; min-height: 320px; border: 0; display: block; }
@media (max-width: 800px) { .locate { grid-template-columns: 1fr; } }

/* --- Footer ------------------------------------------------------------- */
.site-footer {
  background: var(--color-footer-bg);
  color: var(--color-footer-text);
  padding-block: var(--space-8) var(--space-6);
  font-family: var(--font-ui); font-size: .92rem;
}
.site-footer a { color: var(--color-footer-text); }
.site-footer a:hover { color: var(--color-nav-text-hover); }
.footer__grid { display: grid; gap: var(--space-6); grid-template-columns: 1.2fr 1fr 1fr; align-items: start; }
@media (max-width: 800px) { .footer__grid { grid-template-columns: 1fr; } }
.footer__wordmark {
  font-family: var(--font-display); font-size: 1.6rem; line-height: 1.15;
  color: var(--color-footer-heading); margin: 0 0 var(--space-3);
}
.footer__h {
  font-family: var(--font-ui); font-size: .78rem; font-weight: 700;
  letter-spacing: .12em; text-transform: uppercase;
  color: var(--color-footer-heading); margin: 0 0 var(--space-3);
}
.footer__list { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-2); }
.footer__list a { text-decoration: none; }
.footer__list a:hover { text-decoration: underline; }
.footer__bottom {
  margin-top: var(--space-7); padding-top: var(--space-4);
  border-top: 1px solid rgba(255,255,255,.16);
  display: flex; flex-wrap: wrap; gap: var(--space-3) var(--space-5);
  justify-content: space-between; font-size: .82rem; opacity: .8;
}

/* --- Placeholder flag ---------------------------------------------------
   Wrap any not-yet-final copy in <span class="tbd">…</span> so it is obvious
   in review what still needs real content. Delete the rule (or the class)
   before launch — see README. */
.tbd {
  background: repeating-linear-gradient(45deg, rgba(201,162,39,.16) 0 6px, transparent 6px 12px);
  border-bottom: 1px dashed var(--brand-accent-dark);
}

/* --- Additions used by the renderer ------------------------------------- */

/* Desktop: dropdowns also open on hover. */
@media (min-width: 901px) {
  .nav__item[data-has-menu]:hover .nav__submenu,
  .nav__item[data-has-menu]:focus-within .nav__submenu { display: block; }
}

/* Banner background layer injected into [data-mount="banner"]. */
.banner__bg { position: absolute; inset: 0; z-index: 0; }

/* Anchored sections must clear the sticky header. */
[id] { scroll-margin-top: calc(var(--nav-height) + var(--space-4)); }

/* Roster tables (RHAs / AJs / PAAs). */
.roster { width: 100%; border-collapse: collapse; font-family: var(--font-ui); font-size: .93rem; }
.roster th, .roster td { text-align: left; padding: var(--space-3) var(--space-4); border-bottom: 1px solid var(--color-rule); }
.roster th {
  font-size: .78rem; font-weight: 700; letter-spacing: .1em; text-transform: uppercase;
  color: var(--color-text-muted); background: var(--color-page-alt-bg);
  border-bottom: 2px solid var(--color-rule);
}
.roster tbody tr:hover { background: var(--color-page-alt-bg); }
.section--tint .roster th { background: var(--color-page-bg); }



/* Calendar panel: the placeholder must fill the 16:9 slot itself, not sit
   inside a zero-height wrapper. */
.calendar-ph { aspect-ratio: 16 / 9; border-radius: var(--radius-lg); }

/* The college motto, set the way it reads on the crest: letterspaced caps. */
.motto {
  font-family: var(--font-display);
  font-size: .95rem; font-weight: 600;
  letter-spacing: .22em; text-transform: uppercase;
  margin: 0 0 var(--space-3);
}
.hero .motto { color: var(--brand-accent-light); }
.site-footer .motto { color: var(--color-footer-heading); font-size: .8rem; letter-spacing: .18em; }

/* The crest is drawn in navy on a transparent ground, so it vanishes against
   the navy nav bar. In the header only, it sits on a cream plate — the same
   cream as the shield field, so it reads as the crest on paper. Over the hero
   photo the crest keeps its own transparent ground. */
.site-header .crest {
  height: 34px;
  padding: 4px 6px;
  background: var(--brand-cream);
  border-radius: var(--radius-sm);
}

/* Welcome-section photo sits beside the intro copy. */
.welcome__photo { aspect-ratio: 4 / 3; border-radius: var(--radius-lg); }

/* Google Calendar embed. Google's own markup is a fixed 800x600; this makes it
   fill the column and shrink sensibly on phones, where the month grid is tight. */
.calendar-embed {
  display: block; width: 100%; height: 680px;
  border: 0; border-radius: var(--radius-lg);
  background: var(--color-page-alt-bg);
}
@media (max-width: 700px) { .calendar-embed { height: 560px; } }

/* ============================================================================
   PEOPLE — roster cards, profiles, group headings, tab switcher
   Modeled on the pattern Rice's other college sites use: uniform roster cards
   for groups (so mismatched bio lengths can never gap a grid), and a flowing
   article with a floated portrait for the long leadership bios.
   ========================================================================= */

/* --- Group heading ------------------------------------------------------ */
.group-head {
  text-align: center;
  margin: 0 0 var(--space-6);
  padding-bottom: var(--space-3);
  border-bottom: 1px solid var(--color-rule);
}
.group-head h2, .group-head h3 { margin: 0; }
.group-head p {
  max-width: var(--measure); margin: var(--space-3) auto 0;
  color: var(--color-text-muted); font-size: .95rem;
}
/* Blurb standing on its own: nothing above to be separated from, and it
   carries the section by itself, so it takes the lead size used elsewhere. */
.group-head p:first-child {
  margin-top: 0;
  font-size: 1.075rem;
}

/* --- Roster card -------------------------------------------------------- *
   Every card is the same shape: role, name, fixed-ratio portrait, contact.
   Nothing variable-length lives inside, so rows never go ragged.            */
.rcard {
  height: 100%;
  display: flex; flex-direction: column;
  background: var(--color-page-bg);
  border: 1px solid var(--color-rule);
  border-radius: var(--radius-lg);
  overflow: hidden;
  box-shadow: var(--shadow-sm);
}
.rcard__bar { height: 10px; background: var(--brand-primary); flex: none; }
.rcard__body { padding: var(--space-4); display: flex; flex-direction: column; gap: var(--space-2); flex: 1; }
.rcard__role {
  margin: 0; text-align: center;
  font-family: var(--font-ui); font-size: .68rem; font-weight: 700;
  letter-spacing: .12em; text-transform: uppercase; line-height: 1.3;
  color: var(--color-text-muted);
  height: 2.6em;                     /* exactly two lines, always */
  display: flex; align-items: center; justify-content: center;
}
.rcard__name {
  margin: 0; text-align: center;
  font-family: var(--font-display); font-size: 1.05rem; line-height: 1.25;
  color: var(--color-heading);
  height: 2.5em;                     /* exactly two lines, always */
  display: flex; align-items: center; justify-content: center;
  /* The name and the class year are separate flex items, so the whitespace
     between them is dropped — gap puts it back. */
  flex-wrap: wrap; gap: 0 .32em;
}
/* Always rendered, even when a person has no pronouns listed, so the portrait
   below it starts at the same height on every card in the row. */
.rcard__pronouns {
  margin: 0; text-align: center; min-height: 1.2em;
  font-family: var(--font-ui); font-size: .78rem; line-height: 1.2;
  color: var(--color-text-muted);
}
.rcard__photo { aspect-ratio: 1 / 1; border-radius: var(--radius-md); margin-top: var(--space-2); }
.rcard__contact {
  margin: auto 0 0; padding-top: var(--space-3);
  font-family: var(--font-ui); font-size: .82rem;
  word-break: break-word; text-align: center;
}
.rcard__contact a { text-decoration: none; }
.rcard__contact a:hover { text-decoration: underline; }
.rcard__note { margin: 0; text-align: center; font-family: var(--font-ui); font-size: .75rem; color: var(--color-text-muted); }

/* Initial-letter placeholder, used when a person has no photo. */
.ph__initial {
  position: absolute; inset: 0; z-index: 1;
  display: grid; place-items: center;
  font-family: var(--font-display); font-size: 2.6rem; font-weight: 700;
  color: rgba(255,255,255,.72);
}

/* --- Profile (long bios) ------------------------------------------------ *
   The portrait floats and the text wraps around it, so a 400-word bio and a
   60-word bio both read correctly and neither leaves a hole.                */
.profile { max-width: var(--measure); margin-inline: auto; }
.profile + .profile { margin-top: var(--space-8); padding-top: var(--space-8); border-top: 1px solid var(--color-rule); }
.profile__head { text-align: center; margin-bottom: var(--space-5); }
.profile__role {
  font-family: var(--font-ui); font-size: .72rem; font-weight: 700;
  letter-spacing: .14em; text-transform: uppercase;
  color: var(--color-text-muted); margin: 0 0 var(--space-2);
}
.profile__name { font-family: var(--font-display); font-size: 1.6rem; color: var(--color-heading); margin: 0; }
.profile__contact { font-family: var(--font-ui); font-size: .88rem; margin: var(--space-2) 0 0; }
.profile__contact a { text-decoration: none; }
.profile__contact a:hover { text-decoration: underline; }
.profile__photo {
  float: left; width: 240px; aspect-ratio: 1 / 1;
  margin: 0 var(--space-5) var(--space-4) 0;
  border-radius: var(--radius-lg);
  shape-margin: var(--space-4);
}
.profile__body::after { content: ""; display: block; clear: both; }
.profile__body p { text-align: justify; hyphens: auto; }
@media (max-width: 640px) {
  .profile__photo { float: none; width: 100%; max-width: 280px; margin: 0 auto var(--space-5); }
  .profile__body p { text-align: left; hyphens: manual; }
}

/* --- Pill tab switcher -------------------------------------------------- */
.pills {
  display: flex; flex-wrap: wrap; gap: var(--space-2);
  justify-content: center; margin: 0 0 var(--space-7); padding: 0; list-style: none;
}
.pill {
  font-family: var(--font-ui); font-size: .88rem; font-weight: 600;
  padding: var(--space-2) var(--space-5);
  border: 1px solid var(--color-rule); border-radius: var(--radius-pill);
  background: var(--color-page-bg); color: var(--color-link);
  cursor: pointer;
  transition: background var(--duration) var(--ease), color var(--duration) var(--ease),
              border-color var(--duration) var(--ease);
}
.pill:hover { border-color: var(--brand-accent); }
.pill[aria-selected="true"] {
  background: var(--brand-primary); color: var(--color-text-invert); border-color: transparent;
}
.tabpanel[hidden] { display: none; }

/* --- Duties list (position descriptions, kept out of the cards) --------- */
.duties { margin-top: var(--space-8); }
.duties h3 { text-align: center; }

/* Crest sitting on its own line above the wordmark. */
.hero__crest { display: flex; justify-content: center; margin-bottom: var(--space-4); }
.hero__crest .crest--lg { height: clamp(88px, 11vw, 140px); }

/* Pronouns beside a profile name — plain, not the uppercase role treatment. */
.profile__pronouns {
  font-family: var(--font-ui); font-size: .78rem; font-weight: 400;
  letter-spacing: 0; text-transform: none;
  color: var(--color-text-muted);
}

/* Class year beside a name on a roster card. */
.rcard__year { font-size: .85em; color: var(--color-text-muted); font-family: var(--font-ui); }

/* Committee jurisdiction label. */
.juris {
  font-family: var(--font-ui); font-size: .72rem; font-weight: 700;
  letter-spacing: .1em; text-transform: uppercase;
  color: var(--brand-accent-dark); margin: var(--space-2) 0 0;
}

/* Responsibilities, folded away so the committees page stays scannable. */
.resp { margin-top: var(--space-5); border-top: 1px solid var(--color-rule); padding-top: var(--space-3); }
.resp > summary {
  cursor: pointer; font-family: var(--font-ui); font-size: .88rem; font-weight: 600;
  color: var(--color-link); padding: var(--space-2) 0; list-style-position: outside;
}
.resp > summary:hover { color: var(--color-link-hover); }
.resp ul { margin: var(--space-2) 0 var(--space-3); padding-left: var(--space-5); }
.resp li { font-size: .92rem; color: var(--color-text-muted); margin-bottom: var(--space-1); }
.resp li strong { color: var(--color-heading); }
.resp ul ul { margin-top: var(--space-1); }
.expect { border-top: 0; border-bottom: 1px solid var(--color-rule);
  margin: 0 0 var(--space-6); padding-top: 0; }
.propose { font-family: var(--font-ui); font-size: .92rem; margin: 0 0 var(--space-7); }

/* O-Week coordinators group photo, named in a caption beneath it. */
.oweek-photo { max-width: 620px; margin: 0 auto; }
.oweek-photo__img { aspect-ratio: 4 / 3; border-radius: var(--radius-lg); }
.oweek-photo__caption {
  margin-top: var(--space-3);
  text-align: center;
  font-family: var(--font-ui); font-size: .92rem;
  color: var(--color-text-muted);
}

/* ============================================================================
   GALLERY — O-Week photo grid
   ========================================================================= */
.gallery {
  display: grid; gap: var(--space-4);
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 300px), 1fr));
}
.gallery__item { margin: 0; }
.gallery__item img {
  width: 100%; aspect-ratio: 3 / 2; object-fit: cover;
  border-radius: var(--radius-lg); display: block;
  box-shadow: var(--shadow-sm);
}

/* ============================================================================
   PHOTO STRIP — homepage rotating row
   Three or four cards in view, creeping sideways. The row is a real scroll
   container, so trackpad and touch dragging work without any extra code.
   ========================================================================= */
.strip {
  --strip-gap: var(--space-4);
  --cards: 1.15;                       /* mobile shows a peek of the next */
  position: relative;
  margin-top: var(--space-6);
}
/* WCAG 2.2.2 pause control. Visible at rest rather than on hover: a control
   that only appears on hover is not reachable by touch or keyboard. */
.strip__pause {
  position: absolute; top: calc(-1 * var(--space-6)); right: 0; z-index: 3;
  display: inline-flex; align-items: center; gap: 6px;
  font-family: var(--font-ui); font-size: .78rem; font-weight: 600;
  color: var(--color-text-muted);
  background: var(--color-page-bg);
  border: 1px solid var(--color-rule);
  border-radius: var(--radius-pill);
  padding: 4px 11px 4px 9px;
  cursor: pointer;
}
.strip__pause:hover { color: var(--color-heading); border-color: var(--color-heading); }
.strip__pause-icon {
  width: 9px; height: 10px;
  border-left: 3px solid currentColor; border-right: 3px solid currentColor;
}
/* Pressed: the icon becomes a play triangle. */
.strip--stopped .strip__pause-icon {
  width: 0; height: 0;
  border-left: 8px solid currentColor; border-right: 0;
  border-top: 5px solid transparent; border-bottom: 5px solid transparent;
}

.strip__row {
  display: flex;
  gap: var(--strip-gap);
  overflow-x: auto;
  overflow-y: hidden;
  scroll-behavior: auto;               /* the ticker sets scrollLeft directly */
  overscroll-behavior-x: contain;
  scrollbar-width: none;               /* Firefox */
  -ms-overflow-style: none;
  padding-bottom: 2px;                 /* room for the focus ring */
}
.strip__row::-webkit-scrollbar { display: none; }
.strip__row:focus-visible { outline: 3px solid var(--color-focus); outline-offset: 3px; }

.strip__card {
  flex: 0 0 calc((100% - (var(--cards) - 1) * var(--strip-gap)) / var(--cards));
  margin: 0;
}
.strip__card img {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  display: block;
  border-radius: var(--radius-lg);
  background: var(--color-page-alt-bg);
  box-shadow: var(--shadow-sm);
  -webkit-user-drag: none;
  user-select: none;
}

.strip__nav {
  position: absolute; top: calc(50% - var(--space-3));
  transform: translateY(-50%);
  z-index: 2;
  width: 40px; height: 40px; padding: 0;
  display: grid; place-items: center;
  font-size: 1.5rem; line-height: 1;
  color: var(--color-text-invert);
  background: rgba(0, 0, 0, .45);
  border: 1px solid var(--color-ghost-border);
  border-radius: 50%;
  cursor: pointer;
  transition: background var(--duration) var(--ease), opacity var(--duration) var(--ease);
}
.strip__nav:hover { background: rgba(0, 0, 0, .7); }
.strip__nav--prev { left: calc(-1 * var(--space-3)); }
.strip__nav--next { right: calc(-1 * var(--space-3)); }

@media (min-width: 560px)  { .strip { --cards: 2; } }
@media (min-width: 900px)  { .strip { --cards: 3; } }
@media (min-width: 1280px) { .strip { --cards: 4; } }

/* No room to hang the arrows outside the row on small screens. */
@media (max-width: 720px) {
  .strip__nav { width: 34px; height: 34px; font-size: 1.2rem; }
  .strip__nav--prev { left: var(--space-2); }
  .strip__nav--next { right: var(--space-2); }
}

/* ============================================================================
   TEAM PAGE — leads at full width, the rest packed into balanced columns
   ========================================================================= */
.team__divider { margin-top: var(--space-9); }

/* Two real columns, filled by packColumns() in assets/js/site.js rather than
   by the CSS column balancer, which could not be steered to the even split. */
.team__cols { display: flex; gap: var(--space-7); align-items: flex-start; }
.team__col  { flex: 1 1 0; min-width: 0; }
@media (max-width: 820px) {
  .team__cols { flex-direction: column; }
  /* One full-width column runs to about 100 characters a line. The lead
     profiles are already capped at --measure; match them. */
  .team__col { max-width: var(--measure); margin-inline: auto; width: 100%; }
}

.profile--card {
  max-width: none;
  margin: 0 0 var(--space-7);
  width: 100%;
}
.profile--card:last-child { margin-bottom: 0; }
/* No separator rules inside the packed columns — the column gap does that job,
   and a border would land mid-column. */
.profile--card + .profile--card { margin-top: 0; padding-top: 0; border-top: 0; }

/* A small floated portrait, not a full-width banner. A banner adds the same
   ~330px to every card, which stops height tracking bio length and leaves the
   column balancer nothing to work with. Floated, card height follows the text,
   and the three bios (148 / 288 / 141 words) balance nearly evenly. */
.profile--card .profile__photo {
  float: left;
  /* The column is about 550px, so this still leaves ~345px for the text to
     wrap in — roughly 50 characters, which reads fine. */
  width: 190px;
  aspect-ratio: 1 / 1;
  margin: 0 var(--space-4) var(--space-2) 0;
  shape-margin: var(--space-3);
}
/* The float only works while the column is wide. The two columns go
   side-by-side from 820px, so between there and about 1080px each column is
   only ~400px and a 190px float leaves 26 characters a line. Below 1080px the
   photo sits on top instead and the text gets the full column width.
   (The general .profile__photo rule cannot do this: the selector above is more
   specific and wins inside a media query.) */
@media (max-width: 1080px) {
  .profile--card .profile__photo {
    float: none;
    width: 100%;
    max-width: 260px;
    margin: 0 auto var(--space-5);
  }
  .profile--card .profile__head { text-align: center; }
}
.profile--card .profile__head { text-align: left; }
.profile--card .profile__name { font-size: 1.3rem; }
/* Justified text needs more width than a column gives it. */
.profile--card .profile__body p { text-align: left; hyphens: manual; }

/* O-Week date range, sitting under the eyebrow at the top of the page. */
.oweek-dates {
  font-family: var(--font-display);
  font-size: clamp(1.15rem, 2.2vw, 1.5rem);
  color: var(--color-heading);
  margin: 0 0 var(--space-3);
}

/* ============================================================================
   COMMITTEES — small committees pair up, member cards centre under the heading
   ========================================================================= */

/* Centred rather than a left-aligned auto-fill grid, which left two cards
   hugging the left edge with empty tracks beside them. */
.roster-row {
  display: flex; flex-wrap: wrap;
  justify-content: center;
  gap: var(--space-5);
}
.roster-row .rcard { flex: 0 1 190px; }

/* Each committee sits on its own panel so it reads as one object. The blush
   ground separates it from the white page, and the member cards inside stay
   white and so still sit forward of it.                                     */
.committee {
  background: var(--color-panel-bg);
  border: 1px solid var(--color-rule);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  padding: var(--space-6);
}

.committee-pair {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-5);
  /* Stretched, not start-aligned: two panels of visibly different height
     beside each other look like a mistake in a way bare sections did not. */
  align-items: stretch;
  margin-bottom: var(--space-5);
}
/* An odd one left at the end spans the row instead of sitting half-width with
   nothing beside it. */
.committee-pair > .committee:only-child { grid-column: 1 / -1; }
.committee-full { margin-bottom: var(--space-5); }
@media (max-width: 860px) {
  .committee-pair { grid-template-columns: 1fr; gap: var(--space-5); }
}
@media (max-width: 480px) {
  .committee { padding: var(--space-5) var(--space-4); }
}
