/* ============================================================
   PGISR — Editorial homepage layer
   ------------------------------------------------------------
   Layout system for the refined homepage composition: split
   hero, oversized editorial headings, full-bleed narrative
   blocks, and image-led application panels.

   Loaded after site.css/premium.css so it can set the homepage
   rhythm without touching the shared component styles used by
   the other pages.
   ============================================================ */

:root {
  /* One vertical rhythm scale for the whole editorial flow, so
     section spacing stays proportional instead of hand-tuned.
     The hero stays generous; everything after it runs on this
     tighter band so the page reads spacious without being long. */
  --ed-band:      clamp(3.75rem, 6.25vw, 7rem);
  --ed-band-tight:clamp(2.75rem, 4vw, 4.5rem);
  --ed-gap:       clamp(1.75rem, 3.5vw, 3.5rem);
  --ed-wide:      min(100% - (2 * var(--page-gutter)), 1440px);
}

/* Editorial pages opt in, so other pages keep the existing rhythm. */
.editorial .shell-wide { width: var(--ed-wide); margin-inline: auto; }

/* ---- Type scale -------------------------------------------------
   The shared .ops-title caps at 2.8rem, which reads timid at the
   section-opening sizes this layout needs. These are additive so
   the shared component is untouched for other pages. */
.ed-display {
  font-family: var(--font-display);
  font-weight: 700;
  color: var(--ink);
  margin: 0;
  line-height: 0.98;
  letter-spacing: -0.025em;
  font-size: clamp(2.5rem, 5.8vw, 5rem);
  text-wrap: balance;
}
/* Keep the longer Delivers statement editorially oversized without letting
   it fragment into single-word lines at the tested responsive widths. */
#delivers-title {
  font-size: clamp(2.5rem, 5.1vw, 4.5rem);
}
/* Same treatment for the Helps opener so "Built on decades of PWI"
   holds as one line inside the narrower opener column. */
#helps-title {
  font-size: clamp(1.9rem, 3.6vw, 3.2rem);
  /* The manual <br> already sets the two lines; balance would re-split
     the first one at wide viewports even when it fits. */
  text-wrap: wrap;
}
@media (max-width: 420px) {
  #delivers-title {
    font-size: clamp(2.0625rem, 9vw, 2.5rem);
    text-wrap: pretty;
  }
}
@media (max-width: 340px) {
  #delivers-title {
    width: calc(100% + 1.25rem);
    margin-inline: -0.5rem;
    font-size: 1.9rem;
  }

  /* At the narrowest supported viewport, keep the few longest editorial
     headings composed as phrases instead of stacks of isolated words. */
  #hero-title {
    width: calc(100% + 1.5rem);
    max-width: none;
    margin-inline: -0.75rem;
    font-size: 2.5rem;
  }
  #helps-title,
  #workflow-title {
    width: calc(100% + 1.25rem);
    margin-inline: -0.5rem;
  }
  /* No font-size here: #helps-title is a secondary .ed-title now, and its
     own 1.9rem floor is already the right size at this width. */
  #helps-title { text-wrap: pretty; }
  #workflow-title { font-size: 2.35rem; }
}
.ed-title {
  font-family: var(--font-display);
  font-weight: 700;
  color: var(--ink);
  margin: 0;
  line-height: 1.03;
  letter-spacing: -0.02em;
  font-size: clamp(1.9rem, 3.4vw, 3rem);
  text-wrap: balance;
}
.ed-lede {
  font-size: clamp(1rem, 1.25vw, 1.15rem);
  line-height: 1.65;
  color: var(--body);
  margin: 0;
  max-width: 48ch;
}
.ed-kicker {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  font-family: var(--font-mono);
  font-size: 0.62rem;
  font-weight: 700;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--accent);
  margin: 0 0 1.4rem;
}
.ed-kicker::before {
  content: "";
  width: 5px; height: 5px;
  border-radius: 50%;
  background: currentColor;
  flex: none;
}

/* ================================================================
   0 · IMAGE PLACEHOLDERS
   Shared production placeholders reserve the final image dimensions.
   Swap the placeholder element for an approved image while retaining
   the surrounding media container and its ratio class.
   ================================================================ */
.ed-ph {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: auto;
  min-width: 0;
  min-height: 0;
  overflow: hidden;
  padding: clamp(1rem, 3vw, 1.5rem);
  text-align: center;
  background: #09131e;
  border: 1px solid rgba(87, 194, 181, 0.3);
  border-radius: 0;
}
.ed-ph::before {
  content: "";
  position: absolute;
  top: 0;
  left: 50%;
  width: clamp(2.5rem, 8vw, 5rem);
  height: 1px;
  transform: translateX(-50%);
  background: rgba(87, 194, 181, 0.72);
}
.ed-ph-label {
  position: relative;
  z-index: 1;
  font-family: var(--font-mono);
  font-size: clamp(0.56rem, 1.6vw, 0.7rem);
  font-weight: 600;
  line-height: 1.55;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--steel);
  max-width: min(100%, 48ch);
  overflow-wrap: anywhere;
}
.ed-ph-secondary,
.ed-ph-dims {
  display: block;
  font-weight: 400;
  letter-spacing: 0.07em;
  color: var(--muted);
}
.ed-ph-secondary {
  margin-top: 0.3rem;
  text-transform: none;
}
.ed-ph-dims {
  margin-top: 0.4rem;
}
.ed-ph--16x9 { aspect-ratio: 16 / 9; }
.ed-ph--21x9 { aspect-ratio: 21 / 9; }
.ed-ph--3x2  { aspect-ratio: 3 / 2; }
@media (max-width: 420px) {
  .ed-ph {
    padding: 0.75rem;
  }
  .ed-ph-label {
    letter-spacing: 0.055em;
  }
}
/* ================================================================
   1 · HERO — asymmetric split
   Oversized statement on one side, full-bleed property visual on
   the other. No cards, no UI chrome layered over the image.
   ================================================================ */
