:root{
    --brand:#25b657; --brand-2:#189a45; --brand-glow:#3ee06f; --brand-ink:#209d50;
    --black:#0b0c0b; --black-2:#070807; --panel:#131513;
    --ink:#0e100e; --body:#39424c; --muted:#79837b;
    --line:#e8ece8; --hair:#eef1ee; --bg:#ffffff; --bg-app:#f1f3f0; --soft:#f4f7f4;
    --err:#d64545;
    --shadow:0 22px 50px -18px rgba(12,20,14,.20);
    --shadow-sm:0 1px 2px rgba(12,20,14,.04), 0 8px 24px -14px rgba(12,20,14,.14);
    --r:16px; --r-sm:12px;
  }
  *{box-sizing:border-box}
  /* overflow-x on HTML as well as body, not body alone.
     On iOS Safari the horizontal scroll is owned by the document element, and
     `overflow-x:hidden` on body alone is quietly ignored — the page still pans
     sideways. Both are needed. `max-width:100%` stops the element itself from
     being the thing that overflows. */
  /* scrollbar-gutter: the content is centred with margin:0 auto, so whether a
     vertical scrollbar exists changes the usable width — and therefore where
     the centre is. The master console is a long list and HAS one; an agent
     page is often short and does NOT, so switching between them jumped the
     layout sideways by the scrollbar width. Reserving the gutter permanently
     means the centre never moves. Nothing about view-as was ever meant to
     offset the page; the green bar is the only intentional signal. */
  /* ---- iOS focus-zoom guard ------------------------------------------
     Safari on iOS ZOOMS THE PAGE IN when a text field smaller than 16px
     receives focus, and never zooms back out. Tapping the login email box at
     15.5px left the whole portal permanently magnified and panning sideways
     for the rest of the session — which is what looked like a layout bug on
     every screen.

     16px is the threshold, so every field that can take focus on a phone is
     pinned to at least that. Done with a media query so desktop keeps its
     smaller, tighter type. Never fix this with maximum-scale/user-scalable=no:
     that stops the zoom by removing pinch-zoom entirely, which is the exact
     trap that makes HDPhotoHub invoices unreadable on a phone. */
  @media (max-width:760px){
    input,select,textarea{font-size:16px !important}
  }

  /* Desktop only. On a phone the scrollbars are OVERLAY — they float above
     the content and reserve nothing — so a stable gutter there subtracts
     width for a scrollbar that never appears, leaving an uneven margin. The
     jump it fixes (centred content moving when a scrollbar appears) is a
     desktop-only problem, so the fix belongs behind a desktop-only query. */
  @media (pointer: fine){ html{scrollbar-gutter:stable} }
  html,body{margin:0;padding:0;max-width:100%;
    /* hidden first as the fallback, clip second so modern browsers take it.
       `hidden` turns the element into a scroll container, which silently
       breaks position:sticky on the topbar; `clip` blocks the pan WITHOUT
       creating one, so sticky keeps working. */
    overflow-x:hidden;overflow-x:clip}
  body{background:var(--bg-app);color:var(--body);
       font-family:Inter,-apple-system,Segoe UI,Roboto,Helvetica,Arial,sans-serif;
       -webkit-font-smoothing:antialiased;line-height:1.5;letter-spacing:-.005em}
  h1,h2,h3{font-family:Fraunces,Georgia,serif;color:var(--ink);margin:0;line-height:1.12;font-weight:600;letter-spacing:-.015em}
  a{color:inherit}
  button{font-family:inherit}
  .hidden{display:none!important}

  /* ---------- Brand wordmark ---------- */
  .brand{display:inline-flex;align-items:center;gap:11px;font-weight:700;letter-spacing:.02em}
  .brand .mk{width:26px;height:26px;border-radius:6px;display:grid;grid-template-columns:1fr 1fr;grid-template-rows:1fr 1fr;overflow:hidden}
  .brand .mk i{display:block}
  .brand .mk i:nth-child(1){background:#33d96a}.brand .mk i:nth-child(2){background:#209d50}
  .brand .mk i:nth-child(3){background:#0e6b34}.brand .mk i:nth-child(4){background:#33d96a}
  .brand .wm{font-size:17px;text-transform:uppercase}
  .brand .wm b{color:var(--ink)} .brand .wm span{color:var(--brand-ink)}
  .brand.on-dark .wm b{color:#fff} .brand.on-dark .wm span{color:var(--brand-glow)}

  /* ---------- AUTH (split hero) ---------- */
  #auth{min-height:100vh;display:grid;grid-template-columns:1.05fr .95fr}
  .pane-brand{position:relative;overflow:hidden;color:#eef3ee;
    background:radial-gradient(900px 620px at 84% 6%, rgba(37,182,87,.20) 0%, transparent 52%),
               linear-gradient(162deg,#0d0f0d 0%, #070807 100%);
    padding:56px 60px;display:flex;flex-direction:column;justify-content:space-between}
  .pane-brand::before{content:"";position:absolute;left:-10%;right:-10%;top:-60%;height:120%;
    background:radial-gradient(closest-side, rgba(37,182,87,.18), transparent 70%);pointer-events:none}
  .pane-brand::after{content:"";position:absolute;inset:0;opacity:.08;pointer-events:none;
    background-image:linear-gradient(rgba(255,255,255,.6) 1px,transparent 1px),linear-gradient(90deg,rgba(255,255,255,.6) 1px,transparent 1px);
    background-size:36px 36px;mask:radial-gradient(760px 520px at 78% 26%,#000,transparent 74%)}
  .pane-brand>*{position:relative;z-index:1}
  .accent-line{width:52px;height:4px;border-radius:4px;background:linear-gradient(90deg,var(--brand-glow),var(--brand-2));box-shadow:0 0 18px rgba(51,217,106,.55)}
  .hero-h{font-size:clamp(34px,3.4vw,54px);color:#fff;letter-spacing:-.015em;margin:22px 0 16px;max-width:14ch}
  .hero-h em{font-style:italic;color:var(--brand-glow)}
  .hero-p{font-size:18px;line-height:1.55;color:#c3ccc4;max-width:40ch;margin:0}
  .props{display:flex;flex-direction:column;gap:14px;margin-top:34px}
  .prop{display:flex;align-items:center;gap:13px;font-size:15.5px;color:#e9efe9;font-weight:500}
  .prop .pc{width:31px;height:31px;border-radius:9px;background:rgba(37,182,87,.14);border:1px solid rgba(51,217,106,.25);display:flex;align-items:center;justify-content:center}
  .trust{display:flex;align-items:center;gap:10px;font-size:13.5px;color:#aeb9af}
  .stars{color:#ffcf4d;letter-spacing:2px;font-size:14px}

  .pane-login{display:flex;align-items:center;justify-content:center;padding:40px 28px;background:var(--bg)}
  .login-card{width:100%;max-width:392px}
  .login-card .eyebrow{color:var(--brand-ink);font-weight:700;font-size:12.5px;letter-spacing:.14em;text-transform:uppercase;margin-bottom:10px}
  .login-card h2{font-size:30px;margin-bottom:8px}
  .login-card .lead{color:var(--muted);font-size:15px;margin:0 0 26px}
  .field{margin-bottom:16px}
  .field label{display:block;font-size:13px;font-weight:600;color:var(--ink);margin-bottom:7px}
  .field input{width:100%;padding:14px 15px;border-radius:12px;border:1.5px solid var(--line);
    background:#fff;color:var(--ink);font-size:15.5px;transition:border-color .15s, box-shadow .15s}
  .field input::placeholder{color:#aab2ab}
  .field input:focus{outline:none;border-color:var(--brand);box-shadow:0 0 0 4px rgba(37,182,87,.14)}
  .btn-primary{width:100%;margin-top:8px;padding:15px;border:0;border-radius:12px;cursor:pointer;
    background:linear-gradient(180deg,#2bc763,#189a45);color:#06210f;font-size:15.5px;font-weight:700;
    box-shadow:0 8px 22px rgba(24,154,69,.30);transition:transform .06s, box-shadow .15s, opacity .15s}
  .btn-primary:hover{box-shadow:0 12px 28px rgba(24,154,69,.42)}
  .btn-primary:active{transform:translateY(1px)}
  .btn-primary:disabled{opacity:.6;cursor:default;box-shadow:none}
  .msg{min-height:20px;margin-top:14px;font-size:14px}
  .msg.err{color:var(--err);font-weight:500}
  .helper{margin-top:22px;font-size:13px;color:var(--muted);text-align:center}
  .mini-brand{display:none}

  /* ---------- APP shell ---------- */
  .topbar{position:sticky;top:0;z-index:20;background:linear-gradient(180deg,#101210,#0b0c0b);
    border-bottom:1px solid #1c1e1c;display:flex;align-items:center;justify-content:space-between;padding:14px 30px;
    box-shadow:0 10px 30px -18px rgba(0,0,0,.7)}
  .topbar .who{display:flex;align-items:center;gap:16px;font-size:14px;color:#9aa39b}
  .topbar .who b{color:#fff;font-weight:600}
  .btn-ghost{background:rgba(255,255,255,.04);border:1px solid #2b2e2b;color:#d4dad4;border-radius:10px;
    padding:9px 15px;font-size:13.5px;font-weight:600;cursor:pointer;transition:border-color .15s,color .15s,background .15s}
  .btn-ghost:hover{border-color:var(--brand);color:var(--brand-glow);background:rgba(37,182,87,.08)}
  .container{max-width:1160px;margin:0 auto;padding:42px 30px 84px}

  .welcome{display:flex;flex-wrap:wrap;gap:18px;align-items:flex-end;justify-content:space-between;margin-bottom:36px}
  .welcome h1{font-size:clamp(29px,3.2vw,42px);letter-spacing:-.018em}
  .welcome .wsub{color:var(--muted);font-size:15px;margin-top:8px;max-width:52ch}
  .btn-book{display:inline-flex;align-items:center;gap:9px;text-decoration:none;
    background:linear-gradient(180deg,#2bc763,#189a45);color:#06210f;font-weight:700;font-size:14.5px;
    padding:13px 20px;border-radius:12px;box-shadow:0 10px 24px -8px rgba(24,154,69,.5);white-space:nowrap;transition:transform .1s,box-shadow .18s}
  .btn-book:hover{transform:translateY(-1px);box-shadow:0 14px 30px -8px rgba(24,154,69,.6)}

  .section-h{display:flex;align-items:center;gap:13px;margin:38px 0 18px}
  .section-h h3{font-size:14px;font-weight:700;letter-spacing:.12em;text-transform:uppercase;color:var(--muted);font-family:Inter,sans-serif}
  .section-h .bar{width:5px;height:20px;border-radius:3px;background:linear-gradient(180deg,var(--brand-glow),var(--brand-2))}
  .section-h .tag{font-size:12.5px;font-weight:600;color:var(--muted);margin-left:auto;background:#fff;border:1px solid var(--line);padding:5px 12px;border-radius:999px}

  .cards{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(288px,100%),1fr));gap:18px}
  .pcard{border:1px solid var(--line);border-radius:var(--r);background:#fff;overflow:hidden;cursor:pointer;
    box-shadow:var(--shadow-sm);transition:transform .12s, box-shadow .18s, border-color .18s;display:flex;flex-direction:column}
  .pcard:hover{transform:translateY(-3px);box-shadow:var(--shadow);border-color:#d7ddd7}
  .pcard .band{height:104px;position:relative;color:#fff;
    background:radial-gradient(320px 200px at 88% -40%, rgba(37,182,87,.40),transparent 60%),linear-gradient(150deg,#16181600,#0a0b0a),var(--black)}
  .pcard .band .pin{position:absolute;left:16px;top:14px;width:34px;height:34px;border-radius:10px;
    background:rgba(37,182,87,.16);border:1px solid rgba(51,217,106,.28);display:flex;align-items:center;justify-content:center}
  .pcard .band .st{position:absolute;right:14px;top:16px;font-size:10.5px;font-weight:700;letter-spacing:.08em;
    text-transform:uppercase;padding:5px 10px;border-radius:999px;background:rgba(255,255,255,.12);color:#d9ffe6}
  .pcard .pb{padding:15px 17px 17px;display:flex;flex-direction:column;gap:6px;flex:1}
  .pcard .addr{font-size:16px;font-weight:700;color:var(--ink);line-height:1.25}
  .pcard .loc{font-size:13.5px;color:var(--muted)}
  .pcard .specs{margin-top:6px;font-size:13px;color:var(--body);display:flex;gap:12px;flex-wrap:wrap}
  .pcard .view{margin-top:auto;padding-top:12px;color:var(--brand-ink);font-weight:700;font-size:13.5px;display:flex;align-items:center;gap:6px}
  .pcard .pid{margin-top:10px;padding-top:9px;border-top:1px solid var(--line);font-size:11px;color:var(--muted);letter-spacing:.02em;font-variant-numeric:tabular-nums}
  .pcard .band.hasimg{background-size:cover;background-position:center;background-repeat:no-repeat}
  .pcard .band.hasimg::after{content:"";position:absolute;inset:0;background:linear-gradient(180deg,rgba(0,0,0,.04),rgba(0,0,0,.42))}
  .pcard .band .pin,.pcard .band .st{z-index:2}
  .pcard .band .st.sleep{background:rgba(255,255,255,.14);color:#ffe6a8}
  .pcard .band .st.pend{background:rgba(255,255,255,.10);color:#d3dbd6}
  .pcard .view.muted{color:var(--muted)}
  .pcard.asleep{cursor:default}
  .pcard.asleep .band{background:radial-gradient(320px 200px at 88% -40%,rgba(120,120,120,.30),transparent 60%),linear-gradient(150deg,#161816,#0a0b0a),var(--black);filter:grayscale(.25)}
  .pcard .zzz{position:absolute;left:16px;bottom:13px;z-index:2;font-size:12px;font-weight:700;letter-spacing:.03em;color:#e9eef0;display:flex;align-items:center;gap:6px;opacity:.9}
  .wakebtn{margin-top:auto;display:inline-flex;align-items:center;justify-content:center;gap:8px;width:100%;
    padding:11px 14px;border:0;border-radius:12px;cursor:pointer;font:inherit;font-size:14px;font-weight:700;
    color:#04170c;background:linear-gradient(180deg,var(--brand-2),var(--brand));box-shadow:0 6px 16px rgba(32,157,80,.28);transition:filter .15s,transform .1s}
  .wakebtn:hover{filter:brightness(1.06)} .wakebtn:active{transform:translateY(1px)}
  .wakebtn:disabled{opacity:.6;cursor:default;box-shadow:none}
  .wakehint{margin-top:8px;font-size:12.5px;color:var(--muted)}
  .wakemsg{margin-top:10px;font-size:13px;color:#c0392b;line-height:1.45}
  .sleep-panel{max-width:520px;margin:10px auto;text-align:center;border:1px solid var(--line);border-radius:var(--r);
    background:var(--soft);padding:38px 26px}
  .sleep-panel .sp-moon{width:60px;height:60px;margin:0 auto 14px;border-radius:16px;display:flex;align-items:center;justify-content:center;
    background:radial-gradient(120px 90px at 50% 0%,rgba(37,182,87,.16),transparent),var(--black)}
  .sleep-panel h3{font-size:20px;margin-bottom:8px;color:var(--ink)}
  .sleep-panel p{font-size:14px;color:var(--body);line-height:1.55;margin:0 auto 20px;max-width:400px}
  .sleep-panel .wakebtn{width:auto;padding:12px 22px;margin:0 auto}
  .sleeping-sec{margin-top:30px}
  .sleeping-toggle{width:100%;display:flex;align-items:center;justify-content:space-between;gap:12px;
    padding:14px 18px;border:1px solid var(--line);border-radius:var(--r);background:var(--soft);cursor:pointer;
    font:inherit;font-size:14px;font-weight:700;color:var(--ink);transition:border-color .15s}
  .sleeping-toggle:hover{border-color:#d7ddd7}
  .sleeping-toggle > span:first-child{display:inline-flex;align-items:center;gap:9px}
  .sleeping-toggle b{color:var(--muted);font-weight:600;margin-left:2px}
  .sleeping-toggle .chev{transition:transform .18s;color:var(--muted);font-size:12px}
  .sleeping-sec.open .sleeping-toggle .chev{transform:rotate(180deg)}
  .sleeping-cards{margin-top:16px}
  .wake-banner{display:flex;align-items:center;gap:16px;justify-content:space-between;flex-wrap:wrap;
    border:1px solid var(--line);border-radius:var(--r);background:linear-gradient(180deg,#fffaf0,#fff);padding:16px 20px;margin-bottom:22px}
  .wake-banner .wb-txt{display:flex;flex-direction:column;gap:3px;min-width:220px;flex:1}
  .wake-banner .wb-txt b{font-size:14.5px;color:var(--ink)}
  .wake-banner .wb-txt span{font-size:13px;color:var(--body);line-height:1.45}
  .wake-banner .wakebtn{width:auto;padding:11px 18px;flex:none}
  .mcard .tour.sleeping{background:radial-gradient(220px 130px at 50% -10%,rgba(255,217,138,.18),transparent),var(--black);color:#ffe6a8}
  .mcard .tour.sleeping .zzz{font-family:Fraunces,Georgia,serif;font-weight:700;font-size:30px;line-height:1;color:#ffe6a8}
  .mcard .tour.sleeping .zzz sup{font-size:20px} .mcard .tour.sleeping .zzz sub{font-size:14px}
  .mcard .tour.sleeping .ts{margin-top:8px;font-size:12px;letter-spacing:.14em;text-transform:uppercase;opacity:.85}
  .mcard.is-asleep{opacity:.96}
  .mzz{font-size:12.5px;font-weight:700;color:#a9791c}
  .ph-toolbar{display:flex;flex-wrap:wrap;align-items:center;gap:14px;margin:0 0 16px;padding:12px 15px;border:1px solid var(--line);border-radius:12px;background:var(--soft)}
  .ph-size{display:flex;align-items:center;gap:12px;font-size:13px;font-weight:700;color:var(--body)}
  @media (max-width:760px){
    /* Single option: no pill, no radio, just the fact. */
    .ph-size .ph-size-l{font-size:12px;letter-spacing:0;text-transform:none;
      font-weight:650;color:var(--body)}
  }
  .ph-size label{display:inline-flex;align-items:center;gap:5px;font-weight:500;cursor:pointer}
  .ph-size .hint{color:var(--muted);font-size:11.5px}
  .ph-btns{display:flex;flex-wrap:wrap;gap:8px;margin-left:auto}
  .btn-mini{padding:9px 14px;border:1px solid var(--line);border-radius:10px;background:#fff;cursor:pointer;
            font:inherit;font-size:12.5px;font-weight:700;line-height:1.2;color:var(--ink)}
  .btn-mini:hover:not(:disabled){border-color:var(--brand)}
  .btn-mini:disabled{opacity:.5;cursor:default}
  .ph-btns .btn-primary{width:auto;margin-top:0;padding:9px 14px;border-radius:10px;font-size:12.5px;font-weight:700;line-height:1.2}
  .ph-btns .btn-ghost{padding:8px 12px;font-size:12.5px}
  .ph-status{flex-basis:100%;font-size:12.5px;color:var(--muted)}
  .ph-status.ok{color:var(--brand-ink);font-weight:600} .ph-status.err{color:#c0392b}
  .mcard.photo{position:relative}
  .mcard.photo .ph-pick{position:absolute;top:8px;left:8px;z-index:3;background:rgba(255,255,255,.92);border-radius:6px;padding:3px 4px 1px;box-shadow:0 1px 3px rgba(0,0,0,.22)}
  .mcard.photo .ph-pick input{width:16px;height:16px;cursor:pointer;margin:0}
  .ph-name{display:flex;gap:6px;align-items:center;margin-bottom:9px}
  .ph-name .nm-in{flex:1;min-width:0;padding:6px 8px;border:1px solid var(--line);border-radius:7px;font:inherit;font-size:12.5px;color:var(--ink)}
  .ph-name .nm-in:focus{outline:none;border-color:var(--brand)}
  .ph-name .nm-save{flex:none;width:28px;height:28px;border:1px solid var(--line);border-radius:7px;background:#fff;cursor:pointer;color:var(--brand-ink);font-weight:700;line-height:1}
  .ph-name .nm-save:hover{border-color:var(--brand)}
  button.btn-dl{border:0;cursor:pointer;font:inherit}
  .mcard.photo .ph-star{position:absolute;top:8px;right:8px;z-index:3;width:30px;height:30px;border:0;border-radius:8px;
    background:rgba(0,0,0,.42);color:rgba(255,255,255,.85);font-size:17px;line-height:1;cursor:pointer;
    display:flex;align-items:center;justify-content:center;transition:transform .1s,background .15s,color .15s}
  .mcard.photo .ph-star:hover{background:rgba(0,0,0,.62);transform:scale(1.08)}
  .mcard.photo .ph-star.on{background:rgba(0,0,0,.5);color:#ffcf3f;text-shadow:0 0 8px rgba(255,207,63,.6)}
  .mcard.photo .ph-star:disabled{opacity:.6;cursor:default}
  .grid.links{grid-template-columns:repeat(auto-fill,minmax(min(250px,100%),1fr))}
  .mcard.link{flex-direction:row;align-items:center;gap:14px;padding:14px 16px}
  .mcard.link .lk-ic{flex:none;width:46px;height:46px;border-radius:12px;display:flex;align-items:center;justify-content:center;
    background:radial-gradient(80px 60px at 50% 0%,rgba(37,182,87,.18),transparent),var(--black)}
  .mcard.link .lk-b{min-width:0;flex:1;display:flex;flex-direction:column;gap:3px}
  .mcard.link .lk-kind{font-size:11px;font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:var(--muted)}
  .mcard.link .mname{font-weight:600;color:var(--ink);line-height:1.3}
  .mcard.link{align-items:flex-start;padding:16px}
  .mcard.link:hover{border-color:#cfe6d6}
  .mcard.link .lk-host{font-size:12px;color:var(--muted);margin-top:2px;word-break:break-all}
  .mcard.link .lk-acts{display:flex;gap:8px;margin-top:11px;flex-wrap:wrap}
  .lk-btn{padding:7px 12px;border-radius:9px;border:1px solid transparent;cursor:pointer;font:inherit;
          font-size:12px;font-weight:700;line-height:1.4;white-space:nowrap;
          background:linear-gradient(180deg,#2bc763,#189a45);color:#06210f}
  .lk-btn:hover{filter:brightness(1.05)}
  .lk-btn.ghost{background:#fff;border-color:var(--line);color:var(--ink)}
  .lk-btn.ghost:hover{border-color:var(--brand);color:var(--brand-ink)}
  #lbf{position:fixed;inset:0;background:rgba(4,6,5,.86);z-index:80;display:none;align-items:center;justify-content:center;padding:24px}
  #lbf.on{display:flex}
  #lbf .lbf-box{width:min(1040px,96vw);height:min(640px,86vh);background:#000;border-radius:14px;overflow:hidden;display:flex;flex-direction:column;box-shadow:0 30px 80px rgba(0,0,0,.6)}
  #lbf .lbf-bar{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:11px 16px;background:#111;color:#fff}
  #lbf .lbf-bar span{font-size:14px;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  #lbf .lbf-bar button{background:transparent;border:0;color:#fff;font-size:18px;cursor:pointer;line-height:1;padding:4px 8px}
  #lbf iframe{flex:1;width:100%;border:0;background:#000}
  .sd-panel{margin-bottom:26px;border:1px solid var(--line);border-radius:var(--r);background:#fff;overflow:hidden}
  .sd-toggle{width:100%;display:flex;align-items:center;justify-content:space-between;gap:12px;padding:15px 18px;
    background:var(--soft);border:0;cursor:pointer;font:inherit;font-size:14.5px;font-weight:700;color:var(--ink)}
  .sd-toggle .chev{transition:transform .18s;color:var(--muted);font-size:12px}
  .sd-panel.open .sd-toggle .chev{transform:rotate(180deg)}
  .sd-body{padding:20px 18px 18px}
  .sd-group{margin-bottom:20px}
  .sd-gh{font-size:11.5px;font-weight:700;letter-spacing:.12em;text-transform:uppercase;color:var(--muted);margin:0 0 12px;padding-bottom:8px;border-bottom:1px solid var(--line)}
  .sd-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(190px,100%),1fr));gap:14px}
  .sd-f{display:flex;flex-direction:column;gap:6px}
  /* A boxed group for fields that only make sense together — the banner and its
     expiry are one decision, not two unrelated inputs sitting beside the MLS. */
  .sd-group.boxed{border:1px solid var(--line);border-radius:12px;padding:16px 16px 6px;background:var(--soft)}
  .sd-group.boxed .sd-gh{border-bottom:none;padding-bottom:0;margin-bottom:6px;color:var(--ink)}
  .sd-gnote{font-size:12px;line-height:1.55;color:var(--body);margin:0 0 14px;max-width:60ch}
  .sd-group.locked{opacity:.65}
  .sd-group.locked input,.sd-group.locked select{background:var(--hair);cursor:not-allowed}
  .sd-lock{display:inline-flex;align-items:center;gap:6px;font-size:11.5px;font-weight:650;color:var(--muted);
           background:var(--bg);border:1px solid var(--line);border-radius:999px;padding:4px 11px;margin-bottom:12px}
  /* The explanation sits at full opacity even though the fields behind it are
     dimmed — the reason must stay readable, or a greyed-out control just reads
     as broken. */
  .sd-locked-box{opacity:1;background:var(--bg);border:1px solid var(--line);border-radius:10px;
                 padding:13px 15px;margin-bottom:14px}
  .sd-locked-t{font-size:12.5px;font-weight:700;color:var(--ink)}
  .sd-locked-b{margin:5px 0 0;font-size:12px;line-height:1.55;color:var(--body);max-width:58ch}
  .sd-locked-a{display:flex;flex-wrap:wrap;align-items:center;gap:10px;margin-top:11px}
  .sd-kit-buy{flex:none;cursor:pointer;font-size:11.5px;font-weight:700;letter-spacing:.02em;
              color:var(--brand-ink);background:rgba(37,182,87,.10);border:1px solid rgba(51,217,106,.42);
              border-radius:8px;padding:7px 13px;transition:background .15s}
  .sd-kit-buy:hover{background:rgba(37,182,87,.17)}
  .sd-kit-buy:disabled{opacity:.55;cursor:default}
  .sd-kit-note{font-size:11px;color:var(--muted);line-height:1.45}
  .sd-genrow{display:flex;flex-wrap:wrap;align-items:center;gap:11px;margin:0 0 14px}
  .sd-gen-btn{flex:none;cursor:pointer;font-size:11.5px;font-weight:700;color:#fff;
              background:linear-gradient(180deg,var(--brand),var(--brand-2));border:0;border-radius:9px;
              padding:9px 15px;transition:filter .15s}
  .sd-gen-btn:hover{filter:brightness(1.06)}
  .sd-gen-btn:disabled{opacity:.55;cursor:default}
  .sd-gen-note{font-size:11.5px;color:var(--muted);line-height:1.45}
  .sd-f.wide{grid-column:1/-1}
  .sd-f > span{font-size:12.5px;font-weight:600;color:var(--body)}
  .sd-f input,.sd-f select,.sd-f textarea{width:100%;padding:10px 12px;border:1px solid var(--line);border-radius:10px;
    font:inherit;font-size:14px;color:var(--ink);background:#fff;box-sizing:border-box}
  .sd-f textarea{resize:vertical;min-height:92px}
  .sd-f input:focus,.sd-f select:focus,.sd-f textarea:focus{outline:none;border-color:var(--brand);box-shadow:0 0 0 3px rgba(37,182,87,.12)}
  .sd-in{position:relative;display:flex;align-items:center}
  .sd-in.has-pre > span{position:absolute;left:12px;color:var(--muted);font-size:14px}
  .sd-in.has-pre input{padding-left:23px}
  .sd-actions{display:flex;align-items:center;gap:12px;margin-top:4px;flex-wrap:wrap}
  .sd-actions .btn-primary{width:auto;padding:11px 20px}
  .sd-msg{font-size:13px;color:var(--muted)}
  .sd-msg.ok{color:var(--brand-ink);font-weight:700}
  .sd-msg.err{color:#c0392b}
  .kit-card{display:flex;align-items:center;gap:16px;flex-wrap:wrap;margin-bottom:26px;padding:18px 20px;border-radius:var(--r);
    border:1px solid var(--line);background:linear-gradient(135deg,#0c0d0c,#141613);color:#fff;position:relative;overflow:hidden}
  .kit-card.has{background:linear-gradient(135deg,#0a1f12,#0c0d0c)}
  .kit-card::after{content:"";position:absolute;right:-40px;top:-60px;width:220px;height:220px;border-radius:50%;
    background:radial-gradient(circle,rgba(37,182,87,.28),transparent 65%);pointer-events:none}
  .kit-card .kit-ic{flex:none;width:48px;height:48px;border-radius:14px;display:flex;align-items:center;justify-content:center;
    font-size:22px;color:#3ee06f;background:rgba(37,182,87,.14);border:1px solid rgba(51,217,106,.3)}
  .kit-card .kit-b{flex:1;min-width:200px;z-index:1}
  .kit-card .kit-h{font-family:Fraunces,Georgia,serif;font-size:18px;font-weight:700}
  .kit-card .kit-s{font-size:13.5px;color:#b9c3bd;margin-top:3px;line-height:1.45}
  .kit-card .kit-open{width:auto;padding:11px 18px;flex:none;z-index:1}
  /* Viewing-as marker, in the topbar beside the logo. It used to be a
     full-width sticky bar that pushed the hero down — so the one screen whose
     job is "see exactly what the client sees" was the one screen that did not
     match. Quiet, out of the layout, unmistakably present. */
  .viewas{display:flex;align-items:center;gap:9px;margin-left:14px;
    background:rgba(37,182,87,.13);border:1px solid rgba(51,217,106,.32);
    border-radius:999px;padding:4px 5px 4px 12px}
  .viewas .va-t{font-size:12px;color:#cfe9d8;white-space:nowrap}
  .viewas .va-t b{color:#fff;font-weight:700}
  .va-x{font:inherit;font-size:11px;font-weight:700;border:0;cursor:pointer;
    border-radius:999px;padding:4px 11px;background:rgba(255,255,255,.14);color:#eaf6ee}
  .va-x:hover{background:rgba(255,255,255,.26)}
  @media (max-width:700px){
    .viewas{margin-left:8px;padding-left:9px}
    .viewas .va-t{max-width:96px;overflow:hidden;text-overflow:ellipsis}
  }
  .msearch{display:flex;gap:10px;margin:6px 0 22px;max-width:640px}
  .msearch input{flex:1;min-width:0;padding:14px 16px;border:1px solid var(--line);border-radius:12px;font:inherit;font-size:15px;color:var(--ink);background:#fff}
  .msearch input:focus{outline:none;border-color:var(--brand);box-shadow:0 0 0 3px rgba(37,182,87,.12)}
  .msearch .btn-primary{width:auto;padding:0 22px}
  .mresults{display:flex;flex-direction:column;gap:10px;max-width:780px}
  .mrow{display:flex;align-items:center;gap:16px;justify-content:space-between;padding:14px 18px;border:1px solid var(--line);border-radius:14px;background:#fff;box-shadow:var(--shadow-sm)}
  .mrow:hover{border-color:#d7ddd7}
  .mrow .mrow-b{min-width:0;flex:1}
  .mrow .mrow-n{font-weight:700;color:var(--ink);font-size:15px}
  .mrow .mrow-e{font-size:13px;color:var(--muted);margin-top:2px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .mrow .mopen{width:auto;padding:9px 16px;flex:none;font-size:13.5px}
  .logo-img{height:30px;width:auto;display:block}
  .logo-chip{background:#fff;border-radius:11px;padding:7px 13px;display:inline-flex;align-items:center;box-shadow:0 3px 12px rgba(0,0,0,.22)}
  .topbar .logo-chip{padding:6px 11px}
  .topbar .logo-img{height:24px}
  .pane-brand .logo-chip{padding:9px 15px}
  .pane-brand .logo-img{height:36px}
  .mini-brand{display:flex;justify-content:center;margin-bottom:14px}
  .logo-lg{height:46px}
  .welcome-l{display:flex;align-items:center;gap:16px}
  .avatar{flex:none;width:56px;height:56px;border-radius:50%;display:flex;align-items:center;justify-content:center;
    font-family:Fraunces,Georgia,serif;font-weight:700;font-size:21px;color:#04170c;letter-spacing:.02em;
    background:linear-gradient(150deg,var(--brand-2),var(--brand));box-shadow:0 8px 22px rgba(32,157,80,.32)}
  .welcome-sub{font-size:13.5px;color:var(--muted);margin-top:3px}
  .avatar.has-photo{background-size:cover;background-position:center;color:transparent;box-shadow:0 8px 22px rgba(0,0,0,.18)}
  .cards{grid-template-columns:repeat(auto-fill,minmax(min(390px,100%),1fr));gap:14px}
  .pcard.compact{flex-direction:row;align-items:stretch;padding:0;overflow:hidden;transition:box-shadow .16s,border-color .16s,transform .12s}
  .pcard.compact:hover{transform:none;box-shadow:var(--shadow);border-color:#d7ddd7}
  .pcard.compact .pc-thumb{flex:none;width:104px;cursor:pointer;display:flex;align-items:center;justify-content:center;
    background:radial-gradient(120px 90px at 50% 0%,rgba(37,182,87,.16),transparent),var(--black)}
  .pcard.compact .pc-thumb.hasimg{background-size:cover;background-position:center}
  .pcard.compact .pc-body{flex:1;min-width:0;padding:13px 15px 12px;display:flex;flex-direction:column;gap:4px}
  .pc-top{display:flex;align-items:flex-start;justify-content:space-between;gap:10px}
  .pc-addr{font-size:15px;font-weight:700;color:var(--ink);line-height:1.25;min-width:0}
  .pc-meta{font-size:12.5px;color:var(--muted)}
  .pc-sub{font-size:11px;color:var(--muted);font-variant-numeric:tabular-nums;letter-spacing:.02em}
  /* What's in this listing: icon+count facts, kit state, and the Site ID, all on one row. */
  .pc-facts{display:flex;align-items:center;flex-wrap:wrap;gap:5px 12px;margin-top:3px}
  .pc-f{display:inline-flex;align-items:center;gap:5px;font-size:12px;font-weight:700;color:var(--body);font-variant-numeric:tabular-nums;white-space:nowrap}
  .pc-f svg{width:14px;height:14px;flex:none;color:var(--muted)}
  .pc-kit{display:inline-flex;align-items:center;gap:4px;font-size:10.5px;font-weight:800;letter-spacing:.02em;
          padding:3px 8px;border-radius:999px;background:rgba(37,182,87,.13);color:var(--brand-ink);white-space:nowrap}
  .pc-kit svg{width:12px;height:12px;flex:none}
  .pc-kit.off{background:var(--soft);color:var(--muted)}
  .pc-exp{display:inline-flex;align-items:center;gap:4px;font-size:10.5px;font-weight:800;letter-spacing:.02em;
          padding:3px 8px;border-radius:999px;background:var(--soft);color:var(--muted);white-space:nowrap}
  .pc-exp svg{width:12px;height:12px;flex:none}
  .pc-exp.soon{background:#fff3d6;color:#a9791c}
  .pc-exp.gone{background:#fdeaea;color:var(--err)}
  .ph-terms{display:flex;flex-wrap:wrap;gap:8px 16px;margin-top:10px}
  .ph-term{display:inline-flex;align-items:center;gap:6px;font-size:12.5px;color:var(--muted)}
  .ph-term b{color:var(--body);font-weight:700}
  .ph-term svg{width:14px;height:14px;flex:none}
  .ph-term.soon{color:#a9791c} .ph-term.soon b{color:#a9791c}
  .ph-term.gone{color:var(--err)} .ph-term.gone b{color:var(--err)}
  .fb-row{padding:14px 0;border-bottom:1px solid var(--hair)}
  .fb-row:last-child{border-bottom:0}
  .fb-meta{display:flex;align-items:baseline;gap:10px;margin-bottom:5px}
  .fb-meta b{font-size:13.5px;color:var(--ink)}
  .fb-when{font-size:11.5px;color:var(--muted)}
  .fb-text{font-size:14px;color:var(--body);line-height:1.55;white-space:pre-wrap}
  .fb-text.muted{color:var(--muted);font-style:italic}
  button.pc-kit{border:0;font-family:inherit;cursor:pointer;transition:background .14s,box-shadow .14s}
  button.pc-kit.on:hover{background:rgba(37,182,87,.24);box-shadow:0 0 0 1px rgba(37,182,87,.35) inset}
  /* The "No MKT Kit" chip is clickable too — same link, HDPhotoHub decides
     whether to open the kit or offer it. Hover stays neutral: this is an
     invitation to look, not a state to celebrate. */
  button.pc-kit.off:hover{background:var(--line);color:var(--ink)}
  button.pc-kit:active{transform:translateY(1px)}
  .pc-id{margin-left:auto;font-size:11px;color:var(--muted);font-variant-numeric:tabular-nums;letter-spacing:.02em;white-space:nowrap}
  .tok.paid .tok-amt{opacity:.72;font-weight:700;margin-left:3px}
  @media (max-width:560px){ .pc-facts{gap:4px 10px} .pc-id{margin-left:0} }
  .pc-actions{display:flex;flex-wrap:wrap;gap:7px;margin-top:auto;padding-top:9px}
  .pc-btn{padding:7px 12px;border:1px solid var(--line);border-radius:9px;background:#fff;cursor:pointer;font:inherit;font-size:12.5px;font-weight:700;color:var(--ink);display:inline-flex;align-items:center;gap:5px}
  .pc-btn:hover{border-color:var(--brand)}
  .pc-btn.view{color:var(--brand-ink)}
  /* AMBER, not brand green. A green "Pay $269" reads as a settled, healthy
     state — the client sees the colour of "done" on the one control that means
     money is still owed. This matches .ph-btn.primary.owing inside the listing,
     which was already correct; the card was the odd one out. */
  .pc-btn.pay{background:linear-gradient(180deg,#f2b53c,#d99213);border:0;color:#3a2600;
    box-shadow:0 8px 20px -10px rgba(217,146,19,.6)}
  .pc-btn:disabled{opacity:.45;cursor:default;filter:saturate(.4)}
  .pc-btn:disabled:hover{border-color:var(--line)}
  .tok{flex:none;font-size:11px;font-weight:800;letter-spacing:.02em;padding:4px 9px;border-radius:999px;white-space:nowrap}
  .tok.paid{background:rgba(37,182,87,.15);color:var(--brand-ink)}
  .tok.due,.tok.sleep{background:#fff3d6;color:#a9791c}
  /* The amount owed IS the pay control. Amber, solid, with "Pay now" sitting
     under the figure so one object says both what is owed and what to do about
     it — rather than a status chip in one corner and a button repeating the
     same number in another. Once paid it reverts to the plain green statement,
     because there is nothing left to act on. */
  button.tok.due.act{border:0;font-family:inherit;cursor:pointer;display:inline-flex;
    flex-direction:column;align-items:center;gap:1px;line-height:1.15;
    padding:5px 12px;border-radius:12px;
    background:linear-gradient(180deg,#f2b53c,#d99213);color:#3a2600;
    box-shadow:0 8px 20px -10px rgba(217,146,19,.6);
    transition:filter .14s,transform .08s}
  button.tok.due.act .tok-act{font-size:9.5px;font-weight:800;letter-spacing:.09em;
    text-transform:uppercase;opacity:.78}
  button.tok.due.act:hover{filter:brightness(1.05)}
  button.tok.due.act:active{transform:translateY(1px)}
  button.tok.due.act:focus-visible{outline:2px solid #8c6413;outline-offset:2px}
  .tok.pend{background:var(--soft);color:var(--muted)}
  .lbf-actions{display:flex;align-items:center;gap:14px}
  /* Phone: the invoice viewer goes FULL SCREEN.
     At 96vw inside 24px of padding the box was ~340px wide while the invoice
     inside declares width=device-width (390px) — so it laid out wider than its
     container and the right-hand side, where the totals are, was simply cut
     off. Matching the frame to the device width removes the mismatch. The
     toolbar also could not fit Print, Email, Open and Close on one line.

     Safe to do here even though the same trick was reverted for page-level
     wobble: this box is position:fixed, so it never contributes to the
     document width and cannot make the page pan. */
  @media (max-width:760px){
    #lbf{padding:0}
    #lbf .lbf-box{width:100vw;max-width:100vw;height:100vh;height:100dvh;border-radius:0}
    #lbf .lbf-bar{flex-wrap:wrap;gap:6px;padding:9px 12px}
    #lbf .lbf-bar span{flex:1 0 100%;font-size:13px}
    #lbf .lbf-bar button,#lbf .lbf-bar a{font-size:12.5px;padding:5px 9px}
  }

  #lbf .lbf-bar a#lbfOpen{color:#fff;font-size:13px;text-decoration:none;opacity:.85;white-space:nowrap}
  #lbf .lbf-bar a#lbfOpen:hover{opacity:1;text-decoration:underline}
  @media (max-width:560px){ .cards{grid-template-columns:1fr} .pcard.compact .pc-thumb{width:84px} }
  .helper a{color:var(--brand-ink);font-weight:600;text-decoration:none;white-space:nowrap}
  .helper a:hover{text-decoration:underline}

  .empty{border:1px dashed var(--line);border-radius:var(--r);padding:46px 20px;text-align:center;color:var(--muted);background:var(--soft)}

  /* ---------- Gallery ---------- */
  .g-head{display:flex;align-items:flex-start;justify-content:space-between;gap:16px;margin-bottom:22px}
  .g-head h1{font-size:clamp(24px,3vw,34px)}
  .g-head .gloc{color:var(--muted);font-size:15px;margin-top:6px}
  .g-section{margin-top:26px}
  .g-section .gh{font-size:12.5px;font-weight:700;letter-spacing:.12em;text-transform:uppercase;color:var(--ink);margin:0 0 13px;display:flex;align-items:center;gap:10px}
  .g-section .gh .n{background:var(--soft);border:1px solid var(--line);color:var(--body);border-radius:999px;padding:2px 9px;font-size:11px;letter-spacing:.04em}
  .grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(250px,100%),1fr));gap:16px}
  .mcard{border:1px solid var(--line);border-radius:14px;overflow:hidden;background:#fff;display:flex;flex-direction:column;box-shadow:var(--shadow-sm)}
  .thumb{width:100%;aspect-ratio:4/3;object-fit:cover;background:#eef1ee;display:block;border:0;cursor:zoom-in}
  .frame{width:100%;aspect-ratio:16/9;border:0;background:#0b0d0b;display:block}
  .tour{width:100%;aspect-ratio:4/3;display:flex;flex-direction:column;gap:6px;align-items:center;justify-content:center;text-align:center;padding:14px;
    background:radial-gradient(200px 150px at 78% 0,rgba(37,182,87,.30),transparent 60%),var(--black);color:#eafff0}
  .tour .tt{font-weight:700;font-size:14px} .tour .ts{font-size:12px;color:#9df5c1}
  .mbody{padding:11px 13px;display:flex;flex-direction:column;gap:9px;flex:1}
  .mname{font-size:13px;font-weight:600;color:var(--ink);word-break:break-word;line-height:1.3}
  .mact{margin-top:auto;display:flex;gap:8px}
  .btn-dl,.btn-open{flex:1;text-align:center;text-decoration:none;padding:5px 9px;border-radius:7px;font-size:11px;font-weight:700;line-height:1.5}
  .btn-dl{background:#fff;border:1px solid var(--line);color:var(--brand-ink);cursor:pointer}
  .btn-dl:hover{border-color:var(--brand);background:rgba(37,182,87,.07)}
  .btn-open{border:1.5px solid var(--line);color:var(--ink)}
  .btn-open:hover{border-color:var(--brand);color:var(--brand-ink)}
  .loading{color:var(--muted);font-size:14.5px;padding:18px 2px;display:flex;align-items:center;gap:10px}
  .spinner{width:16px;height:16px;border:2.5px solid var(--line);border-top-color:var(--brand);border-radius:50%;animation:spin .7s linear infinite}
  @keyframes spin{to{transform:rotate(360deg)}}

  #lb{position:fixed;inset:0;z-index:80;background:rgba(6,10,7,.94);display:none;align-items:center;justify-content:center;padding:26px;cursor:zoom-out}
  #lb.on{display:flex}
  #lbClose{position:fixed;top:14px;right:14px;width:44px;height:44px;border-radius:50%;
    border:1px solid rgba(255,255,255,.28);background:rgba(6,10,7,.72);color:#fff;
    font-size:17px;line-height:1;cursor:pointer;display:flex;align-items:center;
    justify-content:center;padding:0}
  #lbClose:hover{background:rgba(6,10,7,.94)}
  /* The floating property bar must never hover over a photo. It is a control
     for the page underneath, and tapping it there left the overlay stranded. */
  body.lb-open .pbar{display:none} #lb img{max-width:100%;max-height:100%;border-radius:10px;box-shadow:0 20px 60px rgba(0,0,0,.6)}

  @media (max-width:900px){
    #auth{grid-template-columns:1fr}
    .pane-brand{display:none}
    .pane-login{min-height:100vh;padding:30px 22px}
    .mini-brand{display:flex;justify-content:center;margin-bottom:26px}
    .login-card h2{font-size:26px}
  }
  /* ---------- Home hub ---------- */
  .home-hero{display:flex;flex-wrap:wrap;gap:20px;align-items:center;justify-content:space-between;margin-bottom:32px}
  .home-hero .hh-l{display:flex;align-items:center;gap:18px}
  .avatar.big{width:64px;height:64px;font-size:23px}
  .eyebrow.glow{color:var(--brand-ink);font-weight:700;font-size:11.5px;letter-spacing:.16em;text-transform:uppercase;margin-bottom:8px;display:inline-flex;align-items:center;gap:8px}
  .eyebrow.glow::before{content:"";width:6px;height:6px;border-radius:50%;background:var(--brand-glow);box-shadow:0 0 10px var(--brand-glow)}
  .home-hero h1{font-size:clamp(28px,3.2vw,40px);letter-spacing:-.018em}
  .hh-sub{color:var(--muted);font-size:15px;margin-top:6px;max-width:48ch}
  .home-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(278px,100%),1fr));gap:16px}
  .hmod{position:relative;text-align:left;border:1px solid var(--line);border-radius:18px;background:#fff;padding:22px 20px 20px;cursor:pointer;font:inherit;
    display:flex;flex-direction:column;gap:7px;overflow:hidden;transition:transform .14s,box-shadow .2s,border-color .2s;box-shadow:var(--shadow-sm)}
  .hmod::before{content:"";position:absolute;inset:0;background:radial-gradient(340px 170px at 100% 0%,rgba(37,182,87,.09),transparent 70%);opacity:0;transition:opacity .22s;pointer-events:none}
  .hmod:hover{transform:translateY(-3px);box-shadow:var(--shadow);border-color:#cfe6d6}
  .hmod:hover::before{opacity:1}
  .hmod-ic{width:50px;height:50px;border-radius:15px;display:flex;align-items:center;justify-content:center;color:var(--brand-glow);
    background:linear-gradient(150deg,#12241a,#0b0c0b);border:1px solid rgba(51,217,106,.24);
    box-shadow:inset 0 0 22px rgba(37,182,87,.16), 0 8px 18px -8px rgba(0,0,0,.4);margin-bottom:6px;position:relative}
  .hmod-ic::after{content:"";position:absolute;inset:0;border-radius:15px;background:radial-gradient(30px 20px at 30% 20%,rgba(255,255,255,.14),transparent 70%);pointer-events:none}
  .hmod-ic svg{width:24px;height:24px;position:relative;z-index:1}
  .hmod-t{font-family:Fraunces,Georgia,serif;font-size:19px;font-weight:700;color:var(--ink)}
  .hmod-d{font-size:13.5px;color:var(--muted);line-height:1.45}
  /* Counts and open balance, on the My Properties tile. Separated from the
     description by a hairline so the tile reads as label, then summary —
     not one long run of grey text. */
  .hmod-stats{display:none}
  .hmod-stats.has{display:flex;flex-direction:column;gap:5px;margin-top:12px;
    padding-top:11px;border-top:1px solid var(--line)}
  .hmod-counts{font-size:12.5px;color:var(--muted)}
  .hmod-counts b{color:var(--ink);font-weight:750}
  /* Amber, matching every other "money is owed" surface. Not a control: an
     agent cannot settle several listings at once, so the place to act is the
     listing itself. */
  .hmod-due{font-size:12.5px;font-weight:750;color:#a9791c}
  .hmod-due i{font-style:normal;font-weight:600;opacity:.85}
  .hmod-clear{font-size:12.5px;font-weight:700;color:var(--brand-ink)}
  .hmod-go{margin-top:5px;color:var(--brand-ink);opacity:0;transform:translateX(-4px);transition:opacity .2s,transform .2s}
  .hmod-go svg{width:18px;height:18px}
  .hmod:hover .hmod-go{opacity:1;transform:none}
  .hmod-tag{position:absolute;top:16px;right:16px;font-size:10px;font-weight:800;letter-spacing:.08em;text-transform:uppercase;color:var(--muted);background:var(--soft);border:1px solid var(--line);padding:3px 8px;border-radius:999px}
  .hmod.soon .hmod-ic{color:#8a958c;background:linear-gradient(150deg,#171917,#0e0f0e);border-color:#2b2e2b;box-shadow:none}
  .hmod.soon .hmod-ic::after{display:none}
  /* ---------- Property command center ---------- */
  .ph-eyebrow{color:var(--brand-ink);font-weight:700;font-size:11.5px;letter-spacing:.14em;text-transform:uppercase;margin-bottom:12px}
  .ph-addr{font-size:clamp(28px,3.4vw,44px);letter-spacing:-.02em;line-height:1.08}
  .ph-loc{color:var(--muted);font-size:15.5px;margin-top:9px}
  .ph-facts{display:flex;flex-wrap:wrap;align-items:center;gap:10px;margin-top:18px}
  .ph-facts>span{font-size:12.5px;font-weight:600;color:var(--body);background:#fff;border:1px solid var(--line);padding:7px 13px;border-radius:999px;box-shadow:var(--shadow-sm)}
  .ph-facts .ph-tok{background:none;border:0;padding:0;box-shadow:none}
  button.tok.pay-now{border:0;font-family:inherit;cursor:pointer;background:linear-gradient(180deg,#f2b53c,#d99213);
                     color:#3a2600;padding:8px 14px;font-size:12px;transition:filter .14s,transform .1s}
  button.tok.pay-now:hover{filter:brightness(1.06)}
  button.tok.pay-now:active{transform:translateY(1px)}
  button.tok.pay-now svg{width:13px;height:13px;vertical-align:-2px;stroke:#3a2600}
  #panel.wide .panel-box{width:min(720px,96vw)}
  /* overflow:hidden exists to clip the card's rounded corners on the dashboard.
     Inside the panel the card has no border or background, so the clip has
     nothing to do except shave the first glyph off a group heading that starts
     flush against the boundary — "Listing info" lost its L. */
  #panel .sd-panel{border:0;background:none;padding:0;overflow:visible}
  #panel .sd-panel .sd-body{padding:0}
  .op-lead{font-size:14px;color:var(--body);line-height:1.55;margin-bottom:16px}

  /* ---- Property fact sheet ------------------------------------------
     The agent's private research. Dark header to match the property hero,
     then quiet cards — this is a working document, read for numbers, so it
     stays legible over decorative. */
  .fs-hero{position:relative;overflow:hidden;border-radius:14px;padding:22px 24px;margin-bottom:20px;
           background:radial-gradient(620px 260px at 88% 6%, rgba(37,182,87,.26), transparent 60%),
                      linear-gradient(118deg,#0b0c0b 0%,#101a13 48%,#0b0c0b 100%)}
  .fs-hero::after{content:'';position:absolute;inset:0;opacity:.30;pointer-events:none;
     background-image:linear-gradient(rgba(255,255,255,.05) 1px,transparent 1px),
                      linear-gradient(90deg,rgba(255,255,255,.05) 1px,transparent 1px);
     background-size:46px 46px;mask-image:linear-gradient(115deg,transparent 45%,#000 100%)}
  .fs-eyebrow{position:relative;z-index:1;color:var(--brand-glow);font-weight:700;font-size:10.5px;
              letter-spacing:.16em;text-transform:uppercase}
  .fs-h{position:relative;z-index:1;margin-top:7px;font-family:Fraunces,Georgia,serif;color:#fff;
        font-size:clamp(20px,2.6vw,27px);line-height:1.12;letter-spacing:-.02em}
  .fs-sub{position:relative;z-index:1;margin-top:8px;color:rgba(232,237,233,.72);font-size:12.5px}

  .fs-sec{margin-top:26px}
  .fs-sec:first-of-type{margin-top:0}
  .fs-sh{display:flex;align-items:baseline;gap:10px;padding-bottom:9px;margin-bottom:14px;
         border-bottom:1px solid var(--line)}
  .fs-sh b{font-size:11.5px;font-weight:800;letter-spacing:.14em;text-transform:uppercase;color:var(--ink)}
  .fs-sh span{font-size:12px;color:var(--muted)}

  .fs-grid{display:grid;gap:12px;grid-template-columns:repeat(auto-fill,minmax(min(228px,100%),1fr))}
  .fs-card{border:1px solid var(--line);border-radius:12px;padding:13px 15px;background:var(--bg)}
  .fs-card-t{font-size:10.5px;font-weight:800;letter-spacing:.12em;text-transform:uppercase;color:var(--muted)}
  /* pre-line: sale history arrives as one event per line. Without it the whole
     history collapses onto a single unreadable run. */
  .fs-card-v{margin-top:5px;font-size:15px;font-weight:650;color:var(--ink);line-height:1.35;
    white-space:pre-line}
  .fs-card-d{margin-top:4px;font-size:12px;line-height:1.5;color:var(--body)}
  .fs-src{margin-top:7px;font-size:11px;color:var(--muted)}

  .fs-comp{border:1px solid var(--line);border-radius:12px;padding:13px 15px;background:var(--bg)}
  .fs-comp-h{display:flex;align-items:baseline;justify-content:space-between;gap:10px}
  .fs-comp-a{font-size:12.5px;font-weight:650;color:var(--ink);min-width:0}
  .fs-tag{flex:none;font-size:9.5px;font-weight:800;letter-spacing:.12em;text-transform:uppercase;
          padding:3px 7px;border-radius:5px}
  .fs-tag.live{background:var(--brand);color:#fff}
  .fs-tag.sold{border:1px solid var(--line);color:var(--muted)}
  .fs-price{margin-top:6px;font-family:Fraunces,Georgia,serif;font-size:21px;color:var(--ink)}
  .fs-price small{font-family:Inter,system-ui,sans-serif;font-size:11px;color:var(--muted);margin-left:6px}
  .fs-specs{margin-top:4px;font-size:11.5px;color:var(--body)}

  /* Talking points: how this comp differs from the subject, as chips an agent
     can read off mid-conversation rather than a sentence they have to parse. */
  /* Price reduction on an active comp — called out rather than buried in the
     spec run, because it is the line an agent quotes to a seller. */
  .fs-drop{margin-top:6px;font-size:11.5px;font-weight:650;color:#b4451f}
  .fs-refresh{margin-top:14px}
  .fs-relink{background:none;border:0;padding:0;margin-left:4px;cursor:pointer;
    font:inherit;color:var(--brand);font-weight:650;text-decoration:underline}
  .fs-relink:disabled{opacity:.5;cursor:default}
  @media print{ .fs-refresh{display:none} }
  .fs-points{display:flex;flex-wrap:wrap;gap:5px;margin-top:8px}
  .fs-point{font-size:10.5px;line-height:1.5;padding:2px 7px;border-radius:99px;
    background:var(--wash,rgba(0,0,0,.04));color:var(--muted);white-space:nowrap}

  /* Floor plans. One plan gets the full width; several share a row. Light
     ground regardless of theme — plans are black line art on white, and they
     vanish against a dark card. */
  .fs-plans{display:grid;gap:12px;grid-template-columns:1fr}
  .fs-plans:has(.fs-plan:nth-child(2)){grid-template-columns:repeat(auto-fit,minmax(min(220px,100%),1fr))}
  .fs-plan{display:block;border:1px solid var(--line);border-radius:var(--r);overflow:hidden;
    background:#fff;box-shadow:var(--shadow-sm)}
  .fs-plan img{display:block;width:100%;height:auto;object-fit:contain}

  /* Agent-eyes-only block. Red because it is the one thing on this sheet that
     must not travel, and the colour has to survive a glance. */
  .fs-private{border:1px solid rgba(190,42,42,.35);border-radius:10px;padding:14px 16px 4px;
    background:rgba(190,42,42,.04)}
  .fs-sh-private{border-bottom-color:rgba(190,42,42,.25)}
  .fs-sh-private b{color:#a11f1f}
  .fs-sh-private span{color:#a11f1f;opacity:.8}
  .fs-private .fs-card-v{color:#a11f1f}
  /* Printing is a hand-off medium — a printed sheet ends up in a seller's
     hands as often as an emailed one — so the private block does not print. */
  @media print{ .fs-private,[data-private]{display:none !important} }

  /* Hero: the property's own photograph behind the address, so the sheet is
     visibly about THIS house before any research appears. */
  .fs-hero{position:relative;isolation:isolate;min-height:150px;display:flex;align-items:flex-end}
  .fs-shot{position:absolute;inset:0;z-index:0;background-size:cover;background-position:center;
           opacity:0;transition:opacity .3s}
  .fs-hero.has-shot .fs-shot{opacity:.92}
  .fs-hero.has-shot::before{content:'';position:absolute;inset:0;z-index:1;
    background:linear-gradient(100deg,rgba(6,8,6,.88) 0%,rgba(6,8,6,.62) 38%,rgba(6,8,6,.12) 78%,rgba(6,8,6,.04) 100%)}
  .fs-hero-in{position:relative;z-index:2;width:100%}
  .fs-by{display:flex;align-items:center;gap:9px;margin-top:12px}
  .fs-av{width:30px;height:30px;border-radius:50%;flex:none;display:flex;align-items:center;justify-content:center;
         font-size:11px;font-weight:700;color:var(--brand-glow);background:linear-gradient(150deg,#12241a,#0b0c0b);
         border:1px solid rgba(51,217,106,.34);background-size:cover;background-position:center}
  /* The initials are a PLACEHOLDER for the headshot, not a label on it.
     applyHeadshot() adds .has-photo once the image loads; without this rule
     (which existed only for .chero-av) the initials stayed painted across the
     agent's face. */
  .fs-av.has-photo{color:transparent;border-color:rgba(255,255,255,.3)}
  .fs-by-t{font-size:11.5px;color:rgba(232,237,233,.76)}

  /* Spec strip: the agent's own listing details. */
  .fs-specs-strip{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(112px,100%),1fr));gap:1px;
                  background:var(--line);border:1px solid var(--line);border-radius:12px;
                  overflow:hidden;margin:-6px 0 4px}
  .fs-spec{background:var(--bg);padding:11px 13px}
  .fs-spec .k{display:block;font-size:9.5px;font-weight:800;letter-spacing:.11em;text-transform:uppercase;color:var(--muted)}
  .fs-spec .v{display:block;margin-top:3px;font-size:14px;font-weight:650;color:var(--ink);
              font-variant-numeric:tabular-nums}

  /* Actions sit above the sheet and never print. */
  .fs-actions{display:flex;flex-wrap:wrap;align-items:center;gap:10px;margin:0 0 18px;
              padding-bottom:14px;border-bottom:1px solid var(--line)}
  .fs-act{cursor:pointer;font-size:11.5px;font-weight:700;color:var(--brand-ink);
          background:rgba(37,182,87,.10);border:1px solid rgba(51,217,106,.42);border-radius:9px;
          padding:8px 14px;transition:background .15s}
  .fs-act:hover{background:rgba(37,182,87,.18)}
  .fs-act:disabled{opacity:.55;cursor:default}
  .fs-act-note{font-size:11px;color:var(--muted);line-height:1.45;flex:1;min-width:150px}
  .fs-act-note.ok{color:var(--brand-ink)}
  .fs-act-note.err{color:var(--err)}

  .fs-empty{border:1px dashed var(--line);border-radius:12px;padding:22px;text-align:center}
  .fs-empty p{font-size:13.5px;color:var(--body);line-height:1.6;max-width:52ch;margin:0 auto}
  /* Room dimensions + description: the two sections that close the sheet. */
  .fs-rdf{font-size:11px;font-weight:700;letter-spacing:.12em;text-transform:uppercase;
    color:var(--muted);margin:14px 0 6px}
  .fs-rd{display:grid;grid-template-columns:1fr 1fr;column-gap:34px}
  .fs-rdr{display:flex;align-items:baseline;justify-content:space-between;gap:12px;
    padding:7px 0;border-bottom:1px solid var(--line)}
  .fs-rdn{font-weight:600}
  .fs-rdv{font-variant-numeric:tabular-nums;color:var(--muted);white-space:nowrap}
  .fs-desc p{margin:0 0 10px;line-height:1.62}
  .fs-desc p:last-child{margin-bottom:0}
  @media (max-width:720px){ .fs-rd{grid-template-columns:1fr} }
  @media print{ .fs-rdr,.fs-desc p{break-inside:avoid} }
  .fs-note{margin-top:16px;font-size:11.5px;color:var(--muted);line-height:1.6}
  @media (max-width:620px){ .fs-grid{grid-template-columns:1fr} }
  .op-url{display:flex;gap:8px;margin-bottom:14px}
  .op-url input{flex:1;min-width:0;padding:10px 12px;border:1px solid var(--line);border-radius:10px;
                font:inherit;font-size:12.5px;color:var(--muted);background:var(--soft)}
  .op-lb{display:block;font-size:12px;font-weight:700;color:var(--ink);margin-bottom:6px}
  #opTo{width:100%;padding:11px 13px;border:1px solid var(--line);border-radius:10px;font:inherit;font-size:14px}
  .sc-cap{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
  .sc-cap .nm{flex:1;min-width:0}
  .sc-copy{flex:none;border:1px solid var(--line);background:#fff;border-radius:8px;padding:5px 10px;
           font:inherit;font-size:11.5px;font-weight:700;color:var(--brand-ink);cursor:pointer}
  .sc-copy:hover{border-color:var(--brand)}
  .sc-open{flex:none;font-size:11.5px;font-weight:700;color:var(--brand-ink);text-decoration:none;padding:5px 4px}
  .sc-open:hover{text-decoration:underline}
  .sc-more{display:block;margin:16px auto 0;padding:11px 22px;border:1px solid var(--line);border-radius:999px;
           background:#fff;font:inherit;font-size:13px;font-weight:700;color:var(--brand-ink);cursor:pointer;
           box-shadow:var(--shadow-sm);transition:border-color .14s,transform .1s}
  .sc-more:hover{border-color:var(--brand)}
  .sc-more:active{transform:translateY(1px)}
  .sc-waking{display:flex;align-items:center;gap:10px;padding:12px 16px;margin-bottom:18px;
             border:1px solid var(--line);border-radius:var(--r);background:var(--soft);
             font-size:13px;font-weight:600;color:var(--muted)}
  .sc-waking .spinner{flex:none}
  .lk-copy{margin-left:8px}
  .dsc-gen{display:flex;align-items:center;gap:14px;padding:14px 16px;border:1px solid #cfe6d6;border-radius:var(--r);
           background:linear-gradient(120deg,rgba(37,182,87,.07),rgba(37,182,87,.02))}
  .dsc-gen-b{flex:1;min-width:0}
  .dsc-gen-t{font-weight:700;font-size:14px;color:var(--ink)}
  .dsc-gen-d{font-size:12.5px;color:var(--muted);margin-top:2px}
  .dsc-gen .pc-btn{flex:none}
  .dsc-gen .pc-btn svg{width:13px;height:13px}
  #dscTxt{width:100%;padding:12px 13px;border:1px solid var(--line);border-radius:12px;font:inherit;
          font-size:14px;line-height:1.55;color:var(--body);resize:vertical}
  .dsc-foot{display:flex;align-items:center;gap:12px;margin-top:14px}
  .dsc-msg{flex:1;min-width:0;font-size:12.5px;color:var(--muted)}
  .dsc-msg.ok{color:var(--brand-ink);font-weight:600}
  .dsc-msg.err{color:var(--err);font-weight:600}
  /* Approval record: deliberately plain and factual, not a badge to admire. */
  .dsc-appr{margin-top:14px;padding:11px 14px;border-radius:10px;
            border:1px solid rgba(51,217,106,.32);background:rgba(37,182,87,.07)}
  .dsc-appr-t{font-size:10.5px;font-weight:800;letter-spacing:.14em;text-transform:uppercase;
              color:var(--brand-ink)}
  .dsc-appr-b{margin-top:5px;font-size:12.5px;line-height:1.5;color:var(--ink)}
  .dsc-appr-s{margin-top:3px;font-size:11.5px;color:var(--muted)}
  /* Arrival banner: shown once, right after approving, so the agent can see
     the description landed and knows it is still theirs to edit. */
  .sd-landed{margin:0 0 16px;padding:14px 16px;border-radius:12px;
             border:1px solid rgba(51,217,106,.45);background:rgba(37,182,87,.10);
             animation:sdLandIn .45s ease-out}
  @keyframes sdLandIn{from{opacity:0;transform:translateY(-6px)}to{opacity:1;transform:none}}
  .sd-landed-t{display:flex;align-items:center;gap:8px;font-size:13.5px;font-weight:700;color:var(--brand-ink)}
  .sd-landed-b{margin-top:5px;font-size:12.5px;line-height:1.55;color:var(--ink)}
  @media (prefers-reduced-motion:reduce){ .sd-landed{animation:none} }
  .mreq{display:flex;flex-direction:column;gap:0;border:1px solid var(--line);border-radius:12px;background:#fff;overflow:hidden}
  .rqrow{padding:14px 16px;border-bottom:1px solid var(--hair)}
  .rqrow:last-child{border-bottom:0}
  .rq-top{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin-bottom:6px}
  .rq-kind{font-size:10px;font-weight:800;letter-spacing:.07em;text-transform:uppercase;
           padding:3px 8px;border-radius:999px;background:var(--soft);color:var(--muted)}
  .rq-kind.services{background:rgba(37,182,87,.14);color:var(--brand-ink)}
  .rq-kind.correction{background:#fff3d6;color:#a9791c}
  .rq-who{font-size:12.5px;font-weight:600;color:var(--ink)}
  .rq-when{margin-left:auto;font-size:11.5px;color:var(--muted)}
  .rq-msg{font-size:13.5px;line-height:1.55;color:var(--body);white-space:pre-wrap}
  .mreq .empty,.mreq .loading{padding:20px}
  .movr{display:flex;align-items:center;flex-wrap:wrap;gap:10px 14px;width:100%;margin-top:11px;
        padding-top:11px;border-top:1px solid var(--hair);font-size:12.5px}
  .movr-t{display:inline-flex;align-items:center;gap:7px;font-weight:600;color:var(--body);cursor:pointer}
  .movr-t input{width:15px;height:15px;cursor:pointer;margin:0;accent-color:var(--brand)}
  .movr-d{display:inline-flex;align-items:center;gap:7px;color:var(--muted)}
  .movr-d input{padding:5px 8px;border:1px solid var(--line);border-radius:8px;font:inherit;font-size:12px}
  .movr-d input:disabled{opacity:.45}
  .ovr-msg{margin-left:auto;font-size:11.5px;font-weight:600;color:var(--muted)}
  .ovr-msg.ok{color:var(--brand-ink)} .ovr-msg.err{color:var(--err)}
  .mrow{flex-wrap:wrap}
  .opv{display:grid;grid-template-columns:minmax(0,1.55fr) minmax(min(300px,100%),1fr);gap:18px;align-items:start;margin-bottom:20px}
  .opv-frame{border:1px solid var(--line);border-radius:var(--r);overflow:hidden;background:var(--soft);
             min-height:520px;display:flex;box-shadow:var(--shadow-sm)}
  .opv-frame .loading,.opv-frame .empty{margin:auto;padding:28px;text-align:center}
  /* Where the preview failed, and enough detail to report it without asking
     the agent to open a console. */
  .opv-diag{margin:0 auto 22px;padding:0 28px;text-align:center;font-size:11px;
    line-height:1.5;color:var(--muted);word-break:break-all}
  .opv-if{width:100%;height:640px;border:0;display:block;background:#fff}
  .opv-side{display:flex;flex-direction:column;gap:14px}
  .opv-card{border:1px solid var(--line);border-radius:var(--r);background:#fff;padding:18px;box-shadow:var(--shadow-sm)}
  .opv-h{font-family:Fraunces,Georgia,serif;font-size:17px;color:var(--ink);margin-bottom:14px;letter-spacing:-.01em}
  .opv-card input[type=text],.opv-card input[type=email],.opv-card input[type=tel]{width:100%;padding:10px 12px;
    border:1px solid var(--line);border-radius:10px;font:inherit;font-size:14px}
  .opv-card textarea{width:100%;padding:11px 12px;border:1px solid var(--line);border-radius:10px;
    font:inherit;font-size:13.5px;line-height:1.5;color:var(--body);resize:vertical}
  .opv-note{margin-top:12px;font-size:12px;line-height:1.5;color:var(--muted);background:var(--soft);
            border-radius:10px;padding:10px 12px}
  @media (max-width:900px){ .opv{grid-template-columns:1fr} .opv-if{height:460px} .opv-frame{min-height:0} }
  /* ---- Product cards: the paid things, shown with the agent's own photos ---- */
  .review-cta{display:flex;align-items:center;gap:18px;width:100%;margin-top:30px;padding:20px 24px;
              border:1px solid var(--line);border-radius:var(--r);cursor:pointer;font:inherit;text-align:left;
              background:linear-gradient(110deg,#fffdf7,#faf8f2 55%,#f6f8f4);
              box-shadow:var(--shadow-sm);transition:transform .14s,box-shadow .22s,border-color .2s}
  .review-cta:hover{transform:translateY(-2px);box-shadow:var(--shadow);border-color:#d8c9a0}
  .review-cta{transition:transform .14s,box-shadow .22s,border-color .2s,opacity .38s}
  .review-cta.thanks{cursor:default;border-color:#cfe6d6;background:linear-gradient(110deg,#f2fbf5,#f6f8f4)}
  .review-cta.thanks:hover{transform:none;box-shadow:var(--shadow-sm)}
  .rv-stars{flex:none;display:inline-flex;gap:2px;color:#d8a53a}
  .rv-stars svg{width:19px;height:19px;fill:#f0c264;stroke:#d8a53a;stroke-width:1.4}
  .rv-tx{flex:1;min-width:0;display:flex;flex-direction:column;gap:3px}
  .rv-tx b{font-family:Fraunces,Georgia,serif;font-size:18px;color:var(--ink);letter-spacing:-.01em}
  .rv-tx span{font-size:13px;color:var(--muted)}
  .rv-go{flex:none;display:inline-flex;align-items:center;gap:6px;font-size:13px;font-weight:700;color:var(--brand-ink)}
  .rv-go svg{width:15px;height:15px}
  @media (max-width:620px){
    .review-cta{flex-wrap:wrap;gap:12px;padding:16px}
    .rv-tx b{font-size:16px}
    .rv-go{width:100%}
  }
  .prods{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(238px,100%),1fr));gap:14px}
  .prod{position:relative;display:flex;flex-direction:column;text-align:left;cursor:pointer;font:inherit;
        border:1px solid var(--line);border-radius:16px;background:#fff;overflow:hidden;
        box-shadow:var(--shadow-sm);transition:transform .14s,box-shadow .22s,border-color .2s}
  .prod:hover{transform:translateY(-3px);box-shadow:var(--shadow);border-color:#cfe6d6}
  .prod.on{border-color:#bfe6cd}

  .pr-img{position:relative;display:block;aspect-ratio:16/10;overflow:hidden;background:var(--soft)}
  .pr-bg{position:absolute;inset:0;background:var(--soft) center/cover no-repeat;
         transition:transform .5s cubic-bezier(.2,.8,.3,1)}
  .prod:hover .pr-bg{transform:scale(1.05)}
  .pr-img::after{content:"";position:absolute;inset:0;
                 background:linear-gradient(180deg,rgba(6,8,6,.30),rgba(6,8,6,0) 46%,rgba(6,8,6,.34))}
  /* the twilight card grades the agent's own exterior, so the card IS the demo */
  /* staging: lift and cool the interior so it reads as "before" awaiting a change */

  .pr-tag{position:absolute;top:10px;left:10px;z-index:2;font-size:9.5px;font-weight:800;
          letter-spacing:.09em;text-transform:uppercase;padding:4px 9px;border-radius:999px;
          background:rgba(255,255,255,.92);color:var(--muted);backdrop-filter:blur(6px);white-space:nowrap}
  .prod.on .pr-tag{background:rgba(37,182,87,.94);color:#04170c}
  .ptile-state.owing{background:rgba(217,146,19,.16);color:#a9791c}
  /* Download tile when a balance is outstanding. Amber, never green: this is a
     gate, and it has to read as one before the agent clicks it. */
  /* HDPhotoHub's download page, framed. Tall by design — it carries its own
     toolbar and grid, and a short frame would force two scrollbars. */
  /* HDPhotoHub's download page, framed with its header cropped off.

     Their header is `position: relative; height: 82px` — a normal element at
     the very top of the document. That matters: a static header is only ever
     visible inside the first 82px of the frame's viewport, whatever the scroll
     position. So clipping that band hides it PERMANENTLY — there is no scroll
     position that can bring the logo, the Order Form link or the sign-in
     hamburger back. Which is the point: those all lead into HDPhotoHub, and
     clients must never end up there.

     Done by making the iframe 82px taller than its window and pulling it up by
     the same amount, with overflow:hidden on the wrapper. We cannot inject CSS
     into a cross-origin frame, so cropping is the only lever available.

     The cost, stated plainly: at the very bottom of the page 82px of content
     sits under the crop and cannot be scrolled into view. Their page ends in a
     footer, so in practice this eats chrome rather than photographs — but it
     is a real trade and worth re-checking if their layout changes. */
  /* ---- Download your media ------------------------------------------------
     The page answers "what do I press?" before it shows anything else. Two
     full-width buttons, then a folded-away grid for the minority who want to
     pick photos individually. */
  .dl-actions{display:flex;flex-direction:column;gap:12px;margin:0 0 22px}
  .dl-big{display:flex;align-items:center;gap:16px;width:100%;text-align:left;
    padding:18px 20px;border:1px solid var(--line);border-radius:16px;background:#fff;
    cursor:pointer;font:inherit;color:var(--ink);
    transition:border-color .16s,box-shadow .16s,transform .08s}
  .dl-big:hover{border-color:var(--brand);box-shadow:var(--shadow-sm)}
  .dl-big:active{transform:translateY(1px)}
  /* The primary is the one an agent wants nine times in ten. It should be the
     loudest thing on the screen — louder than any per-photo control. */
  .dl-big.primary{border:0;color:#04170c;
    background:linear-gradient(180deg,var(--brand-2),var(--brand));
    box-shadow:0 12px 28px -12px rgba(32,157,80,.65)}
  .dl-big.primary:hover{filter:brightness(1.04);border:0}
  .dl-big-ic{flex:none;width:42px;height:42px;border-radius:12px;display:flex;
    align-items:center;justify-content:center;background:rgba(0,0,0,.07)}
  .dl-big.primary .dl-big-ic{background:rgba(0,0,0,.14)}
  .dl-big-ic svg{width:20px;height:20px}
  .dl-big-t{display:flex;flex-direction:column;gap:3px;font-size:15.5px;font-weight:750;min-width:0}
  .dl-big-d{font-size:12.5px;font-weight:500;opacity:.78;line-height:1.4}
  .dl-note{margin:2px 0 0;font-size:12px;color:var(--muted);line-height:1.5}
  .dl-status{font-size:12.5px;color:var(--body);min-height:1em}

  .ph-lead{font-size:12.5px;color:var(--muted);line-height:1.55;margin:0 0 14px}

  /* Size selector — the first decision in the grid, since it governs both the
     per-photo icon and the selection download. Segmented, not a loose pair of
     radios, so the active choice is unmistakable. */
  .ph-size{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
  .ph-size-l{font-size:11px;font-weight:800;letter-spacing:.1em;text-transform:uppercase;color:var(--muted)}
  .ph-size label{display:inline-flex;align-items:center;gap:6px;cursor:pointer;
    padding:6px 11px;border:1px solid var(--line);border-radius:99px;background:#fff;
    font-size:12.5px;font-weight:650;color:var(--body);transition:border-color .14s,background .14s,color .14s}
  .ph-size label:hover{border-color:var(--brand)}
  .ph-size label:has(input:checked){border-color:var(--brand);background:rgba(37,182,87,.1);color:var(--brand-ink)}
  .ph-size label i{font-style:normal;font-weight:500;font-size:11px;color:var(--muted)}
  .ph-size input{accent-color:var(--brand);margin:0}

  /* ---- The contact sheet --------------------------------------------------
     Uniform 4:3 rectangles. Mixed aspect ratios read as a file listing; equal
     rectangles read as a proof sheet, which is what an agent expects to see. */
  .ph-grid{display:grid;gap:14px;
    grid-template-columns:repeat(auto-fill,minmax(min(190px,100%),1fr))}
  @media (max-width:760px){
    .ph-grid{grid-template-columns:repeat(2,minmax(0,1fr));gap:10px}
  }
  .pht{display:flex;flex-direction:column;gap:7px;min-width:0}
  .pht-shot{position:relative;display:block;aspect-ratio:4/3;border-radius:12px;
    overflow:hidden;background:var(--black);cursor:pointer;
    border:1px solid var(--line);transition:box-shadow .16s,border-color .16s}
  .pht-shot:hover{border-color:var(--brand)}
  .pht-shot img{width:100%;height:100%;object-fit:cover;display:block}
  .pht-zzz{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;
    color:#ffe6a8;font-size:12px;letter-spacing:.14em;text-transform:uppercase}
  .pht.is-asleep .pht-shot{cursor:default;opacity:.75}

  /* The selection flag. Hidden checkbox, styled square — big enough to hit on
     a phone, quiet enough not to fight the photograph. */
  .pht-shot .ph-cb{position:absolute;opacity:0;width:0;height:0}
  .pht-flag{position:absolute;top:8px;left:8px;z-index:2;width:22px;height:22px;
    border-radius:6px;background:rgba(255,255,255,.9);border:1px solid rgba(0,0,0,.18);
    box-shadow:0 1px 3px rgba(0,0,0,.25);transition:background .14s,border-color .14s}
  .pht-flag::after{content:"";position:absolute;left:7px;top:3px;width:6px;height:11px;
    border-right:2.5px solid #fff;border-bottom:2.5px solid #fff;
    transform:rotate(45deg) scale(.6);opacity:0;transition:opacity .14s,transform .14s}
  .ph-cb:checked~.pht-flag{background:var(--brand);border-color:var(--brand-ink)}
  .ph-cb:checked~.pht-flag::after{opacity:1;transform:rotate(45deg) scale(1)}
  .ph-cb:focus-visible~.pht-flag{outline:2px solid var(--brand-ink);outline-offset:2px}
  .ph-cb:checked~img{filter:brightness(.92)}
  .pht-shot:has(.ph-cb:checked){border-color:var(--brand);box-shadow:0 0 0 2px var(--brand) inset}

  /* Per-photo download: a small icon, not a button. It used to be a solid
     button repeated on every card, which made downloading one at a time look
     like the intended path. */
  .pht-dl{position:absolute;bottom:8px;right:8px;z-index:2;width:30px;height:30px;
    border:0;border-radius:9px;cursor:pointer;display:flex;align-items:center;justify-content:center;
    background:rgba(12,14,12,.55);color:rgba(255,255,255,.9);opacity:0;
    transition:opacity .15s,background .15s}
  .pht-dl svg{width:15px;height:15px}
  .pht-shot:hover .pht-dl,.pht-dl:focus-visible{opacity:1}
  .pht-dl:hover{background:rgba(12,14,12,.8)}
  @media (hover:none){ .pht-dl{opacity:.85} }

  /* Names save on blur — no tick button. A brief green edge is the whole
     confirmation; a status line for every keystroke would be noise. */
  .pht.saving .nm-in{border-color:var(--brand);background:rgba(37,182,87,.06)}
  .ph-more{display:block;margin:16px auto 0;padding:10px 20px;border:1px solid var(--line);
    border-radius:99px;background:#fff;cursor:pointer;font:inherit;font-size:12.5px;
    font-weight:700;color:var(--brand-ink);transition:border-color .14s,background .14s}
  .ph-more:hover{border-color:var(--brand);background:var(--soft)}
  .pht-name{display:flex;gap:6px;align-items:center}
  .pht-name .nm-in{flex:1;min-width:0;padding:7px 9px;border:1px solid var(--line);
    border-radius:8px;font:inherit;font-size:12px;color:var(--ink);background:#fff}
  .pht-name .nm-in:focus{outline:0;border-color:var(--brand)}

  .btn-mini.primary{background:linear-gradient(180deg,var(--brand-2),var(--brand));
    border:0;color:#04170c;font-weight:750}
  .btn-mini.primary:disabled{opacity:.4;filter:saturate(.4)}

  /* Owner preview — form first, no iframe.
     The live page used to sit beside this form; on a phone it panned sideways
     and agents fought that drift while trying to reach the form. The preview
     is now a button that opens a real tab. */
  /* Owner preview layout.

     The previous split put the seller form and the preview card in the left
     column and let the message span both rows on the right. The two columns
     then had nothing to do with each other: the right card's height was the
     sum of two unrelated cards plus a gap, so nothing lined up.

     Grouped by task instead. LEFT is one job — who the seller is, what we
     hold on them, and the promise not to contact them — as a single tall
     card. RIGHT is the other job, stacked in the order it is done: look at
     the preview, then send it. Each column is now one idea, and the rows
     align because the left card spans them both. */
  .opv-wrap-head{max-width:1060px;margin:0 auto}
  .opv2{display:grid;gap:16px;grid-template-columns:1fr;
    max-width:660px;margin:0 auto 28px}

  @media (min-width:940px){
    .opv2{max-width:1060px;grid-template-columns:minmax(0,1fr) minmax(0,1fr)}
    /* No align-items:start — the seller card SPANS both rows, so letting it
       stretch is what makes the two columns end level. */
    .opv2>.opv-card{display:flex;flex-direction:column}
    /* DOM order: 1 seller, 2 preview, 3 send. */
    .opv2>.opv-card:nth-child(1){grid-column:1;grid-row:1 / span 2}
    .opv2>.opv-card:nth-child(2){grid-column:2;grid-row:1}
    .opv2>.opv-card:nth-child(3){grid-column:2;grid-row:2;
      display:flex;flex-direction:column}
    .opv2>.opv-card:nth-child(3) textarea{flex:1;min-height:190px}
    /* Anything that should sit at the foot of a stretched card. */
    .opv2>.opv-card>.opv-privacy{margin-top:auto;padding-top:12px}
  }

  /* Phone: the message box is the tallest thing here and pushed the send
     buttons off the first screen. Shorter, and it still scrolls. */
  @media (max-width:760px){
    .opv2{gap:13px}
    .opv2 textarea{min-height:150px}
    .opv-sendrow .pc-btn{min-width:0}
  }
  .opv-see{display:flex;align-items:center;gap:16px;flex-wrap:wrap;justify-content:space-between}
  .opv-see-b{min-width:0;flex:1}
  .opv-see-d{margin:5px 0 0;font-size:12.5px;color:var(--muted);line-height:1.5}
  .opv-open{flex:none;font-weight:750}
  .opv-open:not(:disabled){border-color:var(--brand);color:var(--brand-ink);background:rgba(37,182,87,.08)}
  .opv-open:disabled{opacity:.5;cursor:default}
  .opv-fields{display:flex;flex-direction:column;gap:4px;margin-bottom:14px}
  .opv-fields .op-lb{margin-top:10px}
  .opv-fields .op-lb:first-child{margin-top:0}
  .op-opt{font-weight:500;color:var(--muted)}
  .opv-note-tight{margin-top:10px}
  .opv2 .opv-send{width:100%;justify-content:center;font-weight:750}

  .opv-web{margin-top:11px;font-size:12px;color:var(--muted);line-height:1.7}
  .opv-web.on{padding:10px 12px;border-radius:10px;background:rgba(217,146,19,.08);
    border:1px solid rgba(217,146,19,.32);color:var(--body)}
  .opv-web.on .opv-web-lead{font-weight:700;color:#8c6413}
  .lnk{background:none;border:0;padding:0;font:inherit;font-size:12px;font-weight:650;
    color:var(--brand-ink);cursor:pointer;text-decoration:underline}
  .lnk:hover{color:var(--brand)}
  .lnk:disabled{color:var(--muted);cursor:default;text-decoration:none;opacity:.7}

  /* Stored details read differently from an empty form — greener, so the
     agent can see at a glance this is something they saved before. */
  /* What Megapixeler actually holds on this seller. A form cannot answer that:
     the same empty boxes mean nothing-saved, not-yet-saved and saved-but-blank. */
  .opv-stored{margin-top:14px;padding:12px 14px;border-radius:12px;
    border:1px solid var(--line);background:var(--soft);display:flex;
    flex-direction:column;gap:7px}
  .opv-stored-h{font-size:10.5px;font-weight:800;letter-spacing:.12em;
    text-transform:uppercase;color:var(--muted)}
  .opv-stored.empty .opv-stored-none{font-size:13px;color:var(--muted);font-style:italic}
  .opv-stored.has{border-color:rgba(37,182,87,.35);background:rgba(37,182,87,.06)}
  .opv-stored-rows{display:flex;flex-direction:column;gap:4px}
  .opv-stored-row{display:flex;gap:10px;align-items:baseline;font-size:13px}
  .opv-stored-row .k{flex:none;width:54px;font-size:11px;font-weight:700;
    letter-spacing:.04em;text-transform:uppercase;color:var(--muted)}
  .opv-stored-row .v{color:var(--ink);font-weight:600;word-break:break-word;min-width:0}
  .opv-stored-when{font-size:11.5px;color:var(--muted)}

  /* Says plainly that we do not contact their client. Agents guard that
     relationship, and a portal holding a seller name should answer the
     question before it is asked. */
  .opv-privacy{display:flex;gap:9px;align-items:flex-start;margin-top:11px;
    font-size:11.5px;line-height:1.55;color:var(--muted)}
  .opv-privacy b{color:var(--body);font-weight:700}
  .opv-privacy-ic{flex:none;font-size:12px;line-height:1.4}

  .opv-saverow{display:flex;align-items:center;gap:12px;margin-top:14px}
  .opv-saved{font-size:12px;color:var(--muted)}
  .opv-saved.ok{color:var(--brand-ink);font-weight:650}
  .opv-saved.err{color:#b4451f;font-weight:650}
  .opv2 .op-url{margin-top:14px}
  .opv-sendrow{display:flex;gap:10px;flex-wrap:wrap;margin-top:14px}
  .opv-sendrow .pc-btn{flex:1;min-width:150px;justify-content:center;font-weight:750}
  .pc-btn.primary{background:linear-gradient(180deg,var(--brand-2),var(--brand));border:0;color:#04170c}
  .pc-btn.primary:disabled{opacity:.45;filter:saturate(.35)}
  .opv2 textarea{width:100%;padding:12px 13px;border:1px solid var(--line);border-radius:12px;
    font:inherit;font-size:13.5px;line-height:1.55;color:var(--body);resize:vertical}
  .opv2 textarea:focus{outline:0;border-color:var(--brand)}

  /* Star on a showcase photo. Sits over the image, always visible once set so
     the agent can see their picks at a glance without hovering each one. */
  .sc-ph{position:relative;margin:0;display:block}
  /* ALWAYS visible, on every device. A hover-only control is a control most
     people never discover — which is precisely why starring went unused when
     it lived on the download page. It sits at 0.8 so it reads as available
     without competing with the photograph. */
  .sc-star{position:absolute;top:6px;right:6px;z-index:2;width:28px;height:28px;
    border:0;border-radius:50%;cursor:pointer;font-size:15px;line-height:1;
    background:rgba(12,14,12,.5);color:rgba(255,255,255,.75);
    opacity:.8;transition:opacity .15s,background .15s,color .15s,transform .08s}
  .sc-ph:hover .sc-star,.sc-star:focus-visible{opacity:1}
  .sc-star.on{opacity:1;background:#f2b53c;color:#3a2600;
    box-shadow:0 4px 12px -3px rgba(217,146,19,.7)}
  .sc-star:active{transform:scale(.92)}
  .sc-star:disabled{cursor:default;opacity:.55}

  /* Deliberately small and grey — a caption, not a callout. It sat two lines
     tall and took space the photographs had earned. */
  .sc-hint{margin:-6px 0 9px;font-size:11.5px;color:var(--muted);line-height:1.4}

  .dl-gate{max-width:520px;margin:32px auto;padding:26px 28px;text-align:center;
    border:1px solid rgba(217,146,19,.4);border-radius:var(--r);background:rgba(217,146,19,.06)}
  .dl-gate-t{font-family:Fraunces,Georgia,serif;font-size:20px;color:#8c6413}
  .dl-gate-b{margin:10px 0 18px;font-size:13.5px;line-height:1.6;color:var(--body)}

  /* Shown when a payment clears while the agent is still in the portal. The
     pay page opens in its own tab and HDPhotoHub cannot send anyone back, so
     the portal notices for itself rather than sitting on a stale "due". */
  .paid-toast{position:fixed;left:50%;bottom:26px;transform:translate(-50%,16px);z-index:80;
    display:flex;flex-direction:column;gap:2px;padding:13px 20px;border-radius:12px;
    background:linear-gradient(180deg,#1c5c33,#123f23);color:#eaf7ee;
    box-shadow:0 18px 40px -14px rgba(0,0,0,.6);opacity:0;pointer-events:none;
    transition:opacity .3s ease,transform .3s cubic-bezier(.2,.8,.3,1);max-width:min(92vw,420px)}
  .paid-toast.on{opacity:1;transform:translate(-50%,0)}
  .paid-toast b{font-size:13.5px;font-weight:700}
  .paid-toast span{font-size:12.5px;color:rgba(234,247,238,.8)}
  @media (prefers-reduced-motion:reduce){ .paid-toast{transition:opacity .3s ease} }


  .pr-b{display:flex;flex-direction:column;gap:5px;padding:15px 16px 16px;flex:1}
  .pr-n{font-family:Fraunces,Georgia,serif;font-size:17.5px;font-weight:600;color:var(--ink);letter-spacing:-.012em}
  .pr-d{flex:1;font-size:12.5px;line-height:1.5;color:var(--muted)}
  .pr-c{margin-top:5px;font-size:12.5px;font-weight:700;color:var(--brand-ink);display:inline-flex;align-items:center;gap:5px}
  .pr-c svg{width:14px;height:14px}
  .prod.soon .pr-c{color:var(--muted)}

  @media (max-width:620px){
    /* One card per row on a phone. Two-up squeezed each photo card to
       ~170px, which cropped the artwork hard and broke card titles onto a
       third line — the tool chips wear two columns fine, the products do not. */
    .prods{grid-template-columns:1fr;gap:10px}
    .pr-b{padding:12px 12px 13px;gap:4px}
    .pr-n{font-size:15px}
    .pr-d{font-size:11.5px}
    .pr-c{font-size:11.5px}
  }
  /* ---- Client hero band (Home + My Properties) -------------------------
     Same artwork for every agent — no per-client logic. Designed to read well
     with or without /hero-banner.jpg, so a missing image degrades to the brand
     gradient rather than a broken band. */
  .chero{position:relative;isolation:isolate;overflow:hidden;border-radius:var(--r);
         margin:0 0 30px;min-height:clamp(190px,22vw,260px);display:flex;background:var(--black)}
  .chero-bg{position:absolute;inset:0;z-index:0;background:
      radial-gradient(680px 320px at 88% 8%, rgba(37,182,87,.28), transparent 62%),
      radial-gradient(520px 300px at 8% 100%, rgba(37,182,87,.14), transparent 60%),
      linear-gradient(118deg,#0b0c0b 0%,#101a13 46%,#0b0c0b 100%);
      background-size:cover;background-position:center}
  .chero.has-img .chero-bg{background-image:url("/hero-banner.jpg?v=1")}
  .chero-mesh{position:absolute;inset:0;z-index:1;width:100%;height:100%;pointer-events:none;
              opacity:.9;mix-blend-mode:screen}
  @media (max-width:760px){ .chero-mesh{opacity:.55} }
  .chero-scrim{position:absolute;inset:0;z-index:2;pointer-events:none;background:
      linear-gradient(96deg, rgba(6,8,6,.90) 0%, rgba(6,8,6,.74) 40%, rgba(6,8,6,.30) 74%, rgba(6,8,6,.44) 100%)}
  /* a faint grid, the "modern/technical" note, kept very low contrast */
  .chero-inner{position:relative;z-index:3;flex:1;display:flex;align-items:center;
               justify-content:space-between;gap:24px;flex-wrap:wrap;padding:clamp(20px,3vw,30px)}
  .chero-l{display:flex;align-items:center;gap:20px;min-width:0}

  .chero-av{flex:none;width:88px;height:88px;border-radius:50%;display:flex;align-items:center;
            justify-content:center;font-family:Fraunces,Georgia,serif;font-size:30px;font-weight:600;
            color:var(--brand-glow);background:linear-gradient(150deg,#12241a,#0b0c0b);
            border:1px solid rgba(51,217,106,.3);
            box-shadow:inset 0 0 26px rgba(37,182,87,.22), 0 10px 30px -12px rgba(0,0,0,.8)}
  .chero-av.has-photo{background-size:cover;background-position:center;color:transparent;
                      border-color:rgba(255,255,255,.28)}

  .chero-tx{min-width:0}
  .chero-eyebrow{color:var(--brand-glow);font-weight:700;font-size:10.5px;letter-spacing:.16em;
                 text-transform:uppercase;opacity:.92;margin-bottom:8px}
  .chero-h{font-family:Fraunces,Georgia,serif;font-size:clamp(26px,3.4vw,40px);line-height:1.05;
           letter-spacing:-.022em;color:#fff;margin:0;text-wrap:balance}
  .chero-sub{color:rgba(232,237,233,.80);font-size:14px;margin:9px 0 0;max-width:54ch;line-height:1.5}
  .chero-email{color:rgba(232,237,233,.55);font-size:12.5px;margin-top:7px}

  .chero-stats{display:flex;flex-wrap:wrap;gap:9px;margin-top:14px}
  .cst{display:inline-flex;align-items:baseline;gap:6px;padding:6px 12px;border-radius:999px;
       background:rgba(255,255,255,.09);border:1px solid rgba(255,255,255,.16);backdrop-filter:blur(6px)}
  .cst b{color:#fff;font-size:15px;font-weight:700;font-variant-numeric:tabular-nums;letter-spacing:-.01em}
  .cst span{color:rgba(232,237,233,.72);font-size:11.5px}

  .chero-book{flex:none;display:inline-flex;align-items:center;gap:8px;text-decoration:none;
              padding:13px 20px;border-radius:12px;font-size:13.5px;font-weight:700;white-space:nowrap;
              background:linear-gradient(180deg,var(--brand),var(--brand-2));color:#04170c;
              box-shadow:0 12px 30px -12px rgba(37,182,87,.7);transition:filter .15s,transform .1s}
  .chero-book:hover{filter:brightness(1.06)}
  .chero-book:active{transform:translateY(1px)}

  /* Section header for the property list */
  .lhead{display:flex;align-items:center;gap:12px;margin:0 0 16px}
  .lhead-t{position:relative;padding-left:12px;font-size:11.5px;font-weight:800;letter-spacing:.14em;
           text-transform:uppercase;color:var(--muted)}
  .lhead-t::before{content:"";position:absolute;left:0;top:0;bottom:0;width:3px;border-radius:2px;
                   background:var(--brand)}
  .lhead-n{margin-left:auto;font-size:12px;color:var(--muted);background:var(--soft);
           border-radius:999px;padding:5px 12px;white-space:nowrap}

  @media (max-width:620px){
    .chero{min-height:0;margin-bottom:22px}
    .chero-inner{padding:18px;gap:16px}
    .chero-l{gap:14px}
    .chero-av{width:62px;height:62px;font-size:22px}
    .chero-sub{font-size:13px}
    .chero-book{width:100%;justify-content:center}
  }
  /* ---- Full-bleed property hero ---------------------------------------- */
  .ph-hero{position:relative;isolation:isolate;background:var(--black);
           min-height:clamp(330px,40vw,470px);display:flex;align-items:stretch;overflow:hidden}
  .ph-bg{position:absolute;inset:0;background:#0b0c0b center/cover no-repeat;z-index:0}
  .ph-hero.has-img .ph-bg{transform:scale(1.02)}
  .ph-scrim{position:absolute;inset:0;z-index:1;pointer-events:none;
    background:
      linear-gradient(96deg, rgba(6,8,6,.94) 0%, rgba(6,8,6,.86) 30%, rgba(6,8,6,.52) 56%, rgba(6,8,6,.16) 78%, rgba(6,8,6,.34) 100%),
      linear-gradient(180deg, rgba(6,8,6,.62) 0%, rgba(6,8,6,0) 30%, rgba(6,8,6,0) 62%, rgba(6,8,6,.55) 100%)}
  .ph-inner{position:relative;z-index:2;width:100%;max-width:1160px;margin:0 auto;
            padding:22px 30px 30px;display:flex;flex-direction:column}
  .ph-back{align-self:flex-start;background:rgba(255,255,255,.10);border:1px solid rgba(255,255,255,.18);
           color:#e8ede9;font:inherit;font-size:12.5px;font-weight:600;cursor:pointer;
           padding:7px 13px;border-radius:999px;display:inline-flex;align-items:center;gap:7px;
           backdrop-filter:blur(8px);transition:background .15s}
  .ph-back:hover{background:rgba(255,255,255,.18);color:#fff}
  .ph-back svg{width:13px;height:13px}
  .ph-body{flex:1;display:flex;align-items:flex-end;justify-content:space-between;gap:26px;margin-top:auto;padding-top:26px}
  .ph-left{min-width:0;max-width:660px}

  .ph-hero .ph-eyebrow{color:var(--brand-glow);font-weight:700;font-size:10.5px;letter-spacing:.16em;
                       text-transform:uppercase;margin-bottom:12px;opacity:.92}
  .ph-hero .ph-addr{font-size:clamp(30px,4.4vw,50px);line-height:1.03;letter-spacing:-.025em;
                    color:#fff;margin:0;text-wrap:balance;text-shadow:0 2px 24px rgba(0,0,0,.4)}
  .ph-hero .ph-loc{color:rgba(232,237,233,.82);font-size:clamp(14px,1.5vw,17px);margin-top:9px}

  .ph-stats{display:flex;flex-wrap:wrap;align-items:center;gap:0;margin-top:22px}
  .hs{display:flex;align-items:center;gap:10px;padding:0 20px 0 0;margin-right:20px;
      border-right:1px solid rgba(255,255,255,.16)}
  .hs:last-child{border-right:0;margin-right:0;padding-right:0}
  .hs-ic{flex:none;color:var(--brand-glow);opacity:.9;display:flex}
  .hs-ic svg{width:21px;height:21px}
  .hs-b{display:flex;flex-direction:column;line-height:1.15}
  .hs-v{color:#fff;font-size:17px;font-weight:700;font-variant-numeric:tabular-nums;letter-spacing:-.01em}
  .hs-l{color:rgba(232,237,233,.62);font-size:11px;font-weight:500;letter-spacing:.03em;margin-top:2px}

  .ph-acts{display:flex;flex-wrap:wrap;align-items:center;gap:9px;margin-top:26px}
  .ph-btn{display:inline-flex;align-items:center;gap:8px;border:0;cursor:pointer;font:inherit;
          padding:12px 19px;border-radius:11px;font-size:13.5px;font-weight:700;white-space:nowrap;
          transition:filter .15s,transform .1s,background .15s}
  .ph-btn svg{width:16px;height:16px;flex:none}
  .ph-btn.primary{background:linear-gradient(180deg,var(--brand),var(--brand-2));color:#04170c;
                  box-shadow:0 10px 26px -10px rgba(37,182,87,.7)}
  /* Money owed is never green — green is the paid state, and agents read colour first. */
  .ph-btn.primary.owing{background:linear-gradient(180deg,#f2b53c,#d99213);color:#3a2600;
                        box-shadow:0 10px 26px -10px rgba(217,146,19,.65)}
  .ph-btn.ghost{background:rgba(255,255,255,.10);color:#f2f5f2;border:1px solid rgba(255,255,255,.22);
                backdrop-filter:blur(8px)}
  .ph-btn.ghost:hover{background:rgba(255,255,255,.2)}
  /* Manage your listing earns a second look without shouting: a warm ivory solid
     against the dark hero, so it reads as the other primary rather than competing
     with the green Download. */
  .ph-btn.feature{background:linear-gradient(180deg,#fffdf7,#f3efe4);color:#171a16;
                  box-shadow:0 10px 28px -12px rgba(0,0,0,.75), 0 0 0 1px rgba(255,255,255,.5) inset;
                  position:relative}
  .ph-btn.feature svg{color:var(--brand-2)}
  .ph-btn.feature:hover{background:linear-gradient(180deg,#ffffff,#f7f4ec);
                        box-shadow:0 14px 34px -12px rgba(0,0,0,.8), 0 0 0 1px rgba(255,255,255,.7) inset}
  .ph-btn:hover{filter:brightness(1.05)}
  .ph-btn:active{transform:translateY(1px)}
  .ph-paid{display:inline-flex;align-items:center;gap:7px;padding:11px 15px;border-radius:11px;
           background:rgba(37,182,87,.20);border:1px solid rgba(62,224,111,.4);
           color:#8ff0ad;font-size:12.5px;font-weight:700;white-space:nowrap}
  .ph-paid svg{width:14px;height:14px}


  .gal-body{padding-top:24px}
  #propTerms:empty{display:none}
  #propTerms{margin-bottom:4px}

  @media (max-width:900px){ .ph-body{padding-top:20px} }
  @media (max-width:620px){
    .ph-hero{min-height:0}
    .ph-inner{padding:14px 16px 20px}
    .ph-stats{gap:8px 0;margin-top:16px}
    .hs{padding-right:13px;margin-right:13px}
    .hs-ic svg{width:18px;height:18px}
    .hs-v{font-size:15px}
    .ph-acts{margin-top:18px;gap:7px}
    .ph-btn{padding:11px 14px;font-size:12.5px;flex:1;justify-content:center}
    .ph-btn.primary{flex-basis:100%}
    .gal-body{padding-top:18px}
  }
  /* ---- Property showcase: a presentation of the delivery, not a file manager ---- */
  .ha-btn svg{width:14px;height:14px;flex:none}
  .ha-btn:hover{filter:brightness(1.04)}
  .ha-btn:active{transform:translateY(1px)}
  .ha-btn.pay{background:linear-gradient(180deg,var(--brand-2),var(--brand));color:#04170c}
  .ha-btn.paid{background:rgba(37,182,87,.92);color:#04170c;cursor:default;box-shadow:0 4px 14px rgba(0,0,0,.18)}
  .pbar-btn.paynow{background:linear-gradient(180deg,#f2b53c,#d99213);color:#3a2600}
  .sc-photos img,.sc-plans img{-webkit-user-select:none;user-select:none;-webkit-touch-callout:none}
  @media (max-width:620px){
    .hero-acts{right:8px;bottom:8px;gap:5px}
    .ha-btn{padding:7px 10px;font-size:11.5px;border-radius:9px}
  }
  .sc-bar{display:flex;flex-wrap:wrap;gap:9px;margin:24px 0 8px}
  .sc-sec{margin-top:30px}
  #gArea .sc-sec:first-child{margin-top:18px}
  .sc-h{display:flex;align-items:baseline;gap:9px;font-size:12px;font-weight:800;letter-spacing:.13em;
        text-transform:uppercase;color:var(--muted);padding-bottom:11px;border-bottom:1px solid var(--hair);margin-bottom:16px}
  .sc-h .n{font-size:11.5px;color:var(--brand-ink);letter-spacing:.02em}
  .sc-photos{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(268px,100%),1fr));gap:12px}
  .sc-photos img{width:100%;aspect-ratio:3/2;object-fit:cover;display:block;border-radius:var(--r-sm);
                 background:var(--soft);cursor:zoom-in;transition:transform .16s,box-shadow .16s}
  .sc-photos img:hover{transform:scale(1.012);box-shadow:var(--shadow)}
  .sc-embeds{display:flex;flex-direction:column;gap:18px}
  .sc-embed{border:1px solid var(--line);border-radius:var(--r);overflow:hidden;background:#fff;box-shadow:var(--shadow-sm)}
  .sc-embed iframe{width:100%;aspect-ratio:16/9;border:0;display:block;background:#0b0c0b}
  .sc-cap{padding:11px 14px;font-size:13px;font-weight:600;color:var(--body);border-top:1px solid var(--hair)}
  .sc-cap .k{display:block;font-size:10.5px;font-weight:800;letter-spacing:.1em;text-transform:uppercase;color:var(--muted);margin-bottom:2px}
  .sc-plans{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(320px,100%),1fr));gap:14px}
  .sc-plans img{width:100%;aspect-ratio:4/3;object-fit:contain;background:#fff;display:block;
                border:1px solid var(--line);border-radius:var(--r-sm);cursor:zoom-in;padding:8px}
  .sc-map{border:1px solid var(--line);border-radius:var(--r);overflow:hidden;box-shadow:var(--shadow-sm)}
  .sc-map iframe{width:100%;height:clamp(240px,32vw,400px);border:0;display:block}
  .sc-maplink{display:inline-flex;align-items:center;gap:7px;padding:12px 16px;background:var(--soft);
              border-radius:var(--r);font-size:13.5px;font-weight:700;color:var(--brand-ink);text-decoration:none}
  .sc-linkcard{display:flex;align-items:center;gap:12px;padding:14px 16px;border:1px solid var(--line);
               border-radius:var(--r);background:#fff;text-decoration:none;color:var(--ink);box-shadow:var(--shadow-sm)}
  .sc-linkcard:hover{border-color:var(--brand)}
  @media (max-width:560px){ .sc-photos{grid-template-columns:repeat(auto-fill,minmax(min(150px,100%),1fr))} }
  @media (max-width:620px){
    .tgroups{gap:16px}
    .ptiles{grid-template-columns:repeat(2,1fr);grid-auto-rows:1fr;gap:8px}
    .ptile{flex-direction:column;align-items:flex-start;gap:8px;padding:11px 11px 12px;border-radius:12px}
    .ptile-ic{width:30px;height:30px;border-radius:9px}
    .ptile-ic svg{width:16px;height:16px}
    .ptile-t{font-size:12.5px}
    /* Two lines is the ceiling on either device — a third makes the row grow
       and the grid ragged again. */
    .ptile-t{-webkit-line-clamp:2;/*title-phone*/}
    .ptile-d{font-size:11px;min-height:calc(1.35em * 2)}
    .ptile.soon .ptile-b{padding-right:0}
    .ptile-soon{top:7px;right:7px}
    .tgroup-h{margin-bottom:9px}
  }
  /* ---- Persistent property bar: the only two things that never scroll away ---- */
  body.has-pbar{padding-bottom:82px}
  .pbar{position:fixed;left:50%;transform:translateX(-50%) translateY(140%);bottom:16px;z-index:60;
        display:flex;gap:8px;padding:7px;border-radius:999px;background:rgba(255,255,255,.92);
        backdrop-filter:blur(14px);border:1px solid var(--line);box-shadow:0 18px 44px -16px rgba(12,20,14,.34);
        transition:transform .26s cubic-bezier(.2,.8,.3,1);max-width:calc(100vw - 24px)}
  .pbar.on{transform:translateX(-50%) translateY(0)}
  /* Secondary weight: leaving is always available but should not compete
     with the action that takes you deeper. */
  .pbar-btn.more span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}
  .pbar-btn.more{min-width:0;flex:1 1 auto;justify-content:center}
  .pbar-btn.ghost{background:transparent;color:var(--body);border:1px solid var(--line)}
  .pbar-btn.ghost:hover{border-color:var(--brand);color:var(--brand-ink);background:var(--soft)}
  @media (max-width:430px){
    /* Two buttons on a narrow phone: drop the label on the secondary one,
       keep the arrow, so the primary action never gets squeezed. */
    .pbar-btn.ghost span{display:none}
    .pbar-btn.ghost{padding-left:12px;padding-right:12px}
  }
  .pbar-btn{display:inline-flex;align-items:center;gap:8px;border:0;cursor:pointer;font:inherit;
            padding:11px 18px;border-radius:999px;font-size:13.5px;font-weight:700;white-space:nowrap;
            background:var(--soft);color:var(--ink);transition:filter .14s,transform .1s}
  .pbar-btn svg{width:16px;height:16px;flex:none}
  .pbar-btn.more{background:linear-gradient(180deg,var(--brand-2),var(--brand));color:#04170c}
  .pbar-btn:hover{filter:brightness(1.05)}
  .pbar-btn:active{transform:translateY(1px)}
  @media (max-width:620px){
    body.has-pbar{padding-bottom:74px}
    .pbar{left:10px;right:10px;bottom:10px;transform:translateY(140%);max-width:none;border-radius:16px}
    .pbar.on{transform:translateY(0)}
    .pbar-btn{flex:1;justify-content:center;padding:12px 10px;font-size:12.5px}
    .pbar-btn{flex:1;justify-content:center}
  }

  /* ---- End-of-media invitation ---- */
  .store-cta{display:flex;align-items:center;gap:16px;width:100%;margin:38px 0 6px;padding:20px 22px;
             border:1px solid #cfe6d6;border-radius:var(--r);cursor:pointer;font:inherit;text-align:left;
             background:linear-gradient(115deg,rgba(37,182,87,.10),rgba(37,182,87,.02));
             transition:border-color .16s,transform .12s,box-shadow .2s}
  .store-cta:hover{border-color:var(--brand);transform:translateY(-2px);box-shadow:var(--shadow)}
  .sc-ic{flex:none;width:46px;height:46px;border-radius:13px;display:flex;align-items:center;justify-content:center;
         color:var(--brand-glow);background:linear-gradient(150deg,#0c2a17,#0b0c0b);
         box-shadow:inset 0 0 22px rgba(37,182,87,.32),0 0 0 1px rgba(51,217,106,.3)}
  .sc-ic svg{width:23px;height:23px}
  .sc-tx{flex:1;min-width:0;display:flex;flex-direction:column;gap:3px}
  .sc-tx b{font-family:Fraunces,Georgia,serif;font-size:19px;color:var(--ink);letter-spacing:-.01em}
  .sc-tx span{font-size:13px;color:var(--muted)}
  .sc-go{flex:none;color:var(--brand-ink)}
  .sc-go svg{width:20px;height:20px}
  @media (max-width:620px){
    .store-cta{gap:13px;padding:16px}
    .sc-ic{width:38px;height:38px;border-radius:11px} .sc-ic svg{width:19px;height:19px}
    .sc-tx b{font-size:16px} .sc-tx span{font-size:12px}
  }

  /* ---- Storefront ---- */
  .sf-head{margin:30px 0 26px;padding-bottom:24px;border-bottom:1px solid var(--hair)}
  .sf-sub{font-size:13.5px;color:var(--muted)}
  .sf-tools{display:flex;flex-direction:column;gap:20px}
  .tgroups{margin:24px 0 10px;display:flex;flex-direction:column;gap:20px}
  .tgroup-h{display:flex;align-items:center;gap:11px;margin-bottom:12px}
  .tgroup-h span{font-size:11.5px;font-weight:800;letter-spacing:.14em;text-transform:uppercase;color:var(--muted)}
  .tgroup-h::after{content:"";flex:1;height:1px;background:var(--hair)}
  .tgroup .ptiles{margin:0}
  .sf-tools .ptile{align-items:flex-start}
  .sf-tools .ptile-ic{margin-top:1px}
  .ptile-state{align-self:flex-start;margin-top:6px;font-size:8.5px;font-weight:800;letter-spacing:.06em;
               text-transform:uppercase;color:var(--brand-ink);background:rgba(37,182,87,.13);
               border-radius:999px;padding:3px 8px;white-space:nowrap}
  .ptile-soon{position:absolute;top:8px;right:9px;font-size:8.5px;font-weight:800;letter-spacing:.09em;
              color:var(--muted);background:var(--soft);border-radius:999px;padding:2px 6px}
  .ptile.soon{cursor:pointer}
  .ptile.soon .ptile-b{padding-right:34px}
  .ptile.soon .ptile-ic{filter:grayscale(1);opacity:.75}
  .dl-head{margin:34px 0 26px;padding-bottom:24px;border-bottom:1px solid var(--hair)}
  .dl-nav{display:flex;align-items:center;justify-content:space-between;gap:12px}
  .dl-title{margin-top:26px;display:flex;flex-direction:column;align-items:center;text-align:center;gap:9px}
  .dl-ic{width:52px;height:52px;border-radius:15px;display:flex;align-items:center;justify-content:center;
         color:var(--brand-glow);background:linear-gradient(150deg,#0c2a17,#0b0c0b);
         box-shadow:inset 0 0 26px rgba(37,182,87,.30),0 0 0 1px rgba(51,217,106,.28)}
  .dl-ic svg{width:26px;height:26px}
  .dl-title b{font-family:Fraunces,Georgia,serif;font-size:clamp(24px,3.2vw,30px);color:var(--ink);letter-spacing:-.015em;line-height:1.15}
  /* 52ch forced a 72-character subtitle onto two lines every single time.
     Wide enough for one line on a desktop, still wrapping on a phone. */
  .dl-title>span:last-child{font-size:13.5px;color:var(--muted);max-width:74ch;line-height:1.55}
  .ptiles{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(258px,100%),1fr));
    grid-auto-rows:1fr;gap:10px;margin:26px 0 10px}
  .ptile{position:relative;display:flex;align-items:center;gap:11px;text-align:left;border:1px solid var(--line);border-radius:13px;background:#fff;padding:11px 12px;cursor:pointer;font:inherit;overflow:hidden;box-shadow:var(--shadow-sm);transition:transform .13s,box-shadow .2s,border-color .2s}
  .ptile::before{content:"";position:absolute;inset:0;background:radial-gradient(240px 130px at 100% 0%,rgba(37,182,87,.09),transparent 70%);opacity:0;transition:opacity .2s;pointer-events:none}
  .ptile:hover{transform:translateY(-2px);box-shadow:var(--shadow);border-color:#cfe6d6}
  .ptile:hover::before{opacity:1}
  .ptile-ic{flex:none;width:36px;height:36px;border-radius:10px;display:flex;align-items:center;justify-content:center;color:var(--brand-glow);
    background:linear-gradient(150deg,#12241a,#0b0c0b);border:1px solid rgba(51,217,106,.22);box-shadow:inset 0 0 18px rgba(37,182,87,.15)}
  .ptile-ic svg{width:18px;height:18px}
  .ptile-b{display:flex;flex-direction:column;gap:2px;min-width:0}
  /* TITLE: one line on a computer, at most two on a phone.
     The copy was shortened so it fits naturally — clamping alone would hide
     the word that says what the tile does behind an ellipsis. The clamp is a
     backstop for a future long label, not the mechanism. */
  .ptile-t{font-weight:700;font-size:13px;color:var(--ink);line-height:1.3;
    display:-webkit-box;-webkit-line-clamp:1;-webkit-box-orient:vertical;overflow:hidden}
  /* Reserve two lines whether the copy needs them or not.
     grid-auto-rows:1fr equalises tiles WITHIN a grid, but each tool group is
     its own grid — so Essential tools came out 106px (one description wraps)
     and Productivity tools 91px (none do). Clamping the description to a
     fixed two lines makes every tile the same height in every group, and
     stops a future long label silently changing a whole row. */
  .ptile-d{font-size:11.5px;color:var(--muted);line-height:1.35;
    min-height:calc(1.35em * 2);display:-webkit-box;-webkit-line-clamp:2;
    -webkit-box-orient:vertical;overflow:hidden}
  /* The primary tile. Emphasis comes from the SURFACE — a tinted ground, a
     stronger border and the dark brand icon — not from recolouring the body
     text. Green description copy made this one tile read as a different KIND
     of thing rather than a more important one, and it was the only place in
     the grid where a description was not muted grey.
     Titles and descriptions stay identical to every other tile, so the eye
     compares like with like. */
  .ptile.lit{border-color:#bfe6cd;background:linear-gradient(180deg,rgba(37,182,87,.07),rgba(37,182,87,.03))}
  .ptile.lit:hover{border-color:var(--brand);background:linear-gradient(180deg,rgba(37,182,87,.12),rgba(37,182,87,.05))}
  .ptile.lit .ptile-ic{background:linear-gradient(150deg,#0c2a17,#0b0c0b);box-shadow:inset 0 0 22px rgba(37,182,87,.32),0 0 0 1px rgba(51,217,106,.3)}
  .ptile.lit .ptile-t{color:var(--ink)}
  .ptile.soon{opacity:.72}

  /* Placed after .lit deliberately: a tile can be BOTH lit and owing, and
     when it is, owing must win — money owed outranks 'this one is ready'.
     Do not move this above .lit. */
  .ptile.owing{border-color:rgba(217,146,19,.45);background:rgba(217,146,19,.06)}
  .ptile.owing .ptile-ic{background:rgba(217,146,19,.16);color:#a9791c}
  .ptile.owing .ptile-t{color:#8c6413}
  .ptile.owing:hover{border-color:rgba(217,146,19,.7);background:rgba(217,146,19,.1)}
  .ptile.owing.lit .ptile-ic{background:rgba(217,146,19,.16);
    box-shadow:none;color:#a9791c}
  .ptile.owing .ptile-d{color:#8c6413;font-weight:600}
  /* compact media */
  .grid.ph-grid{grid-template-columns:repeat(auto-fill,minmax(min(150px,100%),1fr));gap:12px}
  .grid.ph-grid .ph-name{display:none}
  /* invoice viewer actions */
  .lbf-inv{display:none;background:rgba(255,255,255,.14);border:0;color:#fff;font:inherit;font-size:13px;font-weight:600;padding:6px 12px;border-radius:8px;cursor:pointer}
  .lbf-inv:hover{background:rgba(255,255,255,.26)}
  #lbf.invoice .lbf-inv{display:inline-flex;align-items:center}
  #lbf.invoice #lbfOpen{display:none}
  /* ---- Back controls ------------------------------------------------------
     These were 13.5px grey text with no border — indistinguishable from a
     caption. Agents could not find them, so they reached for the browser Back
     button, which used to leave the portal and end the session. Making the
     way OUT of a screen as visible as the ways deeper into it is the fix; the
     history handling is the safety net, not the solution. */
  .crumb{background:#fff;border:1px solid var(--line);border-radius:99px;
    color:var(--ink);font:inherit;font-size:13px;font-weight:700;cursor:pointer;
    padding:8px 15px 8px 12px;margin:0 0 16px;display:inline-flex;align-items:center;gap:6px;
    box-shadow:var(--shadow-sm);transition:border-color .14s,background .14s,transform .08s}
  .crumb:hover{color:var(--brand-ink);border-color:var(--brand);background:var(--soft)}
  .crumb:active{transform:translateY(1px)}

  /* The in-view back buttons (‹ Back, ‹ Back to your media) get the same
     weight, so every screen has one obvious way out in the same place. */
  .pc-btn.back-sc,.pc-btn.back-op,.pc-btn.back-sf{
    font-weight:750;border-color:var(--line);background:#fff;
    box-shadow:var(--shadow-sm);padding-left:11px}
  .pc-btn.back-sc:hover,.pc-btn.back-op:hover,.pc-btn.back-sf:hover{
    border-color:var(--brand);background:var(--soft);color:var(--brand-ink)}

  /* ---------- Slide-in panel ---------- */
  #panel{position:fixed;inset:0;z-index:70;background:rgba(6,10,7,.5);display:none;align-items:stretch;justify-content:flex-end}
  #panel.on{display:flex}
  #panel .panel-box{width:min(460px,96vw);background:#fff;height:100%;display:flex;flex-direction:column;box-shadow:-30px 0 80px rgba(0,0,0,.3);animation:slideIn .24s ease}
  @keyframes slideIn{from{transform:translateX(34px);opacity:.5}to{transform:none;opacity:1}}
  #panel .panel-bar{display:flex;align-items:center;justify-content:space-between;padding:18px 22px;border-bottom:1px solid var(--line)}
  #panel .panel-bar span{font-family:Fraunces,serif;font-size:19px;font-weight:700;color:var(--ink)}
  #panel .panel-bar button{background:none;border:0;font-size:18px;cursor:pointer;color:var(--muted)}
  #panel .panel-body{padding:22px;overflow:auto}
  .soon-wrap{text-align:center;padding:26px 6px}
  .soon-badge{display:inline-block;font-size:11px;font-weight:800;letter-spacing:.1em;text-transform:uppercase;color:var(--brand-ink);background:rgba(37,182,87,.12);padding:6px 14px;border-radius:999px;margin-bottom:16px}
  .soon-wrap p{color:var(--body);line-height:1.6;font-size:15px}
  .connect-lead{color:var(--body);line-height:1.55;font-size:14.5px;margin:0 0 16px}
  .connect-ctx{font-size:13px;color:var(--muted);background:var(--soft);border:1px solid var(--line);padding:9px 12px;border-radius:10px;margin-bottom:14px}
  .connect-wrap textarea{width:100%;padding:13px 14px;border:1px solid var(--line);border-radius:12px;font:inherit;font-size:14.5px;resize:vertical;margin-bottom:14px;box-sizing:border-box}
  .connect-wrap .btn-primary{width:100%}
  .connect-note{margin-top:14px;font-size:12.5px;color:var(--muted);background:var(--soft);border-radius:10px;padding:11px 13px;line-height:1.45}

  @media (max-width:560px){
    .container{padding:22px 16px 60px}
    .topbar{padding:12px 16px}
    .cards{grid-template-columns:1fr}
    .welcome{flex-direction:column;align-items:flex-start}
    .home-grid{grid-template-columns:1fr}
  }

/* ---- Printing the fact sheet ------------------------------------------
   The panel is a slide-over on top of the app. For print we drop everything
   behind it, let the sheet flow down the page, and stop cards splitting
   across a page break. */
@media print{
  body.printing-fs > *:not(#panel){display:none !important}
  body.printing-fs #panel{position:static;display:block;background:none;inset:auto}
  body.printing-fs #panel .panel-box{width:100%;height:auto;box-shadow:none;animation:none}
  body.printing-fs #panel .panel-bar{border-bottom:1px solid #ddd}
  body.printing-fs #panel .panel-bar button{display:none}
  body.printing-fs #panel .panel-body{overflow:visible;padding:0}
  body.printing-fs .fs-actions{display:none !important}
  body.printing-fs .fs-hero{min-height:0;border-radius:0}
  body.printing-fs .fs-hero.has-shot .fs-shot{opacity:.3}
  body.printing-fs .fs-sec{break-inside:auto;page-break-inside:auto}
  body.printing-fs .fs-card,
  body.printing-fs .fs-comp,
  body.printing-fs .fs-spec{break-inside:avoid;page-break-inside:avoid}
  body.printing-fs .fs-sh{break-after:avoid;page-break-after:avoid}
  body.printing-fs .fs-grid{grid-template-columns:repeat(2,1fr)}
  @page{margin:14mm}
}

  /* ---- Main page: account chip + tools strip -----------------------------
     The home hub was merged into this page on 2026-08-22. Listings come
     first because they are the daily job; the account tools sit below because
     they are needed a few times a year. Putting the tools on top would have
     pushed the actual work below the fold. */
  .chero-r{flex:none;display:flex;align-items:center;gap:10px;flex-wrap:wrap;justify-content:flex-end}
  .chero-acct{display:inline-flex;align-items:center;gap:7px;padding:8px 12px;border-radius:999px;
    border:1px solid rgba(255,255,255,.22);background:rgba(255,255,255,.08);
    color:rgba(232,237,233,.72);font-size:12.5px;font-weight:650;cursor:default;user-select:none}
  .chero-acct-soon{font-size:9.5px;font-weight:800;letter-spacing:.1em;text-transform:uppercase;
    padding:2px 6px;border-radius:99px;background:rgba(255,255,255,.14);color:rgba(232,237,233,.8)}

  .mtools{display:grid;gap:10px;grid-template-columns:repeat(auto-fill,minmax(min(220px,100%),1fr));
    grid-auto-rows:1fr;margin:0 0 8px}
  .mtool{display:flex;align-items:center;gap:11px;text-align:left;padding:13px 14px;
    border:1px solid var(--line);border-radius:13px;background:#fff;font:inherit;
    box-shadow:var(--shadow-sm);position:relative}
  button.mtool{cursor:pointer;transition:border-color .16s,background .16s,transform .08s}
  button.mtool:hover{border-color:var(--brand);background:var(--soft)}
  button.mtool:active{transform:translateY(1px)}
  /* Inert by design: rendered as a div, not a button, so it cannot be clicked,
     focused or tabbed to. Dimmed and labelled rather than silently dead. */
  .mtool.soon{opacity:.55;cursor:default}
  .mtool-ic{flex:none;width:34px;height:34px;border-radius:10px;display:flex;align-items:center;
    justify-content:center;background:var(--soft);color:var(--brand-ink)}
  .mtool-ic svg{width:17px;height:17px}
  .mtool-b{display:flex;flex-direction:column;gap:2px;min-width:0}
  .mtool-t{font-size:13.5px;font-weight:700;color:var(--ink)}
  .mtool-d{font-size:11.5px;color:var(--muted);line-height:1.35}
  .mtool-soon{position:absolute;top:9px;right:10px;font-size:9px;font-weight:800;
    letter-spacing:.1em;text-transform:uppercase;color:var(--muted);
    background:var(--soft);border-radius:99px;padding:2px 7px}
  @media (max-width:760px){ .mtools{grid-template-columns:repeat(2,minmax(0,1fr));gap:8px} }

/* ============================================================================
   Chip artwork, 2026-08-22
   ---------------------------------------------------------------------------
   Listing tools chips carry a round photo instead of a line icon. This is a
   photography company: an icon set next to real work reads as a stock
   template. The photo is the listing's own, so the toolbox looks different for
   every property, and a white veil plus reduced saturation keeps it quiet
   enough that the label still reads first.

   The chip itself stays a rectangle. Only the artwork is round.
   ========================================================================== */
  .ptile-av{flex:none;width:42px;height:42px;border-radius:50%;overflow:hidden;position:relative;
    background:#eef3ef center/cover no-repeat;
    box-shadow:0 0 0 1px rgba(11,26,17,.07), 0 1px 3px rgba(11,26,17,.1);
    filter:saturate(.82)}
  /* The veil is a separate layer so it does not wash out the ring. */
  .ptile-av::after{content:"";position:absolute;inset:0;border-radius:50%;
    background:linear-gradient(150deg,rgba(255,255,255,.34),rgba(255,255,255,.1) 55%,rgba(11,26,17,.06))}
  /* No photos yet — delivered empty, or every item hibernated. */
  .ptile-av.blank{background:radial-gradient(120% 120% at 30% 20%,#f2f8f3,#dfeae2)}
  .ptile:hover .ptile-av{filter:saturate(1)}
  .ptile.lit .ptile-av{box-shadow:0 0 0 2px rgba(37,182,87,.55), 0 1px 4px rgba(11,26,17,.14)}
  .ptile.owing .ptile-av{box-shadow:0 0 0 2px rgba(217,146,19,.6), 0 1px 4px rgba(11,26,17,.14)}
  .ptile.soon .ptile-av{filter:grayscale(1) saturate(0) brightness(1.04);opacity:.7}
  .ptile.soon:hover .ptile-av{filter:grayscale(1) saturate(0) brightness(1.04)}

  /* Group sub-line: the heading says what the group is, this says why. */
  .tgroup-h small{display:block;margin-top:3px;font-size:11.5px;font-weight:500;
    color:var(--muted);letter-spacing:0;text-transform:none}

  /* "Need something else on this shoot?" — a band, not a fourth product card.
     Booking us is a different kind of act from the self-serve tools above it. */
  .addband{display:flex;align-items:center;justify-content:space-between;gap:14px;width:100%;
    margin-top:14px;padding:15px 17px;text-align:left;font:inherit;cursor:pointer;
    border:1px dashed var(--line);border-radius:14px;background:var(--soft);
    transition:border-color .16s,background .16s}
  .addband:hover{border-color:var(--brand);background:#fff}
  .ab-tx{display:flex;flex-direction:column;gap:3px;min-width:0}
  .ab-tx b{font-size:13.5px;color:var(--ink)}
  .ab-tx span{font-size:12px;color:var(--muted);line-height:1.4}
  .ab-go{flex:none;display:inline-flex;align-items:center;gap:6px;font-size:12.5px;font-weight:700;color:var(--brand-ink)}
  .ab-go svg{width:14px;height:14px}
  @media (max-width:760px){
    .addband{flex-direction:column;align-items:flex-start;gap:9px;padding:13px 14px}
    .ptile-av{width:34px;height:34px}
  }

/* ============================================================================
   One line on a computer, two at the very most anywhere, 2026-08-22
   ---------------------------------------------------------------------------
   Applies to EVERY chip in the portal, not just the listing tools. A chip that
   grows to three lines breaks the grid row it sits in and pushes its
   neighbours out of alignment, which is what made the tool pages look untidy.

   Clamping alone is not the fix — an ellipsis hides the word that says what
   the chip does. The copy has to be short enough to fit; the clamp is the
   backstop for the cases we did not foresee.
   ========================================================================== */
  .mtool-t, .pr-n, .fs-card-t, .prod .pr-n{
    display:-webkit-box;-webkit-line-clamp:1;-webkit-box-orient:vertical;overflow:hidden}
  .mtool-d, .pr-d, .fs-card-d{
    display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
  @media (max-width:760px){
    .mtool-t, .pr-n, .fs-card-t{-webkit-line-clamp:2}
  }

  /* Unbuilt products read as unbuilt: the photo goes flat, the card sits back.
     Same treatment as a soon chip, so "not yet" looks the same everywhere. */
  .prod.soon{opacity:.78}
  .prod.soon .pr-bg{filter:grayscale(1) brightness(1.05)}
  .prod.soon:hover{transform:none;box-shadow:var(--shadow-sm);border-color:var(--line)}
  .prod.soon .pr-tag{background:rgba(11,26,17,.55);color:#fff}

  /* Account chip, topbar. Quiet by design — it sits among the account
     controls, not among the things we want clicked. Dark bar, so it is
     outlined rather than filled. */
  .tb-acct{display:inline-flex;align-items:center;gap:7px;padding:6px 11px;border-radius:999px;
    border:1px solid rgba(255,255,255,.16);background:rgba(255,255,255,.05);
    color:#c8d1c9;font-size:12.5px;font-weight:600;cursor:default;user-select:none}
  .tb-acct svg{width:14px;height:14px;flex:none}
  .tb-acct-soon{font-size:9px;font-weight:800;letter-spacing:.09em;text-transform:uppercase;
    color:#7f8b81;background:rgba(255,255,255,.08);border-radius:5px;padding:1px 5px}
  /* On a phone the topbar has room for the greeting and one control only. */
  @media (max-width:700px){ .tb-acct{display:none} }

  /* The one pill on the page that is an offer rather than a status. Amber, so
     it does not read as "already yours" the way the green Active pill does. */
  .pr-tag.buy{background:linear-gradient(180deg,#f2ac2a,#dd9412);color:#231602;
    box-shadow:0 2px 10px rgba(217,146,19,.4)}

  /* The veil existed to tame busy listing photos. The fixed art is already
     calm, so the veil only drained it — it goes, and the ring stays. */
  .ptile-av::after{display:none}
  .ptile-av{filter:none}
  .ptile:hover .ptile-av{filter:none}

  /* Account chips, main page. Same round artwork as the listing tools — these
     were the last icons in the portal, and the two pages read as one product
     only when the chip on both looks the same. */
  .mtool-av{flex:none;width:38px;height:38px;border-radius:50%;
    background:#eef3ef center/cover no-repeat;
    box-shadow:0 0 0 1px rgba(11,26,17,.07), 0 1px 3px rgba(11,26,17,.1)}
  .mtool.soon .mtool-av{filter:grayscale(1) brightness(1.04);opacity:.7}
  @media (max-width:760px){ .mtool-av{width:32px;height:32px} }

/* ============================================================================
   The floating listing bar, 2026-08-22
   ---------------------------------------------------------------------------
   The two buttons were measuring 77x68 and 140x102 — different widths AND
   different heights, in a bar 118px tall that should have been 56. The bar is
   a flex row with no align-items, so the items were stretching to a line box
   nothing had asked for, and the ghost button carried a 1px border the filled
   one did not, so the two could never line up even once stretched.

   Fixed geometry instead of inferred: both buttons are the same height, the
   same width, and the same shape. Colour is then the ONLY thing that differs
   between them, which is what makes it read as a decision — filled is the way
   forward, outlined is the way back.
   ========================================================================== */
  .pbar{align-items:center}
  .pbar-btn{height:44px;min-width:152px;padding:0 18px;box-sizing:border-box;
    border:1px solid transparent;line-height:1;justify-content:center;flex:0 0 auto}
  .pbar-btn.more{flex:0 0 auto;min-width:152px}
  .pbar-btn.ghost{border-color:var(--line)}
  .pbar-btn svg{width:16px;height:16px;flex:none}
  @media (max-width:620px){
    /* One row, split evenly — equal halves rather than a wide one and a stub. */
    .pbar-btn{flex:1 1 0;min-width:0;height:46px;padding:0 12px;font-size:12.5px}
    .pbar-btn.more{flex:1 1 0;min-width:0}
  }

  /* Sized to the portal's other buttons (.btn-mini / .pc-btn are 12.5px type
     in a ~36px control). At 44px and 13.5px this bar was reading as a
     different design system floating over the page. */
  .pbar{padding:6px}
  .pbar-btn{height:36px;min-width:130px;padding:0 16px;font-size:12.5px}
  .pbar-btn.more{min-width:130px}
  .pbar-btn svg{width:14px;height:14px}
  @media (max-width:620px){ .pbar-btn{height:40px;font-size:12.5px} }

  /* Now a real button. It still reads as not-yet-available, but it responds to
     the press — the panel behind it says what is coming and when. */
  .mtool.soon{cursor:pointer}
  .mtool.soon:hover{border-color:var(--line);background:var(--soft);opacity:.72}

  /* The unit next to the number. Lighter and slightly smaller than the count,
     so the row still scans as figures first, words second. */
  .pc-f i{font-style:normal;font-weight:500;color:var(--muted);font-size:.92em}

  /* A listing with no usable thumbnail — media still hibernating, or delivered
     without stills — was rendering as a near-black panel beside two bright
     photographs. It read as a broken image, not as an empty one. Light wash
     from the same family as the tool artwork: clearly a placeholder, clearly
     not an error. */
  .pcard.compact .pc-thumb:not(.hasimg){
    background:linear-gradient(150deg,#f2f6f3 0%,#dde8e1 55%,#cddbd3 100%)}
  .pcard.compact .pc-thumb:not(.hasimg) svg{color:#8aa294;opacity:.8}

  /* Account stays visible top-right on a phone — icon-only, so it does not
     crowd the greeting. It was display:none under 700px, which read as the
     control not existing at all. */
  @media (max-width:700px){
    .tb-acct{display:inline-flex;padding:6px 8px}
    .tb-acct > span:not(.tb-acct-soon){display:none}
    .tb-acct-soon{display:none}
  }

  /* Phone tool chips, two-up: the photo circle rides the top-left with the
     SOON badge clear of it, and titles hold to the two-line ceiling. */
  @media (max-width:760px){
    .ptile-av{width:38px;height:38px}
    .ptile{min-height:118px}
    .ptile-t{line-height:1.25}
  }

  /* Two-up tool chips on a phone — RE-DECLARED HERE deliberately. The base
     .ptiles rule (auto-fill, 258px minimum) sits later in this file than the
     original 760px override, so at 390px the minimum won and the grid
     collapsed to one column. Source order is the tiebreak at equal
     specificity, so the phone rule must come last. */
  @media (max-width:760px){
    .ptiles{grid-template-columns:repeat(2,minmax(0,1fr))}
    /* Same source-order trap as the grid above: the desktop one-line title
       clamp sits later in the file than the original phone override, so
       phones were clamping to ONE line and cutting every longer title. Two
       lines is the phone ceiling — declared here, last, so it finally wins. */
    .ptile-t{-webkit-line-clamp:2}
  }

  /* Lightbox paging. Arrows sit at the edges where thumbs already rest on a
     phone; the counter keeps the agent oriented inside a 46-photo set. */
  .lb-nav{position:absolute;top:50%;transform:translateY(-50%);z-index:2;
    width:46px;height:64px;border:0;border-radius:12px;cursor:pointer;
    background:rgba(255,255,255,.1);color:#fff;font-size:34px;line-height:1;
    display:flex;align-items:center;justify-content:center;
    transition:background .15s}
  .lb-nav:hover{background:rgba(255,255,255,.22)}
  #lbPrev{left:10px} #lbNext{right:10px}
  #lbCount{position:absolute;bottom:14px;left:50%;transform:translateX(-50%);
    color:#fff;font-size:12.5px;font-weight:600;letter-spacing:.06em;
    background:rgba(0,0,0,.45);border-radius:999px;padding:5px 13px;
    font-variant-numeric:tabular-nums}
  #lb img{cursor:pointer}
  @media (max-width:760px){ .lb-nav{width:38px;height:56px;font-size:28px} }

/* ============================================================================
   Owner console — spend, tools, health
   ---------------------------------------------------------------------------
   Administrator-facing, so restraint over decoration: this has to look
   professional enough to show a buyer, and legible enough to scan daily.
   ========================================================================== */
  .mspend{margin:0 0 34px}
  .sp-head{display:flex;align-items:baseline;gap:12px;border-bottom:1px solid var(--line);
    padding-bottom:10px;margin-bottom:16px;flex-wrap:wrap}
  .sp-t{font-size:12px;font-weight:800;letter-spacing:.1em;text-transform:uppercase;color:var(--muted)}
  .sp-sub{font-size:12.5px;color:var(--muted);flex:1;min-width:0}
  .sp-cards{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(190px,100%),1fr));gap:12px;margin-bottom:22px}
  .sp-card{border:1px solid var(--line);border-radius:12px;padding:15px 17px;background:#fff;
    display:flex;flex-direction:column;gap:3px}
  .sp-card.big{background:linear-gradient(180deg,rgba(37,182,87,.07),rgba(37,182,87,.02));border-color:#bfe6cd}
  .sp-k{font-size:10.5px;font-weight:800;letter-spacing:.09em;text-transform:uppercase;color:var(--muted)}
  .sp-v{font-family:Fraunces,Georgia,serif;font-size:26px;font-weight:600;color:var(--ink);
    letter-spacing:-.015em;font-variant-numeric:tabular-nums;line-height:1.15}
  .sp-n{font-size:11.5px;color:var(--muted)}
  .sp-bar{display:block;height:5px;border-radius:99px;background:var(--soft);margin-top:7px;overflow:hidden}
  .sp-bar i{display:block;height:100%;width:0;background:var(--brand);border-radius:99px;transition:width .4s}
  .sp-bar i.hot{background:#d99213}
  .sp-cols{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(290px,100%),1fr));gap:24px}
  .sp-h{font-size:10.5px;font-weight:800;letter-spacing:.09em;text-transform:uppercase;color:var(--muted);margin:0 0 8px}
  .sp-rows{display:flex;flex-direction:column;gap:1px}
  .sp-row{display:flex;align-items:center;gap:10px;padding:7px 10px;border-radius:7px;font-size:13px}
  .sp-row:nth-child(odd){background:var(--soft)}
  .sp-row.free .sp-u{color:var(--muted);font-weight:600}
  .sp-l{flex:1;min-width:0;color:var(--ink);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  .sp-c{color:var(--muted);font-size:11.5px;font-variant-numeric:tabular-nums}
  .sp-u{font-weight:700;color:var(--ink);font-variant-numeric:tabular-nums;min-width:62px;text-align:right}

  /* Tool cards. Colour carries one meaning only: does this need me today. */
  .mtools-x{margin:0 0 34px}
  .tk-open{display:flex;align-items:baseline;gap:7px;font-size:12.5px;color:#8c6413;
    background:rgba(217,146,19,.09);border:1px solid rgba(217,146,19,.3);
    border-radius:9px;padding:9px 13px;margin-bottom:14px}
  .tk-open b{font-weight:700}
  .tk-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(300px,100%),1fr));gap:12px}
  .tk{border:1px solid var(--line);border-left:3px solid var(--line);border-radius:11px;
    background:#fff;padding:14px 16px;display:flex;flex-direction:column;gap:7px}
  .tk.ok{border-left-color:var(--brand)}
  .tk.warn{border-left-color:#d99213}
  .tk.idle{border-left-color:#c8cfc9}
  .tk.bad{border-left-color:#c0392b;background:rgba(192,57,43,.02)}
  .tk-top{display:flex;align-items:baseline;justify-content:space-between;gap:10px}
  .tk-n{font-size:14px;color:var(--ink)}
  .tk-s{flex:none;font-size:9.5px;font-weight:800;letter-spacing:.08em;text-transform:uppercase;
    color:var(--muted);background:var(--soft);border-radius:5px;padding:3px 7px}
  .tk.ok .tk-s{color:var(--brand-ink);background:rgba(37,182,87,.12)}
  .tk.bad .tk-s{color:#c0392b;background:rgba(192,57,43,.1)}
  .tk-b{margin:0;font-size:12.5px;line-height:1.45;color:var(--muted)}
  .tk-c{font-size:11.5px;color:var(--ink);font-weight:600}
  .tk-iss{display:flex;flex-direction:column;gap:5px}
  .tk-i{font-size:11.5px;line-height:1.4;padding:6px 9px;border-radius:7px;
    background:rgba(217,146,19,.1);color:#8c6413}
  .tk-i.security,.tk-i.bug{background:rgba(192,57,43,.09);color:#a3271b}
  .tk-acts{display:flex;gap:7px;margin-top:auto;padding-top:4px}
  .tk-global{margin-top:20px;display:flex;flex-direction:column;gap:5px}

  /* Documentation panel */
  .td-bar{display:flex;align-items:center;justify-content:space-between;gap:12px;
    border-bottom:1px solid var(--line);padding-bottom:10px;margin-bottom:14px}
  .td-when{font-size:11.5px;color:var(--muted)}
  .td-md{margin:0;white-space:pre-wrap;font:12.5px/1.6 ui-monospace,"Cascadia Code",Consolas,monospace;
    color:var(--ink);max-height:62vh;overflow:auto;background:var(--soft);
    border-radius:9px;padding:15px 17px}

  /* Flow: boxes and arrows, deliberately. */
  .flow{display:flex;flex-direction:column;align-items:stretch;gap:0}
  .fl-box{position:relative;border:1px solid var(--line);border-radius:10px;background:#fff;
    padding:12px 15px 12px 44px;display:flex;flex-direction:column;gap:2px}
  .fl-box b{font-size:13.5px;color:var(--ink)}
  .fl-box span:last-child{font-size:12px;color:var(--muted);line-height:1.4}
  .fl-n{position:absolute;left:13px;top:13px;width:21px;height:21px;border-radius:50%;
    background:var(--soft);color:var(--brand-ink);font-size:11px;font-weight:800;
    display:flex;align-items:center;justify-content:center}
  .fl-arrow{text-align:center;color:var(--muted);font-size:15px;line-height:1;padding:5px 0}

  /* System map: integrations on the left, what they feed on the right. */
  .mp-lead{margin:0 0 16px;font-size:12.5px;color:var(--muted)}
  .mp{display:flex;flex-direction:column;gap:9px}
  .mp-row{display:flex;align-items:center;gap:11px}
  .mp-int{flex:none;width:172px;border:1px solid var(--line);border-radius:9px;padding:9px 12px;
    display:flex;flex-direction:column;gap:1px;background:#fff}
  .mp-int.paid{border-color:rgba(217,146,19,.45);background:rgba(217,146,19,.05)}
  .mp-int b{font-size:12.5px;color:var(--ink)}
  .mp-int span{font-size:10.5px;color:var(--muted)}
  .mp-arrow{flex:none;color:var(--muted);font-size:15px}
  .mp-tools{display:flex;flex-wrap:wrap;gap:6px;flex:1;min-width:0}
  .mp-tool{font-size:11.5px;border:1px solid var(--line);border-radius:99px;padding:4px 11px;
    color:var(--muted);background:var(--soft)}
  .mp-tool.on{color:var(--brand-ink);border-color:#bfe6cd;background:rgba(37,182,87,.09)}
  @media (max-width:620px){
    .mp-row{flex-direction:column;align-items:stretch;gap:5px}
    .mp-int{width:auto} .mp-arrow{display:none}
  }

  /* Field provenance. The owner needs to know at a glance whether a number
     came from his integrations or from the agent — one is verifiable, the
     other is a claim. Quiet by default; a prefilled field says so plainly
     because it has NOT been saved yet. */
  .sd-src{display:block;font-style:normal;font-size:10.5px;line-height:1.35;margin-top:3px;color:var(--muted)}
  .sd-src.agent{color:var(--muted)}
  .sd-src.county{color:var(--brand-ink);font-weight:600}
  .sd-in input.from-county,input.from-county{background:rgba(37,182,87,.06);border-color:#bfe6cd}

  /* Quotas and free tiers. A limit you cannot see is a limit you hit. */
  .qt-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(250px,100%),1fr));gap:10px}
  .qt{border:1px solid var(--line);border-radius:10px;padding:12px 14px;background:#fff;
    display:flex;flex-direction:column;gap:6px}
  .qt.hot{border-color:rgba(217,146,19,.5);background:rgba(217,146,19,.04)}
  .qt-top{display:flex;align-items:baseline;justify-content:space-between;gap:8px}
  .qt-top b{font-size:13px;color:var(--ink)}
  .qt-tier{font-size:10px;font-weight:700;letter-spacing:.05em;text-transform:uppercase;
    color:var(--muted);background:var(--soft);border-radius:4px;padding:2px 6px;white-space:nowrap}
  .qt-n{font-size:12px;color:var(--muted);font-variant-numeric:tabular-nums}
  .qt-n b{color:var(--ink);font-weight:700}
  .qt-n em{font-style:normal;font-weight:700;color:var(--ink)}
  .qt.hot .qt-n em{color:#8c6413}
  .qt-note{margin:0;font-size:11px;line-height:1.4;color:var(--muted)}
  .qt-go{align-self:flex-start;margin-top:2px}

/* Not-started tools on the console board. Deliberately quieter than the
   open-items banner: roadmap should be visible without competing with debt. */
.tk-ideas{display:flex;align-items:baseline;gap:6px;margin:6px 0 14px;
  font-size:13px;color:var(--muted)}
.tk-ideas b{color:var(--ink);font-weight:600}
/* The closed-portal screen: a dead end with no phone number loses the agent
   who found us early, so the contacts are the point of the page. */
.closed-wrap{min-height:70vh;display:grid;place-items:center;padding:40px 20px}
.closed-card{max-width:480px;text-align:center}
.closed-mark{font-weight:700;letter-spacing:.04em;color:var(--green);margin-bottom:18px}
.closed-card h1{font-size:26px;margin:0 0 12px}
.closed-card p{color:var(--muted);line-height:1.6;margin:0 0 22px}
.closed-contacts{display:flex;flex-direction:column;gap:8px;align-items:center}
.closed-contacts a{color:var(--ink);font-weight:600;text-decoration:none}
.closed-contacts a:hover{text-decoration:underline}

  /* The roadmap list. Quieter than a tool card in every dimension — no border,
     no status chip, no actions — because the difference between "this runs and
     costs money" and "this is an idea" should be visible before you read a
     word of it. */
  .tk-board{margin-top:26px}
  .tb-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(250px,100%),1fr));
    gap:2px 20px}
  .tb{display:flex;flex-direction:column;gap:1px;padding:8px 11px;border-radius:7px}
  .tb:hover{background:var(--soft)}
  .tb-n{font-size:12.5px;font-weight:600;color:var(--ink)}
  .tb-b{font-size:11.5px;line-height:1.4;color:var(--muted)}

  /* Column headings for the spend tables. Small and quiet — they exist to be
     read once, when you first wonder what a number means. */
  .sp-row.sp-hd{background:none;padding-bottom:3px;border-bottom:1px solid var(--line);
    border-radius:0;font-size:10.5px;font-weight:800;letter-spacing:.07em;
    text-transform:uppercase;color:var(--muted)}
  .sp-row.sp-hd .sp-l,.sp-row.sp-hd .sp-c,.sp-row.sp-hd .sp-u{color:var(--muted);font-weight:800}
  .sp-row.sp-hd + .sp-rows .sp-row:nth-child(odd){background:var(--soft)}
  /* An unpriced integration is an open question, not a free one. */
  .sp-row.unpriced .sp-u{color:#8c6413;font-weight:700;font-size:11.5px}
  .sp-row.free .sp-u{color:var(--muted);font-weight:600;font-size:11.5px}
  .sp-row.sp-tot{border-top:1px solid var(--line);border-radius:0;font-weight:700}
  .sp-row.sp-tot .sp-l{font-weight:700}
  .sp-note{font-size:11.5px;line-height:1.45;color:var(--muted);margin:0 0 10px;max-width:70ch}
  .sp-geo{margin-top:4px}

  /* Access switches. The master state is the loudest thing on the screen —
     "is my portal open to the world" should never need to be worked out. */
  .mswitch{margin:0 0 34px}
  .ms-master{display:flex;align-items:center;gap:16px;flex-wrap:wrap;
    border:1px solid var(--line);border-left:3px solid var(--line);
    border-radius:11px;padding:14px 16px;background:#fff;margin-bottom:18px}
  .ms-master.live{border-left-color:var(--brand);background:rgba(37,182,87,.04)}
  .ms-master.closed{border-left-color:#d99213;background:rgba(217,146,19,.05)}
  .ms-m-b{flex:1;min-width:240px;display:flex;flex-direction:column;gap:3px}
  .ms-m-b b{font-size:14px;color:var(--ink)}
  .ms-m-b span{font-size:12.5px;line-height:1.45;color:var(--muted)}
  .ms-tools{display:flex;flex-direction:column;gap:1px}
  .ms-row{display:flex;align-items:center;gap:12px;padding:8px 11px;border-radius:7px;font-size:13px}
  .ms-row:nth-child(odd){background:var(--soft)}
  .ms-n{flex:1;min-width:0;color:var(--ink)}
  .ms-st{font-size:11.5px;color:var(--muted)}
  .ms-row.off .ms-n{color:var(--muted)}
  .ms-row.off .ms-st{color:#8c6413;font-weight:700}

  /* Idea book. Deliberately the least ceremonious thing in the console: the
     cost of capture has to be near zero or it does not get used. */
  .mideas{margin:0 0 34px}
  .id-new{border:1px solid var(--line);border-radius:11px;background:#fff;padding:12px 13px;margin-bottom:16px}
  .id-new textarea{width:100%;box-sizing:border-box;border:none;outline:none;resize:vertical;
    font:inherit;font-size:14.5px;line-height:1.5;color:var(--ink);background:none;min-height:62px}
  .id-bar{display:flex;align-items:center;gap:9px;flex-wrap:wrap;padding-top:8px;
    border-top:1px solid var(--line)}
  .id-bar .btn-primary{width:auto;padding:0 18px;height:34px;font-size:13px}
  .id-mic.rec{background:#c0392b;border-color:#c0392b;color:#fff;
    animation:idpulse 1.4s ease-in-out infinite}
  @keyframes idpulse{0%,100%{opacity:1}50%{opacity:.62}}
  @media (prefers-reduced-motion:reduce){.id-mic.rec{animation:none}}
  .id-hint{font-size:12px;color:var(--muted);flex:1;min-width:0}
  .id-list{display:flex;flex-direction:column;gap:9px}
  .id-row{border:1px solid var(--line);border-radius:10px;background:#fff;padding:12px 14px}
  .id-head{display:flex;align-items:baseline;gap:10px}
  .id-t{flex:1;min-width:0;font-size:14px;color:var(--ink)}
  .id-when{font-size:11.5px;color:var(--muted);white-space:nowrap}
  .id-x{border:none;background:none;color:var(--muted);font-size:18px;line-height:1;
    cursor:pointer;padding:0 2px}
  .id-x:hover{color:#c0392b}
  .id-s{margin:5px 0 0;font-size:13px;line-height:1.5;color:var(--muted)}
  .id-tags{display:flex;gap:5px;flex-wrap:wrap;margin-top:8px}
  .id-tag{font-size:10.5px;font-weight:700;letter-spacing:.04em;text-transform:uppercase;
    color:var(--muted);background:var(--soft);border-radius:5px;padding:3px 7px}
  .id-raw{margin-top:9px}
  .id-raw summary{font-size:11.5px;color:var(--muted);cursor:pointer}
  .id-raw p{margin:6px 0 0;font-size:12.5px;line-height:1.55;color:var(--muted);
    background:var(--soft);border-radius:8px;padding:10px 12px}

  /* Spend tables. Given room to breathe and a boundary of their own: they are
     the densest thing in the console and were previously pressed straight up
     against the quota cards with a bare heading between. */
  .sp-cols{margin-top:34px;gap:18px;
    grid-template-columns:repeat(auto-fit,minmax(min(330px,100%),1fr))}
  .sp-panel{border:1px solid var(--line);border-radius:11px;background:#fff;
    padding:15px 17px 12px}
  .sp-panel .sp-h{margin:0 0 10px}
  .sp-panel .sp-rows{margin-top:2px}
  /* Numeric columns hold their width so the two tables read as one grid and
     digits line up down the page rather than drifting with the labels. */
  .sp-row .sp-c{min-width:52px;text-align:right}
  .sp-row .sp-u{min-width:74px}

  /* Flow panels: a lead line saying what the tool costs and what it touches,
     then a reason under every step. The steps alone said what happens; the
     reasons say why it is built that way, which is the part that cannot be
     read off the product. */
  .fl-lead{display:flex;flex-direction:column;gap:4px;padding-bottom:12px;
    margin-bottom:16px;border-bottom:1px solid var(--line)}
  .fl-lead b{font-size:13.5px;line-height:1.5;color:var(--ink)}
  .fl-cost{font-size:11.5px;color:var(--muted)}
  .fl-tx{display:flex;flex-direction:column;gap:3px;min-width:0}
  .fl-s{font-size:12.5px;line-height:1.45;color:var(--muted)}
  .fl-d{font-size:12px;line-height:1.55;color:var(--muted);
    border-left:2px solid var(--line);padding-left:10px;margin-top:5px}

  /* Photo quality review */
  .qc-form{display:flex;gap:9px;margin:14px 0 8px;max-width:460px}
  .qc-form input{flex:1;min-width:0;padding:11px 13px;border:1px solid var(--line);
    border-radius:10px;font:inherit;font-size:14px;color:var(--ink);background:#fff}
  .qc-form .btn-primary{width:auto;padding:0 18px;height:auto}
  .qc-force{display:flex;align-items:center;gap:7px;font-size:12.5px;color:var(--muted)}
  .qc-who{font-size:12.5px;color:var(--muted);margin:12px 0 0}
  .sp-row.qc-r .sp-l{color:#a3271b}
  .sp-row.qc-c .sp-l{color:#8c6413}
  .qc-photos{display:flex;flex-direction:column;gap:9px}
  .qc-p{border:1px solid var(--line);border-radius:10px;background:#fff;padding:11px 13px}
  .qc-p b{font-size:13px;color:var(--ink)}
  .qc-pf{display:flex;flex-direction:column;gap:5px;margin-top:7px}

  /* Quota chips: the tier line is a sentence now ("Subscription — $74/month"),
     not a one-word token, so it has to be allowed to wrap instead of running
     out past its own border. */
  .qt-top{flex-wrap:wrap}
  .qt-top b{flex:1;min-width:0}
  .qt-tier{white-space:normal;line-height:1.35;max-width:100%;
    overflow-wrap:anywhere;text-align:right}
  .qt-note{overflow-wrap:anywhere}
  .mp-int b,.mp-int span{overflow-wrap:anywhere}

  /* School data panel */
  .sc-card{border:1px solid var(--line);border-left:3px solid var(--line);
    border-radius:11px;background:#fff;padding:14px 16px;margin-bottom:12px}
  .sc-card.ok{border-left-color:var(--brand)}
  .sc-card.stale{border-left-color:#d99213;background:rgba(217,146,19,.04)}
  .sc-h{display:flex;align-items:baseline;justify-content:space-between;gap:10px;flex-wrap:wrap}
  .sc-h b{font-size:14px;color:var(--ink)}
  .sc-tag{font-size:10px;font-weight:800;letter-spacing:.06em;text-transform:uppercase;
    color:var(--muted);background:var(--soft);border-radius:5px;padding:3px 7px}
  .sc-p{font-size:12.5px;line-height:1.55;color:var(--muted);margin:8px 0 0}
  .sc-where{font-size:12.5px;line-height:1.55;color:var(--muted);margin:8px 0 0}
  .sc-where b{color:var(--ink);font-weight:600}
  .sc-acts{display:flex;gap:7px;flex-wrap:wrap;margin-top:12px}
  .sc-paste{margin-top:12px;border-top:1px solid var(--line);padding-top:12px}
  .sc-json{width:100%;box-sizing:border-box;border:1px solid var(--line);border-radius:9px;
    padding:10px 12px;font:12px/1.5 ui-monospace,"Cascadia Code",Consolas,monospace;
    color:var(--ink);resize:vertical}
  .sc-bar{display:flex;align-items:center;gap:10px;margin-top:9px}
  .sc-bar .btn-primary{width:auto;padding:0 18px;height:34px;font-size:13px}
  .sc-msg{font-size:12px;color:var(--muted)}
  .sc-msg.err{color:#c0392b}
  .sc-rows{display:flex;flex-direction:column;gap:9px}
  .sc-row{border:1px solid var(--line);border-radius:10px;background:#fff;padding:11px 13px}
  .sc-r1{display:flex;align-items:baseline;justify-content:space-between;gap:10px}
  .sc-r1 b{font-size:13px;color:var(--ink)}
  .sc-yr{font-size:11.5px;color:var(--muted)}
  .sc-v{display:block;font-size:12px;color:var(--muted);margin-top:3px}
  .sc-cav{font-size:12px;line-height:1.5;color:#8c6413;background:rgba(217,146,19,.09);
    border-radius:7px;padding:8px 10px;margin:8px 0 0}
  .sc-note{font-size:12px;line-height:1.55;color:var(--muted);margin-top:14px;max-width:72ch}

  /* Switches. The control shows its own state, so no row needs a verb — the
     old "Available … [Turn off]" pairing gave no way to tell which half
     described reality. */
  .ms-lead{font-size:12.5px;line-height:1.5;color:var(--muted);margin:-4px 0 10px;max-width:64ch}
  .ms-sw{flex:none;width:42px;height:24px;border-radius:99px;border:1px solid var(--line);
    background:var(--soft);padding:0;cursor:pointer;position:relative;transition:background .16s,border-color .16s}
  .ms-sw i{position:absolute;top:2px;left:2px;width:18px;height:18px;border-radius:50%;
    background:#fff;box-shadow:0 1px 3px rgba(0,0,0,.28);transition:transform .16s}
  .ms-sw.on{background:var(--brand);border-color:var(--brand)}
  .ms-sw.on i{transform:translateX(18px)}
  .ms-sw.busy{opacity:.55}
  .ms-sw:focus-visible{outline:2px solid var(--brand);outline-offset:2px}
  @media (prefers-reduced-motion:reduce){.ms-sw,.ms-sw i{transition:none}}
  /* State text carries the colour too, so the row reads without relying on
     the switch alone. */
  .ms-row .ms-st{min-width:132px;text-align:right;font-weight:600;color:var(--brand-ink)}
  .ms-row.off .ms-st{color:#8c6413}

/* Download control on a rename card. Sits on the image, appears on hover or
   keyboard focus, and is always visible on touch where there is no hover. */
.rn-shot{position:relative}
.rn-dl{position:absolute;right:8px;bottom:8px;width:34px;height:34px;border-radius:9px;
  display:grid;place-items:center;background:rgba(15,20,17,.62);color:#fff;
  opacity:0;transition:opacity .14s,background .14s;text-decoration:none}
.rn-dl svg{width:17px;height:17px}
.rn-card:hover .rn-dl,.rn-dl:focus-visible{opacity:1}
.rn-dl:hover{background:rgba(15,20,17,.85)}
.rn-dl:focus-visible{outline:2px solid #fff;outline-offset:2px}
@media (hover:none){.rn-dl{opacity:1}}
@media (prefers-reduced-motion:reduce){.rn-dl{transition:none}}

  /* Budgets. The default is stated as a sentence rather than a label, because
     "what does this number actually do" is the question, and the answer
     includes what the AGENT sees when it bites. */
  .mbudget{margin:0 0 34px}
  .bg-master{display:flex;align-items:flex-start;gap:18px;flex-wrap:wrap;
    border:1px solid var(--line);border-left:3px solid var(--brand);border-radius:11px;
    padding:14px 16px;background:#fff}
  .bg-m-b{flex:1;min-width:250px;display:flex;flex-direction:column;gap:3px}
  .bg-m-b b{font-size:14px;color:var(--ink)}
  .bg-m-b span{font-size:12.5px;line-height:1.5;color:var(--muted)}
  .bg-set,.bg-r2{display:flex;align-items:center;gap:7px;flex-wrap:wrap}
  .bg-cur{font-size:14px;color:var(--muted)}
  .bg-in{width:92px;padding:8px 10px;border:1px solid var(--line);border-radius:9px;
    font:inherit;font-size:14px;color:var(--ink);background:#fff;
    font-variant-numeric:tabular-nums}
  .bg-sid{width:120px;padding:8px 10px;border:1px solid var(--line);border-radius:9px;
    font:inherit;font-size:14px;color:var(--ink);background:#fff}
  .bg-msg,.bg-msg2,.bg-msg3{font-size:12px;color:var(--muted)}
  .bg-msg.err,.bg-msg2.err,.bg-msg3.err{color:#c0392b}
  .bg-rows{display:flex;flex-direction:column;gap:9px}
  .bg-row{border:1px solid var(--line);border-left:3px solid var(--line);border-radius:10px;
    background:#fff;padding:11px 13px}
  .bg-row.near{border-left-color:#d99213}
  .bg-row.hit{border-left-color:#c0392b;background:rgba(192,57,43,.03)}
  .bg-r1{display:flex;align-items:baseline;justify-content:space-between;gap:10px}
  .bg-r1 b{font-size:13px;color:var(--ink)}
  .bg-spend{font-size:12px;color:var(--muted);font-variant-numeric:tabular-nums}
  .bg-row .sp-bar{margin:7px 0 9px}
  .bg-add{display:flex;align-items:center;gap:7px;flex-wrap:wrap;margin-top:14px;
    padding-top:14px;border-top:1px solid var(--line)}

/* Name field: two lines, so the site id and any VS marker at the end stay
   readable instead of being clipped, and the field never grows wider than the
   photograph it belongs to. */
.rn-in{resize:none;line-height:1.4;font-family:inherit;overflow:hidden}
textarea.rn-in{display:block;min-height:auto}
.rn-count{font-size:10.5px;color:var(--muted);text-align:right;min-height:13px;
  font-variant-numeric:tabular-nums}
.rn-count.low{color:#c0392b;font-weight:700}
.rn-body{position:relative}

  /* ==========================================================================
     Rename screen
     --------------------------------------------------------------------------
     The photograph is the point: the agent is being asked to confirm a visual
     judgement — a den from an office, one bedroom from another — so the image
     gets the space and the name sits under it.
     ========================================================================== */
  .rn-head{display:flex;align-items:flex-start;gap:14px;flex-wrap:wrap;margin-bottom:10px}
  .rn-lead{flex:1;min-width:240px;margin:0;font-size:14px;line-height:1.55;color:var(--ink)}
  .rn-why{font-size:13px;line-height:1.55;color:#8c6413;background:rgba(217,146,19,.09);
    border:1px solid rgba(217,146,19,.28);border-radius:9px;padding:11px 13px;margin-bottom:12px}
  .rn-why.soft{color:var(--muted);background:var(--soft);border-color:var(--line)}
  .rn-why-d{display:block;margin-top:6px;font-size:12px;opacity:.85;
    font-family:ui-monospace,"Cascadia Code",Consolas,monospace;overflow-wrap:anywhere}
  .rn-key{display:flex;gap:16px;flex-wrap:wrap;margin-bottom:12px;font-size:12px;color:var(--muted)}
  .rn-key b{color:var(--ink)}
  .rn-note{font-size:12.5px;color:var(--muted);margin:0 0 12px}

  /* Three across on a desktop, one on a phone. */
  .rn-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:14px}
  @media (max-width:900px){.rn-grid{grid-template-columns:repeat(2,minmax(0,1fr))}}
  @media (max-width:600px){.rn-grid{grid-template-columns:1fr;gap:16px}}

  .rn-card{border:1px solid var(--line);border-radius:12px;background:#fff;overflow:hidden;
    display:flex;flex-direction:column}
  .rn-shot{position:relative;aspect-ratio:3/2;background:var(--soft)}
  .rn-shot img{width:100%;height:100%;object-fit:cover;display:block}
  .rn-body{position:relative;padding:10px 11px 11px;display:flex;flex-direction:column;gap:5px}
  .rn-cur{font-size:11px;color:var(--muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  /* Two lines, so the site id and any VS marker at the end stay readable
     instead of scrolling out of a single-line field. */
  .rn-in{width:100%;box-sizing:border-box;padding:8px 10px;border:1px solid var(--line);
    border-radius:8px;font:inherit;font-size:13px;line-height:1.4;color:var(--ink);
    background:#fff;resize:none;overflow:hidden;display:block}
  .rn-in:focus{outline:none;border-color:var(--brand);box-shadow:0 0 0 3px rgba(37,182,87,.12)}
  .rn-count{font-size:10.5px;color:var(--muted);text-align:right;min-height:13px;
    font-variant-numeric:tabular-nums}
  .rn-count.low{color:#c0392b;font-weight:700}
  .rn-skip{font-size:12px;color:var(--muted);padding:8px 0}
  .rn-card.skipped{opacity:.62}
  /* Amber edge: the system was unsure. Green edge: you changed it. */
  .rn-card.unsure{border-color:rgba(217,146,19,.5)}
  .rn-card.edited{border-color:var(--brand);box-shadow:0 0 0 1px var(--brand)}
  .rn-card.done{opacity:.5}

  /* Download sits on the image, appears on hover or keyboard focus, and stays
     visible on touch where there is no hover. Without a visible control the
     agent has no way to save the photo they are looking at. */
  .rn-dl{position:absolute;right:8px;bottom:8px;width:34px;height:34px;border-radius:9px;
    display:grid;place-items:center;background:rgba(15,20,17,.62);color:#fff;
    opacity:0;transition:opacity .14s,background .14s;text-decoration:none}
  .rn-dl svg{width:17px;height:17px}
  .rn-card:hover .rn-dl,.rn-dl:focus-visible{opacity:1}
  .rn-dl:hover{background:rgba(15,20,17,.85)}
  .rn-dl:focus-visible{outline:2px solid #fff;outline-offset:2px}
  @media (hover:none){.rn-dl{opacity:1}}
  @media (prefers-reduced-motion:reduce){.rn-dl{transition:none}}

  .rn-actions{display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin-top:18px;
    position:sticky;bottom:0;background:#fff;padding:12px 0}

  /* Prices in the console. */
  .mpricing{margin:0 0 34px}
  .pr-row{display:flex;align-items:flex-start;gap:18px;flex-wrap:wrap;
    border:1px solid var(--line);border-left:3px solid var(--brand);border-radius:11px;
    padding:14px 16px;background:#fff}
  .pr-b{flex:1;min-width:250px;display:flex;flex-direction:column;gap:3px}
  .pr-b b{font-size:14px;color:var(--ink)}
  .pr-b span{font-size:12.5px;line-height:1.5;color:var(--muted)}
  .pr-set{display:flex;align-items:center;gap:7px;flex-wrap:wrap}
  .pr-per{font-size:12.5px;color:var(--muted)}
  .pr-msg{font-size:12px;color:var(--muted)}
  .pr-msg.err{color:#c0392b}

  /* The staging offer on an empty room. Disabled on purpose: it names the
     price and says "Soon" rather than pretending to work. */
  .rn-vs{display:flex;align-items:center;gap:7px;flex-wrap:wrap;width:100%;
    margin-top:2px;padding:8px 10px;border:1px dashed var(--line);border-radius:8px;
    background:var(--soft);font:inherit;font-size:12px;color:var(--muted);
    text-align:left;cursor:not-allowed}
  .rn-vs-t{font-weight:600;color:var(--ink);opacity:.72}
  .rn-vs-p{font-variant-numeric:tabular-nums}
  .rn-vs-soon{margin-left:auto;font-size:9.5px;font-weight:800;letter-spacing:.08em;
    text-transform:uppercase;background:#fff;border:1px solid var(--line);
    border-radius:5px;padding:2px 6px}

  /* TEMP: test-listing shortcut. Delete with the block marked TEMP in
     js/03-admin.js and the #mTestJump div in index.html.
     Styled as visibly provisional — dashed border and a "Temporary" tag — so
     it never quietly becomes part of the furniture. */
  .mtestjump{margin:0 0 22px}
  .tj{display:flex;align-items:center;gap:9px;flex-wrap:wrap;
    border:1px dashed var(--line);border-radius:11px;padding:11px 13px;background:var(--soft)}
  .tj-tag{font-size:9.5px;font-weight:800;letter-spacing:.08em;text-transform:uppercase;
    color:#8c6413;background:rgba(217,146,19,.14);border-radius:5px;padding:3px 7px}
  .tj-l{font-size:13px;color:var(--ink);font-weight:600}
  .tj-in{width:130px;padding:8px 10px;border:1px solid var(--line);border-radius:9px;
    font:inherit;font-size:14px;color:var(--ink);background:#fff}
  .tj .btn-primary{width:auto;padding:0 16px;height:34px;font-size:13px}
  .tj-msg{font-size:12px;color:var(--muted)}
  .tj-msg.err{color:#c0392b}

  /* Cost token on a tool tile. This had NO rules at all, so it rendered as
     plain unstyled text — big, flat, and heavier than the tool name it sat
     beside. It is a quiet reassurance, not a headline. */
  .ptile-cost{position:absolute;top:10px;right:10px;
    font-size:9.5px;font-weight:800;letter-spacing:.07em;text-transform:uppercase;
    border-radius:999px;padding:3px 8px;line-height:1.5;pointer-events:none}
  .ptile-cost.free{color:var(--brand-ink);background:rgba(37,182,87,.13);
    border:1px solid rgba(37,182,87,.28)}
  .ptile-cost.paid{color:#8c6413;background:rgba(217,146,19,.13);
    border:1px solid rgba(217,146,19,.3)}
  .ptile{position:relative}

  /* Reading the photographs. A spinner and a half-sentence read as "something
     is stuck"; a named step with a moving bar and an honest duration reads as
     work being done. The bar is indeterminate on purpose — we cannot know how
     far along the model is, and a fake percentage would be a lie that stalls
     at 90%. */
  .rn-panel{min-height:120px}
  .rn-load{display:flex;flex-direction:column;gap:7px;padding:26px 22px;
    border:1px solid var(--line);border-radius:12px;background:#fff;max-width:56ch}
  .rn-load b{font-size:15px;color:var(--ink)}
  .rn-load span{font-size:13px;line-height:1.55;color:var(--muted)}
  .rn-load-bar{height:3px;border-radius:99px;background:var(--soft);overflow:hidden;margin-bottom:6px}
  .rn-load-bar i{display:block;height:100%;width:38%;border-radius:99px;
    background:var(--brand);animation:rnslide 1.5s ease-in-out infinite}
  @keyframes rnslide{0%{transform:translateX(-100%)}100%{transform:translateX(263%)}}
  @media (prefers-reduced-motion:reduce){
    .rn-load-bar i{animation:none;width:100%;opacity:.5}
  }

  /* Budget heading: the value sits on the same line as its label, so the
     setting reads as one thing rather than a section title with a paragraph
     between it and the field it describes. */
  .bg-m-h{display:flex;align-items:center;gap:12px;flex-wrap:wrap}
  .bg-m-h b{font-size:14px;color:var(--ink);flex:none}
  .bg-master{align-items:center}
  .bg-m-b span{max-width:62ch}
  .bg-add-l{font-size:13px;color:var(--ink);font-weight:600;margin-right:2px}

/* Version badge in the topbar. The word "Version" is not decoration: a bare
   date in a corner is unreadable tomorrow, when it is just "some date" with no
   clue what happened then. */
.tb-ver{display:inline-flex;align-items:baseline;gap:6px;
  border:1px solid rgba(255,255,255,.22);background:rgba(255,255,255,.07);
  color:rgba(255,255,255,.8);border-radius:7px;padding:4px 9px;cursor:pointer;
  font:inherit;font-size:11px;font-variant-numeric:tabular-nums;letter-spacing:.02em;
  white-space:nowrap;margin-left:auto}
.tb-ver:hover{background:rgba(255,255,255,.14);color:#fff}
.tb-ver-k{font-size:9px;font-weight:800;letter-spacing:.09em;text-transform:uppercase;
  opacity:.62}
.tb-ver-v{font-weight:600}
@media (max-width:640px){.tb-ver{display:none}}

  /* Reserve room for the cost token so it cannot sit on top of the tool name —
     the same trick .ptile.soon already uses for its SOON badge. */
  .ptile.has-cost .ptile-b{padding-right:46px}
  @media (max-width:600px){
    .ptile.has-cost .ptile-b{padding-right:0}
    .ptile-cost{top:7px;right:7px}
  }

  /* ==========================================================================
     Property heading — action row
     --------------------------------------------------------------------------
     One family of controls at one height. The old row mixed a gradient, a cream
     panel, a translucent ghost and a status chip at three different heights,
     so nothing indicated which control mattered.
     ========================================================================== */
  .ph-acts{margin-top:28px;gap:10px;align-items:stretch}
  .ph-acts .ph-btn,.ph-acts .ph-paid{
    height:42px;padding:0 18px;border-radius:11px;box-sizing:border-box;
    font-size:13.5px;font-weight:700;line-height:1;white-space:nowrap}
  .ph-acts .ph-btn{display:inline-flex;align-items:center;justify-content:center;gap:9px}
  /* Secondary actions share ONE treatment. The cream "feature" panel is kept
     only as a lighter border, so it reads as second in line rather than as a
     different kind of thing entirely. */
  .ph-btn.feature{background:rgba(255,255,255,.14);color:#fff;
    border:1px solid rgba(255,255,255,.34);box-shadow:none}
  .ph-btn.feature:hover{background:rgba(255,255,255,.24);box-shadow:none}
  .ph-btn.feature svg{color:#fff}
  .ph-btn.ghost{background:transparent;border:1px solid rgba(255,255,255,.2);
    color:rgba(255,255,255,.86);font-weight:600}

  /* "Paid" moved out of the button row and up beside the property id, where a
     fact belongs. */
  .ph-status{display:none}
  .ph-status.paid{display:inline-flex;align-items:center;gap:5px;margin-left:12px;
    padding:2px 9px 2px 7px;border-radius:999px;
    background:rgba(37,182,87,.18);border:1px solid rgba(37,182,87,.4);
    color:#d8f5e2;font-weight:700;letter-spacing:0;text-transform:none}
  .ph-status.paid svg{width:12px;height:12px}

  @media (max-width:600px){
    .ph-acts{margin-top:20px;gap:8px}
    .ph-acts .ph-btn{height:44px;padding:0 14px;font-size:13px;flex:1 1 auto}
    .ph-acts .ph-btn.primary{flex-basis:100%}
    .ph-status.paid{margin-left:0;margin-top:6px}
  }

  /* The Apply row and the floating property bar were both claiming the bottom
     edge — the bar slid over the Apply button and the button itself, left at
     btn-primary's default full width, read as an anonymous green stripe.
     The row now sits ABOVE the bar whenever the bar is present, and the
     button is a button again. */
  .rn-actions{border-top:1px solid var(--line);box-shadow:0 -6px 16px rgba(15,20,17,.05)}
  .rn-actions .btn-primary{width:auto;padding:0 24px;height:42px;font-size:13.5px}
  body.has-pbar .rn-actions{bottom:76px}
  @media (max-width:600px){
    body.has-pbar .rn-actions{bottom:72px}
    .rn-actions .btn-primary{flex:1}
  }

  /* Apply lives in the header beside the lead — no more bottom bar fighting
     the floating property bar for the same edge. */
  .rn-head-acts{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
  .rn-head-acts .btn-primary{width:auto;padding:0 22px;height:40px;font-size:13.5px}
  .rn-actions{display:none}

  .rl-pat .sp-l b{font-weight:600;color:var(--ink)}

/* The floating bar stays out of the way while the hero (with the same
   buttons) is on screen, and slides up once it scrolls away. */
.pbar.on.held{transform:translateX(-50%) translateY(140%)}
@media (max-width:600px){.pbar.on.held{transform:translateY(140%)}}

/* Topbar rhythm. The version pill was pressed straight against the greeting —
   margin-left:auto with no gap on the other side. */
.topbar{gap:18px}
.tb-ver{height:34px;box-sizing:border-box;align-items:center}
.topbar .who{flex:none}

/* Badges on a rename card. Words, not glyphs: "?*" needs a legend, "Same
   room?" does not. One accent per meaning, kept apart from the greens. */
.rn-flag{position:absolute;left:8px;font-size:10px;font-weight:800;letter-spacing:.04em;
  border-radius:6px;padding:3px 8px;line-height:1.5;pointer-events:auto;cursor:help}
.rn-flag.room,.rn-flag.group{top:8px;background:rgba(217,146,19,.94);color:#241a04}
.rn-flag.vs{bottom:8px;background:rgba(93,82,226,.94);color:#fff}
.rn-card .rn-flag.vs~.rn-dl,{right:8px}

/* Apply and Look again at ONE height. btn-mini's natural size next to a 40px
   primary read as an accident rather than a hierarchy. */
.rn-head-acts .btn-mini{height:40px;box-sizing:border-box;display:inline-flex;
  align-items:center;padding:0 16px;font-size:13px}

  /* Save / Undo on an edited card. Visible only once the field differs from
     the suggestion — a decision control, not furniture. */
  .rn-save-row{display:flex;gap:7px}
  .rn-save-row .btn-mini{flex:1;height:32px;display:inline-flex;align-items:center;justify-content:center}
  .rn-save-row .rn-revert{flex:0 0 auto}

  /* Learning section */
  .mlearning{margin:0 0 34px}
  .ln-rows{display:flex;flex-direction:column;gap:9px}
  .ln-row{display:flex;align-items:center;gap:14px;flex-wrap:wrap;
    border:1px solid var(--line);border-left:3px solid var(--brand);border-radius:11px;
    background:#fff;padding:12px 15px}
  .ln-row.due{border-left-color:#d99213}
  .ln-b{flex:1;min-width:220px;display:flex;flex-direction:column;gap:2px}
  .ln-n{font-size:13.5px;color:var(--ink)}
  .ln-s{font-size:12px;color:var(--muted)}
  .ln-days{font-size:12px;font-weight:700;color:var(--brand-ink)}
  .ln-row.due .ln-days{color:#8c6413}
  .ln-acts{display:flex;gap:7px;flex-wrap:wrap}
  .ln-insights{display:flex;flex-direction:column;gap:10px}
  .ln-card{border:1px solid var(--line);border-radius:10px;background:#fff;padding:12px 14px;
    display:flex;flex-direction:column;gap:6px}
  .ln-f{font-size:13.5px;color:var(--ink)}
  .ln-e{font-size:12px;color:var(--muted)}
  .ln-r{margin:0;font-size:12.5px;line-height:1.5;color:var(--ink);
    border-left:2px solid var(--brand);padding-left:10px}
  .ln-note{width:100%;box-sizing:border-box;border:1px solid var(--line);border-radius:8px;
    padding:8px 10px;font:inherit;font-size:12.5px;color:var(--ink);resize:vertical}
  .ln-foot{display:flex;align-items:center;gap:12px;margin-top:12px}
  .ln-foot .btn-primary{width:auto;padding:0 20px;height:38px;font-size:13px}
  .ln-msg{font-size:12px;color:var(--muted)}
  /* Approval log line in the rename tool */
  .rn-lastlog{font-size:12.5px;color:var(--muted);margin:0 0 12px;cursor:default}

  /* Download all sits with the other header actions, same height as the rest. */
  .rn-head-acts .rn-dlall{margin-left:auto}
  @media (max-width:600px){.rn-head-acts .rn-dlall{margin-left:0}}

/* Version pill sits on the LEFT, with the listing controls it belongs to.
   margin-right:auto pushes the greeting and Sign out to the far edge. */
.tb-ver{margin-left:0;margin-right:auto}

/* Budget card: heading and explanation on the left, the control as one
   unbroken cluster on the right, note underneath. The old version put a bold
   label, an input, a unit, a button and a message on one flex line, so it
   re-wrapped into a different shape at every window width. */
.bg-master{display:block;padding:15px 17px}
.bg-m-top{display:flex;align-items:center;justify-content:space-between;gap:20px;flex-wrap:wrap}
.bg-m-l{display:flex;flex-direction:column;gap:2px;min-width:200px}
.bg-m-l b{font-size:14px;color:var(--ink)}
.bg-m-l span{font-size:12.5px;line-height:1.5;color:var(--muted);max-width:46ch}
.bg-master .bg-set{flex:none;gap:8px;flex-wrap:nowrap}
.bg-master .bg-in{width:104px;height:38px;box-sizing:border-box;font-size:15px;font-weight:600}
.bg-master .btn-mini{height:38px;display:inline-flex;align-items:center;padding:0 16px}
.bg-m-note{margin:12px 0 0;padding-top:11px;border-top:1px solid var(--line);
  font-size:12px;line-height:1.5;color:var(--muted);max-width:74ch}
.bg-m-note .bg-msg{margin-left:8px}
@media (max-width:600px){
  .bg-m-top{align-items:flex-start}
  .bg-master .bg-set{flex-wrap:wrap}
}

  /* A photo the system is unsure about asks a question, and holds itself out
     of the bulk apply until it gets an answer. Admitting doubt is pointless if
     the doubtful names save themselves alongside the confident ones. */
  .rn-card.asks{border-color:#d99213;box-shadow:0 0 0 1px rgba(217,146,19,.45)}
  .rn-card.checked{border-color:var(--brand)}
  .rn-ask{display:flex;flex-direction:column;gap:6px;padding:9px 10px;margin-top:2px;
    background:rgba(217,146,19,.09);border:1px solid rgba(217,146,19,.3);border-radius:8px}
  .rn-ask-q{font-size:12px;font-weight:600;color:#8c6413;line-height:1.4}
  .rn-ask .btn-mini{height:30px;display:inline-flex;align-items:center;justify-content:center}
  .rn-source{font-size:12.5px;color:var(--muted);margin:0 0 12px}
  .rn-source.warn{color:#8c6413;background:rgba(217,146,19,.09);
    border:1px solid rgba(217,146,19,.28);border-radius:9px;padding:10px 12px;line-height:1.5}

  /* The room-count question. Deliberately a form, not a warning: telling
     somebody to go and edit Property details is a sentence nobody acts on. */
  .rn-source.ask{display:flex;flex-direction:column;gap:6px;color:var(--ink);
    background:rgba(37,182,87,.06);border:1px solid rgba(37,182,87,.3);
    border-radius:11px;padding:14px 16px;margin-bottom:14px}
  .rn-source.ask b{font-size:14px}
  .rn-source.ask span{font-size:12.5px;line-height:1.5;color:var(--muted);max-width:70ch}
  .rn-counts{display:flex;align-items:flex-end;gap:10px;flex-wrap:wrap;margin-top:6px}
  .rn-counts label{display:flex;flex-direction:column;gap:4px;font-size:11.5px;
    font-weight:700;letter-spacing:.04em;text-transform:uppercase;color:var(--muted)}
  .rn-counts input{width:88px;padding:8px 10px;border:1px solid var(--line);border-radius:9px;
    font:inherit;font-size:15px;font-weight:600;color:var(--ink);background:#fff;
    font-variant-numeric:tabular-nums}
  .rn-counts .btn-primary{width:auto;padding:0 18px;height:38px;font-size:13px}
  .rn-counts-msg{font-size:12px;color:#c0392b}

  /* Quick questions. Two photographs, two buttons — the cheapest and most
     reliable way to settle what the model genuinely cannot. */
  .rn-quiz{margin:0 0 16px}
  .rn-quiz:empty{display:none}
  .rn-quiz-h{display:flex;align-items:baseline;justify-content:space-between;gap:10px;
    margin-bottom:2px}
  .rn-quiz-h b{font-size:14px;color:var(--ink)}
  .rn-quiz-n{font-size:11.5px;color:var(--muted);font-variant-numeric:tabular-nums}
  .rn-quiz-q{margin:0 0 10px;font-size:13px;color:var(--muted)}
  .rn-quiz-pair{display:grid;grid-template-columns:1fr 1fr;gap:12px}
  .rn-quiz-pair figure{margin:0;border:1px solid var(--line);border-radius:11px;
    overflow:hidden;background:#fff}
  .rn-quiz-pair img{width:100%;aspect-ratio:3/2;object-fit:cover;display:block}
  .rn-quiz-pair figcaption{padding:7px 10px;font-size:11.5px;color:var(--muted)}
  .rn-quiz-acts{display:flex;align-items:center;gap:9px;flex-wrap:wrap;margin-top:12px}
  .rn-quiz-acts .btn-primary{width:auto;padding:0 20px;height:38px;font-size:13px}
  .rn-quiz-acts .btn-mini{height:38px;display:inline-flex;align-items:center;padding:0 16px}
  .rn-quiz-done{font-size:13px;color:var(--brand-ink);background:rgba(37,182,87,.09);
    border:1px solid rgba(37,182,87,.3);border-radius:10px;padding:11px 13px}
  /* The quiz wraps to one column where two photographs would be too small. */
  @media (max-width:600px){ .rn-quiz-pair{grid-template-columns:1fr} }

  /* One-click alternatives on a question. Correcting a name should not require
     remembering the vocabulary and typing it exactly. */
  .rn-ask-opts{display:flex;flex-wrap:wrap;gap:6px}
  .rn-ask-opts .btn-mini{height:30px;display:inline-flex;align-items:center;
    padding:0 11px;font-size:12px}
  .rn-ask-opts .rn-ok{background:rgba(37,182,87,.14);border-color:rgba(37,182,87,.4);
    color:var(--brand-ink);font-weight:700}
  .rn-ask-other{align-self:flex-start;background:none;border:none;padding:2px 0;
    font:inherit;font-size:11.5px;color:#8c6413;text-decoration:underline;cursor:pointer}

  /* Virtual-staging tag: plain white words on the photograph, no chip, bottom
     right. The download control moves to the TOP right so the two never sit on
     top of each other. */
  .rn-flag.vs{left:auto;right:10px;bottom:9px;top:auto;background:none;padding:0;
    color:#fff;font-weight:700;letter-spacing:.02em;font-size:11px;
    text-shadow:0 1px 3px rgba(0,0,0,.85),0 0 10px rgba(0,0,0,.5)}
  .rn-dl{top:8px;bottom:auto}
  /* The room/group questions stay top LEFT, clear of both. */
  .rn-flag.room,.rn-flag.group{left:8px;right:auto;top:8px}

  /* Header actions share one shape: same height, same radius, same weight, so
     the row reads as a set rather than three unrelated controls. */
  .rn-head-acts .btn-primary,
  .rn-head-acts .btn-mini{height:40px;box-sizing:border-box;border-radius:10px;
    display:inline-flex;align-items:center;justify-content:center;
    padding:0 18px;font-size:13px;font-weight:700;line-height:1;white-space:nowrap}
  .rn-head-acts .btn-mini{font-weight:600}

/* Owner budget control in the top bar. These elements had NO rules at all —
   a raw number input and an unstyled button dropped into a dark bar, which is
   exactly as sloppy as it looked. Sized to its content, not to the browser
   default for a number field. */
.va-budget{display:inline-flex;align-items:center;gap:7px;margin-left:14px;
  padding:4px 5px 4px 11px;border:1px solid rgba(255,255,255,.2);
  background:rgba(255,255,255,.06);border-radius:999px;white-space:nowrap}
.va-budget.over{border-color:rgba(192,57,43,.65);background:rgba(192,57,43,.16)}
.va-k{font-size:9px;font-weight:800;letter-spacing:.09em;text-transform:uppercase;
  color:rgba(255,255,255,.5)}
.va-spent{font-size:12.5px;font-weight:700;color:#fff;font-variant-numeric:tabular-nums}
.va-budget.over .va-spent{color:#ffb4aa}
.va-of{font-size:9px;font-weight:800;letter-spacing:.09em;text-transform:uppercase;
  color:rgba(255,255,255,.5)}
.va-cur{font-size:12.5px;color:rgba(255,255,255,.62);margin-right:-4px}
.va-in{width:52px;padding:4px 6px;border:1px solid rgba(255,255,255,.2);border-radius:7px;
  background:rgba(0,0,0,.28);color:#fff;font:inherit;font-size:12.5px;font-weight:700;
  font-variant-numeric:tabular-nums;text-align:right;-moz-appearance:textfield}
.va-in::-webkit-outer-spin-button,.va-in::-webkit-inner-spin-button{
  -webkit-appearance:none;margin:0}
.va-in:focus{outline:none;border-color:var(--brand);box-shadow:0 0 0 2px rgba(37,182,87,.3)}
.va-budget .va-set{height:26px;padding:0 11px;font-size:11.5px;border-radius:999px;
  background:rgba(255,255,255,.12);border:1px solid rgba(255,255,255,.22);color:#fff}
.va-budget .va-set:hover{background:var(--brand);border-color:var(--brand);color:#04170c}
@media (max-width:820px){ .va-budget{display:none} }

  /* Confirmation badge: a call to action, not an observation. It carries a
     sentence now, so it must be allowed to wrap. */
  .rn-flag.room,.rn-flag.group{max-width:calc(100% - 16px);white-space:normal;
    line-height:1.35;padding:4px 9px}

  /* Group them myself — the honest floor under this whole feature. Two
     identical builder bedrooms are genuinely ambiguous, and somebody who
     walked the house settles it in seconds, for nothing. */
  .rngrid{position:fixed;inset:0;z-index:130;display:grid;place-items:center;padding:20px}
  .rngrid-inner{position:relative;width:min(1120px,100%);max-height:92vh;
    display:flex;flex-direction:column;background:#fff;border-radius:14px;overflow:hidden}
  .rngrid-head{display:flex;align-items:flex-start;gap:14px;padding:16px 18px;
    border-bottom:1px solid var(--line)}
  .rngrid-head b{display:block;font-size:15px;color:var(--ink)}
  .rngrid-head span{display:block;font-size:12.5px;line-height:1.5;color:var(--muted);
    margin-top:3px;max-width:70ch}
  .rngrid-x{margin-left:auto;background:none;border:none;font-size:26px;line-height:1;
    color:var(--muted);cursor:pointer}
  .rngrid-body{flex:1;overflow:auto;padding:14px 18px;display:grid;gap:10px;
    grid-template-columns:repeat(auto-fill,minmax(min(150px,100%),1fr));align-content:start}
  .rngrid-cell{position:relative;padding:0;border:2px solid var(--line);border-radius:10px;
    background:#fff;overflow:hidden;cursor:pointer;display:block;text-align:left}
  .rngrid-cell img{width:100%;aspect-ratio:3/2;object-fit:cover;display:block}
  .rngrid-lab{display:block;padding:5px 7px;font-size:10.5px;color:var(--muted);
    overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  .rngrid-tick{position:absolute;top:6px;right:6px;width:24px;height:24px;border-radius:50%;
    background:var(--brand);color:#04170c;display:none;place-items:center;font-size:13px;font-weight:800}
  .rngrid-cell.on{border-color:var(--brand);box-shadow:0 0 0 2px rgba(37,182,87,.28)}
  .rngrid-cell.on .rngrid-tick{display:grid}
  .rngrid-cell.locked{opacity:.5}
  .rngrid-foot{display:flex;align-items:center;gap:10px;flex-wrap:wrap;
    padding:13px 18px;border-top:1px solid var(--line);background:var(--soft)}
  .rngrid-count{font-size:12.5px;color:var(--muted);min-width:120px}
  .rngrid-name{padding:9px 11px;border:1px solid var(--line);border-radius:9px;
    font:inherit;font-size:13.5px;color:var(--ink);background:#fff}
  .rngrid-foot .btn-primary{width:auto;padding:0 18px;height:40px;font-size:13px}
  .rngrid-foot .btn-mini{height:40px;display:inline-flex;align-items:center;padding:0 16px;
    margin-left:auto}
  @media (max-width:600px){
    .rngrid{padding:0}
    .rngrid-inner{max-height:100vh;border-radius:0}
    .rngrid-foot .btn-mini{margin-left:0}
  }

  /* One photo, large, with its name field. Naming is a visual judgement and a
     230px card cannot carry it — telling a den from an office, or spotting the
     same curtain in two frames, needs the photograph big. */
  body.rnbig-open{overflow:hidden}
  .rnbig{position:fixed;inset:0;z-index:120;display:grid;place-items:center;padding:24px}
  .rnbig-shade{position:absolute;inset:0;background:rgba(9,12,10,.9)}
  .rnbig-inner{position:relative;width:min(1180px,100%);max-height:100%;
    display:flex;flex-direction:column;gap:12px}
  .rnbig-fig{margin:0;background:#0b0d0b;border-radius:12px;overflow:hidden;
    display:grid;place-items:center;min-height:0}
  .rnbig-fig img{max-width:100%;max-height:min(72vh,760px);display:block;object-fit:contain}
  .rnbig-bar{display:flex;align-items:center;gap:12px;flex-wrap:wrap;
    background:#fff;border-radius:12px;padding:12px 14px}
  .rnbig-meta{display:flex;flex-direction:column;gap:2px;min-width:120px}
  .rnbig-n{font-size:11px;font-weight:800;letter-spacing:.07em;text-transform:uppercase;
    color:var(--muted);font-variant-numeric:tabular-nums}
  .rnbig-cur{font-size:11.5px;color:var(--muted);overflow:hidden;text-overflow:ellipsis;
    white-space:nowrap;max-width:280px}
  .rnbig-in{flex:1;min-width:220px;padding:11px 13px;border:1px solid var(--line);
    border-radius:10px;font:inherit;font-size:15px;color:var(--ink);background:#fff}
  .rnbig-in:focus{outline:none;border-color:var(--brand);box-shadow:0 0 0 3px rgba(37,182,87,.14)}
  .rnbig-bar .btn-primary{width:auto;padding:0 20px;height:42px;font-size:13.5px}
  .rnbig-x{position:absolute;top:-4px;right:0;transform:translateY(-100%);
    background:none;border:none;color:#fff;font-size:30px;line-height:1;cursor:pointer;opacity:.8}
  .rnbig-x:hover{opacity:1}
  .rnbig-nav{position:absolute;top:38%;width:46px;height:46px;border-radius:50%;
    border:1px solid rgba(255,255,255,.3);background:rgba(9,12,10,.55);color:#fff;
    font-size:26px;line-height:1;cursor:pointer;display:grid;place-items:center;z-index:2}
  .rnbig-nav:hover{background:rgba(9,12,10,.85)}
  .rnbig-nav.prev{left:-6px}
  .rnbig-nav.next{right:-6px}
  @media (max-width:700px){
    .rnbig{padding:12px}
    .rnbig-nav{top:auto;bottom:96px}
    .rnbig-nav.prev{left:8px} .rnbig-nav.next{right:8px}
    .rnbig-bar{flex-direction:column;align-items:stretch}
    .rnbig-bar .btn-primary{width:100%}
  }

  /* Approved token — the same signal used elsewhere for work an agent has
     signed off, so a listing's state reads at a glance. */
  .rn-approved{display:none}
  .rn-approved.on{display:inline-flex;align-items:baseline;gap:7px;
    background:rgba(37,182,87,.12);border:1px solid rgba(37,182,87,.34);
    border-radius:999px;padding:5px 12px}
  .rn-appr-t{font-size:11px;font-weight:800;letter-spacing:.06em;text-transform:uppercase;
    color:var(--brand-ink)}
  .rn-appr-d{font-size:11.5px;color:var(--muted)}

  /* ==========================================================================
     Rename header, rebuilt
     --------------------------------------------------------------------------
     It had grown by accretion: four grey sentences stacked under a row of four
     mismatched controls, with the lead text squeezed into a narrow column
     beside them. Now it reads top to bottom — what happened, what you can do,
     then the small print.
     ========================================================================== */
  .rn-head2{display:block;margin-bottom:16px}
  .rn-head2 .rn-lead{max-width:74ch;margin:0 0 12px;font-size:14.5px;line-height:1.5}
  .rn-head2 .rn-head-acts{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin:0}
  /* One shape for every control in the row. */
  .rn-head2 .rn-head-acts .btn-primary,
  .rn-head2 .rn-head-acts .btn-mini{height:38px;box-sizing:border-box;border-radius:9px;
    display:inline-flex;align-items:center;justify-content:center;padding:0 16px;
    font-size:13px;font-weight:600;line-height:1;white-space:nowrap;box-shadow:none}
  .rn-head2 .rn-head-acts .btn-primary{font-weight:700;padding:0 20px}
  .rn-head2 .rn-head-acts .rn-dlall{margin-left:auto}

  /* One meta line, not three paragraphs. */
  .rn-meta{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin:12px 0 14px;
    font-size:12px;color:var(--muted);line-height:1.5}
  .rn-meta > *:not(:last-child)::after{content:'·';margin-left:8px;opacity:.5}
  .rn-meta .rn-source{color:var(--muted)}
  .rn-meta .rn-source.warn,.rn-meta .rn-source.ask{color:#8c6413;background:none;
    border:none;padding:0;display:inline}
  /* The approved token, smaller — it is a fact on a line of facts, not a
     control competing with the primary button. */
  .rn-meta .rn-approved.on{display:inline-flex;align-items:baseline;gap:6px;
    background:none;border:none;padding:0;border-radius:0}
  .rn-meta .rn-appr-t{font-size:11px;font-weight:800;letter-spacing:.05em;
    text-transform:uppercase;color:var(--brand-ink)}
  .rn-meta .rn-appr-d{font-size:12px;color:var(--muted)}
  /* The legend is small print and sits with the small print. */
  .rn-key{gap:14px;margin:0 0 14px;font-size:11.5px}

  /* Manual grouping is offered only when something needs it, so when it does
     appear it deserves a line saying why. */
  .rn-why-manual{margin:12px 0 0;font-size:12.5px;line-height:1.55;color:#8c6413;
    background:rgba(217,146,19,.09);border:1px solid rgba(217,146,19,.28);
    border-radius:9px;padding:10px 12px;max-width:78ch}
  .rn-why-manual b{color:var(--ink)}

  /* Five across, and the WHOLE photograph. Cropping to a fixed 3:2 defeats the
     point: the agent is hunting for a window at the left edge or a fan at the
     top, and a crop removes precisely that. */
  .rngrid-body{grid-template-columns:repeat(5,minmax(0,1fr));gap:8px}
  .rngrid-cell img{aspect-ratio:auto;height:auto;max-height:140px;
    object-fit:contain;background:#0f1411}
  @media (max-width:1000px){ .rngrid-body{grid-template-columns:repeat(4,minmax(0,1fr))} }
  @media (max-width:760px){ .rngrid-body{grid-template-columns:repeat(3,minmax(0,1fr))} }
  @media (max-width:520px){ .rngrid-body{grid-template-columns:repeat(2,minmax(0,1fr))} }

  /* The version number leads the badge: comparing "v43" to "v42" is instant,
     comparing two timestamps that differ in two digits is not. */
  .tb-ver-num{font-weight:800;color:#fff;font-size:12px}
  .tb-ver-v{font-weight:500;opacity:.72;font-size:10.5px}

  /* Community library. Communities we hold amenity photos for lead, because
     those are the ones that can be sold again without sending anybody out. */
  .mcomm{margin:0 0 34px}
  .cm-pick{display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin-bottom:14px}
  .cm-pick label{display:flex;align-items:center;gap:8px;font-size:12.5px;color:var(--muted)}
  .cm-sel{padding:9px 11px;border:1px solid var(--line);border-radius:9px;
    font:inherit;font-size:13.5px;color:var(--ink);background:#fff;min-width:260px;max-width:100%}
  .cm-tally{font-size:12px;color:var(--muted)}
  .cm-rows{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(280px,100%),1fr));gap:10px}
  .cm-row{border:1px solid var(--line);border-left:3px solid var(--line);border-radius:11px;
    background:#fff;padding:12px 14px;display:flex;flex-direction:column;gap:3px;
    transition:box-shadow .3s}
  .cm-row.has{border-left-color:var(--brand)}
  .cm-row.flash{box-shadow:0 0 0 3px rgba(37,182,87,.35)}
  .cm-top{display:flex;align-items:baseline;justify-content:space-between;gap:10px;flex-wrap:wrap}
  .cm-n{font-size:13.5px;color:var(--ink)}
  .cm-badge{font-size:10px;font-weight:800;letter-spacing:.05em;text-transform:uppercase;
    color:var(--brand-ink);background:rgba(37,182,87,.13);border-radius:999px;padding:3px 9px;white-space:nowrap}
  .cm-fac{font-size:12px;color:var(--muted)}
  .cm-meta{font-size:11.5px;color:var(--muted);opacity:.85}

  /* Outstanding requests. First panel in the console, because "what did I ask
     for that has not happened" is the question it answers. */
  .mpending{margin:0 0 26px}
  .pd-rows{display:flex;flex-direction:column;gap:1px}
  .pd-rows .sp-h{margin:14px 0 6px}
  .pd-rows .sp-h:first-child{margin-top:0}
  .pd-row{display:flex;align-items:baseline;gap:10px;padding:8px 10px;border-radius:7px;
    font-size:13px;line-height:1.5}
  .pd-row:nth-of-type(odd){background:var(--soft)}
  .pd-id{flex:none;font-size:11px;font-weight:800;letter-spacing:.04em;
    color:var(--brand-ink);background:rgba(37,182,87,.13);border-radius:5px;
    padding:2px 7px;font-variant-numeric:tabular-nums}
  .pd-row.blocked .pd-id{color:#8c6413;background:rgba(217,146,19,.14)}
  .pd-t{flex:1;min-width:0;color:var(--ink)}
  .pd-area{flex:none;font-size:10.5px;font-weight:700;letter-spacing:.05em;
    text-transform:uppercase;color:var(--muted)}
  .pd-x{flex:none;border:none;background:none;color:var(--muted);font-size:17px;
    line-height:1;cursor:pointer;padding:0 2px}
  .pd-x:hover{color:#c0392b}

  /* The replace-everything disclaimer on the rename tool. Deliberately plain:
     this is a consequence to read, not a banner to skim past. */
  .rn-warn{max-width:560px;margin:0 auto;padding:22px 22px 20px;border-radius:12px;
    border:1px solid var(--line);background:var(--soft)}
  .rn-warn b{display:block;font-size:15.5px;line-height:1.35;margin:0 0 8px;color:var(--ink)}
  .rn-warn p{margin:0 0 18px;font-size:13.5px;line-height:1.6;color:var(--muted)}
  .rn-warn-acts{display:flex;flex-wrap:wrap;gap:10px;justify-content:flex-end}
  @media (max-width:520px){
    .rn-warn{padding:18px 16px 16px}
    .rn-warn-acts{justify-content:stretch}
    .rn-warn-acts button{flex:1 1 100%}
  }

  /* A photograph whose room is still unconfirmed but which is not the one
     carrying the question. Held out of the bulk apply, shown as waiting
     rather than as another thing to answer. */
  .rn-card.pending:not(.asks){opacity:.72}
  .rn-card.pending:not(.asks) .rn-shot{outline:2px solid var(--line);outline-offset:-2px}

  /* The naming sandbox. Deliberately plain — it is a workbench, not a
     product, and it should never be mistaken for the tool agents use. */
  .msandbox{margin:0 0 26px}
  .sbx-bar{display:flex;flex-wrap:wrap;gap:10px;align-items:center;margin:0 0 14px}
  .sbx-sid{flex:0 0 130px;padding:9px 11px;border:1px solid var(--line);border-radius:8px;
    font:inherit;font-variant-numeric:tabular-nums;background:var(--card);color:var(--ink)}
  .sbx-fresh{display:flex;align-items:center;gap:6px;font-size:12.5px;color:var(--muted)}
  .sbx-wait{padding:16px;border-radius:9px;background:var(--soft);color:var(--muted);font-size:13.5px}
  .sbx-sum{display:flex;flex-wrap:wrap;align-items:baseline;gap:6px 14px;margin:0 0 10px}
  .sbx-sum .sbx-addr{font-size:15px;color:var(--ink)}
  .sbx-meta{font-size:12px;color:var(--muted);font-variant-numeric:tabular-nums}
  .sbx-notes{margin:0 0 16px;padding:10px 12px 10px 28px;border-radius:8px;background:var(--soft);
    font-size:12.5px;line-height:1.65;color:var(--muted)}
  .sbx-room{margin:0 0 16px;padding:12px;border:1px solid var(--line);border-radius:10px}
  .sbx-room-h{display:flex;align-items:baseline;gap:10px;margin:0 0 6px}
  .sbx-room-h b{font-size:14px;color:var(--ink)}
  .sbx-n{font-size:11.5px;color:var(--muted)}
  .sbx-why{margin:0 0 10px;font-size:12.5px;line-height:1.6;color:var(--muted)}
  .sbx-shots{display:flex;flex-wrap:wrap;gap:8px}
  .sbx-shot{margin:0;width:130px}
  .sbx-shot img{width:100%;aspect-ratio:3/2;object-fit:cover;border-radius:6px;display:block;
    background:var(--soft)}
  .sbx-shot figcaption{margin-top:4px;font-size:10.5px;line-height:1.35;color:var(--muted);
    overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  @media (max-width:520px){ .sbx-shot{width:calc(50% - 4px)} }

  /* Step blocks in the sandbox. The colour states a verdict at a glance:
     green settled, amber unknown, red the sources contradict each other. */
  .sbx-step{margin:0 0 16px;padding:12px 14px;border-radius:10px;border:1px solid var(--line)}
  .sbx-step.ok{border-color:rgba(37,182,87,.4);background:rgba(37,182,87,.05)}
  .sbx-step.warn{border-color:rgba(217,146,19,.4);background:rgba(217,146,19,.05)}
  .sbx-step.bad{border-color:rgba(192,57,43,.4);background:rgba(192,57,43,.05)}
  .sbx-step-h{display:flex;flex-wrap:wrap;align-items:baseline;gap:8px 12px;margin:0 0 10px}
  .sbx-step-h b{font-size:13.5px;color:var(--ink)}
  .sbx-verdict{font-size:12px;font-weight:700;color:var(--muted);font-variant-numeric:tabular-nums}
  .sbx-step.ok .sbx-verdict{color:var(--brand-ink)}
  .sbx-claims{display:flex;flex-direction:column;gap:4px}
  .sbx-claim{display:flex;flex-wrap:wrap;align-items:baseline;gap:4px 12px;font-size:12.5px;
    padding:5px 0;color:var(--muted)}
  .sbx-src{flex:0 0 78px;font-weight:700;color:var(--ink)}
  .sbx-val{flex:0 0 132px;font-variant-numeric:tabular-nums;color:var(--ink)}
  .sbx-det{flex:1;min-width:0;font-size:11.5px}
  .sbx-q{margin:12px 0 8px;font-size:13px;line-height:1.6;color:var(--ink)}
  .sbx-fix{display:flex;flex-wrap:wrap;gap:8px;align-items:center}
  .sbx-fix input{width:104px;padding:7px 10px;border:1px solid var(--line);border-radius:7px;
    font:inherit;font-size:13px;background:var(--card);color:var(--ink)}
  .sbx-settled{font-size:12px;color:var(--brand-ink)}

  /* Floor plan reader. A room that shares every feature with another is
     marked, because knowing that in advance is the useful part. */
  .pr-room{margin:0 0 10px;padding:10px 12px;border:1px solid var(--line);border-radius:9px}
  .pr-room.twin{border-style:dashed;opacity:.85}
  .pr-h{display:flex;flex-wrap:wrap;align-items:baseline;gap:6px 12px;margin:0 0 6px}
  .pr-h b{font-size:13.5px;color:var(--ink)}
  .pr-size{font-size:11.5px;color:var(--muted);font-variant-numeric:tabular-nums}
  .pr-tag{margin-left:auto;font-size:11px;color:var(--brand-ink)}
  .pr-room.twin .pr-tag{color:#8c6413}
  .pr-ring{margin:0;padding:0 0 0 18px;font-size:12px;line-height:1.7;color:var(--muted)}
  .pr-uniq{margin-top:6px}
  .pr-p{font-size:11.5px;color:var(--ink);padding:2px 0}
  .pr-file{font-size:12px;color:var(--muted);max-width:230px}
  .pr-count{font-size:15px;color:var(--ink)}

  /* ---- Voice translator ---------------------------------------------------
     One screen, one button. Full-bleed rather than a side panel: she uses this
     many times a day and the transcript needs room to be read at arm's length.
     Every control is full width and at least 56px tall so it works one-handed
     on a phone. */
  #panel.full .panel-box{width:100vw;max-width:none}
  #panel.full .panel-body{max-width:760px;margin:0 auto;width:100%}

  .vx{display:flex;flex-direction:column;gap:12px}
  .vx-top{display:flex;align-items:center;justify-content:space-between;gap:12px;
    padding-bottom:14px;border-bottom:1px solid var(--line)}
  .vx-who{display:flex;align-items:center;gap:12px;min-width:0}
  .vx-who img{width:52px;height:52px;border-radius:50%;object-fit:cover;
    border:2px solid var(--brand);flex:none}
  .vx-init{width:52px;height:52px;border-radius:50%;flex:none;background:var(--brand);
    color:#fff;display:flex;align-items:center;justify-content:center;
    font-size:22px;font-weight:700;border:2px solid var(--brand)}
  .vx-who b{display:block;font-size:17px;line-height:1.2;color:var(--ink)}
  .vx-who span:not(.vx-init){display:block;font-size:11px;letter-spacing:.12em;
    text-transform:uppercase;color:var(--muted);margin-top:3px}
  .vx-logo{height:26px;width:auto;opacity:.9;flex:none}

  .vx-lbl{font-size:11px;font-weight:700;letter-spacing:.14em;text-transform:uppercase;
    color:var(--muted);margin-top:6px;display:flex;align-items:center;gap:8px}

  /* 16px minimum on inputs: below it iOS Safari zooms the page on focus and she
     has to pinch back out after every sentence. */
  .vx-ta{width:100%;padding:14px 16px;border-radius:var(--r-sm);border:1px solid var(--line);
    background:var(--bg);color:var(--ink);font-size:16px;line-height:1.6;resize:vertical;
    font-family:inherit}
  .vx-ta.out{background:var(--soft);font-size:17px}

  .vx-rec,.vx-copy,.vx-go{width:100%;border-radius:var(--r-sm);border:0;
    font-weight:700;cursor:pointer}
  .vx-rec{height:68px;font-size:19px;background:var(--brand);color:#fff}
  .vx-rec.on{background:var(--err)}
  /* Two controls while listening. Start over is deliberately as reachable as
     Done — discarding a fumbled sentence must never be harder than finishing
     one, or she will press Done just to get out and pay for it. */
  .vx-row{display:grid;grid-template-columns:1fr 1.4fr;gap:10px}
  .vx-cancel,.vx-done{height:68px;border-radius:var(--r-sm);border:0;font-weight:700;cursor:pointer}
  .vx-cancel{font-size:16px;background:var(--soft);color:var(--body);border:1px solid var(--line)}
  .vx-cancel:hover{background:#fff;border-color:var(--muted)}
  .vx-done{font-size:18px;background:var(--err);color:#fff}
  @media (max-width:460px){ .vx-row{grid-template-columns:1fr 1fr} .vx-done{font-size:16px} }
  .vx-copy{height:60px;font-size:17px;background:var(--ink);color:#fff;margin-top:4px}
  .vx-copy:disabled{background:var(--line);color:var(--muted);cursor:default}
  /* Secondary on purpose: the automatic pass has normally already run, and this
     is only the way back after editing the Portuguese by hand. */
  .vx-go{height:46px;font-size:13.5px;font-weight:600;background:transparent;
    color:var(--muted);border:1px solid var(--line)}

  .vx-live{display:none;gap:6px;align-items:flex-end;justify-content:center;height:24px}
  .vx-live.on{display:flex}
  .vx-live span{width:5px;height:8px;border-radius:2px;background:var(--brand);
    animation:vxb .9s ease-in-out infinite}
  .vx-live span:nth-child(2){animation-delay:.15s}
  .vx-live span:nth-child(3){animation-delay:.3s}
  @keyframes vxb{0%,100%{height:8px;opacity:.55}50%{height:23px;opacity:1}}

  .vx-spin{width:12px;height:12px;border-radius:50%;border:2px solid var(--line);
    border-top-color:var(--brand);display:none}
  .vx-spin.on{display:inline-block;animation:vxs .7s linear infinite}
  @keyframes vxs{to{transform:rotate(360deg)}}
  @media (prefers-reduced-motion:reduce){
    .vx-live span{animation:none;height:15px} .vx-spin.on{animation:none}
  }

  .vx-note{margin:2px 0 0;font-size:13px;color:var(--muted);min-height:18px}
  .vx-note.bad{color:var(--err)}

  .vx-meter{margin-top:18px;padding-top:14px;border-top:1px solid var(--line)}
  .vx-mtop{display:flex;align-items:baseline;justify-content:space-between;gap:12px}
  .vx-mtop span{font-size:11px;font-weight:700;letter-spacing:.12em;
    text-transform:uppercase;color:var(--muted)}
  .vx-mtop b{font-size:20px;color:var(--ink);font-variant-numeric:tabular-nums}
  .vx-months{margin-top:8px}
  .vx-mrow{display:flex;justify-content:space-between;gap:12px;padding:6px 0;
    font-size:12.5px;color:var(--body);border-bottom:1px solid var(--hair)}
  .vx-mrow:last-child{border-bottom:0}
  .vx-mrow span:last-child{color:var(--muted);font-variant-numeric:tabular-nums;
    white-space:nowrap}
  .vx-mnone{font-size:12.5px;color:var(--muted)}

  /* ---- Console launcher ---------------------------------------------------
     Above the client lookup: this is the most frequent reason the console is
     opened, and a button below the fold is a button that gets scrolled past. */
  .mvoice{width:100%;display:flex;align-items:center;gap:14px;margin:0 0 14px;
    padding:14px 16px;min-height:66px;border-radius:var(--r);cursor:pointer;
    border:1px solid var(--brand);background:var(--soft);text-align:left;
    box-shadow:var(--shadow-sm)}
  .mvoice:hover{background:#fff;border-color:var(--brand-2)}
  .mvoice-i{flex:none;width:40px;height:40px;border-radius:50%;background:var(--brand);
    color:#fff;display:flex;align-items:center;justify-content:center;font-size:18px}
  .mvoice-t{min-width:0;display:block}
  .mvoice-t b{display:block;font-size:15px;color:var(--ink);line-height:1.25}
  .mvoice-t span{display:block;font-size:12.5px;color:var(--muted);margin-top:2px}
  .mvoice-go{margin-left:auto;flex:none;font-size:22px;color:var(--brand);line-height:1}
  @media (max-width:620px){ .mvoice-t span{display:none} }

  /* ---- Virtual staging picker ---------------------------------------------
     Every photo is offered — no vacancy filter — so the grid is the whole
     shoot and has to stay scannable on a phone. */
  .vs{display:flex;flex-direction:column;gap:14px}
  .vs-head{display:flex;align-items:baseline;justify-content:space-between;gap:12px;
    padding-bottom:10px;border-bottom:1px solid var(--line)}
  .vs-head b{font-size:17px;color:var(--ink)}
  .vs-head span{font-size:11px;letter-spacing:.12em;text-transform:uppercase;color:var(--muted)}

  /* The notes replace the room detection that used to gate this. They are not
     decoration — the checkbox is what enables the button. */
  .vs-tips{border:1px solid var(--line);border-radius:var(--r-sm);background:var(--soft);padding:14px 16px}
  .vs-tips b{display:block;font-size:12px;letter-spacing:.1em;text-transform:uppercase;
    color:var(--muted);margin-bottom:8px}
  .vs-tips ul{margin:0;padding-left:18px}
  .vs-tips li{font-size:13.5px;line-height:1.55;color:var(--body);margin-bottom:6px}
  .vs-tips li:last-child{margin-bottom:0}
  /* The honest warning. Set apart from the tips because it is not advice — it
     is what to expect, and what they can do about it. */
  .vs-warn{margin:12px 0 0;padding:12px 14px;border-radius:var(--r-sm);
    border:1px solid color-mix(in srgb,var(--brand) 30%,var(--line));
    background:color-mix(in srgb,var(--brand) 7%,transparent);
    font-size:13.5px;line-height:1.55;color:var(--body)}
  .vs-warn b{color:var(--ink)}
  .vs-ok{display:flex;align-items:flex-start;gap:9px;margin-top:12px;cursor:pointer;
    padding-top:11px;border-top:1px solid var(--line)}
  .vs-ok input{width:19px;height:19px;flex:none;margin-top:1px;accent-color:var(--brand)}
  .vs-ok span{font-size:13.5px;color:var(--ink);font-weight:600}

  /* The grid. Big enough to judge a room by, which is the whole job here —
     a 132px thumbnail cannot tell you whether a corner is empty. */
  .vs-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:18px}
  .vs-cell{border:2px solid var(--line);border-radius:var(--r-sm);overflow:hidden;
    background:var(--card);transition:border-color .12s,box-shadow .12s}
  .vs-cell.on{border-color:var(--brand);box-shadow:0 0 0 3px color-mix(in srgb,var(--brand) 18%,transparent)}
  .vs-cell.done{opacity:.45;pointer-events:none}
  .vs-shot{position:relative;display:block;width:100%;padding:0;border:0;cursor:pointer;
    background:var(--soft);aspect-ratio:3/2}
  .vs-shot img{width:100%;height:100%;object-fit:cover;display:block}
  .vs-tick{position:absolute;top:10px;right:10px;width:30px;height:30px;border-radius:50%;
    background:var(--brand);color:#fff;display:none;align-items:center;justify-content:center;
    font-size:16px;font-weight:700}
  .vs-cell.on .vs-tick,.vs-cell.done .vs-tick{display:flex}
  .vs-cell.done .vs-tick{background:var(--muted)}
  /* Caption and room type. The room only matters once the photo is chosen, so
     the selector stays quiet until then rather than shouting on every tile. */
  .vs-cellfoot{display:flex;flex-direction:column;gap:7px;padding:10px 12px 12px}
  .vs-cap{font-size:12px;color:var(--muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .vs-room{width:100%;height:38px;padding:0 10px;border:1px solid var(--line);
    border-radius:var(--r-sm);background:var(--soft);color:var(--muted);
    font:inherit;font-size:13px;cursor:pointer;opacity:.6}
  .vs-cell.on .vs-room{background:var(--card);color:var(--ink);font-weight:600;
    border-color:var(--brand);opacity:1}

  .vs-go{width:100%;height:56px;border:0;border-radius:var(--r-sm);background:var(--brand);
    color:#fff;font-size:16px;font-weight:700;cursor:pointer}
  .vs-go:disabled{background:var(--line);color:var(--muted);cursor:default}
  .vs-note{margin:0;font-size:13px;color:var(--muted);min-height:18px}
  .vs-note.bad{color:var(--err)}

  /* Buying. One question, one number, one price — the whole point is that it
     does not look like a shopping cart. */
  .vs-buy{max-width:440px}
  .vs-lede{margin:0;color:var(--muted);font-size:14px;line-height:1.55}
  .vs-have{margin:0;font-size:13px;color:var(--muted)}
  .vs-qty-l{font-weight:600;font-size:14px}
  .vs-qty{display:flex;align-items:center;gap:10px}
  .vs-step{width:44px;height:44px;flex:0 0 44px;border:1px solid var(--line);
    border-radius:var(--r-sm);background:var(--card);color:var(--ink);
    font-size:20px;line-height:1;cursor:pointer}
  .vs-step:hover{border-color:var(--brand)}
  .vs-qty input{flex:1;min-width:0;height:44px;text-align:center;font-size:18px;
    font-weight:600;border:1px solid var(--line);border-radius:var(--r-sm);
    background:var(--card);color:var(--ink)}
  /* The spinners fight the −/+ buttons for the same job. */
  .vs-qty input::-webkit-outer-spin-button,
  .vs-qty input::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}
  .vs-qty input{-moz-appearance:textfield;appearance:textfield}
  /* The number they are being asked to pay, given the weight it deserves. */
  /* Our framing around their form. This is the part that says what is being
     bought, so the invoice page below reads as the card field for THIS
     purchase rather than a demand to settle the whole shoot again. */
  .vs-pay{gap:14px}
  .vs-payhead{display:flex;align-items:center;justify-content:space-between;gap:16px;
    padding:16px 18px;border:1px solid var(--line);border-radius:var(--r-sm);
    background:var(--soft)}
  .vs-payhead div{display:flex;flex-direction:column;gap:3px;min-width:0}
  .vs-payhead b{font-size:16px;color:var(--ink)}
  .vs-payhead span{font-size:12.5px;color:var(--muted);line-height:1.45}
  .vs-payhead em{font-style:normal;font-size:28px;font-weight:700;color:var(--ink);flex:none}
  .vs-payframe{border:1px solid var(--line);border-radius:var(--r-sm);overflow:hidden;
    background:#fff;min-height:520px}
  .vs-payframe iframe{display:block;width:100%;height:74vh;min-height:520px;border:0}
  .vs-thanks{text-align:center;align-items:center}
  .vs-thanks h3{margin:0;font-size:20px;color:var(--ink)}
  .vs-tick-big{width:64px;height:64px;border-radius:50%;background:var(--brand);color:#fff;
    display:flex;align-items:center;justify-content:center;font-size:30px;margin:6px auto 2px}
  @media (max-width:640px){
    .vs-payhead{flex-direction:column;align-items:flex-start;gap:8px}
    .vs-payframe iframe{height:68vh}
  }
  .vs-cost{margin:0;font-size:15px}
  .vs-cost b{font-size:22px}
  .vs-cost span{color:var(--muted);font-size:13px}
  /* Full-bleed picker. #panel.full already goes to 100vw, but .panel-body is
     clamped to 760px for reading text — a photo grid is not reading text, so
     this widens the body only for this one panel. */
  #panel.vsfull .panel-body{max-width:1240px;padding-bottom:24px}
  .vs-pick{gap:26px}
  .vs-sec{display:flex;flex-direction:column;gap:10px}
  .vs-sec h4{margin:0;font-size:12px;letter-spacing:.1em;text-transform:uppercase;
    color:var(--muted);font-weight:700}
  .vs-hint{margin:0;font-size:13px;line-height:1.5;color:var(--muted)}

  /* Style is one decision for the whole listing, so it reads as a row of
     choices rather than a field to fill in. */
  .vs-chips{display:flex;flex-wrap:wrap;gap:8px}
  .vs-chip{padding:9px 16px;border:1px solid var(--line);border-radius:999px;
    background:var(--card);color:var(--body);font:inherit;font-size:13.5px;
    font-weight:600;cursor:pointer;transition:all .12s}
  .vs-chip:hover{border-color:var(--brand);color:var(--ink)}
  .vs-chip.on{background:var(--brand);border-color:var(--brand);color:#fff}

  /* The action stays reachable without scrolling back down a long grid. */
  .vs-foot{display:flex;flex-direction:column;gap:8px;padding:14px 0 4px}
  .vs-more{margin:0;text-align:center}

  /* Not saved yet — said plainly, because the opposite claim cost a client a
     photograph they had paid for. */
  .vs-notyet{padding:10px 13px;border-radius:var(--r-sm);
    border:1px solid color-mix(in srgb,var(--brand) 35%,var(--line));
    background:color-mix(in srgb,var(--brand) 8%,transparent);color:var(--ink)}
  .vs-notyet b{color:var(--brand)}

  /* Every generation, scrollable on a phone and a row on a desktop. */
  .vs-vers{display:flex;flex-direction:column;gap:9px;margin-top:16px}
  .vs-vers h4{margin:0;font-size:12px;letter-spacing:.1em;text-transform:uppercase;
    color:var(--muted);font-weight:700}
  .vs-strip{display:flex;gap:10px;overflow-x:auto;padding-bottom:6px;
    scroll-snap-type:x proximity;-webkit-overflow-scrolling:touch}
  .vs-ver{flex:0 0 132px;scroll-snap-align:start;padding:0;cursor:pointer;
    border:2px solid var(--line);border-radius:var(--r-sm);overflow:hidden;
    background:var(--card);display:flex;flex-direction:column}
  .vs-ver.on{border-color:var(--brand);
    box-shadow:0 0 0 3px color-mix(in srgb,var(--brand) 18%,transparent)}
  .vs-ver img{width:100%;aspect-ratio:3/2;object-fit:cover;display:block}
  .vs-ver span{padding:6px 8px;font-size:11.5px;color:var(--muted);
    text-transform:capitalize;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .vs-ver.on span{color:var(--ink);font-weight:600}
  @media (min-width:760px){ .vs-ver{flex:0 0 156px} }

  /* ---- Furniture removal switch ------------------------------------------ */
  .vs-switch{display:flex;align-items:flex-start;gap:11px;cursor:pointer;
    padding:13px 15px;border:1px solid var(--line);border-radius:var(--r-sm);
    background:var(--soft)}
  .vs-switch input{width:20px;height:20px;flex:none;margin-top:1px;accent-color:var(--brand)}
  .vs-switch span{display:flex;flex-direction:column;gap:3px}
  .vs-switch b{font-size:14.5px;color:var(--ink)}
  .vs-switch i{font-style:normal;font-size:12.5px;color:var(--muted)}
  #vsRemoveExtra{display:flex;flex-direction:column;gap:7px;padding:11px 2px 0}
  .vs-ghost{align-self:flex-start;padding:10px 15px;border:1px solid var(--brand);
    border-radius:var(--r-sm);background:transparent;color:var(--brand);
    font:inherit;font-size:13.5px;font-weight:600;cursor:pointer}
  .vs-ghost:hover:not(:disabled){background:color-mix(in srgb,var(--brand) 10%,transparent)}
  .vs-ghost:disabled{border-color:var(--line);color:var(--muted);cursor:default}
  .vs-full{margin-top:12px}
  .vs-full p{margin:7px 0 0;font-size:13px;line-height:1.55;color:var(--body)}

  /* ---- The painter -------------------------------------------------------- */
  /* Above the panel, not inside it: the photo wants the whole screen and the
     panel's own scrolling would fight the drag. */
  body.vp-open{overflow:hidden}
  .vp{position:fixed;inset:0;z-index:120;display:flex;flex-direction:column;
    background:#0b0e0d;color:#fff}
  .vp-bar{display:flex;align-items:center;justify-content:space-between;gap:12px;
    padding:12px 14px;border-bottom:1px solid rgba(255,255,255,.12);flex:none}
  .vp-title{font-size:13.5px;font-weight:600;text-align:center;flex:1}
  .vp-x{width:38px;height:38px;flex:none;border:0;border-radius:50%;
    background:rgba(255,255,255,.12);color:#fff;font-size:16px;cursor:pointer}
  .vp-save{padding:10px 20px;border:0;border-radius:var(--r-sm);background:var(--brand);
    color:#fff;font:inherit;font-size:14px;font-weight:700;cursor:pointer}
  .vp-save:disabled{opacity:.6;cursor:default}

  /* touch-action none is what makes a drag paint instead of scrolling the page. */
  .vp-stage{position:relative;flex:1;overflow:hidden;display:flex;
    align-items:center;justify-content:center;touch-action:none;cursor:crosshair}
  .vp-zoom{position:relative;transform-origin:center center;will-change:transform;
    max-width:100%;max-height:100%}
  .vp-zoom img{display:block;max-width:100%;max-height:100%;
    width:auto;height:auto;user-select:none;-webkit-user-drag:none}
  .vp-zoom canvas{position:absolute;inset:0;width:100%;height:100%;opacity:.5}
  /* A circle at the true brush size, so nobody has to guess before touching. */
  .vp-cursor{position:absolute;border:2px solid #fff;border-radius:50%;
    transform:translate(-50%,-50%);pointer-events:none;opacity:0;
    box-shadow:0 0 0 1px rgba(0,0,0,.5) inset}
  .vp-cursor.on{opacity:.9}

  .vp-tools{flex:none;display:flex;flex-direction:column;gap:12px;padding:14px;
    border-top:1px solid rgba(255,255,255,.12);background:#111614}
  .vp-modes{display:grid;grid-template-columns:1fr 1fr;gap:10px}
  .vp-mode{padding:14px;border:1px solid rgba(255,255,255,.22);border-radius:var(--r-sm);
    background:transparent;color:#fff;font:inherit;font-size:15px;font-weight:700;cursor:pointer}
  .vp-mode.on{background:var(--brand);border-color:var(--brand)}
  .vp-size{display:flex;align-items:center;gap:12px}
  .vp-size span{font-size:12px;letter-spacing:.08em;text-transform:uppercase;
    color:rgba(255,255,255,.6);font-weight:700;flex:none}
  .vp-size input{flex:1;accent-color:var(--brand)}
  .vp-acts{display:flex;gap:10px}
  .vp-ghost{flex:1;padding:11px;border:1px solid rgba(255,255,255,.22);
    border-radius:var(--r-sm);background:transparent;color:#fff;
    font:inherit;font-size:13.5px;cursor:pointer}
  .vp-hint{margin:0;text-align:center;font-size:12px;color:rgba(255,255,255,.55)}
  .vp-toast{position:absolute;left:50%;bottom:calc(100% + 14px);transform:translateX(-50%);
    padding:9px 16px;border-radius:999px;background:rgba(255,255,255,.94);color:#111;
    font-size:13px;font-weight:600;white-space:nowrap}

  @media (min-width:760px){
    .vp-tools{flex-direction:row;align-items:center;gap:20px}
    .vp-modes{grid-template-columns:auto auto;flex:none}
    .vp-mode{padding:12px 26px}
    .vp-size{flex:1;max-width:280px}
    .vp-acts{flex:none}
    .vp-hint{flex:none;text-align:right}
  }


  /* ---- The staging wizard ------------------------------------------------
     One question per screen. Everything here is sized so the answer is
     obvious without reading: the photo is large, the two choices sit side by
     side, and the action is the only filled button on the screen. */
  .vs-wiz{gap:22px}
  .vs-prog{display:flex;align-items:center;justify-content:space-between;gap:14px;
    padding:0 0 12px;border-bottom:1px solid var(--line)}
  .vs-count{display:flex;gap:18px;align-items:baseline}
  .vs-count span{font-size:11.5px;letter-spacing:.08em;text-transform:uppercase;color:var(--muted)}
  .vs-count b{font-size:19px;color:var(--ink);margin-right:5px;letter-spacing:0;text-transform:none}
  .vs-count .vs-left b{color:var(--brand)}
  .vs-prog b{font-size:15px;color:var(--ink)}
  .vs-dots{display:flex;gap:6px}
  .vs-dot{width:8px;height:8px;border-radius:50%;background:var(--line)}
  .vs-dot.now{background:var(--brand);transform:scale(1.35)}
  .vs-dot.done{background:var(--brand);opacity:.45}

  /* Until the notes are ticked the grid is visibly not ready to be used. */
  .vs-grid.locked{opacity:.4;pointer-events:none}
  .vs-tile{display:flex;flex-direction:column;gap:0;border:2px solid var(--line);
    border-radius:var(--r-sm);overflow:hidden;background:var(--card);padding:0;
    cursor:pointer;aspect-ratio:auto;transition:border-color .12s,box-shadow .12s}
  .vs-tile:hover{border-color:var(--brand);box-shadow:0 0 0 3px color-mix(in srgb,var(--brand) 16%,transparent)}
  .vs-tile img{width:100%;aspect-ratio:3/2;object-fit:cover;display:block}
  .vs-tile .vs-cap{padding:9px 11px;text-align:left}

  /* The photo being worked on. */
  .vs-stage{position:relative;border-radius:var(--r-sm);overflow:hidden;background:var(--soft)}
  .vs-stage img{width:100%;display:block;max-height:52vh;object-fit:contain}
  .vs-veil{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;
    justify-content:center;gap:8px;background:rgba(8,12,10,.62);color:#fff;text-align:center}
  .vs-veil b{font-size:16px}
  .vs-veil span:last-child{font-size:13px;opacity:.8}

  /* Room and style, side by side — two dropdowns, no scrolling, no thinking. */
  .vs-pair{display:grid;grid-template-columns:1fr 1fr;gap:12px}
  .vs-field{display:flex;flex-direction:column;gap:6px}
  .vs-field>span{font-size:12px;letter-spacing:.08em;text-transform:uppercase;
    color:var(--muted);font-weight:700}
  .vs-field select{height:50px;padding:0 12px;border:1px solid var(--line);
    border-radius:var(--r-sm);background:var(--card);color:var(--ink);
    font:inherit;font-size:15px;font-weight:600;cursor:pointer}
  .vs-field select:focus{outline:2px solid var(--brand);outline-offset:1px}

  /* ---- The before/after wipe ---------------------------------------------
     Both images are stacked in the same box at the same size; the top one is
     clipped to --pos so dragging moves the seam. A range input laid invisibly
     over the whole thing gives pointer, touch and keyboard control for free. */
  .vs-cmp{position:relative;border-radius:var(--r-sm);overflow:hidden;
    background:var(--soft);touch-action:pan-y;user-select:none}
  .vs-cmp img{display:block;width:100%;max-height:56vh;object-fit:contain}
  .vs-cmp-base{position:relative}
  .vs-cmp-top{position:absolute;inset:0;clip-path:inset(0 calc(100% - var(--pos)) 0 0)}
  .vs-cmp-top img{height:100%;object-fit:contain}
  .vs-cmp-line{position:absolute;top:0;bottom:0;left:var(--pos);width:2px;
    background:#fff;box-shadow:0 0 0 1px rgba(0,0,0,.25);pointer-events:none}
  .vs-cmp-line span{position:absolute;top:50%;left:50%;width:42px;height:42px;
    margin:-21px 0 0 -21px;border-radius:50%;background:#fff;
    box-shadow:0 2px 10px rgba(0,0,0,.35);display:flex;align-items:center;justify-content:center}
  .vs-cmp-line span::before{content:"‹ ›";font-size:15px;font-weight:700;color:#111;letter-spacing:-1px}
  .vs-cmp-tag{position:absolute;bottom:12px;padding:5px 11px;border-radius:999px;
    background:rgba(8,12,10,.68);color:#fff;font-size:10.5px;letter-spacing:.12em;
    text-transform:uppercase;font-weight:700;pointer-events:none}
  .vs-cmp-tag.left{left:12px}
  .vs-cmp-tag.right{right:12px}
  /* The control itself is invisible; the drawn line above is what is seen. */
  /* Present for keyboard focus only. It must NOT cover the image: while it did,
     it swallowed every touch and the seam never moved on a phone. */
  .vs-cmp-range{position:absolute;left:0;bottom:0;width:100%;height:1px;margin:0;
    opacity:0;pointer-events:none;-webkit-appearance:none;appearance:none;background:none}
  .vs-cmp{cursor:ew-resize;touch-action:pan-y}
  .vs-cmp-range::-webkit-slider-thumb{-webkit-appearance:none;width:44px;height:100%;cursor:ew-resize}
  .vs-cmp-range::-moz-range-thumb{width:44px;height:100%;border:0;background:transparent;cursor:ew-resize}
  /* Sibling order puts the range last so it takes the pointer, so focus is
     matched on the container rather than with a sibling combinator. */
  .vs-cmp:focus-within .vs-cmp-line span{outline:3px solid var(--brand);outline-offset:2px}

  /* Before and after. Side by side on a desktop, stacked on a phone — the
     comparison only works when both are the same width. */
  .vs-ba{display:grid;grid-template-columns:1fr 1fr;gap:14px}
  .vs-ba figure{margin:0;display:flex;flex-direction:column;gap:7px}
  .vs-ba img{width:100%;border-radius:var(--r-sm);display:block;background:var(--soft)}
  .vs-ba figcaption{font-size:11px;letter-spacing:.12em;text-transform:uppercase;
    color:var(--muted);font-weight:700;text-align:center}

  /* The floating listing-tools bar sits above everything and overlapped the
     panel action. The lightbox already hides it the same way. */
  body.panel-open .pbar{display:none}

  @media (max-width:1024px){
    .vs-grid{grid-template-columns:repeat(2,1fr)}
  }
  @media (max-width:640px){
    .vs-grid{grid-template-columns:1fr;gap:14px}
    .vs-count{gap:13px}
    .vs-count b{font-size:17px}
    .vs-pair{grid-template-columns:1fr}
    .vs-ba{grid-template-columns:1fr}
    .vs-stage img{max-height:44vh}
  }

  .vs-more button{border:0;background:none;padding:4px;color:var(--brand);
    font:inherit;font-size:13px;text-decoration:underline;cursor:pointer}
