/* ============ VETURA — the explorer ============ */

/* --- the search card ---
   This page used to open with a ~590px «vault» plate and a loose control row.
   Both are gone. One compact panel now holds the query, every brand and the
   filters, and the h1 moved BELOW it (.exhead): sitting directly under the nav
   wordmark it read as a second logo rather than as a page title. --- */
.extoolwrap{max-width:var(--maxw);margin:0 auto;padding:clamp(92px,12vh,120px) clamp(20px,4vw,56px) 0}
.extool{display:flex;gap:10px;align-items:center;flex-wrap:wrap;
  border:1px solid var(--line);border-radius:16px;background:var(--bg-2);padding:12px 14px}
.extool .searchbar{flex:1;min-width:min(260px,100%)}
.extool .searchbar__box{height:46px;border-radius:11px}
/* flex-shrink:0 — the selects were shrinking below their own label, clipping
   «Modeli» under its chevron. The search box is the only thing that should flex. */
.extool .select{font-size:.72rem;padding:.56em 2.1em .56em 1em;flex:0 0 auto}
/* ★ FIXED widths, not max-widths. A native <select> sizes to its current
   option, so Modeli rendered at 80px while disabled (one placeholder) and would
   have JUMPED wider the moment a brand was picked, reflowing the row under the
   user — the same instability the mobile grid was built to kill. Sort varies the
   same way between «Çmimi ↑» and «Arritja e fundit». Pinned, so the card never
   changes shape as a reward for using it. */
/* .extool .select (0,2,0) outranks a bare .extool__make (0,1,0), so these need
   the parent too or the flex-basis above silently wins. */
.extool .extool__make,.extool .extool__model{flex:0 0 168px}
.extool #exSort{flex:0 0 180px}
#exModel[disabled]{opacity:.45;cursor:not-allowed}
.extool__filbtn{display:none}
.extool__hall{display:none}

/* brand marks — EVERY brand, logo only, NO surrounding box.
   Still <button>s (keyboard, Enter/Space, aria-pressed); .chip is deliberately
   not used because its border, pill and invert-to-white active state are the
   exact chrome being removed here. Selection is shown by full opacity plus the
   site's own accent hairline — the same idiom the nav uses for the active page,
   and it keeps --accent to a hairline rather than a fill. */
/* wrapper carries the rail; it is also the node ui.js relocates between the
   search card and the heading row. */
.exbrands-wrap{position:relative;min-width:0}
/* The baseline under the marks. A HIGHLIGHT, not a scrollbar: strongest
   across the middle and fading to nothing at both ends, so it reads as a soft
   underline rather than a control. It gives logos of different proportions a
   shared baseline; the slow drift is what says there are more of them.
   Hidden when nothing overflows, so it never underlines a row with no tail. */
.exbrands__rail{display:none;height:1px;margin-top:7px;
  background:linear-gradient(90deg,transparent,var(--line-3) 28%,var(--line-3) 72%,transparent)}
