/* ============================================================
   MIRRAH IMAGE SERVICES — Global Styles
   Bold & Vibrant | ADA Compliant | WCAG 2.1 AA
   ============================================================ */

/* ---------- CSS Custom Properties ---------- */
:root {
  --purple:     #1273c2;
  --purple-dark:#0c447c;
  --purple-light:#cfe0f2;
  --orange:     #F97316;
  --orange-dark:#C2410C;
  --teal:       #06B6D4;
  --teal-dark:  #0E7490;
  --indigo:     #080a7d;
  --emerald:    #10B981;
  --pink:       #EC4899;
  --white:      #FFFFFF;
  --off-white:  #F8FAFC;
  --gray-50:    #F9FAFB;
  --gray-100:   #F3F4F6;
  --gray-200:   #E5E7EB;
  /* 2026-08-07. These three were referenced across the site and defined nowhere, so every
     declaration using them was simply invalid and the text fell back to the inherited body color,
     which happened to pass contrast by luck. Values below are measured against white, against
     --gray-50 (#F9FAFB) and against the lightest card and banner backgrounds they actually sit on:
       --gray-300  4.70:1 on white
       --gray-500  5.98:1 on white, 5.72:1 on --gray-50
       --gray-700 10.31:1 on white, 9.00:1 on the palest end of the portal demo banner
     --gray-300 is deliberately NOT a light 300 step. Its only live use is text, and no color light
     enough to read as a 300 clears 4.5:1, so it is the lightest point on the 200 to 400 line that
     does. That is the same compromise already made on --gray-400, which sits a step darker than
     the ramp it came from for exactly this reason. */
  --gray-300:   #6D7482;
  --gray-400:   #6b7280;
  --gray-500:   #5B6472;
  --gray-600:   #4B5563;
  --gray-700:   #374151;
  --gray-800:   #1F2937;
  --gray-900:   #111827;

  --font-heading: 'Poppins', sans-serif;
  --font-body:    'Inter', sans-serif;

  --radius-sm:  0.375rem;
  --radius-md:  0.75rem;
  --radius-lg:  1.25rem;
  --radius-xl:  2rem;

  --shadow-sm:  0 1px 3px rgba(0,0,0,.10), 0 1px 2px rgba(0,0,0,.06);
  --shadow-md:  0 4px 16px rgba(0,0,0,.10);
  --shadow-lg:  0 10px 40px rgba(0,0,0,.15);
  --shadow-xl:  0 20px 60px rgba(0,0,0,.20);
  --shadow-glow-purple: 0 0 40px rgba(18,115,194,.35);
  --shadow-glow-orange: 0 0 40px rgba(249,115,22,.35);
  --shadow-glow-teal:   0 0 40px rgba(6,182,212,.35);

  --transition: 0.3s cubic-bezier(.4,0,.2,1);
  --transition-slow: 0.6s cubic-bezier(.4,0,.2,1);
}

/* ---------- Reset & Base ---------- */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

html {
  scroll-behavior: smooth;
  /* Offset anchor jumps so targeted sections aren't hidden behind the fixed navbar */
  scroll-padding-top: 90px;
  font-size: 16px;
}
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
}

body {
  font-family: var(--font-body);
  color: var(--gray-800);
  background: var(--white);
  line-height: 1.6;
  overflow-x: hidden;
}

img, video { max-width: 100%; height: auto; display: block; }
a { color: inherit; text-decoration: none; }
ul { list-style: none; }
button { cursor: pointer; border: none; background: none; font-family: inherit; }

/* ---------- ADA: Skip Link ---------- */
.skip-link {
  position: absolute;
  top: -100%;
  left: 1rem;
  background: var(--purple);
  color: var(--white);
  padding: .75rem 1.5rem;
  border-radius: var(--radius-md);
  font-weight: 700;
  z-index: 9999;
  transition: top var(--transition);
}
.skip-link:focus { top: 1rem; }

/* ---------- ADA: Focus Styles ---------- */
/* ⭐⭐ 18 August 2026 audit — THE FOCUS RING FAILED WCAG ON EVERY LIGHT PAGE.
   WHAT WAS OPEN. --orange (#F97316) against white is 2.80:1, and against the page grey and the cream
   letter section it is worse (2.68 and 2.65). WCAG 2.1 SC 1.4.11 asks for 3:1 on a focus indicator.
   This is the GLOBAL rule, so it was every link, every input, every page — for the people who navigate
   this site by keyboard, on a site that sells its accessibility on its own Accessibility page.
   WHY NOT JUST DARKEN IT. --orange-dark is 5.18:1 on white and still 3.80:1 on the dark navy hero, so
   it is better on BOTH — but neither orange works on the brand blue (1.76:1 and 1.05:1), and buttons
   are blue. One colour cannot pass against white AND against blue.
   WHAT IT DOES NOW. Two tones. The white halo sits in the gap the outline-offset already leaves, so on
   a dark or blue background the WHITE ring is what you see, and on a light background the dark orange
   is. There is no background this disappears against. Nothing moves: the halo fills a gap that was
   already there, so no layout shifts. */
:focus-visible {
  outline: 3px solid var(--orange-dark);
  outline-offset: 3px;
  border-radius: 3px;
  box-shadow: 0 0 0 3px rgba(255,255,255,.95);
}

/* ---------- Typography ---------- */
h1,h2,h3,h4,h5,h6 {
  font-family: var(--font-heading);
  font-weight: 700;
  line-height: 1.2;
  color: var(--indigo);
}
h1 { font-size: clamp(2.2rem, 5vw, 4rem); }
h2 { font-size: clamp(1.8rem, 3.5vw, 2.75rem); }
h3 { font-size: clamp(1.3rem, 2.5vw, 1.75rem); }
h4 { font-size: 1.25rem; }
p  { color: var(--gray-600); line-height: 1.75; }

/* ---------- Layout ---------- */
.container {
  max-width: 1200px;
  margin: 0 auto;
  padding: 0 1.5rem;
}
.container--wide { max-width: 1400px; margin: 0 auto; padding: 0 1.5rem; }
.section { padding: 5rem 0; }
.section--sm { padding: 3rem 0; }
.section-header { text-align: center; margin-bottom: 3.5rem; }
.section-header p { max-width: 620px; margin: 1rem auto 0; font-size: 1.1rem; }

/* ---------- Gradient Text ---------- */
.gradient-text {
  background: linear-gradient(135deg, var(--purple), var(--orange));
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
}
.gradient-text--teal {
  background: linear-gradient(135deg, var(--teal), var(--emerald));
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
}

/* ---------- Buttons ---------- */
.btn {
  display: inline-flex;
  align-items: center;
  gap: .5rem;
  padding: .85rem 2rem;
  border-radius: 50px;
  font-family: var(--font-heading);
  font-weight: 600;
  font-size: 1rem;
  transition: all var(--transition);
  cursor: pointer;
  border: 2px solid transparent;
  text-decoration: none;
  white-space: nowrap;
}
.btn--primary {
  background: linear-gradient(135deg, var(--purple), var(--purple-dark));
  color: var(--white);
  box-shadow: 0 4px 20px rgba(18,115,194,.4);
}
.btn--primary:hover {
  transform: translateY(-2px);
  box-shadow: 0 8px 30px rgba(18,115,194,.5);
}
/* BLUE, NOT ORANGE, 23 Oct 2026, Jen: "Make the button blue, not orange, and dark blue." The class
   keeps its old name so no page has to change. The fill is the brand blue (white text 4.93:1) and it
   turns navy on hover (white text 17:1). These buttons mostly sit on the dark navy banners, so the
   light ring keeps the edge visible there and the navy hover never melts into the banner.
   On a blue box use .btn--on-blue (white, navy text). Beside another blue button use .btn--navy.
   Checked by test-suites/text-contrast-passes-test.mjs. */
.btn--orange {
  background: var(--purple);
  color: var(--white);
  border-color: rgba(255,255,255,.85);
  box-shadow: 0 4px 20px rgba(18,115,194,.4);
}
.btn--orange:hover {
  background: var(--indigo);
  transform: translateY(-2px);
  box-shadow: 0 8px 30px rgba(18,115,194,.5);
}
.btn--orange.btn--navy { background: var(--indigo); border-color: var(--indigo); }
.btn--orange.btn--navy:hover { background: var(--purple); border-color: var(--purple); }
.btn--orange.btn--on-blue { background: var(--white); color: var(--indigo); border-color: var(--white); }
.btn--orange.btn--on-blue:hover { background: var(--purple-light); color: var(--indigo); border-color: var(--purple-light); }
.btn--teal {
  background: linear-gradient(135deg, var(--teal-dark), #155E75);
  color: var(--white);
  box-shadow: 0 4px 20px rgba(6,182,212,.4);
}
.btn--teal:hover { transform: translateY(-2px); box-shadow: 0 8px 30px rgba(6,182,212,.5); }
.btn--outline {
  background: transparent;
  color: var(--purple);
  border-color: var(--purple);
}
.btn--outline:hover { background: var(--purple); color: var(--white); }
.btn--outline-white {
  background: transparent;
  color: var(--white);
  border-color: rgba(255,255,255,.6);
}
.btn--outline-white:hover { background: rgba(255,255,255,.15); }
.btn--lg { padding: 1.1rem 2.5rem; font-size: 1.1rem; }
.btn--sm { padding: .55rem 1.25rem; font-size: .9rem; }

/* ---------- Cards ---------- */
.card {
  background: var(--white);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-md);
  overflow: hidden;
  transition: transform var(--transition), box-shadow var(--transition);
}
.card:hover { transform: translateY(-6px); box-shadow: var(--shadow-xl); }
.card__body { padding: 2rem; }
.card__icon {
  width: 64px;
  height: 64px;
  border-radius: var(--radius-md);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.75rem;
  margin-bottom: 1.25rem;
}

/* ---------- Badges ---------- */
.badge {
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  padding: .35rem 1rem;
  border-radius: 50px;
  font-size: .8rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .05em;
}
.badge--purple { background: var(--purple-light); color: var(--purple-dark); }
/* ⭐ #9A3412 rather than --orange-dark (#C2410C): the brand orange on its own pale tint is
   3.9:1, and this badge is small bold text. One shade darker clears AA. 3 Aug 2026. */
