/* ==========================================================================
   Site components — depends on tokens.css + base.css being loaded first.
   Surface pairings, layout helpers, and reusable UI components.
   ========================================================================== */

/* ---------- Surfaces ----------
   The old static `.surface--*` wrappers are gone. Surfaces are now the
   per-section palette system in landing.css: `.section--*` sets --section-color
   / --section-fg / --section-accent (and scroll-morphs between sections), the
   consolidated "Dark surfaces" rule there owns the light-on-dark weight
   compensation, and the component button vars (--btn-bg / --btn-fg / …, read
   with fallbacks by .btn--primary below) are set per button (inline or in a
   page rule) where needed. See docs/design-system.md §5. */

/* ---------- Layout containers ----------
   Width helpers from tokens.css. `.container` is the default page width,
   `.container--narrow` for text-heavy sections, `.measure` for individual
   text blocks (65ch). */
.container {
  max-width: var(--container-max);
  margin-inline: auto;
  padding-inline: var(--gutter);
}
.container--narrow {
  max-width: var(--container-narrow);
}
.measure {
  max-width: var(--measure);
}

/* ---------- Stack helpers ----------
   Every-Layout-style vertical-rhythm primitives. .stack uses flex+gap
   (container-style); .stack-flow uses lobotomized-owl margins (works on
   any element without changing display semantics). Both honor a
   --stack-gap override per instance. */
.stack {
  display: flex;
  flex-direction: column;
  gap: var(--stack-gap, var(--space-md));
}
.stack-flow > * + * {
  margin-block-start: var(--stack-gap, var(--space-md));
}

/* ---------- Lead paragraph ---------- */
.lead {
  font-size: var(--text-lead);
  line-height: var(--line-height-base);
  text-wrap: balance;
}

/* ---------- Content list with custom note marker ----------
   Opt-in two ways:
     1. Add `.list` to the `<ul>` directly (handwritten templates).
     2. Wrap Wagtail RichText output in `<div class="rich-text">…</div>` —
        every `<ul>` inside automatically picks up `.list` styling.
   Nav/Footer/UI lists in plain `<ul>` stay neutral. `.list--spark`
   overrides the marker color; light surfaces get a slightly larger
   marker because dark glyphs on light read thinner.

   NOTE: nested lists are out of scope. The flex-based `<li>` layout does
   not handle child `<ul>`s gracefully — disable nested lists in the
   Wagtail RichText feature config (`features=["bold","italic","ul","link"]`
   without "ol" or via custom block restrictions). */
.list,
.rich-text ul {
  display: flex;
  flex-direction: column;
  gap: var(--space-2xs);
}
.list li,
.rich-text ul li {
  display: flex;
  align-items: baseline;
  gap: var(--space-2xs);
  max-width: var(--measure);
}
.list li::before,
.rich-text ul li::before {
  content: "";
  display: inline-block;
  flex-shrink: 0;
  width: var(--list-marker-width, 0.7em);
  height: var(--list-marker-height, 1em);
  margin-inline-start: -0.25em;
  background-color: currentColor;
  /* Inline data-URI avoids file:// CORS issues with mask-image. */
  -webkit-mask: url('data:image/svg+xml;utf8,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 448.88 626.13%22%3E%3Cpath d=%22M233.35,0c3.4,1.8,9.47,3.41,11.38,7.64,8.8,19.52,19.71,36.96,34.2,52.79,35.15,39.13,87.56,70.2,122.03,109.93,87.28,99.05,46.78,209.16-52.8,279.32-9.99,7.28-22.45-1.72-11.1-11.11,160.4-103.39,24.25-202.88-95.07-250.46-3.49,106.35-3.15,211.09-2.97,316.68.45,80.75-85.62,129.34-158.74,120.28-192.6-33.43,4.75-244.24,138.95-155.82,1.17-140.98,2.54-315.08,3.68-455.65-.52-6.79-1.8-10.16,5.44-13.58h4.99Z%22/%3E%3C/svg%3E') center / contain no-repeat;
  mask: url('data:image/svg+xml;utf8,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 448.88 626.13%22%3E%3Cpath d=%22M233.35,0c3.4,1.8,9.47,3.41,11.38,7.64,8.8,19.52,19.71,36.96,34.2,52.79,35.15,39.13,87.56,70.2,122.03,109.93,87.28,99.05,46.78,209.16-52.8,279.32-9.99,7.28-22.45-1.72-11.1-11.11,160.4-103.39,24.25-202.88-95.07-250.46-3.49,106.35-3.15,211.09-2.97,316.68.45,80.75-85.62,129.34-158.74,120.28-192.6-33.43,4.75-244.24,138.95-155.82,1.17-140.98,2.54-315.08,3.68-455.65-.52-6.79-1.8-10.16,5.44-13.58h4.99Z%22/%3E%3C/svg%3E') center / contain no-repeat;
}
.list--spark li::before {
  background-color: var(--color-spark);
}
/* Fallback for Safari < 15.4 / older browsers without mask-image support:
   show a regular disc bullet so list semantics remain visible. */
