/* Authored component library styles */

/* 1. Hero */
.hero {
  position: relative;
  color: var(--color-white);
  overflow: hidden;
}
.hero--simple {
  background: var(--bg-navy-band);
}
.hero--photo {
  background: var(--color-navy);
  min-height: 420px;
  display: flex;
  align-items: flex-end;
}
.hero__media {
  position: absolute;
  inset: 0;
  z-index: 0;
}
.hero__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
/* Navy scrim over the hero photo. This only ties the image to the palette
   and softens it — it is NOT what makes the text readable; .hero__panel
   below is. Measured contrast lives there. */
.hero__overlay {
  position: absolute;
  inset: 0;
  z-index: 1;
  background: var(--hero-scrim);
}
.hero__inner {
  position: relative;
  z-index: 2;
  padding: var(--space-8) var(--space-4);
  max-width: var(--container-max-width);
  margin: 0 auto;
  width: 100%;
}
.hero--simple .hero__inner {
  padding: var(--space-7) var(--space-4);
}
/* The plate that guarantees hero text contrast. 0.92 alpha over navy keeps
   the background below 0.041 luminance even where the photo is at its
   brightest, which is what the rust accent line needs for 3:1. Do not lower
   it without re-measuring both the heading and the accent line. */
.hero__panel {
  display: inline-block;
  max-width: 100%;
  background: rgba(9, 22, 53, 0.92);
  border-left: 4px solid var(--color-rust-bright);
  border-radius: 0 var(--radius-md) var(--radius-md) 0;
  padding: var(--space-5) var(--space-6) var(--space-6);
}
.hero h1, .hero h2 {
  color: var(--color-white);
}
/* The mockup sets the photo hero in caps. Done here rather than in the
   authored text so the heading stays sentence-case for screen readers and
   for the document title. */
.hero--photo h1 {
  text-transform: uppercase;
  letter-spacing: 0.01em;
}
.hero__subheading {
  font-size: var(--text-body-size);
  max-width: 46ch;
}
/* On the photo hero the subheading is the mockup's rust display line
   ("Voices in Harmony") rather than body copy. --color-rust-bright is only
   safe here because it renders at 28px+ bold, where the AA bar is 3:1, AND
   because .hero__panel puts it on near-solid navy. Measured in-browser
   against the composited background, not against the token. Never reuse it
   at body size, and never without the panel behind it. */
.hero--photo .hero__subheading {
  color: var(--color-rust-bright);
  font-family: var(--font-heading);
  font-weight: 700;
  font-size: var(--text-hero-size-mobile);
  line-height: var(--text-hero-line-mobile);
  text-transform: uppercase;
  letter-spacing: 0.01em;
  max-width: none;
  margin-top: calc(var(--space-1) * -1);
}
@media (min-width: 960px) {
  .hero--photo .hero__subheading {
    font-size: var(--text-hero-size);
    line-height: var(--text-hero-line);
  }
}
.hero__cta { margin-top: var(--space-5); }
/* Below 600px the panel is nearly as wide as the viewport, so laying it over
   the photo leaves only slivers of image visible. Stack instead: the photo
   gets its own band and the panel sits under it on the section's own navy.
   The panel keeps its background, so the measured text contrast is unchanged
   — the photo just stops paying for it. */
@media (max-width: 599px) {
  .hero--photo {
    display: block;
    min-height: 0;
  }
  .hero--photo .hero__media {
    position: relative;
    inset: auto;
    aspect-ratio: 4 / 3;
  }
  /* Stacked, the scrim belongs to the image band rather than the section. */
  .hero--photo .hero__overlay { display: none; }
  .hero--photo .hero__media::after {
    content: "";
    position: absolute;
    inset: 0;
    background: var(--hero-scrim);
  }
  .hero--photo .hero__inner {
    padding: var(--space-5) var(--space-4) var(--space-7);
  }
  .hero--photo .hero__panel {
    display: block;
    border-radius: 0 var(--radius-md) var(--radius-md) 0;
  }
}
@media (min-width: 960px) {
  .hero__inner { padding: var(--space-9) var(--space-6); }
  .hero--simple .hero__inner { padding: var(--space-8) var(--space-6); }
}

/* 1b. Authored body copy. Every `body` field goes through js/text-parser.js,
   which emits paragraphs, lists, quotes, dividers and inline links from a
   small Markdown subset — so these four containers need the same treatment.
   (No heading rules: the parser deliberately never emits one.) */
:is(.text-block__body, .image-text__content, .news-item__body, .article__body) :is(ul, ol) {
  margin: 0 0 var(--space-4);
}
:is(.text-block__body, .image-text__content, .news-item__body, .article__body) blockquote {
  margin: 0 0 var(--space-4);
  padding-left: var(--space-4);
  border-left: 3px solid var(--color-slate);
  color: var(--color-text-muted);
  font-style: italic;
}
/* News cards run tighter than the page-width bodies — match their own
   paragraph rhythm (.news-item__body p above). */
