/* =============================================================================
   AIToolsay · /search — the delta on top of the Homepage Studio kit
   -----------------------------------------------------------------------------
   Loaded by livewire/public/search.blade.php, AFTER assets/css/homepage.css.

   THE POINT OF THIS FILE IS HOW LITTLE IS IN IT. /search renders the homepage's
   own kit — its bands, its hero, its search control, its chips, its panels and
   its cards — so everything that page and this page share is styled once, in
   homepage.css, and drifts in neither. What lives here is only what a RESULTS
   page needs and a homepage never does:

     §STACK   several panels stacked in one band, instead of one panel per band
     §HEAD    a panel head of FOUR children, which the kit's two-child
              `space-between` cannot lay out
     §SRX     the result card — a media ROW, and this page's own object rather
              than the listing tile it used to borrow. See its header for why
     §RAIL    the section index under the search field: chips with a glyph and
              a live count, which the plain chip has no slot for
     §EMPTY   the no-results panel and the browse-by-section grid under it
     §LAZY    `content-visibility` on the card and the scroll sentinel, so a
              1,400-hit query stops being a 6.1MB document laid out in full

   RULES OF THE FILE
     1. No colour is written here that the kit does not already own. Every value
        below resolves through `var(--hpx-…)` or `var(--tone-…)`, which is what
        makes the admin's theme and dark mode apply to this page for free.
     2. Selectors are written `.hpx.hpxs …` — (0,3,0) at minimum. The kit states
        its own chip rules as `.hpx .hpx-chip` (0,2,0); a bare `.hpxs-chip`
        (0,1,0) would lose every tie to it regardless of load order.
     3. Dark twins never use the `background` SHORTHAND. The kit paints the chip
        with `background-image` + `background-color`, and a shorthand here would
        silently reset the image the kit relies on.
   ========================================================================== */


/* ═══ §STACK — the panel column ══════════════════════════════════════════════
   The homepage gives every panel a band of its own; a results page has up to
   seven and that rhythm would put 100px of dead air between each pair. One
   band, one stack, the kit's own gap scale.
   ─────────────────────────────────────────────────────────────────────────── */
.hpx.hpxs .hpxs-stack {
    display: flex;
    flex-direction: column;
    gap: 18px;
}

/* ⚠ SCROLL-MARGIN, NOT PADDING. The site header is sticky, so a jump link that
     lands a panel at scroll position 0 parks its head UNDER the header and the
     link reads as broken. This is the only thing that makes the section rail
     above actually work. */
.hpx.hpxs .hpxs-panel {
    scroll-margin-top: 104px;
}

/* A panel's own hue, laid under its head as the softest possible wash — the
   same job `data-tone` does on a homepage rail panel. It is what stops seven
   stacked white panels from reading as one long sheet. */
.hpx.hpxs .hpxs-panel {
    position: relative;
    isolation: isolate;
}

.hpx.hpxs .hpxs-panel::before {
    content: '';
    position: absolute;
    z-index: -1;
    inset: 0 0 auto 0;
    height: 132px;
    border-radius: var(--hpx-r) var(--hpx-r) 0 0;
    background-image: radial-gradient(120% 100% at 0% 0%,
                      rgba(var(--tone-rgb, 54, 128, 237), .07) 0%, transparent 62%);
    pointer-events: none;
}

body.theme-dark .hpx.hpxs .hpxs-panel::before {
    background-image: radial-gradient(120% 100% at 0% 0%,
                      rgba(var(--tone-rgb, 54, 128, 237), .14) 0%, transparent 62%);
}


/* ═══ §HEAD — the panel head, four-up ════════════════════════════════════════
   ⚠ THE KIT'S `space-between` CANNOT LAY THIS OUT. `.hpx-panel-head` is drawn
     in homepage.css for TWO children — glyph and copy — where "space between"
     IS the gap. A results panel head has FOUR: glyph, copy, count pill, and the
     hairline that runs out to the right edge. Under `space-between` the free
     width is split between every pair, so the glyph pins left, the title drifts
     to the middle, and a one-result panel prints its heading a thousand pixels
     from its own icon. That was the old three-up bug on this page; the fix then
     was an auto end-margin on the copy, and an auto margin does not survive a
     fourth child — it swallows the slack the rule needs.

     So the head is restated as a plain flex-start ROW THAT WRAPS: plate, copy
     and count pill sit together as one left cluster, and the rule takes a line
     of its own underneath as a full-width divider. Nothing competes for the
     leftover width, which is the only arrangement that survives both a 390px
     phone and the 1920px shell this install actually runs.
   ─────────────────────────────────────────────────────────────────────────── */
.hpx.hpxs .hpxs-panel .hpx-panel-head {
    display: flex;
    align-items: center;
    justify-content: flex-start;
    flex-wrap: wrap;
    gap: 10px 14px;
    margin-bottom: 0;
    padding-bottom: 16px;
}

/* ⚠ The auto end-margin the three-up fix used is CLEARED here, deliberately.
     An auto margin absorbs ALL the remaining free space on its line, so with
     one still on the copy the count pill would be thrown to the far right edge
     — 1,800px from the title it counts, which reads as two unrelated things
     rather than as a heading and its number. The pill belongs to the title. */
.hpx.hpxs .hpxs-panel .hpx-panel-head .hpx-head-copy {
    margin-inline-end: 0;
    flex: 0 1 auto;
    min-width: 0;
}

/* A vertical's name is editorial copy and short; a translation of it may not
   be. It wraps rather than pushing the count off the panel. */
.hpx.hpxs .hpxs-panel .hpx-panel-head .hpx-title { overflow-wrap: anywhere; }

/* The vertical's own one-line promise, straight off `SearchResults::$types`.
   It is the same sentence the section chip and the browse card use, so a
   visitor reads one description of "Prompts" everywhere on the page. */
.hpx.hpxs .hpxs-panel .srx-blurb {
    margin-top: 3px;
    overflow-wrap: anywhere;
}

/* Head plate — the kit's `.hpx-panel-ico` with a tone halo added under it. The
   halo is a second shadow layer, not a replacement: `.hpx-panel-ico` already
   carries an inset sheen and a drop shadow and both are still wanted. */
.hpx.hpxs .srx-ico {
    width: 52px;
    height: 52px;
    border-radius: 16px;
    font-size: 21px;
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, .26),
        0 10px 22px -10px var(--tone-plate, var(--tone-ink)),
        0 0 0 6px rgba(var(--tone-rgb), .07);
}

body.theme-dark .hpx.hpxs .srx-ico {
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, .14),
        0 10px 22px -10px rgba(0, 0, 0, .8),
        0 0 0 6px rgba(var(--tone-rgb), .12);
}

/* Count pill — the panel's headline number. It replaces the old "N matches"
   sub-line, which freed that line for the blurb above; the number is the thing
   a visitor scans for, so it gets a shape of its own rather than a grey line
   of body copy. */
