/* ══════════════════════════════════════════════════════════════════════════════════════════
   piforge.app — homepage hero and product mosaic
   ══════════════════════════════════════════════════════════════════════════════════════════

   Everything here is scoped under #pf-lp and every keyframe is prefixed pflp-. That is not
   tidiness: this page also loads Tailwind from a CDN, Tailwind ships a keyframe called `ping`,
   and the schematic layer had one too. Whichever stylesheet loaded last would have won, and the
   alarm ring would have animated the wrong property with nothing to show for it in the source.

   The mosaic is five tiles. Each one draws a schematic of what a product does, keeps that drawing
   in motion, then dissolves into a screenshot of the real thing and back again — on its own phase,
   so the grid never flips as a block. Pointing at a tile holds it. */

/* ── palette ────────────────────────────────────────────────────────────────────────────────
     Near-black navy ground, an electric blue used at FULL BLEED for whole sections, white bands for
     relief. PIForge keeps four hues for one job only — the streams in the schematics and the family
     stripe in the index — so the code that makes the catalogue readable survives inside the
     borrowed register instead of fighting it. */
#pf-lp {
    --navy:   #051c2c;
    --navy-2: #0a2739;
    --sheet:  #041823;   /* the drawing sheet */
    --blue:   #2251ff;
    --blue-d: #1a41d8;
    --white:  #ffffff;
    --ink:    #ffffff;
    --slate:  #a9bccb;
    --rule:   #17384c;

    --teal:   #2dd4bf;   /* material & flow */
    --ochre:  #e0b155;   /* time & events */
    --clay:   #ef8a6a;   /* limits & alarms */
    --indigo: #86b0dd;   /* signal */
    --focus:  #6d8dff;

    /* Aptos first, as asked. It is Microsoft 365's face and ships with recent Office, so most
       readers on Windows get it; the rest fall through to the nearest grotesques rather than to a
       serif, which keeps the page's proportions intact either way. */
    --sans: Aptos, "Aptos Display", "Segoe UI Variable", "Segoe UI",
            -apple-system, BlinkMacSystemFont, system-ui, Helvetica, Arial, sans-serif;
    --mono: "Cascadia Mono", Consolas, "SF Mono", ui-monospace, monospace;
  }

#pf-lp { background: var(--navy); color: var(--ink); font-family: var(--sans);
         font-size: 16px; line-height: 1.55; -webkit-font-smoothing: antialiased;
         padding: 96px 0 64px; }
#pf-lp *, #pf-lp *::before, #pf-lp *::after { box-sizing: border-box; }
#pf-lp p { margin: 0; }
#pf-lp a { color: inherit; text-decoration: none; }
#pf-lp :focus-visible { outline: 2px solid var(--focus); outline-offset: 3px; }
@media (max-width: 760px) { #pf-lp { padding: 88px 0 52px; } }
#pf-lp .spine { max-width: 1240px; margin: 0 auto; padding: 0 34px; }
@media (max-width: 560px) {
    #pf-lp .spine { padding: 0 20px; }
  }
#pf-lp .kicker { display: block; font-size: 11px; font-weight: 700; letter-spacing: .14em;
            text-transform: uppercase; color: var(--white); margin-bottom: 8px; }
#pf-lp .kicker.t { color: var(--teal); }
#pf-lp .kicker.o { color: var(--ochre); }
#pf-lp .kicker.c { color: var(--clay); }
#pf-lp .kicker.i { color: var(--indigo); }
#pf-lp h1 { font-weight: 600; font-size: clamp(2.4rem, 4.6vw, 3.7rem); line-height: 1.06;
       letter-spacing: -.028em; margin: 0; text-wrap: balance; }
#pf-lp h2 { font-weight: 600; font-size: clamp(1.7rem, 2.6vw, 2.25rem); line-height: 1.16;
       letter-spacing: -.022em; margin: 0; text-wrap: balance; }
#pf-lp h3 { font-weight: 600; font-size: 1.1rem; line-height: 1.28; margin: 0;
       letter-spacing: -.008em; text-wrap: balance; }