@supports not (mask: url("")) {
  .list,
  .rich-text ul {
    padding-inline-start: 1.2em;
    list-style: disc inside;
  }
  .list li,
  .rich-text ul li {
    display: list-item;
    align-items: initial;
    gap: 0;
  }
  .list li::before,
  .rich-text ul li::before { content: none; }
  .list li::marker,
  .rich-text ul li::marker { color: currentColor; }
  .list--spark li::marker { color: var(--color-spark); }
}

/* ---------- Eyebrow / Section-Label ----------
   Mini Asap-Condensed labels above headlines. Base = plain text;
   modifiers add a Spark accent in different shapes. Inherit color
   from the surface so they read on light AND dark sections. */
.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: var(--space-xs);
  font-family: var(--font-ui);
  /* --text-s (14→16), a step up from the old --text-xs — shared with the
     sound-example captions (.player-mock__item-meta) for consistency. */
  font-size: var(--text-s);
  font-weight: var(--weight-semibold);
  text-transform: uppercase;
  letter-spacing: var(--tracking-wide);
  color: inherit;
  margin: 0;
}
/* Pin: vertical Spark stripe BEFORE the text (full height of label). */
.eyebrow--pin {
  align-items: stretch;
}
.eyebrow--pin::before {
  content: "";
  display: block;
  width: var(--spark-marker-width);
  border-radius: 2px;
  background: var(--color-spark);
  flex-shrink: 0;
}
/* Bar: text on a Spark-filled chip — strongest accent variant.
   Brand decision: Spark stays the bar/chip color. Contrast Spark/Ivory
   is 4.09:1 (just below WCAG AA 4.5:1 for body, above 3:1 for large or
   non-essential UI). Bar/Chip is restricted to label-sized text only —
   never running copy or essential information. The Munsell red carries
   the brand energy and is intentional, not retrofitted for compliance. */
.eyebrow--bar {
  background: var(--color-spark);
  color: var(--color-ivory);
  padding: 0.22em 0.85em;
  border-radius: var(--radius-sm);
}

/* ---------- Tags / Chips ----------
   Small Asap-Condensed pill-labels for categories, occasions, service
   types. Default is outlined with currentColor — universally visible on
   any surface. .tag--spark fills with Spark for high-attention tags
   (same caveat as .eyebrow--bar — label-sized text only). */
.tags {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2xs);
}
.tag {
  display: inline-flex;
  align-items: center;
  gap: 0.4em;
  padding: 0.4em 0.75em;
  font-family: var(--font-ui);
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  text-transform: uppercase;
  letter-spacing: var(--tracking-wide);
  background: transparent;
  color: currentColor;
  border: var(--border-button) solid currentColor;
  border-radius: var(--radius-pill);
  white-space: nowrap;
  line-height: 1;
}
.tag--spark {
  background: var(--color-spark);
  color: var(--color-ivory);
  border-color: transparent;
}