.ed-hero {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.05fr);
  /* The viewport-height term alone caps the hero at 900px regardless
     of width. On a wide, short window (a maximized browser on an
     external monitor) that forces the full-bleed photo to scale up
     so much to cover the width that its subject -- a phone held
     upright -- no longer fits the visible height at any crop. The
     width-based floor grows the hero on those wide/short windows so
     the whole phone stays in frame; it's a no-op everywhere the
     height-based term already wins (every normal laptop window). */
  min-height: max(min(92svh, 900px), calc(46vw + 150px));
  border-bottom: 1px solid var(--line-strong);
  background: var(--bg);
}
.ed-hero-copy {
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: calc(var(--header-h) + var(--ed-band-tight)) clamp(2rem, 5vw, 5.5rem) var(--ed-band-tight) var(--page-gutter);
  /* Keeps the text column from drifting away from the page's
     left edge on very wide screens. */
  margin-left: max(0px, calc((100vw - 1680px) / 2));
}
.ed-hero-title {
  font-size: clamp(2.8rem, 4.9vw, 4.6rem);
  /* A light depth cue, not the legibility mechanism -- an earlier pass
     leaned on a tight near-opaque outline layer to cover for a weak
     gradient, and at this font's size that outline read as a visible
     halo around the letterforms once the backdrop got busy (sun glare
     on water). The gradient below now carries the real contrast work
     again; this is back to a normal soft shadow. */
  text-shadow: 0 2px 4px rgba(0,0,0,0.55), 0 6px 22px rgba(0,0,0,0.3);
}
.ed-hero-lede {
  margin-top: 1.75rem;
  max-width: 38ch;
  /* Scoped brightness/weight bump over the shared .ed-lede colour —
     it was reading a shade too quiet against the darker hero photo.
     Stays a full step under the headline's weight and size. */
  color: #d3e5ef;
  font-weight: 470;
  text-shadow: 0 2px 3px rgba(0,0,0,0.55), 0 4px 16px rgba(0,0,0,0.3);
}
/* Two supporting points, not a single two-line sentence: same accent-dash
   treatment as .equipment-hero-list, so it reads as a restrained technical
   list rather than a broken subheading — no new bullet language introduced. */
.ed-hero-points {
  list-style: none;
  padding: 0;
}
.ed-hero-points li {
  position: relative;
  padding-left: 1.1rem;
}
.ed-hero-points li + li {
  margin-top: 0.4rem;
}
.ed-hero-points li::before {
  content: "";
  position: absolute;
  top: 0.72em;
  left: 0;
  width: 0.55rem;
  height: 1px;
  background: var(--accent);
}
.ed-hero-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1.5rem 2rem;
  margin-top: clamp(2rem, 4vw, 3rem);
}

/* The primary CTA colour lives on a hero-specific selector elsewhere in
   the sheet stack, so the bare .button-primary falls back to the sage
   form-submit fill. Restate the brand gold here so the editorial CTAs
   match the site's primary buttons. */
.ed-hero-actions .button-primary,
.ed-close-actions .button-primary {
  background: #D4A72C;
  border-color: #D4A72C;
  color: #140a03;
}
.ed-hero-actions .button-primary:hover,
.ed-close-actions .button-primary:hover {
  background: #EBC65A;
  border-color: #EBC65A;
}
.ed-hero-actions .button-primary:active,
.ed-close-actions .button-primary:active {
  background: #B58F22;
}
/* While the hero's own CTA is on screen the header repeats it verbatim,
   so the header copy is held back and fades in once the hero button
   scrolls away. Default state is visible — if the script never runs the
   button simply behaves as it always did. */
body.editorial .pgisr-header .pgisr-nav-cta {
  transition: opacity 0.35s ease, transform 0.35s ease;
}
body.editorial.home-page .pgisr-header.is-at-hero .pgisr-nav-cta {
  opacity: 0;
  transform: translateY(-4px);
  pointer-events: none;
}
@media (prefers-reduced-motion: reduce) {
  body.editorial .pgisr-header .pgisr-nav-cta { transition: none; }
}