#pf-lp .lede { color: var(--slate); font-size: 1rem; line-height: 1.62; max-width: 40em; }
/* ── hero copy ──────────────────────────────────────────────────────────────────────────── */
/* One column, not two. The right-hand cell held a drawing title block; with that gone a grid
     would leave it empty, and an empty cell is exactly what reads as an unfinished layout. */
#pf-lp .hero .lede { margin-top: 22px; max-width: 44em; }
/* ── the hero ───────────────────────────────────────────────────────────────────────────────
     The old version was a headline, a paragraph and a bare arrow, all of which faded in together.
     It read as a caption. This one is staged: an eyebrow with a rule that draws itself, a headline
     whose two lines rise out of their own clipping boxes, then the turn of the argument, then the
     detail, then somewhere to go. Every step is a one-shot reveal that settles and stops — a
     looping headline used to live here and was taken out for good reason. */
#pf-lp .hero .eyebrow { display: flex; align-items: center; gap: 14px;
                   font-family: var(--mono); font-size: 11px; letter-spacing: .16em;
                   text-transform: uppercase; color: var(--teal); margin: 0 0 15px;
                   opacity: 0; animation: pflp-appear .6s ease-out .05s forwards; }
#pf-lp .hero .eyebrow::after { content: ""; height: 1px; flex: 1; max-width: 190px;
                          background: currentColor; transform: scaleX(0); transform-origin: left;
                          animation: pflp-rule .8s cubic-bezier(.16,1,.3,1) .35s forwards; }
#pf-lp .hero h1 { font-size: clamp(2.1rem, 3.9vw, 3.3rem); line-height: 1.05; letter-spacing: -.032em; }
#pf-lp .hero .ln { display: block; overflow: hidden; padding-bottom: .06em; }
#pf-lp .hero .ln > span { display: block; transform: translateY(112%);
                     animation: pflp-lift .9s cubic-bezier(.16,1,.3,1) forwards; }
#pf-lp .hero .ln:nth-of-type(1) > span { animation-delay: .18s; }
#pf-lp .hero .ln:nth-of-type(2) > span { animation-delay: .30s; }
#pf-lp .hero { padding-bottom: 30px; }
/* The headline is revealed by a teal bar sweeping across it: the bar grows from the left, covers
     the line, then retracts to the right, uncovering the words as it goes. One moving element, so
     there is nothing to look untidy — and the line itself still rises out of its clipping box
     underneath, which is what gives the reveal weight rather than just motion. */
#pf-lp .hero h1 { font-size: clamp(1.9rem, 4.15vw, 3.7rem); line-height: 1.16;
             letter-spacing: -.035em; }
/* the bar sits on the LINE BOX, not on the h1: pinned to the h1 it left the descenders of y, p
     and g poking out below the sweep, which reads as a rendering fault rather than a reveal */
#pf-lp .hero .ln { display: block; position: relative; overflow: hidden; padding-bottom: .1em; }
#pf-lp .hero .ln > span { display: block; opacity: 0; transform: translateY(108%);
                     animation: pflp-lift .95s cubic-bezier(.16,1,.3,1) .18s forwards,
                                pflp-appear .01s linear .66s forwards; }
#pf-lp .hero .ln::after { content: ""; position: absolute; inset: 0; background: var(--teal);
                     transform: scaleX(0); transform-origin: left; pointer-events: none;
                     animation: pflp-wipe 1.15s cubic-bezier(.65,0,.25,1) .16s forwards; }
@keyframes pflp-wipe {
    0%        { transform: scaleX(0); transform-origin: left; }
    44%       { transform: scaleX(1); transform-origin: left; }
    44.01%    { transform: scaleX(1); transform-origin: right; }
    100%      { transform: scaleX(0); transform-origin: right; }
  }
@keyframes pflp-appear { to { opacity: 1; } }
@keyframes pflp-rule { to { transform: scaleX(1); } }
@keyframes pflp-lift { to { transform: none; } }
/* ── the mosaic ─────────────────────────────────────────────────────────────────────────────
     Deliberately uneven and deliberately off-register: one tall plate, then two staggered columns
     beside it. Every tile is a drawing that keeps resolving into the screen it came from, so the
     grid never sits still and never flips all at once — each tile runs on its own phase. */
