/* Quire of Voyces — flat-file site styles
   Rebuilt against the real inlined Divi CSS pulled from the site export
   (et-critical-inline-css / divi-style-inline-inline-css /
   divi-dynamic-critical-inline-css, per page). Confirmed there:
   - Background is #edd8a6 (cream/parchment) on every page — confirmed
     live on quireofvoyces.org, where #main-content/.et_pb_section render
     as transparent so the body's cream color shows through site-wide.
   - header (#main-header) background: #870021
   - current/active nav item + link accent: #2ea3f2
   - default heading color #333, font-weight 500 (not brand-colored/900)
   - body base: font-size 14px, line-height 1.7em, color #000 (customizer
     override), font Lato (100/300/400/700/900 + italics)
   - buttons are "ghost" style: transparent bg, colored border+text,
     border-radius 3px, font-weight 500
   - nav links are not uppercase
*/

/* 'Leo' is the site's real decorative display font — a custom font the
   original uploaded via the "Use Any Font" WP plugin (not a Google Font),
   recovered from wp-content/uploads/useanyfont/ in the site export. Used
   site-wide for every page's big maroon title ("ABOUT THE QUIRE",
   "Support us", "REPERTOIRE by CONCERT", etc. — all 36pt / color #800000). */
@font-face {
  font-family: 'Leo';
  src: url('/assets/fonts/leo.woff') format('woff');
  font-display: swap;
}

:root {
  --header-bg: #870021;
  --home-bg: #edd8a6;
  --accent: #2ea3f2;
  --link: #0049f4;
  --text: #000000;
  --heading: #333333;
  --title: #800000;
  --text-muted: #666666;
  --footer-bg: #222222;
  --footer-bg-dark: #1f1f1f;
  --footer-text: #cfd6cb;
  --border: #e5e5e5;
  --font: 'Lato', Helvetica, Arial, Lucida, sans-serif;
  --font-display: 'Leo', 'Lato', Helvetica, Arial, Lucida, sans-serif;
}

* { box-sizing: border-box; }

html { scroll-behavior: smooth; }

/* Sticky footer: on short pages (few paragraphs, no long list of CDs,
   etc.) the footer used to sit right under the content wherever that
   happened to end, which on a tall viewport left a gap of the page's
   background color below it instead of the footer sitting flush with
   the bottom of the browser window. body becomes a full-viewport-height
   flex column of header/main/footer; main gets flex:1 so it (not the
   footer) absorbs any leftover space on short pages, while on tall pages
   main just grows past 100vh naturally and pushes the footer down below
   it in normal document flow, exactly like before. */
html, body { height: 100%; }
body {
  margin: 0;
  font-family: var(--font);
  font-weight: 400;
  font-size: 16px;
  color: var(--text);
  background: var(--home-bg);
  line-height: 1.7;
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}
.site-header { flex-shrink: 0; }
main.page { flex: 1 0 auto; }
.site-footer { flex-shrink: 0; }

/* Only the home page gets the cream/parchment background, matching the
   one `.et_pb_section{background-color:#edd8a6 !important}` override
   found on the homepage export — and confirmed live on quireofvoyces.org
   that #main-content/.et_pb_section are transparent site-wide, so #edd8a6
   is the real background on every page, not a homepage-only accent. Set
   as the default `body` background above; no per-page override needed. */

a { color: var(--link); text-decoration: none; }
a:hover { text-decoration: underline; }

h1, h2, h3, h4, h5, h6 {
  color: var(--heading);
  font-weight: 500;
  line-height: 1.2em;
}

/* ---- Public site header / nav ---- */

.site-header {
  background: var(--header-bg);
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.75rem 2rem;
  flex-wrap: wrap;
  position: sticky;
  top: 0;
  z-index: 100;
  box-shadow: 0 1px 0 rgba(0,0,0,0.1);
}

.site-header .brand {
  display: flex;
  align-items: center;
  color: #fff;
  text-decoration: none;
}

.site-header .brand:hover { text-decoration: none; }

.site-header .brand img {
  height: 44px;
  width: auto;
  display: block;
}

.mobile-menu-toggle {
  display: none;
  background: none;
  border: none;
  color: #fff;
  font-size: 1.6rem;
  line-height: 1;
  cursor: pointer;
  padding: 0.25rem 0.5rem;
}

.main-nav ul {
  list-style: none;
  display: flex;
  gap: 1.6rem;
  margin: 0;
  padding: 0;
  flex-wrap: wrap;
}

.main-nav > ul > li {
  position: relative;
}

.main-nav a {
  color: #fff;
  text-decoration: none;
  font-size: 0.95rem;
  font-weight: 500;
  letter-spacing: 0.01em;
}

/* li.current applies at either level, so a submenu page highlights itself
   rather than leaving the accent on its parent. */
.main-nav a:hover,
.main-nav li.current > a {
  color: var(--accent);
}

/* The parent of the current page is highlighted too, but only on desktop —
   there the submenu is hidden until hover, so this is the only clue which
   section you're in. On mobile the submenu is already open on screen, and
   colouring both the parent and the page would leave two items looking
   equally "current" with nothing to distinguish them. */
@media (min-width: 801px) {
  .main-nav li.current-section > a { color: var(--accent); }
}

.main-nav .submenu {
  visibility: hidden;
  opacity: 0;
  position: absolute;
  top: 100%;
  left: 0;
  background: var(--header-bg);
  padding: 0.5rem 0;
  min-width: 190px;
  flex-direction: column;
  z-index: 10;
  box-shadow: 0 6px 14px rgba(0,0,0,0.3);
  transition: opacity 0.25s ease-in-out;
}

.main-nav li:hover .submenu,
.main-nav li:focus-within .submenu {
  visibility: visible;
  opacity: 1;
}

.main-nav .submenu li { padding: 0.4rem 1.1rem; }
.main-nav .submenu a { font-weight: 400; }

@media (max-width: 900px) {
  .mobile-menu-toggle { display: block; }

  .main-nav {
    display: none;
    width: 100%;
    order: 3;
  }

  .main-nav.is-open { display: block; }

  .main-nav ul {
    flex-direction: column;
    gap: 0;
    padding: 0.5rem 0 1rem;
  }

  .main-nav > ul > li { width: 100%; }
  .main-nav a { display: block; padding: 0.6rem 0; }

  .main-nav .submenu {
    visibility: visible;
    opacity: 1;
    position: static;
    box-shadow: none;
    background: rgba(0,0,0,0.15);
    padding-left: 1rem;
  }
}

/* ---- Public page content ---- */

.page {
  padding: 0 0 3rem;
}

.page-inner {
  max-width: 900px;
  margin: 0 auto;
  padding: 3rem 1.5rem;
}

/* The home page has a wider two-column hero, so it gets more room. */
body.is-home .page-inner { max-width: 1200px; }

.home-hero {
  display: flex;
  gap: 2.5rem;
  align-items: flex-start;
  margin-bottom: 2rem;
}

.home-hero-side {
  /* Kept at the original column width so the quote text below still wraps
     the same way it always did — only the images themselves are shrunk
     (see below), not the column that constrains the quote's line length. */
  flex: 0 0 198px;
  align-self: flex-start;
  margin: 0;
  text-align: center;
}

.home-hero-side img {
  /* display:block removes the few px of baseline whitespace browsers add
     above/below inline images, which was throwing off the top alignment
     with the hero photo next to it. */
  display: block;
  width: 158px;
  max-width: 100%;
  height: auto;
  margin: 0 auto 1.25rem;
}

.home-hero-side .home-quote {
  font-family: var(--font-display);
  font-style: italic;
  color: var(--title);
  font-size: 1.05rem;
  line-height: 1.4;
}

/* Higher specificity than ".content figure" (which sets a 1.5rem top
   margin for regular in-page figures) — without this, that generic rule
   was winning and pushing the hero photo 24px lower than the sidebar,
   throwing off the top alignment despite align-self: flex-start here. */
.content .home-hero-photo { flex: 1; max-width: 90%; align-self: flex-start; margin: 0; min-width: 0; }
.content .home-hero-photo img { display: block; width: 100%; height: auto; }

@media (max-width: 800px) {
  .home-hero { flex-direction: column; align-items: center; }

  /* Stacked, the photo of the choir should follow straight on from the
     title — it's the thing worth seeing first — with the logo, badge and
     quote underneath it. The markup keeps the sidebar first because that's
     the desktop column order; `order` re-sequences them for the stacked
     layout without moving anything in the content, so the desktop layout
     is untouched. */
  .content .home-hero-photo {
    order: -1;
    align-self: center;
    max-width: 100%;
    margin-bottom: 1.5rem;
  }
  .content .home-hero-photo figcaption { text-align: center; }
  /* Once the layout has to stack, the logo and anniversary badge move
     side-by-side above the quote, both capped to the quote line's width
     instead of each stacking full-width like they do on desktop. The block
     itself is explicitly centered so it lines up with the centered title
     the same way the hero photo below it does. Width is 330px, not 300px —
     "The most elegant choral ensemble sound" needs ~311px on one line at
     this font, so 300px was just barely too narrow and wrapped it to two. */
  .home-hero-side {
    flex: none;
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    align-items: center;
    align-self: center;
    gap: 0.75rem;
    /* An explicit width (not just max-width) gives the two calc(50%...)
       image widths below a definite basis to resolve against — with only
       max-width set, this box sized to fit-content instead of the cap,
       which could make it narrower than intended and re-introduce wrapping. */
    width: 330px;
    max-width: 100%;
    margin: 0 auto;
  }
  .home-hero-side img {
    width: calc(50% - 0.375rem);
    margin: 0;
  }
  .home-hero-side .home-quote {
    flex: 0 0 100%;
    margin-top: 0.5rem;
  }
}