.exbrands__rail.show{display:block}
.exbrands{display:flex;gap:4px;align-items:center;overflow-x:auto;overflow-y:hidden;
  scrollbar-width:none;-ms-overflow-style:none;
  mask-image:linear-gradient(90deg,#000 93%,transparent);
  -webkit-mask-image:linear-gradient(90deg,#000 93%,transparent)}
.exbrands::-webkit-scrollbar{display:none}
.bmark{position:relative;flex:0 0 auto;display:grid;place-items:center;
  width:68px;height:54px;padding:0;border:0;background:none;cursor:pointer}
.bmark .blogo{height:34px;max-width:56px;margin:0;opacity:.58;
  transition:opacity .25s,transform .35s var(--ease-out)}
.bmark:hover .blogo{opacity:1;transform:translateY(-2px)}
.bmark.is-active .blogo{opacity:1}
.bmark__t{font-family:var(--mono);font-size:.66rem;color:var(--text-2)}
.bmark::after{content:"";position:absolute;left:50%;bottom:4px;width:0;height:1px;
  background:var(--accent);transform:translateX(-50%);transition:width .3s var(--ease-out)}
.bmark.is-active::after{width:24px}
.bmark.is-zero{opacity:.22;pointer-events:none}
.bmark:focus-visible{outline:2px solid var(--line-3);outline-offset:-4px;border-radius:10px}

@media (min-width:961px){
  /* every section is forced open by applyRailDisclosure(), so the summary is
     decoration here — make it inert and drop the chevron. The desktop rail
     then looks and behaves exactly as it did before disclosure existed. */
  .rail__sec > summary{cursor:default;pointer-events:none}
  .rail__sec > summary::after{display:none}
  /* the line is the ORGANISER on desktop, so the track is always drawn —
     logos of different proportions read as a row once they share a
     baseline. The moving segment on it still only appears when there is
     genuinely more to scroll. */
  .exbrands__rail{display:block}
}

/* --- h1, below the card, above the results --- */
.exhead-row{max-width:var(--maxw);margin:0 auto;padding:24px clamp(20px,4vw,56px) 0;
  display:flex;align-items:center;gap:clamp(16px,3vw,40px)}
.exhead{font-size:clamp(1.3rem,2.5vw,1.85rem);font-weight:650;letter-spacing:-.025em;
  line-height:1.15;flex:0 0 auto}
/* >=961px ui.js moves the marks in here; min-width:0 lets the strip scroll
   instead of stretching the row. */
.exhead-row .exbrands-wrap{flex:1;min-width:0}

/* ticker — the marquee is OUT of the markup for now and may come back; the JS
   is guarded, so these rules are kept deliberately so re-adding the element is
   a one-line HTML change. They match nothing today. */
.vault__ticker{margin-top:12px;overflow:hidden;border:1px solid var(--line);border-radius:10px;background:var(--bg-2);
  mask-image:linear-gradient(90deg,transparent,#000 5%,#000 95%,transparent);-webkit-mask-image:linear-gradient(90deg,transparent,#000 5%,#000 95%,transparent)}
.vault__ticker-track{display:flex;gap:44px;white-space:nowrap;padding:9px 0 9px 44px;will-change:transform;width:max-content}
.vault__ticker-track a{font-family:var(--mono);font-size:.7rem;letter-spacing:.05em;color:var(--text-3);display:inline-flex;gap:9px;align-items:center;transition:color .3s}
.vault__ticker-track a:hover{color:var(--text)}
.vault__ticker-track .tk-stat{font-family:var(--mono);font-size:.7rem;letter-spacing:.05em;color:var(--text-2);display:inline-flex;gap:7px;align-items:center}
.vault__ticker-track .tk-stat b{color:var(--text);font-weight:600;font-variant-numeric:tabular-nums}
.vault__ticker-track .tk-new{color:var(--accent);font-size:.58rem;letter-spacing:.2em}

/* --- layout: rail + results --- */
.exwrap{max-width:var(--maxw);margin:0 auto;padding:16px clamp(20px,4vw,56px) 90px;
  display:grid;grid-template-columns:288px 1fr;gap:clamp(20px,2.6vw,38px);align-items:start}

/* rail */
.rail{position:sticky;top:86px;max-height:calc(100dvh - 106px);overflow-y:auto;overscroll-behavior:contain;
  border:1px solid var(--line);border-radius:16px;background:var(--bg-2);padding:6px 16px 16px;scrollbar-width:thin;scrollbar-color:var(--surface-2) transparent}
.rail::-webkit-scrollbar{width:5px}
.rail::-webkit-scrollbar-thumb{background:var(--surface-2);border-radius:3px}
.rail__sec{padding:16px 0 18px;border-bottom:1px solid var(--line)}
.rail__sec:last-child{border-bottom:none}
/* dependent model filter — indented sub-section, revealed when a brand is picked */
.rail__sec--sub{padding-left:12px;border-left:2px solid rgba(209,26,47,.42)}
.rail__sec--sub .rail__label{color:var(--text-2)}
.rail__sub{color:var(--accent);margin-right:.15em}
.rail__label{font-family:var(--mono);font-size:.62rem;letter-spacing:.24em;text-transform:uppercase;color:var(--text-3);margin-bottom:13px;display:flex;justify-content:space-between;align-items:center}
/* sections are <details>; the label is the <summary>. */
.rail__sec > summary{list-style:none;cursor:pointer;display:flex;align-items:center;
  justify-content:space-between;gap:10px}
.rail__sec > summary::-webkit-details-marker{display:none}
.rail__sec > summary::after{content:"";width:7px;height:7px;flex:0 0 auto;
  border-right:1px solid currentColor;border-bottom:1px solid currentColor;
  transform:rotate(45deg) translate(-2px,-2px);transition:transform .28s var(--ease-out)}
.rail__sec[open] > summary::after{transform:rotate(225deg) translate(-2px,-2px)}
.rail__sec > summary:focus-visible{outline:2px solid var(--line-3);outline-offset:3px}
/* the price toggle belongs WITH price, not in a toggle block of its own */
.rail__pricetog{margin-top:14px}
/* sheet header — mobile only; gives the panel a way out that is not the scrim */
.rail__head{display:none}
.rail__headt{font-family:var(--mono);font-size:.68rem;letter-spacing:.22em;
  text-transform:uppercase;color:var(--text-2)}
.rail__close{width:44px;height:44px;margin-right:-10px;display:grid;place-items:center;
  color:var(--text-2);border-radius:50%;transition:color .25s,transform .3s var(--ease-out)}
.rail__close:hover{color:var(--text);transform:rotate(90deg)}
.rail__sec--flat{padding:16px 0 18px;border-bottom:1px solid var(--line)}
.rail__chips{display:flex;flex-wrap:wrap;gap:7px}
.rail__toggles{display:flex;flex-direction:column;gap:12px}
.rail__clear{width:100%;margin-top:2px}
.rail__foot{display:none}

/* range rows */
.rrow{display:flex;flex-direction:column;gap:8px;padding-top:2px}
.rrow__vals{display:flex;justify-content:space-between;font-family:var(--mono);font-size:.72rem;color:var(--text-2)}

/* --- results --- */
.exres{min-width:0}
.exres__bar{display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin-bottom:16px;min-height:34px}
.exres__count{font-family:var(--mono);font-size:.8rem;color:var(--text-2)}
.exres__count b{color:var(--text);font-size:1.05rem;font-weight:600}
.exres__pills{display:flex;gap:8px;flex-wrap:wrap;align-items:center}
.exres__clear{font-family:var(--mono);font-size:.68rem;letter-spacing:.06em;color:var(--text-3);text-decoration:underline;text-underline-offset:3px;transition:color .25s}
.exres__clear:hover{color:var(--accent)}
.exres__notice{display:flex;align-items:center;justify-content:space-between;gap:14px;flex-wrap:wrap;
  margin:0 0 16px;padding:12px 16px;border:1px solid var(--line-2);border-left:2px solid var(--accent);
  border-radius:12px;background:rgba(255,255,255,.02);font-family:var(--mono);font-size:.78rem;color:var(--text-2)}
/* ★ `hidden` is only a UA rule (`[hidden]{display:none}`), and ANY author
   `display` beats it. `.exres__notice` sets `display:flex`, so the notice
   rendered its border, its 12px padding and its accent left-edge even while
   marked hidden — an empty red-edged ghost box sitting above the grid on every
   default view. Verified present on production 2026-08-29. Same shape would
   bite `#exOffers`, which is safe today only because it never sets a display. */
.exres__notice[hidden]{display:none}
.exres__notice b{color:var(--text);font-variant-numeric:tabular-nums}
.exres__notice-btn{font-family:var(--mono);font-size:.72rem;letter-spacing:.06em;text-transform:uppercase;
  color:var(--accent);background:none;border:1px solid var(--line-2);border-radius:999px;padding:6px 14px;cursor:pointer;
  transition:border-color .25s,background .25s,transform .1s}
.exres__notice-btn:hover{border-color:var(--accent);background:rgba(255,255,255,.03)}
.exres__notice-btn:active{transform:scale(.97)}
.exres__grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(295px,1fr));gap:16px}
/* ★ CLS. #exGrid ships EMPTY and is filled from inventory.json, so between load
   and first render the footer sat mid-viewport and then dropped the height of
   the whole catalogue. Measured on production 2026-08-16: one layout shift of
   0.1974, the largest single contributor to a page CLS of 0.32-0.63 — Google
   calls anything above 0.25 poor, and this is the page the commercial queries
   land on.
   `:empty` is the whole fix: it reserves a screen while the grid has no
   children and stops applying the instant the first card is inserted, so it
   costs nothing once the page is live and needs no JS to undo. Content that
   settles BELOW the fold does not count toward CLS, which is why reserving one
   viewport is enough — the footer simply never starts on screen.

   ★ The `:not(:has(...))` is NOT decoration. `#exGrid` is ALSO empty when a
   filter matches nothing, and `.exempty` (its sibling, display:none until JS
   adds .show) is what the visitor reads instead. Without the guard, «Asnjë
   veturë nuk përputhet» would sit under 80vh of blank page — trading a metric
   for a worse experience on the exact screen a frustrated searcher sees.

   Written as ONE rule on purpose: a browser without :has() drops the whole
   declaration and degrades to today's behaviour (a shift), never to the dead
   space a two-rule override would leave behind. */
.exres__grid:empty:not(:has(~ .exempty.show)){min-height:80vh}
.exres__grid .card{content-visibility:auto;contain-intrinsic-size:auto 360px}
/* entrance plays ONLY on genuinely new nodes (.is-new, set by the keyed
   reconcile) — moved/kept cards no longer replay the fade on every filter */
.exres__grid .card.is-new{opacity:0;transform:translateY(22px);animation:cardin .6s var(--ease-out) forwards;animation-delay:calc(min(var(--i),12)*38ms)}
@keyframes cardin{to{opacity:1;transform:none}}
.exempty{text-align:center;padding:80px 20px;border:1px dashed var(--line-2);border-radius:16px;display:none}
.exempty.show{display:block}
.exempty__t{font-size:1.3rem;font-weight:500;margin-bottom:8px}
.exempty__b{color:var(--text-3);margin-bottom:22px}
.shortlist-cta{display:none;margin-bottom:16px}
.shortlist-cta.show{display:inline-flex}

/* --- mobile: rail becomes bottom sheet --- */
@media (max-width:960px){
  .exwrap{grid-template-columns:1fr}
  .extool__filbtn{display:inline-flex;position:relative}
  /* ★ The toolbar was `flex-wrap` over six children with a 300px-min search
     box, so on a phone it produced roughly four UNEVEN rows whose composition
     changed with label length — the single biggest source of the "crowded and
     confusing" complaint. An explicit two-column grid gives three predictable
     rows with aligned columns:
        row 1   search                (spans both)
        row 2   brand logo presets    (spans both, scrolls sideways)
        row 3   Marka   | Modeli
        row 4   Rendit  | Filtro
     Explicit grid-row on each child, because the strip has to sit under the
     SEARCH here while on desktop it wraps to a line under the whole toolbar. */
  .extool{display:grid;grid-template-columns:1fr 1fr;gap:9px;align-items:stretch}
  /* the strip is its own full-width row directly beneath the search box; the
     selects and Filtro follow underneath it */
  .extool .searchbar{grid-column:1/-1;grid-row:1;min-width:0}
  /* bleed to the card edges so a half-chip peeks and invites the scroll */
  .exbrands-wrap{grid-column:1/-1;grid-row:2}
  .exbrands{margin:0 -14px;padding:0 14px}
  /* ~5 marks per 390px screen before the scroll begins, as asked */
  .bmark{width:64px;height:52px}
  .bmark .blogo{height:32px;max-width:52px}
  /* the heading stands alone below 961px — the marks are up in the card */
  .exhead-row{display:block}
  .extool__make{grid-column:1;grid-row:3}
  .extool__model{grid-column:2;grid-row:3}
  #exSort{grid-column:1;grid-row:4}
  .extool__filbtn{grid-column:2;grid-row:4}
  .extool__make,.extool__model{max-width:none}
  /* one height for all four, which also clears the 44px tap floor */
  .extool .select,.extool__filbtn{width:100%;min-height:44px}
  .extool__filbtn{justify-content:center}
  .extool__filbtn .nbadge{position:absolute;top:-7px;right:-7px;min-width:19px;height:19px;border-radius:10px;background:var(--accent);
    color:#fff;font-family:var(--mono);font-size:.62rem;font-weight:600;display:grid;place-items:center;padding:0 5px}
  .rail{position:fixed;inset:auto 0 0 0;top:auto;z-index:180;max-height:82dvh;border-radius:20px 20px 0 0;
    transform:translateY(105%);transition:transform .45s var(--ease-out);background:#121212;padding-bottom:0}
  .rail.open{transform:none}
  .rail__head{display:flex;align-items:center;justify-content:space-between;
    position:sticky;top:0;z-index:2;background:#121212;padding:14px 0 12px;
    border-bottom:1px solid var(--line)}
  /* ★ TAP TARGETS. The range thumbs were 16px (webkit) / 12px (moz) inside a
     26px row and there are eight of them — the hardest controls on the page.
     The toggle rows were worse at ~22px. Growing .range only grows the HIT
     AREA: .range__track and .range__fill are absolutely positioned and
     vertically centred, so the hairline does not move. */
  .rail .range{height:44px}
  .rail .range input[type=range]{height:44px}
  .rail__toggles .toggle,.rail__pricetog{min-height:44px}
  .rail__toggles{gap:6px}
  .rail .chip{min-height:44px}
  .rail__sec > summary{min-height:44px}
  /* collapsed sections only need to be a readable row; the generous desktop
     rhythm just makes the sheet taller than the phone it sits on. */
  .rail__sec{padding:5px 0 7px}
  .rail__sec[open]{padding-bottom:16px}
  .rail__sec--flat{padding:14px 0}
  /* the Apply row must clear the iPhone home indicator */
  .rail__foot{display:flex;position:sticky;bottom:0;background:#121212;padding:14px 0 calc(18px + env(safe-area-inset-bottom));gap:10px;border-top:1px solid var(--line);margin-top:14px}
  .rail__foot .btn{flex:1;justify-content:center}
  .sheet-scrim{position:fixed;inset:0;z-index:170;background:rgba(0,0,0,.55);backdrop-filter:blur(3px);-webkit-backdrop-filter:blur(3px);
    opacity:0;pointer-events:none;transition:opacity .35s}
  .sheet-scrim.show{opacity:1;pointer-events:auto}
}
@media (max-width:560px){
  .exres__grid{grid-template-columns:1fr}
  .extoolwrap{padding-top:clamp(78px,10vh,98px)}
  .exhead-row{padding-top:20px}
  .exhead{font-size:1.3rem}
  .exwrap{padding-top:12px}
}

/* --- Night Visit: the vault room ambience + ledger tick --- */
body::before{content:"";position:fixed;inset:0;z-index:-1;pointer-events:none;opacity:.04;
  background-image:url('/assets/film-poster/vault.jpg');background-size:cover;background-position:center}
.exres__count.tick b{animation:ledgertick .5s var(--ease) 1}
@keyframes ledgertick{0%{opacity:.2;transform:translateY(3px)}100%{opacity:1;transform:none}}
.exres__count b{display:inline-block;font-variant-numeric:tabular-nums;will-change:transform,opacity}
