/* =========================================================================
   InFlightAI — Platform page
   Layers on home.css (tokens, header, footer, topcap) and reuses its platform
   carousel classes (.pslides/.pslide/.pfeature) for the Inspection Workflow.

   Rebuilt from the client's final design, Figma 4326:1335. Every section now
   carries real copy and real artwork; the only stand-in left is the trio of
   icons on the report section, which the asset drop did not include.
   ========================================================================= */

:root {
  /* Align with the rest of the site rather than the Figma frame's own padding.
     The comp insets these sections 120-240px against a fixed 1440 canvas, which
     at 1440 put their content at 235-1205 while the header runs 48-1392 — the
     page read as a narrow column bolted under a full-width header.

     Using the site's own shell tokens instead means every section lines up with
     the logo and the CTA buttons, and with the homepage, at every viewport. */
  --pf-gutter: var(--gutter);
  --pf-shell: var(--maxw);
  --pf-pad: clamp(44px, 6vw, 60px);
  /* The design's proportions still hold inside that wider shell: rows that were
     1200 or 960 in the comp now scale with it, since their grids are in fr. */
}

.pfmain { background: var(--white); }

/* =========================================================================
   Hero (Figma 4277:2849)

   Not the Library's hero: that one fans seven portrait inspection photos.
   This is three wide product screenshots, bottom-aligned and overlapping,
   running off the bottom of the dark band.

   Sized in vw against the 1440 comp so the fan keeps its proportions as the
   viewport narrows, capped at the design's pixel widths so it never inflates
   past it. Heights come from aspect-ratio, which is what makes the three
   different card sizes hold their relationship.
   ========================================================================= */
.pfhero {
  position: relative;
  z-index: 2;
  padding-top: 16px;
  text-align: center;
}
/* a small inline pad only — the section gutter would cut the standfirst's
   670px measure down to 645px at 1440 */
.pfhero__text { max-width: 875px; margin-inline: auto; padding-inline: 20px; }
.pfhero__title {
  font-family: "Outfit", sans-serif;
  font-size: clamp(28px, 2.5vw, 36px);
  font-weight: 500;
  line-height: 1.17;
  letter-spacing: -0.01em;
  color: var(--white);
}
.pfhero__sub {
  max-width: 670px;
  margin: 4px auto 0;
  font-family: "DM Sans", "Outfit", sans-serif;
  font-variation-settings: "opsz" 14;
  font-size: 16px;
  font-weight: 500;
  line-height: 21px;
  color: var(--gray-600);
}

/* The fan is a shell: the three cards together span exactly the header's
   measure, so the outer edges line up with the logo and the CTA buttons. */
.pfhero__fan {
  display: flex;
  align-items: flex-end;
  justify-content: center;
  margin-top: 26px;
  width: 100%;
  max-width: var(--pf-shell);
  margin-inline: auto;
  padding-inline: var(--pf-gutter);
  box-sizing: border-box;
}
/* One composite export now: the three screenshots, their overlaps and their
   shadows are all baked in, so the fan is a single image spanning the shell. */
.pfhero__art { display: block; width: 100%; height: auto; }

@media (max-width: 760px) {
  .pfhero__title { font-size: 26px; }
  .pfhero__sub { font-size: 14px; }
  .pfhero__fan { margin-top: 20px; }
}

.pf-shell {
  width: 100%;
  max-width: var(--pf-shell);
  margin-inline: auto;
  padding-inline: var(--pf-gutter);
}

.pf-section { padding-block: var(--pf-pad); }
.pf-section--dark { background: var(--black); }
.pf-section--tint { background: var(--light-300); }

/* --- shared section heading ------------------------------------------- */
.pf-eyebrow {
  font-family: "Outfit", sans-serif;
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 1.44px;
  text-transform: uppercase;
  color: var(--blue);
}
.pf-title {
  font-family: "Outfit", sans-serif;
  font-size: clamp(24px, 2.4vw, 30px);
  font-weight: 500;
  line-height: 34px;
  color: var(--black);
  text-wrap: balance;
}
.pf-lede {
  font-family: "DM Sans", "Outfit", sans-serif;
  font-variation-settings: "opsz" 14;
  font-size: 16px;
  font-weight: 500;
  line-height: 22px;
  color: var(--gray);
}
/* 16/22, matching .pf-lede — the design sets every body paragraph at this size
   and only the integrations card's text drops to 14. The opsz axis stays at 14
   even here; that is what the design specifies, not a mirror of the size. */
.pf-body {
  font-family: "DM Sans", "Outfit", sans-serif;
  font-variation-settings: "opsz" 14;
  font-size: 16px;
  font-weight: 500;
  line-height: 22px;
  color: var(--gray);
}
.pf-section--dark .pf-title,
.pf-section--dark .pf-feature h3,
.pf-section--dark .pf-video__name,
.pf-section--dark .pf-stat__label { color: var(--white); }
.pf-section--dark .pf-lede,
.pf-section--dark .pf-body,
.pf-section--dark .pf-check,
.pf-section--dark .pf-video__meta { color: var(--gray-600); }

