/* Components of the public booking flow.

   Every brand value comes from tokens.css. If you are about to write a
   colour, a font size or a duration as a literal here, it belongs there
   instead -- that separation is what lets the webinar screens inherit this
   look without choosing it again.

   Red is a signal, and the rule has teeth: it appears on the selected day,
   the primary action, the focus ring, errors, and the rules beside
   headlines. Every available day in the month grid used to be red-bordered
   and red-lettered, which made red the default state and left nothing
   louder for the day a guest actually picks. */

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

html { background: var(--surface-page); }

/* A column, so the footer sits at the bottom of the viewport rather than
   wherever the content happens to end. Without this a short page -- an empty
   webinar overview, a cancellation notice -- left the footer floating with a
   band of page-grey beneath it, which reads as a rendering fault. */
body {
  margin: 0;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  font-family: var(--font-body);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  color: var(--text-body);
  background: var(--surface-page);
  -webkit-font-smoothing: antialiased;
  text-wrap: pretty;

  /* One rule for every text container on every page, because both of these
     properties inherit. That is the whole reason it sits here on `body` and
     not as five patches further down: a long unbreakable string overflows
     whatever box happens to hold it, and the boxes are not the interesting
     part.

     It was measured, not guessed. At a 360px viewport all five public pages
     sit at exactly 360 with realistic content -- and between 561 and 950 with
     a 75-character German compound in the title or in the school name. Both
     of those are typed by people: the title by a colleague in the admin, the
     school by the guest into the registration form, where it then reappears
     on the confirmation page. Nobody has to do anything wrong to produce it.
     Where nothing overflowed as an *element*, the offender was the text node
     itself, which is exactly the case overflow-wrap answers and which no
     min-width fix can reach.

     hyphens: auto because German is allowed to break its compounds, and
     `<html lang="de">` in base.html is what lets the browser do it properly.
     It softens the break where a dictionary is available; overflow-wrap is
     what guarantees the page never scrolls sideways when one is not. */
  overflow-wrap: break-word;
  hyphens: auto;
}

/* Takes the slack, so the footer is pushed down instead of centred. */
main { flex: 1 0 auto; }

h1, h2, h3, h4 {
  margin: 0;
  color: var(--text-strong);
  font-weight: var(--fw-bold);
  line-height: var(--lh-h2);
}

p { margin: 0 0 1em; }
p:last-child { margin-bottom: 0; }

a { color: var(--maiss-red); text-decoration: none; transition: var(--transition-color); }
a:hover { color: var(--red-900); text-decoration: underline; }

a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible {
  outline: 2px solid var(--focus-ring);
  outline-offset: 2px;
}

img { max-width: 100%; display: block; }
strong, b { font-weight: var(--fw-bold); color: var(--text-strong); }
::selection { background: var(--red-100); color: var(--black); }

/* ---- Layout shell ---------------------------------------------------- */

.shell {
  max-width: var(--container-max);
  margin: 0 auto;
  padding-left: var(--page-pad-x);
  padding-right: var(--page-pad-x);
}

.page {
  padding: var(--sp-16) 0 var(--sp-24);
}

/* ---- Site chrome ----------------------------------------------------- */

.site-topbar { height: var(--bw-topbar); background: var(--maiss-red); }

.site-header { background: var(--white); border-bottom: var(--bw-hairline) solid var(--border-hairline); }
.site-header__inner { display: flex; align-items: center; min-height: 84px; }
.site-header__logo { display: block; }

.site-footer {
  background: var(--white);
  border-top: var(--bw-hairline) solid var(--border-hairline);
  padding: var(--sp-10) 0;
}
.site-footer__inner {
  display: flex;
  justify-content: space-between;
  gap: var(--sp-8);
  flex-wrap: wrap;
  font-size: var(--fs-caption);
  color: var(--text-body);
}
.site-footer__address { margin: 0; }
.site-footer__links { display: flex; gap: var(--sp-6); flex-wrap: wrap; }

/* ---- Two building blocks that recur on every screen ------------------- */

/* The kicker above a headline: "EINZELBERATUNG", "TERMIN STEHT". */
.u-eyebrow {
  font-size: var(--fs-eyebrow);
  line-height: var(--lh-eyebrow);
  letter-spacing: var(--ls-eyebrow);
  text-transform: uppercase;
  color: var(--text-eyebrow);
  margin: 0 0 var(--sp-4);
}

/* The signature: a 4px red bar to the left of the headline. The bar is a
   flex child rather than a border so it spans the headline's full height
   however many lines it wraps to. */
.u-rule { display: flex; gap: var(--sp-4); align-items: stretch; }
.u-rule__bar { width: var(--bw-rule); background: var(--accent-rule); flex: none; }
.u-rule--quiet .u-rule__bar { background: var(--border-strong); }

/* Second line of a headline, in Light 300. The contrast between 700 and 300
   is the typographic signature -- see fonts.css. */
.u-light { font-weight: var(--fw-light); }

/* ---- Surfaces -------------------------------------------------------- */

.panel {
  background: var(--surface-card);
  border: var(--bw-hairline) solid var(--border-hairline);
}
.panel--accent { border-top: var(--bw-cardtop) solid var(--maiss-red); }
.panel__body { padding: var(--sp-12) var(--sp-12) var(--sp-10); }