.hpx.hpxs .srx-count {
    display: inline-flex;
    align-items: baseline;
    gap: 5px;
    flex: 0 0 auto;
    padding: 6px 12px;
    border-radius: 999px;
    background-color: var(--tone-bg);
    color: var(--tone-ink);
    box-shadow: inset 0 0 0 1px rgba(var(--tone-rgb), .26);
    font-size: 12px;
    font-weight: 600;
    line-height: 1.2;
    white-space: nowrap;
}

.hpx.hpxs .srx-count-n {
    font-size: 13.5px;
    font-weight: 800;
    font-variant-numeric: tabular-nums;
    letter-spacing: -.012em;
}

/* ── The rule that closes the head ────────────────────────────────────────
   ⚠ IT IS A FULL-WIDTH DIVIDER ON ITS OWN LINE, NOT AN INLINE FILLER.

     It was inline first — `flex: 1` beside the count pill, eating whatever
     width was left. That reads fine in a 900px panel and badly at 1920, which
     is the width this install actually runs (`--hpx-maxw: 1920px`): the head's
     content is a tidy cluster on the left, and the rule then set off from the
     pill and faded out with roughly 1,400px of empty panel still to go. The
     result looked like a border that had failed to draw rather than anything
     deliberate — the same dead-space-at-1920 problem the result cards were
     rebuilt to solve, resurfacing one element higher up.

     `flex: 0 0 100%` in the wrapping head drops it onto its own line, so it
     spans the panel and separates head from results the way a divider is
     supposed to. The fade now runs the whole length instead of dying a quarter
     of the way across, which is what makes a full-width hairline read as an
     edge rather than as a stub. It is ornament and aria-hidden either way. */
.hpx.hpxs .srx-rule {
    flex: 0 0 100%;
    height: 1px;
    margin-top: 2px;
    border-radius: 1px;
    background-image: linear-gradient(90deg,
                      rgba(var(--tone-rgb), .55) 0%,
                      rgba(var(--tone-rgb), .26) 46%,
                      rgba(var(--tone-rgb), .10) 76%,
                      rgba(var(--tone-rgb), 0) 100%);
}

/* The panel's own top edge, in its own hue — three pixels that tell seven
   stacked panels apart at a glance, which the 132px wash alone never did.

   ⚠ IT IS A BACKGROUND LAYER, NOT A PSEUDO-ELEMENT, AND THAT IS THE WHOLE
     POINT. It was `::after` with `inset: 0 0 auto 0; height: 3px;
     border-radius: var(--hpx-r) var(--hpx-r) 0 0` first, and it drew a purple
     line sticking out past BOTH rounded corners, above the panel it belonged
     to. The cause is radius clamping: when a corner radius does not fit its
     box, CSS scales EVERY radius by `min(Li / Si)`. On a 3px-tall bar the left
     and right edges only have 3px for a 20px vertical radius, so the factor is
     3/20 and all four corners collapse to 3px. The panel keeps its real 20px
     corners, so for the first 20px at each end the panel curves inward while
     the bar runs straight on — and `.hpxs-panel` has no `overflow: hidden` to
     hide the difference. It cannot be given one either: the cards inside lift
     4px on hover and would be clipped at the panel's top edge.

     A background layer has no such problem. Backgrounds are clipped to the
     border-box, which follows `border-radius` exactly, so the accent ends
     precisely where the panel's curve does at any radius.

   ⚠ `repeat`, `size` and `position` are all stated explicitly. `.hpx-panel`
     paints itself with the `background` SHORTHAND, which resets those three to
     their initial values — a bare `background-image` here would tile a 3px
     stripe down the entire panel. */
.hpx.hpxs .hpxs-panel {
    background-image: linear-gradient(90deg,
                      rgba(var(--tone-rgb), .85) 0%,
                      rgba(var(--tone-rgb), .28) 34%,
                      rgba(var(--tone-rgb), 0) 72%);
    background-repeat: no-repeat;
    background-size: 100% 3px;
    background-position: 0 0;
}


/* ═══ §SRX — the result card ═════════════════════════════════════════════════
   WHY THIS IS NOT `.dir-tc` ANY MORE.

   Until now each hit rendered the V2 directory listing tile — a 248px CENTRED
   card built for a four-up catalogue grid. On a results page it failed twice:

     · A panel with one hit put a 248px tile in a 1870px panel and left the
       other 1600px empty. `--hpx-maxw` is 1920 on this install, so almost
       every panel looked like a rendering fault rather than a result.
     · `.dir-tc-desc` is a hard two-line clamp with `overflow: hidden`, and the
       blade fed it `Str::limit(…, 92)` on top. Descriptions were cut twice and
       ended mid-word. That sheet is shared by six listing pages, so the clamp
       could not be lifted there without repainting all of them.

   So a results row is now its own object. It is a MEDIA ROW, not a tile:
   plate, copy, action, laid left to right, which is the one shape that fills
   its container at any count — one hit spans the panel, eight hits pack into
   columns, and neither looks marooned. Every colour still resolves through the
   kit's `--tone-*` / `--hpx-*` tokens, so the admin's theme and dark mode
   apply here for free, exactly as rule 1 of this file requires.
   ─────────────────────────────────────────────────────────────────────────── */
.hpx.hpxs .hpxs-resultgrid { margin-top: 2px; }

/* ⚠ `auto-fit`, NOT `auto-fill`, and the max track MUST stay `1fr`.
     auto-fit collapses the empty tracks, so N cards always share the full
     panel width — that is the entire fix for the marooned single result, and
     swapping in auto-fill brings it straight back.
     The `1fr` max is load-bearing for a different reason: a grid picks its
     repetition count from the MAXIMUM track sizing function whenever that max
     is definite, so capping the track at a px value (to "stop a lone row
     stretching") silently divides the column count instead. `1fr` is
     indefinite, so the count comes from the 520px min, which is the intent.
     `min(100%, …)` keeps the min from overflowing a container narrower than
     itself — i.e. every phone. */
.hpx.hpxs .srx-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 520px), 1fr));
    gap: 14px;
    align-items: stretch;
}

/* ⚠ THE CARD IS A CONTAINER, AND ITS INTERNAL BREAKPOINT IS A CONTAINER QUERY.
     A media query would be simply wrong here: with auto-fit the card's width
     is a function of the COLUMN COUNT, not of the viewport, so the same 1440px
     screen renders 664px cards on this page and ~370px cards inside a narrower
     shell. Only the card knows how much room the card has. The phone-width
     media query further down is a fallback for engines without `@container`,
     not the primary rule — at phone widths the two agree. */
