/* "Atrium" homepage theme.
 *
 * A photography-first practice homepage: a full-bleed header photo with the
 * page title lying on its lower edge, the content rising over it as white
 * sheets on a faintly tinted page, light large headings against small
 * letterspaced labels, one dark full-bleed contact band, a light footer.
 *
 * Photos are the point — and the point of failure. Every place a photo would
 * go has a designed empty state, so a practice without pictures gets a page
 * that stands on surface, type and space instead of one with holes in it:
 *
 *   .hero--plain          no header photo -> the theme's bundled hero.jpg
 *   .cms-team__member     no portrait     -> an accent rule over a larger name
 *   .cms-gallery          no pictures     -> the section removes itself
 *   .cms-quote-banner     no background   -> a flat deep accent band with a mark
 *
 * Every colour is mixed from the single --c-accent token, which the practice
 * overrides from the UI (tenant_theme_css, loaded after this file). No
 * hard-coded accent hex anywhere; the neutrals are near-grey with a whisper of
 * the accent in them, so the whole page shifts when the accent does.
 *
 * System fonts only — nothing to download, nothing to license.
 */

:root {
  /* The one colour a practice picks. Everything else is mixed from it. */
  --c-accent: #1d5c56;

  /* Readable text on an accent-coloured surface — the name the islands read
     too. The plain value is the fallback for browsers without relative colour
     syntax; the derivation below flips it to black once the accent is light,
     so a pale accent never ends up with white-on-pale labels. */
  --c-on-accent: #fff;

  /* Text tones. A plain mix with the accent breaks the moment a practice picks
     a pale one (mix 78 % of a light yellow with near-black and the link comes
     out at 2.7:1). So each text tone takes only the accent's *hue* and a share
     of its chroma, and pins its own lightness — the tint follows the accent,
     the contrast does not depend on it. The mixes above each are the fallback
     for browsers without relative colour syntax. */
  --c-ink: color-mix(in oklab, var(--c-accent) 18%, #0e1112);
  --c-ink: oklch(from var(--c-accent) 0.22 calc(c * 0.35) h);
  --c-body: color-mix(in oklab, var(--c-accent) 16%, #55595c);
  --c-body: oklch(from var(--c-accent) 0.44 calc(c * 0.22) h);
  --c-soft: color-mix(in oklab, var(--c-accent) 14%, #6b7074);
  --c-soft: oklch(from var(--c-accent) 0.5 calc(c * 0.2) h);

  /* Links keep the accent's full colour, but never rise above the lightness
     that still passes AA on a white sheet; hover goes darker, not lighter. */
  --c-link: color-mix(in oklab, var(--c-accent) 78%, #12181a);
  --c-link: oklch(from var(--c-accent) min(l, 0.42) c h);
  --c-link-hover: color-mix(in oklab, var(--c-accent) 55%, #12181a);
  --c-link-hover: oklch(from var(--c-accent) min(l, 0.3) c h);

  /* Surfaces. Same rule as the text tones, for the same reason: a plain mix
     carries the accent's own lightness through, so a near-black accent greyed
     the page and the tint band down until the muted type on them failed, and a
     near-white accent bleached the tint band away. Hue and a share of the
     chroma follow the accent; the lightness is the theme's. */
  --c-page: color-mix(in oklab, var(--c-accent) 4%, #f6f6f5);
  --c-page: oklch(from var(--c-accent) 0.973 min(c, 0.012) h);
  --c-sheet: color-mix(in oklab, var(--c-accent) 2%, #ffffff);
  --c-sheet: oklch(from var(--c-accent) 0.995 min(c, 0.006) h);
  --c-line: color-mix(in oklab, var(--c-accent) 12%, #e2e4e5);
  --c-line: oklch(from var(--c-accent) 0.905 min(c, 0.02) h);
  --c-tint: color-mix(in oklab, var(--c-accent) 8%, #ffffff);
  --c-tint: oklch(from var(--c-accent) 0.965 min(c, 0.03) h);
  --c-tint-line: color-mix(in oklab, var(--c-accent) 26%, #ffffff);
  --c-tint-line: oklch(from var(--c-accent) 0.86 min(c, 0.06) h);

  /* `--c-line` is a *decorative* hairline — the rule between two opening-hours
     rows, the ring around a portrait — and is deliberately faint. The boundary
     of a control is not decorative: a form field and a button have to be
     findable, which WCAG puts at 3 : 1. Two tokens rather than one, because
     making `--c-line` strong enough for a field would draw every hairline on
     the page as a hard rule.

       --c-field-line  a neutral border with a whisper of the accent, for the
                       edge of an input on a white sheet
       --c-edge        the accent itself, but never lighter than the page can
                       carry — for the shapes that *are* the accent (the
                       button's outline, the "today" marker). For any accent
                       darker than the cap this is the accent, unchanged. */
  --c-field-line: color-mix(in oklab, var(--c-accent) 22%, #6f7477);
  --c-field-line: oklch(from var(--c-accent) 0.58 min(c, 0.03) h);
  --c-edge: color-mix(in oklab, var(--c-accent) 74%, #43494b);
  --c-edge: oklch(from var(--c-accent) min(l, 0.55) max(c, 0.02) h);

  /* The dark bands (contact, quote, header wall). Pinned for the same reason
     the surfaces are: at 22 % of a white accent the "one dark band of the
     page" came out mid-grey, and the hairline around its input fields sank to
     1.36 : 1 against it. */
  --c-deep: color-mix(in oklab, var(--c-accent) 22%, #13171a);
  --c-deep: oklch(from var(--c-accent) 0.24 min(c, 0.05) h);
  --c-deep-ink: color-mix(in oklab, var(--c-accent) 6%, #ffffff);
  --c-deep-ink: oklch(from var(--c-accent) 0.97 min(c, 0.02) h);
  --c-deep-soft: color-mix(in oklab, var(--c-accent) 14%, #b6bcbf);
  --c-deep-soft: oklch(from var(--c-accent) 0.78 min(c, 0.03) h);
  --c-deep-line: color-mix(in oklab, var(--c-accent) 30%, #454b4e);
  --c-deep-line: oklch(from var(--c-accent) 0.55 min(c, 0.05) h);

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

  --w-page: 72rem;
  --pad: clamp(1.25rem, 5vw, 3rem);
  --bar-h: 4.25rem;
  --shadow: 0 1px 2px rgb(0 0 0 / 4%), 0 18px 42px -22px rgb(0 0 0 / 22%);
}

/* Black or white on the accent — the same rule the form islands encode
   (@conjunto/ui/island.css, docs/dev/islands.md), so a practice gets the
   same label on its homepage button as on the standalone request page.

   The flip is made on the accent's *relative luminance* at 0.1775, not on a
   perceptual lightness: WCAG guarantees every sRGB colour clears 4.5 : 1
   against black or against white, but only around that value. This theme used
   to flip on OKLCH `l` at 0.62, which bottomed out at 1.00 : 1 — an accent
   whose lightness sits inside the clamp's ramp came out with a *grey* label
   (`#1CA010` → `#8A8A8A`), and 2 % of the sRGB cube lands in that band.

   `pow((c + 0.055) / 1.055, 2.4)` is the sRGB transfer function without its
   linear toe, which only bends near-black channels, far from the flip. */
@supports (color: rgb(from red r g b)) and (width: calc(pow(2, 2) * 1px)) {
  :root {
    --c-accent-luminance: calc(
      0.2126 * pow((r / 255 + 0.055) / 1.055, 2.4) +
      0.7152 * pow((g / 255 + 0.055) / 1.055, 2.4) +
      0.0722 * pow((b / 255 + 0.055) / 1.055, 2.4)
    );
    /* 0 or 255 — and the multiplier decides how wide the band of accents is
       that gets neither. At 1000 the ramp is 0.001 of luminance wide, which
       sounds like nothing and is not: #bb5555 sits at 0.1771, four ten-
       thousandths under the flip, and came out with a 40 % grey label at
       1.69 : 1 on its own button. Sweeping the cube at 16 steps per channel
       finds such an accent, so a practice picking a colour by eye certainly
       can. A million makes the ramp 10^-6 wide — narrow enough that any
       accent inside it clears 4.5 : 1 against black *and* white anyway. */
    --c-on-accent-channel: calc(
      255 * clamp(0, (0.1775 - var(--c-accent-luminance)) * 1000000, 1)
    );
    --c-on-accent: rgb(
      from var(--c-accent) var(--c-on-accent-channel)
        var(--c-on-accent-channel) var(--c-on-accent-channel)
    );
  }
}

/* ---------------------------------------------------------------- base --- */

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

html {
  /* The header is fixed; without this an #anchor jump parks its heading
     underneath the bar.
   *
   * Not --bar-h directly: that is the bar's *minimum*, and a long practice
   * name wraps straight through it — "Gemeinschaftspraxis für Allgemeinmedizin
   * und Innere Medizin Dr. …" makes the bar 143 px on a 320 px screen against
   * the 68 px declared here, and every quick-access jump then lands 51 px
   * under it. theme.js measures the bar and overwrites --bar-offset; --bar-h
   * is only the value to fall back on when there is no scripting — and then
   * the bar is not fixed and covers nothing anyway. A separate name on
   * purpose: writing the measurement back into --bar-h would feed it into the
   * bar's own min-height and latch the tallest height it ever had. */
  --bar-offset: var(--bar-h);
  scroll-padding-top: calc(var(--bar-offset) + 1.5rem);
  scroll-behavior: smooth;
}

body {
  margin: 0;
  /* Full-bleed bands are 100vw wide inside a padded column; clip (not hidden)
     keeps them from making the page scroll sideways without breaking sticky. */
  overflow-x: clip;
  background: var(--c-page);
  color: var(--c-body);
  font-family: var(--font);
  font-size: 1.0625rem;
  line-height: 1.7;
  -webkit-font-smoothing: antialiased;
}

img {
  max-width: 100%;
  height: auto;
}

a {
  color: var(--c-link);
  text-decoration-thickness: 1px;
  text-underline-offset: 0.2em;
}

a:hover {
  color: var(--c-link-hover);
}

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

h1,
h2,
h3,
h4 {
  color: var(--c-ink);
  font-weight: 300;
  letter-spacing: -0.015em;
  line-height: 1.15;
  margin: 0 0 1rem;
  text-wrap: balance;
}

p {
  margin: 0 0 1.15em;
  max-width: 68ch;
}

/* The small letterspaced label that sits over every group of facts. */
.footer__label,
.cms-contact__group-title,
.cms-team__role,
.cms-services__category,
.cms-patient-info__name,
.cms-quote-banner__attribution {
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--c-soft);
  margin: 0 0 0.6rem;
}

/* -------------------------------------------------------------- topbar --- */

/* The bar floats on the header photo — but only where scripting can turn it
   solid again further down the page. Without it there is no `.is-scrolled` and
   no menu button, so the bar would carry the whole wrapped nav list *and* keep
   it pinned: 412 px of a 320×568 screen (73 %) forever, with white links lying
   on the white sheets at 1.03 : 1 once the visitor scrolled past the photo.
   Unscripted the header is therefore an ordinary solid sheet at the top of the
   document, which scrolls away and covers nothing. */
.has-js .topbar {
  position: fixed;
  inset-inline: 0;
  top: 0;
  transition: background-color 0.25s ease, box-shadow 0.25s ease;
}

.topbar {
  position: relative;
  z-index: 60;
}

/* The bar's own scrim: a practice photo can be a bright wall exactly under the
   name (the bundled hero is — the name measured 2.23 : 1 against it). It is
   the height of the bar alone, so the photograph below it stays open, and it
   goes with the same fade as the transparent state it belongs to. */
.has-js .topbar::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: linear-gradient(
    to bottom,
    rgb(0 0 0 / 68%) 0%,
    rgb(0 0 0 / 58%) 62%,
    rgb(0 0 0 / 0%) 100%
  );
  transition: opacity 0.25s ease;
}

.has-js .topbar.is-scrolled::before {
  opacity: 0;
}

.topbar.is-scrolled,
html:not(.has-js) .topbar {
  background: var(--c-sheet);
  box-shadow: 0 1px 0 var(--c-line), 0 10px 30px -24px rgb(0 0 0 / 40%);
}

.topbar__inner {
  /* Above the open menu sheet, which is a later sibling and would otherwise
     paint over the button that closes it. */
  position: relative;
  z-index: 1;
  max-width: var(--w-page);
  margin-inline: auto;
  padding: 0 var(--pad);
  min-height: var(--bar-h);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
}

.topbar__brand {
  display: inline-flex;
  align-items: center;
  min-height: 2.75rem;
  text-decoration: none;
  margin-inline-start: auto;
}

/* Over a photo a logo can land on anything — a sky, a white ceiling. The soft
   shadow lifts it off whatever is behind, and goes once the bar is solid. */
.topbar__logo {
  max-height: 2.5rem;
  width: auto;
  filter: drop-shadow(0 1px 8px rgb(0 0 0 / 55%));
}

.topbar.is-scrolled .topbar__logo,
html:not(.has-js) .topbar__logo {
  filter: none;
}

/* A practice logo is usually dark ink on transparency; over the open menu
   sheet it would be unreadable, and recolouring someone's mark is not ours to
   do. The sheet already names every destination, so the brand steps aside. */
.topbar[data-nav-open="true"] .topbar__brand {
  visibility: hidden;
}

.topbar__name {
  color: #fff;
  font-size: 1.05rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-shadow: 0 1px 12px rgb(0 0 0 / 55%);
}

.topbar.is-scrolled .topbar__name,
html:not(.has-js) .topbar__name {
  color: var(--c-ink);
  text-shadow: none;
}

/* The menu button. Shown only once theme.js has run (html.has-js); without
   scripting the nav list below stays a plain wrapped row. */
.topbar__toggle {
  display: none;
  /* Never let the practice name squeeze the burger: it sits in the same flex
     row, and a long German name (two specialities plus a double surname) shrank
     the 2.75rem square to 24 px wide on a 320 px screen. */
  flex: none;
  width: 2.75rem;
  height: 2.75rem;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
  color: #fff;
}

.has-js .topbar__toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.topbar.is-scrolled .topbar__toggle {
  color: var(--c-ink);
}

.topbar__bars,
.topbar__bars::before,
.topbar__bars::after {
  display: block;
  width: 1.5rem;
  height: 1.5px;
  background: currentColor;
  transition: transform 0.2s ease, opacity 0.2s ease;
}

.topbar__bars::before,
.topbar__bars::after {
  content: "";
  position: relative;
}

.topbar__bars::before {
  top: -0.45rem;
}

.topbar__bars::after {
  top: 0.45rem;
}

.topbar[data-nav-open="true"] .topbar__bars {
  background: transparent;
}

.topbar[data-nav-open="true"] .topbar__bars::before {
  transform: translateY(0.45rem) rotate(45deg);
}

.topbar[data-nav-open="true"] .topbar__bars::after {
  transform: translateY(-0.45rem) rotate(-45deg);
}

/* Menu, closed state (with scripting): a full-height sheet off to the side. */
.topbar__list {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem 1.5rem;
  margin: 0;
  padding: 0 var(--pad) 0.75rem;
  max-width: var(--w-page);
  margin-inline: auto;
}

.topbar__link {
  display: inline-block;
  padding: 0.5rem 0;
  min-height: 2.75rem;
  color: #fff;
  font-size: 0.95rem;
  letter-spacing: 0.02em;
  text-decoration: none;
  text-shadow: 0 1px 12px rgb(0 0 0 / 55%);
  border-bottom: 1px solid transparent;
}

.topbar.is-scrolled .topbar__link,
html:not(.has-js) .topbar__link {
  color: var(--c-body);
  text-shadow: none;
}

.topbar__link:hover,
.topbar__link.is-active {
  color: #fff;
  border-bottom-color: currentColor;
}

.topbar.is-scrolled .topbar__link:hover,
.topbar.is-scrolled .topbar__link.is-active,
html:not(.has-js) .topbar__link:hover,
html:not(.has-js) .topbar__link.is-active {
  color: var(--c-link);
  border-bottom-color: var(--c-link);
}

.has-js .topbar__menu {
  position: fixed;
  inset: 0;
  background: var(--c-deep);
  display: grid;
  /* `safe`: with ten sections on a short landscape window the list is taller
     than the sheet, and plain centring splits the overflow both ways — the
     first entry ends up above the top edge of its own scroll box, where
     nothing can reach it. `safe` falls back to start alignment exactly then,
     and is a no-op whenever the list fits. */
  place-content: safe center start;
  padding: 5rem var(--pad);
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.25s ease, visibility 0.25s;
}

.has-js .topbar[data-nav-open="true"] .topbar__menu {
  opacity: 1;
  visibility: visible;
}

.has-js .topbar__list {
  display: block;
  padding: 0;
  overflow-y: auto;
  max-height: 70vh;
}

.has-js .topbar__link,
.has-js .topbar.is-scrolled .topbar__link {
  color: var(--c-deep-ink);
  font-size: clamp(1.4rem, 5vw, 2.25rem);
  font-weight: 300;
  letter-spacing: -0.01em;
  padding: 0.35rem 0;
  text-shadow: none;
  border: 0;
}

/* The page you are on, and the entry under the pointer. Lightened *upwards*
   rather than mixed towards white: 55 % of a near-black accent is a mid grey,
   and on the deep sheet that made the current page (2.21 : 1) harder to read
   than the entries around it. */
.has-js .topbar__link:hover,
.has-js .topbar__link.is-active,
.has-js .topbar.is-scrolled .topbar__link:hover,
.has-js .topbar.is-scrolled .topbar__link.is-active {
  color: color-mix(in oklab, var(--c-accent) 55%, #ffffff);
  border: 0;
}

@supports (color: oklch(from red l c h)) {
  .has-js .topbar__link:hover,
  .has-js .topbar__link.is-active,
  .has-js .topbar.is-scrolled .topbar__link:hover,
  .has-js .topbar.is-scrolled .topbar__link.is-active {
    color: oklch(from var(--c-accent) max(l, 0.78) min(c, 0.12) h);
  }
}

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

.hero {
  position: relative;
  min-height: clamp(26rem, 80vh, 44rem);
  display: flex;
  align-items: flex-end;
  background-color: var(--c-deep);
  background-size: cover;
  background-position: center;
  overflow: hidden;
  isolation: isolate;
}

/* No photo of the practice's own: the bundled default (generated by
   scripts/demo_images) — a bright waiting area, subject to the right, so the
   title keeps the open left. It takes the same scrim as an uploaded photo. */
.hero--plain {
  background-image: url("hero.jpg");
}

/* Scrim under the title. Photos of practice rooms are busy and often bright in
   exactly the lower third, so the title needs its own ground.

   The strong part has to reach as high as the *title* does, not just the lower
   edge: the plate is bottom-aligned but a two-line name reaches some 30 % up,
   and the bundled hero has a bright light shaft exactly there — the white
   title measured 2.33 : 1 against it. The middle still opens up, so the room
   behind is a photograph and not a dark panel. */
.hero::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  background: linear-gradient(
    to top,
    rgb(0 0 0 / 78%) 0%,
    rgb(0 0 0 / 68%) 24%,
    rgb(0 0 0 / 56%) 48%,
    rgb(0 0 0 / 12%) 74%,
    rgb(0 0 0 / 22%) 100%
  );
}

.hero__plate {
  position: relative;
  z-index: 2;
  width: 100%;
  max-width: var(--w-page);
  margin-inline: auto;
  /* The bottom padding must clear the first sheet, which rises up to 4 rem
     into the photo — below that the sheet cuts the title's descenders off. */
  padding: 8rem var(--pad) clamp(5rem, 8vh, 6rem);
}

.hero__title {
  color: #fff;
  font-size: clamp(2.25rem, 7vw, 4.75rem);
  font-weight: 200;
  letter-spacing: -0.03em;
  line-height: 1.02;
  margin: 0;
  max-width: 18ch;
  text-shadow: 0 2px 30px rgb(0 0 0 / 45%);
}

/* Hero block images (one static, several a carousel driven by theme.js). */
.cms-hero {
  position: absolute;
  inset: 0;
  z-index: 0;
}

.cms-hero__track {
  display: flex;
  height: 100%;
  transition: transform 0.9s cubic-bezier(0.4, 0, 0.2, 1);
}

.cms-hero__slide {
  flex: 0 0 100%;
  margin: 0;
  height: 100%;
}

.cms-hero__image {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Fade mode: theme.js adds .is-ready, then stacks the slides. */
.cms-hero.is-ready[data-transition="fade"] .cms-hero__track {
  display: block;
  position: relative;
}

.cms-hero.is-ready[data-transition="fade"] .cms-hero__slide {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity 1.1s ease;
}

.cms-hero.is-ready[data-transition="fade"] .cms-hero__slide.is-active {
  opacity: 1;
}

/* ----------------------------------------------------------- quicknav --- */

/* Shortcuts to the action sections this page actually has. Below the wide
   breakpoint it is a row of chips in the normal flow — it covers nothing,
   which is exactly what a floating overlay does wrong on a narrow window.
   Only where the free margin beside the content column is wider than the rail
   does it lift out of the flow. */
.quicknav {
  max-width: var(--w-page);
  margin: 0 auto;
  padding: 1.25rem var(--pad) 0;
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  position: relative;
  z-index: 3;
}

.quicknav[hidden] {
  display: none;
}

.quicknav__link {
  display: inline-flex;
  align-items: center;
  min-height: 2.75rem;
  padding: 0 1.1rem;
  background: var(--c-sheet);
  border: 1px solid var(--c-line);
  color: var(--c-ink);
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  text-decoration: none;
  box-shadow: var(--shadow);
  transition: background-color 0.2s ease, color 0.2s ease;
}

.quicknav__link:hover {
  background: var(--c-accent);
  border-color: var(--c-accent);
  color: var(--c-on-accent);
}

/* -------------------------------------------------------------- content --- */

.content {
  position: relative;
  z-index: 2;
  max-width: var(--w-page);
  margin: 0 auto;
  padding: 0 var(--pad) clamp(3rem, 8vw, 6rem);
}

/* The white sheets. The vertical rhythm lives on the wrapper the block tag
   emits, never on the section itself. */
.content > .cms-block {
  background: var(--c-sheet);
  box-shadow: var(--shadow);
  padding: clamp(2rem, 5vw, 4.5rem) clamp(1.25rem, 4vw, 4rem);
  margin-block: clamp(1.5rem, 3.5vw, 2.75rem);
}

/* The first sheet rises over the lower edge of the header photo. */
.content > .cms-block:first-child {
  margin-top: clamp(-4rem, -6vw, -2rem);
}

/* Bands that want the full width of the window instead of a sheet. */
.content > .cms-block--full,
.content > .cms-block:has(.cms-quote-banner),
.content > .cms-block:has(.cms-contact),
.content > .cms-block:has(.cms-announcements) {
  background: none;
  box-shadow: none;
  padding: 0;
  margin-inline: calc(50% - 50vw);
}

.content > .cms-block:has(.cms-announcements):first-child,
.content > .cms-block:has(.cms-quote-banner):first-child,
.content > .cms-block:has(.cms-contact):first-child {
  margin-top: 0;
}

.content section {
  scroll-margin-top: calc(var(--bar-offset) + 1.5rem);
}

/* Every section heading gets the same generous entrance. */
.cms-team__title,
.cms-opening-hours__title,
.cms-gallery__title,
.cms-services__title,
.cms-patient-info__title,
.cms-contact__title,
.cms-prescription-link__title,
.cms-appointments-link__title,
.cms-patientportal-link__title,
.cms-map__title,
.cms-announcements__title {
  font-size: clamp(1.75rem, 4.2vw, 3rem);
  margin: 0 0 clamp(1.5rem, 3vw, 2.5rem);
}

/* ----------------------------------------------------------------- team --- */

.cms-team__grid {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: clamp(2.5rem, 5vw, 4rem) clamp(1.5rem, 4vw, 3rem);
}

.cms-team__member {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
}

/* The offset ring is the signature: photo, air, hairline. */
.cms-team__photo {
  width: clamp(8rem, 30vw, 11rem);
  aspect-ratio: 1;
  border-radius: 50%;
  object-fit: cover;
  outline: 1px solid var(--c-line);
  outline-offset: 0.7rem;
  margin: 0.7rem 0 2rem;
}

/* No portrait: no hole, no grey placeholder disc — an accent rule and a larger
   name take the weight the photo would have carried. */
.cms-team__member:not(:has(.cms-team__photo)) {
  border-top: 2px solid var(--c-accent);
  padding-top: 1.5rem;
}

.cms-team__member:not(:has(.cms-team__photo)) .cms-team__name {
  font-size: clamp(1.5rem, 3vw, 2rem);
}

.cms-team__name {
  color: var(--c-ink);
  font-size: 1.3rem;
  font-weight: 300;
  letter-spacing: -0.01em;
  line-height: 1.2;
  margin: 0 0 0.6rem;
}

.cms-team__role {
  margin-bottom: 0.9rem;
}

.cms-team__bio {
  color: var(--c-body);
  font-size: 0.97rem;
}

.cms-team__bio p:last-child {
  margin-bottom: 0;
}

/* -------------------------------------------------------- opening hours --- */

.cms-opening-hours__days {
  list-style: none;
  margin: 0;
  padding: 0;
  max-width: 42rem;
}

.cms-opening-hours__day {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.9rem 0.9rem 0.9rem 0;
  border-bottom: 1px solid var(--c-line);
  border-left: 3px solid transparent;
}

/* "Today" is said by the tint and the marker alone, so both have to survive a
   pale accent — at #ffffff the marker measured 1.03 : 1 against its own row
   and the day silently stopped being marked. */
.cms-opening-hours__day.is-today {
  background: var(--c-tint);
  border-left-color: var(--c-edge);
  padding-left: 0.9rem;
}

.cms-opening-hours__day-name {
  color: var(--c-ink);
  font-weight: 500;
}

/* The abbreviation is a narrow-screen alternative to the full day name. */
.cms-opening-hours__day-abbr {
  display: none;
}

.cms-opening-hours__times {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 0.2rem;
  font-variant-numeric: tabular-nums;
}

.cms-opening-hours__note {
  color: var(--c-soft);
  font-size: 0.85rem;
}

.cms-opening-hours__empty {
  color: var(--c-soft);
}

/* -------------------------------------------------------------- gallery --- */

/* Nothing to show is not an empty grid with a lonely heading — the section
   takes itself out, and so does the sheet it sits on (two sibling :has()
   tests, never nested — nesting one inside the other is invalid CSS). */
.cms-gallery:not(:has(.cms-gallery__item)),
.content > .cms-block:has(.cms-gallery):not(:has(.cms-gallery__item)) {
  display: none;
}

/* A tiled mosaic, not a contact sheet: fixed row height, every fourth picture
   twice as wide and twice as tall. Captions lie on the photo so a long one
   cannot push a tile out of the grid. */
.cms-gallery__grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  grid-auto-rows: 10rem;
  grid-auto-flow: row dense;
  gap: 0.6rem;
}

.cms-gallery__item {
  position: relative;
  margin: 0;
  overflow: hidden;
  background: var(--c-tint);
}

.cms-gallery__link {
  display: block;
  height: 100%;
}

.cms-gallery__image {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.5s ease;
}

.cms-gallery__link:hover .cms-gallery__image {
  transform: scale(1.04);
}

.cms-gallery__caption {
  position: absolute;
  inset-inline: 0;
  bottom: 0;
  padding: 3rem 0.9rem 0.7rem;
  color: #fff;
  font-size: 0.8rem;
  letter-spacing: 0.04em;
  /* The fade has to end where the text begins, not where the box does. A plain
     two-stop gradient over the whole box put the first of three lines (a long
     caption on a 320 px screen) at 24 % black — 1.78 : 1 over a bright photo.
     The 3rem top padding is the fade zone; from there down the veil stays flat
     at 70 %, which holds 7.4 : 1 against a pure white image. */
  background: linear-gradient(
    to top,
    rgb(0 0 0 / 86%) 0%,
    rgb(0 0 0 / 70%) calc(100% - 3rem),
    rgb(0 0 0 / 0%) 100%
  );
  pointer-events: none;
}

/* ------------------------------------------------------------- services --- */

.cms-services__group {
  margin-bottom: 2.5rem;
}

.cms-services__list {
  list-style: none;
  margin: 0;
  padding: 0;
}

.cms-services__item {
  padding: 1.25rem 0;
  border-top: 1px solid var(--c-line);
}

/* Looser leading than the display headings: the coverage badge sits inline in
   this one, and a wrapping name would otherwise collide with it. */
.cms-services__name {
  color: var(--c-ink);
  font-size: 1.1rem;
  font-weight: 500;
  letter-spacing: 0;
  line-height: 1.45;
  margin: 0 0 0.35rem;
}

.cms-services__badge {
  display: inline-block;
  vertical-align: 0.1em;
  margin-left: 0.4rem;
  padding: 0.1rem 0.55rem;
  border: 1px solid var(--c-tint-line);
  background: var(--c-tint);
  color: var(--c-link);
  font-size: 0.68rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.cms-services__description {
  color: var(--c-body);
  font-size: 0.97rem;
}

.cms-services__description p:last-child {
  margin-bottom: 0;
}

/* -------------------------------------------------------- patient info --- */

.cms-patient-info__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: clamp(1.5rem, 3vw, 2.5rem);
}

.cms-patient-info__item {
  padding-top: 1.5rem;
  border-top: 1px solid var(--c-line);
}

.cms-patient-info__name {
  font-size: 0.72rem;
  color: var(--c-link);
}

.cms-patient-info__body {
  color: var(--c-body);
}

.cms-patient-info__body p:last-child {
  margin-bottom: 0;
}

/* ----------------------------------------------------- buttons & links --- */

/* One wide bar with a trailing arrow — the shape every call to action in this
   theme wears. */
.cms-patient-info__download,
.cms-appointments-link__cta,
.cms-patientportal-link__cta,
.cms-contact__submit,
.cms-prescription-link__submit {
  display: inline-flex;
  align-items: center;
  justify-content: space-between;
  gap: 2rem;
  min-height: 3.25rem;
  min-width: min(22rem, 100%);
  padding: 0 1.5rem;
  /* The fill stays the practice's colour exactly; only the outline is capped,
     so a practice that picks a near-white accent still has a button-shaped
     button instead of a label floating on the sheet (1.03 : 1). Below the cap
     the outline *is* the accent and nothing changes. */
  border: 1px solid var(--c-edge);
  background: var(--c-accent);
  color: var(--c-on-accent);
  font-family: inherit;
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  text-decoration: none;
  cursor: pointer;
  transition: background-color 0.2s ease, color 0.2s ease;
}

.cms-patient-info__download::after,
.cms-appointments-link__cta::after,
.cms-patientportal-link__cta::after,
.cms-contact__submit::after,
.cms-prescription-link__submit::after {
  content: "→";
  font-size: 1.1rem;
  letter-spacing: 0;
  transition: transform 0.2s ease;
}

.cms-patient-info__download:hover,
.cms-appointments-link__cta:hover,
.cms-patientportal-link__cta:hover,
.cms-contact__submit:hover,
.cms-prescription-link__submit:hover {
  background: var(--c-deep);
  border-color: var(--c-deep);
  color: var(--c-deep-ink);
}

.cms-patient-info__download:hover::after,
.cms-appointments-link__cta:hover::after,
.cms-patientportal-link__cta:hover::after,
.cms-contact__submit:hover::after,
.cms-prescription-link__submit:hover::after {
  transform: translateX(0.3rem);
}

.cms-patient-info__download {
  margin-top: 1rem;
  min-width: min(16rem, 100%);
}

.cms-prescription-link__submit:disabled,
.cms-contact__submit:disabled {
  background: var(--c-tint);
  border-color: var(--c-tint-line);
  color: var(--c-soft);
  cursor: not-allowed;
}

.cms-prescription-link__unavailable {
  color: var(--c-soft);
  font-size: 0.9rem;
  margin-top: 0.75rem;
}

/* ------------------------------------------------- appointments / portal --- */

.cms-appointments-link,
.cms-patientportal-link {
  background: var(--c-tint);
  padding: clamp(2rem, 4vw, 3rem);
  border-left: 3px solid var(--c-accent);
}

.cms-appointments-link__intro,
.cms-patientportal-link__intro,
.cms-prescription-link__intro {
  color: var(--c-body);
  margin-bottom: 1.75rem;
}

/* ---------------------------------------------------------------- forms --- */

.cms-contact__field,
.cms-prescription-link__field {
  margin-bottom: 1.25rem;
}

.cms-contact__field label,
.cms-prescription-link__field label {
  display: block;
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  margin-bottom: 0.4rem;
}

.cms-contact__field input,
.cms-contact__field textarea,
.cms-contact__field select,
.cms-prescription-link__field input,
.cms-prescription-link__field textarea,
.cms-prescription-link__field select {
  width: 100%;
  min-height: 2.9rem;
  padding: 0.6rem 0.85rem;
  /* Not --c-line: a decorative hairline is 1.25 : 1 and an empty field then
     has no findable edge at all. */
  border: 1px solid var(--c-field-line);
  border-radius: 0;
  background: var(--c-sheet);
  color: var(--c-ink);
  font-family: inherit;
  font-size: 1rem;
}

/* A consent tick is a sentence, not a form label: the shared markup puts the
   <label> before the input, so the theme lays it back out as box + sentence
   and drops the uppercase label styling for this one field. */
.cms-contact__field:has(input[type="checkbox"]),
.cms-prescription-link__field:has(input[type="checkbox"]) {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 0.25rem 0.7rem;
  align-items: start;
}

.cms-contact__field:has(input[type="checkbox"]) label,
.cms-prescription-link__field:has(input[type="checkbox"]) label {
  grid-area: 1 / 2;
  margin: 0;
  font-size: 0.95rem;
  font-weight: 400;
  letter-spacing: 0;
  text-transform: none;
}

/* The consent tick is the one box a request cannot be sent without, and on a
   phone 1.15 rem (18 px) is under every target-size minimum. */
.cms-contact__field input[type="checkbox"],
.cms-prescription-link__field input[type="checkbox"] {
  grid-area: 1 / 1;
  width: 1.5rem;
  min-height: 1.5rem;
  height: 1.5rem;
  margin-top: 0.15rem;
  accent-color: var(--c-accent);
}

.cms-contact__field:has(input[type="checkbox"]) > :not(label):not(input),
.cms-prescription-link__field:has(input[type="checkbox"]) > :not(label):not(input) {
  grid-column: 2;
}

.cms-contact__field textarea,
.cms-prescription-link__field textarea {
  min-height: 8rem;
  resize: vertical;
}

.cms-contact__hint,
.cms-prescription-link__hint {
  display: block;
  color: var(--c-soft);
  font-size: 0.85rem;
  margin-top: 0.3rem;
}

.cms-contact__error,
.cms-prescription-link__error,
.cms-contact__field ul.errorlist,
.cms-prescription-link__field ul.errorlist {
  list-style: none;
  margin: 0.4rem 0 0;
  padding: 0;
  color: color-mix(in oklab, #c0392b 82%, var(--c-accent));
  font-size: 0.9rem;
}

.cms-contact__privacy,
.cms-prescription-link .cms-contact__privacy {
  color: var(--c-soft);
  font-size: 0.9rem;
}

.cms-contact__sent,
.cms-prescription-link__sent {
  border-left: 3px solid var(--c-accent);
  padding-left: 1.25rem;
}

/* ------------------------------------------------------------ contact --- */

/* The one dark band of the page. It gives the layout a floor even when there
   is not a single photograph on the site. */
.cms-contact {
  background: var(--c-deep);
  color: var(--c-deep-ink);
  padding: clamp(3rem, 8vw, 6rem) var(--pad);
}

.cms-contact > * {
  max-width: var(--w-page);
  margin-inline: auto;
}

/* The form is a direct child too, so the centring rule above would indent it
   away from the heading and the channel list it belongs to. */
.cms-contact__form {
  margin-inline: 0;
}

.cms-contact__title {
  color: var(--c-deep-ink);
}

.cms-contact__group {
  margin-bottom: 2rem;
}

.cms-contact__group-title {
  color: var(--c-deep-soft);
}

.cms-contact__list {
  list-style: none;
  margin: 0;
  padding: 0;
}

.cms-contact__item {
  padding: 0.35rem 0;
  font-size: 1.05rem;
}

.cms-contact__item a {
  color: var(--c-deep-ink);
}

.cms-contact__primary {
  color: var(--c-deep-soft);
}

.cms-contact__empty,
.cms-contact .cms-contact__privacy {
  color: var(--c-deep-soft);
}

.cms-contact__field label {
  color: var(--c-deep-soft);
}

.cms-contact__field input,
.cms-contact__field textarea,
.cms-contact__field select {
  background: transparent;
  border-color: var(--c-deep-line);
  color: var(--c-deep-ink);
}

.cms-contact__field input::placeholder,
.cms-contact__field textarea::placeholder {
  color: var(--c-deep-soft);
}

.cms-contact__field input:focus,
.cms-contact__field textarea:focus,
.cms-contact__field select:focus {
  border-color: var(--c-deep-ink);
}

.cms-contact__hint {
  color: var(--c-deep-soft);
}

.cms-contact__submit:hover {
  background: var(--c-deep-ink);
  border-color: var(--c-deep-ink);
  color: var(--c-deep);
}

.cms-contact__sent {
  color: var(--c-deep-ink);
}

/* --------------------------------------------------------- quote banner --- */

.cms-quote-banner {
  position: relative;
  background: var(--c-deep);
  background-size: cover;
  background-position: center;
  padding: clamp(4rem, 12vw, 8rem) var(--pad);
  isolation: isolate;
}

/* Without a background photo the band is a flat accent field carrying an
   oversized quotation mark — a shape, not a missing picture.

   A plain mix keeps the accent's own lightness: 82 % of a pale yellow stays
   pale, and the 200-weight white quote on it measured 2.98 : 1. So the band
   takes the accent's hue and a share of its chroma but pins its own
   lightness — the tint follows the accent, the contrast does not. The mix is
   the fallback for browsers without relative colour syntax. */
.cms-quote-banner:not(.cms-quote-banner--photo) {
  background-image: linear-gradient(
    118deg,
    color-mix(in oklab, var(--c-accent) 82%, #0d1113),
    color-mix(in oklab, var(--c-accent) 20%, #0d1113)
  );
}

@supports (color: oklch(from red l c h)) {
  .cms-quote-banner:not(.cms-quote-banner--photo) {
    background-image: linear-gradient(
      118deg,
      oklch(from var(--c-accent) 0.36 min(c, 0.11) h),
      oklch(from var(--c-accent) 0.19 min(c, 0.06) h)
    );
  }
}

.cms-quote-banner:not(.cms-quote-banner--photo) .cms-quote-banner__inner::before {
  content: "\201C";
  display: block;
  font-size: 7rem;
  line-height: 0.6;
  color: color-mix(in oklab, #ffffff 26%, transparent);
  margin-bottom: 0.5rem;
}

/* Practice interiors are bright and busy; a flat 50 % veil is not enough for a
   200-weight quote. Dark from the side the text starts on, lighter towards the
   right so the room is still visible. */
.cms-quote-banner--photo::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  background: linear-gradient(
    100deg,
    rgb(0 0 0 / 78%) 0%,
    rgb(0 0 0 / 66%) 45%,
    rgb(0 0 0 / 38%) 100%
  );
}

.cms-quote-banner__inner {
  position: relative;
  z-index: 1;
  max-width: var(--w-page);
  margin-inline: auto;
}

.cms-quote-banner__quote {
  color: #fff;
  font-size: clamp(1.6rem, 4.5vw, 3.25rem);
  font-weight: 200;
  letter-spacing: -0.02em;
  line-height: 1.15;
  margin: 0;
  max-width: 24ch;
}

.cms-quote-banner__attribution {
  color: color-mix(in oklab, #ffffff 78%, transparent);
  margin: 1.75rem 0 0;
}

/* --------------------------------------------------------------- map --- */

.cms-map__link {
  display: block;
  text-decoration: none;
  border: 1px solid var(--c-line);
}

.cms-map__image {
  display: block;
  width: 100%;
  height: auto;
}

.cms-map__caption {
  display: block;
  padding: 0.75rem 1rem;
  color: var(--c-soft);
  font-size: 0.85rem;
  border-top: 1px solid var(--c-line);
}

.cms-map__directions {
  color: var(--c-body);
  padding-top: 1.5rem;
}

.cms-map__directions p:last-child {
  margin-bottom: 0;
}

/* ------------------------------------------------------- announcements --- */

.cms-announcements {
  background: var(--c-tint);
  border-block: 1px solid var(--c-tint-line);
  padding: clamp(1.5rem, 4vw, 2.5rem) var(--pad);
}

.cms-announcements__inner {
  max-width: var(--w-page);
  margin-inline: auto;
  position: relative;
}

.cms-announcements__title {
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--c-soft);
  margin: 0 0 1rem;
}

.cms-announcements__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 1.5rem;
}

.cms-announcements__item {
  border-left: 3px solid var(--c-accent);
  padding-left: 1.25rem;
}

/* The tone is a meaning, not a decoration — it only shifts the marker, never
   the type. All five keep a share of the accent so the band reads as one.
 *
 * Capping the *hue* is not enough, because "Note" simply is the practice's
 * accent: a red accent put it on top of "Warning" (16 sRGB units apart on a
 * 3 px rule — the same marker twice), a green one on top of "Good news". Only
 * lightness separates two marks of the same hue, so the five are laid out on
 * two pinned lightness steps instead — "Note" at 0.54, the three literals at
 * 0.42 — with a chroma floor so a grey accent cannot flatten the difference
 * back out. The literals' accent share is 6 %, not the 12 % it was: at 12 % a
 * green accent pulled "Reminder" and "Warning" — two warm tones only 25° of
 * hue apart to begin with — to within 21 sRGB units of each other.
 *
 * The plain mixes are the fallback for browsers without relative colour
 * syntax; there the tones separate by hue alone, as they did before. */
.cms-announcements__item--neutral {
  border-left-color: var(--c-line);
}

.cms-announcements__item--info {
  border-left-color: var(--c-accent);
}

.cms-announcements__item--important {
  border-left-color: color-mix(in oklab, #b45309 94%, var(--c-accent));
}

.cms-announcements__item--alert {
  border-left-color: color-mix(in oklab, #c0392b 94%, var(--c-accent));
}

.cms-announcements__item--good {
  border-left-color: color-mix(in oklab, #2e7d32 94%, var(--c-accent));
}

@supports (color: oklch(from red l c h)) {
  /* Quietest of the five, but still a mark: at 12 % of a pale accent the
     hairline grey vanished into the band (1.24 : 1) and the item lost its
     rule entirely. */
  .cms-announcements__item--neutral {
    border-left-color: oklch(from var(--c-accent) 0.62 min(c, 0.02) h);
  }

  .cms-announcements__item--info {
    border-left-color: oklch(from var(--c-accent) 0.54 max(c, 0.12) h);
  }

  .cms-announcements__item--important {
    border-left-color: oklch(
      from color-mix(in oklab, #b45309 94%, var(--c-accent)) 0.42 max(c, 0.1) h
    );
  }

  .cms-announcements__item--alert {
    border-left-color: oklch(
      from color-mix(in oklab, #c0392b 94%, var(--c-accent)) 0.42 max(c, 0.1) h
    );
  }

  .cms-announcements__item--good {
    border-left-color: oklch(
      from color-mix(in oklab, #2e7d32 94%, var(--c-accent)) 0.42 max(c, 0.1) h
    );
  }
}

.cms-announcements__headline {
  font-size: 1.1rem;
  font-weight: 500;
  margin: 0 0 0.25rem;
}

.cms-announcements__period {
  color: var(--c-soft);
  font-size: 0.85rem;
  margin: 0 0 0.5rem;
}

.cms-announcements__body {
  color: var(--c-body);
  font-size: 0.97rem;
}

.cms-announcements__body p:last-child {
  margin-bottom: 0;
}

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

.footer {
  background: var(--c-sheet);
  border-top: 1px solid var(--c-line);
  padding: clamp(3rem, 7vw, 5rem) var(--pad) 2rem;
}

.footer__inner {
  max-width: var(--w-page);
  margin-inline: auto;
  display: grid;
  gap: clamp(2rem, 5vw, 3.5rem);
}

.footer__heading {
  font-size: clamp(1.4rem, 3vw, 2rem);
  font-weight: 300;
  margin: 0 0 2rem;
}

.footer__contact {
  font-style: normal;
}

.footer__line {
  color: var(--c-body);
  margin: 0 0 1.25rem;
}

/* A phone number and an address are the two things a visitor taps on a phone,
   so they get a target of their own rather than the bare line height. */
.footer__line a {
  display: inline-block;
  min-height: 2.75rem;
  padding: 0.6rem 0;
  text-decoration: none;
}

.footer__hours,
.footer__nav {
  list-style: none;
  margin: 0;
  padding: 0;
}

.footer__hours-row {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.3rem 0;
  max-width: 22rem;
  color: var(--c-body);
}

.footer__slots {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  font-variant-numeric: tabular-nums;
}

.footer__nav a {
  display: inline-block;
  min-height: 2.75rem;
  padding: 0.6rem 0;
  color: var(--c-body);
  text-decoration: none;
}

.footer__nav a:hover {
  color: var(--c-link-hover);
}

.footer__bottom {
  max-width: var(--w-page);
  margin: clamp(2.5rem, 5vw, 4rem) auto 0;
  padding-top: 1.5rem;
  border-top: 1px solid var(--c-line);
  color: var(--c-soft);
  font-size: 0.85rem;
  text-align: center;
}

.footer__login {
  display: inline-block;
  min-height: 2.75rem;
  padding: 0.8rem 0.5rem;
}

/* --------------------------------------------------------- breakpoints --- */

@media (max-width: 26.24em) {
  /* Narrow enough that the full weekday name crowds out the times. */
  .cms-opening-hours__day-name {
    display: none;
  }

  .cms-opening-hours__day-abbr {
    display: inline;
    color: var(--c-ink);
    font-weight: 500;
  }
}

@media (min-width: 40em) {
  .cms-gallery__grid {
    grid-template-columns: repeat(3, 1fr);
    grid-auto-rows: 11rem;
  }

  .cms-gallery__item:nth-child(4n + 1) {
    grid-column: span 2;
    grid-row: span 2;
  }

  .cms-team__grid {
    grid-template-columns: repeat(2, 1fr);
  }

  .cms-services {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr));
    gap: 0 clamp(2rem, 5vw, 4rem);
    align-items: start;
  }

  .cms-services__title {
    grid-column: 1 / -1;
  }

  .cms-patient-info__list {
    grid-template-columns: repeat(2, 1fr);
  }

  /* Both public forms keep a readable measure. Left to the sheet's own width a
     "Insurance number" field would be 950 px of empty box on a desktop. */
  .cms-contact__form,
  .cms-prescription-link__form {
    max-width: 42rem;
  }
}

@media (min-width: 50em) {
  .cms-team__grid {
    grid-template-columns: repeat(3, 1fr);
  }

  .footer__inner {
    grid-template-columns: 1.4fr 1fr 1fr;
  }

  /* A practice with no opening hours (or no menu) must not leave a reserved,
     empty third of the footer standing next to its name. */
  .footer__inner:not(:has(.footer__col--hours)),
  .footer__inner:not(:has(.footer__col--nav)) {
    grid-template-columns: 1.4fr 1fr;
  }

  .footer__inner:not(:has(.footer__col--hours)):not(:has(.footer__col--nav)) {
    grid-template-columns: 1fr;
  }

  /* Map beside directions once there is room for both. */
  .cms-map:has(.cms-map__link) {
    display: grid;
    grid-template-columns: 1.2fr 1fr;
    gap: clamp(1.5rem, 4vw, 3rem);
    align-items: start;
  }

  .cms-map:has(.cms-map__link) .cms-map__title {
    grid-column: 1 / -1;
  }

  .cms-map__directions {
    padding-top: 0;
  }

  .cms-contact__group {
    display: grid;
    grid-template-columns: 12rem 1fr;
    gap: 1rem 2rem;
    align-items: baseline;
    border-top: 1px solid var(--c-deep-line);
    padding-top: 1.5rem;
  }
}

/* The quick-access rail only leaves the flow where the margin beside the
   content column is demonstrably wider than the rail: the column is capped at
   72rem, so from 87.5rem there are ≥ 7.5rem of free margin on each side for a
   2.75rem rail. It can therefore never cover content — the failure mode of the
   floating side menus this pattern is borrowed from. */
@media (min-width: 87.5em) {
  .quicknav {
    position: fixed;
    top: 50%;
    right: 1.25rem;
    transform: translateY(-50%);
    z-index: 55;
    width: auto;
    max-width: none;
    margin: 0;
    padding: 0;
    flex-direction: column;
    gap: 0.35rem;
  }

  /* Vertical tabs, capped in height: the labels are the practice's own section
     headings and can be long, so they wrap into a second line rather than
     growing a tab down the whole window. */
  .quicknav__link {
    writing-mode: vertical-rl;
    min-height: 5rem;
    max-height: 8rem;
    /* One fixed width for every tab so their left edges line up. */
    width: 3.4rem;
    padding: 1rem 0.55rem;
    justify-content: center;
    text-align: center;
    font-size: 0.7rem;
    letter-spacing: 0.1em;
    background: var(--c-deep);
    border-color: var(--c-deep);
    color: var(--c-deep-ink);
  }

  .quicknav__link:hover {
    background: var(--c-accent);
    border-color: var(--c-accent);
    color: var(--c-on-accent);
  }
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

@media print {
  .topbar,
  .quicknav,
  .hero::after {
    display: none;
  }
}
