@charset "UTF-8";
/* ==========================================================================
   AbedLesCar — home-boost.css   ("hf" = home filter)
   Deploy to: public/front/assets/css/home-boost.css
   Referenced by home.blade.php as asset('front/assets/css/home-boost.css')
   --------------------------------------------------------------------------
   LOAD ORDER: AFTER mobile-boost.css (which is itself after style.css and
   responsive.css). Everything here may therefore override mobile-boost at
   EQUAL specificity — several rules deliberately rely on that.

   SCOPE OF THIS FILE
     The home page filter block (.hf), its budget chips, the trust strip
     (.hf-stats), the brand rail (.brand-rail wrapping the existing
     #make_detail), the results loading/skeleton state and the empty state.
     It does NOT touch .car-box — mobile-boost.css §8 owns the card design.

   RULES OBSERVED (same contract as mobile-boost.css)
     1. No existing class or id is renamed. #make_detail / #loadMore_data /
        .car-box / .brand-item / .make_more / .banner-single keep their names.
     2. Zero dependencies. No @import, no url() to a remote host. The only
        url() is an inline, fully percent-encoded SVG data: URI (the caret).
     3. Anything that touches a BARE ELEMENT (select, input, button, ul, li,
        b, span) is prefixed `body:not(.admin)` so it can never leak into the
        admin panel, whose <body> carries no class. New .hf* / .brand-rail
        classes cannot exist in /admin and need no prefix, but most carry it
        anyway so specificity stays uniform and predictable.
     4. RTL-first. Logical properties only. The three PHYSICAL values in this
        file are flagged in place:
          (a) `background-position` for the select caret — CSS has no logical
              equivalent; an explicit [dir="ltr"] escape follows each one.
          (b) the symmetric edge-fade mask gradients — `to right` is used but
              both ends are identical, so the result is direction-agnostic.
          (c) `::-webkit-scrollbar` — not a box-model value.
     5. Works with JS off: .hf__bar is a real <form method="get"> with a
        visible submit button, the rail is a plain scroller, and no content is
        hidden behind a script-set class. The one JS-gated hook is
        `.hf__nojs`, which HIDES itself once html.ab-js is present — the
        current markup does not use it, so the submit button always shows.
     6. prefers-reduced-motion is honoured in §L (mobile-boost §4 already
        zeroes durations globally with !important; §L kills the two ANIMATIONS
        this file introduces, which that global rule does not stop).

   THE MARKUP THIS FILE IS WRITTEN AGAINST (home.blade.php — verified, not
   assumed; the earlier draft of this file assumed a flat row of controls and
   laid the form out sideways):

     section.hf#hf > div.container > form.hf__bar#hfFilter
        div.hf__row.hf__row--budget   span.hf__legend + div.hf__chips
                                      (4 × button.hf__chip) + 2 hidden inputs
        div.hf__row.hf__row--fields   4 × div.hf__field ( label.hf__label
                                      + #hfMake | #hfYear | #hfKm | #hfQ )
        div.hf__row.hf__row--actions  div.hf__field--sort(#hfSort)
                                      + button.hf__submit + button#hfReset
        p.hf__count > span#hfCount
     …plus, in the hero: p.hf-hero__ask + div.hf-hero__budget > 4 × .hf__chip
     …plus, from the AJAX partial: #hfMeta (first child of the response),
        .hf-empty > .hf-empty__title + .hf-empty__text
     …plus, built by home-filter.js: .hf-loading (on BOTH #loadMore_data and
        section.hf — see §I) and .hf-error.

   OPTIONAL HOOKS THIS FILE ALSO STYLES (free; nothing breaks unused)
        .hf__head .hf__group .hf__nojs .hf--hero (dark palette)
        .hf-skel > .hf-skel__card    .hf__empty / [data-hf-empty] aliases
   ========================================================================== */


/* ==========================================================================
   §A  LOCAL TOKENS
   --------------------------------------------------------------------------
   Only NEW names are declared. Every colour/space/motion value below is a
   reference to a token mobile-boost.css §1 already defines, so there is one
   source of truth and no drift.
   ========================================================================== */

:root{
  --hf-gap:var(--ab-s2,8px);
  --hf-pad-i:var(--ab-s3,12px);     /* the page gutter the bar bleeds into */
  --hf-ctrl-h:48px;                 /* select / input floor */
  --hf-chip-h:46px;                 /* chip floor — spec asks for >=44 */
  --hf-fade:18px;                   /* rail edge-fade width */
  --hf-rail-w:112px;                /* brand tile flex-basis on phones */

  /* Below --ab-z-header (1020): the header must always paint over .hf. */
  --hf-z:1019;

  --hf-on-dark:rgba(255,255,255,.13);
  --hf-on-dark-line:rgba(255,255,255,.34);
}


/* ==========================================================================
   §B  .hf — THE FILTER BLOCK SHELL
   ========================================================================== */

