/* Smooth cross-fade on navigation between pages, site-wide. No JS —
   browsers without support just navigate normally (progressive
   enhancement, not a dependency). */
@view-transition {
  navigation: auto;
}

/* Hack (MIT license — see src/static/fonts/HACK-LICENSE.md), the
   site's one self-hosted font; everything else loads from Google
   Fonts (see the <link> in pollen.rkt). Only regular + bold: nothing
   on the site sets font-style: italic on monospace text. */
@font-face {
  font-family: "Hack";
  src: url("/static/fonts/hack-regular.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Hack";
  src: url("/static/fonts/hack-bold.woff2") format("woff2");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

:root {
  /* Core brand colors. --color-dark still comes straight from the
     logo's dark-grey tile; --color-primary has since moved off the
     logo's own orange "O" tile to this warmer coral-orange instead
     (--color-primary-dark derived from it the same way the old one
     was — roughly 18% darker — for hover states). */
  --color-primary: #f67055;
  --color-primary-dark: #ca5c46;
  /* Lighter tint of --color-primary — the answered-option card
     background in the guided inquiry form (see .inquiry-option--done). */
  --color-primary-light: #ffb9ac;
  --color-accent: #f2b705;
  --color-dark: #5a514f;
  --color-text: #232323;
  --color-muted: #6b6b6b;
  --color-bg: #ffffff;
  --color-bg-alt: #f7f5f2;
  --max-width: 72rem;
  --content-width: 60rem;
  --radius: 0.5rem;
  --font-mono: "Hack", ui-monospace, SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace;
  /* .container's left border (below) reads this — black-on-light by
     default, overridden to white-on-dark inside dark-background
     sections like .home-hero (see further down). */
  --container-border-color: rgba(0,0,0,0.1);
  font-size: 100%;
}

* { box-sizing: border-box; }

/* overflow-x: hidden guards against a few px of horizontal scroll
   from the full-bleed break-out trick .carousel (and its trailing
   spacer) use: 100vw is the viewport width INCLUDING the vertical
   scrollbar's own gutter in most browsers, so calc(50% - 50vw) as a
   negative margin pulls .carousel's right edge out slightly past the
   actual visible/scrollable area — by exactly the scrollbar's width.
   Nothing on this site is meant to scroll horizontally, so this is a
   safe backstop, not a mask over a real bug. */
html {
  scroll-behavior: smooth;
  overflow-x: hidden;
}

body {
  margin: 0;
  font-family: "IBM Plex Sans Condensed", "Helvetica Neue", Arial, sans-serif;
  color: var(--color-text);
  background: var(--color-bg);
  line-height: 1.55;
}

/* Distinct, condensed face for all headlines — set once here rather
   than per-selector so every h1-h6 site-wide (hero claim, section
   headings, card titles, ...) picks it up. font-weight: 600 (semi-
   bold) is explicit, not left to the UA-default bold (700) — only
   600 is loaded above, so leaving it at 700 would make the browser
   synthesize a faux-bold instead of using the real cut. */
h1, h2, h3, h4, h5, h6 {
  font-family: "Unica One", "Helvetica Neue", Arial, sans-serif;
  font-weight: 400;
}

img, video { max-width: 100%; height: auto; display: block; }

a { color: var(--color-primary-dark); }
a:hover { color: var(--color-primary); }

/* Container/content: the two width abstractions every section should
   build on, instead of each one hand-rolling (or forgetting) its own
   max-width/padding/margin. .container is the standard page-width
   box — apply it directly to a <section> for the common case, or
   nest it inside a full-bleed section (e.g. .alt) that needs its
   background edge-to-edge but its content aligned like everything
   else. .content nests inside .container (or stands alone) to narrow
   prose/text-heavy content further, for readable line length. */

/* width: 100% on all three below isn't redundant with the max-width —
   a flex item with an auto cross-size AND an auto cross-axis margin
   is excluded from stretch by spec and sized to its own content
   instead (then centered via the margin), so without an explicit
   width these would silently shrink-wrap to content width instead of
   filling-then-clamping whenever one ends up inside a flex container
   (as .home-hero__inner's children do) — the behavior every other,
   non-flex use of these classes gets for free from plain block layout. */

/* border-left/right are declared here (not only inside the media
   query below) at their real width but a transparent color — so the
   space they occupy never changes, only their visibility does — with
   a transition on that color. That's what turns the breakpoint into
   a fade instead of a hard cut: resizing across 76rem still flips a
   plain media query match (CSS can't animate a property *by* viewport
   width, only react to a query's match state changing), but because
   the color change is the only thing moving, the transition smooths
   that flip instead of snapping border-width from 0 to 2px. */
.container {
  width: 100%;
  max-width: var(--max-width);
  margin: 0 auto;
  padding-left: 1.25rem;
  padding-right: 1.25rem;
  border-left: 2px solid transparent;
  border-right: 2px solid transparent;
  transition: border-color 0.3s ease;
}

/* The border only earns its keep once the viewport is wide enough to
   show daylight around the (now width-capped) .container — below
   that it would just sit flush against the viewport edge, redundant
   with the edge itself. --max-width + 4rem, not --max-width alone, so
   there's a visible gutter outside the border on both sides, not just
   the exact moment the cap kicks in. Media features can't read custom
   properties, so this 76rem is --max-width (72rem) + 4rem written out
   — keep the two in sync by hand if --max-width above ever changes. */
@media (min-width: 76rem) {
  .container {
    border-color: var(--container-border-color);
  }
}

.content {
  width: 100%;
  max-width: 40rem;
  margin-left: auto;
  margin-right: auto;
}

/* Wider than .content, for a headline+CTA block that needs more room
   than a paragraph does but shouldn't run the full .container width —
   the home hero composes with this rather than hardcoding its own
   60rem, so the two can't drift apart. */
.content-wide {
  width: 100%;
  max-width: var(--content-width);
  margin-left: auto;
  margin-right: auto;
}

/* header */

/* Full-bleed — a nested .container (markup) gives the gutter/
   max-width/border instead, same split .site-footer uses below for
   the same reason: the background (full width) and the aligned,
   width-capped border need to be two different boxes, not one.
   Vertical padding lives on that nested .container (same pattern
   .site-footer .container uses below), not on .site-header itself —
   padding outside .container would stretch the header bar's height
   past .container's own border-box, leaving its border-left/
   border-right short of the bar's full height instead of running
   edge to edge the way every other .container's border does. */
.site-header .container {
  padding-top: 0.4rem;
  padding-bottom: 0.4rem;
}

/* Home-page-only: float the header over the hero image instead of
   reserving its own white bar above it, then stay pinned (position:
   fixed, not absolute — absolute would scroll away with the page)
   while scrolling, switching to an opaque white bar — and the
   .brand__logo--color variant below instead of --light — once the
   hero has scrolled fully out of view (hero-carousel.js observes
   .home-hero itself for this, same IntersectionObserver pattern
   .hero-cta-bar__sentinel below uses, just watching the hero directly
   rather than a dedicated sentinel). Transparent is reserved for
   "still over the hero", not just "scrolled all the way up" — the
   header should read against the hero's dark photo for as long as
   that's what's actually behind it, and switch the moment something
   else is there instead — [data-theme] (set by hero-carousel.js from
   each section's own data-header-theme markup attribute, one
   IntersectionObserver per themed section) tracks *which* section
   that currently is, not just "hero or not": "dark" (.home-hero,
   still showing through), "light" (the plain white sections — the
   default, also what every non-home-page header always is), or
   "orange" (.home-contact, see its own rule in site.css) — the header
   always matches whatever's actually behind it.
   :has() (not a page-level class) scopes all of this to pages that
   actually have a dark full-bleed hero to float over — every other
   page's .hero/simple-hero has no image (or a much shorter one), so
   the header stays normal, always-white, always --color-logo there.
   z-index: 10 is comfortably above .home-hero's own internal layers
   (stage 0, gradient 1, content 2, pause badge 4) without needing to
   coordinate with them — .home-hero has no z-index of its own, so
   .site-header's explicit stacking context wins regardless. Removing
   it from flow (fixed) is what lets .home-hero fill the full height
   from the very top of the page instead of starting below a reserved
   header bar. .site-header no longer carries .container itself (see
   the nested div in HTML markup) specifically so this full-bleed
   background can span edge-to-edge while that inner .container still
   centers at the normal capped width — keeping its border-left/
   border-right aligned with every other .container section's, instead
   of either sitting flush against the screen edges (full-bleed border)
   or boxing in the background (capped background, visible edge over
   the hero). */
body:has(.home-hero) .site-header {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 10;
  background: transparent;
  transition: background-color 0.25s ease;
}

body:has(.home-hero) .site-header[data-theme="light"] { background: #fff; }

/* Same border-visibility fix .home-contact gives its own content
   below — the default black-based border barely reads against this
   same orange once it's also the header's own background. */
body:has(.home-hero) .site-header[data-theme="orange"] {
  background: var(--color-primary);
  --container-border-color: rgba(255, 255, 255, 0.3);
}

/* .content-wide (not .container) on purpose — same pattern as
   .hero-cta-bar__inner: nesting content-wide one level inside
   .container caps it at 60rem and centers it within the container's
   gutter, landing the logo's left edge at the same x position as the
   hero claim/caption below it, instead of flush with the wider
   .container edge. */
.site-header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
}

/* Three logo variants stacked on top of each other (--color normal
   flow, sized/sizing the .brand box; --light and --dark absolutely
   positioned over it) and crossfaded via opacity so the home-page
   header's theme swaps (see [data-theme] above) read as a smooth
   transition rather than an abrupt image swap. --color (multi-color
   squares) is the one every non-home-page header shows, always
   against a white bar there. On the home page, --light reads against
   the hero's dark photo ("dark" theme); --dark reads against any of
   this header's own *opaque* backgrounds instead ("light" theme's
   white, "orange" theme's brand color alike) — --color is reserved
   for non-home pages so a site-wide logo change doesn't fall out of a
   home-page-only scroll interaction. */
.brand {
  position: relative;
  display: inline-block;
}

.brand__logo { height: 1.5rem; width: auto; transition: opacity 0.25s ease; }

.brand__logo--light,
.brand__logo--dark {
  position: absolute;
  inset: 0;
  opacity: 0;
}

/* :not([data-theme="light"]):not([data-theme="orange"]), not just
   [data-theme="dark"], so the *absence* of the attribute — the state
   at first paint, before hero-carousel.js's observers have run even
   once — also reads as "dark": that's always correct at load, since
   the hero is what's on screen either way, and matching it without
   needing JS to have run yet is what avoids a flash of the wrong logo
   while the page is still loading. */
body:has(.home-hero) .site-header:not([data-theme="light"]):not([data-theme="orange"]) .brand__logo--light { opacity: 1; }
body:has(.home-hero) .site-header:not([data-theme="light"]):not([data-theme="orange"]) .brand__logo--color { opacity: 0; }

body:has(.home-hero) .site-header[data-theme="light"] .brand__logo--dark,
body:has(.home-hero) .site-header[data-theme="orange"] .brand__logo--dark { opacity: 1; }
body:has(.home-hero) .site-header[data-theme="light"] .brand__logo--color,
body:has(.home-hero) .site-header[data-theme="orange"] .brand__logo--color { opacity: 0; }

.lang-switch {
  border: 1px solid var(--color-dark);
  border-radius: 999px;
  /* Right padding trimmed by the letter-spacing value below — letter-
     spacing adds space after every character, trailing one included,
     so left as a plain symmetric padding the extra space after the
     last letter stacks on top of the right padding and visibly
     unbalances the two sides. */
  padding: 0.15rem calc(0.6rem - 0.08em) 0.15rem 0.6rem;
  font-family: var(--font-mono);
  font-size: 0.8rem !important;
  letter-spacing: 0.08em;
  /* inline-flex + a line-height of 1, not the inherited 1.55 (body)
     relied on before — at this small size, with a different
     (monospace) font than body's, the inherited line-height's half-
     leading doesn't split evenly above/below the glyphs, which is
     what read as "text sits a bit high, not quite centered". Flex
     centering on a tight line-height isn't subject to that. */
  display: inline-flex;
  align-items: center;
  line-height: 1;
  background: transparent;
  color: var(--color-dark);
  text-decoration: none;
  transition: border-color 0.25s ease, color 0.25s ease;
}

/* Explicit on :hover too, not just the base state — a:hover (site-
   wide, near the top of this file) outranks a bare .lang-switch on
   specificity (a class vs. a type selector + pseudo-class both count
   as one step, so the tie goes to :hover's extra type selector),
   so without this, hovering would flip the pill to the site's orange
   link-hover color instead of staying put. */
.lang-switch,
.lang-switch:hover {
  color: var(--color-dark);
}

/* Home page only: white border/text instead of the default dark —
   needed wherever the header's own background isn't plain white
   itself. Grouped as "not [data-theme="light"]" rather than listing
   "dark" and "orange" separately: light is the one theme this pill's
   default (dark-on-white) already reads fine against, so it's the
   one exception, not the rule. */
body:has(.home-hero) .site-header:not([data-theme="light"]) .lang-switch,
body:has(.home-hero) .site-header:not([data-theme="light"]) .lang-switch:hover {
  border-color: #fff;
  color: #fff;
}

/* hero */

.hero {
  position: relative;
  background: linear-gradient(180deg, rgba(0,0,0,0.55), rgba(0,0,0,0.35)),
              url("/static/img/hero.jpg") center/cover no-repeat;
  color: #fff;
  padding: 5rem 1.25rem;
  text-align: center;
}

.hero h1 {
  font-size: clamp(2rem, 4vw, 3.2rem);
  margin: 0 0 0.75rem;
}

.hero p {
  font-size: 1.15rem;
  max-width: 40rem;
  margin: 0 auto 1.75rem;
  opacity: 0.95;
}

.button {
  display: inline-block;
  background: var(--color-primary);
  color: #fff;
  text-decoration: none;
  font-weight: 700;
  padding: 0.75rem 1.75rem;
  border: none;
  font-family: var(--font-mono);
  font-size: 1rem;
}

.button:hover { background: var(--color-primary-dark); color: #fff; }

.badge {
  display: inline-block;
  background: var(--color-accent);
  color: var(--color-dark);
  font-weight: 700;
  padding: 0.3rem 0.9rem;
  border-radius: 999px;
  font-size: 0.85rem;
  margin-bottom: 1rem;
}

/* home hero — background carousel. Slides hard-cut (display toggled,
   never opacity/transition — see hero-carousel.js) rather than fading. */

.home-hero {
  /* full-bleed by default now (main section no longer imposes a
     max-width/margin — see the container/content rules above), so no
     override is needed here the way there used to be */
  position: relative;
  overflow: hidden;
  min-height: 60vh;
  color: #fff;
  /* 70vh on mobile, 60vh above — same breakpoint .sticky-cta below
     hides itself at, since the hero's own CTA button is on screen
     either way, making that duplicate bar redundant. Both already
     comfortably fit the hero's content (headline, CTA, pagination/
     caption) with room to spare at the hero's current (small, fixed,
     not fluid) mobile font-size — watch for that margin shrinking
     again if the headline grows back, the way the old fluid
     clamp()'d size once clipped the CTA/pagination against this
     section's own overflow: hidden on short phones. */
  /* .container's border-left (see its rule) is black-on-light by
     default; this dark/image background needs the white-on-dark
     version instead. */
  --container-border-color: rgba(255,255,255,0.1);
  /* Without this, hero-carousel.js's drag-to-navigate gesture (see
     its pointerdown/pointermove handlers) reads as a text-selection
     drag to the browser — the claim/caption get highlighted instead
     of (or alongside) the slide actually changing. */
  user-select: none;
  -webkit-user-select: none;
}

@media (max-width: 60rem) {
  .home-hero { min-height: 70vh; }
}

/* Gutter-giver for everything in the hero: composes with .container
   (same class a plain section would use for its gutter+72rem cap,
   border-left included), NOT .content-wide, because .content-wide
   alone only centers its own box — it doesn't reproduce the gutter
   that .content-wide's *other* uses get for free from an ancestor
   .container. Without that, .home-hero__content's 60rem content-wide
   box would center against the bare viewport instead of against the
   same 72rem-clamped box that "So arbeiten wir" etc. are nested in,
   landing at a different x position on screens wider than 72rem.
   position: absolute + inset (rather than height: 100%) because
   .home-hero only has a min-height, not an explicit height, which a
   percentage height can't resolve against. inset: 0 (not stopping
   short of the bottom) now that .hero-cta-bar is commented out at its
   call sites — see sticky-cta-bar in components.rkt — and there's no
   bar to visually continue into. */
.home-hero__inner {
  position: absolute;
  z-index: 2;
  inset: 0;
  padding-top: 2rem;
  padding-bottom: 2rem;
}

/* The one layout box for everything in the hero: claim+CTA
   top-aligned, slide info (pagination/caption) bottom-aligned, via
   justify-content: space-between on a column, height: 100% so that
   column spans .home-hero__inner's full (inset-derived) height. */
.home-hero__content {
  height: 100%;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  text-align: left;
}

.home-hero__stage {
  position: absolute;
  inset: 0;
  z-index: 0;
  cursor: pointer;
  /* Leaves vertical scrolling to the browser while letting
     hero-carousel.js's pointer handlers see horizontal drags (its
     gesture prev/next) — without this, a touch swipe here would just
     scroll the page before JS ever sees the gesture. */
  touch-action: pan-y;
}

.home-hero__slide {
  /* figures have a default browser margin (e.g. 1em 40px); with
     position: absolute + inset: 0, a non-zero margin is NOT ignored —
     it insets the box from those edges, which is exactly the "padding"
     around the slide image */
  margin: 0;
  position: absolute;
  inset: 0;
  /* Crossfade, not a hard cut: every slide stays in normal rendering
     (no display: none) so the outgoing and incoming slide can be
     visible at once and blend — only opacity switches with
     .is-active, transitioning both together. Order between them
     doesn't matter for how the blend looks: with both the outgoing
     slide's opacity going 1->0 and the incoming's 0->1 on the same
     timeline, standard alpha compositing lands on the same crossfade
     regardless of which is stacked on top. */
  opacity: 0;
  transition: opacity 0.6s ease;
}

.home-hero__slide.is-active { opacity: 1; }

.home-hero__slide img,
.home-hero__slide video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Otherwise dragging to navigate (see .home-hero's user-select:
     none above, same reasoning) picks up the browser's native "drag
     this image" ghost/outline instead. */
  -webkit-user-drag: none;
}

.home-hero::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  background: linear-gradient(180deg, rgba(0,0,0,0.55), rgba(0,0,0,0.35));
}


.home-hero__inner h1 {
  font-size: 2.25rem;
  /* Tight, same ratio the ≥60rem rule below uses (font-size 4rem /
     line-height 4rem) — unitless so it tracks the font-size here too
     (2.25rem), instead of (as before) falling through to body's loose
     1.55 below that breakpoint, which ballooned badly at this size. */
  line-height: 1;
  margin: 0;
  margin-top: 4rem;
}

@media (min-width: 60rem) {
  .home-hero__inner h1 {
    font-size: 4rem;
    letter-spacing: -0.1rem;
  }
}

.home-hero__cta { margin-top: 1.5rem; }

/* Wrapping .home-hero__pagination + .home-hero__caption is a bare,
   unclassed div (see components.rkt) — it's the first flex item of
   .home-hero__content, which is what keeps this pair pinned together
   at the top while space-between pushes the claim to the bottom.
   Neither it nor the pagination row/caption need their own
   .content-wide any more — that's carried once by .home-hero__content
   itself now (see its rule above), so plain block children here
   already sit at the right width/x position for free. */

/* A row of Instagram-Stories-style timeline bullets, one per slide.
   Each is a short track; the active one grows and fills left-to-right
   over the slide duration via the ::fill span's animation (driven by
   the is-active class — see hero-carousel.js, which is also the
   source of truth for the duration and sets --slide-duration to
   match). Clicking a bullet jumps straight to that slide. */
.home-hero__pagination {
  display: flex;
  gap: 0.4rem;
  margin-bottom: 0.75rem;
}

.home-hero__pagination-item {
  appearance: none;
  -webkit-appearance: none;
  border: none;
  padding: 0;
  margin: 0;
  width: 2px;
  height: 2px;
  background: rgba(255,255,255,0.35);
  overflow: hidden;
  position: relative;
  cursor: pointer;
  flex: none;
  transition: width 0.25s ease;
}

.home-hero__pagination-item.is-active {
  width: 2.75rem;
}

/* Starts fully collapsed and scales up to full width over the slide
   duration — transform (not width) so the animation runs on the
   compositor instead of thrashing layout every frame. forwards keeps
   it filled rather than snapping back to empty right before
   hero-carousel.js swaps .is-active to the next bullet. */
.home-hero__pagination-fill {
  position: absolute;
  inset: 0;
  transform-origin: left;
  transform: scaleX(0);
  background: #fff;
}

.home-hero__pagination-item.is-active .home-hero__pagination-fill {
  /* Longhand, not the animation shorthand with var(--slide-duration)
     inside it — WebKit (so, every iOS browser, not just Safari) has a
     long-standing bug where a custom property used inside the
     *shorthand* animation property doesn't take, silently dropping
     the whole declaration — only the longhand animation-duration
     reliably picks it up. */
  animation-name: home-hero-pagination-fill;
  animation-duration: var(--slide-duration, 5s);
  animation-timing-function: linear;
  animation-fill-mode: forwards;
}

/* Must come *after* the .animation shorthand rule above, not before
   (as it previously did) — same specificity either way, but the
   `animation` shorthand always sets every sub-property it controls,
   including animation-play-state back to its default (running) — so
   with this rule first in source order, the later shorthand rule
   silently won the cascade for that sub-property too, and pausing
   never actually froze the fill: it kept animating in the
   background, completing and sitting at 100% while the JS timer
   (genuinely stopped) never advanced the slide, reading as "stuck"
   rather than paused. */
.home-hero.is-paused .home-hero__pagination-fill {
  animation-play-state: paused;
}

@keyframes home-hero-pagination-fill {
  from { transform: scaleX(0); }
  to { transform: scaleX(1); }
}

.home-hero__caption {
  margin: 0;
  font-family: var(--font-mono);
  font-size: 0.8rem;
}

.home-hero__caption-client,
.home-hero__caption-event {
  display: block;
  color: rgba(255,255,255,0.85);
  /* An empty block with no text node generates no line box at all, so
     it collapses to 0 height — explicit line-height + a matching
     min-height is what keeps this line's space reserved while
     hero-carousel.js's typewriter effect has it blanked out between
     clearing and the first typed character, instead of the caption
     (and everything below it, via .home-hero__content's
     space-between) visibly shifting on every slide change. */
  line-height: 1.3;
  min-height: 1.3em;
}

/* Blinking caret, shown only on whichever caption line
   hero-carousel.js is actively typing (.is-typing, toggled per line
   so the caret moves from the client line to the event line instead
   of both blinking at once). */
.home-hero__caption-client.is-typing::after,
.home-hero__caption-event.is-typing::after {
  content: "_";
  animation: home-hero-caret-blink 1s step-end infinite;
}

@keyframes home-hero-caret-blink {
  50% { opacity: 0; }
}

/* Explicit prev/next/play-pause controls below the caption — hero-
   carousel.js wires these to the same show()/togglePause() functions
   the pagination dots and click-to-pause already use, so this is just
   a second, more discoverable way to reach the same behavior. */
.home-hero__controls {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-top: 0.75rem;
}

.home-hero__control {
  appearance: none;
  -webkit-appearance: none;
  position: relative;
  flex: none;
  width: 1rem;
  height: 1rem;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: rgba(255,255,255,0.2);
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: background-color 0.2s ease;
}

.home-hero__control:hover { background: rgba(255,255,255,0.35); }

.home-hero__control svg { width: 0.625rem; height: 0.625rem; }

/* Pause icon in normal flow (sizes the button's content box), play
   icon stacked on top via opacity — same two-icon crossfade pattern
   as .brand__logo above, driven here by .home-hero.is-paused instead
   of the header's [data-theme]. */
.home-hero__control-icon { display: flex; }

.home-hero__control-icon--play {
  position: absolute;
  inset: 0;
  align-items: center;
  justify-content: center;
  opacity: 0;
  transition: opacity 0.2s ease;
}

.home-hero__control-icon--pause { transition: opacity 0.2s ease; }

.home-hero.is-paused .home-hero__control-icon--pause { opacity: 0; }
.home-hero.is-paused .home-hero__control-icon--play { opacity: 1; }

/* Draws the eye to the (otherwise easy-to-miss, 1rem) play button
   once paused, rather than leaving a visitor to notice the slideshow
   just stopped on its own. Same step-end blink as the caption's
   typing caret above, not a smooth fade — reads more like a status
   indicator blinking than a decorative pulse. */
.home-hero.is-paused .home-hero__control--playpause {
  animation: home-hero-control-blink 1.2s step-end infinite;
}

@keyframes home-hero-control-blink {
  50% { opacity: 0.3; }
}

/* CTA bar right after the hero — visually pulled up (negative margin)
   into the space .home-hero reserved for it, so it reads as "inside
   the hero, under the claim" while it's actually a top-level sibling
   of .home-hero, not nested inside it. That's deliberate: position:
   sticky can't stick past its own parent's box, so nesting it inside
   the (comparatively short) hero would stop it from staying stuck
   once you scrolled past the hero's height — see the sticky-cta-bar
   doc comment in components.rkt. hero-carousel.js toggles .is-stuck
   (via IntersectionObserver on the sentinel right before this bar) so
   it only gets an opaque background once it's actually pinned to the
   top over page content, not while it's still overlapping the hero
   image. */

.hero-cta-bar__sentinel { height: 1px; }

.hero-cta-bar {
  position: sticky;
  top: 0;
  z-index: 20;
  margin-top: -4.5rem;
}

.hero-cta-bar.is-stuck {
  background: #fff;
  border-bottom: 1px solid #e5e2dd;
}

/* .hero-cta-bar itself composes with .container (markup) for the same
   gutter+72rem-cap reason .home-hero__inner does — see its comment.
   .hero-cta-bar__inner then composes with .content-wide, nested one
   level inside that .container exactly like every other .content-wide
   use on the site, so its left edge lands at the same x position as
   the claim above it and "So arbeiten wir" below it. No padding of
   its own: the horizontal gutter comes from the outer .container. */
.hero-cta-bar__inner {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  justify-content: flex-start;
  gap: 0.5rem 1.5rem;
  padding-top: 0.75rem;
  padding-bottom: 0.75rem;
}

.hero-cta-bar__link {
  color: #fff;
  font-weight: 600;
  font-size: 0.95rem;
  text-decoration: none;
}

.hero-cta-bar__link:hover { text-decoration: underline; }

.hero-cta-bar.is-stuck .hero-cta-bar__link { color: var(--color-dark); }

/* Partner/client logo marquee, right under the home hero — see
   partner-marquee in components.rkt for the markup rationale
   (doubled track, aria-hidden, why it's inside .container rather
   than full-bleed). overflow: hidden here is what actually clips the
   track to this section's width; the track itself is twice as wide
   as its parent (two back-to-back copies of the logo list) and
   translates by exactly -50% of its own width, which is the same as
   100% of one copy — so the instant the animation "resets" from -50%
   back to 0%, the second copy is already sitting exactly where the
   first one started, and the reset is invisible. */
.partner-marquee {
  overflow: hidden;
  padding-top: 1rem;
  padding-bottom: 1rem;
  /* One source of truth for the lap time, read by both the track's
     scroll animation and the progress bar's fill below, so they stay
     in lockstep with zero JS and a future "slower"/"faster" request
     is a one-line change instead of two. */
  --marquee-duration: 420s;
}

/* Anchors the edge fades below to just the logos' own height — not
   .partner-marquee itself, which also contains .partner-marquee
   __progress-wrap underneath, and not .partner-marquee__track, which
   scrolls (the fades would slide right along with it if they were
   positioned against the one thing actually moving). This wrapper
   does neither: it's sized to the track by ordinary block layout and
   never moves itself.
   The negative margin here cancels .partner-marquee's own (.container)
   padding-left/right, so the fades below — left/right: 0, measured
   from this wrapper's own padding edge — reach all the way to
   .partner-marquee's true outer edge instead of stopping 1.25rem
   short of it. Re-adding that same 1.25rem as this wrapper's own
   padding keeps the track's actual logos positioned exactly where
   they were — only the fade's reach changes, not the content. */
.partner-marquee__viewport {
  position: relative;
  margin-left: -1.25rem;
  margin-right: -1.25rem;
  padding-left: 1.25rem;
  padding-right: 1.25rem;
}

/* Fades the logo track into the page's own white background at each
   edge, instead of hard-clipping a logo mid-image as it scrolls past
   .partner-marquee's overflow: hidden boundary. z-index rather than
   relying on paint order — ::before, despite the name, paints
   *behind* later real children by default, so without it the left
   fade would sit underneath the track instead of over it.
   pointer-events: none so these never intercept clicks meant for the
   track underneath. */
.partner-marquee__viewport::before,
.partner-marquee__viewport::after {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  width: 4rem;
  z-index: 1;
  pointer-events: none;
}

.partner-marquee__viewport::before {
  left: 0;
  background: linear-gradient(90deg, var(--color-bg), transparent);
}

.partner-marquee__viewport::after {
  right: 0;
  background: linear-gradient(270deg, var(--color-bg), transparent);
}

.partner-marquee__track {
  display: flex;
  align-items: center;
  gap: 3rem;
  width: max-content;
  /* Longhand, not the animation shorthand with var(--marquee-duration)
     inside it — see .home-hero__pagination-item.is-active
     .home-hero__pagination-fill's own rule for why: WebKit silently
     drops a custom property used inside the shorthand, which is
     exactly what left this track motionless on iOS. */
  animation-name: partner-marquee-scroll;
  animation-duration: var(--marquee-duration);
  animation-timing-function: linear;
  animation-iteration-count: infinite;
}

.partner-marquee__track img {
  flex: none;
  height: 2.75rem;
  width: auto;
  opacity: 0.6;
}

@keyframes partner-marquee-scroll {
  from { transform: translateX(0); }
  to { transform: translateX(-50%); }
}

/* Left-aligned (not centered — matches the track/heading above it),
   small bar-with-a-thumb below the track: a fixed-width block that
   travels the length of its own track and wraps back to the start,
   rather than a 0-100% fill — same idea as the hero's active
   pagination bullet growing+filling
   (.home-hero__pagination-item.is-active + .home-hero__pagination-
   fill), re-expressed for one continuous loop instead of discrete
   slides to pick among: there's nothing to "complete" here, just
   motion to echo, so a traveling thumb reads better than a fill that
   snaps back to empty. translateX 0 -> (track width - thumb width)
   is a hard reset back to 0 at the end of each lap (default keyframe
   behavior under `infinite`), which is deliberate: it's the same
   "wrap" the marquee track itself does, just visible here instead of
   hidden behind the track's doubled content. */
.partner-marquee__progress-wrap {
  margin-top: 1rem;
}

.partner-marquee__progress {
  position: relative;
  width: 4rem;
  height: 2px;
  background: rgba(0,0,0,0.15);
  overflow: hidden;
}

.partner-marquee__progress-fill {
  position: absolute;
  inset: 0 auto 0 0;
  width: 0.75rem;
  background: var(--color-primary);
  /* Longhand — see .partner-marquee__track's own rule. */
  animation-name: partner-marquee-thumb-travel;
  animation-duration: var(--marquee-duration);
  animation-timing-function: linear;
  animation-iteration-count: infinite;
}

@keyframes partner-marquee-thumb-travel {
  from { transform: translateX(0); }
  to { transform: translateX(3.25rem); } /* track width (4rem) - thumb width (0.75rem) */
}

/* margin-top matches .home-hero__pagination's margin-bottom (its
   caption sits right below it the same way this count sits below
   .partner-marquee__progress) — same "pagination row, then a line of
   mono text right under it" rhythm in both places. */
.partner-marquee__count {
  margin: 0.75rem 0 0;
  font-family: var(--font-mono);
  font-size: 0.75rem;
  line-height: 1.3;
  color: var(--color-muted);
}

/* "in {industry}" directly under the count — same mono/muted line,
   tighter margin than .partner-marquee__count gets above it since
   together they read as one two-line aside, not two separate ones.
   The industry name itself (not "in") is the one that's swapped out,
   via hero-carousel.js's setInterval + typeInto reusing the hero
   caption's own typewriter effect — data-industries (components.rkt)
   is the comma-separated list it cycles through. line-height/
   min-height match .home-hero__caption-client/-event, and for the
   same reason: that typewriter effect blanks the text briefly between
   clearing and the first typed character, and without a reserved
   height an empty line collapses, visibly shifting whatever's below
   it on every cycle. */
.partner-marquee__industries {
  margin: 0.15rem 0 0;
  font-family: var(--font-mono);
  font-size: 0.75rem;
  line-height: 1.3;
  min-height: 1.3em;
  color: var(--color-primary);
}


/* Same blinking caret as the hero caption's own .is-typing — reusing
   its keyframe, not redeclaring an identical one. */
.partner-marquee__industry.is-typing::after {
  content: "_";
  animation: home-hero-caret-blink 1s step-end infinite;
}

@media (prefers-reduced-motion: reduce) {
  .partner-marquee__track { animation: none; }
  .partner-marquee__progress-fill { animation: none; }
  .home-hero.is-paused .home-hero__control--playpause { animation: none; }
  .home-hero__slide { transition: none; }
}

/* sections */

/* Vertical rhythm only — horizontal width/padding is the .container's
   job (applied directly to a <section>, or nested inside one for a
   full-bleed background like .alt), not this tag selector's. That
   split is deliberate: .alt wants this vertical spacing while its
   background stays full-bleed and only its (nested) content gets
   width-constrained — one rule can't give a section both behaviors
   for the same property. */
main section {
  padding-top: 3.5rem;
  padding-bottom: 3.5rem;
}

main section.alt {
  background: var(--color-bg-alt);
}

h2 {
  font-size: 3.5rem;
  line-height: 4rem;
  margin-top: 0;
  margin-bottom: 0.5rem;
}

/* Same mobile cutoff the hero's own h1 and .home-hero's 100vh/
   .sticky-cta's hide use elsewhere. Tight unitless line-height, same
   reasoning as .home-hero__inner h1: 4rem (sized for the 3.5rem
   desktop font-size) would be badly loose against 2.25rem. */
@media (max-width: 60rem) {
  h2 {
    font-size: 2.25rem;
    line-height: 1;
  }
}

/* a second-level heading within a section, e.g. "So arbeiten wir"
   under "Leistungen im Überblick" */
main section > h3 {
  font-size: 1.4rem;
  margin-top: 3rem;
}

.lead {
  font-size: 1.5rem;
  line-height: 2rem;
  margin-top: 0;
  margin-bottom: 4rem;
  color: #777;
  max-width: 40rem;
}

/* Same small-circle-plus-Lucide-icon look as .home-hero__control, in
   its own rule (not a shared class) since the colors invert for a
   plain light section instead of a dark photo — dark-tinted fill
   instead of white-tinted, var(--color-dark) icon instead of #fff. */
.carousel-nav__btn {
  appearance: none;
  -webkit-appearance: none;
  flex: none;
  width: 1rem;
  height: 1rem;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: rgba(0,0,0,0.08);
  color: var(--color-dark);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: background-color 0.2s ease;
}

.carousel-nav__btn svg { width: 0.625rem; height: 0.625rem; }

.carousel-nav__btn:hover { background: rgba(0,0,0,0.15); }

.carousel-nav__btn:disabled {
  opacity: 0.35;
  cursor: default;
}

.carousel-nav__btn:disabled:hover { background: rgba(0,0,0,0.08); }

/* Scoped to #leistungen (not the shared h2/.lead rules) — these two
   spacing tweaks are specific to "Ihr Partner für jede Messe" and its
   lead paragraph, not every section heading/intro on the site. */
#leistungen h2 { margin-top: 6rem; }
#leistungen .lead { margin-bottom: 4rem; }

/* carousel ("how we work" step cards) — full-bleed scroller: breaks
   out of the section's max-width so cards can scroll to the true
   viewport edge, while calculated padding keeps the first card
   aligned with the rest of the page's content column. Trailing
   padding on a scroll container is inconsistently honored across
   browsers, so the right-side gutter is a spacer element (::after)
   instead — same pattern goodi's carousel uses. */

.carousel {
  margin-top: 2rem;
  margin-left: calc(50% - 50vw);
  margin-right: calc(50% - 50vw);
}

.carousel__track {
  display: flex;
  gap: 1.25rem;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  scroll-padding-left: max(1.25rem, calc((100% - var(--content-width)) / 2));
  list-style: none;
  margin: 0;
  padding: 0.25rem 0 0.5rem;
  padding-left: max(1.25rem, calc((100% - var(--content-width)) / 2));
  cursor: grab;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
}

.carousel__track::-webkit-scrollbar { display: none; }

.carousel__track:focus-visible {
  outline: 2px solid var(--color-dark);
  outline-offset: -4px;
}

.carousel__track.grabbing {
  cursor: grabbing;
  scroll-snap-type: none;
  user-select: none;
}

.carousel__track > li {
  flex-shrink: 0;
  width: min(22.5rem, calc(100% - 2rem));
  scroll-snap-align: start;
}

/* trailing spacer so the last card gets the same right-side gutter
   the first card gets from padding-left above */
.carousel__track::after {
  content: "";
  flex-shrink: 0;
  width: max(1.25rem, calc(100vw - 23.75rem));
}

/* stop the browser's native image-drag (which was hijacking our
   custom drag-to-scroll) — pointer-events: none lets mouse events
   fall through to the card link beneath instead of the <img> */
.carousel__track img {
  -webkit-user-drag: none;
  user-select: none;
  pointer-events: none;
}

/* Below the cards: pagination dots, then prev/next underneath them
   (not off to the side, as before) — same stack, just vertical now.
   Left padding here (not on the two children) is the same formula
   .carousel__track uses above, keyed off var(--content-width) rather
   than .container's own (wider) gutter — so this column lands at the
   same x position as "So arbeiten wir" and the cards above. */
.carousel__footer {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.75rem;
  margin-top: 1.25rem;
  padding-left: max(1.25rem, calc((100% - var(--content-width)) / 2));
}

.carousel__pagination {
  display: flex;
  gap: 0.4rem;
}

.carousel-nav {
  display: flex;
  gap: 0.5rem;
}

/* Same monospace/muted treatment as .partner-marquee__count — a
   small aside under the pagination row, not content of its own.
   Nested inside .carousel__footer now (a flex column, see above)
   rather than a sibling below it, so its left-edge alignment and the
   gap before/after it both come from there, not its own margin/
   padding. */
.carousel__experience {
  margin: 0;
  font-family: var(--font-mono);
  font-size: 0.75rem;
  color: var(--color-muted);
}

/* Same small-square-grows-to-a-bar language as
   .home-hero__pagination-item, just on a light background (dark/25%
   fill instead of white/35%) and without that one's timeline-fill
   animation — this carousel is user-scrolled, not auto-advancing on a
   fixed duration, so there's nothing for a fill to count down. */
.carousel__dot {
  width: 2px;
  height: 2px;
  padding: 0;
  margin: 0;
  border: none;
  background: rgba(0,0,0,0.25);
  cursor: pointer;
  flex: none;
  transition: width 0.25s ease;
}

.carousel__dot.is-active {
  width: 2.75rem;
  background: var(--color-primary);
}

/* Poster-style card: full-bleed background image, rounded corners,
   bottom scrim gradient, left-aligned overlay text. img/scrim/content
   are stacked via z-index (not DOM/paint order — ::after would
   otherwise paint over .step-card__content, not under it). */

.step-card {
  position: relative;
  display: block;
  aspect-ratio: 2 / 3;
  border-radius: var(--radius);
  overflow: hidden;
  box-shadow: 0 1px 3px rgba(0,0,0,0.12);
  color: #fff;
}

.step-card img {
  position: absolute;
  inset: 0;
  z-index: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.3s ease;
}

/* Overflow: hidden on .step-card is what keeps this zoom from
   spilling past the card's rounded corners. */
.step-card:hover img { transform: scale(1.06); }

.step-card::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  background: linear-gradient(to top, rgba(0,0,0,0.85) 0%, rgba(0,0,0,0.35) 45%, transparent 75%);
}

