/* ── Funguo operations console ──────────────────────────────────────────
   A working surface, not a marketing page. Different job from the public
   site, so different rules: denser, quieter, and built to be looked at for
   a whole day rather than for ten seconds.

   Every colour is a token. Nothing below hard-codes one, which is what makes
   a dark theme a matter of redefining this block rather than auditing every
   rule in the file. */

:root{
  /* Workspace. Warm off-white rather than white: eight hours of pure #fff is
     tiring, and it makes the surfaces sitting on it disappear. */
  --bg:              #F6F4EF;   /* warm ivory, not grey: the ground the marketplace sits on */
  --surface:         #FFFFFF;
  --surface-sunken:  #F2F1EE;
  --surface-elevated:#FFFFFF;

  --border:          #E4E2DD;
  --border-strong:   #D2CFC8;

  --text-primary:    #1A1726;
  --text-secondary:  #6B6579;
  --text-muted:      #928C9E;
  --text-on-dark:    #EDEAF5;
  --text-on-dark-dim:#A79FC0;

  /* Deep aubergine. The navigation, and almost nowhere else. */
  --nav:             #1E1830;
  --nav-hover:       rgba(255,255,255,.07);
  --nav-active:      rgba(255,255,255,.11);

  /* Semantic accents. Each one means a single thing across the console, so
     that a colour is information rather than decoration -- and so that not
     everything is purple. */
  --acc-ok:      #17795E;  --acc-ok-wash:    #E8F4EF;
  --acc-warn:    #A66A05;  --acc-warn-wash:  #FBF1DF;
  --acc-urgent:  #C2373F;  --acc-urgent-wash:#FBEBEC;
  --acc-violet:  #6247BE;  --acc-violet-wash:#F0EDFA;
  --acc-info:    #235E9E;  --acc-info-wash:  #E9F1F9;
  --acc-brand:   #4A2F97;  --acc-brand-wash: #EFEBFA;

  /* The accent earns its place by being rare. */
  --brand:           #6247BE;
  --brand-strong:    #533CA6;
  --brand-wash:      #F0EDFA;

  /* Status. Each means one thing, everywhere. */
  --success:#1F7A4D;  --success-wash:#E7F4ED;
  --warning:#A66A05;  --warning-wash:#FBF2E2;
  --danger: #B3261E;  --danger-wash: #FBEBEA;
  --info:   #2C5AA8;  --info-wash:   #EAF0FA;
  --neutral:#6B6579;  --neutral-wash:#F0EFEC;

  --shadow-sm: 0 1px 2px rgba(26,23,38,.05);
  --shadow-md: 0 2px 4px rgba(26,23,38,.06), 0 8px 20px -12px rgba(26,23,38,.18);
  --shadow-lg: 0 4px 8px rgba(26,23,38,.07), 0 24px 48px -20px rgba(26,23,38,.28);

  --r-sm:8px; --r:10px; --r-md:12px; --r-lg:14px;
  --nav-w:250px; --top-h:62px;
  --ui: system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;
  --t: 150ms cubic-bezier(.2,.6,.3,1);
}

/* The tokens a dark theme would move. Left here deliberately, unused, as the
   shape of the work rather than a promise it is finished. */
@media (prefers-color-scheme: dark){
  :root[data-portal-theme="dark"]{
    --bg:#141220; --surface:#1C1929; --surface-sunken:#171423; --surface-elevated:#232032;
    --border:#2E2A3E; --border-strong:#3D3852;
    --text-primary:#EFEDF5; --text-secondary:#A9A3BC; --text-muted:#7D7794;
    --brand-wash:#241E3C; --success-wash:#12271C; --warning-wash:#2A2010;
    --danger-wash:#2B1615; --info-wash:#141F33; --neutral-wash:#201D2C;
  }
}

/* ── Shell ──────────────────────────────────────────────────────────────
   Sidebar and workspace, side by side, both filling the height. The old
   console put a 1280 wrapper round a table and left half the monitor empty;
   an operations screen should use the glass it is given. */
body.portal-body{background:var(--bg);color:var(--text-primary);font-family:var(--ui);margin:0}
.shell{display:grid;grid-template-columns:var(--nav-w) minmax(0,1fr);min-height:100vh}

/* ── Navigation ─────────────────────────────────────────────────────────*/
.side{background:var(--nav);color:var(--text-on-dark);display:flex;flex-direction:column;
  position:sticky;top:0;height:100vh;overflow-y:auto;scrollbar-width:thin}
.side::-webkit-scrollbar{width:6px}
.side::-webkit-scrollbar-thumb{background:rgba(255,255,255,.14);border-radius:3px}

.side-brand{display:flex;align-items:center;gap:11px;padding:18px 18px 16px;
  border-bottom:1px solid rgba(255,255,255,.08);flex:none}
.side-brand img{width:112px;height:auto;display:block}
.side-brand .tier{font-size:9.5px;letter-spacing:.13em;text-transform:uppercase;
  color:var(--text-on-dark-dim);margin-top:5px;display:block}

.side-nav{padding:10px 10px 20px;flex:1}
.nav-group{font-size:10px;font-weight:700;letter-spacing:.12em;text-transform:uppercase;
  color:rgba(255,255,255,.34);padding:16px 10px 6px;margin:0}
.nav-group:first-child{padding-top:6px}
.nav-item{display:flex;align-items:center;gap:10px;width:100%;background:none;border:0;
  border-radius:var(--r-sm);padding:8px 10px;font:inherit;font-size:13.5px;
  color:var(--text-on-dark-dim);text-align:left;cursor:pointer;position:relative;
  transition:background var(--t),color var(--t)}