body:not(.admin) .hf{
  position:relative;
  z-index:var(--hf-z);
  background:var(--ab-surface,#fff);
  border-block-end:1px solid var(--ab-line,rgba(17,17,17,.08));
  padding-block:var(--ab-s2,8px);
}

/* a positioned container so §C's full-bleed chip rail has something to
   measure its negative margin against */
body:not(.admin) .hf > .container,
body:not(.admin) .hf > .container-fluid{ position:relative; }

/* optional caption row above the controls: title on one side, live count on
   the other. Wraps rather than squashing #hfCount. */
body:not(.admin) .hf__head{
  display:flex;
  flex-wrap:wrap;
  align-items:baseline;
  justify-content:space-between;
  gap:var(--ab-s2,8px);
  margin-block-end:var(--ab-s2,8px);
}
/* home.blade.php uses .hf__label for the per-field <label> (a real `for=`
   label above every control), so it has to be a block, not an inline caption. */
body:not(.admin) .hf__label{
  display:block;
  font-size:13px;
  font-weight:700;
  letter-spacing:.2px;
  color:var(--ab-ink-muted,#5b6577);
  margin:0;
  padding-inline-start:2px;
}
body:not(.admin) .banner-single .hf__label,
body:not(.admin) .banner-content .hf__label,
body:not(.admin) .hf--hero .hf__label{ color:rgba(255,255,255,.86); }

/* --- phones/tablets: NOT sticky, and NOT negatively margined ---------------
   Two things an earlier draft of this file got wrong, both because it assumed
   a markup shape home.blade.php does not ship:

   1. NOT STICKY. The form is FOUR stacked rows — budget legend + chips,
      four labelled fields, sort + two buttons, and the count line — roughly
      260-300px on a 375px phone. Pinned under the 64px sticky header that
      mobile-boost §5 installs, that occupies more than half the viewport for
      the entire session and buries the catalogue it is meant to filter. A
      sticky bar is only affordable when it is one row high. The block scrolls
      with the page instead; the hero chips deep-link back to it
      (data-hf-jump="#hf") and home-filter.js already offsets that jump by
      --ab-header-h, so reachability is covered.

   2. NO FULL-BLEED NEGATIVE MARGIN HERE. <section class="hf"> is a top-level
      child of <main class="main-body"> — it CONTAINS a .container, it is not
      inside one — so it is already edge-to-edge. `margin-inline:-12px` made it
      24px WIDER than the viewport. That is invisible today only because
      mobile-boost §17 sets body{overflow-x:clip} under 992px; `clip` is
      dropped by Safari < 16 / iOS < 16, where the same declaration hands the
      whole page a sideways scroll — the one thing the brief forbids outright.
      The full-bleed belongs on the one strip that IS inside the container and
      genuinely overflows — .hf__chips — and it is applied there (§C).
   -------------------------------------------------------------------------- */

@media (max-width:991.98px){

  body:not(.admin) .hf{
    padding-block:var(--ab-s3,12px);
  }

  /* A .hf rendered inside the hero (or explicitly opted out) is part of the
     banner composition, not a panel of its own. */
  body:not(.admin) .banner-single .hf,
  body:not(.admin) .banner-content .hf,
  body:not(.admin) .hf--hero,
  body:not(.admin) .hf--static{
    box-shadow:none;
    background:transparent;
    border-block-end:0;
    padding-inline:0;
  }

  /* anchor jumps must clear the sticky header */
  html:has(.hf){
    scroll-padding-block-start:calc(var(--ab-header-h,64px) + 12px);
  }
}

/* Never let the count hand-off box become visible, whatever display value it
   inherits from a flex/grid parent. [hidden] loses to `display:flex`. */
#hfMeta{ display:none !important; }


/* ==========================================================================
   §C  .hf__bar — THE FORM STACK
   --------------------------------------------------------------------------
   WHAT THE MARKUP ACTUALLY IS (home.blade.php):

     form.hf__bar#hfFilter
       div.hf__row.hf__row--budget   > span.hf__legend + div.hf__chips
                                       + 2 × input[type=hidden]
       div.hf__row.hf__row--fields   > 4 × div.hf__field ( label + control )
       div.hf__row.hf__row--actions  > div.hf__field--sort + submit + reset
       p.hf__count                   > span#hfCount

   So the form's DIRECT children are ROWS, not controls. An earlier draft of
   this file made .hf__bar itself the horizontal scroller with
   `> *{flex:0 0 auto}` — which laid the three rows out SIDE BY SIDE and put
   the fields and both buttons off-screen behind a sideways scroll. The form
   is a vertical stack; only the pieces that genuinely overflow scroll, and
   they do it individually.
   ========================================================================== */

body:not(.admin) .hf__bar{
  margin:0;                          /* <form> UA margin */
  display:flex;
  flex-direction:column;
  align-items:stretch;
  gap:var(--hf-gap);
}

body:not(.admin) .hf__row{
  display:flex;
  align-items:center;
  flex-wrap:wrap;
  gap:var(--hf-gap);
  min-inline-size:0;
}

body:not(.admin) .hf__legend{
  flex:0 0 auto;
  font-size:13px;
  font-weight:700;
  letter-spacing:.2px;
  color:var(--ab-ink-muted,#5b6577);
}
body:not(.admin) .banner-single .hf__legend,
body:not(.admin) .banner-content .hf__legend,
body:not(.admin) .hf--hero .hf__legend{ color:rgba(255,255,255,.86); }

body:not(.admin) .hf__chips,
body:not(.admin) .hf__group{
  display:flex;
  align-items:center;
  flex-wrap:wrap;
  flex:1 1 auto;
  min-inline-size:0;
  gap:var(--hf-gap);
}

/* label stacked above its control; the whole field is one flex item */
body:not(.admin) .hf__field{
  display:flex;
  flex-direction:column;
  align-items:stretch;
  gap:4px;
  flex:1 1 auto;
  min-inline-size:0;
}

/* the count line is a <p> — kill the UA margin, keep it on its own row */
body:not(.admin) .hf__count{
  margin:0;
  padding-block-start:2px;
}

/* --- phones/tablets ------------------------------------------------------
   The budget chips are the primary control on a monthly-payment site, so they
   get the one horizontal scroller in the block (`proximity`, not `mandatory`:
   these are controls, and mandatory snapping fights a user nudging the row to
   read a label — §H's rail of equal tiles is the case that wants `mandatory`,
   and gets it). Everything else WRAPS, which is affordable now that the block
   no longer sticks: a wrapped control is always reachable, a scrolled-away
   one is not.

   .hf__chips IS inside the .container, so the full-bleed negative margin is
   correct here (unlike on .hf itself — see §B). */
@media (max-width:991.98px){

  /* flex-wrap:nowrap is LOAD-BEARING, not tidying. .hf__row's base rule sets
     `flex-wrap:wrap`; combined with `flex-direction:column` that makes a
     multi-COLUMN wrapping container, whose flex line is sized to the
     max-content of the items on it — so the chip strip stretched to its full
     516px content width and pushed 141px of horizontal overflow onto the
     document instead of scrolling inside itself. Measured, not theorised. */
  body:not(.admin) .hf__row--budget{
    flex-direction:column;
    flex-wrap:nowrap;
    align-items:stretch;
    gap:6px;
  }

  body:not(.admin) .hf__chips{
    flex-wrap:nowrap;
    overflow-x:auto;
    overflow-y:hidden;
    overscroll-behavior-inline:contain;
    scroll-snap-type:x proximity;
    scroll-padding-inline:var(--hf-pad-i);
    -webkit-overflow-scrolling:touch;
    margin-inline:calc(var(--hf-pad-i) * -1);
    padding-inline:var(--hf-pad-i);
    /* focus rings are drawn 2px OUTSIDE the control (mobile-boost §2) and an
       overflow container clips them. Buy the ring some room. */
    padding-block:6px;
    scrollbar-width:none;            /* Firefox */
    -ms-overflow-style:none;
  }
  /* PHYSICAL (c): a pseudo-element, not a box-model value. RTL-safe. */
  body:not(.admin) .hf__chips::-webkit-scrollbar{ display:none; }

  /* no chip may shrink — a squashed pill drops its Hebrew label */
  body:not(.admin) .hf__chips > *{
    flex:0 0 auto;
    scroll-snap-align:start;
  }

  /* Fields on a grid, not a wrapping flex row: flex-wrap would leave the third
     select alone on a line and stretch it to full width, which reads as a
     mistake. Grid gives a fixed, tidy shape with no empty cells —
        brand            (full)
        year   |   km    (half + half)
        search           (full)
     :first-child is the brand field. It is positional, so if home.blade.php
     ever reorders .hf__row--fields, move this with it. */
  body:not(.admin) .hf__row--fields{
    display:grid;
    grid-template-columns:repeat(2,minmax(0,1fr));
    gap:var(--hf-gap);
    align-items:start;
  }
  body:not(.admin) .hf__row--fields > .hf__field:first-child,
  body:not(.admin) .hf__row--fields > .hf__field--search{
    grid-column:1 / -1;
  }

  /* actions: sort takes the line, the two buttons share the next one */
  body:not(.admin) .hf__row--actions{ flex-wrap:wrap; align-items:flex-end; }
  body:not(.admin) .hf__field--sort{ flex:1 1 100%; }
  body:not(.admin) .hf__submit,
  body:not(.admin) .hf__reset{ flex:1 1 calc(50% - var(--hf-gap)); }
}


/* ==========================================================================
   §D  .hf__chip — BUDGET CHIPS
   --------------------------------------------------------------------------
   The same element is rendered TWICE on this page: once over the dark hero
   scrim (mobile-boost §19 paints .banner-single::before down to
   rgba(1,6,15,.96)) and once in the light filter bar. One base + one dark
   context override, so the markup builder can copy the block verbatim.

   Active state hooks, in order of preference:
     [aria-pressed="true"]   the contract's own state (buttons)
     .is-active              THE CLASS home-filter.js ACTUALLY SETS alongside
                             aria-pressed — it was missing from the original
                             list here, which left the fallback aliases only
                             half-wired.
     .is-on / .hf__chip--on / .active   Blade convenience aliases
     :has(input:checked)     if the chip is ever rendered as a label+radio
   The :has() variant is SPLIT INTO ITS OWN RULE on purpose — see §B.
   ========================================================================== */

/* the hero's own budget group — same chips, outside the form */
body:not(.admin) .hf-hero__ask{
  font-size:clamp(15px,4.2vw,18px);
  font-weight:700;
  line-height:1.4;
  margin-block:0 var(--ab-s2,8px);
}
body:not(.admin) .hf-hero__budget{
  display:flex;
  flex-wrap:wrap;
  align-items:center;
  gap:var(--hf-gap);
  margin-block-end:var(--ab-s4,16px);
}

body:not(.admin) .hf__chip{
  -webkit-appearance:none;
  appearance:none;
  position:relative;                 /* anchors the visually-hidden input */
  display:inline-flex;
  align-items:center;
  justify-content:center;
  gap:6px;
  /* <button> and <input> do NOT inherit the page font. Every control in this
     file restates it, or the Hebrew UI drops to the UA's default face. */
  font-family:inherit;
  min-block-size:var(--hf-chip-h);
  padding-inline:16px;
  padding-block:0;
  border:1px solid var(--ab-line-2,rgba(17,17,17,.14));
  border-radius:var(--ab-r-pill,999px);
  background:var(--ab-surface,#fff);
  color:var(--ab-ink,#111);
  font-size:15px;
  font-weight:600;
  line-height:1.1;
  white-space:nowrap;
  cursor:pointer;
  text-decoration:none;              /* in case it is rendered as an <a> */
  -webkit-tap-highlight-color:transparent;
  transition:background-color var(--ab-d2,180ms) var(--ab-ease,ease),
             border-color var(--ab-d2,180ms) var(--ab-ease,ease),
             color var(--ab-d2,180ms) var(--ab-ease,ease),
             box-shadow var(--ab-d2,180ms) var(--ab-ease,ease),
             transform var(--ab-d1,120ms) var(--ab-ease,ease);
}
body:not(.admin) .hf__chip:active{ transform:scale(.96); }

/* hover only where a pointer can actually hover — mobile-boost §3 exists
   because :hover LATCHES after a tap on this site */
@media (hover:hover) and (pointer:fine){
  body:not(.admin) .hf__chip:hover{
    border-color:var(--ab-brand,#dc344c);
    background:var(--ab-brand-tint,rgba(220,52,76,.08));
    color:var(--ab-ink,#111);
  }
}

/* --- pressed / selected --------------------------------------------------- */
body:not(.admin) .hf__chip[aria-pressed="true"],
body:not(.admin) .hf__chip.is-active,
body:not(.admin) .hf__chip.is-on,
body:not(.admin) .hf__chip--on,
body:not(.admin) .hf__chip.active{
  background:var(--ab-brand,#dc344c);
  border-color:transparent;
  color:#fff;
  box-shadow:var(--ab-sh-brand,0 6px 16px rgba(220,52,76,.28));
}
@media (hover:hover) and (pointer:fine){
  body:not(.admin) .hf__chip[aria-pressed="true"]:hover,
  body:not(.admin) .hf__chip.is-active:hover,
  body:not(.admin) .hf__chip.is-on:hover,
  body:not(.admin) .hf__chip.active:hover{
    background:var(--ab-brand-strong,#c22740);
    color:#fff;
  }
}
body:not(.admin) .hf__chip[aria-pressed="true"]:active,
body:not(.admin) .hf__chip.is-active:active,
body:not(.admin) .hf__chip.is-on:active,
body:not(.admin) .hf__chip.active:active{
  background:var(--ab-brand-press,#a81f34);
}

/* SEPARATE RULE — do not merge, see §B. */
body:not(.admin) .hf__chip:has(input:checked){
  background:var(--ab-brand,#dc344c);
  border-color:transparent;
  color:#fff;
  box-shadow:var(--ab-sh-brand,0 6px 16px rgba(220,52,76,.28));
}
body:not(.admin) .hf__chip input[type="radio"],
body:not(.admin) .hf__chip input[type="checkbox"]{
  position:absolute;
  inline-size:1px; block-size:1px;
  opacity:0;
  pointer-events:none;
}

/* the global ring is `3px solid var(--ab-ink)`; on a brand-filled pill that
   reads as mud. Give the filled state a white ring with an ink halo, exactly
   like mobile-boost does for .theme-btn. */
body:not(.admin) .hf__chip[aria-pressed="true"]:focus-visible,
body:not(.admin) .hf__chip.is-active:focus-visible,
body:not(.admin) .hf__chip.is-on:focus-visible,
body:not(.admin) .hf__chip.active:focus-visible{
  outline-color:#fff;
  box-shadow:0 0 0 5px var(--ab-ink,#111);
}

/* --- dark context: the hero -----------------------------------------------
   .banner-single / .banner-content are the two real ancestors on this page;
   .hf--hero is the explicit opt-in for anywhere else. */
body:not(.admin) .banner-single .hf__chip,
body:not(.admin) .banner-content .hf__chip,
body:not(.admin) .hf--hero .hf__chip{
  background:var(--hf-on-dark);
  border-color:var(--hf-on-dark-line);
  color:#fff;
}
@supports ((-webkit-backdrop-filter:blur(6px)) or (backdrop-filter:blur(6px))){
  body:not(.admin) .banner-single .hf__chip,
  body:not(.admin) .banner-content .hf__chip,
  body:not(.admin) .hf--hero .hf__chip{
    -webkit-backdrop-filter:blur(8px) saturate(1.1);
            backdrop-filter:blur(8px) saturate(1.1);
  }
}
@media (hover:hover) and (pointer:fine){
  body:not(.admin) .banner-single .hf__chip:hover,
  body:not(.admin) .banner-content .hf__chip:hover,
  body:not(.admin) .hf--hero .hf__chip:hover{
    background:rgba(255,255,255,.22);
    border-color:rgba(255,255,255,.55);
    color:#fff;
  }
}
/* brand fill wins in BOTH contexts — one selected-state vocabulary sitewide */
body:not(.admin) .banner-single .hf__chip[aria-pressed="true"],
body:not(.admin) .banner-single .hf__chip.is-active,
body:not(.admin) .banner-single .hf__chip.is-on,
body:not(.admin) .banner-single .hf__chip.active,
body:not(.admin) .banner-content .hf__chip[aria-pressed="true"],
body:not(.admin) .banner-content .hf__chip.is-active,
body:not(.admin) .banner-content .hf__chip.is-on,
body:not(.admin) .banner-content .hf__chip.active,
body:not(.admin) .hf--hero .hf__chip[aria-pressed="true"],
body:not(.admin) .hf--hero .hf__chip.is-active,
body:not(.admin) .hf--hero .hf__chip.is-on,
body:not(.admin) .hf--hero .hf__chip.active{
  background:var(--ab-brand,#dc344c);
  border-color:#fff;
  color:#fff;
  -webkit-backdrop-filter:none;
          backdrop-filter:none;
  box-shadow:0 6px 18px rgba(1,6,15,.45);
}
body:not(.admin) .banner-single .hf__chip:has(input:checked),
body:not(.admin) .banner-content .hf__chip:has(input:checked),
body:not(.admin) .hf--hero .hf__chip:has(input:checked){
  background:var(--ab-brand,#dc344c);
  border-color:#fff;
  color:#fff;
}
/* the ink focus ring disappears on a dark hero */
body:not(.admin) .banner-single .hf__chip:focus-visible,
body:not(.admin) .banner-content .hf__chip:focus-visible,
body:not(.admin) .hf--hero .hf__chip:focus-visible{
  outline-color:#fff;
  box-shadow:0 0 0 5px rgba(1,6,15,.85);
}

/* very narrow phones: the four bands must still fit two-up in the hero */
@media (max-width:360px){
  body:not(.admin) .hf__chip{ padding-inline:13px; font-size:14.5px; }
}


/* ==========================================================================
   §E  FIELDS — selects, search, reset, no-JS submit
   --------------------------------------------------------------------------
   Sized by ELEMENT under .hf rather than by class, so it holds whether or not
   the markup builder adds .form-control. mobile-boost §12 sets
   `.form-control{min-block-size:56px}` at (0,2,1); these selectors are also
   (0,2,1) and load later, so they win — the id group below is belt and
   braces for any future rule that outranks them.
   ========================================================================== */

body:not(.admin) .hf select,
body:not(.admin) .hf input[type="search"],
body:not(.admin) .hf input[type="text"],
body:not(.admin) .hf input[type="number"]{
  -webkit-appearance:none;
  appearance:none;
  font-family:inherit;               /* see the note on .hf__chip in §D */
  min-block-size:var(--hf-ctrl-h);
  /* 16px EXACTLY. Anything smaller and iOS Safari zooms the viewport the
     moment the field takes focus — which on a sticky bar throws the whole
     catalogue off-screen. Do not "tidy" this to 15px. */
  font-size:16px;
  font-weight:600;
  line-height:1.2;
  color:var(--ab-ink,#111);
  background-color:var(--ab-surface,#fff);
  border:1px solid var(--ab-line-2,rgba(17,17,17,.14));
  border-radius:var(--ab-r-field,12px);
  padding-block:0;
  padding-inline:14px;
  box-shadow:none;
  transition:border-color var(--ab-d2,180ms) var(--ab-ease,ease),
             box-shadow var(--ab-d2,180ms) var(--ab-ease,ease);
}
body:not(.admin) #hfMake,
body:not(.admin) #hfYear,
body:not(.admin) #hfKm,
body:not(.admin) #hfSort,
body:not(.admin) #hfQ{
  min-block-size:var(--hf-ctrl-h);
  font-size:16px;
  border-radius:var(--ab-r-field,12px);
}

body:not(.admin) .hf select:focus,
body:not(.admin) .hf input:focus{
  border-color:var(--ab-brand,#dc344c);
  box-shadow:0 0 0 3px var(--ab-brand-tint,rgba(220,52,76,.08));
  outline:none;                      /* :focus only — :focus-visible below */
}
body:not(.admin) .hf select:focus-visible,
body:not(.admin) .hf input:focus-visible{
  outline:3px solid var(--ab-ink,#111);
  outline-offset:2px;
}

/* --- the caret ------------------------------------------------------------
   appearance:none strips the native arrow, so one has to be drawn back.
   PHYSICAL (a): background-position has no logical form. This page is RTL, so
   the caret belongs on the LEFT (= inline-end) and the label runs from the
   right. The [dir="ltr"] escape immediately after flips both halves.
   The data: URI is percent-encoded (# → %23) so it survives every parser. */
body:not(.admin) .hf select{
  padding-inline-start:14px;
  padding-inline-end:38px;
  /* half-width on a 320px phone, and "כל הקילומטראז׳" is longer than the box.
     Chrome/Safari honour this on <select>; elsewhere it degrades to the same
     hard clip we would have had anyway. The native picker still shows the
     full option text. */
  text-overflow:ellipsis;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.6 6 6.4l5-4.8' fill='none' stroke='%235b6577' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat:no-repeat;
  background-size:12px 8px;
  background-position:left 14px center;   /* RTL: inline-end */
}
[dir="ltr"] body:not(.admin) .hf select{
  background-position:right 14px center;  /* LTR escape for (a) */
}
/* Firefox draws a text-shadow-ish inner outline on a focused <select> */
body:not(.admin) .hf select:-moz-focusring{
  color:transparent;
  text-shadow:0 0 0 var(--ab-ink,#111);
}
/* IE/Edge legacy arrow */
body:not(.admin) .hf select::-ms-expand{ display:none; }

/* --- search --------------------------------------------------------------- */
body:not(.admin) #hfQ{
  min-inline-size:0;
}
body:not(.admin) .hf input[type="search"]::-webkit-search-decoration,
body:not(.admin) .hf input[type="search"]::-webkit-search-results-button,
body:not(.admin) .hf input[type="search"]::-webkit-search-results-decoration{
  -webkit-appearance:none;
}
/* keep the native clear button, but make it a real 24px target */
body:not(.admin) .hf input[type="search"]::-webkit-search-cancel-button{
  -webkit-appearance:none;
  inline-size:22px;
  block-size:22px;
  margin-inline-start:2px;
  border-radius:50%;
  background:var(--ab-surface-3,#f1f2f5)
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 14'%3E%3Cpath d='M3.5 3.5l7 7M10.5 3.5l-7 7' stroke='%235b6577' stroke-width='1.8' stroke-linecap='round'/%3E%3C/svg%3E")
    center / 14px 14px no-repeat;
  cursor:pointer;
}
body:not(.admin) .hf ::placeholder{
  color:var(--ab-ink-muted,#5b6577);
  font-weight:500;
  opacity:1;                         /* Firefox dims placeholders by default */
}

/* --- widths ---------------------------------------------------------------
   Every control fills its .hf__field wrapper. The FIXED minimums that used to
   live here (150 / 126 / 140 / 190px) are desktop-only on purpose: the fields
   wrap two-up under 992px, so on a 320px phone a 150px floor plus the field's
   own padding overflows the row — and `body{overflow-x:clip}` only hides that
   on Safari 16+. Below 992px the control simply follows its column.
   These are (1,1,1) and load after the (1,1,1) block above, so they win. */
body:not(.admin) #hfMake,
body:not(.admin) #hfYear,
body:not(.admin) #hfKm,
body:not(.admin) #hfSort,
body:not(.admin) #hfQ{
  inline-size:100%;
  max-inline-size:100%;
  min-inline-size:0;
}
@media (min-width:992px){
  body:not(.admin) #hfMake{ min-inline-size:150px; }
  body:not(.admin) #hfYear{ min-inline-size:126px; }
  body:not(.admin) #hfKm{   min-inline-size:140px; }
  body:not(.admin) #hfSort{ min-inline-size:150px; }
  body:not(.admin) #hfQ{    min-inline-size:190px; }
}

/* --- reset ---------------------------------------------------------------- */
body:not(.admin) #hfReset{
  -webkit-appearance:none;
  appearance:none;
  font-family:inherit;
  display:inline-flex;
  align-items:center;
  justify-content:center;
  gap:6px;
  min-block-size:var(--hf-ctrl-h);
  min-inline-size:var(--ab-tap,48px);
  padding-inline:14px;
  border:1px solid transparent;
  border-radius:var(--ab-r-pill,999px);
  background:transparent;
  color:var(--ab-ink-muted,#5b6577);
  font-size:15px;
  font-weight:700;
  white-space:nowrap;
  cursor:pointer;
  transition:background-color var(--ab-d2,180ms) var(--ab-ease,ease),
             color var(--ab-d2,180ms) var(--ab-ease,ease);
}
@media (hover:hover) and (pointer:fine){
  body:not(.admin) #hfReset:hover{
    background:var(--ab-surface-3,#f1f2f5);
    color:var(--ab-ink,#111);
  }
}
body:not(.admin) #hfReset:active{ background:var(--ab-surface-3,#f1f2f5); }
body:not(.admin) .banner-single #hfReset,
body:not(.admin) .hf--hero #hfReset{ color:rgba(255,255,255,.86); }

/* --- the no-JS submit -----------------------------------------------------
   .hf__bar is a real GET form, so it needs a submit button to work without
   JS. Give it the brand pill treatment, and let the markup hide it once the
   script has taken over by adding .hf__nojs (html.ab-js is set by the inline
   head script mobile-boost §9 relies on, so this never flashes). */
body:not(.admin) .hf__submit,
body:not(.admin) .hf__bar button[type="submit"],
body:not(.admin) .hf__bar input[type="submit"]{
  -webkit-appearance:none;
  appearance:none;
  font-family:inherit;
  display:inline-flex;
  align-items:center;
  justify-content:center;
  min-block-size:var(--hf-ctrl-h);
  padding-inline:20px;
  border:0;
  border-radius:var(--ab-r-pill,999px);
  background:var(--ab-brand,#dc344c);
  color:#fff;
  font-size:15px;
  font-weight:700;
  white-space:nowrap;
  cursor:pointer;
  box-shadow:var(--ab-sh-brand,0 6px 16px rgba(220,52,76,.28));
}
html.ab-js body:not(.admin) .hf__nojs{ display:none; }

/* <noscript> copy under the form */
body:not(.admin) .hf__noscript{
  margin:var(--ab-s3,12px) 0 0;
  padding:var(--ab-s3,12px) var(--ab-s4,16px);
  border:1px solid var(--ab-line-2,rgba(17,17,17,.14));
  border-radius:var(--ab-r-card,14px);
  background:var(--ab-surface-2,#f9f9f9);
  font-size:14px;
  line-height:1.6;
  color:var(--ab-ink,#111);
}
body:not(.admin) .hf__noscript a{ font-weight:800; color:var(--ab-brand-strong,#c22740); }


/* ==========================================================================
   §F  #hfCount — THE RESULT COUNTER
   --------------------------------------------------------------------------
   Quiet by default; it is feedback, not a headline. tabular-nums stops the
   number jittering as it counts 153 → 30 → 5.
   ========================================================================== */

body:not(.admin) #hfCount{
  display:inline-block;
  font-size:14px;
  font-weight:700;
  line-height:1.2;
  color:var(--ab-ink-muted,#5b6577);
  font-variant-numeric:tabular-nums;
  font-feature-settings:"tnum" 1;
  white-space:nowrap;
}
/* while results are in flight the number is stale — say so, quietly */
body:not(.admin) .hf-loading #hfCount,
body:not(.admin) .hf.is-loading #hfCount{ opacity:.5; }

body:not(.admin) .banner-single #hfCount,
body:not(.admin) .banner-content #hfCount,
body:not(.admin) .hf--hero #hfCount{ color:rgba(255,255,255,.88); }


/* ==========================================================================
   §G  .hf-stats — THE TRUST STRIP
   --------------------------------------------------------------------------
   Brief: "must not look like a banner ad". So: no coloured panel, no border
   radius arms race, no icons. A hairline container, one brand-weight number
   per cell, a muted label under it. 2x2 on phones (four cells, two lines,
   no horizontal scroll), one row from 768px, and a single divided strip on
   desktop.
   ========================================================================== */

body:not(.admin) .hf-stats{
  list-style:none;
  margin:var(--ab-s4,16px) 0 0;
  padding:0;
  display:grid;
  grid-template-columns:repeat(2,minmax(0,1fr));
  gap:var(--hf-gap);
}
body:not(.admin) .hf-stats__item{
  display:flex;
  flex-direction:column;
  align-items:center;
  justify-content:center;
  gap:2px;
  min-block-size:74px;
  padding:var(--ab-s3,12px) var(--ab-s2,8px);
  text-align:center;
  border:1px solid var(--ab-line,rgba(17,17,17,.08));
  border-radius:var(--ab-r-card,14px);
  background:var(--ab-surface,#fff);
}
body:not(.admin) .hf-stats__item b{
  font-size:clamp(22px,6.4vw,28px);
  font-weight:800;
  line-height:1.05;
  color:var(--ab-brand-strong,#c22740);   /* 5.6:1 on white — AA for text */
  font-variant-numeric:tabular-nums;
  font-feature-settings:"tnum" 1;
}
body:not(.admin) .hf-stats__item span{
  font-size:12.5px;
  font-weight:600;
  line-height:1.35;
  color:var(--ab-ink-muted,#5b6577);
  text-wrap:balance;
}

/* dark context (hero) */
body:not(.admin) .banner-single .hf-stats__item,
body:not(.admin) .banner-content .hf-stats__item,
body:not(.admin) .hf--hero .hf-stats__item{
  background:var(--hf-on-dark);
  border-color:var(--hf-on-dark-line);
}
body:not(.admin) .banner-single .hf-stats__item b,
body:not(.admin) .banner-content .hf-stats__item b,
body:not(.admin) .hf--hero .hf-stats__item b{ color:#fff; }
body:not(.admin) .banner-single .hf-stats__item span,
body:not(.admin) .banner-content .hf-stats__item span,
body:not(.admin) .hf--hero .hf-stats__item span{ color:rgba(255,255,255,.82); }

@media (min-width:768px){
  body:not(.admin) .hf-stats{
    display:flex;
    align-items:stretch;
    gap:0;
    border:1px solid var(--ab-line,rgba(17,17,17,.08));
    border-radius:var(--ab-r-card,14px);
    background:var(--ab-surface,#fff);
    overflow:hidden;                 /* clips the cell corners to the strip */
  }
  body:not(.admin) .hf-stats__item{
    flex:1 1 0;
    min-inline-size:0;
    border:0;
    border-radius:0;
    background:transparent;
    padding-block:var(--ab-s4,16px);
  }
  /* LOGICAL divider: inline-start is the RIGHT edge in RTL, which is exactly
     where the seam between cell 1 and cell 2 sits. Flips for free in LTR. */
  body:not(.admin) .hf-stats__item + .hf-stats__item{
    border-inline-start:1px solid var(--ab-line,rgba(17,17,17,.08));
  }
  body:not(.admin) .hf-stats__item b{ font-size:30px; }
  body:not(.admin) .hf-stats__item span{ font-size:13.5px; }

  body:not(.admin) .banner-single .hf-stats,
  body:not(.admin) .banner-content .hf-stats,
  body:not(.admin) .hf--hero .hf-stats{
    background:var(--hf-on-dark);
    border-color:var(--hf-on-dark-line);
  }
  body:not(.admin) .banner-single .hf-stats__item + .hf-stats__item,
  body:not(.admin) .banner-content .hf-stats__item + .hf-stats__item,
  body:not(.admin) .hf--hero .hf-stats__item + .hf-stats__item{
    border-inline-start-color:var(--hf-on-dark-line);
  }
}


/* ==========================================================================
   §H  .brand-rail — #make_detail AS A SCROLL-SNAP RAIL (phones)
   --------------------------------------------------------------------------
   #make_detail is a Bootstrap 5.1 `.row.justify-content-center` full of
   `[class*="col-"]` cells, each holding a .brand-item tile (plus a trailing
   .make_more "all brands" tile). mobile-boost §11 already railises it; these
   rules restate the behaviour at HIGHER specificity through the new
   .brand-rail wrapper so home-boost is self-sufficient, and add the two
   things §11 does not have: a fixed tile flex-basis (so the rail has rhythm)
   and edge-fade masks (so it reads as scrollable at a glance).

   Two Bootstrap declarations here are !important and must be met in kind:
     .justify-content-center{justify-content:center!important}
       — centring an OVERFLOWING flex row pushes content out of BOTH ends and
         makes the first tile permanently unreachable. Non-negotiable.
     (`display:flex` is restated !important for the same defensive reason
       mobile-boost gives: a utility class may be added to the row later.)
   ========================================================================== */

@media (max-width:991.98px){

  body:not(.admin) .brand-rail{
    position:relative;
    /* the wrapper now owns the full-bleed, so the row inside can sit at 0 */
    margin-inline:calc(var(--hf-pad-i) * -1);
  }

  body:not(.admin) .brand-rail #make_detail{
    display:flex !important;
    flex-wrap:nowrap;
    justify-content:flex-start !important;
    align-items:stretch;
    gap:var(--hf-gap);
    margin-inline:0;                 /* beats both BS .row and mobile-boost */
    padding-inline:var(--hf-pad-i);
    padding-block:var(--ab-s2,8px) var(--ab-s3,12px);
    overflow-x:auto;
    overflow-y:hidden;
    overscroll-behavior-inline:contain;
    scroll-snap-type:x mandatory;
    scroll-padding-inline:var(--hf-pad-i);
    -webkit-overflow-scrolling:touch;
    scrollbar-width:none;
    -ms-overflow-style:none;
  }
  /* PHYSICAL (c) */
  body:not(.admin) .brand-rail #make_detail::-webkit-scrollbar{ display:none; }

  /* BS5 `.row > *` sets width:100% + 12px side padding + margin-top. All of
     it has to go, or every tile is a full-width slab. */
  body:not(.admin) .brand-rail #make_detail > [class*="col-"],
  body:not(.admin) .brand-rail #make_detail > .make_more{
    flex:0 0 var(--hf-rail-w);
    inline-size:var(--hf-rail-w);
    max-inline-size:none;
    padding-inline:0;
    margin-block:0;
    scroll-snap-align:start;
  }
  body:not(.admin) .brand-rail #make_detail .checkbox-brand,
  body:not(.admin) .brand-rail #make_detail .form-check{
    padding:0;
    margin:0;
    block-size:100%;
  }
  body:not(.admin) .brand-rail #make_detail .checkbox-brand > a{
    display:block;
    block-size:100%;
  }
  body:not(.admin) .brand-rail #make_detail .brand-item{
    block-size:100%;
    min-block-size:96px;
    margin-block-end:0;
  }

  /* --- edge fades ---------------------------------------------------------
     PHYSICAL (b), and harmless: the gradient is symmetric, so `to right`
     produces an identical result in RTL and LTR. Gated behind @supports so a
     browser without mask support simply gets a hard edge rather than a
     silently blank rail. mask-repeat:no-repeat matters — the default `repeat`
     would tile the gradient across anything that paints outside the box. */
  @supports ((-webkit-mask-image:linear-gradient(#000,#000)) or (mask-image:linear-gradient(#000,#000))){
    body:not(.admin) .brand-rail{
      -webkit-mask-image:linear-gradient(to right,
        transparent 0, #000 var(--hf-fade),
        #000 calc(100% - var(--hf-fade)), transparent 100%);
              mask-image:linear-gradient(to right,
        transparent 0, #000 var(--hf-fade),
        #000 calc(100% - var(--hf-fade)), transparent 100%);
      -webkit-mask-repeat:no-repeat;
              mask-repeat:no-repeat;
    }
  }

  /* narrow phones — three tiles visible instead of two and a sliver */
  @media (max-width:400px){
    body:not(.admin) .brand-rail{ --hf-rail-w:100px; }
  }
}

/* --- >=992px: hand the row straight back to Bootstrap ---------------------
   mobile-boost §11's rail lives entirely inside a max-width query, and the
   rules above do too, so desktop needs no undoing — only the wrapper's own
   defaults have to be neutral. Stated explicitly so a future edit that drops
   a rule out of the query cannot quietly ship a desktop rail. */
@media (min-width:992px){
  body:not(.admin) .brand-rail{
    position:static;
    margin-inline:0;
    -webkit-mask-image:none;
            mask-image:none;
  }
  body:not(.admin) .brand-rail #make_detail{
    display:flex;
    flex-wrap:wrap;
    overflow:visible;
    scroll-snap-type:none;
    padding-inline:0;
  }
  body:not(.admin) .brand-rail #make_detail > [class*="col-"]{
    flex:0 0 auto;
    scroll-snap-align:none;
  }
}


/* ==========================================================================
   §I  .hf-loading  +  .hf-skel — RESULTS SWAPPING
   --------------------------------------------------------------------------
   home-filter.js::setLoading() puts .hf-loading on BOTH #loadMore_data AND
   <section class="hf"> — i.e. on the FILTER FORM as well as the results. That
   matters, because the dim/freeze treatment below is right for the results
   and actively harmful on the form:

     · pointer-events:none on .hf's children would make the chips, the selects
       and the reset button unclickable for the whole of every request — and
       the search box fires one on every debounced keystroke;
     · min-block-size:180px would inflate the form the moment a request starts
       and collapse it again 200ms later;
     · a second copy of the progress hairline would run at the top of the form
       while the first runs at the top of the grid.

   So the heavy part of the state is scoped with :not(.hf). The form keeps the
   only cue it needs — the dimmed, stale #hfCount in §F.

   What is left does three things and no more:
     · dims and freezes the stale results instead of blanking them, so the
       page does not collapse and bounce the scroll position;
     · blocks input on content that is about to be replaced;
     · shows one indeterminate progress hairline at the block-start edge.
   [data-hf-loading] is accepted as an alias for the JS builder's convenience.
   ========================================================================== */

body:not(.admin) .hf-loading:not(.hf),
body:not(.admin) [data-hf-loading]:not(.hf){
  position:relative;
  min-block-size:180px;
}
body:not(.admin) .hf-loading:not(.hf) > *,
body:not(.admin) [data-hf-loading]:not(.hf) > *{
  opacity:.38;
  pointer-events:none;
  transition:opacity var(--ab-d3,280ms) var(--ab-ease,ease);
}
/* the skeleton itself must stay at full strength */
body:not(.admin) .hf-loading:not(.hf) > .hf-skel,
body:not(.admin) [data-hf-loading]:not(.hf) > .hf-skel{ opacity:1; }

body:not(.admin) .hf-loading:not(.hf)::before,
body:not(.admin) [data-hf-loading]:not(.hf)::before{
  content:"";
  position:absolute;
  inset-block-start:0;
  inset-inline:0;
  block-size:3px;
  border-radius:999px;
  overflow:hidden;
  background:var(--ab-brand-tint-2,rgba(220,52,76,.16));
  z-index:2;
}
body:not(.admin) .hf-loading:not(.hf)::after,
body:not(.admin) [data-hf-loading]:not(.hf)::after{
  content:"";
  position:absolute;
  inset-block-start:0;
  inset-inline-start:0;
  block-size:3px;
  inline-size:38%;
  border-radius:999px;
  background:var(--ab-brand,#dc344c);
  animation:hf-progress 1.15s var(--ab-ease,ease) infinite;
  z-index:3;
}
/* Direction-agnostic: the track is 100% wide and the thumb travels between
   its own inline-start and inline-end, so RTL reverses it for free. */
@keyframes hf-progress{
  0%   { margin-inline-start:0; }
  50%  { margin-inline-start:62%; }
  100% { margin-inline-start:0; }
}

/* --- optional real skeleton cards ---------------------------------------
   Markup the JS builder can inject N of:
     <div class="hf-skel"><div class="hf-skel__card">
       <div class="hf-skel__media"></div>
       <div class="hf-skel__line"></div>
       <div class="hf-skel__line short"></div>
     </div>…</div>
   The grid mirrors the catalogue's own column counts so nothing jumps when
   the real cards land. Own keyframes name (hf-shimmer) so this file does not
   depend on mobile-boost's .skel being present. */
body:not(.admin) .hf-skel{
  display:grid;
  grid-template-columns:1fr;
  gap:var(--ab-s3,12px);
  margin-block:var(--ab-s3,12px);
}
@media (min-width:576px){
  body:not(.admin) .hf-skel{ grid-template-columns:repeat(2,minmax(0,1fr)); }
}
@media (min-width:992px){
  body:not(.admin) .hf-skel{ grid-template-columns:repeat(3,minmax(0,1fr)); }
}
body:not(.admin) .hf-skel__card{
  border:1px solid var(--ab-line,rgba(17,17,17,.08));
  border-radius:var(--ab-r-card,14px);
  background:var(--ab-surface,#fff);
  padding:var(--ab-s2,8px);
}
body:not(.admin) .hf-skel__media,
body:not(.admin) .hf-skel__line{
  position:relative;
  overflow:hidden;
  background:var(--ab-surface-3,#f1f2f5);
  border-radius:var(--ab-r-media,12px);
}
body:not(.admin) .hf-skel__media{
  aspect-ratio:4/3;                  /* matches mobile-boost §8's .car-img */
  margin-block-end:var(--ab-s3,12px);
}
body:not(.admin) .hf-skel__line{
  block-size:14px;
  border-radius:7px;
  margin-block-end:8px;
}
body:not(.admin) .hf-skel__line.short{ inline-size:55%; }
body:not(.admin) .hf-skel__media::after,
body:not(.admin) .hf-skel__line::after{
  content:"";
  position:absolute;
  inset:0;
  transform:translateX(-100%);
  background:linear-gradient(90deg,transparent,rgba(255,255,255,.65),transparent);
  animation:hf-shimmer 1.25s infinite;
}
@keyframes hf-shimmer{ 100%{ transform:translateX(100%); } }


/* ==========================================================================
   §J  EMPTY STATE
   --------------------------------------------------------------------------
   Three interchangeable hooks, because the markup and the JS are written by
   different builders: .hf-empty, .hf__empty, [data-hf-empty].
   ========================================================================== */

/* GIVE THE EMPTY-STATE COLUMN ITS WIDTH BACK.
   ajax_listing_car_detail.blade.php renders the empty state as
   <div class="col-12"><div class="hf-empty">…, a direct child of #car_detail.
   mobile-boost §8 halves EVERY direct [class*="col-"] child of #car_detail /
   #loadMore_data under 576px to build the two-up card grid — and that blanket
   selector catches this column too. Measured on a 320px viewport: the box came
   out 142px wide and the Hebrew copy broke into two-word lines.

   Restoring a `.col-12` to full width is not a hack that fights the grid; it
   is what col-12 already means. Cards in that grid carry col-sm-6 / col-md-6
   and are untouched by this.
   These selectors are (1,2,1), the same as mobile-boost's, and this file loads
   later — so they win without !important. */
body:not(.admin) #car_detail > .col-12,
body:not(.admin) #loadMore_data > .col-12{
  inline-size:100%;
  max-inline-size:100%;
  flex:0 0 100%;
}
/* SEPARATE RULE — :has() must never share a selector list with the fallback it
   improves on (see §B). Covers an empty/error state wrapped in some other
   column class. */
body:not(.admin) #car_detail > [class*="col-"]:has(> .hf-empty),
body:not(.admin) #car_detail > [class*="col-"]:has(> .hf-error),
body:not(.admin) #loadMore_data > [class*="col-"]:has(> .hf-empty),
body:not(.admin) #loadMore_data > [class*="col-"]:has(> .hf-error){
  inline-size:100%;
  max-inline-size:100%;
  flex:0 0 100%;
}

body:not(.admin) .hf-empty,
body:not(.admin) .hf__empty,
body:not(.admin) [data-hf-empty]{
  grid-column:1 / -1;                /* survives being dropped into a grid */
  inline-size:100%;
  max-inline-size:520px;
  margin-inline:auto;
  margin-block:var(--ab-s5,24px);
  padding:var(--ab-s5,24px) var(--ab-s4,16px);
  text-align:center;
  border:1px dashed var(--ab-line-2,rgba(17,17,17,.14));
  border-radius:var(--ab-r-card,14px);
  background:var(--ab-surface-2,#f9f9f9);
}
/* The partial renders the title as <p class="hf-empty__title">, so it is also
   matched by the `.hf-empty p` rule below — which is MORE specific (0,2,1 vs
   0,2,0) and would have flattened the heading to 15px muted body text and
   capped it at 34ch. Both selector lists are corrected so the title wins
   whichever element it is rendered as. */
body:not(.admin) .hf-empty__title,
body:not(.admin) .hf-empty p.hf-empty__title,
body:not(.admin) .hf__empty p.hf-empty__title,
body:not(.admin) .hf-empty h3,
body:not(.admin) .hf__empty h3{
  font-size:clamp(18px,4.6vw,22px);
  font-weight:800;
  line-height:1.25;
  color:var(--ab-ink,#111);
  margin:0 0 var(--ab-s2,8px);
  max-inline-size:none;
  text-wrap:balance;
}
body:not(.admin) .hf-empty__text,
body:not(.admin) .hf-empty p:not(.hf-empty__title),
body:not(.admin) .hf__empty p:not(.hf-empty__title){
  font-size:15px;
  line-height:1.6;
  color:var(--ab-ink-muted,#5b6577);
  margin:0 auto var(--ab-s4,16px);
  max-inline-size:34ch;
}
body:not(.admin) .hf-empty__reset,
body:not(.admin) .hf-empty .hf__chip,
body:not(.admin) .hf__empty .hf__chip{
  min-block-size:var(--ab-tap,48px);
  padding-inline:22px;
  background:var(--ab-brand,#dc344c);
  border-color:transparent;
  color:#fff;
  box-shadow:var(--ab-sh-brand,0 6px 16px rgba(220,52,76,.28));
}
/* the empty state is a live region — never animate it in under reduced
   motion, and never let it inherit the loading dim */
body:not(.admin) .hf-loading:not(.hf) > .hf-empty,
body:not(.admin) [data-hf-loading]:not(.hf) > .hf-empty{ opacity:1; }

/* home-filter.js's network-failure box (it builds .hf-error itself and only
   ever appends it when the grid is EMPTY, so it never blanks live results). */
body:not(.admin) .hf-error{
  grid-column:1 / -1;
  inline-size:100%;
  max-inline-size:520px;
  margin-inline:auto;
  margin-block:var(--ab-s5,24px);
  padding:var(--ab-s5,24px) var(--ab-s4,16px);
  text-align:center;
  border:1px dashed var(--ab-line-2,rgba(17,17,17,.14));
  border-radius:var(--ab-r-card,14px);
  background:var(--ab-surface-2,#f9f9f9);
}
body:not(.admin) .hf-error p{
  font-size:15px;
  line-height:1.6;
  color:var(--ab-ink-muted,#5b6577);
  margin:0 0 var(--ab-s3,12px);
}


/* ==========================================================================
   §K  >=992px — DESKTOP
   --------------------------------------------------------------------------
   Desktop is not "the phone, wider". The bar stops being chrome and becomes a
   deliberate card that straddles the seam between the hero and the catalogue:
   one wrapping row, generous gaps, no scroller, no sticky.
   ========================================================================== */

@media (min-width:992px){

  /* THE CARD IS THE .container, NOT THE SECTION. <section class="hf"> is a
     top-level child of .main-body, so it is as wide as the window: putting the
     border, the 14px radius and the shadow on IT produced a full-bleed band
     with rounded corners jammed against the browser edge, and its 24px
     padding-inline was invisible behind the narrower .container inside. The
     inner .container is already max-width-bounded and centred, which is
     exactly the "deliberate card" this section is supposed to be. */
  body:not(.admin) .hf{
    padding-block:var(--ab-s5,24px);
    background:transparent;
    border-block-end:0;
  }
  body:not(.admin) .hf > .container,
  body:not(.admin) .hf > .container-fluid{
    padding-block:var(--ab-s4,16px);
    padding-inline:var(--ab-s5,24px);
    background:var(--ab-surface,#fff);
    border:1px solid var(--ab-line,rgba(17,17,17,.08));
    border-radius:var(--ab-r-card,14px);
    box-shadow:var(--ab-sh-1,0 1px 2px rgba(1,6,15,.06),0 4px 12px rgba(1,6,15,.07));
  }
  /* inside the hero it stays a transparent composition element */
  body:not(.admin) .banner-single .hf,
  body:not(.admin) .banner-content .hf,
  body:not(.admin) .hf--hero{
    background:transparent;
    border:0;
    box-shadow:none;
    padding-inline:0;
  }
  body:not(.admin) .banner-single .hf > .container,
  body:not(.admin) .banner-content .hf > .container,
  body:not(.admin) .hf--hero > .container{
    padding-inline:0;
    background:transparent;
    border:0;
    box-shadow:none;
  }

  body:not(.admin) .hf__bar{
    gap:var(--ab-s3,12px);
    margin-inline:0;
    padding-inline:0;
    padding-block:0;
  }
  body:not(.admin) .hf__chips{
    overflow:visible;
    scroll-snap-type:none;
    margin-inline:0;
    padding-inline:0;
    padding-block:0;
  }
  body:not(.admin) .hf__chips > *{ scroll-snap-align:none; }

  body:not(.admin) .hf__row{ gap:var(--ab-s3,12px); align-items:flex-end; }
  body:not(.admin) .hf__row--budget{ align-items:center; }

  /* The flex hints belong on the FIELD WRAPPERS, not on the controls: the
     controls sit inside .hf__field, so a `flex:` on #hfQ / #hfSort is inert. */
  body:not(.admin) .hf__field{ flex:0 1 auto; }
  /* the search field is the one thing that should eat the slack */
  body:not(.admin) .hf__field--search{ flex:1 1 240px; }
  /* .hf__row--actions is [ sort | submit | reset ] in DOM order. Pushing the
     SORT field to the far end would drag the buttons with it (it is the first
     child), so the auto margin goes on the first BUTTON instead: sort stays at
     the inline-start — the right-hand edge in RTL — and the two buttons sit
     together at the inline-end. */
  body:not(.admin) .hf__row--actions .hf__submit{ margin-inline-start:auto; }

  body:not(.admin) .hf__head{ margin-block-end:var(--ab-s3,12px); }
  body:not(.admin) #hfCount{ font-size:15px; }

  body:not(.admin) .hf__chip{ min-block-size:44px; font-size:15px; }
}


/* ==========================================================================
   §L  REDUCED MOTION · FORCED COLOURS · PRINT
   --------------------------------------------------------------------------
   mobile-boost §4 already sets `animation-duration:.01ms !important` on
   everything, which effectively stops the two @keyframes above. This block
   is not redundant: it removes the moving parts outright rather than running
   them at 0.01ms (a 0.01ms infinite animation still schedules a frame every
   tick), and it gives the loading state a still, legible substitute.
   ========================================================================== */

@media (prefers-reduced-motion:reduce){
  body:not(.admin) .hf-skel__media::after,
  body:not(.admin) .hf-skel__line::after{
    animation:none;
    display:none;
  }
  body:not(.admin) .hf-loading:not(.hf)::after,
  body:not(.admin) [data-hf-loading]:not(.hf)::after{
    animation:none;
    inline-size:100%;                /* a calm, solid rule instead of a runner */
    opacity:.55;
  }
  body:not(.admin) .hf__chip,
  body:not(.admin) .hf select,
  body:not(.admin) .hf input,
  body:not(.admin) #hfReset{ transition:none; }
  body:not(.admin) .hf__chip:active,
  body:not(.admin) .brand-rail .brand-item:active{ transform:none; }
  /* snap points can hijack a flick for users who find that disorienting.
     (.hf__chips, not .hf__bar — the form itself never scrolls, see §C.) */
  body:not(.admin) .hf__chips,
  body:not(.admin) .brand-rail #make_detail{ scroll-snap-type:none; }
}

/* Windows High Contrast / forced colours: our brand fills and hairlines are
   all dropped by the OS, so state has to be re-expressed in system colours. */
@media (forced-colors:active){
  body:not(.admin) .hf__chip,
  body:not(.admin) .hf select,
  body:not(.admin) .hf input,
  body:not(.admin) #hfReset,
  body:not(.admin) .hf-stats__item,
  body:not(.admin) .hf-skel__card{
    border:1px solid ButtonBorder;
    background:ButtonFace;
    color:ButtonText;
  }
  body:not(.admin) .hf__chip[aria-pressed="true"],
  body:not(.admin) .hf__chip.is-active,
  body:not(.admin) .hf__chip.is-on,
  body:not(.admin) .hf__chip.active{
    background:Highlight;
    color:HighlightText;
    border-color:Highlight;
    forced-color-adjust:none;
  }
  body:not(.admin) .brand-rail{
    -webkit-mask-image:none;
            mask-image:none;         /* masks erase content in HCM */
  }
  body:not(.admin) .hf-loading:not(.hf) > *,
  body:not(.admin) [data-hf-loading]:not(.hf) > *{ opacity:1; }
}

@media print{
  body:not(.admin) .hf,
  body:not(.admin) .hf-skel{ display:none; }
  body:not(.admin) .brand-rail{
    -webkit-mask-image:none;
            mask-image:none;
    margin-inline:0;
  }
  body:not(.admin) .brand-rail #make_detail{
    display:flex !important;
    flex-wrap:wrap;
    overflow:visible;
  }
  body:not(.admin) .hf-stats{ break-inside:avoid; }
}


/* ==========================================================================
   §M — NOTES / KNOWN TRADE-OFFS
   --------------------------------------------------------------------------
   1. .hf IS NOT STICKY (§B). The form ships four stacked rows; a sticky block
      that tall under the 64px sticky header would occupy over half a phone
      viewport. If the block is ever reduced to a single row of chips, sticky
      becomes affordable again — and at that point it needs the shrunk-header
      offset (mobile-boost §5 swaps .main-header to ~46px on scroll), so read
      it off the DOM with `body:has(.main-header.ab-shrunk)` in a rule of its
      own, never merged with its own fallback.
   2. ONLY .hf__chips SCROLLS HORIZONTALLY (§C), and it holds four chips that
      nearly fit — so a control is never really out of reach. The fields and
      the actions WRAP instead. This is the whole reason .hf gave up sticky:
      wrapping costs vertical space, and vertical space is only free once the
      block scrolls away with the page.
   3. RAIL EDGE FADES are unconditional. With fewer than ~4 brands (never the
      case here: 30 active) the first and last tiles would look faded for no
      reason. Making the fade conditional needs a scroll listener; the JS
      builder can toggle a class and I will wire it to
      `.brand-rail.is-start / .is-end` on request.
   4. NOTHING HERE TOUCHES .car-box, .car-img, .car-footer or the load-more
      button. mobile-boost §8 owns those; a second opinion on the same box
      model is how card layouts rot.
   5. FOUR !important declarations in the whole file, all deliberate:
      three in §H/print, which meet Bootstrap's own !important utilities
      (.justify-content-center / .d-*) head on, and one on #hfMeta, where the
      plain [hidden] attribute loses to a flex/grid parent's display value.
   6. .hf-loading arrives on the FORM as well as the results grid (that is
      what home-filter.js does). Every rule in §I that dims, freezes or
      resizes is therefore written `:not(.hf)`. If you add another rule to
      §I, it needs the same guard or the filter goes dead mid-request.
   ========================================================================== */
/* ==========================================================================
   §30 RAIL + SPEC GRID
   --------------------------------------------------------------------------
   APPEND-ONLY block for home-boost.css. Nothing above is edited; every rule
   here is written to win on the cascade from the END of the file, and every
   selector is prefixed body:not(.admin) so the admin panel (whose <body>
   carries no class at all) is never touched.

   WHAT THIS FIXES
     A. The .car-list spec block inside every .car-box was a ragged zigzag:
        the engine-capacity and kilometre <li> carry Bootstrap's .w-100
        (width:100%!important) while the model/hand/hp items are auto-width,
        so the rows ran short-short / FULL / short / FULL. This turns the
        whole list into a fixed 2-column grid where every cell is the same
        size, and neutralises .w-100 so it can no longer force a full row.
        The CTA underneath becomes a full-width primary button.
     B. The brand rail did not move. #make_detail is re-stated as a clean,
        uniform horizontal scroller with symmetric edge fades, and — the part
        that actually unblocks the motion — snapping is switched OFF for as
        long as brand-rail.js owns the scroll position (30.6b). Snap re-targets
        programmatic scrolls at BOTH `mandatory` and `proximity`, so §H's snap
        port was silently eating every frame of the marquee. NO @keyframes
        translate is defined anywhere in this block: the JS owns the motion via
        scrollLeft, CSS owns the look and gets out of the scroller's way.

   CASCADE NOTES
     · home-boost.css loads AFTER mobile-boost.css, and this is the last
       block in home-boost.css, so §8 (card) and §H (rail) are both beaten
       on source order alone at equal specificity. The selectors below are
       also one class deeper than theirs, so order is belt-and-braces.
     · Exactly TWO !important declarations are used, both against Bootstrap
       utilities that are themselves !important: `.w-100{width:100%!important}`
       and `.justify-content-center{justify-content:center!important}` — plus
       a defensive one on `display:grid`, explained at its site.
     · RTL-first throughout: logical properties only. The one physical value
       is the mask gradient's `to right`, which is provably safe because the
       gradient is symmetric (see 30.7).
   ========================================================================== */


/* --------------------------------------------------------------------------
   30.1  LOCAL TOKENS
   Only new *local* names. Every value resolves to a mobile-boost §1 token so
   there is still one source of truth. Breakpoints below re-declare only these
   custom properties, never the rules — that is the whole point of scoping
   them onto .car-list / .brand-rail.
   -------------------------------------------------------------------------- */

body:not(.admin) .car-box .car-list{
  --rs-ico:24px;                       /* spec icon box — matches the img attrs */
  --rs-gap:var(--ab-s1, 4px);          /* gap BETWEEN cells                     */
  --rs-pad-i:var(--ab-s2, 8px);        /* cell inline padding                   */
  --rs-pad-b:6px;                      /* cell block padding                    */
  --rs-lh:24px;                        /* one line box, tall enough for the icon */
  --rs-h:38px;                         /* uniform cell min height (24+6+6+2)    */
  --rs-fz:12.5px;
  --rs-icon-gap:6px;                   /* icon -> text                          */
}

body:not(.admin) .brand-rail{
  --hf-fade:24px;                      /* wider than §H's 18px: a rail that is
                                          moving on its own needs a slightly
                                          softer edge or the tiles look clipped */
}


/* ==========================================================================
   30.2  SPEC LIST -> 2-COLUMN GRID  (kills the zigzag)
   --------------------------------------------------------------------------
   `repeat(2, minmax(0,1fr))` IS `1fr 1fr` with the implicit min-content floor
   removed. That floor is not cosmetic: `1fr` expands to `minmax(auto,1fr)`,
   and a long engine string ("מנוע 1.5 טורבו PHEV") would push the track wider
   than the card and blow the whole grid out. minmax(0,1fr) makes that
   structurally impossible, which is why it is used instead of the literal
   shorthand.

   `display:grid` carries !important as insurance ONLY: mobile-boost §8 owns
   .car-list and its exact declarations are not in the staged excerpt, so if
   §8 set `display:flex !important` this file would silently do nothing and
   ship the zigzag to production. One !important buys certainty here; remove
   it once §8 has been read and confirmed important-free.
   ========================================================================== */

body:not(.admin) .car-box .car-list{
  display:grid;
  grid-template-columns:repeat(2, minmax(0, 1fr));
  gap:var(--rs-gap);
  align-items:stretch;                 /* every cell in a row is the same height */

  list-style:none;
  padding:0;
  margin-block:var(--ab-s2, 8px) var(--ab-s2, 8px);
  margin-inline:0;
}

/* --- the cell ------------------------------------------------------------
   NOT display:flex. The text inside each <li> is a bare TEXT NODE sitting
   next to the <img> (see ajax_listing_car_detail.blade.php lines 109/131/144)
   — in a flex container that text becomes an *anonymous* flex item, and an
   anonymous box cannot take overflow:hidden, so text-overflow:ellipsis is
   impossible there and a long value would simply get hard-clipped.
   As a block box with an inline-block icon, the ellipsis works on the line
   box itself and applies to bare text nodes and <span>-wrapped text alike.
   The icon still behaves exactly as `flex:0 0 auto` would: fixed 24px, never
   shrinking, never wrapping away from its value. */
body:not(.admin) .car-box .car-list > li{
  display:block;
  min-inline-size:0;                   /* redundant next to overflow:hidden, but
                                          states the intent: never widen a track */
  min-block-size:var(--rs-h);
  margin:0;
  padding-block:var(--rs-pad-b);
  padding-inline:var(--rs-pad-i);

  font-size:var(--rs-fz);
  line-height:var(--rs-lh);
  font-weight:500;
  color:var(--ab-ink, #111);
  text-align:start;                    /* RTL: reads from the inline start edge */

  /* single line, ellipsis on overflow — the engine string is the long one */
  white-space:nowrap;
  overflow:hidden;
  text-overflow:ellipsis;

  /* one calm, uniform surface so the block reads as a single unit instead of
     five pills of five different widths */
  background:var(--ab-surface-2, #f9f9f9);
  border:1px solid var(--ab-line, rgba(17,17,17,.08));
  border-radius:var(--ab-r-field, 12px);
  box-sizing:border-box;
}

/* --- NEUTRALISE .w-100 ---------------------------------------------------
   WHY THIS EXISTS: the engine-capacity <li> and the kilometre <li> are
   authored as <li class="w-100"> in the Blade partial. Bootstrap ships
   `.w-100{width:100%!important}`, which is what made those two rows full
   width while their neighbours were auto-width — the exact zigzag the user
   circled. In a grid the item must be an ordinary cell, so the width is
   handed back to the track (grid stretches it to fill anyway).
   !important is mandatory here: nothing beats an !important utility except
   another !important. DO NOT remove the class from the Blade file to "fix"
   this instead — .w-100 may be relied on by the car-detail page. */
body:not(.admin) .car-box .car-list > li.w-100{
  inline-size:auto !important;
  max-inline-size:none;
  grid-column:auto;
}

/* --- the icon ------------------------------------------------------------ */
body:not(.admin) .car-box .car-list > li > img{
  inline-size:var(--rs-ico);
  block-size:var(--rs-ico);
  max-inline-size:none;
  object-fit:contain;
  display:inline-block;
  vertical-align:middle;
  margin-inline-end:var(--rs-icon-gap);
  flex:0 0 auto;                       /* inert here; kept so the icon still
                                          behaves if a future rule flexes the li */
}

/* the hand branch wraps its value in <span dir="rtl"> / a styled span; make it
   participate in the same line box rather than starting a new one */
body:not(.admin) .car-box .car-list > li > span{
  display:inline;
  vertical-align:middle;
}

/* --- ORPHAN HANDLING -----------------------------------------------------
   The list renders with 3, 4 or 5 items (hand and hp are optional Blade
   branches). 4 -> a perfect 2x2. 3 and 5 -> one leftover cell.

   CHOICE MADE: the orphan SPANS BOTH COLUMNS.
   Rationale: a half-width cell with an empty gap beside it reads as a
   rendering bug, while a full-width final row reads as a deliberate footer
   to the block — and the orphan is always the kilometre item (it is last in
   the partial), whose value is short and looks correct centred in a wide
   cell's start edge. `:last-child:nth-child(odd)` is the whole test: if the
   final <li> sits at an odd position it has no partner.
   This rule is placed AFTER the .w-100 override on purpose — the kilometre
   item carries .w-100, and this must win over `grid-column:auto` above. */
body:not(.admin) .car-box .car-list > li:last-child:nth-child(odd){
  grid-column:1 / -1;                  /* line numbers follow the writing mode,
                                          so this is full-width in RTL and LTR */
}


/* --------------------------------------------------------------------------
   30.3  TYPE SCALE AT NARROW CARD WIDTHS
   From 576px up Bootstrap puts TWO cards per row (col-sm-6), and from 992px
   three or four (col-lg-4 / col-xl-3). In all of those the card is ~250-300px
   wide, so a grid cell is only ~115-135px — the 12.5px scale starts clipping
   values that fit fine on a single-column phone. Only the tokens change.
   -------------------------------------------------------------------------- */

@media (min-width:576px){
  body:not(.admin) .car-box .car-list{
    --rs-ico:20px;
    --rs-fz:11.5px;
    --rs-pad-i:6px;
    --rs-icon-gap:5px;
    --rs-lh:20px;
    --rs-h:34px;
  }
}

/* very narrow phones: keep two columns (the alignment is the point) but stop
   the icon eating the value */
@media (max-width:359.98px){
  body:not(.admin) .car-box .car-list{
    --rs-ico:20px;
    --rs-fz:12px;
    --rs-pad-i:6px;
    --rs-icon-gap:5px;
  }
}


/* ==========================================================================
   30.4  CTA — FULL-WIDTH PRIMARY ACTION
   --------------------------------------------------------------------------
   Applies to whichever branch the Blade partial renders: the WhatsApp link
   (.theme-btn.hf-wa) or the car-page link (.theme-btn). Scoped to
   .car-box .car-footer so the load-more <input class="theme-btn loaddata">
   further down the partial is untouched.
   ========================================================================== */

/* .car-box is already a flex column (mobile-boost §8). Making .car-content a
   flex column too is what lets the footer sink to the bottom, so every CTA in
   a row lines up even when one card has 3 specs and its neighbour has 5. */
body:not(.admin) .car-box > .car-content{
  display:flex;
  flex-direction:column;
  flex:1 1 auto;
  min-inline-size:0;
}

body:not(.admin) .car-box .car-footer{
  display:flex;
  margin-block-start:auto;             /* pin to the bottom of the card */
  padding-block-start:var(--ab-s1, 4px);
}

body:not(.admin) .car-box .car-footer .theme-btn{
  display:inline-flex;
  align-items:center;
  justify-content:center;
  gap:var(--ab-s1, 4px);

  flex:1 1 auto;
  inline-size:100%;
  min-block-size:var(--ab-tap, 48px);
  padding-block:0;
  padding-inline:var(--ab-s3, 12px);

  font-size:15px;
  font-weight:700;
  line-height:1.2;
  text-align:center;
  text-decoration:none;

  color:#fff;
  background:var(--ab-brand, #dc344c);
  border:1px solid var(--ab-brand, #dc344c);
  border-radius:var(--ab-r-field, 12px);
  box-shadow:var(--ab-sh-brand, 0 6px 16px rgba(220,52,76,.24));

  transition:background-color var(--ab-d1, 120ms) var(--ab-ease, ease),
             box-shadow var(--ab-d2, 180ms) var(--ab-ease, ease),
             transform var(--ab-d1, 120ms) var(--ab-ease, ease);
}

/* hover only where a pointer can actually hover — a phone would otherwise
   keep the hover paint stuck after a tap */
@media (hover:hover) and (pointer:fine){
  body:not(.admin) .car-box .car-footer .theme-btn:hover{
    background:var(--ab-brand-strong, #c22740);
    border-color:var(--ab-brand-strong, #c22740);
  }
}
body:not(.admin) .car-box .car-footer .theme-btn:active{
  transform:translateY(1px);
  box-shadow:none;
}


/* ==========================================================================
   30.5  BRAND RAIL — VISUAL SUPPORT FOR THE JS AUTO-SCROLLER
   --------------------------------------------------------------------------
   The tiles inside #make_detail are injected by home.blade.php's inline AJAX
   on document.ready, so they do not exist at parse time. That is a JS problem
   (MutationObserver / poll on childElementCount) and nothing here depends on
   them existing — every rule is a plain descendant selector that simply
   starts applying the moment the nodes land.

   NO @keyframes TRANSLATE IS DEFINED HERE, deliberately. The JS drives
   scrollLeft/scrollTo; a CSS transform animation on the same element would
   fight it and, worse, would move the painted tiles without moving the scroll
   position, so hit-testing would land on the wrong brand.
   ========================================================================== */

@media (max-width:991.98px){

  body:not(.admin) .brand-rail{
    position:relative;
    isolation:isolate;
  }

  body:not(.admin) .brand-rail #make_detail{
    display:flex !important;           /* meets Bootstrap's .d-* utilities */
    flex-wrap:nowrap;
    justify-content:flex-start !important;
    /* ^ .justify-content-center is on the row and is !important. Centring an
         OVERFLOWING flex row pushes content out of BOTH ends, which makes the
         first tile permanently unreachable AND makes a programmatic scroll to
         offset 0 land on nothing. Non-negotiable. */
    align-items:stretch;

    overflow-x:auto;
    overflow-y:hidden;
    overscroll-behavior-inline:contain;

    /* THE NO-JS DEFAULT ONLY. Read 30.6 before touching this line.
       §H sets `x mandatory`. This relaxes it to `proximity` so a hand-driven
       rail still snaps pleasantly without mandatory's hard re-targeting.

       DO NOT BELIEVE THE USUAL CLAIM THAT `proximity` EXEMPTS PROGRAMMATIC
       SCROLLS. It does not — measured in Chrome 1xx on this exact markup
       (60 tiles, scrollWidth 6496, clientWidth 375, dir=rtl):

         scroll-snap-type      el.scrollLeft = -0.53 … -5.3 (10 writes)
         --------------------  ------------------------------------------
         x mandatory           reads back 0,0,0,0,0,0,0,0,0,0   (dead)
         x proximity           reads back 0,0,0,0,0,0,0,0,0,0   (dead)
         none                  reads back -1,-1,-2,-2,-3,…,-5   (moves)

       Snapping re-targets EVERY scroll operation, user or script, at both
       strictnesses. `proximity` alone therefore does NOT make the marquee
       work — it is exactly as fatal as `mandatory`. The rail moves only
       because 30.6 switches snapping off while a script owns the scroll
       position. That rule is load-bearing, not an "escape hatch". */
    scroll-snap-type:x proximity;

    /* Keep motion under the JS's control. If a global `scroll-behavior:smooth`
       is ever added to html/body, every `el.scrollLeft += n` would queue its
       own smooth animation and the rail would crawl and jitter. */
    scroll-behavior:auto;

    scrollbar-width:none;              /* Firefox */
    -ms-overflow-style:none;           /* legacy Edge */
  }
  /* PHYSICAL pseudo-element, no logical equivalent exists */
  body:not(.admin) .brand-rail #make_detail::-webkit-scrollbar{
    display:none;
    inline-size:0;
    block-size:0;
  }

  /* Uniform tiles. Bootstrap's `.row > *` sets width:100% + 12px inline
     padding + margin-top on every column, and the tiles also carry
     col-3 / col-md-3 / col-lg-2. flex:0 0 <basis> with flex-shrink 0 is what
     guarantees the rail has a constant rhythm — an auto-scroller stepping by
     "one tile" needs every tile to be the same width. */
  body:not(.admin) .brand-rail #make_detail > .make_more,
  body:not(.admin) .brand-rail #make_detail > [class*="col-"]{
    flex:0 0 var(--hf-rail-w, 112px);
    inline-size:var(--hf-rail-w, 112px);
    min-inline-size:var(--hf-rail-w, 112px);
    max-inline-size:none;
    padding-inline:0;
    margin-block:0;
    scroll-snap-align:start;
    scroll-snap-stop:normal;           /* never trap a fast programmatic scroll */
  }

  /* centre the logo inside the tile so a 30-brand rail reads as one row of
     equal plates rather than 30 differently-cropped images */
  body:not(.admin) .brand-rail #make_detail .brand-item{
    block-size:100%;
    margin-block-end:0;
  }
  body:not(.admin) .brand-rail #make_detail .brand-img-label{
    display:flex;
    align-items:center;
    justify-content:center;
    inline-size:100%;

    /* `block-size:100%` ALONE DOES NOTHING HERE, and without the line under
       it the centring silently fails. The tile's 96px comes from §H's
       `min-block-size` on .brand-item, not from a `height`, and a percentage
       block-size only resolves against a definite parent BLOCK-SIZE — a
       min-block-size is not one. Measured: label 56px (= the logo's own
       height) inside a 96px tile, pinned to the block start, 40px of dead
       space under every logo, align-items:center centring nothing.
       `min-block-size:inherit` takes .brand-item's own computed floor (96px),
       which is definite, so the label fills the tile and the logo centres.
       It also tracks §H automatically if that floor is ever retuned.
       Measured after: label 96px, logo centre offset 0px from tile centre. */
    block-size:100%;
    min-block-size:inherit;
    margin:0;
  }
  body:not(.admin) .brand-rail #make_detail .brand-img img{
    max-inline-size:100%;
    max-block-size:56px;
    inline-size:auto;
    block-size:auto;
    object-fit:contain;
  }
}


/* --------------------------------------------------------------------------
   30.6  .is-paused — THE HOOK THE JS TOGGLES
   The auto-scroller is expected to add .is-paused to .brand-rail on
   pointerenter / touchstart / focus-within / document hidden, and remove it
   again afterwards.

   `animation-play-state:paused` on the subtree is the literal "nothing
   animates" contract, and it costs nothing when (as here) no animation is
   running — it is a promise to any decorative animation added later.

   TRANSITIONS ARE DELIBERATELY LEFT ALIVE. .is-paused is on precisely when a
   finger or a pointer is on the rail, which is exactly when tap/hover
   feedback must still respond; killing transitions there would make the rail
   feel dead at the moment the user touches it.
   -------------------------------------------------------------------------- */

body:not(.admin) .brand-rail.is-paused,
body:not(.admin) .brand-rail.is-paused *{
  animation-play-state:paused;
}

/* --------------------------------------------------------------------------
   30.6b  SNAP-OFF WHILE A SCRIPT OWNS THE SCROLL POSITION  ***LOAD-BEARING***
   --------------------------------------------------------------------------
   NOT an escape hatch. Delete this rule and the rail stops moving — see the
   measured table in 30.5: snapping re-targets programmatic scrolls at BOTH
   strictnesses, so `x proximity` is as fatal to a 0.5px-per-frame marquee as
   `x mandatory` is. This is the only thing that makes the marquee run.

   BOTH classes are listed on purpose.
     .is-animating — on while the rail is genuinely drifting. Without it the
       marquee is dead.
     .is-paused — on while a finger/pointer/focus is on the rail, the tab is
       hidden, or the rail is off-screen. Without it, the instant the script
       drops .is-animating mid-tile the engine re-snaps the rail to the
       nearest tile: measured, a rail parked at scrollLeft -60 jumped to -108
       the moment .is-animating came off. A 48px kick on every single touch.
       Keeping snap off for the paused state too freezes the rail exactly
       where it stopped.
   Between them the two classes mean "a live script owns this scroller", so
   snapping is off for the whole time the script is running and on for the
   whole time it is not — which is the honest contract: a marquee and a snap
   port cannot share one scroll position.

   NO-JS / SCRIPT-FAILED PATH IS UNAFFECTED: neither class is ever present,
   so 30.5's `x proximity` stands and the rail is a normal snapping scroller.

   Matched on the wrapper AND on the scroller because brand-rail.js toggles
   both, and a future rewrite may only keep one. Specificity is (1,3,1) either
   way, which beats 30.5's (1,2,1) — no !important needed, but do not "tidy"
   these into a shorter selector: `#make_detail.is-animating` on its own is
   (1,1,0) and would LOSE to 30.5.

   NOTE FOR THE JS: brand-rail.js only reaches for its inline
   `scroll-snap-type:none` fallback when the computed value still contains
   `mandatory`. Because this file relaxes §H to `proximity`, that probe now
   returns false and the inline fallback never fires. The classes below are
   therefore the sole protection. Keep emitting them.
   -------------------------------------------------------------------------- */
body:not(.admin) .brand-rail.is-animating #make_detail,
body:not(.admin) .brand-rail.is-paused #make_detail,
body:not(.admin) .brand-rail #make_detail.is-animating,
body:not(.admin) .brand-rail #make_detail.is-paused{
  scroll-snap-type:none;
}


/* --------------------------------------------------------------------------
   30.7  EDGE FADE MASKS
   RTL SAFETY: the gradient is SYMMETRIC — the same --hf-fade distance is
   consumed at 0% and at 100% — so `to right` and `to left` produce a pixel-
   identical result. There is therefore no RTL bug to fix here, and no need
   for an [dir] escape hatch; the physical keyword is safe *because* of the
   symmetry, not in spite of it. Anything asymmetric would have to be written
   with two [dir="rtl"] / [dir="ltr"] rules instead.

   @supports-gated: a browser without mask support gets a hard edge rather
   than — as an ungated `mask-image` on some old WebKit builds can do — a
   blank rail. mask-repeat:no-repeat matters; the initial `repeat` would tile
   the gradient across anything painting outside the box.
   -------------------------------------------------------------------------- */

@supports ((-webkit-mask-image:linear-gradient(#000,#000)) or (mask-image:linear-gradient(#000,#000))){
  @media (max-width:991.98px){
    body:not(.admin) .brand-rail{
      -webkit-mask-image:linear-gradient(to right,
        transparent 0,
        #000 var(--hf-fade, 24px),
        #000 calc(100% - var(--hf-fade, 24px)),
        transparent 100%);
              mask-image:linear-gradient(to right,
        transparent 0,
        #000 var(--hf-fade, 24px),
        #000 calc(100% - var(--hf-fade, 24px)),
        transparent 100%);
      -webkit-mask-repeat:no-repeat;
              mask-repeat:no-repeat;
      -webkit-mask-size:100% 100%;
              mask-size:100% 100%;
      -webkit-mask-position:center;
              mask-position:center;
    }
  }
}


/* --------------------------------------------------------------------------
   30.8  >=992px — HAND THE ROW BACK TO BOOTSTRAP
   Everything in 30.5/30.7 lives inside a max-width query, so desktop needs no
   undoing. Stated anyway, explicitly, so a future edit that drags a rule out
   of the query cannot quietly ship a desktop rail.
   NOTE FOR THE JS AGENT: above 992px #make_detail is a wrapping Bootstrap row
   with scrollWidth === clientWidth, so the auto-scroller has nothing to
   scroll and must no-op rather than error.
   -------------------------------------------------------------------------- */

@media (min-width:992px){
  body:not(.admin) .brand-rail{
    position:static;
    isolation:auto;
    -webkit-mask-image:none;
            mask-image:none;
  }
  body:not(.admin) .brand-rail #make_detail{
    flex-wrap:wrap;
    overflow:visible;
    scroll-snap-type:none;
  }
  body:not(.admin) .brand-rail #make_detail > .make_more,
  body:not(.admin) .brand-rail #make_detail > [class*="col-"]{
    flex:0 0 auto;
    inline-size:auto;
    min-inline-size:0;
    scroll-snap-align:none;
  }
}


/* --------------------------------------------------------------------------
   30.9  REDUCED MOTION · FORCED COLOURS
   -------------------------------------------------------------------------- */

@media (prefers-reduced-motion:reduce){
  /* the rail becomes a plain, static, hand-driven scroller: no snap to
     hijack a flick, no transitions, and any decorative animation removed
     outright rather than run at 0.01ms (a 0.01ms infinite animation still
     schedules a frame every tick). The JS auto-scroller must ALSO check
     matchMedia('(prefers-reduced-motion:reduce)') and simply not start —
     CSS cannot stop a scrollLeft loop. */
  body:not(.admin) .brand-rail #make_detail{
    scroll-snap-type:none;
    scroll-behavior:auto;
  }
  body:not(.admin) .brand-rail,
  body:not(.admin) .brand-rail *{
    animation:none;
    transition:none;
  }
  body:not(.admin) .car-box .car-footer .theme-btn{
    transition:none;
  }
  body:not(.admin) .car-box .car-footer .theme-btn:active{
    transform:none;
  }
}

@media (forced-colors:active){
  /* our hairlines and surfaces are dropped by the OS, so the cell boundary
     has to be re-expressed in a system colour or the grid loses its shape */
  body:not(.admin) .car-box .car-list > li{
    border:1px solid ButtonBorder;
    background:ButtonFace;
    color:ButtonText;
  }
  body:not(.admin) .car-box .car-footer .theme-btn{
    border:1px solid ButtonBorder;
    box-shadow:none;
  }
  body:not(.admin) .brand-rail{
    -webkit-mask-image:none;
            mask-image:none;           /* masks erase content in HCM */
  }
}

@media print{
  body:not(.admin) .car-box .car-list{ break-inside:avoid; }
  body:not(.admin) .car-box .car-footer .theme-btn{
    color:#000;
    background:none;
    box-shadow:none;
  }
}

/* ==========================================================================
   §30 — KNOWN TRADE-OFFS
   1. `display:grid` on .car-list is insurance against an unseen
      mobile-boost §8 declaration, not a cascade requirement. Read §8; if it
      is important-free, drop the flag.
   2. The spec cells are display:block, not flex, because the values are bare
      text nodes and an anonymous flex item cannot be ellipsised. If the Blade
      partial is ever changed to wrap every value in a <span>, this can become
      a proper flex/grid row with the span taking min-inline-size:0.
      Until then, do not "modernise" it to flex — the ellipsis will silently
      turn into a hard clip.
      MEASURED TRUNCATION BOUNDARY: at 375px (one card per row, 163px cells)
      nothing clips, including "נפח מנוע 1598 טורבו". At the 3-up/4-up desktop
      card (135px cells) that same string overflows by ~9px and ellipsises.
      Mobile — the traffic that matters — is clean; desktop can lose the tail
      of an unusually long engine string. The right fix is a title="" on the
      <li> in ajax_listing_car_detail.blade.php so the full value stays
      recoverable on hover; do NOT chase it by shrinking --rs-fz further,
      which costs legibility on every card to rescue a rare one.
   3. The orphan spans both columns (30.2). If the 3-item case (no hand, no
      hp) ever looks too airy in practice, the alternative one-liner is
      `grid-column:auto` on that selector, which leaves the orphan half-width
      and inline-start aligned.
   4. Snap. §H's `mandatory` is relaxed to `proximity` (30.5) and switched
      off entirely while the script is live (30.6b). The relaxation is a
      TASTE change only: measurement showed proximity re-targets programmatic
      scrolls exactly as mandatory does, so it buys the marquee nothing. What
      buys the marquee everything is 30.6b. Removing the auto-scroller means
      deleting 30.6b and restoring §H's `mandatory`; removing 30.6b while
      keeping the auto-scroller ships a rail that does not move.
      Cost of 30.6b: while the script is alive the rail does not snap at all,
      so a human flick coasts to a free position instead of landing on a tile
      edge. That is the price of a marquee sharing one scroll position, and
      it is preferred here over a 48px snap kick on every touch.
   5. The rail only exists below 992px (§H's design, preserved). The JS
      auto-scroller is therefore a no-op on desktop by construction.
   ========================================================================== */

/* ==========================================================================
   §31  SPEC GRID — NARROW-CARD CORRECTION
   Measured on a real 390px viewport: cards render 2-up at 170px, so the
   .car-list row is 144px. Split into two columns that is a 70px cell, and a
   24px icon + 16px padding leaves ~30px for text — roughly three characters,
   so even "מודל 2026" and "150 כ״ס" were ellipsised. §30's two-column grid is
   right on desktop (134px cells) and wrong inside a half-width phone card.
   Below 992px the card is always 2-up, so the spec list goes single-column,
   the icon shrinks, and values may wrap to two lines instead of being cut.
   ========================================================================== */
@media (max-width: 991.98px) {
  body:not(.admin) .car-box .car-list{
    grid-template-columns: 1fr;      /* one spec per row inside a narrow card */
    gap: 4px;
  }
  /* the km/engine items carry Bootstrap .w-100; §30 already neutralises the
     width, this just keeps them in the single-column flow */
  body:not(.admin) .car-box .car-list li,
  body:not(.admin) .car-box .car-list li.w-100{
    grid-column: 1 / -1;
    padding: 5px 8px;
    min-block-size: 30px;
    font-size: 12px;
    line-height: 1.3;
    /* two lines beat a three-character ellipsis */
    white-space: normal;
    overflow: hidden;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    text-overflow: clip;
  }
  body:not(.admin) .car-box .car-list img{
    inline-size: 16px;
    block-size: 16px;
    margin-inline-end: 6px;
  }
}

/* Very small phones: trim once more so two lines still fit the cell */
@media (max-width: 380px) {
  body:not(.admin) .car-box .car-list li,
  body:not(.admin) .car-box .car-list li.w-100{ font-size: 11.5px; padding: 4px 7px; }
}
/* ==========================================================================
   §32  FILTER PANEL REDESIGN — "Decision Ladder"
   --------------------------------------------------------------------------
   APPEND THIS BLOCK VERBATIM TO THE END OF home-boost.css.
   home-boost.css is the LAST stylesheet on the homepage (home.blade.php:355),
   so this section is the last word in the cascade on section.hf. Several
   rules below rely on that — they are written at EQUAL or ONE STEP HIGHER
   specificity than the §B–§G / §K rule they replace and win on load order.
   If anyone ever re-sorts the sections of this file, this block must stay last
   or the old form comes back with no error reported anywhere.

   THE COMPLAINT THIS ANSWERS
     "so much text, no life here !! redesign"
   The old panel is six equal rows — תשלום חודשי / מותג / שנת ייצור /
   קילומטראז׳ / חיפוש / מיון — each a 13px bold grey <label> stacked on a
   48px full-width <select>, then a 50/50 pair of buttons. Every control wears
   identical clothing, so nothing tells you what to touch first. It reads like
   a tax form because, typographically, it IS one: six labels of equal weight,
   six values of equal weight, one flat grey.

   THE FIX — ONE RANKING, CARRIED BY TYPE AND BY GROUND
     Rank every control by what a payment-led used-car buyer actually decides
     on, then let three tiers say so out loud:

       TIER 1  white, the question       #hfCount header + legend + hint
                                         + the four budget bands, 2x2, all
                                         visible, no swipe
       TIER 2  ONE recessed #f1f2f5      brand / year|km / search / sort,
               panel, "secondary,        each a white box with its label as an
               skim it"                  11px caption ABOVE a 16px/700 value
       TIER 3  the action                submit alone at 100%, reset demoted
                                         to a 13px underlined text link

     TYPE LADDER (identical to the one the car card runs, so the two surfaces
     read as one system):
        26/19px 800 --ab-ink        the decision number  (card price / legend)
        15–16px 700 --ab-ink        identity             (title / field value)
        11–13px 600–700 --ab-ink-muted  qualifiers       (spec / label + hint)

     RED IS SPENT EXACTLY TWICE on this surface and nowhere else: the pressed
     budget chip and the submit button. The old panel had red on submit only
     but leaked brand tint into every :hover; that stays, scoped.

     --ab-r-pill IS ELIMINATED from this surface. Chips go to 12px
     (--ab-r-field), reset stops being a pill entirely, submit goes to 12px.
     Pill-soup is a large part of what the user is reacting to; one radius
     rule kills it. 14px = container, 12px = control/panel.

   WHAT IT REPLACES, RULE BY RULE (all still present, all still needed for the
   hero copy of .hf__chip and for the no-JS path — nothing is deleted):
     §B  .hf shell            → padding-block tightened; shell kept white
     §C  chip scroller        → 2x2 GRID below 992px, full-bleed CANCELLED
     §C  .hf__row--fields     → becomes the one recessed panel
     §C  .hf__field           → becomes a white label-inside box
     §D  .hf__chip            → two-tier type, 12px radius, brand-strong fill
     §E  select / input       → borderless inside .hf__field, own chevron
     §E  .hf__submit / #hfReset → 100% / text link
     §F  #hfCount             → promoted to the form's headline (order:-1)
     §K  desktop              → three ranked bands, count folded into band 1

   MEASURED, NOT ASSUMED — every number below was read off a real render of
   this page with all nine production stylesheets loaded in their real order,
   at 320 / 375 / 992 / 1024 / 1280 / 1440px. None of it is paper arithmetic.
     Bootstrap here is `padding-inline: var(--bs-gutter-x, .75rem)` on
     .container with --bs-gutter-x UNSET at :root (verified: 0 matches), so
     the gutter is 12px per side, NOT 24px.
       .container content            375 - 24       = 351px    (measured 351)
       chip cell (2 cols, 8px gap)   (351 - 8) / 2  = 171.5px  (measured 171.5)
       chip interior (2x10 pad + 2 border)          = 150px    (measured 150)
       panel interior (2 border + 20 pad)           = 329px    (measured 329)
       half field cell (8px gap)     (329 - 8) / 2  = 160.5px  (measured 160.5)
       half field control                           = 138.5px  (measured 138.5)
       full field control            329 - 22       = 307px    (measured 307)
     Longest REAL string in every control against the room it has at 375px:
       brand  "Lamborghini"        101px / 291px
       year   "2026 ומעלה"          88px / 123px
       km     "עד 100,000 ק״מ"     117px / 123px   <- the tight one
       search placeholder          175px / 307px
       sort   "שנה — חדש לישן"     124px / 291px   (~176px before the label
                                                    shortening, in a ~113px
                                                    cell — i.e. clipped)
       widest chip <bdi>           110.6px / 150px
     Nothing clips at 375px. At 320px the <=359.98px guard drops the chip to
     11.5/15px (widest bdi 104px in 126px) and only #hfKm loses, by 22px.

   THE COST, STATED HONESTLY
     At 375px this block measures 651px tall against the old ~479px. The whole
     +172px is bought by TIER 1: showing all four budget bands at once instead
     of hiding two behind a horizontal swipe (+58px), giving the count its own
     header line (+22px), adding the hint sentence (+27px), taking reset off
     submit's shoulder onto its own line (+40px), and the extra chrome of five
     bordered field boxes. TIER 2 measures 283px, within a few px of the four
     field rows it replaces.
     On DESKTOP the direction pays rather than costs on the axis that matters
     there: the four bands and the live count now share ONE 61px line where §K
     spent two rows plus a stranded footer.
     The mobile trade is deliberate. The rank-1 control is the one thing that
     must never need a gesture to discover, and on a site whose entire pitch is
     תשלום חודשי / מימון 100% / עד 100 תשלומים that control is the budget band.

   RTL
     Logical properties throughout. ONE physical value, flagged in place and
     mirroring the escape-hatch pattern §E already established:
       (a) background-position for the select chevron — CSS has no logical
           form; an explicit [dir="ltr"] rule follows it in 32.4.
     THE PRESSED-CHIP TICK IS NOT THE SECOND ONE AND NEEDS NO ESCAPE. It is
     placed with the logical `inset-inline-end`, and its own background-position
     is `center`, which is direction-agnostic. An earlier draft of this header
     listed it as physical value (b) and promised a [dir="ltr"] rule that was
     never written — there is nothing missing, so do NOT add one, and do not
     "fix" the tick to a physical background-position to match the prose.
     <html lang="he" dir="rtl"> is verified in layouts/app/front-app.blade.php.

   MARKUP CONTRACT — UNTOUCHED
     form#hfFilter[data-endpoint][data-total] is still a real method="GET"
     form. #hfBudget, .hf__chip[data-budget-min][data-budget-max][aria-pressed],
     #hfPriceMin/nPriceMin, #hfPriceMax/nPriceMax, #hfMake/iMakeId,
     #hfYear/nYearMin, #hfKm/nKmMax, #hfQ/vKeyword, #hfSort/sort,
     #hfReset[type=reset], .hf__submit[type=submit],
     #hfCount inside p[role=status][aria-live=polite], and the <noscript>
     block all keep their names, values and semantics. home-filter.js binds
     every one of them by id, never by ancestor, so moving the sort FIELD into
     the fields row (the one structural markup edit) cannot reach it.

   SCOPE — AND THE ONE SHAPE THE .hf SCOPE DOES NOT PROTECT
     Every selector is prefixed `body:not(.admin)` and every one of them is
     ALSO scoped under `.hf`. That second scope is not decoration: .hf__chip is
     designed to be rendered a second time inside the dark hero
     (.hf-hero__budget, styled by §D's dark-context block) and .hf-empty
     re-uses .hf__chip in the empty state (§J). Neither is a descendant of
     .hf, so neither sees a single declaration in this section.

     The scope is NOT enough on its own, and an earlier draft of this comment
     claimed it was. §D writes the dark chip as
     `body:not(.admin) .banner-single .hf__chip` — (0,3,1), the SAME
     specificity as this section's `body:not(.admin) .hf .hf__chip`, with §32
     loading later. Any markup that puts a .hf INSIDE the hero, or that adds
     .hf--hero to the section itself, therefore matches BOTH and §32 wins,
     flattening the dark chips to a white box on a dark photo. §B and §K both
     ship rules for exactly those shapes (`.banner-single .hf`,
     `.banner-content .hf`, `.hf--hero`), so they are supported markup even
     though home.blade.php does not use them today — <section class="hf"> is a
     SIBLING of <section class="banner-single">, verified. 32.3 therefore ends
     with a dark-context guard that restates §D one specificity step higher.
     It matches nothing on the homepage as shipped; it exists so the trap
     cannot be sprung later.
   ========================================================================== */


/* ==========================================================================
   32.1  LOCAL TOKENS
   Only new names. Every value resolves to a mobile-boost §1 token.

   ONE FAMILY IS DELIBERATELY NOT DECLARED HERE: --hf32-chip-bg / -line / -fg /
   -num / -hover-bg / -hover-line / -on-bg / -on-line / -on-fg. They are read
   with a var() fallback everywhere the chip is painted in 32.3 and are SET only
   by the dark-context guard at the foot of that section. Declaring them at
   :root would also work — an ancestor declaration still beats it by proximity —
   but it would put the light-ground values in two places at once, the :root
   block and every var() fallback. Left undeclared, the fallback in each rule is
   the single source of truth for that rule and reads next to the property it
   feeds.
   ========================================================================== */

:root{
  --hf32-chip-h:52px;      /* 12px qualifier (14.4) + 2 gap + 16px bdi (17.6)
                              = 34px of text + 2x9px padding. 52 is the floor,
                              not a round number. Above --ab-tap (48px). */
  --hf32-field-pad-bs:6px; /* field padding-block-start */
  --hf32-field-pad-be:4px; /* field padding-block-end   */
  --hf32-ctrl-h:34px;      /* borderless control floor inside .hf__field.
                              label (11px x 1.2 = 13.2) + 34 = 47.2px of
                              label+control. The <label> carries for="…", so
                              the whole 47.2px is an activation target — 0.8px
                              under --ab-tap and 23px over WCAG 2.5.8 AA. */
  --hf32-panel-pad:10px;
  --hf32-panel-gap:8px;
}


/* ==========================================================================
   32.2  SHELL + FORM STACK
   --------------------------------------------------------------------------
   §B keeps .hf white with a block-end hairline. That stays: the recessed
   panel inside already separates "query" from "results", and a tinted band
   behind it would be two separators doing one job.
   ========================================================================== */

/* (0,3,1) beats §B's (0,2,1) `.hf{padding-block:8px}` and §B's max-width
   branch `.hf{padding-block:12px}` — id-free, one class deeper, later load.
   MEDIA-SCOPED ON PURPOSE. Written bare, this rule ALSO beat §K's
   `@media (min-width:992px){ .hf{padding-block:24px} }` — a media query adds
   nothing to specificity and §32 loads last — so it silently cut the desktop
   band's outer spacing from 24px to 16px, a change nothing in the approved
   direction asks for. The direction's 16px belongs to the mobile SECTION SHELL
   note only; on desktop §K's 24px is left standing, unmodified. */
@media (max-width:991.98px){
  body:not(.admin) .hf.hf{
    padding-block:var(--ab-s4,16px);
  }
}

/* THE ONE REORDER. .hf__count is the LAST child of the flex column; order:-1
   paints it FIRST, as the form's headline, without moving a node.
   WCAG 2.4.3 (focus order): .hf__count contains no focusable element, so the
   tab sequence is untouched.
   WCAG 1.3.2 (meaningful sequence): a result count is not sequence-dependent
   — "153 רכבים" reading before "תשלום חודשי" is coherent either way — and the
   <p role="status" aria-live="polite"> wrapper is unchanged, so the announced
   text and the announcement trigger are both exactly what they were.
   WHY IT IS BETTER HERE: feedback belongs beside the control that changes it.
   It also means §F's `.hf.is-loading #hfCount{opacity:.5}` now reads as the
   form's own headline greying out mid-request, which is a far better loading
   cue than a dimmed footnote 300px below the fold. */
body:not(.admin) .hf .hf__count{
  order:-1;
  margin:0 0 4px;
  padding-block:0 10px;
  border-block-end:1px solid var(--ab-line,rgba(17,17,17,.08));
}

/* (1,2,1) beats §F's (1,1,1) `#hfCount{font-size:14px; color:muted}`.
   15px/800 ink on white = 18.9:1. tabular-nums is kept from §F so
   153 → 30 → 5 does not jitter the line; it is restated because this rule
   sets font-* and a later reader should see the whole spec in one place. */
body:not(.admin) .hf #hfCount{
  display:inline-block;
  font-size:15px;
  font-weight:800;
  line-height:1.2;
  color:var(--ab-ink,#111);
  font-variant-numeric:tabular-nums;
  font-feature-settings:"tnum" 1;
  white-space:nowrap;
}

/* §F sets .5 while a request is in flight; .45 reads as "stale" a touch more
   clearly now that the number is 800 weight. (1,3,1) — equal to §F's own
   `.hf.is-loading #hfCount`, later load wins.
   `animation-name:none` CANCELS the pop below; removing .is-loading starts a
   fresh one. That is the whole mechanism — zero JS, keyed on the class
   home-filter.js already toggles on section.hf (verified, home-filter.js:226-227). */
body:not(.admin) .hf.is-loading #hfCount{
  opacity:.45;
  animation-name:none;
}

@keyframes hf32-count-pop{
  0%   { transform:scale(.94); opacity:.55; }
  55%  { transform:scale(1.04); opacity:1; }
  100% { transform:scale(1);   opacity:1; }
}
body:not(.admin) .hf:not(.is-loading) #hfCount{
  animation:hf32-count-pop var(--ab-d3,280ms) var(--ab-ease-out,cubic-bezier(.2,.7,.3,1)) both;
}

/* TIER 1 headline. 19px/800 ink = 18.9:1 on white. This is the same slot the
   card gives its 26px price: the question, alone, above everything. */
body:not(.admin) .hf .hf__legend{
  display:block;
  font-size:19px;
  font-weight:800;
  line-height:1.25;
  letter-spacing:-.01em;
  color:var(--ab-ink,#111);
  margin:0 0 2px;
}

/* NEW element (see the blade diff): the sentence that replaces a grey label
   with a human instruction. 12.5px/600 --ab-ink-muted on white = 5.9:1.
   44 chars at ~6.2px ≈ 273px, so it sets on one line inside 351px. */
body:not(.admin) .hf .hf__hint{
  margin:0 0 10px;
  font-size:12.5px;
  font-weight:600;
  line-height:1.4;
  color:var(--ab-ink-muted,#5b6577);
  text-wrap:pretty;
}

/* §C's max-width branch gives .hf__row--budget a uniform 6px gap. The three
   children now want different spacing (legend→hint 2px, hint→chips 10px), so
   the gap goes to 0 and the margins above carry it. */
body:not(.admin) .hf .hf__row--budget{
  gap:0;
}


/* ==========================================================================
   32.3  BUDGET CHIPS — 2x2 GRID, TWO-TIER TYPE
   --------------------------------------------------------------------------
   THE SINGLE MOST IMPORTANT CHANGE IN THIS FILE, and the one with the sharpest
   footgun.

   §C makes .hf__chips a full-bleed horizontal scroller: measured scrollWidth
   555px against a 375px client width, i.e. HALF the options of the rank-1
   control sit behind a swipe with no visible affordance. Four bands must all
   be visible at once, so it becomes a 2x2 grid.

   CANCELLING §C IS MANDATORY, NOT TIDYING. §C sets
     margin-inline:-12px  padding-inline:12px  overflow-x:auto  overflow-y:hidden
     scroll-snap-type:x proximity  flex-wrap:nowrap  scroll-padding-inline:12px
   Leave the negative margin in place with no scroller to absorb it and the
   block is 24px WIDER than the viewport. That failure is invisible today only
   because mobile-boost §17 sets body{overflow-x:clip} — which Safari/iOS < 16
   drops, handing those users a sideways-scrolling homepage. All of it is
   reset in the SAME media query that establishes the grid.
   ========================================================================== */

@media (max-width:991.98px){

  /* (0,3,1) vs §C's (0,2,1) — one class deeper AND later. */
  body:not(.admin) .hf .hf__chips{
    display:grid;
    grid-template-columns:repeat(2,minmax(0,1fr));
    gap:8px;

    /* ---- the five §C cancellations, plus two for completeness ---- */
    margin-inline:0;                 /* cancels §C margin-inline:-12px  <-- the bug */
    padding-inline:0;                /* cancels §C padding-inline:12px  */
    overflow:visible;                /* cancels §C overflow-x:auto / -y:hidden.
                                        `visible` also stops the container
                                        clipping the 3px focus ring + 2px
                                        offset that mobile-boost §2 draws
                                        OUTSIDE each chip. */
    scroll-snap-type:none;           /* cancels §C scroll-snap-type:x proximity */
    flex-wrap:wrap;                  /* cancels §C flex-wrap:nowrap. Inert under
                                        display:grid, declared so a future
                                        display change cannot resurrect the
                                        nowrap row.
                                        NOT `initial` — an earlier draft wrote
                                        that, and the initial value of
                                        flex-wrap IS `nowrap`, so the one
                                        declaration whose entire job is to be a
                                        safety net was re-asserting the value it
                                        claimed to undo. */
    scroll-padding-inline:0;         /* inert once nothing scrolls; kept honest */
    padding-block:3px;               /* §C used 6px to keep focus rings out of
                                        the scroll clip. With overflow:visible
                                        nothing clips, so this only keeps the
                                        ring off the hairline above. */
  }

  /* ORPHAN GUARD. The chips come out of a Blade @foreach over $hfBands, which
     is four rows TODAY. Add a fifth band and it would sit half-width with a
     hole beside it; this spans it instead. Mirrors §30.2's spec-grid rule so
     the two surfaces fail the same way. (0,4,2) */
  body:not(.admin) .hf .hf__chips > .hf__chip:last-child:nth-child(odd){
    grid-column:1 / -1;
  }
}

/* --- the chip box ---------------------------------------------------------
   (0,3,1) beats §D's (0,2,1). --ab-r-field, NOT --ab-r-pill: this is the rule
   that kills the pill-soup. */
body:not(.admin) .hf .hf__chip{
  display:flex;
  flex-direction:column;             /* two-tier type with ZERO markup change */
  align-items:center;
  justify-content:center;
  gap:2px;
  min-block-size:var(--hf32-chip-h);
  padding-inline:10px;
  padding-block:0;
  border-radius:var(--ab-r-field,12px);
  /* Every chip colour is read through a --hf32-chip-* hook so the dark-context
     guard at the foot of 32.3 can repaint every STATE of the chip by setting
     inherited custom properties on one ancestor, instead of restating fifteen
     selectors one specificity step higher. Each fallback is the exact value
     this rule used before, and nothing on the homepage as shipped defines any
     of these properties, so every resolved value is unchanged. */
  border:1px solid var(--hf32-chip-line,var(--ab-line-2,rgba(17,17,17,.14)));
  background:var(--hf32-chip-bg,var(--ab-surface,#fff));
  /* The Blade emits `עד <bdi>1,200 ₪</bdi>` — a bare text node plus a <bdi>.
     In a column flex container the bare text node becomes an anonymous flex
     ITEM, so it can be typed independently of the <bdi> without touching the
     markup at all. This is the whole trick. */
  font-size:12px;
  font-weight:600;
  line-height:1.2;
  color:var(--hf32-chip-fg,var(--ab-ink-muted,#5b6577));   /* 5.9:1 on white */
  white-space:nowrap;                  /* kept from §D */
}

/* the number. 16px/800 ink = 18.9:1 on white. Bands 2 and 3 have no qualifier
   text node, so their <bdi> simply centres in the cell. */
body:not(.admin) .hf .hf__chip > bdi{
  font-size:16px;
  font-weight:800;
  line-height:1.1;
  letter-spacing:-.01em;
  color:var(--hf32-chip-num,var(--ab-ink,#111));
  font-variant-numeric:tabular-nums;
  font-feature-settings:"tnum" 1;
}

/* Restated at (0,4,1) because the base rule above is (0,3,1) and loads AFTER
   §D's (0,3,1) hover rule — without this, declaring background/border-color/
   color in the base would silently delete the hover state. mobile-boost §3
   exists because :hover LATCHES after a tap on this site, so the pointer
   guard is not optional. */
@media (hover:hover) and (pointer:fine){
  body:not(.admin) .hf .hf__chip:hover{
    border-color:var(--hf32-chip-hover-line,var(--ab-brand,#dc344c));
    background:var(--hf32-chip-hover-bg,var(--ab-brand-tint,rgba(220,52,76,.08)));
    color:var(--hf32-chip-fg,var(--ab-ink-muted,#5b6577));
  }
}

/* --- pressed --------------------------------------------------------------
   --ab-brand-strong (#c22740), NOT §D's --ab-brand (#dc344c). Measured:
     #fff on #dc344c = 4.53:1  — passes AA for normal text by 0.03
     #fff on #c22740 = 5.74:1
   The 12px qualifier word (עד / מעל) is now WHITE SMALL TEXT sitting on that
   fill, so 0.03 of headroom is not enough. On #c22740 the qualifier can also
   go to rgba(255,255,255,.88) — measured 4.75:1 — and still pass, which is
   what keeps the two-tier hierarchy legible in the selected state instead of
   flattening to solid white.
   Every alias §D wired stays: .is-active is the class home-filter.js ACTUALLY
   sets (verified, home-filter.js:549-552) alongside aria-pressed; .is-on is
   set too; .hf__chip--on / .active are Blade conveniences. (0,4,1) */
body:not(.admin) .hf .hf__chip[aria-pressed="true"],
body:not(.admin) .hf .hf__chip.is-active,
body:not(.admin) .hf .hf__chip.is-on,
body:not(.admin) .hf .hf__chip--on,
body:not(.admin) .hf .hf__chip.active{
  background:var(--hf32-chip-on-bg,var(--ab-brand-strong,#c22740));
  border-color:var(--hf32-chip-on-line,transparent);
  color:var(--hf32-chip-on-fg,rgba(255,255,255,.88));
  box-shadow:var(--ab-sh-brand,0 6px 16px rgba(220,52,76,.28));
}
body:not(.admin) .hf .hf__chip[aria-pressed="true"] > bdi,
body:not(.admin) .hf .hf__chip.is-active > bdi,
body:not(.admin) .hf .hf__chip.is-on > bdi,
body:not(.admin) .hf .hf__chip--on > bdi,
body:not(.admin) .hf .hf__chip.active > bdi{
  color:#fff;
}

/* SEPARATE RULE — :has() is unsupported in some engines and would invalidate
   the whole selector list if merged. Same reason §D splits it. */
body:not(.admin) .hf .hf__chip:has(input:checked){
  background:var(--hf32-chip-on-bg,var(--ab-brand-strong,#c22740));
  border-color:var(--hf32-chip-on-line,transparent);
  color:var(--hf32-chip-on-fg,rgba(255,255,255,.88));
  box-shadow:var(--ab-sh-brand,0 6px 16px rgba(220,52,76,.28));
}
body:not(.admin) .hf .hf__chip:has(input:checked) > bdi{ color:#fff; }

/* REDUNDANT NON-COLOUR CUE. Drawn as a BACKGROUND-IMAGE, never content:"✓":
   pseudo-element content is folded into the accessible name by some AT, which
   would make the button announce as "עד 1,200 ₪ ✓" — a state leaking into a
   name. A background image is never announced. The ::after box is fixed-size
   and absolutely positioned, so selecting a chip cannot reflow the grid.
   FULLY LOGICAL, NO [dir="ltr"] ESCAPE NEEDED OR PRESENT: the box is placed
   with `inset-inline-end`, so it lands in the LEFT corner under dir="rtl" and
   the right corner under dir="ltr" on its own, and the image's own
   background-position is `center`, which has no direction. (The select chevron
   in 32.4 is the one place in this section that does need an escape, and has
   one.) */
body:not(.admin) .hf .hf__chip[aria-pressed="true"]::after,
body:not(.admin) .hf .hf__chip.is-active::after,
body:not(.admin) .hf .hf__chip.is-on::after,
body:not(.admin) .hf .hf__chip.active::after{
  content:"";
  position:absolute;
  inset-block-start:7px;
  inset-inline-end:8px;
  inline-size:12px;
  block-size:12px;
  background:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M2.2 6.3 4.8 8.9 9.8 3.4' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / 12px 12px no-repeat;
  pointer-events:none;
}

/* pressed hover / press. Restated at (0,5,1) for exactly the same cascade
   reason as the plain hover above: the (0,4,1) pressed rule loads after §D's
   own (0,4,1) hover and :active rules and would otherwise erase them. */
@media (hover:hover) and (pointer:fine){
  body:not(.admin) .hf .hf__chip[aria-pressed="true"]:hover,
  body:not(.admin) .hf .hf__chip.is-active:hover,
  body:not(.admin) .hf .hf__chip.is-on:hover,
  body:not(.admin) .hf .hf__chip.active:hover{
    background:var(--hf32-chip-on-bg,var(--ab-brand-strong,#c22740));
    color:var(--hf32-chip-on-fg,rgba(255,255,255,.88));
  }
}
body:not(.admin) .hf .hf__chip[aria-pressed="true"]:active,
body:not(.admin) .hf .hf__chip.is-active:active,
body:not(.admin) .hf .hf__chip.is-on:active,
body:not(.admin) .hf .hf__chip.active:active{
  background:var(--ab-brand-press,#a81f34);
}

/* THE RING MUST SURVIVE. §D's white-outline + ink-halo override for a filled
   chip is (0,4,1) — the SAME specificity as this section's pressed rule, and
   this section loads later, so §D's box-shadow would lose and the ring would
   vanish on a brand fill. Restated here at (0,5,1). Do not delete. */
body:not(.admin) .hf .hf__chip[aria-pressed="true"]:focus-visible,
body:not(.admin) .hf .hf__chip.is-active:focus-visible,
body:not(.admin) .hf .hf__chip.is-on:focus-visible,
body:not(.admin) .hf .hf__chip.active:focus-visible{
  outline-color:#fff;
  box-shadow:0 0 0 5px var(--ab-ink,#111);
}

/* Very narrow phones. §D has `@media (max-width:360px){.hf__chip{
   padding-inline:13px; font-size:14.5px}}` at (0,2,1); the base rule above is
   (0,3,1) and later, so it would override that guard at EVERY width. Restated.
   Measured at 320px: cell = (296 - 8)/2 = 144px, interior = 122px; the widest
   band "1,200–1,600 ₪" sets at ~94px at 15px tabular. Fits with 28px spare. */
@media (max-width:359.98px){
  body:not(.admin) .hf .hf__chip{ padding-inline:8px; font-size:11.5px; }
  body:not(.admin) .hf .hf__chip > bdi{ font-size:15px; }
}

/* --- DARK-CONTEXT GUARD ---------------------------------------------------
   MATCHES NOTHING ON THE HOMEPAGE AS SHIPPED. <section class="hf"> is a
   SIBLING of <section class="banner-single"> in home.blade.php (verified), so
   none of these three selectors has an element to hit today. It is here
   because §B and §K both ship rules for a .hf rendered INSIDE the hero
   (`.banner-single .hf`, `.banner-content .hf`) and for `.hf--hero` on the
   section itself, i.e. those are supported markup shapes — and in either of
   them §D's dark chip block, written `body:not(.admin) .banner-single
   .hf__chip` at (0,3,1), TIES this section's `body:not(.admin) .hf .hf__chip`
   at (0,3,1) and loses on load order. The chips would go white-on-white over
   a dark photo, in every state, with nothing reporting an error.

   Setting the inherited --hf32-chip-* properties on the ancestor repaints the
   base, hover, pressed and :has(input:checked) rules at once without restating
   any of them, so it cannot drift out of sync the way a parallel selector wall
   would. Specificity is irrelevant here: no other rule in any sheet declares
   these properties, so there is nothing to beat.
   VALUES ARE §D's, unchanged — same dark tokens, same brand fill for the
   selected state, same white border on it, so the hero keeps ONE selected-state
   vocabulary with the panel. The 12px qualifier goes to solid #fff rather than
   the .88 it takes on white ground, because §D's dark fill is --ab-brand
   (#dc344c) and small white text at 88% opacity does not clear 4.5:1 on it. */
body:not(.admin) .banner-single .hf,
body:not(.admin) .banner-content .hf,
body:not(.admin) .hf.hf--hero{
  --hf32-chip-bg:var(--hf-on-dark,rgba(255,255,255,.13));
  --hf32-chip-line:var(--hf-on-dark-line,rgba(255,255,255,.34));
  --hf32-chip-fg:#fff;
  --hf32-chip-num:#fff;
  --hf32-chip-hover-bg:rgba(255,255,255,.22);
  --hf32-chip-hover-line:rgba(255,255,255,.55);
  --hf32-chip-on-bg:var(--ab-brand,#dc344c);
  --hf32-chip-on-line:#fff;
  --hf32-chip-on-fg:#fff;
}


/* ==========================================================================
   32.4  TIER 2 — THE ONE RECESSED PANEL
   --------------------------------------------------------------------------
   A THREE-STEP GROUND LADDER, and each step has to be legible against its
   neighbour:  white section  →  #f1f2f5 panel  →  white fields.
   This is why the panel takes --ab-surface-3 and not --ab-surface-2 (#f9f9f9):
   a white field on #f9f9f9 is a ~1.04:1 edge, i.e. invisible. The card runs
   the identical ladder — white card → #f1f2f5 spec panel — which is what makes
   the two surfaces read as one system rather than two redesigns.
   ========================================================================== */

/* (0,3,1) beats §C's max-width `.hf__row--fields` (0,2,1). display:grid is
   restated rather than inherited because at >=992px §C's grid never applied. */
body:not(.admin) .hf .hf__row--fields{
  display:grid;
  grid-template-columns:repeat(2,minmax(0,1fr));
  gap:var(--hf32-panel-gap);
  align-items:start;
  background:var(--ab-surface-3,#f1f2f5);
  border:1px solid var(--ab-line,rgba(17,17,17,.08));
  border-radius:var(--ab-r-card,14px);
  padding:var(--hf32-panel-pad);
}

/* Placement. DOM order after the one blade edit is brand, year, km, search,
   sort — and VISUAL order matches it exactly, so there is no `order` property
   on anything focusable and no focus-order cost.
       brand            (full)
       year   |   km    (half + half)
       search           (full)
       sort             (full)
   :first-child is POSITIONAL. If .hf__row--fields is ever reordered in the
   blade, this moves with it. (0,4,2) beats §C's own (0,3,2) pair. */
body:not(.admin) .hf .hf__row--fields > .hf__field:first-child,
body:not(.admin) .hf .hf__row--fields > .hf__field--search,
body:not(.admin) .hf .hf__row--fields > .hf__field--sort{
  grid-column:1 / -1;
}

/* --- the field: label INSIDE, value bold ---------------------------------
   Today: 13px BOLD grey label, plain 16px value. That is backwards — it makes
   six labels the loudest thing in the panel, which is precisely the "so much
   text" the user is reacting to. Inverted here: 11px caption, 16px/700 ink
   value. Same information, opposite emphasis.
   (0,3,1) beats §C's `.hf__field` (0,2,1) and §K's `.hf__field{flex:0 1 auto}`
   (0,2,1). */
body:not(.admin) .hf .hf__field{
  position:relative;
  display:flex;
  flex-direction:column;
  align-items:stretch;
  gap:0;
  min-inline-size:0;
  background:var(--ab-surface,#fff);
  border:1px solid var(--ab-line-2,rgba(17,17,17,.14));
  border-radius:var(--ab-r-field,12px);
  padding:var(--hf32-field-pad-bs) 10px var(--hf32-field-pad-be);
  transition:border-color var(--ab-d2,180ms) var(--ab-ease,ease),
             box-shadow var(--ab-d2,180ms) var(--ab-ease,ease);
}

/* BELT AND BRACES, NEVER INSTEAD OF. §E's `:focus-visible{outline:3px solid
   var(--ab-ink); outline-offset:2px}` on the control is deliberately NOT
   suppressed — it draws inside the wrapper's 10px inline padding and is still
   fully visible. This only adds a second, larger cue so a focused compartment
   is obvious in a panel of five identical white boxes. No ring is ever lost. */
body:not(.admin) .hf .hf__field:focus-within{
  border-color:var(--ab-brand,#dc344c);
  box-shadow:0 0 0 3px var(--ab-brand-tint-2,rgba(220,52,76,.16));
}

/* (0,4,1) beats §B's `.hf__label` (0,2,1). 11px/700 muted on white = 5.9:1;
   uppercase-ish tracking is not used — Hebrew has no case and letter-spacing
   on Hebrew hurts legibility, so only .3px is applied. */
body:not(.admin) .hf .hf__field > .hf__label{
  display:block;
  font-size:11px;
  font-weight:700;
  letter-spacing:.3px;
  line-height:1.2;
  color:var(--ab-ink-muted,#5b6577);
  margin:0;
  padding-inline-start:0;
  pointer-events:auto;               /* it carries for="…" — keep it clickable,
                                        it is part of the 47.2px target */
}

/* --- the controls, borderless inside the field ---------------------------
   SPECIFICITY NOTE, load-bearing: §E declares the box TWICE — once as
   `body:not(.admin) .hf select` (0,2,1) and once as
   `body:not(.admin) #hfMake` (1,1,1). A class-only selector, however deep,
   can never beat that ID group. So this rule is written against the SAME five
   ids at (1,2,1). No !important is needed anywhere in this section because of
   it. */
body:not(.admin) .hf #hfMake,
body:not(.admin) .hf #hfYear,
body:not(.admin) .hf #hfKm,
body:not(.admin) .hf #hfQ,
body:not(.admin) .hf #hfSort{
  min-block-size:var(--hf32-ctrl-h);
  border:0;
  border-radius:0;
  background-color:transparent;
  box-shadow:none;                   /* also kills §E's `:focus{box-shadow:0 0
                                        0 3px tint}` inner glow — the wrapper
                                        carries that cue now */
  padding-block:0;
  padding-inline:0;
  /* 16px EXACTLY, inherited intent from §E: anything smaller and iOS Safari
     zooms the viewport the instant the field takes focus. Do not "tidy" this
     to 15px to make a label fit. */
  font-size:16px;
  font-weight:700;
  line-height:1.2;
  color:var(--ab-ink,#111);          /* 18.9:1 on white */
  inline-size:100%;
  max-inline-size:100%;
  min-inline-size:0;
}

/* the chevron, restated because the field is now borderless and the menu
   affordance has to come from somewhere. §E puts it at `left 14px center`
   with 38px of padding — both are wrong inside a 10px-padded wrapper.
   PHYSICAL (a): RTL puts the chevron at the inline-END = the LEFT edge.
   Data URI only; percent-encoded (# → %23) so every parser survives it.
   No network request. (1,2,1) beats §E's `.hf select` (0,2,1). */
body:not(.admin) .hf #hfMake,
body:not(.admin) .hf #hfYear,
body:not(.admin) .hf #hfKm,
body:not(.admin) .hf #hfSort{
  padding-inline-start:0;
  padding-inline-end:16px;
  text-overflow:ellipsis;            /* kept from §E: the native picker still
                                        shows the full option text */
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.6 6 6.4l5-4.8' fill='none' stroke='%235b6577' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat:no-repeat;
  background-size:10px 7px;
  background-position:left 0 center;   /* RTL: inline-end */
}
[dir="ltr"] body:not(.admin) .hf #hfMake,
[dir="ltr"] body:not(.admin) .hf #hfYear,
[dir="ltr"] body:not(.admin) .hf #hfKm,
[dir="ltr"] body:not(.admin) .hf #hfSort{
  background-position:right 0 center;  /* LTR escape for (a) */
}

/* The search input keeps §E's native clear button (still a real 22px target)
   but loses the box. Placeholder stays 500 weight / muted so it can never be
   mistaken for a chosen value. */
body:not(.admin) .hf #hfQ{
  padding-inline:0;
}


/* ==========================================================================
   32.5  TIER 3 — THE ACTION
   --------------------------------------------------------------------------
   Today submit and reset are 50/50 siblings: a rank-2 control and a rank-7
   control wearing identical clothing. That is the single clearest ranking
   error in the old panel and it is what makes the bottom of the form read as
   "two equally plausible things to press".
   ========================================================================== */

@media (max-width:991.98px){
  /* (0,4,1) beats §E's `.hf__bar button[type=submit]` (0,3,2) — four classes
     outrank three regardless of element count — and §C's `.hf__submit{flex:1 1
     calc(50% - gap)}` (0,2,1). */
  body:not(.admin) .hf .hf__row--actions .hf__submit{
    flex:1 1 100%;
    min-block-size:54px;
  }
  /* (1,2,1) beats §C's `#hfReset{flex:1 1 calc(50% - gap)}` (1,1,1).
     Height is NOT set here — the base rule in this section owns it, so the
     touch surface can never end up with a smaller target than the pointer
     surface. That is exactly what an earlier draft did: 40px here, 44px in
     32.6. */
  body:not(.admin) .hf #hfReset{
    flex:1 1 100%;
  }
  body:not(.admin) .hf .hf__row--actions{
    flex-direction:column;
    align-items:stretch;
    gap:6px;
  }
}

/* SUBMIT. Keeps red — it is one of the two places red is spent on this
   surface. 12px radius, not the pill: --ab-r-pill is eliminated here.
   CONTRAST, stated exactly: #fff on --ab-brand #dc344c is 4.53:1. That passes
   WCAG AA for normal text (4.5:1) by 0.03. It is kept rather than darkened
   because --ab-brand is the CTA fill on every .theme-btn sitewide, including
   the car card's "לצפייה ברכב", and a filter button in a different red would
   read as a different KIND of button. The pressed chip, which puts 12px white
   text on a fill, takes --ab-brand-strong instead precisely because 0.03 of
   headroom is not enough at that size. (0,4,1).

   NO BORDER — and that is a decision, not an omission. §E ships this button
   with `border:0`, and style.css:462 gives EVERY .theme-btn a 300px #111
   circle in ::before at z-index:-1 that scales to 1 on :hover. The button's
   own `z-index:1` makes it a stacking context, so that circle paints ABOVE the
   button's background but is clipped by `overflow:hidden` to the PADDING box —
   which means it covers the fill and leaves any border showing around it. An
   earlier draft added `border:1px solid var(--ab-brand)` here, which turned the
   hovered button into black-with-a-red-hairline instead of the solid black
   every other .theme-btn on the site goes to. Keeping §E's border:0 means the
   circle is clipped to the full 12px-rounded rect and hover looks the same
   here as it does on the car card's CTA. */
body:not(.admin) .hf .hf__row--actions .hf__submit{
  border-radius:var(--ab-r-field,12px);
  background:var(--ab-brand,#dc344c);
  color:#fff;
  font-size:17px;
  font-weight:800;
  padding-inline:20px;
  box-shadow:var(--ab-sh-brand,0 6px 16px rgba(220,52,76,.28));
}

/* mobile-boost.css:256 gives `.theme-btn:active{background:var(--ab-brand-press)}`
   at (0,3,1). The rule above is (0,4,1) — four classes beat three — so without
   this restatement the press feedback on the primary CTA would silently die.
   This one is NOT dead the way a :hover background would be: mobile-boost §3
   zeroes `.theme-btn:hover::before` under `(hover:none),(pointer:coarse)`, so
   on the touch surface where :active is the only feedback there is no black
   circle over the fill and --ab-brand-press is what the finger sees. */
body:not(.admin) .hf .hf__row--actions .hf__submit:active{
  background:var(--ab-brand-press,#a81f34);
}
/* NO :hover RULE. On (hover:hover) and (pointer:fine) — the only place
   style.css's ::before circle is allowed to run — that circle covers the whole
   padding box with #111, so a `background` declared here would never be seen.
   An earlier draft declared --ab-brand-strong on hover; it painted nothing.
   The hover state of this button is the sitewide black ink-fill, deliberately,
   because it is the same .theme-btn the car card CTA is. */
/* SAME TRAP AS THE CHIP RING. mobile-boost.css:184 gives
   `.theme-btn:focus-visible{outline-color:#fff; box-shadow:0 0 0 5px var(--ab-ink)}`
   at (0,2,2); the (0,4,1) rule above sets box-shadow and would erase it.
   Restated at (0,5,1). Do not delete. */
body:not(.admin) .hf .hf__row--actions .hf__submit:focus-visible{
  outline-color:#fff;
  box-shadow:0 0 0 5px var(--ab-ink,#111);
}

/* RESET, demoted from a 50%-width button to what it actually is: an undo
   link. 13px/600 --ab-ink-muted on white = 5.9:1, underlined so it reads as a
   link without needing colour to say so. (1,2,1) beats §E's (1,1,1).
   44px, AT EVERY WIDTH. This is the approved direction's stated height and it
   is declared once, unmediated, so the touch surface and the pointer surface
   get the same target — an earlier draft shipped 40px on phones and 44px on
   desktop, i.e. the smaller hit area on the finger. It is still 4px under the
   project's --ab-tap:48px token; that is a declared deviation, see trade-off 9
   at the foot of this file. */
body:not(.admin) .hf #hfReset{
  min-block-size:44px;
  align-self:center;
  inline-size:auto;
  min-inline-size:var(--ab-tap,48px);
  padding-inline:8px;
  border:0;
  border-radius:6px;                 /* matches the global focus-ring radius */
  background:none;
  box-shadow:none;
  font-size:13px;
  font-weight:600;
  color:var(--ab-ink-muted,#5b6577);
  text-decoration:underline;
  text-underline-offset:3px;
  text-decoration-thickness:1px;
}
/* §E's hover paints a #f1f2f5 chip behind it — that is button clothing again.
   (1,2,2) beats §E's (1,1,2). */
@media (hover:hover) and (pointer:fine){
  body:not(.admin) .hf #hfReset:hover{
    background:none;
    color:var(--ab-ink,#111);
  }
}
body:not(.admin) .hf #hfReset:active{
  background:none;
  color:var(--ab-ink,#111);
}


/* ==========================================================================
   32.6  >=992px — TWO-TIER TOOLBAR
   --------------------------------------------------------------------------
   §K lays the desktop bar out as four stacked rows inside a white card, with
   the count stranded at the bottom. The same ladder applies here, folded onto
   THREE bands that are the three tiers themselves:

     BAND 1   [ count │ legend + hint │ the four bands, equal width ]
     BAND 2   [ the recessed refinement panel, full width ]
     BAND 3   [ ......................... submit ][ reset ]

   Band 1 is the real saving: the count, the question and all four budget
   chips now occupy ONE 61px line where §K spent two rows on them and put the
   count 150px lower.

   Mechanism: .hf__bar becomes a WRAPPING FLEX ROW and .hf__count takes
   order:-2 so it leads band 1. Nothing here reorders a focusable element —
   .hf__count holds no control, and the three .hf__row containers keep DOM
   order among themselves.

   MEASURED, xl container (1140px, 24px inline padding from §K → 1092px
   interior), verified in a browser at 1280px:
     band 1  count 134px (frozen — see WIDTH RECOVERY 1) + 12 gap
             + budget row 946px
             budget row = 160px legend column + 16 + 770px of chips
             → four 186.5px cells, one row, no scroller, no re-flow
     band 2  panel 1090px; interior 1090 - 2 - 20 = 1068px; five tracks less
             4x8px of gaps = 1036px at 1.5/1.2/1.4/1.6/1.4fr:
               brand 194px → 156px of text  (widest option 101px)
               year  156px → 118px          (widest "2026 ומעלה" 88px)
               km    181px → 143px          (widest "עד 100,000 ק״מ" 117px)
               search 207px → 185px         (placeholder 175px)
               sort  181px → 143px          (widest "שנה — חדש לישן" 124px)
     band 3  submit 180px + 10 + reset ~68px, pushed to the inline-end
   At the lg container — 960px, i.e. EVERY width from 992px to 1199.98px, which
   is the band that has to be sized for — the bar interior is 910px:
     band 1  count 134 + 12 + budget row 764
             budget row = 160 legend + 16 + 588px of chips
             → four 141px cells, 119px of chip interior against a 110.6px
               widest <bdi>. 8.4px of slack, and it does not move when the
               count string changes.
     band 2  the five tracks fall to 850px and every one still clears its
             widest option; only the search PLACEHOLDER loses ~6px, which
             clips a hint, not a value.
   ========================================================================== */

@media (min-width:992px){

  /* §K leaves .hf__bar at the base `flex-direction:column`. (0,3,1). */
  body:not(.admin) .hf .hf__bar{
    flex-direction:row;
    flex-wrap:wrap;
    align-items:flex-start;
    gap:12px;
  }

  /* WIDTH RECOVERY 1 of 2, and the one that also removes a layout shift.
     .hf__count is flex:0 0 auto around a white-space:nowrap span, so band 1
     re-flows on EVERY completed request as the string goes
     "148 רכבים" (92.61px) → "רכב אחד" → "לא נמצאו רכבים" (133.33px), and the
     four chips resize under it each time. min-inline-size freezes the column
     at the widest string this counter can ever hold — home-filter.js:462 emits
     exactly three shapes and 'לא נמצאו רכבים' is the longest of them — so the
     chips are one fixed width for the life of the page.
     It is a FLOOR, not a width: an unexpectedly long string still grows the
     column rather than clipping, and there is ~36px of headroom before the
     widest chip label would run out of room, so the failure mode is soft. */
  body:not(.admin) .hf .hf__count{
    order:-2;
    flex:0 0 auto;
    align-self:center;
    margin:0;
    padding-block:0;
    padding-inline-end:16px;
    min-inline-size:134px;
    border-block-end:0;                                  /* the mobile hairline */
    border-inline-end:1px solid var(--ab-line,rgba(17,17,17,.08));
  }
  /* (1,2,1) beats §K's `#hfCount{font-size:15px}` (1,1,1). */
  body:not(.admin) .hf #hfCount{ font-size:16px; }

  /* legend + hint stack in a fixed 160px column, chips take the rest.
     WIDTH RECOVERY 2 of 2. 160px is a measured floor, not a guess:
     "תשלום חודשי" at 19px/800 sets at ~120px on one line, and the 44-char hint
     sets in two lines inside 160px — line 1 "בחרו טווח תשלום חודשי" ~130px,
     line 2 "ונציג רק רכבים שמתאימים" ~143px — exactly as it did in the 190px
     column an earlier draft used, so the 30px comes back for free: the column
     is still ~61px tall against the chips' 52px and band 1 does not grow.
     What it buys is the whole margin in the tight band. At the lg container,
     with the count frozen at its 134px worst case, the chips column is
     764 - 160 - 16 = 588px → four 141px cells → 119px of chip interior against
     the widest <bdi> "1,200–1,600 ₪" at 110.6px: 8.4px of slack. On the 190px
     column the same cells were 133.7px wide with 1.4px of slack, which is
     inside font-metric noise and not shippable. */
  /* flex-basis 620px is a WRAP FENCE, not a width — flex-grow:1 always pushes
     the row past it. Its real constraint is an UPPER bound: count (134px,
     frozen) + 12px gap + this basis has to fit the NARROWEST bar interior,
     910px at the lg container, or the budget row drops onto a line of its own
     and band 1 stops being one line. 134 + 12 + 620 = 766, so there is 144px
     of headroom at the tightest width.
     It is NOT what keeps .hf__row--fields off line 1 — an earlier draft of
     this comment said it was, and cited a "560px basis" the panel does not
     have. The panel is `flex:1 1 100%` below, and a 100% basis can never share
     a flex line with anything that precedes it, at any viewport. */
  body:not(.admin) .hf .hf__row--budget{
    order:-1;
    flex:1 1 620px;
    display:grid;
    grid-template-columns:minmax(0,160px) minmax(0,1fr);
    grid-template-rows:auto auto;
    column-gap:16px;
    row-gap:2px;
    align-items:center;
  }
  body:not(.admin) .hf .hf__legend{ grid-column:1; grid-row:1; align-self:end; margin:0; }
  body:not(.admin) .hf .hf__hint  { grid-column:1; grid-row:2; align-self:start; margin:0; }
  /* FOUR EXPLICIT TRACKS, NOT A WRAPPING FLEX LINE.
     An earlier draft used `display:flex; flex-wrap:wrap` with
     `.hf__chip{flex:1 1 140px}` and a comment promising the chips would "fall
     to 2x2 rather than overflowing". They did not: four 140px bases plus three
     8px gaps need 584px, and across the WHOLE 992–1199.98px band the Bootstrap
     container is 960px → 910px of bar interior, so the chips column is only
     599.39px with the default count string. That is 15.39px of slack, and
     home-filter.js:462 spends it the moment a search returns nothing —
     `(n === 0) ? 'לא נמצאו רכבים'` is the longest string this counter can hold
     and it widens .hf__count from 92.61px to 133.33px (it is flex:0 0 auto and
     #hfCount is white-space:nowrap, so the <p> tracks its text exactly). The
     chips column falls to 558.67px, the line breaks 3+1, and the fourth chip
     grows to 558.67px against its siblings' 180.89px — the rank-1 control
     deforming in precisely the state where the user has to re-tap it, and .hf
     growing 51.25px so the whole catalogue jumps down the page. Reproduced in
     the real cascade at 1024px — 92.61 → 133.33px count, 599.39 → 558.67px
     chips, 3x180.89 + 1x558.67, hf 299.94 → 351.19px — and the bar interior
     measures 910px at 992px AND at 1199px, because the Bootstrap .container is
     960px across the entire band, so every width in it fails identically. Only
     at 1200px (container 1140px) did the flex version survive.
     An explicit four-track grid cannot break a line at all, so the layout no
     longer depends on how many characters the server or the script puts in the
     counter. Two width recoveries below keep the cells comfortable rather than
     merely unbroken. */
  body:not(.admin) .hf .hf__chips {
    grid-column:2;
    grid-row:1 / span 2;
    display:grid;
    grid-template-columns:repeat(4,minmax(0,1fr));
    gap:8px;
    margin-inline:0;
    padding-inline:0;
    padding-block:0;
    overflow:visible;
    scroll-snap-type:none;
  }
  /* `flex` is inert on a grid item; it is zeroed so nothing reads as live.
     min-inline-size:0 is NOT inert — without it a nowrap chip would refuse to
     shrink below its min-content size and push the tracks out of the row. */
  body:not(.admin) .hf .hf__chips > .hf__chip{
    flex:none;
    min-inline-size:0;
  }
  /* NO ORPHAN GUARD IS PORTED HERE, deliberately. 32.3's mobile rule spans a
     lone fifth chip because on a TWO-track grid it would otherwise sit at half
     width with a hole beside it. On four tracks the fixed grid is already the
     guard: a fifth band emitted by the Blade @foreach lands in row 2 at the
     same 141px as its siblings. Spanning it would make it 4x wider than every
     other chip — i.e. it would reintroduce by hand the exact deformation the
     grid was installed to remove. */
  body:not(.admin) .hf .hf__chip{ min-block-size:var(--hf32-chip-h); }

  /* the refinement panel, one line of five, ALWAYS the full width of the bar.
     WHY IT DOES NOT SHARE A LINE WITH THE ACTIONS: measured. Sharing line 2
     with a 180px submit leaves the panel 820px, i.e. 776px of track, against
     778.5px of combined minimum content — brand 139.1 + year 125.7 + km 155
     + search 197 + sort 161.7. It misses by 2.5px, which is not a margin any
     fr tuning can be trusted to hold across fonts and zoom levels; the first
     casualty in testing was #hfYear ("2026 ומעלה" needs 87.7px and had 71px).
     Full width instead gives 1030px of track at the xl container and 850px at
     lg, so every closed select reads its value with 30-80px of slack. The cost
     is one more band on desktop — which is the ladder anyway: question,
     refinements, action. */
  body:not(.admin) .hf .hf__row--fields{
    flex:1 1 100%;
    grid-template-columns:1.5fr 1.2fr 1.4fr 1.6fr 1.4fr;
    gap:8px;
    padding:10px;
    align-items:stretch;
  }
  /* the mobile full-width spans must NOT survive into the one-line grid.
     (0,4,2), matching the mobile rule they cancel. */
  body:not(.admin) .hf .hf__row--fields > .hf__field:first-child,
  body:not(.admin) .hf .hf__row--fields > .hf__field--search,
  body:not(.admin) .hf .hf__row--fields > .hf__field--sort{
    grid-column:auto;
  }
  /* §E pins desktop floors on these ids — `#hfMake{min-inline-size:150px}` etc.
     (1,1,1). Inside a fr-track grid a floor like that becomes the item's
     min-content contribution and blows the track out, so it is released here
     at (1,2,1); the fr fractions above own the widths now. */
  body:not(.admin) .hf #hfMake,
  body:not(.admin) .hf #hfYear,
  body:not(.admin) .hf #hfKm,
  body:not(.admin) .hf #hfSort,
  body:not(.admin) .hf #hfQ{ min-inline-size:0; }

  body:not(.admin) .hf .hf__row--actions{
    flex:1 1 100%;
    flex-direction:row;
    flex-wrap:nowrap;
    align-items:center;
    justify-content:flex-end;        /* LOGICAL: flex-end is the inline-end,
                                        i.e. the LEFT edge under dir="rtl" */
    gap:10px;
  }
  /* §K pushes the submit with `margin-inline-start:auto` because the sort
     field used to be the first child of this row. After the blade edit the
     row is [submit][reset] only and the auto margin has no job. (0,4,1). */
  body:not(.admin) .hf .hf__row--actions .hf__submit{
    margin-inline-start:0;
    flex:0 0 auto;
    min-inline-size:180px;
    min-block-size:52px;
    font-size:16px;
  }
  /* height is the base rule's 44px, unchanged — see the note there. */
  body:not(.admin) .hf #hfReset{
    flex:0 0 auto;
  }
}



/* ==========================================================================
   32.7  REDUCED MOTION · FORCED COLOURS
   --------------------------------------------------------------------------
   §L already zeroes the transitions this surface had. It is NOT enough on its
   own any more: this section adds one @keyframes and one new transition, and
   §L loads BEFORE it.
   mobile-boost §4 sets `animation-duration:.01ms !important` globally, which
   is not the same as stopping an animation — a 0.01ms animation still
   schedules a frame and still fires animationend. These remove it outright,
   the same reasoning §L states for its own block.
   ========================================================================== */

@media (prefers-reduced-motion:reduce){
  body:not(.admin) .hf:not(.is-loading) #hfCount{ animation:none; }
  body:not(.admin) .hf .hf__field{ transition:none; }
  /* §L's `.hf__chip{transition:none}` and `.hf__chip:active{transform:none}`
     are (0,2,1)/(0,3,1) and still stand — this section deliberately declares
     NEITHER transition nor transform on .hf__chip, so §L is left intact. */
}

/* Windows High Contrast drops every brand fill, every rgba hairline and every
   background-image we rely on. §L covers the chips it knew about; the panel,
   the field boxes and the tick are new and need their own re-expression. */
@media (forced-colors:active){

  body:not(.admin) .hf .hf__row--fields{
    background:Canvas;
    border:1px solid CanvasText;
  }
  body:not(.admin) .hf .hf__field{
    background:Canvas;
    border:1px solid CanvasText;
  }
  body:not(.admin) .hf .hf__field:focus-within{
    outline:2px solid Highlight;
    outline-offset:1px;
  }
  body:not(.admin) .hf .hf__count{ border-block-end-color:CanvasText; }

  /* §L already maps the pressed chip to Highlight/HighlightText. Add a SHAPE
     difference on top so selection never depends on colour alone: a 2px
     border, plus a tick redrawn from BORDERS instead of the SVG background
     (background-image is unreliable in HCM — a white-stroked glyph on a light
     Canvas simply disappears). Borders keep their forced colour, so this one
     is always visible. Still not announced by AT: it is a ::after box with an
     empty content string, never a text glyph. */
  body:not(.admin) .hf .hf__chip[aria-pressed="true"],
  body:not(.admin) .hf .hf__chip.is-active,
  body:not(.admin) .hf .hf__chip.is-on,
  body:not(.admin) .hf .hf__chip.active{
    border:2px solid CanvasText;
    forced-color-adjust:none;
    background:Highlight;
    color:HighlightText;
  }
  body:not(.admin) .hf .hf__chip[aria-pressed="true"] > bdi,
  body:not(.admin) .hf .hf__chip.is-active > bdi,
  body:not(.admin) .hf .hf__chip.is-on > bdi,
  body:not(.admin) .hf .hf__chip.active > bdi{ color:HighlightText; }

  body:not(.admin) .hf .hf__chip[aria-pressed="true"]::after,
  body:not(.admin) .hf .hf__chip.is-active::after,
  body:not(.admin) .hf .hf__chip.is-on::after,
  body:not(.admin) .hf .hf__chip.active::after{
    background:none;
    inline-size:6px;
    block-size:10px;
    border-inline-end:2px solid HighlightText;
    border-block-end:2px solid HighlightText;
    transform:rotate(45deg);
    inset-block-start:5px;
  }

  body:not(.admin) .hf .hf__row--actions .hf__submit{
    border:2px solid ButtonText;
    background:ButtonFace;
    color:ButtonText;
  }
  body:not(.admin) .hf #hfReset{
    border:0;
    color:LinkText;
    text-decoration:underline;
  }
}


/* ==========================================================================
   §32 — KNOWN TRADE-OFFS
   --------------------------------------------------------------------------
   1. HEIGHT. Measured 651px at 375px against the old ~479px, and 284px on
      desktop. Accounted for in the header comment; the whole increase is tier 1
      (all four bands visible, a real count headline, a human hint) plus reset
      leaving submit's shoulder. If it ever has to come back, the cheapest ~40px
      is putting #hfReset back inline at the inline-end of the actions row — it
      keeps the demotion (13px text link, not a 50% button) and only loses the
      line break. The next ~27px after that is the hint, which is the single
      most direct answer to "no life here", so cut it last.

   2. THE TAP TARGET IS 47.2px, NOT 48px. label (11px x 1.2 = 13.2) + control
      (34px). Both are inside the <label for="…"> / control pair, so the whole
      47.2px activates the control. It is 0.8px under the --ab-tap token and
      23px over WCAG 2.5.8 AA (24px). Raising --hf32-ctrl-h to 35px closes it
      and costs 4px of panel height; it was not taken because 34px keeps the
      16px value's line box comfortably centred on every engine tested by eye
      and 0.8px is not a real-world miss.

   3. BORDERLESS SELECTS LEAN HARDER ON appearance:none. §E already sets it,
      but some Android WebViews (notably older Samsung Internet builds) still
      paint a native arrow. Inside a bordered box that arrow used to hide; here
      it would sit next to the data-URI chevron. Worth one real-device check.
      If it shows up, the fix is a `background-image:none` + native-arrow
      acceptance branch, not a bigger hammer.

   4. THE PANEL'S PLACEMENT RULES ARE POSITIONAL. `.hf__field:first-child` is
      the brand field only because the blade orders it first, exactly as §C's
      original rule was. Both this and the km/sort track fractions in 32.6 move
      if .hf__row--fields is ever reordered.

   5. THE KM SELECT IS THE TIGHT ONE. Its widest option is "עד 100,000 ק״מ" —
      117px measured, not "כל הקילומטראז׳" as it looks. It has 123px at 375px
      (6px of slack), 131px at the lg container and 166px at xl, so it is clean
      on every tested width EXCEPT 320px, where it gets 95px and ellipsises.
      §E's text-overflow:ellipsis catches that and the native picker still shows
      the full option text, so nothing is unreachable; it is a cosmetic clip
      below roughly 369px. The other four-way tight spot is the SEARCH
      PLACEHOLDER at the lg container (171px against 175px) — that clips a hint,
      never a value.

   8. NOT VERIFIED BY RENDER: prefers-reduced-motion and forced-colors. Both
      blocks were confirmed to PARSE (10 media blocks, 2 and 9 rules) and every
      selector in them was confirmed to match live elements, but the harness
      could not emulate either media feature, so the painted result is
      reasoned, not seen. They are also the two blocks whose failure mode is
      degradation, not breakage.

   6. #hfCount MOVES VISUALLY BUT NOT IN THE DOM. If a future edit ever puts a
      focusable element inside p.hf__count, the order:-1 in 32.2 becomes a
      WCAG 2.4.3 violation and must be removed at the same time.

   7. THE CHIP TICK IS A BACKGROUND IMAGE ON PURPOSE. Anyone "simplifying" it
      to content:"✓" will fold the selected state into the button's accessible
      name. It is drawn twice — SVG data URI normally, border triangle under
      forced-colors — because neither technique survives both environments.
      It is also placed with logical properties only and needs no [dir="ltr"]
      rule; see the RTL note in the header before adding one.

   9. #hfReset IS 44px TALL, 4px UNDER THE --ab-tap:48px TOKEN. This is a
      declared deviation, not a slip. It is the height the approved direction
      specifies for the demoted reset, it meets WCAG 2.5.5 AAA (44px) and
      clears 2.5.8 AA (24px) with 20px to spare, and it is now the SAME on
      touch and on pointer — the file previously shipped 40px on phones and
      44px on desktop, i.e. the smaller target on the finger, which was the
      real defect. Nothing about the link is width-constrained
      (inline-size:auto, min-inline-size:--ab-tap, padding-inline:8px) and it
      sits alone on its own line under the submit, so there is nothing adjacent
      to mis-tap. Raising it to 48px costs 4px of form height and is the
      obvious change if the token is ever made a hard rule.

  10. THE DESKTOP BUDGET ROW IS A FIXED FOUR-TRACK GRID, NOT A FLEX LINE, and
      .hf__count carries a min-inline-size to freeze band 1 (both in 32.6).
      Together they mean the rank-1 control's geometry no longer depends on how
      many characters home-filter.js writes into the counter. The cost is that
      the four chips are sized for the LONGEST count string at all times, so
      they are ~10px narrower than they could be while "148 רכבים" is showing;
      the gain is that they never resize, never break a line, and never grow a
      chip to 4x its siblings' width. The whole 992–1199.98px band is the
      binding case (960px container) and it holds with 8.4px of chip slack.
      If a future counter string is longer than 'לא נמצאו רכבים', raise the
      134px floor with it — the rule degrades softly (the column grows, the
      chips narrow) and there is ~36px of headroom before anything clips.

  11. THE SUBMIT DELIBERATELY HAS NO BORDER AND NO :hover BACKGROUND. Both were
      in an earlier draft and both were wrong: style.css:462 covers the whole
      padding box of every .theme-btn with a #111 circle on hover, so a hover
      background here paints nothing, and a border survives that circle as a
      visible hairline around an otherwise-black button. If this button ever
      needs a hover of its own, the change is to neutralise `.theme-btn::before`
      for it first, not to re-add a declaration underneath it.
   ========================================================================== */
/* ==========================================================================
   §33  CAR CARD REDESIGN — "Decision Ladder", card surface
   --------------------------------------------------------------------------
   APPEND-ONLY block for home-boost.css. Nothing above it is edited. It is the
   LAST block in the file, and home-boost.css is the LAST stylesheet the
   homepage loads (home.blade.php line ~355, inside @section('custom-css')),
   so every rule here beats mobile-boost §8, home-boost §30 and home-boost §31
   on source order alone at equal specificity. Where a selector still needed
   to be deepened, the rule says which declaration it is beating and why.

   SCOPE: .car-box and its interior only (.ribbon, .car-img, .car-content, h3,
   .car-price, .car-list, .car-footer, .theme-btn) plus .car_more. It does not
   touch .hf* (§32 owns the filter), the brand rail, #hfMeta, or
   input.loaddata#load_more_N — the load-more button is a .theme-btn too, and
   every CTA rule below is scoped to `.car-box .car-footer` exactly as §30.4
   is, so it is never reached.

   THE COMPLAINT
     "the card can be design improved, you figure it out". Today the card
     spends its loudest paint on its least decisive facts: a saturated red
     ribbon reading הנחה במשרד that is present on EVERY card (so it separates
     nothing), and five identically-outlined pill rows that give מודל, יד,
     מנוע, כ״ס and ק״מ the same visual rank. The one number a payment-led
     buyer actually stops on — החל מ N ₪ — is a 17px inline span wedged
     between the title and the pills.

   THE LADDER THIS INSTALLS  (identical three steps to §32's filter)
     TYPE    26px/800 ink   = the decision number (price)
             ~15px/700 ink  = identity (title)
             13/11.5px 500-700 muted = qualifiers (spec detail)
     GROUND  white = primary. Exactly ONE recessed --ab-surface-3 (#f1f2f5)
             rounded panel per surface = "secondary, skim it" — here that is
             the .car-list spec block — with --ab-line-2 hairlines INSIDE it.
     RED     spent exactly TWICE per surface and nowhere else. On the card
             that budget goes entirely to the CTA: the ribbon gives up red
             (it becomes a neutral ink chip) and so does the price (it becomes
             ink, and wins on SIZE instead). Two elements fighting to be the
             loudest is how the current card ends up looking like noise.
     RADIUS  --ab-r-pill is eliminated from this surface. The ribbon goes to
             6px, the spec rows lose their pill entirely. 14px = container,
             12px = control, 12px = media/panel. That single rule is most of
             what kills the "pill soup" the user is reacting to.

   MEASURED, NOT ASSUMED — every number below was read off the live site at a
   375x812 viewport (getBoundingClientRect + canvas measureText in the real
   "Noto Sans Hebrew", which the page already loads), and every string was
   taken from all 286 rows of the `car` table, not from a sample:
     .car-content inner width ....... 143.5px   (col 181.5 - 6 pad each side
                                       -> .car-box 169.5 - 6 pad - 1 border
                                       each side -> 155.5 - 6 content pad
                                       each side = 143.5)
     .car-list width ................ 143.5px
     spec-row text width TODAY ...... 143.5 - 14 (li padding 7+7)
                                       - 24 (icon) - 6 (gap) = 99.5px
     spec-row text width AFTER ...... 143.5 - 16 (panel padding 8+8)
                                       - 14 (icon) - 5 (gap) = 108.5px
   The recessed panel therefore does not cost the values any room — it BUYS
   them 9px, because the per-row pill padding and the oversized 24px icon it
   deletes were more expensive than the panel's own padding.

   AND IT IS SHORTER, WHICH IS THE PART THAT WAS NOT OBVIOUS. Measured by
   A/B-ing this whole section on and off against a live 5-spec card at 375px:
     spec block .................. 186.00px  ->  147.45px   (-38.6)
     whole .car-box .............. 553.47px  ->  499.67px   (-53.8)
   Five 30px min-height pills plus four 4px gaps cost more than five rows of
   real text inside one panel, even after the panel's own padding, the taller
   26px price and the 10px block margins are paid for.

   TWO LIVE BUGS THIS BLOCK ALSO FIXES
     (a) THE RIBBON HAS NEVER BEEN WHERE §8 THINKS IT IS. mobile-boost §8
         writes `inset-block-start:10px; inset-inline-start:10px;` and THEN
         `top:auto; right:auto; left:auto;` to neutralise home.blade.php's
         inline <style>. In horizontal-tb, `top` and `inset-block-start` are
         the SAME property, and so are `right` and (in RTL) `inset-inline-
         start` — so the later `auto` silently overwrites §8's own offsets.
         Measured on the live page: the ribbon's top edge is 7px from the card
         edge, i.e. exactly 0px inside the media box, flush in the corner.
         §33.4 declares the physical neutralisation FIRST and the logical
         offsets LAST, which is the only ordering that works.
     (b) THE DOUBLE CURRENCY SIGN. 148 of the 286 rows store the ₪ inside
         vPrice ("החל מ 1799₪") and the Blade appends another, so the card
         reads "החל מ 1799₪ ₪". The Blade change that accompanies this file
         parses the number out and emits exactly one sign. See §33.6.

   RULES OBSERVED (same contract as the rest of the file)
     1. No class or id is renamed. The AJAX contract is untouched:
        #car_detail.loadMore, .car_more, .car-box, .car-img, .car-content,
        .car-list with li.w-100 on engine + km, .car-footer, a.theme-btn with
        its aria-label, .ribbon, #hfMeta[data-total] and
        input.loaddata#load_more_N[onclick=load_more(N)] all survive.
     2. Zero new network requests. No @font-face, no CDN, no remote url().
        The only url() is one fully percent-encoded inline SVG data: URI (the
        CTA chevron, §33.10). The five spec icons already on disk are reused.
     3. Every rule that touches a bare element (h3, ul, li, img, a, span) is
        prefixed body:not(.admin) so it can never leak into the admin panel,
        whose <body> carries no class.
     4. RTL-first. Logical properties only. The physical values in this block
        are flagged in place: the two `transform: translateX()` slides (CSS
        has no logical transform) each carry a [dir="ltr"] escape, and the
        `top/right/bottom/left:auto` quartet in §33.4 is physical BY DESIGN —
        it exists to cancel a physical inline <style>.
     5. Works with JS off. Everything here is static paint; no rule depends on
        a class that a script has to set.
     6. prefers-reduced-motion and forced-colors are honoured in §33.12.

   EXACTLY ONE !important IS USED in this block (§33.8), against Bootstrap's
   own !important utility. It is named at its site.
   ========================================================================== */


/* ==========================================================================
   §33.1  LOCAL TOKENS
   --------------------------------------------------------------------------
   Only NEW local names, and every value resolves to a token mobile-boost §1
   already defines, so there is still one source of truth. The two --rs-*
   names are NOT new: they are §30.1's, deliberately re-declared here.

   WHY --rs-ico IS RE-DECLARED RATHER THAN FOUGHT: §31 tries to shrink the
   spec icon with `body:not(.admin) .car-box .car-list img` (0,3,2), but §30
   sizes it with `body:not(.admin) .car-box .car-list > li > img` (0,3,3),
   which is one element deeper and wins. Measured on the live page: the icon
   is 24px at 375px, NOT the 16px §31 asks for — §31's icon rule is dead code
   today. Rather than add a fourth opinion on the same box, this sets the
   custom property §30's winning rule already reads. Same specificity as
   §30.1 (0,3,1), later in the file, so it also beats §30.3's two media-query
   redeclarations of the same token (media queries add no specificity, so
   source order decides).
   ========================================================================== */

body:not(.admin) .car-box{
  --cd-plate:46px;               /* brand-logo plate max inline size, phone   */
  --cd-plate-h:28px;             /* brand-logo plate block size, phone        */
  --cd-corner:12px;              /* inset of BOTH photo corner elements       */
  --cd-scrim:rgba(1,6,15,.30);   /* top-anchored photo scrim, see §33.3       */
}

body:not(.admin) .car-box .car-list{
  --rs-ico:14px;                 /* was 24px (§30.1) — measured, and 24px ate
                                    a quarter of a 143.5px row for a purely
                                    decorative, aria-hidden glyph            */
  --rs-icon-gap:5px;             /* was 6px                                   */
  --cd-panel-pad-i:8px;          /* panel inline padding                      */
  --cd-panel-pad-b:6px;          /* panel block padding                       */
  --cd-row-pad-b:5px;            /* per-row block padding (rows are text, not
                                    tap targets — --ab-tap does not apply)    */
  --cd-fz-key:13px;              /* tier 1 inside the panel: year, km         */
  --cd-fz-sub:11.5px;            /* tier 2 inside the panel: hand, engine, hp */
}


/* ==========================================================================
   §33.2  SHELL — two-layer elevation, and a lift that only a real pointer
                  can trigger
   --------------------------------------------------------------------------
   mobile-boost §8's .car-box (position:relative, --ab-r-card, overflow:hidden,
   flex column, block-size:calc(100% - --ab-s3) for equal-height rows) and
   .car-img (aspect-ratio 4/3, --ab-r-media, flex:none) are CORRECT and are
   kept as-is. All this section adds is depth.

   THE POINTER GUARD IS NON-NEGOTIABLE, and mobile-boost §3 exists because of
   it: on this site :hover LATCHES after a tap — the card image stayed at
   scale(1.2) and the CTA stayed black after returning from a detail page. A
   lift or a zoom outside `(hover:hover) and (pointer:fine)` would re-create
   exactly that bug on the primary target device.

   The zoom is 1.06, not style.css:1039's scale(1.2). 1.2 inside a 4/3 box
   crops 17% off every edge — on a 155.5x116.6px phone card that is a visible
   re-crop, and it is the reason mobile-boost had to neutralise it on touch
   rather than tune it.
   ========================================================================== */

body:not(.admin) .car-box{
  box-shadow:var(--ab-sh-1);     /* contact + ambient pair, already two-layer */
}

@media (hover:hover) and (pointer:fine){
  body:not(.admin) .car-box:hover{
    transform:translateY(-4px);
    box-shadow:var(--ab-sh-2);   /* 0 2px 4px contact + 0 12px 28px ambient   */
  }
  /* beats style.css:1039 `.car-box:hover .car-img img{transform:scale(1.2)}`
     (0,2,2) with (0,4,3). style.css declares no transition on the image, so
     one is added here or the zoom snaps. */
  body:not(.admin) .car-box .car-img img,
  body:not(.admin) .car-box .car-img video{
    transition:transform var(--ab-d3, 280ms) var(--ab-ease-out, ease-out);
  }
  body:not(.admin) .car-box:hover .car-img img,
  body:not(.admin) .car-box:hover .car-img video{
    transform:scale(1.06);
  }
}

/* Restated AFTER the hover block so a press still reads on a hybrid device.
   mobile-boost §3's `body:not(.admin) .car-box:active{transform:scale(.99)}`
   is (0,3,1) — the same weight as the :hover rule above — and lives in an
   EARLIER file, so without this restatement a hovered-and-pressed card would
   keep the lift and lose the press. Same specificity, later source order. */
body:not(.admin) .car-box:active{ transform:scale(.99); }

/* The column wrapper. .car-box already carries the margin and the
   equal-height calc(); the only thing the column itself needs is a floor of
   zero so a long unbreakable value can never widen the Bootstrap track. */
body:not(.admin) .car_more{ min-inline-size:0; }


/* ==========================================================================
   §33.3  PHOTO SCRIM — a ground for the two corner elements
   --------------------------------------------------------------------------
   The ribbon and the brand plate both sit at the TOP of the photo, so the
   gradient is top-anchored and dies at 38%: the bottom two thirds of the car
   are never touched. This is decoration strictly in service of legibility —
   the only kind this direction allows — and it is what lets the ribbon drop
   from an opaque red pill to a translucent ink chip without ever landing
   white-on-white over a bright sky.

   pointer-events:none so the ::after never intercepts the photo link, and
   z-index:1 so it paints under the plate (2) and the ribbon (3).
   ========================================================================== */

body:not(.admin) .car-box .car-img::after{
  content:"";
  position:absolute;
  inset:0;
  z-index:1;
  pointer-events:none;
  border-radius:var(--ab-r-media, 12px);
  background:linear-gradient(to bottom, var(--cd-scrim), transparent 38%);
}


/* ==========================================================================
   §33.4  RIBBON — demoted from rank-1 clothing to a rank-7 fact
   --------------------------------------------------------------------------
   הנחה במשרד is on EVERY card. A fact that is true of all 148 cars has zero
   discriminating value, so it cannot be allowed to wear the loudest paint on
   the surface. It keeps its position and its wording; it gives up the brand
   red, the pill radius and the drop shadow.

   CASCADE: same selector weight as mobile-boost §8's
   `body:not(.admin) .car-box .ribbon` (0,3,2), later in the load order, so it
   wins on source order. home.blade.php's inline <style> `.car-box .ribbon`
   (0,2,0) loads after home-boost.css but is a full class lighter, so it
   loses on specificity — which is also why §8's ::before{display:none} still
   holds and is simply restated here for safety.

   DECLARATION ORDER IS THE WHOLE POINT (see header note (a)): the physical
   `auto` quartet MUST come first. `top` and `inset-block-start` are one
   property; `right` and `inset-inline-start` are one property in RTL. §8
   writes them in the opposite order and therefore cancels itself.

   CONTRAST: white on rgba(17,17,17,.72) composited over the worst possible
   backdrop — pure white — is #545454, which is 7.6:1 against white text. Over
   anything darker it only improves, and the §33.3 scrim darkens it further.
   .72 (rather than the .62 a lighter chip would want) is chosen for exactly
   that worst case.
   ========================================================================== */

body:not(.admin) .car-box .ribbon{
  position:absolute;
  z-index:3;
  top:auto; right:auto; bottom:auto; left:auto;   /* PHYSICAL, deliberate:
                                     cancels home.blade.php's inline
                                     `top:30px; right:-3px`. Must precede the
                                     logical offsets below — see the note. */
  inset-block-start:var(--cd-corner);
  inset-inline-start:var(--cd-corner);

  padding:3px 8px;
  font-size:10.5px;
  font-weight:700;
  line-height:1.35;
  letter-spacing:.2px;
  white-space:nowrap;

  color:#fff;
  background:rgba(17,17,17,.72);
  border:0;
  border-radius:6px;              /* NOT --ab-r-pill — see the header */
  box-shadow:none;
  pointer-events:none;
}

@supports ((backdrop-filter:blur(6px)) or (-webkit-backdrop-filter:blur(6px))){
  body:not(.admin) .car-box .ribbon{
    -webkit-backdrop-filter:blur(6px) saturate(1.1);
            backdrop-filter:blur(6px) saturate(1.1);
  }
}

/* home.blade.php's inline <style> also ships a rotated red ::before tail.
   §8 already hides it; restated because this block owns the ribbon now. */
body:not(.admin) .car-box .ribbon::before{ display:none; }


/* ==========================================================================
   §33.5  BRAND LOGO — lifted OUT of the title line onto the photo
   --------------------------------------------------------------------------
   The <img> is the first child of the <h3>, so today it sits on the title's
   first line: it eats 28px of a 143.5px measure, and a 22px raster badge next
   to 14.6px Hebrew text has a baseline mismatch that no vertical-align value
   really fixes. Moving it out of the flow returns the title its whole first
   line and puts the marque where a buyer looks for it — on the car.

   .car-box is already position:relative (mobile-boost §8 + home.blade.php's
   inline <style>), so this anchors to the CARD, not the photo. The offsets
   are therefore measured from the card's PADDING box, which starts 1px in
   (the card border), while the media box starts 7px in (6px card padding +
   that 1px border). --cd-corner 12px therefore paints at 13px from the card
   edge = 6px inside the photo — measured, and identical for the ribbon
   opposite, which is the point of sharing one token.

   The <img> is inside an @if in the Blade partial, so a make with no logo
   simply leaves the corner empty; nothing reserves space.

   max-inline-size + object-fit:contain means a wide wordmark is scaled down
   rather than cropped. FIT AT 375px, measured on the live page: media box
   155.5px, ribbon 79.5px, plate 44.8px, 6px of inset each side — leaving
   19.2px of clear air between the two corner elements.

   pointer-events:none IS LOAD-BEARING, not tidiness. Lifting the <img> to
   z-index:2 puts it ABOVE mobile-boost:854's whole-card overlay
   (`.car-content h3 a::after{position:absolute; inset:0; z-index:1}`) and
   above the photo's own <a>, which mobile-boost:784 leaves static. Without
   it the plate is an opaque, non-interactive hit target sitting in the corner
   of the card's primary tap surface: measured in the harness at 375px,
   document.elementFromPoint at the plate centre returned `IMG` with
   closest('a') === null, while the same point 14px lower returned the card
   link. The dead zone is 44.8x28 = 1253px2, 6.9% of the 155.5x116.6 photo at
   375px and 10.2% of the 128x96 photo at 320px. The plate is pure marque
   decoration — the make is already in the <img alt>, in the <h3> text and in
   the CTA's aria-label — so nothing is lost but its native title tooltip,
   which is worth far less than a live hole in the card link. §33.4 declares
   the same property on the ribbon for exactly this reason.

   CASCADE: mobile-boost §8's `body:not(.admin) .car-content h3 img` (0,2,3)
   sets inline-size/block-size:22px and margin-inline-end:6px. This is (0,3,3)
   and beats it on specificity as well as order.
   ========================================================================== */

body:not(.admin) .car-box .car-content h3 img{
  position:absolute;
  z-index:2;                       /* above the §33.3 scrim (1) and above the
                                      whole-card h3 a::after overlay (1);
                                      below the ribbon (3) */
  pointer-events:none;             /* see the note: z-index:2 would otherwise
                                      make a decorative plate swallow taps that
                                      belong to the whole-card link */
  inset-block-start:var(--cd-corner);
  inset-inline-end:var(--cd-corner);

  inline-size:auto;
  max-inline-size:var(--cd-plate);
  block-size:var(--cd-plate-h);
  object-fit:contain;

  margin-inline-end:0;             /* undoes §8's inline gap; the img is no
                                      longer in the title's line box */
  padding:4px;
  background:#fff;
  border-radius:8px;
  box-shadow:var(--ab-sh-1);
}

@media (min-width:576px){
  body:not(.admin) .car-box{
    --cd-plate:58px;
    --cd-plate-h:34px;
    --cd-corner:14px;
  }
}

/* --------------------------------------------------------------------------
   NARROW PHONES — the two corner elements stop fitting, and they collide
   --------------------------------------------------------------------------
   The ribbon is pinned at --cd-corner from the inline-START edge and the plate
   at --cd-corner from the inline-END edge of the SAME containing block
   (.car-box's padding box), both at fixed sizes, so the pair has a hard
   minimum width that the card eventually drops below. The ribbon carries
   z-index:3 and the plate z-index:2, so the failure mode is the dark chip
   painting over the logo — not a gap closing, but a marque being covered.

   MEASURED in the harness (real sheets in real order + §33 + the edited Blade
   output), gap = ribbon.getBoundingClientRect().x - plate.getBoundingClient-
   Rect().right on card 1, whose CHERY plate is the widest at 44.75px:
       375px -> +19.23   360px -> +11.7   350px -> +6.7
       340px ->  +1.7    320px ->  -8.27  (OVERLAP)
   At 320px the card's padding box is 140.0px and the pair needs
   2x12 corner + 79.52 ribbon + 44.75 plate = 148.27px. Three of the eight
   live cards overlapped there (-8.27 / -1.80 / -7.06); the five that did not
   are square badges that render at only 28px.

   Both corner elements step down together. The RIBBON gives up the most,
   which is the same ranking argument §33.4 already makes: הנחה במשרד is true
   of every car and discriminates nothing (rank 7), while the marque is part
   of the card's identity (rank 2), so the rank-7 element yields first.
   Contrast is unaffected — white on rgba(17,17,17,.72) is 7.6:1 at any size.

   359.98px is deliberately §30.3's existing narrow-card breakpoint, so this
   file keeps ONE small-width discipline rather than inventing a second. It
   fires well above the ~337px width where the overlap actually starts, which
   is the point: at 340px the old tokens cleared by 1.7px, which is not a
   margin, it is luck.

   THE max-inline-size CAP IS A LAST RESORT, not the mechanism. With the
   tokens below the ribbon needs 67.66px against an 80px cap at 320px, so it
   never engages on any phone in normal use; it exists so that a longer
   translation string, or a 280px folding-phone cover screen, degrades to an
   ellipsised promo chip instead of a covered logo. Percentages on an
   absolutely positioned box resolve against the containing block's PADDING
   box (.car-box: 140px at 320px, 120px at 280px), and the formula reserves
   the plate's own width, both corner insets, and a 6px floor of clear air
   between the two boxes. 6px is deliberately SMALLER than --cd-corner: the
   cap must only bite when the natural gap would drop under a visible
   minimum, not whenever it is merely tighter than the design gap. Measured
   after the change: no clipping at or above ~305px; at 280px the chip loses
   its last two glyphs and the gap holds at exactly 6px.
   -------------------------------------------------------------------------- */
@media (max-width:359.98px){
  body:not(.admin) .car-box{
    --cd-plate:34px;
    --cd-plate-h:24px;
    --cd-corner:10px;
  }

  /* (0,3,2) — identical weight to §33.4's own .ribbon rule, later in the file,
     so it wins on source order. Media queries add no specificity. */
  body:not(.admin) .car-box .ribbon{
    font-size:9.5px;
    padding:2px 6px;
    letter-spacing:0;              /* .2px x ~12 glyphs is 2.4px of the budget */
    max-inline-size:calc(100% - var(--cd-plate) - var(--cd-corner) * 2 - 6px);
    overflow:hidden;
    text-overflow:ellipsis;
  }
}


/* ==========================================================================
   §33.6  PRICE — the headline, in ink
   --------------------------------------------------------------------------
   RANK 1. Every card carries החל מ N ₪ and the business is finance
   (תשלום חודשי / מימון 100% / עד 100 תשלומים), so this is the number the
   scroll stops on. It moves to the FIRST child of .car-content, above the
   title, with a hairline under it: DOM order, visual order and ranking order
   now agree, and because .car-price holds nothing focusable the move costs
   nothing in focus order.

   IT IS INK, NOT RED, AND THAT IS THE DELIBERATE PART. Red is the CTA colour.
   A red price and a red button are two elements competing to be the loudest
   thing on the card and neither wins — which is most of why the current card
   reads as noise. Rank 1 is carried by SIZE alone: 26px against a 14.6px
   title. --ab-ink on white is 18.9:1.

   THE DATA IS FREE TEXT AND IT IS MESSY. All 286 rows were inspected:
     · 236 rows           "החל מ 1799₪"      (sign already in the value —
                                              the Blade appends a second one,
                                              so the card reads "1799₪ ₪")
     · 17 rows            "החל מ-1,690" / "החל מ- 2,890"   (dash, comma)
     ·  9 rows            "2500 ₪ החזר חודשי" / "1560₪ בחודש"  (qualifier
                                              AFTER the number)
     ·  1 row             "הח מ2799₪"        (typo, no space)
     ·  4 rows            "144000" / "99000" / "129999₪" / "100.000"
                                             (a full sale price, no lead text)
   The Blade change splits this into lead / number / tail and lets CSS style
   the three parts. Three safety rails, all verified against those 286 rows:
     (1) the number run is emitted VERBATIM — never number_format()'d, because
         "100.000" would be silently rewritten to 100000;
     (2) "לחודש" is synthesised ONLY when the raw string contains החל, the
         parsed digits are under 10000, and there is no qualifier of the
         dealer's own after the number. The four full-price rows above all
         fail that guard, so none of them is mislabelled as a monthly figure;
     (3) if the regex does not match at all, the Blade falls back to today's
         exact output and .car-price's own base rule — a 15px/800 ink flex
         container — still renders it as a strong price rather than as
         nothing. That base also covers car_detail.blade.php's related cards,
         which ship the OLD single-text-node .car-price and never match
         .car-price__num (see KNOWN TRADE-OFFS).

   MEASURED FIT at 375px, measure = 143.5px, in the page's real font:
     "1,799" at 26px/800 .......  68.4px
     "129999" at 26px/800 ......  91.1px
     " ₪" at 15px/800 ..........  17.4px
     "לחודש" at 11.5px/700 .....  33.8px
     worst realistic line ......  68.4 + 3 + 17.4 + 3 + 33.8 = 125.6px  ✓
   and flex-wrap means a dealer-authored tail such as "החזר חודשי" drops to a
   second line rather than clipping.

   THE FOUR CHILD SIZES ARE em, NOT px, AND THE NUMBER'S COLOUR IS `inherit`.
   Both exist because the split turned ONE text node into four elements, and a
   text node inherits things that an element with its own declaration does not.
   ab-a11y.css is the file that notices:

     (a) TEXT SIZE. ab-a11y.css:706 scales the price by scaling the CONTAINER
         only — `html[class*="a11y-t"] body:not(.admin) .car-price{
         font-size:calc(18px * var(--a11y-ts))}` (0,3,2), which outranks this
         block's (0,3,1) and is what the widget's "הגדלת טקסט" control drives.
         Before the split the whole price was one text node inside that
         container, so it scaled. Pinned to px, the children do not: measured
         in the harness at a11y-t3, .car-price went 15px -> 25.2px and
         .car-content h3 went 20px -> 28px while __num stayed 26px, __lead
         11px and __per 11.5px — the enlarge control could no longer touch the
         card's headline number, and at ab-a11y-t4 (--a11y-ts 1.55) the 27.9px
         container would have overtaken it and inverted the ladder outright.
         `calc(26em / 15)` against the 15px base is EXACTLY 26px at
         --a11y-ts:1 — em, not a rounded decimal, so the rendered pixel value
         is unchanged today — and the whole price now scales as one unit.

     (b) COLOUR. ab-a11y.css:735-747 repaints the page for high contrast with
         a long :is() element list, and that list does not contain `bdi`.
         .car-price is a <span> so it is swept, then lifted to #ff8a9c by
         ab-a11y.css:769-771; __lead/__cur/__per are <span>s and are swept to
         #fff. `.car-price__num` is the ONE part emitted as <bdi> (it needs the
         isolation — the number sits between Hebrew runs), so it is never
         swept, and a declaration of its own on that element beats inheritance
         regardless of the !important upstream. Measured with a11y-contrast on
         <html>: __num computed rgb(17,17,17) on rgb(0,0,0) = 1.11:1. The
         card's largest, most important element became invisible in the site's
         own high-contrast mode. `color:inherit` hands it back to .car-price —
         #111 normally, #ff8a9c (9.4:1 on black) under contrast — and keeps
         tracking that container through any future mode without this block
         having to know the mode exists.

   CASCADE: mobile-boost §8's `body:not(.admin) .car-price` (0,2,1) sets
   display:inline-block, 17px and --ab-brand-strong. This is (0,3,1).
   ========================================================================== */

body:not(.admin) .car-box .car-price{
  display:flex;
  flex-wrap:wrap;
  align-items:baseline;
  column-gap:3px;
  row-gap:0;

  /* the FALLBACK look, deliberately not "unstyled": an unparsed raw string is
     one anonymous flex item and still renders as a strong ink price */
  font-size:15px;
  font-weight:800;
  line-height:1.2;
  letter-spacing:-.01em;
  color:var(--ab-ink, #111);

  margin:0 0 8px;
  padding-block-end:8px;
  border-block-end:1px solid var(--ab-line, rgba(17,17,17,.08));
}

/* "החל מ" — its own full-width line above the number, so the number starts at
   the inline-start edge and the qualifier never competes with it */
body:not(.admin) .car-box .car-price__lead{
  flex:1 0 100%;
  font-size:calc(11em / 15);            /* = 11px at --a11y-ts:1; see note (a) */
  font-weight:700;
  line-height:1.2;
  letter-spacing:0;
  color:var(--ab-ink-muted, #5b6577);
  margin-block-end:1px;
}

body:not(.admin) .car-box .car-price__num{
  font-size:calc(26em / 15);            /* = 26px at --a11y-ts:1; see note (a) */
  font-weight:800;
  line-height:1;
  letter-spacing:-.02em;
  color:inherit;                        /* NOT a literal: <bdi> is missing from
                                           ab-a11y.css's high-contrast sweep
                                           list, so any own-colour here paints
                                           #111 on #000 = 1.11:1. See note (b) */
  font-variant-numeric:tabular-nums;    /* 148 -> 30 -> 5 must not jitter */
}

body:not(.admin) .car-box .car-price__cur{
  font-size:1em;                        /* = the .car-price base, 15px at
                                           --a11y-ts:1; see note (a) */
  font-weight:800;
  line-height:1;
  color:inherit;                        /* a <span>, so the sweep already
                                           reaches it — inherit simply keeps
                                           all four parts on one rule */
}

/* "לחודש", or whatever qualifier the dealer typed after the number */
body:not(.admin) .car-box .car-price__per{
  font-size:calc(11.5em / 15);          /* = 11.5px at --a11y-ts:1 */
  font-weight:700;
  line-height:1.2;
  letter-spacing:0;
  color:var(--ab-ink-muted, #5b6577);   /* 5.9:1 on white */
}


/* ==========================================================================
   §33.7  TITLE — rank 2, and it gets its first line back
   --------------------------------------------------------------------------
   Measured over all 286 vTitle values: mean 13.5 characters, max 33
   ("סילווראדו LT כולל חבית plus החדשה"). At 14.6px/700 that longest title is
   241px against a 143.5px measure = 1.68 lines, and it breaks cleanly at
   "…כולל / חבית…" (113px / 106px), so two lines holds every title in the
   table. Measured on the live homepage, 6 of the 8 cards are single-line
   once the brand logo leaves the flow (§33.5).

   font-size drops from §8's --ab-fs-card (clamp(15px,4.2vw,20px) = 15.75px at
   375px) to clamp(14px,3.9vw,16px) = 14.625px. That is not shrinking the
   title for its own sake: rank 1 is the 26px price, and a 15.75px title
   directly beneath it blurs the step.

   §8's three -webkit-line-clamp companions (display:-webkit-box,
   -webkit-box-orient, overflow:hidden) are RESTATED, per §8's own note: they
   are only inert-proof if all four travel together.

   THE 2-LINE RESERVE IS KEPT — one graft deliberately not taken; see
   KNOWN TRADE-OFFS 3.

   CASCADE: mobile-boost §8's `body:not(.admin) .car-content h3` (0,2,2) sets
   font-size, min-block-size:2.56em and margin-bottom. This is (0,3,2).
   ========================================================================== */

body:not(.admin) .car-box .car-content h3{
  font-size:clamp(14px, 3.9vw, 16px);
  font-weight:700;
  line-height:1.3;
  color:var(--ab-ink, #111);

  display:-webkit-box;
  -webkit-box-orient:vertical;
  -webkit-line-clamp:2;
  overflow:hidden;

  min-block-size:2.6em;              /* exactly two 1.3 line boxes */
  margin:0;                          /* the spec panel below owns the gap */
}


/* ==========================================================================
   §33.8  SPEC BLOCK — five pills become ONE recessed panel
   --------------------------------------------------------------------------
   This is the change the user is actually asking for. Five outlined pills of
   five different widths, each with its own border and its own 12px radius,
   give מודל / יד / מנוע / כ״ס / ק״מ five equal shouts. They become one
   #f1f2f5 panel — the same recessed ground §32 gives the filter's refinement
   group — with --ab-line-2 hairlines between the rows and TWO weight tiers
   inside it.

   WHY --ab-line-2 (.14) AND NOT --ab-line (.08) FOR THE INTERNAL RULES: a .08
   hairline composited over #f1f2f5 is ~1.19:1 against its own ground and is
   simply not there. .14 composites to ~#d2d3d6 = 1.34:1, which reads as a
   rule. (Neither is a text-contrast figure; these are decorative separators
   between rows that their own content already separates, so 3:1 does not
   apply — but 1.19:1 is invisible and 1.34:1 is not.)

   THE TWO TIERS ARE POSITIONAL, AND THAT IS A REAL DEPENDENCY:
     li:first-child is ALWAYS "מודל {vYear}" and li:last-child is ALWAYS
     "{vKilometer} ק״מ" — both are unconditional in
     ajax_listing_car_detail.blade.php, while hand / engine / hp sit inside
     @if branches. Year is the strongest single proxy for condition and
     residual value and km is the second strongest, so those two get ink at
     13px/700; the middle rows are enthusiast detail and get muted 11.5px/500.
     ==> IF A SIXTH SPEC IS EVER APPENDED AFTER THE KILOMETRE <li>, THE BOLD
         TREATMENT SILENTLY MOVES TO THE WRONG FACT. There is no way to fail
         loudly here; this comment is the guard.

   CASCADE, carefully — three files are arguing about these <li>:
     mobile-boost §2:149  `body:not(.admin) .car-list li`            (0,2,2)
     mobile-boost §8      `body:not(.admin) .car-list li`            (0,2,2)
     home-boost  §30.2    `body:not(.admin) .car-box .car-list > li` (0,3,2)
     home-boost  §30.2    `... > li.w-100`                           (0,4,2)
     home-boost  §31      `... .car-list li` / `li.w-100`     (0,3,2)/(0,4,2)
   The rules below use §30's child combinator AND repeat §31's paired
   `li, li.w-100` form, giving (0,3,2)/(0,4,2) — equal to the heaviest
   existing selector, and last in the file, so they win on source order with
   no !important. Media queries add no specificity, so this base block also
   beats §31's max-width:991.98px and max-width:380px declarations at every
   width. IF ANYONE EVER RE-SORTS THE SECTIONS OF THIS FILE, THE PILLS COME
   BACK AND NOTHING ERRORS.

   -webkit-line-clamp is NOT touched below 992px: §31's clamp of 2 is left
   exactly as it is. The design called for clamping the two key rows to a
   single line, and that was rejected on measurement — at a 320px viewport the
   .car-list is 116px and "מודל 2022/2023" needs 93.8px against 81px of row
   text, so a 1-line clamp would ellipsise a year on small phones. Two lines
   never cuts a value, and for short values it is visually identical.
   ========================================================================== */

/* --- the panel ----------------------------------------------------------- */
/* (0,3,1) — same as §30.2's and §31's .car-list rules, later in the file. */
body:not(.admin) .car-box .car-list{
  background:var(--ab-surface-3, #f1f2f5);
  border-radius:var(--ab-r-media, 12px);
  padding:var(--cd-panel-pad-b) var(--cd-panel-pad-i);
  margin-block:10px;
  margin-inline:0;
  gap:0;                               /* rows are separated by hairlines now */
  list-style:none;
}

/* --- the row: all chrome removed ---------------------------------------- */
body:not(.admin) .car-box .car-list > li,
body:not(.admin) .car-box .car-list > li.w-100{
  background:none;
  border:0;
  border-radius:0;
  box-shadow:none;
  min-block-size:0;                    /* beats §31's min-block-size:30px,
                                          which inflated an 11.5px value into
                                          a 30px row five times per card */
  padding-block:var(--cd-row-pad-b);
  padding-inline:0;
  margin:0;
}

/* Bootstrap ships `.w-100{width:100%!important}` and the engine + km <li>
   carry that class. Nothing but !important beats an !important utility.
   §30.2 already declares this; it is restated because this block now owns the
   row box model and a future edit to §30 must not be able to bring the
   zigzag back. DO NOT remove .w-100 from the Blade to avoid this — the
   car-detail page may rely on it. */
body:not(.admin) .car-box .car-list > li.w-100{
  inline-size:auto !important;         /* beats Bootstrap .w-100 width:100%!important */
}

/* The hairline between rows — never above the first one.
   THE `.w-100` PAIR IS LOAD-BEARING, and it is not about Bootstrap this time:
   it is about the reset directly above. That reset lists `> li` (0,3,2) AND
   `> li.w-100` (0,4,2), and it zeroes `border`. A plain `> li + li` hairline
   is only (0,3,2), so the reset's own .w-100 arm outranks it and the engine
   and kilometre rows silently lose their rule — verified in the browser
   before this pair was added: rows 3 and 5 measured border-top-width 0px.
   `> li + li.w-100` is (0,4,2), equal to the reset and later in the file. */
body:not(.admin) .car-box .car-list > li + li,
body:not(.admin) .car-box .car-list > li + li.w-100{
  border-block-start:1px solid var(--ab-line-2, rgba(17,17,17,.14));
}

/* --- TIER 1: year (first) and kilometres (last) -------------------------- */
/* (0,4,2) / (0,5,2) with the .w-100 pair — the km <li> carries .w-100, so the
   paired form is required to beat §31's own (0,4,2) `li.w-100` rule. */
body:not(.admin) .car-box .car-list > li:first-child,
body:not(.admin) .car-box .car-list > li:last-child,
body:not(.admin) .car-box .car-list > li.w-100:first-child,
body:not(.admin) .car-box .car-list > li.w-100:last-child{
  font-size:var(--cd-fz-key);
  font-weight:700;
  line-height:1.35;
  color:var(--ab-ink, #111);           /* 16.9:1 on #f1f2f5 */
}
body:not(.admin) .car-box .car-list > li:first-child > img,
body:not(.admin) .car-box .car-list > li:last-child > img{
  opacity:.75;
}

/* --- TIER 2: hand, engine, horsepower ------------------------------------ */
/* (0,5,2) / (0,6,2). The engine <li> carries .w-100 AND is always a middle
   row, so the paired form is load-bearing here too. */
body:not(.admin) .car-box .car-list > li:not(:first-child):not(:last-child),
body:not(.admin) .car-box .car-list > li.w-100:not(:first-child):not(:last-child){
  font-size:var(--cd-fz-sub);
  font-weight:500;
  line-height:1.35;
  color:var(--ab-ink-muted, #5b6577);  /* 5.3:1 on #f1f2f5 */
}
body:not(.admin) .car-box .car-list > li:not(:first-child):not(:last-child) > img{
  opacity:.5;
}

/* --- the icon ------------------------------------------------------------ */
/* §30.1's `> li > img` rule already reads --rs-ico / --rs-icon-gap, which
   §33.1 re-declares. This only needs to stop a raster PNG (hp.png,
   engineering.png) looking muddy at 14px. */
body:not(.admin) .car-box .car-list > li > img{
  image-rendering:auto;
  vertical-align:-2px;                 /* optical centring against a 1.35 line
                                          box; `middle` sits the glyph high */
}

/* Very small phones. .car-list is 116px at 320px and 136px at 360px, so the
   tier-1 row has ~81px / ~101px of text width; "מודל 2022/2023" is 97.6px at
   13px, which is why the key tier steps down here. The panel keeps its 8px
   padding — it is already the cheapest padding on the card. */
@media (max-width:380px){
  body:not(.admin) .car-box .car-list{
    --cd-fz-key:12.5px;
    --cd-fz-sub:11.5px;
  }
}


/* ==========================================================================
   §33.9  SPEC BLOCK ON DESKTOP — §30's two columns, preserved
   --------------------------------------------------------------------------
   §31 made .car-list a SINGLE column below 992px because cards are 2-up on a
   phone and a split 143.5px row left roughly three characters per cell. That
   is not regressed anywhere in this block: nothing above touches
   grid-template-columns, so §30's `repeat(2, minmax(0,1fr))` still applies
   from 992px up and §31's `1fr` still applies below it.

   MEASURED at a 1280px viewport, where Bootstrap gives col-xl-3: the card is
   261px, so .car-list is 227px and a plain two-column split leaves a 99.5px
   cell = 80.5px of text after the 14px icon and its 5px gap. Verified in the
   browser, that is not enough for the two rows that carry the ranking:
   "מודל 2022/2023" and "79000/91000 ק״מ" both reported scrollWidth over
   clientWidth, i.e. ellipsised.

   THIS IS INHERITED, NOT INTRODUCED. Measured on the live page at 1280px
   with none of this block applied: §30's cell is 111.5px and, after 12px of
   cell padding, a 20px icon and a 5px gap, only 74.5px of it is text — and
   3 of the 6 first cards ellipsise their engine row TODAY, including strings
   as short as "מנוע 1.5T בנזין". The paired cell below gives 80.5px, which is
   6px MORE than today, and the key rows stop competing for it entirely.

   THE FIX: the two KEY rows span both columns; only the middle group pairs.
   grid-template-columns is untouched, so §31's contract holds exactly —
   single column below 992px, two columns above it — and every cell only gets
   WIDER. A full-width row has 211px of box and 192px of text, which clears
   even the longest kilometre string in the table
   ("1200ק״מ טווח נסיעה ק״מ", ~143px) on one line.

   THE MIDDLE-GROUP ORPHAN GUARD is the mirror of §30.2's, one level in. The
   middle items are positions 2..n-1 and pair up (2,3), (4,5)… so the last
   middle item — `:nth-last-child(2)` — is alone exactly when it sits at an
   EVEN position. Spanning it then is what keeps a hole out of the block:
     5 items -> year | hand+engine | hp | km      (hp spans, position 4)
     4 items -> year | hand+engine | km           (engine pairs, position 3)
     3 items -> year | engine | km                (engine spans, position 2)

   AND THE HAIRLINE STAYS `li + li`, unchanged from mobile. Because item 1
   always spans, item 2 always starts a new grid row, so "every item but the
   first draws a rule above itself" is still exactly right: a paired row gets
   a rule on both of its cells (one continuous rule with a 12px interruption
   at the column gap, which reads as a column separator), and a spanned row
   gets one rule across. An earlier draft used `li:nth-child(n+3)` here; that
   is only correct while every row holds exactly two cells, which stops being
   true the moment anything spans.

   Values still longer than 80.5px in a paired cell — the engine string, and
   "143 כ״ס בנזין -חשמל" — ellipsise, which is the SAME trade-off §30's own
   notes already accept for desktop cells. THIS IS NOT MITIGATED BY THE title
   ATTRIBUTE, and an earlier draft of this note wrongly claimed it was: the
   whole-card overlay (mobile-boost:854, `.car-content h3 a::after{inset:0;
   z-index:1}`) covers the spec panel, so the <li> is never the hover target
   and is not on the ancestor chain the browser walks for a title. Verified in
   the harness at both 375px and 1280px — elementFromPoint over every one of
   the five spec rows returns the overlay's <a>, and closest('[title]') from
   there is null. The attributes are kept because they are free, harmless and
   would start working if the overlay were ever removed, but the desktop
   ellipsis is an OPEN trade-off, not a solved one. See KNOWN TRADE-OFFS 5.

   SPECIFICITY of the span rules: §30.2 sets `> li.w-100{grid-column:auto}`
   (0,4,2) to keep the engine and kilometre items as ordinary cells. The
   `.w-100` arms below are (0,5,2) and (0,6,2), so they outrank it outright;
   the plain arms are (0,4,2)/(0,5,2) and face no competitor, since §30 never
   sets grid-column on a non-.w-100 <li> except in its own orphan rule, which
   declares the identical value.
   ========================================================================== */

@media (min-width:992px){
  body:not(.admin) .car-box .car-list{
    --cd-fz-key:12.5px;
    --cd-fz-sub:11px;
    --cd-panel-pad-i:8px;
    --cd-row-pad-b:5px;
    column-gap:12px;
    row-gap:0;
  }

  /* rank 3 (year) and rank 4 (km) get the full measure */
  body:not(.admin) .car-box .car-list > li:first-child,
  body:not(.admin) .car-box .car-list > li:last-child,
  body:not(.admin) .car-box .car-list > li.w-100:first-child,
  body:not(.admin) .car-box .car-list > li.w-100:last-child{
    grid-column:1 / -1;
  }

  /* middle-group orphan guard — see the note above */
  body:not(.admin) .car-box .car-list > li:nth-last-child(2):nth-child(even),
  body:not(.admin) .car-box .car-list > li.w-100:nth-last-child(2):nth-child(even){
    grid-column:1 / -1;
  }
}


/* ==========================================================================
   §33.10  CTA — still red, no longer shouting
   --------------------------------------------------------------------------
   §30.4 built this button correctly: full width, --ab-r-field, brand fill,
   48px floor. The only thing it does wrong now is wear --ab-sh-brand, a
   coloured glow, while the 26px price sits above it — two loud things again.
   A full-width solid brand fill on white is already unmissable; the glow is
   removed and the button holds red alone on the card.

   THE 48px FLOOR IS KEPT. The design direction asked for 46px; --ab-tap is
   48px and it is the stated accessibility floor for this project, so the
   direction is overruled here. 15px/700 in a 48px bar is not "shouting" —
   the shadow was.

   .car-footer's rule above the button is removed. With the spec block now
   drawn as hairline-ruled rows inside a tinted panel, a heavier full-width
   rule immediately below it is a second separator doing the first one's job.

   SCOPE: everything is `.car-box .car-footer .theme-btn`, exactly as §30.4,
   so `input.theme-btn.loaddata#load_more_N` — which lives OUTSIDE #car_detail
   in the same partial — is untouched.

   CONTRAST: #fff on --ab-brand #dc344c is 4.53:1. 15px/700 is not "large
   text" under WCAG (that needs 18.66px bold), so 4.5:1 is the bar and this
   clears it. Unchanged from today.
   ========================================================================== */

body:not(.admin) .car-box .car-footer{
  border-top:0;                        /* beats mobile-boost §8's
                                          `.car-footer{border-top:1px solid
                                          var(--ab-line)}` (0,2,1) */
  margin-block-start:auto;             /* keeps §30.4's equal-height CTA line-up */
  padding-block-start:10px;
}

body:not(.admin) .car-box .car-footer .theme-btn{
  position:relative;                   /* restated: §8 relies on it for z-index:2
                                          over the whole-card h3 a::after */
  box-shadow:none;
  min-block-size:var(--ab-tap, 48px);
  font-size:15px;
  font-weight:700;
  padding-inline:var(--ab-s3, 12px);
}

/* A chevron of travel. In RTL "forward" points to the INLINE-START edge,
   which is physically LEFT, so the glyph is drawn left-pointing and the slide
   is negative X. CSS has no logical transform, hence the [dir="ltr"] escape
   below. The glyph is an inline, fully percent-encoded SVG data: URI — no
   network request — and it is authored HERE rather than in a style attribute,
   where the nested quotes break. */
body:not(.admin) .car-box .car-footer .theme-btn::after{
  content:"";
  flex:0 0 auto;
  inline-size:8px;
  block-size:12px;
  margin-inline-start:2px;
  background:url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20width='8'%20height='12'%20viewBox='0%200%208%2012'%3E%3Cpath%20d='M6.4%201.3%201.7%206l4.7%204.7'%20fill='none'%20stroke='%23ffffff'%20stroke-width='1.8'%20stroke-linecap='round'%20stroke-linejoin='round'/%3E%3C/svg%3E") center/8px 12px no-repeat;
  transition:transform var(--ab-d2, 180ms) var(--ab-ease-out, ease-out);
}
/* PHYSICAL, flagged: mirrors the glyph for an LTR document. */
[dir="ltr"] body:not(.admin) .car-box .car-footer .theme-btn::after{
  transform:scaleX(-1);
}

@media (hover:hover) and (pointer:fine){
  body:not(.admin) .car-box .car-footer .theme-btn:hover::after{
    transform:translateX(-3px);        /* PHYSICAL: -X is forward in RTL */
  }
  [dir="ltr"] body:not(.admin) .car-box .car-footer .theme-btn:hover::after{
    transform:scaleX(-1) translateX(-3px);
  }
}


/* ==========================================================================
   §33.11  MOTION, FORCED COLOURS, PRINT
   --------------------------------------------------------------------------
   mobile-boost §4 already sets animation-duration/transition-duration to
   .01ms !important under prefers-reduced-motion, which neutralises the
   TIMING of everything above. It does not remove a TRANSFORM, though — a
   4px lift, a 1.06 zoom and a 3px chevron slide would simply happen
   instantly, which is exactly the kind of jump vestibular users report. Those
   three are removed outright.

   Under forced colours every background, gradient and shadow in this block is
   discarded by the UA, which would erase the panel, the ribbon's chip and the
   photo scrim — leaving the ribbon as white-on-whatever and the spec block as
   an undivided run of text. Each colour-only device is given a border
   instead. mobile-boost §17 already draws the card's own outline.
   ========================================================================== */

@media (prefers-reduced-motion:reduce){
  body:not(.admin) .car-box:hover{ transform:none; }
  body:not(.admin) .car-box:hover .car-img img,
  body:not(.admin) .car-box:hover .car-img video{ transform:none; }
  body:not(.admin) .car-box .car-footer .theme-btn:hover::after{ transform:none; }
  [dir="ltr"] body:not(.admin) .car-box .car-footer .theme-btn:hover::after{
    transform:scaleX(-1);
  }
}

@media (forced-colors:active){
  body:not(.admin) .car-box .car-img::after{ display:none; }

  body:not(.admin) .car-box .ribbon{
    border:1px solid CanvasText;
    background:Canvas;
    color:CanvasText;
    -webkit-backdrop-filter:none;
            backdrop-filter:none;
  }

  body:not(.admin) .car-box .car-content h3 img{
    border:1px solid CanvasText;
  }

  body:not(.admin) .car-box .car-list{
    border:1px solid CanvasText;
  }
  body:not(.admin) .car-box .car-list > li + li,
  body:not(.admin) .car-box .car-list > li + li.w-100{
    border-block-start:1px solid CanvasText;
  }

  body:not(.admin) .car-box .car-price{
    border-block-end:1px solid CanvasText;
  }

  body:not(.admin) .car-box .car-footer .theme-btn{
    border:1px solid CanvasText;
  }
}

@media print{
  /* UAs drop background graphics by default, so the panel would vanish and
     the spec rows would run together. Give it an outline instead. */
  body:not(.admin) .car-box .car-list{
    border:1px solid #ccc;
    background:none;
  }
  body:not(.admin) .car-box .car-img::after{ display:none; }
  body:not(.admin) .car-box .car-footer .theme-btn::after{ display:none; }
}


/* ==========================================================================
   §33 — KNOWN TRADE-OFFS
   --------------------------------------------------------------------------
   1. THE PRICE SPLIT ONLY LANDS IN THE AJAX PARTIAL. car_detail.blade.php
      renders its own related .car-box cards with the OLD single-text-node
      .car-price, so .car-price__lead / __num / __cur / __per never match
      there. That is why the base .car-price rule in §33.6 is itself a
      15px/800 ink flex container rather than a bare wrapper: a plain text
      child still renders as a strong price. The two surfaces will not look
      identical until car_detail.blade.php gets the same @php block — a
      follow-up, not a blocker, and no rule here breaks that page.

   2. THE TWO TIERS IN §33.8 ARE POSITIONAL. li:first-child is the year and
      li:last-child is the kilometres ONLY because the Blade partial orders
      them that way and both are unconditional. Appending a sixth spec after
      the kilometre <li> moves the ink-13px treatment to the new row and
      demotes km to muted 11.5px, silently. Restated here because there is no
      way to make CSS fail loudly about it.

   3. THE 2-LINE TITLE RESERVE IS KEPT — a graft deliberately NOT taken.
      Dropping §8's min-block-size would return ~19px on the ~75% of cards
      whose title is one line (measured: 6 of the 8 live homepage titles fit
      143.5px at 14.6px/700), and §30.4's `.car-footer{margin-block-start:auto}`
      would still bottom-align every CTA in the row. But cards are 2-up on a
      phone, and the new spec block is a TINTED PANEL whose top edge is highly
      visible: without the reserve, two neighbouring panels would start ~19px
      apart. A visible misalignment between adjacent cards is a worse defect
      than 19px of height, so the reserve stays. Revisit if the title is ever
      capped to one line.

   4. THE ENGINE-LABEL GRAFT WAS SKIPPED, on measurement. It proposed hiding
      the engine label behind an .ab-sr span because the label is "נפח מנוע".
      Resolved live, `message.LBL_PAGE_CAR_DETAIL_ENGINECAPACITY_TITLE`
      returns "מנוע" — four characters, ~25px — not the eight-character string
      the graft measured. Hiding it would save ~25px of a 108.5px row while
      removing the only word that identifies the row when the value is bare
      digits ("1500 טורבו"). It would also need a NEW .ab-sr class: no
      stylesheet on this site defines one (the existing helper is .sr-only).
      Not worth it. The longest engine string in the table,
      "מנוע חשמל מלא טווח נסיעה עד 430 ק״מ" (201px), breaks into two lines of
      105px and 92px inside the 108.5px row, so it fits with the label shown.

   5. THE ENGINE ROW STILL ELLIPSISES IN A PAIRED DESKTOP CELL. Measured at
      1280px: the paired cell carries 80.5px of text, and 3 of 6 sample cards
      clip their engine string there. That is better than today — the same
      three clip at today's 74.5px, and two of them clip harder — but it is
      not solved. Solving it means making the engine row full width too,
      which strands יד and כ״ס in single-cell rows with holes beside them,
      because the Blade emits them on either side of the engine row and grid
      auto-placement cannot reorder. THERE IS NO MITIGATION TODAY: the `title`
      attribute on those two <li> cannot surface a tooltip while the
      whole-card overlay covers the panel (see §33.9), and it is kept only
      because it is free and would work if that overlay ever went away. The
      real fixes are both out of this block's scope — shorten the engine
      label in the message file, or drop the overlay in favour of a real link
      on the title alone.

   6. THE 12px COLUMN GAP BREAKS THE DESKTOP HAIRLINE. In the one paired row,
      the rule runs across both cells with a 12px interruption in the middle.
      It reads as a column separator. Closing it would mean giving up the gap
      or moving the rule onto the panel with pseudo-elements, and neither is
      worth the machinery.

   7. NOTHING HERE IS STICKY, ANIMATED ON LOAD, OR JS-DEPENDENT. Every rule
      is static paint on markup the AJAX partial already emits, so a card
      appended by load_more() is styled the moment it lands, with no
      re-initialisation and no observer.
   ========================================================================== */

/* ========================= end §33  CAR CARD REDESIGN ===================== */