.ed-hero-media {
  position: relative;
  overflow: hidden;
  background: var(--bg-2);
}
.ed-hero-stage {
  position: absolute;
  /* Starts below the header band rather than running under it, so the
     subject never crowds the navigation. Above 900px only — the
     stacked hero already clears the header with its own margin. */
  top: var(--header-h);
  right: 0;
  left: 0;
  width: 100%;
  height: calc(100% - var(--header-h));
  overflow: hidden;
  /* --hero-pos-x/y mirror the old object-position: 54% 15% (see below);
     hero-stage.js reads them to replicate object-fit: cover for the
     whole photo+UI-overlay group, which plain CSS object-fit can't do
     since the overlay isn't a replaced element. */
  --hero-pos-x: 0.54;
  --hero-pos-y: 0.15;
}
/* The photo and the phone-screen text overlay live in one fixed
   1672x941 group (the photo's native pixel size) so the overlay is
   defined once, in image pixel coordinates, and never has to be
   re-derived per breakpoint. hero-stage.js scales/positions the whole
   group to cover .ed-hero-stage, keeping photo and overlay locked
   together at every viewport size. */
.ed-hero-photo-group {
  position: absolute;
  top: 0;
  left: 0;
  width: 1672px;
  height: 941px;
  transform-origin: 0 0;
}
.ed-hero-photo-group img {
  display: block;
  width: 1672px;
  height: 941px;
}
@media (max-width: 900px) {
  .ed-hero-stage { inset: 0; height: 100%; }
  /* --hero-pos-x is object-position-style (the point p% across the
     image lands at p% across the container), not "center on the
     subject" — 0.5 was cropping in symmetrically around the image's
     midpoint, but the phone itself sits at ~54% across the photo, so at
     the tighter 4/5 crop's higher zoom that small offset was enough to
     push the phone almost to the right edge. 0.57 centers the phone
     itself in the visible window at this crop's scale. */
  .ed-hero-stage { --hero-pos-x: 0.57; --hero-pos-y: 0.5; }
}

/* ---- Phone-screen text overlay -----------------------------------
   Sits on top of the blank screen in owner-experience-blank.webp,
   positioned in that photo's own pixel coordinates (the group is a
   fixed 1672x941 box — see .ed-hero-photo-group above). Real markup
   instead of baked-in photo text so copy changes are a text edit,
   not a re-shoot.

   The screen rect below was measured off the photo by thresholding:
   the glass sits at a uniform luminance (~15) between the frame (~0)
   and the background (~200+), and its edges came out dead straight —
   left 863, right 1186.5, top 75, bottom 803. The phone is rendered
   perfectly upright, so NO rotation or perspective transform belongs
   here; adding either visibly skews the text off the glass. The
   dynamic island ends at y≈118 (43px down), which sets padding-top.
   Re-measure these four numbers if the hero photo changes. */
.ed-hero-ui {
  position: absolute;
  top: 75px;
  left: 863px;
  width: 323px;
  height: 728px;
  display: flex;
  flex-direction: column;
  align-items: center;
  /* Top padding clears the dynamic island; the status line sits at the
     top like a real app bar, and the status mark below is centred in
     the space that's left by the auto margins. */
  padding: 52px 20px 64px;
  font-family: var(--font-mono, ui-monospace, monospace);
  text-align: center;
}
/* Tracked-out uppercase mono, matching .ed-kicker's language rather
   than a tight bold setting — the wide tracking and lighter weight are
   what keep it from reading as a utility readout. text-indent cancels
   the trailing letter-space so centred tracked caps stay optically
   centred. Accent is held back for the LIVE flag and the shield; the
   headline sits in near-white, the same hierarchy the page uses. */
.ed-hero-ui-kicker {
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.24em;
  text-indent: 0.24em;
  color: #7f8b90;
  margin: 0;
}
.ed-hero-ui-kicker span { color: var(--accent); }
.ed-hero-ui-title {
  font-size: 14px;
  font-weight: 500;
  letter-spacing: 0.28em;
  text-indent: 0.28em;
  color: #f1f5f6;
  margin: auto 0 0;
}
/* The brand lockup image on the phone screen. Scoped under .ed-hero-ui so
   it outranks .ed-hero-photo-group img above, which sizes every image in
   the group to the photo's 1672 x 941 and would blow the logo up to that. */
.ed-hero-ui .ed-hero-ui-mark {
  display: block;
  /* Icon only, so narrower than the 220px the lockup took. */
  width: 116px;
  height: auto;
  margin: 14px 0 auto;
}
/* Softens the image into the copy column instead of a hard seam. */
.ed-hero-media::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg, var(--bg) 0%, rgba(12,16,23,0.55) 14%, transparent 46%);
  pointer-events: none;
}

/* ---- Full-bleed hero banner ------------------------------------
   The hero image is a wide landscape; holding it in the right-hand
   grid cell cropped most of it away and left a hard vertical seam
   down the middle of the fold. Above 900px the image runs the whole
   banner and the scrim carries the copy column, so the statement
   stays readable and the photograph is seen at close to its own
   proportions. The copy column keeps the width the grid gives it. */