.news-item__body :is(ul, ol, blockquote) { margin-bottom: var(--space-3); }
:is(.text-block__body, .image-text__content, .news-item__body, .article__body) hr {
  border: 0;
  border-top: 1px solid var(--color-border);
  margin: var(--space-5) 0;
}
/* Links inherit the surrounding text colour and lean on the underline, the
   same affordance "Read more" already uses; .btn is the Image+Text call to
   action, which sits in the same container but is not body copy. */
:is(.text-block__body, .image-text__content, .news-item__body, .article__body) a:not(.btn) {
  text-decoration: underline;
  text-underline-offset: 0.15em;
}
:is(.text-block__body, .image-text__content, .news-item__body, .article__body) a:not(.btn):hover {
  color: var(--color-rust);
}

/* 2. Text Block */
.text-block {
  padding: var(--space-7) 0;
}
.text-block--highlight .text-block__panel {
  background: var(--color-slate-pale);
  border-radius: var(--radius-md);
  padding: var(--space-5);
}
.text-block__body p { margin: 0 0 var(--space-4); }
.text-block__body p:last-child { margin-bottom: 0; }
.text-block__body ul { margin: 0 0 var(--space-4); }

/* 3. Featured Videos (YouTube) — the slate band from the mockup. Cards are
   plain links to youtube.com; no iframe is embedded, which keeps the page
   light on mobile networks and avoids third-party cookies before consent. */
.video-grid {
  padding: var(--space-8) 0;
  background-color: var(--color-slate);
}
/* h1 as well as h2: on a page with no hero, renderer.js promotes the first
   section heading to <h1>, and a rule pinned to h2 would stop applying. */
.video-grid :is(h1, h2) {
  text-align: center;
  margin-bottom: var(--space-6);
}
.video-grid__grid {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--space-4);
}
@media (min-width: 960px) {
  .video-grid__grid { grid-template-columns: repeat(4, 1fr); gap: var(--space-5); }
}
.video-card {
  background: var(--color-white);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-card);
  overflow: hidden;
}
.video-card__link {
  display: flex;
  flex-direction: column;
  height: 100%;
  text-decoration: none;
  color: var(--color-text);
}
/* These are <span>s inside the card's single <a> (an anchor may not contain
   block elements here without splitting the link), so each one has to be
   given a box explicitly — aspect-ratio is ignored on inline boxes. */
.video-card__thumb {
  display: block;
  position: relative;
  aspect-ratio: 16 / 9;
  background: var(--color-navy);
}
.video-card__thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
/* Play badge — decorative; the link text carries the accessible name. */
.video-card__play {
  position: absolute;
  inset: 0;
  margin: auto;
  width: 48px;
  height: 34px;
  border-radius: var(--radius-sm);
  background: var(--color-rust);
  display: flex;
  align-items: center;
  justify-content: center;
}
.video-card__play::after {
  content: "";
  border-style: solid;
  border-width: 7px 0 7px 12px;
  border-color: transparent transparent transparent var(--color-white);
}
.video-card__body {
  padding: var(--space-3);
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  flex: 1;
}
.video-card__title {
  display: block;
  font-weight: 700;
  font-size: var(--text-small-size);
  line-height: var(--text-small-line);
  margin: 0;
}
.video-card__date {
  display: block;
  color: var(--color-text-muted);
  font-size: var(--text-label-size);
}
.video-grid__more {
  margin: var(--space-6) 0 0;
  text-align: center;
}

/* 4. Upcoming Events — navy date cards. Horizontal scroll-snap strip on
   mobile (matching the mockup), wrapping grid from tablet up. */
.event-list { padding: var(--space-8) 0; background: var(--color-cream); }
.event-list :is(h1, h2) { text-align: center; margin-bottom: var(--space-6); }
.event-list__strip {
  list-style: none;
  margin: 0;
  padding: 0 0 var(--space-3);
  display: flex;
  gap: var(--space-4);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  -webkit-overflow-scrolling: touch;
}
.event-list__strip > li {
  scroll-snap-align: start;
  flex: 0 0 78%;
}
@media (min-width: 600px) {
  .event-list__strip {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    overflow: visible;
  }
  .event-list__strip > li { flex: initial; }
}
.event-card {
  background: var(--color-navy);
  color: var(--color-white);
  border-radius: var(--radius-md);
  padding: var(--space-4);
  height: 100%;
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}
.event-card__date {
  font-weight: 700;
  font-size: var(--text-h3-size);
  line-height: 1.1;
  text-transform: uppercase;
  letter-spacing: 0.02em;
}
/* base.css colours every h1-h4 navy, which would be invisible on the navy
   card — inherit the card's white instead. */
