/* ============================================================================
   Pingo — Steel screen 1d, TOOLS.  Owns screens/tools.html and nothing else.
   Every selector is scoped under .pgs-tools and every custom property under
   --pgst-*, so nothing leaks into the site or into another screen's file.
   There are no @keyframes at all (see section 11), so there is nothing to
   collide either.  Load AFTER styles.css.

   Rebuilt from the canvas C:/Dev/pingo/design/Pingo Screens.dc.html:
     * the screen markup      lines 356-422  (<div class="opt" id="1d">)
     * the shared head CSS    lines 32-45    (.phone .screen .bloom .bloom2 .sb
                                              .body .card .mono .lbl .nav .nvi
                                              .nvl .tool)
   Screen spec: design/PINGO-STEEL-HANDOVER.md section 4 "Tools (1d)".
   Tokens: same file section 2.  Layout contract: same file section 5.
   Every value below is the canvas's own literal px / hex / rgba / gradient.

   ---------------------------------------------------------------------------
   THE CARDINAL RULE, from C:/Dev/pingo/MASTER-CONTEXT.md:
       "Motion is a liveness cue: nothing hatched, withheld or stale may
        animate."

   On 1d that rule resolves to a number, and the number is ZERO.

   This file declares:
       0 @keyframes
       0 animation declarations
       0 transition declarations
       0 uses of animation-play-state (the forbidden shortcut) anywhere

   Nothing on this screen is running, measuring or arriving. It is a catalogue:
   a search field nobody has typed in, a filter chip row, a Recent card whose
   only reading is explicitly STALE ("LAST RUN 11 MIN AGO"), tiles offering
   tools nobody has started, and a duration warning on one long test. Every one
   of those is a case the rule names. Giving this screen an ambient loop would
   not just be a small infidelity, it would destroy the thing the gallery is
   for: 1a's streaming rows, 1b's drawing dial and 1f's landing ticks only read
   as LIVE because 1d sits beside them dead still.

   The canvas's 1d also has no radar logo mark. The animated 2.8s mark belongs
   to the Home header in "Pingo Home Redesign.dc.html" 6a; 1d's header is the
   23px "Tools" title at canvas line 365 and nothing else. So even the "app
   chrome may sweep" allowance goes unused here, because using it would mean
   INVENTING a mark the canvas does not have, purely to have something move.
   That is the exact instinct this screen exists to refuse.

   The two required gates are still declared, in sections 13 and 14, and they
   are byte-identical to each other apart from the media gate. On this screen
   they are no-ops by construction. Keep them: they are the safety net that
   catches motion if anyone ever adds it here without reading this header.

   ---------------------------------------------------------------------------
   ILLUSTRATIVE VALUES.  Unlike Home 6a, the canvas's 1d has no unfilled
   template holes, so NOTHING had to be invented. Every string and number below
   is the canvas's, verbatim:
     27 AVAILABLE · 4 RECENT · group counts 8 / 6 / 7 · Ping · 1.1.1.1 ·
     LAST RUN 11 MIN AGO · AVG 12 MS · Bufferbloat LATENCY UNDER LOAD ·
     Spectrum APS BY CHANNEL · Signal map WALK THE HOUSE · Trace route EVERY
     HOP OUT · Firewall test ~2.5 MIN · Breach check EMAIL EXPOSURE ·
     Port scan / Find cameras / Subnet.
   They are illustrative rather than measured, and the host page must say so.
   The sentence is on the root as data-pgs-caption.

   ---------------------------------------------------------------------------
   DELIBERATE DIVERGENCES from the canvas. Four, all recorded, none accidental:

     1. The fourth nav tab reads "Diagnose", not the canvas's "Ask"
        (canvas line 408). Required by the settled decision that merges Ask and
        Guided Diagnose into one surface named Diagnose with the AI parked and
        off by default: shipping a tab called "Ask" advertises a chatbot this
        build does not have. The ICON is kept verbatim (speech bubble + spark,
        the handover's Ask glyph) because swapping glyphs is a change to the
        app's icon set, not to this web page, and at 21px beside the word
        "Diagnose" it reads as "talk to the diagnosis", not as an AI badge.
        Flagged for the integrator: mock.html line 310 still labels the same tab
        "Ask", so Home and Tools will disagree until that is harmonised. That
        file is not mine to edit.
        At 9.5px/w600 "Diagnose" measures ~46px inside a ~66px tab column, so it
        fits without wrapping or shrinking the label.

     2. Both tool grids use `minmax(0, 1fr)` where the canvas writes bare `1fr`
        (canvas lines 385, 392). Bare 1fr is min-content-floored, so a tile whose
        mono description cannot shrink pushes its column wider than its
        neighbour; "LATENCY UNDER LOAD" beside "APS BY CHANNEL" measured 4px
        unequal. minmax(0, 1fr) keeps the two columns identical, which is what
        "grid-template-columns:1fr 1fr" was written to mean. Same fix already
        recorded as an open fidelity item for the Home mock's metric grid in
        RESUME-WEBSITE.md.

     3. Sizing follows the 6a mock's proven approach rather than the canvas's
        fixed .phone/.screen pair: the screen is built at a true 375x812 with the
        authored 8.5-9.5px mono floor INTACT and scaled as a whole by
        --gal-scale, with the outer box sized in calc() so it occupies correct
        layout space. Nothing was re-specced smaller. 0.88 is a hard floor and
        section 1 enforces it in CSS.

     4. The two horizontally clipping rows (group chips, Discover chips) use
        `overflow: hidden` exactly as the canvas does (lines 372, 397) rather
        than becoming real scrollers. In the app they scroll; here they are a
        still plate of a scrollable row, and a scrollbar or a drag affordance
        would invite an interaction this fragment cannot honour.

   Not a divergence, but worth knowing: the canvas sets the mono tool
   descriptions and group counts at 8.5px, below the handover's "minimum 9px for
   any mono unit/caption" rule (handover section 2, Type). The canvas is the
   authority on pixels, so 8.5px is reproduced verbatim, and --gal-scale is
   floored at 0.88 for the same reason the site floors --mock-scale there: the
   0.76 and 0.68 steps put these captions at 6.5px and 5.8px.

   ---------------------------------------------------------------------------
   PUBLIC API — everything the integrator needs, so you never open these files.

     ELEMENTS / CLASSES
       .pgs-tools                 the fragment root. Occupies
                                  calc(375px * scale) x calc(812px * scale) of
                                  layout space. box-sizing is content-box so the
                                  optional bezel sits OUTSIDE that box.
       .pgs-tools--bezel          optional device bezel (adds padding + border
                                  outside the box). Off by default.
       .pgs-tools.is-offstage     stop all motion on honest final frames. On 1d
                                  this is a documented no-op, because 1d has no
                                  motion. Toggle it anyway for uniformity.
       .pgst-*                    every internal class. Do not target them.

     ATTRIBUTES ON THE ROOT (read them, do not remove them)
       data-pgs-screen="1d"       stable hook for the shell's tab wiring.
       data-pgs-name="Tools"      the tab's label, so the shell need not hardcode
                                  a string that lives here.
       data-pgs-caption           the exact "numbers are illustrative" sentence
                                  the host page must render visibly.
       role="img" + aria-label    the root IS the accessible description; the
                                  inner .pgst-screen is aria-hidden. If you wrap
                                  this fragment in a tab panel, do not add a
                                  second competing label.

     CSS CUSTOM PROPERTIES YOU MAY SET
       --gal-scale                set on .pgs-tools or ANY ancestor. Default .88.
                                  1 = the authored 375x812 at authored type.
                                  Values below .88 are clamped UP to .88; to
                                  defeat that, edit the one max() in section 1.
                                  If you would rather drive this from the site's
                                  existing knob, map it once in the shell:
                                      .gallery { --gal-scale: var(--mock-scale); }
       Everything else is --pgst-* and is internal. Read them if you like; the
       screen does not expect you to override them.

     WHAT THIS FILE DOES NOT DO
       No JS. No IntersectionObserver (CSS cannot see the viewport; the shell
       owns that). No fonts (the host page loads Sora 400-800 and JetBrains Mono
       500/700; index.html already does). No focus/hover states, because the
       fragment is a picture, not a control surface.
   ============================================================================ */


