/* Your Neighbor Medical Group — shared interactive/motion CSS.
   Loaded by every page (index.html, services.html) so nav, dropdown,
   mobile drawer and scroll animations stay in sync across the site. */

html { scroll-behavior: smooth; }
body { margin: 0; background: var(--white); }
@keyframes yn-marquee { to { transform: translateX(-50%); } }
/* Duration scaled 3x (32s -> 96s) to match app.jsx's 3x-repeated track —
   same px/sec speed as before, just now looping over 3x the distance so
   a full "set" always outsizes the viewport and never runs out mid-scroll. */
.yn-marquee { animation: yn-marquee 96s linear infinite; }
@keyframes yn-wapulse { 0%,100% { box-shadow: 0 6px 24px rgba(37,211,102,.45); } 50% { box-shadow: 0 12px 38px rgba(37,211,102,.8); } }
.yn-wa { animation: yn-wapulse 2.8s ease infinite; }
@media (max-width: 900px) {
  .yn-2col { grid-template-columns: 1fr !important; }
  .yn-svcgrid, .yn-whygrid { grid-template-columns: repeat(2, 1fr) !important; }
  .yn-footgrid { grid-template-columns: 1fr 1fr !important; }
}
/* Contact's 3 columns (schedule / form / map) need more room than a 2-col
   section before they cramp — collapse straight to 1 column rather than
   passing through an awkward 2-then-1 state. */
@media (max-width: 1100px) {
  .yn-contact-grid { grid-template-columns: 1fr !important; }
}
/* The full desktop nav (6 links + Book button) needs ~1000px to fit without
   wrapping/overflowing — switching to the burger at 900px (matching the
   grid breakpoints above) left a 901-999px gap where the links reappeared
   but didn't fit, overflowing the page horizontally. Its own wider,
   independent breakpoint closes that gap. */
@media (max-width: 1000px) {
  .yn-navlinks { display: none !important; }
  .yn-burger { display: inline-flex !important; }
  /* Language switch stays in the main bar next to the theme toggle on
     mobile too (moved out of the drawer) — shrunk at 480px below so the
     brand, toggle, switch and burger all still fit without overflowing. */
}
/* ── Phones: compact the list-heavy sections ("What We Offer", "Why
   Choose Us", footer) so they don't force endless scrolling. Instead of
   collapsing to one tall single column, keep two tidy columns of small
   tiles and trim the generous desktop padding. ── */
