/* =========================================================================
   NjoftimeSot — design system
   Extracted verbatim from docs/mockup/njoftimesot-app.html (THE UI reference).
   Tokens, components and responsive rules are the contract: extend here, never
   fork a second stylesheet.

   The mockup's SPA router rules (.page / .page.active / @keyframes pageIn) are
   intentionally omitted — this site is server-rendered, every page is its own
   document.

   Contents
     1. Tokens & reset          6. Detail page
     2. Header, drawer, nav     7. Forms (shared)
     3. Hero, notice, search    8. Create listing
     4. Sections & cards        9. Auth / contact / success
     5. Category page          10. Toast, footer, mobile CTA, responsive
   ========================================================================= */

:root{
  --wall:#F3F4EF;
  --paper:#FFFFFF;
  --ink:#141912;
  --ink-soft:#4A5346;
  --pine:#123A2C;
  --pine-deep:#0C291F;
  --sun:#FFCE1F;
  --sun-soft:#FFF3C4;
  --tomato:#E8503A;
  --line:#DCDFD4;
  --radius:14px;
  --shadow:0 1px 2px rgba(20,25,18,.05),0 8px 24px rgba(20,25,18,.08);
  --shadow-lift:0 2px 4px rgba(20,25,18,.08),0 16px 40px rgba(20,25,18,.14);
  --font-display:'Archivo Black',sans-serif;
  --font-head:'Archivo',sans-serif;
  --font-body:'Instrument Sans',sans-serif;
  --font-mono:'Spline Sans Mono',monospace;
}
*{margin:0;padding:0;box-sizing:border-box}
html{scroll-behavior:smooth}
body{font-family:var(--font-body);background:var(--wall);color:var(--ink);line-height:1.55;-webkit-font-smoothing:antialiased}
img,svg{display:block}
button{font-family:inherit;cursor:pointer;border:none;background:none;color:inherit}
a{color:inherit;text-decoration:none}
:focus-visible{outline:3px solid var(--sun);outline-offset:2px;border-radius:6px}
::selection{background:var(--sun);color:var(--ink)}
.wrap{max-width:1200px;margin:0 auto;padding:0 20px}