.step-card__content {
  position: absolute;
  z-index: 2;
  left: 0;
  right: 0;
  bottom: 0;
  padding: 1.25rem;
  text-align: left;
}

.step-card__content h3 { margin: 0 0 0.25rem; font-size: 2rem; }
.step-card__content p { margin: 0; font-size: 1rem; color: rgba(255,255,255,0.85); }

/* storage / two-column */

.two-col {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 2.5rem;
  align-items: center;
}

@media (max-width: 40rem) {
  .two-col { grid-template-columns: 1fr; }
}

.two-col img { border-radius: var(--radius); }

/* Home page "Wir freuen uns..." contact section. Nested inside
   .content-wide (not .container directly) so its left/right edges
   line up with the headline/form under it, same as every other
   .content-wide use on the site. 2:1 via object-fit: cover so any
   source photo gets center-cropped to that ratio regardless of its
   own aspect ratio. Hidden for now rather than removed from the
   markup, in case it comes back. */
.team-photo {
  display: none;
  width: 100%;
  aspect-ratio: 2 / 1;
  object-fit: cover;
  border-radius: var(--radius);
  margin-bottom: 2rem;
}

/* .home-contact (not .alt generally, which other sections also use
   for their plain light-grey background) goes full brand-color — same
   dark-background pattern .site-footer uses below: override
   --container-border-color so the nested .container's border reads
   against this background instead of vanishing at its default
   black-based rgba, and set color so text inherits white without
   every descendant (h2, dt/dd, labels) needing its own override. A
   class, not the section's #kontakt/#contact id (German vs. English
   anchor name) — the id differs per language, so styling and
   hero-carousel.js's [data-header-theme] lookup (see .site-header's
   rules above) both need something that doesn't. */