@media (min-width: 901px) {
  .ed-hero-media {
    position: absolute;
    inset: 0;
    z-index: 0;
  }
  .ed-hero-copy {
    position: relative;
    z-index: 1;
  }
  .ed-hero-media::after {
    /* Rebuilt as a tight, localized text scrim rather than a broad
       panel: the old gradient carried real darkness out to 56-72% of
       the width, which read as a second dark surface sitting over the
       photo through the middle of the hero.

       This went through two lighter versions first, both of which
       failed against the real photo rather than a hypothetical one:
       a smooth continuous falloff let the darkness thin out well
       before the headline's own text actually ended (measured live,
       "...Security" runs out to ~44% of the hero's width at every
       desktop breakpoint), and a version that tried to compensate with
       a heavier text-shadow instead just turned that shadow into a
       visible halo once it hit a sun-glare patch on the water. So
       instead of a continuous decay, this holds solidly dark (0.5+)
       across a plateau covering the full width the headline actually
       occupies, and only tapers in the last stretch before the phone
       (~54-61% in) -- protection sized to the real text, not a shape
       chosen for its own sake. Text-shadow is back to a normal soft
       depth cue on top of this, not doing the contrast work itself. */
    background:
      linear-gradient(90deg,
        rgba(12,16,23,0.80) 0%,
        rgba(12,16,23,0.68) 14%,
        rgba(12,16,23,0.58) 28%,
        rgba(12,16,23,0.52) 40%,
        rgba(12,16,23,0.30) 48%,
        rgba(12,16,23,0.12) 53%,
        transparent 58%);
  }
}

@media (max-width: 900px) {
  .ed-hero {
    grid-template-columns: 1fr;
    min-height: 0;
  }
  .ed-hero-copy {
    order: 2;
    margin-left: 0;
    padding: var(--ed-band-tight) var(--page-gutter);
  }
  .ed-hero-media {
    order: 1;
    /* Taller than the old 16/10: at a narrow phone width that crop held
       the photo (and the phone-screen text baked into the same scaled
       group, see hero-stage.js) down around 0.25x native size, shrinking
       the "SITE SECURE / PGISR" overlay to a couple of illegible px. A
       taller crop forces a bigger cover-scale, growing the photo and its
       overlay together — no separate fix needed for the overlay text. */
    aspect-ratio: 4 / 5;
    margin-top: var(--header-h);
  }
  .ed-hero-media::after {
    background: linear-gradient(0deg, var(--bg) 2%, transparent 55%);
  }

  /* The phone-screen overlay is scaled with the photo (hero-stage.js), and
     at a 375px phone that scale is ~0.5: the 10px kicker rendered at 5px
     and the 14px status at 7px. Doubling them here lands them at about
     10px and 13px on screen, and the mark grows in step. All three still
     clear the screen's 323px base width with the tracking they carry. */
  .ed-hero-ui-kicker { font-size: 20px; }
  .ed-hero-ui-title { font-size: 26px; }
  .ed-hero-ui .ed-hero-ui-mark { width: 140px; margin-top: 18px; }
}

/* ---- Credentials — static, no marquee ---------------------------
   The previous infinite ticker repeated three names on a loop.
   A still row states the same facts without perpetual motion. */
.ed-creds {
  border-bottom: 1px solid var(--line);
  background: var(--bg-2);
}
.ed-creds-inner {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 1.25rem clamp(2rem, 5vw, 4.5rem);
  padding-block: clamp(1.5rem, 3vw, 2.25rem);
}
.ed-creds-label {
  font-family: var(--font-mono);
  font-size: 0.6rem;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--muted);
}
.ed-cred {
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
}
.ed-cred b {
  font-size: 0.92rem;
  font-weight: 700;
  color: var(--ink);
  letter-spacing: -0.01em;
}
.ed-cred span {
  font-family: var(--font-mono);
  font-size: 0.62rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted);
}
@media (max-width: 700px) {
  .ed-creds-label { flex: 1 0 100%; margin-right: 0; }
}

/* ================================================================
   2 · SECTION SHELL
   ================================================================ */