.hpx.hpxs .srx-card {
    position: relative;
    isolation: isolate;
    container-type: inline-size;
    padding: 15px 16px;
    border: 1px solid var(--hpx-line);
    border-radius: 18px;
    background-color: var(--hpx-card);
    background-image: radial-gradient(120% 150% at 0% 0%,
                      rgba(var(--tone-rgb), .055) 0%,
                      rgba(var(--tone-rgb), 0) 58%);
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, .6),
        0 1px 2px rgba(16, 24, 40, .04),
        0 14px 30px -26px rgba(16, 24, 40, .5);
    overflow: hidden;
    transition:
        transform .28s cubic-bezier(.16, .84, .44, 1),
        border-color .22s ease,
        box-shadow .28s ease,
        background-image .3s ease;
}

/* ⚠ NO `background` SHORTHAND IN A DARK TWIN — rule 3 of this file. The card
     paints a tone wash as `background-image` over a `background-color`, and a
     shorthand here would reset the wash to none with nothing to say why. */
body.theme-dark .hpx.hpxs .srx-card {
    background-color: var(--hpx-card-2, #1D1D22);
    background-image: radial-gradient(120% 150% at 0% 0%,
                      rgba(var(--tone-rgb), .13) 0%,
                      rgba(var(--tone-rgb), 0) 58%);
    border-color: var(--hpx-line);
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, .05),
        0 1px 2px rgba(0, 0, 0, .42),
        0 14px 30px -26px rgba(0, 0, 0, .9);
}

/* ── ::before — the accent bar that wipes in on hover ──────────────────────
   Resting state is a real designed state, not "the card minus its hover": the
   bar is scaled to nothing at the vertical centre so it opens from the middle
   out, which reads as the card acknowledging the pointer rather than as a
   decoration blinking on. */
.hpx.hpxs .srx-card::before {
    content: '';
    position: absolute;
    z-index: 0;
    inset-block: 14px;
    inset-inline-start: 0;
    width: 3px;
    border-radius: 0 3px 3px 0;
    background-image: linear-gradient(180deg,
                      rgba(var(--tone-rgb), .95) 0%,
                      rgba(var(--tone-rgb), .32) 100%);
    opacity: 0;
    transform: scaleY(0);
    transform-origin: 50% 50%;
    pointer-events: none;
    transition:
        transform .34s cubic-bezier(.16, .84, .44, 1),
        opacity .22s ease;
}

/* ── ::after — the tone bloom behind the top-right corner ──────────────── */
.hpx.hpxs .srx-card::after {
    content: '';
    position: absolute;
    z-index: 0;
    top: -46%;
    right: -12%;
    width: 260px;
    height: 260px;
    border-radius: 50%;
    background-image: radial-gradient(circle,
                      rgba(var(--tone-rgb), .18) 0%,
                      rgba(var(--tone-rgb), 0) 68%);
    opacity: 0;
    transform: scale(.72);
    pointer-events: none;
    transition:
        opacity .4s ease,
        transform .52s cubic-bezier(.16, .84, .44, 1);
}

body.theme-dark .hpx.hpxs .srx-card::after {
    background-image: radial-gradient(circle,
                      rgba(var(--tone-rgb), .30) 0%,
                      rgba(var(--tone-rgb), 0) 68%);
}

/* ── The sheen sweep ───────────────────────────────────────────────────────
   ::before and ::after are both spent above, so the sweep needs an element.
   It is a span rather than a third layer on one of them because a sweep has to
   TRANSLATE, and a background layer cannot be transformed independently of the
   box it paints on. */
.hpx.hpxs .srx-sheen {
    position: absolute;
    z-index: 0;
    inset: 0;
    pointer-events: none;
    background-image: linear-gradient(102deg,
                      rgba(255, 255, 255, 0) 34%,
                      rgba(255, 255, 255, .5) 50%,
                      rgba(255, 255, 255, 0) 66%);
    opacity: 0;
    transform: translateX(-120%);
}

body.theme-dark .hpx.hpxs .srx-sheen {
    background-image: linear-gradient(102deg,
                      rgba(255, 255, 255, 0) 34%,
                      rgba(255, 255, 255, .13) 50%,
                      rgba(255, 255, 255, 0) 66%);
}

/* ── The whole-card hit area ───────────────────────────────────────────────
   Paints under the row, which comes later in the DOM. The row hands its own
   pointer events back only to the title, the description and the button, so
   every other pixel of the card — padding, plate, the gap beside the button —
   belongs to this link. `tabindex="-1"`: the visible title link is the tab
   stop, and three stops to one URL is three times the keyboard work. */
.hpx.hpxs .srx-hit {
    position: absolute;
    z-index: 1;
    inset: 0;
    border-radius: inherit;
    font-size: 0;
}

.hpx.hpxs .srx-row {
    position: relative;
    z-index: 1;
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto;
    align-items: center;
    gap: 16px;
    pointer-events: none;
}

.hpx.hpxs .srx-nm a,
.hpx.hpxs .srx-desc,
.hpx.hpxs .srx-btn { pointer-events: auto; }

/* ── Plate ─────────────────────────────────────────────────────────────────
   `--tone-bg` behind `--tone-ink` is the one pairing that is contrast-safe in
   BOTH modes: light gives a pale tint under deep ink, dark gives a translucent
   tint of the same hue under its light twin. Never fill this from `--tone-ink`
   — that is the trap the kit records at §CHIP. */
.hpx.hpxs .srx-plate {
    display: grid;
    place-items: center;
    width: 58px;
    height: 58px;
    border-radius: 17px;
    background-color: var(--tone-bg);
    color: var(--tone-ink);
    font-size: 23px;
    line-height: 1;
    box-shadow: inset 0 0 0 1px rgba(var(--tone-rgb), .22);
    overflow: hidden;
    transition:
        transform .3s cubic-bezier(.16, .84, .44, 1),
        box-shadow .26s ease;
}

.hpx.hpxs .srx-plate img {
    display: block;
    width: 62%;
    height: 62%;
    object-fit: contain;
}

/* The tools panel carries the tool's own inline glyph, drawn at an intrinsic
   22px. Without this it swims in a 58px plate. Strokes are `currentColor`, so
   the tone ink above reaches it. */
.hpx.hpxs .srx-plate svg {
    width: 54%;
    height: 54%;
}

/* Last resort, and a deliberate one: a monogram of the result's own initial
   beats repeating the vertical's glyph on every card in the panel, which says
   nothing a reader does not already know from the head above it. */
.hpx.hpxs .srx-mono {
    font-size: 24px;
    font-weight: 800;
    letter-spacing: -.02em;
    line-height: 1;
    color: var(--tone-ink);
}

/* ── Copy ──────────────────────────────────────────────────────────────── */
.hpx.hpxs .srx-copy { min-width: 0; }

.hpx.hpxs .srx-line {
    display: flex;
    align-items: flex-start;
    gap: 9px;
    min-width: 0;
}

