/* ══════════════════════════════════════════════════════════════
   MVSD Core — Shared Front-Page Panels
   ══════════════════════════════════════════════════════════════
   Single source of truth for hero, news, supt/principal, and
   mission panel structural + font styling. Loaded on every site
   (district + 11 schools) via mvsd_core/global library.

   Color comes from per-theme CSS custom properties:
     --color-primary, --color-accent, --color-text-muted

   Tweak any element here and it ships to all 12 sites at once.
   ══════════════════════════════════════════════════════════════ */


/* ── Panel: Hero ─────────────────────────────────────────────── */
/* ============================================================
   Front hero — BILLBOARD BAND (feedback #30, 2026-08-05)
   Always-visible headline + blurb + gold CTA over the hero
   video/poster, with a brand-tinted directional scrim and the
   green->gold slash. Renders per-site via --color-primary /
   --color-accent. Replaces the collapse-on-hover .hero-card.
   ============================================================ */
/* ============================================================
   Front hero — BILLBOARD BAND (feedback #30, 2026-08-05)
   Always-visible headline + blurb + gold CTA over the hero
   video/poster, with a brand-tinted directional scrim and the
   green->gold slash. Renders per-site via --color-primary /
   --color-accent. Replaces the collapse-on-hover .hero-card.
   ============================================================ */
/* ============================================================
   Front hero — FEATURED-ARTICLE treatment (feedback #30, option 3)
   2026-08-06: switched from the billboard to option 3 per stakeholder
   consensus. Video is the primary visual; a light bottom-up scrim only
   shades the text band for legibility (does NOT hide the footage). No
   slash. Content anchored bottom-left; "Read more" is an underlined
   link, not a boxed button. Renders per-site via --color-* tokens.
   ============================================================ */
/* ============================================================
   Front hero — FEATURED-ARTICLE treatment (feedback #30, option 3)
   2026-08-06: switched from the billboard to option 3 per stakeholder
   consensus. Video is the primary visual; a light bottom-up scrim only
   shades the text band for legibility (does NOT hide the footage). No
   slash. Content anchored bottom-left; "Read more" is an underlined
   link, not a boxed button. Renders per-site via --color-* tokens.
   ============================================================ */
.hero-zone {
  position: relative;
  height: 62vh;
  min-height: 420px;
  max-height: 560px;
  overflow: hidden;
  background: var(--color-primary);
}

.hero-poster,
.hero-video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  z-index: 0;
}

/* Scrim isolated to the text: a soft radial pool anchored at the bottom-left
   (where the content sits), feathering up and to the right so it fades out
   past the text with no hard edge. The rest of the video stays clear. */
.hero-overlay {
  position: absolute;
  inset: 0;
  z-index: 1;
  background: radial-gradient(78% 118% at 15% 102%,
    rgba(0,0,0,0.86) 0%,
    rgba(0,0,0,0.64) 26%,
    rgba(0,0,0,0.34) 45%,
    rgba(0,0,0,0.12) 61%,
    rgba(0,0,0,0) 76%);
}

.hero-content {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: flex;
  align-items: flex-end;                 /* anchor content to the bottom */
  padding: clamp(1.5rem, 4.5vw, 3.5rem);
  color: #fff;
}

.hero-card {
  position: relative;
  max-width: 760px;
  color: #fff;
}