.home-contact {
  /* So the hero's CTA button (anchor-linked straight to #kontakt/
     #contact now, not a separate page) doesn't scroll the section
     in flush under the fixed home-page header, hiding its top edge. */
  scroll-margin-top: 5rem;
}

.home-contact.alt {
  background: var(--color-primary);
  color: #fff;
  --container-border-color: rgba(255, 255, 255, 0.3);
  /* Same move .site-header's padding made above: main section's
     padding-top/bottom (generic rule, further up this file) lands on
     the *section*, outside the nested .container — fine for a plain
     background, but it leaves .container's border-left/border-right
     short of the section's full height instead of running edge to
     edge. Zero it here and add it back on .container instead. */
  padding-top: 0;
  padding-bottom: 0;
}

.home-contact .container {
  padding-top: 6rem;
  padding-bottom: 6rem;
}

.home-contact .contact-form__optional {
  border-color: rgba(255, 255, 255, 0.4);
}

.home-contact .contact-form__optional legend {
  color: rgba(255, 255, 255, 0.85);
}

/* portfolio */

.gallery {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
  gap: 1rem;
  margin-top: 2rem;
}

.gallery img, .gallery video { border-radius: var(--radius); }

/* Single-column "talk to the owner directly" section under the home
   page's contact form (see Helmut's photo in index.html.pp) — left-
   aligned, on .content-wide (not the narrower .content) so its left
   edge lines up with the other home-page sections above it, but
   still capped narrower than that so a 1200px-wide source photo
   doesn't just get stretched to the full line-length column. */