.notice {
  background: var(--surface-sunken);
  padding: var(--sp-5) var(--sp-6);
  font-size: var(--fs-body-sm);
  line-height: var(--lh-body-sm);
  color: var(--text-body);
}
.notice--error { border-left: var(--bw-rule) solid var(--state-error); background: var(--red-050); }

/* ---- Buttons --------------------------------------------------------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  padding: var(--sp-4) var(--sp-8);
  min-height: 52px;
  border: var(--bw-hairline) solid var(--border-strong);
  border-radius: var(--radius-0);
  background: var(--white);
  color: var(--black);
  font: inherit;
  font-size: var(--fs-body-sm);
  font-weight: var(--fw-bold);
  cursor: pointer;
  transition: var(--transition-color);
}
.btn:hover { border-color: var(--maiss-red); color: var(--maiss-red); text-decoration: none; }

.btn--primary { background: var(--maiss-red); border-color: var(--maiss-red); color: var(--text-on-red); }
.btn--primary:hover { background: var(--hover-darken); border-color: var(--hover-darken); color: var(--text-on-red); }
.btn--primary:active { background: var(--press-darken); border-color: var(--press-darken); }

.btn--secondary { background: var(--white); border-color: var(--maiss-red); color: var(--maiss-red); }
.btn--secondary:hover { background: var(--red-050); }

/* A text action that carries weight without a box -- "Verschieben",
   "Absagen", "← Andere Zeit wählen". */
.btn--link {
  min-height: 0;
  padding: 0;
  border: none;
  background: none;
  color: var(--maiss-red);
  font-weight: var(--fw-bold);
}
.btn--link:hover { color: var(--red-900); text-decoration: underline; background: none; }

.btn[disabled] { opacity: var(--disabled-opacity); cursor: default; }

.actions { display: flex; gap: var(--sp-4); align-items: center; flex-wrap: wrap; }

/* ---- Form controls --------------------------------------------------- */

.field { display: block; margin-bottom: var(--sp-5); }
.field__label {
  display: block;
  font-size: var(--fs-label);
  font-weight: var(--fw-bold);
  color: var(--black);
  margin-bottom: var(--sp-2);
}
.field__required { color: var(--maiss-red); }
.field__optional { font-weight: var(--fw-regular); color: var(--text-body); }

.field input[type="text"],
.field input[type="email"],
.field select,
.field textarea {
  width: 100%;
  padding: var(--sp-3) var(--sp-4);
  border: var(--bw-hairline) solid var(--border-control);
  border-radius: var(--radius-0);
  background: var(--white);
  color: var(--black);
  font: inherit;
  /* Deliberately a literal, not a token: below 16px, iOS Safari zooms the
     viewport in when a field receives focus, so this is a functional floor
     rather than a design choice -- and US-51 needs the whole flow usable on
     a 360px phone, where that zoom would be worst. A token here would invite
     someone to retune it later and silently reintroduce the zoom. */
  font-size: 16px;
}
.field textarea { resize: vertical; }

.field__hint {
  display: block;
  font-size: var(--fs-caption);
  line-height: var(--lh-caption);
  color: var(--text-body);
  margin-top: var(--sp-2);
}

/* Errors are text, never colour alone (NFA-3). The red border is an
   addition to the sentence below the field, never a replacement for it. */
.field--invalid input,
.field--invalid textarea,
.field--invalid select { border: 2px solid var(--maiss-red); }
.field__error {
  display: block;
  font-size: var(--fs-error);
  font-weight: var(--fw-bold);
  color: var(--maiss-red);
  margin-top: var(--sp-2);
}

/* ---- Step indicator -------------------------------------------------- */

/* Squares, not dots, and hairlines between them -- the mockup's shape. The
   connector is a pseudo-element on the item rather than a separate node so
   the markup stays a plain <ol> for a screen reader. */
.steps {
  display: flex;
  justify-content: center;
  align-items: flex-start;
  gap: 0;
  list-style: none;
  margin: 0 0 var(--sp-10);
  padding: 0;
}

.steps__item {
  position: relative;
  flex: 0 1 210px;
  text-align: center;
}

.steps__item + .steps__item::before {
  content: "";
  position: absolute;
  top: 7px;
  right: calc(50% + 30px);
  left: calc(-50% + 30px);
  height: 1px;
  background: var(--border-hairline);
}
.steps__item.is-done + .steps__item::before,
.steps__item.is-done::before { background: var(--maiss-red); }

.steps__mark {
  display: block;
  width: 14px;
  height: 14px;
  margin: 0 auto var(--sp-3);
  background: var(--gray-400);
}
.steps__item.is-done .steps__mark,
.steps__item[aria-current] .steps__mark { background: var(--maiss-red); }

.steps__label {
  display: block;
  font-size: var(--fs-eyebrow);
  line-height: var(--lh-eyebrow);
  letter-spacing: var(--ls-eyebrow);
  text-transform: uppercase;
  color: var(--text-muted);
}
.steps__item[aria-current] .steps__label {
  font-weight: var(--fw-bold);
  color: var(--black);
}

