/* "Indigo" homepage theme.
   A quiet, dark practice homepage in deep indigo and anthracite. One continuous
   night-blue page instead of alternating bands; each section's heading hangs in
   a left rail on wide screens, the way a printed page carries its marginalia.
   A slim bar floats transparently over the hero and frosts on scroll; panels
   are softly rounded and separated by hairlines rather than fills.
   Mobile-first; every accent surface runs through --c-accent so the
   per-practice override (tenant_theme_css) applies. No bundled binaries — the
   type falls back to the platform's system sans (see fonts/README.txt). */

:root {
  /* The design is dark by intent, not by the visitor's preference — telling the
     browser so keeps the native widgets it draws (scrollbars, checkboxes, date
     pickers) dark instead of light-on-dark. */
  color-scheme: dark;

  /* The practice may override --c-accent (izamna.theme_accent). On a dark page
     the readable accent is the *bright* one — a raw accent hex would sink into
     the background, so links and fills use --c-accent-bright and never
     --c-accent directly.

     --c-accent-bright must NOT be color-mix()ed with white: a mix keeps the
     accent's own lightness, so a dark accent (navy, maroon, near-black) still
     comes out dark. Measured over a 12³ sweep of the sRGB cube, the old mix
     put 181 of 1728 accents below 4.5 : 1 — worst case 2.72 : 1, which is a
     link nobody can read and a filled button whose label vanishes. The clamp
     below keeps hue and chroma and moves only the lightness into the band that
     is legible on this page, so every accent lands above 4.5 : 1 (see the
     @supports block; the mix stays as the fallback and is the right answer for
     the indigo this theme ships with).

     -line and -wash are derived from -bright, not from the raw accent, so the
     hairlines and the focus ring track the same clamp. -line draws the outline
     of the download pill and the coverage badge, which is what makes them read
     as a control, so it is mixed far enough to clear 3 : 1 on both surfaces
     (3.76 / 3.44 at worst; the raw-accent mix bottomed out at 2.57). */
  --c-accent: #5573c7;
  --c-accent-bright: color-mix(in srgb, var(--c-accent) 62%, white);
  --c-accent-dim: color-mix(in srgb, var(--c-accent) 78%, black);
  --c-accent-line: color-mix(in srgb, var(--c-accent-bright) 62%, var(--c-page));
  --c-accent-wash: color-mix(in srgb, var(--c-accent-bright) 20%, var(--c-page));

  --c-page: #0d1420;
  --c-surface: #141d2e;
  --c-surface-2: #1b273c;
  --c-line: #24304a;
  --c-ink: #e7edf6;
  --c-muted: #a3b2c9;
  --c-faint: #7b8ba6;

  /* The design was drawn for Inter / Inter Tight; both are optional (nothing
     is bundled), so the stack degrades to the platform's system sans. */
  --font-body: "Inter", system-ui, -apple-system, "Segoe UI", Roboto, Helvetica,
    Arial, sans-serif;
  --font-display: "Inter Tight", "Inter", system-ui, -apple-system, "Segoe UI",
    Roboto, Helvetica, Arial, sans-serif;

  --radius: 12px;
  --radius-sm: 8px;
  --wrap: 74rem;
  --gutter: 1.25rem;
  --rail: 14rem;
  --bar-h: 60px;
  /* How tall the bar *actually* is. It depends on the practice's name and on
     how many sections it published — ten sections wrap the desktop masthead
     onto a third row — so a literal cannot be right for everyone. theme.js
     measures the rendered bar into this via a ResizeObserver (a resize
     listener alone is measured before the webfont swaps and is wrong from then
     on); the literal below is the no-JavaScript fallback, generous enough for
     the usual two-row masthead. It sizes both the anchor offset and the veil
     the bar's own links sit on. */
  --bar-h-measured: 8.5rem;
}

/* Keep hue and chroma of whatever accent the practice picked, clamp only its
   lightness into the band that reads on this page. A floor of L 0.78 puts the
   worst accent in the sRGB cube at 5.6 : 1 against --c-page (measured over a
   12³ sweep, see the note in :root); the ceiling stops a near-white accent
   from turning links into the same white as the headings. */
@supports (color: oklch(from white l c h)) {
  :root {
    --c-accent-bright: oklch(from var(--c-accent) clamp(0.78, calc(l + 0.2), 0.94) c h);
  }
}

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

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