.promo-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 2rem;
  margin: 2rem 0;
  text-align: center;
}

.promo-grid h3 {
  font-family: var(--font-display);
  color: var(--title);
  font-weight: 400;
  font-size: 1.7rem;
  margin: 0 0 0.6rem;
}

.promo-grid p { padding-bottom: 0; }

@media (max-width: 800px) {
  .promo-grid { grid-template-columns: 1fr 1fr; }
}

@media (max-width: 500px) {
  .promo-grid { grid-template-columns: 1fr; }
}

.page h1 {
  font-family: var(--font-display);
  color: var(--title);
  font-weight: 400;
  font-size: 2.75rem;
  line-height: 1.15;
  text-align: center;
  margin: 0 0 1.25rem;
}

.content { color: var(--text); }
.content p { padding-bottom: 1em; margin: 0; }

.content img { max-width: 100%; height: auto; }

.content h2 { font-size: 1.6rem; margin: 1.6rem 0 0.8rem; }
.content h3 { font-size: 1.3rem; margin: 1.4rem 0 0.6rem; }

/* A page's own styled name/role line (used instead of the generic <h1>
   on pages like Nathan Kreitzer's bio) — name in the display font/red,
   role in smaller plain text, left-aligned like the original. Flex (not
   plain inline text) so the role wraps to its own line as a whole unit
   once it doesn't fit next to the name — plain inline spans would
   instead break mid-phrase ("Founder and Artistic" / "Director"), which
   reads worse than the whole tagline just dropping below the name. */
.content .person-title {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  row-gap: 0.2rem;
  column-gap: 0.4rem;
  text-align: left;
  margin: 0 0 1.5rem;
}
.content .person-title .person-name {
  font-family: var(--font-display);
  color: var(--title);
  font-size: 2.25rem;
  font-weight: 400;
}
.content .person-title .person-role {
  font-size: 1.1rem;
  color: var(--heading);
}

/* Singers page: the section heading and the SOPRANOS/ALTOS/etc. subheads
   use the same red display font as page titles in the original. */
.content h2.section-title {
  font-family: var(--font-display);
  color: var(--title);
  text-align: center;
  font-weight: 400;
  font-size: 2.75rem;
  line-height: 1.15;
  margin: 0 0 1.25rem;
}
/* Repertoire page: "Composer in Residence" and soloist credits both drop
   to their own line beneath the composer's name — the inline-block wrapper
   means the second line automatically starts flush with the first (left-
   aligned with the composer), no manual indent guessing needed. */
.rep-person {
  display: inline-block;
  text-align: left;
  vertical-align: top;
}
.rep-person em { font-style: italic; }

/* ---- Repertoire: original title / translation columns ----
   Built from " || " markers at render time (see qv_render_columns).
   A grid rather than a table: every line contributes two cells, so the
   two columns stay aligned row by row even when a title wraps onto a
   second line — which is exactly where a float or inline-block layout
   would drift out of step. */
.rep-columns {
  display: grid;
  grid-template-columns: 1fr 1fr;
  column-gap: 2.5rem;
  row-gap: 0.2rem;
  padding-bottom: 1em;
}
.rep-col { min-width: 0; }
/* The translation is a gloss on the original, not a second title of equal
   weight, so it's set quieter to keep the original the thing you read
   first. */
.rep-col-translation {
  font-style: italic;
  color: #5c5347;
}

@media (max-width: 620px) {
  /* Two columns of titles on a phone leaves both of them as a column of
     orphaned words, so the pair stacks instead: original, then its
     translation tucked underneath. */
  .rep-columns {
    grid-template-columns: 1fr;
    row-gap: 0;
  }
  .rep-col-translation {
    padding-left: 1.25rem;
    margin-bottom: 0.45rem;
  }
  /* Lines that never had a translation would otherwise leave a gap. */
  .rep-col-translation:empty { display: none; }
}

/* ---- Indented lines (editor "Indent" button) ----
   Written once here so the same rule styles the live page and the visual
   editor, which share this stylesheet — what you indent while editing is
   exactly what visitors see.

   The span form needs inline-block: a plain inline span ignores
   margin-left for line-positioning purposes, so the text wouldn't
   actually move. vertical-align keeps a wrapped indented line sitting on
   the same baseline as the rest of the paragraph. */
span.qv-indent {
  display: inline-block;
  vertical-align: top;
}
.qv-indent[data-indent="1"] { margin-left: 2rem; }
.qv-indent[data-indent="2"] { margin-left: 4rem; }
.qv-indent[data-indent="3"] { margin-left: 6rem; }
.qv-indent[data-indent="4"] { margin-left: 8rem; }

/* Deep indents eat most of a phone screen and leave a column of orphaned
   words, so the steps tighten up rather than being dropped altogether —
   the hierarchy still reads, it just costs less width. */
@media (max-width: 620px) {
  .qv-indent[data-indent="1"] { margin-left: 1rem; }
  .qv-indent[data-indent="2"] { margin-left: 2rem; }
  .qv-indent[data-indent="3"] { margin-left: 3rem; }
  .qv-indent[data-indent="4"] { margin-left: 4rem; }
}

/* Homepage: eyebrow sits tight above the title, and the title itself is
   larger than a standard page heading. (Selectors here are written to
   out-specificity ".content .eyebrow" / ".page h1" so they actually win.) */
/* Eyebrow bumped 25% bigger (1rem -> 1.25rem) with no gap to the title
   below it. (Earlier margin-only reductions — 0.075rem, then 0.0375rem —
   kept looking the same because the site-wide ".content p" rule adds
   padding-bottom: 1em to every paragraph, same trap hit on the support
   box and CD pages: that invisible 1em of padding was dwarfing whatever
   tiny margin was set, so the visible gap never actually shrank.
   Zeroing padding-bottom here removes it for real.) The title is sized
   so its own rendered width matches the eyebrow line's width exactly:
   measured both strings' advance widths directly from the Leo font file
   (no kerning table in this font, so a plain glyph-width sum matches
   what the browser renders) — "Santa Barbara City College Department of
   Music presents" is 11/3 times as wide as "Quire of Voyces" at the same
   font-size, so at the eyebrow's 1.25rem that ratio puts the title at
   1.25 * 11/3 = 55/12 ≈ 4.5833rem to land on the same width. Both sizes
   are desktop-only — small screens revert to the original, smaller
   1rem / 3.75rem below, since the enlarged sizes were too big once the
   layout stacks to one column. */
.content p.home-eyebrow { font-size: 1.25rem; margin: 0; padding-bottom: 0; }

/* The big title sets its own font size on inline spans (4.58rem), and
   line-height inherits as a ratio — so the line box became 1.7 × 73px and
   left a chasm between "Quire of" and "Voyces" when it wrapped. A ratio
   just over 1 keeps the two lines close without clipping the descenders
   on the "Q" and "y". */
.content p.home-title,
.content p.home-title span { line-height: 1.05; }
.content h1.home-title { font-size: 4.5833rem; margin-top: 0; }

@media (max-width: 800px) {
  /* The presenting line deliberately keeps its full 1.25rem on mobile.
     It used to drop to 1rem, which made the one piece of plain text on
     the page noticeably smaller exactly where it's hardest to read. It
     fits because the line is broken after "College" below, rather than
     being squeezed onto one line. */
  .content h1.home-title { font-size: 3.75rem; }

  /* Break the presenting line at a sensible place rather than wherever it
     happens to run out of room — "Santa Barbara City College" on one line,
     "Department of Music presents" on the next. Each half is its own span
     so the break is chosen, not left to chance; on wider screens they sit
     inline and the sentence reads as one line as before. */
  .content p.home-eyebrow .eyebrow-part { display: block; }
}

.singers-columns h3 {
  font-family: var(--font-display);
  color: var(--title);
  text-transform: uppercase;
  font-weight: 700;
}

.content .eyebrow {
  text-align: center;
  font-family: var(--font-display);
  color: var(--title);
  font-size: 1rem;
  font-weight: 400;
  margin: 0 0 0.4rem;
}

.content .hint { color: var(--text-muted); font-size: 0.9rem; font-style: italic; }

.content figure { margin: 1.5rem 0; }
.content figure img { display: block; }
.content figure figcaption { font-size: 0.85rem; color: var(--text-muted); margin-top: 0.4rem; }

/* WordPress-style float alignment classes — the original wraps body text
   around images this way (alignleft/alignright/aligncenter), rather than
   stacking a full-width image block above the text. Use these on <img> or
   <figure> so paragraphs after them flow alongside, not underneath. */
.content .align-left {
  float: left;
  margin: 0.3rem 1.5rem 1rem 0;
  max-width: 45%;
}

.content .align-right {
  float: right;
  margin: 0.3rem 0 1rem 1.5rem;
  max-width: 45%;
}

.content .align-center {
  display: block;
  margin: 1.5rem auto;
  max-width: 70%;
  float: none;
}

.content .align-left img,
.content .align-right img,
.content .align-center img {
  width: 100%;
  height: auto;
  display: block;
}

.content .align-left figcaption,
.content .align-right figcaption,
.content .align-center figcaption {
  font-size: 0.8rem;
  color: var(--text-muted);
  margin-top: 0.4rem;
  text-align: center;
}

/* Clears a float so the next heading/section starts on its own line
   instead of tucking in next to a tall floated image. */
.content .clear { clear: both; }