#pf-lp .mosaic { display: grid; grid-template-columns: repeat(12, 1fr); gap: 18px;
            align-items: start; }
#pf-lp .m-hero { grid-column: 8 / -1; grid-row: 1 / span 2; align-self: stretch; }
#pf-lp .m-a { grid-column: 1 / span 4; aspect-ratio: 4 / 3; }
#pf-lp .m-b { grid-column: 5 / span 3; aspect-ratio: 1 / 1; margin-top: 54px; }
#pf-lp .m-c { grid-column: 1 / span 4; aspect-ratio: 3 / 2; }
#pf-lp .m-d { grid-column: 5 / span 3; aspect-ratio: 4 / 3; margin-top: 54px; }
@media (max-width: 1000px) {
    #pf-lp .mosaic { grid-template-columns: repeat(6, 1fr); }
    #pf-lp .m-hero { grid-column: 1 / -1; grid-row: auto; aspect-ratio: 4 / 5; }
    #pf-lp .m-a, #pf-lp .m-c { grid-column: 1 / span 3; }
    #pf-lp .m-b, #pf-lp .m-d { grid-column: 4 / span 3; margin-top: 0; }
  }
@media (max-width: 620px) {
    #pf-lp .mosaic { grid-template-columns: 1fr; }
    #pf-lp .m-hero { aspect-ratio: 3 / 4; }
    #pf-lp .m-a, #pf-lp .m-b, #pf-lp .m-c, #pf-lp .m-d { grid-column: 1 / -1; aspect-ratio: 4 / 3; }
  }
#pf-lp .tile { position: relative; display: block; overflow: hidden;
          border: 1px solid var(--rule); background: var(--sheet); }
#pf-lp .tile .stage { position: absolute; inset: 0; }
#pf-lp .tile svg { display: block; width: 100%; height: 100%;
              transition: opacity .8s ease; }
/* `contain`, not `cover`. Every screenshot here is a wide application window, and the tiles are
     square or taller — cropping one to fill leaves a vertical sliver of a dialog, which is what
     made the earlier version unreadable. Letterboxed against the sheet colour it reads as a framed
     screen, and sitting high in the tile keeps it clear of the caption band. */
#pf-lp .tile .real { position: absolute; inset: 0; width: 100%; height: 100%;
                object-fit: contain; object-position: center 30%;
                background: var(--sheet);   /* same ground as the drawing, so the crossfade does not
                                              flash a different colour behind the two views */
                opacity: 0; transition: opacity .8s ease; }
#pf-lp .tile.is-real svg { opacity: 0; }
#pf-lp .tile.is-real .real { opacity: 1; }
/* The words sit on the picture, so the scrim has to be heavy enough to hold them over a light
     screenshot as well as over the drawing — and the drawings are laid out to keep their content
     clear of this band. */
#pf-lp .tile .scrim { position: absolute; inset: 0; pointer-events: none;
                 background: linear-gradient(to top,
                   rgba(4,18,28,.97) 0%, rgba(4,18,28,.90) 16%,
                   rgba(4,18,28,.55) 34%, rgba(4,18,28,0) 56%); }
#pf-lp .tile .foot { position: absolute; inset: auto 0 0 0; padding: 18px 20px 18px; }
#pf-lp .m-hero .foot { padding: 26px 26px 26px; }
#pf-lp .m-hero h3 { font-size: 1.42rem; }
#pf-lp .m-b h3, #pf-lp .m-d h3 { font-size: .98rem; }
/* which of the two the reader is looking at, said plainly */
#pf-lp .chip { position: absolute; top: 12px; left: 14px; z-index: 2;
          font-family: var(--mono); font-size: 9.5px; letter-spacing: .1em;
          text-transform: uppercase; color: var(--slate);
          border: 1px solid var(--rule); background: rgba(4,18,28,.7);
          padding: 3px 7px; }