html {
  /* The bar floats over the content, so in-page anchors must clear it — by the
     bar's measured height, not by a guess: a practice with ten sections gets a
     three-row masthead, and the old fixed 7.5rem left the target under it. */
  scroll-padding-top: calc(var(--bar-h-measured) + 1rem);
  scroll-behavior: smooth;
}

body {
  margin: 0;
  /* Full-bleed bands are cut with margin-inline: calc(50% - 50vw); 50vw counts
     the scrollbar, so without this the page could scroll a few pixels sideways. */
  overflow-x: hidden;
  background: var(--c-page);
  color: var(--c-ink);
  font-family: var(--font-body);
  font-size: 1rem;
  line-height: 1.65;
  -webkit-text-size-adjust: 100%;
  -webkit-font-smoothing: antialiased;
}

h1,
h2,
h3,
h4 {
  font-family: var(--font-display);
  font-weight: 400;
  line-height: 1.15;
  letter-spacing: -0.015em;
  margin: 0 0 0.6em;
  color: #fff;
}

p {
  margin: 0 0 1rem;
  max-width: 68ch;
}

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

a:hover {
  color: #fff;
}

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

:focus-visible {
  outline: 2px solid var(--c-accent-bright);
  outline-offset: 3px;
}

/* A small letterspaced label — roles, captions, group titles, categories.
   Used often enough that it is worth naming once. */
.u-label,
.cms-team__role,
.cms-gallery__caption,
.cms-contact__group-title,
.cms-services__category,
.footer__head {
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--c-faint);
  margin: 0 0 0.5rem;
}

/* ---------- top bar ---------- */

.bar {
  position: fixed;
  inset: 0 0 auto;
  z-index: 30;
  /* Frosted is the *default* state, not the scrolled one. Nothing but
     JavaScript can tell where the page stands, and a transparent fixed bar over
     the page's own content is unreadable — so without theme.js the bar simply
     stays frosted, which is the safe answer. theme.js takes the frost away
     while the page is at the top, where the hero's veil carries the links. */
  background: color-mix(in srgb, var(--c-page) 88%, transparent);
  backdrop-filter: blur(10px);
  box-shadow: inset 0 -1px 0 var(--c-line);
  transition: background-color 0.25s ease, box-shadow 0.25s ease;
  /* A hard ceiling on top of the clamped name: with the menu open and ten
     sections the list is what grows, and a fixed bar must never be able to
     cover the page it sits on. Whatever does not fit scrolls inside the bar. */
  max-height: 85dvh;
  overflow-y: auto;
  overscroll-behavior: contain;
}

/* Over the hero: transparent, and only while the small-screen menu is shut. */
.bar.is-at-top:not(:has(.bar__toggle:checked)) {
  background: transparent;
  backdrop-filter: none;
  box-shadow: none;
}

.bar__inner {
  max-width: var(--wrap);
  margin: 0 auto;
  padding: 0 var(--gutter);
  min-height: var(--bar-h);
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 1rem;
}

.bar__brand {
  display: flex;
  align-items: center;
  margin-right: auto;
  text-decoration: none;
}

.bar__logo {
  max-height: 34px;
  width: auto;
}

.bar__name {
  font-family: var(--font-display);
  font-size: 1.05rem;
  letter-spacing: 0.01em;
  color: #fff;
  /* The bar is fixed, so its height is taken off every screen for good. A long
     German practice name ("Gemeinschaftspraxis für Allgemeinmedizin und
     Arbeitsmedizin Dr. …") wrapped to five lines on a 320 px screen and grew
     the bar to 199 px — 35 % of the viewport, above the fold and below it. Two
     lines here, the full name in the hero title underneath. */
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  overflow: hidden;
}

/* Small-screen menu: the checkbox is the control, the label draws the burger. */
.bar__toggle {
  position: absolute;
  width: 44px;
  height: 44px;
  right: var(--gutter);
  top: 8px;
  margin: 0;
  opacity: 0;
  cursor: pointer;
}

.bar__burger {
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  cursor: pointer;
}

.bar__burger span,
.bar__burger span::before,
.bar__burger span::after {
  display: block;
  width: 22px;
  height: 1.5px;
  background: var(--c-ink);
  content: "";
  transition: transform 0.2s ease;
}

.bar__burger span::before {
  transform: translateY(-7px);
}

.bar__burger span::after {
  transform: translateY(5.5px);
}

.bar__list {
  display: none;
  list-style: none;
  margin: 0;
  padding: 0.5rem 0 1rem;
  flex-basis: 100%;
}