/* Meta row — badge + date on one line above the title. */
.hero-badge {
  display: inline-block;
  vertical-align: middle;
  font-size: 0.62rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: var(--ls-display);
  color: var(--color-primary, #01491f);
  background: var(--color-accent, #f5a623);
  padding: 0.2rem 0.55rem;
  border-radius: 3px;
  line-height: 1;
  margin: 0 0.55rem 0.55rem 0;
}

.hero-eyebrow {
  display: inline-block;
  vertical-align: middle;
  font-size: clamp(0.7rem, 1.1vw, 0.8rem);
  margin: 0 0 0.55rem;
  text-transform: uppercase;
  letter-spacing: var(--ls-tracked);
  font-weight: 800;
  color: #fff;
  text-shadow: 0 1px 10px rgba(0,0,0,.6);
}

.hero-title {
  color: #fff;
  font-size: clamp(1.9rem, 4.2vw, 3rem);
  font-weight: 800;
  line-height: 1.07;
  letter-spacing: -0.01em;
  margin: 0 0 0.7rem;
  text-wrap: balance;
  text-shadow: 0 2px 22px rgba(0,0,0,.65), 0 1px 3px rgba(0,0,0,.5);
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 4;
  line-clamp: 4;
  overflow: hidden;
}

.hero-subtitle {
  font-size: clamp(0.95rem, 1.4vw, 1.1rem);
  margin: 0 0 1rem;
  line-height: 1.5;
  color: rgba(255, 255, 255, 0.96);
  max-width: 60ch;
  text-shadow: 0 1px 12px rgba(0,0,0,.7), 0 1px 2px rgba(0,0,0,.5);
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
  line-clamp: 3;
  overflow: hidden;
}

/* CTA — underlined "Read more" link (not a boxed button). Dual indicator:
   weight + gold underline; hover deepens both. */
.hero-cta {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  text-decoration: none;
  color: #fff;
  font-weight: 800;
  font-size: 0.95rem;
  letter-spacing: var(--ls-relaxed);
  text-transform: uppercase;
  padding-bottom: 3px;
  border-bottom: 2px solid var(--color-accent, #f5a623);
  text-shadow: 0 1px 10px rgba(0,0,0,.6);
  transition: border-color 150ms ease, gap 150ms ease;
}
.hero-card .hero-cta:hover,
.hero-card .hero-cta:focus-visible {
  color: #fff;
  border-bottom-color: #fff;
  gap: 0.6rem;
}
.hero-cta-text { display: inline-block; }
.hero-cta-arrow { font-size: 1.05rem; font-weight: 900; line-height: 1; flex-shrink: 0; color: var(--color-accent, #f5a623); }
.hero-card .hero-cta:hover .hero-cta-arrow,
.hero-card .hero-cta:focus-visible .hero-cta-arrow { color: #fff; }

/* Mobile: same bottom treatment, a touch more shade for small-screen legibility. */
@media (max-width: 600px) {
  .hero-zone { height: 56vh; min-height: 360px; max-height: 72vh; }
  .hero-content { padding: 1.4rem 1.25rem 1.6rem; }
  .hero-overlay { background: linear-gradient(to top, rgba(0,0,0,0.85) 0%, rgba(0,0,0,0.55) 34%, rgba(0,0,0,0.12) 62%, rgba(0,0,0,0) 82%); }
  .hero-card { max-width: 100%; }
  .hero-title { font-size: clamp(1.5rem, 7vw, 2.1rem); -webkit-line-clamp: 4; line-clamp: 4; }
  .hero-subtitle { -webkit-line-clamp: 3; line-clamp: 3; }
}

.hero-controls {
  position: absolute;
  bottom: 1rem;
  right: 1rem;
  z-index: 3;
}

.hero-pause-btn {
  background: rgba(0,0,0,0.6);
  color: #fff;
  border: 2px solid rgba(255,255,255,0.8);
  border-radius: 4px;
  padding: 0.5rem 0.75rem;
  cursor: pointer;
  font-size: 0.875rem;
  font-weight: 500;
  transition: background 0.15s;
}

.hero-pause-btn:hover {
  background: rgba(0,0,0,0.8);
}

.hero-pause-btn:focus-visible {
  /* sits on dark hero overlay — use bright gold for >= 3:1 */
  outline: 3px solid var(--color-focus-ring-on-dark);
  outline-offset: 2px;
}


/* ══════════════════════════════════════════════════════════════
   Panel: News Two-Column (magazine layout)
   3fr / 2fr grid. The selector for schools uses :has() to only
   apply when the region actually contains 2+ blocks — otherwise
   the district's single-block region would be wrongly gridded
   (block lands in column 1, column 2 empty, content shifts left).
   District: grid is on the inner .news-two-col div (one block).
   Schools : grid is on the region wrapper that holds 2 blocks.
   ══════════════════════════════════════════════════════════════ */
.news-two-col,
.news-zone > .zone-inner > div:has(> .views-element-container + .views-element-container) {
  display: grid;
  grid-template-columns: 3fr 2fr;
  gap: 1.5rem 4rem;
  align-items: start;
}

@media (max-width: 768px) {
  .news-two-col,
  .news-zone > .zone-inner > div:has(> .views-element-container + .views-element-container) {
    grid-template-columns: 1fr;
    gap: 2.5rem;
  }
}

/* ── Primary column heading (left column, this-site content) ──
   Editorial accent border. District inline uses .news-column-heading;
   schools' first Views block emits a bare <h2> inside its container. */
.news-column-heading,
.news-zone > .zone-inner > div > :first-child > h2 {
  border-bottom: 3px solid var(--color-accent);
  padding-bottom: 0.5rem;
  margin: 0 0 1.75rem;
  font-size: 1.35rem;
  font-weight: 700;
  color: var(--color-text, #1a1a1a);
  letter-spacing: var(--ls-tight);
}

/* ══════════════════════════════════════════════════════════════
   Secondary Sidebar Panel (right column)
   Contained, tinted, accent-edged module — distinct from the
   editorial primary column. Used on:
     - District: <div class="news-secondary-panel"> right of .news-two-col
     - Schools : 2nd .views-element-container inside .news-zone region
   ══════════════════════════════════════════════════════════════ */
.news-secondary-panel,
.news-zone > .zone-inner > div > .views-element-container:nth-child(2) {
  background: #fffbf0;
  border-left: 3px solid var(--color-accent);
  border-radius: 0 8px 8px 0;
  padding: 1.75rem 1.5rem 1.25rem;
}

/* Eyebrow-style heading on the secondary panel — small, uppercase,
   accent-tinted. Replaces the heavy border-bottom h2. */
.news-secondary-panel > h2,
.news-secondary-panel .news-column-heading,
.news-zone > .zone-inner > div > .views-element-container:nth-child(2) > h2 {
  margin: 0 0 1rem;
  padding: 0;
  border: none;
  font-size: 0.75rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: var(--ls-tracked);
  color: var(--color-primary);
}

/* ── "View all" footer link ─────────────────────────────────── */
.news-view-all {
  margin-top: 1rem;
  padding-top: 0.75rem;
  border-top: 1px solid var(--color-border, #e0e0e0);
  text-align: right;
}

.news-view-all a {
  font-size: 0.82rem;
  font-weight: 600;
  color: var(--color-primary);
  text-decoration: none;
  text-transform: uppercase;
  letter-spacing: var(--ls-relaxed);
  transition: color 150ms ease;
}

.news-view-all a:hover {
  color: var(--color-primary-dark);
}

/* ──────────────────────────────────────────────────────────────
   Card: PRIMARY — left column, this-site content.
   Bigger image-top card with date + title + summary.
   ────────────────────────────────────────────────────────────── */
.news-card--primary {
  display: block;
  background: transparent;
  border: none;
  border-radius: 0;
  padding-bottom: 1.75rem;
  margin-bottom: 0;
  overflow: visible;
}

/* ──────────────────────────────────────────────────────────────
   Featured-by-flag modifier — pinned + slightly elevated card for
   site_article / mvsd_article entries with field_is_featured = 1
   (when the article isn't currently in the hero on this page).
   Lives alongside .news-card--primary; combined: they look like a
   contained tile with subtle accent treatment + ★ Featured chip.
   ────────────────────────────────────────────────────────────── */
.news-card--featured {
  position: relative;
  background: color-mix(in srgb, var(--color-primary, #01491f) 3%, #fff);
  border: 1px solid color-mix(in srgb, var(--color-primary, #01491f) 18%, transparent);
  border-radius: 8px;
  padding: 1.1rem 1.1rem 1.25rem;
  box-shadow: 0 3px 14px rgba(0, 0, 0, 0.08);
  margin-bottom: 1rem;
}

/* Override the .views-row divider rule — featured tile is its own
   container so it shouldn't get a top border + extra padding-top. */
.views-row > .news-card--primary.news-card--featured,
.views-row + .views-row > .news-card--primary.news-card--featured {
  padding-top: 1.1rem;
  border-top: none;
}

/* ★ Featured badge — corner overlay matching the existing
   section-primary treatment. Shows on every .news-card--featured. */
.news-card--featured::before {
  content: '★ Featured';
  position: absolute;
  top: 1.4rem;
  left: 1.4rem;
  z-index: 3;
  font-size: 0.62rem;
  font-weight: 800;
  letter-spacing: var(--ls-display);
  text-transform: uppercase;
  color: var(--color-primary, #01491f);
  background: var(--color-accent, #f5a623);
  padding: 0.25rem 0.6rem 0.3rem;
  border-radius: 999px;
  line-height: 1;
  box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
}

/* Slight title boost when featured — same hierarchy as section-primary. */
.news-card--featured.news-card--primary .news-card-title {
  font-size: 1.2rem;
  line-height: 1.25;
}
.news-card--featured.news-card--primary .news-card-cover {
  margin-bottom: 0.85rem;
}

/* Teaser variant — just the ★ flag, nothing else. Per feedback #2 the tile
   box (tint + border + shadow) from .news-card--featured is fully reset back to
   the plain teaser look, so the featured item reads as a normal feed card
   marked only by the star. */
.news-card--teaser.news-card--featured {
  position: relative;
  background: transparent;
  border: none;
  border-radius: 0;
  box-shadow: none;
  padding: 0.85rem 0;
  margin: 0;
}
.news-card--teaser.news-card--featured::before {
  content: '★';
  position: absolute;
  top: 0.3rem;
  left: 0.3rem;
  z-index: 2;
  width: 1.1rem;
  height: 1.1rem;
  font-size: 0.7rem;
  padding: 0;
  border-radius: 999px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25);
  color: var(--color-primary, #01491f);
  background: var(--color-accent, #f5a623);
  letter-spacing: var(--ls-normal);
}

/* Divider between cards — targets the views-row wrapper so it works
   regardless of :last-child context inside the view output. */
.views-row + .views-row > .news-card--primary {
  padding-top: 1.75rem;
  border-top: 1px solid var(--color-border, #e0e0e0);
}

.news-card--primary:last-child,
.views-row:last-child .news-card--primary {
  padding-bottom: 0;
}

.news-card--primary .news-card-cover {
  width: 100%;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  border-radius: 6px;
  margin-bottom: 1rem;
  background: var(--color-bg-subtle, #f5f5f5);
}

.news-card--primary .news-card-cover img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.news-card--primary .news-card-cover--placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
}

/* ── Hover overlay drawer ─────────────────────────────────── */
/* Wraps the image + overlay so the overlay can position over the image. */
.news-card-cover-wrap {
  position: relative;
  overflow: hidden;
  border-radius: 6px;
  margin-bottom: 1rem;
}

/* When using the wrap, the cover itself doesn't need its own margin/radius */
.news-card-cover-wrap .news-card-cover {
  margin-bottom: 0;
  border-radius: 0;
}

/* The overlay — gradient wash slides in from right. The title and body
   box animate independently: body from the right, title from the left,
   both shooting in like drawers for a dynamic layered effect. */
.news-card-overlay {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  background: linear-gradient(
    105deg,
    rgba(0,0,0,0) 0%,
    rgba(0,0,0,0.65) 25%,
    rgba(0,0,0,0.8) 60%
  );
  color: #fff;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  padding: 0;
  opacity: 0;
  transform: translateX(40%);
  transition:
    transform 300ms cubic-bezier(0.16, 1, 0.3, 1),
    opacity 200ms ease;
  pointer-events: none;
}

/* Trigger on card hover or keyboard focus within */
.news-card--primary:hover .news-card-overlay,
.news-card--primary:focus-within .news-card-overlay {
  opacity: 1;
  transform: translateX(0);
  pointer-events: auto;
}

/* ── Overlay title — shoots in from the RIGHT, sits near top ── */
.news-card-overlay__title {
  margin-top: 0.6rem;
  margin-left: auto;
  margin-right: 0;
  margin-bottom: 0;
  width: 65%;
  padding: 0.6rem 1rem 0.5rem 0.85rem;
  font-size: 1.05rem;
  font-weight: 800;
  line-height: 1.25;
  color: var(--color-accent, #f5a623);
  text-shadow: 0 1px 6px rgba(0,0,0,0.6);
  border-left: 4px solid var(--color-accent, #f5a623);
  transform: translateX(110%);
  transition: transform 320ms cubic-bezier(0.16, 1, 0.3, 1) 80ms;
}

.news-card--primary:hover .news-card-overlay__title,
.news-card--primary:focus-within .news-card-overlay__title {
  transform: translateX(0);
}

/* ── Content box — shoots in from the RIGHT, centered vertically ── */
.news-card-overlay__body {
  margin: auto 0 auto auto;
  width: 65%;
  background: var(--color-primary, #01491f);
  padding: 0.7rem 1rem;
  border-radius: 4px 0 0 4px;
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  transform: translateX(110%);
  transition: transform 320ms cubic-bezier(0.16, 1, 0.3, 1) 120ms;
}

.news-card--primary:hover .news-card-overlay__body,
.news-card--primary:focus-within .news-card-overlay__body {
  transform: translateX(0);
}

.news-card-overlay__text {
  margin: 0;
  font-size: 0.85rem;
  line-height: 1.55;
  color: rgba(255,255,255,0.92);
}

.news-card-overlay__cta {
  display: inline-block;
  font-size: 0.73rem;
  font-weight: 700;
  color: var(--color-accent, #f5a623);
  letter-spacing: var(--ls-snug);
  text-transform: uppercase;
  text-decoration: none;
}

.news-card-overlay__cta:hover,
.news-card-overlay__cta:focus-visible {
  /* Explicit accent color override — without this the global
     `a:hover { color: var(--color-primary) }` rule from base.css
     fires and the CTA shifts to dark green, matching the body
     background, making the link look invisible. */
  color: var(--color-accent, #f5a623);
  /* Two-indicator a11y rule: idle is gold-on-green and we can't
     shift the color (no AA-passing alternative without matching the
     BG) — so the underline pairs with a font-weight bump instead.
     See `feedback_dual_link_indicators.md` in memory. */
  font-weight: 900;
  text-decoration: underline;
}

/* Respect prefers-reduced-motion */
@media (prefers-reduced-motion: reduce) {
  .news-card-overlay,
  .news-card-overlay__title,
  .news-card-overlay__body {
    transition: none;
  }
}

/* ── Body peek + gold border — non-featured primary cards only ──
   Original 3-stage drawer animation preserved (gradient fades in,
   title shoots in from the right with its accent border, body shoots
   in from the right with a longer delay). Two additions:

   (a) Body box gets a 4px gold left-border to mirror the title's
       accent edge — when the body slides in, the two stack with a
       continuous vertical accent stripe.
   (b) Body box's idle transform leaves a small peek (12px = 4px
       gold border + 8px of green padding) sticking out the right
       edge of the cover, signalling there's something behind the
       image without exposing the body text (body's 1rem left
       padding clips the inner content comfortably).

   To make the peek visible at idle, the parent overlay no longer
   fades opacity 0 → 1; instead its gradient wash moves to a ::before
   pseudo so we can fade only the dark backdrop on hover while keeping
   the body box visible from the start. The parent overlay also drops
   its own slide transform — only its inner title + body slide.

   Featured/hero card retains its original treatment (parent fade,
   no peek, no body border) — its visual prominence comes from size
   plus the ::before accent on the card itself. */
.news-card--primary:not(.news-card--featured) .news-card-overlay {
  opacity: 1;
  transform: none;
  background: none;
  transition: none;
}
.news-card--primary:not(.news-card--featured) .news-card-overlay::before {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(
    105deg,
    rgba(0, 0, 0, 0) 0%,
    rgba(0, 0, 0, 0.65) 25%,
    rgba(0, 0, 0, 0.8) 60%
  );
  opacity: 0;
  pointer-events: none;
  transition: opacity 280ms ease;
  z-index: 0;
}
.news-card--primary:not(.news-card--featured):hover .news-card-overlay::before,
.news-card--primary:not(.news-card--featured):focus-within .news-card-overlay::before {
  opacity: 1;
}

.news-card--primary:not(.news-card--featured) .news-card-overlay__body {
  border-left: 4px solid var(--color-accent, #f5a623);
  /* 18px peek = 4px gold border + 14px of green padding. Body's
     left padding bumped to 1.5rem (24px) so text starts 28px from
     the outer edge — keeps a comfortable 10px buffer behind the peek. */
  padding-left: 1.5rem;
  transform: translateX(calc(100% - 18px));
  /* Sit above the gradient pseudo. */
  position: relative;
  z-index: 1;
}
/* Hover override at matching specificity (the `:not()` adds class-
   selector weight so the bare `.news-card--primary:hover .news-card-
   overlay__body` rule above couldn't win on its own — body would stay
   stuck at the peek without this). */
.news-card--primary:not(.news-card--featured):hover .news-card-overlay__body,
.news-card--primary:not(.news-card--featured):focus-within .news-card-overlay__body {
  transform: translateX(0);
}

/* ── Pop-out chevron indicator — non-featured primary cards only ──
   A small accent-color disc with a chevron sits just to the left of
   the body's left edge. Idle: chevron points LEFT (`<`) — visual
   cue that something will open. Hover/focus: rotates 180° to point
   RIGHT (`>`) — body is now exposed. The icon is positioned on the
   body itself, so it slides with the body during the drawer reveal,
   staying visually attached to its left edge. */
.news-card--primary:not(.news-card--featured) .news-card-overlay__body::before {
  content: "";
  position: absolute;
  left: -41px;
  top: 50%;
  width: 33px;
  height: 33px;
  border-radius: 50%;
  background-color: var(--color-accent, #f5a623);
  /* Chevron stroke is a fixed dark color so it reads on every theme's
     accent (gold / yellow / sage / red). currentColor would inherit
     the body's white — invisible. */
  background-image: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%231a1a1a'%20stroke-width='3'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpolyline%20points='15%2018%209%2012%2015%206'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: center;
  background-size: 18px 18px;
  box-shadow: 0 3px 8px rgba(0, 0, 0, 0.35);
  transform: translateY(-50%);
  transition: transform 320ms cubic-bezier(.2, .8, .2, 1);
  pointer-events: none;
  z-index: 2;
}
.news-card--primary:not(.news-card--featured):hover .news-card-overlay__body::before,
.news-card--primary:not(.news-card--featured):focus-within .news-card-overlay__body::before {
  transform: translateY(-50%) rotate(180deg);
}

@media (prefers-reduced-motion: reduce) {
  .news-card--primary:not(.news-card--featured) .news-card-overlay::before,
  .news-card--primary:not(.news-card--featured) .news-card-overlay__body::before {
    transition: none;
  }
}

.news-card--primary .news-card-body {
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}

.news-card--primary .news-card-date {
  font-size: 0.75rem;
  color: var(--color-text-muted, #5a5a5a);
  text-transform: uppercase;
  letter-spacing: var(--ls-loose);
  font-weight: 500;
}

.news-card--primary .news-card-title {
  margin: 0 0 0.6rem;
  font-size: 1.15rem;
  font-weight: 700;
  line-height: 1.3;
  color: var(--color-text, #1a1a1a);
}

/* Mobile-only summary — visible on touch devices where hover overlay is inaccessible */
.news-card-summary--mobile {
  display: none;
  margin: 0.25rem 0 0;
  font-size: 0.85rem;
  color: var(--color-text-muted, #5a5a5a);
  line-height: 1.5;
}

/* Only show on mobile where hover overlay doesn't work */
@media (max-width: 768px) {
  .news-card-summary--mobile {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
  }
}

/* Hide on desktop — the hover overlay handles this */
@media (min-width: 769px) {
  .news-card-summary--mobile {
    display: none;
  }
}

/* .news-card-summary removed — body snippet now renders
   in the hover overlay (.news-card-overlay) instead. */

/* ──────────────────────────────────────────────────────────────
   Newsletter highlights — grid of latest-per-school cards at top
   of /newsletters landing page
   ────────────────────────────────────────────────────────────── */
.newsletter-highlights {
  margin: 2rem 0 3rem;
}
.newsletter-highlights__heading {
  font-size: 1.25rem;
  font-weight: 700;
  color: var(--color-text);
  margin: 0 0 1.25rem;
  padding-bottom: 0.5rem;
  border-bottom: 3px solid var(--color-accent);
  letter-spacing: var(--ls-tight);
}
.newsletter-highlights__grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: 1rem;
}
.newsletter-highlight-card {
  background: #fff;
  border: 1px solid rgba(0,0,0,0.06);
  border-radius: 10px;
  padding: 1.1rem 1.25rem 1rem;
  display: flex;
  flex-direction: column;
  gap: 0.45rem;
  box-shadow: 0 1px 3px rgba(0,0,0,0.03);
  transition: transform 0.2s ease, box-shadow 0.2s ease, border-color 0.2s ease;
}
.newsletter-highlight-card:hover {
  transform: translateY(-2px);
  box-shadow: 0 8px 20px rgba(0,0,0,0.08);
  border-color: rgba(0,0,0,0.12);
}
.newsletter-highlight-card__meta {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 0.5rem;
}
.newsletter-highlight-card__school {
  font-size: 0.7rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: var(--ls-loose);
  color: var(--color-primary);
}
.newsletter-highlight-card__date {
  font-size: 0.75rem;
  color: var(--color-text-muted, #5a5a5a);
}
.newsletter-highlight-card__title {
  margin: 0;
  font-size: 1rem;
  font-weight: 600;
  line-height: 1.35;
  color: var(--color-text);
}
.newsletter-highlight-card__title a {
  color: inherit;
  text-decoration: none;
}
.newsletter-highlight-card__actions {
  display: flex;
  gap: 0.5rem;
  margin-top: auto;
  padding-top: 0.5rem;
}
.newsletter-highlight-card__read,
.newsletter-highlight-card__pdf {
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: var(--ls-relaxed);
  text-transform: uppercase;
  padding: 0.35rem 0.7rem;
  border-radius: 4px;
  text-decoration: none;
}
.newsletter-highlight-card__read {
  background: var(--color-primary);
  color: #fff;
}
.newsletter-highlight-card__read:hover {
  filter: brightness(1.1);
}
.newsletter-highlight-card__pdf {
  background: var(--color-bg-subtle, #f5f5f7);
  color: var(--color-primary);
  border: 1px solid rgba(0,0,0,0.06);
}
.newsletter-highlight-card__pdf:hover {
  background: var(--color-primary);
  color: #fff;
  border-color: var(--color-primary);
}

/* ──────────────────────────────────────────────────────────────
   Newsletter aggregator — compact list rows (district /newsletters)
   ────────────────────────────────────────────────────────────── */
.newsletter-row {
  display: grid;
  grid-template-columns: 110px 180px 1fr auto;
  gap: 1rem;
  align-items: center;
  padding: 0.875rem 1rem;
  border-bottom: 1px solid rgba(0,0,0,0.08);
  background: transparent;
  transition: background 0.15s;
}

.newsletter-row:first-child {
  padding-top: 0;
}
.newsletter-row:last-child {
  border-bottom: none;
}
.newsletter-row:hover {
  background: color-mix(in srgb, var(--color-primary) 4%, transparent);
}

.newsletter-row__date {
  font-size: 0.8rem;
  color: var(--color-text-muted, #5a5a5a);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: var(--ls-relaxed);
  white-space: nowrap;
}

.newsletter-row__source {
  font-size: 0.85rem;
  color: var(--color-primary);
  font-weight: 600;
}

.newsletter-row__title {
  margin: 0;
  font-size: 0.95rem;
  font-weight: 600;
  line-height: 1.35;
  min-width: 0;
}
.newsletter-row__title a {
  color: var(--color-text);
  text-decoration: none;
}
.newsletter-row__title a:hover {
  color: var(--color-primary);
  text-decoration: underline;
}

.newsletter-row__actions {
  display: flex;
  gap: 0.5rem;
  flex-wrap: wrap;
  white-space: nowrap;
}
.newsletter-row__action {
  display: inline-block;
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: var(--ls-relaxed);
  text-transform: uppercase;
  padding: 0.35rem 0.7rem;
  border-radius: 4px;
  background: var(--color-bg-subtle, #f5f5f7);
  color: var(--color-primary);
  text-decoration: none;
  border: 1px solid rgba(0,0,0,0.06);
}
.newsletter-row__action:hover {
  background: var(--color-primary);
  color: #fff;
  border-color: var(--color-primary);
}

@media (max-width: 700px) {
  .newsletter-row {
    grid-template-columns: 1fr auto;
    gap: 0.5rem;
  }
  .newsletter-row__date,
  .newsletter-row__source {
    grid-column: 1 / -1;
  }
  .newsletter-row__title {
    grid-column: 1;
  }
  .newsletter-row__actions {
    grid-column: 2;
  }
}

/* ──────────────────────────────────────────────────────────────
   Section-primary pinned article (parent/student resource pages)
   ──────────────────────────────────────────────────────────────
   Targets: any view-block container whose id ends in
   -parent-section-primary or -student-section-primary. Renders
   the primary card as a raised "Featured" tile with accent tag. */
[id$="-parent-section-primary"] .news-card--primary,
[id$="-student-section-primary"] .news-card--primary {
  background: linear-gradient(135deg,
    color-mix(in srgb, var(--color-primary) 4%, #fff),
    #fff);
  border: 1px solid color-mix(in srgb, var(--color-primary) 12%, transparent);
  border-radius: 12px;
  padding: 1.75rem;
  margin-bottom: 2rem;
  box-shadow: 0 4px 16px rgba(0,0,0,0.06);
}

[id$="-parent-section-primary"] .news-card--primary::before,
[id$="-student-section-primary"] .news-card--primary::before {
  content: '★ Featured';
  display: inline-block;
  font-size: 0.65rem;
  font-weight: 700;
  letter-spacing: var(--ls-tracked);
  text-transform: uppercase;
  color: #1a1a1a;
  background: var(--color-accent);
  padding: 0.3rem 0.75rem;
  border-radius: 999px;
  margin-bottom: 1rem;
}

[id$="-parent-section-primary"] .news-card--primary .news-card-title,
[id$="-student-section-primary"] .news-card--primary .news-card-title {
  font-size: 1.5rem;
  line-height: 1.2;
  margin-top: 0.5rem;
}

[id$="-parent-section-primary"] .news-card--primary .news-card-summary,
[id$="-student-section-primary"] .news-card--primary .news-card-summary {
  font-size: 1rem;
  margin-top: 0.5rem;
}

/* ──────────────────────────────────────────────────────────────
   Card: TEASER — right column, cross-site content.
   Compact horizontal: small thumb + date + title.
   No summary (it's a teaser; click through for more).
   ────────────────────────────────────────────────────────────── */
.news-card--teaser {
  display: grid;
  grid-template-columns: 60px 1fr;
  gap: 0.75rem;
  align-items: start;
  background: transparent;
  border: none;
  border-radius: 0;
  padding: 0.85rem 0;
  margin: 0;
}

/* Dividers between teaser cards — target views-row wrappers */
.views-row + .views-row > .news-card--teaser {
  border-top: 1px solid var(--color-border, #e0e0e0);
  padding-top: 0.85rem;
}

.views-row:first-child > .news-card--teaser {
  padding-top: 0;
}

.views-row:last-child > .news-card--teaser {
  padding-bottom: 0;
}

.news-card--teaser .news-card-thumb {
  width: 60px;
  height: 60px;
  overflow: hidden;
  border-radius: 6px;
  background: rgba(0,0,0,0.05);
}

.news-card--teaser .news-card-thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.news-card--teaser .news-card-thumb--placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
}

.news-card--teaser .news-card-body {
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
  min-width: 0;
}

.news-card--teaser .news-card-date {
  font-size: 0.7rem;
  color: var(--color-text-muted, #5a5a5a);
  text-transform: uppercase;
  letter-spacing: var(--ls-loose);
  font-weight: 500;
}

.news-card--teaser .news-card-title {
  margin: 0;
  font-size: 0.9rem;
  font-weight: 600;
  line-height: 1.35;
  color: var(--color-text, #1a1a1a);
}

/* Link treatment — unified across all news-card variants (primary,
   teaser, featured) so the three card types feel related. Same gradient-
   grow technique as .mvsd-link-anim, but bumped to 3px thickness as the
   "feature" signature — distinguishes a news card title from regular
   body links without becoming a different system. Trigger on hover OR
   when the parent card has focus-within (keyboard pathway). */
.news-card--primary .news-card-title a,
.news-card--teaser .news-card-title a,
.news-card--featured .news-card-title a {
  color: inherit;
  text-decoration: none;
  background-image: linear-gradient(var(--link-underline-color), var(--link-underline-color));
  background-size: 0 var(--link-underline-thickness);
  background-position: 0 100%;
  background-repeat: no-repeat;
  padding-bottom: 2px;
  transition:
    background-size var(--link-anim-duration) var(--link-anim-ease),
    color 200ms ease;
}

.news-card--primary .news-card-title a:hover,
.news-card--primary:focus-within .news-card-title a,
.news-card--teaser .news-card-title a:hover,
.news-card--teaser:focus-within .news-card-title a,
.news-card--featured .news-card-title a:hover,
.news-card--featured:focus-within .news-card-title a {
  background-size: 100% var(--link-underline-thickness);
  color: var(--color-primary);
}

@media (prefers-reduced-motion: reduce) {
  .news-card--primary .news-card-title a,
  .news-card--teaser .news-card-title a,
  .news-card--featured .news-card-title a {
    transition: none;
  }
}

.news-card-placeholder-icon {
  font-size: 1.5rem;
  opacity: 0.3;
}


/* ══════════════════════════════════════════════════════════════
   Panel: Split (Superintendent / Principal zone)
   ══════════════════════════════════════════════════════════════ */
.kudos-grid,
.split-panel {
  display: grid;
  grid-template-columns: 200px 1fr;
  gap: 2rem;
  align-items: center;
}

@media (max-width: 600px) {
  .kudos-grid,
  .split-panel {
    grid-template-columns: 1fr;
    text-align: center;
  }
}

.kudos-grid > img,
.split-panel__media {
  width: 100%;
  aspect-ratio: 1;
  object-fit: cover;
  border-radius: 8px;
  box-shadow: 0 4px 16px rgba(0,0,0,0.12);
  display: block;
}

.kudos-grid p:first-of-type,
.split-panel__eyebrow {
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: var(--ls-loose);
  color: var(--color-primary);
  font-weight: 700;
  margin: 0 0 0.5rem;
}

.kudos-grid h2,
.split-panel__title {
  margin: 0 0 1rem;
  font-size: clamp(1.5rem, 2.5vw, 2rem);
  font-weight: 700;
  line-height: 1.2;
}

.split-panel__title a {
  color: inherit;
  text-decoration: none;
}
.split-panel__title a:hover {
  color: var(--color-primary);
  text-decoration: underline;
}

.kudos-grid p:not(:first-of-type),
.split-panel__text {
  line-height: 1.7;
  color: var(--color-text, #3a3a3a);
  margin: 0 0 1.25rem;
  font-size: 1rem;
}

.kudos-grid > div > a,
.split-panel__cta,
.btn-cta {
  display: inline-block;
  background: var(--color-accent);
  color: #1a1a1a;
  padding: 0.75rem 1.5rem;
  border-radius: 4px;
  text-decoration: none;
  font-weight: 700;
  border: 0;
  cursor: pointer;
}

.kudos-grid > div > a:hover,
.split-panel__cta:hover,
.btn-cta:hover {
  filter: brightness(0.92);
}

/* Superintendent's Spotlight — PHOTO + VIDEO modes ("has-media"): two columns
   like the Kudos panel — media on the LEFT (360px, ~50% larger than the 200px
   rotating photo), title + details on the RIGHT. Collapses to a
   title → media → content stack on phones. Message / article / promo modes keep
   the single-column layout above. The template emits
   eyebrow → title → media → body → cta in DOM order, which IS the mobile stack;
   grid-areas only reposition the media on wide screens. */
.sup-spotlight--has-media {
  display: grid;
  grid-template-columns: 360px 1fr;
  column-gap: 2rem;
  align-items: start;
  /* Eyebrow sits in its own row above; the media starts at the TITLE row so the
     title top and media top line up. The trailing 1fr "slack" row absorbs any
     extra media height (16:9 video @ 360px = 202px; tall photos) so the text
     rows stay tight instead of spreading apart. */
  grid-template-rows: auto auto auto auto 1fr;
  grid-template-areas:
    ".     eyebrow"
    "media title"
    "media body"
    "media cta"
    "media slack";
}
.sup-spotlight--has-media .split-panel__eyebrow { grid-area: eyebrow; margin-bottom: 0.25rem; }
.sup-spotlight--has-media .split-panel__title   { grid-area: title; }
.sup-spotlight--has-media .split-panel__text    { grid-area: body; }
.sup-spotlight--has-media .btn-cta              { grid-area: cta; justify-self: start; align-self: start; }
.sup-spotlight--has-media .sup-spotlight__video,
.sup-spotlight--has-media .sup-spotlight__photo {
  grid-area: media;
  align-self: start;
  width: 100%;
  max-width: none;
  margin: 0;
}

.sup-spotlight__video {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9;
  border-radius: 6px;
  overflow: hidden;
  background: #000;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
}
.sup-spotlight__video iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
}

/* Photo mode: natural aspect ratio, same rounded / shadowed frame as the video. */
.sup-spotlight__photo {
  border-radius: 6px;
  overflow: hidden;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
  line-height: 0;
}
.sup-spotlight__photo img {
  display: block;
  width: 100%;
  height: auto;
}

@media (max-width: 600px) {
  .sup-spotlight--has-media {
    grid-template-columns: 1fr;
    grid-template-rows: auto;
    grid-template-areas:
      "eyebrow"
      "title"
      "media"
      "body"
      "cta";
    text-align: center;
  }
  .sup-spotlight--has-media .split-panel__eyebrow { align-self: auto; }
  .sup-spotlight--has-media .split-panel__title   { margin-bottom: 1rem; }
  .sup-spotlight--has-media .sup-spotlight__video,
  .sup-spotlight--has-media .sup-spotlight__photo { max-width: 480px; margin: 0 auto 1.25rem; }
  .sup-spotlight--has-media .btn-cta              { justify-self: center; }
}

/* Superintendent "Share a Kudos" figure: a single spotlight tile injected by
   mvsd_helpers_preprocess_block(), reshuffled per page load. Override the
   full-bleed .spotlight-strip band (interior pages) so the image reads as the
   same square portrait the split panel expects. */
.kudos-grid > .kudos-figure {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 1;
  margin: 0;
  border-radius: 8px;
  box-shadow: 0 4px 16px rgba(0,0,0,0.12);
  overflow: hidden;
  line-height: 0;
}

.kudos-grid > .kudos-figure > img.spotlight-tile {
  width: 100%;
  height: 100%;
  aspect-ratio: 1;
  object-fit: cover;
  display: block;
}


/* ══════════════════════════════════════════════════════════════
   Panel: Mission (evergreen zone) — full mission + 3 pillars
   ══════════════════════════════════════════════════════════════ */
.mission-panel {
  text-align: center;
  max-width: 960px;
  margin: 0 auto;
}

/* ── Mission statement block ── */
.mission-panel__statement {
  margin-bottom: 2.5rem;
}

.mission-panel__eyebrow {
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: var(--ls-display);
  color: var(--color-primary);
  font-weight: 700;
  margin: 0 0 0.75rem;
}

.mission-panel__mission {
  font-size: clamp(0.95rem, 1.8vw, 1.1rem);
  max-width: 720px;
  margin: 0 auto;
  color: var(--color-text, #333);
  line-height: 1.75;
}

/* ── Vision / Somos heading ── */
.mission-panel__vision {
  margin-bottom: 2.5rem;
  padding: 1.5rem 0;
  border-top: 1px solid var(--color-border, #e0e0e0);
  border-bottom: 1px solid var(--color-border, #e0e0e0);
}

.mission-panel__title {
  font-size: clamp(2rem, 5vw, 3rem);
  color: var(--color-primary);
  margin: 0;
  font-weight: 900;
  line-height: 1.1;
  letter-spacing: var(--ls-tight);
}

.mission-panel__subtitle {
  font-size: clamp(0.85rem, 1.5vw, 1.05rem);
  color: var(--color-text-muted, #5a5a5a);
  margin: 0.5rem 0 0;
  font-style: italic;
  line-height: 1.5;
}

/* ── Three pillars: Belong / Dream / Achieve ── */
.mission-panel__pillars {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1.5rem;
}

.mission-pillar {
  padding: 1.75rem 1.25rem;
  border-radius: 10px;
  background: #fff;
  border: 1px solid var(--color-border, #e0e0e0);
  box-shadow: 0 2px 12px rgba(0,0,0,0.05);
  transition: transform 200ms ease, box-shadow 200ms ease;
  border-top: 4px solid var(--color-primary);
}

.mission-pillar:hover {
  transform: translateY(-3px);
  box-shadow: 0 6px 20px rgba(0,0,0,0.1);
}

.mission-pillar--belong { border-top-color: var(--color-primary); }
.mission-pillar--dream { border-top-color: var(--color-accent); }
.mission-pillar--achieve { border-top-color: var(--color-primary-mid); }

.mission-pillar__heading {
  margin: 0 0 0.6rem;
  font-size: 1.3rem;
  font-weight: 800;
  color: var(--color-primary);
  line-height: 1.2;
}

.mission-pillar--dream .mission-pillar__heading { color: var(--color-accent-deep); }
.mission-pillar--achieve .mission-pillar__heading { color: var(--color-primary-mid); }

.mission-pillar__text {
  margin: 0;
  font-size: 0.92rem;
  color: var(--color-text-muted, #555);
  line-height: 1.6;
}

/* Mobile: pillars stack */
@media (max-width: 640px) {
  .mission-panel__pillars {
    grid-template-columns: 1fr;
    gap: 1rem;
  }
  .mission-pillar {
    padding: 1.25rem 1rem;
  }
}

/* ──────────────────────────────────────────────────────────────
   Error pages (404 / 403)
   ────────────────────────────────────────────────────────────── */
.error-page {
  max-width: 640px;
  margin: 3rem auto 4rem;
  text-align: center;
  padding: 3rem 2rem;
  background: #fff;
  border-radius: 14px;
  border: 1px solid rgba(0, 0, 0, 0.05);
  box-shadow: 0 10px 32px rgba(0, 0, 0, 0.06);
}
.error-page__code {
  font-size: clamp(3.5rem, 10vw, 5.5rem);
  font-weight: 800;
  color: var(--color-primary);
  line-height: 1;
  letter-spacing: var(--ls-tight);
  opacity: 0.85;
  margin-bottom: 0.5rem;
}
.error-page__title {
  font-size: clamp(1.5rem, 3vw, 2rem);
  font-weight: 700;
  color: var(--color-text);
  margin: 0 0 1rem;
  line-height: 1.2;
}
.error-page__message {
  font-size: 1.0625rem;
  color: var(--color-text-muted, #5a5a5a);
  line-height: 1.6;
  margin: 0 0 1.5rem;
}
.error-page__links {
  list-style: none;
  margin: 0 0 1.5rem;
  padding: 0;
  text-align: left;
  display: inline-block;
}
.error-page__links li {
  padding: 0.5rem 0;
  border-bottom: 1px solid rgba(0, 0, 0, 0.06);
}
.error-page__links li:last-child { border-bottom: none; }
.error-page__links a {
  color: var(--color-primary);
  font-weight: 600;
  text-decoration: none;
}
.error-page__links a:hover { text-decoration: underline; }
.error-page__footnote {
  font-size: 0.9rem;
  color: var(--color-text-muted, #5a5a5a);
  margin: 1.5rem 0 0;
}


/* ══════════════════════════════════════════════════════════════
   ParentSquare Feed — sidebar compact list
   ══════════════════════════════════════════════════════════════ */

/* Scope override: links inside the ParentSquare block start at primary
   (the same color the unified .mvsd-link-anim defaults to on hover),
   so without this they'd appear stuck. Flip --link-hover-color to
   accent — same trick as the .site-footer scope override. The accent
   underline grow + accent color shift now both land in brand gold. */
[id$="-parentsquare-feed"] {
  --link-hover-color: var(--color-accent-deep);
}

.ps-feed__item {
  padding: 0.6rem 0;
  border-bottom: 1px solid var(--color-border, #e0e0e0);
}

.ps-feed__item:last-child {
  border-bottom: none;
}

.ps-feed__date {
  font-size: 0.7rem;
  color: var(--color-text-muted, #777);
  text-transform: uppercase;
  letter-spacing: var(--ls-relaxed);
  display: block;
  margin-bottom: 0.15rem;
}

.ps-feed__title {
  font-size: 0.88rem;
  font-weight: 600;
  line-height: 1.35;
  color: var(--color-text, #333);
  display: block;
}

.ps-feed__link {
  display: block;
  margin-top: 0.2rem;
}

.ps-feed__link a {
  font-size: 0.72rem;
  padding: 0.4rem 0;
  display: inline-block;
  font-weight: 600;
  color: var(--color-primary);
  text-transform: uppercase;
  letter-spacing: var(--ls-relaxed);
  /* Hover via .mvsd-link-anim (gradient grow underline). */
}

.ps-feed__footer {
  margin-top: 0.75rem;
  padding-top: 0.5rem;
  border-top: 1px solid var(--color-border, #e0e0e0);
  text-align: right;
}

.ps-feed__footer a {
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--color-primary);
  text-transform: uppercase;
  letter-spacing: var(--ls-relaxed);
  /* Hover via .mvsd-link-anim (matches read-more links above). */
}

.ps-feed__empty {
  font-size: 0.85rem;
  color: var(--color-text-muted, #999);
  font-style: italic;
  text-align: center;
  padding: 1rem 0;
}


/* ── ParentSquare feed panel — similar to school highlights but distinct ── */
.news-zone > .zone-inner > div > .views-element-container:nth-child(3) {
  background: var(--color-primary-light, #e8f5ed);
  border-left: 3px solid var(--color-primary);
  border-radius: 0 8px 8px 0;
  padding: 1.25rem 1.5rem 1rem;
}

.news-zone > .zone-inner > div > .views-element-container:nth-child(3) > h2 {
  margin: 0 0 0.75rem;
  padding: 0;
  border: none;
  font-size: 0.72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: var(--ls-tracked);
  color: var(--color-primary-dark);
}

/* ── Right column panel titles — bold, prominent like Kudos heading ── */
.news-zone > .zone-inner > div > .views-element-container:nth-child(2) > h2,
.news-zone > .zone-inner > div > .views-element-container:nth-child(3) > h2 {
  font-size: clamp(1.1rem, 2vw, 1.4rem) !important;
  font-weight: 700 !important;
  text-transform: none !important;
  letter-spacing: normal !important;
  color: var(--color-primary) !important;
  margin: 0 0 0.75rem !important;
  line-height: 1.2;
}

.news-zone > .zone-inner > div > .views-element-container:nth-child(3) > h2 {
  color: var(--color-primary-dark) !important;
}


/* ══════════════════════════════════════════════════════════════
   NEWS ZONE MULTI-BLOCK LAYOUT
   Works for both district (4 blocks) and schools (4 blocks).
   First block floats left. All others stack in the right column.
   ══════════════════════════════════════════════════════════════ */

/* Switch from grid to block when 3+ blocks exist (detected by PS feed) */
.news-zone > .zone-inner > div:has(> [id$=-parentsquare-feed]),
.news-zone > .zone-inner > div:has(> [id$=-parentsquare-feed]) {
  display: block !important;
  overflow: hidden;
}

/* First block = left column (school news on schools, district feed on district) */
.news-zone > .zone-inner > div:has(> [id$=-parentsquare-feed]) > :first-child,
.news-zone > .zone-inner > div:has(> [id$=-parentsquare-feed]) > :first-child {
  float: left;
  width: 64%;
  margin-right: 4%;
}

/* All other blocks = right column (flow naturally beside the float) */
.news-zone > .zone-inner > div:has(> [id$=-parentsquare-feed]) > :not(:first-child),
.news-zone > .zone-inner > div:has(> [id$=-parentsquare-feed]) > :not(:first-child),
.news-zone > .zone-inner > div:has(> [id$=-parentsquare-feed]) > [id$=-upcoming-events],
.news-zone > .zone-inner > div:has(> [id$=-parentsquare-feed]) > [id$=-upcoming-events] {
  overflow: hidden;
  margin-bottom: 1.5rem;
}

/* Mobile: stack everything */
@media (max-width: 768px) {
  .news-zone > .zone-inner > div:has(> [id$=-parentsquare-feed]) > :first-child,
  .news-zone > .zone-inner > div:has(> [id$=-parentsquare-feed]) > :first-child {
    float: none;
    width: 100%;
    margin-right: 0;
    margin-bottom: 2rem;
  }
}

/* ── MVSD-THIN-FRONT-FIX: hold the right column when the left is short ──
   The right column above is not a real column: each block is a BFC
   (overflow:hidden) that narrows only WHILE the 64% float is still
   beside it. On a school with almost no news the float is short
   (Centennial/Madison left column = 604px vs 2588-2701px elsewhere),
   so by the time the ParentSquare block is laid out the float has
   already ended and the block expands to the full container width
   (measured 1152px at a 1440 viewport, against 369px on every other
   site). Giving the right-column blocks an explicit column offset
   makes the geometry independent of the left column's height.
   68% + 32% reproduces the existing 64% float + 4% gutter exactly,
   so this is a no-op on every site whose left column is tall enough. */
.news-zone > .zone-inner > div:has(> [id$=-parentsquare-feed]) > :not(:first-child) {
  width: 32%;
  margin-left: 68%;
}

@media (max-width: 768px) {
  .news-zone > .zone-inner > div:has(> [id$=-parentsquare-feed]) > :not(:first-child) {
    width: auto;
    margin-left: 0;
  }
}

/* ══════════════════════════════════════════════════════════════
   RIGHT COLUMN PANEL STYLING (universal — works on all sites)
   Three distinct panel colors, matched by ID suffix.
   ══════════════════════════════════════════════════════════════ */

/* Events panel — subtle gray, primary-mid accent */
[id$=-upcoming-events],
[id$=-upcoming-events] {
  background: var(--color-bg-subtle, #f5f5f5) !important;
  border-left: 3px solid var(--color-primary-mid) !important;
  border-radius: 0 8px 8px 0 !important;
  padding: 1.25rem 1.5rem 1rem !important;
}

/* School Spotlight / District News panel — warm cream, accent border */
.news-secondary-panel,
[id$=-school-highlights],
[id$=-school-highlights],
[id$=-district-news],
[id$=-district-news] {
  background: #fffbf0 !important;
  border-left: 3px solid var(--color-accent) !important;
  border-radius: 0 8px 8px 0 !important;
  padding: 1.25rem 1.5rem 1rem !important;
}

/* ParentSquare panel — primary-light tint */
[id$=-parentsquare-feed],
[id$=-parentsquare-feed] {
  background: var(--color-primary-light, #e8f5ed) !important;
  border-left: 3px solid var(--color-primary) !important;
  border-radius: 0 8px 8px 0 !important;
  padding: 1.25rem 1.5rem 1rem !important;
}

/* Panel titles — consistent sizing across all panels */
[id$=-upcoming-events] > h2,
[id$=-upcoming-events] > h2,
[id$=-school-highlights] > h2,
[id$=-school-highlights] > h2,
[id$=-district-news] > h2,
[id$=-district-news] > h2,
[id$=-parentsquare-feed] > h2,
[id$=-parentsquare-feed] > h2 {
  font-size: clamp(1.1rem, 2vw, 1.4rem) !important;
  font-weight: 700 !important;
  text-transform: none !important;
  letter-spacing: normal !important;
  margin: 0 0 0.75rem !important;
  line-height: 1.2 !important;
  padding: 0 !important;
  border: none !important;
}

[id$=-upcoming-events] > h2,
[id$=-upcoming-events] > h2 { color: var(--color-primary-mid) !important; }

[id$=-school-highlights] > h2,
[id$=-school-highlights] > h2,
[id$=-district-news] > h2,
[id$=-district-news] > h2 { color: var(--color-primary) !important; }

[id$=-parentsquare-feed] > h2,
[id$=-parentsquare-feed] > h2 { color: var(--color-primary-dark) !important; }

/* ══════════════════════════════════════════════════════════════
   School name eyebrow on teaser cards
   ══════════════════════════════════════════════════════════════ */

.news-card-school {
  display: block;
  font-size: 0.7rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: var(--ls-loose);
  color: var(--color-primary);
  margin-bottom: 0.1rem;
}

/* ══════════════════════════════════════════════════════════════
   Upcoming Events — Google Calendar feed
   ══════════════════════════════════════════════════════════════ */

.events-list {
  list-style: none;
  margin: 0;
  padding: 0;
}

.events-list__item {
  display: flex;
  gap: 0.75rem;
  padding: 0.6rem 0;
  border-bottom: 1px solid var(--color-border, #e0e0e0);
  align-items: flex-start;
}

.events-list__item:last-child {
  border-bottom: none;
}

.events-list__date-col {
  flex-shrink: 0;
  width: 4rem;
  text-align: center;
  padding: 0.4rem 0.25rem;
  background: var(--color-primary);
  border-radius: 6px;
  color: var(--color-on-primary);
  line-height: 1;
}

.events-list__date {
  display: block;
  font-size: 0.88rem;
  font-weight: 700;
  letter-spacing: var(--ls-snug);
}

.events-list__time {
  display: block;
  font-size: 0.72rem;
  font-weight: 600;
  margin-top: 0.2rem;
  color: var(--color-on-primary);
  text-transform: uppercase;
  letter-spacing: var(--ls-snug);
}

.events-list__info {
  flex: 1;
  min-width: 0;
  padding-top: 0.15rem;
}

.events-list__title {
  font-size: 0.85rem;
  font-weight: 600;
  line-height: 1.35;
  color: var(--color-text, #333);
  /* inline-flex so the element shrinks to text width — otherwise the
     unified gradient underline (background-image sized 100% of the
     element) would span the whole row instead of just the title text. */
  display: inline-flex;
  align-items: center;
  min-height: 2.75rem;
  padding: 0.2rem 0;
  /* Hover/focus animation comes from the unified .mvsd-link-anim rule
     in base.css — same accent grow-in as feed titles + body links. */
}

.events-empty {
  font-size: 0.85rem;
  color: var(--color-text-muted, #999);
  font-style: italic;
  text-align: center;
  padding: 1rem 0;
}

/* ══════════════════════════════════════════════════════════════
   ParentSquare Feed — sidebar compact list
   ══════════════════════════════════════════════════════════════ */

.ps-feed__item {
  padding: 0.6rem 0;
  border-bottom: 1px solid var(--color-border, #e0e0e0);
}

.ps-feed__item:last-child {
  border-bottom: none;
}

.ps-feed__date {
  font-size: 0.7rem;
  color: var(--color-text-muted, #777);
  text-transform: uppercase;
  letter-spacing: var(--ls-relaxed);
  display: block;
  margin-bottom: 0.15rem;
}

.ps-feed__title {
  font-size: 0.88rem;
  font-weight: 600;
  line-height: 1.35;
  color: var(--color-text, #333);
  display: block;
}

.ps-feed__link {
  display: block;
  margin-top: 0.2rem;
}

.ps-feed__link a {
  font-size: 0.72rem;
  padding: 0.4rem 0;
  display: inline-block;
  font-weight: 600;
  color: var(--color-primary);
  text-transform: uppercase;
  letter-spacing: var(--ls-relaxed);
  /* Hover via .mvsd-link-anim (gradient grow underline). */
}

.ps-feed__footer {
  margin-top: 0.75rem;
  padding-top: 0.5rem;
  border-top: 1px solid var(--color-border, #e0e0e0);
  text-align: right;
}

.ps-feed__footer a {
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--color-primary);
  text-transform: uppercase;
  letter-spacing: var(--ls-relaxed);
  /* Hover via .mvsd-link-anim (matches read-more links above). */
}

.ps-feed__empty {
  font-size: 0.85rem;
  color: var(--color-text-muted, #999);
  font-style: italic;
  text-align: center;
  padding: 1rem 0;
}

/* Remove bottom margin from last right-column panel */
.news-zone > .zone-inner > div > :last-child {
  margin-bottom: 0 !important;
}

/* Mobile: tighter panel padding */
@media (max-width: 768px) {
  [id$=-upcoming-events],
  [id$=-school-highlights],
  [id$=-district-news],
  [id$=-parentsquare-feed] {
    padding: 1rem 1rem 0.75rem !important;
  }
}

/* ══════════════════════════════════════════════════════════════
   Search Results Page
   ══════════════════════════════════════════════════════════════ */

/* ── Search results page form ── */
#views-exposed-form-mvsd-search-page-1 {
  margin-bottom: 2.5rem;
  padding: 1.75rem 2rem;
  background: var(--color-bg-subtle, #f5f5f5);
  border-radius: 12px;
  border: 1px solid var(--color-border, #e0e0e0);
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 0.75rem;
}

#views-exposed-form-mvsd-search-page-1 .form-item-keys {
  flex: 1;
  min-width: 200px;
}

#views-exposed-form-mvsd-search-page-1 .form-item-keys label {
  display: block;
  font-size: 0.78rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: var(--ls-loose);
  color: var(--color-primary);
  margin-bottom: 0.4rem;
}

#views-exposed-form-mvsd-search-page-1 .form-item-keys input[type="text"],
#views-exposed-form-mvsd-search-page-1 .form-item-keys input[type="search"] {
  width: 100%;
  padding: 0.7rem 1rem;
  font-size: 1rem;
  border: 2px solid var(--color-border, #e0e0e0);
  border-radius: 8px;
  background: #fff;
  transition: border-color 200ms ease, box-shadow 200ms ease;
}

#views-exposed-form-mvsd-search-page-1 .form-item-keys input:focus {
  border-color: var(--color-primary);
  box-shadow: 0 0 0 3px rgba(var(--color-primary-rgb, 1,73,31), 0.1);
  outline: none;
}

#views-exposed-form-mvsd-search-page-1 .form-actions {
  flex-shrink: 0;
}

#views-exposed-form-mvsd-search-page-1 .form-actions input[type="submit"] {
  padding: 0.7rem 2rem;
  font-size: 0.95rem;
  font-weight: 700;
  background: var(--color-primary);
  color: var(--color-on-primary);
  border: none;
  border-radius: 8px;
  cursor: pointer;
  text-transform: uppercase;
  letter-spacing: var(--ls-relaxed);
  transition: background 200ms ease, transform 100ms ease;
}

#views-exposed-form-mvsd-search-page-1 .form-actions input[type="submit"]:hover {
  background: var(--color-primary-dark);
  transform: translateY(-1px);
}

#views-exposed-form-mvsd-search-page-1 .form-actions input[type="submit"]:active {
  transform: translateY(0);
}

@media (max-width: 768px) {
  #views-exposed-form-mvsd-search-page-1 {
    padding: 1rem;
    gap: 0;
  }

  #views-exposed-form-mvsd-search-page-1 .form-item-keys {
    flex: 1;
    min-width: 0;
  }

  #views-exposed-form-mvsd-search-page-1 .form-item-keys label {
    display: none;
  }

  #views-exposed-form-mvsd-search-page-1 .form-item-keys input[type="text"],
  #views-exposed-form-mvsd-search-page-1 .form-item-keys input[type="search"] {
    border-radius: 8px 0 0 8px;
    border-right: none;
    padding: 0.65rem 0.75rem;
  }

  #views-exposed-form-mvsd-search-page-1 .form-actions input[type="submit"] {
    padding: 0.65rem 1rem;
    border-radius: 0 8px 8px 0;
    font-size: 0.85rem;
  }
}

.search-result {
  display: flex;
  gap: 1rem;
  padding: 1.25rem 0;
  border-bottom: 1px solid var(--color-border, #e0e0e0);
  align-items: flex-start;
}

.search-result:last-child {
  border-bottom: none;
}

.search-result__thumb {
  flex-shrink: 0;
  width: 100px;
  height: 70px;
  border-radius: 6px;
  overflow: hidden;
  background: var(--color-bg-subtle, #f5f5f5);
}

.search-result__thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.search-result__body {
  flex: 1;
  min-width: 0;
}

.search-result__header {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-bottom: 0.25rem;
}

.search-result__type {
  font-size: 0.68rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: var(--ls-loose);
  color: var(--color-on-primary);
  background: var(--color-primary);
  padding: 0.1rem 0.4rem;
  border-radius: 3px;
  white-space: nowrap;
}

.search-result__date {
  font-size: 0.75rem;
  color: var(--color-text-muted, #777);
}

.search-result__title {
  margin: 0 0 0.3rem;
  font-size: 1.05rem;
  font-weight: 600;
  line-height: 1.3;
}

.search-result__title a {
  color: var(--color-text, #333);
  text-decoration: none;
}

.search-result__title a:hover {
  color: var(--color-primary);
  text-decoration: underline;
}

/* Long unbroken tokens (e.g. Some_File_Name.pdf) must wrap or they force
   horizontal page overflow on narrow screens. Audit 2026-07-10 mobile pass. */
.search-result__title,
.search-result__title a,
.search-result__header {
  overflow-wrap: anywhere;
  word-break: break-word;
  min-width: 0;
}

.search-result__excerpt {
  margin: 0;
  font-size: 0.88rem;
  color: var(--color-text-muted, #555);
  line-height: 1.5;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

@media (max-width: 480px) {
  .search-result__thumb {
    width: 70px;
    height: 50px;
  }
}

.search-no-results {
  text-align: center;
  padding: 3rem 1rem;
  font-size: 1.05rem;
  color: var(--color-text-muted, #666);
}

/* ── 404/403 inline search form ── */
.error-page__search {
  margin: 1.5rem 0;
}

.error-page__search-wrap {
  display: flex;
  max-width: 480px;
  margin: 0 auto;
}

.error-page__search-input {
  flex: 1;
  padding: 0.7rem 1rem;
  font-size: 1rem;
  border: 2px solid var(--color-border, #e0e0e0);
  border-right: none;
  border-radius: 8px 0 0 8px;
  background: #fff;
  transition: border-color 200ms ease;
}

.error-page__search-input:focus {
  border-color: var(--color-primary);
  outline: none;
}

.error-page__search-btn {
  padding: 0.7rem 1.5rem;
  font-size: 0.95rem;
  font-weight: 700;
  background: var(--color-primary);
  color: var(--color-on-primary);
  border: none;
  border-radius: 0 8px 8px 0;
  cursor: pointer;
  text-transform: uppercase;
  letter-spacing: var(--ls-relaxed);
  transition: background 200ms ease;
}

.error-page__search-btn:hover {
  background: var(--color-primary-dark);
}

.error-page__links-heading {
  font-size: 0.88rem;
  color: var(--color-text-muted, #666);
  margin: 1.5rem 0 0.5rem;
}

/* ── Mobile news cards: drop the hover slide-out, show a standard card ─────────
   (2026-06-02, stakeholder ask) On touch there is no hover, and :focus-within
   could make the slide-out overlay pop unpredictably. Below 768px we hide the
   overlay entirely; the card then reads as a standard image / title / excerpt
   card — the .news-card-summary--mobile excerpt already renders in the body at
   this breakpoint. Desktop (>=769px) keeps the hover slide-out unchanged.
   Class-based, so it covers the mvsd / dept / site article cards uniformly. */
@media (max-width: 768px) {
  .news-card-overlay {
    display: none !important;
  }

  /* Give the standard mobile card a touch more of the excerpt (3 lines) so it
     reads as a real "feeder", and a clear tap target on the title. */
  .news-card-summary--mobile {
    -webkit-line-clamp: 3;
    font-size: 0.9rem;
  }

  .news-card-title a {
    text-decoration: none;
  }
}

/* ── Front-page boxes: full card frame on mobile (stakeholder ask) ─────────────
   (2026-06-02) The Upcoming Events / School Spotlight / ParentSquare boxes on
   the front page were framed only on the left; on mobile (where they stack
   full-width) that reads as unfinished. Give each a complete card frame — border
   all sides + rounded corners (the gold left accent is kept/strengthened) — so
   each reads as a clean framed card. Targeted by stable block IDs via attribute
   selectors so it works on the district front and any school front variant.
   Mobile-only; desktop layout unchanged. */
@media (max-width: 600px) {
  [id*="upcoming-events"],
  [id*="school-highlights"],
  [id*="parentsquare-feed"] {
    border: 1px solid var(--color-border, #e2e8e5);
    border-left: 4px solid var(--color-accent, #f5a623);
    border-radius: 10px;
    padding: 0.75rem 1rem 1rem;
    background: var(--color-surface, #fff);
    margin-bottom: 1.25rem;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06);
  }
}

/* == Split search results ======================================
   /search runs two queries and renders them side by side: pages on
   the left, attachments on the right. They used to share one list of
   ten rows and attachments won it outright — on a school subdomain a
   common term returned ten files and zero pages, because file results
   carry no domain grants while node results do.

   Mobile stacks them PAGES FIRST. Someone hunting for a page should
   never have to scroll past the attachment list to reach one. */
.search-split__grid {
  display: grid;
  grid-template-columns: 1.6fr 1fr;
  gap: var(--space-8, 2rem);
  /* stretch, not start, so both columns share a height and the pagers line up */
  align-items: stretch;
}
.search-split__heading {
  font-size: var(--font-size-lg);
  color: var(--color-primary);
  margin: 0 0 var(--space-4);
  padding-bottom: var(--space-2);
  border-bottom: 2px solid var(--color-accent);
  display: flex;
  align-items: baseline;
  gap: var(--space-2);
}
.search-split__count {
  font-size: var(--font-size-sm);
  font-weight: var(--font-weight-normal, 400);
  color: var(--color-text-muted, #555);
}
.search-split__count::before { content: "("; }
.search-split__count::after  { content: ")"; }

/* Both columns show 10 results, but a page card is taller than a file row, so
   the columns still end at different heights. Make each column a flex column
   and push its pager down with margin-top:auto, so the two pagers sit on the
   same line however the rows fall.

   The pages column holds its pager directly. The embedded files view wraps
   its own in two divs, so those have to stretch and lay out as columns too or
   the auto margin has nothing to push against. */
.search-split__col {
  display: flex;
  flex-direction: column;
}
.search-split__col--files > .views-element-container,
.search-split__col--files > .views-element-container > [class*="js-view-dom-id"] {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  min-height: 0;
}
.search-split__col .pager {
  margin-top: auto;
  padding-top: var(--space-5, 1.25rem);

  /* The pager sizes itself against the width it actually has, not the
     viewport — see the container-query block further down. */
  container-type: inline-size;
  container-name: searchpager;
}

/* ── Pager: adapt to the width it actually has ──────────────────────────
   The pager wrapped onto a second row, and viewport breakpoints cannot fix
   it, for two reasons:

   1. One viewport width means two very different pager widths. At 1000px
      the pages pager has 557px to work with and the files pager 306px.
   2. The pager grows with the page you are on. On page 1 it is
      "1 2 3 4 5 … Next › Last »" (~350px), but once you are past page 5
      core adds "« First ‹ Previous …" on the left and it needs ~735px —
      wider than the pages column EVER gets (689px at a 1440px viewport).
      That is why the owner still saw wrapping: it was not only the narrow
      column, it was every column, as soon as you paged in.

   So the pager is its own query container and sheds weight against its own
   inline size, cheapest-first:
     740px — drop "« First" / "Last »", but only mid-set, where the
             pager is at its widest and they are pure redundancy
     620px — drop the words, keep the glyphs « ‹ › »
     440px — show only the current page and its two neighbours
     300px — show only the current page

   What never goes: the current page, the ellipses that say "there is more
   here", and Previous/Next. Hiding the redundant numbered links with
   display:none takes them out of the accessibility tree too, which is the
   point — a screen-reader user should not have to hear seven page links
   that all still exist one Next away. (visibility:hidden would keep them in
   the tree but also keep their width, which would not fix anything.) The
   <nav> and its "Pagination" heading are untouched.

   flex-wrap stays ON deliberately. If a tier is ever a few pixels short —
   a 3-digit page number, a long translation of "Previous" — the pager
   wraps as it does today rather than overflowing its column or clipping a
   control. Wrapping is the fallback, no longer the normal state. */

/* The ellipsis is a bare <li> with no <a> inside, so it is shorter than its
   neighbours and sits off the shared baseline. Give it the same box. */
.search-split__col .pager__item--ellipsis {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 2.4rem;
  padding: 0 0.35rem;
}

/* 740px — drop the first/last jumps, but ONLY on the pages that actually
   need the room. The pager is at its widest mid-set, which is exactly when
   both Previous and Next exist; on page 1 (no Previous) and on the last
   page (no Next) it is ~200px narrower and "Last »" still fits, so leave
   it alone rather than stripping a control that costs nothing there.
   The numbers reach the same pages, so this is the cheapest thing to lose. */
@container searchpager (max-width: 740px) {
  .search-split__col .pager__items:has(.pager__item--previous):has(.pager__item--next) > .pager__item--first,
  .search-split__col .pager__items:has(.pager__item--previous):has(.pager__item--next) > .pager__item--last {
    display: none;
  }
}

/* 620px — glyph only. The visible label is an aria-hidden span, so dropping
   it costs nothing: the accessible name still comes from the sibling
   .visually-hidden "Previous page" / "Next page" span, and the anchor keeps
   its title ("Go to next page") as a hover tooltip. All four convert
   together — a chevron Next beside a worded "Last »" reads as a bug. */
@container searchpager (max-width: 620px) {
  .search-split__col .pager__item--first a > span[aria-hidden="true"],
  .search-split__col .pager__item--previous a > span[aria-hidden="true"],
  .search-split__col .pager__item--next a > span[aria-hidden="true"],
  .search-split__col .pager__item--last a > span[aria-hidden="true"] {
    display: none;
  }
  .search-split__col .pager__item--first a::after    { content: "\00AB"; }
  .search-split__col .pager__item--previous a::after { content: "\2039"; }
  .search-split__col .pager__item--next a::after     { content: "\203A"; }
  .search-split__col .pager__item--last a::after     { content: "\00BB"; }
  .search-split__col .pager__item--first a,
  .search-split__col .pager__item--previous a,
  .search-split__col .pager__item--next a,
  .search-split__col .pager__item--last a {
    padding: 0 0.5rem;
    font-size: 1.2rem;
  }
}

/* 440px — current page and its immediate neighbours only. The numbers are
   the <li>s with no --modifier class; :has() picks the one before the
   active page, the adjacent sibling picks the one after. */
@container searchpager (max-width: 440px) {
  .search-split__col .pager__items > li:not([class*="pager__item--"]) {
    display: none;
  }
  .search-split__col .pager__items > li.is-active,
  .search-split__col .pager__items > li.is-active + li:not([class*="pager__item--"]),
  .search-split__col .pager__items > li:has(+ .is-active):not([class*="pager__item--"]) {
    display: block;
  }
  /* tighter numbers so three of them still clear a 300px column */
  .search-split__col .pager__items > li:not([class*="pager__item--"]) a {
    min-width: 2.2rem;
    padding: 0 0.4rem;
  }
}

/* 300px — last resort: the current page on its own, between the chevrons.
   Extra .pager__item in the selector so this outranks the un-hide rules
   above without needing !important. */
@container searchpager (max-width: 300px) {
  .search-split__col .pager__items > li.pager__item:not([class*="pager__item--"]):not(.is-active) {
    display: none;
  }
}

/* The attachments column gets its own surface so it reads as a distinct
   panel rather than a second run of results, and its rows are styled as a
   file list: an icon, the filename, then a quiet meta line. */
.search-split__col--files {
  background: var(--color-bg-subtle, #f5f5f5);
  border: 1px solid var(--color-border, #e0e0e0);
  border-radius: var(--radius-md, 6px);
  padding: var(--space-5, 1.25rem);
}
.search-split__col--files .search-split__heading {
  margin-top: 0;
}

/* file-list rows */
.search-split__col--files article.search-result {
  display: grid;
  grid-template-columns: 20px 1fr;
  column-gap: var(--space-3, 0.75rem);
  align-items: start;
  padding: var(--space-3, 0.75rem) 0;
  border-bottom: 1px solid var(--color-border, #e0e0e0);
}
.search-split__col--files article.search-result:last-of-type {
  border-bottom: 0;
}
.search-split__col--files article.search-result::before {
  content: "";
  width: 18px;
  height: 20px;
  margin-top: 2px;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23667' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z'/%3E%3Cpolyline points='14 2 14 8 20 8'/%3E%3C/svg%3E") no-repeat center / contain;
}
.search-split__col--files .search-result__body {
  min-width: 0;   /* let long filenames wrap instead of stretching the grid */
}
.search-split__col--files .search-result__title {
  font-size: var(--font-size-base);
  margin: 0 0 0.15rem;
  overflow-wrap: anywhere;
}
/* type + size read as one quiet meta line under the name */
.search-split__col--files .search-result__header {
  order: 2;
  gap: var(--space-2, 0.5rem);
  font-size: var(--font-size-sm);
  opacity: 0.8;
}
.search-split__col--files .search-result__body {
  display: flex;
  flex-direction: column;
}
.search-split__col--files .search-result__title { order: 1; }
.search-split__col--files .search-result__series { order: 3; margin: 0.1rem 0 0; }
.search-split__col--files .search-result__excerpt { order: 4; margin-top: 0.25rem; }

/* Preview trigger — sits last in the row. Needs an explicit order or it
   defaults to 0 and jumps above the filename. The icon must be sized here
   rather than in the modal's own library, which this page never loads. */
.search-split__col--files .search-result__preview { order: 5; }
.search-result__preview {
  margin: 0.35rem 0 0;
  font-size: var(--font-size-sm, 0.875rem);
}
.search-result__preview a {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  color: var(--color-primary);
}
.search-result__preview svg {
  width: 1em;
  height: 1em;
  flex: 0 0 auto;
}

/* The attachments column is narrower, so its rows are a compact single
   line rather than the card treatment the page results get. */
.search-split__col--files .search-result {
  padding: var(--space-3) 0;
}
.search-split__col--files .search-result__excerpt {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  font-size: var(--font-size-sm);
}
.search-split__col--files .search-result__thumb { display: none; }

@media (max-width: 900px) {
  .search-split__grid { grid-template-columns: 1fr; }
  /* explicit, so the order never depends on source order alone */
  .search-split__col--pages { order: 1; }
  .search-split__col--files { order: 2; }
  /* stacked, there is nothing to align to — a pushed-down pager would just
     leave a hole under a short column. */
  .search-split__col,
  .search-split__col--files > .views-element-container,
  .search-split__col--files > .views-element-container > [class*="js-view-dom-id"] {
    display: block;
  }
  .search-split__col .pager { margin-top: var(--space-6, 1.5rem); }
  .search-split__col--files { padding: var(--space-4, 1rem); }

  /* Stacked means phone/tablet. The shared pager shrinks its targets to
     2.1rem (33.6px) below 540px, which is under the 44px WCAG 2.2 AAA
     target size; on a search page the pager is the whole navigation, so
     hold Previous/Next at 44px and keep the numbers from shrinking. There
     is room for it: stacked, each column has the full content width. */
  .search-split__col .pager__item a {
    min-width: 2.4rem;
    height: 2.75rem;
  }
  .search-split__col .pager__item--first a,
  .search-split__col .pager__item--previous a,
  .search-split__col .pager__item--next a,
  .search-split__col .pager__item--last a {
    min-width: 2.75rem;
  }
  .search-split__col .pager__item--ellipsis { height: 2.75rem; }
}

/* ── Split search: in-place paging state ───────────────────────────────
   js/search-split-pager.js re-pages each column with fetch + a DOM swap
   instead of a document load. The mechanism was right and it still felt
   broken, because nothing visible happened until the response arrived —
   measured at 5.8s on a cold column. So the click now has its own
   choreography, independent of the request:

     on click    the page scrolls to the exposed search form (JS)
     +120ms      .is-pager-loading — the column turns over to a skeleton
     on arrival  .is-pager-entering — the new rows ease in

   Two classes, not one. .is-pager-busy goes on immediately and is
   deliberately invisible: it carries aria-busy and disarms the pager so a
   second click cannot stack up. .is-pager-loading is the visible loading
   state and waits 120ms, because a warm response lands in ~30ms and a
   skeleton that flashes for two frames is worse than no skeleton at all.

   The stale rows go out with `visibility`, not `opacity`. Dimmed text is
   the worst of both: unreadable to a sighted reader and still fully
   present to a screen reader. visibility:hidden takes the rows out of the
   page and out of the accessibility tree while keeping every pixel of
   their box — so the column does not resize, the document height does not
   change, there is no layout shift when the skeleton appears or leaves,
   and the scroll already running has nothing to fight.

   Progressive enhancement: with JS off none of these hooks ever appears
   and the pagers are ordinary links, so none of this applies. */

/* Containing block for the loading layer. No offsets, so nothing moves;
   set unconditionally rather than with the state class, so the layer is
   never positioned against the wrong ancestor for a frame. */
.search-split__col {
  position: relative;
}

/* Immediate, invisible: don't let a second click stack up on a column
   that is already loading. */
.search-split__col.is-pager-busy .pager a {
  pointer-events: none;
}

/* The heading stays — it is the reader's anchor and the focus target.
   Everything else in the column steps aside for the skeleton. */
.search-split__col.is-pager-loading > :not(.search-split__heading):not(.search-split__loader) {
  visibility: hidden;
}

/* bottom:0 so the layer spans the whole remaining column. It draws nothing
   down there — the point is to give the badge below a containing block tall
   enough to stay stuck to for as long as the reader is anywhere in this
   column. Without it the badge scrolls off with the skeleton and the reader
   flying up the page sees a plain white column with no explanation. */
.search-split__loader {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 2;
  pointer-events: none;
}
/* The files column is a padded panel, and an absolutely positioned child
   is laid out against its padding box — so inset the layer by the same
   padding or the skeleton bars run wider than the rows they stand in for. */
.search-split__col--files .search-split__loader {
  left: var(--space-5, 1.25rem);
  right: var(--space-5, 1.25rem);
}

/* "Loading results…" — the honest, readable half of the indicator. The
   shimmer alone is ambiguous at 5s; this says it in words. aria-hidden in
   the markup: role="status" already announces the outcome, and the column
   is aria-busy while this is up. */
.search-split__loader-badge {
  /* Pinned just under the masthead for as long as any part of this column is
     on screen, so the answer to "is it doing anything?" is always in view —
     including during the scroll, when the skeleton itself is still off the
     top of the window. --split-sticky-top is written by JS from the measured
     masthead height; the fallback matches its collapsed height. */
  position: sticky;
  top: var(--split-sticky-top, 60px);
  z-index: 1;
  /* flex + fit-content rather than inline-flex: sticky on an inline-level box
     is not reliable across browsers, and this keeps the pill the same shape. */
  display: flex;
  width: -moz-fit-content;
  width: fit-content;
  align-items: center;
  gap: 0.5rem;
  margin: 0 0 var(--space-4, 1rem);
  padding: 0.3rem 0.75rem 0.3rem 0.55rem;
  border: 1px solid var(--color-border, #e0e0e0);
  border-radius: 999px;
  background: var(--color-bg, #ffffff);
  /* #5a5a5a on #ffffff = 7.0:1 — this text is fully readable, unlike the
     0.55-opacity column it replaces. */
  color: var(--color-text-muted, #5a5a5a);
  font-size: var(--font-size-sm, 0.875rem);
  line-height: 1.4;
}

/* Brand-tinted, so the spinner belongs to whichever of the 13 sites you
   are on rather than looking like a framework default. */
.search-split__loader-ring {
  width: 1em;
  height: 1em;
  flex: 0 0 auto;
  border: 2px solid var(--color-border, #e0e0e0);
  border-top-color: var(--color-brand, #008544);
  border-radius: 50%;
  animation: mvsd-split-spin 700ms linear infinite;
}
@keyframes mvsd-split-spin {
  to { transform: rotate(360deg); }
}

/* Skeleton rows, drawn to the same rhythm as real result rows: a title
   line, a full body line, a short one, and the same hairline rule between
   them. JS decides how many to draw from the space left on screen. */
.search-split__skel-row {
  padding-bottom: var(--space-4, 1rem);
  margin-bottom: var(--space-4, 1rem);
  border-bottom: 1px solid var(--color-border, #e0e0e0);
}
.search-split__skel-row:last-child {
  margin-bottom: 0;
  border-bottom: 0;
}
.search-split__skel-line {
  display: block;
  height: 0.7rem;
  width: 100%;
  margin-bottom: 0.55rem;
  border-radius: var(--radius-sm, 4px);
  background-color: #e6e6e6;
  background-image: linear-gradient(
    90deg,
    rgba(255, 255, 255, 0) 0%,
    rgba(255, 255, 255, 0.9) 50%,
    rgba(255, 255, 255, 0) 100%
  );
  background-repeat: no-repeat;
  background-size: 180px 100%;
  animation: mvsd-split-shimmer 1250ms ease-in-out infinite;
}
.search-split__skel-line--title {
  height: 1rem;
  width: 62%;
  margin-bottom: 0.7rem;
  background-color: #dcdcdc;
}
.search-split__skel-line--short {
  width: 38%;
  margin-bottom: 0;
}
@keyframes mvsd-split-shimmer {
  from { background-position: -180px 0; }
  to   { background-position: calc(100% + 180px) 0; }
}
/* Offset each row so the column breathes instead of pulsing in unison. */
.search-split__skel-row:nth-child(2) .search-split__skel-line { animation-delay:  90ms; }
.search-split__skel-row:nth-child(3) .search-split__skel-line { animation-delay: 180ms; }
.search-split__skel-row:nth-child(4) .search-split__skel-line { animation-delay: 270ms; }
.search-split__skel-row:nth-child(5) .search-split__skel-line { animation-delay: 360ms; }
.search-split__skel-row:nth-child(6) .search-split__skel-line { animation-delay: 450ms; }
.search-split__skel-row:nth-child(7) .search-split__skel-line { animation-delay: 540ms; }
.search-split__skel-row:nth-child(8) .search-split__skel-line { animation-delay: 630ms; }

/* Arrival. Short and single-step — the rows rise 6px and fade in together
   rather than snapping. No stagger: the pager sits at the bottom of the
   column and a staggered pager arriving last reads as lag, not polish. */
.search-split__col.is-pager-entering > :not(.search-split__heading) {
  animation: mvsd-split-in 200ms cubic-bezier(0.22, 0.61, 0.36, 1) both;
}
@keyframes mvsd-split-in {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: none; }
}

/* Reduced motion: the state changes still happen, none of them move.
   The scroll becomes an instant jump (JS), the rows appear rather than
   ease in, the shimmer holds still, and the spinner — which is nothing
   BUT motion — is dropped for the wording it sits beside. */
@media (prefers-reduced-motion: reduce) {
  .search-split__col.is-pager-entering > * {
    animation: none;
  }
  .search-split__skel-line {
    animation: none;
    background-image: none;
  }
  .search-split__loader-ring {
    display: none;
  }
  .search-split__loader-badge {
    padding-left: 0.75rem;
  }
}

/* Stacked, the files panel drops to a smaller padding — keep the loading
   layer lined up with it. */
@media (max-width: 900px) {
  .search-split__col--files .search-split__loader {
    left: var(--space-4, 1rem);
    right: var(--space-4, 1rem);
  }
}

/* The heading is the scroll AND focus target after a swap. JS gives it
   tabindex="-1", so it is never tabbed to directly; :focus alone would
   flash a ring at a mouse user who clicked the pager. :focus-visible
   shows the ring for the keyboard path that actually needs to see where
   it landed. */
.search-split__heading:focus { outline: none; }
.search-split__heading:focus-visible {
  outline: 3px solid var(--color-focus-ring);
  outline-offset: 4px;
}

/* == /search advanced options ==================================
   MVSD-SEARCH-ADVANCED (feedback #59 part 2).

   The exposed form is a flex row: search box, then Search button, both on
   one line. The panel has to be a full-width row underneath, so it takes
   flex-basis:100% and the row wraps. The wrapper already sets flex-wrap,
   so nothing above this needs to change.

   Styled as a plain disclosure rather than a card. It sits inside a tinted,
   bordered form already, and a second border inside the first reads as a
   nested box rather than as one panel.
   ============================================================== */
#views-exposed-form-mvsd-search-page-1 .search-advanced {
  flex: 0 0 100%;
  margin: 0.25rem 0 0;
  border-top: 1px solid var(--color-border, #e0e0e0);
  padding-top: 0.6rem;
}

#views-exposed-form-mvsd-search-page-1 .search-advanced > summary {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  width: auto;
  cursor: pointer;
  padding: 0.25rem 0.35rem;
  margin-inline-start: -0.35rem;
  border-radius: 6px;
  font-size: 0.85rem;
  font-weight: 700;
  letter-spacing: var(--ls-loose);
  text-transform: uppercase;
  color: var(--color-primary);
  /* Colour is never the only cue: the marker rotates and the text is
     underlined on hover, so the control still reads as a control for
     someone who cannot separate it from the surrounding text by hue. */
  list-style: none;
}

/* Safari still needs the WebKit pseudo-element removed by name. */
#views-exposed-form-mvsd-search-page-1 .search-advanced > summary::-webkit-details-marker {
  display: none;
}

#views-exposed-form-mvsd-search-page-1 .search-advanced > summary::before {
  content: "";
  width: 0;
  height: 0;
  border-inline-start: 6px solid currentColor;
  border-top: 4px solid transparent;
  border-bottom: 4px solid transparent;
  transition: transform 150ms ease;
  flex: none;
}

#views-exposed-form-mvsd-search-page-1 .search-advanced[open] > summary::before {
  transform: rotate(90deg);
}

#views-exposed-form-mvsd-search-page-1 .search-advanced > summary:hover {
  text-decoration: underline;
}

#views-exposed-form-mvsd-search-page-1 .search-advanced > summary:focus-visible {
  outline: 3px solid var(--color-focus-ring, #1a1a1a);
  outline-offset: 2px;
}

#views-exposed-form-mvsd-search-page-1 .search-advanced__intro {
  margin: 0.6rem 0 0.75rem;
  font-size: 0.9rem;
  color: var(--color-text-muted, #555);
}

/* One checkbox row per line. A two-column grid rather than inline flow: the
   labels are full sentences and the longest one wraps at 390px, and with the
   box and the label merely inline the second line ran back under the box
   instead of hanging under the first line of its own label. The grid gives
   every row the same text column, and the description lines up with it for
   free instead of being nudged there with a magic-number margin. */
#views-exposed-form-mvsd-search-page-1 .search-advanced .form-type-checkbox,
#views-exposed-form-mvsd-search-page-1 .search-advanced .js-form-type-checkbox {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  column-gap: 0.55rem;
  align-items: start;
  margin: 0 0 0.85rem;
}

#views-exposed-form-mvsd-search-page-1 .search-advanced input[type="checkbox"] {
  /* A 44px row is impractical inside a compact panel, but the box itself must
     not be a pin-prick: 1.1rem plus the label's own hit area keeps the target
     comfortable. The top margin optically centres it on the first line of the
     label rather than on the whole wrapped block. */
  grid-column: 1;
  grid-row: 1;
  width: 1.1rem;
  height: 1.1rem;
  margin: 0.15rem 0 0;
  accent-color: var(--color-primary);
  cursor: pointer;
}

#views-exposed-form-mvsd-search-page-1 .search-advanced input[type="checkbox"]:focus-visible {
  outline: 3px solid var(--color-focus-ring, #1a1a1a);
  outline-offset: 2px;
}

#views-exposed-form-mvsd-search-page-1 .search-advanced label {
  grid-column: 2;
  grid-row: 1;
  display: block;
  font-size: 0.95rem;
  font-weight: 600;
  line-height: 1.35;
  text-transform: none;
  letter-spacing: normal;
  color: var(--color-text, #222);
  cursor: pointer;
  margin: 0;
}

#views-exposed-form-mvsd-search-page-1 .search-advanced .description {
  grid-column: 2;
  grid-row: 2;
  margin: 0.15rem 0 0;
  font-size: 0.85rem;
  line-height: 1.45;
  color: var(--color-text-muted, #555);
}

#views-exposed-form-mvsd-search-page-1 .search-advanced__apply {
  margin-top: 0.25rem;
  padding: 0.55rem 1.5rem;
  font-size: 0.85rem;
  font-weight: 700;
  background: var(--color-primary);
  color: var(--color-on-primary);
  border: none;
  border-radius: 8px;
  cursor: pointer;
  text-transform: uppercase;
  letter-spacing: var(--ls-relaxed);
  transition: background 200ms ease, transform 100ms ease;
}

#views-exposed-form-mvsd-search-page-1 .search-advanced__apply:hover {
  background: var(--color-primary-dark);
  transform: translateY(-1px);
}

#views-exposed-form-mvsd-search-page-1 .search-advanced__apply:focus-visible {
  outline: 3px solid var(--color-focus-ring, #1a1a1a);
  outline-offset: 2px;
}

/* The mobile rule above collapses the form's gap to 0 so the box and the
   Search button read as one control. The panel is a separate row and needs
   its own breathing room back. */
@media (max-width: 768px) {
  #views-exposed-form-mvsd-search-page-1 .search-advanced {
    margin-top: 0.9rem;
    padding-top: 0.75rem;
  }
}

/* == "Advanced options are on" note ============================
   Sits between the form and the results. Deliberately loud enough to be
   noticed, because it is the explanation for a result count that would
   otherwise look wrong, and the only exit for someone who arrived on a
   shared link. */
.search-adv-note {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.5rem 1rem;
  margin: -1.5rem 0 2rem;
  padding: 0.75rem 1rem;
  border-inline-start: 4px solid var(--color-accent, #f5a623);
  border-radius: 0 8px 8px 0;
  background: var(--color-bg-subtle, #f5f5f5);
}

.search-adv-note__text {
  margin: 0;
  font-size: 0.95rem;
  color: var(--color-text, #222);
}

/* Two indicators, not one: this link is set off by colour AND underline,
   so it does not depend on hue alone. */
.search-adv-note__clear {
  font-size: 0.9rem;
  font-weight: 700;
  color: var(--color-primary);
  text-decoration: underline;
}

.search-adv-note__clear:hover {
  text-decoration-thickness: 2px;
}

.search-adv-note__clear:focus-visible {
  outline: 3px solid var(--color-focus-ring, #1a1a1a);
  outline-offset: 2px;
}

/* With the attachments column left out, the pages column takes the whole
   width. Capped, because a search result is a line of prose and a 1,400px
   measure is unreadable. */
.search-split__grid--single {
  grid-template-columns: minmax(0, 68ch);
}

@media (max-width: 900px) {
  .search-split__grid--single {
    grid-template-columns: 1fr;
  }
}