.ed-section {
  padding-block: var(--ed-band);
  border-bottom: 1px solid var(--line);
}
.ed-section--tight { padding-block: var(--ed-band-tight); }
.ed-section--alt   { background: var(--bg-2); }
.ed-section--deep  { background: #090d13; }

/* Section opener: oversized heading left, short copy right. */
.ed-opener {
  display: grid;
  grid-template-columns: minmax(0, 1.15fr) minmax(0, 0.85fr);
  gap: var(--ed-gap);
  align-items: end;
}
/* No ch-based cap here: the display headings scale with vw while ch
   tracks the body font, so a 60ch cap makes two-line lockups wrap to
   three lines when the two sizes drift apart across browsers. */
.ed-opener--stack { grid-template-columns: 1fr; }
/* A second opener inside a merged band needs its own separation from
   the block above it, since it no longer gets section padding. */
.ed-opener--follow {
  margin-top: clamp(2.75rem, 4.5vw, 4.5rem);
  padding-top: clamp(2.25rem, 3.5vw, 3.25rem);
  border-top: 1px solid var(--line-strong);
}
@media (max-width: 860px) {
  .ed-opener { grid-template-columns: 1fr; align-items: start; }
}

/* ================================================================
   3 · WORKFLOW SEQUENCE — Detect / Verify / Assess / Respond
   Four true panels cropped from the approved artwork sit on the
   page grid. Hairline connectors between panels carry the
   left-to-right sequence, so no arrows are baked into the imagery.
   ================================================================ */
.ed-stages {
  --ed-flow-gap: clamp(1.5rem, 2.75vw, 2.75rem);
  list-style: none;
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  column-gap: var(--ed-flow-gap);
  row-gap: clamp(2.25rem, 3.5vw, 3rem);
  margin: clamp(2.25rem, 4vw, 3.5rem) 0 0;
  padding: 0;
}
.ed-stage {
  display: flex;
  flex-direction: column;
  min-width: 0;
}
.ed-stage-media {
  position: relative;
  margin: 0;
  border: 1px solid var(--line-strong);
  background: var(--bg-3);
}
.ed-stage-media img {
  display: block;
  width: 100%;
  height: auto;
}
/* Connector drawn in the column gap at the panels' vertical center:
   a fading hairline that resolves into a chevron at the next panel. */
.ed-stage + .ed-stage .ed-stage-media::before {
  content: "";
  position: absolute;
  top: 50%;
  right: 100%;
  width: var(--ed-flow-gap);
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--accent));
}
.ed-stage + .ed-stage .ed-stage-media::after {
  content: "";
  position: absolute;
  top: 50%;
  left: -0.5rem;
  width: 0.42rem;
  height: 0.42rem;
  border-top: 1px solid var(--accent);
  border-right: 1px solid var(--accent);
  transform: translateY(-50%) rotate(45deg);
}
/* Caption sits under its panel, left-aligned with the panel edge. */
.ed-stage-caption {
  display: flex;
  flex-direction: column;
  gap: 0.55rem;
  padding-top: 1.05rem;
}
.ed-stage-head {
  display: flex;
  align-items: baseline;
  gap: 0.65rem;
}
.ed-stage-num {
  flex: none;
  font-family: var(--font-mono);
  font-size: 0.66rem;
  font-weight: 700;
  line-height: 1;
  letter-spacing: 0.1em;
  color: var(--accent);
}
.ed-stage-name {
  font-family: var(--font-display);
  font-size: clamp(1.3rem, 1.65vw, 1.55rem);
  font-weight: 750;
  letter-spacing: -0.02em;
  line-height: 1;
  color: var(--ink);
  margin: 0;
}
/* The status is a subordinate readout, not an individually boxed chip. */
.ed-stage-status {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin: 0;
  font-family: var(--font-mono);
  font-size: 0.68rem;
  font-weight: 600;
  line-height: 1.35;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--body);
}
.ed-stage-status::before {
  content: "";
  width: 0.8rem;
  height: 1px;
  background: var(--accent);
  flex: none;
}

/* Narrow tablets: two-by-two grid; connectors only within each row. */
@media (min-width: 641px) and (max-width: 960px) {
  .ed-stages { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .ed-stage:nth-child(3) .ed-stage-media::before,
  .ed-stage:nth-child(3) .ed-stage-media::after { display: none; }
}

/* Mobile: a vertical sequence of thumb-and-caption rows, with the
   connector rotated to run down between the thumbs. */
@media (max-width: 640px) {
  .ed-stages { grid-template-columns: 1fr; row-gap: 1.9rem; }
  .ed-stage {
    display: grid;
    grid-template-columns: 6.75rem minmax(0, 1fr);
    gap: 1.15rem;
    align-items: center;
  }
  .ed-stage-caption { padding-top: 0; }
  .ed-stage + .ed-stage .ed-stage-media::before {
    top: auto;
    right: auto;
    bottom: 100%;
    left: 50%;
    width: 1px;
    height: 1.9rem;
    background: linear-gradient(180deg, transparent, var(--accent));
  }
  .ed-stage + .ed-stage .ed-stage-media::after {
    top: -0.55rem;
    left: 50%;
    transform: translateX(-50%) rotate(135deg);
  }
}

/* ================================================================
   4 · FEATURE — asymmetric image-led composition
   Used for Professional Monitoring and Peace of Mind. The image
   runs wide and the copy sits in a narrow column beside it.
   ================================================================ */
.ed-feature {
  display: grid;
  grid-template-columns: minmax(0, 1.85fr) minmax(0, 1fr);
  gap: var(--ed-gap);
  align-items: center;
}
/* Flipping the order alone would leave the image in the narrow
   column, so the ratio is mirrored with it. */
.ed-feature--flip { grid-template-columns: minmax(0, 1fr) minmax(0, 1.85fr); }
.ed-feature--flip .ed-feature-media { order: 2; }
.ed-feature-media {
  position: relative;
  margin: 0;
  overflow: hidden;
  border: 1px solid var(--line-strong);
  background: var(--bg-3);
}
.ed-feature-media > .ed-ph { border: 0; }
.ed-feature-media img {
  width: 100%; height: auto;
  display: block;
}
.ed-feature-copy .ed-title { margin-bottom: 1.5rem; }
.ed-feature-points {
  list-style: none;
  margin: 1.5rem 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.7rem;
}
.ed-feature-points li {
  position: relative;
  padding-left: 1.6rem;
  font-size: 0.95rem;
  line-height: 1.6;
  color: var(--body);
}
.ed-feature-points li::before {
  content: "";
  position: absolute;
  left: 0; top: 0.6em;
  width: 8px; height: 1px;
  background: var(--accent);
}
@media (max-width: 900px) {
  .ed-feature,
  .ed-feature--flip { grid-template-columns: 1fr; }
  .ed-feature--flip .ed-feature-media { order: 0; }
}

/* Second feature in a shared band — separated by rule and space
   rather than by another full section's padding. */
.ed-feature--stacked {
  margin-top: clamp(2.5rem, 4vw, 4rem);
  padding-top: clamp(2.5rem, 4vw, 4rem);
  border-top: 1px solid var(--line-strong);
}

/* ---- Two views of one system -----------------------------------
   The band carries the monitoring team's view and the property
   owner's view. These are two positions in the same PGISR system,
   not an ordered pair, so the marker on the dividing rule below does
   that work; the kickers use the page's standard dot treatment. */
.ed-feature--stacked { position: relative; }
/* Masks the dividing rule so the marker sits in a clean break. */
.ed-feature--stacked::before {
  content: "";
  position: absolute;
  top: -1px;
  left: 50%;
  width: 2.6rem;
  height: 1.2rem;
  transform: translate(-50%, -50%);
  background: var(--bg);
}
.ed-feature--stacked::after {
  content: "";
  position: absolute;
  top: -1px;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 0; height: 0;
  border-left: 5px solid transparent;
  border-right: 5px solid transparent;
  border-top: 7px solid var(--accent);
}

/* Each view's list is literally what that party has on screen, so it
   is set as a readout panel rather than as marketing bullets. */
.ed-readout {
  gap: 0;
  margin-top: 1.6rem;
  border-top: 1px solid var(--line);
}
.ed-readout li {
  padding: 0.78rem 0 0.78rem 1.6rem;
  border-bottom: 1px solid var(--line);
  font-family: var(--font-mono);
  font-size: 0.74rem;
  line-height: 1.45;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--body);
}
.ed-readout li::before { top: 1.8em; }