/* ---------- Pull-Quote ----------
   Caveat in display size — for testimonials, pull-quotes, personal
   moments. Pulls --color-accent from the surface so it integrates with
   the section's sanctioned headline color. Attribution sits below in
   small Asap Condensed UI type. */
.pull-quote {
  font-family: var(--font-accent);
  font-size: var(--text-l);
  line-height: 1.15;
  font-weight: var(--weight-regular);
  color: var(--color-accent, currentColor);
  margin: 0;
  max-width: var(--measure);
  word-spacing: var(--word-spacing-accent);
}
.pull-quote__attribution {
  margin-block-start: var(--space-sm);
  font-family: var(--font-ui);
  font-size: var(--text-s);
  font-weight: var(--weight-semibold);
  text-transform: uppercase;
  letter-spacing: var(--tracking-wide);
  color: currentColor;
}

/* ---------- Buttons — shared base ---------- */
.btn {
  --btn-weight: var(--weight-semibold-base);
  --btn-stroke-width: 0px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-xs);
  font-family: var(--font-ui);
  font-size: var(--text-button);
  font-weight: var(--btn-weight);
  /* Tight, centred text so any button that wraps to two lines (narrow phones:
     "Soundcheck planen", "Booking-Anfrage senden") stays compact and centred
     instead of inheriting the loose body line-height / left text-align. Harmless
     on single-line buttons (flex already centres those). */
  line-height: 1.1;
  text-align: center;
  text-transform: uppercase;
  letter-spacing: var(--tracking-wide);
  padding:
    calc((var(--space-xs) * 0.88) - var(--btn-stroke-width))
    calc((var(--space-lg) * 0.88) - var(--btn-stroke-width));
  border: var(--btn-stroke-width) solid transparent;
  border-radius: var(--radius-pill);
  cursor: pointer;
  text-decoration: none;
  transition: background var(--transition-base),
              background-image var(--transition-base),
              color var(--transition-base),
              border-color var(--transition-base),
              box-shadow var(--transition-base),
              transform var(--transition-fast);
}
.btn:active {
  transform: translate(1px, 1px);
  box-shadow: var(--shadow-pressed);
  filter: brightness(0.92);
}

/* Primary — surface-aware via component-level vars.
   Set --btn-bg, --btn-fg, --btn-glow-color per button (inline on the element or
   in a page/section rule) to match the surface it sits on.
   Defaults below render as Marian/Ivory/Pear if nothing sets them.
   Plasticity: inner highlight on top edge + compact pressed shadow
   (color via --btn-drop-shadow, surface-aware so dark sections invert
   to a light glow). */
.btn--primary {
  position: relative;
  overflow: hidden;
  background-color: var(--btn-bg, var(--color-marian));
  color: var(--btn-fg, var(--color-ivory));
  box-shadow:
    inset 0 1px 0 color-mix(in srgb, var(--color-ivory) 40%, transparent),
    inset 0 -2px 0 color-mix(in srgb, var(--color-oxford) 20%, transparent),
    0 3px 6px var(--btn-drop-shadow, color-mix(in srgb, var(--color-oxford) 15%, transparent));
  transition: box-shadow var(--transition-base),
              transform var(--transition-fast);
}
.btn--primary::before {
  content: "";
  position: absolute;
  top: 0;
  left: 4%;
  width: 92%;
  height: 50%;
  background-image: linear-gradient(
    var(--btn-glow-color, var(--color-pear)) 0%,
    var(--btn-glow-color, var(--color-pear)) var(--btn-glow-stop, 0%),
    transparent 100%
  );
  border-radius: var(--radius-pill);
  opacity: 0.55;
  pointer-events: none;
  transition: opacity var(--transition-base),
              transform var(--transition-fast);
}
.btn--primary > * { position: relative; z-index: 1; }
.btn--primary:hover {
  transition: box-shadow var(--transition-base),
              transform 460ms cubic-bezier(0.18, 1.35, 0.42, 1);
  transform: translateY(2px);
  box-shadow:
    inset 0 2px 2px color-mix(in srgb, var(--color-oxford) 14%, transparent),
    inset 0 -1px 0 color-mix(in srgb, var(--color-ivory) 26%, transparent),
    0 1px 3px var(--btn-drop-shadow, color-mix(in srgb, var(--color-oxford) 14%, transparent));
}
.btn--primary:hover::before {
  transition: opacity var(--transition-base),
              transform 460ms cubic-bezier(0.18, 1.35, 0.42, 1);
  opacity: 0.62;
  transform: translateY(1px);
}
.btn--primary:active {
  transition: box-shadow var(--transition-base),
              transform 460ms cubic-bezier(0.18, 1.35, 0.42, 1);
  transform: translateY(3px);
  box-shadow:
    inset 0 2px 3px color-mix(in srgb, var(--color-oxford) 18%, transparent),
    0 1px 2px color-mix(in srgb, var(--color-oxford) 12%, transparent);
  filter: brightness(0.92);
}
@media (prefers-reduced-motion: reduce) {
  .btn--primary,
  .btn--primary:hover,
  .btn--primary:active {
    transition: box-shadow var(--transition-base),
                transform var(--transition-fast);
  }
  .btn--primary::before,
  .btn--primary:hover::before {
    transition: opacity var(--transition-base),
                transform var(--transition-fast);
  }
}

