/* ============================================================
   STELLAR Broadband — base styles, design tokens, custom grid
   ============================================================ */

/* ============================================================
   DESIGN TOKENS
   Everything color lives here. To restyle, edit a token — not the
   rules below. To add a class, reuse these variables/utilities.
   ============================================================ */
:root {
  /* ---- 1. Brand palette (raw colors, dark → light) ---- */
  --navy-950: #07203f;   /* deepest space edge */
  --navy-900: #0a1f44;
  --navy-850: #0a2c50;
  --navy-800: #102a5c;
  --navy-700: #0e3d68;

  --blue-800: #123f6b;
  --blue-700: #15509e;
  --blue-600: #1e6fd0;   /* primary brand blue */
  --brand-teal: #008bbf; /* "Born in Michigan" band gradient teal — also the two-tone heading accent */
  --blue-500: #2f7cb0;
  --blue-400: #4a90c9;

  --cyan-500: #4793cf;
  --cyan-400: #3fc6ff;   /* primary accent */
  --cyan-300: #6fb8e6;
  --cyan-200: #a9dcfb;
  --cyan-100: #eaf6ff;   /* near-white tint */

  /* ---- Accessible cyan for TEXT on light surfaces ----
     --cyan-400 is the brand accent and is correct for fills, borders and glows, but as TEXT on
     white it measures only 1.96:1 — WCAG AA wants 4.5:1 for normal text and 3:1 for large.
     Every cyan-text contrast failure in the axe sweep traced back to using an accent cyan
     (#3fc6ff / #10b8ea / #29b6e8 / #05aeff / #4cc3f0) as a foreground. Two tokens fix the class
     of bug instead of patching each site, and both keep the same hue family so copy still reads
     as brand cyan rather than navy:

       --cyan-ink      normal text. Verified >= 4.5:1 on all four light surfaces in use —
                       #ffffff 5.63, --bg-alt #f4f8ff 5.28, #fcfcfc 5.49, #eef3f8 5.04.
                       Value reuses #0d6f96, already introduced ad hoc for .news-tab.is-active,
                       rather than adding yet another near-identical hex.
       --cyan-display  LARGE text only (>=24px, or >=19px bold), where AA needs just 3:1 —
                       #ffffff 3.37, #f4f8ff 3.17. Keeps headline cyan visibly brighter than
                       body cyan; do NOT use it below those sizes.

     Large-text rule of thumb: 24px+ normal or 18.66px+ bold. If in doubt use --cyan-ink. */
  --cyan-ink:     #0d6f96;
  --cyan-display: #0f97c2;

  /* ---- 2. Neutrals / surfaces ---- */
  --white:        #ffffff;
  --ink:          #1a2233;   /* body text */
  --muted:        #5b6b85;   /* secondary text */
  --line:         #e4ecf7;   /* card borders */
  --field-border: #cdd9ec;   /* form inputs */
  --bg-alt:       #f4f8ff;   /* light section bg */

  /* ---- 3. Semantic aliases (use these in components) ---- */
  --color-text:    var(--ink);
  --color-heading: var(--navy-900);
  --color-accent:  var(--cyan-400);
  --glow-cyan:     rgba(90, 200, 255, .5);
  --border-glow:   rgba(120, 215, 255, .9);

  /* ---- 4. Gradients & glows (the cosmic theme, tweak here) ---- */
  --grad-header:  linear-gradient(90deg, var(--navy-900) 0%, var(--navy-800) 45%, var(--blue-700) 100%);
  /* Pure cosmic gradient (no image) — used on its own for the bare splash */
  --grad-cosmic:  radial-gradient(70% 55% at 50% 6%, rgba(110,185,230,.55) 0%, transparent 55%),
                  radial-gradient(120% 90% at 50% 100%, var(--blue-500) 0%, #1a5688 30%, var(--navy-700) 55%, var(--navy-850) 78%, var(--navy-950) 100%);
  /* Marketing background image, with the gradient kept beneath as fallback */
  --grad-splash:  url("../img/space-bg.webp") center / cover no-repeat,
                  var(--grad-cosmic);
  --grad-tile:    linear-gradient(180deg, rgba(155,215,245,.88) 0%, rgba(70,150,210,.70) 55%, rgba(30,95,160,.70) 100%);
  --grad-heading: linear-gradient(180deg, var(--cyan-200) 0%, var(--cyan-300) 55%, var(--cyan-500) 100%);
  /* Canonical Support-section gradient heading (Help Center, article quick-jump section titles, etc). */
  --grad-support-heading: linear-gradient(90deg, #05aeff 0%, #80cfff 100%);

  /* ---- 5. Layout ---- */
  --radius:    14px;
  --gutter:    24px;
  --container: 1200px;
  --font: "Montserrat", "Segoe UI", system-ui, -apple-system, helvetica, arial, sans-serif;
}

/* ---- Color utility classes (quick to apply on any element) ---- */
.text-white  { color: var(--white); }
.text-cyan   { color: var(--cyan-400); }
.text-navy   { color: var(--navy-900); }
.text-muted  { color: var(--muted); }
.bg-navy     { background: var(--navy-900); }
.bg-blue     { background: var(--blue-600); }
.bg-alt      { background: var(--bg-alt); }
.bg-cosmic   { background: var(--grad-splash); }

/* ---- Reset ---- */
*, *::before, *::after { box-sizing: border-box; }
body, h1, h2, h3, h4, p, ul, figure { margin: 0; }
/* The `hidden` attribute must always win — an explicit `display` rule would otherwise override it. */
[hidden] { display: none !important; }
ul { list-style: none; padding: 0; }
img { max-width: 100%; display: block; }
a { text-decoration: none; color: inherit; }

body {
  font-family: var(--font);
  color: var(--ink);
  line-height: 1.6;
  background: var(--white);
  overflow-x: hidden;   /* safety net against stray horizontal scroll */
}

/* ---- Accessibility ---- */
/* Visible keyboard focus (WCAG 2.4.7) — clear cyan ring on any control */
a:focus-visible,
button:focus-visible,
.tile:focus-visible,
.hub-action:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible {
  outline: 3px solid var(--cyan-400);
  outline-offset: 3px;
}
/* Respect reduced-motion (WCAG 2.3.3 / 2.2.2) */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
}
/* Screen-reader-only utility */
.sr-only {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0,0,0,0); white-space: nowrap; border: 0;
}

/* Skip link: hidden off-screen until keyboard-focused, then jumps above the header. */
.skip-link {
  position: absolute; top: -100px; left: 12px; z-index: 1000;
  background: var(--navy-900); color: #fff; padding: 12px 20px;
  border-radius: 0 0 8px 8px; font-weight: 700; text-decoration: none;
  transition: top .15s ease;
}
.skip-link:focus {
  top: 0; outline: 3px solid var(--blue-600); outline-offset: 2px;
}

/* Scroll-reveal: fade + rise. main.js adds .is-visible when the element scrolls into view. */
[data-reveal] {
  opacity: 0; transform: translateY(28px);
  transition: opacity .7s ease, transform .7s cubic-bezier(.2,.7,.2,1);
  will-change: opacity, transform;
}
[data-reveal].is-visible { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  [data-reveal] { opacity: 1; transform: none; }
}

/* ---- Layout helpers ---- */
.container {
  width: 100%;
  margin-inline: auto;
  /* Fluid: fills the viewport, side padding scales with screen width. */
  padding-inline: clamp(20px, 5vw, 80px);
}

/* ============================================================
   Custom 12-column grid (Bootstrap-style syntax, ~zero bloat)
   ============================================================ */
.row {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: var(--gutter);
}
.col-1  { grid-column: span 1; }
.col-2  { grid-column: span 2; }
.col-3  { grid-column: span 3; }
.col-4  { grid-column: span 4; }
.col-5  { grid-column: span 5; }
.col-6  { grid-column: span 6; }
.col-7  { grid-column: span 7; }
.col-8  { grid-column: span 8; }
.col-9  { grid-column: span 9; }
.col-10 { grid-column: span 10; }
.col-11 { grid-column: span 11; }
.col-12 { grid-column: span 12; }

/* Tablet */
@media (max-width: 992px) {
  .col-3, .col-4 { grid-column: span 6; }
}
/* Mobile — stack everything */
@media (max-width: 768px) {
  [class^="col-"] { grid-column: 1 / -1; }
}

/* ============================================================
   Buttons
   ============================================================ */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 12px 24px;
  border-radius: 8px;
  font-weight: 600;
  border: 2px solid transparent;
  cursor: pointer;
  transition: transform .15s ease, background .15s ease;
}
.btn:hover { transform: translateY(-1px); }
.btn--primary { background: var(--cyan-400); color: var(--navy-900); }
.btn--navy    { background: var(--navy-900); color: var(--white); }
.btn--navy:hover { background: var(--blue-700); }
.btn--ghost   { background: transparent; border-color: var(--white); color: var(--white); }
.btn--block   { width: 100%; }
/* Hero CTA — outlined by default, fills cyan on hover (per mockup annotation) */
.btn--hero {
  background: transparent; border-color: rgba(180,225,255,.85); color: var(--white);
  padding: 13px 30px;
}
.btn--hero:hover { background: var(--cyan-400); border-color: var(--cyan-400); color: var(--navy-900); }

/* ---- Gradient border — HUB Live Chat / phone buttons ONLY ----
   This glowing masked gradient ring is unique to the hub, so it stays distinct
   from the home hero / top-bar / product / login buttons (which keep their own
   solid/outlined borders defined in their own rules). */