#pf-lp .tile.is-real .chip { color: var(--white); border-color: rgba(255,255,255,.3); }
#pf-lp .chip::after { content: "schematic"; }
#pf-lp .tile.is-real .chip::after { content: "live screen"; }
#pf-lp .tile:hover .chip { border-color: var(--blue); }
/* ── the drawing animations ────────────────────────────────────────────────────────────────
     Everything starts paused, so a drawing further down the page has not already played itself out
     before the reader arrives. The gate has to out-specify the per-element rules below, because the
     `animation` shorthand resets play-state to running and a plain `.fig-anim *` rule loses to
     every one of them. */
#pf-lp .tile:not(.is-playing) .fig-anim * { animation-play-state: paused; }
@keyframes pflp-fade { to { opacity: 1; } }
@keyframes pflp-show { to { opacity: .95; } }
@keyframes pflp-draw { to { stroke-dashoffset: 0; } }
@keyframes pflp-drift { to { stroke-dashoffset: -24; } }
@keyframes pflp-breathe { 0%, 100% { opacity: .95; } 50% { opacity: .35; } }
@keyframes pflp-ping { 0% { r: 3; opacity: 1; } 70%, 100% { r: 10; opacity: 0; } }
/* PIFlow — the plant is understood vessel by vessel, then stream by stream */
#pf-lp .fig-anim .vessel { opacity: 0; animation: pflp-fade .45s ease-out forwards; }
#pf-lp .fig-anim .vessel:nth-of-type(1) { animation-delay: .08s; }
#pf-lp .fig-anim .vessel:nth-of-type(2) { animation-delay: .16s; }
#pf-lp .fig-anim .vessel:nth-of-type(3) { animation-delay: .24s; }
#pf-lp .fig-anim .vessel:nth-of-type(4) { animation-delay: .32s; }
#pf-lp .fig-anim .vessel:nth-of-type(5) { animation-delay: .40s; }
#pf-lp .fig-anim .stream { stroke-dasharray: 100; stroke-dashoffset: 100;
                      animation: pflp-draw .8s cubic-bezier(.4,0,.2,1) forwards; }
#pf-lp .fig-anim .s1 { animation-delay: .55s; }
#pf-lp .fig-anim .s2 { animation-delay: .66s; }
#pf-lp .fig-anim .s3 { animation-delay: 1.05s; }
#pf-lp .fig-anim .s4 { animation-delay: 1.16s; }
#pf-lp .fig-anim .s5 { animation-delay: 1.55s; }
#pf-lp .fig-anim .flow { stroke-dasharray: 3 9; opacity: 0;
                    animation: pflp-show .5s linear 2.0s forwards, pflp-drift 2.6s linear 2.0s infinite; }
#pf-lp .fig-anim .tip { opacity: 0; animation: pflp-fade .3s ease-out forwards; }
#pf-lp .fig-anim .t1, #pf-lp .fig-anim .t2 { animation-delay: 1.30s; }
#pf-lp .fig-anim .t3, #pf-lp .fig-anim .t4 { animation-delay: 1.80s; }
#pf-lp .fig-anim .t5 { animation-delay: 2.30s; }
#pf-lp .fig-anim .signal { stroke-dasharray: 100; stroke-dashoffset: 100;
                      animation: pflp-draw .7s ease-out 1.9s forwards; }
#pf-lp .fig-anim .signal-dot { opacity: 0; animation: pflp-fade .35s ease-out 2.5s forwards; }
#pf-lp .fig-anim .draft { opacity: 0; animation: pflp-show .5s ease-out 2.7s forwards,
                                            pflp-breathe 2.6s ease-in-out 3.2s infinite; }
#pf-lp .fig-anim .draft-label { opacity: 0; animation: pflp-fade .45s ease-out 2.9s forwards; }
#pf-lp .fig-anim .tag { opacity: 0; animation: pflp-fade .45s ease-out .75s forwards; }
/* Sankey — the bands fill from source to sink, so width reads as quantity */
#pf-lp .fig-anim .band { stroke-dasharray: 100; stroke-dashoffset: 100;
                    animation: pflp-draw 1.0s cubic-bezier(.4,0,.2,1) forwards; }