/* Secondary — ghost / outline variants */
.btn--ghost-light {
  --btn-stroke-width: var(--border-button-strong);
  background: transparent;
  color: var(--color-oxford);
  /* Dark stroke on a light surface → use the stronger border so it reads as
     heavy as the light-stroke variants do on dark. */
  border-color: var(--color-oxford);
}
.btn--ghost-light:hover {
  background: var(--color-oxford);
  color: var(--color-ivory);
}
.btn--ghost-marian {
  --btn-stroke-width: var(--border-button-strong);
  background: transparent;
  color: var(--color-marian);
  /* Dark stroke on a light surface → stronger border (see --ghost-light). */
  border-color: var(--color-marian);
}
.btn--ghost-marian:hover {
  background: var(--color-marian);
  color: var(--color-ivory);
}
.btn--ghost-pear {
  --btn-stroke-width: var(--border-button);
  --btn-weight: var(--weight-medium);
  background: color-mix(in srgb, currentColor 9%, transparent);
  color: var(--color-pear);
  border-color: transparent;
  box-shadow: inset 0 0 0 var(--btn-stroke-width) currentColor;
}
.btn--ghost-pear:hover {
  background: var(--color-pear);
  color: var(--color-oxford);
  box-shadow: none;
}
.btn--ghost-ivory {
  --btn-stroke-width: var(--border-button);
  --btn-weight: var(--weight-medium);
  background: color-mix(in srgb, currentColor 9%, transparent);
  color: var(--color-ivory);
  border-color: transparent;
  box-shadow: inset 0 0 0 var(--btn-stroke-width) currentColor;
}
.btn--ghost-ivory:hover {
  background: var(--color-ivory);
  color: var(--color-oxford);
  box-shadow: none;
}

/* ---------- Inline link ----------
   Color + weight contrast, animated underline on hover. On dark surfaces
   use the .link-inline--on-dark modifier: lighter blue tint and one
   weight step lighter (light text on dark optically reads bolder). */
.link-inline {
  position: relative;
  color: var(--color-marian);
  font-weight: var(--weight-medium);
  text-decoration: none;
  background-image: linear-gradient(currentColor, currentColor);
  background-size: 0% 1px;
  background-repeat: no-repeat;
  background-position: 0 100%;
  transition: background-size var(--transition-base);
}
.link-inline:hover {
  background-size: 100% 1px;
}
.link-inline--on-dark {
  color: var(--color-marian-light);
  font-weight: var(--weight-regular);
}

/* ---------- Nav link ----------
   Sliding underline left-to-right on hover; permanent on
   [aria-current="page"]. Color follows the surface (inherits body color),
   so a link on a dark section automatically reads in Ivory. */