/* ============ Header ============ */
.topbar{position:sticky;top:0;z-index:60;background:rgba(243,244,239,.88);backdrop-filter:blur(12px);border-bottom:1px solid var(--line)}
.topbar-inner{display:flex;align-items:center;gap:24px;height:66px}
.logo{display:flex;align-items:center;gap:10px;flex-shrink:0}
.logo-mark{width:34px;height:34px;border-radius:9px;background:var(--pine);position:relative;flex-shrink:0}
.logo-mark::after{content:"";position:absolute;right:6px;top:6px;width:9px;height:9px;border-radius:50%;background:var(--sun)}
.logo-text{font-family:var(--font-head);font-weight:700;font-size:19px;letter-spacing:-.3px}
.logo-text b{color:var(--pine)}
.logo-text .dot{color:var(--tomato)}
.nav{display:flex;gap:4px;margin-left:8px}
.nav a{padding:8px 13px;border-radius:9px;font-weight:600;font-size:14.5px;color:var(--ink-soft);transition:background .15s,color .15s}
.nav a:hover,.nav a.active{background:#E9EBE1;color:var(--ink)}
.top-actions{margin-left:auto;display:flex;align-items:center;gap:10px}
.btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;font-weight:700;font-size:14.5px;border-radius:11px;padding:11px 18px;transition:transform .15s,box-shadow .15s,background .15s,filter .15s}
.btn:active{transform:scale(.97)}
.btn-ghost{color:var(--ink);border:1.5px solid var(--line);background:var(--paper)}
.btn-ghost:hover{border-color:var(--ink-soft)}
.btn-primary{background:var(--pine);color:#fff;box-shadow:var(--shadow)}
.btn-primary:hover{background:var(--pine-deep);box-shadow:var(--shadow-lift)}
.btn-sun{background:var(--sun);color:var(--ink);box-shadow:var(--shadow)}
.btn-sun:hover{filter:brightness(1.04);box-shadow:var(--shadow-lift)}
.btn-block{width:100%}
.btn-lg{padding:15px 24px;font-size:16px}
.hamburger{display:none;width:44px;height:44px;border-radius:11px;border:1.5px solid var(--line);background:var(--paper);align-items:center;justify-content:center;flex-direction:column;gap:5px}
.hamburger span{width:18px;height:2px;background:var(--ink);border-radius:2px;transition:transform .25s,opacity .25s}
.hamburger.open span:nth-child(1){transform:translateY(7px) rotate(45deg)}
.hamburger.open span:nth-child(2){opacity:0}
.hamburger.open span:nth-child(3){transform:translateY(-7px) rotate(-45deg)}
.drawer{display:none;position:fixed;inset:66px 0 0 0;z-index:55;background:var(--wall);padding:24px 20px;flex-direction:column;gap:6px;overflow:auto}
.drawer.open{display:flex}
.drawer a{padding:14px 12px;border-bottom:1px solid var(--line);font-weight:600;font-size:17px}
.drawer .btn{margin-top:16px}

/* ============ Breadcrumb ============ */
.crumbs{display:flex;align-items:center;gap:8px;flex-wrap:wrap;padding:22px 0 0;font-family:var(--font-mono);font-size:12.5px;color:var(--ink-soft)}
.crumbs a:hover{color:var(--ink);text-decoration:underline}
.crumbs .sep{opacity:.5}
.crumbs .cur{color:var(--ink);font-weight:600}

/* ============ Hero (home) ============ */
.hero{padding:52px 0 24px;position:relative;overflow:hidden}
.hero-grid{display:grid;grid-template-columns:1.15fr .85fr;gap:44px;align-items:start}
.eyebrow{display:inline-flex;align-items:center;gap:8px;font-family:var(--font-mono);font-size:12.5px;font-weight:600;letter-spacing:.08em;text-transform:uppercase;color:var(--pine);background:var(--sun-soft);border:1px solid #F0DD8A;padding:6px 12px;border-radius:999px;margin-bottom:20px}
.eyebrow .pulse{width:8px;height:8px;border-radius:50%;background:var(--tomato);animation:pulse 1.6s infinite}
@keyframes pulse{0%,100%{opacity:1;transform:scale(1)}50%{opacity:.4;transform:scale(.75)}}
.hero h1{font-family:var(--font-display);font-size:clamp(38px,5.2vw,64px);line-height:1.02;letter-spacing:-.5px;text-transform:uppercase}
.hero h1 .hl{display:inline-block;background:var(--sun);padding:0 12px 4px;border-radius:8px;transform:rotate(-1.2deg)}
.hero-sub{margin-top:20px;font-size:17px;color:var(--ink-soft);max-width:52ch}
.hero-cta{margin-top:26px;display:flex;gap:12px;flex-wrap:wrap}
.stat-row{display:flex;gap:28px;margin-top:36px;flex-wrap:wrap}
.stat{font-family:var(--font-mono)}
.stat b{font-size:26px;font-weight:600;display:block;line-height:1.1}
.stat span{font-size:12px;letter-spacing:.06em;text-transform:uppercase;color:var(--ink-soft)}

.notice{position:relative;background:var(--paper);border-radius:6px 6px 0 0;box-shadow:var(--shadow-lift);transform:rotate(1.4deg);padding:30px 28px 0;margin-top:8px}
.notice::before{content:"";position:absolute;top:-11px;left:50%;transform:translateX(-50%);width:22px;height:22px;border-radius:50%;background:radial-gradient(circle at 35% 30%,#FF7A66,var(--tomato) 60%);box-shadow:0 3px 6px rgba(20,25,18,.3)}
.notice-tag{font-family:var(--font-mono);font-size:11.5px;letter-spacing:.1em;text-transform:uppercase;color:var(--tomato);font-weight:600}
.notice h3{font-family:var(--font-head);font-weight:700;font-size:22px;margin:8px 0 6px;letter-spacing:-.3px}
.notice p{font-size:14.5px;color:var(--ink-soft)}
.notice-price{font-family:var(--font-mono);font-weight:600;font-size:24px;margin-top:14px;color:var(--pine)}
.notice-meta{display:flex;gap:14px;margin-top:10px;font-size:13px;color:var(--ink-soft)}
.tear-strips{display:flex;margin-top:22px;border-top:2px dashed var(--line)}
.tear{flex:1;padding:14px 4px 18px;text-align:center;border-right:2px dashed var(--line);font-family:var(--font-mono);font-size:10.5px;font-weight:600;letter-spacing:.04em;text-transform:uppercase;color:var(--ink-soft);writing-mode:vertical-rl;text-orientation:mixed;min-height:96px;transition:transform .2s,background .2s,color .2s;transform-origin:top center;background:var(--paper)}
.tear:last-child{border-right:none}
.tear:hover{transform:rotate(4deg) translateY(6px);background:var(--sun-soft);color:var(--ink)}
.tear.torn{transform:rotate(9deg) translateY(26px);opacity:.35;pointer-events:none}
.notice-hint{position:absolute;bottom:-34px;left:8px;font-family:var(--font-mono);font-size:11.5px;color:var(--ink-soft);display:flex;align-items:center;gap:6px}
.live-feed{margin-top:58px;background:var(--pine);color:#fff;border-radius:var(--radius);padding:16px 18px;transform:rotate(-.6deg);box-shadow:var(--shadow);font-family:var(--font-mono);font-size:13px;display:flex;align-items:center;gap:12px;overflow:hidden}
.live-feed .pulse{width:8px;height:8px;border-radius:50%;background:var(--sun);animation:pulse 1.6s infinite;flex-shrink:0}
#liveText{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;opacity:1;transition:opacity .35s}
#liveText.fade{opacity:0}

/* ============ Search ============ */
/* `auto`, not `0`, on the horizontal side. This element is also a `.wrap`,
   which centres itself with `margin:0 auto` — and a `margin` SHORTHAND here
   resets left/right to whatever it names. Writing `44px 0 8px` set them to 0,
   so the band pinned itself to the left edge of the viewport while every other
   .wrap on the page stayed centred. It shipped that way from phase 03, when
   the markup gained `.wrap`, until phase 19. If this rule ever needs to set
   only the vertical margins, use margin-block. */
.search-band{margin:44px auto 8px}
/* THREE columns for the three children the one shared partial renders:
   the q cell, the city+category pair, and the button. It used to declare
   four (for home's four direct children) and /kerko's wrapper faked the
   middle two with `grid-column:span 2` — so the day that override was not
   in the stylesheet a browser had cached, the pair collapsed into one
   column and the button stretched across the rest. The template and the
   column count now agree by construction (phase 19b). */
.search-box{background:var(--paper);border:1.5px solid var(--line);border-radius:18px;box-shadow:var(--shadow);display:grid;grid-template-columns:1.6fr 2fr auto;overflow:hidden}
.search-cell{display:flex;flex-direction:column;gap:2px;padding:14px 18px;border-right:1.5px solid var(--line)}
.search-cell label{font-family:var(--font-mono);font-size:10.5px;letter-spacing:.08em;text-transform:uppercase;color:var(--ink-soft)}
.search-cell input,.search-cell select{border:none;background:none;font-family:var(--font-body);font-size:15.5px;font-weight:600;color:var(--ink);outline:none}
.search-cell select{appearance:none;cursor:pointer}
.search-go{background:var(--sun);font-weight:800;font-size:15px;padding:0 30px;display:flex;align-items:center;gap:8px;transition:filter .15s}
.search-go:hover{filter:brightness(1.05)}

/* ============ Sections ============ */
section.block{padding:56px 0}
.sec-head{display:flex;align-items:end;justify-content:space-between;gap:20px;margin-bottom:28px;flex-wrap:wrap}
.sec-head h2{font-family:var(--font-display);font-size:clamp(24px,3vw,34px);text-transform:uppercase;letter-spacing:-.3px;line-height:1.1}
.sec-head .kicker{font-family:var(--font-mono);font-size:12px;letter-spacing:.1em;text-transform:uppercase;color:var(--tomato);font-weight:600;display:block;margin-bottom:8px}
.sec-link{font-weight:700;font-size:14.5px;color:var(--pine);display:inline-flex;align-items:center;gap:6px}
.sec-link:hover{text-decoration:underline}

/* categories */
.cat-grid{display:grid;grid-template-columns:repeat(6,1fr);gap:14px}
.cat{background:var(--paper);border:1.5px solid var(--line);border-radius:var(--radius);padding:20px 16px 18px;display:flex;flex-direction:column;gap:12px;transition:transform .18s,box-shadow .18s,border-color .18s}
.cat:hover{transform:translateY(-4px);box-shadow:var(--shadow-lift);border-color:var(--pine)}
.cat-icon{width:46px;height:46px;border-radius:12px;display:flex;align-items:center;justify-content:center}
.cat-icon svg,.icon-s svg{width:24px;height:24px;stroke:var(--ink);fill:none;stroke-width:1.9;stroke-linecap:round;stroke-linejoin:round}
.cat b{font-family:var(--font-head);font-weight:700;font-size:15px;letter-spacing:-.2px}
.cat span{font-family:var(--font-mono);font-size:11.5px;color:var(--ink-soft)}
.ci-1{background:#FFE8A3}.ci-2{background:#D9EAD9}.ci-3{background:#FBD8CF}
.ci-4{background:#DDE6F5}.ci-5{background:#EFE0F2}.ci-6{background:#E3EED2}

/* chips */
.chips{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:24px}
.chip{font-weight:700;font-size:13.5px;padding:9px 16px;border-radius:999px;background:var(--paper);border:1.5px solid var(--line);color:var(--ink-soft);transition:all .15s}
.chip:hover{border-color:var(--ink-soft);color:var(--ink)}
.chip.active{background:var(--ink);border-color:var(--ink);color:var(--sun)}

/* listing cards */
.list-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:18px}
.card{background:var(--paper);border-radius:var(--radius);overflow:hidden;border:1.5px solid var(--line);transition:transform .18s,box-shadow .18s;display:flex;flex-direction:column;position:relative;cursor:pointer}
.card:hover{transform:translateY(-4px);box-shadow:var(--shadow-lift)}
.card-media{aspect-ratio:4/3;position:relative;overflow:hidden;display:flex;align-items:center;justify-content:center}
.card-media svg.glyph{width:64px;height:64px;stroke:rgba(20,25,18,.55);fill:none;stroke-width:1.6;stroke-linecap:round;stroke-linejoin:round}
/* The diagonal hatch belongs to the PLACEHOLDER, never to a photograph.
   It was written as an unconditional ::after and therefore painted an
   18%-white lattice over every real listing image on the site — the cards
   looked washed out and nobody could point at which rule did it, because
   the element carrying the stripes is the one holding the <img>. Gated on
   a class the SERVER sets from whether a thumbnail exists, so the two can
   never disagree; `.is-placeholder` is the same signal that picks the
   gradient tint below (phase 19b). */
.card-media.is-placeholder::after{content:"";position:absolute;inset:0;background:repeating-linear-gradient(-45deg,transparent 0 14px,rgba(255,255,255,.18) 14px 28px)}
.m-auto1{background:linear-gradient(135deg,#D9EAD9,#B8D8BC)}
.m-auto2{background:linear-gradient(135deg,#DDE6F5,#BBCDE8)}
.m-auto3{background:linear-gradient(135deg,#FBD8CF,#F3BBAC)}
.m-prod{background:linear-gradient(135deg,#FFE8A3,#F5D671)}
.m-prona{background:linear-gradient(135deg,#EFE0F2,#DCC3E2)}
.m-pune{background:linear-gradient(135deg,#E3EED2,#CBDFAC)}
.m-sherb{background:linear-gradient(135deg,#D6EEF0,#B2DCE0)}
.m-kafshe{background:linear-gradient(135deg,#F5E3CB,#EACCA4)}
.badge{position:absolute;top:12px;left:12px;z-index:2;font-family:var(--font-mono);font-size:10.5px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;background:var(--ink);color:var(--sun);padding:5px 10px;border-radius:7px}
.badge.new{background:var(--tomato);color:#fff}
.fav{position:absolute;top:10px;right:10px;z-index:2;width:36px;height:36px;border-radius:10px;background:rgba(255,255,255,.9);backdrop-filter:blur(4px);display:flex;align-items:center;justify-content:center;transition:transform .15s}
.fav:hover{transform:scale(1.1)}
.fav svg{width:18px;height:18px;fill:none;stroke:var(--ink);stroke-width:2}
.fav.on svg{fill:var(--tomato);stroke:var(--tomato)}
.card-body{padding:16px 16px 18px;display:flex;flex-direction:column;gap:8px;flex:1}
.card-city{font-family:var(--font-mono);font-size:11px;letter-spacing:.06em;text-transform:uppercase;color:var(--ink-soft);display:flex;align-items:center;gap:6px}
.card-city::before{content:"";width:7px;height:7px;border-radius:50%;background:var(--pine)}
.card h3{font-family:var(--font-head);font-weight:700;font-size:15.5px;letter-spacing:-.2px;line-height:1.3}
.card-foot{margin-top:auto;display:flex;align-items:center;justify-content:space-between;padding-top:8px;gap:8px}
.price{font-family:var(--font-mono);font-weight:600;font-size:17px;color:var(--pine);background:var(--sun-soft);padding:4px 10px;border-radius:8px;border:1px solid #F0DD8A;white-space:nowrap}
.time{font-family:var(--font-mono);font-size:11px;color:var(--ink-soft)}
.empty{grid-column:1/-1;text-align:center;padding:60px 20px;background:var(--paper);border:1.5px dashed var(--line);border-radius:var(--radius);color:var(--ink-soft);font-weight:600}
.empty b{display:block;font-family:var(--font-head);font-size:19px;color:var(--ink);margin-bottom:6px}

/* steps */
.steps{display:grid;grid-template-columns:repeat(3,1fr);gap:18px}
.step{background:var(--paper);border:1.5px solid var(--line);border-radius:var(--radius);padding:28px 24px;position:relative;overflow:hidden}
.step-num{font-family:var(--font-display);font-size:56px;line-height:1;color:var(--sun);-webkit-text-stroke:1.5px var(--ink);margin-bottom:14px}
.step b{font-family:var(--font-head);font-weight:700;font-size:17px;display:block;margin-bottom:8px}
.step p{font-size:14.5px;color:var(--ink-soft)}

/* biz */
.biz{background:var(--pine);border-radius:22px;color:#fff;padding:56px 48px;position:relative;overflow:hidden}
.biz::before{content:"";position:absolute;right:-60px;top:-60px;width:260px;height:260px;border-radius:50%;background:var(--sun);opacity:.14}
.biz::after{content:"";position:absolute;right:40px;bottom:-90px;width:200px;height:200px;border-radius:50%;border:2px dashed rgba(255,255,255,.25)}
.biz h2{font-family:var(--font-display);font-size:clamp(24px,3vw,36px);text-transform:uppercase;max-width:20ch;line-height:1.1}
.biz p{margin:16px 0 26px;opacity:.85;max-width:48ch}

/* ============ Category page ============ */
.cat-hero{padding:34px 0 26px;border-bottom:1px solid var(--line)}
.cat-hero-inner{display:flex;align-items:center;gap:18px;flex-wrap:wrap}
.cat-hero .cat-icon{width:58px;height:58px;border-radius:16px}
.cat-hero .cat-icon svg{width:30px;height:30px}
.cat-hero h1{font-family:var(--font-display);font-size:clamp(26px,3.6vw,42px);text-transform:uppercase;letter-spacing:-.4px;line-height:1.05}
.cat-hero .count{font-family:var(--font-mono);font-size:13px;color:var(--ink-soft)}
/* The landing's one-sentence summary (phase 19). Measured, not decorative:
   ~64ch is where a line stops being scannable next to a 42px display heading. */
.cat-blurb{margin-top:10px;max-width:64ch;font-size:15px;line-height:1.55;color:var(--ink-soft)}
.city-strip-head{font-family:var(--font-mono);font-size:11px;letter-spacing:.1em;text-transform:uppercase;color:var(--ink-soft);margin-bottom:10px}
/* The city you are already on: a chip, so the strip reads as one row, but not a
   link to the page you are looking at. */
.chip.is-current{background:var(--ink);border-color:var(--ink);color:var(--sun);cursor:default}
.cat-layout{display:grid;grid-template-columns:260px 1fr;gap:32px;padding:32px 0 64px}
.filters{position:sticky;top:86px;align-self:start;display:flex;flex-direction:column;gap:22px}
.filters-body{display:flex;flex-direction:column;gap:22px}

/* The sheet's chrome exists in the markup at every width so the same DOM serves
   both modes; on desktop it is simply not shown (phase 14). */
.filters-head,.sheet-foot,.sheet-backdrop,.filter-pill{display:none}

/* /kerko wraps its city and category cells in a .filters panel so the SAME
   nodes can become the bottom sheet ≤780px — the cells move, they are never
   duplicated, which is what keeps one GET form with one copy of each name
   (phase 19). On desktop the wrapper spans the two grid columns those cells
   used to occupy, so the band renders exactly as before; the home page, which
   still has four direct children in its .search-box, is untouched.
   Specificity is deliberately equal to `.filters` and the rule sits AFTER it,
   so the ≤780px sheet rules further down still win. */
.search-filters{display:grid;grid-template-columns:1fr 1fr;position:static;gap:0;min-width:0}
.search-filters .filters-body{display:contents}
.search-hint{max-width:62ch;margin:-8px 0 26px;color:var(--ink-soft);font-size:15px;line-height:1.6}
.filter-box{background:var(--paper);border:1.5px solid var(--line);border-radius:var(--radius);padding:18px}
.filter-box h4{font-family:var(--font-mono);font-size:11px;letter-spacing:.1em;text-transform:uppercase;color:var(--ink-soft);margin-bottom:12px}
.f-opt{display:flex;align-items:center;gap:10px;padding:7px 4px;border-radius:8px;font-weight:600;font-size:14px;cursor:pointer;transition:background .12s}
.f-opt:hover{background:var(--wall)}
.f-opt input{accent-color:var(--pine);width:16px;height:16px;cursor:pointer}
.f-range{display:flex;gap:8px;align-items:center}
.f-range input{width:100%;border:1.5px solid var(--line);border-radius:9px;padding:9px 10px;font-family:var(--font-mono);font-size:13px;background:var(--wall)}
.f-range span{color:var(--ink-soft)}
/* The filter's own currency (phase 16). Sits under the two bounds rather than
   beside them: the sidebar column is ~230px and a third control on that row
   squeezes both numbers below three digits. */
.f-currency{margin-top:8px;width:auto;padding:8px 30px 8px 12px;font-family:var(--font-mono);font-size:13px;background-color:var(--wall);background-position:right 10px center;border-radius:9px}
.filter-apply{margin-top:4px}
.cat-toolbar{display:flex;align-items:center;justify-content:space-between;gap:14px;margin-bottom:20px;flex-wrap:wrap}
.result-count{font-family:var(--font-mono);font-size:13px;color:var(--ink-soft)}
.sort-wrap{display:flex;align-items:center;gap:8px;font-size:13.5px;font-weight:600}
.sort-wrap select{border:1.5px solid var(--line);border-radius:9px;padding:8px 12px;font-family:var(--font-body);font-weight:600;font-size:13.5px;background:var(--paper);cursor:pointer}
.cat-list-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:16px}

/* ============ Detail page ============ */
.detail-layout{display:grid;grid-template-columns:1.6fr 1fr;gap:32px;padding:26px 0 64px;align-items:start}
.gallery{background:var(--paper);border:1.5px solid var(--line);border-radius:var(--radius);overflow:hidden}
.gallery-main{aspect-ratio:16/10;position:relative;display:flex;align-items:center;justify-content:center;transition:background .3s}
/* Same rule, same reason, on the listing page's hero photo. */
.gallery-main.is-placeholder::after{content:"";position:absolute;inset:0;background:repeating-linear-gradient(-45deg,transparent 0 18px,rgba(255,255,255,.16) 18px 36px)}
.gallery-main svg{width:110px;height:110px;stroke:rgba(20,25,18,.5);fill:none;stroke-width:1.4;stroke-linecap:round;stroke-linejoin:round;z-index:1}
.gallery-main .badge{top:16px;left:16px}
.thumbs{display:flex;gap:10px;padding:12px}
.thumb{width:76px;height:58px;border-radius:9px;border:2px solid transparent;overflow:hidden;position:relative;cursor:pointer;flex-shrink:0;display:flex;align-items:center;justify-content:center}
.thumb svg{width:26px;height:26px;stroke:rgba(20,25,18,.5);fill:none;stroke-width:1.7}
.thumb.sel{border-color:var(--pine)}
.detail-body{background:var(--paper);border:1.5px solid var(--line);border-radius:var(--radius);padding:26px;margin-top:20px}
.detail-body h2{font-family:var(--font-head);font-weight:700;font-size:19px;margin-bottom:14px;letter-spacing:-.2px}
.detail-body p{color:var(--ink-soft);font-size:15px}
.spec-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:0 24px;margin-top:6px}
.spec{display:flex;justify-content:space-between;gap:12px;padding:11px 0;border-bottom:1px dashed var(--line);font-size:14px}
.spec span{color:var(--ink-soft)}
.spec b{font-family:var(--font-mono);font-weight:600}
.aside{position:sticky;top:86px;display:flex;flex-direction:column;gap:18px}
.buy-box{background:var(--paper);border:1.5px solid var(--line);border-radius:var(--radius);padding:24px;box-shadow:var(--shadow)}
.buy-box .card-city{margin-bottom:8px}
.buy-box h1{font-family:var(--font-head);font-weight:700;font-size:21px;letter-spacing:-.3px;line-height:1.3;margin-bottom:14px}
.buy-price{font-family:var(--font-mono);font-weight:600;font-size:30px;color:var(--pine);margin-bottom:4px}
/* The «≈ … L me kursin e sotëm» line (phase 16). Deliberately quiet: it is an
   aid, not the price — the price is what the seller typed, one line up. */
.buy-approx{font-family:var(--font-mono);font-size:12.5px;color:var(--ink-soft);margin:-2px 0 4px}
.buy-meta{font-family:var(--font-mono);font-size:12px;color:var(--ink-soft);display:flex;gap:14px;margin-bottom:18px}
.buy-actions{display:flex;flex-direction:column;gap:10px}
.seller-box{background:var(--paper);border:1.5px solid var(--line);border-radius:var(--radius);padding:20px}
.seller-head{display:flex;align-items:center;gap:14px;margin-bottom:14px}
.avatar{width:48px;height:48px;border-radius:50%;background:var(--sun);display:flex;align-items:center;justify-content:center;font-family:var(--font-display);font-size:18px;flex-shrink:0}
.seller-head b{font-family:var(--font-head);font-weight:700;font-size:15.5px;display:block}
.seller-head span{font-family:var(--font-mono);font-size:11.5px;color:var(--ink-soft)}
.msg-form{display:flex;flex-direction:column;gap:10px;margin-top:6px}
.msg-form textarea{border:1.5px solid var(--line);border-radius:11px;padding:12px 14px;font-family:var(--font-body);font-size:14.5px;resize:vertical;min-height:84px;background:var(--wall)}
.safety{background:var(--sun-soft);border:1px solid #F0DD8A;border-radius:var(--radius);padding:16px 18px;font-size:13.5px;color:var(--ink-soft)}
.safety b{color:var(--ink);display:block;margin-bottom:4px;font-family:var(--font-head)}
.similar{padding:0 0 64px}

/* ============ Forms shared ============ */
.field{display:flex;flex-direction:column;gap:7px;margin-bottom:18px}
.field label{font-weight:700;font-size:14px}
.field .hint{font-family:var(--font-mono);font-size:11.5px;color:var(--ink-soft);font-weight:400}
.input,.select,.textarea{border:1.5px solid var(--line);border-radius:11px;padding:13px 15px;font-family:var(--font-body);font-size:15px;background:var(--paper);color:var(--ink);width:100%;transition:border-color .15s}
.input:focus,.select:focus,.textarea:focus{outline:none;border-color:var(--pine)}
.textarea{resize:vertical;min-height:120px}
.select{appearance:none;cursor:pointer;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8'%3E%3Cpath d='M1 1l5 5 5-5' stroke='%234A5346' stroke-width='2' fill='none' stroke-linecap='round'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right 15px center}
.field-row{display:grid;grid-template-columns:1fr 1fr;gap:16px}
/* Amount + currency are one control (phase 16). The select is sized to its
   widest symbol plus the chevron the .select background paints, and both
   children are min-width:0 so the amount can shrink inside a grid column
   rather than pushing the select out of it. */
.price-input{display:grid;grid-template-columns:1fr 74px;gap:8px}
.price-input > *{min-width:0}
.price-input .select{padding-left:13px;padding-right:30px;background-position:right 10px center;text-align:center}
.form-err{color:var(--tomato);font-size:13px;font-weight:600;display:none}
.field.invalid .input,.field.invalid .select{border-color:var(--tomato)}
.field.invalid .form-err{display:block}

/* ============ Create listing ============ */
.create-layout{display:grid;grid-template-columns:1.5fr 1fr;gap:36px;padding:32px 0 64px;align-items:start}
.form-card{background:var(--paper);border:1.5px solid var(--line);border-radius:18px;padding:30px;box-shadow:var(--shadow)}
.form-card h2{font-family:var(--font-head);font-weight:700;font-size:19px;margin-bottom:20px;display:flex;align-items:center;gap:10px}
.form-card h2 .n{width:28px;height:28px;border-radius:50%;background:var(--sun);font-family:var(--font-display);font-size:13px;display:inline-flex;align-items:center;justify-content:center;flex-shrink:0}
.form-card + .form-card{margin-top:22px}
.dynamic-fields-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:0 16px}
.dynamic-field{min-width:0}
.dynamic-field .select:disabled{cursor:not-allowed;background-color:var(--wall);color:var(--ink-soft);opacity:.72}
.field-dependency-hint{font-family:var(--font-mono);font-size:11.5px;color:var(--ink-soft)}
.field-dependency-hint[hidden]{display:none}
/* Choices.js follows the native form language while keeping its select closed. */
.dynamic-field .choices{margin:0}
.dynamic-field .choices__inner{min-height:48px;border:1.5px solid var(--line);border-radius:11px;
  background:var(--paper);padding:7px 38px 5px 10px;font-family:var(--font-body);font-size:15px}
.dynamic-field .is-focused .choices__inner,.dynamic-field .is-open .choices__inner{
  border-color:var(--pine);box-shadow:0 0 0 3px #EAF2ED}
.dynamic-field .choices.is-open .choices__inner{border-radius:11px}
.dynamic-field .choices__list--single{padding:5px 8px}
.dynamic-field .choices__input{background:var(--paper);border:1.5px solid var(--line);border-radius:9px;
  padding:10px 12px;margin:8px;width:calc(100% - 16px);font-family:var(--font-body);font-size:14px}
.dynamic-field .choices__list--dropdown,.dynamic-field .choices__list[aria-expanded]{
  z-index:80;margin-top:6px;border:1.5px solid var(--line);border-radius:11px;background:var(--paper);
  box-shadow:var(--shadow-lift)}
.dynamic-field .choices__list--dropdown .choices__item,.dynamic-field .choices__list[aria-expanded] .choices__item{
  padding:10px 12px;font-size:14px;word-break:normal}
.dynamic-field .choices__list--dropdown .choices__item--selectable.is-highlighted,
.dynamic-field .choices__list[aria-expanded] .choices__item--selectable.is-highlighted{background:var(--sun-soft)}
.dynamic-field .choices__list--multiple .choices__item{background:var(--pine);border-color:var(--pine);
  color:#fff;border-radius:999px}
.dynamic-field .choices.is-disabled .choices__inner{background:var(--wall);opacity:.72}
.cat-pick{display:grid;grid-template-columns:repeat(3,1fr);gap:10px}
.cat-pick button{border:1.5px solid var(--line);border-radius:11px;padding:14px 10px;display:flex;flex-direction:column;align-items:center;gap:8px;font-weight:700;font-size:12.5px;background:var(--wall);transition:all .15s}
.cat-pick button:hover{border-color:var(--ink-soft)}
.cat-pick button.sel{border-color:var(--pine);background:var(--sun-soft)}
.cat-pick .cat-icon{width:38px;height:38px;border-radius:10px}
.cat-pick .cat-icon svg{width:20px;height:20px}
/* The dashed container holds everything about photos: the CTA, the helper
   line, the thumbs and the counter. It was a <label>, which is INLINE, so the
   border drew itself around the text runs instead of around the block and the
   counter fell outside it (phase 14). The label is now a block child. */
.dropzone{border:2px dashed var(--line);border-radius:14px;padding:22px 20px;text-align:center;
  color:var(--ink-soft);font-weight:600;transition:border-color .15s,background .15s}
.dropzone:hover,.dropzone:focus-within{border-color:var(--pine);background:var(--sun-soft)}
.dropzone-cta{display:block;cursor:pointer;padding:10px 0}
.dropzone-cta b{display:block;color:var(--ink);font-family:var(--font-head);margin-bottom:4px}
.dropzone-hint{display:block;font-size:13px;line-height:1.5;font-weight:600}
.dropzone .photo-row{justify-content:center}
.dropzone .photo-count{margin-top:12px;font-family:var(--font-mono);font-size:11.5px;
  letter-spacing:.04em;color:var(--ink-soft)}
.dropzone .form-errors{text-align:left;margin-bottom:12px}
.photo-row{display:flex;gap:10px;flex-wrap:wrap;margin-top:14px}
.photo-slot{width:82px;height:64px;border-radius:10px;position:relative;display:flex;align-items:center;justify-content:center;overflow:hidden}
.photo-slot svg{width:24px;height:24px;stroke:rgba(20,25,18,.45);fill:none;stroke-width:1.8}
.photo-slot .rm{position:absolute;top:3px;right:3px;width:20px;height:20px;border-radius:6px;background:rgba(20,25,18,.75);color:#fff;font-size:11px;display:flex;align-items:center;justify-content:center}
.photo-slot.main::after{content:"KRYESORE";position:absolute;bottom:0;left:0;right:0;background:var(--ink);color:var(--sun);font-family:var(--font-mono);font-size:8px;letter-spacing:.06em;text-align:center;padding:2px 0}
.preview-sticky{position:sticky;top:86px}
.preview-label{font-family:var(--font-mono);font-size:11.5px;letter-spacing:.1em;text-transform:uppercase;color:var(--ink-soft);margin-bottom:12px;display:flex;align-items:center;gap:8px}
.preview-label::before{content:"";width:8px;height:8px;border-radius:50%;background:var(--tomato);animation:pulse 1.6s infinite}
.preview-card-wrap{transform:rotate(1deg)}
.preview-tip{margin-top:20px;background:var(--paper);border:1.5px solid var(--line);border-radius:var(--radius);padding:16px 18px;font-size:13.5px;color:var(--ink-soft)}
.preview-tip b{color:var(--ink);font-family:var(--font-head)}

/* ============ Auth pages ============ */
.auth-wrap{min-height:calc(100vh - 66px);display:grid;grid-template-columns:1fr 1fr;align-items:stretch}
.auth-side{background:var(--pine);color:#fff;padding:64px 56px;display:flex;flex-direction:column;justify-content:space-between;position:relative;overflow:hidden}
.auth-side::before{content:"";position:absolute;left:-80px;bottom:-80px;width:300px;height:300px;border-radius:50%;background:var(--sun);opacity:.13}
.auth-side::after{content:"";position:absolute;right:-40px;top:60px;width:180px;height:180px;border-radius:50%;border:2px dashed rgba(255,255,255,.22)}
.auth-side h2{font-family:var(--font-display);font-size:clamp(26px,3vw,40px);text-transform:uppercase;line-height:1.08;max-width:16ch}
.auth-side h2 .hl{background:var(--sun);color:var(--ink);padding:0 10px 3px;border-radius:7px;display:inline-block;transform:rotate(-1.2deg)}
.auth-quote{font-family:var(--font-mono);font-size:13px;opacity:.8;max-width:40ch;position:relative;z-index:1}
.auth-form-col{display:flex;align-items:center;justify-content:center;padding:48px 24px}
.auth-card{width:100%;max-width:420px}
.auth-card h1{font-family:var(--font-display);font-size:28px;text-transform:uppercase;margin-bottom:8px}
.auth-card .sub{color:var(--ink-soft);margin-bottom:28px;font-size:15px}
.auth-card .sub a{color:var(--pine);font-weight:700}
.auth-card .sub a:hover{text-decoration:underline}
.pass-wrap{position:relative}
.pass-wrap .input{padding-right:74px}
.pass-toggle{position:absolute;right:8px;top:50%;transform:translateY(-50%);font-family:var(--font-mono);font-size:11.5px;font-weight:600;letter-spacing:.05em;color:var(--pine);padding:6px 10px;border-radius:7px}
.pass-toggle:hover{background:var(--sun-soft)}
.auth-extra{display:flex;justify-content:space-between;align-items:center;margin:-6px 0 20px;font-size:13.5px}
.auth-extra label{display:flex;gap:8px;align-items:center;font-weight:600;cursor:pointer}
.auth-extra input{accent-color:var(--pine)}
.auth-extra a{color:var(--pine);font-weight:700}
.divider{display:flex;align-items:center;gap:14px;margin:22px 0;color:var(--ink-soft);font-family:var(--font-mono);font-size:11.5px;text-transform:uppercase;letter-spacing:.08em}
.divider::before,.divider::after{content:"";flex:1;height:1px;background:var(--line)}
.acct-type{display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-bottom:18px}
.acct-type button{border:1.5px solid var(--line);border-radius:11px;padding:14px;font-weight:700;font-size:14px;background:var(--wall);display:flex;flex-direction:column;gap:3px;align-items:flex-start;transition:all .15s}
.acct-type button span{font-weight:400;font-size:12px;color:var(--ink-soft);font-family:var(--font-mono)}
.acct-type button.sel{border-color:var(--pine);background:var(--sun-soft)}

/* ============ Contact ============ */
.contact-layout{display:grid;grid-template-columns:1fr 1.3fr;gap:36px;padding:40px 0 72px;align-items:start}
.contact-info h1{font-family:var(--font-display);font-size:clamp(28px,3.4vw,44px);text-transform:uppercase;line-height:1.05;margin-bottom:18px}
.contact-info>p{color:var(--ink-soft);font-size:16px;max-width:42ch;margin-bottom:30px}
.c-item{display:flex;gap:16px;align-items:flex-start;padding:16px 0;border-top:1px dashed var(--line)}
.c-item .cat-icon{width:42px;height:42px;border-radius:11px;flex-shrink:0}
.c-item .cat-icon svg{width:20px;height:20px}
.c-item b{font-family:var(--font-head);font-weight:700;display:block;font-size:15px}
.c-item span{font-family:var(--font-mono);font-size:13px;color:var(--ink-soft)}

/* ============ Success state ============ */
.success{max-width:560px;margin:70px auto;text-align:center;background:var(--paper);border:1.5px solid var(--line);border-radius:22px;padding:56px 40px;box-shadow:var(--shadow)}
.success .big{width:84px;height:84px;border-radius:50%;background:var(--sun);margin:0 auto 24px;display:flex;align-items:center;justify-content:center;font-size:38px;animation:pop .45s cubic-bezier(.68,-0.55,.27,1.55)}
@keyframes pop{from{transform:scale(0)}to{transform:scale(1)}}
.success h2{font-family:var(--font-display);font-size:26px;text-transform:uppercase;margin-bottom:10px}
.success p{color:var(--ink-soft);margin-bottom:26px}
.success .btn-row{display:flex;gap:12px;justify-content:center;flex-wrap:wrap}

/* ============ Toast ============ */
.toast{position:fixed;left:50%;bottom:28px;transform:translateX(-50%) translateY(20px);z-index:100;background:var(--ink);color:#fff;font-weight:600;font-size:14.5px;padding:14px 22px;border-radius:12px;box-shadow:var(--shadow-lift);opacity:0;pointer-events:none;transition:opacity .25s,transform .25s;display:flex;align-items:center;gap:10px;max-width:calc(100vw - 40px)}
.toast.show{opacity:1;transform:translateX(-50%) translateY(0)}
.toast .dot{width:9px;height:9px;border-radius:50%;background:var(--sun);flex-shrink:0}

/* ============ Footer ============ */
footer{background:var(--ink);color:#C9CEC2;padding:56px 0 32px;margin-top:auto}
.foot-grid{display:grid;grid-template-columns:1.4fr 1fr 1fr 1fr;gap:36px;margin-bottom:44px}
.foot-grid h4{font-family:var(--font-mono);font-size:11.5px;letter-spacing:.1em;text-transform:uppercase;color:var(--sun);margin-bottom:16px}
.foot-grid a{display:block;padding:5px 0;font-size:14.5px;transition:color .15s}
.foot-grid a:hover{color:#fff}
.foot-brand p{margin-top:14px;font-size:14px;max-width:34ch;opacity:.75}
.foot-bottom{border-top:1px solid rgba(255,255,255,.12);padding-top:24px;display:flex;justify-content:space-between;gap:16px;flex-wrap:wrap;font-family:var(--font-mono);font-size:12px;opacity:.65}

.mob-cta{display:none;position:fixed;left:0;right:0;bottom:0;z-index:50;padding:12px 16px calc(12px + env(safe-area-inset-bottom));background:rgba(243,244,239,.92);backdrop-filter:blur(12px);border-top:1px solid var(--line)}
.mob-cta .btn{width:100%;font-size:16px;padding:15px}

/* ============ Responsive ============ */
@media (max-width:1020px){
  .cat-grid{grid-template-columns:repeat(3,1fr)}
  .list-grid{grid-template-columns:repeat(3,1fr)}
  .cat-list-grid{grid-template-columns:repeat(2,1fr)}
  .hero-grid{grid-template-columns:1fr;gap:36px}
  .notice{max-width:520px;margin:24px auto 0}
  .live-feed{max-width:520px;margin:58px auto 0}
  .foot-grid{grid-template-columns:1fr 1fr}
  .detail-layout{grid-template-columns:1fr}
  .aside{position:static}
  .cat-layout{grid-template-columns:1fr}
  .filters{position:static}
  .filters-body{flex-direction:row;flex-wrap:wrap}
  .filter-box{flex:1;min-width:220px}
  .create-layout{grid-template-columns:1fr}
  .preview-sticky{position:static}
  .auth-wrap{grid-template-columns:1fr}
  .auth-side{display:none}
  .contact-layout{grid-template-columns:1fr}
}
@media (max-width:780px){
  .nav{display:none}
  .top-actions .btn-ghost{display:none}
  .top-actions .btn-primary{display:none}
  .hamburger{display:flex}
  .search-box{grid-template-columns:1fr}
  .search-cell{border-right:none;border-bottom:1.5px solid var(--line)}
  .search-go{padding:16px;justify-content:center}
  .list-grid{grid-template-columns:repeat(2,1fr);gap:12px}
  .cat-list-grid{grid-template-columns:repeat(2,1fr);gap:12px}
  .steps{grid-template-columns:1fr}
  .biz{padding:40px 26px}
  .mob-cta{display:block}
  body{padding-bottom:76px}
  section.block{padding:44px 0}
  .spec-grid{grid-template-columns:1fr}
  .field-row,.dynamic-fields-grid{grid-template-columns:1fr}
  .cat-pick{grid-template-columns:repeat(2,1fr)}
  /* The wizard's step headings carry a long hint; without wrap the flex row
     pushes it off to the side and the number loses its heading (phase 14). */
  .form-card h2{flex-wrap:wrap}

  /* ---- filters as a bottom sheet (phase 14) ----
     The sidebar leaves the flow entirely: a phone user scrolled past the whole
     filter set — 1 561px of it on Apartamente — before the first listing. */
  /* In the band (home and /kerko) the pill is a normal block-level row under
     the q cell; above a result grid (category page) it sticks. Same element,
     two placements — .band-pill is what tells them apart. */
  .band-pill{position:static;margin:12px 0 0;align-self:start}
  .filter-pill{display:inline-flex;position:sticky;top:8px;z-index:40;align-items:center;gap:8px;
    margin-bottom:14px;padding:10px 16px;border-radius:999px;background:var(--ink);color:#fff;
    font-family:var(--font-head);font-size:14px;font-weight:700;cursor:pointer;
    box-shadow:var(--shadow-lift)}
  .filter-pill svg{width:17px;height:17px;stroke:currentColor;fill:none;stroke-width:2;
    stroke-linecap:round}
  .filter-pill-count{background:var(--sun);color:var(--ink);font-family:var(--font-mono);
    font-size:11.5px;border-radius:999px;padding:1px 8px}

  .filters{position:fixed;left:0;right:0;bottom:0;top:auto;z-index:70;
    max-height:86vh;background:var(--paper);border-radius:22px 22px 0 0;
    box-shadow:0 -14px 40px rgba(20,25,18,.22);
    transform:translateY(100%);transition:transform .28s ease;
    display:flex;flex-direction:column;gap:0;padding:0;overflow:hidden;visibility:hidden}
  .filters-switch:checked ~ .sheet-host .filters{transform:translateY(0);visibility:visible}

  .filters-head{display:flex;align-items:center;gap:10px;padding:8px 18px 12px;
    border-bottom:1.5px solid var(--line);position:relative;touch-action:none}
  .filters-head b{font-family:var(--font-head);font-size:16px;flex:1;text-align:center}
  .sheet-grip{position:absolute;top:8px;left:50%;transform:translateX(-50%);
    width:44px;height:5px;border-radius:3px;background:var(--line)}
  .sheet-close{width:34px;height:34px;border-radius:10px;display:flex;align-items:center;
    justify-content:center;cursor:pointer;color:var(--ink-soft);margin-top:8px}
  .filters-head b{margin-top:8px}

  .filters-body{flex:1;overflow-y:auto;-webkit-overflow-scrolling:touch;
    padding:16px 18px;flex-direction:column;flex-wrap:nowrap;gap:18px}
  .filters-body .filter-box{flex:none;min-width:0}
  /* display:contents put the two cells straight into the band on desktop;
     inside the sheet the body is a real scrolling column again. */
  .search-filters .filters-body{display:flex}

  .sheet-foot{display:grid;grid-template-columns:auto 1fr;gap:10px;padding:12px 18px;
    padding-bottom:calc(12px + env(safe-area-inset-bottom));
    border-top:1.5px solid var(--line);background:var(--paper)}
  .sheet-apply{cursor:pointer}

  .sheet-backdrop{position:fixed;inset:0;z-index:60;background:rgba(20,25,18,.45);
    opacity:0;pointer-events:none;transition:opacity .28s ease}
  .filters-switch:checked ~ .sheet-host .sheet-backdrop{display:block;opacity:1;pointer-events:auto}

  /* The sticky bottom CTA and the sheet must not share the screen. The
     :has() rule covers the no-JS path (the CTA is not a sibling of the
     checkbox); body.sheet-open is what app.js sets, and one of the two always
     applies. */
  body:has(.filters-switch:checked) .mob-cta,body.sheet-open .mob-cta{display:none}
}

/* Someone who asked for less motion gets the sheet without the slide. */
@media (max-width:780px) and (prefers-reduced-motion:reduce){
  .filters,.sheet-backdrop{transition:none}
}
@media (max-width:520px){
  .list-grid{grid-template-columns:1fr}
  .cat-list-grid{grid-template-columns:1fr}
  .cat-grid{grid-template-columns:repeat(2,1fr)}
  .stat-row{gap:20px}
  .hero{padding-top:36px}
  .tear{min-height:82px}
  .foot-grid{grid-template-columns:1fr}
  .form-card{padding:22px 18px}
}
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{animation:none!important;transition:none!important}
  html{scroll-behavior:auto}
}

/* =========================================================================
   Server-rendered adjustments (not in the mockup)
   The mockup was a single-document SPA, so `footer{margin-top:auto}` never had
   a flex parent to resolve against. Real pages vary in height, so give the body
   a column layout and let main grow — the footer then sticks to the bottom on
   short pages and flows naturally on long ones.
   ========================================================================= */
body{display:flex;flex-direction:column;min-height:100vh}
body > main{flex:1 0 auto}
.skip-link{position:absolute;left:-9999px;top:0;z-index:100;background:var(--pine);color:#fff;font-weight:700;padding:12px 18px;border-radius:0 0 11px 0}
.skip-link:focus{left:0}

/* =========================================================================
   Phase 03 — components the mockup implies but does not spell out
   ========================================================================= */

/* Card images fill the media box; the mockup used gradient placeholders. */
.card-media img{width:100%;height:100%;object-fit:cover}
.card h3 a{display:block}
.card h3 a:hover{text-decoration:underline}
.card-excerpt{font-size:13.5px;color:var(--ink-soft);line-height:1.45}
.card-excerpt mark{background:var(--sun);color:var(--ink);padding:0 2px;border-radius:3px}
/* A listing with no amount still needs a chip, just a quieter one. */
.price-soft{color:var(--ink-soft);background:var(--wall);border-color:var(--line);font-size:14px}
.buy-price-soft{font-size:22px;color:var(--ink-soft)}

/* Category subtree chips are links, not buttons. */
a.chip{display:inline-flex;align-items:center;gap:6px}

/* Pagination */
.pager{display:flex;align-items:center;justify-content:center;gap:8px;flex-wrap:wrap;padding:34px 0 8px}
.pager-num{font-family:var(--font-mono);font-size:14px;font-weight:600;min-width:40px;height:40px;
  display:inline-flex;align-items:center;justify-content:center;border:1.5px solid var(--line);
  border-radius:10px;background:var(--paper);transition:border-color .15s,background .15s}
.pager-num:hover{border-color:var(--ink-soft)}
.pager-num.active{background:var(--ink);border-color:var(--ink);color:var(--sun)}

/* Phone reveal — replaces the button in place via HTMX. */
.phone-reveal{display:flex;flex-direction:column;gap:6px}
.phone-reveal span{font-family:var(--font-mono);font-size:11.5px;color:var(--ink-soft)}
.phone-reveal b{font-family:var(--font-head);font-size:15px}
.phone-reveal-limited{background:var(--sun-soft);border:1px solid #F0DD8A;border-radius:var(--radius);padding:14px 16px}

/* Report form lives in a <details> so it costs nothing until opened. */
.report-box{background:var(--paper);border:1.5px solid var(--line);border-radius:var(--radius);padding:16px 18px}
.report-box summary{font-weight:700;font-size:14px;cursor:pointer;list-style:none}
.report-box summary::-webkit-details-marker{display:none}
.report-box summary:hover{color:var(--tomato)}
.report-box .msg-form{margin-top:12px}
.report-ok{color:var(--pine);font-weight:600;font-size:13.5px}
.report-err{color:var(--tomato);font-weight:600;font-size:13.5px}

/* Honeypot: off-screen for people, present in the DOM for bots. */
.hp{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}
.visually-hidden{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;
  clip:rect(0 0 0 0);white-space:nowrap;border:0}

/* Gallery: real images replace the mockup's glyph placeholders. */
.gallery-main img{position:absolute;inset:0}
.thumb img{width:100%;height:100%;object-fit:cover}
.thumb:focus-visible{border-color:var(--pine)}

/* Tear-off strips are links now, so they need the button reset. */
a.tear{display:block;text-decoration:none}

/* HTMX in-flight feedback: dim the grid being replaced. */
.htmx-request.list-grid,.htmx-request.cat-list-grid,#catResults.htmx-request{opacity:.5;transition:opacity .15s}

/* Long unbroken words (legacy titles, URLs in descriptions) must never widen
   the page on a 390px screen. */
.crumbs .cur,.card h3,.buy-box h1,.detail-body p{overflow-wrap:anywhere}

/* =========================================================================
   Phase 05 — auth, account, admin
   ========================================================================= */

/* Account-type picker. The mockup drew it with <button>s; here it is a real
   radio group so it works with JS off and announces as a radiogroup. The radio
   itself is visually hidden and the styling hangs off :checked. */
.acct-option{border:1.5px solid var(--line);border-radius:11px;padding:14px;font-weight:700;
  font-size:14px;background:var(--wall);display:flex;flex-direction:column;gap:3px;
  align-items:flex-start;cursor:pointer;transition:border-color .15s,background .15s}
.acct-option span{font-weight:400;font-size:12px;color:var(--ink-soft);font-family:var(--font-mono)}
.acct-type label{display:block}
.acct-type input:checked + .acct-option{border-color:var(--pine);background:var(--sun-soft)}
/* Keyboard users tab to the radio, which is off-screen — move the ring onto
   the thing they can actually see. */
.acct-type input:focus-visible + .acct-option{outline:2px solid var(--pine);outline-offset:2px}

/* Validation summary above a form. role="alert", so it is also announced. */
.form-errors{background:#FDECE8;border:1.5px solid var(--tomato);border-radius:var(--radius);
  padding:12px 16px;margin-bottom:18px}
.form-errors p{color:#9B2C18;font-size:14px;font-weight:600;line-height:1.5}
.form-errors p + p{margin-top:4px}

/* One-shot flash after a redirect. */
.flash{background:var(--sun-soft);border:1.5px solid var(--sun);border-radius:var(--radius);
  padding:12px 18px;font-weight:600;font-size:14.5px}

/* The header logout button is a form; it must not break the action row. */
.logout-form{display:inline}

/* Inline emphasis inside .safety, where <b> is display:block. */
.mono{font-family:var(--font-mono);color:var(--ink);font-weight:600}

/* =========================================================================
   Phase 06 — create wizard, my-listings, moderation
   ========================================================================= */

/* Photo strip. The mockup drew placeholder tiles; these hold real thumbnails,
   plus the reorder controls it never needed. */
.photo-slot img{width:100%;height:100%;object-fit:cover}
.photo-slot .rm{border:0;cursor:pointer;line-height:1;z-index:2}
.photo-move{position:absolute;bottom:0;left:0;display:flex;gap:1px;z-index:2}
.photo-slot.main .photo-move{bottom:12px}
.photo-move button{width:20px;height:18px;border:0;background:rgba(20,25,18,.75);color:#fff;
  font-size:12px;line-height:1;cursor:pointer}
.photo-move button:first-child{border-radius:0 6px 0 0}
.photo-move button:disabled{opacity:.35;cursor:default}
.photo-move button:hover:not(:disabled){background:var(--pine)}

/* Sale / rent chips are radios: correct with JS off, and announced as a group. */
.chip-radio{display:inline-block;cursor:pointer}
.chip-radio input{position:absolute;width:1px;height:1px;margin:-1px;overflow:hidden;clip:rect(0 0 0 0)}
.chip-radio input:checked + .chip{background:var(--ink);border-color:var(--ink);color:var(--sun)}
.chip-radio input:focus-visible + .chip{outline:2px solid var(--pine);outline-offset:2px}

.check{display:flex;align-items:center;gap:9px;font-weight:600;cursor:pointer}
.check input{accent-color:var(--pine);width:17px;height:17px}
.req{color:var(--tomato)}

/* The create form's file input is visually-hidden behind the dropzone label. */
.dropzone:focus-within{border-color:var(--pine);background:var(--sun-soft)}

/* ---- my listings ---- */
.quota-bar{background:var(--paper);border:1.5px solid var(--line);border-radius:var(--radius);
  padding:14px 18px;font-size:14.5px;color:var(--ink-soft)}
.quota-bar b{font-family:var(--font-mono);font-size:16px;color:var(--ink)}
.quota-full{border-color:var(--tomato);background:#FDECE8}

.group-head{font-family:var(--font-head);font-weight:700;font-size:16px;margin:28px 0 12px;
  display:flex;align-items:center;gap:10px}
.group-head span{font-family:var(--font-mono);font-size:12px;background:var(--sun-soft);
  border-radius:999px;padding:2px 9px}

.mine-grid{display:grid;gap:12px}
.mine-card{display:flex;gap:16px;background:var(--paper);border:1.5px solid var(--line);
  border-radius:var(--radius);padding:14px}
.mine-media{width:120px;height:90px;border-radius:11px;flex-shrink:0;overflow:hidden;background:var(--wall)}
.mine-media img{width:100%;height:100%;object-fit:cover}
.mine-body{flex:1;min-width:0}
.mine-body h4{font-family:var(--font-head);font-weight:700;font-size:15.5px;margin-bottom:6px;
  overflow-wrap:anywhere}
.mine-meta{display:flex;flex-wrap:wrap;gap:10px;align-items:center;font-family:var(--font-mono);
  font-size:12px;color:var(--ink-soft);margin-bottom:10px}
.mine-note{background:#FDECE8;border-radius:9px;padding:8px 12px;font-size:13.5px;margin-bottom:10px}
.mine-actions{display:flex;flex-wrap:wrap;gap:8px;align-items:center}
.mine-actions .btn{font-size:13px;padding:8px 14px}
.inline-form{display:inline}
.btn-danger{background:transparent;border:1.5px solid var(--line);color:var(--tomato)}
.btn-danger:hover{border-color:var(--tomato);background:#FDECE8}

/* Status pill. Colour carries meaning, so the label carries it too. */
.badge-status{font-family:var(--font-mono);font-size:10.5px;letter-spacing:.06em;
  text-transform:uppercase;padding:3px 9px;border-radius:999px;background:var(--wall);
  border:1px solid var(--line);color:var(--ink)}
.badge-status.s-active{background:var(--sun-soft);border-color:#F0DD8A}
.badge-status.s-sold{background:var(--pine);border-color:var(--pine);color:#fff}
.badge-status.s-expired,.badge-status.s-rejected{background:#FDECE8;border-color:var(--tomato);color:#9B2C18}
.badge-status.s-pending{background:#EAF2ED;border-color:#B9CFC2}

@media (max-width:520px){
  .mine-card{flex-direction:column}
  .mine-media{width:100%;height:150px}
}

/* =========================================================================
   Phase 07 — favourites, messaging, saved searches
   ========================================================================= */

/* ---- the heart ---- */
/* The mockup's .fav is absolutely positioned inside .card (position:relative);
   the form wrapper must not add a box of its own. */
.fav-form{display:contents}
.fav-detail{display:block}
.fav{border:0;cursor:pointer;padding:0}
.fav svg{width:18px;height:18px;fill:none;stroke:var(--ink);stroke-width:2}
.fav.on svg{fill:var(--tomato);stroke:var(--tomato)}
.fav:focus-visible{outline:2px solid var(--pine);outline-offset:2px}
.fav-count{display:block;font-family:var(--font-mono);font-size:11.5px;color:var(--ink-soft);
  font-weight:400;margin-top:2px}

/* Favourites page: a listing that stopped being live stays, but reads as past. */
.faded-card{position:relative}
.faded-card .card{opacity:.62;filter:saturate(.55)}
.faded-card:hover .card{opacity:1;filter:none}
.faded-card > .badge-status{position:absolute;top:10px;left:10px;z-index:3}

/* ---- account menu ---- */
.acct-menu{position:relative}
.acct-menu > summary{list-style:none;cursor:pointer;display:inline-flex;align-items:center;gap:8px}
.acct-menu > summary::-webkit-details-marker{display:none}
.acct-menu-panel{position:absolute;right:0;top:calc(100% + 8px);z-index:60;min-width:230px;
  background:var(--paper);border:1.5px solid var(--line);border-radius:14px;padding:8px;
  box-shadow:var(--shadow-lift)}
.acct-menu-panel a{display:flex;justify-content:space-between;align-items:center;gap:10px;
  padding:10px 12px;border-radius:9px;font-weight:600;font-size:14.5px}
.acct-menu-panel a:hover{background:var(--wall)}

.unread-badge{display:inline-flex;align-items:center;justify-content:center;min-width:20px;
  height:20px;padding:0 6px;border-radius:999px;background:var(--tomato);color:#fff;
  font-family:var(--font-mono);font-size:11.5px;font-weight:600}
.unread-badge.is-zero{display:none}

/* ---- inbox ---- */
.thread-list{display:grid;gap:10px}
.thread-row{display:flex;gap:16px;align-items:center;background:var(--paper);
  border:1.5px solid var(--line);border-radius:var(--radius);padding:14px 18px}
.thread-row.is-unread{border-color:var(--pine);background:var(--sun-soft)}
.thread-main{flex:1;min-width:0;display:grid;gap:4px}
.thread-top{display:flex;justify-content:space-between;gap:12px;align-items:baseline}
.thread-top b{font-family:var(--font-head);font-size:15px}
.thread-listing{font-family:var(--font-mono);font-size:12px;color:var(--ink-soft);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.thread-last{font-size:14px;color:var(--ink-soft);overflow-wrap:anywhere}
.thread-you{font-weight:700;color:var(--ink)}
.thread-side{display:flex;align-items:center;gap:10px;flex-shrink:0}
.thread-side .btn{font-size:12.5px;padding:7px 12px}
.dot-new{width:9px;height:9px;border-radius:50%;background:var(--tomato);flex-shrink:0}

/* ---- thread ---- */
.thread-wrap{padding:20px 0 64px;max-width:820px}
.thread-head{display:flex;justify-content:space-between;gap:20px;align-items:flex-start;
  padding-bottom:16px;border-bottom:1.5px solid var(--line);margin-bottom:20px;flex-wrap:wrap}
.thread-head h2{font-family:var(--font-display);font-size:24px;text-transform:uppercase}
.thread-listing-link{display:grid;gap:4px;text-align:right;background:var(--paper);
  border:1.5px solid var(--line);border-radius:var(--radius);padding:12px 16px;min-width:220px}
.thread-listing-link b{font-family:var(--font-head);font-size:14.5px}

.thread-body{display:grid;gap:12px;margin-bottom:24px}
.day-sep{display:flex;align-items:center;gap:14px;margin:10px 0 2px;color:var(--ink-soft)}
.day-sep::before,.day-sep::after{content:"";flex:1;height:1px;background:var(--line)}
.day-sep span{font-family:var(--font-mono);font-size:11.5px;letter-spacing:.06em;text-transform:uppercase}
.bubble-row{display:flex}
.bubble-row.mine{justify-content:flex-end}
.bubble{max-width:min(76%,560px);border-radius:16px;padding:12px 16px;background:var(--paper);
  border:1.5px solid var(--line)}
.bubble p{font-size:15px;line-height:1.5;overflow-wrap:anywhere}
.bubble-meta{display:block;margin-top:6px;font-family:var(--font-mono);font-size:11px;
  color:var(--ink-soft)}
.bubble-row.mine .bubble{background:var(--pine);border-color:var(--pine);color:#fff}
.bubble-row.mine .bubble-meta{color:rgba(255,255,255,.7)}
.thread-reply{margin-top:8px}

/* Contact box on the listing page. */
.own-listing{margin-top:14px;background:var(--wall);border-radius:11px;padding:12px 14px;
  font-size:14px;color:var(--ink-soft)}
.own-listing a{color:var(--pine);font-weight:700;display:block;margin-top:4px}

/* ---- saved searches ---- */
/* The panel overlays rather than expanding the toolbar row: a details element
   that grows in place shoves the result count and the sort control around
   every time it is opened. */
.save-search{position:relative}
.save-search > summary{list-style:none;cursor:pointer;font-size:13px;padding:8px 14px}
.save-search > summary::-webkit-details-marker{display:none}
.save-search[open] > summary{background:var(--sun-soft);border-color:var(--pine)}
.save-search-form{position:absolute;left:0;top:calc(100% + 8px);z-index:60;
  width:min(420px,80vw);display:flex;gap:8px;flex-wrap:wrap;
  background:var(--paper);border:1.5px solid var(--line);border-radius:14px;padding:12px;
  box-shadow:var(--shadow-lift)}
.save-search-form .input{flex:1;min-width:180px}
.save-search-form .hint{flex-basis:100%}

.saved-list{display:grid;gap:12px}
.saved-row{display:flex;justify-content:space-between;gap:20px;align-items:center;flex-wrap:wrap;
  background:var(--paper);border:1.5px solid var(--line);border-radius:var(--radius);padding:16px 18px}
.saved-main h4{font-family:var(--font-head);font-weight:700;font-size:15.5px;margin-bottom:4px}
.saved-summary{font-size:14px;color:var(--ink-soft);margin-bottom:4px;overflow-wrap:anywhere}
.saved-actions{display:flex;gap:8px;align-items:center;flex-shrink:0}

@media (max-width:780px){
  .acct-menu-panel{right:auto;left:0}
  .thread-row{flex-direction:column;align-items:stretch}
  .thread-side{justify-content:flex-end}
  .thread-listing-link{text-align:left;min-width:0;width:100%}
}

/* ==========================================================================
   Phase 08 — monetization: badges, promoted block, wallet, plans, admin tables
   ========================================================================== */

/* ---- promoted cards ----
   The sun border is the product (highlight); the badges sit in the same corner
   the "NEW" badge already uses, stacked, so a listing with both TOP and Promo
   reads as one column rather than two overlapping labels. */
.card.is-promo{border-color:var(--sun);box-shadow:0 0 0 3px var(--sun-soft)}
.card.is-promo:hover{border-color:var(--sun)}
.promo-badges{position:absolute;top:12px;left:12px;z-index:3;display:flex;
  flex-direction:column;align-items:flex-start;gap:5px}
.promo-badges .badge{position:static}
.badge.promo{background:var(--pine);color:var(--sun)}

/* The pinned block. Labelled, and visually separated from the honest grid
   below it — paid placement that looks identical to the sort order is a lie. */
.promoted{margin-bottom:22px;padding:16px 18px 18px;border:1.5px dashed var(--sun);
  border-radius:var(--radius);background:linear-gradient(180deg,var(--sun-soft),transparent 70%)}
.promoted > h3{margin-bottom:14px}
.promoted > h3 span{font-family:var(--font-mono);font-size:11.5px;letter-spacing:.1em;
  text-transform:uppercase;color:var(--pine);background:var(--paper);
  border:1px solid #F0DD8A;border-radius:999px;padding:5px 12px}

.featured-strip{background:var(--paper);border-top:1.5px solid var(--line);
  border-bottom:1.5px solid var(--line)}

/* ---- wallet ---- */
.wallet-head{display:flex;justify-content:space-between;align-items:center;gap:20px;
  flex-wrap:wrap;background:var(--paper);border:1.5px solid var(--line);
  border-radius:var(--radius);padding:18px 20px;margin-bottom:18px}
.wallet-head .kicker{display:block;margin-bottom:4px}
.wallet-balance{font-family:var(--font-mono);font-size:34px;font-weight:600;color:var(--pine)}
.wallet-balance-small{font-family:var(--font-mono);font-size:22px;font-weight:600;
  color:var(--pine);padding:6px 0}
.price-row{display:flex;justify-content:space-between;gap:14px;padding:5px 0;font-size:13.5px}
.price-row b{font-family:var(--font-mono)}

/* ---- data tables (wallet, invoices, admin) ----
   Wrapped in an overflow container: a seven-column order table cannot be made
   to fit 390px, and a page that scrolls sideways as a whole is worse than a
   table that does. */
.table-wrap{overflow-x:auto;border:1.5px solid var(--line);border-radius:var(--radius);
  background:var(--paper)}
.data-table{width:100%;border-collapse:collapse;min-width:560px}
.data-table th{text-align:left;font-family:var(--font-mono);font-size:11px;letter-spacing:.06em;
  text-transform:uppercase;color:var(--ink-soft);padding:12px 14px;
  border-bottom:1.5px solid var(--line);white-space:nowrap}
.data-table td{padding:12px 14px;border-bottom:1px solid var(--line);font-size:14px;
  vertical-align:top}
.data-table tr:last-child td{border-bottom:none}
.data-table .num{text-align:right;font-family:var(--font-mono);white-space:nowrap}
.data-table .num.neg{color:var(--tomato)}
.data-table .num.pos{color:var(--pine)}
.data-table .ref{display:block;font-family:var(--font-mono);font-size:11px;
  color:var(--ink-soft);overflow-wrap:anywhere}

/* ---- promotion picker ---- */
.promote-listing{display:grid;gap:4px;background:var(--wall);border-radius:11px;padding:12px 14px}
.promo-list{display:grid;gap:12px}
.promo-option{display:flex;justify-content:space-between;gap:18px;align-items:center;
  flex-wrap:wrap;border:1.5px solid var(--line);border-radius:var(--radius);padding:14px 16px;
  background:var(--paper)}
.promo-option:hover{border-color:var(--pine)}
.promo-copy{flex:1;min-width:220px}
.promo-copy b{font-family:var(--font-head);font-size:15.5px}
.promo-copy p{font-size:13.5px;color:var(--ink-soft);margin-top:3px}
.promo-buy{display:flex;align-items:center;gap:12px;flex-shrink:0}
.allowance-tag,.blocked-tag{display:inline-block;margin-top:7px;font-family:var(--font-mono);
  font-size:11px;letter-spacing:.04em;padding:4px 9px;border-radius:999px}
.allowance-tag{background:var(--sun-soft);border:1px solid #F0DD8A;color:var(--pine)}
.blocked-tag{background:#FDECE8;border:1px solid var(--tomato);color:#9B2C18}
.promo-option button[disabled],.plan-card button[disabled]{opacity:.45;cursor:not-allowed}

/* ---- plans ---- */
.plan-current{display:flex;justify-content:space-between;gap:24px;flex-wrap:wrap;
  background:var(--pine);color:#fff;border-radius:var(--radius);padding:20px 22px;margin-bottom:22px}
.plan-current b{font-family:var(--font-display);font-size:26px;text-transform:uppercase;display:block}
.plan-current .kicker,.plan-current .time{color:rgba(255,255,255,.72)}
.allowance-grid{display:flex;gap:22px;flex-wrap:wrap}
.allowance{text-align:right}
.allowance b{font-family:var(--font-mono);font-size:22px;color:var(--sun)}
.allowance b span{font-size:14px;color:rgba(255,255,255,.6)}
.allowance > span{display:block;font-size:12px;color:rgba(255,255,255,.72)}

.plan-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:16px}
.plan-card{background:var(--paper);border:1.5px solid var(--line);border-radius:var(--radius);
  padding:20px}
.plan-card.is-current{border-color:var(--pine);box-shadow:0 0 0 3px #EAF2ED}
.plan-card h3{font-family:var(--font-display);font-size:20px;text-transform:uppercase}
.plan-price{margin:8px 0 14px}
.plan-price b{font-family:var(--font-mono);font-size:24px;color:var(--pine)}
.plan-price span{color:var(--ink-soft);font-size:13px}
.plan-features{list-style:none;display:grid;gap:6px;margin-bottom:16px;font-size:14px}
.plan-features li::before{content:"✓ ";color:var(--pine);font-weight:700}

/* ---- admin ---- */
.admin-find{display:flex;gap:10px;flex-wrap:wrap;align-items:center}
.admin-find .input,.admin-find .select{flex:1;min-width:180px;max-width:340px}

@media (max-width:980px){
  .plan-grid{grid-template-columns:1fr}
}
@media (max-width:780px){
  .wallet-balance{font-size:28px}
  .promo-option{flex-direction:column;align-items:stretch}
  .promo-buy{justify-content:space-between}
  .allowance{text-align:left}
}

/* ==========================================================================
   Phase 09 — payments: pack picker, pending top-ups
   ========================================================================== */

/* Each pack is its own single-button form, so the page needs no JavaScript and
   there is no radio-then-submit step between wanting and buying. */
.pack-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:12px}
.pack{width:100%;display:grid;gap:4px;justify-items:center;cursor:pointer;
  background:var(--paper);border:1.5px solid var(--line);border-radius:var(--radius);
  padding:18px 12px;transition:all .15s}
.pack:hover{border-color:var(--pine);background:var(--sun-soft)}
.pack b{font-family:var(--font-mono);font-size:20px;font-weight:600;color:var(--pine)}
.pack span{font-size:12.5px;color:var(--ink-soft)}

.pending-list{display:grid;gap:10px;margin-bottom:18px}
.pending-row{display:flex;justify-content:space-between;gap:18px;align-items:center;
  flex-wrap:wrap;background:var(--sun-soft);border:1.5px solid #F0DD8A;
  border-radius:var(--radius);padding:14px 16px}
.pending-row b{font-family:var(--font-head);font-size:15px}
/* Older than a day: still pending as far as the provider is concerned, just
   dimmed so it stops competing with today's payment for attention. */
.pending-row.is-stale{background:var(--wall);border-color:var(--line);opacity:.8}

.wallet-head .chips{flex-wrap:nowrap}

@media (max-width:780px){
  .wallet-head .chips{flex-wrap:wrap}
  .pending-row{flex-direction:column;align-items:stretch}
}

/* ==========================================================================
   Phase 10 — admin panel: KPI cards, sparklines, dense tables, tools
   ========================================================================== */

/* The banner an admin sets at /admin/cilesimet. Sun, not tomato: it is a
   notice, not an error, and the site is still working. */
.site-notice{background:var(--sun);color:var(--ink);font-size:14.5px;font-weight:600;
  padding:10px 0;border-bottom:1.5px solid #E0B400}
.site-notice .wrap{display:flex;gap:10px;align-items:center}
.site-notice .wrap::before{content:"●";font-size:10px;color:var(--pine)}

.admin-nav{row-gap:8px}

/* ---- dashboard ---- */
.kpi-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:14px;
  margin-bottom:22px}
.kpi{display:grid;gap:4px;background:var(--paper);border:1.5px solid var(--line);
  border-radius:var(--radius);padding:18px 20px;transition:all .15s}
.kpi:hover{border-color:var(--pine)}
.kpi b{font-family:var(--font-mono);font-size:28px;font-weight:600;color:var(--pine);
  line-height:1.1}
.kpi > span{font-size:13.5px;font-weight:600}
.kpi em{font-style:normal;font-family:var(--font-mono);font-size:11.5px;color:var(--ink-soft)}
.kpi-alert{border-color:var(--tomato);box-shadow:0 0 0 3px #FDECE8}
.kpi-alert b{color:var(--tomato)}
.kpi-liability b{color:var(--ink)}

.spark-row{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:14px;
  margin-bottom:22px}
.spark-card{background:var(--paper);border:1.5px solid var(--line);border-radius:var(--radius);
  padding:16px 18px}
.spark-card h4{font-family:var(--font-mono);font-size:11px;letter-spacing:.06em;
  text-transform:uppercase;color:var(--ink-soft);margin-bottom:6px}
.spark-total{font-family:var(--font-mono);font-size:22px;font-weight:600;color:var(--pine)}
.spark{display:block;width:100%;height:44px;margin:8px 0 4px}
.spark polyline{fill:none;stroke:var(--pine);stroke-width:1.6;vector-effect:non-scaling-stroke;
  stroke-linejoin:round;stroke-linecap:round}

.admin-links{display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));gap:12px}
.admin-link{display:grid;gap:2px;background:var(--paper);border:1.5px solid var(--line);
  border-radius:var(--radius);padding:14px 16px}
.admin-link:hover{border-color:var(--pine);background:var(--sun-soft)}
.admin-link b{font-family:var(--font-head);font-size:15px}
.admin-link span{font-size:12.5px;color:var(--ink-soft)}

/* ---- dense tables ---- */
.admin-thumb{width:56px;height:42px;object-fit:cover;border-radius:7px;display:block}
.admin-thumb-empty{background:var(--wall);border:1px dashed var(--line)}
.data-table tr.is-off{opacity:.55}
.row-inline{display:flex;gap:6px;align-items:center;flex-wrap:wrap}
.row-inline form{display:inline}

/* Row actions in a <details> so fifty rows do not become a wall of buttons.
   The panel is absolutely positioned for the same reason the saved-search one
   is: a details that grows in place shoves every row below it. */
.row-actions{position:relative}
.row-actions > summary{list-style:none;cursor:pointer;white-space:nowrap}
.row-actions > summary::-webkit-details-marker{display:none}
.row-actions[open] > summary{background:var(--sun-soft);border-color:var(--pine)}
.row-actions-panel{position:absolute;right:0;top:calc(100% + 6px);z-index:60;width:280px;
  display:grid;gap:10px;background:var(--paper);border:1.5px solid var(--line);
  border-radius:14px;padding:12px;box-shadow:var(--shadow-lift)}
.row-actions-panel form{display:grid;gap:8px}

/* ---- the two-pane category manager (phase 13) ----
   82 categories were a flat table; the tree is now a <details> per parent, so
   the collapse costs no JavaScript and survives the enforced CSP. */
.cat-manager{display:grid;grid-template-columns:320px minmax(0,1fr);gap:24px;
  padding:22px 0 64px;align-items:start}
.cat-pane-left{position:sticky;top:86px;background:var(--paper);border:1.5px solid var(--line);
  border-radius:var(--radius);padding:16px;max-height:calc(100vh - 110px);overflow-y:auto}
.cat-pane-right{min-width:0}
.cat-search{display:flex;gap:8px;margin-bottom:10px}
.cat-search .input{flex:1;min-width:0}
.cat-legend{font-size:11.5px;margin-bottom:10px}

.cat-branch,.cat-kids{list-style:none;display:grid;gap:2px}
.cat-kids{margin:2px 0 8px 14px;padding-left:10px;border-left:1.5px solid var(--line)}
.cat-node{border-radius:10px}
.cat-sum{display:flex;align-items:center;gap:4px;list-style:none;cursor:pointer;
  border-radius:10px;padding:2px}
.cat-sum::-webkit-details-marker{display:none}
.cat-chev{flex-shrink:0;width:20px;text-align:center;color:var(--ink-soft);font-size:11px;
  transition:transform .15s;display:inline-block}
.cat-node[open] > .cat-sum .cat-chev{transform:rotate(90deg)}
.cat-link{flex:1;min-width:0;display:flex;align-items:baseline;gap:8px;justify-content:space-between;
  padding:6px 8px;border-radius:9px;font-size:14px}
.cat-link:hover{background:var(--wall)}
.cat-link b{font-family:var(--font-head);font-size:14px}
.cat-child{padding-left:6px}
.cat-counts{flex-shrink:0;font-family:var(--font-mono);font-size:11px;color:var(--ink-soft)}
.cat-sep{padding:0 4px;color:var(--line)}
.cat-empty{font-size:12px;color:var(--ink-soft);margin:2px 0 8px 24px}
.cat-move{display:flex;gap:4px;flex-shrink:0}
.cat-sum.is-off > .cat-link,.cat-link.is-off{opacity:.5;text-decoration:line-through}
.cat-sum.is-sel > .cat-link,.cat-kid.is-sel > .cat-link{background:var(--sun-soft);
  box-shadow:inset 0 0 0 1.5px var(--pine)}
.cat-kid{display:flex;align-items:center;gap:4px}
.cat-kid > .cat-link{flex:1;min-width:0}

.pane-head{display:flex;justify-content:space-between;gap:16px;flex-wrap:wrap;
  align-items:flex-start;margin-bottom:18px}
.pane-head h3{font-family:var(--font-display);text-transform:uppercase;font-size:24px;
  line-height:1.1;display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.pane-meta{font-family:var(--font-mono);font-size:12px;color:var(--ink-soft);margin-top:6px}

/* The per-field editor hangs off its own table row so the fields table stays a
   table — one <tr> of columns, one <tr> holding the drawer. */
.row-editor > td{padding-top:0;border-bottom:1px solid var(--line)}
.field-editor > summary{list-style:none;cursor:pointer;display:inline-flex}
.field-editor > summary::-webkit-details-marker{display:none}
.editor-body{background:var(--wall);border-radius:14px;padding:16px 18px;margin-top:10px}
.opt-head{font-family:var(--font-head);font-size:14px;margin:18px 0 8px}
.opt-table{min-width:0}
.opt-table td{padding:8px 10px;vertical-align:middle}
.opt-table .row-inline{flex-wrap:nowrap}
.opt-table .input-sm{min-width:0;flex:1}
.opt-table .opt-value{flex:1.2}
.opt-table .ref{white-space:nowrap}
.input-sm{padding:7px 10px;font-size:13px}
.btn-xs{padding:6px 10px;font-size:12px;border-radius:9px;white-space:nowrap}

/* ---- moderation bulk bar (phase 15) ----
   The importer can drop hundreds of rows into the queue, so "approve the ones
   I ticked" has to be one action rather than one page load each. */
.bulk-bar{display:flex;align-items:center;justify-content:space-between;gap:16px;flex-wrap:wrap;
  background:var(--paper);border:1.5px solid var(--line);border-radius:var(--radius);
  padding:12px 18px;margin-bottom:18px;position:sticky;top:76px;z-index:30}
.mod-head{display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin-bottom:14px}
.mod-head h2{margin-bottom:0;flex:1;min-width:200px}
.mod-head .f-opt{margin:0}

/* ---- static page texts (phase 13) ---- */
.page-sum{list-style:none;cursor:pointer;display:flex;gap:12px;align-items:baseline;
  flex-wrap:wrap}
.page-sum::-webkit-details-marker{display:none}
.page-sum::before{content:"▸";color:var(--ink-soft);font-size:12px}
details[open] > .page-sum::before{content:"▾"}
.page-sum b{font-family:var(--font-head);font-size:16px}
.page-editor{display:grid;grid-template-columns:1.3fr 1fr;gap:24px;margin-top:20px;
  align-items:start}
.page-body{font-family:var(--font-mono);font-size:13px;line-height:1.6}
.page-preview{background:var(--wall);border-radius:14px;padding:16px 18px;font-size:14px;
  max-height:520px;overflow-y:auto}
.page-preview h3{font-family:var(--font-head);font-size:17px;margin-bottom:4px}
.page-preview h5{font-family:var(--font-head);font-size:14px;margin:14px 0 4px}
.page-preview p{margin-bottom:8px;overflow-wrap:anywhere}

/* ---- categories & fields ---- */
.field-list{display:grid;gap:12px}
.field-card{background:var(--paper);border:1.5px solid var(--line);border-radius:var(--radius);
  padding:16px 18px}
.field-card.is-off{opacity:.6;border-style:dashed}
.field-card-head{display:flex;justify-content:space-between;gap:16px;flex-wrap:wrap;
  align-items:flex-start}
.field-card-head b{font-family:var(--font-head);font-size:15.5px}
.key-locked{background:var(--wall);border:1px dashed var(--line);border-radius:9px;
  padding:8px 12px;font-family:var(--font-mono);font-size:13px}
code{font-family:var(--font-mono);font-size:12.5px;background:var(--wall);
  border-radius:5px;padding:1px 5px}

/* ---- plans ---- */
.plan-admin-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:16px}

/* ---- reports ---- */
.report-list{display:grid;gap:12px}
.report-card{background:var(--paper);border:1.5px solid var(--line);border-radius:var(--radius);
  padding:16px 18px}
.report-head{display:flex;justify-content:space-between;gap:16px;flex-wrap:wrap;
  align-items:flex-start}
.report-details{background:var(--wall);border-radius:11px;padding:10px 14px;margin:10px 0;
  font-size:14px;overflow-wrap:anywhere}
.report-actions{display:flex;gap:12px;flex-wrap:wrap;margin-top:12px}
.report-actions form{display:flex;gap:8px;align-items:center;flex:1;min-width:260px}
.report-actions .input{flex:1}
.report-resolution{margin-top:10px;font-size:14px;color:var(--ink-soft)}

/* ---- redirects ---- */
.chain{display:grid;gap:6px;margin-top:10px}
.chain-hop{display:flex;gap:10px;align-items:center;flex-wrap:wrap;font-size:13.5px}

/* ---- tools ---- */
.tool-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:16px}
.form-card.is-stub{border-style:dashed;opacity:.75}
.tool-result{background:var(--paper);border:1.5px solid var(--line);border-radius:var(--radius);
  padding:16px 18px;margin-bottom:20px}
.tool-result.is-ok{border-color:var(--pine);box-shadow:0 0 0 3px #EAF2ED}
.tool-result.is-fail{border-color:var(--tomato);box-shadow:0 0 0 3px #FDECE8}
.tool-result-head{display:flex;justify-content:space-between;gap:16px;flex-wrap:wrap;
  margin-bottom:10px}
.tool-result pre{background:var(--ink);color:#EDEFE8;border-radius:11px;padding:14px 16px;
  font-family:var(--font-mono);font-size:12.5px;line-height:1.5;overflow-x:auto;
  white-space:pre-wrap;overflow-wrap:anywhere;max-height:420px;overflow-y:auto}

@media (max-width:980px){
  /* One column below the tablet break: a 320px tree next to a form with two
     inputs side by side is narrower than either needs. The tree stops being
     sticky too — a pane that scrolls independently on a phone traps the page. */
  .cat-manager{grid-template-columns:1fr}
  .cat-pane-left{position:static;max-height:none}
  .page-editor{grid-template-columns:1fr}
}

@media (max-width:780px){
  .kpi b{font-size:23px}
  .row-actions-panel{position:static;width:auto;box-shadow:none;margin-top:8px}
  .report-actions form{min-width:0}
  .pane-head h3{font-size:20px}
}

/* ===========================================================================
   Phase 11 — layout utilities, because the CSP is enforced
   ---------------------------------------------------------------------------
   `style-src 'self'` blocks style ATTRIBUTES, not only <style> blocks. The
   templates carried 177 of them — almost all one-line spacing tweaks — and the
   alternative to moving them here was adding 'unsafe-inline', which is most of
   what the policy exists to prevent.

   These are deliberately boring and named for what they do. Anything that is a
   real component still gets a real component class; this block is only for the
   "this instance needs 14px of air" cases that never justified one.
   ======================================================================== */

.mt-6{margin-top:6px}    .mt-8{margin-top:8px}    .mt-10{margin-top:10px}
.mt-12{margin-top:12px}  .mt-14{margin-top:14px}  .mt-16{margin-top:16px}
.mt-18{margin-top:18px}  .mt-24{margin-top:24px}  .mt-26{margin-top:26px}
.mt-28{margin-top:28px}  .mt-32{margin-top:32px}

.mb-8{margin-bottom:8px}   .mb-14{margin-bottom:14px}  .mb-16{margin-bottom:16px}
.mb-18{margin-bottom:18px} .mb-20{margin-bottom:20px}

.my-14{margin:14px 0}  .my-18{margin:18px 0}
/* Flush top, 18px below — for a <p> whose default top margin must go. */
.m-flush-18{margin:0 0 18px}
/* Pulls a widget up under its label, then keeps the gap below it. */
.m-tuck-14{margin:-6px 0 14px}

.pt-6{padding-top:6px}    .pt-8{padding-top:8px}    .pt-10{padding-top:10px}
.pt-16{padding-top:16px}  .pt-18{padding-top:18px}  .pt-20{padding-top:20px}
.pt-24{padding-top:24px}  .pb-64{padding-bottom:64px}

/* The two page-body rhythms used across the account and payment pages. */
.page-pad{padding:20px 0 64px}
.page-pad-lg{padding:48px 0 64px}
.mw-620{max-width:620px}

/* ---- one-property helpers ---- */
.d-inline{display:inline}
.d-inline-flex{display:inline-flex}
.jc-center{justify-content:center}
.fw-400{font-weight:400}
.fs-16{font-size:16px}
.is-dim{opacity:.6}
.cur-default{cursor:default}
.t-pine{color:var(--pine)}
.t-sun{color:var(--sun)}
.t-tomato{color:var(--tomato)}
.t-paper{color:#fff}
.bg-line{background:var(--line)}
.bg-paper{background:#fff}

/* A photo filling its fixed-ratio frame. `.is-layered` is the gallery's main
   image, which sits above the blurred backdrop behind it. */
.img-cover{width:100%;height:100%;object-fit:cover}
.img-cover.is-layered{z-index:1}

/* A line of secondary detail under a heading or inside a summary box. */
.meta-row{padding:6px 0;font-size:14px;color:var(--ink-soft)}
.pad-row{padding:6px 0}

/* Category tree indentation. The depth is a number from the database, so it
   arrives as a data attribute and the widths live here — an inline
   `width:{$depth * 18}px` is exactly the kind of computed style the CSP
   forbids, and the tree is only ever a handful of levels deep. */
.depth-rail{display:inline-block;width:0}
[data-depth="1"] .depth-rail{width:18px}
[data-depth="2"] .depth-rail{width:36px}
[data-depth="3"] .depth-rail{width:54px}
[data-depth="4"] .depth-rail{width:72px}
[data-depth="5"] .depth-rail{width:90px}

/* The help article runs a wider body column than the listing detail it shares
   a layout with, and its title uses the display face. Both were inline styles
   until the CSP made that impossible (phase 11). */
.detail-layout.is-article{grid-template-columns:1.6fr 1fr}
.article-title{font-family:var(--font-display);text-transform:uppercase;
  font-size:clamp(24px,3vw,34px);line-height:1.1}

/* htmx's indicator rules, which htmx would otherwise inject as a <style>
   element the CSP refuses. Copied verbatim from htmx 2.0.4's _n(); the meta tag
   in partials/head.latte turns its own injection off. */
.htmx-indicator{opacity:0}
.htmx-request .htmx-indicator{opacity:1; transition: opacity 200ms ease-in;}
.htmx-request.htmx-indicator{opacity:1; transition: opacity 200ms ease-in;}

/* ---- filter sidebar: the tail of the field list (phase 12) ----
   A <details>, so the collapse needs no JavaScript and is unaffected by the
   enforced CSP. The summary is styled as a block button to match the other
   sidebar controls. */
.filter-more{margin-bottom:14px}
.filter-more > summary{cursor:pointer;list-style:none;margin-bottom:14px}
.filter-more > summary::-webkit-details-marker{display:none}
.filter-more > summary::after{content:" ▾"}
.filter-more[open] > summary::after{content:" ▴"}


/* Compact checkbox groups for make/model filters. */
.filter-options-more{margin-top:8px}
.filter-options-toggle{display:flex;align-items:center;justify-content:center;width:100%;
  cursor:pointer;list-style:none;border:1.5px solid var(--line);border-radius:10px;
  background:var(--paper);color:var(--pine);font-family:var(--font-head);
  font-size:13px;font-weight:700;padding:9px 10px}
.filter-options-toggle::-webkit-details-marker{display:none}
.filter-options-toggle:hover{border-color:var(--pine);background:var(--sun-soft)}
.filter-options-more .show-less{display:none}
.filter-options-more[open] .show-more{display:none}
.filter-options-more[open] .show-less{display:inline}
.filter-options-extra{display:grid;padding-top:8px}
.model-filter-hint{margin:0;padding:10px 11px;background:var(--wall);border-radius:9px;line-height:1.45}

/* ============ Turnstile host page (phase 20) ============
   The bare page the mobile app opens in a WebView. It is not inside
   layout.latte — a header, drawer and footer around a challenge box would be
   noise in a sheet the size of the box. */
.ts-page{display:flex;align-items:center;justify-content:center;min-height:100vh;background:var(--wall);padding:24px}
.ts-wrap{max-width:360px;text-align:center}
.ts-title{font-family:var(--font-head);font-size:20px;margin-bottom:6px}
.ts-lead{color:var(--ink-soft);font-size:15px;margin-bottom:20px}
.ts-status{margin-top:14px;font-family:var(--font-mono);font-size:12.5px;color:var(--ink-soft);min-height:1.2em}