/* The open panel gets what is left of the screen below the brand row and
   scrolls inside itself. Ten sections at a 44 px tap target are 596 px — more
   than a 667 px phone has left — and because the bar is fixed, an entry past
   the bottom edge could not be scrolled to at all. */
.bar__toggle:checked ~ .bar__list {
  display: block;
  max-height: calc(100dvh - var(--bar-h) - 0.75rem);
  overflow-y: auto;
  overscroll-behavior: contain;
}

.bar__link {
  display: block;
  padding: 0.65rem 0;
  min-height: 44px;
  color: var(--c-ink);
  text-decoration: none;
  font-size: 0.95rem;
  border-bottom: 1px solid var(--c-line);
}

.bar__link:hover,
.bar__link.is-active {
  color: var(--c-accent-bright);
}

/* Wide screens get a two-row masthead: the practice on the first line, the
   sections on the second. A practice with ten sections would otherwise wrap the
   bar anyway — this makes the second line the design instead of an accident,
   and keeps the row of links aligned with the content column below. */
@media (min-width: 56rem) {
  .bar__toggle,
  .bar__burger {
    display: none;
  }

  .bar__inner {
    align-items: baseline;
    padding-top: 1.15rem;
    padding-bottom: 0.9rem;
    row-gap: 0.9rem;
  }

  /* The checked variant is repeated so it wins on specificity: a visitor who
     opened the burger and then turned the phone landscape would otherwise keep
     the stacked, height-capped panel on the wide layout. */
  .bar__list,
  .bar__toggle:checked ~ .bar__list {
    display: flex;
    flex-wrap: wrap;
    flex-basis: 100%;
    gap: 0.6rem 1.4rem;
    padding: 0;
    max-height: none;
    overflow: visible;
  }

  .bar__link {
    padding: 0;
    min-height: 0;
    border-bottom: 0;
    position: relative;
    font-size: 0.92rem;
    letter-spacing: 0.01em;
  }

  /* A hairline that grows from the left — the bar's only movement. */
  .bar__link::after {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    bottom: -6px;
    height: 1px;
    background: var(--c-accent-bright);
    transform: scaleX(0);
    transform-origin: left;
    transition: transform 0.2s ease;
  }

  .bar__link:hover::after,
  .bar__link.is-active::after {
    transform: scaleX(1);
  }
}

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

.hero {
  position: relative;
  isolation: isolate;
  min-height: clamp(17rem, 58vh, 32rem);
  display: flex;
  align-items: flex-end;
  overflow: hidden;
  background-size: cover;
  background-position: center;
  /* The ground under the header photo: a CSS-drawn indigo field — a soft
     off-centre glow over a deep gradient, ruled by a fine diagonal lattice. */
  background-color: var(--c-page);
  background-image:
    repeating-linear-gradient(
      -45deg,
      color-mix(in srgb, var(--c-accent) 9%, transparent) 0 1px,
      transparent 1px 14px
    ),
    radial-gradient(
      70% 90% at 78% 12%,
      color-mix(in srgb, var(--c-accent) 42%, transparent) 0%,
      transparent 68%
    ),
    linear-gradient(160deg, var(--c-surface-2) 0%, var(--c-page) 72%);
}

/* With a photo the lattice/gradient stack is replaced by the image (inline for
   the static fallback, an <img> for the hero block), and a graded scrim keeps
   the white title legible against whatever the practice uploaded. */
.hero--photo {
  background-image: none;
}

/* Bundled default photo (generated by scripts/demo_images) — a misty blue lake,
   cool enough to hold the night-blue page. Shown until the practice supplies
   one of its own, which the template marks with .hero--photo. */
.hero:not(.hero--photo) {
  background-image: url("hero.jpg");
}

.hero::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  /* Two veils over whatever the practice uploaded.

     The first is the bar's: it floats over the photo with no background of its
     own while the page is at the top, so its links need something to sit on.
     It is exactly as tall as the bar really is (--bar-h-measured) — the old
     single gradient reached its dark end only in the topmost pixel row and
     left the second row of links at 1.76 : 1 over a bright photo.

     The second is the page's own fade into the content below. */
  background:
    linear-gradient(
        to bottom,
        color-mix(in srgb, var(--c-page) 90%, transparent) 0%,
        color-mix(in srgb, var(--c-page) 86%, transparent) 84%,
        transparent 100%
      )
      top / 100% calc(var(--bar-h-measured) + 1.25rem) no-repeat,
    linear-gradient(
      to top,
      color-mix(in srgb, var(--c-page) 94%, transparent) 0%,
      color-mix(in srgb, var(--c-page) 66%, transparent) 42%,
      color-mix(in srgb, var(--c-page) 26%, transparent) 74%,
      color-mix(in srgb, var(--c-page) 60%, transparent) 100%
    );
}