/* Everything responsive lives in the two blocks that close this file, and they
   are the LAST thing in it -- see the note there. They have to come after every
   rule they override: a media query adds no specificity, so a plain later rule
   beats an earlier @media rule of equal weight. Append new sections above them.

   ---- Literal font sizes: nine survive, and this is the whole list ----

   Verify with `grep -n 'font-size: [0-9]'` before editing this paragraph.

     16px    .field controls -- a functional iOS-zoom floor, not a design
             choice, and outside --fs-control on purpose (see the declaration)
     27px    .type-panel__heading h1
     23px    .calendar__month
     12.5px  .calendar__legend
     38px    .wpage__heading h1
     30px    .wdetail__heading h1
     16.5px  .wdetail__text
     34px    .wdetail__count
     34px    .hostpage__heading h1

   All bespoke mockup values with one consumer each, where a token named after
   its only use would be indirection without abstraction. The two 34s are a
   coincidence, not a shared value: a page headline and a big numeral that
   happen to land on the same number. Tokenising them would tie two unrelated
   things together, and whoever retuned one would silently move the other.

   Everything that repeats, or that matches a token already in tokens.css,
   reads from one: 22px -> --fs-h3, 28px -> --fs-h2, 19px -> --fs-lead,
   16px -> --fs-control, 14px -> --fs-label, 13.5px -> --fs-error,
   11.5px -> --fs-micro. The last of those is new: 11.5px had one consumer
   (.calendar__weekdays) until the webinar cards gave it two more, and three
   uses is a scale step rather than a bespoke value.

   Two substitutions read oddly and are deliberate. .wcard__host and
   .wcard__seats take --fs-error, a token named for the field-error text it was
   introduced for -- the same reuse .cancel__notice and .reschedule__note
   already make, for the same reason: the rule is about the value, and two more
   13.5px literals are worse than a token with a narrow name.

   This inventory has been wrong twice -- it once named four literals while ten
   were in the file, then five while fifteen more had been appended below it. An
   inventory comment is how the next reader decides the pass is finished, which
   makes it worth more than the tidiness it describes. Count them before
   changing this line. */

/* Three columns: what it is, the month, the times. flex-wrap rather than a
   grid so each column can state its own minimum and the layout collapses in
   the order a guest reads it (US-51). */
.booking-card {
  display: flex;
  flex-wrap: wrap;
  align-items: stretch;
  background: var(--surface-card);
  border: var(--bw-hairline) solid var(--border-hairline);
}

.type-panel {
  flex: 1 1 280px;
  min-width: 260px;
  padding: var(--sp-8);
  border-right: var(--bw-hairline) solid var(--border-hairline);
}
.type-panel__image { width: 100%; height: 180px; object-fit: cover; margin-bottom: var(--sp-6); }
.type-panel__heading { margin-bottom: var(--sp-6); }
.type-panel__heading h1 { font-size: 27px; line-height: var(--lh-h1); }
.type-panel__description { font-size: var(--fs-body-sm); line-height: var(--lh-body-sm); margin-bottom: var(--sp-6); }

.type-panel__facts {
  display: grid;
  gap: var(--sp-4);
  margin: 0 0 var(--sp-6);
  padding-top: var(--sp-5);
  border-top: var(--bw-hairline) solid var(--border-hairline);
}
.type-panel__facts dt { font-size: var(--fs-caption); color: var(--text-body); }
.type-panel__facts dd { margin: 2px 0 0; font-size: var(--fs-control); font-weight: var(--fw-bold); color: var(--black); }

.type-panel__host { display: flex; gap: var(--sp-3); align-items: center; }
.type-panel__portrait { width: 56px; height: 56px; border-radius: var(--radius-circle); object-fit: cover; flex: none; }
.type-panel__host-name { display: block; }
.type-panel__host-org { display: block; font-size: var(--fs-caption); font-weight: var(--fw-regular); color: var(--text-body); }

.type-panel__tz { margin-bottom: 0; }

/* ---- Calendar -------------------------------------------------------- */

.booking-card__cal {
  flex: 2 1 380px;
  min-width: 340px;
  padding: var(--sp-8);
  border-right: var(--bw-hairline) solid var(--border-hairline);
}

.calendar__nav { display: flex; align-items: center; justify-content: center; gap: var(--sp-6); margin-bottom: var(--sp-6); }
.calendar__month { font-size: 23px; min-width: 200px; text-align: center; }
.calendar__nav-link {
  width: 34px; height: 34px;
  border: none; background: none;
  color: var(--black); font-size: var(--fs-h3); line-height: 1; cursor: pointer;
}
.calendar__nav-link:hover { color: var(--maiss-red); }
.calendar__nav-link--disabled, .calendar__nav-link--disabled:hover { color: var(--gray-400); cursor: default; }

/* minmax(0, ...) rather than a bare 1fr: a grid track's automatic minimum
   is its content's min-content size, so a bare 1fr cannot shrink a day
   number below its own intrinsic width. That never mattered until the
   reschedule screen nested this same grid inside a second layer of
   horizontal padding (.reschedule__body on top of .shell) and narrowed its
   available width below what seven unclamped tracks need, which is what
   overflowed the viewport at 360px (US-51). */
.calendar__weekdays, .calendar__grid { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 6px; }
.calendar__weekdays {
  margin-bottom: var(--sp-2);
  font-size: var(--fs-micro);
  letter-spacing: var(--ls-label);
  color: var(--text-muted);
  text-align: center;
  text-transform: uppercase;
}