/* centred variant used by the model library, workflow and reports sections */
.pf-head {
  display: flex;
  flex-direction: column;
  gap: 10px;
  align-items: center;
  text-align: center;
  padding-bottom: 16px;
  max-width: 960px;
  margin-inline: auto;
}
.pf-head .pf-lede { max-width: 670px; }

/* left-aligned variant for the two-column sections */
.pf-head--start { align-items: flex-start; text-align: left; margin-inline: 0; }

/* --- the pill button, shared with the library page --------------------- */
.pf-pill {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 12px 16px;
  border: 1px solid var(--blue);
  border-radius: 80px;
  background: none;
  font-family: "Outfit", sans-serif;
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 1.44px;
  text-transform: uppercase;
  color: var(--blue);
  cursor: pointer;
  transition: background-color 0.2s var(--ease), color 0.2s var(--ease);
}
.pf-pill:hover { background: var(--blue); color: var(--white); }
.pf-pill:focus-visible { outline: 2px solid var(--blue); outline-offset: 3px; }
/* the exported glyph already points up-and-right — no rotation needed */
.pf-pill__arrow { flex: 0 0 auto; width: 9px; height: 9px; fill: currentColor; }

/* =========================================================================
   Shared artwork treatment
   ========================================================================= */
.pf-tile {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 12.8px;
  box-shadow: 0 30px 25px -18px rgba(0, 15, 35, 0.35);
}

/* =========================================================================
   Intelligence from the real-world, delivered (Figma 4326:1424)
   A stack of inspection cards fading out under a column of feature cards.
   ========================================================================= */
.pf-intel {
  display: grid;
  grid-template-columns: minmax(0, 640fr) minmax(0, 392fr);
  gap: clamp(28px, 4vw, 48px);
  align-items: start;
  margin-top: clamp(28px, 3.5vw, 44px);
}

/* The design runs the stack past the fold and dissolves it into the page
   rather than ending on a hard edge, so the column is clipped and masked. */
.pf-intel__stack {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 18px;
  /* A ratio, not a fixed height: the column is wider here than the design's 640,
     so 707px would clip a whole card earlier than the comp does. This shows the
     same proportion of the stack at any width. */
  aspect-ratio: 640 / 707;
  /* The crop is vertical — it hides the bottom of the stack — but plain
     overflow:hidden clips every side, and the lead card's 44px-blur shadow sits
     hard against the left and right edges, so it was being sliced off flat.
     overflow:clip takes a margin: the clip box grows 32px on each side, enough
     for the blur to fall off naturally, while the crop still happens.
     overflow:hidden stays first as the fallback — a browser without clip
     support ignores the second declaration and keeps today's behaviour. */
  overflow: hidden;
  overflow: clip;
  overflow-clip-margin: 32px;
}
.pf-intel__stack::after {
  content: "";
  position: absolute;
  /* Extended over the clip margin: the 32px now showing below the crop line
     would otherwise be raw artwork sitting outside the fade. */
  inset: auto -32px -32px -32px;
  height: calc(34% + 32px);
  background: linear-gradient(to bottom, rgba(255, 255, 255, 0) 0%, #fff 78%);
  pointer-events: none;
}
.pf-intel__stack img { display: block; width: 100%; height: auto; border-radius: 8px; }
.pf-intel__stack img:first-child { box-shadow: 0 24px 44px rgba(0, 15, 35, 0.16); }
/* the trailing three are inset under the lead card, per the design */
.pf-intel__stack img:not(:first-child) {
  width: 90.5%;
  margin-left: 2%;
  box-shadow: 0 5px 12px rgba(0, 15, 35, 0.1);
}

.pf-intel__cards { list-style: none; display: flex; flex-direction: column; gap: 16px; }
.pf-intelcard {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 20px;
  border: 1px solid var(--light);
  border-radius: 8px;
  background: var(--white);
}
/* ---- Load-in for the Intelligence section --------------------------------
   This section sits directly under the hero, so it is on screen before there
   is anything to scroll: the global `reveal` utility deliberately never arms
   anything above the fold, and would leave it static. So it animates on load
   instead, in CSS rather than JS — the stylesheet is render-blocking, so the
   cards start hidden and rise in rather than flashing first.

   The two columns interleave: a stack card, then a feature card, alternating
   down the section so it reads as one composition assembling rather than two
   lists racing. Same 14px / 0.7s / --ease as every other motion on the site. */
@keyframes pf-intel-in {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: none; }
}
.pf-intel__stack img,
.pf-intelcard {
  animation: pf-intel-in 0.7s var(--ease) both;
  animation-delay: var(--pf-d, 0s);
}
.pf-intel__stack img:nth-child(1) { --pf-d: 0.04s; }
.pf-intel__stack img:nth-child(2) { --pf-d: 0.10s; }
.pf-intel__stack img:nth-child(3) { --pf-d: 0.16s; }
.pf-intel__stack img:nth-child(4) { --pf-d: 0.22s; }
.pf-intelcard:nth-child(1) { --pf-d: 0.07s; }
.pf-intelcard:nth-child(2) { --pf-d: 0.13s; }
.pf-intelcard:nth-child(3) { --pf-d: 0.19s; }
.pf-intelcard:nth-child(4) { --pf-d: 0.25s; }
.pf-intelcard:nth-child(5) { --pf-d: 0.31s; }