.hero__plate {
  position: relative;
  z-index: 2;
  width: 100%;
  max-width: var(--wrap);
  margin: 0 auto;
  padding: 6rem var(--gutter) 2.75rem;
}

.hero__title {
  position: relative;
  margin: 0;
  max-width: 20ch;
  font-weight: 300;
  font-size: clamp(2rem, 6vw, 3.6rem);
  letter-spacing: -0.03em;
  text-wrap: balance;
}

/* A veil under the title, not over the whole photo. How far up the title
   reaches depends on how long the practice's name is: at four lines its first
   line climbed into the bright middle of a light photo and white came out at
   1.99 : 1 (large text still needs 3). A band that belongs to the title grows
   with it, and the 4 rem fade is always the air above the first line, so the
   photo keeps the rest of the frame. Full-bleed: the title sits in a centred
   column, the veil must not. */
.hero__title::before {
  content: "";
  position: absolute;
  z-index: -1;
  /* The title's own box is narrow (20ch) and sits in the left of the column,
     so the veil is bled far past both edges and left to .hero's overflow to
     clip it — centring it on the title would leave the right of the frame
     uncovered. */
  left: -100vw;
  right: -100vw;
  top: -4rem;
  bottom: -3rem;
  background: linear-gradient(
    to bottom,
    transparent 0,
    color-mix(in srgb, var(--c-page) 62%, transparent) 4rem,
    color-mix(in srgb, var(--c-page) 74%, transparent) 100%
  );
}

/* A short accent rule under the title — the one flourish in the shell. */
.hero__title::after {
  content: "";
  display: block;
  width: 4.5rem;
  height: 2px;
  margin-top: 1.5rem;
  background: var(--c-accent-bright);
}

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

.hero .cms-hero__track {
  display: flex;
  height: 100%;
  transition: transform 0.7s ease;
}

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

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

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

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

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

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

.content {
  max-width: var(--wrap);
  margin: 0 auto;
  padding: 0 var(--gutter);
}

/* The vertical rhythm sits on the wrapper render_homepage_blocks emits — a rule
   on ``.content > section`` would never match. */
.content > .cms-block,
.content > .cms-block--full {
  margin-block: clamp(3rem, 7vw, 5.5rem);
}

/* One continuous page: sections are told apart by a hairline and air, not by
   alternating fills. */
.content > .cms-block > section,
.content > .cms-block--full > section {
  border-top: 1px solid var(--c-line);
  padding-top: clamp(1.5rem, 3vw, 2.5rem);
}

/* The two bands that break out of the column carry no rule of their own. */
.content .cms-quote-banner,
.content .cms-announcements {
  border-top: 0;
  padding-top: 0;
}

/* Section headings. */
.cms-team__title,
.cms-opening-hours__title,
.cms-gallery__title,
.cms-services__title,
.cms-patient-info__title,
.cms-contact__title,
.cms-map__title,
.cms-prescription-link__title,
.cms-appointments-link__title,
.cms-patientportal-link__title,
.cms-announcements__title {
  font-size: clamp(1.5rem, 3.2vw, 2rem);
  font-weight: 300;
  letter-spacing: -0.02em;
}

/* On an own /<slug>/ page the hero already says the block's title. */
.content--single .cms-team__title,
.content--single .cms-opening-hours__title,
.content--single .cms-gallery__title,
.content--single .cms-services__title,
.content--single .cms-patient-info__title,
.content--single .cms-contact__title,
.content--single .cms-map__title,
.content--single .cms-prescription-link__title,
.content--single .cms-appointments-link__title,
.content--single .cms-patientportal-link__title {
  display: none;
}

/* The rail: on wide screens a section's heading steps out into the left margin
   and everything else keeps the wider right column. Sections that are a band or
   a centred panel (quote, announcements, the three CTAs) stay out of it. */