#pf-lp .fig-anim .b1 { animation-delay: .30s; }
#pf-lp .fig-anim .b2 { animation-delay: .44s; }
#pf-lp .fig-anim .b3 { animation-delay: 1.10s; }
#pf-lp .fig-anim .b4 { animation-delay: 1.24s; }
#pf-lp .fig-anim .node { opacity: 0; animation: pflp-fade .45s ease-out .08s forwards; }
#pf-lp .fig-anim .bar { opacity: 0; animation: pflp-fade .45s ease-out .95s forwards; }
#pf-lp .fig-anim .num { opacity: 0; animation: pflp-fade .45s ease-out forwards; }
#pf-lp .fig-anim .n1 { animation-delay: .80s; }
#pf-lp .fig-anim .n2 { animation-delay: .90s; }
#pf-lp .fig-anim .n3 { animation-delay: 1.45s; }
#pf-lp .fig-anim .n4 { animation-delay: 1.90s; }
#pf-lp .fig-anim .n5 { animation-delay: 2.05s; }
/* AlarmIQ — the flood arrives in time order, which is the whole point */
#pf-lp .fig-anim .lane { opacity: 0; animation: pflp-fade .35s ease-out forwards; }
#pf-lp .fig-anim .l1 { animation-delay: .08s; }
#pf-lp .fig-anim .l2 { animation-delay: .16s; }
#pf-lp .fig-anim .l3 { animation-delay: .24s; }
#pf-lp .fig-anim .l4 { animation-delay: .32s; }
#pf-lp .fig-anim .chat { opacity: 0; animation: pflp-fade .28s ease-out forwards,
                                           pflp-breathe 1.3s ease-in-out infinite; }
#pf-lp .fig-anim .chat:nth-of-type(odd) { animation-delay: .65s, 2.1s; }
#pf-lp .fig-anim .chat:nth-of-type(even) { animation-delay: .85s, 2.4s; }
#pf-lp .fig-anim .ev { opacity: 0; animation: pflp-fade .3s ease-out forwards; }
#pf-lp .fig-anim .e1 { animation-delay: 1.45s; }
#pf-lp .fig-anim .e2 { animation-delay: 1.75s; }
#pf-lp .fig-anim .e3 { animation-delay: 2.00s; }
/* this one fades rather than draws: the draw animation sets stroke-dasharray in CSS, which beats
     the presentation attribute and would flatten the dashes into a solid rule — and a solid rule
     reads as a limit, not as "the flood starts here" */
#pf-lp .fig-anim .flood-line { opacity: 0; animation: pflp-fade .4s ease-out 2.25s forwards; }
#pf-lp .fig-anim .verdict { opacity: 0; animation: pflp-fade .45s ease-out 2.6s forwards; }
#pf-lp .fig-anim .verdict-ring { opacity: 0; animation: pflp-ping 2.1s ease-out 2.9s infinite; }
/* Correlation — the cloud arrives, then the line it implies, then the number */
#pf-lp .fig-anim .frame { opacity: 0; animation: pflp-fade .4s ease-out .08s forwards; }
#pf-lp .fig-anim .cloud { opacity: 0; animation: pflp-fade .9s ease-out .45s forwards; }
#pf-lp .fig-anim .fit { stroke-dasharray: 100; stroke-dashoffset: 100;
                     animation: pflp-draw 1.0s cubic-bezier(.4,0,.2,1) 1.25s forwards; }