.nav-link {
  position: relative;
  font-family: var(--font-ui);
  font-size: var(--text-base);
  font-weight: var(--weight-semibold);
  text-transform: uppercase;
  letter-spacing: var(--tracking-wide);
  color: inherit;
  text-decoration: none;
  padding-block: var(--space-2xs);
  white-space: nowrap;
}
.nav-link::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: 0;
  width: 100%;
  height: 2px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform var(--transition-base);
}
.nav-link:hover::after,
.nav-link[aria-current="page"]::after {
  transform: scaleX(1);
}

/* Inline + nav links use a 2px ring drawn via pseudo-element so we can
   position it asymmetrically around the glyph — the line-height-box of
   inline text is taller above the glyph than below, so a symmetric ring
   visually reads as "too high". Pseudo offsets compensate. Uses ::after
   for inline links (free) and ::before for nav links (::after is the
   hover underline). Buttons keep the default outline from base.css. */
.link-inline:focus-visible,
.nav-link:focus-visible {
  outline: none;
}
.link-inline:focus-visible::after,
.nav-link:focus-visible::before {
  content: "";
  position: absolute;
  inset: 1px -2px -3px -2px;
  border: 2px solid var(--focus-ring-color);
  border-radius: 2px;
  pointer-events: none;
}

/* ---------- Sticky vertical "Say yes to Sax" CTA ----------
   Marian body, Spark border-left, vertical text. Visibility: Marian body
   works on light sections (Ivory/Pear/Cool Gray); Spark edge guarantees
   visibility on Oxford/Marian. Hover uses a vertical press transform
   + dual-tinted pressed shadow so the movement reads on light AND
   dark backgrounds. The body derives shared CTA geometry from the rendered
   button so page chrome can align to the rail without duplicate overrides.
   The rail floats OVER full-bleed content (images bleed under it, the icon
   hangs into the hero tiles) — so the body must NOT reserve a right-edge
   gutter. Content that genuinely needs to stay clear of the rail opts in
   locally (e.g. the mobile Unterricht content stack in landing.css). */
body:has(.btn-sticky-cta) {
  --sticky-cta-center-y: 50%;
  --sticky-cta-padding-block: var(--space-xs);
  --sticky-cta-height: max(
    clamp(9rem, 7.86rem + 5.71vw, 12rem),
    calc(8.8rem + var(--sticky-cta-padding-block) + var(--sticky-cta-padding-block))
  );
  --sticky-cta-top-y: calc(var(--sticky-cta-center-y) - (var(--sticky-cta-height) / 2));
  --sticky-cta-bottom-y: calc(var(--sticky-cta-top-y) + var(--sticky-cta-height));
}
body:has(.sticky-cta--top) {
  --sticky-cta-center-y: calc(44svh - 16px);
  --sticky-cta-padding-block: var(--space-sm);
}
@media (max-width: 720px) {
  body:has(.sticky-cta--top) {
    --sticky-cta-center-y: calc(35svh - 16px);
    --sticky-cta-padding-block: clamp(1.1rem, 0.85rem + 0.65vw, 1.45rem);
  }
}