/* Three states, three shapes -- and only the selected one is filled red.
   A red ring says "there is something here", a red disc says "this is the
   one you picked". */
.calendar__day {
  aspect-ratio: 1;
  width: 100%;
  display: grid;
  place-items: center;
  border: 1px solid transparent;
  border-radius: var(--radius-circle);
  background: none;
  font: inherit;
  font-size: var(--fs-control);
  color: var(--gray-400);
  cursor: default;
}
button.calendar__day {
  border: 1.5px solid var(--maiss-red);
  background: var(--white);
  color: var(--black);
  font-weight: var(--fw-bold);
  cursor: pointer;
  transition: var(--transition-color);
}
button.calendar__day:hover { background: var(--red-050); }
button.calendar__day--selected,
button.calendar__day--selected:hover {
  background: var(--maiss-red);
  border: 2px solid var(--maiss-red);
  color: var(--text-on-red);
}
.calendar__day--disabled { background: var(--gray-200); border-color: var(--gray-200); color: var(--text-muted); }
.calendar__day--pad { background: none; border-color: transparent; }
.calendar__day--today { text-decoration: underline; }
.htmx-request.calendar__day { opacity: var(--disabled-opacity); }
/* NFA-4: the whole grid while a month is being fetched -- the slowest step on
   the page. pointer-events so a second click cannot queue a second month. */
.htmx-request.booking-card__cal { opacity: var(--disabled-opacity); pointer-events: none; }

.calendar__legend {
  display: flex;
  gap: var(--sp-6);
  flex-wrap: wrap;
  list-style: none;
  margin: var(--sp-5) 0 0;
  padding: var(--sp-4) 0 0;
  border-top: var(--bw-hairline) solid var(--border-hairline);
  font-size: 12.5px;
  color: var(--text-body);
}
.calendar__legend li { display: flex; align-items: center; gap: var(--sp-2); }
.calendar__key { width: 14px; height: 14px; border-radius: var(--radius-circle); display: block; }
.calendar__key--selected { background: var(--maiss-red); }
.calendar__key--free { border: 1.5px solid var(--maiss-red); }
.calendar__key--none { background: var(--gray-200); }

/* ---- Times ----------------------------------------------------------- */

.booking-card__side { flex: 1 1 240px; min-width: 220px; padding: var(--sp-8) var(--sp-6); }
.times__day { margin: 0; font-size: var(--fs-control); font-weight: var(--fw-bold); color: var(--black); }
.times__tz { margin: var(--sp-1) 0 var(--sp-5); font-size: var(--fs-caption); color: var(--text-body); }
.times__placeholder { font-size: var(--fs-body-sm); color: var(--text-muted); }

.times__list { display: grid; gap: var(--sp-2); max-height: 396px; overflow-y: auto; }
.times__list button {
  padding: 13px 0;
  width: 100%;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-0);
  background: var(--white);
  color: var(--black);
  font: inherit;
  font-size: var(--fs-control);
  font-weight: var(--fw-bold);
  cursor: pointer;
  transition: var(--transition-color);
}
.times__list button:hover { border-color: var(--maiss-red); color: var(--maiss-red); }

.booking-window {
  margin: var(--sp-5) 0 0;
  text-align: center;
  font-size: var(--fs-caption);
  color: var(--text-body);
}

/* ---- Result and dead-end pages --------------------------------------- */

/* Centred: for a page that IS the panel -- a confirmation, a cancellation, a
   dead end. Nothing sits beside it, so the middle is where it belongs. */
.panel--narrow { max-width: 820px; margin: 0 auto; }

/* Left-aligned: for a panel that sits UNDER a page heading. Centring one there
   gives the page two competing axes, and this design pins everything to a red
   rule on the left -- the mismatch is the first thing a reader notices. */
.panel--message { max-width: 820px; }

.result__headline { font-size: var(--fs-result); line-height: var(--lh-h1); margin-bottom: var(--sp-3); }
.result__lead {
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  max-width: var(--content-max);
  margin-bottom: var(--sp-8);
}

/* .panel--narrow, .result__headline and .result__lead already exist -- Task 6
   added them with _unavailable.html, which uses the same shape. Only the
   actions row and the facts grid are new here. */
.result__actions { margin-top: var(--sp-8); gap: var(--sp-4) var(--sp-6); }

/* Four facts, two by two, separated by hairlines rather than boxes. The
   grid draws its own lines: an outer border plus per-cell borders would
   double every rule. */
.facts-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  border-top: var(--bw-hairline) solid var(--border-hairline);
}
.facts-grid__cell {
  padding: var(--sp-6) var(--sp-6) var(--sp-6) 0;
  border-bottom: var(--bw-hairline) solid var(--border-hairline);
}
.facts-grid__cell:nth-child(even) {
  padding-left: var(--sp-6);
  padding-right: 0;
  border-left: var(--bw-hairline) solid var(--border-hairline);
}
.facts-grid__label { margin: 0 0 var(--sp-1); font-size: var(--fs-caption); color: var(--text-body); }
.facts-grid__value { margin: 0; font-size: var(--fs-body); font-weight: var(--fw-bold); color: var(--black); }
.facts-grid__note { margin: 3px 0 0; font-size: var(--fs-label); color: var(--text-body); }

