/* =========================================================================
   DEE Sprachschule — editorial design system

   The direction is type-led rather than photo-led, and that is a decision
   made from the assets rather than from fashion: every photograph the school
   has is an empty room. A layout built around big hero photography would put
   a deserted classroom at the top of the page, which is the opposite of what
   a language school needs to say.

   So typography carries the page. Photographs are treated as texture —
   desaturated and tinted into the brand — never as the subject. The result
   also happens to differentiate hard from the stock-photo look the local
   competitor uses.

   Structure:
     1  Fonts
     2  Tokens
     3  Reset & base
     4  Typography
     5  Layout primitives
     6  Motion
     7  Components
     8  Responsive
   ====================================================================== */

/* -------------------------------------------------------------------------
   1  FONTS — self-hosted variable, see inc/enqueue.php for the licensing note
   ---------------------------------------------------------------------- */

@font-face {
  font-family: "Bricolage";
  src: url("../fonts/bricolage-var.woff2") format("woff2-variations");
  font-weight: 200 800;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "InterVar";
  src: url("../fonts/inter-var.woff2") format("woff2-variations");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

/*
 * Flags — and the only reason a third font exists.
 *
 * Windows ships no country-flag glyphs at all: Chrome on Windows renders 🇩🇪
 * as the letters "DE". Every other platform has them. Rather than detect the
 * platform, the pair is always drawn from this subset — 78 KB, flags only,
 * self-hosted like the other two, and requested solely by the country field
 * because `unicode-range` limits it to the regional-indicator block.
 *
 * Twemoji artwork, CC BY 4.0, © Twitter/X — see
 * assets/fonts/TwemojiCountryFlags-LICENSE.md, which ships with the theme as
 * that licence requires. Packaging by TalkJS (MIT).
 *
 * font-display: swap, so a slow font never delays the field: the code shows
 * first and the flag replaces it.
 */
@font-face {
  font-family: "TwemojiFlags";
  src: url("../fonts/TwemojiCountryFlags.woff2") format("woff2");
  unicode-range: U+1F1E6-1F1FF;
  font-display: swap;
}

/* -------------------------------------------------------------------------
   2  TOKENS
   ---------------------------------------------------------------------- */

:root {
  /* Ink & paper -----------------------------------------------------------
     The ground is warm off-white, not #fff. On a page that is mostly type,
     pure white glares and makes the ink look thin; paper makes the same
     typography read as considered rather than as unstyled. */
  --dee-paper:       #fbfaf8;
  --dee-paper-deep:  #f4f2ee;
  --dee-surface:     #ffffff;
  --dee-ink:         #14202f;  /* body text — warmer and softer than navy */
  --dee-ink-soft:    #5b6b7d;  /* 5.2:1 on paper */
  /*
   * Was #8c99a8, which measured 2.78:1 on paper — well under the 4.5:1 that
   * WCAG 2.1 AA requires for body-size text. It is not a decorative tone: it
   * carries the section labels, the fact-panel keys and every form label, so
   * failing there fails the parts of the page a visitor reads to orient
   * themselves. #5f6c7d keeps the same quiet register and clears 4.5:1 on
   * every ground the design uses, including the darker --dee-paper-deep
   * sections where the first correction still measured 4.38:1.
   */
  --dee-ink-faint:   #5f6c7d;
  /*
   * The oversized level numeral (A1, B2 …) is large text, so 3:1 applies —
   * but #cdc7bd measured 1.61:1, which is not legible, only visible. This
   * clears the bar while still sitting behind the headline in the hierarchy.
   */
  --dee-numeral:     #847b70;

  /* Brand ---------------------------------------------------------------- */
  /*
   * The blue in the mark, sampled from the logo file rather than guessed:
   * icon-512.png is 24,746 pixels of exactly this one value. The palette
   * below was built around --dee-blue (#2563eb), which is a different,
   * cooler blue — so until now nothing on the site used the school's own.
   */
  --dee-logo-blue:   #3698db;
  /*
   * The highlighter is the logo blue at full strength — the value the client
   * named, not a wash of it.
   *
   * A tint was the cautious first answer and it was too cautious: at 45% the
   * mark read as a pale box rather than as ink. Full strength measures 5.1:1
   * under navy type, so the price is still comfortably above AA — which is
   * the only reason full strength is available here at all. A saturated
   * yellow, the colour every competitor uses for this, would not be.
   */
  --dee-marker:      #3698db;
  /*
   * The headline's accent line on the navy hero. It was a literal in two
   * places — the base rule and the photo-hero override — and became a third
   * when the gradient version was removed. 8.4:1 on the navy, which is what
   * it was picked for.
   */
  --dee-hero-accent: #7ec2ff;
  --dee-navy:        #002147;
  --dee-navy-deep:   #08172c;
  --dee-blue:        #2563eb;
  --dee-blue-dark:   #1d4ed8;  /* AA on paper for link text */
  --dee-blue-tint:   #dbeafe;
  --dee-blue-wash:   #eff6ff;

  /*
   * Per-level accent system (A1–C1):
   * Full identity with solid tones, dark contrast variants, subtle background
   * tints, and hairline borders for cards, badges, buttons, and tables.
   */
  --dee-lvl-a1:        #2563eb; /* A1: Bright Sky/Royal Blue (Start) */
  --dee-lvl-a1-dark:   #1d4ed8;
  --dee-lvl-a1-tint:   #eff6ff;
  --dee-lvl-a1-border: #bfdbfe;

  --dee-lvl-a2:        #059669; /* A2: Vibrant Emerald / Teal (Everyday Confidence) */
  --dee-lvl-a2-dark:   #047857;
  --dee-lvl-a2-tint:   #ecfdf5;
  --dee-lvl-a2-border: #a7f3d0;

  --dee-lvl-b1:        #d97706; /* B1: Sunny Golden Amber (Independence) */
  --dee-lvl-b1-dark:   #b45309;
  --dee-lvl-b1-tint:   #fffbeb;
  --dee-lvl-b1-border: #fde68a;
  /*
   * One step darker than -dark, for the amber button's own hover. B1 is the
   * only level whose -dark tone is still light enough that pressing it needs
   * a fourth stop; the other four reuse their -dark.
   */
  --dee-lvl-b1-deep:   #92400e;

  --dee-lvl-b2:        #7c3aed; /* B2: Royal Violet/Purple (Profession & Study) */
  --dee-lvl-b2-dark:   #6d28d9;
  --dee-lvl-b2-tint:   #faf5ff;
  --dee-lvl-b2-border: #ddd6fe;

  --dee-lvl-c1:        #1e40af; /* C1: Deep Indigo / Sapphire (Mastery) */
  --dee-lvl-c1-dark:   #1e3a8a;
  --dee-lvl-c1-tint:   #f0f7ff;
  --dee-lvl-c1-border: #bfdbfe;

  /* Signals — used only for status, never for decoration ------------------ */
  --dee-signal-free: #10b981;  /* places still open, and the hero's live dot */
  --dee-signal-low:  #f59e0b;  /* few places left, and the "most booked" flag */

  /*
   * The bright end of the blue ramp. These only appear on navy — the photo
   * hero's gradient headline, its eyebrow, its rail — where the brand blue
   * itself is too close to the ground to read.
   */
  --dee-navy-mid:    #083b7a;
  --dee-blue-soft:   #60a5fa;
  --dee-blue-pale:   #93c5fd;
  --dee-sky:         #0284c7;
  --dee-sky-soft:    #38bdf8;
  --dee-slate-wash:  #f8fafc;  /* the cooler of the two section grounds */

  /*
   * The two status colours, one step darker than the palette they came from.
   *
   * They were #059669 and #d97706 — the A2 and B1 level accents, borrowed
   * because "places available" ought to look like the same family as the rest
   * of the site. As TEXT on paper they measure 3.61:1 and 3.05:1, and both are
   * 15px, which needs 4.5:1. Every seat line on the site said so: the price
   * table, the course page, the level cards, the appointment picker, the
   * landing pages. Nobody reported it, because it is legible to anyone whose
   * eyes are fine.
   *
   * These are the -dark variants of the same two hues, so nothing about the
   * palette changes except that it now passes: 5.26:1 and 4.81:1 on paper.
   * Both are only ever used as `color` or `border-color` — checked before
   * changing them — so no white-on-colour pairing moves underneath this.
   */
  --dee-ok:          #047857;
  --dee-warn:        #b45309;

  /*
   * WhatsApp's own green, and an ink dark enough to be read on it. Tokens
   * rather than literals because the colour appears in two places — the
   * floating pill on desktop and the action bar on phones — and the whole
   * point of it is that those two are recognisably the same button.
   */
  --dee-wa-green:      #25d366;
  --dee-wa-green-dark: #1fbb5b;
  --dee-wa-ink:        #06301c;
  --dee-err:         #b3261e;

  /*
   * Text and icons sitting ON a filled accent. Named for the role, not the
   * colour: every level button, the step numerals and the run table's head
   * were each carrying their own literal #ffffff, which is how a palette
   * change quietly leaves one of them unreadable.
   */
  --dee-on-accent:   #ffffff;

  --dee-rule:        #e4e0d9;  /* hairlines — warm, so they sit on paper */
  --dee-rule-strong: #cdc7bd;

  /* Type ----------------------------------------------------------------- */
  --dee-display: "Bricolage", "Inter", system-ui, sans-serif;
  --dee-font:    "InterVar", "Inter", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;

  /* A fluid scale with real contrast. German compounds are long, so the
     body size is generous and the measure stays narrow. */
  --dee-fs-xs:   0.8125rem;
  --dee-fs-sm:   0.9375rem;
  --dee-fs-base: 1.0625rem;
  --dee-fs-lg:   clamp(1.125rem, 1.05rem + 0.35vw, 1.3125rem);
  --dee-fs-xl:   clamp(1.375rem, 1.2rem + 0.8vw, 1.75rem);
  --dee-fs-2xl:  clamp(1.625rem, 1.35rem + 1.2vw, 2.25rem);
  /*
   * 3rem, not 4rem. Every section heading on the page was set at 64px —
   * hero size, nine times over — which pushed most of them onto two lines
   * and gave the page no typographic hierarchy at all: the h1 and the h2s
   * were the same shout. A heading that is clearly subordinate to the
   * headline reads as organised; nine competing headlines read as loud.
   */
  --dee-fs-3xl:  clamp(1.875rem, 1.4rem + 1.8vw, 3rem);

  /*
   * Heading aliases.
   *
   * Six declarations across the course page and the price card asked for
   * --dee-fs-h2 / -h3 / -h4, which were never defined and carried no fallback.
   * An undefined custom property makes the whole declaration invalid, so those
   * six font-sizes were being dropped on the floor: the sections inherited
   * whatever the cascade happened to give them and the intended hierarchy
   * never existed. Naming them here is the smaller fix — the call sites read
   * better as "h3" than as "xl", and the scale is where that mapping belongs.
   */
  --dee-fs-h2: var(--dee-fs-2xl);
  --dee-fs-h3: var(--dee-fs-xl);
  --dee-fs-h4: var(--dee-fs-lg);
  --dee-fs-4xl:  clamp(2.5rem, 1.6rem + 3.4vw, 4.5rem);

  /* Space ---------------------------------------------------------------- */
  --dee-s1: 0.25rem; --dee-s2: 0.5rem;  --dee-s3: 0.75rem; --dee-s4: 1rem;
  --dee-s5: 1.5rem;  --dee-s6: 2rem;    --dee-s7: 2.25rem; --dee-s8: 3rem;
  /*
   * s9 is the band between sections, and it was 120px top AND bottom on
   * nine sections — 1,900 pixels of nothing on one page. Generous spacing
   * reads as confidence right up to the point where a visitor has to scroll
   * past emptiness to find the next thing, and then it reads as a page with
   * not much on it. The homepage measured 10,200px against a competitor's
   * 4,700 carrying the same number of sections; almost none of that
   * difference was content.
   */
  --dee-s9: clamp(2.75rem, 1.5rem + 3.2vw, 4.5rem);

  /* Shape ---------------------------------------------------------------- */
  --dee-r-sm: 6px; --dee-r: 10px; --dee-r-lg: 16px; --dee-r-full: 999px;
  --dee-shadow-sm:    0 1px 2px rgba(20,32,47,.04), 0 2px 6px rgba(20,32,47,.03);
  --dee-shadow:       0 1px 2px rgba(20,32,47,.04), 0 6px 20px rgba(20,32,47,.05);
  --dee-shadow-card:  0 4px 20px -2px rgba(0, 33, 71, 0.07);
  --dee-shadow-hover: 0 14px 34px -4px rgba(0, 33, 71, 0.13);
  /*
   * A filled button's own shadow. Neutral, like every other shadow here.
   *
   * The three design passes gave each level a shadow tinted to its own
   * accent — blue under A1, amber under B1, violet under B2 — at .25 and .35
   * opacity, plus a lift on hover. On a page with five level cards, three
   * service cards and four value props that is twelve coloured glows visible
   * at once, and the effect the client asked to have removed.
   */
  --dee-shadow-btn:   0 2px 6px -1px rgba(0, 33, 71, 0.14);
  --dee-shadow-float: 0 20px 48px -8px rgba(0, 33, 71, 0.22);
  --dee-shadow-lg:    0 12px 44px rgba(20,32,47,.11);

  --dee-wrap:  1180px;
  --dee-wide:  1400px;
  --dee-prose: 62ch;

  --dee-ease: cubic-bezier(.22, .61, .36, 1);
}

/* -------------------------------------------------------------------------
   3  RESET & BASE
   ---------------------------------------------------------------------- */

*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }

body {
  margin: 0;
  /*
   * `clip`, not `hidden`.
   *
   * The mobile drawer is position: fixed and parked off-screen with
   * translateX(100%), and a transformed fixed element still counts toward the
   * document's scrollable overflow — which is the last few pixels of sideways
   * scroll left on a phone once the header stopped overflowing.
   *
   * overflow-x: hidden would fix it and take position: sticky with it, and
   * this site has a sticky header and a sticky action bar. `clip` suppresses
   * the overflow without creating a scroll container, so sticky survives.
   */
  overflow-x: clip;
  font-family: var(--dee-font);
  font-size: var(--dee-fs-base);
  line-height: 1.7;
  color: var(--dee-ink);
  background: var(--dee-paper);
  -webkit-font-smoothing: antialiased;
  font-synthesis-weight: none;
  text-rendering: optimizeLegibility;
}

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

a { color: var(--dee-blue-dark); text-decoration-thickness: 1px; text-underline-offset: 3px; }
a:hover { color: var(--dee-navy); }

::selection { background: var(--dee-navy); color: #fff; }

/* Accessibility ---------------------------------------------------------- */
:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
  outline: 3px solid var(--dee-blue);
  outline-offset: 2px;
  border-radius: 3px;
}
.dee-skip {
  position: absolute; left: -9999px; top: 0; z-index: 999;
  background: var(--dee-navy); color: #fff; padding: var(--dee-s3) var(--dee-s5);
  border-radius: 0 0 var(--dee-r) 0; font-weight: 600;
}
.dee-skip:focus { left: 0; color: #fff; }
.dee-sr {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* -------------------------------------------------------------------------
   4  TYPOGRAPHY
   ---------------------------------------------------------------------- */

h1, h2, h3, h4 {
  /*
   * Every heading, not just .dee-section__title — which is where this pair
   * already lived and where it stopped. The search-results h1 interpolates
   * whatever the visitor typed, so "Suchergebnisse für „Prüfungsvorbereitung"
   * arrives as one 24-character unbreakable word set at --dee-fs-4xl, and it
   * ran 452px wide inside a 350px column on a normal phone.
   *
   * German has no shortage of words that do this. The base rule is the right
   * place for it.
   */
  overflow-wrap: break-word; hyphens: auto;
  font-family: var(--dee-display);
  color: var(--dee-navy);
  line-height: 1.06;
  margin: 0 0 var(--dee-s4);
  letter-spacing: -0.025em;
  text-wrap: balance;
}
h1 { font-size: var(--dee-fs-4xl); font-weight: 700; letter-spacing: -0.038em; }
h2 { font-size: var(--dee-fs-2xl); font-weight: 700; letter-spacing: -0.03em; }
h3 { font-size: var(--dee-fs-lg); font-weight: 700; line-height: 1.2; letter-spacing: -0.02em; }
h4 { font-size: var(--dee-fs-base); font-weight: 700; line-height: 1.3; }

p { margin: 0 0 var(--dee-s4); text-wrap: pretty; }

/* The eyebrow is the editorial signature — it labels every section like a
   department heading in a magazine. */
.dee-eyebrow {
  display: block;
  font-family: var(--dee-font);
  font-size: var(--dee-fs-xs); font-weight: 600;
  letter-spacing: .16em; text-transform: uppercase;
  color: var(--dee-ink-faint);
  margin-bottom: var(--dee-s4);
}

.dee-lead {
  font-size: var(--dee-fs-lg);
  line-height: 1.55;
  color: var(--dee-ink-soft);
  max-width: 52ch;
}

/* Dates, prices and seat counts must not jitter as they change. */
time, .dee-start__day, .dee-start__price, .dee-card__price,
.dee-level__meta dd, .dee-facts__row dd, .dee-booking__price-value {
  font-variant-numeric: tabular-nums;
}

/* -------------------------------------------------------------------------
   5  LAYOUT PRIMITIVES
   ---------------------------------------------------------------------- */

.dee-wrap  { width: min(100% - 2.5rem, var(--dee-wrap)); margin-inline: auto; }
.dee-wrap--wide { width: min(100% - 2.5rem, var(--dee-wide)); }
/*
 * Prose comes out of the editor, and the editor is where a Word document
 * gets pasted.
 *
 * The Muster-Widerrufsformular arrived that way: its fill-in blanks are runs
 * of up to 76 underscores, which the browser treats as one word. One word
 * 635px wide inside a 390px phone — body has overflow-x: clip, so it was not
 * a sideways scroll but a sentence cut off at the screen edge, which is how
 * the school reported it.
 *
 * break-word rather than anywhere: the two wrap identically in a block like
 * this one, and anywhere additionally lets the paragraph's min-content fall
 * to a single character, which would let a narrow grid track collapse around
 * it. The blanks break; ordinary German keeps its word boundaries.
 */
.dee-prose { max-width: var(--dee-prose); overflow-wrap: break-word; }

.dee-section { padding-block: var(--dee-s9); position: relative; }
.dee-section--tight { padding-block: var(--dee-s7); }
.dee-section--alt { background: var(--dee-paper-deep); }

/* A hairline between sections instead of a slab of background colour.
   Alternating grey blocks is the tell of a template; a rule is a decision. */
.dee-section + .dee-section:not(.dee-section--alt)::before {
  content: ""; position: absolute; inset: 0 auto auto 0; width: 100%; height: 1px;
  background: var(--dee-rule);
}

.dee-grid { display: grid; gap: var(--dee-s5); }
.dee-grid--3 { grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); }
/*
 * auto-FILL, not auto-fit, for lists whose length the school controls.
 *
 * auto-fit collapses the empty tracks, so a programme page with exactly one
 * published course renders that course as a single 1180px-wide card with a
 * 663px cover — the same markup that looks correct on the hub, where there
 * are always four or more. auto-fill keeps the tracks, so one card is one
 * card's width. Identical to --3 as soon as the row is full.
 */
.dee-grid--fill { grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); }

/* Section heads carry a running number set in the display face. It gives the
   page a spine and tells a reader how far through a long homepage they are. */
.dee-section__head { margin-bottom: clamp(1.75rem, 1rem + 1.6vw, 2.5rem); max-width: 46rem; }
.dee-section__head .dee-eyebrow { display: flex; align-items: baseline; gap: var(--dee-s3); }
/* --dee-blue is a 3.3:1 tone on paper-deep — fine as a border or a fill,
   not as small text. The numeral uses the darker accent. */
.dee-section__n {
  font-family: var(--dee-display); font-weight: 800; font-size: var(--dee-fs-base);
  color: var(--dee-blue-dark); letter-spacing: 0;
}
.dee-section__n::after {
  content: ""; display: inline-block; width: 1.85rem; height: 2px;
  background: var(--dee-blue); margin-left: var(--dee-s3);
  vertical-align: middle; border-radius: 2px;
}
.dee-section__head h2 { margin-bottom: var(--dee-s4); }
.dee-section__head p:last-child { margin-bottom: 0; }
.dee-section__head--row {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: var(--dee-s6); max-width: none;
}

/* -------------------------------------------------------------------------
   6  MOTION — purposeful, and entirely optional
   ---------------------------------------------------------------------- */

/*
 * Nothing is hidden by a selector the markup carries. `.dee-reveal` is added
 * by JavaScript, and only to elements it has measured as below the fold — so
 * a page whose script never runs, or runs late, is simply a page without
 * animation rather than a page with invisible content. See assets/js/main.js
 * for why that trade is the whole point.
 */
.dee-reveal {
  opacity: 0;
  transform: translateY(12px);
  transition: opacity .42s var(--dee-ease), transform .42s var(--dee-ease);
  transition-delay: var(--dee-delay, 0ms);
}
.dee-reveal.is-in { opacity: 1; transform: none; }

@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;
  }
  .dee-reveal { opacity: 1 !important; transform: none !important; }
}

/* -------------------------------------------------------------------------
   7  COMPONENTS
   ---------------------------------------------------------------------- */

/* Buttons ---------------------------------------------------------------- */
.dee-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--dee-s2);
  padding: 0.875rem 1.5rem; border-radius: var(--dee-r-sm);
  font-family: var(--dee-font); font-weight: 600; font-size: var(--dee-fs-sm);
  text-decoration: none; border: 1.5px solid transparent; cursor: pointer;
  min-height: 48px; /* WCAG 2.5.5 target size */
  transition: background-color .18s var(--dee-ease), color .18s var(--dee-ease),
              border-color .18s var(--dee-ease), transform .18s var(--dee-ease);
}
.dee-btn:active { transform: translateY(1px); }
.dee-btn--primary { background: var(--dee-navy); color: #fff; border-color: var(--dee-navy); }
.dee-btn--primary:hover { background: var(--dee-blue-dark); border-color: var(--dee-blue-dark); color: #fff; }
.dee-btn--ghost { background: transparent; color: var(--dee-navy); border-color: var(--dee-rule-strong); }
.dee-btn--ghost:hover { border-color: var(--dee-navy); background: var(--dee-surface); color: var(--dee-navy); }
.dee-btn--dark { background: var(--dee-navy); color: #fff; }
.dee-btn--dark:hover { background: var(--dee-navy-deep); color: #fff; }
.dee-btn--sm { padding: 0.55rem 0.95rem; font-size: var(--dee-fs-xs); min-height: 40px; }
.dee-btn--lg { padding: 1.0625rem 2rem; font-size: var(--dee-fs-base); }
.dee-btn--light { background: #fff; color: var(--dee-navy); border-color: #fff; }
.dee-btn--light:hover { background: var(--dee-blue-wash); color: var(--dee-navy); }
.dee-btn--outline { background: transparent; color: #fff; border-color: rgba(255,255,255,.42); }
.dee-btn--outline:hover { border-color: #fff; background: rgba(255,255,255,.1); color: #fff; }
/* WhatsApp brand green is 3.11:1 behind white text. The floating bubble can
   keep it (it is an icon, judged as a non-text control at 3:1); a button with
   a written label cannot, so this darkens to 5.2:1. */
/*
 * The WhatsApp button is not WhatsApp green.
 *
 * It was #0a7d3c, a green that appeared nowhere else in a navy-and-blue
 * palette and read as a third-party badge glued onto the header — which is
 * exactly what it looked like. The channel stays, because it is how this
 * school gets most of its first contacts; the glyph carries the recognition,
 * which is all it ever needed to do.
 */
.dee-btn--wa { background: var(--dee-navy); color: #fff; border-color: var(--dee-navy); }
.dee-btn--wa:hover { background: var(--dee-navy-deep); border-color: var(--dee-navy-deep); color: #fff; }
.dee-cta-pair { display: flex; flex-wrap: wrap; gap: var(--dee-s3); }

/* Announcement bar ------------------------------------------------------- */
.dee-announce { background: var(--dee-navy-deep); color: #fff; font-size: var(--dee-fs-sm); }
.dee-announce__inner {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: center;
  gap: var(--dee-s4); padding-block: var(--dee-s3);
}
.dee-announce strong { color: #fff; font-weight: 600; }
.dee-announce__text { color: rgba(255,255,255,.82); }
.dee-announce__sep { opacity: .45; margin-inline: var(--dee-s1); }
.dee-announce__cta {
  color: #fff; font-weight: 600; text-decoration: none;
  display: inline-flex; align-items: center; gap: var(--dee-s2);
  border-bottom: 1px solid rgba(255,255,255,.35); padding-bottom: 1px;
}
.dee-announce__cta:hover { color: #fff; border-color: #fff; }

/* Header ----------------------------------------------------------------- */
.dee-header {
  position: sticky; top: 0; z-index: 100;
  background: rgba(251,250,248,.88);
  backdrop-filter: saturate(1.6) blur(12px);
  border-bottom: 1px solid var(--dee-rule);
}
.dee-header__inner {
  display: flex; align-items: center; gap: var(--dee-s5);
  padding-block: var(--dee-s4);
  width: min(100% - 2.5rem, var(--dee-wide));
  margin-inline: auto;
}
/*
 * `flex: none` here meant the wordmark never gave ground, and at 320px the
 * lockup is 276px wide inside a 280px wrap — so the burger was pushed to
 * x=320 on a 320px viewport. Entirely off-screen: on the smallest phones
 * there was no way to open the menu at all, and every page carried 16px of
 * horizontal scroll as the receipt.
 *
 * The mark keeps its size; the text beside it is what yields.
 */
.dee-brand { display: flex; align-items: center; gap: var(--dee-s3); text-decoration: none; flex: 0 1 auto; min-width: 0; }
.dee-brand__mark { display: flex; align-items: center; flex: none; }
.dee-brand__mark img, .dee-brand__mark .dee-logo {
  height: 46px; width: auto; max-width: 140px; object-fit: contain;
}
.dee-brand__text { display: flex; flex-direction: column; line-height: 1.25; min-width: 0; }
.dee-brand__tag {
  font-size: 0.6875rem; color: var(--dee-ink-faint); white-space: nowrap;
  letter-spacing: .04em; text-transform: uppercase;
}
.dee-brand__name {
  font-family: var(--dee-display); font-weight: 700; font-size: var(--dee-fs-base);
  color: var(--dee-navy); white-space: nowrap; letter-spacing: -0.02em;
}

/*
 * On a 320–380px phone the strapline is the first thing to go: it is a
 * descriptor, not the name, and losing it keeps "DEE Sprachschule Dortmund"
 * whole rather than truncating a proper noun mid-word.
 */
@media (max-width: 380px) {
  .dee-brand { gap: var(--dee-s2); }
  .dee-brand__tag  { display: none; }
  .dee-brand__name { font-size: var(--dee-fs-sm); white-space: normal; }
  .dee-brand__mark img, .dee-brand__mark .dee-logo { height: 38px; max-width: 104px; }
}

.dee-nav { margin-left: auto; }
.dee-nav > ul {
  display: flex; align-items: center; gap: clamp(0.75rem, 1.3vw, 1.4rem);
  list-style: none; margin: 0; padding: 0;
}
/*
 * `ul a`, not `a` — this rule styles MENU LINKS, and the drawer contains
 * several things that are anchors without being menu links.
 *
 * It read `.dee-nav a`, which is (0,1,1). A type selector outranks a class,
 * so it beat `.dee-btn--primary` (0,1,0) and painted every button inside the
 * navigation --dee-ink on --dee-navy: 1.10:1, a filled navy block with
 * nothing legible on it. The client photographed it and asked what the word
 * was supposed to be.
 *
 * The first fix was `a:not(.dee-btn)`, which repaired the buttons and then
 * did the same thing to the next non-menu anchor added to the panel: the
 * sign-out link took the nav's 18px and lost its underline. Excluding
 * classes one at a time is a list that grows every time the drawer gains a
 * control. Both menus are lists, so `ul a` says the thing itself, and the
 * identity band, the phone card and the buttons keep their own type.
 */
.dee-nav ul a {
  color: var(--dee-ink); text-decoration: none; font-weight: 500;
  font-size: var(--dee-fs-sm); white-space: nowrap;
  padding-block: .35rem; border-bottom: 1.5px solid transparent;
  transition: color .18s var(--dee-ease), border-color .18s var(--dee-ease);
}
.dee-nav ul a:hover, .dee-nav .current-menu-item > a {
  color: var(--dee-navy); border-color: var(--dee-blue);
}

/*
 * Submenus.
 *
 * `.dee-nav ul` used to be flex unconditionally, so the five level pages
 * nested under "Courses" rendered as a second row of links wedged under the
 * first — the English menu looked broken the moment it gained a hierarchy.
 * The child list is now a real panel.
 *
 * Opened on hover AND on focus-within AND on a .is-open class that main.js
 * toggles: hover alone excludes keyboard users, and :focus-within alone
 * excludes touch, where the first tap on a parent link would otherwise
 * navigate before the submenu was ever seen.
 */
.dee-nav li { position: relative; }
.dee-nav .menu-item-has-children > a { padding-right: 0.95rem; }
.dee-nav .menu-item-has-children > a::after {
  content: ""; position: absolute; right: 0; top: 50%;
  width: .42em; height: .42em; margin-top: -.28em;
  border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor;
  transform: rotate(45deg); opacity: .55;
}
.dee-nav .sub-menu {
  position: absolute; top: 100%; left: -0.9rem; z-index: 60;
  display: block; min-width: 13rem; margin: 0; padding: .5rem 0;
  list-style: none;
  background: #fff;
  border: 1px solid var(--dee-rule);
  border-radius: var(--dee-radius, 4px);
  box-shadow: 0 18px 44px -22px rgba(9, 24, 44, .38);
  /* Hidden by clip, not display:none — the panel keeps its measured width. */
  opacity: 0; visibility: hidden; transform: translateY(-4px);
  transition: opacity .16s var(--dee-ease), transform .16s var(--dee-ease), visibility .16s;
}
.dee-nav li:hover > .sub-menu,
.dee-nav li:focus-within > .sub-menu,
.dee-nav li.is-open > .sub-menu {
  opacity: 1; visibility: visible; transform: none;
}
.dee-nav .sub-menu a {
  display: block; padding: .42rem 1.1rem; border-bottom: 0;
  border-left: 2px solid transparent;
}
.dee-nav .sub-menu a:hover,
.dee-nav .sub-menu .current-menu-item > a {
  border-bottom: 0; border-left-color: var(--dee-blue);
  background: var(--dee-surface); color: var(--dee-navy);
}
@media (prefers-reduced-motion: reduce) {
  .dee-nav .sub-menu { transition: none; transform: none; }
}
.dee-header__actions { display: flex; gap: var(--dee-s3); flex: none; }
/*
 * 44px, and flex: none so the row squeezes the wordmark rather than the only
 * control on it. It had been measuring 16px wide at 320px — under the touch
 * target this project holds itself to, on the width where it matters most.
 */
.dee-burger {
  display: none; background: none; border: 0; cursor: pointer; color: var(--dee-navy);
  flex: none; place-items: center; width: 44px; height: 44px; padding: 0;
}

/* Hero ------------------------------------------------------------------- */
.dee-hero { padding-block: clamp(2.5rem, 1rem + 4vw, 5rem) var(--dee-s8); }

/*
 * Asymmetric on purpose: a 50/50 split reads as a template. The text column
 * gets the weight, the image column is a supporting note.
 *
 * The right column holds a photograph if the school has set one, and the live
 * fact panel otherwise (see dee_hero_facts). It is never an empty grid child
 * silently claiming its 5fr — which is what squeezed the headline into 40% of
 * the page in the first pass.
 */
.dee-hero__inner {
  display: grid;
  grid-template-columns: minmax(0, 6fr) minmax(0, 5fr);
  gap: clamp(2rem, 1rem + 4vw, 5rem);
  align-items: center;
  width: min(100% - 2.5rem, var(--dee-wide));
}

.dee-hero__title { margin-bottom: var(--dee-s5); }
/*
 * #7ec2ff, not --dee-blue. The accent line sits on the navy hero now, and
 * --dee-blue measures 3.1:1 against it — below AA even for large text, which
 * is exempt only down to 3:1 and this is a headline people are meant to read,
 * not a decorative flourish.
 */
.dee-hero__title span { color: var(--dee-hero-accent); }
.dee-hero .dee-lead { max-width: 46ch; margin-bottom: var(--dee-s6); }
.dee-hero__note {
  display: inline-flex; align-items: center; gap: var(--dee-s2);
  margin: var(--dee-s6) 0 0; padding: var(--dee-s2) var(--dee-s4);
  background: var(--dee-surface); border: 1px solid var(--dee-rule);
  border-radius: var(--dee-r-full);
  font-size: var(--dee-fs-sm); color: var(--dee-ink-soft);
}
.dee-hero__note strong { color: var(--dee-navy); font-weight: 600; }

/* Figures ---------------------------------------------------------------- */
.dee-figure { margin: 0; position: relative; }
.dee-figure img {
  border-radius: var(--dee-r-lg);
  width: 100%; object-fit: cover; display: block;
  /*
   * A grade, not a duotone.
   *
   * The first version was grayscale(1) under a navy multiply, written when the
   * only pictures available were empty rooms under office lighting. The
   * school's actual photography is of people, and full desaturation drained
   * them: a language school whose students are rendered in grey reads as an
   * archive, not a classroom. Skin tones survive at 0.82 saturation while the
   * palette still sits calmly under the type.
   */
  filter: saturate(.82) contrast(1.04);
}
/*
 * A scrim weighted to the bottom edge, where the fact card sits. A full-bleed
 * tint over the whole frame was what made the image look like a placeholder.
 */
.dee-figure::after {
  content: ""; position: absolute; inset: 0; border-radius: var(--dee-r-lg);
  background:
    linear-gradient(to top, rgba(0,33,71,.52) 0%, rgba(0,33,71,.16) 34%, rgba(0,33,71,0) 62%),
    linear-gradient(150deg, rgba(22,134,239,.14), rgba(0,33,71,.06));
  pointer-events: none;
}
.dee-figure--hero img  { aspect-ratio: 4 / 5; }
.dee-figure--split img { aspect-ratio: 1 / 1; }

.dee-figure--page {
  margin: var(--dee-s6) 0 var(--dee-s7);
}
.dee-figure--page img { aspect-ratio: 21 / 9; }
@media (max-width: 720px) { .dee-figure--page img { aspect-ratio: 3 / 2; } }

/* An optional heavier treatment, for imagery used as background texture. */
.dee-figure--muted img { filter: saturate(.35) contrast(1.06) brightness(1.02); }

/* Hero: the fact card overlaps the foot of the photograph ----------------- */
.dee-hero__media.has-photo { position: relative; }
.dee-hero__media.has-photo .dee-herofacts {
  position: absolute; left: var(--dee-s5); right: var(--dee-s5); bottom: var(--dee-s5);
  margin: 0;
  background: rgba(255,255,255,.94);
  backdrop-filter: saturate(1.4) blur(6px);
  box-shadow: 0 24px 48px -28px rgba(9,24,44,.55);
}
/*
 * Below this width the card would cover the face it sits on. It returns to
 * being a block under the picture, which is what it was designed as.
 */
@media (max-width: 1100px) {
  .dee-hero__media.has-photo .dee-herofacts {
    position: static; margin-top: calc(var(--dee-s5) * -1);
    margin-inline: var(--dee-s5);
  }
}

/* Feature strip ---------------------------------------------------------- */
.dee-features {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: 0; list-style: none; margin: 0; padding: 0;
  border-block: 1px solid var(--dee-rule);
}
.dee-feature {
  display: grid; grid-template-columns: auto 1fr; column-gap: var(--dee-s3);
  align-items: center; padding: var(--dee-s5) var(--dee-s4);
}
.dee-feature + .dee-feature { border-left: 1px solid var(--dee-rule); }
.dee-feature .dee-icon { grid-row: 1 / 3; color: var(--dee-blue); }
.dee-feature__k {
  font-family: var(--dee-display); font-weight: 700; font-size: var(--dee-fs-lg);
  color: var(--dee-navy); line-height: 1.15; letter-spacing: -0.02em;
}
.dee-feature__v { font-size: var(--dee-fs-sm); color: var(--dee-ink-soft); line-height: 1.35; }

/* Trust strip (inner pages) ---------------------------------------------- */
.dee-trust {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(170px,1fr)); gap: var(--dee-s5);
  border-block: 1px solid var(--dee-rule); padding-block: var(--dee-s5);
}
.dee-trust__item { text-align: center; }
.dee-trust__k { display: block; font-family: var(--dee-display); font-weight: 700; color: var(--dee-navy); }
.dee-trust__v { display: block; font-size: var(--dee-fs-sm); color: var(--dee-ink-soft); }

/* Course finder ---------------------------------------------------------- */
.dee-finder {
  background: var(--dee-surface);
  border: 1px solid var(--dee-rule);
  border-radius: var(--dee-r-lg);
  padding: clamp(1.5rem, 1rem + 2vw, 2.5rem);
  box-shadow: var(--dee-shadow);
}
.dee-finder__title { font-size: var(--dee-fs-xl); margin-bottom: var(--dee-s5); }
.dee-finder__row { display: grid; grid-template-columns: repeat(3, 1fr) auto; gap: var(--dee-s4); align-items: end; }
.dee-finder__field { margin: 0; }
.dee-finder__field label {
  display: block; font-size: var(--dee-fs-xs); font-weight: 600; text-transform: uppercase;
  letter-spacing: .1em; color: var(--dee-ink-faint); margin-bottom: var(--dee-s2);
}
.dee-finder__field select {
  width: 100%; min-height: 52px; padding: 0 var(--dee-s4); font: inherit;
  font-size: var(--dee-fs-sm); color: var(--dee-navy);
  background: var(--dee-paper); border: 1.5px solid var(--dee-rule);
  border-radius: var(--dee-r-sm); cursor: pointer;
  transition: border-color .18s var(--dee-ease);
}
.dee-finder__field select:hover { border-color: var(--dee-rule-strong); }
.dee-finder__field select:focus { border-color: var(--dee-blue); }
.dee-finder__submit { margin: 0; }
.dee-finder__submit .dee-btn { min-height: 52px; width: 100%; }
.dee-finder__count { margin: var(--dee-s4) 0 0; font-size: var(--dee-fs-sm); color: var(--dee-ink-soft); }
.dee-finder__count:empty { display: none; }

/* Value propositions ----------------------------------------------------- */
.dee-props { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: var(--dee-s4); }
.dee-prop {
  padding: var(--dee-s6) var(--dee-s5);
  background: var(--dee-surface);
  border: 1px solid var(--dee-rule);
  border-top: 3px solid var(--dee-navy);
  border-radius: var(--dee-r-lg);
  box-shadow: var(--dee-shadow-sm);
  transition: transform .2s var(--dee-ease), box-shadow .2s var(--dee-ease), border-color .2s var(--dee-ease);
}
.dee-prop:hover {
  transform: translateY(-3px);
  box-shadow: var(--dee-shadow-card);
  border-color: var(--dee-blue-tint);
  border-top-color: var(--dee-blue);
}
.dee-prop + .dee-prop { border-left: 1px solid var(--dee-rule); }
.dee-prop__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  border-radius: var(--dee-r);
  background: var(--dee-blue-wash);
  border: 1px solid var(--dee-blue-tint);
  color: var(--dee-blue);
  margin-bottom: var(--dee-s4);
}
.dee-prop__title {
  font-family: var(--dee-display);
  font-weight: 700;
  font-size: var(--dee-fs-base);
  color: var(--dee-navy);
  margin-bottom: var(--dee-s2);
}
.dee-prop__text { margin: 0; font-size: var(--dee-fs-sm); color: var(--dee-ink-soft); line-height: 1.6; }

/* The three real language chips on the translations page. */
.dee-langchips {
  display: flex; flex-wrap: wrap; gap: var(--dee-s3);
  list-style: none; margin: 0 0 var(--dee-s6); padding: 0;
}
.dee-langchips li {
  padding: var(--dee-s2) var(--dee-s4); border-radius: 999px;
  background: var(--dee-blue-wash); border: 1px solid var(--dee-blue-tint);
  color: var(--dee-navy); font-weight: 600; font-size: var(--dee-fs-sm);
}

/* Audience list — the medical page's "who this is for". Same card language
   as the trust strip (icon left, label right) rather than a new pattern. */
.dee-audience {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: var(--dee-s4); list-style: none; margin: 0; padding: 0;
}
.dee-audience li {
  display: flex; align-items: center; gap: var(--dee-s3);
  padding: var(--dee-s4) var(--dee-s5); background: var(--dee-surface);
  border: 1px solid var(--dee-rule); border-radius: var(--dee-r-lg);
  font-weight: 600; color: var(--dee-navy);
}
.dee-audience__icon { display: flex; flex: none; color: var(--dee-blue); }

/* Level cards — the editorial centrepiece --------------------------------
   The level is set as a large numeral in the display face rather than inside
   a coloured circle. It is the most recognisable thing on the page for
   someone who already knows they need B1. */
.dee-levels {
  /*
   * A gap, and no rule across the top. These were columns of a table divided
   * by hairlines; as cards they need air between them, and the rule that used
   * to separate them is now each card's own border.
   */
  display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: var(--dee-s4);
}
.dee-level {
  position: relative; display: flex; flex-direction: column;
  padding: var(--dee-s6) var(--dee-s5) var(--dee-s5);
  background: var(--dee-surface);
  border: 1px solid var(--dee-rule);
  border-radius: var(--dee-r-lg);
  border-top-width: 4px;
  border-top-color: var(--dee-rule-strong);
  box-shadow: var(--dee-shadow-card);
  transition: transform .25s var(--dee-ease), box-shadow .25s var(--dee-ease), border-color .25s var(--dee-ease);
}
.dee-level:hover {
  transform: translateY(-4px);
  box-shadow: var(--dee-shadow-hover);
}

.dee-level__badge {
  display: block; width: auto; height: auto; background: none;
  font-family: var(--dee-display); font-weight: 800;
  font-size: clamp(2.5rem, 2rem + 2vw, 3.5rem); line-height: 1;
  letter-spacing: -0.04em; color: var(--dee-navy);
  margin-bottom: var(--dee-s3);
  transition: color .22s var(--dee-ease), transform .22s var(--dee-ease);
}
.dee-level:hover .dee-level__badge { transform: scale(1.04); }

/* Distinct 5-level colour identities */
.dee-level[data-level="A1"] { border-top-color: var(--dee-lvl-a1); }
.dee-level[data-level="A2"] { border-top-color: var(--dee-lvl-a2); }
.dee-level[data-level="B1"] { border-top-color: var(--dee-lvl-b1); }
.dee-level[data-level="B2"] { border-top-color: var(--dee-lvl-b2); }
.dee-level[data-level="C1"] { border-top-color: var(--dee-lvl-c1); }

.dee-level[data-level="A1"] .dee-level__badge { color: var(--dee-lvl-a1); }
.dee-level[data-level="A2"] .dee-level__badge { color: var(--dee-lvl-a2); }
.dee-level[data-level="B1"] .dee-level__badge { color: var(--dee-lvl-b1); }
.dee-level[data-level="B2"] .dee-level__badge { color: var(--dee-lvl-b2); }
.dee-level[data-level="C1"] .dee-level__badge { color: var(--dee-lvl-c1); }


.dee-level.is-featured {
  border-top-color: var(--dee-lvl-b1);
  box-shadow: var(--dee-shadow-card);
}

.dee-level__stage {
  margin: 0 0 var(--dee-s2); font-size: var(--dee-fs-xs); font-weight: 600;
  text-transform: uppercase; letter-spacing: .12em; color: var(--dee-ink-faint);
}
/*
 * The same size as a course card's title. These two card types sit a screen
 * apart on the home page and the client reads them as one family — so a
 * heading that was a step smaller in one of them read as an inconsistency
 * rather than as a hierarchy.
 */
.dee-level__title {
  font-size: clamp(1.25rem, 1.12rem + 0.5vw, 1.5rem);
  line-height: 1.2;
  margin-bottom: var(--dee-s3);
  text-wrap: balance;
}
.dee-level__title a { color: var(--dee-navy); text-decoration: none; }
.dee-level__title a::after { content: ""; position: absolute; inset: 0; } /* whole card is the target */
.dee-level__text { font-size: var(--dee-fs-sm); color: var(--dee-ink-soft); margin-bottom: var(--dee-s5); line-height: 1.6; }
.dee-level__meta { margin: auto 0 var(--dee-s4); padding-top: var(--dee-s4); border-top: 1px solid var(--dee-rule); }
.dee-level__meta > div { display: flex; justify-content: space-between; gap: var(--dee-s3); font-size: var(--dee-fs-sm); align-items: baseline; }
/*
 * The same marked rows as a course card.
 *
 * These two lists sit on the same page and say the same kind of thing, and
 * one of them had icons while the other did not — which the client noticed
 * before we did. Same rule as there: a column of grey words is scanned as a
 * block, distinct marks are scanned as things.
 */
.dee-level__meta dt { display: flex; align-items: center; }
.dee-level__meta dt .dee-dt__icon { margin-inline-end: .45rem; }
/*
 * The value never wraps; the label may.
 *
 * Five cards across a 1180px wrap leaves about 200px of content per card, and
 * "Course fee" beside "from 569 €" does not fit — so the price broke after
 * the number and the € landed on a line of its own, with the marker stretched
 * around a two-line box. A blue smear with a stray euro sign in it, on the
 * one figure the card exists to state.
 *
 * The label is allowed to wrap because a two-line "Course / fee" beside a
 * clean price is tidy; the reverse is not.
 */
.dee-level__meta dd { white-space: nowrap; }
/*
 * The label keeps its word; the value gives way.
 *
 * `min-width: 0` was here so a long label would shrink rather than shove the
 * value out of the row — which worked while the label was plain text and
 * broke the moment it became an icon plus text: the icon took its width from
 * the same box, and "Kursgebühr" came out on the live home page as
 * "Kursgebüh", clipped mid-word on all five cards.
 *
 * The value is the short half here (a date, "ab 569 €"), so it is the half
 * that can afford to shrink. Nothing is ever cut off mid-word again.
 */
.dee-level__meta dt { flex: 0 0 auto; white-space: nowrap; }
.dee-level__meta dd { min-width: 0; }
.dee-level__meta > div + div { margin-top: var(--dee-s2); }
.dee-level__meta dt { color: var(--dee-ink-faint); }
.dee-level__meta dd { margin: 0; font-weight: 600; color: var(--dee-navy); }
.dee-level__link {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--dee-s2);
  font-size: var(--dee-fs-sm); font-weight: 600; padding: .55rem .9rem;
  border-radius: var(--dee-r); text-decoration: none; margin-top: var(--dee-s4);
  transition: all .2s var(--dee-ease);
}
.dee-level__link svg { transition: transform .22s var(--dee-ease); }
.dee-level:hover .dee-level__link svg { transform: translateX(3px); }



/* Next starts — an editorial list, not a card grid ------------------------ */
.dee-starts { border-top: 1px solid var(--dee-rule); }
.dee-start {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  gap: clamp(1rem, 3vw, 3rem);
  align-items: center;
  padding-block: var(--dee-s6);
  border-bottom: 1px solid var(--dee-rule);
  transition: background-color .2s var(--dee-ease);
}
.dee-start:hover { background: var(--dee-surface); }
.dee-start__date {
  display: grid; place-content: center; text-align: center;
  min-width: 92px; padding: var(--dee-s3);
  border-right: 1px solid var(--dee-rule); line-height: 1;
}
.dee-start__day {
  display: block; font-family: var(--dee-display); font-weight: 700;
  font-size: 2.5rem; letter-spacing: -0.04em; color: var(--dee-navy);
}
.dee-start__month {
  display: block; font-size: var(--dee-fs-xs); text-transform: uppercase;
  letter-spacing: .18em; color: var(--dee-ink-soft); margin-top: .35rem;
}
.dee-start__year { display: block; font-size: var(--dee-fs-xs); color: var(--dee-ink-faint); }
.dee-start__body { min-width: 0; }
.dee-start__title { font-size: var(--dee-fs-lg); margin-bottom: var(--dee-s2); }
.dee-start__title a { color: var(--dee-navy); text-decoration: none; }
.dee-start__title a:hover { color: var(--dee-blue-dark); }
.dee-start__meta { margin: 0 0 var(--dee-s3); font-size: var(--dee-fs-sm); color: var(--dee-ink-soft); }
.dee-start__foot {
  display: flex; align-items: center; gap: var(--dee-s5);
  border-top: 0; padding-top: 0;
}
.dee-start__price {
  font-family: var(--dee-display); font-weight: 700;
  font-size: var(--dee-fs-xl); color: var(--dee-navy); letter-spacing: -0.02em;
}

/* Seat status — one vocabulary everywhere a cycle appears ----------------- */
.dee-seat {
  display: inline-flex; align-items: center; gap: var(--dee-s2); margin: 0;
  font-size: var(--dee-fs-sm); font-weight: 600;
}
.dee-seat__dot { width: .5rem; height: .5rem; border-radius: 50%; background: currentColor; flex: none; }
.dee-seat__dot--free { color: var(--dee-ok); }
.dee-seat--free { color: var(--dee-ok); }
.dee-seat--low  { color: var(--dee-warn); }
.dee-seat--wait { color: var(--dee-warn); }
.dee-seat--sold { color: var(--dee-err); }

/* Split sections --------------------------------------------------------- */
.dee-split {
  display: grid; grid-template-columns: minmax(0, 6fr) minmax(0, 5fr);
  gap: clamp(2rem, 1rem + 4vw, 5rem); align-items: center;
}
.dee-split:not(:has(.dee-figure)) { grid-template-columns: minmax(0, var(--dee-prose)); }

.dee-split__copy > :last-child { margin-bottom: 0; }
.dee-split--reverse .dee-figure { order: -1; }

.dee-speclist { margin: 0 0 var(--dee-s6); border-top: 1px solid var(--dee-rule); }
.dee-speclist > div {
  display: flex; justify-content: space-between; gap: var(--dee-s4);
  padding-block: var(--dee-s3); border-bottom: 1px solid var(--dee-rule);
}
.dee-speclist dt { color: var(--dee-ink-soft); font-size: var(--dee-fs-sm); }
.dee-speclist dd { margin: 0; font-weight: 600; text-align: right; color: var(--dee-navy); }

/* Services --------------------------------------------------------------- */
.dee-services { display: grid; grid-template-columns: repeat(auto-fit, minmax(290px, 1fr)); gap: var(--dee-s5); }
.dee-service {
  position: relative; background: var(--dee-surface);
  border: 1px solid var(--dee-rule);
  border-top: 3px solid var(--dee-navy);
  border-radius: var(--dee-r-lg);
  padding: var(--dee-s6);
  box-shadow: var(--dee-shadow-card);
  transition: border-color .2s var(--dee-ease), transform .2s var(--dee-ease), box-shadow .2s var(--dee-ease);
}
.dee-service:hover, .dee-service:focus-within {
  border-color: var(--dee-blue-tint);
  border-top-color: var(--dee-blue);
  transform: translateY(-4px);
  box-shadow: var(--dee-shadow-hover);
}
.dee-service__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  border-radius: var(--dee-r);
  background: var(--dee-blue-wash);
  border: 1px solid var(--dee-blue-tint);
  color: var(--dee-blue);
  margin-bottom: var(--dee-s5);
}
.dee-service__title {
  font-family: var(--dee-display);
  font-weight: 700;
  font-size: var(--dee-fs-xl);
  margin-bottom: var(--dee-s3);
  letter-spacing: -0.02em;
}
.dee-service__title a { color: var(--dee-navy); text-decoration: none; }
.dee-service__title a::after { content: ""; position: absolute; inset: 0; }
.dee-service__text { font-size: var(--dee-fs-sm); color: var(--dee-ink-soft); margin-bottom: var(--dee-s4); line-height: 1.6; }
.dee-service__link {
  display: inline-flex;
  align-items: center;
  gap: var(--dee-s1);
  font-size: var(--dee-fs-sm);
  font-weight: 700;
  color: var(--dee-blue-dark);
}

/* Why DEE ---------------------------------------------------------------- */
.dee-why { list-style: none; margin: 0; padding: 0; display: grid; gap: 0; }
.dee-why__item {
  display: grid; grid-template-columns: auto 1fr; gap: var(--dee-s4); align-items: start;
  padding-block: var(--dee-s4); border-bottom: 1px solid var(--dee-rule);
}
.dee-why__item svg { color: var(--dee-blue); margin-top: .3em; flex: none; }

/* Closing band ----------------------------------------------------------- */
.dee-band { background: var(--dee-navy-deep); color: #fff; padding-block: var(--dee-s9); }
.dee-band__inner { display: grid; grid-template-columns: auto 1fr auto; gap: var(--dee-s6); align-items: center; }
.dee-band__icon {
  display: grid; place-items: center; width: 60px; height: 60px;
  border-radius: var(--dee-r-full); border: 1px solid rgba(255,255,255,.22); color: #fff;
}
.dee-band__icon .dee-icon { width: 28px; height: 28px; }
.dee-band__title { color: #fff; margin-bottom: var(--dee-s3); }
.dee-band__lead { margin: 0; color: rgba(255,255,255,.78); max-width: 50ch; font-size: var(--dee-fs-base); }
.dee-band__lead strong { color: #fff; font-weight: 600; }
.dee-band__actions { display: flex; gap: var(--dee-s3); flex-wrap: wrap; }
/*
 * Once they wrap, they match.
 *
 * The two buttons are sized by their words — "Kursplatz sichern" is 210px,
 * "Kostenlos einstufen" 229px. Side by side that reads as two buttons. Stacked
 * on a phone, one above the other, 19px of difference reads as a mistake, and
 * that is what the school circled. Nothing here changes the row layout; below
 * the wrap they simply take the full width they are already sharing.
 */
@media (max-width: 560px) {
  .dee-band__actions .dee-btn { flex: 1 1 100%; justify-content: center; }
}

/* Testimonials ----------------------------------------------------------- */
.dee-quotes__title { margin-bottom: var(--dee-s8); }
.dee-quotes__grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(270px, 1fr)); gap: var(--dee-s6); }
.dee-quote { margin: 0; padding-top: var(--dee-s5); border-top: 2px solid var(--dee-navy); }
.dee-quote blockquote {
  margin: 0 0 var(--dee-s4);
  font-family: var(--dee-display); font-size: var(--dee-fs-lg);
  line-height: 1.42; color: var(--dee-navy); letter-spacing: -0.015em;
}
.dee-quote blockquote p { margin: 0; }
.dee-quote figcaption { font-size: var(--dee-fs-sm); color: var(--dee-ink-soft); }
.dee-quote figcaption strong { display: block; color: var(--dee-ink); font-weight: 600; }

/* Cards ------------------------------------------------------------------ */
.dee-card {
  display: flex; flex-direction: column; height: 100%;
  background: var(--dee-surface); border: 1px solid var(--dee-rule);
  border-radius: var(--dee-r-lg); padding: var(--dee-s5);
  transition: border-color .2s var(--dee-ease), box-shadow .2s var(--dee-ease);
}
.dee-card:hover { border-color: var(--dee-blue-tint); box-shadow: var(--dee-shadow); }
/*
 * The card's own cover — the same per-level CEFR artwork as the course
 * hero, scaled down. Every course grid on the site (hub, level pages,
 * finder) was a stack of plain white text cards with nothing to look at
 * until a title was read; this gives each one a distinct, on-brand visual
 * anchor without needing real photography. Decorative only: it repeats the
 * title link's destination, so it is hidden from assistive tech rather than
 * announced as a second, unlabelled link to the same place.
 */
.dee-card__cover {
  display: block; margin: calc(var(--dee-s5) * -1) calc(var(--dee-s5) * -1) var(--dee-s4);
  aspect-ratio: 16 / 9; overflow: hidden;
  border-radius: var(--dee-r-lg) var(--dee-r-lg) 0 0;
  background: var(--dee-navy);
  position: relative;
}
.dee-card__cover .dee-chero__art { position: static; width: 100%; height: 100%; }

/*
 * The level, on the picture.
 *
 * Same idea as the course page's hero and at the same place in the frame, so
 * a person who has seen one recognises the other — but sized for a card in a
 * grid of three rather than a page header, and clamped so five across on a
 * laptop does not overflow the panel.
 *
 * It replaces the small grey level/format row that used to sit under the
 * picture; printing both would say the same two words twice on one card.
 */
.dee-card__caption {
  position: absolute; inset-inline-start: var(--dee-s4); inset-block-end: var(--dee-s3);
  display: flex; flex-direction: column; gap: .05rem; pointer-events: none;
}
.dee-card__caption-level {
  font-family: var(--dee-display); font-weight: 800;
  font-size: clamp(1.75rem, 1.4rem + 1.4vw, 2.5rem); line-height: 1;
  letter-spacing: -0.03em; color: #fff;
  text-shadow: 0 2px 12px rgba(0,10,25,.35);
}
.dee-card__caption-format {
  color: rgba(255,255,255,.85); font-size: var(--dee-fs-xs); font-weight: 600;
  letter-spacing: .06em; text-transform: uppercase;
}
/*
 * A course card falls back to its generated cover art and only shows a
 * photograph once the school has set a featured image on that course, so both
 * states have to sit in the same 16/9 frame.
 */
.dee-card__cover img {
  width: 100%; height: 100%; object-fit: cover; display: block;
  transition: transform .45s var(--dee-ease);
}
.dee-card:hover .dee-card__cover img { transform: scale(1.06); }
@media (prefers-reduced-motion: reduce) {
  .dee-card__cover img { transition: none; }
  .dee-card:hover .dee-card__cover img { transform: none; }
}
.dee-card__head { display: flex; gap: var(--dee-s2); margin-bottom: var(--dee-s4); }
.dee-card__level {
  font-family: var(--dee-display); font-weight: 700; font-size: var(--dee-fs-lg);
  color: var(--dee-navy); letter-spacing: -0.02em;
}
.dee-card__format { font-size: var(--dee-fs-xs); color: var(--dee-ink-soft); align-self: center; }
/*
 * The card's title, one step up.
 *
 * The client's note was "make the title a bit bigger in this card", and on a
 * card whose job is to be scanned in a grid he is right: the title was set at
 * the same --dee-fs-lg as a paragraph heading deep inside a page, where it
 * competes with the level badge above it and the bold figures below. Its own
 * clamp rather than --dee-fs-xl, which is a section heading and would shout.
 */
.dee-card__title {
  font-size: clamp(1.25rem, 1.12rem + 0.5vw, 1.5rem);
  line-height: 1.2;
  margin-bottom: var(--dee-s4);
  text-wrap: balance;
}
.dee-card__title a { color: var(--dee-navy); text-decoration: none; }
.dee-card__meta { margin: 0 0 var(--dee-s4); }
/*
 * The value can now be two facts — "Mo–Do, 08:30–12:00 Uhr" — so the row has
 * to survive a value longer than its label. gap keeps the two apart when the
 * value fills the row; min-width:0 lets the label shrink instead of shoving
 * the value out; and the value aligns to the end so a wrapped second line
 * still reads as one column.
 */
.dee-card__meta > div { display: flex; justify-content: space-between; align-items: baseline; gap: var(--dee-s2); font-size: var(--dee-fs-sm); padding-block: .3rem; }
/*
 * Same rule as the level cards, and for the same reason.
 *
 * `min-width: 0` on the label let it shrink so a long value would not shove
 * it out of the row. Once the label became an icon plus a word, the icon
 * took its width from that same box and the word was cut instead: every
 * course card on the site was reading "Unterricht" clipped to fit and
 * "Gruppe" shaved. The value is the half that can wrap — it already does —
 * so it is the half that gives way.
 */
.dee-card__meta dt { color: var(--dee-ink-faint); flex: 0 0 auto; white-space: nowrap; }
.dee-card__meta dd { margin: 0; font-weight: 600; text-align: end; min-width: 0; }
/*
 * The clock is one word.
 *
 * The longest value on the card is two facts joined by a comma — "Mo, Mi,
 * Fr, 18:00–20:15 Uhr" — and it has to wrap somewhere. The browser's own
 * choice was the en dash inside the time, so the card read "18:00–" on one
 * line and "20:15 Uhr" on the next. Forbidding that one break leaves the
 * comma after the days as the only place a line can end, which is where a
 * person would break it.
 *
 * `text-wrap: balance` was tried here first and was the wrong tool: it
 * evens the lines, so it moved days onto the second row to match its
 * length. Making the clock unbreakable fixes the cause instead.
 */
.dee-nowrap { white-space: nowrap; }
.dee-card__foot {
  margin-top: auto; padding-top: var(--dee-s4); border-top: 1px solid var(--dee-rule);
  display: flex; align-items: center; justify-content: space-between; gap: var(--dee-s3);
}
.dee-card__price { font-family: var(--dee-display); font-weight: 800; font-size: 1.5rem; color: var(--dee-navy); letter-spacing: -0.02em; }
/*
 * "Preis auf Anfrage" is a sentence, not a figure.
 *
 * It occupies the slot a 1.5rem number occupies, and at that weight and size
 * it shouts louder than the courses that do state a fee — the eye reads the
 * biggest thing in the row as the most important offer. Dropped to the size
 * of the surrounding meta text and to the muted ink, so a card without a
 * price reads as quieter than one with a price, which is the truth of it.
 *
 * The highlight sweep applied to .dee-card__price above is switched off for
 * the same reason: it is an emphasis mark for a number.
 */
.dee-card__price--open {
  font-family: inherit;
  font-weight: 600;
  font-size: var(--dee-fs-sm);
  color: var(--dee-ink-soft);   /* 5.2:1 on paper */
  letter-spacing: 0;
  padding-inline: 0;
}
.dee-card__price--open::before,
.dee-card__price--open::after { display: none; }

/*
 * Level accent — a 4px top rule and a tinted badge, keyed off the
 * data-level attribute dee_course_card() and dee_level_cards() emit.
 */
.dee-card[data-level] { border-top: 4px solid var(--dee-rule-strong); box-shadow: var(--dee-shadow-card); }
.dee-card[data-level="A1"] { border-top-color: var(--dee-lvl-a1); }
.dee-card[data-level="A2"] { border-top-color: var(--dee-lvl-a2); }
.dee-card[data-level="B1"] { border-top-color: var(--dee-lvl-b1); }
.dee-card[data-level="B2"] { border-top-color: var(--dee-lvl-b2); }
.dee-card[data-level="C1"] { border-top-color: var(--dee-lvl-c1); }
.dee-card[data-level="A1"] .dee-card__level { color: var(--dee-lvl-a1); font-weight: 800; }
.dee-card[data-level="A2"] .dee-card__level { color: var(--dee-lvl-a2); font-weight: 800; }
.dee-card[data-level="B1"] .dee-card__level { color: var(--dee-lvl-b1); font-weight: 800; }
.dee-card[data-level="B2"] .dee-card__level { color: var(--dee-lvl-b2); font-weight: 800; }
.dee-card[data-level="C1"] .dee-card__level { color: var(--dee-lvl-c1); font-weight: 800; }

.dee-card[data-level="A1"]:hover { border-color: var(--dee-lvl-a1-border); border-top-color: var(--dee-lvl-a1); }
.dee-card[data-level="A2"]:hover { border-color: var(--dee-lvl-a2-border); border-top-color: var(--dee-lvl-a2); }
.dee-card[data-level="B1"]:hover { border-color: var(--dee-lvl-b1-border); border-top-color: var(--dee-lvl-b1); }
.dee-card[data-level="B2"]:hover { border-color: var(--dee-lvl-b2-border); border-top-color: var(--dee-lvl-b2); }
.dee-card[data-level="C1"]:hover { border-color: var(--dee-lvl-c1-border); border-top-color: var(--dee-lvl-c1); }

/* Breadcrumbs ------------------------------------------------------------ */
.dee-crumbs { padding-block: var(--dee-s4); font-size: var(--dee-fs-xs); color: var(--dee-ink-faint); }
.dee-crumbs ol { display: flex; flex-wrap: wrap; gap: var(--dee-s2); list-style: none; margin: 0; padding: 0; }
.dee-crumbs li + li::before { content: "/"; margin-right: var(--dee-s2); color: var(--dee-rule-strong); }
.dee-crumbs a { color: var(--dee-ink-soft); text-decoration: none; }
.dee-crumbs a:hover { color: var(--dee-navy); text-decoration: underline; }

/* GEO blocks ------------------------------------------------------------- */
.dee-answer {
  border-left: 2px solid var(--dee-blue); padding: var(--dee-s2) 0 var(--dee-s2) var(--dee-s5);
  margin-block: var(--dee-s6);
}
.dee-answer__q { font-size: var(--dee-fs-xl); margin-bottom: var(--dee-s3); }
.dee-answer__a { margin: 0; font-size: var(--dee-fs-lg); line-height: 1.55; color: var(--dee-ink); }

.dee-facts {
  border: 1px solid var(--dee-rule); border-radius: var(--dee-r-lg);
  padding: var(--dee-s5); background: var(--dee-surface);
}
.dee-facts__title { font-size: var(--dee-fs-base); margin-bottom: var(--dee-s4); }
.dee-facts__list { margin: 0; }
.dee-facts__row {
  display: flex; justify-content: space-between; gap: var(--dee-s4);
  padding-block: var(--dee-s3); border-bottom: 1px solid var(--dee-rule);
}
.dee-facts__row:last-child { border-bottom: 0; }
.dee-facts__row dt { color: var(--dee-ink-soft); font-size: var(--dee-fs-sm); }
.dee-facts__row dd { margin: 0; font-weight: 600; text-align: right; color: var(--dee-navy); }
.dee-facts__stand { margin: var(--dee-s4) 0 0; font-size: var(--dee-fs-xs); color: var(--dee-ink-faint); }

.dee-author {
  display: flex; gap: var(--dee-s5); align-items: flex-start;
  border-top: 1px solid var(--dee-rule); padding-top: var(--dee-s5); margin-block: var(--dee-s7);
}
.dee-author__img img { width: 60px; height: 60px; border-radius: var(--dee-r-full); object-fit: cover; }
.dee-author__label {
  font-size: var(--dee-fs-xs); text-transform: uppercase; letter-spacing: .12em;
  color: var(--dee-ink-faint); display: block; margin-bottom: var(--dee-s2);
}
.dee-author__name { font-weight: 600; color: var(--dee-navy); }
.dee-author__role, .dee-author__quals, .dee-author__date { font-size: var(--dee-fs-sm); color: var(--dee-ink-soft); }

.dee-steps { margin-block: var(--dee-s6); }
.dee-steps__title {
  font-family: var(--dee-display);
  font-size: var(--dee-fs-xl);
  font-weight: 700;
  color: var(--dee-navy);
  margin-bottom: var(--dee-s5);
  letter-spacing: -0.02em;
}
.dee-steps__list { list-style: none; margin: 0; padding: 0; counter-reset: dee-step; }
.dee-steps__item {
  display: grid; grid-template-columns: auto 1fr; gap: var(--dee-s4);
  padding-block: var(--dee-s4); border-bottom: 1px solid var(--dee-rule);
  align-items: start;
}
.dee-steps__num {
  font-family: var(--dee-display); font-weight: 800; font-size: 1.15rem;
  color: var(--dee-navy); line-height: 1; letter-spacing: -0.02em;
  width: 44px; height: 44px; border-radius: var(--dee-r-full);
  background: var(--dee-blue-wash); border: 1.5px solid var(--dee-blue-tint);
  display: inline-flex; align-items: center; justify-content: center;
  flex: none; margin-top: .15rem;
}
.dee-steps__h {
  font-family: var(--dee-display);
  font-weight: 700;
  font-size: var(--dee-fs-lg);
  color: var(--dee-navy);
  margin: 0 0 var(--dee-s1);
}
.dee-steps__p { margin: 0; font-size: var(--dee-fs-sm); color: var(--dee-ink-soft); line-height: 1.55; }

.dee-faq__title { margin-bottom: var(--dee-s5); }
.dee-faq__list { border-top: 1px solid var(--dee-rule); }
.dee-faq__item { border-bottom: 1px solid var(--dee-rule); padding-block: var(--dee-s5); }
.dee-faq__q { font-size: var(--dee-fs-base); margin-bottom: var(--dee-s3); }
.dee-faq__a { margin: 0; color: var(--dee-ink-soft); font-size: var(--dee-fs-sm); }

.dee-compare { margin-block: var(--dee-s6); }
.dee-compare__title { font-size: var(--dee-fs-lg); }
.dee-compare__intro { color: var(--dee-ink-soft); }
.dee-compare__scroll { overflow-x: auto; }
.dee-compare__table { width: 100%; border-collapse: collapse; font-size: var(--dee-fs-sm); }
.dee-compare__table th, .dee-compare__table td {
  text-align: left; padding: var(--dee-s3) var(--dee-s4); border-bottom: 1px solid var(--dee-rule);
}
.dee-compare__table th { font-weight: 600; color: var(--dee-navy); }

.dee-related { margin-block: var(--dee-s6); }
.dee-related__title { font-size: var(--dee-fs-lg); }
.dee-related__list { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: var(--dee-s3); }
.dee-related__list a {
  display: inline-block; padding: .4rem .9rem; border: 1px solid var(--dee-rule);
  border-radius: var(--dee-r-full); font-size: var(--dee-fs-sm); text-decoration: none;
  color: var(--dee-ink); background: var(--dee-surface);
}
.dee-related__list a:hover { border-color: var(--dee-blue); color: var(--dee-navy); }

/* Enrolment form --------------------------------------------------------- */
.dee-booking {
  background: var(--dee-surface);
  border: 1px solid var(--dee-rule);
  border-top: 4px solid var(--dee-blue);
  border-radius: var(--dee-r-lg);
  padding: clamp(1.5rem, 1rem + 2vw, 2.5rem);
  box-shadow: var(--dee-shadow-card);
}
.dee-booking__step { border: 0; padding: 0; margin: 0 0 var(--dee-s7); }
.dee-booking__legend {
  display: flex; align-items: center; gap: var(--dee-s3); padding: 0;
  font-family: var(--dee-display); font-weight: 700; font-size: var(--dee-fs-base);
  color: var(--dee-navy); margin-bottom: var(--dee-s4); letter-spacing: -0.015em;
}
.dee-booking__num {
  display: grid; place-items: center; width: 28px; height: 28px; flex: none;
  background: var(--dee-blue-wash); border: 1.5px solid var(--dee-blue-tint);
  border-radius: var(--dee-r-full); color: var(--dee-navy);
  font-family: var(--dee-display); font-size: var(--dee-fs-xs); font-weight: 800;
}
.dee-booking__hint { font-size: var(--dee-fs-sm); color: var(--dee-ink-soft); margin-bottom: var(--dee-s4); }
.dee-booking__opts { display: grid; gap: var(--dee-s3); }
.dee-booking__opts--row { grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); }
.dee-booking__opts--dates { grid-template-columns: 1fr; }

.dee-opt { display: block; cursor: pointer; }
.dee-opt input { position: absolute; opacity: 0; width: 0; height: 0; }
.dee-opt__box {
  display: flex; flex-direction: column; gap: .15rem;
  padding: var(--dee-s4); border: 1.5px solid var(--dee-rule);
  border-radius: var(--dee-r); background: var(--dee-paper);
  transition: border-color .18s var(--dee-ease), background-color .18s var(--dee-ease);
}
.dee-opt__box strong { font-weight: 600; color: var(--dee-navy); }
.dee-opt__box small { font-size: var(--dee-fs-xs); color: var(--dee-ink-soft); }
.dee-opt:hover .dee-opt__box { border-color: var(--dee-rule-strong); }
.dee-opt input:checked + .dee-opt__box { border-color: var(--dee-blue); background: var(--dee-blue-wash); }
.dee-opt input:focus-visible + .dee-opt__box { outline: 3px solid var(--dee-blue); outline-offset: 2px; }
.dee-opt input:disabled + .dee-opt__box { opacity: .55; cursor: not-allowed; }
.dee-opt--date .dee-opt__box { flex-direction: row; align-items: baseline; flex-wrap: wrap; gap: var(--dee-s3); }
.dee-opt--date .dee-opt__box strong { flex: 1 0 auto; }
.dee-opt__time { color: var(--dee-ink-soft); }
.dee-opt .is-free { color: var(--dee-ok); font-weight: 600; }
.dee-opt .is-low  { color: var(--dee-warn); font-weight: 600; }
.dee-opt .is-wait { color: var(--dee-warn); font-weight: 600; }
.dee-opt .is-sold { color: var(--dee-err); font-weight: 600; }

/*
 * A full run is still an option, so it must not read as a disabled control.
 * It is dimmed enough to be visibly different from a free run and no further:
 * the whole point is that it can be chosen.
 */
.dee-opt--date.is-sold .dee-opt__box { background: var(--dee-paper-deep); }
.dee-opt__note {
  flex: 1 0 100%; margin-top: .35rem; color: var(--dee-ink-soft);
  font-size: var(--dee-fs-xs); line-height: 1.45;
}
.dee-opt input:checked + .dee-opt__box .dee-opt__note { color: var(--dee-navy); }

/* Staff-only, so it is marked as staff-only rather than dressed as a field. */
.dee-booking__testflag {
  display: flex; gap: .6rem; align-items: flex-start;
  margin: var(--dee-s5) 0 0; padding: var(--dee-s3) var(--dee-s4);
  border: 1px dashed var(--dee-rule-strong); border-radius: var(--dee-r);
  background: var(--dee-paper-deep); color: var(--dee-ink-soft);
  font-size: var(--dee-fs-xs); line-height: 1.5;
}
.dee-booking__testflag input { margin-top: .18rem; }

.dee-booking__more {
  margin-top: var(--dee-s3); background: none; border: 0; padding: .4rem 0;
  color: var(--dee-blue-dark); font: inherit; font-size: var(--dee-fs-sm);
  font-weight: 600; cursor: pointer; text-decoration: underline;
}
.dee-booking__reveal { padding: var(--dee-s4) 0 var(--dee-s2) var(--dee-s5); border-left: 2px solid var(--dee-blue-tint); }
.dee-booking__note { margin: 0; font-size: var(--dee-fs-sm); color: var(--dee-ink-soft); }
.dee-file__label { display: block; font-weight: 600; font-size: var(--dee-fs-sm); margin-bottom: var(--dee-s2); }
.dee-file input[type=file] { font-size: var(--dee-fs-sm); }
.dee-file__hint { display: block; margin-top: var(--dee-s2); font-size: var(--dee-fs-xs); color: var(--dee-ink-faint); }
.dee-file__error { display: block; margin-top: var(--dee-s2); color: var(--dee-err); font-weight: 600; font-size: var(--dee-fs-sm); }

.dee-hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }
.dee-booking__errors {
  border-left: 2px solid var(--dee-err); background: #fdf3f2; color: #7d201a;
  padding: var(--dee-s5); border-radius: 0 var(--dee-r) var(--dee-r) 0; margin-bottom: var(--dee-s6);
}
.dee-booking__errors ul { margin: var(--dee-s2) 0 0; padding-left: 1.2em; }
.dee-booking__errors li { font-size: var(--dee-fs-sm); }

.dee-grid--form { display: grid; grid-template-columns: repeat(6, 1fr); gap: var(--dee-s4); }
.dee-field { margin: 0; }
.dee-field--full       { grid-column: span 6; }
.dee-field--half       { grid-column: span 3; }
.dee-field--third      { grid-column: span 2; }
.dee-field--two-thirds { grid-column: span 4; }
.dee-field label { display: block; font-size: var(--dee-fs-sm); font-weight: 600; margin-bottom: var(--dee-s2); }
/*
 * `select` joins input and textarea here.
 *
 * The Anrede field is the first plain <select> in this form — the country
 * fields are a custom control layered over a hidden one — and without this it
 * rendered as a browser default box beside eleven styled ones.
 */
.dee-field input, .dee-field textarea, .dee-field select {
  width: 100%; padding: .7rem var(--dee-s4); font: inherit; font-size: var(--dee-fs-sm);
  color: var(--dee-ink); background: var(--dee-paper);
  border: 1.5px solid var(--dee-rule); border-radius: var(--dee-r-sm);
  transition: border-color .18s var(--dee-ease), background-color .18s var(--dee-ease);
}
.dee-field input:hover, .dee-field textarea:hover, .dee-field select:hover { border-color: var(--dee-rule-strong); }
.dee-field input:focus, .dee-field textarea:focus, .dee-field select:focus { border-color: var(--dee-blue); background: var(--dee-surface); }
/*
 * The country select is a FIELD until JavaScript makes it something else.
 *
 * This used to strip its padding, border and background on the assumption
 * that country.js would replace it — and country.js hides the select itself,
 * with `.dee-cc__native`, once the replacement is wired up. So on a page with
 * the script the rule did nothing, and on a page without it the visitor got a
 * bare 21px-tall select wedged between 44px-tall inputs: the one state the
 * enhancement was carefully written to degrade to, rendered as though the CSS
 * had failed to load. Found by measuring every control on every page rather
 * than by looking at a page with working JavaScript, which is the only way
 * this class of bug is ever found.
 */
.dee-check {
  display: grid; grid-template-columns: auto 1fr; gap: var(--dee-s3);
  align-items: start; margin-top: var(--dee-s5); font-size: var(--dee-fs-sm); color: var(--dee-ink-soft);
}
/* Size and alignment live with the other touch targets, at the foot of this file. */
.dee-check input { flex: none; }

.dee-booking__foot {
  display: flex; align-items: center; justify-content: space-between; gap: var(--dee-s5);
  flex-wrap: wrap; padding-top: var(--dee-s5); border-top: 1px solid var(--dee-rule);
}
.dee-booking__price-label { display: block; font-size: var(--dee-fs-xs); text-transform: uppercase; letter-spacing: .1em; color: var(--dee-ink-faint); }
.dee-booking__price-value { font-family: var(--dee-display); font-weight: 700; font-size: var(--dee-fs-2xl); color: var(--dee-navy); letter-spacing: -0.03em; }
.dee-booking__price-note { display: block; font-size: var(--dee-fs-xs); color: var(--dee-ink-soft); }
.dee-booking__legal { margin: var(--dee-s5) 0 0; font-size: var(--dee-fs-xs); color: var(--dee-ink-faint); }
.dee-booking__empty { color: var(--dee-ink-soft); }
.dee-req { color: var(--dee-err); text-decoration: none; border: 0; }

/* WhatsApp float --------------------------------------------------------- */
.dee-wa {
  position: fixed; right: 1.25rem; bottom: 1.25rem; z-index: 90;
  display: grid; place-items: center; width: 54px; height: 54px;
  border-radius: var(--dee-r-full); background: var(--dee-navy); color: #fff;
  border: 1px solid rgba(255, 255, 255, .18);
  box-shadow: 0 12px 32px -12px rgba(0, 16, 38, .72);
  transition: transform .2s var(--dee-ease), background-color .2s var(--dee-ease);
}
.dee-wa:hover { transform: scale(1.06); color: #fff; }

/* Footer ----------------------------------------------------------------- */
.dee-footer { background: var(--dee-navy-deep); color: rgba(255,255,255,.72); padding-block: var(--dee-s8) var(--dee-s6); }
.dee-footer a { color: rgba(255,255,255,.86); text-decoration: none; }
.dee-footer a:hover { color: #fff; text-decoration: underline; }
.dee-footer__cols { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: var(--dee-s6); }
.dee-footer h2, .dee-footer h3 { color: #fff; font-size: var(--dee-fs-sm); text-transform: uppercase; letter-spacing: .12em; font-family: var(--dee-font); font-weight: 600; }
.dee-footer ul { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--dee-s2); font-size: var(--dee-fs-sm); }
.dee-footer__bottom {
  margin-top: var(--dee-s7); padding-top: var(--dee-s5);
  border-top: 1px solid rgba(255,255,255,.14);
  display: flex; flex-wrap: wrap; gap: var(--dee-s4); justify-content: space-between;
  font-size: var(--dee-fs-xs);
}
.dee-footer img { filter: brightness(0) invert(1); }

/* Social links (footer) --------------------------------------------------- */
/*
 * `.dee-footer ul` above (class + element, 0-1-1) outranks a bare `.dee-social`
 * (0-1-0) — CSS did not care that this list is also `.dee-social`, only that
 * it is a <ul> inside `.dee-footer`, so its `display: grid` quietly won and
 * the row of three icons stacked into a column of three. `.dee-footer
 * .dee-social` (0-2-0) is the one selector below that actually outranks it;
 * plain `.dee-social` stays for the sidebar's "Folge uns" widget, which sits
 * outside `.dee-footer` and was never affected.
 */
.dee-social {
  list-style: none; margin: var(--dee-s4) 0 0; padding: 0;
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--dee-s3);
}
.dee-footer .dee-social {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--dee-s3);
}
.dee-social a {
  display: grid; place-items: center; width: 38px; height: 38px; flex: 0 0 auto;
  border-radius: var(--dee-r-full); border: 1px solid rgba(255,255,255,.18);
  color: rgba(255,255,255,.86);
  transition: background-color .2s var(--dee-ease), color .2s var(--dee-ease), border-color .2s var(--dee-ease);
}
.dee-social a:hover { background: rgba(255,255,255,.12); border-color: rgba(255,255,255,.32); color: #fff; text-decoration: none; }

/* Google rating badge (hero) ----------------------------------------------- */
.dee-google-rating {
  display: inline-flex; align-items: center; gap: var(--dee-s3);
  margin: var(--dee-s5) 0 0; padding: var(--dee-s2) var(--dee-s4);
  background: #fff; border-radius: var(--dee-r-full);
  box-shadow: 0 8px 24px -10px rgba(0, 33, 71, .28);
  text-decoration: none; color: var(--dee-ink);
}
.dee-google-rating:hover { text-decoration: none; box-shadow: 0 10px 28px -8px rgba(0, 33, 71, .36); }
.dee-google-rating__stars { display: flex; gap: 1px; color: #f5a623; flex: none; }
.dee-google-rating__text { font-size: var(--dee-fs-sm); color: var(--dee-ink-soft); }
.dee-google-rating__text strong { color: var(--dee-navy); font-weight: 700; margin-inline-end: .3em; }
.dee-google-rating__count { color: var(--dee-ink-soft); }
@media (max-width: 480px) {
  .dee-google-rating { flex-wrap: wrap; }
  .dee-google-rating__count { flex-basis: 100%; }
}

/* Icons ------------------------------------------------------------------ */
.dee-icon { width: 24px; height: 24px; }

/* -------------------------------------------------------------------------
   8  RESPONSIVE
   ---------------------------------------------------------------------- */

@media (max-width: 1200px) {
  .dee-burger { display: grid; margin-left: auto; }
  .dee-nav {
    position: fixed; inset: 0 0 0 28%; background: var(--dee-paper);
    padding: var(--dee-s8) var(--dee-s5);
    transform: translateX(100%); transition: transform .25s var(--dee-ease);
    box-shadow: var(--dee-shadow-lg); overflow-y: auto; z-index: 120;
  }
  .dee-nav[data-open="true"] { transform: none; }
  .dee-nav > ul { flex-direction: column; align-items: flex-start; gap: var(--dee-s4); }
  .dee-nav ul a { font-size: var(--dee-fs-lg); }
  .dee-header__actions { display: none; }

  /*
   * In the drawer the submenu is an indented list, not a floating panel:
   * a hover-triggered dropdown has no meaning on a touch device, and an
   * absolutely-positioned one would hang off the edge of the drawer.
   */
  .dee-nav .sub-menu {
    position: static; opacity: 1; visibility: visible; transform: none;
    min-width: 0; margin: var(--dee-s3) 0 0; padding: 0 0 0 var(--dee-s4);
    background: none; border: 0; border-left: 1px solid var(--dee-rule);
    border-radius: 0; box-shadow: none;
    display: flex; flex-direction: column; gap: var(--dee-s3);
  }
  .dee-nav .sub-menu a { padding: 0 0 0 var(--dee-s3); font-size: var(--dee-fs-base); }
  .dee-nav .menu-item-has-children > a::after { display: none; }
}

@media (max-width: 980px) {
  .dee-hero__inner { grid-template-columns: 1fr; gap: var(--dee-s6); }
  /*
   * A photograph may lead on a narrow screen; the fact panel may not. Hoisting
   * the panel above the copy pushed the H1 — the largest contentful paint and
   * the reason the visitor is here — off the first screen entirely. Only the
   * figure gets promoted.
   */
  .dee-hero__media:has(.dee-figure) { order: -1; }
  .dee-figure--hero img { aspect-ratio: 16 / 9; }
  .dee-split { grid-template-columns: 1fr; gap: var(--dee-s6); }
  .dee-split--reverse .dee-figure { order: 0; }
  .dee-band__inner { grid-template-columns: 1fr; }
  .dee-band__icon { display: none; }
}

@media (max-width: 860px) {
  .dee-finder__row { grid-template-columns: 1fr 1fr; }
  .dee-feature + .dee-feature { border-left: 0; border-top: 1px solid var(--dee-rule); }
  .dee-prop + .dee-prop { border-left: 0; }
}

@media (max-width: 720px) {
  .dee-start { grid-template-columns: auto 1fr; row-gap: var(--dee-s4); }
  .dee-start__foot {
    grid-column: 1 / -1; justify-content: space-between;
    padding-top: var(--dee-s4); border-top: 1px solid var(--dee-rule);
  }
  .dee-start__date { min-width: 72px; }
  .dee-start__day { font-size: 2rem; }
  .dee-section__head--row { flex-direction: column; align-items: flex-start; }
}

@media (max-width: 560px) {
  .dee-finder__row { grid-template-columns: 1fr; }
  .dee-grid--form { grid-template-columns: 1fr; }
  .dee-field--full, .dee-field--half, .dee-field--third, .dee-field--two-thirds { grid-column: span 1; }
  .dee-booking { padding: var(--dee-s5) var(--dee-s4); }
  .dee-booking__foot { flex-direction: column; align-items: stretch; }
  .dee-booking__foot .dee-btn { width: 100%; }
}

/* Hero fact panel --------------------------------------------------------
   Stands in for the photograph the school does not have, and answers the
   four questions a visitor came with. Values are live from the course data. */
.dee-herofacts {
  background: var(--dee-surface);
  border: 1px solid var(--dee-rule);
  border-radius: var(--dee-r-lg);
  padding: var(--dee-s6);
  box-shadow: var(--dee-shadow);
}
.dee-herofacts__list { margin: 0; }
.dee-herofacts__row {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--dee-s4); padding-block: var(--dee-s4);
  border-bottom: 1px solid var(--dee-rule);
}
.dee-herofacts__row:last-child { border-bottom: 0; }
.dee-herofacts__row dt { color: var(--dee-ink-soft); font-size: var(--dee-fs-sm); }
.dee-herofacts__row dd {
  margin: 0; font-weight: 600; color: var(--dee-navy); text-align: right;
  font-variant-numeric: tabular-nums;
}
.dee-herofacts__row.is-lead { padding-top: 0; display: block; }
.dee-herofacts__row.is-lead dt {
  font-size: var(--dee-fs-xs); text-transform: uppercase; letter-spacing: .12em;
  color: var(--dee-ink-faint); margin-bottom: var(--dee-s2);
}
.dee-herofacts__row.is-lead dd {
  font-family: var(--dee-display); font-weight: 700;
  font-size: clamp(2rem, 1.4rem + 1.8vw, 2.75rem);
  letter-spacing: -0.035em; text-align: left; line-height: 1;
}
.dee-herofacts__note {
  margin: var(--dee-s5) 0 0; padding-top: var(--dee-s4);
  border-top: 1px solid var(--dee-rule);
  font-size: var(--dee-fs-sm); color: var(--dee-ink-soft);
}
/* Sentence on one line, call to action on the next — deliberately, rather
   than wherever the measure happened to break it. */
.dee-herofacts__notetext { display: block; }
.dee-herofacts__notelink { display: inline-block; margin-top: var(--dee-s2); font-weight: 600; }

/* =========================================================================
   LANGUAGE, ACCOUNTS, ILLUSTRATIONS
   ====================================================================== */

/* Language switcher ------------------------------------------------------ */
.dee-langs { display: flex; align-items: center; gap: 2px; flex: none; }
.dee-langs__item {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 40px; min-height: 40px; padding: 0 .5rem;
  font-size: var(--dee-fs-xs); font-weight: 600; letter-spacing: .06em;
  color: var(--dee-ink-soft); text-decoration: none;
  border-radius: var(--dee-r-sm);
  transition: color .18s var(--dee-ease), background-color .18s var(--dee-ease);
}
.dee-langs__item:hover { color: var(--dee-navy); background: var(--dee-paper-deep); }
.dee-langs__item.is-current { color: var(--dee-navy); background: var(--dee-paper-deep); }

/* Illustrations ----------------------------------------------------------
   Sized by their container, never by intrinsic width — an SVG that sets its
   own size fights every grid it is placed in. */
.dee-ill { width: 100%; height: auto; display: block; }
.dee-illwrap {
  background: var(--dee-surface);
  border: 1px solid var(--dee-rule);
  border-radius: var(--dee-r-lg);
  padding: clamp(1rem, .5rem + 2vw, 2.25rem);
}

/* Notices ---------------------------------------------------------------- */
.dee-notice {
  border-left: 3px solid var(--dee-blue);
  background: var(--dee-blue-wash);
  padding: var(--dee-s5);
  border-radius: 0 var(--dee-r) var(--dee-r) 0;
  margin-bottom: var(--dee-s6);
}
.dee-notice p:last-child { margin-bottom: 0; }
.dee-notice--ok   { border-color: var(--dee-ok);   background: #eef7f1; }
.dee-notice--warn { border-color: var(--dee-warn); background: #fdf6ea; }

/* Auth forms ------------------------------------------------------------- */
.dee-gate {
  background: var(--dee-surface); border: 1px solid var(--dee-rule);
  border-radius: var(--dee-r-lg); padding: clamp(1.25rem, .75rem + 2vw, 2rem);
}
.dee-gate__head { padding-bottom: var(--dee-s5); border-bottom: 1px solid var(--dee-rule); margin-bottom: var(--dee-s6); }
.dee-gate__title { font-size: var(--dee-fs-xl); margin-bottom: var(--dee-s2); }
.dee-gate__lead { color: var(--dee-ink-soft); font-size: var(--dee-fs-sm); margin-bottom: var(--dee-s4); }
.dee-gate__price { display: flex; flex-direction: column; margin: 0; }
.dee-gate__forms { display: grid; gap: var(--dee-s6); }
@media (min-width: 900px) { .dee-gate__forms { grid-template-columns: 1fr 1.15fr; gap: var(--dee-s7); align-items: start; } }

.dee-auth { display: block; }
.dee-auth + .dee-auth { padding-top: var(--dee-s6); border-top: 1px solid var(--dee-rule); }
@media (min-width: 900px) {
  .dee-auth + .dee-auth {
    padding-top: 0; padding-left: var(--dee-s7);
    border-top: 0; border-left: 1px solid var(--dee-rule);
  }
}
.dee-auth__title { font-size: var(--dee-fs-lg); margin-bottom: var(--dee-s4); }
.dee-auth__intro { font-size: var(--dee-fs-sm); color: var(--dee-ink-soft); margin-bottom: var(--dee-s5); }
.dee-auth .dee-field { margin-bottom: var(--dee-s4); }
.dee-auth .dee-btn { width: 100%; margin-top: var(--dee-s5); }
.dee-auth__alt { margin: var(--dee-s4) 0 0; font-size: var(--dee-fs-sm); text-align: center; }

/* Student area ----------------------------------------------------------- */
.dee-wrap--narrow { width: min(100% - 2.5rem, 62rem); }
.dee-account__head {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: var(--dee-s5); flex-wrap: wrap;
  padding-bottom: var(--dee-s5); border-bottom: 1px solid var(--dee-rule);
  margin-bottom: var(--dee-s7);
}
.dee-account__head h1 { font-size: var(--dee-fs-2xl); margin-bottom: var(--dee-s2); }
.dee-account__head .dee-lead { font-size: var(--dee-fs-sm); margin: 0; }
.dee-account__list { display: grid; gap: var(--dee-s5); }
.dee-account__item {
  display: grid; grid-template-columns: 1fr auto; gap: var(--dee-s5);
  background: var(--dee-surface); border: 1px solid var(--dee-rule);
  border-radius: var(--dee-r-lg); padding: var(--dee-s6);
}
.dee-account__item h3 { font-size: var(--dee-fs-lg); margin-bottom: var(--dee-s4); }
.dee-account__item .dee-speclist { margin-bottom: 0; }
.dee-account__status { text-align: right; }
.dee-account__ref { margin: var(--dee-s3) 0 0; font-size: var(--dee-fs-xs); color: var(--dee-ink-faint); font-variant-numeric: tabular-nums; }
.dee-account__empty { color: var(--dee-ink-soft); }
.dee-badge {
  display: inline-block; padding: .25em .75em; border-radius: var(--dee-r-full);
  font-size: var(--dee-fs-xs); font-weight: 600; color: #fff;
  background: var(--dee-badge, var(--dee-navy)); white-space: nowrap;
}
@media (max-width: 640px) {
  .dee-account__item { grid-template-columns: 1fr; }
  .dee-account__status { text-align: left; }
}

/* The way out of a course, on the account card and on the legal page.
 *
 * Quiet on purpose. It sits beside the enrolment it ends, in the same column
 * as the status badge, and it is a link rather than a button: a control that
 * competes with "Kursplatz sichern" for attention is a control somebody
 * presses by accident. The confirmation, the deadline and the consequence all
 * live one click away, on the Widerrufsbelehrung itself. */
.dee-account__cancel { margin: var(--dee-s3) 0 0; font-size: var(--dee-fs-xs); }
.dee-account__cancel a { color: var(--dee-ink-soft); text-decoration: underline; text-underline-offset: 2px; }
.dee-account__cancel a:hover, .dee-account__cancel a:focus-visible { color: var(--dee-err); }
.dee-account__pending {
  margin: var(--dee-s3) 0 0; font-size: var(--dee-fs-xs);
  color: var(--dee-warn);
}

/* The bridge into wp-admin, shown only to people who may edit the site.
 *
 * Deliberately not styled as an alert: it is not a warning, it is a door. A
 * washed panel with real buttons, above the course list rather than below it,
 * because somebody who can edit the site is here to edit the site. */
.dee-manage {
  background: var(--dee-blue-wash); border: 1px solid var(--dee-blue-tint);
  border-radius: var(--dee-r-lg); padding: var(--dee-s6);
  margin-bottom: var(--dee-s7);
}
.dee-manage__head h2 { font-size: var(--dee-fs-lg); margin-bottom: var(--dee-s2); }
.dee-manage__head p { margin: 0; color: var(--dee-ink-soft); font-size: var(--dee-fs-sm); max-width: 52ch; }
.dee-manage__list {
  list-style: none; margin: var(--dee-s5) 0 0; padding: 0;
  display: flex; flex-wrap: wrap; gap: var(--dee-s3);
}
.dee-manage__list a { background: var(--dee-surface); }
.dee-manage__all { margin: var(--dee-s4) 0 0; font-size: var(--dee-fs-xs); }
.dee-manage__all a { color: var(--dee-ink-soft); }

/* Widerruf / Stornierung ------------------------------------------------- */
.dee-widerruf { margin-top: var(--dee-s8); padding-top: var(--dee-s7); border-top: 1px solid var(--dee-rule); }
.dee-widerruf > h2 { font-size: var(--dee-fs-xl); }
.dee-widerruf__booking {
  background: var(--dee-blue-wash); border: 1px solid var(--dee-blue-tint);
  border-radius: var(--dee-r-lg); padding: var(--dee-s6);
  margin-bottom: var(--dee-s6);
}
.dee-widerruf__booking h3 { font-size: var(--dee-fs-lg); margin-bottom: var(--dee-s4); }
.dee-widerruf__booking .dee-speclist { margin-bottom: var(--dee-s4); border-top: 0; }
.dee-widerruf__verdict { margin: 0; font-weight: 600; }
.dee-form--widerruf .dee-form__grid { margin-bottom: var(--dee-s5); }

/* Top bar: language switcher with flags ---------------------------------- */
.dee-announce__inner { justify-content: space-between; }
.dee-announce__text { margin: 0; }
.dee-announce .dee-langs { margin-left: auto; }
.dee-langs__item {
  color: rgba(255,255,255,.72);
  gap: var(--dee-s2);
  min-height: 32px;
  padding: 0 .55rem;
}
.dee-langs__item:hover { color: #fff; background: rgba(255,255,255,.1); }
.dee-langs__item.is-current { color: #fff; background: rgba(255,255,255,.14); }
.dee-flag {
  width: 21px; height: 15px; border-radius: 2px; flex: none;
  /* A hairline keeps the white of the Union Flag from bleeding into the bar. */
  box-shadow: 0 0 0 1px rgba(255,255,255,.35);
}
.dee-langs__code { font-size: var(--dee-fs-xs); font-weight: 600; letter-spacing: .06em; }

@media (max-width: 720px) {
  .dee-announce__inner { gap: var(--dee-s3); }
  .dee-announce__cta { display: none; }
  .dee-announce__text { font-size: var(--dee-fs-xs); }
}

/* The rooms ---------------------------------------------------------------
 *
 * Six equal tiles, three across, two rows.
 *
 * This replaces a 2x2 lead image with five singles beside it, and the reason
 * is arithmetic rather than taste. Full-bleed, three columns, a square lead
 * spanning two of them is 926px tall on its own; the band came to 1,500px of
 * a 10,200px page — fifteen per cent of the homepage spent on six
 * photographs of empty rooms. The lead treatment was defended here on the
 * grounds that a uniform grid "reads as a stock library". That argument was
 * about ELEVEN tiles. At six it is wrong in the other direction: the
 * emphasis was not doing enough work to be worth eight hundred pixels, and
 * the picture that got the weight is a classroom with a monitor in the
 * foreground, which is not the frame you would choose to enlarge.
 *
 * 16:10 rather than 4:3, so two rows come to 580px instead of 700 — and
 * because these are wide rooms shot on a phone, a wider crop loses ceiling
 * rather than content.
 */
.dee-rooms__title { margin: var(--dee-s2) 0 var(--dee-s3); }
.dee-rooms__lead {
  max-width: var(--dee-prose); margin: 0 0 var(--dee-s6);
  color: var(--dee-ink-soft); font-size: var(--dee-fs-lg); line-height: 1.55;
}
/*
 * Three columns and six pictures: two full rows, no orphan. The old note
 * here worried about a sixth tile hanging alone on a third row — that was a
 * consequence of the lead spanning four cells, and it goes away with it.
 */
.dee-rooms__grid {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--dee-s3);
}
.dee-rooms__item { margin: 0; position: relative; overflow: hidden; border-radius: var(--dee-r-lg); }
.dee-rooms__item img {
  display: block; width: 100%; height: 100%; object-fit: cover;
  aspect-ratio: 16 / 10;
  /*
   * Lifted, not muted. The old values pulled saturation DOWN on photographs
   * that are already flat — interiors, overcast daylight, a phone sensor —
   * which is a treatment that works on rich imagery and makes ordinary
   * imagery look like a scanned brochure. A little more colour and a little
   * more light is the difference between "empty room" and "bright room".
   */
  filter: saturate(1.04) contrast(1.05) brightness(1.04);
  transition: transform .5s var(--dee-ease);
}
.dee-rooms__item:hover img { transform: scale(1.03); }

@media (prefers-reduced-motion: reduce) {
  .dee-rooms__item img { transition: none; }
  .dee-rooms__item:hover img { transform: none; }
}
@media (max-width: 980px) {
  .dee-rooms__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 560px) {
  /* Still two up. Six stacked full-width photographs is four screens of
     scrolling to say one thing, and the thing is "the rooms are ordinary and
     bright", which one screen says perfectly well. */
  .dee-rooms__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--dee-s2); }
  .dee-rooms__item img { aspect-ratio: 4 / 3; }
}

/* =========================================================================
   NAVIGATION SPLIT & UI PASS

   The main navigation now carries the offer and nothing else. Everything a
   visitor looks for *after* they have decided — about, team, contact, phone,
   language — sits in the service strip above the header. Two consequences
   worth stating: the four course products get the horizontal room they were
   competing for, and the strip that was previously one announcement now earns
   its height by carrying real navigation.
   ====================================================================== */

/* Service strip ----------------------------------------------------------- */
.dee-announce__inner {
  justify-content: space-between;
  gap: var(--dee-s5);
  padding-block: var(--dee-s2);
  min-height: 42px;
  flex-wrap: nowrap;
}
.dee-announce__lead,
.dee-announce__utility {
  display: flex; align-items: center; gap: var(--dee-s4);
  min-width: 0;
}
.dee-announce__lead { flex: 1 1 auto; }
.dee-announce__utility { flex: none; }

.dee-utility__list {
  display: flex; align-items: center; gap: var(--dee-s4);
  list-style: none; margin: 0; padding: 0;
}
.dee-utility__list a,
.dee-announce__tel {
  display: inline-flex; align-items: center; gap: var(--dee-s2);
  /* 4.6:1 on --dee-navy-deep. The strip is small text on a dark ground, which
     is exactly where a "subtle" grey stops being readable. */
  color: rgba(255,255,255,.78);
  text-decoration: none; font-size: var(--dee-fs-xs); white-space: nowrap;
  transition: color .16s var(--dee-ease);
}
.dee-utility__list a:hover,
.dee-announce__tel:hover,
.dee-utility .current-menu-item > a { color: #fff; }
.dee-announce__tel { font-variant-numeric: tabular-nums; }
.dee-announce__utility .dee-langs { margin-left: var(--dee-s2); padding-left: var(--dee-s4); border-left: 1px solid rgba(255,255,255,.18); }

/* The drawer copy of the service links — desktop never sees it. */
.dee-nav__service { display: none; }

@media (max-width: 1200px) {
  /*
   * Below this the strip would wrap to three lines, so the service links and
   * the phone number leave it — and reappear inside the burger menu, which is
   * why .dee-nav__service exists rather than the links simply vanishing.
   */
  .dee-utility, .dee-announce__tel { display: none; }
  .dee-announce__inner { flex-wrap: wrap; justify-content: center; }

  .dee-nav__service {
    display: block;
    margin-top: var(--dee-s7);
    padding-top: var(--dee-s5);
    border-top: 1px solid var(--dee-rule);
  }
  .dee-nav__servicehead {
    margin: 0 0 var(--dee-s4);
    font-size: var(--dee-fs-xs); letter-spacing: .12em; text-transform: uppercase;
    color: var(--dee-ink-faint);
  }
  .dee-nav__servicelist {
    display: flex; flex-direction: column; gap: var(--dee-s4);
    list-style: none; margin: 0 0 var(--dee-s5); padding: 0;
  }
  .dee-nav__servicelist a { font-size: var(--dee-fs-base); }
  .dee-nav__tel {
    display: inline-block; font-family: var(--dee-display); font-weight: 700;
    font-size: var(--dee-fs-lg); color: var(--dee-navy); text-decoration: none;
  }
}
@media (max-width: 560px) {
  /* The date is the reason the strip exists; the CTA repeats in the hero. */
  .dee-announce__cta { display: none; }
}

/* Header depth on scroll --------------------------------------------------
   The header is translucent over paper. Sitting on top of a photograph with
   no shadow, it read as part of the picture; the class is applied by JS only
   once the page has actually scrolled, so the resting state stays flat. */
.dee-header { transition: box-shadow .2s var(--dee-ease), background-color .2s var(--dee-ease); }
.dee-header.is-stuck {
  background: rgba(251,250,248,.95);
  box-shadow: 0 1px 0 var(--dee-rule), 0 10px 30px -18px rgba(9,24,44,.45);
}

/* Focus — visible, and only for keyboards --------------------------------- */
:focus-visible {
  outline: 3px solid var(--dee-blue);
  outline-offset: 2px;
  border-radius: 2px;
}
.dee-announce :focus-visible { outline-color: #fff; }

/* Level cards ------------------------------------------------------------
   These were columns separated by hairlines — correct as an editorial table,
   wrong as the primary way into five product pages. They are cards now, and
   the whole card is the hit area rather than the small link at its foot. */
.dee-level {
  position: relative;
  padding: var(--dee-s6) var(--dee-s5);
  background: var(--dee-surface);
  border: 1px solid var(--dee-rule);
  border-radius: var(--dee-r-lg);
  border-top-width: 3px;
  border-top-color: var(--dee-rule-strong);
  transition: transform .22s var(--dee-ease), box-shadow .22s var(--dee-ease), border-color .22s var(--dee-ease);
}
.dee-level:hover {
  transform: translateY(-3px);
  box-shadow: 0 18px 38px -24px rgba(9,24,44,.42);
  border-top-color: var(--dee-blue);
}
.dee-level.is-featured { border-top-color: var(--dee-blue); box-shadow: var(--dee-shadow); }
/* The title link is stretched over the card, so the meta list stays selectable. */
.dee-level__title a::after { content: ""; position: absolute; inset: 0; border-radius: inherit; }
/*
 * The card's "Kurs ansehen" is a <span aria-hidden="true">, not a link — the
 * whole card is the click target, via .dee-level__title a::after stretched to
 * inset: 0. The span only has to be PAINTED above that overlay, which is what
 * the z-index is for.
 *
 * It must never RECEIVE the click. With pointer-events left at auto it sat on
 * top of the overlay and swallowed every press, so the one element on the card
 * that looks like a button was the only dead spot on it — five cards on the
 * home page and five more on /abendkurse/, at every width. Reported by the
 * client as "a lot of buttons not working", and they were right.
 */
.dee-level__link { position: relative; z-index: 1; pointer-events: none; }
@media (prefers-reduced-motion: reduce) {
  .dee-level { transition: none; }
  .dee-level:hover { transform: none; }
}

/* Course and service cards get the same behaviour ------------------------- */
.dee-card, .dee-service {
  transition: transform .22s var(--dee-ease), box-shadow .22s var(--dee-ease);
}
.dee-card:hover, .dee-service:hover {
  transform: translateY(-3px);
  box-shadow: 0 18px 38px -24px rgba(9,24,44,.38);
}
@media (prefers-reduced-motion: reduce) {
  .dee-card, .dee-service { transition: none; }
  .dee-card:hover, .dee-service:hover { transform: none; }
}

/* Section rhythm ---------------------------------------------------------
   The alternating band was #f4f2ee against #fbfaf8 — a two-percent shift that
   read as a rendering artefact rather than as a change of subject. It now has
   a hairline top and bottom so the boundary is deliberate. */
.dee-section--alt {
  border-top: 1px solid var(--dee-rule);
  border-bottom: 1px solid var(--dee-rule);
}

/* Mobile action bar ------------------------------------------------------
   On a phone the two things a visitor does are call and enrol, and both were
   a scroll away at every point on a long page. The floating WhatsApp circle
   is replaced by this on small screens — two circles and a bar competing in
   the same corner is worse than either alone. */
/*
 * The fixed bar is the CAMPAIGN pages' pattern, and only theirs.
 *
 * It used to be the mobile pattern for the whole site, with the floating
 * WhatsApp pill hidden below 720px so the two could not compete in the same
 * corner. That was a defensible call and it had one consequence nobody
 * traced: the client asked for "a reaction like this" over a competitor's
 * page — three floating buttons down the right edge, on a PHONE — we built
 * it, and he could never see it, because on a phone he got the bar instead.
 * He came back weeks later saying nothing had been done.
 *
 * So the two patterns are split by page rather than by width. An ordinary
 * page gets the floating stack at every size; a landing page gets the bar at
 * every size, because there the bar IS the page's call to action and a
 * campaign page has exactly one thing to ask for.
 */
.dee-actionbar { display: none; }

/*
 * On a phone the docked bar replaces the floating discs — on every page now,
 * not only the campaign ones.
 *
 * The discs are a fixed 52px column down the middle of the right edge, and
 * measured across four pages at four phone widths, TWELVE of the sixteen
 * combinations had text behind them: the fee on the hero card, the Google
 * rating, four columns of the price table — and "Kursplatz sichern" and
 * "Kostenlos einstufen lassen", which are buttons. A disc over a button is
 * not an aesthetic complaint, it is a mis-tap.
 *
 * A docked bar cannot cover anything, because the page reserves its height
 * below. The discs keep the desktop, where they sit in the margin beside the
 * measure and cover nothing.
 */
@media (max-width: 720px) {
  .dee-actionbar {
    display: grid; grid-template-columns: 1fr 1fr;
    position: fixed; inset: auto 0 0 0; z-index: 120;
    background: rgba(255,255,255,.97);
    border-top: 1px solid var(--dee-rule);
    box-shadow: 0 -8px 30px -20px rgba(9,24,44,.5);
    padding: var(--dee-s3) var(--dee-s4);
    padding-bottom: calc(var(--dee-s3) + env(safe-area-inset-bottom, 0px));
    gap: var(--dee-s3);
  }
  .dee-actionbar .dee-btn { width: 100%; justify-content: center; }
  /* Room for the bar, so it never covers the last line of the footer. */
  body { padding-bottom: 4.75rem; }
}

/* -------------------------------------------------------------------------
   The drawer must escape the header.

   `backdrop-filter` on .dee-header makes it a containing block for every
   `position: fixed` descendant — a rule that surprises almost everyone the
   first time. The nav drawer is such a descendant, so instead of covering the
   viewport it was clipped to the height of the header: about 70px of a
   full-screen menu, with the rest of the links simply not on screen.

   Below the drawer breakpoint the blur is dropped and the header goes solid.
   Nothing is lost visually — the effect exists to let paper show through a
   translucent bar on a wide screen — and the drawer gets its viewport back.
   ---------------------------------------------------------------------- */
@media (max-width: 1200px) {
  .dee-header {
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
    background: var(--dee-paper);
  }
  .dee-header.is-stuck { background: var(--dee-paper); }

  /* The drawer sits above the fixed action bar, not behind it. */
  .dee-nav { z-index: 130; }
}

/* -------------------------------------------------------------------------
   Two mobile corrections found by opening the drawer on a phone.
   ---------------------------------------------------------------------- */
@media (max-width: 720px) {
  /* The action bar is for browsing, not for navigating a menu. With the drawer
     open it covered the last two service links and offered a third and fourth
     competing action on a screen already showing a list of them. */
  body:has(.dee-nav[data-open="true"]) .dee-actionbar { display: none; }

  /* Belt and braces for engines without :has() — the drawer scrolls clear. */
  .dee-nav { padding-bottom: 6rem; }

  /*
   * A single-course page's hero already carries its own "Jetzt anmelden"
   * and "Kostenlos einstufen lassen" pair — moved up there specifically so
   * a phone visitor had something tappable without a scroll — and on
   * common phone heights that pair sits right where the fixed bar's 61px
   * strip lives, so the bar landed on top of the exact buttons it exists
   * to be a substitute for. Same call as the drawer above: a fixed bar
   * over a page's own primary CTA is worse than either alone, and here the
   * hero CTA is the one that already knows which course it is for.
   */
  body:has(.dee-chero__cta) .dee-actionbar { display: none; }
}

@media (max-width: 980px) {
  /*
   * The headline leads on a phone.
   *
   * The hero photograph used to be hoisted above the copy on narrow screens,
   * decided when the media column was a picture and nothing else. It now
   * carries the fact card as well, so hoisting it pushed the H1 — the largest
   * contentful paint and the sentence that says what this school does — below
   * a photograph and a five-row table. Order restored: say it, then show it.
   */
  .dee-hero__media:has(.dee-figure) { order: 0; }
}

/* =========================================================================
   ART DIRECTION PASS

   The system was correct and unremarkable: right typography, right spacing,
   nothing that made anyone look twice. Everything below adds *depth* — ground
   that is not flat, edges that are not all 1px, and one oversized editorial
   device per screen — without touching the structure or the contrast ratios.
   ====================================================================== */

/* Section heads: the numeral becomes the device ---------------------------
   It was a 17px blue number in front of a label, which is a footnote. As an
   outlined display figure in its own column it does the job a magazine
   department number does: it tells you where you are in a long page before
   you have read a word of it. */
.dee-section__head {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  column-gap: clamp(1rem, 2.2vw, 2.75rem);
  align-items: start;
  max-width: none;
}
.dee-section__headtext { max-width: 46rem; }

.dee-section__n {
  font-family: var(--dee-display);
  font-weight: 800;
  font-size: clamp(2.5rem, 1.5rem + 3.2vw, 4.75rem);
  line-height: .78;
  letter-spacing: -0.055em;
  /* Outlined, so it sits behind the headline in the hierarchy while still
     being large. A solid figure this size would compete with the H2. */
  color: transparent;
  -webkit-text-stroke: 1.5px var(--dee-rule-strong);
  text-stroke: 1.5px var(--dee-rule-strong);
  user-select: none;
  padding-top: .06em;
}
.dee-section__n::after { content: none; }
/* Firefox before 116 and every engine without text-stroke gets a solid tone
   at the same value — quieter than the headline, still legible. */
@supports not ((-webkit-text-stroke: 1px currentColor) or (text-stroke: 1px currentColor)) {
  .dee-section__n { color: var(--dee-rule-strong); }
}
.dee-section__head--row { display: grid; align-items: end; }
.dee-section__head--row > :last-child { align-self: end; }
@media (max-width: 720px) {
  .dee-section__head { grid-template-columns: 1fr; row-gap: var(--dee-s3); }
  .dee-section__n { font-size: 2.5rem; }
}

/* The eyebrow gets its rule back, now that the numeral has left it ---------- */
.dee-section__headtext .dee-eyebrow {
  display: flex; align-items: center; gap: var(--dee-s3);
}
.dee-section__headtext .dee-eyebrow::before {
  content: ""; width: 1.75rem; height: 2px; flex: none;
  background: var(--dee-blue);
}

/* Hero ground -------------------------------------------------------------
   Two very wide, very soft washes. The page was one flat paper tone from top
   to bottom; this gives the first screen a horizon without introducing a
   coloured band that would have to be justified everywhere else. */
.dee-hero {
  position: relative;
  background:
    radial-gradient(58rem 40rem at 88% -20%, var(--dee-blue-wash) 0%, rgba(238,244,251,0) 62%),
    radial-gradient(44rem 32rem at -8% 8%, rgba(244,242,238,.85) 0%, rgba(244,242,238,0) 60%);
}

/* The photograph sits on a block, not on the page -------------------------- */
.dee-hero__media.has-photo { position: relative; isolation: isolate; }
.dee-hero__media.has-photo::before {
  content: "";
  position: absolute;
  /* Down and to the LEFT, into the column gap — offsetting right would push
     past the page edge and hand every visitor a horizontal scrollbar. */
  inset: 2rem 2rem -1.25rem -1.25rem;
  border-radius: var(--dee-r-lg);
  background: linear-gradient(150deg, var(--dee-blue-tint), var(--dee-paper-deep) 70%);
  z-index: 0;
}
.dee-hero__media.has-photo .dee-figure { position: relative; z-index: 1; }
.dee-hero__media.has-photo .dee-herofacts { z-index: 2; }
@media (max-width: 980px) {
  /* The offset block reads as a mistake once the columns stack. */
  .dee-hero__media.has-photo::before { display: none; }
}

/* The fact card gets a masthead ------------------------------------------- */
.dee-herofacts {
  padding: 0;
  overflow: hidden;
  box-shadow: 0 1px 2px rgba(20,32,47,.05), 0 24px 48px -30px rgba(9,24,44,.55);
}
.dee-herofacts__list { padding: 0 var(--dee-s6); }
.dee-herofacts__row.is-lead {
  margin-inline: calc(var(--dee-s6) * -1);
  padding: var(--dee-s5) var(--dee-s6);
  background: var(--dee-navy);
  border-bottom: 0;
}
.dee-herofacts__row.is-lead dt { color: rgba(255,255,255,.68); }
.dee-herofacts__row.is-lead dd { color: #fff; }
.dee-herofacts__note { padding: var(--dee-s4) var(--dee-s6) var(--dee-s6); margin: 0; }

/* Buttons: weight, not decoration ----------------------------------------- */
.dee-btn {
  transition: transform .16s var(--dee-ease), box-shadow .16s var(--dee-ease),
              background-color .16s var(--dee-ease), border-color .16s var(--dee-ease);
}
.dee-btn--primary,
.dee-btn--dark {
  box-shadow: inset 0 1px 0 rgba(255,255,255,.14), 0 10px 22px -14px rgba(0,33,71,.85);
}
.dee-btn--primary:hover,
.dee-btn--dark:hover { transform: translateY(-1px); box-shadow: 0 16px 28px -14px rgba(11,106,196,.75); }
.dee-btn--wa:hover { transform: translateY(-1px); }
@media (prefers-reduced-motion: reduce) {
  .dee-btn { transition: none; }
  .dee-btn:hover { transform: none; }
}

/* Feature strip: the icons become chips ------------------------------------ */
.dee-feature .dee-icon {
  box-sizing: content-box;
  padding: .5rem;
  border-radius: var(--dee-r-full);
  background: var(--dee-blue-wash);
  color: var(--dee-blue-dark);
}

/* Alternating band: warm, not grey ---------------------------------------- */
.dee-section--alt { background: #f5f2ec; }

/* Testimonials: a rule that starts in brand blue -------------------------- */
.dee-quote {
  border-top: 0;
  background-image: linear-gradient(to right, var(--dee-blue) 0 3rem, var(--dee-rule-strong) 3rem 100%);
  background-size: 100% 2px;
  background-repeat: no-repeat;
  background-position: top left;
}

/* Closing band and footer ------------------------------------------------- */
.dee-band {
  background:
    radial-gradient(40rem 26rem at 12% -30%, rgba(22,134,239,.30), transparent 65%),
    linear-gradient(135deg, var(--dee-navy) 0%, var(--dee-navy-deep) 70%);
}
.dee-footer { border-top: 3px solid var(--dee-blue); }
.dee-footer__trust {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: var(--dee-s4);
  padding-bottom: var(--dee-s6);
  margin-bottom: var(--dee-s6);
  border-bottom: 1px solid rgba(255, 255, 255, .14);
}
.dee-footer__trust-item {
  display: flex; align-items: center; gap: var(--dee-s3);
  font-size: var(--dee-fs-sm); font-weight: 500;
  color: rgba(255, 255, 255, .9);
  /* Now a link: no underline at rest, a clear one on hover and on focus. */
  text-decoration: none;
  transition: color .2s var(--dee-ease);
}
.dee-footer__trust-item:hover { color: var(--dee-on-accent); }
.dee-footer__trust-item:hover span:last-child { text-decoration: underline; text-underline-offset: 3px; }
@media (prefers-reduced-motion: reduce) { .dee-footer__trust-item { transition: none; } }
/*
 * The icon keeps its own weight against the navy. --dee-blue is the brand
 * blue and sits at roughly 3:1 on the footer ground, which is fine for a
 * decorative glyph beside its own label but would not be for the label.
 */
.dee-footer__trust-icon { display: flex; flex: none; color: var(--dee-blue); }
.dee-footer__trust-icon .dee-icon { width: 20px; height: 20px; }
.dee-footer__mark { display: block; margin-bottom: var(--dee-s4); }
/*
 * The logo keeps its own colours, on a white chip.
 *
 * `filter: brightness(0) invert(1)` was the obvious way to reverse one asset
 * out on a dark ground, and it destroys this particular mark: the "D" is a
 * navy outline around a filled blue counter, and silhouetting merges the two
 * into a solid blob — the same failure the 16px favicon had, for the same
 * reason. A chip costs nothing and keeps the logo legible.
 */
.dee-footer__mark img {
  height: 40px; width: auto; max-width: 150px; object-fit: contain;
  background: #fff; padding: .5rem .7rem; border-radius: var(--dee-r);
  /* Explicit: a generic `.dee-footer img { filter: … }` further up the file
     still silhouettes this to a white rectangle otherwise — which is exactly
     what it looked like until the preview showed it. */
  filter: none;
}

/* =========================================================================
   FORMS, NOTICES, CONSENT
   ====================================================================== */

.dee-form { margin: 0; }
.dee-form__grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  gap: var(--dee-s4) var(--dee-s5);
}
.dee-form__field { margin: 0; display: flex; flex-direction: column; gap: var(--dee-s2); }
.dee-form__field.is-wide { grid-column: 1 / -1; }
.dee-form__field label {
  font-size: var(--dee-fs-sm); font-weight: 600; color: var(--dee-ink);
}
.dee-form__req { color: var(--dee-err); margin-left: .15em; }
.dee-form__hint { font-size: var(--dee-fs-xs); color: var(--dee-ink-faint); }

.dee-form input[type="text"], .dee-form input[type="email"],
.dee-form input[type="tel"], .dee-form input[type="number"],
.dee-form textarea, .dee-form select {
  width: 100%; font: inherit; font-size: var(--dee-fs-base);
  color: var(--dee-ink); background: var(--dee-surface);
  border: 1px solid var(--dee-rule-strong); border-radius: var(--dee-r);
  padding: .7rem .85rem;
  /* 16px minimum, or iOS zooms the whole page on focus and the visitor loses
     their place in the form they were halfway through. */
  min-height: 2.85rem;
  transition: border-color .16s var(--dee-ease), box-shadow .16s var(--dee-ease);
}
.dee-form textarea { min-height: 7rem; resize: vertical; line-height: 1.55; }
.dee-form :is(input, textarea, select):focus {
  border-color: var(--dee-blue);
  box-shadow: 0 0 0 3px var(--dee-blue-wash);
  outline: none;
}
.dee-form :is(input, textarea, select):focus-visible { outline: none; }

.dee-form__check, .dee-form__consent label {
  display: flex; align-items: flex-start; gap: var(--dee-s3);
  font-weight: 400; font-size: var(--dee-fs-sm); line-height: 1.5;
  color: var(--dee-ink-soft); cursor: pointer;
}
.dee-form__check input, .dee-form__consent input {
  /* 20px, not the browser's 13px — a consent checkbox that is hard to hit is
     a consent checkbox somebody ticks by accident. */
  width: 1.25rem; height: 1.25rem; margin: .1rem 0 0; flex: none; accent-color: var(--dee-navy);
}
.dee-form__consent { margin: var(--dee-s5) 0; }
.dee-form__note { margin: var(--dee-s4) 0 0; font-size: var(--dee-fs-sm); color: var(--dee-ink-faint); }

/* The honeypot. Off-screen rather than display:none — some bots skip anything
   that is not rendered, and this needs to look real to them. */
.dee-form__hp {
  position: absolute !important; width: 1px; height: 1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap;
}

/* Notices ---------------------------------------------------------------- */
.dee-note {
  border-radius: var(--dee-r); padding: var(--dee-s5);
  margin-bottom: var(--dee-s5); border-left: 4px solid;
}
.dee-note strong { display: block; margin-bottom: var(--dee-s2); }
.dee-note p, .dee-note ul { margin: 0; }
.dee-note ul { padding-left: 1.1rem; }
.dee-note--ok  { background: #eaf6ee; border-color: var(--dee-ok); color: #12401f; }
.dee-note--err { background: #fdeceb; border-color: var(--dee-err); color: #6d1512; }
.dee-note:focus { outline: 3px solid var(--dee-blue); outline-offset: 2px; }

/* Consent-gated embeds ---------------------------------------------------- */
.dee-consent {
  background: var(--dee-blue-wash);
  border: 1px solid var(--dee-blue-tint);
  border-radius: var(--dee-r-lg);
  padding: var(--dee-s7) var(--dee-s6);
  text-align: center;
}
.dee-consent__title { margin: 0 0 var(--dee-s2); font-size: var(--dee-fs-lg); }
.dee-consent__text { margin: 0 0 var(--dee-s5); font-size: var(--dee-fs-sm); color: var(--dee-ink-soft); }
.dee-consent__fallback { margin: var(--dee-s4) 0 0; font-size: var(--dee-fs-sm); }
.dee-consent.is-loaded { padding: 0; border: 0; background: none; overflow: hidden; }
.dee-consent__frame {
  display: block; width: 100%; aspect-ratio: 16 / 9; min-height: 320px;
  border: 0; border-radius: var(--dee-r-lg);
}

/* Search ------------------------------------------------------------------ */
.dee-search { display: flex; gap: var(--dee-s3); max-width: 32rem; }
.dee-search input[type="search"] {
  flex: 1; font: inherit; font-size: var(--dee-fs-base);
  border: 1px solid var(--dee-rule-strong); border-radius: var(--dee-r);
  padding: .7rem .85rem; min-height: 2.85rem; background: var(--dee-surface);
}
.dee-search input[type="search"]:focus {
  border-color: var(--dee-blue); box-shadow: 0 0 0 3px var(--dee-blue-wash); outline: none;
}

/* =========================================================================
   COMPOSITION PASS

   Read as a whole page rather than as a screen at a time, the homepage was
   eight consecutive light slabs at identical width with identical alignment
   and an identical square photograph on one side. Each screen looked fine.
   The scroll had no spine.

   Three structural moves, no new content:
     1. one dark full-bleed block, on the school's main product
     2. one edge-to-edge image band, for the rooms
     3. the fact strip lifted into a card that overlaps the hero
   ====================================================================== */

/* 1 — The flagship block --------------------------------------------------- */
.dee-flagship {
  padding: 0;
  background:
    radial-gradient(46rem 30rem at 8% -20%, rgba(22,134,239,.26), transparent 62%),
    linear-gradient(140deg, var(--dee-navy) 0%, var(--dee-navy-deep) 72%);
  color: rgba(255,255,255,.82);
  border-block: 0;
}
.dee-flagship__inner {
  display: grid;
  grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr);
  align-items: center;
}
.dee-flagship__copy {
  /* Aligns with .dee-wrap on the left, breathes on the right. The max() keeps
     it flush with every other section's left edge at any viewport width. */
  padding-inline: max(1.25rem, calc((100vw - var(--dee-wrap)) / 2)) clamp(2rem, 4vw, 4.5rem);
  padding-block: var(--dee-s9);
}
.dee-flagship__media { align-self: stretch; }
.dee-flagship__media .dee-figure,
.dee-flagship__media .dee-illwrap { height: 100%; }
.dee-flagship__media img {
  height: 100%; width: 100%; object-fit: cover;
  min-height: 30rem;
  /* Square off the edge that meets the viewport; keep the inner corner. */
  border-radius: var(--dee-r-lg) 0 0 var(--dee-r-lg);
  aspect-ratio: auto;
}
.dee-flagship__media .dee-figure::after { border-radius: var(--dee-r-lg) 0 0 var(--dee-r-lg); }

/* Type and rules invert on the dark ground. */
.dee-flagship .dee-section__head { margin-bottom: var(--dee-s5); }
.dee-flagship h2 { color: #fff; }
.dee-flagship .dee-lead { color: rgba(255,255,255,.80); }
.dee-flagship .dee-eyebrow { color: rgba(255,255,255,.62); }
.dee-flagship .dee-section__n { -webkit-text-stroke-color: rgba(255,255,255,.30); }
@supports not ((-webkit-text-stroke: 1px currentColor) or (text-stroke: 1px currentColor)) {
  .dee-flagship .dee-section__n { color: rgba(255,255,255,.30); }
}
.dee-flagship .dee-speclist > div { border-color: rgba(255,255,255,.16); }
.dee-flagship .dee-speclist dt { color: rgba(255,255,255,.62); }
.dee-flagship .dee-speclist dd { color: #fff; }

@media (max-width: 900px) {
  .dee-flagship__inner { grid-template-columns: 1fr; }
  .dee-flagship__copy { padding-block: var(--dee-s8) var(--dee-s7); }
  .dee-flagship__media img { min-height: 18rem; border-radius: 0; }
  .dee-flagship__media .dee-figure::after { border-radius: 0; }
}

/* 2 — The rooms, edge to edge ---------------------------------------------- */
.dee-rooms__grid {
  /* Break out of .dee-wrap to the viewport, keeping a hair of margin so the
     images never touch a phone's bezel. */
  width: calc(100vw - 2.5rem);
  max-width: none;
  margin-left: calc(50% - 50vw + 1.25rem);
}
@media (min-width: 1600px) {
  /* Past this the pictures become wallpaper rather than evidence. */
  .dee-rooms__grid { width: min(calc(100vw - 2.5rem), 1600px); margin-left: calc(50% - min(50vw - 1.25rem, 800px)); }
}

/* 3 — The fact strip, lifted ---------------------------------------------- */
.dee-features {
  position: relative;
  z-index: 2;
  margin-top: calc(var(--dee-s7) * -1);
  background: var(--dee-surface);
  border: 1px solid var(--dee-rule);
  border-radius: var(--dee-r-lg);
  box-shadow: 0 1px 2px rgba(20,32,47,.04), 0 26px 50px -34px rgba(9,24,44,.5);
  overflow: hidden;
}
.dee-features .dee-feature { padding-block: var(--dee-s5); }
@media (max-width: 720px) {
  .dee-features { margin-top: calc(var(--dee-s5) * -1); }
}

/*
 * The strip reused OUTSIDE the hero — the course hub places it under a
 * plain paragraph, not a dark hero panel, so the "lifted card" negative
 * margin above has nothing to overlap into and would instead pull the
 * white card up over the text before it. This wrapper cancels exactly
 * that offset (mirrors the mobile breakpoint's own -s5 at ≤720px) so the
 * card keeps its shadow-and-radius look without colliding with the copy.
 */
.dee-hub__facts { padding-top: var(--dee-s7); }
@media (max-width: 720px) {
  .dee-hub__facts { padding-top: var(--dee-s5); }
}

/* 4 — The profile block — REMOVED -------------------------------------------
   `.dee-split--portrait` and `.dee-split__caption` were written for the "why
   DEE" section when it was a copy column beside a 4:5 portrait. That layout
   is gone: the section's height was being set by the photograph rather than
   by anything it said, and the same person now appears as an 84px byline
   above a three-column grid of reasons.

   Deleted rather than left in place. Dead selectors are the reason a
   stylesheet becomes a place nobody dares change anything in, and these two
   matched nothing at all. The byline rules live with the rest of the density
   pass at the end of this file.
   ------------------------------------------------------------------------ */

/* 5 — Service cards with presence ------------------------------------------
   Two small cards adrift in a full-width band read as an afterthought; these
   are the school's second and third revenue lines. */
.dee-services { gap: var(--dee-s5); }
.dee-service {
  padding: var(--dee-s7) var(--dee-s6);
  background: var(--dee-surface);
  border: 1px solid var(--dee-rule);
  border-top: 3px solid var(--dee-blue);
  border-radius: var(--dee-r-lg);
  display: flex; flex-direction: column; gap: var(--dee-s3);
}
.dee-service__icon {
  display: inline-flex; width: 3rem; height: 3rem; margin-bottom: var(--dee-s2);
  align-items: center; justify-content: center;
  border-radius: var(--dee-r-full); background: var(--dee-blue-wash); color: var(--dee-blue-dark);
}
.dee-service__title { font-size: var(--dee-fs-xl); margin: 0; }
.dee-service__text { margin: 0; color: var(--dee-ink-soft); line-height: 1.6; }
.dee-service__link { margin-top: auto; padding-top: var(--dee-s4); font-weight: 600; color: var(--dee-blue-dark); }

/* 6 — Hero balance --------------------------------------------------------
   The fact card was the full width of the media column and covered more than
   half the photograph, which made the picture read as a texture behind a
   table rather than as a photograph. Inset from the left and lifted off the
   bottom edge, it becomes a card ON a picture — and the picture survives. */
@media (min-width: 1101px) {
  .dee-hero__media.has-photo .dee-herofacts {
    left: 14%;
    right: var(--dee-s5);
    bottom: var(--dee-s5);
  }
  .dee-hero__media.has-photo .dee-figure--hero img { aspect-ratio: 3 / 4; }
}

/* The block behind the photograph, made visible.
   At a 2rem inset it showed as a 12px sliver nobody would read as intentional. */
.dee-hero__media.has-photo::before {
  inset: 3.25rem 3.25rem -1.5rem -2rem;
  background: linear-gradient(150deg, var(--dee-blue-tint), var(--dee-paper-deep) 72%);
}

/* =========================================================================
   PASS — THE LIGHT HERO: BRIGHT, HUMAN, PHOTO-LED

   This replaces a dark hero, and the reasoning for the reversal is worth
   keeping. The dark version fixed a real problem — the page was one
   undifferentiated light ground with no emphasis anywhere — but it fixed it
   with weight rather than with warmth, and a language school is not a
   fintech. What the first screen has to communicate is that a person will
   teach you and other people will be in the room. Navy does not say that.
   Photography of learners does.

   So the emphasis stays and the means change: the hero is light, the type is
   large, and the photograph is the largest object on the screen, in its own
   colours rather than graded into the palette. The page still has a spine —
   the flagship band and the closing band remain dark — but the top of it is
   now the warmest part of the site instead of the coldest.
   ====================================================================== */

:root {
  --dee-fs-3xl: clamp(2.25rem, 1.4rem + 3.4vw, 4.25rem);
  /*
   * 5.25rem. German is the constraint: "Sicher sprechen." is sixteen
   * characters with no short words in it, and past this it breaks across two
   * lines inside a headline that already declares its own line breaks. A
   * display size you have to fight the language to use is the wrong size.
   */
  --dee-fs-4xl: clamp(2.625rem, 1.35rem + 4.6vw, 5.25rem);

  --dee-shadow-card: 0 2px 4px -2px rgba(20, 32, 47, .06),
                     0 12px 28px -14px rgba(20, 32, 47, .14);
  --dee-shadow-float: 0 4px 10px -4px rgba(12, 26, 45, .10),
                      0 30px 60px -28px rgba(12, 26, 45, .30);
}

/* -------------------------------------------------------------------------
   1  The field
   ---------------------------------------------------------------------- */

.dee-hero {
  position: relative;
  isolation: isolate;
  color: var(--dee-ink);
  padding-block: clamp(2.5rem, 1.5rem + 4vw, 5rem) 0;
  /*
   * Warm paper with two very quiet washes of brand colour — one behind the
   * photograph, one under the headline. Quiet enough that it reads as light
   * falling on the page rather than as a gradient somebody applied.
   */
  background:
    radial-gradient(80% 70% at 88% 6%, rgba(22, 134, 239, .10), transparent 62%),
    radial-gradient(70% 60% at 2% 40%, rgba(22, 134, 239, .05), transparent 60%),
    linear-gradient(180deg, #ffffff 0%, var(--dee-paper) 58%, var(--dee-paper) 100%);
}

/* 7fr/5fr: the headline is the largest thing on the page and needs the room.
   Scoped, or it reinstates two columns below the breakpoint that collapses
   the grid — source order beats specificity when specificity ties. */
@media (min-width: 981px) {
  .dee-hero__inner {
    grid-template-columns: minmax(0, 6.4fr) minmax(0, 5.6fr);
    align-items: center;
    padding-bottom: clamp(2.5rem, 1.5rem + 4vw, 4.5rem);
  }
}
@media (max-width: 980px) {
  .dee-hero__inner { padding-bottom: var(--dee-s6); }
}

.dee-hero__title {
  font-size: var(--dee-fs-4xl);
  line-height: 0.99;
  letter-spacing: -0.045em;
  text-wrap: balance;
  margin-bottom: var(--dee-s5);
  color: var(--dee-navy);
}
.dee-hero__title span { color: var(--dee-blue-dark); }

.dee-hero .dee-lead {
  max-width: 44ch;
  font-size: var(--dee-fs-lg);
  color: var(--dee-ink-soft);
}

/* An eyebrow with an actual rule, so it reads as a label rather than as a
   line of shouting small caps floating above the headline. */
.dee-hero .dee-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: var(--dee-s3);
  color: var(--dee-blue-dark);
}
.dee-hero .dee-eyebrow::before {
  content: "";
  width: 2rem;
  height: 2px;
  background: var(--dee-blue);
  border-radius: 2px;
}

/* -------------------------------------------------------------------------
   2  The photograph — the largest object on the screen

   Natural colour. The dark version graded these hard toward navy because the
   only pictures then in play were empty rooms; the hero now carries people,
   and draining them is the one thing that would undo the point of putting
   them there. A light grade seats the picture without touching skin tones.
   ---------------------------------------------------------------------- */

.dee-hero .dee-figure {
  overflow: hidden;
  border-radius: var(--dee-r-lg);
  box-shadow: var(--dee-shadow-float);
}
.dee-hero .dee-figure img {
  filter: saturate(1.02) contrast(1.02);
  aspect-ratio: 4 / 5;
  object-position: center;
  border-radius: var(--dee-r-lg);
}
/*
 * A scrim only where the fact card sits. A tint across the whole frame is
 * what made the photograph look like a placeholder in the very first build.
 */
.dee-hero .dee-figure::after {
  background: linear-gradient(to top,
    rgba(0, 20, 45, .58) 0%, rgba(0, 20, 45, .16) 38%, rgba(0, 20, 45, 0) 66%);
  mix-blend-mode: normal;
}

/* The pale rectangle that used to sit behind the photo: now a soft brand-blue
   halo offset behind it, which gives depth without drawing a second box. */
.dee-hero__media.has-photo::before {
  display: block;
  inset: 2rem -1.75rem -1.75rem 2.5rem;
  border-radius: var(--dee-r-lg);
  background: linear-gradient(150deg, rgba(22, 134, 239, .16), rgba(0, 33, 71, .06));
  filter: blur(2px);
}

/* The fact card: glass over the foot of the photograph. */
.dee-hero__media.has-photo .dee-herofacts {
  background: rgba(255, 255, 255, .90);
  border: 1px solid rgba(255, 255, 255, .9);
  backdrop-filter: saturate(1.5) blur(16px);
  box-shadow: var(--dee-shadow-float);
}

/* -------------------------------------------------------------------------
   3  The rail that closes the hero

   The strip is an elevated white card everywhere else on the site, which is
   what it is for on the inner pages where it lifts off a light ground. In the
   hero it is a quiet rule of facts, so the card, its shadow, its radius and
   the negative top margin that pulled it up over the previous section are all
   unset. Leaving the card in place and only recolouring the text is how an
   earlier build shipped four icons floating on a blank slab.
   ---------------------------------------------------------------------- */

.dee-hero__rail { padding-bottom: clamp(1.25rem, .5rem + 1.5vw, 2rem); }
.dee-hero__rail .dee-features {
  margin-top: 0;
  background: transparent;
  border: 0;
  border-top: 1px solid var(--dee-rule);
  border-radius: 0;
  box-shadow: none;
  overflow: visible;
}
.dee-hero__rail .dee-feature + .dee-feature { border-left-color: var(--dee-rule); }

@media (max-width: 720px) {
  /* Stacked rows do not want vertical hairlines between them. */
  .dee-hero__rail .dee-feature + .dee-feature {
    border-left: 0;
    border-top: 1px solid var(--dee-rule);
  }
}

/* -------------------------------------------------------------------------
   4  The header stays light

   A dark header was tried so the chrome and the hero would read as one field.
   With a light hero there is nothing to merge into, and the logo goes back to
   its own colours — no white chip, which is one less thing standing between
   the school's mark and the visitor.
   ---------------------------------------------------------------------- */

@media (max-width: 560px) {
  /* Two shrink-to-fit buttons stacking at two different widths reads as a
     mistake rather than as a hierarchy. */
  .dee-hero .dee-cta-pair { display: grid; gap: var(--dee-s3); }
  .dee-hero .dee-cta-pair .dee-btn { width: 100%; justify-content: center; }
}

/* -------------------------------------------------------------------------
   5  Surfaces below the fold

   One shadow used consistently, instead of eleven hairline boxes. Still
   quiet — this is a school, not a startup landing page — but the cards now
   sit on the paper rather than being drawn onto it.
   ---------------------------------------------------------------------- */

.dee-finder,
.dee-level,
.dee-prop,
.dee-start,
.dee-service {
  box-shadow: var(--dee-shadow-card);
}
.dee-level,
.dee-service {
  transition: transform .22s var(--dee-ease), box-shadow .22s var(--dee-ease);
}
.dee-level:hover,
.dee-service:hover {
  transform: translateY(-3px);
  box-shadow: 0 4px 8px -4px rgba(20, 32, 47, .08),
              0 22px 44px -20px rgba(20, 32, 47, .22);
}

@media (prefers-reduced-motion: reduce) {
  .dee-level, .dee-service { transition: none; }
  .dee-level:hover, .dee-service:hover { transform: none; }
}

/* Section headings get the same ceiling raise, or they look small under a
   hero that now runs to 5.25rem.
   overflow-wrap/hyphens: "Prüfungsvorbereitung" and its siblings are single
   German compound words with no space to break on. At the mobile ceiling
   size they ran past the 350px content column and off the edge of the
   phone rather than wrapping — `lang="de"` on <html> is already set, so
   `hyphens: auto` gets a real hyphenation point instead of a bare
   mid-word break when the fallback is even needed. */
.dee-section__title { font-size: var(--dee-fs-3xl); letter-spacing: -0.035em; line-height: 1.02; overflow-wrap: break-word; hyphens: auto; }


/* -------------------------------------------------------------------------
   6  Surfaces below the fold

   One shadow, used consistently, instead of eleven hairline boxes. The card
   is still quiet — this is a school, not a startup landing page — but it now
   sits on the paper rather than being drawn onto it.
   ---------------------------------------------------------------------- */

.dee-finder,
.dee-level,
.dee-prop,
.dee-start,
.dee-service {
  box-shadow: var(--dee-shadow-card);
}
.dee-level,
.dee-service {
  transition: transform .22s var(--dee-ease), box-shadow .22s var(--dee-ease);
}
.dee-level:hover,
.dee-service:hover {
  transform: translateY(-3px);
  box-shadow: 0 4px 8px -4px rgba(20, 32, 47, .08),
              0 22px 44px -20px rgba(20, 32, 47, .22);
}

@media (prefers-reduced-motion: reduce) {
  .dee-level, .dee-service { transition: none; }
  .dee-level:hover, .dee-service:hover { transform: none; }
}

/* Section headings get the same ceiling raise, or they look small under a
   hero that now goes to 6.5rem.
   overflow-wrap/hyphens: see the identical rule above — long unbreakable
   German compound words (e.g. "Prüfungsvorbereitung") overflowed the
   350px mobile content column at this size instead of wrapping. */
.dee-section__title { font-size: var(--dee-fs-3xl); letter-spacing: -0.035em; line-height: 1.02; overflow-wrap: break-word; hyphens: auto; }

/* -------------------------------------------------------------------------
   7  The ceiling crop — for rooms only

   The flagship band and the placement-test block both render
   `kursraum-projektor`: a room photographed from the doorway with the camera
   level, so the top third of the frame is projector mount, strip light and
   cable tray. object-position cannot remove it — the source is 4:3 landscape
   and the window is square or portrait, so the overflow is horizontal and
   there is no vertical slack to move through. Scaling up inside a clipped
   box does what was wanted; translateY must be NEGATIVE, because moving an
   image DOWN inside a fixed window brings the TOP of it into view, which here
   means more ceiling rather than less.

   Deliberately NOT applied to the hero. The hero carries a photograph with
   faces in it, and the same shift that removes a projector mount removes the
   top of somebody's head — which is exactly what it did on the first deploy.
   If the school later puts a room photograph back in the hero, the crop
   belongs there too; if it puts people into the flagship band, it has to come
   off here.
   ---------------------------------------------------------------------- */

.dee-flagship__media,
.dee-figure--split {
  overflow: hidden;
}
.dee-flagship__media img,
.dee-figure--split img {
  transform: scale(1.22) translateY(-9%);
  transform-origin: center;
}

/* -------------------------------------------------------------------------
   8  The oversized level numeral

   #847b70 is a warm stone grey, chosen when the page ground was the only
   thing it had to sit against. Beside a navy hero it reads as a different
   design — a beige numeral in a blue system. This keeps the same quiet weight
   in the hierarchy and the same contrast ratio, in the palette the rest of
   the page is actually built from.
   ---------------------------------------------------------------------- */

:root { --dee-numeral: #7e8ba0; }

/* -------------------------------------------------------------------------
   9  The value props

   Four columns of 13px text between hairlines read as a footnote, not as the
   answer to "why this school". They keep the four-up rhythm and get the size
   and leading of something meant to be read.
   ---------------------------------------------------------------------- */

.dee-prop__title { font-size: var(--dee-fs-lg); }
.dee-prop__text { font-size: var(--dee-fs-base); line-height: 1.62; }
@media (min-width: 981px) {
  .dee-prop { padding-inline: var(--dee-s5); }
}

/* On a phone two shrink-to-fit buttons stack at two different widths, which
   reads as a mistake rather than as a hierarchy. */
@media (max-width: 560px) {
  .dee-hero .dee-cta-pair { display: grid; gap: var(--dee-s3); }
  .dee-hero .dee-cta-pair .dee-btn { width: 100%; justify-content: center; }
}

/* -------------------------------------------------------------------------
   10  The room gallery

   Six phone photographs of empty rooms at full saturation, side by side, look
   like a property listing. Graded toward the palette they become what the
   section actually claims to be — evidence that the place is real and looks
   after itself — without pretending to be photography they are not.

   Note the ceiling crop is deliberately NOT applied here. In the hero the
   ceiling is an accident of framing; in a gallery captioned "so sieht es bei
   uns aus", the whole room is the subject.
   ---------------------------------------------------------------------- */

.dee-rooms__item img {
  filter: saturate(.72) contrast(1.06) brightness(.97);
  transition: transform .4s var(--dee-ease), filter .4s var(--dee-ease);
}
.dee-rooms__item::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(150deg, rgba(0, 33, 71, .16), rgba(22, 134, 239, .07));
  mix-blend-mode: multiply;
  transition: opacity .4s var(--dee-ease);
}
/* On hover the grade lifts — the picture comes forward as you look at it. */
.dee-rooms__item:hover img { filter: saturate(.92) contrast(1.03) brightness(1); transform: scale(1.04); }
.dee-rooms__item:hover::after { opacity: .35; }

@media (prefers-reduced-motion: reduce) {
  .dee-rooms__item img, .dee-rooms__item::after { transition: none; }
}

/* =========================================================================
   PASS — CHROME: THE FLOATING ACTION, THE LOADER, THE SCROLLBAR
   ====================================================================== */

/* -------------------------------------------------------------------------
   1  The WhatsApp action, labelled

   Moved out of the header, where it was a second button competing with the
   page's own primary action so that neither won. Down here it is permanent,
   always reachable, and no longer arguing with anything.

   It is a pill rather than a bare disc because the disc is navy now — it
   belongs to this palette, not WhatsApp's — and an unlabelled navy circle is
   a guess. The label is real text, so it is also the control's accessible
   name rather than something only a screen reader can reach.
   ---------------------------------------------------------------------- */

.dee-wa {
  position: fixed; right: 1.25rem; bottom: 1.25rem; z-index: 90;
  display: inline-flex; align-items: center; gap: .6rem;
  width: auto; height: auto; min-height: 54px;
  padding: .7rem 1.15rem .7rem .95rem;
  border-radius: var(--dee-r-full);
  background: var(--dee-navy); color: #fff;
  border: 1px solid rgba(255, 255, 255, .16);
  box-shadow: 0 4px 12px -4px rgba(0, 16, 38, .40), 0 18px 40px -16px rgba(0, 16, 38, .55);
  font-family: var(--dee-font); font-weight: 600; font-size: var(--dee-fs-sm);
  line-height: 1; text-decoration: none;
  transition: transform .2s var(--dee-ease), background-color .2s var(--dee-ease);
}
.dee-wa:hover { background: var(--dee-navy-deep); color: #fff; transform: translateY(-2px); }
.dee-wa:focus-visible { outline: 3px solid var(--dee-blue); outline-offset: 3px; }
.dee-wa svg { flex: none; width: 22px; height: 22px; }
.dee-wa__label { white-space: nowrap; }

@media (prefers-reduced-motion: reduce) {
  .dee-wa { transition: none; }
  .dee-wa:hover { transform: none; }
}

/*
 * On a phone the pill becomes a disc.
 *
 * 217px of labelled pill is more than half of a 390px screen, sitting over
 * the content. The mark alone is enough here and only here: WhatsApp's glyph
 * on WhatsApp's green is a shape people already read, which is exactly the
 * argument this file refuses to make for an unlabelled navy circle. The
 * accessible name comes from the aria-label the markup already carries, so
 * nothing is lost to a screen reader.
 */
/*
 * Inside the stack the pill is a disc like the other two — the shared
 * .dee-actions__item rule sizes it. Outside the stack (nothing renders it
 * that way today, but the class is public) it keeps the pill it always was.
 */
.dee-actions .dee-wa { padding: 0 14px; gap: 0; }

/* -------------------------------------------------------------------------
   2  The loader

   The rule that makes a loader safe: it is REMOVED BY DEFAULT and only shown
   while the page is genuinely still arriving. A loader that starts visible in
   CSS and waits for JavaScript to hide it is a blank white page for anybody
   whose script fails, is blocked, or times out — the failure mode is total.

   So `html.no-js` never shows it (no-js is stripped by main.js the moment it
   runs), the overlay carries `aria-hidden`, and there is a hard CSS-only
   timeout: after 4 seconds the fade runs regardless of what any script did or
   did not do. Nothing here can trap a visitor.
   ---------------------------------------------------------------------- */

/*
 * Hidden by default and shown only when `.js` is present. That class is set
 * by a synchronous inline script in the head, so with scripts off it is never
 * set and this overlay is never displayed — the failure mode is "no loader",
 * never "blank page". Gating the other way round, on `html.no-js`, was the
 * first attempt and it was exactly backwards: main.js is deferred, so the
 * loader would have appeared after the page had already painted.
 */
.dee-loader { display: none; }
html.js .dee-loader {
  position: fixed; inset: 0; z-index: 9999;
  display: grid; place-items: center;
  background: var(--dee-paper);
  animation: dee-loader-timeout 0s linear 4s forwards;
}
html.js .dee-loader[hidden] { display: none; }

.dee-loader__mark {
  width: 72px; height: 72px;
  border-radius: 16px;
  box-shadow: 0 10px 30px -12px rgba(12, 26, 45, .35);
  animation: dee-loader-pulse 1.4s var(--dee-ease) infinite;
}
.dee-loader__bar {
  position: absolute; left: 50%; bottom: 34%;
  width: 132px; height: 3px; margin-left: -66px;
  border-radius: 3px; overflow: hidden;
  background: var(--dee-rule);
}
.dee-loader__bar::after {
  content: ""; display: block; height: 100%; width: 40%;
  border-radius: 3px; background: var(--dee-blue);
  animation: dee-loader-slide 1.1s var(--dee-ease) infinite;
}

@keyframes dee-loader-pulse {
  0%, 100% { transform: scale(1);    opacity: 1; }
  50%      { transform: scale(.94);  opacity: .82; }
}
@keyframes dee-loader-slide {
  0%   { transform: translateX(-110%); }
  100% { transform: translateX(360%); }
}
@keyframes dee-loader-timeout { to { opacity: 0; visibility: hidden; } }

.dee-loader.is-leaving {
  opacity: 0; visibility: hidden;
  transition: opacity .45s var(--dee-ease), visibility 0s linear .45s;
}

/*
 * Reduced motion gets no pulse, no sliding bar and no fade — just the mark,
 * gone the moment the page is ready. Vestibular triggers are not decoration.
 */
@media (prefers-reduced-motion: reduce) {
  .dee-loader__mark,
  .dee-loader__bar::after { animation: none; }
  .dee-loader.is-leaving { transition: none; }
}

/* -------------------------------------------------------------------------
   3  The scrollbar

   Both syntaxes, because they are not interchangeable: Firefox understands
   `scrollbar-color`, Chromium and Safari want `::-webkit-scrollbar`. Sized at
   12px rather than the fashionable 6px — a scrollbar is a control, and a
   hairline one is unusable for anyone dragging it with a trackball, a head
   pointer, or an unsteady hand.
   ---------------------------------------------------------------------- */

html {
  scrollbar-color: var(--dee-rule-strong) var(--dee-paper-deep);
  scrollbar-width: auto;
}
::-webkit-scrollbar { width: 12px; height: 12px; }
::-webkit-scrollbar-track { background: var(--dee-paper-deep); }
::-webkit-scrollbar-thumb {
  background: var(--dee-rule-strong);
  border-radius: 8px;
  border: 3px solid var(--dee-paper-deep); /* inset, so the thumb reads as a pill */
}
::-webkit-scrollbar-thumb:hover { background: #a9a196; }
::-webkit-scrollbar-corner { background: var(--dee-paper-deep); }

/* On the dark bands the light thumb would glow. Scoped to elements that
   actually scroll inside a dark section rather than applied globally. */
.dee-flagship ::-webkit-scrollbar-track,
.dee-band ::-webkit-scrollbar-track { background: rgba(255, 255, 255, .06); }
.dee-flagship ::-webkit-scrollbar-thumb,
.dee-band ::-webkit-scrollbar-thumb {
  background: rgba(255, 255, 255, .28);
  border-color: transparent;
}

/* =========================================================================
   PASS — THE PRICES & TERMINE PAGE

   The most load-bearing URL on the site: the school prints QR codes pointing
   at it. It now carries every course AND every exam sitting in anchored
   sections, so "what does the telc B1 exam cost and when is it" is one jump
   rather than a scroll past everything else.
   ====================================================================== */

.dee-jump {
  display: flex; flex-wrap: wrap; gap: var(--dee-s3);
  margin: var(--dee-s6) 0 0; padding: var(--dee-s5) 0 0;
  border-top: 1px solid var(--dee-rule);
}
.dee-jump__item {
  display: inline-flex; align-items: center; gap: .5rem;
  padding: .5rem .9rem;
  border: 1px solid var(--dee-rule-strong); border-radius: var(--dee-r-full);
  background: var(--dee-surface); color: var(--dee-navy);
  font-size: var(--dee-fs-sm); font-weight: 600; text-decoration: none;
  transition: border-color .18s var(--dee-ease), background-color .18s var(--dee-ease);
}
.dee-jump__item:hover { border-color: var(--dee-blue); background: var(--dee-blue-wash); }
.dee-jump__item:focus-visible { outline: 3px solid var(--dee-blue); outline-offset: 2px; }
.dee-jump__count {
  min-width: 1.4em; padding: .05em .4em; border-radius: var(--dee-r-full);
  background: var(--dee-blue-wash); color: var(--dee-blue-dark);
  font-size: var(--dee-fs-xs); text-align: center;
}
/* The unit rides with the number and never wraps away from it. */
.dee-jump__unit { font-weight: 500; white-space: nowrap; }

/*
 * An anchored jump lands the heading hard against the top of the viewport,
 * under the sticky header. scroll-margin gives it room without any script.
 */
.dee-section[id] { scroll-margin-top: 6rem; }

.dee-pricetable__date small {
  display: block; color: var(--dee-ink-soft); font-size: var(--dee-fs-xs);
  font-variant-numeric: tabular-nums;
}

/* The seat column — the one thing the competitor's price list cannot tell
   you. Colour carries the state, and the word carries it too, because
   roughly one man in twelve cannot rely on the colour. */
.dee-seat { font-size: var(--dee-fs-sm); font-weight: 600; white-space: nowrap; }
.dee-seat.is-free { color: var(--dee-ok); }
.dee-seat.is-low  { color: var(--dee-warn); }
.dee-seat.is-wait { color: var(--dee-warn); }
.dee-seat.is-sold { color: var(--dee-err); }

.dee-pricetable th[scope="row"] { min-width: 14rem; }
.dee-pricetable .dee-chip { margin-left: .4rem; vertical-align: middle; }

@media (max-width: 720px) {
  .dee-jump { gap: var(--dee-s2); }
  .dee-jump__item { font-size: var(--dee-fs-xs); padding: .4rem .7rem; }
}

/* =========================================================================
/* =========================================================================
   PASS — THE SPLIT HERO

   Four attempts got this wrong before it got right, and each failure was
   informative.

   1. Photograph in a rounded card beside the headline. Read as a
      placeholder, because the only pictures were empty rooms.
   2. Same, with a nicer card. Still a placeholder — the card was never the
      problem.
   3. Full-bleed over the building on Kampstraße, with a directional scrim.
      The scrim was tuned until the words passed AA, at which point the
      photograph was navy soup. The diagnosis was not "too dark": the crop
      selected sky and roofline, and a scrim over sky is a flat field. The
      building itself is also a 1960s block on a corner with a lamp post
      through the middle of it — a location document, not a hero.
   4. This one. The photograph is not underneath the words at all. It owns
      the right of the screen edge to edge, top to bottom, at full clarity,
      and the words sit on navy beside it. Nothing is composited over
      anything, so nothing has to be compromised: the type is white on
      #001c3c and the picture is a picture.

   The subject changed too. `beratungsraum-logo` is the consultation room —
   the school's own wordmark and claim painted two metres tall on the wall,
   daylight, the table people actually sit at to be advised. It says whose
   building it is, which the exterior never did.
   ========================================================================= */

.dee-hero--photo {
  /*
   * Where the veil finishes and the card's half begins. One value, read by
   * the gradient's last stop AND by the grid track the card centres in, so
   * the picture becomes fully clear exactly where the card's half starts —
   * and neither can move without the other.
   */
  --dee-hero-right: clamp(420px, 48%, 860px);
  position: relative;
  isolation: isolate;
  color: #fff;
  padding-block: clamp(3rem, 1.5rem + 5vw, 6rem) 0;
  overflow: hidden;
  /*
   * Not flat navy. A single #001c3c rectangle beside a photograph looks
   * like a missing background; the warm lift at the top left gives the
   * headline somewhere to sit and reads as light rather than as a fill.
   */
  background:
    radial-gradient(90% 120% at 4% 0%, #06356f 0%, rgba(6, 53, 111, 0) 64%),
    radial-gradient(60% 80% at 30% 100%, rgba(22, 134, 239, .18), transparent 70%),
    var(--dee-navy);
}

/* The photograph panel ---------------------------------------------------
 *
 * Absolutely positioned rather than a grid child, for one reason: it has to
 * reach the right edge of the VIEWPORT while the words stay inside the
 * content measure. A grid child is bounded by the wrap; margin-right:
 * calc(50% - 50vw) escapes it but takes the horizontal scrollbar with it on
 * any browser where 100vw includes the gutter.
 */
/*
 * The photograph is the WHOLE hero, and the navy is a veil over it.
 *
 * It used to be a panel occupying the right 48%, with the navy a solid field
 * beside it. The client's word for the result was that the hero "feels split
 * to two half" — which it was: two rectangles of equal visual weight meeting
 * on a line, and the 106px feather softened that line without removing the
 * reading of it.
 *
 * Now there is one picture edge to edge and one veil across it: opaque where
 * the headline sits, and gone by the point the old seam used to be. Nothing
 * meets anything; the navy runs out.
 */
.dee-hero--photo .dee-hero__bg {
  position: absolute;
  inset: 0;
  z-index: -1;
  overflow: hidden;
}
.dee-hero--photo .dee-hero__bgimg {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /*
   * 90% across, and the number is arithmetic rather than taste. The panel
   * is portrait and the photograph is 4:3, so `cover` scales to the panel's
   * HEIGHT and the entire horizontal overflow — around 950px of a 2400px
   * frame — is what object-position selects from. The wordmark on the wall
   * is the reason this photograph was chosen and it lives in the last 500px
   * of the frame: anything below about 87% cuts it in half, which is what
   * the first attempt did. 90% keeps it whole with a margin, and still
   * holds the cabinet, the flowers and one of the chairs.
   */
  object-position: 90% 50%;
  display: block;
}

/*
 * A feather, not a scrim.
 *
 * This gradient does one job — dissolve the panel's left edge into the navy
 * so the composition reads as one field rather than as two rectangles — and
 * it is fully transparent across the two thirds of the panel that anyone
 * actually looks at. No text is ever laid over that part, so nothing here
 * is trading legibility against the picture. That trade is what killed the
 * previous three heroes.
 */
.dee-hero--photo .dee-hero__bg::after {
  content: "";
  position: absolute;
  inset: 0;
  /*
   * One gradient, three stops — down from two gradients and eight.
   *
   * The second one darkened the foot of the photograph so the fact rail
   * could be read over it. The rail now has a ground of its own (see
   * .dee-hero__rail below), so that layer was dimming a picture to solve a
   * problem that no longer exists. What is left does the one job the note
   * above describes: dissolve the panel's left edge into the navy.
   */
  /*
   * Four stops, and the last one is the whole point: the veil reaches full
   * transparency exactly at the line where the card's half begins, so the
   * picture is completely clear underneath the card and completely covered
   * under the headline, with the whole of the distance between them spent
   * getting from one to the other.
   *
   * The solid stretch is short — 14% — because "the left side background
   * should be much less". The long middle is what stops the composition
   * reading as two panels: there is no width at which you can point and say
   * the navy ends here and the photograph starts there.
   */
  /*
   * A flat tint, and one gradient over it.
   *
   * The tint is not a second scrim in the sense the check on it forbids —
   * that one existed to darken the FOOT of the picture so the rail could be
   * read over it, and the rail has had a ground of its own since. This is
   * even, across the whole frame, and it is here because the photograph's
   * brightest region is a window sitting exactly where the headline's
   * longest line ends.
   *
   * It is a margin, not a pass: measured worst-case at 1440, the headline
   * runs 4.77:1 without it and 7.51:1 with, and the accent line 4.10:1
   * against 5.51:1 — both clear the 3:1 that 84px type needs either way.
   * What the tint buys is that the difference between the first word and
   * the last stops being visible as a change in weight.
   */
  background-color: rgba(0, 28, 60, .34);
  /*
   * Four stops, and the last one is the whole point: the veil reaches full
   * transparency exactly at the line where the card's half begins, so the
   * picture is completely clear under the card and completely covered under
   * the headline, with the entire distance between them spent getting from
   * one to the other.
   *
   * The solid stretch is short — 12% — because "the left side background
   * should be much less". The long middle is what stops the composition
   * reading as two panels: there is no width at which you can point and say
   * the navy ends here and the photograph begins there.
   *
   * The two middle stops hold the veil high across the measure of the
   * headline and drop it only past the last word. Straight-line
   * interpolation from 12% to the split put .42 under "lernen." — white on
   * a lit window.
   */
  background-image: linear-gradient(90deg,
    var(--dee-navy) 0%,
    var(--dee-navy) 12%,
    rgba(0, 28, 60, .82) 34%,
    rgba(0, 28, 60, .55) 46%,
    rgba(0, 28, 60, 0) calc(100% - var(--dee-hero-right)));
}

/* Layout on the split ---------------------------------------------------- */

/*
 * 1200px, not the 980px the rest of the page collapses at.
 *
 * The split needs three things across one line: a headline at its full
 * measure, a fact card wide enough for a date and a price, and enough
 * photograph left over that it is a photograph rather than a stripe. At
 * 1024 those three do not fit — the card lands squarely on the wordmark on
 * the wall, which is the one thing in the frame worth showing. So the split
 * gets its own, higher breakpoint and everything below it stacks. A layout
 * that only works at one width is not responsive, it is a screenshot.
 */
@media (min-width: 1200px) {
  /*
   * The copy column narrows and the fact card is pulled left and down, so
   * it straddles the seam: its left third over navy, the rest over the
   * lower corner of the photograph, clear of the wordmark on the wall. The
   * upper two thirds of the picture stay untouched.
   */
  /*
   * The LAST column IS the photograph, to the pixel — and it has to be the
   * last one for that to be true.
   *
   * The card used to be pulled left out of its column with a negative margin
   * so it straddled the seam. It read as a card that had slipped: its centre
   * sat 105px left of the panel's, which is close enough to centred to look
   * like a mistake rather than a decision. Computing an offset instead needs
   * one arithmetic where the wrap tracks the viewport and another where it
   * caps, and is wrong the moment the panel's own min/max clamps bite.
   *
   * So the column is given the panel's own expression, `clamp(420px, 48%,
   * 860px)`, and centring is `justify-self: center` with no number to keep in
   * step. The catch — and the reason this is a three-track grid rather than
   * the two it was — is WHAT THE PERCENTAGE IS OF. The panel is absolute
   * against .dee-hero, so its 48% is 48% of the hero. A grid track's 48% is
   * 48% of the grid's content box, so while the wrap carried a left margin
   * the two resolved against different boxes and the card drifted right by
   * half that margin: 9px at 1470, and ~180px at 2560, where the panel caps
   * at 860 and the column does not.
   *
   * The wrap's left gutter is therefore a TRACK rather than a margin. The
   * grid now spans the hero edge to edge, so 48% here and 48% there are the
   * same 48%, and the last track begins and ends exactly where the panel
   * does at every width.
   */
  .dee-hero--photo .dee-hero__inner {
    width: 100%;
    max-width: none;
    margin-inline: 0;
    padding-inline: 0;
    grid-template-columns:
      max(1.25rem, calc((100% - var(--dee-wide)) / 2))
      minmax(0, 1fr)
      var(--dee-hero-right);
    /*
     * Zero, because a gap would be added to the gutter track as well and the
     * copy would no longer start on the wrap's line. The breathing room
     * between the copy and the panel is the copy's own padding instead.
     */
    column-gap: 0;
    align-items: center;
    padding-bottom: clamp(2rem, 1rem + 3vw, 3.5rem);
  }
  .dee-hero--photo .dee-hero__copy {
    grid-column: 2;
    padding-right: clamp(2rem, 1rem + 4vw, 5rem);
  }
  .dee-hero--photo .dee-hero__media {
    grid-column: 3;
    justify-self: center;
    width: min(100%, 21.5rem);
    position: relative;
    z-index: 1;
  }
}

/* Type on the navy ------------------------------------------------------- */

.dee-hero--photo .dee-hero__title { color: #fff; }
.dee-hero--photo .dee-hero__title span { color: #8fd0ff; }
.dee-hero--photo .dee-lead { color: rgba(255, 255, 255, .88); }
.dee-hero--photo .dee-eyebrow { color: #8fd0ff; }
.dee-hero--photo .dee-eyebrow::before { background: #8fd0ff; }

/* Primary inverts to navy-on-white; the ghost gets a visible edge. */
.dee-hero--photo .dee-btn--primary {
  background: #fff; color: var(--dee-navy); border-color: #fff;
  box-shadow: 0 18px 40px -18px rgba(0, 12, 30, .8);
}
.dee-hero--photo .dee-btn--primary:hover { background: #e8f2ff; border-color: #e8f2ff; }
.dee-hero--photo .dee-btn--ghost {
  color: #fff;
  border-color: rgba(255, 255, 255, .45);
  background: rgba(255, 255, 255, .08);
  backdrop-filter: blur(4px);
}
.dee-hero--photo .dee-btn--ghost:hover {
  border-color: #fff; background: rgba(255, 255, 255, .16);
}

/*
 * The fact card is white, and opaque.
 *
 * Opaque for the reason it always was: it is the only element over the
 * photograph and it carries the three numbers a visitor came for, so their
 * contrast cannot be allowed to depend on what the school puts behind them.
 *
 * White rather than navy because the whole hero is navy now — the field, the
 * rail, the feathered edge of the picture — and a navy card on a navy field
 * separated only by a hairline is a card you have to look for. White is the
 * one value on this screen that nothing else uses, so the card reads as the
 * thing in front. It also lets the card use the site's ordinary ink and rule
 * colours instead of a second, inverted set maintained beside them.
 */
.dee-hero--photo .dee-herofacts {
  background: var(--dee-surface);
  border: 1px solid var(--dee-rule);
  box-shadow: 0 40px 80px -32px rgba(0, 8, 22, .55);
}
/* The masthead row keeps the navy — it is the one band of it left. */
.dee-hero--photo .dee-herofacts__row.is-lead { background: var(--dee-navy); }
.dee-hero--photo .dee-herofacts__row dt { color: var(--dee-ink-soft); }
.dee-hero--photo .dee-herofacts__row dd { color: var(--dee-navy); }
.dee-hero--photo .dee-herofacts__row.is-lead dt { color: rgba(255, 255, 255, .70); }
.dee-hero--photo .dee-herofacts__row.is-lead dd { color: var(--dee-on-accent); }
.dee-hero--photo .dee-herofacts__row { border-bottom-color: var(--dee-rule); }
.dee-hero--photo .dee-herofacts__note {
  border-top-color: var(--dee-rule);
  color: var(--dee-ink-soft);
}
.dee-hero--photo .dee-herofacts__note a { color: var(--dee-blue-dark); }
/*
 * The inverted set that used to live here is gone.
 *
 * When the card was navy it needed its own white type, its own translucent
 * rules and its own pale link colour — a second palette maintained beside
 * the first, and the reason the card's contents disappeared the moment the
 * card turned white: white type on a white card, invisible, with only the
 * masthead and the link still legible. That is what a parallel palette costs
 * the first time the thing underneath it changes.
 *
 * The card is white, so it uses the site's ordinary ink, rule and link
 * colours — which are declared once, measured once, and cannot fall out of
 * step with a background they no longer depend on. Only the masthead band
 * still inverts, because only the masthead band is still navy.
 */
.dee-hero--photo .dee-herofacts__row.is-lead { background: var(--dee-navy); }

/* The rail closes the hero on the dark. */
.dee-hero--photo .dee-hero__rail .dee-features { border-top-color: rgba(255, 255, 255, .22); }
.dee-hero--photo .dee-hero__rail .dee-feature + .dee-feature { border-left-color: rgba(255, 255, 255, .18); }
.dee-hero--photo .dee-hero__rail .dee-feature__k { color: #fff; }
.dee-hero--photo .dee-hero__rail .dee-feature__v { color: rgba(255, 255, 255, .68); }
.dee-hero--photo .dee-hero__rail .dee-feature .dee-icon {
  /* The chip behind each rail icon, on the band's own navy rather than a
     wash of white over whatever happens to be behind it. */
  background: var(--dee-navy-mid); color: #8fd0ff;
}

@media (max-width: 1199px) {
  /*
   * Below the split, the composition becomes a stack: the photograph is a
   * band under the header, then the words on navy. The panel stops being
   * absolute and simply flows — which is why it is the first child in the
   * markup and not a decorative ::before. Source order IS the small-screen
   * layout, so the picture is downloaded once and never duplicated.
   */
  .dee-hero--photo { padding-top: 0; }
  .dee-hero--photo .dee-hero__bg {
    /*
     * `relative`, not `static`, and the difference is the whole hero.
     *
     * The band is in flow either way — that is all `static` was here for.
     * But .dee-hero__bgvid is `position: absolute; inset: 0`, and a static
     * parent is not a containing block, so below this breakpoint the video
     * resolved against .dee-hero instead and stretched to the full 1306px
     * of it: the headline, the ghost button, the rating chip, the fact card
     * and the rail all sat on moving footage. "Kostenlos einstufen" was
     * white type over a sunlit classroom wall.
     *
     * On the split above 1200px the panel is absolute and already a
     * containing block, which is why this only ever went wrong on a phone —
     * and why the offline preview, which has no video, could not show it.
     */
    position: relative;
    z-index: auto;
    width: auto;
    min-width: 0;
    max-width: none;
    height: clamp(190px, 30vw, 340px);
    margin-bottom: clamp(1.75rem, 1rem + 3vw, 2.75rem);
  }
  /*
   * The band is wide and short, so `cover` scales to WIDTH and the crop is
   * vertical — the mirror of the split, where the panel is narrow and tall
   * and the crop is horizontal. Which is why this needs its own value: 48%
   * down holds the table, the wall and the wordmark together; the split's
   * 90% across would mean nothing here.
   */
  .dee-hero--photo .dee-hero__bgimg { object-position: 62% 48%; }

  /*
   * With the picture in its own band, the two columns underneath are only
   * words and a fact card, and the card does not need a twelfth-based
   * share of anything — it needs about 20rem. Giving it a fraction instead
   * took enough width off the headline that "Sicher sprechen." broke across
   * two lines mid-phrase, which is the sort of thing that looks like a bug
   * to a client and is one.
   */
  @media (min-width: 981px) {
    .dee-hero--photo .dee-hero__inner {
      grid-template-columns: minmax(0, 1fr) minmax(0, 20rem);
      gap: clamp(1.75rem, 1rem + 2vw, 3rem);
    }
  }
  /* Only the foot of the band is darkened, so it hands off to the navy
     rather than ending on a hard horizontal line. */
  .dee-hero--photo .dee-hero__bg::after {
    background: linear-gradient(to top,
      var(--dee-navy) 0%,
      rgba(0, 28, 60, .55) 22%,
      rgba(0, 28, 60, 0) 62%);
  }
}

@media (max-width: 980px) {
  .dee-hero--photo .dee-hero__rail .dee-feature + .dee-feature {
    border-left: 0; border-top: 1px solid rgba(255, 255, 255, .18);
  }
}

/* The contact page's building photograph — wide, so the façade reads, and
   never taller than a third of the viewport so the address stays visible
   without scrolling on a phone. */
.dee-contact__photo { margin: var(--dee-s5) 0 var(--dee-s6); }
.dee-contact__photo img { aspect-ratio: 21 / 9; object-position: 50% 70%; }
@media (max-width: 720px) {
  .dee-contact__photo img { aspect-ratio: 3 / 2; max-height: 34vh; }
}

/* =========================================================================
   PASS — THE TEAM, THE GREEN, AND THE STRIP ON A PHONE

   Three unrelated complaints from the same review, kept together because
   they are one release.
   ========================================================================= */

/* -------------------------------------------------------------------------
   1  The team
   ---------------------------------------------------------------------- */

.dee-team__title { font-size: var(--dee-fs-3xl); margin: var(--dee-s2) 0 var(--dee-s3); color: var(--dee-navy); }
.dee-team__lead  { max-width: 58ch; color: var(--dee-ink-soft); margin: 0 0 var(--dee-s7); }

.dee-team__grid {
  display: grid;
  /*
   * auto-fit with a floor, not a fixed column count. The school has one
   * member today and may have five next term; a hardcoded `repeat(3, 1fr)`
   * would leave a single card marooned in the left third of the page with
   * two empty columns beside it, which reads as a page that failed to load.
   * With auto-fit and no max, one card fills the row and looks intended.
   */
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 17rem), 1fr));
  gap: var(--dee-s5);
  list-style: none; margin: 0; padding: 0;
}

.dee-team__item {
  display: flex; flex-direction: column;
  background: var(--dee-surface);
  border: 1px solid var(--dee-rule);
  border-radius: var(--dee-r-lg);
  padding: var(--dee-s6);
  box-shadow: 0 1px 2px rgba(20, 32, 47, .04), 0 26px 50px -34px rgba(9, 24, 44, .5);
}

.dee-team__photo { margin: 0 0 var(--dee-s5); }
.dee-team__photo img {
  width: 88px; height: 88px; border-radius: var(--dee-r-full);
  object-fit: cover; display: block;
}

/*
 * Initials rather than a silhouette. Nobody in the team has a photograph
 * yet, and a row of identical grey avatars is the visual signature of an
 * unfinished directory. Initials look chosen.
 */
.dee-team__initials {
  width: 88px; height: 88px; margin: 0 0 var(--dee-s5);
  display: grid; place-items: center;
  border-radius: var(--dee-r-full);
  background: linear-gradient(145deg, var(--dee-navy) 0%, #0b3f7d 100%);
  color: #fff; font-family: var(--dee-display); font-weight: 700;
  font-size: 1.85rem; letter-spacing: .02em;
}

.dee-team__name { font-size: var(--dee-fs-xl); margin: 0 0 var(--dee-s1); color: var(--dee-navy); }
.dee-team__role {
  margin: 0 0 var(--dee-s4);
  font-size: var(--dee-fs-sm); font-weight: 600; color: var(--dee-blue-dark);
}
.dee-team__bio { margin: 0 0 var(--dee-s5); color: var(--dee-ink-soft); line-height: 1.6; }

.dee-team__facts { margin: auto 0 0; padding-top: var(--dee-s4); border-top: 1px solid var(--dee-rule); }
.dee-team__facts dt {
  font-size: var(--dee-fs-xs); letter-spacing: .08em; text-transform: uppercase;
  color: var(--dee-ink-faint); margin-top: var(--dee-s3);
}
.dee-team__facts dd { margin: 2px 0 0; font-size: var(--dee-fs-sm); color: var(--dee-ink); }

/* -------------------------------------------------------------------------
   2  The WhatsApp action is green

   It was navy — house palette, consistent, and wrong. WhatsApp's green is
   not decoration, it is the recognition: people identify that button by
   colour before they read anything, and a navy pill in the corner of a navy
   site is a button you have to stop and parse.

   #25D366 is WhatsApp's actual green, unmodified. The ink on it is near-black
   green rather than white, and that is not a compromise — white on #25D366
   measures 1.99:1, which fails AA for text and fails even the 3:1 floor for
   graphics. Every site that ships the white-on-green bubble ships that
   failure. Dark ink on the same green measures 7.9:1, keeps the brand colour
   exactly, and is legible in sunlight, which is where a phone actually is.
   ---------------------------------------------------------------------- */

.dee-wa {
  background: var(--dee-wa-green);
  color: var(--dee-wa-ink);
  border-color: rgba(0, 40, 20, .16);
  box-shadow: 0 4px 12px -4px rgba(4, 60, 30, .45), 0 18px 40px -16px rgba(4, 60, 30, .5);
}
.dee-wa:hover { background: var(--dee-wa-green-dark); color: var(--dee-wa-ink); }
.dee-wa:focus-visible { outline-color: var(--dee-navy); }

/* The phone bar carries the same action below 720px, so it carries the same
   colour — the recognition has to survive the breakpoint. */
.dee-btn--wa {
  background: var(--dee-wa-green);
  color: var(--dee-wa-ink);
  border-color: var(--dee-wa-green);
}
.dee-btn--wa:hover {
  background: var(--dee-wa-green-dark);
  border-color: var(--dee-wa-green-dark);
  color: var(--dee-wa-ink);
}

/* -------------------------------------------------------------------------
   3  The service strip on a phone

   It was three lines tall and roughly 90px of a 844px screen — a tenth of
   the first view spent on a utility bar, above a header, above the hero.
   The cause was a single declaration: below 1200px the strip was told to
   wrap and centre, which is right at tablet width where the lead and the
   language switcher genuinely do not fit side by side, and wrong on a phone
   where the switcher is 90px wide and there is room for both.
   ---------------------------------------------------------------------- */

@media (max-width: 720px) {
  .dee-announce__inner {
    flex-wrap: nowrap;
    justify-content: space-between;
    gap: var(--dee-s3);
    padding-block: .3rem;
    min-height: 34px;
  }
  .dee-announce__lead { min-width: 0; }
  .dee-announce__text {
    font-size: var(--dee-fs-xs);
    /* One line, always. The date is the payload; if the viewport is narrow
       enough that it will not fit, an ellipsis is a smaller failure than a
       second row. */
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }

  /* The divider was separating the strip's two halves. With the service
     links gone below 1200px there is nothing on its left to divide. */
  .dee-announce__utility .dee-langs {
    margin-left: 0; padding-left: 0; border-left: 0;
  }
  .dee-langs__item { min-height: 26px; padding: 0 .4rem; gap: .3rem; }
  .dee-flag { width: 17px; height: 12px; }
  .dee-langs__code { font-size: 11px; }
}

@media (max-width: 460px) {
  /* Below this the start time costs the date its room. The date is the
     reason the strip exists; the time is on the course page. */
  .dee-announce__sep, .dee-announce__time { display: none; }
}

/* =========================================================================
   PASS — DENSITY

   The homepage measured 10,202px against a competitor's 4,677 carrying the
   same number of sections. Almost none of the difference was content: nine
   sections at 120px of padding top and bottom is 1,900px of nothing, every
   section heading was set at hero size, and two blocks were tall because of
   the photographs beside them rather than because of anything they said.

   The rule applied throughout: a section's height should be set by what it
   says. Where it was set by a decoration, the decoration got smaller.
   ========================================================================= */

/* The reasons, as a grid ---------------------------------------------------
 *
 * Six one-line facts stacked in a single narrow column is a 400px column of
 * text with an enormous amount of unused width beside it. Three across reads
 * faster and is the shape the content actually is: a list of equals, none of
 * which is more important than the next.
 */
.dee-why {
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 19rem), 1fr));
  column-gap: var(--dee-s6);
  border-top: 1px solid var(--dee-rule);
}
.dee-why__item { padding-block: .7rem; font-size: var(--dee-fs-sm); }

/* The byline: a portrait at the size a byline needs. */
.dee-why__intro {
  display: flex; align-items: center; gap: var(--dee-s5);
  margin-bottom: var(--dee-s6); max-width: 62rem;
}
.dee-why__portrait { margin: 0; flex: none; }
.dee-why__portrait img {
  width: 84px; height: 84px; border-radius: var(--dee-r-full);
  object-fit: cover; display: block;
  box-shadow: 0 0 0 1px var(--dee-rule), 0 12px 28px -18px rgba(9, 24, 44, .6);
}
.dee-why__intro .dee-lead { margin-bottom: var(--dee-s2); }
.dee-why__byline { margin: 0; font-size: var(--dee-fs-sm); }
.dee-why__byline strong { color: var(--dee-navy); }
.dee-why__byline span { color: var(--dee-ink-soft); }
.dee-why__byline span::before { content: " · "; }

@media (max-width: 560px) {
  .dee-why__intro { flex-direction: column; align-items: flex-start; gap: var(--dee-s4); }
}

/* Lists breathe less ------------------------------------------------------
 *
 * 16px above and below every row, on lists of three to six rows, in three
 * places. Individually invisible; together most of a screen.
 */
.dee-steps__item { padding-block: .7rem; }
.dee-steps { margin-block: var(--dee-s5); }
.dee-steps__h { margin-bottom: var(--dee-s4); }
.dee-faq__item { padding-block: var(--dee-s4); }

/* Cards: the padding was set for a page with room to spare ---------------- */
.dee-prop { padding: var(--dee-s5); }
.dee-prop__icon { margin-bottom: var(--dee-s4); }
.dee-prop__title { margin-bottom: var(--dee-s2); }
.dee-service { padding: var(--dee-s5); }
.dee-service__icon { margin-bottom: var(--dee-s4); }

/* The closing band was 248px to say one sentence and show two buttons. */
.dee-band { padding-block: var(--dee-s7); }

/* Steps, laid across ------------------------------------------------------
 *
 * The same three steps, turned ninety degrees. Down the page they are a
 * checklist; across it they are a process, with the numerals reading left to
 * right the way a person expects a sequence to. The rules move with them:
 * a bottom border between stacked rows becomes a left border between
 * columns, or the last step ends on a line that separates it from nothing.
 */
.dee-steps--row .dee-steps__list {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 15rem), 1fr));
  gap: var(--dee-s4);
  border-top: 0;
}
.dee-steps--row .dee-steps__item {
  border: 1px solid var(--dee-rule);
  border-radius: var(--dee-r-lg);
  background: var(--dee-surface);
  box-shadow: var(--dee-shadow-sm);
  padding: var(--dee-s5);
  display: flex;
  flex-direction: column;
  gap: var(--dee-s3);
  transition: transform .2s var(--dee-ease), box-shadow .2s var(--dee-ease), border-color .2s var(--dee-ease);
}
.dee-steps--row .dee-steps__item:hover {
  transform: translateY(-2px);
  box-shadow: var(--dee-shadow-card);
  border-color: var(--dee-blue-tint);
}
/*
 * No separator rule between the cards, and none taken away on a phone.
 *
 * There used to be a `+ .dee-steps__item { border-left; padding-left }` pair
 * here and a media query that removed both below 720px. It was written when
 * the steps were an undecorated column separated by hairlines. They are
 * bordered cards now, and against cards the old rules did damage rather than
 * nothing: on a phone the second and third card lost their LEFT BORDER and
 * their LEFT PADDING, while the first kept both, and all three lost their
 * right padding — so the numbers 2 and 3 sat flush on an open edge, 24px to
 * the left of the 1 above them, and the school drew a line down the screen
 * to show us. Measured at 390px before the fix: padding 24/0/24/24 on the
 * first item against 24/0/24/0 on the others.
 *
 * A card carries its own border and its own padding on every side. There is
 * nothing left for a sibling selector to say.
 */

.dee-testflow__lead { max-width: 62ch; }
.dee-testflow .dee-btn { margin-top: var(--dee-s2); }

/* The level cards on a phone ----------------------------------------------
 *
 * Five cards stacked is 2,550px — a third of the whole page, spent on a
 * scale most visitors already know which end of they are at. Auto-fit gives
 * one column below about 500px and there is no honest way around that: two
 * 170px columns cannot hold "Niederlassungserlaubnis".
 *
 * So they go sideways. A snapping row shows A1 and most of A2 at rest, which
 * is the affordance — a card cut off at the edge is what tells somebody there
 * is another one. Height falls to a single card.
 *
 * Two things this must not do, and does not. It must not hide content from a
 * keyboard: the links inside stay in the tab order and the browser scrolls
 * the container to whichever one receives focus. And it must not trap a
 * vertical swipe: `scroll-snap-type: x` constrains snapping to one axis, so a
 * finger dragging up still scrolls the page.
 */
@media (max-width: 700px) {
  .dee-levels {
    display: flex;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scroll-padding-inline: 1.25rem;
    gap: var(--dee-s3);
    /* Escape the wrap so the row bleeds off both edges rather than stopping
       inside a gutter, which reads as a broken grid rather than a carousel. */
    width: calc(100vw - 2.5rem);
    margin-left: calc(50% - 50vw + 1.25rem);
    padding-bottom: var(--dee-s4);
    -webkit-overflow-scrolling: touch;
    scrollbar-width: thin;
  }
  .dee-levels > .dee-level {
    flex: 0 0 clamp(14rem, 76vw, 20rem);
    scroll-snap-align: start;
  }
  /* The last card needs something past it or it cannot snap to the start. */
  .dee-levels::after {
    content: ""; flex: 0 0 1px;
  }
}

/* =========================================================================
   PASS — THE DRAWER, AND THE BAR AT THE BOTTOM

   Reported as "I can't close it back". Reproduced immediately: the panel is
   `position: fixed` over the right of the screen, the burger that opens it
   sits in the header underneath, and the only other way out was the Escape
   key. On a phone that is a trap — the menu opens and the browser's back
   button is the exit.
   ========================================================================= */

body.dee-navopen { overflow: hidden; }

@media (max-width: 1200px) {

  /* The scrim ------------------------------------------------------------
   * Both a way out and the thing that tells you there is one: a panel with
   * dimmed page behind it reads as dismissible, a panel against a bright
   * page reads as the new state of the site.
   */
  .dee-nav__scrim {
    position: fixed; inset: 0; z-index: 125;
    background: rgba(0, 14, 32, .5);
    backdrop-filter: blur(2px);
    border: 0;
    animation: dee-fade .2s var(--dee-ease);
  }
  .dee-nav__scrim[hidden] { display: none; }

  @keyframes dee-fade { from { opacity: 0 } to { opacity: 1 } }
  @media (prefers-reduced-motion: reduce) {
    .dee-nav__scrim { animation: none; }
  }

  /* The panel ------------------------------------------------------------
   * A measured width rather than `inset-inline-start: 28%`. On a 390px phone
   * 28% left 280px of panel; on a 1024px tablet it left 737px of mostly
   * empty column. A drawer is a list of links — it wants a comfortable
   * reading width and no more.
   */
  .dee-nav {
    inset: 0 0 0 auto;
    width: min(88vw, 22rem);
    padding: 0 0 var(--dee-s6);
    z-index: 130;
    display: flex; flex-direction: column;
    overscroll-behavior: contain;
  }

  /* The bar at the top of the panel, with the way out in it. Sticky, so the
     close button is reachable from anywhere in a long menu without
     scrolling back up. */
  .dee-nav__top {
    position: sticky; top: 0; z-index: 2;
    display: flex; align-items: center; justify-content: space-between;
    gap: var(--dee-s4);
    padding: var(--dee-s4) var(--dee-s5);
    background: var(--dee-paper);
    border-bottom: 1px solid var(--dee-rule);
  }
  .dee-nav__toptitle {
    font-size: var(--dee-fs-xs); font-weight: 600;
    letter-spacing: .12em; text-transform: uppercase;
    color: var(--dee-ink-faint);
  }
  .dee-nav__close {
    display: grid; place-items: center;
    width: 44px; height: 44px; margin-right: -.5rem;
    border: 0; border-radius: var(--dee-r-full);
    background: var(--dee-paper-deep); color: var(--dee-navy);
    cursor: pointer;
  }
  .dee-nav__close:hover { background: var(--dee-rule); }

  /*
   * Rows, not a floating list.
   *
   * The links were 21px (--dee-fs-lg) items in a column with a 16px gap and
   * nothing between them — big type in loose space, which is the shape of a
   * splash screen rather than a menu. As full-width rows with hairlines they
   * are the same tap target at a readable size, and the panel holds the main
   * navigation, the service links and the actions without scrolling.
   */
  .dee-nav > ul {
    gap: 0; width: 100%; padding: 0 var(--dee-s5);
  }
  .dee-nav > ul > li { width: 100%; border-bottom: 1px solid var(--dee-rule); }
  .dee-nav > ul > li > a {
    display: flex; align-items: center; width: 100%;
    min-height: 50px; padding-block: var(--dee-s3);
    font-size: var(--dee-fs-base); font-weight: 600;
  }
  .dee-nav .sub-menu a {
    display: flex; align-items: center; min-height: 42px;
    font-size: var(--dee-fs-sm);
  }

  .dee-nav__service {
    margin-top: var(--dee-s5);
    padding: var(--dee-s5) var(--dee-s5) 0;
    border-top: 1px solid var(--dee-rule);
  }
  .dee-nav__servicelist a { display: flex; min-height: 40px; align-items: center; }
  .dee-nav__tel {
    display: inline-flex; align-items: center; gap: var(--dee-s2);
    font-size: var(--dee-fs-base);
  }

  /* The panel's own actions, pinned under the list rather than floating in
     the middle of it. */
  .dee-nav__cta {
    display: grid; gap: var(--dee-s3);
    margin-top: auto; padding: var(--dee-s6) var(--dee-s5) 0;
  }
  .dee-nav__cta .dee-btn { width: 100%; }
}

/* The header's action corner: two controls, spaced, never a button beside a
   hairline link.
 *
 * NO `display` here. The corner is hidden below 1200px — the burger carries
 * everything there — and a later rule setting `display: flex` at equal
 * specificity un-hides it at every width. That is the third time this exact
 * shape has shipped in this file: the top bar's phone number, and before it
 * the utility links. It put "Einstufungstest" and "Anmelden" on top of the
 * logo on a 390px phone.
 *
 * Alignment and spacing apply wherever the element is shown; whether it is
 * shown belongs to the breakpoint that decides it. */
.dee-header__actions { align-items: center; gap: var(--dee-s2); }

/* A glyph inside a button, sized to the label rather than to a grid. */
.dee-btn--icon { gap: var(--dee-s2); }
.dee-btn__icon { flex: none; }

/*
 * The account page's tabs.
 *
 * The two forms used to sit side by side, so each was about half the
 * container. One tab panel is the whole of it, and a 1000px-wide password
 * field looks like a mistake — a short form reads as a short form, and the
 * measure keeps it that way at any window size.
 */
.dee-tabs--auth .dee-tabs__panel { max-width: 34rem; }
.dee-tabs--auth .dee-tabs__list { justify-content: flex-start; }

/* The drawer is never a drawer on a wide screen.
 *
 * Marked in the markup rather than listed here. This was a hand-kept list of
 * three class names, and the identity band added to the panel was not on it:
 * it rendered on desktop as a 554px blue box between the logo and the menu,
 * pushing the header from 110px to 178px. Nothing failed, because nothing
 * asserted that the drawer's parts stay in the drawer.
 *
 * `data-drawer` says what the element is — part of the panel — so a control
 * added to the drawer is hidden here by construction, and headerphone.mjs
 * checks that every element carrying it is gone at desktop widths. */
@media (min-width: 1201px) {
  .dee-nav [data-drawer], .dee-nav__scrim { display: none; }
}

/* -------------------------------------------------------------------------
   The bar at the bottom of a phone

   Two buttons at 48px with 15px labels, each stretched to half a 390px
   screen: "WhatsApp-Beratung" does not fit on one line at that width, so it
   wrapped and the bar became 86px tall — a tenth of the viewport, permanently,
   to offer two actions.

   44px and 13px. Still above the 24px WCAG 2.5.5 target minimum with room to
   spare, and now the labels fit on one line, which is what was making them
   look oversized: a two-line button reads as a block, not a control.
   ---------------------------------------------------------------------- */
@media (max-width: 720px) {
  .dee-actionbar {
    padding: .5rem var(--dee-s3);
    padding-bottom: calc(.5rem + env(safe-area-inset-bottom, 0px));
    gap: var(--dee-s2);
  }
  .dee-actionbar .dee-btn {
    min-height: 44px;
    padding: .5rem .75rem;
    font-size: var(--dee-fs-xs);
    letter-spacing: 0;
    white-space: nowrap;
  }
  .dee-actionbar .dee-btn svg { width: 17px; height: 17px; flex: none; }
  /* The bar got shorter, so the room reserved for it does too — and it is
     only reserved on the pages that still draw one. */
  body.dee-lp { padding-bottom: 3.9rem; }

  /* Replaces the :has() version — the class is set by the same function that
     owns every other piece of drawer state, so it cannot drift, and it works
     in engines without :has(). */
  body.dee-navopen .dee-actionbar { display: none; }
}

/* The admin bar owns the top 32px --------------------------------------
 *
 * Only logged-in users see it, so this is invisible to visitors — but the
 * people reviewing this site are logged in on every visit, and the drawer's
 * sticky header (with the close button in it) was sliding underneath the
 * toolbar. "I can't close it" is exactly the report this produces, and it
 * would have been reproduced only by the two people whose opinion decides
 * whether the site ships.
 */
@media (max-width: 1200px) {
  body.admin-bar .dee-nav,
  body.admin-bar .dee-nav__scrim { top: 32px; }
}
@media screen and (max-width: 782px) {
  /* WordPress makes its own bar taller below this width. */
  body.admin-bar .dee-nav,
  body.admin-bar .dee-nav__scrim { top: 46px; }
}

/* =========================================================================
   PASS — THE INNER PAGES ON A PHONE

   Reported as "the internal pages are messy on mobile". One cause, five
   files: the course page, the placement page, the translations page, the
   contact page and the team member page each declared their two-column
   layout as an INLINE style. Inline styles win against every rule in this
   stylesheet regardless of specificity and cannot be overridden by a media
   query — so `grid-template-columns: 1fr 420px` stayed 1fr 420px at 390px
   wide, the page became 961px, and the whole site scrolled sideways with the
   right-hand column mostly off screen.

   None of this was visible in review because the preview harness only ever
   rendered the homepage, which is the one page with no such layout on it.
   ========================================================================= */

.dee-2col {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 420px);
  gap: var(--dee-s8);
  align-items: start;
}
.dee-2col--narrow { grid-template-columns: minmax(0, 1fr) minmax(0, 380px); }
.dee-2col--even   { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
.dee-2col--media  { grid-template-columns: minmax(0, 280px) minmax(0, 1fr); gap: var(--dee-s7); }

/*
 * minmax(0, …) on both tracks, not bare `1fr`.
 *
 * A grid track's default minimum is `auto`, which means "at least as wide as
 * the content" — so one long unbroken string, a wide table or a `white-space:
 * nowrap` price was enough to push a column past its share and the whole grid
 * past the viewport. That is the second half of why these pages overflowed,
 * and it would have survived the collapse below if left alone.
 */

@media (max-width: 900px) {
  .dee-2col,
  .dee-2col--narrow,
  .dee-2col--even,
  .dee-2col--media {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--dee-s6);
  }
}

/* -------------------------------------------------------------------------
   The price table becomes cards

   This is the page whose URL is printed on the school's QR codes, so it is
   the page most likely to be opened on a phone and the least forgiving place
   to hide anything. At 390px an eight-column table is 995px wide: the level
   and format were half visible, and the price and the enrolment button — the
   two things the page exists for — were entirely off screen behind a
   horizontal scroll nobody would think to try.

   Each row becomes a card and each cell a labelled line. The markup stays a
   real <table> with real <th scope> — a screen reader still hears "Kursgebühr,
   589 Euro" because the header association is in the HTML, not in the
   presentation. The visible labels come from `data-label`, which is why the
   template carries them.
   ---------------------------------------------------------------------- */

@media (max-width: 760px) {
  .dee-pricetable,
  .dee-pricetable tbody,
  .dee-pricetable tr,
  .dee-pricetable th,
  .dee-pricetable td { display: block; width: auto; }

  /* Hidden from sight, not from assistive technology: the header cells are
     what make the data cells mean anything. */
  .dee-pricetable thead {
    position: absolute; width: 1px; height: 1px;
    margin: -1px; padding: 0; overflow: hidden;
    clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
  }

  .dee-pricetable tr {
    border: 1px solid var(--dee-rule);
    border-radius: var(--dee-r-lg);
    background: var(--dee-surface);
    padding: var(--dee-s5);
    margin-bottom: var(--dee-s4);
    box-shadow: 0 1px 2px rgba(20, 32, 47, .04);
  }
  .dee-pricetable th[scope="row"] {
    min-width: 0;
    padding: 0 0 var(--dee-s3);
    margin-bottom: var(--dee-s3);
    border-bottom: 1px solid var(--dee-rule);
    font-size: var(--dee-fs-base);
  }
  .dee-pricetable td {
    display: flex; align-items: baseline; justify-content: space-between;
    gap: var(--dee-s4);
    padding: .4rem 0;
    border: 0;
    text-align: right;
  }
  .dee-pricetable td::before {
    content: attr(data-label);
    flex: none;
    font-size: var(--dee-fs-xs);
    color: var(--dee-ink-soft);
    text-align: left;
  }
  /* A cell with no label is the button cell — it gets the full width. */
  .dee-pricetable td:not([data-label]) { display: block; padding-top: var(--dee-s4); }
  .dee-pricetable td:not([data-label]) .dee-btn { width: 100%; }

  .dee-pricetable__date small { display: inline; margin-left: .35rem; }

  /* The scroll container has nothing left to scroll. */
  .dee-compare__scroll:has(.dee-pricetable) { overflow: visible; }
}

/* -------------------------------------------------------------------------
   Tables that stay tables

   The document table on the translations page and the comparison tables
   elsewhere are genuinely tabular and read fine in three or four columns —
   they just have to scroll INSIDE their container rather than taking the
   page with them. Now that the parent grid collapses they do, and this adds
   the thing that was missing: a visible edge, so a horizontal scroll is
   discoverable rather than a secret.
   ---------------------------------------------------------------------- */
.dee-compare__scroll {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior-x: contain;
  background:
    linear-gradient(to right, var(--dee-paper) 30%, rgba(251, 250, 248, 0)) left / 24px 100% no-repeat,
    linear-gradient(to left,  var(--dee-paper) 30%, rgba(251, 250, 248, 0)) right / 24px 100% no-repeat,
    radial-gradient(farthest-side at 0 50%, rgba(9, 24, 44, .16), rgba(9, 24, 44, 0)) left / 12px 100% no-repeat,
    radial-gradient(farthest-side at 100% 50%, rgba(9, 24, 44, .16), rgba(9, 24, 44, 0)) right / 12px 100% no-repeat;
  background-attachment: local, local, scroll, scroll;
}

/* -------------------------------------------------------------------------
   The footer on a phone

   Fourteen links down one column, 34px apart, ending in a right-aligned
   stack of legal links: about 1,100px of footer to scroll past. The groups
   are <details> now — expanded on a wide screen, collapsed on a narrow one,
   and always expanded when JavaScript has not run.
   ---------------------------------------------------------------------- */

.dee-footer__group { border: 0; }
.dee-footer__group > summary {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--dee-s4);
  list-style: none;                 /* Firefox */
  cursor: default;
}
.dee-footer__group > summary::-webkit-details-marker { display: none; }
.dee-footer__group > summary h2 { margin: 0; }
.dee-footer__chev { display: none; flex: none; opacity: .7; }

@media (min-width: 701px) {
  /*
   * Inert above the breakpoint. The heading is a heading again — no pointer,
   * no toggle, and no way to collapse a column in a layout that has room for
   * all of them and would look broken with one of them shut.
   */
  .dee-footer__group > summary { pointer-events: none; margin-bottom: var(--dee-s4); }
}

/*
 * The legal links read across, not down.
 *
 * Four items stacked in a right-hand column was the previous behaviour at
 * every width — inherited from `.dee-footer ul { display: grid }`, which
 * nobody had noticed applied here too. Impressum and Datenschutzerklärung are
 * required to be easy to find; a vertical stack in the corner is the opposite
 * of a row along the foot of the page.
 */
.dee-footer .dee-footer__legal {
  display: flex; flex-wrap: wrap; gap: var(--dee-s2) var(--dee-s5);
  justify-content: flex-end;
}

@media (max-width: 700px) {
  .dee-footer__cols { gap: 0; }

  .dee-footer__group {
    border-top: 1px solid rgba(255, 255, 255, .14);
  }
  .dee-footer__group > summary {
    /* 52px, so a thumb hits the row and not the four characters of the word
       in it. The whole row is the control. */
    min-height: 52px;
    padding-block: var(--dee-s3);
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
  }
  .dee-footer__chev { display: block; transition: transform .18s var(--dee-ease); }
  .dee-footer__group[open] .dee-footer__chev { transform: rotate(180deg); }

  .dee-footer__group ul { padding-bottom: var(--dee-s4); }
  .dee-footer__group li a {
    display: flex; align-items: center; min-height: 40px;
  }

  /* The address block: the phone number and the e-mail are the two things
     anybody scrolls this far for, so they become targets rather than lines
     of small print. */
  .dee-footer__cols > div:first-child address a {
    display: inline-flex; align-items: center; min-height: 40px;
  }

  .dee-footer__bottom { justify-content: center; text-align: center; }
  /*
   * flex, explicitly.
   *
   * `.dee-footer ul` sets `display: grid` for the link columns, and it is
   * (0,1,1) against this class's (0,1,0) — so it won on SPECIFICITY, not
   * source order, and `display: flex` here was silently discarded. The first
   * attempt at this fix looked correct, was correct, and did nothing: the
   * four legal links stayed one per line, which is the one part of a footer
   * a visitor has a legal right to find quickly. Hence the extra
   * `.dee-footer` — the smallest thing that outranks it.
   */
  .dee-footer .dee-footer__legal {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: var(--dee-s2) var(--dee-s5);
  }
  .dee-footer__legal a { display: inline-flex; align-items: center; min-height: 40px; }
  .dee-footer__copy { margin: 0; width: 100%; }
}

@media (prefers-reduced-motion: reduce) {
  .dee-footer__chev { transition: none; }
}

/* The agency credit — its own line, quieter than the legal links, which are
   the ones a visitor has a right to find. */
.dee-footer__credit {
  width: 100%;
  margin: var(--dee-s5) 0 0;
  padding-top: var(--dee-s4);
  border-top: 1px solid rgba(255, 255, 255, .1);
  font-size: var(--dee-fs-xs);
  color: rgba(255, 255, 255, .5);
}
.dee-footer__credit a { color: rgba(255, 255, 255, .78); text-decoration: none; }
.dee-footer__credit a:hover { color: #fff; text-decoration: underline; }

@media (max-width: 560px) {
  /*
   * Comparison tables stay tables, but they stop needing a scroll.
   *
   * These are three or four columns of two or three words — a genuine
   * side-by-side, where turning each row into a card would destroy the
   * comparison that is the entire point. What made them 481px wide on a
   * 390px screen was not the words, it was 16px of padding on each side of
   * every cell: 128px of a 350px measure spent on air. Tighter cells and one
   * step down in type and they fit, and a horizontal scroll that nobody has
   * to discover is better than the most discoverable scroll affordance.
   */
  .dee-compare__table { font-size: var(--dee-fs-xs); }
  .dee-compare__table th,
  .dee-compare__table td { padding: var(--dee-s3) var(--dee-s2); }
  .dee-compare__table th:first-child,
  .dee-compare__table td:first-child { padding-left: 0; }
  .dee-compare__table th:last-child,
  .dee-compare__table td:last-child { padding-right: 0; }
}

/*
 * The last two inline layouts.
 *
 * Neither of these overflowed anything — a one-column list and a wrapping
 * row are harmless at any width. They are moved out anyway, because the rule
 * worth keeping is "layout lives in the stylesheet", and a rule with two
 * exceptions in it is a rule nobody can test. The five that DID break the
 * site started as harmless too.
 */
.dee-contactlist {
  list-style: none; padding: 0; margin: 0;
  display: grid; gap: var(--dee-s3);
  font-size: var(--dee-fs-sm);
}
.dee-rowhead {
  display: flex; flex-wrap: wrap; align-items: baseline;
  gap: var(--dee-s4); margin-bottom: var(--dee-s5);
}

/* A fact stated inside the booking form ----------------------------------
 *
 * Where the course happens is no longer a question, but it is still the
 * thing an applicant most wants confirmed before they commit — so it reads
 * as a stated fact in the same rhythm as the steps around it, rather than
 * disappearing into a hidden field.
 */
.dee-booking__fact {
  display: grid; gap: .15rem;
  margin: 0 0 var(--dee-s5);
  padding: var(--dee-s4) var(--dee-s5);
  background: var(--dee-paper-deep);
  border: 1px solid var(--dee-rule);
  border-radius: var(--dee-r);
}
.dee-booking__factk {
  font-size: var(--dee-fs-xs); letter-spacing: .08em; text-transform: uppercase;
  color: var(--dee-ink-faint);
}
.dee-booking__fact strong { color: var(--dee-navy); }
.dee-booking__fact small { color: var(--dee-ink-soft); font-size: var(--dee-fs-sm); }

/* =========================================================================
   PASS — FILLING THE FORM IN FOUR LANGUAGES

   The site is German and English. The FORMS can be filled in German,
   English, Arabic and Chinese, because the people whose German is weakest
   are exactly the people who have to fill one in, and a form somebody cannot
   read is a form they abandon.

   The switcher is scoped to the form and never appears in the header: four
   words in the header would promise four translated sites that do not exist.
   ========================================================================= */

.dee-flang {
  display: flex; align-items: center; flex-wrap: wrap;
  gap: var(--dee-s3) var(--dee-s4);
  margin-bottom: var(--dee-s5);
  padding-bottom: var(--dee-s4);
  border-bottom: 1px solid var(--dee-rule);
}
.dee-flang__label {
  font-size: var(--dee-fs-xs); letter-spacing: .08em; text-transform: uppercase;
  color: var(--dee-ink-faint);
}
.dee-flang__list {
  display: flex; flex-wrap: wrap; gap: var(--dee-s2);
  list-style: none; margin: 0; padding: 0;
}
.dee-flang__item {
  display: inline-flex; align-items: center;
  min-height: 40px; padding: 0 var(--dee-s4);
  border: 1px solid var(--dee-rule); border-radius: var(--dee-r-full);
  font-size: var(--dee-fs-sm); font-weight: 600;
  color: var(--dee-ink-soft); text-decoration: none;
  background: var(--dee-surface);
  transition: border-color .16s var(--dee-ease), color .16s var(--dee-ease);
}
.dee-flang__item:hover { border-color: var(--dee-blue); color: var(--dee-navy); }
.dee-flang__item.is-current {
  background: var(--dee-navy); border-color: var(--dee-navy); color: #fff;
}

/*
 * Each label is set in its own script, so each needs its own family. A CJK
 * glyph rendered from a Latin webfont falls back per-character and comes out
 * a different weight and size from the text beside it; Arabic rendered from
 * a font with no Arabic coverage does the same and loses its joining.
 */
.dee-flang__item[lang="ar"] { font-family: "Noto Naskh Arabic", "Segoe UI", Tahoma, sans-serif; font-size: var(--dee-fs-base); }
.dee-flang__item[lang="zh"] { font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Noto Sans CJK SC", sans-serif; }

/* -------------------------------------------------------------------------
   The form, mirrored

   `dir` is set on the <form>, not on <html>: the page has not changed
   language, the form has. Everything below is what mirroring actually
   requires beyond the browser's own reversal — the pieces that are
   positioned, padded or aligned by hand and would otherwise stay on the
   left while the text moved right.
   ---------------------------------------------------------------------- */

[dir="rtl"].dee-form,
[dir="rtl"].dee-booking { text-align: right; }

[dir="rtl"].dee-form .dee-form__req,
[dir="rtl"].dee-booking .dee-req { margin-right: .25rem; margin-left: 0; }

[dir="rtl"].dee-booking .dee-booking__legend { text-align: right; }
[dir="rtl"].dee-booking .dee-booking__num { margin-left: var(--dee-s3); margin-right: 0; }

[dir="rtl"].dee-form .dee-form__check,
[dir="rtl"].dee-booking .dee-check { flex-direction: row-reverse; }

[dir="rtl"].dee-booking .dee-booking__errors ul,
[dir="rtl"].dee-form ul { padding-right: 1.2rem; padding-left: 0; }

/*
 * Numbers, dates, prices and IBANs stay left-to-right inside a mirrored
 * form. Arabic mirrors the sentence, not the figure: "589 €" reversed is a
 * different number, and an IBAN reversed is unusable.
 */
[dir="rtl"] .dee-booking__fee,
[dir="rtl"] .dee-booking__price,
[dir="rtl"] .dee-opt__box time,
[dir="rtl"] input[type="email"],
[dir="rtl"] input[type="tel"],
[dir="rtl"] input[type="date"] { direction: ltr; text-align: left; }

/* Scripts need their own line-height; Arabic and CJK both sit taller than
   Latin at the same size and clip against a 1.4 measure written for it. */
[lang="ar"].dee-form, [lang="ar"].dee-booking { line-height: 1.85; }
[lang="zh"].dee-form, [lang="zh"].dee-booking { line-height: 1.8; }
[lang="ar"].dee-form, [lang="ar"].dee-booking,
[lang="ar"] .dee-form__hint { font-family: "Noto Naskh Arabic", "Segoe UI", Tahoma, sans-serif; }
[lang="zh"].dee-form, [lang="zh"].dee-booking,
[lang="zh"] .dee-form__hint { font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Noto Sans CJK SC", sans-serif; }

/*
 * The seat status gets its own line.
 *
 * `.dee-opt--date .dee-opt__box` is a wrapping flex row, so the status sat
 * beside the class times whenever the two happened to fit and dropped below
 * them whenever they did not — inline on one date, on its own line on the
 * next, in the same list. It is the line that decides whether somebody can
 * book at all, so it should not be the line whose position depends on how
 * long the word "Uhr" makes the row.
 *
 * flex-basis rather than a break element: the note below it already uses the
 * same idiom, and this keeps the row a row.
 */
.dee-opt--date .dee-opt__box > small.is-free,
.dee-opt--date .dee-opt__box > small.is-low,
.dee-opt--date .dee-opt__box > small.is-wait,
.dee-opt--date .dee-opt__box > small.is-sold {
  flex: 1 0 100%;
  margin-top: .1rem;
}

/* -------------------------------------------------------------------------
   Conditional reveals that survive without JavaScript

   These panels used to carry the `hidden` attribute and were unhidden only
   by script — while the server demanded the upload regardless. With scripts
   off, choosing "I have a certificate" produced a form whose required field
   was invisible and whose submission was rejected for the missing file: an
   unresolvable loop, on the path a paying applicant most needs.

   So the default is VISIBLE, and the hiding is gated on `html.js` — set by
   the inline script in the head before first paint. No JavaScript, no
   hiding, every field on screen and usable.

   `:has()` does the work where it exists, which is every current browser;
   `.is-open` is what booking.js sets, and covers the rest.
   ---------------------------------------------------------------------- */
html.js .dee-booking__reveal { display: none; }
html.js .dee-opt:has(input:checked) + .dee-booking__reveal,
html.js .dee-booking__reveal.is-open { display: block; }

/*
 * The location panel reveals from a different shape.
 *
 * The prerequisite panels sit directly after their own `<label class="dee-opt">`,
 * so `.dee-opt:has(input:checked) + .dee-booking__reveal` reaches them. The
 * where-are-you panel sits after the whole `.dee-booking__opts` row instead —
 * so that selector matched nothing and, without JavaScript, the passport
 * field would have shown for everyone including applicants already in
 * Germany.
 */
html.js .dee-booking__opts:has(input[name="dee_location"][value="abroad"]:checked)
  + .dee-booking__reveal[data-reveal-for="abroad"] { display: block; }

/* Fields inside a reveal panel, so the visa questions read as a set. */
.dee-field { display: grid; gap: .3rem; margin: 0 0 var(--dee-s4); }
.dee-field label { font-weight: 600; font-size: var(--dee-fs-sm); color: var(--dee-navy); }
.dee-field__hint { font-size: var(--dee-fs-xs); color: var(--dee-ink-soft); }
.dee-booking__reveal .dee-check { margin-bottom: var(--dee-s4); }

/* The country field ------------------------------------------------------
 *
 * The select is the control; the search box above it is an enhancement that
 * only exists once JavaScript has added it, and only above 720px where the
 * native picker is the weaker option.
 */
.dee-country { width: 100%; }

/* The searchable country control -----------------------------------------
 *
 * A button that shows the answer, and a panel with a search box and a list.
 * The <select> is still in the DOM behind it, moved off screen — it is what
 * gets submitted, and what everybody sees if this script never runs.
 */
.dee-cc { position: relative; }
.dee-cc .dee-cc__native {
  position: absolute; width: 1px; height: 1px; margin: -1px;
  padding: 0; overflow: hidden; clip: rect(0 0 0 0); border: 0;
}

.dee-cc__flag {
  /* The subset first: on Windows the system fonts have no flag glyphs, and
     without this the pair renders as two letters. */
  font-family: "TwemojiFlags", var(--dee-font);
  font-size: 1.15em; line-height: 1; flex: none;
}

.dee-cc__button {
  display: flex; align-items: center; gap: .55rem; width: 100%;
  padding: .65rem .75rem; font: inherit; text-align: start;
  border: 1.5px solid var(--dee-rule); border-radius: var(--dee-r-sm);
  background: var(--dee-surface); color: var(--dee-navy); cursor: pointer;
}
.dee-cc__button:hover { border-color: var(--dee-rule-strong); }
.dee-cc__button:focus-visible { outline: 3px solid var(--dee-blue); outline-offset: 1px; }
.dee-cc__button.is-empty .dee-cc__value { color: var(--dee-ink-faint); }
.dee-cc__value { flex: 1 1 auto; }
.dee-cc__caret { flex: none; color: var(--dee-ink-soft); }
.dee-cc.is-open .dee-cc__button { border-color: var(--dee-blue); }

.dee-cc__panel {
  position: absolute; z-index: 30; inset-inline: 0; top: calc(100% + .3rem);
  display: flex; flex-direction: column;
  border: 1px solid var(--dee-rule-strong); border-radius: var(--dee-r);
  background: var(--dee-paper);
  box-shadow: 0 18px 40px -22px rgba(9,24,44,.55);
  overflow: hidden;
}
.dee-cc__panel[hidden] { display: none; }

.dee-cc__search {
  width: 100%; padding: .6rem .75rem; font: inherit; font-size: var(--dee-fs-sm);
  border: 0; border-bottom: 1px solid var(--dee-rule); background: var(--dee-surface);
}
.dee-cc__search:focus { outline: 0; }
.dee-cc__search::-webkit-search-cancel-button { cursor: pointer; }

.dee-cc__list {
  margin: 0; padding: .25rem; list-style: none;
  max-height: 15rem; overflow-y: auto; overscroll-behavior: contain;
}
.dee-cc__opt {
  display: flex; align-items: center; gap: .55rem;
  padding: .5rem .55rem; border-radius: var(--dee-r-sm);
  font-size: var(--dee-fs-sm); color: var(--dee-navy); cursor: pointer;
}
/* Highlight follows the KEYBOARD, and hover matches it — two different
   highlights moving independently is how a listbox starts lying about what
   Enter will do. */
.dee-cc__opt:hover,
.dee-cc__opt.is-active { background: var(--dee-blue-wash); }
.dee-cc__opt[aria-selected="true"] { font-weight: 600; }
.dee-cc__empty {
  margin: 0; padding: .9rem; font-size: var(--dee-fs-sm); color: var(--dee-ink-soft);
}
.dee-cc__empty[hidden] { display: none; }

@media (max-width: 720px) {
  /*
   * A dropdown pinned under a field near the bottom of a phone screen opens
   * into the keyboard. Full width, taller list, and it can grow upward —
   * `top` stays, but the list gets the room the panel would have wasted.
   */
  .dee-cc__list { max-height: 55vh; }
  .dee-cc__opt { padding: .7rem .6rem; }   /* 44px touch target */
}

/* The placement-test appointments ----------------------------------------
 *
 * A different shape from the course-run list above it, deliberately. A course
 * run is a decision — it carries a price, a duration, a teacher — and gets a
 * full-width row. A placement appointment is a date and a time, so the slots
 * tile: eight of them stacked full-width inside an indented reveal panel push
 * the applicant's own details off the screen, and the appointment is the less
 * important of the two.
 */
.dee-booking__opts--slots {
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  margin: var(--dee-s3) 0 var(--dee-s3);
}
.dee-booking__opts--slots .dee-opt--date .dee-opt__box {
  flex-direction: column; align-items: flex-start; gap: .15rem;
  padding: var(--dee-s3) var(--dee-s4);
}
/*
 * A full appointment IS disabled here, unlike a full course run — there is no
 * waiting list for a placement test, the school simply runs another one. So it
 * reads as unavailable rather than as a choice with a consequence.
 */
.dee-booking__opts--slots .dee-opt--date.is-sold .dee-opt__box {
  background: var(--dee-paper-deep); border-style: dashed;
}
.dee-booking__opts--slots .dee-opt--date.is-sold { cursor: not-allowed; }

/* The line under the slots: an escape hatch, so quieter than the question. */
.dee-booking__note--soft { font-size: var(--dee-fs-xs); color: var(--dee-ink-faint); }

/* =========================================================================
 * ONE QUESTION AT A TIME
 *
 * The enrolment form asks 38 things. Every one of them is needed — a school
 * enrolling somebody who may need a visa cannot ask fewer — but 3,445 pixels
 * of form on a phone is not an enrolment, it is paperwork, and the visitor
 * decides which of the two it is in the first second.
 *
 * Everything below applies only under `.dee-booking--wiz`, a class the script
 * adds. Without JavaScript none of it is in effect and the long form is
 * exactly what it was: the steps are the same fieldsets, in the same order,
 * with the same names.
 * ====================================================================== */

/* Announced, never shown. */
.dee-sr-only {
  position: absolute; width: 1px; height: 1px; margin: -1px;
  padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ---- The progress bar ---------------------------------------------------
 *
 * A row of numbered dots with their step names. On a phone the names would
 * wrap into four lines of text above a form that is trying to be short, so
 * only the current step keeps its name there — the rest are numerals.
 */
.dee-wiz__progress {
  display: flex; align-items: flex-start; gap: var(--dee-s2);
  margin: 0 0 var(--dee-s6); padding: 0; list-style: none;
  counter-reset: none;
  /*
   * The site header is sticky. Every step change scrolls this bar to the top
   * of the viewport, which without a margin is the top of the viewport UNDER
   * the header — so the visitor's first sight of each new step was the step
   * they had just left, half covered. Matches the anchor offset used for
   * sections.
   */
  scroll-margin-top: 6rem;
}
.dee-wiz__dot {
  flex: 1 1 0; display: flex; flex-direction: column; align-items: center;
  gap: .35rem; text-align: center; position: relative;
  font-size: var(--dee-fs-xs); color: var(--dee-ink-faint);
}
/* The rule between the dots, drawn from each dot to the previous one. */
.dee-wiz__dot::before {
  content: ""; position: absolute; top: 13px; right: 50%; left: -50%;
  height: 2px; background: var(--dee-rule); z-index: 0;
}
.dee-wiz__dot:first-child::before { display: none; }
.dee-wiz__dot.is-done::before,
.dee-wiz__dot.is-at::before { background: var(--dee-blue); }

.dee-wiz__dot-num {
  position: relative; z-index: 1;
  display: grid; place-items: center; width: 28px; height: 28px;
  border: 2px solid var(--dee-rule); border-radius: var(--dee-r-full);
  background: var(--dee-paper); font-weight: 600; font-size: var(--dee-fs-xs);
  color: var(--dee-ink-faint);
  transition: background-color .18s var(--dee-ease), border-color .18s var(--dee-ease), color .18s var(--dee-ease);
}
.dee-wiz__dot.is-at .dee-wiz__dot-num {
  /*
   * blue-dark, not blue.
   *
   * White on --dee-blue is 3.69:1 — under the 4.5:1 that 13px text needs, on
   * the one element in the progress bar whose whole job is saying where you
   * are. blue-dark takes it to 5.42:1 and is visually the same control.
   * The connecting rule keeps the lighter blue: it is decoration, and
   * decoration is not held to a text ratio.
   */
  border-color: var(--dee-blue-dark); background: var(--dee-blue-dark); color: #fff;
}
.dee-wiz__dot.is-done .dee-wiz__dot-num {
  border-color: var(--dee-blue); background: var(--dee-blue-wash); color: var(--dee-blue-dark);
  cursor: pointer;
}
.dee-wiz__dot.is-done { cursor: pointer; color: var(--dee-blue-dark); }
.dee-wiz__dot.is-at { color: var(--dee-navy); font-weight: 600; }
.dee-wiz__dot-label { line-height: 1.25; max-width: 12ch; }

/* The course facts, gathered into one strip under the progress bar. */
.dee-wiz__facts {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: var(--dee-s3); margin: 0 0 var(--dee-s6);
}
.dee-wiz__facts .dee-booking__fact { margin: 0; }

@media (max-width: 720px) {
  .dee-wiz__facts { grid-template-columns: 1fr; gap: var(--dee-s2); }
}

/* ---- One step visible --------------------------------------------------
 *
 * `hidden` does the hiding — the attribute, not a class — so a step is hidden
 * for assistive technology as well as visually. A step that is only visually
 * hidden is still in the tab order, and tabbing into an invisible form is
 * worse than seeing all of it.
 */
.dee-booking--wiz .dee-booking__step[hidden] { display: none; }
.dee-booking--wiz .dee-booking__step {
  border: 0; padding: 0; margin: 0;
}
/* The step number is in the progress bar now; repeating it in the legend
   says "2" twice, two centimetres apart, about different things. */
.dee-booking--wiz .dee-booking__num { display: none; }
.dee-booking--wiz .dee-booking__legend {
  font-size: var(--dee-fs-h3); margin-bottom: var(--dee-s4);
}
.dee-booking--wiz .dee-booking__legend:focus-visible {
  outline: 3px solid var(--dee-blue); outline-offset: 4px;
}

/* ---- Moving between them ------------------------------------------------ */
.dee-wiz__nav {
  display: flex; align-items: center; gap: var(--dee-s4);
  margin-top: var(--dee-s6); padding-top: var(--dee-s5);
  border-top: 1px solid var(--dee-rule);
}
/* Next sits on the right on both sides of the mirror: the forward button
   follows the reading direction, which `margin-inline-start` gives us. */
.dee-wiz__next { margin-inline-start: auto; }
.dee-wiz__back[hidden], .dee-wiz__next[hidden] { display: none; }
.dee-wiz__count { margin: 0; font-size: var(--dee-fs-sm); color: var(--dee-ink-soft); }
.dee-wiz__back:not([hidden]) + .dee-wiz__count { margin-inline-start: auto; }
.dee-wiz__back:not([hidden]) + .dee-wiz__count + .dee-wiz__next { margin-inline-start: var(--dee-s4); }

.dee-wiz__problem {
  margin: var(--dee-s5) 0 0; padding: var(--dee-s3) var(--dee-s4);
  border-left: 2px solid var(--dee-err); background: #fdf3f2; color: #7d201a;
  border-radius: 0 var(--dee-r) var(--dee-r) 0;
  font-size: var(--dee-fs-sm); font-weight: 600;
}
[dir="rtl"] .dee-wiz__problem { border-left: 0; border-right: 2px solid var(--dee-err); border-radius: var(--dee-r) 0 0 var(--dee-r); }
.dee-wiz__problem[hidden] { display: none; }

/* The field the visitor has to come back to, marked on the field itself —
   a message at the top of a step is not where the eye is. */
.dee-booking--wiz .is-invalid,
.dee-booking--wiz .is-invalid:focus {
  border-color: var(--dee-err) !important;
  box-shadow: 0 0 0 3px #fdecea;
}

/* ---- The review step ---------------------------------------------------- */
.dee-booking__summary {
  display: grid; grid-template-columns: auto 1fr; gap: .4rem var(--dee-s4);
  margin: 0 0 var(--dee-s6); padding: var(--dee-s5);
  border: 1px solid var(--dee-rule); border-radius: var(--dee-r);
  background: var(--dee-paper-deep); font-size: var(--dee-fs-sm);
}
.dee-booking__summary[hidden] { display: none; }
.dee-booking__summary dt { color: var(--dee-ink-soft); }
.dee-booking__summary dd { margin: 0; font-weight: 600; color: var(--dee-navy); }
.dee-wiz__edit {
  background: none; border: 0; padding: 0 .2rem; font: inherit;
  font-weight: 500; color: var(--dee-blue-dark); text-decoration: underline;
  cursor: pointer;
}

@media (max-width: 720px) {
  /*
   * The pair of buttons sticks to the bottom of the screen, just above the
   * action bar.
   *
   * Without this "Weiter" is the last thing on a step that can be a screen
   * and a half long, sitting in the same corner as a fixed bar offering
   * "Platz sichern" — so the primary control of the form competes with, and
   * is sometimes covered by, a shortcut past it. 3.9rem is the height the
   * action bar reserves at this breakpoint.
   */
  .dee-booking--wiz .dee-wiz__nav {
    position: sticky; bottom: calc(3.9rem + env(safe-area-inset-bottom, 0px));
    z-index: 5; margin-top: var(--dee-s5);
    padding: var(--dee-s3) var(--dee-s4);
    background: rgba(255,255,255,.97);
    border: 1px solid var(--dee-rule); border-radius: var(--dee-r);
    box-shadow: 0 -6px 24px -18px rgba(9,24,44,.45);
  }

  /* Names off, numerals on — except for where the visitor actually is. */
  .dee-wiz__dot-label { display: none; }
  .dee-wiz__dot.is-at .dee-wiz__dot-label { display: block; max-width: 16ch; }
  .dee-wiz__dot { flex: 0 0 auto; }
  .dee-wiz__dot.is-at { flex: 1 1 auto; }
  .dee-wiz__progress { gap: var(--dee-s3); }
  .dee-wiz__dot::before { display: none; }

  /* The pair of buttons is the primary control on a phone; the counter is
     already spoken by the progress bar, so it gives up its space first. */
  .dee-wiz__count { display: none; }
  .dee-wiz__nav { gap: var(--dee-s3); }
  .dee-wiz__next, .dee-wiz__back { flex: 1 1 0; justify-content: center; }
  .dee-booking__summary { grid-template-columns: 1fr; gap: .1rem; padding: var(--dee-s4); }
  .dee-booking__summary dt { margin-top: .6rem; }
  .dee-booking__summary dt:first-child { margin-top: 0; }
}

/* =========================================================================
 * THE ANMELDELISTE
 *
 * Several enrolments in one act. Styled as a list of decisions already made,
 * not as a shopping basket — no quantity steppers, no subtotal column, no
 * "proceed to payment". Nothing is paid here; the school confirms and then
 * invoices, and the visual language has to say so.
 * ====================================================================== */

/* The secondary action under the run picker.
 *
 * Hidden until the script that keeps its hidden field in step has run —
 * without it the button would post an empty run and the server would fall
 * back to the soonest one, which is not what the visitor picked. */
.dee-cart__add { display: none; }
.dee-has-cart .dee-cart__add {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--dee-s3);
  margin-top: var(--dee-s5); padding-top: var(--dee-s4);
  border-top: 1px dashed var(--dee-rule);
}
.dee-cart__add-lead { margin: 0; font-size: var(--dee-fs-sm); color: var(--dee-ink-soft); }
.dee-cart__count {
  font-size: var(--dee-fs-sm); font-weight: 600; color: var(--dee-blue-dark);
}
/* Never visible: it exists only to give the button something valid to post. */
.dee-cart__addform { display: contents; }

.dee-cart__items {
  display: grid; gap: var(--dee-s3); margin: 0 0 var(--dee-s6); padding: 0; list-style: none;
}
.dee-cart__item {
  display: flex; align-items: flex-start; gap: var(--dee-s4);
  padding: var(--dee-s4); border: 1.5px solid var(--dee-rule);
  border-radius: var(--dee-r); background: var(--dee-paper);
}
.dee-cart__item.is-sold { background: var(--dee-paper-deep); }
.dee-cart__item-main { flex: 1 1 auto; display: grid; gap: .2rem; }
.dee-cart__item-main strong { color: var(--dee-navy); }
.dee-cart__item-meta { font-size: var(--dee-fs-sm); color: var(--dee-ink-soft); }
.dee-cart__item-wait { font-size: var(--dee-fs-xs); color: var(--dee-warn); font-weight: 600; }
.dee-cart__item-price { flex: none; font-weight: 600; color: var(--dee-navy); }
.dee-cart__remove { flex: none; }
.dee-cart__remove-btn {
  background: none; border: 0; padding: .2rem; font: inherit;
  font-size: var(--dee-fs-sm); color: var(--dee-ink-soft);
  text-decoration: underline; cursor: pointer;
}
.dee-cart__remove-btn:hover { color: var(--dee-err); }

.dee-cart--empty {
  display: grid; gap: var(--dee-s4); justify-items: start;
  padding: var(--dee-s6); border: 1px dashed var(--dee-rule-strong);
  border-radius: var(--dee-r); background: var(--dee-paper-deep);
}

/* Inside the review step the list is a reminder, not a control — quieter, and
   with no remove buttons to press by mistake at the moment of committing. */
.dee-booking__step--review .dee-cart__items { gap: var(--dee-s2); }
.dee-booking__step--review .dee-cart__item {
  border: 0; border-inline-start: 2px solid var(--dee-rule); border-radius: 0;
  background: none; padding: var(--dee-s2) var(--dee-s4);
}

@media (max-width: 720px) {
  .dee-cart__item { flex-wrap: wrap; gap: var(--dee-s2); }
  .dee-cart__item-main { flex: 1 1 100%; }
  .dee-cart__remove { margin-inline-start: auto; }
  .dee-cart__add { gap: var(--dee-s2); }
  .dee-cart__add .dee-btn { width: 100%; justify-content: center; }
}

/* Rule 11 — the sittings a preparation course leads to.
 *
 * Below the enrolment form, not beside it: the course is the decision, the
 * exam is the follow-on. Renders only when the school actually has sittings,
 * so on a school that prepares but does not administer, this is never seen.
 */
.dee-exam-dates {
  margin-top: var(--dee-s6); padding: var(--dee-s5);
  border: 1.5px solid var(--dee-rule); border-radius: var(--dee-r);
  background: var(--dee-paper-deep);
}
.dee-exam-dates__title { margin: 0 0 var(--dee-s2); font-size: var(--dee-fs-h4); }
.dee-exam-dates__lead { margin: 0 0 var(--dee-s4); font-size: var(--dee-fs-sm); color: var(--dee-ink-soft); }
.dee-exam-dates__list { margin: 0; padding: 0; list-style: none; display: grid; gap: var(--dee-s3); }
.dee-exam-dates__item {
  display: flex; align-items: center; justify-content: space-between; gap: var(--dee-s4);
  padding: var(--dee-s3) var(--dee-s4); background: var(--dee-paper);
  border: 1px solid var(--dee-rule); border-radius: var(--dee-r-sm);
}
.dee-exam-dates__meta { display: block; font-size: var(--dee-fs-xs); color: var(--dee-ink-soft); }

/* The exam step's own upload sits directly under the fieldset, not in a
   reveal panel — identity is required whatever else is chosen. */
.dee-booking__step--exam > .dee-file { display: block; margin-top: var(--dee-s4); }

@media (max-width: 720px) {
  .dee-exam-dates__item { flex-wrap: wrap; }
  .dee-exam-dates__item .dee-btn { width: 100%; justify-content: center; }
}

/* =========================================================================
 * THE COURSE PAGE AS A SALES PAGE
 *
 * "Just blocks of content" — and it was. This is the vocabulary that replaces
 * the blocks: a stat bar, icon grids, a day timeline, a progress rail, a
 * qualifying checklist and a price card. One spacing rhythm across all of
 * them, so the page reads as one document rather than as six pasted widgets.
 * ====================================================================== */

.dee-cp { margin: var(--dee-s8) 0; }
.dee-cp > h2 { margin: 0 0 var(--dee-s2); font-size: var(--dee-fs-h2); }
.dee-cp__lead { margin: 0 0 var(--dee-s5); color: var(--dee-ink-soft); }
.dee-cp__source {
  margin: var(--dee-s4) 0 0; font-size: var(--dee-fs-xs); color: var(--dee-ink-faint);
}

/* The icon: one size, one stroke, inheriting colour from its context. */
.dee-ci { flex: none; color: var(--dee-blue-dark); }

/* ---- The four facts, above everything ---------------------------------- */
.dee-statbar {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: var(--dee-s3); margin: 0 0 var(--dee-s7);
  padding: var(--dee-s4); border: 1px solid var(--dee-rule);
  border-radius: var(--dee-r); background: var(--dee-paper-deep);
}
.dee-statbar__item { display: flex; align-items: flex-start; gap: var(--dee-s3); }
.dee-statbar__item strong { display: block; color: var(--dee-navy); font-size: var(--dee-fs-sm); }
.dee-statbar__item small { display: block; color: var(--dee-ink-soft); font-size: var(--dee-fs-xs); }

/* ---- Icon grids: outcomes, what's included ----------------------------- */
.dee-cp__grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: var(--dee-s5);
}
.dee-cp__grid--3 { grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); }
.dee-cp__item { display: flex; align-items: flex-start; gap: var(--dee-s3); }
.dee-cp__item strong { display: block; color: var(--dee-navy); margin-bottom: .15rem; }
.dee-cp__item p { margin: 0; font-size: var(--dee-fs-sm); color: var(--dee-ink-soft); line-height: 1.55; }

/* ---- The day, as a timeline -------------------------------------------- */
.dee-day { margin: 0; padding: 0; list-style: none; }
.dee-day__row {
  display: flex; gap: var(--dee-s5); padding: var(--dee-s4) 0;
  border-bottom: 1px solid var(--dee-rule);
}
.dee-day__row:last-child { border-bottom: 0; }
.dee-day__time {
  flex: 0 0 8.5rem; font-variant-numeric: tabular-nums;
  font-weight: 600; color: var(--dee-blue-dark); font-size: var(--dee-fs-sm);
}
.dee-day__what strong { display: block; color: var(--dee-navy); }
.dee-day__what small { display: block; color: var(--dee-ink-soft); font-size: var(--dee-fs-sm); }

/* ---- The step up ------------------------------------------------------- */
.dee-prog {
  display: flex; align-items: center; gap: var(--dee-s4);
  padding: var(--dee-s5); border: 1px solid var(--dee-rule);
  border-radius: var(--dee-r); background: var(--dee-paper);
}
.dee-prog__end { display: flex; align-items: center; gap: var(--dee-s3); flex: none; }
.dee-prog__end strong { font-size: var(--dee-fs-sm); color: var(--dee-ink-soft); font-weight: 500; }
.dee-prog__end--to strong { color: var(--dee-navy); font-weight: 600; }
.dee-prog__badge {
  display: grid; place-items: center; width: 44px; height: 44px; flex: none;
  border-radius: var(--dee-r-full); background: var(--dee-paper-deep);
  color: var(--dee-ink-soft); font-weight: 700; font-family: var(--dee-display);
}
.dee-prog__end--to .dee-prog__badge { background: var(--dee-blue-dark); color: #fff; }
.dee-prog__track { flex: 1 1 auto; display: flex; align-items: center; gap: .4rem; }
.dee-prog__track span {
  flex: 1 1 0; height: 3px; border-radius: 2px;
  background: linear-gradient(90deg, var(--dee-rule), var(--dee-blue));
}

/* ---- Does this course fit me? ------------------------------------------ */
.dee-cp__checks { margin: 0; padding: 0; list-style: none; display: grid; gap: var(--dee-s3); }
.dee-cp__checks li { display: flex; align-items: flex-start; gap: var(--dee-s3); }
.dee-cp__checks .dee-ci { color: var(--dee-ok); margin-top: .1rem; }
.dee-cp__out {
  margin: var(--dee-s5) 0 0; padding: var(--dee-s4);
  border-left: 2px solid var(--dee-blue); background: var(--dee-blue-wash);
  border-radius: 0 var(--dee-r) var(--dee-r) 0; font-size: var(--dee-fs-sm);
}
[dir="rtl"] .dee-cp__out {
  border-left: 0; border-right: 2px solid var(--dee-blue);
  border-radius: var(--dee-r) 0 0 var(--dee-r);
}

/* ---- Where it happens --------------------------------------------------- */
.dee-cp__addr { font-style: normal; margin: 0 0 var(--dee-s4); line-height: 1.6; }
.dee-cp__transport { margin: 0; padding: 0; list-style: none; display: grid; gap: var(--dee-s2); }
.dee-cp__transport li { font-size: var(--dee-fs-sm); color: var(--dee-ink-soft); }
.dee-cp__transport strong { color: var(--dee-navy); }

/* ---- The price card that replaced the form ----------------------------- */
.dee-pricecard {
  position: sticky; top: 6rem;
  padding: var(--dee-s5); border: 1.5px solid var(--dee-rule);
  border-radius: var(--dee-r); background: var(--dee-paper);
  box-shadow: 0 20px 40px -32px rgba(9,24,44,.5);
}
.dee-pricecard__name { margin: 0; font-size: var(--dee-fs-sm); color: var(--dee-ink-soft); }
.dee-pricecard__price {
  margin: .1rem 0 var(--dee-s4); font-size: var(--dee-fs-h2);
  font-weight: 700; color: var(--dee-navy); line-height: 1;
}
.dee-pricecard__facts { margin: 0 0 var(--dee-s5); display: grid; gap: .45rem; }
.dee-pricecard__facts > div { display: flex; justify-content: space-between; gap: var(--dee-s3); font-size: var(--dee-fs-sm); }
.dee-pricecard__facts dt { color: var(--dee-ink-soft); }
.dee-pricecard__facts dd { margin: 0; font-weight: 600; color: var(--dee-navy); text-align: end; }
.dee-pricecard__facts dd.is-free { color: var(--dee-ok); }
.dee-pricecard__facts dd.is-wait { color: var(--dee-warn); }
.dee-pricecard__cta { width: 100%; justify-content: center; }
.dee-pricecard__alt { width: 100%; justify-content: center; margin-top: var(--dee-s3); }
.dee-pricecard__note {
  margin: var(--dee-s4) 0 0; font-size: var(--dee-fs-xs);
  color: var(--dee-ink-faint); text-align: center;
}

/* =========================================================================
 * THE ENROLMENT PAGE
 *
 * The form on a page of its own, with the course beside it. Two columns on a
 * wide screen; on a phone the summary goes FIRST, because there it is context
 * for what follows rather than a summary of it.
 * ====================================================================== */

.dee-enrol {
  display: grid; grid-template-columns: minmax(0, 1fr) 21rem;
  gap: var(--dee-s7); align-items: start;
}
.dee-enrol__aside { display: grid; gap: var(--dee-s5); position: sticky; top: 6rem; }

.dee-yourcourse {
  padding: var(--dee-s5); border: 1.5px solid var(--dee-blue-tint);
  border-radius: var(--dee-r); background: var(--dee-blue-wash);
}
.dee-yourcourse__label {
  margin: 0 0 var(--dee-s3); font-size: var(--dee-fs-xs); font-weight: 600;
  letter-spacing: .08em; text-transform: uppercase; color: var(--dee-blue-dark);
}
.dee-yourcourse__head { display: flex; gap: var(--dee-s3); align-items: flex-start; margin-bottom: var(--dee-s4); }
.dee-yourcourse__badge {
  display: grid; place-items: center; width: 40px; height: 40px; flex: none;
  border-radius: var(--dee-r-full); background: var(--dee-blue-dark);
  color: #fff; font-weight: 700;
}
.dee-yourcourse__head strong { display: block; color: var(--dee-navy); line-height: 1.3; }
.dee-yourcourse__head small { display: block; color: var(--dee-ink-soft); font-size: var(--dee-fs-xs); }
.dee-yourcourse__facts { margin: 0 0 var(--dee-s4); display: grid; gap: .35rem; }
.dee-yourcourse__facts > div { display: flex; justify-content: space-between; gap: var(--dee-s3); font-size: var(--dee-fs-sm); }
.dee-yourcourse__facts dt { color: var(--dee-ink-soft); }
.dee-yourcourse__facts dd { margin: 0; font-weight: 600; color: var(--dee-navy); text-align: end; }
.dee-yourcourse__price {
  margin: 0; font-size: var(--dee-fs-h3); font-weight: 700; color: var(--dee-navy);
}
.dee-yourcourse__note { margin: var(--dee-s2) 0 var(--dee-s4); font-size: var(--dee-fs-xs); color: var(--dee-ink-soft); }
.dee-yourcourse__back { font-size: var(--dee-fs-sm); font-weight: 600; color: var(--dee-blue-dark); }

/* What happens after the button — the cheapest anxiety to remove. */
.dee-after {
  padding: var(--dee-s5); border: 1px solid var(--dee-rule);
  border-radius: var(--dee-r); background: var(--dee-paper-deep);
}
.dee-after__title { margin: 0 0 var(--dee-s4); font-size: var(--dee-fs-h4); }
.dee-after__list { margin: 0; padding: 0; list-style: none; display: grid; gap: var(--dee-s4); }
.dee-after__list li { display: flex; gap: var(--dee-s3); align-items: flex-start; }
.dee-after__num {
  display: grid; place-items: center; width: 26px; height: 26px; flex: none;
  border-radius: var(--dee-r-full); background: var(--dee-blue-dark); color: #fff;
  font-size: var(--dee-fs-xs); font-weight: 700;
}
.dee-after__list strong { display: block; color: var(--dee-navy); font-size: var(--dee-fs-sm); }
.dee-after__list small { display: block; color: var(--dee-ink-soft); font-size: var(--dee-fs-xs); line-height: 1.5; }

@media (max-width: 900px) {
  .dee-enrol { grid-template-columns: 1fr; }
  /*
   * The summary moves above the form on a narrow screen. Ordered, not
   * reordered in the markup: the card is what tells somebody which course
   * they are enrolling in, and below the form it answers a question they
   * have already stopped asking.
   */
  .dee-enrol__aside { position: static; order: -1; }
  .dee-after { order: 2; }
}

@media (max-width: 720px) {
  .dee-statbar { gap: var(--dee-s4); }
  .dee-day__row { flex-direction: column; gap: .2rem; }
  .dee-day__time { flex: none; }
  .dee-prog { flex-wrap: wrap; }
  .dee-prog__track { order: 3; flex: 1 0 100%; }
  .dee-pricecard { position: static; }
  .dee-cp { margin: var(--dee-s7) 0; }
}

/* =========================================================================
 * EVERY COURSE RUN, IN ONE TABLE
 *
 * Seventy rows of comparable data. A real <table>, because that is what this
 * is — and because on a phone the SAME markup becomes cards through CSS
 * alone, using the data-label each cell already carries. Ten columns cannot
 * survive 390px; the information can.
 * ====================================================================== */

.dee-runs { margin: var(--dee-s6) 0; }

/* ---- Filters ------------------------------------------------------------ */
/*
 * Flex, not a fixed six-column grid.
 *
 * The grid was `2fr repeat(4, 1fr) auto`, which assumes all four selects are
 * present — and they are not: a filter with fewer than two distinct values is
 * dropped, because a filter that cannot narrow anything is furniture. With
 * three controls the reset button landed in column four and the bar ended in a
 * third of a metre of empty box.
 *
 * Flex makes the row describe itself: the search box takes the slack, the
 * selects size to their content, and the reset is pushed to the end whatever
 * the count.
 */
.dee-runs__filters {
  display: flex; flex-wrap: wrap; align-items: end;
  gap: var(--dee-s3) var(--dee-s4);
  padding: var(--dee-s4); margin-bottom: var(--dee-s4);
  border: 1px solid var(--dee-rule); border-radius: var(--dee-r);
  background: var(--dee-paper);
}
.dee-runs__search { flex: 1 1 16rem; min-width: 12rem; }
.dee-runs__filter { flex: 0 1 11rem; }
/* Pushed to the end, and never wrapped mid-label: "Filter zurücksetzen" broke
   over two lines and doubled the height of the whole bar. */
.dee-runs__reset { margin-inline-start: auto; }
.dee-runs__reset .dee-btn { white-space: nowrap; }
/* Without the script the controls filter nothing, so they are not offered. */
.dee-runs:not(.is-live) .dee-runs__filters { display: none; }
.dee-runs__filters p { margin: 0; display: grid; gap: .3rem; }
.dee-runs__filters label { font-size: var(--dee-fs-xs); font-weight: 600; color: var(--dee-ink-soft); }
.dee-runs__filters input,
.dee-runs__filters select {
  width: 100%; padding: .55rem .7rem; font: inherit; font-size: var(--dee-fs-sm);
  border: 1px solid var(--dee-rule); border-radius: var(--dee-r-sm);
  background: var(--dee-surface);
}
.dee-runs__count { margin: 0 0 var(--dee-s3); font-size: var(--dee-fs-sm); color: var(--dee-ink-soft); }
.dee-runs:not(.is-live) .dee-runs__count { display: none; }

/* ---- The table ---------------------------------------------------------- */
.dee-runs__table {
  width: 100%; border-collapse: separate; border-spacing: 0;
  border: 1px solid var(--dee-rule); border-radius: var(--dee-r); overflow: hidden;
  font-size: var(--dee-fs-sm);
}
.dee-runs__table thead th {
  padding: var(--dee-s3) var(--dee-s4); text-align: start; vertical-align: bottom;
  background: var(--dee-navy); color: #fff; font-size: var(--dee-fs-xs);
  font-weight: 600; letter-spacing: .02em; white-space: nowrap;
}
.dee-runs__table tbody td {
  padding: var(--dee-s3) var(--dee-s4); vertical-align: middle;
  border-top: 1px solid var(--dee-rule);
}
.dee-runs__row:nth-child(even) td { background: var(--dee-paper-deep); }
.dee-runs__row:hover td { background: var(--dee-blue-wash); }
.dee-runs__row[hidden] { display: none; }
.dee-runs__table small { display: block; font-size: var(--dee-fs-xs); color: var(--dee-ink-soft); }

/* Sortable headers are buttons, so they are reachable and announceable. */
.dee-runs__sort {
  background: none; border: 0; padding: 0; font: inherit; color: inherit;
  font-weight: 600; cursor: pointer; display: inline-flex; gap: .3rem; align-items: center;
}
.dee-runs__sort span { opacity: .55; }
/* The active column's arrow is at full strength — it reports a state, where
   the others only offer an affordance. */
.dee-runs__sort.is-sorted { text-decoration: underline; text-underline-offset: 4px; }
.dee-runs__sort.is-sorted span { opacity: 1; }
.dee-runs__sort:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }

.dee-runs__level {
  display: inline-grid; place-items: center; min-width: 2.5rem; padding: .22rem .55rem;
  border-radius: var(--dee-r-sm); background: var(--dee-navy); color: #fff;
  font-family: var(--dee-display); font-weight: 700; font-size: var(--dee-fs-sm);
  letter-spacing: .02em;
}
.dee-runs__row[data-level="A1"] .dee-runs__level { background: var(--dee-lvl-a1); }
/*
 * A2 and B1 take their DARK variant here, and the other three do not.
 *
 * This badge is white type on the level colour at 15px, which needs 4.5:1.
 * Blue, violet and indigo clear it comfortably (5.2, 5.6, 8.7); emerald and
 * amber do not (3.77 and 3.19) — they are the two lightest hues in the level
 * palette and the only two that were ever going to fail. Same rule already
 * applies to the level cards' button, where somebody had noticed the amber
 * and not the green.
 */
.dee-runs__row[data-level="A2"] .dee-runs__level { background: var(--dee-lvl-a2-dark); }
.dee-runs__row[data-level="B1"] .dee-runs__level { background: var(--dee-lvl-b1-dark); }
.dee-runs__row[data-level="B2"] .dee-runs__level { background: var(--dee-lvl-b2); }
.dee-runs__row[data-level="C1"] .dee-runs__level { background: var(--dee-lvl-c1); }

.dee-runs__date strong { color: var(--dee-navy); }
.dee-runs__places { display: inline-flex; align-items: center; gap: .4rem; }
/*
 * The five things set in the display face that were still at body size and
 * had a reason not to be: the price and the level chip in the run table, a
 * course card's title, a step heading, and the related-links heading.
 *
 * The other six that measure at or below body size stay there on purpose —
 * the logo wordmark is locked to its lockup, "THEMEN" and "Preis" are labels
 * rather than values, and the enrolment step numeral lives inside a 28px
 * circle. Bricolage being a display face is not a reason to set everything
 * in it large.
 */
.dee-runs__price { font-family: var(--dee-display); font-weight: 750; font-size: var(--dee-fs-lg); color: var(--dee-navy); white-space: nowrap; }
.dee-runs__action { text-align: end; }
.dee-runs__action .dee-btn { white-space: nowrap; }

/* The availability light. Colour is never the only signal — the word beside
   it says the same thing, for colour-blind readers and for screenshots. */
.dee-runs__dot {
  display: inline-block; width: 10px; height: 10px; border-radius: 50%;
  margin-inline-end: .4rem; vertical-align: baseline;
}
.dee-runs__dot--free { background: var(--dee-signal-free); box-shadow: 0 0 0 2px rgba(16,185,129,.2); }
.dee-runs__dot--low  { background: var(--dee-signal-low); box-shadow: 0 0 0 2px rgba(245,158,11,.2); }
.dee-runs__dot--sold { background: #ef4444; box-shadow: 0 0 0 2px rgba(239,68,68,.2); }

.dee-runs__empty {
  margin: var(--dee-s5) 0 0; padding: var(--dee-s5);
  border: 1px dashed var(--dee-rule-strong); border-radius: var(--dee-r);
  background: var(--dee-paper-deep); color: var(--dee-ink-soft);
}
.dee-runs__legend {
  display: flex; flex-wrap: wrap; gap: var(--dee-s5);
  margin-top: var(--dee-s4); font-size: var(--dee-fs-xs); color: var(--dee-ink-soft);
}
.dee-runs__legend-note { margin-inline-start: auto; }

/* Narrow: the search takes its own line, the selects share the next, and the
   reset stops being pushed to the end because there is no end to push to. */
@media (max-width: 1100px) {
  .dee-runs__search { flex: 1 1 100%; }
  .dee-runs__filter { flex: 1 1 8rem; }
  .dee-runs__reset  { flex: 1 1 100%; margin-inline-start: 0; }
  .dee-runs__reset .dee-btn { width: 100%; }
}

/* ---- On a phone the table becomes cards --------------------------------
 *
 * Same markup, same data, same order. Each cell prints the column name from
 * its own data-label, so nothing has to be repeated in the HTML and nothing
 * can drift out of step with the header row.
 */
/* ---- Phone: the row becomes a card -------------------------------------
 *
 * The first attempt gave each <td> `display: contents` and let the row's own
 * two-column grid pair every label with its value. That works only while each
 * cell holds exactly ONE child, and half of them hold two — the start date is
 * a <strong> plus the weekday, the places cell is a dot plus a count plus a
 * word. Every extra child shifted the whole row by one cell, so the labels
 * marched away from their values: "Kursende" ended up beside the class times
 * and the card was actively misleading rather than merely ugly.
 *
 * So the CELL is the grid now, not the row. Each <td> is its own label/value
 * pair, and the label spans however many lines the value takes — which makes
 * the pairing structural instead of a coincidence of child counts.
 */
@media (max-width: 860px) {
  .dee-runs__table { border: 0; }
  .dee-runs__table thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
  .dee-runs__table tbody td { border: 0; background: none !important; }

  .dee-runs__row {
    display: block; margin-bottom: var(--dee-s4);
    padding: var(--dee-s4); border: 1.5px solid var(--dee-rule);
    border-radius: var(--dee-r); background: var(--dee-paper);
  }

  /*
   * The label sits ABOVE its value, not in a column beside it.
   *
   * The first version gave every cell a 8.5rem label column and painted the
   * label with `::before { content: attr(data-label) }`. Two problems the
   * client's screenshot showed in one frame: a fixed 8.5rem column is most of
   * a phone's width spent on grey words, so the values were crushed into what
   * was left; and a generated ::before cannot hold an icon, so the labels had
   * to stay bare text. Both are gone — the label is a real element now, it
   * carries its icon, and it takes only the height of one small line.
   */
  .dee-runs__row td {
    display: flex; justify-content: space-between; align-items: baseline;
    gap: var(--dee-s4); padding: .5rem 0; text-align: end;
    border-top: 1px solid var(--dee-rule);
  }
  /*
   * Label left, value right, one line each — a receipt, not a form.
   *
   * Stacking the label above its value read clearly but doubled the height of
   * every card: nine facts became eighteen lines, and a four-row table became
   * eight screens of scrolling. Side by side, the labels form a scannable
   * left edge and the values a right one.
   */
  /* The label may shrink; the VALUE may not. "Unterrichtszeiten" is a long
     word and a non-shrinking label left "Mo–Do" breaking across two lines. */
  .dee-runs__lbl {
    flex: 0 1 auto; min-width: 0; display: flex; align-items: center; gap: .4rem;
    color: var(--dee-ink-soft); font-size: var(--dee-fs-xs); font-weight: 600;
    text-align: start;
  }
  .dee-runs__lbl .dee-ci { width: 15px; height: 15px; opacity: .8; }
  /* The second line of a cell (the weekday, the UE count, the seat wording)
     rides under its value on the right, not off on its own row. */
  .dee-runs__table small { display: block; }
  .dee-runs__places { justify-content: flex-end; }
  .dee-runs__times { flex: 0 1 auto; min-width: 0; }

  /* The level badge, the course name and the button are the card's masthead
     and its action: no label, no rule, full width. */
  .dee-runs__row td:first-child,
  .dee-runs__row td:nth-child(2),
  .dee-runs__action { border-top: 0; padding: 0; }
  .dee-runs__row td:first-child .dee-runs__lbl,
  .dee-runs__row td:nth-child(2) .dee-runs__lbl,
  .dee-runs__action .dee-runs__lbl { display: none; }
  .dee-runs__row td:nth-child(2) {
    margin: .35rem 0 var(--dee-s2); font-size: var(--dee-fs-lg);
    font-weight: 700; line-height: 1.25;
  }
  .dee-runs__row td:nth-child(2) a { color: var(--dee-navy); }
  .dee-runs__action { margin-top: var(--dee-s4); }
  .dee-runs__action .dee-btn { width: 100%; justify-content: center; }

  .dee-runs__legend-note { margin-inline-start: 0; flex: 1 0 100%; }
}

/* The run-table section's standfirst, and the hub's link to it -------------
 *
 * The intro exists because the table opens with a row of filters, and a row
 * of filters under a bare heading does not say what it filters. One sentence
 * between them turns a control panel back into a section.
 */
.dee-section__intro {
  max-width: 62ch; margin: calc(var(--dee-s3) * -1) 0 var(--dee-s5);
  color: var(--dee-ink-soft); font-size: var(--dee-fs-lg); line-height: 1.55;
}
.dee-hub__dates { margin: var(--dee-s5) 0 0; }
.dee-hub__dates-count {
  margin-inline-start: var(--dee-s2); padding: .1rem .5rem;
  border-radius: 999px; background: var(--dee-blue-wash);
  color: var(--dee-navy); font-size: var(--dee-fs-xs); font-weight: 700;
}

/* ==========================================================================
   COURSE HERO · LEARNING PHASES · TAB BAR
   Added for the client's "very poor, just blocks of content" review.
   ========================================================================== */

/* ---- Hero ---------------------------------------------------------------
 *
 * Text left, media right, and the media is not decoration — it carries the
 * price badge, which is the fact the old page put furthest from the eye.
 */
.dee-chero {
  display: grid; grid-template-columns: 1.05fr .95fr;
  gap: var(--dee-s6); align-items: center;
}
/*
 * min-width: 0 — the grid item, not the heading.
 *
 * The heading already carries overflow-wrap: break-word, and it still pushed
 * the six telc pages 54px off a 390px screen: eyebrow, title, answer and the
 * "Jetzt anmelden" button all sat past the right edge, clipped. break-word
 * says how a line MAY break; it does not change the element's min-content
 * width, and a grid item's automatic minimum size IS its min-content width.
 * So "Prüfungsvorbereitung" — one 20-character word at hero size — set the
 * track to 424px inside a 350px container and took the whole column with it.
 *
 * Only the telc courses have a title long enough to do it, which is why it
 * survived every check on the intensive courses.
 */
.dee-chero__body { min-width: 0; }
.dee-chero__title { margin: var(--dee-s2) 0 var(--dee-s4); }

.dee-chero__chips { display: flex; flex-wrap: wrap; gap: var(--dee-s2); margin: 0 0 var(--dee-s4); padding: 0; list-style: none; }
.dee-chip--fact {
  display: inline-flex; align-items: center; gap: .4rem;
  padding: .35rem .7rem; border-radius: 999px;
  border: 1px solid var(--dee-rule); background: var(--dee-paper);
  font-size: var(--dee-fs-xs); font-weight: 600; color: var(--dee-ink-soft);
}
.dee-chip--fact .dee-ci { width: 16px; height: 16px; }
.dee-chip--fact.is-level { background: var(--dee-navy); border-color: var(--dee-navy); color: #fff; letter-spacing: .04em; }
/* The seat colours, the same three used by the run table's dots and the
   enrolment form's seat line. One fact, one colour, everywhere. */
.dee-chip--fact.is-free { color: var(--dee-ok);   border-color: color-mix(in srgb, var(--dee-ok) 35%, var(--dee-rule)); }
.dee-chip--fact.is-low  { color: var(--dee-warn); border-color: color-mix(in srgb, var(--dee-warn) 40%, var(--dee-rule)); }
.dee-chip--fact.is-sold { color: var(--dee-err);  border-color: color-mix(in srgb, var(--dee-err) 35%, var(--dee-rule)); }

.dee-chero__cta { display: flex; flex-wrap: wrap; gap: var(--dee-s3); margin-top: var(--dee-s5); }

.dee-chero__media {
  position: relative; margin: 0;
  border-radius: var(--dee-r); overflow: hidden;
  background: var(--dee-navy);
  /* 4:3 reserved before the image loads, so the hero never jumps. */
  aspect-ratio: 4 / 3;
}
.dee-chero__img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* The no-photograph cover. Composed, not a placeholder — see the PHP for why. */
/*
 * The drawn cover: real artwork (the CEFR-ladder SVG from
 * dee_course_cover_art), with the level/format caption layered over its
 * bottom edge.
 *
 * It replaced a flat navy panel with only a level numeral on it — accurate,
 * but every one of the ten course pages looked identical, which read as
 * "we didn't have a picture" rather than as a design choice. The ladder
 * picture is different per level, so it no longer is.
 */
.dee-chero__drawn { position: absolute; inset: 0; overflow: hidden; }
.dee-chero__art { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }

.dee-chero__caption {
  position: absolute; inset-inline-start: var(--dee-s5); inset-block-end: var(--dee-s5);
  display: flex; flex-direction: column; gap: .1rem;
}
.dee-chero__level {
  font-family: var(--dee-display); font-weight: 800;
  font-size: clamp(2.5rem, 6vw, 3.75rem); line-height: 1;
  color: #fff; letter-spacing: -0.03em;
  text-shadow: 0 2px 12px rgba(0,10,25,.35);
}
.dee-chero__format {
  color: rgba(255,255,255,.85); font-size: var(--dee-fs-sm); font-weight: 600;
  letter-spacing: .06em; text-transform: uppercase;
}

.dee-chero__badge {
  position: absolute; inset-inline-end: var(--dee-s4); inset-block-end: var(--dee-s4);
  display: grid; gap: .1rem; padding: var(--dee-s3) var(--dee-s4);
  border-radius: var(--dee-r-sm); background: #fff;
  box-shadow: 0 8px 28px rgba(0,33,71,.22);
  text-align: end;
}
.dee-chero__badge-label { font-size: var(--dee-fs-xs); font-weight: 600; color: var(--dee-ink-soft); }
.dee-chero__badge-price { font-family: var(--dee-display); font-size: var(--dee-fs-2xl); line-height: 1; color: var(--dee-navy); }
.dee-chero__badge-note { font-size: var(--dee-fs-xs); color: var(--dee-ink-soft); }

@media (max-width: 900px) {
  .dee-chero { grid-template-columns: 1fr; gap: var(--dee-s5); }
  /* Picture first on a phone: it is the thing that says what this page is
     before any text has been read. */
  .dee-chero__media { order: -1; aspect-ratio: 16 / 10; }
  .dee-chero__cta .dee-btn { flex: 1 1 100%; justify-content: center; }
  /*
   * The price badge shares the bottom edge with the level/format caption on
   * desktop because there is width to spare. A 16:10 mobile crop has none —
   * bottom-right and bottom-left collide, and the badge (three lines of
   * text) ends up sitting on top of both the caption and the artwork. Moving
   * it to the top edge gives each its own corner.
   */
  .dee-chero__badge { inset-block-start: var(--dee-s4); inset-block-end: auto; }
}

/* ---- The four learning phases ------------------------------------------ */
.dee-phases { margin: var(--dee-s6) 0; }
.dee-phases__title { margin-bottom: var(--dee-s2); }
.dee-phases__lead { max-width: 62ch; margin: 0 0 var(--dee-s5); color: var(--dee-ink-soft); }
.dee-phases__list { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--dee-s3); counter-reset: none; }

.dee-phase {
  border: 1.5px solid var(--dee-rule); border-radius: var(--dee-r);
  background: var(--dee-paper); overflow: hidden;
}
.dee-phase[open] { border-color: var(--dee-blue); background: var(--dee-surface); }
.dee-phase__head {
  display: flex; align-items: center; gap: var(--dee-s4);
  padding: var(--dee-s4); cursor: pointer;
  list-style: none;               /* Firefox */
  min-height: 48px;               /* WCAG 2.5.5 */
}
.dee-phase__head::-webkit-details-marker { display: none; }
.dee-phase__head:focus-visible { outline: 2px solid var(--dee-blue-dark); outline-offset: -3px; }

.dee-phase__num {
  flex: 0 0 auto; display: grid; place-items: center;
  width: 2.5rem; height: 2.5rem; border-radius: 50%;
  background: var(--dee-blue-wash); color: var(--dee-navy);
  font-family: var(--dee-display); font-size: var(--dee-fs-lg); line-height: 1;
}
.dee-phase[open] .dee-phase__num { background: var(--dee-navy); color: #fff; }

.dee-phase__heading { flex: 1 1 auto; display: grid; gap: .1rem; }
.dee-phase__heading strong { color: var(--dee-navy); font-size: var(--dee-fs-lg); line-height: 1.3; }
.dee-phase__heading small { color: var(--dee-ink-soft); font-size: var(--dee-fs-xs); font-weight: 600; letter-spacing: .03em; }

.dee-phase__chev { flex: 0 0 auto; color: var(--dee-ink-soft); transition: transform .2s var(--dee-ease); }
.dee-phase[open] .dee-phase__chev { transform: rotate(180deg); }

.dee-phase__body { padding: 0 var(--dee-s4) var(--dee-s4) calc(var(--dee-s4) * 2 + 2.5rem); }
.dee-phase__body > p { margin-top: 0; max-width: 68ch; color: var(--dee-ink); }
.dee-phase__cando { list-style: none; margin: var(--dee-s4) 0 0; padding: 0; display: grid; gap: var(--dee-s3); }
.dee-phase__cando li { display: flex; gap: var(--dee-s3); align-items: flex-start; }
.dee-phase__cando .dee-ci { flex: 0 0 auto; margin-top: .15rem; color: var(--dee-blue-dark); }
.dee-phase__cando strong { display: block; color: var(--dee-navy); }
.dee-phase__cando span { font-size: var(--dee-fs-sm); color: var(--dee-ink-soft); }

@media (max-width: 640px) {
  /* The numeral's indent is a luxury the narrow column cannot pay for. */
  .dee-phase__body { padding-inline-start: var(--dee-s4); }
}

/* ---- The tab bar --------------------------------------------------------
 *
 * Every hiding rule is scoped to .is-live, which only the script adds. A
 * stylesheet that arrives without its script must never be able to hide five
 * sixths of the page.
 */
.dee-tabs { margin: var(--dee-s5) 0; }
.dee-tabs__bar {
  /*
   * Under the site header, not behind it.
   *
   * `top: 0` pinned the strip to the viewport — and the header is itself
   * sticky at top:0 with z-index 100, so the tab bar slid underneath it and
   * the tabs became unreachable the moment you scrolled. 5rem clears the 79px
   * header with a hair of daylight; the header's own z-index keeps the
   * stacking order right without this having to fight it.
   */
  position: sticky; top: 5rem; z-index: 20;
  margin-bottom: var(--dee-s6);
  background: var(--dee-paper);
  border-bottom: 1px solid var(--dee-rule);
}
.dee-tabs__list {
  display: flex; gap: var(--dee-s2);
  overflow-x: auto; scrollbar-width: none;
  scroll-snap-type: x proximity;
  /*
   * A visible edge, same reasoning as `.dee-compare__scroll`: a hidden
   * scrollbar plus a hard cut at the container's edge reads as "the last
   * tab is clipped", not "swipe for more" — on a course page the row runs
   * to six tabs and the last one ("Lehrmaterial") sat flush against the
   * viewport edge with nothing to say it wasn't just cut off. The fade
   * costs nothing when the row already fits.
   */
  background:
    linear-gradient(to right, var(--dee-paper) 30%, rgba(251, 250, 248, 0)) left / 20px 100% no-repeat,
    linear-gradient(to left,  var(--dee-paper) 30%, rgba(251, 250, 248, 0)) right / 20px 100% no-repeat;
  background-attachment: local, local;
}
.dee-tabs__list::-webkit-scrollbar { display: none; }

.dee-tabs__tab {
  display: inline-flex; align-items: center; gap: .5rem;
  padding: var(--dee-s3) var(--dee-s4);
  border-bottom: 3px solid transparent;
  color: var(--dee-ink-soft); font-weight: 600; font-size: var(--dee-fs-sm);
  text-decoration: none; white-space: nowrap; scroll-snap-align: start;
  min-height: 48px;
  transition: color .18s var(--dee-ease), border-color .18s var(--dee-ease);
}
.dee-tabs__tab .dee-ci { width: 18px; height: 18px; opacity: .75; }
.dee-tabs__tab:hover { color: var(--dee-navy); border-bottom-color: var(--dee-rule-strong); }
.dee-tabs__tab.is-active { color: var(--dee-navy); border-bottom-color: var(--dee-navy); }
.dee-tabs__tab.is-active .dee-ci { opacity: 1; }
.dee-tabs__tab:focus-visible { outline: 2px solid var(--dee-blue-dark); outline-offset: -2px; border-radius: var(--dee-r-sm); }

/*
 * NO rule here hides a panel.
 *
 * That is deliberate and it is the safety property the whole design rests on.
 * Hiding is done entirely by the `hidden` attribute, which only the script
 * sets — so a stylesheet that arrives without its JavaScript cannot hide
 * anything, and a visitor whose script fails gets the complete page.
 *
 * It also has to stay this way for a second reason: the script hides panels
 * with hidden="until-found" so browser find-in-page can still reach them, and
 * an explicit `display: none` here would override that and silently take the
 * searchability back.
 *
 * The panel's own H2 is redundant with the tab that named it — kept for the
 * document outline, hidden from the eye.
 */
.dee-tabs.is-live .dee-tabs__panel-title {
  position: absolute; width: 1px; height: 1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap;
}
.dee-tabs.is-live .dee-tabs__panel:focus-visible { outline: 2px solid var(--dee-blue-dark); outline-offset: 6px; border-radius: var(--dee-r); }
/* The first section inside a panel must not add a second top margin under the
   bar — the panel is already spaced. */
.dee-tabs.is-live .dee-tabs__panel > :first-child { margin-top: 0; }

/* Not live: the bar is a table of contents, so it must not be sticky and the
   panels need separating from one another. */
.dee-tabs:not(.is-live) .dee-tabs__bar { position: static; }
.dee-tabs:not(.is-live) .dee-tabs__panel + .dee-tabs__panel {
  margin-top: var(--dee-s6); padding-top: var(--dee-s6);
  border-top: 1px solid var(--dee-rule);
}

@media (max-width: 640px) {
  .dee-tabs__tab { padding-inline: var(--dee-s3); }
  .dee-tabs__tab .dee-ci { display: none; }   /* Room for the words. */
}
@media (prefers-reduced-motion: reduce) {
  .dee-phase__chev, .dee-tabs__tab { transition: none; }
}

/* ---- Blog index ---------------------------------------------------------
 *
 * A lead post, then a grid. The old version gave every post the same size, so
 * a blog with three posts read as an empty shelf and one with thirty read as
 * an undifferentiated list.
 */
.dee-post { position: relative; }
.dee-post__media {
  display: block; position: relative; overflow: hidden;
  border-radius: var(--dee-r); background: var(--dee-navy);
  aspect-ratio: 16 / 9;
}
.dee-post__img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* The drawn cover for a post with no picture: its own initial, so the grid
   keeps its rhythm instead of collapsing into ragged text blocks. */
.dee-post__drawn {
  position: absolute; inset: 0; display: grid; place-items: center;
  background:
    radial-gradient(110% 80% at 75% 15%, color-mix(in srgb, var(--dee-blue) 50%, transparent), transparent 62%),
    linear-gradient(155deg, var(--dee-navy-deep), var(--dee-navy));
}
.dee-post__drawn span {
  font-family: var(--dee-display); font-weight: 800; color: rgba(255,255,255,.9);
  font-size: clamp(2.5rem, 6vw, 4.5rem); line-height: 1;
}

.dee-post__meta {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--dee-s3);
  margin: var(--dee-s4) 0 var(--dee-s2);
  font-size: var(--dee-fs-xs); color: var(--dee-ink-soft);
}
.dee-post__flag {
  padding: .2rem .55rem; border-radius: 999px;
  background: var(--dee-navy); color: #fff; font-weight: 700; letter-spacing: .03em;
}
.dee-post__cat { color: var(--dee-blue-dark); font-weight: 700; text-decoration: none; }
.dee-post__cat:hover { text-decoration: underline; }

/* The card picture's own overlay badges — topic and date, decorative (the
   same two facts are real text in .dee-post__meta below); see
   dee_post_badges() in inc/blog.php. */
.dee-post__badges {
  position: absolute; inset: var(--dee-s3) var(--dee-s3) auto; z-index: 1;
  display: flex; flex-wrap: wrap; gap: .4rem; pointer-events: none;
}
.dee-post__badge {
  padding: .25rem .65rem; border-radius: 999px; font-size: var(--dee-fs-xs);
  font-weight: 700; letter-spacing: .02em; color: #fff;
  background: color-mix(in srgb, var(--dee-navy-deep) 82%, transparent);
  backdrop-filter: blur(2px);
}
.dee-post__badge--date { font-weight: 500; background: color-mix(in srgb, var(--dee-ink) 55%, transparent); }

.dee-post__title { margin: 0 0 var(--dee-s2); letter-spacing: -0.025em; }
.dee-post__title a { color: var(--dee-navy); text-decoration: none; }
.dee-post__title a:hover { text-decoration: underline; text-underline-offset: 3px; }
/* The whole card is the click target, but only the title is the LINK — so the
   accessible name stays the headline rather than becoming the entire card. */
.dee-post__title a::after { content: ""; position: absolute; inset: 0; }
.dee-post__excerpt { margin: 0; color: var(--dee-ink-soft); }

/*
 * A 3:2 picture across 1.15 of the columns was taller than everything beside
 * it, so the text sat in the vertical middle of a column with a third of its
 * height empty above and below. Equal columns and a wider crop put the two
 * halves on the same scale.
 */
.dee-post--lead { display: grid; grid-template-columns: 1fr 1fr; gap: var(--dee-s6); align-items: center; margin-bottom: var(--dee-s7); }
.dee-post--lead .dee-post__media { aspect-ratio: 16 / 10; }
.dee-post--lead .dee-post__meta { margin-top: 0; }
/* --fs-2xl, not --fs-3xl: 3xl is the page's H1 size, and a lead headline set
   at the same size as the page title reads as a second page title. */
.dee-post--lead .dee-post__title { font-size: var(--dee-fs-2xl); line-height: 1.1; }
.dee-post__more { margin: var(--dee-s4) 0 0; }
.dee-post__more-link { display: inline-flex; align-items: center; gap: .4rem; color: var(--dee-blue-dark); font-weight: 700; }
.dee-post--lead:hover .dee-post__more-link { text-decoration: underline; }

.dee-postgrid { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--dee-s6) var(--dee-s5); }
.dee-post--card {
  background: var(--dee-surface);
  border: 1px solid var(--dee-rule);
  border-radius: var(--dee-r-lg);
  padding: var(--dee-s4);
  box-shadow: var(--dee-shadow-sm);
  display: flex;
  flex-direction: column;
  transition: transform .2s var(--dee-ease), box-shadow .2s var(--dee-ease), border-color .2s var(--dee-ease);
}
.dee-post--card:hover {
  transform: translateY(-4px);
  box-shadow: var(--dee-shadow-hover);
  border-color: var(--dee-blue-tint);
}
.dee-post--card .dee-post__media {
  border-radius: var(--dee-r);
  margin-bottom: var(--dee-s3);
}
.dee-post--card .dee-post__meta {
  margin-top: 0;
}
.dee-post--card .dee-post__title {
  font-family: var(--dee-display);
  font-weight: 700;
  font-size: var(--dee-fs-lg);
  line-height: 1.3;
}

@media (max-width: 900px) {
  .dee-post--lead { grid-template-columns: 1fr; gap: var(--dee-s4); }
  .dee-postgrid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 600px) {
  .dee-postgrid { grid-template-columns: 1fr; }
}

/* ---- Blog sidebar --------------------------------------------------------
 * Categories, recent posts, follow-us — see dee_blog_sidebar() in inc/blog.php
 * for why "popular posts" from the reference mockups became "recent" instead.
 * Sticky on desktop like the course page's price card, so the widgets stay
 * in view beside a long article instead of scrolling off after one screen.
 */
.dee-blog-layout {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 300px);
  gap: var(--dee-s7);
  align-items: start;
}
.dee-blog-main { min-width: 0; }
.dee-blog-aside { display: grid; gap: var(--dee-s5); position: sticky; top: 6rem; }

.dee-blog-widget {
  background: var(--dee-surface); border: 1px solid var(--dee-rule);
  border-radius: var(--dee-r-lg); padding: var(--dee-s5);
}
.dee-blog-widget__title {
  margin: 0 0 var(--dee-s4); font-size: var(--dee-fs-sm);
  text-transform: uppercase; letter-spacing: .08em; color: var(--dee-ink-soft);
}

/* The search widget reuses .dee-search (searchform.php) rather than a
   bespoke input — stacked here instead of side-by-side, because the sidebar
   column is 300px and side-by-side leaves too little room for the input to
   be usable at that width. */
.dee-blog-widget--search .dee-search { flex-direction: column; max-width: none; }
.dee-blog-widget--search .dee-btn { width: 100%; justify-content: center; }

.dee-blog-cats { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--dee-s2); }
.dee-blog-cats a {
  display: flex; align-items: center; justify-content: space-between; gap: var(--dee-s3);
  padding: .35rem 0; color: var(--dee-ink); text-decoration: none;
  border-bottom: 1px solid var(--dee-rule);
}
.dee-blog-cats li:last-child a { border-bottom: 0; }
.dee-blog-cats a:hover { color: var(--dee-blue-dark); }
.dee-blog-cats__count { font-size: var(--dee-fs-xs); color: var(--dee-ink-faint); }

.dee-blog-recent { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--dee-s4); }
.dee-blog-recent li { display: grid; gap: .2rem; }
.dee-blog-recent a { color: var(--dee-navy); font-weight: 600; text-decoration: none; }
.dee-blog-recent a:hover { color: var(--dee-blue-dark); text-decoration: underline; }
.dee-blog-recent time { font-size: var(--dee-fs-xs); color: var(--dee-ink-faint); }

/* dee-social ships styled for the dark footer (white-on-navy); this widget
   sits on a light card, so its colours are overridden rather than the shared
   component forked. */
.dee-blog-widget .dee-social { margin-top: 0; }
.dee-blog-widget .dee-social a { border-color: var(--dee-rule); color: var(--dee-ink-soft); }
.dee-blog-widget .dee-social a:hover { background: var(--dee-blue-wash); color: var(--dee-blue-dark); }

@media (max-width: 900px) {
  .dee-blog-layout { grid-template-columns: minmax(0, 1fr); }
  .dee-blog-aside { position: static; }
}

/* ---- The shared empty state --------------------------------------------
 *
 * Used by the blog today and available to anything else that can legitimately
 * have nothing in it. A blank page under a heading reads as a broken site;
 * this reads as a section that is honestly not full yet, and it offers a way
 * onward rather than a dead end.
 */
.dee-empty {
  display: grid; justify-items: center; gap: var(--dee-s3);
  max-width: 46ch; margin: var(--dee-s7) auto; padding: var(--dee-s7) var(--dee-s5);
  border: 1.5px dashed var(--dee-rule-strong); border-radius: var(--dee-r-lg);
  background: var(--dee-paper); text-align: center;
}
.dee-empty__mark {
  display: grid; place-items: center; width: 3.5rem; height: 3.5rem;
  border-radius: 50%; background: var(--dee-blue-wash); color: var(--dee-navy);
}
.dee-empty__mark .dee-ci { width: 26px; height: 26px; }
.dee-empty__title { margin: 0; font-size: var(--dee-fs-xl); }
.dee-empty__text { margin: 0 0 var(--dee-s3); color: var(--dee-ink-soft); }

/* The price card travels with the reader, beside the tabs. */
.dee-course__aside { display: grid; gap: var(--dee-s5); position: sticky; top: 6rem; }
@media (max-width: 1000px) {
  /* Stacked, and no longer sticky — a sticky card in a single column is a
     block that refuses to scroll away. */
  .dee-course__aside { position: static; margin-top: var(--dee-s6); }
}

/* ---- Icon-labelled definition terms -------------------------------------
 *
 * The price card, the course cards and the run table's phone view all print a
 * column of labelled facts. They were bare grey words; a column of those is
 * scanned as one block and read as none of them.
 */
.dee-dt__icon { display: inline-flex; margin-inline-end: .45rem; color: var(--dee-blue-dark); vertical-align: -.2em; }
.dee-dt__icon .dee-ci { width: 16px; height: 16px; }
.dee-pricecard__facts dt,
.dee-card__meta dt { display: flex; align-items: center; }
.dee-pricecard__facts dt .dee-dt__icon,
.dee-card__meta dt .dee-dt__icon { margin-inline-end: .45rem; }

/* On the desktop table the column headers already say what each cell is, so
   the per-cell labels would be a second set of headings inside the data. */
.dee-runs__lbl { display: none; }
@media (max-width: 860px) { .dee-runs__lbl { display: flex; } }

/* -------------------------------------------------------------------------
   Paying: the three ways, and the detail behind each

   A radio group where the option is the whole card rather than the twelve
   pixels of the control. This is the one question in the form where the
   answer changes what the visitor has to DO next — turn up with cash, open a
   banking app, or click a link — so each option carries a line saying which,
   and selecting one reveals the specifics underneath rather than sending
   them to look for an e-mail.
   ---------------------------------------------------------------------- */

.dee-payopts { display: grid; gap: var(--dee-s3); margin-top: var(--dee-s4); }

.dee-payopt {
  display: flex; align-items: flex-start; gap: var(--dee-s3);
  padding: var(--dee-s4);
  border: 1px solid var(--dee-rule);
  border-radius: var(--dee-r);
  background: #fff;
  cursor: pointer;
  transition: border-color .18s var(--dee-ease), box-shadow .18s var(--dee-ease);
}
.dee-payopt:hover { border-color: var(--dee-rule-strong); }
.dee-payopt input { margin-top: .2em; width: 1.15rem; height: 1.15rem; flex: none; accent-color: var(--dee-navy); }

/*
 * :has(), with a plain-checked fallback that costs nothing. Engines without
 * :has() simply show an unhighlighted but perfectly usable radio group —
 * the selection is still visible in the control itself.
 */
.dee-payopt:has(input:checked) {
  border-color: var(--dee-navy);
  box-shadow: inset 0 0 0 1px var(--dee-navy);
}
.dee-payopt:has(input:focus-visible) {
  outline: 2px solid var(--dee-blue-dark); outline-offset: 2px;
}

.dee-payopt__body { display: grid; gap: .15rem; }
.dee-payopt__label { color: var(--dee-navy); }
.dee-payopt__hint { font-size: var(--dee-fs-sm); color: var(--dee-ink-soft); }

/*
 * Hidden by the same contract the other reveal panels use: display:none only
 * once JavaScript has confirmed it is running (html.js), .is-open put on by
 * booking.js, and :has() doing it directly where it exists. With no
 * JavaScript every block is visible — longer, but nothing is unreachable.
 */
html.js .dee-paydetail { display: none; }
html.js .dee-paydetail.is-open { display: block; }

.dee-paydetail {
  margin-top: var(--dee-s4);
  padding: var(--dee-s5);
  border-radius: var(--dee-r);
  background: var(--dee-paper-alt, #f4f2ee);
  border: 1px solid var(--dee-rule);
}
.dee-paydetail__head {
  margin: 0 0 var(--dee-s3);
  font-size: var(--dee-fs-sm); text-transform: uppercase; letter-spacing: .1em;
  color: var(--dee-navy);
}
.dee-paydetail__list { display: grid; gap: var(--dee-s2); margin: 0; }
.dee-paydetail__list > div { display: flex; flex-wrap: wrap; gap: var(--dee-s2) var(--dee-s4); }
.dee-paydetail__list dt { min-width: 8rem; color: var(--dee-ink-soft); font-size: var(--dee-fs-sm); margin: 0; }
.dee-paydetail__list dd { margin: 0; font-weight: 600; color: var(--dee-navy); }
/* An IBAN is copied by eye, four characters at a time — tabular figures and
   a little tracking are the difference between that working and not. */
.dee-paydetail__list code {
  font-variant-numeric: tabular-nums; letter-spacing: .04em;
  background: none; padding: 0; font-size: 1em;
}
.dee-paydetail__addr { margin: 0 0 var(--dee-s2); font-style: normal; line-height: 1.7; }
.dee-paydetail__note { margin: var(--dee-s3) 0 0; font-size: var(--dee-fs-sm); color: var(--dee-ink-soft); }

/*
 * A German IBAN is 22 characters, 27 once it is grouped in fours — and at
 * 390px that wrapped after the fifth group, leaving "00" alone on its own
 * line. Nothing was unreadable, but a number somebody is copying digit by
 * digit into a banking app should not change shape halfway through. Slightly
 * tighter tracking and a hair smaller buys the whole thing one line.
 */
@media (max-width: 430px) {
  .dee-paydetail { padding: var(--dee-s4); }
  .dee-paydetail__list code { font-size: .92em; letter-spacing: .01em; }
  /*
   * Stack the label above its value, always.
   *
   * The row is a wrapping flex line with an 8rem label, so at this width
   * SOME values wrapped under their label and others stayed beside it,
   * depending on length — the account holder went below, the BIC stayed
   * alongside and read as though it had been indented on purpose. One
   * shape for every row is worth more here than saving four lines.
   */
  .dee-paydetail__list > div { display: block; }
  .dee-paydetail__list dt { min-width: 0; margin-bottom: .1rem; }
}

@media (prefers-reduced-motion: reduce) {
  .dee-payopt { transition: none; }
}

/* Video — hero loop and the film ----------------------------------------- */

/*
 * The loop sits exactly where the hero photograph sits, on top of it. The
 * photograph is the poster and the fallback, so there is no moment where the
 * hero is empty and no layout shift when the video arrives.
 */
.dee-hero__bgvid {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  display: block;
  border: 0;
  /* Matches the still it replaces, so the swap is not a visible jump. */
  filter: saturate(.82) contrast(1.04);
}
/*
 * Belt and braces. main.js never attaches the source under reduced motion, so
 * this rule should have nothing to hide — but if a future change attaches it
 * eagerly, the visitor's stated preference still wins here.
 */
@media (prefers-reduced-motion: reduce) {
  .dee-hero__bgvid { display: none; }
}

.dee-film__frame {
  position: relative;
  border-radius: var(--dee-r-lg);
  overflow: hidden;
  background: var(--dee-navy);
  box-shadow: var(--dee-shadow-card);
  margin-top: var(--dee-s6);
}
.dee-film__video { display: block; width: 100%; height: auto; aspect-ratio: 16 / 9; background: var(--dee-navy); }

/*
 * One button over the poster, sized as a target rather than as a glyph.
 * It is a real <button>, so it is reachable by keyboard and announces itself;
 * the film's own controls take over once it is playing.
 */
.dee-film__play {
  position: absolute; inset: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: var(--dee-s3);
  width: 100%; border: 0; cursor: pointer;
  background: linear-gradient(180deg, rgba(0, 33, 71, .12), rgba(0, 33, 71, .46));
  color: var(--dee-on-accent);
  font-family: var(--dee-display); font-weight: 700; font-size: var(--dee-fs-lg);
  transition: background .3s var(--dee-ease);
}
.dee-film__play:hover { background: linear-gradient(180deg, rgba(0, 33, 71, .2), rgba(0, 33, 71, .56)); }
.dee-film__play-icon {
  display: grid; place-items: center;
  width: 68px; height: 68px; border-radius: var(--dee-r-full);
  background: var(--dee-blue); color: var(--dee-on-accent);
  box-shadow: var(--dee-shadow-btn);
  transition: transform .3s var(--dee-ease);
}
.dee-film__play:hover .dee-film__play-icon { transform: scale(1.06); }
@media (prefers-reduced-motion: reduce) {
  .dee-film__play, .dee-film__play-icon { transition: none; }
  .dee-film__play:hover .dee-film__play-icon { transform: none; }
}

/* Course dates — the card's short list, and the full section ------------- */

/*
 * Inside the fact card the dates are a list, not a value, so the row breaks
 * to its own line rather than fighting the dt/dd columns the other facts use.
 */
.dee-pricecard__starts { display: block; }
.dee-pricecard__starts dd { margin: var(--dee-s2) 0 0; }
.dee-starts-mini { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--dee-s2); min-width: 0; }
/*
 * The seat label wraps rather than holding the row open.
 *
 * With `white-space: nowrap` on it and space-between on the row, "noch 2
 * Plätze frei" beside a date was enough to push the whole price card 4px past
 * a 390px viewport and put a horizontal scrollbar on the course page. The
 * date is the fixed part; the label is the part that gives.
 */
.dee-starts-mini__row {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--dee-s2); min-width: 0; flex-wrap: wrap;
  font-family: var(--dee-display); font-weight: 700; color: var(--dee-navy);
}
.dee-starts-mini__row > bdi { flex: none; }
.dee-starts-mini__seat {
  font-family: var(--dee-font); font-weight: 500; font-size: var(--dee-fs-xs);
  color: var(--dee-ink-soft); min-width: 0; text-align: right;
}
.dee-starts-mini__seat.is-free { color: var(--dee-ok); }
.dee-starts-mini__seat.is-low  { color: var(--dee-warn); }
.dee-starts-mini__seat.is-sold,
.dee-starts-mini__seat.is-wait { color: var(--dee-err); }
.dee-starts-mini__more {
  display: inline-block; margin-top: var(--dee-s3);
  font-size: var(--dee-fs-sm); color: var(--dee-blue-dark);
}

.dee-dates { list-style: none; margin: var(--dee-s5) 0 0; padding: 0; }
/*
 * A row, not a table. Four fields at desktop and a stack on a phone, and the
 * seat status keeps its own column so a full run reads as full before the
 * button is reached rather than after.
 */
.dee-dates__row {
  display: grid; align-items: center; gap: var(--dee-s3) var(--dee-s5);
  grid-template-columns: minmax(0, 12rem) minmax(0, 1fr) auto auto;
  padding-block: var(--dee-s4);
  border-top: 1px solid var(--dee-rule);
}
.dee-dates__row:last-child { border-bottom: 1px solid var(--dee-rule); }
.dee-dates__row.is-sold { color: var(--dee-ink-soft); }
.dee-dates__when { display: flex; flex-direction: column; }
.dee-dates__start { font-family: var(--dee-display); font-weight: 700; font-size: var(--dee-fs-lg); color: var(--dee-navy); }
.dee-dates__end   { font-size: var(--dee-fs-xs); color: var(--dee-ink-faint); }
.dee-dates__meta  { display: flex; flex-wrap: wrap; gap: var(--dee-s1) var(--dee-s4); font-size: var(--dee-fs-sm); color: var(--dee-ink-soft); }
.dee-dates__seat  { font-size: var(--dee-fs-sm); font-weight: 600; white-space: nowrap; }
.dee-dates__seat.is-free { color: var(--dee-ok); }
.dee-dates__seat.is-low  { color: var(--dee-warn); }
.dee-dates__seat.is-sold,
.dee-dates__seat.is-wait { color: var(--dee-err); }
.dee-dates__cta { white-space: nowrap; }

@media (max-width: 720px) {
  .dee-dates__row {
    grid-template-columns: 1fr auto;
    align-items: start;
  }
  .dee-dates__when { grid-column: 1; }
  .dee-dates__seat { grid-column: 2; justify-self: end; }
  .dee-dates__meta { grid-column: 1 / -1; }
  .dee-dates__cta  { grid-column: 1 / -1; justify-self: stretch; text-align: center; }
}

/* =========================================================================
 * DESIGN ENRICHMENT PASS — CHEERFUL, VIBRANT & RICH VISUAL AESTHETICS
 *
 * Implements the cheerful color highlights, modern badges, floating cards,
 * rich icon chips, and energetic level elements from the reference designs.
 * ====================================================================== */

/* 1. Cheerful Backgrounds & Section Rhythm -------------------------------- */
.dee-section--alt {
  background: linear-gradient(180deg, var(--dee-slate-wash) 0%, var(--dee-lvl-c1-tint) 50%, var(--dee-slate-wash) 100%);
  /*
   * The middle stop was written as #f0f6ff, one unit of green away from
   * --dee-lvl-c1-tint (#f0f7ff), which is the palette's name for that blue.
   * Two near-identical values is how a palette starts to drift, so this uses
   * the token. It is the only pixel this cleanup deliberately changed.
   */
}

.dee-hero:not(.dee-hero--photo) {
  background:
    radial-gradient(80% 70% at 88% 6%, rgba(37, 99, 235, .10), transparent 62%),
    radial-gradient(70% 60% at 2% 40%, rgba(5, 150, 105, .06), transparent 60%),
    linear-gradient(180deg, var(--dee-on-accent) 0%, var(--dee-slate-wash) 60%, var(--dee-blue-wash) 100%);
  color: var(--dee-ink);
}
.dee-hero:not(.dee-hero--photo) .dee-hero__title {
  color: var(--dee-navy);
}
.dee-hero:not(.dee-hero--photo) .dee-hero__title span {
  background: linear-gradient(135deg, var(--dee-blue-dark) 0%, var(--dee-blue) 50%, var(--dee-sky) 100%);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  display: inline-block;
}
.dee-hero:not(.dee-hero--photo) .dee-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: var(--dee-s2);
  padding: 0.35rem 0.9rem;
  background: var(--dee-blue-wash);
  border: 1px solid var(--dee-lvl-a1-border);
  border-radius: var(--dee-r-full);
  color: var(--dee-blue-dark);
  font-size: var(--dee-fs-xs);
  font-weight: 700;
  letter-spacing: .08em;
  box-shadow: var(--dee-shadow-sm);
}
.dee-hero:not(.dee-hero--photo) .dee-eyebrow::before {
  content: "";
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--dee-signal-free);
  box-shadow: 0 0 0 3px rgba(16, 185, 129, 0.3);
}

/* Photo Split Hero (Dark Navy Field with Split Classroom Photograph) ------
 *
 * One flat navy, not two radial glows over it.
 *
 * The glows were doing what glows do: making a flat colour look like it had
 * been considered. What they actually produced was a field whose brightness
 * changed under the headline, so the same white type sat on three different
 * greys between the eyebrow and the buttons — and a soft bright patch at the
 * lower left that competed with the photograph on the right for the eye. A
 * navy field is a stronger ground for white type than a navy field with the
 * lights on.
 */
.dee-hero--photo {
  background: var(--dee-navy);
  color: var(--dee-on-accent);
}
.dee-hero--photo .dee-hero__title {
  color: var(--dee-on-accent);
}
/*
 * The third line is a colour, not a gradient.
 *
 * `background-clip: text` with a transparent fill has two costs the effect
 * never paid for: the type is no longer a colour any contrast tool can
 * measure — it is a picture of type — and on the widest headline the ramp
 * ran out mid-word, so "erreichen." shaded lighter than "Ziele" for no
 * reason a reader could name. #7ec2ff is where the ramp started, measures
 * 8.4:1 on the navy, and is one flat, checkable value.
 */
.dee-hero--photo .dee-hero__title span {
  color: var(--dee-hero-accent);
  display: inline-block;
}
.dee-hero--photo .dee-lead {
  color: rgba(255, 255, 255, 0.92);
}
.dee-hero--photo .dee-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: var(--dee-s2);
  padding: 0.35rem 0.9rem;
  background: rgba(37, 99, 235, 0.22);
  border: 1px solid rgba(147, 197, 253, 0.35);
  border-radius: var(--dee-r-full);
  color: var(--dee-blue-pale);
  font-size: var(--dee-fs-xs);
  font-weight: 700;
  letter-spacing: .08em;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
}
.dee-hero--photo .dee-eyebrow::before {
  content: "";
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--dee-signal-free);
  box-shadow: 0 0 0 3px rgba(16, 185, 129, 0.35);
}

/*
 * The rail is a band, not four transparent boxes on a photograph.
 *
 * The four facts sat directly on whatever was behind them, and on the split
 * hero that is navy for the first two and a PHOTOGRAPH for the last two —
 * "8 Wochen" over a chair, "Zentral in Dortmund" over a wooden floor, with a
 * hard vertical seam between them where the scrim ran out. Legible on this
 * photograph, at this width, today; a different picture and it is not.
 *
 * Full-bleed by spread rather than by width: a 100vw child overflows
 * horizontally as soon as there is a scrollbar, and this element is inside a
 * centred wrap. A very large box-shadow spread with the vertical overflow
 * clipped away paints edge to edge, cannot be measured wrong, and needs no
 * change to the markup.
 */
.dee-hero--photo .dee-hero__rail {
  position: relative;
  background: var(--dee-navy-deep);
  box-shadow: 0 0 0 100vmax var(--dee-navy-deep);
  clip-path: inset(0 -100vmax);
  padding-top: var(--dee-s2);
}
.dee-hero--photo .dee-hero__rail .dee-features {
  border-top: 0;
}
.dee-hero--photo .dee-feature__k {
  color: var(--dee-on-accent);
}
.dee-hero--photo .dee-feature__v {
  color: rgba(255, 255, 255, 0.78);
}
.dee-hero--photo .dee-feature .dee-icon {
  color: var(--dee-sky-soft);
}
.dee-hero--photo .dee-feature + .dee-feature {
  border-left: 1px solid rgba(255, 255, 255, 0.14);
}

/* Google Rating Badge in Hero */
.dee-google-rating {
  box-shadow: 0 6px 20px -6px rgba(0, 33, 71, 0.14), 0 2px 6px rgba(0, 33, 71, 0.06);
  border: 1px solid rgba(0, 33, 71, 0.08);
  transition: transform .2s var(--dee-ease), box-shadow .2s var(--dee-ease);
}
.dee-google-rating:hover {
  transform: translateY(-2px);
  box-shadow: 0 12px 28px -6px rgba(0, 33, 71, 0.2);
}
.dee-google-rating__stars {
  color: var(--dee-signal-low);
}

/* 3. Value Proposition Themed Icon Chips ---------------------------------- */
.dee-prop {
  background: var(--dee-on-accent);
  border: 1px solid var(--dee-rule);
  border-top-width: 4px;
  border-radius: var(--dee-r-lg);
  box-shadow: var(--dee-shadow-card);
  transition: transform .25s var(--dee-ease), box-shadow .25s var(--dee-ease), border-color .25s var(--dee-ease);
}
.dee-prop:hover {
  /* No lift. The shadow says "raised"; the card does not also have to jump. */
  box-shadow: var(--dee-shadow-hover);
}

.dee-prop:nth-child(1) { border-top-color: var(--dee-lvl-a1); }
.dee-prop:nth-child(2) { border-top-color: var(--dee-lvl-a2); }
.dee-prop:nth-child(3) { border-top-color: var(--dee-lvl-b1); }
.dee-prop:nth-child(4) { border-top-color: var(--dee-lvl-b2); }

.dee-prop:nth-child(1):hover { border-color: var(--dee-lvl-a1-border); border-top-color: var(--dee-lvl-a1); box-shadow: var(--dee-shadow-hover); }
.dee-prop:nth-child(2):hover { border-color: var(--dee-lvl-a2-border); border-top-color: var(--dee-lvl-a2); box-shadow: var(--dee-shadow-hover); }
.dee-prop:nth-child(3):hover { border-color: var(--dee-lvl-b1-border); border-top-color: var(--dee-lvl-b1); box-shadow: var(--dee-shadow-hover); }
.dee-prop:nth-child(4):hover { border-color: var(--dee-lvl-b2-border); border-top-color: var(--dee-lvl-b2); box-shadow: var(--dee-shadow-hover); }

.dee-prop__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 52px;
  height: 52px;
  border-radius: 14px;
  margin-bottom: var(--dee-s4);
  box-shadow: 0 2px 6px rgba(0, 33, 71, 0.04);
}
.dee-prop:nth-child(1) .dee-prop__icon { background: var(--dee-blue-wash); border: 1px solid var(--dee-lvl-a1-border); color: var(--dee-blue); }
.dee-prop:nth-child(2) .dee-prop__icon { background: var(--dee-lvl-a2-tint); border: 1px solid var(--dee-lvl-a2-border); color: var(--dee-lvl-a2); }
.dee-prop:nth-child(3) .dee-prop__icon { background: var(--dee-lvl-b1-tint); border: 1px solid var(--dee-lvl-b1-border); color: var(--dee-lvl-b1); }
.dee-prop:nth-child(4) .dee-prop__icon { background: var(--dee-lvl-b2-tint); border: 1px solid var(--dee-lvl-b2-border); color: var(--dee-lvl-b2); }

/* 4. Level Cards (A1 - C1) Rich Polish ------------------------------------ */
.dee-level {
  background: var(--dee-on-accent);
  border: 1px solid var(--dee-rule);
  border-top-width: 4px;
  border-radius: var(--dee-r-lg);
  box-shadow: var(--dee-shadow-card);
  transition: transform .25s var(--dee-ease), box-shadow .25s var(--dee-ease), border-color .25s var(--dee-ease);
}
.dee-level:hover {
  /* No lift. The shadow says "raised"; the card does not also have to jump. */
}

.dee-level[data-level="A1"]:hover { border-color: var(--dee-lvl-a1-border); border-top-color: var(--dee-lvl-a1); box-shadow: var(--dee-shadow-hover); }
.dee-level[data-level="A2"]:hover { border-color: var(--dee-lvl-a2-border); border-top-color: var(--dee-lvl-a2); box-shadow: var(--dee-shadow-hover); }
.dee-level[data-level="B1"]:hover { border-color: var(--dee-lvl-b1-border); border-top-color: var(--dee-lvl-b1); box-shadow: var(--dee-shadow-hover); }
.dee-level[data-level="B2"]:hover { border-color: var(--dee-lvl-b2-border); border-top-color: var(--dee-lvl-b2); box-shadow: var(--dee-shadow-hover); }
.dee-level[data-level="C1"]:hover { border-color: var(--dee-lvl-c1-border); border-top-color: var(--dee-lvl-c1); box-shadow: var(--dee-shadow-hover); }

/*
 * NOT redundant, however identical these look to the pair at the top of the
 * file. Between the two sits `.dee-level.is-featured { border-top-color:
 * var(--dee-blue) }`, at equal specificity — so without this re-assertion the
 * featured B2 card loses its violet edge and turns brand blue. Deleting these
 * as duplicates is a change a screenshot diff catches and a code review does
 * not.
 */
.dee-level[data-level="A1"] { border-top-color: var(--dee-lvl-a1); }
.dee-level[data-level="A2"] { border-top-color: var(--dee-lvl-a2); }
.dee-level[data-level="B1"] { border-top-color: var(--dee-lvl-b1); }
.dee-level[data-level="B2"] { border-top-color: var(--dee-lvl-b2); }
.dee-level[data-level="C1"] { border-top-color: var(--dee-lvl-c1); }

.dee-level[data-level="A1"] .dee-level__badge { color: var(--dee-lvl-a1); }
.dee-level[data-level="A2"] .dee-level__badge { color: var(--dee-lvl-a2); }
.dee-level[data-level="B1"] .dee-level__badge { color: var(--dee-lvl-b1); }
.dee-level[data-level="B2"] .dee-level__badge { color: var(--dee-lvl-b2); }
.dee-level[data-level="C1"] .dee-level__badge { color: var(--dee-lvl-c1); }

/* Solid Level CTA Action Buttons */
.dee-level .dee-level__link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--dee-s2);
  font-size: var(--dee-fs-sm);
  font-weight: 700;
  padding: .65rem 1.1rem;
  border-radius: var(--dee-r);
  text-decoration: none;
  margin-top: var(--dee-s4);
  color: var(--dee-on-accent);
  transition: all .2s var(--dee-ease);
}
.dee-level[data-level="A1"] .dee-level__link { background: var(--dee-lvl-a1); color: var(--dee-on-accent); border: 1px solid var(--dee-lvl-a1); box-shadow: var(--dee-shadow-btn); }
/* Emerald, for the same reason amber below it already was. */
.dee-level[data-level="A2"] .dee-level__link { background: var(--dee-lvl-a2-dark); color: var(--dee-on-accent); border: 1px solid var(--dee-lvl-a2-dark); box-shadow: var(--dee-shadow-btn); }
.dee-level[data-level="B1"] .dee-level__link { background: var(--dee-lvl-b1-dark); color: var(--dee-on-accent); border: 1px solid var(--dee-lvl-b1-dark); box-shadow: var(--dee-shadow-btn); }
.dee-level[data-level="B2"] .dee-level__link { background: var(--dee-lvl-b2); color: var(--dee-on-accent); border: 1px solid var(--dee-lvl-b2); box-shadow: var(--dee-shadow-btn); }
.dee-level[data-level="C1"] .dee-level__link { background: var(--dee-lvl-c1); color: var(--dee-on-accent); border: 1px solid var(--dee-lvl-c1); box-shadow: var(--dee-shadow-btn); }

.dee-level[data-level="A1"]:hover .dee-level__link { background: var(--dee-lvl-a1-dark); color: var(--dee-on-accent); border-color: var(--dee-lvl-a1-dark); box-shadow: var(--dee-shadow); }
.dee-level[data-level="A2"]:hover .dee-level__link { background: var(--dee-lvl-a2-dark); color: var(--dee-on-accent); border-color: var(--dee-lvl-a2-dark); box-shadow: var(--dee-shadow); }
.dee-level[data-level="B1"]:hover .dee-level__link { background: var(--dee-lvl-b1-deep); color: var(--dee-on-accent); border-color: var(--dee-lvl-b1-deep); box-shadow: var(--dee-shadow); }
.dee-level[data-level="B2"]:hover .dee-level__link { background: var(--dee-lvl-b2-dark); color: var(--dee-on-accent); border-color: var(--dee-lvl-b2-dark); box-shadow: var(--dee-shadow); }
.dee-level[data-level="C1"]:hover .dee-level__link { background: var(--dee-lvl-c1-dark); color: var(--dee-on-accent); border-color: var(--dee-lvl-c1-dark); box-shadow: var(--dee-shadow); }

/* Featured Tag (B2) */
.dee-level__flag {
  position: absolute;
  top: var(--dee-s3);
  right: var(--dee-s3);
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: .02em;
  padding: .3rem .75rem;
  border-radius: var(--dee-r-full);
  background: linear-gradient(135deg, var(--dee-signal-low), var(--dee-lvl-b1));
  color: var(--dee-on-accent);
  box-shadow: var(--dee-shadow-btn);
  border: 1px solid rgba(255, 255, 255, 0.4);
}

/* 5. Services Cards Polish ------------------------------------------------ */
.dee-service:nth-child(1) { border-top-color: var(--dee-lvl-a1); }
.dee-service:nth-child(2) { border-top-color: var(--dee-lvl-a2); }
.dee-service:nth-child(3) { border-top-color: var(--dee-lvl-b1); }

.dee-service:nth-child(1):hover { border-color: var(--dee-lvl-a1-border); border-top-color: var(--dee-lvl-a1); box-shadow: var(--dee-shadow-hover); }
.dee-service:nth-child(2):hover { border-color: var(--dee-lvl-a2-border); border-top-color: var(--dee-lvl-a2); box-shadow: var(--dee-shadow-hover); }
.dee-service:nth-child(3):hover { border-color: var(--dee-lvl-b1-border); border-top-color: var(--dee-lvl-b1); box-shadow: var(--dee-shadow-hover); }

.dee-service:nth-child(1) .dee-service__icon { background: var(--dee-blue-wash); border: 1px solid var(--dee-lvl-a1-border); color: var(--dee-blue); }
.dee-service:nth-child(2) .dee-service__icon { background: var(--dee-lvl-a2-tint); border: 1px solid var(--dee-lvl-a2-border); color: var(--dee-lvl-a2); }
.dee-service:nth-child(3) .dee-service__icon { background: var(--dee-lvl-b1-tint); border: 1px solid var(--dee-lvl-b1-border); color: var(--dee-lvl-b1); }

/* 6. Process Step Flow Circular Badges ------------------------------------ */
.dee-steps__num {
  font-family: var(--dee-display);
  font-weight: 800;
  font-size: 1.15rem;
  color: var(--dee-on-accent);
  line-height: 1;
  letter-spacing: -0.02em;
  width: 44px;
  height: 44px;
  border-radius: var(--dee-r-full);
  background: linear-gradient(135deg, var(--dee-blue) 0%, var(--dee-blue-dark) 100%);
  border: 3px solid var(--dee-blue-wash);
  box-shadow: var(--dee-shadow-btn);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  margin-top: .15rem;
}

/* 7. Course Runs Table High-Contrast Polish ------------------------------- */
.dee-runs__table thead th {
  background: var(--dee-navy);
  color: var(--dee-on-accent);
  padding: var(--dee-s3) var(--dee-s4);
}

/* 8. Single Course Price Card & CTA Button -------------------------------- */
.dee-pricecard {
  border-top: 4px solid var(--dee-blue);
  box-shadow: var(--dee-shadow-card);
}
.dee-pricecard__price {
  color: var(--dee-navy);
}
.dee-pricecard__cta {
  background: var(--dee-blue);
  border-color: var(--dee-blue);
  color: var(--dee-on-accent);
  box-shadow: var(--dee-shadow-btn);
}
.dee-pricecard__cta:hover {
  background: var(--dee-blue-dark);
  border-color: var(--dee-blue-dark);
  box-shadow: var(--dee-shadow);
  color: var(--dee-on-accent);
}

/* 9. Blog Cards Polish ---------------------------------------------------- */
.dee-post--card {
  box-shadow: var(--dee-shadow-card);
  transition: transform .25s var(--dee-ease), box-shadow .25s var(--dee-ease), border-color .25s var(--dee-ease);
}
.dee-post--card:hover {
  /* No lift. The shadow says "raised"; the card does not also have to jump. */
  box-shadow: var(--dee-shadow-hover);
  border-color: var(--dee-blue-tint);
}

/* =========================================================================
   PASS — THE HERO ON A PHONE

   Measured, not felt: at 390px the hero was 1668px tall and at 320px it was
   1896px. Four screens of hero before the first course. The parts are all
   correct individually — this is what they do when a layout designed as a
   side-by-side composition becomes a single column and every piece keeps its
   desktop proportions.

   Nothing is removed. The three numbers a visitor came for, the four facts
   and the rating all stay; they stop each taking a screen to say it.
   ========================================================================= */

@media (max-width: 720px) {
  /*
   * Two columns, not four rows.
   *
   * .dee-features is repeat(auto-fit, minmax(190px, 1fr)) — right for the
   * page, wrong here: at 350px of content 190px resolves to exactly one
   * column, so four short facts became four full-width rows of ~95px. As a
   * 2×2 grid the same four facts take half the height and read as a block
   * rather than as a list that will not end.
   */
  .dee-hero__rail .dee-features { grid-template-columns: 1fr 1fr; }
  .dee-hero__rail .dee-feature { padding: var(--dee-s4) var(--dee-s3); }
  .dee-hero__rail .dee-feature__k { font-size: var(--dee-fs-base); }

  /*
   * The 2×2 needs its rules on both axes. The stacked rule that the
   * one-column stack used sat only between siblings, which on a grid draws
   * a line down the middle of the pair instead of around it.
   */
  .dee-hero--photo .dee-hero__rail .dee-feature + .dee-feature { border-top: 0; }
  .dee-hero--photo .dee-hero__rail .dee-feature:nth-child(n + 3) {
    border-top: 1px solid rgba(255, 255, 255, .18);
  }
  .dee-hero--photo .dee-hero__rail .dee-feature:nth-child(even) {
    border-left: 1px solid rgba(255, 255, 255, .18);
  }
}

/*
 * Below 360 the pair is 140px per cell, which breaks "Präsenz & Online"
 * across three lines and costs back everything the grid saved. One column
 * again, but with the tighter padding.
 */
@media (max-width: 359px) {
  .dee-hero__rail .dee-features { grid-template-columns: 1fr; }
  .dee-hero--photo .dee-hero__rail .dee-feature:nth-child(even) { border-left: 0; }
  .dee-hero--photo .dee-hero__rail .dee-feature + .dee-feature {
    border-top: 1px solid rgba(255, 255, 255, .18);
  }
}

/*
 * The rating chip stops being a lozenge.
 *
 * The old rule pushed the review count onto its own line with
 * flex-basis:100%, so the chip became three lines and 95px tall — while
 * keeping a 999px radius, which on a 95px box is not a pill, it is a
 * capsule with nothing in the corners. The count now stays inline and the
 * radius drops to the card radius, so a chip that does wrap still looks
 * like a chip.
 */
@media (max-width: 480px) {
  .dee-google-rating {
    border-radius: var(--dee-r-lg);
    padding: var(--dee-s3) var(--dee-s4);
    gap: var(--dee-s2);
  }
  .dee-google-rating__count { flex-basis: auto; font-size: var(--dee-fs-xs); }
  .dee-google-rating__text { font-size: var(--dee-fs-xs); }
}

/*
 * The card stops repeating the rail.
 *
 * Below the rail's breakpoint the two sit one under the other, so "A1 – C1"
 * and the format are each stated twice inside 400 vertical pixels. The rail
 * keeps them — it is the more compact of the two and it is where they read
 * as a caption — and the card keeps what only it has: the date, the price,
 * the group size and the free placement test.
 */
@media (max-width: 720px) {
  .dee-herofacts__row.is-echoed { display: none; }

  /*
   * With two rows gone the card's desktop padding is the remaining bulk:
   * 24px above the date, 16px around each row and 32px under the note, on a
   * 350px-wide card.
   */
  .dee-herofacts__list { padding-inline: var(--dee-s5); }
  .dee-herofacts__row { padding-block: var(--dee-s3); }
  .dee-herofacts__row.is-lead { padding: var(--dee-s5) var(--dee-s5) var(--dee-s4); }
  .dee-herofacts__note { padding: var(--dee-s3) var(--dee-s5) var(--dee-s5); }
}

/*
 * The eyebrow is a tag, not a capsule.
 *
 * Same failure as the rating chip: a 999px radius is a pill only while the
 * content is one line. "Deutsch-Intensivkurse A1 – C1 · Dortmund & Online"
 * wraps to two on a phone, and a 999px radius on a two-line box puts a
 * semicircle on each end of a rectangle.
 */
@media (max-width: 560px) {
  .dee-hero .dee-eyebrow { border-radius: var(--dee-r-md); }
}

/*
 * The Google mark inside the rating badge.
 *
 * flex:none so it never shrinks when the sentence beside it wraps, and no
 * colour of our own: the four fills are the trademark and inheriting the
 * badge's ink would quietly turn it into a grey letter.
 */
.dee-gmark { flex: none; display: block; }
.dee-google-rating .dee-gmark { margin-inline-end: 1px; }

/*
 * A hairline between the mark and the stars.
 *
 * Without it the G reads as the first of six glyphs in one row — a logo, five
 * stars — instead of as the source the stars belong to. The rule says "this
 * rating, from that service" in one pixel.
 */
.dee-google-rating__stars {
  padding-inline-start: var(--dee-s3);
  border-inline-start: 1px solid var(--dee-rule);
}
@media (max-width: 480px) {
  .dee-google-rating__stars { padding-inline-start: var(--dee-s2); }
}

/* =========================================================================
   PASS — THE THREE THINGS THE CLIENT MARKED UP

   1  The dates on the price card
   2  The service block in the drawer
   3  A stack of contact actions rather than one bubble
   ========================================================================= */

/* 1 — The dates become a panel of choices --------------------------------
 *
 * "This is the basis on which a person picks and books the date" — and it
 * was the densest, flattest part of the card: a label, three lines of text,
 * and a link, all sharing the card's ground. It now reads as its own block
 * and every row is the choice it looks like.
 */
.dee-pricecard__facts > .dee-pricecard__starts {
  /*
   * `display: block`, and the selector has to match the one it is beating:
   * `.dee-pricecard__facts > div` sets flex at (0,2,1), so a bare
   * `.dee-pricecard__starts` at (0,1,0) lost silently and the block stayed a
   * two-column fact row.
   *
   * The fact rows are flex — label left, value right — and this block was
   * one of them, so "Nächste Termine" took a 111px column and left the dates
   * 213px. Every row then wrapped its seat label onto a second line and each
   * date came out 74px tall. Full width, label above, and the three rows fit
   * on one line each.
   */
  display: block;
  background: var(--dee-paper-deep);
  border: 1px solid var(--dee-rule);
  border-radius: var(--dee-r-md);
  padding: var(--dee-s4);
  margin-block: var(--dee-s2);
}
.dee-pricecard__starts dt { margin-bottom: var(--dee-s3); }
/* The fact rows right-align their values; a list of choices reads left. */
.dee-pricecard__facts .dee-pricecard__starts dd { margin: 0; text-align: start; }
.dee-starts-mini { gap: var(--dee-s1); }

.dee-starts-mini__row {
  /* A row that is a link needs the target size of one. */
  min-height: 40px;
  padding: var(--dee-s2) var(--dee-s3);
  border-radius: var(--dee-r-sm);
  background: var(--dee-surface);
  border: 1px solid transparent;
  text-decoration: none;
  transition: border-color .15s var(--dee-ease), background-color .15s var(--dee-ease);
}
.dee-starts-mini__row:hover,
.dee-starts-mini__row:focus-visible {
  border-color: var(--dee-blue);
  background: var(--dee-surface);
  text-decoration: none;
}
/*
 * The arrow appears on hover on a pointer device and is always there on a
 * touch one, where there is no hover to reveal it and the affordance has to
 * be visible at rest.
 */
.dee-starts-mini__go {
  flex: none; display: inline-flex; color: var(--dee-blue-dark);
  opacity: 0; transition: opacity .15s var(--dee-ease);
}
.dee-starts-mini__go svg { width: 16px; height: 16px; }
.dee-starts-mini__row:hover .dee-starts-mini__go,
.dee-starts-mini__row:focus-visible .dee-starts-mini__go { opacity: 1; }
@media (hover: none) {
  .dee-starts-mini__go { opacity: .55; }
}
/* space-between already puts it right; auto margin fought the wrap. */
.dee-starts-mini__row .dee-starts-mini__seat { margin-inline-start: 0; }
.dee-starts-mini__more { margin-top: var(--dee-s2); }

/* 2 — The service block in the drawer ------------------------------------
 *
 * The heading now names what is in the box (i18n: nav_service), and the
 * number is framed as the action it has always been: an icon chip, a label
 * saying what pressing it does, and the number itself — at 48px, which is
 * a touch target rather than a line of bold text.
 */
.dee-nav__tel {
  display: flex; align-items: center; gap: var(--dee-s3);
  min-height: 48px; padding: var(--dee-s3) var(--dee-s4);
  border: 1px solid var(--dee-rule); border-radius: var(--dee-r-md);
  background: var(--dee-surface); color: var(--dee-navy);
  text-decoration: none;
}
.dee-nav__tel:hover, .dee-nav__tel:focus-visible {
  border-color: var(--dee-blue); text-decoration: none;
}
.dee-nav__tel-icon {
  flex: none; display: grid; place-items: center;
  width: 34px; height: 34px; border-radius: var(--dee-r-full);
  background: var(--dee-blue-tint, rgba(22,134,239,.12)); color: var(--dee-blue-dark);
}
.dee-nav__tel-text { display: grid; min-width: 0; }
.dee-nav__tel-label {
  font-family: var(--dee-font); font-weight: 500;
  font-size: var(--dee-fs-xs); color: var(--dee-ink-soft);
}
.dee-nav__tel-num {
  font-family: var(--dee-display); font-weight: 700;
  font-size: var(--dee-fs-base); color: var(--dee-navy);
}

/* Identity, at the top of the drawer ---------------------------------------
 *
 * A band rather than a card. The phone card below is one of several actions
 * in a list and reads as a card correctly; this is the panel's header — it
 * answers "am I signed in, and as whom" before the reader looks at anything
 * else — so it is full-bleed against the top of the panel with a rule under
 * it, the same way the panel's own title sits above it.
 */
.dee-nav__me {
  padding: var(--dee-s4) var(--dee-s5);
  border-bottom: 1px solid var(--dee-rule);
  background: var(--dee-blue-wash);
}
.dee-nav__meinfo {
  display: flex; align-items: center; gap: var(--dee-s3);
  min-height: 44px; color: var(--dee-navy);
}
.dee-nav__meicon {
  flex: none; display: grid; place-items: center;
  width: 40px; height: 40px; border-radius: var(--dee-r-full);
  background: var(--dee-navy); color: var(--dee-on-accent);
  font-family: var(--dee-display); font-weight: 700;
  font-size: var(--dee-fs-sm); letter-spacing: .02em;
}
.dee-nav__metext { display: grid; min-width: 0; flex: 1 1 auto; }
.dee-nav__melabel {
  font-family: var(--dee-font); font-weight: 500;
  font-size: var(--dee-fs-xs); color: var(--dee-ink-soft);
}
/*
 * A display name is arbitrary text, unlike a phone number: one word, a full
 * name with a title, or an email address when the account has no name set,
 * in a panel 320px wide on the narrowest phone. One line, ellipsised.
 */
.dee-nav__mename {
  font-family: var(--dee-display); font-weight: 700;
  font-size: var(--dee-fs-base); color: var(--dee-navy);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.dee-nav__mego { flex: none; color: var(--dee-ink-soft); display: grid; place-items: center; }

/*
 * The caption that names the zone. Without it the band read as a stray
 * button floating above the menu rather than as the account area.
 */
.dee-nav__mecap {
  margin: 0 0 var(--dee-s2);
  font-family: var(--dee-font); font-weight: 600;
  font-size: var(--dee-fs-xs); letter-spacing: .08em; text-transform: uppercase;
  color: var(--dee-ink-soft);
}

/*
 * Two actions, side by side and equal — sign in and create an account are
 * equal choices, and so are the account and signing out. The secondary used
 * to be an underlined link, which made one of each pair look like a footnote.
 *
 * `1fr 1fr` rather than auto: the German and English labels differ in length
 * ("Konto erstellen" against "Create account"), and equal columns keep the
 * pair from re-weighting itself per language.
 */
.dee-nav__meactions {
  display: grid; grid-template-columns: 1fr 1fr; gap: var(--dee-s2);
  margin-top: var(--dee-s3);
}
.dee-nav__meactions .dee-btn { width: 100%; text-align: center; justify-content: center; }
/* Below this the two labels stop fitting side by side and stack instead. */
@media (max-width: 359px) {
  .dee-nav__meactions { grid-template-columns: 1fr; }
}

/*
 * Sign out, and its signed-out twin "create an account", sit inside the band
 * — the one action that only means anything next to the name above it.
 */
.dee-nav__signout {
  display: inline-flex; align-items: center;
  min-height: 24px; margin-top: var(--dee-s2);
  font-size: var(--dee-fs-sm); font-weight: 500;
  color: var(--dee-ink-soft); text-decoration: underline;
  text-underline-offset: 3px;
}
.dee-nav__signout:hover, .dee-nav__signout:focus-visible { color: var(--dee-navy); }

/* 3 — Two stacked actions in the corner ----------------------------------
 *
 * The wrapper takes the fixed position the WhatsApp pill used to hold, so
 * the two sit as one stack and the pill stops positioning itself.
 */
/*
 * Down the right-hand edge, vertically centred — not tucked into the corner.
 *
 * The corner is where a chat bubble goes and people have learned to ignore
 * it. The edge is where the competitor put theirs and where the client kept
 * pointing, and it has one practical advantage on a phone: it is clear of
 * the browser's own bottom chrome and of the home indicator, both of which
 * eat the bottom 80px of a real device and neither of which shows up in a
 * screenshot taken in a desktop browser.
 */
.dee-actions {
  position: fixed; right: 1rem; top: 50%; transform: translateY(-50%); z-index: 90;
  display: grid; gap: var(--dee-s3); justify-items: end;
}

/*
 * …and never on a phone, where the bar takes over.
 *
 * This hide lives next to the rule it overrides rather than up in the phone
 * section beside the bar it replaces. Written there it LOST — `.dee-actions`
 * is declared further down the file at equal specificity, so the later rule
 * won and the phone drew both. Fourth time in this stylesheet that a hide has
 * been placed above the thing it hides.
 */
@media (max-width: 720px) {
  .dee-actions { display: none; }
}

.dee-actions .dee-wa { position: static; right: auto; bottom: auto; z-index: auto; }

/*
 * Discs at rest, labelled on hover and on focus.
 *
 * The file argues elsewhere that an unlabelled navy circle is a guess, and
 * that is still true — so the label has not been deleted, it is collapsed.
 * `max-width` transitions from 0 to a generous ceiling, the text is clipped
 * rather than hidden, and it is still the control's accessible name. Keyboard
 * focus opens it exactly as hover does, which is the part that usually gets
 * forgotten and the part that makes it more than decoration.
 *
 * Hover-less pointers never open it: on a phone there is no hover state to
 * enter, the labels would either never appear or appear on the tap that was
 * meant to place the call.
 */
.dee-actions__item {
  display: inline-flex; align-items: center; justify-content: flex-end;
  gap: 0;
  width: 52px; height: 52px; min-height: 52px;
  padding: 0 14px; border: 0;
  border-radius: var(--dee-r-full);
  cursor: pointer;
  overflow: hidden;
  text-decoration: none;
  font-family: var(--dee-font); font-weight: 600; font-size: var(--dee-fs-sm);
  line-height: 1; white-space: nowrap;
  transition: width .22s var(--dee-ease), background-color .2s var(--dee-ease), transform .2s var(--dee-ease);
}
.dee-actions__item svg { flex: none; }
.dee-actions__label {
  max-width: 0; opacity: 0;
  overflow: hidden;
  transition: max-width .22s var(--dee-ease), opacity .18s var(--dee-ease), margin .22s var(--dee-ease);
}

@media (hover: hover) and (min-width: 721px) {
  .dee-actions__item:hover,
  .dee-actions__item:focus-visible { width: auto; padding-inline: 18px 20px; }
  .dee-actions__item:hover .dee-actions__label,
  .dee-actions__item:focus-visible .dee-actions__label {
    max-width: 14rem; opacity: 1; margin-inline-start: .6rem;
  }
}

/* The share disc, in the school's own blue rather than a third navy circle. */
.dee-actions__share {
  background: var(--dee-logo-blue); color: var(--dee-on-accent);
  box-shadow: 0 4px 12px -4px rgba(0, 16, 38, .40), 0 18px 40px -16px rgba(0, 16, 38, .55);
}
.dee-actions__share:hover { background: var(--dee-sky); }
.dee-actions__share:focus-visible { outline: 3px solid var(--dee-navy); outline-offset: 3px; }
.dee-actions__share.is-copied { background: var(--dee-ok); }
.dee-actions__share[hidden] { display: none; }

/*
 * The phone is a disc, not a second pill. Two labelled pills stacked in a
 * corner read as a menu that has escaped the page; a disc above a labelled
 * pill reads as one primary action with a shortcut over it.
 */
.dee-actions__call {
  background: var(--dee-navy); color: var(--dee-on-accent);
  border: 1px solid rgba(255, 255, 255, .16);
  box-shadow: 0 4px 12px -4px rgba(0, 16, 38, .40), 0 18px 40px -16px rgba(0, 16, 38, .55);
}
.dee-actions__call:hover { background: var(--dee-navy-deep); color: var(--dee-on-accent); transform: translateY(-2px); text-decoration: none; }
.dee-actions__call:focus-visible { outline: 3px solid var(--dee-blue); outline-offset: 3px; }

/*
 * The stack stays on a phone — see the note on .dee-actionbar for why it
 * used to be hidden there and why that was wrong. It sits a little tighter
 * to the corner, because 1.25rem of inset on a 390px screen is a lot of
 * screen given to a margin.
 */
/*
 * Out of the way of the headline on a phone — see the note in main.js. The
 * class is only ever set below 720px, so this rule is scoped to nothing else
 * and a desktop stack cannot be hidden by a stale class after a resize.
 */
body.dee-actions-off .dee-actions {
  opacity: 0;
  visibility: hidden;
  transform: translateY(-50%) translateX(1rem);
  pointer-events: none;
}
.dee-actions {
  transition: opacity .24s var(--dee-ease), transform .24s var(--dee-ease), visibility .24s;
}
@media (prefers-reduced-motion: reduce) {
  .dee-actions { transition: none; }
}

@media (max-width: 720px) {
  .dee-actions { right: .7rem; gap: var(--dee-s2); }
  /* A floating stack over an open menu is furniture on top of a list of
     links — the same rule the bar already had. */
  body.dee-navopen .dee-actions,
  body:has(.dee-nav[data-open="true"]) .dee-actions { display: none; }
}
@media (prefers-reduced-motion: reduce) {
  .dee-actions__call { transition: none; }
  .dee-actions__call:hover { transform: none; }
}

/* =========================================================================
   LANDING PAGES — the campaign template (inc/landing.php)

   A light hero, not the homepage's navy one. That is the one real departure
   from every other page here, and it is deliberate: the homepage hero is navy
   because the site needs a front door with weight, whereas an ad landing page
   is arrived at with intent already formed and its job is to get out of the
   way of the offer. White ground, one very large headline, the photograph at
   full clarity beside it, and the four facts a visitor came to check sitting
   directly under the words.

   Everything below reuses a component that already exists — .dee-level,
   .dee-prop, .dee-steps, .dee-seat, .dee-actionbar — and only adds the
   containers those components sit in.
   ====================================================================== */

.dee-lphero { padding-block: clamp(2rem, 1rem + 3vw, 3.5rem) clamp(2rem, 1rem + 3vw, 3.5rem); }

.dee-lphero__inner {
  display: grid;
  grid-template-columns: minmax(0, 11fr) minmax(0, 12fr);
  gap: clamp(1.5rem, 1rem + 3vw, 4rem);
  align-items: center;
  width: min(100% - 2.5rem, var(--dee-wide));
}

.dee-lphero__title {
  font-family: var(--dee-display);
  /*
   * Smaller than the homepage's --dee-fs-4xl, and that is the layout talking
   * rather than the hierarchy.
   *
   * The three lines are written as three lines — "Deutsch lernen." / "Sicher
   * sprechen." / "Ziele erreichen." — with hard breaks between them, so a line
   * that does not fit its column does not shrink, it wraps, and the headline
   * silently becomes four lines with "sprechen." alone on one of them. At 4xl
   * the middle line overflowed at every width between 1000 and 1500px. This
   * caps at 56px, which fits the longest German line in the narrower of the
   * two columns; the English lines are shorter and were never at risk, which
   * is why the German render is the one that has to be looked at.
   */
  font-size: clamp(2.25rem, 1.35rem + 2.8vw, 3.5rem);
  font-weight: 800;
  line-height: 1.04;
  letter-spacing: -0.035em;
  color: var(--dee-navy);
  margin: var(--dee-s3) 0 var(--dee-s4);
  text-wrap: balance;
  /*
   * German is why. "Prüfungsvorbereitung" is one word of twenty characters,
   * and at the 36px floor of the clamp above it is 380px wide inside a 350px
   * column — two pixels of horizontal scroll on the whole page at 390, which
   * is how a phone visitor gets a landing page that wobbles sideways. The
   * same rule already sits on .dee-section__title for the same word.
   */
  overflow-wrap: break-word;
  hyphens: auto;
}
/*
 * --dee-blue on paper, not the pale tone the navy hero uses. The accent line sits on the
 * light ground here, where the pale blue would measure under 2:1; the same
 * sentence on the navy homepage hero needs the opposite correction. Two
 * grounds, two tones, one rule — the accent is always the one that passes.
 */
.dee-lphero__title span { color: var(--dee-blue); }
/*
 * The long form of the accent line — set by dee_landing_hero() when the
 * sentence is too long to hold the headline size without wrapping. Same
 * colour, same weight, one step down, so it still reads as the third line of
 * the headline rather than as a paragraph that wandered up.
 */
.dee-lphero__title span.dee-lphero__sub {
  display: block;
  font-size: .58em;
  letter-spacing: -0.02em;
  margin-top: .3em;
}

.dee-lphero__where {
  display: flex; align-items: center; gap: var(--dee-s2);
  margin: 0 0 var(--dee-s5);
  color: var(--dee-ink-soft); font-size: var(--dee-fs-lg);
}
.dee-lphero__where .dee-icon { width: 20px; height: 20px; color: var(--dee-blue); flex: none; }

/* The four-fact rail ----------------------------------------------------- */
.dee-lpfacts {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(96px, 1fr));
  list-style: none; margin: 0 0 var(--dee-s6); padding: 0;
}
.dee-lpfact {
  display: grid; justify-items: start; gap: var(--dee-s2);
  padding: 0 var(--dee-s4);
}
.dee-lpfact:first-child { padding-left: 0; }
.dee-lpfact + .dee-lpfact { border-left: 1px solid var(--dee-rule); }
.dee-lpfact__icon svg { width: 26px; height: 26px; color: var(--dee-blue); display: block; }
.dee-lpfact__v {
  font-size: var(--dee-fs-sm); font-weight: 600; color: var(--dee-navy); line-height: 1.3;
}

/* The photograph, and the slogan over its corner ------------------------- */
.dee-lphero__media { position: relative; }
.dee-lphero__img {
  display: block; width: 100%; height: auto;
  aspect-ratio: 4 / 3; object-fit: cover;
  /*
   * One corner heavily rounded, three lightly. It is the shape the mockups
   * draw and it does one useful thing beyond looking deliberate: the deep
   * corner is the top-left, which is where the photograph meets the headline
   * column, so the two blocks read as one composition rather than as a column
   * of text next to a rectangle.
   */
  border-radius: clamp(1.5rem, 1rem + 4vw, 4rem) var(--dee-r-lg) var(--dee-r-lg) var(--dee-r-lg);
  filter: saturate(.92) contrast(1.02);
}

/*
 * The slogan badge — a shape, not an image.
 *
 * The mockups paint it as a brush stroke. A brush stroke would be a raster
 * asset, redrawn per campaign in two languages, on a site whose whole argument
 * is that it is fast. Four unequal border-radii give the same impression of
 * something painted rather than boxed, cost nothing, and — the part an image
 * cannot do — reflow when the German sentence inside runs a word longer than
 * the English one.
 */
.dee-lpbadge {
  position: absolute; top: clamp(.75rem, 2vw, 1.75rem); right: clamp(.75rem, 2vw, 1.75rem);
  max-width: min(58%, 20rem);
  margin: 0; padding: var(--dee-s4) var(--dee-s5);
  background: var(--dee-navy);
  color: var(--dee-on-accent);
  border-radius: 46% 54% 52% 48% / 62% 38% 62% 38%;
  box-shadow: var(--dee-shadow-float);
  font-family: var(--dee-display); font-weight: 700;
  font-size: clamp(1rem, .8rem + .7vw, 1.5rem); line-height: 1.28;
  letter-spacing: -0.02em;
  text-align: center;
}
.dee-lpbadge span { display: block; }

/* The level cards -------------------------------------------------------- */
.dee-levels--lp { grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); }
/*
 * "Termine auf Anfrage", where .dee-seat would normally print a seat count.
 * It takes the seat row's place rather than being appended beside it, so the
 * cards stay the same height whether or not a level has published dates.
 */
.dee-level__soon {
  margin: 0; font-size: var(--dee-fs-sm); color: var(--dee-ink-faint);
}

.dee-lpmore { margin: var(--dee-s6) 0 0; text-align: center; }
.dee-lpmore a {
  display: inline-flex; align-items: center; gap: var(--dee-s2);
  font-weight: 600; color: var(--dee-blue-dark);
}

/* "Warum DEE?" — one row of four, boxed like the mockup ------------------ */
.dee-props--lp {
  grid-template-columns: repeat(auto-fit, minmax(215px, 1fr));
  gap: 0;
  background: var(--dee-surface);
  border: 1px solid var(--dee-rule);
  border-radius: var(--dee-r-lg);
  box-shadow: var(--dee-shadow-card);
  overflow: hidden;
}
.dee-props--lp .dee-prop { padding: var(--dee-s6) var(--dee-s5); margin: 0; }
.dee-props--lp .dee-prop + .dee-prop { border-left: 1px solid var(--dee-rule); }

/* The navy next-start band ----------------------------------------------- */
.dee-lpband {
  background: var(--dee-navy);
  color: var(--dee-on-accent);
  border-radius: var(--dee-r-lg);
  padding: clamp(1.5rem, 1rem + 2vw, 2.75rem);
  display: grid;
  grid-template-columns: auto 1fr;
  align-items: center;
  gap: clamp(1.25rem, 1rem + 2vw, 3rem);
}
.dee-lpband__lead { display: flex; align-items: center; gap: var(--dee-s5); }
.dee-lpband__ring {
  display: grid; place-items: center; flex: none;
  width: 78px; height: 78px; border-radius: 50%;
  border: 2px solid var(--dee-blue-soft);
}
.dee-lpband__ring svg { width: 34px; height: 34px; color: var(--dee-blue-pale); }
.dee-lpband__label {
  margin: 0; font-size: var(--dee-fs-sm); letter-spacing: .1em; text-transform: uppercase;
  color: rgba(255,255,255,.78);
}
.dee-lpband__date {
  margin: var(--dee-s1) 0 0; font-family: var(--dee-display); font-weight: 800;
  font-size: clamp(1.75rem, 1.2rem + 2vw, 3rem); line-height: 1; letter-spacing: -0.03em;
}
.dee-lpband__soon { margin: var(--dee-s1) 0 0; font-size: var(--dee-fs-lg); color: rgba(255,255,255,.9); }

.dee-lpband__cols {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(112px, 1fr));
  list-style: none; margin: 0; padding: 0;
}
.dee-lpband__cols > li {
  display: grid; justify-items: center; gap: var(--dee-s1);
  padding: 0 var(--dee-s4); text-align: center;
}
.dee-lpband__cols > li + li { border-left: 1px solid rgba(255,255,255,.18); }
.dee-lpband__icon svg { width: 26px; height: 26px; color: rgba(255,255,255,.85); display: block; }
.dee-lpband__k { font-weight: 700; font-size: var(--dee-fs-sm); }
.dee-lpband__v { font-size: var(--dee-fs-xs); color: rgba(255,255,255,.7); }
.dee-lpband__seats--free .dee-lpband__k,
.dee-lpband__seats--free .dee-lpband__icon svg { color: var(--dee-signal-free); }
.dee-lpband__seats--low .dee-lpband__k,
.dee-lpband__seats--low .dee-lpband__icon svg { color: var(--dee-signal-low); }
.dee-lpband__cta { grid-column: 1 / -1; margin: 0; text-align: center; }

/* Three steps, with the two actions beside them -------------------------- */
.dee-lpsteps {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 18rem);
  gap: clamp(1.5rem, 1rem + 3vw, 3.5rem); align-items: center;
}
.dee-lpsteps .dee-steps { margin-block: 0; }
.dee-lpsteps__cta { display: grid; gap: var(--dee-s3); align-content: center; }
.dee-lpsteps__cta .dee-btn { width: 100%; justify-content: center; }

/* The closing contact panel ---------------------------------------------- */
.dee-lpcontact {
  background: var(--dee-navy);
  color: var(--dee-on-accent);
  border-radius: var(--dee-r-lg);
  padding: clamp(1.5rem, 1rem + 2vw, 3rem);
  display: grid;
  grid-template-columns: minmax(0, 14rem) minmax(0, 2.3fr) minmax(0, 1fr);
  gap: clamp(1.5rem, 1rem + 2vw, 3rem);
  align-items: center;
}
.dee-lpcontact__head h2 { color: var(--dee-on-accent); margin: 0 0 var(--dee-s2); }
.dee-lpcontact__head p { margin: 0; color: rgba(255,255,255,.78); font-size: var(--dee-fs-base); }

.dee-lpcontact__ways,
.dee-lpcontact__trust { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--dee-s5); }
.dee-lpcontact__ways { grid-template-columns: repeat(auto-fit, minmax(148px, 1fr)); }
.dee-lpcontact__trust {
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  border-left: 1px solid rgba(255,255,255,.18);
  padding-left: clamp(1rem, 2vw, 2rem);
}
.dee-lpcontact__ways a,
.dee-lpcontact__trust > li {
  display: grid; grid-template-columns: auto 1fr; column-gap: var(--dee-s3);
  align-items: start; color: inherit; text-decoration: none;
}
.dee-lpcontact__ways a:hover .dee-lpcontact__v { text-decoration: underline; }
.dee-lpcontact__icon { grid-row: 1 / 3; }
.dee-lpcontact__icon svg { width: 26px; height: 26px; color: var(--dee-blue-pale); display: block; }
.dee-lpcontact__k { font-weight: 700; font-size: var(--dee-fs-sm); }
.dee-lpcontact__v { font-size: var(--dee-fs-sm); color: rgba(255,255,255,.76); line-height: 1.45; }

/*
 * The sticky bar stays up at every width on a campaign page.
 *
 * dee_action_bar() already draws exactly the bar the mockups put along the
 * bottom — WhatsApp on the left, secure-your-place on the right — and already
 * hides the floating bubble rather than sitting beside it. On the rest of the
 * site it is a phone affordance and disappears above 720px; here it is the
 * page's standing call to action, so it is only the ceiling that is lifted.
 * No second bar, no duplicated markup.
 */
@media (min-width: 721px) {
  body.dee-lp .dee-actionbar {
    display: flex; justify-content: center; gap: var(--dee-s4);
    position: fixed; inset: auto 0 0 0; z-index: 120;
    background: rgba(255,255,255,.97);
    border-top: 1px solid var(--dee-rule);
    box-shadow: 0 -8px 30px -20px rgba(9,24,44,.5);
    padding: var(--dee-s3) var(--dee-s5);
  }
  body.dee-lp .dee-actionbar .dee-btn { min-width: 15rem; justify-content: center; }
  body.dee-lp .dee-wa,
  body.dee-lp .dee-actions { display: none; }
  body.dee-lp { padding-bottom: 5rem; }
}

/* Responsive ------------------------------------------------------------- */
@media (max-width: 980px) {
  /*
   * minmax(0, 1fr), not 1fr.
   *
   * A bare `1fr` track is `minmax(auto, 1fr)`, and `auto` there means
   * min-content — so the track grows to fit the longest unbreakable word in
   * it rather than the column growing a scrollbar. "Prüfungsvorbereitung" at
   * the headline's 36px floor is 372px wide, the column is 350px, and the
   * result was two pixels of horizontal scroll on the whole page at 390.
   * Hyphenation is the belt; this is the braces, and it is the half that
   * works in a browser with no German hyphenation dictionary loaded.
   */
  .dee-lphero__inner { grid-template-columns: minmax(0, 1fr); }
  /* Photograph first on a phone: it is the fastest statement of what this is,
     and the headline is directly under it rather than a scroll below. */
  .dee-lphero__media { order: -1; }
  .dee-lpband { grid-template-columns: 1fr; }
  .dee-lpsteps { grid-template-columns: 1fr; }
  .dee-lpcontact { grid-template-columns: 1fr; }
  .dee-lpcontact__trust {
    border-left: 0; padding-left: 0;
    border-top: 1px solid rgba(255,255,255,.18); padding-top: var(--dee-s5);
  }
}

@media (max-width: 720px) {
  .dee-lpfacts { grid-template-columns: 1fr 1fr; gap: var(--dee-s4) 0; }
  .dee-lpfact:nth-child(odd) { padding-left: 0; }
  .dee-lpfact:nth-child(odd) { border-left: 0; }
  .dee-lpbadge { position: static; max-width: none; margin-top: var(--dee-s4); border-radius: var(--dee-r-lg); }
  .dee-props--lp .dee-prop + .dee-prop { border-left: 0; border-top: 1px solid var(--dee-rule); }
  .dee-lpband__cols > li + li { border-left: 0; }
  .dee-lpband__lead { flex-direction: column; align-items: flex-start; gap: var(--dee-s3); }
}

/* =========================================================================
   TOUCH TARGETS — WCAG 2.2 SC 2.5.8 (AA), 24 × 24 CSS pixels

   Found by measuring every control on every page at 1440 and at 390 rather
   than by looking at screenshots. Nine controls across the site came in under
   24px in one dimension: the top utility bar's links, the price table's sort
   buttons and row links, the blog's category chip, and every custom checkbox
   and radio in the forms.

   None of them was unusable — they are all comfortably clickable with a mouse
   — and that is exactly why none of them was ever reported. 2.5.8 is about
   the people for whom "comfortably clickable with a mouse" is not the test:
   a tremor, a phone in one hand on a tram, a stylus.

   Inline links inside a sentence are deliberately NOT touched. The success
   criterion exempts them, and enlarging them would break the line they sit in.
   ====================================================================== */

/* The desktop utility bar — "Über uns · Team · Kontakt · Blog" and the phone
   number beside them. 22px tall, because they were sized by their text.

   `display` is NOT set here, and that omission is the fix for a bug this
   block caused. Both of these are hidden below 1200px — the strip would wrap
   to three lines otherwise, and both reappear inside the burger menu. This
   rule sat later in the file with equal specificity and set `display:
   inline-flex`, so it un-hid them at every width. On a 390px phone the phone
   number then took 151px of a 390px strip and squeezed "Nächster Kursstart:
   07.09.2026" into 68px, which rendered as "Nächster Kurss…" — the date, the
   only reason the strip exists, ellipsised away by an accessibility fix.

   The sizing applies everywhere; the display belongs with the breakpoint that
   decides whether the element exists at all. */
.dee-utility__list a,
.dee-announce__tel {
  align-items: center;
  min-height: 24px;
}
@media (min-width: 1201px) {
  .dee-utility__list a,
  .dee-announce__tel { display: inline-flex; }
}

/* The price table's column sorters, and the course name in each row. */
.dee-runs__sort { min-height: 24px; }
.dee-runs__table tbody td a {
  display: inline-flex; align-items: center; min-height: 24px;
}

/* The blog's category chip. */
.dee-post__cat { display: inline-flex; align-items: center; min-height: 24px; }

/*
 * The footer's column headings.
 *
 * They are <summary> elements — the columns collapse on a phone — which makes
 * them controls at every width, including the one where they are only ever
 * read. 16px tall, because a summary is sized by its text.
 */
.dee-footer__group > summary { min-height: 24px; display: flex; align-items: center; }

/*
 * Every custom checkbox and radio in the forms.
 *
 * 1.1rem is 17.6px and the browser default is 13px; both are under the bar.
 * 1.5rem is 24px exactly, which is the criterion rather than a round number
 * — the controls are already large enough to look deliberate at that size and
 * making them larger starts to look like a mistake.
 *
 * `accent-color` keeps the native control and tints it, rather than replacing
 * it with a styled span: a real checkbox announces itself correctly to a
 * screen reader, works with the keyboard and inherits the platform's own
 * focus ring, and every one of those has to be rebuilt by hand the moment it
 * is swapped for a div.
 */
.dee-check input,
.dee-form__check input,
.dee-form__consent input[type="checkbox"],
.dee-payopt > input[type="radio"],
.dee-field input[type="checkbox"],
.dee-field input[type="radio"] {
  width: 1.5rem; height: 1.5rem; flex: none;
  accent-color: var(--dee-blue);
}
/* The box was vertically centred against a 1.1rem control; it is taller now. */
.dee-check input { margin-top: 0; }


/* =========================================================================
   THE PRICE HIGHLIGHTER

   The client pointed at a competitor's page — the price sitting on a marker
   sweep, the one thing on the screen your eye lands on — and asked for the
   same in the school's own blue, "like it's brush made".

   The first attempt was four unequal border-radii and a gradient. It read as
   a soft lozenge: no two corners alike, but every edge smooth, and nothing
   about it said a hand had been anywhere near it. What makes a stroke look
   painted is not irregular corners, it is what happens along the EDGES and at
   the ENDS — the bristles leaving a wavy top and bottom, a break where the
   brush ran dry, and a thin flick where it lifted off the paper.

   So the shape is a real path, carried as an SVG mask rather than as a
   picture. Mask rather than a background image for one reason that matters:
   the colour stays a CSS token, so changing --dee-marker changes the ink and
   nothing has to be redrawn or recoloured. And it is a mask rather than an
   inline <svg> in the markup because this decorates four different elements
   in three different templates, none of which should have to carry a drawing.

   preserveAspectRatio="none" on both paths: the stroke stretches to whatever
   the number is, from "ab 149 €" to "ab 1.299 €", instead of being centred at
   one size and cropped at the others.
   ====================================================================== */

.dee-mark,
.dee-pricecard__price,
.dee-chero__badge-price,
.dee-card__price,
.dee-level__meta .is-fee {
  position: relative;
  isolation: isolate;
  /* The sweep overshoots the glyphs, so the text needs room to sit in. */
  padding-inline: .2em;
  /*
   * And it has to hug the number.
   *
   * Two of these four are block-level — the price card's price is a 370px
   * box with "589 €" at the left of it — so without this the marker swept
   * the whole column and read as a filled bar rather than as a stroke over a
   * figure. `fit-content` rather than `display: inline-block`, because these
   * elements sit in flex and grid parents that rely on their current display.
   */
  width: fit-content;
  max-width: 100%;
}

/* The stroke: a wavy band, two dry-brush breaks, and the flick at the end. */
.dee-mark::before,
.dee-pricecard__price::before,
.dee-chero__badge-price::before,
.dee-card__price::before,
.dee-level__meta .is-fee::before {
  content: "";
  position: absolute;
  z-index: -1;
  inset: -.14em -.42em -.22em -.34em;
  background: var(--dee-marker);
  -webkit-mask: url("data:image/svg+xml,<svg%20xmlns=%22http://www.w3.org/2000/svg%22%20viewBox=%220%200%20320%2060%22%20preserveAspectRatio=%22none%22><path%20fill-rule=%22evenodd%22%20d=%22M8%2019c40-5.4%2096-7.6%20150-7%2056%20.6%20106%202.4%20138%205.6%206%20.6%208.4%202.2%207.6%205-1%203.6-1.4%2015.4-2.2%2019.6-.6%203.4-3.4%204.8-9.4%205.2-36%202.6-88%203.6-144%203-56-.6-104-2.4-136-5.6-6-.6-9-2.4-8.4-6.2.8-5%201-13.2.4-17.4C3.6%2020.6%204.6%2019.4%208%2019Zm230%201.6c19%20.8%2038%202%2050%203.4-13%20.7-32%20.2-48-.7-14-.8-14-3%20-2-2.7ZM32%2044.4c31%202.2%2076%203.7%20120%204.1-40%20.6-79-.3-110-2-7-.4-10-1.6-10-2.1Z%22/><path%20d=%22M296%2025.8c10-.8%2020%201.6%2023%204.8%201.4%201.6%200%202.8-2.6%202-6.4-1.8-14.6-2.8-20.6-2.6-3%20.1-3-3.9.2-4.2Z%22/></svg>") center / 100% 100% no-repeat;
  mask: url("data:image/svg+xml,<svg%20xmlns=%22http://www.w3.org/2000/svg%22%20viewBox=%220%200%20320%2060%22%20preserveAspectRatio=%22none%22><path%20fill-rule=%22evenodd%22%20d=%22M8%2019c40-5.4%2096-7.6%20150-7%2056%20.6%20106%202.4%20138%205.6%206%20.6%208.4%202.2%207.6%205-1%203.6-1.4%2015.4-2.2%2019.6-.6%203.4-3.4%204.8-9.4%205.2-36%202.6-88%203.6-144%203-56-.6-104-2.4-136-5.6-6-.6-9-2.4-8.4-6.2.8-5%201-13.2.4-17.4C3.6%2020.6%204.6%2019.4%208%2019Zm230%201.6c19%20.8%2038%202%2050%203.4-13%20.7-32%20.2-48-.7-14-.8-14-3%20-2-2.7ZM32%2044.4c31%202.2%2076%203.7%20120%204.1-40%20.6-79-.3-110-2-7-.4-10-1.6-10-2.1Z%22/><path%20d=%22M296%2025.8c10-.8%2020%201.6%2023%204.8%201.4%201.6%200%202.8-2.6%202-6.4-1.8-14.6-2.8-20.6-2.6-3%20.1-3-3.9.2-4.2Z%22/></svg>") center / 100% 100% no-repeat;
  transform: rotate(-1.2deg);
  pointer-events: none;
}

/*
 * The second pass — where a real marker doubles back along the bottom of the
 * line it has just drawn. Rotated the other way, so the two edges never line
 * up, and translucent, so the overlap is visibly denser than the tail.
 */
.dee-mark::after,
.dee-pricecard__price::after,
.dee-chero__badge-price::after,
.dee-card__price::after,
.dee-level__meta .is-fee::after {
  content: "";
  position: absolute;
  z-index: -1;
  inset: .06em -.30em -.16em -.24em;
  background: var(--dee-marker);
  opacity: .45;
  -webkit-mask: url("data:image/svg+xml,<svg%20xmlns=%22http://www.w3.org/2000/svg%22%20viewBox=%220%200%20320%2060%22%20preserveAspectRatio=%22none%22><path%20d=%22M14%2038c34%204.2%2086%206.6%20142%207%2052%20.4%20100-1%20132-4%207-.6%209.6.8%207.4%203-4.4%204.4-44%207.4-100%208-62%20.6-134-1.6-172-6-8-1-12-5.4-9.4-8Z%22/></svg>") center / 100% 100% no-repeat;
  mask: url("data:image/svg+xml,<svg%20xmlns=%22http://www.w3.org/2000/svg%22%20viewBox=%220%200%20320%2060%22%20preserveAspectRatio=%22none%22><path%20d=%22M14%2038c34%204.2%2086%206.6%20142%207%2052%20.4%20100-1%20132-4%207-.6%209.6.8%207.4%203-4.4%204.4-44%207.4-100%208-62%20.6-134-1.6-172-6-8-1-12-5.4-9.4-8Z%22/></svg>") center / 100% 100% no-repeat;
  transform: rotate(.8deg);
  pointer-events: none;
}

/*
 * No mask support, no stroke — a rounded band instead.
 *
 * Without this the pseudo-element would paint an unmasked RECTANGLE the full
 * size of its inset: a hard blue box over the price, which is worse than no
 * highlight at all. Every engine this site supports has masks; the guard is
 * for the one that does not and has not been thought of yet.
 */
@supports not (mask-image: url("#x")) {
  .dee-mark::before, .dee-pricecard__price::before, .dee-chero__badge-price::before,
  .dee-card__price::before, .dee-level__meta .is-fee::before {
    border-radius: .5em 1.2em .6em 1em / .9em .5em 1.1em .55em;
  }
  .dee-mark::after, .dee-pricecard__price::after, .dee-chero__badge-price::after,
  .dee-card__price::after, .dee-level__meta .is-fee::after { display: none; }
}

/*
 * Reduced motion is about movement, not about ink — the stroke does not
 * animate, so it stays. Forced-colours mode is different: there the browser
 * replaces every colour with the user's own pair, and a background that
 * cannot be replaced would sit as a solid block over the text.
 */
@media (forced-colors: active) {
  .dee-mark::before, .dee-mark::after,
  .dee-pricecard__price::before, .dee-pricecard__price::after,
  .dee-chero__badge-price::before, .dee-chero__badge-price::after,
  .dee-card__price::before, .dee-card__price::after,
  .dee-level__meta .is-fee::before, .dee-level__meta .is-fee::after { display: none; }
}
