/* Part Finder results page, redesigned to match Figma
   (cards: 1627-12386, list: 1627-17063). Wired to the same InstantSearch.

   THIS FILE MUST BE SELF-SUFFICIENT. It ships inside a Webflow Code
   Component, and Webflow renders those in a SHADOW ROOT (<code-island>).
   The marketing site's stylesheet does NOT cross that boundary, so the
   `.text-*` / `.heading-*` / `is-*` system classes on the markup style
   nothing there — verified 2026-08-24 on cloyes-stg/timing-systems, where
   `.pf-field-label` computed 14px/400 instead of 0.75rem/600.

   CSS custom properties DO inherit across the shadow boundary, so every
   size below is written token-first with a rem fallback:
   `var(--font-size--text-small, 0.875rem)`. The token keeps both surfaces
   on one ramp; the fallback keeps the component correct on a page that
   does not define the tokens. Never rely on a class this file does not
   itself define.

   Every value resolves against the Webflow tokens in webflow-tokens.css,
   so the finder inherits the marketing site's palette, type ramp and
   spacing scale — including the mobile variable mode, which retunes the
   type ramp below 991px without this file knowing about it.

   Sizes are rem throughout. The handful of literals left are control
   dimensions the design system has no token for (input heights, menu
   max-heights, thumbnail boxes); each carries its px equivalent so the
   Figma value stays traceable. */

/*
 * SEMANTIC MARGIN RESET — load-bearing, do not delete.
 *
 * This file is bundled two ways. In the Next.js app it sits alongside
 * webflow-system.css, whose `.text-medium, .text-regular, ... { margin: 0 }`
 * rule zeroes the browser's default `<p>` margins. But the finder ALSO ships
 * as a Webflow Code Component, and there it renders inside a SHADOW ROOT that
 * loads exactly one stylesheet: this component's own bundle. webflow-system.css
 * is not in it, so `.text-medium` / `.text-regular` are undefined, their margin
 * reset never lands, and every `<p>` falls back to the UA default `margin: 1em 0`.
 *
 * Measured on the published Timing Systems page before this rule: the product
 * card's title-to-part-number gap was 42px instead of 8px (title margin-bottom
 * 18px + the 8px flex gap + part-number margin-top 16px), and part-number to
 * "View Part" was 32px instead of 16px. All 24 semantic elements in the shadow
 * root were affected.
 *
 * :where() keeps this at specificity 0, so any existing rule still wins and
 * nothing downstream has to fight it.
 */
.pf :where(p, h1, h2, h3, h4, h5, h6, ul, ol, figure, blockquote) {
  margin: 0;
}

/*
 * BOX-SIZING RESET — load-bearing, and for the same reason as the margin
 * reset above.
 *
 * Every measurement in this file was authored against app/globals.css, whose
 * `*, *::before, *::after { box-sizing: border-box }` applies to the whole
 * Next app. That rule does not exist inside the shadow root, so on Webflow
 * the entire finder falls back to content-box and every element with both an
 * explicit width and padding renders wider than it was drawn.
 *
 * The visible one was .pf-sidebar: at <=991px it is width:100%, and its 24px
 * padding either side plus the 1px border land ON TOP of the full width and
 * push the page 50px past the viewport. The Webflow-side patch script pinned
 * that single case; the cause is general, so the reset is too — and it also
 * closes the desktop gap, where the sidebar was rendering 370px on Webflow
 * against the 320px it renders in the app.
 *
 * Copied from globals.css deliberately, selector shape and all: the two must
 * agree, or the same markup measures differently on the two surfaces.
 */
.pf,
.pf *,
.pf *::before,
.pf *::after {
  box-sizing: border-box;
}

/*
 * CONTROL FONT RESET — same reason as the margin reset above.
 *
 * `.pf` sets font-family, but form controls do NOT inherit it: the UA
 * stylesheet gives button/input/select/textarea their own family, and that
 * beats inheritance. On a Next page the `.text-*` system classes happened to
 * cover it up; in the shadow root they are undefined, so every control fell
 * back to the UA's Arial while the text around it rendered in Poppins.
 *
 * The tab strip is where it showed most (the tabs are `<button>`), which is
 * why the Webflow-side shadow-root patch script carried a `.pf-tab
 * { font-family: inherit }` line. It belongs here, and applied to every
 * control rather than to the one that was noticed — the search field is an
 * `<input>` and had exactly the same problem.
 *
 * Only the family. Size and weight stay with the per-control rules, and
 * :where() keeps this at specificity 0 so none of them have to fight it.
 */
.pf :where(button, input, select, textarea) {
  font-family: inherit;
}

.search-page {
  width: 100%;
}
.search-page__config-error {
  color: #b42318;
  background: #fef3f2;
  border: var(--border--1px) solid #fecdca;
  border-radius: var(--radius--8px);
  padding: var(--spacing--16px);
}

.pf {
  display: flex;
  flex-direction: column;
  gap: var(--spacing--40px);
  width: 100%;
  color: var(--color--ink);
  font-family: var(--font--body);
  /* Inherited by everything inside. The .text-* system classes used to
     supply this, but they cannot reach into the shadow root (see header). */
  line-height: var(--line-height--150, 1.5);
}
/* Search by Vehicle with its grid showing: 80px between the bar and the
   results on desktop (Lean, 2026-10-22). The query tabs' full-width list and
   the stacked mobile layout keep the 40px above. */
@media screen and (min-width: 992px) {
  .pf:has(> .pf-results:not(.pf-results--full)) {
    gap: var(--spacing--80px);
  }
}

/* ── Tabbed bar ─────────────────────────────────────────────── */
.pf-bar {
  display: flex;
  flex-direction: column;
}
/* No padding-left. The strip starts flush with the card below it — the
   active tab's left edge and the card's left edge are the same line in
   Figma, and a 4px inset broke that alignment. */
.pf-tabs {
  display: flex;
  gap: var(--spacing--12px);
  align-items: center;
}
.pf-tab {
  font-size: var(--font-size--text-small, 0.875rem);
  font-weight: var(--weight--semibold, 600);
  padding: var(--spacing--12px) var(--spacing--24px);
  letter-spacing: var(--letter-spacing--tight);
  line-height: var(--line-height--20px);
  color: var(--color--text-muted);
  background: transparent;
  border: none;
  border-radius: var(--radius--8px) var(--radius--8px) 0 0;
  cursor: pointer;
  transition: color var(--dur-fast, 0.2s) var(--ease-inout, ease),
    background-color var(--dur-fast, 0.2s) var(--ease-inout, ease);
}
/* Resting tabs brighten on hover. Colour only: tabs are controls, so no
   transform. */