/* Calmer, lighter treatment for the lifestyle beat. */
.ed-section--calm {
  background:
    radial-gradient(120% 90% at 78% 10%, rgba(42,150,136,0.07), transparent 62%),
    var(--bg);
}

/* ================================================================
   5 · APPLICATION PANELS
   Image-led panels rather than a tag list or a directory grid.
   ================================================================ */
.ed-apps {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  column-gap: clamp(1.25rem, 2.5vw, 2.5rem);
  row-gap: 1.5rem;
  margin-top: clamp(1.75rem, 3vw, 2.5rem);
}
/* Extra breathing room above the sectors-served row so it reads as
   its own beat under "How PGISR Helps" rather than a continuation
   of the numbered process steps directly above it. */
.ed-apps-divider {
  margin-top: clamp(2.5rem, 4vw, 3.5rem);
  padding-top: clamp(1.75rem, 3vw, 2.5rem);
  border-top: 1px solid var(--line);
}
/* Ledger cells — index, glyph, and name stacked together as one
   unit per column; no rules or seams, the columns alone carry the row. */
.ed-app {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
  padding: 0;
  text-decoration: none;
}
.ed-app-idx {
  margin-bottom: 0.9rem;
  font-family: var(--font-mono);
  font-size: 0.62rem;
  letter-spacing: 0.16em;
  color: var(--muted);
}
/* Outline glyphs reuse the site's existing technical icon style
   while the cards remain clearly static rather than faux controls. */
.ed-app-icon {
  display: block;
  width: clamp(1.4rem, 1.7vw, 1.75rem);
  height: clamp(1.4rem, 1.7vw, 1.75rem);
  flex: 0 0 auto;
  margin-bottom: 0.7rem;
}
/* Sits under the process steps rather than under a heading of its own,
   so the names read one notch below .ed-step p, not above it. */
.ed-app-name {
  font-family: var(--font-display);
  font-size: clamp(1rem, 1.2vw, 1.12rem);
  font-weight: 600;
  letter-spacing: -0.01em;
  line-height: 1.25;
  color: var(--ink);
  margin: 0;
}
.ed-app-note {
  font-size: 0.85rem;
  line-height: 1.5;
  color: var(--body);
  margin: 0.5rem 0 0;
}

/* ---- Wide band image under a section opener -------------------- */
.ed-band-media {
  margin: clamp(2rem, 3.5vw, 3rem) 0 0;
}
/* Homepage image bands use the requested 16:9 final-media ratio. */
.ed-band-media img,
.ed-band-media .ed-ph {
  aspect-ratio: 16 / 9;
  object-fit: cover;
  object-position: center 62%;
}

/* Feature media boxes reserve the same 16:9 frame. */
.ed-feature-media .ed-ph { aspect-ratio: 16 / 9; }

/* ---- Prominent band variant --------------------------------------
   For the one or two homepage visuals that are genuinely major
   storytelling assets (not supporting photography) — currently the
   Detect/Verify/Assess/Respond workflow visual. Taller ratio, more
   generous cap, but still short of full-screen. */
.ed-band-media--feature img,
.ed-band-media--feature .ed-ph {
  aspect-ratio: 16 / 9;
}

/* ================================================================
   5b · PROCESS STEPS — "How PGISR Helps"
   Six deliberate capabilities in a balanced editorial grid. Short
   accent rules and quiet indices provide structure without cards or
   table-like dividers.
   ================================================================ */
