/* Products hub (/products/) — centered platform-style hero with the
   product cards fanned across the hero foot (the reserved plat-fan style),
   then one block per product with a Dashboard ⇄ End-user toggle (bright
   desktop analytics vs light phone flow).

   The dashboard side stopped being skeleton art on 2026-08-18 (Mike): each
   product now shows its own console — the real nav plus a readout built from
   three primitives (ph-dmeter tracks, ph-drow queues, ph-dscore matches) over
   a ph-dstats counter strip. Workforce is the exception that proves it: its
   console already exists as components/WorkforceSession.astro, so the hub
   renders that component rather than a copy of it. */

.p-products-hub {
  background: var(--color-background);
  color: var(--color-foreground);
}
.p-products-hub .ph-mono { font-family: var(--font-sans); }
/* kickers come from the base.css .kicker primitive (2026-07-26) */

/* ---------- hero: BRIGHT (Sofia, 2026-07-25: never dark) — centered copy,
   the end-user phone in the middle of the stage below, floating product
   cards around it ---------- */
/* exactly one viewport tall: the copy sits in the upper half, the stage
   takes what remains, and the phone crops at the fold (Sofia: the hero
   only gets the hero real estate) */
/* hero shell, copy lockup, AND ground (dot grid + corner wash + blue
   foot wash) come from the shared HubHero component (components/HubHero
   .astro + hub-hero.css, 2026-07-28 unification with /platform/) — this
   page keeps ONLY the phone/orbit stage. The page's own drifting fold
   aurora is retired; the shared foot wash paints the fold now. */
/* the stage: the product fan (Sofia 2026-08-13, the reserved plat-fan card
   style — platform.css § plat-fan, removed from /platform/ 2026-08-06 and
   earmarked for reuse): the eight product cards spread across the hero
   foot like a held hand — white cards, icon chip + name over the white
   fade, the product glyph on a quiet dotted canvas as the artwork.
   --fan-i runs -3.5..3.5 from the markup; distance from center drives
   rotation, drop and stacking (--fan-z). Hovering lifts a card upright.
   The 2026-07-30 gradient-tile arc lives in git. */
.p-products-hub .ph-hero { overflow: hidden; }
/* pinned to the hero's foot and cropped mid-card (the plat-fan crop): the
   container shows ~62% of the card's height (cards are 4:5, so height =
   1.25 × width) and hides the rest — card bottoms never appear */
.p-products-hub .ph-hero__fan {
  --fan-w: clamp(200px, 16.5vw, 260px);
  display: flex;
  justify-content: center;
  align-items: flex-start;
  width: 100%;
  flex: none;
  margin-top: auto;
  padding-top: 48px;
  height: calc(var(--fan-w) * 1.25 * 0.74 + 48px);
  overflow: hidden;
}
.p-products-hub .ph-fan__card {
  position: relative;
  display: block;
  width: var(--fan-w);
  aspect-ratio: 4 / 5;
  margin-inline: -12px;
  overflow: hidden;
  border-radius: 20px;
  background: var(--color-white);
  text-align: left;
  text-decoration: none;
  color: inherit;
  z-index: var(--fan-z);
  /* thin grey stroke so overlapping white cards separate (Sofia 2026-08-18) */
  box-shadow: inset 0 0 0 1px var(--color-grey-200);
  transform-origin: 50% 100%;
  transform: rotate(calc(var(--fan-i) * 3.2deg))
    translateY(calc(var(--fan-i) * var(--fan-i) * 9px));
  transition: transform 0.34s var(--ease-out-expo), box-shadow 0.34s ease;
}
.p-products-hub .ph-fan__card:hover,
.p-products-hub .ph-fan__card:focus-visible {
  z-index: 10;
  transform: rotate(0deg)
    translateY(calc(var(--fan-i) * var(--fan-i) * 9px - 14px));
  box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--fan-tone, var(--color-blue)) 40%, transparent);
}
/* title bar floating over the artwork, fading white → transparent below
   (the plat-fan dramatic fade, shortened for the narrower card) */
.p-products-hub .ph-fan__head {
  position: absolute;
  inset: 0 0 auto 0;
  z-index: 2;
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 15px 14px 84px;
  background: linear-gradient(
    180deg,
    var(--color-white) 0%,
    var(--color-white) 30%,
    color-mix(in oklab, var(--color-white) 92%, transparent) 50%,
    color-mix(in oklab, var(--color-white) 72%, transparent) 66%,
    color-mix(in oklab, var(--color-white) 45%, transparent) 80%,
    color-mix(in oklab, var(--color-white) 20%, transparent) 91%,
    transparent 100%
  );
  pointer-events: none;
}
.p-products-hub .ph-fan__icon {
  display: inline-flex;
  flex-shrink: 0;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border-radius: 8px;
  background: color-mix(in oklab, var(--fan-tone, var(--color-blue)) 12%, var(--color-white));
  color: var(--fan-tone, var(--color-blue));
}
.p-products-hub .ph-fan__icon .ds-icon { width: 15px; height: 15px; }
.p-products-hub .ph-fan__name {
  font-size: var(--fs-sm);
  font-weight: 500;
  line-height: 1.25;
  color: var(--color-black);
}
/* the artwork: the shared hub dot grid on a ground washed with the card's
   tone (deepest at the foot, releasing upward into the white fade), the
   product glyph in the tone centered in the visible band; hovering zooms
   it gently */
.p-products-hub .ph-fan__media {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  /* full-white ground, no tone gradient, no dot texture (Sofia 2026-08-18)
     — the thin grey stroke on the card carries the separation */
  background: var(--color-white);
  transform-origin: 50% 62%;
  transition: transform 0.5s var(--ease-out-expo);
}
.p-products-hub .ph-fan__glyph {
  width: 64px;
  height: 64px;
  color: var(--fan-tone, var(--color-blue));
}
.p-products-hub .ph-fan__card:hover .ph-fan__media { transform: scale(1.05); }
@media (prefers-reduced-motion: reduce) {
  .p-products-hub .ph-fan__media { transition: none; }
  .p-products-hub .ph-fan__card:hover .ph-fan__media { transform: none; }
}
/* narrow screens: the fan folds into a tidy two-column grid — fully
   visible, so the crop and the bottom-pinning come off */
@media (max-width: 1099px) {
  .p-products-hub .ph-hero { height: auto; min-height: 100svh; }
  .p-products-hub .ph-hero .hub-hero__inner { padding-bottom: 48px; }
  .p-products-hub .ph-hero__fan {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 10px;
    margin-top: 40px;
    padding: 0 20px;
    height: auto;
    overflow: visible;
  }
  .p-products-hub .ph-fan__card {
    width: auto;
    aspect-ratio: 16 / 10;
    margin-inline: 0;
    transform: none;
  }
  .p-products-hub .ph-fan__card:hover { transform: none; }
  .p-products-hub .ph-fan__glyph { width: 44px; height: 44px; }
}

/* ---------- product blocks with the Dashboard ⇄ End-user toggle ---------- */
.p-products-hub .ph-products {
  border-top: 1px solid var(--color-border-light);
  background: var(--color-background);
}
.p-products-hub .ph-products__inner {
  margin-inline: auto;
  max-width: var(--container-large);
  padding: var(--space-section-sm) var(--space-inline);
}
@media (min-width: 768px) { .p-products-hub .ph-products__inner { padding-block: var(--space-section); } }
@media (min-width: 1024px) { .p-products-hub .ph-products__inner { padding-inline: 24px; } }
.p-products-hub .ph-products__title {
  margin-top: 16px;
  font-family: var(--font-display);
  font-weight: 500;
  letter-spacing: var(--track-tighter);
  font-size: clamp(32px, 3.6vw, 52px);
  line-height: 1.05;
  color: var(--color-black);
}
/* no max-width cap: the one-sentence intro stays on a single line */
.p-products-hub .ph-products__intro {
  margin-top: 16px;
  font-size: var(--fs-body);
  line-height: var(--leading-body);
  color: var(--color-grey-on-white);
}
/* carousel nav: a vertical selector rail beside the card on desktop —
   the product list can keep growing without fighting for one row (Sofia,
   2026-07-24). Each tab is an icon + full product name (icons alone don't
   identify the products for a new visitor). Below 1024px the rail folds
   back into a wrapping pill row above the card. */
.p-products-hub .ph-products__layout { margin-top: 40px; }
@media (min-width: 1024px) {
  .p-products-hub .ph-products__layout {
    display: grid;
    grid-template-columns: 300px minmax(0, 1fr);
    gap: 40px;
    align-items: start;
  }
  .p-products-hub .ph-carousel { margin-top: 0; }
}
.p-products-hub .ph-products__rail {
  display: flex;
  flex-direction: column;
  gap: 18px;
}
.p-products-hub .ph-products__tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.p-products-hub .ph-products__tab {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  height: 46px;
  padding: 0 16px 0 13px;
  border: 1px solid var(--color-border-light);
  border-radius: 13px;
  background: var(--color-white);
  color: var(--color-grey-on-white);
  cursor: pointer;
  transition: color 0.2s ease, border-color 0.2s ease, background-color 0.2s ease, transform 0.2s ease;
}
.p-products-hub .ph-products__tab:hover {
  color: var(--color-blue);
  transform: translateY(-2px);
}
.p-products-hub .ph-products__tab.is-active {
  border-color: var(--color-blue);
  color: var(--color-blue);
}
/* desktop rail: the pills become flush rows in one column */
@media (min-width: 1024px) {
  .p-products-hub .ph-products__tabs {
    flex-direction: column;
    align-items: stretch;
    gap: 4px;
  }
  .p-products-hub .ph-products__tab {
    height: auto;
    justify-content: flex-start;
    padding: 12px 14px;
    border-color: transparent;
    background: none;
    border-radius: 12px;
    text-align: left;
  }
  .p-products-hub .ph-products__tab:hover {
    background: var(--color-grey-100);
    transform: none;
  }
  .p-products-hub .ph-products__tab.is-active {
    border-color: var(--color-blue);
    background: var(--color-white);
  }
  .p-products-hub .ph-products__ctrls { padding-left: 14px; }
}
.p-products-hub .ph-products__tab-icon {
  flex: none;
  width: 20px;
  height: 20px;
}
.p-products-hub .ph-products__tab-label {
  font-size: var(--fs-sm);
  font-weight: 500;
  line-height: 1;
  white-space: nowrap;
}
.p-products-hub .ph-products__ctrls {
  display: flex;
  align-items: center;
  gap: 10px;
}
.p-products-hub .ph-products__count {
  margin-right: 4px;
  font-size: var(--fs-xs);
  letter-spacing: var(--track-wide);
  font-variant-numeric: tabular-nums;
  color: var(--color-grey-on-white);
}
.p-products-hub .ph-products__arrow {
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  padding: 0;
  border: 1px solid var(--color-border-light);
  border-radius: 50%;
  background: var(--color-white);
  color: var(--color-grey-500);
  cursor: pointer;
  transition: background 0.2s ease, color 0.2s ease, border-color 0.2s ease;
}
.p-products-hub .ph-products__arrow:hover {
  background: var(--color-black);
  border-color: var(--color-black);
  color: var(--color-white);
}

