/* premium-content — owned by one agent; layered on top of styles.css */

/* ============================================================================
   PREMIUM — CONTENT PAGES + SITE CHROME
   Scope: blog listing, blog posts, about, staff, contact, plus the frame that
   wraps every page (notice strip, header, footer, buttons, links, booking
   modal, assistant panel).

   Direction: "Soft UI Evolution". Depth comes from the shared --elev-* ramp,
   motion from --dur/--ease-out, rhythm from --space-*. Palette, fonts and
   layout structure are deliberately untouched.
   ============================================================================ */


/* ---------------------------------------------------------------------------
   1. BUTTON FAMILY (global)
   The last sharp-cornered element on the site. Brought into the same 8px band
   as every card and panel so the button family reads as one system.
   --------------------------------------------------------------------------- */
.button,
.button-small,
.button-outline,
.article a.button,
.article a[href="#consult"]{
  border-radius:var(--r);
}
.button{
  padding:14px 24px;
  box-shadow:var(--elev-1);
  transition:
    background-color var(--dur) var(--ease-out),
    border-color var(--dur) var(--ease-out),
    box-shadow var(--dur) var(--ease-out),
    transform var(--dur-fast) var(--ease-out);
}
.button:hover{
  transform:translateY(-2px);
  box-shadow:var(--elev-3);
}
.button:active{
  transform:translateY(0);
  box-shadow:var(--elev-1);
  transition-duration:80ms;
}
.button-small{padding:11px 17px}
.header-compact .button-small{padding:10px 15px}
.button-outline{box-shadow:none}
.button-outline:hover{box-shadow:var(--elev-2)}

/* Arrow glyphs travel a little on hover — the only motion these need. */
.button span,
.text-link span{transition:transform var(--dur) var(--ease-out)}
.button:hover span,
.text-link:hover span{transform:translateX(4px)}

.text-link{
  padding-bottom:5px;
  border-bottom-color:rgb(7 82 143 / .34);
  transition:border-color var(--dur) var(--ease-out),color var(--dur) var(--ease-out);
}
.text-link:hover{border-bottom-color:currentColor}

.crumb{transition:opacity var(--dur) var(--ease-out)}
.crumb:hover{opacity:.72}


/* ---------------------------------------------------------------------------
   2. TOP NOTICE STRIP
   Was a cramped 34px band. A little more height and tracking lets it read as
   a deliberate ribbon rather than a leftover utility bar.
   --------------------------------------------------------------------------- */
.notice{
  min-height:38px;
  gap:2.1rem;
  letter-spacing:.085em;
  box-shadow:inset 0 -1px 0 rgb(255 255 255 / .08);
}
.notice a{
  padding-bottom:2px;
  border-bottom:1px solid transparent;
  transition:border-color var(--dur) var(--ease-out),color var(--dur) var(--ease-out);
}
.notice a:hover{border-bottom-color:rgb(216 237 249 / .7)}
@media(max-width:800px){
  .notice{min-height:34px;gap:1.2rem;letter-spacing:.06em}
}


/* ---------------------------------------------------------------------------
   3. HEADER
   Structure, sticky behaviour and the scroll-compact state are unchanged —
   only the quality of the transition, the hairline and the nav hover.
   --------------------------------------------------------------------------- */
.site-header{
  border-bottom-color:rgb(183 210 229 / .62);
  transition:
    height var(--dur) var(--ease-in-out),
    background-color var(--dur) var(--ease-out),
    box-shadow var(--dur) var(--ease-out),
    border-color var(--dur) var(--ease-out);
}
.header-compact .site-header{
  box-shadow:var(--elev-2);
  border-color:rgb(183 210 229 / .4);
}
.site-header__inner{padding:0 var(--space-4)}
@media(max-width:800px){
  .site-header__inner{padding:0 18px}
}