.ed-steps {
  list-style: none;
  margin: clamp(1.4rem, 2.4vw, 2rem) 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  grid-auto-rows: 1fr;
  gap: clamp(1.25rem, 2.2vw, 1.75rem) clamp(1.5rem, 3vw, 3rem);
}
.ed-step {
  position: relative;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-content: start;
  align-items: baseline;
  column-gap: 0.8rem;
  min-width: 0;
  min-height: 5.25rem;
  padding: 1rem 0 0;
}
.ed-step-num {
  font-family: var(--font-mono);
  font-size: 0.68rem;
  font-weight: 700;
  line-height: 1.4;
  letter-spacing: 0.1em;
  color: var(--accent);
}
.ed-step p {
  margin: 0;
  font-size: clamp(1.08rem, 1.35vw, 1.22rem);
  font-weight: 600;
  line-height: 1.35;
  color: var(--ink);
  letter-spacing: -0.01em;
}

@media (max-width: 960px) {
  .ed-steps {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 640px) {
  .ed-steps {
    grid-template-columns: 1fr;
    grid-auto-rows: auto;
    gap: 0.75rem;
    margin-top: 1.25rem;
  }
  .ed-step {
    min-height: 0;
    padding: 1rem 0 0.75rem;
  }
  /* The desktop clamp()s still land near their max here, stacking with
     the steps' own trailing space into a much bigger gap than the tight
     0.75rem rhythm used between the steps themselves. */
  .ed-apps-divider {
    margin-top: 1rem;
    padding-top: 1.5rem;
  }
}

/* ================================================================
   6 · CORE QUALITIES — typographic, no icon cards
   ================================================================ */
.ed-qualities {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 240px), 1fr));
  gap: clamp(1.5rem, 2.5vw, 2.25rem) var(--ed-gap);
  margin-top: clamp(1.75rem, 3vw, 2.5rem);
}
/* The qualities are four parallel statements, not four steps, so they
   carry no index. The rule plus this opening space is what separates
   them; it replaces the space the old counter used to occupy. */
.ed-quality {
  padding-top: 1.6rem;
  border-top: 1px solid var(--line-strong);
}
.ed-quality h3 {
  font-family: var(--font-display);
  font-size: clamp(1.3rem, 2vw, 1.7rem);
  font-weight: 700;
  letter-spacing: -0.015em;
  color: var(--ink);
  margin: 0 0 0.75rem;
}
.ed-quality p {
  font-size: 0.92rem;
  line-height: 1.65;
  color: var(--body);
  margin: 0;
}

.ed-qualities-cta {
  margin: clamp(1.75rem, 3vw, 2.5rem) 0 0;
  font-size: 0.95rem;
  line-height: 1.6;
  color: var(--body);
}
.ed-qualities-cta a {
  color: var(--ink);
  text-decoration: none;
  border-bottom: 1px solid var(--accent);
  padding-bottom: 1px;
}
.ed-qualities-cta a:hover { color: var(--accent); }

/* ================================================================
   7 · CLOSING CTA — compact horizontal band
   ================================================================ */
.ed-close {
  padding-block: clamp(2rem, 3.5vw, 2.75rem);
  border-top: 1px solid var(--line-strong);
  border-bottom: 0;
  background:
    radial-gradient(90% 70% at 50% 40%, rgba(42,150,136,0.07), transparent 70%),
    var(--bg);
}
.ed-close-band {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 1.25rem 2.5rem;
}
.ed-close-copy { max-width: 46ch; }
.ed-close-title {
  font-family: var(--font-display);
  font-size: clamp(1.4rem, 2.2vw, 1.9rem);
  font-weight: 700;
  line-height: 1.2;
  letter-spacing: -0.02em;
  color: var(--ink);
  margin: 0 0 0.4rem;
  text-wrap: balance;
}
.ed-close-lede {
  font-size: 0.95rem;
  line-height: 1.55;
  color: var(--body);
  margin: 0;
}
.ed-close-actions {
  margin-top: 0;
  display: flex;
  justify-content: center;
  flex: none;
}
@media (max-width: 700px) {
  .ed-close-band { flex-direction: column; align-items: flex-start; }
  .ed-close-actions { width: 100%; }
  .ed-close-actions .button { width: 100%; }
}

/* ================================================================
   Motion — restrained. One fade-and-rise, no parallax, no loops.
   ================================================================ */
html.anim .ed-reveal {
  opacity: 0;
  transform: translateY(18px);
  transition: opacity 0.7s cubic-bezier(0.22,1,0.36,1),
              transform 0.7s cubic-bezier(0.22,1,0.36,1);
  will-change: opacity, transform;
}
html.anim .ed-reveal.is-visible {
  opacity: 1;
  transform: none;
}

@media (prefers-reduced-motion: reduce) {
  html.anim .ed-reveal {
    opacity: 1;
    transform: none;
    transition: none;
  }
}

/* The simulation still is very wide; capping its height keeps it a
   preview rather than a second full-screen visual. */