@media (min-width: 64rem) {
  .content:not(.content--single) > .cms-block > .cms-team,
  .content:not(.content--single) > .cms-block > .cms-opening-hours,
  .content:not(.content--single) > .cms-block > .cms-gallery,
  .content:not(.content--single) > .cms-block > .cms-services,
  .content:not(.content--single) > .cms-block > .cms-patient-info,
  .content:not(.content--single) > .cms-block > .cms-contact,
  .content:not(.content--single) > .cms-block > .cms-map {
    display: grid;
    grid-template-columns: var(--rail) minmax(0, 1fr);
    column-gap: 3.5rem;
  }

  .content:not(.content--single) > .cms-block > .cms-team > *,
  .content:not(.content--single) > .cms-block > .cms-opening-hours > *,
  .content:not(.content--single) > .cms-block > .cms-gallery > *,
  .content:not(.content--single) > .cms-block > .cms-services > *,
  .content:not(.content--single) > .cms-block > .cms-patient-info > *,
  .content:not(.content--single) > .cms-block > .cms-contact > *,
  .content:not(.content--single) > .cms-block > .cms-map > * {
    grid-column: 2;
  }

  .content:not(.content--single) > .cms-block > .cms-team > .cms-team__title,
  .content:not(.content--single)
    > .cms-block
    > .cms-opening-hours
    > .cms-opening-hours__title,
  .content:not(.content--single) > .cms-block > .cms-gallery > .cms-gallery__title,
  .content:not(.content--single) > .cms-block > .cms-services > .cms-services__title,
  .content:not(.content--single)
    > .cms-block
    > .cms-patient-info
    > .cms-patient-info__title,
  .content:not(.content--single) > .cms-block > .cms-contact > .cms-contact__title,
  .content:not(.content--single) > .cms-block > .cms-map > .cms-map__title {
    grid-column: 1;
    grid-row: 1;
    margin: 0;
    text-wrap: balance;
  }
}

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

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

.cms-team__member {
  background: var(--c-surface);
  border: 1px solid var(--c-line);
  border-radius: var(--radius);
  overflow: hidden;
}

/* A phone reads a team better as a list than as a column of full-width
   portraits: photo left, name and role beside it. The row spans a generous
   number of grid rows so any number of text children keeps the photo's height. */
.cms-team__member {
  display: grid;
  grid-template-columns: 6.5rem minmax(0, 1fr);
  align-content: start;
  column-gap: 1.1rem;
  padding: 0 1.1rem 0 0;
}

.cms-team__photo {
  grid-column: 1;
  grid-row: 1 / span 9;
  display: block;
  width: 100%;
  height: 100%;
  min-height: 8.5rem;
  object-fit: cover;
  /* Portraits are lit for a white page; a touch less light seats them in the
     dark surface without washing skin tones out. */
  filter: saturate(0.94) brightness(0.96);
}

.cms-team__name {
  grid-column: 2;
  margin: 1rem 0 0.25rem;
  font-family: var(--font-display);
  font-size: 1.02rem;
  color: #fff;
}

.cms-team__role {
  grid-column: 2;
  margin: 0;
}

.cms-team__bio {
  grid-column: 2;
  margin: 0.75rem 0 1rem;
  color: var(--c-muted);
  font-size: 0.92rem;
}

.cms-team__bio p {
  margin: 0 0 0.5rem;
}

/* From tablet width up the list becomes a grid of portrait cards. */
@media (min-width: 40rem) {
  .cms-team__grid {
    gap: 1.25rem;
    grid-template-columns: repeat(auto-fill, minmax(13rem, 1fr));
  }

  .cms-team__member {
    display: block;
    padding: 0 0 1.1rem;
  }

  .cms-team__photo {
    width: 100%;
    height: auto;
    min-height: 0;
    aspect-ratio: 4 / 5;
  }

  .cms-team__name {
    margin: 1rem 1.1rem 0.25rem;
  }

  .cms-team__role {
    margin: 0 1.1rem;
  }

  .cms-team__bio {
    margin: 0.75rem 1.1rem 0;
  }
}

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

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

.cms-opening-hours__day {
  display: flex;
  align-items: baseline;
  gap: 1rem;
  padding: 0.55rem 0;
  border-bottom: 1px solid var(--c-line);
}

.cms-opening-hours__day-name {
  flex: 0 0 8.5rem;
  color: var(--c-muted);
}

/* The abbreviation is the block's small-screen spelling of the same word. */
.cms-opening-hours__day-abbr {
  display: none;
}

.cms-opening-hours__times {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem 1rem;
  font-variant-numeric: tabular-nums;
  color: var(--c-ink);
}

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

.cms-opening-hours__day.is-today {
  border-left: 2px solid var(--c-accent-bright);
  margin-left: -0.85rem;
  padding-left: 0.85rem;
}

