/* ==========================================================================
   FAMILY TREE DENTAL — contact.css
   The Contact page's own four sections, and nothing else.
   ---------------------------------------------------------------------------
   Loaded after style.css and system.css. Everything shared — tokens, the nav
   pill, buttons, the eyebrow, the headline mask, the hours list, the
   appointment band, the testimonial split, the clinic panel, the wave — is
   already supplied by those two and by the global components. What is here is
   only:

     01. The hero            the green field and the film beside it
     02. The play button
     03. The contact composition   the panel lifted over the form card
     04. The information panel
     05. The form
     06. The consultation
     07. The map frame
     08. Entry states        this page's own reveal channels
     09. Responsive
     10. Reduced motion

   Entry states are authored in CSS and lifted by `.no-js` — the same contract
   system.css section 04 uses, so a page that never gets its JavaScript is a
   finished page rather than an empty one.

   THE COLOUR RUNS DOWNHILL INTO THE SHARED HALF. The hero is on ivory, the
   contact section warms to pale blue, the consultation holds it and the map
   closes on #e8f2fd — which is the exact colour the appointment band beneath
   it opens with. There is no seam between this page's sections and the
   shared ones, and that is deliberate: change one end and check the other.
   ========================================================================== */


/* ==========================================================================
   01. THE HERO — THE GREEN, LIFTED OFF THE PAGE
   ---------------------------------------------------------------------------
   The band itself lives in system.css: page-hero.php emits it for five callers
   and only this page loads this file, so the shared composition had to move
   somewhere every caller could reach. What is left here is what makes THIS
   page's opening its own.

   THE PRACTICE GREEN STAYS, AND ONLY HERE. It was on all five inner pages,
   which is what made them read as one page with five titles; kept for the page
   a visitor arrives at meaning to get in touch, it goes back to being the
   brand's colour rather than the template's.

   The change is that the band stops being full-bleed. It becomes a card lying
   on the ivory with the film overlapping its right edge — the same two pieces,
   composed rather than butted together.

   Everything below overrides system.css, which loads first.
   ========================================================================== */