/* Cancel screen: the plain-notice box repeating the booking, and the
   optional per-appointment-type deadline text below the reason field. */
.cancel__summary { margin-bottom: var(--sp-6); }
.cancel__notice {
  /* 13.5px already exists as --fs-error (used by .field__error) -- reused
     here rather than repeating the literal for an unrelated purpose. */
  font-size: var(--fs-error);
  line-height: var(--lh-body-sm);
  color: var(--text-body);
  margin: var(--sp-4) 0 var(--sp-6);
}

/* ---- Two-column detail card (form, cancel, reschedule) --------------- */

.detail-card {
  display: flex;
  flex-wrap: wrap;
  align-items: stretch;
  background: var(--surface-card);
  border: var(--bw-hairline) solid var(--border-hairline);
}

.detail-card__summary {
  flex: 1 1 300px;
  min-width: 280px;
  padding: var(--sp-8);
  border-right: var(--bw-hairline) solid var(--border-hairline);
  background: var(--surface-subtle);
}
.detail-card__when { margin-bottom: var(--sp-6); }
.detail-card__when p { margin: 0; }
.detail-card__date, .detail-card__time { display: block; font-size: var(--fs-h3); line-height: var(--lh-h3); color: var(--black); }
.detail-card__date { font-weight: var(--fw-bold); }

.detail-card__facts { display: grid; gap: var(--sp-3); margin: 0 0 var(--sp-6); font-size: var(--fs-body-sm); }
.detail-card__facts dt { color: var(--text-body); }
.detail-card__facts dd { margin: 0; font-weight: var(--fw-bold); color: var(--black); }

.detail-card__form { flex: 2 1 420px; min-width: 340px; padding: var(--sp-8) var(--sp-10); }
.detail-card__lead { margin: var(--sp-2) 0 var(--sp-8) 22px; font-size: var(--fs-body-sm); color: var(--text-body); }
.detail-card__privacy { margin: var(--sp-5) 0; }
.detail-card__reassurance { font-size: var(--fs-caption); color: var(--text-body); }

/* ---- Error summary --------------------------------------------------- */

/* The list at the top of a form that failed. Every entry links to its field,
   so a keyboard user reaches the problem without hunting for it -- which is
   the half of NFA-3 that a red border alone cannot do. */
.error-summary {
  border-left: var(--bw-rule) solid var(--maiss-red);
  padding: var(--sp-1) 0 var(--sp-1) var(--sp-5);
  margin-bottom: var(--sp-8);
}
.error-summary__title { margin: 0 0 var(--sp-1); font-size: var(--fs-lead); font-weight: var(--fw-bold); color: var(--black); }
.error-summary ul { margin: var(--sp-3) 0 0; padding-left: var(--sp-5); color: var(--maiss-red); line-height: 1.7; }
.error-summary a { color: var(--maiss-red); text-decoration: underline; }

/* ---- Reschedule ------------------------------------------------------ */

.reschedule__head { padding: var(--sp-8) var(--sp-10); border-bottom: var(--bw-hairline) solid var(--border-hairline); }
.reschedule__body { padding: var(--sp-8) var(--sp-10) var(--sp-10); }

.reschedule__facts { display: flex; gap: var(--sp-10); flex-wrap: wrap; margin: var(--sp-5) 0 0 22px; }
.reschedule__facts dt { font-size: var(--fs-caption); color: var(--text-body); margin-bottom: 3px; }
.reschedule__facts dd { margin: 0; font-size: var(--fs-body); font-weight: var(--fw-bold); color: var(--black); }

/* The old time is struck through in red -- the one place a line through
   text is doing work rather than decorating. */
.reschedule__old { text-decoration-line: line-through; text-decoration-color: var(--maiss-red); }

.reschedule__h { font-size: var(--fs-control); margin-bottom: var(--sp-1); }
.reschedule__hint { font-size: var(--fs-label); color: var(--text-body); margin-bottom: var(--sp-5); }
.reschedule__note { margin-top: var(--sp-5); font-size: var(--fs-error); color: var(--text-body); }
.reschedule__actions { margin-top: var(--sp-6); }

/* Inside the reschedule panel the card is already framed by the panel. */
.booking-card--bare { border: none; }
.booking-card--bare .booking-card__cal { border-left: var(--bw-hairline) solid var(--border-hairline); }

/* ---- Slot taken -------------------------------------------------------- */

/* The remaining times of the day the slot was lost on. Buttons rather than
   links -- each one resubmits the kept-along guest details, which is the
   whole point of this screen (US-20). */
.alternatives { display: flex; gap: var(--sp-2); flex-wrap: wrap; margin-bottom: var(--sp-6); }
.alternatives .btn { min-height: 48px; padding: var(--sp-3) var(--sp-5); font-size: var(--fs-control); }

/* ---- Webinar overview ------------------------------------------------ */

.wpage__heading { margin-bottom: var(--sp-5); }
.wpage__heading h1 { font-size: 38px; line-height: var(--lh-display); }
.wpage__intro {
  max-width: var(--content-max);
  margin: 0 0 var(--sp-10) 22px;
  font-size: var(--fs-body);
  line-height: var(--lh-body);
}