.cms-opening-hours__day.is-today .cms-opening-hours__day-name,
.cms-opening-hours__day.is-today .cms-opening-hours__times {
  color: #fff;
}

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

@media (max-width: 26rem) {
  .cms-opening-hours__day-name {
    display: none;
  }

  .cms-opening-hours__day-abbr {
    display: block;
    flex: 0 0 2.5rem;
    color: var(--c-muted);
  }
}

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

.cms-gallery__grid {
  display: grid;
  gap: 0.9rem;
  grid-template-columns: repeat(auto-fill, minmax(9.5rem, 1fr));
}

.cms-gallery__item {
  margin: 0;
}

.cms-gallery__link {
  display: block;
  border-radius: var(--radius-sm);
  overflow: hidden;
}

.cms-gallery__image {
  display: block;
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  filter: brightness(0.9);
  transition: filter 0.25s ease, transform 0.35s ease;
}

.cms-gallery__link:hover .cms-gallery__image {
  filter: brightness(1.05);
  transform: scale(1.02);
}

.cms-gallery__caption {
  margin: 0.55rem 0 0;
  text-transform: none;
  letter-spacing: 0.02em;
  font-weight: 400;
  font-size: 0.82rem;
}

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

.cms-services__group + .cms-services__group {
  margin-top: 2.25rem;
}

.cms-services__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 0 2.5rem;
  grid-template-columns: repeat(auto-fill, minmax(17rem, 1fr));
}

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

.cms-services__name {
  margin: 0 0 0.3rem;
  font-size: 1rem;
  font-weight: 500;
  color: #fff;
}

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

.cms-services__description p {
  margin: 0;
}

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

.cms-services__badge--public {
  border-color: var(--c-accent-line);
  color: var(--c-accent-bright);
}

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

.cms-patient-info__list {
  list-style: none;
  margin: 0;
  padding: 0;
  counter-reset: info;
}

.cms-patient-info__item {
  counter-increment: info;
  position: relative;
  padding: 1.1rem 0 1.1rem 3rem;
  border-top: 1px solid var(--c-line);
}

.cms-patient-info__item::before {
  content: counter(info, decimal-leading-zero);
  position: absolute;
  left: 0;
  top: 1.2rem;
  font-variant-numeric: tabular-nums;
  font-size: 0.78rem;
  letter-spacing: 0.08em;
  color: var(--c-accent-bright);
}

.cms-patient-info__name {
  margin: 0 0 0.35rem;
  font-size: 1.05rem;
  font-weight: 500;
}

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

.cms-patient-info__body p {
  margin: 0 0 0.5rem;
}

.cms-patient-info__download {
  display: inline-block;
  margin-top: 0.35rem;
  padding: 0.45rem 1rem;
  min-height: 44px;
  line-height: 2.1;
  border: 1px solid var(--c-accent-line);
  border-radius: 999px;
  color: var(--c-accent-bright);
  text-decoration: none;
  font-size: 0.88rem;
}

.cms-patient-info__download:hover {
  background: var(--c-accent-wash);
  color: #fff;
}

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

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

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

.cms-contact__item {
  padding: 0.3rem 0;
  color: var(--c-ink);
}

.cms-contact__primary {
  color: var(--c-accent-bright);
}

.cms-contact__empty,
.cms-contact__privacy {
  color: var(--c-faint);
  font-size: 0.88rem;
}

@media (min-width: 40rem) {
  .cms-contact__group {
    display: grid;
    grid-template-columns: 11rem minmax(0, 1fr);
    gap: 0 1.5rem;
    align-items: baseline;
  }
}

/* Contact + prescription forms share one input treatment. */
.cms-contact__form,
.cms-prescription-link__form {
  margin-top: 1.75rem;
  max-width: 34rem;
}

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

.cms-contact__field label,
.cms-prescription-link__field label {
  display: block;
  margin-bottom: 0.35rem;
  font-size: 0.85rem;
  color: var(--c-muted);
}

.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%;
  padding: 0.7rem 0.85rem;
  background: var(--c-surface);
  border: 1px solid var(--c-line);
  border-radius: var(--radius-sm);
  color: var(--c-ink);
  font: inherit;
}

/* The consent gate is a checkbox, but the block emits label-then-widget like
   every other field. Reversing the row puts the box in front of its sentence
   without touching the shared template. */
.cms-contact__field--consent,
.cms-prescription-link__field--consent {
  display: flex;
  flex-direction: row-reverse;
  justify-content: flex-end;
  align-items: flex-start;
  gap: 0.65rem;
  flex-wrap: wrap;
}

