/* ==========================================================================
   Frontend polish pass 2 (t_frontpolish01) — loaded last on every page.

   Scope: craft only. Hero sharpness/capsule, card crop + overlay alignment +
   price type, villa-page rhythm + amenity grid + reviews, search rail +
   result-card states + empty state, header compaction + language prominence,
   and the micro-interaction layer (buttons, calendar cells, toasts).

   Rules that keep this file honest:
   - Nothing here moves the layout of a page that has already painted: the
     scroll-reveal uses transform/opacity only, the header shrinks by padding
     inside its existing min-height, and every overlay is absolutely placed.
   - Tokens, radii and easings come from lux.css/design-polish.css, so this
     layer can never invent a second design language.
   - Every block is a no-op when its component is absent.
   ========================================================================== */

/* ---------- 0. motion tokens + shared easing ---------- */
:root{
  --e-out:cubic-bezier(.22,.61,.36,1);
  --e-in-out:cubic-bezier(.4,0,.2,1);
  --t-press:120ms;
}

/* ---------- 1. hero: sharpness, crop, capsule craft ---------- */
/* The 6% static scale on .hero-bg resampled the bitmap on every frame — the
   single largest sharpness loss on the LCP image. The inset does the same
   edge protection with no transform, so the photo stays pixel-exact. */
.hero-bg{transform:none;inset:-2% 0 -2%}
.hero-bg img{object-position:center 58%}
.hero h1{text-shadow:0 1px 2px rgba(6,20,17,.28),0 10px 34px rgba(6,20,17,.36)}
.hero .sub{text-shadow:0 1px 2px rgba(6,20,17,.30)}

/* the capsule: persistent labels, real dividers, one optical baseline */
.herosearch{gap:0;padding:6px 6px 6px var(--s5)}
.herosearch label{padding:6px 0 6px var(--s4);gap:.1rem;justify-content:center}
.herosearch label:first-of-type{padding-left:0}
.herosearch label + label{border-left:1px solid var(--line-2)}
.herosearch label > span{
  font-size:.66rem;font-weight:700;letter-spacing:.1em;text-transform:uppercase;
  color:var(--ink-3);line-height:1.4;
}
.herosearch select,.herosearch input{
  border:0;background:transparent;font-size:.95rem;font-weight:600;color:var(--ink);
  min-height:24px;line-height:1.4;padding:0;
}
.herosearch label::after{top:1.85rem;right:.55rem;opacity:.6;transition:opacity var(--t-micro) ease}
.herosearch label:hover::after{opacity:1}
.herosearch label:focus-within::after{opacity:1}
.herosearch button{
  height:48px;min-width:124px;border-radius:var(--r-pill);
  font-weight:700;letter-spacing:.01em;
  box-shadow:0 1px 2px rgba(6,20,17,.2),0 8px 18px rgba(6,20,17,.18);
  transition:transform var(--t-press) var(--e-out),box-shadow var(--t-micro) ease,
    filter var(--t-micro) ease;
}
.herosearch button:hover{filter:brightness(1.07);box-shadow:0 2px 4px rgba(6,20,17,.22),0 12px 26px rgba(6,20,17,.24)}
.herosearch button:active{transform:translateY(1px) scale(.995)}
.herosearch:focus-within{box-shadow:var(--shadow-onphoto),0 0 0 3px rgba(216,188,147,.45)}

@media (max-width:860px){
  .herosearch{padding:12px;gap:10px;border-radius:var(--r-lg)}
  .herosearch label{padding:.45rem .7rem;border-radius:var(--r-sm)}
  .herosearch label > span{font-size:.62rem;letter-spacing:.08em}
  .herosearch button{height:50px;min-width:0;border-radius:var(--r-md);margin-top:2px}
  .herosearch label:focus-within{outline-offset:1px}
}

/* ---------- 2. cards: one crop, one overlay band, honest price type ---------- */
/* Every grid locks the media box to 4:3, including the compact and tile grids
   that used to inherit whatever ratio the source photo had. */
.vmedia,.grid .vmedia,.tiles .vmedia,.occgrid .vmedia{aspect-ratio:4/3;overflow:hidden}
.vmedia .vstrip > picture img{object-fit:cover;object-position:center 55%}