/* carousel: one product card visible at a time. The top margin exists only
   below 1024px (rail folded above the card); on desktop this rule would
   outrank the grid layout's margin-top: 0 (same specificity, later in the
   file) and push the card 20px below the rail's first button. */
@media (max-width: 1023px) {
  .p-products-hub .ph-carousel { margin-top: 20px; }
}
.p-products-hub .ph-prod {
  display: none;
  border: 1px solid var(--color-border-light);
  border-radius: 20px;
  background: var(--color-grey-50);
  padding: 28px 24px;
}
.p-products-hub .ph-prod.is-active {
  display: flex;
  flex-direction: column;
  gap: 22px;
  animation: ph-pane-in 0.35s ease both;
}
@media (min-width: 1024px) {
  .p-products-hub .ph-prod.is-active { padding: 32px 36px 36px; }
}
@media (prefers-reduced-motion: reduce) {
  .p-products-hub .ph-prod.is-active { animation: none; }
}
/* header row: description left, view toggle right; the visual below gets
   the full card width */
.p-products-hub .ph-prod__head {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px 32px;
}
.p-products-hub .ph-prod__intro { min-width: 0; }
.p-products-hub .ph-prod__line {
  max-width: 58ch;
  font-size: var(--fs-body);
  line-height: var(--leading-body);
  color: var(--color-foreground);
}
.p-products-hub .ph-prod__explore {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-top: 10px;
  font-size: var(--fs-sm);
  letter-spacing: var(--track-wide);
  color: var(--color-black);
  text-decoration: none;
}
.p-products-hub .ph-prod__explore svg { transition: transform 0.2s ease; }
.p-products-hub .ph-prod__explore:hover { color: var(--color-blue); }
.p-products-hub .ph-prod__explore:hover svg { transform: translate(2px, -2px); }

/* stage: toggle pill + the two panes. Both panes share one height so the
   Dashboard ⇄ End-user toggle never jumps; the height is set by the
   end-user side, which is portrait (the end user is on a phone). */
.p-products-hub .ph-prod__stage { min-width: 0; --ph-stage-h: 512px; }
.p-products-hub .ph-prod__toggle {
  display: inline-flex;
  gap: 4px;
  padding: 4px;
  border: 1px solid var(--color-border-light);
  border-radius: 999px;
  background: var(--color-background);
}
.p-products-hub .ph-prod__mode {
  padding: 7px 16px;
  border: 0;
  border-radius: 999px;
  background: none;
  font-size: var(--fs-xs);
  letter-spacing: var(--track-wide);
  color: var(--color-grey-on-white);
  cursor: pointer;
  transition: background 0.2s ease, color 0.2s ease;
}
.p-products-hub .ph-prod__mode.is-active {
  background: var(--color-black);
  color: var(--color-white);
}
.p-products-hub .ph-pane { display: none; }
.p-products-hub .ph-pane.is-active { display: block; animation: ph-pane-in 0.35s ease both; }
@keyframes ph-pane-in {
  from { opacity: 0; transform: translateY(8px); }
  to { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .p-products-hub .ph-pane.is-active { animation: none; }
}

/* skeleton primitive (light grounds; the dash overrides the tint) */
.p-products-hub .ph-skel {
  display: block;
  height: 9px;
  border-radius: 999px;
  background: var(--color-grey-100);
}
.p-products-hub .ph-skel--w45 { width: 45%; }
.p-products-hub .ph-skel--w50 { width: 50%; }
.p-products-hub .ph-skel--w60 { width: 60%; }
.p-products-hub .ph-skel--w65 { width: 65%; }
.p-products-hub .ph-skel--w70 { width: 70%; }
.p-products-hub .ph-skel--w80 { width: 80%; }
.p-products-hub .ph-skel--center { margin-inline: auto; }

/* ---------- dashboard pane: bright desktop console (the real dashboard
   is light — Sofia, 2026-07-25: never the dark version) ---------- */
.p-products-hub .ph-dash {
  display: flex;
  flex-direction: column;
  /* height, not min-height: with only a minimum, a flex child has no fixed
     box to divide, so the ssv's images sized themselves and the window grew
     past the stage (540 instead of 512) — and the readouts that ran long
     pushed it to 521. A definite height gives every readout a real box to
     fit into, and keeps the six windows identical. */
  height: var(--ph-stage-h);
  overflow: hidden;
  border: 1px solid var(--color-border-light);
  border-radius: 16px;
  background: var(--color-white);
  box-shadow: none;
}
.p-products-hub .ph-dash__bar {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 12px 16px;
  border-bottom: 1px solid var(--color-border-light);
}
.p-products-hub .ph-dash__dot {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--color-grey-200);
}
.p-products-hub .ph-dash__crumb {
  margin-left: 10px;
  font-size: var(--fs-xs);
  letter-spacing: var(--track-wide);
  color: var(--color-grey-400);
}
.p-products-hub .ph-dash__body {
  display: grid;
  grid-template-columns: 132px minmax(0, 1fr);
  gap: 20px;
  flex: 1;
  min-height: 300px;
  padding: 20px;
}
@media (max-width: 639px) {
  /* 512, not 448: the taller readouts (five agent/match rows, the data-source
     table with its decision foot) measured 509 here, so the card grew past
     its own stage and the panel jumped when you switched products. The flow
     tab just gains air around the phone. */
  .p-products-hub .ph-prod__stage { --ph-stage-h: 512px; }
  .p-products-hub .ph-dash__body { grid-template-columns: minmax(0, 1fr); min-height: 260px; }
  .p-products-hub .ph-dash__side { display: none; }
  .p-products-hub .ph-phone { min-height: 392px; }
}
/* ---- the product's own nav (2026-08-18) ----
   Skeleton lines read as "a dashboard, unspecified"; the real consoles on
   /products/deepsight/ and in WorkforceSession draw the nav, so this one does
   too. The active row is the page the readout beside it belongs to. */
.p-products-hub .ph-dash__side {
  display: flex;
  flex-direction: column;
  gap: 16px;
  padding-right: 16px;
  border-right: 1px solid var(--color-border-light);
}
.p-products-hub .ph-dash__brand { display: flex; align-items: center; }
.p-products-hub .ph-dash__logo { display: block; width: 62px; height: auto; }
.p-products-hub .ph-dash__nav { display: flex; flex-direction: column; gap: 2px; }
.p-products-hub .ph-dash__navitem {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 8px;
  border-radius: var(--radius-sm);
  font-size: 11px;
  line-height: 1.2;
  color: var(--color-grey-400);
  white-space: nowrap;
}
.p-products-hub .ph-dash__navitem.is-on {
  background: var(--color-blue-100);
  color: var(--color-blue);
  font-weight: 500;
}
.p-products-hub .ph-dash__navicon { flex: none; width: 13px; height: 13px; }

/* ---- readout: the panel head, then one of four bodies ---- */
/* min-height:0 as well as min-width: a grid item defaults to min-height:auto,
   so the ssv's images pushed the column past the body's 20px padding-bottom
   and the document card sat flush on the window's floor (Mike 2026-08-18) */
.p-products-hub .ph-dash__main { display: flex; flex-direction: column; min-width: 0; min-height: 0; }
.p-products-hub .ph-dhead {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  padding-bottom: 12px;
  border-bottom: 1px solid var(--color-border-light);
}
.p-products-hub .ph-dhead__title {
  font-size: 13px;
  font-weight: 500;
  color: var(--color-black);
}
.p-products-hub .ph-dhead__meta { font-style: normal; font-size: 11px; color: var(--color-grey-400); }
.p-products-hub .ph-dhead__meta--live {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  color: var(--color-blue);
}
.p-products-hub .ph-dhead__meta--live::before {
  content: "";
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--color-blue);
}
/* ---- Workforce renders the shared WorkforceSession console instead of a
   ph-dash variation (Mike 2026-08-18). Three scoped overrides fit it to this
   stage; the component and its two other surfaces are untouched:
   (1) it fills the pane instead of capping at its own 540px,
   (2) the ambient float is dropped — this stage does not float,
   (3) the re-auth phone is hidden, because the End-user flow tab is the
       phone. Same move /platform/fraud-analytics/ makes on the walk stage. */
/* Round 2 (Mike 2026-08-18, two screenshots side by side): "que el tamaño del
   browser y el estilo del browser estén como en Deepsight… en Workforce está
   muy chiquito". So the component no longer brings its own window — it is
   mounted INSIDE the same .ph-dash chrome every other product uses (three
   dots + a text crumb, full pane width), with its own bar and frame off.
   Its type was drawn for a 540px window (nav 7px, rows 6.5px, pills 5px) and
   is re-scaled here to the ph-dash ladder so the six read as one system. */
/* the height chain, so the nav's divider runs to the floor of the window and
   the account foot (margin-top:auto in the component) actually lands at the
   bottom: ph-dash → ph-wfs → wfs-win → wfs-win__body must each pass the
   stretch down. .wfs-stage is a plain block in the component, which is where
   the chain broke — the window sat at its natural height with the divider
   stopping mid-pane (Mike 2026-08-18). */