/* Relevance position within the panel. Ordinal, not a medal: the podium
   gold/silver/bronze the listing tile wears would claim a ranking this page
   does not have, and it reads as nonsense on a panel with one hit. */
.hpx.hpxs .srx-rank {
    display: inline-grid;
    place-items: center;
    flex: 0 0 auto;
    min-width: 22px;
    height: 22px;
    margin-top: 2px;
    padding: 0 6px;
    border-radius: 8px;
    background-color: var(--tone-bg);
    color: var(--tone-ink);
    box-shadow: inset 0 0 0 1px rgba(var(--tone-rgb), .24);
    font-size: 11.5px;
    font-weight: 800;
    font-variant-numeric: tabular-nums;
    line-height: 1;
    transition: transform .28s cubic-bezier(.34, 1.56, .64, 1);
}

/* ⚠ (0,3,0) — three classes — so it outranks the `:not()` chain in
     custom.ltr.css that paints every public heading, which measures (0,2,2). */
.hpx.hpxs .srx-nm {
    margin: 0;
    min-width: 0;
    font-size: 16px;
    font-weight: 750;
    line-height: 1.34;
    letter-spacing: -.014em;
    color: var(--hpx-ink);
    transition: color .2s ease;
}

/* ⚠ THE TITLE WRAPS. IT IS NEVER ELLIPSED. The listing tile it replaced set
     `white-space: nowrap` + `text-overflow: ellipsis`, which on a narrow tile
     cut most product names in half. A row has the width to print the whole
     name, and a search result whose name is truncated is a result the visitor
     cannot identify. */
.hpx.hpxs .srx-nm a {
    color: inherit;
    text-decoration: none;
    overflow-wrap: anywhere;
    transition: color .2s ease;
}

/* ⚠ FULL TEXT, NO CLAMP, NO `Str::limit`. See the §SRX header: this is half of
     why the tile was replaced. The row is wide enough to carry the sentence,
     the grid stretches every card in a row to the tallest of them, so nothing
     ragged comes of it, and a description that stops mid-word is the one thing
     a results page must not do.
     The measure is capped in `ch` rather than px because at 1920 a single-hit
     panel is one 1870px row, and a 200-character line at that width is
     unreadable however well it is set. */
.hpx.hpxs .srx-desc {
    margin: 5px 0 0;
    max-width: 92ch;
    font-size: 13.5px;
    font-weight: 450;
    line-height: 1.62;
    color: var(--hpx-ink-3);
    overflow-wrap: anywhere;
}

/* ── Action ────────────────────────────────────────────────────────────── */
.hpx.hpxs .srx-go {
    display: flex;
    align-items: center;
    flex: 0 0 auto;
}

/* The site's button, in the card's hue: solid `--tone-plate` under a white
   sheen, which is the same construction `.hpx-panel-ico`, `.hpx-sc-go` and the
   listing card's own CTA use. `--tone-plate` is the token that carries a real
   dark-mode value — filling from `--tone-ink` is what makes a chip glow. */
.hpx.hpxs .srx-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 7px;
    padding: 11px 16px;
    border: 0;
    border-radius: 12px;
    background-color: var(--tone-plate, var(--tone-ink));
    background-image: linear-gradient(160deg,
                      rgba(255, 255, 255, .22) 0%,
                      rgba(255, 255, 255, 0) 58%);
    font-size: 13px;
    font-weight: 700;
    line-height: 1.2;
    letter-spacing: -.006em;
    white-space: nowrap;
    box-shadow: 0 10px 20px -12px rgba(var(--tone-rgb), .95);
    transition:
        gap .2s ease,
        transform .22s cubic-bezier(.16, .84, .44, 1),
        box-shadow .24s ease,
        background-image .22s ease;
}

/* ⚠ EVERY STATE RESTATED. `.hpx a { color: inherit }` in the kit and the link
     rules in custom.ltr.css both reach this anchor; without the full list a
     visited or hovered button drags its label to the page ink and the white
     text disappears into the fill. */
.hpx.hpxs .srx-btn,
.hpx.hpxs .srx-btn:hover,
.hpx.hpxs .srx-btn:focus,
.hpx.hpxs .srx-btn:focus-visible,
.hpx.hpxs .srx-btn:active,
.hpx.hpxs .srx-btn:visited {
    color: #fff;
    text-decoration: none;
}

.hpx.hpxs .srx-btn .srx-arr {
    flex: 0 0 auto;
    width: 14px;
    height: 14px;
    color: #fff;
    transition: transform .22s cubic-bezier(.16, .84, .44, 1);
}

/* Dark twin — the tone plates are lightened for dark surfaces, so a flat white
   sheen over them lands white-on-mid-blue. A black wash under the sheen pulls
   the label's contrast back without desaturating the hue. */
body.theme-dark .hpx.hpxs .srx-btn {
    background-image: linear-gradient(160deg,
                      rgba(255, 255, 255, .20) 0%,
                      rgba(0, 0, 0, .16) 100%);
    box-shadow: 0 10px 20px -12px rgba(0, 0, 0, .95);
}


/* ── HOVER — the "after" half of every state above ────────────────────────
   Guarded by `hover: hover` so a touch device never latches any of it on tap.
   The lift is 4px, not the tile's 6px: a row is up to 1870px wide and the same
   translate on that mass reads as the layout jumping rather than as a card
   responding. */
@media (hover: hover) {
    .hpx.hpxs .srx-card:hover {
        transform: translateY(-4px);
        border-color: var(--tone-line);
        box-shadow:
            inset 0 1px 0 rgba(255, 255, 255, .7),
            0 1px 2px rgba(16, 24, 40, .05),
            0 26px 44px -28px rgba(var(--tone-rgb), .6);
    }

    body.theme-dark .hpx.hpxs .srx-card:hover {
        border-color: var(--tone-line);
        box-shadow:
            inset 0 1px 0 rgba(255, 255, 255, .07),
            0 1px 2px rgba(0, 0, 0, .5),
            0 26px 44px -28px rgba(0, 0, 0, .95);
    }

    .hpx.hpxs .srx-card:hover::before { opacity: 1; transform: scaleY(1); }
    .hpx.hpxs .srx-card:hover::after  { opacity: 1; transform: scale(1); }

    .hpx.hpxs .srx-card:hover .srx-sheen {
        animation: srxSweep .9s cubic-bezier(.22, .61, .36, 1) 1;
    }

    .hpx.hpxs .srx-card:hover .srx-plate {
        transform: translateY(-2px) scale(1.05);
        box-shadow:
            inset 0 0 0 1px rgba(var(--tone-rgb), .5),
            0 10px 20px -12px rgba(var(--tone-rgb), .7);
    }

    .hpx.hpxs .srx-card:hover .srx-rank { transform: scale(1.1); }
    .hpx.hpxs .srx-card:hover .srx-nm,
    .hpx.hpxs .srx-card:hover .srx-nm a { color: var(--tone-ink); }

    .hpx.hpxs .srx-card:hover .srx-btn {
        gap: 10px;
        transform: translateY(-1px);
        background-image: linear-gradient(160deg,
                          rgba(255, 255, 255, .36) 0%,
                          rgba(255, 255, 255, .04) 62%);
        box-shadow: 0 16px 26px -12px rgba(var(--tone-rgb), 1);
    }

    /* (0,4,1) — beats the (0,3,1) dark scrim above, so dark mode gets the
       brightening too instead of freezing on its resting sheen. */
    body.theme-dark .hpx.hpxs .srx-card:hover .srx-btn {
        background-image: linear-gradient(160deg,
                          rgba(255, 255, 255, .30) 0%,
                          rgba(0, 0, 0, .12) 100%);
        box-shadow: 0 16px 26px -12px rgba(0, 0, 0, 1);
    }

    .hpx.hpxs .srx-card:hover .srx-btn .srx-arr { transform: translateX(3px); }
}