/* ---------------------------------------------------------------------------
   1. Outer box, scale, tokens, defensive reset

   Why an outer box plus an inner scaled screen: transform: scale() does not
   change layout size, so a bare scaled 812px screen would still reserve 812px
   and leave a gap. The box reserves the SCALED size in calc(); the screen is
   authored at true size inside it and scaled from its top-left corner.
   --------------------------------------------------------------------------- */

.pgs-tools {
  /* --pgst-scale is used by BOTH the box calc() and the transform, so they can
     never drift apart. max() enforces the 0.88 floor from RESUME-WEBSITE.md's
     fidelity fix #7: below it the 8.5px mono captions break the 9px rule that
     the floor exists to protect. Larger values pass through untouched. */
  --pgst-scale: max(.88, var(--gal-scale, .88));

  /* content-box so .pgs-tools--bezel's padding and border sit OUTSIDE the 375px */
  box-sizing: content-box;
  width: calc(375px * var(--pgst-scale));
  height: calc(812px * var(--pgst-scale));
  flex: none;
  position: relative;
  user-select: none;
  -webkit-user-select: none;

  /* Type reset. The host page's body sets line-height 1.6 and its own family;
     both would break this stack, and every negative letter-spacing below
     assumes Sora is actually loaded. */
  font-family: var(--pgst-font);
  font-size: 16px;
  font-weight: 400;
  line-height: normal;
  letter-spacing: normal;
  text-align: left;
  color: var(--pgst-ink);
  -webkit-font-smoothing: antialiased;

  --pgst-font: 'Sora', system-ui, -apple-system, 'Segoe UI', sans-serif;
  --pgst-mono: 'JetBrains Mono', ui-monospace, 'SF Mono', Consolas, monospace;

  /* Colour tokens, handover section 2. Only the ones 1d actually uses are
     declared; this screen has no semantic state, so mint/amber/red are
     deliberately ABSENT. Nothing here passes, cautions or fails, so nothing
     here may borrow those hues. */
  --pgst-ink: #F2F6FC;          /* ink   — titles, tool names, values */
  --pgst-ink2: #D7E0EC;         /* ink2  — chip text, icon strokes */
  --pgst-faint: #94A2B6;        /* faint — mono labels and descriptions */
  --pgst-faint2: #7F8EA4;       /* faint2 — search placeholder, group counts */
  --pgst-on-light: #0B121C;     /* onLight — text on the white chip and tile */
  --pgst-tab: #7C8CA1;          /* inactive tab */

  --pgst-glass: rgba(9, 14, 21, .52);            /* sur, + blur(20px) */
  --pgst-line: rgba(255, 255, 255, .11);         /* line — 1px, load-bearing */
  --pgst-line-soft: rgba(255, 255, 255, .09);    /* lineSoft — hairline rules */
  --pgst-line-strong: rgba(255, 255, 255, .14);
  --pgst-soft: rgba(255, 255, 255, .06);         /* surSoft — tiles, chips */
}