@media (max-width: 600px) {
  /* Keep 2 columns (don't collapse to 1) + tighter gaps */
  .yn-svcgrid { grid-template-columns: 1fr 1fr !important; gap: 10px !important; }
  .yn-whygrid { grid-template-columns: 1fr 1fr !important; gap: 10px !important; }

  /* Trim the tall 5rem section padding down on phones */
  #services, #why-us { padding: 3rem 1.1rem !important; }
  /* #reviews and #insurance are full-bleed marquees (padding: Ns 0 in
     JSX already) — deliberately excluded here so their tracks stay
     edge-to-edge instead of getting inset by this override. */
  #how-it-works, #faq, #team { padding: 3rem 1.1rem !important; }
  .yn-faq-item summary { padding: 0.95rem 1rem !important; font-size: 0.92rem !important; }
  .yn-faq-answer { padding: 0 1rem 1rem !important; }
  /* Mental-health keeps extra top/bottom padding so the edge fade below
     never overlaps content. */
  #mental-health { padding: calc(2.4rem + 40px) 1.1rem !important; }
  /* Phones: drop the decorative wave cut and instead melt the navy band
     into the page background with a soft transparency fade at each edge
     — reads as calmer than a hard wave shape at this size. Masking (not
     a color-matched gradient overlay) so it blends correctly with
     whatever's actually behind it, light or dark mode alike. */
  #mental-health .yn-wave { display: none !important; }
  #mental-health {
    /* White = fully shown, black/transparent = hidden — CSS mask
       gradients read by luminance, not alpha, so the "kept" stops must
       be white, not black. */
    -webkit-mask-image: linear-gradient(to bottom, transparent 0, #fff 42px, #fff calc(100% - 42px), transparent 100%) !important;
    mask-image: linear-gradient(to bottom, transparent 0, #fff 42px, #fff calc(100% - 42px), transparent 100%) !important;
  }
  #about { padding: 3rem 1.1rem !important; }

  /* About: Core Values tighten on phones */
  .yn-valuesgrid { grid-template-columns: 1fr 1fr !important; gap: 10px !important; }
  .yn-valuesgrid > * { padding: 1.15rem 0.8rem !important; }
  .yn-valuesgrid h4 { font-size: 0.95rem !important; }
  .yn-valuesgrid p { font-size: 0.78rem !important; }
  .yn-steps { gap: 22px !important; }

  /* Team: three 4:5 portraits in one compact row (was a tall single
     stack ~2000px). Captions shrink to role + one-line note so the row
     stays legible at ~118px per card. */
  .yn-team { grid-template-columns: repeat(3, 1fr) !important; gap: 8px !important; }
  .yn-member figcaption { padding: 0.55rem 0.5rem 0.65rem !important; gap: 3px !important; }
  .yn-member strong { font-size: 0.72rem !important; line-height: 1.2 !important; }
  .yn-member span { font-size: 0.63rem !important; line-height: 1.32 !important; }
  /* About Us page: 4-person team grid — 2x2 reads better than 4 cramped
     columns at phone width. */
  .yn-team4 { grid-template-columns: repeat(2, 1fr) !important; gap: 12px !important; }

  /* Service cards → compact centred tiles: icon on top, title below,
     smaller type. Tighter than before (shorter padding + smaller icon
     tile) so all 16 read as a dense, scannable grid with far less scroll. */
  .yn-svcgrid > a {
    flex-direction: column !important;
    align-items: center !important;
    text-align: center !important;
    gap: 0.4rem !important;
    padding: 0.7rem 0.4rem !important;
  }
  .yn-svcgrid > a > span:first-child { width: 40px !important; height: 40px !important; }
  .yn-svcgrid > a > span:first-child svg { width: 20px !important; height: 20px !important; }
  .yn-svcgrid > a > span:last-child { align-items: center !important; }
  .yn-svcgrid > a > span:last-child > span { font-size: 0.74rem !important; line-height: 1.18 !important; }

  /* Why-Us cards: tighter padding + smaller number/icon so the 2×2 block
     is noticeably shorter. */
  .yn-whygrid > * { padding: 0.95rem 0.6rem !important; }
  .yn-whygrid > * > div:first-child { margin-bottom: 6px !important; }
  .yn-whygrid > * > div:nth-child(2) { font-size: 1.1rem !important; margin-bottom: 2px !important; }
  .yn-whygrid > * h3 { font-size: 0.86rem !important; }
  .yn-whygrid > * p { font-size: 0.76rem !important; line-height: 1.4 !important; }

  /* Mental-health cards: reduce the generous glass-card padding and top
     band so the 2×2 grid and the whole navy section are much shorter. */
  #mental-health .yn-mh > * { padding: 0.95rem !important; }
  #mental-health .yn-mh h4 { margin: 8px 0 3px !important; font-size: 0.9rem !important; }
  #mental-health .yn-mh p { font-size: 0.78rem !important; line-height: 1.4 !important; }

  /* Footer: brand block spans full width, then the three link columns
     share a tidy 2-column grid beneath it instead of three tall stacked
     blocks — roughly halves the footer's height. */
  .yn-footgrid { grid-template-columns: 1fr 1fr !important; gap: 1.4rem 1rem !important; }
  .yn-footgrid > :first-child { grid-column: 1 / -1 !important; }
  footer { padding-top: 2.75rem !important; }

  /* Top utility bar: all four items don't fit on a phone, so it wrapped
     into a messy two-line strip. Keep one balanced line — phone number
     left, "Book Appointment" right. The hours live in the Contact
     section and WhatsApp already has its floating button + drawer entry.
     (TopBar has no class hooks; scoped via its inline navy-900 bg.) */
  .yn-page > div[style*="--navy-900"] { padding-left: 1.1rem !important; padding-right: 1.1rem !important; }
  .yn-page > div[style*="--navy-900"] > div:first-child > span:nth-child(2) { display: none !important; }
  .yn-page > div[style*="--navy-900"] > div:last-child > a:first-child { display: none !important; }

  /* Services-page hero: the "jump to any service" pill list (16 items,
     one per service) stacked one-per-row and ran ~684px tall on a phone —
     nearly a full screen of chips before any real content. Turned into a
     single swipeable row instead: every label stays fully readable (no
     truncation, no icon-only shrink), it's just a horizontal scroll away
     rather than a long vertical wall. */
  .yn-svc-jump {
    flex-wrap: nowrap !important;
    justify-content: flex-start !important;
    overflow-x: auto !important;
    -webkit-overflow-scrolling: touch;
    scroll-snap-type: x proximity;
    scrollbar-width: none;
    padding: 0.15rem 0 0.5rem !important;
    /* Edge fade hints there's more to scroll, without a hard cut line —
       same technique as the insurance-logos marquee (.yn-logos). */
    -webkit-mask-image: linear-gradient(90deg, transparent, #000 16px, #000 calc(100% - 16px), transparent);
    mask-image: linear-gradient(90deg, transparent, #000 16px, #000 calc(100% - 16px), transparent);
  }
  .yn-svc-jump::-webkit-scrollbar { display: none; }
  .yn-svc-jump a {
    flex: none !important;
    white-space: nowrap !important;
    padding: 0.42rem 0.8rem !important;
    font-size: 0.8rem !important;
    scroll-snap-align: start;
  }

  /* Service cards: single column, shorter photo, tighter padding + chips
     so a 30-sub-service card still scrolls reasonably on a phone. */
  .yn-svc-grid { grid-template-columns: 1fr !important; gap: 16px !important; }
  .yn-svc-photo { aspect-ratio: 16 / 9 !important; }
  .yn-svc-body { padding: 1.15rem 1.15rem 1.35rem !important; }
  .yn-svc-body h3 { font-size: 1.02rem !important; }
  .yn-chip { font-size: 0.7rem !important; padding: 0.28rem 0.58rem !important; }
}

/* ── Hero (About Us / Services / Why Us photo-only heroes) ──
   These base classes now belong only to the "photo-only" hero pattern:
   a full-bleed photo, a plain navy scrim, nothing overlaid — used by
   About Us today. The homepage hero (Hero() in app.jsx) stopped sharing
   this system 2026-08-24 when it moved to its own self-contained
   .yn-p35-* layout (see the "HOME HERO" block further down) — that
   redesign confines its own photo to a small side panel instead of a
   full-bleed background, so it no longer needs this shared scrim
   system. */
.yn-hero-photo-box {
  position: relative;
  overflow: hidden;
  box-shadow: 0 20px 50px rgba(5, 20, 40, 0.16);
  /* Full viewport width, edge to edge, while staying in normal document
     flow — the standard "breakout" trick: 100vw is the true viewport
     width regardless of nesting, and 50% here resolves against this
     element's own containing block, so the difference between the two
     is exactly how far to pull each edge out to reach the real viewport
     edge, on either side, at any width. */
  width: 100vw;
  margin-left: calc(-50vw + 50%);
  margin-right: calc(-50vw + 50%);
  /* Height scales continuously with viewport width (25vw) rather than
     hitting a flat px ceiling — a flat cap (this used to read
     "clamp(460px, 46vw, 720px)") makes the SAME pixel height sit under
     very different widths on different monitors: a 1920px (24") and a
     3440px (34" ultrawide) screen both hit the old 720px cap, but 720px
     under 1920px of width reads as a noticeably taller, more-cropped
     band than the identical 720px under 3440px does — the two monitors
     showed visibly different photo proportions for that reason, not a
     bug in the crop position itself. (25vw, not the 21vw this first
     shipped at: 21vw fixed the cross-monitor mismatch but cropped too
     tight on both edges — barely any headroom above the group's heads,
     and their torsos cut off close underneath. Raised across the board
     so both edges gain breathing room, unevenly on purpose: with
     .yn-hero-photo-img's "center 22%" anchor below, the crop removes
     78% of any shrinkage from the bottom and only 22% from the top, so
     more space below the shoulders than above the heads without
     touching that anchor value itself.) 25vw is calibrated so 3440px
     lands at ~860px and 1920px at ~480px — both read as the same
     panoramic proportions, just less tightly cropped than before at
     either. The 420px floor keeps mid-size desktop widths (roughly
     1101–1680px, where 25vw alone would dip below that) from reading as
     a thin strip; the 900px ceiling only matters past ~3600px, wider
     than any current monitor class this was tuned against. */
  min-height: clamp(420px, 25vw, 900px);
}
.yn-hero-photo-img {
  position: absolute;
  inset: 0;
  background-size: cover;
  /* "center 22%" keeps faces in frame at every crop ratio — the group
     photo's heads sit in the upper third, coats fill the rest, so a
     plain "center" crops into foreheads on short/wide boxes. Also the
     reason raising the box's min-height (above) puts most of the extra
     room below the group rather than above it: at 22%, `cover` only
     ever trims 22% of any surplus off the top, 78% off the bottom. */
  background-position: center 22%;
  background-repeat: no-repeat;
}
/* Left-heavy → right-clear navy scrim: dark enough on the left for the
   copy to sit on, fading out toward the right so the group stays
   clearly visible rather than being flattened under a uniform tint. A
   soft bottom wash is layered in too, for the fact-strip's overlap zone
   and for legibility if the content block grows tall on narrow screens.

   Stops are in PX, not %, and deliberately so: the copy column's width
   is capped in px (.yn-hero-content-inner's 560px, plus the ~24–32px
   left gutter — ~584–592px total, fairly constant across breakpoints
   since that cap doesn't scale with viewport), but a %-based gradient
   is relative to viewport width, which does scale — tried % first, and
   it held opaque past the text column on a 1440px desktop but stopped
   noticeably short of the column on a 900px tablet. Px stops keep the
   dark zone the same physical width the text column actually is, at
   every viewport, rather than growing or shrinking with it.

   Values stay moderate (peaks at 0.88, never fully opaque) rather than
   blacking the left edge out solid: the nearest team member's coat and
   shoulder stay softly visible through the wash instead of vanishing
   under a flat color block, which reads as more considered than a hard
   cut from "photo" to "navy panel". */
.yn-hero-scrim {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    linear-gradient(180deg, rgba(4, 38, 76, 0) 55%, rgba(4, 38, 76, 0.55) 100%),
    linear-gradient(
      95deg,
      rgba(4, 38, 76, 0.88) 0px,
      rgba(6, 47, 92, 0.80) 280px,
      rgba(8, 58, 105, 0.62) 600px,
      rgba(8, 58, 105, 0.30) 920px,
      rgba(8, 58, 105, 0.06) 1300px
    );
}
/* About-only mirror of .yn-hero-scrim's left fade, anchored to the
   right edge instead (270deg = "to left", so the gradient starts opaque
   at the right edge and fades moving left — same px distances as the
   left version, just flipped). Each stop is +0.10 more opaque than its
   left-side counterpart (0.88→0.98, 0.80→0.90, 0.62→0.72, 0.30→0.40,
   0.06→0.16), per spec — this page has no text sitting on top of either
   side, so there's no contrast reason for the two edges to differ; the
   extra opacity on the right is a deliberate asymmetry, not a mistake
   left over from copying the left values. Layered as a second div
   alongside .yn-hero-scrim rather than folded into one gradient list,
   so each side's fade stays independently tunable. */
.yn-hero-scrim-right {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(
    270deg,
    rgba(4, 38, 76, 0.98) 0px,
    rgba(6, 47, 92, 0.90) 280px,
    rgba(8, 58, 105, 0.72) 600px,
    rgba(8, 58, 105, 0.40) 920px,
    rgba(8, 58, 105, 0.16) 1300px
  );
}
/* ═══════════ HOME HERO — "Propuesta 35" (Hero() in app.jsx) ═══════════
   Recreates a client-supplied reference mockup: navy headline, four
   inline feature items, two buttons, one small floating rating card.

   Text-over-full-bleed-image (like the reference mockup, and like this
   hero's earlier Hero1.png background) only works when the image has a
   genuinely empty zone for the text to sit in — Hero1.png did (its
   subject sat right-weighted, left half empty). The animation frames
   that replaced it don't: the subject (logo, then coat, then hands —
   see HERO's comment in app.jsx) sits CENTERED in every frame, so full
   width + overlaid text meant the copy was always one frame — or one
   wider viewport — away from crossing into it. Confirmed the hard way:
   a percentage-based "keep N% clear of center" version still visibly
   crossed into the subject.

   So the animation gets a box of its own at every width, and text never
   sits on it. Above ~768px that's a real two-column layout:
   .yn-p35-grid (text) and .yn-p35-bg (the animation, a proper flex item
   now rather than an absolutely-positioned full-bleed layer) side by
   side, ordered via `order` so text stays first in DOM/reading order.
   Below it they stack — same idea, one column (see the max-width:767px
   block further down). Either way overlap is structurally impossible,
   regardless of viewport width or the subject's shape in a given frame,
   unlike clearance math against a shared full-bleed layer.

   yn-p35-* throughout — a fresh prefix, not yn-p12-* or yn-hh-* (earlier
   designs here) or yn-hero-* (which belongs solely to the photo-only
   heroes on About/Services/Why Us), so nothing here can collide with
   either. */
/* Wraps <section id="home"> so it can be pinned (below) without
   collapsing the page under it: a sticky element's "stuck" duration is
   governed by its PARENT's extra height, not its own, so this wrapper
   is what actually reserves the scroll room the animation plays across.
   Plain-height/no-op on phones — see the min-width block below. */
.yn-p35-scrollwrap { position: relative; }
.yn-p35 {
  position: relative;
  overflow: hidden;
  /* Fallback color only — fully covered by .yn-p35-bg-img once it loads
     (background-size:cover always fills this section entirely), just
     avoids a flash of bare white before the image paints. */
  background: linear-gradient(180deg, var(--white) 0%, var(--surface-sky) 55%, var(--white) 100%);
  padding: clamp(3rem, 6vw, 5.5rem) 2rem clamp(4rem, 7vw, 6rem);
}
/* .yn-p35-scrollwrap and .yn-p35 get pinned above ~768px — see the big
   media query placed after .yn-p35-copy below, once .yn-p35-bg,
   .yn-p35-bg-img and .yn-p35-grid all have their base rules in place
   for it to override. It has to come after all of them in source order:
   same specificity either way, so whichever rule is LATER in the file
   wins, @media condition or not. */
.yn-p35-bg { position: absolute; inset: 0; z-index: 0; overflow: hidden; }
.yn-p35-bg-img {
  position: absolute;
  inset: 0;
  /* Poster = frame 1, what shows before the canvas paints and whenever
     it never does (no JS, prefers-reduced-motion). Set here rather than
     inline in Hero() so the phone block below can point it at the
     lighter encode instead — the ?v must be kept in step with
     HERO_FRAME_V in app.jsx. */
  background-image: url("assets/hero-anim/f0001.webp?v=3");
  background-size: cover;
  background-repeat: no-repeat;
  /* Centered (not right-weighted): this sequence's subject (logo, then
     coat, then hands) sits in the middle of the frame, unlike the old
     Hero1.png's right-anchored stethoscope. 38% vertical keeps it
     slightly above dead-center, matching where the subject actually
     sits across the sequence. Must match the canvas's own drawCover()
     anchor in app.jsx (also 50%/38%) — this is only what shows before
     the canvas draws its first frame (or when it never does: no JS,
     phones, prefers-reduced-motion — see Hero()'s effect). */
  background-position: 50% 38%;
}
.yn-p35-canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
}
/* A white .yn-p35-scrim used to sit here, washing out the image so the
   copy could be read on top of it. Both layouts now give the animation
   a box of its own with no text over it — the two-column split ≥768px,
   the stacked block below it — so there is nothing left to protect and
   the element went away with it. */
.yn-p35-grid {
  position: relative;
  z-index: 1;
  max-width: var(--container-max);
  margin: 0 auto;
}
/* 640px ceiling — only actually binding below 768px (phones/tablets,
   full-bleed-with-scrim mode): at ≥768px .yn-p35-grid's own
   flex-basis:460px (set in the pinning media query below) is the
   tighter constraint, so .yn-p35-copy just fills it. */
.yn-p35-copy { max-width: 640px; }

/* Pin the hero for one extra viewport-height of scroll room so the
   frame sequence in Hero()'s canvas effect actually plays out on
   screen instead of scrolling away mid-sequence — see that effect's
   comment in app.jsx for why this replaced an earlier unpinned version.
   768px (not the animation's own max-width:640px cutoff in app.jsx)
   is deliberately higher: below it .yn-p35-scrollwrap stays auto-height
   and .yn-p35 stays position:relative/block (set above), matching where
   the canvas effect itself is skipped too (app.jsx's isCompact check
   uses the same 768px) — see the two-column split below for why this
   hero needs more room than a phone/small-tablet width can spare.

   prefers-reduced-motion: no-preference is required too, and for the
   same reason it's required for the canvas draws in app.jsx: pinning
   without it would force reduced-motion users to scroll through an
   extra, dead 100vh of nothing-happening space (the canvas skips
   drawing but the scroll room would still be reserved) — worse than no
   animation at all.

   Placed here (after .yn-p35-bg, .yn-p35-bg-img and .yn-p35-grid/-copy's
   own base rules above) rather than up near .yn-p35-scrollwrap/.yn-p35
   where it conceptually belongs: a media query doesn't out-rank a plain
   rule of equal specificity, so it has to come AFTER everything it
   overrides in source order or those later base rules would win
   instead — confirmed the hard way with .yn-p35-bg silently staying
   full-bleed-absolute at 1280/1920px despite this block "setting" it to
   a flex item, because the unconditional base rule further down the
   file was winning the cascade. */
@media (min-width: 768px) and (prefers-reduced-motion: no-preference) {
  .yn-p35-scrollwrap { height: 200vh; }
  /* min-height:100vh so the pinned hero fills the viewport — anything
     shorter and the sticky section would leave a visible band of empty
     wrapper below it for the whole pinned stretch (the wrapper holds
     nothing else).

     display:flex row (not the block layout used below 768px) is what
     turns .yn-p35-grid and .yn-p35-bg into the two real columns — see
     the big comment at the top of this section. align-items:center
     vertically centers .yn-p35-grid; .yn-p35-bg overrides that for
     itself with align-self:stretch (below) so the animation panel still
     fills the full height.

     Asymmetric padding is what puts the panel flush against three of
     its four edges, per an explicit request: top = the floating nav's
     own height (62px inner + 2×0.7rem outer padding — see Nav's inline
     styles in shared.jsx) so the panel starts exactly at the header's
     bottom edge instead of sliding under the glass island once pinned;
     right and bottom = 0, so the panel reaches the viewport's right
     edge and butts directly against <Marquee/> below with no white
     band between them. Only the left keeps padding — that's the text
     column's side. gap:0 for the same reason: the panel's own left-edge
     mask (below) is what separates the columns now, and a flex gap on
     top of it would just push the animation further right for nothing.

     The matching NEGATIVE top margin is what makes that top edge line
     up before the hero is pinned as well as after. Pinned, the section
     sits at viewport 0 and the 85px padding lands the panel exactly at
     the nav's bottom. Unpinned (page freshly loaded), the section
     starts below the nav's own flow box instead, so that same padding
     showed up as an 85px white band between header and video. Pulling
     the section up by exactly the nav's height cancels that: the
     section's box now starts where the nav's does, the padding puts the
     panel at the nav's bottom edge in BOTH states, and the nav still
     paints over the overlap (it's sticky with z-index 80, this isn't). */
  .yn-p35 { position: sticky; top: 0; min-height: 100vh; display: flex; flex-direction: row; align-items: center; gap: 0; margin-top: -85px; padding: 85px 0 0 clamp(1.5rem, 4vw, 3rem); }
  /* Fluid, not a flat width: this breakpoint starts at 768px (small
     tablets), where a flat 460px text column left the animation panel
     squeezed to a tall, oddly narrow sliver. Scaling with viewport width
     lets both columns share the squeeze at tablet widths and settles at
     440px once there's room to spare on laptops+. */
  .yn-p35-grid { order: 1; flex: 0 0 clamp(280px, 34vw, 440px); max-width: clamp(280px, 34vw, 440px); margin: 0; }
  /* Turns from an absolutely-positioned full-bleed layer (the
     below-768px / phones+tablets+reduced-motion behavior, set in the
     base .yn-p35-bg rule above) into a normal flex item that only ever
     occupies the remaining space next to .yn-p35-grid — that's the
     actual mechanism that makes the split real instead of just visual.
     align-self:stretch fills the row's full height (.yn-p35's own
     min-height:100vh) regardless of the row's align-items:center (which
     is for .yn-p35-grid).

     No radius/shadow (an earlier version had both): with the panel now
     flush to three edges, a rounded outline would just re-draw the hard
     "pasted rectangle" seam this is meant to lose. The left edge — the
     one facing the text, the only one not against a viewport/section
     boundary — instead fades out over 170px so the animation dissolves
     into the page rather than ending on a line. transparent→#fff (not
     →#000) because a CSS mask gradient is read by LUMINANCE here, so
     white is the "keep" end; black would hide exactly the wrong half
     (same trap as the Mental Health section's edge fade). */
  .yn-p35-bg {
    order: 2; position: relative; inset: auto;
    flex: 1 1 0%; align-self: stretch; min-width: 0;
    border-radius: 0; box-shadow: none;
    -webkit-mask-image: linear-gradient(to right, transparent 0, #fff 170px);
    mask-image: linear-gradient(to right, transparent 0, #fff 170px);
  }
  /* Both layers stop being full-height fills of the panel and instead
     take the frames' own 16:9 shape, pinned to the panel's top edge.
     Why not just leave them inset:0 and let background-size sort it
     out: `cover` scaled to the panel's HEIGHT and threw ~45% of each
     frame's width off the sides — the "YOUR NEIGHBOR" wordmark spans
     nearly the full frame, so it was visibly chopped at both ends
     (reported as the video looking cut). Sizing the BOX to 16:9 instead
     means the whole frame always shows, edge to edge across the panel,
     with no crop in either direction — and, unlike a fit-to-width
     background inside a full-height box, the element's bottom edge now
     lands exactly on the image's bottom edge, which is what lets the
     fade below land there too.

     The mask fades both horizontal edges into the page, the same way
     .yn-p35-bg's mask does the left one. The stops are where they are
     because of what's actually in the frames — measured across the
     sequence rather than eyeballed: the logo frames keep their artwork
     inside 9.8%–98.9% of frame height (the photo frames fill the frame
     edge to edge, but they're photography, so fading into the page is
     the point). 8% and 90% sit just clear of the artwork, so the logo
     and the "YOUR NEIGHBOR / MEDICAL GROUP" wordmark never get eaten —
     only the empty backdrop above and the soft reflection below do.
     Percentages, not px, so those margins hold at every panel size
     instead of only the width they were measured at.

     A 1px black letterbox line used to sit on the top and bottom rows
     of every frame (left over from the intermediate v1/v2 were cut
     from) and read as a thin dark rule under the header; the v3 frames
     come straight off the master, which has none, so that is gone at
     the source rather than merely faded here.

     #fff→transparent, not #000, for the luminance reason noted on
     .yn-p35-bg's mask above. */
  .yn-p35-bg-img, .yn-p35-canvas {
    inset: 0 0 auto 0;
    height: auto;
    aspect-ratio: 16 / 9;
    -webkit-mask-image: linear-gradient(to bottom, transparent 0, #fff 8%, #fff 90%, transparent 100%);
    mask-image: linear-gradient(to bottom, transparent 0, #fff 8%, #fff 90%, transparent 100%);
  }
  /* Box is exactly the frames' own ratio here, so cover crops nothing —
     it matches drawCover()'s centred fill in app.jsx either way. */
  .yn-p35-bg-img { background-size: cover; background-position: 50% 50%; }
}

/* ── Phones: the same two blocks, stacked ──
   No pin down here (the min-width:768px query above doesn't apply), and
   deliberately so: a viewport can't hold the copy AND a 16:9 panel at
   once at this width, and forcing a pin would mean gutting the copy.
   Stacking keeps the rule that matters — text never sits on top of the
   animation — while letting each have its full width.

   Copy first, animation last, so the animation lands directly above
   <Marquee/> and the headline still greets you at the top. Hero()'s
   effect measures the panel's own travel across the viewport in this
   layout, so the sequence plays start-to-finish precisely while the
   block is on screen. */
@media (max-width: 767px) {
  .yn-p35 { display: flex; flex-direction: column; padding: 0; }
  /* Section padding is 0 so the panel can run edge to edge; the copy
     carries its own instead. */
  /* The glass logo photo sits behind the copy as a watermark — phones
     only, because this is the one layout where the copy has a band of
     its own with nothing else in it (>=768px the animation panel is
     already the right-hand column, and a second image behind the text
     there would just fight it).

     Two stacked backgrounds, order matters: the gradient is listed
     FIRST so it paints ON TOP of the photo (CSS stacks the first layer
     nearest the viewer), which is what turns the photo into a wash
     rather than a picture.

     The gradient is not a flat tint, and the reason is legibility, not
     taste. The copy block runs two very different contrast regimes down
     its length: the headline is 39px #0B4F94, which only needs 3:1 and
     has room to spare, while the four feature descriptions are 12px
     #5E6E82 — a colour that sits at just 5.21:1 on pure white, so it
     starts with almost nothing in hand against the 4.5:1 AA floor for
     small text. A single alpha that keeps those four legible would have
     bleached the photo out of the whole block.

     So the wash is light where the headline is (0.84–0.86) and ramps to
     0.96 by 44%, right as the feature list starts. Measured on the
     rendered page — screenshot the block with the text blanked, decode
     it to raw RGB and take the darkest pixel under each text box — that
     lands the four descriptions at 4.82–4.91:1 and the headline at
     6.15:1. The flat 0.88 tint this replaced measured 4.14–4.44:1 on
     those same four lines, i.e. it failed AA, which is not something
     the eye catches on a watermark this faint.

     50% 38% rather than dead centre: the logo mark sits in the upper
     half of the source frame, and 38% brings it up behind the headline
     — the half of the block that can carry it. */
  .yn-p35-grid {
    order: 1; margin: 0; padding: 2.25rem 1.15rem 2.25rem;
    background-image:
      linear-gradient(180deg, rgba(255, 255, 255, 0.84) 0%, rgba(255, 255, 255, 0.86) 24%, rgba(255, 255, 255, 0.96) 44%, rgba(255, 255, 255, 0.97) 100%),
      url("assets/hero-phone-logo.webp");
    background-size: cover, cover;
    background-position: 50% 50%, 50% 38%;
    background-repeat: no-repeat, no-repeat;
  }
  /* From absolute full-bleed layer (the base rule) to a plain block in
     the flow, so nothing overlaps.

     14:9 rather than the frames' native 16:9: at full phone width 16:9
     is only ~219px tall, which read as a thin strip. Going taller at a
     fixed width means `cover` zooms in and trims the sides — no
     stretching, so nothing is distorted, but content can fall off the
     edges. Scanning the sequence puts the limit at 3:2: the logo frames
     keep their artwork inside 12.8%–92% of frame width, and 3:2 trims
     7.8% per side, which leaves the "YOUR NEIGHBOR" wordmark's final R
     flush against the edge — intact, but close enough to read as cut.
     14:9 trims 6.25% instead, clearing that R by ~1.75% of the frame,
     and gives up only 8px of height for it. The photo frames run edge
     to edge, but they're photography, so trimming those is just
     framing. Worth ~15% more height than 16:9. */
  .yn-p35-bg {
    order: 2;
    position: relative;
    inset: auto;
    width: 100%;
    aspect-ratio: 14 / 9;
  }
  .yn-p35-bg-img { background-image: url("assets/hero-anim-sm/f0001.webp?v=3"); background-position: 50% 50%; }
  /* Left and right run to the screen edges, so only the horizontal
     edges need dissolving — same stops, and for the same measured
     reasons, as the ≥768px panel's. */
  .yn-p35-bg-img, .yn-p35-canvas {
    -webkit-mask-image: linear-gradient(to bottom, transparent 0, #fff 8%, #fff 90%, transparent 100%);
    mask-image: linear-gradient(to bottom, transparent 0, #fff 8%, #fff 90%, transparent 100%);
  }
}

/* Fixed hex, not theme tokens, throughout this copy block: --navy-700,
   --text-strong etc. have real dark-mode overrides, but those are tuned
   for text sitting on the PAGE's own theme-following background (which
   goes dark navy in dark mode) — this copy sits on the hero animation
   frames instead, fixed light images that never change with theme, so
   it needs colors that stay fixed too. Confirmed via dark-mode
   screenshot (back when this was still Hero1.png, same light-image
   situation): with the
   theme tokens, --navy-700's dark-mode value (a light sky blue, meant
   for light-on-dark-navy-page contrast) landed on this same light image
   and the headline nearly disappeared. Values below are each token's
   own light-mode hex (tokens/colors.css), pinned unconditionally. */
.yn-p35-h1 {
  font-family: var(--font-display);
  font-weight: 500;
  line-height: 1.08;
  color: #0B4F94;
  margin: 0 0 1.25rem;
  /* Larger ceiling (was 3.6rem) now that the hero is a full 100vh box
     above ~640px (see .yn-p35's min-width:641px rule) instead of
     whatever height the copy column happened to need — the old size
     read as small and disconnected in that much more room. */
  font-size: clamp(2.4rem, 1.7rem + 3vw, 4.1rem);
}
.yn-p35-h1 span { display: block; }
.yn-p35-sub { font-size: 1.15rem; color: #142033; line-height: 1.6; margin: 0 0 2.25rem; max-width: 40ch; }

.yn-p35-features {
  display: grid;
  /* Single column, not 2: the narrower ~520px copy column (above
     ~640px — see .yn-p35-copy's min-width:641px rule) left two columns
     squeezed to ~250px each, tight for an icon + two lines of label.
     One column also reads cleaner and fills the taller hero's vertical
     rhythm better than a cramped 2×2 block. */
  grid-template-columns: 1fr;
  gap: 1rem;
  margin-bottom: 2.5rem;
}
.yn-p35-feature { display: flex; align-items: flex-start; gap: 0.75rem; }
.yn-p35-feature-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  flex-shrink: 0;
  border-radius: var(--radius-md);
  background: #E8F3FC;
  color: #0B4F94;
}
.yn-p35-feature strong { display: block; font-size: var(--text-sm); font-weight: 700; color: #101B2B; margin-bottom: 2px; }
.yn-p35-feature span { display: block; font-size: var(--text-xs); color: #5E6E82; line-height: 1.4; }

.yn-p35-buttons { display: flex; gap: 14px; flex-wrap: wrap; }

/* The mockup's small floating "trusted by our community" rating card
   used to live here (.yn-p35-rating-card/-top/-row/-sub/-icon, plus its
   own phone overrides) — removed on request along with its markup in
   Hero(). */

@media (max-width: 560px) {
  .yn-p35-buttons { flex-direction: column; }
  /* !important: Button.jsx sets width inline ("auto" unless the `block`
     prop is passed). */
  .yn-p35-buttons > a { width: 100% !important; }
}
/* Photo-only hero (About Us): same .yn-hero-photo-box/-img classes the
   homepage hero uses — same breakout mechanics, same min-height floor
   at each breakpoint — but with no .yn-hero-content inside driving extra
   height from its padding. That's exactly why the homepage's own
   700px rule above sets min-height:0 (its box gets all the height it
   needs from the content padding instead); this page has no such
   content to fall back on, so it needs its own floor restored at that
   width instead of collapsing to 0. */
.yn-hero-photo-only { min-height: clamp(420px, 25vw, 900px); }
@media (max-width: 1100px) and (min-width: 701px) {
  .yn-hero-photo-only { min-height: clamp(400px, 52vw, 620px); }
}
@media (max-width: 700px) {
  .yn-hero-photo-only { min-height: clamp(320px, 62vw, 460px); }
}
/* Both scrims on About's photo-only hero, lightened three times over
   three follow-up requests, each off the PRIOR result, not the
   original: 15% (× 0.85), then 20% (× 0.80), then 25% (× 0.75) —
   0.85 × 0.80 × 0.75 = 0.51. Applied as an opacity multiplier on the
   layers rather than hand-editing every stop in both gradients so the
   two stay proportionally identical to their originals. Scoped to
   .yn-hero-photo-only so the homepage's single left-side scrim (still
   calibrated for text contrast, not just look) is untouched. */
.yn-hero-photo-only .yn-hero-scrim,
.yn-hero-photo-only .yn-hero-scrim-right {
  opacity: 0.51;
}
/* Both edge scrims fade over ~1300px each — fine on a wide desktop
   photo where that's a fraction of the width, but under ~900px the two
   fades overlap across the ENTIRE box (every pixel is within 1300px of
   BOTH edges at once), and two ~0.8-alpha navy layers stacked on each
   other compound to near-total opacity — confirmed on a 390px phone:
   the team photo all but disappeared under a solid navy block. Scoped
   to .yn-hero-photo-only (About's photo-only hero) so this doesn't
   touch the homepage's single left-side scrim, which doesn't have this
   compounding problem. Dialing each layer's own opacity down further
   still (rather than rewriting their gradient stops per breakpoint)
   keeps both edges still visibly darker than the center — the framing
   effect that was asked for — without the double-layered blackout.
   0.26 here (not the 0.51 above) is that same doubling fix carried
   forward at the current baseline: 0.5 × 0.51. */
@media (max-width: 900px) {
  .yn-hero-photo-only .yn-hero-scrim,
  .yn-hero-photo-only .yn-hero-scrim-right {
    opacity: 0.26;
  }
}
@media (prefers-reduced-motion: reduce) {
  .yn-marquee, .yn-wa { animation: none; }
  html { scroll-behavior: auto; }
}
/* Nav links — 4px underline in the primary colour, pinned to the very
   bottom of the nav bar, revealed left→right on hover. */
.yn-navlinks .yn-navlink {
  position: relative;
  display: inline-flex;
  align-items: center;
  height: 62px;               /* match the glass island height */
  padding: 0 0.85rem;
  font-size: var(--text-sm);
  font-weight: 500;
  color: var(--text-body);
  transition: color 300ms cubic-bezier(.2,.8,.2,1);
}
.yn-navlinks .yn-navlink:hover { color: var(--color-primary); }
/* Floating rounded underline, inset from the text so it reads cleanly
   inside the rounded glass pill (never touches the island's edge). */
.yn-navlinks .yn-navlink::after {
  content: "";
  position: absolute;
  left: 0.85rem; right: 0.85rem; bottom: 11px;
  height: 3px;
  border-radius: 3px;
  background: var(--color-primary);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 300ms cubic-bezier(.2,.8,.2,1);
}
.yn-navlinks .yn-navlink:hover::after,
.yn-hasdd:hover .yn-navlink::after { transform: scaleX(1); }

/* ── Hamburger button (mobile only) ── */
.yn-burger {
  display: none;
  align-items: center; justify-content: center;
  width: 44px; height: 44px;
  border: none; background: transparent;
  color: var(--text-strong); cursor: pointer;
  border-radius: var(--radius-sm);
  transition: background 200ms ease, color 200ms ease;
}
.yn-burger:hover { background: var(--navy-50); color: var(--color-primary); }

/* ── Dark-mode toggle button (always visible) ── */
.yn-theme-toggle {
  display: inline-flex; align-items: center; justify-content: center;
  width: 42px; height: 42px; flex: none;
  border: 1px solid var(--line);
  background: transparent;
  color: var(--navy-700);
  cursor: pointer;
  border-radius: var(--radius-pill);
  transition: background 250ms ease, color 250ms ease, border-color 250ms ease, transform 300ms cubic-bezier(.2,.8,.2,1);
}
.yn-theme-toggle:hover { background: var(--navy-50); color: var(--color-primary); border-color: var(--color-primary); }
.yn-theme-toggle:active { transform: scale(0.9); }
.yn-theme-icon { transition: transform 450ms cubic-bezier(.2,.8,.2,1); }
.yn-theme-toggle:hover .yn-theme-icon { transform: rotate(40deg); }

/* ── Language switch (EN / ES) — sits right of the dark-mode toggle ── */
.yn-lang-switch {
  position: relative;
  display: inline-flex; align-items: center;
  width: 76px; height: 42px; flex: none;
  padding: 3px;
  border: 1px solid var(--line);
  background: var(--surface-subtle);
  border-radius: var(--radius-pill);
  cursor: pointer;
  transition: border-color 250ms ease, transform 300ms cubic-bezier(.2,.8,.2,1);
}
.yn-lang-switch:hover { border-color: var(--color-primary); }
.yn-lang-switch:active { transform: scale(0.95); }
.yn-lang-thumb {
  position: absolute;
  top: 3px; left: 3px;
  width: 35px; height: 36px;
  background: var(--color-primary);
  border-radius: var(--radius-pill);
  box-shadow: var(--shadow-xs);
  transition: transform 300ms cubic-bezier(.2,.8,.2,1);
}
.yn-lang-switch[data-lang="es"] .yn-lang-thumb { transform: translateX(35px); }
.yn-lang-opt {
  position: relative; z-index: 1;
  width: 35px; text-align: center;
  font-family: var(--font-body);
  font-size: 0.68rem; font-weight: 700; letter-spacing: 0.03em;
  color: var(--text-muted);
  transition: color 300ms ease;
  pointer-events: none;
}
.yn-lang-switch[data-lang="en"] .yn-lang-opt[data-opt="en"],
.yn-lang-switch[data-lang="es"] .yn-lang-opt[data-opt="es"] { color: #fff; }

@media (max-width: 480px) {
  .yn-theme-toggle, .yn-burger { width: 38px; height: 38px; }
  .yn-lang-switch { width: 64px; height: 38px; }
  .yn-lang-thumb { width: 29px; height: 32px; }
  .yn-lang-switch[data-lang="es"] .yn-lang-thumb { transform: translateX(29px); }
  .yn-lang-opt { width: 29px; font-size: 0.6rem; }
}

/* ── Services dropdown (desktop mega-menu) ── */
.yn-hasdd { position: relative; display: inline-flex; align-items: center; height: 74px; }
.yn-hasdd .yn-navlink svg { transition: transform 250ms cubic-bezier(.2,.8,.2,1); }
.yn-hasdd:hover .yn-navlink svg { transform: rotate(180deg); }
.yn-dropdown {
  position: absolute;
  top: 100%; left: 50%;
  min-width: 460px; max-width: min(460px, 92vw);
  max-height: min(75vh, 560px);
  overflow-y: auto;
  padding: 0.55rem;
  background: var(--glass-panel);
  backdrop-filter: blur(18px) saturate(180%);
  -webkit-backdrop-filter: blur(18px) saturate(180%);
  border: 1px solid var(--line);
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow-xl);
  opacity: 0; visibility: hidden;
  transform: translate(-50%, 8px);
  transition: opacity 220ms ease, transform 220ms ease, visibility 220ms;
  z-index: 90;
}
.yn-hasdd:hover .yn-dropdown,
.yn-hasdd:focus-within .yn-dropdown,
.yn-hasdd.is-open .yn-dropdown {
  opacity: 1; visibility: visible; transform: translate(-50%, 0);
}
/* When opened by click, keep the chevron flipped like the hover state. */
.yn-hasdd.is-open .yn-navlink svg { transform: rotate(180deg); }
.yn-ddgrid { display: grid; grid-template-columns: 1fr 1fr; gap: 2px; }
.yn-dditem {
  display: flex; align-items: center; gap: 12px;
  padding: 0.6rem 0.7rem;
  border-radius: var(--radius-md);
  color: var(--text-strong);
  font-family: var(--font-body);
  font-size: var(--text-sm); font-weight: 500;
  transition: background 180ms ease, color 180ms ease;
}
.yn-dditem:hover { background: var(--navy-50); color: var(--color-primary); }
.yn-ddicon {
  display: inline-flex; align-items: center; justify-content: center;
  width: 34px; height: 34px; flex: none;
  border-radius: var(--radius-sm);
  background: var(--navy-50); color: var(--navy-700);
  transition: background 180ms ease, color 180ms ease;
}
.yn-dditem:hover .yn-ddicon { background: var(--color-primary); color: #fff; }
.yn-ddfoot {
  display: flex; align-items: center; justify-content: center; gap: 8px;
  margin-top: 6px; padding: 0.7rem;
  border-top: 1px solid var(--line);
  color: var(--color-primary); font-weight: 600; font-size: var(--text-sm);
  transition: color 180ms ease;
}
.yn-ddfoot:hover { color: var(--navy-900); }

/* ── Mobile slide-out sidebar ── */
.yn-scrim {
  position: fixed; inset: 0;
  background: var(--drawer-scrim);
  -webkit-backdrop-filter: blur(2px); backdrop-filter: blur(2px);
  opacity: 0; pointer-events: none;
  transition: opacity 300ms cubic-bezier(.2,.8,.2,1);
  z-index: 90;
}
.yn-scrim[data-open="true"] { opacity: 1; pointer-events: auto; }
.yn-drawer {
  position: fixed; top: 0; right: 0;
  height: 100%; width: min(82vw, 340px);
  display: flex; flex-direction: column;
  padding: 1.1rem 1.1rem 1.6rem;
  background: var(--glass-panel-strong);
  -webkit-backdrop-filter: blur(22px) saturate(180%); backdrop-filter: blur(22px) saturate(180%);
  border-left: 1px solid rgba(255,255,255,0.6);
  box-shadow: var(--shadow-xl);
  transform: translateX(105%);
  transition: transform 300ms cubic-bezier(.2,.8,.2,1);
  z-index: 100; overflow-y: auto;
}
.yn-drawer[data-open="true"] { transform: translateX(0); }
.yn-drawer-head {
  display: flex; align-items: center; justify-content: space-between;
  padding-bottom: 0.8rem; margin-bottom: 0.5rem;
  border-bottom: 1px solid var(--line);
}
.yn-drawer-links { display: flex; flex-direction: column; margin-bottom: 1rem; }
.yn-drawer-links a {
  display: flex; align-items: center; justify-content: space-between;
  padding: 0.95rem 0.35rem;
  font-family: var(--font-display); font-size: var(--text-lg); font-weight: 500;
  color: var(--text-strong);
  border-bottom: 1px solid var(--line);
  transition: color 200ms ease, padding-left 200ms ease;
}
.yn-drawer-links a svg { color: var(--navy-300); }
.yn-drawer-links a:hover { color: var(--color-primary); padding-left: 0.85rem; }

@media (prefers-reduced-motion: reduce) {
  .yn-navlinks .yn-navlink,
  .yn-navlinks .yn-navlink::after,
  .yn-dropdown, .yn-scrim, .yn-drawer, .yn-lang-thumb { transition: none; }
}

/* ═══════════ MOTION / "COME ALIVE" ═══════════ */

/* Page-load fade (opacity only → safe for fixed children) */
.yn-page { animation: yn-pagein .6s ease both; }
@keyframes yn-pagein { from { opacity: 0; } to { opacity: 1; } }

/* Scroll progress bar (top of viewport) */
.yn-progress {
  position: fixed; top: 0; left: 0; right: 0; height: 3px;
  transform: scaleX(0); transform-origin: 0 50%;
  background: var(--gradient-brand);
  z-index: 85; pointer-events: none;
  will-change: transform;
}

/* Dot-grid + grain texture: baked directly into each gradient-band
   section's own `background` (Team/Why Us in app.jsx, Reviews in
   shared.jsx — see DOTS_LAYER/GRAIN_LAYER/TEXTURE_LAYERS there), NOT a
   standalone class here. A fixed full-page overlay was tried first and
   reverted — at a z-index high enough to show over a section's own
   background, it also showed over that section's real content (hero
   photo, team photos, icons, even the nav bar), since plain overlay
   compositing can't tell "empty background" from "a photo" apart. See
   the comment above DOTS_LAYER in shared.jsx for the full writeup. */

/* Scroll-anchor offset for smooth in-page / cross-page navigation
   (applies to homepage <section id> AND services-page <div id> anchors) */
[id] { scroll-margin-top: 100px; }

/* Scroll reveal — elements fade + rise as they enter the viewport */
.reveal, .reveal-group {
  opacity: 0; transform: translateY(28px);
  transition: opacity .7s cubic-bezier(.2,.8,.2,1), transform .7s cubic-bezier(.2,.8,.2,1);
  will-change: opacity, transform;
}
.reveal.in, .reveal-group.in { opacity: 1; transform: none; }

/* Insurance "logos" marquee — auto-loop, sliding in and out */
.yn-logos {
  overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 7%, #000 93%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 7%, #000 93%, transparent);
}
.yn-logos-track {
  display: inline-flex; align-items: center; gap: 14px;
  width: max-content; padding: 4px 7px;
  /* Content is now "Primary Care" + its 8 plans, then "Mental Health" +
     its 17 plans (25 plan chips + 2 label chips = 27-item sequence),
     repeated 2x per set then doubled for the seamless -50% loop — see
     Insurance() in app.jsx. Measured: one raw 27-item sequence is
     ~4354px, so the 2x "set" the animation actually scrolls through
     (the -50% travel distance) is ~8708px — comfortably outsizes 4K
     widths. 207s holds the ~42px/s speed the old 10-generic-chip
     version scrolled at (8708px / 42px/s ≈ 207s). */
  animation: yn-marquee 207s linear infinite;
}
.yn-logos:hover .yn-logos-track { animation-play-state: paused; }
.yn-logo-chip {
  display: inline-flex; align-items: center; gap: 8.16px; white-space: nowrap;
  /* Sizes are the pre-2026-07-29 values *1.02 ("agranda un 2%"). */
  padding: 0.612rem 1.173rem;
  background: var(--surface); border: 1px solid var(--border-color);
  border-radius: var(--radius-pill); box-shadow: var(--shadow-xs);
  color: var(--text-strong); font-size: calc(var(--text-sm) * 1.02); font-weight: 600;
}
/* navy-50 (#E8F3FC) is the exact same hex as this section's own
   --surface-sky background, so a navy-50 chip was invisible against it
   — green-100 survives on hue alone (green vs. blue bg), but a same-hue
   blue chip needs an actual lightness jump to read as a chip at all.
   navy-300 gives that jump while staying a clear step lighter than the
   navy-700 label chips, preserving the label > chip > section-bg
   hierarchy. */
.yn-logo-chip[data-tone="sky"] { background: var(--navy-300); color: var(--navy-900); border-color: transparent; }
.yn-logo-chip[data-tone="green"] { background: var(--green-100); color: var(--green-700); border-color: transparent; }
.yn-logo-label {
  display: inline-flex; align-items: center; gap: 8.16px; white-space: nowrap;
  padding: 0.714rem 1.377rem;
  border-radius: var(--radius-pill); color: #fff;
  font-size: calc(var(--text-sm) * 1.02); font-weight: 800;
  letter-spacing: 0.01em;
}
/* Fixed (non-theme-reactive) hex, not var(--navy-700)/var(--green-600):
   these labels are a solid fill with white text on top, and both those
   tokens brighten in dark mode for a different job (foreground text ON
   a dark surface) — used as a background here they'd wash out the white
   text to ~2:1/3.55:1 (2026-07-31 audit). The literal light-mode shade
   already clears 4.5:1 and needs to stay put regardless of theme. */
.yn-logo-label[data-tone="sky"] { background: #0B4F94; }
.yn-logo-label[data-tone="green"] { background: #3F7A28; }

/* Services marquee — pause on hover */
.yn-marquee:hover { animation-play-state: paused; }

/* Shimmer — sweeping highlight for the promo badge */
.yn-shimmer { position: relative; overflow: hidden; }
.yn-shimmer::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(115deg, transparent 30%, rgba(255,255,255,0.85) 50%, transparent 70%);
  transform: translateX(-130%);
  animation: yn-shimmer 3s ease-in-out infinite;
}
@keyframes yn-shimmer { 0% { transform: translateX(-130%); } 55%, 100% { transform: translateX(130%); } }

@media (prefers-reduced-motion: reduce) {
  .reveal, .reveal-group { opacity: 1 !important; transform: none !important; transition: none !important; }
  .yn-page, .yn-logos-track, .yn-reviews-track, .yn-marquee, .yn-shimmer::after, .yn-hh-photo-img { animation: none !important; }
  .yn-shimmer::after { display: none; }
  .yn-progress { display: none; }
}

/* ═══════════ HOW IT WORKS / TESTIMONIALS / WAVES ═══════════ */

/* Wave section dividers (mental-health navy band) */
.yn-wave {
  position: absolute; left: 0; right: 0;
  height: 56px; pointer-events: none; overflow: hidden;
}
.yn-wave-top { top: -1px; }
.yn-wave-bottom { bottom: -1px; }
.yn-wave svg { display: block; width: 100%; height: 100%; }

/* 3-step "How It Works" cards */
.yn-step {
  position: relative;
  text-align: center;
  padding: 2rem 1.4rem 1.6rem;
  background: var(--surface);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-xs);
}
.yn-step-num {
  position: absolute; top: -15px; left: 50%; transform: translateX(-50%);
  width: 30px; height: 30px;
  display: flex; align-items: center; justify-content: center;
  background: linear-gradient(135deg, var(--gold-500), var(--gold-600));
  color: #fff; font-weight: 700; font-size: 0.85rem;
  border-radius: 50%;
  box-shadow: var(--shadow-sm);
}
/* Desktop: dotted connector between steps guides the eye left→right */
@media (min-width: 901px) {
  .yn-step:not(:last-child)::after {
    content: "";
    position: absolute; top: 50%; right: -19px;
    width: 20px; border-top: 2px dashed var(--line-strong);
  }
}

/* Google review stars (used by the badge link + each review card).
   gold-500, the original brand amber — briefly switched to gold-600 for
   WCAG contrast (gold-500 measures ~2:1 on white), but the user wants
   the original golden look back here specifically; reverted 2026-08-01.
   The rating is still conveyed to screen readers via the "5.0" text and
   each card's aria-label="5/5", so this is a purely visual tradeoff. */
.yn-stars {
  color: var(--gold-500);
  font-size: 1rem; letter-spacing: 3px;
}

/* "Write Your Review on Google" badge link, above the marquee. Idle
   state is the plain pill it always was; hover/focus lights up a soft
   chasing RGB ring in the actual Google "G" colors (same set as
   GoogleGIcon / the review-card accents below it) — an invitation to
   click, not a distraction at rest.

   The ring is drawn with the padding+mask "gradient border" technique
   (only the padding-width band around the pill is visible, the fill is
   masked out) rather than a blurred filled shape — a filled conic-
   gradient badly distorts on this pill's wide/short aspect ratio (most
   of the visible area falls in the narrow top/bottom angular slice vs.
   the wide left/right slice, reading as two hard color blobs instead of
   a smooth ring). The colors are animated by sliding a repeating
   linear-gradient via `background-position` (plain, universally-
   supported keyframe animation) rather than rotating a conic-gradient's
   angle — an earlier `@property`-registered custom-property version
   animated correctly for the first ~100ms then visibly froze (repro'd
   both visually and by sampling the computed custom property over time
   in a throwaway Playwright script), so don't reintroduce that approach
   without re-verifying it actually keeps animating past the first frame. */
.yn-google-badge {
  position: relative; isolation: isolate;
  display: inline-flex; align-items: center; gap: 8px;
  padding: 0.6rem 1.2rem;
  background: var(--surface); border: 1px solid var(--border-color);
  border-radius: var(--radius-pill); box-shadow: var(--shadow-xs);
  color: var(--text-strong); font-size: var(--text-sm); font-weight: 600;
  text-decoration: none;
  transition: box-shadow 300ms ease, transform 300ms ease;
}
.yn-google-badge .yn-stars { margin: 0; }
.yn-google-badge::before {
  content: ""; position: absolute; inset: -3px; z-index: -1;
  border-radius: inherit; padding: 3px;
  background: linear-gradient(90deg, #4285F4, #34A853, #FBBC05, #EA4335, #4285F4, #34A853, #FBBC05, #EA4335);
  background-size: 300% 100%;
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask-composite: exclude;
  filter: blur(3px);
  opacity: 0;
  transition: opacity 400ms ease;
}
.yn-google-badge:hover, .yn-google-badge:focus-visible {
  box-shadow: var(--shadow-md); transform: translateY(-1px);
}
.yn-google-badge:hover::before, .yn-google-badge:focus-visible::before {
  opacity: 1;
  animation: yn-rgb-slide 6s linear infinite;
}
/* Touch devices have no hover to trigger the ring with — a tap fires
   :hover, then it sticks until the visitor taps elsewhere or navigates
   away, so it reads as a random one-off flash rather than a feature.
   Keep it always on there instead of gating it behind a pointer event
   that doesn't really exist on a phone. */
@media (hover: none) {
  .yn-google-badge::before {
    opacity: 1;
    animation: yn-rgb-slide 6s linear infinite;
  }
}
@keyframes yn-rgb-slide { to { background-position: -300% 0%; } }
@media (prefers-reduced-motion: reduce) {
  .yn-google-badge::before { animation: none !important; }
}

/* Google reviews marquee — same auto-loop, mask-faded-edge technique as
   the insurance logos marquee (.yn-logos), see Reviews() in shared.jsx
   and .yn-logos-track above for the loop math this mirrors. */
.yn-reviews {
  overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 7%, #000 93%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 7%, #000 93%, transparent);
}
.yn-reviews-track {
  display: inline-flex; align-items: stretch; gap: 18px;
  width: max-content; padding: 4px 7px;
  /* 10 real reviews doubled per "set" then doubled again for the -50%
     loop (same 4x pattern as .yn-logos-track). Measured via a throwaway
     Playwright script: one raw 10-card sequence ≈ 3840px at the 340px
     card width below, so the 2x "set" the animation travels ≈ 7680px.
     140s ≈ the ~55px/s a reader can comfortably scan card text at
     (slower than the terser insurance chips, since these have full
     sentences to read) — re-measure if the review count/card width
     changes. */
  animation: yn-marquee 140s linear infinite;
}
.yn-reviews:hover .yn-reviews-track { animation-play-state: paused; }
.yn-review-card {
  position: relative; overflow: hidden;
  margin: 0; flex: none; width: 340px;
  padding: 1.5rem 1.4rem;
  background: var(--surface); border: 1px solid var(--border-color);
  border-top: 3px solid var(--review-accent, var(--gold-500));
  border-radius: var(--radius-lg); box-shadow: var(--shadow-xs);
  display: flex; flex-direction: column; gap: 0.9rem;
}
.yn-review-card[data-tone="gold"] { --review-accent: var(--gold-500); }
.yn-review-card[data-tone="sky"] { --review-accent: var(--navy-500); }
.yn-review-card[data-tone="green"] { --review-accent: var(--green-600); }
/* Large decorative opening quote — purely typographic, not tied to any
   reviewer's identity — gives each card some warmth/personality without
   a photo standing in for someone it isn't. */
.yn-review-quote {
  position: absolute; top: -0.4rem; right: 0.7rem;
  font-family: var(--font-display); font-size: 4.5rem; line-height: 1;
  color: var(--review-accent, var(--gold-500)); opacity: 0.14;
  pointer-events: none; user-select: none;
}
.yn-review-top { display: flex; align-items: center; gap: 12px; z-index: 1; }
/* The real Google mark (GoogleGIcon in shared.jsx), not a photo — see
   Reviews() there for why: pairing a real or fabricated face with a real
   reviewer's real name would misrepresent them, so every card attributes
   the quote to its actual source instead. */
.yn-review-avatar {
  flex: none; width: 40px; height: 40px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: #fff; border: 1px solid var(--border-color); box-shadow: var(--shadow-xs);
}
.yn-review-who { display: flex; flex-direction: column; gap: 2px; z-index: 1; }
.yn-review-who strong { font-size: var(--text-sm); color: var(--text-strong); }
.yn-review-who .yn-stars { font-size: 0.8rem; }
.yn-review-card blockquote {
  position: relative; z-index: 1;
  margin: 0; font-size: var(--text-sm); line-height: 1.6;
  color: var(--text-body);
  display: -webkit-box; -webkit-line-clamp: 5; -webkit-box-orient: vertical;
  overflow: hidden;
}

/* Google Maps teaser (Contact section, third column) — the iframe is
   pointer-events:none purely decorative (its own pan/zoom would trap
   scroll and fight the outer link); the surrounding <a> is the actual
   tap target for the whole card, taking visitors to Google Maps. Height
   is set per-usage (inline style) rather than here — the Contact section
   stretches it to match the form card's height via grid. */
.yn-map-teaser {
  position: relative; display: block;
  border-radius: var(--radius-lg); overflow: hidden;
  border: 1px solid var(--border-color); box-shadow: var(--shadow-xs);
  /* Quiet by default so it doesn't compete with the form's Button for
     attention; sharpens up to full opacity on hover/focus as an
     invitation to explore, without needing that attention up front. */
  opacity: 0.6;
  transition: opacity 250ms ease;
}
.yn-map-teaser:hover, .yn-map-teaser:focus-visible {
  opacity: 1;
}
.yn-map-teaser iframe {
  position: absolute; inset: 0; width: 100%; height: 100%; border: 0;
  pointer-events: none;
}
.yn-map-teaser::after {
  content: ""; position: absolute; inset: 0;
  background: rgba(11,79,148,0); transition: background 200ms ease;
}
.yn-map-teaser:hover::after { background: rgba(11,79,148,0.08); }

/* Team cards ("Nuestro Equipo") */
.yn-member {
  margin: 0;
  background: var(--surface);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-lg);
  overflow: hidden;
  box-shadow: var(--shadow-xs);
}
.yn-member img { width: 100%; aspect-ratio: 3 / 4; object-fit: cover; display: block; }
.yn-member figcaption { padding: 1rem 1.15rem 1.2rem; display: flex; flex-direction: column; gap: 4px; }
.yn-member strong { color: var(--text-strong); font-size: var(--text-base); }
.yn-member span { color: var(--text-muted); font-size: var(--text-sm); line-height: 1.5; }

/* About: Core Values grid */
.yn-valuesgrid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 18px; }
@media (max-width: 900px) { .yn-valuesgrid { grid-template-columns: repeat(2, 1fr); } }

/* Why Us page: stats band (4 numbers) */
@media (max-width: 700px) { .yn-whystats { grid-template-columns: repeat(2, 1fr) !important; gap: 24px 12px !important; } }

/* FAQ accordion (native <details>/<summary>) */
.yn-faq { display: flex; flex-direction: column; gap: 10px; }
.yn-faq-item {
  background: var(--surface);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-xs);
  overflow: hidden;
}
.yn-faq-item summary {
  display: flex; align-items: center; justify-content: space-between; gap: 14px;
  padding: 1.1rem 1.3rem;
  cursor: pointer; list-style: none;
  font-family: var(--font-body); font-weight: 600; font-size: var(--text-base);
  color: var(--text-strong);
  transition: color 200ms ease;
}
.yn-faq-item summary::-webkit-details-marker { display: none; }
.yn-faq-item summary:hover { color: var(--color-primary); }
.yn-faq-item summary svg { flex: none; color: var(--color-primary); transition: transform 300ms cubic-bezier(.2,.8,.2,1); }
.yn-faq-item[open] summary svg { transform: rotate(180deg); }
.yn-faq-answer { padding: 0 1.3rem 1.2rem; }
.yn-faq-answer p { margin: 0; font-size: var(--text-sm); line-height: 1.7; color: var(--text-body); }
.yn-faq-item[open] summary { color: var(--color-primary); }

/* Tablet: steps stack before they get cramped. Team keeps its 3-across
   row (three 4:5 portraits side by side) at every width — just tightens
   on phones (see the max-width:600px block). Reviews is a marquee, not a
   grid, so it needs no stacking override at any width. */
@media (max-width: 900px) {
  .yn-steps { grid-template-columns: 1fr !important; gap: 24px !important; }
  .yn-team { max-width: 100% !important; gap: 12px !important; }
  .yn-team4 { grid-template-columns: repeat(2, 1fr) !important; max-width: 640px !important; margin: 0 auto !important; gap: 16px !important; }
}

/* ═══════════ SERVICES PAGE ═══════════ */

.yn-svc-jump {
  display: flex; flex-wrap: wrap; gap: 8px;
  justify-content: center;
}
.yn-svc-jump a {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 0.5rem 0.95rem;
  background: var(--surface); border: 1px solid var(--border-color);
  border-radius: var(--radius-pill);
  color: var(--text-body); font-size: var(--text-sm); font-weight: 500;
  transition: background 200ms ease, color 200ms ease, border-color 200ms ease, transform 200ms ease;
}
.yn-svc-jump a:hover { background: var(--color-primary); color: #fff; border-color: var(--color-primary); transform: translateY(-2px); }

/* Three-across service cards: photo, then icon/title/description, then
   every sub-service as a compact chip (some services list 20-30 of
   them — a chip cloud wraps naturally instead of stretching the card
   into a mile-long checklist). */
.yn-svc-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 22px; }
/* 13 cards in 3 columns leaves one card alone on the last row, flush left
   with an empty gap beside it — center it under the middle column
   instead. :nth-child(3n+1) combined with :last-child only matches when
   the final card truly is alone (count % 3 === 1), so this self-adjusts
   if the service count ever changes to another 3n+1 total. */
.yn-svc-grid > *:last-child:nth-child(3n+1) { grid-column: 2; }

.yn-svc-card {
  display: flex; flex-direction: column;
  background: var(--surface); border: 1px solid var(--border-color);
  border-radius: var(--radius-lg); overflow: hidden; box-shadow: var(--shadow-xs);
  scroll-margin-top: 90px;
  transition: transform 300ms cubic-bezier(.2,.8,.2,1), box-shadow 300ms cubic-bezier(.2,.8,.2,1), border-color 300ms cubic-bezier(.2,.8,.2,1);
}
.yn-svc-card:hover { transform: translateY(-4px); box-shadow: var(--shadow-lg); border-color: var(--navy-100); }

.yn-svc-photo { width: 100%; aspect-ratio: 16 / 10; overflow: hidden; background: var(--surface-subtle); }
.yn-svc-photo img { width: 100%; height: 100%; object-fit: cover; display: block; transition: transform 400ms ease; }
.yn-svc-card:hover .yn-svc-photo img { transform: scale(1.045); }

.yn-svc-body { padding: 1.4rem 1.5rem 1.6rem; display: flex; flex-direction: column; flex: 1; }
.yn-svc-icontile { margin-bottom: 0.85rem; }
.yn-svc-body h3 { margin: 0 0 8px; font-family: var(--font-body); font-size: var(--text-lg); font-weight: 700; color: var(--text-strong); line-height: 1.3; }
.yn-svc-desc { margin: 0 0 1.1rem; font-size: var(--text-sm); color: var(--text-muted); line-height: 1.6; }
/* No opacity dampening: text-muted alone is already ~5.2:1 on white;
   the added 0.8 opacity (removed 2026-07-31) blended it down to 3.47:1,
   an AA fail, on all 13 service cards. */
.yn-svc-included { margin: 0 0 0.55rem; font-size: 0.72rem; font-weight: 700; letter-spacing: 0.07em; text-transform: uppercase; color: var(--text-muted); }

.yn-chipcloud { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 1.15rem; }
.yn-chip {
  display: inline-flex; align-items: center;
  padding: 0.32rem 0.65rem; border-radius: var(--radius-pill);
  font-size: 0.74rem; font-weight: 600; line-height: 1.3;
  background: var(--navy-50); color: var(--navy-700);
}
.yn-svc-card[data-tone="green"] .yn-chip { background: var(--green-100); color: var(--green-700); }
.yn-svc-card[data-tone="gold"] .yn-chip { background: var(--gold-100); color: var(--gold-600); }
.yn-svc-card .yn-inline-link { margin-top: auto; padding-top: 2px; }

@media (max-width: 1080px) {
  .yn-svc-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 640px) {
  .yn-svc-grid { grid-template-columns: 1fr; }
}

/* Small inline text link with the same sliding-underline motion as the nav */
.yn-inline-link {
  position: relative;
  display: inline-flex; align-items: center; gap: 4px;
  color: var(--color-primary); font-weight: 700; font-size: var(--text-sm);
  margin-top: 14px;
}
.yn-inline-link::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: -2px; height: 2px;
  background: var(--color-primary); transform: scaleX(0); transform-origin: left center;
  transition: transform 300ms cubic-bezier(.2,.8,.2,1);
}
.yn-inline-link:hover::after { transform: scaleX(1); }

@media (max-width: 640px) {
  .yn-svc-card { grid-template-columns: 1fr; }
}

/* ── Contact form — name/phone fields stack on phones; side by side
   they clip the label and truncate placeholder text (e.g. "786.250.344"). ── */
@media (max-width: 560px) {
  .yn-formrow { grid-template-columns: 1fr !important; }
}