.badge--orange { background: #FFEDD5; color: #9A3412; }
.badge--teal   { background: #CFFAFE; color: var(--teal-dark); }
.badge--emerald{ background: #D1FAE5; color: #065F46; }

/* ---------- Navigation ---------- */
.navbar {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 1000;
  transition: all var(--transition);
  padding: 1.25rem 0;
}
.navbar--scrolled {
  background: rgba(255,255,255,.96);
  backdrop-filter: blur(12px);
  box-shadow: var(--shadow-md);
  padding: .75rem 0;
}
.navbar__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 2rem;
}
.navbar__logo {
  display: flex;
  align-items: center;
  gap: .75rem;
  font-family: var(--font-heading);
  font-weight: 800;
  font-size: 1.4rem;
  color: var(--white);
  transition: color var(--transition);
}
.navbar--scrolled .navbar__logo { color: var(--indigo); }
.navbar__logo-icon {
  width: 44px;
  height: 44px;
  background: linear-gradient(135deg, var(--purple), var(--orange));
  border-radius: var(--radius-md);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.3rem;
  flex-shrink: 0;
}
.navbar__nav {
  display: flex;
  align-items: center;
  gap: .25rem;
}
.navbar__link {
  padding: .5rem 1rem;
  border-radius: var(--radius-sm);
  font-weight: 500;
  color: rgba(255,255,255,.9);
  transition: all var(--transition);
  font-size: .95rem;
}
.navbar--scrolled .navbar__link { color: var(--gray-700); }
.navbar__link:hover,
.navbar__link--active {
  background: rgba(255,255,255,.15);
  color: var(--white);
}
/* CONTRAST, 23 Oct 2026. The brand blue on its pale tint is 3.66:1; the navy is 9.6:1. The blue
   itself is untouched; only the text on the tint moves to the brand navy. */
.navbar--scrolled .navbar__link:hover {
  background: var(--purple-light);
  color: var(--indigo);
}
.navbar__link--active {
  color: var(--white) !important;
  background: rgba(255,255,255,.2) !important;
}
.navbar--scrolled .navbar__link--active {
  color: var(--indigo) !important;
  background: var(--purple-light) !important;
}
.navbar__actions { display: flex; align-items: center; gap: .75rem; }
.navbar__phone {
  white-space: nowrap;
  font-weight: 700;
  color: rgba(255,255,255,.9);
  font-size: .9rem;
  display: flex;
  align-items: center;
  gap: .4rem;
  transition: color var(--transition);
}
.navbar--scrolled .navbar__phone { color: var(--gray-700); }
/* 23 Oct 2026, Jen: "Make the button blue, not orange, and dark blue." Brand blue fill, navy on hover.
   The navbar starts over the dark hero and over the blue page header, so a white ring keeps the
   button's edge visible on both; on the white scrolled bar the ring is not needed. */
.navbar__portal-btn {
  white-space: nowrap;
  background: var(--purple);
  border: 2px solid rgba(255,255,255,.9);
  color: var(--white) !important;
  padding: .55rem 1.25rem;
  border-radius: 50px;
  font-weight: 700;
  font-size: .9rem;
  display: flex;
  align-items: center;
  gap: .4rem;
  transition: all var(--transition);
  box-shadow: 0 2px 10px rgba(18,115,194,.4);
}
.navbar__portal-btn:hover { background: var(--indigo); transform: translateY(-1px); box-shadow: 0 4px 16px rgba(18,115,194,.5); }
.navbar--scrolled .navbar__portal-btn { border-color: var(--purple); }
.navbar--scrolled .navbar__portal-btn:hover { border-color: var(--indigo); }

/* Hamburger */
.navbar__hamburger {
  display: none;
  flex-direction: column;
  gap: 5px;
  width: 30px;
  cursor: pointer;
  padding: 4px;
  background: none;
  border: none;
}
.navbar__hamburger span {
  display: block;
  height: 2px;
  background: var(--white);
  border-radius: 2px;
  transition: all var(--transition);
}
.navbar--scrolled .navbar__hamburger span { background: var(--indigo); }
.navbar__hamburger.open span:nth-child(1) { transform: rotate(45deg) translate(5px,5px); }
.navbar__hamburger.open span:nth-child(2) { opacity: 0; }
.navbar__hamburger.open span:nth-child(3) { transform: rotate(-45deg) translate(5px,-5px); }

.navbar__mobile {
  display: none;
  flex-direction: column;
  background: var(--white);
  border-top: 1px solid var(--gray-200);
  padding: 1rem 0;
}
.navbar__mobile.open { display: flex; }
.navbar__mobile .navbar__link {
  color: var(--gray-700);
  padding: .75rem 1.5rem;
  border-radius: 0;
}
.navbar__mobile .navbar__link:hover { background: var(--purple-light); color: var(--indigo); }

/* ---------- Hero ---------- */
.hero {
  position: relative;
  min-height: 100vh;
  display: flex;
  align-items: center;
  overflow: hidden;
  background: linear-gradient(135deg, var(--indigo) 0%, #0c447c 40%, #08325c 70%, #1273c2 100%);
}
.hero__canvas {
  position: absolute;
  inset: 0;
  opacity: .4;
}
.hero__blobs {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
}
.hero__blob {
  position: absolute;
  border-radius: 50%;
  filter: blur(80px);
  opacity: .5;
  animation: blobFloat 8s ease-in-out infinite;
}
.hero__blob--1 {
  width: 500px; height: 500px;
  background: radial-gradient(circle, var(--orange), transparent);
  top: -100px; right: -100px;
  animation-delay: 0s;
}
.hero__blob--2 {
  width: 400px; height: 400px;
  background: radial-gradient(circle, var(--teal), transparent);
  bottom: -80px; left: 10%;
  animation-delay: 3s;
}
.hero__blob--3 {
  width: 300px; height: 300px;
  background: radial-gradient(circle, var(--pink), transparent);
  top: 30%; left: 60%;
  animation-delay: 6s;
}
@keyframes blobFloat {
  0%,100% { transform: translate(0,0) scale(1); }
  33%      { transform: translate(20px,-20px) scale(1.05); }
  66%      { transform: translate(-10px,15px) scale(.95); }
}

.hero__particles {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

.hero__content {
  position: relative;
  z-index: 2;
  width: 100%;
  padding-top: 6rem;
}
.hero__grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 4rem;
  align-items: center;
}
.hero__badge { margin-bottom: 1.5rem; display: flex; align-items: center; gap: .5rem; }
.hero__badge-dot {
  width: 8px; height: 8px;
  background: var(--emerald);
  border-radius: 50%;
  animation: pulse-dot 2s ease-in-out infinite;
}
@keyframes pulse-dot {
  0%,100% { box-shadow: 0 0 0 0 rgba(16,185,129,.7); }
  50%      { box-shadow: 0 0 0 8px rgba(16,185,129,0); }
}
/* CONTRAST, 23 Oct 2026. This badge sits on the dark .hero, so a DARKER emerald would read worse,
   not better (#047857 is 3.0:1 on the navy). A pale emerald clears 4.5:1 on every stop of the
   hero gradient the left column covers (navy, #0c447c, #08325c). */
.hero__badge-text { color: #A7F3D0; font-weight: 600; font-size: .9rem; }

.hero__title { color: var(--white); margin-bottom: 1.5rem; }
.hero__title span {
  background: linear-gradient(135deg, var(--orange), #FCD34D);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
}
.hero__desc { color: rgba(255,255,255,.8); font-size: 1.15rem; margin-bottom: 2.5rem; max-width: 520px; }
.hero__actions { display: flex; gap: 1rem; flex-wrap: wrap; margin-bottom: 3rem; }
.hero__stats { display: flex; gap: 2.5rem; flex-wrap: wrap; }
.hero__stat-value {
  font-family: var(--font-heading);
  font-size: 2rem;
  font-weight: 800;
  color: var(--white);
  display: block;
}
.hero__stat-label { color: rgba(255,255,255,.65); font-size: .85rem; }

.hero__visual {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
}
.hero__cards-stack {
  position: relative;
  width: 100%;
  max-width: 460px;
}
.hero__float-card {
  background: rgba(255,255,255,.1);
  backdrop-filter: blur(16px);
  border: 1px solid rgba(255,255,255,.2);
  border-radius: var(--radius-lg);
  padding: 1.5rem;
  animation: floatCard 6s ease-in-out infinite;
}
.hero__float-card--main { animation-delay: 0s; }
.hero__float-card--sm {
  position: absolute;
  animation-delay: 2s;
  padding: 1rem 1.25rem;
  border-radius: var(--radius-md);
  display: flex;
  align-items: center;
  gap: .75rem;
}
.hero__float-card--sm1 { bottom: -2rem; left: -2rem; animation-delay: 1s; }
.hero__float-card--sm2 { top: -1.5rem; right: -1.5rem; animation-delay: 3s; }
@keyframes floatCard {
  0%,100% { transform: translateY(0); }
  50%      { transform: translateY(-12px); }
}
.hero__float-card-icon { font-size: 2.5rem; margin-bottom: .75rem; }
.hero__float-card h4 { color: var(--white); font-size: 1.1rem; margin-bottom: .25rem; }
.hero__float-card p  { color: rgba(255,255,255,.7); font-size: .85rem; margin: 0; }
.hero__float-card--sm .hero__float-icon { font-size: 1.75rem; }
.hero__float-card--sm .hero__float-text { font-weight: 700; color: var(--white); font-size: .9rem; }
.hero__float-card--sm .hero__float-sub  { color: rgba(255,255,255,.7); font-size: .75rem; }

/* ---------- Services Section ---------- */
.services-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(320px,1fr));
  gap: 1.75rem;
}
.service-card {
  background: var(--white);
  border-radius: var(--radius-lg);
  padding: 2rem;
  border: 2px solid transparent;
  box-shadow: var(--shadow-md);
  transition: all var(--transition);
  position: relative;
  overflow: hidden;
}
.service-card::before {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(135deg, var(--purple), var(--teal));
  opacity: 0;
  transition: opacity var(--transition);
  z-index: 0;
}
.service-card:hover::before { opacity: 1; }
.service-card:hover { transform: translateY(-8px); box-shadow: var(--shadow-xl); }
.service-card:hover .service-card__title,
.service-card:hover .service-card__desc { color: var(--white); }
.service-card:hover .service-card__icon { background: rgba(255,255,255,.2); }
.service-card > * { position: relative; z-index: 1; }
.service-card__icon {
  width: 72px; height: 72px;
  border-radius: var(--radius-md);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 2rem;
  margin-bottom: 1.25rem;
  transition: background var(--transition);
}
.service-card__title { margin-bottom: .75rem; font-size: 1.2rem; transition: color var(--transition); }
.service-card__desc  { margin: 0; font-size: .95rem; transition: color var(--transition); }
.service-card__link  {
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  margin-top: 1.25rem;
  font-weight: 600;
  font-size: .9rem;
  color: var(--purple);
  transition: all var(--transition);
}
.service-card:hover .service-card__link { color: rgba(255,255,255,.9); gap: .75rem; }

/* ---------- Stats Banner ---------- */
.stats-banner {
  background: linear-gradient(135deg, var(--indigo), var(--purple));
  padding: 4rem 0;
  overflow: hidden;
  position: relative;
}
.stats-banner::before {
  content: '';
  position: absolute;
  inset: 0;
  background: url("data:image/svg+xml,%3Csvg width='60' height='60' viewBox='0 0 60 60' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Cg fill='%23ffffff' fill-opacity='0.03'%3E%3Cpath d='M36 34v-4h-2v4h-4v2h4v4h2v-4h4v-2h-4zm0-30V0h-2v4h-4v2h4v4h2V6h4V4h-4zM6 34v-4H4v4H0v2h4v4h2v-4h4v-2H6zM6 4V0H4v4H0v2h4v4h2V6h4V4H6z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E");
}
.stats-grid {
  display: grid;
  grid-template-columns: repeat(4,1fr);
  gap: 2rem;
  position: relative;
  z-index: 1;
}
.stat-item { text-align: center; }
.stat-item__value {
  font-family: var(--font-heading);
  font-size: 3rem;
  font-weight: 800;
  color: var(--white);
  display: block;
  line-height: 1;
  margin-bottom: .5rem;
}
/* CONTRAST, 23 Oct 2026. The suffix sits on .stats-banner (navy to blue). Bright orange was 1.7:1 on
   the blue end. A pale orange, same hue, is large text and clears 3:1 on both ends. */
.stat-item__suffix { color: #FED7AA; }
.stat-item__label { color: rgba(255,255,255,.7); font-size: .95rem; }

/* ---------- Features / Why Mirrah ---------- */
.features-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 4rem;
  align-items: center;
}
.features-list { display: flex; flex-direction: column; gap: 1.5rem; }
.feature-item {
  display: flex;
  gap: 1.25rem;
  align-items: flex-start;
  padding: 1.25rem;
  border-radius: var(--radius-md);
  transition: background var(--transition);
}
.feature-item:hover { background: var(--gray-50); }
.feature-item__icon {
  width: 52px; height: 52px;
  border-radius: var(--radius-sm);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.5rem;
  flex-shrink: 0;
}
.feature-item__title { font-size: 1.05rem; margin-bottom: .35rem; }
.feature-item__desc  { font-size: .9rem; margin: 0; }

/* Visual side mosaic */
.features-visual {
  position: relative;
  height: 500px;
}
.features-mosaic {
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-template-rows: 1fr 1fr;
  gap: 1rem;
  height: 100%;
}
.mosaic-card {
  border-radius: var(--radius-lg);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 1.5rem;
  text-align: center;
  color: var(--white);
  font-weight: 700;
  font-size: 1rem;
  position: relative;
  overflow: hidden;
}
.mosaic-card span { font-size: 2.5rem; margin-bottom: .5rem; display: block; }
.mosaic-card--purple { background: linear-gradient(135deg, var(--purple), var(--purple-dark)); }
.mosaic-card--orange { background: linear-gradient(135deg, var(--orange), var(--orange-dark)); }
.mosaic-card--teal   { background: linear-gradient(135deg, var(--teal), var(--teal-dark)); }
.mosaic-card--emerald{ background: linear-gradient(135deg, var(--emerald), #059669); }
.mosaic-card:first-child { grid-row: span 2; }

/* ---------- Testimonials ---------- */
.testimonials { background: var(--gray-50); }
.testimonials-grid { display: grid; grid-template-columns: repeat(3,1fr); gap: 1.75rem; }
.testimonial-card {
  background: var(--white);
  border-radius: var(--radius-lg);
  padding: 2rem;
  box-shadow: var(--shadow-md);
  position: relative;
}
.testimonial-card::before {
  content: '"';
  position: absolute;
  top: 1rem;
  right: 1.5rem;
  font-size: 5rem;
  font-family: Georgia, serif;
  color: var(--purple-light);
  line-height: 1;
}
.testimonial-card__stars { color: #F59E0B; font-size: 1.1rem; margin-bottom: 1rem; }
.testimonial-card__text  { color: var(--gray-600); font-style: italic; margin-bottom: 1.5rem; }
.testimonial-card__author { display: flex; align-items: center; gap: 1rem; }
.testimonial-card__avatar {
  width: 48px; height: 48px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.25rem;
  flex-shrink: 0;
}
.testimonial-card__name { font-weight: 700; color: var(--indigo); font-size: .95rem; }
.testimonial-card__role { color: var(--gray-400); font-size: .8rem; }

/* ---------- Blog Cards ---------- */
.blog-grid { display: grid; grid-template-columns: repeat(3,1fr); gap: 1.75rem; }
.blog-card {
  background: var(--white);
  border-radius: var(--radius-lg);
  overflow: hidden;
  box-shadow: var(--shadow-md);
  transition: all var(--transition);
}
.blog-card:hover { transform: translateY(-6px); box-shadow: var(--shadow-xl); }
.blog-card__thumb {
  height: 200px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 4rem;
  position: relative;
  overflow: hidden;
}
.blog-card__body { padding: 1.5rem; }
.blog-card__meta { display: flex; gap: 1rem; align-items: center; margin-bottom: .75rem; }
.blog-card__date { color: var(--gray-400); font-size: .8rem; }
.blog-card__title { margin-bottom: .75rem; font-size: 1.1rem; }
.blog-card__excerpt { font-size: .9rem; margin-bottom: 1rem; }
.blog-card__read-more {
  font-weight: 600;
  color: var(--purple);
  font-size: .9rem;
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  transition: gap var(--transition);
}
.blog-card__read-more:hover { gap: .75rem; }

/* ---------- CTA Section ---------- */
.cta-section {
  background: linear-gradient(135deg, var(--purple), var(--indigo));
  position: relative;
  overflow: hidden;
  text-align: center;
  padding: 5rem 0;
}
.cta-section::before {
  content: '';
  position: absolute;
  width: 600px; height: 600px;
  background: radial-gradient(circle, rgba(249,115,22,.3), transparent);
  border-radius: 50%;
  top: -200px; right: -100px;
}
.cta-section::after {
  content: '';
  position: absolute;
  width: 400px; height: 400px;
  background: radial-gradient(circle, rgba(6,182,212,.3), transparent);
  border-radius: 50%;
  bottom: -150px; left: -50px;
}
.cta-section > * { position: relative; z-index: 1; }
.cta-section h2 { color: var(--white); margin-bottom: 1rem; }
.cta-section p  { color: rgba(255,255,255,.8); max-width: 560px; margin: 0 auto 2.5rem; font-size: 1.1rem; }
.cta-section .btn-group { display: flex; gap: 1rem; justify-content: center; flex-wrap: wrap; }

/* ---------- Partner Logos ---------- */
.partners { background: var(--gray-50); padding: 3rem 0; }
.partners__grid {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 3rem;
  flex-wrap: wrap;
}
.partner-logo {
  background: var(--white);
  border-radius: var(--radius-md);
  padding: 1rem 2rem;
  box-shadow: var(--shadow-sm);
  font-weight: 700;
  color: var(--gray-600);
  font-size: .95rem;
  display: flex;
  align-items: center;
  gap: .75rem;
  transition: all var(--transition);
  text-decoration: none;
}
.partner-logo:hover { box-shadow: var(--shadow-md); color: var(--purple); transform: translateY(-2px); }
.partner-logo__icon { font-size: 1.5rem; }

/* ---------- Events ---------- */
.events-list { display: flex; flex-direction: column; gap: 1.25rem; }
.event-item {
  display: flex;
  gap: 1.5rem;
  align-items: flex-start;
  background: var(--white);
  border-radius: var(--radius-lg);
  padding: 1.75rem;
  box-shadow: var(--shadow-sm);
  border-left: 4px solid var(--purple);
  transition: all var(--transition);
}
.event-item:hover { box-shadow: var(--shadow-md); transform: translateX(4px); }
.event-item__date-block {
  text-align: center;
  min-width: 70px;
  background: linear-gradient(135deg, var(--purple), var(--purple-dark));
  border-radius: var(--radius-md);
  padding: .75rem .5rem;
  color: var(--white);
}
.event-item__month { font-size: .75rem; font-weight: 600; text-transform: uppercase; letter-spacing: .05em; opacity: .8; }
.event-item__day   { font-size: 2rem; font-weight: 800; line-height: 1; }
.event-item__title { font-size: 1.1rem; margin-bottom: .35rem; }
.event-item__meta  { display: flex; gap: 1rem; flex-wrap: wrap; }
.event-item__meta-item { color: var(--gray-500); font-size: .85rem; display: flex; align-items: center; gap: .35rem; }

/* ---------- Footer ---------- */
.footer {
  background: var(--indigo);
  color: rgba(255,255,255,.8);
  padding: 4rem 0 2rem;
}
/* ⭐⭐ THE FOOTER ON A PHONE. Fixed 3 August 2026, found in an audit and confirmed by screenshot at
   375px: 22 elements were rendering off the right edge of the screen, including the whole Services
   list, the whole Get Started column, and the entire Contact block. The street address, the office
   number, the after-hours number and the email address were all invisible on every phone, on all 16
   pages.

   THE CAUSE WAS NOT THIS RULE. It was that every page carried the grid as an INLINE style attribute
   instead, and an inline style cannot be overridden by a media query, so the two collapse rules below
   never applied and never had. body{overflow-x:hidden} then quietly clipped the overflow rather than
   letting it scroll, which is why nobody saw a horizontal scrollbar and noticed.

   For a disability services agency whose visitors are mostly families on a phone looking for a number
   to call, this was the most expensive twelve characters on the site. Five columns here so the pages
   look exactly as they did on a laptop; 1024 and 768 below do the collapsing. */
.footer__grid {
  display: grid;
  grid-template-columns: 1.5fr 1fr 1fr 1fr 1.3fr;
  gap: 2.5rem;
}
.footer__brand-name {
  font-family: var(--font-heading);
  font-size: 1.5rem;
  font-weight: 800;
  color: var(--white);
  margin-bottom: .75rem;
  display: flex;
  align-items: center;
  gap: .75rem;
}
.footer__brand-desc { font-size: .9rem; margin-bottom: 1.5rem; line-height: 1.75; }
.footer__socials { display: flex; gap: .75rem; }
.footer__social {
  width: 40px; height: 40px;
  background: rgba(255,255,255,.08);
  border-radius: var(--radius-sm);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.1rem;
  transition: all var(--transition);
  text-decoration: none;
  color: rgba(255,255,255,.8);
}
.footer__social:hover { background: var(--purple); color: var(--white); transform: translateY(-2px); }
.footer__heading { color: var(--white); font-size: 1rem; font-weight: 700; margin-bottom: 1.25rem; }
.footer__links { display: flex; flex-direction: column; gap: .6rem; }
.footer__link {
  color: rgba(255,255,255,.65);
  font-size: .9rem;
  transition: color var(--transition);
  display: flex;
  align-items: center;
  gap: .4rem;
}
.footer__link:hover { color: var(--orange); }
.footer__contact-item {
  display: flex;
  align-items: flex-start;
  gap: .75rem;
  font-size: .9rem;
  margin-bottom: .75rem;
  color: rgba(255,255,255,.65);
}
.footer__contact-icon { color: var(--orange); flex-shrink: 0; margin-top: .1rem; }
.footer__bottom {
  border-top: 1px solid rgba(255,255,255,.1);
  padding-top: 2rem;
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap;
  gap: 1rem;
  font-size: .85rem;
}
.footer__ada-badge {
  display: flex;
  align-items: center;
  gap: .5rem;
  background: rgba(16,185,129,.15);
  border: 1px solid rgba(16,185,129,.3);
  border-radius: 50px;
  padding: .35rem .9rem;
  color: var(--emerald);
  font-size: .8rem;
  font-weight: 600;
}

/* ---------- Scroll Animations ---------- */
.reveal {
  opacity: 0;
  transform: translateY(30px);
  transition: opacity .7s ease, transform .7s ease;
}
.reveal.in-view { opacity: 1; transform: translateY(0); }
.reveal--left { transform: translateX(-30px); }
.reveal--left.in-view { transform: translateX(0); }
.reveal--right { transform: translateX(30px); }
.reveal--right.in-view { transform: translateX(0); }
.reveal--scale { transform: scale(.95); }
.reveal--scale.in-view { transform: scale(1); }

/* Stagger children */
.stagger > * {
  opacity: 0;
  transform: translateY(20px);
  transition: opacity .6s ease, transform .6s ease;
}
.stagger.in-view > *:nth-child(1) { transition-delay: .1s; opacity: 1; transform: none; }
.stagger.in-view > *:nth-child(2) { transition-delay: .2s; opacity: 1; transform: none; }
.stagger.in-view > *:nth-child(3) { transition-delay: .3s; opacity: 1; transform: none; }
.stagger.in-view > *:nth-child(4) { transition-delay: .4s; opacity: 1; transform: none; }
.stagger.in-view > *:nth-child(5) { transition-delay: .5s; opacity: 1; transform: none; }
.stagger.in-view > *:nth-child(6) { transition-delay: .6s; opacity: 1; transform: none; }

/* ---------- Video Modal ---------- */
.video-section {
  background: linear-gradient(135deg, var(--indigo), #0c447c);
  padding: 5rem 0;
  text-align: center;
  position: relative;
  overflow: hidden;
}
.video-section h2 { color: var(--white); margin-bottom: 1rem; }
.video-section p  { color: rgba(255,255,255,.75); margin-bottom: 2.5rem; max-width: 560px; margin-left: auto; margin-right: auto; }
.video-play-btn {
  width: 90px; height: 90px;
  background: linear-gradient(135deg, var(--orange), var(--orange-dark));
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 2rem;
  color: var(--white);
  box-shadow: 0 0 0 16px rgba(249,115,22,.2), 0 0 0 32px rgba(249,115,22,.1);
  animation: pulsePlay 2s ease-in-out infinite;
  transition: transform var(--transition);
  cursor: pointer;
  border: none;
  margin-bottom: 1.5rem;
}
.video-play-btn:hover { transform: scale(1.1); }
@keyframes pulsePlay {
  0%,100% { box-shadow: 0 0 0 16px rgba(249,115,22,.2), 0 0 0 32px rgba(249,115,22,.1); }
  50%      { box-shadow: 0 0 0 24px rgba(249,115,22,.15), 0 0 0 48px rgba(249,115,22,.05); }
}
.video-thumbnails {
  display: flex;
  gap: 1.25rem;
  justify-content: center;
  flex-wrap: wrap;
  margin-top: 2rem;
}
.video-thumb {
  background: rgba(255,255,255,.08);
  backdrop-filter: blur(8px);
  border: 1px solid rgba(255,255,255,.15);
  border-radius: var(--radius-md);
  padding: 1.25rem 1.75rem;
  color: var(--white);
  cursor: pointer;
  transition: all var(--transition);
  text-align: center;
  min-width: 160px;
}
.video-thumb:hover { background: rgba(255,255,255,.15); transform: translateY(-4px); }
.video-thumb__icon { font-size: 2rem; margin-bottom: .5rem; display: block; }
.video-thumb__title { font-weight: 600; font-size: .9rem; }
.video-thumb__duration { color: rgba(255,255,255,.6); font-size: .8rem; }

/* ---------- Utility ---------- */
.text-center { text-align: center; }
.text-white  { color: var(--white) !important; }
.text-purple { color: var(--purple); }
/* CONTRAST, 23 Oct 2026. Text shades of the same hues: 5.2:1 and 5.4:1 on white (were 2.8 and 2.4). */
.text-orange { color: var(--orange-dark); }
.text-teal   { color: var(--teal-dark); }
.mb-0 { margin-bottom: 0; }
.mt-1 { margin-top: 1rem; }
.mt-2 { margin-top: 2rem; }
.hidden { display: none; }
.sr-only { position:absolute; width:1px; height:1px; padding:0; margin:-1px; overflow:hidden; clip:rect(0,0,0,0); border:0; }

/* ---------- Page Header ---------- */
/* ⭐⭐ HEADER + SPACING TOKENS (2026-08-07). The banner, the gradient and the curve are
   unchanged — same brand colours, same ellipse. What changed is the BOX around them:

     · The header now RESERVES room for its own curve (padding-bottom = gap + curve height),
       so the curve can never sit on top of the tabs, buttons or cards that follow it. Nothing
       below the banner has to be pulled up underneath it any more.
     · Height follows the content. The old `padding: 8rem 0 4rem` was a fixed slab that left
       dead space on desktop and made the banner enormous on a phone.
     · --ph-gap is the ONE spacing value: banner → tabs, then tabs → first card. Every page
       and both portals use it, so they all look the same.
     · overflow is no longer hidden, because it was clipping keyboard focus rings on anything
       focusable near the top of the banner.

   The portals override the tokens (smaller top padding, shorter curve) — they never restate
   the background, the gradient or the colour. That still lives here. */
:root {
  --ph-pad-top: 8rem;      /* clears the fixed marketing navbar */
  --ph-pad-bottom: 2rem;   /* real breathing room ABOVE the curve */
  --ph-curve-h: 60px;      /* how tall the decorative curve is */
  --ph-curve-fill: var(--white);   /* whatever surface the banner sits on */
  --ph-gap: 1.75rem;       /* the one gap: banner → tabs → first card */
  --ph-anchor-offset: 110px;       /* fixed navbar height, for #anchor jumps */
}
.page-header {
  background: linear-gradient(135deg, var(--indigo), var(--purple));
  padding: var(--ph-pad-top) 0 calc(var(--ph-pad-bottom) + var(--ph-curve-h));
  text-align: center;
  position: relative;
  overflow: visible;
  isolation: isolate;
  margin-bottom: var(--ph-gap);
  scroll-margin-top: var(--ph-anchor-offset);
}
/* Header content sits ABOVE the curve, never inside it. */
.page-header > * { position: relative; z-index: 1; }
.page-header::after {
  content: '';
  position: absolute;
  bottom: 0; left: 0; right: 0;
  height: var(--ph-curve-h);
  background: var(--ph-curve-fill);
  clip-path: ellipse(55% 100% at 50% 100%);
  z-index: 0;
  pointer-events: none;
}
.page-header h1 { color: var(--white); margin-bottom: .75rem; overflow-wrap: break-word; }
.page-header p   { color: rgba(255,255,255,.8); max-width: 580px; margin: 0 auto; font-size: 1.1rem; }
/* Focus rings near the banner must stay visible now that nothing is clipped. */
.page-header a:focus-visible,
.page-header button:focus-visible { outline: 3px solid #FCD34D; outline-offset: 3px; }
/* The banner already carries the gap, so the section under it must not add a second one. */
.page-header + .section { padding-top: 0; }
/* An #anchor jump has to land below the fixed navbar, not underneath it. */
:target { scroll-margin-top: var(--ph-anchor-offset); }
@media (max-width: 768px) {
  :root {
    /* Measured, not guessed: the fixed navbar is 101px tall once the logo wraps to two lines,
       so anything less than this puts the badge and the title underneath it. */
    --ph-pad-top: 7.25rem;
    --ph-pad-bottom: 1.35rem;
    --ph-curve-h: 34px;
    --ph-gap: 1.25rem;
    --ph-anchor-offset: 86px;
  }
  /* Centred text squeezes badly in a narrow column — left-align it instead. */
  .page-header { text-align: left; }
  .page-header p { margin: 0; }
  .page-header h1 { font-size: clamp(1.5rem, 5.5vw, 2rem); }
}

/* ---------- Announcement Bar ---------- */
.announcement-bar {
  background: linear-gradient(90deg, var(--purple), var(--teal));
  color: var(--white);
  text-align: center;
  padding: .6rem 1rem;
  font-size: .9rem;
  font-weight: 600;
  position: relative;
  z-index: 1001;
}
.announcement-bar a { color: #FCD34D; text-decoration: underline; }

/* ---------- Accessibility Panel ---------- */
.a11y-panel {
  position: fixed;
  bottom: 5rem;
  right: 1.5rem;
  z-index: 900;
  display: flex;
  flex-direction: column;
  gap: .5rem;
}
.a11y-btn {
  width: 44px; height: 44px;
  background: var(--purple);
  color: var(--white);
  border-radius: var(--radius-sm);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.1rem;
  cursor: pointer;
  box-shadow: var(--shadow-md);
  border: none;
  transition: all var(--transition);
  title: "";
}
.a11y-btn:hover { background: var(--purple-dark); transform: scale(1.05); }
/* 23 Oct 2026: the "on" state was orange. It is the navy now, ringed in white so it reads against the blue. */
.a11y-btn.active { background: var(--indigo); box-shadow: 0 0 0 2px var(--white), 0 0 0 4px var(--indigo); }
/* The accessibility toolbar sits on purple, so it needs the halo most of all. */
.a11y-btn:focus-visible { outline: 3px solid #C2410C; outline-offset: 2px; box-shadow: 0 0 0 2px rgba(255,255,255,.95); }

/* Accessibility modes are defined once, in the consolidated block lower in this file. */

/* ---------- Back to Top ---------- */
.back-to-top {
  position: fixed;
  bottom: 1.5rem;
  right: 1.5rem;
  width: 48px; height: 48px;
  background: linear-gradient(135deg, var(--purple), var(--purple-dark));
  color: var(--white);
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.25rem;
  box-shadow: var(--shadow-md);
  cursor: pointer;
  transition: all var(--transition);
  opacity: 0;
  pointer-events: none;
  border: none;
  z-index: 900;
}
.back-to-top.visible { opacity: 1; pointer-events: all; }
.back-to-top:hover { transform: translateY(-4px); box-shadow: var(--shadow-lg); }

/* ---------- Chat Widget Placeholder ---------- */
.chat-widget {
  position: fixed;
  bottom: 1.5rem;
  left: 1.5rem;
  z-index: 900;
}
.chat-btn {
  width: 60px; height: 60px;
  background: linear-gradient(135deg, var(--teal), var(--teal-dark));
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.5rem;
  box-shadow: var(--shadow-lg);
  cursor: pointer;
  border: none;
  color: var(--white);
  animation: pulsePlay 3s ease-in-out infinite;
  transition: transform var(--transition);
}
.chat-btn:hover { transform: scale(1.1); }
/* ⭐⭐ THE BUBBLE TAKES NO CLICKS. It sat on top of the "Get Started Today" button on the hero at
   every width tested, so a click on the left of that button opened the chat instead of the form.
   It is a decoration, and a decoration should never be able to eat a click on the most important
   button on the site. `.chat-widget.quiet` below fades it once somebody scrolls, so it is a greeting
   rather than a thing permanently parked over the page. */
.chat-bubble {
  pointer-events: none;
  position: absolute;
  bottom: 70px;
  left: 0;
  background: var(--white);
  border-radius: var(--radius-md) var(--radius-md) var(--radius-md) 0;
  padding: .75rem 1rem;
  box-shadow: var(--shadow-lg);
  white-space: nowrap;
  font-size: .85rem;
  font-weight: 600;
  color: var(--indigo);
  animation: bubbleIn .5s ease .5s both;
  pointer-events: none;
}
@keyframes bubbleIn {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* ---------- Responsive ---------- */
@media (max-width: 1024px) {
  .hero__grid        { grid-template-columns: 1fr; gap: 3rem; }
  .hero__visual      { display: none; }
  .features-grid     { grid-template-columns: 1fr; }
  .features-visual   { height: 300px; }
  .stats-grid        { grid-template-columns: repeat(2,1fr); }
  .footer__grid      { grid-template-columns: 1fr 1fr; }
  .testimonials-grid { grid-template-columns: 1fr 1fr; }
  .blog-grid         { grid-template-columns: 1fr 1fr; }
}

@media (max-width: 768px) {
  .navbar__nav       { display: none; }
  .navbar__hamburger { display: flex; }
  .navbar__phone     { display: none; }
  .hero__actions     { flex-direction: column; align-items: flex-start; }
  .hero__stats       { gap: 1.5rem; }
  .services-grid     { grid-template-columns: 1fr; }
  .testimonials-grid { grid-template-columns: 1fr; }
  .blog-grid         { grid-template-columns: 1fr; }
  .footer__grid      { grid-template-columns: 1fr; gap: 2rem; }
  .stats-grid        { grid-template-columns: repeat(2,1fr); }
}

@media (max-width: 480px) {
  .stats-grid { grid-template-columns: 1fr 1fr; }
  .hero__stat-value { font-size: 1.5rem; }
  .section  { padding: 3.5rem 0; }
  .btn--lg  { padding: .9rem 1.75rem; }
  .cta-section .btn-group { flex-direction: column; align-items: center; }
}

/* ═══════ ⛔⛔⛔ 10/09/2026 (Jen) — "The phone menu button is cut off on small phones." ═══════
   MEASURED, NOT REASONED, in Chrome at real viewport widths against the shipped file:

       viewport   menu button box      verdict
         320px    x 307.05 .. 331.05   ⛔ right edge 11.05px PAST the viewport
         330px    x 307.05 .. 331.05   ⛔ still past it
         331px    x 307.05 .. 331.05   fits, by 0.05px
         360px    x 312    .. 336      fits

   ⛔ SO THE BREAK IS AT 330px AND BELOW, and a 320px phone is a real phone: that is an iPhone SE of
   the first generation, an iPhone 5 or 5s, and most 320px Android handsets. ⚠ AND IT IS NOT MERELY
   OVERFLOWING. `document.scrollWidth` equals the viewport width at 320, so there is no sideways
   scroll to reach it: the button is genuinely unreachable, which is what she is describing.

   ⛔⛔ AND THE CONSEQUENCE IS LARGER THAN ONE BUTTON. `.navbar__nav` is `display:none` below 768, so
   on a phone this button is the ONLY way to the site's navigation, and the mobile panel it opens is
   also the only place the Family Portal link appears on a phone. A clipped button takes the whole
   menu with it.

   ⭐ THE CAUSE. `.navbar__inner` is `nowrap` with `space-between`, and at 320 its content needs
   331.05px inside a container that ends at 296. Flex items do not wrap, so the LAST item in the row,
   this button, is the one pushed out.
   ⛔ `white-space` DOES NOT WRAP FLEX ITEMS. That is a recorded trap on this codebase and it is the
   first thing somebody reaches for on a cut-off control in a row. It cannot fix this.

   ⭐⭐ THREE CANDIDATES WERE MEASURED AND THE OTHER TWO WERE REJECTED ON THE NUMBERS:
     · shrink the brand type below 360 — ⛔ STILL CLIPPED at 280px. A partial fix that reads as a fix.
     · let the row shrink with `min-width:0` and an ellipsis — fits everywhere, ⛔ but it TRUNCATED the
       brand name AND the portal label, and it did so at 360 too, where nothing was wrong. That is a
       fix that degrades a screen in order to repair it.
     · hide the portal BUTTON below 340 — ⭐ fits at 240, 280, 320, 330 and 340, changes nothing at
       341 and above, and truncates nothing at any width. Measured at twelve widths from 240 to 1200.

   ⭐ NOTHING IS LOST BY HIDING IT, AND MORE IS GAINED. The Family Portal link is already inside the
   mobile panel this button opens. Today, at 320, that panel cannot be opened at all, so the portal is
   unreachable; after this it is one tap away. The fix makes the portal MORE reachable, not less.

   ⚠ 340 AND NOT 360 ON PURPOSE. At 341 to 360 the button already fits, so hiding a call to action
   there would be a cost with no benefit. 340 clears the 331.05 figure with ten pixels of margin
   rather than sitting on a sub-pixel boundary.
   ⚠ THE TAP TARGET IS UNTOUCHED. Her 09/29 work set this button to a 24px minimum and that rule is
   left exactly where it is; this is a different fault at a different place in the cascade. */
@media (max-width: 340px) {
  .navbar__portal-btn { display: none; }
}

/* ---------- Brand Identity (Royal Blue from Logo) ---------- */
:root {
  --royal-blue:      #1273c2;
  --royal-blue-dark: #0c447c;
  --royal-blue-light:#dbe8f7;
}
.btn--blue {
  background: linear-gradient(135deg, var(--royal-blue), var(--royal-blue-dark));
  color: var(--white);
  box-shadow: 0 4px 20px rgba(18,115,194,.35);
}
.btn--blue:hover { transform: translateY(-2px); box-shadow: 0 8px 30px rgba(18,115,194,.5); }

/* ---------- Logo Brand Styles ---------- */
.navbar__logo-wrap {
  display: flex;
  align-items: center;
  gap: .6rem;
  text-decoration: none;
}
/* When using the actual PNG (black bg) — show in a contained box */
.navbar__logo-img {
  height: 52px;
  width: auto;
  display: block;
  object-fit: contain;
  border-radius: var(--radius-sm);
  transition: opacity var(--transition);
}
/* PNG has black bg — invert on scrolled white navbar */
.navbar--scrolled .navbar__logo-img {
  background: var(--white);
  border-radius: 6px;
  padding: 2px 4px;
}
/* Keep PNG visible on both dark and light navbar */
.navbar__logo-img:hover { opacity: .85; }
.navbar__logo-emblem {
  width: 44px;
  height: 44px;
  border: 2.5px solid #1273c2;
  border-radius: 50%;
  background: rgba(255,255,255,.08);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  font-size: 1.3rem;
  transition: all var(--transition);
}
.navbar--scrolled .navbar__logo-emblem { border-color: var(--royal-blue); background: var(--royal-blue-light); }
.navbar__logo-text { display: flex; flex-direction: column; line-height: 1.1; }
.navbar__logo-name {
  font-family: var(--font-heading);
  font-weight: 800;
  font-size: .7rem;
  letter-spacing: .18em;
  color: rgba(255,255,255,.85);
  transition: color var(--transition);
}
.navbar__logo-services {
  font-family: var(--font-heading);
  font-weight: 800;
  font-size: 1rem;
  letter-spacing: .08em;
  color: #9898e6;
  transition: color var(--transition);
}
.navbar--scrolled .navbar__logo-name { color: var(--indigo); }
.navbar--scrolled .navbar__logo-services { color: var(--royal-blue); }

/* ---------- New Split Hero ---------- */
.hero-split {
  display: grid;
  grid-template-columns: 1fr 1fr;
  min-height: 100vh;
}
.hero-split__left {
  background: linear-gradient(160deg, var(--indigo) 0%, #070956 40%, #0a0c66 70%, #0a0c66 100%);
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 8rem 5rem 5rem 5rem;
  position: relative;
  overflow: hidden;
}
.hero-split__left::before {
  content: '';
  position: absolute;
  width: 500px; height: 500px;
  background: radial-gradient(circle, rgba(18,115,194,.25) 0%, transparent 70%);
  top: -100px; left: -100px;
  border-radius: 50%;
}
.hero-split__right {
  position: relative;
  overflow: hidden;
}
.hero-split__photo {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
  display: block;
}
.hero-split__photo-overlay {
  position: absolute;
  inset: 0;
  background: linear-gradient(to right, rgba(8,10,125,.5) 0%, transparent 40%);
}
.hero-split__badge-float {
  position: absolute;
  bottom: 2.5rem;
  left: 2rem;
  background: white;
  border-radius: var(--radius-lg);
  padding: 1rem 1.5rem;
  box-shadow: var(--shadow-xl);
  display: flex;
  align-items: center;
  gap: .75rem;
  max-width: 280px;
  animation: floatUp 3s ease-in-out infinite;
}
.hero-split__badge-dot {
  width: 12px; height: 12px;
  background: #10B981;
  border-radius: 50%;
  box-shadow: 0 0 0 4px rgba(16,185,129,.2);
  flex-shrink: 0;
  animation: pulse 2s infinite;
}
.hero-split__badge-text { font-size: .85rem; font-weight: 700; color: var(--indigo); }
.hero-split__promise {
  font-family: var(--font-heading);
  font-size: .9rem;
  font-weight: 600;
  color: #9898e6;
  letter-spacing: .12em;
  text-transform: uppercase;
  margin-bottom: 1.25rem;
}
.hero-split__title {
  font-size: clamp(2.4rem, 4.5vw, 4.2rem);
  line-height: 1.1;
  color: var(--white);
  margin-bottom: 1.5rem;
  font-family: var(--font-heading);
  font-weight: 800;
}
.hero-split__title span { color: #9898e6; }
.hero-split__desc {
  color: rgba(255,255,255,.75);
  font-size: 1.1rem;
  line-height: 1.75;
  margin-bottom: 2.5rem;
  max-width: 500px;
}
.hero-split__actions { display: flex; gap: 1rem; flex-wrap: wrap; margin-bottom: 3rem; }
.hero-split__stats {
  display: flex;
  gap: 2rem;
  padding-top: 2rem;
  border-top: 1px solid rgba(255,255,255,.12);
}
.hero-split__stat-value {
  font-family: var(--font-heading);
  font-size: 2rem;
  font-weight: 800;
  color: var(--white);
  display: block;
}
.hero-split__stat-label { font-size: .78rem; color: rgba(255,255,255,.55); }

/* ---------- Brand Promise Strip ---------- */
.brand-strip {
  background: linear-gradient(135deg, var(--royal-blue) 0%, var(--purple) 50%, var(--indigo) 100%);
  padding: 4.5rem 0;
  color: var(--white);
}
.brand-strip__grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 3rem;
  text-align: center;
}
.brand-strip__item__icon { font-size: 2.5rem; margin-bottom: 1rem; }
.brand-strip__compare {
  font-size: .8rem;
  font-weight: 600;
  letter-spacing: .05em;
  text-transform: uppercase;
  color: rgba(255,255,255,.5);
  margin-bottom: .25rem;
  text-decoration: line-through;
}
.brand-strip__item h3 { color: var(--white); font-size: 1.1rem; margin-bottom: .5rem; }
.brand-strip__item p { color: rgba(255,255,255,.7); font-size: .9rem; }

/* ---------- Photo Gallery ---------- */
.photo-gallery {
  padding: 5rem 0;
  background: var(--gray-50);
}
.gallery-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: 260px 260px;
  gap: 1rem;
  border-radius: var(--radius-xl);
  overflow: hidden;
}
.gallery-item {
  position: relative;
  overflow: hidden;
  background: var(--gray-200);
}
.gallery-item:first-child { grid-column: span 2; }
.gallery-item img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform .6s ease;
  display: block;
}
.gallery-item:hover img { transform: scale(1.05); }
.gallery-item__caption {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  padding: 1.5rem 1.25rem .75rem;
  background: linear-gradient(to top, rgba(0,0,0,.7) 0%, transparent 100%);
  color: white;
  font-size: .85rem;
  font-weight: 600;
  transform: translateY(100%);
  transition: transform var(--transition);
}
.gallery-item:hover .gallery-item__caption { transform: translateY(0); }
.gallery-placeholder {
  width: 100%; height: 100%;
  display: flex; flex-direction: column;
  align-items: center; justify-content: center;
  gap: .5rem;
  background: linear-gradient(135deg, var(--purple-light), #b5d4f4);
  color: var(--purple-dark);
  font-size: .85rem;
  font-weight: 600;
  text-align: center;
  padding: 1rem;
}
.gallery-placeholder span { font-size: 2.5rem; }

/* ---------- Testimonials with Photos ---------- */
.testimonial-photo {
  width: 56px;
  height: 56px;
  border-radius: 50%;
  object-fit: cover;
  object-position: center top;
  flex-shrink: 0;
  border: 3px solid var(--purple-light);
}
.testimonial-photo-placeholder {
  width: 56px;
  height: 56px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.5rem;
  flex-shrink: 0;
  border: 3px solid var(--purple-light);
}

/* ---------- Responsive Additions ---------- */
@media (max-width: 1024px) {
  .hero-split { grid-template-columns: 1fr; }
  .hero-split__right { height: 50vh; }
  .hero-split__left { padding: 7rem 2.5rem 3.5rem; }
  .brand-strip__grid { grid-template-columns: 1fr; gap: 2rem; }
  .gallery-grid { grid-template-columns: 1fr 1fr; grid-template-rows: 220px 220px 220px; }
  .gallery-item:first-child { grid-column: span 2; }
}
@media (max-width: 768px) {
  .hero-split__right { height: 40vh; }
  .hero-split__actions { flex-direction: column; }
  .hero-split__stats { gap: 1.25rem; }
  .gallery-grid { grid-template-columns: 1fr; grid-template-rows: repeat(6, 200px); }
  .gallery-item:first-child { grid-column: span 1; }
  .brand-strip { padding: 3rem 0; }
}

/* ─────────────────────────────────────────
   TASTE-KILL LAYER — premium finish details
   ───────────────────────────────────────── */

/* Gradient text that animates */
@keyframes gradientShift {
  0%   { background-position: 0% 50%; }
  50%  { background-position: 100% 50%; }
  100% { background-position: 0% 50%; }
}
.gradient-text-animate {
  background: linear-gradient(135deg, #1273c2, #1273c2, #F97316, #06B6D4);
  background-size: 300% 300%;
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
  animation: gradientShift 5s ease infinite;
}

/* Refined selection color */
::selection { background: rgba(102,136,255,.25); color: var(--indigo); }

/* Better font rendering */
body { -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-rendering: optimizeLegibility; }

/* Scrollbar styling */
::-webkit-scrollbar { width: 6px; }
::-webkit-scrollbar-track { background: var(--gray-100); }
::-webkit-scrollbar-thumb { background: linear-gradient(var(--royal-blue), var(--purple)); border-radius: 3px; }

/* Glassmorphism utility */
.glass {
  background: rgba(255,255,255,.08);
  border: 1px solid rgba(255,255,255,.12);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
}

/* Back-to-top upgrade */
.back-to-top {
  opacity: 0;
  transform: scale(0.8);
  transition: opacity .3s ease, transform .4s cubic-bezier(0.34,1.56,0.64,1), background .2s ease;
}
.back-to-top.visible { opacity: 1; transform: scale(1); }
.back-to-top:hover { transform: scale(1.1) translateY(-2px) !important; }

/* Promise section underline accent */
.promise-headline strong {
  position: relative;
  display: inline-block;
}
.promise-headline strong::after {
  content: '';
  position: absolute;
  bottom: -4px;
  left: 0; right: 0;
  height: 3px;
  background: linear-gradient(90deg, var(--royal-blue), var(--purple));
  border-radius: 2px;
  transform: scaleX(0);
  transform-origin: left;
  transition: transform .6s cubic-bezier(0.16,1,0.3,1);
}
.in-view .promise-headline strong::after { transform: scaleX(1); }

/* Hero split right photo — subtle scale-in */
.hero-split__right { overflow: hidden; }
.hero-split__photo { transform-origin: center; }

/* Partner logos — hover lift */
.partner-logo {
  transition: all .3s cubic-bezier(0.34,1.56,0.64,1);
}
.partner-logo:hover {
  transform: translateY(-4px) scale(1.03);
  box-shadow: 0 10px 30px rgba(0,0,0,.1);
}

/* Dark section heading gradient */
.services-dark .section-header h2 span {
  display: inline-block;
}

/* Impact section number glow */
.impact-item:hover .impact-item__value {
  filter: drop-shadow(0 0 20px rgba(18,115,194,.3));
}

/* Testimonial card quote mark */
.testimonial-v2::before {
  content: '"';
  position: absolute;
  top: 1rem; right: 1.5rem;
  font-size: 6rem;
  font-family: Georgia, serif;
  line-height: 1;
  color: var(--royal-blue-light);
  pointer-events: none;
}

/* Difference row — subtle border glow on hover */
.difference-row:hover .difference-visual {
  box-shadow: 0 30px 80px rgba(18,115,194,.15);
  transition: box-shadow .5s ease;
}

/* Link hover underline - global */
.footer__link {
  position: relative;
  display: inline-block;
}
.footer__link::after {
  content: '';
  position: absolute;
  bottom: -1px;
  left: 0; width: 0;
  height: 1px;
  background: rgba(255,255,255,.5);
  transition: width .25s ease;
}
.footer__link:hover::after { width: 100%; }

/* Button focus ring — keyboard nav. Halo added 18 Aug 2026: the orange alone is 1.76:1 on the brand
   blue these buttons actually are, so on a blue button the white ring is the one doing the work. */
.btn:focus-visible {
  outline: 3px solid var(--orange-dark);
  outline-offset: 4px;
  box-shadow: 0 0 0 4px rgba(255,255,255,.95);
}

/* Section divider — subtle gradient line */
.section-divider {
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--gray-200), transparent);
  border: none;
  margin: 0;
}

/* ============================================================
   ACCESSIBILITY MODES (toolbar) — consolidated & persisted
   Toggled by js/main.js; the choice is saved in localStorage
   and re-applied on every page load.
   ============================================================ */

/* ── High contrast ──────────────────────────────────────────
   Boost overall contrast, AND force low-contrast accent headings
   (light-blue text on the dark navy heroes) to a bright, legible
   near-white so the toggle visibly fixes them. */
body.high-contrast { filter: contrast(1.35) brightness(1.05); }
body.high-contrast .about-hero h1 span,
body.high-contrast .hero-v3__headline span,
body.high-contrast .hero-split__title span,
body.high-contrast .services-dark h2 span { color: #e4eefb !important; -webkit-text-fill-color: #e4eefb !important; }
/* Gradient "clipped" text → solid, high-contrast fill */
body.high-contrast [style*="background-clip:text"],
body.high-contrast [style*="-webkit-background-clip: text"],
body.high-contrast [style*="background-clip: text"] {
  -webkit-text-fill-color: #05052e !important; color: #05052e !important; background: none !important;
}

/* ── Large text ─────────────────────────────────────────────
   A base font bump alone can't grow the site's many fixed-px and
   inline-styled elements. Zooming the content regions scales ALL
   of them together — headings, paragraphs, buttons, cards — while
   leaving the fixed navbar and toolbar chrome untouched. */
body.large-text main,
body.large-text footer { zoom: 1.15; }
body.large-text { font-size: 1.06rem; }          /* fallback for pages without <main> */

/* ── Dyslexia-friendly font ─────────────────────────────────
   Apply to TEXT only, and explicitly restore icon fonts so the
   Font Awesome social/brand icons don't turn into empty boxes. */
body.dyslexia-font,
body.dyslexia-font p, body.dyslexia-font li, body.dyslexia-font a,
body.dyslexia-font span, body.dyslexia-font h1, body.dyslexia-font h2,
body.dyslexia-font h3, body.dyslexia-font h4, body.dyslexia-font h5, body.dyslexia-font h6,
body.dyslexia-font button, body.dyslexia-font .btn, body.dyslexia-font label,
body.dyslexia-font input, body.dyslexia-font textarea, body.dyslexia-font select,
body.dyslexia-font td, body.dyslexia-font th, body.dyslexia-font blockquote {
  font-family: 'Comic Sans MS', 'Comic Sans', 'Trebuchet MS', Verdana, sans-serif !important;
  letter-spacing: .03em; word-spacing: .12em;
}
/* Never re-font icon glyphs (Font Awesome). */
body.dyslexia-font .fa, body.dyslexia-font .fas, body.dyslexia-font .far,
body.dyslexia-font .fab, body.dyslexia-font .fa-brands, body.dyslexia-font .fa-solid,
body.dyslexia-font .fa-regular, body.dyslexia-font [class*="fa-"] {
  font-family: "Font Awesome 6 Free", "Font Awesome 6 Brands", "FontAwesome" !important;
  letter-spacing: normal !important; word-spacing: normal !important;
}

/* Announcement bar height transition */
.announcement-bar { overflow: hidden; }

/* ── Fancy stats banner (existing pages still use this) ── */
.stat-item { transition: transform .3s cubic-bezier(0.34,1.56,0.64,1); }
.stat-item:hover { transform: translateY(-4px); }

/* Reduce motion */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}

/* Fix: inline-styled white logo text disappearing on white scrolled navbar */
.navbar--scrolled .navbar__logo-wrap span { color: var(--indigo) !important; }


/* ⭐ Once the visitor starts reading, the greeting has done its job. Kept as a class the page adds
   rather than a timer, so it never fades while somebody is still looking at the top of the page. */
.chat-widget.quiet .chat-bubble { opacity: 0; visibility: hidden; transition: opacity .4s ease, visibility .4s ease; }
/* ⭐ The call button is an <a> now, not a <button>, so it needs the same shape spelled out.
   44px minimum on every side: WCAG 2.2 target size, and it is the one control on the page somebody
   may be tapping one-handed while holding a phone to their ear. */
a.chat-btn { text-decoration: none; min-width: 44px; min-height: 44px; }


/* ⭐ ROOM FOR THE FLOATING BUTTONS. On a phone the call button sits bottom-left and the accessibility
   tools sit bottom-right, both fixed, and the last row of the footer ran underneath them: tapping
   "Get the App" opened the phone dialer instead. They cannot move (a call button that is not where
   your thumb is, is not a call button), so the footer ends above them. Found 3 August 2026 by asking
   elementFromPoint who actually receives the tap, rather than whether the boxes overlap. */
@media (max-width: 768px) {
  /* ⚠ `.footer` not `footer`. The class carries `padding: 4rem 0 2rem`, and a class beats a bare
     element selector, so the first version of this rule lost silently and the tap kept going to the
     dialer. Checked by asking who receives the tap, not by reading the stylesheet. */
  .footer { padding-bottom: 6rem; }
}


/* ⭐ FOOTER TAP TARGETS. Measured at 15px tall, against a 24px minimum. Padding rather than a height,
   so the columns keep their spacing and nothing reflows. 3 August 2026. */
.footer a { display: inline-block; padding: .35rem 0; }


/* ═══════════ ⭐⭐ ONE BUTTON CONTRACT, 5 August 2026 ═══════════
   Jen: "make sure it all match."

   The audit on 6 July found two button systems living side by side: the staff portal writes
   `btn-primary` (284 uses) and the family portal and public site write `btn--primary` (29). One
   hyphen apart, completely separate CSS, and a button written the wrong way round renders with no
   styling at all.

   ⚠ WHAT IS DELIBERATELY *NOT* UNIFIED: the look. The public site and the family portal use the
   brand's big gradient pills. The staff portal is a dense working tool with hundreds of small
   buttons on a screen, and turning those into pills would wreck every management page. Different
   sizes on purpose is design; the same button behaving differently in two places is the fault.

   So what is shared is the CONTRACT, and it lives here, once:
     · a visible focus ring, for anybody using a keyboard
     · a disabled state that looks disabled and cannot be clicked
     · a real touch target on a touch screen
   Each portal maps the other one's class names onto its own look, so neither spelling can ever
   produce an unstyled button. */
.btn, .btn-primary, .btn--primary, .btn-outline, .btn--outline,
.btn-green, .btn-amber, .btn-red-outline, .btn-light, .btn--orange, .btn--teal {
  font-family: inherit;
  -webkit-tap-highlight-color: transparent;
}
.btn:focus-visible, [class*="btn-"]:focus-visible, [class*="btn--"]:focus-visible {
  /* ⚠ The old comment here said this orange worked "against blue and against purple". Measured on
     18 Aug 2026 it is 1.76:1 on the brand blue — it did not. The white halo is what makes it visible
     on a coloured button; the darker orange is what makes it visible on a white one. */
  outline: 3px solid #C2410C;
  outline-offset: 2px;
  box-shadow: 0 0 0 2px rgba(255,255,255,.95);
}
.btn[disabled], [class*="btn-"][disabled], [class*="btn--"][disabled],
.btn[aria-disabled="true"] {
  opacity: .45; cursor: not-allowed; pointer-events: none; box-shadow: none; transform: none;
}

/* ⭐ TOUCH TARGETS. 6 July audit item 6, and Jen asked for it on 5 August.
   ⚠ On a MOUSE nothing changes, because the staff portal fits a great deal on a screen on purpose
   and 44px tall buttons everywhere would undo that. On a touch screen, where a fingertip is about
   9mm and a mis-tap on "remove" costs somebody real work, everything clickable gets the full
   guideline. `pointer: coarse` is the browser telling us it is a finger, not a cursor. */
@media (pointer: coarse) {
  .btn, [class*="btn-"], [class*="btn--"] { min-height: 44px; }
  .btn-sm, .btn--sm { min-height: 40px; padding-left: .8rem; padding-right: .8rem; }
  /* The bare inline actions: the ✕ next to an assigned staff member, edit, delete, remove. These
     were the ones actually named in the audit, and they are <a> tags rather than buttons. */
  a[onclick], .link-action {
    min-height: 44px; min-width: 44px;
    display: inline-flex; align-items: center; justify-content: center;
  }
  /* ⚠ Not links that sit inside a sentence. Stretching one of those to 44px puts a hole in the
     paragraph it lives in. */
  p a[onclick], li a[onclick], span.inline-text a[onclick] { min-height: 0; min-width: 0; display: inline; }
}


/* ═══════════ ⭐ SKELETON LOADERS, 5 August 2026 ═══════════
   6 July audit item 2, and Jen asked for it: every loading state in the portal was the plain word
   "Loading…" in grey. 202 of them in the staff portal, 25 in the family portal.

   A skeleton is better than a word for a reason that is not decoration: it holds the SHAPE of what
   is coming, so the page does not jump when the real content lands, and somebody on a slow phone in
   a car park can see the difference between "still coming" and "there is nothing here".

   ⚠ aria-hidden and role=status: a screen reader should hear "Loading" once, not read out eight
   grey rectangles. */
.skel { display: block; background: linear-gradient(90deg,#F1F5F9 25%,#E2E8F0 37%,#F1F5F9 63%);
  background-size: 400% 100%; border-radius: 8px; height: 1rem; margin: .45rem 0;
  animation: skelshine 1.4s ease-in-out infinite; }
.skel--title { height: 1.15rem; width: 42%; }
.skel--line  { width: 100%; }
.skel--short { width: 65%; }
@keyframes skelshine { 0% { background-position: 100% 50%; } 100% { background-position: 0 50%; } }
@media (prefers-reduced-motion: reduce) { .skel { animation: none; } }

/* ═══════════ ⭐⭐⭐ THE iPAD "IT GOES AWAY WHEN I TAP IT" BUG — 19 August 2026 ═══════════
   Jen: "when you add or edit an event or activity you can click on it but it will go away and you
   have to click it again to get back to the space where you can type." On an iPad.

   WHAT IS ACTUALLY HAPPENING. Safari on iOS auto-zooms the page whenever you tap a form field whose
   text is smaller than 16px, to make it readable. Zooming re-lays the page out, so the box slides
   out from under your finger mid-tap. You tap, it moves, you tap again. Every field on these forms
   is 14.4px, so it is every field — which is why Jen said "add OR edit an event or activity"
   rather than naming one box. Nothing is broken in the code; a browser is being helpful.

   ⚠⚠ THE OBVIOUS FIX IS THE WRONG ONE. Everyone reaches for maximum-scale=1 / user-scalable=no in
   the viewport tag. It does stop the zoom — by disabling pinch-zoom for the whole page, for
   everybody, permanently. That is a WCAG 1.4.4 failure and it would take magnification away from
   exactly the people this agency exists for. It is not going in this file.

   WHAT THIS DOES INSTEAD. 16px is the threshold, so on TOUCH devices the form controls are 16px and
   Safari has no reason to zoom. `pointer: coarse` matches a finger and not a mouse, so the desktop
   layout is untouched — and it matches precisely when the bug can occur, because the auto-zoom is
   a touch behaviour in the first place. !important is needed because these font sizes are inline
   on the elements themselves. */
@media (pointer: coarse) {
  input[type="text"], input[type="search"], input[type="email"], input[type="tel"],
  input[type="url"], input[type="password"], input[type="number"], input[type="date"],
  input[type="time"], input[type="datetime-local"], input[type="month"], input[type="week"],
  input:not([type]), select, textarea {
font-size: 16px !important;
  }
}

/* ═══════════════════════════════════════════════════════════════════════════
   ⭐ 09/18/2026 — THE ACCESSIBILITY TOOLBAR WAS SITTING ON THE PASSWORD BOX.
   Measured at 390×844 on portal.html: the toolbar is a fixed 44px column at
   x 322–366, y 616–764, and the family login's own controls run to x 326.
   It overlapped the password field AND the "Forgot password?" button. On the
   sign-in screen, which is the one screen a family cannot go around.

   Why the fix is a launcher and not "move it a few pixels". At 390 the login
   card fills x 64–326 and the Sign In button fills the bottom strip, so at
   the top of that page there is no spare rectangle big enough for a 44×148
   column. Nudging it left or down puts it on a different control. So on a
   phone the toolbar collapses to ONE button parked in the right-hand gutter,
   and the three choices open as a sheet the person asked for and can dismiss
   (Escape, the backdrop, or the same button). A sheet that a person opened
   and can close is allowed to cover things; a bar they never asked for is not.

   body gets bottom padding so the end of the document clears the launcher,
   and Back-to-top moves up so the two do not stack on each other.
   ═══════════════════════════════════════════════════════════════════════════ */
.a11y-launcher { display: none; }

@media (max-width: 480px) {
  .a11y-panel {
    flex-direction: column;
    align-items: flex-end;
    gap: .5rem;
    bottom: .5rem;
    right: .5rem;
    z-index: 960;
  }
  /* Collapsed is the default: only the launcher is on screen. */
  .a11y-panel .a11y-btn { display: none; }
  .a11y-panel.is-open .a11y-btn { display: flex; }

  .a11y-launcher {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 44px; height: 44px;
    background: var(--purple);
    color: var(--white);
    border: none;
    border-radius: var(--radius-sm);
    box-shadow: var(--shadow-md);
    font-size: 1.1rem;
    cursor: pointer;
  }
  .a11y-launcher:focus-visible {
    outline: 3px solid #C2410C; outline-offset: 2px;
    box-shadow: 0 0 0 2px rgba(255,255,255,.95);
  }
  .a11y-panel.is-open .a11y-launcher { background: var(--purple-dark); }

  /* The backdrop only exists while the sheet is open, so nothing behind it is
     clickable by accident and a tap anywhere closes it. */
  .a11y-backdrop {
    position: fixed; inset: 0;
    background: rgba(15,23,42,.45);
    z-index: 955;
    border: none; padding: 0; margin: 0;
    cursor: pointer;
  }

  body { padding-bottom: 3.75rem; }
  .back-to-top { bottom: 4.5rem; }
}

/* Above 480px nothing changes: the toolbar is the column it has always been. */
@media (min-width: 481px) {
  .a11y-backdrop { display: none; }
}

/* ═══════════ ⭐ TARGET SIZE (MINIMUM): 24×24 — 29 September 2026 ═══════════
   Jen, 09/29: "fix the under-24 ones". WCAG 2.2 success criterion 2.5.8 is 24×24. The 24 to 44
   band is a separate question she has not answered yet, so NOTHING in that band is touched here.

   ⚠ WHY THIS IS MEASURED IN A BROWSER AND NEVER READ OUT OF THIS FILE. The navbar hamburger
   declares `width: 30px; padding: 4px` at :361, which reads as 30×24 and passes. It RENDERS
   22.64×24 on the site and 21.66×24 on the game shell pages, because it sits in a flex row that
   wants 358.9px of a 327px viewport and `flex-shrink: 1` squeezes it. A check that reads declared
   CSS certifies a control that fails under a finger. Assert getBoundingClientRect at 375 or do not
   assert. The suite that guards this is tap-targets-24-test.

   ⚠ NOT LINKS INSIDE A SENTENCE. The rule at :1832 already refuses to stretch those to 44px
   because it puts a hole in the paragraph, and WCAG 2.5.8 exempts them by name ("the target is in
   a sentence"). Three of them are deliberately left alone and they are NOT oversights:
       ssi-calculator.html:179        "call us at (407) 813-2112 and we will…"
       supported-living-homes.html:580 "(407) 813-2112 and we will tell you…"
       get-started.html:198           "a limited number of <scholarship>…"
   Everything below is a whole value or a standalone control, never words in a running sentence. */

/* ⭐ THE NAVBAR MENU BUTTON, and the one change on this branch that is visible on a game page.
   It declares `width: 30px` at :361 and renders 22.64×24 on the site and 21.66×24 on the five game
   shell pages, because it is a flex item in a row that wants 358.9px of a 327px phone and
   `flex-shrink: 1` squeezes it below its own declared width. min-width is the floor that shrinking
   cannot cross, so it lands on exactly 24 and takes 1.36px back from a row that had it to spare.

   ⚠ GAMES. css/styles.css is loaded by games/index, play, group, learn and cards, and nothing in
   CSS can tell a game page from a site page without a marker class in a file under games/, which
   is not mine to edit. Jen was asked and chose "fix it everywhere, games included" on 09/29. It is
   her call and it is recorded here because the standing rule is that games are final. No game art,
   layout, script or content is touched: the menu button goes 21.66 → 24 wide and every other
   rectangle on those five pages is identical, which tap-targets-24-test asserts page by page. */
.navbar__hamburger { min-width: 24px; min-height: 24px; }

/* Already block or flex. These need height and nothing else, so the box does not change shape. */
.footer__link,
a.directions-btn { min-height: 24px; }

/* Inline links that ARE the value of their row, not words in a sentence. inline-block is what lets
   a height apply at all: min-height does nothing to a plain inline box. */
.contact-card__value a,
.resource-card__detail a,
.service-v3-card__body a,
footer a[href^="tel:"],
footer a[href^="mailto:"] {
  display: inline-block;
  min-height: 24px;
}


/* The address blocks on the two legal pages and the barrier note on accessibility.html. These read
   as prose to a crude test because their paragraph holds other text, but each link is a labelled
   value on its own <br> line ("Phone: <link>", "📞 <link> · ✉️ <link>"), not words inside a running
   sentence, so the WCAG inline exception does not cover them and a height costs the line nothing.
   .contact-block is a class added to those two paragraphs for exactly this, rather than a selector
   that guesses at position and breaks the next time somebody edits the page. */
.contact-block a[href^="tel:"],
.contact-block a[href^="mailto:"],
.legal-note a[href^="tel:"],
.legal-note a[href^="mailto:"] {
  display: inline-block;
  min-height: 24px;
}

/* The portal shell: the sign-in door and the screens behind it. These were missed on my first pass
   because I swept the public pages and not the doors, and Jen's own approval named the staff login
   controls. "Change my password" was 150.73×17 on six pages.
   ⚠ `nav > .container > a` is the portal header's "← Back to Website". The public navbar nests its
   links under .navbar__* and does not match this, which is asserted rather than assumed: every
   public page is measured before and after and none of them moves. */
nav > .container > a,
.portal-links a,
.back-nav a,
.portal-card__body button,
.portal-card__body a[href^="mailto:"],
a.out {
  display: inline-block;
  min-height: 24px;
}

/* ⚠ "Sign out" on my-page.html is a standalone action alone in its own <p>, and it rendered
   115.09×23 with display:inline and min-height:0. Those come from the coarse-pointer rule at :1834,
   `p a[onclick], li a[onclick], …`, which exists to keep a 44px box from punching a hole in a
   paragraph. That rule is right about links inside sentences and too broad by one case: a link that
   IS the whole paragraph is not sitting in prose. Specificity (0,1,2) equals it and this file is
   later, so this wins without an !important. The sentence links it protects are untouched, which is
   asserted: the four in-sentence links stay under 24 and the suite says so by name. */
p a.out,
li a.out { display: inline-block; min-height: 24px; }
