/* --------------------------------------------------------
   FONTS — self-hosted Open Sans (humanist sans, closest free
   match to the Frutiger LT used on the concert flyers). Variable
   weight 300–800, subsetted to latin + latin-ext for German
   umlauts and composer-name accents. Used for headlines.
-------------------------------------------------------- */
@font-face {
  font-family: 'Open Sans';
  font-style: normal;
  font-weight: 300 800;
  font-stretch: 100%;
  font-display: swap;
  src: url(../fonts/opensans-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Open Sans';
  font-style: normal;
  font-weight: 300 800;
  font-stretch: 100%;
  font-display: swap;
  src: url(../fonts/opensans-latinext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* --------------------------------------------------------
   RESET & BASE
-------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

:root {
  /* Palette derived from the concert flyers: deep brand blue as the spine,
     warm yellow + lime green as seasonal accents, cool neutral grounds. */
  --dark:       #102146;
  --dark-warm:  #14305C;
  --white:      #FFFFFF;  /* foreground/text only — not used as a page background */

  /* The single brand blue (#013A85) is held by exactly two tokens:
       --brand-blue       FIXED — always #013A85 (use where the colour must NOT
                          adapt: nav underline bar, map "Ort" pill).
       --brand-blue-deep  REMAPPABLE — #013A85 here, but .zone--blue overrides it
                          to #fff so all text/links/accents auto-flip on the navy
                          field. Use this for everything else (text, borders, fills). */
  --brand-blue:   #013A85;
  --brand-blue-deep: #013A85;
  /* Body / running text ("Laufschrift") colour on the light field. Separate
     from --brand-blue-deep (headings, labels, accents = "Schrift") so the two
     can be themed independently. .zone--blue remaps it for the dark field. */
  --text-body: #013A85;
  --brand-navy:   #102146;
  /* The flyer field yellow (#FFCA58) — the page background. REMAPPABLE: .zone--blue
     overrides it to #102146 so the whole field flips to navy. Single token (no
     fixed variant — there is no #FFCA58 that should stay yellow on the navy field). */
  --brand-yellow: #FFCA58;
  /* Share/Karte pill (Component Library share.css) — dark-blue outline, not black. */
  --share-border:       rgba(1, 58, 133, 0.40);
  --share-hover-bg:     rgba(1, 58, 133, 0.06);
  --share-border-hover: rgba(1, 58, 133, 0.60);
  --brand-green:  #C2D62D;
  /* Link accent. The "single brand blue" rule is relaxed for links only: body
     text stays the deep navy (#013A85); links get a brighter, more saturated
     royal blue so they're recognisable without an underline. Clears AA contrast
     on the yellow field (~4.9:1). REMAPPABLE: on the navy field (.zone--blue) it
     flips to the flyer gold so links stay legible there. */
  --link:       #1645CF;
  --link-hover: #0E2F9E;

  --serif: Georgia, 'Times New Roman', serif;
  --sans:  -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif;
  /* Headline face — Frutiger-alike humanist sans (flyer identity). Falls back
     to Frutiger/Segoe/Avenir then the system sans while the woff2 loads. */
  --display: 'Open Sans', 'Frutiger', 'Frutiger LT', 'Segoe UI', 'Avenir Next', var(--sans);

  --space-xs:  0.35rem;
  --space-sm:  0.75rem;
  --space-md:  1.25rem;
  --space-lg:  2rem;
  --space-xl:  3rem;

  --max-width: 72rem;

  /* Single knob for the horizontal gap between the two columns of side-by-side
     blocks: Zweispalter, concerts-listing, venue-info, next-concert. */
  --col-gap: calc(var(--space-md) + 50px);

  /* Single fine-tuning knob: how many font-weight units the yellow zone is
     nudged bolder than the blue/default reference, to optically match white-on-
     navy bloom. Applied (via calc) to body, headings and rubrik labels alike.
     Raise for heavier yellow text, lower toward 0 to remove compensation. */
  --yellow-weight-boost: 50;

  /* Heading-size scale + per-level remap. Each heading level (H1/H2/H3) resolves
     its size through --hN-size, which defaults to its own scale step. The CMS
     (Site → Gestaltung) can remap a level to another step — or to body size — so
     e.g. all headings can share one size without losing the option of distinct
     sizes. Only font-size is remapped; weight/family/colour stay heading-like. */
  --hsize-h1:   clamp(2rem, 5vw, 3.5rem);
  --hsize-h2:   clamp(1.5rem, 3.5vw, 2.25rem);
  --hsize-h3:   clamp(1.1rem, 2.5vw, 1.5rem);
  --hsize-body: 1rem;
  --h1-size: var(--hsize-h1);
  --h2-size: var(--hsize-h2);
  --h3-size: var(--hsize-h3);

  /* Shared corner radius for content images (hero, two-column, concert cards…)
     so they round consistently on the flat yellow. */
  --img-radius: 5px;
}

html { font-size: 16px; scroll-behavior: smooth; }

body {
  font-family: var(--sans);
  color: var(--text-body);
  background: var(--brand-yellow);
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  min-height: 100svh;
}

/* Sticky footer: the last colour zone grows to fill the viewport so its field
   (navy for a blue zone, yellow otherwise) always reaches the footer — no body
   gap below short pages. The blue zone is always last when present; otherwise
   the yellow zone is. */
.zone--blue { flex-grow: 1; }
.zone--yellow:not(:has(~ .zone--blue)) { flex-grow: 1; }

/* --------------------------------------------------------
   SEITENMARKE — rotated (−90°) label on the left of the usable
   page area, overlaying the colour zones. Present only when a
   `seitenmarke` block exists; renderPage wraps the page content in
   .page-main so the label anchors to the top (nav bottom) and the
   content shifts right. Desktop only (hidden ≤ 959px / mobile).
-------------------------------------------------------- */
/* .page-main becomes the flex child that grows (so the last zone still
   reaches the footer) and the positioning context for the label. */
.has-seitenmarke .page-main {
  position: relative;
  flex: 1 0 auto;
  display: flex;
  flex-direction: column;
}
.seitenmarke { display: none; }
@media (min-width: 960px) {
  /* Shared geometry. Seitenmarke + content form one centred "viewArea" band that
     grows with the window up to --max-width, then centres. The label is a fixed
     column of width --sm-reserve (visual thickness ≈ font size, plus the
     configurable Abstand gap); the content fills the rest of the band. */
  .has-seitenmarke .page-main {
    --sm-thick: var(--sm-size, 2rem);
    --sm-reserve: calc(var(--sm-thick) + var(--sm-gap, 1rem));
  }
  .seitenmarke {
    display: block;
    position: absolute;
    top: 0;                       /* = bottom of the nav bar */
    /* Left text edge of the centred band; floors at --space-md when narrow, so
       the label rides the centred viewArea and is never clipped. */
    left: calc(max(0px, (100% - var(--max-width)) / 2) + var(--space-md));
    z-index: 4;
    pointer-events: none;
  }
  /* Rotate −90°: end of text to the top (under nav), reading bottom-to-top;
     the unrotated top edge lands on the usable-area left edge; the text
     extends downward as far as its length needs. */
  .seitenmarke__text {
    position: absolute; top: 0; left: 0;
    transform-origin: 0 0;
    transform: rotate(-90deg) translateX(-100%);
    white-space: nowrap;
    /* Match the logo wordmark face (.nav__brand uses var(--serif)). */
    font-family: var(--serif);
    font-weight: 700;
    line-height: 1;
    font-size: var(--sm-size, 2rem);
    color: var(--sm-color, var(--brand-blue-deep));
  }
  /* Content stays centred (base margin:0 auto / width:100% / max-width); it just
     insets past the fixed Seitenmarke column. So the whole band centres above
     max-width, and below it the content fills the rest of the viewArea. The gap
     from the label's baseline to the content equals the configured Abstand. */
  .has-seitenmarke .page-main .container,
  .has-seitenmarke .page-main .hero {
    padding-left: calc(var(--space-md) + var(--sm-reserve));
  }
}

img { display: block; max-width: 100%; height: auto; }
a   { color: var(--link); text-decoration: none; }
a:hover { color: var(--link-hover); text-decoration: underline; }

.container {
  width: 100%;
  max-width: var(--max-width);
  margin: 0 auto;
  padding: 0 var(--space-sm);
}
@media (min-width: 768px) {
  .container { padding: 0 var(--space-md); }
}

/* --------------------------------------------------------
   TYPOGRAPHY
-------------------------------------------------------- */
h1, h2, h3 {
  font-family: var(--display);
  font-weight: 750;
  line-height: 1.2;
  color: var(--brand-blue-deep);
}
h1 { font-size: var(--h1-size); }
h2 { font-size: var(--h2-size); }
h3 { font-size: var(--h3-size); }

aside.rte-note {
  background: #fff8c4;
  /* Always dark text: the note keeps its light background even in the blue
     zone. Literal #013A85 (the single text blue) — the zone remaps --text AND
     --brand-blue-deep to white, so a token can't stay dark on this light note. */
  color: #013A85;
  border-left: 4px solid #d4a017;
  border-right: 4px solid #d4a017;
  padding: 0.6rem 1rem;
  margin: 1rem 0;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.92em;
}

.label {
  font-family: var(--sans);
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--brand-blue-deep);
}

/* --------------------------------------------------------
   NAVIGATION
-------------------------------------------------------- */
.nav {
  position: static;
  background: var(--brand-yellow);
  padding-top: 30px;
  padding-bottom: var(--space-lg);
}
html { scroll-padding-top: 0; }
/* Centred, stacked header: logo/wordmark on top, nav items 50px below. */
.nav__inner {
  display: flex; flex-direction: column; align-items: center;
  gap: 25px;
  /* Appearance knobs (overridden inline per-site by renderNav from
     site.appearance): logo lockup scale + alignment, nav-row alignment. */
  --logo-scale: 1;
  --logo-align: center;
  --nav-align: center;
  --logo-color: #013A85;
}
.nav__brand {
  font-family: var(--serif);
  /* The lockup is one block: the (nowrap) wordmark sets its width and the swoosh
     is a % of that, so font-size scales the whole block uniformly. Cap the
     font-size to a fraction of the viewport so the block never exceeds the page
     width — on narrow screens / at large logo sizes the whole lockup shrinks to
     fit, staying on one line. The vw factor is tuned to the wordmark length. */
  font-size: min(calc(1rem * var(--logo-scale)), 5.5vw);
  align-self: var(--logo-align);
  color: var(--logo-color); white-space: nowrap;
  max-width: 100%;
  display: inline-flex; flex-direction: column; align-items: stretch;
  gap: calc(0.085rem + 6px); line-height: 1;
}
/* Wordmark set like the printed logo: all lower-case, "kammerchor" bold,
   "zürcher unterland" regular weight. */
.nav__wordmark { text-transform: lowercase; font-weight: 400; letter-spacing: 0.01em; }
.nav__wordmark-strong { font-weight: 700; }
/* Swoosh painted via CSS mask so --logo-color can recolour it (an <img> SVG
   can't be recoloured from the page). aspect-ratio from the SVG viewBox
   (95.41×41.531). */
.nav__logo {
  width: 43%; margin-left: 38%; display: block;
  aspect-ratio: 95.41 / 41.531;
  background-color: var(--logo-color);
  -webkit-mask: url(../images/logo-arc.svg) no-repeat center / contain;
  mask: url(../images/logo-arc.svg) no-repeat center / contain;
}
.nav__links {
  display: flex; flex-wrap: wrap;
  /* align-self places the shrink-to-fit block; justify-content aligns each
     wrapped row inside it so multi-line nav stays flush to the same edge. */
  justify-content: var(--nav-align);
  align-self: var(--nav-align);
  list-style: none;
  /* horizontal spacing between items; when the row wraps, lines stack at the
     font's regular line height (row-gap: 0) rather than the big flex gap. */
  column-gap: var(--space-md); row-gap: 0;
  line-height: 1.6;
}
.nav__links a {
  font-size: 0.85rem; color: var(--brand-blue-deep);
  letter-spacing: 0.08em; font-weight: 700; text-transform: uppercase;
}
.nav__links a:hover { color: var(--brand-blue-deep); text-decoration: none; }
.nav__toggle {
  display: none; flex-direction: column; gap: 5px;
  background: none; border: none; cursor: pointer; padding: 4px;
}
.nav__toggle span {
  display: block; width: 22px; height: 2px;
  background: var(--brand-blue); border-radius: 1px;
}
.nav.open .nav__links {
  display: flex; flex-direction: column;
  position: absolute; top: 3.5rem; left: 0; right: 0;
  background: var(--brand-yellow);
  box-shadow: 0 8px 12px -6px rgba(0,0,0,0.25);
  padding: var(--space-md); gap: var(--space-sm);
}
@media (min-width: 960px) {
  .nav__brand  { font-size: min(calc(1.1rem * var(--logo-scale)), 5.5vw); }
}
@media (min-width: 960px) and (max-width: 1100px) {
  .nav__links  { gap: var(--space-sm); }
  .nav__links a { font-size: 0.8rem; }
}

/* --------------------------------------------------------
   HERO
-------------------------------------------------------- */
.hero {
  position: relative;
  overflow: hidden;
  width: 100%;
  max-width: var(--max-width);
  margin: 0 auto;
  /* Rounded corners (overflow:hidden clips the photo AND the overlay slab's
     bottom to the same radius) so the hero reads as an integrated block on the
     flat yellow rather than a hard-edged rectangle. */
  border-radius: var(--img-radius);
}
/* Nav is now in normal flow (centred header), so the hero no longer needs a
   top offset to clear a fixed bar. */
.hero__img {
  display: block;
  width: 100%;
  object-fit: cover;
  /* Hero uses the aspect ratio selected per image in the CMS (--hero-aspect);
     unset = the image's native proportions. Mobile can override below via a
     block-level mobile_crop. */
  aspect-ratio: var(--hero-aspect, auto);
}
/* Mobile: use hero block's mobile_crop (CSS custom props) — falls back to a
   square crop centred on the subject if block didn't set them. */
@media (max-width: 767px) {
  .hero__img {
    /* Phones: an explicit mobile crop wins; otherwise inherit the selected
       hero aspect, falling back to the image's natural proportions.
       object-position only bites when a crop is actually set. */
    aspect-ratio: var(--hero-mobile-aspect, var(--hero-aspect, auto));
    height: auto;
    object-position: var(--hero-mobile-pos, center 30%);
  }
}
/* No max-height on the hero — the hero block is width-capped by --max-width
   and the CMS-set aspect-ratio determines the height. Pick a flat ratio
   (3/1, 21/9, 16/9) in the CMS to avoid tall heroes on wide screens. */
.hero__overlay {
  position: absolute; inset: 0;
  background: linear-gradient(to bottom,
    rgba(16,33,70,0.05) 0%, rgba(16,33,70,0.30) 65%, rgba(16,33,70,0.88) 100%);
}
.hero__content {
  position: absolute; inset: 0; z-index: 2;
  padding: var(--space-md) var(--space-sm) var(--space-md);
  max-width: var(--max-width); margin: 0 auto;
  display: flex; flex-direction: column; justify-content: flex-end;
  pointer-events: none;
}
.hero__content > * { pointer-events: auto; }
@media (min-width: 768px) {
  .hero__content { padding: var(--space-lg) var(--space-md) var(--space-md); }
}
.hero--has-nav .hero__content { padding-bottom: 3.5rem; }
@media (min-width: 768px) {
  .hero--has-nav .hero__content { padding-bottom: 4rem; }
}
.hero h1 {
  color: var(--white);
  margin-bottom: var(--space-xs);
  font-size: clamp(1.3rem, 3.2vw, 2.4rem);
  line-height: 1.2;
  overflow-wrap: break-word;
  hyphens: auto;
  opacity: 0.8;
}
.hero .label { color: var(--brand-yellow); text-shadow: 0 1px 2px rgba(0,0,0,0.6); }
.hero__tagline {
  font-family: var(--display);
  font-size: clamp(1rem, 2.5vw, 1.35rem);
  color: rgba(255,255,255,0.85);
  font-style: italic;
  margin-bottom: var(--space-md);
}

/* Heroless concert-detail title header — leads the page on the flat yellow
   field, flyer-style (no photo band, no date line above the title). */
.concert-detail__head {
  padding-top: var(--space-md);
  padding-bottom: 0;
}
.concert-detail__title {
  color: var(--brand-blue-deep);
  margin-bottom: var(--space-xs);
}
.concert-detail__subtitle {
  font-family: var(--display);
  font-size: clamp(1rem, 2.5vw, 1.35rem);
  color: var(--brand-blue-deep);
  font-style: italic;
  margin-bottom: 0;
}

/* --------------------------------------------------------
   SECTIONS
-------------------------------------------------------- */
.section { padding: var(--space-md) 0; }
/* Give the first section of the yellow zone some top breathing room under the
   header (heroless pages especially). */
.zone--yellow > section.section:first-of-type { padding-top: 0; }

/* --------------------------------------------------------
   COLOUR ZONES — two-tone field like the concert flyer.
   Content above the `zone-break` marker renders on the yellow
   field (dark text); content below renders on the dark-blue
   field (light text). Both zones are full-bleed; content stays
   in the centred .container inside each section.
-------------------------------------------------------- */
.zone { width: 100%; }
/* Curved yellow→blue boundary (off-centre swell). Full-bleed; the -1px margin
   guarantees no subpixel seam against the blue zone below. */
.zone-divider {
  display: block; width: 100%; height: 90px;
  color: var(--brand-navy);
  margin-bottom: -1px;
}
@media (max-width: 600px) { .zone-divider { height: 56px; } }
.zone--blue {
  /* Re-map the design tokens so token-driven components reskin for navy. */
  --brand-yellow:    var(--brand-navy);   /* the field yellow flips to the navy field colour */
  --zone-accent:     #ffffff;   /* white accent on the navy field (drives the blue-zone button hover) */
  /* The remappable brand blue flips to white here, so all text, links, accents,
     borders and fills built on --brand-blue-deep auto-reskin for the navy field. */
  --brand-blue-deep: #ffffff;
  /* Body / running text on the navy field (separately themable from --brand-blue-deep). */
  --text-body: #ffffff;
  /* Rust would muddy against navy — links flip to the flyer gold instead. */
  --link:       #FFCA58;
  --link-hover: #ffd87e;
  --share-border:       rgba(255, 255, 255, 0.40);
  --share-hover-bg:     rgba(255, 255, 255, 0.08);
  --share-border-hover: rgba(255, 255, 255, 0.70);
  background: var(--brand-navy);
  color: var(--text-body);
  padding: var(--space-lg) 0;
  /* Positioning context for the Dekor layer (scattered symbols behind content). */
  position: relative;
}
/* --------------------------------------------------------
   DEKOR — scattered SVG symbols on the dark zone. A layer behind
   the content (z-index 0; content lifted to 1) whose box extends
   up by --decor-bleed so a few symbols cross the divider into the
   light zone. Each symbol is a tinted, low-opacity, blended mask.
-------------------------------------------------------- */
.zone--blue > section { position: relative; z-index: 1; }
.zone-decor {
  position: absolute;
  left: 0; right: 0;
  /* Clip box. Bottom is a hard edge at the blue zone's lower border; the top is
     lifted by --decor-headroom (half a max symbol, set by the generator) so the
     upward bleed across the divider isn't cut. overflow:hidden (not clip-path)
     so symbols are clipped for SCROLL too — clip-path only hides them visually,
     letting big symbols near the bottom extend the page below the dark field
     into the light bg. */
  top: calc(-1 * (var(--decor-bleed, 0px) + var(--decor-headroom, 0px)));
  bottom: 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
}
.zone-decor__field {
  /* Placement box: the blue zone extended up by --decor-bleed. Symbols scatter
     here; only their natural half-size overhang reaches into the headroom above,
     so they kiss the divider instead of spilling into the light zone. */
  position: absolute;
  left: 0; right: 0;
  top: var(--decor-headroom, 0px);
  bottom: 0;
}
.zone-decor__sym {
  position: absolute;
  display: block;
  -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
  -webkit-mask-position: center;  mask-position: center;
  -webkit-mask-size: contain;     mask-size: contain;
}
/* White text on the navy field blooms (irradiation) and reads a little heavier
   than the same weight on yellow. Rather than thinning the blue, nudge the
   yellow-zone text slightly bolder so both fields look optically matched. The
   nudge for every text type derives from the single --yellow-weight-boost knob
   (in :root): base weight + boost. Bases: body 400, headings 750, rubrik 600. */
.zone--yellow { font-weight: calc(400 + var(--yellow-weight-boost)); }
.zone--yellow h1, .zone--yellow h2, .zone--yellow h3,
.zone--yellow .rich-text h2, .zone--yellow .rich-text h3, .zone--yellow .rich-text h4 { font-weight: calc(750 + var(--yellow-weight-boost)); }
.zone--yellow .label { font-weight: calc(600 + var(--yellow-weight-boost)); }
/* In the blue zone the primary button is a yellow pill, so its label must be
   dark (white-on-yellow fails contrast); outline hover likewise. Literal
   #013A85 (the single text blue) — a token would go white inside the zone. */
.zone--blue .btn--primary { color: #013A85; }
.zone--blue .btn--primary:hover { background: color-mix(in srgb, var(--zone-accent) 88%, #000); border-color: color-mix(in srgb, var(--zone-accent) 88%, #000); color: #013A85; }
.zone--blue .btn--outline:hover { color: #013A85; }
.section__header { margin-bottom: 0; }
.section__header:not(:first-child) { margin-top: var(--space-lg); }
.section__header .label { margin-bottom: var(--space-xs); display: block; }
.section__header h2 { margin-bottom: 15px; }
.section__header .engagement__intro { max-width: 52rem; margin-top: var(--space-xs); line-height: 1.6; }

/* Consistent vertical rhythm between sibling blocks inside a section */
.section .container > .block + .block { margin-top: var(--space-xl); }
/* Algorithmic listing blocks (next-concert, upcoming-concerts) read as a
   sub-element of their section, not a standalone block: no top gap, so they sit
   tight under the section heading / each other. */
.section .container > .block + .block--algo { margin-top: 0; }

/* --------------------------------------------------------
   FEATURED CARD
-------------------------------------------------------- */
.concert-featured {
  display: grid; grid-template-columns: 1fr;
  /* When wrapped to one column on narrow screens, the vertical gap between image
     and body matches the regular block spacing (like the Zweispalter). The
     --linked listing variant is display:block, so this only affects next-concert. */
  row-gap: var(--space-xl);
  overflow: hidden;
}
/* Both featured variants (next-concert + concerts-listing) sit flush — no card
   inset; image and text align with the surrounding content and horizontal
   separation comes from the grid column-gap (--col-gap). */
.concert-featured__img {
  width: 100%;
  aspect-ratio: 2/1; object-fit: cover;
  border-radius: var(--img-radius);
}
.concert-featured__body { padding: 0; }
.concert-card__date {
  font-size: 0.78rem; font-weight: 600;
  letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--brand-blue-deep); margin-bottom: var(--space-xs);
}
.concert-featured h3 { margin-bottom: 0.15rem; }
.concert-card__venue { font-size: 0.9rem; color: var(--brand-blue-deep); margin-bottom: var(--space-xs); }
/* next-concert: one line per performance (date + venue) */
.concert-card__perfs {
  list-style: none; margin: 0.15rem 0 var(--space-sm); padding: 0;
  display: flex; flex-direction: column; gap: 0.15rem;
}
.concert-card__perfs li { font-size: 0.85rem; line-height: 1.4; color: var(--brand-blue-deep); }
.concert-card__pdate { font-weight: 600; }
.concert-card__pvenue { font-weight: 400; }
.concert-card__desc { font-size: 0.9rem; line-height: 1.5; margin-bottom: var(--space-sm); }
.concert-card__description {
  font-size: 0.85rem; line-height: 1.5;
  color: var(--brand-blue-deep); margin-bottom: var(--space-sm);
  display: -webkit-box;
  -webkit-line-clamp: 5;
  line-clamp: 5;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.concert-card__description > p { margin: 0 0 0.4em; }
.concert-card__description > p:last-child { margin-bottom: 0; }
@media (min-width: 768px) {
  .concert-featured { grid-template-columns: 1fr 1fr; }
  /* Wider separation between image and facts, matching the Zweispalter gap.
     +50px on top of the image's own inset margin + body padding. */
  .concert-featured:not(.concert-featured--linked) { column-gap: var(--col-gap); }
  /* .concert-featured__img aspect-ratio/height set by widget inline styles */
}

/* Listing variant: article wrapper holds the clickable link plus a separate
   actions row (Karte / Merken & Teilen). The link carries the grid so image
   and body still sit side-by-side on desktop. overflow:visible on the article
   lets the Share popup and expanded Karte canvas escape the card's rounded
   corner clipping — the inner link handles image corner clipping instead. */
.concert-featured--linked { display: block; overflow: visible; }
.concert-featured__link {
  display: grid; grid-template-columns: 1fr;
  /* Wrapped to one column on narrow screens: vertical gap between image and body
     matches the regular block spacing (like the Zweispalter / next-concert). */
  row-gap: var(--space-xl);
  color: inherit; text-decoration: none;
  overflow: hidden;
  border-radius: 2px 2px 0 0;
}
@media (min-width: 768px) {
  .concert-featured__link { grid-template-columns: 1fr 1fr; column-gap: var(--col-gap); }
}
.concert-featured--linked .perf-list__actions {
  padding: 0 0 var(--space-sm);
}

/* --------------------------------------------------------
   CHIP ROW
-------------------------------------------------------- */
.concerts-row { display: flex; flex-wrap: wrap; gap: var(--space-xs); margin-top: var(--space-sm); }
.concert-chip {
  flex: 1 1 14rem; display: flex; align-items: center;
  gap: var(--space-sm); padding: 0;
  text-decoration: none; color: var(--brand-blue-deep);
}
.concert-chip:hover { text-decoration: none; color: var(--brand-blue-deep); }
.concert-chip__date { display: flex; flex-direction: column; align-items: center; min-width: 2.8rem; line-height: 1; }
.concert-chip__day { font-family: var(--display); font-size: 1.5rem; color: var(--brand-blue-deep); }
.concert-chip__month { font-size: 0.65rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.08em; color: var(--brand-blue-deep); }
.concert-chip__info { display: flex; flex-direction: column; }
.concert-chip__title { font-family: var(--display); font-size: 0.95rem; line-height: 1.2; }
.concert-chip__venue { font-size: 0.8rem; color: var(--brand-blue-deep); }
.concert-chip__img { width: 3.5rem; height: 3.5rem; object-fit: cover; border-radius: var(--img-radius); flex-shrink: 0; }

/* --------------------------------------------------------
   TWO-COLUMN
-------------------------------------------------------- */
/* Horizontal gap between the two columns; when the block wraps to one column on
   narrow screens, the vertical gap between the stacked cards matches the regular
   space between blocks (--space-xl) rather than the tighter column gap. */
.two-col { display: grid; grid-template-columns: 1fr; column-gap: var(--space-md); row-gap: var(--space-xl); }
.two-col__card { display: flex; flex-direction: column; gap: var(--space-sm); }
.two-col__text p { margin-bottom: var(--space-xs); }
.two-col__text h3 { margin-bottom: 10px; }
.two-col__text > :last-child { margin-bottom: 0; }
/* Image shape follows the per-image aspect setting (emitted inline by imgStyle);
   unset = the photo's natural proportions. */
.two-col__img { width: 100%; border-radius: var(--img-radius); object-fit: cover; }
@media (min-width: 768px) {
  .two-col { grid-template-columns: 1fr 1fr; column-gap: var(--col-gap); }
  /* Single card (card 2 hidden): span the full usable width. */
  .two-col--single { grid-template-columns: 1fr; }
}
/* OVERLAY text position — the former 'Stimmen' treatment: text sits over a
   bottom gradient on the image, in light type. */
.two-col__card--overlay { position: relative; gap: 0; overflow: hidden; border-radius: var(--img-radius); }
.two-col__card--overlay .two-col__img { border-radius: 0; display: block; }
.two-col__grad { position: absolute; inset: 0; background: linear-gradient(to bottom, transparent 35%, rgba(42,37,32,0.4) 60%, rgba(42,37,32,0.95) 100%); }
.two-col__card--overlay .two-col__text { position: absolute; bottom: 0; left: 0; right: 0; padding: var(--space-sm) var(--space-md); color: rgba(255,255,255,0.92); }
.two-col__card--overlay .two-col__text .label,
.two-col__card--overlay .two-col__text h3 { color: #fff; }
.two-col__card--overlay .btn--outline { color: #fff; border-color: rgba(255,255,255,0.7); }



/* --------------------------------------------------------
   STATS ROW
-------------------------------------------------------- */
.archive-stats { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--space-sm); margin-bottom: var(--space-md); }
.archive-stat__number {
  font-family: var(--display); font-size: clamp(1.4rem, 3vw, 1.9rem); font-weight: 700;
  line-height: 1; color: var(--brand-blue-deep); margin-bottom: 0.25rem;
}
.archive-stat__label { font-size: 0.85rem; color: var(--brand-blue-deep); }
@media (min-width: 600px) {
  .archive-stats { grid-template-columns: repeat(4, 1fr); }
}

.archive-year + .archive-year { margin-top: 25px; }
.archive-year__list { list-style: none; padding-left: 0; margin: 0; }
.archive-row { margin-top: 10px; }
.archive-row__venue { font-style: italic; }

.rb-subnav {
  font-size: 0.95rem;
  margin-bottom: var(--space-md);
  color: var(--brand-blue-deep);
}
.rb-subnav__link { color: inherit; text-decoration: none; }
.rb-subnav__link:hover { text-decoration: underline; }
.rb-subnav__link--active { color: var(--brand-blue-deep); font-weight: 600; }
.rb-subnav__sep { margin: 0 0.5rem; opacity: 0.4; }

.rb-search {
  display: flex;
  gap: 0.5rem;
  align-items: center;
  margin-bottom: 0.5rem;
  flex-wrap: wrap;
}
.rb-search__input {
  flex: 1 1 220px;
  min-width: 0;
  padding: 0.4rem 0.6rem;
  font: inherit;
  border: 1px solid var(--border, #ccc);
  border-radius: 999px;
  background: var(--brand-yellow);
  color: inherit;
}
.rb-search__input:focus { outline: 2px solid var(--brand-blue-deep); outline-offset: 1px; }
.rb-search__btn {
  height: 2rem;
  padding: 0 1rem;
  border-radius: 999px;
  border: 1px solid currentColor;
  background: transparent;
  color: inherit;
  font: inherit;
  cursor: pointer;
  white-space: nowrap;
}
.rb-search__btn:hover { background: var(--brand-blue-deep); color: var(--brand-yellow); }
.rb-note { color: var(--brand-blue-deep); font-size: 0.9rem; margin-top: var(--space-md); }

/* ── Geschichte axis-tree: one accordion for every history lens ───────────── */
/* Expand/collapse toolbar (axis-tree-controls.js) — sits above the tree. */
.axis-tree-controls {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem;
  margin: 0.25rem 0 0.6rem;
}
.axis-tree-controls__label {
  font-size: 0.85rem;
  color: var(--brand-blue-deep);
  margin-right: 0.1rem;
}
.axis-tree-controls__btn {
  font: inherit;
  font-size: 0.85rem;
  line-height: 1.4;
  padding: 0.1rem 0.6rem;
  border: 1px solid var(--share-border, rgba(1, 58, 133, 0.4));
  border-radius: 999px;
  background: transparent;
  color: var(--brand-blue-deep);
  cursor: pointer;
}
.axis-tree-controls__btn:hover { background: var(--share-hover-bg, rgba(1, 58, 133, 0.06)); }

.axis-tree { margin-top: var(--space-sm); }
.axis-tree__spine {
  border-top: 1px solid var(--share-border, rgba(1, 58, 133, 0.22));
  scroll-margin-top: 3.5rem;
}
.axis-tree__spine:last-child { border-bottom: 1px solid var(--share-border, rgba(1, 58, 133, 0.22)); }

.axis-tree__spine-summary,
.axis-tree__entity-summary {
  cursor: pointer;
  list-style: none;
  display: flex;
  align-items: baseline;
  gap: 0.45rem;
}
.axis-tree__spine-summary::-webkit-details-marker,
.axis-tree__entity-summary::-webkit-details-marker { display: none; }
/* Disclosure caret (rotates when open) — mirrors the CMS .cms-block pattern. */
.axis-tree__spine-summary::before,
.axis-tree__entity-summary::before {
  content: '▸';
  flex: 0 0 auto;
  font-size: 0.7em;
  color: var(--brand-blue-deep);
  transition: transform 0.15s;
}
.axis-tree__spine[open] > .axis-tree__spine-summary::before,
.axis-tree__entity[open] > .axis-tree__entity-summary::before { transform: rotate(90deg); }

.axis-tree__spine-summary {
  font-family: var(--display);
  font-weight: 600;
  font-size: 1.15rem;
  padding: 0.55rem 0;
  color: var(--brand-blue-deep);
}
.axis-tree__spine-summary a { color: inherit; text-decoration: none; }
.axis-tree__spine-summary a:hover { text-decoration: underline; }

.axis-tree__items { list-style: none; margin: 0 0 0.5rem; padding: 0 0 0 1.1rem; }
.axis-tree__entity { border-bottom: 1px solid var(--border, rgba(0, 0, 0, 0.07)); }
.axis-tree__entity-summary { padding: 0.3rem 0; font-size: 1rem; }

.axis-tree__leaves {
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
  padding: 0.2rem 0 0.6rem 1.1rem;
}
.axis-tree__leaf { text-decoration: none; color: inherit; }
.axis-tree__leaf:hover { text-decoration: underline; }
.axis-tree__leaf-year { color: var(--brand-blue-deep); font-variant-numeric: tabular-nums; margin-right: 0.35rem; }
.axis-tree__profile { display: inline-block; margin-bottom: 0.3rem; font-size: 0.85rem; color: var(--brand-blue-deep); }
.axis-tree__lifespan { color: var(--brand-blue-deep); font-weight: normal; font-size: 0.8em; }
.axis-tree .rb-count { color: var(--brand-blue-deep); font-size: 0.8em; font-weight: normal; }
/* Chronological leaves are full archive rows; works leaves keep their layout. */
.axis-tree__items > .archive-row { margin: 0.4rem 0; }
/* Chronological "Produktionen" view hides the inline works lines; the
   "Produktionen und Werke" button shows them again (axis-tree-controls.js). */
.axis-tree--hide-works .archive-row__program { display: none; }
/* /geschichte/werke — "nur Chorwerke" hides works never performed chorally
   (every occurrence flagged non_choral); "alle Werke" / Zuklappen show all. */
.axis-tree--choral-only .repertoire-work--non-choral { display: none; }
.axis-tree__spine--empty { display: none; }

/* /geschichte/werke — catalog of works grouped by composer */
.repertoire-works {
  list-style: none;
  padding: 0;
  margin: 0;
}
.repertoire-work {
  padding: 0.25rem 0;
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  align-items: baseline;
  border-bottom: 1px solid var(--border, #eee);
}
.repertoire-work__title { flex: 1; min-width: 60%; }
.repertoire-work__count { color: var(--brand-blue-deep); font-size: 0.85em; }
.repertoire-work__years { color: var(--brand-blue-deep); font-size: 0.9em; }
.repertoire-work__years a { color: inherit; text-decoration: none; }
.repertoire-work__years a:hover { color: var(--brand-blue-deep); text-decoration: underline; }

.concerts-listing > * + * { margin-top: 25px; }

/* --------------------------------------------------------
   TABLE LIST
-------------------------------------------------------- */
.archive-highlight {
  display: grid; grid-template-columns: 1fr; gap: 0;
}
.archive-item { display: flex; gap: var(--space-md); padding: var(--space-sm) var(--space-md); border-bottom: 1px solid rgba(0,0,0,0.06); }
.archive-item--link { text-decoration: none; color: inherit; }
.archive-item--link:hover { background: rgba(160,120,44,0.06); }
.archive-item:last-child { border-bottom: none; }
.archive-item:nth-child(even) { background: rgba(0,0,0,0.02); }
.archive-item__key { font-family: var(--display); font-size: 1rem; font-weight: 600; color: var(--brand-blue-deep); min-width: 2.8rem; flex-shrink: 0; }
.archive-item__value { font-size: 0.9rem; flex: 1; color: var(--brand-blue-deep); }

.archive-highlight--compact .archive-item { padding-top: calc(var(--space-sm) / 4); padding-bottom: calc(var(--space-sm) / 4); }

/* Table variant (table-list block): one row per item, key right-aligned,
   value left-aligned — keys line up cleanly across the column. */
.archive-highlight--table { display: table; width: 100%; border-collapse: collapse; gap: 0; }
.archive-highlight--table .archive-item {
  display: table-row;
  padding: 0;
  border-bottom: 0;
  background: transparent;
  gap: 0;
}
.archive-highlight--table .archive-item__key,
.archive-highlight--table .archive-item__value {
  display: table-cell;
  padding: calc(var(--space-sm) / 2) var(--space-md);
  vertical-align: top;
}
/* width:1% = shrink-to-fit, so the value column gets the rest. Keys don't
   break by default (their spaces are glued to &nbsp; in render); a "|" the
   editor inserts becomes a <wbr> responsive break point for long keys. */
.archive-highlight--table .archive-item__key { text-align: right; min-width: 0; width: 1%; }
.archive-highlight--table .archive-item__value { text-align: left; }

/* --------------------------------------------------------
   RICH TEXT
-------------------------------------------------------- */
.rich-text p { margin-bottom: var(--space-sm); }
.rich-text p:last-child { margin-bottom: 0; }
/* rte-klein is an RTE-only class — apply it everywhere RTE bodies render (Fliesstext,
   Karten-Bodies, Spielort-Info …), not only inside .rich-text wrappers. */
p.rte-klein { font-size: calc(1rem - 2pt); }
.rich-text h2, .rich-text h3, .rich-text h4 {
  font-family: var(--display);
  margin-top: var(--space-md);
  margin-bottom: var(--space-xs);
}
.rich-text h2:first-child, .rich-text h3:first-child, .rich-text h4:first-child { margin-top: 0; }
/* Hanging indent: the marker is pinned at the block's left edge (aligned with
   the text/headings above), the item text is indented, and wrapped lines align
   under the text rather than under the marker. */
.rich-text ul, .rich-text ol { margin: 0 0 var(--space-sm); padding-left: 0; list-style: none; }
.rich-text ul:last-child, .rich-text ol:last-child { margin-bottom: 0; }
.rich-text li { position: relative; padding-left: 1.3em; }
.rich-text ul > li::before { content: "•"; position: absolute; left: 0.2em; }
.rich-text ol { counter-reset: rte-ol; }
.rich-text ol > li { counter-increment: rte-ol; }
.rich-text ol > li::before { content: counter(rte-ol) "."; position: absolute; left: 0; }

/* Collapsible (<details>) inside rich text — the <summary> acts as a tappable
   sub-heading. */
.rich-text details { margin: 0 0 var(--space-sm); }
.rich-text details:last-child { margin-bottom: 0; }
.rich-text summary { cursor: pointer; font-weight: 700; color: var(--brand-blue-deep); }
.rich-text summary:hover { color: var(--link-hover); }
.rich-text details[open] > summary { margin-bottom: var(--space-sm); }

/* flow-root contains floats so a tall figure at block bottom can't drag the
   next block's text into its margin. */
.rich-text { display: flow-root; }
.rte-figure { margin: 0; }
.rte-figure img { width: 100%; height: auto; display: block; }
.rte-figure figcaption {
  font-size: 0.85rem;
  color: var(--brand-blue-deep);
  padding-top: 0.4rem;
  font-style: italic;
}
.rte-figure--float-left  { float: left;  margin: 0.25rem 1.5rem 0.75rem 0; }
.rte-figure--float-right { float: right; margin: 0.25rem 0 0.75rem 1.5rem; }
.rte-figure--inline      { clear: both;  margin: var(--space-md) 0; }
.rte-figure--w-25 { width: 25%; }
.rte-figure--w-33 { width: 33%; }
.rte-figure--w-50 { width: 50%; }

/* Aspect-ratio overrides — applied to the img so the figcaption keeps natural
   height. Without one of these the image's intrinsic ratio is used. */
.rte-figure--ar-1-1   img,
.rte-figure--ar-3-4   img,
.rte-figure--ar-4-3   img,
.rte-figure--ar-3-2   img,
.rte-figure--ar-16-9  img { object-fit: cover; }
.rte-figure--ar-1-1   img { aspect-ratio: 1 / 1;  }
.rte-figure--ar-3-4   img { aspect-ratio: 3 / 4;  }
.rte-figure--ar-4-3   img { aspect-ratio: 4 / 3;  }
.rte-figure--ar-3-2   img { aspect-ratio: 3 / 2;  }
.rte-figure--ar-16-9  img { aspect-ratio: 16 / 9; }

@media (max-width: 600px) {
  .rte-figure--float-left,
  .rte-figure--float-right { float: none; width: 100%; margin: var(--space-md) 0; }
}

/* --------------------------------------------------------
   BUTTONS
-------------------------------------------------------- */
.btn {
  display: inline-flex; align-items: center; gap: 0.5rem;
  font-family: var(--sans); font-size: 0.85rem; font-weight: 600;
  letter-spacing: 0.06em; text-transform: uppercase;
  height: 2rem; padding: 0 1.2rem; box-sizing: border-box; line-height: 1;
  /* transparent border keeps the box-height identical between filled and
     outline variants so they line up next to .share-trigger pills. */
  border: 1px solid transparent; border-radius: 999px;
  cursor: pointer; text-decoration: none;
  transition: background 0.2s, transform 0.15s;
}
.btn:hover { text-decoration: none; transform: translateY(-1px); }
.btn--primary { background: var(--brand-blue-deep); color: var(--white); border-color: var(--brand-blue-deep); }
.btn--primary:hover { background: var(--brand-blue-deep); border-color: var(--brand-blue-deep); }
.btn--outline { background: transparent; color: var(--brand-blue-deep); border-color: var(--brand-blue-deep); }
.btn--outline:hover { background: var(--brand-blue-deep); border-color: var(--brand-blue-deep); color: var(--white); }
.btn--light { background: rgba(255,255,255,0.15); color: var(--white); border-color: rgba(255,255,255,0.4); }
.btn--light:hover { background: rgba(255,255,255,0.25); }
.btn-group { display: flex; flex-wrap: wrap; gap: var(--space-sm); margin-top: var(--space-sm); }

/* --------------------------------------------------------
   SEPARATOR
-------------------------------------------------------- */
.sep { width: 3rem; height: 1px; background: var(--brand-blue-deep); border: none; margin: var(--space-sm) 0; }
.sep--center { margin-left: auto; margin-right: auto; }

/* --------------------------------------------------------
   MAP BLOCK (public)
-------------------------------------------------------- */
.map-block {
  overflow: hidden;
  margin-top: var(--space-sm);
}
.map-block__placeholder { padding: 0; }
.map-block__canvas[hidden] ~ .map-block__list { display: none; }
.map-block__address { font-size: 1rem; line-height: 1.5; }
.map-block__load {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  margin-left: 0.5rem;
  padding: 0.15rem 0.6rem;
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--brand-blue-deep);
  background: transparent;
  border: 1px solid var(--brand-blue-deep);
  border-radius: 2px;
  cursor: pointer;
  font-family: inherit;
  vertical-align: baseline;
}
.map-block__load:hover { background: var(--brand-blue-deep); color: #fff; }
.map-block__canvas { width: 100%; height: 24rem; }
.map-block {
  position: relative;
}
.map-block__close {
  position: absolute;
  top: 0.5rem;
  right: 0.5rem;
  z-index: 1000;
  width: 2rem;
  height: 2rem;
  border: none;
  border-radius: 50%;
  background: rgba(16, 33, 70, 0.85);
  color: #fff;
  font-size: 1rem;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  box-shadow: 0 2px 4px rgba(0,0,0,0.2);
}
.map-block__close:hover { background: var(--brand-navy); }
.map-block__close[hidden] { display: none; }
.map-block__list {
  padding: var(--space-sm) var(--space-md);
  border-top: 1px solid rgba(0,0,0,0.08);
  font-size: 0.9rem;
}
.map-block__list strong { display: block; margin-bottom: var(--space-xs); color: var(--brand-blue-deep); text-transform: uppercase; font-size: 0.75rem; letter-spacing: 0.08em; }
.map-block__list ul { list-style: none; padding: 0; margin: 0; }
.map-block__list li { display: flex; align-items: baseline; gap: 0.5rem; padding: 0.15rem 0; }
.map-block__list strong { display: inline; margin: 0; color: var(--brand-blue-deep); text-transform: none; font-size: inherit; letter-spacing: 0; }
.map-block__list__type { font-weight: 600; color: var(--brand-blue-deep); display: none; }

/* Venue-scoped external links — appears as a subline under the venue address
   in the performance list. Inline header so the whole thing fits on one line. */
.venue-links {
  margin-top: 0.15rem;
  font-size: 0.82rem;
  color: var(--brand-blue-deep);
}
.venue-links strong {
  color: var(--brand-blue-deep);
  text-transform: uppercase;
  font-size: 0.72rem;
  letter-spacing: 0.06em;
  margin-right: 0.4rem;
}
.venue-links p { display: inline; margin: 0; }

/* Pin styles live in /components/map-widget/map-pin.css, linked
   conditionally by render.ts when a page uses a map block. */

.map-list__type { display: inline-block; width: 0.7rem; height: 0.7rem; border-radius: 50%; margin-right: 0.25rem; }
.map-list__type--venue    { background: var(--brand-blue); }
.map-list__type--parking  { background: #2c5e8a; }
.map-list__type--transit  { background: #3a7a50; }
.map-list__type--entrance { background: #e07b20; }
.map-list__type--info     { background: #6b7280; }

/* --------------------------------------------------------
   CONTACTS GRID (contacts block)
-------------------------------------------------------- */
.contacts-grid {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-md);
}
.contact-card {
  padding: var(--space-md) 0;
  flex: 1 1 350px;
  max-width: 350px;
}
.contact-card h3 {
  font-size: 1rem;
  color: var(--brand-blue-deep);
  margin-bottom: var(--space-xs);
}
.image-links {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(9rem, 1fr));
  gap: var(--space-md);
  margin-top: var(--space-sm);
}
.image-link {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-xs);
  text-decoration: none;
  color: var(--brand-blue-deep);
  padding: var(--space-xs);
  border-radius: 2px;
  transition: background 0.15s;
  height: 7rem;
}
a.image-link:hover { background: rgba(0,0,0,0.04); text-decoration: none; }

/* Boxed variant: each tile sits on a solid background (e.g. white for sponsor
   logos) with very slightly rounded corners. Colour comes from --image-link-bg. */
.image-links--boxed .image-link {
  background: var(--image-link-bg, #fff);
  border-radius: 4px;
  padding: var(--space-sm);
}
.image-links--boxed a.image-link:hover {
  background: var(--image-link-bg, #fff);
  filter: brightness(0.96);
}
.image-link__img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
  object-position: center;
}
.image-link__caption {
  font-size: 0.85rem;
  text-align: center;
  color: var(--brand-blue-deep);
  flex-shrink: 0;
}
.image-link:has(.image-link__caption) { height: auto; min-height: 7rem; }
.image-link:has(.image-link__caption) .image-link__img { height: 5rem; flex: 1; }

/* Wider logos (ratio ≥ 1.7, tagged by /js/image-links.js) span 2 grid columns */
.image-link--wide { grid-column: span 2; }
@media (max-width: 500px) {
  .image-link--wide { grid-column: span 1; }
}

/* "Gleich grosse Kacheln": every IMAGE is forced to 3:2 (object-fit:contain, so
   nothing is cropped) and the card wraps it plus padding — so all cards end up
   the same size. Wide logos no longer span two columns. NB: putting aspect-ratio
   on the CARD alone didn't work — the inner img's height:100% resolves to its
   intrinsic height and inflates the card back to the logo's own aspect, so the
   3:2 box has to live on the IMG. */
.image-links--square .image-link--wide { grid-column: span 1; }
.image-links--square .image-link {
  height: auto;
  min-height: 0;
  padding: 5px;
}
.image-links--square .image-link__img,
.image-links--square .image-link:has(.image-link__caption) .image-link__img {
  aspect-ratio: 3 / 2;
  width: 100%;
  height: auto;
  flex: none;
}

/* Image-grid block — responsive auto-fill grid with optional uniform aspect
   ratio. Tile aspect-ratio is set via inline style on the <a> (so the editor
   can change it per block); focal-point via object-position on the <img>. */
.image-grid {
  display: grid;
  gap: var(--space-sm, 0.75rem);
  margin: var(--space-sm) 0 var(--space-md);
}
.image-grid__link {
  display: block;
  overflow: hidden;
  border-radius: 2px;
  background: rgba(0, 0, 0, 0.04);
  cursor: zoom-in;
}
.image-grid__img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: var(--img-radius);
  /* `aspect-ratio` on the link gives a fixed-shape tile and the img fills it.
     When the link has no aspect-ratio (natural mode), height:auto is forced
     below so images keep their natural proportions. */
}
.image-grid__link:not([style*="aspect-ratio"]) .image-grid__img {
  height: auto;
  object-fit: contain;
}

.contact-card__photo {
  display: block;
  width: 5rem; height: 5rem;
  object-fit: cover;
  border-radius: 50%;
  margin-bottom: var(--space-sm);
}
.contact-card__name { font-weight: 600; margin-bottom: var(--space-xs); }
.contact-card p { font-size: 0.9rem; line-height: 1.5; margin-bottom: 0.15rem; }
.contact-card a { color: var(--brand-blue-deep); }
.contact-card a:hover { color: var(--brand-blue-deep); }

/* --------------------------------------------------------
   FOOTER
-------------------------------------------------------- */
.footer {
  background: var(--dark);
  color: rgba(255,255,255,0.5);
  padding: var(--space-sm) 0;
  font-size: 0.8rem;
}
.footer a { color: rgba(255,255,255,0.5); }
.footer a:hover { color: var(--white); }
.footer__bottom {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: var(--space-sm);
}

/* Prev/next concert navigation — overlays the hero's darkened bottom gradient */
/* Prev/next concert nav now sits in normal flow at the top of the heroless
   concert-detail page (on the yellow field), not overlaid on a dark hero. */
.concert-nav {
  color: var(--brand-blue-deep);
}
.concert-nav__row {
  display: flex;
  justify-content: space-between;
  align-items: stretch;
  gap: var(--space-md);
  padding: var(--space-sm) var(--space-sm) 0;
}
@media (min-width: 768px) {
  .concert-nav__row { padding: var(--space-sm) var(--space-md) 0; }
}
.concert-nav__cell {
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
  text-decoration: none;
  color: inherit;
  min-width: 0;
  flex: 1 1 0;
  padding: 0.35rem 0.25rem;
}
.concert-nav__cell--right {
  text-align: right;
  align-items: flex-end;
}
.concert-nav__cell--empty { visibility: hidden; }
.concert-nav__cell:hover .concert-nav__summary { text-decoration: underline; }
.concert-nav__label {
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}
.concert-nav__summary {
  font-size: 0.95rem;
  font-weight: 500;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  width: 100%;
  max-width: 100%;
  display: block;
}
.concert-nav__cell--right .concert-nav__summary { text-align: right; }

/* Concert photo gallery — uniform height, wrapping row, click to open lightbox */
.concert-photos {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-sm);
  margin: var(--space-sm) 0;
}
.concert-photos__item {
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
}
.concert-photos__link {
  display: block;
  cursor: zoom-in;
  line-height: 0;
}
.concert-photos__item img {
  height: 150px;
  width: auto;
  max-width: 100%;
  object-fit: cover;
  border-radius: 2px;
  transition: transform 0.15s ease;
}
.concert-photos__link:hover img { transform: translateY(-2px); }
.concert-photos__item figcaption {
  font-size: 0.85rem;
  color: var(--color-muted, #666);
}

/* Lightbox overlay */
.lightbox {
  position: fixed;
  inset: 0;
  background: rgba(0,0,0,0.9);
  display: none;
  align-items: center;
  justify-content: center;
  z-index: 9999;
}
.lightbox.open { display: flex; }
.lightbox__img {
  max-width: 92vw;
  max-height: 88vh;
  object-fit: contain;
  box-shadow: 0 8px 40px rgba(0,0,0,0.6);
}
.lightbox__caption {
  position: absolute;
  bottom: 1rem;
  left: 50%;
  transform: translateX(-50%);
  color: #fff;
  background: rgba(0,0,0,0.55);
  padding: 0.4rem 0.8rem;
  border-radius: 3px;
  font-size: 0.9rem;
  max-width: 80vw;
  text-align: center;
}
.lightbox__btn {
  position: absolute;
  background: rgba(0,0,0,0.5);
  color: #fff;
  border: 0;
  font-size: 1.8rem;
  line-height: 1;
  width: 3rem;
  height: 3rem;
  border-radius: 50%;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
}
.lightbox__btn:hover { background: rgba(0,0,0,0.75); }
.lightbox__btn--prev { left: 1rem; top: 50%; transform: translateY(-50%); }
.lightbox__btn--next { right: 1rem; top: 50%; transform: translateY(-50%); }
.lightbox__btn--close { right: 1rem; top: 1rem; font-size: 1.4rem; }

/* Composer info — eye icon button + modal */
.composer-info {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  vertical-align: baseline;
  background: transparent;
  border: 0;
  padding: 0 0.15rem;
  margin-left: 0.15rem;
  color: var(--brand-blue-deep);
  cursor: pointer;
  line-height: 1;
  border-radius: 2px;
  transition: color 0.15s;
}
.composer-info:hover,
.composer-info:focus-visible {
  color: var(--brand-blue-deep);
  outline: none;
}
.composer-modal {
  position: fixed;
  inset: 0;
  background: rgba(0,0,0,0.6);
  display: none;
  align-items: center;
  justify-content: center;
  z-index: 9999;
  padding: 1rem;
}
.composer-modal.open { display: flex; }
.composer-modal__box {
  position: relative;
  background: var(--brand-yellow);
  color: var(--brand-blue-deep);
  max-width: 640px;
  width: 100%;
  max-height: 85vh;
  overflow-y: auto;
  padding: var(--space-md, 1.5rem);
  border-radius: 3px;
  box-shadow: 0 8px 40px rgba(0,0,0,0.4);
}
.composer-modal__close {
  position: absolute;
  top: 0.5rem;
  right: 0.5rem;
  background: transparent;
  border: 0;
  font-size: 1.6rem;
  line-height: 1;
  width: 2rem;
  height: 2rem;
  cursor: pointer;
  color: var(--brand-blue-deep);
}
.composer-modal__close:hover { color: var(--brand-blue-deep); }
.composer-modal__content h2 { margin-top: 0; }
.composer-modal__content p { margin: 0 0 0.75rem; }
.composer-modal__content ul { margin: 0 0 0.75rem 1.25rem; }

/* Intern-access block — "Interne Funktionen" button on /internals */
.intern-access-block {
  text-align: center;
  margin: var(--space-md, 1.5rem) 0;
}
.intern-access-block__intro {
  margin-bottom: var(--space-sm, 0.75rem);
}

/* Intern-access modal — email + 6-digit-code login without leaving /internals */
.intern-access-modal {
  position: fixed;
  inset: 0;
  background: rgba(0,0,0,0.6);
  display: none;
  align-items: center;
  justify-content: center;
  z-index: 9999;
  padding: 1rem;
}
.intern-access-modal.open { display: flex; }
.intern-access-modal__box {
  position: relative;
  background: var(--brand-yellow);
  color: var(--brand-blue-deep);
  max-width: 22rem;
  width: 100%;
  max-height: 85vh;
  overflow-y: auto;
  padding: var(--space-md, 1.5rem);
  border-radius: 3px;
  box-shadow: 0 8px 40px rgba(0,0,0,0.4);
}
.intern-access-modal__close {
  position: absolute;
  top: 0.5rem;
  right: 0.5rem;
  background: transparent;
  border: 0;
  font-size: 1.6rem;
  line-height: 1;
  width: 2rem;
  height: 2rem;
  cursor: pointer;
  color: var(--brand-blue-deep);
}
.intern-access-modal__close:hover { color: var(--brand-blue-deep); }
.intern-access-modal__title { margin: 0 0 0.25rem; }
.intern-access-modal__intro {
  margin: 0 0 1rem;
  color: var(--brand-blue-deep);
  font-size: 0.9rem;
}
.intern-access-modal__box label {
  display: block;
  font-size: 0.85rem;
  margin-bottom: 0.25rem;
  color: var(--brand-blue-deep);
}
.intern-access-modal__box input[type="email"],
.intern-access-modal__box input[type="text"] {
  width: 100%;
  padding: 0.5rem 0.6rem;
  border: 1px solid #d4d4d4;
  border-radius: 3px;
  font-size: 1rem;
  font-family: inherit;
  box-sizing: border-box;
}
.intern-access-modal__submit { width: 100%; margin-top: 1rem; }
.intern-access-modal__alt {
  margin-top: 1rem;
  font-size: 0.85rem;
  text-align: center;
  color: var(--brand-blue-deep);
}
.intern-access-modal__alt a { color: inherit; }
.intern-access-modal__note {
  margin-top: 1.5rem;
  font-size: 0.8rem;
  color: var(--brand-blue-deep);
}
.intern-access-modal__msg {
  margin: 0 0 0.75rem;
  padding: 0.5rem 0.6rem;
  border-radius: 3px;
  font-size: 0.85rem;
}
.intern-access-modal__msg--ok { background: #ecfdf5; color: #065f46; }
.intern-access-modal__msg--err { background: #fef2f2; color: #991b1b; }

/* PDF thumbnails — displayed inline with program/Programmheft links and press items */
.pdf-cards {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-md);
  margin: var(--space-sm) 0;
}
.pdf-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.4rem;
  text-decoration: none;
  color: inherit;
  min-width: 140px;
  max-width: 280px;
  font-size: 0.9rem;
  text-align: center;
}
.pdf-card__thumb {
  height: 180px;
  width: auto;
  max-width: 100%;
  object-fit: contain;
  border-radius: var(--img-radius);
  transition: transform 0.15s ease;
}
.pdf-card:hover .pdf-card__thumb {
  transform: translateY(-2px);
}
.pdf-card__thumb--icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 140px;
  font-size: 3rem;
}
.pdf-card__label { font-weight: 500; }

.press-list .press-item {
  display: flex;
  gap: var(--space-md);
  /* Entries separated by space, not a divider line — the 1px rule read as a
     whitish line on the navy blue zone. */
  margin-bottom: var(--space-lg);
  list-style: none;
}
.press-list .press-item:last-child { margin-bottom: 0; }
.press-item__thumb {
  flex: 0 0 auto;
  display: block;
}
.press-item__thumb img {
  width: 110px;
  height: 140px;
  object-fit: cover;
  object-position: top center;
  transition: transform 0.15s ease;
}
.press-item__thumb:hover img { transform: translateY(-2px); }
.press-item__body { flex: 1 1 auto; min-width: 0; }
.press-item__meta { opacity: 0.75; font-size: 0.9rem; }
.press-item__title { font-weight: 600; margin: 0.15rem 0 0.4rem; }
.press-item__excerpt { margin: 0; font-style: italic; opacity: 0.9; }

/* Press card retains fixed-aspect crop (article previews look better cropped). */
.press-item__thumb--wide img {
  width: 200px;
  height: 140px;
  object-position: center;
}

/* Performances list on production detail page */
.perf-list {
  list-style: none;
  margin: 0 0 var(--space-md);
  padding: 0;
}
.perf-list__item {
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
  /* Entries separated by space, not a divider line (whitish on the blue zone). */
  margin-bottom: var(--space-lg);
}
.perf-list__row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-xs) var(--space-md);
  align-items: center;
}
/* Reset the base .map-block styling that is intended for the standalone
   map block (on dedicated pages) — the inline variant is just a pill
   button sitting in a flex row with the share trigger. */
.map-block--inline {
  background: transparent;
  border-radius: 0;
  overflow: visible;
  margin-top: 0;
}
/* The inline Karte button uses the shared .share-trigger pill style (from
   Component Library's share.css). Reset the base .map-block__load heavy
   accent look that would otherwise override. */
.map-block--inline .map-block__load {
  margin-left: 0;
  color: inherit;
}
/* When the canvas is revealed, break the inline map-block onto its own row
   and hide the Karte button (maps.js no longer has a placeholder to toggle). */
.map-block--inline:has(.map-block__canvas:not([hidden])) {
  flex-basis: 100%;
  width: 100%;
  margin-top: var(--space-xs);
}
.map-block--inline:has(.map-block__canvas:not([hidden])) .map-block__load {
  display: none;
}
/* Karte + Merken & Teilen on a second line below date/venue. */
.perf-list__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-xs);
  margin-top: 1rem;
}
.perf-list__item:last-child { margin-bottom: 0; }
.perf-list__date { font-weight: 600; }
.perf-list__venue { color: var(--brand-blue-deep); }
.perf-list__badge {
  display: inline-block;
  padding: 0.1rem 0.5rem;
  border-radius: 0.25rem;
  font-size: 0.8rem;
  font-weight: 600;
}
.perf-list__badge--cancelled { background: #fdecea; color: #b71c1c; }
.perf-list__badge--postponed { background: #fff4e5; color: #8a5a00; }

/* Share trigger placement on concert detail pages (share component itself
   lives in Component Library). The concert template puts the trigger inline
   with the Karte button in .perf-list__actions — no extra margin needed. */

/* Venue gallery — large hero + thumbnail strip with click-to-swap */
.venue-gallery {
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
  margin-bottom: var(--space-xs);
}

/* Performer detail page photo gallery — flowing grid of figures, sized for
   portraits. First image gets a wider span on desktop. */
.performer-gallery {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
  gap: var(--space-sm);
  margin-bottom: var(--space-md);
}
.performer-gallery__item {
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
}
.performer-gallery__item img {
  width: 100%;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  border-radius: 3px;
  background: var(--brand-yellow);
  display: block;
}
.performer-gallery__item figcaption {
  font-size: 0.78rem;
  color: var(--brand-blue-deep);
  font-style: italic;
}
.venue-gallery__hero {
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  border-radius: var(--img-radius);
  display: block;
}
/* Cap the gallery (hero + thumbs) so the large image doesn't dominate the page:
   on the Spielort detail, and in the Aufführungen list of upcoming concerts
   (past concerts don't render a gallery at all). */
.venue-detail-media .venue-gallery,
.perf-list .venue-gallery { max-width: 400px; }
.venue-gallery__thumbs {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  gap: var(--space-xs);
  overflow-x: auto;
}
.venue-gallery__thumbs li { flex: 0 0 auto; }
.venue-gallery__thumb {
  width: 6.25rem;
  height: 4.25rem;
  padding: 0;
  border: 2px solid transparent;
  border-radius: 3px;
  background: none;
  cursor: pointer;
  overflow: hidden;
  transition: border-color .12s, opacity .12s;
  opacity: 0.75;
}
.venue-gallery__thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.venue-gallery__thumb:hover { opacity: 1; }
.venue-gallery__thumb.is-active {
  border-color: var(--brand-blue-deep);
  opacity: 1;
}

/* Geschichte detail-page "mehr / weniger zeigen" toggle */
.rb-details-toggle {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  background: transparent;
  border: none;
  padding: 0.2rem 0;
  margin: 0 0 var(--space-sm);
  font: inherit;
  font-size: 0.88rem;
  color: var(--brand-blue-deep);
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 0.18em;
}
.rb-details-toggle:hover { color: var(--brand-blue-deep); }
.rb-details-toggle .rb-details-toggle__more { display: none; }
.rb-details-toggle .rb-details-toggle__less { display: inline; }
.rb-details-toggle[aria-expanded="false"] .rb-details-toggle__more { display: inline; }
.rb-details-toggle[aria-expanded="false"] .rb-details-toggle__less { display: none; }

/* Venue-info block: optional hero / map / Anfahrt / gallery / links combined
   into one configurable block. `--two-col` splits media (left) from facts (right)
   on viewports >= 50rem; otherwise media stacks above facts. */
.venue-info { display: flex; flex-direction: column; gap: var(--space-sm); margin: var(--space-md) 0; }
.venue-info__media { display: flex; flex-direction: column; gap: var(--space-xs); min-width: 0; }
.venue-info__hero {
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  border-radius: var(--img-radius);
  border-radius: 4px;
  display: block;
}
.venue-info__facts { display: flex; flex-direction: column; gap: var(--space-xs); min-width: 0; }
.venue-info__address { margin: 0; font-size: 1rem; line-height: 1.5; }
.venue-info__links { list-style: none; padding: 0; margin: 0; display: flex; flex-wrap: wrap; gap: 0.4rem 1rem; }
.venue-info__links li::before { content: "→ "; color: var(--brand-blue-deep); }
.venue-info__links a { text-decoration: none; }
.venue-info__links a:hover { text-decoration: underline; }
@media (min-width: 50rem) {
  .venue-info--two-col {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    align-items: start;
    gap: var(--space-md);
    column-gap: var(--col-gap);
  }
}

/* --------------------------------------------------------
   Karte + Merken & Teilen pills == regular outline buttons.
   They keep the .share-trigger class (share JS hooks onto it) and the Karte
   keeps .map-block__load, so we override with higher-specificity selectors —
   and place this last so it also wins source order over the later-loaded
   Component Library share.css.
-------------------------------------------------------- */
button.share-trigger,
.map-block__load.share-trigger {
  display: inline-flex; align-items: center; gap: 0.5rem;
  font-family: var(--sans); font-size: 0.85rem; font-weight: 600;
  letter-spacing: 0.06em; text-transform: uppercase;
  height: 2rem; padding: 0 1.2rem; box-sizing: border-box; line-height: 1;
  border: 1px solid var(--brand-blue-deep); border-radius: 999px;
  background: transparent; color: var(--brand-blue-deep);
  cursor: pointer; text-decoration: none;
  transition: background 0.2s, transform 0.15s;
}
button.share-trigger:hover,
.map-block__load.share-trigger:hover {
  background: var(--brand-blue-deep); color: var(--white); border-color: var(--brand-blue-deep);
  transform: translateY(-1px);
}
.zone--blue button.share-trigger:hover,
.zone--blue .map-block__load.share-trigger:hover { color: #013A85; }

/* Framed content images — a single shared rule. A light drop shadow lifts the
   image off the field; box-shadow is painted outside the box, so (unlike the
   former border) it doesn't affect layout and the shadow follows each element's
   --img-radius. Covers: Zweispalter (image + overlay wrapped in `.two-col__media`,
   added in render.ts → case 'two-column'), Bildraster tiles, both venue hero
   images, and the featured concert cards (next-concert + concerts-listing). */
.two-col__media,
.image-grid__link,
.venue-gallery__hero,
.venue-info__hero,
.concert-featured__img { box-shadow: 0 4px 14px rgba(0, 0, 0, 0.12); }
.two-col__media {
  position: relative;                       /* positioning context for the overlay grad/text */
  border-radius: var(--img-radius);
  overflow: hidden;
}
.two-col__media .two-col__img { border-radius: 0; }