@media (prefers-reduced-motion: reduce) {
  .pf-intel__stack img,
  .pf-intelcard { animation: none; }
}

.pf-intelcard__head { display: flex; align-items: center; gap: 12px; }
/* Icons removed 2026-08-31 — the heads are text only now. Hidden rather than
   pulled from the markup so the client can bring them back from one rule. */
.pf-intelcard__head img { display: none; }
.pf-intelcard__head img--legacy {
  width: 42px;
  height: 42px;
  flex: 0 0 auto;
  /* the white plate is drawn inside the SVG, so this has to be a filter */
  filter: drop-shadow(0 3px 8px rgba(13, 27, 62, 0.14));
}
.pf-intelcard h3 {
  font-family: "Outfit", sans-serif;
  font-size: 20px;
  font-weight: 500;
  line-height: 25px;
  color: var(--black);
}

/* --- AI model library row -----------------------------------------------
   The marquee itself is home.css's. Platform starts its single lane on the
   page gutter rather than home.css's own inset, so the first card lines up
   with the logo and every other section here. */
/* The row is full-bleed but the shell is centred and capped, so a flat gutter
   only lines up below --maxw. Add back half the leftover width above it. */
.pf-section.models .model-track {
  padding-left: calc(max(0px, (100vw - var(--pf-shell)) / 2) + var(--pf-gutter));
}
/* home.css fits ~6.2 cards to the viewport. Starting this row on the gutter,
   that lands the last card 7-18px short of the right edge at every common
   width — a gap, not the overhang the design wants. Slightly wider cards put a
   partial card under the edge instead, so the row reads as continuing. */
.pf-section.models .mcard {
  /* Exactly 5.5 cards across the visible track, so the sixth is always cut in
     half. Derived from the track's own measure rather than 100vw: above --maxw
     the shell centres while a viewport-based width keeps growing, so the cut
     drifted from half a card to a sliver to nothing at all across 1024-1920. */
  --avail: calc(100vw - max(0px, (100vw - var(--maxw)) / 2) - var(--gutter));
  --mw: clamp(150px, calc(var(--avail) / 5.5 - 26px), 340px);
}
/* Matched to home.css's 26px on 2026-08-31 at the client's request. The wider
   40px was here because this row is parked — where the last card falls is fixed
   rather than always mid-scroll — and 26px had left one ~92% visible, close
   enough to whole that it read as a clipping mistake rather than "the row
   continues". Re-check that edge if the card measure changes again. */
.pf-section.models .model-track { gap: 26px; }
/* home.css sits the cards in a 20px band; this row is the section's only
   content, so it gets more room above and below them. */
.pf-section.models .model-row { padding-block: 42px; }

/* =========================================================================
   Geospatial awareness & live flight inspections (Figma 4326:1551)
   The old telemetry and live-mission sections, merged: one map beside two
   detail tiles, the drone breaking the left edge and the mission tracker
   lying across the bottom.
   ========================================================================= */
.pf-geo { overflow: hidden; }
.pf-geo__art { position: relative; margin-top: clamp(12px, 1.6vw, 22px); }
.pf-geo__row {
  display: grid;
  grid-template-columns: minmax(0, 800fr) minmax(0, 374fr);
  gap: 1.34%;
}
.pf-geo__map { width: 100%; height: 100%; object-fit: cover; border-radius: 12.8px; display: block; }
/* 20px of the desktop row's 521px height, expressed as a percentage so the
   whole composition scales as one piece — at 390px the gap comes down with the
   images instead of swallowing them. A grid row-gap percentage resolves against
   the container's block size, which here is set by the grid row the stack is
   stretched into, so it is definite rather than circular. */
.pf-geo__stack { display: grid; grid-template-rows: 1fr 1fr; gap: 3.84%; min-height: 0; }
.pf-geo__stack img { width: 100%; height: 100%; object-fit: cover; border-radius: 12.8px; display: block; }

/* Positioned against the row rather than the section: percentages of the row's
   width keep the composition together at any breakpoint, and translateY works
   off the drone's own height so it never depends on the row resolving one. */