.p-products-hub .ph-wfs { display: flex; flex: 1; width: 100%; min-height: 0; animation: none; }
.p-products-hub .ph-wfs .wfs-win {
  width: 100%;
  flex: 1;
  border: 0;
  border-radius: 0;
}
.p-products-hub .ph-wfs .wfs-win__bar { display: none; }
.p-products-hub .ph-wfs .wfs-win__body { flex: 1; min-height: 0; }
.p-products-hub .ph-wfs .wfs-phone { display: none; }
/* 20px of padding at the foot, which is what the divider runs down to now
   that the account block is gone */
.p-products-hub .ph-wfs .wfs-win__side { flex: 0 0 168px; padding: 20px 12px; }
.p-products-hub .ph-wfs .wfs-side__item { font-size: 11px; gap: 8px; padding: 6px 8px; border-radius: var(--radius-sm); }
/* the active row takes the tinted treatment the other five consoles use
   (blue-100 ground, blue label) instead of the component's solid blue-500
   bar — Mike 2026-08-18, so the nav reads the same across the six */
.p-products-hub .ph-wfs .wfs-side__item--on {
  background: var(--color-blue-100);
  color: var(--color-blue);
}
.p-products-hub .ph-wfs .wfs-side__ico { width: 13px; height: 13px; }
.p-products-hub .ph-wfs .wfs-side__logo { width: 62px; }
.p-products-hub .ph-wfs .wfs-side__product { font-size: 13px; }
/* the account foot comes off here: none of the other five consoles carry one,
   and the nav reads as one system without it (Mike 2026-08-18) */
.p-products-hub .ph-wfs .wfs-side__user { display: none; }
/* the readout: same steps as ph-dhead / ph-drow / ph-dpill */
.p-products-hub .ph-wfs .wfs-win__title { padding: 20px 20px 0; font-size: 13px; }
.p-products-hub .ph-wfs .wfs-win__profile { gap: 16px; padding: 16px 20px 18px; }
.p-products-hub .ph-wfs .wfs-win__avatar { width: 60px; height: 60px; }
.p-products-hub .ph-wfs .wfs-win__pill { padding: 3px 9px; font-size: 10px; font-weight: 500; }
.p-products-hub .ph-wfs .wfs-win__namebar { width: 148px; height: 10px; }
.p-products-hub .ph-wfs .wfs-win__metabar { width: 180px; height: 10px; }
.p-products-hub .ph-wfs .wfs-win__metabar--short { width: 116px; }
.p-products-hub .ph-wfs .wfs-win__list { padding: 0 20px 20px; }
.p-products-hub .ph-wfs .wfs-list__head { padding: 8px 10px; font-size: 10px; letter-spacing: 0; }
.p-products-hub .ph-wfs .wfs-list__row { padding: 11px 10px; gap: 12px; }
.p-products-hub .ph-wfs .wfs-list__ava { width: 26px; height: 26px; }
.p-products-hub .ph-wfs .wfs-list__ico { width: 13px; height: 13px; }
.p-products-hub .ph-wfs .wfs-list__who { gap: 10px; }
.p-products-hub .ph-wfs .wfs-list__name { font-size: 12px; font-weight: 500; }
.p-products-hub .ph-wfs .wfs-list__cell { font-size: 11px; }
.p-products-hub .ph-wfs .wfs-list__pill { padding: 3px 9px; font-size: 10px; font-weight: 500; letter-spacing: 0; }
/* the fifth row is not hidden here — the hub passes the component a four-row
   queue instead (Mike 2026-08-18), so the other two pages keep all five */

/* ---- ssv: the Deepsight panel of the Single Session View (Mike 2026-08-18).
   Verdict summary on the header line, then the selfie ⇄ document comparison
   beside the two check groups. Same 2-column split the product ships. ---- */
.p-products-hub .ph-dverdicts { display: flex; align-items: center; gap: 8px; }
.p-products-hub .ph-dpill--dot { display: inline-flex; align-items: center; gap: 6px; }
.p-products-hub .ph-dpill--dot::before {
  content: "";
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentcolor;
}
.p-products-hub .ph-ssv {
  display: grid;
  grid-template-columns: 248px minmax(0, 1fr);
  align-items: stretch;
  gap: 24px;
  flex: 1;
  min-height: 0;
  padding-top: 12px;
}
/* the session view sets the two captures side by side, but its card is far
   taller than this pane: at 978×512 the check column runs ~380px and the
   shots ~210, which left the left half mostly air. Stacking them — selfie
   over document — fills the same height and keeps the comparison reading
   top-to-bottom. */
/* the shots take exactly the height the check column sets, so the two halves
   always end on the same line — a fixed aspect-ratio here made the left column
   the taller one and pushed the window past its 512px stage */
.p-products-hub .ph-ssv__shots { display: flex; flex-direction: column; gap: 10px; min-height: 0; }
.p-products-hub .ph-shot { display: flex; flex-direction: column; gap: 6px; min-height: 0; }
/* the selfie was the taller of the two and left the document card with no
   room; evening them out (and cropping tighter on the face) gives the licence
   its full card back */
.p-products-hub .ph-shot:first-child { flex: 1; }
.p-products-hub .ph-shot:last-child { flex: 1; }
.p-products-hub .ph-shot__label {
  font-style: normal;
  font-size: 10px;
  font-weight: 500;
  color: var(--color-grey-400);
}
/* the frame holds the capture and the analysis mesh over it */
.p-products-hub .ph-shot__frame { position: relative; display: flex; flex: 1; min-height: 0; }
.p-products-hub .ph-shot__img {
  display: block;
  flex: 1;
  width: 100%;
  min-height: 0;
  object-fit: cover;
  /* the crop holds the face rather than the middle of the frame */
  object-position: 50% 26%;
  border-radius: var(--radius-md);
  border: 1px solid var(--color-border-light);
  background: var(--color-grey-50);
}
/* the licence is read, not cropped — it sits whole on the grey plate the way a
   document viewer shows it; the selfie fills its frame */
.p-products-hub .ph-shot--doc .ph-shot__img { object-fit: contain; padding: 8px; }

/* the analysis mesh: translucent blue nodes wired together over what was read.
   Non-uniform scaling is deliberate — the viewBox is 0..100 on both axes with
   preserveAspectRatio="none", so the nodes track the shot at any size rather
   than drifting off the face when the pane reflows. */
.p-products-hub .ph-mesh {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}
.p-products-hub .ph-mesh__link {
  stroke: var(--color-blue);
  stroke-width: 0.4;
  opacity: 0.42;
  vector-effect: non-scaling-stroke;
}
.p-products-hub .ph-mesh__node { fill: var(--color-blue); opacity: 0.62; }
.p-products-hub .ph-ssv__checks { display: flex; flex-direction: column; gap: 10px; min-height: 0; }
.p-products-hub .ph-group {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--color-border-light);
  border-radius: var(--radius-md);
  overflow: hidden;
}
.p-products-hub .ph-group__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 9px 14px;
  border-bottom: 1px solid var(--color-border-light);
}
.p-products-hub .ph-group__head b { font-size: 12px; font-weight: 500; color: var(--color-black); }
.p-products-hub .ph-group__sub {
  padding: 5px 14px;
  background: var(--color-grey-50);
  font-style: normal;
  font-size: 10px;
  font-weight: 500;
  color: var(--color-grey-400);
}
.p-products-hub .ph-check {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 6px 14px;
}
.p-products-hub .ph-check + .ph-check { border-top: 1px solid var(--color-border-light); }
.p-products-hub .ph-check__label { font-size: 11px; font-weight: 400; color: var(--color-grey-500); }
/* verdict reads as a dot + word, not a pill — the product's own treatment */
.p-products-hub .ph-check__verdict {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-style: normal;
  font-size: 11px;
  color: var(--color-grey-500);
  white-space: nowrap;
}
.p-products-hub .ph-check__verdict::before {
  content: "";
  width: 6px;
  height: 6px;
  border-radius: 50%;
}
.p-products-hub .ph-check__verdict--green::before { background: var(--color-green-500); }
.p-products-hub .ph-check__verdict--red::before { background: var(--color-red-brand); }

/* ---- agents: the Agents console lifted from /use-cases/agentic-identity/
   (Mike 2026-08-18). Same parts as that page's hero — tabs, the owner card
   wired by dashed leads to its scoped agents, the delegation footer — plus
   step 01 of its walk, the card that splits a session into a human lane and
   a detected agent lane. Its own .at-* sheet is not loaded on this route, so
   the rules are restated here at this pane's scale. ---- */
.p-products-hub .ph-ag { display: flex; flex-direction: column; flex: 1; min-height: 0; padding-top: 14px; }
.p-products-hub .ph-ag__ico { width: 11px; height: 11px; flex: none; }
.p-products-hub .ph-ag__tabs {
  display: flex;
  gap: 20px;
  padding-bottom: 10px;
  border-bottom: 1px solid var(--color-border-light);
}
.p-products-hub .ph-ag__tabs i {
  font-style: normal;
  font-size: 11px;
  color: var(--color-grey-400);
}
.p-products-hub .ph-ag__tabs i.is-on {
  position: relative;
  color: var(--color-blue);
  font-weight: 500;
}
.p-products-hub .ph-ag__tabs i.is-on::after {
  content: "";
  position: absolute;
  inset: auto 0 -11px 0;
  height: 2px;
  border-radius: 2px;
  background: var(--color-blue);
}
.p-products-hub .ph-ag__graph {
  display: grid;
  grid-template-columns: minmax(0, 150px) 64px minmax(0, 1fr);
  align-items: center;
  gap: 0;
  padding: 16px 0;
}
.p-products-hub .ph-ag__owner {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  padding: 14px 10px;
  border: 1px solid var(--color-border-light);
  border-radius: var(--radius-md);
  background: var(--color-white);
}
.p-products-hub .ph-ag__owner-av {
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: var(--color-blue-100);
  font-style: normal;
  font-family: var(--font-display);
  font-size: 13px;
  font-weight: 600;
  color: var(--color-blue);
}
.p-products-hub .ph-ag__owner-name { font-size: 12px; font-weight: 500; color: var(--color-black); }
.p-products-hub .ph-ag__owner-check {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-style: normal;
  font-size: 10px;
  color: var(--color-green-600);
}
/* the leads are alive on the source page and they are alive here: the dash
   pattern flows toward the agent, and a packet runs the path now and then —
   same two animations as agentic-trust.css (at-link-flow / at-packet) */