.ed-section .deployment-preview-img {
  max-height: clamp(320px, 38vw, 520px);
  object-fit: cover;
  object-position: center top;
}
/* The placeholder standing in for that render reserves the same band,
   so approved artwork drops in without moving anything below it. */
.ed-section .deployment-preview-img.ed-ph {
  height: auto;
  min-height: 0;
  aspect-ratio: 2530 / 1373;
}

/* Application panels stack down in stages instead of jumping to one
   column, so the row never leaves a single orphan panel. */
@media (max-width: 1100px) { .ed-apps { grid-template-columns: repeat(3, minmax(0,1fr)); } }
/* Below tablet the ledger reads as a thin stacked list, so it becomes
   a 2-col grid instead, each cell marked off by a top rule rather than
   a boxed card (a full border reads as a clickable nav tile, which
   these aren't); the fifth item spans both columns rather than
   dangling alone in its own row. */
@media (max-width: 760px) {
  .ed-apps {
    grid-template-columns: repeat(2, minmax(0,1fr));
    column-gap: 0.9rem;
    row-gap: 0;
  }
  .ed-app {
    min-height: 0;
    padding: 1.1rem 0 1.3rem;
    border-top: 1px solid var(--line);
  }
  .ed-app-idx { margin-bottom: 0.6rem; }
  .ed-app-icon { margin-bottom: 0.5rem; }
  /* The divider above already draws this line for the first row —
     without this, its rule and the divider sit right on top of each
     other as two near-touching lines. */
  .ed-app:nth-child(-n+2) { border-top: none; padding-top: 0; }
  .ed-app:last-child { grid-column: 1 / -1; }
}

/* ---- Homepage band image · one live event -----------------------
   "Streaming sensor data alone reveals little" needs its visual to show
   sensing turning into action, not just a map of sensors. The artwork
   already carries an orange marker on the driveway; these marks name it
   and show the nearest sensor reacting to it. Deliberately three marks
   only — a triggered sensor, a short inward signal, and one tag — so the
   picture stays a photograph with a note on it, not a dashboard.
   Coordinates are percentages of the image, which is 16:9 in a 16:9
   frame, so object-fit crops nothing and they stay true at every width. */
.ed-band-event {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

/* The sensor that picked the event up. Sits over the existing cyan
   marker, so it reads as that node going active rather than a new one. */
.ed-band-event-sensor {
  position: absolute;
  left: 61.1%;
  top: 83%;
  width: 26px;
  height: 26px;
  margin: -13px 0 0 -13px;
  border: 1px solid rgba(224, 138, 62, 0.9);
  border-radius: 50%;
  box-shadow: 0 0 12px rgba(224, 138, 62, 0.45);
}

.ed-band-event-sensor::after {
  content: "";
  position: absolute;
  inset: -7px;
  border: 1px solid rgba(224, 138, 62, 0.5);
  border-radius: 50%;
  animation: ed-band-event-pulse 2.6s ease-out infinite;
}

/* Short run inward, toward the house and the system behind it. Stops well
   short of the building: it signals direction, it is not a wire diagram. */
.ed-band-event-link {
  position: absolute;
  left: 61.1%;
  top: 83%;
  width: 9.5%;
  height: 1px;
  transform-origin: 0 50%;
  transform: rotate(213deg);
  background: linear-gradient(90deg, rgba(224, 138, 62, 0.85), rgba(224, 138, 62, 0));
}

.ed-band-event-tag {
  position: absolute;
  left: 77.5%;
  top: 79.5%;
  display: grid;
  gap: 0.12rem;
  padding: 0.4rem 0.6rem;
  transform: translateY(-50%);
  border-left: 2px solid #e08a3e;
  background: rgba(6, 14, 21, 0.82);
  backdrop-filter: blur(3px);
  -webkit-backdrop-filter: blur(3px);
  white-space: nowrap;
}

.ed-band-event-tag b {
  color: #f4c48d;
  font-family: var(--font-mono);
  font-size: 0.6rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.ed-band-event-tag i {
  color: rgba(226, 234, 238, 0.72);
  font-family: var(--font-mono);
  font-size: 0.55rem;
  font-style: normal;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

@keyframes ed-band-event-pulse {
  0% { opacity: 0.9; transform: scale(0.72); }
  70% { opacity: 0; transform: scale(1.5); }
  100% { opacity: 0; transform: scale(1.5); }
}

/* The tag would crowd a phone-width crop; the marked sensor and its
   signal still carry the event there. */
/* The tag would crowd a phone-width crop; the marked sensor and its
   signal still carry the event there. The ring is sized down hard as well:
   at a fixed 26px it was proportionally three times larger against a
   356px-wide image than against the desktop one, which made the sensor
   louder than the event it is reacting to. */
@media (max-width: 640px) {
  .ed-band-event-tag { display: none; }
  .ed-band-event-sensor {
    width: 13px;
    height: 13px;
    margin: -6.5px 0 0 -6.5px;
    box-shadow: 0 0 7px rgba(224, 138, 62, 0.35);
  }
  .ed-band-event-sensor::after { inset: -4px; }
  .ed-band-event-link { width: 7%; }
}

@media (prefers-reduced-motion: reduce) {
  .ed-band-event-sensor::after { animation: none; }
}