.hub-action { position: relative; }
.hub-action::before {
  content: ""; position: absolute; inset: 0; border-radius: inherit; padding: 1.6px;
  background: linear-gradient(180deg, #005b95 0%, #44b0f4 40%, #83e5ff 80%, #82e5ff 100%);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
          mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor; mask-composite: exclude;
  pointer-events: none;
}

/* ============================================================
   Header / nav
   ============================================================ */
.site-header {
  position: absolute; top: 0; left: 0; right: 0; z-index: 50;
  background: transparent;
  border-bottom: none;
  box-shadow: none;
  color: var(--white);
}
/* Subtle top scrim so the transparent white nav stays readable on ANY page
   background (dark hero or a light/white utility page). */
.site-header::before {
  content: ""; position: absolute; top: 0; left: 0; right: 0; height: 120px;
  background: linear-gradient(180deg, rgba(7,29,57,.55), transparent);
  z-index: -1; pointer-events: none;
}
.site-header__inner {
  display: flex; align-items: center; justify-content: space-between;
  gap: 24px; padding-block: 14px;padding: 15px 10px 1px 10px;
}
.site-header__logo { display: flex; align-items: center; gap: 10px; }
.site-header__logo-img { height: 90px; width: auto; display: block; }
.logo-mark {
  width: 26px; height: 26px; border-radius: 50%;
  background: radial-gradient(circle at 30% 30%, var(--cyan-400), var(--blue-600));
}
.logo-text { font-weight: 700; letter-spacing: 2px; }

.site-nav { display: flex; align-items: center; gap: 20px; }
.site-nav__list { display: flex; gap: 16px; }
/* Without nowrap, a zero-margin fit at common 1366px widths shrinks these flex
   items and wraps the label to 2 lines instead of just not fitting. */
.site-nav__list a { font-size: 11px;  text-transform: uppercase; letter-spacing: .6px; white-space: nowrap; }
.site-nav__list a:hover, .site-nav__list a.is-active { opacity: 1; color: var(--cyan-400); }
/* Nav dropdown (Support) */
.has-dropdown { position: relative; }
.nav-caret { font-size: 9px; opacity: .8; }
.site-nav__dropdown {
  position: absolute; top: 100%; left: -8px; min-width: 200px;
  list-style: none; padding: 8px; background: #fff; border-radius: 10px;
  box-shadow: 0 16px 36px rgba(8,29,57,.24); z-index: 60;
  margin: 0; opacity: 0; visibility: hidden; transform: translateY(6px);
  transition: opacity .15s ease, transform .15s ease;
}
/* Transparent bridge across the visual gap so hover doesn't drop between the
   nav item and the panel (fixes the "disappears when you move toward it" bug). */
.site-nav__dropdown::before { content: ""; position: absolute; left: 0; right: 0; top: -16px; height: 16px; }
.has-dropdown:hover .site-nav__dropdown,
.has-dropdown:focus-within .site-nav__dropdown { opacity: 1; visibility: visible; transform: translateY(10px); }
.site-nav__dropdown a { display: block; padding: 9px 14px; border-radius: 8px; color: var(--navy-900); font-weight: 600; font-size: 13px; text-transform: none; letter-spacing: 0; white-space: nowrap; opacity: 1; }
.site-nav__dropdown a:hover { background: var(--bg-alt); color: var(--blue-700); }
.site-nav__actions { display: flex; align-items: center; gap: 18px; }
.site-nav__actions a { white-space: nowrap; }
/* Login = filled navy, Get Started = filled teal — both white text + 1px white border (per mockup) */
.site-nav__login {
  background: #173770; border: 1px solid var(--white); color: var(--white);
  border-radius: 8px; padding: 9px 26px;
}
.site-nav__login:hover { background: #0f2a59; border-color: var(--white); color: var(--white); }
.site-nav__cta {
  background: var(--brand-teal); color: var(--white);
  border: 1px solid var(--white);
  font-weight: 700; font-size: 14px;
  border-radius: 8px; padding: 10px 22px;
  transition: background .15s ease, transform .15s ease;
}
.site-nav__cta:hover { background: #00a3dd; color: var(--white); transform: translateY(-1px); }

.nav-toggle {
  display: none; flex-direction: column; gap: 5px;
  background: none; border: 0; cursor: pointer;
}
.nav-toggle span { width: 26px; height: 2px; background: var(--white); }

/* ============================================================
   Hero
   ============================================================ */
.hero {
  background: linear-gradient(135deg, var(--navy-900), var(--blue-700));
  color: var(--white);
  text-align: center;
  padding: 110px 0;
}
.hero__title { font-size: clamp(32px, 5vw, 56px); font-weight: 700; }
.hero__subtitle { max-width: 620px; margin: 18px auto 30px; opacity: .9; }
.hero__actions { display: flex; gap: 14px; justify-content: center; flex-wrap: wrap; }

/* ============================================================
   Sections
   ============================================================ */
.section { padding: 40px 0; }
.section--alt { background: var(--bg-alt); }
/* --band-bg lets a section recolour itself at runtime (Products: the carousel's
   active service drives it). Defaults to the flat brand blue everywhere else. */
.section--blue { background: var(--band-bg, #0b75bb); color: #fff; transition: background-color .55s ease; }
/* Glowing Michigan fiber-map on the right (screen blend drops the map's dark backing). */
.section--map { position: relative; overflow: hidden; background: linear-gradient(90deg, #0b75bb 0%, #173a7e 100%); }
.section--map::after {
  content: ""; position: absolute; right: -7%; top: 50%; transform: translateY(-50%);
  width: 54%; aspect-ratio: 943 / 1001; z-index: 0; pointer-events: none;
  background: url("../img/michigan-fiber-map.webp") center / contain no-repeat;
  mix-blend-mode: screen; opacity: .8;
}
.section--map > .container { position: relative; z-index: 1; }
@media (max-width: 768px) { .section--map::after { display: none; } }
.section__lead--light { color: var(--white); }
.section__title { text-align: center; font-size: 45px; margin-bottom: 12px; color: var(--navy-900); }
.section__title--left { text-align: left; }
.section__title--light { color: var(--white); }
.hl-blue { color: var(--brand-teal); }   /* two-tone heading accent — matches the band gradient teal */
/* Full-sentence gradient heading (teal -> navy, matches the "Born in Michigan" band) */
.section__title--grad {
  /* Bright cyan -> navy across the whole sentence, matching the mockup title. */
  background: linear-gradient(90deg, #71e5ff 0%, #003a70 100%);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  color: transparent;
}
.section__title .hl { color: var(--cyan-display); }  /* two-tone section titles (cyan leading words) */

/* ============================================================
   Owners & Developers
   ============================================================ */
.text-azure { color: #10b8ea; }
.btn--azure { background: #10b8ea; color: var(--navy-900); border-radius: 8px; }
.btn--azure:hover { background: #0ea3d0; }

/* 8-tile full-bleed service strip */
.service-tiles { display: grid; grid-template-columns: repeat(4, 1fr); gap: 0; }
.service-tile { position: relative; aspect-ratio: 4 / 3; overflow: hidden; display: flex; align-items: center; justify-content: center; }
.service-tile .media-ph { position: absolute; inset: 0; height: 100%; border-radius: 0; aspect-ratio: auto; }
/* Uniform blue tint over every tile image (per mockup). */
.service-tile::after { content: ""; position: absolute; inset: 0; background: linear-gradient(180deg, rgba(18,90,152,.5), rgba(12,64,120,.56)); }
/* Label centered in the middle of each image (both axes). */
.service-tile__label { position: relative; z-index: 2; color: #fff; font-size: clamp(20px, 1.9vw, 26px); font-weight: 800; text-align: center; padding: 0 14px; text-shadow: 0 1px 10px rgba(0,0,0,.5); }
@media (max-width: 992px) { .service-tiles { grid-template-columns: repeat(2, 1fr); } }

/* Badge circular glowing icon */
.badge__icon--ring { display: grid; place-items: center; width: 92px; height: 92px; padding: 0; border-radius: 50%; border: 1.5px solid rgba(120,215,255,.8); box-shadow: 0 0 24px rgba(90,200,255,.45); background: #f4faff; }
.badge__icon--ring svg { width: 46px; height: 46px; }

/* Essential Solutions — light 2-column */
/* Light band with a faint wave graphic behind the intro column (mockup). */
.essential-band { position: relative; overflow: hidden; background: linear-gradient(180deg, #f4fbff, #eaf6ff); }
.essential-band::before {
  content: ""; position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background: radial-gradient(120% 90% at -10% 60%, rgba(120,200,245,.22), transparent 55%),
              radial-gradient(80% 70% at 8% 20%, rgba(150,215,250,.18), transparent 60%);
}
/* Decorative glow-line strands along the left edge, behind the intro copy (per mockup). */
.essential-band__lines {
  position: absolute; left: 0; top: 0; bottom: 0; width: 1000px;
  z-index: 0; pointer-events: none;
  background: url("../img/essential-glow-lines.png") left / contain no-repeat;
  background: image-set(url("../img/essential-glow-lines.webp") type("image/webp"),
                         url("../img/essential-glow-lines.png") type("image/png")) left / contain no-repeat;
  background-size: auto;
}
.essential-band > .container { position: relative; z-index: 1; }
.essential { display: grid; grid-template-columns: 1fr 1.25fr; gap: 44px; align-items: center; }
.essential__intro { align-self: center; }
/* Narrower column than the site-wide 54px section title allows for — smaller size keeps it to 2 lines (per mockup). */
.essential__intro .section__title { font-size: 36px; }
.essential__list { display: grid; gap: 4px; background: #fff; border-radius: 20px; padding: 20px 34px; box-shadow: 0 18px 44px rgba(16,42,92,.10); }
.essential__item { padding: 20px 0; }
.essential__item h3 { color: var(--navy-900); font-size: 20px; margin-bottom: 6px; }
.essential__item p { color: #1a2b58; font-size: 14px; }
@media (max-width: 768px) { .essential { grid-template-columns: 1fr; } }

/* Manage Your Community — image + description list */
.manage-block { display: grid; grid-template-columns: 1.1fr 1fr; gap: 44px; align-items: center; }
/* Background-removed laptop cutout — floats free instead of sitting in a photo card. */
.manage-block__laptop { width: 100%; height: auto; display: block; margin-inline: auto; filter: drop-shadow(0 24px 40px rgba(8,29,57,.28));margin-left: -138px;  }
.manage-list { display: grid; gap: 22px; }
.manage-list h3 { color: var(--cyan-ink); font-size: 20px; margin-bottom: 4px; }
.manage-list p { color: #1a2b58; }
/* Residents-only: icon badge beside each item (mockup treatment; owners-developers'
   manage-list has no icon markup, so this never applies there). */
.manage-list__row { display: flex; gap: 16px; align-items: flex-start; }
.manage-list__icon { flex: 0 0 auto; display: grid; place-items: center; width: 46px; height: 46px; border-radius: 50%; color: #10b8ea; border: 1.5px solid rgba(16,184,234,.4); box-shadow: 0 0 14px rgba(16,184,234,.2); }
.manage-list__icon svg { width: 24px; height: 24px; }
/* Delivered badge art carries its own glow ring — drop the CSS ring/border for it. */
img.manage-list__icon { width: 74px; height: 74px; object-fit: contain; border: 0; border-radius: 0; box-shadow: none; }
.residents img.manage-list__icon { width: 104px; height: 104px; }
@media (max-width: 768px) { .manage-block { grid-template-columns: 1fr; } }

/* Residents "Manage your services" — copy left, laptop+phone composite right, both
   over the delivered portrait/city backdrop. The gradient stays as the base colour so
   the backdrop's angled panels have something to sit on at any aspect ratio. */
.manage-band-res {
  position: relative; color: #fff; overflow: hidden;
  background: linear-gradient(100deg, #0b2a49 0%, #114a75 52%, #1d719f 100%);
}
.manage-band-res::before {
  content: ""; position: absolute; inset: 0; z-index: 0;
  background: url("../img/residents-manage.png") center / cover no-repeat;
}
/* Scrim under the copy column only — the backdrop's portrait panel is too light on
   its right side for white text to hold up unaided. */
.manage-band-res::after {
  content: ""; position: absolute; inset: 0; z-index: 1;
  background: linear-gradient(90deg, rgba(7,32,58,.74) 0%, rgba(7,32,58,.42) 40%, rgba(7,32,58,0) 62%);
}
.manage-band-res > .container { position: relative; z-index: 2; }
.manage-band-res .manage-block { grid-template-columns: minmax(0, 46%); gap: 36px; }
.manage-band-res .manage-list { gap: 34px; }
.manage-band-res .manage-list h3 { color: #fff; font-size: 24px; }
.manage-band-res .manage-list p { color: rgba(255,255,255,.9); }
/* The artwork is the background now, so the band needs its own vertical rhythm rather than
   being sized by a foreground image bleeding off the bottom edge. */
.manage-band-res { min-height: 560px; display: flex; align-items: center; }
@media (max-width: 768px) {
  .manage-band-res .manage-block { grid-template-columns: 1fr; }
  /* Stacked, the copy spans the full width and the backdrop's bright city panel runs
     straight through it — the directional scrim can't help, so cover the whole band. */
  .manage-band-res::after { background: rgba(7,32,58,.74); }
}

/* Testimonial carousel arrows — left-aligned under the quote column (per mockup) */
.testimonial__nav { display: flex; gap: 14px; justify-content: flex-start; margin-top: 24px; }
.testimonial__arrow { width: 44px; height: 44px; border-radius: 50%; background: var(--navy-900); color: #fff; border: 0; cursor: pointer; font-size: 18px; }
.section__lead { text-align: center; color: var(--muted); margin-bottom: 40px; }
.section__lead--strong { color: var(--navy-900); font-weight: 700; }
/* Compound selector so the light variant wins over the base .section__lead color above */
.section__lead.section__lead--light { color: var(--white); }
.section__title + .section__lead { margin-top: 0; }

/* ============================================================
   Home — Hero (cosmic)
   ============================================================ */
/* Hero + Explore share ONE cosmic background living on the wrapper, so the hero
   scene continues behind the second section (no separate bg / no seam). */
.home-cosmic {
  position: relative;
  overflow: hidden;
  perspective: 1600px;
  background: radial-gradient(110% 60% at 50% 0%, #1b558a 0%, #123f6b 38%, #0a3455 66%, #01456c 100%);
}
/* Scroll-zoom wrapper: separate layer from .hero-planet's own idle tilt animation so
   the two transforms don't fight over the same property (a CSS animation on `transform`
   always wins over a same-element inline `transform`, which would otherwise silently eat
   the JS-driven scroll zoom). preserve-3d passes .home-cosmic's perspective through to
   .hero-planet's rotateX/Y so the tilt keeps its depth instead of flattening out. */
.hero-planet-zoom {
  position: absolute; inset: 0; z-index: -1;
  transform-style: preserve-3d;
  will-change: transform;
}
/* Planet is its own layer (not a flat background) so it can tilt in 3D,
   like a slowly rotating globe, without disturbing the sky/stars above it.
   Oversized + perspective-tilted, clipped by .home-cosmic's overflow:hidden.

   The 168%/-34% oversize is driven by the tilt depth, not picked for looks. A perspective
   rotateX pivoting at the bottom foreshortens the layer's top edge — it recedes AND its
   corners pull inward — so at the 22deg rest tilt a 116% layer left its own rectangular
   edge inside the viewport: a hard diagonal seam down both sides and a horizontal band
   under the nav, with .home-cosmic's gradient showing through. Measured at this viewport:
   140% still seams, 168% covers. If the tilt in the keyframes below is ever increased,
   re-check the corners — coverage is a function of that angle.
   background-position-y is 50% (was 37%) because the larger box makes `cover` scale the
   image up, which drops the horizon off-screen; 50% puts the curve back in the lower band. */
.hero-planet {
  position: absolute;
  top: -34%; left: -34%; width: 168%; height: 168%;
  background:
    url("../img/hero-home.png") center top / cover no-repeat;
  background:
    image-set(url("../img/hero-home.webp") type("image/webp"),
              url("../img/hero-home.png") type("image/png")) center top / cover no-repeat;
  background-position: 1% 50%;
  transform-style: preserve-3d;
  backface-visibility: hidden;
  will-change: transform;
  transform-origin: 50% 100%;
  animation: hero-planet-rollback 22s ease-in-out infinite;
}
/* Backward roll, not a side-to-side wobble. The old keyframes swung rotateY -7deg -> +7deg,
   which reads as the planet shaking its head; the ask is for it to pitch AWAY, like a globe
   rotating backwards under you.
     - rotateX only, always positive: positive rotateX pushes the far edge away from the
       viewer, so the horizon line lies back and the surface opens up. No rotateY at all.
     - transform-origin at 50% 100% pins the pivot to the bottom of the layer, where the
       planet's mass actually is. Pivoting at the default center would slide the horizon
       curve up and down the viewport instead of rotating it in place.
     - translateY + scale ride along with the tilt: as the surface lies back it settles
       slightly down and grows, which is what a receding sphere does. This is the part that
       sells "rotating" rather than "hinging".
   Kept entirely on `transform` (no background-position) so it stays on the compositor —
   .hero-planet is a 116% layer, and repainting that every frame would visibly stutter.

   Starts AT the back tilt: 0% is the deepest rotateX, so the very first painted frame is
   already rolled back rather than easing into it from flat. The cycle then drifts forward over
   62% and snaps back over the remaining 38% — the quicker, more legible motion is the backward
   one, and ease-in-out dwells on the 0%/100% extreme, so tilted-back is the state it rests in. */
@keyframes hero-planet-rollback {
  0%   { transform: rotateX(22deg) translate3d(0, 2.4%, 0) scale(1.10); }
  62%  { transform: rotateX(7deg)  translate3d(0, 0, 0)    scale(1.03); }
  100% { transform: rotateX(22deg) translate3d(0, 2.4%, 0) scale(1.10); }
}
@media (prefers-reduced-motion: reduce) { .hero-planet { animation: none; } }
.home-hero {
  position: relative; overflow: hidden;
  color: var(--white);
  padding: 140px 0 210px;
  min-height: 760px;            /* taller, so the planet curve fills the lower band like the mockup */
  background: none;             /* cosmic bg is on .home-cosmic wrapper now */
}
.home-hero__canvas {
  position: absolute; inset: 0; width: 100%; height: 100%;
  z-index: 1; pointer-events: none;
}
.home-hero__glow {
  position: absolute; left: 50%; bottom: -60%; transform: translateX(-50%);
  width: 140%; aspect-ratio: 1; border-radius: 50%; pointer-events: none;
  background: radial-gradient(circle at 50% 0%, rgba(80,180,255,.45), transparent 55%);
  box-shadow: 0 0 120px 30px rgba(80,180,255,.25);
}
.home-hero__inner { position: relative; z-index: 2; }

/* ---- Hero stars: sparkle cluster layered above the planet curve, twinkling INDEPENDENTLY.
        Previously one <img> of stars.png carried a single animation, so all 8 sparkles were
        pixels in one bitmap pulsing together — no amount of CSS can desync pixels inside one
        image. Each star is now its own element spriting that same png: .hero-stars is the
        image-sized stage (aspect-ratio matches stars.png's 2102x635 so the % coordinates below
        stay correct at any width), and each .hero-star is a small window onto one sparkle.

        The nth-child block is GENERATED, not hand-tuned. Star centres came from scanning the
        png's alpha channel; each rule then solves CSS's percentage background-position
        (offset = p% x (box - image)) so the sparkle lands dead-centre in its box:
            p = 100 x (b/2 - f) / (b - 1),  b = box/image, f = star centre as a fraction
        Box is 3.4x the bright core so the tapered beams are not clipped. If stars.png is ever
        re-exported, re-scan and regenerate — these numbers are specific to that file.

        Delays are NEGATIVE on purpose. A positive delay leaves the element at its untransformed
        style until the clock catches up, so on load every delayed star sat at full opacity and
        then visibly snapped into the cycle. A negative delay starts the animation already that
        far in, so the field is out of phase from the first painted frame with no pop. Durations
        (2.9-6.1s) share no common factor, so the set does not drift back into lockstep. ---- */
.hero-stars {
  position: absolute; top: 0; left: 0; width: 100%;
  aspect-ratio: 2102 / 635;
  z-index: 1; pointer-events: none;
}
.hero-star {
  position: absolute;
  background-image: url("../img/stars.png");
  background-repeat: no-repeat;
  /* opacity + scale only — both composite, so 8 concurrent animations stay off the main thread.
     The old rule animated filter: brightness(), which repaints; that is fine for one layer and
     wasteful for eight. */
  animation-name: hero-star-twinkle;
  animation-timing-function: ease-in-out;
  animation-iteration-count: infinite;
  animation-direction: alternate;
  will-change: opacity, transform;
}
@keyframes hero-star-twinkle {
  0%   { opacity: .35; transform: scale(.82); }
  100% { opacity: 1;   transform: scale(1.06); }
}
/* generated — see note above */
.hero-star:nth-child(1) { left: 65.202%; top:  6.951%; width: 10.676%; height: 35.339%; background-size:  936.72% 282.98%; background-position: 72.995% 10.749%; animation-duration: 4.3s; animation-delay: 0s;   }
.hero-star:nth-child(2) { left: 89.804%; top: 66.069%; width:  8.411%; height: 27.843%; background-size: 1188.91% 359.16%; background-position: 98.052% 91.562%; animation-duration: 3.1s; animation-delay: -1.7s; }
.hero-star:nth-child(3) { left:  8.061%; top: 13.870%; width:  7.117%; height: 23.559%; background-size: 1405.08% 424.47%; background-position:  8.679% 18.145%; animation-duration: 5.7s; animation-delay: -0.6s; }
.hero-star:nth-child(4) { left: 80.230%; top: 22.095%; width:  7.441%; height: 24.630%; background-size: 1343.99% 406.01%; background-position: 86.679% 29.315%; animation-duration: 3.7s; animation-delay: -2.9s; }
.hero-star:nth-child(5) { left: 85.168%; top: 74.662%; width:  5.823%; height: 19.276%; background-size: 1717.32% 518.79%; background-position: 90.435% 92.490%; animation-duration: 6.1s; animation-delay: -1.1s; }
.hero-star:nth-child(6) { left: 57.490%; top: 36.698%; width:  5.500%; height: 18.205%; background-size: 1818.34% 549.31%; background-position: 60.836% 44.865%; animation-duration: 2.9s; animation-delay: -3.6s; }
.hero-star:nth-child(7) { left:  1.434%; top: 30.529%; width:  4.853%; height: 16.063%; background-size: 2060.78% 622.55%; background-position:  1.507% 36.371%; animation-duration: 4.9s; animation-delay: -2.2s; }
.hero-star:nth-child(8) { left: 70.615%; top: 39.264%; width:  4.529%; height: 14.992%; background-size: 2207.98% 667.02%; background-position: 73.965% 46.189%; animation-duration: 3.4s; animation-delay: -0.9s; }
@media (prefers-reduced-motion: reduce) { .hero-star { animation: none; opacity: .9; } }

/* ---- Hero meteors: streak in from the distant sky toward the planet,
        growing (back -> front depth) and fading out on arrival. ---- */
.hero-meteors { position: absolute; inset: 0; z-index: 1; pointer-events: none; overflow: hidden; }
.meteor {
  position: absolute;
  width: 2px; height: 110px;
  border-radius: 2px;
  /* bright head at the leading (bottom) end, fading tail behind it */
  background: linear-gradient(to bottom, rgba(150,215,255,0) 0%, rgba(170,222,255,.85) 85%, #ffffff 100%);
  filter: drop-shadow(0 0 6px rgba(120,200,255,.95));
  opacity: 0;
  transform: translate3d(0,0,0) rotate(var(--ang)) scale(.35);
  will-change: transform, opacity;
}
/* Meteor 1 — upper-center sky, dives down-right into the planet */
.meteor--1 { top: 3%; left: 50%; --ang: -34deg; --dx: 230px; --dy: 360px;
  animation: meteor-fall 7s linear 1s infinite; }
/* Meteor 2 — upper-right sky, dives down-left into the planet (offset timing) */
.meteor--2 { top: 6%; left: 82%; --ang: 40deg; --dx: -300px; --dy: 340px;
  animation: meteor-fall 8.5s linear 4.2s infinite; }
@keyframes meteor-fall {
  0%   { opacity: 0; transform: translate3d(0,0,0) rotate(var(--ang)) scale(.3); }
  8%   { opacity: 1; }
  34%  { opacity: 0; transform: translate3d(var(--dx), var(--dy), 0) rotate(var(--ang)) scale(1.2); }
  100% { opacity: 0; transform: translate3d(var(--dx), var(--dy), 0) rotate(var(--ang)) scale(1.2); }
}
@media (prefers-reduced-motion: reduce) { .meteor { animation: none; } }
/* White words are light; the cyan .hl words are bold (per mockup). */
.home-hero__title { padding-top: 9%; font-size: clamp(26px, 4.4vw, 50px); font-weight: 300; line-height: 1.2; overflow-wrap: break-word; }
@media (max-width: 600px) { .home-hero { padding: 96px 0 90px; } .home-hero__title { font-size: 24px; } }
.home-hero__title .hl { color: var(--cyan-400); font-weight: 700; }
.home-hero__subtitle { max-width: 560px; margin: 22px 0 32px; opacity: .9; }
.home-hero__subtitle em { font-style: italic; font-weight: 600; opacity: 1; }

.availability { display: flex; gap: 12px; max-width: 560px; flex-wrap: wrap; }
.availability input {
  flex: 1 1 280px; padding: 14px 18px; border-radius: 999px;
  border: 1px solid rgba(255,255,255,.4); background: rgba(255,255,255,.12);
  color: var(--white); font: inherit;
}
.availability input::placeholder { color: rgba(255,255,255,.7); }
.availability input:focus { outline: none; background: rgba(255,255,255,.2); }

/* ============================================================
   Home — Services row (8 icons)
   ============================================================ */
/* Cosmic section that continues the hero: white heading on the starfield, the
   icon row sits in a full-width WHITE bar, and the cosmic band shows again below
   it (where the hover description card appears) — per the mockup. */
.services-strip {
  padding: 40px 0 200px;
  background: none;             /* sits on the shared .home-cosmic background */
  color: #fff;
  position: relative; overflow: visible;
}
.services-strip .section__title { color: #fff; margin-bottom: 26px; }
/* Full-bleed white icon bar (the "nav bar"). Overflow stays visible so the
   hover card can drop below the bar onto the cosmic band. */
.services-bar { background: #fff; box-shadow: 0 10px 30px rgba(4,16,40,.35); }
/* New PNG service icons (glow baked into the asset) */
.services-row__iconimg { width: 100px; height: 100px; object-fit: contain; display: block; }
.services-row {
  display: grid; grid-template-columns: repeat(8, 1fr); gap: 16px;
  max-width: var(--container); margin-inline: auto;
  padding: 26px clamp(20px, 5vw, 80px);
}
.services-row__item {
  position: relative;
  display: flex; flex-direction: column; align-items: center; gap: 10px;
  text-align: center; color: var(--navy-900); cursor: pointer;
  transition: transform .15s ease, color .15s ease;
}
/* Blue line-art icons with a soft cyan glow (per mockup) on the white section. */
.services-row__icon { color: var(--blue-600); filter: drop-shadow(0 0 7px rgba(60,180,255,.55)); }
/* Inline icons (Security, Access, IoT): add the glowing circle ring so they
   match the delivered PNG icons that already have one. */
.services-row__icon:has(svg) {
  display: inline-grid; place-items: center;
  width: 62px; height: 62px; border-radius: 50%;
  box-shadow: inset 0 0 0 1.6px rgba(120,205,255,.6), 0 0 20px rgba(90,200,255,.35);
}
.services-row__item:hover,
.services-row__item:focus-visible { transform: translateY(-4px); color: var(--blue-600); outline: none; }

/* Description card — revealed on hover/focus (per mockup). Solid cyan, left-aligned,
   no pointer triangle, a divider above the text links, and sparkle stars bottom-right. */
.services-row__pop {
  position: absolute; top: calc(100% + 16px); left: 50%;
  transform: translateX(-50%) translateY(6px);
  width: 262px; z-index: 20;
  display: flex; flex-direction: column; gap: 6px; text-align: left;
  /* Deep bottom padding is deliberate: the mockup's card is 263px tall against ~202px of content,
     and that surplus is empty space the sparkles sit in. At 26px they landed on the second link;
     64px clears the upper sparkle, whose glow reaches 59px above the card's bottom edge. */
  padding: 22px 24px 64px; border-radius: 12px;
  background: #71e5ff;   /* solid bright cyan per mockup */
  color: var(--navy-900);
  box-shadow: 0 18px 44px rgba(16,42,92,.28);
  /* Two sparkles in the lower-right corner, cropped from the hero's stars.png rather than drawn.
     This was a hand-authored SVG data URI of two Bezier star paths — hard-edged solid white
     points, where the mockup's are soft lens flares: a bright core with four diffuse tapering
     beams. Reusing the delivered hero art gets the exact character instead of approximating it.

     Geometry is measured, not eyeballed. The mockup's card is 272x263 — near 1:1 with our 262 —
     so its pixels are read directly: larger sparkle centred 49px in / 30px up, smaller 30px in /
     48px up, with visible spans of 33px and 21px. The source crop radius for each was solved by
     matching glow profile (span at four luminance thresholds, composited over this card colour)
     against the mockup's, landing within 1px at every threshold. A first pass sized them ~2.1x
     too large, which bloomed the two into a single haze.

     Those card-relative offsets are baked into the 68x62 asset, so it anchors flush to the corner. */
  background-image: url("../img/pop-sparkles.webp");
  background-repeat: no-repeat; background-position: right 0 bottom 0;
  opacity: 0; visibility: hidden; pointer-events: none;
  transition: opacity .18s ease, transform .18s ease;
}
.services-row__item:hover .services-row__pop,
.services-row__item:focus-within .services-row__pop {
  opacity: 1; visibility: visible; pointer-events: auto;
  transform: translateX(-50%) translateY(0);
}
.services-row__pop-title { font-weight: 800; font-size: 17px; line-height: 1.2; color: var(--navy-900); }
.services-row__pop-desc  { font-size: 13px; color: rgba(6,32,64,.85); }
/* Divider + text links (not buttons) per mockup. */
.services-row__pop-actions {
  display: flex; flex-direction: column; gap: 8px; margin-top: 12px; padding-top: 14px;
  border-top: 1.5px solid rgba(6,42,80,.35);
}
.pop-btn {
  display: inline-block; font-size: 14px; font-weight: 800; color: var(--navy-900);
  background: none; border: 0; padding: 0; text-align: left;
  transition: color .15s ease;
}
.pop-btn:hover { color: var(--blue-700); }
/* Hidden wherever hover is UNAVAILABLE, at any width — not just below 768px. A tablet in
   landscape (1024px, touch) previously fell between the two mechanisms: too wide for the panel,
   no hover for the popup, so service descriptions were unreachable entirely. (hover: none) is the
   real condition; the width clause stays for a narrow desktop window, which has hover but no room.
   The popup cannot be made to work on touch anyway — iOS Safari does not focus non-form elements
   on tap, so :focus-within never fires. */
@media (hover: none), (max-width: 768px) { .services-row__pop { display: none; } }
/* The touch replacement for those hover popups: one shared sheet pinned to the bottom of the
   viewport, filled by main.js from the tapped tile. Fixed positioning is safe here because the
   sheet lives outside the tiles — a transformed ancestor would otherwise capture it. Hidden by the
   [hidden] attribute, so with no JS it simply never appears and nothing is left half-open. */
.services-sheet {
  /* IN FLOW, not fixed. Pinned to the bottom of the viewport it covered the last grid row, so
     tapping those tiles hit the sheet instead of the tile (IoT and IT Support both opened Access
     Control). Sitting below the grid it overlaps nothing at all, which is the whole point — every
     tile stays tappable no matter which one is open. main.js scrolls it into view on open. */
  margin: 20px 16px 4px;
  /* relative, or the absolutely-positioned close button anchors to an ancestor instead — it landed
     at the top of the white services bar once this stopped being position:fixed. */
  position: relative;
  display: flex; flex-direction: column; gap: 6px;
  padding: 18px 44px 18px 20px;
  background: #71e5ff; color: var(--navy-900);
  border-radius: 14px; box-shadow: 0 12px 30px rgba(6,30,60,.24);
  text-align: left;
}
.services-sheet[hidden] { display: none; }
.services-sheet__close {
  position: absolute; top: 8px; right: 8px;
  width: 34px; height: 34px; min-width: 34px;   /* >=24px target (WCAG 2.5.8) */
  display: grid; place-items: center;
  background: none; border: 0; cursor: pointer;
  font-size: 24px; line-height: 1; color: var(--navy-900);
}
.services-sheet__title { font-weight: 800; font-size: 17px; line-height: 1.2; }
.services-sheet__desc  { font-size: 13px; color: rgba(6,32,64,.85); }
.services-sheet__links {
  display: flex; flex-direction: column; gap: 8px;
  margin-top: 10px; padding-top: 12px; border-top: 1.5px solid rgba(6,42,80,.35);
}
/* Positioning per Jose's direction. */
@media (max-width: 768px) {
  .services-sheet {
    position: absolute;
    margin-top: -100%;
    width: stretch;
  }
}
/* Mirror of the popup rule: the panel is hidden only where the popup can actually be used —
   hover available AND enough width. Anything else (incl. a 1024px touch tablet) gets the panel. */
@media (hover: hover) and (min-width: 769px) { .services-sheet { display: none !important; } }
.services-row__icon svg { width: 48px; height: 48px; }
.services-row__label { font-size: 13px; font-weight: 600; color: var(--navy-900); }
@media (max-width: 992px) { .services-row { grid-template-columns: repeat(4, 1fr); row-gap: 28px; } }
@media (max-width: 560px) { .services-row { grid-template-columns: repeat(2, 1fr); } }

/* ============================================================
   Home — Audience cards
   ============================================================ */
/* Photo + a SEPARATE rounded outlined "button" below it (per mockup) */
.audience-card {
  display: flex; flex-direction: column; gap: 16px; height: 100%;
}
.audience-card__media {
  display: block; aspect-ratio: 16 / 10; overflow: hidden;
  border-radius: var(--radius);
  background: linear-gradient(135deg, #4a90c9, #1e6fd0) center/cover no-repeat;
  box-shadow: 0 10px 28px rgba(16,42,92,.14);
  transition: box-shadow .2s ease;
}
.audience-card:hover .audience-card__media { box-shadow: 0 16px 38px rgba(16,42,92,.22); }
.audience-card__label {
  margin-top: auto;            /* keep all three buttons bottom-aligned */
  display: flex; align-items: center; justify-content: center;
  min-height: 56px; padding: 12px 18px; text-align: center;
  border-radius: 12px;
  /* Gradient border (cyan bottom-left → navy right) over a white fill, per mockup. */
  border: 2px solid transparent;
  background:
    linear-gradient(#fff, #fff) padding-box,
    linear-gradient(115deg, #c9f1fd 0%, #62dcf8 26%, #2a93d2 60%, #043f74 100%) border-box;
  box-shadow: 0 6px 16px rgba(16,42,92,.10);
  font-weight: 700; color: var(--navy-900);
  transition: background .15s ease, box-shadow .15s ease;
}
.audience-card:hover .audience-card__label {
  background:
    linear-gradient(#f3fbff, #f3fbff) padding-box,
    linear-gradient(115deg, #c9f1fd 0%, #62dcf8 26%, #2a93d2 60%, #043f74 100%) border-box;
  box-shadow: 0 10px 24px rgba(16,42,92,.16);
}

/* ============================================================
   Home — Feature blurbs
   ============================================================ */
.feature { padding: 16px 0; }
.feature__title { color: #023770; text-transform: uppercase; font-size: 15px; letter-spacing: .5px; margin-bottom: 8px; }
.feature__body { color: var(--muted); font-size: 15px; }

/* ============================================================
   Home — Born in Michigan band
   ============================================================ */
/* Per mockup: SOLID teal background (no gradient). Copy is centered in the
   left column; the map sits in a separate dark rounded panel on the right. */
/* z-index is load-bearing: [data-reveal] sets will-change:opacity,transform, which makes
   this section a stacking context, so .michigan__art's own z-index can't lift it above
   the NEXT section — the map's overhang got painted over and looked chopped flat at the
   band edge. Raising the whole section fixes it. */
/* Band background is a DEEPER teal than --brand-teal (#008bbf). At #008bbf every piece of text on
   this band failed AA: white 3.85:1, the #f2f9fc paragraph 3.62:1, and the title's text-shadow
   2.85:1 — all needing 4.5. The token itself is unchanged because it is also the two-tone heading
   accent elsewhere; only this band is darkened. #00648a puts white at 6.6:1. */
.michigan { background: #00648a; color: var(--white); position: relative; z-index: 2; overflow: visible; }
.michigan__inner { display: grid; grid-template-columns: 1.1fr .9fr; gap: 40px; align-items: center; padding: 70px 20px; }
.michigan__copy { text-align: center; display: flex; flex-direction: column; align-items: center; }
/* Header is light cyan with a subtle darker-teal emboss (per mockup), not white. */
/* Shadow darkened from rgba(0,66,98,.55): at 55% over the old band it resolved to ~#007cac, only
   2.85:1 against the #6dd7ff type, which axe flags as the shadow doing the work of a background.
   Against the new band this resolves to ~#002738 and 9.4:1. */
.michigan__title { font-size: 30px; margin-bottom: 16px; color: #6dd7ff; text-shadow: 0 2px 3px rgba(0,28,42,.85); }
/* No opacity: .95 knocked the paragraph off full white and cost contrast for no visible gain. */
.michigan__copy p { margin-bottom: 24px; }
/* Michigan fiber-map art — a square card that floats over the section below.
   Measured off the mockup at 1366 (which maps 1:1): 450x447, ~62px of overhang past
   the band, ending ~44px from the page edge. The asset is 691x675, so the card has to
   stay square — landscape + `cover` crops the state's ends off. */
.michigan__art {
  align-self: center; justify-self: end;
  width: 450px; max-width: 100%; aspect-ratio: 691 / 675;
  border-radius: 24px; position: relative; z-index: 3;
  /* .michigan__inner runs full-bleed with 20px padding, so a POSITIVE right margin is
     what lands the card 44px from the page edge as the mockup has it; a negative one
     pushed it past the viewport and added a horizontal scrollbar. */
  margin: 30px 24px -132px 0;
  background: #062a4d url("../img/michigan-map.webp") center / cover no-repeat;
  box-shadow: 0 22px 52px rgba(0,0,0,.32);
  animation: mi-float 7s ease-in-out infinite;
}
/* Slow idle drift so it reads as floating rather than pinned. The global
   prefers-reduced-motion block flattens this. */
@keyframes mi-float {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-10px); }
}
@media (max-width: 768px) {
  .michigan__inner { grid-template-columns: 1fr; }
  /* -100 (not -60) so it still overhangs ~30px: the card is square now, so the value
     tuned for the old 300px-tall card left it sitting short of the boundary. */
  .michigan__art { width: 100%; justify-self: center; margin: 20px 0 -100px; }
}

/* ============================================================
   Home — Testimonial
   ============================================================ */
/* Light-blue backdrop behind the card (per mockup). */
.testimonial-section { background: linear-gradient(180deg, #eaf6ff 0%, #cdecff 100%); }
/* Residents' own mockup uses a teal backdrop here instead — scoped so home/owners-developers/
   business keep their light-blue version. */
.residents .testimonial-section { background: #29809b; }
/* Off-white card wrapping the whole testimonial (media + heading + quote + nav). */
.testimonial-card {
  background: #f9f9f9; border-radius: 28px; padding: 48px;
  box-shadow: 0 20px 50px rgba(16,42,92,.14);
}
.testimonial { display: grid; grid-template-columns: 1fr 1fr; gap: 36px; align-items: center; }
.testimonial__body { display: flex; flex-direction: column; }
.testimonial__title { text-align: left; font-size: 30px; margin-bottom: 18px; }
.testimonial__media {
  position: relative; aspect-ratio: 16/10; border-radius: var(--radius);
  /* Video poster thumbnail + slight dark overlay so the play button stays legible.
     Anchored left: the baked-in name/title caption sits flush against the photo's
     left edge, so a center-cropped cover background clips it — pin left instead
     and let any cover-crop overflow come off the empty right side. */
  background:
    linear-gradient(rgba(8,29,57,.25), rgba(8,29,57,.38)),
    #16324a url("../img/thumb-video-test.webp") left center / cover no-repeat;
  overflow: hidden;
  display: flex; align-items: center; justify-content: center;
  box-shadow: 0 16px 40px rgba(16,42,92,.20);
}
.testimonial__quote p { font-size: 18px; color: var(--ink); margin-bottom: 16px; }
.testimonial__quote cite { font-weight: 700; color: var(--navy-900); font-style: normal; }
@media (max-width: 768px) { .testimonial { grid-template-columns: 1fr; } }

/* ============================================================
   Home — Partners
   ============================================================ */
.partners { background: var(--brand-teal); color: var(--white); padding: 70px 0; }
/* Thin underline rule below the heading (per mockup) — scoped here, not on the
   shared --light modifier, since News & Insights reuses that same class without one. */
.partners .section__title { position: relative; padding-bottom: 18px; }
.partners .section__title::after {
  content: ""; position: absolute; left: 50%; bottom: 0; transform: translateX(-50%);
  width: 64px; height: 2px; background: rgba(255,255,255,.7);
}
/* Partner logos composite (white logos on transparent) */
.partners__logos { display: block; width: 100%; max-width: 980px; height: auto; margin: 28px auto 0; }
.partners__grid { display: grid; grid-template-columns: repeat(5, 1fr); gap: 28px; margin-top: 20px; }
.partners__item {
  display: flex; align-items: center; justify-content: center;
  min-height: 64px; padding: 12px; text-align: center;
  background: transparent;
  font-weight: 700; font-size: 14px; letter-spacing: .5px; opacity: .92;
}
@media (max-width: 768px) { .partners__grid { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 480px) { .partners__grid { grid-template-columns: repeat(2, 1fr); } }

/* ============================================================
   Home — News & Insights
   ============================================================ */
/* Per mockup: vertical gradient, teal -> white (top to bottom). */
.news { background: linear-gradient(180deg, #82d3f1 0%, #ffffff 100%); color: var(--white); padding: 70px 0; }
.news-stack { display: grid; gap: 24px; align-content: stretch; }
.news-stack .news-card { min-height: 0; }
/* Scrollable teaser carousel: arrows scroll the track; next card peeks on the right. */
.news-carousel__track {
  display: flex; gap: 20px; align-items: stretch;
  overflow-x: auto; scroll-snap-type: x mandatory; scroll-behavior: smooth;
  scrollbar-width: none; -ms-overflow-style: none;
  padding-bottom: 4px;
}
.news-carousel__track::-webkit-scrollbar { display: none; }
/* Featured carousel: the main card is full and centred; via data-peek="quarter"
   the previous card shows ~a quarter on the left and the next ~a half on the right. */
.news-carousel__track > .news-card { flex: 0 0 calc(54% - 10px); aspect-ratio: 2 / 1; scroll-snap-align: center; }
.news-carousel__foot { display: flex; align-items: center; justify-content: space-between; gap: 16px; margin-top: 24px; flex-wrap: wrap; }
.news__viewall { color: #fff; font-weight: 700; letter-spacing: .3px; }
.news__viewall:hover { color: var(--navy-900); }
.news-carousel__nav { display: flex; gap: 12px; }
.carousel-arrow {
  width: 46px; height: 46px; border-radius: 50%; cursor: pointer;
  background: rgba(255,255,255,.9); color: var(--blue-700); border: 0; font-size: 22px; line-height: 1;
  transition: background .15s ease, transform .15s ease;
}
.carousel-arrow:hover { background: #fff; transform: translateY(-1px); }
.carousel-arrow:disabled { opacity: .4; cursor: default; transform: none; }
@media (max-width: 768px) {
  .news-carousel__track > .news-card { flex-basis: 86%; }
}
.news-card {
  display: block; position: relative; overflow: hidden;
  border-radius: var(--radius); color: var(--white);
  min-height: 280px;
  box-shadow: 0 12px 30px rgba(8,29,57,.3);
}
.news-card__media { position: absolute; inset: 0; background: linear-gradient(135deg, #1e6fd0, #0c3a63) center/cover; }
/* Per mockup annotation: a blue filter tints the peeking cards and "dissolves when
   it is the main image" — i.e. the centered/active card shows full colour. */
.news-card--feature .news-card__media::after {
  content:""; position:absolute; inset:0;
  background: linear-gradient(180deg, rgba(12,92,150,.55) 0%, rgba(6,38,78,.78) 100%);
  transition: opacity .45s ease;
}
.news-card--feature.is-active .news-card__media::after,
.news-card--feature:hover .news-card__media::after,
.news-card--feature:focus-visible .news-card__media::after { opacity: 0; }
/* A permanent soft bottom gradient keeps the overlaid text legible when full-colour. */
.news-card--feature .news-card__media::before {
  content:""; position:absolute; inset:0; z-index:1;
  background: linear-gradient(0deg, rgba(4,18,38,.72) 0%, rgba(4,18,38,0) 45%);
}
.news-card__body { position: relative; z-index: 2; display: flex; flex-direction: column; gap: 6px; padding: 28px; height: 100%; justify-content: flex-end; }
/* Keep text legible once the filter dissolves */
.news-card--feature .news-card__body { text-shadow: 0 1px 12px rgba(4,18,38,.85); }
.news-card__eyebrow { font-size: 13px; opacity: .85; text-transform: uppercase; letter-spacing: 1px; }
.news-card__title { font-size: 26px; font-weight: 700; }
.news-card__meta { font-size: 14px; opacity: .85; }
.news-card__more { margin-top: 8px; font-weight: 600; display: flex; align-items: center; gap: 10px; }
.news-card__more-icon {
  display: inline-flex; align-items: center; justify-content: center;
  width: 30px; height: 30px; border-radius: 50%; border: 1.5px solid currentColor;
  flex-shrink: 0;
}
.news-card--feature .news-card__more { align-self: flex-end; }
.news-card--plain { background: var(--white); color: var(--ink); }
.news-card--plain .news-card__media { position: relative; height: 150px; inset: auto; }
.news-card--plain .news-card__body { justify-content: flex-start; }
.news-card--plain .news-card__title { font-size: 18px; color: var(--navy-900); }
.news-card--plain .news-card__more { color: var(--blue-600); }

/* ============================================================
   Home — Contact block
   ============================================================ */
.contact-block {
  position: relative; overflow: hidden;
  padding: 70px 0; color: var(--white);
  background: linear-gradient(135deg, var(--navy-900), var(--blue-700)); /* fallback under the image */
}
/* Dedicated contact background (already oriented, glow at top — no flip/overlay). */
.contact-block::before {
  content: ""; position: absolute; inset: 0; z-index: 0;
  background: url("../img/contact-background.webp") center / cover no-repeat;
}
.contact-block > .container { position: relative; z-index: 1; }
.contact-block__office h2 { color: var(--white); margin-bottom: 16px; }
.contact-block__office p { opacity: .9; margin-bottom: 8px;max-width: 226px; }
.contact-block__office-label { font-weight: 700; opacity: 1; margin-top: 8px; }
.contact-block .contact-form { color: var(--ink); }

/* ============================================================
   Service card
   ============================================================ */
.service-card {
  display: block; height: 100%;
  background: var(--white);
  border: 1px solid #e4ecf7;
  border-radius: var(--radius);
  padding: 28px;
  text-align: center;
  transition: transform .15s ease, box-shadow .15s ease;
}
.service-card:hover { transform: translateY(-4px); box-shadow: 0 12px 30px rgba(16,42,92,.12); }
.service-card__icon { width: 56px; height: 56px; margin: 0 auto 16px; }
.service-card__icon--placeholder {
  display: block; border-radius: 50%;
  background: linear-gradient(135deg, var(--blue-600), var(--cyan-400));
}
.service-card__title { color: var(--navy-900); margin-bottom: 8px; }
.service-card__desc { color: var(--muted); font-size: 15px; }

/* ============================================================
   Forms
   ============================================================ */
.field { display: block; margin-bottom: 16px; }
.field__label { display: block; font-size: 14px; font-weight: 600; margin-bottom: 6px; }
.field input, .field textarea, .field select {
  width: 100%; padding: 12px 16px;
  border: 1px solid #bcdcf0; border-radius: 10px;
  font: inherit; line-height: 1.4; background: #eef8fd; color: var(--ink);   /* light-cyan fill per mockup */
}
/* Native select UA-chrome ignores author padding unless appearance is reset — without this it
   renders a different height than sibling inputs even with identical padding/border/font. */
.field select {
  appearance: none; -webkit-appearance: none; -moz-appearance: none;
  padding-right: 40px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8' fill='none'%3E%3Cpath d='M1 1.5L6 6.5L11 1.5' stroke='%235b6b85' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 16px center;
}
.field input:focus, .field textarea:focus, .field select:focus {
  outline: none; border-color: var(--blue-600);
  box-shadow: 0 0 0 3px rgba(30,111,208,.15);
}
.contact-form {
  background: var(--white);
  border-radius: var(--radius);
  padding: 28px;
  box-shadow: 0 12px 30px rgba(16,42,92,.08);
}
/* Optional icon tile above the form heading (Support "Submit a Support Request"). */
.contact-form__icon { display: grid; place-items: center; width: 66px; height: 66px; margin: 0 auto 14px; border-radius: 16px; background: #eaf6ff; color: var(--blue-600); box-shadow: 0 0 20px rgba(90,200,255,.45); }
.contact-form__icon svg { width: 34px; height: 34px; }
.contact-form__heading { margin-bottom: 16px; color: var(--navy-900); text-align: center; }
.contact-form__intro { margin-bottom: 20px; color: var(--muted); font-size: 15px; }
/* Submit is centered + compact (not full-width), navy-blue per mockup. */
.contact-form__submit { text-align: center; margin-top: 12px; }
.contact-form__submit .btn { min-width: 180px; padding: 14px 44px; border-radius: 8px; background: #023770; }
.contact-form__submit .btn:hover { background: #0a4b95; }

/* ============================================================
   Footer
   ============================================================ */
.site-footer { background: var(--navy-900); color: var(--white); padding-top: 56px; }
.site-footer__logo { width: 190px; max-width: 60%; height: auto; margin-bottom: 14px; }
.site-footer__inner { display: grid; grid-template-columns: 2fr 1fr 1fr 1fr; gap: 30px; }
.site-footer__col-title { margin-bottom: 12px; color: var(--cyan-400); font-size: 16px; font-weight: 700; }
.site-footer a:hover { color: var(--cyan-400); }
.site-footer__col p { margin-bottom: 6px; opacity: .85; font-size: 14px; }
.site-footer__col ul { list-style: none; display: grid; gap: 9px; margin-top: 10px; }
.site-footer__col a { font-size: 14px; opacity: .9; }
/* Social icons (Follow Us) */
.site-footer__social { display: flex; gap: 12px; margin-top: 18px; }
.site-footer__social a { display: grid; place-items: center; width: 36px; height: 36px; border-radius: 50%; background: rgba(255,255,255,.10); color: #fff; }
.site-footer__social a:hover { background: var(--cyan-400); color: var(--navy-900); }
.site-footer__bottom {
  margin-top: 44px; padding: 20px;
  border-top: 1px solid rgba(255,255,255,.12);
  font-size: 13px; opacity: .85;
  /* Left-aligned, not space-between: the legal links used to sit in the bottom-right corner,
     where the floating live-chat launcher covers them (Sitemap is the last item). */
  display: flex; align-items: center; justify-content: flex-start; flex-wrap: wrap; gap: 12px 28px;
}
.site-footer__legal { display: flex; flex-wrap: wrap; gap: 18px; list-style: none; }
@media (max-width: 768px) { .site-footer__bottom { flex-direction: column; align-items: flex-start; } }

/* ============================================================
   Splash / gateway pages (Welcome, Support Hub) — cosmic theme
   ============================================================ */
.splash {
  position: relative;
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  background: var(--grad-splash);
  color: var(--white);
  padding: 60px 20px 0;
}

/* Bare splash (Hub) — darker, more saturated navy-teal + focused top halo; top-anchored */
.splash--bare {
  align-items: flex-start;
  padding-top: clamp(56px, 8vh, 100px);
  background:
    radial-gradient(40% 30% at 50% 5%, rgba(120,185,215,.55), transparent 55%),
    radial-gradient(120% 95% at 50% 100%, #0a5a8c 0%, #0d4470 28%, #013660 60%, #002e52 100%);
}
.splash--bare .splash__lockup { margin-bottom: 16px; }
.splash--bare .splash__head { margin-bottom: 28px; }
/* Match mockup proportions: bigger logo, wider tile row. */
.splash--bare .splash__inner { max-width: 1200px; }
.splash--bare .splash__logo { width: 390px; }
/* Space background — zoomed + bottom-aligned so the horizon glare sits near the top, rotated 180deg. */
.splash--bare::before {
  content: ""; position: absolute; left: 0; right: 0; top: 0; height: 172%; z-index: 0; pointer-events: none;
  background: #002e52 url("../img/space-bg.webp") center top / auto 130% no-repeat;
  transform: translateY(-39%) rotate(180deg);
}
.splash--bare .splash__earth { display: none; }

/* Top-anchored splash (Welcome) — content sits near the top, not centered */
.splash--top { align-items: flex-start; padding-top: clamp(96px, 14vh, 150px); }

/* Logo pinned to the top-left corner (Welcome) */
.splash__lockup--corner {
  position: absolute; top: 26px; left: 38px; z-index: 3; margin: 0;
}
.splash__lockup--corner .splash__logo { width: 150px; }
@media (max-width: 600px) {
  .splash__lockup--corner { top: 18px; left: 20px; }
  .splash__lockup--corner .splash__logo { width: 120px; }
}

/* Simple CSS starfield — plain div stars, sit behind content (no canvas/JS) */
.stars { position: absolute; inset: 0; z-index: 1; pointer-events: none; overflow: hidden; }
.star {
  position: absolute; border-radius: 50%; background: #fff;
  box-shadow: 0 0 6px 1px rgba(170,220,255,.7);
  opacity: .8; animation: star-twinkle 3s ease-in-out infinite;
}
.star--blue { background: #9cd3ff; box-shadow: 0 0 7px 1px rgba(90,180,255,.85); }
@keyframes star-twinkle { 0%, 100% { opacity: .2; } 50% { opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .star { animation: none; opacity: .7; } }

/* Glowing curved earth horizon at the bottom */
.splash__earth {
  position: absolute;
  left: 50%; bottom: -78vw;
  width: 160vw; height: 160vw;
  transform: translateX(-50%);
  border-radius: 50%;
  background:
    radial-gradient(circle at 50% 8%, rgba(120,210,255,.75), rgba(40,120,190,.35) 28%, rgba(20,70,120,.1) 44%, transparent 56%);
  box-shadow: 0 -2px 90px 18px rgba(90,200,255,.55);
  z-index: 0; pointer-events: none;
}

.splash__inner { position: relative; z-index: 2; width: 100%; max-width: 1000px; text-align: center; }
.splash__brand { display: inline-flex; align-items: center; gap: 10px; margin-bottom: 48px; }
.logo-mark--glow { box-shadow: 0 0 18px rgba(63,198,255,.8); }

/* Brand lockup (Support Hub) — STELLAR Broadband logo */
.splash__lockup { display: inline-flex; margin-bottom: 28px; }
.splash__logo { width: 300px; max-width: 70vw; height: auto; }

.splash__head { margin-bottom: 48px; }
.splash__title {
  font-size: clamp(40px, 7vw, 72px); font-weight: 700; letter-spacing: 1px;
  text-shadow: 0 2px 30px rgba(63,198,255,.5);
}
.splash__title--sm { font-size: clamp(28px, 4.5vw, 44px); }
.splash__subtitle { opacity: .85; font-size: 16px; margin-top: 6px; }
.splash__subtitle--lg { font-size: clamp(20px, 3vw, 30px); opacity: .95; }

/* Glossy gradient text fill: light cyan top → sky-blue bottom (Support Hub) */
.splash__title--grad,
.splash__subtitle--grad {
  background: var(--grad-heading);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  -webkit-text-fill-color: transparent;
  text-shadow: none;          /* override the white title glow */
  opacity: 1;
}
/* Forced-colors / High Contrast: gradient-clipped text would vanish — restore solid */
@media (forced-colors: active) {
  .splash__title--grad,
  .splash__subtitle--grad {
    background: none;
    -webkit-text-fill-color: CanvasText;
    color: CanvasText;
  }
}

/* Glassmorphic glowing tiles */
.tiles { display: grid; grid-template-columns: repeat(3, 1fr); gap: 28px; }
.tile {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 14px; padding: 44px 24px; min-height: 230px;
  color: var(--white); text-align: center;
  border-radius: 18px;
  /* Crisp luminous cyan stroke */
  border: 1.5px solid rgba(120,215,255,.9);
  /* Vertical gradient: light cyan top → deeper blue bottom */
  background: var(--grad-tile);
  backdrop-filter: blur(4px);
  box-shadow:
    0 1px 0 rgba(255,255,255,.45) inset,           /* top gloss            */
    0 0 0 1px rgba(120,215,255,.35),               /* tight outer halo     */
    0 10px 40px rgba(10,40,80,.45),                /* drop shadow          */
    0 0 28px rgba(90,200,255,.55);                 /* cyan glow            */
  transition: transform .2s ease, box-shadow .2s ease, border-color .2s ease;
}
.tile:hover {
  transform: translateY(-6px);
  border-color: rgba(180,235,255,1);
  box-shadow:
    0 1px 0 rgba(255,255,255,.55) inset,
    0 0 0 1px rgba(150,225,255,.5),
    0 16px 54px rgba(10,40,80,.55),
    0 0 44px rgba(120,215,255,.85);
}
.tile__icon { color: #ffffff; filter: drop-shadow(0 0 12px rgba(150,225,255,.9)); }
.tile__icon svg { width: 60px; height: 60px; }
/* New PNG tile icons (white glyph + glow baked into the asset) */
.tile__iconimg { width: 88px; height: 88px; object-fit: contain; display: block; }
.tiles--4 .tile__iconimg { width: 150px; height: 150px; }
.tile__title { font-size: 22px; font-weight: 700; text-shadow: 0 1px 8px rgba(10,40,80,.4); }
.tile__title--sm { font-size: 19px; }
.tile__sub { font-size: 13px; opacity: .9; max-width: 200px; }

/* 4-up tile layout (Support Hub) — taller, denser, more saturated */
.tiles--4 { grid-template-columns: repeat(4, 1fr); gap: 40px; }
.tiles--4 .tile {
  min-height: 205px; padding: 24px 18px; gap: 10px;
  /* Cyan fill + gradient border (bright cyan top -> deeper blue bottom). */
  border: 1.6px solid transparent;
  background:
    linear-gradient(180deg, #5ec8ec 0%, #33aadc 55%, #1f92c8 100%) padding-box,
    linear-gradient(180deg, #e6f8ff 0%, #8ad6f2 32%, #1f8ec6 100%) border-box;
}
.tiles--4 .tile__icon { filter: drop-shadow(0 0 16px rgba(180,240,255,1)) drop-shadow(0 0 6px rgba(120,255,220,.7)); }
.tiles--4 .tile__icon svg { width: 72px; height: 72px; }
.tiles--4 .tile__title { font-size: 22px; font-weight: 800; text-align: center; max-width: 10ch; margin-inline: auto; line-height: 1.2; }
/* 5-star rating row (Tech Support tile) */
.tile__stars { display: block; margin-top: -4px; font-size: 15px; letter-spacing: 3px; color: #eafaff; text-shadow: 0 0 8px rgba(150,225,255,.9); }

/* Live Chat + phone action bar — transparent center, glowing cyan outline */
.hub-actions { display: flex; gap: 24px; justify-content: center; margin-top: 40px; flex-wrap: wrap; }
.hub-action {
  display: inline-flex; align-items: center; gap: 12px;
  padding: 7px 32px 7px 16px; border-radius: 14px; color: #fff;
  font: inherit; font-weight: 600; font-size: 18px; cursor: pointer;
  /* Transparent fill; gradient border comes from the masked ::before overlay below. */
  border: 0; background: transparent;
  box-shadow: 0 0 16px rgba(90,200,255,.35);      /* subtle outer glow only, no inner fill */
  transition: transform .15s ease, box-shadow .15s ease, border-color .15s ease;
}
.hub-action:hover {
  transform: translateY(-2px);
  box-shadow: 0 0 26px rgba(120,215,255,.6);
}
/* icon sits in a solid light circle */
.hub-action__icon {
  display: inline-flex; align-items: center; justify-content: center;
  width: 34px; height: 34px; border-radius: 50%;
  background: #eaf6ff; color: var(--blue-700);
  box-shadow: 0 0 12px rgba(150,225,255,.7);
}
.hub-action__icon svg { width: 18px; height: 18px; display: block; }
/* Glowing PNG icons (chat/phone) sit directly on the dark pill — no light circle. */
.hub-action__icon:has(.hub-action__iconimg) { background: transparent; box-shadow: none; width: 64px; height: 64px; margin: -14px 0; }
.hub-action__iconimg { width: 64px; height: 64px; object-fit: contain; display: block; }

@media (max-width: 900px) { .tiles--4 { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 768px) {
  .tiles { grid-template-columns: 1fr; }
}

@media (max-width: 768px) {
  .site-footer__inner { grid-template-columns: 1fr; }
}

/* Nav switches to the hamburger menu earlier than other 768px breakpoints:
   between ~769-1000px there isn't enough room for the full-text nav links to
   stay on one line each, so labels like "Who We Serve" wrap to 3 lines with
   the dropdown caret stranded alone — broken on common tablet widths
   (iPad Mini/Air/Pro portrait). Widening this one breakpoint avoids that
   without touching the 768px footer/tiles breakpoints above. */
@media (max-width: 1024px) {
  .site-nav {
    display: none; position: absolute; top: 100%; left: 0; right: 0;
    flex-direction: column; align-items: flex-start; gap: 16px;
    background: var(--navy-800); padding: 20px;
  }
  .site-nav.is-open { display: flex; }
  .site-nav__list { flex-direction: column; gap: 14px; }
  .nav-toggle { display: flex; }
  /* Dropdown shows inline (indented) in the mobile menu. */
  .site-nav__dropdown {
    position: static; opacity: 1; visibility: visible; transform: none;
    background: transparent; box-shadow: none; padding: 8px 0 0 14px; margin: 6px 0 0;
  }
  .site-nav__dropdown a { color: #fff; padding: 6px 0; }
  .site-nav__dropdown a:hover { background: transparent; color: var(--cyan-400); }
  .nav-caret { display: none; }
}

/* ============================================================
   Media placeholder — holds layout while marketing media is
   outstanding. Set an item's $img to drop in the real asset.
   ============================================================ */
.media-ph {
  display: block; position: relative; width: 100%;
  aspect-ratio: var(--media-aspect, 16 / 9);
  border-radius: var(--radius); overflow: hidden;
  background-color: #0c3a63;
  background-image: var(--grad-cosmic);
  background-size: cover; background-position: center; background-repeat: no-repeat;
  box-shadow: inset 0 0 60px rgba(80,180,255,.25);
}
.media-ph::after {                       /* sweeping shimmer */
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(110deg, transparent 35%, rgba(255,255,255,.10) 50%, transparent 65%);
  background-size: 220% 100%;
  animation: media-shimmer 2s linear infinite;
}
.media-ph__label {
  position: absolute; inset: 0; z-index: 1;
  display: flex; align-items: center; justify-content: center;
  color: rgba(255,255,255,.65); font-size: 12px; font-weight: 600;
  letter-spacing: 1px; text-transform: uppercase;
}
.media-ph.is-loaded { box-shadow: none; }
.media-ph.is-loaded::after { content: none; }
.media-ph--round { border-radius: 50%; }
@keyframes media-shimmer { to { background-position: -220% 0; } }

/* ============================================================
   Page hero — interior pages (image/placeholder + overlay copy)
   ============================================================ */
.page-hero {
  position: relative; overflow: hidden;
  color: var(--white); min-height: 360px; max-height: 600px;
  display: flex; align-items: center;
  background-color: #0c3a63;
  background-image: var(--grad-cosmic);
  /* no-repeat is load-bearing, not decoration. Any hero variant that overrides background-size
     with something other than cover/100% will TILE without it, because repeat is the CSS default.
     That is exactly how the article hero shipped a three-times-stacked photo on mobile. */
  background-size: cover; background-position: center; background-repeat: no-repeat;
}
.page-hero--tall { min-height: 460px; }
/* Article heroes with an embedded widget (e.g. the Speed Test iframe) need much more
   room than the base .page-hero's 600px cap allows, or the content clips top/bottom. */
.page-hero--widget { max-height: none; padding-block: 40px; }
.page-hero__media { position: absolute; inset: 0; }
/* Zoom-out parallax hero image — starts zoomed in, scales down + drifts as the
   user scrolls the hero out of view (see initParallaxZoom in main.js).
   will-change hints the browser to promote this to its own layer for smooth
   scroll-driven transforms; the static scale(1.12) is the no-JS fallback. */
.page-hero__media--parallax-zoom { will-change: transform; transform: scale(1.45); }
@media (prefers-reduced-motion: reduce) { .page-hero__media--parallax-zoom { transform: none; } }
.page-hero__media .media-ph { height: 100%; border-radius: 0; aspect-ratio: auto; }
/* Background video (Support hero) */
.page-hero__video { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; z-index: 0; }
.page-hero--video { min-height: 600px; }
/* About hero is a shorter band than the product/support video heroes (per mockup). */
.page-hero--about { min-height: 520px; }
/* ---- Residents hero (mockups-media/Revised Residents Page/1.png) --------------------------------
   Scoped to .residents on purpose: .page-hero--about is shared with /business and /about, and only
   the Residents mockup calls for this. Its hero band runs to y900 on a 2049px artboard = a 1440
   design at 1.423x, so 633 CSS px — which also needs max-height lifted, since the base .page-hero
   caps at 600px and would silently swallow the change.
   The mockup's photo is graded cool: measured across the whole band it sits at mean RGB (61,93,102),
   blue-minus-red +41 and luma 85, against our (56,55,54), -2 and 55 — i.e. ours renders both too
   neutral and too dark. The scrim below replaces the shared navy one with a teal wash that lifts and
   cools it. NOTE this is an approximation: the mockup also uses a WIDER CROP than
   residents-hero.webp, so a colour overlay gets the cast close but cannot reproduce the framing.
   A graded/re-cropped asset is the real fix. ---- */
.residents .page-hero--about { min-height: 633px; max-height: 633px; }
.residents .page-hero--about::before {
  background:
    linear-gradient(90deg, rgba(7,29,57,.40) 0%, rgba(7,29,57,.14) 55%, transparent 100%),
    linear-gradient(180deg, rgba(78,168,190,.46), rgba(44,124,152,.42));
}
/* No color overlay over video heroes — show the clean footage; text stays legible via text-shadow. */
.page-hero--video .page-hero__title,
.page-hero--video .page-hero__subtitle { text-shadow: 0 2px 12px rgba(4,18,40,.55), 0 1px 3px rgba(4,18,40,.6); }
/* Small screens: skip the video (save mobile data) — show the poster still image instead.
   Each video hero sets --hero-poster inline. */
@media (max-width: 768px) {
  .page-hero--video .page-hero__video { display: none; }
  .page-hero--video {
    background-image: var(--hero-poster);
    background-size: cover; background-position: center;
  }
}
/* Reduced motion: swap the autoplaying video for its still poster (same technique as mobile above) —
   users who've asked the OS to reduce motion shouldn't get a looping video with no way to stop it. */
@media (prefers-reduced-motion: reduce) {
  .page-hero--video .page-hero__video { display: none; }
  .page-hero--video {
    background-image: var(--hero-poster);
    background-size: cover; background-position: center;
  }
}
.page-hero::before {                     /* legibility scrim */
  content: ""; position: absolute; inset: 0; z-index: 1;
  background: linear-gradient(90deg, rgba(7,29,57,.6) 0%, rgba(7,29,57,.28) 55%, transparent 100%);
}
/* Video heroes: no color overlay at all (must come AFTER .page-hero::before to win). */
.page-hero--video::before { background: none; }
.page-hero__inner { position: relative; z-index: 2; padding-block: 70px; }
/* Light hero (Support) — light wash over the photo, dark text */
.page-hero--light { color: var(--ink); }
.page-hero--light::before {
  background: linear-gradient(90deg, rgba(238,248,255,.94) 0%, rgba(238,248,255,.62) 52%, rgba(238,248,255,.18) 100%);
}
.page-hero--light .page-hero__eyebrow { color: var(--blue-600); }
.page-hero--light .page-hero__title { color: var(--navy-900); }
.page-hero--light .page-hero__subtitle { color: var(--ink); opacity: .9; }
/* Keep the transparent white nav readable over the light hero top */
.page-hero--light::after {
  content: ""; position: absolute; top: 0; left: 0; right: 0; height: 96px; z-index: 1;
  background: linear-gradient(180deg, rgba(7,29,57,.45), transparent);
  pointer-events: none;
}
.page-hero__eyebrow { color: var(--cyan-400); font-weight: 700; letter-spacing: 1px; text-transform: uppercase; font-size: 13px; }
.page-hero__title { font-size: clamp(30px, 4.4vw, 52px); font-weight: 700; line-height: 1.15; margin: 10px 0 14px; max-width: 760px; }
.page-hero__subtitle { max-width: 560px; opacity: .92;  }
.page-hero__actions { display: flex; gap: 14px; flex-wrap: wrap; margin-top: 26px; }

/* ============================================================
   Form status + field errors — shared by every form on the site
   (login, forgot-password, get-started, request-service, contact-form,
   careers, callback-card). JS toggles .is-success/.is-error; this is the
   styling that was missing entirely, so every message rendered as plain
   unstyled text with no color/border cue for sighted users. A solid tinted
   card reads consistently whether the form sits on a light or dark background.
   ============================================================ */
.form-status {
  display: block; padding: 13px 16px; margin-bottom: 18px;
  border-radius: 10px; font-size: 14px; font-weight: 600; line-height: 1.5;
  border: 1px solid transparent;
}
.form-status.is-success { background: #eafaf0; border-color: #8fdcb0; color: #1a7a45; }
.form-status.is-error   { background: #fdeceb; border-color: #f3b4ae; color: #b3261e; }
/* Per-field error text (aria-describedby target — see main.js showFieldErrors). */
.field__error { display: block; margin-top: 6px; font-size: 13px; font-weight: 600; color: #c0362c; }

/* ============================================================
   Auth (Login) — cosmic split with glass card
   ============================================================ */
.auth {
  position: relative; overflow: hidden;
  /* Cap height near the mockup's wide proportion so the bg image isn't over-zoomed. */
  min-height: min(760px, calc(100vh - 64px));
  display: flex; align-items: center;
  color: var(--white);
}
.auth__bg-image {
  position: absolute; inset: 0; z-index: -1; pointer-events: none;
  background: url("../img/login-bg.webp") left / cover no-repeat;
}
/* Brighter cyan glow across the top-center (per mockup's luminous burst). */
.auth::before {
  content: ""; position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background: radial-gradient(65% 50% at 50% -2%, rgba(130,215,247,.6), rgba(90,190,235,.18) 40%, transparent 62%);
}
.auth__inner { position: relative; z-index: 2; }
.auth__canvas { position: absolute; inset: 0; width: 100%; height: 100%; z-index: 1; pointer-events: none; }
.auth__inner {
  position: relative; z-index: 2;
  display: grid; grid-template-columns: 1fr 1fr; gap: 48px; align-items: center;
  padding-block: 60px; width: 100%;
}
.auth__welcome { display: flex; flex-direction: column; align-items: center; text-align: center; }
.auth__welcome-title { font-size: clamp(34px, 5vw, 60px); font-weight: 700; text-shadow: 0 2px 30px rgba(63,198,255,.5); }
.auth__orb { width: clamp(180px, 22vw, 300px); margin-top: 24px; }
.auth__orb-img { width: 50%; height: auto; display: block; margin-inline: auto; filter: drop-shadow(0 0 40px rgba(90,200,255,.55)); }

.auth-card {
  justify-self: end; width: 100%; max-width: 540px;
  padding: 30px; border-radius: 24px;
  border: 1.5px solid rgba(150,210,240,.5);
  background: linear-gradient(180deg, rgba(60,120,165,.28), rgba(20,55,95,.35));
  backdrop-filter: blur(14px);
  box-shadow: 0 20px 60px rgba(8,29,57,.5), 0 0 30px rgba(90,200,255,.25);
}
/* Glossy gradient Login button (auth-scoped, not global) */
.auth-card .btn--primary {
  background: linear-gradient(90deg, #1a78c8 0%, #3fb4ec 55%, #7ad6f7 100%);
  color: #fff; border-radius: 12px;
  box-shadow: 0 0 24px rgba(90,200,255,.5), inset 0 1px 0 rgba(255,255,255,.5);
}
/* Two outlined pill buttons side by side (no enclosing track) — per mockup */
.toggle {
  display: grid; grid-template-columns: 1fr 1fr; gap: 16px;
  margin-bottom: 22px;
}
.toggle__btn {
  padding: 12px 16px; border-radius: 8px; cursor: pointer;
  font: inherit; font-weight: 700; color: #fff;
  border: 1.5px solid rgba(150,210,240,.7);
  background: rgba(255,255,255,.05); backdrop-filter: blur(4px);
  transition: background .15s ease, border-color .15s ease;
}
.toggle__btn.is-active { background: rgba(150,215,255,.22); border-color: rgba(190,235,255,1); color: #fff; box-shadow: 0 0 16px rgba(120,210,255,.45) inset, 0 0 14px rgba(120,210,255,.3); }

/* Dark form fields (auth) — pair with .field markup */
.field--dark .field__label { color: rgba(255,255,255,.9); }
.field--dark input {
  background: rgba(190,215,225,.85); color: #14323e;
  border: 1px solid rgba(255,255,255,.25); border-radius: 12px; padding: 14px 16px;
}
.field--dark input::placeholder { color: rgba(30,60,75,.6); }
.field--dark input:focus { border-color: var(--cyan-400); box-shadow: 0 0 0 3px rgba(63,198,255,.35); }
/* Lighter red on dark glass cards — the default .field__error red is too dark to read here. */
.field--dark .field__error { color: #ff9b93; }
.auth-card__row { display: flex; align-items: center; justify-content: center; margin: 6px 0 18px; font-size: 14px; }
.auth-card__check { display: inline-flex; align-items: center; gap: 8px; }
.auth-card__links { display: flex; justify-content: center; gap: 56px; margin-top: 16px; font-size: 14px; }
.auth-card__links a { color: rgba(205,225,235,.85); }
.auth-card__links a:hover { color: var(--cyan-400); }
@media (max-width: 860px) {
  .auth__inner { grid-template-columns: 1fr; text-align: center; }
  .auth-card { justify-self: center; }
  .auth__orb { margin-inline: auto; }
}

/* Find Your Fiberhood — reuses the login page's background so the top strip above the map
   (and any gutter before the Google Map finishes loading) isn't blank white. */
stellar-map .stellar-map-header {
  z-index: 10;
  background: #ffffff87;
  color: white;
}
div#or-separator-desktop {
  color: black;
}
.fiberhood {
  padding-top: 118px;
  background: url("../img/login-bg.webp") left / cover no-repeat;
}
/* Visible page title in the strip above the map. The nav is position:absolute over the page
   (logo 90px + padding ≈ 106px tall), so .fiberhood's padding-top has to clear it before the
   title paints — otherwise the two collide. White because the strip is the dark login photo;
   the text-shadow keeps it legible over the photo's lighter regions. */
.fiberhood__page-title {
  margin: 0 0 20px;
  padding-inline: 20px; /* keeps the title off the edges on narrow phones — wraps rather than overflows */
  text-align: center;
  color: var(--white);
  font-size: clamp(30px, 4.4vw, 52px);
  font-weight: 700;
  line-height: 1.15;
  text-shadow: 0 2px 18px rgba(7, 29, 57, .5);
}

/* ============================================================
   Feature block — alternating media / copy (Products, Owners)
   ============================================================ */
/* Full-bleed alternating service bands (Products): photo half + colored panel half */
/* Recurring glow-line accent running down the seams between blocks (per mockup) — same
   asset/technique as .essential-band__lines on Owners & Developers, tiled vertically here
   since the mockup repeats it at nearly every block transition instead of just once. */
.features { position: relative; overflow: hidden; }
.features::before {
  content: ""; position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background: url("../img/essential-glow-lines.png") center top repeat-y;
  background: image-set(url("../img/essential-glow-lines.webp") type("image/webp"),
                         url("../img/essential-glow-lines.png") type("image/png")) center top repeat-y;
  background-size: 420px auto;
  opacity: .55; mix-blend-mode: screen;
}
.feature-block {
  display: grid; grid-template-columns: 1fr 1fr; align-items: stretch; min-height: 470px;
  position: relative; scroll-margin-top: 12px;
}
/* ---- Anchor arrival: a band linked from the carousel announces itself with a
       light sweep, a rim flash, and an icon pop. JS toggles .is-anchor-arrive
       once the smooth scroll lands. Reduced-motion is covered globally. ---- */
/* Two overlays, both above the panels: ::after sweeps, ::before flashes the rim.
   (An inset shadow on the block itself would paint under the panel backgrounds.) */
.feature-block::after,
.feature-block::before {
  content: ""; position: absolute; inset: 0; opacity: 0; pointer-events: none;
}
.feature-block::after { z-index: 4; }
.feature-block::before { z-index: 5; }
.feature-block.is-anchor-arrive::after {
  background: linear-gradient(102deg, transparent 30%, rgba(140,225,255,.62) 50%, transparent 70%);
  animation: fb-sweep 1.1s cubic-bezier(.22,.61,.36,1);
}
.feature-block.is-anchor-arrive::before {
  box-shadow: inset 0 0 0 3px rgba(120,215,255,.95), inset 0 0 44px rgba(90,200,255,.5);
  animation: fb-rim 1.2s ease-out;
}
.feature-block.is-anchor-arrive .feature-block__icon { animation: fb-icon-pop .9s .1s cubic-bezier(.2,.8,.2,1); }
.feature-block.is-anchor-arrive .feature-block__title { animation: fb-title-in .8s ease-out; }
@keyframes fb-sweep {
  0%   { opacity: 0; transform: translateX(-100%); }
  12%  { opacity: 1; }
  100% { opacity: 0; transform: translateX(100%); }
}
@keyframes fb-rim {
  0%   { opacity: 0; }
  18%  { opacity: 1; }
  100% { opacity: 0; }
}
@keyframes fb-icon-pop {
  0%   { transform: scale(1); }
  35%  { transform: scale(1.16) rotate(-5deg); }
  100% { transform: scale(1); }
}
@keyframes fb-title-in {
  0%   { opacity: .35; transform: translateY(10px); }
  100% { opacity: 1; transform: none; }
}
.feature-block--reverse .feature-block__media { order: 2; }
.feature-block__media { background-size: cover; background-position: center; background-repeat: no-repeat; min-height: 300px; }
.feature-block__panel { display: flex; align-items: center; padding: 56px clamp(28px, 5vw, 88px); }
.feature-block__inner { max-width: 560px; }
.feature-block__panel--light { background: #fff; color: var(--ink); }
.feature-block__panel--fill { background: linear-gradient(160deg, #1a86cf 0%, #0d5fa6 55%, #0a3f78 100%); color: #fff; }
/* Large circular icon */
/* Title + icon share a row; icon sits to the right of the title (mockup). */
.feature-block__head { display: flex; align-items: center; gap: 18px; margin-bottom: 12px; }
.feature-block__icon { flex: 0 0 auto; display: inline-flex; color: var(--blue-600); filter: drop-shadow(0 0 8px rgba(90,200,255,.55)); }
.feature-block__icon svg { width: 78px; height: 78px; }
/* Same delivered ring-glow PNGs as the home "Explore Our Services" row. The art
   has generous internal padding, so the box runs larger than the SVG fallback. */
.feature-block__iconimg { width: 112px; height: 112px; object-fit: contain; display: block; }
.feature-block__panel--fill .feature-block__icon { color: #fff; filter: drop-shadow(0 0 9px rgba(150,220,255,.6)); }
/* The PNG line art is brand blue, which disappears on the blue panel — flatten it
   to white (matching how the inline SVGs are recolored there) and keep the glow. */
.feature-block__panel--fill .feature-block__iconimg {
  filter: brightness(0) invert(1) drop-shadow(0 0 10px rgba(150,220,255,.7));
}
.feature-block__title { font-size: clamp(26px, 3vw, 38px); font-weight: 800; margin: 0; color: var(--blue-600); }
.feature-block__panel--fill .feature-block__title { color: #fff; }
.feature-block__tagline { font-weight: 700; font-size: 14px; color: var(--blue-600); margin-bottom: 12px; letter-spacing: .3px; }
.feature-block__panel--fill .feature-block__tagline { color: rgba(255,255,255,.95); }
.feature-block__body { color: var(--muted); margin-bottom: 18px; line-height: 1.6; }
.feature-block__panel--fill .feature-block__body { color: rgba(255,255,255,.9); }
.fb-actions { display: flex; gap: 12px; margin-top: 18px; flex-wrap: wrap; }
.btn--outline { background: transparent; border-color: var(--blue-600); color: var(--blue-600); }
.btn--sm { padding: 8px 22px; font-size: 14px; }
.feature-block__panel--fill .btn--outline { border-color: rgba(255,255,255,.85); color: #fff; }
.section--dark { background: linear-gradient(160deg, var(--navy-900), var(--navy-950)); color: var(--white); }
.section--dark .section__title { color: var(--white); }
@media (max-width: 768px) {
  .feature-block { grid-template-columns: 1fr; }
  .feature-block--reverse .feature-block__media { order: 0; }
  .feature-block__media { min-height: 240px; }
  .feature-block__panel { padding: 40px 22px; }
}

/* ============================================================
   Service spotlight carousel (Products — section 2)
   ============================================================ */
/* Base deck — also used by the Support "Self-Help and Video Guides" carousel. */
.svc-carousel__track {
  display: flex; gap: 22px; overflow-x: auto; scroll-snap-type: x mandatory;
  scroll-behavior: smooth; scrollbar-width: none; padding: 4px;
}
.svc-carousel__track::-webkit-scrollbar { display: none; }
/* --bleed (Products): the deck ignores the container gutters so the next card runs
   off the right edge, the arrows overlay it instead of stacking under it, and the
   bottom margin + the section's own 40px leave the shallow strip of blue the
   mockup shows between the cards and the first service band. */
.svc-carousel--bleed { position: relative; margin-top: 34px; margin-bottom: 52px; }
.svc-carousel--bleed .svc-carousel__track {
  gap: 60px; padding: 4px 0 4px 11.3vw; scroll-padding-left: 11.3vw;
}
/* Card geometry read off the mockup: 840x623 at a 1366 viewport, so ~61.5vw wide
   on a 1.35:1 ratio, with the deck's left edge at ~11.3vw. */
.product-slide {
  flex: 0 0 61.5vw; aspect-ratio: 840 / 623; scroll-snap-align: start; position: relative;
  border-radius: 18px; overflow: hidden; text-decoration: none;
  color: #fff; background-size: cover; background-position: center;
  display: flex; box-shadow: 0 16px 38px rgba(4,20,44,.35);
}
.product-slide::before {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(4,20,44,.55) 0%, rgba(4,20,44,.1) 45%, rgba(4,20,44,.62) 100%);
}
/* Per mockup annotation: a blue filter tints the peeking cards and "dissolves when it is the
   main image" — same treatment as .guide-card's/.news-card--feature's centered-card dissolve. */
.product-slide::after {
  content: ""; position: absolute; inset: 0; z-index: 1;
  background: linear-gradient(180deg, rgba(12,92,150,.55) 0%, rgba(6,38,78,.78) 100%);
  transition: opacity .45s ease;
}
.product-slide.is-active::after,
.product-slide:hover::after,
.product-slide:focus-visible::after { opacity: 0; }
/* Mockup: title + tagline sit at the TOP-left, "Read more" at the BOTTOM-right. */
.product-slide__inner {
  position: relative; z-index: 2; flex: 1 1 auto; padding: 52px clamp(28px, 4.4vw, 62px) 42px;
  display: flex; flex-direction: column; justify-content: space-between;
  text-align: left; /* the band itself is centred — the cards are not */
}
.product-slide__title { display: block; font-size: clamp(24px, 3.5vw, 48px); font-weight: 800; line-height: 1.1; }
.product-slide__tag { display: block; color: #d8f0ff; font-size: clamp(14px, 1.3vw, 18px); font-weight: 600; margin-top: 10px; }
.product-slide__more {
  align-self: flex-end; display: inline-flex; align-items: center; gap: 14px;
  font-size: 20px; font-weight: 600; color: #fff;
}
.product-slide__arrow {
  display: inline-grid; place-items: center; width: 44px; height: 44px;
  border: 2px solid #fff; border-radius: 50%; font-size: 19px; line-height: 1;
  transition: transform .3s ease, background-color .3s ease, color .3s ease;
}
.product-slide:hover .product-slide__arrow,
.product-slide:focus-visible .product-slide__arrow { transform: translateX(5px); background: #fff; color: var(--blue-600); }
.svc-carousel__nav { display: flex; justify-content: center; gap: 12px; margin-top: 22px; }
/* Overlaid nav — vertically centred against the deck, clear of the card text. */
.svc-carousel--bleed .svc-carousel__nav {
  position: absolute; inset: 0; z-index: 3; margin-top: 0; pointer-events: none;
  align-items: center; justify-content: space-between; padding-inline: 14px;
}
.svc-carousel--bleed .carousel-arrow { pointer-events: auto; }
@media (max-width: 700px) {
  .svc-carousel--bleed .svc-carousel__track { gap: 22px; padding-left: 7vw; scroll-padding-left: 7vw; }
  .product-slide { flex-basis: 86vw; aspect-ratio: 1 / 1; }
  .product-slide__inner { padding: 30px 26px; }
  .product-slide__more { font-size: 16px; }
  .product-slide__arrow { width: 36px; height: 36px; font-size: 16px; }
}

/* ============================================================
   Apartments — hero (T04-adjacent; own gradient, not .page-hero)
   ============================================================ */
/* Two-column hero on a flat 90deg gradient. Not .page-hero: that one is a
   full-bleed centred photo/video band with a dark scrim, which fights both the
   gradient and the left-aligned copy this mockup calls for. Top padding clears
   the absolutely-positioned .site-header. */
.apt-hero {
  position: relative; overflow: hidden; color: var(--white);
  background: linear-gradient(90deg, #0066b9 0%, #00d1ff 100%);
  padding: 160px 0 74px;
}
/* Mockup: the gradient dissolves into the white band that follows. */
.apt-hero::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 104px;
  background: linear-gradient(180deg, rgba(255,255,255,0), #fff);
  pointer-events: none; z-index: 2;
}
/* Two 4-point sparkles upper-left.
   These are the SAME stars the home hero uses — cropped out of img/stars.png (one large,
   one small) rather than redrawn as SVG paths, so the sparkle shape, glow falloff and
   ray length match the home page exactly instead of only approximating it. */
.apt-hero__sparkles {
  position: absolute; top: 108px; left: 1.4%; width: 140px; height: 128px; z-index: 1;
  background-image: url("../img/star-lg.webp"), url("../img/star-sm.webp");
  background-repeat: no-repeat, no-repeat;
  background-position: 59px 4px, 24px 60px;
  background-size: 72px 72px, 46px 46px;
  pointer-events: none;
}
/* Glow lines on the right, behind the globe (mockup). Same asset + treatment the
   Products/Owners feature seams use, just placed right and dialled back with
   opacity. z-index 1 keeps it under .apt-hero__inner (z-3) — i.e. behind the art. */
.apt-hero__beams {
  position: absolute; top: 0; right: 0; width: 62%; height: 100%; z-index: 1;
  pointer-events: none; opacity: .42;
  background: url("../img/fiber-light-lines.png") right center / 190% auto no-repeat;
  background-image: image-set(url("../img/fiber-light-lines.webp") type("image/webp"),
                              url("../img/fiber-light-lines.png") type("image/png"));
  /* Fade the inner edge so the layer can't cut a hard seam across the copy column. */
  -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 38%);
  mask-image: linear-gradient(90deg, transparent 0, #000 38%);
}
.apt-hero__inner {
  position: relative; z-index: 3;
  display: grid; grid-template-columns: minmax(0, 1.02fr) minmax(0, .98fr);
  gap: 40px; align-items: center;
}
.apt-hero__copy { max-width: 620px; }
/* White words are light, the cyan .hl words bold — same treatment as the home hero. */
.apt-hero__title {
  /* Mockup: the title measures ~2.6% of page width, and the two lines are airy. */
  font-size: clamp(28px, 2.7vw, 38px); font-weight: 400; line-height: 1.42;
  margin: 0 0 24px;
}
.apt-hero__title .hl { color: var(--cyan-400); font-weight: 700; }
.apt-hero__lead { font-size: 17px; line-height: 1.55; margin: 0 0 16px; }
.apt-hero__lead--strong { font-weight: 700; margin-bottom: 32px; }
/* Solid cyan fill — the home hero button's hover state, used as the resting state here. */
.btn--apt {
  background: var(--cyan-400); border-color: var(--cyan-400); color: var(--navy-900);
  padding: 14px 32px; font-weight: 600;
}
.btn--apt:hover,
.btn--apt:focus-visible { background: var(--cyan-200); border-color: var(--cyan-200); color: var(--navy-900); }
.apt-hero__art { justify-self: end; }
.apt-hero__art img { display: block; width: 100%; max-width: 520px; height: auto; }
@media (max-width: 900px) {
  .apt-hero { padding: 150px 0 84px; }
  .apt-hero__inner { grid-template-columns: 1fr; gap: 24px; }
  .apt-hero__copy { max-width: none; }
  /* Art second and capped, so the copy still owns the fold on a phone. */
  .apt-hero__art { justify-self: center; }
  .apt-hero__art img { max-width: 420px; }
  .apt-hero__sparkles { display: none; }
}

/* ============================================================
   Apartments — city filter row + community directory
   ============================================================ */
.city-band { background: #fff; padding: 34px 0; }
.city-filter { position: relative; max-width: var(--container); margin-inline: auto; padding-inline: 64px; }
.city-filter__track {
  display: flex; gap: 8px; list-style: none; margin: 0; padding: 0;
  overflow-x: auto; scrollbar-width: none; scroll-behavior: smooth;
}
.city-filter__track::-webkit-scrollbar { display: none; }
.city-chip {
  appearance: none; border: 1px solid transparent; background: transparent;
  color: var(--navy-900); font-family: inherit; font-size: 17px; font-weight: 700;
  white-space: nowrap; padding: 10px 18px; border-radius: 999px; cursor: pointer;
  transition: background-color .18s ease, color .18s ease, border-color .18s ease;
}
.city-chip:hover { background: var(--cyan-100); }
/* The mockup shows no selected state; a filter needs one to be usable. */
.city-chip.is-selected { background: var(--blue-600); border-color: var(--blue-600); color: #fff; }
.city-filter__arrow {
  position: absolute; top: 50%; transform: translateY(-50%);
  background: var(--navy-900); border-color: var(--navy-900); color: #fff;
}
.city-filter__arrow--prev { left: 4px; }
.city-filter__arrow--next { right: 4px; }
.city-filter__arrow:disabled { opacity: .35; }

.community-band { background: linear-gradient(90deg, #0066b9 0%, #00d1ff 100%); }
/* One panel, hairlines drawn by the grid gap: filtering rows in/out can never
   leave a dangling border the way per-cell borders would. */
.community-panel {
  display: grid; grid-template-columns: 1fr 1fr; gap: 1px;
  background: rgba(2, 55, 112, .5);
  border: 1px solid rgba(2, 55, 112, .5); border-radius: 14px; overflow: hidden;
}
.community-row {
  /* Translucent so the hero's glow lines carry through, as in the mockup. */
  background: rgba(203, 237, 250, .9);
  display: flex; align-items: center; gap: 18px; padding: 22px 20px;
}
.community-row__photo {
  flex: 0 0 auto; width: 84px; height: 84px; border-radius: 50%;
  object-fit: cover; display: block;
}
.community-row__photo--empty { background: linear-gradient(180deg, #cfeafb 0%, #eaf6ff 55%, #b9d98f 100%); }
.community-row__body { flex: 1 1 auto; min-width: 0; }
.community-row__name { font-size: 17px; font-weight: 800; color: var(--navy-900); margin: 0 0 7px; }
/* Mockup used #05aeff here — 1.67:1 on this fill. Darkened to clear AA (7.1:1). */
.community-row__addr { color: #0f4d80; font-size: 15px; line-height: 1.4; margin: 0; }
/* Mockup's glossy gradient put white text at 1.5–2.8:1. Solid brand blue is 4.95:1
   and matches the flat buttons used everywhere else on the site. */
.btn--subscribe {
  flex: 0 0 auto; background: var(--blue-600); border-color: var(--blue-600);
  color: #fff; font-weight: 700; font-size: 15px; padding: 11px 20px; white-space: nowrap;
}
.btn--subscribe:hover,
.btn--subscribe:focus-visible { background: var(--blue-700); border-color: var(--blue-700); color: #fff; }
.community-panel__empty { color: #fff; font-weight: 600; text-align: center; margin: 28px 0 0; }
/* Directory search + pager — revealed by main.js for a selected city (the Featured view omits them). */
.community-toolbar { display: flex; justify-content: flex-end; margin: 0 0 16px; }
.community-search__input {
  width: 260px; max-width: 100%; padding: 10px 14px; font-size: 15px;
  border: 1px solid rgba(2, 55, 112, .4); border-radius: 999px;
  background: #fff; color: var(--navy-900);
}
.community-search__input:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }
.community-pager { display: flex; flex-wrap: wrap; justify-content: center; gap: 8px; margin: 24px 0 0; }
.community-pager__btn {
  min-width: 40px; padding: 8px 12px; font-size: 14px; font-weight: 700; cursor: pointer;
  color: #fff; background: rgba(255, 255, 255, .16);
  border: 1px solid rgba(255, 255, 255, .5); border-radius: 8px;
}
.community-pager__btn:hover:not([disabled]):not(.is-current) { background: rgba(255, 255, 255, .3); }
.community-pager__btn.is-current { background: #fff; color: var(--navy-900); border-color: #fff; }
.community-pager__btn[disabled] { opacity: .45; cursor: default; }
@media (max-width: 900px) {
  .community-panel { grid-template-columns: 1fr; }
}
@media (max-width: 560px) {
  /* Explicit grid, not flex-wrap: with flex the row broke differently depending on
     how long the community name was, so adjacent rows didn't match. */
  .community-row {
    display: grid; grid-template-columns: 76px minmax(0, 1fr);
    gap: 14px 16px; align-items: center; padding: 20px 18px;
  }
  .community-row__photo { width: 76px; height: 76px; }
  .community-row__body { grid-column: 2; }
  .btn--subscribe { grid-column: 1 / -1; text-align: center; }
  .city-filter { padding-inline: 46px; }
}

/* ============================================================
   Badges row (Owners — "Your Partner in Progress")
   ============================================================ */
.badges { display: grid; grid-template-columns: repeat(3, 1fr); gap: 24px; margin-top: 30px; }
.badge { text-align: center; padding: 24px; }
/* Large blue glyph in a soft cyan/green glow halo (per mockup). */
.badge__icon {
  display: inline-grid; place-items: center;
  width: 96px; height: 96px; margin: 0 auto 16px; border-radius: 50%;
  background: radial-gradient(circle at 50% 45%, #f6fcff, #e6f5ff);
  border: 1.5px solid rgba(150,230,255,.7);
  box-shadow: 0 0 26px rgba(90,205,235,.5), 0 0 12px rgba(130,240,205,.38);
  color: var(--blue-600);
}
.badge__icon svg { width: 52px; height: 52px; filter: drop-shadow(0 0 5px rgba(90,205,255,.5)); }
/* Delivered PNG badge icons already bake in the glow — no CSS ring/halo. */
.badge__icon:has(img) { width: auto; height: auto; background: none; border: 0; box-shadow: none; }
.badge__iconimg { width: 180px; height: 180px; object-fit: contain; display: block; }
.badge__title { color: var(--navy-900); font-weight: 700; }
@media (max-width: 768px) { .badges { grid-template-columns: 1fr; } }

/* ============================================================
   Solutions / info columns (Owners — 3-4 up text columns)
   ============================================================ */
.infocols { display: grid; grid-template-columns: repeat(3, 1fr); gap: 30px; margin-top: 30px; }
.infocol__title { color: var(--cyan-300); font-size: 18px; margin-bottom: 10px; }
.infocol__body { color: rgba(255,255,255,.82); font-size: 15px; }
.infocols--4 { grid-template-columns: repeat(4, 1fr); }
@media (max-width: 900px) { .infocols, .infocols--4 { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 560px) { .infocols, .infocols--4 { grid-template-columns: 1fr; } }

/* Manage cards (Owners) — 3 light cards */
/* Cyan band the 3 cards sit on; cards pull up to overlap the dashboard above. */
.manage-band { background: linear-gradient(180deg, #22bfe9 0%, #0e8fc6 100%); padding: 0 0 60px; margin-top: 150px; }
.mini-cards { display: grid; grid-template-columns: repeat(3, 1fr); gap: 24px; margin-top: -120px; }
.mini-card { background: var(--white); border: 1px solid var(--line); border-radius: var(--radius); padding: 30px 26px; text-align: center; box-shadow: 0 16px 40px rgba(8,29,57,.18); }
.mini-card__icon { display: block; width: 48px; height: 48px; margin: 0 auto 14px; color: var(--blue-600); }
.mini-card__icon svg { width: 100%; height: 100%; }
.mini-card__title { color: var(--navy-900); margin-bottom: 8px; }
.mini-card__body { color: var(--muted); font-size: 14px; }
@media (max-width: 768px) { .mini-cards { grid-template-columns: 1fr; } }

/* ============================================================
   Timeline (About Us)
   ============================================================ */
.timeline { position: relative; max-width: 900px; margin: 40px auto 0; }
/* gap is 96px, not 28px, because the node geometry between orb and card needs room: a 12px tail
   + 36px clear + a 27px dot = 75px. At 28px the dot had to straddle the card edge, which is why
   it used to sit half on top of the card. */
.timeline__item { position: relative; display: grid; grid-template-columns: 232px 1fr; gap: 96px; margin-bottom: 28px; align-items: center; }
/* Vertical spine, per item rather than one full-height line on .timeline. The mockup has NO spine
   above the first dot (verified: nothing at x716 for y1500-1840) and none below the last card, and
   the old .timeline::before ran the full height at left:116px — straight through the 2001 orb.
   Drawn from each dot's centre down through the 28px margin to the next dot. */
.timeline__item::before {
  content: ""; position: absolute; z-index: 0;
  left: 272px; transform: translateX(-50%);
  top: 0; bottom: -28px; width: 3px; background: #fff;
}
/* The spine must be CONTINUOUS and touch every circle. Running each segment from its own dot
   (top:50%) down through the margin left a gap equal to the top half of the next item — measured
   at 116px per joint, so the line visibly stopped short of each circle. Each segment now spans its
   whole item plus the 28px margin, and only the two ends are trimmed: the first starts at its dot,
   the last stops at its dot. Result is one unbroken line from the first circle to the last. */
.timeline__item:first-child::before { top: 50%; }
.timeline__item:last-child::before  { bottom: 50%; }
/* Horizontal connector, orb edge -> dot. White in the mockup (#ffffff, 4 mockup px), NOT the
   card blue. Spans from the end of the 232px year column to the dot's left edge. */
.timeline__item::after {
  content: ""; position: absolute; z-index: 0;
  left: 232px; width: 27px; height: 2px;
  top: 50%; transform: translateY(-50%); background: #fff;
}
/* Delivered glossy orb graphic (glow baked in); year sits on top. */
.timeline__year {
  display: flex; flex-direction: column; align-items: center; justify-content: center; line-height: 1.05;
  width: 232px; height: 232px;
  background: url("../img/Orb.png") center / contain no-repeat;
  color: #fff; font-weight: 800; font-size: 36px; text-shadow: 0 1px 6px rgba(4,40,80,.55);
  position: relative; z-index: 1;
}
/* Light card with navy title + short underline accent (per mockup). */
.timeline__card {
  position: relative;
  background: #92d8ff;
  border-radius: var(--radius); padding: 22px 26px;
  box-shadow: 0 12px 28px rgba(4,30,60,.22);
}
.timeline__card h3 { color: #023770; font-size: 18px; margin-bottom: 12px; padding-bottom: 10px; position: relative; }
.timeline__card h3::after { content: ""; position: absolute; left: 0; bottom: 0; width: 56px; height: 2px; background: #5ab4e6; }
.timeline__card p { color: #23527d; font-size: 15px; }
/* Connector line + node dot from the orb to the card. */
/* Speech-bubble TAIL on the card's left edge, pointing at the dot. Measured off the mockup by
   scanning columns left of the card edge (x831): 24px tall at -2, 20 at -6, 15 at -10, 10 at -14,
   6 at -18, 1 at -22 — a clean triangle 23 mockup px deep and 25 tall, vertically centred on
   y1890, exactly the dot's centre. At the mockup's 1.897x scale (2732/1440) that is 12x13 CSS px.
   Same #92d8ff as the card, so it reads as part of it. */
.timeline__card::before {
  content: ""; position: absolute; left: -12px; top: 50%; transform: translateY(-50%);
  width: 0; height: 0;
  border-top: 6.5px solid transparent;
  border-bottom: 6.5px solid transparent;
  border-right: 12px solid #92d8ff;
}
/* Node DOT. Mockup: a flat #92d8ff fill 51 mockup px across (x690..740) => 27px, no glow. It was
   13px of near-white #eaf7ff with a glow, less than half the size and the wrong colour, sitting
   at left:-7px so it straddled the card edge instead of standing clear of the tail. */
.timeline__card::after {
  content: ""; position: absolute; left: -69px; top: 50%; transform: translateY(-50%);
  width: 27px; height: 27px; border-radius: 50%; background: #92d8ff;
}
/* Single glow accent CLOSING the timeline — one only, centred, well below the last card.
   Measured in new-Revised About Us Page.png: centred at y~4241, roughly 245px under the final
   card and ~187px above the section end, spanning ~934 of 2732px (about a third of the section
   width) and tapering to nothing at both ends. It is NOT repeated per row.
   Kept as its own element rather than .timeline::after because .timeline::before draws the
   vertical spine with bottom:10px — a block ::after would grow .timeline and drag the spine down
   through the glow, whereas the mockup ends the spine at the last card. */
/* ---- Timeline scroll choreography ------------------------------------------------------------
   Each .timeline__item carries [data-reveal], so main.js's existing IntersectionObserver stamps
   .is-visible once as the row enters view — same mechanism the services strip uses, no new JS and
   reduced-motion is already honoured there. Because the observer fires per row, the stagger comes
   from the scroll itself rather than from fixed nth-child delays, so it stays in step however fast
   the user scrolls.

   The parts land in the order the eye reads them: orb, then card, then the connector draws out to
   the dot, then the spine flows down toward the next row.
   The spine also carries a slow continuous gradient travel, which is what reads as "flow" once the
   row has settled — a soft bright band drifting downward along the line. ---- */
.timeline__year {
  opacity: 0; transform: scale(.86);
  transition: opacity .75s ease .04s, transform .75s cubic-bezier(.2,.7,.2,1) .04s;
}
.timeline__item.is-visible .timeline__year { opacity: 1; transform: none; }

.timeline__card {
  opacity: 0; transform: translateX(26px);
  transition: opacity .75s ease .16s, transform .75s cubic-bezier(.2,.7,.2,1) .16s;
}
.timeline__item.is-visible .timeline__card { opacity: 1; transform: none; }

/* Connector draws left-to-right, out of the orb toward the dot. translateY(-50%) has to be kept
   in the transform or the line jumps off its centre line while animating. */
.timeline__item::after {
  transform: translateY(-50%) scaleX(0); transform-origin: left center;
  transition: transform .55s cubic-bezier(.2,.7,.2,1) .34s;
}
.timeline__item.is-visible::after { transform: translateY(-50%) scaleX(1); }

/* Spine draws downward from the dot, slowest of the four so the line always trails the content. */
.timeline__item::before {
  opacity: 0; transform: translateX(-50%) scaleY(0); transform-origin: top center;
  transition: opacity 1.15s ease .46s, transform 1.15s cubic-bezier(.35,0,.2,1) .46s;
  background: linear-gradient(180deg, rgba(255,255,255,.35) 0%, #fff 42%, rgba(255,255,255,.35) 100%);
  background-size: 100% 240%;
  animation: timeline-spine-flow 7s linear infinite;
}
.timeline__item.is-visible::before { opacity: 1; transform: translateX(-50%) scaleY(1); }
@keyframes timeline-spine-flow {
  from { background-position: 0 -120%; }
  to   { background-position: 0 120%; }
}

@media (prefers-reduced-motion: reduce) {
  .timeline__year, .timeline__card { opacity: 1; transform: none; transition: none; }
  .timeline__item::after  { transform: translateY(-50%) scaleX(1); transition: none; }
  .timeline__item::before {
    opacity: 1; transform: translateX(-50%) scaleY(1); transition: none;
    animation: none; background: #fff;
  }
}

.timeline-glow {
  display: block; width: min(492px, 80%); height: 72px; margin: 95px auto 0;
  background: url("../img/1x/line-glow.webp") center / 100% 100% no-repeat;
}
@media (max-width: 600px) {
  .timeline__item { grid-template-columns: 80px 1fr; gap: 16px; }
  .timeline__item::before { left: 88px; }        /* in the orb->card gap, NOT through the orb */
  .timeline__item::after { display: none; }      /* no room for a connector at 16px gap */
  .timeline__card::after { display: none; }      /* nor for a 27px dot */
  .timeline__year { width: 80px; height: 80px; font-size: 14px; }
}

/* ============================================================
   Team grid (About Us)
   ============================================================ */
/* padding-top reserves the space the overflowing heads need. .team-card__photo is
   overflow:visible with the figure at 121% of the tile (the mockup's treatment), so each head
   rises ~21% of the tile height above its tile — ~62px on these 296px tiles. Without this the
   heads punch into the lead row's badges directly above. */
.team-grid { display: grid; grid-template-columns: repeat(4, calc((100% - 78px) / 8)); justify-content: space-between; gap: 26px; margin-top: 8px; padding-top: 36px; }
.team-card { text-align: center; }
.team-card__name { font-weight: 700; }
.team-card__role { font-size: 12px; opacity: .95; }
@media (max-width: 860px) {
  .team-grid { grid-template-columns: repeat(2, calc((100% - 26px) / 4)); row-gap: 52px; }
}
@media (max-width: 480px) {
  .team-grid { grid-template-columns: 50%; row-gap: 64px; }
}

/* Photo card: real photo (cutout, transparent bg) sits on a solid color block so every
   headshot reads consistently even though the source photos have different backgrounds. */
/* overflow is VISIBLE on purpose. In the mockup the colour square is a BACKDROP, not a frame:
   the head rises clear of its top edge onto the page wash. Measured on the Ryan card in
   new-Revised About Us Page.png — the head sits 111px above the tile top and the figure is 121%
   of the tile height, with the body flush to the tile's bottom. Clipping to the square (the
   previous overflow:hidden) beheaded anyone whose source crop was tall.
   Row padding-top below reserves the space that overflow now needs, so an overflowing head
   cannot collide with the badge of the row above. */
.team-card__photo {
  display: block; position: relative; aspect-ratio: 1; overflow: visible;
  border-radius: 4px; margin-bottom: 12px;
  background: var(--card-color, #bfe6fb);
  border: 1px solid rgba(255,255,255,.5);
  /* Only the TOP is open. overflow:visible alone was too blunt — it stopped clipping sideways
     too, and these cutouts are wider than their tiles (Ryan and Erika spilled 54px past EACH
     edge). In the mockup the photos are flush with the tile's left/right edges and cut off at its
     bottom, with the tile's corner rounding applied; only the head escapes upward.
     inset() with a negative top expands the clip region above the box while keeping the other
     three sides on it, and `round` reapplies the corner radius. -100% is relative to the box
     height, so the headroom scales with the tile instead of being a magic pixel value. */
  clip-path: inset(-100% 0 0 0 round 4px);
}
.team-card__photo img {
  position: absolute; bottom: 0; left: 50%; transform: translateX(-50%);
  height: 121%; width: auto; max-width: none; display: block;
}
.team-card__badge {
  display: inline-flex; flex-direction: column; align-items: center; gap: 2px;
  background: rgba(29,90,148,.55); border: 1px solid rgba(255,255,255,.5);
  border-radius: 10px; padding: 10px 16px; color: #fff; min-width: 70%;
}

/* Light cyan team section with flowing fiber-line art (per mockup) */
.team-section {
  color: #06375f; position: relative; overflow: hidden;
  background: linear-gradient(135deg, #eaf7ff 0%, #bfe6fb 45%, #4fb3e8 100%);
}
.team-section::before {
  content: ""; position: absolute; inset: 0;
  background: url("../img/fiber-light-lines.webp") center / cover no-repeat;
  opacity: .6; pointer-events: none;
}
.team-section > .container { position: relative; z-index: 1; }
.team-head {
  display: flex; align-items: flex-end; justify-content: space-between; flex-wrap: wrap;
  gap: 30px; margin-bottom: 28px;
  /* Same reason as .team-grid: the lead heads overflow ~47px above their 224px tiles, which
     without headroom escape the section entirely and overlap the timeline band above. */
  padding-top: 36px;
}
.team-title { text-align: left; line-height: .95; }
.team-title__a, .team-title__b { display: block; font-weight: 700; text-shadow: 0 4px 18px rgba(10,50,90,.35); }
.team-title__a { color: #fff; font-size: clamp(38px, 5.5vw, 64px); }
.team-title__b { color: rgba(255,255,255,.9); font-size: clamp(26px, 3.8vw, 44px); }
.team-head .team-card--lead { width: calc((100% - 78px) / 8); }
/* These must follow the base rule: media queries add no specificity, so placed earlier in the
   file the 4-column value simply won. Each mirrors the .team-grid column count at that width so
   a lead tile is always exactly the size of a grid tile. */
@media (max-width: 860px) { .team-head .team-card--lead { width: calc((100% - 26px) / 4); } }
@media (max-width: 480px) { .team-head .team-card--lead { width: 50%; } }
@media (max-width: 680px) {
  /* Below 680px the lead cards wrap onto their own lines, and the 30px flex gap is narrower than
     a lead head's ~47px overflow, so the lower lead's head landed on the upper one's badge. */
  .team-head { justify-content: center; text-align: center; row-gap: 44px; }
  .team-title { text-align: center; }
}
/* Must come AFTER the 680px block above, which sets row-gap:82px — at 480px the grid drops to one
   column so a tile is 432px and its head overflows ~91px, more than 82px of gap. */
@media (max-width: 480px) { .team-head { row-gap: 64px; } }

/* ============================================================
   Support — Help Center, FAQ accordion, guides, status panel
   ============================================================ */
.help-cards { display: grid; grid-template-columns: repeat(2, 1fr); gap: 24px; max-width: 880px; margin: 40px auto 0; }
.help-card { display: flex; gap: 16px; align-items: flex-start; background: var(--white); border: 1px solid var(--line); border-radius: var(--radius); padding: 24px; transition: transform .15s ease, box-shadow .15s ease; }
.help-card:hover { transform: translateY(-3px); box-shadow: 0 12px 30px rgba(16,42,92,.12); }
.help-card__icon { display: block; flex: 0 0 auto; width: 48px; height: 48px; color: var(--blue-600); }
.help-card__icon svg { width: 100%; height: 100%; }
.help-card__title { color: var(--navy-900); margin-bottom: 6px; }
.help-card__more { color: var(--blue-600); font-weight: 600; font-size: 14px; }
@media (max-width: 700px) { .help-cards { grid-template-columns: 1fr; } }

/* FAQ accordion (uses native <details>) */
.faq { max-width: 820px; margin: 0 auto; }
.faq__item { border-bottom: 1px solid var(--line); }
.faq__item summary {
  display: flex; justify-content: space-between; align-items: center; gap: 16px;
  padding: 18px 4px; cursor: pointer; font-weight: 600; color: var(--navy-900);
  list-style: none;
}
.faq__item summary::-webkit-details-marker { display: none; }
.faq__item summary::after { content: "+"; color: var(--blue-600); font-size: 22px; font-weight: 400; transition: transform .2s ease; }
.faq__item[open] summary::after { content: "−"; }
.faq__item p { padding: 0 4px 18px; color: var(--muted); }

/* Video / self-help guide cards */
/* Self-Help video guides — large carousel cards with a "Go watch" control (mockup). */
.guides-carousel { margin-top: 34px; }
.guides-carousel .svc-carousel__track > .guide-card {
  flex: 0 0 calc(64% - 22px); scroll-snap-align: center;
  position: relative; aspect-ratio: 16 / 9; border-radius: 18px; overflow: hidden;
  text-decoration: none; background-size: cover; background-position: center;
  box-shadow: 0 16px 40px rgba(4,20,44,.3);
}
.guide-card::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(4,20,44,.12) 35%, rgba(4,20,44,.6) 100%);
}
/* Per mockup annotation: a blue filter tints the peeking cards and "dissolves when it is the
   main image" — same treatment as .news-card--feature's centered-card dissolve. */
.guide-card::before {
  content: ""; position: absolute; inset: 0; z-index: 1;
  background: linear-gradient(180deg, rgba(12,92,150,.55) 0%, rgba(6,38,78,.78) 100%);
  transition: opacity .45s ease;
}
.guide-card.is-active::before,
.guide-card:hover::before,
.guide-card:focus-visible::before { opacity: 0; }
.guide-card__title {
  position: absolute; left: 26px; bottom: 24px; z-index: 2; color: #fff;
  font-size: clamp(24px, 2.4vw, 34px); font-weight: 800; text-shadow: 0 2px 12px rgba(0,0,0,.45);
}
.guide-card__watch {
  position: absolute; right: 28px; top: 50%; transform: translateY(-50%); z-index: 2;
  display: inline-flex; align-items: center; gap: 12px; color: #fff; font-size: 19px; font-weight: 600;
}
.guide-card__watch-ic { display: inline-grid; place-items: center; width: 52px; height: 52px; border-radius: 50%; border: 2px solid rgba(255,255,255,.9); font-size: 22px; }
@media (max-width: 700px) { .guides-carousel .svc-carousel__track > .guide-card { flex-basis: 86%; } }

/* Network / service status panel */
.status-panel { background: linear-gradient(160deg, var(--navy-900), var(--navy-950)); color: var(--white); border-radius: var(--radius); padding: 30px; display: grid; grid-template-columns: 1fr 1fr; gap: 30px; }
.status-panel__list { display: grid; gap: 14px; }
.status-row { display: flex; align-items: center; justify-content: space-between; padding: 12px 16px; background: rgba(255,255,255,.06); border-radius: 10px; }
.status-dot { width: 10px; height: 10px; border-radius: 50%; display: inline-block; margin-right: 8px; }
.status-dot--ok { background: #3ddc84; box-shadow: 0 0 10px #3ddc84; }
.status-dot--warn { background: #ffb020; box-shadow: 0 0 10px #ffb020; }
@media (max-width: 768px) { .status-panel { grid-template-columns: 1fr; } }

/* Support team CTA (2 cards: chat / request) */
.support-cta { display: grid; grid-template-columns: 1fr 1.2fr; gap: 28px; margin-top: 30px; align-items: start; }
@media (max-width: 768px) { .support-cta { grid-template-columns: 1fr; } }

/* ============================================================
   Support page — LIGHT sky-blue theme (overrides earlier dark)
   ============================================================ */
.support-sky        { background: linear-gradient(180deg, #f8fcff, #ecf7ff); }
/* Help Center section — radial glow centered behind the cards, per mockup. */
.support-sky--radial { background: radial-gradient(circle at 50% 50%, #c2e8ff 0%, #ffffff 100%); }
/* Canonical Support gradient heading — reuse wherever a support page needs a gradient title. */
.section__title--support-grad {
  background: var(--grad-support-heading);
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent; color: transparent;
}
/* Support subheaders (Self-Help Guides, Live Service Updates, Our Support Team, etc.) — same
   dark blue as the article body's h3 and the "Still need help?" band, not the generic navy. */
.support-sky .section__title:not(.section__title--grad):not(.section__title--support-grad),
.support-sky--vivid .section__title:not(.section__title--grad):not(.section__title--support-grad) {
  color: #023770;
}
/* Real isometric device/network artwork behind the FAQ band (marketing asset). */
.support-sky--vivid {
  position: relative; overflow: hidden;
  background: #b6e5fb url("../img/support-faq-bg.webp") center top / 138% auto no-repeat;
}
.support-sky--vivid > .container { position: relative; z-index: 1; }
/* Subtle light facets behind the guides band */
.support-sky--facets { position: relative; overflow: hidden; background: #80cfff; }
.support-sky--facets::before {
  content: ""; position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background:
    linear-gradient(126deg, rgba(111,192,235,.14) 0 24%, transparent 24% 44%),
    linear-gradient(300deg, rgba(111,192,235,.10) 0 18%, transparent 18% 40%);
}
.support-sky--facets > .container { position: relative; z-index: 1; }

/* Hero search bar */
/* Frosted-glass search pill — magnifier icon on the left, matching the mockup. */
.hero-search {
  display: flex; align-items: center; gap: 14px;
  max-width: 620px; margin-top: 22px; padding: 12px 26px;
  background: rgba(255,255,255,.32); border: 3px solid #6b7280;
  border-radius: 999px; backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px);
  box-shadow: 0 10px 30px rgba(8,29,57,.18);
}
/* Bigger grey magnifier, flipped so the handle points to the left. */
.hero-search__icon { flex: 0 0 auto; padding: 0; border: 0; background: transparent; color: #6b7280; font-size: 32px; line-height: 1; cursor: pointer; transform: scaleX(-1); }
.hero-search input { flex: 1; border: 0; outline: 0; background: transparent; font: inherit; color: #2a2f38; }
.hero-search input::placeholder { color: #7f858e; }
.hero-search:focus-within { outline: 3px solid var(--blue-600); outline-offset: 3px; }

/* Help Center cards — title left, circular glowing icon right */
.help-cards { grid-template-columns: repeat(2, 1fr); gap: 30px; max-width: 800px; margin-inline: auto; }
.help-card {
  display: flex; flex-direction: column; align-items: stretch; gap: 10px;
  background: #fff; border: 1px solid var(--line); border-radius: 16px; padding: 26px 28px;
  box-shadow: 0 10px 30px rgba(16,42,92,.08);
}
/* Top row: title, then the glowing icon right beside it (left-aligned, not far-right). */
.help-card__head { display: flex; align-items: center; justify-content: flex-start; gap: 22px; }
.help-card__title { font-size: 32px; font-weight: 700; color: #023770; }
.help-card__body  { font-size: 18px; color: var(--muted); }
.help-card__more  { font-size: 14px; font-weight: 700; color: var(--cyan-ink); margin-top: 2px; }
.help-card__icon {
  flex: 0 0 auto; display: grid; place-items: center;
  width: 66px; height: 66px; padding: 0; border-radius: 50%;
  color: var(--blue-600); background: #eaf6ff;
  border: 1.5px solid rgba(120,215,255,.8); box-shadow: 0 0 22px rgba(90,200,255,.45);
}
.help-card__icon svg { width: 34px; height: 34px; }
/* Detailed category icons are bare glowing glyphs — no ring — per the mockup. */
.help-card__icon:has(img) {
  width: auto; height: auto; border: 0; background: transparent; box-shadow: none;
}
.help-card__iconimg {
  width: 118px; height: 118px; object-fit: contain; display: block;
}

/* ---- Modal (Help Center category -> article list) ---- */
.modal { position: fixed; inset: 0; z-index: 1000; display: grid; place-items: center; padding: 24px; }
.modal[hidden] { display: none; }
.modal__overlay { position: absolute; inset: 0; background: rgba(4,20,44,.62); backdrop-filter: blur(4px); -webkit-backdrop-filter: blur(4px); }
.modal__panel {
  position: relative; z-index: 1; width: min(480px, 100%);
  background: #fff; border-radius: 20px; padding: 38px 36px 32px; text-align: center;
  box-shadow: 0 34px 80px rgba(4,20,44,.42); animation: modalIn .22s ease;
}
@keyframes modalIn { from { opacity: 0; transform: translateY(16px) scale(.97); } to { opacity: 1; transform: none; } }
.modal__close {
  position: absolute; top: 14px; right: 16px; width: 34px; height: 34px;
  background: none; border: 0; font-size: 28px; line-height: 1; color: var(--muted); cursor: pointer;
  border-radius: 50%; transition: background .15s, color .15s;
}
.modal__close:hover { background: #eef4fb; color: var(--navy-900); }
.modal__icon { display: block; width: 78px; height: 78px; margin: 0 auto 14px; }
.modal__icon img {
  width: 78px; height: 78px; object-fit: contain;
  filter: drop-shadow(0 0 7px rgba(80,195,255,.7)) drop-shadow(0 0 2px rgba(130,220,255,.9));
}
.modal__title { color: #023770; font-size: clamp(22px, 3vw, 28px); margin-bottom: 8px; }
/* Video guide modal — wider panel, video fills it edge-to-edge below the title. */
.modal__panel--video { width: min(800px, 100%); }
.modal__video { display: block; width: 100%; border-radius: 12px; background: #000; }
.modal__lead { color: var(--muted); font-size: 14px; line-height: 1.5; margin: 0 auto 20px; max-width: 340px; }
.modal__links { list-style: none; display: grid; gap: 8px; margin: 0 0 22px; padding: 0; text-align: left; }
.modal__links a {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 13px 16px; border-radius: 11px; border: 1px solid var(--line);
  color: var(--navy-900); font-weight: 600; transition: background .15s, border-color .15s, color .15s;
}
.modal__links a:hover { background: #eef8fd; border-color: var(--blue-600); color: var(--blue-700); }
.modal__links a span { color: var(--blue-600); }

/* FAQ — two-column white panel */
.faq-panel {
  display: grid; grid-template-columns: 1fr 1.1fr; gap: 28px; align-items: start;
  background: #fff;  padding: 40px; box-shadow: 0 20px 50px rgba(8,29,57,.18);
}
/* Diagonal hatch-line bands above and below the FAQ panel (200px each). */
.faq-lines {
  height: 200px;
  background-color: rgba(150,210,242,.6);
  background-image: repeating-linear-gradient(135deg, rgba(255,255,255,.5) 0 1.5px, rgba(255,255,255,0) 1.5px 11px);
}
.faq-panel__intro { border-left: 1px solid #e0e9f3; border-right: 1px solid #e0e9f3; padding: 0 26px; margin: 0 20px; }
.faq-panel__intro h2 { font-size: clamp(28px, 3.4vw, 40px); color: #023770; margin-bottom: 10px; }
.faq-panel__intro p  { color: var(--muted); margin-bottom: 20px; }
.faq-panel .faq__item { border: 1px solid var(--line); border-radius: 10px; margin-bottom: 16px; padding: 2px 18px; }
.faq-panel .faq__item summary::after { content: "⌄"; }
.faq-panel .faq__item[open] summary::after { content: "⌃"; }
/* FAQ rows that link straight to a support article instead of expanding inline. */
.faq__item--link {
  display: flex; justify-content: space-between; align-items: center; gap: 16px;
  padding: 18px 4px; font-weight: 600; color: var(--navy-900);
}
.faq__item--link::after { content: "→"; color: var(--blue-600); font-size: 18px; }
.faq__item--link:hover { color: var(--blue-600); }
@media (max-width: 820px) { .faq-panel { grid-template-columns: 1fr; } }

/* Video guides — title overlaid on image, staggered */

/* Live Service Updates dashboard (light) */
.live-dash { background: #ecf7ff; border-radius: 20px; padding: 24px; margin-top: 24px; box-shadow: 0 16px 40px rgba(16,42,92,.10); }
.live-dash__bar { display: flex; align-items: center; gap: 14px; margin-bottom: 20px; }
.live-dash__pill { background: #023770; color: #fff; padding: 8px 20px; border-radius: 999px; font-weight: 700; }
.live-dash__user { margin-left: auto; color: #023770; font-weight: 600; }
.live-dash__grid { display: grid; grid-template-columns: 1fr 1fr; gap: 18px; }
.dash-card { background: #fff; border-radius: 14px; padding: 20px; box-shadow: 0 6px 18px rgba(16,42,92,.08); }
.dash-card--wide { grid-column: 1 / -1; }
.dash-card h3 { color: #023770; font-size: 22px; }
.dash-eyebrow { text-transform: uppercase; letter-spacing: 1px; font-size: 13px; color: #023770; margin-bottom: 12px; }
.dash-muted { color: var(--muted); font-size: 14px; }
.dash-row { display: flex; align-items: center; justify-content: space-between; }
.dash-row--head { margin: 14px 0 6px; font-weight: 700; color: var(--navy-900); }
.dash-seeall { color: var(--cyan-400); font-weight: 600; font-size: 14px; }
.dash-feed { display: flex; justify-content: space-between; background: var(--bg-alt); border-radius: 8px; padding: 10px 14px; margin-top: 8px; font-size: 14px; color: var(--ink); }
.dash-legend { display: flex; gap: 18px; flex-wrap: wrap; font-size: 13px; color: var(--ink); margin-bottom: 14px; }
.dash-legend span { display: inline-flex; align-items: center; }
.status-dot--down { background: #e0443d; box-shadow: 0 0 10px #e0443d; }
.dash-map { height: 150px; border-radius: 10px; position: relative; overflow: hidden;
  background:
    repeating-linear-gradient(0deg, rgba(255,255,255,.06) 0 1px, transparent 1px 24px),
    repeating-linear-gradient(90deg, rgba(255,255,255,.06) 0 1px, transparent 1px 24px),
    radial-gradient(circle at 50% 50%, #1b6fb0, #0a3a63); }
.dash-map::before { content: ""; position: absolute; left: 28%; top: 38%; width: 14px; height: 14px; border-radius: 50%; background: #3ddc84; box-shadow: 0 0 12px #3ddc84, 120px 40px 0 -2px #ffb020, 120px 40px 14px -4px rgba(255,176,32,.7); }
.dash-hex { position: absolute; left: 50%; top: 50%; width: 40px; height: 46px; transform: translate(-50%,-50%); background: #e0443d; clip-path: polygon(50% 0,100% 25%,100% 75%,50% 100%,0 75%,0 25%); box-shadow: 0 0 18px rgba(224,68,61,.8); }
.dash-progress__bar { height: 8px; border-radius: 999px; background: #d9e7f5; position: relative; margin-bottom: 10px; }
.dash-progress__bar span { position: absolute; left: 0; top: 0; bottom: 0; border-radius: 999px; background: var(--cyan-400); }
.dash-progress__stops { display: flex; justify-content: space-between; font-size: 12px; color: var(--muted); margin-bottom: 16px; }
.dash-wave { height: 90px; border-radius: 10px; margin-top: 12px; position: relative; overflow: hidden;
  background:
    repeating-linear-gradient(90deg, rgba(8,55,112,.06) 0 1px, transparent 1px 44px),
    linear-gradient(180deg, #f3f9ff, #eaf4ff); }
.dash-wave::after { content: ""; position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(63,198,255,.55), rgba(63,198,255,.06));
  clip-path: polygon(0 72%, 10% 58%, 22% 64%, 34% 40%, 46% 52%, 58% 32%, 70% 46%, 82% 26%, 100% 38%, 100% 100%, 0 100%); }
.dash-radios { display: flex; flex-direction: column; gap: 10px; align-items: center; color: var(--ink); }
.dash-radios label { display: inline-flex; align-items: center; gap: 8px; }
@media (max-width: 768px) { .live-dash__grid { grid-template-columns: 1fr; } }

/* How To Connect's "By Property" launcher is hidden: the modal is reached through the
   ?community=..&help=.. deep link instead. The button still ships (the article opts in via
   connection_modal), so un-hiding is a one-line change; tests/hermetic/connection-instruction.spec.ts
   pins it as present-but-hidden. */
.article__by-property {
  display: none;
}

/* Support CTA band (light) + cards */
/* Faint support-team photo behind the CTA (light wash keeps cards/text readable). */
.support-cta-band {
  background:
    linear-gradient(rgba(222,240,250,.9), rgba(222,240,250,.94)),
    #c6e3f5 url("../img/products-support.webp") center / cover no-repeat;
}
.support-cta-band .section__title { color: #023770; }
.support-cta__col { display: flex; flex-direction: column; gap: 24px; }
.support-card { background: #fff; border-radius: 16px; padding: 26px; box-shadow: 0 10px 30px rgba(16,42,92,.10); }
.support-card__icon { display: grid; place-items: center; width: 54px; height: 54px; border-radius: 50%; background: #eaf6ff; color: var(--blue-600); border: 1.5px solid rgba(120,215,255,.8); box-shadow: 0 0 18px rgba(90,200,255,.4); margin-bottom: 14px; }
.support-card__icon svg { width: 26px; height: 26px; }
.support-card h3 { color: #023770; margin-bottom: 8px; }
.support-card p { color: var(--muted); font-size: 15px; }
.support-card__hours { color: var(--ink); margin-top: 10px; }
.support-card__phone { color: var(--blue-600); font-weight: 700; text-decoration: underline; }
.support-cta__form .contact-form { box-shadow: 0 16px 40px rgba(8,29,57,.18); }

/* ============================================================
   Support templates — category index (T10) + article (T11)
   ============================================================ */
.breadcrumb { font-size: 14px; color: var(--muted); margin-bottom: 24px; }
.breadcrumb a { color: var(--blue-600); }
.breadcrumb a:hover { color: var(--cyan-400); }
.breadcrumb__current { color: var(--ink); }

.support-layout { display: grid; grid-template-columns: 240px 1fr; gap: 40px; align-items: start; }
@media (max-width: 768px) { .support-layout { grid-template-columns: 1fr; } }

.support-nav { background: #fff; border: 1px solid var(--line); border-radius: var(--radius); padding: 20px; position: sticky; top: 100px; }
.support-nav__heading { font-size: 13px; text-transform: uppercase; letter-spacing: .5px; color: var(--muted); margin-bottom: 12px; }
.support-nav ul { display: grid; gap: 4px; }
.support-nav__item { display: block; padding: 10px 12px; border-radius: 8px; color: var(--navy-900); font-weight: 600; }
.support-nav__item:hover { background: var(--bg-alt); }
.support-nav__item.is-active { background: #eaf6ff; color: var(--blue-700); }
@media (max-width: 768px) { .support-nav { position: static; } }

.article-list { display: grid; gap: 16px; }
.article-list__item { display: block; background: #fff; border: 1px solid var(--line); border-radius: var(--radius); padding: 22px 24px; transition: box-shadow .15s ease, transform .15s ease; }
.article-list__item:hover { transform: translateY(-2px); box-shadow: 0 12px 30px rgba(16,42,92,.10); }
.article-list__title { display: block; font-size: 18px; font-weight: 700; color: #023770; margin-bottom: 6px; }
.article-list__excerpt { display: block; color: var(--muted); font-size: 15px; }
.article-list__more { display: inline-block; margin-top: 10px; font-weight: 700; font-size: 14px; color: var(--cyan-ink); }

/* Support-article hero banner (per the delivered header image). */
/* Support-article hero: full-bleed photo with centered title + search bar,
   matching the "How to find your MAC address" mockup. */
/* Fallback for articles with no delivered hero photo yet — reuse the login page's
   background instead of the generic cosmic gradient. An inline header_img (set per
   article) always wins over this since inline styles beat stylesheet rules. */
.page-hero--article {
  min-height: clamp(480px, 50vw, 600px);
  /* cover by default. The 128% zoom below is a DESKTOP framing choice and only holds while the
     painted height still clears this hero's floor: background-size:128% fixes the width and lets
     the height fall out of the aspect ratio, so at 390px wide the art paints 241px tall inside a
     480px hero — and repeated to fill it. Threshold for the 2.071:1 art is ~820px viewport
     (1.28 x 820 / 2.071 = 507px vs a 480px floor); 900px leaves margin for taller art. */
  background-size: cover;
  background-image: url("../img/login-bg.webp");
}
@media (min-width: 900px) {
  .page-hero--article { background-size: 128%; }
}
.page-hero--article::before {
  background: linear-gradient(180deg, rgba(4,20,44,.30), rgba(4,20,44,.10) 45%, rgba(4,20,44,.28));
}
.page-hero--article .page-hero__inner {
  width: 100%; text-align: center;
  /* .site-header is position:absolute and floats transparently over the hero, and it is 106px
     tall — but .page-hero__inner only pads 70px. The hero centres its content, so short titles
     sit low and never notice; a long one (news headlines run to 160 chars) fills the box, the
     centring bottoms out, and the first line lands UNDER the logo. 112px guarantees clearance and
     simply lets the hero grow, since min-height is a floor not a cap here. Scoped to article
     heroes: that is where long titles live, and other heroes keep their existing rhythm. */
  padding-top: 112px;
}
.page-hero--article .page-hero__title {
  margin: 0 auto; max-width: 900px; font-size: clamp(34px, 5vw, 60px);
  text-shadow: 0 2px 14px rgba(4,18,40,.5), 0 1px 3px rgba(4,18,40,.55);
}
.page-hero--article .hero-search { margin-inline: auto; }
/* Opt-in left-aligned article hero (How To Connect). The default article hero is centred and
   emits title > search > subtitle; the mockup wants left-aligned title > subtitle > search, so
   the inner becomes a flex column and the three children are reordered. Scoped to the modifier
   class so the other subtitled articles keep the centred hero they were designed against. */
.page-hero--align-left .page-hero__inner {
  text-align: left; display: flex; flex-direction: column; align-items: flex-start; gap: 6px;
}
.page-hero--align-left .page-hero__title    { order: 1; margin: 0; max-width: 820px; }
.page-hero--align-left .page-hero__subtitle { order: 2; margin: 0 0 18px; }
.page-hero--align-left .hero-search         { order: 3; margin-inline: 0; }
/* Embedded STELLAR Speed Test widget (speed-is-not-performing hero) — sized/positioned
   per mockup: a floating card roughly half the hero's width, tall enough for the
   logo/Start-button/stats-row/IP-address layout the external page renders. */
.page-hero__widget {
  width: min(560px, 92%); margin: 28px auto 0; border-radius: 20px; overflow: hidden;
  box-shadow: 0 20px 50px rgba(4,20,44,.35);
}
.page-hero__widget iframe { display: block; width: 100%; height: 480px; border: 0; }
@media (max-width: 600px) { .page-hero__widget iframe { height: 420px; } }

/* MAC-address article body: OS subheads with Apple icon + cyan numbered steps. */
.article__body .mac-os-head {
  display: flex; align-items: center; gap: 12px;
  color: #023770; font-size: clamp(20px, 2.4vw, 28px); margin: 34px 0 14px;
}
.article__body .mac-os-head__apple { flex: 0 0 auto; fill: #0b2a4a; }
/* Platform glyphs beside each subhead. The icon component emits 48px, so size is set here rather
   than adding a variant. Only width/height/flex — NOT fill: the brand marks are filled with
   currentColor while the line icons are stroked with it and rely on fill:none, so forcing a fill
   would turn those into solid blobs. currentColor comes from .mac-os-head's own color. */
.article__body .mac-os-head > svg { flex: 0 0 auto; width: 22px; height: 22px; }
.article__body ol.mac-steps {
  list-style: none; counter-reset: step; padding: 0; margin: 0 0 22px;
}
.article__body ol.mac-steps > li {
  counter-increment: step; position: relative; padding-left: 40px;
  margin-bottom: 12px; color: var(--ink); line-height: 1.5;
}
.article__body ol.mac-steps > li::before {
  content: counter(step) " |"; position: absolute; left: 0; top: 0;
  color: var(--cyan-ink); font-weight: 700; font-size: 1.02em; letter-spacing: 1px;
}
/* ---- How To Connect (mockups-media/howtoconnect.png) --------------------------------------
   Centred cyan intro, a row of gradient tab pills, then .setup-card step blocks (reused, not
   re-invented — the existing card already puts steps left / device photo right, and ol.mac-steps
   already renders the mockup's cyan "1 |" numerals).
   The first pill is a real <details>/<summary> so the mockup's open dropdown works with no JS
   and stays keyboard- and screen-reader-operable for free. ---- */
.article__body .connect-intro { text-align: center; margin: 6px 0 30px; }
.article__body .connect-intro__title {
  color: var(--cyan-display);            /* large display cyan: 3.37:1 on white, AA for 24px+ */
  font-size: clamp(30px, 4vw, 45px); font-weight: 700; line-height: 1.15; margin: 0 0 12px;
}
.article__body .connect-intro__lead {
  color: var(--navy-900); font-size: 17px; max-width: 720px; margin: 0 auto;
}

.article__body .connect-tabs {
  display: flex; flex-wrap: wrap; gap: 14px;
  align-items: flex-start;               /* an open dropdown must not stretch its neighbours */
  margin: 0 0 34px;
}
.article__body .connect-tab__pill {
  display: block; padding: 13px 22px; border-radius: 8px;
  background: linear-gradient(90deg, #6fe0fb 0%, #2f9de8 55%, #0b4fa8 100%);
  color: var(--white); font-weight: 700; font-size: 14px; text-align: center;
  text-decoration: none; cursor: pointer; border: 0;
}
.article__body .connect-tab__pill:hover { filter: brightness(1.06); }
.article__body .connect-tab--menu { position: relative; }
/* Kill the native disclosure triangle, then draw the mockup's chevron ourselves. */
.article__body .connect-tab--menu > summary { list-style: none; padding-right: 44px; }
.article__body .connect-tab--menu > summary::-webkit-details-marker { display: none; }
.article__body .connect-tab--menu > summary::after {
  content: ""; position: absolute; right: 20px; top: 50%;
  width: 9px; height: 9px; margin-top: -7px;
  border-right: 2.5px solid var(--white); border-bottom: 2.5px solid var(--white);
  transform: rotate(45deg); transition: transform .18s ease;
}
.article__body .connect-tab--menu[open] > summary::after { transform: rotate(-135deg); margin-top: -3px; }
.article__body .connect-tab__menu {
  list-style: none; margin: 0; padding: 0;
  background: #d7ecf8; border-radius: 0 0 8px 8px; overflow: hidden;
}
.article__body .connect-tab__menu li + li { border-top: 1px solid #c3dcec; }
.article__body .connect-tab__menu a {
  display: block; padding: 11px 18px; color: var(--navy-900);
  text-decoration: none; font-size: 14px;
}
.article__body .connect-tab__menu a:hover { background: #c8e3f4; }

.article__body .connect-section-head {
  text-align: center; color: var(--navy-900);
  font-size: clamp(18px, 2vw, 22px); font-weight: 700; margin: 40px 0 26px;
}
/* Divider between step blocks, as in the mockup. */
.article__body .setup-card + .connect-section-head { padding-top: 34px; border-top: 1px solid #dbe6ef; }
.article__body .setup-card + .setup-card { padding-top: 26px; border-top: 1px solid #dbe6ef; }
/* The mockup highlights the Nokia Wi-Fi Gateway block on a light-blue panel. */
.article__body .setup-card--accent {
  background: #d5ecfa; border-radius: 18px; padding: 30px; border-top: 0;
}
.article__body .setup-card--accent + .connect-section-head { border-top: 0; }
.article__body .connect-note { color: var(--muted); font-size: 14px; margin: 14px 0 0; }
/* Sub-heading inside a step card (the Cross Connect panel splits its steps under two of them). */
.article__body .setup-card__subhead {
  color: var(--navy-900); font-size: 15px; font-weight: 800; margin: 20px 0 8px;
}
/* The "Connect device directly" / "Connect your Wi-Fi Router" lead line inside a step card.
   Pinned rather than left to the UA's default h4, which is what it was riding on. Values match
   what that default resolved to, so the cards already signed off on do not shift.
   :not() keeps it clear of .setup-card__subhead, which is also an h4 and has its own size. */
.article__body .setup-card__text > h4:not(.setup-card__subhead) {
  color: var(--ink); font-size: 16px; font-weight: 700; line-height: 1.3; margin: 0;
}
/* ...and the second list has to keep counting from where the first stopped, because the copy
   cross-references itself: "follow steps 1 and 2 listed above", "repeat steps 3-6". A plain
   second <ol class="mac-steps"> would restart at 1 (counter-reset: step) and break both. */
.article__body ol.mac-steps--from-3 { counter-reset: step 2; }
/* Part-2 additions (mockups-media/how-to-connect-2.png). */
.article__body .connect-lead {
  text-align: center; color: var(--navy-900); font-size: 15px;
  max-width: 900px; margin: -8px auto 26px;
}
.article__body .connect-intro--mid { margin: 46px 0 26px; }
/* Nested detail under a numbered step: the mockup puts a bold label on the step line, then
   indented bullets/prose beneath it. mac-steps li is padded left for its "1 |" marker, so the
   nested list only needs its own indent, not a second one. */
/* Opt-in via class, NOT position. Unscoped, this rule turned EVERY <strong> in a step into a
   block, so "Open <strong>Settings</strong> > <strong>System</strong>" exploded onto one line per
   label. :first-child does not fix it either — it ignores text nodes, so the <strong> in
   "Open <strong>Settings</strong>" still counts as the first ELEMENT child. Only a heading-style
   lead-in label wants block, and it now says so explicitly. */
.article__body .mac-steps > li > strong.step-label { display: block; color: var(--navy-900); margin-bottom: 6px; }
.article__body .mac-steps > li > p { margin: 0 0 8px; }
.article__body .mac-steps > li > ul { margin: 0 0 6px; padding-left: 18px; list-style: disc; }
.article__body .mac-steps > li > ul > li { margin-bottom: 6px; }
/* Full-width product screenshot (the WiFi dashboard). */
.article__body .connect-showcase { margin: 0 0 34px; }
.article__body .connect-showcase img { display: block; width: 100%; height: auto; }
@media (max-width: 700px) {
  .article__body .connect-tabs { gap: 10px; }
  .article__body .connect-tab__pill { width: 100%; }
  .article__body .connect-tab--menu { width: 100%; }
}

/* ---- DIRECTV channel lineup documents ------------------------------------------------------
   The lineups are flat artwork from DIRECTV (no PDF exists upstream), so each page is a figure
   whose image links to itself at full size — a dense channel grid is unreadable at column width
   on a phone, and the link is the zoom affordance. auto-fit keeps two-up on desktop and one-up
   on narrow screens without a breakpoint. ---- */
.article__body .lineup-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 22px; margin: 0 0 30px;
}
.article__body .lineup-page { margin: 0; }
.article__body .lineup-page--wide { grid-column: 1 / -1; }   /* Stream pages are landscape */
.article__body .lineup-page a {
  display: block; border: 1px solid var(--line); border-radius: 12px; overflow: hidden;
  background: #fff; transition: border-color .15s ease, box-shadow .15s ease;
}
.article__body .lineup-page a:hover,
.article__body .lineup-page a:focus-visible {
  border-color: var(--blue-600); box-shadow: 0 6px 20px rgba(7, 29, 57, .12);
}
.article__body .lineup-page img { display: block; width: 100%; height: auto; }
.article__body .lineup-page figcaption {
  margin-top: 8px; font-size: 13px; color: var(--muted); text-align: center;
}
/* Service picker at the top of the hub. */
.article__body .lineup-choice {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 20px; margin: 6px 0 34px;
}
.article__body .lineup-choice__card {
  display: flex; flex-direction: column; align-items: center; gap: 12px;
  padding: 24px 20px; border: 1px solid var(--line); border-radius: 14px;
  background: #fff; text-decoration: none; color: var(--navy-900); font-weight: 600;
  transition: border-color .15s ease, transform .15s ease;
}
.article__body .lineup-choice__card:hover { border-color: var(--blue-600); transform: translateY(-2px); }
.article__body .lineup-choice__card img { width: 150px; height: auto; }

/* Screenshot figure (placeholder until the real OS captures are supplied). */
/* Settings-path visual. Deliberately NOT a mock screenshot: it renders the menu path as chips so
   it aids scanning without implying "this is what your screen looks like", which a fabricated UI
   image would. Also survives OS redesigns, unlike a screenshot.

   The chevrons are drawn with CSS borders rather than a "›" character, so no separator text leaks
   into the accessibility tree — the list is read as the four steps it is. */
.article__body .path-viz { margin: 0 0 30px; }
.article__body .path-viz__steps {
  list-style: none; counter-reset: none; margin: 0; padding: 18px 20px;
  display: flex; flex-wrap: wrap; align-items: center; gap: 10px 18px;
  background: #eef7fd; border: 1px solid #cfe6f7; border-radius: 14px;
}
.article__body .path-viz__step {
  position: relative; margin: 0;
  background: #fff; border: 1px solid #cfe6f7; border-radius: 9px;
  padding: 9px 14px; font-size: 15px; font-weight: 700; color: var(--navy-900);
  white-space: nowrap;
}
/* Chevron between chips, drawn from borders. */
.article__body .path-viz__step + .path-viz__step::before {
  content: ""; position: absolute; left: -13px; top: 50%;
  width: 7px; height: 7px; margin-top: -4px;
  border-top: 2px solid var(--cyan-display); border-right: 2px solid var(--cyan-display);
  transform: rotate(45deg);
}
/* The chip that actually holds the value. --cyan-ink, not --cyan-display: white on the display
   cyan is only 3.4:1, and 15px bold does not qualify as large text, so it fails AA. The ink
   variant is 5.6:1. */
.article__body .path-viz__step--target {
  background: var(--cyan-ink); border-color: var(--cyan-ink); color: #fff;
}
.article__body .path-viz figcaption { margin-top: 10px; color: var(--muted); font-size: 14px; }
@media (max-width: 560px) {
  /* Stacked, so the chevron moves from between chips to above them. */
  .article__body .path-viz__steps { flex-direction: column; align-items: flex-start; gap: 16px; }
  .article__body .path-viz__step { white-space: normal; }
  .article__body .path-viz__step + .path-viz__step::before {
    left: 14px; top: -12px; margin-top: 0; transform: rotate(135deg);
  }
}

.article__body .mac-shot { margin: 0 0 30px; }
.article__body .mac-shot__ph {
  display: grid; place-items: center; min-height: 300px; padding: 20px;
  background: #eef3f8; border: 1px dashed #b9c8d8; border-radius: 12px;
  color: var(--muted); font-weight: 600; text-align: center;
}
.article__body .mac-shot figcaption { margin-top: 10px; color: var(--muted); font-size: 14px; }
/* Real connection diagrams (e.g. DIRECTV receiver hookup) — same figure/caption rhythm as .mac-shot,
   just an actual photo instead of the placeholder box. */
.article__body .mac-shot img { display: block; width: 100%; max-width: 640px; height: auto; }
/* Receiver setup cards (how-to-set-up) — instructions + diagram side by side per mockup.
   Only the TEXT block gets the white card treatment; the diagram floats plain on the page. */
.article__body .setup-card {
  display: flex; gap: 32px; align-items: center; flex-wrap: wrap; margin: 0 0 26px;
}
.article__body .setup-card__text {
  flex: 1 1 320px; min-width: 260px;
  background: #fcfcfc; border: 1px solid #eef0f2; border-radius: 16px; padding: 28px 32px;
}
.article__body .setup-card__media { flex: 1 1 320px; min-width: 260px; }
.article__body .setup-card__media img { display: block; width: 100%; height: auto; }
/* Delivered art that is small at source — the My Account SSID shot is 190px wide — must NOT be
   stretched to the 320px media column: upscaling it blurs the label text, which is the whole
   point of that screenshot. This sizes to the file's natural width and only ever shrinks. */
.article__body .setup-card__media--sm { flex: 0 1 auto; min-width: 0; }
.article__body .setup-card__media--sm img { width: auto; max-width: 100%; }
.article__body .setup-card__title { color: #173c58; font-size: 19px; margin: 0 0 6px; }
.article__body .setup-card__note { font-weight: 800;display: block; color: var(--cyan-ink); font-size: 13px; margin-bottom: 14px; }
.article__body .setup-card ol.mac-steps { margin-bottom: 0; }
.article { background: #fff; border: 1px solid var(--line); border-radius: var(--radius); padding: 36px 40px; }
/* Single-column article (no sidebar, no card) — matches the support-article mockup. */
.article--single { max-width: 940px; margin-inline: auto; background: none; border: 0; border-radius: 0; padding: 0; }
.article__header { border-bottom: 1px solid var(--line); padding-bottom: 18px; margin-bottom: 24px; }
.article__eyebrow { color: var(--blue-600); font-weight: 700; font-size: 13px; text-transform: uppercase; letter-spacing: .5px; }
.article__title { color: var(--navy-900); font-size: clamp(26px, 3.4vw, 36px); margin: 6px 0 8px; }
.article__meta { color: var(--muted); font-size: 14px; }
.article__body { color: var(--ink); line-height: 1.7; }
.article__body h2 { color: var(--navy-900); font-size: 20px; margin: 26px 0 10px; }
/* Device-class section heading, for articles that genuinely nest h3s under h2s (the MAC-address
   page). Needed because the base sizes above are INVERTED — h2 is 20px while h3 is 26px — so a
   real h2 > h3 hierarchy reads backwards. Scoped to a class rather than raising the base h2,
   which would restyle all 25 support articles at once. */
.article__body h2.mac-section {
  font-size: clamp(26px, 3vw, 32px); color: #023770;
  margin: 44px 0 6px; padding-top: 22px; border-top: 1px solid var(--line);
}
.article__body h2.mac-section:first-of-type { border-top: 0; padding-top: 0; }
/* Subheaders throughout support content (article h3's, "Still need help?", etc.) — same
   dark blue everywhere: #023770. */
.article__body h3 { color: #023770; font-size: 26px; margin: 26px 0 10px; }
/* Account-management "how to ___" articles (Renew/Transfer/Cancel service) — italic cyan note
   above a big left-aligned navy title, per mockup. */
.article__body .article__note { display: block; text-align: center; font-style: italic; color: var(--cyan-ink); margin: 0 0 28px; font-size: 15px; }
.article__body .article__giant-title { color: #023770; font-size: clamp(32px, 4vw, 44px); font-weight: 800; margin: 0 0 18px; }
.article__body .hl { color: var(--cyan-display); }
/* "Was this helpful?" sits beside the body instead of below it on these same articles. */
.article--side-helpful { display: grid; grid-template-columns: 1fr 320px; gap: 10px 40px; align-items: start; }
.article--side-helpful .article__body { grid-column: 1; grid-row: 1; }
.article--side-helpful .article__helpful { grid-column: 2; grid-row: 1; margin-top: 0; }
.article--side-helpful .article__related { grid-column: 1 / -1; grid-row: 2; }
@media (max-width: 820px) {
  .article--side-helpful { grid-template-columns: 1fr; }
  .article--side-helpful .article__helpful { grid-column: 1; grid-row: 2; }
  .article--side-helpful .article__related { grid-row: 3; }
}
.article__body p { margin-bottom: 14px; }
.article__body ul, .article__body ol { margin: 0 0 14px 22px; }
.article__body ul { list-style: disc; }
.article__body ul li::marker { color: #1fb7ff; }
.article__body ol { list-style: decimal; }
.article__body li { margin-bottom: 6px; }
/* Section headings that double as quick-jump-tab targets — the canonical support-page
   gradient (--grad-support-heading), same one used on Help Center and reused wherever a
   support page needs a gradient heading. */
.article__body h2.article__section-title {
  text-align: center; font-size: 34px; margin-top: 34px;
  background: var(--grad-support-heading);
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent; color: transparent;
}

/* Quick-jump pills linking to an article's h2 sections (only on articles with multiple named sections). */
.article__jump-tabs { display: flex; justify-content: center; gap: 12px; flex-wrap: wrap; padding: 30px 24px 0; }
.article__jump-tab {
  padding: 12px 22px; border-radius: 8px; font-weight: 700; font-size: 15px; color: var(--white);
  background: linear-gradient(90deg, #81edff 0%, #0055ba 100%);
  transition: filter .15s ease;
}
.article__jump-tab:hover { filter: brightness(1.08); }

.article__helpful {
  margin-top: 30px; padding: 22px 24px; border-radius: var(--radius);
  background: #cbebff; color: var(--navy-900);
}
.article__helpful-title { display: block; font-weight: 700; font-size: 17px; margin-bottom: 16px; }
.article__helpful-actions { display: flex; gap: 12px; }
.article__helpful-btn {
  display: inline-flex; align-items: center; gap: 8px; padding: 10px 20px; border-radius: 8px;
  background: #3d6c9a; color: var(--white); font-weight: 700; font-size: 15px; border: 0;
}
.article__helpful-btn:hover { background: #345d85; }
.article__helpful-btn:disabled { opacity: .6; cursor: default; }
.article__helpful-thanks { display: block; margin-top: 12px; font-weight: 600; }
/* White-card variant (Renew/Transfer/Cancel service mockups) — plain white instead of the light-blue
   fill used elsewhere (e.g. roommate-access), sitting beside the body instead of below it. */
.article__helpful--card {
  background: #fff; border: 1px solid #eef0f2; box-shadow: 0 8px 24px rgba(4,20,44,.08);
}
.article__related { margin-top: 30px; }
.article__related h2 { font-size: 18px; color: var(--navy-900); margin-bottom: 10px; }
.article__related ul { display: grid; gap: 8px; }
.article__related a { color: var(--blue-600); font-weight: 600; }
.article__related a:hover { color: var(--cyan-400); }

/* ============================================================
   Utility templates — Thank-you, Sitemap, Careers, Search, Status
   ============================================================ */
/* Thank-you / confirmation. Extra top padding: unlike every other interior page, this one has
   no .page-hero to clear .site-header (position:absolute, floats over content) — without it the
   nav overlaps the checkmark/title. */
.confirm { text-align: center; padding-top: 140px; }
.confirm__icon { display: inline-grid; place-items: center; width: 62px; height: 62px; border-radius: 50%; background: var(--cyan-400); color: var(--navy-900); font-size: 38px; font-weight: 700; margin-bottom: 20px; box-shadow: 0 0 26px rgba(90,200,255,.5); }
.confirm__title { font-size: clamp(30px, 4vw, 44px); color: var(--navy-900); }
.confirm__lead { max-width: 560px; margin: 12px auto 30px; color: var(--muted); }
.confirm__steps { display: flex; gap: 18px; justify-content: center; flex-wrap: wrap; margin-bottom: 30px; }
.confirm__step { display: flex; align-items: center; gap: 10px; color: var(--ink); font-weight: 600; }
.confirm__num { display: grid; place-items: center; width: 28px; height: 28px; border-radius: 50%; background: #eaf6ff; color: var(--blue-700); font-size: 14px; }
.confirm__actions { display: flex; gap: 14px; justify-content: center; flex-wrap: wrap; }

/* HTML sitemap */
.sitemap-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 32px; }
.sitemap-col__heading { font-size: 14px; text-transform: uppercase; letter-spacing: .5px; color: var(--blue-600); margin-bottom: 12px; }
.sitemap-col ul { display: grid; gap: 8px; }
.sitemap-col a { color: var(--ink); }
.sitemap-col a:hover { color: var(--cyan-400); }
@media (max-width: 768px) { .sitemap-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 480px) { .sitemap-grid { grid-template-columns: 1fr; } }

/* Careers — Black Hole Tour. One continuous wide image (careers-tour-strip)
   pinned behind the page as a sticky "porthole" while 5 content stops scroll
   past over it; JS (data-tour) pans the image horizontally in sync with
   scroll progress through .tour, so it reads as a ship flying sideways past
   the black hole rather than separate unrelated banners. See main.js. */
.tour { position: relative; background: #000; }
/* Position is fully JS-managed (see main.js): absolute at rest, fixed while
   .tour is mid-scroll (pinned "porthole" effect), then absolute again once
   .tour has fully scrolled past (frozen at its final spot instead of staying
   fixed over whatever comes after it). */
.tour__bg { position: absolute; top: 0; left: 0; width: 100%; height: 100vh; overflow: hidden; z-index: 0; perspective: 1400px; }
.tour__bg-img {
  /* Position is fully JS-computed (translate in px + scale) — see transformFor() in main.js —
     since the hero needs the full ring centered (a computed scale/offset based on its actual
     bounding box) while later stops zoom into the logo, and blending the two needs real pixel
     math rather than CSS percentage shortcuts. */
  position: absolute; top: 0; left: 0; height: auto; width: auto; max-width: none;
  will-change: transform;
}
.tour__stops { position: relative; z-index: 1; }
.tour__stop {
  min-height: 100vh; display: flex; align-items: center; justify-content: center;
  color: #fff; text-align: center;
}
/* Frosted panel behind the text — the image varies from pure black to bright
   white/blue as it pans, so text needs guaranteed contrast rather than relying
   on where it happens to land. */
.tour__content {
  max-width: 640px; margin-inline: auto; padding: 36px 40px;
  background: rgba(4,10,20,.5); backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
  border-radius: 20px;
}
.tour__icon {
  display: grid; place-items: center; width: 92px; height: 92px; margin: 0 auto 22px;
  border-radius: 50%; border: 1.5px solid rgba(120,215,255,.8);
  box-shadow: 0 0 26px rgba(90,205,235,.5), 0 0 12px rgba(130,240,205,.38);
  background: radial-gradient(circle at 50% 45%, rgba(255,255,255,.14), rgba(255,255,255,.02));
}
.tour__icon svg { width: 46px; height: 46px; filter: drop-shadow(0 0 5px rgba(90,205,255,.5)); color: #fff; }
.tour__title { font-size: clamp(28px, 4vw, 44px); font-weight: 800; margin-bottom: 14px; text-shadow: 0 2px 16px rgba(0,0,0,.6); }
.tour__body { font-size: 18px; opacity: .92; line-height: 1.6; text-shadow: 0 2px 12px rgba(0,0,0,.6); }
.tour__quote { font-size: clamp(26px, 3.6vw, 40px); font-weight: 700; line-height: 1.3; text-shadow: 0 2px 16px rgba(0,0,0,.6); }
@media (prefers-reduced-motion: reduce) { .tour__bg-img { transform: translate(0, -50%) !important; } }

/* Nebula blobs — soft blurred glows behind the black hole image, same CSS-only
   decoration approach as .stars/.star elsewhere (no image assets). Parallax
   offset (data-tour-parallax, see main.js) is applied to the outer .tour__nebula
   so it composes independently with the inner __glow's own ambient drift
   animation, rather than both fighting over the same transform. */
.tour__nebulae { position: absolute; inset: 0; overflow: hidden; }
.tour__nebula { position: absolute; will-change: transform; }
.tour__nebula__glow { display: block; width: 100%; height: 100%; border-radius: 50%; filter: blur(80px); mix-blend-mode: screen; animation: nebula-drift 42s ease-in-out infinite; }
.tour__nebula--a { width: 900px; height: 900px; top: -220px; left: 8%; }
.tour__nebula--a .tour__nebula__glow { background: radial-gradient(circle, rgba(63,198,255,.5), transparent 70%); animation-duration: 46s; }
.tour__nebula--b { width: 1100px; height: 1100px; bottom: -320px; right: 4%; }
.tour__nebula--b .tour__nebula__glow { background: radial-gradient(circle, rgba(30,111,208,.45), transparent 70%); animation-duration: 38s; animation-delay: -12s; }
.tour__nebula--c { width: 700px; height: 700px; top: 32%; left: 42%; }
.tour__nebula--c .tour__nebula__glow { background: radial-gradient(circle, rgba(111,184,230,.4), transparent 70%); animation-duration: 52s; animation-delay: -24s; }
@keyframes nebula-drift {
  0%, 100% { transform: translate(0, 0) scale(1); opacity: .5; }
  50%      { transform: translate(24px, -16px) scale(1.06); opacity: .68; }
}
@media (prefers-reduced-motion: reduce) { .tour__nebula__glow { animation: none; opacity: .55; } }

/* Ring halo — soft white/blue glow that hugs close around the ring itself (unlike the farther-
   out .tour__nebula blobs above). Positioned in the image's own natural coordinate space
   (centered on the ring at 1150,1925 — see RING_CX/RING_CY in main.js) and given the SAME
   translate/scale/tilt transform as the image itself via [data-tour-halo], so it stays locked
   to the ring through every pan/zoom/tilt instead of drifting independently. The rotation below
   lives on a separate inner element so it doesn't fight with that JS-applied transform — a
   single symmetric radial glow wouldn't show any motion, so 3 offset blobs orbit instead. */
.tour__ring-halo { position: absolute; left: -350px; top: 425px; width: 3000px; height: 3000px; will-change: transform; }
.tour__ring-halo__spin { position: absolute; inset: 0; animation: ring-halo-spin 60s linear infinite; }
.tour__ring-halo__blob { position: absolute; border-radius: 50%; filter: blur(110px); mix-blend-mode: screen; }
.tour__ring-halo__blob--a { width: 900px; height: 900px; top: 60px; left: 1050px; background: radial-gradient(circle, rgba(255,255,255,.32), transparent 70%); }
.tour__ring-halo__blob--b { width: 800px; height: 800px; top: 1850px; left: 260px; background: radial-gradient(circle, rgba(63,198,255,.38), transparent 70%); }
.tour__ring-halo__blob--c { width: 820px; height: 820px; top: 1850px; left: 1980px; background: radial-gradient(circle, rgba(111,184,230,.32), transparent 70%); }
@keyframes ring-halo-spin {
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
}
@media (prefers-reduced-motion: reduce) { .tour__ring-halo__spin { animation: none; } }

/* Careers — benefits ("We Offer ...") */
.benefits-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 24px; margin-top: 30px; }
@media (max-width: 900px) { .benefits-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 600px) { .benefits-grid { grid-template-columns: 1fr; } }

/* Careers — open roles */
.job-list { display: grid; gap: 14px; margin: 30px 0 0; }
.job { display: flex; align-items: center; justify-content: space-between; gap: 16px; background: #fff; border: 1px solid var(--line); border-radius: var(--radius); padding: 20px 24px; }
.job__title { display: block; font-weight: 700; color: var(--navy-900); }
.job__meta { display: block; font-size: 14px; color: var(--muted); margin-top: 4px; }

/* ── TEMPORARY: no vacancies open ─────────────────────────────────────────────
   Hides the "Open Positions" list and the "Apply" form on /careers. Nothing is
   deleted — careers.php still carries the roles array, the list markup and the
   whole form, so restoring is deleting this one block.

   display:none (not visibility/opacity) so the sections leave the accessibility
   tree and the tab order too: a hidden-but-focusable form would let a keyboard or
   screen-reader user fill in an application that nobody is reading.

   Open Positions is matched via :has() because that section has no id or class of
   its own — it is just .section.section--alt, which also matches sections on other
   pages. .job-list appears nowhere but /careers, so :has() scopes it precisely
   without touching the markup. (:has() has been baseline since 2023; if it ever
   needs to work without it, give that <section> an id instead.)

   TO RESTORE: delete this block. No other change required.
   ───────────────────────────────────────────────────────────────────────────── */
.section:has(> .container > .job-list),
.section:has(> .container > h2 + .job-list),
#careers-apply {
  display: none;
}

/* Search */
.search-status { color: var(--muted); margin-bottom: 20px; }
.search-status strong { color: var(--navy-900); }

/* Network status */
.status-banner { display: flex; align-items: center; gap: 12px; padding: 18px 22px; border-radius: var(--radius); font-weight: 700; margin: 8px 0 28px; }
.status-banner--ok { background: #e8f8ef; color: #1c7a45; }
.status-banner--warn { background: #fff5e0; color: #946100; }
/* Help & Network Status — support option cards */
.status-options { display: grid; grid-template-columns: repeat(3, 1fr); gap: 24px; margin-bottom: 20px; }
.status-option { background: #fff; border: 1px solid var(--line); border-radius: var(--radius); padding: 26px; text-align: center; box-shadow: 0 10px 26px rgba(16,42,92,.08); display: flex; flex-direction: column; align-items: center; }
.status-option__icon { display: grid; place-items: center; width: 60px; height: 60px; border-radius: 50%; background: #eaf6ff; color: var(--blue-600); box-shadow: 0 0 18px rgba(90,200,255,.4); margin-bottom: 14px; }
.status-option__icon svg { width: 30px; height: 30px; }
.status-option__title { color: var(--navy-900); font-size: 18px; margin-bottom: 8px; }
.status-option__body { color: var(--muted); font-size: 14px; margin-bottom: 8px; }
.status-option__meta { color: var(--blue-700); font-weight: 600; font-size: 13px; margin-bottom: 16px; }
.status-option .btn { margin-top: auto; }
.status-phone { text-align: center; color: var(--muted); font-size: 14px; }
.status-phone a { color: var(--blue-600); font-weight: 700; }
@media (max-width: 768px) { .status-options { grid-template-columns: 1fr; } }
.status-list { display: grid; gap: 10px; }
.status-list__row { display: flex; align-items: center; justify-content: space-between; padding: 14px 18px; background: #fff; border: 1px solid var(--line); border-radius: 10px; }
.status-list__label { color: var(--muted); font-size: 14px; }
.incident-list { display: grid; gap: 16px; margin-top: 16px; }
.incident { background: #fff; border: 1px solid var(--line); border-radius: var(--radius); padding: 20px 24px; }
.incident__date { font-size: 13px; color: var(--muted); }
.incident__title { color: var(--navy-900); font-size: 18px; margin: 4px 0 6px; }
.incident__body { color: var(--muted); font-size: 15px; }

/* ============================================================
   Network Status — from mockups-media/Network Status.png (top bar excluded).
   Two LIGHT panels over a deep-blue starfield. This replaced a dark-glass
   version of the same layout; the mockup's panels are #e3ebef with navy
   type, so every child had to flip from light-on-dark to dark-on-light.
   Colours below are sampled from the mockup, not eyeballed.
   ============================================================ */
.netstatus {
  position: relative; overflow: hidden;
  /* Mockup bg: deep teal-blue, lighter at top-centre where the glow sits. */
  background: radial-gradient(120% 75% at 50% -12%, #0b6f9c 0%, #015279 34%, #00405e 100%);
  color: var(--white);
  /* .site-header is position:absolute and floats transparently over the page, so a band starting
     at y=0 slides under the nav. .page-hero only cleared it via its 360px min-height; this layout
     has no such floor, so the offset is explicit. */
  padding: clamp(118px, 14vh, 164px) 0 76px;
}
.netstatus .stars { z-index: 1; }
.netstatus__inner { position: relative; z-index: 2; }

/* Mockup: 589px and 523px panels in a 1366 frame -> 1.126:1, equal heights. */
.netstatus__cols {
  display: grid; grid-template-columns: 1.126fr 1fr; gap: 20px; align-items: stretch;
}
.ns-panel {
  background: #e3ebef; border-radius: 20px; padding: 30px 28px 34px;
  color: var(--navy-900);
}
.ns-panel__title {
  text-transform: uppercase; letter-spacing: .01em;
  color: #003079; font-size: clamp(18px, 1.65vw, 22px); font-weight: 800;
  text-align: center; margin: 0 0 26px;
}
.ns-panel__title--left { text-align: left; }
.ns-subhead { color: #003079; font-size: 17px; font-weight: 800; margin: 26px 0 12px; }

/* ---- Support Options: 2x2 ringed icon tiles ---- */
.ns-opts {
  list-style: none; margin: 0; padding: 0;
  display: grid; grid-template-columns: 1fr 1fr; gap: 30px 16px;
}
.ns-opt {
  display: flex; flex-direction: column; align-items: center; gap: 16px;
  width: 100%; padding: 8px 4px;
  background: none; border: 0; cursor: pointer; font: inherit;
  color: #0e4f8a; text-align: center;
}
/* NO CSS ring: the delivered art already contains the cyan ring and its glow. Drawing another
   here double-ringed every tile. Only the lift on hover is ours. */
.ns-opt__glyph { display: block; line-height: 0; transition: transform .16s ease; }
.ns-opt__glyph img { display: block; width: 104px; height: 104px; }
.ns-opt__label {
  font-size: 17px; font-weight: 800; line-height: 1.25; color: #0b3c72;
}
.ns-opt:hover .ns-opt__glyph,
.ns-opt:focus-visible .ns-opt__glyph { transform: translateY(-2px) scale(1.04); }
.ns-opt:focus-visible { outline: 3px solid #0e63a8; outline-offset: 4px; border-radius: 12px; }

/* ---- Active Incidents card ---- */
.ns-incidents {
  background: #9bd8ff; border-radius: 16px; padding: 20px 22px 22px;
  box-shadow: 0 14px 26px rgba(3,40,70,.22);
}
.ns-incidents__head {
  display: flex; align-items: center; justify-content: space-between; gap: 14px;
  margin-bottom: 14px;
}
.ns-incidents__title {
  text-transform: uppercase; color: #052a63; font-size: 19px; font-weight: 800; margin: 0;
}
.ns-badge {
  flex: 0 0 auto; border-radius: 999px; padding: 7px 20px;
  font-size: 14px; font-weight: 800; text-transform: uppercase; letter-spacing: .02em;
  color: #fff; background: #1f9e17;   /* mockup green #42d935 is only 1.9:1 with white; this is 4.6:1 */
}
.ns-badge--warn { background: #a8551a; }

/* Incidents render INSIDE the card, so they are plain text rather than nested cards. */
.netstatus .incident-list {
  list-style: none; margin: 0; padding: 0 6px 0 0; display: grid; gap: 12px;
  /* Bound the feed so a long incident list doesn't bury the service board. overflow-y:auto keeps the
     scroll region only when the list overflows; the persistent styled scrollbar below then signals
     there is more (macOS overlay scrollbars auto-hide, which hid that cue). */
  max-height: 28rem; overflow-y: auto; overscroll-behavior: contain;
}
/* Force a persistent (non-overlay) scrollbar so it is obvious the incident list scrolls. Do NOT add
   scrollbar-width/scrollbar-color to the rule above: in Chromium a non-auto value for either one
   disables these pseudo-elements, which drops the bar back to the auto-hiding overlay scrollbar. */
.netstatus .incident-list::-webkit-scrollbar { width: 10px; }
.netstatus .incident-list::-webkit-scrollbar-track { background: rgba(16, 42, 92, .08); border-radius: 8px; }
.netstatus .incident-list::-webkit-scrollbar-thumb { background: rgba(16, 42, 92, .35); border-radius: 8px; }
/* Firefox has no ::-webkit-scrollbar, so it takes the standard properties instead — scoped here so the
   two mechanisms can never collide in Chromium. */
@supports not selector(::-webkit-scrollbar) {
  .netstatus .incident-list {
    scrollbar-width: thin; scrollbar-color: rgba(16, 42, 92, .45) rgba(16, 42, 92, .08);
  }
}
/* Same-page targets for the Network Status support tiles — modest gap on jump (header is not fixed). */
#request-callback, #submit-support-request { scroll-margin-top: 24px; }
.netstatus .incident {
  background: none; border: 0; border-radius: 0; padding: 0;
  color: #0a3260; font-size: 15.5px; line-height: 1.5;
}
.netstatus .incident__date { display: block; color: #14507f; font-size: 13px; margin-bottom: 2px; }
/* Hidden, not removed. main.js builds .incident__title from alert_category + alert_type
   ("Internet Maintenance"), which the message below then repeats verbatim -- the mockup shows the
   sentence once. Kept in the DOM so the heading is still there for assistive tech and so a future
   terser message format can simply un-hide it. */
.netstatus .incident__title { position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; }
.netstatus .incident__body { color: #0a3260; margin: 0; }

/* ---- Per-service board, on the light panel ---- */
.netstatus .status-list { display: grid; gap: 8px; }
.netstatus .status-list__row {
  background: #fff; border: 1px solid #cfe0ea; border-radius: 10px;
  color: var(--navy-900); padding: 12px 16px;
}
.netstatus .status-list__label { color: #4a6b83; }
.status-list__name { display: inline-flex; align-items: center; gap: 10px; }
.status-list__icon { display: inline-flex; flex: 0 0 auto; line-height: 0; color: #0e63a8; }
.status-list__icon svg { width: 24px; height: 24px; }
/* The dot ships margin-right for the old text-only layout; the flex gap replaces it. */
.status-list__name .status-dot { margin-right: 0; }

@media (max-width: 900px) {
  .netstatus__cols { grid-template-columns: 1fr; }
}
@media (max-width: 420px) {
  /* Two 104px rings plus gutters stop fitting; one column beats squeezing them. */
  .ns-opts { grid-template-columns: 1fr; }
}

/* ============================================================
   Mobile fixes — kept at the very end so they win over the
   earlier (later-defined) .help-cards / .tiles overrides.
   ============================================================ */
@media (max-width: 700px) { .help-cards { grid-template-columns: 1fr; } }
@media (max-width: 768px) {
  .tiles--4 { grid-template-columns: repeat(2, 1fr); gap: 16px; }
  .tiles--4 .tile { min-height: 160px; padding: 26px 14px; }
  .tiles--4 .tile__icon svg { width: 56px; height: 56px; }
}

/* ============================================================
   Find Your Fiberhood (T08) — full-viewport map + address lookup
   (Map tiles + geocoding come from the backend; this is the shell.)
   ============================================================ */
.fiberhood__map {
  position: relative; min-height: 100vh; min-height: 100dvh;
  display: flex; align-items: center; overflow: hidden;
  background-color: #dbe7f1;
  background-image:
    repeating-linear-gradient(0deg, rgba(110,140,175,.13) 0 1px, transparent 1px 66px),
    repeating-linear-gradient(90deg, rgba(110,140,175,.13) 0 1px, transparent 1px 66px),
    radial-gradient(120% 80% at 68% 32%, #e8f1f9, #cfe0ee 68%, #bcd3e6 100%);
}
/* A couple of faint 'streets' for map texture (visible only until the map loads). */
.fiberhood__map::before {
  content: ""; position: absolute; inset: 0; pointer-events: none; z-index: 0;
  background:
    linear-gradient(66deg, transparent 48%, rgba(255,255,255,.55) 48% 49.3%, transparent 49.3%),
    linear-gradient(-58deg, transparent 62%, rgba(255,255,255,.45) 62% 63%, transparent 63%);
}
/* Live Google Map fills the whole section, behind the lookup card. */
.fiberhood__gmap { position: absolute; inset: 0; z-index: 1; }
.fiberhood__mapnote {
  position: absolute; right: clamp(24px, 7vw, 120px); top: 50%; transform: translateY(-50%);
  z-index: 1; display: flex; flex-direction: column; align-items: center; gap: 16px;
  max-width: 300px; text-align: center; color: #5c7793; font-weight: 600;
}
.fiberhood__pin {
  width: 46px; height: 46px; position: relative;
  background: var(--brand-teal); border-radius: 50% 50% 50% 0; transform: rotate(-45deg);
  box-shadow: 0 12px 26px rgba(0,80,120,.35);
}
.fiberhood__pin::after {
  content: ""; position: absolute; top: 9px; left: 9px; width: 28px; height: 28px;
  border-radius: 50%; background: #fff url("../img/apple-touch-icon.png") center / 20px no-repeat;
  transform: rotate(45deg); /* counter-rotate: parent pin is rotated -45deg, keep the mark upright */
}
.fiberhood__lookup {
  position: relative; z-index: 2;
  margin: 120px 0 0 clamp(20px, 6vw, 96px);
  width: min(440px, calc(100% - 40px));
  background: rgba(255,255,255,.97); border-radius: 18px; padding: 34px 34px 30px;
  box-shadow: 0 26px 64px rgba(8,29,57,.24);
}
.fiberhood__title { font-size: clamp(28px, 3.2vw, 38px); color: var(--navy-900); margin-bottom: 10px; }
.fiberhood__lead { color: var(--muted); margin-bottom: 22px; }
.fiberhood__form { display: flex; flex-direction: column; gap: 12px; }
.fiberhood__form input, .fiberhood__form select {
  width: 100%; padding: 14px 16px; font: inherit; line-height: 1.4;
  border: 1px solid #bcdcf0; border-radius: 10px; background: #eef8fd; color: var(--ink);
}
.fiberhood__form select {
  appearance: none; -webkit-appearance: none; -moz-appearance: none;
  padding-right: 40px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8' fill='none'%3E%3Cpath d='M1 1.5L6 6.5L11 1.5' stroke='%235b6b85' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 16px center;
}
.fiberhood__form input:focus, .fiberhood__form select:focus { outline: none; border-color: var(--blue-600); box-shadow: 0 0 0 3px rgba(30,111,208,.15); }
.fiberhood__or { text-align: center; color: var(--muted); font-size: 13px; font-weight: 600; text-transform: uppercase; letter-spacing: .5px; margin: 2px 0; }
.fiberhood__form .btn { width: 100%; }
.fiberhood__hint { margin-top: 14px; font-size: 13px; color: var(--muted); }
@media (max-width: 700px) {
  .fiberhood__mapnote { display: none; }
  .fiberhood__lookup { margin: 108px auto 0; }
}
/* NEW functional elements added by the Location-Discovery client — a baseline the UX designer refines.
   (Additive; does not override the styled form/map/card rules above.) */
.fiberhood__results {
  list-style: none; margin: 0; padding: 0; max-height: 320px; overflow-y: auto;
  border: 1px solid #bcdcf0; border-radius: 10px; background: #fff;
}
.fiberhood__result {
  display: flex; flex-direction: column; gap: 2px; padding: 10px 14px; cursor: pointer;
  border-bottom: 1px solid #eef4f9;
}
.fiberhood__result:last-child { border-bottom: 0; }
.fiberhood__result:hover, .fiberhood__result.is-active { background: #eef8fd; }
.fiberhood__result-title { font-weight: 600; color: var(--navy-900); }
.fiberhood__result-addr { font-size: 13px; color: var(--muted); }
.fiberhood__result-status { font-size: 12px; font-weight: 600; color: var(--brand-teal); }
.fiberhood__result.is-loading, .fiberhood__result.is-error, .fiberhood__result.is-empty {
  padding: 12px 14px; color: var(--muted); cursor: default;
}
/* Always-available escape to the lead flow; sits at the end of the results list. */
.fiberhood__result.is-hatch {
  padding: 12px 14px; color: var(--muted); cursor: default;
  border-top: 1px solid #dbe7f1; background: #f7fbfe;
}
.fiberhood__result.is-hatch a { color: var(--blue-600); font-weight: 600; }
/* Page-owned marker/result flyout, positioned bottom-RIGHT: the search panel permanently owns the left side,
   so the bottom-right corner is the least-intrusive spot (it doesn't collide with the panel). */
.fiberhood__flyout {
  position: absolute; z-index: 3; right: clamp(20px, 6vw, 96px); bottom: 26px;
  width: min(360px, calc(100% - 40px));
  background: #fff; border-radius: 14px; padding: 18px 20px;
  box-shadow: 0 20px 50px rgba(8,29,57,.24);
}
.fiberhood__flyout-close {
  position: absolute; top: 8px; right: 12px; border: 0; background: none; font-size: 22px;
  line-height: 1; color: var(--muted); cursor: pointer;
}
.fiberhood__flyout-title { font-size: 18px; color: var(--navy-900); margin: 0 0 6px; }
.fiberhood__flyout-address { font-size: 13px; color: var(--muted); margin: 0 0 8px; }
.fiberhood__flyout-status { font-size: 14px; font-weight: 600; color: var(--brand-teal); margin: 0 0 12px; }
.fiberhood__flyout-action { display: inline-block; }

/* Request Service - universal lead form (functional BASELINE; design lead refines). A bright, standard page in
   the site's design language (NOT the dark .auth hero); rides the shared .container + .row/.col-* grid. */
.request-service { padding: 120px 0 80px; }
.request-service__head { text-align: center; margin-bottom: 26px; }
.request-service__title { color: var(--navy-900); font-size: clamp(30px, 4vw, 46px); font-weight: 800; }
.request-service__sub { color: var(--muted); margin-top: 10px; }
/* The form as a bright card (subtle shadow), centered — replaces the old .auth-card glass panel. */
.lead-form { max-width: 820px; margin: 0 auto; background: #fff; border: 1px solid #e2e8f0;
  border-radius: 18px; padding: 32px; box-shadow: 0 12px 40px rgba(8,29,57,.08); }
/* Pick-form modal: EXTENDS the shared .modal component (overlay/panel/title/lead) with legacy's horizontal
   image-bubble choices + support link. The .modal shell (fixed overlay, show/hide via [hidden]) is shared. */
.lead-modal__panel { max-width: 640px; }
.lead-modal__panel .modal__lead { max-width: none; }
.lead-modal__prompt { font-weight: 700; color: var(--navy-900); margin: 6px 0 14px; }
.lead-modal__choices { display: flex; flex-wrap: wrap; justify-content: center; gap: 16px 20px; margin-bottom: 22px; }
.lead-modal__choice {
  display: flex; flex-direction: column; align-items: center; gap: 8px; width: 96px;
  padding: 6px; border: 0; background: none; font: inherit; font-weight: 700; color: var(--navy-900);
  cursor: pointer; text-align: center;
}
.lead-modal__choice-img {
  width: 84px; height: 84px; border-radius: 50%; object-fit: cover;
  box-shadow: 0 6px 18px rgba(8,29,57,.18); transition: transform .15s ease, box-shadow .15s ease;
}
.lead-modal__choice:hover .lead-modal__choice-img { transform: translateY(-3px) scale(1.04); box-shadow: 0 10px 26px rgba(8,29,57,.28); }
.lead-modal__choice-label { font-size: 12px; letter-spacing: .3px; line-height: 1.2; }
.lead-modal__support { display: flex; align-items: center; justify-content: center; gap: 12px; margin: 0; color: var(--muted); font-size: 14px; }
.lead-modal__support-icon { display: inline-flex; width: 42px; height: 42px; color: var(--blue-600); }
.lead-modal__support-icon svg, .lead-modal__support-icon img { width: 100%; height: 100%; }
.lead-modal__support a { color: var(--blue-600); font-weight: 600; }
/* Lead form + arrival banner. */
.lead-form.auth-card { margin: 0 auto; }
/* Collected required-field errors render one per line (the submit handler joins them with newlines). */
.lead-form [data-form-status] { white-space: pre-line; text-align: left; }
.lead-form__banner {
  display: flex; align-items: center; gap: 10px; margin-bottom: 18px; padding: 12px 14px;
  background: #eef8fd; border: 1px solid #bcdcf0; border-radius: 10px;
}
.lead-form__banner[hidden] { display: none; }
.lead-form__banner-label { font-size: 12px; font-weight: 600; text-transform: uppercase; color: var(--muted); letter-spacing: .5px; }
.lead-form__banner-name { font-weight: 600; color: var(--navy-900); }
.lead-form__change { margin-left: auto; font: inherit; color: var(--blue-600); background: none; border: 0; cursor: pointer; text-decoration: underline; }
/* Per-type field groups: the router shows/enables only the active one. Reset default fieldset chrome. */
.lead-fields { border: 0; padding: 0; margin: 0; min-width: 0; }
/* Success confirmation. */
.lead-success { max-width: 560px; margin: 40px auto; text-align: center; }
.lead-success__title { font-size: 24px; color: var(--navy-900); margin-bottom: 10px; }
.lead-success__ref { font-weight: 600; color: var(--brand-teal); margin-bottom: 8px; }
/* Fields ride the shared .row / .col-* grid; only reset field spacing + lay out the option groups. */
.lead-form .row { margin-bottom: var(--gutter); }
.lead-form .field { margin: 0; }
fieldset.field { border: 0; padding: 0; margin: 0; min-width: 0; }
.lead-radios { display: flex; flex-wrap: wrap; gap: 8px 24px; margin-top: 6px; }
.lead-checks { display: grid; grid-template-columns: 1fr 1fr; gap: 8px 16px; margin-top: 6px; }
.lead-radios label, .lead-checks label { display: flex; align-items: flex-start; gap: 8px; font-weight: 500; line-height: 1.3; }
/* The shared .field input rule forces width:100%; a checkbox/radio must stay intrinsic size and sit beside its label. */
.lead-radios input, .lead-checks input { width: auto; flex: none; margin: 2px 0 0; }
@media (max-width: 640px) { .lead-checks { grid-template-columns: 1fr; } }

/* Get Started - single-column, location-first onboarding (rebuild v2; provisional, design lead refines).
   IA mirrors the design lead's Welcome signup.php (location-first, centered) in the new-site design system. */
.get-started { align-items: flex-start; background: url("../img/login-bg.webp") left / cover no-repeat; }
.get-started__container {
  position: relative; z-index: 2;
  width: min(860px, 100%); margin: 0 auto; padding-top: 120px; padding-bottom: 80px;
}
.get-started__head { text-align: center; margin-bottom: 26px; }
.get-started__title {
  color: #fff; font-size: clamp(32px, 4vw, 52px); font-weight: 800;
  text-shadow: 0 2px 16px rgba(4,20,44,.45);
}
.get-started__sub { color: rgba(255,255,255,.85); margin-top: 10px; }
.get-started .auth-card { max-width: 100%; }

/* Create-account form: two fields per row instead of one long stacked column. */
.get-started-form {
  display: grid;
  grid-template-columns: 1fr 1fr;
  column-gap: 20px;
}
.get-started-form [data-form-status],
.get-started-form .get-started__community,
.get-started-form .get-started__prefs,
.get-started-form .get-started__hint,
.get-started-form > .btn,
.get-started-form .auth-card__links {
  grid-column: 1 / -1;
}
@media (max-width: 640px) {
  .get-started-form { grid-template-columns: 1fr; }
}

/* Dark-surface parity for selects/checkboxes the base only styles for light surfaces. */
.field--dark select, .field--dark textarea {
  background: rgba(255,255,255,.92); color: var(--navy-900, #0b2440); border-color: transparent;
}
.field--dark select:focus, .field--dark textarea:focus {
  border-color: var(--cyan-400); box-shadow: 0 0 0 3px rgba(63,198,255,.35);
}

/* Step 1 - location: tabs + search + results dropdown. */
.get-started__tabs { display: flex; gap: 10px; justify-content: center; margin-bottom: 18px; }
.get-started__tab {
  display: inline-flex; align-items: center; gap: 8px; padding: 12px 22px; border-radius: 12px;
  border: 1px solid rgba(255,255,255,.28); background: rgba(255,255,255,.08); color: #fff;
  font: inherit; font-weight: 600; cursor: pointer; text-decoration: none;
}
.get-started__tab.is-active { background: rgba(63,198,255,.22); border-color: rgba(63,198,255,.55); }
.get-started__search { position: relative; }
.get-started__results {
  list-style: none; margin: 6px 0 0; padding: 6px; max-height: 320px; overflow-y: auto;
  background: #fff; border-radius: 12px; box-shadow: 0 12px 40px rgba(4,20,44,.4);
}
.get-started__result {
  display: flex; align-items: center; gap: 12px; padding: 10px 14px; border-radius: 8px;
  cursor: pointer; color: var(--navy-900, #0b2440);
}
.get-started__result:hover, .get-started__result:focus { background: #eaf6ff; outline: none; }
.get-started__result-thumb {
  flex: 0 0 auto; width: 44px; height: 44px; border-radius: 50%; overflow: hidden;
  display: grid; place-items: center; background: #eaf6ff; color: var(--blue-600, #1e6fd0);
}
.get-started__result-thumb img { width: 100%; height: 100%; object-fit: cover; }
.get-started__result-thumb.is-pin { font-size: 20px; }
.get-started__result-body { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.get-started__result-body strong { font-weight: 700; }
.get-started__result-body span { font-size: 13px; color: rgba(10,36,64,.7); }
.get-started__result.is-empty { color: rgba(10,36,64,.7); cursor: default; }
/* Leads affordance (destination deferred): "Don't see your address? Request service now!" */
.get-started__result--request { cursor: default; padding: 0; }
.get-started__result--request a {
  display: flex; flex-direction: column; gap: 2px; width: 100%; padding: 12px 14px;
  border-top: 1px solid #e4eef7; text-decoration: none; color: var(--blue-600, #1e6fd0);
}
.get-started__result--request a:hover { background: #eaf6ff; }
.get-started__result--request strong { font-weight: 700; color: var(--navy-900, #0b2440); }
.get-started__result--request span { font-size: 13px; }

/* Community banner + change control (account step). */
.get-started__community {
  display: flex; align-items: center; flex-wrap: wrap; gap: 4px 10px; margin-bottom: 16px; padding: 12px 16px;
  border-radius: 12px; background: rgba(63,198,255,.16); border: 1px solid rgba(63,198,255,.4);
}
.get-started__community-label { font-size: 12px; text-transform: uppercase; letter-spacing: .6px; color: rgba(255,255,255,.7); width: 100%; }
.get-started__community-name { font-size: 18px; font-weight: 700; color: #fff; }
.get-started__community-img { flex: 0 0 auto; width: 44px; height: 44px; border-radius: 50%; object-fit: cover; background: rgba(255,255,255,.15); }
.get-started__change {
  margin-left: auto; padding: 4px 12px; border-radius: 999px; border: 1px solid rgba(255,255,255,.4);
  background: transparent; color: #fff; font: inherit; font-size: 13px; cursor: pointer;
}

/* Reveal (show/hide) affordance for masked inputs. */
.get-started__reveal-wrap { position: relative; display: block; }
.get-started__reveal {
  position: absolute; right: 8px; top: 50%; transform: translateY(-50%);
  background: transparent; border: 0; color: var(--blue-600, #1e6fd0); font: inherit; font-size: 13px; cursor: pointer;
}

/* Preferred contact method checkbox row. */
.get-started__prefs { border: 0; padding: 0; margin-bottom: 16px; }
.get-started__pref { display: inline-flex; align-items: center; gap: 6px; margin-right: 18px; color: rgba(255,255,255,.9); }
.get-started__pref input { width: auto; margin: 0; }
.get-started__hint { font-size: 13px; color: rgba(255,255,255,.75); margin: 4px 0 14px; text-align: center; }

/* ============================================================
   News & Insights listing (T12)
   ============================================================ */
.news-hero {
  position: relative; overflow: hidden; display: flex; align-items: center;
  min-height: 460px; color: var(--white);
  background-size: cover; background-position: center;
}
/* Category filter pills */
.news-tabs { display: flex; flex-wrap: wrap; justify-content: center; gap: 12px; margin: 22px 0 42px; }
.news-tab {
  padding: 8px 20px; border-radius: 999px; border: 1px solid #cfe0ee; background: #fff;
  color: var(--navy-900); font: inherit; font-weight: 600; font-size: 14px; cursor: pointer;
  transition: background .15s ease, color .15s ease, border-color .15s ease;
}
.news-tab:hover { border-color: var(--blue-600); }
/* #10b8ea gave white-on-cyan only 2.32:1 (WCAG AA needs 4.5:1 for 14px text). Darkened to
   #0d6f96 => 5.63:1. Same hue family, still reads as the brand cyan. */
.news-tab.is-active { background: #0d6f96; border-color: #0d6f96; color: #fff; }

/* Magazine-style featured row */
.news-featured { display: grid; grid-template-columns: repeat(3, 1fr); gap: 32px; align-items: start; }
.nf-col { display: flex; flex-direction: column; gap: 20px; }
.nf-text { display: block; text-decoration: none; }
.nf-text h3 { font-size: 22px; font-weight: 800; color: var(--navy-900); margin-bottom: 10px; line-height: 1.25; }
.nf-text:hover h3 { color: var(--blue-600); }
.nf-text p { color: var(--muted); font-size: 14px; line-height: 1.6; }
/* #9aa4b2 was 2.52:1 on white; #5b6673 is 5.84:1 (and 4.94:1 on the sky gradient). */
.nf-meta { display: block; margin-top: 10px; font-size: 12px; color: #5b6673; }
.nf-img { display: block; border-radius: 14px; aspect-ratio: 4 / 3; background-size: cover; background-position: center; box-shadow: 0 12px 30px rgba(16,42,92,.14); }
.nf-img--tall { aspect-ratio: 3 / 4; }
@media (max-width: 860px) { .news-featured { grid-template-columns: 1fr; } .nf-img--tall { aspect-ratio: 16 / 10; } }

/* Latest Posts */
.news-latest { background: linear-gradient(180deg, #dbeffb, #cfe8f8); }
.news-latest__title { font-size: clamp(28px, 3vw, 40px); color: #0d5a97; font-weight: 800; margin-bottom: 30px; }
.post-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 28px; }
.post-card { display: flex; flex-direction: column; background: #fff; border-radius: 16px; overflow: hidden; box-shadow: 0 14px 34px rgba(16,42,92,.12); }
.post-card__media { display: block; aspect-ratio: 16 / 9; background-size: cover; background-position: center; }
.post-card__body { padding: 22px 24px 26px; }
/* #8a94a3 was 3.06:1 on the white card; #5b6673 is 5.84:1. */
.post-card__meta { font-size: 12px; color: #5b6673; }
.post-card__title { font-size: 18px; font-weight: 800; color: var(--navy-900); margin: 8px 0; line-height: 1.3; }
.post-card__title a { color: inherit; }
.post-card__title a:hover { color: var(--blue-600); }
.post-card__excerpt { font-size: 14px; color: var(--muted); line-height: 1.6; }
@media (max-width: 720px) { .post-grid { grid-template-columns: 1fr; } }

/* Pagination */
.pagination { display: flex; align-items: center; justify-content: center; gap: 10px; margin-top: 44px; }
.pagination__page { min-width: 32px; text-align: center; padding: 6px 8px; border-radius: 8px; color: var(--blue-700); font-weight: 700; }
.pagination__page:hover { background: rgba(16,184,234,.14); }
.pagination__page.is-active { background: #10b8ea; color: #fff; }
.pagination__gap { color: var(--muted); }

/* ============================================================
   Residents / Business audience pages
   ============================================================ */
/* Stats row — big cyan number + label, vertical dividers */
.stats-row { display: flex; justify-content: center; margin-top: 36px; flex-wrap: wrap; }
.stat { position: relative; flex: 1 1 0; min-width: 150px; padding: 4px 16px; text-align: center; border-right: 1px solid rgba(120,180,230,.4); }
.stat:last-child { border-right: 0; }
.stat__num { display: block; font-size: clamp(28px, 3vw, 40px); font-weight: 400; color: #2a97fc; line-height: 1.1; }
.stat__label { display: block; margin-top: 8px; color: var(--muted); font-size: 14px; }
/* --decorated (Residents): lighter numbers, tighter columns so labels stay on one
   line, and dividers that stop short of the icon. Business uses the base treatment. */
.stats-row--decorated .stat { padding: 4px 14px; border-right: 0; }
.stats-row--decorated .stat:not(:last-child)::after {
  content: ""; position: absolute; right: 0; top: 40%; bottom: 2%;
  border-right: 1px solid rgba(120,180,230,.45);
}
.stats-row--decorated .stat__num { font-size: clamp(26px, 2.9vw, 36px); font-weight: 400; color: var(--cyan-display); line-height: 1.15; }
.stats-row--decorated .stat__label { margin-top: 6px; color: var(--navy-900); }
/* Decorated variant (Residents): the delivered headset-in-ring art, stars included. */
.stat__icon { display: block; width: 86px; height: 86px; object-fit: contain; margin: 0 auto 6px; }

/* Residents — connected-devices showcase band (delivered render on white).
   Zero bottom padding: the mockup runs the devices right into the teal band below,
   and the asset is pre-cropped to the 94% the mockup actually shows. */
.devices-band { padding-bottom: 0; }
.devices-band__rule { border: 0; border-top: 1px solid rgba(30,111,208,.45); margin: 0 0 46px; }
.devices-band__img { display: block; width: 100%; height: auto; margin-inline: auto; }
@media (max-width: 700px) { .stat { flex-basis: 45%; border-right: 0; margin-bottom: 22px; } }

/* Residents feature quad (2×2, icons, teal band per mockup) */
/* #319bbb could not carry AA body copy: white on it is only 3.21:1, and 15px normal text needs
   4.5:1 — no alpha of white fixes that, so the PANEL had to darken. #29809b gives white 4.51:1
   (and the 20px bold title 4.51 too, well past its 3:1 bar). Same hue, one step deeper.
   .residents .testimonial-section shares this exact colour on the same page, so it moves with
   the band — leaving one at #319bbb would put two near-identical teals side by side. */
.feature-quad-band { background: #29809b; color: #fff;padding: 5%;
  line-height: 3; margin-top: -174px;
  display: inline-block;}
.feature-quad { display: grid; grid-template-columns: 1fr 1fr; gap: 38px 48px; }
.feature-quad__item { display: flex; gap: 18px; align-items: flex-start; }
.feature-quad__icon { flex: 0 0 auto; display: grid; place-items: center; width: 88px; height: 88px; }
.feature-quad__icon img { display: block; width: 100%; height: auto; }
.feature-quad__title { color: var(--white); font-size: 20px; margin-bottom: 6px; }
.feature-quad__body { color: var(--white); font-size: 15px; line-height: 1.6; }
@media (max-width: 760px) { .feature-quad { grid-template-columns: 1fr; } }

/* Residents "Connected by STELLAR" band — light blue gradient per mockup */
.connected { position: relative; overflow: hidden; color: #fff; padding: 84px 0;
  background: linear-gradient(180deg, #2e5f8b 0%, #5091b5 55%, #88e6fc 100%); }
/* Glow ribbons. The mockup sweeps flowing light strands out of the globe's top-right and across
   to the right edge; the section had no such layer at all (both ::before and ::after were unset),
   so the band rendered as a flat gradient. Reuses fiber-light-lines.webp — the site's existing
   ribbon art, already used by .team-section and the Owners bands — rather than a new asset.
   Anchored right/top and oversized so the strands enter behind the globe and run off the right
   edge, which .connected's overflow:hidden already clips. Held back to .5 opacity: at full
   strength it competes with the copy, and the mockup's strands are noticeably thinner.
   The gradient must stay BEHIND it and the content in front, hence the z-indexes below. */
.connected::before {
  content: "";
  position: absolute;
  top: 0%;
  width: 100%;
  height: 100%;
  z-index: 0;
  pointer-events: none;
  background: url("../img/fiber-light-lines.webp") right/ 133% auto no-repeat;
  opacity: 0.6;
}
.connected > .container { position: relative; z-index: 1; }
.connected__inner { display: grid; grid-template-columns: 1fr 1fr; gap: 40px; align-items: center; }
/* Same delivered globe/city art as the Apartments hero (appartment-world.png),
   sitting left of the copy per the mockup. Slightly knocked back — over this light
   gradient the mockup's version reads softer than the hero's. */
.connected__art { display: block; width: 100%; max-width: 520px; height: auto; margin-inline: auto; opacity: .9; }
.connected__copy h2 { font-size: clamp(30px, 3.4vw, 44px); font-weight: 700; margin-bottom: 14px; }
.connected__copy strong { color: #7fd6f2; }
.connected__copy p { color: rgba(255,255,255,.85); margin-bottom: 22px; max-width: 520px; }
@media (max-width: 760px) { .connected__inner { grid-template-columns: 1fr; } .connected__art { max-width: 360px; } }

/* Business section 2 — mockup type/button treatment */
.eyebrow-cyan { color: var(--cyan-ink); text-transform: uppercase; letter-spacing: 1.6px; font-size: 15px; font-weight: 700; margin-bottom: 14px; }
/* Flat navy at a lighter weight — overrides .section__title's size/weight and cancels
   any gradient text-fill inherited from --grad usage elsewhere. */
.section__title--plain {
  font-size: clamp(24px, 2.7vw, 34px); font-weight: 500; color: var(--navy-900);
  background: none; -webkit-text-fill-color: currentColor;
}
.btn--pill-arrow {
  background: #fff; border: 1.5px solid var(--navy-900); color: var(--navy-900);
  border-radius: 999px; padding: 12px 26px; font-size: 15px; font-weight: 600;
  display: inline-flex; align-items: center; gap: 12px;
}
.btn--pill-arrow:hover, .btn--pill-arrow:focus-visible { background: var(--navy-900); color: #fff; }
.btn__arrow { font-size: 17px; line-height: 1; transition: transform .25s ease; }
.btn--pill-arrow:hover .btn__arrow { transform: translateX(4px); }
.btn--navy { background: var(--navy-900); border-color: var(--navy-900); color: #fff; }
.btn--navy:hover, .btn--navy:focus-visible { background: var(--blue-700); border-color: var(--blue-700); color: #fff; }

/* Business "Guaranteed Satisfaction" — copy + photo collage */
.satisfaction { display: grid; grid-template-columns: 1fr 1fr; gap: 46px; align-items: center; }
/* Mockup: light cyan, regular weight, one line — not the navy extra-bold section title. */
.satisfaction__title { font-size: clamp(26px, 2.9vw, 38px); font-weight: 400; color: var(--cyan-display); margin: 0 0 18px; }
.satisfaction__body { color: var(--muted); margin-bottom: 26px; }
.hl-cyan { color: var(--cyan-ink); }
.satisfaction__list { display: grid; gap: 24px; margin-bottom: 28px; }
/* Label-only rows with a bare glyph — the mockup has no circular badge behind it. */
.satisfaction__item { display: flex; gap: 16px; align-items: center; }
.satisfaction__icon { flex: 0 0 auto; display: grid; place-items: center; width: 49px; height: 49px; color: var(--blue-600); }
.satisfaction__icon img { display: block; width: 100%; height: auto; }
.satisfaction__icon svg { width: 38px; height: 38px; }
.satisfaction__item h3 { color: var(--cyan-ink); font-size: 19px; font-weight: 500; margin: 0; }
.satisfaction__actions { display: flex; gap: 12px; flex-wrap: wrap; }

/* Staggered photo collage (mockup geometry, as % of the collage box so it scales).
   Box spans the badge at the top through the lowest photo: 1009x959 in mockup px. */
.satisfaction__collage { position: relative; aspect-ratio: 1009 / 959; }
.sc-photo {
  position: absolute; border-radius: 14px; background-size: cover; background-position: center;
  box-shadow: 0 14px 34px rgba(16,42,92,.16);
}
.sc-photo--a { left: 0.3%;  top: 0.1%;  width: 64.4%; height: 61.9%; }
.sc-photo--b { left: 13.6%; top: 63.7%; width: 51.8%; height: 36.3%; }
.sc-photo--c { left: 67.4%; top: 23.6%; width: 32.6%; height: 61.2%; }
/* Badge slots — positions measured off the mockup; art pending delivery. */
.sc-badge { position: absolute; height: auto; object-fit: contain; }
.sc-badge--one   { left: 68.2%; top: 0;     width: 20.8%; }
.sc-badge--two   { left: 0.2%;  top: 64.7%; width: 11.3%; }
.sc-badge--three { left: 68.3%; top: 87.6%; width: 11.3%; }
@media (max-width: 820px) { .satisfaction { grid-template-columns: 1fr; } }

/* ---- Business testimonials carousel (Revised Commercial Business Page.png) -------------------
   Light gradient band, navy pill, navy heading, then a track of quote cards. The centred card is
   opaque and the neighbours sit faded and slightly inset, which is what gives the mockup its
   peeking effect; .is-active is stamped by the shared carousel JS in main.js.
   Arrows are present for that JS (it bails without them) and for keyboard use, but visually
   hidden — the mockup paginates with dots. ---- */
.testimonial-band {
  background: linear-gradient(180deg, #cdeafc 0%, #e8f6fe 45%, #d8effd 100%);
  text-align: center;
}
.testimonial-band__pill {
  display: inline-block; background: var(--navy-900); color: #fff;
  padding: 7px 20px; border-radius: 999px; font-size: 14px; font-weight: 600; margin: 0 0 14px;
}
.testimonial-band__title {
  color: var(--navy-900); font-size: clamp(26px, 3.4vw, 42px); font-weight: 700; margin: 0 0 34px;
}
.quote-carousel { position: relative; }
.quote-carousel__track {
  display: flex; gap: 28px; overflow-x: auto; scroll-behavior: smooth;
  scroll-padding-inline: 50%;
  padding: 6px calc((100% - min(640px, 82%)) / 2) 10px;
  scrollbar-width: none;
}
.quote-carousel__track::-webkit-scrollbar { display: none; }
/* The track is tabbable (see the axe note in business.php), so it needs a visible focus ring. */
.quote-carousel__track:focus-visible { outline: 3px solid var(--blue-600); outline-offset: 4px; border-radius: 18px; }
.quote-card {
  flex: 0 0 min(640px, 82%); margin: 0;
  background: #fff; border-radius: 16px; padding: 34px 38px;
  box-shadow: 0 14px 34px rgba(16,42,92,.12);
  /* Neighbours are knocked back; the centred card comes forward. */
  opacity: .45; transform: scale(.97);
  transition: opacity .35s ease, transform .35s ease;
}
.quote-card.is-active { opacity: 1; transform: none; }
.quote-card blockquote {
  margin: 0 0 22px; color: var(--ink); font-size: 17px; line-height: 1.65;
}
.quote-card figcaption {
  border-top: 1px solid #e4ecf7; padding-top: 18px;
  color: var(--navy-900); font-weight: 700; font-size: 15px;
}
/* Role sits under the name, lighter — the live carousel and the mockup both set it apart. */
.quote-card__role { display: block; font-weight: 400; font-style: italic; color: var(--muted); margin-top: 3px; }
.quote-carousel__arrow { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); border: 0; padding: 0; }
.quote-carousel__dots {
  display: inline-flex; gap: 10px; align-items: center;
  background: rgba(255,255,255,.75); border-radius: 999px; padding: 8px 14px; margin-top: 26px;
}
.quote-carousel__dots button {
  width: 9px; height: 9px; border-radius: 50%; border: 0; padding: 0; cursor: pointer;
  background: #b9d3e4; transition: background .2s ease, transform .2s ease;
}
.quote-carousel__dots button.is-current { background: var(--navy-900); transform: scale(1.15); }
@media (max-width: 700px) { .quote-card { padding: 26px 22px; } }

/* ---------------------------------------------------------------------------
   News article (T13) — src/pages/news/_article-layout.php
   Heroes here are plain brand chrome: most legacy news images are promo graphics
   with text burned in, so overlaying the H1 on one makes both unreadable. The
   article image renders in the body instead (.article__image).
   --------------------------------------------------------------------------- */
.news-article-hero { min-height: clamp(320px, 34vw, 420px); }
/* News headlines need their own, smaller scale. .page-hero--article's clamp(34px, 5vw, 60px) was
   sized for short support titles ("Renew My Service", 16 chars); real news headlines run 100-160
   characters, and at 60px a 159-char one filled 7 lines / 483px and pushed the hero to 600px — on
   mobile, 11 lines / 430px, i.e. the entire first screen was the headline. Same two-class
   specificity as the rule it overrides, and it wins on file order by sitting after it. */
.news-article-hero .page-hero__title {
  font-size: clamp(23px, 2.5vw, 34px);
  line-height: 1.2;
  max-width: 820px;
}

.article__meta {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
  margin: 0 0 22px; font-size: 14px; color: var(--muted);
}
.article__date { font-weight: 600; }
.article__meta-sep { color: #b6c6d6; }
/* #10b8ea is only 2.32:1 on white — fine for large display type, not for 14px links.
   #0b6d92 is 5.81:1. Applies to every cyan link in the news templates. */
.article__tag {
  color: #0b6d92; text-decoration: none; font-weight: 600;
}
.article__tag:hover { text-decoration: underline; }

.article__image { margin: 0 0 28px; }
.article__image img {
  display: block; width: 100%; height: auto; border-radius: 14px;
  box-shadow: 0 12px 32px rgba(4, 20, 44, .14);
}

.article__back { margin-top: 32px; }
.article__back a { color: #0b6d92; text-decoration: none; font-weight: 600; }
.article__back a:hover { text-decoration: underline; }

/* axe "link-in-text-block": the breadcrumb link sat at 1.09:1 against the surrounding
   crumb text, and no colour change can fix that — the current-page crumb is grey text of
   almost the same lightness. WCAG allows either 3:1 against neighbouring text OR a
   non-colour cue, so the link is underlined.
   Applied to ALL breadcrumbs (news, support, city pages): the markup is shared, so scoping
   this to one section just meant the same violation resurfaced on the next page that used it. */
.breadcrumb a {
  color: #0b6d92; text-decoration: underline; text-underline-offset: 2px;
}

/* Testimonial video (home) — click-to-play. The <video> fills the media box and sits above
   the CSS poster background; the custom play button hides once playback starts and native
   controls take over. */
.testimonial__media--video .testimonial__video {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; border-radius: inherit; background: #16324a;
}
/* Transparent full-area hit target. The poster artwork already draws its own play button,
   so this control is deliberately invisible — it exists to make the whole frame clickable
   and to give keyboard/screen-reader users a real, labelled control. */
.testimonial__media--video .testimonial__videobtn {
  position: absolute; inset: 0; z-index: 2;
  width: 100%; height: 100%; padding: 0;
  border: 0; background: transparent; cursor: pointer;
  border-radius: inherit;
}
.testimonial__media--video .testimonial__videobtn:focus-visible {
  outline: 3px solid var(--cyan-400, #10b8ea); outline-offset: -3px;
}
.testimonial__media--video.is-playing .testimonial__videobtn {
  display: none;
}

/* ---- Section 2 "Explore Our Services" — scroll-in choreography ----
   Piggybacks on the existing [data-reveal] observer: main.js adds .is-visible to
   .services-strip once, and everything below cascades off that. No extra JS.

   The white bar rises and its shadow blooms, then the eight services stagger in behind
   it (--i is set per <li> in home.php), each icon popping a beat after its own label.

   IMPORTANT: this animates the independent `translate` / `scale` properties, NOT
   `transform`. .services-row__item:hover already owns transform (translateY(-4px)), and a
   .is-visible rule on transform would be more specific and permanently kill the hover
   lift. Keeping the two on separate properties lets both run without fighting. */

.services-strip .services-bar {
  opacity: 0;
  translate: 0 34px;
  scale: .985;
  box-shadow: 0 0 0 rgba(4, 16, 40, 0);
  transition:
    opacity .75s ease,
    translate .9s cubic-bezier(.16, .84, .28, 1),
    scale .9s cubic-bezier(.16, .84, .28, 1),
    box-shadow .9s ease;
}
.services-strip.is-visible .services-bar {
  opacity: 1; translate: none; scale: 1;
  box-shadow: 0 10px 30px rgba(4, 16, 40, .35);
}

.services-strip .services-row__item {
  opacity: 0;
  translate: 0 26px;
  transition:
    opacity .55s ease,
    translate .65s cubic-bezier(.16, .84, .28, 1);
  transition-delay: calc(150ms + var(--i, 0) * 65ms);
}
.services-strip.is-visible .services-row__item { opacity: 1; translate: none; }

/* Icon blooms in slightly late with a gentle overshoot, and its glow fades up with it. */
.services-strip .services-row__icon {
  scale: .68;
  filter: drop-shadow(0 0 0 rgba(60, 180, 255, 0));
  transition:
    scale .7s cubic-bezier(.22, 1.35, .32, 1),
    filter .7s ease;
  transition-delay: calc(220ms + var(--i, 0) * 65ms);
}
.services-strip.is-visible .services-row__icon {
  scale: 1;
}

.services-strip .services-row__label {
  opacity: 0;
  translate: 0 8px;
  transition: opacity .5s ease, translate .5s ease;
  transition-delay: calc(280ms + var(--i, 0) * 65ms);
}
.services-strip.is-visible .services-row__label { opacity: 1; translate: none; }

@media (prefers-reduced-motion: reduce) {
  .services-strip .services-bar,
  .services-strip .services-row__item,
  .services-strip .services-row__label {
    opacity: 1; translate: none; scale: 1; transition: none;
  }
  .services-strip .services-bar { box-shadow: 0 10px 30px rgba(4, 16, 40, .35); }
  .services-strip .services-row__icon {
    scale: 1; transition: none;
    filter: drop-shadow(0 0 7px rgba(60, 180, 255, .55));
  }
}

/* ---- Section 3 audience cards — 3D flip-in ----
   Same mechanism as the services strip: main.js stamps .is-visible on the [data-reveal]
   section once, and the cards swing open from their left edge like doors, staggered
   left to right. No extra JS.

   The three cards share ONE perspective origin on .row, so they read as a single scene
   rather than three unrelated flips.

   Safe to animate `transform` here (unlike the services strip): .audience-card:hover only
   ever touches box-shadow, so nothing is competing for the property. The label uses
   `translate` and restates the hover transitions it would otherwise clobber. */

.audience-strip .row { perspective: 1400px; }

.audience-strip .audience-card__media {
  opacity: 0;
  transform: rotateY(-72deg);
  transform-origin: left center;
  backface-visibility: hidden;
  transition:
    opacity .5s ease,
    transform .85s cubic-bezier(.18, .78, .26, 1),
    box-shadow .2s ease;
  transition-delay: calc(var(--i, 0) * 130ms);
}
.audience-strip.is-visible .audience-card__media {
  opacity: 1;
  transform: none;
}

.audience-strip .audience-card__label {
  opacity: 0;
  translate: 0 14px;
  transition:
    opacity .5s ease,
    translate .5s cubic-bezier(.2, .7, .2, 1),
    background .15s ease,
    box-shadow .15s ease;
  transition-delay: calc(300ms + var(--i, 0) * 130ms);
}
.audience-strip.is-visible .audience-card__label { opacity: 1; translate: none; }

@media (prefers-reduced-motion: reduce) {
  .audience-strip .row { perspective: none; }
  .audience-strip .audience-card__media {
    opacity: 1; transform: none; transition: box-shadow .2s ease;
  }
  .audience-strip .audience-card__label {
    opacity: 1; translate: none;
    transition: background .15s ease, box-shadow .15s ease;
  }
}

/* ---- City landing pages (/fiber-internet, /fiber-internet/<city>) ---- */
.city-hero { min-height: clamp(320px, 34vw, 430px); }

.city-intro {
  max-width: 760px; margin: 0 auto;
}
.city-intro p {
  font-size: 17px; line-height: 1.75; color: var(--muted); margin-bottom: 18px;
}

.city-services {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 26px; margin-top: 34px;
}
.city-services__item {
  background: #fff; border-radius: 16px; padding: 24px;
  box-shadow: 0 10px 26px rgba(16, 42, 92, .10);
}
.city-services__item h3 {
  font-size: 17px; font-weight: 800; color: var(--navy-900); margin-bottom: 8px;
}
.city-services__item p { font-size: 14px; line-height: 1.6; color: var(--muted); }
@media (max-width: 980px) { .city-services { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 560px) { .city-services { grid-template-columns: 1fr; } }

.city-grid {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 26px; margin-top: 40px;
}
.city-card {
  display: block; background: #fff; border-radius: 18px; padding: 28px;
  box-shadow: 0 12px 30px rgba(16, 42, 92, .12);
  text-decoration: none; border: 1px solid #e3edf6;
  transition: transform .18s ease, box-shadow .18s ease, border-color .18s ease;
}
.city-card:hover {
  transform: translateY(-4px); border-color: #b9dcf3;
  box-shadow: 0 18px 40px rgba(16, 42, 92, .18);
}
.city-card__name { font-size: 22px; font-weight: 800; color: var(--navy-900); margin-bottom: 10px; }
.city-card__lede { font-size: 14px; line-height: 1.6; color: var(--muted); margin-bottom: 14px; }
.city-card__meta { font-size: 12px; font-weight: 700; color: #0b6d92; }
@media (max-width: 980px) { .city-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 620px) { .city-grid { grid-template-columns: 1fr; } }

.city-links {
  display: flex; flex-wrap: wrap; justify-content: center; gap: 10px 18px; margin-top: 20px;
}
.city-links a {
  color: #0b6d92; font-weight: 600; text-decoration: none;
  padding: 8px 16px; border-radius: 999px; border: 1px solid #cfe0ee; background: #fff;
}
.city-links a:hover { border-color: #0b6d92; text-decoration: underline; }