.pf-geo__drone {
  position: absolute;
  left: -11.25%;
  top: 0;
  width: 25.4%;
  height: auto;
  transform: translateY(-27%);
  pointer-events: none;
}
.pf-geo__tracker {
  position: absolute;
  left: 4.83%;
  bottom: -7.2%;
  width: 90.3%;
  height: auto;
  border-radius: 10px;
  box-shadow: 0 24px 44px rgba(0, 15, 35, 0.4);
}
/* the tracker hangs below the row, so the features need to clear it */
.pf-geo .pf-features { margin-top: clamp(60px, 7vw, 96px); }

/* =========================================================================
   Time series analysis (Figma 4326:1669)
   ========================================================================= */
.pf-trend { background: var(--light-100, #f4f6f9); }
.pf-trend__row {
  display: grid;
  grid-template-columns: minmax(0, 360fr) minmax(0, 552fr);
  gap: clamp(28px, 4vw, 48px);
  align-items: center;
}
.pf-trend__text { display: flex; flex-direction: column; gap: 16px; }
.pf-trend__art { position: relative; }
.pf-trend__chart { display: block; width: 100%; height: auto; border-radius: 12px; box-shadow: 0 24px 44px rgba(0, 15, 35, 0.12); }
/* the popup sits over the chart's last reading */
.pf-trend__popup {
  position: absolute;
  right: -2%;
  top: 39%;
  width: 20%;
  height: auto;
  border-radius: 8px;
  box-shadow: 0 10px 26px rgba(0, 15, 35, 0.18);
}

/* =========================================================================
   Automated AI inspection report (Figma 4326:1689)
   Three report pages laid on a desk, with the generation time called out.
   ========================================================================= */
.pf-reportart {
  position: relative;
  margin-top: clamp(28px, 4vw, 52px);
  /* the popup inside is sized in cqw so it scales with the artwork */
  container-type: inline-size;
}
.pf-reportart__bg {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 16px;
  /* No drop shadow on the desk itself — the three pages laid on it keep theirs. */
}
/* Three pages laid on the desk, bottom-aligned and overlapping left-to-right,
   the first one larger. Percentages are read off the mockup against the desk:
   the run sits 5.9% in from the left, 8.7% from the right, its baseline 8.4%
   up from the bottom, and each page tucks ~1.9% under the one before it. */
.pf-reportart__pages {
  position: absolute;
  left: 5.9%;
  right: 8.7%;
  bottom: 8.4%;
  display: flex;
  align-items: flex-end;
}
.pf-reportart__pages img {
  display: block;
  height: auto;
  border-radius: 4px;
  box-shadow: 0 12px 30px rgba(0, 15, 35, 0.18);
}
/* left page sits on top, each next one behind it */
.pf-reportart__pages img:nth-child(1) { width: 35.8%; z-index: 3; }
.pf-reportart__pages img:nth-child(2) { width: 33.3%; margin-left: -1.9%; z-index: 2; }
.pf-reportart__pages img:nth-child(3) { width: 34.8%; margin-left: -1.9%; z-index: 1; }
/* Live text rather than the baked export, the same way the homepage's .ptip
   card works: real copy, sized in cqw against the artwork so it tracks it. */
.pf-reportpop {
  position: absolute;
  /* Straddling the desk's right edge rather than sitting inside it. The overhang
     is kept under the page gutter so the card can never push the document wider
     than the viewport. */
  right: -3%;
  top: 21%;
  z-index: 1;
  display: flex;
  align-items: center;
  gap: 0.84cqw;
  padding: 0.88cqw 1.3cqw 1.05cqw 0.92cqw;
  border-radius: 0.88cqw;
  background: #fff;
  overflow: hidden;
  box-shadow: 0 0.85cqw 2.15cqw -0.85cqw rgba(10, 20, 50, 0.34);
}
.pf-reportpop__mark { flex: 0 0 auto; width: 2.37cqw; height: auto; display: block; }
.pf-reportpop__text { display: flex; flex-direction: column; gap: 0.12cqw; }
.pf-reportpop__label {
  font-family: "Outfit", sans-serif;
  font-size: 0.88cqw;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  line-height: 1.1;
  color: #2e88fe;
}
.pf-reportpop__value {
  font-family: "Outfit", sans-serif;
  font-size: 1.57cqw;
  font-weight: 500;
  line-height: 1.15;
  letter-spacing: -0.01em;
  color: #0d1b3e;
}
/* the brand ramp along the bottom edge, as the design draws it */
.pf-reportpop::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 0.26cqw;
  background: linear-gradient(90deg, #2e88fe, #8e46d0);
}

/* =========================================================================
   Data and APIs (Figma 4326:1754)
   ========================================================================= */
.pf-api {
  background: url("../img/platform/api/bg.webp") center bottom / cover no-repeat, var(--black);
}
/* The diagram is a layer, not a block in the flow. Cropped tight enough to sit
   in the flow, its glow ended on a hard rectangular edge; given the room to fall
   off it has to overlap the copy, so it sits behind the heading and the features
   with the section clipping whatever runs past.
 *
 * .pf-api__stage is the space the pills themselves occupy — the image is larger
 * than it, and offset so the pills land inside it. Both numbers come from where
 * the opaque artwork sits in the export: x 0.4-98.1%, y 31.8-77.5%. */
.pf-api { position: relative; overflow: hidden; }
.pf-api > .pf-shell { position: relative; z-index: 1; }
.pf-api__stage {
  position: relative;
  z-index: 0;
  /* 80% of the shell; the image is 102.4% of this, the artwork running a little
     past the pills on each side. */
  width: 80%;
  margin-inline: auto;
  aspect-ratio: 1660 / 529;

  /* The stage IS the pills band: the image is far taller than it, with the glow
     spilling above and below behind the copy. So these two margins are the real
     gap between the outer pills and the text, not just image padding. */
  margin-top: clamp(28px, 3.5vw, 54px);
  margin-bottom: clamp(48px, 6vw, 88px);
}
.pf-api__art {
  position: absolute;
  left: 50%;
  /* The Aug 26 export is used whole — uncropped, so its gradient falls off
     inside the file instead of ending on a hard edge. That means the pills are
     only part of it: they occupy x 5.6-89.7%, y 8.9-79.1% of the image, with
     glow all round out to x 3.0-92.5%, y 6.0-93.9%.

     So the image has to be sized off the PILL BAND, not the file: the band is
     84.1% of the width, hence 100/0.841 = 118.9% to make the pills span the
     stage, and pulled up 11.7% of the stage height to bring their top edge onto
     the stage's. Re-measure both if the artwork is re-exported — the Aug 28
     export kept the same width but sat 0.9% higher in its canvas. */
  top: -11.7%;
  translate: -50% 0;
  width: 118.9%;
  max-width: none;
  height: auto;
  pointer-events: none;
}
.pf-api .pf-features { margin-top: 0; }

.pf-api .pf-features { margin-top: clamp(20px, 3vw, 36px); }

/* --- feature triples (inspection-cards, telemetry, reports) ------------ */
.pf-features {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(24px, 4.5vw, 64px);
  margin-top: clamp(28px, 3.5vw, 44px);
  list-style: none;
}
.pf-features--stack { grid-template-columns: 1fr; gap: 26px; margin-top: 0; align-content: center; }
.pf-feature { display: flex; flex-direction: column; gap: 6px; }
.pf-features--stack .pf-feature { display: flex; flex-direction: column; gap: 6px; padding-top: 16px; }
/* Sized on the icon itself, not on a variant. Scoped to --stack, the plain
   grid left the SVG unconstrained and it grew to fill its column. */
.pf-feature__icon { width: 42px; height: 42px; margin-bottom: 10px; flex: 0 0 auto; }
/* Same treatment as the Intelligence cards' icons: the white plate is drawn
   inside the SVG, so the lift has to be a filter, not a box-shadow. */
.pf-feature__icon--gradient { filter: drop-shadow(0 3px 8px rgba(13, 27, 62, 0.14)); }
/* Hidden 2026-08-27. Scoped to the section rather than to the --gradient class,
   so the icons stay available if that treatment is reused elsewhere. The markup
   is untouched — delete this rule to bring them back. */
.pf-reports .pf-feature__icon { display: none; }
/* Same blue-to-purple ramp as the dashboard's stat rules. */
.pf-feature__rule { height: 4px; background: linear-gradient(90deg, #2e88fe 0%, #8e46d0 100%); margin-bottom: 10px; }
.pf-feature h3 {
  font-family: "Outfit", sans-serif;
  font-size: 20px;
  font-weight: 500;
  line-height: 25px;
  color: var(--black);
}

/* --- checklist (live-mission) ----------------------------------------- */
.pf-checks { list-style: none; display: flex; flex-direction: column; gap: 12px; }
.pf-check {
  display: flex;
  gap: 10px;
  align-items: center;
  font-family: "DM Sans", "Outfit", sans-serif;
  font-variation-settings: "opsz" 14;
  font-size: 16px;
  font-weight: 500;
  line-height: 22px;
  color: var(--gray);
}
.pf-check__icon { flex: 0 0 auto; width: 22px; height: 22px; fill: var(--blue); }

/* =========================================================================
   Video playlist (Figma 4277:2891)

   A featured video beside a list of three. All four open the modal below —
   the list is a way in, not a way to swap the hero.
   ========================================================================= */
.pf-videohead { display: flex; align-items: center; justify-content: space-between; gap: 24px; }
/* The section's own art: a magenta bloom on the dark ground, anchored left of
   centre where the design puts it. Sits over --black so it still reads as one
   of the dark bands if the image is slow. */
.pf-videosection {
  padding-bottom: clamp(66px, 8vw, 104px);
  background:
    url("../img/platform/video/bg.webp") left center / cover no-repeat,
    var(--black);
}
.pf-videos { display: grid; grid-template-columns: minmax(0, 700fr) minmax(0, 434fr); gap: 26px; margin-top: 26px; }

/* --- the featured video ------------------------------------------------ */

/* The stage the poster sits in, and that the iframe replaces it with. Both are
   the same box, so swapping one for the other does not move anything. */
.pf-vplayer { position: relative; }
.pf-vplayer iframe {
  display: block;
  width: 100%;
  aspect-ratio: 700 / 400;
  border: 0;
  border-radius: 12.8px;
  background: #000;
}


/* --- the playlist ------------------------------------------------------ */
/* Top-aligned against the featured video, not centred in the leftover height. */
/* The four films divide the column's height between them, so the first sits on
   the video's top edge and the last on its bottom edge. The row's height is the
   video's, since that is the taller of the two columns at desktop widths.

   min-height on the item is the floor: it is what the thumbnail, the meta line
   and a two-line title actually need. Below roughly 1000px the video gets
   shorter than 4 x that floor, and rather than crush the text the list simply
   stays its natural height and the video sits shorter — which is what it did
   before this rule existed. */
.pf-vlist { display: flex; flex-direction: column; gap: 16px; list-style: none; height: 100%; }
.pf-vlist > li { flex: 1 1 0; min-height: 78px; display: flex; }
.pf-vlist > li > .pf-vitem { height: 100%; }

/* The two-column layout runs down to 981px, and at the bottom of that range the
   video is shorter than four items at their normal floor — 315px against 360.
   Tightening the gap and the padding buys the ~45px needed, so the column still
   lands exactly on the video's edges instead of overhanging it. */
@media (min-width: 981px) and (max-width: 1150px) {
  .pf-vlist { gap: 10px; }
  .pf-vlist > li { min-height: 68px; }
  .pf-vlist > li > .pf-vitem { padding: 6px; gap: 12px; }
}
.pf-vitem {
  display: flex;
  gap: 16px;
  align-items: center;
  width: 100%;
  padding: 10px;
  border: 1px solid rgba(136, 152, 170, 0.25);
  border-radius: 8px;
  background: rgba(255, 255, 255, 0);
  text-align: left;
  cursor: pointer;
  font: inherit;
  transition: background-color 0.2s var(--ease), border-color 0.2s var(--ease);
}
.pf-vitem { box-sizing: border-box; text-decoration: none; color: inherit; }

/* the design's hover: a blue wash behind a blue hairline */
.pf-vitem:hover,
.pf-vitem:focus-visible {
  background: rgba(46, 136, 254, 0.15);
  border-color: var(--blue);
}
.pf-vitem:focus-visible { outline: 2px solid var(--blue); outline-offset: 2px; }
/* The film currently in the player. Same wash as hover so the row reads as one
   control, with a solid hairline to say which one is actually loaded. */
.pf-vitem.is-active {
  background: rgba(46, 136, 254, 0.14);
  border-color: var(--blue);
}
/* Height-led so it shrinks with the row, keeping the design's 150x80 shape.
   The cap stops it growing past the design size on a very tall column. */
.pf-vitem__thumb {
  flex: 0 0 auto;
  height: 100%;
  max-height: 80px;
  width: auto;
  aspect-ratio: 150 / 80;
  border-radius: 6px;
  overflow: hidden;
  background: var(--gray);
}
.pf-vitem__thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.pf-vitem__text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.pf-vitem__meta {
  font-family: "DM Sans", "Outfit", sans-serif;
  font-variation-settings: "opsz" 14;
  font-size: 12px;
  font-weight: 500;
  color: var(--gray-600);
}
.pf-vitem__title {
  font-family: "Outfit", sans-serif;
  font-size: 16px;
  font-weight: 500;
  line-height: 1.25;
  color: var(--white);
}


@media (max-width: 860px) {
  .pf-videos { grid-template-columns: 1fr; }
  /* 2.5-up would leave slivers on a phone — back to roughly one and a peek. */
  .pf-card { width: min(420px, 82vw); }
}
@media (max-width: 620px) {
  .pf-vitem__thumb { width: 110px; height: 62px; }
}

/* =========================================================================
   AI Model Library row — the homepage card, simplified: image, scrim, name.
   ========================================================================= */
.pf-models { margin-top: 8px; }
.pf-models__row {
  display: flex;
  gap: 26px;
  padding-block: 8px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-padding-inline: var(--pf-gutter);
  padding-inline: var(--pf-gutter);
  scrollbar-width: none;
  list-style: none;
}
.pf-models__row::-webkit-scrollbar { display: none; }
.pf-model {
  position: relative;
  flex: 0 0 auto;
  width: 200px;
  height: 288px;
  border-radius: 12.8px;
  overflow: hidden;
  background: var(--gray-600);
  scroll-snap-align: start;
  display: flex;
  align-items: flex-end;
  padding: 20.8px;
  box-shadow: 0 30px 26px -22px rgba(0, 15, 35, 0.35);
}
.pf-model img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
/* the design's scrim: transparent to 60%, then down to near-black */
.pf-model::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(to bottom, rgba(0, 15, 35, 0) 60%, rgba(0, 15, 35, 0.85) 100%);
}
.pf-model__name {
  position: relative;
  z-index: 1;
  font-family: "Outfit", sans-serif;
  font-size: 20px;
  font-weight: 500;
  line-height: 1.15;
  letter-spacing: -0.2px;
  color: var(--white);
}
.pf-models__foot { display: flex; justify-content: center; margin-top: 26px; }

/* =========================================================================
   Integrations — dark, a scrolling row of partner cards from the CMS
   ========================================================================= */
.pf-intro-row { display: flex; align-items: flex-end; justify-content: space-between; gap: 24px; padding-bottom: 16px; }
.pf-nav { display: flex; gap: 10px; }
.pf-nav__btn {
  display: grid;
  place-items: center;
  width: 44px;
  height: 37px;
  padding: 0;
  border: 1px solid var(--blue);
  border-radius: 80px;
  background: none;
  color: var(--blue);
  cursor: pointer;
  transition: background-color 0.2s var(--ease), color 0.2s var(--ease), opacity 0.2s var(--ease);
}
.pf-nav__btn:hover:not(:disabled) { background: var(--blue); color: var(--white); }
.pf-nav__btn:disabled { opacity: 0.35; cursor: default; }
.pf-nav__btn:focus-visible { outline: 2px solid var(--white); outline-offset: 3px; }
.pf-nav__icon { width: 20px; height: 19px; fill: currentColor; }
.pf-nav__icon--back { scale: -1 1; }

/* =========================================================================
   Inspection workflow — reuses .pslides / .pslide from home.css for the panel,
   with the design's ruled steps in place of the homepage's icon features.
   ========================================================================= */
.pf-steps {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 48px;
  margin-top: clamp(24px, 3vw, 40px);
  list-style: none;
}
.pf-step {
  display: flex;
  flex-direction: column;
  gap: 16px;
  padding-top: 16px;
  border: 0;
  background: none;
  text-align: left;
  cursor: pointer;
  font: inherit;
  color: inherit;
}
/* A progress track, not a state colour: the rule is the empty groove and the
   fill inside it runs the length of the slide, exactly as the homepage's
   .pfeatures__bar does. JS creates the fill, so the markup stays one span. */
.pf-step__rule {
  position: relative;
  height: 4px;
  border-radius: 4px;
  background: #dfe3ea;
  overflow: hidden;
}
.pf-step__fill {
  position: absolute;
  inset: 0;
  border-radius: 4px;
  background: linear-gradient(90deg, #c0dbff 0%, #2e88fe 50%, #8e46d0 100%);
  clip-path: inset(0 100% 0 0);
  will-change: clip-path;
}
.pf-step__n {
  font-family: "Outfit", sans-serif;
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 1.44px;
  text-transform: uppercase;
  color: var(--blue);
}
.pf-step h3 {
  font-family: "Outfit", sans-serif;
  font-size: 20px;
  font-weight: 500;
  line-height: 25px;
  color: var(--black);
  /* The "STEP n" label sat 22px off the heading — the column's 16px gap plus a
     +6px margin — against only 6px between the heading and its body copy, so it
     read as three separate blocks. -4px nets 12px: the label reads as belonging
     to the heading, and the step still separates cleanly from the one above. */
  margin-top: -4px;
}
/* The step is a flex column with gap:16px, so a plain margin-top left 22px
   under the heading where the feature columns sit at 6px. The negative margin
   cancels the inherited gap for this one child, matching .pf-feature exactly;
   the rule, "Step N" and the heading keep the full 16px between them. */
.pf-step p { margin-top: -10px; }
.pf-step:focus-visible { outline: 2px solid var(--blue); outline-offset: 4px; border-radius: 4px; }

/* The panel the slides sit in. The gradient is its own export rather than a
   CSS ramp — the design's has a fine diagonal weave through it. */
.pf-panel {
  position: relative;
  max-width: var(--pf-shell);
  margin: clamp(26px, 3.6vw, 48px) auto 0;
  aspect-ratio: 960 / 518;
  border-radius: 16px;
  overflow: hidden;
  background: url("../img/platform/workflow/bg.webp") center / cover no-repeat, var(--black);
}
.pf-panel .pslide { position: absolute; inset: 0; }
.pf-panel .pslide__bg { width: 100%; height: 100%; object-fit: cover; }
/* the browser mock is 796 of the panel's 960, sitting flush on its bottom edge */
.pf-panel__ui {
  position: absolute;
  left: 50%;
  bottom: 0;
  translate: -50% 0;
  width: 83%;
  height: auto;
  border-radius: 12.8px 12.8px 0 0;
}

/* =========================================================================
   Responsive
   ========================================================================= */
@media (max-width: 980px) {
  /* Sized in cqw, the badge shrinks with the artwork; below this its label is
     about six pixels tall, so it is dropped rather than shown unreadable. */
  .pf-reportpop { display: none; }

  .pf-intel { grid-template-columns: 1fr; }
  .pf-trend__row { grid-template-columns: 1fr; }
  .pf-panel__ui { width: 84%; }

  /* 37px tall is under the 44px touch minimum. */
  .pf-nav__btn { height: 44px; }

  .pf-features { grid-template-columns: 1fr; }
  .pf-steps { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 28px; }
  .pf-videos { grid-template-columns: 1fr; }

  /* The drone reads as debris once the row is this narrow, and the tracker
     stops being legible long before that. */
  .pf-geo__drone { display: none; }

  /* At 80% the pill labels stop being readable on a phone well before the
     diagram stops fitting, so it takes the full measure down here. */
  .pf-api__stage { width: 100%; margin-block: clamp(28px, 5vw, 48px); }
  .pf-geo .pf-features { margin-top: clamp(40px, 6vw, 72px); }
}

@media (max-width: 760px) {
  /* The geospatial grid is NOT stacked or turned into a carousel on mobile —
     it scales down whole, keeping the desktop composition. The columns are
     already fr ratios and the row gap is a percentage, so the only thing that
     had to change was the stack's gap; see .pf-geo__stack. */
  .pf-geo__tracker { position: static; width: 100%; margin-top: 16px; }
  .pf-geo .pf-features { margin-top: clamp(28px, 5vw, 44px); }

  /* the fade would eat most of a short stack at this width */
  .pf-intel__stack { max-height: none; }
  .pf-intel__stack::after { display: none; }
  .pf-intel__stack img:not(:first-child) { width: 100%; margin-left: 0; }

  .pf-trend__popup { display: none; }
}

@media (max-width: 620px) {
  .pf-steps { grid-template-columns: 1fr; }
  /* The tracker is a very wide strip; squeezed to a phone its labels are about
     two pixels tall and it reads as noise rather than a timeline. */
  .pf-geo__tracker { display: none; }
  .pf-videohead, .pf-intro-row { flex-direction: column; align-items: flex-start; gap: 14px; }
  .pf-video__item { grid-template-columns: 110px minmax(0, 1fr); }
  /* the three report pages are unreadable at this width; the desk still reads */
  .pf-reportart__pages { gap: 1%; }
}

/* =========================================================================
   Mobile: two sections adopt the homepage's carousel patterns (Aug 26)

   860px is the homepage's own breakpoint for the platform slideshow and The
   Latest, and these are meant to read as the same components, so they switch
   at the same width rather than at platform.css's 980/760/620 steps. This
   block sits last so it wins over the 760px rules at phone widths.
   ========================================================================= */
.pf-flowmobile { display: none; }

@media (max-width: 860px) {
  /* --- Inspection workflow: panel + 4 stacked steps -> one slide at a time -- */
  .pf-panel,
  .pf-steps { display: none; }

  .pf-flowmobile { display: block; margin-top: clamp(26px, 3.6vw, 48px); }
  .pf-flowcar {
    display: flex;
    gap: 16px;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
  }
  .pf-flowcar::-webkit-scrollbar { display: none; }

  .pf-flowslide {
    flex: 0 0 100%;
    scroll-snap-align: center;
    display: flex;
    flex-direction: column;
    gap: 18px;
  }
  /* same frame the desktop panel draws, so the mock still sits on its bottom edge */
  .pf-flowslide__panel {
    display: flex;
    align-items: flex-end;
    justify-content: center;
    aspect-ratio: 960 / 518;
    border-radius: 16px;
    overflow: hidden;
    background: url("../img/platform/workflow/bg.webp") center / cover no-repeat, var(--black);
  }
  .pf-flowslide__panel img {
    display: block;
    width: 83%;
    height: auto;
    border-radius: 12.8px 12.8px 0 0;
  }
  .pf-flowslide__text { display: flex; flex-direction: column; gap: 6px; }
  .pf-flowslide__text h3 { margin-top: 4px; }
  .pf-flowslide__bar {
    height: 4px;
    border-radius: 4px;
    margin-bottom: 8px;
    background: linear-gradient(90deg, #C0DBFF 0%, #2E88FE 50%, #8E46D0 100%);
  }

  .pf-flowcar__dots { display: flex; justify-content: center; gap: 8px; margin-top: 22px; }
  .pf-flowcar__dots button {
    width: 8px; height: 8px; padding: 0; border: 0; border-radius: 20px;
    background: #c8d1dd;
    transition: background-color 0.25s var(--ease), width 0.25s var(--ease);
  }
  .pf-flowcar__dots button.is-active { background: var(--blue); width: 24px; }
  .pf-flowcar__dots button:focus-visible { outline: 2px solid var(--blue); outline-offset: 3px; }

}

@media (prefers-reduced-motion: reduce) {
  .pf-flowcar { scroll-behavior: auto; }
}