.wchips { display: flex; gap: var(--sp-2); flex-wrap: wrap; margin-bottom: var(--sp-8); }
.wchip {
  padding: 9px var(--sp-5);
  border: var(--bw-hairline) solid var(--border-hairline);
  background: var(--white);
  color: var(--black);
  font-size: var(--fs-label);
  transition: var(--transition-color);
}
.wchip:hover { border-color: var(--maiss-red); color: var(--maiss-red); text-decoration: none; }
.wchip.is-current {
  border-color: var(--maiss-red);
  background: var(--maiss-red);
  color: var(--text-on-red);
  font-weight: var(--fw-bold);
}

.wgrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(285px, 1fr)); gap: var(--sp-8); }

.wcard {
  display: flex;
  flex-direction: column;
  border: var(--bw-hairline) solid var(--border-hairline);
  background: var(--surface-card);
}
.wcard__media { position: relative; }
.wcard__media img { width: 100%; aspect-ratio: 4 / 3; object-fit: cover; }

/* Red because it is a status, not decoration -- the one place on this page
   where red is not an action. */
.wcard__flag {
  position: absolute;
  top: 0;
  right: 0;
  margin: 0;
  padding: var(--sp-2) var(--sp-4);
  background: var(--maiss-red);
  color: var(--text-on-red);
  font-size: var(--fs-micro);
  letter-spacing: .14em;
  text-transform: uppercase;
  font-weight: var(--fw-bold);
}
.wcard__flag--bare { position: static; align-self: flex-start; }

.wcard__topic {
  margin: 0;
  padding: 9px var(--sp-5);
  background: var(--maiss-red);
  color: var(--text-on-red);
  font-size: var(--fs-micro);
  letter-spacing: .14em;
  text-transform: uppercase;
  font-weight: var(--fw-bold);
}

.wcard__body { display: flex; flex-direction: column; flex: 1; padding: var(--sp-6); }
.wcard__when { display: flex; align-items: baseline; gap: var(--sp-3); margin: 0 0 var(--sp-4); }
.wcard__day { font-size: var(--fs-h2); font-weight: var(--fw-bold); color: var(--black); line-height: 1; }
.wcard__time { font-size: var(--fs-label); color: var(--text-body); }
.wcard__title { font-size: var(--fs-lead); line-height: var(--lh-h3); margin-bottom: var(--sp-2); }
.wcard__text { font-size: var(--fs-body-sm); line-height: var(--lh-body-sm); margin-bottom: var(--sp-3); }
.wcard__host { font-size: var(--fs-error); color: var(--text-body); margin-bottom: var(--sp-5); }

.wcard__foot {
  margin-top: auto;
  padding-top: var(--sp-4);
  border-top: var(--bw-hairline) solid var(--border-hairline);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  flex-wrap: wrap;
}
.wcard__seats { font-size: var(--fs-error); color: var(--text-body); }
.wcard__seats--none { color: var(--maiss-red); font-weight: var(--fw-bold); }
.wcard__cta { min-height: 42px; padding: var(--sp-2) var(--sp-5); }

.wpast { margin-top: var(--sp-12); padding-top: var(--sp-6); border-top: var(--bw-hairline) solid var(--border-hairline); }
.wpast__list { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-4); }
.wpast__item { display: flex; gap: var(--sp-5); flex-wrap: wrap; align-items: baseline; color: var(--text-body); }
.wpast__date { flex: 0 0 90px; font-size: var(--fs-body); font-weight: var(--fw-bold); }
.wpast__title { flex: 1 1 320px; min-width: 0; font-size: var(--fs-control); }
.wpast__audience { color: var(--text-muted); }
.wpast__note { flex: 0 1 200px; font-size: var(--fs-label); }

/* ---- One webinar ----------------------------------------------------- */

.wdetail {
  display: flex;
  flex-wrap: wrap;
  align-items: stretch;
  background: var(--surface-card);
  border: var(--bw-hairline) solid var(--border-hairline);
}
.wdetail__main { flex: 2 1 420px; min-width: 340px; padding: var(--sp-10) var(--sp-10) var(--sp-8); }
.wdetail__side {
  flex: 1 1 320px;
  min-width: 280px;
  padding: var(--sp-10);
  border-left: var(--bw-hairline) solid var(--border-hairline);
  background: var(--surface-subtle);
}
.wdetail__heading { margin-bottom: var(--sp-5); }
.wdetail__heading h1 { font-size: 30px; line-height: var(--lh-h1); }
.wdetail__text { font-size: 16.5px; line-height: var(--lh-body); max-width: var(--content-max); margin-bottom: var(--sp-6); }
.wdetail__image { width: 100%; max-height: 320px; object-fit: cover; margin-bottom: var(--sp-6); }

.wdetail__facts {
  display: grid;
  gap: var(--sp-4);
  margin: 0;
  padding-top: var(--sp-5);
  border-top: var(--bw-hairline) solid var(--border-hairline);
}
.wdetail__facts dt { font-size: var(--fs-caption); color: var(--text-body); }
.wdetail__facts dd { margin: 2px 0 0; font-size: var(--fs-control); font-weight: var(--fw-bold); color: var(--black); }
.wdetail__note { display: block; font-size: var(--fs-caption); font-weight: var(--fw-regular); color: var(--text-body); margin-top: 2px; }