/* badge stack and rating chip share one top band: same inset, same height,
   same radius — they read as a row of card furniture, not two systems. */
.vcard .vbadges{top:12px;left:12px;gap:.32rem}
.vchips{position:absolute;top:12px;right:12px;z-index:3}
.vbadge-pill,.rchip{
  height:26px;border-radius:var(--r-pill);
  box-shadow:0 1px 2px rgba(6,20,17,.22),0 6px 16px rgba(6,20,17,.16);
}
.vbadge-pill{display:inline-flex;align-items:center;padding:0 .55rem;font-size:.66rem}
.rchip{border-radius:var(--r-pill);font-size:.74rem;overflow:hidden}
.rchip .rscore{padding:0 .42rem;background:var(--ink)}
.rchip .rlab{padding:0 .5rem 0 .42rem}
.rchip .rlab{background:rgba(255,255,255,.94)}
.rchip[data-lvl="exc"] .rlab{background:#DCEEDF;color:#14532D}
.rchip[data-lvl="verygood"] .rlab{background:#E7F1DC;color:#2C4A17}
.rchip[data-lvl="good"] .rlab{background:#F3EEE6;color:#4A3B26}
.rchip[data-lvl="ok"] .rlab{background:#F1E9E3;color:#5A4232}

/* price: one line, number leads, unit rides the number, never a second line */
.vprice{
  display:flex;align-items:baseline;gap:.32rem;flex-wrap:nowrap;
  border-top:1px solid var(--line);padding-top:var(--s2);margin-top:var(--s3);
}
.vprice .from{
  order:-1;font-size:.78rem;font-weight:500;color:var(--ink-3);
  text-transform:none;letter-spacing:0;white-space:nowrap;
}
.vprice .amt{font-size:1.32rem;font-weight:700;letter-spacing:-.035em;line-height:1.05}
.vprice .unit{font-size:.76rem;color:var(--ink-3);white-space:nowrap;margin-left:.05rem}
.vprice .por{font-size:.95rem;font-weight:650;color:var(--ink-2)}
/* the lei anchor is context, not a headline: one clamped line, tabular */
.vlei{
  display:block;margin-top:.1rem;font-size:.74rem;line-height:1.35;color:var(--ink-3);
  font-variant-numeric:tabular-nums;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
.vlei small{font-size:.7rem;opacity:.8}
.vcard .vweek{margin-top:.1rem;font-size:.72rem;color:var(--ink-3)}
.vdep{font-size:.72rem}

/* card response: the photo settles, the card lifts a hair, the frame sharpens */
.vcard{transition:transform var(--t-hover) var(--e-out)}
.vcard:hover{transform:translateY(-2px)}
.vcard:hover .vmedia{box-shadow:0 2px 6px rgba(6,20,17,.10),0 18px 36px rgba(6,20,17,.14)}
.vmedia{transition:box-shadow var(--t-hover) var(--e-out),outline-color var(--t-micro) ease}
.vcard:hover .vmediap .vframe{transform:none}

@media (max-width:520px){
  .vcard .vbadges{top:10px;left:10px}
  .vchips{top:10px;right:10px}
  .vbadge-pill,.rchip{height:24px}
  .vbadge-pill{font-size:.62rem;padding:0 .48rem}
  .rchip{font-size:.7rem}
  .vprice .amt{font-size:1.24rem}
}

/* ---------- 3. villa page: rhythm, amenity grid, reviews, lightbox ---------- */
/* One vertical rhythm, and headings that belong to the block under them
   (more space above than below, a hairline that is the block's own). */
body[data-page="villa"] .block{margin-top:var(--s8);padding-top:var(--s6)}
body[data-page="villa"] .block > h2{
  font-size:clamp(1.28rem,1.7vw,1.5rem);letter-spacing:-.024em;
  margin:0 0 var(--s4);padding-bottom:var(--s3);border-bottom:1px solid var(--line);
}
body[data-page="villa"] .block > h2 + *{margin-top:0}
body[data-page="villa"] .prose{font-size:1.02rem;line-height:1.72}
body[data-page="villa"] .prose br + br{line-height:2.1}
.villahead{padding-bottom:var(--s5);margin-bottom:var(--s4)}

/* amenities: a real matrix — equal cells, one icon plate, aligned labels */
.amen{
  display:grid;grid-template-columns:repeat(auto-fill,minmax(230px,1fr));
  gap:.4rem .8rem;margin:0;padding:0;list-style:none;
  border:1px solid var(--line);border-radius:var(--r-card);padding:var(--s4);
  background:var(--card);
}
.amen li{
  display:flex;align-items:center;gap:.65rem;min-height:44px;
  padding:.35rem .45rem;border-radius:var(--r-sm);
  font-size:.93rem;line-height:1.3;
  transition:background var(--t-micro) ease;
}
.amen li:hover{background:var(--accent-soft)}
.amen .ai{
  width:30px;height:30px;border-radius:9px;flex:none;
  background:var(--accent-soft);color:var(--accent);
  display:grid;place-items:center;
}
.amen .ai svg{width:17px;height:17px}
.amen li:hover .ai{background:#fff}

/* reviews: legible header, real card anatomy, clamped body with a way out */
.revsum2{grid-template-columns:minmax(0,1fr) minmax(0,1.2fr);gap:var(--s6)}
.revbig2 .num{font-size:3.4rem}
.revbig2 small{font-size:.86rem;color:var(--ink-2)}
.revscore2{grid-template-columns:9.5rem 1fr 2.4rem;font-size:.86rem}
.revscore2 .bar{height:6px}
.revitem{padding:var(--s4) var(--s4) var(--s3);box-shadow:var(--shadow-sm)}
.revhead{display:flex;align-items:center;gap:.5rem;margin-bottom:.45rem}
.revhead strong{font-size:.94rem}
.revhead .muted{font-size:.78rem}
.revhead .rate{margin-left:auto;font-size:.76rem;font-weight:700;color:var(--ink-2)}
.revav{
  width:30px;height:30px;border-radius:50%;flex:none;display:grid;place-items:center;
  background:var(--accent-soft);color:var(--accent);font-weight:700;font-size:.82rem;
  border:1px solid var(--line);
}
.revbody{margin:0;color:var(--ink-2);line-height:1.6;font-size:.94rem;
  display:-webkit-box;-webkit-line-clamp:5;-webkit-box-orient:vertical;overflow:hidden}
.revitem.open .revbody{-webkit-line-clamp:unset;display:block}
.revmore{
  margin-top:.35rem;padding:.15rem 0;border:0;background:none;cursor:pointer;
  font:inherit;font-size:.8rem;font-weight:650;color:var(--brass-ink);
  text-decoration:underline;text-underline-offset:3px;
}
.revmore:hover{color:var(--ink)}

/* lightbox: fade + a settle instead of a hard cut */
.lightbox{background:rgba(9,24,21,.94);
  -webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px);
  animation:lb-in 180ms var(--e-out) both}
.lightbox.closing{animation:lb-out 140ms var(--e-in-out) both}
.lb-body img{animation:lb-img 220ms var(--e-out) both}
.lb-strip img{opacity:.42;transition:opacity var(--t-micro) ease,outline-color var(--t-micro) ease}
.lb-strip img:hover{opacity:.8}
.lb-strip img.on{opacity:1;outline:2px solid #fff;outline-offset:1px}
@keyframes lb-in{from{opacity:0}to{opacity:1}}
@keyframes lb-out{from{opacity:1}to{opacity:0}}
@keyframes lb-img{from{opacity:0;transform:scale(.985)}to{opacity:1;transform:none}}

@media (max-width:860px){
  .amen{grid-template-columns:1fr 1fr;padding:var(--s3);gap:.3rem}
  .amen li{font-size:.86rem;min-height:42px;padding:.3rem .35rem}
  .revsum2{grid-template-columns:1fr}
}

/* ---------- 4. search: sticky rail, result states, empty state ---------- */
@media (min-width:861px){
  .results{align-items:start}
  /* (0,2,1) so this beats design-reference.css, which parks the rail at a
     flat 20px — under the 68px sticky header that offset is invisible */
  .results > form.filters,
  .results > .filters{
    position:sticky;top:calc(var(--hdr-h) + var(--s4));
    max-height:calc(100svh - var(--hdr-h) - var(--s6));overflow-y:auto;
    overscroll-behavior:contain;padding-right:.35rem;
    scrollbar-width:thin;
  }
  .filters .fgroup{margin-bottom:.2rem}
  .filters .fgroup h4{letter-spacing:.09em;font-size:.68rem;color:var(--ink-3);margin-bottom:.45rem}
  .filters .fchk{transition:border-color var(--t-micro) ease,background var(--t-micro) ease,
    color var(--t-micro) ease,box-shadow var(--t-micro) ease,transform var(--t-press) var(--e-out)}
  .filters .fchk:hover{transform:translateY(-1px)}
  .filters .fchk:active{transform:none}
}
/* result cards respond like cards, not like links */
.resultlist .vcard{transition:transform var(--t-hover) var(--e-out),border-color var(--t-hover) ease}
.resultlist .vcard:hover{outline:1px solid var(--line-2)}

.empty{padding:var(--s8) var(--s5) var(--s7)}
.empty::before{
  content:"";display:block;width:56px;height:56px;margin:0 auto var(--s4);
  border-radius:50%;background:var(--accent-soft) no-repeat center/24px 24px;
  background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23122F2A' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='7'/%3E%3Cpath d='M20 20l-4.2-4.2M8.5 11h5'/%3E%3C/svg%3E");
}
.empty h3{font-size:clamp(1.2rem,2.4vw,1.5rem);letter-spacing:-.02em}
.empty .chiprow .chip-x{background:var(--card)}

/* ---------- 5. header: compaction, language switcher, sticky craft ---------- */
.langsw{display:flex;align-items:center;gap:.45rem}
.langsw-lb{font-size:.64rem;font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:var(--ink-3)}
body.overhero .langsw-lb{color:rgba(255,255,255,.66)}
.langs{
  padding:2px;border:1px solid var(--line);border-radius:var(--r-pill);
  background:rgba(255,255,255,.55);
}
.langs a{border-radius:var(--r-pill);padding:.25rem .45rem;gap:.3rem;min-height:28px}
.langs a span{font-size:.72rem}
.langs a.on{background:#fff;border-color:transparent;box-shadow:0 1px 2px rgba(6,20,17,.16)}
body.overhero .langs{background:rgba(255,255,255,.12);border-color:rgba(255,255,255,.26)}
body.overhero .langs a.on{background:rgba(255,255,255,.92);color:var(--ink);box-shadow:none}

/* compaction: the bar loses height and shadow once the page is scrolled, and
   the over-hero dark treatment is dropped as soon as the photo is gone */
.hdr{transition:min-height 180ms var(--e-out),box-shadow 180ms ease,
  background-color 180ms ease,border-color 180ms ease}
body.hdr-slim .hdr{
  height:calc(var(--hdr-h) - 12px);min-height:0;
  box-shadow:0 1px 2px rgba(6,20,17,.06),0 6px 18px rgba(6,20,17,.06);
}
body.hdr-slim:not(.overhero) .hdr{background:rgba(250,248,244,.97)}
body.hdr-slim .hdr .brand .word{font-size:.98rem}
body.hdr-slim .hdr .navt{height:40px}
body.hdr-slim .hdr .hdravail,
body.hdr-slim .hdr .hdrcta a{min-height:34px;padding-block:.3rem}
body.hdr-slim.overhero .hdr{background:linear-gradient(180deg,rgba(9,24,21,.92),rgba(9,24,21,.80))}

@media (max-width:860px){
  .langsw{flex-direction:column;align-items:flex-start;gap:.3rem;width:100%}
  .langsw-lb{font-size:.6rem}
  .langs{width:100%;justify-content:flex-start}
  .langs a{flex:1 1 auto;justify-content:center;min-height:38px}
}

/* ---------- 6. micro-interactions ---------- */
.btn,.vbook,.vask,.sfopen,.chip-x,.pgnum,.more,.mlink,.hdravail{
  transition:transform var(--t-press) var(--e-out),box-shadow var(--t-micro) ease,
    background-color var(--t-micro) ease,border-color var(--t-micro) ease,
    color var(--t-micro) ease,filter var(--t-micro) ease;
}
.btn:active,.vbook:active:not(:disabled),.vask:active,.sfopen:active{transform:translateY(1px)}
.vbook:hover:not(:disabled){filter:brightness(1.05);box-shadow:0 1px 2px rgba(6,20,17,.14),0 6px 14px rgba(6,20,17,.14)}
.vask:hover{box-shadow:var(--shadow-sm);border-color:var(--ink-3)}
.more:hover,.mlink:hover{transform:translateX(1px)}

/* calendar: cells answer on press, selections pop once, range reads as one bar */
.calx-day{transition:background var(--t-micro) ease,color var(--t-micro) ease,
  transform var(--t-press) var(--e-out),box-shadow var(--t-micro) ease}
.calx-day.pickable:active{transform:scale(.96)}
.calx-day.in-range{background:#E4DBCB;transition:background var(--t-micro) ease}
.calx-day.sel-start,.calx-day.sel-end{
  background:var(--accent);color:#fff;box-shadow:0 1px 3px rgba(6,20,17,.22);
}
.calx-day.sel-start .calx-price,.calx-day.sel-end .calx-price{color:rgba(255,255,255,.85)}

/* toasts: one line of confirmation, bottom centre, gone in three seconds */
.toasts{
  position:fixed;left:50%;bottom:calc(var(--s6) + env(safe-area-inset-bottom));
  transform:translateX(-50%);z-index:95;display:flex;flex-direction:column;
  align-items:center;gap:.4rem;pointer-events:none;width:max-content;max-width:92vw;
}
.toast{
  display:flex;align-items:center;gap:.5rem;
  padding:.6rem .9rem;border-radius:var(--r-pill);
  background:var(--ink);color:#fff;font-size:.86rem;font-weight:600;
  box-shadow:0 2px 6px rgba(6,20,17,.24),0 14px 32px rgba(6,20,17,.28);
  animation:toast-in 200ms var(--e-out) both;
}
.toast.out{animation:toast-out 160ms var(--e-in-out) both}
.toast svg{width:15px;height:15px;flex:none;color:#C8F0DC}
/* the filter sheet owns the bottom edge while it is open — lift the toast
   above its sticky action row instead of printing over "Show results" */
body.sf-sheet .toasts{bottom:calc(var(--s6) + 84px + env(safe-area-inset-bottom))}
@keyframes toast-in{from{opacity:0;transform:translateY(10px) scale(.98)}to{opacity:1;transform:none}}
@keyframes toast-out{to{opacity:0;transform:translateY(6px)}}

/* ---------- 7. reveal on scroll (transform/opacity only) ---------- */
@media (prefers-reduced-motion:no-preference){
  .rv{opacity:0;transform:translateY(10px);
    transition:opacity 420ms var(--e-out),transform 420ms var(--e-out)}
  .rv.in{opacity:1;transform:none}
}
@media (prefers-reduced-motion:reduce){
  .lightbox,.lb-body img,.toast,.rv{animation:none!important;transition:none!important;opacity:1!important;transform:none!important}
  .hdr{transition:none}
}


/* ---------- scroll politeness (t_browse01) ----------
   The bar leaves on the way down so the reader gets the whole screen, and
   returns the moment they scroll up. Transform only: no reflow, no CLS. */
.hdr{transform:translateY(0);will-change:transform;
  transition:transform 220ms cubic-bezier(.2,.6,.2,1),min-height 180ms cubic-bezier(.2,.6,.2,1),
  box-shadow 180ms ease,background-color 180ms ease,border-color 180ms ease}
body.hdr-hide .hdr{transform:translateY(-104%);box-shadow:none}

/* floating back-to-top: hidden until two screens in, 44px target */
.totop{
  position:fixed;right:max(var(--gutter),14px);bottom:calc(14px + env(safe-area-inset-bottom));
  z-index:44;width:44px;height:44px;display:grid;place-items:center;
  border-radius:50%;border:1px solid var(--line);
  background:var(--card);color:var(--accent);box-shadow:var(--shadow-md);
  cursor:pointer;opacity:0;transform:translateY(10px);pointer-events:none;
  transition:opacity 180ms ease,transform 180ms ease,background 150ms ease,color 150ms ease;
}
.totop svg{width:19px;height:19px}
.totop:hover{background:var(--accent);color:#fff}
.totop:focus-visible{outline:2px solid var(--accent-2);outline-offset:2px}
.totop.on{opacity:1;transform:none;pointer-events:auto}

@media (prefers-reduced-motion:reduce){
  .hdr,.totop{transition:none}
}