#pf-lp .fig-anim .stat { opacity: 0; animation: pflp-fade .45s ease-out 2.15s forwards; }
/* Gantt — the shift fills in from the start of the window */
#pf-lp .fig-anim .track { opacity: 0; animation: pflp-fade .35s ease-out forwards; }
#pf-lp .fig-anim .k1 { animation-delay: .08s; }
#pf-lp .fig-anim .k2 { animation-delay: .16s; }
#pf-lp .fig-anim .k3 { animation-delay: .24s; }
#pf-lp .fig-anim .blk { opacity: 0; animation: pflp-fade .3s ease-out forwards; }
#pf-lp .fig-anim .blk:nth-of-type(1) { animation-delay: .50s; }
#pf-lp .fig-anim .blk:nth-of-type(2) { animation-delay: .70s; }
#pf-lp .fig-anim .blk:nth-of-type(3) { animation-delay: .90s; }
#pf-lp .fig-anim .blk:nth-of-type(4) { animation-delay: 1.10s; }
#pf-lp .fig-anim .blk:nth-of-type(5) { animation-delay: 1.30s; }
#pf-lp .fig-anim .axis { opacity: 0; animation: pflp-fade .4s ease-out 1.55s forwards; }
/* ── the permanent layer ───────────────────────────────────────────────────────────────────
     The reveal builds the drawing; this keeps it alive afterwards. Without it each tile assembled
     itself once and then sat perfectly still until the crossfade came round again, which read as
     "the animation stopped".

     A packet is one short dash chased along a normalised path: with pathLength="100" and a
     6-and-100 pattern, driving the offset from 106 to 0 walks that dash from the start of the line
     clean off the end, once per cycle, for ever. */
#pf-lp .fig-anim .packet { stroke-dasharray: 6 100; stroke-dashoffset: 106; opacity: 0;
                      animation: pflp-fade .4s linear 1.9s forwards,
                                 pflp-packet 2.1s cubic-bezier(.45,0,.55,1) 1.9s infinite; }
#pf-lp .fig-anim .packet.p1 { animation-delay: 1.90s, 1.90s; }
#pf-lp .fig-anim .packet.p2 { animation-delay: 2.05s, 2.05s; }
#pf-lp .fig-anim .packet.p3 { animation-delay: 2.35s, 2.35s; }
#pf-lp .fig-anim .packet.p4 { animation-delay: 2.50s, 2.50s; }
#pf-lp .fig-anim .packet.p5 { animation-delay: 2.80s, 2.80s; }
@keyframes pflp-packet { from { stroke-dashoffset: 106; } to { stroke-dashoffset: 0; } }
/* the process node keeps taking the load */
#pf-lp .fig-anim .throb { animation: pflp-fade .45s ease-out .95s forwards, pflp-throb 2.4s ease-in-out 1.6s infinite; }
@keyframes pflp-throb { 0%, 100% { opacity: 1; } 50% { opacity: .62; } }
/* the timelines keep being re-evaluated, so the scan keeps crossing them */
#pf-lp .fig-anim .scan { transform-box: view-box; transform-origin: 0 0; opacity: 0;
                    animation: pflp-fade .4s linear 2.4s forwards, pflp-scan 4.2s linear 2.4s infinite; }
#pf-lp .fig-anim .scan.g { animation: pflp-fade .4s linear 1.8s forwards, pflp-scanG 5.4s linear 1.8s infinite; }
@keyframes pflp-scan { from { transform: translateX(0); } to { transform: translateX(336px); } }
@keyframes pflp-scanG { from { transform: translateX(0); } to { transform: translateX(332px); } }
/* the correlation window slides the way the symbol computes it */
#pf-lp .fig-anim .roll { transform-box: view-box; transform-origin: 0 0; opacity: 0;
                    animation: pflp-fade .5s linear 2.3s forwards, pflp-roll 5.6s ease-in-out 2.3s infinite; }
@keyframes pflp-roll { 0% { transform: translateX(0); } 50% { transform: translateX(238px); }
                    100% { transform: translateX(0); } }
#pf-lp .fig-anim .cloud circle { animation: pflp-twinkle 2.8s ease-in-out infinite; }
#pf-lp .fig-anim .cloud circle:nth-child(3n) { animation-delay: .5s; }
#pf-lp .fig-anim .cloud circle:nth-child(3n+1) { animation-delay: 1.2s; }
@keyframes pflp-twinkle { 0%, 100% { opacity: 1; } 50% { opacity: .45; } }
/* ── entrances with some snap ──────────────────────────────────────────────────────────────
     Plain opacity fades made a five-tile grid feel inert. Blocks now arrive with direction: the
     alarm cascade slides in from where its time axis starts, and the shift wipes across. */