.wdetail__seats { display: flex; align-items: baseline; gap: var(--sp-2); margin: 0 0 var(--sp-2); }
.wdetail__count { font-size: 34px; font-weight: var(--fw-bold); color: var(--black); line-height: 1; }
.wdetail__of { font-size: var(--fs-body-sm); color: var(--text-body); }
.wdetail__seatline { font-size: var(--fs-body-sm); font-weight: var(--fw-bold); color: var(--maiss-red); margin: var(--sp-3) 0 0; }

.wbar { height: 6px; background: var(--gray-200); margin: 0 0 var(--sp-6); }
.wbar__fill { display: block; height: 6px; background: var(--maiss-red); }

.wdetail__hint { font-size: var(--fs-caption); line-height: var(--lh-caption); color: var(--text-body); margin-bottom: var(--sp-5); }
/* The confidentiality note sits *below* the registration form, where every
   other hint in this column sits above what it explains. A <form> carries no
   bottom margin of its own, so without this the sentence butts straight
   against the submit button and reads as part of it. */
.wdetail__hint--after { margin-top: var(--sp-4); }
.wdetail__action { width: 100%; justify-content: center; }


/* ---- A host's appointment types -------------------------------------- */

.hostpage__heading { margin-bottom: var(--sp-8); }
.hostpage__heading h1 { font-size: 34px; line-height: var(--lh-h1); }

.typelist { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-4); }
.typelist__item {
  display: flex;
  gap: var(--sp-6);
  align-items: center;
  flex-wrap: wrap;
  padding: var(--sp-6);
  background: var(--surface-card);
  border: var(--bw-hairline) solid var(--border-hairline);
}
.typelist__body { flex: 1 1 320px; min-width: 0; }
.typelist__title { font-size: var(--fs-h3); line-height: var(--lh-h3); margin-bottom: var(--sp-2); }
.typelist__text { font-size: var(--fs-body-sm); line-height: var(--lh-body-sm); margin-bottom: var(--sp-2); }
.typelist__facts { margin: 0; font-size: var(--fs-caption); color: var(--text-body); }
.typelist__cta { flex: 0 0 auto; }
/* Host portrait on the "who would you like to talk to?" list. Same circle as
   .type-panel__portrait rather than a shared class: that one belongs to the
   type panel's BEM block, and borrowing it across blocks is how a change to
   one silently reshapes the other. */
.typelist__portrait { width: 56px; height: 56px; border-radius: var(--radius-circle); object-fit: cover; flex: none; }

/* Spacing for the appointment sections on the site root. Nothing else: both
   reuse .typelist, and the headings reuse .u-rule. */
.wappt { margin-top: var(--sp-10); }

/* ---- Old time -> new time -------------------------------------------------
   The one new component on the confirm/decline/reschedule screens. Everything
   else there reuses .facts-grid, .field and .actions exactly as
   confirmed.html and cancel.html do.

   .reschedule__facts was what the reschedule summary first reused, and it was
   the wrong thing: it is a flex strip carrying a hard-coded `margin-left: 22px`
   that aligns it under the *head's* rule bar, so inside .reschedule__body that
   indent has nothing to align to and the pairs ran together.

   No arrow glyph between the two: it would point sideways while the blocks
   stack at 360px. The line-through in Maiss red already says "replaced", and
   that treatment is the system's own -- see .reschedule__old, which this
   deliberately matches rather than reusing across BEM blocks. */
.timeshift { display: flex; gap: var(--sp-10); flex-wrap: wrap; margin: 0 0 var(--sp-6); }
.timeshift__label { display: block; font-size: var(--fs-caption); color: var(--text-body); margin-bottom: 3px; }
.timeshift__value { display: block; font-size: var(--fs-control); font-weight: var(--fw-bold); color: var(--black); }
.timeshift__value--old {
  font-weight: var(--fw-regular);
  color: var(--text-body);
  text-decoration-line: line-through;
  text-decoration-color: var(--maiss-red);
}

/* ---- Responsive ------------------------------------------------------- */

/* Two blocks, one per breakpoint, and every responsive rule in the file lives
   in one of them. Verify with `grep -n @media` before editing this line: it
   should return exactly these two, and nothing above them.

   This has now drifted twice. First there were three 640px blocks and two
   900px ones scattered through the file, under a comment claiming they were
   "kept together on purpose". Then the webinar and host sections were appended
   BELOW the merged pair and brought a 900px block and a 640px block of their
   own -- four blocks under a comment saying two. Both times the comment was
   the only thing that would have caught it.

   The second drift was not merely untidy, and this is the part worth
   understanding. A media query contributes nothing to specificity, so an
   @media rule beats a plain rule of equal weight only by coming later in the
   source. With the pair sitting mid-file, a mobile override added to it could
   not touch any webinar or host selector declared below it -- the hazard this
   comment documents, live in the file the comment sits in. The fix was to move
   the pair to the true foot, after every plain rule, and fold the two strays
   into it.

   So: both blocks stay LAST, and anything appended to this file goes above
   them, never below. Wider breakpoint first, for the same cascade reason. */