.pgs-tools *,
.pgs-tools *::before,
.pgs-tools *::after { box-sizing: border-box; }

/* The site's typography rules reach div/span; zero them inside the plate. */
.pgs-tools div,
.pgs-tools span { margin: 0; padding: 0; }

.pgs-tools svg { display: block; flex: none; overflow: visible; }

/* Optional device bezel — canvas .phone, line 32. Pure canvas chrome, so it is
   opt-in: the gallery frames the screens itself. */
.pgs-tools.pgs-tools--bezel {
  background: #060B16;
  padding: calc(9px * var(--pgst-scale));
  border: calc(9px * var(--pgst-scale)) solid #03060c;
  border-radius: calc(46px * var(--pgst-scale));
  box-shadow: 0 0 0 2px #16223a, 0 30px 70px rgba(0, 0, 0, .6);
}

/* Type helpers. Canvas .mono (line 39) and .lbl (line 41), verbatim. */
.pgs-tools .pgst-mono {
  font-family: var(--pgst-mono);
  font-variant-numeric: tabular-nums;
}
.pgs-tools .pgst-lbl {
  font: 700 9.5px var(--pgst-mono);
  letter-spacing: 1.6px;
  color: var(--pgst-faint);
}


/* ---------------------------------------------------------------------------
   2. Screen root and the two bloom layers
   Canvas .screen line 33, .bloom line 34, .bloom2 line 35.
   --------------------------------------------------------------------------- */