/* Matches .inquiry-form's own max-width — the questions above. */
.founder img {
  /* width: 100% (not just max-width) so it actually shrinks below
     32rem on a narrower container instead of holding that fixed
     512px floor and overflowing — max-width alone only caps the top
     end, same gap the global img{max-width:100%} rule (overridden
     here by this more specific selector) exists to close everywhere
     else. */
  width: 100%;
  max-width: 32rem;
  margin: 5rem 0;
  border-radius: var(--radius);
}

/* contact */

.contact-details dt {
  font-weight: 700;
  margin-top: 1rem;
}

.contact-details dd { margin: 0.1rem 0 0; }

/* Phone/email as the visual focus of the block — mono (matches the
   site's other mono-set numerals/labels), sized well past body text,
   and quiet until hovered: no underline at rest, color stays #333
   (overriding the global a/a:hover color — .contact-details dd a's
   extra specificity wins either way) so the only hover cue is the
   underline appearing, not a color shift. */
.contact-details dd a {
  font-family: var(--font-mono);
  font-size: 3rem;
  color: #333;
  text-decoration: none;
}

.contact-details dd a:hover {
  text-decoration: underline;
}


form.contact-form {
  display: grid;
  gap: 1rem;
  max-width: 32rem;
  margin-top: 2rem;
}