.cms-contact__field--consent label,
.cms-prescription-link__field--consent label {
  flex: 1;
  margin: 0;
  color: var(--c-ink);
}

.cms-contact__field input[type="checkbox"],
.cms-prescription-link__field input[type="checkbox"] {
  width: 1.15rem;
  height: 1.15rem;
  flex: none;
  margin-top: 0.25rem;
  padding: 0;
  accent-color: var(--c-accent-bright);
}

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

.cms-contact__field input:focus,
.cms-contact__field textarea:focus,
.cms-prescription-link__field input:focus,
.cms-prescription-link__field textarea:focus {
  outline: none;
  border-color: var(--c-accent-bright);
  box-shadow: 0 0 0 3px var(--c-accent-wash);
}

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

.cms-contact__error,
.cms-prescription-link__error,
.cms-contact__field ul.errorlist,
.cms-prescription-link__field ul.errorlist {
  margin: 0.4rem 0 0;
  padding: 0;
  list-style: none;
  color: #ffb4b4;
  font-size: 0.85rem;
}

.cms-contact__sent {
  color: var(--c-accent-bright);
}

/* ---------- buttons (CTA blocks, form submits) ---------- */

.cms-contact__submit,
.cms-prescription-link__submit,
.cms-appointments-link__cta,
.cms-patientportal-link__cta {
  display: inline-block;
  padding: 0.8rem 1.9rem;
  min-height: 44px;
  border: 0;
  border-radius: 999px;
  background: var(--c-accent-bright);
  /* The fill is always a light mix of the accent, so the label is the page's
     dark — that stays legible whatever accent the practice picks. */
  color: var(--c-page);
  font: inherit;
  font-weight: 600;
  text-decoration: none;
  cursor: pointer;
  transition: filter 0.2s ease;
}

.cms-contact__submit:hover,
.cms-prescription-link__submit:hover,
.cms-appointments-link__cta:hover,
.cms-patientportal-link__cta:hover {
  filter: brightness(1.12);
  color: var(--c-page);
}

/* Switched off, not switched invisible. The flat surface fill and the cursor
   already say "off"; the label still has to be readable, so it uses --c-muted
   (5.9 : 1) rather than --c-faint, which came out at 4.34 : 1. */
.cms-contact__submit:disabled,
.cms-prescription-link__submit:disabled {
  background: var(--c-surface-2);
  color: var(--c-muted);
  cursor: not-allowed;
  filter: none;
}

.cms-prescription-link__unavailable {
  margin: 0.75rem 0 0;
  color: var(--c-faint);
  font-size: 0.88rem;
}

/* ---------- the three call-to-action blocks ---------- */

.cms-prescription-link,
.cms-appointments-link,
.cms-patientportal-link {
  background: var(--c-surface);
  border: 1px solid var(--c-line);
  border-radius: var(--radius);
  padding: clamp(1.5rem, 4vw, 2.75rem);
}

/* They are panels, not ruled sections. */
.content > .cms-block > .cms-prescription-link,
.content > .cms-block > .cms-appointments-link,
.content > .cms-block > .cms-patientportal-link {
  border-top: 1px solid var(--c-line);
}

.cms-appointments-link,
.cms-patientportal-link {
  text-align: center;
}

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

.cms-appointments-link__intro p,
.cms-patientportal-link__intro p {
  margin-inline: auto;
}

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

.cms-quote-banner {
  position: relative;
  isolation: isolate;
  /* Break out of the content column into a full-width band. */
  margin-inline: calc(50% - 50vw);
  padding: clamp(3rem, 8vw, 5.5rem) var(--gutter);
  background-color: var(--c-surface);
  background-size: cover;
  background-position: center;
  text-align: center;
}

.cms-quote-banner--photo::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: color-mix(in srgb, var(--c-page) 74%, transparent);
}

.cms-quote-banner__inner {
  max-width: 46rem;
  margin: 0 auto;
}

.cms-quote-banner__quote {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 300;
  font-size: clamp(1.3rem, 3.4vw, 2.1rem);
  line-height: 1.35;
  letter-spacing: -0.02em;
  color: #fff;
  text-wrap: balance;
}

.cms-quote-banner__attribution {
  margin: 1.5rem 0 0;
  max-width: none;
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--c-accent-bright);
}

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

.cms-announcements {
  border-radius: var(--radius);
  background: var(--c-surface);
  border: 1px solid var(--c-line);
  padding: clamp(1.25rem, 3vw, 2rem);
}