.p-products-hub .ph-ag__links { position: relative; align-self: stretch; }
.p-products-hub .ph-ag__links svg { display: block; width: 100%; height: 100%; }
.p-products-hub .ph-ag__link {
  stroke: var(--color-blue);
  stroke-width: 1.5;
  stroke-dasharray: 4 4;
  fill: none;
  animation: ph-ag-flow 1.6s linear infinite;
}
.p-products-hub .ph-ag__link.is-wait { stroke: var(--color-blue-200); }
.p-products-hub .ph-ag__packet {
  position: absolute;
  top: 0;
  left: 0;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--color-blue);
  offset-rotate: 0deg;
  opacity: 0;
  animation: ph-ag-packet 6s ease-in-out 0.8s infinite;
}
.p-products-hub .ph-ag__packet:nth-of-type(2) { animation-delay: 3.8s; }
@keyframes ph-ag-flow {
  to { stroke-dashoffset: -16; }
}
@keyframes ph-ag-packet {
  0% { offset-distance: 0%; opacity: 0; }
  6% { opacity: 1; }
  30% { opacity: 1; }
  36% { offset-distance: 100%; opacity: 0; }
  100% { offset-distance: 100%; opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .p-products-hub .ph-ag__link { animation: none; }
  .p-products-hub .ph-ag__packet { display: none; }
}
.p-products-hub .ph-ag__agents { display: flex; flex-direction: column; gap: 8px; }
.p-products-hub .ph-ag__agent {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 12px;
  border: 1px solid var(--color-border-light);
  border-radius: var(--radius-md);
  background: var(--color-white);
}
.p-products-hub .ph-ag__agent-av {
  display: grid;
  place-items: center;
  width: 22px;
  height: 22px;
  flex: none;
  border-radius: 50%;
  background: var(--color-blue-100);
  color: var(--color-blue);
}
.p-products-hub .ph-ag__agent-txt { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.p-products-hub .ph-ag__agent-txt b { font-size: 11px; font-weight: 500; color: var(--color-black); }
.p-products-hub .ph-ag__agent-txt em { font-style: normal; font-size: 10px; color: var(--color-grey-400); }
.p-products-hub .ph-ag__agent-dot {
  width: 6px;
  height: 6px;
  margin-left: auto;
  flex: none;
  border-radius: 50%;
  background: var(--color-green-500);
}
.p-products-hub .ph-ag__agent.is-wait .ph-ag__agent-dot { background: var(--color-yellow-500); }
/* step 01 of the walk: human lane vs detected-agent lane */
.p-products-hub .ph-ag__detect {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 12px;
  border: 1px solid var(--color-border-light);
  border-radius: var(--radius-md);
  background: color-mix(in oklab, var(--color-grey-50) 60%, var(--color-white));
}
.p-products-hub .ph-ag__detect-head {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 11px;
  font-weight: 500;
  color: var(--color-black);
}
.p-products-hub .ph-ag__lane {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 7px 10px;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  background: var(--color-white);
}
.p-products-hub .ph-ag__lane.is-flag {
  border-color: var(--color-blue-200);
  background: var(--color-blue-100);
}
.p-products-hub .ph-ag__lane-glyph {
  display: grid;
  place-items: center;
  width: 20px;
  height: 20px;
  flex: none;
  border-radius: 50%;
  background: var(--color-white);
  color: var(--color-grey-400);
}
.p-products-hub .ph-ag__lane.is-flag .ph-ag__lane-glyph { color: var(--color-blue); }
.p-products-hub .ph-ag__lane-label { font-size: 11px; font-weight: 400; color: var(--color-grey-500); }
.p-products-hub .ph-ag__lane-pill {
  margin-left: auto;
  padding: 2px 8px;
  border-radius: 999px;
  background: var(--color-grey-50);
  font-style: normal;
  font-size: 10px;
  font-weight: 500;
  color: var(--color-grey-400);
}
.p-products-hub .ph-ag__lane-pill.is-accent {
  background: color-mix(in oklab, var(--color-blue-200) 55%, var(--color-white));
  color: var(--color-blue);
}
.p-products-hub .ph-ag__foot {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-top: auto;
  padding-top: 12px;
  font-size: 10px;
  color: var(--color-grey-400);
}

/* ---- ndv: the single-session view for a product with no document. Same
   furniture as the age read — score, name bar, reviewer actions — but the ID
   plate the console usually shows beside the selfie is simply absent, and the
   middle result card reports data sources instead of documents. ---- */
.p-products-hub .ph-ndv { display: flex; flex-direction: column; flex: 1; min-height: 0; gap: 18px; padding-top: 18px; }
.p-products-hub .ph-ndv__ico { width: 13px; height: 13px; flex: none; }
.p-products-hub .ph-ndv__top {
  display: flex;
  align-items: center;
  gap: 20px;
  padding-bottom: 18px;
  border-bottom: 1px solid var(--color-border-light);
}
.p-products-hub .ph-ndv__who { display: flex; flex-direction: column; align-items: flex-start; gap: 14px; flex: 1; min-width: 0; }
.p-products-hub .ph-ndv__who .ph-age__score b { color: var(--color-green-600); }
/* the two capture slots sit on one baseline, each with its own label */
.p-products-hub .ph-ndv__shots { display: flex; align-items: flex-start; gap: 14px; flex: none; }
.p-products-hub .ph-ndv__shot { display: flex; flex-direction: column; align-items: center; gap: 8px; }
.p-products-hub .ph-ndv__shot em { font-style: normal; font-size: 10px; color: var(--color-grey-400); }
.p-products-hub .ph-ndv__face {
  display: block;
  width: 84px;
  height: 84px;
  border-radius: 50%;
  object-fit: cover;
  border: 1px solid var(--color-border-light);
  background: var(--color-grey-50);
}
/* the ID slot the console always draws — held open and empty, because this
   product never asks for a document */
.p-products-hub .ph-ndv__plate {
  display: grid;
  place-items: center;
  width: 118px;
  height: 84px;
  border-radius: var(--radius-md);
  background: color-mix(in oklab, var(--color-grey-100) 70%, var(--color-white));
  font-style: normal;
  font-size: 10px;
  color: var(--color-grey-400);
}
.p-products-hub .ph-ndv__selfie { display: flex; flex-direction: column; align-items: center; gap: 8px; flex: none; }
.p-products-hub .ph-ndv__selfie img {
  display: block;
  width: 84px;
  height: 84px;
  border-radius: 50%;
  object-fit: cover;
  border: 1px solid var(--color-border-light);
  background: var(--color-grey-50);
}
.p-products-hub .ph-ndv__selfie em { font-style: normal; font-size: 10px; color: var(--color-grey-400); }
.p-products-hub .ph-ndv__cards { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; }
.p-products-hub .ph-ndv__card {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 8px;
  padding: 14px 16px;
  border: 1px solid var(--color-border-light);
  border-radius: var(--radius-md);
}
.p-products-hub .ph-ndv__card-label {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 10px;
  color: var(--color-grey-400);
}
.p-products-hub .ph-ndv__card-label .ds-icon { color: var(--color-green-600); }
.p-products-hub .ph-ndv__card-val {
  font-family: var(--font-display);
  font-size: 17px;
  font-weight: 600;
  line-height: 1.15;
  letter-spacing: var(--track-tight);
  color: var(--color-green-600);
}
/* document information: present, and empty on purpose */
.p-products-hub .ph-ndv__doc {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-top: auto;
  padding-top: 14px;
  border-top: 1px solid var(--color-border-light);
}
.p-products-hub .ph-ndv__doc-head { display: flex; align-items: center; gap: 14px; }
.p-products-hub .ph-ndv__doc-head b { font-size: 11px; font-weight: 500; color: var(--color-black); }
.p-products-hub .ph-ndv__doc-rows { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 10px; }
.p-products-hub .ph-ndv__doc-row {
  display: flex;
  flex-direction: column;
  gap: 3px;
  padding: 8px 12px;
  border-radius: var(--radius-sm);
  background: color-mix(in oklab, var(--color-grey-50) 60%, var(--color-white));
}
.p-products-hub .ph-ndv__doc-row b { font-size: 10px; font-weight: 400; color: var(--color-grey-400); }
.p-products-hub .ph-ndv__doc-row i { font-style: normal; font-size: 11px; font-weight: 500; color: var(--color-grey-500); }
.p-products-hub .ph-ndv__doc-row i.is-ok { color: var(--color-green-600); }
/* the two values the user actually supplied read as data; the rest read as
   the absences they are */
.p-products-hub .ph-ndv__doc-row i.is-filled { font-weight: 600; color: var(--color-black); }

/* the four registries the decision leaned on */
.p-products-hub .ph-ndv__sources { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; margin-left: auto; }
.p-products-hub .ph-ndv__sources em { font-style: normal; font-size: 10px; color: var(--color-grey-400); }
.p-products-hub .ph-ndv__source {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 11px;
  border-radius: 999px;
  background: color-mix(in oklab, var(--color-grey-50) 80%, var(--color-white));
  font-style: normal;
  font-size: 10px;
  color: var(--color-grey-500);
}
.p-products-hub .ph-ndv__source::before {
  content: "";
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--color-green-500);
}

/* ---- gfm: GovFaceMatch is a comparison, so the console shows the two it
   runs — the live selfie against the portrait the DMV holds, and the licence
   fields against the government record. The diagram version of this lives on
   the product page (components/UnifiedFlow.astro); this is the session view.
   Reuses the ssv's .ph-group / .ph-check rows so the two consoles read as one
   system. ---- */
.p-products-hub .ph-gfm { display: flex; flex-direction: column; flex: 1; min-height: 0; gap: 16px; padding-top: 16px; }
.p-products-hub .ph-gfm__head {
  display: flex;
  align-items: center;
  gap: 18px;
  padding-bottom: 16px;
  border-bottom: 1px solid var(--color-border-light);
}
.p-products-hub .ph-gfm__head .ph-age__score b { color: var(--color-black); }
.p-products-hub .ph-gfm__head .ph-age__person { width: 130px; }
.p-products-hub .ph-gfm__head .ph-age__checks { margin-left: auto; }
/* the record list carries six rows and the pair carries two portraits, so the
   split leans to the right rather than sitting even */
.p-products-hub .ph-gfm__cols {
  display: grid;
  grid-template-columns: minmax(0, 0.82fr) minmax(0, 1.18fr);
  align-items: start;
  gap: 14px;
  min-height: 0;
}
/* the pair: what the person just sent, and what the state already had */
.p-products-hub .ph-gfm__pair {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 14px 12px;
}
.p-products-hub .ph-gfm__face { display: flex; flex-direction: column; align-items: center; gap: 8px; min-width: 0; }
.p-products-hub .ph-gfm__face img {
  display: block;
  width: 92px;
  height: 92px;
  border-radius: 50%;
  object-fit: cover;
  border: 1px solid var(--color-border-light);
  background: var(--color-grey-50);
}
.p-products-hub .ph-gfm__face em { font-style: normal; font-size: 10px; color: var(--color-grey-400); }
/* the match itself: a short wire between the two portraits */
.p-products-hub .ph-gfm__vs {
  position: relative;
  flex: 0 0 26px;
  height: 1px;
  margin-bottom: 18px;
  background: var(--color-green-500);
}
.p-products-hub .ph-gfm__vs::before,
.p-products-hub .ph-gfm__vs::after {
  content: "";
  position: absolute;
  top: 50%;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--color-green-500);
  transform: translateY(-50%);
}
.p-products-hub .ph-gfm__vs::before { left: -2px; }
.p-products-hub .ph-gfm__vs::after { right: -2px; }