/* Keyboard parity. The tab stop is the title link, so the CARD has to answer
   when its title is focused — otherwise the pointer gets a designed state and
   the keyboard gets a bare outline on a word. */
.hpx.hpxs .srx-card:focus-within {
    border-color: var(--hpx-brand);
    box-shadow:
        0 0 0 3px var(--hpx-brand-glow, rgba(54, 128, 237, .28)),
        0 14px 30px -24px rgba(16, 24, 40, .5);
}

.hpx.hpxs .srx-card:focus-within::before { opacity: 1; transform: scaleY(1); }

.hpx.hpxs .srx-nm a:focus-visible,
.hpx.hpxs .srx-btn:focus-visible {
    outline: 3px solid var(--hpx-brand);
    outline-offset: 3px;
    border-radius: 8px;
}

.hpx.hpxs .srx-card:active { transform: translateY(-1px); }

/* ═══ §RAIL — the section index ══════════════════════════════════════════════
   The kit's chip row, carrying a glyph and a count. Both are additions, not
   overrides: the pill itself, its hover fill, its sweep and its focus ring are
   the kit's and are not touched.
   ─────────────────────────────────────────────────────────────────────────── */
.hpx.hpxs .hpxs-chip {
    gap: 8px;
    padding-inline: 14px;
}

.hpx.hpxs .hpxs-chip i {
    font-size: 12.5px;
    color: var(--tone-ink);
    transition: color .25s ease;
}

.hpx.hpxs .hpxs-n {
    display: inline-grid;
    place-items: center;
    min-width: 20px;
    height: 19px;
    padding: 0 6px;
    border-radius: 7px;
    background-color: var(--tone-bg);
    color: var(--tone-ink);
    font-size: 11px;
    font-weight: 800;
    font-variant-numeric: tabular-nums;
    line-height: 1;
    transition: background-color .25s ease, color .25s ease;
}

/* ⚠ THE HOVER STATE HAS TO INVERT BOTH. The kit fills the chip brand-blue and
     turns its label white on hover; an amber or emerald `--tone-ink` glyph left
     on that fill measures under 2:1 and the count chip keeps a pale tint on a
     saturated blue. Same treatment on :focus-visible, which the kit fills too —
     and OUTSIDE the hover query, for the same reason the kit states there: a
     keyboard user on a touch device reports `hover: none`. */