@media (max-width: 900px) {
  /* One column below tablet width. The borders that separated the columns
     become separators between stacked blocks, otherwise the last one draws
     a stray line down the right edge (US-51). */
  .type-panel, .booking-card__cal {
    border-right: none;
    border-bottom: var(--bw-hairline) solid var(--border-hairline);
  }

  /* The reschedule screen's bare card gives its calendar a left hairline to
     separate it from the times column. Once stacked there is no times column
     beside it, so that line has no counterpart and reads as a stray mark down
     the left edge -- the mirror image of the border-right the rule above
     clears, and it needs clearing in the same place. */
  .booking-card--bare .booking-card__cal { border-left: none; }

  /* Below the stacking breakpoint the calendar sits alone on its row, so its
     two-column minimum is no longer doing any work -- and flex-shrink cannot
     pull an element below its own min-width, which is what pushed a 340px
     column out of a 280px content box at 360px viewport width (US-51). */
  .booking-card__cal { min-width: 0; }

  .detail-card__summary { border-right: none; border-bottom: var(--bw-hairline) solid var(--border-hairline); }

  /* Once stacked, .detail-card__form is alone on its row and its 340px
     min-width no longer describes a real two-column layout -- it is just a
     floor that flex-shrink cannot cross. At 360px, .shell's content box is
     only 320px (see the 640px gutter rule below), so without this the form
     column pokes past the viewport by a few pixels, exactly the overflow
     .booking-card__cal { min-width: 0; } already prevents on the slot
     picker (US-51). */
  .detail-card__form { min-width: 0; }

  .wdetail__side { border-left: none; border-top: var(--bw-hairline) solid var(--border-hairline); }
  /* Stacked, so the two-column minimums are only floors flex-shrink cannot get
     under -- the overflow this project has hit three times (US-51). */
  .wdetail__main, .wdetail__side { min-width: 0; }
}

@media (max-width: 640px) {
  /* 40px gutters each side cost a fifth of a 360px viewport. The desktop
     value is right for a 1180px page and wrong for a phone. */
  .shell { padding-left: var(--sp-5); padding-right: var(--sp-5); }

  /* Below 360px the three labels cannot sit side by side without wrapping
     into an unreadable stack of single letters (US-51). The marks stay, the
     labels go -- aria-current still reports the position. */
  .steps__label { display: none; }
  .steps__item { flex: 1 1 0; }

  /* WCAG 2.2 SC 2.5.8 Target Size (Minimum, AA): a control must be at least
     24 x 24 CSS px. The month arrows were 19.33 x 34 at both 360px and 320px
     -- not because anything overflowed, but because .calendar__month's
     200px min-width plus 2 x 24px of gap wanted more room than the column
     had, and the only flex items able to give it back were the two buttons.
     They shrank instead of the label, silently, and a page that links an
     accessibility statement in its own footer cannot do that.

     Three declarations, and all three are needed: the label has to be allowed
     to shrink (min-width), the buttons have to be forbidden from it
     (flex: none), and the gap has to come down or there is nothing left for
     the label. Measured afterwards at 320, 360 and 390px: 34 x 34 buttons,
     no horizontal overflow. Do not reintroduce the shrink. */
  .calendar__nav { gap: var(--sp-4); }
  .calendar__month { min-width: 0; }
  .calendar__nav-link { flex: none; }

  .facts-grid { grid-template-columns: 1fr; }
  .facts-grid__cell:nth-child(even) { padding-left: 0; border-left: none; }

  /* .reschedule__body's own horizontal padding stacks on top of .shell's
     already-reduced mobile gutter above, leaving the seven-column calendar
     grid narrower than it is anywhere else in the booking flow -- narrow
     enough that two-digit day numbers were clipped behind their neighbouring
     circle (US-51). Only the card bleeds back out to the panel's own edges
     (already its visual frame); the surrounding text keeps its padding rather
     than running into the panel border too. */
  .booking-card--bare { margin-left: calc(-1 * var(--sp-10)); margin-right: calc(-1 * var(--sp-10)); }

  /* The button drops below the text and takes the full width -- side by side
     it would be squeezed under 24px of tap target (WCAG 2.2 SC 2.5.8). */
  .typelist__cta { width: 100%; justify-content: center; }
}

/* NFA-3: the plain list of the next free times, the route that is not the
   calendar picture. Deliberately styled as text with buttons rather than as a
   second grid -- its whole point is that it reads in order. */
.nextfree {
  margin-top: var(--sp-6);
  padding: var(--sp-5) var(--sp-5) var(--sp-4);
  background: var(--surface-card);
  border-top: var(--bw-hairline) solid var(--border-hairline);
}
.nextfree__title {
  margin: 0 0 var(--sp-1);
  font-size: var(--fs-h3);
  color: var(--text-strong);
}
.nextfree__hint {
  margin: 0 0 var(--sp-4);
  font-size: var(--fs-body-sm);
  color: var(--text-muted);
}
.nextfree__day + .nextfree__day { margin-top: var(--sp-4); }
.nextfree__date {
  margin: 0 0 var(--sp-2);
  font-size: var(--fs-body-sm);
  font-weight: var(--fw-bold);
  color: var(--text-strong);
}
.nextfree__times {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
  margin: 0;
  padding: 0;
  list-style: none;
}
.nextfree__times button {
  padding: var(--sp-2) var(--sp-4);
  border: var(--bw-hairline) solid var(--border-control);
  border-radius: var(--radius-0);
  background: var(--surface-card);
  color: var(--text-strong);
  font: inherit;
  cursor: pointer;
}
.nextfree__times button:hover { border-color: var(--maiss-red); color: var(--maiss-red); }