.event-card__title {
  color: inherit;
  font-weight: 700;
  margin: var(--space-2) 0 0;
}
.event-card__meta { font-size: var(--text-small-size); opacity: 0.92; }
.event-card__desc {
  font-size: var(--text-small-size);
  margin: var(--space-2) 0 0;
}
.event-card__link {
  margin-top: auto;
  padding-top: var(--space-3);
  font-weight: 700;
  color: var(--color-white);
}
.event-list__empty { text-align: center; color: var(--color-text-muted); }

/* 5. Choir News — the v1 newsfeed. */
.news-list { padding: var(--space-8) 0; background: var(--color-slate-pale); }
.news-list :is(h1, h2) { text-align: center; margin-bottom: var(--space-6); }
.news-list__items {
  list-style: none;
  margin: 0 auto;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  max-width: 760px;
}
.news-item {
  background: var(--color-white);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-card);
  padding: var(--space-5);
}
.news-item__date {
  color: var(--color-text-muted);
  font-size: var(--text-label-size);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.news-item__title { margin: var(--space-1) 0 var(--space-3); }
.news-item__body p { margin: 0 0 var(--space-3); }
.news-item__body p:last-child { margin-bottom: 0; }
/* A card with an image stacks it on top on small screens and splits
   image-left / text-right from 600px up — the list caps at 760px, so the
   site-wide 960px break would leave tablets stacked. */
.news-item--with-image {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-4);
}
.news-item__media img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: var(--radius-sm);
}
@media (min-width: 600px) {
  .news-item--with-image {
    grid-template-columns: 2fr 3fr;
    gap: var(--space-5);
    align-items: start;
  }
}
.news-list__empty { text-align: center; color: var(--color-text-muted); }

/* 5b. A single news article at /news/{slug} — not an authored component, so
   it is laid out by js/article.js rather than by a renderer. */
.article { padding: var(--space-8) 0; }
.article__inner { max-width: 760px; }
.article__date {
  color: var(--color-text-muted);
  font-size: var(--text-label-size);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.article__title { margin: var(--space-1) 0 var(--space-5); }
.article__figure { margin: 0 0 var(--space-5); }
.article__figure img {
  width: 100%;
  height: auto;
  border-radius: var(--radius-md);
}
.article__body p { margin: 0 0 var(--space-4); }
.article__body p:last-child { margin-bottom: 0; }
.article__back { margin-top: var(--space-6); }

/* 6. Image + Text */
.image-text { padding: var(--space-7) 0; }
.image-text__grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-5);
  align-items: center;
}
.image-text__media img {
  border-radius: var(--radius-md);
  width: 100%;
  height: auto;
}
@media (min-width: 960px) {
  .image-text__grid { grid-template-columns: 1fr 1fr; gap: var(--space-7); }
  .image-text--image-right .image-text__media { order: 2; }
  .image-text--image-right .image-text__content { order: 1; }
}

/* 7. CTA / Link Band */
.cta-band { padding: var(--space-7) 0; text-align: center; }
.cta-band--dark {
  background: var(--bg-navy-band);
  color: var(--color-white);
}
.cta-band--dark :is(h1, h2) { color: var(--color-white); }
.cta-band--light {
  background: var(--color-slate-pale);
  color: var(--color-text);
}
.cta-band__body { max-width: 60ch; margin: 0 auto var(--space-5); }
.cta-band__buttons {
  display: flex;
  gap: var(--space-3);
  justify-content: center;
  flex-wrap: wrap;
}

/* 8. Application Form Embed */
.form-embed { padding: var(--space-7) 0; }
.form-embed__intro { max-width: 60ch; }

/* 9. Contact Band */
.contact-band { padding: var(--space-7) 0; text-align: center; }
.contact-band--dark {
  background: var(--color-navy);
  color: var(--color-white);
}
.contact-band--dark :is(h1, h2) { color: var(--color-white); }
.contact-band--light {
  background: var(--color-white);
  color: var(--color-text);
}
.contact-band__body { max-width: 60ch; margin: 0 auto var(--space-5); }
.contact-band__row {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-5);
  flex-wrap: wrap;
  margin-bottom: var(--space-5);
}
.contact-band__email {
  font-weight: 700;
  text-decoration: underline;
}
.contact-band--dark .social-links__link {
  background: rgba(255, 255, 255, 0.12);
  color: var(--color-white);
}
.contact-band--light .social-links__link {
  background: var(--color-slate-pale);
  color: var(--color-text);
}
.contact-band .social-links {
  justify-content: center;
}
