/* AllExpress24 ------------------------------------------------------------
   Self-hosted, no external requests: no web fonts, no CDN, no trackers.
   That is a deliberate GDPR decision, not a shortcut. It is why this site
   needs no cookie banner.
   ------------------------------------------------------------------------ */

:root {
  --navy: #1b3b6f;
  --navy-900: #10254a;
  --navy-700: #234a89;
  --navy-50: #eef3fa;
  --orange: #ff6b35;
  --orange-600: #e85520;
  --orange-50: #fff2ec;

  --ink: #14213d;
  --body: #46536b;
  --muted: #6b7789;
  --line: #dfe5ee;
  --bg: #ffffff;
  --bg-alt: #f6f8fc;

  --radius: 14px;
  --radius-sm: 9px;
  --shadow-sm: 0 1px 2px rgba(20, 33, 61, .06), 0 2px 8px rgba(20, 33, 61, .05);
  --shadow: 0 4px 12px rgba(20, 33, 61, .07), 0 18px 40px rgba(20, 33, 61, .07);

  --wrap: 1160px;
  --gap: clamp(1.25rem, 3vw, 2.25rem);

  --font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue",
          Arial, "Noto Sans", "Liberation Sans", sans-serif;
}

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
/* Motion is decoration here, never information. Everything animated has a
   readable static state, so killing all of it costs the visitor nothing. */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
  .marquee-track { animation: none !important; flex-wrap: wrap; justify-content: center; width: 100%; }
  /* .riders is SMIL (<animateMotion>), which CSS animation rules do not reach,
     so it has to be removed outright rather than paused. */
  .hero-orb, .hero-grid, .route-pulse, .riders { display: none; }
}