.nav-item:hover{background:var(--nav-hover);color:var(--text-on-dark)}
.nav-item:focus-visible{outline:2px solid var(--brand);outline-offset:-2px}
.nav-item.is-on{background:var(--nav-active);color:#fff;font-weight:600}
/* A rail rather than a filled block: it marks the row without shouting. */
.nav-item.is-on::before{content:"";position:absolute;left:-10px;top:6px;bottom:6px;width:3px;
  background:var(--brand);border-radius:0 3px 3px 0}
.nav-item svg{width:16px;height:16px;flex:none;stroke:currentColor;fill:none;stroke-width:1.6;
  stroke-linecap:round;stroke-linejoin:round;opacity:.85}
.nav-item.is-on svg{opacity:1}
/* Badges only where there is something to act on. */
.nav-n{margin-left:auto;font-size:11px;font-weight:600;background:rgba(255,255,255,.13);
  color:var(--text-on-dark);border-radius:999px;padding:1px 7px;min-width:20px;text-align:center}
.nav-item.is-on .nav-n{background:rgba(255,255,255,.22)}
.nav-n.urgent{background:var(--danger);color:#fff}

/* ── Top bar ────────────────────────────────────────────────────────────*/
.top{height:var(--top-h);background:var(--surface);border-bottom:1px solid var(--border);
  display:flex;align-items:center;gap:16px;padding:0 28px;position:sticky;top:0;z-index:20}
.crumb{font-size:13px;color:var(--text-secondary);display:flex;align-items:center;gap:7px;min-width:0}
.crumb b{color:var(--text-primary);font-weight:600}
.crumb .sep{color:var(--text-muted)}

.top-search{margin-left:auto;position:relative;flex:0 1 320px;min-width:0}
.top-search input{width:100%;padding:8px 12px 8px 34px;border:1px solid var(--border);
  border-radius:var(--r-sm);background:var(--surface-sunken);font:inherit;font-size:13px;
  color:var(--text-primary)}
.top-search input:focus{outline:none;border-color:var(--brand);background:var(--surface);
  box-shadow:0 0 0 3px var(--brand-wash)}
.top-search svg{position:absolute;left:11px;top:50%;transform:translateY(-50%);width:15px;height:15px;
  stroke:var(--text-muted);fill:none;stroke-width:1.8;pointer-events:none}

.top-btn{display:inline-flex;align-items:center;gap:7px;background:none;border:1px solid transparent;
  border-radius:var(--r-sm);padding:7px 10px;font:inherit;font-size:13px;color:var(--text-secondary);
  cursor:pointer;transition:background var(--t),color var(--t),border-color var(--t);white-space:nowrap}
.top-btn:hover{background:var(--surface-sunken);color:var(--text-primary)}
.top-btn svg{width:16px;height:16px;stroke:currentColor;fill:none;stroke-width:1.7}
.top-btn.ghost{border-color:var(--border)}

.avatar-btn{display:inline-flex;align-items:center;gap:9px;background:none;border:0;padding:4px;
  border-radius:var(--r-sm);cursor:pointer;font:inherit}
.avatar-btn:hover{background:var(--surface-sunken)}
.avatar{width:30px;height:30px;border-radius:50%;background:var(--brand);color:#fff;
  display:grid;place-items:center;font-size:12px;font-weight:700;flex:none}
.avatar-who{text-align:left;line-height:1.25}
.avatar-who b{display:block;font-size:13px;font-weight:600;color:var(--text-primary)}
.avatar-who span{display:block;font-size:10.5px;color:var(--text-muted);letter-spacing:.04em}

.menu{position:absolute;right:24px;top:calc(var(--top-h) - 6px);z-index:60;background:var(--surface-elevated);
  border:1px solid var(--border);border-radius:var(--r-md);box-shadow:var(--shadow-lg);
  padding:6px;min-width:190px}
.menu button,.menu a{display:block;width:100%;text-align:left;background:none;border:0;
  border-radius:var(--r-sm);padding:8px 10px;font:inherit;font-size:13px;color:var(--text-primary);
  text-decoration:none;cursor:pointer}
.menu button:hover,.menu a:hover{background:var(--surface-sunken)}
.menu hr{border:0;border-top:1px solid var(--border);margin:5px 2px}

/* ── Workspace ──────────────────────────────────────────────────────────*/
.work{padding:28px 32px 64px;min-width:0}
.page-head{display:flex;align-items:flex-start;gap:20px;flex-wrap:wrap;margin-bottom:22px}
.page-head h1{font-size:29px;line-height:1.15;letter-spacing:-.02em;margin:0;font-weight:650;
  font-family:var(--ui);color:var(--text-primary)}
.page-head p{margin:7px 0 0;font-size:14px;color:var(--text-secondary);max-width:70ch}
.page-actions{margin-left:auto;display:flex;gap:8px;flex-wrap:wrap}

h2.section{font-size:19px;font-weight:650;letter-spacing:-.01em;margin:32px 0 12px}

/* ── Metrics ────────────────────────────────────────────────────────────*/
.metrics{display:grid;grid-template-columns:repeat(auto-fit,minmax(168px,1fr));gap:12px;margin-bottom:8px}
.metric{background:var(--surface);border:1px solid var(--border);border-radius:var(--r-md);
  padding:15px 16px;box-shadow:var(--shadow-sm)}
.metric-label{font-size:11.5px;font-weight:600;letter-spacing:.05em;text-transform:uppercase;
  color:var(--text-muted);display:flex;align-items:center;gap:6px}
.metric-value{font-size:28px;font-weight:650;letter-spacing:-.02em;line-height:1.1;margin-top:7px}
.metric-note{font-size:11.5px;color:var(--text-muted);margin-top:3px}
.metric.is-urgent .metric-value{color:var(--danger)}
.metric.is-warn .metric-value{color:var(--warning)}
.metric a{color:inherit;text-decoration:none}

/* ── Attention ──────────────────────────────────────────────────────────*/
.attention{display:grid;gap:8px;margin-top:8px}
.att-row{display:flex;align-items:center;gap:12px;background:var(--surface);
  border:1px solid var(--border);border-left:3px solid var(--warning);
  border-radius:var(--r);padding:12px 14px;font-size:13.5px;text-align:left;
  cursor:pointer;font:inherit;width:100%;transition:border-color var(--t),box-shadow var(--t)}
.att-row:hover{box-shadow:var(--shadow-sm);border-left-color:var(--brand)}
.att-row.danger{border-left-color:var(--danger)}
.att-row b{font-weight:650}
.att-row .go{margin-left:auto;color:var(--text-muted);font-size:12px;white-space:nowrap}

/* ── Toolbar ────────────────────────────────────────────────────────────*/
.toolbar{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-bottom:14px}
.toolbar .find{position:relative;flex:0 1 260px;min-width:170px}
.toolbar .find input{width:100%;padding:7px 11px 7px 31px;border:1px solid var(--border);
  border-radius:var(--r-sm);background:var(--surface);font:inherit;font-size:13px}
.toolbar .find input:focus{outline:none;border-color:var(--brand);box-shadow:0 0 0 3px var(--brand-wash)}
.toolbar .find svg{position:absolute;left:10px;top:50%;transform:translateY(-50%);width:14px;height:14px;
  stroke:var(--text-muted);fill:none;stroke-width:1.8}
.toolbar select{padding:7px 26px 7px 10px;border:1px solid var(--border);border-radius:var(--r-sm);
  background:var(--surface);font:inherit;font-size:13px;color:var(--text-primary)}
.toolbar select:focus{outline:none;border-color:var(--brand);box-shadow:0 0 0 3px var(--brand-wash)}
.toolbar .count{margin-left:auto;font-size:12.5px;color:var(--text-muted)}

/* ── Tables ─────────────────────────────────────────────────────────────
   The primary surface. Dense, quiet, and the same everywhere. */
.tbl-wrap{background:var(--surface);border:1px solid var(--border);border-radius:var(--r-md);
  overflow:auto;box-shadow:var(--shadow-sm)}
table.tbl{width:100%;border-collapse:separate;border-spacing:0;font-size:13.5px}
.tbl thead th{position:sticky;top:0;z-index:1;background:var(--surface-sunken);
  font-size:11px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;
  color:var(--text-secondary);text-align:left;padding:10px 14px;white-space:nowrap;
  border-bottom:1px solid var(--border)}
.tbl tbody td{padding:11px 14px;border-bottom:1px solid var(--border);vertical-align:middle;
  color:var(--text-primary)}
.tbl tbody tr:last-child td{border-bottom:0}
.tbl tbody tr{transition:background var(--t)}
.tbl tbody tr:hover{background:var(--surface-sunken)}
.tbl tbody tr.clickable{cursor:pointer}
.tbl .num{text-align:right;font-variant-numeric:tabular-nums}
.tbl .dim{color:var(--text-secondary)}
.tbl .meta{font-size:11.5px;color:var(--text-muted);display:block;margin-top:2px}
.tbl .strong{font-weight:600}
.tbl th.sortable{cursor:pointer;user-select:none}
.tbl th.sortable:hover{color:var(--text-primary)}
.tbl th .arrow{opacity:.45;margin-left:4px;font-size:9px}
.tbl th.sorted .arrow{opacity:1}
.row-actions{display:flex;gap:4px;justify-content:flex-end}
.icon-btn{background:none;border:1px solid transparent;border-radius:6px;padding:5px 7px;
  font:inherit;font-size:12.5px;color:var(--text-secondary);cursor:pointer;white-space:nowrap;
  transition:background var(--t),color var(--t),border-color var(--t)}
.icon-btn:hover{background:var(--surface-sunken);color:var(--text-primary);border-color:var(--border)}
.icon-btn.ok:hover{color:var(--success);border-color:var(--success)}
.icon-btn.no:hover{color:var(--danger);border-color:var(--danger)}

/* ── Status ─────────────────────────────────────────────────────────────
   One meaning per colour, used nowhere else. */
.badge{display:inline-flex;align-items:center;gap:5px;font-size:11.5px;font-weight:600;
  padding:3px 9px;border-radius:999px;white-space:nowrap;line-height:1.5}
.badge::before{content:"";width:5px;height:5px;border-radius:50%;background:currentColor;flex:none}
.badge.ok     {background:var(--success-wash); color:var(--success)}
.badge.pending{background:var(--warning-wash); color:var(--warning)}
.badge.bad    {background:var(--danger-wash);  color:var(--danger)}
.badge.info   {background:var(--info-wash);    color:var(--info)}
.badge.off    {background:var(--neutral-wash); color:var(--neutral)}
.badge.plain::before{display:none}

/* ── Empty states ───────────────────────────────────────────────────────
   Compact and deliberate. The old one filled a monitor to say nothing. */
.empty-state{background:var(--surface);border:1px solid var(--border);border-radius:var(--r-md);
  padding:34px 28px;text-align:center;box-shadow:var(--shadow-sm)}
.empty-state .mark{width:44px;height:44px;margin:0 auto 14px;border-radius:50%;
  display:grid;place-items:center;background:var(--success-wash);color:var(--success)}
.empty-state .mark.neutral{background:var(--neutral-wash);color:var(--neutral)}
.empty-state .mark svg{width:21px;height:21px;stroke:currentColor;fill:none;stroke-width:1.9;
  stroke-linecap:round;stroke-linejoin:round}
.empty-state h3{font-size:16.5px;font-weight:650;margin:0 0 5px}
.empty-state p{font-size:13.5px;color:var(--text-secondary);margin:0 auto;max-width:52ch;line-height:1.6}
.empty-state .facts{margin-top:14px;font-size:12px;color:var(--text-muted)}
.empty-state .facts span+span::before{content:"·";margin:0 8px;color:var(--border-strong)}

/* ── Drawer ─────────────────────────────────────────────────────────────
   Inspect without losing your place in the queue. */
.drawer-bg{position:fixed;inset:0;background:rgba(26,23,38,.34);z-index:70;backdrop-filter:blur(1px)}
.drawer{position:fixed;top:0;right:0;bottom:0;z-index:71;width:min(560px,100%);
  background:var(--surface);border-left:1px solid var(--border);box-shadow:var(--shadow-lg);
  display:flex;flex-direction:column}
.drawer-head{display:flex;align-items:flex-start;gap:14px;padding:20px 22px 16px;
  border-bottom:1px solid var(--border);flex:none}
.drawer-head h2{font-size:18px;font-weight:650;margin:0;letter-spacing:-.01em}
.drawer-head p{margin:5px 0 0;font-size:12.5px;color:var(--text-secondary)}
.drawer-x{margin-left:auto;background:none;border:1px solid var(--border);border-radius:var(--r-sm);
  width:30px;height:30px;font-size:17px;line-height:1;color:var(--text-secondary);cursor:pointer;flex:none}
.drawer-x:hover{background:var(--surface-sunken);color:var(--text-primary)}
.drawer-body{padding:18px 22px 28px;overflow-y:auto;flex:1}
.dl{display:grid;grid-template-columns:minmax(96px,auto) 1fr;gap:9px 16px;font-size:13.5px;margin:0}
.dl dt{color:var(--text-muted);font-size:12px}
.dl dd{margin:0;color:var(--text-primary);overflow-wrap:anywhere}
.drawer-sec{margin-top:22px;padding-top:18px;border-top:1px solid var(--border)}
.drawer-sec h3{font-size:11.5px;font-weight:700;letter-spacing:.07em;text-transform:uppercase;
  color:var(--text-muted);margin:0 0 10px}
.drawer-foot{padding:14px 22px;border-top:1px solid var(--border);display:flex;gap:8px;
  flex-wrap:wrap;background:var(--surface-sunken);flex:none}

/* ── Buttons ────────────────────────────────────────────────────────────*/
.btn-p,.btn-s{border-radius:var(--r-sm);padding:8px 14px;font:inherit;font-size:13.5px;
  font-weight:600;cursor:pointer;border:1px solid transparent;transition:background var(--t),
  border-color var(--t),color var(--t)}
.btn-p{background:var(--brand);color:#fff}
.btn-p:hover{background:var(--brand-strong)}
.btn-s{background:var(--surface);color:var(--text-primary);border-color:var(--border-strong)}
.btn-s:hover{background:var(--surface-sunken)}
.btn-s.danger:hover{color:var(--danger);border-color:var(--danger)}
.btn-p:disabled,.btn-s:disabled{opacity:.55;cursor:default}

.note{font-size:12.5px;color:var(--text-muted);line-height:1.6;margin-top:12px;max-width:74ch}

/* ── Responsive ─────────────────────────────────────────────────────────*/
.nav-toggle{display:none}
@media (max-width:1000px){
  /* minmax(0,1fr), not 1fr: a bare 1fr is minmax(auto,1fr), and an auto
     minimum is the content's min-content width -- so one wide table inside
     stretched the column past the viewport and scrolled the whole page
     sideways instead of scrolling inside its own frame. */
  .shell{grid-template-columns:minmax(0,1fr)}
  .side{position:fixed;left:0;top:0;bottom:0;width:var(--nav-w);z-index:80;
    transform:translateX(-100%);transition:transform var(--t)}
  .side.is-open{transform:none;box-shadow:var(--shadow-lg)}
  .nav-toggle{display:inline-flex}
  .work{padding:20px 18px 60px}
  .top{padding:0 16px;gap:10px}
  .top-search{flex-basis:auto;width:100%;order:5;display:none}
  .page-head h1{font-size:24px}
}
@media (max-width:560px){
  .work{padding:16px 12px 56px}
  .metrics{grid-template-columns:repeat(auto-fit,minmax(140px,1fr))}
  .drawer{width:100%}
  .hide-sm{display:none}
}
@media (prefers-reduced-motion:reduce){*{transition:none!important}}

/* styles.css also defines .note, for a different surface. The console's own
   wins by coming last and by saying everything it needs. */
.work .note{background:none;border:0;padding:0;color:var(--text-muted);font-size:12.5px;
  line-height:1.65;max-width:74ch;margin-top:14px}
.work .note code{background:var(--surface-sunken);border-radius:4px;padding:1px 5px;font-size:12px}

/* ── Entering a listing ─────────────────────────────────────────────────
   A form in the drawer, using the drawer's own width rather than a page of
   its own. Two-up where the pair belongs together -- price and bedrooms,
   city and neighbourhood -- and full width where the answer is prose. */
.nl-field{margin-bottom:14px}
.nl-field label{display:block;font-size:12.5px;font-weight:600;color:var(--text-secondary);margin-bottom:6px}
.nl-field input,.nl-field select,.nl-field textarea{
  width:100%;padding:9px 11px;border:1px solid var(--border);border-radius:var(--r-sm);
  background:var(--surface);color:var(--text-primary);font:inherit;font-size:14px}
.nl-field textarea{resize:vertical;line-height:1.6;min-height:96px}
.nl-field input:focus,.nl-field select:focus,.nl-field textarea:focus{
  outline:none;border-color:var(--brand);box-shadow:0 0 0 3px var(--brand-wash)}
.nl-field .note{margin:5px 0 0;font-size:12px;color:var(--text-muted)}
.nl-two{display:grid;grid-template-columns:1fr 1fr;gap:12px}
@media (max-width:520px){.nl-two{grid-template-columns:1fr;gap:0}}
/* The drawer is a light surface, so the shared .auth-msg red would be the
   dark-card one. This states its own. */
.drawer .auth-msg{margin-top:4px;min-height:18px;font-size:13px;text-align:left;color:var(--text-secondary)}
.drawer .auth-msg.is-error{color:var(--danger);font-weight:500}

/* ══ Dashboard ═════════════════════════════════════════════════════════
   A command centre rather than a table of contents. Everything here draws
   something the database actually returned; where a figure does not exist
   the card says so in words instead of showing a trend nobody recorded. */

.dash-head h1{font-family:var(--serif,Georgia,serif);font-size:27px;letter-spacing:-.015em}
.dash-actions{align-items:center}
.stamp{font-size:12.5px;color:var(--text-muted);white-space:nowrap}
.btn-s .ic,.btn-p .ic{width:15px;height:15px;margin-right:6px;vertical-align:-2px}
#refreshNow.is-spinning .ic{animation:pt-spin .9s linear infinite}
@keyframes pt-spin{to{transform:rotate(360deg)}}
.ic{width:18px;height:18px;fill:none;stroke:currentColor;stroke-width:1.7;
  stroke-linecap:round;stroke-linejoin:round}

/* ── Inside Funguo ────────────────────────────────────────────────────
   The property is the hero, so the image gets roughly two thirds of the
   card and the type sits in the gradient rather than on top of it. */
.strip-h{font-family:var(--serif,Georgia,serif);font-size:16.5px;font-weight:600;
  margin:0 0 10px;letter-spacing:-.005em}
.strip{display:grid;grid-template-columns:repeat(6,1fr);gap:12px;margin-bottom:22px}
@media(max-width:1180px){.strip{grid-template-columns:repeat(3,1fr)}}
@media(max-width:660px){.strip{grid-template-columns:repeat(2,1fr)}}
.strip-card{position:relative;display:block;height:212px;padding:0;border:1px solid var(--border);
  border-radius:14px;overflow:hidden;background:var(--nav);color:#fff;cursor:pointer;
  text-align:left;transition:transform 180ms ease,box-shadow 180ms ease}
.strip-card:hover{transform:translateY(-2px);box-shadow:0 12px 28px -16px rgba(20,14,40,.6)}
.strip-card:focus-visible{outline:2px solid var(--brand);outline-offset:2px}
.strip-img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  transition:transform 260ms ease}
.strip-card:hover .strip-img{transform:scale(1.04)}
.strip-card::after{content:"";position:absolute;inset:0;
  background:linear-gradient(180deg,rgba(18,12,37,0) 42%,rgba(18,12,37,.86) 100%)}
/* No photograph is a real state, not a gap to paper over. A quiet
   aubergine field with the area's own coordinates on it, never a stock
   interior standing in for a property nobody has photographed. */
.strip-card.no-shot{background:
  radial-gradient(120% 90% at 50% 0%, rgba(98,71,190,.28), transparent 60%),
  linear-gradient(165deg,#241A4D,#171033)}
.strip-card.no-shot::after{background:none}
.strip-card.is-load{background:linear-gradient(90deg,#221A3C,#2C2350,#221A3C);
  background-size:200% 100%;animation:pt-shimmer 1.3s ease-in-out infinite;border-color:transparent}
.strip-body{position:absolute;left:0;right:0;bottom:0;z-index:1;padding:13px 14px}
.strip-price{display:block;font-size:15px;font-weight:650;letter-spacing:-.01em;margin-bottom:1px}
.strip-name{display:block;font-family:var(--serif,Georgia,serif);font-size:15.5px;line-height:1.2}
.strip-sub{display:block;margin-top:3px;font-size:11.5px;color:rgba(255,255,255,.72)}
.strip-coord{font-variant-numeric:tabular-nums;letter-spacing:.02em}
@media(prefers-reduced-motion:reduce){
  .strip-card,.strip-img{transition:none}
  .strip-card:hover{transform:none}
  .strip-card:hover .strip-img{transform:none}
  .strip-card.is-load{animation:none}
}

/* ── the six counts ───────────────────────────────────────────────────*/
.metrics{display:grid;grid-template-columns:repeat(6,1fr);gap:12px;margin-bottom:22px}
@media(max-width:1180px){.metrics{grid-template-columns:repeat(3,1fr)}}
@media(max-width:620px){.metrics{grid-template-columns:repeat(2,1fr)}}
.kpi{background:var(--surface);border:1px solid var(--border);border-radius:var(--r);
  padding:14px 15px 13px;transition:transform 170ms ease,box-shadow 170ms ease,border-color 170ms ease}
.kpi:hover{transform:translateY(-2px);box-shadow:0 8px 20px -16px rgba(20,14,40,.5);
  border-color:var(--border-strong)}
.kpi-top{display:flex;align-items:center;gap:8px;margin-bottom:11px}
.kpi-ic{display:grid;place-items:center;width:28px;height:28px;border-radius:8px;flex:none}
.kpi-label{font-size:11.5px;font-weight:650;letter-spacing:.055em;text-transform:uppercase;
  color:var(--text-secondary);line-height:1.25}
.kpi-value{font-size:31px;font-weight:600;letter-spacing:-.02em;line-height:1;
  font-variant-numeric:tabular-nums}
.kpi-note{margin-top:6px;font-size:12px;color:var(--text-muted)}
.kpi.is-ok     .kpi-ic{background:var(--acc-ok-wash);color:var(--acc-ok)}
.kpi.is-warn   .kpi-ic{background:var(--acc-warn-wash);color:var(--acc-warn)}
.kpi.is-urgent .kpi-ic{background:var(--acc-urgent-wash);color:var(--acc-urgent)}
.kpi.is-violet .kpi-ic{background:var(--acc-violet-wash);color:var(--acc-violet)}
.kpi.is-info   .kpi-ic{background:var(--acc-info-wash);color:var(--acc-info)}
.kpi.is-brand  .kpi-ic{background:var(--acc-brand-wash);color:var(--acc-brand)}
/* A zero is a real answer, so it is quiet rather than alarming. */
.kpi.is-zero .kpi-value{color:var(--text-muted);font-weight:500}
.kpi.is-zero .kpi-ic{background:var(--surface-sunken);color:var(--text-muted)}

/* ── panels ───────────────────────────────────────────────────────────*/
.dash-split{display:grid;grid-template-columns:1fr 1fr;gap:16px;margin-bottom:16px}
@media(max-width:1000px){.dash-split{grid-template-columns:1fr}}
.panel{background:var(--surface);border:1px solid var(--border);border-radius:var(--r);
  padding:16px 18px 18px;margin-bottom:16px}
.panel-head{display:flex;align-items:baseline;gap:12px;margin-bottom:14px}
.panel-head h2{font-family:var(--serif,Georgia,serif);font-size:16.5px;font-weight:600;margin:0;
  letter-spacing:-.005em}
.panel-link{margin-left:auto;background:none;border:0;padding:0;font:inherit;font-size:12.5px;
  font-weight:600;color:var(--brand);cursor:pointer}
.panel-link:hover{text-decoration:underline}

/* Nothing to do is a result, not an empty page: it gets a line, not a slab. */
.all-clear{display:flex;gap:12px;align-items:flex-start;padding:14px 15px;border-radius:var(--r-sm);
  background:var(--acc-ok-wash)}
.all-clear.quiet{background:var(--surface-sunken)}
.all-clear b{font-size:14px}
.all-clear p{margin:3px 0 0;font-size:13px;color:var(--text-secondary);line-height:1.55}
.ac-tick{display:grid;place-items:center;width:26px;height:26px;border-radius:50%;flex:none;
  background:var(--acc-ok);color:#fff}
.ac-tick .ic{width:15px;height:15px;stroke-width:2.4}
.att-row{display:flex;align-items:center;gap:10px;width:100%}
.att-dot{width:7px;height:7px;border-radius:50%;background:var(--acc-warn);flex:none}
.att-row.danger .att-dot{background:var(--acc-urgent)}

/* ── activity ─────────────────────────────────────────────────────────*/
.feed{list-style:none;margin:0;padding:0}
.feed-row{display:flex;gap:11px;align-items:flex-start;padding:11px 0;
  border-bottom:1px solid var(--border)}
.feed-row:last-child{border-bottom:0;padding-bottom:0}
.feed-dot{width:8px;height:8px;border-radius:50%;margin-top:6px;flex:none;background:var(--text-muted)}
.feed-dot.is-ok{background:var(--acc-ok)}
.feed-dot.is-bad{background:var(--acc-urgent)}
.feed-dot.is-info{background:var(--acc-info)}
.feed-dot.is-off{background:var(--border-strong)}
.feed-body{min-width:0;flex:1}
.feed-body b{display:block;font-size:13.5px;font-weight:600}
.feed-sub,.feed-by,.feed-why{display:block;font-size:12.5px;color:var(--text-secondary);margin-top:2px}
.feed-by{color:var(--text-muted)}
.feed-why{font-style:italic}
.feed-when{font-size:12px;color:var(--text-muted);white-space:nowrap;flex:none}

/* ── pulse ────────────────────────────────────────────────────────────*/
.pulse-row{margin-bottom:13px}
.pulse-name{display:flex;align-items:center;gap:8px;font-size:13.5px;font-weight:600;margin-bottom:5px}
.sig{font-size:10.5px;font-weight:650;letter-spacing:.04em;text-transform:uppercase;
  padding:2px 7px;border-radius:99px;background:var(--surface-sunken);color:var(--text-muted)}
.sig.is-undersupplied{background:var(--acc-urgent-wash);color:var(--acc-urgent)}
.sig.is-high_demand{background:var(--acc-warn-wash);color:var(--acc-warn)}
.sig.is-balanced{background:var(--acc-ok-wash);color:var(--acc-ok)}
.sig.is-oversupplied{background:var(--acc-info-wash);color:var(--acc-info)}
.pulse-bars{display:grid;gap:3px}
.bar{display:block;height:7px;border-radius:99px;min-width:2px;
  transition:width 220ms cubic-bezier(.2,.6,.3,1)}
.bar.demand{background:var(--acc-violet)}
.bar.supply{background:var(--border-strong)}
.pulse-nums{display:flex;gap:14px;margin-top:4px;font-size:11.5px;color:var(--text-muted)}
.pulse-key{margin:14px 0 0;font-size:11.5px;color:var(--text-muted);line-height:1.5}
/* A skeleton rather than a jump, while the second round trip lands. */
.pulse-skel i{display:block;height:34px;border-radius:var(--r-sm);margin-bottom:10px;
  background:linear-gradient(90deg,var(--surface-sunken),var(--bg),var(--surface-sunken));
  background-size:200% 100%;animation:pt-shimmer 1.3s ease-in-out infinite}
@keyframes pt-shimmer{to{background-position:-200% 0}}
@media(prefers-reduced-motion:reduce){
  .kpi,.strip-card,.strip-img,.bar{transition:none}
  .kpi:hover,.strip-card:hover{transform:none}
  .strip-card:hover .strip-img{transform:none}
  .pulse-skel i,#refreshNow.is-spinning .ic{animation:none}
}
.bar-none{display:block;font-size:11px;color:var(--text-muted);line-height:1.5}

/* ── global search results ────────────────────────────────────────────*/
.top-search{position:relative}
.gs-panel{position:absolute;top:calc(100% + 6px);left:0;right:0;z-index:60;max-height:70vh;
  overflow-y:auto;background:var(--surface);border:1px solid var(--border);border-radius:var(--r);
  box-shadow:0 16px 40px -20px rgba(20,14,40,.55);padding:6px}
.gs-group{margin:8px 8px 4px;font-size:10.5px;font-weight:700;letter-spacing:.07em;
  text-transform:uppercase;color:var(--text-muted)}
.gs-row{display:block;width:100%;text-align:left;background:none;border:0;border-radius:var(--r-sm);
  padding:7px 9px;cursor:pointer;font:inherit}
.gs-row:hover,.gs-row:focus-visible{background:var(--surface-sunken);outline:none}
.gs-row b{display:block;font-size:13.5px;font-weight:600}
.gs-row span{display:block;font-size:12px;color:var(--text-secondary);margin-top:1px}
.gs-none{margin:10px;font-size:13px;color:var(--text-secondary)}

/* ── neighbourhood intelligence ──────────────────────────────────────*/
.hoods{display:grid;grid-template-columns:repeat(auto-fill,minmax(230px,1fr));gap:14px}
.hood{background:var(--surface);border:1px solid var(--border);border-radius:var(--r);overflow:hidden;
  transition:transform 170ms ease,box-shadow 170ms ease}
.hood:hover{transform:translateY(-2px);box-shadow:0 10px 24px -18px rgba(20,14,40,.5)}
.hood-shot{position:relative;display:block;width:100%;height:118px;padding:0;border:0;cursor:pointer;
  background:linear-gradient(160deg,#241A4D,#1A1330);overflow:hidden}
.hood-shot img{width:100%;height:100%;object-fit:cover;transition:transform 260ms ease}
.hood:hover .hood-shot img{transform:scale(1.05)}
.hood-shot::after{content:"";position:absolute;inset:0;
  background:linear-gradient(180deg,rgba(18,12,37,.05) 40%,rgba(18,12,37,.8) 100%)}
.hood-name{position:absolute;left:11px;bottom:9px;z-index:1;display:flex;align-items:center;gap:5px;
  color:#fff;font-weight:650;font-size:14px}
.hood-name .ic{width:13px;height:13px;opacity:.85}
.hood-body{display:flex;align-items:center;gap:16px;padding:11px 13px 9px}
.hood-stat b{display:block;font-size:19px;font-weight:600;line-height:1.1;font-variant-numeric:tabular-nums}
.hood-stat span{font-size:11px;color:var(--text-muted)}
.hood-sig{margin-left:auto}
.hood-credit{margin:0;padding:0 13px 11px;font-size:10.5px;color:var(--text-muted);line-height:1.4}
.hood-credit a{color:inherit}
@media(prefers-reduced-motion:reduce){
  .hood,.hood-shot img{transition:none}
  .hood:hover{transform:none}
  .hood:hover .hood-shot img{transform:none}
}

/* ── sidebar groups ──────────────────────────────────────────────────*/
.nav-group{display:flex;align-items:center;gap:7px;width:100%;background:none;border:0;
  padding:14px 14px 6px;font:inherit;font-size:10.5px;font-weight:700;letter-spacing:.09em;
  text-transform:uppercase;color:var(--text-on-dark-dim);cursor:pointer;text-align:left}
.nav-group:hover{color:var(--text-on-dark)}
.nav-group:focus-visible{outline:2px solid var(--brand);outline-offset:-2px;border-radius:4px}
.nav-caret{width:0;height:0;margin-left:auto;border-left:4px solid currentColor;
  border-top:3.5px solid transparent;border-bottom:3.5px solid transparent;
  transition:transform 160ms ease;opacity:.7}
.nav-group[aria-expanded="true"] .nav-caret{transform:rotate(90deg)}
.nav-group .nav-n{margin-left:6px}
/* A clearer "you are here": a filled rail, not only a tint. */
.nav-item.is-on{position:relative}
.nav-item.is-on::before{content:"";position:absolute;left:0;top:6px;bottom:6px;width:3px;
  border-radius:0 3px 3px 0;background:var(--brand)}
@media(prefers-reduced-motion:reduce){.nav-caret{transition:none}}

/* ── drawer additions ────────────────────────────────────────────────*/
.shots{display:grid;grid-template-columns:repeat(3,1fr);gap:6px}
.shot{width:100%;aspect-ratio:4/3;object-fit:cover;border-radius:var(--r-sm);
  border:1px solid var(--border);background:var(--surface-sunken)}
.int-row{display:flex;gap:26px}
.int b{display:block;font-size:21px;font-weight:600;line-height:1.1;font-variant-numeric:tabular-nums}
.int span{font-size:12px;color:var(--text-muted)}

/* ── Toast ────────────────────────────────────────────────────────────
   One line of feedback that does not block the page, unlike the alert() it
   replaces, and which says which action it is talking about. */
.toast{position:fixed;left:50%;bottom:26px;transform:translateX(-50%);z-index:200;
  max-width:min(520px,calc(100vw - 32px));padding:11px 16px;border-radius:10px;
  font-size:13.5px;font-weight:500;color:#fff;background:var(--nav);
  box-shadow:0 12px 32px -12px rgba(20,14,40,.6);animation:toast-in 180ms ease}
.toast.is-ok::before{content:"\2713  ";font-weight:700}
.toast.is-bad{background:var(--acc-urgent)}
.toast.is-bad::before{content:"\26A0  ";font-weight:700}
@keyframes toast-in{from{opacity:0;transform:translate(-50%,8px)}}
@media(prefers-reduced-motion:reduce){.toast{animation:none}}

/* Availability queue */
.tbl .sub{display:block;font-size:11.5px;color:var(--text-muted);margin-top:1px}
.never{color:var(--acc-urgent);font-weight:600}
.panel-head .count{margin-left:auto;font-size:12.5px;color:var(--text-muted)}

/* The moderation pin: small enough to sit in the drawer, large enough that
   a coordinate in the wrong half of the country is obvious at a glance. */
.pin-check{display:block;width:100%;max-width:232px;margin:0 0 12px;background:#faf8f5;border:1px solid #e8e1ea;border-radius:10px}

/* ── The listings workspace ─────────────────────────────────────────────
   A table of properties is not a table of rows: the thing being moderated
   is a place, and a moderator recognises a place by looking at it. These
   rules add the picture, separate the two status questions, and put the
   destructive moves behind a deliberate second click. */

/* Counts that are also the filter. Each one is the list, counted, so a card
   cannot claim a number the table below it does not show. */
.sum-strip{display:grid;grid-template-columns:repeat(6,minmax(0,1fr));gap:10px;margin-bottom:14px}
.sum-card{display:flex;flex-direction:column;gap:3px;align-items:flex-start;text-align:left;
  background:var(--surface);border:1px solid var(--border);border-radius:var(--r-md);
  padding:12px 14px;font:inherit;cursor:pointer;box-shadow:var(--shadow-sm);
  transition:border-color var(--t),box-shadow var(--t),background var(--t)}
.sum-card:hover{border-color:var(--border-strong)}
.sum-card:focus-visible{outline:2px solid var(--brand);outline-offset:2px}
.sum-card.is-on{border-color:var(--brand);background:var(--brand-wash);box-shadow:none}
.sum-n{font-size:24px;font-weight:650;letter-spacing:-.02em;line-height:1.1;color:var(--text-primary)}
.sum-l{font-size:11px;font-weight:600;letter-spacing:.05em;text-transform:uppercase;color:var(--text-muted)}
.sum-card.is-on .sum-l{color:var(--brand)}

/* Lanes and the narrowing selects. One row on a desktop, wrapping on a phone. */
.fbar{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin-bottom:14px}
.lanes{display:inline-flex;background:var(--surface-sunken);border:1px solid var(--border);
  border-radius:999px;padding:3px;gap:2px}
.lane{border:0;background:none;border-radius:999px;padding:6px 13px;font:inherit;font-size:12.5px;
  font-weight:600;color:var(--text-secondary);cursor:pointer;transition:background var(--t),color var(--t)}
.lane:hover{color:var(--text-primary)}
.lane.is-on{background:var(--surface);color:var(--brand);box-shadow:var(--shadow-sm)}
.lane:focus-visible{outline:2px solid var(--brand);outline-offset:2px}
.fsels{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-left:auto}
.fsel{display:inline-flex;align-items:center;gap:6px;font-size:12px;color:var(--text-muted)}
.fsel>span{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
.fsel select{padding:7px 26px 7px 10px;border:1px solid var(--border);border-radius:var(--r-sm);
  background:var(--surface);font:inherit;font-size:13px;color:var(--text-primary)}
.fsel select:focus{outline:none;border-color:var(--brand);box-shadow:0 0 0 3px var(--brand-wash)}

/* The photograph, and the honest absence of one. */
.tbl td.c-thumb,.tbl th.c-thumb{width:60px;padding-right:0}
.lthumb{display:block;width:46px;height:46px;border-radius:8px;overflow:hidden;
  background:var(--surface-sunken);border:1px solid var(--border)}
.lthumb img{width:100%;height:100%;object-fit:cover;display:block}
.lthumb.is-none{display:flex;align-items:center;justify-content:center;
  border-style:dashed;border-color:var(--border-strong)}
.lthumb.is-none i{font-style:normal;font-size:9px;font-weight:700;letter-spacing:.04em;
  text-transform:uppercase;color:var(--text-muted);text-align:center;line-height:1.2;padding:0 3px}

.owner{display:inline-flex;align-items:center;gap:5px}
.vtick{display:inline-flex;color:var(--success)}
.vtick .ic{width:13px;height:13px;stroke:currentColor;fill:none;stroke-width:2.4}

/* Availability carries a second line when the confirmation is getting old;
   the badge says the state, the line says how it was arrived at. */
.tbl td .meta{display:block;font-size:11.5px;color:var(--text-muted);margin-top:2px}
.tbl td .badge + .badge{margin-left:5px}

/* A sortable heading is a button, so it can be tabbed to and pressed. */
.th-sort{display:inline-flex;align-items:center;gap:5px;background:none;border:0;padding:0;
  font:inherit;font-size:11px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;
  color:inherit;cursor:pointer}
.th-sort:hover{color:var(--text-primary)}
.th-sort.is-on{color:var(--brand)}
.th-sort:focus-visible{outline:2px solid var(--brand);outline-offset:2px;border-radius:4px}
.th-caret{opacity:.55;font-size:10px}
.th-sort.is-on .th-caret{opacity:1}

/* The overflow. Everything that is destructive, or simply not the move
   somebody came to make, lives behind it. */
.menu-wrap{position:relative;display:inline-block}
.menu-wrap>summary{list-style:none;cursor:pointer;border:1px solid transparent;border-radius:6px;
  padding:4px 8px;color:var(--text-secondary);font-size:15px;line-height:1.2;
  transition:background var(--t),border-color var(--t)}
.menu-wrap>summary::-webkit-details-marker{display:none}
.menu-wrap>summary:hover{background:var(--surface-sunken);border-color:var(--border);color:var(--text-primary)}
.menu-wrap>summary:focus-visible{outline:2px solid var(--brand);outline-offset:2px}
.menu-pop{position:absolute;right:0;top:calc(100% + 4px);z-index:20;min-width:150px;
  background:var(--surface-elevated);border:1px solid var(--border);border-radius:var(--r-sm);
  box-shadow:0 8px 24px rgba(26,23,38,.14);padding:4px;display:grid;gap:2px}
.menu-item{display:block;width:100%;text-align:left;background:none;border:0;border-radius:6px;
  padding:7px 10px;font:inherit;font-size:13px;color:var(--text-primary);cursor:pointer}
.menu-item:hover{background:var(--surface-sunken)}
.menu-item.danger{color:var(--danger)}
.menu-item.danger:hover{background:var(--danger-wash)}
.menu-item:focus-visible{outline:2px solid var(--brand);outline-offset:-2px}

.pager{display:flex;align-items:center;justify-content:flex-end;gap:12px;margin-top:12px;
  font-size:12.5px;color:var(--text-muted)}

@media(max-width:1100px){
  .sum-strip{grid-template-columns:repeat(3,minmax(0,1fr))}
  .fsels{margin-left:0}
}
@media(max-width:640px){
  .sum-strip{grid-template-columns:repeat(2,minmax(0,1fr));gap:8px}
  .sum-n{font-size:20px}
  .fsels{width:100%}
  .fsel,.fsel select{flex:1 1 140px}
  .tbl td.c-thumb,.tbl th.c-thumb{width:46px}
  .lthumb{width:38px;height:38px}
}

/* Density and wrapping. A price that wraps onto two lines makes a row twice
   as tall for no information, and the owner's tick belongs against the name
   rather than adrift at the column edge. */
.tbl td.num{white-space:nowrap}
.owner{flex-wrap:nowrap;gap:4px}
.owner .vtick{flex:none}
.tbl tbody td{padding-top:9px;padding-bottom:9px}
.tbl td .strong{display:block;line-height:1.35}
.lthumb.is-none i{line-height:1.15}

/* A photo that exists but did not arrive is not the same as no photo, and
   neither claim fits in 46 pixels of text -- so this one is a mark with the
   sentence in its tooltip, and the row's own columns still say everything. */
.lthumb.is-warn{display:flex;align-items:center;justify-content:center;
  border:1px dashed var(--warning);background:var(--warning-wash)}
.lthumb.is-warn i{font-style:normal;font-weight:700;font-size:15px;color:var(--warning)}
/* The tick belongs against the name it verifies. */
.owner{white-space:nowrap}

/* The column holding the header and the workspace is a grid item, and a grid
   item will not shrink below its content unless it is told it may. Without
   this the table's own horizontal scroll never engages. */
.shell>div{min-width:0}
.tbl-wrap{max-width:100%}

/* The mark in the top bar is for the widths where the sidebar -- which
   normally carries it -- has slid off-canvas. */
.top-brand{display:none}
.top-brand img{display:block;width:118px;height:auto}
@media (max-width:1000px){
  .top-brand{display:block;flex:none}
  /* With the mark in the bar there is no room left for the trail, and it was
     overflowing its box without so much as an ellipsis. The heading directly
     below names the section, and the sidebar is the navigation -- so the
     crumb goes on a phone, the way the search already does. */
  .crumb{display:none}
}