form.contact-form label {
  display: block;
  font-weight: 600;
  margin-bottom: 0.3rem;
}

form.contact-form input,
form.contact-form textarea,
.inquiry-step__input {
  width: 100%;
  padding: 0.6rem 0.75rem;
  border: 1px solid #ccc;
  border-radius: var(--radius);
  font: inherit;
}

/* The two field groups contact-form builds (required fields, then
   the optional fieldset) are each their own mini-grid with the same
   1rem gap the outer form.contact-form grid uses between its direct
   children — field spacing stays visually consistent whether a field
   is in the required group or the optional one. */
.contact-form__required,
.contact-form__optional {
  display: grid;
  gap: 1rem;
}

/* Visually set apart from the required fields above it — a plain
   border is enough to read as "optional, answer if you can" without
   looking like a separate, more intimidating form. */
.contact-form__optional {
  border: 1px solid #e5e2dd;
  border-radius: var(--radius);
  margin: 0;
  padding: 0.5rem 1.25rem 1.25rem;
}

.contact-form__optional legend {
  padding: 0 0.4rem;
  font-weight: 600;
  font-size: 0.85rem;
  color: var(--color-muted);
}

/* guided sales-inquiry form (see inquiry.rkt / inquiry-form.js) */

.inquiry-form {
  display: grid;
  gap: 0.75rem;
  max-width: 32rem;
  margin-top: 2rem;
}