#pf-lp .fig-anim .ev, #pf-lp .fig-anim .blk { transform-box: fill-box; }
#pf-lp .fig-anim .ev { animation: pflp-slidein .45s cubic-bezier(.16,1,.3,1) forwards; }
#pf-lp .fig-anim .blk { transform-origin: left center;
                   animation: pflp-wipein .4s cubic-bezier(.16,1,.3,1) forwards; }
@keyframes pflp-slidein { from { opacity: 0; transform: translateX(-16px); }
                       to   { opacity: 1; transform: none; } }
@keyframes pflp-wipein { from { opacity: 0; transform: scaleX(0); }
                       to   { opacity: 1; transform: scaleX(1); } }
/* the signal keeps reporting */
#pf-lp .fig-anim .signal-dot { animation: pflp-fade .35s ease-out 2.5s forwards,
                                     pflp-throb 1.8s ease-in-out 3.0s infinite; }
/* ── reduced motion ────────────────────────────────────────────────────────────────────────
     Two goes at this were wrong in the same direction. First it switched the drawings off entirely,
     so on Windows Server — where "show animations" is off by default and Chrome therefore reports
     `reduce` — the schematics never played at all. Then it kept the reveal but killed everything
     that repeats, so they played once and froze, which is the same complaint again.

     The page's whole argument is the drawing working, so here the flag makes the motion CALMER
     rather than absent. What is left is small-amplitude by construction: a short dash travelling a
     thin line, a one-pixel scan, an opacity breath — no large moving areas, no parallax. Each runs
     at roughly half speed. The one genuinely loud effect, a ring that grows outward, is dropped. */
@media (prefers-reduced-motion: reduce) {
    #pf-lp .rise { animation: none; }
    /* the hero arrives finished rather than half-built: an animation-less .ln would otherwise stay
       translated 112% down and the headline would simply be missing */
    #pf-lp .hero .eyebrow { animation: none; opacity: 1; }
    #pf-lp .hero .ln::after { animation: none; transform: scaleX(0); }
    #pf-lp .hero .ln > span { animation: none; transform: none; opacity: 1; }
    #pf-lp .hero .eyebrow::after { animation: none; transform: scaleX(1); }
    #pf-lp .fig-anim .packet { animation-duration: .4s, 4.4s; }
    #pf-lp .fig-anim .flow { animation-duration: .5s, 5.4s; }
    #pf-lp .fig-anim .draft { animation-duration: .5s, 5.6s; }
    #pf-lp .fig-anim .chat { animation-duration: .28s, 3.0s; }
    #pf-lp .fig-anim .scan { animation-duration: .4s, 9.0s; }
    #pf-lp .fig-anim .scan.g { animation-duration: .4s, 11.0s; }
    #pf-lp .fig-anim .roll { animation-duration: .5s, 12.0s; }
    #pf-lp .fig-anim .throb, #pf-lp .fig-anim .signal-dot { animation-duration: .45s, 5.0s; }
    #pf-lp .fig-anim .cloud circle { animation-duration: 6.0s; }
    #pf-lp .fig-anim .verdict-ring { display: none; }
  }
#pf-lp .arrow-btn { display: inline-flex; align-items: center; justify-content: center;
               margin-top: 26px; width: 56px; height: 56px; border-radius: 50%;
               background: rgba(255,255,255,.12); color: var(--white); font-size: 1.25rem;
               transition: background .18s ease, transform .18s ease; }
#pf-lp .arrow-btn:hover { background: var(--blue); transform: translateX(3px); }
@keyframes bob { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-10px); } }
@keyframes blip { 0%, 100% { opacity: 1; } 50% { opacity: .35; } }
@keyframes pflp-rise { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: none; } }
#pf-lp .rise { animation: pflp-rise .7s cubic-bezier(.16,1,.3,1) both; }
#pf-lp .d1 { animation-delay: .05s; }
#pf-lp .d2 { animation-delay: .14s; }
#pf-lp .d3 { animation-delay: .23s; }
@media (prefers-reduced-motion: reduce) {
    #pf-lp .rise { animation: none; }
    #pf-lp .arrow-btn { transition: none; }
  }