/* A small floated thumbnail followed by descriptive text, used for things
   like CD covers and small icons with a caption/blurb beside them. */
.content .thumb-left {
  float: left;
  margin: 0.2rem 1.25rem 1rem 0;
  width: 140px;
}

.content .thumb-left img { width: 100%; height: auto; display: block; }

/* Recordings page: CD cover art + title/description as a flex row instead
   of a float. A float only keeps text beside the image for as many lines
   as the image is tall — once a longer description (like the 2013
   Christmas album) runs past the bottom of the cover art, the remaining
   wrapped lines fall back to the container's full width, so they land
   flush with the true left edge while the earlier lines were indented
   past the image. That mismatched left edge is what "spills over to the
   left border" looked like. A flex row keeps the text column at a fixed
   left position for every line, and align-items:flex-start lines the top
   of the art up with the top of the title, regardless of how long the
   description runs. */
.content .cd-entry {
  display: flex;
  align-items: flex-start;
  gap: 1.25rem;
  margin: 0 0 1.75rem;
}
.content .cd-entry-art { flex: 0 0 140px; width: 140px; }
.content .cd-entry-art img { width: 100%; height: auto; display: block; }
.content .cd-entry-text { flex: 1; min-width: 0; }
.content .cd-entry-text h3 { margin-top: 0; }
.content .cd-entry-text p { margin-bottom: 0; }

@media (max-width: 600px) {
  .content .cd-entry { flex-direction: column; gap: 0.5rem; }
  .content .cd-entry-art { width: 140px; }
}

/* Christmas with the Quire of Voyces (2013): the description is long
   enough that lining the art up with the title (like every other entry)
   left it sitting oddly high above the bulk of the text. This variant
   puts the title on its own full-width line, with the art centered on
   the paragraph below it. (A flex-start top edge was tried first to line
   up the very top of the art with the very top of the text, but the
   paragraph's line-height adds leading space above the first line's
   glyphs that the image doesn't have, so the art's top edge ended up a
   few pixels above where the letters themselves start — centering
   sidesteps that mismatch entirely.)

   Grid (with named areas) instead of nested flex rows so the stacking
   order can differ by breakpoint: desktop wants title on top spanning
   both columns, with art+description as a row below it; mobile wants
   art on top, then title, then description — an order a flexbox couldn't
   give art/title/description independently since art and description
   are nested one level deeper than title. Grid areas let each of the
   three pieces be placed independently at each breakpoint. */
.content .cd-entry--split {
  display: grid;
  grid-template-columns: 140px 1fr;
  grid-template-areas: "title title" "art desc";
  align-items: center;
  column-gap: 1.25rem;
  row-gap: 0.5rem;
}
.content .cd-entry--split .cd-entry-title { grid-area: title; margin: 0; }
.content .cd-entry--split .cd-entry-art { grid-area: art; width: 140px; }
.content .cd-entry--split .cd-entry-art img { width: 100%; height: auto; display: block; }
.content .cd-entry--split .cd-entry-desc { grid-area: desc; min-width: 0; }
/* Same padding-bottom trap as the support box mail/phone fix: the
   site-wide .content p rule adds padding-bottom:1em below the visible
   text, so the desc box being centered (via align-items:center above)
   isn't the same as the visible text being centered — the invisible
   trailing padding pushed the text's true center above the box's
   center, which made the art (which has no such padding and just fills
   the row) look like it had drifted down to the text's bottom instead
   of its middle. Zeroing it here makes the box match the visible text. */
.content .cd-entry--split .cd-entry-desc p { margin: 0; padding-bottom: 0; }

@media (max-width: 600px) {
  .content .cd-entry--split {
    grid-template-columns: 1fr;
    grid-template-areas: "art" "title" "desc";
  }
  .content .cd-entry--split .cd-entry-art { width: 140px; }
}

/* Concerts page: photo floats to the left of each concert's date/venue
   details (single overall column, not a separate two-column row), sized
   noticeably smaller than a full-width figure. */
.content .concert-photo {
  float: left;
  margin: 0.2rem 1.5rem 1rem 0;
  width: 220px;
}

.content .concert-photo img { width: 100%; height: auto; display: block; }

/* Concerts/Tours: each entry (photo + heading + details) is a single
   wrapping element rather than a run of floated siblings terminated by a
   manually-placed .clear div. overflow:hidden is the clearfix — it
   contains the floated photo inside the entry's own box so the box's
   height wraps around it, and the next entry starts clear below with no
   separate clearing element needed. The bottom margin is what actually
   guarantees space between one entry and the next (rather than however
   much margin the next figure/heading happened to carry). */
.content .concert-entry,
.content .tour-entry {
  overflow: hidden;
  margin-bottom: 1.75rem;
}

/* Singers page: the real layout is a 1/4 - 1/2 - 1/4 row (names, photo,
   names), with the photo centered in the middle column. Grid guarantees
   consistent column widths; the left list sits closer to the photo than
   the right list (extra margin pushes the right list further out). */
.singers-columns {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  gap: 1.25rem;
  align-items: start;
  margin: 1.5rem 0;
}

.singers-columns .singers-list { min-width: 0; margin-top: 1.5rem; }
/* The left list's grid track is wide (1fr), but the real site floats this
   block against its column's right edge rather than stretching the text
   across the whole track — shrink it to content and hug the photo. */
.singers-columns .singers-list:first-of-type { justify-self: end; }
.singers-columns .singers-list:last-of-type { margin-left: 1.25rem; }
.singers-columns .singers-photo { text-align: center; }
.singers-columns .singers-photo img {
  width: 360px;
  max-width: 100%;
  height: auto;
  border-radius: 2px;
  animation: singers-photo-in 0.9s ease-out both;
}

.singers-columns h3 { margin-top: 0; }

/* Mimics the original page's on-load entrance animation for the group photo. */
@keyframes singers-photo-in {
  from { opacity: 0; transform: translateY(60px); }
  to { opacity: 1; transform: translateY(0); }
}

@media (max-width: 800px) {
  /* Below 800px there's no room for three side-by-side tracks (names,
     photo, names), but going all the way down to one full-width column
     buried the photo between two long name lists. Two columns of names
     — sopranos/tenors on the left, altos/baritones/basses on the right
     — with the photo spanning both underneath reads better and still
     fits width-wise. Named grid areas (not DOM order) put the photo
     last visually without having to move it in the actual markup.

     The two columns' left edges are pinned to line up with the "S" in
     "Singers" and the "S" in "Section" from the heading above, rather
     than an even 50/50 split — measured directly from the Leo font file
     at the heading's actual size (2.75rem = 44px): "Singers by Section"
     is ~350.3px wide there, and "Singers by " (everything up to the
     second S) is ~209.9px of that. Since the heading is centered, its
     own left edge sits at 50% - 175.2px from the shared container's
     left edge (.singers-columns and the <h2> are siblings with the same
     box width, so 50% means the same thing for both) — that's the width
     given to the empty first column below, so the boundary lands under
     that letter at any viewport width this media query applies to, not
     just one specific screen size. max() keeps it from going negative
     on the very narrowest phones. */
  .singers-columns {
    grid-template-columns: max(0px, calc(50% - 175.2px)) 209.9px 1fr;
    grid-template-areas: "spacer list1 list2" "photo photo photo";
    gap: 0;
  }
  .singers-columns .singers-list:first-of-type {
    grid-area: list1;
    justify-self: stretch;
    text-align: left;
  }
  .singers-columns .singers-list:last-of-type {
    grid-area: list2;
    justify-self: stretch;
    margin-left: 0;
    text-align: left;
  }
  .singers-columns .singers-photo { grid-area: photo; margin-top: 1.5rem; }
  .content .align-left,
  .content .align-right { float: none; max-width: 100%; margin: 0 auto 1rem; }
  .content .thumb-left { float: none; width: 160px; margin: 0 auto 1rem; }
  /* Left-aligned with the surrounding text, not centered — matches the
     text's left edge instead of floating in the middle of the column. */
  .content .concert-photo { float: none; width: 160px; margin: 0 0 1rem; }
}

/* Ghost-style buttons/links matching the original's .et_pb_button look */
.content a.button-link,
.btn {
  display: inline-block;
  border: 2px solid var(--accent);
  color: var(--accent) !important;
  background: transparent;
  padding: 0.5rem 1.4rem;
  border-radius: 3px;
  font-weight: 500;
  text-decoration: none !important;
}

.content a.button-link:hover, .btn:hover {
  background: var(--accent);
  color: #fff !important;
}

/* ---- Footer ---- */

.site-footer {
  background: var(--footer-bg);
  color: var(--footer-text);
}

.site-footer .footer-inner {
  max-width: 1080px;
  margin: 0 auto;
  padding: 2.5rem 1.5rem 1rem;
  text-align: center;
}