.btn-sticky-cta {
  position: fixed;
  top: var(--sticky-cta-top-y);
  right: 0;
  transform: none;
  z-index: 100;

  width: var(--cta-rail-width);
  height: var(--sticky-cta-height);

  writing-mode: vertical-rl;
  text-orientation: mixed;

  display: inline-flex;
  align-items: center;
  justify-content: center;

  /* Deep crimson (#840021, Spark hue ~345°) flat base — carries the whole text
     band at WCAG AAA with Ivory (10.2:1). The gloss sits ON TOP as a floating,
     inset pill highlight in ::before — the SAME element every .btn--primary
     carries, just rotated into the rail (lit inner half, rounded cap = the
     "ellipse" on the outer side). Because it is inset it never touches the Spark
     border, so there is no dark seam. */
  --cta-fill: #840021;         /* deep crimson base + text band — AAA reference */
  background-color: var(--cta-fill);
  color: var(--color-ivory);
  font-family: var(--font-ui);
  font-weight: var(--weight-semibold);
  font-size: var(--text-s);
  text-transform: uppercase;
  letter-spacing: var(--tracking-wide);
  text-decoration: none;
  white-space: nowrap;

  /* Pure-Spark edge as border-left — follows border-radius automatically. The
     full-brightness Spark reads as a luminous edge against the slightly dimmed
     fill. Overridable via --cta-edge-width if a section needs a thicker rail. */
  --cta-edge-width: 4px;
  /* Half the rail width = fully-round left side; the gloss pill below is a full
     stadium whose cap radius (half ITS width) lands on this rail's inner edge,
     so the two round shapes stay concentric and their curves run parallel. */
  --cta-corner-radius: calc(var(--cta-rail-width) / 2);
  border: none;
  border-left: var(--cta-edge-width) solid var(--color-spark);
  border-radius: var(--cta-corner-radius) 0 0 var(--cta-corner-radius);
  /* Physical properties — vertical-rl flips logical block/inline. */
  padding: var(--sticky-cta-padding-block) 0;
  gap: var(--space-2xs);

  /* Clean dark drop only — depth against the page, no ivory/cool-gray sheen. */
  box-shadow: -3px 0 8px color-mix(in srgb, var(--color-oxford) 22%, transparent);

  /* Presses as one rail so the icon and label move with the button. */
  transform-origin: right center;
  transition: transform var(--transition-base),
              box-shadow var(--transition-base);
  cursor: pointer;
}
/* The gloss element — the SAME floating, inset, pill-rounded highlight that every
   .btn--primary carries in its ::before, rotated into the rail: it hugs the lit
   INNER half and its rounded cap is the "ellipse" reading toward the outer edge.
   Inset on all sides so it floats free of the Spark border (no dark seam) and its
   own rounding never has to match the rail's. Spark glow, fading out before the
   centred label column so the bright Spark stays off the text (label keeps AAA). */
.btn-sticky-cta::before {
  content: "";
  position: absolute;
  top: 2%;
  left: 0;
  width: 92%;
  height: 96%;
  /* Horizontal gloss: the light tone hugs the inner (left) edge and fades to
     transparent toward the outer edge. It fades out before the centred label
     column so the bright Spark stays off the text and the label keeps AAA. */
  background-image: linear-gradient(
    90deg,
    color-mix(in srgb, var(--color-spark) 55%, transparent) 0%,
    color-mix(in srgb, var(--color-spark) 45%, transparent) 12%,
    transparent 55%
  );
  /* Full stadium → completely round top & bottom. Its cap radius (half the pill
     width) lands on the rail's inner edge, so the round caps stay concentric with
     the rail's fully-round corners and the curves run parallel. */
  border-radius: var(--radius-pill);
  pointer-events: none;
  transition: opacity var(--transition-base);
}
.btn-sticky-cta > * {
  position: relative;
  z-index: 1;
}
.btn-sticky-cta > span {
  flex-shrink: 0;
  white-space: nowrap;
}
.btn-sticky-cta__icon {
  width: 1.6em;
  height: auto;
  /* Override base.css svg { max-width: 100% } so icon can exceed button width. */
  max-width: none;
  flex-shrink: 0;
  /* Nudge right to optically balance the Spark border-left. */
  transform: translateX(3px);
}
.btn-sticky-cta__icon path:nth-child(2) {
  fill: var(--color-ivory);
}
.btn-sticky-cta:hover {
  transform: translateY(2px);
  box-shadow:
    inset 0 2px 3px color-mix(in srgb, var(--color-oxford) 18%, transparent),
    -2px 1px 5px color-mix(in srgb, var(--color-oxford) 22%, transparent);
}
.btn-sticky-cta:active {
  transform: translateY(3px);
}

@media (max-width: 720px) {
  .btn-sticky-cta.sticky-cta--top {
    font-size: 0.95rem;
  }
}