nav{gap:30px}
/* Understated underline that grows from the left; transform-only. */
nav > a:not(.button){
  position:relative;
  padding-bottom:3px;
  transition:color var(--dur) var(--ease-out);
}
nav > a:not(.button)::after{
  content:"";
  position:absolute;
  left:0;right:0;bottom:0;
  height:2px;
  border-radius:2px;
  background:#1675bb;
  transform:scaleX(0);
  transform-origin:left center;
  transition:transform var(--dur) var(--ease-out);
}
nav > a:not(.button):hover{color:#1675bb}
nav > a:not(.button):hover::after{transform:scaleX(1)}
@media(max-width:800px){
  nav{gap:6px;border-radius:0 0 var(--r-lg) var(--r-lg);box-shadow:var(--elev-3)}
  nav > a:not(.button){padding:10px 2px}
}


/* ---------------------------------------------------------------------------
   4. FOOTER
   Previously bare text floating on the page background. Now a quiet tinted
   panel that closes the page, with a real column rhythm.
   --------------------------------------------------------------------------- */
footer{
  margin-top:var(--space-5);
  /* 28px inline padding lands the columns on the same rail as page content,
     leaving the tinted panel as a slim frame around it. */
  padding:var(--space-5) 28px var(--space-4);
  gap:var(--space-4) var(--space-3);
  align-items:start;
  background:#eef5fb;
  border-top:1px solid rgb(183 210 229 / .55);
  border-radius:var(--r-lg) var(--r-lg) 0 0;
  font-size:12.5px;
  line-height:1.6;
}
footer strong{
  font-size:10.5px;
  letter-spacing:.13em;
  color:#1a5f96;
}
footer p{margin-top:12px}
footer a{
  border-bottom:1px solid transparent;
  transition:color var(--dur) var(--ease-out),border-color var(--dur) var(--ease-out);
}
footer a:hover{color:#1675bb;border-bottom-color:rgb(22 117 187 / .45)}
.footer-brand{padding-right:var(--space-3)}
.footer-brand p{max-width:34ch;color:var(--ink-soft)}
@media(max-width:800px){
  footer{
    margin-top:var(--space-4);
    padding:var(--space-4) 18px var(--space-3);
    gap:var(--space-3) 20px;
    /* Panel is edge-to-edge on phones, so rounded corners would only show
       slivers of page background. */
    border-radius:0;
  }
}


/* ---------------------------------------------------------------------------
   5. PAGE / ARTICLE HEROES
   --------------------------------------------------------------------------- */
.page-hero{padding:var(--space-6) var(--space-4) var(--space-5)}
.page-hero p{margin-top:var(--space-2);line-height:1.65}

.article-hero{
  padding-top:var(--space-6);
  padding-bottom:var(--space-6);
  border-bottom:1px solid rgb(183 210 229 / .5);
}
.article-hero .crumb{margin-top:var(--space-3);color:#1675bb}
@media(max-width:800px){
  .page-hero{padding:var(--space-5) 18px var(--space-4)}
  .article-hero{padding-top:var(--space-5);padding-bottom:var(--space-5)}
}


/* ---------------------------------------------------------------------------
   6. LONG-FORM TYPOGRAPHY — bare .article
   --------------------------------------------------------------------------- */
.article{
  max-width:72ch;
  margin:var(--space-6) auto;
  font-size:1.05rem;
  line-height:1.78;
}
.article p{margin:0 0 var(--space-3)}
.article h2{margin-top:var(--space-5);margin-bottom:var(--space-2)}
.article h3{margin-top:var(--space-4);margin-bottom:14px}
.article ul,
.article ol{margin:var(--space-3) 0}
.article li{margin:10px 0}
.article img{
  margin:var(--space-4) auto;
  border-radius:var(--r-lg);
  box-shadow:var(--elev-2);
}
.article a{
  text-underline-offset:3px;
  text-decoration-thickness:1px;
  transition:color var(--dur) var(--ease-out);
}
.article blockquote{
  margin:var(--space-4) 0;
  padding:var(--space-3) var(--space-3) var(--space-3) var(--space-4);
  background:#f2f8fd;
  border-left:3px solid #1675bb;
  border-radius:var(--r);
  box-shadow:var(--elev-1);
}
@media(max-width:800px){
  .article{margin:var(--space-5) auto}
}


/* ---------------------------------------------------------------------------
   7. LONG-FORM TYPOGRAPHY — .resource-article (blog posts)
   This is where a content site's quality is judged, so it carries the one
   piece of boldness in this pass: a lede paragraph and a small accent rule
   anchoring each section heading. Everything around it stays quiet.
   --------------------------------------------------------------------------- */
.resource-article{
  font-size:1.09rem;
  line-height:1.8;
  color:#2f5b7d;
}
.resource-article__body{max-width:68ch}

/* Lede — the opening paragraph carries a little more weight. */
.resource-article__body > p:first-of-type{
  margin-bottom:var(--space-3);
  color:#26567a;
  font-size:1.22rem;
  line-height:1.66;
}

.resource-article p{margin:0 0 var(--space-3)}

.resource-article h2{
  position:relative;
  margin:var(--space-5) 0 var(--space-2);
  padding-top:var(--space-3);
}
.resource-article h2::before{
  content:"";
  position:absolute;
  top:0;left:0;
  width:44px;height:3px;
  border-radius:2px;
  background:#1675bb;
}
.resource-article h3{margin:var(--space-4) 0 12px}

.resource-article strong,
.resource-article b{color:#0d4c7d}

/* Markers: smaller, brand blue, with a comfortable hanging indent. */
.resource-article ul{margin:var(--space-3) 0}
.resource-article li{margin:12px 0;padding-left:28px}
.resource-article li:before{
  top:.82em;
  width:6px;height:6px;
  background:#1675bb;
}
.resource-article li ul{margin:12px 0 4px}
.resource-article li li:before{
  background:transparent;
  box-shadow:inset 0 0 0 1.5px #7ab0d6;
}

.resource-article blockquote{
  margin:var(--space-4) 0;
  padding:var(--space-3) var(--space-3) var(--space-3) var(--space-4);
  border-left:3px solid #1675bb;
  border-radius:var(--r);
  box-shadow:var(--elev-1);
}

.resource-article img{
  display:block;
  margin:var(--space-4) auto;
  border-radius:var(--r-lg);
  box-shadow:var(--elev-2);
}

.resource-article a{
  text-decoration-thickness:1px;
  text-underline-offset:4px;
  transition:color var(--dur) var(--ease-out),text-decoration-color var(--dur) var(--ease-out);
}
.resource-article a:hover{color:#1675bb;text-decoration-color:#1675bb}

@media(max-width:700px){
  .resource-article{font-size:1.02rem}
  .resource-article__body > p:first-of-type{font-size:1.12rem}
  .resource-article h2{margin-top:var(--space-4)}
}


/* ---------------------------------------------------------------------------
   8. BLOG POST HERO + TWO-COLUMN LAYOUT
   Structure preserved; the aside becomes a real card so "Here to help" reads
   as an object rather than stray text.
   --------------------------------------------------------------------------- */
.resource-article-hero__image{
  border-radius:var(--r-lg);
  box-shadow:20px 20px 0 #d9edf8,var(--elev-2);
}
@media(max-width:700px){
  .resource-article-hero__image{box-shadow:10px 10px 0 #d9edf8,var(--elev-1)}
}

/* The aside gains card padding, so the column widens just enough to keep the
   same text measure it had as bare text. */
.resource-article-layout{grid-template-columns:minmax(0,1fr) 316px}
.resource-article-aside{
  position:sticky;
  top:104px;
  padding:var(--space-3) var(--space-3) 10px;
  border:1px solid #d5e7f4;
  border-radius:var(--r-lg);
  background:#fff;
  box-shadow:var(--elev-2);
}
.resource-article-aside::before{
  content:"";
  display:block;
  width:40px;height:3px;
  margin-bottom:var(--space-3);
  border-radius:2px;
  background:#1675bb;
}
.resource-article-aside h2{margin:12px 0 10px}
.resource-article-aside > span{margin-bottom:var(--space-2)}
.resource-article-aside a,
.resource-article-aside button{
  align-items:center;
  padding:14px 0;
  border-top-color:#dfeaf3;
  transition:color var(--dur) var(--ease-out);
}
.resource-article-aside button{border-bottom-color:#dfeaf3}
.resource-article-aside a b,
.resource-article-aside button b{
  display:inline-block;
  transition:transform var(--dur) var(--ease-out);
}
.resource-article-aside a:hover b,
.resource-article-aside button:hover b{transform:translateX(4px)}
@media(max-width:760px){
  .resource-article-aside{position:static;padding:var(--space-3)}
}


/* ---------------------------------------------------------------------------
   9. RESOURCE LISTING — featured + cards
   --------------------------------------------------------------------------- */
.featured-resource{
  margin-bottom:var(--space-3);
  border-radius:var(--r-lg);
  box-shadow:var(--elev-3);
}
.featured-resource b{transition:transform var(--dur) var(--ease-out)}
.featured-resource:hover b{transform:translateX(4px)}

.resource-card{
  border-color:#d5e7f4;
  border-radius:var(--r-lg);
  box-shadow:var(--elev-1);
  transition:
    transform var(--dur) var(--ease-out),
    box-shadow var(--dur) var(--ease-out),
    border-color var(--dur) var(--ease-out);
}
.resource-card:hover{
  transform:translateY(-6px);
  border-color:#9cc8e4;
  box-shadow:var(--elev-4);
}
.resource-card img{transition:transform var(--dur-slow) var(--ease-out)}
.resource-card:hover img{transform:scale(1.035)}
.resource-card__copy{padding:var(--space-3) var(--space-3) 26px}
.resource-card h3{margin:12px 0 var(--space-3)}
.resource-card b{transition:transform var(--dur) var(--ease-out)}
.resource-card:hover b{transform:translateX(4px)}
.resource-directory{gap:var(--space-3)}
@media(max-width:700px){
  .resource-directory{gap:var(--space-2)}
  .resource-card:hover{transform:none}
}


/* ---------------------------------------------------------------------------
   10. ABOUT / TEAM
   The hard offset block behind portraits is an established site motif — it
   stays, but gains a soft layer underneath so it sits on the page instead of
   being pasted onto it.
   --------------------------------------------------------------------------- */
.about-team-portrait{
  border-radius:var(--r-lg);
  box-shadow:18px 18px 0 #d9edf8,var(--elev-2);
}
.about-team-portrait figcaption{
  padding:20px 23px 21px;
  border-top-left-radius:var(--r);
}
.about-team-band{
  border-radius:var(--r-lg);
  box-shadow:var(--elev-3);
}
.about-team-band > div{padding:var(--space-4)}
.about-team-note > div:last-child p{margin-bottom:var(--space-3)}

.team-profile{gap:var(--space-6)}
.team-profile img{
  border-radius:var(--r-lg);
  box-shadow:18px 18px 0 #d9edf8,var(--elev-2);
}
.team-profile p{margin-bottom:var(--space-3);line-height:1.72}
@media(max-width:800px){
  .about-team-portrait{box-shadow:10px 10px 0 #d9edf8,var(--elev-1)}
  .team-profile{gap:var(--space-4)}
  .team-profile img{box-shadow:10px 10px 0 #d9edf8,var(--elev-1)}
}


/* ---------------------------------------------------------------------------
   11. CONTACT
   The three detail tiles were a hairline grid, which left doubled borders and
   a clipped hover lift. They become three separate soft cards.
   --------------------------------------------------------------------------- */
.contact-hero figure{
  border-radius:var(--r-lg);
  box-shadow:20px 20px 0 #d7ebf8,var(--elev-2);
}

.contact-details{
  gap:var(--space-2);
  border-top:0;
  border-left:0;
  border-radius:0;
  overflow:visible;
}
.contact-detail{
  padding:var(--space-3) var(--space-3) 28px;
  border:1px solid #d5e7f4;
  border-radius:var(--r-lg);
  box-shadow:var(--elev-1);
  transition:
    background-color var(--dur) var(--ease-out),
    color var(--dur) var(--ease-out),
    border-color var(--dur) var(--ease-out),
    box-shadow var(--dur) var(--ease-out),
    transform var(--dur) var(--ease-out);
}
.contact-detail:hover{
  transform:translateY(-5px);
  border-color:#07528f;
  box-shadow:var(--elev-4);
}
.contact-detail b{
  display:inline-block;
  transition:transform var(--dur) var(--ease-out);
}
.contact-detail:hover b{transform:translateX(4px)}

.contact-hours{
  padding:var(--space-5);
  border-radius:var(--r-lg);
  box-shadow:var(--elev-1);
}
.contact-hours dl > div{
  padding:20px 0;
  border-top-color:#c6dced;
}
@media(max-width:760px){
  .contact-hero figure{box-shadow:12px 12px 0 #d7ebf8,var(--elev-1)}
  .contact-detail:hover{transform:none}
  .contact-hours{padding:var(--space-4) var(--space-3)}
}


/* ---------------------------------------------------------------------------
   12. CONTENT LIST ROWS
   --------------------------------------------------------------------------- */
.content-list{border-top-color:rgb(183 210 229 / .6)}
.list-item{
  padding:var(--space-3) var(--space-2);
  border-bottom-color:rgb(183 210 229 / .6);
  border-radius:var(--r);
  transition:background-color var(--dur) var(--ease-out);
}
.list-item:hover{background:rgb(234 243 250 / .7)}


/* ---------------------------------------------------------------------------
   13. BOOKING MODAL
   High-intent surface: deeper elevation, calmer field rhythm, and a short
   entrance so it arrives rather than appears.
   --------------------------------------------------------------------------- */
.booking-modal__panel{
  gap:var(--space-2);
  padding:var(--space-4) var(--space-4) var(--space-3);
  border-radius:var(--r-lg);
  box-shadow:var(--elev-4),0 40px 90px rgb(2 35 63 / .22);
}
.booking-modal.open .booking-modal__panel{
  animation:booking-panel-in var(--dur-slow) var(--ease-out) both;
}
@keyframes booking-panel-in{
  from{opacity:0;transform:translateY(14px) scale(.985)}
  to{opacity:1;transform:none}
}
.booking-modal__panel h2{margin-bottom:2px}
.booking-modal__panel > span{margin-bottom:10px;color:#456d8c}
.booking-modal label{gap:9px;font-size:.72rem;letter-spacing:.08em}
.booking-modal input,
.booking-modal textarea{
  padding:13px 14px;
  border-color:#cfe2f0;
  border-radius:var(--r);
  box-shadow:var(--elev-1);
  transition:
    border-color var(--dur-fast) var(--ease-out),
    box-shadow var(--dur-fast) var(--ease-out);
}
.booking-modal input:hover,
.booking-modal textarea:hover{border-color:#9cc8e4}
.booking-modal input:focus,
.booking-modal textarea:focus{
  border-color:#1675bb;
  box-shadow:0 0 0 4px rgb(22 117 187 / .14);
}
.booking-modal .button{margin-top:var(--space-2)}
.booking-modal small{
  grid-column:1/-1;
  margin-top:2px;
  padding-top:var(--space-2);
  border-top:1px solid #dfeaf3;
}
.booking-close{
  transition:background-color var(--dur) var(--ease-out),transform var(--dur) var(--ease-out);
}
.booking-close:hover{background:#cbe4f5;transform:scale(1.06)}
@media(max-width:760px){
  .booking-modal__panel{padding:var(--space-3)}
}

.booking-modal__panel{grid-template-columns:1fr;width:min(560px,100%)}
.booking-modal__panel>label,.booking-modal__panel>.button,.booking-modal__panel>.booking-error{grid-column:1/-1}
.booking-modal label em{justify-self:end;margin-top:-26px;color:#7190a8;font-size:.65rem;font-style:normal;font-weight:650;letter-spacing:0;text-transform:none}
.booking-modal .booking-phone-preference{display:flex;align-items:center;gap:11px;cursor:pointer;font-size:.78rem;letter-spacing:0;text-transform:none}
.booking-modal .booking-phone-preference input{flex:none;width:18px;height:18px;margin:0;padding:0;accent-color:#07528f;box-shadow:none}
.booking-modal .booking-phone-preference span{color:#174f7f;font-weight:700}
.booking-error{margin:0;padding:11px 13px;border-left:3px solid #b94848;background:#fff1f1;color:#8b3030;font-size:.76rem;line-height:1.45}
@media(max-width:600px){.booking-modal{align-items:flex-start;padding:14px;overflow:auto}.booking-modal__panel{margin:auto;padding:28px 22px;gap:13px}.booking-modal__panel h2{font-size:2rem}.booking-modal__panel>span{margin-bottom:2px;font-size:.88rem}.booking-modal textarea{min-height:76px}.booking-modal small{padding-top:12px}}


/* ---------------------------------------------------------------------------
   14. ASSISTANT (launcher + panel)
   The glass treatment is kept; only the entrance, the header alignment and
   the launcher's hover craft are refined.
   --------------------------------------------------------------------------- */
.assistant-launch{
  padding:13px 19px;
  box-shadow:var(--elev-3);
  transition:transform var(--dur) var(--ease-out),box-shadow var(--dur) var(--ease-out);
}
.assistant-launch:hover{
  transform:translateY(-2px);
  box-shadow:var(--elev-4);
}
.assistant-launch:active{transform:translateY(0);transition-duration:80ms}

.assistant.open{animation:assistant-in var(--dur) var(--ease-out) both}
@keyframes assistant-in{
  from{opacity:0;transform:translateY(10px) scale(.985)}
  to{opacity:1;transform:none}
}
/* Title and status line were mis-aligned: the status sat 17px further in. */
.assistant header > div{
  display:flex;
  flex-direction:column;
  align-items:flex-start;
  gap:3px;
}
.assistant header small{margin-left:0}
.assistant header b{line-height:1.2}
.chat-note{padding:2px 20px 14px;line-height:1.5}


/* ---------------------------------------------------------------------------
   15. REDUCED MOTION
   The foundation collapses durations; kill the entrances outright.
   --------------------------------------------------------------------------- */
@media(prefers-reduced-motion:reduce){
  .booking-modal.open .booking-modal__panel,
  .assistant.open{animation:none}
  .button:hover,
  .resource-card:hover,
  .contact-detail:hover,
  .assistant-launch:hover{transform:none}
}


/* ---------------------------------------------------------------------------
   16. SCROLL-IN COVERAGE
   Sections that previously had no entrance at all. These reuse the shared
   .reveal system (one-shot, IntersectionObserver + geometry fallback, and
   already neutralised under prefers-reduced-motion by styles.css), but with a
   lighter transform than the default: full-bleed bands and card grids read
   better with a short rise than with the blur-and-scale used for hero copy.
   Transform/opacity only — no horizontal movement, so nothing can widen the
   layout viewport.
   --------------------------------------------------------------------------- */
.doctor-consultation.reveal,
.contact-detail.reveal,
.contact-hours.reveal,
.directory-heading > .reveal,
.google-reviews__summary.reveal,
.google-review-card.reveal,
.resource-article.reveal,
.resource-article-aside.reveal{
  filter:none;
  transform:translateY(20px);
  transition:
    opacity var(--dur-slow) var(--ease-out),
    transform var(--dur-slow) var(--ease-out);
  transition-delay:var(--reveal-delay,0ms);
}
.doctor-consultation.reveal.reveal-in,
.contact-detail.reveal.reveal-in,
.contact-hours.reveal.reveal-in,
.directory-heading > .reveal.reveal-in,
.google-reviews__summary.reveal.reveal-in,
.google-review-card.reveal.reveal-in,
.resource-article.reveal.reveal-in,
.resource-article-aside.reveal.reveal-in{transform:none}

/* The hover lift must win once the card has settled. */
.contact-detail.reveal.reveal-in:hover{transform:translateY(-5px);transition-delay:0ms}
.google-review-card.reveal.reveal-in:hover{transform:translateY(-2px);transition-delay:0ms}


/* ---------------------------------------------------------------------------
   17. FIRST-PAINT ENTRANCE
   One orchestrated moment: the chrome settles in, the hero copy follows on its
   existing timeline, and the chat launcher arrives last. Gated on
   .page-entrance, which JS adds at first render — without it every element is
   simply visible, so nothing here can strand content off-screen.
   --------------------------------------------------------------------------- */
.page-entrance .notice{animation:chrome-drop var(--dur-slow) var(--ease-out) both}
.page-entrance .site-header__inner{
  animation:chrome-drop var(--dur-slow) var(--ease-out) both;
  animation-delay:70ms;
}
.page-entrance .assistant-launch{
  animation:chrome-rise var(--dur-slow) var(--ease-out) both;
  animation-delay:640ms;
}
@keyframes chrome-drop{
  from{opacity:0;transform:translateY(-8px)}
  to{opacity:1;transform:none}
}
@keyframes chrome-rise{
  from{opacity:0;transform:translateY(10px) scale(.96)}
  to{opacity:1;transform:none}
}

@media(prefers-reduced-motion:reduce){
  .page-entrance .notice,
  .page-entrance .site-header__inner,
  .page-entrance .assistant-launch{animation:none}
  .contact-detail.reveal.reveal-in:hover,
  .google-review-card.reveal.reveal-in:hover{transform:none}
}


/* ---------------------------------------------------------------------------
   18. SCROLL-LINKED REVEALS
   The entrance for every section is bound to --reveal-progress, which app.js
   recomputes from scroll position on each frame (see setupScrollReveal) — the
   same model as --feature-progress on the home feature bands. The motion
   therefore advances *and reverses* with the scrollbar instead of firing once
   and finishing off-screen.

   .reveal-in is applied at the same moment as .reveal, so every settled-state
   rule above (and every hover lift, which is more specific than this block)
   still applies; this block only re-binds the animated properties.

   Fallback: --reveal-progress defaults to 1 here, and .reveal-scroll is only
   ever added by the same JS statement that writes the first value. No JS, a
   thrown script, or a blocked app.js all leave sections fully visible.
   Transform is translateY + scale only — nothing horizontal, so the layout
   viewport can never widen.
   --------------------------------------------------------------------------- */
.reveal.reveal-in.reveal-scroll{
  opacity:var(--reveal-progress,1);
  transform:
    translateY(calc((1 - var(--reveal-progress,1)) * 30px))
    scale(calc(.988 + var(--reveal-progress,1) * .012));
  filter:none;
  /* Short linear smoothing between rAF samples, matching the feature bands.
     !important is needed only to beat the !important transition on .service-card. */
  transition:opacity .16s linear,transform .16s linear!important;
  transition-delay:0ms!important;
  will-change:opacity,transform;
}

@media(prefers-reduced-motion:reduce){
  .reveal.reveal-in.reveal-scroll{
    opacity:1!important;
    transform:none!important;
    filter:none!important;
    transition:none!important;
  }
}