.site-footer a { color: #fff; }
.site-footer a:hover { color: rgba(255,255,255,0.7); }

.site-footer .footer-bottom {
  background: var(--footer-bg-dark);
  text-align: center;
  padding: 0.9rem 1.5rem;
  font-size: 0.85rem;
  color: #bbb;
}

.site-footer .footer-bottom a { color: #bbb; }

/* ---- Persistent background-music player ----
   Fixed to the bottom of the viewport, present on every public page (via
   includes/footer.php) so playback survives navigating around the site.
   See assets/js/player.js for how. */
.global-player {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 500;
  background: var(--header-bg);
  border-top: 3px solid var(--title);
  box-shadow: 0 -4px 14px rgba(0, 0, 0, 0.3);
}
.global-player[hidden] { display: none; }

.global-player-inner {
  max-width: 1080px;
  margin: 0 auto;
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.6rem 1.5rem;
}

/* In-place navigation (assets/js/nav.js) fades the outgoing content while
   the next page is being fetched. The delay on the transition means a
   fast swap — which is most of them, since these are small local pages —
   completes before any dimming becomes visible, so quick clicks don't
   flicker; only a genuinely slow response shows feedback. */
body.is-navigating main.page {
  opacity: 0.55;
  transition: opacity 0.15s ease 0.12s;
}
/* nav.js focuses <main> after a swap so screen readers announce the new
   page. That's a programmatic focus, not keyboard navigation, so it
   shouldn't paint a focus ring. */
main.page:focus { outline: none; }

/* Skip buttons. These hold an inline SVG chevron pair rather than a text
   glyph, so the sizing lives on the <svg> and the colour is inherited
   from the button via currentColor — one colour change on :hover then
   covers both. */
.global-player-nav-btn {
  background: none;
  border: none;
  color: #fff;
  cursor: pointer;
  padding: 0.4rem 0.3rem;
  flex-shrink: 0;
  opacity: 0.7;
  display: flex;
  align-items: center;
  transition: opacity 0.15s ease, color 0.15s ease;
}
.global-player-nav-btn svg {
  width: 15px;
  height: 15px;
  display: block;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.9;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.global-player-nav-btn:hover { opacity: 1; color: var(--accent); }
.global-player-nav-btn[hidden] { display: none; }

/* The scrolling title: the wrap clips to a fixed width and hides overflow;
   the title itself is the thing that gets nudged left/right via CSS
   animation, but only when JS (assets/js/player.js) has determined it's
   actually too long to fit and set --qv-scroll-distance/-duration and the
   is-scrolling class — a short title just sits still, no animation. */
.global-player-title-wrap {
  flex: 1 1 auto;
  min-width: 0;
  max-width: 260px;
  overflow: hidden;
  white-space: nowrap;
}
.global-player-title {
  display: inline-block;
  color: #fff;
  font-weight: 700;
  font-size: 0.9rem;
  white-space: nowrap;
}
.global-player-title.is-scrolling {
  animation-name: global-player-scroll;
  animation-timing-function: ease-in-out;
  animation-iteration-count: infinite;
  animation-duration: var(--qv-scroll-duration, 6s);
}
@keyframes global-player-scroll {
  0%, 15% { transform: translateX(0); }
  45%, 55% { transform: translateX(var(--qv-scroll-distance, 0)); }
  85%, 100% { transform: translateX(0); }
}

/* Width here is functional, not cosmetic. Browsers drop controls out of
   the native audio player when it gets narrow, and the scrub bar is the
   first thing to go — below roughly 300px Chrome shows only play/time and
   the timeline disappears entirely, so the track can't be seeked. Hence a
   hard 300px floor and a generous flex-basis: the audio element gets the
   lion's share of the bar and the title yields to it, rather than the
   other way round. */
.global-player-audio {
  flex: 1 1 360px;
  min-width: 300px;
  height: 36px;
}

/* Reserves space at the bottom of the page while the player bar is
   showing, so it never covers the real footer or page content. */
body.has-global-player { padding-bottom: 78px; }

/* Below this width there isn't room for the title and a 300px-wide audio
   element side by side, and shrinking the audio would cost the scrub bar.
   So the bar wraps to two rows instead: title and skip buttons on top,
   full-width audio underneath, which keeps seeking usable on phones. */
@media (max-width: 700px) {
  .global-player-inner {
    flex-wrap: wrap;
    justify-content: center;
    padding: 0.5rem 1rem;
    gap: 0.35rem 0.5rem;
  }
  .global-player-title-wrap {
    max-width: none;
    flex: 1 1 auto;
    text-align: center;
  }
  .global-player-audio {
    flex: 1 1 100%;
    min-width: 0;
    width: 100%;
  }
  body.has-global-player { padding-bottom: 108px; }
}

/* ---- Admin ---- */

body.admin {
  font-family: var(--font);
  background: #f2ede0;
  color: #222;
}

.admin-header {
  background: var(--header-bg);
  color: #fff;
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0.9rem 2rem;
}

.admin-header .brand { font-weight: 700; color: #fff; }
/* Set quieter than the name it follows: useful when you need it, not
   competing with the title the rest of the time. */
.admin-header .brand-version {
  font-weight: 400;
  font-size: 0.8rem;
  opacity: 0.7;
  margin-left: 0.15rem;
}

.admin-header nav a {
  color: #fff;
  text-decoration: none;
  margin-left: 1.2rem;
  font-size: 0.9rem;
}

.admin-header nav a:hover { color: var(--accent); }

.admin-main {
  max-width: 900px;
  margin: 0 auto;
  padding: 2rem 1.5rem 4rem;
}

.admin-main h1 { color: var(--header-bg); }

.admin-toolbar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 1.5rem;
}
/* Editor page: History link + Preview + Save Page, right above the
   formatting toolbar rather than up at the top of the page — this is
   the "top" that matters while you're actually editing. */
.editor-actions-bar {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  gap: 1rem;
  flex-wrap: wrap;
  margin-bottom: 0.5rem;
}
.editor-actions-bar button { font-size: 0.85rem; padding: 0.4rem 0.9rem; }
/* Bottom Cancel link, to the right of the second Save Page button at the
   very end of the form — a plain text link (not a filled button) so it
   doesn't compete with Save as the primary action, just like its twin
   up in .editor-actions-bar. */
.editor-bottom-cancel { margin-left: 1rem; font-size: 0.9rem; }
/* Preview buttons are green everywhere they appear (here and on the
   History screen) — a distinct color from Save/Delete/Show changes so
   it reads as the safe, look-don't-touch action. */
#editor-preview-btn { background: #1c6b3a; }
#editor-preview-btn:hover { background: #17572f; }
/* History page only: "Back to editor" reads as a breadcrumb, not an
   action. On screens wide enough to have margin to spare, it's
   absolutely positioned into that margin — sitting to the left of the
   title, bottom-aligned with its text — so the title itself stays put
   at the toolbar's left edge (flush with the version boxes below it)
   instead of being pushed rightward by the link sharing its row. On
   narrower screens there's no margin to float it into, so it drops
   below the title in normal flow instead. */
.admin-toolbar--history {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.4rem;
}
.admin-toolbar--history h1 { margin: 0; order: 1; }
.admin-toolbar--history > a { order: 2; }

@media (min-width: 1100px) {
  .admin-toolbar--history {
    display: block;
    position: relative;
  }
  .admin-toolbar--history > a {
    position: absolute;
    right: 100%;
    bottom: 0;
    margin-right: 1rem;
    white-space: nowrap;
  }
}

.admin-table {
  width: 100%;
  border-collapse: collapse;
  background: #fff;
  box-shadow: 0 1px 3px rgba(0,0,0,0.08);
}

.admin-table th, .admin-table td {
  text-align: left;
  padding: 0.7rem 1rem;
  border-bottom: 1px solid var(--border);
  font-size: 0.92rem;
}

.admin-table th {
  background: #f0e6c8;
}

.row-actions form.inline-form { display: inline; }

.button, button, input[type="submit"] {
  background: var(--header-bg);
  color: #fff;
  border: none;
  padding: 0.55rem 1.1rem;
  border-radius: 4px;
  font-size: 0.95rem;
  font-family: var(--font);
  font-weight: 700;
  cursor: pointer;
  text-decoration: none;
  display: inline-block;
}

.button:hover, button:hover { background: #6b0019; text-decoration: none; }

.link-button {
  background: none;
  border: none;
  padding: 0;
  color: var(--link);
  text-decoration: underline;
  cursor: pointer;
  font-size: 0.92rem;
}

.link-button.danger { color: #b3261e; }

.admin-login {
  width: 300px;
  margin: 4rem auto;
  background: #fff;
  padding: 2rem;
  border-radius: 6px;
  box-shadow: 0 2px 8px rgba(0,0,0,0.15);
}

.page-form label, .admin-login label {
  display: block;
  margin-bottom: 1rem;
  font-size: 0.92rem;
  font-weight: 700;
}

.page-form label.checkbox {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-weight: normal;
}

.page-form input[type="text"],
.page-form input[type="password"],
.page-form select,
.page-form textarea,
.admin-login input {
  width: 100%;
  padding: 0.5rem;
  font-weight: normal;
  border: 1px solid var(--border);
  border-radius: 4px;
  font-family: inherit;
  margin-top: 0.3rem;
}

.page-form textarea { font-family: Consolas, Monaco, monospace; font-size: 0.85rem; }

.hint { font-weight: normal; color: var(--text-muted); font-size: 0.85rem; }

/* Backups page: raw output from backup.sh (either just-run, or the tail
   of its log file) — a plain monospace scroll box, not styled up as
   anything fancier, since it's diagnostic text meant to be read literally
   if something went wrong (e.g. "rclone: command not found"). */
.backup-log {
  background: #1e1e1e;
  color: #d8d8d8;
  font-family: Consolas, Monaco, monospace;
  font-size: 0.8rem;
  line-height: 1.5;
  padding: 1rem;
  border-radius: 4px;
  overflow-x: auto;
  max-height: 320px;
  overflow-y: auto;
  white-space: pre-wrap;
  word-break: break-word;
}

/* ---- Page content editor (visual / HTML source toggle) ---- */

.editor-toolbar {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem;
  align-items: center;
  background: #f0e6c8;
  border: 1px solid var(--border);
  border-bottom: none;
  border-radius: 4px 4px 0 0;
  padding: 0.4rem;
}

.editor-toolbar button {
  background: #fff;
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 3px;
  font-weight: 400;
  font-size: 0.85rem;
  padding: 0.3rem 0.55rem;
  line-height: 1;
  cursor: pointer;
}

.editor-toolbar button:hover { background: #fff2d6; }

.editor-toolbar button.is-active {
  background: var(--header-bg);
  color: #fff;
  border-color: var(--header-bg);
}

.editor-toolbar .toolbar-sep {
  width: 1px;
  align-self: stretch;
  background: var(--border);
  margin: 0 0.15rem;
}

.editor-toolbar select {
  /* .page-form select elsewhere in this file forces width:100% for the
     title/nav-label inputs — same specificity, so this only wins because
     it's declared later. Without it the dropdown would stretch to fill
     the whole toolbar row instead of sitting sized to its own options. */
  width: max-content;
  margin-top: 0;
  background: #fff;
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 3px;
  font-family: var(--font);
  font-weight: 400;
  font-size: 0.85rem;
  padding: 0.3rem 1.1rem 0.3rem 0.35rem;
  line-height: 1;
  cursor: pointer;
}
.editor-toolbar select:hover { background: #fff2d6; }

.editor-toolbar .toolbar-push { margin-left: auto; }

.wysiwyg-editor {
  border: 1px solid var(--border);
  border-radius: 0 0 4px 4px;
  padding: 1rem 1.25rem;
  min-height: 300px;
  background: #fff;
  font-weight: normal;
}

.wysiwyg-editor:focus { outline: 2px solid var(--accent); outline-offset: -2px; }

/* Images are natively draggable and a contenteditable region natively
   accepts drops, so dragging one to a new spot in the text already
   works with no JS — this cursor is just the visual hint that it will. */
.wysiwyg-editor img:hover { cursor: move; }
.wysiwyg-editor img.qv-img-selected { outline: 2px solid var(--accent); outline-offset: 2px; }

/* Editing aids only (never shown on the public site, since these are all
   scoped under .wysiwyg-editor rather than plain .content). Two levels:
   an outline around each whole entry — the "horizontal cell" of photo +
   text that Concerts/Tours/Recordings each repeat — and, inside the
   Recordings entry specifically, a second outline marking where the art
   column ends and the text column begins. Outline (not border) so
   neither one adds to the box's size or shifts anything. */
.wysiwyg-editor .concert-entry,
.wysiwyg-editor .tour-entry,
.wysiwyg-editor .cd-entry {
  outline: 1px dashed var(--accent, #8a6d3b);
  outline-offset: 6px;
}
.wysiwyg-editor .cd-entry-art,
.wysiwyg-editor .cd-entry-text,
.wysiwyg-editor .cd-entry--split .cd-entry-art,
.wysiwyg-editor .cd-entry--split .cd-entry-desc {
  outline: 1px dashed var(--accent, #8a6d3b);
  outline-offset: 4px;
}

/* A permanent "add a new entry" slot pinned to the top of the entries
   list on Concerts/Tours/Recordings while editing — inserted by JS, and
   stripped back out before the content is ever saved/previewed/switched
   to HTML view, so it never becomes real page markup. Sized and dashed
   like the entries below it so it visibly reads as an empty version of
   the same "cell", with a plus sign standing in for a photo+text entry
   that hasn't been added yet. */
.qv-add-entry-placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.6rem;
  min-height: 90px;
  margin-bottom: 1.75rem;
  border: 2px dashed var(--accent, #8a6d3b);
  border-radius: 6px;
  background: #fdf8ee;
  color: var(--accent, #8a6d3b);
  font-weight: 700;
  font-family: var(--font);
  cursor: pointer;
  user-select: none;
}
.qv-add-entry-placeholder:hover { background: #f7ecd2; }
.qv-add-entry-plus { font-size: 1.8rem; line-height: 1; }

/* Floating controls for a selected image — positioned in fixed/absolute
   coordinates tracking the image's on-screen box (via JS), not inside
   the editable content itself, so they never end up saved as part of
   the page. */
.img-toolbar {
  display: none;
  position: absolute;
  z-index: 500;
  align-items: center;
  gap: 0.3rem;
  background: #222;
  border-radius: 4px;
  padding: 0.3rem;
  box-shadow: 0 2px 8px rgba(0,0,0,0.3);
}
.img-toolbar button {
  background: #444;
  color: #fff;
  border: none;
  border-radius: 3px;
  padding: 0.25rem 0.55rem;
  font-size: 0.75rem;
  font-family: var(--font);
  font-weight: 400;
  cursor: pointer;
}
.img-toolbar button:hover { background: #666; }
.img-toolbar-sep { width: 1px; align-self: stretch; background: #555; margin: 0 0.1rem; }

.img-resize-handle {
  display: none;
  position: absolute;
  z-index: 500;
  width: 14px;
  height: 14px;
  background: var(--accent);
  border: 2px solid #fff;
  border-radius: 50%;
  box-shadow: 0 1px 3px rgba(0,0,0,0.4);
  cursor: nwse-resize;
}

.editor-source-wrap textarea {
  border-radius: 0 0 4px 4px !important;
  min-height: 300px;
}

.editor-hint {
  font-weight: normal;
  color: var(--text-muted);
  font-size: 0.85rem;
  margin: 0.3rem 0 0.5rem;
}

/* Page history: one card per version — the live page included, not just
   past ones. The version number, badged "Current"/"Oldest" where
   applicable, is followed right on the same line by the plain-text
   timestamp/author (not a link — see .history-version-meta); directly
   below the timestamp, left-aligned with where it starts, sit "Preview"
   (opens a real render of that version in a popup window, which has its
   own "Revert to this version" button for archived versions, so there's
   no separate revert control on the card), "Show changes" (diffs
   against the previous non-deleted version, omitted where there isn't
   one), and "Delete this version" — all on one row. */
.history-list { display: flex; flex-direction: column; gap: 1.25rem; margin-top: 1rem; }
.history-entry {
  background: #fff;
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 1rem 1.25rem;
}
/* Two columns: 1=the "Version N — " prefix (just wide enough for its own
   text), 2=everything that needs to line up with where the timestamp
   starts (the timestamp itself, and the actions row below it). Only the
   prefix and the timestamp get explicit row/column placement; the
   actions row and the reverted-from note are left with NO explicit
   grid-row on purpose — column 2 is already occupied through row 1, so
   the grid's normal auto-placement search lands each of them, in DOM
   order, on the next free row in that same column, which is what keeps
   them flush with the timestamp's left edge without hand-counting rows. */
.history-card-grid {
  display: grid;
  grid-template-columns: auto 1fr;
  align-items: baseline;
  column-gap: 0;
  row-gap: 0.6rem;
}
.history-version-prefix {
  grid-row: 1;
  grid-column: 1;
  font-size: 1rem;
  font-weight: 700;
  color: var(--text-muted);
  white-space: nowrap;
}
.history-version-sep { margin-left: 0.3rem; }
/* The timestamp/author text used to be a clickable link that opened the
   preview; now that "Preview" is its own button, this is plain text. */
.history-version-meta { grid-row: 1; grid-column: 2; font-size: 0.9rem; justify-self: start; }
/* The actions row starts flush with "Version N" (column 1 of the outer
   grid), not with the timestamp above it — hence spanning both columns
   rather than sitting in column 2 like .history-version-meta does.
   It's its own grid (not flex) with a fixed-width slot for "Show
   changes" specifically so "Delete this version" lands in the same
   horizontal spot whether or not this card has a Show changes button —
   a flex row would instead let Delete slide left to fill that gap.
   Revert sits in its own column too, immediately after Preview (both
   real buttons on the "what does this version look like" side of the
   row), rather than inside .history-preview-btn's column, so it lines
   up the same way across every card regardless of Preview's own width. */
.history-version-actions {
  grid-column: 1 / -1;
  justify-self: start;
  display: grid;
  grid-template-columns: auto auto 9.5rem auto;
  align-items: center;
  column-gap: 1rem;
}
.history-preview-btn { grid-column: 1; }
/* display:contents on the <form> wrappers takes the form's own box out
   of the layout entirely, so its <button> becomes the actual grid item —
   the same as .history-preview-btn and .history-diff-toggle, which are
   bare <button>s with no wrapping element. Without this, the form (a
   plain block box around one button) was the thing being centered by
   align-items:center, and its box wasn't guaranteed to match the
   buttons' box pixel-for-pixel, which is what left Revert looking a
   pixel or two off from Preview/Show changes despite identical padding.
   grid-column/justify-self move down onto the button itself, since the
   form no longer generates a box to hold them. */
.history-revert-form,
.history-delete-form { display: contents; }
.history-revert-form button { grid-column: 2; justify-self: start; }
.history-diff-toggle { grid-column: 3; justify-self: start; }
.history-delete-form button { grid-column: 4; justify-self: start; }
.history-reverted-note { grid-column: 1 / -1; justify-self: start; font-size: 0.8rem; font-style: italic; color: var(--text-muted); }
/* Preview, Revert, and Show changes are real, differently-colored
   buttons — Preview green (it's the safe, look-don't-touch action),
   Revert the site's primary maroon (it's a real action, just a reversible
   one — reverting archives the current content first), Show changes in
   the accent gold. Delete rides along in the same row as a plain link
   instead (it's the one truly irreversible action here), vertically
   centered against the buttons' text via align-items:center on
   .history-version-actions above. */
.history-preview-btn,
.history-revert-form button,
.history-diff-toggle {
  border: none;
  border-radius: 4px;
  padding: 0.3rem 0.75rem;
  font-size: 0.8rem;
  font-weight: 700;
  font-family: inherit;
  color: #fff;
  cursor: pointer;
}
.history-preview-btn { background: #1c6b3a; }
.history-revert-form button { background: var(--header-bg); }
.history-diff-toggle { background: var(--accent, #8a6d3b); }
.history-preview-btn:hover,
.history-diff-toggle:hover { opacity: 0.85; }
.history-revert-form button:hover { background: #6b0019; }

.history-badge {
  font-size: 0.7rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: #fff;
  background: var(--accent, #8a6d3b);
  border-radius: 3px;
  padding: 0.05rem 0.4rem;
  margin-left: 0.3rem;
  vertical-align: middle;
}
.history-deleted-tag { font-size: 0.85rem; font-weight: 400; font-style: italic; color: var(--text-muted); margin-left: 0.3rem; }

@media (max-width: 640px) {
  .history-card-grid { grid-template-columns: 1fr; }
  .history-version-prefix,
  .history-version-meta,
  .history-version-actions,
  .history-reverted-note { grid-row: auto; grid-column: 1; justify-self: start; }
  .history-version-meta { display: block; margin-top: 0.15rem; }
}

/* Small popup window for previewing an archived (or current) version of
   a page rendered through the real template/stylesheet, opened from the
   "Preview" button above. */
.history-modal-overlay {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.5);
  align-items: center;
  justify-content: center;
  z-index: 1000;
  padding: 2rem;
}
/* display:flex only once the hidden attribute is removed by JS — an
   author rule of display:flex directly on the class would otherwise
   override the [hidden] UA style and show the (empty) overlay on load. */
.history-modal-overlay:not([hidden]) { display: flex; }
.history-modal {
  background: #fff;
  border-radius: 6px;
  width: min(900px, 100%);
  height: min(80vh, 800px);
  display: flex;
  flex-direction: column;
  overflow: hidden;
  box-shadow: 0 10px 40px rgba(0, 0, 0, 0.3);
}
.history-modal-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.6rem 1rem;
  background: #f7f2e2;
  border-bottom: 1px solid var(--border);
  font-weight: 700;
  font-size: 0.9rem;
}
.history-modal-close {
  background: none;
  border: none;
  font-size: 1.4rem;
  line-height: 1;
  cursor: pointer;
  color: var(--text-muted);
  padding: 0 0.25rem;
}
.history-modal-close:hover { color: var(--text); }
.history-modal iframe {
  flex: 1;
  border: none;
  width: 100%;
}

/* Compact branded dialogs (link insert/edit, delete confirmation) — small,
   content-sized popups instead of the browser's native prompt()/confirm(),
   built on the same overlay/modal shell as the bigger preview modals but
   sized down and re-themed: a plain white header with the site's display
   font/maroon for the title (echoing the page-title styling elsewhere)
   instead of the shared cream header, and a light footer bar for actions,
   matching a normal "dialog" layout. */
.action-modal {
  height: auto;
  width: min(480px, 92vw);
}
.action-modal .history-modal-header {
  background: #fff;
  border-bottom: 1px solid var(--border);
  padding: 1.1rem 1.5rem;
}
.action-modal .history-modal-header span {
  font-family: var(--font-display);
  font-size: 1.6rem;
  font-weight: 400;
  color: var(--title);
}
.action-modal .history-modal-close { font-size: 1.6rem; }
.action-modal-body { padding: 1.25rem 1.5rem; }
.action-modal-label {
  display: block;
  font-weight: 700;
  font-size: 0.85rem;
  margin-bottom: 0.3rem;
}
.action-modal-label:not(:first-child) { margin-top: 1rem; }
.action-modal-input {
  display: block;
  width: 100%;
  padding: 0.55rem 0.7rem;
  border: 1px solid var(--border);
  border-radius: 4px;
  font-family: var(--font);
  font-size: 0.95rem;
}
.action-modal-input:focus { outline: 2px solid var(--accent); outline-offset: -1px; }

.modal-footer {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.75rem 1.5rem;
  background: #f7f2e2;
  border-top: 1px solid var(--border);
}
.modal-footer-spacer { flex: 1; }
.modal-btn {
  border: none;
  border-radius: 4px;
  padding: 0.5rem 1.1rem;
  font-size: 0.9rem;
  font-weight: 700;
  font-family: var(--font);
  cursor: pointer;
}
.modal-btn-cancel { background: #fff; color: var(--text); border: 1px solid var(--border); }
.modal-btn-cancel:hover { background: #f0f0f0; }
.modal-btn-primary { background: var(--header-bg); color: #fff; }
.modal-btn-primary:hover { background: #6d001a; }
.modal-btn-danger { background: #fff; color: #b3261e; border: 1px solid #b3261e; }
.modal-btn-danger:hover { background: #fdecea; }
.modal-btn-danger-solid { background: #b3261e; color: #fff; }
.modal-btn-danger-solid:hover { background: #8f1e18; }

.image-picker-modal { height: min(75vh, 700px); }
.image-picker-body {
  flex: 1;
  overflow-y: auto;
  padding: 1rem;
}
.image-picker-upload-row {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin-bottom: 1rem;
  padding-bottom: 1rem;
  border-bottom: 1px solid var(--border);
}
.image-picker-upload-row button {
  background: var(--accent, #8a6d3b);
  color: #fff;
  border: none;
  border-radius: 4px;
  padding: 0.45rem 1rem;
  font-size: 0.85rem;
  font-weight: 700;
  font-family: inherit;
  cursor: pointer;
}
.image-picker-upload-row button:hover { opacity: 0.85; }
.image-picker-upload-row button:disabled { opacity: 0.6; cursor: default; }
.image-picker-hint {
  font-size: 0.8rem;
  color: var(--text-muted);
  font-style: italic;
}
/* Pushed hard right so a long multi-file failure list grows away from the
   button rather than shoving it around mid-upload. */
.image-picker-status {
  font-size: 0.8rem;
  color: var(--text-muted);
  margin-left: auto;
  text-align: right;
}
.image-picker-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
  gap: 0.75rem;
}
.image-picker-item {
  border: 2px solid var(--border);
  border-radius: 4px;
  padding: 0;
  background: #f7f2e2;
  cursor: pointer;
  overflow: hidden;
  aspect-ratio: 1 / 1;
  display: block;
}
.image-picker-item:hover { border-color: var(--accent, #8a6d3b); }
.image-picker-item img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.image-picker-empty {
  grid-column: 1 / -1;
  color: var(--text-muted);
  font-size: 0.85rem;
  text-align: center;
  padding: 2rem 0;
}

/* A disabled Save reads as "nothing to save here", so it's muted rather
   than looking broken — and the cursor stops short of inviting a click. */
.editor-save-btn:disabled {
  opacity: 0.45;
  cursor: default;
}

/* "Include audio" sits beside the Back up now button rather than under it,
   so it reads as a modifier of that action instead of a separate setting. */
.backup-run-form {
  display: flex;
  align-items: baseline;
  gap: 0.9rem;
  flex-wrap: wrap;
  margin-bottom: 1rem;
}
.backup-audio-toggle { font-size: 0.9rem; cursor: pointer; }
.backup-audio-toggle input { margin-right: 0.35rem; }
.backup-audio-toggle .hint { margin-left: 0.3rem; }

/* The images opt-in inside the restore dialog: indented and quieter than
   the warning above it, so it reads as a choice rather than another alarm. */
.restore-images-toggle {
  display: block;
  margin: 0.9rem 0 0.6rem;
  font-size: 0.9rem;
  cursor: pointer;
}
.restore-images-toggle input { margin-right: 0.4rem; }
.restore-images-toggle .hint { display: block; margin: 0.15rem 0 0 1.35rem; }

/* ---- Self test (Conductor > selftest.php) ---- */
.selftest-summary {
  font-weight: 700;
  padding: 0.6rem 0.9rem;
  border-radius: 4px;
  display: inline-block;
}
.selftest-summary.is-passed { background: #e2f0e2; color: #1c5b1c; }
.selftest-summary.is-failed { background: #f7dcdc; color: #8c1c1c; }
.selftest-row {
  display: flex;
  align-items: baseline;
  gap: 0.6rem;
  flex-wrap: wrap;
  padding: 0.25rem 0;
  font-size: 0.9rem;
  border-bottom: 1px solid var(--border);
}
.selftest-flag {
  font-family: var(--font-mono, monospace);
  font-size: 0.75rem;
  font-weight: 700;
  padding: 0.1rem 0.4rem;
  border-radius: 3px;
  flex-shrink: 0;
}
.selftest-row.is-passed .selftest-flag { background: #e2f0e2; color: #1c5b1c; }
.selftest-row.is-failed .selftest-flag { background: #f7dcdc; color: #8c1c1c; }
.selftest-row.is-failed { background: #fdf4f4; }
.selftest-detail {
  flex-basis: 100%;
  margin: 0.3rem 0 0.4rem;
  padding: 0.5rem 0.7rem;
  background: #fff;
  border: 1px solid var(--border);
  border-radius: 4px;
  font-size: 0.75rem;
  white-space: pre-wrap;
  word-break: break-word;
}

/* ---- Image library (Conductor > Images) ----
   Wider tiles than the picker's grid: this view is for identifying a
   specific file among near-identical ones, so the filename and its usage
   have to be readable, not just the thumbnail. */
.image-admin-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 0.9rem;
  margin: 0.75rem 0 1.5rem;
}
.image-admin-item {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 0.5rem;
  background: #f7f2e2;
  position: relative;
  cursor: pointer;
}
/* Nothing to click on an in-use tile, so it shouldn't invite a click. */
.image-admin-item.is-locked { cursor: default; opacity: 0.75; }
.image-admin-item img {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  border-radius: 4px;
  display: block;
  background: #fff;
}
.image-admin-item input[type="checkbox"] {
  position: absolute;
  top: 0.75rem;
  left: 0.75rem;
  width: 18px;
  height: 18px;
  /* Sits on top of the thumbnail, which can be any colour — the white
     box and shadow keep it findable against a pale photo. */
  accent-color: var(--title);
  background: #fff;
  box-shadow: 0 0 0 2px #fff;
  border-radius: 3px;
  cursor: pointer;
}
.image-admin-item:has(input:checked) { border-color: var(--title); background: #f0e3c8; }
.image-admin-name {
  font-size: 0.75rem;
  font-family: var(--font-mono, monospace);
  word-break: break-all;
  line-height: 1.35;
}
.image-admin-meta { font-size: 0.72rem; color: var(--text-muted); line-height: 1.35; }
.image-admin-actions { align-items: center; gap: 0.75rem; }
.danger-button {
  background: #a12;
  color: #fff;
  border: none;
  border-radius: 4px;
  padding: 0.45rem 1rem;
  font-size: 0.85rem;
  font-weight: 700;
  font-family: inherit;
  cursor: pointer;
}
.danger-button:hover:not(:disabled) { opacity: 0.88; }
.danger-button:disabled { opacity: 0.45; cursor: default; }

/* ---- Carousel manager (page editor) ----
   Sits directly above the content editor on pages that contain a carousel.
   Thumbnails are square-cropped so a mix of portrait and landscape photos
   still reads as a tidy grid. */
.carousel-panel {
  border: 1px solid var(--border);
  border-radius: 6px;
  background: #f7f2e2;
  padding: 0.9rem 1rem 1rem;
  margin: 0 0 0.75rem;
}
.carousel-panel-head {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin-bottom: 0.35rem;
}
.carousel-panel-count {
  color: var(--text-muted);
  font-size: 0.85rem;
  /* Pushes the Add button to the far right of the row. */
  margin-right: auto;
}
.carousel-panel .editor-hint { margin: 0 0 0.75rem; }
.carousel-panel-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(110px, 1fr));
  gap: 0.6rem;
}
.carousel-panel-item {
  position: relative;
  aspect-ratio: 1 / 1;
  border: 2px solid var(--border);
  border-radius: 4px;
  overflow: hidden;
  cursor: grab;
}
.carousel-panel-item:active { cursor: grabbing; }
/* The thumbnail being dragged stays visible but recedes, so the gap it
   leaves and the position it would drop into are both readable at a
   glance — the grid reflows live during the drag. */
.carousel-panel-item.is-dragging {
  opacity: 0.35;
  border-style: dashed;
}
/* Reordering also works from the keyboard, so the focus ring has to be
   clearly visible — it's the only cue showing which photo the arrow keys
   will move. */
.carousel-panel-item:focus-visible {
  outline: 3px solid var(--accent, #8a6d3b);
  outline-offset: 2px;
}
.carousel-panel-item img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
/* The remove control sits on the thumbnail itself rather than below it,
   so each photo and its button read as one unit — there's no ambiguity
   about which photo a button belongs to, which matters in a dense grid
   of near-identical group shots. */
.carousel-panel-remove {
  position: absolute;
  top: 4px;
  right: 4px;
  width: 24px;
  height: 24px;
  border: none;
  border-radius: 50%;
  background: rgba(0, 0, 0, 0.6);
  color: #fff;
  font-size: 1rem;
  line-height: 1;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  transition: background 0.15s ease;
}
.carousel-panel-remove:hover { background: var(--danger, #a12); }
.carousel-panel-empty {
  grid-column: 1 / -1;
  color: var(--text-muted);
  font-size: 0.85rem;
  text-align: center;
  padding: 1.5rem 0;
}

.history-diff {
  margin: 0.5rem 0 0;
  border: 1px solid var(--border);
  border-radius: 4px;
  padding: 0.5rem 0;
  font-family: Consolas, Monaco, monospace;
  font-size: 0.8rem;
  max-height: 320px;
  overflow-y: auto;
}
.diff-line { padding: 0.1rem 0.75rem; white-space: pre-wrap; word-break: break-word; }
.diff-added { background: #e6f4ea; color: #1c6b3a; }
.diff-removed { background: #fbeaea; color: #b3261e; text-decoration: line-through; }
.diff-equal { color: var(--text-muted); }

.error { color: #b3261e; background: #fbeaea; padding: 0.7rem 1rem; border-radius: 4px; }
.success { color: #1c6b3a; background: #e6f4ea; padding: 0.7rem 1rem; border-radius: 4px; }

/* ==========================================================================
   Support page — matches the live site's layout: a 3-column header row
   (QoV logo / "Support Us" title / Guild badge linking to /guild), then a
   2-column body row (paragraph text / interactive donation tab widget).
   ========================================================================== */
.support-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
  margin-bottom: 2rem;
}
.support-header-logo,
.support-header-guild { flex: 0 0 150px; }
.support-header-logo img,
.support-header-guild img {
  /* Fixed width AND height (not width + height:auto) — the two source
     images aren't the same aspect ratio (QoV logo is square, the Guild
     badge is wider than it is tall). object-fit:cover fills the full
     150x150 box for both instead of letterboxing the wider one down to
     a smaller rendered height (which is what contain was doing). */
  display: block;
  width: 150px;
  height: 150px;
  object-fit: cover;
  margin: 0 auto;
}
.content h2.support-header-title {
  flex: 1;
  margin: 0;
  font-size: 2.5rem;
}
.support-header-guild { display: block; }

.support-body {
  display: flex;
  gap: 2.5rem;
  align-items: flex-start;
}
/* The box is wider than the text column — an uneven split instead of a
   plain 50/50 flex:1 / flex:1. */
.support-text { flex: 0.8; min-width: 0; }
/* Vertical tab list down the left side of the white box, content panel to
   the right — matches the live site rather than a horizontal pill-button
   row above the content. */
.support-tabs {
  flex: 1.4;
  min-width: 0;
  display: flex;
  align-items: stretch;
  background: #fff;
  border-radius: 4px;
  box-shadow: 0 1px 4px rgba(0,0,0,0.15);
  overflow: hidden;
}
.support-tabs-nav {
  display: flex;
  flex-direction: column;
  flex: 0 0 38%;
  border-right: 1px solid var(--border);
}
.support-tab-btn {
  font-family: var(--font);
  font-size: 1.05rem;
  font-weight: 700;
  text-align: left;
  color: var(--text-muted);
  text-decoration: underline;
  background: transparent;
  border: none;
  border-bottom: 1px solid var(--border);
  border-radius: 0;
  padding: 1.1rem 1.4rem;
  cursor: pointer;
}
.support-tab-btn:last-child { border-bottom: none; }
.support-tab-btn.is-active,
.support-tab-btn:hover { color: var(--text); background: rgba(0,0,0,0.03); }
.support-tabs-panels {
  flex: 1;
  min-width: 0;
  padding: 0.75rem 0.9rem;
  position: relative;
}
.support-tab-panel { display: none; }
/* flex column (not block) so justify-content can position the panel's
   text vertically within the full height of the box below. */
.support-tab-panel.is-active {
  display: flex;
  flex-direction: column;
  min-height: 100%;
}
.support-tab-panel :first-child { margin-top: 0; }
.support-tab-panel :last-child { margin-bottom: 0; }
/* The site-wide .content p rule adds padding-bottom: 1em to every
   paragraph — inside these short blurbs that extra space sits below the
   text inside the <p>'s own box, so centering the box (via
   translateY(-50%) below) actually centered on the text's TOP, not its
   middle, since the box's true center sat lower than the visible text's
   center. Zeroing it here makes the box match the text exactly. */
.support-tab-panel p { padding-bottom: 0; }

/* Donate by Mail / Donate By Phone: not centered on the box as a whole —
   centered on their own nav button (the 2nd and 3rd of 4 equal-height
   rows in .support-tabs-nav), so the blurb's vertical middle lines up
   with "Donate by Mail" / "Donate By Phone" specifically. Expressed as a
   % of the box height (row centers sit at 1.5/4 and 2.5/4 down four
   equal rows) rather than a fixed px offset, so it still tracks the
   button if font size/box size ever changes. Volunteer stays pinned to
   the bottom of the box, unchanged. */
.support-tab-panel[data-panel="mail"].is-active,
.support-tab-panel[data-panel="phone"].is-active {
  display: block;
  position: absolute;
  left: 0.9rem;
  right: 0.9rem;
  min-height: 0;
  transform: translateY(-50%);
}
.support-tab-panel[data-panel="mail"].is-active { top: 37.5%; }
.support-tab-panel[data-panel="phone"].is-active { top: 62.5%; }
.support-tab-panel[data-panel="volunteer"].is-active {
  justify-content: flex-end;
}

@media (max-width: 800px) {
  .support-header { flex-wrap: wrap; justify-content: center; text-align: center; }
  .content h2.support-header-title { flex: 0 0 100%; order: -1; }
  .support-body { flex-direction: column; }
}

@media (max-width: 560px) {
  .support-tabs { flex-direction: column; }
  .support-tabs-nav {
    flex: 0 0 auto;
    flex-direction: row;
    flex-wrap: wrap;
    border-right: none;
    border-bottom: 1px solid var(--border);
  }
  .support-tab-btn { border-bottom: none; flex: 1 1 auto; text-align: center; }
  .support-tabs-panels { padding: 0.75rem; }
}

/* ==========================================================================
   Guild page — top intro is a 2-column row ("Join the Guild!" title +
   paragraph / "Here's how:" + mail-dues instructions), followed by a photo
   carousel, followed by a black-background section (Russian Icon Paintings)
   that runs to the bottom of the page with red text throughout.
   ========================================================================== */
.guild-intro {
  display: flex;
  gap: 2.5rem;
  align-items: flex-start;
  margin-bottom: 2rem;
}
.guild-intro > div { flex: 1; min-width: 0; }
.content h2.guild-intro-title,
.content h3.guild-intro-subtitle {
  font-family: var(--font-display);
  color: var(--title);
  font-weight: 400;
  line-height: 1.15;
  text-align: left;
  font-size: 2rem;
  margin: 0 0 0.75rem;
}
.content h3.guild-intro-subtitle { font-style: italic; }

.guild-intro-mail { font-style: italic; }
.guild-intro-mail-bold { color: #000; font-weight: 700; }
.guild-intro-mail-address { color: #000; font-weight: 400; }

@media (max-width: 800px) {
  .guild-intro { flex-direction: column; }
}

/* Photo carousel — fades between slides, dot navigation matches the
   pagination-dot pattern seen on the live site's slider. */
.guild-carousel {
  position: relative;
  margin: 0 0 2.5rem;
  border-radius: 4px;
  overflow: hidden;
  background: #000;
  aspect-ratio: 16 / 9;
}
.guild-carousel-slide {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity 0.8s ease;
}
.guild-carousel-slide.is-active { opacity: 1; z-index: 1; }
.guild-carousel-slide img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.guild-carousel-dots {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0.75rem;
  z-index: 2;
  display: flex;
  justify-content: center;
  gap: 0.4rem;
}
.guild-carousel-dots button {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  border: 1px solid #fff;
  background: rgba(255,255,255,0.4);
  padding: 0;
  cursor: pointer;
}
.guild-carousel-dots button.is-active { background: #fff; }

/* Prev/next arrows — semi-transparent circles that brighten on hover,
   vertically centered over the slide. Icon is an inline SVG chevron
   (not a text glyph) so it sits dead-center in the circle at a
   consistent size regardless of font metrics. */
.guild-carousel-arrow {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  z-index: 2;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  border: none;
  background: rgba(0, 0, 0, 0.4);
  color: #fff;
  padding: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: background 0.2s ease;
}
.guild-carousel-arrow svg {
  width: 22px;
  height: 22px;
  display: block;
}
.guild-carousel-arrow:hover { background: rgba(0, 0, 0, 0.65); }
.guild-carousel-prev { left: 0.75rem; }
.guild-carousel-next { right: 0.75rem; }

@media (max-width: 600px) {
  .guild-carousel-arrow { width: 36px; height: 36px; }
  .guild-carousel-arrow svg { width: 18px; height: 18px; }
  .guild-carousel-prev { left: 0.4rem; }
  .guild-carousel-next { right: 0.4rem; }
}

/* Black-background section: from the "Russian Icon Paintings" heading to
   the bottom of the page. Same width as the carousel/content column (no
   horizontal bleed) — only the bottom margin is pulled negative so the
   black fill reaches the page's actual bottom edge. */
body.page-guild .page { padding-bottom: 0; }
.guild-icons-section {
  background: #000;
  color: #d4342c;
  text-align: center;
  margin: 0 0 -3rem;
  padding: 3rem 1.5rem;
}
.guild-icons-section p { color: #d4342c; }
.guild-icons-section h2.section-title {
  color: #d4342c;
  margin-bottom: 1rem;
}
.guild-icons-section .guild-icons-note {
  font-size: 1.1rem;
  margin-bottom: 2rem;
}
.guild-icons-grid {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 2rem;
}
.guild-icons-grid figure {
  margin: 0;
  width: 190px;
}
.guild-icons-grid img {
  width: 100%;
  height: auto;
  border-radius: 2px;
  display: block;
}
.guild-icons-grid figure figcaption {
  color: #d4342c;
  margin-top: 0.6rem;
  font-style: italic;
  font-size: 1.05rem;
}

/* ==========================================================================
   Contact ("Say hi!") page — restores the original two-column layout:
   the form on the left, the existing contact info on the right.
   ========================================================================== */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.contact-body {
  display: flex;
  gap: 2.5rem;
  align-items: flex-start;
  margin-top: 1rem;
}
.contact-form-col,
.contact-text-col { flex: 1; min-width: 0; }

.contact-form-row {
  display: flex;
  gap: 1.25rem;
}
.contact-form-row .contact-field { flex: 1; min-width: 0; }

.contact-field { margin-bottom: 1.25rem; }
.contact-field input,
.contact-field textarea {
  display: block;
  width: 100%;
  background: #eee;
  border: none;
  border-radius: 0;
  padding: 16px;
  font-family: var(--font);
  font-size: 1rem;
  color: var(--text);
}
.contact-field textarea { height: 150px; resize: vertical; }
.contact-field input:focus,
.contact-field textarea:focus {
  outline: 2px solid var(--header-bg);
  outline-offset: 1px;
}

.contact-honeypot { display: none; }

.contact-submit-row { text-align: right; }
.content button.contact-submit,
.content input.contact-submit {
  display: inline-block;
  border: 2px solid var(--header-bg);
  color: var(--header-bg);
  background: transparent;
  padding: 6px 20px;
  border-radius: 3px;
  font-weight: 500;
  font-family: var(--font);
  font-size: 1rem;
  cursor: pointer;
}
.content button.contact-submit:hover,
.content input.contact-submit:hover { background: var(--header-bg); color: #fff; }

.content .contact-text-col p:first-child { margin-top: 0; }

@media (max-width: 800px) {
  .contact-body { flex-direction: column; }
  .contact-form-row { flex-direction: column; gap: 0; }
}

@media (max-width: 800px) {
  .guild-icons-section { padding: 2.5rem 1rem 3rem; }
}

/* ==========================================================================
   Mailing List page — the Mailchimp embedded signup form, restyled to
   match the rest of the site (gray fields, ghost submit button) instead
   of Mailchimp's bare default markup.
   ========================================================================== */
/* width: min-content sizes this box to its narrowest child that still
   can't wrap any smaller — the nowrap tagline. (display:table/inline-block
   with the default "auto" width was tried first, but auto resolves to
   max-content, not min-content, and the Country dropdown's longest option
   text — "Bonaire, Saint Eustatius and Saba" — has a wider max-content
   than the tagline, so auto sizing was stretching the box to fit that
   instead. min-content sidesteps it and reliably matches the tagline.)
   margin:0 auto centers the resulting box on the page. */
.mc-signup-wrap {
  width: min-content;
  margin: 0 auto;
}
.content .mc-tagline {
  white-space: nowrap;
  text-align: right;
  font-size: 1.05rem;
  margin: 0 0 0.2rem;
}
#mc_embed_signup { width: 100%; margin: 0; }
.mc-required-note {
  text-align: right;
  font-size: 0.85rem;
  color: var(--text-muted);
  margin: 0 0 1rem;
}
.mc-asterisk { color: #b3261e; }
.mc-obelisk { font-size: 0.8em; vertical-align: super; }
.mc-dagger-note {
  text-align: right;
  font-size: 0.85rem;
  color: var(--text-muted);
  margin: 0 0 0.35rem;
}

.mc-field-group { margin-bottom: 1.25rem; }
.mc-field-group label {
  display: block;
  font-weight: 500;
  margin-bottom: 0.35rem;
}
.mc-field-group input,
.mc-field-group select {
  display: block;
  width: 100%;
  min-width: 0;
  /* Explicit height + line-height instead of relying on padding alone —
     browsers give <select> a slightly different native intrinsic height
     than <input> even with identical padding/border/font-size, which is
     what was throwing the row out of alignment by a pixel or two. Pinning
     both to the same box-sizing:border-box height makes them identical. */
  height: 36px;
  line-height: 20px;
  background: #eee;
  border: none;
  border-radius: 0;
  padding: 8px 10px;
  font-family: var(--font);
  font-size: 0.9rem;
  color: var(--text);
}
.mc-field-group input:focus,
.mc-field-group select:focus {
  outline: 2px solid var(--header-bg);
  outline-offset: 1px;
}

.mc-field-row {
  display: grid;
  /* minmax(0, ...) instead of a bare fr: grid tracks default to an "auto"
     minimum that respects each field's natural min-content width (the
     Country dropdown's longest option, in particular), which was forcing
     this row wider than the tagline above it. minmax(0, ...) removes that
     floor so the row can actually shrink to match. Postal code is 10%
     narrower than an even third, State/Province is back to an even third,
     and Country picks up the difference. */
  grid-template-columns: minmax(0, 0.9fr) minmax(0, 1fr) minmax(0, 1.1fr);
  gap: 1rem;
  margin-bottom: 0;
}
.mc-field-row .mc-field-third { min-width: 0; margin-bottom: 1.25rem; }

#mce-responses .response { margin-bottom: 1rem; }

.mc-submit-row { text-align: center; margin-top: 0.5rem; }

@media (max-width: 600px) {
  .mc-field-row { grid-template-columns: 1fr; gap: 0; }
  /* The tagline can't stay one line on narrow screens — let it wrap and
     drop the shrink-to-fit table trick in favor of a plain full-width,
     centered block. */
  .mc-signup-wrap { display: block; width: 100%; }
  .content .mc-tagline { white-space: normal; }
}