.inquiry-step {
    margin-top: 1rem;
    opacity: 1;
    transition: opacity 0.6s ease;
}

/* Starting point for the fade-in render() gives a freshly-appended
   step — either the next question or the summary row for the one
   just answered (see inquiry-form.js) — added before the element is
   in the document, then removed a frame later so the opacity change
   above actually transitions instead of snapping straight to 1.
   Previously-answered summary rows further up don't get this: they're
   rebuilt too (render() replaces the whole list every time) but look
   visually unchanged, so fading them as well would be a distraction,
   not a help. */
.inquiry-step.is-entering { opacity: 0; }


/* An answered step. Shared shell for both variants below — see
   .inquiry-step--active for the same step while it's still being
   asked. */
/* Every answered step keeps the same question-above-card shape it
   had while active — just the one chosen/typed answer below the
   question now, not the full option list (or input + continue
   button) — rather than collapsing into a one-line summary. The card
   is plain .inquiry-option plus .inquiry-option--done (see its own
   rule), and doubles as the edit control: clicking it re-opens the
   step (every option again, for a select; the field, for text/
   textarea). */
.inquiry-step--done {
  display: grid;
  gap: 0.5rem;
  /* padding: 0.4rem 0; */
}

/* The one step currently being asked — question, then either its
   option cards or its input/textarea + continue button, stacked with
   a consistent gap (so none of the pieces needs its own margin). */