@media (hover: hover) {
  .pf-tab:not(.pf-tab--active):hover {
    color: var(--color--ink, #14181f);
  }
}
.pf-tab:focus-visible {
  outline: 2px solid var(--color--blue-bright);
  outline-offset: 2px;
}
.pf-tab--active {
  background: var(--color--blue-bright);
  color: var(--color--white);
  border: var(--border--1px) solid #e3e7ec;
  border-bottom: none;
  border-radius: var(--radius--16px) var(--radius--16px) 0 0;
}

/*
 * On-dark tab strip — opt in with `surface="dark"` on SearchApp, or the
 * "Dark background" option on the Webflow component.
 *
 * The strip is the only part of the finder drawn onto the host page rather
 * than onto the card, so it is the only part whose colours depend on what is
 * behind it. Everything above is the Figma default (2388:8084) and assumes a
 * white page. This block is its inverse, for the one placement that sits on
 * the navy hero: the active tab becomes the white block so it still reads as
 * the front-most surface, and the resting tabs go translucent white.
 *
 * It must stay an opt-in and never become the default. Applied on a white
 * page it turns the resting tabs into near-white text on white — legible at
 * the border and nowhere else — which is what the staging /part-finder page
 * showed while a build carrying this treatment unconditionally was deployed.
 *
 * Only the three colour declarations are restated. Padding, radii, borders and
 * type all come from the rules above, so the two surfaces cannot drift into
 * different tab geometry. Hover lifts the resting label to full strength, the
 * on-dark counterpart of the light strip going to ink.
 */
.pf--on-dark .pf-tab {
  /* grey-50 at 70%, not white at 70%: the resting label should read as a
     recessive tint of the card's own surface colour, not as dimmed white. */
  color: rgba(245, 246, 249, 0.7);
}
@media (hover: hover) {
  .pf--on-dark .pf-tab:not(.pf-tab--active):hover {
    color: rgba(245, 246, 249, 1);
  }
}
.pf--on-dark .pf-tab--active {
  background: var(--color--white);
  color: var(--color--blue-bright);
}
/*
 * TEMPLATE PAGES - Stock / High Performance as underline tabs in the tab row
 * (Figma 2814:36099), on any scoped placement. `.pf-bar--scoped` is set when
 * the page has a product scope; /parts and the home bar keep the in-card
 * checkboxes. 12px apart, 24px sides, 14/20 SemiBold, 4px red underline on the
 * active one. The underline is reserved on both so switching moves nothing,
 * and padding-bottom gives back its 4px so the row stays the tabs' 44px.
 */
.pf-tabs-end {
  display: flex;
  margin-left: auto;
}
.pf-modes {
  display: flex;
  gap: var(--spacing--12px);
  align-items: center;
}
.pf-mode {
  font-size: var(--font-size--text-small, 0.875rem);
  font-weight: var(--weight--semibold, 600);
  line-height: var(--line-height--20px);
  letter-spacing: var(--letter-spacing--tight);
  padding: var(--spacing--12px) var(--spacing--24px) var(--spacing--8px);
  color: var(--color--text-muted);
  background: transparent;
  border: none;
  border-bottom: 0.25rem solid transparent;
  border-radius: var(--radius--8px) var(--radius--8px) 0 0;
  cursor: pointer;
  white-space: nowrap;
  transition: color var(--dur-fast, 0.2s) var(--ease-inout, ease),
    border-color var(--dur-fast, 0.2s) var(--ease-inout, ease);
}
.pf-mode--active {
  color: var(--color--ink, #14181f);
  border-bottom-color: var(--color--red);
}
.pf-mode:focus-visible {
  outline: 2px solid var(--color--blue-bright);
  outline-offset: 2px;
}
@media (hover: hover) {
  .pf-mode:not(.pf-mode--active):hover {
    color: var(--color--ink, #14181f);
  }
}
.pf--on-dark .pf-mode {
  color: rgba(245, 246, 249, 0.7);
}
.pf--on-dark .pf-mode--active {
  color: var(--color--white);
}
/* One view per width: the tab-row tabs from 768px, the in-card control below
   (the mobile template keeps it in the card as the 2-up segment). The divider
   goes with the in-card control it separates. */
@media screen and (min-width: 768px) {
  .pf-bar--scoped .pf-actions .pf-seg,
  .pf-bar--scoped .pf-actions .pf-vspacer {
    display: none;
  }
}
@media screen and (max-width: 767px) {
  .pf-tabs-end {
    display: none;
  }
}
.pf-bar-card {
  display: flex;
  flex-direction: column;
  gap: var(--spacing--24px);
  padding: var(--spacing--24px);
  background: var(--color--grey-50);
  border: var(--border--1px) solid #e3e7ec;
  border-radius: var(--radius--12px);
  box-shadow: 0 1.125rem 3.125rem -1.375rem rgba(13, 31, 56, 0.35);
}
.pf-bar-card--v {
  border-top-left-radius: 0;
}
.pf-fields {
  display: flex;
  gap: var(--spacing--16px);
  align-items: flex-end;
}
.pf-field {
  display: flex;
  flex-direction: column;
  gap: var(--spacing--12px);
  flex: 1 1 0;
  min-width: 0;
}
.pf-field--grow {
  flex: 1 1 0;
}
.pf-field-label {
  font-size: var(--font-size--text-tiny, 0.75rem);
  font-weight: var(--weight--semibold, 600);
  /* -0.01em, not the -0.02em `tight` token: Figma tracks the small
     control labels half as far. No Webflow token for this step. */
  letter-spacing: -0.01em;
  line-height: var(--line-height--14px);
  text-transform: uppercase;
  color: var(--color--text-muted);
}
.pf-select-wrap {
  position: relative;
  width: 100%;
}
.pf-select {
  display: flex;
  align-items: center;
  width: 100%;
  height: var(--size--button-height);
  background: var(--color--white);
  border: var(--border--1px) solid #d8dde3;
  border-radius: var(--radius--12px);
  padding: 0 0.875rem 0 var(--spacing--8px); /* 14px / 8px */
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.pf-select--open {
  border-color: var(--color--blue-bright);
}
/*
 * A field whose turn has not come. The row fills left to right, so Year waits
 * on Vehicle Type, Make on Year, and so on - see fieldPrerequisite, which owns
 * the rule.
 *
 * The fill is #f2f2f2 rather than --color--grey-50, and the difference is the
 * point: grey-50 is what a LIST ROW tints to on hover, so reusing it here would
 * give "unavailable" and "under the cursor" the same colour in one component.
 * #f2f2f2 is already the finder's unavailable surface - it is what
 * .pf-facet-row--off .pf-box fills with - so the two read as one idea.
 *
 * 0.55 on the contents matches .pf-facet-row--off for the same reason. It is on
 * the three children rather than the button, so the fill stays at full strength
 * underneath and the field keeps a body; fading the whole control turned it
 * into a gap in the row, which is the one thing a locked field must not look
 * like - it still has a label to read and a reason to show.
 *
 * cursor: default, matching .pf-btn-reset:disabled and the Webflow bar's own
 * .cl-pf-field.is-disabled. Not not-allowed: nothing here is forbidden, it is
 * only not this control's turn yet.
 */
/*
 * QA #15 replaces the treatment described above with the frame's own.
 *
 * Figma 2388:8086 marks a locked field exactly one way: 50% opacity on the
 * WHOLE filter group, label and control together. The control itself keeps its
 * white fill, its #D8DDE3 border and full-strength text — there is no grey
 * fill and no per-child fade.
 *
 * The note above argued the opposite, that fading the whole control turns it
 * into a gap in the row. That reasoning was sound on its own terms, but it was
 * a build-time judgement and the design says otherwise; the client asked for
 * the frame. Keeping it here because it is the thing to re-read if the dimmed
 * row ever reads as missing rather than as not-yet-your-turn.
 *
 * cursor: default still applies — nothing here is forbidden, it is only not
 * this control's turn yet.
 */
.pf-select:disabled {
  cursor: default;
}
.pf-field--locked {
  opacity: 0.5;
}
.pf-input {
  position: relative;
  display: flex;
  align-items: center;
  height: var(--size--button-height);
  background: var(--color--white);
  border: var(--border--1px) solid #d8dde3;
  border-radius: var(--radius--12px);
  padding: 0 var(--spacing--16px);
}
.pf-select-icon {
  width: 1.125rem; /* 18px */
  height: 1.125rem;
  margin: 0 var(--spacing--8px) 0 var(--spacing--4px);
  flex: 0 0 auto;
}
.pf-select-value {
  flex: 1 1 auto;
  min-width: 0;
  font-size: 0.8125rem; /* 13px */
  font-weight: var(--weight--medium);
  letter-spacing: -0.01em;
  color: #2d3037;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.pf-select-value--ph {
  color: var(--color--text-muted);
  font-weight: var(--weight--regular);
}
.pf-select-chev {
  width: var(--spacing--16px);
  height: var(--spacing--16px);
  margin-left: var(--spacing--8px);
  flex: 0 0 auto;
  pointer-events: none;
}
.pf-menu {
  position: absolute;
  top: calc(100% + var(--spacing--6px));
  left: 0;
  right: 0;
  z-index: 60;
  background: var(--color--white);
  border: var(--border--1px) solid #d8dde3;
  border-radius: var(--radius--12px);
  box-shadow: 0 1.125rem 3.125rem -1.375rem rgba(13, 31, 56, 0.35);
  max-height: 17.5rem; /* 280px */
  overflow: auto;
  padding: var(--spacing--6px);
}
/* Flipped above the button when there is no room below — see `dropUp` in
   search-app.tsx. `top: auto` has to be restated or the base rule's value
   keeps winning and the menu is anchored on both edges at once. */
.pf-menu--up {
  top: auto;
  bottom: calc(100% + var(--spacing--6px));
}
.pf-menu-search {
  width: 100%;
  box-sizing: border-box;
  padding: var(--spacing--8px) 0.625rem; /* 8px / 10px */
  margin-bottom: var(--spacing--6px);
  border: var(--border--1px) solid #d8dde3;
  border-radius: var(--radius--8px);
  font-size: 0.8125rem; /* 13px */
  outline: none;
}
.pf-menu-opts {
  display: flex;
  flex-direction: column;
}
.pf-opt {
  display: block;
  width: 100%;
  text-align: left;
  padding: 0.625rem var(--spacing--12px); /* 10px / 12px */
  border: none;
  background: none;
  border-radius: var(--radius--8px);
  font-size: 0.8125rem; /* 13px */
  color: #2d3037;
  cursor: pointer;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.pf-opt:hover {
  background: var(--color--grey-50);
}
.pf-opt--active {
  background: #eef2f8;
  font-weight: var(--weight--semibold);
}
.pf-menu-empty {
  padding: 0.625rem var(--spacing--12px);
  font-size: 0.8125rem; /* 13px */
  color: #949ca8;
}
.pf-input-el {
  flex: 1 1 auto;
  min-width: 0;
  border: none;
  outline: none;
  background: transparent;
  font-size: 0.8125rem; /* 13px */
  font-weight: var(--weight--medium);
  color: #2d3037;
}
.pf-input-el::placeholder {
  color: var(--color--text-muted);
}

.pf-actions {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--spacing--16px);
  min-height: 2.75rem; /* 44px */
}
/*
 * `display: contents` on both wrappers, so the actions row is byte-identical to
 * what it rendered before they were introduced. They exist only so the 767px
 * block can regroup them; see the mobile section at the end of this file.
 */
.pf-seg,
.pf-actions-btns {
  display: contents;
}
.pf-check {
  display: flex;
  align-items: center;
  gap: var(--spacing--8px);
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
}
.pf-box {
  display: flex;
  align-items: center;
  justify-content: center;
  width: var(--spacing--16px);
  height: var(--spacing--16px);
  border: var(--border--1px) solid var(--border--darker);
  border-radius: 0.3125rem; /* 5px */
  background: var(--color--white);
  flex: 0 0 auto;
}
.pf-box--on {
  background: var(--color--red);
  border-color: var(--color--red);
}
.pf-box img {
  width: 0.875rem; /* 14px */
  height: 0.875rem;
  display: block;
}
.pf-check-lbl {
  font-size: var(--font-size--text-small, 0.875rem);
  font-weight: var(--weight--medium, 500);
  letter-spacing: -0.01em;
  color: #2d3037;
}
.pf-vspacer {
  width: var(--border--1px);
  height: var(--spacing--12px);
  border-radius: var(--radius--pill);
  background: var(--border--muted);
  flex: 0 0 auto;
}
.pf-btn-reset {
  font-size: var(--font-size--text-small, 0.875rem);
  font-weight: var(--weight--semibold, 600);
  color: var(--color--text-muted);
  padding: var(--spacing--12px) var(--spacing--16px);
  border: none;
  background: none;
  border-radius: var(--radius--8px);
  cursor: pointer;
}
.pf-btn-reset:disabled {
  color: rgba(90, 100, 114, 0.5);
  cursor: default;
}
.pf-btn-find {
  font-size: var(--font-size--text-small, 0.875rem);
  font-weight: var(--weight--semibold, 600);
  display: flex;
  align-items: center;
  gap: var(--spacing--12px);
  color: var(--color--white);
  padding: var(--spacing--12px) var(--spacing--16px);
  border: none;
  border-radius: var(--radius--8px);
  cursor: pointer;

  /*
   * `.btn.is-primary`, transcribed from the published stylesheet
   * (cloyes-stg.webflow.io/stylesheet). The track is twice the button's
   * width: flat red for the first half, the red gradient for the second.
   * At rest only the flat half shows; hover slides the track across, which
   * is the gradient wipe. Colours are the tokens with the published values
   * as fallbacks, because inside the Webflow shadow root the tokens are only
   * there if the host page defines them.
   */
  background-color: var(--color--red, #db192a);
  background-image: linear-gradient(
    90deg,
    var(--color--red, #db192a) 0% 50%,
    var(--color--red-gradient-start, #dc192b) 50%,
    var(--color--red-gradient-end, #930512) 100%
  );
  background-position: 0% center;
  background-repeat: no-repeat;
  background-size: 200% 100%;
  box-shadow:
    0 0.0625rem 0.1875rem transparent,
    0 0.375rem 0.375rem transparent,
    0 0.8125rem 0.5rem transparent;
  /* The published per-property timings: the wipe trails on 0.4s, the rest
     lands on 0.2s. column-gap and padding on --ease-out like the stylesheet's
     gap; the others on its plain `ease`. */
  transition:
    background-position 0.4s ease,
    box-shadow var(--dur-fast, 0.2s) ease,
    column-gap var(--dur-fast, 0.2s) var(--ease-out, ease),
    padding var(--dur-fast, 0.2s) var(--ease-out, ease);
}
/*
 * Hover: the wipe, the shadow, and the arrow moving by a GAP change (0.75rem
 * to 1rem), never a translate. One deliberate difference from the reference:
 * the 0.25rem the gap gains is taken back from the right padding. Find Parts
 * sits in a flex row beside Reset vehicle and the Stock/HP checks, and a
 * button that widened on hover would shove all of them sideways under the
 * cursor. The label stays put and only the arrow moves, as on the site.
 *
 * Only where hovering is real, and never on a disabled Search (below the
 * minimum query length), which must not look pressable.
 */
@media (hover: hover) {
  .pf-btn-find:not(:disabled):hover {
    background-position: 100% center;
    column-gap: var(--spacing--16px);
    padding-right: var(--spacing--12px);
    box-shadow:
      0 0.0625rem 0.1875rem rgba(0, 0, 0, 0.03),
      0 0.375rem 0.375rem rgba(0, 0, 0, 0.03),
      0 0.8125rem 0.5rem rgba(0, 0, 0, 0.02);
  }
}
@media (prefers-reduced-motion: reduce) {
  .pf-btn-find {
    transition: none;
  }
}
.pf-btn-search {
  height: var(--size--button-height);
  justify-content: center;
}
.pf-arrow {
  font-size: 0.9375rem; /* 15px */
  line-height: var(--line-height--100);
}
/* Both arrows are Figma's own glyphs rather than the `→` character (see
   ViewPartArrow and ButtonArrow). Each SVG carries its size as px attributes,
   so it is restated here in rem to keep it on the fluid root with everything
   else; `display: block` drops the inline baseline gap that would otherwise
   sit the arrow a pixel low against its label. Two sizes because they are two
   drawings: 13x10 for a link, 16x16 on the button's own grid. */
.pf-arrow svg {
  display: block;
}
.pf-viewpart .pf-arrow svg {
  width: 0.8125rem; /* 13px */
  height: 0.625rem; /* 10px */
}
.pf-btn-find .pf-arrow svg {
  width: 1rem; /* 16px */
  height: 1rem;
}
.pf-searchrow {
  display: flex;
  gap: var(--spacing--16px);
  align-items: flex-end;
}
.pf-searchfield {
  position: relative;
  flex: 1 1 auto;
  min-width: 0;
}
.pf-suggest {
  position: absolute;
  top: calc(100% + var(--spacing--6px));
  left: 0;
  right: 0;
  z-index: 60;
  background: var(--color--white);
  border: var(--border--1px) solid #d8dde3;
  border-radius: var(--radius--12px);
  box-shadow: 0 1.125rem 3.125rem -1.375rem rgba(13, 31, 56, 0.35);
  max-height: 20rem; /* 320px */
  overflow: auto;
  padding: var(--spacing--6px);
}
.pf-suggest-opt {
  display: flex;
  align-items: baseline;
  gap: 0.625rem; /* 10px */
  width: 100%;
  text-align: left;
  padding: 0.625rem var(--spacing--12px);
  border: none;
  background: none;
  border-radius: var(--radius--8px);
  cursor: pointer;
}
.pf-suggest-opt--active {
  background: #eef2f8;
}
.pf-suggest-pn {
  font-weight: var(--weight--semibold);
  font-size: 0.8125rem; /* 13px */
  color: #14284a;
}
.pf-suggest-title {
  font-size: 0.8125rem; /* 13px */
  color: var(--color--text-muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.pf-suggest-map {
  margin-left: auto;
  font-size: var(--font-size--text-tiny);
  color: #949ca8;
}

/* ── Results shell ──────────────────────────────────────────── */
.pf-results {
  display: flex;
  gap: var(--spacing--32px);
  align-items: flex-start;
}
.pf-sidebar {
  width: 20rem; /* 320px */
  flex: 0 0 20rem;
  display: flex;
  flex-direction: column;
  gap: var(--spacing--20px);
  background: var(--color--white);
  border: var(--border--1px) solid #e3e7ec;
  border-radius: var(--radius--12px);
  /* 24px less the 1px border. Figma (3114:12634) strokes the panel inside its
     320px, so its content is 272px; a full 24px of padding on top of an
     outside border left 270, and every facet row 2px short of the frame. */
  padding: calc(var(--spacing--24px) - var(--border--1px));

  /* Desktop only — the filters follow the reader down a long grid.
   *
   * `.pf-results` already sets `align-items: flex-start`, which is what makes
   * this work at all: the default `stretch` would size the sidebar to the full
   * row height, leaving it nothing to travel within.
   *
   * The max-height is not decoration. The panel is ~34rem with a fresh
   * catalog, but facet lists grow as a vehicle narrows the results, and a
   * sticky element taller than the viewport pins its TOP off-screen — the last
   * facets would become unreachable, with no scrollbar to reveal them. Capping
   * it to the visible area and letting it scroll internally keeps every filter
   * reachable at any height. It costs nothing while the panel is short, since
   * `auto` shows no scrollbar until there is overflow. */
  position: sticky;
  top: var(--spacing--24px);
  max-height: calc(100vh - var(--spacing--24px) * 2);
  overflow-y: auto;
}
.pf-main {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: var(--spacing--56px);
}

/* ── Sidebar ────────────────────────────────────────────────── */
.pf-sidebar-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.pf-sidebar-title {
  font-size: var(--font-size--text-medium, 1.125rem);
  font-weight: var(--weight--semibold, 600);
  letter-spacing: var(--letter-spacing--tight);
  color: var(--color--ink);
}
.pf-clear {
  font-size: var(--font-size--text-small, 0.875rem);
  color: rgba(90, 100, 114, 0.7);
  text-decoration: underline;
  background: none;
  border: none;
  cursor: pointer;
}
.pf-clear:disabled {
  color: rgba(90, 100, 114, 0.35);
  cursor: default;
}
.pf-vehicle {
  display: flex;
  flex-direction: column;
  gap: var(--spacing--8px);
  background: var(--color--blue-bright);
  border-radius: var(--radius--12px);
  padding: var(--spacing--16px);
}
.pf-vehicle-top {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--spacing--8px);
}
.pf-vehicle-icon {
  width: 1.125rem; /* 18px */
  height: 1.125rem;
  flex: 0 0 auto;
  filter: brightness(0) invert(1);
}
.pf-vehicle-name {
  font-size: var(--font-size--text-small, 0.875rem);
  font-weight: var(--weight--medium, 500);
  flex: 1 1 auto;
  color: var(--color--white);
  letter-spacing: var(--letter-spacing--tight);
}
.pf-vehicle-change {
  font-size: var(--font-size--text-tiny, 0.75rem);
  color: var(--overlay--white-75);
  text-decoration: underline;
  background: none;
  border: none;
  cursor: pointer;
  flex: 0 0 auto;
}
.pf-vehicle-mode {
  font-size: var(--font-size--text-tiny, 0.75rem);
  color: var(--overlay--white-75);
}
/*
 * Two lines held open, whether or not there is text in them yet.
 *
 * This line swaps a `.pf-skel--count` bar for its sentence on EVERY search,
 * not only the first: a 14px placeholder became a 42px two-line string and
 * shoved the view toggle and both facet groups down 28px each time. In the
 * 320px sidebar "Showing 3429 of 3429 compatible results" is always two
 * lines; the query tabs' shorter wording is one, so two is the common case
 * rather than the worst one.
 *
 * min-height rather than height, so a longer string still wraps past it, and
 * computed from the two tokens the text is actually set in rather than from
 * the 42px that happens to fall out of them today.
 */
.pf-showing {
  font-size: var(--font-size--text-small, 0.875rem);
  color: var(--color--text-muted);
  min-height: calc(
    2 * var(--line-height--150, 1.5) * var(--font-size--text-small, 0.875rem)
  );
}
/*
 * Figma 2814:15539 holds the line and Card / List 16px apart. The reserved
 * second line used to sit under a one-line string, so the gap read as the
 * sidebar's 20px plus an empty 21px line. The text now sits on the bottom of
 * its box, the spare line goes above it, and the toggle closes to 16px.
 */
.pf-sidebar .pf-showing {
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
}
.pf-sidebar .pf-showing + .pf-viewtoggle {
  margin-top: calc(var(--spacing--16px) - var(--spacing--20px));
}
.pf-viewtoggle {
  display: flex;
  gap: var(--spacing--12px);
}
.pf-viewbtn {
  font-size: var(--font-size--text-regular, 1rem);
  font-weight: var(--weight--semibold, 600);
  flex: 1 1 0;
  padding: var(--spacing--8px) var(--spacing--16px);
  border: none;
  border-radius: var(--radius--8px);
  background: var(--color--grey-50);
  color: var(--color--text-muted);
  cursor: pointer;
}
.pf-viewbtn--active {
  background: var(--color--blue-bright);
  color: var(--color--white);
}
.pf-facet {
  display: flex;
  flex-direction: column;
  border-top: var(--border--1px) solid #d8dde3;
  padding-top: var(--spacing--16px);
}
.pf-facet-head {
  font-size: var(--font-size--text-regular, 1rem);
  font-weight: var(--weight--semibold, 600);
  letter-spacing: -0.01em; /* -0.16px at 16px */
  color: #2d3037;
  padding-bottom: var(--spacing--4px);
}
.pf-facet-row {
  display: flex;
  align-items: center;
  /*
   * No gap. Figma (3114:12708) spaces the checkbox from the name by 8px and
   * then pushes the count to the far edge with space-between: there is no
   * gap between the name and the count. A row gap of 8px put one there too,
   * and those 8px are what wrapped "Timing Chain Components" at 1440. The
   * box-to-name 8px is the box's own margin below.
   */
  gap: 0;
  padding: var(--spacing--8px) 0;
  /* The whole row toggles the filter — it is a <label> around the checkbox —
     so the whole row has to say so. The real input carries cursor: pointer,
     but it is opacity 0 and 16px square, so everywhere the visitor actually
     aims (the name, the count, the gap between them) showed an arrow. The
     --off rule below resets this to default for a row with nothing behind
     it, and wins on order. */
  cursor: pointer;
}
/*
 * Subcategories, indented under their parent line on the rule Figma draws
 * (2388:9612). A left border on the container rather than a pseudo-element:
 * it then spans exactly the rows present, with no height to keep in sync.
 */
.pf-subfacets {
  display: flex;
  flex-direction: column;
  /* 7px + the 1px rule + 16px = Figma's 24px indent (3114:12705, pl-7). */
  margin-left: calc(var(--spacing--8px) - var(--border--1px));
  padding-left: var(--spacing--16px);
  border-left: var(--border--1px) solid var(--border--muted);
}

/*
 * A value that exists in the taxonomy but has nothing behind it for this
 * search. Greyed and unclickable, never hidden: "Heavy Duty 0" tells the
 * visitor the line exists and is empty here, which a missing row cannot.
 */
.pf-facet-row--off {
  cursor: default;
}
.pf-facet-row--off .pf-facet-name,
.pf-facet-row--off .pf-facet-count {
  color: var(--color--text-muted);
  opacity: 0.55;
}
/* A filled box rather than an empty white one. At 0.55 opacity the border
   alone was nearly gone, so a row with nothing behind it read as a gap in the
   list instead of as a filter that exists and happens to be empty — which is
   the whole point of keeping those rows on screen. The fill gives it a body at
   the same weight as the greyed label beside it. */
.pf-facet-row--off .pf-box {
  opacity: 0.55;
  background-color: #f2f2f2;
}

/*
 * The real checkbox, kept for keyboard and screen readers, but not the thing
 * on screen — `.pf-box` beside it is. A native checkbox cannot take a border
 * radius (`appearance` is `auto`, so the UA draws it), and `accent-color`
 * could only ever tint it blue-bright. Figma gives these the same 5px red box
 * the Stock / High Performance rows already use.
 *
 * Hidden with opacity rather than `display: none` or `visibility: hidden`, so
 * it stays focusable and still announces its checked state.
 */
.pf-facet-row input {
  position: absolute;
  width: var(--spacing--16px);
  height: var(--spacing--16px);
  margin: 0;
  opacity: 0;
  cursor: pointer;
  flex: 0 0 auto;
}
/* The 8px between box and name (the row itself has no gap, see above). */
.pf-facet-row .pf-box {
  margin-right: var(--spacing--8px);
}
/* The focus ring has to move to the box, since the input itself is invisible. */
.pf-facet-row input:focus-visible + .pf-box {
  outline: 2px solid var(--color--blue-bright);
  outline-offset: 2px;
}
.pf-facet-name {
  font-size: var(--font-size--text-small, 0.875rem);
  font-weight: var(--weight--medium, 500);
  flex: 1 1 auto;
  letter-spacing: -0.01em;
  color: #2d3037;
}
.pf-facet-count {
  font-size: var(--font-size--text-tiny, 0.75rem);
  font-style: normal;
  color: var(--color--ink);
  background: var(--color--white);
  border: var(--border--1px) solid var(--border--muted);
  border-radius: var(--radius--8px);
  /* Figma's pill is 8px each side INCLUDING its inside stroke, so the padding
     is 7px; 8px plus an outside border made every count 2px wider. Tracking
     is Figma's -0.24px at 12px. */
  padding: var(--spacing--2px) calc(var(--spacing--8px) - var(--border--1px));
  letter-spacing: -0.02em;
  min-width: 1.75rem; /* 28px */
  text-align: center;
  /* Never shrink below the digits. The name beside it is `flex: 1 1 auto`, so
     without this the pill is squeezed to its 28px minimum and a four-character
     count ("999+") spills over its own border. */
  flex: 0 0 auto;
}
.pf-facet-row--disabled .pf-facet-name,
.pf-facet-row--disabled .pf-facet-count {
  color: rgba(90, 100, 114, 0.4);
}

/* ── Card grid ──────────────────────────────────────────────── */
.pf-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--spacing--16px);
}
/*
 * An <a>, not a <div> - the whole card navigates. See PartCard, and
 * .cl-news-card.is-link on the marketing site, which is the same shape.
 *
 * The two extra declarations are what an anchor needs and a div did not.
 * The colour one matters most: without it the UA paints every descendant
 * link-blue, and while .pf-card-title and .pf-card-pn set their own colours,
 * anything added to the card later would inherit the wrong one by default.
 *
 * Nothing here sets a cursor. An <a href> is a pointer already, and .pf-card
 * is also CardSkeleton's class - a placeholder has no href, so it keeps the
 * default arrow, which is what a card with nothing behind it should show.
 */
.pf-card {
  display: flex;
  flex-direction: column;
  border: var(--border--1px) solid var(--border--muted);
  border-radius: var(--radius--12px);
  overflow: hidden;
  background: var(--color--white);
  text-decoration: none;
  color: inherit;
}
/*
 * The focus ring the card now needs, being a single tab stop where it used to
 * be a link buried in a div. Taken from .cl-news-card.is-link:focus-visible on
 * the marketing site - blue, 2px, 3px offset - so the two card types ring
 * identically on a page that shows both.
 *
 * An outline rather than a border or a box-shadow: .pf-card clips its children
 * with overflow: hidden, and the offset puts this ring outside that clip.
 * :focus-visible, not :focus, so a mouse click does not leave a ring behind.
 */
.pf-card:focus-visible {
  outline: 2px solid var(--color--blue);
  outline-offset: 3px;
}
.pf-card-img {
  height: 9.6875rem; /* 155px */
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--color--white);
  /* Clips the hover zoom. .pf-card clips it too, but only at the card's outer
     edge — without this the growing shot would cross into .pf-card-body and
     sit over the title on its way. */
  overflow: hidden;
}
/*
 * Inset the product shot inside its box rather than letting it fill the
 * frame, so the card keeps a margin of white around the part.
 *
 * Percentages, not rem, so the inset stays proportional to the card at
 * every grid breakpoint. `max-height` resolves because `.pf-card-img`
 * has a definite height.
 *
 * A fixed `width` with a clamping `max-height` would normally squash the
 * image; it does not here because `.pf-thumb` sets `object-fit: contain`,
 * which letterboxes the content inside the element box and preserves the
 * aspect ratio. Keep that `object-fit` if this rule stays.
 *
 * Descendant selector (0,1,1) so it outranks `.pf-thumb`'s own
 * `max-width: 100%` / `width: auto` without needing !important.
 */
.pf-card-img img {
  width: 80%;
  max-height: 70%;
}
/* The body fills the card and View Part sits on its floor, so a card with a
   fitment note and one without still line their links up across a grid row. */
.pf-card-body {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  gap: var(--spacing--16px);
  padding: var(--spacing--16px);
  background: var(--color--grey-50);
}
.pf-card-body > .pf-viewpart {
  margin-top: auto;
}
.pf-card-text {
  display: flex;
  flex-direction: column;
  gap: var(--spacing--8px);
  min-width: 0;
}
.pf-card-title {
  font-size: var(--font-size--text-medium, 1.125rem);
  font-weight: var(--weight--bold, 700);
  letter-spacing: var(--letter-spacing--tight);
  line-height: var(--line-height--140);
  color: var(--color--ink);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/*
 * Red and semibold so the part number stands out on the card: client QA asked
 * for it to read as the thing you came for, not as muted metadata. Kept in
 * step with .pf-row-pn so the grid and the list mark the number the same way.
 */
.pf-card-pn {
  font-size: var(--font-size--text-regular, 1rem);
  font-weight: var(--weight--semibold, 600);
  color: var(--color--red);
  line-height: var(--line-height--150);
}
/* The fitment note on a card, in the row meta's muted grey. One line, like
   the title: a long note ("Stl; Flat; w/o Hdwr; 90mm; 33.5mm") truncates and
   the full text is in the title attribute. */
.pf-card-note {
  margin: var(--spacing--0);
  color: var(--color--text-muted);
  line-height: var(--line-height--150);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.pf-viewpart {
  font-size: var(--font-size--text-small, 0.875rem);
  font-weight: var(--weight--semibold, 600);
  display: inline-flex;
  align-items: center;
  gap: var(--spacing--6px);
  color: var(--color--blue-bright);
  letter-spacing: var(--letter-spacing--tight);
  text-decoration: none;
  flex: 0 0 auto;
}

/*
 * Card hover — the treatment the marketing site gives .cl-news-card on
 * /timing-systems, brought over. It lives in the sitewide motion embed there
 * (Site Settings > Custom Code, the "Cards: lift 4px, image zoom 10%" block),
 * which the finder never sees: this renders inside a shadow root, so every
 * sitewide rule stops at the boundary and only the custom properties cross.
 *
 * Figma annotates that row "Card hover state: image zoom 10%, button arrow
 * expands gap by 8px". Two departures from it, both deliberate:
 *
 *   The zoom is 1.15, not the site's 1.1. A news card's photo fills its frame
 *   edge to edge; a part sits inset at 80% of a white well, so the same 10%
 *   moves a much smaller shape and barely registers.
 *
 *   The arrow moves by GAP, never by transform — .btn-tertiary on the Webflow
 *   side grows column-gap to 1rem and the motion directive forbids transform
 *   on controls outright. .pf-viewpart rests at 6px rather than the site's
 *   8px, so 1rem is a slightly longer throw than "+8px", and is the same
 *   destination, which is what keeps the two surfaces looking alike.
 *
 * Inside @media (hover: hover) like every other hover in this file, so a tap
 * on a touch device cannot leave a card parked mid-zoom with no way back.
 */
@media (hover: hover) {
  .pf-card:hover .pf-card-img img {
    transform: scale(1.15);
  }
  /* column-gap, not the gap shorthand: only the horizontal one changes, and
     naming the longhand keeps the transition below matched to it. */
  .pf-card:hover .pf-viewpart {
    column-gap: 1rem;
  }
}

/* Photo placeholder */
.pf-photo {
  display: flex;
  align-items: center;
  gap: var(--spacing--8px);
}
.pf-photo-dash {
  width: var(--spacing--12px);
  height: var(--spacing--2px);
  border-radius: var(--radius--pill);
  background: var(--color--red);
}
.pf-photo-text {
  font-size: 0.9375rem; /* 15px */
  font-weight: var(--weight--semibold);
  letter-spacing: var(--letter-spacing--tight);
  color: var(--color--text-muted);
  white-space: nowrap;
}
.pf-photo--compact .pf-photo-text {
  font-size: 0.5625rem; /* 9px */
  letter-spacing: var(--letter-spacing--none);
}
.pf-photo--compact .pf-photo-dash {
  width: var(--spacing--6px);
}

/* ── List ───────────────────────────────────────────────────── */
.pf-list {
  display: flex;
  flex-direction: column;
  gap: var(--spacing--16px);
}
.pf-row {
  display: flex;
  /* stretch, not center: the thumbnail well is a full-height panel now, so it
     has to run the height of the row rather than sit centred inside it. */
  align-items: stretch;
  gap: var(--spacing--16px);
  /* No padding on the row itself. The image well supplies the left inset, the
     text its own vertical inset, and View Part the right one — which is what
     lets the well reach the row's top and bottom edges. */
  padding: 0;
  /* Clips the well to the row's corner radius. */
  overflow: hidden;
  border: var(--border--1px) solid var(--border--muted);
  border-radius: var(--radius--12px);
  background: var(--color--white);
}
/*
 * Figma 2388:11544, annotated "List item active hover state": the row tints to
 * grey-50 on hover.
 *
 * Inside @media (hover: hover) per the motion directive, so a touch device
 * cannot leave a row stuck in the hovered tint after a tap. The colour eases
 * rather than snapping — see the Hover motion block — and there is no
 * transform, which the directive forbids on controls.
 */
@media (hover: hover) {
  .pf-row:hover {
    background: var(--color--grey-50);
  }
  /*
   * The image well stays white while the rest of the row tints, separated by
   * the hairline Figma draws (2388:14711). Catalog photography is shot on
   * white, so tinting behind it would put a grey frame around every cutout.
   * The divider appears only on hover because at rest there are no two
   * surfaces to divide.
   */
  .pf-row:hover .pf-row-thumb {
    background: var(--color--white);
    border-right: var(--border--1px) solid var(--border--muted);
  }
  /*
   * And the text steps away from the divider, so the row opens up under the
   * cursor rather than only changing colour.
   *
   * --spacing--16px, which IS 1rem - the token rather than the literal, so it
   * stays on the fluid root with the row's own gap and inset.
   *
   * This is the one hover in the file that moves layout, and it is safe here
   * for a reason worth stating: .pf-row-text is flex: 1 1 auto with
   * min-width: 0, and the row's width is fixed by the list. So the padding
   * comes out of the text's own content box - it shrinks, the title and meta
   * were already truncating with an ellipsis, and nothing beside it moves.
   * View Part is flex: 0 0 auto and stays exactly where it was. Try the same
   * trick on a row whose width is content-driven and it pushes the whole row.
   */
  .pf-row:hover .pf-row-text {
    padding-left: var(--spacing--16px);
  }
}
.pf-row-thumb {
  /* A panel, not a box: auto width so it hugs the 80px image, full height so
     it reads as its own surface against the tinted row on hover. */
  width: auto;
  height: unset;
  min-height: 100%;
  /* Square, at rest and on hover both. The well is a panel running into the
     row's own rounded corner, which `overflow: hidden` on .pf-row clips for
     it; a radius of its own would round the inside edge as well and read as a
     floating tile. */
  border-radius: 0;
  /* Held open, not absent. Hover draws the divider on this same edge, and a
     border that appears from nothing takes a pixel out of the well and nudges
     every line of text beside it — a whole row twitching under the cursor. */
  border-right: var(--border--1px) solid transparent;
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  /*
   * White, like every other product-image well in the app. The catalog
   * photography is all shot on a white field, so any tinted background shows up
   * as a visible frame around the cutout instead of reading as part of the
   * photo. Matches `.pf-card-img` here, and `.pd-gallery__main`,
   * `.pd-gallery__thumb` and `.pd-card__media` on the product detail page.
   */
  background: var(--color--white);
  overflow: hidden;
}
.pf-row-text {
  flex: 1 1 auto;
  min-width: 0;
  /* Its own vertical inset, now that the row has none, and centred against a
     well that is taller than the two lines of text. */
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding-top: var(--spacing--16px);
  padding-bottom: var(--spacing--16px);
}
.pf-row-title {
  font-size: var(--font-size--text-regular, 1rem);
  color: var(--color--ink);
  line-height: var(--line-height--140);
}
.pf-row-pn {
  font-weight: var(--weight--bold);
  color: var(--color--red);
}
.pf-row-meta {
  font-size: var(--font-size--text-small, 0.875rem);
  color: var(--color--text-muted);
  margin-top: var(--spacing--4px);
  /*
   * One line, truncated. The fitment note that lands here is usually a word
   * ("Upper", "Left") but can be a full spec string —
   * "Stl; Flat; w/o Hdwr; 90mm; 33.5mm" — and wrapping that would push the row
   * taller than every other row in the list. The element carries a `title`
   * with the full text whenever there is a note, so nothing is unreachable.
   */
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ── Query-tab results (Part Number / Cross Reference) ──────── */
/*
 * Figma 2388:12357 (part) and 2388:12485 (cross). One full-width list, no
 * sidebar, no card/list toggle — a part-number lookup has nothing to filter.
 *
 * `--full` carries no declarations of its own: .pf-main is already
 * `flex: 1 1 0`, so removing the sidebar from the flex row is what widens it.
 * The class exists so the layout is legible in the inspector and so a future
 * full-width-only rule has somewhere to live.
 */
.pf-qresults {
  display: flex;
  flex-direction: column;
  gap: var(--spacing--16px);
}
/*
 * TYPE IN THIS BLOCK FOLLOWS THE PUBLISHED SYSTEM, NOT THE FIGMA FRAME.
 *
 * The stylesheet (cloyes-stg.webflow.io/stylesheet) splits type in two.
 * Section 3, the prose scale, is five sizes at line height 150% with no
 * tracking, composed as a size class plus a weight combo. Section 7, the UI
 * text styles, are four named styles with deliberately tighter line heights,
 * and it says why: "because the text sits inside fixed-height controls" —
 * .cl-pf-tab 14/20/-2%, .cl-pf-label 12/14/-1%, .cl-pf-val 13/16/-1%,
 * .cl-pf-check-lbl 14/21/0.
 *
 * A results row is prose in a box that grows with its content, not a
 * fixed-height control, so it takes the section 3 rule. The Figma frames
 * (2388:12393, 2388:12485) draw this text at 1.4 line height with -1% and -2%
 * tracking, which is the control treatment applied to content; those values
 * were transcribed literally here at first and are what made the results read
 * a size off from the rest of the site. Sizes and weights still come straight
 * from the frames — only the rhythm is the system's.
 */
.pf-qcount {
  display: flex;
  align-items: center;
  gap: var(--spacing--12px);
  font-size: var(--font-size--text-regular, 1rem);
  line-height: var(--line-height--150, 1.5);
  color: var(--color--text-muted);
}
/*
 * The line above a closest-match list.
 *
 * Muted, and sized one step below the count above it, because it is an aside
 * about the answer rather than the answer. The two stems are bold so the
 * difference between what was typed and what was searched is readable at a
 * glance — that difference is the entire content of the sentence.
 */
.pf-qclosest {
  font-size: var(--font-size--text-small, 0.875rem);
  line-height: var(--line-height--150, 1.5);
  color: var(--color--text-muted);
  margin-bottom: var(--spacing--12px);
}
.pf-qclosest strong {
  font-weight: var(--weight--semibold, 600);
  color: var(--color--ink);
}
/* Figma draws this as a 3.6px vector, in the count line and again between the
   two meta values on a Part Number row. A bullet glyph is the same mark
   without an image request, scaled down because Poppins' own bullet is much
   larger than the drawn dot. */
.pf-dot {
  font-size: 0.5rem; /* 8px */
  line-height: 1;
}
.pf-qlist {
  display: flex;
  flex-direction: column;
  gap: var(--spacing--16px);
}
/*
 * The query-tab row, built like the list row it sits beside.
 *
 * Same construction as `.pf-row`: no padding of its own, a full-height white
 * image well supplying the left inset, the body supplying its own, and the
 * whole thing tinting on hover with the well staying white behind the cutout.
 * The two are the same object — a result you can click through to a part — and
 * were only drawn differently because they were built weeks apart.
 *
 * The one structural difference stays: this row is a COLUMN, because Cross
 * Reference hangs an interchange block under the main line. So the well runs
 * the height of `.pf-qrow-main` rather than of the whole row, which is the
 * part of it that has a thumbnail to sit beside.
 */
.pf-qrow {
  display: flex;
  flex-direction: column;
  /* Figma reads 23px, which is the auto-layout gap either side of a 1px
     divider. 24px is the scale value and the 1px difference is not visible. */
  gap: var(--spacing--24px);
  /* None, like .pf-row: the well, the body and the interchange block each
     carry their own, which is what lets the well reach the row's edges. */
  padding: 0;
  /* Clips the well to the row's corner radius. */
  overflow: hidden;
  background: var(--color--white);
  border: var(--border--1px) solid var(--border--muted);
  border-radius: var(--radius--16px);
}
@media (hover: hover) {
  .pf-qrow:hover {
    background: var(--color--grey-50);
  }
  .pf-qrow:hover .pf-qrow-thumb {
    background: var(--color--white);
    border-right: var(--border--1px) solid var(--border--muted);
  }
  /*
   * And the columns step away from the divider, the same 1rem the list row
   * gives .pf-row-text. Same gesture, same token, same timing.
   *
   * ON .pf-qrow-cols, NOT .pf-qrow-main. The two rows do not line up the way
   * their names suggest: .pf-qrow-main is the counterpart of .pf-row - the
   * flex line that HOLDS the well - while .pf-qrow-cols is the counterpart of
   * .pf-row-text. Padding .pf-qrow-main would move the thumbnail well too,
   * and the well is built to reach the row's left edge (.pf-qrow carries no
   * padding and clips with overflow: hidden precisely so it can). It would
   * detach on hover and open a 1rem strip of the tinted row beside a white
   * well, which is not an indent, it is a gap.
   *
   * .pf-qrow-cols already sets padding: 16px 16px 16px 0, whose zero carries
   * the note "nothing on the left: the well and the 24px gap beside it are
   * the left inset". This is that zero, on hover only.
   */
  .pf-qrow:hover .pf-qrow-cols {
    padding-left: var(--spacing--16px);
  }
}
.pf-qrow-main {
  display: flex;
  /* stretch, not center, so the well is a panel rather than a floating box. */
  align-items: stretch;
  gap: var(--spacing--24px);
}
.pf-qrow-thumb {
  /* Hugs its 80px image and runs the full height of the main line. */
  width: auto;
  height: unset;
  min-height: 100%;
  padding: 1rem;
  /* Reserved, not absent — see .pf-row-thumb. A border appearing on hover
     would shift every line of text beside it. */
  border-right: var(--border--1px) solid transparent;
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  /* Same reasoning as .pf-row-thumb: the catalog photography is shot on
     white, so any tint reads as a frame around the cutout. */
  background: var(--color--white);
}
/*
 * An 80px box, not an 80px cap — and that distinction is load-bearing.
 *
 * PartThumb's compact variant is `width: auto; height: auto` under a max-*
 * pair, so before the file arrives the image measures 0x0. The `<img>` is
 * `loading="lazy"`, and a lazy image with no box is one the browser can decide
 * is not worth fetching: measured here, `complete: false` and natural 0x0
 * forever, with the well collapsed to its own padding at 29px instead of 112.
 * Nothing errored, and a direct fetch of the same src returned 200 image/webp.
 *
 * Giving it the box up front breaks the loop, and is what `.pf-list .pf-thumb`
 * already does — which is why the list row never had this problem and this one
 * always did.
 */
.pf-qrow-thumb .pf-thumb--compact {
  width: var(--spacing--80px);
  height: var(--spacing--80px);
  max-width: none;
  max-height: none;
}
.pf-qrow-thumb .pf-photo--compact {
  width: 100%;
  height: 100%;
}
.pf-qrow-cols {
  flex: 1 1 0;
  min-width: 0;
  /* Its own insets, now that the row has none. Nothing on the left: the well
     and the 24px gap beside it are the left inset. */
  padding: var(--spacing--16px) var(--spacing--16px) var(--spacing--16px) 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--spacing--24px);
}
.pf-qrow-col {
  display: flex;
  flex-direction: column;
  gap: var(--spacing--4px);
  min-width: 0;
}
.pf-qrow-label {
  font-size: var(--font-size--text-tiny, 0.75rem);
  line-height: var(--line-height--150, 1.5);
  color: var(--color--text-muted);
}
.pf-qrow-value {
  font-size: var(--font-size--text-medium, 1.125rem);
  font-weight: var(--weight--bold);
  line-height: var(--line-height--150, 1.5);
  color: var(--color--ink);
}
.pf-qrow-sub {
  font-size: var(--font-size--text-medium, 1.125rem);
  line-height: var(--line-height--150, 1.5);
  color: var(--color--ink);
}
/*
 * Part Number row body. Figma 2388:12396: part number and title on one line,
 * a meta line under it, 8px apart — no labelled columns, because this tab has
 * nothing to explain about why the part matched.
 */
.pf-qrow-col--part {
  gap: var(--spacing--8px);
}
.pf-qrow-headline {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--spacing--8px);
  font-size: var(--font-size--text-medium, 1.125rem);
  line-height: var(--line-height--150, 1.5);
  color: var(--color--ink);
}
.pf-qrow-pn {
  font-weight: var(--weight--bold);
}
.pf-qrow-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--spacing--8px);
  font-size: var(--font-size--text-regular, 1rem);
  line-height: var(--line-height--150, 1.5);
  color: var(--color--text-muted);
}
.pf-qrow-meta-part {
  display: inline-flex;
  align-items: center;
  gap: var(--spacing--8px);
}
/*
 * Inset 1rem each side, so the divider lines up with the interchange block
 * underneath it rather than running the full width of the card.
 *
 * Both values come off --spacing--16px, which IS 1rem and is the same token
 * .pf-qrow-ix uses for its own horizontal padding. Writing the width as a calc
 * on that token rather than a literal 2rem is what stops the two sides from
 * drifting apart if the inset is ever retuned.
 *
 * margin alone (margin: 0 var(--spacing--16px)) would compute the same width
 * under the column's align-items: stretch, but only while that stays stretch.
 * The explicit width survives a change to the parent's alignment.
 */
.pf-qrow-rule {
  height: var(--border--1px);
  background: var(--border--muted);
  width: calc(100% - 2 * var(--spacing--16px));
  margin-left: var(--spacing--16px);
}
.pf-qrow-ix {
  display: flex;
  flex-direction: column;
  gap: var(--spacing--8px);
  /* The row's padding is gone, so the interchange block carries its own.
     The rule above it now matches this inset rather than running edge to edge,
     so the divider starts and ends where INTERCHANGE does. (It used to span the
     full width on the argument that a short divider reads as a stray line; with
     the two aligned it reads as the block's own top edge instead.) */
  padding: 0 var(--spacing--16px) var(--spacing--16px);
}
.pf-qrow-pills {
  display: flex;
  flex-wrap: wrap;
  gap: var(--spacing--12px);
  list-style: none;
  padding: 0;
  margin: 0;
}
.pf-qrow-pill {
  padding: var(--spacing--6px) var(--spacing--8px);
  background: var(--color--grey-50);
  border: var(--border--1px) solid var(--border--muted);
  border-radius: var(--radius--8px);
  font-size: var(--font-size--text-tiny, 0.75rem);
  font-weight: var(--weight--medium);
  line-height: var(--line-height--150);
  color: var(--color--text-muted);
}

/* ── Pager ──────────────────────────────────────────────────── */
.pf-pager {
  display: flex;
  align-items: center;
  justify-content: space-between;
}
/*
 * Previous and Next are the same control, and their colour says whether they
 * WORK, not which way they point.
 *
 * Blue was pinned to Next, so a live Previous sat grey beside a live Next and
 * read as the disabled one of the pair — on page 2 of 5, where both do the
 * same job in opposite directions. The state is the only thing worth
 * colouring, so the enabled look is the base and `:disabled` is the exception.
 *
 * `currentColor` on the arrow carries all of this for free: one declaration
 * moves the border, the label and the glyph together, and they cannot drift.
 */
.pf-pager-edge {
  font-size: var(--font-size--text-small, 0.875rem);
  font-weight: var(--weight--semibold, 600);
  display: flex;
  align-items: center;
  gap: var(--spacing--8px);
  padding: var(--spacing--12px) var(--spacing--24px);
  border: var(--border--1px) solid var(--color--blue-bright);
  border-radius: var(--radius--8px);
  background: none;
  color: var(--color--blue-bright);
  cursor: pointer;
}
.pf-pager-edge .pf-arrow svg {
  width: 1rem; /* 16px */
  height: 1rem;
}
/* Grey out as one. `--color--text-disabled` and `--border--muted` are the same
   rgba(90,100,114,0.2) the design specifies for a deactivated arrow, and
   `currentColor` carries it to the glyph, so the border, the label and the
   arrow all land on it from these two lines. */
.pf-pager-edge:disabled {
  color: var(--color--text-disabled);
  border-color: var(--border--muted);
  cursor: default;
}
.pf-pager-nums {
  display: flex;
  gap: var(--spacing--12px);
}
.pf-pager-num {
  font-size: var(--font-size--text-regular, 1rem);
  font-weight: var(--weight--semibold, 600);
  width: var(--size--page-btn);
  height: var(--size--page-btn);
  border: var(--border--1px) solid var(--border--muted);
  border-radius: var(--radius--8px);
  background: var(--color--white);
  color: var(--color--text-muted);
  cursor: pointer;
}
.pf-pager-num--active {
  background: var(--color--blue-bright);
  color: var(--color--white);
}

/*
 * Pager hover, transcribed from the published stylesheet
 * (cloyes-stg.webflow.io/stylesheet), not invented here.
 *
 * Previous / Next are `.btn.is-hollow` in everything but name: blue outline,
 * transparent fill, a label and an arrow. So they take its hover: grey-50
 * fill, the three-layer shadow, and the arrow moving by a GAP change (0.5rem
 * to 1rem), never a translate. The hollow button pays for its wider gap out
 * of the padding on the arrow's side, so the button keeps its width and the
 * label stays still; the modifiers say which side that is. The colour step
 * to --color--blue is `.cl-pager-btn.is-enabled:hover`, the site's own pager.
 *
 * Page numbers are `.cl-page-num:not(.is-active):hover`: label and border go
 * to --color--blue-bright, the active page's colour. :not(--active) keeps a
 * blue label off the blue fill.
 *
 * Durations are `.cl-page-num`'s: colour and fill on --dur-fast, the border
 * and the moves on --dur-base. The shadow starts transparent, as the hollow
 * button's does, so it fades in instead of popping.
 */
.pf-pager-edge {
  box-shadow:
    0 0.0625rem 0.1875rem transparent,
    0 0.375rem 0.375rem transparent,
    0 0.8125rem 0.5rem transparent;
  transition:
    color var(--dur-fast, 0.2s) var(--ease-inout, ease),
    background-color var(--dur-fast, 0.2s) var(--ease-inout, ease),
    border-color var(--dur-base, 0.32s) var(--ease-out, ease),
    box-shadow var(--dur-base, 0.32s) var(--ease-inout, ease),
    column-gap var(--dur-base, 0.32s) var(--ease-out, ease),
    padding var(--dur-base, 0.32s) var(--ease-out, ease);
}
.pf-pager-num {
  transition:
    color var(--dur-fast, 0.2s) var(--ease-inout, ease),
    background-color var(--dur-fast, 0.2s) var(--ease-inout, ease),
    border-color var(--dur-base, 0.32s) var(--ease-out, ease);
}
/* Hover only where hovering is real: on touch a :hover sticks after the tap
   and would leave the grown gap on the button just pressed. */
@media (hover: hover) {
  .pf-pager-edge:not(:disabled):hover {
    color: var(--color--blue);
    border-color: var(--color--blue);
    background-color: var(--color--grey-50);
    column-gap: var(--spacing--16px);
    box-shadow:
      0 0.0625rem 0.1875rem rgba(0, 0, 0, 0.03),
      0 0.375rem 0.375rem rgba(0, 0, 0, 0.03),
      0 0.8125rem 0.5rem rgba(0, 0, 0, 0.02);
  }
  .pf-pager-edge--prev:not(:disabled):hover {
    padding-left: var(--spacing--16px);
  }
  .pf-pager-edge--next:not(:disabled):hover {
    padding-right: var(--spacing--16px);
  }
  .pf-pager-num:not(.pf-pager-num--active):hover {
    color: var(--color--blue-bright);
    border-color: var(--color--blue-bright);
  }
}
@media (prefers-reduced-motion: reduce) {
  .pf-pager-edge,
  .pf-pager-num {
    transition: none;
  }
}

/* ── Skeletons ──────────────────────────────────────────────── */
@keyframes pf-shimmer {
  0% {
    background-position: -12.5rem 0;
  }
  100% {
    background-position: calc(12.5rem + 100%) 0;
  }
}
.pf-skel,
.pf-skel-block,
.pf-select--skeleton {
  background-color: #eef1f5;
  background-image: linear-gradient(90deg, #eef1f5 0, #f6f8fb 5rem, #eef1f5 10rem);
  background-size: 12.5rem 100%;
  background-repeat: no-repeat;
  animation: pf-shimmer 1.2s ease-in-out infinite;
  border-radius: 0.375rem; /* 6px — skeleton only, no token */
}
.pf-skel-block {
  border-radius: 0;
}
.pf-skel--count {
  display: block;
  height: 0.875rem; /* 14px */
  width: 70%;
}
/* Stands in for the page numbers, whose count is data. Sized to the five
   buttons `usePagination({ padding: 2 })` shows at most: 5 x 36px plus four
   12px gaps. */
.pf-skel--pagenums {
  display: block;
  height: var(--size--page-btn);
  width: 14.25rem; /* 228px */
}

/*
 * MASKED REAL ELEMENTS, not bars of a guessed height.
 *
 * Each skeleton below reuses the class its live counterpart wears and holds
 * an `&nbsp;`, so the element sizes itself from its own font-size and
 * line-height exactly as it will once text arrives. `color: transparent`
 * hides the space; `.pf-skel` paints the shimmer over it. The widths are the
 * only thing invented here, and a width cannot cause vertical shift.
 *
 * The bars this replaced were 18px and 14px tall against real line boxes of
 * 25.2px and 24px, which is how a card came out 4px short. Anything measured
 * by hand drifts the moment the type scale moves; this cannot.
 */
.pf-card--skeleton :where(.pf-card-title, .pf-card-pn, .pf-viewpart),
.pf-row--skeleton :where(.pf-row-title, .pf-row-meta, .pf-viewpart),
.pf-facet-row--skeleton :where(.pf-facet-name, .pf-facet-count) {
  color: transparent;
}
.pf-card--skeleton .pf-card-title {
  width: 80%;
}
.pf-card--skeleton .pf-card-pn {
  width: 40%;
}
.pf-card--skeleton .pf-viewpart,
.pf-row--skeleton .pf-viewpart {
  width: 5.25rem; /* 84px */
}
.pf-row--skeleton .pf-row-title {
  width: 55%;
}
.pf-row--skeleton .pf-row-meta {
  width: 35%;
}
/*
 * The count goes to the RIGHT EDGE, where the real count is.
 *
 * In a live row `.pf-facet-name` is `flex: 1 1 auto` and fills whatever is
 * left, so the count is pushed hard against the row's end. Capping the
 * placeholder's width to keep it reading as a name-length bar took that job
 * away from it: the two bars ended up touching in the middle of an otherwise
 * empty row, which looks like one control rather than a name and its tally.
 *
 * `margin-inline-end: auto` gives the freed space back to the gap rather than
 * to the bar, so the placeholder keeps a name's proportions AND the count
 * keeps its position - which also means the count does not slide sideways
 * when the real numbers arrive.
 */
.pf-facet-row--skeleton .pf-facet-name {
  max-width: 8rem;
  margin-inline-end: auto;
}
.pf-facet-row--skeleton .pf-facet-count {
  width: 2rem;
}

/*
 * Affordances off, for the same reason as `.pf-actions--skeleton` above: the
 * shared classes carry a pointer cursor and hover motion that a placeholder
 * has no business offering. `.pf-card--skeleton` is a div rather than the
 * anchor `.pf-card` normally is, so it is already unfocusable; this is about
 * what the cursor claims.
 */
:where(.pf-card--skeleton, .pf-row--skeleton, .pf-facet-row--skeleton,
  .pf-facet-head--skeleton, .pf-viewtoggle--skeleton > *, .pf-clear--skeleton,
  .pf-pager--skeleton .pf-pager-edge) {
  cursor: default;
  pointer-events: none;
}
/* The real Clear all and the real pager edges are both disabled on arrival —
   nothing is filtered yet, and there is no page to go back from — so the
   placeholder wears the colour :disabled gives them. A span has no disabled
   state for the pseudo-class to match. */
.pf-clear--skeleton {
  color: rgba(90, 100, 114, 0.35);
}

@media (prefers-reduced-motion: reduce) {
  .pf-skel,
  .pf-skel-block,
  .pf-select--skeleton {
    animation: none;
  }
}

/*
 * The skeleton's actions row — the live controls, made inert.
 *
 * It reuses `.pf-check`, `.pf-btn-reset` and `.pf-btn-find` so the row
 * occupies exactly the height it will after hydration; see the note in
 * SearchLayoutSkeleton for why it is drawn at all. Those classes carry
 * affordances the skeleton has no business offering, so this undoes them:
 * a pointer cursor over something that cannot be clicked is the kind of
 * detail that reads as a broken page rather than a loading one.
 *
 * Reset is dimmed to the colour `.pf-btn-reset:disabled` gives it, because
 * that IS its state on arrival — there is no vehicle to reset until one is
 * picked. The pseudo-class cannot do it here, since a span has no disabled
 * state to match.
 */
.pf-actions--skeleton :where(.pf-check, .pf-btn-reset, .pf-btn-find) {
  cursor: default;
  pointer-events: none;
}
.pf-actions--skeleton .pf-btn-reset {
  color: rgba(90, 100, 114, 0.5);
}

/* ── Mobile results toolbar ─────────────────────────────────────
   Figma 2388:12789. Rendered only below 991px (ResultsToolbar), where it
   stands in for the sidebar's head; the facets move into .pf-sheet. */
.pf-toolbar {
  display: flex;
  flex-direction: column;
  gap: var(--spacing--24px);
}
.pf-toolbar-row {
  display: flex;
  align-items: stretch;
  gap: var(--spacing--12px);
}
.pf-filters-btn {
  flex: 1 1 0;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--spacing--12px);
  padding: var(--spacing--8px) var(--spacing--16px);
  font-size: var(--font-size--text-regular, 1rem);
  font-weight: var(--weight--semibold, 600);
  line-height: var(--line-height--150, 1.5);
  color: var(--color--black, #000);
  background: var(--color--white);
  border: var(--border--1px) solid #e3e7ec;
  border-radius: var(--radius--8px);
  cursor: pointer;
}
.pf-filters-count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 1.5rem; /* 24px */
  min-width: 1.5rem;
  padding: 0 0.5625rem; /* 9px */
  font-size: 0.75rem; /* 12px */
  font-weight: var(--weight--regular, 400);
  line-height: var(--line-height--20px);
  color: var(--color--white);
  background: var(--color--red);
  border: var(--border--1px) solid var(--border--muted);
  border-radius: var(--radius--pill);
}
/* The Card / List pair as a small segmented track, not the sidebar's two
   full-width buttons. Fixed 78px halves, per the frame. */
.pf-viewtoggle--compact {
  flex: 0 0 auto;
  gap: 0;
  padding: var(--spacing--4px);
  background: var(--color--white);
  border: var(--border--1px) solid #e3e7ec;
  border-radius: var(--radius--8px);
}
.pf-viewtoggle--compact .pf-viewbtn {
  flex: 0 0 auto;
  width: 4.875rem; /* 78px */
  padding: var(--spacing--8px) 0;
  font-size: 0.75rem; /* 12px */
  line-height: var(--line-height--20px);
  letter-spacing: var(--letter-spacing--tight);
  background: transparent;
  border-radius: var(--radius--4px, 0.25rem);
}
.pf-viewtoggle--compact .pf-viewbtn--active {
  background: var(--color--blue-bright);
}
/* One line here, against the sidebar's two: the toolbar is full width, and
   "Showing 13 of 13 compatible results" fits a 320px phone on one. */
.pf-showing--toolbar {
  min-height: calc(var(--line-height--150, 1.5) * var(--font-size--text-small, 0.875rem));
}
/* Both skeleton heads are sent (SearchLayoutSkeleton); width picks one. The
   live toolbar is only ever rendered below 991px, so this never hides it. */
@media screen and (min-width: 992px) {
  .pf-toolbar {
    display: none;
  }
}

/* ── Filter sheet ───────────────────────────────────────────────
   Figma 2388:13511. A bottom sheet over a tinted, blurred scrim.

   It slides; the motion directive's no-transform rule is for controls, and
   this is a surface arriving, the same as the reveal's own rise. Visibility
   is held on a delayed transition so the sheet finishes sliding out before it
   leaves the accessibility tree, and comes back instantly when opened. */
.pf-sheet {
  position: fixed;
  inset: 0;
  z-index: 1000;
  visibility: hidden;
  transition: visibility 0s linear var(--dur-base, 0.32s);
}
.pf-sheet[data-open="true"] {
  visibility: visible;
  transition-delay: 0s;
}
.pf-sheet-scrim {
  position: absolute;
  inset: 0;
  background: rgba(30, 41, 81, 0.3);
  -webkit-backdrop-filter: blur(0.171875rem); /* 2.75px */
  backdrop-filter: blur(0.171875rem);
  opacity: 0;
  transition: opacity var(--dur-base, 0.32s) var(--ease-out, ease);
}
.pf-sheet[data-open="true"] .pf-sheet-scrim {
  opacity: 1;
}
.pf-sheet-panel {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  display: flex;
  flex-direction: column;
  /* dvh so the browser's own toolbar never covers Show results. */
  max-height: 85vh;
  max-height: 85dvh;
  background: var(--color--white);
  border: var(--border--1px) solid #e3e7ec;
  border-bottom: none;
  border-radius: var(--radius--12px) var(--radius--12px) 0 0;
  outline: none;
  transform: translateY(100%);
  transition: transform var(--dur-base, 0.32s) var(--ease-out, ease);
}
.pf-sheet[data-open="true"] .pf-sheet-panel {
  transform: none;
}
.pf-sheet-handle {
  position: absolute;
  top: 0.8125rem; /* 13px: centred on Figma's stroke at 15px */
  left: 50%;
  width: 2.5rem; /* 40px */
  height: 0.25rem;
  margin-left: -1.25rem;
  border-radius: var(--radius--pill);
  background: #d8dde3;
}
.pf-sheet-head {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--spacing--16px) var(--spacing--20px);
  border-bottom: var(--border--1px) solid #d8dde3;
}
.pf-sheet-title {
  font-size: var(--font-size--text-regular, 1rem);
  font-weight: var(--weight--semibold, 600);
  letter-spacing: var(--letter-spacing--tight);
  line-height: var(--line-height--20px);
  color: var(--color--ink);
}
.pf-sheet-body {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
}
/* Each group is its own band, ruled underneath and inset 20px, rather than
   the sidebar's rule-on-top inside a padded card. The last one gives its rule
   to the footer's. */
.pf-sheet .pf-facet {
  border-top: none;
  border-bottom: var(--border--1px) solid #d8dde3;
  padding: var(--spacing--16px) var(--spacing--20px) var(--spacing--8px);
}
.pf-sheet .pf-facet:last-child {
  border-bottom: none;
}
.pf-sheet-foot {
  flex: 0 0 auto;
  padding: var(--spacing--16px) var(--spacing--20px);
  padding-bottom: calc(var(--spacing--16px) + env(safe-area-inset-bottom, 0px));
  border-top: var(--border--1px) solid #d8dde3;
}
.pf-sheet-show {
  width: 100%;
  height: 2.8125rem; /* 45px */
  padding: var(--spacing--12px) var(--spacing--16px);
  font-size: var(--font-size--text-small, 0.875rem);
  font-weight: var(--weight--semibold, 600);
  line-height: var(--line-height--150, 1.5);
  color: var(--color--white);
  background: var(--color--red);
  border: none;
  border-radius: var(--radius--8px);
  cursor: pointer;
}
@media (prefers-reduced-motion: reduce) {
  .pf-sheet,
  .pf-sheet-scrim,
  .pf-sheet-panel {
    transition: none;
  }
}

/* The pager's "1 of 5", mobile only. */
.pf-pager-count {
  display: none;
  font-size: var(--font-size--text-regular, 1rem);
  font-weight: var(--weight--semibold, 600);
  color: var(--color--text-muted);
}
.pf-pager-count-now {
  color: #222529;
}

/* Reset search is drawn in the mobile frames only; see QueryPanel. */
.pf-btn-reset--query {
  display: none;
}

/* The vehicle chip inside the bar exists for the mobile fold only. */
.pf-vehicle--bar {
  display: none;
}

/* ── Responsive ─────────────────────────────────────────────────
   991px and 767px match Webflow's `medium` and `small` breakpoints, so
   the finder reflows in step with the navbar, the footer and the
   token set's mobile mode. 1280px is a finder-only step: the four-up
   card grid runs out of room before the chrome does. */
@media (max-width: 1280px) {
  .pf-grid {
    grid-template-columns: repeat(3, 1fr);
  }
}
@media screen and (max-width: 991px) {
  .pf-results {
    flex-direction: column;
    /* Stretch, not the desktop flex-start. That value exists so the sticky
       sidebar has room to travel; in a column it shrink-wraps each child
       instead, and the loading grid, whose cards have no text to give it a
       width, rendered at 252px of a 400px phone. */
    align-items: stretch;
  }
  .pf-sidebar {
    width: 100%;
    flex-basis: auto;
    /* Stacked above the grid rather than beside it, so there is nothing to
     * stick alongside — pinning it here would park a full-width panel over the
     * results the reader is scrolling to. Back to normal flow, and the height
     * cap goes with it so the panel is never scrollable-within-scrollable on
     * touch. */
    position: static;
    max-height: none;
    overflow-y: visible;
  }
  /*
   * The query row stacks. Three items side by side (two label columns and
   * View Part) cannot hold their widths at phone size, and `justify-content:
   * space-between` would strand the link far from the part it belongs to.
   * Left aligned throughout, per the global mobile directive.
   */
  .pf-qrow-main {
    align-items: flex-start;
    gap: var(--spacing--16px);
  }
  .pf-qrow-cols {
    flex-direction: column;
    align-items: flex-start;
    gap: var(--spacing--16px);
  }
  .pf-fields {
    flex-wrap: wrap;
  }
  .pf-field {
    flex: 1 1 45%;
  }
  .pf-grid {
    grid-template-columns: repeat(2, 1fr);
  }
  .pf-actions {
    flex-wrap: wrap;
    justify-content: flex-start;
  }
}
@media screen and (max-width: 767px) {
  /*
   * STOCK / HIGH PERFORMANCE BECOMES A SEGMENTED CONTROL.
   *
   * Figma mobile nodes 1888:32808 (home) and 1949:13618 (Timing Systems) both
   * move this control out of the actions row and up under the tabs, as a 2-up
   * segmented control: selected half gets a grey-50 fill, a red bottom rule and
   * black label text. Desktop keeps the two checkboxes at the bottom right.
   *
   * This shipped on the Webflow home bar only, as a `:has()` rule in an embed
   * inside the "Cloyes Part Finder" component. The app surface never had it, so
   * /parts and /timing-systems have always rendered plain checkboxes on a
   * phone. Consolidating onto this component is what surfaced the divergence;
   * putting it here fixes every surface at once instead of re-stranding it.
   *
   * `.pf-actions` drops to `display: contents` so its three groups become direct
   * children of `.pf-bar-card`'s column and can be ordered against `.pf-fields`.
   */
  .pf-actions {
    display: contents;
  }
  .pf-seg {
    display: flex;
    order: -1;
    gap: 0;
    border: var(--border--1px) solid #e3e7ec;
    border-radius: var(--radius--8px);
    /* 4px inset, so each half sits inside the container rather than filling it
       edge to edge — this is what gives the selected half its own rounded block
       (Figma 2388:12804). */
    padding: var(--spacing--4px);
    overflow: hidden;
    background: var(--color--white);
  }
  /* Equal halves: flex-basis 0 rather than width 50%, so the border does not
     push the second half onto a new line. */
  /*
   * Figma draws each half as 172x44 with 24px side padding, but that padding is
   * an auto-layout artifact, not a visual requirement: the halves here are
   * `flex: 1` and centre their label, so the width comes from the container and
   * the side padding only ever decides when the label runs out of room. At 24px
   * "Stock Replacement" no longer fits a 375px phone and wraps to two lines,
   * taking the control from 45px to 65px tall. An 8px inset keeps the label off
   * the edge, renders identically to the frame at 440, and leaves the narrow
   * phones alone.
   */
  .pf-seg .pf-check {
    flex: 1 1 0%;
    justify-content: center;
    padding: var(--spacing--12px) var(--spacing--8px);
    border-radius: var(--radius--4px);
    /* Reserved on both halves so selecting one shifts nothing. */
    border-bottom: var(--border--1px) solid transparent;
  }
  /*
   * The segment labels carry their own type here. `.pf-check-lbl` is shared
   * with the desktop checkbox row, where it is text-small/medium; the mobile
   * toggle is a tighter 12/20 SemiBold (Figma 2388:12806 / 2388:12808), and the
   * resting half is muted so the selected one reads as selected. Without this
   * both halves rendered identical black 13.33/400 and the control had no
   * selected state you could see.
   */
  .pf-seg .pf-check-lbl {
    font-size: var(--font-size--text-tiny, 0.75rem);
    font-weight: var(--weight--semibold, 600);
    line-height: var(--line-height--20px);
    letter-spacing: var(--letter-spacing--tight);
    color: var(--color--text-muted);
    /* One line always: the control's height is part of the bar's rhythm, and a
       wrapped label silently makes it 20px taller. Below 360px the font steps
       down instead — see the narrow-phone block at the end of this file. */
    white-space: nowrap;
  }
  /* The checkbox itself is a desktop affordance; the segment IS the control. */
  .pf-seg .pf-box {
    display: none;
  }
  .pf-seg .pf-check:has(.pf-box--on) {
    background: var(--color--grey-50);
    border-bottom-color: var(--color--red);
  }
  .pf-seg .pf-check:has(.pf-box--on) .pf-check-lbl {
    color: var(--color--black, #000);
  }
  .pf-vspacer {
    display: none;
  }
  .pf-actions-btns {
    display: flex;
    order: 1;
    align-items: center;
    justify-content: flex-end;
    gap: var(--spacing--16px);
  }

  .pf-field {
    flex: 1 1 100%;
  }

  /* Two up, not one. Figma's mobile grid (2388:12789) holds two cards per row
     at its 440px frame with the same 16px gap, so the 991px rule carries down
     to phone width unchanged and nothing overrides it here. */

  /* The placeholder at half width. 15px "PHOTO COMING SOON" is ~200px on one
     line, wider than a 2-up card at any phone size. Figma sets it at 12px
     (2388:12902), which fits a 192px card at 440; below ~400px even that
     overflows, so it wraps to two lines instead of shrinking further.
     The inset and gap are the smallest that keep the dashes off the card
     edge and still leave room for "PHOTO COMING" on one line at 375; the
     16px Figma inset forced three lines there. */
  .pf-card-img .pf-photo {
    gap: var(--spacing--6px);
    padding: 0 var(--spacing--8px);
  }
  .pf-card-img .pf-photo-text {
    font-size: 0.75rem; /* 12px */
    white-space: normal;
    text-align: center;
    text-wrap: balance;
  }
  .pf-card-img .pf-photo-dash {
    flex: 0 0 auto;
  }
  /* Field on its own line, then Reset search and Search sharing the row
     below in halves (2388:13794, 2388:13951). Wrap rather than column so the
     two buttons can sit side by side. */
  .pf-searchrow {
    flex-wrap: wrap;
    align-items: stretch;
  }
  .pf-searchrow > .pf-field {
    flex: 1 1 100%;
  }
  /* Scoped to the row so it outranks `.pf-btn-reset`'s align-self, which
     comes later in the file. */
  .pf-searchrow > .pf-btn-reset--query {
    display: block;
    flex: 1 1 0;
    align-self: auto;
  }
  .pf-searchrow > .pf-btn-search {
    flex: 1 1 0;
  }

  /*
   * THE FOLD (Figma 2388:12789). With a vehicle chosen, the bar is the
   * segmented control and the blue chip; Change opens the fields again. See
   * VehiclePanel for when it folds. `:has()` because the chip that carries the
   * state is a sibling of the fields, not their parent: the column order above
   * needs every group to stay a direct child of `.pf-bar-card`.
   */
  .pf-vehicle--bar {
    display: flex;
  }
  .pf-bar-card:has(.pf-vehicle--folded) .pf-fields,
  .pf-bar-card:has(.pf-vehicle--folded) .pf-actions-btns {
    display: none;
  }

  /*
   * Tabs fill the width at 12px (Figma 2388:12793). At 14px with 24px insets
   * the three ran 46px past a 320px screen. Grown from their labels rather
   * than in equal thirds: "Part Number" is much shorter than the other two,
   * and thirds wrapped all three to two lines at 375 where Figma has one.
   * min-width 0 lets a tab go narrower than its label, so on the narrowest
   * phones a label wraps instead of pushing the page sideways.
   */
  /* Stretch so a wrapped label and a one-line one stay the same height and
     all three still meet the card. */
  .pf-tabs {
    gap: 0;
    align-items: stretch;
  }
  .pf-tab {
    flex: 1 1 auto;
    min-width: 0;
    padding: var(--spacing--12px) var(--spacing--8px);
    font-size: 0.75rem; /* 12px */
    text-align: center;
  }
  /* Filling the width puts Cross Reference over the card's top-right corner,
     so it gets the same square join Search by Vehicle has on the left. On
     desktop the strip stops short of that corner and the radius stays. */
  .pf-bar-card--x {
    border-top-right-radius: 0;
  }

  /*
   * THE LIST ROW (Figma 2388:12653): a stacked card with no photo. Part
   * number on its own line, then the title, the meta, and View Part under
   * all three. Red stays on the number per client QA, as on desktop.
   */
  .pf-row {
    flex-direction: column;
    gap: var(--spacing--24px);
    padding: var(--spacing--16px);
    border-radius: var(--radius--16px);
  }
  .pf-row-thumb {
    display: none;
  }
  .pf-row-text,
  .pf-row:hover .pf-row-text {
    padding: 0;
  }
  .pf-row-title {
    font-size: var(--font-size--text-medium, 1.125rem);
  }
  .pf-row-pn {
    display: block;
    margin-bottom: var(--spacing--8px);
  }
  /* Wraps here. The desktop row truncates so every row keeps one height; a
     stacked card has no neighbour to keep level with, and Figma wraps
     "US Sprockets Not Included" to a second line. */
  .pf-row-meta {
    margin-top: var(--spacing--8px);
    font-size: var(--font-size--text-regular, 1rem);
    white-space: normal;
  }
  /* Two classes plus the row, to outrank `.pf-list .pf-viewpart`, which is
     later in this file and would otherwise put its 16px back. */
  .pf-list .pf-row .pf-viewpart {
    padding-right: 0;
  }

  /*
   * THE LOOKUP CARD (Figma 2388:13951 cross, 2388:13794 part): the photo sits
   * above the text instead of in a full-height well beside it. A 400px card
   * cannot spare a 112px column, and the frame shows a small top-left shot
   * inset like everything under it. The hover rules go with the well, since
   * there is no divider left to draw or step away from.
   */
  .pf-qrow-main {
    flex-direction: column;
    padding: var(--spacing--16px) var(--spacing--16px) 0;
  }
  .pf-qrow-thumb,
  .pf-qrow:hover .pf-qrow-thumb {
    min-height: 0;
    padding: 0;
    justify-content: flex-start;
    border-right: none;
  }
  .pf-qrow-thumb .pf-thumb--compact {
    width: var(--spacing--64px);
    height: var(--spacing--64px);
  }
  .pf-qrow-cols,
  .pf-qrow:hover .pf-qrow-cols {
    padding: 0;
  }

  /* "Previous   1 of 5   Next" on one line (Figma 2388:12779). */
  .pf-pager-nums {
    display: none;
  }
  .pf-pager-count {
    display: inline;
  }
  .pf-pager-edge {
    padding: var(--spacing--12px) 0.8125rem; /* 13px */
  }
  .pf-btn-search {
    justify-content: center;
  }
}

/* ── Result thumbnails ──────────────────────────────────────── */
/*
 * `contain` rather than `cover`: catalog shots are tall (a 1500x1987 chain is
 * typical) and cropping to fill would cut the ends off the part, which is the
 * one thing the shot is meant to show.
 */
.pf-thumb {
  display: block;
  max-width: 100%;
  max-height: 100%;
  width: auto;
  height: auto;
  object-fit: contain;
}
.pf-thumb--compact {
  max-width: var(--spacing--64px);
  max-height: var(--spacing--64px);
  border-radius: var(--radius--8px);
}

/*
 * The list's own image, at 80px square and squared off.
 *
 * Scoped to .pf-list on purpose. `.pf-thumb` and `.pf-thumb--compact` are
 * shared with the card grid and with the Part Number / Cross Reference rows,
 * so setting these globally would resize all three. The max-* pair has to be
 * lifted as well, not just overridden: --compact caps at 64px, and a cap wins
 * over a width regardless of which rule declares it.
 */
.pf-list .pf-thumb {
  width: var(--spacing--80px);
  height: var(--spacing--80px);
  max-width: none;
  max-height: none;
  border-radius: 0;
}
/* The "photo coming soon" placeholder stands in for the image, so it takes the
   same footprint or the well collapses on parts without one. */
.pf-list .pf-photo--compact {
  width: var(--spacing--80px);
  height: var(--spacing--80px);
}
/* The well's own inset. The row carries no padding, so this is what keeps the
   image off the row's left edge and off the text beside it. */
.pf-list .pf-row-thumb {
  padding: 1rem;
}
/* Hover must not reintroduce a radius either — the two are one rule in intent,
   and splitting them is how the resting and hovered states drift apart. */
.pf-row:hover .pf-row-thumb {
  border-radius: 0;
}
/* The right inset the row no longer carries. */
.pf-list .pf-viewpart {
  padding-right: var(--spacing--16px);
}

/*
 * Segment labels below 360px.
 *
 * The segmented control is sized against Figma's 440px mobile frame, where each
 * half comfortably holds its label. At 320px a half is only ~150px and the
 * labels, which do not wrap by design, overflow the card. Trimming the label a
 * step recovers the fit. Webflow's narrowest breakpoint is 479px, far too wide
 * to target this, which is why the Webflow bar carried the same rule in an
 * embed rather than a class.
 *
 * Below 991px the fluid root is a fixed 16px, so this rem value is exact.
 */
@media screen and (max-width: 360px) {
  .pf-seg .pf-check {
    padding-left: 0.125rem;
    padding-right: 0.125rem;
  }
  .pf-seg .pf-check-lbl {
    font-size: 0.6875rem; /* 11px */
  }
}

/* ── Empty results ──────────────────────────────────────────────
   Figma 2388:11669 (vehicle), 2388:12327 (part), 2388:12455 (cross).

   A search returning nothing used to render an empty grid: no message and no
   way out, which reads as a broken page rather than an honest answer. The
   panel keeps the grid's own border so the results column does not visibly
   collapse when the count drops to zero. */
/*
 * Figma 2388:12444. Every size here is restated rather than left to the
 * `.text-*` classes on the markup: those do not exist in the shadow root (see
 * the file header), so on Webflow the title was rendering at whatever the card
 * inherited instead of 16px, and the button had no size of its own at all.
 */
.pf-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  /* 24px between the three blocks: icon, the title+body group, the button. */
  gap: var(--spacing--24px);
  min-height: 17.6875rem; /* 283px — the drawn card height */
  /* Figma sets padding-block only; the card is full width and its content is
     centred. The 24px sides are ours, so the copy never touches the edge on a
     narrow screen. */
  padding: var(--spacing--16px) var(--spacing--24px);
  text-align: center;
  background: var(--color--white);
  border: var(--border--1px) solid var(--border--muted);
  border-radius: var(--radius--12px);
}
.pf-empty-icon {
  display: flex;
  color: var(--color--text-muted);
}
.pf-empty-content {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--spacing--8px);
}
.pf-empty-title {
  font-size: var(--font-size--text-regular, 1rem);
  font-weight: var(--weight--semibold, 600);
  line-height: var(--line-height--150, 1.5);
  color: var(--color--ink);
}
.pf-empty-body {
  max-width: 22.25rem; /* 356px */
  font-size: var(--font-size--text-small, 0.875rem);
  line-height: var(--line-height--150, 1.5);
  color: var(--color--text-muted);
}
/* An outlined button, per Figma — the red primary belongs to Find Parts and
   Search, and offering the same weight to "give up and start again" would
   compete with them. No transform on hover, per docs/MOTION_SYSTEM.md. */
.pf-empty-btn {
  /* No margin-top: the card's 24px gap already sets it off. */
  padding: var(--spacing--12px) var(--spacing--24px);
  font-size: var(--font-size--text-small, 0.875rem);
  font-weight: var(--weight--semibold, 600);
  line-height: var(--line-height--150, 1.5);
  color: var(--color--blue-bright);
  background: var(--color--white);
  border: var(--border--1px) solid var(--color--blue-bright);
  border-radius: var(--radius--8px);
  cursor: pointer;
}
@media (hover: hover) {
  .pf-empty-btn:hover {
    background: var(--color--grey-50);
  }
}
.pf-empty-btn:focus-visible {
  outline: 2px solid var(--color--blue-bright);
  outline-offset: 2px;
}

/* ── Hover motion ───────────────────────────────────────────────
 *
 * Every hover in this file changes a COLOUR and nothing else — a row tints,
 * a well keeps its white against it, a dropdown option lights up — and until
 * now each of them snapped. One declaration, on the elements that change
 * rather than on their `:hover` rules, so the colour eases back out as well
 * as in.
 *
 * Only `background-color` and `border-color` are named. `transition: all` here
 * would animate layout on the two rows that also change size with their
 * content, and the directive forbids transform on controls outright, so there
 * is nothing else to move.
 *
 * `--dur-fast`, which docs/MOTION_SYSTEM.md names for exactly this — "colour,
 * border and background changes on controls" — token-first with a literal
 * fallback, because the tokens come from the host page and cannot be assumed
 * inside the shadow root.
 *
 * The thumbnail wells transition cleanly because they already hold a
 * transparent right border open at rest: a border appearing from `none` has no
 * from-colour to ease out of, and would pop.
 */
.pf-opt,
.pf-row,
.pf-row-thumb,
.pf-qrow,
.pf-qrow-thumb,
.pf-empty-btn {
  transition:
    background-color var(--dur-fast, 0.2s) var(--ease-out, ease),
    border-color var(--dur-fast, 0.2s) var(--ease-out, ease);
}
/* The two rows' text sliding away from their dividers. Their own rule because
   they are the only elements here that transition a LAYOUT property, and the
   list above is deliberately colour-only - see the note about `transition:
   all`. --dur-base rather than --dur-fast: the tint is an instant
   acknowledgement, the shift is a movement, and at 0.2s a 1rem slide reads as
   a twitch. Both named together so the list row and the query row can never
   drift to different speeds; they are the same gesture on the same object. */
.pf-row-text,
.pf-qrow-cols {
  transition: padding-left var(--dur-base, 0.32s) var(--ease-out, ease);
}
/* A field unlocking is a fade, not a snap: the fill leaves and the label and
   icons come back up to full strength together. Opacity joins the list here
   because that is what the locked state fades, and only on the select - the
   reveal system owns opacity everywhere else and two owners would fight. */
.pf-select,
.pf-select-icon,
.pf-select-value,
.pf-select-chev,
.pf-field-label {
  transition:
    background-color var(--dur-fast, 0.2s) var(--ease-out, ease),
    border-color var(--dur-fast, 0.2s) var(--ease-out, ease),
    opacity var(--dur-fast, 0.2s) var(--ease-out, ease);
}
/*
 * The card's two, which are not colour and so are not in the list above.
 *
 * Their durations are the ones the marketing site uses for the same pair, not
 * --dur-fast: the zoom rides --dur-slow so a 15% scale reads as a move rather
 * than a jump, and the arrow rides --dur-base. Copying the site's timings is
 * the point — the finder sits directly below a row of .cl-news-card on some
 * pages, and two cards easing at different speeds is more obvious than either
 * speed on its own.
 *
 * transform-origin is stated rather than left to its 50% 50% default, because
 * .pf-card-img centres its image with flex and a future change to that
 * alignment would otherwise silently move where the zoom pushes from.
 */
.pf-card-img img {
  transition: transform var(--dur-slow, 0.5s) var(--ease-out, ease);
  transform-origin: 50% 50%;
}
.pf-viewpart {
  transition: column-gap var(--dur-base, 0.32s) var(--ease-out, ease);
}
@media (prefers-reduced-motion: reduce) {
  .pf-opt,
  .pf-row,
  .pf-row-thumb,
  .pf-qrow,
  .pf-qrow-thumb,
  .pf-empty-btn,
  .pf-card-img img,
  .pf-viewpart,
  .pf-select,
  .pf-select-icon,
  .pf-select-value,
  .pf-select-chev,
  .pf-field-label,
  .pf-row-text,
  .pf-qrow-cols {
    transition: none;
  }
  /* The zoom is a transform, so the global clamp has to take the destination
     away as well as the easing — otherwise it still snaps to 1.15. */
  .pf-card:hover .pf-card-img img {
    transform: none;
  }
}

/* ── Collapsible facet heads ────────────────────────────────────
   Figma 2388:11669 puts a chevron on each sidebar group. The heads were
   plain text, so a long facet list could not be folded away. */
.pf-facet-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  padding: 0;
  background: none;
  border: none;
  color: inherit;
  text-align: left;
  cursor: pointer;
  /*
   * NOT `font: inherit`. That shorthand resets font-size and font-weight, and
   * this rule comes after the one above that sets them — so the head kept its
   * 16px/600 only because `.text-regular is-semibold` on the markup happened
   * to supply them. Those classes do not exist in the shadow root, so on
   * Webflow the section headings fell back to inherited 16px/400 and read as
   * lighter than the facet names beneath them. Family is handled for every
   * control by the reset at the top of this file.
   */
}
.pf-facet-chev {
  display: flex;
  color: var(--color--text-muted);
  /* A rotation, not a translate: the chevron is part of a control, and
     docs/MOTION_SYSTEM.md forbids transform motion on controls only for
     movement — turning to show state is the state, not decoration. */
  transform: rotate(-90deg);
  /* --dur-instant, not the --dur-1 this used to name: there is no such token
     in app/motion.css, so it had been silently falling back to the literal.
     0.12s is the same 120ms, now from the scale. */
  transition: transform var(--dur-instant, 0.12s) var(--ease-out, ease);
}
/* The glyph carries width="12" height="12" as SVG attributes, which are px and
   so do not track the fluid root the rest of the finder is sized against. The
   CSS wins over the attributes, which is what puts the chevron back on the rem
   scale. */
.pf-facet-chev svg {
  width: 0.8rem;
  height: 0.8rem;
}
.pf-facet-chev--open {
  transform: none;
}
@media (prefers-reduced-motion: reduce) {
  .pf-facet-chev { transition: none; }
}

/* ── Query field label + hint ───────────────────────────────────
   Figma labels both query tabs `PART NUMBER  (Min 4 characters)`. */
.pf-field-labels {
  display: flex;
  align-items: baseline;
  gap: var(--spacing--8px);
}
.pf-field-hint {
  /* Stated here rather than left to the `text-tiny` class on the markup. That
     class does not exist inside the Webflow shadow root (see the file header),
     so on that surface the hint was inheriting whatever `.pf` sets and rendering
     larger than the label it sits beside. Token first, rem fallback, like every
     other size in this file. */
  font-size: var(--font-size--text-tiny, 0.75rem);
  color: var(--color--text-muted);
  text-transform: none;
  letter-spacing: 0;
}

/* Reset vehicle, in the vehicle tab's actions row, muted until there is a
   selection to reset. The query tabs have no equivalent: their only reset is
   the one inside the zero-results panel. */
.pf-btn-reset {
  align-self: flex-end;
  padding: var(--spacing--12px) var(--spacing--16px);
  background: none;
  border: none;
  color: var(--color--text-muted);
  cursor: pointer;
  white-space: nowrap;
}
.pf-btn-reset:disabled {
  opacity: 0.5;
  cursor: default;
}
/* Below the minimum length Search is unavailable rather than silently
   returning everything. */
.pf-btn-search:disabled {
  opacity: 0.5;
  cursor: default;
}

/* ── Entrance motion ────────────────────────────────────────────
 *
 * The finder animates itself. The site's reveal runtime cannot see into the
 * Webflow shadow root, so `data-reveal*` did nothing here; useEntrance in
 * search-app.tsx explains the split. Values are the motion system's own
 * (docs/MOTION_SYSTEM.md): --dur-entrance on --ease-out, 70ms --stagger,
 * --reveal travel. Token first with the literal as fallback, like every
 * other value in this file, because inside the shadow root the tokens are
 * inherited from the host page and cannot be assumed.
 *
 * .pf-mo          the element itself enters
 * .pf-mo-group    its direct children enter, cascading in DOM order
 * [data-pf-in]    written by useEntrance when the element is in view
 *
 * The hide rule keys on the ABSENCE of data-pf-in, and only markup rendered
 * after mount carries these classes, so there is no state in which the
 * content is hidden without the script that shows it.
 */
@keyframes pf-rise {
  from {
    opacity: 0;
    transform: translateY(var(--reveal, 24px));
  }
}

/* The in-card cascade travels a third as far: the card around it is already
   moving, and a full 24px inside a 24px move reads as a second arrival. */
@keyframes pf-rise-sm {
  from {
    opacity: 0;
    transform: translateY(calc(var(--reveal, 24px) / 3));
  }
}

@keyframes pf-fade {
  from {
    opacity: 0;
  }
}

.pf-mo:not([data-pf-in]),
.pf-mo-group:not([data-pf-in]) > * {
  opacity: 0;
}

/*
 * `backwards`, never `both` or `forwards`. Backwards holds the first keyframe
 * through the stagger delay, so a late card does not sit visible and then
 * vanish; and it releases the element entirely the moment the animation
 * ends. A forwards fill would pin `transform: none` on every card for the
 * life of the page and silently cancel anything that transforms them later.
 */
.pf-mo[data-pf-in],
.pf-mo-group[data-pf-in] > * {
  animation: pf-rise var(--dur-entrance, 0.75s) var(--ease-out, cubic-bezier(0.16, 1, 0.3, 1)) backwards;
  animation-delay: calc(var(--pf-i, 0) * var(--stagger, 70ms));
}

/* A card that is itself entering: its contents cascade on the shorter
   travel, one step behind the card. */
.pf-mo.pf-mo-group[data-pf-in] > * {
  animation-name: pf-rise-sm;
  animation-delay: calc((var(--pf-i, 0) + 1) * var(--stagger, 70ms));
}

/* Stagger index by position. CSS rather than an inline --i from script, so a
   child that mounts later (the vehicle chip appearing, a closest-match list)
   is indexed with no code at all. Capped at nine steps: a 48-card page would
   otherwise take three and a half seconds to finish arriving. Named --pf-i,
   not --i, so MotionProvider's index can never leak in or be overwritten. */
/* The first child is stated too: custom properties inherit, so without this
   it would take whatever index its own parent carries in an outer group. */
.pf-mo-group > :first-child { --pf-i: 0; }
.pf-mo-group > :nth-child(2) { --pf-i: 1; }
.pf-mo-group > :nth-child(3) { --pf-i: 2; }
.pf-mo-group > :nth-child(4) { --pf-i: 3; }
.pf-mo-group > :nth-child(5) { --pf-i: 4; }
.pf-mo-group > :nth-child(6) { --pf-i: 5; }
.pf-mo-group > :nth-child(7) { --pf-i: 6; }
.pf-mo-group > :nth-child(8) { --pf-i: 7; }
.pf-mo-group > :nth-child(9) { --pf-i: 8; }
.pf-mo-group > :nth-child(n + 10) { --pf-i: 9; }

/* The pager never enters: it is controls, and it should already be under the
   visitor's hand when the next page lands. */
.pf-mo-group > .pf-pager {
  opacity: 1;
  animation: none;
}

/* Tab change: the panel inside the bar card crossfades. 200ms and no travel,
   per the "tab indicator" spec, because the vehicle and query panels are
   different heights and a slide would drag the page with it. The panels
   remount per tab, so a mount animation is all this needs. On first load it
   finishes inside the bar's own stagger delay, so it never doubles up. */
.pf-bar-card > * {
  animation: pf-fade var(--dur-fast, 0.2s) var(--ease-inout, ease) backwards;
}

/* A YMME menu opening. Opacity only: it hangs off a control. */
.pf-menu {
  animation: pf-fade var(--dur-fast, 0.2s) var(--ease-out, ease) backwards;
}

/* ── Facet expand / collapse ────────────────────────────────────
 * Grid rows 0fr to 1fr animates to the body's intrinsic height with no
 * measuring. --dur-base, the system's duration for a layout move; the fade
 * rides --dur-fast so the rows are gone before the box finishes closing
 * rather than being sliced by it.
 */
.pf-collapse {
  display: grid;
  grid-template-rows: 1fr;
  transition:
    grid-template-rows var(--dur-base, 0.32s) var(--ease-out, cubic-bezier(0.16, 1, 0.3, 1)),
    opacity var(--dur-fast, 0.2s) var(--ease-inout, ease);
}
.pf-collapse[data-open="false"] {
  grid-template-rows: 0fr;
  opacity: 0;
}
/*
 * The clipping box. Padded and pulled back by the same amount so the focus
 * ring on a row's checkbox (outline-offset 2px) is not shaved off by the
 * overflow, while the rows sit exactly where they did before.
 *
 * position: relative is what makes the clip hold. overflow only clips
 * absolute descendants whose containing block is this box or inside it, and
 * the hidden checkbox in each row (.pf-facet-row input) is absolute. Without
 * it they resolved against the sticky .pf-sidebar, escaped every closed
 * Collapse, and padded the sidebar's scroll area with empty space below the
 * last facet.
 */
.pf-collapse-inner {
  position: relative;
  display: flex;
  flex-direction: column;
  min-height: 0;
  overflow: hidden;
  padding: 0.25rem;
  margin: -0.25rem;
}

@media (prefers-reduced-motion: reduce) {
  .pf-mo[data-pf-in],
  .pf-mo-group[data-pf-in] > *,
  .pf-bar-card > *,
  .pf-menu {
    animation: none;
  }
  .pf-tab {
    transition: none;
  }
  .pf-collapse {
    transition: none;
  }
}