.cms-announcements__close {
  display: none;
}

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

/* The tone is a meaning, not a colour: each one is named here once and drawn
   through --a-tone, so a new tone needs a single line.

   All five are literals, the accent among them deliberately not. Painting
   "note" with the practice's accent collapsed it onto one of the other four
   for 324 of 1000 sampled accents (worst distance 0.012 in OKLab — the same
   colour): a red accent made "note" read as "attention", an amber one as
   "important". A tone is what the practice *means*, so it must not move when
   the practice recolours its site. */
.cms-announcements__item {
  --a-tone: var(--c-faint);
  border-left: 2px solid var(--a-tone);
  padding: 0.15rem 0 0.15rem 1rem;
}

.cms-announcements__item--info {
  --a-tone: #7fb2ff;
}

.cms-announcements__item--important {
  --a-tone: #e8b45c;
}

.cms-announcements__item--alert {
  --a-tone: #e8756f;
}

.cms-announcements__item--good {
  --a-tone: #74c69d;
}

.cms-announcements__headline {
  margin: 0 0 0.2rem;
  font-size: 1rem;
  font-weight: 500;
  color: var(--a-tone);
}

.cms-announcements__period {
  margin: 0 0 0.35rem;
  font-size: 0.78rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--c-faint);
}

.cms-announcements__body {
  color: var(--c-muted);
}

.cms-announcements__body p {
  margin: 0 0 0.5rem;
}

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

.cms-map__link {
  display: block;
  border-radius: var(--radius-sm);
  overflow: hidden;
  text-decoration: none;
}

.cms-map__image {
  display: block;
  width: 100%;
  height: auto;
  /* A daylight map tile is far brighter than this page — damp it down. */
  filter: brightness(0.82) saturate(0.8) contrast(1.05);
}

.cms-map__caption {
  display: block;
  margin-top: 0.5rem;
  color: var(--c-muted);
  font-size: 0.88rem;
}

.cms-map__directions {
  color: var(--c-muted);
  margin-top: 1.25rem;
}

.cms-map__directions p {
  margin: 0 0 0.5rem;
}

/* Directions beside the map once there is room for both. */
@media (min-width: 50rem) {
  .cms-map:has(.cms-map__link) .cms-map__link {
    grid-column: 2;
  }

  .cms-map:has(.cms-map__link) .cms-map__directions {
    margin-top: 1.25rem;
  }
}

/* ---------- cookie banner / policy (rendered by core, styled here) ---------- */

/* The consent banner brings its own, deliberately theme-independent palette
   (core/css/cookie-banner.css) — a light panel that must read the same on
   every theme. This theme's blanket `h1…h4 { color: #fff }` reached into it
   and put its heading white on white (1.00 : 1). Headings inside the banner
   take the panel's own ink instead. */
.cj-cookie-banner :is(h1, h2, h3, h4) {
  color: inherit;
}

.cookie-policy__list {
  color: var(--c-muted);
}

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

.footer {
  margin-top: clamp(3rem, 8vw, 6rem);
  background: var(--c-surface);
  border-top: 1px solid var(--c-line);
}

.footer__inner {
  max-width: var(--wrap);
  margin: 0 auto;
  padding: clamp(2.25rem, 5vw, 3.5rem) var(--gutter);
  display: grid;
  gap: 2rem;
}

@media (min-width: 46rem) {
  .footer__inner {
    grid-template-columns: 1.2fr 1fr 1fr;
    gap: 3rem;
  }
}

.footer__logo {
  max-height: 46px;
  width: auto;
  margin-bottom: 0.75rem;
}

.footer__name {
  margin: 0;
  font-family: var(--font-display);
  font-size: 1.05rem;
  color: #fff;
}

.footer__line {
  margin: 0 0 0.5rem;
  color: var(--c-muted);
  font-size: 0.92rem;
}

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

/* The foot repeats the whole section list, so on a phone this is a second full
   navigation — eleven links that came out 32 px tall, i.e. under the thumb
   size the bar's own links already keep. */
.footer__links a {
  display: flex;
  align-items: center;
  min-height: 44px;
  padding: 0.25rem 0;
  color: var(--c-muted);
  text-decoration: none;
  font-size: 0.92rem;
}

.footer__links a:hover {
  color: var(--c-accent-bright);
}

.footer__settings {
  color: var(--c-faint);
}

/* ---------- motion ---------- */

@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;
  }
}