@media (hover: hover) {
    .hpx.hpxs .hpxs-chip:hover i { color: #fff; }

    .hpx.hpxs .hpxs-chip:hover .hpxs-n {
        background-color: rgba(255, 255, 255, .22);
        color: #fff;
    }
}

.hpx.hpxs .hpxs-chip:focus-visible i { color: #fff; }

.hpx.hpxs .hpxs-chip:focus-visible .hpxs-n {
    background-color: rgba(255, 255, 255, .22);
    color: #fff;
}

/* The interpunct between the two counts in the hero badge. */
.hpx.hpxs .hpxs-sep {
    margin-inline: 6px;
    opacity: .55;
}

/* A search term is visitor input, not editorial copy: it can be one 60-letter
   word, and the hero headline is 44px. It wraps mid-word rather than pushing
   the hero sideways. */
.hpx.hpxs .hpxs-term {
    overflow-wrap: anywhere;
    word-break: break-word;
}


/* ═══ §EMPTY — nothing matched ═══════════════════════════════════════════════
   The panel is a small stage: a brand aura behind everything, two slow orbit
   rings and four floating sparks around the glyph — the same visual family as
   the hero's orbit above it, at panel scale. Ornament only: every word sits
   OUTSIDE the stage, in flow, so nothing decorative can ever cover copy.

   ⚠ Aura and stage are z-index:-1 / in-flow inside an `isolation: isolate`
     panel — the same trick §STACK uses — so the decoration paints above the
     panel surface and below every line of text without a z-index arms race. */
.hpx.hpxs .hpxs-empty {
    position: relative;
    isolation: isolate;
    overflow: hidden;
    align-items: center;
    padding: 52px 24px 44px;
    text-align: center;
}

/* Two washes, brand blue and violet, so the panel reads branded before a word
   is read. Literal rgba twice (light / dark) because no kit token exposes the
   brand as bare channels. */
.hpx.hpxs .hpxs-e-aura {
    position: absolute;
    z-index: -1;
    inset: 0;
    background-image:
        radial-gradient(110% 90% at 50% -10%, rgba(54, 128, 237, .10) 0%, transparent 58%),
        radial-gradient(70% 70% at 88% 108%, rgba(139, 92, 246, .07) 0%, transparent 60%);
    pointer-events: none;
}

body.theme-dark .hpx.hpxs .hpxs-e-aura {
    background-image:
        radial-gradient(110% 90% at 50% -10%, rgba(54, 128, 237, .20) 0%, transparent 58%),
        radial-gradient(70% 70% at 88% 108%, rgba(139, 92, 246, .14) 0%, transparent 60%);
}

/* ── The stage: rings + sparks around the glyph ──────────────────── */
.hpx.hpxs .hpxs-e-stage {
    position: relative;
    display: inline-grid;
    place-items: center;
    width: 168px;
    height: 150px;
    margin-bottom: 14px;
    pointer-events: none;
}

.hpx.hpxs .hpxs-e-ring {
    position: absolute;
    inset: 0;
    margin: auto;
    border-radius: 50%;
    border: 1.5px dashed var(--hpx-brand-line, #CFE0FA);
}

.hpx.hpxs .hpxs-e-r1 {
    width: 118px;
    height: 118px;
    animation: hpxsSpin 26s linear infinite;
}

.hpx.hpxs .hpxs-e-r2 {
    width: 164px;
    height: 164px;
    opacity: .55;
    animation: hpxsSpin 44s linear infinite reverse;
}

body.theme-dark .hpx.hpxs .hpxs-e-ring { border-color: rgba(122, 168, 240, .34); }

/* Four sparks in the card palette's first four hues, floating out of phase so
   the stage never reads as a static graphic. Bright literals that carry in
   both themes. */
.hpx.hpxs .hpxs-e-dot {
    position: absolute;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    opacity: .85;
    animation: hpxsFloat 3.6s ease-in-out infinite alternate;
}

.hpx.hpxs .hpxs-e-d1 { top: 16px;  left: 22px;  background-color: #3680ED; }
.hpx.hpxs .hpxs-e-d2 { top: 34px;  right: 12px; background-color: #8B5CF6; width: 6px; height: 6px; animation-duration: 4.4s; animation-delay: .6s; }
.hpx.hpxs .hpxs-e-d3 { bottom: 20px; left: 8px;  background-color: #10B981; width: 6px; height: 6px; animation-duration: 4s;   animation-delay: 1.1s; }
.hpx.hpxs .hpxs-e-d4 { bottom: 8px;  right: 30px; background-color: #F59E0B; animation-duration: 4.8s; animation-delay: .3s; }

/* The kit's panel glyph, at hero size, with a breathing brand halo. The
   keyframes restate the plate's own two shadows so the pulse ADDS a ring
   instead of replacing the kit's depth. */
.hpx.hpxs .hpxs-bigico {
    width: 68px;
    height: 68px;
    border-radius: 20px;
    font-size: 27px;
    animation: hpxsBreathe 3.4s ease-in-out infinite;
    transition: transform .35s cubic-bezier(.22, .61, .36, 1);
    will-change: transform;
}

@media (hover: hover) {
    .hpx.hpxs .hpxs-empty:hover .hpxs-bigico {
        transform: translateY(-4px) scale(1.05) rotate(-4deg);
    }
}

/* Copy. Restated at (0,4,0) on purpose: custom.ltr.css styles every public h2
   through a (0,2,2) :not() chain in light mode, and this heading must not
   inherit that page-level look. */
.hpx.hpxs .hpxs-empty .hpx-title {
    margin-bottom: 8px;
    font-size: clamp(22px, 3vw, 28px);
    line-height: 1.2;
}

.hpx.hpxs .hpxs-empty .hpx-sub {
    max-width: 54ch;
    margin: 0 auto;
}

/* ── Actions: the kit's own buttons, centred ─────────────────────── */
.hpx.hpxs .hpxs-e-actions {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 10px;
    margin-top: 24px;
}

/* ── The Ctrl+K hint. Desktop only — under 721px there is no Ctrl. ── */
.hpx.hpxs .hpxs-e-kbd {
    display: flex;
    align-items: center;
    gap: 5px;
    margin: 18px 0 0;
    font-size: 12px;
    color: var(--hpx-ink-3);
}

.hpx.hpxs .hpxs-e-kbd kbd {
    display: inline-grid;
    place-items: center;
    min-width: 22px;
    height: 21px;
    padding: 0 6px;
    border: 1px solid var(--hpx-line);
    border-bottom-width: 2px;
    border-radius: 6px;
    background-color: var(--hpx-card-2);
    color: var(--hpx-ink-2);
    font-family: inherit;
    font-size: 11px;
    font-weight: 700;
    line-height: 1;
}

.hpx.hpxs .hpxs-e-plus { opacity: .6; }


/* ═══ §VERT — the browse-by-section cards ════════════════════════════════════
   The homepage's "Discover More" card (`hpx-igcard`, tile variant), reused
   WHOLE. The blade puts `hpx-icongrid is-centred hpx-ig-tile` on the container,
   so every one of that card's rules in homepage.css already applies — the
   haloed plate, the dots, the tone-fill action button, the bottom bar and all
   hover / dark / focus / phone-sideways behaviour. Nothing is restyled here.

   The ONE thing this page changes is the container layout. `hpx-icongrid` is a
   fixed CSS grid, and seven cards in a four-wide grid leave a ragged last row;
   a centred flex wrap sits the short row under the middle of the long one
   instead. `display:flex` at (0,3,0) overrides `.hpx-icongrid`'s grid at
   (0,1,0), and the kit's `grid-template-columns` media queries fall dead on a
   flex box — so the card's own ≤480px sideways rules (scoped to
   `.hpx-icongrid.hpx-ig-tile`) still fire, and phones get the sideways layout
   for free.
   ─────────────────────────────────────────────────────────────────────────── */
/* The showcase head sits in an `hpx-al-center` wrapper, which already centres
   it and its copy — this only owns the band rhythm and the sticky-header jump
   offset (the wrapper is the `#hpxs-browse` anchor). */
.hpx.hpxs .hpxs-browse-headwrap {
    margin-top: 40px;
    scroll-margin-top: 104px;
}

.hpx.hpxs .hpxs-browse {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: var(--hpx-g, 18px);
    margin-top: 12px;
}

/* A fixed card width so the wrap is even and the row stays centred. `0 1` — no
   grow — keeps every card one size instead of stretching the last row's three
   to fill the band. */
.hpx.hpxs .hpxs-browse .hpx-igcard {
    flex: 0 1 244px;
    animation: hpxsRise .5s var(--hpx-a-ease, ease-out) both;
    animation-delay: calc(var(--hpx-i, 0) * 45ms);
}


/* ═══ §RESP — responsive ═════════════════════════════════════════════════════
   The kit's own ladder, plus the browse grid's own steps. The card's internal
   rules are the homepage's; only the flex-basis is tuned here.
   ─────────────────────────────────────────────────────────────────────────── */
@media (max-width: 1024px) {
    .hpx.hpxs .hpxs-panel           { scroll-margin-top: 88px; }
    .hpx.hpxs .hpxs-browse-headwrap { scroll-margin-top: 88px; }
}

@media (max-width: 720px) {
    .hpx.hpxs .hpxs-stack { gap: 14px; }

    .hpx.hpxs .hpxs-empty { padding: 38px 16px 32px; }

    .hpx.hpxs .hpxs-e-stage {
        width: 136px;
        height: 122px;
        margin-bottom: 10px;
    }

    .hpx.hpxs .hpxs-e-r1 { width: 96px;  height: 96px; }
    .hpx.hpxs .hpxs-e-r2 { width: 134px; height: 134px; }

    .hpx.hpxs .hpxs-bigico {
        width: 58px;
        height: 58px;
        border-radius: 17px;
        font-size: 23px;
    }

    /* No Ctrl on a phone. */
    .hpx.hpxs .hpxs-e-kbd { display: none; }

    .hpx.hpxs .hpxs-browse-headwrap { margin-top: 32px; }

    /* Two-up before the card flips sideways at 480. */
    .hpx.hpxs .hpxs-browse .hpx-igcard { flex: 1 1 46%; min-width: 200px; }
}

/* ≤480 the homepage card turns sideways on its own (its rules key on
   `.hpx-icongrid.hpx-ig-tile`, which the container carries) — so all this has
   to do is let the card take the full row. */
@media (max-width: 480px) {
    .hpx.hpxs .hpxs-browse .hpx-igcard { flex: 1 1 100%; min-width: 0; }

    .hpx.hpxs .hpxs-e-actions .hpx-btn { width: 100%; justify-content: center; }
}


/* ═══ §MOTION ════════════════════════════════════════════════════════════════ */
@keyframes hpxsSpin {
    to { transform: rotate(360deg); }
}

@keyframes hpxsFloat {
    from { transform: translateY(3px); }
    to   { transform: translateY(-5px); }
}

/* Restates the kit plate's own inset + drop shadows so the halo is added on
   top of them, not swapped in for them. */
@keyframes hpxsBreathe {
    0%, 100% {
        box-shadow:
            inset 0 1px 0 rgba(255, 255, 255, .24),
            0 10px 22px -10px var(--tone-ink),
            0 0 0 0 var(--hpx-brand-glow, rgba(54, 128, 237, .28));
    }
    55% {
        box-shadow:
            inset 0 1px 0 rgba(255, 255, 255, .24),
            0 10px 22px -10px var(--tone-ink),
            0 0 0 16px rgba(54, 128, 237, 0);
    }
}

@keyframes hpxsRise {
    from { opacity: 0; transform: translateY(12px); }
    to   { opacity: 1; transform: translateY(0); }
}

@media (prefers-reduced-motion: reduce) {
    .hpx.hpxs .hpxs-chip i,
    .hpx.hpxs .hpxs-n,
    .hpx.hpxs .hpxs-bigico { transition: none; }

    .hpx.hpxs .hpxs-e-ring,
    .hpx.hpxs .hpxs-e-dot,
    .hpx.hpxs .hpxs-bigico,
    .hpx.hpxs .hpxs-browse .hpx-igcard { animation: none; }
}


/* ═══ §SRX-RESP — the result card across widths ══════════════════════════════
   Two ladders, and they are not the same ladder.

     · The CARD's own breakpoint is a `@container` query, because with auto-fit
       the card's width comes from the column count, not from the viewport —
       see the note at `.srx-card`.
     · The PANEL's chrome (head plate, title size, paddings) is viewport work,
       because a phone is a phone whatever the grid did.

   The `@media` copy of the card rule is a fallback for engines without
   container queries. At phone widths the two agree exactly, so an engine that
   honours both applies the same declarations twice and nothing fights.
   ─────────────────────────────────────────────────────────────────────────── */

/* Card narrower than a comfortable row → plate and copy stay side by side,
   the button drops to its own full-width line under both. Stacking the plate
   too would leave a 58px square alone on a line above a title. */
@container (max-width: 430px) {
    .hpx.hpxs .srx-row {
        grid-template-columns: auto minmax(0, 1fr);
        align-items: start;
        gap: 13px 14px;
    }

    .hpx.hpxs .srx-go   { grid-column: 1 / -1; }
    .hpx.hpxs .srx-btn  { width: 100%; }
}

@media (max-width: 1024px) {
    .hpx.hpxs .srx-grid { gap: 12px; }
    .hpx.hpxs .srx-desc { max-width: none; }
}

@media (max-width: 720px) {
    .hpx.hpxs .hpxs-panel { padding: 16px 14px 18px; }

    .hpx.hpxs .hpxs-panel .hpx-panel-head {
        gap: 9px 11px;
        padding-bottom: 13px;
    }

    .hpx.hpxs .srx-ico {
        width: 44px;
        height: 44px;
        border-radius: 13px;
        font-size: 18px;
    }

    .hpx.hpxs .hpxs-panel .hpx-title { font-size: 17.5px; }

    .hpx.hpxs .srx-count   { padding: 5px 10px; font-size: 11.5px; }
    .hpx.hpxs .srx-count-n { font-size: 12.5px; }

    /* It used to be hidden here — an inline `flex: 1` hairline had no slack to
       measure at this width and came out as a stray dash. Now that it is a
       full-width divider on its own line it works at every width, and a phone
       is where the separation between a head and the first card matters most. */
    .hpx.hpxs .srx-rule { margin-top: 1px; }

    .hpx.hpxs .srx-card { padding: 13px 14px; border-radius: 16px; }
    .hpx.hpxs .srx-row  { gap: 13px; }

    .hpx.hpxs .srx-plate {
        width: 50px;
        height: 50px;
        border-radius: 15px;
        font-size: 20px;
    }

    .hpx.hpxs .srx-mono { font-size: 21px; }
    .hpx.hpxs .srx-nm   { font-size: 15.5px; }
    .hpx.hpxs .srx-desc { font-size: 13px; }
}

/* Container-query fallback. Kept in step with the `@container` block above —
   edit both or neither. */
@media (max-width: 560px) {
    .hpx.hpxs .srx-row {
        grid-template-columns: auto minmax(0, 1fr);
        align-items: start;
        gap: 13px 14px;
    }

    .hpx.hpxs .srx-go  { grid-column: 1 / -1; }
    .hpx.hpxs .srx-btn { width: 100%; padding: 12px 16px; }
}

@media (max-width: 400px) {
    .hpx.hpxs .srx-card  { padding: 12px; }
    .hpx.hpxs .srx-plate { width: 44px; height: 44px; border-radius: 13px; font-size: 18px; }
    .hpx.hpxs .srx-mono  { font-size: 19px; }
    .hpx.hpxs .srx-line  { gap: 7px; }
}


/* ═══ §SRX-MOTION ════════════════════════════════════════════════════════════
   One sweep, played once per hover. It is an animation rather than a
   transition because it has to return to its start position afterwards, and a
   transition that reverses would drag the highlight back across the card. */
@keyframes srxSweep {
    0%   { opacity: 0; transform: translateX(-120%); }
    16%  { opacity: 1; }
    100% { opacity: 0; transform: translateX(120%); }
}

@media (prefers-reduced-motion: reduce) {
    .hpx.hpxs .srx-card,
    .hpx.hpxs .srx-card::before,
    .hpx.hpxs .srx-card::after,
    .hpx.hpxs .srx-plate,
    .hpx.hpxs .srx-rank,
    .hpx.hpxs .srx-btn,
    .hpx.hpxs .srx-btn .srx-arr { transition: none; }

    .hpx.hpxs .srx-sheen { display: none; }

    /* The lift goes; the colour, the border and the accent bar stay, so the
       card still answers the pointer without anything moving. */
    .hpx.hpxs .srx-card:hover,
    .hpx.hpxs .srx-card:active { transform: none; }

    .hpx.hpxs .srx-card:hover .srx-plate,
    .hpx.hpxs .srx-card:hover .srx-rank,
    .hpx.hpxs .srx-card:hover .srx-btn,
    .hpx.hpxs .srx-card:hover .srx-btn .srx-arr { transform: none; }
}


/* ═══ §LAZY — lazy rendering for large result sets ═══════════════════════════
   /search returns EVERY match of every vertical and offers nothing to click to
   see them — that is a standing decision and none of this changes it. What it
   changes is how much work a big result set costs, on two separate axes:

     · TRANSFER + PARSE — the panels ship `SearchResults::FIRST_SLICE` cards
       and the rest are fetched from /search/more as the visitor scrolls. That
       is markup and JS, not CSS; the sentinel below is its only surface here.
     · LAYOUT + PAINT — `content-visibility` on the card, so the cards that
       HAVE arrived cost nothing until they are near the viewport.

   Both were needed. A broad query ("ai") matched 1,408 tools: lazy fetching
   alone still leaves a visitor who scrolls with hundreds of live cards, and
   `content-visibility` alone still ships the 6.1MB document.
   ─────────────────────────────────────────────────────────────────────────── */

/* ⚠ `contain-intrinsic-size` IS NOT OPTIONAL HERE. Without it every skipped
     card measures 0 tall, the page collapses to a fraction of its real height
     and the scrollbar leaps on every scroll. `auto <length>` makes the browser
     REMEMBER each card's last real height and use the 106px guess only for one
     it has never rendered — which is what keeps the thumb steady while a
     ragged column of one- and two-line descriptions streams in.

   ⚠ This sits on the same element as `container-type: inline-size` (see §SRX).
     They compose: the card's inline size still comes from its grid track, so
     the `@container` stack point keeps firing while skipped, and only the
     BLOCK size is stood in for. Verified at 390px — the card still stacks. */
.hpx.hpxs .srx-card {
    content-visibility: auto;
    contain-intrinsic-size: auto 106px;
}

/* ── The sentinel ─────────────────────────────────────────────────────────
   Where a panel's rendered run stops. The loader watches it, fetches the next
   batch into the grid above and removes it when the vertical is exhausted, so
   it is only ever on screen for the moment a batch is in flight — it is a
   progress indicator, NOT a control. Nothing here is clickable except the
   `<noscript>` link inside it, which no JS-capable browser ever renders. */
.hpx.hpxs .srx-more {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    min-height: 56px;
    margin-top: 14px;
    padding: 12px 16px;
    border: 1px dashed var(--hpx-line-strong, var(--hpx-line));
    border-radius: 14px;
    color: var(--hpx-ink-3);
    font-size: 13px;
    font-weight: 500;
    text-align: center;
}

/* Failed fetch — the loader stops trying and says so rather than spinning at a
   visitor forever. It stays armed, so a later scroll retries. */
.hpx.hpxs .srx-more[data-failed="1"] .srx-more-spin { animation: none; opacity: .3; }

.hpx.hpxs .srx-more-spin {
    flex: 0 0 auto;
    width: 15px;
    height: 15px;
    border-radius: 50%;
    border: 2px solid rgba(var(--tone-rgb), .25);
    border-top-color: var(--tone-ink);
    animation: srxSpin .7s linear infinite;
}

/* ⚠ NEVER GIVE `<noscript>` A `display`. It was `display: contents` here for
     about an hour and printed its own source code at every visitor: when
     scripting is ENABLED the parser does not build elements inside `noscript`,
     it keeps the markup as one raw TEXT node, and the only thing hiding it is
     the UA's `noscript { display: none }`. Override that and the browser
     faithfully renders `<a class="srx-btn" href="…">Show all 1,408 results</a>`
     as visible text. There is no author-side styling of a noscript that is
     ever correct — style what is INSIDE it, which only a no-JS browser parses
     as elements. */
.hpx.hpxs .srx-more .srx-more-all {
    display: inline-flex;
    text-decoration: none;
}

@keyframes srxSpin { to { transform: rotate(360deg); } }

@media (max-width: 720px) {
    .hpx.hpxs .srx-more {
        min-height: 50px;
        margin-top: 12px;
        font-size: 12.5px;
    }
}

@media (prefers-reduced-motion: reduce) {
    /* The spinner is the one thing here that must keep moving — it is the only
       signal that a fetch is in flight — so it slows rather than stops. */
    .hpx.hpxs .srx-more-spin { animation-duration: 2.4s; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   §SRXLOGO — the result mark fills its plate                     (2026-08-25)
   ═══════════════════════════════════════════════════════════════════════════
   The same pass §TCLOGO ran on the directory cards and §SCLOGO ran on the
   homepage rails. `.srx-plate` is a 58px TINTED square and the mark inside it
   sat at 62% — a 36px logo with 11px of `--tone-bg` on every side. A search
   panel is the one place a reader scans marks rather than names, so this is
   where the small-logo-in-a-coloured-box reading costs the most.

     58px plate -> 58px mark      (52px at the phone step, and it follows)

   `object-fit: contain` is untouched and is what makes 100% safe: a square
   mark fills the plate exactly, a wide wordmark fits to width and centres.
   The plate already carries `overflow: hidden`, so a square mark is clipped to
   its own 17px curve and reads as an app icon.

   Only the `<img>` branch of `_srxcard.blade.php` moves. The inline `<svg>`
   below it stays at 54% — that is a VERTICAL's glyph drawn on a 24px grid, not
   a brand mark, and scaling it up is how a crisp glyph turns furry. The
   `.srx-mono` initial and the Font Awesome `<i>` are untouched for the same
   reason. Same carve-out §TCLOGO documents. */
.hpx.hpxs .srx-plate img { width: 100%; height: 100%; }


/* ── §SRXLOGO-RING) The border survives a full-bleed logo ─────────────────
   The plate's edge is an INSET box-shadow, which paints on its background,
   below the content. An opaque mark — and several ship their own white or
   black tile — covers it, and the plate loses its edge on exactly the cards
   where the tint no longer draws one.

   A pseudo redraws the same ring above the image. It has to restate BOTH
   states, because the resting ring and the hover ring are declared on the
   plate itself and neither reaches through the logo now. The hover shadow's
   second layer — the tone-coloured drop — is deliberately NOT restated: it
   falls outside the box, so the image never covered it. */
.hpx.hpxs .srx-plate { position: relative; }

.hpx.hpxs .srx-plate::after {
    content: '';
    position: absolute;
    inset: 0;
    z-index: 1;
    border-radius: inherit;
    pointer-events: none;
    box-shadow: inset 0 0 0 1px rgba(var(--tone-rgb), .22);
    transition: box-shadow .26s ease;
}

@media (hover: hover) {
    .hpx.hpxs .srx-card:hover .srx-plate::after { box-shadow: inset 0 0 0 1px rgba(var(--tone-rgb), .5); }
}