body {
  margin: 0;
  font-family: var(--font);
  font-size: clamp(1rem, .97rem + .15vw, 1.0625rem);
  line-height: 1.65;
  color: var(--body);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3 { color: var(--ink); line-height: 1.18; letter-spacing: -.018em; margin: 0 0 .6em; }
h1 { font-size: clamp(2rem, 1.35rem + 2.7vw, 3.15rem); font-weight: 800; }
h2 { font-size: clamp(1.5rem, 1.2rem + 1.3vw, 2.1rem); font-weight: 750; }
h3 { font-size: clamp(1.08rem, 1rem + .35vw, 1.25rem); font-weight: 700; }
p { margin: 0 0 1rem; }
a { color: var(--navy-700); text-decoration-thickness: 1px; text-underline-offset: 3px; }
a:hover { color: var(--orange-600); }
img, svg { max-width: 100%; }
ul, ol { margin: 0 0 1rem; padding-left: 1.15rem; }

:focus-visible {
  outline: 3px solid var(--orange);
  outline-offset: 2px;
  border-radius: 4px;
}

.wrap { width: min(100% - 2.5rem, var(--wrap)); margin-inline: auto; }
.wrap-narrow { width: min(100% - 2.5rem, 760px); margin-inline: auto; }

.visually-hidden {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

.skip {
  position: absolute; left: 50%; translate: -50% -140%;
  z-index: 100; background: var(--navy); color: #fff;
  padding: .7rem 1.2rem; border-radius: 0 0 var(--radius-sm) var(--radius-sm);
  font-weight: 600; text-decoration: none; transition: translate .18s;
}
.skip:focus { translate: -50% 0; color: #fff; }

.icon { width: 24px; height: 24px; flex: none; }
.icon-sm { width: 17px; height: 17px; }

/* ---------------------------------------------------------------- buttons */

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: .5rem;
  padding: .72rem 1.3rem;
  border: 1.5px solid transparent; border-radius: var(--radius-sm);
  font: inherit; font-weight: 650; line-height: 1.25;
  text-decoration: none; cursor: pointer;
  transition: background-color .16s, color .16s, border-color .16s, transform .16s, box-shadow .16s;
}
.btn:active { transform: translateY(1px); }
.btn-lg { padding: .9rem 1.6rem; font-size: 1.02rem; }
.btn-block { display: flex; width: 100%; margin-top: .6rem; }

.btn-accent { background: var(--orange); color: #fff; box-shadow: 0 6px 16px rgba(255, 107, 53, .28); }
.btn-accent:hover { background: var(--orange-600); color: #fff; box-shadow: 0 8px 22px rgba(255, 107, 53, .34); }

.btn-outline { border-color: var(--line); background: #fff; color: var(--navy); }
.btn-outline:hover { border-color: var(--navy); background: var(--navy-50); color: var(--navy); }

.btn-ghost { border-color: rgba(255, 255, 255, .45); color: #fff; background: transparent; }
.btn-ghost:hover { background: rgba(255, 255, 255, .12); color: #fff; border-color: #fff; }

/* WhatsApp buttons carry WhatsApp's own green. People scan for that colour
   rather than reading the label, and it separates "message me now" from the
   orange "get a quote" path instead of making them compete. */
.btn-whatsapp { background: #25d366; color: #fff; box-shadow: 0 6px 16px rgba(37, 211, 102, .3); }
.btn-whatsapp:hover { background: #1eb85a; color: #fff; box-shadow: 0 8px 22px rgba(37, 211, 102, .36); }
.btn-whatsapp .icon { color: #fff; }

/* ----------------------------------------------------------------- header */

.site-header {
  position: sticky; top: 0; z-index: 50;
  background: rgba(255, 255, 255, .93);
  backdrop-filter: saturate(180%) blur(10px);
  border-bottom: 1px solid var(--line);
}
.header-inner { display: flex; align-items: center; gap: 1rem; min-height: 68px; }
.brand { display: inline-flex; align-items: center; flex: none; order: 1; }
.brand img { display: block; height: 30px; width: auto; }

/* Explicit order, because the language switcher is a sibling of the nav rather
   than a child of it: DOM order is brand, nav, language, CTA, burger, and the
   burger has to keep its place at the far edge in both LTR and RTL. */
.site-nav { order: 2; }
.dd-lang { order: 3; }
.nav-cta { order: 4; }
.nav-toggle { order: 5; }

.nav-toggle {
  display: none;
  width: 44px; height: 44px; padding: 0;
  background: none; border: 1px solid var(--line); border-radius: var(--radius-sm);
  cursor: pointer; color: var(--navy);
}
.nav-toggle-bars { display: grid; gap: 4px; justify-items: center; }
.nav-toggle-bars span { display: block; width: 19px; height: 2px; background: currentColor; border-radius: 2px; transition: translate .18s, rotate .18s, opacity .18s; }
.nav-toggle[aria-expanded="true"] .nav-toggle-bars span:nth-child(1) { translate: 0 6px; rotate: 45deg; }
.nav-toggle[aria-expanded="true"] .nav-toggle-bars span:nth-child(2) { opacity: 0; }
.nav-toggle[aria-expanded="true"] .nav-toggle-bars span:nth-child(3) { translate: 0 -6px; rotate: -45deg; }

.site-nav { display: flex; align-items: center; gap: .5rem; margin-inline-start: auto; }
.nav-list { display: flex; align-items: center; gap: .25rem; list-style: none; margin: 0; padding: 0; }
.nav-link {
  display: block; padding: .5rem .62rem; border-radius: var(--radius-sm);
  color: var(--ink); font-size: .935rem; font-weight: 550; text-decoration: none;
}
.nav-link:hover { background: var(--navy-50); color: var(--navy); }
.nav-link[aria-current="page"] { color: var(--navy); box-shadow: inset 0 -2px 0 var(--orange); }

/* Dropdowns, built on <details> so they work with JavaScript disabled.
   Five service names plus five language names laid out side by side filled the
   whole bar and squeezed out the CTA, which is the only element in the header
   that makes money. */
.dd { position: relative; }
.dd > summary {
  display: flex; align-items: center; gap: .38rem;
  padding: .5rem .62rem; border-radius: var(--radius-sm);
  color: var(--ink); font-size: .935rem; font-weight: 550;
  cursor: pointer; list-style: none; white-space: nowrap;
}
.dd > summary::-webkit-details-marker { display: none; }
.dd > summary:hover { background: var(--navy-50); color: var(--navy); }
.dd[open] > summary { background: var(--navy-50); color: var(--navy); }
.dd[data-active] > summary { box-shadow: inset 0 -2px 0 var(--orange); }

.dd-caret {
  width: 7px; height: 7px; margin-left: .1rem;
  border-right: 1.8px solid currentColor; border-bottom: 1.8px solid currentColor;
  rotate: 45deg; translate: 0 -2px; transition: rotate .18s, translate .18s;
}
.dd[open] .dd-caret { rotate: 225deg; translate: 0 2px; }

.dd-menu {
  position: absolute; z-index: 60; top: calc(100% + .45rem); left: 0;
  min-width: 232px; margin: 0; padding: .35rem; list-style: none;
  background: #fff; border: 1px solid var(--line); border-radius: var(--radius);
  box-shadow: var(--shadow);
  animation: dd-in .16s ease-out;
}
.dd-menu-end { left: auto; right: 0; min-width: 168px; }
[dir="rtl"] .dd-menu { left: auto; right: 0; }
[dir="rtl"] .dd-menu-end { right: auto; left: 0; }
@keyframes dd-in { from { opacity: 0; translate: 0 -5px; } to { opacity: 1; translate: 0 0; } }

.dd-menu a {
  display: flex; align-items: center; gap: .6rem;
  padding: .6rem .65rem; border-radius: var(--radius-sm);
  color: var(--ink); font-size: .93rem; font-weight: 550; text-decoration: none;
  white-space: nowrap;
}
.dd-menu a:hover { background: var(--navy-50); color: var(--navy); }
.dd-menu a[aria-current="page"] { background: var(--orange-50); color: var(--orange-600); }
.dd-menu .icon { color: var(--navy-700); }
.dd-menu a:hover .icon { color: var(--orange-600); }

/* Language codes, not flags: a flag is a country, not a language. */
.lang-code { font-size: .78rem; font-weight: 700; letter-spacing: .04em; }
.dd-lang .lang-code { color: var(--muted); }
.dd-lang[open] .lang-code, .dd-lang > summary:hover .lang-code { color: var(--navy); }
.dd-menu a.is-current { background: var(--navy-50); color: var(--navy); }
.dd-menu a .lang-code { min-width: 1.7rem; color: var(--muted); }
.dd-menu a.is-current .lang-code { color: var(--orange-600); }

.nav-cta { padding: .6rem 1.05rem; font-size: .93rem; margin-inline-start: .35rem; }

@media (max-width: 1040px) {
  .nav-toggle { display: grid; place-items: center; }
  .site-nav {
    position: fixed; inset: 68px 0 auto; display: none;
    flex-direction: column; align-items: stretch; gap: 1rem;
    padding: 1.25rem; background: #fff;
    border-bottom: 1px solid var(--line); box-shadow: var(--shadow);
    max-height: calc(100dvh - 68px); overflow-y: auto;
    margin-inline-start: 0;
  }
  .site-nav.is-open { display: flex; }
  .nav-list { flex-direction: column; align-items: stretch; gap: 0; }
  .nav-link { padding: .85rem .6rem; border-bottom: 1px solid var(--line); border-radius: 0; font-size: 1rem; }

  /* Inside the collapsed panel the services dropdown expands inline. The
     language dropdown is NOT in that panel any more, so these rules are scoped
     to .site-nav or they would flatten the floating language menu too. */
  .site-nav .dd > summary { padding: .85rem .6rem; border-bottom: 1px solid var(--line); border-radius: 0; font-size: 1rem; }
  .site-nav .dd-menu {
    position: static; min-width: 0; margin: 0; padding: .2rem 0 .5rem .6rem;
    border: 0; border-bottom: 1px solid var(--line); border-radius: 0;
    box-shadow: none; animation: none;
  }
  .site-nav .dd-menu a { padding: .7rem .5rem; }

  /* The language switcher lives in the bar itself, always one tap away. */
  .dd-lang { margin-inline-start: auto; }
  .dd-lang > summary {
    min-height: 44px; padding: 0 .6rem;
    border: 1px solid var(--line); border-radius: var(--radius-sm);
  }
  .dd-lang .lang-code { color: var(--navy); font-size: .84rem; }
  .dd-menu-end { min-width: 190px; }

  /* Hidden on phones only: the sticky bottom bar already carries this CTA, and
     three controls plus a logo do not fit across 375px without crowding. */
  .nav-cta { margin-inline-start: 0; }
  @media (max-width: 720px) { .nav-cta { display: none; } }
}

/* ------------------------------------------------------------------- hero */

.hero {
  background:
    radial-gradient(1100px 480px at 88% -10%, rgba(255, 107, 53, .16), transparent 62%),
    linear-gradient(168deg, var(--navy-900), var(--navy) 58%, #22508f);
  color: #fff; padding: clamp(3rem, 7vw, 5.5rem) 0;
}
.hero-inner { display: grid; grid-template-columns: minmax(0, 1.15fr) minmax(0, .85fr); gap: var(--gap); align-items: center; }
.hero h1 { color: #fff; }
.hero .lead { font-size: clamp(1.05rem, 1rem + .45vw, 1.24rem); color: rgba(255, 255, 255, .87); max-width: 56ch; }
.hero-actions { display: flex; flex-wrap: wrap; gap: .7rem; margin: 1.6rem 0 0; }
@media (max-width: 900px) { .hero-inner { grid-template-columns: 1fr; } }

/* --------------------------------------------------- hero with the picker */
/* The client asked why a visitor has to scroll past a headline to find out what
   is sold. He is right, and the answer is not to delete the headline: it is the
   page's only h1 and it carries every keyword the site ranks for. So the hero
   got shorter and the six services moved into it. One band, one screen, one
   decision, and the h1 still says "Umzug, Transport und Reinigung in Frankfurt"
   to anything that reads markup. */

.hero-pick { padding: clamp(2.2rem, 4.5vw, 3.6rem) 0; }
.hero-pick .hero-inner { grid-template-columns: minmax(0, .92fr) minmax(0, 1.08fr); align-items: center; }
.hero-pick h1 { font-size: clamp(1.75rem, 1.35rem + 1.9vw, 2.85rem); }
.hero-pick .lead { margin-bottom: 0; }

.hero-eyebrow {
  display: flex; flex-wrap: wrap; align-items: center; gap: .5rem;
  margin: 0 0 .9rem; padding: 0; list-style: none;
  font-size: .8rem; font-weight: 700; letter-spacing: .06em; text-transform: uppercase;
  color: rgba(255, 255, 255, .72);
}
.hero-eyebrow span + span::before {
  content: ""; display: inline-block; vertical-align: middle;
  width: 4px; height: 4px; margin-inline-end: .55rem;
  border-radius: 50%; background: var(--orange);
}

.hero-trust { display: flex; flex-wrap: wrap; gap: .5rem 1.1rem; margin: 1.1rem 0 0; padding: 0; list-style: none; }
.hero-trust li { display: flex; align-items: center; gap: .4rem; font-size: .88rem; color: rgba(255, 255, 255, .82); }
.hero-trust .icon { color: var(--orange); flex: none; }

.hero-pick-panel {
  padding: 1.15rem; border-radius: var(--radius);
  background: rgba(255, 255, 255, .07); border: 1px solid rgba(255, 255, 255, .16);
  backdrop-filter: blur(2px);
}
.pick-title {
  margin: 0 0 .85rem; color: #fff;
  font-size: 1.02rem; font-weight: 700; letter-spacing: .01em;
}
.hero-pick-panel .tiles { grid-template-columns: 1fr 1fr; gap: .6rem; }
.pick-all {
  display: inline-flex; align-items: center; gap: .4rem;
  margin-top: .95rem; font-size: .92rem; font-weight: 700;
  color: #fff; text-decoration: none;
  border-bottom: 1px solid rgba(255, 107, 53, .7); padding-bottom: 2px;
}
.pick-all:hover { border-bottom-color: var(--orange); }
.pick-all .icon { color: var(--orange); transition: translate .18s; }
.pick-all:hover .icon { translate: 3px 0; }

@media (max-width: 900px) {
  .hero-pick .hero-inner { grid-template-columns: 1fr; gap: 1.4rem; }
  /* The trust row and the two buttons are the two blocks between the headline
     and the services on a phone. The proof band directly below repeats the same
     claims as numbers and the sticky bar carries call and WhatsApp, so both are
     redundant here and both cost the thing the client actually asked for:
     services on the first screen. */
  .hero-pick .hero-trust,
  .hero-pick .hero-actions { display: none; }
  .hero-pick-panel { padding: .85rem; }
}

/* ----------------------------------------------------- hero motion layer */
/* Pure CSS and SVG. No images, no JS, no stock photography. Everything here
   stops dead under prefers-reduced-motion (see the block at the end). */

.hero { position: relative; overflow: hidden; isolation: isolate; }
.hero-inner { position: relative; z-index: 2; }
.hero-motion { position: absolute; inset: 0; z-index: 1; pointer-events: none; }

.hero-routes { position: absolute; inset: 0; width: 100%; height: 100%; }

/* The pulse is a short dash chased along the same path as the static line,
   so it reads as movement along a route rather than a decorative squiggle. */
.route-pulse path {
  stroke-dasharray: 14 100;
  animation: route-run 9s cubic-bezier(.55, 0, .45, 1) infinite;
}
.route-pulse path:nth-child(2) { animation-duration: 11s; animation-delay: -3.5s; }
@keyframes route-run {
  0%   { stroke-dashoffset: 114; opacity: 0; }
  12%  { opacity: 1; }
  88%  { opacity: 1; }
  100% { stroke-dashoffset: 0; opacity: 0; }
}

/* Service vehicles riding the routes. The badge is what keeps a thin white
   stroke legible over the gradient without adding a drop shadow. */
.rider-badge { fill: rgba(255, 255, 255, .1); stroke: rgba(255, 255, 255, .22); stroke-width: 1; }
.rider-icon {
  fill: none; stroke: #fff; stroke-width: 1.7;
  stroke-linecap: round; stroke-linejoin: round;
}
.riders .rider:nth-child(1) .rider-icon { stroke: var(--orange); }
.riders .rider:nth-child(3) .rider-icon { stroke: var(--orange); }

/* Hidden unless the browser can actually place them on the route. Without
   offset-path they would all pile up at the SVG origin, which looks broken. */
.riders { display: none; }
@supports (offset-path: path("M0 0")) {
  .riders { display: block; }
  .rider {
    opacity: .85;
    offset-rotate: auto;
    offset-distance: 0%;
    animation: ride var(--dur, 20s) linear var(--delay, 0s) infinite;
  }
}
@keyframes ride {
  from { offset-distance: 0%; }
  to   { offset-distance: 100%; }
}

.hero-orb {
  position: absolute; border-radius: 50%;
  filter: blur(70px); opacity: .5; will-change: transform;
}
.hero-orb-1 {
  width: 46vw; height: 46vw; max-width: 620px; max-height: 620px;
  top: -18%; right: -8%;
  background: radial-gradient(circle, rgba(255, 107, 53, .55), transparent 68%);
  animation: drift-a 26s ease-in-out infinite alternate;
}
.hero-orb-2 {
  width: 38vw; height: 38vw; max-width: 500px; max-height: 500px;
  bottom: -26%; left: -10%;
  background: radial-gradient(circle, rgba(90, 160, 255, .42), transparent 68%);
  animation: drift-b 32s ease-in-out infinite alternate;
}
@keyframes drift-a {
  from { transform: translate3d(0, 0, 0) scale(1); }
  to   { transform: translate3d(-5%, 7%, 0) scale(1.12); }
}
@keyframes drift-b {
  from { transform: translate3d(0, 0, 0) scale(1.08); }
  to   { transform: translate3d(7%, -6%, 0) scale(1); }
}

/* Slow-scrolling grid: gives the block depth without competing with the text. */
.hero-grid {
  position: absolute; inset: -50% -10% -10%;
  background-image:
    linear-gradient(rgba(255, 255, 255, .05) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255, 255, 255, .05) 1px, transparent 1px);
  background-size: 62px 62px;
  mask-image: radial-gradient(120% 70% at 50% 40%, #000 20%, transparent 72%);
  animation: grid-slide 34s linear infinite;
}
@keyframes grid-slide {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(62px, 62px, 0); }
}

/* Entrance: content settles in once, it does not loop. */
.hero-copy > * { animation: rise .7s cubic-bezier(.2, .7, .3, 1) backwards; }
.hero-copy > :nth-child(1) { animation-delay: .04s; }
.hero-copy > :nth-child(2) { animation-delay: .12s; }
.hero-copy > :nth-child(3) { animation-delay: .2s; }
.hero-copy > :nth-child(4) { animation-delay: .28s; }
.hero-copy > :nth-child(5) { animation-delay: .36s; }
.hero-panel-inner { animation: rise .8s cubic-bezier(.2, .7, .3, 1) .3s backwards; }
@keyframes rise {
  from { opacity: 0; transform: translate3d(0, 14px, 0); }
  to   { opacity: 1; transform: none; }
}

.chip { animation: float-chip 7s ease-in-out infinite; }
.chip:nth-child(2) { animation-delay: -1.4s; }
.chip:nth-child(3) { animation-delay: -2.8s; }
.chip:nth-child(4) { animation-delay: -4.2s; }
.chip:nth-child(5) { animation-delay: -5.6s; }
@keyframes float-chip {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-5px); }
}

/* -------------------------------------------------------------- partners */

.partners { padding: clamp(1.6rem, 3vw, 2.2rem) 0; background: #fff; border-bottom: 1px solid var(--line); }
.partners-title {
  margin: 0 0 1rem; text-align: center;
  font-size: .76rem; font-weight: 700; letter-spacing: .12em;
  text-transform: uppercase; color: var(--muted);
}
.marquee {
  overflow: hidden;
  mask-image: linear-gradient(90deg, transparent, #000 9%, #000 91%, transparent);
}
.marquee-track {
  display: flex; align-items: center;
  width: max-content; margin: 0; padding: 0; list-style: none;
  animation: marquee 22s linear infinite;
}
.marquee.is-paused .marquee-track { animation-play-state: paused; }

/* The track holds the logo list twice, so a 50% shift lands exactly on the
   start of the duplicate and the loop has no seam. Spacing is a per-item
   margin, NOT flex gap: gap is only applied *between* children, so the
   duplicated half comes out one gap short and the loop visibly jumps. */
.marquee-item { margin-inline-end: clamp(2.5rem, 6vw, 4.5rem); }
@keyframes marquee {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(-50%, 0, 0); }
}
/* Full colour, not greyscale. Two of these logos are solid brand tiles (navy
   and turquoise); desaturating them turns them into grey boxes sitting next to
   floating wordmarks. Height comes per-logo from --logo-h, set at build time
   from the image's real aspect ratio. */
.marquee-item img {
  display: block; height: var(--logo-h, 34px); width: auto;
  opacity: .88; transition: opacity .2s, transform .2s;
}
.marquee-item:hover img, .marquee-item a:focus-visible img { opacity: 1; transform: scale(1.04); }

/* -------------------------------------------------------------- page hero */

.page-hero { background: var(--navy-50); border-bottom: 1px solid var(--line); padding: clamp(2rem, 5vw, 3.4rem) 0; }
.page-hero-inner { display: flex; gap: 1.4rem; align-items: flex-start; }
.page-hero .lead { font-size: clamp(1.02rem, .98rem + .4vw, 1.18rem); color: var(--ink); max-width: 62ch; }
.for-who { display: inline-block; padding: .35rem .75rem; border-radius: 999px; background: #fff; border: 1px solid var(--line); font-size: .9rem; font-weight: 600; color: var(--navy); }

.breadcrumbs { border-bottom: 1px solid var(--line); background: #fff; font-size: .85rem; }
.breadcrumbs ol { display: flex; flex-wrap: wrap; gap: .4rem; list-style: none; margin: 0; padding: .7rem 0; }
.breadcrumbs li + li::before { content: "/"; margin-right: .4rem; color: var(--line); }
.breadcrumbs a { color: var(--muted); text-decoration: none; }
.breadcrumbs a:hover { color: var(--navy); }
.breadcrumbs [aria-current] { color: var(--ink); font-weight: 600; }

/* --------------------------------------------------------------- sections */

.section { padding: clamp(2.75rem, 6vw, 4.75rem) 0; }
.section-alt { background: var(--bg-alt); border-block: 1px solid var(--line); }
.section-head { max-width: 62ch; margin-bottom: clamp(1.6rem, 3vw, 2.4rem); }
.section-head p { font-size: 1.06rem; color: var(--body); margin: 0; }

.grid { display: grid; gap: 1.1rem; }
/* Hard 3 columns on desktop: there are 5 services, and auto-fit would drop to
   4 across and leave a single orphan card on the second row. */
.grid-3 { grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); }
@media (min-width: 900px) { .grid-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
.grid-4 { grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); }
@media (min-width: 900px) { .grid-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); } }

.split { display: grid; grid-template-columns: minmax(0, 1.25fr) minmax(0, .9fr); gap: clamp(1.5rem, 4vw, 3.2rem); align-items: start; }
.split-form { grid-template-columns: minmax(0, 1.35fr) minmax(0, .8fr); }
@media (max-width: 880px) { .split, .split-form { grid-template-columns: 1fr; } }

/* ------------------------------------------------------------------ cards */

.card {
  display: block; padding: 1.5rem;
  background: #fff; border: 1px solid var(--line); border-radius: var(--radius);
  box-shadow: var(--shadow-sm); text-decoration: none; color: inherit;
  transition: transform .18s, box-shadow .18s, border-color .18s;
}
a.card:hover { transform: translateY(-3px); box-shadow: var(--shadow); border-color: #c9d6e8; }
.card h3, .card h2 { margin-bottom: .45rem; }
.card p { margin: 0; font-size: .96rem; }

.card-icon {
  display: grid; place-items: center;
  width: 50px; height: 50px; margin-bottom: 1rem;
  border-radius: 12px;
  background: var(--tint-solid, var(--navy-50)); color: var(--tint-ink, var(--navy));
  transition: transform .18s;
}
a.card:hover .card-icon { transform: scale(1.06) rotate(-3deg); }

/* One colour per service, carried across the home cards, the service page hero
   and the related-service cards. On a phone the whole site is one long scroll,
   and five identical white boxes in a row is where people stop reading. The
   colour also becomes a wayfinding cue: orange is always the moving pages. */
.tint { background: var(--tint-bg); border-color: var(--tint-line); }
.tint .card-icon { background: var(--tint-solid); color: #fff; }
.tint .card-more { color: var(--tint-ink); }
a.tint:hover { border-color: var(--tint-solid); }
a.tint:hover .card-more { color: var(--tint-ink); }

/* Six now that moving and transport are separate services, and they have to stay
   telling apart at 46px. Moving takes the brand orange because it is the
   flagship; transport takes the brand navy so the two siblings do not read as
   one smear of orange; the caretaker service moves to slate, which is the right
   register for it and frees the navy. */
.tint-umzug         { --tint-bg: #fff1ea; --tint-line: #ffd3bf; --tint-solid: #e2551f; --tint-ink: #b8410f; }
.tint-transport     { --tint-bg: #eef3fa; --tint-line: #cfddf1; --tint-solid: #1b3b6f; --tint-ink: #1b3b6f; }
.tint-entruempelung { --tint-bg: #ecf6ef; --tint-line: #c6e4d0; --tint-solid: #1f7a45; --tint-ink: #176035; }
.tint-auto          { --tint-bg: #f0eefb; --tint-line: #d6d0f0; --tint-solid: #4b3fa8; --tint-ink: #3d3390; }
.tint-reinigung     { --tint-bg: #e8f5fa; --tint-line: #bfe0ed; --tint-solid: #0e6f92; --tint-ink: #0b5a77; }
.tint-hausmeister   { --tint-bg: #eff1f4; --tint-line: #d3d8e0; --tint-solid: #4a5568; --tint-ink: #3c465a; }

.page-hero.tint { background: var(--tint-bg); border-bottom-color: var(--tint-line); }
.page-hero.tint .for-who { border-color: var(--tint-line); color: var(--tint-ink); }
.page-hero.tint .btn-outline { border-color: var(--tint-line); color: var(--tint-ink); }
.page-hero.tint .btn-outline:hover { border-color: var(--tint-solid); background: #fff; }

.card-more {
  display: inline-flex; align-items: center; gap: .35rem;
  margin-top: 1rem; font-size: .92rem; font-weight: 650; color: var(--navy);
}
a.card:hover .card-more { color: var(--orange-600); }
a.card:hover .card-more .icon { translate: 3px 0; }
.card-more .icon { transition: translate .18s; }

.card-mini { text-align: center; }
.card-mini .card-icon { margin-inline: auto; }
.card-mini h3 { margin: 0; font-size: 1rem; }

.card-contact { text-align: center; }
.card-contact .card-icon { margin-inline: auto; }
.card-contact h2 { font-size: 1.1rem; margin-bottom: .2rem; }
.card-contact p { color: var(--navy); font-weight: 600; }

.aside-card {
  padding: 1.6rem; background: var(--navy-50);
  border: 1px solid var(--line); border-radius: var(--radius);
  position: sticky; top: 88px;
}
.aside-card h2 { font-size: 1.2rem; }
@media (max-width: 880px) { .aside-card { position: static; } }

/* ------------------------------------------------------------------ lists */

.checklist { list-style: none; margin: 0 0 1.2rem; padding: 0; display: grid; gap: .65rem; }
.checklist li { display: flex; gap: .65rem; align-items: flex-start; }
.checklist .icon { margin-top: .28rem; color: var(--tint-solid, var(--orange)); }
.checklist-plain .icon { color: var(--navy); }

/* The "read more" control only ever exists on phones. JavaScript un-hides the
   button on every screen (it cannot know the breakpoint at parse time), so the
   default here has to be none or it appears on desktop next to text that is
   already fully visible. */
.more-toggle { display: none; }

/* On a phone the pill list answers "do you come to my city" instantly and the
   paragraph goes behind the toggle. On desktop there is room, so the original
   reading order is restored: paragraph, then pills. */
.areas-block { display: flex; flex-direction: column; align-items: flex-start; }
@media (min-width: 721px) {
  .areas-block .about-more { order: 2; }
  .areas-block .pills-first { order: 3; }
}

.pills { display: flex; flex-wrap: wrap; gap: .5rem; list-style: none; margin: 1rem 0 0; padding: 0; }
.pills li {
  display: inline-flex; align-items: center; gap: .35rem;
  padding: .4rem .8rem; background: #fff; border: 1px solid var(--line);
  border-radius: 999px; font-size: .88rem; font-weight: 550; color: var(--ink);
}
.pills .icon { color: var(--navy-700); }

.steps { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 1.1rem; list-style: none; margin: 0; padding: 0; counter-reset: step; }
.step { padding: 1.4rem; background: #fff; border: 1px solid var(--line); border-radius: var(--radius); box-shadow: var(--shadow-sm); }
.step-n { display: block; margin-bottom: .7rem; font-size: 1.55rem; font-weight: 800; color: var(--orange); letter-spacing: -.03em; }
.step h3 { margin-bottom: .35rem; }
.step p { margin: 0; font-size: .95rem; }

.mini-steps { display: grid; gap: .85rem; margin: 0; padding-left: 1.1rem; }
.mini-steps li strong { display: block; color: var(--ink); }
.mini-steps li span { font-size: .92rem; }

/* ---------------------------------------------------------------- reviews */

.stars { display: inline-flex; gap: 2px; vertical-align: -2px; }
.star { width: 17px; height: 17px; fill: var(--orange); }
.star-empty { fill: #d9dfe9; }

.rating-summary { display: flex; flex-wrap: wrap; align-items: center; gap: .55rem; margin: 0 0 1.5rem; font-size: .96rem; }
.rating-summary strong { font-size: 1.15rem; color: var(--ink); }
.rating-summary span { color: var(--muted); }
.rating-inline { display: flex; align-items: center; gap: .45rem; font-size: .92rem; }

/* Carousel dots exist in the HTML on every screen and only show up once the
   track is actually a track (phones). Desktop keeps the three-up grid. */
.rv-dots { display: none; }

.card-review { margin: 0; display: flex; flex-direction: column; gap: .8rem; }
.card-review blockquote { margin: 0; }
.card-review blockquote p { font-size: 1rem; color: var(--ink); }
.card-review figcaption { margin-top: auto; display: grid; gap: .1rem; font-size: .88rem; }
.card-review figcaption strong { color: var(--ink); }
.card-review figcaption span { color: var(--muted); }

/* -------------------------------------------------------------------- faq */

.faq-item { border-bottom: 1px solid var(--line); }
.faq-item summary {
  display: flex; justify-content: space-between; align-items: center; gap: 1rem;
  padding: 1.05rem 0; cursor: pointer; list-style: none;
  font-weight: 650; color: var(--ink); font-size: 1.03rem;
}
.faq-item summary::-webkit-details-marker { display: none; }
.faq-item summary::after {
  content: ""; flex: none; width: 11px; height: 11px;
  border-right: 2px solid var(--navy); border-bottom: 2px solid var(--navy);
  rotate: 45deg; translate: 0 -3px; transition: rotate .18s;
}
.faq-item[open] summary::after { rotate: 225deg; translate: 0 3px; }
.faq-item summary:hover { color: var(--navy-700); }
.faq-answer { padding-bottom: 1.15rem; }
.faq-answer p { margin: 0; max-width: 72ch; }

/* ------------------------------------------------------------------- band */

.band { background: linear-gradient(140deg, var(--navy-900), var(--navy) 70%); color: #fff; padding: clamp(2.4rem, 5vw, 3.6rem) 0; }
.band-inner { display: flex; flex-wrap: wrap; gap: 1.6rem; align-items: center; justify-content: space-between; }
.band h2 { color: #fff; margin-bottom: .4rem; }
.band p { margin: 0; color: rgba(255, 255, 255, .85); max-width: 54ch; }
.band-actions { display: flex; flex-wrap: wrap; gap: .7rem; }

/* ------------------------------------------------------------------- form */

.wrap-form { width: min(100% - 2.5rem, 900px); margin-inline: auto; }
.quote-form { display: grid; gap: 1.1rem; }
.required-hint { margin: .4rem 0 0; font-size: .88rem; color: var(--muted); }
.details-hint { margin: .6rem 0 0; font-size: .88rem; color: var(--muted); }

.step { margin: 0; padding: 1.5rem; border: 1px solid var(--line); border-radius: var(--radius); background: #fff; box-shadow: var(--shadow-sm); }
.step legend {
  display: flex; align-items: center; gap: .6rem;
  padding: 0 .5rem; margin-left: -.5rem;
  font-size: 1.1rem; font-weight: 700; color: var(--ink);
}
.step-num {
  display: grid; place-items: center; width: 26px; height: 26px;
  border-radius: 50%; background: var(--navy); color: #fff;
  font-size: .85rem; font-weight: 700;
}
.step > .pick-grid, .step > .qset-grid, .step > #qsets { margin-top: 1.1rem; }

/* Service picker: one tap, and the choice stays on screen while the
   follow-up questions are answered. A dropdown hides the context. */
/* Two up on a phone, so all five services are visible without scrolling past
   step 2. Five single-column cards buries the rest of the form. */
.pick-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(125px, 1fr)); gap: .7rem; }
@media (min-width: 760px) { .pick-grid-svc { grid-template-columns: repeat(6, minmax(0, 1fr)); } }

/* Once a service is picked the other five step back. The client's note was that
   the chosen one has to "pop" and the rest fade, and fading is right where
   hiding would be wrong: unlike the package, this choice is often made on this
   very page, and someone who tapped the wrong tile has to see the right one
   without looking for a reset. Not opacity alone, which would fail for anyone
   who cannot perceive a 45% difference: the chosen tile also keeps its colour,
   its border and its weight while the others go flat. */
.pick-grid-svc.is-picked .pick { opacity: .42; filter: saturate(.35); transition: opacity .18s, filter .18s; }
.pick-grid-svc.is-picked .pick:has(input:checked) { opacity: 1; filter: none; }
.pick-grid-svc.is-picked .pick:hover,
.pick-grid-svc.is-picked .pick:focus-within { opacity: 1; filter: none; }
.pick-grid.is-invalid { outline: 2px solid var(--orange-600); outline-offset: 6px; border-radius: var(--radius-sm); }
.pick { position: relative; display: block; cursor: pointer; }
.pick input {
  position: absolute; inset: 0; width: 100%; height: 100%;
  margin: 0; opacity: 0; cursor: pointer;
}
.pick-inner {
  display: grid; justify-items: center; gap: .55rem; height: 100%;
  padding: 1.1rem .7rem; text-align: center;
  border: 1.5px solid var(--line); border-radius: var(--radius-sm);
  background: #fff; color: var(--ink);
  transition: border-color .16s, background-color .16s, transform .16s, box-shadow .16s;
}
.pick-inner .icon { width: 26px; height: 26px; color: var(--navy); transition: color .16s; }
.pick-label { font-size: .92rem; font-weight: 600; line-height: 1.3; }
.pick:hover .pick-inner { border-color: #b9cbe4; transform: translateY(-2px); }
.pick input:checked + .pick-inner {
  border-color: var(--orange); background: var(--orange-50);
  box-shadow: 0 0 0 3px rgba(255, 107, 53, .16);
}
.pick input:checked + .pick-inner .icon { color: var(--orange-600); }
.pick input:focus-visible + .pick-inner { outline: 3px solid var(--orange); outline-offset: 2px; }

/* One question per row, with exactly one exception below. Side by side they were
   quick to skim and slow to fill: on a phone two 160px boxes each hold four
   characters of a street name, and the client watched people give up on exactly
   that. A single column also means the tier-gated questions appear and disappear
   without the rows above them reflowing sideways. */
.qset-grid { display: grid; grid-template-columns: minmax(0, 1fr); gap: 1rem; max-width: 620px; }
.qset[hidden], .qset-common[hidden], .pick-first[hidden], .field[hidden], .field-pair[hidden] { display: none; }

/* The exception: an address and its postal code are one question, so they are one
   row. A wide street box and a narrow box for the five digits. It holds on a
   phone precisely because the columns are not equal, which is what failed the
   first time. Top aligned, not bottom: the postal box carries a resolved-city
   line under it, and aligning on the bottom edge would drop the street label out
   of line with it. Client's instruction, 2026-08-17. */
.field-pair { display: grid; grid-template-columns: minmax(0, 1fr) 7rem; gap: .7rem; align-items: start; }
.qset, .qset-common { animation: rise .35s cubic-bezier(.2, .7, .3, 1); }
.qset-common { margin-top: 1rem; padding-top: 1rem; border-top: 1px dashed var(--line); }
.pick-first { margin: 1.1rem 0 0; padding: .9rem 1rem; background: var(--bg-alt); border: 1px dashed var(--line); border-radius: var(--radius-sm); font-size: .93rem; color: var(--muted); }

/* --------------------------------------------------------- mobile bar */

.mobile-bar { display: none; }
@media (max-width: 720px) {
  /* Call and message, both labelled. "Anrufen" has to read as a word: the
     people who reach for it are the ones who want a human on the line now,
     and a bare handset glyph does not say that. */
  /* Lighter than it was. At .96 opacity with a hard top border the bar read as
     a second page footer permanently stuck over the content, and with the two
     hero buttons still on screen it made four buttons competing at once. Now it
     floats: no border, no full-width slab, real blur, and the buttons sit on a
     rounded pill so the page clearly continues underneath. */
  .mobile-bar {
    position: fixed; inset: auto 0 0; z-index: 60;
    display: grid; grid-template-columns: 1fr 1fr; gap: .5rem;
    padding: .5rem .7rem calc(.5rem + env(safe-area-inset-bottom));
    background: linear-gradient(to top, rgba(255, 255, 255, .92) 55%, rgba(255, 255, 255, 0));
    backdrop-filter: saturate(150%) blur(8px);
    -webkit-backdrop-filter: saturate(150%) blur(8px);
    border-top: 0;
    /* Slides away while reading down the page, returns the moment the visitor
       scrolls back up, which is when wanting to contact someone happens. */
    transition: translate .28s cubic-bezier(.2, .7, .3, 1), opacity .28s;
  }
  .mobile-bar.is-hidden { translate: 0 130%; opacity: 0; }
  .mobile-bar .btn { padding: .72rem .6rem; font-size: .93rem; box-shadow: 0 4px 14px rgba(20, 33, 61, .16); }
  .site-footer { padding-bottom: 5.5rem; }
}
.field { display: grid; gap: .4rem; }
.field-row { display: grid; grid-template-columns: 1fr 1fr; gap: 1.1rem; }
@media (max-width: 620px) { .field-row { grid-template-columns: 1fr; } }
.field label { font-size: .92rem; font-weight: 650; color: var(--ink); }
.req { color: var(--orange-600); }

.field input, .field select, .field textarea {
  width: 100%; padding: .78rem .9rem;
  font: inherit; color: var(--ink);
  background: #fff; border: 1.5px solid var(--line); border-radius: var(--radius-sm);
  transition: border-color .16s, box-shadow .16s;
}
.field textarea { resize: vertical; min-height: 130px; }
.field input:focus, .field select:focus, .field textarea:focus {
  outline: none; border-color: var(--navy-700); box-shadow: 0 0 0 3px rgba(35, 74, 137, .14);
}
.field [aria-invalid="true"] { border-color: var(--orange-600); }

.form-actions { display: flex; flex-wrap: wrap; gap: .7rem; }
.form-error { margin: 0; padding: .7rem .9rem; border-radius: var(--radius-sm); background: var(--orange-50); color: #a8340d; font-size: .93rem; font-weight: 600; }
.privacy-note, .price-note {
  display: flex; gap: .55rem; align-items: flex-start;
  margin: 0; padding: .85rem 1rem;
  background: var(--bg-alt); border: 1px solid var(--line); border-radius: var(--radius-sm);
  font-size: .89rem; color: var(--muted);
}
.privacy-note .icon, .price-note .icon { margin-top: .18rem; flex: none; color: var(--navy-700); }
.price-note { color: var(--ink); font-weight: 550; background: var(--orange-50); border-color: #ffd9c7; }
.price-note .icon { color: var(--orange-600); }

/* ------------------------------------------------------------------ prose */

.prose h2 { margin-top: 2.2rem; font-size: 1.3rem; }
.prose h2:first-of-type { margin-top: 1.4rem; }
.prose .lead { font-size: 1.08rem; color: var(--ink); }
.prose .note { font-size: .92rem; color: var(--muted); }
.prose ul { display: grid; gap: .35rem; }
.address { font-style: normal; }

/* ----------------------------------------------------------------- footer */

.site-footer { background: var(--navy-900); color: rgba(255, 255, 255, .76); padding: clamp(2.5rem, 5vw, 3.6rem) 0 1.5rem; font-size: .94rem; }
.footer-grid { display: grid; grid-template-columns: minmax(0, 1.5fr) repeat(3, minmax(0, 1fr)); gap: var(--gap); }
@media (max-width: 880px) { .footer-grid { grid-template-columns: 1fr 1fr; } }
@media (max-width: 520px) { .footer-grid { grid-template-columns: 1fr; } }
.footer-brand img { height: 30px; width: auto; margin-bottom: .9rem; }
.footer-brand p { max-width: 42ch; }
.site-footer h2 { color: #fff; font-size: .82rem; font-weight: 700; text-transform: uppercase; letter-spacing: .08em; margin-bottom: .8rem; }
.site-footer ul { list-style: none; margin: 0; padding: 0; display: grid; gap: .45rem; }
.site-footer a { color: rgba(255, 255, 255, .78); text-decoration: none; }
.site-footer a:hover { color: #fff; text-decoration: underline; text-underline-offset: 3px; }
.footer-bottom {
  display: flex; flex-wrap: wrap; gap: .8rem; justify-content: space-between; align-items: center;
  margin-top: 2.2rem; padding-top: 1.3rem; border-top: 1px solid rgba(255, 255, 255, .14);
  font-size: .85rem; color: rgba(255, 255, 255, .6);
}
.footer-bottom p { margin: 0; }
.no-tracking { display: flex; align-items: center; gap: .45rem; }
.no-tracking .icon { color: var(--orange); }
.credit a { color: rgba(255, 255, 255, .82); font-weight: 600; text-decoration: none; border-bottom: 1px solid rgba(255, 107, 53, .6); }
.credit a:hover { color: #fff; border-bottom-color: var(--orange); }

/* ------------------------------------------------------------ service marks */
/* Was stock photography, one 4:3 picture per service. Replaced 2026-08-15 with
   drawn marks in the brand's own colours, at the client's request. Two reasons
   it is the right call and not just a preference: the photographs on offer are
   the same photographs every removals firm in Frankfurt licensed, so they say
   "a company like this one" rather than "this company"; and at 44px on a phone a
   photo of a room is a brown smudge while a mark is still a mark. */

.mark {
  display: grid; place-items: center; flex: none;
  width: 46px; height: 46px; border-radius: 13px;
  background: var(--tint-solid, var(--navy)); color: #fff;
  box-shadow: 0 6px 16px -8px color-mix(in srgb, var(--tint-solid, var(--navy)) 75%, transparent);
}
.mark-icon { width: 25px; height: 25px; stroke-width: 1.7; }
.mark-xl { width: clamp(84px, 16vw, 116px); height: clamp(84px, 16vw, 116px); border-radius: 26px; }
.mark-xl .mark-icon { width: 54%; height: 54%; }

/* ------------------------------------------------------------ service tiles */
/* The picker. Mark and name, nothing else: the client's verdict on the
   paragraph version was that people would be overwhelmed and leave. */

.section-head-tight { margin-bottom: clamp(1rem, 2vw, 1.5rem); }
.section-head-tight p { font-size: 1rem; color: var(--muted); }

.tiles { display: grid; gap: 1rem; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); }

/* A row, not a card with a picture on top. Six services stacked as picture cards
   is three screens; six rows is one, and a row puts the mark and the name on the
   same eye line so the set reads as a menu rather than as a gallery. */
.tile {
  display: flex; align-items: center; gap: .75rem;
  padding: .6rem .75rem;
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  background: var(--bg); text-decoration: none;
  box-shadow: var(--shadow-sm);
  transition: translate .18s, box-shadow .18s, border-color .18s;
}
.tile:hover { translate: 0 -2px; box-shadow: var(--shadow); border-color: var(--tint-solid, var(--line)); }
.tile:hover .tile-arrow { translate: 4px 0; }

.tile-body {
  display: flex; align-items: center; justify-content: space-between; gap: .5rem;
  flex: 1 1 auto; min-width: 0;
}
.tile-name { font-weight: 700; font-size: .98rem; color: var(--ink); line-height: 1.2; }
.tile-arrow { color: var(--tint-ink, var(--navy-700)); transition: translate .18s; flex: none; }

/* -------------------------------------------------------------------- proof */
/* Five numbers where five sentences used to be. */

.proof { background: var(--navy); color: #fff; padding: clamp(1.4rem, 3vw, 2rem) 0; }
.proof-list {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
  gap: 1rem 1.25rem; margin: 0; padding: 0; list-style: none; text-align: center;
}
.proof-list li { display: grid; gap: .1rem; }
.proof-list strong { font-size: clamp(1.5rem, 1.1rem + 1.6vw, 2.1rem); font-weight: 800; color: #fff; line-height: 1.1; }
.proof-list span { font-size: .84rem; color: rgba(255, 255, 255, .82); line-height: 1.35; }

/* ------------------------------------------------------------- lite process */

.steps-lite { grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); }
.step-lite h3 { margin: 0; font-size: 1rem; }

/* ----------------------------------------------------------------- packages */
/* Three scope tiers, no prices. A tier is a scope promise; the number still
   comes from the free site visit. */

/* Stretch, not start: the three "anfragen" buttons have to land on one line or
   the middle tier reads as the short one. `.pkg .btn { margin-top: auto }` does
   the rest. */
.pkg-grid { display: grid; gap: 1.1rem; grid-template-columns: repeat(auto-fit, minmax(270px, 1fr)); align-items: stretch; }

.pkg {
  position: relative; display: flex; flex-direction: column;
  padding: 1.4rem 1.3rem; border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--bg); box-shadow: var(--shadow-sm);
}
.pkg.is-best {
  border-color: var(--tint-solid, var(--navy)); border-width: 2px;
  box-shadow: var(--shadow); padding-top: 1.9rem;
}
.pkg-badge {
  position: absolute; top: -.7rem; left: 1.2rem;
  background: var(--tint-solid, var(--navy)); color: #fff;
  font-size: .74rem; font-weight: 700; letter-spacing: .02em;
  padding: .28rem .65rem; border-radius: 999px;
}
.pkg h3, .pkg-name { margin-bottom: .15rem; }
.pkg-tag { color: var(--tint-ink, var(--navy-700)); font-weight: 600; font-size: .95rem; margin-bottom: 1rem; }

/* The package header is a button so a phone can collapse the card down to its
   name and its one-line differentiator. Desktop never collapses: there the
   three cards already sit side by side and the button is inert.

   Why this exists: as three full-height stacked cards the tiers spanned about
   990px on a 390px phone, so with the header and the sticky bar taking their
   cut a visitor could never get more than one and a half packages on screen.
   There was no moment where "the three packages" existed as a visible set, and
   comparing them is what choosing is. Collapsed, all three names and taglines
   land inside the first screen and the choice is a set again. Nothing is
   deleted, it opens in place, per the round 7 rule. */
.pkg-head {
  display: flex; align-items: center; gap: .8rem; width: 100%;
  padding: 0; margin: 0; border: 0; background: none;
  font: inherit; color: inherit; text-align: inherit;
}
.pkg-headtext { display: block; flex: 1 1 auto; min-width: 0; }
.pkg-title { display: block; }
.pkg-head .pkg-tag { margin-bottom: 0; display: block; font-size: .92rem; }
.pkg-chev { flex: 0 0 auto; color: var(--tint-ink, var(--navy-700)); display: none; }
/* Flex column that grows, so `.pkg .btn { margin-top: auto }` still reaches the
   request button now that it lives inside the collapsible body. Without this
   the three desktop buttons stop landing on one line and the middle tier reads
   as the short one, which is the exact thing the grid comment above warns
   about. */
.pkg-body { display: flex; flex-direction: column; flex: 1 1 auto; }
.checklist-tight { margin-bottom: 1.2rem; }
.checklist-tight li { font-size: .93rem; }
.pkg .btn { margin-top: auto; }
.pkg-note { margin: 1.4rem 0 0; font-size: .93rem; color: var(--muted); max-width: 68ch; }

/* Two options instead of three: one full-scope package and one custom. The
   custom card is deliberately quieter, outlined rather than filled, because it
   is the escape hatch and not the recommendation. */
.pkg-grid-2 { grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); max-width: 900px; }
.pkg.is-custom { background: var(--bg-alt); box-shadow: none; border-style: dashed; }
.pkg.is-custom .checklist .icon { color: var(--muted); }

/* ------------------------------------------------------- service page hero */

.page-hero-mark .page-hero-inner {
  display: flex; gap: var(--gap); align-items: center; justify-content: space-between;
}
.page-hero-mark .mark-xl { order: 2; }

/* A one-line band since 2026-08-17. A visitor who just tapped a service is here
   to pick a package, so the hero says which service this is and gets out of the
   way; the lead, the audience line and the buttons moved below the cards. */
.page-hero-svc { padding: clamp(1.4rem, 3vw, 2.2rem) 0; }
.page-hero-svc .page-hero-inner { align-items: center; }

/* The block directly under a hero band: its h2 is the instruction for the cards
   underneath it, not the start of a new chapter, so it does not need a chapter's
   worth of air above it. */
.section-first { padding-top: clamp(1.4rem, 3vw, 2.25rem); }

/* Under the cards, not over them. Above, it put 84px of "how pricing works"
   between the instruction and the first card on a phone; below, it answers the
   question at the moment the cards raise it. */
.pkg-lead { margin: 1.5rem 0 0; font-size: 1rem; color: var(--body); max-width: 68ch; }
.pkg-lead + .pkg-note { margin-top: .45rem; }

/* ------------------------------------------------------- package picker */

.pkg-pick { border: 0; margin: 0 0 1.4rem; padding: 0; }
.pkg-pick legend { font-weight: 650; color: var(--ink); padding: 0; margin-bottom: .6rem; }
.pick-grid-2 { grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); }
.pick-grid-3 { grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); }
.pick-sm .pick-inner { flex-direction: column; align-items: flex-start; gap: .1rem; padding: .7rem .85rem; }
.pick-sub { font-size: .82rem; color: var(--muted); font-weight: 400; line-height: 1.3; }
.pick-sm input:checked + .pick-inner .pick-sub { color: inherit; opacity: .85; }
.pick-custom .pick-inner { border-style: dashed; }

/* Once a tier is chosen the others are removed and this brings them back. Text
   button, not a tile: it must not compete with the choice it undoes. */
.pkg-change {
  margin-top: .55rem; padding: 0; border: 0; background: none;
  color: var(--navy-700); font: inherit; font-size: .88rem; font-weight: 650;
  text-decoration: underline; text-underline-offset: 3px; cursor: pointer;
}
.pkg-change:hover { color: var(--orange-600); }
.pkg-pick.is-locked .pick-grid { grid-template-columns: minmax(0, 320px); }
.pkg-pick .pick[hidden] { display: none; }

/* ------------------------------------------------------------ postal code */

.field-plz { position: relative; }
.plz-city {
  display: block; min-height: 1.05rem; margin-top: .3rem;
  font-size: .85rem; font-weight: 650; color: var(--muted); opacity: 0;
  transition: opacity .18s;
}
.plz-city.is-on { opacity: 1; color: var(--navy-700); }

/* ------------------------------------------------------------------- flags */

.flag {
  width: 20px; height: 14px; flex: none; display: block;
  border-radius: 2px;
  /* A white flag on a white menu vanishes at the edges. The inset ring is
     cheaper than a border, which would eat into the 20x14 artwork. */
  box-shadow: 0 0 0 1px rgba(20, 33, 61, .18) inset;
}
.dd-lang > summary .flag { margin-inline-end: .1rem; }
.dd-menu a { display: flex; align-items: center; gap: .55rem; }
.dd-menu .flag { margin: 0; }
[dir="rtl"] .flag { transform: none; }

/* ------------------------------------------------- tiles and packages, phone */

@media (max-width: 720px) {
  /* The drifting orbs pass behind the hero paragraph. In motion they read as
     depth; the instant they sit still behind a line of text they read as a
     grey smudge, which on a phone is indistinguishable from a broken image.
     The route lines and grid stay, they never cross the copy. */
  .hero-orb { display: none; }

  /* One column, six rows, all six on the first screen with the headline above
     them. Two across would fit as well, but it halves the room for a name and
     "Hausmeisterservice" is seventeen characters. */
  .tiles, .hero-pick-panel .tiles { grid-template-columns: 1fr; gap: .45rem; }
  .tile { padding: .5rem .6rem; gap: .65rem; }
  .tile-name { font-size: .95rem; }
  .mark { width: 38px; height: 38px; border-radius: 11px; }
  .mark-icon { width: 21px; height: 21px; }

  .proof-list { grid-template-columns: repeat(3, 1fr); gap: .9rem .6rem; }
  .proof-list li:nth-child(n+4) { grid-column: span 1; }

  /* Doubled class, not for weight's sake: the generic mobile `.steps` rule
     further down would otherwise win on source order and stack these. */
  .steps.steps-lite { grid-template-columns: 1fr 1fr; gap: .6rem; }
  .steps.steps-lite .step-lite { padding: .7rem .8rem; border-bottom: 0; display: grid; gap: .1rem; }

  /* The mark above the words on a phone: it is the fastest answer to "am I in
     the right place", and it is the whole reason this rebuild happened. */
  .page-hero-mark .page-hero-inner { flex-direction: column; align-items: flex-start; gap: 1rem; }
  .page-hero-mark .mark-xl { order: -1; width: 64px; height: 64px; border-radius: 18px; }

  /* Nine area pills wrapped to four rows and made the about block the tallest
     text on the page. Five is enough to establish the range; the remaining
     countries are named in full in the paragraph behind the toggle, so nothing
     is actually withheld. */
  .pills-first li:nth-child(n+6) { display: none; }

  /* Tighter than the desktop card, so the first card clears the fold whole and
     the second one shows its name underneath it. A visitor who cannot see that
     there is a second package does not know there is a choice to make. */
  .pkg-grid { gap: 1rem; }
  .pkg { padding: 1.05rem 1rem; }
  .pkg.is-best { padding-top: 1.5rem; }
  .pkg h3, .pkg-name { font-size: 1.2rem; }
  .pkg-tag { margin-bottom: .7rem; font-size: .92rem; }
  .checklist-tight { margin-bottom: .95rem; gap: .35rem; }
  .checklist-tight li { font-size: .91rem; }

  /* Collapsed tiles. `is-accordion` is set by JS, so with scripting off the
     cards render exactly as they did before: long, but complete. */
  .pkg-grid.is-accordion { gap: .7rem; }
  .pkg-grid.is-accordion .pkg { padding: .3rem 1rem; }
  .pkg-grid.is-accordion .pkg.is-best { padding-top: .95rem; }
  .pkg-grid.is-accordion .pkg-head { min-height: 56px; }
  .pkg-grid.is-accordion .pkg-head .pkg-tag { margin-bottom: 0; }
  .pkg-grid.is-accordion .pkg-chev { display: block; transition: transform .18s ease; }
  .pkg-grid.is-accordion .pkg-head[aria-expanded="true"] .pkg-chev { transform: rotate(180deg); }
  .pkg-grid.is-accordion .pkg-body { padding-top: .85rem; padding-bottom: .5rem; }
}

/* Beats `.pkg-body { display: block }`, which would otherwise win over the
   user-agent rule for the hidden attribute. */
.pkg-body[hidden] { display: none; }

/* Proof in the first screen of a service page. Compact, wrapping, and quiet:
   it has to register as evidence in passing, not compete with the h1. */
.svc-proof {
  list-style: none; margin: .9rem 0 0; padding: 0;
  display: flex; flex-wrap: wrap; gap: .35rem .95rem;
}
.svc-proof li {
  display: flex; align-items: center; gap: .35rem;
  font-size: .86rem; font-weight: 600; color: var(--tint-ink, var(--navy-700));
}
.svc-proof .icon { flex: 0 0 auto; }
@media (max-width: 720px) {
  .svc-proof { margin-top: .75rem; gap: .3rem .7rem; }
  .svc-proof li { font-size: .8rem; }
}

/* -------------------------------------------------------------------- rtl */

[dir="rtl"] .tile-arrow,
[dir="rtl"] .card-more .icon,
[dir="rtl"] .checklist .icon { scale: -1 1; }
[dir="rtl"] .pkg-badge { left: auto; right: 1.2rem; }
[dir="rtl"] .lang-list { border-left: 0; border-right: 1px solid var(--line); padding-left: 0; padding-right: 1rem; }
[dir="rtl"] .breadcrumbs li + li::before { margin-right: 0; margin-left: .4rem; }

/* ----------------------------------------------------------------- mobile */
/* Most visitors arrive on a phone from WhatsApp or a Google Maps listing, so
   this block is the primary layout, not an afterthought. */

/* Anchors must clear the sticky header when jumped to. */
:target, [id] { scroll-margin-top: 84px; }

@media (max-width: 720px) {
  body { font-size: 1rem; }

  .section { padding: 2.25rem 0; }
  .hero { padding: 2.25rem 0 2.5rem; }
  .wrap, .wrap-narrow, .wrap-form { width: min(100% - 1.75rem, var(--wrap)); }

  h1 { font-size: clamp(1.75rem, 6.4vw, 2.2rem); letter-spacing: -.022em; }
  h2 { font-size: clamp(1.35rem, 5.2vw, 1.7rem); }
  .hero .lead, .page-hero .lead { font-size: 1.02rem; }

  /* Full-width stacked buttons: thumbs miss side-by-side targets. */
  .hero-actions, .band-actions, .form-actions { flex-direction: column; align-items: stretch; }
  .hero-actions .btn, .band-actions .btn, .form-actions .btn { width: 100%; }
  .btn-lg { padding: .95rem 1.2rem; }
  .btn { min-height: 48px; }

  .card { padding: 1.15rem; }
  .card-icon { width: 42px; height: 42px; margin-bottom: .7rem; }
  .card-icon .icon { width: 21px; height: 21px; }

  /* Service cards become compact rows: five tall cards is a long dead scroll. */
  .grid-3 { gap: .7rem; }
  .card-service {
    display: grid; grid-template-columns: auto 1fr; gap: .2rem .9rem;
    align-items: center; padding: 1rem 1.1rem;
  }
  /* "Details ansehen" on its own line cost a row per card, five times over, to
     say what the whole card already is: a link. A chevron at the edge says it
     in no vertical space at all. */
  .card-service {
    grid-template-columns: auto 1fr auto;
    grid-template-areas: "icon title chev" "icon text chev";
  }
  .card-service .card-icon { grid-area: icon; margin: 0; align-self: center; }
  .card-service h3 { grid-area: title; margin: 0; font-size: 1.05rem; }
  .card-service p { grid-area: text; font-size: .92rem; line-height: 1.5; }
  .card-service .card-more { display: none; }
  .card-service::after {
    content: ""; grid-area: chev; align-self: center;
    width: 9px; height: 9px; margin-inline-start: .3rem;
    border-top: 2px solid var(--tint-ink, var(--navy));
    border-inline-end: 2px solid var(--tint-ink, var(--navy));
    rotate: 45deg; opacity: .55;
  }
  [dir="rtl"] .card-service::after { rotate: -135deg; }

  /* Hero trust list becomes a chip row. Four stacked rows of text was 149px of
     the first screen; as chips it is one or two lines and reads as badges
     rather than as more copy to get through. The fifth item is the language
     list, which the switcher in the header now says on its own. */
  .trust { display: flex; flex-wrap: wrap; gap: .4rem; margin-top: 1.1rem; }
  .trust li {
    padding: .3rem .65rem; border-radius: 999px;
    background: rgba(255, 255, 255, .1); border: 1px solid rgba(255, 255, 255, .18);
    font-size: .82rem; gap: .35rem;
  }
  .trust li:nth-child(n+4) { display: none; }
  .trust .icon { width: 14px; height: 14px; }

  /* "So läuft es ab" was four full cards, 970px. One bordered list, four rows:
     the number carries the sequence, the card chrome was doing nothing. */
  .steps {
    gap: 0; background: #fff;
    border: 1px solid var(--line); border-radius: var(--radius);
    box-shadow: var(--shadow-sm); overflow: hidden;
  }
  .steps > .step-p {
    display: grid; grid-template-columns: auto 1fr; gap: 0 .8rem;
    align-items: baseline; padding: .85rem 1rem;
    border: 0; border-bottom: 1px solid var(--line); border-radius: 0; box-shadow: none;
  }
  .steps > .step-p:last-child { border-bottom: 0; }
  .steps > .step-p .step-n { margin: 0; font-size: 1rem; }
  .steps > .step-p h3 { margin: 0; font-size: 1rem; }
  .steps > .step-p p { grid-column: 2; margin: .15rem 0 0; font-size: .89rem; line-height: 1.45; }

  /* Reviews: horizontal snap track, one card at a time, advancing on its own.
     Stacked they were the tallest block on the page and nobody reached card 3. */
  .reviews-track {
    display: flex; gap: .7rem;
    overflow-x: auto; scroll-snap-type: x mandatory;
    scrollbar-width: none; -webkit-overflow-scrolling: touch;
    /* Exactly the .wrap gutter (1.75rem / 2), so cards can bleed to the screen
       edge without pushing the document 2px wider than the viewport. */
    margin-inline: -.875rem; padding-inline: .875rem;
    scroll-padding-inline: .875rem;
  }
  .reviews-track::-webkit-scrollbar { display: none; }
  .reviews-track > .card-review { flex: 0 0 88%; scroll-snap-align: start; }

  .rv-dots { display: flex; justify-content: center; gap: .4rem; margin-top: 1rem; }
  .rv-dot {
    width: 7px; height: 7px; padding: 0; border: 0; border-radius: 50%;
    background: #cdd6e4; cursor: pointer; transition: width .2s, background-color .2s;
  }
  .rv-dot[aria-current="true"] { width: 20px; border-radius: 4px; background: var(--orange); }

  /* About: paragraph one, then a toggle. The rest stays in the HTML. */
  .about-more { display: none; }
  .about-more.is-open { display: block; }
  .more-toggle:not([hidden]) {
    display: inline-flex; align-items: center; gap: .5rem;
    padding: .55rem 0; background: none; border: 0;
    font: inherit; font-size: .94rem; font-weight: 650; color: var(--navy-700);
    cursor: pointer;
  }
  .more-toggle .dd-caret { border-color: currentColor; }
  .more-toggle[aria-expanded="true"] .dd-caret { rotate: 225deg; translate: 0 2px; }

  .step { padding: 1.15rem; }
  .step-n { font-size: 1.3rem; margin-bottom: .4rem; }

  .page-hero { padding: 1.75rem 0 2rem; }
  /* Service page only: the packages have to start on the first screen. Measured
     on a 375x812 phone, this band plus the header and breadcrumb leaves the first
     card starting at about 350px instead of 883px. */
  .page-hero.page-hero-svc { padding: .85rem 0 1.05rem; }
  .page-hero-mark.page-hero-svc .page-hero-inner { gap: .55rem; }
  .page-hero-svc .mark-xl { width: 46px; height: 46px; border-radius: 13px; }
  .section.section-first { padding-top: 1rem; }
  .section-first .section-head-tight { margin-bottom: .7rem; }
  .partners { padding: 1.25rem 0; }
  .aside-card { padding: 1.15rem; }
  .split, .split-form { gap: 1.5rem; }

  .faq-item summary { font-size: 1rem; padding: .95rem 0; }

  /* The quote form is the money page: strip its chrome down on small screens. */
  .step { border-radius: 12px; padding: 1.1rem; }
  .step legend { font-size: 1rem; }
  .quote-form { gap: .8rem; }
  .field input, .field select, .field textarea { padding: .82rem .85rem; font-size: 1rem; }
  .qset-grid { gap: .8rem; }

  .footer-grid { gap: 1.75rem; }
  .footer-bottom { flex-direction: column; align-items: flex-start; gap: .5rem; }
}

/* Very small phones (iPhone SE and similar). */
@media (max-width: 380px) {
  .field-pair { grid-template-columns: minmax(0, 1fr) 5.6rem; gap: .5rem; }
  .pick-grid { grid-template-columns: 1fr 1fr; gap: .5rem; }
  .pick-inner { padding: .85rem .4rem; }
  .pick-label { font-size: .84rem; }
  .mobile-bar .btn { font-size: .88rem; padding: .72rem .4rem; }
}

/* --------------------------------------------------------- scroll reveal */
/* The class is added by JavaScript, never by the build. A visitor with JS off,
   or with reduced motion on, gets the finished state and never sees these
   rules at all: nothing can end up permanently invisible. */

.reveal { opacity: 0; transform: translate3d(0, 18px, 0); }
.reveal-on { transition: opacity .55s cubic-bezier(.2, .7, .3, 1), transform .55s cubic-bezier(.2, .7, .3, 1); }
.reveal.is-in { opacity: 1; transform: none; }

/* Stagger inside a group, so a row of cards arrives as a wave, not a slab. */
.reveal:nth-child(2) { transition-delay: .07s; }
.reveal:nth-child(3) { transition-delay: .14s; }
.reveal:nth-child(4) { transition-delay: .21s; }
.reveal:nth-child(5) { transition-delay: .28s; }

@media (prefers-reduced-motion: reduce) {
  .reveal { opacity: 1; transform: none; }
}

/* ------------------------------------------------------------------ print */

@media print {
  .site-header, .band, .nav-toggle, .hero-actions, .form-actions { display: none !important; }
  body { color: #000; font-size: 11pt; }
  .hero, .band { background: none; color: #000; }
  .hero h1, .band h2 { color: #000; }
  a[href^="http"]::after { content: " (" attr(href) ")"; font-size: 9pt; color: #555; }
}