.pgs-tools .pgst-screen {
  position: relative;
  width: 375px;
  height: 812px;
  flex: none;
  border-radius: 38px;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  background: linear-gradient(180deg,
    #22303F 0%, #1A2634 13%, #111A25 36%, #0A0F16 66%, #04070B 100%);
  transform: scale(var(--pgst-scale));
  transform-origin: top left;
}

.pgs-tools .pgst-bloom { position: absolute; top: 0; left: 0; right: 0; }

/* bloom: the full-width top glow, top 46% of the screen */
.pgs-tools .pgst-bloom--sheet {
  height: 46%;
  background: linear-gradient(180deg,
    rgba(163, 187, 214, .2), rgba(163, 187, 214, .06) 46%, transparent 100%);
}
/* bloomCore: the header lift, top 22% */
.pgs-tools .pgst-bloom--core {
  height: 22%;
  background: radial-gradient(120% 100% at 50% 0%,
    rgba(190, 210, 232, .16), transparent 72%);
}


/* ---------------------------------------------------------------------------
   3. Status bar — canvas .sb, line 36
   --------------------------------------------------------------------------- */

.pgs-tools .pgst-sb {
  height: 44px;
  flex: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 26px;
  font: 700 12px var(--pgst-font);
  color: #D7E0EC;
  position: relative;
  z-index: 3;
}
.pgs-tools .pgst-sb-icons { display: flex; gap: 6px; align-items: center; }


/* ---------------------------------------------------------------------------
   4. Content column — canvas .body, line 37.
   18px screen padding (handover section 2, Geometry) and it does NOT scroll:
   the stack is tuned to fit 812px. See section 10 for the height budget.
   --------------------------------------------------------------------------- */

.pgs-tools .pgst-col {
  flex: 1;
  min-height: 0;
  position: relative;
  z-index: 2;
  padding: 2px 18px 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}


/* ---------------------------------------------------------------------------
   5. Title block — canvas lines 364-367
   --------------------------------------------------------------------------- */

.pgs-tools .pgst-titles { padding: 2px 0 12px; flex: none; }

.pgs-tools .pgst-title {
  font-size: 23px;
  font-weight: 800;
  letter-spacing: -.6px;
  color: var(--pgst-ink);
}
.pgs-tools .pgst-subtitle {
  font-size: 9.5px;
  color: var(--pgst-faint);
  letter-spacing: 1.2px;
  margin-top: 4px;
}


/* ---------------------------------------------------------------------------
   6. Search field — canvas lines 368-371, built on .card (canvas line 38)

   Radius 16 rather than the card's usual 20-24 because this reads as a field,
   not a panel; that is the canvas's own choice and the handover allows 12-16
   for an inset cell. Placeholder colour is faint2, the tertiary caption tone,
   which is exactly what an unfilled field is.
   --------------------------------------------------------------------------- */

.pgs-tools .pgst-card {
  background: var(--pgst-glass);
  border: 1px solid var(--pgst-line);
  -webkit-backdrop-filter: blur(20px);
  backdrop-filter: blur(20px);
}

.pgs-tools .pgst-search {
  border-radius: 16px;
  padding: 11px 13px;
  display: flex;
  align-items: center;
  gap: 10px;
  flex: none;
}
.pgs-tools .pgst-search-ph {
  font-size: 12.5px;
  color: var(--pgst-faint2);
}


/* ---------------------------------------------------------------------------
   7. Group chips — canvas lines 372-377

   The selected chip is the light action (handover section 2: "Actions are
   light, not coloured"), so selection is expressed by lightness, never by a
   hue. That matters here: mint on a filter chip would read as a passing
   measurement.
   --------------------------------------------------------------------------- */

.pgs-tools .pgst-groups {
  display: flex;
  gap: 7px;
  margin-top: 11px;
  flex: none;
  overflow: hidden;   /* a still plate of a scrollable row — divergence 4 */
}

.pgs-tools .pgst-chip {
  flex: none;
  border-radius: 14px;
  padding: 7px 13px;
  background: rgba(255, 255, 255, .07);
  border: 1px solid rgba(255, 255, 255, .13);
  color: var(--pgst-ink2);
  font-size: 11.5px;
  font-weight: 600;
}
/* border:0 because the canvas's selected chip declares no border at all
   (line 373), and padding stays at the inherited verbatim 7px 13px. That does
   mean its text sits 1px higher than its bordered neighbours' — which is what
   the canvas itself renders. The outer heights still match, because
   .pgst-groups is a plain flex row and align-items defaults to stretch. Left
   as authored rather than "corrected". */
.pgs-tools .pgst-chip--on {
  background: #F2F6FC;
  border: 0;
  color: var(--pgst-on-light);
  font-weight: 700;
}


/* ---------------------------------------------------------------------------
   8. Section label rows — canvas lines 378, 384, 391, 396

   One shared rule, because the canvas repeats the same inline style four times.
   DISCOVER's top padding is 13px not 14px (canvas line 396); that 1px is the
   canvas's, and .pgst-sect--tight preserves it rather than tidying it away.
   --------------------------------------------------------------------------- */

.pgs-tools .pgst-sect {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 14px 2px 9px;
  flex: none;
}
.pgs-tools .pgst-sect--tight { padding: 13px 2px 9px; }

.pgs-tools .pgst-rule {
  flex: 1;
  height: 1px;
  background: var(--pgst-line-soft);
}
.pgs-tools .pgst-count {
  font-size: 8.5px;
  color: var(--pgst-faint2);
}


/* ---------------------------------------------------------------------------
   9. The Recent card — canvas lines 379-383

   Radius 18 (the canvas's), icon tile 38px with the 12px radius the handover
   specifies for icon tiles. "Re-run" is the secondary action form: surSoft +
   line, never a coloured button.

   HONESTY NOTE. This card is the reason 1d must be still. Its meta line is a
   PAST reading, 11 minutes old. If anything in this card pulsed, breathed or
   spun, the card would claim that reading is current. It does not, and nothing
   in this file targets it with motion of any kind.
   --------------------------------------------------------------------------- */

.pgs-tools .pgst-recent {
  border-radius: 18px;
  padding: 11px 13px;
  display: flex;
  align-items: center;
  gap: 11px;
  flex: none;
}

.pgs-tools .pgst-recent-icon {
  width: 38px;
  height: 38px;
  flex: none;
  border-radius: 12px;
  background: rgba(255, 255, 255, .07);
  border: 1px solid var(--pgst-line-strong);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--pgst-ink2);
}