/* ---- age: the session read (Mike's screenshot 2026-08-18, then two passes
   on composition). The header row says WHO the session is — score, what was
   checked, the name, the reviewer's two actions — opposite the estimate and
   what was kept of the image. Under it, three boxes, one per readout. The
   jurisdiction flags and the Beta chip came out on the second pass: the panel
   was carrying more chips than it could read. ---- */
.p-products-hub .ph-age { display: flex; flex-direction: column; flex: 1; min-height: 0; gap: 22px; padding-top: 20px; }
.p-products-hub .ph-age__ico { width: 12px; height: 12px; flex: none; }
.p-products-hub .ph-age__top {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 230px);
  gap: 20px;
  padding-bottom: 22px;
  border-bottom: 1px solid var(--color-border-light);
}
.p-products-hub .ph-age__who { display: flex; flex-direction: column; align-items: flex-start; gap: 14px; }
.p-products-hub .ph-age__score { display: flex; align-items: baseline; gap: 6px; }
.p-products-hub .ph-age__score b {
  font-family: var(--font-display);
  font-size: 32px;
  font-weight: 600;
  line-height: 1;
  letter-spacing: var(--track-tight);
  color: var(--color-red-brand);
}
.p-products-hub .ph-age__score i { font-style: normal; font-size: 12px; color: var(--color-grey-400); }
.p-products-hub .ph-age__score em { margin-left: 4px; }
.p-products-hub .ph-age__checks { display: inline-flex; gap: 8px; }
/* the name as a bar, the way WorkforceSession draws its employee detail */
.p-products-hub .ph-age__person {
  display: block;
  width: 168px;
  height: 13px;
  border-radius: 999px;
  background: var(--color-grey-200);
}
.p-products-hub .ph-age__actions { display: inline-flex; gap: 10px; }
.p-products-hub .ph-age__actions i {
  padding: 6px 14px;
  border: 1px solid var(--color-border-light);
  border-radius: 999px;
  background: var(--color-white);
  font-style: normal;
  font-size: 11px;
  color: var(--color-grey-500);
}
/* the privacy panel is the product's own promise, so it sits opposite the
   identity rather than as a footnote */
.p-products-hub .ph-age__privacy {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 18px 14px;
  border: 1px solid var(--color-border-light);
  border-radius: var(--radius-md);
  background: color-mix(in oklab, var(--color-grey-50) 60%, var(--color-white));
  text-align: center;
}
.p-products-hub .ph-age__privacy-val {
  font-family: var(--font-display);
  font-size: 34px;
  font-weight: 600;
  line-height: 1;
  letter-spacing: var(--track-tight);
  color: var(--color-black);
}
.p-products-hub .ph-age__privacy-head {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  margin-top: 2px;
  font-size: 11px;
  font-weight: 500;
  color: var(--color-green-600);
}
.p-products-hub .ph-age__privacy-sub { font-style: normal; font-size: 10px; color: var(--color-grey-400); }

/* --- three boxes across: the age verdict, then each captured signal --- */
/* age verification takes half the row, the two signal boxes split the rest */
.p-products-hub .ph-age__detail {
  display: grid;
  grid-template-columns: 2fr 1fr 1fr;
  gap: 14px;
}
.p-products-hub .ph-age__box {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 16px;
  border: 1px solid var(--color-border-light);
  border-radius: var(--radius-md);
}
.p-products-hub .ph-age__box-label { font-style: normal; font-size: 11px; font-weight: 500; color: var(--color-black); }
.p-products-hub .ph-age__box-val { display: flex; align-items: baseline; gap: 5px; }
.p-products-hub .ph-age__box-val b {
  font-family: var(--font-display);
  font-size: 28px;
  font-weight: 600;
  line-height: 1;
  letter-spacing: var(--track-tight);
  color: var(--color-black);
}
.p-products-hub .ph-age__box-val i { font-style: normal; font-size: 11px; color: var(--color-grey-400); }
.p-products-hub .ph-age__box-foot { display: flex; align-items: center; gap: 8px; }
.p-products-hub .ph-age__box-foot em { font-style: normal; font-size: 10px; color: var(--color-grey-400); }

/* the counter strip a real console opens with, above the table */
.p-products-hub .ph-dstats {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px;
  padding: 16px 0 18px;
}
.p-products-hub .ph-dstat {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 12px 14px;
  border: 1px solid var(--color-border-light);
  border-radius: var(--radius-md);
}
.p-products-hub .ph-dstat__label { font-style: normal; font-size: 11px; color: var(--color-grey-400); }
.p-products-hub .ph-dstat__value {
  font-family: var(--font-display);
  font-size: 22px;
  font-weight: 600;
  line-height: 1.1;
  letter-spacing: var(--track-tight);
  color: var(--color-black);
}

/* rows keep their natural height and the table starts right under the counter
   strip — stretching them to fill a 512px pane reads as a spreadsheet, and
   centering the block floats it away from the counters it belongs to */
.p-products-hub .ph-dread {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
}

/* status pill — the canonical tone triplet (tone-100 ground, tone-500 text) */
.p-products-hub .ph-dpill {
  flex: none;
  justify-self: end;
  padding: 3px 9px;
  border-radius: 999px;
  font-style: normal;
  font-size: 10px;
  font-weight: 500;
  line-height: 1.3;
  white-space: nowrap;
}
.p-products-hub .ph-dpill--green { background: var(--color-green-100); color: var(--color-green-600); }
.p-products-hub .ph-dpill--red { background: var(--color-red-100); color: var(--color-red-600); }
.p-products-hub .ph-dpill--yellow { background: var(--color-yellow-100); color: var(--color-yellow-500); }
.p-products-hub .ph-dpill--blue { background: var(--color-blue-100); color: var(--color-blue); }
.p-products-hub .ph-dpill--grey { background: var(--color-grey-50); color: var(--color-grey-400); }

/* shared track — the bar behind a signal, a source hit rate, a match score */
.p-products-hub .ph-dtrack {
  height: 6px;
  border-radius: 999px;
  background: var(--color-grey-100);
  overflow: hidden;
}
.p-products-hub .ph-dtrack__fill {
  display: block;
  width: var(--fill);
  height: 100%;
  border-radius: inherit;
}
.p-products-hub .ph-dtrack__fill--blue { background: var(--color-blue); }
.p-products-hub .ph-dtrack__fill--red { background: var(--color-red-brand); }
.p-products-hub .ph-dtrack__fill--grey { background: var(--color-grey-200); }

/* meters — Deepsight's behavior signals, Non-Document's data sources */
.p-products-hub .ph-dmeter {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(120px, 240px) 46px 78px;
  align-items: center;
  gap: 20px;
  padding: 12px 0;
  border-bottom: 1px solid var(--color-border-light);
}
.p-products-hub .ph-dmeter:last-child { border-bottom: 0; }
.p-products-hub .ph-dmeter__label {
  font-size: 12px;
  font-weight: 400;
  color: var(--color-grey-500);
}
.p-products-hub .ph-dmeter__val {
  justify-self: end;
  font-style: normal;
  font-size: 11px;
  color: var(--color-grey-400);
}
.p-products-hub .ph-dfoot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-top: 12px;
  padding: 11px 12px;
  border-radius: var(--radius-md);
  background: var(--color-grey-50);
}
.p-products-hub .ph-dfoot b { font-size: 12px; font-weight: 500; color: var(--color-black); }