.inquiry-step--active {
  display: grid;
  gap: 0.5rem;
}

.inquiry-step--active .inquiry-step__question,
.inquiry-step--done .inquiry-step__question {
  display: block;
  font-weight: 500;
    font-size: 1.25rem;
}

/* A select step's options, each its own full-width card rather than
   a native <select> — picking one both answers and advances, so
   there's no separate continue button here (unlike the text/textarea
   case below). Plain block layout with the gap as each card's own
   margin-bottom (not the container's `gap`) — see .is-leaving below,
   which needs that margin to be a per-card property it can collapse
   to 0, which a container-level `gap` can't do. */
.inquiry-step__options {
  display: block;
}

.inquiry-option {
  display: block;
  width: 100%;
  text-align: left;
  margin-bottom: 0.5rem;
  padding: 0.7rem 1rem;
  border: 1px solid #e5e2dd;
  border-radius: var(--radius);
  background: #fff;
  font: inherit;
    font-size: 1.5rem;
  font-weight: 600;
  color: #333;
  cursor: pointer;
  overflow: hidden;
  transition:
    border-color 0.15s ease,
    background-color 0.15s ease,
    opacity 0.3s ease,
    max-height 0.3s ease,
    margin-bottom 0.3s ease,
    padding-top 0.3s ease,
    padding-bottom 0.3s ease,
    border-top-width 0.3s ease,
    border-bottom-width 0.3s ease;
}