/* flex:1 + min-width:0 so a long tool name truncates instead of shoving the
   Re-run button off the card. */
.pgs-tools .pgst-recent-text { flex: 1; min-width: 0; }

.pgs-tools .pgst-recent-name {
  font-size: 12.5px;
  font-weight: 700;
  color: var(--pgst-ink);
}
.pgs-tools .pgst-recent-meta {
  font-size: 9px;
  color: var(--pgst-faint);
  margin-top: 2px;
  white-space: nowrap;
}

.pgs-tools .pgst-rerun {
  flex: none;
  border-radius: 12px;
  padding: 7px 12px;
  background: rgba(255, 255, 255, .09);
  border: 1px solid rgba(255, 255, 255, .16);
  font-size: 11px;
  font-weight: 700;
  color: var(--pgst-ink);
}


/* ---------------------------------------------------------------------------
   10. Tool tiles, the Discover chip row, and the nav reserve
   Canvas .tool line 45; grids lines 385 and 392; chip row lines 397-401;
   reserve line 402.

   THE LAYOUT CONTRACT (handover section 5) — measured, not assumed:
     status bar 44 + column 2 + titles 59 + search 41 + chips 40 + label 35
     + recent 62 + label 35 + two tile rows 173 + label 35 + one tile row 82
     + label 34 + chip row 35 = 781, leaving 31px of slack.
   The column is flex-start, so that slack collects BELOW the 104px reserve.
   The Discover chip row therefore ends ~49px above the nav's top edge: past the
   >= 20px minimum the nav's shadow needs, and inside the <= 60px maximum the
   handover sets for an empty band. If this screen ever overflows, remove a
   block. Do not nudge padding and do not shrink the 104px reserve.
   --------------------------------------------------------------------------- */