/* list — the Workforce identity queue, the Agentic Identity agent sessions */
.p-products-hub .ph-drow {
  display: grid;
  grid-template-columns: 28px minmax(0, 1fr) minmax(0, 150px) 86px;
  align-items: center;
  gap: 14px;
  padding: 11px 0;
  border-bottom: 1px solid var(--color-border-light);
}
.p-products-hub .ph-drow__meta {
  font-style: normal;
  font-size: 11px;
  color: var(--color-grey-400);
}
.p-products-hub .ph-drow:last-child { border-bottom: 0; }
.p-products-hub .ph-drow__avatar {
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: var(--color-grey-100);
}
.p-products-hub .ph-drow__glyph {
  display: grid;
  place-items: center;
  width: 26px;
  height: 26px;
  border-radius: var(--radius-sm);
  background: var(--color-blue-100);
  color: var(--color-blue);
}
.p-products-hub .ph-drow__glyphico { width: 14px; height: 14px; }
.p-products-hub .ph-drow__who { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.p-products-hub .ph-drow__name {
  font-size: 12px;
  font-weight: 500;
  color: var(--color-black);
}
.p-products-hub .ph-drow__sub {
  font-style: normal;
  font-size: 11px;
  color: var(--color-grey-400);
}

/* scores — GovFaceMatch, where the number against the state record is the story */
.p-products-hub .ph-drow--score { grid-template-columns: minmax(0, 1fr) minmax(150px, 280px) 86px; }
.p-products-hub .ph-dscore { display: flex; align-items: center; gap: 12px; }
.p-products-hub .ph-dscore .ph-dtrack { flex: 1; }
.p-products-hub .ph-dscore__val {
  flex: none;
  font-family: var(--font-display);
  font-size: 12px;
  font-weight: 500;
  font-variant-numeric: tabular-nums;
  color: var(--color-grey-500);
}


/* ---- narrow screens: the console keeps its head and its verdicts, and
   drops the columns a 300px-wide card cannot hold. The earlier @media that
   hides .ph-dash__side sits ABOVE the rules that build the nav, so it loses
   on source order — it is re-stated here, after them. ---- */
@media (max-width: 639px) {
  .p-products-hub .ph-dash__side { display: none; }
  .p-products-hub .ph-dash__body { padding: 16px; }
  .p-products-hub .ph-dstats { gap: 8px; padding: 12px 0 14px; }
  .p-products-hub .ph-dstat { padding: 10px; }
  .p-products-hub .ph-dstat__label { font-size: 10px; }
  .p-products-hub .ph-dstat__value { font-size: 17px; }
  /* the track and its number go; the label and the verdict are the row */
  .p-products-hub .ph-dmeter,
  .p-products-hub .ph-dmeter--wide { grid-template-columns: minmax(0, 1fr) auto; gap: 10px; }
  .p-products-hub .ph-dmeter .ph-dtrack,
  .p-products-hub .ph-dmeter__val { display: none; }
  .p-products-hub .ph-drow { grid-template-columns: 24px minmax(0, 1fr) auto; gap: 10px; }
  .p-products-hub .ph-drow__meta { display: none; }
  .p-products-hub .ph-drow--score { grid-template-columns: minmax(0, 1fr) 34px auto; }
  .p-products-hub .ph-drow--score .ph-dtrack { display: none; }

  /* the Workforce console: nav off, and the queue down to name + status */
  .p-products-hub .ph-wfs .wfs-win__side { display: none; }
  .p-products-hub .ph-wfs .wfs-list__head,
  .p-products-hub .ph-wfs .wfs-list__row { grid-template-columns: minmax(0, 1fr) auto; }
  .p-products-hub .ph-wfs .wfs-list__head span:nth-child(2),
  .p-products-hub .ph-wfs .wfs-list__head span:nth-child(3),
  .p-products-hub .ph-wfs .wfs-list__cell { display: none; }
  .p-products-hub .ph-ndv { gap: 12px; padding-top: 12px; }
  .p-products-hub .ph-ndv__top { gap: 12px; padding-bottom: 12px; }
  .p-products-hub .ph-ndv__who { gap: 10px; }
  .p-products-hub .ph-ndv__selfie img { width: 62px; height: 62px; }
  .p-products-hub .ph-ndv__selfie em { display: none; }
  .p-products-hub .ph-ndv__cards { grid-template-columns: minmax(0, 1fr); gap: 8px; }
  .p-products-hub .ph-ndv__card { padding: 9px 12px; gap: 4px; }
  .p-products-hub .ph-ndv__sources { display: none; }
  .p-products-hub .ph-ndv__plate { width: 82px; height: 58px; }
  .p-products-hub .ph-ndv__shots { gap: 8px; }
  .p-products-hub .ph-ndv__doc { padding-top: 10px; gap: 6px; }
  /* only the two rows that say the product's point: no document, and what
     stood in for it. The other two are dashes at this width. */
  .p-products-hub .ph-ndv__doc-rows { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 6px; }
  .p-products-hub .ph-ndv__doc-row { padding: 6px 9px; }
  /* the document block goes: four label/value pairs plus the source chips do
     not fit under three result cards at 300px, and the empty ID plate above
     already says there was no document */
  .p-products-hub .ph-ndv__doc { display: none; }
  .p-products-hub .ph-age__actions i { padding: 4px 10px; font-size: 10px; }
  .p-products-hub .ph-ndv__card-val { font-size: 14px; }
  .p-products-hub .ph-ndv__cards { gap: 5px; }
  .p-products-hub .ph-ndv { gap: 8px; padding-top: 8px; }
  .p-products-hub .ph-ndv__top { padding-bottom: 8px; }
  .p-products-hub .ph-ndv__who { gap: 7px; }
  .p-products-hub .ph-age__score b { font-size: 22px; }
  .p-products-hub .ph-ndv__card { padding: 7px 10px; gap: 3px; }
  .p-products-hub .ph-ndv__plate { width: 66px; height: 46px; font-size: 9px; }
  .p-products-hub .ph-ndv__selfie img { width: 52px; height: 52px; }

  /* the two comparisons stack: portraits over the field list */
  .p-products-hub .ph-gfm { gap: 10px; padding-top: 10px; }
  .p-products-hub .ph-gfm__head { flex-wrap: wrap; gap: 10px; padding-bottom: 10px; }
  .p-products-hub .ph-gfm__head .ph-age__checks { margin-left: 0; }
  .p-products-hub .ph-gfm__cols { grid-template-columns: minmax(0, 1fr); gap: 10px; }
  .p-products-hub .ph-gfm__pair { padding: 10px; gap: 8px; }
  .p-products-hub .ph-gfm__face img { width: 74px; height: 74px; }
  /* six field rows plus the portraits overshoot a 438px stage — the last two
     drop, and the "6 of 6" pill still says how many were checked */
  .p-products-hub .ph-gfm__cols .ph-group:last-child .ph-check:nth-last-child(-n+2) { display: none; }

  /* the age read stacks: identity over the privacy panel, then the age
     verification card. The captured-signals column drops — the header and the
     estimate are what the section is about, and all four blocks need ~500px
     against a 438px stage */
  .p-products-hub .ph-age__top { grid-template-columns: minmax(0, 1fr); gap: 10px; }
  .p-products-hub .ph-age__detail { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .p-products-hub .ph-age__box:first-child { grid-column: 1 / -1; }
  .p-products-hub .ph-age__person { font-size: 18px; }
  .p-products-hub .ph-age__score b { font-size: 24px; }
  .p-products-hub .ph-age__privacy { padding: 12px; }
  .p-products-hub .ph-age__privacy-val { font-size: 26px; }
  .p-products-hub .ph-age { gap: 10px; padding-top: 10px; }
  .p-products-hub .ph-age__top { padding-bottom: 10px; }
  .p-products-hub .ph-age__who { gap: 8px; }
  .p-products-hub .ph-age__detail { gap: 8px; }
  .p-products-hub .ph-age__box { padding: 8px 10px; gap: 3px; }
  .p-products-hub .ph-age__box-val b { font-size: 18px; }
  .p-products-hub .ph-age__box-label { font-size: 10px; }
  .p-products-hub .ph-age__actions i { padding: 5px 11px; }
  .p-products-hub .ph-age__privacy { padding: 10px; gap: 3px; }
  .p-products-hub .ph-age__privacy-val { font-size: 24px; }

  /* the agents console stacks: the owner over the agents it delegates to,
     with the dashed leads dropped (they only read across a wide pane) and the
     third agent trimmed so the detection card — the part of the walk Mike
     picked out — still fits above the fold of the stage */
  .p-products-hub .ph-ag__graph { grid-template-columns: minmax(0, 1fr); gap: 10px; padding: 12px 0; }
  .p-products-hub .ph-ag__links { display: none; }
  .p-products-hub .ph-ag__owner { flex-direction: row; justify-content: flex-start; gap: 10px; padding: 10px 12px; }
  .p-products-hub .ph-ag__owner-av { width: 30px; height: 30px; font-size: 11px; }
  .p-products-hub .ph-ag__owner-check { margin-left: auto; }
  .p-products-hub .ph-ag__agent:nth-child(3) { display: none; }
  .p-products-hub .ph-ag__foot { padding-top: 8px; }

  /* the ssv goes single-column: the two captures side by side over the first
     check group. Both groups plus the shots need ~590px and the stage is 512,
     so Multi-modal intelligence drops here rather than being clipped. */
  /* one column, rows pinned to the top so the spare height lands at the foot
     instead of opening a gap between the captures and the checks */
  .p-products-hub .ph-ssv { grid-template-columns: minmax(0, 1fr); grid-template-rows: auto auto; align-content: start; gap: 14px; }
  /* the title plus three verdict pills need ~350px; the document's own verdict
     is already spelled out by the capture labelled below it */
  .p-products-hub .ph-dverdicts .ph-dpill:last-child { display: none; }
  .p-products-hub .ph-ssv__shots { flex-direction: row; gap: 10px; flex: none; }
  .p-products-hub .ph-shot { flex: 1; }
  .p-products-hub .ph-shot__img { height: 92px; flex: none; }
  .p-products-hub .ph-ssv__checks .ph-group:nth-child(2) { display: none; }

  /* the detail's right-hand skeleton bars are sized for the 540px window and
     run past the edge of a phone-width card */
  .p-products-hub .ph-wfs .wfs-win__meta { display: none; }
  /* and the desktop scale-up overshoots the 448px stage by ~28px here */
  .p-products-hub .ph-wfs .wfs-win__title { padding: 14px 16px 0; }
  .p-products-hub .ph-wfs .wfs-win__profile { gap: 12px; padding: 12px 16px; }
  .p-products-hub .ph-wfs .wfs-win__avatar { width: 44px; height: 44px; }
  .p-products-hub .ph-wfs .wfs-win__list { padding: 0 16px 14px; }
  .p-products-hub .ph-wfs .wfs-list__row { padding: 8px; }
  .p-products-hub .ph-wfs .wfs-list__head { padding: 6px 8px; }
}

/* ---------- end-user pane: light phone ---------- */
.p-products-hub .ph-pane--flow {
  display: none;
  place-items: center;
  min-height: var(--ph-stage-h);
  border: 1px solid var(--color-border-light);
  border-radius: 16px;
  background:
    radial-gradient(circle at 1px 1px, color-mix(in oklab, var(--color-grey-200) 45%, transparent) 1px, transparent 0) 0 0 / 22px 22px,
    var(--color-background);
  padding: 28px;
}
.p-products-hub .ph-pane--flow.is-active { display: grid; }

/* the flow plays like a short video: the phone cycles its stages while the
   backstage pointer beside it narrates what runs invisibly (a live check
   the user never sees). A hairline connector ties the note to the phone. */
.p-products-hub .ph-flowstage {
  display: flex;
  align-items: center;
  gap: 64px;
}
.p-products-hub .ph-pointer {
  position: relative;
  width: 250px;
  padding: 18px 20px;
  text-align: left;
  background: var(--color-white);
  border: 1px solid var(--color-border-light);
  border-radius: 14px;
  box-shadow: none;
}
.p-products-hub .ph-pointer::before {
  content: "";
  position: absolute;
  left: 100%;
  top: 50%;
  width: 64px;
  height: 1px;
  background: var(--color-grey-200);
}
/* the pointer tip: a static blue dot resting on the phone's edge */
.p-products-hub .ph-pointer::after {
  content: "";
  position: absolute;
  left: calc(100% + 60px);
  top: 50%;
  width: 8px;
  height: 8px;
  margin-top: -4px;
  border-radius: 50%;
  background: var(--color-blue);
}
.p-products-hub .ph-pointer__kicker {
  font-size: var(--fs-xs);
  letter-spacing: var(--track-wide);
  color: var(--color-kicker-on-white);
}
/* notes stack in one grid cell: the card keeps the tallest note's height,
   so the swap never reflows the canvas */
.p-products-hub .ph-pointer__notes {
  display: grid;
  margin-top: 8px;
}
.p-products-hub .ph-pointer__note {
  grid-area: 1 / 1;
  margin: 0;
  font-size: var(--fs-sm);
  line-height: 1.55;
  color: var(--color-black);
  opacity: 0;
  transition: opacity 0.45s ease;
}
.p-products-hub .ph-pointer__note.is-active { opacity: 1; }
.p-products-hub .ph-pointer__dots {
  display: flex;
  gap: 5px;
  margin-top: 14px;
}
.p-products-hub .ph-pointer__dots i {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--color-grey-200);
  transition: background 0.3s ease;
}
.p-products-hub .ph-pointer__dots i.is-active { background: var(--color-blue); }
@media (max-width: 639px) {
  .p-products-hub .ph-flowstage {
    flex-direction: column-reverse;
    gap: 18px;
  }
  .p-products-hub .ph-pointer { width: min(280px, 100%); }
  .p-products-hub .ph-pointer::before,
  .p-products-hub .ph-pointer::after { display: none; }
}
/* the phone is a clean bezel around REAL captures of the product flow
   (Sofia, 2026-07-25: real UI, never skeleton art) — the screens carry
   their own wordmark, copy and CTA, so the bezel adds no chrome */
.p-products-hub .ph-phone {
  position: relative;
  width: 224px;
  min-height: 452px;
  overflow: hidden;
  border: 1px solid var(--color-border-light);
  border-radius: 26px;
  background: var(--color-white);
  box-shadow: none;
}
/* the flow film fills the bezel edge to edge */
.p-products-hub .ph-phone__video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* ============================================================
   ALT B (/products-b/, Sofia 2026-08-18): the Dashboard ⇄ End-user
   switcher IS the page — hero-ized spacing only, everything else
   identical. Scoped to the solo modifier so /products/ is untouched.
   ============================================================ */
.p-products-hub--solo .ph-products {
  padding-top: 56px;
  min-height: 100svh;
}
/* the PINNED WALK (Sofia 2026-08-18: "when the user reaches this point,
   keep the user there and change products with scroll"): the behavior
   (products-hub-walk.js) stretches the section into a runway; this inner
   pins for its whole length and the scroll position picks the product.
   The flex centering distributes the air above/below the frame content. */
@media (min-width: 1024px) {
  .p-products-hub--solo .ph-products { padding-top: 0; }
  .p-products-hub--solo .ph-products__inner {
    position: sticky;
    top: 0;
    height: 100svh;
    display: flex;
    flex-direction: column;
    justify-content: center;
    padding-top: 96px; /* the fixed header's band */
    padding-bottom: 32px;
  }
}
@media (prefers-reduced-motion: reduce) {
  .p-products-hub--solo .ph-products__inner { position: static; height: auto; }
}
/* the wireframe geometry (Sofia 2026-08-18): CENTERED head (hub pages may
   center), the product tabs as ONE horizontal pill row spanning the inner
   width, the stage full-width below — the vertical rail + 2-col split of
   /products/ is undone inside the solo scope only. */
.p-products-hub--solo .ph-products__inner {
  text-align: center;
}
/* head rhythm: real air above and below the copy (Sofia 2026-08-18:
   "distribute properly"); the flex frame centers the whole stack */
.p-products-hub--solo .ph-products__title { margin-top: 24px; }
.p-products-hub--solo .ph-products__intro { margin-top: 16px; }
.p-products-hub--solo .ph-products__layout { margin-top: 44px; }
.p-products-hub--solo .ph-products__intro {
  margin-inline: auto;
}
.p-products-hub--solo .ph-products__layout,
.p-products-hub--solo .ph-products__rail,
.p-products-hub--solo .ph-products__tabs,
.p-products-hub--solo .ph-products__card {
  text-align: left; /* the centered head must not center the working UI */
}
@media (min-width: 1024px) {
  .p-products-hub--solo .ph-products__layout {
    display: flex;
    flex-direction: column;
    /* stretch, not start: the base grid's align-items leaks in and would
       shrink the stage card to its content width */
    align-items: stretch;
    gap: 24px;
  }
  /* tabs: back to the base pill look, one row across the full width */
  .p-products-hub--solo .ph-products__tabs {
    flex-direction: row;
    align-items: center;
    flex-wrap: wrap;
    gap: 8px;
  }
  .p-products-hub--solo .ph-products__tab {
    flex: 1;
    justify-content: center;
    height: 46px;
    padding: 0 16px 0 13px;
    border: 1px solid var(--color-border-light);
    border-radius: 999px;
    background: var(--color-white);
  }
  .p-products-hub--solo .ph-products__tab.is-active {
    border-color: var(--color-blue);
    background: var(--color-blue-100);
  }
  /* the count + arrows retire — the row itself is the navigation */
  .p-products-hub--solo .ph-products__ctrls { display: none; }
  /* the stage placeholder a step shorter (Sofia 2026-08-18): the whole
     card reads in one viewport, no scroll needed */
  .p-products-hub--solo .ph-prod__stage { --ph-stage-h: 268px; }
  /* the dash panes hold intrinsic height above the var — cap them so the
     stage really lands at the shorter seat */
  .p-products-hub--solo .ph-dash { max-height: var(--ph-stage-h); }
  .p-products-hub--solo .ph-dash__chart { min-height: 0; }
  /* the section's own inner padding stacks under the hero seat — the seat
     already carries the air */

}

/* ============================================================
   ALT C (/products-c/, Sofia 2026-08-18): the /platform/ console
   layout for products — light rail (brand seat + product list) left,
   dark stage right; each product card carries ONLY its name + the
   Dashboard ⇄ End-user toggle over the visual. Scoped to the console
   modifier so /products/ and /products-b/ are untouched.
   ============================================================ */
.p-products-hub--console .phc { border-top: 0; }
.p-products-hub--console .phc__grid {
  display: grid;
  min-height: 100svh;
}
@media (min-width: 1024px) {
  .p-products-hub--console .phc__grid { grid-template-columns: 300px minmax(0, 1fr); }
}
/* rail — the platform sidebar recipe: light panel, hard division */
.p-products-hub--console .phc__rail {
  /* more air under the main nav (Sofia 2026-08-18) */
  padding: 168px 24px 48px;
  background: var(--color-background);
  border-right: 1px solid var(--color-border-light);
}
.p-products-hub--console .phc__home {
  display: inline-flex;
  align-items: center;
  gap: 12px;
}
.p-products-hub--console .phc__tile {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border-radius: 12px;
  background: var(--color-white);
  border: 1px solid var(--color-border-light);
}
.p-products-hub--console .phc__halo {
  width: 20px;
  height: 20px;
  background-color: transparent;
  background-image: linear-gradient(to top right, var(--color-black), var(--color-blue-500));
}
.p-products-hub--console .phc__brand {
  font-size: var(--fs-sm);
  font-weight: 500;
  color: var(--color-black);
}
/* the product list: flush rows, active row lit */
.p-products-hub--console .phc__list {
  margin-top: 32px;
  flex-direction: column;
  align-items: stretch;
  gap: 4px;
}
.p-products-hub--console .phc__list .ph-products__tab {
  height: auto;
  justify-content: flex-start;
  padding: 12px 14px;
  border: 0;
  border-radius: 10px;
  background: none;
  color: var(--color-grey-500);
}
.p-products-hub--console .phc__list .ph-products__tab:hover { color: var(--color-black); }
.p-products-hub--console .phc__list .ph-products__tab.is-active {
  background: var(--color-blue-100);
  color: var(--color-blue);
}
/* stage — off-white ground (Sofia 2026-08-18: the aurora retired; the
   grey-50 tint is the component-tint exception to the white-page rule) */
.p-products-hub--console .phc__stage {
  min-width: 0;
  /* the top padding swallows the sticky header (124px) — 166 leaves the 42px
     of air Mike asked for between the menu and the card.
     Sides: the card centres itself in the grey ground (max-width + margin
     auto), so above 1400 there is no side padding at all — the centring does
     the work (Mike 2026-08-18). Below that the ground is narrower than the
     card's 1040 max, and with no padding it would touch the rail and the
     window edge, so a floor of 32 stays. */
  padding: 166px 32px 64px;
  background: var(--color-grey-50);
}
@media (min-width: 1280px) {
  .p-products-hub--console .phc__stage { padding: 166px 32px 72px; }
}
.p-products-hub--console .ph-carousel {
  width: min(100%, 1040px);
  margin-inline: auto;
}
@media (min-width: 1400px) {
  .p-products-hub--console .phc__stage { padding-inline: 0; }
}
/* the stage placeholder a step shorter (Sofia 2026-08-18: too tall — the
   card must sit whole in the first viewport) */
.p-products-hub--console .ph-prod__stage { --ph-stage-h: 430px; }
/* the product card sits white on the grey stage */
.p-products-hub--console .ph-prod { background: var(--color-white); }
/* the card head: name · one-liner · Explore CTA left, the view toggle right */
.p-products-hub--console .phc__id {
  display: flex;
  flex-direction: column;
  gap: 8px;
  min-width: 0;
}
.p-products-hub--console .phc__line {
  font-size: var(--fs-body);
  line-height: var(--leading-body);
  color: var(--color-grey-on-white);
  max-width: 58ch;
}
.p-products-hub--console .phc__cta {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-top: 2px;
  font-size: var(--fs-sm);
  font-weight: 500;
  color: var(--color-blue);
}
.p-products-hub--console .phc__cta svg { transition: transform 0.25s ease; }
.p-products-hub--console .phc__cta:hover svg { transform: translate(2px, -2px); }

.p-products-hub--console .phc__name {
  font-family: var(--font-display);
  font-weight: 500;
  letter-spacing: var(--track-tighter);
  font-size: 24px;
  line-height: 1.1;
  color: var(--color-black);
}
.p-products-hub--console .phc__head { align-items: flex-start; }
/* mobile: the rail folds into a top strip, the stage follows */
@media (max-width: 1023px) {
  .p-products-hub--console .phc__rail { padding: 96px 20px 24px; border-right: 0; border-bottom: 1px solid var(--color-border-light); }
  .p-products-hub--console .phc__list { flex-direction: row; flex-wrap: wrap; }
  .p-products-hub--console .phc__list .ph-products__tab { padding: 9px 12px; }
  .p-products-hub--console .phc__stage { padding: 32px 20px 48px; }
}

/* ---- console fit (2026-08-18 merge): Sofia's console stage is 430px, not the
   512 the readouts were drawn against, so the two that run longest — the
   agents console and the non-document session — tighten here rather than
   being clipped. Scoped to the console modifier: the readouts keep their
   original rhythm anywhere else they are used. ---- */
.p-products-hub--console .ph-ag { padding-top: 8px; }
.p-products-hub--console .ph-ag__tabs { padding-bottom: 8px; }
.p-products-hub--console .ph-ag__graph { padding: 10px 0; }
.p-products-hub--console .ph-ag__owner { padding: 10px 8px; gap: 5px; }
.p-products-hub--console .ph-ag__owner-av { width: 34px; height: 34px; }
.p-products-hub--console .ph-ag__agents { gap: 6px; }
.p-products-hub--console .ph-ag__agent { padding: 6px 10px; }
.p-products-hub--console .ph-ag__detect { padding: 9px; gap: 4px; }
.p-products-hub--console .ph-ag__lane { padding: 5px 9px; }
.p-products-hub--console .ph-ag__foot { padding-top: 8px; }

.p-products-hub--console .ph-ndv { gap: 12px; padding-top: 12px; }
.p-products-hub--console .ph-ndv__top { padding-bottom: 12px; }
.p-products-hub--console .ph-ndv__who { gap: 10px; }
.p-products-hub--console .ph-ndv__card { padding: 10px 13px; gap: 6px; }
.p-products-hub--console .ph-ndv__doc { padding-top: 10px; gap: 8px; }
.p-products-hub--console .ph-ndv__doc-row { padding: 6px 10px; }
/* the flow pane's phone was taller than the console stage, so switching to
   End-user grew the card (Mike 2026-08-18). It scales to fit instead. */
.p-products-hub--console .ph-phone { width: 190px; min-height: 384px; border-radius: 22px; }
.p-products-hub--console .ph-flowstage { gap: 20px; }
.p-products-hub--console .ph-pane { padding: 0; }

/* the last of the agents console's height */
.p-products-hub--console .ph-ag__graph { padding: 6px 0; }
.p-products-hub--console .ph-ag__agent-av { width: 20px; height: 20px; }
.p-products-hub--console .ph-ag__detect-head { font-size: 10px; }

@media (max-width: 639px) {
  /* the same tightening again on a 300px card, where every readout is
     already stacked and the stage is still 430 */
  .p-products-hub--console .ph-age { gap: 6px; padding-top: 6px; }
  .p-products-hub--console .ph-age__top { padding-bottom: 6px; gap: 6px; }
  .p-products-hub--console .ph-age__who { gap: 6px; }
  .p-products-hub--console .ph-age__privacy { padding: 8px; }
  .p-products-hub--console .ph-age__privacy-val { font-size: 20px; }
  .p-products-hub--console .ph-age__box { padding: 6px 9px; }
  .p-products-hub--console .ph-gfm { gap: 6px; padding-top: 6px; }
  .p-products-hub--console .ph-gfm__head { padding-bottom: 6px; gap: 6px; }
  .p-products-hub--console .ph-gfm__face img { width: 58px; height: 58px; }
  .p-products-hub--console .ph-gfm__pair { padding: 8px; }
  .p-products-hub--console .ph-gfm__cols .ph-group:last-child .ph-check:nth-last-child(-n+3) { display: none; }
  .p-products-hub--console .ph-ndv { gap: 6px; padding-top: 6px; }
  .p-products-hub--console .ph-ndv__top { padding-bottom: 6px; }
  .p-products-hub--console .ph-ndv__cards { gap: 4px; }
  .p-products-hub--console .ph-ndv__card { padding: 5px 9px; }
  .p-products-hub--console .ph-ag__graph { padding: 4px 0; }
  .p-products-hub--console .ph-ag__detect { padding: 7px; }
}
/* the agents console still ran 19px long: the third agent row is what
   overflowed, and two delegations plus the pending one still read as a fan */
.p-products-hub--console .ph-ag__agent { padding: 5px 10px; }
.p-products-hub--console .ph-ag__agent-txt em { font-size: 9px; }
.p-products-hub--console .ph-ag__lane { padding: 4px 9px; }
.p-products-hub--console .ph-ag__lane-glyph { width: 17px; height: 17px; }
.p-products-hub--console .ph-ag__foot { padding-top: 6px; }

@media (max-width: 639px) {
  .p-products-hub--console .ph-age__box { padding: 5px 8px; gap: 2px; }
  .p-products-hub--console .ph-age__box-val b { font-size: 16px; }
  .p-products-hub--console .ph-age__actions i { padding: 3px 9px; }
  .p-products-hub--console .ph-age__score b { font-size: 20px; }
  .p-products-hub--console .ph-ndv__card-val { font-size: 13px; }
  .p-products-hub--console .ph-ndv__selfie img { width: 44px; height: 44px; }
  .p-products-hub--console .ph-ndv__plate { width: 56px; height: 38px; }
  .p-products-hub--console .ph-ndv__who { gap: 5px; }
  .p-products-hub--console .ph-ag__owner { padding: 7px; }
  .p-products-hub--console .ph-ag__owner-av { width: 26px; height: 26px; }
}
/* last 11px of the agents console: the detection card's own head row */
.p-products-hub--console .ph-ag__detect { gap: 3px; padding: 7px 9px; }
.p-products-hub--console .ph-ag__tabs { padding-bottom: 7px; }
.p-products-hub--console .ph-ag__tabs i.is-on::after { inset: auto 0 -8px 0; }

@media (max-width: 639px) {
  .p-products-hub--console .ph-age__privacy { padding: 6px; gap: 2px; }
  .p-products-hub--console .ph-age__privacy-val { font-size: 18px; }
  .p-products-hub--console .ph-age__card-body { padding: 6px 9px; }
  .p-products-hub--console .ph-ndv__card { padding: 4px 8px; }
  .p-products-hub--console .ph-ndv__cards { gap: 3px; }
}
/* the last few pixels of the console fit */
.p-products-hub--console .ph-ag__agent-txt b { font-size: 10px; }
.p-products-hub--console .ph-ag__owner-name { font-size: 11px; }
@media (max-width: 639px) {
  .p-products-hub--console .ph-age__card-val b { font-size: 20px; }
  .p-products-hub--console .ph-ndv__shot em { font-size: 9px; }
  .p-products-hub--console .ph-ndv__face { width: 44px; height: 44px; }
}
.p-products-hub--console .ph-ag__agents { gap: 5px; }
@media (max-width: 639px) {
  .p-products-hub--console .ph-age__card-head { gap: 6px; }
  .p-products-hub--console .ph-age__box-label { font-size: 9px; }
  .p-products-hub--console .ph-ndv__doc { display: none; }
  .p-products-hub--console .ph-ndv__shots { gap: 8px; }
}
/* the agents console and the age read, last few pixels against the 430 stage */
.p-products-hub--console .ph-ag__agents { gap: 4px; }
.p-products-hub--console .ph-ag__detect { padding: 6px 9px; }
@media (max-width: 639px) {
  .p-products-hub--console .ph-age__box { padding: 4px 8px; }
  .p-products-hub--console .ph-age__card-body { padding: 5px 8px; }
  .p-products-hub--console .ph-ndv__shot em { display: none; }
}
.p-products-hub--console .ph-ag { padding-top: 6px; }
@media (max-width: 639px) {
  .p-products-hub--console .ph-age { gap: 5px; padding-top: 5px; }
  .p-products-hub--console .ph-ndv__cards { gap: 2px; }
  .p-products-hub--console .ph-ndv { gap: 5px; }
}
@media (max-width: 639px) {
  .p-products-hub--console .ph-age__box-val b { font-size: 15px; }
  .p-products-hub--console .ph-ndv__card-val { font-size: 12px; }
}
@media (max-width: 639px) {
  .p-products-hub--console .ph-age__top { gap: 5px; }
  .p-products-hub--console .ph-age__actions i { padding: 3px 8px; font-size: 9px; }
}