.inquiry-option:last-child { margin-bottom: 0; }

.inquiry-option:hover { border-color: var(--color-primary); }

/* The chosen card is disabled for the tail end of chooseOption's
   sequence in inquiry-form.js (simplest way to make it inert while
   it settles into its "answered" look) — without this, the browser's
   own default disabled-button dimming would mute that settle, which
   is supposed to read as a clean fade to .inquiry-option--done's
   colors, not a fade to a washed-out version of them. */
.inquiry-option:disabled { opacity: 1; cursor: default; }

/* The not-picked cards, on choosing one (see chooseOption in
   inquiry-form.js) — two stages, in sequence rather than together, so
   the chosen card stays put until the others are actually gone rather
   than drifting upward as they shrink underneath it:

   1. is-fading: just opacity, each card still holding its full size
      — so the chosen card doesn't move yet.
   2. is-leaving, added only once (1) has finished: now that they're
      invisible, their box collapses — margin-bottom closing along
      with it, not a fixed container gap, is what then lets the
      chosen card slide up with no gap left behind. max-height starts
      at the card's own measured height (set inline by JS, since
      "auto" can't be transitioned) and is driven to 0 here. */
.inquiry-option.is-fading { opacity: 0; }

.inquiry-option.is-leaving {
  opacity: 0;
  max-height: 0 !important;
  margin-bottom: 0;
  padding-top: 0;
  padding-bottom: 0;
  border-top-width: 0;
  border-bottom-width: 0;
}

/* The one card shown for an already-answered select step (see
   .inquiry-step--done-select) — same card, plus a small edit icon on
   the right so it still reads as re-openable now that it stands
   alone rather than among the rest of the options, and a light-orange
   tint instead of plain white so it visibly reads as "answered"
   rather than just another live option. */
.inquiry-option--done {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  background: var(--color-primary-light);
  border-color: var(--color-primary-light);
  color: #333;
}

.inquiry-option__edit-icon {
  display: inline-flex;
  flex: none;
  width: 1rem;
  height: 1rem;
  /* No color of its own — inherits .inquiry-option--done's #333. */
}

.inquiry-option__edit-icon svg { width: 100%; height: 100%; }

.inquiry-step__continue,
.inquiry-form__submit {
  justify-self: start;
}

/* Fixed, always-last name/email/phone/company block (see "contact"
   in the spec) — same two-column layout contact-form's own fieldset
   groups use. */
.inquiry-form__contact h3 {
  margin: 0;
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--color-muted);
}

.inquiry-form__contact-fields {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1rem;
}

@media (max-width: 30rem) {
  .inquiry-form__contact-fields { grid-template-columns: 1fr; }
}

.inquiry-form__contact-fields label {
  display: block;
  font-weight: 600;
  margin-bottom: 0.3rem;
}

/* Home page's version sits on .home-contact.alt's brand-orange
   background (see that rule) — .button's default orange-on-white
   look would otherwise disappear against it, and the muted grey
   below reads poorly too, so both get the same white-on-orange
   treatment .home-contact .contact-form__optional already uses. */
.home-contact .inquiry-form__contact h3 { color: rgba(255, 255, 255, 0.75); }

.home-contact .inquiry-option {
  border-color: rgba(255, 255, 255, 0.4);
  background: rgba(255, 255, 255, 0.9);
}

.home-contact .inquiry-option:hover { border-color: #fff; }

/* Same specificity (two classes) as .home-contact .inquiry-option
   above, so it'd otherwise lose to source order — declared after it
   so .inquiry-option--done's own tint actually wins here instead of
   being overridden back to the plain live-card fill. */
.home-contact .inquiry-option--done {
  background: var(--color-primary-light);
  border-color: var(--color-primary-light);
  color: #333;
}

.home-contact .inquiry-step__continue,
.home-contact .inquiry-form__submit {
  background: #fff;
  color: var(--color-primary);
}

.home-contact .inquiry-step__continue:hover,
.home-contact .inquiry-form__submit:hover {
  background: rgba(255, 255, 255, 0.85);
  color: var(--color-primary-dark);
}

/* footer */

/* Full-bleed grey background (not capped at .container's max-width —
   the footer's own inner .container div handles that, same split as
   .home-hero/.home-hero__inner). Same dark-background override of
   --container-border-color as .home-hero (see its rule), so that
   inner .container's border stays visible against this dark bg
   instead of the default black-on-light rendering nearly invisibly. */
.site-footer {
  /* Deliberately darker than var(--color-dark) (used for borders,
     the lang-switch pill, etc. elsewhere) — the footer wants to read
     as the end of the page, not just another --color-dark surface. */
  background: #2e2a28;
  text-align: left;
  font-family: var(--font-mono);
  color: rgba(255,255,255,0.8);
  font-size: 0.9rem;
  --container-border-color: rgba(255,255,255,0.1);
}

.site-footer .container {
  padding-top: 2rem;
  padding-bottom: 2rem;
}

.site-footer p { margin: 0.25rem 0; }

/* Four independent blocks (contact, address, legal, bank details —
   see page-foot in pollen.rkt), stacked with a blank-line-sized gap
   between each. */
.footer-groups {
  display: grid;
  gap: 1.5rem;
}

/* Plain text, not a normal link — no color of its own (inherits the
   footer's own rgba(255,255,255,0.8)) and no underline. */
.footer-group a {
  color: inherit;
  text-decoration: none;
}

.footer-group .contact-details { margin: 0; }

/* The big mono phone/email (see .contact-details dd a) lived at the
   top of the home page's contact section originally — moved here so
   it's reachable from every page, not just that one. Its #333/3rem
   styling was sized for sitting alone on a bright background; here
   it's one piece among the footer's other (0.9rem) text on a near-
   black one, so both get dialed back to fit in. */
.site-footer .contact-details dd a { font-size: 1.5rem; color: #fff; }

/* sticky mobile CTA bar — hidden for now (the hero itself is a full
   100vh on mobile below, with its own "Jetzt anfragen"/"Get in
   touch" button already on screen, so this duplicate bar pinned to
   the bottom isn't earning its keep). Left in, not deleted, in case
   that changes again. */

.sticky-cta { display: none; }

@media (max-width: 60rem) {
  .sticky-cta {
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    z-index: 40;
    gap: 0.75rem;
    padding: 0.6rem 1rem;
    background: #fff;
    border-top: 1px solid #e5e2dd;
    box-shadow: 0 -2px 8px rgba(0,0,0,0.1);
  }

  .sticky-cta-phone {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    border: 1px solid var(--color-dark);
    border-radius: var(--radius);
    color: var(--color-dark);
    text-decoration: none;
    font-weight: 600;
    font-size: 0.9rem;
  }

  .sticky-cta .button {
    flex: 1;
    text-align: center;
  }
}