.ct-hero {
  overflow: visible;
  padding-bottom: clamp(2.5rem, 7vh, 4.5rem);
  background:
    radial-gradient(58% 46% at 88% 6%, rgba(110, 178, 244, .18) 0%, rgba(110, 178, 244, 0) 62%),
    linear-gradient(170deg, var(--sv-ivory) 0%, #f2f6fa 100%);
}

/* The card: shell width, its own radius, its own shadow. `overflow: visible`
   so the film can hang past the right edge. */
.ct-hero__inner {
  position: relative;
  width: var(--sv-shell);
  margin-inline: auto;
  /* The green takes the larger share: the film is pulled back over it, so its
     column only has to hold what is left showing. */
  grid-template-columns: minmax(0, 1fr) minmax(0, .82fr);
  min-height: clamp(21rem, 46vh, 29rem);
}

/* ALL FOUR CORNERS. The green is a card in its own right, so it is not cut
   square on the side the film covers — the film no longer reaches that edge. */
.ct-hero__panel {
  border-radius: var(--sv-r-xl);
  /* The right padding carries the film's overlap as well as its own gutter,
     so the copy never runs under the card lying on top of it. */
  padding: clamp(2.5rem, 5.5vw, 4.5rem) clamp(6rem, 11vw, 11rem) clamp(2.5rem, 5.5vw, 4.5rem) clamp(2rem, 5vw, 4rem);
  box-shadow: 0 24px 60px rgba(11, 45, 82, .16);
}

.ct-hero__copy {
  max-width: 26rem;
  margin-left: 0;
}

/* THE FILM LIES ON THE GREEN — IT DOES NOT MEET IT.
   The previous attempt overlapped by 43px but gave the frame the row's full
   height, so both rectangles shared a top and a bottom edge and the pair read
   as two halves butted together, which is exactly what this page was meant to
   stop doing. Two things fix it: the stage is inset vertically, so green shows
   above and below the film and the film is plainly the upper layer; and the
   overlap is deep enough to be read as one.

   It also no longer hangs past the shell. Overhanging the right edge put the
   card 29px outside the column every other section on the page lines up to. */
.ct-hero__stage {
  align-items: stretch;
  margin-left: calc(clamp(4rem, 7vw, 8rem) * -1);
  margin-right: 0;
  padding-block: clamp(1.5rem, 3.4vh, 2.75rem);
  padding-inline: 0;
}

.ct-hero__frame {
  height: auto;
  border-radius: var(--sv-r-lg);
  /* Deeper than the panel's, because it is the piece in front. */
  box-shadow: 0 30px 70px rgba(6, 33, 58, .34), 0 6px 16px rgba(6, 33, 58, .18);
}

/* THESE HAVE TO BE RESTATED, NOT INHERITED. system.css stacks the band at
   980px from inside a media query, and this file loads after it — a media
   query adds no specificity, so the plain rules above would win at every
   width and the card would never stack. The breakpoints match system.css's
   deliberately: change one, change the other. */
@media (max-width: 1180px) {
  .ct-hero__copy { max-width: 24rem; }
}

@media (max-width: 980px) {
  /* Card becomes two stacked cards, and the overlap is given back as a gap —
     an overlap needs width to be an overlap rather than a collision. */
  .ct-hero__inner  { grid-template-columns: minmax(0, 1fr); min-height: 0; gap: clamp(1.25rem, 4vw, 2rem); }
  .ct-hero__panel  { border-radius: var(--sv-r-xl); padding: clamp(2.25rem, 7vw, 3.5rem) clamp(1.5rem, 5vw, 3rem); }
  .ct-hero__copy   { max-width: none; }
  .ct-hero__stage  { margin-right: 0; }
  .ct-hero__frame  { height: auto; aspect-ratio: 16 / 10; }
}


/* ==========================================================================
   02. THE PLAY BUTTON
   ---------------------------------------------------------------------------
   Authored `hidden` and revealed by contact.js, which removes the video's own
   `controls` in the same breath. So the native controls are what a visitor
   without JavaScript gets — a working player either way, never a decorative
   button that does nothing.

   The Our Office page has its own copy of this control in office.css. The two
   are deliberately not shared yet: promoting them to system.css means one
   class name across two pages' markup and two scripts, and that is a change
   worth making the day a THIRD page needs a player — not before.
   ========================================================================== */
.ct-play {
  position: absolute;
  top: 50%; left: 50%;
  z-index: 2;
  display: grid;
  place-items: center;
  width: clamp(4.5rem, 8vw, 6rem);
  aspect-ratio: 1;
  padding: 0;
  color: #fff;
  /* Dark rather than light: a white scrim disappears against the bright
     ceilings and lit walls this clip is full of, while a dark one holds the
     white glyph at every frame of the footage. */
  background: rgba(6, 33, 58, .42);
  border: 0;
  border-radius: 50%;
  cursor: pointer;
  box-shadow: 0 10px 30px rgba(6, 33, 58, .3);
  -webkit-backdrop-filter: blur(8px) saturate(140%);
  backdrop-filter: blur(8px) saturate(140%);
  transform: translate(-50%, -50%);
  transition: background var(--t-fast) var(--ease-out),
              transform var(--t-med) var(--ease-out);
}
.ct-play:hover { background: rgba(6, 33, 58, .56); transform: translate(-50%, -50%) scale(1.05); }
.ct-play:focus-visible { outline: 2px solid #fff; outline-offset: 4px; }

/* The ring breathes only while the film is paused — once it is playing the
   button is a pause control, and a pulsing pause control is a distraction. */
.ct-play__ring {
  position: absolute;
  inset: -6px;
  border: 1px solid rgba(255, 255, 255, .5);
  border-radius: 50%;
  animation: ct-pulse 3.4s var(--ease-out) infinite;
}
@keyframes ct-pulse {
  0%, 100% { transform: scale(1);    opacity: .55; }
  50%      { transform: scale(1.09); opacity: .18; }
}

/* One element, two glyphs. A triangle drawn with borders becomes two bars by
   swapping the border for a box-shadow — no icon swap, no second element. */
.ct-play__mark {
  width: 0; height: 0;
  margin-left: .28em;
  border-top: .58rem solid transparent;
  border-bottom: .58rem solid transparent;
  border-left: .95rem solid currentColor;
}
.ct-play[aria-pressed="true"] .ct-play__ring { animation: none; opacity: .3; }
.ct-play[aria-pressed="true"] .ct-play__mark {
  width: .28rem; height: 1.1rem;
  margin-left: 0;
  border: 0;
  background: currentColor;
  box-shadow: .48rem 0 0 currentColor;
  transform: translateX(-.24rem);
}

/* Present for a reader, absent for a viewer — the button is a circle. */
.ct-play__label {
  position: absolute;
  width: 1px; height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}


/* ==========================================================================
   03. THE CONTACT COMPOSITION
   ---------------------------------------------------------------------------
   THE OVERLAP IS THE DESIGN. The information panel lifts off the form card's
   left edge and a hairline is drawn between the two, so what a visitor sees
   is one object with two halves rather than two cards that happen to be near
   each other. The card's left padding carries the overlap, which is why the
   two numbers below are written from the same clamp.
   ========================================================================== */
.ct-connect {
  position: relative;
  isolation: isolate;
  overflow: clip;
  padding-block: clamp(3.5rem, 9vh, 6.5rem) clamp(3rem, 8vh, 5.5rem);
  background: linear-gradient(180deg, var(--sv-ivory) 0%, #f4f9ff 46%, #eef5fd 100%);
}

.ct-connect__wash {
  position: absolute;
  top: -18%;
  right: -12%;
  z-index: -1;
  width: min(60vw, 44rem);
  aspect-ratio: 1;
  border-radius: 50%;
  background: radial-gradient(circle at 50% 50%,
              rgba(127, 227, 212, .18) 0%,
              rgba(110, 178, 244, .12) 46%,
              rgba(110, 178, 244, 0) 70%);
  filter: blur(18px);
  pointer-events: none;
}

.ct-connect__inner {
  position: relative;
  width: var(--sv-shell);
  margin-inline: auto;
  display: grid;
  grid-template-columns: minmax(0, .82fr) minmax(0, 1.18fr);
  align-items: start;
}

/* THERE IS NO DRAWN CONNECTOR BETWEEN THE TWO HALVES, and that is a decision
   rather than an omission. A hairline run from the panel into the card either
   crosses the form's own labels or has to be positioned against a column edge
   it cannot see — and the overlap, with the panel's shadow falling across the
   card beneath it, already says the two are one object. A second device
   saying the same thing is the visual noise this page is built to avoid. */


/* ==========================================================================
   04. THE INFORMATION PANEL
   ---------------------------------------------------------------------------
   The practice's deep blue, and it sits ABOVE the form card in the stack —
   which is what the negative margin needs to be legible rather than clipped.
   ========================================================================== */
.ct-panel {
  position: relative;
  z-index: 2;
  isolation: isolate;
  overflow: hidden;
  /* Lifted and pushed right, so it hangs over the card's corner. */
  margin-top: clamp(1.25rem, 3vw, 2.75rem);
  margin-right: calc(clamp(1.5rem, 3.4vw, 4rem) * -1);
  padding: clamp(1.6rem, 3vw, 2.6rem) clamp(1.5rem, 2.8vw, 2.4rem);
  border-radius: var(--sv-r-lg);
  color: var(--sv-on-dark);
  background:
    radial-gradient(90% 70% at 82% 6%, rgba(127, 227, 212, .26) 0%, rgba(127, 227, 212, 0) 58%),
    linear-gradient(158deg, #2b8ad8 0%, #1a72d6 34%, #0f4f96 72%, #0e4f5e 100%);
  box-shadow: 0 26px 60px rgba(11, 45, 82, .26);
}

.ct-panel__wash {
  position: absolute;
  inset: 0;
  z-index: -1;
  background:
    radial-gradient(40% 30% at 12% 88%, rgba(255, 255, 255, .16) 0%, rgba(255, 255, 255, 0) 70%);
  pointer-events: none;
}
.ct-panel__leaf {
  position: absolute;
  right: -14%;
  bottom: -18%;
  z-index: -1;
  width: min(60%, 15rem);
  color: rgba(255, 255, 255, .08);
  pointer-events: none;
}
.ct-panel__leaf svg { width: 100%; height: auto; }

.ct-panel__block + .ct-panel__block { margin-top: clamp(1.4rem, 3vw, 2rem); }

/* The hairline between blocks. Drawn rather than bordered so it can stop
   short of both edges and read as a rule instead of as a division. */
.ct-panel__block + .ct-panel__block::before {
  content: "";
  display: block;
  width: 100%;
  height: 1px;
  margin-bottom: clamp(1.4rem, 3vw, 2rem);
  background: linear-gradient(90deg, rgba(255, 255, 255, .34) 0%, rgba(255, 255, 255, .06) 100%);
}

.ct-panel__label {
  font-family: var(--f-ui);
  font-size: .72rem;
  font-weight: 600;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, .78);
}
.ct-panel__label + .ct-panel__line,
.ct-panel__label + .sv-hours { margin-top: .75rem; }

.ct-panel__line {
  display: flex;
  align-items: flex-start;
  gap: .65rem;
  font-family: var(--f-sans);
  font-size: clamp(.95rem, .92rem + .18vw, 1.06rem);
  line-height: 1.62;
  color: #fff;
  font-variant-numeric: var(--nums-ui);
}
.ct-panel__icon { flex: none; width: 20px; height: 20px; margin-top: .12em; color: var(--c-mint); }
.ct-panel__icon svg { width: 20px; height: 20px; }

/* The design's own "(Map)", kept word for word and given the affordance the
   word alone does not have. */
.ct-panel__map {
  margin-left: .35rem;
  font-family: var(--f-ui);
  font-size: .84em;
  color: rgba(255, 255, 255, .9);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: .22em;
  text-decoration-color: rgba(255, 255, 255, .45);
  transition: color var(--t-fast) var(--ease-out),
              text-decoration-color var(--t-fast) var(--ease-out);
}
.ct-panel__map:hover { color: var(--c-mint); text-decoration-color: currentColor; }

.ct-panel__phone {
  position: relative;
  font-size: clamp(1.1rem, 1rem + .5vw, 1.4rem);
  font-family: var(--f-ui);
  font-weight: 500;
  letter-spacing: .01em;
  color: #fff;
  transition: color var(--t-fast) var(--ease-out);
}
.ct-panel__phone::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: -.18em;
  height: 1px;
  background: var(--c-mint);
  transform: scaleX(0);
  transform-origin: 0 50%;
  transition: transform var(--t-med) var(--ease-out);
}
.ct-panel__phone:hover { color: var(--c-mint); }
.ct-panel__phone:hover::after { transform: scaleX(1); }

/* --- The hours, on the dark ground ---------------------------------------
   The markup is the clinic panel's, so site.js marks today's row here too.
   Only the colours are re-stated; nothing about the structure is repeated. */
.ct-hours .sv-hours__row {
  padding: .46rem 0;
  font-size: clamp(.82rem, .8rem + .12vw, .89rem);
  border-bottom-color: rgba(255, 255, 255, .18);
}
.ct-hours .sv-hours__row span:first-child { color: rgba(255, 255, 255, .78); }
.ct-hours .sv-hours__row span:last-child  { color: #fff; }
.ct-hours .sv-hours__row--closed span:last-child { color: rgba(255, 255, 255, .6); }
.ct-hours .sv-hours__row.is-today span:first-child { color: #fff; }
.ct-hours .sv-hours__row.is-today::before { background: var(--c-mint); }


/* ==========================================================================
   05. THE FORM
   ---------------------------------------------------------------------------
   White, quiet, and generous. The card carries the overlap in its left
   padding — the same clamp .ct-panel pulls itself right by — so the two
   numbers cannot drift apart.
   ========================================================================== */
.ct-form-card {
  position: relative;
  z-index: 1;
  padding: clamp(1.9rem, 3.6vw, 3.4rem);
  padding-left: calc(clamp(1.5rem, 3.4vw, 4rem) + clamp(1.9rem, 3.6vw, 3.4rem));
  background: rgba(255, 255, 255, .88);
  border: 1px solid var(--sv-card-brd);
  border-radius: var(--sv-r-lg);
  box-shadow: var(--sh-md);
  -webkit-backdrop-filter: blur(20px) saturate(165%);
  backdrop-filter: blur(20px) saturate(165%);
}

.ct-field + .ct-field { margin-top: clamp(1.5rem, 3vh, 2.1rem); }

.ct-field__label {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: .4rem;
  cursor: pointer;
}
.ct-field__name {
  font-family: var(--f-ui);
  font-size: .95rem;
  font-weight: 500;
  color: var(--c-blue-900);
}
/* The practice's own parenthetical. Quieter than the label but never grey on
   grey — it carries a real instruction. */
.ct-field__note {
  font-family: var(--f-ui);
  font-size: .78rem;
  font-weight: 400;
  line-height: 1.45;
  color: var(--c-ink-faint);
}

/* THE BOX IS THE UNDERLINE'S CONTAINER, not a border on the input itself:
   the resting rule and the focus rule are two elements, so one can be drawn
   across the other without either moving. */
.ct-field__box {
  position: relative;
  display: block;
  margin-top: .5rem;
  border-bottom: 1px solid rgba(120, 170, 225, .5);
  transition: border-color var(--t-fast) var(--ease-out);
}
.ct-field__rule {
  position: absolute;
  left: 0; right: 0; bottom: -1px;
  height: 2px;
  border-radius: 2px;
  background: linear-gradient(90deg, var(--c-blue-500), var(--c-mint));
  transform: scaleX(0);
  transform-origin: 0 50%;
  transition: transform var(--t-med) var(--ease-out);
}

.ct-field__input {
  display: block;
  width: 100%;
  /* 46px of target at the smallest step, which is a comfortable thumb. */
  min-height: 46px;
  padding: .55rem .25rem .6rem;
  font-family: var(--f-ui);
  font-size: 1rem;
  line-height: 1.5;
  color: var(--c-ink);
  background: transparent;
  border: 0;
  border-radius: 0;
  font-variant-numeric: var(--nums-ui);
  transition: background var(--t-fast) var(--ease-out);
}
.ct-field__input:focus { outline: none; }
.ct-field__input::placeholder { color: transparent; }

/* Focus is stated three ways — the rule draws, the resting border darkens and
   the field takes the faintest tint — because one of the three has to survive
   forced colours, and the tint is what makes the ACTIVE field findable when a
   visitor looks back at the form after reading something else. */
.ct-field__box:focus-within { border-bottom-color: var(--c-blue-500); }
.ct-field__box:focus-within .ct-field__rule { transform: scaleX(1); }
.ct-field__box:focus-within .ct-field__input { background: rgba(214, 232, 251, .28); }

.ct-field__input--area {
  min-height: 6.5rem;
  resize: vertical;
  font-family: var(--f-sans);
  line-height: 1.65;
}

/* The error state. The message is the BROWSER'S OWN, in the visitor's own
   language — contact.js copies it out of validationMessage rather than
   writing a second set of English sentences. */
.ct-field.is-invalid .ct-field__box { border-bottom-color: #d7513f; }
.ct-field.is-invalid .ct-field__rule {
  background: #d7513f;
  transform: scaleX(1);
}
.ct-field__err {
  margin-top: .5rem;
  font-family: var(--f-ui);
  font-size: .82rem;
  line-height: 1.45;
  color: #b8402f;
}

/* The spam trap: gone for a person, present for a bot. Not `display: none` —
   some bots skip what is not rendered. */
.ct-form__trap {
  position: absolute;
  left: -9999px;
  width: 1px; height: 1px;
  overflow: hidden;
}

.ct-form__foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1rem 1.25rem;
  margin-top: clamp(1.8rem, 4vh, 2.6rem);
}
.ct-form__submit {
  letter-spacing: .08em;
  text-transform: uppercase;
}
.ct-form__submit[disabled] { opacity: .6; cursor: progress; }

.ct-form__status {
  font-family: var(--f-ui);
  font-size: .86rem;
  line-height: 1.5;
  color: var(--c-ink-faint);
}
.ct-form__status.is-error { color: #b8402f; }

/* --- The confirmation ---------------------------------------------------- */
.ct-form__done { text-align: center; padding-block: clamp(1.5rem, 4vh, 3rem); }
.ct-form__done-mark { display: inline-grid; place-items: center; color: var(--c-blue-500); }
.ct-form__done-mark svg { width: 52px; height: 52px; }
.ct-form__done-title {
  margin-top: .9rem;
  font-family: var(--f-display);
  font-size: clamp(1.5rem, 1.2rem + 1vw, 2rem);
  font-weight: 400;
  color: var(--c-blue-900);
}
.ct-form__done-text {
  max-width: 34ch;
  margin: .6rem auto 0;
  font-size: .98rem;
  line-height: 1.65;
  color: var(--c-ink-soft);
}
.ct-form__done-text a { color: var(--c-blue-700); text-decoration: underline; text-underline-offset: .18em; }
.ct-form__again {
  margin-top: 1.4rem;
  background: none;
  border: 0;
  cursor: pointer;
}


/* ==========================================================================
   06. THE CONSULTATION
   ---------------------------------------------------------------------------
   One centred column in a lot of air. Centred is right for a heading and a
   single paragraph — but the measure is held to ~64ch so the lines never
   become the long centred ribbons that make a page hard to read.
   ========================================================================== */
.ct-consult {
  position: relative;
  padding-block: clamp(3.5rem, 10vh, 7rem) clamp(2rem, 5vh, 3.25rem);
  background: linear-gradient(180deg, #eef5fd 0%, #f4f9ff 100%);
  text-align: center;
}

.ct-consult__inner {
  width: min(54rem, 100% - 2 * var(--gutter));
  margin-inline: auto;
}

/* The drawn rule that stands in for an eyebrow. There is no label in the
   design above this heading and inventing one would be inventing content —
   so the section opens with a mark instead of a word. */
.ct-consult__rule {
  display: block;
  width: 62px;
  height: 2px;
  margin: 0 auto clamp(1.2rem, 3vh, 1.9rem);
  border-radius: 2px;
  background: linear-gradient(90deg, var(--c-mint), var(--c-blue-500));
  transform: scaleX(0);
  transform-origin: 50% 50%;
}

.ct-consult__title {
  font-family: var(--f-display);
  font-size: clamp(1.95rem, 1.1rem + 2.7vw, 3.1rem);
  font-weight: 400;
  line-height: 1.1;
  letter-spacing: -0.018em;
  color: var(--c-blue-700);
}
.ct-consult__title em { font-style: italic; color: var(--c-blue-500); }

.ct-consult__text {
  max-width: 64ch;
  margin: clamp(1.2rem, 3vh, 1.9rem) auto 0;
  font-size: clamp(.98rem, .95rem + .18vw, 1.08rem);
  line-height: 1.78;
  color: var(--c-ink-soft);
}


/* ==========================================================================
   07. THE MAP FRAME
   ---------------------------------------------------------------------------
   The frame is the design; what fills it is data. It closes on #e8f2fd, which
   is the colour the appointment band below opens with — the two sections meet
   with no seam, and that is why the gradient's last stop is not a round
   number somebody liked.
   ========================================================================== */
.ct-map {
  position: relative;
  padding-block: clamp(1.5rem, 4vh, 2.5rem) clamp(3.5rem, 9vh, 6rem);
  background: linear-gradient(180deg, #f4f9ff 0%, #eef5fd 55%, #e8f2fd 100%);
}

.ct-map__inner {
  width: var(--sv-shell);
  margin-inline: auto;
}

.ct-map__frame {
  position: relative;
  margin: 0;
  overflow: hidden;
  /* 21:9 on a desktop is a map you can read a neighbourhood from without it
     taking the whole screen. The ratio is re-set on narrow widths below. */
  aspect-ratio: 21 / 9;
  border: 1px solid var(--sv-card-brd);
  border-radius: var(--sv-r-lg);
  background: linear-gradient(140deg, #e4eefb 0%, #dbe9f7 52%, #e9f3fd 100%);
  box-shadow: 0 14px 34px rgba(11, 45, 82, .1);
  transition: box-shadow var(--t-slow) var(--ease-out);
}
.ct-map__frame:hover { box-shadow: 0 22px 54px rgba(11, 45, 82, .16); }

.ct-map__embed {
  display: block;
  width: 100%;
  height: 100%;
  border: 0;
  /* A stop of saturation off, so a third party's colours sit inside this
     page's palette instead of shouting over it. Restored on hover, when the
     map is the thing being used rather than the thing being passed. */
  filter: saturate(.82) contrast(1.02);
  transition: filter var(--t-slow) var(--ease-out);
}
.ct-map__frame:hover .ct-map__embed { filter: none; }

/* The holding state, used only when config.php carries no embed. Decoration
   and nothing else: no streets, no pin, nothing that could be mistaken for a
   map of somewhere. */
.ct-map__holding {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  color: rgba(26, 114, 214, .16);
}
.ct-map__holding svg { width: min(22%, 9rem); height: auto; }
.ct-map__rings {
  position: absolute;
  inset: 0;
  background:
    radial-gradient(closest-side circle at 50% 50%, rgba(255, 255, 255, .5) 98%, transparent 100%) 50% 50% / 26% 46% no-repeat,
    radial-gradient(closest-side circle at 50% 50%, rgba(255, 255, 255, .32) 98%, transparent 100%) 50% 50% / 44% 78% no-repeat,
    radial-gradient(closest-side circle at 50% 50%, rgba(255, 255, 255, .2) 98%, transparent 100%) 50% 50% / 64% 112% no-repeat;
  pointer-events: none;
}


/* ==========================================================================
   08. ENTRY STATES — this page's own reveal channels
   ---------------------------------------------------------------------------
   system.css section 04 already hides [data-sv] and [data-sv-mask] on every
   page. These are the channels that only exist here. Same contract: the start
   state is authored in CSS so nothing flashes, and `.no-js` returns every one
   of them to its finished state.
   ========================================================================== */
[data-ct-mask]  { clip-path: inset(0% 0% 100% 0%); }
[data-ct-map]   { clip-path: inset(0% 0% 100% 0%); }
[data-ct-panel] { clip-path: inset(0% 100% 0% 0%); }
[data-ct-card]  { opacity: 0; }
[data-ct-row]   { opacity: 0; }

.no-js [data-ct-mask],
.no-js [data-ct-map]   { clip-path: none; }
.no-js [data-ct-panel] { clip-path: none; }
.no-js [data-ct-card],
.no-js [data-ct-row]   { opacity: 1; }
.no-js .ct-consult__rule { transform: none; }


/* ==========================================================================
   09. RESPONSIVE
   ---------------------------------------------------------------------------
   Checked at 1440, 1280, 1024, 768, 480, 390 and 360. The two structural
   changes are the hero becoming a stack and the contact composition losing
   its overlap — below 980px the panel and the card are simply two cards, one
   above the other, because an overlap needs width to be an overlap rather
   than a collision.
   ========================================================================== */
@media (max-width: 1180px) {
  .ct-connect__inner { grid-template-columns: minmax(0, .9fr) minmax(0, 1.1fr); }
}

@media (max-width: 980px) {

  /* ONE COLUMN, INFORMATION FIRST. The markup is already in that order, so
     nothing is reordered here — the overlap is simply given back as a gap. */
  .ct-connect__inner { grid-template-columns: minmax(0, 1fr); gap: clamp(1.5rem, 4vw, 2.5rem); }
  .ct-panel     { margin: 0; }
  .ct-form-card { padding: clamp(1.6rem, 4.5vw, 2.4rem); }
}

@media (max-width: 700px) {
  .ct-map__frame { aspect-ratio: 4 / 3; }
}

@media (max-width: 560px) {
  .ct-consult       { padding-block: clamp(2.75rem, 8vh, 4rem) clamp(1.5rem, 4vh, 2.25rem); }
  .ct-consult__text { text-align: left; }

  /* Two blocks of the panel can share a row at this width without either
     losing its measure, which keeps the hours in view beside the number. */
  .ct-panel      { padding: clamp(1.4rem, 5vw, 1.9rem) clamp(1.25rem, 4.5vw, 1.6rem); }
  .ct-form-card  { padding: clamp(1.4rem, 5vw, 1.9rem) clamp(1.25rem, 4.5vw, 1.6rem); }
  .ct-form__foot { flex-direction: column; align-items: stretch; }
  .ct-form__submit { width: 100%; }
  .ct-form__status { text-align: center; }
}

@media (max-width: 400px) {
  .ct-play        { width: 4rem; }
  .ct-map__frame  { aspect-ratio: 1 / 1; }
  .ct-panel__line { font-size: .95rem; }
}


/* ==========================================================================
   10. REDUCED MOTION
   ---------------------------------------------------------------------------
   contact.js returns before building a single timeline when the query
   matches, so what is left here is the motion it does not own: the play
   button's pulse, the map's filter and the hover transitions. The FORM keeps
   its focus transitions — a focus ring that appears instantly is not motion
   anybody asked to be spared.
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {
  [data-ct-mask],
  [data-ct-map]   { clip-path: none; }
  [data-ct-panel] { clip-path: none; }
  [data-ct-card],
  [data-ct-row]   { opacity: 1; }
  .ct-consult__rule { transform: none; }

  .ct-play__ring { animation: none; }
  .ct-map__embed,
  .ct-map__frame { transition: none; }
  .ct-map__embed { filter: none; }
}

/* "Please remove all image and image-container shadow effects so the images
   look clean and flat."  page-hero.php emits {prefix}-hero__frame as the
   <figure> that holds the hero photograph, so it is an image container like
   any other. The first sweep covered service-detail.css and team.css; this
   one was missed. Measured, not assumed — the computed style still carried
   the elevation on this page. */
.ct-hero__frame { box-shadow: none; }

/* The form's own title, above the fields. Sized under the section heading so
   the two do not compete: this names the form, the H2 names the section. */
.ct-form__title {
  margin: 0 0 clamp(1rem, 2.5vh, 1.5rem);
  font-family: var(--f-display);
  font-size: clamp(1.15rem, .9rem + .9vw, 1.5rem);
  font-weight: 400;
  line-height: 1.2;
  letter-spacing: -0.01em;
  color: var(--c-ink);
  text-wrap: balance;
}

/* The practice's film on this page, under the directions it belongs with.
   Capped at the width the original gives it. */
.ct-consult__film {
  max-width: 600px;
  margin-inline: auto;
  margin-top: clamp(1.75rem, 4.5vh, 2.75rem);
}