.pgs-tools .pgst-grid {
  display: grid;
  /* minmax(0, 1fr), not bare 1fr — divergence 2 */
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 9px;
  flex: none;
}

.pgs-tools .pgst-tool {
  border-radius: 16px;
  padding: 12px 11px;
  background: var(--pgst-soft);
  border: 1px solid var(--pgst-line);
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.pgs-tools .pgst-tool-name {
  font-size: 12.5px;
  font-weight: 700;
  color: var(--pgst-ink);
}
/* 8.5px: the canvas's value, below the handover's 9px mono floor. Kept verbatim
   and protected by the 0.88 scale floor instead. See the header. */
.pgs-tools .pgst-tool-desc {
  font-size: 8.5px;
  color: var(--pgst-faint);
  margin-top: 2px;
}

.pgs-tools .pgst-chiprow {
  display: flex;
  gap: 7px;
  flex: none;
  overflow: hidden;   /* divergence 4, as with .pgst-groups */
}
.pgs-tools .pgst-tchip {
  flex: none;
  border-radius: 13px;
  padding: 9px 12px;
  background: var(--pgst-soft);
  border: 1px solid var(--pgst-line);
  font-size: 11.5px;
  font-weight: 600;
  color: var(--pgst-ink);
  white-space: nowrap;
}

.pgs-tools .pgst-reserve { height: 104px; flex: none; }


/* ---------------------------------------------------------------------------
   11. Floating tab bar — canvas .nav line 42, .nvi 43, .nvl 44, markup 404-410
   --------------------------------------------------------------------------- */

.pgs-tools .pgst-nav {
  position: absolute;
  left: 16px;
  right: 16px;
  bottom: 14px;
  height: 72px;
  border-radius: 26px;
  background: rgba(9, 13, 20, .88);
  border: 1px solid var(--pgst-line);
  -webkit-backdrop-filter: blur(22px);
  backdrop-filter: blur(22px);
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 6px;
  z-index: 5;
  box-shadow: 0 14px 34px rgba(0, 0, 0, .5);
}

.pgs-tools .pgst-tab {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  color: var(--pgst-tab);
  min-width: 0;   /* so "Diagnose" cannot widen its column past its 1fr share */
}
.pgs-tools .pgst-tab-lbl { font-size: 9.5px; font-weight: 600; }

/* The active tab is Tools, because this IS Tools. Canvas line 407 sets the item
   colour inline (#F2F6FC) and bumps its label to 700. Those are two separate
   facts and they are kept separate, exactly as mock.css does for Home's nav:
     .is-active        = "this tab is the current screen" (icon + text go to ink)
     .pgst-tab--tools  = "this is the centre Tools tab" (its label is always ink
                         and 700, active or not, because it is the anchor item)
   On 1d both happen to apply to the same element. Do not merge them, or a
   gallery that reuses this nav for another screen loses the anchor styling. */
.pgs-tools .pgst-tab.is-active { color: var(--pgst-ink); }
.pgs-tools .pgst-tab.is-active .pgst-tab-lbl {
  color: var(--pgst-ink);
  font-weight: 700;
}
.pgs-tools .pgst-tab--tools .pgst-tab-lbl {
  color: var(--pgst-ink);
  font-weight: 700;
}

.pgs-tools .pgst-tools-tile {
  width: 34px;
  height: 34px;
  border-radius: 12px;
  background: linear-gradient(150deg, #FFFFFF, #C9D6E6);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--pgst-on-light);
  box-shadow: 0 8px 18px rgba(0, 0, 0, .45);
}


/* ---------------------------------------------------------------------------
   12. NO @keyframes.

   There is no keyframes block in this file, on purpose. It is not an omission
   and it does not need filling in. See the header: 1d has no live moment, so it
   has no motion, and the naming convention (every keyframe on this screen would
   be prefixed `pgstools*`) has nothing to name.

   The handover's authored motion vocabulary and why each entry is absent here:
     sweep 2.8s    logo mark          — 1d has no logo mark (canvas line 365)
     pulse 1.6-2.4s live dots         — nothing on 1d is live
     ring 3-4s     expanding ring     — nothing is scanning or answering
     breathe 6s    lit tile glow      — no tile holds a measured reading
     flowX .8-1s   dashed link        — no link strip on this screen
     travel 2.6s   packet dot         — no traffic is being sent
     marquee 7-9s  trace              — no trace panel on this screen
     draw 1.7s     arc fill on appear — no dial on this screen
     bar 2.2s      signal ladder      — no signal readout on this screen
     1s quadrant   INDETERMINATE work — nothing on 1d is working. This one is
                   the trap: a rotating quadrant is cheap to add and looks
                   "designed", but it asserts that something is in progress. On
                   a catalogue screen that assertion is simply false.
   --------------------------------------------------------------------------- */


/* ---------------------------------------------------------------------------
   13. HONEST FINAL FRAMES — block A: offstage.

   The gallery shell toggles .is-offstage on .pgs-tools when this screen is not
   the active tab. This is the web's TickerMode, mirroring the app's
   IndexedStack + TickerMode, where offstage tabs genuinely stop ticking.

   On 1d it is a NO-OP by construction, and it is provably so: there are no
   animations and no transitions to stop, so this block cannot change a single
   rendered pixel. It is kept for two reasons. First, the shell must be able to
   treat all six screens identically. Second, it is a safety net: if a future
   edit slips motion into this subtree without reading the header, that motion
   dies the moment the screen goes offstage.

   A blanket is normally the wrong tool, because `animation: none` freezes an
   element at its BASE state, which for an entrance animation is a pre-entrance
   state nobody should ever see. styles.css says as much at line 720. It is
   correct here, and only here, precisely BECAUSE the screen has no animations:
   with zero animations the base state IS the rendered state, so the blanket is
   mathematically the identity transform. On any screen that does animate, write
   explicit per-element final frames instead.

   Note what this block does NOT contain: animation-play-state. Pausing leaves a
   frozen mid-frame, which is a lie about a moment that never happened, and it
   is forbidden across this project.

   ***  KEEP THIS BLOCK AND BLOCK B (section 14) IDENTICAL.  ***
   --------------------------------------------------------------------------- */

.pgs-tools.is-offstage,
.pgs-tools.is-offstage *,
.pgs-tools.is-offstage *::before,
.pgs-tools.is-offstage *::after {
  animation: none !important;
  transition: none !important;
}


/* ---------------------------------------------------------------------------
   14. HONEST FINAL FRAMES — block B: prefers-reduced-motion.

   Byte-identical to block A apart from the gate. Every selector is gated on
   html:not(.motion-opt-in), matching styles.css lines 375-378 and mock.css
   lines 901-916, so the site's existing "Play the motion" button keeps working:
   motion.js sets html.motion-opt-in, this block stops applying, and the visitor
   sees whatever the screen would have done. On 1d that is still nothing, which
   is the honest answer and is the same in every state.

   Block A is deliberately NOT gated on .motion-opt-in: off-screen is a
   performance fact, not a preference.
   --------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  html:not(.motion-opt-in) .pgs-tools,
  html:not(.motion-opt-in) .pgs-tools *,
  html:not(.motion-opt-in) .pgs-tools *::before,
  html:not(.motion-opt-in) .pgs-tools *::after {
    animation: none !important;
    transition: none !important;
  }
}
